@wix/himalaya-cli 0.1187.0 → 0.1189.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/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/site-shell.d.ts +10 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/core.mjs +4 -0
- package/dist/cli.mjs +329 -94
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/capabilities.md +26 -3
- package/guides/component-reference.json +4 -24
- package/guides/component-reference.md +4 -9
- package/guides/himi-test.md +31 -0
- package/guides/qa-builds.md +1 -1
- package/package.json +2 -2
|
Binary file
|
package/guides/capabilities.md
CHANGED
|
@@ -25,7 +25,7 @@ camera — import from @himalaya/camera
|
|
|
25
25
|
exports: capturePhoto, pickDocument, scanQR
|
|
26
26
|
declare: config.ts `capabilities` AND each calling screen's `logicBundle.declaredCapabilities`
|
|
27
27
|
binary: needs a NATIVE build — iOS NSCameraUsageDescription; Android android.permission.CAMERA …
|
|
28
|
-
shells: served by owner-lite;
|
|
28
|
+
shells: served by owner-lite, player; `himi dist` adds it to base44, branded-lite, brandy; NOT in the demo-app binary
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
Agents: the same data is the `himi_capabilities` MCP tool. `himi sdk <name>` also prints the
|
|
@@ -89,8 +89,23 @@ Name the shell your app ships in once, in `himalaya.content.json`, and both `him
|
|
|
89
89
|
|
|
90
90
|
`himi test` boots every screen's real worker and dispatches its actions. A declared capability
|
|
91
91
|
answers with its "unavailable" result there, so the crawl checks that your worker handles a
|
|
92
|
-
declined camera or a missing position without breaking
|
|
93
|
-
|
|
92
|
+
declined camera or a missing position without breaking; a second pass then answers the modelled
|
|
93
|
+
ones (camera, location, photos, speech, …) with a SUCCESS result, so the code behind a granted
|
|
94
|
+
permission runs too. Two things in the `--json` report are about capabilities:
|
|
95
|
+
|
|
96
|
+
- a **`capability-undeclared`** finding for every call the screen's gate denied — even one your
|
|
97
|
+
worker caught, which on device looks like a dead button rather than an error;
|
|
98
|
+
- **`capabilityCoverage`**: each `capability.<id>.<verb>` your workers call, and what the crawl
|
|
99
|
+
answers it with — `success` (modelled), `store` (a real session store: `local_database`,
|
|
100
|
+
`secure_storage`), `unavailable-only` (no model yet, so only the declined path runs), or `denied`.
|
|
101
|
+
See [himi-test → Capabilities](himi-test.md#capabilities).
|
|
102
|
+
|
|
103
|
+
The bundle scan only ever **reports**: it never adds a capability to a screen's declaration. The
|
|
104
|
+
per-screen list is the authorization boundary, so a worker shared by two screens cannot widen the
|
|
105
|
+
one that never makes the call.
|
|
106
|
+
|
|
107
|
+
In the web preview, camera capture and geolocation use the browser's own file picker and location
|
|
108
|
+
prompt.
|
|
94
109
|
|
|
95
110
|
## 5. Ship it
|
|
96
111
|
|
|
@@ -103,6 +118,14 @@ geolocation use the browser's own file picker and location prompt.
|
|
|
103
118
|
entitlements, Android permissions / features) and registers their handlers at boot.
|
|
104
119
|
`himi capabilities --shell <s>` shows such an id as `yes → dist`, and `himi validate` warns that
|
|
105
120
|
it "needs a new `himi dist`" — the installed binary cannot call it until you rebuild.
|
|
121
|
+
- **"needs a new binary".** A successful `himi dist` remembers what its binary was built with —
|
|
122
|
+
on the job (`buildCapabilities`) and in your package (`.himi/last-dist.json`). From then on
|
|
123
|
+
`himi push` prints `needs a new binary: <ids> — run himi dist` when the release declares an id
|
|
124
|
+
that build lacks, a following device's draft offer says the same, and `himi validate` compares
|
|
125
|
+
against that build rather than the committed shell.
|
|
126
|
+
- **Never a silent strip.** On iOS, a capability whose entitlement the signing profile cannot grant
|
|
127
|
+
fails the dist job, naming the capability — the binary would otherwise build green and fail on
|
|
128
|
+
the first call. The minted profile's Apple capabilities are derived from the build's own set.
|
|
106
129
|
- **Preview before you build:** `himi dist --plan` prints what the release declares, what the shell
|
|
107
130
|
already serves, what the build would add and the exact native delta. No job is started.
|
|
108
131
|
- **Write the permission prompt.** The OS shows a sentence when the app asks for camera, location,
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
"notImplementedComponents": [
|
|
7
7
|
"FieldError",
|
|
8
8
|
"Picker",
|
|
9
|
-
"DatePicker",
|
|
10
9
|
"Tabs",
|
|
11
10
|
"Snackbar",
|
|
12
11
|
"Slider",
|
|
@@ -348,22 +347,16 @@
|
|
|
348
347
|
"name": "DatePicker",
|
|
349
348
|
"category": "Form primitives",
|
|
350
349
|
"propsType": "DatePickerProps",
|
|
351
|
-
"bindings": [
|
|
350
|
+
"bindings": [
|
|
351
|
+
"valuePath"
|
|
352
|
+
],
|
|
352
353
|
"dispatches": [
|
|
353
354
|
{
|
|
354
355
|
"callback": "onChange",
|
|
355
356
|
"key": "value",
|
|
356
357
|
"encoding": "unix-seconds-string",
|
|
357
|
-
"note": "Unix SECONDS, string-encoded so the params mirror stays legal. iOS
|
|
358
|
+
"note": "Unix SECONDS, string-encoded so the params mirror stays legal, clamped into [minUnix, maxUnix]. iOS, Android and web conform (iOS shipped `valueUnix` as an int until the SwiftUI-parity DatePicker fix); RN ships nothing. The normative key is `value` because that is what the arms use for every other scalar control.",
|
|
358
359
|
"divergences": [
|
|
359
|
-
{
|
|
360
|
-
"arms": [
|
|
361
|
-
"ios"
|
|
362
|
-
],
|
|
363
|
-
"kind": "wrong-key",
|
|
364
|
-
"actual": "sends `valueUnix` as an int instead of the contract's `value`.",
|
|
365
|
-
"reason": "Only web conforms. This is the widest split in the vocabulary and the clearest argument for the file."
|
|
366
|
-
},
|
|
367
360
|
{
|
|
368
361
|
"arms": [
|
|
369
362
|
"rn"
|
|
@@ -382,19 +375,6 @@
|
|
|
382
375
|
]
|
|
383
376
|
}
|
|
384
377
|
],
|
|
385
|
-
"notImplemented": {
|
|
386
|
-
"props": [
|
|
387
|
-
"mode",
|
|
388
|
-
"minUnix",
|
|
389
|
-
"maxUnix",
|
|
390
|
-
"valuePath"
|
|
391
|
-
],
|
|
392
|
-
"platforms": [
|
|
393
|
-
"ios"
|
|
394
|
-
],
|
|
395
|
-
"severity": "styling",
|
|
396
|
-
"note": "The picker itself renders as a native date wheel — these four props are inert: `mode: \"time\"` still renders a date wheel; `minUnix`/`maxUnix` do not clamp; `valuePath` does not bind."
|
|
397
|
-
},
|
|
398
378
|
"propsSource": "export interface DatePickerProps {\n valueUnix?: number;\n minUnix?: number;\n maxUnix?: number;\n mode?: \"date\" | \"time\" | \"datetime\";\n onChange?: Action;\n /** \"$service:\" sentinel → ISO-8601 string (or unix seconds); prefills + tracks. */\n valuePath?: string;\n}"
|
|
399
379
|
},
|
|
400
380
|
{
|
|
@@ -52,7 +52,7 @@ See also **[Modifiers](#modifiers)** (the `modifiers` block) and **[Actions](#ac
|
|
|
52
52
|
| `FormField` | Form primitives | — |
|
|
53
53
|
| `FieldError` | Form primitives | `textPath` |
|
|
54
54
|
| `Picker` | Form primitives | — |
|
|
55
|
-
| `DatePicker` | Form primitives |
|
|
55
|
+
| `DatePicker` | Form primitives | `valuePath` |
|
|
56
56
|
| `StatefulSection` | State envelopes | — |
|
|
57
57
|
| `Skeleton` | State envelopes | — |
|
|
58
58
|
| `FragmentSlot` | Descriptor-shipped dynamic structure | `casePath` |
|
|
@@ -116,16 +116,15 @@ See also **[Modifiers](#modifiers)** (the `modifiers` block) and **[Actions](#ac
|
|
|
116
116
|
|
|
117
117
|
These props are accepted by the schema and pass validation, but the named platform's renderer never reads them — they silently do nothing (no warning, no log). Prefer a prop NOT listed here, or drive the behaviour from a worker.
|
|
118
118
|
|
|
119
|
-
**Scope:
|
|
119
|
+
**Scope: 13 of 84 components, all of them ios-only** — every other component/platform pair reads every prop it decodes. The list splits in two, and the halves mean different things:
|
|
120
120
|
|
|
121
121
|
- **`category` (4: `BottomSheet`, `Menu`, `Tooltip`, `Popover`)** — the prop changes the component's *kind*. These genuinely are **not implemented**: an overlay renders always-visible inline, so the component does not do the job its name implies. Check the row's note for a working alternative — for a dismissible sheet it is `presentation: "sheet"` on the navigating `Action`, not `BottomSheet`.
|
|
122
|
-
- **`styling` (
|
|
122
|
+
- **`styling` (9: `FieldError`, `Picker`, `Tabs`, `Snackbar`, `Slider`, `ActivityIndicator`, `ChipsInput`, `OtpInput`, `Video`)** — the component itself **works**; only the listed prop is inert. `Slider` on iOS is a working slider whose `debounceMs` does not throttle — not a broken `Slider`. Use the component; just do not depend on that one prop.
|
|
123
123
|
|
|
124
124
|
| Component | Unread props | Platform | Kind | Note |
|
|
125
125
|
|---|---|---|---|---|
|
|
126
126
|
| `FieldError` | `severity` | ios | styling | `severity: "warning"` still paints `danger` red. |
|
|
127
127
|
| `Picker` | `optionsPath`, `placeholder` | ios | styling | `optionsPath` does not bind options; `placeholder` is not shown. |
|
|
128
|
-
| `DatePicker` | `mode`, `minUnix`, `maxUnix`, `valuePath` | ios | styling | The picker itself renders as a native date wheel — these four props are inert: `mode: "time"` still renders a date wheel; `minUnix`/`maxUnix` do not clamp; `valuePath` does not bind. |
|
|
129
128
|
| `Tabs` | `style` | ios | styling | The tab bar itself renders — only `style` is inert: `swipe` still renders as top tabs. |
|
|
130
129
|
| `Snackbar` | `durationMs` | ios | styling | `durationMs` does not control the auto-dismiss timeout. |
|
|
131
130
|
| `Slider` | `debounceMs` | ios | styling | `debounceMs` does not throttle the onChange stream. |
|
|
@@ -821,17 +820,13 @@ export interface DatePickerProps {
|
|
|
821
820
|
}
|
|
822
821
|
```
|
|
823
822
|
|
|
824
|
-
> ⚠️ **Implemented, but these props are inert on ios:** `mode`, `minUnix`, `maxUnix`, `valuePath` — The picker itself renders as a native date wheel — these four props are inert: `mode: "time"` still renders a date wheel; `minUnix`/`maxUnix` do not clamp; `valuePath` does not bind.
|
|
825
|
-
|
|
826
823
|
**Dispatches** — see [What a control sends](#what-a-control-sends-action-payloads):
|
|
827
824
|
|
|
828
825
|
| callback | key | type |
|
|
829
826
|
|---|---|---|
|
|
830
827
|
| `onChange` | `value` | unix-seconds-string |
|
|
831
828
|
|
|
832
|
-
> `onChange` — Unix SECONDS, string-encoded so the params mirror stays legal. iOS
|
|
833
|
-
|
|
834
|
-
> ⚠️ **`onChange` on ios — DIVERGES:** sends `valueUnix` as an int instead of the contract's `value`. Only web conforms. This is the widest split in the vocabulary and the clearest argument for the file.
|
|
829
|
+
> `onChange` — Unix SECONDS, string-encoded so the params mirror stays legal, clamped into [minUnix, maxUnix]. iOS, Android and web conform (iOS shipped `valueUnix` as an int until the SwiftUI-parity DatePicker fix); RN ships nothing. The normative key is `value` because that is what the arms use for every other scalar control.
|
|
835
830
|
|
|
836
831
|
> ⚠️ **`onChange` on rn — DIVERGES:** dispatches the bare action with no date at all.
|
|
837
832
|
|
package/guides/himi-test.md
CHANGED
|
@@ -125,6 +125,7 @@ Only **unambiguous** defects, so a green run stays worth trusting:
|
|
|
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
127
|
| `native-decode-failed` | error | Under `--native`, the real Swift/Kotlin decoder rejected the baked descriptor bytes (one bad enum blanks the whole screen on device). |
|
|
128
|
+
| `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). |
|
|
128
129
|
| `journey-failed` | error | A `himi-test.json` journey named an action the screen lacks, threw, or never rendered its `expectText`. |
|
|
129
130
|
| `inverse-pair-diverges` | **warning** | An action and the action that undoes it do not return to the state the boot settled on — `add` then `remove` leaving a different list, or a counter it forgot to put back. |
|
|
130
131
|
| `refresh-not-idempotent` | **warning** | `refresh` from a fresh boot settles somewhere other than the boot did, on identical data — usually a refresh that appends instead of replacing. |
|
|
@@ -267,6 +268,36 @@ went unproven, it names the gap and pairs it with a himi command or a source edi
|
|
|
267
268
|
derived from what actually ran, never homework. Assembly:
|
|
268
269
|
`tools/himi-cli/src/coverage.ts`.
|
|
269
270
|
|
|
271
|
+
## Capabilities
|
|
272
|
+
|
|
273
|
+
A `capability.*` call is answered twice. The main pass answers every granted one with `null` — the
|
|
274
|
+
device's "unavailable" arm — so a screen's declined-camera / no-position path is checked. The
|
|
275
|
+
capability-success pass then re-crawls each screen whose bundle calls a **modelled** capability
|
|
276
|
+
(audio-record, speech, on-device-ai, calls, media-playback, calendar, files, photos, pdf, share,
|
|
277
|
+
open-url, camera, location) with a success answer shaped exactly like the one its SDK binding
|
|
278
|
+
destructures, so the code behind a granted permission runs too. `local_database` and
|
|
279
|
+
`secure_storage` are served from a real session store on both passes.
|
|
280
|
+
|
|
281
|
+
`--json` carries what each call got as `capabilityCoverage`:
|
|
282
|
+
|
|
283
|
+
```jsonc
|
|
284
|
+
"capabilityCoverage": {
|
|
285
|
+
"counts": { "success": 2, "store": 1, "unavailable-only": 1, "denied": 0 },
|
|
286
|
+
"calls": {
|
|
287
|
+
"capability.camera.capture": { "arm": "success", "screens": ["notes"] },
|
|
288
|
+
"capability.local_database.getAll": { "arm": "store", "screens": ["notes"] },
|
|
289
|
+
"capability.location.getCurrent": { "arm": "success", "screens": ["notes"] },
|
|
290
|
+
"capability.haptic.play": { "arm": "unavailable-only", "screens": ["notes"] }
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
`unavailable-only` means no model exists yet, so only the declined path of that call has run;
|
|
296
|
+
`denied` means no screen running the call grants its id (each denial is also a
|
|
297
|
+
`capability-undeclared` finding), and `deniedOn` lists screens that deny a call others allow. The
|
|
298
|
+
map is static — it says what a call would be answered with, not that a tap reached it; the gap
|
|
299
|
+
ledger says that.
|
|
300
|
+
|
|
270
301
|
## Writes to Wix
|
|
271
302
|
|
|
272
303
|
Every run lists what the app **writes** to the Wix site, per screen and action — the inventory an
|
package/guides/qa-builds.md
CHANGED
|
@@ -326,7 +326,7 @@ one never blocks a rollout — the dist routes just `501` with the reason.
|
|
|
326
326
|
| `HIMI_DIST_ALLOWED_XCODE_VERSIONS` | comma-separated Xcode versions a caller may pin (`xcodeVersion` in the request body); unset ⇒ the built-in list. Nothing upstream constrains this field — the Job Service client validates it as `z.string().max(50)` — so without the allow-list it is caller-supplied text choosing a toolchain on a shared pool. A blank value reads as unset (the built-in list), never as "allow anything". |
|
|
327
327
|
| `HIMI_DIST_APPLE_SIGNING` | **Minted iOS signing is ON by default** — set `0`/`false`/`off` to disable it and go back to scavenging a profile off the pool. Rarely what you want: minting ships the profile and the certificate with the job, so nothing has to pre-exist on the machine. (Earlier text here cited `0 profile(s) available` on four machines as a reason to keep minting on — that reading came from a TRUNCATED survey and is retracted below; build 992367 logged 352 profiles. The recommendation is unchanged, the evidence for it was wrong.) |
|
|
328
328
|
| `HIMI_DIST_APPLE_API_KEY_NAME` | Apple account the identity is minted under; unset ⇒ `wix-enterprise` |
|
|
329
|
-
| `HIMI_DIST_APPLE_CAPABILITIES` |
|
|
329
|
+
| `HIMI_DIST_APPLE_CAPABILITIES` | Apple capability types to ADD to every minted id. The set itself is derived per job: push + associated domains (the template baseline) plus the Apple capability of every entitlement in the iOS plan of the job's `buildCapabilities` (`appleCapabilitiesForBuild`). This variable only **widens** that derived set (e.g. `APP_GROUPS` for a widget) — it can never remove a derived capability, because the sync call replaces rather than merges and a narrower list would switch off what the content asked for. Unset ⇒ the derived set alone |
|
|
330
330
|
| `QA_DIST_SLACK_CHANNEL` | Post QA build results to a channel instead of DMing the requester. Worth setting: a DM is unreadable by anything but that person, so a channel is what makes build results scriptable (and visible to the team). |
|
|
331
331
|
|
|
332
332
|
Both per-credential caps are **clamped into the range that can be enforced**, and the two ranges
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1189.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": "6cdd1d60a3c8d77a450fac977716f1d7ded301af4e074c978148513e"
|
|
71
71
|
}
|