@wix/himalaya-cli 0.1622.0 → 0.1624.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/sdk/ui/src/index.d.ts +28 -2
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/schema.d.ts +18 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/badges-v2/src/extensions.d.ts +42 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/events/src/index.d.ts +8 -3
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/ui.mjs +15 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-badges.mjs +13 -0
- package/dist/cli.mjs +3511 -2583
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/component-reference.json +3 -1
- package/guides/component-reference.md +21 -2
- package/guides/designing-himi-screens.md +3 -1
- package/guides/himi-json-output.md +34 -0
- package/guides/one-app-to-himi-app.md +104 -0
- package/guides/sdk-reference.json +55 -5
- package/package.json +2 -2
- package/templates/branded-lite/tier5-src/_shared/access-gates-table.ts +8 -0
- package/templates/branded-lite/tier5-src/_shared/access-gates.ts +341 -0
- package/templates/branded-lite/tier5-src/himi-branded-lite-access-nav/index.ts +45 -0
|
Binary file
|
|
@@ -581,7 +581,7 @@
|
|
|
581
581
|
"category": "Feedback",
|
|
582
582
|
"propsType": "AlertDialogProps",
|
|
583
583
|
"bindings": [],
|
|
584
|
-
"propsSource": "export interface AlertDialogProps {\n title: string;\n message?: string;\n confirmAction
|
|
584
|
+
"propsSource": "export interface AlertDialogProps {\n title: string;\n message?: string;\n /** Required unless `buttons` is set. */\n confirmAction?: Action;\n cancelAction?: Action;\n destructive?: boolean;\n /** #1059 — confirm button label; overridable (mirrors NavigationActionRouter's\n * `confirmLabel`). Default \"Confirm\", or \"Delete\" when `destructive`. */\n confirmLabel?: string;\n /** #1059 — cancel button label; overridable. Default \"Cancel\". */\n cancelLabel?: string;\n /** The overlay traps focus and hides the rest of the tree from AT while\n * presented (iOS `accessibilityViewIsModal`, Android `isTraversalGroup`, ARIA\n * `aria-modal`). TRI-STATE: absent takes this component's default (**true**), an\n * explicit `false` opts it out. */\n modal?: boolean;\n /** Up to three buttons, drawn in platform order (iOS/macOS: the cancel button in the\n * cancel position, two side by side, three stacked; Android/web: Material order). They replace\n * `confirmAction`/`cancelAction`; setting both is a validator warning, and the buttons win. */\n buttons?: AlertButton[];\n}"
|
|
585
585
|
},
|
|
586
586
|
{
|
|
587
587
|
"name": "RichText",
|
|
@@ -1288,6 +1288,8 @@
|
|
|
1288
1288
|
"TabItem": "export interface TabItem {\n id: string;\n label: string;\n badge?: string;\n}",
|
|
1289
1289
|
"PickerOption": "export interface PickerOption {\n id: string;\n label: string;\n /** #3801 — a colour chip before the label: a colour token name or \"#RRGGBB\". Drawn first. */\n swatch?: string;\n /** #3801 — a small remote thumbnail before the label (drawn when there is no swatch). */\n imageUrl?: string;\n /** #3801 — a leading icon name (drawn when there is no swatch or image). */\n icon?: IconRef;\n /** #3801 — shown but not choosable; never dispatched through `onChange`. */\n disabled?: boolean;\n}",
|
|
1290
1290
|
"PickerFieldStyle": "export interface PickerFieldStyle {\n borderColor?: string;\n borderWidth?: number;\n cornerRadius?: number;\n minHeight?: number;\n padding?: number;\n chevronIcon?: string;\n placeholderColor?: string;\n}",
|
|
1291
|
+
"AlertButtonRole": "export type AlertButtonRole = \"default\" | \"cancel\" | \"destructive\";",
|
|
1292
|
+
"AlertButton": "export interface AlertButton {\n id: string;\n label: string;\n /** `\"cancel\"` (at most one) takes the cancel position and is what scrim/back/Esc dismissal\n * resolves as; `\"destructive\"` draws with the `danger` token. Default `\"default\"`. */\n role?: AlertButtonRole;\n /** Runs on press. */\n action?: Action;\n}",
|
|
1291
1293
|
"GaugeRing": "export interface GaugeRing {\n /** Fraction 0..1 for this ring. */\n value?: number;\n /** `$service:`/`$item.` binding → a live number (overrides `value`). */\n valuePath?: string;\n tint?: TokenName;\n}",
|
|
1292
1294
|
"WidgetTimeRef": "export interface WidgetTimeRef {\n /** Epoch seconds the style counts from/to. */\n at: number;\n /** SwiftUI `Text.DateStyle` / Android time style (default \"timer\"). */\n style?: \"timer\" | \"relative\" | \"date\" | \"time\" | \"offset\";\n}",
|
|
1293
1295
|
"CornerRadii": "export interface CornerRadii {\n topLeading?: number;\n topTrailing?: number;\n bottomLeading?: number;\n bottomTrailing?: number;\n}",
|
|
@@ -1235,7 +1235,8 @@ export interface SnackbarProps {
|
|
|
1235
1235
|
export interface AlertDialogProps {
|
|
1236
1236
|
title: string;
|
|
1237
1237
|
message?: string;
|
|
1238
|
-
|
|
1238
|
+
/** Required unless `buttons` is set. */
|
|
1239
|
+
confirmAction?: Action;
|
|
1239
1240
|
cancelAction?: Action;
|
|
1240
1241
|
destructive?: boolean;
|
|
1241
1242
|
/** #1059 — confirm button label; overridable (mirrors NavigationActionRouter's
|
|
@@ -1248,6 +1249,10 @@ export interface AlertDialogProps {
|
|
|
1248
1249
|
* `aria-modal`). TRI-STATE: absent takes this component's default (**true**), an
|
|
1249
1250
|
* explicit `false` opts it out. */
|
|
1250
1251
|
modal?: boolean;
|
|
1252
|
+
/** Up to three buttons, drawn in platform order (iOS/macOS: the cancel button in the
|
|
1253
|
+
* cancel position, two side by side, three stacked; Android/web: Material order). They replace
|
|
1254
|
+
* `confirmAction`/`cancelAction`; setting both is a validator warning, and the buttons win. */
|
|
1255
|
+
buttons?: AlertButton[];
|
|
1251
1256
|
}
|
|
1252
1257
|
```
|
|
1253
1258
|
|
|
@@ -2508,7 +2513,9 @@ A few props take a typed **object** rather than nested components. Some are arra
|
|
|
2508
2513
|
`TabItem[]`, `Picker.options` / `WheelPicker.options` are a `PickerOption[]` (and
|
|
2509
2514
|
`Picker.field` is a single `PickerFieldStyle`, the drawn field's look), and
|
|
2510
2515
|
`Gauge.rings` is a `GaugeRing[]` (concentric rings, drawn outer→inner), and
|
|
2511
|
-
`RichContentEditor.tools` is a `RichContentEditorTool[]` (a fixed list of toolbar buttons)
|
|
2516
|
+
`RichContentEditor.tools` is a `RichContentEditorTool[]` (a fixed list of toolbar buttons), and
|
|
2517
|
+
`AlertDialog.buttons` is an `AlertButton[]` (1–3 buttons, at most one `cancel`; it replaces
|
|
2518
|
+
`confirmAction`/`cancelAction`).
|
|
2512
2519
|
`Shape` takes three objects: `cornerRadii` is a `CornerRadii` (layout-direction corners,
|
|
2513
2520
|
also `modifiers.clipCornerRadii`), `fillGradient` is a `Gradient` and `stroke` is a
|
|
2514
2521
|
`ShapeStroke` (its `dash` is on/off lengths; empty is solid).
|
|
@@ -2592,6 +2599,18 @@ export interface ShapeStroke {
|
|
|
2592
2599
|
/** on/off dash lengths in pt/dp; empty ⇒ solid. RN draws any dash as its fixed `dashed` style. */
|
|
2593
2600
|
dash?: number[];
|
|
2594
2601
|
}
|
|
2602
|
+
|
|
2603
|
+
export type AlertButtonRole = "default" | "cancel" | "destructive";
|
|
2604
|
+
|
|
2605
|
+
export interface AlertButton {
|
|
2606
|
+
id: string;
|
|
2607
|
+
label: string;
|
|
2608
|
+
/** `"cancel"` (at most one) takes the cancel position and is what scrim/back/Esc dismissal
|
|
2609
|
+
* resolves as; `"destructive"` draws with the `danger` token. Default `"default"`. */
|
|
2610
|
+
role?: AlertButtonRole;
|
|
2611
|
+
/** Runs on press. */
|
|
2612
|
+
action?: Action;
|
|
2613
|
+
}
|
|
2595
2614
|
```
|
|
2596
2615
|
|
|
2597
2616
|
## Modifiers
|
|
@@ -332,7 +332,9 @@ scroll. *Reach for `SegmentedControl` for 2–4 in-content modes; `Tabs`/tab-bar
|
|
|
332
332
|
> explicit `PageControl` if the dots need to read.
|
|
333
333
|
|
|
334
334
|
**Feedback & overlays** — `Banner` for a persistent inline message (with a retry action when a refresh fails over content you kept; a screen with nothing to show uses an `ErrorState`, see §5);
|
|
335
|
-
`Snackbar` for a transient confirmation; `AlertDialog` for a blocking decision
|
|
335
|
+
`Snackbar` for a transient confirmation; `AlertDialog` for a blocking decision (up to three `buttons`
|
|
336
|
+
— "Save / Discard / Cancel" — with roles `default` / `cancel` / `destructive`; a worker's
|
|
337
|
+
`ui.alert({ buttons })` resolves `{ buttonId }`); `BottomSheet` for
|
|
336
338
|
contextual actions/detail; `Tooltip`/`Popover` for a small anchored hint. *Reach for `Snackbar`, not
|
|
337
339
|
`AlertDialog`, to confirm a completed action — don't block on success.* The `Snackbar` COMPONENT draws
|
|
338
340
|
inline where you place it; for a transient toast that floats at the bottom of the screen — an app
|
|
@@ -464,6 +464,40 @@ top-level `code` on stderr.
|
|
|
464
464
|
`navLogicBundle` that differs, or its `navigation` cannot be edited safely; the
|
|
465
465
|
literal to merge is returned in `snippet` and nothing is written (exit 1).
|
|
466
466
|
|
|
467
|
+
## `himi one-app access` codes
|
|
468
|
+
|
|
469
|
+
Carries the source's locked pages (members only, a badge, a paid plan) and its app-wide login requirement into a
|
|
470
|
+
migrated app. Success prints `ok: true` and a `status`: `written`, `unchanged`, `would_write` (`--dry-run`), `in_sync`
|
|
471
|
+
(`--check`) or `no_gates`; `unmapped` lists locked pages with no Himi screen, which are never guessed, and `loginWall`
|
|
472
|
+
says `required`, `not_required` or `unknown` with its `basis` (`evidence`, `flag` or `none`); when it is `required` it also
|
|
473
|
+
lists `enforcedOn` (`ios`, `android`) and `notEnforcedOn` (`web`: the web host enforces a wall only for its own account
|
|
474
|
+
mode). `loginWall.kept` is true when the source does not require login but the app already has a wall (for example one chosen with `--login-wall required`): it stays, and only an explicit `--login-wall none` is refused. `homeEntries` lists the locked pages whose entry is the app's home destination: it stays on the bar behind its lock screen and is never hidden. `himi one-app migrate` adds
|
|
475
|
+
the warning `access_policy_unavailable` to the manifest when the source did not report the login setting. Failures print `ok: false` and a top-level `code`
|
|
476
|
+
on stderr.
|
|
477
|
+
|
|
478
|
+
- `invalid_usage`: required options are missing, duplicated or unknown, `--screen` is not `<layoutItemId>=<screenId>`,
|
|
479
|
+
`--login-wall` is not `required` or `none`, or `--dry-run` and `--check` are both given (exit 2).
|
|
480
|
+
- `evidence_invalid`: the evidence manifest or `raw-structure.json` is missing, invalid or fails its recorded hash,
|
|
481
|
+
`access-policy.json` does not match the hash in the manifest, or the coverage ledger cannot be read or has rows whose
|
|
482
|
+
source changed (exit 1).
|
|
483
|
+
- `app_uninspectable`: `config.ts` or `dev/index.ts` cannot be read or parsed, `dev/index.ts` has no literal `SCREENS`,
|
|
484
|
+
or a file cannot be written; in that case every file written so far is put back as it was (exit 1).
|
|
485
|
+
- `access_engine_missing`: the app lacks `tier5-src/_shared/access-gates.ts` or
|
|
486
|
+
`tier5-src/himi-branded-lite-access-nav`, so a table naming gates would lock nothing; re-scaffold from the current
|
|
487
|
+
template (exit 1).
|
|
488
|
+
- `gate_screen_missing`: a `--screen` names a screen `dev/index.ts` does not declare (exit 1).
|
|
489
|
+
- `app_services_unavailable`: page locks read app-level state through app services, which only an app that has never
|
|
490
|
+
shipped an older binary may use, and the app neither declares `app: { newApp: true }` nor was given `--new-app`; nothing
|
|
491
|
+
is written (exit 1). `--new-app` is the author's statement that the app is new.
|
|
492
|
+
- `needs_manual_merge`: a locked page is mapped to another screen than the app carries (`moved` lists `layoutItemId`, `from`, `to`: the old screen is still wrapped in its lock), a screen payload holds more than `id`, `body` and `modifiers` (or is not a literal object), an entry or row already has a
|
|
493
|
+
different `hiddenPath`, `navigation.navLogicBundle` is a worker that does not answer the gates, `config.ts` has no
|
|
494
|
+
literal `auth`, or the app requires login (`requireLogin`) while the source no longer does; nothing is written (exit 1).
|
|
495
|
+
- `gates_removed`: the app carries gates that this run would not carry: the source has none, or fewer `--screen`
|
|
496
|
+
mappings were given than the app already has gates; `dropped` names the gate keys. Taking a lock out is not
|
|
497
|
+
automatic (exit 1).
|
|
498
|
+
- `access_out_of_sync` (`--check`): the app does not carry the source's rules as they are now; `outOfSync` names the
|
|
499
|
+
files, and a locked page with no `--screen` yet counts too, so a script that gates on the exit code never passes while a locked page is open (exit 1).
|
|
500
|
+
|
|
467
501
|
## `himi one-app validate-design` codes
|
|
468
502
|
|
|
469
503
|
- `invalid_usage`: required options are missing or incompatible (exit 2).
|
|
@@ -388,6 +388,8 @@ Apply these interpretation rules:
|
|
|
388
388
|
- Keep navigation visibility, reachability and data access separate. Reevaluate
|
|
389
389
|
membership/plan/badge gates at runtime; an operator's successful read is not an
|
|
390
390
|
end-user access policy. Never expose protected content beneath a visual gate.
|
|
391
|
+
Carry a locked page's rule with `himi one-app access` (see "Locked pages" below):
|
|
392
|
+
it is a presentation rule, and the data stays protected by its own Wix API.
|
|
391
393
|
- Exclude `ntt.*` definitions and placements from coverage. Preserve configured
|
|
392
394
|
header/top-bar intent; do not add unconfigured drawer or header surfaces.
|
|
393
395
|
- Before publishing, run the migration-only top-bar coverage check:
|
|
@@ -1306,6 +1308,108 @@ then compare those four source journeys in the real host. Keep their missing
|
|
|
1306
1308
|
behavior explicit in coverage and the report. A stock template screenshot or a
|
|
1307
1309
|
passing identity check cannot substitute for the fresh reconstruction/device pass.
|
|
1308
1310
|
|
|
1311
|
+
### Locked pages: members only, a badge, a paid plan
|
|
1312
|
+
|
|
1313
|
+
A One App owner can lock a page (a layout item) for members only, for holders of a badge or for holders of a paid
|
|
1314
|
+
plan, and choose whether a viewer who may not enter sees a lock screen with the owner's message and button, or no
|
|
1315
|
+
tab at all. Those rules are in the AUTHORED structure (`raw-structure.json`, `layoutItems[].permissions`). The
|
|
1316
|
+
structure a Visitor reads is already evaluated for that Visitor: every rule becomes "members only" and the badge and
|
|
1317
|
+
plan ids are gone, so never read the rules from an enriched view. `himi one-app coverage` lists each rule as an
|
|
1318
|
+
`access` row; the rows stay `unresolved` until you carry the rule:
|
|
1319
|
+
|
|
1320
|
+
```bash
|
|
1321
|
+
himi one-app access --evidence-dir .himi/one-app --content . --new-app \
|
|
1322
|
+
--screen <layoutItemId>=<himiScreenId> --screen <layoutItemId>=<himiScreenId>
|
|
1323
|
+
```
|
|
1324
|
+
|
|
1325
|
+
Pass every `--screen` of the app each time: a run that names fewer screens than the gates already in the app would
|
|
1326
|
+
drop a lock, and is refused (`gates_removed`, which lists what it would drop).
|
|
1327
|
+
|
|
1328
|
+
The route decision (which Himi screen a locked page became) is yours; no file records it, so pass it with `--screen`
|
|
1329
|
+
(or `--screens-file`). A locked page with no screen is listed under `unmapped`, never guessed. The command:
|
|
1330
|
+
|
|
1331
|
+
- writes `tier5-src/_shared/access-gates-table.ts`, the gate table the nav worker reads;
|
|
1332
|
+
- puts each gated screen behind a lock screen: the screen's `payload` becomes a `FragmentSlot` whose `open` case is
|
|
1333
|
+
the original screen, moved as it was, and whose default case is the lock, so the page body is not mounted until the
|
|
1334
|
+
viewer is shown to be allowed (a cold start, an unresolved value and an unknown value all render the lock);
|
|
1335
|
+
- binds the tab-bar and drawer entries, and the rows that open the screen, of every gate that may hide (hidden mode,
|
|
1336
|
+
or a lock only members see) to the gate's flag in the app-level nav worker: `$service:brandedLiteNav.accessHidden.<key>`
|
|
1337
|
+
on a tab or drawer entry, `$app:brandedLiteNav.accessHidden.<key>` on a row inside a screen. Tab and drawer
|
|
1338
|
+
entries also get `hiddenUntilResolved`, so they stay off the bar until the worker answers;
|
|
1339
|
+
The home destination (the first tab, the first rail item, or the first drawer row of an app with neither) is the one
|
|
1340
|
+
entry that is never hidden: the boot route, deep links and push taps root on it, and the nav check rejects
|
|
1341
|
+
`hiddenUntilResolved` there. A lock on the home page stays on the bar and shows its lock screen instead; the output
|
|
1342
|
+
lists it as `homeEntries`;
|
|
1343
|
+
- reads the gate's answer inside each lock screen from the same worker, through `$app:brandedLiteNav.accessState.<key>`.
|
|
1344
|
+
A screen has its own worker, so a `$service:` binding there would read that worker and never see the answer;
|
|
1345
|
+
`$app:` reads the app-level one. App services are a feature of apps that have never shipped an older binary, so the
|
|
1346
|
+
command needs your word that this app is new: `--new-app` writes `app: { newApp: true }` into `config.ts`. Without it
|
|
1347
|
+
(and without that declaration already in the file) the command stops with `app_services_unavailable` and writes
|
|
1348
|
+
nothing. An app that has already shipped gets page locks only after its native floor supports app services (1.9.0 or later):
|
|
1349
|
+
until then the command refuses it, and that is by design;
|
|
1350
|
+
- points the app-level bundle (`navigation.navLogicBundle`, or `app.logicBundle` when the app already uses that
|
|
1351
|
+
spelling; declaring both is refused) at `himi-branded-lite-access-nav`, the badges worker that also answers the
|
|
1352
|
+
gates. Ids that normalize to one gate key (`page-a`, `page_a`) get a short hash suffix, so no two pages share a decision; a key an earlier run wrote stays with its page, so a later run never renames it. Mapping a locked page to a different screen than before is refused (`needs_manual_merge`, `moved`): the old screen is still wrapped in its lock. An app whose source locks no page keeps the badges-only worker, byte for byte, and pays nothing;
|
|
1353
|
+
- ties each `access` row of the coverage ledger to the screen and gate (`target`), and never overwrites a target you
|
|
1354
|
+
set. The status stays `unresolved`: it moves only on recorded `access-state` evidence from a device.
|
|
1355
|
+
|
|
1356
|
+
It is idempotent. `--dry-run` writes nothing; `--check` fails with `access_out_of_sync` and names the files that no
|
|
1357
|
+
longer carry the source's rules, so run it after any change to the source or the screens. It refuses to edit what it
|
|
1358
|
+
cannot edit safely (`needs_manual_merge`) and removes nothing it wrote earlier (`gates_removed`).
|
|
1359
|
+
|
|
1360
|
+
**What the lock is.** It is PRESENTATION ONLY, as it is in the One App. The data behind a page stays protected by its
|
|
1361
|
+
own Wix API: a Visitor's call still gets a 401, 403 or 428, and a screen shows its sign-in state. The descriptor is
|
|
1362
|
+
served to every device, and the One App itself sends a locked page's structure to the viewer it denies, so static
|
|
1363
|
+
content in a locked screen is not a secret. What the lock keeps is the owner's rule on the tab, for public data too.
|
|
1364
|
+
|
|
1365
|
+
**Who sees what** (decided by the worker in `tier5-src/_shared/access-gates.ts`):
|
|
1366
|
+
|
|
1367
|
+
- No rule: open. Rules by precedence: badges, then paid plans, then members only.
|
|
1368
|
+
- A Visitor is blocked by every rule and always gets the sign-in lock, with the owner's message and button when the
|
|
1369
|
+
owner set them, else the stock copy. When only members may see the lock, the tab is hidden for a Visitor and the
|
|
1370
|
+
stock copy applies.
|
|
1371
|
+
- A member opens a badge gate with one of its badge ids (`POST /badges/v4/assignments/query`, filtered to the member)
|
|
1372
|
+
and a plan gate with an active plan order of one of its plan ids (`@himalaya/checkout` `activePlanIds`). A blocked
|
|
1373
|
+
member sees the lock for the rule's own kind: a badge asks to contact the business, a plan offers the plans, or asks to
|
|
1374
|
+
contact the business when none of its plans is on offer any more.
|
|
1375
|
+
- Hidden mode removes the tab for anyone blocked. There is NO owner or admin bypass: an owner uses the owner app.
|
|
1376
|
+
- Every gate starts locked and opens only on proof. A read that fails leaves the member locked with that rule's button,
|
|
1377
|
+
except that a gate already open stays open through a failed re-read (a blip while offline). Nothing is persisted or
|
|
1378
|
+
restored: a snapshot can never open a tab. A new identity closes every gate before the next answer is read.
|
|
1379
|
+
|
|
1380
|
+
**One cost of locking a list.** A screen whose body is a paged list now has that list inside the lock's `FragmentSlot`.
|
|
1381
|
+
The descriptor check reports it as the warning `paged_list_not_at_scroll_root`: Android recycles rows only for a list
|
|
1382
|
+
that sits directly in the root column, so a long locked list is drawn without recycling. Renderers accept it and the
|
|
1383
|
+
lock works; keep a locked list short, or lock a screen that holds the list in a detail page.
|
|
1384
|
+
|
|
1385
|
+
**Differences from the One App to report.** The plans lock does not name the plans (the One App does); the badge button
|
|
1386
|
+
opens the business chat without the prefilled request message; two stock lines (`plansDescription`, `contact*`) are this
|
|
1387
|
+
repository's own, because the One App's zero-plans strings are not in any source read. Translate the stock copy through
|
|
1388
|
+
the app's catalog like any other string. A gated screen's own worker still loads while locked (the lock is a
|
|
1389
|
+
presentation rule), and an entry that is not a tab, drawer entry or a row that opens the screen directly (a button, a
|
|
1390
|
+
link, a card) is not hidden: it opens the lock. A row bound inside a screen is hidden only once the app worker has answered: a
|
|
1391
|
+
node-level `hiddenPath` has no fail-closed mode (only tab, drawer and rail entries have `hiddenUntilResolved`), so until the worker
|
|
1392
|
+
answers, or for good when it never loads, a Visitor sees that row. Opening it shows the lock, never the page.
|
|
1393
|
+
|
|
1394
|
+
**The app-wide login requirement.** The dashboard's Sign up & login switch decides whether the source app asks for a
|
|
1395
|
+
sign-in before showing anything (`visitorModeEnabled` false) or lets people browse first. `himi one-app migrate` reads it
|
|
1396
|
+
as the site's Visitor (no owner login) and saves it as `access-policy.json`, bound to the manifest hash. It is
|
|
1397
|
+
supporting context: when the source does not report it, the value is `null` and the manifest warns
|
|
1398
|
+
(`access_policy_unavailable`); unknown is never read as either answer. `himi one-app access` then turns the app's own
|
|
1399
|
+
login wall on when the source requires login: `auth` in `config.ts` becomes `requireLogin(...)`, a one-line helper
|
|
1400
|
+
written beside the imports that sets `required: true` on the provider block. With the wall on, the app shows the sign-in
|
|
1401
|
+
(the stock one, or your own gate screen) before any content, and a Visitor session does not pass it. The command never
|
|
1402
|
+
takes a wall out (`needs_manual_merge`): dropping a login requirement is yours to decide. For evidence collected before
|
|
1403
|
+
the setting was recorded, or when the owner tells you, decide it explicitly with `--login-wall required|none`; the
|
|
1404
|
+
explicit choice wins over the evidence. The wall works with or without locked pages.
|
|
1405
|
+
The wall is enforced on iOS and Android. The web host enforces a wall only for its own account mode, so a
|
|
1406
|
+
migrated app opened in the web host still shows its content to a Visitor: the command's output says so
|
|
1407
|
+
(`loginWall.notEnforcedOn`), and a web release must not rely on it. Enforcing the wall on web is a separate follow-up, not part of this command.
|
|
1408
|
+
|
|
1409
|
+
**Check on a device**, as a Visitor, as a signed-in member who has neither the badge nor the plan, and as one who has
|
|
1410
|
+
it, and record the result as the rows' `access-state` evidence. The member probe of the badge read is the one thing no
|
|
1411
|
+
source read can prove: `queryBadgeAssignments` is declared for the app identity, so confirm it answers a member session.
|
|
1412
|
+
|
|
1309
1413
|
### Screen-content contract
|
|
1310
1414
|
|
|
1311
1415
|
Use the current [screen design guide](https://apps.wix.com/_api/himi-serve/docs/designing-himi-screens.md) and the app's
|
|
@@ -5302,7 +5302,19 @@
|
|
|
5302
5302
|
"name": "AlertOptions",
|
|
5303
5303
|
"kind": "interface",
|
|
5304
5304
|
"jsdoc": "",
|
|
5305
|
-
"decl": "export interface AlertOptions {\n /** Required — the native presenters drop alerts with an empty title. */\n title: string;\n message?: string;\n /** Confirm button label. Default \"Confirm\". */\n confirmLabel?: string;\n /** Cancel button label. OMIT for a single-button alert (no cancel button). */\n cancelLabel?: string;\n /** Style the confirm button with the `danger` token. A destructive confirm is not the\n * affirmative button: its `confirm.actionId` still runs, but without gesture credit. */\n destructive?: boolean;\n /** The affirmative button's ACTION. Pressing it runs `actionId` as a NEW invocation\n * with user-gesture origin (so an app service's `app.<svc>.<action>` may return `_nav` and\n * navigate — the \"Ready — View\" alert). `label` replaces `confirmLabel`. The id is checked when\n * you set it, against this worker: a `capability.<id>.*` needs `<id>` allowed, an `app.*` from a\n * screen worker needs `app_services` and an exported action, a `tier5.*` must be this worker's\n * own; anything else rejects (`action_not_allowed`). Cancel and dismissal run nothing. */\n confirm?: AlertConfirm;\n}"
|
|
5305
|
+
"decl": "export interface AlertOptions {\n /** Required — the native presenters drop alerts with an empty title. */\n title: string;\n message?: string;\n /** Confirm button label. Default \"Confirm\". */\n confirmLabel?: string;\n /** Cancel button label. OMIT for a single-button alert (no cancel button). */\n cancelLabel?: string;\n /** Style the confirm button with the `danger` token. A destructive confirm is not the\n * affirmative button: its `confirm.actionId` still runs, but without gesture credit. */\n destructive?: boolean;\n /** The affirmative button's ACTION. Pressing it runs `actionId` as a NEW invocation\n * with user-gesture origin (so an app service's `app.<svc>.<action>` may return `_nav` and\n * navigate — the \"Ready — View\" alert). `label` replaces `confirmLabel`. The id is checked when\n * you set it, against this worker: a `capability.<id>.*` needs `<id>` allowed, an `app.*` from a\n * screen worker needs `app_services` and an exported action, a `tier5.*` must be this worker's\n * own; anything else rejects (`action_not_allowed`). Cancel and dismissal run nothing. */\n confirm?: AlertConfirm;\n /** Up to three buttons, replacing the four options above; see `AlertButtonOptions`. */\n buttons?: AlertButtonOptions[];\n}"
|
|
5306
|
+
},
|
|
5307
|
+
{
|
|
5308
|
+
"name": "AlertButtonRole",
|
|
5309
|
+
"kind": "type",
|
|
5310
|
+
"jsdoc": "/** #4659 — `\"cancel\"` (at most one) sits in the cancel position and is what dismissal by scrim, back\n * or Esc resolves as; `\"destructive\"` draws with the `danger` token. Default `\"default\"`. */",
|
|
5311
|
+
"decl": "export type AlertButtonRole = \"default\" | \"cancel\" | \"destructive\";"
|
|
5312
|
+
},
|
|
5313
|
+
{
|
|
5314
|
+
"name": "AlertButtonOptions",
|
|
5315
|
+
"kind": "interface",
|
|
5316
|
+
"jsdoc": "/** #4659 — one button of an `alert({ buttons })`. Test id `alert.<id>`; its label is the accessible\n * name. Buttons draw in platform order and the result names the one pressed (`buttonId`). With\n * `buttons`, `confirmLabel` / `cancelLabel` / `destructive` / `confirm` are not sent; `confirm` is\n * shorthand for one `role: \"default\"` button. Each `actionId` is checked when you set it exactly as\n * `confirm.actionId` is (reject, show nothing); from an app service only a `default`-role press\n * carries gesture credit. More than three buttons, more than one `cancel`, or an empty / repeated\n * `id` or empty `label` rejects `invalid_buttons`. */",
|
|
5317
|
+
"decl": "export interface AlertButtonOptions {\n id: string;\n label: string;\n role?: AlertButtonRole;\n /** Run on press, as a new invocation (see `AlertOptions.confirm`). Omit to just await the press. */\n actionId?: string;\n /** Passed to the action (JSON types kept). */\n args?: Record<string, unknown>;\n}"
|
|
5306
5318
|
},
|
|
5307
5319
|
{
|
|
5308
5320
|
"name": "AlertConfirm",
|
|
@@ -5314,7 +5326,7 @@
|
|
|
5314
5326
|
"name": "AlertResult",
|
|
5315
5327
|
"kind": "interface",
|
|
5316
5328
|
"jsdoc": "",
|
|
5317
|
-
"decl": "export interface AlertResult {\n /** true ⇒ the user tapped confirm; false ⇒ cancel or the alert was dismissed
|
|
5329
|
+
"decl": "export interface AlertResult {\n /** true ⇒ the user tapped confirm (with `buttons`: a `default`-role button); false ⇒ cancel,\n * another button, or the alert was dismissed externally (e.g. a deep-link reset cleared all\n * presented overlays). */\n confirmed: boolean;\n /** #4659 — the id of the button pressed: one of `buttons`, or `\"confirm\"` / `\"cancel\"` for the\n * legacy options. Dismissal by scrim/back/Esc resolves as the `cancel` button; with none, or when\n * the host clears the alert, it is `null`. */\n buttonId: string | null;\n}"
|
|
5318
5330
|
},
|
|
5319
5331
|
{
|
|
5320
5332
|
"name": "alert",
|
|
@@ -8722,6 +8734,44 @@
|
|
|
8722
8734
|
"jsdoc": "",
|
|
8723
8735
|
"decl": "export function updateBadgesOrder(\n req: WixUpdateBadgesOrderRequest = {} as WixUpdateBadgesOrderRequest,\n opts?: WixCallOptions,\n): Promise<WixUpdateBadgesOrderResponse>;",
|
|
8724
8736
|
"http": "PATCH /badges/v4/badges/order"
|
|
8737
|
+
},
|
|
8738
|
+
{
|
|
8739
|
+
"name": "WixBadgeAssignment",
|
|
8740
|
+
"kind": "interface",
|
|
8741
|
+
"jsdoc": "/** One badge given to one member. */",
|
|
8742
|
+
"decl": "export interface WixBadgeAssignment {\n id?: string;\n badgeId?: string;\n memberId?: string;\n createdDate?: string;\n updatedDate?: string;\n}"
|
|
8743
|
+
},
|
|
8744
|
+
{
|
|
8745
|
+
"name": "WixQueryBadgeAssignmentsRequest",
|
|
8746
|
+
"kind": "interface",
|
|
8747
|
+
"jsdoc": "",
|
|
8748
|
+
"decl": "export interface WixQueryBadgeAssignmentsRequest {\n query?: { filter?: Record<string, unknown>; cursorPaging?: WixCursorPaging };\n}"
|
|
8749
|
+
},
|
|
8750
|
+
{
|
|
8751
|
+
"name": "WixQueryBadgeAssignmentsResponse",
|
|
8752
|
+
"kind": "interface",
|
|
8753
|
+
"jsdoc": "",
|
|
8754
|
+
"decl": "export interface WixQueryBadgeAssignmentsResponse {\n badgeAssignments?: WixBadgeAssignment[];\n pagingMetadata?: WixCursorPagingMetadata;\n}"
|
|
8755
|
+
},
|
|
8756
|
+
{
|
|
8757
|
+
"name": "WixBadgeIcon",
|
|
8758
|
+
"kind": "interface",
|
|
8759
|
+
"jsdoc": "/** The badge icon exactly as the live API sends it. The generated `WixBadge.icon` is typed `string`\n * from the upstream package, but the service returns this image object. */",
|
|
8760
|
+
"decl": "export interface WixBadgeIcon {\n id?: string;\n url?: string;\n height?: number;\n width?: number;\n}"
|
|
8761
|
+
},
|
|
8762
|
+
{
|
|
8763
|
+
"name": "queryBadgeAssignments",
|
|
8764
|
+
"kind": "function",
|
|
8765
|
+
"jsdoc": "/** Which badges members hold — POST /badges/v4/assignments/query. A Visitor can read it\n * (`BADGES.BADGE_READ_MEMBERS`), so a members list can show badges without a sign-in.\n * Filter by `memberId: { $in: [...] }` and page with `cursorPaging`: a member can hold dozens of\n * badges, so one page of many members can need several calls.\n *\n * Prefer this over the generated `listMembersBadgeIds`, whose route\n * (`POST /badges/v4/badges/members`) answers 404 on the live service.\n *\n * @scope visitor — an anonymous Visitor reads it (200, observed live). The generated spec declares the app\n * identity only, so a signed-in member's read is not yet observed: an empty or refused answer means \"no badge\n * known\", never \"no badge held\". */",
|
|
8766
|
+
"decl": "export function queryBadgeAssignments(\n req: WixQueryBadgeAssignmentsRequest = {},\n opts?: WixCallOptions,\n): Promise<WixQueryBadgeAssignmentsResponse>;",
|
|
8767
|
+
"http": "POST /badges/v4/assignments/query",
|
|
8768
|
+
"scope": "visitor"
|
|
8769
|
+
},
|
|
8770
|
+
{
|
|
8771
|
+
"name": "badgeIconUrl",
|
|
8772
|
+
"kind": "function",
|
|
8773
|
+
"jsdoc": "/** The icon image URL of a badge, or \"\" when it has none. Reads the live `{ url }` object and also the\n * plain string the generated type promises, so a caller needs no cast. */",
|
|
8774
|
+
"decl": "export function badgeIconUrl(badge: Pick<WixBadge, \"icon\">): string;"
|
|
8725
8775
|
}
|
|
8726
8776
|
]
|
|
8727
8777
|
},
|
|
@@ -18893,13 +18943,13 @@
|
|
|
18893
18943
|
"name": "WixEventLocation",
|
|
18894
18944
|
"kind": "interface",
|
|
18895
18945
|
"jsdoc": "",
|
|
18896
|
-
"decl": "export interface WixEventLocation {\n /** VENUE | ONLINE
|
|
18946
|
+
"decl": "export interface WixEventLocation {\n /** VENUE | ONLINE (Events v3 `Location.LocationType`; `TBD` is not a type). */\n type?: string;\n name?: string;\n address?: string;\n}"
|
|
18897
18947
|
},
|
|
18898
18948
|
{
|
|
18899
18949
|
"name": "WixEvent",
|
|
18900
18950
|
"kind": "interface",
|
|
18901
18951
|
"jsdoc": "",
|
|
18902
|
-
"decl": "export interface WixEvent {\n id: string;\n title?: string;\n /** Normally one of `WixEventStatus` — `UPCOMING` (published and scheduled to start),\n * `STARTED`, `ENDED`, `CANCELED`, `DRAFT`. Events v1 called the first of those `SCHEDULED`,\n * and this SDK reads v3, so a row here never carries `SCHEDULED`.\n *\n * Deliberately NOT narrowed to that union: `decodeEvent` fills this from the server's\n * `status` and passes a value it does not recognise straight through, because dropping or\n * rewriting one would lose a real event. A union here would be a claim this SDK cannot\n * enforce. Compare against `WixEventStatus` when you need the set it knows. */\n eventStatus?: string;\n /** EventType: RSVP |
|
|
18952
|
+
"decl": "export interface WixEvent {\n id: string;\n title?: string;\n /** Normally one of `WixEventStatus` — `UPCOMING` (published and scheduled to start),\n * `STARTED`, `ENDED`, `CANCELED`, `DRAFT`. Events v1 called the first of those `SCHEDULED`,\n * and this SDK reads v3, so a row here never carries `SCHEDULED`.\n *\n * Deliberately NOT narrowed to that union: `decodeEvent` fills this from the server's\n * `status` and passes a value it does not recognise straight through, because dropping or\n * rewriting one would lose a real event. A union here would be a claim this SDK cannot\n * enforce. Compare against `WixEventStatus` when you need the set it knows. */\n eventStatus?: string;\n /** EventType: RSVP | TICKETING | EXTERNAL | NONE — the GA values of the v3\n * `RegistrationType.Type` enum that `decodeEvent` reads from `registration.type`.\n * (v1 spelled `TICKETING` / `NONE` as `TICKETS` / `NO_REGISTRATION`; v3 does not.) Not narrowed\n * to a union for the same reason as `eventStatus`: `decodeEvent` passes an unrecognised\n * value straight through rather than drop it. */\n eventType?: string;\n scheduling?: WixEventScheduling;\n location?: WixEventLocation;\n mainImage?: WixEventImage;\n slug?: string;\n about?: string;\n /** Events v3: a Ricos document ({@link WixEventRichContent}), returned only when the `TEXTS`\n * fieldset is requested (`getEvent(id, { fields: [\"TEXTS\"] })`). Older payloads sent a string. */\n description?: string | WixEventRichContent;\n}"
|
|
18903
18953
|
},
|
|
18904
18954
|
{
|
|
18905
18955
|
"name": "WixGetEventListResponse",
|
|
@@ -18979,7 +19029,7 @@
|
|
|
18979
19029
|
{
|
|
18980
19030
|
"name": "WixEventWrite",
|
|
18981
19031
|
"kind": "interface",
|
|
18982
|
-
"jsdoc": "/** Write shape for create/update (Events v3). Verified-minimal: a create needs\n * BOTH `name` and `title`, a `dateAndTimeSettings` window, a `location`, and a\n * `registration.initialType` (RSVP |
|
|
19032
|
+
"jsdoc": "/** Write shape for create/update (Events v3). Verified-minimal: a create needs\n * BOTH `name` and `title`, a `dateAndTimeSettings` window, a `location`, and a\n * `registration.initialType` (RSVP | TICKETING in Events v3\n * `InitialRegistrationType.Type`). */",
|
|
18983
19033
|
"decl": "export interface WixEventWrite {\n name?: string;\n title?: string;\n dateAndTimeSettings?: { startDate?: string; endDate?: string; timeZoneId?: string };\n location?: { type?: string; name?: string };\n registration?: { initialType?: string };\n mainImage?: WixEventImage;\n about?: string;\n /** Ricos document; replaces the whole description. */\n description?: WixEventRichContent;\n}"
|
|
18984
19034
|
},
|
|
18985
19035
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1624.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": [
|
|
@@ -72,5 +72,5 @@
|
|
|
72
72
|
"artifactId": "himalaya-cli"
|
|
73
73
|
}
|
|
74
74
|
},
|
|
75
|
-
"falconPackageHash": "
|
|
75
|
+
"falconPackageHash": "8b49e7e93dbedda48e52f25013bfc1733182135023026eb82f93a5be"
|
|
76
76
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// This app's access gates: the One App page rules (members only, badge, paid plan) the app keeps.
|
|
2
|
+
//
|
|
3
|
+
// EMPTY in a scaffold, and then nothing in `access-gates.ts` reads or publishes anything. `himi one-app access`
|
|
4
|
+
// replaces this file for a migrated One App whose source locks a page; do not edit it by hand, re-run the command
|
|
5
|
+
// (it is idempotent).
|
|
6
|
+
import type { AccessGate } from "./access-gates.js";
|
|
7
|
+
|
|
8
|
+
export const ACCESS_GATES: readonly AccessGate[] = [];
|