@wix/himalaya-cli 0.839.0 → 0.841.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.
Files changed (27) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/schema.d.ts +30 -0
  2. package/dist/cli.mjs +12 -18
  3. package/guides/component-reference.json +5 -3
  4. package/guides/component-reference.md +33 -6
  5. package/package.json +2 -2
  6. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-aria/index.ts +29 -1
  7. package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-aria-history/index.ts +10 -1
  8. package/templates/community-club-owner/tier5-src/himi-owner-lite-aria/index.ts +29 -1
  9. package/templates/community-club-owner/tier5-src/himi-owner-lite-aria-history/index.ts +10 -1
  10. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-aria/index.ts +29 -1
  11. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-aria-history/index.ts +10 -1
  12. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-aria/index.ts +29 -1
  13. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-aria-history/index.ts +10 -1
  14. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-aria/index.ts +29 -1
  15. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-aria-history/index.ts +10 -1
  16. package/templates/owner-lite/tier5-src/himi-owner-lite-aria/index.ts +29 -1
  17. package/templates/owner-lite/tier5-src/himi-owner-lite-aria-history/index.ts +10 -1
  18. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-aria/index.ts +29 -1
  19. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-aria-history/index.ts +10 -1
  20. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-aria/index.ts +29 -1
  21. package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-aria-history/index.ts +10 -1
  22. package/templates/restaurant-owner/tier5-src/himi-owner-lite-aria/index.ts +29 -1
  23. package/templates/restaurant-owner/tier5-src/himi-owner-lite-aria-history/index.ts +10 -1
  24. package/templates/retail-store-owner/tier5-src/himi-owner-lite-aria/index.ts +29 -1
  25. package/templates/retail-store-owner/tier5-src/himi-owner-lite-aria-history/index.ts +10 -1
  26. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-aria/index.ts +29 -1
  27. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-aria-history/index.ts +10 -1
@@ -500,13 +500,29 @@ export type TextContent = {
500
500
  text: string;
501
501
  } | {
502
502
  template: InterpolatedText;
503
+ } | {
504
+ timeRef: WidgetTimeRef;
503
505
  };
506
+ /** Lever D (RFC 0002 OS-widget reactive leaf) — a sanctioned DECLARATIVE live time the OS
507
+ * ticks with NO worker and NO refresh, so it is a frozen literal rather than a
508
+ * `$service:`/`$item.` binding. `at` is epoch SECONDS. Mirrors iOS `WidgetTimeRef` and
509
+ * Android `WidgetTimeRef`; `core/ts/src/validator.ts` pins the same `{ at, style? }` shape
510
+ * and style set for widget snapshots. */
511
+ export interface WidgetTimeRef {
512
+ /** Epoch seconds the style counts from/to. */
513
+ at: number;
514
+ /** SwiftUI `Text.DateStyle` / Android time style (default "timer"). */
515
+ style?: "timer" | "relative" | "date" | "time" | "offset";
516
+ }
504
517
  export type TextProps = TextContent & {
505
518
  style?: TokenName;
506
519
  /** Foreground color token (default "textPrimary"). */
507
520
  color?: TokenName;
508
521
  /** Tail-truncate after N lines (absent = unlimited). */
509
522
  maxLines?: number;
523
+ /** Lever D — a live time value (countdown/relative) the OS ticks with no refresh.
524
+ * When present it OVERRIDES `text`. Widget-safe render only. */
525
+ timeRef?: WidgetTimeRef;
510
526
  /** RFC 0009 — render `text` as a constrained Markdown subset. */
511
527
  markdown?: boolean;
512
528
  /** RFC 0034 — capability enrichments. */
@@ -730,6 +746,9 @@ export interface AvatarStripProps {
730
746
  caption?: string;
731
747
  /** Fired when tapping any avatar. */
732
748
  onTap?: Action;
749
+ /** Gradient token painted as a ring around each avatar — the "story" ring.
750
+ * Resolved through the gradient tokens, not the colour ones. */
751
+ ringGradient?: TokenName;
733
752
  }
734
753
  export interface BadgeProps {
735
754
  /** Badge text — binding-aware ("$item."/"$service:") on web, iOS and Android. */
@@ -1215,6 +1234,14 @@ export interface TableProps {
1215
1234
  rows?: TableRow[];
1216
1235
  rowsPath?: string;
1217
1236
  }
1237
+ /** One ring of a concentric multi-ring Gauge (Apple-Fitness style). */
1238
+ export interface GaugeRing {
1239
+ /** Fraction 0..1 for this ring. */
1240
+ value?: number;
1241
+ /** `$service:`/`$item.` binding → a live number (overrides `value`). */
1242
+ valuePath?: string;
1243
+ tint?: TokenName;
1244
+ }
1218
1245
  export interface GaugeProps {
1219
1246
  value?: number;
1220
1247
  /** `$service:`/`$item.` binding → a live number (overrides `value`). */
@@ -1224,6 +1251,9 @@ export interface GaugeProps {
1224
1251
  label?: string;
1225
1252
  kind?: "radial" | "linear";
1226
1253
  tint?: TokenName;
1254
+ /** Concentric multi-ring gauge, drawn outer→inner. When present it overrides the
1255
+ * single `value`/`valuePath` radial. */
1256
+ rings?: GaugeRing[];
1227
1257
  /** Motion grammar (Batch 1, item 4) — tween the fill on value change instead of
1228
1258
  * snapping; gated by reduced motion. Mirror of ProgressBarProps.animated. */
1229
1259
  animated?: boolean;
package/dist/cli.mjs CHANGED
@@ -5926,7 +5926,6 @@ __export(validate_descriptor_core_exports, {
5926
5926
  NATIVE_MODIFIERS_CLASS: () => NATIVE_MODIFIERS_CLASS,
5927
5927
  NATIVE_NESTED_CLASSES: () => NATIVE_NESTED_CLASSES,
5928
5928
  NATIVE_NESTED_PROPS: () => NATIVE_NESTED_PROPS,
5929
- NATIVE_ONLY_PROPS: () => NATIVE_ONLY_PROPS,
5930
5929
  NATIVE_PROP_ENUMS: () => NATIVE_PROP_ENUMS,
5931
5930
  NATIVE_REQUIRED_PROPS: () => NATIVE_REQUIRED_PROPS,
5932
5931
  SERVICE_ONLY_BINDING_PROPS: () => SERVICE_ONLY_BINDING_PROPS,
@@ -6717,14 +6716,14 @@ function componentPropFindings(descriptor) {
6717
6716
  const base = at ? `${at}.body.props` : "body.props";
6718
6717
  for (const name of Object.keys(bag)) {
6719
6718
  const path = `${base}.${name}`;
6720
- const kind = own(declared, name) ?? own(own(NATIVE_ONLY_PROPS, type) ?? {}, name);
6719
+ const kind = own(declared, name);
6721
6720
  if (kind === void 0) {
6722
6721
  if (LEGACY_UNSCORED_KEYS.has(`${type}.${name}`)) continue;
6723
6722
  const hint = MODIFIER_KEYS.has(name) ? ` \u2014 \`${name}\` is a MODIFIER, not a prop: move it out of \`props\` and into the node's \`modifiers\` bag (\`{ id, body, modifiers: { ${name}: \u2026 } }\`)` : "";
6724
6723
  out.push({
6725
6724
  path,
6726
6725
  kind: "hygiene",
6727
- message: `${type} has no prop \`${name}\` \u2014 the native decoders are built with \`ignoreUnknownKeys = true\`, so this key is SILENTLY DROPPED on iOS and Android and the value never reaches the screen (web, whose props are \`any\`, may still show it). Declared props: ${[...Object.keys(declared), ...Object.keys(own(NATIVE_ONLY_PROPS, type) ?? {})].sort().join(", ") || "(none)"}${hint}`
6726
+ message: `${type} has no prop \`${name}\` \u2014 the native decoders are built with \`ignoreUnknownKeys = true\`, so this key is SILENTLY DROPPED on iOS and Android and the value never reaches the screen (web, whose props are \`any\`, may still show it). Declared props: ${Object.keys(declared).sort().join(", ") || "(none)"}${hint}`
6728
6727
  });
6729
6728
  continue;
6730
6729
  }
@@ -7608,7 +7607,7 @@ function validateScreenDescriptor(screenId, descriptor, opts = {}) {
7608
7607
  services: Object.keys(services)
7609
7608
  };
7610
7609
  }
7611
- var CRAWL_BLOCKING_PASSES, BOOT_EVAL_TIMEOUT_MS, DEVICE_PARITY_WITHHELD, defaultEvaluator, bootEvaluator, actionEvaluator, NATIVE_PROP_ENUMS, KNOWN_PROPS, INTEGER_PROPS, NATIVE_REQUIRED_PROPS, bareNestedClass, NATIVE_NESTED_CLASSES, NATIVE_MODIFIERS_CLASS, NATIVE_DESCRIPTOR_CLASS, NATIVE_DESCRIPTOR_NESTED, NATIVE_NESTED_PROPS, MODIFIER_KEYS, INTEGER_MODIFIERS, MODIFIER_KINDS, SCHEMA_SCORED_NODES, CORE_PACKAGES, NATIVE_ONLY_PROPS, LEGACY_UNSCORED_KEYS, DYNAMIC_PLACEHOLDER, LITERAL_ONLY_PROPS, SERVICE_ONLY_BINDING_PROPS, WHOLE_VALUE_BINDING, EMBEDDED_BINDING, OPTIONS_BINDING_PROPS;
7610
+ var CRAWL_BLOCKING_PASSES, BOOT_EVAL_TIMEOUT_MS, DEVICE_PARITY_WITHHELD, defaultEvaluator, bootEvaluator, actionEvaluator, NATIVE_PROP_ENUMS, KNOWN_PROPS, INTEGER_PROPS, NATIVE_REQUIRED_PROPS, bareNestedClass, NATIVE_NESTED_CLASSES, NATIVE_MODIFIERS_CLASS, NATIVE_DESCRIPTOR_CLASS, NATIVE_DESCRIPTOR_NESTED, NATIVE_NESTED_PROPS, MODIFIER_KEYS, INTEGER_MODIFIERS, MODIFIER_KINDS, SCHEMA_SCORED_NODES, CORE_PACKAGES, LEGACY_UNSCORED_KEYS, DYNAMIC_PLACEHOLDER, LITERAL_ONLY_PROPS, SERVICE_ONLY_BINDING_PROPS, WHOLE_VALUE_BINDING, EMBEDDED_BINDING, OPTIONS_BINDING_PROPS;
7612
7611
  var init_validate_descriptor_core = __esm({
7613
7612
  "../../core/dev-server/src/validate-descriptor.core.ts"() {
7614
7613
  init_validator();
@@ -7682,6 +7681,7 @@ var init_validate_descriptor_core = __esm({
7682
7681
  onTap: "any",
7683
7682
  overflowCount: "number",
7684
7683
  overlapRatio: "number",
7684
+ ringGradient: "string",
7685
7685
  showOverflow: "boolean",
7686
7686
  size: "number"
7687
7687
  },
@@ -7849,6 +7849,7 @@ var init_validate_descriptor_core = __esm({
7849
7849
  label: "string",
7850
7850
  max: "number",
7851
7851
  min: "number",
7852
+ rings: "array",
7852
7853
  tint: "string",
7853
7854
  tintPath: "string",
7854
7855
  value: "number",
@@ -8131,7 +8132,8 @@ var init_validate_descriptor_core = __esm({
8131
8132
  template: "any",
8132
8133
  text: "string",
8133
8134
  textAlign: "string",
8134
- textDirection: "string"
8135
+ textDirection: "string",
8136
+ timeRef: "any"
8135
8137
  },
8136
8138
  TextField: {
8137
8139
  autoCapitalization: "string",
@@ -8475,16 +8477,6 @@ var init_validate_descriptor_core = __esm({
8475
8477
  CORE_PACKAGES = new Set(
8476
8478
  [...CORE_COMPONENTS].map((key2) => key2.slice(0, key2.indexOf(".")))
8477
8479
  );
8478
- NATIVE_ONLY_PROPS = {
8479
- // Schema.kt:1970 — `String?`, a gradient token → a per-avatar "story" ring.
8480
- AvatarStrip: { ringGradient: "string" },
8481
- // Schema.kt:2362 — `List<GaugeRing>?`, a concentric multi-ring gauge (overrides the value).
8482
- Gauge: { rings: "array" },
8483
- // Schema.kt:944 — `WidgetTimeRef?`, a widget-safe live clock; on a widget it overrides `text`.
8484
- // A serializable, so `any`: `NATIVE_NESTED_PROPS` owns what is INSIDE it, exactly as it does
8485
- // for every other object-valued prop.
8486
- Text: { timeRef: "any" }
8487
- };
8488
8480
  LEGACY_UNSCORED_KEYS = /* @__PURE__ */ new Set([
8489
8481
  // 297 sites / 8 packages. Meant `leadingIcon` (or `trailingIcon`).
8490
8482
  "Button.icon",
@@ -36843,7 +36835,6 @@ __export(validate_descriptor_exports, {
36843
36835
  NATIVE_MODIFIERS_CLASS: () => NATIVE_MODIFIERS_CLASS,
36844
36836
  NATIVE_NESTED_CLASSES: () => NATIVE_NESTED_CLASSES,
36845
36837
  NATIVE_NESTED_PROPS: () => NATIVE_NESTED_PROPS,
36846
- NATIVE_ONLY_PROPS: () => NATIVE_ONLY_PROPS,
36847
36838
  NATIVE_PROP_ENUMS: () => NATIVE_PROP_ENUMS,
36848
36839
  NATIVE_REQUIRED_PROPS: () => NATIVE_REQUIRED_PROPS,
36849
36840
  SERVICE_ONLY_BINDING_PROPS: () => SERVICE_ONLY_BINDING_PROPS,
@@ -63114,7 +63105,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
63114
63105
  ...surfaceIssues(dir, outcome.surfaceNav, strict),
63115
63106
  ...tokenColorIssues(dir),
63116
63107
  ...await iconIssues(dir, strict),
63117
- ...fontIssues(dir, strict)
63108
+ ...fontIssues(dir, strict),
63109
+ ...storesV1Issues(dir, strict)
63118
63110
  ]);
63119
63111
  if (hasErrors && !force) {
63120
63112
  print({ ...report, pushed: false, hint: "lint found errors \u2014 fix them, or re-run `himi push --force` to publish anyway" });
@@ -63468,8 +63460,10 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
63468
63460
  const { report, hasErrors } = summarizeLint(app, bres, outcome, strict, [
63469
63461
  ...await cmsIssues(dir, app, strict, { local: true }),
63470
63462
  ...surfaceIssues(dir, outcome.surfaceNav, strict),
63463
+ ...tokenColorIssues(dir),
63471
63464
  ...await iconIssues(dir, strict),
63472
- ...fontIssues(dir, strict)
63465
+ ...fontIssues(dir, strict),
63466
+ ...storesV1Issues(dir, strict)
63473
63467
  ]);
63474
63468
  if (hasErrors && !force) {
63475
63469
  rmSync9(built, { recursive: true, force: true });
@@ -101,7 +101,7 @@
101
101
  "bindings": [
102
102
  "text"
103
103
  ],
104
- "propsSource": "export type TextProps = TextContent & {\n style?: TokenName;\n /** Foreground color token (default \"textPrimary\"). */\n color?: TokenName;\n /** Tail-truncate after N lines (absent = unlimited). */\n maxLines?: number;\n /** Render `text` as a constrained Markdown subset. */\n markdown?: boolean;\n /** Capability enrichments. */\n textAlign?: \"leading\" | \"center\" | \"trailing\" | \"justify\";\n /** Base writing direction. \"auto\" (or \"rtl\") makes a bidi paragraph resolve +\n * align by its own strong-directional content (Hebrew/Arabic → right-aligned,\n * RTL layout), matching per-message direction in chat bubbles. Absent/\"ltr\" =\n * the current left-to-right behavior. Both renderers honor it (parity). */\n textDirection?: \"auto\" | \"ltr\" | \"rtl\";\n decoration?: \"underline\" | \"strikethrough\";\n lineSpacing?: number;\n /** Per-item gate (usually an `$item.` field pre-substituted per row): when it\n * resolves empty, the text collapses to zero size instead of taking layout. */\n collapseWhenEmpty?: boolean;\n /** Motion grammar (Batch 1, item 4) — count-up tween for a numeric value on\n * change; non-numeric values render instantly. Gated by reduced motion. */\n animateValue?: boolean;\n /** Motion grammar — reveal the (post-substitution literal) text word-by-word,\n * once per distinct content, like a chat assistant \"typing\" its reply. Each\n * content animates a single time (progress is remembered), so list re-renders\n * and scrolls don't restart it. Gated by reduced motion (snaps to full).\n * Both renderers honor it (parity). Default nil/false. */\n animateReveal?: boolean;\n};"
104
+ "propsSource": "export type TextProps = TextContent & {\n style?: TokenName;\n /** Foreground color token (default \"textPrimary\"). */\n color?: TokenName;\n /** Tail-truncate after N lines (absent = unlimited). */\n maxLines?: number;\n /** Lever D — a live time value (countdown/relative) the OS ticks with no refresh.\n * When present it OVERRIDES `text`. Widget-safe render only. */\n timeRef?: WidgetTimeRef;\n /** Render `text` as a constrained Markdown subset. */\n markdown?: boolean;\n /** Capability enrichments. */\n textAlign?: \"leading\" | \"center\" | \"trailing\" | \"justify\";\n /** Base writing direction. \"auto\" (or \"rtl\") makes a bidi paragraph resolve +\n * align by its own strong-directional content (Hebrew/Arabic → right-aligned,\n * RTL layout), matching per-message direction in chat bubbles. Absent/\"ltr\" =\n * the current left-to-right behavior. Both renderers honor it (parity). */\n textDirection?: \"auto\" | \"ltr\" | \"rtl\";\n decoration?: \"underline\" | \"strikethrough\";\n lineSpacing?: number;\n /** Per-item gate (usually an `$item.` field pre-substituted per row): when it\n * resolves empty, the text collapses to zero size instead of taking layout. */\n collapseWhenEmpty?: boolean;\n /** Motion grammar (Batch 1, item 4) — count-up tween for a numeric value on\n * change; non-numeric values render instantly. Gated by reduced motion. */\n animateValue?: boolean;\n /** Motion grammar — reveal the (post-substitution literal) text word-by-word,\n * once per distinct content, like a chat assistant \"typing\" its reply. Each\n * content animates a single time (progress is remembered), so list re-renders\n * and scrolls don't restart it. Gated by reduced motion (snaps to full).\n * Both renderers honor it (parity). Default nil/false. */\n animateReveal?: boolean;\n};"
105
105
  },
106
106
  {
107
107
  "name": "Image",
@@ -388,7 +388,7 @@
388
388
  "bindings": [
389
389
  "avatarsPath"
390
390
  ],
391
- "propsSource": "export interface AvatarStripProps {\n /** `$service:` binding → a live array of `{imageUrl, initials}` (overrides `avatars`). */\n avatarsPath?: string;\n /** Literal fallback (Tier 0–4); ignored if `avatarsPath` resolves. */\n avatars?: AvatarStripAvatar[];\n /** Diameter in points (default 40). */\n size?: number;\n /** 0..1; shift = size * (1 - overlapRatio) (default 0.67). */\n overlapRatio?: number;\n /** Max avatars before overflow (default 4). */\n maxVisible?: number;\n /** Default true. */\n showOverflow?: boolean;\n /** Explicit overflow; if 0/absent computed from total. */\n overflowCount?: number;\n /** Literal caption (or `$service:` upstream-resolved). */\n caption?: string;\n /** Fired when tapping any avatar. */\n onTap?: Action;\n}"
391
+ "propsSource": "export interface AvatarStripProps {\n /** `$service:` binding → a live array of `{imageUrl, initials}` (overrides `avatars`). */\n avatarsPath?: string;\n /** Literal fallback (Tier 0–4); ignored if `avatarsPath` resolves. */\n avatars?: AvatarStripAvatar[];\n /** Diameter in points (default 40). */\n size?: number;\n /** 0..1; shift = size * (1 - overlapRatio) (default 0.67). */\n overlapRatio?: number;\n /** Max avatars before overflow (default 4). */\n maxVisible?: number;\n /** Default true. */\n showOverflow?: boolean;\n /** Explicit overflow; if 0/absent computed from total. */\n overflowCount?: number;\n /** Literal caption (or `$service:` upstream-resolved). */\n caption?: string;\n /** Fired when tapping any avatar. */\n onTap?: Action;\n /** Gradient token painted as a ring around each avatar — the \"story\" ring.\n * Resolved through the gradient tokens, not the colour ones. */\n ringGradient?: TokenName;\n}"
392
392
  },
393
393
  {
394
394
  "name": "Banner",
@@ -651,7 +651,7 @@
651
651
  "valuePath",
652
652
  "tintPath"
653
653
  ],
654
- "propsSource": "export interface GaugeProps {\n value?: number;\n /** `$service:`/`$item.` binding → a live number (overrides `value`). */\n valuePath?: string;\n min?: number;\n max?: number;\n label?: string;\n kind?: \"radial\" | \"linear\";\n tint?: TokenName;\n /** Motion grammar (Batch 1, item 4) — tween the fill on value change instead of\n * snapping; gated by reduced motion. Mirror of ProgressBarProps.animated. */\n animated?: boolean;\n /** #1055 — `$service:`/`$item.` binding resolving to a tint TOKEN NAME (overrides `tint`). Binding-aware. */\n tintPath?: string;\n}"
654
+ "propsSource": "export interface GaugeProps {\n value?: number;\n /** `$service:`/`$item.` binding → a live number (overrides `value`). */\n valuePath?: string;\n min?: number;\n max?: number;\n label?: string;\n kind?: \"radial\" | \"linear\";\n tint?: TokenName;\n /** Concentric multi-ring gauge, drawn outer→inner. When present it overrides the\n * single `value`/`valuePath` radial. */\n rings?: GaugeRing[];\n /** Motion grammar (Batch 1, item 4) — tween the fill on value change instead of\n * snapping; gated by reduced motion. Mirror of ProgressBarProps.animated. */\n animated?: boolean;\n /** #1055 — `$service:`/`$item.` binding resolving to a tint TOKEN NAME (overrides `tint`). Binding-aware. */\n tintPath?: string;\n}"
655
655
  },
656
656
  {
657
657
  "name": "Rating",
@@ -887,6 +887,8 @@
887
887
  "Presentation": "export type Presentation =\n | \"push\"\n | \"sheet\"\n | \"replace\"\n | \"dismiss\"\n | \"back\"\n | \"full_screen\"\n | \"alert\"\n | \"snackbar\";",
888
888
  "FilterChip": "export interface FilterChip {\n id: string;\n label: string;\n leadingIcon?: IconRef;\n count?: number;\n}",
889
889
  "TabItem": "export interface TabItem {\n id: string;\n label: string;\n badge?: string;\n}",
890
+ "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}",
891
+ "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}",
890
892
  "Border": "export interface Border {\n width: number;\n color: TokenRef;\n}"
891
893
  }
892
894
  }
@@ -167,7 +167,7 @@ So `border` nests an object and `boxShadow`/`backgroundGradient` nest strings. R
167
167
  element interface (printed below) rather than extrapolating from the level.
168
168
 
169
169
  - Modifier-level (`TokenRef` object): `modifiers.background`, `modifiers.shadow`, `modifiers.backgroundGradient`, `modifiers.appear`, `modifiers.material`, `modifiers.pressMotion`, `modifiers.border.color`.
170
- - Component-prop-level (bare `TokenName` string): `Card.background`, `Text.style`, `Text.color`, `Image.placeholder`, `Image.tint`, `Icon.tint`, `Toggle.trackOn`, `Toggle.trackOff`, `Toggle.thumb`, `Badge.token`, `Tag.token`, `ProgressBar.tint`, `ProgressBar.trackColor`, `ListItem.titleStyle`, `ListItem.subtitleStyle`, `ListItem.titleColor`, `ListItem.subtitleColor`, `ListItem.overlineColor`, `Slider.tint`, `ActivityIndicator.tint`, `Chip.token`, `Label.style`, `Label.color`, `Gauge.tint`, `Rating.color`, `Chart.color`, `DonutChart.color`, `VoiceNote.tint`, `Marquee.style`, `Marquee.color`, `Fab.tint`.
170
+ - Component-prop-level (bare `TokenName` string): `Card.background`, `Text.style`, `Text.color`, `Image.placeholder`, `Image.tint`, `Icon.tint`, `Toggle.trackOn`, `Toggle.trackOff`, `Toggle.thumb`, `Badge.token`, `Tag.token`, `ProgressBar.tint`, `ProgressBar.trackColor`, `AvatarStrip.ringGradient`, `ListItem.titleStyle`, `ListItem.subtitleStyle`, `ListItem.titleColor`, `ListItem.subtitleColor`, `ListItem.overlineColor`, `Slider.tint`, `ActivityIndicator.tint`, `Chip.token`, `Label.style`, `Label.color`, `Gauge.tint`, `Rating.color`, `Chart.color`, `DonutChart.color`, `VoiceNote.tint`, `Marquee.style`, `Marquee.color`, `Fab.tint`.
171
171
 
172
172
  There is **no `modifiers.color` and no `modifiers.tint`** — a `tint` is always a component
173
173
  prop. Of the two nested slots spelled `color`, `modifiers.border.color` is a `TokenRef`
@@ -366,6 +366,9 @@ export type TextProps = TextContent & {
366
366
  color?: TokenName;
367
367
  /** Tail-truncate after N lines (absent = unlimited). */
368
368
  maxLines?: number;
369
+ /** Lever D — a live time value (countdown/relative) the OS ticks with no refresh.
370
+ * When present it OVERRIDES `text`. Widget-safe render only. */
371
+ timeRef?: WidgetTimeRef;
369
372
  /** Render `text` as a constrained Markdown subset. */
370
373
  markdown?: boolean;
371
374
  /** Capability enrichments. */
@@ -915,6 +918,9 @@ export interface AvatarStripProps {
915
918
  caption?: string;
916
919
  /** Fired when tapping any avatar. */
917
920
  onTap?: Action;
921
+ /** Gradient token painted as a ring around each avatar — the "story" ring.
922
+ * Resolved through the gradient tokens, not the colour ones. */
923
+ ringGradient?: TokenName;
918
924
  }
919
925
  ```
920
926
 
@@ -1265,6 +1271,9 @@ export interface GaugeProps {
1265
1271
  label?: string;
1266
1272
  kind?: "radial" | "linear";
1267
1273
  tint?: TokenName;
1274
+ /** Concentric multi-ring gauge, drawn outer→inner. When present it overrides the
1275
+ * single `value`/`valuePath` radial. */
1276
+ rings?: GaugeRing[];
1268
1277
  /** Motion grammar (Batch 1, item 4) — tween the fill on value change instead of
1269
1278
  * snapping; gated by reduced motion. Mirror of ProgressBarProps.animated. */
1270
1279
  animated?: boolean;
@@ -1913,12 +1922,15 @@ export interface LogicBundleRef {
1913
1922
  }
1914
1923
  ```
1915
1924
 
1916
- ## Element shapes (list & tab items)
1925
+ ## Element shapes (list & tab items, and other typed prop objects)
1917
1926
 
1918
- A few props take an array of typed **element objects** rather than nested components:
1919
- `FilterChips.chips` is a `FilterChip[]`, and `SegmentedControl.options` / `Tabs.tabs` are a
1920
- `TabItem[]`. The prop blocks above name those arrays; here are the element interfaces themselves
1921
- (each item's own fields — `id` is what an `onChange` reports back).
1927
+ A few props take a typed **object** rather than nested components. Some are arrays of them:
1928
+ `FilterChips.chips` is a `FilterChip[]`, `SegmentedControl.options` / `Tabs.tabs` are a
1929
+ `TabItem[]`, and `Gauge.rings` is a `GaugeRing[]` (concentric rings, drawn outer→inner).
1930
+ One is a single object: `Text.timeRef` is a `WidgetTimeRef`, the widget-safe live clock —
1931
+ note its `at` is REQUIRED and is in epoch SECONDS. The prop blocks above name these types;
1932
+ here are the interfaces themselves (for the arrays, each item's own fields — `id` is what an
1933
+ `onChange` reports back).
1922
1934
 
1923
1935
  ```ts
1924
1936
  export interface FilterChip {
@@ -1933,6 +1945,21 @@ export interface TabItem {
1933
1945
  label: string;
1934
1946
  badge?: string;
1935
1947
  }
1948
+
1949
+ export interface GaugeRing {
1950
+ /** Fraction 0..1 for this ring. */
1951
+ value?: number;
1952
+ /** `$service:`/`$item.` binding → a live number (overrides `value`). */
1953
+ valuePath?: string;
1954
+ tint?: TokenName;
1955
+ }
1956
+
1957
+ export interface WidgetTimeRef {
1958
+ /** Epoch seconds the style counts from/to. */
1959
+ at: number;
1960
+ /** SwiftUI `Text.DateStyle` / Android time style (default "timer"). */
1961
+ style?: "timer" | "relative" | "date" | "time" | "offset";
1962
+ }
1936
1963
  ```
1937
1964
 
1938
1965
  ## Modifiers
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/himalaya-cli",
3
- "version": "0.839.0",
3
+ "version": "0.841.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": [
@@ -63,5 +63,5 @@
63
63
  "artifactId": "himalaya-cli"
64
64
  }
65
65
  },
66
- "falconPackageHash": "5de4fef57d6c6e87d57791a1f1af4e7bd241ef8902a4fbb3292442a0"
66
+ "falconPackageHash": "60bd923f4e7d6bcb8c585e19b160bbc63f2db7758a553bd612e945ad"
67
67
  }
@@ -186,5 +186,33 @@ const svc = defineService<AriaChatState, {
186
186
  },
187
187
  });
188
188
 
189
- svc.load();
189
+ // NO module-scope `svc.load()`, deliberately — the descriptor's `onAppear` is the
190
+ // only entry point, and on Android the self-kick did not merely duplicate it, it
191
+ // DISABLED the screen.
192
+ //
193
+ // `load` opens by creating a conversation, so a self-kick puts a `wixApi.call`
194
+ // inside the bundle's own evaluation — and a bridge call made during
195
+ // `worker.boot(bundle)` stalls on the Android WebView. The host completes it
196
+ // (`bridge_wix_call … ok=true` is logged between `bundle eval done` and
197
+ // `services=[…]`) but the JS promise never settles. `createOnce` then caches that
198
+ // promise as the per-site create latch, so the `onAppear` load — dispatched
199
+ // correctly, and fine on its own — awaits the same dead promise and never returns
200
+ // either. Result on Android: no greeting, no prompt chips, no conversation, and a
201
+ // Send that does nothing, for the life of the screen. Nothing reports it, because
202
+ // a pending dispatch has no timeout: an action that never settles is
203
+ // indistinguishable from one still running (#2518).
204
+ //
205
+ // That stall is a known Android defect, not a new one. `WebViewJSWorker` already
206
+ // prepends per-screen input into the bundle's own evaluate rather than assigning it
207
+ // separately, and says why: "the bundle's first wixApi.call could stall". Aria is
208
+ // simply the first owner-lite screen to call the network at module scope and so the
209
+ // first to meet it head-on. Fixing the stall is a core-runtime change tracked
210
+ // separately; not calling the network before the screen exists is right regardless.
211
+ //
212
+ // The self-kick was never load-bearing. Both hosts queue a `tier5.*` action
213
+ // dispatched before the worker is up — `Tier5WorkerSession.invoke` on Android and
214
+ // `HimalayaScreenHost.dispatch` on iOS — and both say in as many words that the
215
+ // self-kick is what made `onAppear` only LOOK like it worked. It also cost a
216
+ // second conversation-create attempt per open and minted the greeting with
217
+ // fallback copy, since the copy pack only arrives with the onAppear params.
190
218
  export { svc };
@@ -38,5 +38,14 @@ const svc = defineService<AriaHistoryState, {
38
38
  },
39
39
  });
40
40
 
41
- svc.load();
41
+ // NO module-scope `svc.load()` — same reason as the chat adapter next door, which
42
+ // carries the full explanation. This `load` opens with `getConversations`, so a
43
+ // self-kick makes a bridge call inside the bundle's own evaluation, and such a call
44
+ // stalls on the Android WebView (#2518).
45
+ //
46
+ // It is less damaging here than on the chat screen: this load has no create latch
47
+ // for a dead promise to poison, so the `onAppear` load issues its own request and
48
+ // the list still fills. What the self-kick leaves behind is a dispatch that never
49
+ // settles — `pendingDispatches` has no timeout, so it is held for the life of the
50
+ // worker, on every open. Not worth keeping for a call whose result nothing reads.
42
51
  export { svc };
@@ -186,5 +186,33 @@ const svc = defineService<AriaChatState, {
186
186
  },
187
187
  });
188
188
 
189
- svc.load();
189
+ // NO module-scope `svc.load()`, deliberately — the descriptor's `onAppear` is the
190
+ // only entry point, and on Android the self-kick did not merely duplicate it, it
191
+ // DISABLED the screen.
192
+ //
193
+ // `load` opens by creating a conversation, so a self-kick puts a `wixApi.call`
194
+ // inside the bundle's own evaluation — and a bridge call made during
195
+ // `worker.boot(bundle)` stalls on the Android WebView. The host completes it
196
+ // (`bridge_wix_call … ok=true` is logged between `bundle eval done` and
197
+ // `services=[…]`) but the JS promise never settles. `createOnce` then caches that
198
+ // promise as the per-site create latch, so the `onAppear` load — dispatched
199
+ // correctly, and fine on its own — awaits the same dead promise and never returns
200
+ // either. Result on Android: no greeting, no prompt chips, no conversation, and a
201
+ // Send that does nothing, for the life of the screen. Nothing reports it, because
202
+ // a pending dispatch has no timeout: an action that never settles is
203
+ // indistinguishable from one still running (#2518).
204
+ //
205
+ // That stall is a known Android defect, not a new one. `WebViewJSWorker` already
206
+ // prepends per-screen input into the bundle's own evaluate rather than assigning it
207
+ // separately, and says why: "the bundle's first wixApi.call could stall". Aria is
208
+ // simply the first owner-lite screen to call the network at module scope and so the
209
+ // first to meet it head-on. Fixing the stall is a core-runtime change tracked
210
+ // separately; not calling the network before the screen exists is right regardless.
211
+ //
212
+ // The self-kick was never load-bearing. Both hosts queue a `tier5.*` action
213
+ // dispatched before the worker is up — `Tier5WorkerSession.invoke` on Android and
214
+ // `HimalayaScreenHost.dispatch` on iOS — and both say in as many words that the
215
+ // self-kick is what made `onAppear` only LOOK like it worked. It also cost a
216
+ // second conversation-create attempt per open and minted the greeting with
217
+ // fallback copy, since the copy pack only arrives with the onAppear params.
190
218
  export { svc };
@@ -38,5 +38,14 @@ const svc = defineService<AriaHistoryState, {
38
38
  },
39
39
  });
40
40
 
41
- svc.load();
41
+ // NO module-scope `svc.load()` — same reason as the chat adapter next door, which
42
+ // carries the full explanation. This `load` opens with `getConversations`, so a
43
+ // self-kick makes a bridge call inside the bundle's own evaluation, and such a call
44
+ // stalls on the Android WebView (#2518).
45
+ //
46
+ // It is less damaging here than on the chat screen: this load has no create latch
47
+ // for a dead promise to poison, so the `onAppear` load issues its own request and
48
+ // the list still fills. What the self-kick leaves behind is a dispatch that never
49
+ // settles — `pendingDispatches` has no timeout, so it is held for the life of the
50
+ // worker, on every open. Not worth keeping for a call whose result nothing reads.
42
51
  export { svc };
@@ -186,5 +186,33 @@ const svc = defineService<AriaChatState, {
186
186
  },
187
187
  });
188
188
 
189
- svc.load();
189
+ // NO module-scope `svc.load()`, deliberately — the descriptor's `onAppear` is the
190
+ // only entry point, and on Android the self-kick did not merely duplicate it, it
191
+ // DISABLED the screen.
192
+ //
193
+ // `load` opens by creating a conversation, so a self-kick puts a `wixApi.call`
194
+ // inside the bundle's own evaluation — and a bridge call made during
195
+ // `worker.boot(bundle)` stalls on the Android WebView. The host completes it
196
+ // (`bridge_wix_call … ok=true` is logged between `bundle eval done` and
197
+ // `services=[…]`) but the JS promise never settles. `createOnce` then caches that
198
+ // promise as the per-site create latch, so the `onAppear` load — dispatched
199
+ // correctly, and fine on its own — awaits the same dead promise and never returns
200
+ // either. Result on Android: no greeting, no prompt chips, no conversation, and a
201
+ // Send that does nothing, for the life of the screen. Nothing reports it, because
202
+ // a pending dispatch has no timeout: an action that never settles is
203
+ // indistinguishable from one still running (#2518).
204
+ //
205
+ // That stall is a known Android defect, not a new one. `WebViewJSWorker` already
206
+ // prepends per-screen input into the bundle's own evaluate rather than assigning it
207
+ // separately, and says why: "the bundle's first wixApi.call could stall". Aria is
208
+ // simply the first owner-lite screen to call the network at module scope and so the
209
+ // first to meet it head-on. Fixing the stall is a core-runtime change tracked
210
+ // separately; not calling the network before the screen exists is right regardless.
211
+ //
212
+ // The self-kick was never load-bearing. Both hosts queue a `tier5.*` action
213
+ // dispatched before the worker is up — `Tier5WorkerSession.invoke` on Android and
214
+ // `HimalayaScreenHost.dispatch` on iOS — and both say in as many words that the
215
+ // self-kick is what made `onAppear` only LOOK like it worked. It also cost a
216
+ // second conversation-create attempt per open and minted the greeting with
217
+ // fallback copy, since the copy pack only arrives with the onAppear params.
190
218
  export { svc };
@@ -38,5 +38,14 @@ const svc = defineService<AriaHistoryState, {
38
38
  },
39
39
  });
40
40
 
41
- svc.load();
41
+ // NO module-scope `svc.load()` — same reason as the chat adapter next door, which
42
+ // carries the full explanation. This `load` opens with `getConversations`, so a
43
+ // self-kick makes a bridge call inside the bundle's own evaluation, and such a call
44
+ // stalls on the Android WebView (#2518).
45
+ //
46
+ // It is less damaging here than on the chat screen: this load has no create latch
47
+ // for a dead promise to poison, so the `onAppear` load issues its own request and
48
+ // the list still fills. What the self-kick leaves behind is a dispatch that never
49
+ // settles — `pendingDispatches` has no timeout, so it is held for the life of the
50
+ // worker, on every open. Not worth keeping for a call whose result nothing reads.
42
51
  export { svc };
@@ -186,5 +186,33 @@ const svc = defineService<AriaChatState, {
186
186
  },
187
187
  });
188
188
 
189
- svc.load();
189
+ // NO module-scope `svc.load()`, deliberately — the descriptor's `onAppear` is the
190
+ // only entry point, and on Android the self-kick did not merely duplicate it, it
191
+ // DISABLED the screen.
192
+ //
193
+ // `load` opens by creating a conversation, so a self-kick puts a `wixApi.call`
194
+ // inside the bundle's own evaluation — and a bridge call made during
195
+ // `worker.boot(bundle)` stalls on the Android WebView. The host completes it
196
+ // (`bridge_wix_call … ok=true` is logged between `bundle eval done` and
197
+ // `services=[…]`) but the JS promise never settles. `createOnce` then caches that
198
+ // promise as the per-site create latch, so the `onAppear` load — dispatched
199
+ // correctly, and fine on its own — awaits the same dead promise and never returns
200
+ // either. Result on Android: no greeting, no prompt chips, no conversation, and a
201
+ // Send that does nothing, for the life of the screen. Nothing reports it, because
202
+ // a pending dispatch has no timeout: an action that never settles is
203
+ // indistinguishable from one still running (#2518).
204
+ //
205
+ // That stall is a known Android defect, not a new one. `WebViewJSWorker` already
206
+ // prepends per-screen input into the bundle's own evaluate rather than assigning it
207
+ // separately, and says why: "the bundle's first wixApi.call could stall". Aria is
208
+ // simply the first owner-lite screen to call the network at module scope and so the
209
+ // first to meet it head-on. Fixing the stall is a core-runtime change tracked
210
+ // separately; not calling the network before the screen exists is right regardless.
211
+ //
212
+ // The self-kick was never load-bearing. Both hosts queue a `tier5.*` action
213
+ // dispatched before the worker is up — `Tier5WorkerSession.invoke` on Android and
214
+ // `HimalayaScreenHost.dispatch` on iOS — and both say in as many words that the
215
+ // self-kick is what made `onAppear` only LOOK like it worked. It also cost a
216
+ // second conversation-create attempt per open and minted the greeting with
217
+ // fallback copy, since the copy pack only arrives with the onAppear params.
190
218
  export { svc };
@@ -38,5 +38,14 @@ const svc = defineService<AriaHistoryState, {
38
38
  },
39
39
  });
40
40
 
41
- svc.load();
41
+ // NO module-scope `svc.load()` — same reason as the chat adapter next door, which
42
+ // carries the full explanation. This `load` opens with `getConversations`, so a
43
+ // self-kick makes a bridge call inside the bundle's own evaluation, and such a call
44
+ // stalls on the Android WebView (#2518).
45
+ //
46
+ // It is less damaging here than on the chat screen: this load has no create latch
47
+ // for a dead promise to poison, so the `onAppear` load issues its own request and
48
+ // the list still fills. What the self-kick leaves behind is a dispatch that never
49
+ // settles — `pendingDispatches` has no timeout, so it is held for the life of the
50
+ // worker, on every open. Not worth keeping for a call whose result nothing reads.
42
51
  export { svc };
@@ -186,5 +186,33 @@ const svc = defineService<AriaChatState, {
186
186
  },
187
187
  });
188
188
 
189
- svc.load();
189
+ // NO module-scope `svc.load()`, deliberately — the descriptor's `onAppear` is the
190
+ // only entry point, and on Android the self-kick did not merely duplicate it, it
191
+ // DISABLED the screen.
192
+ //
193
+ // `load` opens by creating a conversation, so a self-kick puts a `wixApi.call`
194
+ // inside the bundle's own evaluation — and a bridge call made during
195
+ // `worker.boot(bundle)` stalls on the Android WebView. The host completes it
196
+ // (`bridge_wix_call … ok=true` is logged between `bundle eval done` and
197
+ // `services=[…]`) but the JS promise never settles. `createOnce` then caches that
198
+ // promise as the per-site create latch, so the `onAppear` load — dispatched
199
+ // correctly, and fine on its own — awaits the same dead promise and never returns
200
+ // either. Result on Android: no greeting, no prompt chips, no conversation, and a
201
+ // Send that does nothing, for the life of the screen. Nothing reports it, because
202
+ // a pending dispatch has no timeout: an action that never settles is
203
+ // indistinguishable from one still running (#2518).
204
+ //
205
+ // That stall is a known Android defect, not a new one. `WebViewJSWorker` already
206
+ // prepends per-screen input into the bundle's own evaluate rather than assigning it
207
+ // separately, and says why: "the bundle's first wixApi.call could stall". Aria is
208
+ // simply the first owner-lite screen to call the network at module scope and so the
209
+ // first to meet it head-on. Fixing the stall is a core-runtime change tracked
210
+ // separately; not calling the network before the screen exists is right regardless.
211
+ //
212
+ // The self-kick was never load-bearing. Both hosts queue a `tier5.*` action
213
+ // dispatched before the worker is up — `Tier5WorkerSession.invoke` on Android and
214
+ // `HimalayaScreenHost.dispatch` on iOS — and both say in as many words that the
215
+ // self-kick is what made `onAppear` only LOOK like it worked. It also cost a
216
+ // second conversation-create attempt per open and minted the greeting with
217
+ // fallback copy, since the copy pack only arrives with the onAppear params.
190
218
  export { svc };
@@ -38,5 +38,14 @@ const svc = defineService<AriaHistoryState, {
38
38
  },
39
39
  });
40
40
 
41
- svc.load();
41
+ // NO module-scope `svc.load()` — same reason as the chat adapter next door, which
42
+ // carries the full explanation. This `load` opens with `getConversations`, so a
43
+ // self-kick makes a bridge call inside the bundle's own evaluation, and such a call
44
+ // stalls on the Android WebView (#2518).
45
+ //
46
+ // It is less damaging here than on the chat screen: this load has no create latch
47
+ // for a dead promise to poison, so the `onAppear` load issues its own request and
48
+ // the list still fills. What the self-kick leaves behind is a dispatch that never
49
+ // settles — `pendingDispatches` has no timeout, so it is held for the life of the
50
+ // worker, on every open. Not worth keeping for a call whose result nothing reads.
42
51
  export { svc };
@@ -186,5 +186,33 @@ const svc = defineService<AriaChatState, {
186
186
  },
187
187
  });
188
188
 
189
- svc.load();
189
+ // NO module-scope `svc.load()`, deliberately — the descriptor's `onAppear` is the
190
+ // only entry point, and on Android the self-kick did not merely duplicate it, it
191
+ // DISABLED the screen.
192
+ //
193
+ // `load` opens by creating a conversation, so a self-kick puts a `wixApi.call`
194
+ // inside the bundle's own evaluation — and a bridge call made during
195
+ // `worker.boot(bundle)` stalls on the Android WebView. The host completes it
196
+ // (`bridge_wix_call … ok=true` is logged between `bundle eval done` and
197
+ // `services=[…]`) but the JS promise never settles. `createOnce` then caches that
198
+ // promise as the per-site create latch, so the `onAppear` load — dispatched
199
+ // correctly, and fine on its own — awaits the same dead promise and never returns
200
+ // either. Result on Android: no greeting, no prompt chips, no conversation, and a
201
+ // Send that does nothing, for the life of the screen. Nothing reports it, because
202
+ // a pending dispatch has no timeout: an action that never settles is
203
+ // indistinguishable from one still running (#2518).
204
+ //
205
+ // That stall is a known Android defect, not a new one. `WebViewJSWorker` already
206
+ // prepends per-screen input into the bundle's own evaluate rather than assigning it
207
+ // separately, and says why: "the bundle's first wixApi.call could stall". Aria is
208
+ // simply the first owner-lite screen to call the network at module scope and so the
209
+ // first to meet it head-on. Fixing the stall is a core-runtime change tracked
210
+ // separately; not calling the network before the screen exists is right regardless.
211
+ //
212
+ // The self-kick was never load-bearing. Both hosts queue a `tier5.*` action
213
+ // dispatched before the worker is up — `Tier5WorkerSession.invoke` on Android and
214
+ // `HimalayaScreenHost.dispatch` on iOS — and both say in as many words that the
215
+ // self-kick is what made `onAppear` only LOOK like it worked. It also cost a
216
+ // second conversation-create attempt per open and minted the greeting with
217
+ // fallback copy, since the copy pack only arrives with the onAppear params.
190
218
  export { svc };
@@ -38,5 +38,14 @@ const svc = defineService<AriaHistoryState, {
38
38
  },
39
39
  });
40
40
 
41
- svc.load();
41
+ // NO module-scope `svc.load()` — same reason as the chat adapter next door, which
42
+ // carries the full explanation. This `load` opens with `getConversations`, so a
43
+ // self-kick makes a bridge call inside the bundle's own evaluation, and such a call
44
+ // stalls on the Android WebView (#2518).
45
+ //
46
+ // It is less damaging here than on the chat screen: this load has no create latch
47
+ // for a dead promise to poison, so the `onAppear` load issues its own request and
48
+ // the list still fills. What the self-kick leaves behind is a dispatch that never
49
+ // settles — `pendingDispatches` has no timeout, so it is held for the life of the
50
+ // worker, on every open. Not worth keeping for a call whose result nothing reads.
42
51
  export { svc };
@@ -186,5 +186,33 @@ const svc = defineService<AriaChatState, {
186
186
  },
187
187
  });
188
188
 
189
- svc.load();
189
+ // NO module-scope `svc.load()`, deliberately — the descriptor's `onAppear` is the
190
+ // only entry point, and on Android the self-kick did not merely duplicate it, it
191
+ // DISABLED the screen.
192
+ //
193
+ // `load` opens by creating a conversation, so a self-kick puts a `wixApi.call`
194
+ // inside the bundle's own evaluation — and a bridge call made during
195
+ // `worker.boot(bundle)` stalls on the Android WebView. The host completes it
196
+ // (`bridge_wix_call … ok=true` is logged between `bundle eval done` and
197
+ // `services=[…]`) but the JS promise never settles. `createOnce` then caches that
198
+ // promise as the per-site create latch, so the `onAppear` load — dispatched
199
+ // correctly, and fine on its own — awaits the same dead promise and never returns
200
+ // either. Result on Android: no greeting, no prompt chips, no conversation, and a
201
+ // Send that does nothing, for the life of the screen. Nothing reports it, because
202
+ // a pending dispatch has no timeout: an action that never settles is
203
+ // indistinguishable from one still running (#2518).
204
+ //
205
+ // That stall is a known Android defect, not a new one. `WebViewJSWorker` already
206
+ // prepends per-screen input into the bundle's own evaluate rather than assigning it
207
+ // separately, and says why: "the bundle's first wixApi.call could stall". Aria is
208
+ // simply the first owner-lite screen to call the network at module scope and so the
209
+ // first to meet it head-on. Fixing the stall is a core-runtime change tracked
210
+ // separately; not calling the network before the screen exists is right regardless.
211
+ //
212
+ // The self-kick was never load-bearing. Both hosts queue a `tier5.*` action
213
+ // dispatched before the worker is up — `Tier5WorkerSession.invoke` on Android and
214
+ // `HimalayaScreenHost.dispatch` on iOS — and both say in as many words that the
215
+ // self-kick is what made `onAppear` only LOOK like it worked. It also cost a
216
+ // second conversation-create attempt per open and minted the greeting with
217
+ // fallback copy, since the copy pack only arrives with the onAppear params.
190
218
  export { svc };
@@ -38,5 +38,14 @@ const svc = defineService<AriaHistoryState, {
38
38
  },
39
39
  });
40
40
 
41
- svc.load();
41
+ // NO module-scope `svc.load()` — same reason as the chat adapter next door, which
42
+ // carries the full explanation. This `load` opens with `getConversations`, so a
43
+ // self-kick makes a bridge call inside the bundle's own evaluation, and such a call
44
+ // stalls on the Android WebView (#2518).
45
+ //
46
+ // It is less damaging here than on the chat screen: this load has no create latch
47
+ // for a dead promise to poison, so the `onAppear` load issues its own request and
48
+ // the list still fills. What the self-kick leaves behind is a dispatch that never
49
+ // settles — `pendingDispatches` has no timeout, so it is held for the life of the
50
+ // worker, on every open. Not worth keeping for a call whose result nothing reads.
42
51
  export { svc };
@@ -186,5 +186,33 @@ const svc = defineService<AriaChatState, {
186
186
  },
187
187
  });
188
188
 
189
- svc.load();
189
+ // NO module-scope `svc.load()`, deliberately — the descriptor's `onAppear` is the
190
+ // only entry point, and on Android the self-kick did not merely duplicate it, it
191
+ // DISABLED the screen.
192
+ //
193
+ // `load` opens by creating a conversation, so a self-kick puts a `wixApi.call`
194
+ // inside the bundle's own evaluation — and a bridge call made during
195
+ // `worker.boot(bundle)` stalls on the Android WebView. The host completes it
196
+ // (`bridge_wix_call … ok=true` is logged between `bundle eval done` and
197
+ // `services=[…]`) but the JS promise never settles. `createOnce` then caches that
198
+ // promise as the per-site create latch, so the `onAppear` load — dispatched
199
+ // correctly, and fine on its own — awaits the same dead promise and never returns
200
+ // either. Result on Android: no greeting, no prompt chips, no conversation, and a
201
+ // Send that does nothing, for the life of the screen. Nothing reports it, because
202
+ // a pending dispatch has no timeout: an action that never settles is
203
+ // indistinguishable from one still running (#2518).
204
+ //
205
+ // That stall is a known Android defect, not a new one. `WebViewJSWorker` already
206
+ // prepends per-screen input into the bundle's own evaluate rather than assigning it
207
+ // separately, and says why: "the bundle's first wixApi.call could stall". Aria is
208
+ // simply the first owner-lite screen to call the network at module scope and so the
209
+ // first to meet it head-on. Fixing the stall is a core-runtime change tracked
210
+ // separately; not calling the network before the screen exists is right regardless.
211
+ //
212
+ // The self-kick was never load-bearing. Both hosts queue a `tier5.*` action
213
+ // dispatched before the worker is up — `Tier5WorkerSession.invoke` on Android and
214
+ // `HimalayaScreenHost.dispatch` on iOS — and both say in as many words that the
215
+ // self-kick is what made `onAppear` only LOOK like it worked. It also cost a
216
+ // second conversation-create attempt per open and minted the greeting with
217
+ // fallback copy, since the copy pack only arrives with the onAppear params.
190
218
  export { svc };
@@ -38,5 +38,14 @@ const svc = defineService<AriaHistoryState, {
38
38
  },
39
39
  });
40
40
 
41
- svc.load();
41
+ // NO module-scope `svc.load()` — same reason as the chat adapter next door, which
42
+ // carries the full explanation. This `load` opens with `getConversations`, so a
43
+ // self-kick makes a bridge call inside the bundle's own evaluation, and such a call
44
+ // stalls on the Android WebView (#2518).
45
+ //
46
+ // It is less damaging here than on the chat screen: this load has no create latch
47
+ // for a dead promise to poison, so the `onAppear` load issues its own request and
48
+ // the list still fills. What the self-kick leaves behind is a dispatch that never
49
+ // settles — `pendingDispatches` has no timeout, so it is held for the life of the
50
+ // worker, on every open. Not worth keeping for a call whose result nothing reads.
42
51
  export { svc };
@@ -186,5 +186,33 @@ const svc = defineService<AriaChatState, {
186
186
  },
187
187
  });
188
188
 
189
- svc.load();
189
+ // NO module-scope `svc.load()`, deliberately — the descriptor's `onAppear` is the
190
+ // only entry point, and on Android the self-kick did not merely duplicate it, it
191
+ // DISABLED the screen.
192
+ //
193
+ // `load` opens by creating a conversation, so a self-kick puts a `wixApi.call`
194
+ // inside the bundle's own evaluation — and a bridge call made during
195
+ // `worker.boot(bundle)` stalls on the Android WebView. The host completes it
196
+ // (`bridge_wix_call … ok=true` is logged between `bundle eval done` and
197
+ // `services=[…]`) but the JS promise never settles. `createOnce` then caches that
198
+ // promise as the per-site create latch, so the `onAppear` load — dispatched
199
+ // correctly, and fine on its own — awaits the same dead promise and never returns
200
+ // either. Result on Android: no greeting, no prompt chips, no conversation, and a
201
+ // Send that does nothing, for the life of the screen. Nothing reports it, because
202
+ // a pending dispatch has no timeout: an action that never settles is
203
+ // indistinguishable from one still running (#2518).
204
+ //
205
+ // That stall is a known Android defect, not a new one. `WebViewJSWorker` already
206
+ // prepends per-screen input into the bundle's own evaluate rather than assigning it
207
+ // separately, and says why: "the bundle's first wixApi.call could stall". Aria is
208
+ // simply the first owner-lite screen to call the network at module scope and so the
209
+ // first to meet it head-on. Fixing the stall is a core-runtime change tracked
210
+ // separately; not calling the network before the screen exists is right regardless.
211
+ //
212
+ // The self-kick was never load-bearing. Both hosts queue a `tier5.*` action
213
+ // dispatched before the worker is up — `Tier5WorkerSession.invoke` on Android and
214
+ // `HimalayaScreenHost.dispatch` on iOS — and both say in as many words that the
215
+ // self-kick is what made `onAppear` only LOOK like it worked. It also cost a
216
+ // second conversation-create attempt per open and minted the greeting with
217
+ // fallback copy, since the copy pack only arrives with the onAppear params.
190
218
  export { svc };
@@ -38,5 +38,14 @@ const svc = defineService<AriaHistoryState, {
38
38
  },
39
39
  });
40
40
 
41
- svc.load();
41
+ // NO module-scope `svc.load()` — same reason as the chat adapter next door, which
42
+ // carries the full explanation. This `load` opens with `getConversations`, so a
43
+ // self-kick makes a bridge call inside the bundle's own evaluation, and such a call
44
+ // stalls on the Android WebView (#2518).
45
+ //
46
+ // It is less damaging here than on the chat screen: this load has no create latch
47
+ // for a dead promise to poison, so the `onAppear` load issues its own request and
48
+ // the list still fills. What the self-kick leaves behind is a dispatch that never
49
+ // settles — `pendingDispatches` has no timeout, so it is held for the life of the
50
+ // worker, on every open. Not worth keeping for a call whose result nothing reads.
42
51
  export { svc };
@@ -186,5 +186,33 @@ const svc = defineService<AriaChatState, {
186
186
  },
187
187
  });
188
188
 
189
- svc.load();
189
+ // NO module-scope `svc.load()`, deliberately — the descriptor's `onAppear` is the
190
+ // only entry point, and on Android the self-kick did not merely duplicate it, it
191
+ // DISABLED the screen.
192
+ //
193
+ // `load` opens by creating a conversation, so a self-kick puts a `wixApi.call`
194
+ // inside the bundle's own evaluation — and a bridge call made during
195
+ // `worker.boot(bundle)` stalls on the Android WebView. The host completes it
196
+ // (`bridge_wix_call … ok=true` is logged between `bundle eval done` and
197
+ // `services=[…]`) but the JS promise never settles. `createOnce` then caches that
198
+ // promise as the per-site create latch, so the `onAppear` load — dispatched
199
+ // correctly, and fine on its own — awaits the same dead promise and never returns
200
+ // either. Result on Android: no greeting, no prompt chips, no conversation, and a
201
+ // Send that does nothing, for the life of the screen. Nothing reports it, because
202
+ // a pending dispatch has no timeout: an action that never settles is
203
+ // indistinguishable from one still running (#2518).
204
+ //
205
+ // That stall is a known Android defect, not a new one. `WebViewJSWorker` already
206
+ // prepends per-screen input into the bundle's own evaluate rather than assigning it
207
+ // separately, and says why: "the bundle's first wixApi.call could stall". Aria is
208
+ // simply the first owner-lite screen to call the network at module scope and so the
209
+ // first to meet it head-on. Fixing the stall is a core-runtime change tracked
210
+ // separately; not calling the network before the screen exists is right regardless.
211
+ //
212
+ // The self-kick was never load-bearing. Both hosts queue a `tier5.*` action
213
+ // dispatched before the worker is up — `Tier5WorkerSession.invoke` on Android and
214
+ // `HimalayaScreenHost.dispatch` on iOS — and both say in as many words that the
215
+ // self-kick is what made `onAppear` only LOOK like it worked. It also cost a
216
+ // second conversation-create attempt per open and minted the greeting with
217
+ // fallback copy, since the copy pack only arrives with the onAppear params.
190
218
  export { svc };
@@ -38,5 +38,14 @@ const svc = defineService<AriaHistoryState, {
38
38
  },
39
39
  });
40
40
 
41
- svc.load();
41
+ // NO module-scope `svc.load()` — same reason as the chat adapter next door, which
42
+ // carries the full explanation. This `load` opens with `getConversations`, so a
43
+ // self-kick makes a bridge call inside the bundle's own evaluation, and such a call
44
+ // stalls on the Android WebView (#2518).
45
+ //
46
+ // It is less damaging here than on the chat screen: this load has no create latch
47
+ // for a dead promise to poison, so the `onAppear` load issues its own request and
48
+ // the list still fills. What the self-kick leaves behind is a dispatch that never
49
+ // settles — `pendingDispatches` has no timeout, so it is held for the life of the
50
+ // worker, on every open. Not worth keeping for a call whose result nothing reads.
42
51
  export { svc };
@@ -186,5 +186,33 @@ const svc = defineService<AriaChatState, {
186
186
  },
187
187
  });
188
188
 
189
- svc.load();
189
+ // NO module-scope `svc.load()`, deliberately — the descriptor's `onAppear` is the
190
+ // only entry point, and on Android the self-kick did not merely duplicate it, it
191
+ // DISABLED the screen.
192
+ //
193
+ // `load` opens by creating a conversation, so a self-kick puts a `wixApi.call`
194
+ // inside the bundle's own evaluation — and a bridge call made during
195
+ // `worker.boot(bundle)` stalls on the Android WebView. The host completes it
196
+ // (`bridge_wix_call … ok=true` is logged between `bundle eval done` and
197
+ // `services=[…]`) but the JS promise never settles. `createOnce` then caches that
198
+ // promise as the per-site create latch, so the `onAppear` load — dispatched
199
+ // correctly, and fine on its own — awaits the same dead promise and never returns
200
+ // either. Result on Android: no greeting, no prompt chips, no conversation, and a
201
+ // Send that does nothing, for the life of the screen. Nothing reports it, because
202
+ // a pending dispatch has no timeout: an action that never settles is
203
+ // indistinguishable from one still running (#2518).
204
+ //
205
+ // That stall is a known Android defect, not a new one. `WebViewJSWorker` already
206
+ // prepends per-screen input into the bundle's own evaluate rather than assigning it
207
+ // separately, and says why: "the bundle's first wixApi.call could stall". Aria is
208
+ // simply the first owner-lite screen to call the network at module scope and so the
209
+ // first to meet it head-on. Fixing the stall is a core-runtime change tracked
210
+ // separately; not calling the network before the screen exists is right regardless.
211
+ //
212
+ // The self-kick was never load-bearing. Both hosts queue a `tier5.*` action
213
+ // dispatched before the worker is up — `Tier5WorkerSession.invoke` on Android and
214
+ // `HimalayaScreenHost.dispatch` on iOS — and both say in as many words that the
215
+ // self-kick is what made `onAppear` only LOOK like it worked. It also cost a
216
+ // second conversation-create attempt per open and minted the greeting with
217
+ // fallback copy, since the copy pack only arrives with the onAppear params.
190
218
  export { svc };
@@ -38,5 +38,14 @@ const svc = defineService<AriaHistoryState, {
38
38
  },
39
39
  });
40
40
 
41
- svc.load();
41
+ // NO module-scope `svc.load()` — same reason as the chat adapter next door, which
42
+ // carries the full explanation. This `load` opens with `getConversations`, so a
43
+ // self-kick makes a bridge call inside the bundle's own evaluation, and such a call
44
+ // stalls on the Android WebView (#2518).
45
+ //
46
+ // It is less damaging here than on the chat screen: this load has no create latch
47
+ // for a dead promise to poison, so the `onAppear` load issues its own request and
48
+ // the list still fills. What the self-kick leaves behind is a dispatch that never
49
+ // settles — `pendingDispatches` has no timeout, so it is held for the life of the
50
+ // worker, on every open. Not worth keeping for a call whose result nothing reads.
42
51
  export { svc };