@wix/himalaya-cli 0.1450.0 → 0.1452.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/cli.mjs CHANGED
@@ -8059,6 +8059,7 @@ function buttonVariant(style) {
8059
8059
  var SYSTEM_FONT_FAMILY, TONAL_ELEVATION_ALPHA, BUTTON_MIN_HIT_TARGET, nonNegative, nonEmpty2, own, COLOR_TOKEN_PROPS, TYPOGRAPHY_TOKEN_PROPS, BUTTON_VARIANTS;
8060
8060
  var init_tokens = __esm({
8061
8061
  "../../core/ts/src/tokens.ts"() {
8062
+ "use strict";
8062
8063
  SYSTEM_FONT_FAMILY = "$system";
8063
8064
  TONAL_ELEVATION_ALPHA = [0, 0.05, 0.08, 0.11, 0.12, 0.14];
8064
8065
  BUTTON_MIN_HIT_TARGET = 44;
@@ -8114,6 +8115,7 @@ function resolveTranslation(value, catalog3, sourceCatalog) {
8114
8115
  var BINDING_SIGILS, BINDING_SIGIL_RE, TRANSLATION_PREFIX, TRANSLATION_KEY_RE;
8115
8116
  var init_bindings = __esm({
8116
8117
  "../../core/ts/src/bindings.ts"() {
8118
+ "use strict";
8117
8119
  BINDING_SIGILS = ["service", "flag", "item", "t"];
8118
8120
  BINDING_SIGIL_RE = new RegExp(
8119
8121
  `^\\$(?:${BINDING_SIGILS.filter((s2) => s2 !== "t").join("|")})\\b|^\\$t:`
@@ -20256,6 +20258,11 @@ function roleOf(name) {
20256
20258
  if (n2.includes("accent") || n2.includes("primary") || n2.includes("link")) return "accent";
20257
20259
  return "other";
20258
20260
  }
20261
+ function isLegacyLightOnly(colors) {
20262
+ if (!colors) return true;
20263
+ for (const v2 of Object.values(colors)) if (v2 != null && typeof v2 === "object") return false;
20264
+ return true;
20265
+ }
20259
20266
  function synthScheme(hex2, name, scheme) {
20260
20267
  if (scheme === "light") return hex2;
20261
20268
  const hsl = hexToHsl(hex2);
@@ -20330,6 +20337,7 @@ function baseKitMotionDefaults(resolved2, source) {
20330
20337
  }
20331
20338
  function makeTokenResolvers(source, scheme, idiom = WEB_IDIOM_CONTEXT) {
20332
20339
  const tokens2 = baseKitMotionDefaults(resolveIdiom(source, idiom), source);
20340
+ const synthesize = isLegacyLightOnly(tokens2.colors);
20333
20341
  const color = (name, fallback = "#1a1a1a") => {
20334
20342
  if (name == null) return fallback;
20335
20343
  if (typeof name !== "string") {
@@ -20347,7 +20355,7 @@ function makeTokenResolvers(source, scheme, idiom = WEB_IDIOM_CONTEXT) {
20347
20355
  const direct = resolveSchemeColor(v2, scheme);
20348
20356
  return typeof direct === "string" ? direct : fallback;
20349
20357
  }
20350
- return synthScheme(v2, name, scheme);
20358
+ return synthesize ? synthScheme(v2, name, scheme) : v2;
20351
20359
  };
20352
20360
  const font = (style = "body") => {
20353
20361
  const t2 = tokens2.typography?.[style] ?? tokens2.fonts?.[style] ?? tokens2.typography?.body ?? tokens2.fonts?.body;
@@ -38214,6 +38222,12 @@ function browserIsRTL() {
38214
38222
  }
38215
38223
  return false;
38216
38224
  }
38225
+ function ambientIsRTL(isRTL) {
38226
+ return isRTL ?? browserIsRTL();
38227
+ }
38228
+ function layoutIsRTL(ctx) {
38229
+ return ctx.layoutRTL ?? ambientIsRTL(ctx.isRTL);
38230
+ }
38217
38231
  function ctxEnv(ctx) {
38218
38232
  return {
38219
38233
  scheme: ctx.scheme,
@@ -38501,7 +38515,7 @@ function variantStyle(variant, tk, baseBackground) {
38501
38515
  return {};
38502
38516
  }
38503
38517
  }
38504
- function makeModStyle(tk) {
38518
+ function makeModStyle(tk, isRTL = () => false) {
38505
38519
  return function modStyle(mods) {
38506
38520
  if (!mods) return {};
38507
38521
  if (mods.hidden === true) return { display: "none" };
@@ -38594,7 +38608,8 @@ function makeModStyle(tk) {
38594
38608
  const ox = pick(mods.offsetX, mods.offset_x);
38595
38609
  const oy = pick(mods.offsetY, mods.offset_y);
38596
38610
  if (ox != null && ox !== 0 || oy != null && oy !== 0) {
38597
- const tr2 = `translate(${ox ?? 0}px, ${oy ?? 0}px)`;
38611
+ const tx = ox != null && ox !== 0 && isRTL() ? -ox : ox ?? 0;
38612
+ const tr2 = `translate(${tx}px, ${oy ?? 0}px)`;
38598
38613
  s2.transform = s2.transform ? `${s2.transform} ${tr2}` : tr2;
38599
38614
  }
38600
38615
  const maskCss = gradientCss(mods.mask, tk);
@@ -123101,7 +123116,7 @@ function makeCtx(tokens2, scheme = "light", opts = {}) {
123101
123116
  sizeClass: opts.sizeClass,
123102
123117
  isRTL: opts.isRTL,
123103
123118
  containerWidth: opts.containerWidth,
123104
- modStyle: makeModStyle(tk),
123119
+ modStyle: makeModStyle(tk, () => ambientIsRTL(opts.isRTL)),
123105
123120
  catalog: opts.catalog,
123106
123121
  localeTag: opts.localeTag,
123107
123122
  provider,
@@ -123147,7 +123162,7 @@ function withTheme(ctx, theme) {
123147
123162
  spacing: { ...base.spacing ?? {}, ...theme.spacing ?? {} }
123148
123163
  };
123149
123164
  const tk = makeTokenResolvers(merged, ctx.scheme, ctx.idiomContext);
123150
- return { ...ctx, ...tk, modStyle: makeModStyle(tk) };
123165
+ return { ...ctx, ...tk, modStyle: makeModStyle(tk, () => layoutIsRTL(ctx)) };
123151
123166
  }
123152
123167
  function ensureValueSwapKeyframes() {
123153
123168
  ensureTransitionKeyframes();
@@ -125295,6 +125310,11 @@ function renderInner(node, ctx) {
125295
125310
  const hListItem = ctx.hListItem === true;
125296
125311
  if (modifiers?.theme) ctx = withTheme(ctx, resolveItemDeep2(modifiers.theme, ctx));
125297
125312
  if (ctx.hListItem) ctx = { ...ctx, hListItem: false };
125313
+ const ld = modifiers?.layoutDirection ?? modifiers?.layout_direction;
125314
+ if ((ld === "ltr" || ld === "rtl") && layoutIsRTL(ctx) !== (ld === "rtl")) {
125315
+ const pinnedRTL = ld === "rtl";
125316
+ ctx = { ...ctx, layoutRTL: pinnedRTL, modStyle: makeModStyle(ctx, () => pinnedRTL) };
125317
+ }
125298
125318
  const pkg = node.body?.package;
125299
125319
  const C2 = ctx.color;
125300
125320
  const wrap = ctx.modStyle(resolveModBindings(modifiers, ctx));
@@ -126993,6 +127013,7 @@ var init_renderNode = __esm({
126993
127013
  submit();
126994
127014
  };
126995
127015
  const inputBase = { flex: 1, minWidth: 0, minHeight: multilineBox ? 44 : void 0, alignSelf: "stretch", border: "none", outline: "none", background: "transparent", padding: multilineBox ? 0 : "11px 0", margin: 0, width: "100%", boxSizing: "border-box", fontFamily: bodyFont(ctx), fontSize: pxToRem(15), color: C2("textPrimary", "#13171e"), resize: "none" };
127016
+ const fieldDir = layoutIsRTL(ctx) ? "auto" : void 0;
126996
127017
  const accIcon = (name) => /* @__PURE__ */ jsx10("span", { style: { display: "inline-grid", placeItems: "center", width: 18, height: 18, flex: "none" }, children: iconSvg(name, { size: 17, color: muted }) });
126997
127018
  const box = borderless ? { display: "flex", alignItems: "center", gap: 8, width: "100%", boxSizing: "border-box", ...wrap } : { display: "flex", alignItems: "center", gap: 8, width: "100%", background: C2("surfacePrimary", "#fff"), border: `1px solid ${errored ? C2("danger", "#E62214") : C2("border", "#e3e3e3")}`, borderRadius: ctx.radius("md", 8), padding: multilineBox ? "11px 14px" : "0 14px", boxSizing: "border-box", minHeight: multilineBox ? 48 : 44, ...wrap };
126998
127019
  const composedBox = addIntrinsicPadding(box, wrap) ?? box;
@@ -127001,7 +127022,7 @@ var init_renderNode = __esm({
127001
127022
  /* @__PURE__ */ jsxs7("div", { style: composedBox, children: [
127002
127023
  props.leadingIcon && accIcon(props.leadingIcon),
127003
127024
  prefixText && /* @__PURE__ */ jsx10("span", { style: { color: muted, flex: "none" }, children: prefixText }),
127004
- multilineBox ? /* @__PURE__ */ jsx10("textarea", { "data-component-id": componentId, id: fieldDomId, "data-component-type": componentType, ...a11yFwd, ref: inputRef, value: local, onChange: onInput, onKeyDown, onFocus: onFieldFocus, onBlur: onFieldBlur, placeholder: placeholder3, rows: 2, "aria-label": ariaLabelProp ?? placeholderName, "aria-labelledby": labelledBy, "aria-required": required3, "aria-invalid": errored || void 0, "aria-describedby": [errorId, describedByProp].filter(Boolean).join(" ") || void 0, inputMode, autoCapitalize, maxLength, autoCorrect: suggestOff ? "off" : suggestOn ? "on" : void 0, spellCheck: suggestOff ? false : suggestOn ? true : void 0, autoComplete: suggestOff ? "off" : void 0, style: inputBase }) : /* @__PURE__ */ jsx10("input", { "data-component-id": componentId, id: htmlId, "data-component-type": componentType, ...a11yFwd, ref: inputRef, type: secure && !(visibilityToggle && valueVisible) ? "password" : "text", value: local, onChange: onInput, onKeyDown, onFocus: onFieldFocus, onBlur: onFieldBlur, placeholder: placeholder3, "aria-label": ariaLabelProp ?? placeholderName, "aria-labelledby": labelledBy, "aria-required": required3, "aria-invalid": errored || void 0, "aria-describedby": [errorId, describedByProp].filter(Boolean).join(" ") || void 0, inputMode, autoCapitalize, maxLength, autoCorrect: suggestOff ? "off" : suggestOn ? "on" : void 0, spellCheck: suggestOff ? false : suggestOn ? true : void 0, autoComplete: suggestOff ? "off" : void 0, enterKeyHint, style: inputBase }),
127025
+ multilineBox ? /* @__PURE__ */ jsx10("textarea", { "data-component-id": componentId, id: fieldDomId, "data-component-type": componentType, ...a11yFwd, ref: inputRef, value: local, onChange: onInput, onKeyDown, onFocus: onFieldFocus, onBlur: onFieldBlur, placeholder: placeholder3, dir: fieldDir, rows: 2, "aria-label": ariaLabelProp ?? placeholderName, "aria-labelledby": labelledBy, "aria-required": required3, "aria-invalid": errored || void 0, "aria-describedby": [errorId, describedByProp].filter(Boolean).join(" ") || void 0, inputMode, autoCapitalize, maxLength, autoCorrect: suggestOff ? "off" : suggestOn ? "on" : void 0, spellCheck: suggestOff ? false : suggestOn ? true : void 0, autoComplete: suggestOff ? "off" : void 0, style: inputBase }) : /* @__PURE__ */ jsx10("input", { "data-component-id": componentId, id: htmlId, "data-component-type": componentType, ...a11yFwd, ref: inputRef, type: secure && !(visibilityToggle && valueVisible) ? "password" : "text", value: local, onChange: onInput, onKeyDown, onFocus: onFieldFocus, onBlur: onFieldBlur, placeholder: placeholder3, dir: fieldDir, "aria-label": ariaLabelProp ?? placeholderName, "aria-labelledby": labelledBy, "aria-required": required3, "aria-invalid": errored || void 0, "aria-describedby": [errorId, describedByProp].filter(Boolean).join(" ") || void 0, inputMode, autoCapitalize, maxLength, autoCorrect: suggestOff ? "off" : suggestOn ? "on" : void 0, spellCheck: suggestOff ? false : suggestOn ? true : void 0, autoComplete: suggestOff ? "off" : void 0, enterKeyHint, style: inputBase }),
127005
127026
  suffixText && /* @__PURE__ */ jsx10("span", { style: { color: muted, flex: "none" }, children: suffixText }),
127006
127027
  props.clearButton && local && /* @__PURE__ */ jsx10("span", { onClick: () => {
127007
127028
  setLocal("");
@@ -128118,6 +128139,7 @@ var init_renderNode = __esm({
128118
128139
  "input",
128119
128140
  {
128120
128141
  value: local,
128142
+ dir: layoutIsRTL(ctx) ? "auto" : void 0,
128121
128143
  onChange: (e2) => onInput(e2.currentTarget.value),
128122
128144
  onKeyDown: (e2) => {
128123
128145
  if (e2.key === "Enter") {
@@ -128490,8 +128512,9 @@ var init_renderNode = __esm({
128490
128512
  const revealMarkdown = props.markdown === true && revealSource != null ? mdSource ?? revealSource : null;
128491
128513
  const content = countContent != null ? countContent : revealSource != null && revealSource !== "" ? /* @__PURE__ */ jsx10(RevealText, { text: revealSource, reduce: ctx.reduceMotion(), markdownHtml: revealMarkdown != null ? mdInline(revealMarkdown, accentTextColor(ctx)).__html : void 0 }) : icuPattern != null ? /* @__PURE__ */ jsx10(InterpolatedTextView, { pattern: icuPattern, params: props.template?.params ?? {}, ctx }) : mdSource != null ? /* @__PURE__ */ jsx10("span", { dangerouslySetInnerHTML: mdInline(mdSource, accentTextColor(ctx)) }) : txt(props.text, ctx);
128492
128514
  const authoredDirection = props.textDirection === "auto" || props.textDirection === "ltr" || props.textDirection === "rtl";
128515
+ const layoutRTL = !authoredDirection && layoutIsRTL(ctx);
128493
128516
  const dir = authoredDirection ? props.textDirection : "auto";
128494
- const tAlign = props.textAlign === "center" ? "center" : props.textAlign === "trailing" ? authoredDirection ? "end" : "right" : props.textAlign === "justify" ? "justify" : props.textAlign === "leading" ? authoredDirection ? "start" : "left" : void 0;
128517
+ const tAlign = props.textAlign === "center" ? "center" : props.textAlign === "trailing" ? authoredDirection ? "end" : layoutRTL ? "left" : "right" : props.textAlign === "justify" ? "justify" : props.textAlign === "leading" ? authoredDirection ? "start" : layoutRTL ? "right" : "left" : layoutRTL ? "right" : void 0;
128495
128518
  const tDecor = props.decoration === "strikethrough" ? "line-through" : props.decoration === "underline" ? "underline" : void 0;
128496
128519
  const ln2 = typeof props.lineSpacing === "number" ? pxToRem((f2.line ?? 1.4) * f2.size + props.lineSpacing) : f2.line;
128497
128520
  const swapped = textSwap > 0 && content != null && content !== "" ? (ensureValueSwapKeyframes(), /* @__PURE__ */ jsx10("span", { style: { animation: `himalaya-enter-fade ${motionDefaultsDuration(ctx.kit, 200)}ms cubic-bezier(0.2,0,0,1) both` }, children: content }, textSwap)) : content;
@@ -129385,7 +129408,7 @@ var init_renderNode = __esm({
129385
129408
  ctx.onAction({ ...action, args: { ...action.args, value: v2, index: i2 } });
129386
129409
  }, style: { minWidth: 44, minHeight: 44, border: 0, background: "transparent", color: "inherit", opacity: 0.6, cursor: props.disabled ? "default" : "pointer", fontSize: pxToRem(13) }, children: "\xD7" })
129387
129410
  ] }, i2)),
129388
- props.onAdd ? /* @__PURE__ */ jsx10("input", { "aria-label": placeholderText || "Add a chip", placeholder: placeholderText || "Add\u2026", value: draft, disabled: !!props.disabled || !ctx.onAction, onChange: (event) => setDraft(event.currentTarget.value), onKeyDown: (event) => {
129411
+ props.onAdd ? /* @__PURE__ */ jsx10("input", { "aria-label": placeholderText || "Add a chip", placeholder: placeholderText || "Add\u2026", dir: layoutIsRTL(ctx) ? "auto" : void 0, value: draft, disabled: !!props.disabled || !ctx.onAction, onChange: (event) => setDraft(event.currentTarget.value), onKeyDown: (event) => {
129389
129412
  if (event.key !== "Enter" || event.nativeEvent.isComposing || props.disabled || !ctx.onAction) return;
129390
129413
  event.preventDefault();
129391
129414
  const value = draft.trim();
@@ -129598,8 +129621,9 @@ var init_renderNode = __esm({
129598
129621
  const W2 = 100;
129599
129622
  const H2 = 100;
129600
129623
  const all = drawable.flatMap((sr2) => sr2.values);
129601
- const min = Math.min(...all);
129602
- const max = Math.max(...all);
129624
+ const hasBars = drawable.some((sr2) => sr2.kind === "bar");
129625
+ const min = hasBars ? Math.min(0, ...all) : Math.min(...all);
129626
+ const max = hasBars ? Math.max(0, ...all) : Math.max(...all);
129603
129627
  const span = max - min || 1;
129604
129628
  const yAt = (v2) => H2 - (v2 - min) / span * H2;
129605
129629
  const xAt = (i2, n2) => n2 === 1 ? W2 / 2 : i2 / (n2 - 1) * W2;
@@ -129612,13 +129636,14 @@ var init_renderNode = __esm({
129612
129636
  const w2 = Math.max(barGeom.width, 0.5);
129613
129637
  return /* @__PURE__ */ jsx10("g", { "data-series": sr2.label || si2, children: sr2.values.map((v2, i2) => {
129614
129638
  const top = yAt(v2);
129639
+ const base = yAt(0);
129615
129640
  return /* @__PURE__ */ jsx10(
129616
129641
  "rect",
129617
129642
  {
129618
129643
  x: barGeom.lefts[lane]?.[i2] ?? 0,
129619
- y: top,
129644
+ y: Math.min(top, base),
129620
129645
  width: w2,
129621
- height: Math.max(H2 - top, 0.5),
129646
+ height: Math.max(Math.abs(base - top), 0.5),
129622
129647
  fill: sr2.color
129623
129648
  },
129624
129649
  i2
@@ -161521,32 +161546,32 @@ var init_preview_assets_generated = __esm({
161521
161546
  "../../packages/serve/src/preview-assets.generated.ts"() {
161522
161547
  init_preview_assets_format();
161523
161548
  PREVIEW_ASSET_MANIFEST = [
161524
- { key: "assets/DashboardHost-C0zY6LXc.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 2916, sha256: "2ae0514356f33d624fbdea4f37763d9485585ae8c47efda81e9fd4976134aa66" },
161525
- { key: "assets/DevDrawer--HNffqm4.js", contentType: "application/javascript; charset=utf-8", offset: 2924, length: 16744, sha256: "bc1aa20ec7d0244b30ee071da75acf380ebc7087013247c78a6a4f813ee42658" },
161526
- { key: "assets/IdiomCompare-BcPm59UD.js", contentType: "application/javascript; charset=utf-8", offset: 19668, length: 1892, sha256: "e47795d60a59d872dc9d1a31cf166940f4eeb1683e2bc858b62da24f1d7835b2" },
161527
- { key: "assets/LightboxViewer-B3iMQPin.js", contentType: "application/javascript; charset=utf-8", offset: 21560, length: 8132, sha256: "7a035923df5986b7775d3398725f9234d1d7ddf46e0a5af8e9f6bd74d771590d" },
161528
- { key: "assets/PhonePreviewControl-CRKLF95b.js", contentType: "application/javascript; charset=utf-8", offset: 29692, length: 37729, sha256: "e65e0be6f821b3fd13c847c5ae7fff2880a39bf603a3bd426878af78e3d814a7" },
161529
- { key: "assets/SchemeCompare-Bn99KkCH.js", contentType: "application/javascript; charset=utf-8", offset: 67421, length: 1824, sha256: "7f2f13e931a686d80e03ce3673dc16e93619c93326fb447d216ee2e5bffc4807" },
161530
- { key: "assets/index-DFazEEqa.js", contentType: "application/javascript; charset=utf-8", offset: 69245, length: 1268538, sha256: "3718cafcaf0cdc962f5d1c5d6bc3cf5e9ee2b1f11e918fb7e9c629e5b0a49576" },
161531
- { key: "assets/pdf-NnG-NcU-.js", contentType: "application/javascript; charset=utf-8", offset: 1337783, length: 488199, sha256: "f60ce93a839789588474a844c60da2ebc210efbd3f50f04cc4e44eb8e127cddc" },
161532
- { key: "assets/pdf.worker.min-BQa_JDET.js", contentType: "application/javascript; charset=utf-8", offset: 1825982, length: 73, sha256: "41bcfda4f3c8c0a81c785ea87c69afc8e7d0ed8c333324aee94c273d881bb6aa" },
161533
- { key: "assets/pdf.worker.min-BmVo14Nb.mjs", contentType: "application/javascript; charset=utf-8", offset: 1826055, length: 1317034, sha256: "a33cfe728c584fdba4fcc1fd54bcdc2f9f2f13889ddbb5b2bd1d0f8cbe49b84e" },
161534
- { key: "assets/pdfDocument-MaeR1HVD.js", contentType: "application/javascript; charset=utf-8", offset: 3143089, length: 2868, sha256: "2752019f5f58a8818f6471de600ccfb647cfab7577501d19d0eface21e7820dc" },
161535
- { key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 3145957, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
161536
- { key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 3150567, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
161537
- { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 3639151, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
161538
- { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 3730075, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
161539
- { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 3821059, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
161540
- { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 3912039, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
161541
- { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 4002911, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
161542
- { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 4093891, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
161543
- { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 4202527, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
161544
- { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 4311611, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
161545
- { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 4420659, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
161546
- { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 4528359, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
161547
- { key: "himi-sw.js", contentType: "application/javascript; charset=utf-8", offset: 4616467, length: 6748, sha256: "4a92459977d7cefa1a6a7e020c3a63509737f083b3f2773557c1a5771665811a" },
161548
- { key: "index.html", contentType: "text/html; charset=utf-8", offset: 4623215, length: 4947, sha256: "31e294c8a2eff7f23f4b24e1696713854eb517ad048ef9cc6967c90b9abca5ba" },
161549
- { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 4628162, length: 17786, sha256: "084107ca997628c248f1b0ba3a7494744850df39fad813546ab8bdb82a6058da" }
161549
+ { key: "assets/DashboardHost-DHg737_J.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 2916, sha256: "ba02376a739002a2cfdddf2171a88943fefe3c96d891acaffdaf7a6269a21c7f" },
161550
+ { key: "assets/DevDrawer-Dv0jOOVg.js", contentType: "application/javascript; charset=utf-8", offset: 2924, length: 16744, sha256: "6f2432ca864fd12307ebe508972896f80b939688049261b810c20677cdf47aeb" },
161551
+ { key: "assets/IdiomCompare-B3ygKWWA.js", contentType: "application/javascript; charset=utf-8", offset: 19668, length: 1892, sha256: "e0c2f6385823c78ca9ebafbc6ad1a6911429afaf4e672e8c0806760f872d22bf" },
161552
+ { key: "assets/LightboxViewer-dk9y5AXX.js", contentType: "application/javascript; charset=utf-8", offset: 21560, length: 8132, sha256: "1f1fc6d36e57b8ad8737abf7a275b5d42c1e8448b32a6a1f40abd2ff580f1faf" },
161553
+ { key: "assets/PhonePreviewControl-DG7jCSLI.js", contentType: "application/javascript; charset=utf-8", offset: 29692, length: 37729, sha256: "de51e874734effc34cf7ccf8fe6ea87fb831fdaa87af947456fa5b2852c5eda4" },
161554
+ { key: "assets/SchemeCompare-CAIZvnUI.js", contentType: "application/javascript; charset=utf-8", offset: 67421, length: 1824, sha256: "0557f704437af69e3ff81ea229379ecbb1e25acb321e34c67feae6026e7f0277" },
161555
+ { key: "assets/index-tRKXWUtH.js", contentType: "application/javascript; charset=utf-8", offset: 69245, length: 1269195, sha256: "a3c8a7d117e9057a19bd0e1e162df14bd67d783dad938fa18c0b46c128e491c3" },
161556
+ { key: "assets/pdf-BGZQFD3z.js", contentType: "application/javascript; charset=utf-8", offset: 1338440, length: 488199, sha256: "45778957c20ba1348ec582d28916eadaad6808aa9d7c6244e3d29ad7d72ff14e" },
161557
+ { key: "assets/pdf.worker.min-BQa_JDET.js", contentType: "application/javascript; charset=utf-8", offset: 1826639, length: 73, sha256: "41bcfda4f3c8c0a81c785ea87c69afc8e7d0ed8c333324aee94c273d881bb6aa" },
161558
+ { key: "assets/pdf.worker.min-BmVo14Nb.mjs", contentType: "application/javascript; charset=utf-8", offset: 1826712, length: 1317034, sha256: "a33cfe728c584fdba4fcc1fd54bcdc2f9f2f13889ddbb5b2bd1d0f8cbe49b84e" },
161559
+ { key: "assets/pdfDocument-BK3iUf4H.js", contentType: "application/javascript; charset=utf-8", offset: 3143746, length: 2868, sha256: "b6af1f9159b81971953dc0d06431ccb130b2ecbf473459332db6de4cc4cbbbb7" },
161560
+ { key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 3146614, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
161561
+ { key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 3151224, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
161562
+ { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 3639808, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
161563
+ { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 3730732, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
161564
+ { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 3821716, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
161565
+ { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 3912696, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
161566
+ { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 4003568, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
161567
+ { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 4094548, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
161568
+ { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 4203184, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
161569
+ { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 4312268, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
161570
+ { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 4421316, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
161571
+ { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 4529016, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
161572
+ { key: "himi-sw.js", contentType: "application/javascript; charset=utf-8", offset: 4617124, length: 6748, sha256: "4a92459977d7cefa1a6a7e020c3a63509737f083b3f2773557c1a5771665811a" },
161573
+ { key: "index.html", contentType: "text/html; charset=utf-8", offset: 4623872, length: 4947, sha256: "54a5febec3be66748da191dc685e0007e5b7dbfc29c110b39f39244b1446139e" },
161574
+ { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 4628819, length: 17786, sha256: "084107ca997628c248f1b0ba3a7494744850df39fad813546ab8bdb82a6058da" }
161550
161575
  ];
161551
161576
  }
161552
161577
  });
Binary file
@@ -4743,6 +4743,12 @@
4743
4743
  "source": "core/sdk/webview/src/index.ts",
4744
4744
  "description": "Tier-5 typed binding for the page ↔ worker message channel of a worker-backed webview screen (Part 2 / RFC 0025 composition).",
4745
4745
  "api": [
4746
+ {
4747
+ "name": "\"./dispatcher.js\"",
4748
+ "kind": "reexport",
4749
+ "jsdoc": "",
4750
+ "decl": "export {\n PAGE_HANDSHAKE_CAPABILITY,\n PAGE_HANDSHAKE_METHOD,\n type ExposedPageCapability,\n type PageCapabilityRequest,\n type PageCapabilityResponse,\n type PageConsoleEvent,\n type PageCtx,\n type PageLifecycleEvent,\n type PageRequestHandler,\n type PageStream,\n} from \"./dispatcher.js\";"
4751
+ },
4746
4752
  {
4747
4753
  "name": "postToPage",
4748
4754
  "kind": "function",
@@ -4752,43 +4758,43 @@
4752
4758
  {
4753
4759
  "name": "onPageMessage",
4754
4760
  "kind": "function",
4755
- "jsdoc": "/**\n * Register a handler for messages the page posts via `window.HimalayaWorker.post(msg)`.\n * The latest registered handler wins. Call this once during the bundle's setup.\n */",
4756
- "decl": "export function onPageMessage(cb: (msg: unknown) => void): void;"
4761
+ "jsdoc": "/**\n * Register a handler for messages the page posts via `window.HimalayaWorker.post(msg)` that no\n * responder (`exposeCapabilitiesToPage`, `onPageRequest`) claims. The latest registered handler\n * wins. `instanceId` is the embedded WebView the host says the message came from (`\"\"` for the\n * full-screen page). Call this once during the bundle's setup.\n */",
4762
+ "decl": "export function onPageMessage(cb: (msg: unknown, instanceId: string) => void): void;"
4757
4763
  },
4758
4764
  {
4759
- "name": "PageCapabilityRequest",
4760
- "kind": "interface",
4761
- "jsdoc": "",
4762
- "decl": "export interface PageCapabilityRequest {\n v: 1;\n id: string;\n capability: string;\n method: string;\n args: unknown[];\n}"
4765
+ "name": "onPageRequest",
4766
+ "kind": "function",
4767
+ "jsdoc": "/**\n * Answer page requests `call(namespace, method, args)` from `@wix/himalaya/webview-page` (or\n * `himalaya.<namespace>.<method>(…)`) with worker code. A handler gets `(args, ctx)` and returns a value or a promise; a throw answers\n * `ok: false`. To stream, return `openPageStream(ctx.instanceId, ctx.requestId)`.\n *\n * Throws when `namespace` is `\"himalaya\"`, already registered, already exposed, or not\n * `/^[a-z][a-z0-9_]{0,63}$/`. A method the namespace lacks answers `code: \"unknown_method\"`.\n */",
4768
+ "decl": "export function onPageRequest(namespace: string, handlers: Readonly<Record<string, PageRequestHandler>>): void;"
4763
4769
  },
4764
4770
  {
4765
- "name": "PageCapabilityResponse",
4766
- "kind": "interface",
4767
- "jsdoc": "",
4768
- "decl": "export interface PageCapabilityResponse {\n v: 1;\n id: string;\n ok: boolean;\n result?: unknown;\n error?: { message: string; code?: string };\n}"
4771
+ "name": "emitToPage",
4772
+ "kind": "function",
4773
+ "jsdoc": "/**\n * Push an event to one page instance, or `\"*\"` for every instance that has sent a message or\n * mounted and not unmounted. `event` is `\"<namespace>.<event>\"`, split on the first dot; the page\n * receives it through `himalaya.<namespace>.on(\"<event>\", cb)`.\n */",
4774
+ "decl": "export function emitToPage(instanceId: string, event: `${string}.${string}`, data: unknown): void;"
4769
4775
  },
4770
4776
  {
4771
- "name": "PAGE_HANDSHAKE_CAPABILITY",
4772
- "kind": "const",
4773
- "jsdoc": "/** `call(\"himalaya\", \"capabilities\")` answers `{ v: 1, capabilities: { <id>: [<method>…] } }`:\n * exactly the allowlist this worker was given. Reserved, so no real capability can take it. */",
4774
- "decl": "export const PAGE_HANDSHAKE_CAPABILITY = \"himalaya\";"
4777
+ "name": "openPageStream",
4778
+ "kind": "function",
4779
+ "jsdoc": "/**\n * Open a stream answer for an in-flight `onPageRequest` call. Return the handle from the handler;\n * the page then iterates the chunks. After `end`, `error`, or a page cancel, `next` is a no-op.\n */",
4780
+ "decl": "export function openPageStream(instanceId: string, requestId: string): PageStream;"
4775
4781
  },
4776
4782
  {
4777
- "name": "PAGE_HANDSHAKE_METHOD",
4778
- "kind": "const",
4779
- "jsdoc": "",
4780
- "decl": "export const PAGE_HANDSHAKE_METHOD = \"capabilities\";"
4783
+ "name": "onPageLifecycle",
4784
+ "kind": "function",
4785
+ "jsdoc": "/**\n * Observe host lifecycle envelopes (`mounted | loaded | active | inactive | crashed | reloaded |\n * navBlocked | unmounted`). They arrive only on the host's lifecycle primitive, never from a page.\n * On a runtime without instance support, nothing is delivered. Returns an unsubscribe function.\n */",
4786
+ "decl": "export function onPageLifecycle(cb: (e: PageLifecycleEvent) => void): () => void;"
4781
4787
  },
4782
4788
  {
4783
- "name": "ExposedPageCapability",
4784
- "kind": "interface",
4785
- "jsdoc": "",
4786
- "decl": "export interface ExposedPageCapability {\n module: Record<string, unknown>;\n methods: readonly string[];\n}"
4789
+ "name": "onPageConsole",
4790
+ "kind": "function",
4791
+ "jsdoc": "/**\n * Observe `console_forwarding` output of the embedded pages. UNTRUSTED page data: a page can forge\n * these, so never treat them as host events. Returns an unsubscribe function.\n */",
4792
+ "decl": "export function onPageConsole(cb: (e: PageConsoleEvent) => void): () => void;"
4787
4793
  },
4788
4794
  {
4789
4795
  "name": "exposeCapabilitiesToPage",
4790
4796
  "kind": "function",
4791
- "jsdoc": "/**\n * Expose selected typed @himalaya/* modules to the hosting page.\n *\n * The worker author must pass both the imported module and its explicit verb allowlist:\n *\n * import * as health from \"@himalaya/health\";\n * exposeCapabilitiesToPage({\n * health: { module: health, methods: [\"availability\", \"query\"] },\n * });\n *\n * The bundle still has to declare `webview` plus every exposed capability. Importing only\n * selected modules keeps native permissions and `himi dist` additions opt-in.\n */",
4797
+ "jsdoc": "/**\n * Expose selected typed @himalaya/* modules to the hosting page.\n *\n * The worker author must pass both the imported module and its explicit verb allowlist:\n *\n * import * as health from \"@himalaya/health\";\n * exposeCapabilitiesToPage({\n * health: { module: health, methods: [\"availability\", \"query\"] },\n * });\n *\n * The bundle still has to declare `webview` plus every exposed capability. Importing only\n * selected modules keeps native permissions and `himi dist` additions opt-in. The page handshake\n * (`call(\"himalaya\", \"capabilities\")`) answers this allowlist plus every `onPageRequest` namespace.\n */",
4792
4798
  "decl": "export function exposeCapabilitiesToPage(\n capabilities: Readonly<Record<string, ExposedPageCapability>>,\n): void;"
4793
4799
  },
4794
4800
  {
@@ -4811,52 +4817,46 @@
4811
4817
  "decl": "export type { HimalayaPageCapabilities, HimalayaPageSdk } from \"./capabilities.generated.js\";"
4812
4818
  },
4813
4819
  {
4814
- "name": "WebViewPageRequest",
4815
- "kind": "interface",
4816
- "jsdoc": "",
4817
- "decl": "export interface WebViewPageRequest {\n v: 1;\n id: string;\n capability: string;\n method: string;\n args: unknown[];\n}"
4818
- },
4819
- {
4820
- "name": "WebViewPageError",
4821
- "kind": "interface",
4822
- "jsdoc": "",
4823
- "decl": "export interface WebViewPageError {\n message: string;\n code?: string;\n}"
4824
- },
4825
- {
4826
- "name": "WebViewPageResponse",
4827
- "kind": "interface",
4820
+ "name": "\"./client.js\"",
4821
+ "kind": "reexport",
4828
4822
  "jsdoc": "",
4829
- "decl": "export interface WebViewPageResponse {\n v: 1;\n id: string;\n ok: boolean;\n result?: unknown;\n error?: WebViewPageError;\n}"
4823
+ "decl": "export type {\n PageEventHandler,\n WebViewPageError,\n WebViewPageEvent,\n WebViewPageRequest,\n WebViewPageResponse,\n WebViewPageStreamEnvelope,\n} from \"./client.js\";"
4830
4824
  },
4831
4825
  {
4832
4826
  "name": "call",
4833
4827
  "kind": "function",
4834
- "jsdoc": "/** Invoke one method through the companion worker. Primarily useful to generated bindings.\n * A call that shows native UI (a permission prompt, the share sheet) answers only when the user\n * is done with it: pass a long `timeoutMs` (e.g. 120_000) rather than the 30-second default. */",
4828
+ "jsdoc": "/** Invoke one method through the companion worker. Primarily useful to generated bindings.\n * A call that shows native UI (a permission prompt, the share sheet) answers only when the user\n * is done with it: pass a long `timeoutMs` (e.g. 120_000) rather than the 30-second default.\n * A method the worker answers as a stream resolves to an `AsyncIterable` of its chunks:\n * `for await (const chunk of await call(…))`; `break` cancels it on the worker. */",
4835
4829
  "decl": "export function call<T>(\n capability: string,\n method: string,\n args: unknown[] = [],\n timeoutMs = 30_000,\n): Promise<T>;"
4836
4830
  },
4831
+ {
4832
+ "name": "on",
4833
+ "kind": "function",
4834
+ "jsdoc": "/** Subscribe to `namespace.event`, pushed by the worker's `emitToPage(iid, \"<namespace>.<event>\", data)`.\n * Same as `himalaya.<namespace>.on(event, handler)`. Returns the unsubscribe function. */",
4835
+ "decl": "export function on(namespace: string, event: string, handler: PageEventHandler): () => void;"
4836
+ },
4837
4837
  {
4838
4838
  "name": "enabledCapabilities",
4839
4839
  "kind": "function",
4840
4840
  "jsdoc": "/**\n * The capabilities and methods this page's companion worker answers, as `{ <id>: [<method>…] }`;\n * `null` outside the app, when the app is older than the handshake, or nothing answered in\n * `timeoutMs`. A list is remembered (and returned at once, whatever `timeoutMs`); a miss is not,\n * because a worker that is still booting drops the first messages.\n */",
4841
- "decl": "export async function enabledCapabilities(timeoutMs = 3_000): Promise<Record<string, string[]> | null>;"
4841
+ "decl": "export function enabledCapabilities(timeoutMs = 3_000): Promise<Record<string, string[]> | null>;"
4842
4842
  },
4843
4843
  {
4844
4844
  "name": "isEnabled",
4845
4845
  "kind": "function",
4846
4846
  "jsdoc": "/** Whether the companion worker lets this page call `capability.method`, read from\n * enabledCapabilities() — nothing is called. `false` when there is no list. */",
4847
- "decl": "export async function isEnabled(capability: string, method: string, timeoutMs = 3_000): Promise<boolean>;"
4847
+ "decl": "export function isEnabled(capability: string, method: string, timeoutMs = 3_000): Promise<boolean>;"
4848
4848
  },
4849
4849
  {
4850
4850
  "name": "probe",
4851
4851
  "kind": "function",
4852
- "jsdoc": "/** For an app older than the handshake: CALL `capability.method` and report whether it answered\n * (even with an error). It runs the method, so pass only a read-only one. */",
4853
- "decl": "export async function probe(capability: string, method: string, args: unknown[] = [], timeoutMs = 3_000): Promise<boolean>;"
4852
+ "jsdoc": "/** For an app older than the handshake: CALL `capability.method` and report whether it answered\n * (even with an error other than `unknown_method`). It runs the method, so pass only a read-only one. */",
4853
+ "decl": "export function probe(capability: string, method: string, args: unknown[] = [], timeoutMs = 3_000): Promise<boolean>;"
4854
4854
  },
4855
4855
  {
4856
4856
  "name": "himalaya",
4857
4857
  "kind": "const",
4858
- "jsdoc": "/**\n * Typed SDK proxy for every request/response capability in CAPABILITY_REGISTRY.\n * A namespace is usable only when this screen's companion worker explicitly imported and\n * exposed it and the bundle + host both declared it.\n */",
4859
- "decl": "export const himalaya = new Proxy({ version: 1 as const }, {\n get(target, property) {\n if (property === \"version\") return target.version;\n if (typeof property !== \"string\" || property === \"then\") return undefined;\n return pageMember(property, []);\n },\n}) as HimalayaPageSdk;"
4858
+ "jsdoc": "/**\n * Typed SDK proxy for every request/response capability in CAPABILITY_REGISTRY.\n * A namespace is usable only when this screen's companion worker explicitly imported and\n * exposed it and the bundle + host both declared it. Built by the same `merge` a host uses for the\n * injected client, so `himalaya.call/on/probe/…` are the client's members here too.\n */",
4859
+ "decl": "export const himalaya = client.merge({}) as HimalayaPageSdk;"
4860
4860
  },
4861
4861
  {
4862
4862
  "name": "health",
@@ -79,7 +79,7 @@ type Bridge = { post(message: unknown): boolean; onMessage(handler: (message: un
79
79
  type Reply = { v: 1; id: string; ok: boolean; result?: unknown; error?: { message: string; code?: string } };
80
80
 
81
81
  export class HimalayaError extends Error {
82
- /** "not_in_app" | "bridge_refused" | "timeout", or the capability's own code (e.g. "not_authorized"). */
82
+ /** "not_in_app" | "bridge_refused" | "timeout" | "unknown_method", or the capability's own code (e.g. "not_authorized"). */
83
83
  readonly code: string;
84
84
  constructor(message: string, code: string) {
85
85
  super(message);
@@ -224,8 +224,9 @@ export async function probe(capability: string, method: string, args: unknown[]
224
224
  await call(capability, method, args, timeoutMs);
225
225
  return true;
226
226
  } catch (error) {
227
- // Only an answer from the app (even an error) proves the method is enabled.
228
- return !(error instanceof HimalayaError && ["timeout", "not_in_app", "bridge_refused"].includes(error.code));
227
+ // Only an answer from the app (even an error) proves the method is enabled — except the app
228
+ // saying it has no such method.
229
+ return !(error instanceof HimalayaError && ["timeout", "not_in_app", "bridge_refused", "unknown_method"].includes(error.code));
229
230
  }
230
231
  }
231
232
 
@@ -85,6 +85,104 @@ Do not build one worker that imports every SDK. Static bundle scanning would cor
85
85
  that the release uses every capability, forcing unrelated permissions and native modules into the
86
86
  binary. One app-specific worker imports exactly the app’s selected subset.
87
87
 
88
+ ## Custom namespaces, events and streams
89
+
90
+ One worker can serve any number of embedded pages at once. Beside `exposeCapabilitiesToPage`, the
91
+ worker answers its own namespaces, pushes events and streams results; all of them share one
92
+ internal dispatcher, so registering one never replaces another (and `onPageMessage` still receives
93
+ every message none of them claims, including a handler registered directly on
94
+ `himalaya.webview.onPageMessage` after `@himalaya/webview` loaded).
95
+
96
+ ```ts
97
+ import { emitToPage, onPageLifecycle, onPageRequest, openPageStream } from "@himalaya/webview";
98
+
99
+ onPageRequest("nano", {
100
+ // (args, ctx) → value | promise. ctx = { instanceId, requestId, active }.
101
+ "location.getCurrentLocation": async () => ({ lat: 32.08, lng: 34.78 }),
102
+ // Return a stream handle to answer with many chunks.
103
+ "steps.watch": (_args, ctx) => {
104
+ const stream = openPageStream(ctx.instanceId, ctx.requestId);
105
+ const timer = setInterval(() => stream.next({ steps: Math.random() }), 1000);
106
+ stream.onCancel(() => clearInterval(timer)); // the page broke out of its loop
107
+ return stream;
108
+ },
109
+ });
110
+
111
+ emitToPage("*", "nano.theme.changed", { dark: true }); // or one instance id
112
+ const off = onPageLifecycle(({ instanceId, state }) => console.log(instanceId, state)); // mounted … unmounted
113
+ ```
114
+
115
+ - `ctx.instanceId` is the WebView the **host** says the request came from; a page-sent `iid` is
116
+ ignored. `ctx.active` is live: `false` between `inactive` and `active` lifecycle events.
117
+ - A namespace — and an exposed capability id — follows the capability-id pattern
118
+ (`/^[a-z][a-z0-9_]{0,63}$/`). Registering it twice, registering `himalaya`, or a name already
119
+ exposed throws. So do names the page's `himalaya.<name>` cannot reach: `call`, `on`, `probe`,
120
+ `version`, `then`, `constructor` and `general`, a method named `on`, and a method with a `then`,
121
+ `toString` or `valueOf` segment. The handshake lists custom namespaces beside exposed capabilities.
122
+ - A request whose page unmounted, reloaded or crashed before it answered is not answered at all:
123
+ the instance id may already belong to a new document. A `reloaded` right after `crashed` counts
124
+ as one boundary; a `mounted` or `loaded` in between ends that pair (so a host that remounts after
125
+ a crash delivers `reloaded` before the new document's `loaded`). A message still queued when
126
+ its instance unmounted reaches `onPageMessage` but revives nothing, and its request is not
127
+ answered; the instance is back once it mounts again.
128
+ - A method a registered namespace lacks answers at once with
129
+ `{ ok: false, error: { code: "unknown_method" } }` — the page does not wait out a timeout, and
130
+ `probe()` reads it as "not enabled". A request for a capability that is neither exposed nor
131
+ registered is not the dispatcher's: it reaches `onPageMessage` (the bundle's own protocol) and is
132
+ otherwise unanswered, because pages built against an older `probe()` read any answer as
133
+ "enabled". A method outside an allowlist and unknown methods on the reserved `himalaya` name also
134
+ stay unanswered.
135
+ - `emitToPage(iid, "<ns>.<event>", data)` splits on the first dot; `"*"` reaches every instance
136
+ that has sent a message or mounted and has not unmounted (on a single-page runtime, its page).
137
+ - A stream answers `{ v: 1, id, ok: true, stream: true }`, then `{ v: 1, sid, chunk }`… and
138
+ `{ v: 1, sid, end: true }` or `{ v: 1, sid, error }`; `sid` is the request id. After `end`,
139
+ `error`, a page cancel, or the instance unmounting, reloading or crashing, `next` is a no-op.
140
+ `onCancel` also runs when a handler opens a stream and then returns something else or throws,
141
+ and at once if it is registered after the stream was abandoned. `next(undefined)` sends `null`.
142
+ - `onPageLifecycle` envelopes come only from the host's lifecycle primitive; one arriving as a page
143
+ message is never treated as lifecycle. Of the page's `{ v: 1, sys }` messages the dispatcher keeps
144
+ only `cancel` and `console`; any other `sys` reaches `onPageMessage`. `onPageConsole` surfaces `console_forwarding` output — **untrusted** page
145
+ data the page can forge; never treat it as a host event.
146
+ - On a runtime without instance support (`himalaya.webview.onPageLifecycle` absent) every message
147
+ is instance `""`, lifecycle never fires, and posts to any other instance are dropped. Such a host
148
+ does not report a page reload either, so a stream there stops only when the page cancels it:
149
+ bound the producer (a count or a deadline) rather than relying on `onCancel` alone.
150
+ - A page `probe()` of a streamed method cancels the stream it started.
151
+
152
+ On the page:
153
+
154
+ ```ts
155
+ import { call, on } from "@wix/himalaya/webview-page";
156
+
157
+ declare function applyTheme(theme: unknown): void;
158
+ declare function render(reading: { steps: number }): void;
159
+
160
+ // A typed capability has the same method: himalaya.<capability>.on("<event>", cb).
161
+ const off = on("nano", "theme.changed", (data) => applyTheme(data));
162
+ let readings = 0;
163
+ for await (const reading of await call<AsyncIterable<{ steps: number }>>("nano", "steps.watch")) {
164
+ render(reading);
165
+ if (++readings === 10) break; // sends { v: 1, sys: "cancel", sid } — the worker's onCancel runs
166
+ }
167
+ off();
168
+ ```
169
+
170
+ A stream `error` envelope throws from the loop. The page accepts only `v: 1` envelopes, and
171
+ responses only for a request id it sent.
172
+
173
+ **Injected client (planned host behaviour).** No host injects it yet: today a page imports
174
+ `@wix/himalaya/webview-page`. The native and web hosts are planned to inject the same client at
175
+ document start for worker-bridged WebViews, so inline HTML will need no import.
176
+ `PAGE_CLIENT_SOURCE` (`@himalaya/webview-page/page-client`, generated from `src/client.ts` by
177
+ `scripts/generate-page-client.ts`) is a script that defines no global and evaluates to
178
+ `createPageClient(getBridge)`. The host's bridge shim defines `window.himalaya` non-writable, so
179
+ the client is to be merged into the shim's own object before it is frozen:
180
+ `client.merge({ general: … })` adds `call`, `on`, `enabledCapabilities`, `isEnabled`, `probe` and
181
+ `version`, freezes the object, and resolves any other name to a namespace proxy
182
+ (`himalaya.nano.on(…)`, `himalaya.nano.location.getCurrentLocation()`). The package's own
183
+ `himalaya` export is built the same way, so both surfaces have the same members. Coercing a
184
+ namespace to a string (`` `${himalaya.nano}` ``) sends nothing to the worker.
185
+
88
186
  ## Brandy
89
187
 
90
188
  Name the capabilities; Brandy supplies the companion worker, so neither the page author nor the
@@ -135,9 +233,10 @@ Base44 is accepted only when the same Brandy contract contains a Base44 binding.
135
233
  - Errors preserve a typed `code` when the SDK provides one.
136
234
  - The page cannot use raw `capability.*` messages: Brandy site descriptors keep
137
235
  `capabilitiesRequired: []`; native calls go through the companion worker.
138
- - v1 is request/response. SDK helpers returning `AsyncIterable`, accepting JavaScript callbacks,
139
- or depending on worker action names need a page-specific adapter built from their lower-level
140
- start/next/stop verbs. Do not expose such a helper unchanged.
236
+ - `exposeCapabilitiesToPage` is request/response. SDK helpers returning `AsyncIterable`, accepting
237
+ JavaScript callbacks, or depending on worker action names need an `onPageRequest` adapter
238
+ (a stream or `emitToPage` events) built from their lower-level start/next/stop verbs. Do not
239
+ expose such a helper unchanged.
141
240
 
142
241
  The package source includes complete `health-page.ts` and `health-worker.ts` examples matching the
143
242
  snippets above.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/himalaya-cli",
3
- "version": "0.1450.0",
3
+ "version": "0.1452.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": "9e4b4eed20568576a872a08d2eebfc47562e413465af5dbaa19c3902"
74
+ "falconPackageHash": "c345fa006ed03ed32be63ed23a653016d907cbd352ccb6171b77e23e"
75
75
  }