@wix/himalaya-cli 0.1447.0 → 0.1449.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/guides/designing-himi-screens.md +15 -13
- package/guides/himi-test.md +1 -1
- package/guides/push-cli-onboarding.md +31 -0
- package/guides/recipe-dynamic-list.md +9 -0
- package/guides/testing-himi-apps.md +3 -3
- package/guides/wix-api-usage.md +17 -0
- package/guides/wix-sdk-overview.md +1 -0
- package/package.json +2 -2
|
@@ -176,11 +176,13 @@ responsive master/detail. *Reach for `Card` to cluster, not to wrap every single
|
|
|
176
176
|
(`columns: 1, columnsMedium: 2`); `Table` for tabular rows; `Carousel`/`Pager` for swipeable panels;
|
|
177
177
|
`Timeline` for chronological events. Compose rows as `ListItem` / `LabeledContent` / `DisclosureGroup`
|
|
178
178
|
cells inside a `Card([VStack(spacing: 0)])`.
|
|
179
|
-
>
|
|
180
|
-
>
|
|
181
|
-
>
|
|
182
|
-
> screen
|
|
183
|
-
>
|
|
179
|
+
> For a feed/list *screen*, prefer a root `VStack` with a direct vertical worker-bound `LazyList`
|
|
180
|
+
> when the screen has the simple root shape supported by the native host; Android flattens that
|
|
181
|
+
> shape into one lazy root so long lists do not compose every row. Other root shapes stay on the
|
|
182
|
+
> eager screen path, as does a root list that sets `pagination`, `stickyHeader` or
|
|
183
|
+
> `rowSwipeActions`. A `LazyList` nested deeper inside the screen's outer scroll is rendered
|
|
184
|
+
> eagerly on Android to avoid nested-scroll measurement failures, even in a fixed-height panel. A
|
|
185
|
+
> worker-bound horizontal `LazyList` is eager on Android too, so keep rails short.
|
|
184
186
|
|
|
185
187
|
**Text** — `Text` for a single styled string (`maxLines` to truncate); `RichText` for inline mixed
|
|
186
188
|
marks (bold/italic/link within one paragraph); `RichContent` for a Wix Ricos document with blocks,
|
|
@@ -233,12 +235,12 @@ validation, which is what it used to cost.
|
|
|
233
235
|
for the standard case; `Fab` for a single floating primary action on a scroll; `Menu` for a set of
|
|
234
236
|
secondary actions behind one affordance. *One `primary` button per screen.* An **`iconOnly` button still
|
|
235
237
|
needs a `title`** (`Button.title` is non-optional in the native schema — it doubles as the a11y label).
|
|
236
|
-
> **
|
|
237
|
-
>
|
|
238
|
-
>
|
|
239
|
-
>
|
|
240
|
-
> error state, suspect a missing required prop, not a network failure.
|
|
241
|
-
>
|
|
238
|
+
> **Required fields still matter.** A single missing non-optional field (e.g. a titleless `Button`)
|
|
239
|
+
> can make the **whole screen** fail to decode and fall back to the app's generic *"Couldn't load"*
|
|
240
|
+
> error state. An unknown value in an optional enum field decodes to nil (the field is simply absent; only a required enum with an explicit fallback receives one), and an undecodable child
|
|
241
|
+
> (for example an unknown required discriminator) is replaced by an `unknown` placeholder, so those cases do not discard the rest of the screen. When a
|
|
242
|
+
> screen unexpectedly shows the error state, suspect a missing required prop, not a network failure.
|
|
243
|
+
> (The dev-server serves it `200`; required-field validation is on-device.)
|
|
242
244
|
|
|
243
245
|
**Navigation** — `Tabs` / `SegmentedControl` to switch peer views; `Pager` + `PageControl` for
|
|
244
246
|
full-width swipe; `StepIndicator` for a wizard's progress; `CollapsingHeader` for a large-title-to-inline
|
|
@@ -313,8 +315,8 @@ build/validate/render cycles because the failure looks like a content bug rather
|
|
|
313
315
|
"top". A wishlist heart authored as a top-right overlay therefore lands **center-right**. For a
|
|
314
316
|
true corner overlay use a `ZStack` whose overlay child carries its own padding, rather than
|
|
315
317
|
looking for an alignment value that does not exist. Authoring one anyway is a hard error —
|
|
316
|
-
`validate --strict`
|
|
317
|
-
|
|
318
|
+
`validate --strict` still catches unknown enum values for authoring feedback, even though the
|
|
319
|
+
runtime decoders decode an unknown optional-field value to nil (a required discriminator degrades the child to an `unknown` placeholder) rather than discarding the whole screen.
|
|
318
320
|
- **A `Text` sharing a flex row with a `Spacer` gets truncated or wrapped.** The spacer takes the
|
|
319
321
|
slack the text needed. Give the text `fillMaxWidth` (or put it in its own row) instead of relying
|
|
320
322
|
on the spacer to push a sibling; see the "centered separator" idiom above for the same hazard with
|
package/guides/himi-test.md
CHANGED
|
@@ -124,7 +124,7 @@ Only **unambiguous** defects, so a green run stays worth trusting:
|
|
|
124
124
|
| `nav-target-missing` | **warning** | A `himi.open` whose target is neither a baked screen, nor one of the app's declared `linkableScreens`, nor an instance of one (`course_detail_c1` under the base `course_detail`) — the tap opens nothing. Only judged when the caller supplies the app's exact linkable set; an absent set means no opinion, never a guess. A target still carrying an **unresolved** `$` token is dropped before it becomes an edge and is never judged — but one that RESOLVED to a concrete id is judged, which is the point: `$item.detailScreenId` resolving to `course_detail_c1` against the first row is exactly the case the instance rule exists for. |
|
|
125
125
|
| `poll-action-missing` | error | A `_poll` directive every host will silently ignore — an action the bundle never declares, a malformed `action`, a missing `id`, or a non-positive `intervalMs`. Each ends the same way: a screen that never refreshes, with nothing saying why. Nothing in the descriptor names the polled action, so no static check can see it. (A merely too-small interval is legal — the host clamps it.) |
|
|
126
126
|
| `no-request-issued` | **warning** | A worker that uses the Wix transport but never fetches — "the screen loaded with sample data." A warning: a conditional or tap-triggered fetch is legitimate. |
|
|
127
|
-
| `native-decode-failed` | error | Under `--native`, the real Swift/Kotlin decoder rejected the baked descriptor bytes (
|
|
127
|
+
| `native-decode-failed` | error | Under `--native`, the real Swift/Kotlin decoder rejected the baked descriptor bytes (the oracle decodes strictly, so an unknown enum value or malformed child is reported here even though production decoding degrades it to a fallback or an `unknown` placeholder) — or the release's `tokens.json`, reported with `screen: "tokens.json"`: both natives decode it in one strict pass, so a single fractional `typography.*.size` or a `motions.*.duration` written in seconds drops the whole theme. A token finding fails the run but never counts as a failed screen. |
|
|
128
128
|
| `token-type-invalid` | error | The package's tokens file holds a value a native `Int` field rejects — `typography.<k>.size` or `.weight`, `motions.<k>.duration` (milliseconds: `0.3` → `300`), or a `spacing` / `radius` entry — in the base document or any `idiom.<overlay>`. Both natives decode tokens.json in one strict pass, so one such value drops the WHOLE theme (iOS "Theme unavailable"; Android default palette and fonts) while the web preview looks right. Reported with `screen: "tokens.json"`, never counted as a failed screen; `himi validate` reports the same finding. |
|
|
129
129
|
| `capability-undeclared` | error | A `capability.<id>.<verb>` call the screen's gate denied — reported from the gate itself, so it is raised **even when the worker catches the rejection** (which on device leaves a control that silently does nothing). Fix: declare the id on that screen's `logicBundle.declaredCapabilities` and in `config.ts` `capabilities`. One per capability per screen. See [Capabilities](#capabilities). |
|
|
130
130
|
| `journey-failed` | error | A `himi-test.json` journey named an action the screen lacks, threw, or never rendered its `expectText`. |
|
|
@@ -203,6 +203,37 @@ routes: [
|
|
|
203
203
|
A notification whose link matches no route opens the app without navigating. `himi validate`
|
|
204
204
|
warns when a declared route names a screen the app does not declare.
|
|
205
205
|
|
|
206
|
+
### Notification action buttons
|
|
207
|
+
|
|
208
|
+
Declare actionable categories in the app's source `config.ts`. The native shells render one
|
|
209
|
+
button per category action on iOS and Android; the notification payload selects the category.
|
|
210
|
+
This is structural app configuration, not a `himi notify send` flag:
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
push: {
|
|
214
|
+
categories: [{
|
|
215
|
+
id: "time.action-required",
|
|
216
|
+
actions: [
|
|
217
|
+
{ id: "review", title: "Review" },
|
|
218
|
+
{ id: "snooze", title: "Snooze 1h", input: true },
|
|
219
|
+
],
|
|
220
|
+
}],
|
|
221
|
+
observerAction: "tier5.myNav.onNotification",
|
|
222
|
+
},
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
The app-level worker action named by `observerAction` receives every notification through the
|
|
226
|
+
existing observer path. Use `readNotificationEvent` from `@himalaya/push` to read its params:
|
|
227
|
+
|
|
228
|
+
- `notificationAction` is the pressed action id, or `""` for a receipt or ordinary body tap.
|
|
229
|
+
- `notificationText` is the inline reply for an `input: true` action, or `""` otherwise.
|
|
230
|
+
- Action presses have `tapped: "false"`; they are responses to an already-observed notification,
|
|
231
|
+
not new arrivals. They never navigate. The body tap retains the existing link navigation.
|
|
232
|
+
|
|
233
|
+
Each action has its own deduplication key, so a foreground receipt does not swallow a later button
|
|
234
|
+
press and pressing the same button twice is reported once. A press received before the worker is
|
|
235
|
+
configured is queued and replayed once the current site's configuration is ready.
|
|
236
|
+
|
|
206
237
|
**Customer push QA builds use `himi dist --signing byo`.** After publishing an approved
|
|
207
238
|
release, use a backend and reachable runner source that support the customer-signing flow.
|
|
208
239
|
Use the app owner's account for both logins and explicitly select the deployed customer target:
|
|
@@ -14,6 +14,15 @@ the app's `.agents/skills/himalaya/examples/` (written by `himi init` and `himi
|
|
|
14
14
|
card grids). `Carousel` and `Menu` take `itemsPath` the same way. Do **not** hand-roll
|
|
15
15
|
a "VStack of Cards" — that renders only static items and can't bind live data.
|
|
16
16
|
|
|
17
|
+
For a long list screen, make the vertical `LazyList` a direct child of the root `VStack`
|
|
18
|
+
when the rest of the root uses only the supported simple layout. Android can then flatten
|
|
19
|
+
the root into one `LazyColumn` and compose only visible rows. This applies only to a plain
|
|
20
|
+
list: a `LazyList` that sets `pagination`, `stickyHeader` or `rowSwipeActions` keeps the
|
|
21
|
+
screen's own scroll on Android and composes every row. A list nested deeper inside the
|
|
22
|
+
screen's outer scroll also stays eager, and a fixed-height panel inside that scroll does not
|
|
23
|
+
change that on Android. A worker-bound horizontal list is also eager on Android: it renders
|
|
24
|
+
every row in a plain `Row`, so keep rails short.
|
|
25
|
+
|
|
17
26
|
**`Grid` is not a `LazyList` with one column.** It shares `itemsPath` and the row
|
|
18
27
|
template, and nothing else: the gesture props in §5 (`onPullToRefresh`, `pagination`)
|
|
19
28
|
and `stickyHeader`/`rowSwipeActions` are declared on `LazyListProps` only. A key `Grid`
|
|
@@ -317,9 +317,9 @@ findings appear as accepted-risk entries so the file stays auditable.
|
|
|
317
317
|
|
|
318
318
|
### What it cannot tell you
|
|
319
319
|
|
|
320
|
-
This is the **web renderer's** view. It cannot see native decode
|
|
321
|
-
|
|
322
|
-
blank on device when bound — so rather than pass those silently it names them:
|
|
320
|
+
This is the **web renderer's** view. It cannot see native-only decode failures (for example, a
|
|
321
|
+
missing required field can still blank an iOS/Android screen while this tree looks healthy) or
|
|
322
|
+
components that render blank on device when bound — so rather than pass those silently it names them:
|
|
323
323
|
|
|
324
324
|
```
|
|
325
325
|
⚠ 2 nodes NOT verifiable headless:
|
package/guides/wix-api-usage.md
CHANGED
|
@@ -104,6 +104,23 @@ response. The client holds **no** auth or HTTP —
|
|
|
104
104
|
that's `WixApiCapability` (attaches auth per call, 401→refresh→retry). Import the domain by its canonical
|
|
105
105
|
package `@himalaya/wix-<domain>` (unversioned name; the REST version is in the path — RFC 0043 D2).
|
|
106
106
|
|
|
107
|
+
### Read an owner-created async job
|
|
108
|
+
|
|
109
|
+
The first-party `@himalaya/wix-async-jobs` client exposes the current state of an async job through the
|
|
110
|
+
Wix gateway. It is an owner-scoped read and requires `INFRA.ASYNC_JOB_READ`; visitor sessions receive
|
|
111
|
+
403. Poll the returned `job.status` while it is `INITIALIZED` or `PROCESSING`, and stop at `FINISHED`
|
|
112
|
+
or `FAILED`:
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
import { getAsyncJob } from "@himalaya/wix-async-jobs";
|
|
116
|
+
|
|
117
|
+
const { job } = await getAsyncJob(jobId);
|
|
118
|
+
const status = job?.status;
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The client calls `GET /async-jobs/v1/async-jobs/{jobId}`. A missing job is an HTTP 404 with
|
|
122
|
+
`JOB_NOT_FOUND`; do not treat that response as authorization evidence.
|
|
123
|
+
|
|
107
124
|
> **Catalog V1 vs V3 — use V3 by default.** For a new Stores reader use
|
|
108
125
|
> **`queryStoreProducts`** (POST
|
|
109
126
|
> `/stores/v3/products/query`) and **`getStoreProduct`**, from the same `@himalaya/wix-stores`
|
|
@@ -43,6 +43,7 @@ Same idea, one canonical entry — don't reach for the others:
|
|
|
43
43
|
| I want to… | Canonical door | Layer |
|
|
44
44
|
|---|---|---|
|
|
45
45
|
| Read/write a Wix domain (products, bookings, members…) | `@himalaya/wix-<domain>` from a worker | L3 |
|
|
46
|
+
| Read the state of an owner-created async job | `@himalaya/wix-async-jobs` → `getAsyncJob(jobId)` | L3 |
|
|
46
47
|
| Emit a BI beacon | `wix-platform.bi` | L2 |
|
|
47
48
|
| Conduct an experiment / read a flag | `wix-platform.experiments` / `wix-platform.flags` | L2 |
|
|
48
49
|
| Translate a string / read the locale | `wix-platform.i18n` | L2 |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1449.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": "
|
|
74
|
+
"falconPackageHash": "9703ffb9052d9fc0ed9a8ec8510c21e600640b5a10c12c51d336e278"
|
|
75
75
|
}
|