siteon
v2.0.0
Published
Manage Siteon forms and generate type-safe API clients
Maintainers
Readme
Siteon CLI
Create and manage Siteon content types and public forms, and generate API clients and submission helpers in your project. Node.js 18 or later is required to run the bundled CLI.
Creating and managing forms
Run these commands in your application directory:
siteon --help
siteon forms --help
siteon public-forms --help
siteon forms auth
siteon forms list
siteon forms get <content-type-id>
siteon forms create article.json --dry-run
siteon forms create article.json
siteon forms update <content-type-id> patch.json --dry-run
siteon public-forms auth
siteon public-forms list
siteon public-forms get <form-id>
siteon public-forms create contact.json --dry-run
siteon public-forms create contact.json
siteon public-forms update <form-id> patch.json --dry-run
siteon public-forms update <form-id> patch.jsonsiteon forms manages CMS content types; siteon public-forms manages forms accepting website submissions. Both groups share authentication and configuration. These commands create definitions, not records or submissions. siteon init still generates clients from saved definitions. Run it after creating or changing a form to refresh the generated helpers.
The earlier siteon forms list|get|create|update <content|public> ... syntax remains supported for compatibility. New commands do not need a kind argument.
Definitions are JSON objects with settings and fields:
{
"settings": { "name": "Contact", "slug": "my-app-contact" },
"fields": [
{ "key": "email", "label": "Email", "type": "EMAIL", "required": true },
{ "key": "message", "label": "Message", "type": "TEXTAREA", "required": true }
]
}Content fields use name, slug, lowercase type, isRequired, orderIndex, and properties. Public fields use label, key, uppercase type, required, and order. The CLI fills missing order and required flags. Content definitions also support relations, simple repeaters, and block repeaters. siteon --help introduces both groups and includes both form guides. Each group's help, including subcommand help, shows its supported fields, JSON examples, and update rules. Coding assistants can read these details through normal CLI help. siteon forms prompt and siteon public-forms prompt print their respective guides on their own. Generic examples are in examples/forms.
Keep administrative credentials in your private project .env or process environment:
SITEON_API_URL="https://api.compitcom.in"
SITEON_WORKSPACE_ID="your-workspace-id"
SITEON_EMAIL="your-email"
SITEON_PASSWORD="your-password"The default .env and siteon.config.json are found at the nearest project root, including when called from a nested source directory. The config supplies baseUrl and workspaceId. Without a saved API URL, the CLI uses https://api.compitcom.in. A workspace ID is required; the CLI never substitutes the account's primary workspace. Interactive terminals prompt for missing credentials. Scripts must provide them through the environment or config. Login and refresh tokens stay in memory and are redacted from command output.
Shared options are --env <file>, --config <file>, --api-url <url>, and --workspace <id>. --workspace-id is an alias. Paths supplied as options or positional arguments are relative to the working directory. An explicit env/config file replaces the corresponding default file. JSON config accepts apiUrl or baseUrl, workspaceId, and optional private email/password values. Keep files containing credentials out of version control and frontend imports. Option precedence is command flags, process environment, the env file, JSON config, then the default API URL. Env values are parsed without variable expansion, so password characters such as $ stay literal. Both API origins and URLs ending in /api work.
Create --dry-run validates and prints the normalized definition entirely offline, without loading config or credentials. A real create checks existing slugs, checks content relation targets in the selected workspace, saves settings and fields, and reads the result back. Public slugs are globally unique, so the backend can still reject a slug used in another workspace. Successful writes print JSON containing the saved ID, definition, editor path, and public definition/submission URLs where applicable. Progress and errors go to stderr.
Updates merge fields by content slug or public key. Omitted fields and settings stay in place; existing fields may be partial, while new fields need a display name and type. Properties and public validation merge one level. Supply nested property objects in full. Omitted block children are preserved. Existing types cannot change. The CLI does not delete forms, fields, or submissions. Update --dry-run authenticates and reads the saved form and relation targets, then prints the merged definition without writes.
Public SELECT and MULTI_SELECT options may be strings or objects with value, label, and optional disabled. Prefer strings for dashboard compatibility. Public slugs cannot be renamed through updates. Set settings.active to toggle a public form; the CLI calls its separate toggle endpoint. Email replies need a subject, content, and replyEmailFieldKey identifying an EMAIL field. Email sending requires configured workspace mail. A webhook ID must already exist in the workspace.
Settings and fields save in separate requests. If a write fails, the CLI reports the new form ID when known and gives commands to inspect and resume with update. If creation times out without an ID, list forms and find the slug before retrying. There is no automatic rollback or retry after an ambiguous network failure. Block updates replace backend child rows, so child IDs may change. Requests time out after 30 seconds. A 401 refreshes the in-memory token once. A new login can invalidate another session's refresh token on backends that store one refresh token per user.
The backend enforces workspace permissions. Content creation needs form read/create permissions and update permission for later edits. Public creation needs public-form read/create/update permissions because fields save through the update endpoint. Both groups' auth commands also need workspace view permission; narrower accounts can check access with the respective list command instead.
Usage
Run in your application directory:
siteon init
siteon init --workspace <workspace-id>
siteon init --reconfigure
siteon init --skip-install
siteon init --no-animationThe CLI asks for your email and password, lists active workspaces where you have ADMIN access, and detects project settings from package.json and tsconfig.json. Credentials are used for authentication and are never saved to generated files or configuration.
Framework detection checks the nearest project manifest, framework configuration files, and package scripts. Next.js is recognized through its dependency, next.config.js, next.config.mjs, next.config.ts, or Next.js commands. Detection also works from nested folders such as app and components, and respects workspace package boundaries. Existing framework choices are preserved; use --reconfigure to change a previously saved choice.
The Siteon ASCII banner uses a brief cyan sweep animation in interactive terminals. Redirected output, CI, terminals without color, and narrow terminals show the static banner. Use --no-animation to disable the effect.
Choose regular forms and public forms separately. Each selection supports all, specific forms, or none. Empty regular-form selections continue to public forms. You can also generate the core client without selecting either kind of form.
On subsequent runs, the CLI reuses project settings and offers to keep the saved selections. Use --reconfigure to choose settings again, or --workspace to switch workspaces. Deleted and inactive forms are reported and excluded from regeneration. Their existing files and exports remain available.
A failed form request stops initialization before generation and leaves existing clients and configuration intact. Network requests time out after 30 seconds. Ctrl+C cancels initialization.
Generated files
For a TypeScript React or Next.js project:
siteon.config.json
.env # If environment storage is selected
src/siteon/
index.ts
siteon.ts # Configuration, data fetching, media, submission
types.ts
media.ts # React media hooks
siteon-image.tsx # Client image component
siteon-image-server.tsx # Next.js only
forms/
index.ts
posts.ts
public-forms/
index.ts
contact.tsJavaScript projects use .js and .jsx. Static sites use browser ES modules and native fetch. React helpers are generated for React, Next.js, and Vite projects with React installed. Vue and other projects receive the core client without React imports.
Form selection chooses which forms to add or refresh on this run. Existing regular-form and public-form exports remain in the indexes when you deselect a form. Saved selections accumulate for the same workspace and output directory. To remove a generated form, remove its export and its saved config entry explicitly. Existing image components are preserved so local changes survive regeneration.
Before writing generated code, the CLI checks existing files for local changes. It ignores whitespace, quote style, semicolons, trailing commas, redundant parentheses, and ordinary comments. Actual code, type annotations, string values, and meaningful compiler directives remain significant. Formatting-only edits are preserved as they are.
If local edits would be replaced, one multiselect lists Skip all, Overwrite all, and the affected files. A bulk option applies to every listed file. Otherwise, only selected files are overwritten, and leaving the selection empty keeps all listed files untouched. Selecting both bulk options is rejected. Regular-form and public-form files are considered only when their forms are selected for regeneration.
Generation fingerprints are recorded in siteon.config.json so later runs can distinguish local edits from normal schema updates. Older projects without those records are compared with the new generated output and may require review on the first run. Configuration and environment updates continue to use the saved settings and existing merge behavior. Cancelling review leaves files and configuration unchanged.
Form slugs must produce unique filenames and function names. Conflicting or reserved names are reported before writing any generated files. Related selected forms get type imports, including relations inside block repeaters. Unselected relation targets keep the existing any resolved data type for compatibility.
Fetching regular forms
For a form with slug posts and a field with slug slug:
import { getAllPosts, getPostBySlug, getPostById } from "./siteon";
const { data, pagination } = await getAllPosts({
page: 1,
pageSize: 10,
filters: { "data.title": { contains: "Hello" } },
orderBy: [{ field: "order", direction: "asc" }],
resolveRelations: true,
});
const post = await getPostBySlug("hello-world", true);
const byId = await getPostById("submission-id");get...BySlug is generated only when the form has a slug or *-slug field. By-slug and by-ID helpers return null when no submission matches. Their second argument is an optional resolveRelations boolean.
For static sites, import ./siteon/index.js from a <script type="module">.
Submitting public forms
import { submitContact, validateContact } from "./siteon";
const formData = { fullName: "Asha", age: 0 };
const errors = validateContact(formData);
if (!errors.length) await submitContact(formData);Field keys with separators are converted to camel case in the generated arguments, such as full-name to fullName. Submitted FormData uses the original backend keys. Existing camel-case keys retain their spelling.
Submission signatures follow the form's fields:
await submitContact(formData); // Data fields only
await submitContact(formData, files); // Data and file fields
await submitUpload(files); // File fields only
await submitEmpty(); // No fields
await submitContact(formData, files, { captchaToken });An object containing only optional fields defaults to {}. Omit an optional uploads object or pass {}. To pass captcha options after an optional uploads argument, provide {} for that argument.
Client validation checks required values, finite numbers, select options, email and phone formats, file counts, individual file size, and total file size. A required number may be 0. Backend validation remains authoritative for custom validation rules. Forms requiring captcha must receive a captcha token in submission options.
Environment configuration
The CLI adds variables to .env using the framework's prefix:
| Framework | Prefix | Access |
| --------------------------- | -------------- | ----------------- |
| Next.js | NEXT_PUBLIC_ | process.env |
| Vite and Vue | VITE_ | import.meta.env |
| React with Create React App | REACT_APP_ | process.env |
| Other | None | process.env |
VITE_SITEON_BASE_URL=https://api.compitcom.in
VITE_SITEON_WORKSPACE_ID=your-workspace-idSwitching workspaces updates the Siteon workspace variable while preserving custom base URLs and unrelated variables. Check any overrides in .env.local or environment-specific files yourself. Restart the development server after changing variables. For browser projects without a matching environment loader, select config-file storage.
Next.js enables React cache by default. React and Vite setups can opt in, and reruns honor the saved useReactCache preference. React's cache is intended for React Server Components, including those in frameworks other than Next.js. See the React cache documentation.
If @tanstack/react-query is installed, media hooks use it and require a QueryClientProvider. useSiteOnMedias keeps its existing array of query results. Otherwise it uses React state and effects and returns { isLoading, images }, with images nullable while loading. Existing filter types remain accepted, including AND arrays, while object-style AND filters are also supported by the types.
Development
bun install --frozen-lockfile
bun run typecheck
bun test
bun run build
node dist/index.js --helpTests cover initialization with empty selections, request failures, generated TypeScript, JavaScript reruns, public-form validation, framework detection, and environment updates. Build refreshes the bundled CLI and copies this README into dist.
