@wix/himalaya-cli 0.1480.0 → 0.1481.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/dev-server/src/app-module.d.ts +1 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/builder.d.ts +3 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/state/src/index.d.ts +47 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/app-services-gate.d.ts +86 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/bindings.d.ts +22 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/define-app.d.ts +10 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/index.d.ts +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/schema.d.ts +35 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/validator.d.ts +87 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/core.mjs +148 -3
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/sdui.mjs +34 -4
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/state.mjs +95 -0
- package/dist/cli.mjs +1733 -1175
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/component-reference.json +1 -1
- package/guides/component-reference.md +4 -0
- package/guides/sdk-reference.json +32 -2
- package/guides/tier-5-add-a-screen.md +50 -2
- package/package.json +2 -2
- package/templates/beauty-salon-owner/dev/index.ts +624 -59
- package/templates/community-club-owner/dev/index.ts +599 -57
- package/templates/events-meetups-owner/dev/index.ts +543 -52
- package/templates/gym-fitness-owner/dev/index.ts +649 -61
- package/templates/nonprofit-cause-owner/dev/index.ts +593 -56
- package/templates/owner-lite/dev/index.ts +698 -67
- package/templates/podcast-creator-owner/dev/index.ts +599 -57
- package/templates/portfolio-creative-owner/dev/index.ts +624 -59
- package/templates/restaurant-owner/dev/index.ts +649 -61
- package/templates/retail-store-owner/dev/index.ts +574 -55
- package/templates/yoga-studio-owner/dev/index.ts +593 -56
|
Binary file
|
|
@@ -1271,7 +1271,7 @@
|
|
|
1271
1271
|
}
|
|
1272
1272
|
],
|
|
1273
1273
|
"descriptor": {
|
|
1274
|
-
"ScreenDescriptor": "export interface ScreenDescriptor {\n screenId: string;\n renderer: RendererKind;\n title?: string;\n /** Present when `renderer` is `sdui_intent` or `sdui_layout`. */\n payload?: Component;\n /** A component pinned ABOVE the scrolling payload (sticky tab-header / toolbar).\n * Rendered by the host outside the screen scroll, so it stays put as content\n * scrolls. Optional; absent = no sticky header. */\n stickyHeader?: Component;\n /** A component pinned BELOW the scrolling payload (sticky footer — price/confirm\n * bar, peeking bottom-sheet). Rendered outside the screen scroll by the host. */\n stickyFooter?: Component;\n /** When true, the host wraps the screen in a scroll that starts pinned to the\n * bottom and shows a floating \"jump to latest\" button whenever the user scrolls\n * up (a chat transcript). Tapping it animates back to the bottom. Absent/false =\n * a normal top-anchored scroll. Honored by the app host (Router). */\n scrollToBottom?: boolean;\n /** The chat transcript scroll policy. On a send the host pins the\n * named component near the top and reserves the space the reply grows into;\n * when the reply outgrows it the host follows the tail. A drag pauses\n * following, and only then is a jump-to-latest control shown. */\n transcriptScroll?: TranscriptScroll;\n /** Present when `renderer` is `webview_native_bridge` or `webview_ds`. */\n url?: string;\n capabilitiesRequired?: string[];\n schemaVersion: number;\n togglesApplied?: string[];\n /** Per-session flag/experiment assignments baked in for this request. */\n assignments?: import(\"./flags.js\").Assignment[];\n /** Per-screen top bar (trailing actions +\n * leading/style override). Fully replaces `NavigationConfig.topBarDefault`. */\n topBar?: TopBarConfig;\n etag?: string;\n cacheControl?: CacheControl;\n telemetryScreenName?: string;\n bundleSri?: string;\n manifestVersion?: number;\n /**\n * Present on Tier-5 screens. The presence of this field is the tier-5\n * signal — there is no separate `tier: 5` flag.\n */\n logicBundle?: LogicBundleRef;\n /**\n * Static per-screen input injected as `globalThis.himalaya.input` before the\n * Tier-5 worker bundle evaluates — the worker reads it synchronously in `load()`\n * (e.g. `himalaya.input.id` for a detail screen, or a baked catalog like\n * `himalaya.input.cmsCollections`).\n *\n * A push merges its navigation parameters into this object on web, iOS, and Android.\n * For example, `himi.open({ screenId: \"event\", id: \"$item.id\" })` makes the id\n * available as `himalaya.input.id` in the pushed worker; static `input` remains the\n * fallback for values baked into a descriptor or a templated route. The host also\n * supplies `screenId`. See docs/tier-5-add-a-screen.md → \"Navigate to a detail screen\".\n *\n * Arbitrary JSON object; consumed by the web host (ScreenController) and the\n * native JSWorker.\n */\n input?: Record<string, unknown>;\n /**\n * Tier 3 / Tier 4 — behavior of the hosted WebView. Ignored by SDUI tiers.\n * Authored in the descriptor builder (git); served OTA verbatim.\n */\n webViewConfig?: WebViewConfig;\n}",
|
|
1274
|
+
"ScreenDescriptor": "export interface ScreenDescriptor {\n screenId: string;\n renderer: RendererKind;\n title?: string;\n /** Present when `renderer` is `sdui_intent` or `sdui_layout`. */\n payload?: Component;\n /** A component pinned ABOVE the scrolling payload (sticky tab-header / toolbar).\n * Rendered by the host outside the screen scroll, so it stays put as content\n * scrolls. Optional; absent = no sticky header. */\n stickyHeader?: Component;\n /** A component pinned BELOW the scrolling payload (sticky footer — price/confirm\n * bar, peeking bottom-sheet). Rendered outside the screen scroll by the host. */\n stickyFooter?: Component;\n /** When true, the host wraps the screen in a scroll that starts pinned to the\n * bottom and shows a floating \"jump to latest\" button whenever the user scrolls\n * up (a chat transcript). Tapping it animates back to the bottom. Absent/false =\n * a normal top-anchored scroll. Honored by the app host (Router). */\n scrollToBottom?: boolean;\n /** The chat transcript scroll policy. On a send the host pins the\n * named component near the top and reserves the space the reply grows into;\n * when the reply outgrows it the host follows the tail. A drag pauses\n * following, and only then is a jump-to-latest control shown. */\n transcriptScroll?: TranscriptScroll;\n /** The page's title for a host that shows it in its own navigation bar (iOS `himalayaEmbedTitle`, Android\n * `ProvideHimalayaEmbedTitle`): it gets the title as soon as it has the descriptor, before the worker boots, and\n * `replaces` is not drawn. Every other host ignores it, so the in-content header stays. */\n hostTitle?: HostTitle;\n /** Present when `renderer` is `webview_native_bridge` or `webview_ds`. */\n url?: string;\n capabilitiesRequired?: string[];\n schemaVersion: number;\n togglesApplied?: string[];\n /** Per-session flag/experiment assignments baked in for this request. */\n assignments?: import(\"./flags.js\").Assignment[];\n /** Per-screen top bar (trailing actions +\n * leading/style override). Fully replaces `NavigationConfig.topBarDefault`. */\n topBar?: TopBarConfig;\n etag?: string;\n cacheControl?: CacheControl;\n telemetryScreenName?: string;\n bundleSri?: string;\n manifestVersion?: number;\n /**\n * Present on Tier-5 screens. The presence of this field is the tier-5\n * signal — there is no separate `tier: 5` flag.\n */\n logicBundle?: LogicBundleRef;\n /**\n * Static per-screen input injected as `globalThis.himalaya.input` before the\n * Tier-5 worker bundle evaluates — the worker reads it synchronously in `load()`\n * (e.g. `himalaya.input.id` for a detail screen, or a baked catalog like\n * `himalaya.input.cmsCollections`).\n *\n * A push merges its navigation parameters into this object on web, iOS, and Android.\n * For example, `himi.open({ screenId: \"event\", id: \"$item.id\" })` makes the id\n * available as `himalaya.input.id` in the pushed worker; static `input` remains the\n * fallback for values baked into a descriptor or a templated route. The host also\n * supplies `screenId`. See docs/tier-5-add-a-screen.md → \"Navigate to a detail screen\".\n *\n * Arbitrary JSON object; consumed by the web host (ScreenController) and the\n * native JSWorker.\n */\n input?: Record<string, unknown>;\n /**\n * Tier 3 / Tier 4 — behavior of the hosted WebView. Ignored by SDUI tiers.\n * Authored in the descriptor builder (git); served OTA verbatim.\n */\n webViewConfig?: WebViewConfig;\n}",
|
|
1275
1275
|
"Component": "export interface Component {\n id: string;\n body: ComponentBody;\n modifiers?: Modifiers;\n minVersion?: number;\n}",
|
|
1276
1276
|
"LogicBundleRef": "export interface LogicBundleRef {\n url: string;\n /** \"sha256-...\" SRI string. */\n integrity: string;\n contentType?: string;\n /** SDK capability ids the bundle is permitted to import / invoke. */\n declaredCapabilities: string[];\n /** Bundle refuses to load on a binary older than this (semver). */\n minBinaryVersion?: string;\n /** Bundle's own semver. */\n bundleVersion?: string;\n /** Base64 detached publisher signature over the bundle bytes\n * (authenticity beyond SRI). Verified by a host-injected verifier when present;\n * unsigned bundles load as today. */\n signature?: string;\n /** The publisher key id a host pins, paired with `signature`. */\n keyId?: string;\n /** Ambient refresh (gap G2): the host invokes `action` (a `tier5.<svc>.<action>`\n * path) every `intervalMs` while the screen is visible — workers have no timer\n * of their own, so the host owns the cadence. */\n refresh?: { intervalMs: number; action: string };\n}",
|
|
1277
1277
|
"Modifiers": "export interface Modifiers {\n padding?: EdgeInsets;\n background?: TokenRef;\n cornerRadius?: number;\n /** Fixed intrinsic width (pt/dp/px). Honored by iOS (`FrameIfPresent`), Android\n * (frame) and web (`modifiers.ts`). With no `ScrollView` in the vocabulary and\n * regions clipped at `maxHeight`, `width`/`height`/`fillMaxWidth` are the main\n * sizing tools for embed/host content. */\n width?: number;\n /** Fixed intrinsic height (pt/dp/px). See `width`. */\n height?: number;\n /** Fill the available cross-axis width (keeps any fixed `height`). Mirrors\n * Compose `fillMaxWidth` / SwiftUI `.frame(maxWidth: .infinity)`. See `width`. */\n fillMaxWidth?: boolean;\n /** CAP the node's laid-out width at this many points. It CONSTRAINS, it\n * does not SET: a node narrower than the cap keeps its intrinsic width, so a\n * short chat bubble stays short while a long one stops at the cap — the\n * asymmetry `width` cannot express and `weight` cannot either (weights divide\n * the *available* space, so every child lands on the same fraction).\n * The cap covers the node's TOTAL width, padding + border included (CSS\n * `max-width` under `box-sizing: border-box`). `fillMaxWidth` grabs the axis but\n * THE CAP WINS — fill + cap is exactly `maxWidth` wide; a literal `width` larger\n * than the cap is clamped to it too. POINTS, not a fraction: a modifier is\n * resolved with no portable notion of \"the row\" on any renderer — compose a\n * percentage from a weighted sibling gap instead. `0`/absent = no cap. */\n maxWidth?: number;\n /** Flex weight along the parent stack's MAIN axis (HStack = width, VStack =\n * height). The stack measures its intrinsic (unweighted) children first, then\n * divides what is LEFT among the weighted ones in proportion to their weights:\n * two children at `1` split the leftover equally, `2` and `1` split it 2:1.\n * Absent (or <= 0) keeps the node at its intrinsic size. Use this — not\n * `fillMaxWidth` — when a node should claim the remaining space *beside* its\n * siblings; a full-bleed fill grabs the whole axis and starves them. Ignored\n * outside an HStack/VStack.\n * CAVEAT — row-sharing controls have NO intrinsic width to measure first: in an\n * HStack a `Button` and a `Toggle` are implicitly weighted, so they DIVIDE the\n * row with your weighted child instead of taking a width ahead of it —\n * `[VStack(weight:1), Button, Button]` is a three-way split, not \"the VStack gets\n * the remainder\". To opt a Button out on EVERY renderer set `fullWidth: false`\n * (an explicit flag wins in both directions; absent falls back to the style\n * default, which is \"share\" for every style but `tertiary`/`link`), or use\n * `iconOnly`. Otherwise give the actions their own row.\n * See `himi docs designing-himi-screens` §4. */\n weight?: number;\n /** RTL — pin the subtree's writing direction: `\"ltr\"` | `\"rtl\"` | `\"locale\"`\n * (inherit). The common RTL pattern is the inverse of `Text.textDirection`: pin a\n * container `ltr` (a logotype, an attachment-tile row, a composer button row)\n * inside an otherwise-RTL screen. Absent = inherit the ambient direction. #1060. */\n layoutDirection?: \"ltr\" | \"rtl\" | \"locale\";\n /** Absolute visual translation (pt/dp/px). Applied as the OUTERMOST transform so\n * it shifts the fully-styled node WITHOUT changing its layout footprint — lets a\n * ZStack place polar/absolute children (e.g. AgentOrbit). Negative allowed. */\n offsetX?: number;\n offsetY?: number;\n onTap?: Action;\n /** Double-tap gesture (e.g. Instagram double-tap-to-like). Distinct from onTap. */\n onDoubleTap?: Action;\n accessibilityLabel?: string;\n hidden?: boolean;\n /** Data-bound conditional visibility: a `\"$service:<svc>.<field>\"`\n * or `\"$item.<field>\"` sentinel resolving to a bool at render; when true the\n * subtree fully COLLAPSES (zero layout, like `hidden`), overriding the\n * literal `hidden`. */\n hiddenPath?: string;\n /** Long-press gesture modifier. */\n onLongPress?: Action;\n /** Fires once when the component first appears on screen. */\n onAppear?: Action;\n /** Scoped token overrides for the subtree. */\n theme?: ThemeOverrides;\n /** Names a token from the app's `shadows` registry. */\n shadow?: TokenRef;\n /** Names a token from the app's `gradients` registry (background fill). */\n backgroundGradient?: TokenRef;\n /** Value-driven gradient: a `$service:`/`$item.` path resolving to a gradient\n * TOKEN NAME used as the live background (e.g. weather sky day→night). */\n backgroundGradientPath?: string;\n /** Value-driven background COLOR: a `$service:`/`$item.` path resolving to a\n * color TOKEN NAME used as the live background. Honored on iOS + Android\n * (`BoundBackgroundIfPresent`); web render support is tracked in #1057. */\n backgroundColorPath?: string;\n /** Value-driven background IMAGE: a `$service:`/`$item.` path resolving to an\n * image URL used as the live background. Honored on iOS + Android; web render\n * support is tracked in #1057. */\n backgroundImagePath?: string;\n /** #1051 — MEASURE (publish): report this node's laid-out size into the renderer's\n * self-contained (worker-free) measure store under the named keys, so a SIBLING can\n * feed the number back into its own layout via a `$measure:<key>` binding. The SDUI\n * equivalent of SwiftUI `.onGeometryChange` / Compose `onGloballyPositioned`; the\n * canonical use is a pinned bottom bar whose measured height becomes a scroll view's\n * bottom inset (sticky-footer + scroll-inset, unrepresentable before — #1051). */\n onMeasure?: Measure;\n /** #1051 — bound height: a `\"$measure:<key>\"` (measure store) or\n * `\"$service:<svc>.<field>\"` / `\"$item.<field>\"` (worker/row state) sentinel resolving\n * to a NUMBER at render. Wins over the literal `height`. String path only, so a\n * binding can never blank the node (never overload the numeric `height`). */\n heightPath?: string;\n /** #1051 — bound width. See `heightPath`. Wins over the literal `width`. */\n widthPath?: string;\n /** #1051 — bound TOP inset (the header-height → top-inset idiom). A `$measure:`/\n * `$service:`/`$item.` sentinel resolving to a number; added as top padding. */\n paddingTopPath?: string;\n /** #1051 — bound BOTTOM inset (the sticky-footer-height → bottom-inset idiom). A\n * `$measure:`/`$service:`/`$item.` sentinel resolving to a number; added as bottom\n * padding so the last scroll row clears a pinned bottom bar. */\n paddingBottomPath?: string;\n /** #1053 — INLINE gradient background paint. Distinct from `backgroundGradient`\n * (which names a `gradients` registry token an embed host can't register): this\n * carries its stops/colours in the descriptor, so it works anywhere. Painted as\n * a surface (behind children), below `material`/`backgroundGradient` if those are\n * also set. */\n gradient?: Gradient;\n /** #1053 — gradient ALPHA MASK: the node shows through where the gradient is\n * opaque and fades where it's transparent (a transparent-token stop = fully\n * clear). The material-under-gradient-scrim / scroll-fade-out idiom. Mirrors iOS\n * `.mask()`, Android `BlendMode.DstIn`, web `mask-image`. */\n mask?: Gradient;\n /** Inline border/stroke. */\n border?: Border;\n /** Subtree alpha 0.0–1.0; absent = opaque. */\n opacity?: number;\n /** #433 — constrain the subtree to a width:height ratio (e.g. `1` = square,\n * `1.777` = 16:9). Width-driven: the height derives from the resolved width.\n * Lets a data-bound Grid cell / photo tile hold its shape at any width. */\n aspectRatio?: number;\n /** Names a token from the app's `motions` registry; the subtree\n * fades + slides up on first appearance. */\n appear?: TokenRef;\n /** Surface material token (flat/glass/frosted). */\n material?: TokenRef;\n /** Per-node construction-language override. */\n variant?: string;\n /** Per-node density / motion override. */\n density?: string;\n motion?: string;\n /** Motion grammar (Batch 1) — press/tap feedback style\n * (auto|none|scale|highlight|scaleHighlight|lift); timing comes from `motion`.\n * Applied only when the node is interactive. Unknown degrades to `auto`. */\n pressFeedback?: string;\n /** Motion grammar (Batch 1) — press-coupled haptic\n * (none|selection|light|medium|heavy|success|warning|error); fires with onTap.\n * Default none (opt-in). Web is a no-op. */\n haptic?: string;\n /** Motion grammar (Batch 1) — animate this container's size changes instead of\n * snapping (iOS `.animation(value:)`, Android `animateContentSize`, web height\n * transition). Curve from the active `motion` personality. */\n animateContentSize?: boolean;\n /** Motion grammar (Batch 1) — enter/exit transition; supersedes `appear` when\n * both are present. */\n transition?: Transition;\n /** Motion grammar (Batch 2, scroll-driven) — defer the `transition` enter until\n * the node first crosses into the scroll viewport (reveal-on-scroll). Gated by\n * reduced motion (shown immediately when reduced). */\n revealOnScroll?: boolean;\n /** Motion grammar (Batch 2, scroll-driven) — parallax factor: the node drifts\n * vertically at this fraction of the scroll delta as it moves through the\n * viewport. Gated by reduced motion. Generalizes CollapsingHeader parallaxFactor. */\n parallax?: number;\n /** Motion grammar (Batch 4, rich visual) — when a backgroundGradient is present,\n * continuously drift/rotate it (animated gradient). Gated by reduced motion. */\n animatedGradient?: boolean;\n /** Motion grammar (Batch 3, hero/nav) — shared-element key: a matching\n * transitionId on the source + destination screen morphs that element across\n * navigation (web View Transitions / iOS matchedTransitionSource / Android\n * SharedTransitionLayout). Gated by reduced motion. */\n transitionId?: string;\n /** Motion grammar (Batch 4, rich visual) — render the backgroundGradient as a\n * mesh (overlapping multi-point blend) rather than a linear sweep; combine with\n * animatedGradient to drift it. */\n meshGradient?: boolean;\n /** Motion grammar (Batch 4, celebration) — burst a one-shot confetti overlay\n * within the node on appear. Gated by reduced motion. */\n confetti?: boolean;\n /** Motion grammar (Batch 2, scroll-driven) — pin this node to the top of its\n * scroll container (sticky section header). Functional positioning; not gated\n * by reduced motion. */\n sticky?: boolean;\n /** Motion grammar (Batch 2, scroll-driven) — turn this thin node into a\n * reading-progress bar that fills left→right with scroll (scaleX). web reads\n * window scroll; native reads the host scroll fraction. Functional. */\n scrollProgress?: boolean;\n /** Motion grammar (Batch 4, rich vector) — a named built-in vector animation\n * (\"loader\" | \"success\" | \"pulse\"), dependency-free. Gated by reduced motion.\n * Arbitrary Lottie/Rive JSON is the lib-backed superset follow-up. */\n vectorAnim?: string;\n /** Motion grammar (Batch 1, choreography) — delay this node's ENTER transition\n * by N ms so a screen can SEQUENCE its entrance beyond list stagger (\"title\n * fades, subtitle slides in 100ms later\"). Adds to any list `staggerMs`. Gated\n * by reduced motion. 0/absent = no extra delay. */\n enterDelayMs?: number;\n /** Motion grammar (Phase-3, per-node MotionSpec) — overrides the PRESS-feedback\n * curve with a `motions`-registry token, mirroring `Transition.motion` for the\n * enter curve. Absent → press uses the global `motion` personality. */\n pressMotion?: TokenRef;\n /** Motion grammar (Phase-3, gesture-driven) — finger-tracked drag-to-dismiss; past\n * threshold along `direction` it animates off and fires `action`, else springs back. */\n swipeDismiss?: SwipeDismiss;\n /** Motion grammar (Phase-4, reduced-motion) — per-node escape from the reduced-motion\n * gate. Default true (respect). false = \"must move anyway\" (transition/press animate\n * even when reduced motion is on). */\n respectReducedMotion?: boolean;\n /** #1052 — uniform scale (1 = no change). */\n scale?: number;\n /** #1052 — rotation in DEGREES. */\n rotation?: number;\n /** #1052 — stacking order within a ZStack/overlay. */\n zIndex?: number;\n /** #1052 — gaussian blur radius (pt/dp/px). */\n blur?: number;\n /** #1052 — `false` = decorative (ignores taps, unlike `hidden` which stays hit-testable);\n * `true` = force hit-testable (a clear tap target). */\n hitTestable?: boolean;\n /** #1052 — explicit drop shadow (colour + radius + offset), for upward / multi-layer\n * shadows the `shadow` token can't express. */\n boxShadow?: Shadow;\n /** The role assistive technology should announce. Absent = the\n * renderer INFERS it from the component type, so an author never restates the\n * obvious. `\"decorative\"` is node-local: the node itself stops being an\n * accessibility element (no role, not a stop) while its children stay\n * traversable — the ARIA `role=\"presentation\"` semantic. To remove the subtree\n * too, use `accessibilityHidden`. */\n accessibilityRole?: AccessibilityRole;\n /** The supplementary \"what happens if I act\" phrase\n * (iOS `accessibilityHint`, Android `onClickLabel`, ARIA `aria-describedby`).\n * Never a substitute for `accessibilityLabel`: AT may not speak a hint at all. */\n accessibilityHint?: string;\n /** Remove this node AND its subtree from the accessibility tree.\n * Distinct from `hidden` (which removes it visually too) and from the\n * `\"decorative\"` role (node-local; children stay reachable). */\n accessibilityHidden?: boolean;\n /** Mark the node as a heading at level 1–6, for rotor / heading\n * navigation. Implies the `\"heading\"` role when `accessibilityRole` is absent.\n * The LEVEL reaches iOS and web only: Android (Compose `heading()`) and React Native\n * (`accessibilityRole: \"header\"`) have no level primitive and mark a plain heading. */\n headingLevel?: number;\n /** An explicit SPOKEN value where the visual and spoken values\n * differ (a rating \"3 of 5\", a gauge \"72 percent\"). Where the value is derivable\n * from a prop the renderer computes it and this override is unnecessary. */\n accessibilityValue?: string;\n /** Additive state that a single role cannot carry. A node may\n * hold several. */\n accessibilityTraits?: AccessibilityTrait[];\n /** Explicit traversal index within the nearest focus group. Absent ⇒\n * the arm's visual / DOM order. The lower index is reached FIRST, which is why iOS\n * (whose `accessibilitySortPriority` is descending) negates it. */\n focusOrder?: number;\n /** This node's subtree is ONE traversal scope: children are ordered\n * relative to each other, then the group takes its parent's slot (iOS\n * `shouldGroupAccessibilityChildren`, Android `isTraversalGroup`, ARIA grouping). */\n focusGroup?: boolean;\n /** AT / keyboard focus lands here when the screen or a newly presented\n * modal appears. At most one per focus scope. */\n initialFocus?: boolean;\n /** A general live-region announcement, on any node and any transition.\n * The generalization of `FragmentSlotCase.accessibilityAnnouncement`, which only ever\n * fired on a fragment-slot case swap. */\n announce?: LiveRegion;\n /** Clip ANY node (content + surface) to a shape:\n * \"rectangle\" | \"roundedRectangle\" | \"capsule\" | \"circle\" | \"ellipse\". Unknown/empty =\n * no shape clip (`cornerRadius` keeps its meaning). When set it replaces the\n * corner-radius-only clip; a \"roundedRectangle\" uses `clipCornerRadii`, else `cornerRadius`. */\n clipShape?: string;\n /** Uneven corner radii for `clipShape: \"roundedRectangle\"`. */\n clipCornerRadii?: CornerRadii;\n /** A recurring, finite, transform-only motion on a decorative node: a\n * living character's idle `hop`, a `blink`, a working `breathe`. Never changes the\n * node's layout footprint. Stopped by reduced motion unless `respectReducedMotion`\n * is false. */\n ambientMotion?: AmbientMotion;\n}",
|
|
@@ -2301,6 +2301,10 @@ export interface ScreenDescriptor {
|
|
|
2301
2301
|
* when the reply outgrows it the host follows the tail. A drag pauses
|
|
2302
2302
|
* following, and only then is a jump-to-latest control shown. */
|
|
2303
2303
|
transcriptScroll?: TranscriptScroll;
|
|
2304
|
+
/** The page's title for a host that shows it in its own navigation bar (iOS `himalayaEmbedTitle`, Android
|
|
2305
|
+
* `ProvideHimalayaEmbedTitle`): it gets the title as soon as it has the descriptor, before the worker boots, and
|
|
2306
|
+
* `replaces` is not drawn. Every other host ignores it, so the in-content header stays. */
|
|
2307
|
+
hostTitle?: HostTitle;
|
|
2304
2308
|
/** Present when `renderer` is `webview_native_bridge` or `webview_ds`. */
|
|
2305
2309
|
url?: string;
|
|
2306
2310
|
capabilitiesRequired?: string[];
|
|
@@ -10,6 +10,12 @@
|
|
|
10
10
|
"jsdoc": "",
|
|
11
11
|
"decl": "export interface ServiceDefinition<S> {\n /** Initial state for the service. Must be JSON-serializable. */\n state: S;\n\n /**\n * Actions: pure functions of `(state, ...args) → newState` (or async). The\n * platform wraps each action so calling it from JS or from `__invokeAction`\n * (native side) updates the service's state and notifies subscribers.\n */\n actions?: Record<\n string,\n // `never[]`, not `unknown[]` — same reason as defineService's constraint below:\n // parameters are contravariant, so `unknown[]` rejects every handler that narrows\n // its payload. Leaving this one loose would reintroduce the same TS2344 for anyone\n // who annotates a `ServiceDefinition<S>` explicitly instead of inferring it.\n (state: S, ...args: never[]) => S | undefined | Promise<S | undefined>\n >;\n\n /**\n * Keys a cold boot takes from `state`, never from the persisted snapshot (cold-boot\n * hydration). For UI state that must describe THIS run — an editor's one-shot seed, a\n * \"still loading\" gate, an open sheet — where last run's value would be wrong, not just stale.\n * Runtimes that honour it set `himalaya.hydrationOptOut`; an older one ignores the option.\n */\n notHydrated?: readonly (keyof S & string)[];\n\n /**\n * Keys that start each VISIT from `state`: when a cached embed shows the screen again (its warm worker\n * reclaimed), these go back to their declared values before the screen reloads. For the same kind of\n * per-run UI state as `notHydrated` (an editor's one-shot seed, an open sheet); never data a returning\n * screen should keep showing. A cold boot never restores them either. A full app's own screens and an\n * uncached embed ignore the reset.\n */\n perVisit?: readonly (keyof S & string)[];\n}"
|
|
12
12
|
},
|
|
13
|
+
{
|
|
14
|
+
"name": "ServiceExports",
|
|
15
|
+
"kind": "interface",
|
|
16
|
+
"jsdoc": "/**\n * App services — `defineService(name, { …, exports })`: what SCREEN-WORKER code may reach when this\n * service is an app service (a `defineService` in the app's `app.logicBundle`). `app.dispatch` to an\n * action not listed, and `app.read` of a path not under a listed state entry, reject `not_exported`.\n * Each `state` entry is a top-level state key or a dotted path under one. Descriptor `$app:` bindings\n * and descriptor-authored `app.*` actions are app-authored and NOT limited by it. Ignored in a screen\n * bundle. The validator checks every entry exists. `A` narrows `actions` to the service's own names.\n *\n * Typed on `defineService`'s parameter, NOT on `ServiceDefinition<S>`: there it would be\n * `ServiceExports<S, Record<string, unknown>>`, and a helper that spreads a `ServiceDefinition<S>`\n * into `defineService` would fail to assign `string[]` to the narrowed action names.\n */",
|
|
17
|
+
"decl": "export interface ServiceExports<S, A = Record<string, unknown>> {\n actions?: readonly (keyof A & string)[];\n state?: readonly ((keyof S & string) | `${keyof S & string}.${string}`)[];\n}"
|
|
18
|
+
},
|
|
13
19
|
{
|
|
14
20
|
"name": "ServiceHandle",
|
|
15
21
|
"kind": "interface",
|
|
@@ -86,7 +92,31 @@
|
|
|
86
92
|
"name": "defineService",
|
|
87
93
|
"kind": "function",
|
|
88
94
|
"jsdoc": "/**\n * Register a service. The returned object exposes `getState()` and one method\n * per action; calling an action method awaits the action and returns the new\n * state.\n */\n/**\n * The action-map constraint uses `...args: never[]`, NOT `...args: unknown[]`.\n *\n * `unknown[]` looks stricter and is in fact useless here: parameters are\n * contravariant, so a handler declared `(s: State, id?: string) => State` is not\n * assignable to `(s: State, ...args: unknown[]) => State`, and EVERY action map\n * that narrows its payload — which is every well-typed one — failed the constraint\n * with TS2344. That was 102 of the 240 errors the Tier-5 typecheck lane found, and\n * worse than noise: the constraint failed before tsc ever looked INSIDE the\n * handlers, masking ~118 genuine errors in their bodies. `never[]` is the standard\n * \"any function shape\" constraint and lets that checking through.\n *\n * The RETURN side matters too: it is `Promise<S | undefined>`, not\n * `Promise<S> | Promise<undefined>`. Those are different types — a union of promises is\n * not a promise of a union — so an async action with a conditional `return undefined`\n * (the stale-generation guard several workers use to drop an out-of-order refresh)\n * inferred `Promise<S | undefined>` and failed the old constraint. The new spelling\n * subsumes all four original cases.\n *\n * THE TRADE-OFF, stated plainly. `never[]` is the standard \"any function shape\"\n * constraint, but it is also the CONTEXTUAL type for an unannotated payload param — so in\n * the inference form (`defineService(name, def)`, no explicit type args) an unannotated\n * `(s, v) => ({ ...s, query: v })` types `v` as `never`, which is assignable to anything\n * and therefore checks nothing. `unknown[]` checked that one case and broke every handler\n * that narrows its payload — 102 diagnostics — while ALSO hiding the errors inside their\n * bodies, so it was strictly worse. The mitigation is to annotate: the explicit\n * `defineService<S, {...}>` form (used by every worker in tier5-bundles-src) is fully\n * checked, and the two inference-form workers in members-library annotate their params, so\n * nothing is exposed today. Prefer the explicit form in new workers.\n *\n * Types only — the runtime registration below is untouched.\n */",
|
|
89
|
-
"decl": "export function defineService<S, A extends Record<string, (s: S, ...args: never[]) => S | undefined | Promise<S | undefined>>>(\n name: string,\n def: ServiceDefinition<S> & { actions?: A }\n): ServiceHandle<S> & {\n [K in keyof A]: (...args: Parameters<A[K]> extends [unknown, ...infer R] ? R : never[]) => Promise<S>\n};"
|
|
95
|
+
"decl": "export function defineService<S, A extends Record<string, (s: S, ...args: never[]) => S | undefined | Promise<S | undefined>>>(\n name: string,\n def: ServiceDefinition<S> & { actions?: A; exports?: ServiceExports<S, A> }\n): ServiceHandle<S> & {\n [K in keyof A]: (...args: Parameters<A[K]> extends [unknown, ...infer R] ? R : never[]) => Promise<S>\n};"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"name": "AppServiceErrorCode",
|
|
99
|
+
"kind": "type",
|
|
100
|
+
"jsdoc": "/** Why an app-service call could not run. Mirrors `APP_SERVICE_ERROR_CODES` in `@himalaya/core`. */",
|
|
101
|
+
"decl": "export type AppServiceErrorCode = \"not_booted\" | \"unavailable\" | \"no_service\" | \"no_action\" | \"not_exported\" | \"undeclared\";"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"name": "AppServiceError",
|
|
105
|
+
"kind": "type",
|
|
106
|
+
"jsdoc": "/**\n * The rejection `app.read` / `app.dispatch` produce: an `Error` named `AppServiceError` with a\n * `code`. Never a null result — \"nothing ran\" always rejects. A plain `Error` rather than a\n * subclass, because worker bundles target an engine floor that has no `class` syntax.\n */",
|
|
107
|
+
"decl": "export type AppServiceError = Error & { readonly code: AppServiceErrorCode };"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"name": "isAppServiceError",
|
|
111
|
+
"kind": "function",
|
|
112
|
+
"jsdoc": "/** Is this an `app.read` / `app.dispatch` rejection? Narrows to {@link AppServiceError}. */",
|
|
113
|
+
"decl": "export function isAppServiceError(err: unknown): err is AppServiceError;"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"name": "app",
|
|
117
|
+
"kind": "const",
|
|
118
|
+
"jsdoc": "/**\n * The app's services, from a SCREEN worker. Requires the bundle to declare the\n * `app_services` capability, and an app whose minimum binary ships app services.\n */",
|
|
119
|
+
"decl": "export const app = {\n /**\n * A read-only, point-in-time JSON copy of an exported app-service path (`\"jobs.active\"`).\n * Resolves `undefined` only for an exported path that is unset; rejects with an\n * {@link AppServiceError} when it cannot answer.\n */\n read(path: string): Promise<unknown> {\n return Promise.resolve()\n .then(() => checkAppTarget(\"path\", path))\n .then((p) => callAppBridge(\"__himalaya_app_read\", `app.read(\"${p}\")`, [p]));\n },\n /**\n * Run an exported app-service action (`\"jobs.start\"`) and resolve with its result payload\n * (never its state). Rejects with an {@link AppServiceError} when the call cannot run, so\n * \"it started\" can never be confused with \"nothing ran\".\n */\n dispatch(action: string, args?: unknown): Promise<unknown> {\n // Serialized AT the call, so a caller reusing one args object in a loop sends each value it\n // passed, and an unserializable one rejects with the coded error rather than a bare TypeError.\n let argsJson: string | undefined;\n let why = \"\";\n try {\n argsJson = args === undefined ? \"\" : JSON.stringify(args);\n } catch (err) {\n why = `: ${String((err as Error)?.message ?? err)}`;\n }\n // `JSON.stringify` answers `undefined` (no throw) for a top-level function or symbol.\n if (typeof argsJson !== \"string\") {\n return Promise.reject(appServiceError(\"no_action\", `@himalaya/state: app.dispatch(\"${String(action)}\") args are not JSON-serializable${why}`));\n }\n return Promise.resolve()\n .then(() => checkAppTarget(\"action\", action))\n .then((a) => callAppBridge(\"__himalaya_app_dispatch\", `app.dispatch(\"${a}\")`, [a, argsJson]));\n },\n};"
|
|
90
120
|
},
|
|
91
121
|
{
|
|
92
122
|
"name": "\"@himalaya/core/validation\"",
|
|
@@ -1101,7 +1131,7 @@
|
|
|
1101
1131
|
"name": "TopBarConfig",
|
|
1102
1132
|
"kind": "interface",
|
|
1103
1133
|
"jsdoc": "/** The shell-owned top bar. The shell paints\n * `ScreenDescriptor.title` and computes the leading slot (back XOR menu) from\n * nav depth; this adds the trailing action cluster + leading/style overrides.\n * Lives on `ScreenDescriptor.topBar` (authoritative) and\n * `NavigationConfig.topBarDefault` (app-level fallback, fully replaced). */",
|
|
1104
|
-
"decl": "export interface TopBarConfig {\n /** Trailing (right-edge) actions, authored order = leading→trailing. */\n actions?: TopBarAction[];\n /** Leading override: \"\" | \"auto\" (shell-computed) | \"back\" | \"menu\" | \"none\". */\n leading?: string;\n /** Content-under-bar: \"\" | \"opaque\" (default) | \"transparent\" | \"immersive\". */\n style?: string;\n /** Toolbar items (drawn after the legacy `actions`). */\n items?: ToolbarItem[];\n /** \"\" / \"automatic\" (default) | \"large\" | \"inline\". */\n titleDisplay?: string;\n /** The literal subtitle (the fallback for `subtitlePath`). */\n subtitle?: string;\n /** \"\" / \"visible\" (default) | \"hidden\". */\n visibility?: string;\n /** Bar fill token. iOS 26 keeps the system glass (amendment R12). */\n background?: TokenRef;\n
|
|
1134
|
+
"decl": "export interface TopBarConfig {\n /** Trailing (right-edge) actions, authored order = leading→trailing. */\n actions?: TopBarAction[];\n /** Leading override: \"\" | \"auto\" (shell-computed) | \"back\" | \"menu\" | \"none\". */\n leading?: string;\n /** Content-under-bar: \"\" | \"opaque\" (default) | \"transparent\" | \"immersive\". */\n style?: string;\n /** Toolbar items (drawn after the legacy `actions`). */\n items?: ToolbarItem[];\n /** \"\" / \"automatic\" (default) | \"large\" | \"inline\". */\n titleDisplay?: string;\n /** The literal subtitle (the fallback for `subtitlePath`). */\n subtitle?: string;\n /** \"\" / \"visible\" (default) | \"hidden\". */\n visibility?: string;\n /** Bar fill token. iOS 26 keeps the system glass (amendment R12). */\n background?: TokenRef;\n /** \"Native top-bar search\" — the screen's search, drawn by whoever draws its bar natively (an embed's host\n * today: iOS `himalayaEmbedSearch`, Android `ProvideHimalayaEmbedSearch`). Read per screen only. */\n searchable?: SearchableConfig;\n /** amendment — the screen's logo; overrides `NavigationConfig.topBarLogo`. */\n logo?: TopBarLogo;\n /** amendment — the title as a menu. */\n titleMenu?: TopBarTitleMenu;\n /** amendment — live subtitle (`$service:`); `subtitle` is the fallback. */\n subtitlePath?: string;\n /** amendment — \"\" / \"pinned\" (default) | \"hide_on_scroll\". */\n scrollBehavior?: string;\n /** amendment — truthy ⇒ leaving the presentation asks to discard. Unset/unresolved ⇒ false. */\n dirtyPath?: string;\n}"
|
|
1105
1135
|
},
|
|
1106
1136
|
{
|
|
1107
1137
|
"name": "SplashConfig",
|
|
@@ -858,10 +858,58 @@ the hand-off deliberately:
|
|
|
858
858
|
target surface support it;
|
|
859
859
|
- persist shared/cross-device state in Wix Data or another backend, then reload it;
|
|
860
860
|
- co-locate a multi-step flow in one screen with `FragmentSlot` when the state is
|
|
861
|
-
truly one screen-local interaction
|
|
861
|
+
truly one screen-local interaction;
|
|
862
|
+
- keep it in an **app service** (below) when it has to outlive every screen: a background
|
|
863
|
+
job, a count shown on several screens, an action to replay after sign-in.
|
|
862
864
|
|
|
863
865
|
Never author `$service:screenA.value` in screen B and expect screen A's worker to
|
|
864
|
-
remain attached—the binding is unresolved by design.
|
|
866
|
+
remain attached—the binding is unresolved by design. Bind `$app:<svc>.<path>` instead.
|
|
867
|
+
|
|
868
|
+
### App services: state that outlives every screen
|
|
869
|
+
|
|
870
|
+
An app service is a `defineService` in the app's one app-level bundle, which the shell
|
|
871
|
+
keeps running for the whole session:
|
|
872
|
+
|
|
873
|
+
```ts
|
|
874
|
+
// config.ts — canonical spelling. `navigation.navLogicBundle` is the older alias;
|
|
875
|
+
// declaring both is an error. Both bake into the same wire field.
|
|
876
|
+
defineApp({ /* … */ app: { logicBundle: { url: "/v1/bundles/myapp-services", integrity: "", declaredCapabilities: ["wix_api"] } } });
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
```ts
|
|
880
|
+
// tier5-src/myapp-services/index.ts
|
|
881
|
+
defineService("jobs", {
|
|
882
|
+
state: { active: [], progress: 0 },
|
|
883
|
+
actions: { start: async (s, prompt: string) => ({ ...s /* … */ }) },
|
|
884
|
+
// What SCREEN-WORKER code may reach. Descriptors are not limited by it.
|
|
885
|
+
exports: { actions: ["start"], state: ["active", "progress"] },
|
|
886
|
+
});
|
|
887
|
+
```
|
|
888
|
+
|
|
889
|
+
- **Read from any descriptor** with `$app:<svc>.<path>`, in a binding field only: a
|
|
890
|
+
`…Path` twin, `itemsPath`, `hiddenPath`, `casePath`, or a nav chrome `*Path`. Until the
|
|
891
|
+
app worker answers, the literal sibling renders. `$app:` as a plain prop with no twin
|
|
892
|
+
(`WebView.url`) is a validation error, and so is `$app:` in a nav item's `hiddenPath`
|
|
893
|
+
(keep `$service:` there).
|
|
894
|
+
- **Call it from any descriptor** with `actionId: "app.<svc>.<action>"` (exactly three
|
|
895
|
+
segments).
|
|
896
|
+
- **From a screen worker** (once your himi version lists the `app_services` capability —
|
|
897
|
+
until then `himi validate` reports it as unknown), declare it and use
|
|
898
|
+
`app.read("jobs.active")` / `app.dispatch("jobs.start", args)` from `@himalaya/state`.
|
|
899
|
+
Both reject with a coded `AppServiceError` (`not_booted`, `unavailable`, `no_service`,
|
|
900
|
+
`no_action`, `not_exported`, `undeclared`) instead of resolving to nothing.
|
|
901
|
+
- A service name may be declared once per app: never in both the app bundle and a screen
|
|
902
|
+
bundle.
|
|
903
|
+
|
|
904
|
+
**The gate.** Old binaries cannot run any of this, and the server cannot downgrade a
|
|
905
|
+
descriptor per request. So `$app:`, `app.*`, `exports`, and a screen bundle that declares
|
|
906
|
+
`app_services` or calls `app.read` / `app.dispatch` are **validation errors** unless the
|
|
907
|
+
app's oldest served binary ships app services. That floor is the lowest
|
|
908
|
+
`minBinaryVersion` across the app's rollout rings; a ring without one counts as unbounded.
|
|
909
|
+
No released binary ships app services yet, so today no app qualifies — not even a new one,
|
|
910
|
+
because nothing would resolve `$app:` or run `app.*` yet. From the release that ships them, a
|
|
911
|
+
brand-new app that has never shipped an older binary declares `app: { newApp: true }` and
|
|
912
|
+
qualifies from day one. The validator's message names the floor it found and both ways to qualify.
|
|
865
913
|
|
|
866
914
|
### Runtime-unknown structure with `WorkerSubtree` (RFC 0046)
|
|
867
915
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1481.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": "ce0a3d62f73b916b8d1a8115889b3b1570ca0993950c20311f26694b"
|
|
75
75
|
}
|