@wix/himalaya-cli 0.1026.0 → 0.1028.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/builder.d.ts +9 -0
- package/dist/cli.mjs +1128 -666
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/app-config.md +6 -0
- package/guides/headless-loop.md +3 -1
- package/package.json +2 -2
- package/templates/beauty-salon/dev/index.ts +331 -199
- package/templates/beauty-salon/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/beauty-salon/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/beauty-salon-owner/dev/index.ts +857 -458
- package/templates/beauty-salon-owner/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/beauty-salon-owner/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/branded-lite/dev/index.ts +1539 -623
- package/templates/branded-lite/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/branded-lite/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/community-club/dev/index.ts +237 -142
- package/templates/community-club/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/community-club/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/community-club-owner/dev/index.ts +857 -458
- package/templates/community-club-owner/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/community-club-owner/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/events-meetups/dev/index.ts +202 -129
- package/templates/events-meetups/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/events-meetups/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/events-meetups-owner/dev/index.ts +815 -458
- package/templates/events-meetups-owner/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/events-meetups-owner/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/gym-fitness/dev/index.ts +461 -212
- package/templates/gym-fitness/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/gym-fitness/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/gym-fitness-owner/dev/index.ts +758 -338
- package/templates/gym-fitness-owner/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/gym-fitness-owner/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/himi-chat/dev/index.ts +26 -1
- package/templates/nonprofit-cause/dev/index.ts +246 -153
- package/templates/nonprofit-cause/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/nonprofit-cause/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/nonprofit-cause-owner/dev/index.ts +716 -338
- package/templates/nonprofit-cause-owner/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/nonprofit-cause-owner/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/owner-lite/dev/index.ts +758 -338
- package/templates/owner-lite/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/owner-lite/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/podcast-creator/dev/index.ts +255 -164
- package/templates/podcast-creator/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/podcast-creator/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/podcast-creator-owner/dev/index.ts +857 -458
- package/templates/podcast-creator-owner/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/podcast-creator-owner/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/portfolio-creative/dev/index.ts +287 -175
- package/templates/portfolio-creative/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/portfolio-creative/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/portfolio-creative-owner/dev/index.ts +857 -458
- package/templates/portfolio-creative-owner/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/portfolio-creative-owner/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/restaurant/dev/index.ts +200 -126
- package/templates/restaurant/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/restaurant/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/restaurant-owner/dev/index.ts +758 -338
- package/templates/restaurant-owner/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/restaurant-owner/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/retail-store/dev/index.ts +113 -138
- package/templates/retail-store/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/retail-store/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/retail-store-owner/dev/index.ts +716 -338
- package/templates/retail-store-owner/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/retail-store-owner/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/surface-showcase/dev/index.ts +27 -0
- package/templates/yoga-studio/dev/index.ts +427 -198
- package/templates/yoga-studio/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/yoga-studio/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/yoga-studio-owner/dev/index.ts +716 -338
- package/templates/yoga-studio-owner/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/yoga-studio-owner/tier5-src/_shared/collection-service.ts +28 -3
package/dist/cli.mjs
CHANGED
|
@@ -5351,7 +5351,6 @@ function walk(node, registry, path2, out) {
|
|
|
5351
5351
|
var SYSTEM_FONT_FAMILY, TONAL_ELEVATION_ALPHA;
|
|
5352
5352
|
var init_tokens = __esm({
|
|
5353
5353
|
"../../core/ts/src/tokens.ts"() {
|
|
5354
|
-
"use strict";
|
|
5355
5354
|
SYSTEM_FONT_FAMILY = "$system";
|
|
5356
5355
|
TONAL_ELEVATION_ALPHA = [0, 0.05, 0.08, 0.11, 0.12, 0.14];
|
|
5357
5356
|
}
|
|
@@ -5378,7 +5377,6 @@ function resolveTranslation(value, catalog, sourceCatalog) {
|
|
|
5378
5377
|
var BINDING_SIGILS, BINDING_SIGIL_RE, TRANSLATION_PREFIX, TRANSLATION_KEY_RE;
|
|
5379
5378
|
var init_bindings = __esm({
|
|
5380
5379
|
"../../core/ts/src/bindings.ts"() {
|
|
5381
|
-
"use strict";
|
|
5382
5380
|
BINDING_SIGILS = ["service", "flag", "item", "t"];
|
|
5383
5381
|
BINDING_SIGIL_RE = new RegExp(
|
|
5384
5382
|
`^\\$(?:${BINDING_SIGILS.filter((s) => s !== "t").join("|")})\\b|^\\$t:`
|
|
@@ -22580,6 +22578,40 @@ var init_icons = __esm({
|
|
|
22580
22578
|
}
|
|
22581
22579
|
});
|
|
22582
22580
|
|
|
22581
|
+
// ../../core/web-renderer/src/webviewFrame.ts
|
|
22582
|
+
function currentOrigin() {
|
|
22583
|
+
try {
|
|
22584
|
+
const origin = typeof window !== "undefined" ? window.location?.origin : void 0;
|
|
22585
|
+
return origin && origin !== "null" ? origin : null;
|
|
22586
|
+
} catch {
|
|
22587
|
+
return null;
|
|
22588
|
+
}
|
|
22589
|
+
}
|
|
22590
|
+
function webviewFrameSandbox(url, grants2 = [], pageOrigin = currentOrigin()) {
|
|
22591
|
+
const parsed = url.replace(/^[\u0000-\u0020]+|[\u0000-\u0020]+$/g, "").replace(/[\t\n\r]/g, "");
|
|
22592
|
+
const absolute = /^[a-z][a-z0-9+.-]*:/i.test(parsed);
|
|
22593
|
+
let target;
|
|
22594
|
+
try {
|
|
22595
|
+
target = new URL(parsed, pageOrigin ?? "http://relative.invalid");
|
|
22596
|
+
} catch {
|
|
22597
|
+
return null;
|
|
22598
|
+
}
|
|
22599
|
+
if (!NETWORK_SCHEMES.has(target.protocol)) return null;
|
|
22600
|
+
const crossOrigin = pageOrigin !== null && absolute && target.origin !== pageOrigin;
|
|
22601
|
+
const tokens = ["allow-scripts", ...grants2.filter((g) => g !== "allow-scripts" && g !== "allow-same-origin")];
|
|
22602
|
+
if (crossOrigin) tokens.splice(1, 0, "allow-same-origin");
|
|
22603
|
+
return { src: crossOrigin ? target.href : url, sandbox: tokens.join(" ") };
|
|
22604
|
+
}
|
|
22605
|
+
function isWebviewUrlAllowed(url) {
|
|
22606
|
+
return webviewFrameSandbox(url, [], null) !== null;
|
|
22607
|
+
}
|
|
22608
|
+
var NETWORK_SCHEMES;
|
|
22609
|
+
var init_webviewFrame = __esm({
|
|
22610
|
+
"../../core/web-renderer/src/webviewFrame.ts"() {
|
|
22611
|
+
NETWORK_SCHEMES = /* @__PURE__ */ new Set(["http:", "https:"]);
|
|
22612
|
+
}
|
|
22613
|
+
});
|
|
22614
|
+
|
|
22583
22615
|
// ../../core/web-renderer/src/a11y/controls.tsx
|
|
22584
22616
|
import React3 from "react";
|
|
22585
22617
|
import { jsx as jsx4, jsxs } from "react/jsx-runtime";
|
|
@@ -22907,6 +22939,65 @@ var init_controls = __esm({
|
|
|
22907
22939
|
}
|
|
22908
22940
|
});
|
|
22909
22941
|
|
|
22942
|
+
// ../../core/web-renderer/src/a11y/modalStack.ts
|
|
22943
|
+
function pushModalLayer(el) {
|
|
22944
|
+
const layer = { el: typeof el === "function" ? el : () => el };
|
|
22945
|
+
layers.push(layer);
|
|
22946
|
+
sync();
|
|
22947
|
+
return {
|
|
22948
|
+
isTop: () => layers[layers.length - 1] === layer,
|
|
22949
|
+
release: () => {
|
|
22950
|
+
const i = layers.indexOf(layer);
|
|
22951
|
+
if (i < 0) return;
|
|
22952
|
+
layers.splice(i, 1);
|
|
22953
|
+
sync();
|
|
22954
|
+
}
|
|
22955
|
+
};
|
|
22956
|
+
}
|
|
22957
|
+
function topElement() {
|
|
22958
|
+
for (let i = layers.length - 1; i >= 0; i--) {
|
|
22959
|
+
const el = layers[i].el();
|
|
22960
|
+
if (el?.isConnected) return el;
|
|
22961
|
+
}
|
|
22962
|
+
return null;
|
|
22963
|
+
}
|
|
22964
|
+
function sync() {
|
|
22965
|
+
watcher?.disconnect();
|
|
22966
|
+
watcher = null;
|
|
22967
|
+
for (const el of madeInert) el.removeAttribute("inert");
|
|
22968
|
+
madeInert.clear();
|
|
22969
|
+
const top = topElement();
|
|
22970
|
+
if (!top) return;
|
|
22971
|
+
const scope = top.parentElement?.closest(`[${MODAL_SCOPE_ATTR}]`) ?? top.ownerDocument.body;
|
|
22972
|
+
const levels = [];
|
|
22973
|
+
let node = top;
|
|
22974
|
+
while (node !== scope && node.parentElement) {
|
|
22975
|
+
const parent = node.parentElement;
|
|
22976
|
+
levels.push(parent);
|
|
22977
|
+
for (const sibling of Array.from(parent.children)) {
|
|
22978
|
+
if (sibling === node || SKIP.has(sibling.tagName) || sibling.hasAttribute("inert")) continue;
|
|
22979
|
+
sibling.setAttribute("inert", "");
|
|
22980
|
+
madeInert.add(sibling);
|
|
22981
|
+
}
|
|
22982
|
+
node = parent;
|
|
22983
|
+
}
|
|
22984
|
+
const Observer = top.ownerDocument.defaultView?.MutationObserver;
|
|
22985
|
+
if (Observer && levels.length) {
|
|
22986
|
+
watcher = new Observer(() => sync());
|
|
22987
|
+
for (const level of levels) watcher.observe(level, { childList: true });
|
|
22988
|
+
}
|
|
22989
|
+
}
|
|
22990
|
+
var MODAL_SCOPE_ATTR, SKIP, layers, madeInert, watcher;
|
|
22991
|
+
var init_modalStack = __esm({
|
|
22992
|
+
"../../core/web-renderer/src/a11y/modalStack.ts"() {
|
|
22993
|
+
MODAL_SCOPE_ATTR = "data-himi-modal-scope";
|
|
22994
|
+
SKIP = /* @__PURE__ */ new Set(["SCRIPT", "STYLE", "LINK", "META", "TEMPLATE", "NOSCRIPT", "HEAD"]);
|
|
22995
|
+
layers = [];
|
|
22996
|
+
madeInert = /* @__PURE__ */ new Set();
|
|
22997
|
+
watcher = null;
|
|
22998
|
+
}
|
|
22999
|
+
});
|
|
23000
|
+
|
|
22910
23001
|
// ../../core/web-renderer/src/listGestures.tsx
|
|
22911
23002
|
import { useRef, useState as useState2 } from "react";
|
|
22912
23003
|
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
@@ -24158,8 +24249,8 @@ function autoGrowBox(contentHeight, lineHeight, verticalPadding, maxLines) {
|
|
|
24158
24249
|
const cap = Math.max(floor, lineHeight * lines + verticalPadding);
|
|
24159
24250
|
return { height: Math.max(floor, Math.min(contentHeight, cap)), scrolls: contentHeight > cap };
|
|
24160
24251
|
}
|
|
24161
|
-
function wrapModalMenu(modal, label2, placement, menu) {
|
|
24162
|
-
return modal ? /* @__PURE__ */ jsx6("div", { role: "dialog", "aria-modal": "true", "aria-label": label2, style: placement, children: menu }) : menu;
|
|
24252
|
+
function wrapModalMenu(modal, label2, placement, ref, menu) {
|
|
24253
|
+
return modal ? /* @__PURE__ */ jsx6("div", { ref, role: "dialog", "aria-modal": "true", "aria-label": label2, style: placement, children: menu }) : menu;
|
|
24163
24254
|
}
|
|
24164
24255
|
function bindMediaSlot(value, sessionId) {
|
|
24165
24256
|
if (typeof value === "string") {
|
|
@@ -24263,9 +24354,10 @@ function withExtras(name, render) {
|
|
|
24263
24354
|
const additive = addIntrinsicPadding(el.props.style, wrap ?? {});
|
|
24264
24355
|
const inferredDecorative = el.props[INFERRED_DECORATIVE] === true;
|
|
24265
24356
|
const iconGlyph2 = el.props[ICON_GLYPH] === true;
|
|
24357
|
+
const roleWhenNamed = el.props[ROLE_WHEN_NAMED];
|
|
24266
24358
|
if (!Object.keys(pass).length) {
|
|
24267
|
-
if (inferredDecorative || iconGlyph2) {
|
|
24268
|
-
return React5.cloneElement(el, { [INFERRED_DECORATIVE]: void 0, [ICON_GLYPH]: void 0, ...additive ? { style: additive } : {} });
|
|
24359
|
+
if (inferredDecorative || iconGlyph2 || roleWhenNamed != null) {
|
|
24360
|
+
return React5.cloneElement(el, { [INFERRED_DECORATIVE]: void 0, [ICON_GLYPH]: void 0, [ROLE_WHEN_NAMED]: void 0, ...additive ? { style: additive } : {} });
|
|
24269
24361
|
}
|
|
24270
24362
|
return additive ? React5.cloneElement(el, { style: additive }) : /* @__PURE__ */ jsx6(Fragment3, { children: el });
|
|
24271
24363
|
}
|
|
@@ -24277,6 +24369,14 @@ function withExtras(name, render) {
|
|
|
24277
24369
|
const nodeSpeaksForItself = pass["aria-label"] != null || passRole != null && passRole !== "presentation" && passRole !== "none" || typeof pass.onClick === "function" || typeof pass.onDoubleClick === "function";
|
|
24278
24370
|
if (pass["aria-hidden"] == null && nodeSpeaksForItself) next["aria-hidden"] = void 0;
|
|
24279
24371
|
}
|
|
24372
|
+
if (roleWhenNamed != null) {
|
|
24373
|
+
next[ROLE_WHEN_NAMED] = void 0;
|
|
24374
|
+
const isControl = typeof pass.onClick === "function" || typeof pass.onDoubleClick === "function";
|
|
24375
|
+
const roleAuthored = pass[AUTHORED_ROLE] === true;
|
|
24376
|
+
if (typeof roleWhenNamed === "string" && pass["aria-label"] != null && pass.role == null && prev.role == null && !isControl && !roleAuthored) {
|
|
24377
|
+
next.role = roleWhenNamed;
|
|
24378
|
+
}
|
|
24379
|
+
}
|
|
24280
24380
|
if (iconGlyph2) {
|
|
24281
24381
|
next[ICON_GLYPH] = void 0;
|
|
24282
24382
|
if (pass.role === "presentation" && typeof pass.onClick !== "function" && typeof pass.onDoubleClick !== "function") {
|
|
@@ -24290,6 +24390,7 @@ function withExtras(name, render) {
|
|
|
24290
24390
|
delete next[SYNTHETIC_TAP_ROLE];
|
|
24291
24391
|
const tabIndexIsSynthetic = next[SYNTHETIC_TABINDEX] === true;
|
|
24292
24392
|
delete next[SYNTHETIC_TABINDEX];
|
|
24393
|
+
delete next[AUTHORED_ROLE];
|
|
24293
24394
|
if (additive) next.style = additive;
|
|
24294
24395
|
const ownsInteractiveSemantics = isNativeInteractiveElement(el) || hasInteractiveReactDescendant(el);
|
|
24295
24396
|
if (ownsInteractiveSemantics) {
|
|
@@ -24774,8 +24875,36 @@ function ensureInitialFocusRuntime() {
|
|
|
24774
24875
|
restoreFocusOnDismiss(presentedScope, active);
|
|
24775
24876
|
}
|
|
24776
24877
|
el.focus();
|
|
24878
|
+
if (document.activeElement === el) enterAuthoredOrderOnTab(el);
|
|
24879
|
+
}
|
|
24880
|
+
}, 0);
|
|
24881
|
+
}
|
|
24882
|
+
function enterAuthoredOrderOnTab(target) {
|
|
24883
|
+
const doc = target.ownerDocument;
|
|
24884
|
+
const scope = target.closest(PRESENTED_SCOPE);
|
|
24885
|
+
const root = scope ?? doc;
|
|
24886
|
+
const onKeyDown = (e) => {
|
|
24887
|
+
if (e.key !== "Tab" || e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.defaultPrevented || e.target !== target) return;
|
|
24888
|
+
if (target.tabIndex > 0) return;
|
|
24889
|
+
const ordered = Array.from(root.querySelectorAll("[tabindex]")).filter((c) => c.tabIndex > 0 && c.closest(PRESENTED_SCOPE) === scope).sort((a, b) => a.tabIndex - b.tabIndex);
|
|
24890
|
+
for (const c of ordered) {
|
|
24891
|
+
c.focus();
|
|
24892
|
+
if (doc.activeElement === c) {
|
|
24893
|
+
e.preventDefault();
|
|
24894
|
+
e.stopPropagation();
|
|
24895
|
+
return;
|
|
24896
|
+
}
|
|
24777
24897
|
}
|
|
24898
|
+
};
|
|
24899
|
+
const onBlur = () => setTimeout(() => {
|
|
24900
|
+
if (doc.activeElement !== target) disarm();
|
|
24778
24901
|
}, 0);
|
|
24902
|
+
const disarm = () => {
|
|
24903
|
+
target.removeEventListener("keydown", onKeyDown);
|
|
24904
|
+
target.removeEventListener("blur", onBlur);
|
|
24905
|
+
};
|
|
24906
|
+
target.addEventListener("keydown", onKeyDown);
|
|
24907
|
+
target.addEventListener("blur", onBlur);
|
|
24779
24908
|
}
|
|
24780
24909
|
function ariaModal(modal, dflt) {
|
|
24781
24910
|
const on3 = modal === true || modal === false ? modal : dflt;
|
|
@@ -24810,6 +24939,7 @@ function applyA11ySemantics(node, ctx, extra) {
|
|
|
24810
24939
|
if (typeof headingLevel === "number" && headingLevel >= 1 && headingLevel <= 6) {
|
|
24811
24940
|
extra["aria-level"] = String(headingLevel);
|
|
24812
24941
|
}
|
|
24942
|
+
if (role != null && Object.prototype.hasOwnProperty.call(ARIA_ROLE, role)) extra[AUTHORED_ROLE] = true;
|
|
24813
24943
|
const hint = str7(m.accessibilityHint ?? m.accessibility_hint);
|
|
24814
24944
|
const value = str7(m.accessibilityValue ?? m.accessibility_value);
|
|
24815
24945
|
if (value) extra["aria-valuetext"] = value;
|
|
@@ -25005,7 +25135,10 @@ function renderNodeInner(node, ctx) {
|
|
|
25005
25135
|
if (composed) extra.style = composed;
|
|
25006
25136
|
}
|
|
25007
25137
|
}
|
|
25008
|
-
if (typeof el.type === "string")
|
|
25138
|
+
if (typeof el.type === "string") {
|
|
25139
|
+
delete extra[SYNTHETIC_TABINDEX];
|
|
25140
|
+
delete extra[AUTHORED_ROLE];
|
|
25141
|
+
}
|
|
25009
25142
|
let out = Object.keys(extra).length ? React5.cloneElement(el, extra) : el;
|
|
25010
25143
|
if (a11yHint) {
|
|
25011
25144
|
out = /* @__PURE__ */ jsx6(A11yHintDescription, { hint: a11yHint, idBase: componentId, children: out });
|
|
@@ -25726,7 +25859,7 @@ function renderInner(node, ctx) {
|
|
|
25726
25859
|
}
|
|
25727
25860
|
}
|
|
25728
25861
|
}
|
|
25729
|
-
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;
|
|
25862
|
+
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, ROLE_WHEN_NAMED, AUTHORED_ROLE, 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;
|
|
25730
25863
|
var init_renderNode = __esm({
|
|
25731
25864
|
"../../core/web-renderer/src/renderNode.tsx"() {
|
|
25732
25865
|
"use strict";
|
|
@@ -25743,8 +25876,10 @@ var init_renderNode = __esm({
|
|
|
25743
25876
|
init_env();
|
|
25744
25877
|
init_actionParams();
|
|
25745
25878
|
init_icons();
|
|
25879
|
+
init_webviewFrame();
|
|
25746
25880
|
init_icon_catalog_generated();
|
|
25747
25881
|
init_controls();
|
|
25882
|
+
init_modalStack();
|
|
25748
25883
|
init_listGestures();
|
|
25749
25884
|
init_worker_subtree();
|
|
25750
25885
|
init_preview_surfaces();
|
|
@@ -26275,6 +26410,7 @@ var init_renderNode = __esm({
|
|
|
26275
26410
|
const popupPlacement = { position: "absolute", top: "100%", right: 0, zIndex: 20, marginTop: 4 };
|
|
26276
26411
|
const anchorRef = React5.useRef(null);
|
|
26277
26412
|
const menuRef = React5.useRef(null);
|
|
26413
|
+
const dialogRef = React5.useRef(null);
|
|
26278
26414
|
const itemsKey = items.map((it, i) => `${it?.id ?? i}:${it?.disabled ? 0 : 1}`).join("|");
|
|
26279
26415
|
React5.useEffect(() => {
|
|
26280
26416
|
if (!open || !modal) return;
|
|
@@ -26284,7 +26420,9 @@ var init_renderNode = __esm({
|
|
|
26284
26420
|
}, [open, modal, itemsKey]);
|
|
26285
26421
|
React5.useEffect(() => {
|
|
26286
26422
|
if (!open || !modal) return;
|
|
26423
|
+
const layer = pushModalLayer(() => dialogRef.current);
|
|
26287
26424
|
return () => {
|
|
26425
|
+
layer.release();
|
|
26288
26426
|
const active = document.activeElement;
|
|
26289
26427
|
if (active == null || active === document.body || !document.contains(active)) anchorRef.current?.focus();
|
|
26290
26428
|
};
|
|
@@ -26322,11 +26460,11 @@ var init_renderNode = __esm({
|
|
|
26322
26460
|
setOpen((v) => !v);
|
|
26323
26461
|
}
|
|
26324
26462
|
},
|
|
26325
|
-
style: { display: "inline-flex", alignItems: "center", cursor: "pointer" },
|
|
26463
|
+
style: { display: "inline-flex", alignItems: "center", justifyContent: "center", minWidth: 44, minHeight: 44, cursor: "pointer" },
|
|
26326
26464
|
children: props.anchor ? renderNode(props.anchor, ctx) : iconSvg("more", { size: 20, color: C("textSecondary", "#636b78") })
|
|
26327
26465
|
}
|
|
26328
26466
|
),
|
|
26329
|
-
open && wrapModalMenu(modal, anchorLabel, popupPlacement, /* @__PURE__ */ jsx6(
|
|
26467
|
+
open && wrapModalMenu(modal, anchorLabel, popupPlacement, dialogRef, /* @__PURE__ */ jsx6(
|
|
26330
26468
|
"div",
|
|
26331
26469
|
{
|
|
26332
26470
|
ref: menuRef,
|
|
@@ -26958,13 +27096,14 @@ var init_renderNode = __esm({
|
|
|
26958
27096
|
const inlineHtml = props.inlineHtml != null && isBinding(props.inlineHtml) ? boundHtml : props.inlineHtml;
|
|
26959
27097
|
const urlStr = typeof url === "string" && url.length > 0 && !isBinding(url) ? url : void 0;
|
|
26960
27098
|
const htmlStr = typeof inlineHtml === "string" && inlineHtml.length > 0 && !isBinding(inlineHtml) ? inlineHtml : void 0;
|
|
27099
|
+
const urlFrame = urlStr ? webviewFrameSandbox(urlStr) : null;
|
|
26961
27100
|
const h = typeof props.height === "number" && props.height > 0 ? props.height : void 0;
|
|
26962
27101
|
const ar = typeof props.aspectRatio === "number" && props.aspectRatio > 0 ? props.aspectRatio : void 0;
|
|
26963
27102
|
const frameStyle = { width: "100%", boxSizing: "border-box", border: "none", borderRadius: ctx.radius("md", 8), background: "#fff", ...h ? { height: h } : ar ? { aspectRatio: String(ar) } : { height: 200 } };
|
|
26964
27103
|
const bandColor = typeof props.coverBandColor === "string" && props.coverBandColor.length > 0 ? props.coverBandColor : void 0;
|
|
26965
27104
|
return /* @__PURE__ */ jsxs3("div", { style: { width: "100%", position: "relative", ...bandColor ? { background: bandColor, borderRadius: ctx.radius("md", 8), overflow: "hidden" } : {}, ...wrap }, children: [
|
|
26966
27105
|
bandColor ? /* @__PURE__ */ jsx6("div", { "data-testid": "webview-cover-band", style: { height: 8, background: bandColor } }) : null,
|
|
26967
|
-
htmlStr ? /* @__PURE__ */ jsx6("iframe", { title: "webview", srcDoc: htmlStr, sandbox: "allow-scripts", style: frameStyle }) :
|
|
27106
|
+
htmlStr ? /* @__PURE__ */ jsx6("iframe", { title: "webview", srcDoc: htmlStr, sandbox: "allow-scripts", style: frameStyle }) : urlFrame ? /* @__PURE__ */ jsx6("iframe", { title: "webview", src: urlFrame.src, sandbox: urlFrame.sandbox, style: frameStyle }) : /* @__PURE__ */ jsx6("div", { style: { ...frameStyle, display: "grid", placeItems: "center", color: "#999", fontFamily: "ui-monospace, monospace", fontSize: 11, border: "1px dashed #ccc" }, children: urlStr ? "WebView (url not allowed)" : "WebView (no url)" })
|
|
26968
27107
|
] });
|
|
26969
27108
|
});
|
|
26970
27109
|
InteractivePicker = withExtras("InteractivePicker", ({ props, ctx, wrap }) => {
|
|
@@ -27242,6 +27381,8 @@ var init_renderNode = __esm({
|
|
|
27242
27381
|
SYNTHETIC_TABINDEX = "data-hm-synthetic-tabindex";
|
|
27243
27382
|
INFERRED_DECORATIVE = "data-hm-inferred-decorative";
|
|
27244
27383
|
ICON_GLYPH = "data-hm-icon-glyph";
|
|
27384
|
+
ROLE_WHEN_NAMED = "data-hm-role-when-named";
|
|
27385
|
+
AUTHORED_ROLE = "data-hm-authored-role";
|
|
27245
27386
|
INTERACTIVE_ROLES = /* @__PURE__ */ new Set([
|
|
27246
27387
|
"button",
|
|
27247
27388
|
"checkbox",
|
|
@@ -27388,7 +27529,7 @@ var init_renderNode = __esm({
|
|
|
27388
27529
|
const tAlign = props.textAlign === "center" ? "center" : props.textAlign === "trailing" ? "right" : props.textAlign === "justify" ? "justify" : props.textAlign === "leading" ? "left" : void 0;
|
|
27389
27530
|
const tDecor = props.decoration === "strikethrough" ? "line-through" : props.decoration === "underline" ? "underline" : void 0;
|
|
27390
27531
|
const ln = typeof props.lineSpacing === "number" ? pxToRem((f.line ?? 1.4) * f.size + props.lineSpacing) : f.line;
|
|
27391
|
-
return /* @__PURE__ */ jsx6("div", { ...countAttrs, style: { fontFamily: fontStack(f.family, ctx.idiom), fontSize: f.remSize, fontWeight: f.weight, lineHeight: ln, letterSpacing: f.letterSpacing, color: C(resolveScalarStatic(props.color, ctx) ?? "textPrimary", "#13171e"), whiteSpace: "pre-wrap", overflowWrap: "anywhere", wordBreak: "break-word", minWidth: 0, ...tAlign ? { textAlign: tAlign } : {}, ...tDecor ? { textDecoration: tDecor } : {}, ...props.maxLines ? { display: "-webkit-box", WebkitLineClamp: props.maxLines, WebkitBoxOrient: "vertical", overflow: "hidden" } : {}, ...wrap }, children: content == null || content === "" ? collapse ? null : "\xA0" : content });
|
|
27532
|
+
return /* @__PURE__ */ jsx6("div", { ...countAttrs, style: { fontFamily: fontStack(f.family, ctx.idiom), fontSize: f.remSize, fontWeight: f.weight, lineHeight: ln, letterSpacing: f.letterSpacing, color: C(resolveScalarStatic(props.color, ctx) ?? "textPrimary", "#13171e"), whiteSpace: props.maxLines === 1 ? "nowrap" : "pre-wrap", overflowWrap: "anywhere", wordBreak: "break-word", minWidth: 0, ...tAlign ? { textAlign: tAlign } : {}, ...tDecor ? { textDecoration: tDecor } : {}, ...props.maxLines === 1 ? { overflow: "hidden", textOverflow: "ellipsis" } : props.maxLines ? { display: "-webkit-box", WebkitLineClamp: props.maxLines, WebkitBoxOrient: "vertical", overflow: "hidden" } : {}, ...wrap }, children: content == null || content === "" ? collapse ? null : "\xA0" : content });
|
|
27392
27533
|
});
|
|
27393
27534
|
ImageNode = withExtras("ImageNode", ({ props, ctx, wrap }) => {
|
|
27394
27535
|
const C = ctx.color;
|
|
@@ -27449,7 +27590,7 @@ var init_renderNode = __esm({
|
|
|
27449
27590
|
const iconName = isBinding(props.name) ? String(bound ?? "") : props.name;
|
|
27450
27591
|
const contentDescription = useResolvedScalar(props.contentDescription, ctx);
|
|
27451
27592
|
const described = contentDescription != null && String(contentDescription).trim() !== "";
|
|
27452
|
-
const a11y = described ? { role: "img", "aria-label": String(contentDescription), [ICON_GLYPH]: true } : { "aria-hidden": "true", [INFERRED_DECORATIVE]: true, [ICON_GLYPH]: true };
|
|
27593
|
+
const a11y = described ? { role: "img", "aria-label": String(contentDescription), [ICON_GLYPH]: true } : { "aria-hidden": "true", [INFERRED_DECORATIVE]: true, [ICON_GLYPH]: true, [ROLE_WHEN_NAMED]: "img" };
|
|
27453
27594
|
return /* @__PURE__ */ jsx6("span", { ...a11y, style: { display: "inline-grid", placeItems: "center", width: size + 6, height: size + 6, lineHeight: 1, flex: "none", ...wrap }, children: iconSvg(iconName, { size, color: C(resolveScalarStatic(props.tint, ctx) ?? "textPrimary", "#636b78") }) });
|
|
27454
27595
|
});
|
|
27455
27596
|
ButtonNode = withExtras("ButtonNode", ({ props, ctx, wrap }) => {
|
|
@@ -27585,11 +27726,13 @@ var init_renderNode = __esm({
|
|
|
27585
27726
|
const thick = Math.max(3, Math.round(size / 8));
|
|
27586
27727
|
const bound = useResolvedScalar(props.valuePath, ctx);
|
|
27587
27728
|
const aiRaw = props.valuePath != null ? bound : props.value;
|
|
27588
|
-
const
|
|
27729
|
+
const aiNum = typeof aiRaw === "number" ? aiRaw : typeof aiRaw === "string" && aiRaw.trim() !== "" ? Number(aiRaw) : void 0;
|
|
27730
|
+
const determinate = !props.indeterminate && aiNum !== void 0 && Number.isFinite(aiNum);
|
|
27589
27731
|
if (determinate) {
|
|
27590
|
-
const pct = Math.max(0, Math.min(1,
|
|
27732
|
+
const pct = Math.max(0, Math.min(1, aiNum));
|
|
27591
27733
|
const ringMask = `radial-gradient(farthest-side, transparent calc(100% - ${thick}px), #000 calc(100% - ${thick}px))`;
|
|
27592
|
-
|
|
27734
|
+
const a11y = { "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": Math.round(pct * 100) };
|
|
27735
|
+
return /* @__PURE__ */ jsx6("div", { role: "progressbar", ...a11y, style: { width: size, height: size, borderRadius: "50%", flex: "none", background: `conic-gradient(${tint} ${pct * 360}deg, ${track} 0deg)`, WebkitMask: ringMask, mask: ringMask, ...wrap } });
|
|
27593
27736
|
}
|
|
27594
27737
|
ensureSpinKeyframes();
|
|
27595
27738
|
return /* @__PURE__ */ jsx6("div", { role: "progressbar", style: { width: size, height: size, borderRadius: "50%", border: `${thick}px solid ${track}`, borderTopColor: tint, boxSizing: "border-box", flex: "none", animation: ctx.empty ? void 0 : "himalaya-spin 0.8s linear infinite", ...wrap } });
|
|
@@ -28264,18 +28407,23 @@ var init_renderNode = __esm({
|
|
|
28264
28407
|
const next = multiSelect ? isSel ? selected.filter((x) => x !== id) : [...selected, id] : isSel ? [] : [id];
|
|
28265
28408
|
ctx.onAction({ ...onChange, args: { ...onChange.args ?? {}, selectedIds: next } });
|
|
28266
28409
|
};
|
|
28267
|
-
return
|
|
28268
|
-
|
|
28269
|
-
|
|
28270
|
-
|
|
28271
|
-
|
|
28272
|
-
|
|
28273
|
-
|
|
28274
|
-
|
|
28275
|
-
|
|
28276
|
-
|
|
28277
|
-
|
|
28278
|
-
|
|
28410
|
+
return (
|
|
28411
|
+
// ONE horizontally scrolling row, like the iOS ScrollView(.horizontal) and the
|
|
28412
|
+
// Android LazyRow. Wrapping here turned a long filter set into a ragged grid and
|
|
28413
|
+
// pushed a sibling count onto two lines (#3080, #3004).
|
|
28414
|
+
/* @__PURE__ */ jsx6("div", { role: "group", style: { display: "flex", gap: 8, flexWrap: "nowrap", overflowX: "auto", scrollbarWidth: "none", width: "100%", minWidth: 0, ...wrap }, children: chips.map((c, i) => {
|
|
28415
|
+
const on3 = selected.includes(c.id);
|
|
28416
|
+
const chipStyle = { display: "flex", flex: "none", whiteSpace: "nowrap", gap: 6, alignItems: "center", fontFamily: bodyFont(ctx), fontWeight: 500, fontSize: 13, border: `1px solid ${on3 ? "transparent" : C("border", "#ddd")}`, background: on3 ? C("accentPrimary", "#116DFF") : "transparent", color: on3 ? C("textOnAccent", "#fff") : C("textSecondary", "#666"), padding: "6px 12px", borderRadius: 999 };
|
|
28417
|
+
const inner = /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
28418
|
+
asText2(c.label),
|
|
28419
|
+
c.count != null && /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
28420
|
+
" ",
|
|
28421
|
+
/* @__PURE__ */ jsx6("span", { style: { opacity: 0.7, fontSize: 11 }, children: c.count })
|
|
28422
|
+
] })
|
|
28423
|
+
] });
|
|
28424
|
+
return interactive ? /* @__PURE__ */ jsx6("button", { type: "button", "aria-pressed": on3, onClick: () => toggle(c.id), style: { all: "unset", cursor: "pointer", boxSizing: "border-box", ...chipStyle }, children: inner }, c.id ?? i) : /* @__PURE__ */ jsx6("span", { style: chipStyle, children: inner }, c.id ?? i);
|
|
28425
|
+
}) })
|
|
28426
|
+
);
|
|
28279
28427
|
});
|
|
28280
28428
|
TILE_PX = 256;
|
|
28281
28429
|
MAX_MERCATOR_LAT = 85.05112878;
|
|
@@ -29279,6 +29427,7 @@ __export(src_exports, {
|
|
|
29279
29427
|
isBinding: () => isBinding,
|
|
29280
29428
|
isNodeLike: () => isNodeLike,
|
|
29281
29429
|
isSerifFamily: () => isSerifFamily,
|
|
29430
|
+
isWebviewUrlAllowed: () => isWebviewUrlAllowed,
|
|
29282
29431
|
makeCtx: () => makeCtx,
|
|
29283
29432
|
makeModStyle: () => makeModStyle,
|
|
29284
29433
|
makeTokenResolvers: () => makeTokenResolvers,
|
|
@@ -29287,7 +29436,8 @@ __export(src_exports, {
|
|
|
29287
29436
|
renderDescriptorToHtml: () => renderDescriptorToHtml,
|
|
29288
29437
|
renderNode: () => renderNode,
|
|
29289
29438
|
servicePath: () => servicePath,
|
|
29290
|
-
useBoundValue: () => useBoundValue
|
|
29439
|
+
useBoundValue: () => useBoundValue,
|
|
29440
|
+
webviewFrameSandbox: () => webviewFrameSandbox
|
|
29291
29441
|
});
|
|
29292
29442
|
var init_src3 = __esm({
|
|
29293
29443
|
"../../core/web-renderer/src/index.ts"() {
|
|
@@ -29301,6 +29451,7 @@ var init_src3 = __esm({
|
|
|
29301
29451
|
init_AppRegistry();
|
|
29302
29452
|
init_helpers();
|
|
29303
29453
|
init_icons();
|
|
29454
|
+
init_webviewFrame();
|
|
29304
29455
|
}
|
|
29305
29456
|
});
|
|
29306
29457
|
|
|
@@ -32789,18 +32940,18 @@ function startBundleArtifactWatcher(state) {
|
|
|
32789
32940
|
});
|
|
32790
32941
|
};
|
|
32791
32942
|
try {
|
|
32792
|
-
const
|
|
32943
|
+
const watcher2 = watch(TIER5_ROOT2, { persistent: false }, (_event, filename) => {
|
|
32793
32944
|
const bundle = builtBundleName(filename);
|
|
32794
32945
|
if (!bundle) return;
|
|
32795
32946
|
pending.add(bundle);
|
|
32796
32947
|
if (timer) clearTimeout(timer);
|
|
32797
32948
|
timer = setTimeout(flush, 120);
|
|
32798
32949
|
});
|
|
32799
|
-
|
|
32950
|
+
watcher2.on("error", (err) => {
|
|
32800
32951
|
console.warn(`[himalaya-dev] bundle watcher stopped: ${err.message}`);
|
|
32801
32952
|
});
|
|
32802
32953
|
console.log(`[himalaya-dev] watching built bundles: ${TIER5_ROOT2}`);
|
|
32803
|
-
return
|
|
32954
|
+
return watcher2;
|
|
32804
32955
|
} catch (err) {
|
|
32805
32956
|
console.warn(`[himalaya-dev] bundle watcher unavailable: ${err.message}`);
|
|
32806
32957
|
return void 0;
|
|
@@ -32835,7 +32986,7 @@ function startBundleSourceWatcher(state) {
|
|
|
32835
32986
|
building = false;
|
|
32836
32987
|
};
|
|
32837
32988
|
try {
|
|
32838
|
-
const
|
|
32989
|
+
const watcher2 = watch(TIER5_SRC_ROOT, { persistent: false, recursive: true }, (_event, filename) => {
|
|
32839
32990
|
if (!filename || !/\.(ts|tsx)$/.test(filename)) return;
|
|
32840
32991
|
const name = filename.split(sep7)[0];
|
|
32841
32992
|
if (!name || name.startsWith(".")) return;
|
|
@@ -32843,11 +32994,11 @@ function startBundleSourceWatcher(state) {
|
|
|
32843
32994
|
if (timer) clearTimeout(timer);
|
|
32844
32995
|
timer = setTimeout(flush, 200);
|
|
32845
32996
|
});
|
|
32846
|
-
|
|
32997
|
+
watcher2.on("error", (err) => {
|
|
32847
32998
|
console.warn(`[himalaya-dev] bundle source watcher stopped: ${err.message}`);
|
|
32848
32999
|
});
|
|
32849
33000
|
console.log(`[himalaya-dev] watching T5 bundle sources: ${TIER5_SRC_ROOT}`);
|
|
32850
|
-
return
|
|
33001
|
+
return watcher2;
|
|
32851
33002
|
} catch (err) {
|
|
32852
33003
|
console.warn(`[himalaya-dev] bundle source watcher unavailable: ${err.message}`);
|
|
32853
33004
|
return void 0;
|
|
@@ -33015,7 +33166,7 @@ function startAppSourceWatcher(state) {
|
|
|
33015
33166
|
}
|
|
33016
33167
|
};
|
|
33017
33168
|
try {
|
|
33018
|
-
const
|
|
33169
|
+
const watcher2 = watch(appDir2, { persistent: false, recursive: true }, (_event, filename) => {
|
|
33019
33170
|
if (!filename) return;
|
|
33020
33171
|
const rel = String(filename).split(sep7).join("/");
|
|
33021
33172
|
if (!classifyAppPath(rel)) return;
|
|
@@ -33023,11 +33174,11 @@ function startAppSourceWatcher(state) {
|
|
|
33023
33174
|
if (timer) clearTimeout(timer);
|
|
33024
33175
|
timer = setTimeout(flush, 200);
|
|
33025
33176
|
});
|
|
33026
|
-
|
|
33177
|
+
watcher2.on("error", (err) => {
|
|
33027
33178
|
console.warn(`[himalaya-dev] app source watcher stopped: ${err.message}`);
|
|
33028
33179
|
});
|
|
33029
33180
|
console.log(`[himalaya-dev] watching app source: ${appDir2}`);
|
|
33030
|
-
return
|
|
33181
|
+
return watcher2;
|
|
33031
33182
|
} catch (err) {
|
|
33032
33183
|
console.warn(`[himalaya-dev] app source watcher unavailable: ${err.message}`);
|
|
33033
33184
|
return void 0;
|
|
@@ -35697,10 +35848,10 @@ function cmsAnswer(seed2, method, bare, body) {
|
|
|
35697
35848
|
pagingMetadata: { count: rows.length, tooManyToCount: false }
|
|
35698
35849
|
};
|
|
35699
35850
|
}
|
|
35700
|
-
function layeredTransport(
|
|
35701
|
-
const rules =
|
|
35702
|
-
const cms =
|
|
35703
|
-
const canned =
|
|
35851
|
+
function layeredTransport(layers2) {
|
|
35852
|
+
const rules = layers2.rules?.length ? [...layers2.rules] : null;
|
|
35853
|
+
const cms = layers2.cmsSeed && Object.keys(layers2.cmsSeed).length ? layers2.cmsSeed : null;
|
|
35854
|
+
const canned = layers2.canned && Object.keys(layers2.canned).length ? layers2.canned : null;
|
|
35704
35855
|
const label2 = [rules && "mocked", cms && "cms", canned && "canned"].filter(Boolean).join("+") || "offline";
|
|
35705
35856
|
const call = async (method, path2, body) => {
|
|
35706
35857
|
const m = String(method).toUpperCase();
|
|
@@ -39030,6 +39181,332 @@ var init_net_freeze = __esm({
|
|
|
39030
39181
|
}
|
|
39031
39182
|
});
|
|
39032
39183
|
|
|
39184
|
+
// src/studio-page.ts
|
|
39185
|
+
function renderStudioHtml(initial) {
|
|
39186
|
+
const accent = initial.app.palette.find((p) => p.name === "accentPrimary")?.hex ?? "#3b6fd8";
|
|
39187
|
+
return `<!doctype html>
|
|
39188
|
+
<html lang="en">
|
|
39189
|
+
<head>
|
|
39190
|
+
<meta charset="utf-8">
|
|
39191
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
39192
|
+
<title>${escapeHtml(initial.app.name)} \xB7 build board</title>
|
|
39193
|
+
<link rel="icon" id="fav" href="data:,">
|
|
39194
|
+
<style>
|
|
39195
|
+
: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)}
|
|
39196
|
+
@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}}
|
|
39197
|
+
*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--ink);font:14px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}
|
|
39198
|
+
.wrap{max-width:1180px;margin:0 auto;padding:20px 20px 60px}
|
|
39199
|
+
header{display:flex;align-items:center;gap:12px;margin-bottom:16px}
|
|
39200
|
+
.icon{width:40px;height:40px;border-radius:10px;background:var(--accent);object-fit:cover;flex:none}
|
|
39201
|
+
h1{font-size:20px;font-weight:600;margin:0}.sub{color:var(--muted);font-size:13px}
|
|
39202
|
+
.right{margin-left:auto;text-align:right}.clock{font-size:22px;font-variant-numeric:tabular-nums;font-weight:600}
|
|
39203
|
+
.live{display:inline-flex;align-items:center;gap:6px;color:var(--muted);font-size:12px}.dot{width:8px;height:8px;border-radius:50%;background:var(--ok)}.stale .dot{background:var(--faint)}
|
|
39204
|
+
.steps{display:grid;grid-template-columns:repeat(8,1fr);gap:6px;margin:4px 0 16px}.step .bar{height:6px;border-radius:3px;background:var(--line)}.step.done .bar{background:var(--ok)}.step.cur .bar{background:var(--accent)}
|
|
39205
|
+
.step .lbl{font-size:11px;color:var(--faint);margin-top:4px;text-transform:capitalize}.step.cur .lbl{color:var(--ink);font-weight:600}
|
|
39206
|
+
.card{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:14px 16px;box-shadow:var(--shadow)}
|
|
39207
|
+
.now{display:flex;gap:12px;align-items:flex-start;margin-bottom:16px}.now .msg{font-size:16px}.now .meta{color:var(--muted);font-size:12px}
|
|
39208
|
+
.grid{display:grid;grid-template-columns:320px 1fr;gap:16px;align-items:start}@media (max-width:860px){.grid{grid-template-columns:1fr}.steps .lbl{display:none}}
|
|
39209
|
+
h2{font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;margin:0 0 10px}
|
|
39210
|
+
.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}
|
|
39211
|
+
.phone img,.phone iframe{width:100%;height:100%;object-fit:cover;object-position:top;border:0;display:block;cursor:zoom-in}
|
|
39212
|
+
.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}
|
|
39213
|
+
.cap{text-align:center;color:var(--muted);font-size:12px;margin-top:8px}
|
|
39214
|
+
.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}
|
|
39215
|
+
.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)}
|
|
39216
|
+
.chip.ok{background:var(--okbg);color:var(--ok);border-color:transparent}.chip.warn{background:var(--warnbg);color:var(--warn);border-color:transparent}.chip.bad{background:var(--badbg);color:var(--bad);border-color:transparent}
|
|
39217
|
+
.wall{display:grid;grid-template-columns:repeat(auto-fill,minmax(112px,1fr));gap:14px}
|
|
39218
|
+
.shot{text-align:center}.shot .frame{aspect-ratio:390/844;border-radius:16px;border:5px solid #111;overflow:hidden;background:#fff}.shot img{width:100%;height:100%;object-fit:cover;object-position:top;display:block;cursor:zoom-in}
|
|
39219
|
+
.shot .id{font-size:12px;margin-top:6px;word-break:break-all}.badge{display:inline-block;font-size:10px;padding:1px 7px;border-radius:999px;margin-top:3px}.badge.new{background:var(--okbg);color:var(--ok)}.badge.chg{background:var(--warnbg);color:var(--warn)}
|
|
39220
|
+
.section{margin-bottom:16px}.brand{display:flex;gap:14px;align-items:center;flex-wrap:wrap}.brand .site{width:220px;border-radius:10px;border:1px solid var(--line);cursor:zoom-in}
|
|
39221
|
+
.sw{display:flex;gap:6px}.sw span{width:22px;height:22px;border-radius:50%;border:1px solid var(--line)}
|
|
39222
|
+
.nav{display:flex;flex-wrap:wrap;gap:6px}.nav span{font-size:12px;padding:3px 8px;border-radius:6px;background:var(--bg);border:1px solid var(--line)}
|
|
39223
|
+
.log{list-style:none;margin:0;padding:0}.log li{display:flex;gap:10px;padding:10px 0;border-top:1px solid var(--line)}.log li:first-child{border-top:0}
|
|
39224
|
+
.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}
|
|
39225
|
+
.empty{color:var(--faint);font-size:13px;padding:8px 0}
|
|
39226
|
+
#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}
|
|
39227
|
+
.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}}
|
|
39228
|
+
.changed .frame{animation:chg .9s ease both}@keyframes chg{35%{opacity:.25;transform:scale(.96)}100%{opacity:1;transform:none}}
|
|
39229
|
+
.step.fresh .bar{animation:fill .7s ease both;transform-origin:left}@keyframes fill{from{transform:scaleX(0)}to{transform:scaleX(1)}}
|
|
39230
|
+
.slidein{animation:slide .45s cubic-bezier(.2,.8,.2,1) both}@keyframes slide{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
|
|
39231
|
+
.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}}
|
|
39232
|
+
.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}}
|
|
39233
|
+
.icon,.step.cur .bar{transition:background-color .8s}.sw.pop span{animation:pop .6s ease both}@keyframes pop{50%{transform:scale(1.25)}}
|
|
39234
|
+
.quiet{color:var(--warn)}.quiet .dot{background:var(--warn)}.idle .dot{background:var(--faint)}
|
|
39235
|
+
.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)}
|
|
39236
|
+
#fx{position:fixed;inset:0;width:100%;height:100%;pointer-events:none;z-index:8}
|
|
39237
|
+
@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}}
|
|
39238
|
+
.scrub{display:flex;align-items:center;gap:8px;margin:-6px 0 4px}.scrub[hidden]{display:none}.scrub input{flex:1;min-width:0}
|
|
39239
|
+
.scrub .rd{font-size:12px;color:var(--muted);min-width:160px;font-variant-numeric:tabular-nums}
|
|
39240
|
+
.marks{position:relative;height:8px;margin:0 9px 12px}.marks span{position:absolute;top:0;width:7px;height:7px;border-radius:50%;background:var(--faint);transform:translateX(-50%)}.marks .ms{background:var(--warn)}.marks .bad{background:var(--bad)}
|
|
39241
|
+
.viewing{font-size:13px;padding:6px 10px;border-radius:8px;background:var(--warnbg);color:var(--warn);margin:0 0 12px}.viewing[hidden]{display:none}.viewing a{color:inherit}
|
|
39242
|
+
.newdot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--bad);margin-left:6px;vertical-align:middle}.newdot[hidden]{display:none}
|
|
39243
|
+
#focus[hidden],#still[hidden]{display:none}
|
|
39244
|
+
.reveal{position:fixed;inset:0;z-index:7;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.5)}.reveal[hidden]{display:none}
|
|
39245
|
+
.rv{background:var(--card);border-radius:16px;padding:18px;max-width:760px;width:calc(100% - 32px)}.rv h3{margin:0;font-size:18px}.rv .row{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px;margin-top:12px}
|
|
39246
|
+
.rv figure{margin:0}.rv figcaption{font-size:12px;color:var(--muted);margin-bottom:6px}.rv .site img{width:100%;border-radius:10px;border:1px solid var(--line)}
|
|
39247
|
+
.rv .ph{position:relative;aspect-ratio:390/844;max-height:60vh;border-radius:22px;border:6px solid #111;overflow:hidden;background:#fff;margin:0 auto}.rv .ph img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:top}
|
|
39248
|
+
.rv .after{clip-path:inset(0 100% 0 0);transition:clip-path 1.4s cubic-bezier(.6,0,.2,1)}.rv.on .after{clip-path:inset(0 0 0 0)}
|
|
39249
|
+
@media (prefers-reduced-motion:reduce){.rv .after{transition:none}.enter,.changed .frame,.step.fresh .bar,.slidein,.phone.pulse,.sw.pop span,.toast{animation:none}.icon,.step.cur .bar{transition:none}}
|
|
39250
|
+
</style>
|
|
39251
|
+
</head>
|
|
39252
|
+
<body>
|
|
39253
|
+
<div class="wrap">
|
|
39254
|
+
<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>
|
|
39255
|
+
<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>
|
|
39256
|
+
<div><span class="live idle" id="agent"><span class="dot"></span><span id="agentt">Waiting for the agent</span></span></div>
|
|
39257
|
+
<div><button class="tog" id="snd" type="button" aria-pressed="false">Sound off</button><button class="tog" id="say" type="button" aria-pressed="false" hidden>Read aloud: off</button><button class="tog" id="ntf" type="button" aria-pressed="false" hidden>Notices off</button></div></div></header>
|
|
39258
|
+
<div class="steps" id="steps"></div>
|
|
39259
|
+
<div class="scrub" id="scrub" hidden><button class="tog" id="replay" type="button">Replay</button><input type="range" id="slider" min="0" max="1" step="1" value="1" aria-label="Build timeline"><span class="rd" id="readout"></span><button class="tog" id="golive" type="button">Live<span class="newdot" id="newdot" hidden></span></button></div>
|
|
39260
|
+
<div class="marks" id="marks"></div>
|
|
39261
|
+
<div class="viewing" id="viewing" hidden>Viewing <span id="viewingt"></span> \xB7 <a href="#" id="backlive">Back to live</a></div>
|
|
39262
|
+
<div class="card now"><div style="flex:1"><div class="meta" id="nowmeta">Now</div><div class="msg" id="nowmsg"></div></div></div>
|
|
39263
|
+
<div class="grid">
|
|
39264
|
+
<div><div class="card"><h2 id="focuslbl">Latest</h2><div id="focus"></div><div id="still" hidden></div><div class="film" id="film"></div>
|
|
39265
|
+
<button class="tog" id="pop" type="button" hidden>Pop out phone</button></div></div>
|
|
39266
|
+
<div>
|
|
39267
|
+
<div class="chips" id="chips"></div>
|
|
39268
|
+
<div class="card section"><h2>Screens</h2><div class="wall" id="wall"></div></div>
|
|
39269
|
+
<div class="card section" id="brandcard"><h2>Brand</h2><div class="brand" id="brand"></div></div>
|
|
39270
|
+
<div class="card section" id="navcard"><h2>Navigation the test crawl followed</h2><div class="nav" id="nav"></div></div>
|
|
39271
|
+
<div class="card section"><h2>Postcards</h2><ul class="log" id="log"></ul></div>
|
|
39272
|
+
</div></div></div>
|
|
39273
|
+
<div id="lb"><img alt=""></div>
|
|
39274
|
+
<div class="reveal" id="reveal" hidden role="dialog" aria-labelledby="rvh"><div class="rv" id="rv"><div style="display:flex;justify-content:space-between;align-items:center;gap:12px"><h3 id="rvh">Your brand, in your app</h3><button class="tog" id="rvx" type="button">Close</button></div><div class="row" id="rvrow"></div></div></div>
|
|
39275
|
+
<canvas id="fx" aria-hidden="true"></canvas>
|
|
39276
|
+
<script>window.__himiInitial = ${scriptJson(initial)};</script>
|
|
39277
|
+
<script>
|
|
39278
|
+
(function(){
|
|
39279
|
+
var cur=null, lastSeen=Date.now();
|
|
39280
|
+
function $(id){return document.getElementById(id)}
|
|
39281
|
+
function el(tag,cls,txt){var e=document.createElement(tag);if(cls)e.className=cls;if(txt!=null)e.textContent=txt;return e}
|
|
39282
|
+
function clear(e){while(e.firstChild)e.removeChild(e.firstChild)}
|
|
39283
|
+
function nowMs(){return asOf||Date.now()}
|
|
39284
|
+
function ago(ts){var s=Math.max(0,Math.round((nowMs()-Date.parse(ts))/1000));if(s<60)return s+"s ago";var m=Math.round(s/60);if(m<60)return m+" min ago";return Math.round(m/60)+" h ago"}
|
|
39285
|
+
function hhmm(ts){var d=new Date(ts);return d.toLocaleTimeString([], {hour:"2-digit",minute:"2-digit"})}
|
|
39286
|
+
function recent(ts){return nowMs()-Date.parse(ts)<10*60*1000}
|
|
39287
|
+
function zoomable(img){img.addEventListener("click",function(){var lb=$("lb");lb.firstChild.src=img.src;lb.style.display="flex"})}
|
|
39288
|
+
function img(src,cls){var i=el("img",cls);i.src=src;i.alt="";i.loading="lazy";zoomable(i);return i}
|
|
39289
|
+
function chip(txt,kind){return el("span","chip"+(kind?" "+kind:""),txt)}
|
|
39290
|
+
function render(s){
|
|
39291
|
+
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;
|
|
39292
|
+
if(s.app.icon){$("icon").src=s.app.icon}else{$("icon").removeAttribute("src")}
|
|
39293
|
+
var steps=$("steps");clear(steps);var n=s.current?s.current.stepNumber:0;
|
|
39294
|
+
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)});
|
|
39295
|
+
var last=s.journal[0];
|
|
39296
|
+
$("nowmsg").textContent=last?last.message:"Waiting for the first postcard.";
|
|
39297
|
+
$("nowmeta").textContent=last?("Now \xB7 "+(last.step?("step "+last.stepNumber+" of 8, "+last.step+" \xB7 "):"")+ago(last.ts)):"Now";
|
|
39298
|
+
var film=$("film");clear(film);
|
|
39299
|
+
if(!rewinding){var n0=s.timelineFrames||0;$("scrub").hidden=n0<2;$("slider").max=String(Math.max(1,n0-1));$("slider").value=$("slider").max}
|
|
39300
|
+
if(rewinding){paintStill(s)}else{$("still").hidden=true;$("focus").hidden=false;var focus=$("focus");
|
|
39301
|
+
/* The live frame is KEPT across renders while its URL and its run are unchanged (a restarted run on
|
|
39302
|
+
the same port is a different server, and the old frame would never see its builds). A new iframe is a full page
|
|
39303
|
+
load of the preview: every postcard, rebuild and the once-a-minute re-render used to throw away
|
|
39304
|
+
the in-place repaint, the preview's scroll and wherever the owner had navigated inside it. */
|
|
39305
|
+
if(pip&&(!s.live||pip.frame.getAttribute("src")!==s.live.url||pip.frame.getAttribute("data-run")!==s.live.runId))bringBack();
|
|
39306
|
+
if(pip){paintStrip(s)}else{
|
|
39307
|
+
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;
|
|
39308
|
+
if(kept){while(focus.lastChild&&focus.lastChild!==kept.parentNode)focus.removeChild(focus.lastChild)}else clear(focus);
|
|
39309
|
+
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))}
|
|
39310
|
+
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"))}
|
|
39311
|
+
else{$("focuslbl").textContent="Latest";focus.appendChild(el("div","empty","The first render appears here."))}
|
|
39312
|
+
if(s.focus&&s.focus.frames.length>1)s.focus.frames.forEach(function(fm){film.appendChild(img(fm.img))});}}
|
|
39313
|
+
var chips=$("chips");clear(chips);var h=s.health;
|
|
39314
|
+
if(h.validate)chips.appendChild(chip(h.validate.ok?"Validate passing":"Validate: "+h.validate.errors+" errors",h.validate.ok?"ok":"bad"));
|
|
39315
|
+
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)}
|
|
39316
|
+
h.ux.forEach(function(u){chips.appendChild(chip("UX drive "+u.platform+": "+u.status,u.status==="passed"?"ok":u.status==="failed"?"bad":"warn"))});
|
|
39317
|
+
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"));
|
|
39318
|
+
if(!chips.firstChild)chips.appendChild(chip("Checks appear here as validate, test and push run"));
|
|
39319
|
+
var wall=$("wall");clear(wall);
|
|
39320
|
+
if(!s.screens.length)wall.appendChild(el("div","empty","Screens appear here as they render."));
|
|
39321
|
+
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));
|
|
39322
|
+
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)});
|
|
39323
|
+
var brand=$("brand");clear(brand);$("brandcard").style.display=(s.brand.site||s.app.palette.length)?"":"none";
|
|
39324
|
+
if(s.brand.site){var si=img(s.brand.site,"site");brand.appendChild(si)}
|
|
39325
|
+
if(s.brand.site&&s.focus&&s.focus.frames.length){brand.appendChild(el("span","sub","\u2192"));var pf=el("div","shot");pf.style.width="90px";var ff=el("div","frame");ff.appendChild(img(s.focus.frames[s.focus.frames.length-1].img));pf.appendChild(ff);brand.appendChild(pf)}
|
|
39326
|
+
if(s.app.palette.length){var sw=el("div","sw");s.app.palette.forEach(function(c){var d=el("span");d.style.background=c.hex;d.title=c.name+" "+c.hex;sw.appendChild(d)});brand.appendChild(sw)}
|
|
39327
|
+
var nav=$("nav");clear(nav);$("navcard").style.display=s.nav.length?"":"none";s.nav.forEach(function(e){nav.appendChild(el("span",null,e.from+" \u2192 "+e.to))});
|
|
39328
|
+
var log=$("log");clear(log);if(!s.journal.length)log.appendChild(el("li","empty","Postcards the agent journals appear here."));
|
|
39329
|
+
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));
|
|
39330
|
+
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)});
|
|
39331
|
+
paintPop(s);
|
|
39332
|
+
}
|
|
39333
|
+
/* Motion, sound and notices answer a CHANGE, never a redraw: effects() compares what is on the page
|
|
39334
|
+
now with what it showed last, so opening the board, the once-a-minute redraw and the two-second
|
|
39335
|
+
poll of an unchanged state do nothing, and each effect names a real event. */
|
|
39336
|
+
var seen=null,actx=null,sound=false,notices=false;
|
|
39337
|
+
var tlStates=null,rewinding=false,replaying=false,asOf=0,replayTimer=null;
|
|
39338
|
+
function foldAll(frames){var out=[],st=null,meta={};(frames||[]).forEach(function(f){
|
|
39339
|
+
var ns={step:null,now:null,screens:{},palette:[],checks:{validate:null,test:null,push:null},build:null};
|
|
39340
|
+
if(!f.key&&st){ns.step=st.step;ns.now=st.now;for(var k in st.screens)ns.screens[k]=st.screens[k];ns.palette=st.palette;ns.checks=st.checks;ns.build=st.build}
|
|
39341
|
+
if("step" in f)ns.step=f.step;if("now" in f)ns.now=f.now;if(f.palette)ns.palette=f.palette;if(f.checks)ns.checks=f.checks;if("build" in f)ns.build=f.build;
|
|
39342
|
+
var sc=f.screens||{};for(var id in sc){if(sc[id]===null)delete ns.screens[id];else ns.screens[id]=sc[id]}
|
|
39343
|
+
for(var j in ns.screens){var m=meta[j];if(!m)meta[j]={first:f.ts,changed:f.ts,img:ns.screens[j],n:1};else if(m.img!==ns.screens[j]){m.changed=f.ts;m.img=ns.screens[j];m.n++}}
|
|
39344
|
+
var copy={};for(var q in meta)copy[q]={first:meta[q].first,changed:meta[q].changed,n:meta[q].n};
|
|
39345
|
+
ns.meta=copy;ns.ts=f.ts;ns.reveal=f.reveal||null;out.push(ns);st=ns});return out}
|
|
39346
|
+
function viewAt(i){var st=tlStates[i],b=cur;
|
|
39347
|
+
var screens=Object.keys(st.screens).sort().map(function(id){var m=st.meta[id];return{id:id,img:st.screens[id],firstSeen:m.first,changedAt:m.changed,versions:m.n}});
|
|
39348
|
+
var t=st.checks.test,prevGaps=null;for(var k=i-1;k>=0&&t;k--){var pt=tlStates[k].checks.test;if(pt&&pt.gaps!==t.gaps){prevGaps=pt.gaps;break}}
|
|
39349
|
+
var fid=b.focus?b.focus.id:null,fimg=fid&&st.screens[fid];
|
|
39350
|
+
return{v:"tl-"+i,generatedAt:st.ts,app:{name:b.app.name,icon:b.app.icon,palette:st.palette.map(function(p){return{name:p[0],hex:p[1]}})},steps:b.steps,
|
|
39351
|
+
current:st.step?{step:st.step.name,stepNumber:st.step.n,of:8}:null,startedAt:b.startedAt,
|
|
39352
|
+
journal:journalAt(st,b),screens:screens,focus:fimg?{id:fid,frames:[{ts:st.ts,img:fimg}]}:null,
|
|
39353
|
+
health:{validate:st.checks.validate?{ok:st.checks.validate.ok,errors:st.checks.validate.errors,warnings:0,at:st.ts}:null,
|
|
39354
|
+
test:t?{ok:t.ok,screens:t.screens,actions:t.actions,gaps:t.gaps,prevGaps:prevGaps,errors:0,at:st.ts}:null,ux:[],
|
|
39355
|
+
push:st.checks.push?{app:"",releaseId:st.checks.push.releaseId,draft:st.checks.push.draft,at:st.ts}:null},
|
|
39356
|
+
brand:b.brand,nav:b.nav,live:null,pastBuild:st.build,reveal:st.reveal?{at:st.ts,site:st.reveal.site,before:st.reveal.before,after:st.reveal.after}:null,timelineFrames:b.timelineFrames}}
|
|
39357
|
+
/* The board keeps only the newest postcards; the timeline remembers the one showing at each moment. */
|
|
39358
|
+
function journalAt(st,b){var jr=b.journal.filter(function(x){return x.ts<=st.ts});if(st.now&&(!jr[0]||jr[0].ts!==st.now.ts))jr.unshift({ts:st.now.ts,message:st.now.message,images:st.now.images,step:st.step?st.step.name:null,stepNumber:st.step?st.step.n:null});return jr}
|
|
39359
|
+
function loadTimeline(cb){window.__himiTimeline=function(frames){tlStates=foldAll(frames);cb()};var sc=document.createElement("script");sc.src="timeline.js?t="+Date.now();sc.onload=sc.onerror=function(){sc.remove()};document.head.appendChild(sc)}
|
|
39360
|
+
function readout(i){var st=tlStates[i],t0=Date.parse(tlStates[0].ts);return hhmm(st.ts)+(st.step?" \xB7 step "+st.step.n+", "+st.step.name:"")+" \xB7 "+Math.round((Date.parse(st.ts)-t0)/60000)+" min in"}
|
|
39361
|
+
function marks(){var m=$("marks");clear(m);var n=tlStates.length;tlStates.forEach(function(st,i){var p=tlStates[i-1],kind=null;
|
|
39362
|
+
if(st.build&&st.build.ok===false&&(!p||p.build!==st.build))kind="bad";
|
|
39363
|
+
else if(st.reveal||(st.checks.push&&(!p||!p.checks.push||p.checks.push.releaseId!==st.checks.push.releaseId))||(st.step&&st.step.n===8&&(!p||!p.step||p.step.n<8)))kind="ms";
|
|
39364
|
+
else if(st.now&&(!p||!p.now||p.now.ts!==st.now.ts))kind="";
|
|
39365
|
+
if(kind===null)return;var d=el("span",kind||null);d.style.left=(n>1?i/(n-1)*100:0)+"%";m.appendChild(d)})}
|
|
39366
|
+
function paintStill(s){$("focus").hidden=true;var still=$("still");still.hidden=false;clear(still);$("focuslbl").textContent="Home at "+hhmm(s.generatedAt);
|
|
39367
|
+
if(s.focus&&s.focus.frames.length){var p=el("div","phone");p.appendChild(img(s.focus.frames[0].img));still.appendChild(p)}else still.appendChild(el("div","empty","No picture of the home screen yet at this moment."))}
|
|
39368
|
+
function rewindTo(i){if(!tlStates||tlStates.length<2)return null;i=Math.max(0,Math.min(tlStates.length-1,i));rewinding=true;asOf=Date.parse(tlStates[i].ts);
|
|
39369
|
+
var sl=$("slider");sl.max=String(tlStates.length-1);sl.value=String(i);var r=readout(i);$("readout").textContent=r;sl.setAttribute("aria-valuetext",r);
|
|
39370
|
+
$("viewing").hidden=false;$("viewingt").textContent=hhmm(tlStates[i].ts);var s=viewAt(i);render(s);return s}
|
|
39371
|
+
function enterRewind(i){loadTimeline(function(){if(!tlStates||tlStates.length<2)return;marks();rewindTo(i==null?tlStates.length-1:i<0?tlStates.length-1+i:i)})}
|
|
39372
|
+
function stopReplay(){replaying=false;if(replayTimer){clearTimeout(replayTimer);replayTimer=null}$("replay").textContent="Replay"}
|
|
39373
|
+
function toLive(){stopReplay();rewinding=false;asOf=0;$("viewing").hidden=true;$("newdot").hidden=true;$("still").hidden=true;$("focus").hidden=false;$("readout").textContent="";seen=snap(cur);if(seen.accent)document.documentElement.style.setProperty("--accent",seen.accent);render(cur)}
|
|
39374
|
+
/* The replay plan: about 30 s whatever the build's length. Frames that carry a milestone (a step,
|
|
39375
|
+
a draft, a failed build, the reveal) always play; the rest are sampled down to 120 moments; gaps
|
|
39376
|
+
follow real time, 150 ms-1.5 s each, and are scaled down so the whole never runs past 30 s. */
|
|
39377
|
+
function replayPlan(){var n=tlStates.length,keep={0:1};keep[n-1]=1;
|
|
39378
|
+
for(var i=1;i<n;i++){var st=tlStates[i],p=tlStates[i-1];if(st.reveal||(st.step&&(!p.step||p.step.n!==st.step.n))||(st.checks.push&&(!p.checks.push||p.checks.push.releaseId!==st.checks.push.releaseId))||(st.build&&st.build.ok===false&&p.build!==st.build))keep[i]=1}
|
|
39379
|
+
var idx=[],MAX=120;if(n<=MAX){for(var a=0;a<n;a++)idx.push(a)}else{var room=MAX-Object.keys(keep).length;for(var k=1;k<=room;k++)keep[Math.round(k*(n-1)/(room+1))]=1;idx=Object.keys(keep).map(Number).sort(function(x,y){return x-y})}
|
|
39380
|
+
var t0=Date.parse(tlStates[0].ts),span=Math.max(1,Date.parse(tlStates[n-1].ts)-t0),gaps=[],sum=0;
|
|
39381
|
+
for(var q=1;q<idx.length;q++){var g=Math.min(1500,Math.max(150,(Date.parse(tlStates[idx[q]].ts)-Date.parse(tlStates[idx[q-1]].ts))/span*30000));gaps.push(g);sum+=g}
|
|
39382
|
+
var f=sum>30000?30000/sum:1;return{idx:idx,gaps:gaps.map(function(x){return x*f}),total:sum*f}}
|
|
39383
|
+
function replay(){loadTimeline(function(){if(!tlStates||tlStates.length<2)return;marks();replaying=true;$("replay").textContent="Pause";
|
|
39384
|
+
var scale=window.__himiReplayScale!=null?window.__himiReplayScale:1,plan=replayPlan();window.__himiReplayPlan={idx:plan.idx,totalMs:plan.total};
|
|
39385
|
+
seen=snap(rewindTo(0));var q=0;
|
|
39386
|
+
(function next(){if(!replaying)return;q++;if(q>=plan.idx.length){toLive();return}
|
|
39387
|
+
replayTimer=setTimeout(function(){var s=rewindTo(plan.idx[q]);if(s)effects(s);next()},plan.gaps[q-1]*scale)})()})}
|
|
39388
|
+
/* The floating phone: the ONE live frame moves into an always-on-top window (Document Picture-in-
|
|
39389
|
+
Picture; a small ordinary window elsewhere) and back. Two copies would run the app twice and
|
|
39390
|
+
drift apart as the owner taps; the cost of moving is one reload per move. */
|
|
39391
|
+
var pip=null;
|
|
39392
|
+
function canPip(){return !!window.documentPictureInPicture}
|
|
39393
|
+
function paintStrip(s){if(!pip)return;pip.strip.firstChild.textContent=s.current?s.current.stepNumber+"/8 \xB7 "+s.current.step:"";pip.strip.lastChild.textContent=s.journal[0]?s.journal[0].message:""}
|
|
39394
|
+
function fitPip(){if(!pip)return;var w=pip.w.innerWidth,h=pip.w.innerHeight-44;if(w>0&&h>0)pip.frame.style.transform="scale("+Math.min(w/390,h/844)+")"}
|
|
39395
|
+
function mountPip(w,fr){var d=w.document;d.title=cur.app.name+" \xB7 phone";
|
|
39396
|
+
var st=d.createElement("style");st.textContent="html,body{margin:0;height:100%;background:#111;font:12px -apple-system,Segoe UI,Roboto,sans-serif}.pp{position:absolute;top:0;left:0;right:0;bottom:44px;overflow:hidden}.pp iframe{position:absolute;top:0;left:0;width:390px;height:844px;border:0;transform-origin:0 0}.pp.pulse{outline:3px solid #1f7a4d;outline-offset:-3px}.pp.bad{outline-color:#a12a2a}.strip{position:absolute;left:0;right:0;bottom:0;height:44px;padding:4px 10px;box-sizing:border-box;background:#fff;color:#1c1c1a}.strip div:first-child{color:#6b6a64}.strip div:last-child{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}";
|
|
39397
|
+
d.head.appendChild(st);var box=d.createElement("div");box.className="pp";d.body.appendChild(box);
|
|
39398
|
+
var home=fr.parentNode;box.appendChild(fr);
|
|
39399
|
+
var strip=d.createElement("div");strip.className="strip";strip.appendChild(d.createElement("div"));strip.appendChild(d.createElement("div"));d.body.appendChild(strip);
|
|
39400
|
+
pip={w:w,box:box,frame:fr,strip:strip,home:home};
|
|
39401
|
+
var note=el("div","empty","Phone popped out \xB7 ");var back=el("a",null,"Bring back");back.href="#";back.addEventListener("click",function(e){e.preventDefault();bringBack()});note.appendChild(back);note.id="away";home.appendChild(note);
|
|
39402
|
+
w.addEventListener("resize",fitPip);w.addEventListener("pagehide",bringBack);fitPip();paintStrip(cur);paintPop(cur)}
|
|
39403
|
+
var pipRefused=false;
|
|
39404
|
+
function openWindow(fr,afterPip){var w=window.open("","himiPhone","width=340,height=760");if(!w){$("pop").textContent=afterPip?"Open in a window":"Pop-up blocked";return}mountPip(w,fr)}
|
|
39405
|
+
/* A browser can expose Document PiP and still refuse the window (an embedded webview does): fall
|
|
39406
|
+
back to the small window rather than a click that does nothing and says nothing. The refusal may
|
|
39407
|
+
have spent the click's user activation, so a popup opened from it can be blocked: then the button
|
|
39408
|
+
offers the window, and the next click opens it directly with an activation of its own. */
|
|
39409
|
+
function popOut(){var fr=$("focus").querySelector("iframe.vp");if(!fr||pip)return;
|
|
39410
|
+
if(canPip()&&!pipRefused){Promise.resolve().then(function(){return window.documentPictureInPicture.requestWindow({width:320,height:740})}).then(function(w){mountPip(w,fr)},function(){pipRefused=true;openWindow(fr,true)})}
|
|
39411
|
+
else openWindow(fr)}
|
|
39412
|
+
function bringBack(){if(!pip)return;var p=pip;pip=null;var away=document.getElementById("away");if(away&&away.parentNode)away.parentNode.removeChild(away);
|
|
39413
|
+
p.frame.style.transform="";if(p.home&&p.home.isConnected!==false)p.home.appendChild(p.frame);else if(p.frame.parentNode)p.frame.parentNode.removeChild(p.frame);try{p.w.close()}catch(e){}fit();paintPop(cur)}
|
|
39414
|
+
function paintPop(s){var b=$("pop");b.hidden=!(s&&s.live)||rewinding;b.textContent=pip?"Bring back":canPip()&&!pipRefused?"Pop out phone":"Open in a window"}
|
|
39415
|
+
/* The brand reveal (decided board-side, played here only when it ARRIVES as a change) and opt-in
|
|
39416
|
+
read aloud: postcards and milestones, never rebuild messages, the newer cancelling the older. */
|
|
39417
|
+
var revealTimer=null,speakOn=false;try{speakOn=localStorage.getItem("himiStudioSpeak")==="1"}catch(e){}
|
|
39418
|
+
function fig(cap,cls){var f=el("figure",cls||null);f.appendChild(el("figcaption",null,cap));return f}
|
|
39419
|
+
function phoneImg(srcs){var ph=el("div","ph");srcs.forEach(function(p){var i=el("img",p[1]||null);i.src=p[0];i.alt="";ph.appendChild(i)});return ph}
|
|
39420
|
+
function showReveal(r){var row=$("rvrow"),rv=$("rv");clear(row);rv.classList.remove("on");
|
|
39421
|
+
if(r.site){var fs=fig("Your website","site");var si=el("img");si.src=r.site;si.alt="";fs.appendChild(si);row.appendChild(fs)}
|
|
39422
|
+
var same=!r.before||r.before===r.after;
|
|
39423
|
+
if(same){var f1=fig("Your app, your brand");f1.appendChild(phoneImg([[r.after]]));row.appendChild(f1)}
|
|
39424
|
+
else if(reduced()){var fb=fig("Your app, before");fb.appendChild(phoneImg([[r.before]]));row.appendChild(fb);var fa=fig("Your app, your brand");fa.appendChild(phoneImg([[r.after]]));row.appendChild(fa)}
|
|
39425
|
+
else{var fw=fig("Your app");fw.appendChild(phoneImg([[r.before],[r.after,"after"]]));row.appendChild(fw);setTimeout(function(){rv.classList.add("on")},700)}
|
|
39426
|
+
var box=$("reveal");box.hidden=false;box.setAttribute("data-shown",String((+box.getAttribute("data-shown")||0)+1));clearTimeout(revealTimer);revealTimer=setTimeout(hideReveal,6000)}
|
|
39427
|
+
function hideReveal(){$("reveal").hidden=true;clearTimeout(revealTimer)}
|
|
39428
|
+
function speak(t){if(!speakOn||!t)return;try{var ss=window.speechSynthesis;if(!ss||!window.SpeechSynthesisUtterance)return;ss.cancel();var u=new SpeechSynthesisUtterance(t);u.lang=navigator.language||"en";ss.speak(u)}catch(e){}}try{sound=localStorage.getItem("himiStudioSound")==="1";notices=localStorage.getItem("himiStudioNotify")==="1"}catch(e){}
|
|
39429
|
+
var raf=window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(f){return setTimeout(function(){f(Date.now())},16)};
|
|
39430
|
+
function now(){return window.performance&&performance.now?performance.now():Date.now()}
|
|
39431
|
+
function reduced(){try{return matchMedia("(prefers-reduced-motion: reduce)").matches}catch(e){return false}}
|
|
39432
|
+
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){}}
|
|
39433
|
+
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")}};
|
|
39434
|
+
/* Notices are the BOARD's opt-in, not just the browser's: a permission granted to this origin once
|
|
39435
|
+
(an earlier board, another run) must not switch them on, and the toggle must switch them off. */
|
|
39436
|
+
function notify(title,body){if(replaying)return;try{if(notices&&"Notification" in window&&Notification.permission==="granted"&&document.hidden)new Notification(title,{body:body})}catch(e){}}
|
|
39437
|
+
function accentNow(){return (getComputedStyle(document.documentElement).getPropertyValue("--accent")||"").trim()||"#3b6fd8"}
|
|
39438
|
+
/* The preview lays out at a real phone's viewport (390 x 844 CSS px) and is scaled into the frame.
|
|
39439
|
+
Sized to the frame itself it was ~280px wide: narrower than any phone, so screens overflowed
|
|
39440
|
+
sideways and scrolled horizontally. */
|
|
39441
|
+
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)))}
|
|
39442
|
+
window.addEventListener("resize",fit);
|
|
39443
|
+
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){}}
|
|
39444
|
+
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)})()}
|
|
39445
|
+
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)})()}
|
|
39446
|
+
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:s.pastBuild?s.pastBuild.at:null,run:s.live?s.live.runId:s.pastBuild?s.pastBuild.run:null,push:s.health.push?s.health.push.releaseId:null,gaps:s.health.test?s.health.test.gaps:null,accent:acc,reveal:s.reveal?s.reveal.at:null}}
|
|
39447
|
+
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}
|
|
39448
|
+
function effects(s){var is=snap(s),was=seen;seen=is;if(is.accent)document.documentElement.style.setProperty("--accent",is.accent);
|
|
39449
|
+
/* The phone (kept across renders) and the Now line outlive a render: clear what they played last. */
|
|
39450
|
+
var stage=rewinding?$("still"):$("focus"),ph=stage.querySelector(".phone"),nm=$("nowmsg");if(ph)ph.classList.remove("pulse","bad");nm.classList.remove("slidein");if(!was)return;
|
|
39451
|
+
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();
|
|
39452
|
+
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()}
|
|
39453
|
+
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])}
|
|
39454
|
+
/* A rebuild is a later build of the SAME run: a run appearing, or restarting, records its first
|
|
39455
|
+
build too, and nothing was rebuilt then. */
|
|
39456
|
+
if(is.build&&was.build&&is.run===was.run&&is.build!==was.build){var b=s.live&&s.live.lastBuild||s.pastBuild;if(ph){void ph.offsetWidth;ph.classList.add("pulse");if(!b.ok)ph.classList.add("bad")}if(pip){pip.box.classList.remove("pulse","bad");void pip.box.offsetWidth;pip.box.classList.add("pulse");if(!b.ok)pip.box.classList.add("bad");pip.strip.lastChild.textContent=buildLine(b)}var tt=el("div","toast"+(b.ok?"":" bad"),buildLine(b));stage.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&&s.live.buildError||"")}}
|
|
39457
|
+
if(was.gaps!=null&&is.gaps!=null&&is.gaps!==was.gaps)countTo($("gapn"),was.gaps,is.gaps);
|
|
39458
|
+
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))}
|
|
39459
|
+
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")}
|
|
39460
|
+
var said=false;if(is.top&&is.top!==was.top){speak((s.current?"Step "+s.current.stepNumber+", "+s.current.step+". ":"")+(s.journal[0]?s.journal[0].message:""));said=true}
|
|
39461
|
+
if((published||handed)&&!said)speak(published?"Your draft is ready to open on your phone.":"Your app is handed over.");
|
|
39462
|
+
if(is.reveal&&is.reveal!==was.reveal)showReveal(s.reveal);
|
|
39463
|
+
}
|
|
39464
|
+
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}
|
|
39465
|
+
function paintToggles(){var sy=$("say");sy.hidden=!("speechSynthesis" in window);sy.textContent="Read aloud: "+(speakOn?"on":"off");sy.className="tog"+(speakOn?" on":"");sy.setAttribute("aria-pressed",String(speakOn));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))}
|
|
39466
|
+
function setNotices(v){notices=v;try{localStorage.setItem("himiStudioNotify",v?"1":"0")}catch(e){}paintToggles()}
|
|
39467
|
+
$("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()});
|
|
39468
|
+
/* The click acts on what the button SAYS (the effective state), so a remembered opt-in whose browser
|
|
39469
|
+
permission was since reset reads "off" and one click asks for permission, not two. */
|
|
39470
|
+
$("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){}});
|
|
39471
|
+
document.addEventListener("click",function(){try{if(actx&&actx.state==="suspended")actx.resume()}catch(e){}},{once:true});
|
|
39472
|
+
paintToggles();
|
|
39473
|
+
$("slider").addEventListener("input",function(){var i=+this.value;if(replaying)stopReplay();if(!rewinding||!tlStates)enterRewind(i);else rewindTo(i)});
|
|
39474
|
+
$("replay").addEventListener("click",function(){if(replaying){stopReplay();return}replay()});
|
|
39475
|
+
$("golive").addEventListener("click",toLive);
|
|
39476
|
+
$("rvx").addEventListener("click",hideReveal);$("reveal").addEventListener("click",function(e){if(e.target===this)hideReveal()});
|
|
39477
|
+
$("say").addEventListener("click",function(){speakOn=!speakOn;try{localStorage.setItem("himiStudioSpeak",speakOn?"1":"0")}catch(e){}paintToggles();if(speakOn)speak("Read aloud is on.")});
|
|
39478
|
+
$("pop").addEventListener("click",function(){if(pip)bringBack();else popOut()});
|
|
39479
|
+
$("backlive").addEventListener("click",function(e){e.preventDefault();toLive()});
|
|
39480
|
+
document.addEventListener("keydown",function(e){if($("scrub").hidden)return;var tg=e.target,tn=tg&&tg.tagName;
|
|
39481
|
+
if(e.key==="Escape"&&rewinding){toLive();return}
|
|
39482
|
+
if((e.key==="ArrowLeft"||e.key==="ArrowRight")&&!(tg&&tg.id==="slider")){var d=e.key==="ArrowRight"?1:-1;if(!rewinding){if(d<0)enterRewind(d)}else rewindTo(+$("slider").value+d);e.preventDefault()}
|
|
39483
|
+
if(e.key===" "&&tn!=="BUTTON"&&tn!=="INPUT"){e.preventDefault();$("replay").click()}});
|
|
39484
|
+
window.__himiStudio=function(s){lastSeen=Date.now();if(!cur||cur.v!==s.v){cur=s;if(rewinding){$("newdot").hidden=false;return}render(s);effects(s)}else{cur.generatedAt=s.generatedAt}};
|
|
39485
|
+
$("lb").addEventListener("click",function(){this.style.display="none"});
|
|
39486
|
+
window.__himiStudio(window.__himiInitial);
|
|
39487
|
+
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);
|
|
39488
|
+
var ticks=0;
|
|
39489
|
+
setInterval(function(){if(!cur)return;if(++ticks%60===0&&!rewinding)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;
|
|
39490
|
+
$("clock").textContent=(hh?hh+":":"")+(mm<10&&hh?"0":"")+mm+":"+(ss<10?"0":"")+ss;
|
|
39491
|
+
$("updated").textContent="updated "+ago(cur.generatedAt);$("live").className="live"+(Date.now()-lastSeen>10000?" stale":"");
|
|
39492
|
+
var a=activityAt(cur),q=a?Date.now()-a:0,done=cur.current&&cur.current.stepNumber===8;
|
|
39493
|
+
$("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);
|
|
39494
|
+
})();
|
|
39495
|
+
</script>
|
|
39496
|
+
</body>
|
|
39497
|
+
</html>
|
|
39498
|
+
`;
|
|
39499
|
+
}
|
|
39500
|
+
function escapeHtml(s) {
|
|
39501
|
+
return s.replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]);
|
|
39502
|
+
}
|
|
39503
|
+
var scriptJson;
|
|
39504
|
+
var init_studio_page = __esm({
|
|
39505
|
+
"src/studio-page.ts"() {
|
|
39506
|
+
scriptJson = (value) => JSON.stringify(value).replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
39507
|
+
}
|
|
39508
|
+
});
|
|
39509
|
+
|
|
39033
39510
|
// src/progress.ts
|
|
39034
39511
|
var progress_exports = {};
|
|
39035
39512
|
__export(progress_exports, {
|
|
@@ -39276,6 +39753,152 @@ var init_progress = __esm({
|
|
|
39276
39753
|
}
|
|
39277
39754
|
});
|
|
39278
39755
|
|
|
39756
|
+
// src/studio-timeline.ts
|
|
39757
|
+
import { existsSync as existsSync39, readFileSync as readFileSync42 } from "node:fs";
|
|
39758
|
+
import { join as join36 } from "node:path";
|
|
39759
|
+
function stateOf(view) {
|
|
39760
|
+
const j = view.journal[0];
|
|
39761
|
+
const h = view.health;
|
|
39762
|
+
const b = view.live?.lastBuild ?? null;
|
|
39763
|
+
return {
|
|
39764
|
+
step: view.current ? { n: view.current.stepNumber, name: view.current.step } : null,
|
|
39765
|
+
now: j ? { ts: j.ts, message: j.message, images: j.images } : null,
|
|
39766
|
+
screens: Object.fromEntries(view.screens.map((s) => [s.id, s.img])),
|
|
39767
|
+
palette: view.app.palette.map((p) => [p.name, p.hex]),
|
|
39768
|
+
checks: {
|
|
39769
|
+
validate: h.validate ? { ok: h.validate.ok, errors: h.validate.errors } : null,
|
|
39770
|
+
test: h.test ? { screens: h.test.screens, actions: h.test.actions, gaps: h.test.gaps, ok: h.test.ok } : null,
|
|
39771
|
+
push: h.push ? { draft: h.push.draft, releaseId: h.push.releaseId } : null
|
|
39772
|
+
},
|
|
39773
|
+
build: b && view.live ? { ok: b.ok, ms: b.ms, screens: b.screens, at: b.at, run: view.live.runId } : null
|
|
39774
|
+
};
|
|
39775
|
+
}
|
|
39776
|
+
function frameFor(state, prev, ts2, v, key2) {
|
|
39777
|
+
if (key2 || !prev) return { ts: ts2, v, key: true, ...state };
|
|
39778
|
+
const f = { ts: ts2, v };
|
|
39779
|
+
if (!same(state.step, prev.step)) f.step = state.step;
|
|
39780
|
+
if (!same(state.now, prev.now)) f.now = state.now;
|
|
39781
|
+
const screens = {};
|
|
39782
|
+
for (const [id, img] of Object.entries(state.screens)) if (prev.screens[id] !== img) screens[id] = img;
|
|
39783
|
+
for (const id of Object.keys(prev.screens)) if (!(id in state.screens)) screens[id] = null;
|
|
39784
|
+
if (Object.keys(screens).length) f.screens = screens;
|
|
39785
|
+
if (!same(state.palette, prev.palette)) f.palette = state.palette;
|
|
39786
|
+
if (!same(state.checks, prev.checks)) f.checks = state.checks;
|
|
39787
|
+
if (!same(state.build, prev.build)) f.build = state.build;
|
|
39788
|
+
return f;
|
|
39789
|
+
}
|
|
39790
|
+
function fold(prev, f) {
|
|
39791
|
+
const base = f.key || !prev ? EMPTY : prev;
|
|
39792
|
+
const screens = f.key ? {} : { ...base.screens };
|
|
39793
|
+
for (const [id, img] of Object.entries(f.screens ?? {})) {
|
|
39794
|
+
if (img === null) delete screens[id];
|
|
39795
|
+
else screens[id] = img;
|
|
39796
|
+
}
|
|
39797
|
+
return {
|
|
39798
|
+
step: "step" in f ? f.step ?? null : base.step,
|
|
39799
|
+
now: "now" in f ? f.now ?? null : base.now,
|
|
39800
|
+
screens,
|
|
39801
|
+
palette: f.palette ?? base.palette,
|
|
39802
|
+
checks: f.checks ?? base.checks,
|
|
39803
|
+
build: "build" in f ? f.build ?? null : base.build
|
|
39804
|
+
};
|
|
39805
|
+
}
|
|
39806
|
+
function validFrame(f) {
|
|
39807
|
+
if (!isObj(f) || !isStr(f.ts) || !isStr(f.v)) return false;
|
|
39808
|
+
if (f.key !== void 0 && f.key !== true) return false;
|
|
39809
|
+
if ("step" in f && !nullOr(f.step, (x) => typeof x.n === "number" && isStr(x.name))) return false;
|
|
39810
|
+
if ("now" in f && !nullOr(f.now, (x) => isStr(x.ts) && isStr(x.message) && strs(x.images))) return false;
|
|
39811
|
+
if ("screens" in f && !(isObj(f.screens) && Object.values(f.screens).every((x) => x === null || isStr(x)))) return false;
|
|
39812
|
+
if ("palette" in f && !(Array.isArray(f.palette) && f.palette.every((p) => Array.isArray(p) && p.length === 2 && p.every(isStr)))) return false;
|
|
39813
|
+
if ("checks" in f) {
|
|
39814
|
+
const c = f.checks;
|
|
39815
|
+
if (!isObj(c)) return false;
|
|
39816
|
+
if (!nullOr(c.validate ?? null, (x) => typeof x.ok === "boolean" && typeof x.errors === "number")) return false;
|
|
39817
|
+
if (!nullOr(c.test ?? null, (x) => ["screens", "actions", "gaps"].every((k) => typeof x[k] === "number") && typeof x.ok === "boolean")) return false;
|
|
39818
|
+
if (!nullOr(c.push ?? null, (x) => typeof x.draft === "boolean" && isStr(x.releaseId))) return false;
|
|
39819
|
+
}
|
|
39820
|
+
if ("build" in f && !nullOr(f.build, (x) => typeof x.ok === "boolean" && (x.ms === null || typeof x.ms === "number") && strs(x.screens) && isStr(x.at) && isStr(x.run))) return false;
|
|
39821
|
+
if ("reveal" in f && !(isObj(f.reveal) && (f.reveal.site === null || isStr(f.reveal.site)) && isStr(f.reveal.before) && isStr(f.reveal.after))) return false;
|
|
39822
|
+
return true;
|
|
39823
|
+
}
|
|
39824
|
+
function readTimeline(dir) {
|
|
39825
|
+
const file = join36(dir, TIMELINE_FILE);
|
|
39826
|
+
if (!existsSync39(file)) return [];
|
|
39827
|
+
const out = [];
|
|
39828
|
+
for (const line of readFileSync42(file, "utf8").split("\n")) {
|
|
39829
|
+
if (!line.trim()) continue;
|
|
39830
|
+
try {
|
|
39831
|
+
const f = JSON.parse(line);
|
|
39832
|
+
if (validFrame(f)) out.push(f);
|
|
39833
|
+
} catch {
|
|
39834
|
+
}
|
|
39835
|
+
}
|
|
39836
|
+
const first = out.findIndex((f) => f.key === true);
|
|
39837
|
+
return first < 0 ? [] : out.slice(first);
|
|
39838
|
+
}
|
|
39839
|
+
function trim(frames) {
|
|
39840
|
+
if (frames.length <= MAX_FRAMES) return frames;
|
|
39841
|
+
for (let i = 1; i < frames.length; i++) if (frames[i].key && frames.length - i <= MAX_FRAMES) return frames.slice(i);
|
|
39842
|
+
return frames.slice(-MAX_FRAMES);
|
|
39843
|
+
}
|
|
39844
|
+
function writeTimelineJs(dir, frames) {
|
|
39845
|
+
writeFileAtomic(join36(dir, TIMELINE_JS), `window.__himiTimeline && window.__himiTimeline(${scriptJson(frames)});
|
|
39846
|
+
`);
|
|
39847
|
+
}
|
|
39848
|
+
function appendFrame(dir, view, reveal = null) {
|
|
39849
|
+
const frames = readTimeline(dir);
|
|
39850
|
+
const last = frames[frames.length - 1];
|
|
39851
|
+
if (last && last.v === view.v && !reveal) {
|
|
39852
|
+
if (!existsSync39(join36(dir, TIMELINE_JS))) writeTimelineJs(dir, frames);
|
|
39853
|
+
return frames.length;
|
|
39854
|
+
}
|
|
39855
|
+
let prev = null;
|
|
39856
|
+
for (const f of frames) prev = fold(prev, f);
|
|
39857
|
+
const frame = frameFor(stateOf(view), prev, view.generatedAt, view.v, frames.length % KEYFRAME_EVERY === 0);
|
|
39858
|
+
if (reveal) frame.reveal = reveal;
|
|
39859
|
+
const kept = trim([...frames, frame]);
|
|
39860
|
+
writeFileAtomic(join36(dir, TIMELINE_FILE), kept.map((f) => JSON.stringify(f)).join("\n") + "\n");
|
|
39861
|
+
writeTimelineJs(dir, kept);
|
|
39862
|
+
return kept.length;
|
|
39863
|
+
}
|
|
39864
|
+
function brandLanded(view, first) {
|
|
39865
|
+
const was = accentOf(first?.palette);
|
|
39866
|
+
const is = accentOf(view.app.palette);
|
|
39867
|
+
return was !== null && is !== null && was !== is || view.journal.some((j) => j.step === "brand");
|
|
39868
|
+
}
|
|
39869
|
+
function revealFor(view, memory) {
|
|
39870
|
+
if (memory.revealedAt || !memory.brandSeenAt || !view.focus || !view.focus.frames.length) return null;
|
|
39871
|
+
const latest = view.focus.frames[view.focus.frames.length - 1];
|
|
39872
|
+
if (latest.ts < memory.brandSeenAt) return null;
|
|
39873
|
+
const firstVersion = memory.timeline.find((t) => t.id === view.focus.id);
|
|
39874
|
+
const before = firstVersion ? `../history/${firstVersion.sha}.${firstVersion.ext}` : latest.img;
|
|
39875
|
+
return { site: view.brand.site, before, after: latest.img };
|
|
39876
|
+
}
|
|
39877
|
+
var TIMELINE_FILE, TIMELINE_JS, MAX_FRAMES, KEYFRAME_EVERY, same, EMPTY, isStr, isObj, strs, nullOr, accentOf;
|
|
39878
|
+
var init_studio_timeline = __esm({
|
|
39879
|
+
"src/studio-timeline.ts"() {
|
|
39880
|
+
init_progress();
|
|
39881
|
+
init_studio_page();
|
|
39882
|
+
TIMELINE_FILE = join36(".himi", "studio", "timeline.jsonl");
|
|
39883
|
+
TIMELINE_JS = join36(".himi", "studio", "timeline.js");
|
|
39884
|
+
MAX_FRAMES = 2e3;
|
|
39885
|
+
KEYFRAME_EVERY = 50;
|
|
39886
|
+
same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
39887
|
+
EMPTY = { step: null, now: null, screens: {}, palette: [], checks: { validate: null, test: null, push: null }, build: null };
|
|
39888
|
+
isStr = (x) => typeof x === "string";
|
|
39889
|
+
isObj = (x) => typeof x === "object" && x !== null && !Array.isArray(x);
|
|
39890
|
+
strs = (x) => Array.isArray(x) && x.every(isStr);
|
|
39891
|
+
nullOr = (x, ok) => x === null || isObj(x) && ok(x);
|
|
39892
|
+
accentOf = (palette2) => {
|
|
39893
|
+
for (const p of palette2 ?? []) {
|
|
39894
|
+
const [name, hex2] = Array.isArray(p) ? p : [p.name, p.hex];
|
|
39895
|
+
if (name === "accentPrimary") return hex2;
|
|
39896
|
+
}
|
|
39897
|
+
return null;
|
|
39898
|
+
};
|
|
39899
|
+
}
|
|
39900
|
+
});
|
|
39901
|
+
|
|
39279
39902
|
// src/studio.ts
|
|
39280
39903
|
var studio_exports = {};
|
|
39281
39904
|
__export(studio_exports, {
|
|
@@ -39294,8 +39917,8 @@ __export(studio_exports, {
|
|
|
39294
39917
|
writeStudioRecord: () => writeStudioRecord
|
|
39295
39918
|
});
|
|
39296
39919
|
import { createHash as createHash20 } from "node:crypto";
|
|
39297
|
-
import { existsSync as
|
|
39298
|
-
import { basename as basename9, extname as extname3, join as
|
|
39920
|
+
import { existsSync as existsSync40, readdirSync as readdirSync20, readFileSync as readFileSync43, realpathSync as realpathSync4, statSync as statSync8 } from "node:fs";
|
|
39921
|
+
import { basename as basename9, extname as extname3, join as join37, relative as relative6, resolve as resolve33, sep as sep9 } from "node:path";
|
|
39299
39922
|
import { pathToFileURL as pathToFileURL7 } from "node:url";
|
|
39300
39923
|
function realInside(dir, abs) {
|
|
39301
39924
|
try {
|
|
@@ -39320,12 +39943,12 @@ function archiveFile(dir, memory, abs) {
|
|
|
39320
39943
|
if (size === 0) return null;
|
|
39321
39944
|
const key2 = relative6(dir, abs);
|
|
39322
39945
|
const hit = memory.files?.[key2];
|
|
39323
|
-
if (hit && hit.size === size && hit.mtimeMs === mtimeMs && hit.ino === ino &&
|
|
39946
|
+
if (hit && hit.size === size && hit.mtimeMs === mtimeMs && hit.ino === ino && existsSync40(join37(dir, HISTORY_DIR, `${hit.sha}.${hit.ext}`))) {
|
|
39324
39947
|
return { sha: hit.sha, ext: hit.ext, file: `${hit.sha}.${hit.ext}` };
|
|
39325
39948
|
}
|
|
39326
39949
|
let archived;
|
|
39327
39950
|
try {
|
|
39328
|
-
archived = archiveBytes(dir,
|
|
39951
|
+
archived = archiveBytes(dir, readFileSync43(real));
|
|
39329
39952
|
} catch {
|
|
39330
39953
|
return null;
|
|
39331
39954
|
}
|
|
@@ -39334,17 +39957,17 @@ function archiveFile(dir, memory, abs) {
|
|
|
39334
39957
|
return { sha: archived.sha256, ext: archived.ext, file: `${archived.sha256}.${archived.ext}` };
|
|
39335
39958
|
}
|
|
39336
39959
|
function loadMemory(dir, now) {
|
|
39337
|
-
const raw = obj(readJson2(
|
|
39960
|
+
const raw = obj(readJson2(join37(dir, MEMORY_FILE)));
|
|
39338
39961
|
if (raw && raw.version === 1 && obj(raw.shots) && Array.isArray(raw.timeline)) return raw;
|
|
39339
39962
|
return { version: 1, createdAt: now, shots: {}, timeline: [] };
|
|
39340
39963
|
}
|
|
39341
39964
|
function observeShots(dir, memory, now) {
|
|
39342
|
-
const shotsDir =
|
|
39965
|
+
const shotsDir = join37(dir, ".himi", "shots");
|
|
39343
39966
|
const seen = /* @__PURE__ */ new Set();
|
|
39344
|
-
const files =
|
|
39967
|
+
const files = existsSync40(shotsDir) ? readdirSync20(shotsDir).filter((f) => /\.(png|jpe?g)$/i.test(f)).sort() : [];
|
|
39345
39968
|
for (const f of files) {
|
|
39346
39969
|
const id = basename9(f, extname3(f));
|
|
39347
|
-
const archived = archiveFile(dir, memory,
|
|
39970
|
+
const archived = archiveFile(dir, memory, join37(shotsDir, f));
|
|
39348
39971
|
if (!archived) continue;
|
|
39349
39972
|
seen.add(id);
|
|
39350
39973
|
const { sha, ext } = archived;
|
|
@@ -39359,14 +39982,14 @@ function observeShots(dir, memory, now) {
|
|
|
39359
39982
|
memory.shots[id] = { ...prev, present: true };
|
|
39360
39983
|
}
|
|
39361
39984
|
}
|
|
39362
|
-
if (
|
|
39985
|
+
if (existsSync40(shotsDir)) {
|
|
39363
39986
|
for (const [id, shot] of Object.entries(memory.shots)) if (!seen.has(id) && shot.present) memory.shots[id] = { ...shot, present: false };
|
|
39364
39987
|
}
|
|
39365
39988
|
if (memory.timeline.length > MAX_TIMELINE) memory.timeline = memory.timeline.slice(-MAX_TIMELINE);
|
|
39366
39989
|
return memory;
|
|
39367
39990
|
}
|
|
39368
39991
|
function palette(dir) {
|
|
39369
|
-
const colors = obj(obj(readJson2(
|
|
39992
|
+
const colors = obj(obj(readJson2(join37(dir, "tokens.json")))?.colors);
|
|
39370
39993
|
if (!colors) return [];
|
|
39371
39994
|
const pick2 = (key2) => {
|
|
39372
39995
|
const v = colors[key2];
|
|
@@ -39376,7 +39999,7 @@ function palette(dir) {
|
|
|
39376
39999
|
return ["accentPrimary", "accentSecondary", "accentSurface", "surfacePrimary", "textPrimary"].map(pick2).filter((x) => !!x);
|
|
39377
40000
|
}
|
|
39378
40001
|
function appIdentity(dir) {
|
|
39379
|
-
const manifest = obj(readJson2(
|
|
40002
|
+
const manifest = obj(readJson2(join37(dir, "himalaya.content.json")));
|
|
39380
40003
|
const name = text(manifest?.name) ?? basename9(resolve33(dir));
|
|
39381
40004
|
const icon = text(manifest?.icon)?.trim();
|
|
39382
40005
|
const iconPath = icon ? resolve33(dir, icon) : null;
|
|
@@ -39384,12 +40007,12 @@ function appIdentity(dir) {
|
|
|
39384
40007
|
return { name, iconFile: real && statSync8(real).isFile() ? iconPath : null };
|
|
39385
40008
|
}
|
|
39386
40009
|
function testRuns(dir) {
|
|
39387
|
-
const att =
|
|
39388
|
-
if (!
|
|
40010
|
+
const att = join37(dir, ".himi", "attestations");
|
|
40011
|
+
if (!existsSync40(att)) return [];
|
|
39389
40012
|
const runs = [];
|
|
39390
40013
|
for (const f of readdirSync20(att)) {
|
|
39391
40014
|
if (!f.endsWith(".json") || f === "latest.json") continue;
|
|
39392
|
-
const r = obj(readJson2(
|
|
40015
|
+
const r = obj(readJson2(join37(att, f)));
|
|
39393
40016
|
if (!r || r.tool !== "himi-test" || typeof r.runId !== "string") continue;
|
|
39394
40017
|
const report2 = obj(r.report);
|
|
39395
40018
|
const coverage = obj(r.coverage);
|
|
@@ -39405,20 +40028,20 @@ function testRuns(dir) {
|
|
|
39405
40028
|
return runs.sort((a, b) => a.runId.localeCompare(b.runId));
|
|
39406
40029
|
}
|
|
39407
40030
|
function siteHome(dir) {
|
|
39408
|
-
for (const pages of [
|
|
39409
|
-
if (!
|
|
40031
|
+
for (const pages of [join37(dir, ".himi", "business-book", "evidence", "pages"), join37(dir, "evidence", "pages")]) {
|
|
40032
|
+
if (!existsSync40(pages)) continue;
|
|
39410
40033
|
const home = readdirSync20(pages).filter((f) => /^home.*\.(png|jpe?g)$/i.test(f)).sort()[0];
|
|
39411
|
-
if (home) return
|
|
40034
|
+
if (home) return join37(pages, home);
|
|
39412
40035
|
}
|
|
39413
40036
|
return null;
|
|
39414
40037
|
}
|
|
39415
40038
|
function uxStatuses(dir) {
|
|
39416
|
-
const platforms = obj(obj(readJson2(
|
|
40039
|
+
const platforms = obj(obj(readJson2(join37(dir, ".himi", "ux-audit.json")))?.platforms);
|
|
39417
40040
|
if (!platforms) return [];
|
|
39418
40041
|
return Object.entries(platforms).map(([platform, rec]) => ({ platform, status: text(obj(rec)?.status) ?? "" })).filter((p) => p.status);
|
|
39419
40042
|
}
|
|
39420
40043
|
function liveRun(dir) {
|
|
39421
|
-
const rec = obj(readJson2(
|
|
40044
|
+
const rec = obj(readJson2(join37(dir, RUN_RECORD)));
|
|
39422
40045
|
const url = text(rec?.url);
|
|
39423
40046
|
const pid = rec?.pid;
|
|
39424
40047
|
if (!url || !/^https?:\/\//i.test(url) || typeof pid !== "number") return null;
|
|
@@ -39468,9 +40091,9 @@ function buildView(dir, memory, now) {
|
|
|
39468
40091
|
const runs = testRuns(dir);
|
|
39469
40092
|
const last = runs[runs.length - 1];
|
|
39470
40093
|
const prev = runs[runs.length - 2];
|
|
39471
|
-
const validate3 = obj(readJson2(
|
|
39472
|
-
const push = obj(readJson2(
|
|
39473
|
-
const edges = readJson2(
|
|
40094
|
+
const validate3 = obj(readJson2(join37(dir, VALIDATE_RECORD)));
|
|
40095
|
+
const push = obj(readJson2(join37(dir, PUSH_RECORD)));
|
|
40096
|
+
const edges = readJson2(join37(dir, EDGES_RECORD));
|
|
39474
40097
|
const nav = [];
|
|
39475
40098
|
if (Array.isArray(edges)) {
|
|
39476
40099
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -39508,9 +40131,11 @@ function buildView(dir, memory, now) {
|
|
|
39508
40131
|
},
|
|
39509
40132
|
brand: { site: siteImg },
|
|
39510
40133
|
nav,
|
|
39511
|
-
live: liveRun(dir)
|
|
40134
|
+
live: liveRun(dir),
|
|
40135
|
+
timelineFrames: 0,
|
|
40136
|
+
reveal: memory.reveal ?? null
|
|
39512
40137
|
};
|
|
39513
|
-
const { generatedAt: _ignored, ...stable } = view;
|
|
40138
|
+
const { generatedAt: _ignored, timelineFrames: _count, ...stable } = view;
|
|
39514
40139
|
const v = createHash20("sha256").update(JSON.stringify(stable)).digest("hex").slice(0, 16);
|
|
39515
40140
|
return { v, ...view };
|
|
39516
40141
|
}
|
|
@@ -39521,16 +40146,33 @@ function writeBoard(dir, now) {
|
|
|
39521
40146
|
if (!realDirIn(dir, STUDIO_DIR)) throw new UnsafeHimiDirError(STUDIO_DIR);
|
|
39522
40147
|
if (!realDirIn(dir, HISTORY_DIR)) throw new UnsafeHimiDirError(HISTORY_DIR);
|
|
39523
40148
|
const memory = observeShots(dir, loadMemory(dir, now), now);
|
|
39524
|
-
|
|
39525
|
-
|
|
39526
|
-
|
|
40149
|
+
let view = buildView(dir, memory, now);
|
|
40150
|
+
let reveal = null;
|
|
40151
|
+
try {
|
|
40152
|
+
if (!memory.brandSeenAt && brandLanded(view, readTimeline(dir)[0])) memory.brandSeenAt = now;
|
|
40153
|
+
reveal = revealFor(view, memory);
|
|
40154
|
+
if (reveal) {
|
|
40155
|
+
memory.revealedAt = now;
|
|
40156
|
+
memory.reveal = { at: now, ...reveal };
|
|
40157
|
+
view = buildView(dir, memory, now);
|
|
40158
|
+
}
|
|
40159
|
+
} catch {
|
|
40160
|
+
reveal = null;
|
|
40161
|
+
}
|
|
40162
|
+
try {
|
|
40163
|
+
view.timelineFrames = appendFrame(dir, view, reveal);
|
|
40164
|
+
} catch {
|
|
40165
|
+
view.timelineFrames = 0;
|
|
40166
|
+
}
|
|
40167
|
+
writeAtomic(join37(dir, MEMORY_FILE), JSON.stringify(memory));
|
|
40168
|
+
writeAtomic(join37(dir, STATE_FILE), `window.__himiStudio && window.__himiStudio(${scriptJson(view)});
|
|
39527
40169
|
`);
|
|
39528
|
-
writeAtomic(
|
|
40170
|
+
writeAtomic(join37(dir, STUDIO_PAGE), renderStudioHtml(view));
|
|
39529
40171
|
return view;
|
|
39530
40172
|
}
|
|
39531
40173
|
function refreshStudio(dir, now = /* @__PURE__ */ new Date()) {
|
|
39532
40174
|
try {
|
|
39533
|
-
if (!
|
|
40175
|
+
if (!existsSync40(join37(dir, STUDIO_PAGE))) return { refreshed: false };
|
|
39534
40176
|
return { refreshed: true, view: writeBoard(dir, now.toISOString()) };
|
|
39535
40177
|
} catch {
|
|
39536
40178
|
return { refreshed: false };
|
|
@@ -39538,225 +40180,38 @@ function refreshStudio(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
39538
40180
|
}
|
|
39539
40181
|
function openStudio(dir, now = /* @__PURE__ */ new Date()) {
|
|
39540
40182
|
const view = writeBoard(dir, now.toISOString());
|
|
39541
|
-
const page =
|
|
40183
|
+
const page = join37(dir, STUDIO_PAGE);
|
|
39542
40184
|
return { page, url: pathToFileURL7(page).href, view };
|
|
39543
40185
|
}
|
|
39544
40186
|
function writeStudioRecord(dir, record2, value) {
|
|
39545
40187
|
try {
|
|
39546
40188
|
if (!realDirIn(dir, ".himi")) return;
|
|
39547
|
-
writeAtomic(
|
|
40189
|
+
writeAtomic(join37(dir, record2), `${JSON.stringify(value, null, 2)}
|
|
39548
40190
|
`);
|
|
39549
40191
|
} catch {
|
|
39550
40192
|
}
|
|
39551
40193
|
}
|
|
39552
|
-
|
|
39553
|
-
const accent = initial.app.palette.find((p) => p.name === "accentPrimary")?.hex ?? "#3b6fd8";
|
|
39554
|
-
return `<!doctype html>
|
|
39555
|
-
<html lang="en">
|
|
39556
|
-
<head>
|
|
39557
|
-
<meta charset="utf-8">
|
|
39558
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
39559
|
-
<title>${escapeHtml(initial.app.name)} \xB7 build board</title>
|
|
39560
|
-
<link rel="icon" id="fav" href="data:,">
|
|
39561
|
-
<style>
|
|
39562
|
-
: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)}
|
|
39563
|
-
@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}}
|
|
39564
|
-
*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--ink);font:14px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}
|
|
39565
|
-
.wrap{max-width:1180px;margin:0 auto;padding:20px 20px 60px}
|
|
39566
|
-
header{display:flex;align-items:center;gap:12px;margin-bottom:16px}
|
|
39567
|
-
.icon{width:40px;height:40px;border-radius:10px;background:var(--accent);object-fit:cover;flex:none}
|
|
39568
|
-
h1{font-size:20px;font-weight:600;margin:0}.sub{color:var(--muted);font-size:13px}
|
|
39569
|
-
.right{margin-left:auto;text-align:right}.clock{font-size:22px;font-variant-numeric:tabular-nums;font-weight:600}
|
|
39570
|
-
.live{display:inline-flex;align-items:center;gap:6px;color:var(--muted);font-size:12px}.dot{width:8px;height:8px;border-radius:50%;background:var(--ok)}.stale .dot{background:var(--faint)}
|
|
39571
|
-
.steps{display:grid;grid-template-columns:repeat(8,1fr);gap:6px;margin:4px 0 16px}.step .bar{height:6px;border-radius:3px;background:var(--line)}.step.done .bar{background:var(--ok)}.step.cur .bar{background:var(--accent)}
|
|
39572
|
-
.step .lbl{font-size:11px;color:var(--faint);margin-top:4px;text-transform:capitalize}.step.cur .lbl{color:var(--ink);font-weight:600}
|
|
39573
|
-
.card{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:14px 16px;box-shadow:var(--shadow)}
|
|
39574
|
-
.now{display:flex;gap:12px;align-items:flex-start;margin-bottom:16px}.now .msg{font-size:16px}.now .meta{color:var(--muted);font-size:12px}
|
|
39575
|
-
.grid{display:grid;grid-template-columns:320px 1fr;gap:16px;align-items:start}@media (max-width:860px){.grid{grid-template-columns:1fr}.steps .lbl{display:none}}
|
|
39576
|
-
h2{font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;margin:0 0 10px}
|
|
39577
|
-
.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}
|
|
39578
|
-
.phone img,.phone iframe{width:100%;height:100%;object-fit:cover;object-position:top;border:0;display:block;cursor:zoom-in}
|
|
39579
|
-
.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}
|
|
39580
|
-
.cap{text-align:center;color:var(--muted);font-size:12px;margin-top:8px}
|
|
39581
|
-
.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}
|
|
39582
|
-
.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)}
|
|
39583
|
-
.chip.ok{background:var(--okbg);color:var(--ok);border-color:transparent}.chip.warn{background:var(--warnbg);color:var(--warn);border-color:transparent}.chip.bad{background:var(--badbg);color:var(--bad);border-color:transparent}
|
|
39584
|
-
.wall{display:grid;grid-template-columns:repeat(auto-fill,minmax(112px,1fr));gap:14px}
|
|
39585
|
-
.shot{text-align:center}.shot .frame{aspect-ratio:390/844;border-radius:16px;border:5px solid #111;overflow:hidden;background:#fff}.shot img{width:100%;height:100%;object-fit:cover;object-position:top;display:block;cursor:zoom-in}
|
|
39586
|
-
.shot .id{font-size:12px;margin-top:6px;word-break:break-all}.badge{display:inline-block;font-size:10px;padding:1px 7px;border-radius:999px;margin-top:3px}.badge.new{background:var(--okbg);color:var(--ok)}.badge.chg{background:var(--warnbg);color:var(--warn)}
|
|
39587
|
-
.section{margin-bottom:16px}.brand{display:flex;gap:14px;align-items:center;flex-wrap:wrap}.brand .site{width:220px;border-radius:10px;border:1px solid var(--line);cursor:zoom-in}
|
|
39588
|
-
.sw{display:flex;gap:6px}.sw span{width:22px;height:22px;border-radius:50%;border:1px solid var(--line)}
|
|
39589
|
-
.nav{display:flex;flex-wrap:wrap;gap:6px}.nav span{font-size:12px;padding:3px 8px;border-radius:6px;background:var(--bg);border:1px solid var(--line)}
|
|
39590
|
-
.log{list-style:none;margin:0;padding:0}.log li{display:flex;gap:10px;padding:10px 0;border-top:1px solid var(--line)}.log li:first-child{border-top:0}
|
|
39591
|
-
.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}
|
|
39592
|
-
.empty{color:var(--faint);font-size:13px;padding:8px 0}
|
|
39593
|
-
#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}
|
|
39594
|
-
.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}}
|
|
39595
|
-
.changed .frame{animation:chg .9s ease both}@keyframes chg{35%{opacity:.25;transform:scale(.96)}100%{opacity:1;transform:none}}
|
|
39596
|
-
.step.fresh .bar{animation:fill .7s ease both;transform-origin:left}@keyframes fill{from{transform:scaleX(0)}to{transform:scaleX(1)}}
|
|
39597
|
-
.slidein{animation:slide .45s cubic-bezier(.2,.8,.2,1) both}@keyframes slide{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
|
|
39598
|
-
.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}}
|
|
39599
|
-
.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}}
|
|
39600
|
-
.icon,.step.cur .bar{transition:background-color .8s}.sw.pop span{animation:pop .6s ease both}@keyframes pop{50%{transform:scale(1.25)}}
|
|
39601
|
-
.quiet{color:var(--warn)}.quiet .dot{background:var(--warn)}.idle .dot{background:var(--faint)}
|
|
39602
|
-
.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)}
|
|
39603
|
-
#fx{position:fixed;inset:0;width:100%;height:100%;pointer-events:none;z-index:8}
|
|
39604
|
-
@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}}
|
|
39605
|
-
@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}}
|
|
39606
|
-
</style>
|
|
39607
|
-
</head>
|
|
39608
|
-
<body>
|
|
39609
|
-
<div class="wrap">
|
|
39610
|
-
<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>
|
|
39611
|
-
<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>
|
|
39612
|
-
<div><span class="live idle" id="agent"><span class="dot"></span><span id="agentt">Waiting for the agent</span></span></div>
|
|
39613
|
-
<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>
|
|
39614
|
-
<div class="steps" id="steps"></div>
|
|
39615
|
-
<div class="card now"><div style="flex:1"><div class="meta" id="nowmeta">Now</div><div class="msg" id="nowmsg"></div></div></div>
|
|
39616
|
-
<div class="grid">
|
|
39617
|
-
<div><div class="card"><h2 id="focuslbl">Latest</h2><div id="focus"></div><div class="film" id="film"></div></div></div>
|
|
39618
|
-
<div>
|
|
39619
|
-
<div class="chips" id="chips"></div>
|
|
39620
|
-
<div class="card section"><h2>Screens</h2><div class="wall" id="wall"></div></div>
|
|
39621
|
-
<div class="card section" id="brandcard"><h2>Brand</h2><div class="brand" id="brand"></div></div>
|
|
39622
|
-
<div class="card section" id="navcard"><h2>Navigation the test crawl followed</h2><div class="nav" id="nav"></div></div>
|
|
39623
|
-
<div class="card section"><h2>Postcards</h2><ul class="log" id="log"></ul></div>
|
|
39624
|
-
</div></div></div>
|
|
39625
|
-
<div id="lb"><img alt=""></div>
|
|
39626
|
-
<canvas id="fx" aria-hidden="true"></canvas>
|
|
39627
|
-
<script>window.__himiInitial = ${scriptJson(initial)};</script>
|
|
39628
|
-
<script>
|
|
39629
|
-
(function(){
|
|
39630
|
-
var cur=null, lastSeen=Date.now();
|
|
39631
|
-
function $(id){return document.getElementById(id)}
|
|
39632
|
-
function el(tag,cls,txt){var e=document.createElement(tag);if(cls)e.className=cls;if(txt!=null)e.textContent=txt;return e}
|
|
39633
|
-
function clear(e){while(e.firstChild)e.removeChild(e.firstChild)}
|
|
39634
|
-
function ago(ts){var s=Math.max(0,Math.round((Date.now()-Date.parse(ts))/1000));if(s<60)return s+"s ago";var m=Math.round(s/60);if(m<60)return m+" min ago";return Math.round(m/60)+" h ago"}
|
|
39635
|
-
function hhmm(ts){var d=new Date(ts);return d.toLocaleTimeString([], {hour:"2-digit",minute:"2-digit"})}
|
|
39636
|
-
function recent(ts){return Date.now()-Date.parse(ts)<10*60*1000}
|
|
39637
|
-
function zoomable(img){img.addEventListener("click",function(){var lb=$("lb");lb.firstChild.src=img.src;lb.style.display="flex"})}
|
|
39638
|
-
function img(src,cls){var i=el("img",cls);i.src=src;i.alt="";i.loading="lazy";zoomable(i);return i}
|
|
39639
|
-
function chip(txt,kind){return el("span","chip"+(kind?" "+kind:""),txt)}
|
|
39640
|
-
function render(s){
|
|
39641
|
-
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;
|
|
39642
|
-
if(s.app.icon){$("icon").src=s.app.icon}else{$("icon").removeAttribute("src")}
|
|
39643
|
-
var steps=$("steps");clear(steps);var n=s.current?s.current.stepNumber:0;
|
|
39644
|
-
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)});
|
|
39645
|
-
var last=s.journal[0];
|
|
39646
|
-
$("nowmsg").textContent=last?last.message:"Waiting for the first postcard.";
|
|
39647
|
-
$("nowmeta").textContent=last?("Now \xB7 "+(last.step?("step "+last.stepNumber+" of 8, "+last.step+" \xB7 "):"")+ago(last.ts)):"Now";
|
|
39648
|
-
var focus=$("focus");var film=$("film");clear(film);
|
|
39649
|
-
/* The live frame is KEPT across renders while its URL and its run are unchanged (a restarted run on
|
|
39650
|
-
the same port is a different server, and the old frame would never see its builds). A new iframe is a full page
|
|
39651
|
-
load of the preview: every postcard, rebuild and the once-a-minute re-render used to throw away
|
|
39652
|
-
the in-place repaint, the preview's scroll and wherever the owner had navigated inside it. */
|
|
39653
|
-
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;
|
|
39654
|
-
if(kept){while(focus.lastChild&&focus.lastChild!==kept.parentNode)focus.removeChild(focus.lastChild)}else clear(focus);
|
|
39655
|
-
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))}
|
|
39656
|
-
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"))}
|
|
39657
|
-
else{$("focuslbl").textContent="Latest";focus.appendChild(el("div","empty","The first render appears here."))}
|
|
39658
|
-
if(s.focus&&s.focus.frames.length>1)s.focus.frames.forEach(function(fm){film.appendChild(img(fm.img))});
|
|
39659
|
-
var chips=$("chips");clear(chips);var h=s.health;
|
|
39660
|
-
if(h.validate)chips.appendChild(chip(h.validate.ok?"Validate passing":"Validate: "+h.validate.errors+" errors",h.validate.ok?"ok":"bad"));
|
|
39661
|
-
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)}
|
|
39662
|
-
h.ux.forEach(function(u){chips.appendChild(chip("UX drive "+u.platform+": "+u.status,u.status==="passed"?"ok":u.status==="failed"?"bad":"warn"))});
|
|
39663
|
-
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"));
|
|
39664
|
-
if(!chips.firstChild)chips.appendChild(chip("Checks appear here as validate, test and push run"));
|
|
39665
|
-
var wall=$("wall");clear(wall);
|
|
39666
|
-
if(!s.screens.length)wall.appendChild(el("div","empty","Screens appear here as they render."));
|
|
39667
|
-
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));
|
|
39668
|
-
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)});
|
|
39669
|
-
var brand=$("brand");clear(brand);$("brandcard").style.display=(s.brand.site||s.app.palette.length)?"":"none";
|
|
39670
|
-
if(s.brand.site){var si=img(s.brand.site,"site");brand.appendChild(si)}
|
|
39671
|
-
if(s.brand.site&&s.focus&&s.focus.frames.length){brand.appendChild(el("span","sub","\u2192"));var pf=el("div","shot");pf.style.width="90px";var ff=el("div","frame");ff.appendChild(img(s.focus.frames[s.focus.frames.length-1].img));pf.appendChild(ff);brand.appendChild(pf)}
|
|
39672
|
-
if(s.app.palette.length){var sw=el("div","sw");s.app.palette.forEach(function(c){var d=el("span");d.style.background=c.hex;d.title=c.name+" "+c.hex;sw.appendChild(d)});brand.appendChild(sw)}
|
|
39673
|
-
var nav=$("nav");clear(nav);$("navcard").style.display=s.nav.length?"":"none";s.nav.forEach(function(e){nav.appendChild(el("span",null,e.from+" \u2192 "+e.to))});
|
|
39674
|
-
var log=$("log");clear(log);if(!s.journal.length)log.appendChild(el("li","empty","Postcards the agent journals appear here."));
|
|
39675
|
-
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));
|
|
39676
|
-
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)});
|
|
39677
|
-
}
|
|
39678
|
-
/* Motion, sound and notices answer a CHANGE, never a redraw: effects() compares what is on the page
|
|
39679
|
-
now with what it showed last, so opening the board, the once-a-minute redraw and the two-second
|
|
39680
|
-
poll of an unchanged state do nothing, and each effect names a real event. */
|
|
39681
|
-
var seen=null,actx=null,sound=false,notices=false;try{sound=localStorage.getItem("himiStudioSound")==="1";notices=localStorage.getItem("himiStudioNotify")==="1"}catch(e){}
|
|
39682
|
-
var raf=window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(f){return setTimeout(function(){f(Date.now())},16)};
|
|
39683
|
-
function now(){return window.performance&&performance.now?performance.now():Date.now()}
|
|
39684
|
-
function reduced(){try{return matchMedia("(prefers-reduced-motion: reduce)").matches}catch(e){return false}}
|
|
39685
|
-
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){}}
|
|
39686
|
-
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")}};
|
|
39687
|
-
/* Notices are the BOARD's opt-in, not just the browser's: a permission granted to this origin once
|
|
39688
|
-
(an earlier board, another run) must not switch them on, and the toggle must switch them off. */
|
|
39689
|
-
function notify(title,body){try{if(notices&&"Notification" in window&&Notification.permission==="granted"&&document.hidden)new Notification(title,{body:body})}catch(e){}}
|
|
39690
|
-
function accentNow(){return (getComputedStyle(document.documentElement).getPropertyValue("--accent")||"").trim()||"#3b6fd8"}
|
|
39691
|
-
/* The preview lays out at a real phone's viewport (390 x 844 CSS px) and is scaled into the frame.
|
|
39692
|
-
Sized to the frame itself it was ~280px wide: narrower than any phone, so screens overflowed
|
|
39693
|
-
sideways and scrolled horizontally. */
|
|
39694
|
-
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)))}
|
|
39695
|
-
window.addEventListener("resize",fit);
|
|
39696
|
-
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){}}
|
|
39697
|
-
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)})()}
|
|
39698
|
-
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)})()}
|
|
39699
|
-
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}}
|
|
39700
|
-
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}
|
|
39701
|
-
function effects(s){var is=snap(s),was=seen;seen=is;if(is.accent)document.documentElement.style.setProperty("--accent",is.accent);
|
|
39702
|
-
/* The phone (kept across renders) and the Now line outlive a render: clear what they played last. */
|
|
39703
|
-
var ph=$("focus").querySelector(".phone"),nm=$("nowmsg");if(ph)ph.classList.remove("pulse","bad");nm.classList.remove("slidein");if(!was)return;
|
|
39704
|
-
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();
|
|
39705
|
-
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()}
|
|
39706
|
-
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])}
|
|
39707
|
-
/* A rebuild is a later build of the SAME run: a run appearing, or restarting, records its first
|
|
39708
|
-
build too, and nothing was rebuilt then. */
|
|
39709
|
-
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||"")}}
|
|
39710
|
-
if(was.gaps!=null&&is.gaps!=null&&is.gaps!==was.gaps)countTo($("gapn"),was.gaps,is.gaps);
|
|
39711
|
-
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))}
|
|
39712
|
-
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")}
|
|
39713
|
-
}
|
|
39714
|
-
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}
|
|
39715
|
-
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))}
|
|
39716
|
-
function setNotices(v){notices=v;try{localStorage.setItem("himiStudioNotify",v?"1":"0")}catch(e){}paintToggles()}
|
|
39717
|
-
$("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()});
|
|
39718
|
-
/* The click acts on what the button SAYS (the effective state), so a remembered opt-in whose browser
|
|
39719
|
-
permission was since reset reads "off" and one click asks for permission, not two. */
|
|
39720
|
-
$("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){}});
|
|
39721
|
-
document.addEventListener("click",function(){try{if(actx&&actx.state==="suspended")actx.resume()}catch(e){}},{once:true});
|
|
39722
|
-
paintToggles();
|
|
39723
|
-
window.__himiStudio=function(s){lastSeen=Date.now();if(!cur||cur.v!==s.v){cur=s;render(s);effects(s)}else{cur.generatedAt=s.generatedAt}};
|
|
39724
|
-
$("lb").addEventListener("click",function(){this.style.display="none"});
|
|
39725
|
-
window.__himiStudio(window.__himiInitial);
|
|
39726
|
-
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);
|
|
39727
|
-
var ticks=0;
|
|
39728
|
-
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;
|
|
39729
|
-
$("clock").textContent=(hh?hh+":":"")+(mm<10&&hh?"0":"")+mm+":"+(ss<10?"0":"")+ss;
|
|
39730
|
-
$("updated").textContent="updated "+ago(cur.generatedAt);$("live").className="live"+(Date.now()-lastSeen>10000?" stale":"");
|
|
39731
|
-
var a=activityAt(cur),q=a?Date.now()-a:0,done=cur.current&&cur.current.stepNumber===8;
|
|
39732
|
-
$("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);
|
|
39733
|
-
})();
|
|
39734
|
-
</script>
|
|
39735
|
-
</body>
|
|
39736
|
-
</html>
|
|
39737
|
-
`;
|
|
39738
|
-
}
|
|
39739
|
-
function escapeHtml(s) {
|
|
39740
|
-
return s.replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]);
|
|
39741
|
-
}
|
|
39742
|
-
var STUDIO_DIR, STUDIO_PAGE, STATE_FILE, MEMORY_FILE, VALIDATE_RECORD, PUSH_RECORD, EDGES_RECORD, RUN_RECORD, MAX_TIMELINE, MAX_JOURNAL, MAX_NAV_EDGES, readJson2, obj, num, text, historyUrl, runTime, scriptJson;
|
|
40194
|
+
var STUDIO_DIR, STUDIO_PAGE, STATE_FILE, MEMORY_FILE, VALIDATE_RECORD, PUSH_RECORD, EDGES_RECORD, RUN_RECORD, MAX_TIMELINE, MAX_JOURNAL, MAX_NAV_EDGES, readJson2, obj, num, text, historyUrl, runTime;
|
|
39743
40195
|
var init_studio = __esm({
|
|
39744
40196
|
"src/studio.ts"() {
|
|
40197
|
+
init_studio_page();
|
|
40198
|
+
init_studio_timeline();
|
|
39745
40199
|
init_progress();
|
|
39746
|
-
|
|
39747
|
-
|
|
39748
|
-
|
|
39749
|
-
|
|
39750
|
-
|
|
39751
|
-
|
|
39752
|
-
|
|
39753
|
-
|
|
40200
|
+
init_studio_page();
|
|
40201
|
+
STUDIO_DIR = join37(".himi", "studio");
|
|
40202
|
+
STUDIO_PAGE = join37(STUDIO_DIR, "index.html");
|
|
40203
|
+
STATE_FILE = join37(STUDIO_DIR, "state.js");
|
|
40204
|
+
MEMORY_FILE = join37(STUDIO_DIR, "memory.json");
|
|
40205
|
+
VALIDATE_RECORD = join37(".himi", "validate.json");
|
|
40206
|
+
PUSH_RECORD = join37(".himi", "last-push.json");
|
|
40207
|
+
EDGES_RECORD = join37(".himi", "test-edges.json");
|
|
40208
|
+
RUN_RECORD = join37(".himi", "run.json");
|
|
39754
40209
|
MAX_TIMELINE = 500;
|
|
39755
40210
|
MAX_JOURNAL = 80;
|
|
39756
40211
|
MAX_NAV_EDGES = 40;
|
|
39757
40212
|
readJson2 = (file) => {
|
|
39758
40213
|
try {
|
|
39759
|
-
return JSON.parse(
|
|
40214
|
+
return JSON.parse(readFileSync43(file, "utf8"));
|
|
39760
40215
|
} catch {
|
|
39761
40216
|
return null;
|
|
39762
40217
|
}
|
|
@@ -39766,7 +40221,6 @@ var init_studio = __esm({
|
|
|
39766
40221
|
text = (v) => typeof v === "string" && v ? v : null;
|
|
39767
40222
|
historyUrl = (fileName) => `../history/${fileName}`;
|
|
39768
40223
|
runTime = (runId) => runId.replace(/-[0-9a-f]+$/i, "");
|
|
39769
|
-
scriptJson = (value) => JSON.stringify(value).replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
39770
40224
|
}
|
|
39771
40225
|
});
|
|
39772
40226
|
|
|
@@ -40245,11 +40699,11 @@ __export(captcha_exports, {
|
|
|
40245
40699
|
captchaContentInput: () => captchaContentInput,
|
|
40246
40700
|
runCaptcha: () => runCaptcha
|
|
40247
40701
|
});
|
|
40248
|
-
import { readFileSync as
|
|
40702
|
+
import { readFileSync as readFileSync44 } from "node:fs";
|
|
40249
40703
|
import { resolve as resolve34 } from "node:path";
|
|
40250
40704
|
function readObject(path2) {
|
|
40251
40705
|
try {
|
|
40252
|
-
return JSON.parse(
|
|
40706
|
+
return JSON.parse(readFileSync44(path2, "utf8"));
|
|
40253
40707
|
} catch {
|
|
40254
40708
|
return {};
|
|
40255
40709
|
}
|
|
@@ -40393,11 +40847,11 @@ var init_push_setup_apple_credentials = __esm({
|
|
|
40393
40847
|
});
|
|
40394
40848
|
|
|
40395
40849
|
// src/push-onboarding.ts
|
|
40396
|
-
import { existsSync as
|
|
40397
|
-
import { basename as basename10, dirname as dirname22, join as
|
|
40850
|
+
import { existsSync as existsSync41, mkdirSync as mkdirSync18, readFileSync as readFileSync45, statSync as statSync9, writeFileSync as writeFileSync14, chmodSync as chmodSync2 } from "node:fs";
|
|
40851
|
+
import { basename as basename10, dirname as dirname22, join as join38, resolve as resolve35 } from "node:path";
|
|
40398
40852
|
function readJson3(path2) {
|
|
40399
40853
|
try {
|
|
40400
|
-
const parsed = JSON.parse(
|
|
40854
|
+
const parsed = JSON.parse(readFileSync45(path2, "utf8"));
|
|
40401
40855
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
40402
40856
|
} catch {
|
|
40403
40857
|
return {};
|
|
@@ -40405,9 +40859,9 @@ function readJson3(path2) {
|
|
|
40405
40859
|
}
|
|
40406
40860
|
function pushInputsFromContent(dir) {
|
|
40407
40861
|
const root = resolve35(dir);
|
|
40408
|
-
if (!
|
|
40409
|
-
const content = readJson3(
|
|
40410
|
-
const provisioning = readJson3(
|
|
40862
|
+
if (!existsSync41(join38(root, "himalaya.content.json"))) return { initialized: false };
|
|
40863
|
+
const content = readJson3(join38(root, "himalaya.content.json"));
|
|
40864
|
+
const provisioning = readJson3(join38(root, "provisioning.json"));
|
|
40411
40865
|
const native = provisioning.native ?? {};
|
|
40412
40866
|
return {
|
|
40413
40867
|
initialized: true,
|
|
@@ -40482,7 +40936,7 @@ function readKeyFile(path2) {
|
|
|
40482
40936
|
}
|
|
40483
40937
|
let body;
|
|
40484
40938
|
try {
|
|
40485
|
-
body =
|
|
40939
|
+
body = readFileSync45(path2, "utf8");
|
|
40486
40940
|
} catch {
|
|
40487
40941
|
return { ok: false, code: "key_file_unreadable", reason: "cannot read the selected key file; check its path and file permissions" };
|
|
40488
40942
|
}
|
|
@@ -40536,13 +40990,13 @@ function buildPushSetupBody(i, keys) {
|
|
|
40536
40990
|
};
|
|
40537
40991
|
}
|
|
40538
40992
|
function readPushOnboarding(dir) {
|
|
40539
|
-
const path2 =
|
|
40540
|
-
if (!
|
|
40993
|
+
const path2 = join38(resolve35(dir), PUSH_ONBOARDING_PATH);
|
|
40994
|
+
if (!existsSync41(path2)) return { version: 1 };
|
|
40541
40995
|
const parsed = readJson3(path2);
|
|
40542
40996
|
return { version: 1, ...parsed };
|
|
40543
40997
|
}
|
|
40544
40998
|
function writeFile(dir, file) {
|
|
40545
|
-
const path2 =
|
|
40999
|
+
const path2 = join38(resolve35(dir), PUSH_ONBOARDING_PATH);
|
|
40546
41000
|
mkdirSync18(dirname22(path2), { recursive: true, mode: 448 });
|
|
40547
41001
|
writeFileSync14(path2, JSON.stringify(file, null, 2) + "\n", { mode: 384 });
|
|
40548
41002
|
try {
|
|
@@ -40571,8 +41025,8 @@ function recordPushDeferral(dir, d) {
|
|
|
40571
41025
|
return push;
|
|
40572
41026
|
}
|
|
40573
41027
|
function clearPushDeferral(dir) {
|
|
40574
|
-
const path2 =
|
|
40575
|
-
if (!
|
|
41028
|
+
const path2 = join38(resolve35(dir), PUSH_ONBOARDING_PATH);
|
|
41029
|
+
if (!existsSync41(path2)) return;
|
|
40576
41030
|
const { push: _dropped, ...rest } = readPushOnboarding(dir);
|
|
40577
41031
|
writeFile(dir, { ...rest, version: 1 });
|
|
40578
41032
|
}
|
|
@@ -41305,8 +41759,8 @@ __export(template_trim_exports, {
|
|
|
41305
41759
|
routeMatcher: () => routeMatcher,
|
|
41306
41760
|
runTemplateTrim: () => runTemplateTrim
|
|
41307
41761
|
});
|
|
41308
|
-
import { cpSync, existsSync as
|
|
41309
|
-
import { dirname as dirname23, join as
|
|
41762
|
+
import { cpSync, existsSync as existsSync42, mkdirSync as mkdirSync19, readdirSync as readdirSync21, readFileSync as readFileSync46, renameSync as renameSync4, rmSync as rmSync8, statSync as statSync10, writeFileSync as writeFileSync15 } from "node:fs";
|
|
41763
|
+
import { dirname as dirname23, join as join39 } from "node:path";
|
|
41310
41764
|
function routeMatcher(pattern) {
|
|
41311
41765
|
const detail = /^\^([A-Za-z0-9_]+)\(\?:\[_\/\]\(\.\+\)\)\?\$$/.exec(pattern);
|
|
41312
41766
|
if (detail) {
|
|
@@ -42000,20 +42454,20 @@ function homeModulesPass(app, kept, edited) {
|
|
|
42000
42454
|
return { text: patched.src, dropped: patched.droppedModules };
|
|
42001
42455
|
}
|
|
42002
42456
|
function listWorkers(dir) {
|
|
42003
|
-
const root =
|
|
42004
|
-
if (!
|
|
42005
|
-
const dirs = readdirSync21(root).filter((n) => statSync10(
|
|
42457
|
+
const root = join39(dir, "tier5-src");
|
|
42458
|
+
if (!existsSync42(root)) return { dirs: [], files: {} };
|
|
42459
|
+
const dirs = readdirSync21(root).filter((n) => statSync10(join39(root, n)).isDirectory()).sort();
|
|
42006
42460
|
const files = {};
|
|
42007
42461
|
const walk2 = (abs, rel) => {
|
|
42008
42462
|
for (const name of readdirSync21(abs)) {
|
|
42009
42463
|
if (name === "node_modules") continue;
|
|
42010
|
-
const p =
|
|
42464
|
+
const p = join39(abs, name);
|
|
42011
42465
|
const r = `${rel}/${name}`;
|
|
42012
42466
|
if (statSync10(p).isDirectory()) walk2(p, r);
|
|
42013
|
-
else if (/\.(?:[cm]?[jt]sx?|json)$/.test(name)) files[r] =
|
|
42467
|
+
else if (/\.(?:[cm]?[jt]sx?|json)$/.test(name)) files[r] = readFileSync46(p, "utf8");
|
|
42014
42468
|
}
|
|
42015
42469
|
};
|
|
42016
|
-
for (const d of dirs) walk2(
|
|
42470
|
+
for (const d of dirs) walk2(join39(root, d), `tier5-src/${d}`);
|
|
42017
42471
|
return { dirs, files };
|
|
42018
42472
|
}
|
|
42019
42473
|
function csv(v) {
|
|
@@ -42036,16 +42490,16 @@ async function runTemplateTrim(req, deps) {
|
|
|
42036
42490
|
links = req.links;
|
|
42037
42491
|
}
|
|
42038
42492
|
const dir = req.dir;
|
|
42039
|
-
const devPath =
|
|
42040
|
-
const configPath =
|
|
42041
|
-
if (!
|
|
42493
|
+
const devPath = join39(dir, "dev/index.ts");
|
|
42494
|
+
const configPath = join39(dir, "config.ts");
|
|
42495
|
+
if (!existsSync42(devPath) || !existsSync42(configPath)) {
|
|
42042
42496
|
return refuse3(new TrimRefusal(`${dir} has no dev/index.ts + config.ts \u2014 point --content at an app scaffolded with \`himi init --template\``));
|
|
42043
42497
|
}
|
|
42044
42498
|
if (isTemplateSourceTree(dir)) {
|
|
42045
42499
|
return refuse3(new TrimRefusal(`${dir} is a template source tree (its identity is still __HIMI_APP_*__ sentinels) \u2014 trim the app \`himi init --template\` scaffolds from it, not the template itself`));
|
|
42046
42500
|
}
|
|
42047
|
-
const dev =
|
|
42048
|
-
const config =
|
|
42501
|
+
const dev = readFileSync46(devPath, "utf8");
|
|
42502
|
+
const config = readFileSync46(configPath, "utf8");
|
|
42049
42503
|
const workers = listWorkers(dir);
|
|
42050
42504
|
let plan;
|
|
42051
42505
|
try {
|
|
@@ -42055,22 +42509,22 @@ async function runTemplateTrim(req, deps) {
|
|
|
42055
42509
|
throw e;
|
|
42056
42510
|
}
|
|
42057
42511
|
if (req.dryRun) return { code: 0, result: { ok: true, dryRun: true, ...plan.report, validate: null } };
|
|
42058
|
-
const hadHimi =
|
|
42059
|
-
const backupRel =
|
|
42060
|
-
const backup =
|
|
42512
|
+
const hadHimi = existsSync42(join39(dir, ".himi"));
|
|
42513
|
+
const backupRel = join39(".himi", "trim-backup", (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-"));
|
|
42514
|
+
const backup = join39(dir, backupRel);
|
|
42061
42515
|
const originals = [[devPath, "dev/index.ts"], [configPath, "config.ts"]];
|
|
42062
42516
|
const moved = [];
|
|
42063
42517
|
const restore = () => {
|
|
42064
42518
|
for (const [path2, rel] of originals) {
|
|
42065
|
-
const original =
|
|
42066
|
-
if (!
|
|
42519
|
+
const original = readFileSync46(join39(backup, rel));
|
|
42520
|
+
if (!existsSync42(path2) || !readFileSync46(path2).equals(original)) writeFileSync15(path2, original);
|
|
42067
42521
|
}
|
|
42068
|
-
for (const name of [...moved].reverse()) renameSync4(
|
|
42522
|
+
for (const name of [...moved].reverse()) renameSync4(join39(backup, "tier5-src", name), join39(dir, "tier5-src", name));
|
|
42069
42523
|
};
|
|
42070
42524
|
const dropBackup = () => {
|
|
42071
42525
|
rmSync8(backup, { recursive: true, force: true });
|
|
42072
|
-
for (const d of [dirname23(backup),
|
|
42073
|
-
if (d ===
|
|
42526
|
+
for (const d of [dirname23(backup), join39(dir, ".himi")]) {
|
|
42527
|
+
if (d === join39(dir, ".himi") && hadHimi) break;
|
|
42074
42528
|
try {
|
|
42075
42529
|
if (!readdirSync21(d).length) rmSync8(d, { recursive: true });
|
|
42076
42530
|
} catch {
|
|
@@ -42096,9 +42550,9 @@ async function runTemplateTrim(req, deps) {
|
|
|
42096
42550
|
return { code: 1, result: { ok: false, error: `${error} (${message}); every file was restored`, rolledBack: true, ...base(validate4) } };
|
|
42097
42551
|
};
|
|
42098
42552
|
try {
|
|
42099
|
-
mkdirSync19(
|
|
42100
|
-
for (const [path2, rel] of originals) cpSync(path2,
|
|
42101
|
-
if (plan.removedWorkers.length) mkdirSync19(
|
|
42553
|
+
mkdirSync19(join39(backup, "dev"), { recursive: true });
|
|
42554
|
+
for (const [path2, rel] of originals) cpSync(path2, join39(backup, rel));
|
|
42555
|
+
if (plan.removedWorkers.length) mkdirSync19(join39(backup, "tier5-src"), { recursive: true });
|
|
42102
42556
|
} catch (e) {
|
|
42103
42557
|
dropBackup();
|
|
42104
42558
|
return { code: 1, result: { ok: false, error: `could not back up the app before trimming it (${e.message}); nothing was changed`, rolledBack: true, ...base() } };
|
|
@@ -42106,7 +42560,7 @@ async function runTemplateTrim(req, deps) {
|
|
|
42106
42560
|
try {
|
|
42107
42561
|
const moveDir = deps.moveDir ?? renameSync4;
|
|
42108
42562
|
for (const name of plan.removedWorkers) {
|
|
42109
|
-
moveDir(
|
|
42563
|
+
moveDir(join39(dir, "tier5-src", name), join39(backup, "tier5-src", name));
|
|
42110
42564
|
moved.push(name);
|
|
42111
42565
|
}
|
|
42112
42566
|
if (plan.dev !== dev) writeFileSync15(devPath, plan.dev);
|
|
@@ -42117,7 +42571,7 @@ async function runTemplateTrim(req, deps) {
|
|
|
42117
42571
|
let failure;
|
|
42118
42572
|
let validate3;
|
|
42119
42573
|
try {
|
|
42120
|
-
const written = parseApp(
|
|
42574
|
+
const written = parseApp(readFileSync46(devPath, "utf8"), readFileSync46(configPath, "utf8"));
|
|
42121
42575
|
const leftovers = leftoverNavRefs(written.nav.value, plan.removedIds);
|
|
42122
42576
|
if (leftovers.length) failure = { error: "navigation still names screens this trim removed", leftovers };
|
|
42123
42577
|
else {
|
|
@@ -42811,8 +43265,8 @@ __export(pack_exports, {
|
|
|
42811
43265
|
});
|
|
42812
43266
|
import { createHash as createHash21 } from "node:crypto";
|
|
42813
43267
|
import { deflateRawSync, inflateRawSync } from "node:zlib";
|
|
42814
|
-
import { existsSync as
|
|
42815
|
-
import { dirname as dirname24, join as
|
|
43268
|
+
import { existsSync as existsSync43, mkdirSync as mkdirSync20, readFileSync as readFileSync47, readdirSync as readdirSync22, rmSync as rmSync9, statSync as statSync11, writeFileSync as writeFileSync16 } from "node:fs";
|
|
43269
|
+
import { dirname as dirname24, join as join40, resolve as resolve37 } from "node:path";
|
|
42816
43270
|
function writeZip(entries) {
|
|
42817
43271
|
const sorted2 = entries.slice().sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
42818
43272
|
const total = sorted2.reduce((n, e) => n + e.bytes.length, 0);
|
|
@@ -42906,13 +43360,13 @@ function inflateEntry(buf, entry) {
|
|
|
42906
43360
|
return bytes2;
|
|
42907
43361
|
}
|
|
42908
43362
|
function readIf(path2) {
|
|
42909
|
-
return
|
|
43363
|
+
return existsSync43(path2) && statSync11(path2).isFile() ? readFileSync47(path2) : null;
|
|
42910
43364
|
}
|
|
42911
43365
|
function listDir(dir) {
|
|
42912
|
-
return
|
|
43366
|
+
return existsSync43(dir) ? readdirSync22(dir).filter((f) => statSync11(join40(dir, f)).isFile()) : [];
|
|
42913
43367
|
}
|
|
42914
43368
|
function gatherReleaseEntries(appDir2) {
|
|
42915
|
-
const manifestPath =
|
|
43369
|
+
const manifestPath = join40(appDir2, HIMI_PACKAGE_MANIFEST_PATH);
|
|
42916
43370
|
const manifestBytes = readIf(manifestPath);
|
|
42917
43371
|
if (!manifestBytes) throw new Error(`no ${HIMI_PACKAGE_MANIFEST_PATH} in ${appDir2} \u2014 build a release there first`);
|
|
42918
43372
|
const manifest = JSON.parse(manifestBytes.toString("utf8"));
|
|
@@ -42936,7 +43390,7 @@ function gatherReleaseEntries(appDir2) {
|
|
|
42936
43390
|
}
|
|
42937
43391
|
const missing = [];
|
|
42938
43392
|
for (const rel of wanted) {
|
|
42939
|
-
const bytes2 = readIf(
|
|
43393
|
+
const bytes2 = readIf(join40(appDir2, rel));
|
|
42940
43394
|
if (bytes2) entries.push({ path: rel, bytes: bytes2 });
|
|
42941
43395
|
else missing.push(rel);
|
|
42942
43396
|
}
|
|
@@ -42947,12 +43401,12 @@ function gatherReleaseEntries(appDir2) {
|
|
|
42947
43401
|
);
|
|
42948
43402
|
}
|
|
42949
43403
|
for (const name of SINGLETONS) {
|
|
42950
|
-
const bytes2 = readIf(
|
|
43404
|
+
const bytes2 = readIf(join40(appDir2, name));
|
|
42951
43405
|
if (bytes2) entries.push({ path: name, bytes: bytes2 });
|
|
42952
43406
|
}
|
|
42953
43407
|
const skipped = [];
|
|
42954
43408
|
for (const sub of ["screens", "bundles", "assets", "widgets"]) {
|
|
42955
|
-
for (const f of listDir(
|
|
43409
|
+
for (const f of listDir(join40(appDir2, sub))) {
|
|
42956
43410
|
if (!wanted.has(`${sub}/${f}`)) skipped.push(`${sub}/${f}`);
|
|
42957
43411
|
}
|
|
42958
43412
|
}
|
|
@@ -42985,18 +43439,18 @@ function buildEntries(appDir2, app, opts) {
|
|
|
42985
43439
|
return { all, header, manifest, skipped };
|
|
42986
43440
|
}
|
|
42987
43441
|
function packRelease(releaseRoot, app, out, opts = {}) {
|
|
42988
|
-
const appDir2 =
|
|
43442
|
+
const appDir2 = join40(resolve37(releaseRoot), app);
|
|
42989
43443
|
const { all, header, skipped } = buildEntries(appDir2, app, opts);
|
|
42990
43444
|
const buf = writeZip(all);
|
|
42991
|
-
const isDir2 =
|
|
42992
|
-
const outFile = isDir2 ?
|
|
43445
|
+
const isDir2 = existsSync43(out) && statSync11(out).isDirectory();
|
|
43446
|
+
const outFile = isDir2 ? join40(resolve37(out), packageFileName(app, header.releaseId)) : resolve37(out);
|
|
42993
43447
|
mkdirSync20(dirname24(outFile), { recursive: true });
|
|
42994
43448
|
writeFileSync16(outFile, buf);
|
|
42995
43449
|
return { app, releaseId: header.releaseId, header, out: outFile, bytes: buf.length, entryCount: all.length, skipped };
|
|
42996
43450
|
}
|
|
42997
43451
|
function resolvePackageDirDest(outDir, app, releaseId) {
|
|
42998
43452
|
const packagedApp = (dir) => {
|
|
42999
|
-
const bytes2 = readIf(
|
|
43453
|
+
const bytes2 = readIf(join40(dir, HIMI_PACKAGE_HEADER_PATH));
|
|
43000
43454
|
if (!bytes2) return void 0;
|
|
43001
43455
|
try {
|
|
43002
43456
|
return JSON.parse(bytes2.toString("utf8")).app;
|
|
@@ -43005,15 +43459,15 @@ function resolvePackageDirDest(outDir, app, releaseId) {
|
|
|
43005
43459
|
}
|
|
43006
43460
|
};
|
|
43007
43461
|
const replaceable = (dir) => {
|
|
43008
|
-
if (!
|
|
43462
|
+
if (!existsSync43(dir)) return true;
|
|
43009
43463
|
if (!statSync11(dir).isDirectory()) return false;
|
|
43010
43464
|
return readdirSync22(dir).length === 0 || packagedApp(dir) === app;
|
|
43011
43465
|
};
|
|
43012
|
-
if (
|
|
43466
|
+
if (existsSync43(outDir) && !statSync11(outDir).isDirectory()) {
|
|
43013
43467
|
throw new Error(`refusing to write a package tree over ${outDir} \u2014 it is a file, not a directory`);
|
|
43014
43468
|
}
|
|
43015
43469
|
if (replaceable(outDir)) return outDir;
|
|
43016
|
-
const child =
|
|
43470
|
+
const child = join40(outDir, packageDirName(app, releaseId));
|
|
43017
43471
|
if (!replaceable(child)) {
|
|
43018
43472
|
throw new Error(
|
|
43019
43473
|
`refusing to replace ${child}: it is not empty and is not a ${app} package (no ${HIMI_PACKAGE_HEADER_PATH}). Pass --out to a new or empty directory.`
|
|
@@ -43027,13 +43481,13 @@ function packReleaseToDir(releaseRoot, app, outDir, opts = {}) {
|
|
|
43027
43481
|
"a package carrying the app's source has no --format dir form: readers that predate the source entry drop it before hashing a directory and refuse the package as tampered. Pack it as a .himi archive."
|
|
43028
43482
|
);
|
|
43029
43483
|
}
|
|
43030
|
-
const appDir2 =
|
|
43484
|
+
const appDir2 = join40(resolve37(releaseRoot), app);
|
|
43031
43485
|
const { all, header, skipped } = buildEntries(appDir2, app, opts);
|
|
43032
43486
|
const dest = resolvePackageDirDest(resolve37(outDir), app, header.releaseId);
|
|
43033
43487
|
rmSync9(dest, { recursive: true, force: true });
|
|
43034
43488
|
let bytes2 = 0;
|
|
43035
43489
|
for (const entry of all) {
|
|
43036
|
-
const target =
|
|
43490
|
+
const target = join40(dest, entry.path);
|
|
43037
43491
|
mkdirSync20(dirname24(target), { recursive: true });
|
|
43038
43492
|
writeFileSync16(target, entry.bytes);
|
|
43039
43493
|
bytes2 += entry.bytes.length;
|
|
@@ -43056,21 +43510,21 @@ function openPackageBuffer(buf) {
|
|
|
43056
43510
|
return openFromEntries(readZip(buf), { requireHeader: true });
|
|
43057
43511
|
}
|
|
43058
43512
|
function openPackageFile(file) {
|
|
43059
|
-
return openPackageBuffer(
|
|
43513
|
+
return openPackageBuffer(readFileSync47(file));
|
|
43060
43514
|
}
|
|
43061
43515
|
function openPackageDir(dir) {
|
|
43062
43516
|
const root = resolve37(dir);
|
|
43063
43517
|
const entries = /* @__PURE__ */ new Map();
|
|
43064
43518
|
const walk2 = (rel) => {
|
|
43065
|
-
const abs = rel ?
|
|
43519
|
+
const abs = rel ? join40(root, rel) : root;
|
|
43066
43520
|
for (const name of readdirSync22(abs)) {
|
|
43067
43521
|
const childRel = rel ? `${rel}/${name}` : name;
|
|
43068
|
-
const childAbs =
|
|
43522
|
+
const childAbs = join40(abs, name);
|
|
43069
43523
|
if (statSync11(childAbs).isDirectory()) walk2(childRel);
|
|
43070
|
-
else if (isSafeEntryName(childRel)) entries.set(childRel,
|
|
43524
|
+
else if (isSafeEntryName(childRel)) entries.set(childRel, readFileSync47(childAbs));
|
|
43071
43525
|
}
|
|
43072
43526
|
};
|
|
43073
|
-
if (!
|
|
43527
|
+
if (!existsSync43(root)) throw new Error(`no such package directory: ${root}`);
|
|
43074
43528
|
walk2("");
|
|
43075
43529
|
const manifestBytes = entries.get(HIMI_PACKAGE_MANIFEST_PATH);
|
|
43076
43530
|
if (manifestBytes) {
|
|
@@ -43112,10 +43566,10 @@ function unpackTo(buf, dest, appFallback) {
|
|
|
43112
43566
|
if (!app) throw new Error("package declares no app id (no himi-package.json and no manifest.app)");
|
|
43113
43567
|
if (!isSafeAppId(app)) throw new Error(`package declares an unsafe app id ${JSON.stringify(app)} \u2014 refusing to unpack it`);
|
|
43114
43568
|
const root = resolve37(dest);
|
|
43115
|
-
const appDir2 =
|
|
43569
|
+
const appDir2 = join40(root, app);
|
|
43116
43570
|
rmSync9(appDir2, { recursive: true, force: true });
|
|
43117
43571
|
for (const [rel, bytes2] of entries) {
|
|
43118
|
-
const target =
|
|
43572
|
+
const target = join40(appDir2, rel);
|
|
43119
43573
|
mkdirSync20(dirname24(target), { recursive: true });
|
|
43120
43574
|
writeFileSync16(target, bytes2);
|
|
43121
43575
|
}
|
|
@@ -43151,20 +43605,20 @@ __export(app_source_exports, {
|
|
|
43151
43605
|
writeConflicts: () => writeConflicts,
|
|
43152
43606
|
zipAppSource: () => zipAppSource
|
|
43153
43607
|
});
|
|
43154
|
-
import { readdirSync as readdirSync23, lstatSync as lstatSync6, readFileSync as
|
|
43155
|
-
import { join as
|
|
43608
|
+
import { readdirSync as readdirSync23, lstatSync as lstatSync6, readFileSync as readFileSync48, mkdirSync as mkdirSync21, writeFileSync as writeFileSync17, existsSync as existsSync44, rmSync as rmSync10, rmdirSync, unlinkSync as unlinkSync3 } from "node:fs";
|
|
43609
|
+
import { join as join41, resolve as resolve38, sep as sep10 } from "node:path";
|
|
43156
43610
|
import { deflateRawSync as deflateRawSync2 } from "node:zlib";
|
|
43157
43611
|
function walkSourceTree(dir, file, skip) {
|
|
43158
43612
|
const walk2 = (relDir) => {
|
|
43159
|
-
for (const name of readdirSync23(
|
|
43160
|
-
const rel = relDir ?
|
|
43161
|
-
const st = lstatSync6(
|
|
43613
|
+
for (const name of readdirSync23(join41(dir, relDir))) {
|
|
43614
|
+
const rel = relDir ? join41(relDir, name) : name;
|
|
43615
|
+
const st = lstatSync6(join41(dir, rel));
|
|
43162
43616
|
if (st.isSymbolicLink()) {
|
|
43163
43617
|
skip(rel);
|
|
43164
43618
|
continue;
|
|
43165
43619
|
}
|
|
43166
43620
|
if (st.isDirectory()) {
|
|
43167
|
-
if (isDeniedSourceDir(name, relDir) ||
|
|
43621
|
+
if (isDeniedSourceDir(name, relDir) || existsSync44(join41(dir, rel, PACKAGE_DIR_MARKER))) skip(rel);
|
|
43168
43622
|
else walk2(rel);
|
|
43169
43623
|
continue;
|
|
43170
43624
|
}
|
|
@@ -43182,7 +43636,7 @@ function collectAppSource(dir) {
|
|
|
43182
43636
|
const skipped = [];
|
|
43183
43637
|
walkSourceTree(
|
|
43184
43638
|
dir,
|
|
43185
|
-
(archivePath, hostRel) => entries.push({ path: archivePath, bytes:
|
|
43639
|
+
(archivePath, hostRel) => entries.push({ path: archivePath, bytes: readFileSync48(join41(dir, hostRel)) }),
|
|
43186
43640
|
(hostRel) => skipped.push(hostRel)
|
|
43187
43641
|
);
|
|
43188
43642
|
entries.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
@@ -43236,13 +43690,13 @@ function writeAppSource(entries, destDir) {
|
|
|
43236
43690
|
const segments = entry.path.split("/");
|
|
43237
43691
|
let dir = root;
|
|
43238
43692
|
for (const segment of segments.slice(0, -1)) {
|
|
43239
|
-
dir =
|
|
43693
|
+
dir = join41(dir, segment);
|
|
43240
43694
|
const kind = pathKind(dir);
|
|
43241
43695
|
if (kind?.isSymbolicLink()) unlinkSync3(dir);
|
|
43242
43696
|
else if (kind) continue;
|
|
43243
43697
|
mkdirSync21(dir);
|
|
43244
43698
|
}
|
|
43245
|
-
const target =
|
|
43699
|
+
const target = join41(root, ...segments);
|
|
43246
43700
|
if (pathKind(target)?.isSymbolicLink()) unlinkSync3(target);
|
|
43247
43701
|
writeFileSync17(target, entry.bytes);
|
|
43248
43702
|
written.push(entry.path);
|
|
@@ -43250,7 +43704,7 @@ function writeAppSource(entries, destDir) {
|
|
|
43250
43704
|
return written;
|
|
43251
43705
|
}
|
|
43252
43706
|
function staleSourcePaths(entries, destDir) {
|
|
43253
|
-
if (!
|
|
43707
|
+
if (!existsSync44(destDir)) return [];
|
|
43254
43708
|
const archived = new Set(entries.map((e) => e.path));
|
|
43255
43709
|
const stale = [];
|
|
43256
43710
|
walkSourceTree(destDir, (archivePath) => {
|
|
@@ -43277,7 +43731,7 @@ function writeConflicts(entries, destDir) {
|
|
|
43277
43731
|
let dir = root;
|
|
43278
43732
|
let stop = false;
|
|
43279
43733
|
for (const [i, segment] of segments.slice(0, -1).entries()) {
|
|
43280
|
-
dir =
|
|
43734
|
+
dir = join41(dir, segment);
|
|
43281
43735
|
const kind2 = pathKind(dir);
|
|
43282
43736
|
if (!kind2 || kind2.isSymbolicLink()) {
|
|
43283
43737
|
stop = true;
|
|
@@ -43289,7 +43743,7 @@ function writeConflicts(entries, destDir) {
|
|
|
43289
43743
|
break;
|
|
43290
43744
|
}
|
|
43291
43745
|
if (stop) continue;
|
|
43292
|
-
const kind = pathKind(
|
|
43746
|
+
const kind = pathKind(join41(root, ...segments));
|
|
43293
43747
|
if (kind && !kind.isSymbolicLink() && kind.isDirectory()) {
|
|
43294
43748
|
say(entry.path, "is a directory here, but the release has a file at that path");
|
|
43295
43749
|
}
|
|
@@ -43299,22 +43753,22 @@ function writeConflicts(entries, destDir) {
|
|
|
43299
43753
|
function removeStaleSource(entries, destDir) {
|
|
43300
43754
|
const root = resolve38(destDir);
|
|
43301
43755
|
const removed = staleSourcePaths(entries, root);
|
|
43302
|
-
for (const rel of removed) rmSync10(
|
|
43756
|
+
for (const rel of removed) rmSync10(join41(root, ...rel.split("/")), { force: true });
|
|
43303
43757
|
const needed = /* @__PURE__ */ new Set();
|
|
43304
43758
|
for (const entry of entries) {
|
|
43305
43759
|
if (isDeniedSourcePath(entry.path)) continue;
|
|
43306
43760
|
const segments = entry.path.split("/");
|
|
43307
43761
|
for (let i = 1; i < segments.length; i++) needed.add(segments.slice(0, i).join("/"));
|
|
43308
43762
|
}
|
|
43309
|
-
if (
|
|
43763
|
+
if (existsSync44(root)) pruneEmptyDirs(root, "", needed, removed);
|
|
43310
43764
|
return removed.sort();
|
|
43311
43765
|
}
|
|
43312
43766
|
function pruneEmptyDirs(root, rel, needed, removed) {
|
|
43313
43767
|
let empty = true;
|
|
43314
|
-
for (const name of readdirSync23(rel ?
|
|
43315
|
-
const childRel = rel ?
|
|
43768
|
+
for (const name of readdirSync23(rel ? join41(root, rel) : root)) {
|
|
43769
|
+
const childRel = rel ? join41(rel, name) : name;
|
|
43316
43770
|
const posix3 = childRel.split(sep10).join("/");
|
|
43317
|
-
const kind = lstatSync6(
|
|
43771
|
+
const kind = lstatSync6(join41(root, childRel));
|
|
43318
43772
|
if (kind.isSymbolicLink() || !kind.isDirectory() || isDeniedSourceDir(name, rel)) {
|
|
43319
43773
|
empty = false;
|
|
43320
43774
|
continue;
|
|
@@ -43324,7 +43778,7 @@ function pruneEmptyDirs(root, rel, needed, removed) {
|
|
|
43324
43778
|
empty = false;
|
|
43325
43779
|
continue;
|
|
43326
43780
|
}
|
|
43327
|
-
rmdirSync(
|
|
43781
|
+
rmdirSync(join41(root, childRel));
|
|
43328
43782
|
removed.push(`${posix3}/`);
|
|
43329
43783
|
}
|
|
43330
43784
|
return empty;
|
|
@@ -43379,13 +43833,13 @@ __export(eject_exports, {
|
|
|
43379
43833
|
EJECTABLE: () => EJECTABLE,
|
|
43380
43834
|
ejectModule: () => ejectModule
|
|
43381
43835
|
});
|
|
43382
|
-
import { existsSync as
|
|
43383
|
-
import { dirname as dirname25, join as
|
|
43836
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync22, readFileSync as readFileSync49, writeFileSync as writeFileSync18 } from "node:fs";
|
|
43837
|
+
import { dirname as dirname25, join as join42, relative as relative7, resolve as resolve39, sep as sep11 } from "node:path";
|
|
43384
43838
|
function locate(repoRootOrCwd, mod) {
|
|
43385
43839
|
const inRepo = resolve39(repoRootOrCwd, `stdlib/flows/${mod}/src/index.ts`);
|
|
43386
|
-
if (
|
|
43840
|
+
if (existsSync45(inRepo)) return { path: inRepo, form: "source" };
|
|
43387
43841
|
const dist = resolve39(repoRootOrCwd, `node_modules/@wix/himalaya/dist/${mod}.mjs`);
|
|
43388
|
-
if (
|
|
43842
|
+
if (existsSync45(dist)) return { path: dist, form: "bundle" };
|
|
43389
43843
|
return null;
|
|
43390
43844
|
}
|
|
43391
43845
|
function specifiersFor(mod) {
|
|
@@ -43409,7 +43863,7 @@ function ejectModule(opts) {
|
|
|
43409
43863
|
};
|
|
43410
43864
|
}
|
|
43411
43865
|
const ext = found.form === "source" ? "ts" : "mjs";
|
|
43412
|
-
const target =
|
|
43866
|
+
const target = join42(contentDir2, "tier5-src", "_ejected", `${mod}.${ext}`);
|
|
43413
43867
|
mkdirSync22(dirname25(target), { recursive: true });
|
|
43414
43868
|
const banner = `// EJECTED from @wix/himalaya/${mod}. This app owns this file now.
|
|
43415
43869
|
//
|
|
@@ -43423,15 +43877,15 @@ function ejectModule(opts) {
|
|
|
43423
43877
|
// gate still applies. Ejecting buys layout and flow, never the floor.
|
|
43424
43878
|
|
|
43425
43879
|
`;
|
|
43426
|
-
const normalized =
|
|
43880
|
+
const normalized = readFileSync49(found.path, "utf8").replace(
|
|
43427
43881
|
/(["'])@himalaya\/([a-z0-9-]+(?:\/[a-z0-9-]+)?)\1/g,
|
|
43428
43882
|
(_m, q, sub) => `${q}@wix/himalaya/${sub}${q}`
|
|
43429
43883
|
);
|
|
43430
43884
|
writeFileSync18(target, banner + normalized);
|
|
43431
43885
|
const rewired = [];
|
|
43432
43886
|
for (const f of files) {
|
|
43433
|
-
if (!
|
|
43434
|
-
const before =
|
|
43887
|
+
if (!existsSync45(f)) continue;
|
|
43888
|
+
const before = readFileSync49(f, "utf8");
|
|
43435
43889
|
let after = before;
|
|
43436
43890
|
let rel = relative7(dirname25(f), target).split(sep11).join("/").replace(/\.tsx?$/, ".js");
|
|
43437
43891
|
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
@@ -43479,14 +43933,14 @@ __export(test_exports, {
|
|
|
43479
43933
|
scopeDescriptors: () => scopeDescriptors,
|
|
43480
43934
|
writeRecordedMocks: () => writeRecordedMocks
|
|
43481
43935
|
});
|
|
43482
|
-
import { existsSync as
|
|
43483
|
-
import { join as
|
|
43936
|
+
import { existsSync as existsSync46, mkdirSync as mkdirSync23, readFileSync as readFileSync50, writeFileSync as writeFileSync19 } from "node:fs";
|
|
43937
|
+
import { join as join43, resolve as resolve40 } from "node:path";
|
|
43484
43938
|
function readTestConfig(dir) {
|
|
43485
43939
|
const p = resolve40(dir, TEST_CONFIG_FILE);
|
|
43486
|
-
if (!
|
|
43940
|
+
if (!existsSync46(p)) return {};
|
|
43487
43941
|
let parsed;
|
|
43488
43942
|
try {
|
|
43489
|
-
parsed = JSON.parse(
|
|
43943
|
+
parsed = JSON.parse(readFileSync50(p, "utf8"));
|
|
43490
43944
|
} catch (e) {
|
|
43491
43945
|
throw new Error(`${TEST_CONFIG_FILE} is not valid JSON \u2014 ${e.message}`);
|
|
43492
43946
|
}
|
|
@@ -43529,7 +43983,7 @@ function readTestConfig(dir) {
|
|
|
43529
43983
|
function readNetRules(path2) {
|
|
43530
43984
|
let parsed;
|
|
43531
43985
|
try {
|
|
43532
|
-
parsed = JSON.parse(
|
|
43986
|
+
parsed = JSON.parse(readFileSync50(path2, "utf8"));
|
|
43533
43987
|
} catch (e) {
|
|
43534
43988
|
throw new Error(`--net ${path2} could not be read as JSON \u2014 ${e.message}`);
|
|
43535
43989
|
}
|
|
@@ -43550,7 +44004,7 @@ function readNetRules(path2) {
|
|
|
43550
44004
|
function defaultNetRules(dir) {
|
|
43551
44005
|
for (const rel of ["dev/net-mocks.json", "tests/net-mocks.json"]) {
|
|
43552
44006
|
const p = resolve40(dir, rel);
|
|
43553
|
-
if (
|
|
44007
|
+
if (existsSync46(p)) {
|
|
43554
44008
|
const rules = readNetRules(p);
|
|
43555
44009
|
if (rules.length) return { rules, from: rel };
|
|
43556
44010
|
}
|
|
@@ -43566,7 +44020,7 @@ function readCannedResponses() {
|
|
|
43566
44020
|
];
|
|
43567
44021
|
for (const url of candidates) {
|
|
43568
44022
|
try {
|
|
43569
|
-
const parsed = JSON.parse(
|
|
44023
|
+
const parsed = JSON.parse(readFileSync50(url, "utf8"));
|
|
43570
44024
|
const byKey = {};
|
|
43571
44025
|
for (const [k, v] of Object.entries(parsed)) {
|
|
43572
44026
|
if (!k.startsWith("//")) byKey[k] = v;
|
|
@@ -43658,8 +44112,8 @@ function writeRecordedMocks(opts) {
|
|
|
43658
44112
|
mkdir: (p) => mkdirSync23(p, { recursive: true }),
|
|
43659
44113
|
write: (p, s) => writeFileSync19(p, s)
|
|
43660
44114
|
};
|
|
43661
|
-
fs.mkdir(
|
|
43662
|
-
fs.write(
|
|
44115
|
+
fs.mkdir(join43(opts.dir, "dev"));
|
|
44116
|
+
fs.write(join43(opts.dir, "dev", "net-mocks.json"), JSON.stringify(opts.mocks, null, 2) + "\n");
|
|
43663
44117
|
return { ok: true, rules, to: "dev/net-mocks.json" };
|
|
43664
44118
|
}
|
|
43665
44119
|
function scopeDescriptors(descriptors, requestedIds, invalidScreens) {
|
|
@@ -43973,12 +44427,12 @@ async function runCrawl(opts) {
|
|
|
43973
44427
|
};
|
|
43974
44428
|
}
|
|
43975
44429
|
function describeTransport(net, opts, ran) {
|
|
43976
|
-
const
|
|
43977
|
-
if (net)
|
|
44430
|
+
const layers2 = [];
|
|
44431
|
+
if (net) layers2.push(`mocked (${net.from})`);
|
|
43978
44432
|
const cmsCount = Object.keys(opts.cmsSeed ?? {}).length;
|
|
43979
|
-
if (cmsCount)
|
|
43980
|
-
if (opts.canned?.count)
|
|
43981
|
-
const base =
|
|
44433
|
+
if (cmsCount) layers2.push(`cms (${cmsCount} seeded collection${cmsCount === 1 ? "" : "s"})`);
|
|
44434
|
+
if (opts.canned?.count) layers2.push(`canned (${opts.canned.count} frozen endpoints, ${opts.canned.from} \u2014 exercises code paths, not API-contract truth)`);
|
|
44435
|
+
const base = layers2.length ? layers2.join(" + ") : "offline (no net fixture \u2014 screens are crawled against a rejecting transport, which exercises their failure UI)";
|
|
43982
44436
|
const hostile = ran.hostile ? " + hostile boot passes (empty-lists, all-500)" : "";
|
|
43983
44437
|
const relations = ran.relations ? " + relations" : "";
|
|
43984
44438
|
const deep = ran.deep ? ` + deep chains (depth ${opts.deep})` : "";
|
|
@@ -44116,14 +44570,14 @@ var mobile_ux_lint_exports = {};
|
|
|
44116
44570
|
__export(mobile_ux_lint_exports, {
|
|
44117
44571
|
mobileUxIssues: () => mobileUxIssues
|
|
44118
44572
|
});
|
|
44119
|
-
import { existsSync as
|
|
44120
|
-
import { join as
|
|
44573
|
+
import { existsSync as existsSync47, readFileSync as readFileSync51 } from "node:fs";
|
|
44574
|
+
import { join as join44 } from "node:path";
|
|
44121
44575
|
function mobileUxIssues(dir, strict) {
|
|
44122
|
-
const file =
|
|
44123
|
-
if (!
|
|
44576
|
+
const file = join44(dir, "MOBILE-UX.md");
|
|
44577
|
+
if (!existsSync47(file)) return [];
|
|
44124
44578
|
let text5;
|
|
44125
44579
|
try {
|
|
44126
|
-
text5 =
|
|
44580
|
+
text5 = readFileSync51(file, "utf8");
|
|
44127
44581
|
} catch {
|
|
44128
44582
|
return [];
|
|
44129
44583
|
}
|
|
@@ -45798,8 +46252,8 @@ __export(functions_exports, {
|
|
|
45798
46252
|
resolveFunctionsTarget: () => resolveFunctionsTarget,
|
|
45799
46253
|
runRemoteFunctionOperation: () => runRemoteFunctionOperation
|
|
45800
46254
|
});
|
|
45801
|
-
import { readFileSync as
|
|
45802
|
-
import { join as
|
|
46255
|
+
import { readFileSync as readFileSync52, existsSync as existsSync48 } from "node:fs";
|
|
46256
|
+
import { join as join45, resolve as resolve41 } from "node:path";
|
|
45803
46257
|
function resolveFunctionsTarget(input) {
|
|
45804
46258
|
const explicitUrl = input.functionsUrl?.trim();
|
|
45805
46259
|
if (explicitUrl) return { mode: "remote", baseUrl: explicitUrl };
|
|
@@ -45818,9 +46272,9 @@ async function loadFunctionsApp(dir) {
|
|
|
45818
46272
|
}
|
|
45819
46273
|
const sources = {};
|
|
45820
46274
|
for (const definition of config.functions.functions) {
|
|
45821
|
-
const source = [".ts", ".js", ".mts", ".mjs"].map((extension) =>
|
|
46275
|
+
const source = [".ts", ".js", ".mts", ".mjs"].map((extension) => join45(loaded.dir, "functions", `${definition.name}${extension}`)).find(existsSync48);
|
|
45822
46276
|
if (!source) throw new Error(`missing source for function ${definition.name}; expected functions/${definition.name}.ts`);
|
|
45823
|
-
sources[definition.name] =
|
|
46277
|
+
sources[definition.name] = readFileSync52(source, "utf8");
|
|
45824
46278
|
}
|
|
45825
46279
|
const data = config.cms || config.data ? mergeDataResources(config) : void 0;
|
|
45826
46280
|
const dataErrors = validateDataResources(data, loaded.name).filter((issue2) => issue2.severity === "error");
|
|
@@ -45972,14 +46426,14 @@ __export(studio_reel_exports, {
|
|
|
45972
46426
|
utcDay: () => utcDay
|
|
45973
46427
|
});
|
|
45974
46428
|
import { createHash as createHash24 } from "node:crypto";
|
|
45975
|
-
import { lstatSync as lstatSync7, readFileSync as
|
|
45976
|
-
import { basename as basename11, join as
|
|
46429
|
+
import { lstatSync as lstatSync7, readFileSync as readFileSync53 } from "node:fs";
|
|
46430
|
+
import { basename as basename11, join as join46 } from "node:path";
|
|
45977
46431
|
function loadMemory2(dir) {
|
|
45978
|
-
const m = readJson4(
|
|
45979
|
-
if (!
|
|
46432
|
+
const m = readJson4(join46(dir, ".himi", "studio", "memory.json"));
|
|
46433
|
+
if (!isObj2(m) || m.version !== 1 || !isObj2(m.shots) || !Array.isArray(m.timeline)) return null;
|
|
45980
46434
|
const shots = [];
|
|
45981
46435
|
for (const [id, s] of Object.entries(m.shots)) {
|
|
45982
|
-
if (!
|
|
46436
|
+
if (!isObj2(s)) continue;
|
|
45983
46437
|
const file = historyName(s.sha, s.ext);
|
|
45984
46438
|
const firstSeen = str(s.firstSeen);
|
|
45985
46439
|
if (!file || !firstSeen) continue;
|
|
@@ -45988,7 +46442,7 @@ function loadMemory2(dir) {
|
|
|
45988
46442
|
}
|
|
45989
46443
|
const timeline = [];
|
|
45990
46444
|
for (const t of m.timeline) {
|
|
45991
|
-
if (!
|
|
46445
|
+
if (!isObj2(t)) continue;
|
|
45992
46446
|
const file = historyName(t.sha, t.ext);
|
|
45993
46447
|
const ts2 = str(t.ts);
|
|
45994
46448
|
const id = str(t.id);
|
|
@@ -46012,8 +46466,8 @@ function planReel(dir) {
|
|
|
46012
46466
|
const memory = loadMemory2(dir);
|
|
46013
46467
|
const { entries } = readProgress(dir);
|
|
46014
46468
|
const summary = summarizeProgress(entries);
|
|
46015
|
-
const manifest = readJson4(
|
|
46016
|
-
const tokens = readJson4(
|
|
46469
|
+
const manifest = readJson4(join46(dir, "himalaya.content.json"));
|
|
46470
|
+
const tokens = readJson4(join46(dir, "tokens.json"));
|
|
46017
46471
|
const accentToken = tokens?.colors?.accentPrimary;
|
|
46018
46472
|
const accentRaw = typeof accentToken === "string" ? accentToken : accentToken?.light;
|
|
46019
46473
|
const accent = typeof accentRaw === "string" && ACCENT.test(accentRaw) ? accentRaw : DEFAULT_ACCENT;
|
|
@@ -46028,7 +46482,7 @@ function planReel(dir) {
|
|
|
46028
46482
|
ts: e.ts,
|
|
46029
46483
|
message: e.message,
|
|
46030
46484
|
step: str(e.step),
|
|
46031
|
-
files: (Array.isArray(e.images) ? e.images : []).map((i) =>
|
|
46485
|
+
files: (Array.isArray(e.images) ? e.images : []).map((i) => isObj2(i) && typeof i.file === "string" ? basename11(i.file) : "").filter((f) => HISTORY_NAME.test(f))
|
|
46032
46486
|
}));
|
|
46033
46487
|
const times = [summary.startedAt, ...timeline.map((t) => t.ts), memory?.createdAt].filter((x) => !!x).sort();
|
|
46034
46488
|
const startedAt = times[0] ?? null;
|
|
@@ -46055,10 +46509,10 @@ function inlineImages(dir, plan, budget = REEL_BUDGET_BYTES) {
|
|
|
46055
46509
|
const verified = (f) => {
|
|
46056
46510
|
if (!HISTORY_NAME.test(f)) return null;
|
|
46057
46511
|
try {
|
|
46058
|
-
const path2 =
|
|
46512
|
+
const path2 = join46(dir, HISTORY_DIR, f);
|
|
46059
46513
|
const st = lstatSync7(path2);
|
|
46060
46514
|
if (!st.isFile() || st.nlink !== 1) return null;
|
|
46061
|
-
const bytes2 =
|
|
46515
|
+
const bytes2 = readFileSync53(path2);
|
|
46062
46516
|
return createHash24("sha256").update(bytes2).digest("hex") === f.slice(0, 64) && imageExtension(bytes2) === f.slice(65) ? bytes2 : null;
|
|
46063
46517
|
} catch {
|
|
46064
46518
|
return null;
|
|
@@ -46178,7 +46632,7 @@ function buildReel(dir, budget = REEL_BUDGET_BYTES) {
|
|
|
46178
46632
|
const { plan, images } = inlineImages(dir, planReel(dir), budget);
|
|
46179
46633
|
return { html: renderReel(plan, images), plan };
|
|
46180
46634
|
}
|
|
46181
|
-
var REEL_BUDGET_BYTES, MAX_FLIP_FRAMES, DEFAULT_ACCENT, ACCENT, HISTORY_NAME, MIME2, mimeOf, readJson4,
|
|
46635
|
+
var REEL_BUDGET_BYTES, MAX_FLIP_FRAMES, DEFAULT_ACCENT, ACCENT, HISTORY_NAME, MIME2, mimeOf, readJson4, isObj2, str, historyName, cited;
|
|
46182
46636
|
var init_studio_reel = __esm({
|
|
46183
46637
|
"src/studio-reel.ts"() {
|
|
46184
46638
|
init_progress();
|
|
@@ -46192,12 +46646,12 @@ var init_studio_reel = __esm({
|
|
|
46192
46646
|
mimeOf = (file) => MIME2[file.slice(65)] ?? "image/png";
|
|
46193
46647
|
readJson4 = (file) => {
|
|
46194
46648
|
try {
|
|
46195
|
-
return JSON.parse(
|
|
46649
|
+
return JSON.parse(readFileSync53(file, "utf8"));
|
|
46196
46650
|
} catch {
|
|
46197
46651
|
return null;
|
|
46198
46652
|
}
|
|
46199
46653
|
};
|
|
46200
|
-
|
|
46654
|
+
isObj2 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
46201
46655
|
str = (v) => typeof v === "string" && v ? v : null;
|
|
46202
46656
|
historyName = (sha, ext) => typeof sha === "string" && typeof ext === "string" && HISTORY_NAME.test(`${sha}.${ext}`) ? `${sha}.${ext}` : null;
|
|
46203
46657
|
cited = (p) => [
|
|
@@ -46223,9 +46677,9 @@ __export(native_decode_exports, {
|
|
|
46223
46677
|
runNativeDecode: () => runNativeDecode
|
|
46224
46678
|
});
|
|
46225
46679
|
import { execFileSync as execFileSync5, spawnSync as spawnSync2 } from "node:child_process";
|
|
46226
|
-
import { existsSync as
|
|
46680
|
+
import { existsSync as existsSync49, mkdtempSync as mkdtempSync2, readFileSync as readFileSync54, rmSync as rmSync11, writeFileSync as writeFileSync20 } from "node:fs";
|
|
46227
46681
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
46228
|
-
import { join as
|
|
46682
|
+
import { join as join47 } from "node:path";
|
|
46229
46683
|
import { fileURLToPath as fileURLToPath20 } from "node:url";
|
|
46230
46684
|
function nativeDecodePackageDir() {
|
|
46231
46685
|
return fileURLToPath20(new URL("../../../core/runtime/ios/HimalayaCore/", import.meta.url));
|
|
@@ -46235,8 +46689,8 @@ function nativeDecodeAndroidHarnessDir() {
|
|
|
46235
46689
|
}
|
|
46236
46690
|
function nativeOracleShipped() {
|
|
46237
46691
|
return {
|
|
46238
|
-
ios:
|
|
46239
|
-
android:
|
|
46692
|
+
ios: existsSync49(join47(nativeDecodePackageDir(), "Package.swift")),
|
|
46693
|
+
android: existsSync49(join47(nativeDecodeAndroidHarnessDir(), "gradlew"))
|
|
46240
46694
|
};
|
|
46241
46695
|
}
|
|
46242
46696
|
function detectNativeDecode(options = {}) {
|
|
@@ -46247,7 +46701,7 @@ function detectNativeDecode(options = {}) {
|
|
|
46247
46701
|
return { platform: "ios", available: false, reason: `the iOS decoder oracle requires macOS (darwin); this host is ${hostPlatform}` };
|
|
46248
46702
|
}
|
|
46249
46703
|
if (!swiftAvailable) return { platform: "ios", available: false, reason: "swift is not on PATH" };
|
|
46250
|
-
const packageAvailable = options.packageAvailable ??
|
|
46704
|
+
const packageAvailable = options.packageAvailable ?? existsSync49(join47(packageDir, "Package.swift"));
|
|
46251
46705
|
if (!packageAvailable) {
|
|
46252
46706
|
return {
|
|
46253
46707
|
platform: "ios",
|
|
@@ -46259,7 +46713,7 @@ function detectNativeDecode(options = {}) {
|
|
|
46259
46713
|
}
|
|
46260
46714
|
function localPropertiesSdk(harnessDir) {
|
|
46261
46715
|
try {
|
|
46262
|
-
const match =
|
|
46716
|
+
const match = readFileSync54(join47(harnessDir, "local.properties"), "utf8").match(/^sdk\.dir\s*=\s*(.+)$/m);
|
|
46263
46717
|
return match?.[1]?.trim().replace(/\\([ :\\])/g, "$1") ?? null;
|
|
46264
46718
|
} catch {
|
|
46265
46719
|
return null;
|
|
@@ -46267,8 +46721,8 @@ function localPropertiesSdk(harnessDir) {
|
|
|
46267
46721
|
}
|
|
46268
46722
|
function detectAndroidNativeDecode(options = {}) {
|
|
46269
46723
|
const harnessDir = options.harnessDir ?? nativeDecodeAndroidHarnessDir();
|
|
46270
|
-
const gradlew =
|
|
46271
|
-
const gradlewAvailable = options.gradlewAvailable ??
|
|
46724
|
+
const gradlew = join47(harnessDir, "gradlew");
|
|
46725
|
+
const gradlewAvailable = options.gradlewAvailable ?? existsSync49(gradlew);
|
|
46272
46726
|
if (!gradlewAvailable) {
|
|
46273
46727
|
return {
|
|
46274
46728
|
platform: "android",
|
|
@@ -46278,7 +46732,7 @@ function detectAndroidNativeDecode(options = {}) {
|
|
|
46278
46732
|
}
|
|
46279
46733
|
const androidHome = options.androidHome ?? process.env.ANDROID_HOME ?? "";
|
|
46280
46734
|
const sdk = androidHome.trim() || (options.localPropertiesSdk !== void 0 ? options.localPropertiesSdk : localPropertiesSdk(harnessDir));
|
|
46281
|
-
const sdkAvailable = options.sdkAvailable ?? (typeof sdk === "string" && sdk.length > 0 &&
|
|
46735
|
+
const sdkAvailable = options.sdkAvailable ?? (typeof sdk === "string" && sdk.length > 0 && existsSync49(sdk));
|
|
46282
46736
|
if (!sdkAvailable) {
|
|
46283
46737
|
return {
|
|
46284
46738
|
platform: "android",
|
|
@@ -46350,14 +46804,14 @@ function parseNativeDecodeOutput(stdout, expectedScreenIds, platform = "ios") {
|
|
|
46350
46804
|
return verdicts;
|
|
46351
46805
|
}
|
|
46352
46806
|
function runNativeDecode(options) {
|
|
46353
|
-
const descriptorDir = mkdtempSync2(
|
|
46807
|
+
const descriptorDir = mkdtempSync2(join47(tmpdir3(), "himi-native-decode-"));
|
|
46354
46808
|
const startedAt = Date.now();
|
|
46355
46809
|
try {
|
|
46356
46810
|
for (const descriptor of options.descriptors) {
|
|
46357
46811
|
if (typeof descriptor.descriptorJson !== "string") {
|
|
46358
46812
|
throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
|
|
46359
46813
|
}
|
|
46360
|
-
writeFileSync20(
|
|
46814
|
+
writeFileSync20(join47(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
|
|
46361
46815
|
}
|
|
46362
46816
|
options.progress?.("building cached Swift oracle");
|
|
46363
46817
|
execFileSync5("swift", ["build", "--package-path", options.packageDir, "--product", "himi-decode-oracle"], {
|
|
@@ -46369,7 +46823,7 @@ function runNativeDecode(options) {
|
|
|
46369
46823
|
encoding: "utf8"
|
|
46370
46824
|
}).trim();
|
|
46371
46825
|
options.progress?.(`running real Swift decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
|
|
46372
|
-
const stdout = execFileSync5(
|
|
46826
|
+
const stdout = execFileSync5(join47(binPath, "himi-decode-oracle"), ["--dir", descriptorDir], {
|
|
46373
46827
|
stdio: ["ignore", "pipe", "pipe"],
|
|
46374
46828
|
encoding: "utf8"
|
|
46375
46829
|
});
|
|
@@ -46387,15 +46841,15 @@ function runNativeDecode(options) {
|
|
|
46387
46841
|
}
|
|
46388
46842
|
}
|
|
46389
46843
|
function runAndroidNativeDecode(options) {
|
|
46390
|
-
const descriptorDir = mkdtempSync2(
|
|
46391
|
-
const outputPath =
|
|
46844
|
+
const descriptorDir = mkdtempSync2(join47(tmpdir3(), "himi-native-decode-android-"));
|
|
46845
|
+
const outputPath = join47(descriptorDir, "verdicts.ndjson");
|
|
46392
46846
|
const startedAt = Date.now();
|
|
46393
46847
|
try {
|
|
46394
46848
|
for (const descriptor of options.descriptors) {
|
|
46395
46849
|
if (typeof descriptor.descriptorJson !== "string") {
|
|
46396
46850
|
throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
|
|
46397
46851
|
}
|
|
46398
|
-
writeFileSync20(
|
|
46852
|
+
writeFileSync20(join47(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
|
|
46399
46853
|
}
|
|
46400
46854
|
options.progress?.(`running real Kotlin decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
|
|
46401
46855
|
execFileSync5(options.gradlew, [
|
|
@@ -46410,7 +46864,7 @@ function runAndroidNativeDecode(options) {
|
|
|
46410
46864
|
stdio: ["ignore", "ignore", "pipe"],
|
|
46411
46865
|
encoding: "utf8"
|
|
46412
46866
|
});
|
|
46413
|
-
const stdout =
|
|
46867
|
+
const stdout = readFileSync54(outputPath, "utf8");
|
|
46414
46868
|
return {
|
|
46415
46869
|
platform: "android",
|
|
46416
46870
|
verdicts: parseNativeDecodeOutput(stdout, options.descriptors.map((descriptor) => descriptor.screenId), "android"),
|
|
@@ -46480,13 +46934,13 @@ __export(browser_authoring_exports, {
|
|
|
46480
46934
|
});
|
|
46481
46935
|
import { createServer as createServer3 } from "node:http";
|
|
46482
46936
|
import { createHash as createHash25, randomBytes as randomBytes4 } from "node:crypto";
|
|
46483
|
-
import { existsSync as
|
|
46484
|
-
import { join as
|
|
46937
|
+
import { existsSync as existsSync50, readdirSync as readdirSync24, readFileSync as readFileSync55, realpathSync as realpathSync5, statSync as statSync12 } from "node:fs";
|
|
46938
|
+
import { join as join48, posix, relative as relative8, sep as sep12 } from "node:path";
|
|
46485
46939
|
function humanMs(ms) {
|
|
46486
46940
|
return ms < 1e3 ? `${ms}ms` : `${Math.round(ms / 1e3)}s`;
|
|
46487
46941
|
}
|
|
46488
46942
|
function collectWorkerSources(tier5SrcDir, bundleName) {
|
|
46489
|
-
const root =
|
|
46943
|
+
const root = join48(tier5SrcDir, bundleName);
|
|
46490
46944
|
const files = {};
|
|
46491
46945
|
const visitedDirs = /* @__PURE__ */ new Set();
|
|
46492
46946
|
const walk2 = (abs, rel) => {
|
|
@@ -46494,16 +46948,16 @@ function collectWorkerSources(tier5SrcDir, bundleName) {
|
|
|
46494
46948
|
if (visitedDirs.has(real)) return;
|
|
46495
46949
|
visitedDirs.add(real);
|
|
46496
46950
|
for (const name of readdirSync24(abs).sort()) {
|
|
46497
|
-
const childAbs =
|
|
46951
|
+
const childAbs = join48(abs, name);
|
|
46498
46952
|
const childRel = posix.join(rel, name);
|
|
46499
46953
|
if (statSync12(childAbs).isDirectory()) {
|
|
46500
46954
|
walk2(childAbs, childRel);
|
|
46501
46955
|
} else if (/\.(ts|tsx|js|mjs|json)$/.test(name)) {
|
|
46502
|
-
files[childRel] =
|
|
46956
|
+
files[childRel] = readFileSync55(childAbs, "utf8");
|
|
46503
46957
|
}
|
|
46504
46958
|
}
|
|
46505
46959
|
};
|
|
46506
|
-
if (!
|
|
46960
|
+
if (!existsSync50(root)) return null;
|
|
46507
46961
|
walk2(root, `/tier5-src/${bundleName}`);
|
|
46508
46962
|
const entry = [`/tier5-src/${bundleName}/index.ts`, `/tier5-src/${bundleName}/index.js`].find((p) => p in files);
|
|
46509
46963
|
if (!entry) return null;
|
|
@@ -46520,20 +46974,20 @@ function collectRelativeSiblings(files, tier5SrcDir) {
|
|
|
46520
46974
|
const spec = m[1];
|
|
46521
46975
|
const virtual = posix.normalize(posix.join(dir, spec));
|
|
46522
46976
|
if (!virtual.startsWith("/tier5-src/")) continue;
|
|
46523
|
-
const onDisk =
|
|
46977
|
+
const onDisk = join48(tier5SrcDir, virtual.slice("/tier5-src/".length));
|
|
46524
46978
|
const candidates = [
|
|
46525
46979
|
onDisk,
|
|
46526
46980
|
`${onDisk}.ts`,
|
|
46527
46981
|
`${onDisk}.js`,
|
|
46528
46982
|
onDisk.replace(/\.js$/, ".ts"),
|
|
46529
|
-
|
|
46530
|
-
|
|
46983
|
+
join48(onDisk, "index.ts"),
|
|
46984
|
+
join48(onDisk, "index.js")
|
|
46531
46985
|
];
|
|
46532
46986
|
for (const abs of candidates) {
|
|
46533
|
-
if (!
|
|
46987
|
+
if (!existsSync50(abs) || statSync12(abs).isDirectory()) continue;
|
|
46534
46988
|
const key2 = `/tier5-src/${relative8(tier5SrcDir, abs).split(sep12).join(posix.sep)}`;
|
|
46535
46989
|
if (key2 in files) break;
|
|
46536
|
-
files[key2] =
|
|
46990
|
+
files[key2] = readFileSync55(abs, "utf8");
|
|
46537
46991
|
queue.push(key2);
|
|
46538
46992
|
break;
|
|
46539
46993
|
}
|
|
@@ -46568,7 +47022,7 @@ function collectSdkModules(files, resolveSubpath) {
|
|
|
46568
47022
|
function sdkSubpathReader(resolve48) {
|
|
46569
47023
|
return (sub) => {
|
|
46570
47024
|
try {
|
|
46571
|
-
return
|
|
47025
|
+
return readFileSync55(resolve48(`@wix/himalaya/${sub}`), "utf8");
|
|
46572
47026
|
} catch {
|
|
46573
47027
|
return null;
|
|
46574
47028
|
}
|
|
@@ -46740,8 +47194,8 @@ __export(coverage_exports, {
|
|
|
46740
47194
|
suppressedNativeKeys: () => suppressedNativeKeys,
|
|
46741
47195
|
trendAndStore: () => trendAndStore
|
|
46742
47196
|
});
|
|
46743
|
-
import { existsSync as
|
|
46744
|
-
import { dirname as dirname26, join as
|
|
47197
|
+
import { existsSync as existsSync51, mkdirSync as mkdirSync24, readFileSync as readFileSync56, writeFileSync as writeFileSync21 } from "node:fs";
|
|
47198
|
+
import { dirname as dirname26, join as join49 } from "node:path";
|
|
46745
47199
|
function suppressedNativeKeys(oracle) {
|
|
46746
47200
|
return [...oracle.ios ? [] : ["native-decode|ios"], ...oracle.android ? [] : ["native-decode|android"]];
|
|
46747
47201
|
}
|
|
@@ -46921,11 +47375,11 @@ function assembleLedger(r, options = {}) {
|
|
|
46921
47375
|
return out;
|
|
46922
47376
|
}
|
|
46923
47377
|
function trendAndStore(dir, entries, suppressed) {
|
|
46924
|
-
const p =
|
|
47378
|
+
const p = join49(dir, LEDGER_FILE);
|
|
46925
47379
|
let previous = null;
|
|
46926
47380
|
try {
|
|
46927
|
-
if (
|
|
46928
|
-
const parsed = JSON.parse(
|
|
47381
|
+
if (existsSync51(p)) {
|
|
47382
|
+
const parsed = JSON.parse(readFileSync56(p, "utf8"));
|
|
46929
47383
|
if (Array.isArray(parsed.keys)) previous = parsed.keys.filter((k) => typeof k === "string");
|
|
46930
47384
|
}
|
|
46931
47385
|
} catch {
|
|
@@ -46964,11 +47418,11 @@ function formatLedger(entries, trend) {
|
|
|
46964
47418
|
return out.join("\n");
|
|
46965
47419
|
}
|
|
46966
47420
|
function diffAndStoreObservations(dir, current) {
|
|
46967
|
-
const p =
|
|
47421
|
+
const p = join49(dir, OBS_FILE);
|
|
46968
47422
|
let previous = null;
|
|
46969
47423
|
try {
|
|
46970
|
-
if (
|
|
46971
|
-
const parsed = JSON.parse(
|
|
47424
|
+
if (existsSync51(p)) {
|
|
47425
|
+
const parsed = JSON.parse(readFileSync56(p, "utf8"));
|
|
46972
47426
|
if (parsed.screens && typeof parsed.screens === "object" && !Array.isArray(parsed.screens) && Object.values(parsed.screens).every(
|
|
46973
47427
|
(v) => Array.isArray(v) && v.every((l) => typeof l === "string")
|
|
46974
47428
|
)) {
|
|
@@ -47017,8 +47471,8 @@ var LEDGER_FILE, OBS_FILE;
|
|
|
47017
47471
|
var init_coverage = __esm({
|
|
47018
47472
|
"src/coverage.ts"() {
|
|
47019
47473
|
init_native_decode();
|
|
47020
|
-
LEDGER_FILE =
|
|
47021
|
-
OBS_FILE =
|
|
47474
|
+
LEDGER_FILE = join49(".himi", "test-ledger.json");
|
|
47475
|
+
OBS_FILE = join49(".himi", "test-observations.json");
|
|
47022
47476
|
}
|
|
47023
47477
|
});
|
|
47024
47478
|
|
|
@@ -47029,11 +47483,11 @@ __export(design_kits_exports, {
|
|
|
47029
47483
|
kitsDir: () => kitsDir,
|
|
47030
47484
|
listKits: () => listKits2
|
|
47031
47485
|
});
|
|
47032
|
-
import { existsSync as
|
|
47033
|
-
import { join as
|
|
47486
|
+
import { existsSync as existsSync52, readFileSync as readFileSync57, readdirSync as readdirSync25 } from "node:fs";
|
|
47487
|
+
import { join as join50, basename as basename12 } from "node:path";
|
|
47034
47488
|
import { fileURLToPath as fileURLToPath21 } from "node:url";
|
|
47035
47489
|
function kitsDir() {
|
|
47036
|
-
return KIT_DIR_CANDIDATES.find((p) =>
|
|
47490
|
+
return KIT_DIR_CANDIDATES.find((p) => existsSync52(p));
|
|
47037
47491
|
}
|
|
47038
47492
|
function listKits2() {
|
|
47039
47493
|
const dir = kitsDir();
|
|
@@ -47057,7 +47511,7 @@ In a published @wix/himalaya-cli this is a packaging bug \u2014 the kits should
|
|
|
47057
47511
|
if (!kits.includes(name)) {
|
|
47058
47512
|
return { ok: false, kit: name, kits, problems: [`no design kit named "${name}". Available: ${kits.join(", ")}`] };
|
|
47059
47513
|
}
|
|
47060
|
-
const raw =
|
|
47514
|
+
const raw = readFileSync57(join50(dir, `${name}.json`), "utf8");
|
|
47061
47515
|
let parsed;
|
|
47062
47516
|
try {
|
|
47063
47517
|
parsed = JSON.parse(raw);
|
|
@@ -47081,9 +47535,9 @@ var init_design_kits = __esm({
|
|
|
47081
47535
|
"src/design-kits.ts"() {
|
|
47082
47536
|
KIT_DIR_CANDIDATES = [
|
|
47083
47537
|
// in-repo: tools/himi-cli/src/design-kits.ts → <repo>/stdlib/design-kits/
|
|
47084
|
-
|
|
47538
|
+
join50(fileURLToPath21(new URL("../../..", import.meta.url)), "stdlib", "design-kits"),
|
|
47085
47539
|
// published CLI: <pkg>/dist/cli.mjs → <pkg>/stdlib/design-kits/
|
|
47086
|
-
|
|
47540
|
+
join50(fileURLToPath21(new URL("..", import.meta.url)), "stdlib", "design-kits")
|
|
47087
47541
|
];
|
|
47088
47542
|
}
|
|
47089
47543
|
});
|
|
@@ -47097,11 +47551,11 @@ __export(assets_exports, {
|
|
|
47097
47551
|
removeAssetPayload: () => removeAssetPayload,
|
|
47098
47552
|
verifyReport: () => verifyReport
|
|
47099
47553
|
});
|
|
47100
|
-
import { readFileSync as
|
|
47554
|
+
import { readFileSync as readFileSync58 } from "node:fs";
|
|
47101
47555
|
import { basename as basename13 } from "node:path";
|
|
47102
47556
|
function declaredAssets(dir) {
|
|
47103
47557
|
return collectAssets(dir).map((a) => {
|
|
47104
|
-
const bytes2 =
|
|
47558
|
+
const bytes2 = readFileSync58(a.path);
|
|
47105
47559
|
return {
|
|
47106
47560
|
name: a.name,
|
|
47107
47561
|
sha256: assetSha256(bytes2),
|
|
@@ -47178,7 +47632,7 @@ function verifyReport(dir, app, manifest) {
|
|
|
47178
47632
|
};
|
|
47179
47633
|
}
|
|
47180
47634
|
function addAssetPayload(manifest, filePath, opts) {
|
|
47181
|
-
const bytes2 =
|
|
47635
|
+
const bytes2 = readFileSync58(filePath);
|
|
47182
47636
|
const name = opts.name ?? basename13(filePath);
|
|
47183
47637
|
const sha2565 = assetSha256(bytes2);
|
|
47184
47638
|
const record2 = {
|
|
@@ -48493,7 +48947,14 @@ function indexHtml(asset, pathname, creds, handoverAttempted = false) {
|
|
|
48493
48947
|
headers: {
|
|
48494
48948
|
"content-type": asset.contentType || "text/html; charset=utf-8",
|
|
48495
48949
|
"cache-control": creds || handoverAttempted ? "no-store" : "public, max-age=60, stale-while-revalidate=600",
|
|
48496
|
-
"content-security-policy": previewCsp(nonce)
|
|
48950
|
+
"content-security-policy": previewCsp(nonce),
|
|
48951
|
+
// This document's URL can name a credential: `?pvt=` (still accepted from an embedder such
|
|
48952
|
+
// as the dashboard frame) or a `?h=` code before the inline script strips it. The browser
|
|
48953
|
+
// default sends the FULL URL as `Referer` on same-origin requests, so every `/v1/*` read,
|
|
48954
|
+
// the gateway's request log and the Tier-5 frame's `document.referrer` would carry it.
|
|
48955
|
+
// `strict-origin` sends the origin alone. Not `no-referrer`: that also turns a same-origin
|
|
48956
|
+
// POST's `Origin` header into `null`, and `/v1/telemetry/ingest` is one (#2386).
|
|
48957
|
+
"referrer-policy": "strict-origin"
|
|
48497
48958
|
}
|
|
48498
48959
|
});
|
|
48499
48960
|
}
|
|
@@ -48527,7 +48988,7 @@ function previewResponse(pathname, assets, mount = "/preview", creds, handoverAt
|
|
|
48527
48988
|
var T5_FRAME_CSP, PREVIEW_BASE_JS, PREVIEW_ENTRY_RECOVERY_JS, MOUNT_STRIP;
|
|
48528
48989
|
var init_preview2 = __esm({
|
|
48529
48990
|
"../../packages/serve/src/preview.ts"() {
|
|
48530
|
-
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'";
|
|
48991
|
+
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'; sandbox allow-scripts";
|
|
48531
48992
|
PREVIEW_BASE_JS = // Both serve mounts (/preview framed + /app unframed — RFC 0051 track D) serve the SAME
|
|
48532
48993
|
// embedded artifact, so one shim derives whichever mount the browser is on. Non-greedy:
|
|
48533
48994
|
// the EARLIEST mount segment wins, mirroring the SPA's own deployBase (an app literally
|
|
@@ -48780,21 +49241,21 @@ var init_preview_assets_generated = __esm({
|
|
|
48780
49241
|
"../../packages/serve/src/preview-assets.generated.ts"() {
|
|
48781
49242
|
init_preview_assets_format();
|
|
48782
49243
|
PREVIEW_ASSET_MANIFEST = [
|
|
48783
|
-
{ key: "assets/index-
|
|
48784
|
-
{ key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset:
|
|
48785
|
-
{ key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset:
|
|
48786
|
-
{ key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset:
|
|
48787
|
-
{ key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset:
|
|
48788
|
-
{ key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset:
|
|
48789
|
-
{ key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset:
|
|
48790
|
-
{ key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset:
|
|
48791
|
-
{ key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset:
|
|
48792
|
-
{ key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset:
|
|
48793
|
-
{ key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset:
|
|
48794
|
-
{ key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset:
|
|
48795
|
-
{ key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset:
|
|
48796
|
-
{ key: "index.html", contentType: "text/html; charset=utf-8", offset:
|
|
48797
|
-
{ key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset:
|
|
49244
|
+
{ key: "assets/index-Dn3oPAne.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1044844, sha256: "7b781f264f2aac500b00ea4def7cb6f3c19e46dd4ebb3b797de5da8386056543" },
|
|
49245
|
+
{ key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 1044852, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
|
|
49246
|
+
{ key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 1049462, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
|
|
49247
|
+
{ key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1538046, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
|
|
49248
|
+
{ key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1628970, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
|
|
49249
|
+
{ key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1719954, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
|
|
49250
|
+
{ key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1810934, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
|
|
49251
|
+
{ key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1901806, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
|
|
49252
|
+
{ key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1992786, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
|
|
49253
|
+
{ key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 2101422, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
|
|
49254
|
+
{ key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 2210506, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
|
|
49255
|
+
{ key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 2319554, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
|
|
49256
|
+
{ key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 2427254, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
|
|
49257
|
+
{ key: "index.html", contentType: "text/html; charset=utf-8", offset: 2515362, length: 4947, sha256: "25d01e5f772c7b782ca7c68f997765d3838295369054c0855ba63320d071ec22" },
|
|
49258
|
+
{ key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 2520309, length: 17209, sha256: "dffc9718e2faa63ae2cc919e0a842f585ed565aaaa7c53778e90379442c731b6" }
|
|
48798
49259
|
];
|
|
48799
49260
|
}
|
|
48800
49261
|
});
|
|
@@ -48810,9 +49271,9 @@ __export(run_exports, {
|
|
|
48810
49271
|
runPackage: () => runPackage,
|
|
48811
49272
|
withoutProdServe: () => withoutProdServe
|
|
48812
49273
|
});
|
|
48813
|
-
import { cpSync as cpSync2, existsSync as
|
|
49274
|
+
import { cpSync as cpSync2, existsSync as existsSync53, mkdirSync as mkdirSync25, mkdtempSync as mkdtempSync3, readFileSync as readFileSync59, rmSync as rmSync12, statSync as statSync13 } from "node:fs";
|
|
48814
49275
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
48815
|
-
import { dirname as dirname27, join as
|
|
49276
|
+
import { dirname as dirname27, join as join51 } from "node:path";
|
|
48816
49277
|
import { fileURLToPath as fileURLToPath22 } from "node:url";
|
|
48817
49278
|
function makePackageRunHandler(opts) {
|
|
48818
49279
|
return makeRunHandler({
|
|
@@ -48831,9 +49292,9 @@ async function fetchBytes(url) {
|
|
|
48831
49292
|
}
|
|
48832
49293
|
async function resolvePackage(source, workDir) {
|
|
48833
49294
|
const isUrl2 = /^https?:\/\//i.test(source);
|
|
48834
|
-
if (!isUrl2 &&
|
|
48835
|
-
const appDirManifest =
|
|
48836
|
-
if (
|
|
49295
|
+
if (!isUrl2 && existsSync53(source) && statSync13(source).isDirectory()) {
|
|
49296
|
+
const appDirManifest = join51(source, "release-manifest.json");
|
|
49297
|
+
if (existsSync53(appDirManifest)) {
|
|
48837
49298
|
const opened2 = openPackageDir(source);
|
|
48838
49299
|
if (!opened2.validation.ok) {
|
|
48839
49300
|
throw new Error(`package is not valid:
|
|
@@ -48842,9 +49303,9 @@ async function resolvePackage(source, workDir) {
|
|
|
48842
49303
|
const app2 = opened2.header?.app ?? opened2.manifest?.app;
|
|
48843
49304
|
if (!app2) throw new Error(`${source} has no app id (no himi-package.json and no manifest.app)`);
|
|
48844
49305
|
if (!isSafeAppId(app2)) throw new Error(`${source} declares an unsafe app id ${JSON.stringify(app2)} \u2014 refusing to open it`);
|
|
48845
|
-
const root2 = workDir ?? mkdtempSync3(
|
|
48846
|
-
const target =
|
|
48847
|
-
if (
|
|
49306
|
+
const root2 = workDir ?? mkdtempSync3(join51(tmpdir4(), "himi-run-"));
|
|
49307
|
+
const target = join51(root2, app2);
|
|
49308
|
+
if (join51(source) !== target) {
|
|
48848
49309
|
mkdirSync25(root2, { recursive: true });
|
|
48849
49310
|
rmSync12(target, { recursive: true, force: true });
|
|
48850
49311
|
cpSync2(source, target, { recursive: true });
|
|
@@ -48861,8 +49322,8 @@ async function resolvePackage(source, workDir) {
|
|
|
48861
49322
|
}
|
|
48862
49323
|
throw new Error(`${source} is a directory but has no release-manifest.json \u2014 is it a package?`);
|
|
48863
49324
|
}
|
|
48864
|
-
const bytes2 = isUrl2 ? await fetchBytes(source) :
|
|
48865
|
-
const root = workDir ?? mkdtempSync3(
|
|
49325
|
+
const bytes2 = isUrl2 ? await fetchBytes(source) : readFileSync59(source);
|
|
49326
|
+
const root = workDir ?? mkdtempSync3(join51(tmpdir4(), "himi-run-"));
|
|
48866
49327
|
const { app, appDir: appDir2 } = unpackTo(bytes2, root);
|
|
48867
49328
|
const opened = openPackageDir(appDir2);
|
|
48868
49329
|
if (!opened.validation.ok) {
|
|
@@ -48885,14 +49346,14 @@ async function loadPreviewAssets() {
|
|
|
48885
49346
|
const mod = await Promise.resolve().then(() => (init_preview_assets_generated(), preview_assets_generated_exports));
|
|
48886
49347
|
const here = dirname27(fileURLToPath22(import.meta.url));
|
|
48887
49348
|
const candidates = [
|
|
48888
|
-
|
|
49349
|
+
join51(here, "preview-assets.generated.bin"),
|
|
48889
49350
|
// published: copied next to the bundled CLI
|
|
48890
|
-
|
|
49351
|
+
join51(here, "../../../packages/serve/src/preview-assets.generated.bin")
|
|
48891
49352
|
// in-repo checkout
|
|
48892
49353
|
];
|
|
48893
49354
|
for (const path2 of candidates) {
|
|
48894
|
-
if (!
|
|
48895
|
-
const blob =
|
|
49355
|
+
if (!existsSync53(path2)) continue;
|
|
49356
|
+
const blob = readFileSync59(path2);
|
|
48896
49357
|
return mod.assemblePreviewAssetsFromBlob(new Uint8Array(blob.buffer, blob.byteOffset, blob.byteLength));
|
|
48897
49358
|
}
|
|
48898
49359
|
return /* @__PURE__ */ new Map();
|
|
@@ -48987,9 +49448,9 @@ __export(run_watch_exports, {
|
|
|
48987
49448
|
watchedContentDir: () => watchedContentDir,
|
|
48988
49449
|
writeRunRecord: () => writeRunRecord
|
|
48989
49450
|
});
|
|
48990
|
-
import { closeSync as closeSync2, constants, existsSync as
|
|
49451
|
+
import { closeSync as closeSync2, constants, existsSync as existsSync54, fstatSync, lstatSync as lstatSync8, statSync as statSync14, mkdirSync as mkdirSync26, openSync as openSync2, readFileSync as readFileSync60, realpathSync as realpathSync6, renameSync as renameSync5, rmSync as rmSync13, writeFileSync as writeFileSync22, watch as fsWatch } from "node:fs";
|
|
48991
49452
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
48992
|
-
import { extname as extname4, join as
|
|
49453
|
+
import { extname as extname4, join as join52, resolve as resolve42, sep as sep13 } from "node:path";
|
|
48993
49454
|
function diffReleases(prev, next) {
|
|
48994
49455
|
const bundles = Object.keys(next.bundles).filter((b) => prev.bundles[b]?.sha256 !== next.bundles[b].sha256).sort();
|
|
48995
49456
|
const changedBundles = new Set(bundles);
|
|
@@ -49028,8 +49489,8 @@ function watchContent(dir, onChange, opts = {}) {
|
|
|
49028
49489
|
const watch2 = opts.watch ?? ((p, o, l) => fsWatch(p, o, (event, file) => l(event, file === null ? null : String(file))));
|
|
49029
49490
|
let timer = null;
|
|
49030
49491
|
const pending = /* @__PURE__ */ new Set();
|
|
49031
|
-
const
|
|
49032
|
-
if (!file || ignoredChange(file, (rel) => isDir(
|
|
49492
|
+
const watcher2 = watch2(dir, { recursive: true }, (_event, file) => {
|
|
49493
|
+
if (!file || ignoredChange(file, (rel) => isDir(join52(dir, rel)))) return;
|
|
49033
49494
|
pending.add(file);
|
|
49034
49495
|
if (timer) clearTimeout(timer);
|
|
49035
49496
|
timer = setTimeout(() => {
|
|
@@ -49042,7 +49503,7 @@ function watchContent(dir, onChange, opts = {}) {
|
|
|
49042
49503
|
return {
|
|
49043
49504
|
close() {
|
|
49044
49505
|
if (timer) clearTimeout(timer);
|
|
49045
|
-
|
|
49506
|
+
watcher2.close();
|
|
49046
49507
|
}
|
|
49047
49508
|
};
|
|
49048
49509
|
}
|
|
@@ -49050,7 +49511,7 @@ function watchedContentDir(source) {
|
|
|
49050
49511
|
if (!source || /^https?:\/\//i.test(source)) return null;
|
|
49051
49512
|
const dir = resolve42(source);
|
|
49052
49513
|
try {
|
|
49053
|
-
return statSync14(dir).isDirectory() &&
|
|
49514
|
+
return statSync14(dir).isDirectory() && existsSync54(join52(dir, "himalaya.content.json")) ? dir : null;
|
|
49054
49515
|
} catch {
|
|
49055
49516
|
return null;
|
|
49056
49517
|
}
|
|
@@ -49107,7 +49568,7 @@ function serialize(task) {
|
|
|
49107
49568
|
});
|
|
49108
49569
|
}
|
|
49109
49570
|
function himiDir(dir) {
|
|
49110
|
-
const root =
|
|
49571
|
+
const root = join52(dir, ".himi");
|
|
49111
49572
|
try {
|
|
49112
49573
|
return lstatSync8(root).isDirectory() ? root : null;
|
|
49113
49574
|
} catch (e) {
|
|
@@ -49119,11 +49580,11 @@ function himiDir(dir) {
|
|
|
49119
49580
|
function writeRunRecord(dir, record2) {
|
|
49120
49581
|
const root = himiDir(dir);
|
|
49121
49582
|
if (!root) return false;
|
|
49122
|
-
const tmp =
|
|
49583
|
+
const tmp = join52(root, `.run.json.${process.pid}.${randomUUID3()}.tmp`);
|
|
49123
49584
|
try {
|
|
49124
49585
|
writeFileSync22(tmp, `${JSON.stringify(record2, null, 2)}
|
|
49125
49586
|
`, { flag: "wx" });
|
|
49126
|
-
renameSync5(tmp,
|
|
49587
|
+
renameSync5(tmp, join52(root, "run.json"));
|
|
49127
49588
|
} catch (e) {
|
|
49128
49589
|
rmSync13(tmp, { force: true });
|
|
49129
49590
|
throw e;
|
|
@@ -49131,7 +49592,7 @@ function writeRunRecord(dir, record2) {
|
|
|
49131
49592
|
return true;
|
|
49132
49593
|
}
|
|
49133
49594
|
function removeRunRecord(dir, owner) {
|
|
49134
|
-
const root =
|
|
49595
|
+
const root = join52(dir, ".himi");
|
|
49135
49596
|
try {
|
|
49136
49597
|
if (!lstatSync8(root).isDirectory()) return;
|
|
49137
49598
|
} catch {
|
|
@@ -49146,15 +49607,16 @@ function removeRunRecord(dir, owner) {
|
|
|
49146
49607
|
}
|
|
49147
49608
|
if (typeof pid === "number" && pid !== owner) return;
|
|
49148
49609
|
}
|
|
49149
|
-
rmSync13(
|
|
49610
|
+
rmSync13(join52(root, "run.json"), { force: true });
|
|
49150
49611
|
}
|
|
49151
49612
|
function boardFile(dir, pathname) {
|
|
49152
49613
|
let rel = null;
|
|
49153
|
-
if (pathname === "/__himi/studio/" || pathname === "/__himi/studio/index.html") rel =
|
|
49154
|
-
else if (pathname === "/__himi/studio/state.js") rel =
|
|
49614
|
+
if (pathname === "/__himi/studio/" || pathname === "/__himi/studio/index.html") rel = join52("studio", "index.html");
|
|
49615
|
+
else if (pathname === "/__himi/studio/state.js") rel = join52("studio", "state.js");
|
|
49616
|
+
else if (pathname === "/__himi/studio/timeline.js") rel = join52("studio", "timeline.js");
|
|
49155
49617
|
else {
|
|
49156
49618
|
const m = /^\/__himi\/history\/([0-9a-f]{64}\.(png|jpg|gif|webp))$/.exec(pathname);
|
|
49157
|
-
if (m) rel =
|
|
49619
|
+
if (m) rel = join52("history", m[1]);
|
|
49158
49620
|
}
|
|
49159
49621
|
if (!rel) return null;
|
|
49160
49622
|
const bytes2 = readConfined(resolve42(dir, ".himi"), rel);
|
|
@@ -49170,7 +49632,7 @@ function readConfined(root, rel) {
|
|
|
49170
49632
|
const parts = rel.split(sep13);
|
|
49171
49633
|
let at = root;
|
|
49172
49634
|
for (let i = 0; i < parts.length; i++) {
|
|
49173
|
-
at =
|
|
49635
|
+
at = join52(at, parts[i]);
|
|
49174
49636
|
const st = lstatSync8(at);
|
|
49175
49637
|
if (st.isSymbolicLink() || !(i === parts.length - 1 ? st.isFile() : st.isDirectory())) return null;
|
|
49176
49638
|
}
|
|
@@ -49179,7 +49641,7 @@ function readConfined(root, rel) {
|
|
|
49179
49641
|
const fd = openSync2(at, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
49180
49642
|
try {
|
|
49181
49643
|
if (!fstatSync(fd).isFile()) return null;
|
|
49182
|
-
return
|
|
49644
|
+
return readFileSync60(fd);
|
|
49183
49645
|
} finally {
|
|
49184
49646
|
closeSync2(fd);
|
|
49185
49647
|
}
|
|
@@ -49230,7 +49692,7 @@ __export(run_browser_exports, {
|
|
|
49230
49692
|
runInBrowser: () => runInBrowser
|
|
49231
49693
|
});
|
|
49232
49694
|
import { createServer as createServer5 } from "node:http";
|
|
49233
|
-
import { existsSync as
|
|
49695
|
+
import { existsSync as existsSync55, readFileSync as readFileSync61 } from "node:fs";
|
|
49234
49696
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
49235
49697
|
import { dirname as dirname28, resolve as resolve43 } from "node:path";
|
|
49236
49698
|
import { fileURLToPath as fileURLToPath23 } from "node:url";
|
|
@@ -49238,7 +49700,7 @@ function stagedDir() {
|
|
|
49238
49700
|
return process.env.HIMI_BROWSER_PLANE_OUT ? resolve43(process.env.HIMI_BROWSER_PLANE_OUT) : resolve43(REPO, "packages", "serve", "dist", "browser-plane");
|
|
49239
49701
|
}
|
|
49240
49702
|
function missingStaged() {
|
|
49241
|
-
return [...SERVED].filter((f) => !
|
|
49703
|
+
return [...SERVED].filter((f) => !existsSync55(resolve43(stagedDir(), f))).sort();
|
|
49242
49704
|
}
|
|
49243
49705
|
function ensureBrowserPlaneStaged() {
|
|
49244
49706
|
if (missingStaged().length === 0) return { ok: true, detail: "already staged" };
|
|
@@ -49328,7 +49790,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
|
|
|
49328
49790
|
}
|
|
49329
49791
|
const name = path2 === "/" || path2 === "/index.html" ? "host.html" : path2.slice(1);
|
|
49330
49792
|
if (SERVED.has(name)) {
|
|
49331
|
-
if (!
|
|
49793
|
+
if (!existsSync55(resolve43(stagedDir(), name))) {
|
|
49332
49794
|
const restaged = ensureBrowserPlaneStaged();
|
|
49333
49795
|
if (!restaged.ok) {
|
|
49334
49796
|
res.writeHead(503, { "content-type": "application/json" });
|
|
@@ -49338,7 +49800,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
|
|
|
49338
49800
|
}
|
|
49339
49801
|
let bytes2;
|
|
49340
49802
|
try {
|
|
49341
|
-
bytes2 =
|
|
49803
|
+
bytes2 = readFileSync61(resolve43(stagedDir(), name));
|
|
49342
49804
|
} catch (e) {
|
|
49343
49805
|
res.writeHead(503, { "content-type": "application/json" });
|
|
49344
49806
|
res.end(JSON.stringify({ error: "browser_plane_unstaged", file: name, detail: String(e) }));
|
|
@@ -49798,7 +50260,7 @@ __export(preflight_exports, {
|
|
|
49798
50260
|
parseStoreConfig: () => parseStoreConfig,
|
|
49799
50261
|
requireEnv: () => requireEnv
|
|
49800
50262
|
});
|
|
49801
|
-
import { existsSync as
|
|
50263
|
+
import { existsSync as existsSync56, readFileSync as readFileSync62 } from "node:fs";
|
|
49802
50264
|
import { isAbsolute as isAbsolute3, relative as relative9, resolve as resolve44 } from "node:path";
|
|
49803
50265
|
function isInsideRepo(p) {
|
|
49804
50266
|
const rel = relative9(REPO_ROOT3, resolve44(p));
|
|
@@ -49855,10 +50317,10 @@ function parseStoreConfig(text5) {
|
|
|
49855
50317
|
}
|
|
49856
50318
|
function loadStoreConfig(app) {
|
|
49857
50319
|
const p = storeConfigPath(app);
|
|
49858
|
-
if (!
|
|
50320
|
+
if (!existsSync56(p)) {
|
|
49859
50321
|
throw new Error(`No store config at ${p}. Create apps/${app}/store/store.config.yaml first (see /setup-store-signing).`);
|
|
49860
50322
|
}
|
|
49861
|
-
return parseStoreConfig(
|
|
50323
|
+
return parseStoreConfig(readFileSync62(p, "utf8"));
|
|
49862
50324
|
}
|
|
49863
50325
|
var init_preflight = __esm({
|
|
49864
50326
|
"../store-release/preflight.ts"() {
|
|
@@ -49877,19 +50339,19 @@ __export(credential_profile_exports, {
|
|
|
49877
50339
|
profilePath: () => profilePath,
|
|
49878
50340
|
resolveStoreCredentials: () => resolveStoreCredentials
|
|
49879
50341
|
});
|
|
49880
|
-
import { existsSync as
|
|
50342
|
+
import { existsSync as existsSync57, readFileSync as readFileSync63 } from "node:fs";
|
|
49881
50343
|
import { homedir as homedir5 } from "node:os";
|
|
49882
|
-
import { join as
|
|
50344
|
+
import { join as join53 } from "node:path";
|
|
49883
50345
|
function credentialsDir(home = homedir5()) {
|
|
49884
|
-
return
|
|
50346
|
+
return join53(home, ".himalaya", "store-credentials");
|
|
49885
50347
|
}
|
|
49886
50348
|
function profilePath(name, home = homedir5()) {
|
|
49887
50349
|
if (!PROFILE_NAME.test(name)) {
|
|
49888
50350
|
throw new Error(
|
|
49889
|
-
`credential profile ${JSON.stringify(name)} is not a profile name \u2014 use letters, digits, ".", "_" or "-" starting with a letter or digit. It names ${
|
|
50351
|
+
`credential profile ${JSON.stringify(name)} is not a profile name \u2014 use letters, digits, ".", "_" or "-" starting with a letter or digit. It names ${join53(credentialsDir(home), "<name>.json")}; it is never a path.`
|
|
49890
50352
|
);
|
|
49891
50353
|
}
|
|
49892
|
-
return
|
|
50354
|
+
return join53(credentialsDir(home), `${name}.json`);
|
|
49893
50355
|
}
|
|
49894
50356
|
function parseProfile(text5, label2) {
|
|
49895
50357
|
let doc;
|
|
@@ -49920,8 +50382,8 @@ function resolveStoreCredentials(opts) {
|
|
|
49920
50382
|
const { app, cfg } = opts;
|
|
49921
50383
|
const env = opts.env ?? process.env;
|
|
49922
50384
|
const home = opts.home ?? homedir5();
|
|
49923
|
-
const read = opts.readProfile ?? ((p) =>
|
|
49924
|
-
const exists = opts.profileExists ??
|
|
50385
|
+
const read = opts.readProfile ?? ((p) => readFileSync63(p, "utf8"));
|
|
50386
|
+
const exists = opts.profileExists ?? existsSync57;
|
|
49925
50387
|
const ios = cfg.ios ?? {};
|
|
49926
50388
|
const flagName = opts.profileFlag?.trim();
|
|
49927
50389
|
const named = namedProfile(cfg, opts.profileFlag);
|
|
@@ -50001,9 +50463,9 @@ __export(preflight_app_exports, {
|
|
|
50001
50463
|
preflightApp: () => preflightApp,
|
|
50002
50464
|
profileAccount: () => profileAccount
|
|
50003
50465
|
});
|
|
50004
|
-
import { readFileSync as
|
|
50466
|
+
import { readFileSync as readFileSync64, existsSync as existsSync58, readdirSync as readdirSync26, statSync as statSync15 } from "node:fs";
|
|
50005
50467
|
import { createHash as createHash26 } from "node:crypto";
|
|
50006
|
-
import { join as
|
|
50468
|
+
import { join as join54 } from "node:path";
|
|
50007
50469
|
function analyze(projectYml, storeConfig, icon, account) {
|
|
50008
50470
|
const f = [];
|
|
50009
50471
|
const has = (re, s) => re.test(s);
|
|
@@ -50067,13 +50529,13 @@ function profileAccount(app, storeConfig, opts = {}) {
|
|
|
50067
50529
|
}
|
|
50068
50530
|
}
|
|
50069
50531
|
async function preflightApp(app, opts = {}) {
|
|
50070
|
-
const projectYml =
|
|
50071
|
-
const storeConfig =
|
|
50532
|
+
const projectYml = existsSync58(iosProjectYml(app)) ? readFileSync64(iosProjectYml(app), "utf8") : "";
|
|
50533
|
+
const storeConfig = existsSync58(storeConfigPath(app)) ? readFileSync64(storeConfigPath(app), "utf8") : "";
|
|
50072
50534
|
if (!storeConfig) return [{ level: "error", message: `no apps/${app}/store/store.config.yaml \u2014 run /setup-store-signing first.` }];
|
|
50073
50535
|
const findings = analyze(
|
|
50074
50536
|
projectYml,
|
|
50075
50537
|
storeConfig,
|
|
50076
|
-
await appIconState(
|
|
50538
|
+
await appIconState(join54(appDir(app), "ios")),
|
|
50077
50539
|
profileAccount(app, storeConfig, opts)
|
|
50078
50540
|
);
|
|
50079
50541
|
findings.push(...analyzeListing(metadataFilesPresent(app), listScreenshots(app)));
|
|
@@ -50102,17 +50564,17 @@ function analyzeSubmissionRecord(appLevel, review, opts) {
|
|
|
50102
50564
|
return f;
|
|
50103
50565
|
}
|
|
50104
50566
|
function appLevelMetadataFiles(app, locale = "en-US") {
|
|
50105
|
-
const root =
|
|
50567
|
+
const root = join54(storeDir(app), "metadata");
|
|
50106
50568
|
const out = /* @__PURE__ */ new Set();
|
|
50107
|
-
if (
|
|
50569
|
+
if (existsSync58(root)) {
|
|
50108
50570
|
for (const n of readdirSync26(root)) if (n.endsWith(".txt")) out.add(n);
|
|
50109
50571
|
}
|
|
50110
|
-
if (
|
|
50572
|
+
if (existsSync58(join54(root, locale, "privacy_url.txt"))) out.add("privacy_url.txt");
|
|
50111
50573
|
return out;
|
|
50112
50574
|
}
|
|
50113
50575
|
function reviewInfoFiles(app) {
|
|
50114
|
-
const dir =
|
|
50115
|
-
if (!
|
|
50576
|
+
const dir = join54(storeDir(app), "review_information");
|
|
50577
|
+
if (!existsSync58(dir)) return /* @__PURE__ */ new Set();
|
|
50116
50578
|
return new Set(readdirSync26(dir).filter((n) => n.endsWith(".txt")));
|
|
50117
50579
|
}
|
|
50118
50580
|
function isValidAppStoreSize(w, h) {
|
|
@@ -50222,12 +50684,12 @@ function analyzePlayListing(assets) {
|
|
|
50222
50684
|
return f;
|
|
50223
50685
|
}
|
|
50224
50686
|
function playListingAssets(app, locale = "en-US") {
|
|
50225
|
-
const dir =
|
|
50687
|
+
const dir = join54(storeDir(app), "play", locale, "images");
|
|
50226
50688
|
const read = (names) => {
|
|
50227
50689
|
for (const name of names) {
|
|
50228
|
-
const p =
|
|
50690
|
+
const p = join54(dir, name);
|
|
50229
50691
|
try {
|
|
50230
|
-
if (statSync15(p).isFile()) return { name, bytes:
|
|
50692
|
+
if (statSync15(p).isFile()) return { name, bytes: readFileSync64(p) };
|
|
50231
50693
|
} catch {
|
|
50232
50694
|
}
|
|
50233
50695
|
}
|
|
@@ -50258,26 +50720,26 @@ function analyzeListing(metaFiles, shots) {
|
|
|
50258
50720
|
return f;
|
|
50259
50721
|
}
|
|
50260
50722
|
function metadataFilesPresent(app, locale = "en-US") {
|
|
50261
|
-
const dir =
|
|
50262
|
-
if (!
|
|
50723
|
+
const dir = join54(storeDir(app), "metadata", locale);
|
|
50724
|
+
if (!existsSync58(dir)) return /* @__PURE__ */ new Set();
|
|
50263
50725
|
return new Set(readdirSync26(dir).filter((n) => n.endsWith(".txt")));
|
|
50264
50726
|
}
|
|
50265
50727
|
function listScreenshots(app, locale = "en-US") {
|
|
50266
50728
|
const out = [];
|
|
50267
|
-
const flat =
|
|
50268
|
-
if (
|
|
50729
|
+
const flat = join54(storeDir(app), "screenshots", locale);
|
|
50730
|
+
if (existsSync58(flat)) {
|
|
50269
50731
|
for (const png of readdirSync26(flat).filter((n) => n.endsWith(".png"))) {
|
|
50270
|
-
const sz = pngSize(
|
|
50732
|
+
const sz = pngSize(readFileSync64(join54(flat, png)));
|
|
50271
50733
|
if (sz) out.push({ name: png, w: sz.w, h: sz.h });
|
|
50272
50734
|
}
|
|
50273
50735
|
}
|
|
50274
|
-
const legacy =
|
|
50275
|
-
if (
|
|
50736
|
+
const legacy = join54(storeDir(app), "metadata", locale, "screenshots");
|
|
50737
|
+
if (existsSync58(legacy)) {
|
|
50276
50738
|
for (const deviceDir of readdirSync26(legacy)) {
|
|
50277
|
-
const d =
|
|
50739
|
+
const d = join54(legacy, deviceDir);
|
|
50278
50740
|
if (!statSync15(d).isDirectory()) continue;
|
|
50279
50741
|
for (const png of readdirSync26(d).filter((n) => n.endsWith(".png"))) {
|
|
50280
|
-
const sz = pngSize(
|
|
50742
|
+
const sz = pngSize(readFileSync64(join54(d, png)));
|
|
50281
50743
|
if (sz) out.push({ name: `${deviceDir}/${png}`, w: sz.w, h: sz.h });
|
|
50282
50744
|
}
|
|
50283
50745
|
}
|
|
@@ -50285,13 +50747,13 @@ function listScreenshots(app, locale = "en-US") {
|
|
|
50285
50747
|
return out;
|
|
50286
50748
|
}
|
|
50287
50749
|
function placeholderHashes2() {
|
|
50288
|
-
const templateIos =
|
|
50289
|
-
if (!
|
|
50750
|
+
const templateIos = join54(appDir("_template"), "ios");
|
|
50751
|
+
if (!existsSync58(templateIos)) return [LEGACY_PLACEHOLDER_SHA2562];
|
|
50290
50752
|
for (const target of readdirSync26(templateIos)) {
|
|
50291
|
-
const p =
|
|
50753
|
+
const p = join54(templateIos, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
|
|
50292
50754
|
try {
|
|
50293
50755
|
if (!statSync15(p).isFile()) continue;
|
|
50294
|
-
return [LEGACY_PLACEHOLDER_SHA2562, createHash26("sha256").update(
|
|
50756
|
+
return [LEGACY_PLACEHOLDER_SHA2562, createHash26("sha256").update(readFileSync64(p)).digest("hex")];
|
|
50295
50757
|
} catch {
|
|
50296
50758
|
}
|
|
50297
50759
|
}
|
|
@@ -50322,12 +50784,12 @@ async function pixelIssues(bytes2) {
|
|
|
50322
50784
|
}
|
|
50323
50785
|
}
|
|
50324
50786
|
async function appIconState(iosDir) {
|
|
50325
|
-
if (!
|
|
50787
|
+
if (!existsSync58(iosDir)) return { exists: false, isPlaceholder: false, storeIssues: [] };
|
|
50326
50788
|
for (const target of readdirSync26(iosDir)) {
|
|
50327
|
-
const p =
|
|
50789
|
+
const p = join54(iosDir, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
|
|
50328
50790
|
try {
|
|
50329
50791
|
if (!statSync15(p).isFile()) continue;
|
|
50330
|
-
const bytes2 =
|
|
50792
|
+
const bytes2 = readFileSync64(p);
|
|
50331
50793
|
const hash = createHash26("sha256").update(bytes2).digest("hex");
|
|
50332
50794
|
const pixels = await pixelIssues(bytes2);
|
|
50333
50795
|
return {
|
|
@@ -50399,7 +50861,7 @@ __export(version_exports, {
|
|
|
50399
50861
|
setAndroidVersion: () => setAndroidVersion,
|
|
50400
50862
|
setIosVersion: () => setIosVersion
|
|
50401
50863
|
});
|
|
50402
|
-
import { readFileSync as
|
|
50864
|
+
import { readFileSync as readFileSync65, writeFileSync as writeFileSync23 } from "node:fs";
|
|
50403
50865
|
function readIosVersion(projectYml) {
|
|
50404
50866
|
const marketing = matchScalar(projectYml, "CFBundleShortVersionString");
|
|
50405
50867
|
const build2 = matchScalar(projectYml, "CFBundleVersion");
|
|
@@ -50457,8 +50919,8 @@ function setAndroidVersion(gradle, v) {
|
|
|
50457
50919
|
function bumpVersion(app, opts) {
|
|
50458
50920
|
const iosPath = iosProjectYml(app);
|
|
50459
50921
|
const gradlePath = androidGradle(app);
|
|
50460
|
-
const iosYml =
|
|
50461
|
-
const gradle =
|
|
50922
|
+
const iosYml = readFileSync65(iosPath, "utf8");
|
|
50923
|
+
const gradle = readFileSync65(gradlePath, "utf8");
|
|
50462
50924
|
const current = readIosVersion(iosYml);
|
|
50463
50925
|
const next = {
|
|
50464
50926
|
marketing: opts.marketing ?? current.marketing,
|
|
@@ -50475,7 +50937,7 @@ var init_version = __esm({
|
|
|
50475
50937
|
});
|
|
50476
50938
|
|
|
50477
50939
|
// ../store-release/register-bundle.ts
|
|
50478
|
-
import { readFileSync as
|
|
50940
|
+
import { readFileSync as readFileSync66 } from "node:fs";
|
|
50479
50941
|
import { createPrivateKey as createPrivateKey2, sign } from "node:crypto";
|
|
50480
50942
|
function b64url2(b) {
|
|
50481
50943
|
return Buffer.from(b).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
@@ -50493,7 +50955,7 @@ function bundleIdBody(identifier, name, platform = "IOS") {
|
|
|
50493
50955
|
async function registerBundleId(opts) {
|
|
50494
50956
|
const env = requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
|
|
50495
50957
|
assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
|
|
50496
|
-
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID,
|
|
50958
|
+
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync66(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
|
|
50497
50959
|
const res = await fetch(`${ASC_API}/v1/bundleIds`, {
|
|
50498
50960
|
method: "POST",
|
|
50499
50961
|
headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
|
|
@@ -50547,7 +51009,7 @@ __export(asc_status_exports, {
|
|
|
50547
51009
|
ascStatus: () => ascStatus,
|
|
50548
51010
|
buildVerdict: () => buildVerdict
|
|
50549
51011
|
});
|
|
50550
|
-
import { readFileSync as
|
|
51012
|
+
import { readFileSync as readFileSync67 } from "node:fs";
|
|
50551
51013
|
function buildVerdict(builds) {
|
|
50552
51014
|
if (!builds.length) {
|
|
50553
51015
|
return "NO builds registered \u2014 if you uploaded recently and it's been >15 min, the binary was REJECTED IN PROCESSING (reason is email-only; run validate-binary.ts / scan-purpose-strings.ts to reproduce it).";
|
|
@@ -50561,7 +51023,7 @@ function buildVerdict(builds) {
|
|
|
50561
51023
|
function client(creds) {
|
|
50562
51024
|
const env = creds ?? requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
|
|
50563
51025
|
assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
|
|
50564
|
-
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID,
|
|
51026
|
+
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync67(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
|
|
50565
51027
|
return async (path2) => {
|
|
50566
51028
|
const r = await fetch(`${ASC}${path2}`, { headers: { Authorization: `Bearer ${jwt}` } });
|
|
50567
51029
|
return { status: r.status, json: await r.json().catch(() => ({})) };
|
|
@@ -50721,7 +51183,7 @@ __export(secrets_exports, {
|
|
|
50721
51183
|
runRemoteSecretsCommand: () => runRemoteSecretsCommand,
|
|
50722
51184
|
runSecretsCommand: () => runSecretsCommand
|
|
50723
51185
|
});
|
|
50724
|
-
import { readFileSync as
|
|
51186
|
+
import { readFileSync as readFileSync68 } from "node:fs";
|
|
50725
51187
|
function environment(value) {
|
|
50726
51188
|
if (value === "preview" || value === "production") return value;
|
|
50727
51189
|
throw new Error("--environment must be preview or production");
|
|
@@ -50752,7 +51214,7 @@ async function runSecretsCommand(operation, flags, io, options = {}) {
|
|
|
50752
51214
|
io.log(JSON.stringify(await vault.list({ app, environment: env })));
|
|
50753
51215
|
return 0;
|
|
50754
51216
|
}
|
|
50755
|
-
const value = options.readValue ? options.readValue() :
|
|
51217
|
+
const value = options.readValue ? options.readValue() : readFileSync68(0, "utf8").replace(/\r?\n$/, "");
|
|
50756
51218
|
if (operation === "set") await vault.set({ app, environment: env, name, value });
|
|
50757
51219
|
else if (operation === "rotate") await vault.rotate({ app, environment: env, name, value });
|
|
50758
51220
|
else throw new Error(`unknown secrets operation ${operation}`);
|
|
@@ -50781,7 +51243,7 @@ async function runRemoteSecretsCommand(operation, flags, io, options) {
|
|
|
50781
51243
|
}
|
|
50782
51244
|
let body;
|
|
50783
51245
|
if (operation !== "list") {
|
|
50784
|
-
const value = options.readValue ? options.readValue() :
|
|
51246
|
+
const value = options.readValue ? options.readValue() : readFileSync68(0, "utf8").replace(/\r?\n$/, "");
|
|
50785
51247
|
body = JSON.stringify({ value });
|
|
50786
51248
|
}
|
|
50787
51249
|
const response = await (options.fetchImpl ?? fetch)(url, { method: operation === "list" ? "GET" : operation === "set" ? "PUT" : "POST", headers: headers2, body });
|
|
@@ -50817,15 +51279,15 @@ __export(notify_exports, {
|
|
|
50817
51279
|
runNotify: () => runNotify,
|
|
50818
51280
|
saveAdminSession: () => saveAdminSession
|
|
50819
51281
|
});
|
|
50820
|
-
import { chmodSync as chmodSync3, mkdirSync as mkdirSync27, readFileSync as
|
|
51282
|
+
import { chmodSync as chmodSync3, mkdirSync as mkdirSync27, readFileSync as readFileSync69, writeFileSync as writeFileSync24 } from "node:fs";
|
|
50821
51283
|
import { homedir as homedir6 } from "node:os";
|
|
50822
|
-
import { dirname as dirname30, join as
|
|
51284
|
+
import { dirname as dirname30, join as join55 } from "node:path";
|
|
50823
51285
|
function defaultSessionsPath() {
|
|
50824
|
-
return process.env.HIMI_ADMIN_SESSIONS_FILE ??
|
|
51286
|
+
return process.env.HIMI_ADMIN_SESSIONS_FILE ?? join55(homedir6(), ".himalaya", "admin-sessions.json");
|
|
50825
51287
|
}
|
|
50826
51288
|
function loadSessionsFile(path2 = defaultSessionsPath()) {
|
|
50827
51289
|
try {
|
|
50828
|
-
return JSON.parse(
|
|
51290
|
+
return JSON.parse(readFileSync69(path2, "utf8"));
|
|
50829
51291
|
} catch {
|
|
50830
51292
|
return {};
|
|
50831
51293
|
}
|
|
@@ -54383,7 +54845,7 @@ var init_brand_font = __esm({
|
|
|
54383
54845
|
|
|
54384
54846
|
// src/site-analyze/write-artifacts.ts
|
|
54385
54847
|
import { mkdirSync as mkdirSync28, writeFileSync as writeFileSync25 } from "node:fs";
|
|
54386
|
-
import { join as
|
|
54848
|
+
import { join as join56 } from "node:path";
|
|
54387
54849
|
function attachVeloSources(book, sources, put) {
|
|
54388
54850
|
const byPath = new Map((sources ?? []).map((s) => [s.path, s.text]));
|
|
54389
54851
|
for (const f of book.velo.files) {
|
|
@@ -54538,12 +55000,12 @@ async function downloadMedia(book, fetchImpl, put) {
|
|
|
54538
55000
|
}
|
|
54539
55001
|
async function writeBusinessBook(result, opts) {
|
|
54540
55002
|
const out = opts.outDir;
|
|
54541
|
-
mkdirSync28(
|
|
54542
|
-
mkdirSync28(
|
|
55003
|
+
mkdirSync28(join56(out, "evidence/pages"), { recursive: true });
|
|
55004
|
+
mkdirSync28(join56(out, "media/catalog"), { recursive: true });
|
|
54543
55005
|
const files = [];
|
|
54544
55006
|
const put = (rel, body) => {
|
|
54545
|
-
const p =
|
|
54546
|
-
mkdirSync28(
|
|
55007
|
+
const p = join56(out, rel);
|
|
55008
|
+
mkdirSync28(join56(p, ".."), { recursive: true });
|
|
54547
55009
|
writeFileSync25(p, body);
|
|
54548
55010
|
files.push(rel);
|
|
54549
55011
|
};
|
|
@@ -54637,8 +55099,8 @@ var init_customer_build = __esm({
|
|
|
54637
55099
|
});
|
|
54638
55100
|
|
|
54639
55101
|
// src/site-analyze/apply.ts
|
|
54640
|
-
import { existsSync as
|
|
54641
|
-
import { dirname as dirname31, isAbsolute as isAbsolute4, join as
|
|
55102
|
+
import { existsSync as existsSync59, readFileSync as readFileSync70, writeFileSync as writeFileSync26, copyFileSync as copyFileSync3, mkdirSync as mkdirSync29, realpathSync as realpathSync7, statSync as statSync16 } from "node:fs";
|
|
55103
|
+
import { dirname as dirname31, isAbsolute as isAbsolute4, join as join57, resolve as resolve45, sep as sep14 } from "node:path";
|
|
54642
55104
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
54643
55105
|
function unpairedRedirectNote(overlay) {
|
|
54644
55106
|
if (!overlay.wix?.clientId || overlay.wix.redirectUri) return void 0;
|
|
@@ -54653,7 +55115,7 @@ function committedShellProvisioning(path2) {
|
|
|
54653
55115
|
function findRepoRoot(cwd) {
|
|
54654
55116
|
let dir = cwd;
|
|
54655
55117
|
for (let i = 0; i < 8; i++) {
|
|
54656
|
-
if (SHELL_NAMES2.some((name) =>
|
|
55118
|
+
if (SHELL_NAMES2.some((name) => existsSync59(join57(dir, shellAppDir(name), "package.json")))) return dir;
|
|
54657
55119
|
const next = dirname31(dir);
|
|
54658
55120
|
if (next === dir) break;
|
|
54659
55121
|
dir = next;
|
|
@@ -54721,11 +55183,11 @@ function mergeCustomerOwned(committed, overlay) {
|
|
|
54721
55183
|
}
|
|
54722
55184
|
function buildMergedContract(options) {
|
|
54723
55185
|
const { appDir: appDir2, packageDir, overlay } = options;
|
|
54724
|
-
const committedPath =
|
|
54725
|
-
if (!
|
|
55186
|
+
const committedPath = join57(appDir2, "provisioning.json");
|
|
55187
|
+
if (!existsSync59(committedPath)) {
|
|
54726
55188
|
throw new Error(`shell has no committed provisioning.json at ${committedPath} to build a contract from`);
|
|
54727
55189
|
}
|
|
54728
|
-
const committed = JSON.parse(
|
|
55190
|
+
const committed = JSON.parse(readFileSync70(committedPath, "utf8"));
|
|
54729
55191
|
const merged = mergeCustomerOwned(committed, overlay);
|
|
54730
55192
|
const overlayFontFamily = (overlay.branding ?? {}).fontFamily;
|
|
54731
55193
|
const branding = merged.branding ?? {};
|
|
@@ -54737,8 +55199,8 @@ function buildMergedContract(options) {
|
|
|
54737
55199
|
};
|
|
54738
55200
|
const stage = (fromRel, toRel) => {
|
|
54739
55201
|
const from = contained(packageDir, fromRel);
|
|
54740
|
-
const to = contained(
|
|
54741
|
-
if (!from || !to || !
|
|
55202
|
+
const to = contained(join57(appDir2, STAGED), toRel.slice(STAGED.length + 1));
|
|
55203
|
+
if (!from || !to || !existsSync59(from)) return void 0;
|
|
54742
55204
|
let real;
|
|
54743
55205
|
let realRoot;
|
|
54744
55206
|
try {
|
|
@@ -54760,11 +55222,11 @@ function buildMergedContract(options) {
|
|
|
54760
55222
|
};
|
|
54761
55223
|
const icon = stage("media/icon.png", `${STAGED}/icon.png`);
|
|
54762
55224
|
if (icon) branding.appIconPath = icon;
|
|
54763
|
-
const facesPath =
|
|
54764
|
-
if (
|
|
55225
|
+
const facesPath = join57(packageDir, "media/fonts/faces.json");
|
|
55226
|
+
if (existsSync59(facesPath)) {
|
|
54765
55227
|
let faces = [];
|
|
54766
55228
|
try {
|
|
54767
|
-
const parsed = JSON.parse(
|
|
55229
|
+
const parsed = JSON.parse(readFileSync70(facesPath, "utf8"));
|
|
54768
55230
|
faces = Array.isArray(parsed) ? parsed : [];
|
|
54769
55231
|
} catch {
|
|
54770
55232
|
faces = [];
|
|
@@ -54785,9 +55247,9 @@ function buildMergedContract(options) {
|
|
|
54785
55247
|
merged.branding = branding;
|
|
54786
55248
|
const body = `${JSON.stringify(merged, null, 2)}
|
|
54787
55249
|
`;
|
|
54788
|
-
const path2 =
|
|
55250
|
+
const path2 = join57(packageDir, "provisioning.contract.json");
|
|
54789
55251
|
writeFileSync26(path2, body);
|
|
54790
|
-
const localPath =
|
|
55252
|
+
const localPath = join57(appDir2, LOCAL_CONTRACT_REL);
|
|
54791
55253
|
mkdirSync29(dirname31(localPath), { recursive: true });
|
|
54792
55254
|
writeFileSync26(localPath, body);
|
|
54793
55255
|
staged.push(localPath);
|
|
@@ -54797,8 +55259,8 @@ async function applyOverlays(input) {
|
|
|
54797
55259
|
const cwd = resolve45(input.cwd);
|
|
54798
55260
|
const shell = input.shell ?? DEFAULT_BRANDABLE_SHELL;
|
|
54799
55261
|
assertKnownShell(shell);
|
|
54800
|
-
const overlay = JSON.parse(
|
|
54801
|
-
const tokens = JSON.parse(
|
|
55262
|
+
const overlay = JSON.parse(readFileSync70(input.overlayPath, "utf8"));
|
|
55263
|
+
const tokens = JSON.parse(readFileSync70(input.tokensPath, "utf8"));
|
|
54802
55264
|
const wrote = [];
|
|
54803
55265
|
const notes = [];
|
|
54804
55266
|
const repoRoot2 = findRepoRoot(cwd);
|
|
@@ -54808,7 +55270,7 @@ async function applyOverlays(input) {
|
|
|
54808
55270
|
`shell "${shell}" cannot bake a customer brand \u2014 it ships no prepare:customer script`
|
|
54809
55271
|
);
|
|
54810
55272
|
}
|
|
54811
|
-
const appDir2 =
|
|
55273
|
+
const appDir2 = join57(repoRoot2, shellAppDir(shell));
|
|
54812
55274
|
const packageDir = dirname31(resolve45(input.overlayPath));
|
|
54813
55275
|
const { path: contract, staged } = buildMergedContract({ appDir: appDir2, packageDir, overlay });
|
|
54814
55276
|
wrote.push(...staged);
|
|
@@ -54830,10 +55292,10 @@ async function applyOverlays(input) {
|
|
|
54830
55292
|
note: `prepare:customer --contract with a merged contract (committed provisioning.json untouched)${unpairedInRepo ? ` \xB7 ${unpairedInRepo}` : ""}`
|
|
54831
55293
|
};
|
|
54832
55294
|
}
|
|
54833
|
-
const pkgProv =
|
|
55295
|
+
const pkgProv = join57(cwd, "provisioning.json");
|
|
54834
55296
|
assertNotCommitted(pkgProv, input.forbiddenProvisioning);
|
|
54835
|
-
if (
|
|
54836
|
-
const cur = JSON.parse(
|
|
55297
|
+
if (existsSync59(pkgProv)) {
|
|
55298
|
+
const cur = JSON.parse(readFileSync70(pkgProv, "utf8"));
|
|
54837
55299
|
const merged = deepMerge4(cur, overlay);
|
|
54838
55300
|
writeFileSync26(pkgProv, JSON.stringify(merged, null, 2) + "\n");
|
|
54839
55301
|
wrote.push(pkgProv);
|
|
@@ -54841,9 +55303,9 @@ async function applyOverlays(input) {
|
|
|
54841
55303
|
writeFileSync26(pkgProv, JSON.stringify(overlay, null, 2) + "\n");
|
|
54842
55304
|
wrote.push(pkgProv);
|
|
54843
55305
|
}
|
|
54844
|
-
const pkgTokens =
|
|
54845
|
-
if (
|
|
54846
|
-
const cur = JSON.parse(
|
|
55306
|
+
const pkgTokens = join57(cwd, "tokens.json");
|
|
55307
|
+
if (existsSync59(pkgTokens) && (tokens.colors || tokens.typography)) {
|
|
55308
|
+
const cur = JSON.parse(readFileSync70(pkgTokens, "utf8"));
|
|
54847
55309
|
const merged = deepMerge4(cur, tokens);
|
|
54848
55310
|
const mergedColors = merged.colors;
|
|
54849
55311
|
if (mergedColors && typeof mergedColors === "object" && !Array.isArray(mergedColors)) {
|
|
@@ -54862,9 +55324,9 @@ async function applyOverlays(input) {
|
|
|
54862
55324
|
wrote.push(pkgTokens);
|
|
54863
55325
|
}
|
|
54864
55326
|
const homeAction = homeRefreshActionId(shell);
|
|
54865
|
-
const homeSrc =
|
|
54866
|
-
if (homeAction &&
|
|
54867
|
-
const prev =
|
|
55327
|
+
const homeSrc = join57(cwd, "dev/index.ts");
|
|
55328
|
+
if (homeAction && existsSync59(homeSrc)) {
|
|
55329
|
+
const prev = readFileSync70(homeSrc, "utf8");
|
|
54868
55330
|
const patched = patchBrandParams(prev, overlay, homeAction);
|
|
54869
55331
|
let next = patched.src;
|
|
54870
55332
|
if (!patched.foreign && overlay.installedVerticals?.length) {
|
|
@@ -54887,13 +55349,13 @@ async function applyOverlays(input) {
|
|
|
54887
55349
|
notes.push(`${patched.unparsed} onAppear params block(s) in ${homeSrc} could not be read \u2014 any brand values inside them were not applied`);
|
|
54888
55350
|
}
|
|
54889
55351
|
}
|
|
54890
|
-
if (!input.iconPath || !
|
|
55352
|
+
if (!input.iconPath || !existsSync59(input.iconPath)) {
|
|
54891
55353
|
const book = input.iconPath ? dirname31(dirname31(resolve45(input.iconPath))) : void 0;
|
|
54892
55354
|
notes.push(
|
|
54893
55355
|
book ? `no icon installed \u2014 ${siteLogoAbsence(book).hint}` : "no icon installed and no business book to say why \u2014 `himi icon generate` draws one from the accent, or `himi icon set <file.png>` installs the customer's own mark"
|
|
54894
55356
|
);
|
|
54895
55357
|
}
|
|
54896
|
-
if (input.iconPath &&
|
|
55358
|
+
if (input.iconPath && existsSync59(input.iconPath)) {
|
|
54897
55359
|
try {
|
|
54898
55360
|
const installed = await installIcon(cwd, input.iconPath, { derivePlay: true });
|
|
54899
55361
|
wrote.push(...installed.wrote);
|
|
@@ -59048,7 +59510,7 @@ __export(cli_exports, {
|
|
|
59048
59510
|
runSiteAnalyze: () => runSiteAnalyze,
|
|
59049
59511
|
runSiteFunctionCli: () => runSiteFunctionCli
|
|
59050
59512
|
});
|
|
59051
|
-
import { readFileSync as
|
|
59513
|
+
import { readFileSync as readFileSync71 } from "node:fs";
|
|
59052
59514
|
import { resolve as resolve46 } from "node:path";
|
|
59053
59515
|
function assetFetchFor(_opts) {
|
|
59054
59516
|
return pinnedFetch2;
|
|
@@ -59135,7 +59597,7 @@ async function runSiteFunctionCli(opts) {
|
|
|
59135
59597
|
let source;
|
|
59136
59598
|
if (opts.sourcePath) {
|
|
59137
59599
|
const p = resolve46(opts.cwd ?? process.cwd(), opts.sourcePath);
|
|
59138
|
-
source =
|
|
59600
|
+
source = readFileSync71(p, "utf8");
|
|
59139
59601
|
}
|
|
59140
59602
|
let body;
|
|
59141
59603
|
if (opts.bodyRaw != null) {
|
|
@@ -59392,7 +59854,7 @@ __export(site_create_exports, {
|
|
|
59392
59854
|
runSiteList: () => runSiteList,
|
|
59393
59855
|
writeProvisioningBinding: () => writeProvisioningBinding
|
|
59394
59856
|
});
|
|
59395
|
-
import { existsSync as
|
|
59857
|
+
import { existsSync as existsSync60, readFileSync as readFileSync72, writeFileSync as writeFileSync27 } from "node:fs";
|
|
59396
59858
|
import { resolve as resolvePath2 } from "node:path";
|
|
59397
59859
|
function oauthClientName(projectName) {
|
|
59398
59860
|
return `${projectName} client`;
|
|
@@ -59541,7 +60003,7 @@ async function runSiteCreate(opts) {
|
|
|
59541
60003
|
if (!wantOauthApp) return { ...base, nextSteps: nextSteps(metaSiteId) };
|
|
59542
60004
|
return { ...base, clientId, redirectUri, nextSteps: nextSteps(metaSiteId, clientId) };
|
|
59543
60005
|
}
|
|
59544
|
-
function writeProvisioningBinding(target, binding2, fs = { existsSync:
|
|
60006
|
+
function writeProvisioningBinding(target, binding2, fs = { existsSync: existsSync60, readFileSync: readFileSync72, writeFileSync: writeFileSync27 }) {
|
|
59545
60007
|
const msid = binding2.siteId;
|
|
59546
60008
|
const path2 = resolvePath2(target);
|
|
59547
60009
|
const committed = committedShellProvisioning(path2);
|
|
@@ -60214,11 +60676,11 @@ var init_context = __esm({
|
|
|
60214
60676
|
});
|
|
60215
60677
|
|
|
60216
60678
|
// src/cli.ts
|
|
60217
|
-
import { mkdtempSync as mkdtempSync4, readFileSync as
|
|
60679
|
+
import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync73, mkdirSync as mkdirSync30, writeFileSync as writeFileSync28, existsSync as existsSync61, rmSync as rmSync14, readdirSync as readdirSync27, statSync as statSync17, lstatSync as lstatSync9, accessSync, constants as constants2, renameSync as renameSync6, cpSync as cpSync3 } from "node:fs";
|
|
60218
60680
|
import { execFile, execFileSync as execFileSync7, spawnSync as spawnSync5, spawn as spawn6 } from "node:child_process";
|
|
60219
60681
|
import { createHash as createHash27, randomUUID as randomUUID5 } from "node:crypto";
|
|
60220
60682
|
import { tmpdir as tmpdir5, homedir as homedir7, hostname } from "node:os";
|
|
60221
|
-
import { join as
|
|
60683
|
+
import { join as join58, resolve as resolve47, relative as relative10, basename as basename14, dirname as dirname32 } from "node:path";
|
|
60222
60684
|
import { fileURLToPath as fileURLToPath24 } from "node:url";
|
|
60223
60685
|
|
|
60224
60686
|
// ../serve-cli/src/client.ts
|
|
@@ -63494,8 +63956,8 @@ var str6 = (v) => typeof v === "string" ? v : void 0;
|
|
|
63494
63956
|
var num2 = (v) => typeof v === "string" && v !== "" && Number.isFinite(Number(v)) ? Number(v) : void 0;
|
|
63495
63957
|
function embeddedTemplateCatalog() {
|
|
63496
63958
|
return availableTemplates().map((name) => {
|
|
63497
|
-
const path2 =
|
|
63498
|
-
const meta = JSON.parse(
|
|
63959
|
+
const path2 = join58(templateSourceDir(name), TEMPLATE_META_FILE);
|
|
63960
|
+
const meta = JSON.parse(readFileSync73(path2, "utf8"));
|
|
63499
63961
|
if (!meta || typeof meta.title !== "string" || typeof meta.description !== "string" || !Array.isArray(meta.tags)) {
|
|
63500
63962
|
throw new Error(`${path2} must be { title: string, description: string, tags: string[], category?: string }`);
|
|
63501
63963
|
}
|
|
@@ -64164,7 +64626,7 @@ var COMMANDS = [
|
|
|
64164
64626
|
];
|
|
64165
64627
|
function cliVersion() {
|
|
64166
64628
|
try {
|
|
64167
|
-
return JSON.parse(
|
|
64629
|
+
return JSON.parse(readFileSync73(new URL("../package.json", import.meta.url), "utf8")).version ?? "unknown";
|
|
64168
64630
|
} catch {
|
|
64169
64631
|
return "unknown";
|
|
64170
64632
|
}
|
|
@@ -64282,7 +64744,7 @@ function ageInDays(publishedAt, now = Date.now()) {
|
|
|
64282
64744
|
}
|
|
64283
64745
|
function packageVersion(path2) {
|
|
64284
64746
|
try {
|
|
64285
|
-
const version2 = JSON.parse(
|
|
64747
|
+
const version2 = JSON.parse(readFileSync73(path2, "utf8")).version;
|
|
64286
64748
|
return typeof version2 === "string" && version2 ? version2 : void 0;
|
|
64287
64749
|
} catch {
|
|
64288
64750
|
return void 0;
|
|
@@ -64291,7 +64753,7 @@ function packageVersion(path2) {
|
|
|
64291
64753
|
function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("./authoring-runtime/node_modules/@wix/himalaya/package.json", import.meta.url)) {
|
|
64292
64754
|
let dir = resolve47(fromDir);
|
|
64293
64755
|
for (; ; ) {
|
|
64294
|
-
const version2 = packageVersion(
|
|
64756
|
+
const version2 = packageVersion(join58(dir, "node_modules", "@wix", "himalaya", "package.json"));
|
|
64295
64757
|
if (version2) return { version: version2, source: "local" };
|
|
64296
64758
|
const parent = dirname32(dir);
|
|
64297
64759
|
if (parent === dir) break;
|
|
@@ -64301,7 +64763,7 @@ function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("
|
|
|
64301
64763
|
if (bundled) return { version: bundled, source: "bundled" };
|
|
64302
64764
|
try {
|
|
64303
64765
|
const root = execFileSync7("npm", ["root", "-g"], { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
64304
|
-
const version2 = root ? packageVersion(
|
|
64766
|
+
const version2 = root ? packageVersion(join58(root, "@wix", "himalaya", "package.json")) : void 0;
|
|
64305
64767
|
return version2 ? { version: version2, source: "global" } : {};
|
|
64306
64768
|
} catch {
|
|
64307
64769
|
return {};
|
|
@@ -64348,11 +64810,11 @@ var UPDATE_RETRY_AFTER_FAILURE_MS = 60 * 60 * 1e3;
|
|
|
64348
64810
|
var UPDATE_SNOOZE_MS = 24 * 60 * 60 * 1e3;
|
|
64349
64811
|
var UPDATE_REEXEC_ENV = "HIMI_UPDATED_ONCE";
|
|
64350
64812
|
function updateCachePath(env = process.env) {
|
|
64351
|
-
return env.HIMI_UPDATE_CACHE_FILE ??
|
|
64813
|
+
return env.HIMI_UPDATE_CACHE_FILE ?? join58(homedir7(), ".himalaya", "update-check.json");
|
|
64352
64814
|
}
|
|
64353
64815
|
function readUpdateCache(path2) {
|
|
64354
64816
|
try {
|
|
64355
|
-
const parsed = JSON.parse(
|
|
64817
|
+
const parsed = JSON.parse(readFileSync73(path2, "utf8"));
|
|
64356
64818
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
64357
64819
|
} catch {
|
|
64358
64820
|
return {};
|
|
@@ -64420,12 +64882,12 @@ function createUpdateRunner(spawn7 = spawnSync5) {
|
|
|
64420
64882
|
},
|
|
64421
64883
|
installedVersion: () => {
|
|
64422
64884
|
const root = globalNodeModulesRoot();
|
|
64423
|
-
return root ? packageVersion(
|
|
64885
|
+
return root ? packageVersion(join58(root, "@wix", "himalaya-cli", "package.json")) : void 0;
|
|
64424
64886
|
},
|
|
64425
64887
|
reexec: (argv) => {
|
|
64426
64888
|
const root = globalNodeModulesRoot();
|
|
64427
|
-
const entry = root ?
|
|
64428
|
-
if (!entry || !
|
|
64889
|
+
const entry = root ? join58(root, "@wix", "himalaya-cli", "dist", "cli.mjs") : void 0;
|
|
64890
|
+
if (!entry || !existsSync61(entry)) return void 0;
|
|
64429
64891
|
const result = spawnSync5(process.execPath, [entry, ...argv], {
|
|
64430
64892
|
// inherit keeps PIPED STDIN working — commands that read stdin must survive a re-exec.
|
|
64431
64893
|
stdio: "inherit",
|
|
@@ -64472,7 +64934,7 @@ function staleUpdateLockFile(cachePath, now) {
|
|
|
64472
64934
|
for (const path2 of [`${cachePath}.lock.break`, `${cachePath}.lock`]) {
|
|
64473
64935
|
let content;
|
|
64474
64936
|
try {
|
|
64475
|
-
content =
|
|
64937
|
+
content = readFileSync73(path2, "utf8");
|
|
64476
64938
|
} catch {
|
|
64477
64939
|
continue;
|
|
64478
64940
|
}
|
|
@@ -64495,7 +64957,7 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
|
|
|
64495
64957
|
const mine = lockStamp(now);
|
|
64496
64958
|
const readLock = (path2) => {
|
|
64497
64959
|
try {
|
|
64498
|
-
return
|
|
64960
|
+
return readFileSync73(path2, "utf8");
|
|
64499
64961
|
} catch {
|
|
64500
64962
|
return void 0;
|
|
64501
64963
|
}
|
|
@@ -64792,9 +65254,9 @@ function diagnoseBody(body) {
|
|
|
64792
65254
|
const out = {};
|
|
64793
65255
|
const emptied = [];
|
|
64794
65256
|
for (const [key2, value] of Object.entries(body)) {
|
|
64795
|
-
const
|
|
64796
|
-
if (
|
|
64797
|
-
out[key2] =
|
|
65257
|
+
const fold2 = (key2 === "issues" || key2 === "failures" || key2 === "warnings") && folded(value);
|
|
65258
|
+
if (fold2) emptied.push(key2);
|
|
65259
|
+
out[key2] = fold2 ? [] : value;
|
|
64798
65260
|
}
|
|
64799
65261
|
if (emptied.length) out.foldedIntoFindings = emptied;
|
|
64800
65262
|
return out;
|
|
@@ -65033,7 +65495,7 @@ function executableOnPath(name, env = process.env) {
|
|
|
65033
65495
|
const suffixes = process.platform === "win32" ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
|
|
65034
65496
|
for (const dir of entries) {
|
|
65035
65497
|
for (const suffix of suffixes) {
|
|
65036
|
-
const candidate =
|
|
65498
|
+
const candidate = join58(dir, `${name}${suffix}`);
|
|
65037
65499
|
try {
|
|
65038
65500
|
if (!statSync17(candidate).isFile()) continue;
|
|
65039
65501
|
if (process.platform !== "win32") accessSync(candidate, constants2.X_OK);
|
|
@@ -65142,7 +65604,7 @@ async function nativeConfigAdvisories(app, configSource) {
|
|
|
65142
65604
|
const { iosProjectYml: iosProjectYml2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
65143
65605
|
const { androidOptedIn: androidOptedIn3, LABEL_IOS_SPLASH: LABEL_IOS_SPLASH2 } = await Promise.resolve().then(() => (init_splash(), splash_exports));
|
|
65144
65606
|
const iosYmlPath = iosProjectYml2(app);
|
|
65145
|
-
const iosYml =
|
|
65607
|
+
const iosYml = existsSync61(iosYmlPath) ? readFileSync73(iosYmlPath, "utf8") : "";
|
|
65146
65608
|
let optedIn = iosYml.includes(LABEL_IOS_SPLASH2);
|
|
65147
65609
|
if (!optedIn) {
|
|
65148
65610
|
const { androidManifestPath: androidManifestPath3 } = await Promise.resolve().then(() => (init_gen_native_config(), gen_native_config_exports));
|
|
@@ -65156,7 +65618,7 @@ async function nativeConfigAdvisories(app, configSource) {
|
|
|
65156
65618
|
}
|
|
65157
65619
|
function readConfigSource(dir) {
|
|
65158
65620
|
try {
|
|
65159
|
-
return
|
|
65621
|
+
return readFileSync73(join58(dir, "config.ts"), "utf8");
|
|
65160
65622
|
} catch {
|
|
65161
65623
|
return null;
|
|
65162
65624
|
}
|
|
@@ -65168,7 +65630,7 @@ function writePngFile(path2, base64) {
|
|
|
65168
65630
|
}
|
|
65169
65631
|
async function initFromRemoteTemplate(name, parentDir, template, c) {
|
|
65170
65632
|
const dir = resolve47(parentDir, name);
|
|
65171
|
-
if (
|
|
65633
|
+
if (existsSync61(join58(dir, "himalaya.content.json"))) {
|
|
65172
65634
|
throw new Error(`content package already exists at ${dir}`);
|
|
65173
65635
|
}
|
|
65174
65636
|
const r = await c.fetchTemplateSource(TEMPLATE_APP_PREFIX + template);
|
|
@@ -65211,7 +65673,7 @@ function symlinkDestinationIssue(dest) {
|
|
|
65211
65673
|
function restoreDestinationIssue(dest, force) {
|
|
65212
65674
|
const link = symlinkDestinationIssue(dest);
|
|
65213
65675
|
if (link) return link;
|
|
65214
|
-
if (!
|
|
65676
|
+
if (!existsSync61(dest)) return null;
|
|
65215
65677
|
if (!statSync17(dest).isDirectory()) {
|
|
65216
65678
|
return { error: `${dest} exists and is not a directory`, hint: "pass --out/--name to land somewhere else, or remove the file" };
|
|
65217
65679
|
}
|
|
@@ -65226,7 +65688,7 @@ function restoreDestinationIssue(dest, force) {
|
|
|
65226
65688
|
function isHimalayaMonorepoCheckout(start) {
|
|
65227
65689
|
let dir = resolve47(start);
|
|
65228
65690
|
for (; ; ) {
|
|
65229
|
-
if (
|
|
65691
|
+
if (existsSync61(join58(dir, "tools", "himi-cli", "src", "cli.ts")) && existsSync61(join58(dir, "core", "serve", "src", "server.ts"))) return true;
|
|
65230
65692
|
const parent = dirname32(dir);
|
|
65231
65693
|
if (parent === dir) return false;
|
|
65232
65694
|
dir = parent;
|
|
@@ -65269,7 +65731,7 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
65269
65731
|
Object.entries(files).map(([rel, body]) => [rel, rel === "himalaya.content.json" ? substituteIdentity(body, slug) : body])
|
|
65270
65732
|
);
|
|
65271
65733
|
const repoRoot2 = resolve47(fileURLToPath24(new URL("../../..", import.meta.url)));
|
|
65272
|
-
const root =
|
|
65734
|
+
const root = join58(repoRoot2, "node_modules", ".cache", "himi-template-preview");
|
|
65273
65735
|
const stillRunning = (pid) => {
|
|
65274
65736
|
try {
|
|
65275
65737
|
process.kill(pid, 0);
|
|
@@ -65283,12 +65745,12 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
65283
65745
|
if (!entry.isDirectory()) continue;
|
|
65284
65746
|
const pid = Number(entry.name.startsWith(`${slug}-`) ? entry.name.slice(slug.length + 1) : NaN);
|
|
65285
65747
|
if (Number.isInteger(pid) && pid > 0 && pid !== process.pid && !stillRunning(pid)) {
|
|
65286
|
-
rmSync14(
|
|
65748
|
+
rmSync14(join58(root, entry.name), { recursive: true, force: true });
|
|
65287
65749
|
}
|
|
65288
65750
|
}
|
|
65289
65751
|
} catch {
|
|
65290
65752
|
}
|
|
65291
|
-
const dest =
|
|
65753
|
+
const dest = join58(root, `${slug}-${process.pid}`);
|
|
65292
65754
|
rmSync14(dest, { recursive: true, force: true });
|
|
65293
65755
|
mkdirSync30(dest, { recursive: true });
|
|
65294
65756
|
materializeSource(forBuild, displayName, dest, slug);
|
|
@@ -65296,8 +65758,8 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
65296
65758
|
}
|
|
65297
65759
|
async function appId(dir) {
|
|
65298
65760
|
try {
|
|
65299
|
-
const { readFileSync:
|
|
65300
|
-
const m = JSON.parse(
|
|
65761
|
+
const { readFileSync: readFileSync74 } = await import("node:fs");
|
|
65762
|
+
const m = JSON.parse(readFileSync74(join58(dir, "himalaya.content.json"), "utf8"));
|
|
65301
65763
|
if (m.name) return m.name;
|
|
65302
65764
|
} catch {
|
|
65303
65765
|
}
|
|
@@ -65305,8 +65767,8 @@ async function appId(dir) {
|
|
|
65305
65767
|
}
|
|
65306
65768
|
async function contentVisibility(dir) {
|
|
65307
65769
|
try {
|
|
65308
|
-
const { readFileSync:
|
|
65309
|
-
const m = JSON.parse(
|
|
65770
|
+
const { readFileSync: readFileSync74 } = await import("node:fs");
|
|
65771
|
+
const m = JSON.parse(readFileSync74(join58(dir, "himalaya.content.json"), "utf8"));
|
|
65310
65772
|
if (m.visibility === "public" || m.visibility === "unlisted") return m.visibility;
|
|
65311
65773
|
} catch {
|
|
65312
65774
|
}
|
|
@@ -65530,7 +65992,7 @@ async function recordedReleaseForContentQuietly(dir, resolution, onDrift) {
|
|
|
65530
65992
|
try {
|
|
65531
65993
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
65532
65994
|
const bres = await buildContentForValidation2(dir, { resolution });
|
|
65533
|
-
out = mkdtempSync4(
|
|
65995
|
+
out = mkdtempSync4(join58(tmpdir5(), "himi-ux-record-"));
|
|
65534
65996
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
65535
65997
|
const outcome = await buildReleaseFromContent2(dir, out, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {}, collect: { lint: true } });
|
|
65536
65998
|
const releaseId = outcome.manifest.releaseId;
|
|
@@ -65708,7 +66170,7 @@ async function producedWidgetFamilies(dir) {
|
|
|
65708
66170
|
let js;
|
|
65709
66171
|
for (const candidate of [`${name}.bundle.js`, `${name}.js`, name]) {
|
|
65710
66172
|
try {
|
|
65711
|
-
js =
|
|
66173
|
+
js = readFileSync73(join58(outDir, candidate), "utf8");
|
|
65712
66174
|
break;
|
|
65713
66175
|
} catch {
|
|
65714
66176
|
}
|
|
@@ -65739,7 +66201,7 @@ async function producedWidgetFamilies(dir) {
|
|
|
65739
66201
|
}
|
|
65740
66202
|
return { families, source: "dist/bundles" };
|
|
65741
66203
|
}
|
|
65742
|
-
var boardOpen = (dir) =>
|
|
66204
|
+
var boardOpen = (dir) => existsSync61(join58(dir, ".himi", "studio", "index.html"));
|
|
65743
66205
|
var BOARD_REFRESHERS = /* @__PURE__ */ new Set(["render", "test", "validate", "build", "push", "icon", "site", "ux", "progress"]);
|
|
65744
66206
|
async function leaveForBoard(dir, record2, value) {
|
|
65745
66207
|
if (!boardOpen(dir)) return;
|
|
@@ -66127,7 +66589,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66127
66589
|
const sourceDir = resolve47(str6(flags["source-dir"]) ?? appDir2);
|
|
66128
66590
|
let meta;
|
|
66129
66591
|
try {
|
|
66130
|
-
meta = JSON.parse(
|
|
66592
|
+
meta = JSON.parse(readFileSync73(join58(sourceDir, TEMPLATE_META_FILE), "utf8"));
|
|
66131
66593
|
} catch {
|
|
66132
66594
|
io.error(JSON.stringify({ error: `no ${TEMPLATE_META_FILE} in ${sourceDir} \u2014 a template must declare { title, description, tags } to be published`, hint: `add ${TEMPLATE_META_FILE} next to himalaya.content.json (or pass --source-dir <dir>)` }));
|
|
66133
66595
|
return 2;
|
|
@@ -66137,7 +66599,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66137
66599
|
return 2;
|
|
66138
66600
|
}
|
|
66139
66601
|
try {
|
|
66140
|
-
const appearance = extractTemplateAppearance(JSON.parse(
|
|
66602
|
+
const appearance = extractTemplateAppearance(JSON.parse(readFileSync73(join58(sourceDir, "tokens.json"), "utf8")));
|
|
66141
66603
|
meta = { ...appearance, ...meta };
|
|
66142
66604
|
} catch {
|
|
66143
66605
|
}
|
|
@@ -66149,7 +66611,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66149
66611
|
const force = flags.force === true;
|
|
66150
66612
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
66151
66613
|
const bres = await buildContentForValidation2(buildDir, { resolution: resolutionFlag(flags) });
|
|
66152
|
-
const out = mkdtempSync4(
|
|
66614
|
+
const out = mkdtempSync4(join58(tmpdir5(), "himi-template-"));
|
|
66153
66615
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
66154
66616
|
const outcome = await buildReleaseFromContent2(buildDir, out, {
|
|
66155
66617
|
...hasWorkers ? { tier5Dir: bundleOutDir2(buildDir) } : {},
|
|
@@ -66202,7 +66664,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66202
66664
|
let iconHash;
|
|
66203
66665
|
if (iconPath) {
|
|
66204
66666
|
try {
|
|
66205
|
-
const bytes2 =
|
|
66667
|
+
const bytes2 = readFileSync73(iconPath);
|
|
66206
66668
|
payload.icon = bytes2.toString("base64");
|
|
66207
66669
|
iconHash = createHash27("sha256").update(bytes2).digest("hex");
|
|
66208
66670
|
} catch {
|
|
@@ -66435,7 +66897,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66435
66897
|
const { navIssues: navIssues2 } = await Promise.resolve().then(() => (init_nav_lint(), nav_lint_exports));
|
|
66436
66898
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
66437
66899
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
66438
|
-
const out = mkdtempSync4(
|
|
66900
|
+
const out = mkdtempSync4(join58(tmpdir5(), "himi-validate-"));
|
|
66439
66901
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
66440
66902
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
66441
66903
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -66478,7 +66940,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66478
66940
|
const path2 = dpxSessionTokenPath();
|
|
66479
66941
|
let raw;
|
|
66480
66942
|
try {
|
|
66481
|
-
raw =
|
|
66943
|
+
raw = readFileSync73(path2, "utf8");
|
|
66482
66944
|
} catch {
|
|
66483
66945
|
throw new Error(`no DPX BO session at ${path2}; run dpx auth login, write dpx auth token to that path, then himi login --dpx --target bo`);
|
|
66484
66946
|
}
|
|
@@ -66598,13 +67060,13 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66598
67060
|
case "studio": {
|
|
66599
67061
|
const { openStudio: openStudio2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
|
|
66600
67062
|
const dir = contentDir(flags);
|
|
66601
|
-
if (!
|
|
67063
|
+
if (!existsSync61(join58(dir, "himalaya.content.json"))) {
|
|
66602
67064
|
io.error(JSON.stringify({ ok: false, error: "not_a_content_package", dir, hint: "run from the app directory (or pass --content <dir>) \u2014 the board reads that package's .himi/" }));
|
|
66603
67065
|
return 2;
|
|
66604
67066
|
}
|
|
66605
67067
|
if (pos[1] === "reel") {
|
|
66606
67068
|
const { buildReel: buildReel2 } = await Promise.resolve().then(() => (init_studio_reel(), studio_reel_exports));
|
|
66607
|
-
const out = resolve47(str6(flags.out) ??
|
|
67069
|
+
const out = resolve47(str6(flags.out) ?? join58(dir, ".himi", "making-of.html"));
|
|
66608
67070
|
const { html, plan } = buildReel2(dir);
|
|
66609
67071
|
mkdirSync30(dirname32(out), { recursive: true });
|
|
66610
67072
|
writeFileSync28(out, html);
|
|
@@ -66654,7 +67116,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66654
67116
|
const { appendProgress: appendProgress2, readProgress: readProgress2, summarizeProgress: summarizeProgress2, parseStep: parseStep2, notifyDesktop: notifyDesktop2, appLabel: appLabel2, journalPath: journalPath2, ProgressError: ProgressError2, JOURNEY_STEPS: JOURNEY_STEPS2 } = await Promise.resolve().then(() => (init_progress(), progress_exports));
|
|
66655
67117
|
const dir = contentDir(flags);
|
|
66656
67118
|
const journal = journalPath2(dir);
|
|
66657
|
-
const hint =
|
|
67119
|
+
const hint = existsSync61(join58(dir, "himalaya.content.json")) ? {} : { hint: "no himalaya.content.json here \u2014 run from the app directory (or pass --content <dir>) so the build board finds this journal" };
|
|
66658
67120
|
const message = pos.slice(1).join(" ").trim();
|
|
66659
67121
|
if (!message) {
|
|
66660
67122
|
if (flags.step !== void 0 || flags.image !== void 0 || flags.notify === true) {
|
|
@@ -66746,7 +67208,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66746
67208
|
case "test": {
|
|
66747
67209
|
const dir = contentDir(flags);
|
|
66748
67210
|
const structuredOutput = flags.json === true || io.isTTY !== true;
|
|
66749
|
-
if (
|
|
67211
|
+
if (existsSync61(join58(dir, "functions"))) {
|
|
66750
67212
|
const { invokeLocalFunction: invokeLocalFunction2, loadFunctionsApp: loadFunctionsApp2 } = await Promise.resolve().then(() => (init_functions(), functions_exports));
|
|
66751
67213
|
const loaded = await loadFunctionsApp2(dir);
|
|
66752
67214
|
const results = [];
|
|
@@ -66833,7 +67295,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66833
67295
|
}
|
|
66834
67296
|
}
|
|
66835
67297
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
66836
|
-
const out = mkdtempSync4(
|
|
67298
|
+
const out = mkdtempSync4(join58(tmpdir5(), "himi-test-"));
|
|
66837
67299
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
66838
67300
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
66839
67301
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -66878,7 +67340,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66878
67340
|
io.error(JSON.stringify({ error: `screen "${screen.screenId}" has no Tier-5 worker, so there is nothing for the browser loop to build` }));
|
|
66879
67341
|
return 2;
|
|
66880
67342
|
}
|
|
66881
|
-
const sources = collectWorkerSources2(
|
|
67343
|
+
const sources = collectWorkerSources2(join58(dir, "tier5-src"), screen.bundleName);
|
|
66882
67344
|
if (!sources) {
|
|
66883
67345
|
io.error(JSON.stringify({ error: `no worker source found at tier5-src/${screen.bundleName} \u2014 the browser loop compiles SOURCE, not the built bundle` }));
|
|
66884
67346
|
return 2;
|
|
@@ -67039,7 +67501,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67039
67501
|
const sp = await runShotsPass2({
|
|
67040
67502
|
descriptors: scopeDescriptors2(outcome.descriptors ?? [], pos.slice(1), invalidScreens),
|
|
67041
67503
|
tokens: outcome.tokens,
|
|
67042
|
-
outDir:
|
|
67504
|
+
outDir: join58(dir, ".himi", "shots"),
|
|
67043
67505
|
width: 390,
|
|
67044
67506
|
layers: { rules: shotRules, ...cmsSeed ? { cmsSeed } : {}, ...canned ? { canned: canned.byKey } : {} },
|
|
67045
67507
|
...budgetMs ? { budgetMs } : {},
|
|
@@ -67077,7 +67539,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67077
67539
|
releaseId: result.releaseId,
|
|
67078
67540
|
releasePayload: release,
|
|
67079
67541
|
descriptors: attestedDescriptors,
|
|
67080
|
-
screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""),
|
|
67542
|
+
screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""), join58(dir, ".himi", "shots", name)])),
|
|
67081
67543
|
coverage: {
|
|
67082
67544
|
screens: crawledScreens.size,
|
|
67083
67545
|
actionsDispatched: result.actions.exercised,
|
|
@@ -67167,7 +67629,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67167
67629
|
return 2;
|
|
67168
67630
|
}
|
|
67169
67631
|
try {
|
|
67170
|
-
const raw = stateArg.trim().startsWith("{") ? stateArg :
|
|
67632
|
+
const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync73(stateArg.replace(/^@/, ""), "utf8");
|
|
67171
67633
|
injectedState = JSON.parse(raw);
|
|
67172
67634
|
} catch (e) {
|
|
67173
67635
|
io.error(JSON.stringify({ error: `--state must be inline JSON or a path to a .json file \u2014 ${e.message}` }));
|
|
@@ -67182,7 +67644,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67182
67644
|
return 2;
|
|
67183
67645
|
}
|
|
67184
67646
|
try {
|
|
67185
|
-
const raw = inputArg.trim().startsWith("{") ? inputArg :
|
|
67647
|
+
const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync73(inputArg.replace(/^@/, ""), "utf8");
|
|
67186
67648
|
const parsed = JSON.parse(raw);
|
|
67187
67649
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("must be a JSON object");
|
|
67188
67650
|
injectedInput = parsed;
|
|
@@ -67231,7 +67693,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67231
67693
|
}
|
|
67232
67694
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
67233
67695
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
67234
|
-
const out = mkdtempSync4(
|
|
67696
|
+
const out = mkdtempSync4(join58(tmpdir5(), "himi-render-"));
|
|
67235
67697
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
67236
67698
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
67237
67699
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -67245,7 +67707,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67245
67707
|
const diagnostics = (outcome.lint ?? []).find((s) => s.screenId === screenId)?.issues ?? [];
|
|
67246
67708
|
let pngFile;
|
|
67247
67709
|
let attestationPngFile;
|
|
67248
|
-
const shotPath =
|
|
67710
|
+
const shotPath = join58(dir, ".himi", "shots", `${screenId}.png`);
|
|
67249
67711
|
const pngTarget = typeof flags.png === "string" ? str6(flags.png) : flags.png === true ? shotPath : void 0;
|
|
67250
67712
|
if (pngTarget && r.pngBase64) {
|
|
67251
67713
|
pngFile = writePngFile(pngTarget, r.pngBase64);
|
|
@@ -67581,7 +68043,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
67581
68043
|
io.error(JSON.stringify(linked));
|
|
67582
68044
|
return 1;
|
|
67583
68045
|
}
|
|
67584
|
-
if (
|
|
68046
|
+
if (existsSync61(dest)) {
|
|
67585
68047
|
if (!statSync17(dest).isDirectory()) {
|
|
67586
68048
|
io.error(JSON.stringify({
|
|
67587
68049
|
error: `${dest} exists and is not a directory`,
|
|
@@ -67594,7 +68056,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
67594
68056
|
io.error(JSON.stringify({ error: `${dest} already exists and is not empty`, hint: "pass --force to write into it anyway (merging, and naming what it keeps), --replace to restore exactly what was archived, or --out/--name to land somewhere else" }));
|
|
67595
68057
|
return 1;
|
|
67596
68058
|
}
|
|
67597
|
-
if (replace && occupied && !
|
|
68059
|
+
if (replace && occupied && !existsSync61(join58(dest, "himalaya.content.json"))) {
|
|
67598
68060
|
io.error(JSON.stringify({
|
|
67599
68061
|
error: `${dest} is not a content package \u2014 refusing to --replace it`,
|
|
67600
68062
|
hint: "--replace only clears a directory that holds himalaya.content.json. Check --out/--name, or pass --force to merge into it instead."
|
|
@@ -67733,7 +68195,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
67733
68195
|
const force = flags.force === true;
|
|
67734
68196
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
67735
68197
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
67736
|
-
const out = mkdtempSync4(
|
|
68198
|
+
const out = mkdtempSync4(join58(tmpdir5(), "himi-push-"));
|
|
67737
68199
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
67738
68200
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
67739
68201
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -68254,7 +68716,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68254
68716
|
}
|
|
68255
68717
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
68256
68718
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
68257
|
-
const built = mkdtempSync4(
|
|
68719
|
+
const built = mkdtempSync4(join58(tmpdir5(), "himi-pack-"));
|
|
68258
68720
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
68259
68721
|
const outcome = await buildReleaseFromContent2(dir, built, {
|
|
68260
68722
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -68457,7 +68919,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68457
68919
|
}));
|
|
68458
68920
|
return 1;
|
|
68459
68921
|
}
|
|
68460
|
-
const archive =
|
|
68922
|
+
const archive = readFileSync73(resolve47(file));
|
|
68461
68923
|
const result = await client2().createPackageShare({
|
|
68462
68924
|
app: opened.header.app,
|
|
68463
68925
|
releaseId: opened.header.releaseId,
|
|
@@ -68511,11 +68973,11 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68511
68973
|
const app = await appId(dir2);
|
|
68512
68974
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
68513
68975
|
const bres = await buildContentBundles2(dir2, { resolution: resolutionFlag(flags) });
|
|
68514
|
-
temp = mkdtempSync4(
|
|
68976
|
+
temp = mkdtempSync4(join58(tmpdir5(), "himi-run-build-"));
|
|
68515
68977
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
68516
68978
|
const initial = await buildReleaseFromContent2(dir2, temp, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir2) } : {} });
|
|
68517
68979
|
servedMissing = initial.missingBundles;
|
|
68518
|
-
source =
|
|
68980
|
+
source = join58(temp, app);
|
|
68519
68981
|
}
|
|
68520
68982
|
const chromeArg = str6(flags.chrome) ?? "preview";
|
|
68521
68983
|
if (chromeArg !== "preview" && chromeArg !== "app") {
|
|
@@ -68551,7 +69013,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68551
69013
|
if (!recordKit) return;
|
|
68552
69014
|
startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
68553
69015
|
const failure = record2(served2, { ok: true, at: startedAt });
|
|
68554
|
-
if (!recorded) io.error(JSON.stringify({ run: "run_record_skipped", message: `${failure ?? `${
|
|
69016
|
+
if (!recorded) io.error(JSON.stringify({ run: "run_record_skipped", message: `${failure ?? `${join58(dir, ".himi")} is not a real directory`}, so the build board will not frame this preview.` }));
|
|
68555
69017
|
await refreshBoard();
|
|
68556
69018
|
};
|
|
68557
69019
|
const retract = async () => {
|
|
@@ -68582,7 +69044,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68582
69044
|
}
|
|
68583
69045
|
const watchKit = watch2 ? await Promise.resolve().then(() => (init_run_watch(), run_watch_exports)) : null;
|
|
68584
69046
|
const bus = watchKit ? new watchKit.ReloadBus() : void 0;
|
|
68585
|
-
if (watch2) served = mkdtempSync4(
|
|
69047
|
+
if (watch2) served = mkdtempSync4(join58(tmpdir5(), "himi-run-served-"));
|
|
68586
69048
|
const running = await runPackage2(source, {
|
|
68587
69049
|
port,
|
|
68588
69050
|
chrome: chromeArg,
|
|
@@ -68594,15 +69056,15 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68594
69056
|
...recordKit ? { extraRoutes: (request) => recordKit.boardFile(dir, new URL(request.url).pathname) } : {},
|
|
68595
69057
|
...watchKit && served && bus ? { workDir: served, screenEvents: bus } : {}
|
|
68596
69058
|
});
|
|
68597
|
-
let
|
|
69059
|
+
let watcher2;
|
|
68598
69060
|
let rebuild;
|
|
68599
69061
|
let stopping = false;
|
|
68600
69062
|
try {
|
|
68601
69063
|
await announce(running);
|
|
68602
69064
|
if (watchKit && bus) {
|
|
68603
69065
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
68604
|
-
const live2 =
|
|
68605
|
-
const manifestOf = (tree) => JSON.parse(
|
|
69066
|
+
const live2 = join58(running.releaseRoot, running.app);
|
|
69067
|
+
const manifestOf = (tree) => JSON.parse(readFileSync73(join58(tree, "release-manifest.json"), "utf8"));
|
|
68606
69068
|
let current = manifestOf(live2);
|
|
68607
69069
|
const failed2 = async (message) => {
|
|
68608
69070
|
if (stopping) return;
|
|
@@ -68613,7 +69075,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68613
69075
|
};
|
|
68614
69076
|
rebuild = watchKit.serialize(async () => {
|
|
68615
69077
|
const t0 = Date.now();
|
|
68616
|
-
const next = mkdtempSync4(
|
|
69078
|
+
const next = mkdtempSync4(join58(tmpdir5(), "himi-run-build-"));
|
|
68617
69079
|
try {
|
|
68618
69080
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
68619
69081
|
if (bres.compileErrors.length) {
|
|
@@ -68630,14 +69092,14 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68630
69092
|
return;
|
|
68631
69093
|
}
|
|
68632
69094
|
if (stopping) return;
|
|
68633
|
-
const fresh = manifestOf(
|
|
69095
|
+
const fresh = manifestOf(join58(next, running.app));
|
|
68634
69096
|
const diff = watchKit.diffReleases(current, fresh);
|
|
68635
69097
|
const retired = `${live2}.retired-${Date.now()}`;
|
|
68636
69098
|
renameSync6(live2, retired);
|
|
68637
69099
|
try {
|
|
68638
|
-
renameSync6(
|
|
69100
|
+
renameSync6(join58(next, running.app), live2);
|
|
68639
69101
|
} catch {
|
|
68640
|
-
cpSync3(
|
|
69102
|
+
cpSync3(join58(next, running.app), live2, { recursive: true });
|
|
68641
69103
|
}
|
|
68642
69104
|
rmSync14(retired, { recursive: true, force: true });
|
|
68643
69105
|
current = fresh;
|
|
@@ -68652,7 +69114,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68652
69114
|
rmSync14(next, { recursive: true, force: true });
|
|
68653
69115
|
}
|
|
68654
69116
|
});
|
|
68655
|
-
|
|
69117
|
+
watcher2 = watchKit.watchContent(dir, () => rebuild?.());
|
|
68656
69118
|
}
|
|
68657
69119
|
} catch (e) {
|
|
68658
69120
|
await retract().catch(() => {
|
|
@@ -68674,7 +69136,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68674
69136
|
await new Promise((done) => {
|
|
68675
69137
|
const stop = async () => {
|
|
68676
69138
|
stopping = true;
|
|
68677
|
-
|
|
69139
|
+
watcher2?.close();
|
|
68678
69140
|
try {
|
|
68679
69141
|
await rebuild?.stop();
|
|
68680
69142
|
await retract();
|
|
@@ -69235,7 +69697,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69235
69697
|
io.error(JSON.stringify({ error: `patch ${kind} needs --file`, usage: PATCH_USAGE }));
|
|
69236
69698
|
return 2;
|
|
69237
69699
|
}
|
|
69238
|
-
if (!
|
|
69700
|
+
if (!existsSync61(file)) {
|
|
69239
69701
|
io.error(JSON.stringify({ error: `no such file: ${file}` }));
|
|
69240
69702
|
return 2;
|
|
69241
69703
|
}
|
|
@@ -69291,7 +69753,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69291
69753
|
lintNote: "`himi patch` sends a raw file. Nothing here built or linted your app \u2014 `himi push --only <selector>` is the same edit with the full lint gate in front of it."
|
|
69292
69754
|
};
|
|
69293
69755
|
if (kind === "tokens" || kind === "app-config") {
|
|
69294
|
-
const body =
|
|
69756
|
+
const body = readFileSync73(file, "utf8");
|
|
69295
69757
|
const patch2 = kind === "tokens" ? { tokens: body } : { appConfig: body };
|
|
69296
69758
|
return runReleasePatch({
|
|
69297
69759
|
...common,
|
|
@@ -69306,7 +69768,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69306
69768
|
io.error(JSON.stringify({ error: "patch screen needs a <screenId>", usage: PATCH_USAGE }));
|
|
69307
69769
|
return 2;
|
|
69308
69770
|
}
|
|
69309
|
-
const descriptor =
|
|
69771
|
+
const descriptor = readFileSync73(file, "utf8");
|
|
69310
69772
|
try {
|
|
69311
69773
|
JSON.parse(descriptor);
|
|
69312
69774
|
} catch (e) {
|
|
@@ -69346,7 +69808,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69346
69808
|
extra: { kind, screen: id, file: { path: file, bytes: Buffer.byteLength(descriptor, "utf8") } }
|
|
69347
69809
|
});
|
|
69348
69810
|
}
|
|
69349
|
-
const bytes2 =
|
|
69811
|
+
const bytes2 = readFileSync73(file);
|
|
69350
69812
|
const sha = createHash27("sha256").update(bytes2).digest("hex");
|
|
69351
69813
|
const forScreens = (str6(flags["for-screen"]) ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
69352
69814
|
if (flags["no-rebind"] !== void 0 && flags["no-rebind"] !== true) {
|
|
@@ -69490,7 +69952,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69490
69952
|
}
|
|
69491
69953
|
let def;
|
|
69492
69954
|
try {
|
|
69493
|
-
const parsed = JSON.parse(arg.startsWith("@") ?
|
|
69955
|
+
const parsed = JSON.parse(arg.startsWith("@") ? readFileSync73(arg.slice(1), "utf8") : arg);
|
|
69494
69956
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
69495
69957
|
io.error(JSON.stringify({ error: "invalid_definition", problems: [`--definition must be a JSON object, got ${Array.isArray(parsed) ? "an array" : parsed === null ? "null" : typeof parsed}`] }));
|
|
69496
69958
|
return 2;
|
|
@@ -69954,7 +70416,7 @@ ${label2}`);
|
|
|
69954
70416
|
const platform = str6(flags.platform)?.split(",").map((p) => p.trim()).filter(Boolean);
|
|
69955
70417
|
{
|
|
69956
70418
|
const distDir = contentDir(flags);
|
|
69957
|
-
if (
|
|
70419
|
+
if (existsSync61(join58(distDir, "himalaya.content.json"))) {
|
|
69958
70420
|
const issues = await iconIssues(distDir, flags.strict === true, { requireDeclared: true, requireVerified: true });
|
|
69959
70421
|
const errors = issues.filter((i) => i.severity === "error");
|
|
69960
70422
|
for (const i of issues.filter((i2) => i2.severity === "warning")) {
|
|
@@ -70223,7 +70685,7 @@ ${label2}`);
|
|
|
70223
70685
|
const dpxPath = dpxSessionTokenPath();
|
|
70224
70686
|
let dpx;
|
|
70225
70687
|
try {
|
|
70226
|
-
dpx =
|
|
70688
|
+
dpx = readFileSync73(dpxPath, "utf8").trim();
|
|
70227
70689
|
} catch {
|
|
70228
70690
|
io.error(JSON.stringify({ error: `no dpx session at ${dpxPath} \u2014 run \`dpx auth login\` then \`dpx auth token > ${dpxPath}\` (dpx 2.x keeps its own state in ~/.dpx/auth.json and does NOT write the legacy session file), or omit --dpx` }));
|
|
70229
70691
|
return 1;
|
|
@@ -70625,7 +71087,7 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
|
|
|
70625
71087
|
const path2 = dpxSessionTokenPath();
|
|
70626
71088
|
let raw;
|
|
70627
71089
|
try {
|
|
70628
|
-
raw =
|
|
71090
|
+
raw = readFileSync73(path2, "utf8");
|
|
70629
71091
|
} catch {
|
|
70630
71092
|
io.error(JSON.stringify({ error: `no DPX BO session at ${path2}` }));
|
|
70631
71093
|
return 1;
|