@wix/himalaya-cli 0.1432.0 → 0.1433.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.
@@ -61,8 +61,8 @@ whose `Task` entity anyone may read and write:
61
61
 
62
62
  | Tab | Screen | Worker | Pattern it shows |
63
63
  |---|---|---|---|
64
- | Tasks | `b44_tasks` | `tasks` | list, create, bulk-create, update, delete; loading / empty / error / ready; pull to refresh |
65
- | (pushed) | `b44_task` | `task` | read one row by its id (a nav param), edit, delete then go back |
64
+ | Tasks | `b44_tasks` | `b44-task-list` | **generated** by `himi base44 screens`: list, create, delete; loading / empty / error / ready; pull to refresh |
65
+ | (pushed) | `b44_task` | `b44-task` | **generated**: read one row by its id (a nav param), edit, delete then go back |
66
66
  | Functions | `b44_functions` | `functions` | `functions.invoke(name, payload)` with the reply and the error painted |
67
67
  | Account | `b44_account` | `account` | Native Google sign-in (requires tenant app-link associations), email + password and emailed-code sign-in, register, reset, profile, sign out |
68
68
 
@@ -89,10 +89,14 @@ Turn the book's entities and functions into an adopted declaration, then wire it
89
89
  himi base44 adopt --content . --book ../.himi/base44-book --write # the book step 1 wrote, one level up → base44-entities.ts (never overwrites)
90
90
  ```
91
91
 
92
+ The starter's `config.ts` declares the sample `Task` as a local `const base44Entities = [...]`.
93
+ Delete that declaration, then import yours in its place (keeping both fails with "Identifier
94
+ 'base44Entities' has already been declared"):
95
+
92
96
  ```ts
93
97
  import { base44Entities, base44Functions } from "./base44-entities.js";
94
98
  // …
95
- base44: { appId: "<id>", entities: base44Entities, functions: base44Functions },
99
+ base44: { appId: base44AppId, entities: base44Entities, functions: base44Functions },
96
100
  ```
97
101
 
98
102
  `himi validate` then lints the declaration (`pass: "base44"`), and `himi base44 entities query`
@@ -112,15 +116,21 @@ until you do. See [`base44-sdk`](base44-sdk.md#typed-rows).
112
116
 
113
117
  ## 3. Plan the screens from the book
114
118
 
119
+ `himi base44 screens` (step 4) applies the rules below for you, so this step is about choosing
120
+ **what to declare**: which entities, in what order (with up to three entities each gets a tab; with
121
+ four or more, the first two get tabs and the rest go under More), which fields and which `rls`. The rules describe what the generator emits. Read them to predict the result, and to
122
+ know what to customise afterwards.
123
+
115
124
  Write `.himi/screen-plan.md` before editing code. For each entity in `book.entities`:
116
125
 
117
126
  1. **Decide whether it gets a tab.** An entity that a top-level route reads (`routes[].entities`)
118
127
  and that a user browses gets a tab. A child entity (one whose rows only make sense under a
119
128
  parent, such as `OrderItem` under `Order`) gets a section on the parent's detail screen
120
129
  instead. Keep to 3–5 tabs. Account always takes one when the app is not public (step 5).
121
- 2. **Pick the list row.** The title is the first `required` string field, preferring one named
122
- `title`, `name` or `label`. The subtitle is one or two short fields (a status `enum`, a date, a
123
- number). Never put a long text field in a row.
130
+ 2. **Pick the list row.** The title is the entity's `displayField` if it declares one, else the
131
+ first `required` string field, preferring one named `title`, `name` or `label`. The subtitle is
132
+ one or two short fields (a status `enum`, a date, a number). Never put a long text field in a
133
+ row.
124
134
  3. **Pick the detail and form fields** from each field's JSON Schema type:
125
135
 
126
136
  | Field (`type` / `format` / `enum`) | Detail shows | Form control |
@@ -129,20 +139,28 @@ Write `.himi/screen-plan.md` before editing code. For each entity in `book.entit
129
139
  | `string` + long text (`description`, `notes`, `body`, …) | `Text` with `maxLines` | `TextField` with `multilineMaxLines` |
130
140
  | `string` + `enum` | `Badge` / `Text` | `SegmentedControl` (≤ 4 values) or `Picker` |
131
141
  | `string` + `format: date` / `date-time` | formatted `Text` | `DatePicker` |
132
- | `string` + `format: email` / `uri` | `Text`, tap opens mail / URL | `TextField` with `keyboard: "email"` / `"url"` |
142
+ | `string` + `format: email` / `uri` | `Text` (the generator does not make it tappable yet) | `TextField` with `keyboard: "email"` / `"url"` |
133
143
  | `string` holding an image URL (`image`, `photo`, `avatar`, `*_url`) | `Image` | read-only, see [file upload](#what-the-sdk-cannot-do) |
134
144
  | `number` / `integer` | `Text` (with unit) | `Stepper` (small ranges) or numeric `TextField` |
135
145
  | `boolean` | `Badge` or `Text` | `Toggle` |
136
- | `array` of strings | `FilterChips` / `ChipsInput` (read-only) | `ChipsInput` |
137
- | `object` / nested `array` of objects | a sub-section of rows | none at first. Edit it on the web app |
146
+ | `array` of strings | comma-joined `Text` | `ChipsInput` |
147
+ | `object` / nested `array` of objects | its JSON as `Text` (a sub-section of rows is yours to build) | none. Edit it on the web app |
138
148
  | built-ins `id`, `created_date`, `updated_date`, `created_by` | "Created …" metadata row | never editable |
139
149
 
140
150
  4. **Respect the entity's rules.** `rls` (and field-level `rls`) decide what the signed-in user
141
- may do. Offer only the writes `BOOK.md` lists for the entity. An operation whose rule is
142
- `false` gets no button. A rule that is a condition (`{ "created_by": "{{user.email}}" }`)
143
- means the write only works for a signed-in user, on their own rows, so it belongs behind
144
- sign-in (step 5). A denied call still fails with Base44's message, and every screen must paint
145
- that error rather than swallow it.
151
+ may do. Declare the `rls` `BOOK.md` lists for the entity. The generator gates each write
152
+ control on its operation's rule (falling back to the entity-level `write` rule):
153
+
154
+ | Rule | Control |
155
+ |---|---|
156
+ | `false`, or absent | not emitted at all |
157
+ | `true` | always shown |
158
+ | exactly `{ "created_by": "{{user.email}}" }` or `{ "created_by_id": "{{user.id}}" }` | shown only on the signed-in user's own rows |
159
+ | any other condition | shown only when signed in |
160
+
161
+ A field whose field-level `rls.write` is not `true` is read-only in the form. The gate is
162
+ advisory: a denied call still fails with Base44's message, and every screen paints that error
163
+ rather than swallowing it.
146
164
  5. **Use the sample rows** (`sampleRows`, already redacted) to size rows and choose the subtitle,
147
165
  never as data the app ships.
148
166
 
@@ -151,22 +169,48 @@ Compose each screen with [`designing-himi-screens`](designing-himi-screens.md)
151
169
 
152
170
  ## 4. Build one list + detail per entity
153
171
 
154
- Copy the Task pair and rename it. For an entity `Project`:
172
+ Declare the entity, then generate its screens:
173
+
174
+ ```bash
175
+ himi base44 adopt --content . --book ../.himi/base44-book --write # or declare by hand (step 2)
176
+ himi base44 screens --content . --json
177
+ ```
178
+
179
+ For each entity in `config.ts` `base44.entities`, `himi base44 screens` writes a list screen
180
+ (`b44_<plural>`, e.g. `b44_projects`) and a detail screen (`b44_<name>`, e.g. `b44_project`):
181
+
182
+ - `tier5-src/_shared/b44-<entity>-plan.ts`: the plan (row title and subtitle, facts, form
183
+ controls, write gates) the rules in step 3 produce. The list, the detail and the descriptors all
184
+ read it, so this is the file to customise.
185
+ - `tier5-src/b44-<entity>-list/index.ts` and `tier5-src/b44-<entity>/index.ts`: one-line worker
186
+ entries over the template's shared engine (`_shared/entity-list.ts`, `_shared/entity-detail.ts`).
187
+ Each entity gets its own bundle and service, so two entity tabs never share state.
188
+ - `dev/entities.generated.ts` and `config.entities.generated.ts`: the screen registrations and the
189
+ `linkableScreens` / `tabBar` items. `dev/index.ts` and `config.ts` already import them.
190
+
191
+ The first three entities in config order get a tab, in front of Functions and Account. With more,
192
+ the last entity slot becomes a generated `b44_more` screen listing the rest, so the bar never has
193
+ more than five items. Ids pluralise naively (`Category` → `b44_categories`, `Person` →
194
+ `b44_persons`); give the entity a `title` for the visible name. Two entities that would share an id
195
+ are refused with `code: "entity_id_collision"`.
196
+
197
+ Re-running is safe. Each generated file starts with
198
+ `// @generated by himi base44 screens — sha256:<hash>`:
199
+
200
+ - an unchanged config reports every file `unchanged` and writes nothing;
201
+ - a generated file you edited by hand (its body no longer matches the hash) is reported
202
+ `skipped-edited` and left alone, and the command still exits 0. Pass `--force` to overwrite it;
203
+ - files for an entity you removed from `config.ts` are reported in `orphaned[]` and never deleted.
204
+
205
+ `--dry-run` reports the same outcomes without writing. Failures carry a top-level `code`
206
+ (`no_entities_block`, `entity_id_collision`, `content_dir_not_base44_starter`), per
207
+ [`himi-json-output`](himi-json-output.md). The generator never calls Base44.
155
208
 
156
- - `tier5-src/projects/index.ts` from `tier5-src/tasks/index.ts`. Set `ENTITY = "Project"`, the
157
- service name (`b44Projects`), and `toRow()` for the fields you chose. Keep the structure:
158
- module-eval `load()`, the `latestList` sequence that drops stale replies, the `pendingWrites`
159
- guard, and `derive()` producing the `hide*` flags.
160
- - `tier5-src/project/index.ts` from `tier5-src/task/index.ts`. `inputId()` reads the row id from
161
- the nav param, `get(id)` loads it, and `remove` returns `navigate(…, { presentation: "back" })`
162
- from the action the host dispatched.
163
- - In `dev/index.ts`, a `projects()` and a `project()` builder (copy `tasks()` and `task()`), each
164
- bound with `bundle: "<worker dir>"` and `declaredCapabilities: ["base44"]`. Register both in
165
- `screens.exact` and the tab root in `seed.screens`.
166
- - In `config.ts`, a `linkableScreens` entry for each (the detail with `paramKeys: ["id"]` and its
167
- list as `parentScreenId`) and a `tabBar` item for the list.
209
+ To change a screen beyond what the plan expresses (a filtered list, a child section, a custom
210
+ action), edit its generated entry or plan. The edit makes the file `skipped-edited`, so the
211
+ generator leaves it alone from then on.
168
212
 
169
- The calls a worker makes, all on `entities("<Name>")`:
213
+ The calls the engine makes (and a customised worker can make), all on `entities("<Name>")`:
170
214
 
171
215
  | Need | Call |
172
216
  |---|---|
@@ -187,7 +231,9 @@ Rules that keep it correct:
187
231
  `$item.openLabel`. `himi validate` flags this as an error.
188
232
  - **Every write re-lists**, and a failed write keeps the list on screen with the error above it.
189
233
  Only a failed *first* list is the error state.
190
- - Remove `tasks` / `task` once your own entities replace them, and change `homeScreenId`.
234
+ - Replace the sample `Task` declaration with your own entities and re-run `himi base44 screens`.
235
+ The home screen is the first entity's list. The generator reports the sample's files as
236
+ `orphaned`; delete them by hand.
191
237
 
192
238
  ## 5. Auth: the Account tab
193
239
 
@@ -147,4 +147,3 @@ Failure codes are listed in [`himi-json-output`](himi-json-output.md#himi-base44
147
147
  full-set sync, which is why it is a separate, deliberate step.
148
148
  - **Typed clients and hermetic test data**: `entities<"X">()` typed from the declaration, with
149
149
  `seed` rows as mocks.
150
- - **Generated screens**: list and detail screens per declared entity.
@@ -249,6 +249,24 @@ branch on them without parsing prose:
249
249
  - `source_unavailable`: the project download (the eject read) failed, so no drift was
250
250
  computed. Row counts still ran; `sourceRead` is `"unavailable"` and `sourceError` says why.
251
251
 
252
+ ## `himi base44 screens` codes
253
+
254
+ `himi base44 screens` (#4560, [base44-app-to-himi-app](base44-app-to-himi-app.md)) generates one
255
+ list + detail screen per declared `base44.entities` entity. Failures print `ok: false` and `code`
256
+ on stderr (exit 1):
257
+
258
+ - `content_dir_not_base44_starter`: the directory lacks the shared engine the generated files
259
+ import (`missing[]` names the files). Scaffold with `himi init --template base44-starter`.
260
+ - `no_entities_block`: `config.ts` declares no `base44.entities`, so there is nothing to generate.
261
+ - `entity_id_collision`: two entities would generate the same screen id (or one would shadow
262
+ `b44_functions` / `b44_account` / `b44_more`); `entity`, `screenId` and `with` name the clash.
263
+ - `config_unloadable` / `invalid_config`: as for `himi base44 entities` above.
264
+
265
+ On success (`ok: true`, stdout, exit 0) `files[]` gives every generated path with its `outcome`:
266
+ `written`, `unchanged`, or `skipped-edited` (the file was edited by hand and was left alone; pass
267
+ `--force` to overwrite it). A skipped file is not a failure. `orphaned[]`, when present, lists
268
+ generated files for entities no longer declared. They are never deleted.
269
+
252
270
  ## Follow-ups
253
271
 
254
272
  - Migrate failure envelopes in subcommands other than `push`, keeping this contract.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/himalaya-cli",
3
- "version": "0.1432.0",
3
+ "version": "0.1433.0",
4
4
  "type": "module",
5
5
  "description": "himi — the Himalaya authoring CLI. Build a Tier-5 content package on your own machine, push it to the production serve as a draft, preview it on web + Himi Player, and read worker logs back — the remote dev loop. Wraps @himalaya/serve-cli for transport.",
6
6
  "keywords": [
@@ -71,5 +71,5 @@
71
71
  "artifactId": "himalaya-cli"
72
72
  }
73
73
  },
74
- "falconPackageHash": "796dbf6642a176106f5ab3335bbab9788c281db7f264524e0c7fb8e3"
74
+ "falconPackageHash": "f0352e9dd51208b098564413b02976840565ff1539e321ae4ea327f5"
75
75
  }