@botlr/cli 0.1.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/README.md +154 -8
- package/dist/cli.js +902 -138
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +303 -6
- package/dist/index.js +719 -21
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
1
|
# @botlr/cli
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- `botlr schema pull` and `botlr schema push`: the explicit way to resolve props schema drift in either direction. A code push still never changes the schema.
|
|
8
|
+
|
|
9
|
+
- `botlr schema pull <name...>` (or `--all` for every manifest in `sectionsDir`) fetches the section definition's props schema from the dashboard and writes it as `schema` into `<name>.botlr.json`, in the CLI's fixed key order and in whichever format the dashboard has (field DSL or FormBuilder). It says "unchanged" when the manifest already holds the same schema, and regenerates `<name>.props.ts` afterwards unless `--no-types` or `"types": false`.
|
|
10
|
+
- `botlr schema push <name> [--force] [--yes]` reads `schema` from the manifest (an error when it is missing), fetches the dashboard's current schema, prints both formats and a diff of the field keys (added, removed, kept; node names for FormBuilder schemas), asks for confirmation unless `--yes`, then replaces the dashboard's schema (needs `BOTLR_PAT`). When the two schemas are in different formats the server answers 409 and the CLI prints both formats and says to rerun with `--force`; a 422 (not an object of fields, or the definition is not project-scoped) prints the server's message. A successful push regenerates the props file.
|
|
11
|
+
- The drift warning of `push` and `sections status` now names both commands: `botlr schema pull <name>` to take the dashboard's schema, `botlr schema push <name>` to send the code's. A manifest `schema` in the FormBuilder format now takes part in the drift comparison too (by node names), since `schema pull` can write one.
|
|
12
|
+
- `@botlr/sdk`: `client.sections.getSchema(name)` (site token, `GET /api/sections/{name}/schema`) and `client.sections.putSchema(name, { schema, force })` (personal token, `PUT /api/sections/{name}/schema`), with the `SectionSchemaFormat`, `SectionSchemaGetResponse`, `SectionSchemaPutBody` and `SectionSchemaPutResponse` types, `schemaFormat(schema)`, `SectionDefinition.format`, `BotlrSchemaFormatConflictError` (the 409 with `currentFormat` and `newFormat`) and `botlrErrorMessage(error)` to read a server's `detail` message. `SectionManifest.schema` is typed as `SectionSchema` (either format).
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- Updated dependencies
|
|
17
|
+
- @botlr/sdk@0.5.0
|
|
18
|
+
|
|
19
|
+
## 0.2.0
|
|
20
|
+
|
|
21
|
+
### Minor Changes
|
|
22
|
+
|
|
23
|
+
- Prop types from the dashboard's schema, and a warning when the code and the dashboard disagree about the props.
|
|
24
|
+
|
|
25
|
+
- `pull` writes `<name>.props.ts` next to the manifest: `export interface <ExportName>Props { ... }` generated from the section definition's props schema as the dashboard stores it (`definition.schema` in the pull response), in both the field DSL and the older FormBuilder format. `required: true` makes a property non-optional; a `select` with plain or `{ value }` options becomes a union of literals; asset and reference types become `string | Record<string, unknown>`; types the CLI does not know become `unknown`. The file carries a "generated, do not edit" header and is left alone when its text is unchanged. `--no-types` on a pull, or `"types": false` in `botlr.config.json`, turns it off.
|
|
26
|
+
- `push` and `sections status` warn when the manifest has a `schema` object (the props the code expects, field DSL only) and its keys differ from the definition's schema on the server: props the code expects that the dashboard does not define, and props the dashboard defines that the code does not list. The warning only reports; the dashboard owns the schema. The manifest's `schema` is otherwise a seed for `push --create`.
|
|
27
|
+
- `sections init` fills `schema` from the zod object a component's `XDefinition.schema` points at when it can read it (field names, a best-effort type, `required` unless optional or defaulted); otherwise it leaves `schema` out.
|
|
28
|
+
- `@botlr/sdk`: `SectionManifest.schema`, the `SectionSchemaField`, `SectionFieldSchema`, `SectionFormBuilderNode`, `SectionFormBuilderSchema` and `SectionSchema` types, and the `isFieldSchema` / `isFormBuilderSchema` guards. `SectionDefinition.schema` is typed as `SectionSchema | Record<string, unknown>`.
|
|
29
|
+
|
|
30
|
+
- Pull writes manifests in a fixed key order and keeps the section registry up to date.
|
|
31
|
+
|
|
32
|
+
- `<name>.botlr.json` is always written as 2-space JSON with `section`, `framework`, `entry`, `exportName`, `files`, `title`, `description`, `category`, `icon`, `dependencies`, then unknown keys alphabetically (`dependencies` lists `npm` before `internal`, nested objects sorted). The server stores manifests as jsonb, which forgets key order, so a pull right after a push no longer shows up as a change in git. A pull also leaves the manifest file alone when it already holds the same data.
|
|
33
|
+
- After a pull, when `publisher-section-registry.ts` (or the file named by the new `registryFile` config key, relative to `sectionsDir`) exists, the CLI adds `import { <exportName> } from "./<entry>";` after the last import and `"<name>": <exportName>,` as the last registry entry, keeping existing entries and formatting. Already-registered sections leave the file untouched; `--no-registry` skips the step; a missing registry prints a one-line notice.
|
|
34
|
+
- `sections init` reads the registry from `registryFile` too.
|
|
35
|
+
- The lock stays one entry per section name per app (documented; `--dir` shares it). `pulledAt` is now kept when the same scope, version and hash land again, so re-pulling does not rewrite the lock.
|
|
36
|
+
|
|
37
|
+
### Patch Changes
|
|
38
|
+
|
|
39
|
+
- Updated dependencies
|
|
40
|
+
- @botlr/sdk@0.4.0
|
|
41
|
+
|
|
3
42
|
## 0.1.2
|
|
4
43
|
|
|
5
44
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -17,38 +17,184 @@ pnpm add -D @botlr/cli
|
|
|
17
17
|
"baseUrl": "https://api.botlr.io",
|
|
18
18
|
"appId": "00000000-0000-0000-0000-000000000000",
|
|
19
19
|
"framework": "react-next",
|
|
20
|
-
"sectionsDir": "components/sections"
|
|
20
|
+
"sectionsDir": "components/sections",
|
|
21
|
+
"registryFile": "publisher-section-registry.ts",
|
|
22
|
+
"types": true
|
|
21
23
|
}
|
|
22
24
|
```
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
`
|
|
26
|
+
`registryFile` is optional and relative to `sectionsDir`; it names the
|
|
27
|
+
component registry `pull` keeps up to date and `sections init` reads.
|
|
28
|
+
`types` (default true) makes `pull` write `<name>.props.ts` from the
|
|
29
|
+
definition's props schema; `false` turns it off for the app.
|
|
30
|
+
|
|
31
|
+
Environment: `BOTLR_API_KEY` (site token, for pull/list/status and `schema
|
|
32
|
+
pull`) and `BOTLR_PAT` (personal access token with `write:sections`, for
|
|
33
|
+
`push` and `schema push`).
|
|
26
34
|
`BOTLR_BASE_URL`, `BOTLR_APP_ID`, `BOTLR_FRAMEWORK` and `BOTLR_SECTIONS_DIR`
|
|
27
35
|
override the file; `--framework` and `--dir` override both.
|
|
28
36
|
|
|
29
37
|
## Commands
|
|
30
38
|
|
|
31
39
|
```
|
|
32
|
-
botlr pull <name...> | --all [--framework react-next] [--dir components/sections] [--version N] [--shared] [--force]
|
|
40
|
+
botlr pull <name...> | --all [--framework react-next] [--dir components/sections] [--version N] [--shared] [--force] [--no-registry] [--no-types]
|
|
33
41
|
botlr push <name> [-m msg] [--shared] [--create] [--force]
|
|
34
42
|
botlr sections list
|
|
35
43
|
botlr sections status [name...] [--offline]
|
|
36
44
|
botlr sections init [--force] [--dry-run]
|
|
45
|
+
botlr schema pull <name...> | --all [--no-types]
|
|
46
|
+
botlr schema push <name> [--force] [-y, --yes] [--no-types]
|
|
37
47
|
```
|
|
38
48
|
|
|
39
49
|
- `pull` writes every file of the section under `sectionsDir`, plus
|
|
40
50
|
`<name>.botlr.json` (the manifest, never holding version or hash) and the
|
|
41
51
|
lock entry in `.botlr/sections.lock.json`. A section whose local files
|
|
42
|
-
changed since the last pull is skipped unless `--force`.
|
|
52
|
+
changed since the last pull is skipped unless `--force`. When the registry
|
|
53
|
+
file exists, `pull` also adds `import { <exportName> } from "./<entry>";`
|
|
54
|
+
and `"<name>": <exportName>,` to it, keeping what is there; a section that
|
|
55
|
+
is already registered leaves the file untouched, and `--no-registry` skips
|
|
56
|
+
this step. Without a registry file the pull prints a one-line notice.
|
|
57
|
+
A pull also writes `<name>.props.ts` from the definition's props schema
|
|
58
|
+
(see "Prop types" below) unless `--no-types` or `"types": false`.
|
|
43
59
|
- `push` reads the manifest and its files, hashes them, and pushes with
|
|
44
60
|
`baseVersion` from the lock so a stale checkout gets a conflict instead of
|
|
45
61
|
overwriting someone's version. `--force` omits `baseVersion`. `--create`
|
|
46
|
-
adds the section definition when the dashboard does not know it yet
|
|
62
|
+
adds the section definition when the dashboard does not know it yet,
|
|
63
|
+
seeded with the manifest's `schema` when it has one. After the push the
|
|
64
|
+
CLI warns when the manifest's `schema` and the definition's schema list
|
|
65
|
+
different props (see "Schema drift" below).
|
|
47
66
|
- `sections status` compares the local content hash with the lock and the
|
|
48
67
|
server's latest: `clean`, `modified`, `behind`, `diverged`, or
|
|
49
|
-
`untracked` for a manifest with no lock entry.
|
|
68
|
+
`untracked` for a manifest with no lock entry. For manifests that carry a
|
|
69
|
+
`schema`, it also fetches the definition and prints the drift warning
|
|
70
|
+
(not with `--offline`).
|
|
50
71
|
- `sections init` derives first manifests from a satellite app's
|
|
51
72
|
`publisher-section-registry.ts` and the `XDefinition` exports next to each
|
|
52
|
-
component.
|
|
73
|
+
component. When the definition's `schema` points at a `z.object({...})`
|
|
74
|
+
in the same file, the manifest gets a `schema` with the field names and a
|
|
75
|
+
best-effort type (`z.string()` → `text`, `z.number()` → `number`,
|
|
76
|
+
`z.boolean()` → `boolean`, `z.enum([...])` → `select` with options,
|
|
77
|
+
`z.array(...)` → `array`, `z.object`/`z.record` → `json`,
|
|
78
|
+
`z.union([z.string(), z.any()])` → `asset`; `required` unless
|
|
79
|
+
`.optional()`, `.nullable()` or `.default(...)`). Fields it cannot read are
|
|
80
|
+
left out, and so is `schema` when nothing could be read. Review them, then
|
|
81
|
+
`botlr push <name> --create` per section.
|
|
82
|
+
- `schema pull` copies the dashboard's props schema into the manifest's
|
|
83
|
+
`schema`; `schema push` sends the manifest's `schema` to the dashboard.
|
|
84
|
+
These are the only commands that change a definition's schema; see
|
|
85
|
+
"Schema drift" below.
|
|
86
|
+
|
|
87
|
+
## Prop types
|
|
88
|
+
|
|
89
|
+
The dashboard owns a section definition's props schema. `pull` turns it
|
|
90
|
+
into TypeScript so a component does not have to repeat it in zod:
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
// components/sections/hero.props.ts (generated, do not edit)
|
|
94
|
+
export interface HeroProps {
|
|
95
|
+
/** Heading */
|
|
96
|
+
heading: string;
|
|
97
|
+
subheading?: string;
|
|
98
|
+
alignment?: "left" | "center" | "right";
|
|
99
|
+
image?: string | Record<string, unknown>;
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The interface is named after the manifest's `exportName` (else a
|
|
104
|
+
PascalCase of the slug) plus `Props`. Field types map as follows: text,
|
|
105
|
+
textarea, markdown, richtext, string, email, tel, url, icon, color, date,
|
|
106
|
+
datetime → `string`; number, integer, currency → `number`; boolean →
|
|
107
|
+
`boolean`; select → a union of the option values (`options` as plain values
|
|
108
|
+
or `{ value }` objects), else `string`, and an array of that with
|
|
109
|
+
`multiple`; multiselect, tags → `string[]`; array, list, repeater →
|
|
110
|
+
`unknown[]`; json, jsonb, object → `Record<string, unknown>`; asset,
|
|
111
|
+
asset-picker-*, media, document, page, reference, relation,
|
|
112
|
+
entity_reference, app_instance, forum_thread → `string | Record<string,
|
|
113
|
+
unknown>`; anything else → `unknown`. `required: true` makes the property
|
|
114
|
+
non-optional. The older FormBuilder format (`{ nodes: [...] }`) is walked
|
|
115
|
+
the same way, with groups flattened and repeater items typed from their
|
|
116
|
+
`fields`. A definition without fields yields `Record<string, unknown>`. The
|
|
117
|
+
file is rewritten only when its text changes. Import the type in the
|
|
118
|
+
component:
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
import type { HeroProps } from "./hero.props";
|
|
122
|
+
export function Hero(props: HeroProps) { ... }
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Schema drift
|
|
126
|
+
|
|
127
|
+
A manifest may carry a `schema` object (normally the field DSL, the same
|
|
128
|
+
shape the dashboard stores): the props the code expects. A code `push`
|
|
129
|
+
never writes it to the server's definition except as the seed for
|
|
130
|
+
`push --create`. On `push` and `sections status` the CLI compares that
|
|
131
|
+
object's keys with the definition's schema and warns:
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
warning: props schema of 'hero' differs between the code and the dashboard
|
|
135
|
+
the code expects props the dashboard does not define: ctaLink
|
|
136
|
+
the dashboard defines props the code does not list: image
|
|
137
|
+
the dashboard owns the schema; a code push never changes it. To resolve:
|
|
138
|
+
botlr schema pull hero takes the dashboard's schema into hero.botlr.json
|
|
139
|
+
botlr schema push hero sends the code's schema to the dashboard
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
The warning changes nothing. Resolve it in one of two directions:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
botlr schema pull hero # the dashboard is right: copy its schema into hero.botlr.json
|
|
146
|
+
botlr schema push hero # the code is right: replace the dashboard's schema with the manifest's
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
`schema pull <name...>` (or `--all` for every manifest in `sectionsDir`)
|
|
150
|
+
fetches the definition's props schema and writes it as `schema` into
|
|
151
|
+
`<name>.botlr.json`, in the fixed key order and in whichever format the
|
|
152
|
+
dashboard has. It prints `schema unchanged` when the manifest already says
|
|
153
|
+
the same, and regenerates `<name>.props.ts` afterwards unless `--no-types`
|
|
154
|
+
(or `"types": false`). A section the app has no definition for is skipped
|
|
155
|
+
with a notice.
|
|
156
|
+
|
|
157
|
+
`schema push <name>` reads `schema` from the manifest (an error when it is
|
|
158
|
+
missing), fetches the dashboard's current schema and prints the formats and
|
|
159
|
+
a diff of the field keys, then asks before sending (`--yes` skips the
|
|
160
|
+
question, and is required when there is no terminal):
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
schema of 'hero': dashboard has field-dsl (2 fields), code has field-dsl (3 fields)
|
|
164
|
+
+ added ctaLink, subheading
|
|
165
|
+
- removed image
|
|
166
|
+
= kept heading
|
|
167
|
+
replace the dashboard's schema of 'hero' with the code's? [y/N]
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
For a FormBuilder schema (`{ nodes: [...] }`) the keys are the node names.
|
|
171
|
+
When the dashboard's schema and the manifest's are in different formats the
|
|
172
|
+
server refuses with 409; the CLI prints both formats and says to rerun with
|
|
173
|
+
`--force`, which replaces the schema whatever its format. A 422 (the
|
|
174
|
+
`schema` is not an object of field definitions, or the definition is not
|
|
175
|
+
project-scoped and the template has to be installed into the project first)
|
|
176
|
+
prints the server's message. After a successful push the CLI regenerates
|
|
177
|
+
`<name>.props.ts` from the stored schema. `schema push` needs `BOTLR_PAT`,
|
|
178
|
+
like `push`.
|
|
179
|
+
|
|
180
|
+
## Manifest format
|
|
181
|
+
|
|
182
|
+
The CLI always writes `<name>.botlr.json` the same way: 2-space JSON with
|
|
183
|
+
the keys `section`, `framework`, `entry`, `exportName`, `files`, `title`,
|
|
184
|
+
`description`, `category`, `icon`, `dependencies`, `schema` in that order,
|
|
185
|
+
then any other keys alphabetically; inside `dependencies`, `npm` before `internal`,
|
|
186
|
+
with package names sorted. The server stores manifests as jsonb and does not
|
|
187
|
+
keep key order, so this normalization is what makes a pull right after a
|
|
188
|
+
push produce no diff. A pull leaves a manifest file alone when the local
|
|
189
|
+
file already says the same thing, whatever its formatting.
|
|
190
|
+
|
|
191
|
+
## The lock file
|
|
192
|
+
|
|
193
|
+
`.botlr/sections.lock.json` has one entry per section name for the whole
|
|
194
|
+
app, next to `botlr.config.json`. It is not keyed by directory: `--dir`
|
|
195
|
+
points a command at another sections directory but records into the same
|
|
196
|
+
lock, so a section name means one thing per app. `pulledAt` is when the
|
|
197
|
+
recorded version first landed locally; pulling the same version again keeps
|
|
198
|
+
it, so a no-op pull does not touch the lock file either.
|
|
53
199
|
|
|
54
200
|
Commit the manifests and the lock file; keep `BOTLR_PAT` out of the repo.
|