@wix/himalaya-cli 0.1022.0 → 0.1023.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/schema.d.ts +53 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/validator.d.ts +52 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/core.mjs +16 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/sdui.mjs +16 -0
- package/dist/cli.mjs +308 -121
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/component-reference.json +5 -5
- package/guides/component-reference.md +35 -0
- package/guides/designing-himi-screens.md +7 -3
- package/guides/headless-loop.md +8 -1
- package/guides/release-notes.md +40 -0
- package/guides/testing-himi-apps.md +9 -12
- package/guides/wix-api-usage.md +4 -2
- package/guides/wix-login-integration.md +2 -1
- package/guides/wix-sdk-overview.md +6 -1
- package/package.json +2 -2
package/dist/cli.mjs
CHANGED
|
@@ -6004,6 +6004,22 @@ var init_validator = __esm({
|
|
|
6004
6004
|
enum: ["selected", "disabled", "updates_frequently", "plays_sound", "starts_media"]
|
|
6005
6005
|
}
|
|
6006
6006
|
},
|
|
6007
|
+
// RFC 0058 §4 — focus and announcement (core.proto Modifiers 70–73). `modifiers`
|
|
6008
|
+
// is `additionalProperties: false`, so a descriptor carrying one of these would be
|
|
6009
|
+
// REJECTED on every arm at once until the validator knows it — which makes this
|
|
6010
|
+
// part of the vocabulary rather than a downstream consumer of it.
|
|
6011
|
+
focusOrder: { type: "integer" },
|
|
6012
|
+
focusGroup: { type: "boolean" },
|
|
6013
|
+
initialFocus: { type: "boolean" },
|
|
6014
|
+
announce: {
|
|
6015
|
+
type: "object",
|
|
6016
|
+
additionalProperties: false,
|
|
6017
|
+
properties: {
|
|
6018
|
+
politeness: { type: "string", enum: ["polite", "assertive"] },
|
|
6019
|
+
text: { type: "string" },
|
|
6020
|
+
trigger: { type: "string", enum: ["on_change", "on_appear", "both", "none"] }
|
|
6021
|
+
}
|
|
6022
|
+
},
|
|
6007
6023
|
// #1052 — explicit drop shadow (colour token + radius + offset), alongside the `shadow` token form.
|
|
6008
6024
|
boxShadow: {
|
|
6009
6025
|
type: "object",
|
|
@@ -8851,6 +8867,7 @@ var init_validate_descriptor_core = __esm({
|
|
|
8851
8867
|
scrollToDatePath: "string",
|
|
8852
8868
|
stickyHeaders: "boolean"
|
|
8853
8869
|
},
|
|
8870
|
+
// RFC 0058 §4 — `modal` is the focus-trap tri-state on each of the four overlays.
|
|
8854
8871
|
AlertDialog: {
|
|
8855
8872
|
cancelAction: "any",
|
|
8856
8873
|
cancelLabel: "string",
|
|
@@ -8858,6 +8875,7 @@ var init_validate_descriptor_core = __esm({
|
|
|
8858
8875
|
confirmLabel: "string",
|
|
8859
8876
|
destructive: "boolean",
|
|
8860
8877
|
message: "string",
|
|
8878
|
+
modal: "boolean",
|
|
8861
8879
|
title: "string"
|
|
8862
8880
|
},
|
|
8863
8881
|
Avatar: { imageUrl: "string", initials: "string", size: "number" },
|
|
@@ -8887,6 +8905,7 @@ var init_validate_descriptor_core = __esm({
|
|
|
8887
8905
|
detents: "array",
|
|
8888
8906
|
dismissible: "boolean",
|
|
8889
8907
|
edge: "string",
|
|
8908
|
+
modal: "boolean",
|
|
8890
8909
|
onDismiss: "any",
|
|
8891
8910
|
presented: "boolean",
|
|
8892
8911
|
presentedPath: "string",
|
|
@@ -9170,7 +9189,7 @@ var init_validate_descriptor_core = __esm({
|
|
|
9170
9189
|
startIndex: "number",
|
|
9171
9190
|
startPositionSeconds: "number"
|
|
9172
9191
|
},
|
|
9173
|
-
Menu: { anchor: "any", items: "array", itemsPath: "string", style: "string" },
|
|
9192
|
+
Menu: { anchor: "any", items: "array", itemsPath: "string", modal: "boolean", style: "string" },
|
|
9174
9193
|
MonthCalendar: {
|
|
9175
9194
|
decorations: "array",
|
|
9176
9195
|
decorationsPath: "string",
|
|
@@ -9223,6 +9242,7 @@ var init_validate_descriptor_core = __esm({
|
|
|
9223
9242
|
anchor: "any",
|
|
9224
9243
|
content: "any",
|
|
9225
9244
|
edge: "string",
|
|
9245
|
+
modal: "boolean",
|
|
9226
9246
|
onDismiss: "any",
|
|
9227
9247
|
presented: "boolean",
|
|
9228
9248
|
presentedPath: "string"
|
|
@@ -9653,6 +9673,7 @@ var init_validate_descriptor_core = __esm({
|
|
|
9653
9673
|
"blur",
|
|
9654
9674
|
"cornerRadius",
|
|
9655
9675
|
"enterDelayMs",
|
|
9676
|
+
"focusOrder",
|
|
9656
9677
|
"headingLevel",
|
|
9657
9678
|
"height",
|
|
9658
9679
|
"maxWidth",
|
|
@@ -17303,6 +17324,21 @@ function absoluteUrlRejection(path2) {
|
|
|
17303
17324
|
}
|
|
17304
17325
|
return OWNER_SCOPED_WIX_HOST.test(host) ? "owner-only" : "open-proxy";
|
|
17305
17326
|
}
|
|
17327
|
+
async function mintAnonymousVisitor(clientId, fetchImpl = fetch) {
|
|
17328
|
+
const res = await fetchImpl(`${WIX_API}/oauth2/token`, {
|
|
17329
|
+
method: "POST",
|
|
17330
|
+
headers: { "Content-Type": "application/json" },
|
|
17331
|
+
body: JSON.stringify({ clientId, grantType: "anonymous" })
|
|
17332
|
+
});
|
|
17333
|
+
const text5 = await res.text();
|
|
17334
|
+
let j = {};
|
|
17335
|
+
try {
|
|
17336
|
+
j = text5 ? JSON.parse(text5) : {};
|
|
17337
|
+
} catch {
|
|
17338
|
+
}
|
|
17339
|
+
if (res.status !== 200 || !j.access_token) throw new Error(`visitor mint failed (${res.status})`);
|
|
17340
|
+
return j.access_token;
|
|
17341
|
+
}
|
|
17306
17342
|
async function wixVisitorCall(method, path2, body, token, fetchImpl = fetch, forwardedHeaders = {}) {
|
|
17307
17343
|
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(path2)) throw new Error("absolute URLs are not allowed");
|
|
17308
17344
|
const url = `${WIX_API}${path2.startsWith("/") ? path2 : `/${path2}`}`;
|
|
@@ -17379,43 +17415,13 @@ function wixClientIdOf(appConfigJson) {
|
|
|
17379
17415
|
if (typeof clientId !== "string" || !clientId) return { error: "no_client_id" };
|
|
17380
17416
|
return { clientId };
|
|
17381
17417
|
}
|
|
17382
|
-
var WIX_API, ONE_APP_SESSION, OWNER_SCOPED_WIX_HOST,
|
|
17418
|
+
var WIX_API, ONE_APP_SESSION, OWNER_SCOPED_WIX_HOST, WIX_FORWARDABLE_HEADERS, OWNER_REFRESH_MARGIN_MS, OWNER_RENEW_MIN_AGE_MS, OWNER_MINT_TIMEOUT_MS, OwnerInstanceCache, OWNER_SITES_QUERY_PATH, OWNER_SITES_COUNT_PATH, OwnerSitesCache;
|
|
17383
17419
|
var init_wix_bridge = __esm({
|
|
17384
17420
|
"../../core/serve-runtime/src/wix-bridge.ts"() {
|
|
17385
17421
|
init_sha256();
|
|
17386
17422
|
WIX_API = "https://www.wixapis.com";
|
|
17387
17423
|
ONE_APP_SESSION = "https://apps.wix.com/_api/one-app-session-web/v3/businesses";
|
|
17388
17424
|
OWNER_SCOPED_WIX_HOST = /(^|\.)wix\.com$/i;
|
|
17389
|
-
VisitorTokenCache = class {
|
|
17390
|
-
constructor(fetchImpl = fetch) {
|
|
17391
|
-
this.fetchImpl = fetchImpl;
|
|
17392
|
-
}
|
|
17393
|
-
cache = /* @__PURE__ */ new Map();
|
|
17394
|
-
async token(clientId, now = Date.now()) {
|
|
17395
|
-
const hit = this.cache.get(clientId);
|
|
17396
|
-
if (hit && hit.expiresAt > now) return hit.token;
|
|
17397
|
-
const res = await this.fetchImpl(`${WIX_API}/oauth2/token`, {
|
|
17398
|
-
method: "POST",
|
|
17399
|
-
headers: { "Content-Type": "application/json" },
|
|
17400
|
-
body: JSON.stringify({ clientId, grantType: "anonymous" })
|
|
17401
|
-
});
|
|
17402
|
-
const text5 = await res.text();
|
|
17403
|
-
let j = {};
|
|
17404
|
-
try {
|
|
17405
|
-
j = text5 ? JSON.parse(text5) : {};
|
|
17406
|
-
} catch {
|
|
17407
|
-
}
|
|
17408
|
-
if (res.status !== 200 || !j.access_token)
|
|
17409
|
-
throw new Error(`visitor mint failed (${res.status})`);
|
|
17410
|
-
const ttlMs = Math.max(60, (j.expires_in ?? 4 * 3600) - 60) * 1e3;
|
|
17411
|
-
this.cache.set(clientId, { token: j.access_token, expiresAt: now + ttlMs });
|
|
17412
|
-
return j.access_token;
|
|
17413
|
-
}
|
|
17414
|
-
/** Drop a cached token (e.g. after a 401 from wixapis) so the next call re-mints. */
|
|
17415
|
-
invalidate(clientId) {
|
|
17416
|
-
this.cache.delete(clientId);
|
|
17417
|
-
}
|
|
17418
|
-
};
|
|
17419
17425
|
WIX_FORWARDABLE_HEADERS = /* @__PURE__ */ new Set([
|
|
17420
17426
|
"x-wix-language",
|
|
17421
17427
|
"x-wix-linguist",
|
|
@@ -20030,6 +20036,7 @@ function shouldRevealError(args) {
|
|
|
20030
20036
|
var EMAIL_RE, URL_HOST_RE, INTEGER_RE, NUMBER_RE;
|
|
20031
20037
|
var init_validation = __esm({
|
|
20032
20038
|
"../../core/ts/src/validation.ts"() {
|
|
20039
|
+
"use strict";
|
|
20033
20040
|
EMAIL_RE = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;
|
|
20034
20041
|
URL_HOST_RE = /^[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*(:[0-9]+)?$/;
|
|
20035
20042
|
INTEGER_RE = /^[+-]?[0-9]+$/;
|
|
@@ -23473,6 +23480,7 @@ function validateWorkerSubtree(raw, slotId, policy, actionCatalog) {
|
|
|
23473
23480
|
var WORKER_SUBTREE_CEILINGS, ID_PART, ACTION_ID;
|
|
23474
23481
|
var init_worker_subtree = __esm({
|
|
23475
23482
|
"../../core/ts/src/worker-subtree.ts"() {
|
|
23483
|
+
"use strict";
|
|
23476
23484
|
init_worker_subtree_safe_types_generated();
|
|
23477
23485
|
WORKER_SUBTREE_CEILINGS = Object.freeze({
|
|
23478
23486
|
maxEncodedBytes: 65536,
|
|
@@ -24142,6 +24150,9 @@ function autoGrowBox(contentHeight, lineHeight, verticalPadding, maxLines) {
|
|
|
24142
24150
|
const cap = Math.max(floor, lineHeight * lines + verticalPadding);
|
|
24143
24151
|
return { height: Math.max(floor, Math.min(contentHeight, cap)), scrolls: contentHeight > cap };
|
|
24144
24152
|
}
|
|
24153
|
+
function wrapModalMenu(modal, label2, placement, menu) {
|
|
24154
|
+
return modal ? /* @__PURE__ */ jsx6("div", { role: "dialog", "aria-modal": "true", "aria-label": label2, style: placement, children: menu }) : menu;
|
|
24155
|
+
}
|
|
24145
24156
|
function bindMediaSlot(value, sessionId) {
|
|
24146
24157
|
if (typeof value === "string") {
|
|
24147
24158
|
const prefix = `$media:${sessionId}.`;
|
|
@@ -24269,11 +24280,13 @@ function withExtras(name, render) {
|
|
|
24269
24280
|
}
|
|
24270
24281
|
const roleIsSynthetic = next[SYNTHETIC_TAP_ROLE] === true;
|
|
24271
24282
|
delete next[SYNTHETIC_TAP_ROLE];
|
|
24283
|
+
const tabIndexIsSynthetic = next[SYNTHETIC_TABINDEX] === true;
|
|
24284
|
+
delete next[SYNTHETIC_TABINDEX];
|
|
24272
24285
|
if (additive) next.style = additive;
|
|
24273
24286
|
const ownsInteractiveSemantics = isNativeInteractiveElement(el) || hasInteractiveReactDescendant(el);
|
|
24274
24287
|
if (ownsInteractiveSemantics) {
|
|
24275
24288
|
if (roleIsSynthetic) delete next.role;
|
|
24276
|
-
delete next.tabIndex;
|
|
24289
|
+
if (tabIndexIsSynthetic) delete next.tabIndex;
|
|
24277
24290
|
delete next.onKeyDown;
|
|
24278
24291
|
}
|
|
24279
24292
|
if (pass.style) next.style = { ...additive ?? prev.style ?? {}, ...pass.style };
|
|
@@ -24709,6 +24722,57 @@ function calKeyActivate(enabled, activate) {
|
|
|
24709
24722
|
activate();
|
|
24710
24723
|
};
|
|
24711
24724
|
}
|
|
24725
|
+
function restoreFocusOnDismiss(scope, opener) {
|
|
24726
|
+
const Observer = document.defaultView?.MutationObserver;
|
|
24727
|
+
if (!Observer) return;
|
|
24728
|
+
presentedOpeners.set(scope, opener);
|
|
24729
|
+
if (presentedObserver) return;
|
|
24730
|
+
presentedObserver = new Observer(() => {
|
|
24731
|
+
for (const [s, o] of presentedOpeners) {
|
|
24732
|
+
if (s.isConnected) continue;
|
|
24733
|
+
presentedOpeners.delete(s);
|
|
24734
|
+
const active = document.activeElement;
|
|
24735
|
+
if ((active == null || active === document.body) && o.isConnected && typeof o.focus === "function") o.focus();
|
|
24736
|
+
}
|
|
24737
|
+
if (presentedOpeners.size === 0) {
|
|
24738
|
+
presentedObserver?.disconnect();
|
|
24739
|
+
presentedObserver = null;
|
|
24740
|
+
}
|
|
24741
|
+
});
|
|
24742
|
+
presentedObserver.observe(document.body, { childList: true, subtree: true });
|
|
24743
|
+
}
|
|
24744
|
+
function ensureInitialFocusRuntime() {
|
|
24745
|
+
if (initialFocusScheduled || typeof document === "undefined") return;
|
|
24746
|
+
initialFocusScheduled = true;
|
|
24747
|
+
setTimeout(() => {
|
|
24748
|
+
initialFocusScheduled = false;
|
|
24749
|
+
const targets = Array.from(document.querySelectorAll("[data-himalaya-initial-focus]"));
|
|
24750
|
+
const active = document.activeElement;
|
|
24751
|
+
const unplaced = active == null || active === document.body;
|
|
24752
|
+
const fresh = targets.filter((t) => !initialFocusSeen.has(t));
|
|
24753
|
+
let presented;
|
|
24754
|
+
let presentedScope = null;
|
|
24755
|
+
for (const t of fresh) {
|
|
24756
|
+
const scope = t.closest(PRESENTED_SCOPE);
|
|
24757
|
+
if (scope && !(active && scope.contains(active))) {
|
|
24758
|
+
presented = t;
|
|
24759
|
+
presentedScope = scope;
|
|
24760
|
+
}
|
|
24761
|
+
}
|
|
24762
|
+
for (const t of fresh) initialFocusSeen.add(t);
|
|
24763
|
+
const el = presented ?? (unplaced ? fresh[0] : void 0);
|
|
24764
|
+
if (el && typeof el.focus === "function") {
|
|
24765
|
+
if (presented && presentedScope && !unplaced && active instanceof HTMLElement) {
|
|
24766
|
+
restoreFocusOnDismiss(presentedScope, active);
|
|
24767
|
+
}
|
|
24768
|
+
el.focus();
|
|
24769
|
+
}
|
|
24770
|
+
}, 0);
|
|
24771
|
+
}
|
|
24772
|
+
function ariaModal(modal, dflt) {
|
|
24773
|
+
const on3 = modal === true || modal === false ? modal : dflt;
|
|
24774
|
+
return on3 ? "true" : void 0;
|
|
24775
|
+
}
|
|
24712
24776
|
function applyA11ySemantics(node, ctx, extra) {
|
|
24713
24777
|
const m = node?.modifiers;
|
|
24714
24778
|
if (!m) return void 0;
|
|
@@ -24764,6 +24828,32 @@ function applyA11ySemantics(node, ctx, extra) {
|
|
|
24764
24828
|
}
|
|
24765
24829
|
}
|
|
24766
24830
|
}
|
|
24831
|
+
const focusOrder = m.focusOrder ?? m.focus_order;
|
|
24832
|
+
if (typeof focusOrder === "number" && Number.isFinite(focusOrder)) {
|
|
24833
|
+
extra.tabIndex = Math.max(1, Math.trunc(focusOrder) + 1);
|
|
24834
|
+
}
|
|
24835
|
+
if ((m.focusGroup ?? m.focus_group) === true && extra.role == null) extra.role = "group";
|
|
24836
|
+
if ((m.initialFocus ?? m.initial_focus) === true) {
|
|
24837
|
+
extra["data-himalaya-initial-focus"] = "1";
|
|
24838
|
+
if (extra.tabIndex == null) {
|
|
24839
|
+
extra.tabIndex = -1;
|
|
24840
|
+
extra[SYNTHETIC_TABINDEX] = true;
|
|
24841
|
+
}
|
|
24842
|
+
ensureInitialFocusRuntime();
|
|
24843
|
+
}
|
|
24844
|
+
const announce = m.announce;
|
|
24845
|
+
if (announce && typeof announce === "object" && !Array.isArray(announce)) {
|
|
24846
|
+
const trigger = str7(announce.trigger) ?? "on_change";
|
|
24847
|
+
if (trigger === "none") {
|
|
24848
|
+
extra["aria-live"] = "off";
|
|
24849
|
+
} else {
|
|
24850
|
+
extra["aria-live"] = str7(announce.politeness) === "assertive" ? "assertive" : "polite";
|
|
24851
|
+
extra["aria-atomic"] = "true";
|
|
24852
|
+
extra["aria-relevant"] = trigger === "on_appear" ? "additions" : trigger === "both" ? "additions text" : "text";
|
|
24853
|
+
const text5 = str7(announce.text);
|
|
24854
|
+
if (text5 && extra["aria-label"] == null) extra["aria-label"] = text5;
|
|
24855
|
+
}
|
|
24856
|
+
}
|
|
24767
24857
|
return hint;
|
|
24768
24858
|
}
|
|
24769
24859
|
function renderNodeInner(node, ctx) {
|
|
@@ -24856,7 +24946,10 @@ function renderNodeInner(node, ctx) {
|
|
|
24856
24946
|
extra.role = "button";
|
|
24857
24947
|
if (typeof el.type !== "string") extra[SYNTHETIC_TAP_ROLE] = true;
|
|
24858
24948
|
}
|
|
24859
|
-
extra.tabIndex
|
|
24949
|
+
if (extra.tabIndex == null) {
|
|
24950
|
+
extra.tabIndex = 0;
|
|
24951
|
+
if (typeof el.type !== "string") extra[SYNTHETIC_TABINDEX] = true;
|
|
24952
|
+
}
|
|
24860
24953
|
const prevOnKeyDown = el.props.onKeyDown;
|
|
24861
24954
|
extra.onKeyDown = (e) => {
|
|
24862
24955
|
prevOnKeyDown?.(e);
|
|
@@ -24904,6 +24997,7 @@ function renderNodeInner(node, ctx) {
|
|
|
24904
24997
|
if (composed) extra.style = composed;
|
|
24905
24998
|
}
|
|
24906
24999
|
}
|
|
25000
|
+
if (typeof el.type === "string") delete extra[SYNTHETIC_TABINDEX];
|
|
24907
25001
|
let out = Object.keys(extra).length ? React5.cloneElement(el, extra) : el;
|
|
24908
25002
|
if (a11yHint) {
|
|
24909
25003
|
out = /* @__PURE__ */ jsx6(A11yHintDescription, { hint: a11yHint, idBase: componentId, children: out });
|
|
@@ -25333,7 +25427,7 @@ function renderInner(node, ctx) {
|
|
|
25333
25427
|
case "Popover": {
|
|
25334
25428
|
return /* @__PURE__ */ jsxs3("div", { style: { display: "inline-flex", flexDirection: "column", alignItems: "flex-start", gap: 6, ...wrap }, children: [
|
|
25335
25429
|
props.anchor ? renderNode(props.anchor, ctx) : null,
|
|
25336
|
-
/* @__PURE__ */ jsx6("div", { role: "dialog", "aria-label": props.title != null ? asBoundText(props.title, ctx) : "Popover", style: { minWidth: 160, maxWidth: 280, background: C("surfacePrimary", "#fff"), border: `1px solid ${C("border", "#e3e3e3")}`, borderRadius: 12, boxShadow: "0 6px 20px rgba(0,0,0,.14)", padding: 12 }, children: props.content ? renderNode(props.content, ctx) : null })
|
|
25430
|
+
/* @__PURE__ */ jsx6("div", { role: "dialog", "aria-modal": ariaModal(props.modal, false), "aria-label": props.title != null ? asBoundText(props.title, ctx) : "Popover", style: { minWidth: 160, maxWidth: 280, background: C("surfacePrimary", "#fff"), border: `1px solid ${C("border", "#e3e3e3")}`, borderRadius: 12, boxShadow: "0 6px 20px rgba(0,0,0,.14)", padding: 12 }, children: props.content ? renderNode(props.content, ctx) : null })
|
|
25337
25431
|
] });
|
|
25338
25432
|
}
|
|
25339
25433
|
// ───────────── chips & selection (RFC 0030) ─────────────
|
|
@@ -25601,7 +25695,7 @@ function renderInner(node, ctx) {
|
|
|
25601
25695
|
] });
|
|
25602
25696
|
}
|
|
25603
25697
|
case "AlertDialog":
|
|
25604
|
-
return /* @__PURE__ */ jsxs3("div", { role: "alertdialog", "aria-modal":
|
|
25698
|
+
return /* @__PURE__ */ jsxs3("div", { role: "alertdialog", "aria-modal": ariaModal(props.modal, true), "aria-label": props.title != null ? asBoundText(props.title, ctx) : "Alert", style: { background: C("surfacePrimary", "#fff"), borderRadius: ctx.radius("lg", 14), padding: 18, width: "100%", boxSizing: "border-box", border: `1px solid ${C("border", "#e3e3e3")}`, boxShadow: "0 12px 30px -12px rgba(0,0,0,.4)", ...wrap }, children: [
|
|
25605
25699
|
/* @__PURE__ */ jsx6("div", { style: { fontFamily: bodyFont(ctx), fontWeight: 700, fontSize: 17, color: C("textPrimary", "#111") }, children: txt(props.title, ctx) }),
|
|
25606
25700
|
/* @__PURE__ */ jsx6("div", { style: { fontFamily: bodyFont(ctx), fontSize: 14, lineHeight: 1.45, color: C("textSecondary", "#666"), margin: "6px 0 16px" }, children: txt(props.message, ctx) }),
|
|
25607
25701
|
/* @__PURE__ */ jsxs3("div", { style: { display: "flex", gap: 10 }, children: [
|
|
@@ -25624,7 +25718,7 @@ function renderInner(node, ctx) {
|
|
|
25624
25718
|
}
|
|
25625
25719
|
}
|
|
25626
25720
|
}
|
|
25627
|
-
var useIsomorphicLayoutEffect, ResponsiveGrid, SPLIT_EXPANDED_MIN_WIDTH, SPLIT_COLUMN_GAP, ResponsiveSplitView, ABSOLUTE_URL_RE, appearKeyframesInjected, pressStylesInjected, FOCUS_RING_CSS, focusStylesInjected, HLIST_CHILD_CSS, hListStylesInjected, listAnimateRuntimeInstalled, transitionKeyframesInjected, countUpRuntimeInjected, MEASURE_PREFIX, measureRuntimeInjected, revealRuntimeInjected, vectorAnimStylesInjected, scrollProgressRuntimeInjected, confettiRuntimeInjected, lottieRuntimeInjected, riveRuntimeInjected, gradientKeyframesInjected, parallaxRuntimeInjected, spinKeyframesInjected, marqueeKeyframesInjected, alignItems, zJustifyItems, hAlignItems, bodyFont, kids, rowKids, staggeredKids, asTextL10n, asBoundText, useBoundString, InterpolatedTextView, txt, selectFragmentCase, fragmentValueHash, fragmentSlotContent, FragmentSlotNode, WorkerSubtreeNode, resolveItemDeep2, resolveSwipeActions, resolveModBindings, resolvedComponentId, directServiceBindings, ReactiveDirectScalars, HiddenGate, KEYBOARD_INPUT_MODES, AUTOCAPITALIZE_VALUES, ENTER_KEY_HINTS, AUTOGROW_CEILING, EditableField, MenuNode, LoadMoreSentinel, FieldErrorNode, FormView, MediaSlotProvider, MEDIA_ITEM_BINDABLE, MediaPlayerView, VideoNode, PdfViewNode, WebViewNode, InteractivePicker, InteractiveDatePicker, InteractiveSearchField, InteractiveStepper, SYNTHETIC_TAP_ROLE, INFERRED_DECORATIVE, ICON_GLYPH, INTERACTIVE_ROLES, ALWAYS_INTERACTIVE_COMPONENT_TYPES, controlNode, ToggleNode, SliderNode, SelectionControlNode, TabsNode, SegmentedControlNode, DisclosureGroupNode, GridNode, SplitViewNode, TextNode, ImageNode, AvatarNode, IconNode, ButtonNode, OtpInputNode, ProgressBarNode, ActivityIndicatorNode, BottomSheetNode, ChipsInputNode, ChipNode, TableNode, GaugeRing, GaugeNode, RATING_METRICS, ratingMetrics, RatingNode, AvatarStripNode, CHART_STROKE_CYCLE, chartStrokeAt, chartBarCenter, ChartNode, donutSliceOpacity, DonutChartNode, LegendMarker, LegendNode, cellAlign, DataTableNode, voiceNoteState, voiceNoteDelivery, VOICE_NOTE_DEFAULT_BARS, clampBarCount, VoiceNoteNode, TimelineNode, WheelPickerNode, ColorPickerNode, FilterChipsNode, TILE_PX, MAX_MERCATOR_LAT, DEFAULT_TILE_MAX_ZOOM, CIRCLE_SEGMENTS, METRES_PER_DEG_LAT, MARKER_HIT_RADIUS, SHAPE_HIT_RADIUS, MapNode, CollapsingHeaderNode, UnsupportedOnSurface, CALENDAR_DATE_ONLY_RE, CAL_DEFAULT_MAX_DOTS, CAL_AGENDA_INITIAL_DAYS, CAL_AGENDA_PAGE_DAYS, CAL_DEFAULT_SNAP_MINUTES, CAL_UNASSIGNED_LANE_ID, MonthCalendarNode, TimeGridNode, AgendaNode, ARIA_ROLE, A11yHintDescription, WebRenderer;
|
|
25721
|
+
var useIsomorphicLayoutEffect, ResponsiveGrid, SPLIT_EXPANDED_MIN_WIDTH, SPLIT_COLUMN_GAP, ResponsiveSplitView, ABSOLUTE_URL_RE, appearKeyframesInjected, pressStylesInjected, FOCUS_RING_CSS, focusStylesInjected, HLIST_CHILD_CSS, hListStylesInjected, listAnimateRuntimeInstalled, transitionKeyframesInjected, countUpRuntimeInjected, MEASURE_PREFIX, measureRuntimeInjected, revealRuntimeInjected, vectorAnimStylesInjected, scrollProgressRuntimeInjected, confettiRuntimeInjected, lottieRuntimeInjected, riveRuntimeInjected, gradientKeyframesInjected, parallaxRuntimeInjected, spinKeyframesInjected, marqueeKeyframesInjected, alignItems, zJustifyItems, hAlignItems, bodyFont, kids, rowKids, staggeredKids, asTextL10n, asBoundText, useBoundString, InterpolatedTextView, txt, selectFragmentCase, fragmentValueHash, fragmentSlotContent, FragmentSlotNode, WorkerSubtreeNode, resolveItemDeep2, resolveSwipeActions, resolveModBindings, resolvedComponentId, directServiceBindings, ReactiveDirectScalars, HiddenGate, KEYBOARD_INPUT_MODES, AUTOCAPITALIZE_VALUES, ENTER_KEY_HINTS, AUTOGROW_CEILING, EditableField, MenuNode, LoadMoreSentinel, FieldErrorNode, FormView, MediaSlotProvider, MEDIA_ITEM_BINDABLE, MediaPlayerView, VideoNode, PdfViewNode, WebViewNode, InteractivePicker, InteractiveDatePicker, InteractiveSearchField, InteractiveStepper, SYNTHETIC_TAP_ROLE, SYNTHETIC_TABINDEX, INFERRED_DECORATIVE, ICON_GLYPH, INTERACTIVE_ROLES, ALWAYS_INTERACTIVE_COMPONENT_TYPES, controlNode, ToggleNode, SliderNode, SelectionControlNode, TabsNode, SegmentedControlNode, DisclosureGroupNode, GridNode, SplitViewNode, TextNode, ImageNode, AvatarNode, IconNode, ButtonNode, OtpInputNode, ProgressBarNode, ActivityIndicatorNode, BottomSheetNode, ChipsInputNode, ChipNode, TableNode, GaugeRing, GaugeNode, RATING_METRICS, ratingMetrics, RatingNode, AvatarStripNode, CHART_STROKE_CYCLE, chartStrokeAt, chartBarCenter, ChartNode, donutSliceOpacity, DonutChartNode, LegendMarker, LegendNode, cellAlign, DataTableNode, voiceNoteState, voiceNoteDelivery, VOICE_NOTE_DEFAULT_BARS, clampBarCount, VoiceNoteNode, TimelineNode, WheelPickerNode, ColorPickerNode, FilterChipsNode, TILE_PX, MAX_MERCATOR_LAT, DEFAULT_TILE_MAX_ZOOM, CIRCLE_SEGMENTS, METRES_PER_DEG_LAT, MARKER_HIT_RADIUS, SHAPE_HIT_RADIUS, MapNode, CollapsingHeaderNode, UnsupportedOnSurface, CALENDAR_DATE_ONLY_RE, CAL_DEFAULT_MAX_DOTS, CAL_AGENDA_INITIAL_DAYS, CAL_AGENDA_PAGE_DAYS, CAL_DEFAULT_SNAP_MINUTES, CAL_UNASSIGNED_LANE_ID, MonthCalendarNode, TimeGridNode, AgendaNode, ARIA_ROLE, initialFocusScheduled, initialFocusSeen, PRESENTED_SCOPE, presentedOpeners, presentedObserver, A11yHintDescription, WebRenderer;
|
|
25628
25722
|
var init_renderNode = __esm({
|
|
25629
25723
|
"../../core/web-renderer/src/renderNode.tsx"() {
|
|
25630
25724
|
"use strict";
|
|
@@ -25989,7 +26083,9 @@ var init_renderNode = __esm({
|
|
|
25989
26083
|
AUTOCAPITALIZE_VALUES = /* @__PURE__ */ new Set(["none", "words", "sentences", "characters"]);
|
|
25990
26084
|
ENTER_KEY_HINTS = /* @__PURE__ */ new Set(["done", "go", "next", "send", "search"]);
|
|
25991
26085
|
AUTOGROW_CEILING = 12;
|
|
25992
|
-
EditableField = ({ props, ctx, wrap, multiline, id: htmlId, "data-component-id": componentId, "data-component-type": componentType }) => {
|
|
26086
|
+
EditableField = ({ props, ctx, wrap, multiline, id: htmlId, "data-component-id": componentId, "data-component-type": componentType, tabIndex: tabIndexProp, "data-hm-synthetic-tabindex": tabIndexIsSynthetic, "data-himalaya-initial-focus": initialFocusMarker, "aria-live": ariaLive, "aria-atomic": ariaAtomic, "aria-relevant": ariaRelevant, "aria-label": ariaLabelProp }) => {
|
|
26087
|
+
const tabIndex = tabIndexIsSynthetic === true ? void 0 : tabIndexProp;
|
|
26088
|
+
const a11yFwd = { tabIndex, "data-himalaya-initial-focus": initialFocusMarker, "aria-live": ariaLive, "aria-atomic": ariaAtomic, "aria-relevant": ariaRelevant };
|
|
25993
26089
|
const C = ctx.color;
|
|
25994
26090
|
const ctrl = props.text ?? props.value;
|
|
25995
26091
|
const cfg = ctrl && typeof ctrl === "object" ? ctrl : {};
|
|
@@ -26134,7 +26230,7 @@ var init_renderNode = __esm({
|
|
|
26134
26230
|
/* @__PURE__ */ jsxs3("div", { style: box, children: [
|
|
26135
26231
|
props.leadingIcon && accIcon(props.leadingIcon),
|
|
26136
26232
|
props.prefix && /* @__PURE__ */ jsx6("span", { style: { color: muted, flex: "none" }, children: String(props.prefix) }),
|
|
26137
|
-
multilineBox ? /* @__PURE__ */ jsx6("textarea", { "data-component-id": componentId, id: htmlId, "data-component-type": componentType, ref: inputRef, value: local, onChange: onInput, onFocus: onFieldFocus, onBlur: onFieldBlur, placeholder: placeholder2, rows: 2, "aria-label": placeholder2, "aria-invalid": errored || void 0, "aria-describedby": errorId, 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__ */ jsx6("input", { "data-component-id": componentId, id: htmlId, "data-component-type": componentType, ref: inputRef, type: secure ? "password" : "text", value: local, onChange: onInput, onKeyDown, onFocus: onFieldFocus, onBlur: onFieldBlur, placeholder: placeholder2, "aria-label": placeholder2, "aria-invalid": errored || void 0, "aria-describedby": errorId, 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 }),
|
|
26233
|
+
multilineBox ? /* @__PURE__ */ jsx6("textarea", { "data-component-id": componentId, id: htmlId, "data-component-type": componentType, ...a11yFwd, ref: inputRef, value: local, onChange: onInput, onFocus: onFieldFocus, onBlur: onFieldBlur, placeholder: placeholder2, rows: 2, "aria-label": ariaLabelProp ?? placeholder2, "aria-invalid": errored || void 0, "aria-describedby": errorId, 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__ */ jsx6("input", { "data-component-id": componentId, id: htmlId, "data-component-type": componentType, ...a11yFwd, ref: inputRef, type: secure ? "password" : "text", value: local, onChange: onInput, onKeyDown, onFocus: onFieldFocus, onBlur: onFieldBlur, placeholder: placeholder2, "aria-label": ariaLabelProp ?? placeholder2, "aria-invalid": errored || void 0, "aria-describedby": errorId, 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 }),
|
|
26138
26234
|
props.suffix && /* @__PURE__ */ jsx6("span", { style: { color: muted, flex: "none" }, children: String(props.suffix) }),
|
|
26139
26235
|
props.clearButton && local && /* @__PURE__ */ jsx6("span", { onClick: () => {
|
|
26140
26236
|
setLocal("");
|
|
@@ -26166,15 +26262,47 @@ var init_renderNode = __esm({
|
|
|
26166
26262
|
document.removeEventListener("keydown", onKey);
|
|
26167
26263
|
};
|
|
26168
26264
|
}, [open]);
|
|
26265
|
+
const modal = ariaModal(props.modal, false) === "true";
|
|
26266
|
+
const anchorLabel = props.anchor?.modifiers?.accessibilityLabel || "More actions";
|
|
26267
|
+
const popupPlacement = { position: "absolute", top: "100%", right: 0, zIndex: 20, marginTop: 4 };
|
|
26268
|
+
const anchorRef = React5.useRef(null);
|
|
26269
|
+
const menuRef = React5.useRef(null);
|
|
26270
|
+
const itemsKey = items.map((it, i) => `${it?.id ?? i}:${it?.disabled ? 0 : 1}`).join("|");
|
|
26271
|
+
React5.useEffect(() => {
|
|
26272
|
+
if (!open || !modal) return;
|
|
26273
|
+
const menu = menuRef.current;
|
|
26274
|
+
if (!menu || menu.contains(document.activeElement)) return;
|
|
26275
|
+
(menu.querySelector('[role="menuitem"][tabindex="0"]') ?? menu).focus();
|
|
26276
|
+
}, [open, modal, itemsKey]);
|
|
26277
|
+
React5.useEffect(() => {
|
|
26278
|
+
if (!open || !modal) return;
|
|
26279
|
+
return () => {
|
|
26280
|
+
const active = document.activeElement;
|
|
26281
|
+
if (active == null || active === document.body || !document.contains(active)) anchorRef.current?.focus();
|
|
26282
|
+
};
|
|
26283
|
+
}, [open, modal]);
|
|
26284
|
+
const trapTab = (e) => {
|
|
26285
|
+
if (!modal || e.key !== "Tab") return;
|
|
26286
|
+
const items2 = Array.from(menuRef.current?.querySelectorAll('[role="menuitem"][tabindex="0"]') ?? []);
|
|
26287
|
+
if (!items2.length) {
|
|
26288
|
+
e.preventDefault();
|
|
26289
|
+
return;
|
|
26290
|
+
}
|
|
26291
|
+
const at = items2.indexOf(document.activeElement);
|
|
26292
|
+
const next = e.shiftKey ? at <= 0 ? items2.length - 1 : at - 1 : at < 0 || at === items2.length - 1 ? 0 : at + 1;
|
|
26293
|
+
e.preventDefault();
|
|
26294
|
+
items2[next].focus();
|
|
26295
|
+
};
|
|
26169
26296
|
return /* @__PURE__ */ jsxs3("span", { ref: hostRef, style: { position: "relative", display: "inline-flex", ...wrap }, children: [
|
|
26170
26297
|
/* @__PURE__ */ jsx6(
|
|
26171
26298
|
"span",
|
|
26172
26299
|
{
|
|
26300
|
+
ref: anchorRef,
|
|
26173
26301
|
role: "button",
|
|
26174
26302
|
tabIndex: 0,
|
|
26175
26303
|
"aria-haspopup": "menu",
|
|
26176
26304
|
"aria-expanded": open,
|
|
26177
|
-
"aria-label":
|
|
26305
|
+
"aria-label": anchorLabel,
|
|
26178
26306
|
onClick: (e) => {
|
|
26179
26307
|
e.stopPropagation();
|
|
26180
26308
|
setOpen((v) => !v);
|
|
@@ -26190,11 +26318,14 @@ var init_renderNode = __esm({
|
|
|
26190
26318
|
children: props.anchor ? renderNode(props.anchor, ctx) : iconSvg("more", { size: 20, color: C("textSecondary", "#636b78") })
|
|
26191
26319
|
}
|
|
26192
26320
|
),
|
|
26193
|
-
open && /* @__PURE__ */ jsx6(
|
|
26321
|
+
open && wrapModalMenu(modal, anchorLabel, popupPlacement, /* @__PURE__ */ jsx6(
|
|
26194
26322
|
"div",
|
|
26195
26323
|
{
|
|
26324
|
+
ref: menuRef,
|
|
26196
26325
|
role: "menu",
|
|
26197
|
-
|
|
26326
|
+
tabIndex: modal ? -1 : void 0,
|
|
26327
|
+
onKeyDown: trapTab,
|
|
26328
|
+
style: { ...modal ? {} : popupPlacement, display: "flex", flexDirection: "column", minWidth: 180, background: C("surfacePrimary", "#fff"), border: `1px solid ${C("border", "#e3e3e3")}`, borderRadius: 12, boxShadow: "0 6px 20px rgba(0,0,0,.12)", overflow: "hidden", padding: 4 },
|
|
26198
26329
|
children: items.map((it, i) => /* @__PURE__ */ jsxs3(
|
|
26199
26330
|
"div",
|
|
26200
26331
|
{
|
|
@@ -26223,7 +26354,7 @@ var init_renderNode = __esm({
|
|
|
26223
26354
|
it?.id ?? i
|
|
26224
26355
|
))
|
|
26225
26356
|
}
|
|
26226
|
-
)
|
|
26357
|
+
))
|
|
26227
26358
|
] });
|
|
26228
26359
|
});
|
|
26229
26360
|
LoadMoreSentinel = ({ ctx, pagination }) => {
|
|
@@ -27100,6 +27231,7 @@ var init_renderNode = __esm({
|
|
|
27100
27231
|
] });
|
|
27101
27232
|
});
|
|
27102
27233
|
SYNTHETIC_TAP_ROLE = "data-hm-synthetic-role";
|
|
27234
|
+
SYNTHETIC_TABINDEX = "data-hm-synthetic-tabindex";
|
|
27103
27235
|
INFERRED_DECORATIVE = "data-hm-inferred-decorative";
|
|
27104
27236
|
ICON_GLYPH = "data-hm-icon-glyph";
|
|
27105
27237
|
INTERACTIVE_ROLES = /* @__PURE__ */ new Set([
|
|
@@ -27463,7 +27595,7 @@ var init_renderNode = __esm({
|
|
|
27463
27595
|
if (gated && presented !== true && presented !== "true") return null;
|
|
27464
27596
|
const grabber = props.showGrabber !== false;
|
|
27465
27597
|
const sheet = idiomControls(ctx.idiom).sheet;
|
|
27466
|
-
return /* @__PURE__ */ jsx6("div", { style: { position: "absolute", inset: 0, background: "rgba(0,0,0,.35)", zIndex: 50, display: "flex", flexDirection: "column", justifyContent: "flex-end", ...wrap }, children: /* @__PURE__ */ jsxs3("div", { role: "dialog", "aria-modal":
|
|
27598
|
+
return /* @__PURE__ */ jsx6("div", { style: { position: "absolute", inset: 0, background: "rgba(0,0,0,.35)", zIndex: 50, display: "flex", flexDirection: "column", justifyContent: "flex-end", ...wrap }, children: /* @__PURE__ */ jsxs3("div", { role: "dialog", "aria-modal": ariaModal(props.modal, true), "aria-label": props.title != null ? sheetTitle : "Sheet", style: { width: "100%", background: C("surfacePrimary", "#fff"), borderRadius: `${sheet.cornerRadius}px ${sheet.cornerRadius}px 0 0`, boxShadow: "0 -4px 24px rgba(0,0,0,.12)", overflow: "hidden" }, children: [
|
|
27467
27599
|
grabber && /* @__PURE__ */ jsx6("div", { style: { display: "flex", justifyContent: "center", padding: "8px 0 4px" }, children: /* @__PURE__ */ jsx6("div", { style: { width: sheet.grabberWidth, height: sheet.grabberHeight, borderRadius: 999, background: C("surfaceTertiary", "#d8dce2") } }) }),
|
|
27468
27600
|
/* @__PURE__ */ jsx6("div", { style: { padding: "8px 16px 16px" }, children: props.content ? renderNode(props.content, ctx) : null })
|
|
27469
27601
|
] }) });
|
|
@@ -29001,6 +29133,11 @@ var init_renderNode = __esm({
|
|
|
29001
29133
|
grid: "grid",
|
|
29002
29134
|
gridcell: "gridcell"
|
|
29003
29135
|
};
|
|
29136
|
+
initialFocusScheduled = false;
|
|
29137
|
+
initialFocusSeen = /* @__PURE__ */ new WeakSet();
|
|
29138
|
+
PRESENTED_SCOPE = '[aria-modal="true"], [role="dialog"], [role="alertdialog"], [role="menu"]';
|
|
29139
|
+
presentedOpeners = /* @__PURE__ */ new Map();
|
|
29140
|
+
presentedObserver = null;
|
|
29004
29141
|
A11yHintDescription = ({ hint, idBase, children, ...forwarded }) => {
|
|
29005
29142
|
const descId = `${idBase ?? "hm"}__hint${React5.useId()}`;
|
|
29006
29143
|
const own3 = children.props;
|
|
@@ -39279,11 +39416,22 @@ function liveRun(dir) {
|
|
|
39279
39416
|
const build2 = obj(rec?.build);
|
|
39280
39417
|
try {
|
|
39281
39418
|
process.kill(pid, 0);
|
|
39419
|
+
const at = text(build2?.at);
|
|
39282
39420
|
return {
|
|
39283
39421
|
url,
|
|
39422
|
+
// Which run this is: a restart on the same port serves the same URL from a new process.
|
|
39423
|
+
runId: `${pid}@${text(rec?.startedAt) ?? ""}`,
|
|
39284
39424
|
buildError: build2?.ok === false ? text(build2.error) ?? "the last rebuild failed" : null,
|
|
39285
39425
|
// Only `--watch` wrote this record before plain runs did, so a record without the key is one.
|
|
39286
|
-
watching: rec?.watching !== false
|
|
39426
|
+
watching: rec?.watching !== false,
|
|
39427
|
+
lastBuild: build2 && at ? {
|
|
39428
|
+
at,
|
|
39429
|
+
ok: build2.ok !== false,
|
|
39430
|
+
ms: typeof build2.ms === "number" && Number.isFinite(build2.ms) ? Math.max(0, Math.round(build2.ms)) : null,
|
|
39431
|
+
screens: (Array.isArray(build2.screens) ? build2.screens : []).filter((x) => typeof x === "string").slice(0, 20),
|
|
39432
|
+
tokens: build2.tokens === true,
|
|
39433
|
+
config: build2.config === true
|
|
39434
|
+
} : null
|
|
39287
39435
|
};
|
|
39288
39436
|
} catch {
|
|
39289
39437
|
return null;
|
|
@@ -39400,6 +39548,7 @@ function renderStudioHtml(initial) {
|
|
|
39400
39548
|
<meta charset="utf-8">
|
|
39401
39549
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
39402
39550
|
<title>${escapeHtml(initial.app.name)} \xB7 build board</title>
|
|
39551
|
+
<link rel="icon" id="fav" href="data:,">
|
|
39403
39552
|
<style>
|
|
39404
39553
|
:root{--bg:#f6f5f2;--card:#fff;--ink:#1c1c1a;--muted:#6b6a64;--faint:#a3a19a;--line:#e6e3dc;--ok:#1f7a4d;--okbg:#e3f3ea;--warn:#8a5a00;--warnbg:#fbefd6;--bad:#a12a2a;--badbg:#fbe4e4;--accent:${accent};--shadow:0 1px 2px rgba(0,0,0,.04),0 4px 16px rgba(0,0,0,.04)}
|
|
39405
39554
|
@media (prefers-color-scheme:dark){:root{--bg:#121211;--card:#1c1c1a;--ink:#ecebe6;--muted:#a3a19a;--faint:#6b6a64;--line:#2c2b28;--okbg:#15301f;--ok:#7fd3a2;--warnbg:#33270f;--warn:#f0c46b;--badbg:#3a1616;--bad:#f09a9a;--shadow:none}}
|
|
@@ -39418,6 +39567,7 @@ h1{font-size:20px;font-weight:600;margin:0}.sub{color:var(--muted);font-size:13p
|
|
|
39418
39567
|
h2{font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;margin:0 0 10px}
|
|
39419
39568
|
.phone{width:100%;max-width:300px;aspect-ratio:390/844;border-radius:34px;border:9px solid #111;background:#fff;overflow:hidden;margin:0 auto;display:block}
|
|
39420
39569
|
.phone img,.phone iframe{width:100%;height:100%;object-fit:cover;object-position:top;border:0;display:block;cursor:zoom-in}
|
|
39570
|
+
.phone.vpf{position:relative}.phone iframe.vp{position:absolute;top:0;left:0;width:390px;height:844px;transform-origin:0 0;transform:scale(var(--k,.72));cursor:auto}
|
|
39421
39571
|
.cap{text-align:center;color:var(--muted);font-size:12px;margin-top:8px}
|
|
39422
39572
|
.film{display:flex;gap:6px;overflow-x:auto;margin-top:12px;padding-bottom:4px}.film img{width:48px;aspect-ratio:390/844;object-fit:cover;object-position:top;border-radius:8px;border:1px solid var(--line);cursor:zoom-in}
|
|
39423
39573
|
.chips{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:16px}.chip{font-size:12px;padding:5px 10px;border-radius:999px;background:var(--card);border:1px solid var(--line);color:var(--muted)}
|
|
@@ -39432,12 +39582,26 @@ h2{font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;le
|
|
|
39432
39582
|
.log .t{color:var(--faint);font-size:12px;min-width:64px;font-variant-numeric:tabular-nums}.log .s{font-size:11px;color:var(--muted);text-transform:capitalize}.log .imgs{display:flex;gap:6px;margin-top:6px}.log .imgs img{height:72px;border-radius:8px;border:1px solid var(--line);cursor:zoom-in}
|
|
39433
39583
|
.empty{color:var(--faint);font-size:13px;padding:8px 0}
|
|
39434
39584
|
#lb{position:fixed;inset:0;background:rgba(0,0,0,.72);display:none;align-items:center;justify-content:center;z-index:9;cursor:zoom-out}#lb img{max-height:92vh;max-width:92vw;border-radius:14px;background:#fff}
|
|
39585
|
+
.enter{animation:enter .7s cubic-bezier(.2,.8,.2,1) both}@keyframes enter{from{opacity:0;transform:translateY(10px) scale(.94);filter:grayscale(1)}to{opacity:1;transform:none;filter:none}}
|
|
39586
|
+
.changed .frame{animation:chg .9s ease both}@keyframes chg{35%{opacity:.25;transform:scale(.96)}100%{opacity:1;transform:none}}
|
|
39587
|
+
.step.fresh .bar{animation:fill .7s ease both;transform-origin:left}@keyframes fill{from{transform:scaleX(0)}to{transform:scaleX(1)}}
|
|
39588
|
+
.slidein{animation:slide .45s cubic-bezier(.2,.8,.2,1) both}@keyframes slide{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
|
|
39589
|
+
.phone.pulse{animation:pulse 1s ease-out}.phone.pulse.bad{animation-name:pulsebad}@keyframes pulse{from{outline:3px solid var(--ok);outline-offset:0}to{outline:3px solid transparent;outline-offset:10px}}@keyframes pulsebad{from{outline:3px solid var(--bad);outline-offset:0}to{outline:3px solid transparent;outline-offset:10px}}
|
|
39590
|
+
.toast{display:block;width:max-content;max-width:100%;margin:8px auto 0;font-size:12px;padding:4px 10px;border-radius:999px;background:var(--okbg);color:var(--ok);animation:toast 3.4s ease both}.toast.bad{background:var(--badbg);color:var(--bad)}@keyframes toast{0%{opacity:0;transform:translateY(4px)}10%,80%{opacity:1;transform:none}100%{opacity:0}}
|
|
39591
|
+
.icon,.step.cur .bar{transition:background-color .8s}.sw.pop span{animation:pop .6s ease both}@keyframes pop{50%{transform:scale(1.25)}}
|
|
39592
|
+
.quiet{color:var(--warn)}.quiet .dot{background:var(--warn)}.idle .dot{background:var(--faint)}
|
|
39593
|
+
.tog{font:inherit;font-size:12px;color:var(--muted);background:none;border:1px solid var(--line);border-radius:999px;padding:2px 9px;margin:6px 0 0 6px;cursor:pointer}.tog.on{color:var(--ink);border-color:var(--ink)}
|
|
39594
|
+
#fx{position:fixed;inset:0;width:100%;height:100%;pointer-events:none;z-index:8}
|
|
39595
|
+
@media (max-width:560px){header{flex-wrap:wrap}.right{margin-left:0;width:100%;text-align:left;display:flex;flex-wrap:wrap;align-items:center;gap:4px 12px}.right .clock{font-size:18px}.tog{margin:0 6px 0 0}}
|
|
39596
|
+
@media (prefers-reduced-motion:reduce){.enter,.changed .frame,.step.fresh .bar,.slidein,.phone.pulse,.sw.pop span,.toast{animation:none}.icon,.step.cur .bar{transition:none}}
|
|
39435
39597
|
</style>
|
|
39436
39598
|
</head>
|
|
39437
39599
|
<body>
|
|
39438
39600
|
<div class="wrap">
|
|
39439
39601
|
<header><img class="icon" id="icon" alt=""><div><h1 id="name"></h1><div class="sub">Build board \xB7 updates itself as the app is built</div></div>
|
|
39440
|
-
<div class="right"><div class="clock" id="clock">00:00</div><div class="live" id="live"><span class="dot"></span><span id="updated">live</span></div
|
|
39602
|
+
<div class="right"><div class="clock" id="clock">00:00</div><div class="live" id="live"><span class="dot"></span><span id="updated">live</span></div>
|
|
39603
|
+
<div><span class="live idle" id="agent"><span class="dot"></span><span id="agentt">Waiting for the agent</span></span></div>
|
|
39604
|
+
<div><button class="tog" id="snd" type="button" aria-pressed="false">Sound off</button><button class="tog" id="ntf" type="button" aria-pressed="false" hidden>Notices off</button></div></div></header>
|
|
39441
39605
|
<div class="steps" id="steps"></div>
|
|
39442
39606
|
<div class="card now"><div style="flex:1"><div class="meta" id="nowmeta">Now</div><div class="msg" id="nowmsg"></div></div></div>
|
|
39443
39607
|
<div class="grid">
|
|
@@ -39450,6 +39614,7 @@ h2{font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;le
|
|
|
39450
39614
|
<div class="card section"><h2>Postcards</h2><ul class="log" id="log"></ul></div>
|
|
39451
39615
|
</div></div></div>
|
|
39452
39616
|
<div id="lb"><img alt=""></div>
|
|
39617
|
+
<canvas id="fx" aria-hidden="true"></canvas>
|
|
39453
39618
|
<script>window.__himiInitial = ${scriptJson(initial)};</script>
|
|
39454
39619
|
<script>
|
|
39455
39620
|
(function(){
|
|
@@ -39464,27 +39629,33 @@ function zoomable(img){img.addEventListener("click",function(){var lb=$("lb");lb
|
|
|
39464
39629
|
function img(src,cls){var i=el("img",cls);i.src=src;i.alt="";i.loading="lazy";zoomable(i);return i}
|
|
39465
39630
|
function chip(txt,kind){return el("span","chip"+(kind?" "+kind:""),txt)}
|
|
39466
39631
|
function render(s){
|
|
39467
|
-
document.title=s.app.name+" \xB7 build board";$("name").textContent=s.app.name;
|
|
39632
|
+
var sn=s.current?s.current.stepNumber:0;document.title=(sn?"("+sn+"/8) ":"")+s.app.name+" \xB7 build board";favicon(sn,!!(s.live&&s.live.buildError));$("name").textContent=s.app.name;
|
|
39468
39633
|
if(s.app.icon){$("icon").src=s.app.icon}else{$("icon").removeAttribute("src")}
|
|
39469
39634
|
var steps=$("steps");clear(steps);var n=s.current?s.current.stepNumber:0;
|
|
39470
39635
|
s.steps.forEach(function(name,i){var d=el("div","step"+(i+1<n?" done":i+1===n?" cur":""));d.appendChild(el("div","bar"));d.appendChild(el("div","lbl",(i+1)+". "+name));steps.appendChild(d)});
|
|
39471
39636
|
var last=s.journal[0];
|
|
39472
39637
|
$("nowmsg").textContent=last?last.message:"Waiting for the first postcard.";
|
|
39473
39638
|
$("nowmeta").textContent=last?("Now \xB7 "+(last.step?("step "+last.stepNumber+" of 8, "+last.step+" \xB7 "):"")+ago(last.ts)):"Now";
|
|
39474
|
-
var focus=$("focus");
|
|
39475
|
-
|
|
39639
|
+
var focus=$("focus");var film=$("film");clear(film);
|
|
39640
|
+
/* The live frame is KEPT across renders while its URL and its run are unchanged (a restarted run on
|
|
39641
|
+
the same port is a different server, and the old frame would never see its builds). A new iframe is a full page
|
|
39642
|
+
load of the preview: every postcard, rebuild and the once-a-minute re-render used to throw away
|
|
39643
|
+
the in-place repaint, the preview's scroll and wherever the owner had navigated inside it. */
|
|
39644
|
+
var kept=s.live?focus.querySelector("iframe"):null;if(kept&&(kept.getAttribute("src")!==s.live.url||kept.getAttribute("data-run")!==s.live.runId))kept=null;
|
|
39645
|
+
if(kept){while(focus.lastChild&&focus.lastChild!==kept.parentNode)focus.removeChild(focus.lastChild)}else clear(focus);
|
|
39646
|
+
if(s.live){$("focuslbl").textContent="Live preview";if(!kept){var f=el("div","phone vpf");var fr=document.createElement("iframe");fr.className="vp";fr.setAttribute("width","390");fr.setAttribute("height","844");fr.setAttribute("data-run",s.live.runId);fr.src=s.live.url;fr.title="Live preview";f.appendChild(fr);focus.appendChild(f)}fit();if(s.live.buildError){var be=el("div","chip bad",null);be.style.display="block";be.style.marginTop="8px";be.textContent="Last edit did not build, still showing the last good version: "+s.live.buildError;focus.appendChild(be)}focus.appendChild(el("div","cap",(s.live.watching?"Repaints as the app is edited \xB7 ":"The build this run started with; himi run --watch repaints on every edit \xB7 ")+s.live.url))}
|
|
39476
39647
|
else if(s.focus&&s.focus.frames.length){var fl=s.focus.frames;$("focuslbl").textContent="Latest \xB7 "+s.focus.id;var p=el("div","phone");p.appendChild(img(fl[fl.length-1].img));focus.appendChild(p);focus.appendChild(el("div","cap",fl.length+(fl.length===1?" version":" versions")+" so far"))}
|
|
39477
39648
|
else{$("focuslbl").textContent="Latest";focus.appendChild(el("div","empty","The first render appears here."))}
|
|
39478
39649
|
if(s.focus&&s.focus.frames.length>1)s.focus.frames.forEach(function(fm){film.appendChild(img(fm.img))});
|
|
39479
39650
|
var chips=$("chips");clear(chips);var h=s.health;
|
|
39480
39651
|
if(h.validate)chips.appendChild(chip(h.validate.ok?"Validate passing":"Validate: "+h.validate.errors+" errors",h.validate.ok?"ok":"bad"));
|
|
39481
|
-
if(h.test){var t=h.test;var
|
|
39652
|
+
if(h.test){var t=h.test;var moved=t.prevGaps!=null&&t.prevGaps!==t.gaps;var tc=chip("Test crawl: "+t.screens+" screens, "+t.actions+" actions, "+(moved?"gaps "+t.prevGaps+" \u2192 ":""),t.ok?"ok":"bad");var gn=el("span",null,String(t.gaps));gn.id="gapn";tc.appendChild(gn);if(!moved)tc.appendChild(document.createTextNode(" gaps"));chips.appendChild(tc)}
|
|
39482
39653
|
h.ux.forEach(function(u){chips.appendChild(chip("UX drive "+u.platform+": "+u.status,u.status==="passed"?"ok":u.status==="failed"?"bad":"warn"))});
|
|
39483
39654
|
if(h.push)chips.appendChild(chip((h.push.draft?"Draft published":"Published live")+" \xB7 "+h.push.releaseId.slice(0,10),h.push.draft?"warn":"ok"));
|
|
39484
39655
|
if(!chips.firstChild)chips.appendChild(chip("Checks appear here as validate, test and push run"));
|
|
39485
39656
|
var wall=$("wall");clear(wall);
|
|
39486
39657
|
if(!s.screens.length)wall.appendChild(el("div","empty","Screens appear here as they render."));
|
|
39487
|
-
s.screens.forEach(function(sc){var d=el("div","shot");var fr=el("div","frame");fr.appendChild(img(sc.img));d.appendChild(fr);d.appendChild(el("div","id",sc.id));
|
|
39658
|
+
s.screens.forEach(function(sc){var d=el("div","shot");d.setAttribute("data-id",sc.id);var fr=el("div","frame");fr.appendChild(img(sc.img));d.appendChild(fr);d.appendChild(el("div","id",sc.id));
|
|
39488
39659
|
if(recent(sc.firstSeen)&&sc.versions===1)d.appendChild(el("span","badge new","New"));else if(recent(sc.changedAt)&&sc.versions>1)d.appendChild(el("span","badge chg","Changed"));wall.appendChild(d)});
|
|
39489
39660
|
var brand=$("brand");clear(brand);$("brandcard").style.display=(s.brand.site||s.app.palette.length)?"":"none";
|
|
39490
39661
|
if(s.brand.site){var si=img(s.brand.site,"site");brand.appendChild(si)}
|
|
@@ -39495,14 +39666,61 @@ function render(s){
|
|
|
39495
39666
|
s.journal.forEach(function(j){var li=el("li");li.appendChild(el("div","t",hhmm(j.ts)));var body=el("div");body.appendChild(el("div",null,j.message));if(j.step)body.appendChild(el("div","s","step "+j.stepNumber+" \xB7 "+j.step));
|
|
39496
39667
|
if(j.images.length){var row=el("div","imgs");j.images.forEach(function(u){row.appendChild(img(u))});body.appendChild(row)}li.appendChild(body);log.appendChild(li)});
|
|
39497
39668
|
}
|
|
39498
|
-
|
|
39669
|
+
/* Motion, sound and notices answer a CHANGE, never a redraw: effects() compares what is on the page
|
|
39670
|
+
now with what it showed last, so opening the board, the once-a-minute redraw and the two-second
|
|
39671
|
+
poll of an unchanged state do nothing, and each effect names a real event. */
|
|
39672
|
+
var seen=null,actx=null,sound=false,notices=false;try{sound=localStorage.getItem("himiStudioSound")==="1";notices=localStorage.getItem("himiStudioNotify")==="1"}catch(e){}
|
|
39673
|
+
var raf=window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(f){return setTimeout(function(){f(Date.now())},16)};
|
|
39674
|
+
function now(){return window.performance&&performance.now?performance.now():Date.now()}
|
|
39675
|
+
function reduced(){try{return matchMedia("(prefers-reduced-motion: reduce)").matches}catch(e){return false}}
|
|
39676
|
+
function tone(f,t,d,v,type){if(!sound)return;try{if(!actx){var AC=window.AudioContext||window.webkitAudioContext;if(!AC)return;actx=new AC()}var o=actx.createOscillator(),g=actx.createGain(),n=actx.currentTime+(t||0),dd=d||.18;o.type=type||"sine";o.frequency.value=f;g.gain.setValueAtTime(0,n);g.gain.linearRampToValueAtTime(v||.05,n+.01);g.gain.exponentialRampToValueAtTime(.0001,n+dd);o.connect(g);g.connect(actx.destination);o.start(n);o.stop(n+dd+.05)}catch(e){}}
|
|
39677
|
+
var SND={tick:function(){tone(1320,0,.05,.025,"triangle")},post:function(){tone(880,0,.08,.03)},step:function(){tone(523);tone(784,.12)},win:function(){tone(523);tone(659,.1);tone(784,.2);tone(1047,.3,.35)},fail:function(){tone(160,0,.3,.05,"sawtooth")}};
|
|
39678
|
+
/* Notices are the BOARD's opt-in, not just the browser's: a permission granted to this origin once
|
|
39679
|
+
(an earlier board, another run) must not switch them on, and the toggle must switch them off. */
|
|
39680
|
+
function notify(title,body){try{if(notices&&"Notification" in window&&Notification.permission==="granted"&&document.hidden)new Notification(title,{body:body})}catch(e){}}
|
|
39681
|
+
function accentNow(){return (getComputedStyle(document.documentElement).getPropertyValue("--accent")||"").trim()||"#3b6fd8"}
|
|
39682
|
+
/* The preview lays out at a real phone's viewport (390 x 844 CSS px) and is scaled into the frame.
|
|
39683
|
+
Sized to the frame itself it was ~280px wide: narrower than any phone, so screens overflowed
|
|
39684
|
+
sideways and scrolled horizontally. */
|
|
39685
|
+
function fit(){var ph=$("focus").querySelector(".phone.vpf");if(!ph)return;var w=ph.clientWidth,h=ph.clientHeight;if(w&&h)ph.style.setProperty("--k",String(Math.min(w/390,h/844)))}
|
|
39686
|
+
window.addEventListener("resize",fit);
|
|
39687
|
+
function favicon(n,bad){try{var c=document.createElement("canvas");c.width=c.height=32;var x=c.getContext&&c.getContext("2d");if(!x)return;x.lineWidth=5;x.strokeStyle="rgba(128,128,128,.35)";x.beginPath();x.arc(16,16,12,0,6.2832);x.stroke();x.strokeStyle=accentNow();x.beginPath();x.arc(16,16,12,-1.5708,-1.5708+6.2832*n/8);x.stroke();if(bad){x.fillStyle="#d33";x.beginPath();x.arc(25,7,6,0,6.2832);x.fill()}$("fav").href=c.toDataURL("image/png")}catch(e){}}
|
|
39688
|
+
function burst(){var c=$("fx");c.setAttribute("data-bursts",String((+c.getAttribute("data-bursts")||0)+1));if(reduced())return;var x=c.getContext&&c.getContext("2d");if(!x)return;var W=c.width=innerWidth,H=c.height=innerHeight,cols=["#1f7a4d","#3b6fd8","#e0a030","#d4537e",accentNow()],P=[];for(var i=0;i<120;i++)P.push({x:W/2,y:H*.35,vx:(Math.random()-.5)*14,vy:-Math.random()*12-4,c:cols[i%cols.length],r:Math.random()*6.28});var t0=now();(function f(){x.clearRect(0,0,W,H);P.forEach(function(p){p.x+=p.vx;p.y+=p.vy;p.vy+=.35;p.r+=.2;x.save();x.translate(p.x,p.y);x.rotate(p.r);x.fillStyle=p.c;x.fillRect(-4,-2,8,4);x.restore()});if(now()-t0<2200)raf(f);else x.clearRect(0,0,W,H)})()}
|
|
39689
|
+
function countTo(e,a,b){if(!e)return;if(reduced()){e.textContent=String(b);return}var t0=now();(function f(){var k=Math.min(1,(now()-t0)/900);e.textContent=String(Math.round(a+(b-a)*k));if(k<1)raf(f)})()}
|
|
39690
|
+
function snap(s){var sc={},acc=null;s.screens.forEach(function(x){sc[x.id]=x.img});s.app.palette.forEach(function(p){if(p.name==="accentPrimary")acc=p.hex});return{screens:sc,step:s.current?s.current.stepNumber:0,top:s.journal[0]?s.journal[0].ts:null,build:s.live&&s.live.lastBuild?s.live.lastBuild.at:null,run:s.live?s.live.runId:null,push:s.health.push?s.health.push.releaseId:null,gaps:s.health.test?s.health.test.gaps:null,accent:acc}}
|
|
39691
|
+
function buildLine(b){if(!b.ok)return "Build failed \xB7 still showing the last good version";var what=b.screens.length?b.screens.slice(0,3).join(", ")+(b.screens.length>3?" +"+(b.screens.length-3):""):b.tokens?"design tokens":b.config?"app config":"no visible change";return "Rebuilt"+(b.ms!=null?" in "+(b.ms/1000).toFixed(1)+" s":"")+" \xB7 "+what}
|
|
39692
|
+
function effects(s){var is=snap(s),was=seen;seen=is;if(is.accent)document.documentElement.style.setProperty("--accent",is.accent);
|
|
39693
|
+
/* The phone (kept across renders) and the Now line outlive a render: clear what they played last. */
|
|
39694
|
+
var ph=$("focus").querySelector(".phone"),nm=$("nowmsg");if(ph)ph.classList.remove("pulse","bad");nm.classList.remove("slidein");if(!was)return;
|
|
39695
|
+
var ticked=false;[].forEach.call($("wall").children,function(d){var id=d.getAttribute("data-id");if(!id)return;if(!(id in was.screens)){d.classList.add("enter");ticked=true}else if(was.screens[id]!==is.screens[id]){d.classList.add("changed");ticked=true}});if(ticked)SND.tick();
|
|
39696
|
+
if(is.top&&is.top!==was.top){void nm.offsetWidth;nm.classList.add("slidein");var li=$("log").firstChild;if(li&&li.classList)li.classList.add("slidein");SND.post()}
|
|
39697
|
+
if(is.step>was.step){var cs=$("steps").children[is.step-1];if(cs)cs.classList.add("fresh");SND.step();notify(s.app.name+" \xB7 step "+is.step+" of 8",s.journal[0]?s.journal[0].message:s.steps[is.step-1])}
|
|
39698
|
+
/* A rebuild is a later build of the SAME run: a run appearing, or restarting, records its first
|
|
39699
|
+
build too, and nothing was rebuilt then. */
|
|
39700
|
+
if(is.build&&was.build&&is.run===was.run&&is.build!==was.build){var b=s.live.lastBuild;if(ph){void ph.offsetWidth;ph.classList.add("pulse");if(!b.ok)ph.classList.add("bad")}var tt=el("div","toast"+(b.ok?"":" bad"),buildLine(b));$("focus").appendChild(tt);setTimeout(function(){if(tt.parentNode)tt.parentNode.removeChild(tt)},3500);if(b.ok)SND.tick();else{SND.fail();notify(s.app.name+" \xB7 build failed",s.live.buildError||"")}}
|
|
39701
|
+
if(was.gaps!=null&&is.gaps!=null&&is.gaps!==was.gaps)countTo($("gapn"),was.gaps,is.gaps);
|
|
39702
|
+
if(is.accent&&was.accent&&is.accent!==was.accent){var sw=$("brand").querySelector(".sw");if(sw)sw.classList.add("pop");favicon(is.step,!!(s.live&&s.live.buildError))}
|
|
39703
|
+
var published=is.push&&is.push!==was.push,handed=is.step===8&&was.step<8;if(published||handed){burst();SND.win();notify(s.app.name,published?"Draft published":"Handed over")}
|
|
39704
|
+
}
|
|
39705
|
+
function activityAt(s){var m=0;function add(v){var d=v?Date.parse(v):0;if(d>m)m=d}if(s.journal[0])add(s.journal[0].ts);s.screens.forEach(function(x){add(x.changedAt)});if(s.live&&s.live.lastBuild)add(s.live.lastBuild.at);["validate","test","push"].forEach(function(k){if(s.health[k])add(s.health[k].at)});return m}
|
|
39706
|
+
function paintToggles(){var b=$("snd");b.textContent=sound?"Sound on":"Sound off";b.className="tog"+(sound?" on":"");b.setAttribute("aria-pressed",String(sound));var nb=$("ntf");if(!("Notification" in window)){nb.hidden=true;return}var p=Notification.permission,on=notices&&p==="granted";nb.hidden=p==="denied";nb.textContent=on?"Notices on":"Notices off";nb.className="tog"+(on?" on":"");nb.setAttribute("aria-pressed",String(on))}
|
|
39707
|
+
function setNotices(v){notices=v;try{localStorage.setItem("himiStudioNotify",v?"1":"0")}catch(e){}paintToggles()}
|
|
39708
|
+
$("snd").addEventListener("click",function(){sound=!sound;try{localStorage.setItem("himiStudioSound",sound?"1":"0")}catch(e){}if(sound){try{if(actx&&actx.resume)actx.resume()}catch(e){}SND.post()}paintToggles()});
|
|
39709
|
+
/* The click acts on what the button SAYS (the effective state), so a remembered opt-in whose browser
|
|
39710
|
+
permission was since reset reads "off" and one click asks for permission, not two. */
|
|
39711
|
+
$("ntf").addEventListener("click",function(){try{var p=Notification.permission;if(notices&&p==="granted"){setNotices(false);return}if(p==="granted"){setNotices(true);return}if(Notification.permission==="default")Promise.resolve(Notification.requestPermission()).then(function(p){setNotices(p==="granted")})}catch(e){}});
|
|
39712
|
+
document.addEventListener("click",function(){try{if(actx&&actx.state==="suspended")actx.resume()}catch(e){}},{once:true});
|
|
39713
|
+
paintToggles();
|
|
39714
|
+
window.__himiStudio=function(s){lastSeen=Date.now();if(!cur||cur.v!==s.v){cur=s;render(s);effects(s)}else{cur.generatedAt=s.generatedAt}};
|
|
39499
39715
|
$("lb").addEventListener("click",function(){this.style.display="none"});
|
|
39500
39716
|
window.__himiStudio(window.__himiInitial);
|
|
39501
39717
|
setInterval(function(){var sc=document.createElement("script");sc.src="state.js?t="+Date.now();sc.onload=sc.onerror=function(){sc.remove()};document.head.appendChild(sc)},2000);
|
|
39502
39718
|
var ticks=0;
|
|
39503
39719
|
setInterval(function(){if(!cur)return;if(++ticks%60===0)render(cur);var start=cur.startedAt?Date.parse(cur.startedAt):Date.now();var s=Math.max(0,Math.floor((Date.now()-start)/1000));var hh=Math.floor(s/3600),mm=Math.floor(s%3600/60),ss=s%60;
|
|
39504
39720
|
$("clock").textContent=(hh?hh+":":"")+(mm<10&&hh?"0":"")+mm+":"+(ss<10?"0":"")+ss;
|
|
39505
|
-
$("updated").textContent="updated "+ago(cur.generatedAt);$("live").className="live"+(Date.now()-lastSeen>10000?" stale":"")
|
|
39721
|
+
$("updated").textContent="updated "+ago(cur.generatedAt);$("live").className="live"+(Date.now()-lastSeen>10000?" stale":"");
|
|
39722
|
+
var a=activityAt(cur),q=a?Date.now()-a:0,done=cur.current&&cur.current.stepNumber===8;
|
|
39723
|
+
$("agent").className="live"+(!a?" idle":done?"":q>5*60*1000?" quiet":"");$("agentt").textContent=!a?"Waiting for the agent":done?"Handed over":q>5*60*1000?"Quiet for "+Math.floor(q/60000)+" min":"Agent active"},1000);
|
|
39506
39724
|
})();
|
|
39507
39725
|
</script>
|
|
39508
39726
|
</body>
|
|
@@ -47241,7 +47459,6 @@ function makeServeHandler(opts) {
|
|
|
47241
47459
|
);
|
|
47242
47460
|
})();
|
|
47243
47461
|
const webwixFetch = opts.webwixFetch ?? fetch;
|
|
47244
|
-
const webwixTokens = new VisitorTokenCache(webwixFetch);
|
|
47245
47462
|
const webwixOwnerInstances = new OwnerInstanceCache(webwixFetch);
|
|
47246
47463
|
const webwixOwnerSites = new OwnerSitesCache(webwixFetch);
|
|
47247
47464
|
const webwixOwnerRungOn = () => opts.webwixOwnerRung !== false;
|
|
@@ -47543,7 +47760,7 @@ ${releaseId}`;
|
|
|
47543
47760
|
const pkce = await generatePkce();
|
|
47544
47761
|
let authUrl;
|
|
47545
47762
|
try {
|
|
47546
|
-
const visitor = await
|
|
47763
|
+
const visitor = await mintAnonymousVisitor(resolved2.config.clientId, webwixFetch);
|
|
47547
47764
|
authUrl = await hostedAuthUrl(
|
|
47548
47765
|
{ ...resolved2.config, mode: path2.endsWith("/register") ? "signup" : "login", state, challenge: pkce.challenge },
|
|
47549
47766
|
visitor,
|
|
@@ -47614,7 +47831,14 @@ ${releaseId}`;
|
|
|
47614
47831
|
const reqPath = String(call.path ?? "/");
|
|
47615
47832
|
const body = call.body === void 0 ? void 0 : typeof call.body === "string" ? call.body : JSON.stringify(call.body);
|
|
47616
47833
|
const forwardedHeaders = normalizeWixForwardedHeaders(call.headers);
|
|
47834
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(reqPath)) {
|
|
47835
|
+
return absoluteUrlRejection(reqPath) === "owner-only" ? json3(501, { error: "webwix_owner_only", app: app2 }) : json3(400, { error: "absolute_urls_not_allowed" });
|
|
47836
|
+
}
|
|
47617
47837
|
const callerCookie = request.headers.get("cookie") ?? "";
|
|
47838
|
+
if (!call.checkOwnerSession && webwixOwnerRungOn() && method === "POST" && isOwnerSitesPath(reqPath) && !/wixSession2=/.test(callerCookie)) {
|
|
47839
|
+
served.rung = "sites";
|
|
47840
|
+
return json3(501, { error: "webwix_owner_no_session", app: app2 });
|
|
47841
|
+
}
|
|
47618
47842
|
if (!call.checkOwnerSession && webwixOwnerRungOn() && method === "POST" && isOwnerSitesPath(reqPath) && /wixSession2=/.test(callerCookie)) {
|
|
47619
47843
|
served.rung = "sites";
|
|
47620
47844
|
try {
|
|
@@ -47633,32 +47857,8 @@ ${releaseId}`;
|
|
|
47633
47857
|
}
|
|
47634
47858
|
if (call.ownerMsid !== void 0) {
|
|
47635
47859
|
served.rung = call.checkOwnerSession === true ? "gate" : "owner";
|
|
47636
|
-
if (!webwixOwnerRungOn()) {
|
|
47637
|
-
|
|
47638
|
-
}
|
|
47639
|
-
const msid = String(call.ownerMsid);
|
|
47640
|
-
if (!isSafeMsid(msid)) return json3(400, { error: "webwix_owner_bad_msid" });
|
|
47641
|
-
const cookie = request.headers.get("cookie") ?? "";
|
|
47642
|
-
if (!/wixSession2=/.test(cookie)) return json3(501, { error: "webwix_owner_no_session", app: app2 });
|
|
47643
|
-
try {
|
|
47644
|
-
const instance = await webwixOwnerInstances.instance(msid, cookie);
|
|
47645
|
-
if (call.checkOwnerSession === true) return json3(200, { status: 200, body: JSON.stringify({ ready: true }) }, { "cache-control": "no-store" });
|
|
47646
|
-
const first = await wixVisitorCall(method, reqPath, body, instance, webwixFetch, forwardedHeaders);
|
|
47647
|
-
if (first.status !== 401) return json3(200, first);
|
|
47648
|
-
webwixOwnerInstances.invalidate(msid, cookie);
|
|
47649
|
-
const fresh = await webwixOwnerInstances.instance(msid, cookie);
|
|
47650
|
-
return json3(200, await wixVisitorCall(method, reqPath, body, fresh, webwixFetch, forwardedHeaders));
|
|
47651
|
-
} catch (e) {
|
|
47652
|
-
const msg = String(e?.message ?? e);
|
|
47653
|
-
if (msg.includes("absolute URLs")) {
|
|
47654
|
-
return absoluteUrlRejection(reqPath) === "owner-only" ? json3(501, { error: "webwix_owner_only", app: app2 }) : json3(400, { error: "absolute_urls_not_allowed" });
|
|
47655
|
-
}
|
|
47656
|
-
if (msg.includes("owner mint failed")) {
|
|
47657
|
-
if (/owner mint failed \(5\d\d\)/.test(msg)) return json3(502, { error: "webwix_bridge_upstream_failed" });
|
|
47658
|
-
return json3(501, { error: "webwix_owner_mint_failed", app: app2 });
|
|
47659
|
-
}
|
|
47660
|
-
return json3(502, { error: "webwix_bridge_upstream_failed", detail: msg.slice(0, 200) });
|
|
47661
|
-
}
|
|
47860
|
+
if (!webwixOwnerRungOn()) return json3(503, { error: "webwix_owner_disabled" });
|
|
47861
|
+
return json3(501, { error: "webwix_owner_direct_only", app: app2 });
|
|
47662
47862
|
}
|
|
47663
47863
|
const resolved2 = wixClientIdOf(utf8Decode(cfgBytes));
|
|
47664
47864
|
if ("error" in resolved2) {
|
|
@@ -47675,28 +47875,11 @@ ${releaseId}`;
|
|
|
47675
47875
|
try {
|
|
47676
47876
|
return json3(200, await wixVisitorCall(method, reqPath, body, memberToken, webwixFetch, forwardedHeaders), { "cache-control": "no-store" });
|
|
47677
47877
|
} catch (e) {
|
|
47678
|
-
|
|
47679
|
-
if (msg.includes("absolute URLs")) {
|
|
47680
|
-
return absoluteUrlRejection(reqPath) === "owner-only" ? json3(501, { error: "webwix_owner_only", app: app2 }) : json3(400, { error: "absolute_urls_not_allowed" });
|
|
47681
|
-
}
|
|
47682
|
-
return json3(502, { error: "webwix_bridge_upstream_failed", detail: msg.slice(0, 200) });
|
|
47878
|
+
return json3(502, { error: "webwix_bridge_upstream_failed", detail: String(e?.message ?? e).slice(0, 200) });
|
|
47683
47879
|
}
|
|
47684
47880
|
}
|
|
47685
47881
|
}
|
|
47686
|
-
|
|
47687
|
-
const token = await webwixTokens.token(resolved2.clientId);
|
|
47688
|
-
const first = await wixVisitorCall(method, reqPath, body, token, webwixFetch, forwardedHeaders);
|
|
47689
|
-
if (first.status !== 401) return json3(200, first);
|
|
47690
|
-
webwixTokens.invalidate(resolved2.clientId);
|
|
47691
|
-
const fresh = await webwixTokens.token(resolved2.clientId);
|
|
47692
|
-
return json3(200, await wixVisitorCall(method, reqPath, body, fresh, webwixFetch, forwardedHeaders));
|
|
47693
|
-
} catch (e) {
|
|
47694
|
-
const msg = String(e?.message ?? e);
|
|
47695
|
-
if (msg.includes("absolute URLs")) {
|
|
47696
|
-
return absoluteUrlRejection(reqPath) === "owner-only" ? json3(501, { error: "webwix_owner_only", app: app2 }) : json3(400, { error: "absolute_urls_not_allowed" });
|
|
47697
|
-
}
|
|
47698
|
-
return json3(502, { error: "webwix_bridge_upstream_failed", detail: msg.slice(0, 200) });
|
|
47699
|
-
}
|
|
47882
|
+
return json3(501, { error: "webwix_visitor_direct_only", app: app2 });
|
|
47700
47883
|
})();
|
|
47701
47884
|
status = res.status;
|
|
47702
47885
|
return res;
|
|
@@ -48280,7 +48463,7 @@ function indexHtml(asset, pathname, creds, handoverAttempted = false) {
|
|
|
48280
48463
|
void pathname;
|
|
48281
48464
|
const nonce = scriptNonce();
|
|
48282
48465
|
const raw = new TextDecoder().decode(assetBytes(asset));
|
|
48283
|
-
const head = `<script nonce="${nonce}">${PREVIEW_BASE_JS}</script>` + (creds ? `<script nonce="${nonce}">${previewCredentialsJs(creds)}</script>` : handoverAttempted ? `<script nonce="${nonce}">${stripHandoverParamJs()}</script>` : "");
|
|
48466
|
+
const head = `<script nonce="${nonce}">${PREVIEW_BASE_JS}</script><script nonce="${nonce}">${PREVIEW_ENTRY_RECOVERY_JS}</script>` + (creds ? `<script nonce="${nonce}">${previewCredentialsJs(creds)}</script>` : handoverAttempted ? `<script nonce="${nonce}">${stripHandoverParamJs()}</script>` : "");
|
|
48284
48467
|
const html = raw.replace(/(=|url\()(["']?)\/preview\//g, "$1$2").replace(/<head(\s[^>]*)?>/i, (tag) => `${tag}${head}`);
|
|
48285
48468
|
return new Response(html, {
|
|
48286
48469
|
status: 200,
|
|
@@ -48332,7 +48515,7 @@ function previewResponse(pathname, assets, mount = "/preview", creds, handoverAt
|
|
|
48332
48515
|
headers: { "content-type": "application/json; charset=utf-8" }
|
|
48333
48516
|
});
|
|
48334
48517
|
}
|
|
48335
|
-
var T5_FRAME_CSP, PREVIEW_BASE_JS, MOUNT_STRIP;
|
|
48518
|
+
var T5_FRAME_CSP, PREVIEW_BASE_JS, PREVIEW_ENTRY_RECOVERY_JS, MOUNT_STRIP;
|
|
48336
48519
|
var init_preview2 = __esm({
|
|
48337
48520
|
"../../packages/serve/src/preview.ts"() {
|
|
48338
48521
|
T5_FRAME_CSP = "default-src 'none'; script-src 'unsafe-inline' 'unsafe-eval'; connect-src 'none'; img-src 'none'; media-src 'none'; style-src 'unsafe-inline'; base-uri 'none'; form-action 'none'";
|
|
@@ -48341,6 +48524,7 @@ var init_preview2 = __esm({
|
|
|
48341
48524
|
// the EARLIEST mount segment wins, mirroring the SPA's own deployBase (an app literally
|
|
48342
48525
|
// named "app" — /preview/a/app — must not hijack the base).
|
|
48343
48526
|
'(function(){var m=location.pathname.match(/^(.*?\\/(?:preview|app))(?:\\/|$)/);var b=document.createElement("base");b.href=(m?m[1]:"")+"/";document.head.insertBefore(b,document.head.firstChild)})();';
|
|
48527
|
+
PREVIEW_ENTRY_RECOVERY_JS = '(function(){var K="himalaya.preview.entryReload";function show(){if(document.getElementById("himalaya-preview-load-failed"))return;var d=document.createElement("div");d.id="himalaya-preview-load-failed";d.setAttribute("role","alert");d.style.cssText="position:fixed;inset:0;z-index:2147483647;display:flex;flex-direction:column;align-items:center;justify-content:center;box-sizing:border-box;padding:32px;text-align:center;font:15px/1.5 system-ui,sans-serif;background:#f5f7fa;color:#111";var p=document.createElement("p");p.textContent="This app couldn\\u2019t load \\u2014 a new version may have just been published.";var b=document.createElement("button");b.type="button";b.textContent="Reload";b.addEventListener("click",function(){location.reload()});d.appendChild(p);d.appendChild(b);(document.body||document.documentElement).appendChild(d)}function failed(){var now=Date.now(),last=0;try{last=+sessionStorage.getItem(K)||0}catch(e){}if(now-last>60000){try{sessionStorage.setItem(K,String(now));location.reload();return}catch(e){}}if(document.body)show();else document.addEventListener("DOMContentLoaded",show)}window.addEventListener("error",function(e){var t=e&&e.target;if(t&&t.tagName==="SCRIPT"&&t.type==="module")failed()},true)})();';
|
|
48344
48528
|
MOUNT_STRIP = {
|
|
48345
48529
|
// Precompiled — this runs on every request of the public serving hot path.
|
|
48346
48530
|
"/preview": /^\/preview\/?/,
|
|
@@ -48587,21 +48771,21 @@ var init_preview_assets_generated = __esm({
|
|
|
48587
48771
|
"../../packages/serve/src/preview-assets.generated.ts"() {
|
|
48588
48772
|
init_preview_assets_format();
|
|
48589
48773
|
PREVIEW_ASSET_MANIFEST = [
|
|
48590
|
-
{ key: "assets/index-
|
|
48591
|
-
{ key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset:
|
|
48592
|
-
{ key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset:
|
|
48593
|
-
{ key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset:
|
|
48594
|
-
{ key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset:
|
|
48595
|
-
{ key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset:
|
|
48596
|
-
{ key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset:
|
|
48597
|
-
{ key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset:
|
|
48598
|
-
{ key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset:
|
|
48599
|
-
{ key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset:
|
|
48600
|
-
{ key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset:
|
|
48601
|
-
{ key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset:
|
|
48602
|
-
{ key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset:
|
|
48603
|
-
{ key: "index.html", contentType: "text/html; charset=utf-8", offset:
|
|
48604
|
-
{ key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset:
|
|
48774
|
+
{ key: "assets/index-hHpGDjBZ.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1038931, sha256: "65ef206c528bdc3e9b7ec6907e734267cd225ed33513982c46ecb3bbdd6d44ee" },
|
|
48775
|
+
{ key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 1038939, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
|
|
48776
|
+
{ key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 1043549, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
|
|
48777
|
+
{ key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1532133, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
|
|
48778
|
+
{ key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1623057, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
|
|
48779
|
+
{ key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1714041, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
|
|
48780
|
+
{ key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1805021, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
|
|
48781
|
+
{ key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1895893, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
|
|
48782
|
+
{ key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1986873, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
|
|
48783
|
+
{ key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 2095509, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
|
|
48784
|
+
{ key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 2204593, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
|
|
48785
|
+
{ key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 2313641, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
|
|
48786
|
+
{ key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 2421341, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
|
|
48787
|
+
{ key: "index.html", contentType: "text/html; charset=utf-8", offset: 2509449, length: 4947, sha256: "f07de6435f49d7608a56b7af529229f2ccc10901ab33a9e600e01f10b60975d6" },
|
|
48788
|
+
{ key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 2514396, length: 17209, sha256: "dffc9718e2faa63ae2cc919e0a842f585ed565aaaa7c53778e90379442c731b6" }
|
|
48605
48789
|
];
|
|
48606
48790
|
}
|
|
48607
48791
|
});
|
|
@@ -63412,9 +63596,10 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
|
|
|
63412
63596
|
(--ai writes rows for you to review first)
|
|
63413
63597
|
himi secrets set|list|rotate --app <app> --name <name> [--environment preview|production]
|
|
63414
63598
|
encrypted secret metadata; set/rotate read the value from stdin
|
|
63415
|
-
himi render <screenId> [--content <dir>] [--scheme dark] [--png <file>] [--tree] [--dump-state] [--static] [--live] [--state <json|file>] [--input <json|file>] [--width <px> | --device <name>] [--rtl] [--load-budget <ms>]
|
|
63599
|
+
himi render <screenId> [--content <dir>] [--scheme dark] [--png [<file>]] [--tree] [--dump-state] [--static] [--live] [--state <json|file>] [--input <json|file>] [--width <px> | --device <name>] [--rtl] [--load-budget <ms>]
|
|
63416
63600
|
[--remote --app <app> --release <id>]
|
|
63417
63601
|
headless web render + diagnostics (no sim). Default: local content dir.
|
|
63602
|
+
A bare --png writes .himi/shots/<screenId>.png (what the build board shows).
|
|
63418
63603
|
--remote fetches GET /v1/preview/\u2026/render from the serve plane (post-push).
|
|
63419
63604
|
It returns the pushed descriptor STRUCTURE only \u2014 NO png and NO live data
|
|
63420
63605
|
(the serve has no headless browser); for a pixel view or REAL fetched data
|
|
@@ -63593,7 +63778,9 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
|
|
|
63593
63778
|
plane, no dev-server. With no argument it packs the current
|
|
63594
63779
|
content package first \u2014 edit, run, look at it.
|
|
63595
63780
|
--watch rebuilds on every save and repaints the open tab
|
|
63596
|
-
(a failed build keeps the last good preview).
|
|
63781
|
+
(a failed build keeps the last good preview). The build board
|
|
63782
|
+
is served beside it at /__himi/studio/ with the preview framed
|
|
63783
|
+
in it. Blocks until Ctrl-C.
|
|
63597
63784
|
himi flags list|set|ramp|rm [<key>] [--app <a>]
|
|
63598
63785
|
read/change operational flags (RFC 0013); writes report
|
|
63599
63786
|
servedNow from the device door, never just ok
|
|
@@ -63920,7 +64107,7 @@ var COMMANDS = [
|
|
|
63920
64107
|
{ name: "ux", summary: "audit or record mobile UX evidence. `audit` checks the public-safe contract, seeded blank acceptance rows, placeholder source copy, app-specific mocks, and iOS/Android audit records. It warns while existing templates migrate; `--strict` promotes missing evidence. `record` stores checks performed on an installed iOS/Android build: `--checks` is required for passed|failed and empty for unavailable, which drove nothing and needs a `--reason` instead. `record` also STAMPS the release it audited (it resolves the id from a build, the same one a push would publish), because an unforced `himi push` of a release with screens refuses when no drive is recorded for THAT release, or when the one that is recorded says `failed` \u2014 the artifact stopped being advice nobody reads (#2955). `unavailable` still satisfies it; only `failed` refuses.", required: "audit [--content <dir>] [--strict] [--json] | record --content <dir> --platform ios|android --status passed|failed|unavailable [--checks back,keyboard,...] [--reason <text>]" },
|
|
63921
64108
|
{ name: "progress", summary: 'the build JOURNAL an agent keeps for the owner while it works. `himi progress "<what changed>" --step <1-8|name> --image <png>` appends one postcard to .himi/progress.jsonl \u2014 the step is one of the customer journey\'s eight (discover, classify, plan, implement, brand, validate, review, download) \u2014 and COPIES each image, content-addressed, into .himi/history/, because .himi/shots/ is overwritten by every render and cleared by every full `himi test`, so a path into it would later show a different picture than the one the owner was sent. --image repeats. --notify also raises a best-effort desktop notification for an owner who stepped away. A bare `himi progress` prints the journal with the current step and elapsed time \u2014 also how an agent recovers its place after its context was compacted. Local only: nothing is sent anywhere.', required: '["<message>" [--step <1-8|name>] [--image <png>]\u2026 [--notify]] [--content <dir>]' },
|
|
63922
64109
|
{ name: "studio", summary: "open the BUILD BOARD \u2014 one local page the owner can leave open while an agent builds their app, which fills itself in: every screen as it renders (NEW/CHANGED badges, and each earlier version kept for a filmstrip), the journey stepper and the latest postcard from `himi progress`, the validate/test/UX/draft checks as they run, the site next to the app's home screen with its palette, and the navigation the test crawl followed. Writes .himi/studio/index.html and opens it; the page re-reads its state every two seconds, so nothing needs to be served. OPT-IN BY EXISTENCE: until this command has run, no other command touches .himi/studio/ \u2014 after it, render/test/validate/push/icon/site/ux/progress each refresh the board as they finish (best-effort; never fails a command). Every image is a content-addressed copy in .himi/history/, never a live path into .himi/shots/. Local only, no secrets: it never reads a preview token, handover code or control token. --no-open prints the path instead (SSH, CI). `himi studio reel` writes the MAKING-OF: one self-contained HTML file (every image inlined, nothing fetched) with a flipbook of the home screen version by version, captioned by the postcard in effect at the time, the final screens, and every postcard \u2014 sized to stay attachable, thinning frames first. Defaults to .himi/making-of.html (never archived by push); --out to put it elsewhere.", required: "[--content <dir>] [--no-open] | reel [--out <file>] [--no-open]" },
|
|
63923
|
-
{ name: "render", summary: "headless-render a screen with the web renderer: render-tree + diagnostics, optional --png <file
|
|
64110
|
+
{ name: "render", summary: "headless-render a screen with the web renderer: render-tree + diagnostics, optional --png [<file>] (bare: .himi/shots/<id>.png, what the build board shows), --scheme dark, --tree. Local by default (content dir). Pass --remote --app --release to hit GET /v1/preview/\u2026/render on the serve plane after a push. Boots the worker so $service bindings resolve; --static raw bindings; --live real Wix fetches; --state injects worker state; --input supplies pre-boot navigation params; --width/--device for PNG viewport; --rtl for dir=rtl + $env:isRTL.", required: "<screenId> [--content <dir>] [--scheme dark] [--png [<file>]] [--tree] [--static] [--live] [--state <json|file>] [--input <json|file>] [--width <px> | --device <name>] [--rtl] [--remote --app --release]" },
|
|
63924
64111
|
{ name: "cms", summary: "inspect, provision, and seed the app's CMS (Wix Data) collections, declared as a `cms` block in config.ts. `query` is READ-ONLY \u2014 by default it fetches ONLY the physical ids `config.ts` declares (item counts + schema drift) and reports `siteScanned: false`; it never lists the site, so an UNDECLARED `himi_<app>_` collection this app owns is not reached without `--all`. `--all` SCANS the site \u2014 every collection it lists is labeled `owned`/`adopted`/`foreign`, and it describes every foreign one \u2014 id, non-system field keys + types, and the site's read role \u2014 so an app with no `cms` block at all can DISCOVER a collection to adopt (`--all` is the one case where a missing `cms` block is not 'nothing to do'). Foreign collections are described up to a cap and are never item-counted (`itemCount: null`), because a row count is one query each; `foreign.count` is how many the scan LISTED \u2014 it follows the list endpoint's pages, and `listingIncomplete: true` says when the walk stopped short of the end, with `unlistedCollections` counting what it left out when Wix gave a paging total \u2014 and `foreign.truncated` says how many of those went undescribed, each still NAMED in `foreign.others` (id + displayName), so a collection the site already has is never hidden behind the cap. The scan is OWNER-scoped \u2014 it needs --site <msid> (or WIX_SITE_ID) plus owner auth via `wix token`; a visitor token can read a public collection's ITEMS but can never enumerate collections, so there is no tokenless discovery path. `create` reconciles declared collections additively and idempotently, and REFUSES any id outside the app's `himi_<app>_` namespace, so it is safe against a production site. It reports declared-vs-site `permissionDrift` but never writes permissions unless asked with --apply-permissions, so a field reconcile can't silently revert access control changed in the dashboard. `seed` inserts the git-tracked `seed:` rows into EMPTY owned collections (--force to add to a non-empty one; --ai writes placeholder rows plus a refinement prompt for you to review). Adopted collections (declared by `wixId`) are read-only and never created, updated, or seeded. Site from --site <msid> or WIX_SITE_ID; owner auth via `wix token`.", required: "query|create|seed [--site <msid>] [--content <dir>] [--all] [--dry-run] [--force] [--allow-destructive] [--apply-permissions] [--only <id>] [--ai] [--count <n>]" },
|
|
63925
64112
|
{ name: "data", summary: "read-only plan or explicitly provision/seed declared KV and Wix Data resources. Preview and production are separate scopes. KV administration uses the operator data plane from --data-url/HIMI_DATA_ADMIN_URL and HIMI_DATA_ADMIN_TOKEN; draft push never calls it.", required: "plan|create|seed [--site <msid>] [--environment preview|production] [--content <dir>] [--data-url <url>] [--dry-run] [--force]" },
|
|
63926
64113
|
{ name: "icons", summary: "list the valid Icon.name vocabulary (an unknown name renders a fallback glyph; validate warns on unknown names) (offline)", required: "[--json]" },
|
|
@@ -68447,7 +68634,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68447
68634
|
current = fresh;
|
|
68448
68635
|
servedMissing = outcome.missingBundles;
|
|
68449
68636
|
for (const [event, data] of watchKit.reloadEvents(diff)) bus.publish(event, data);
|
|
68450
|
-
record2(running, { ok: true, at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
68637
|
+
record2(running, { ok: true, at: (/* @__PURE__ */ new Date()).toISOString(), ms: Date.now() - t0, screens: diff.screens, tokens: diff.tokens, config: diff.config });
|
|
68451
68638
|
await refreshBoard();
|
|
68452
68639
|
io.error(JSON.stringify({ watch: "rebuilt", ms: Date.now() - t0, screens: diff.screens, tokens: diff.tokens, config: diff.config, tabs: bus.listeners }));
|
|
68453
68640
|
} catch (e) {
|