@wix/himalaya-cli 0.1135.0 → 0.1137.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/dist/cli.mjs +8072 -6792
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/base44-app-context.md +222 -0
- package/guides/designing-himi-screens.md +1 -1
- package/guides/himi-mcp.md +1 -0
- package/guides/index.json +6 -0
- package/guides/recipe-dynamic-list.md +1 -1
- package/guides/recipe-form-submit.md +2 -2
- package/guides/recipe-voice-journal.md +4 -4
- package/guides/tier-5-add-a-screen.md +11 -1
- package/package.json +2 -2
|
Binary file
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# Base44 app context — `himi base44 analyze`
|
|
2
|
+
|
|
3
|
+
`himi base44 analyze` turns a [Base44](https://base44.com) app into an **app book**: one folder
|
|
4
|
+
holding a machine-readable `book.json`, an agent-readable `BOOK.md`, the app's project source and
|
|
5
|
+
screenshots. It is the Base44 counterpart of `himi site analyze` (see `himi docs wix-business-context`),
|
|
6
|
+
and it exists so the coding agent building a Himi app from a Base44 app reads the app's real
|
|
7
|
+
entities, schemas, backend functions and routes instead of guessing them from the rendered site.
|
|
8
|
+
|
|
9
|
+
It is **read-only**. Every call it makes is a GET, and it never writes to the Base44 app.
|
|
10
|
+
|
|
11
|
+
## Quick start
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Visitor pass — no sign-in. What any browser sees at the published URL.
|
|
15
|
+
himi base44 analyze --url https://<tenant>.base44.app --out .himi/base44-book
|
|
16
|
+
|
|
17
|
+
# Owner pass — you are signed in as the app's owner or an editor.
|
|
18
|
+
himi base44 login
|
|
19
|
+
himi base44 whoami
|
|
20
|
+
himi base44 analyze --app-id <24-hex app id> --url https://<tenant>.base44.app --out .himi/base44-book
|
|
21
|
+
|
|
22
|
+
# Print the book itself on stdout (for a script or an agent)
|
|
23
|
+
himi base44 analyze --url https://<tenant>.base44.app --json
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Read `BOOK.md` first, then `book.json` for detail. The default folder is `.himi/base44-book/`.
|
|
27
|
+
It sits inside `.himi/`, so `himi push` never archives it as app source.
|
|
28
|
+
|
|
29
|
+
## The two passes
|
|
30
|
+
|
|
31
|
+
| | Visitor pass | Owner pass |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| Needs | `--url` | `--app-id` **and** a Base44 session |
|
|
34
|
+
| Identity | app id, name, description, favicon, theme colour, language from the published page | plus the app's name and description from its app record |
|
|
35
|
+
| Routes | router paths found in a self-hosted bundle (a Base44-hosted app loads its pages at run time, so usually none) | path → page component → entities it reads, from the source router |
|
|
36
|
+
| Look | screenshots + colours from the Playwright crawl (the same crawl `site analyze` uses) | same, when `--url` is also given |
|
|
37
|
+
| Entities | — | every entity: JSON schema, field types, required fields, row- and field-level access rules, up to `--sample` redacted rows |
|
|
38
|
+
| Functions | — | every backend function: name, entry file, `http` (it serves requests itself) or `invoke`, HTTP methods it branches on, scheduled automations |
|
|
39
|
+
| Agents, connectors | — | agent names, descriptions and tools; connector **types, scopes and status only** |
|
|
40
|
+
| Secrets | — | secret **names** only |
|
|
41
|
+
| Auth | — | visibility (public / private / workspace) and enabled sign-in providers |
|
|
42
|
+
| Source | — | the project files under `<out>/source/`, filtered (below) |
|
|
43
|
+
|
|
44
|
+
**The owner pass is never inferred.** A URL-only run stays a visitor pass even when you are signed
|
|
45
|
+
in and the published page names its app id. Only an explicit `--app-id` asks for the owner pass,
|
|
46
|
+
and without a session that is refused with exit code 2 before anything is read.
|
|
47
|
+
|
|
48
|
+
**Nothing is fatal.** When a chapter cannot be read, the run still writes the book and lists the
|
|
49
|
+
chapter in `gaps[]` with the reason. Common reasons: a refused read (your role can view the app but
|
|
50
|
+
not edit it), no browser for the crawl, or an app id the published page does not carry. This is how
|
|
51
|
+
a viewer's run looks: the visitor pass plus whatever the role could read, with every refused chapter
|
|
52
|
+
listed in `gaps[]`.
|
|
53
|
+
|
|
54
|
+
## Signing in
|
|
55
|
+
|
|
56
|
+
| Mode | How | Stored where |
|
|
57
|
+
|---|---|---|
|
|
58
|
+
| Interactive | `himi base44 login` runs Base44's device sign-in. You approve a code in the browser, and only read access (`apps:read`) is asked for | `~/.himi/base44/session.json`, mode 0600 |
|
|
59
|
+
| Reuse the Base44 CLI's session | `himi base44 login --from-base44-cli` imports what `npx base44 login` stored | the same file |
|
|
60
|
+
| CI | `BASE44_ACCESS_TOKEN=<token>` in the environment | nowhere, it is read from the environment |
|
|
61
|
+
|
|
62
|
+
`BASE44_ACCESS_TOKEN` wins over a stored session. `himi base44 whoami` says which one is in effect
|
|
63
|
+
(`source: "env" | "session"`), who it belongs to and when it expires. It never prints the token.
|
|
64
|
+
`himi base44 logout` deletes the stored session. A stored session that has expired is refreshed
|
|
65
|
+
once, automatically, with its refresh token. The environment token is used exactly as given.
|
|
66
|
+
`BASE44_API_URL` points every call at another Base44 API host (the default is
|
|
67
|
+
`https://app.base44.com`).
|
|
68
|
+
|
|
69
|
+
The session is a user credential. It never goes into the repo or the book.
|
|
70
|
+
|
|
71
|
+
## Options
|
|
72
|
+
|
|
73
|
+
| Flag | Meaning |
|
|
74
|
+
|---|---|
|
|
75
|
+
| `--url <https://…>` | The published app. Runs the visitor pass. |
|
|
76
|
+
| `--app-id <id>` | The app id (24 hex characters, as in `app.base44.com/apps/<id>`). Runs the owner pass. |
|
|
77
|
+
| `--out <dir>` | Book folder. Default `.himi/base44-book`. It must be new, a previous app book (whose `source/` and `screenshots/` are replaced), or free of `book.json`, `BOOK.md`, `source/` and `screenshots/`. Anything else is refused rather than overwritten. |
|
|
78
|
+
| `--sample <n>` | Sample rows per entity, 0–100. Default 5. `--sample 0` reads no rows. |
|
|
79
|
+
| `--json` | Print the book on stdout instead of the summary. |
|
|
80
|
+
| `--no-browser` | Skip the Playwright crawl (recorded as a `look` gap). |
|
|
81
|
+
|
|
82
|
+
The MCP server (`himi mcp`) exposes the same collector as the tool `himi_base44_analyze`
|
|
83
|
+
(`url`, `appId`, `out`, `sample`). It returns the book as `structuredContent`. Toward Base44 it is
|
|
84
|
+
read-only, but it writes the book folder, so it is not annotated read-only to the host.
|
|
85
|
+
|
|
86
|
+
## The book (`book.json`, schema v1)
|
|
87
|
+
|
|
88
|
+
```jsonc
|
|
89
|
+
{
|
|
90
|
+
"schemaVersion": 1,
|
|
91
|
+
"kind": "base44-app-book",
|
|
92
|
+
"generatedAt": "2026-09-30T12:00:00.000Z",
|
|
93
|
+
"mode": "owner", // or "visitor"
|
|
94
|
+
"input": { "url": "https://fixit.base44.app/", "appId": "68c0…cdef", "sample": 5 },
|
|
95
|
+
"identity": { "appId": "68c0…cdef", "appIdSource": "input", "name": "FixIt Tracker",
|
|
96
|
+
"faviconUrl": "…/favicon.png", "colors": { "theme-color": "#4f46e5" }, "lang": "en" },
|
|
97
|
+
"routes": [
|
|
98
|
+
{ "path": "/", "component": "Dashboard", "file": "src/pages/Dashboard.jsx",
|
|
99
|
+
"entities": ["Job"], "source": "project-files" }
|
|
100
|
+
],
|
|
101
|
+
"entities": [
|
|
102
|
+
{ "name": "Job", "fields": [{ "name": "status", "type": "string", "required": true,
|
|
103
|
+
"enum": ["open", "done"] }],
|
|
104
|
+
"required": ["title", "status"], "schema": { /* the JSON Schema, verbatim */ },
|
|
105
|
+
"rls": { "read": { "created_by": "{{user.email}}" }, "delete": false },
|
|
106
|
+
"sampleRows": [{ "title": "Fix phone", "created_by": "[redacted-email]" }],
|
|
107
|
+
"file": "base44/entities/Job.jsonc", "source": "project-files" }
|
|
108
|
+
],
|
|
109
|
+
"functions": [
|
|
110
|
+
{ "name": "sendReport", "sourcePath": "base44/functions/sendReport/entry.ts", "kind": "http",
|
|
111
|
+
"methods": ["POST"], "invoke": "base44.functions.invoke(\"sendReport\", payload)",
|
|
112
|
+
"automations": [{ "name": "weekly", "type": "scheduled", "schedule": "0 9 * * 1" }] }
|
|
113
|
+
],
|
|
114
|
+
"agents": [{ "name": "job_helper", "tools": [{ "entity": "Job", "operations": ["read"] }] }],
|
|
115
|
+
"connectors": [{ "type": "gmail", "scopes": ["…/gmail.send"], "status": "active" }],
|
|
116
|
+
"secrets": { "names": ["STRIPE_KEY"] },
|
|
117
|
+
"auth": { "visibility": "private", "requiresLogin": true, "providers": ["email-password", "google"] },
|
|
118
|
+
"look": { "pages": [ /* the crawl's pages + screenshots */ ], "theme": { "colors": {}, "fonts": {} } },
|
|
119
|
+
"source": { "root": "source", "files": 42, "denied": [".env.local"],
|
|
120
|
+
"secretFlagged": [{ "path": "src/api/keys.js", "reason": "a GitHub token" }] },
|
|
121
|
+
"gaps": [{ "chapter": "look", "reason": "playwright_not_installed: …" }]
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Every fact carries a `source`: `published-spa` (any visitor could see it), `project-files` (the
|
|
126
|
+
app's own project files) or `rest` (the owner-authenticated API). Treat an operation with no rule as
|
|
127
|
+
**open**: the Base44 CLI's own local server allows an operation whose rule is missing, `null` or
|
|
128
|
+
empty.
|
|
129
|
+
|
|
130
|
+
`BOOK.md` is the same content, summarised for an agent. For each entity it lists the worker calls
|
|
131
|
+
the Himi app would make through the `@himalaya/base44` capability: `base44.entities.<Name>.list()`,
|
|
132
|
+
`.filter({…})`, `.get(id)`, and the writes (`create`, `update`, `delete`) that the entity's rules do
|
|
133
|
+
not forbid outright.
|
|
134
|
+
|
|
135
|
+
## What is deliberately never collected
|
|
136
|
+
|
|
137
|
+
- **Secret values.** Only secret names are read. The secrets listing returns a map, and its values
|
|
138
|
+
are dropped the moment it arrives.
|
|
139
|
+
- **Connector tokens and account details.** A connector is its type, scopes and status. The
|
|
140
|
+
connected account's email and any other key are dropped field by field, not filtered afterwards.
|
|
141
|
+
- **Your session.** It stays in `~/.himi/base44/` or the environment and appears in no output.
|
|
142
|
+
- **People's contact details in sample rows.** Emails and phone numbers are replaced with
|
|
143
|
+
`[redacted-email]` / `[redacted-phone]`. A column whose name says credential (`password`,
|
|
144
|
+
`token`, `api_key`, `secret`, `session`, …) loses its value outright, and every token-shaped
|
|
145
|
+
string (JWTs, Base44 workspace keys, GitHub/Slack/AWS/Stripe/Google keys, bearer headers, private
|
|
146
|
+
keys) becomes `[redacted-token]`.
|
|
147
|
+
- **Credential files in the source.** The project files pass through the same deny-list and secret
|
|
148
|
+
scan `himi push` uses for its source archive, and the scan is widened by every token shape listed
|
|
149
|
+
above. Dotenv files, key material, `.git`, `node_modules` and build output are dropped (listed in
|
|
150
|
+
`source.denied`). A file whose *content* looks like a credential (a hardcoded `sk_live_…` in a
|
|
151
|
+
function, say) is named in `source.secretFlagged` with the reason, and its bytes are never
|
|
152
|
+
written.
|
|
153
|
+
- **A copy of the app.** See below.
|
|
154
|
+
|
|
155
|
+
As a last check, the writer scans the serialized book and `BOOK.md` again, and refuses to write
|
|
156
|
+
either if anything token-shaped survived redaction.
|
|
157
|
+
|
|
158
|
+
## What Base44 exposes
|
|
159
|
+
|
|
160
|
+
This section records what the collector relies on. It was read from the source of the official
|
|
161
|
+
Base44 CLI (`base44` on npm, v0.1.24, MIT), not guessed.
|
|
162
|
+
|
|
163
|
+
**Project layout.** An app is a Vite + React SPA plus a `base44/` folder. `base44/config.jsonc`
|
|
164
|
+
names the resource directories, each relative to `base44/`. Their defaults are `entities/`,
|
|
165
|
+
`functions/`, `agents/`, `connectors/` and `auth/`, and each holds `.json` or `.jsonc` files:
|
|
166
|
+
|
|
167
|
+
| Path | Holds |
|
|
168
|
+
|---|---|
|
|
169
|
+
| `base44/entities/<Name>.jsonc` | a JSON Schema object with `name`, `properties`, `required`, `rls` (`read`, `create`, `update`, `delete`, `write`). Each rule is `true`, `false` or a condition such as `{ "created_by": "{{user.email}}" }`. Fields may carry their own `rls`. |
|
|
170
|
+
| `base44/functions/<name>/function.jsonc` | `name`, `entry` (relative to that folder), `automations` (scheduled or entity-triggered). A zero-config function is just `functions/<name>/entry.{js,ts}`. Functions run on Deno. |
|
|
171
|
+
| `base44/agents/<name>.jsonc` | `name`, `description`, `instructions`, `tool_configs` (`entity_name` + `allowed_operations`, or `function_name`) |
|
|
172
|
+
| `base44/connectors/<type>.jsonc` | `type` (`gmail`, `slack`, …) and `scopes` |
|
|
173
|
+
| `base44/auth/*.jsonc` | `enableUsernamePassword`, `enableGoogleLogin`, `enableMicrosoftLogin`, `enableFacebookLogin`, `enableAppleLogin`, `enableSSOLogin`, … |
|
|
174
|
+
|
|
175
|
+
Apps built in the Base44 editor before that layout keep entities at the project root
|
|
176
|
+
(`entities/*.json`) and one file per function (`functions/<name>.js`). The collector reads both
|
|
177
|
+
places. Pages are routed either by a React Router tree (`<Route path=… element={<Page/>}>`) or by
|
|
178
|
+
Base44's page registry (`PAGES = { Name: Component }`, routed at `/<Name>`, with the `mainPage` at
|
|
179
|
+
`/`).
|
|
180
|
+
|
|
181
|
+
**API.** Everything is under `https://app.base44.com` (or `BASE44_API_URL`) and authenticated with
|
|
182
|
+
`Authorization: Bearer <access token>`:
|
|
183
|
+
|
|
184
|
+
| Request | Returns | Used for |
|
|
185
|
+
|---|---|---|
|
|
186
|
+
| `GET /api/apps/<id>` | `name`, `user_description`, `public_settings` (`public_without_login`, `private_with_login`, `workspace_with_login`), `auth_config` | identity, auth |
|
|
187
|
+
| `GET /api/apps/<id>/eject` | the project as a tarball | source, entities, functions, agents, connectors, routes |
|
|
188
|
+
| `GET /api/apps/<id>/backend-functions` | `{ functions: [{ name, entry, files, automations }] }` | functions the download lacks (their `files` are not copied) |
|
|
189
|
+
| `GET /api/apps/<id>/agent-configs` | `{ items: [agent config], total }` | agents the download lacks |
|
|
190
|
+
| `GET /api/apps/<id>/external-auth/list` | `{ integrations: [{ integration_type, status, scopes, user_email }] }` | connectors (`user_email` dropped) |
|
|
191
|
+
| `GET /api/apps/<id>/secrets` | a name → value map | secret **names** |
|
|
192
|
+
| `GET /api/apps/<id>/entities/<Name>?limit=<n>` | rows | sample rows |
|
|
193
|
+
|
|
194
|
+
There is no read endpoint for entity schemas (the CLI only pushes them), so schemas come from the
|
|
195
|
+
downloaded project alone. When the download is refused, the entities chapter is a gap.
|
|
196
|
+
|
|
197
|
+
**Why the collector does not run `base44 eject`.** `eject` downloads the code with
|
|
198
|
+
`GET /api/apps/<id>/eject`. It then creates a **new app** named "<name> Copy" (`POST /api/apps`),
|
|
199
|
+
writes that new app's id into the download, and offers to deploy it. That is a write to your Base44
|
|
200
|
+
account. The collector makes the same download request and stops there.
|
|
201
|
+
|
|
202
|
+
**Sign-in.** Base44 uses the OAuth 2.0 device flow for its CLI. `POST /oauth/device/code` with
|
|
203
|
+
`client_id: base44_cli` returns a user code and a verification URL. `POST /oauth/token`
|
|
204
|
+
(`grant_type=urn:ietf:params:oauth:grant-type:device_code`) is polled until the user approves.
|
|
205
|
+
`POST /oauth/token` with `grant_type=refresh_token` renews a session, and `GET /oauth/userinfo`
|
|
206
|
+
names the user. The Base44 CLI keeps its own session in `~/.base44/auth/auth.json`. himi keeps its
|
|
207
|
+
own, and reads the Base44 CLI's only on `--from-base44-cli`.
|
|
208
|
+
|
|
209
|
+
**Published apps.** An app published on `<tenant>.base44.app` is served by Base44's platform shell.
|
|
210
|
+
Its HTML carries the app's identity: `og:site_name`, description, favicon, `theme-color`, and the
|
|
211
|
+
app id on the Base44 badge tag (`<script data-app-id="<id>" …>`). The app's own page code loads at
|
|
212
|
+
run time, so the visitor pass usually finds **no routes** there and says so in `gaps[]`. The owner
|
|
213
|
+
pass reads them from the source router instead. A self-hosted build of an ejected app is a plain
|
|
214
|
+
Vite bundle: the app id is baked in (`VITE_BASE44_APP_ID`) and the router's `path` strings survive
|
|
215
|
+
minification, so the visitor pass finds both. The visitor pass reads the HTML and up to four of its
|
|
216
|
+
same-origin scripts, through the same SSRF- and DNS-rebinding-guarded fetch `himi site analyze`
|
|
217
|
+
uses. A third-party script tag is never followed.
|
|
218
|
+
|
|
219
|
+
## Not in scope
|
|
220
|
+
|
|
221
|
+
- Generating the Himi app from the book. That is the agent's job.
|
|
222
|
+
- Writing anything back to the Base44 app.
|
|
@@ -281,7 +281,7 @@ Concrete patterns lifted from real usage:
|
|
|
281
281
|
- **Cell list** — `card([ vstack({ spacing: 0, alignment: "leading", children: [ …ListItem cells… ] }) ])`. `spacing: 0` because the cells own their own dividers/padding.
|
|
282
282
|
- **Overlay** — `zstack({ alignment: "center", children: [ backdropImage(cornerRadius 12), withModifiers(label, { padding, background: { token: "accentPrimary" }, cornerRadius: 10 }) ] })`.
|
|
283
283
|
- **Responsive** — `grid({ columns: 1, columnsMedium: 2, spacing: 12 })` for 1-up on phone / 2-up on tablet; `splitView({ primary, detail, primaryMaxWidth: 280 })` for master/detail that stacks on a phone; set `contentMaxWidth` in tokens so wide surfaces keep a readable column instead of running edge-to-edge.
|
|
284
|
-
- **Centered separator, not a flanked divider** — the classic "—— or ——" needs each `divider()` to take equal remaining width, and the HStack row-share only kicks in for controls with an intrinsic fill. **Never put a bare `divider()` inside an HStack**: it
|
|
284
|
+
- **Centered separator, not a flanked divider** — the classic "—— or ——" needs each `divider()` to take equal remaining width, and the HStack row-share only kicks in for controls with an intrinsic fill. **Never put a bare `divider()` inside an HStack for a row that must render on Android**: iOS and web draw it as a thin vertical rule the height of the row, but Android still draws a horizontal rule that claims the row's full width and squeezes its siblings (a stat row's `12` wraps to `1`/`2`). For a stats row, separate the columns with `spacer()`s or spacing instead. Use a **centered caption** instead: `hstack({ children: [spacer(), text("or continue with", "caption", { color: "textSecondary" }), spacer()] })`, optionally over a single full-width `divider()`.
|
|
285
285
|
|
|
286
286
|
> **Intrinsic-fill controls grab the row.** `Button` and `TextField` have an intrinsic FILL, so the next four idioms are about NOT letting that surprise you (they were the papercuts every off-repo app hit):
|
|
287
287
|
|
package/guides/himi-mcp.md
CHANGED
|
@@ -77,6 +77,7 @@ runs a session with it.
|
|
|
77
77
|
| `himi_login` | Open a browser window where the user signs in to Wix, so publishing works with no terminal. It returns the sign-in link at once; call it again to see whether the sign-in finished. |
|
|
78
78
|
| `himi_push` | Publish a **draft**: private to the owner, viewable by preview link and in Himi Player, not live. |
|
|
79
79
|
| `himi_share`, `himi_preview_links` | Share links for a published release. |
|
|
80
|
+
| `himi_base44_analyze` | Read a Base44 app into an app book (read-only) and return it as structured content — `himi docs base44-app-context`. |
|
|
80
81
|
|
|
81
82
|
Each tool acts on the agent's workspace folder unless it is given a `dir`.
|
|
82
83
|
|
package/guides/index.json
CHANGED
|
@@ -208,6 +208,12 @@
|
|
|
208
208
|
"category": "Wix SDK",
|
|
209
209
|
"file": "wix-business-context.md"
|
|
210
210
|
},
|
|
211
|
+
{
|
|
212
|
+
"id": "base44-app-context",
|
|
213
|
+
"title": "Base44 app context (himi base44 analyze)",
|
|
214
|
+
"category": "CLI & Loop",
|
|
215
|
+
"file": "base44-app-context.md"
|
|
216
|
+
},
|
|
211
217
|
{
|
|
212
218
|
"id": "headless-business-to-himi-app",
|
|
213
219
|
"title": "From Wix Headless / Back Office → a native Himi app",
|
|
@@ -43,7 +43,7 @@ State holds the **normalized rows** plus the display strings for every screen st
|
|
|
43
43
|
Actions are `load` (kicked at boot) and `retry`; a `search` action filters in-worker.
|
|
44
44
|
|
|
45
45
|
```ts
|
|
46
|
-
import { defineService } from "@himalaya/state";
|
|
46
|
+
import { defineService } from "@wix/himalaya/state";
|
|
47
47
|
|
|
48
48
|
interface Row { // FLAT strings/booleans only — see "Normalize" below
|
|
49
49
|
id: string; name: string; price: string; initial: string;
|
|
@@ -83,8 +83,8 @@ see [tier-5-add-a-screen.md](../tier-5-add-a-screen.md#cross-field-validation).
|
|
|
83
83
|
## 2. The worker: validate in `submit`, return the outcome as state
|
|
84
84
|
|
|
85
85
|
```ts
|
|
86
|
-
import { defineService } from "@himalaya/state";
|
|
87
|
-
import { createDraftPost, type WixDraftPostWrite } from "@himalaya/wix-blog";
|
|
86
|
+
import { defineService } from "@wix/himalaya/state";
|
|
87
|
+
import { createDraftPost, type WixDraftPostWrite } from "@wix/himalaya/wix-blog";
|
|
88
88
|
|
|
89
89
|
interface FormState {
|
|
90
90
|
title: string; body: string; // prefill values (edit mode / echo after save)
|
|
@@ -6,10 +6,10 @@ processing. A background build must declare `audio_record_background`; web and m
|
|
|
6
6
|
foreground capture only.
|
|
7
7
|
|
|
8
8
|
```ts
|
|
9
|
-
import { startSession, stopSession, listSegments } from "@himalaya/audio-record";
|
|
10
|
-
import * as speech from "@himalaya/speech";
|
|
11
|
-
import * as diarization from "@himalaya/speaker-diarization";
|
|
12
|
-
import { upsert } from "@himalaya/local-db";
|
|
9
|
+
import { startSession, stopSession, listSegments } from "@wix/himalaya/audio-record";
|
|
10
|
+
import * as speech from "@wix/himalaya/speech";
|
|
11
|
+
import * as diarization from "@wix/himalaya/speaker-diarization";
|
|
12
|
+
import { upsert } from "@wix/himalaya/local-db";
|
|
13
13
|
|
|
14
14
|
export async function beginVoiceJournal() {
|
|
15
15
|
const session = await startSession({ mode: "foreground", chunkSeconds: 30 });
|
|
@@ -129,7 +129,17 @@ one object either way.
|
|
|
129
129
|
> the two in step. Until that divergence list is empty, defensive reducers
|
|
130
130
|
> (`String(p?.value ?? p?.text ?? "")`) remain the safe way to read a payload.
|
|
131
131
|
|
|
132
|
-
So a text-input reducer is `setDraft: (s,
|
|
132
|
+
So a text-input reducer is `setDraft: (s, p) => ({ ...s, draft: String(p?.value ?? "") })`, bound with `onChange: { actionId: "tier5.notes.setDraft" }`.
|
|
133
|
+
|
|
134
|
+
**The payload argument can be absent.** A host calls the reducer with one merged object when
|
|
135
|
+
`params`/`args` carry anything, and with **no argument at all** when both are empty — so the
|
|
136
|
+
second parameter is `undefined`, not `{}`. A device always injects `{ value }` for the controls in
|
|
137
|
+
the table, but `himi test` does not always have a value to type: a field whose legal value it
|
|
138
|
+
cannot read off the app (a `Slider`, `Stepper`, `Toggle`, `DatePicker`, or a text field with no
|
|
139
|
+
seeded word to borrow) is dispatched **with no payload**, exactly as an argument-less button is.
|
|
140
|
+
Destructuring in the signature — `(s, { value }) => …` — then throws `Cannot destructure property
|
|
141
|
+
'value' of 'undefined'`, and the crawl reports it against your reducer. Read through `p?.` (or
|
|
142
|
+
default the parameter, `(s, { value } = {}) => …`) and every reducer survives both callers.
|
|
133
143
|
|
|
134
144
|
**Per-row actions carry `$item` fields.** In a bound list/grid, `$item.<field>` substitutes into an action's `params` per row — so a per-row delete is `action: { actionId: "tier5.notes.remove", params: { id: "$item.id" } }`, and the reducer reads `remove: (s, { id }) => …`. (`$item` also substitutes into any prop string, e.g. `text: "$item.title"`.)
|
|
135
145
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1137.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": [
|
|
@@ -67,5 +67,5 @@
|
|
|
67
67
|
"artifactId": "himalaya-cli"
|
|
68
68
|
}
|
|
69
69
|
},
|
|
70
|
-
"falconPackageHash": "
|
|
70
|
+
"falconPackageHash": "db47ced7662fdcbd6e6edb639fb12fb7131e5dd21f79ca0ce73e4fe3"
|
|
71
71
|
}
|