@wix/himalaya-cli 0.1026.0 → 0.1027.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 +1052 -653
- 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
|
@@ -5378,7 +5378,6 @@ function resolveTranslation(value, catalog, sourceCatalog) {
|
|
|
5378
5378
|
var BINDING_SIGILS, BINDING_SIGIL_RE, TRANSLATION_PREFIX, TRANSLATION_KEY_RE;
|
|
5379
5379
|
var init_bindings = __esm({
|
|
5380
5380
|
"../../core/ts/src/bindings.ts"() {
|
|
5381
|
-
"use strict";
|
|
5382
5381
|
BINDING_SIGILS = ["service", "flag", "item", "t"];
|
|
5383
5382
|
BINDING_SIGIL_RE = new RegExp(
|
|
5384
5383
|
`^\\$(?:${BINDING_SIGILS.filter((s) => s !== "t").join("|")})\\b|^\\$t:`
|
|
@@ -22907,6 +22906,65 @@ var init_controls = __esm({
|
|
|
22907
22906
|
}
|
|
22908
22907
|
});
|
|
22909
22908
|
|
|
22909
|
+
// ../../core/web-renderer/src/a11y/modalStack.ts
|
|
22910
|
+
function pushModalLayer(el) {
|
|
22911
|
+
const layer = { el: typeof el === "function" ? el : () => el };
|
|
22912
|
+
layers.push(layer);
|
|
22913
|
+
sync();
|
|
22914
|
+
return {
|
|
22915
|
+
isTop: () => layers[layers.length - 1] === layer,
|
|
22916
|
+
release: () => {
|
|
22917
|
+
const i = layers.indexOf(layer);
|
|
22918
|
+
if (i < 0) return;
|
|
22919
|
+
layers.splice(i, 1);
|
|
22920
|
+
sync();
|
|
22921
|
+
}
|
|
22922
|
+
};
|
|
22923
|
+
}
|
|
22924
|
+
function topElement() {
|
|
22925
|
+
for (let i = layers.length - 1; i >= 0; i--) {
|
|
22926
|
+
const el = layers[i].el();
|
|
22927
|
+
if (el?.isConnected) return el;
|
|
22928
|
+
}
|
|
22929
|
+
return null;
|
|
22930
|
+
}
|
|
22931
|
+
function sync() {
|
|
22932
|
+
watcher?.disconnect();
|
|
22933
|
+
watcher = null;
|
|
22934
|
+
for (const el of madeInert) el.removeAttribute("inert");
|
|
22935
|
+
madeInert.clear();
|
|
22936
|
+
const top = topElement();
|
|
22937
|
+
if (!top) return;
|
|
22938
|
+
const scope = top.parentElement?.closest(`[${MODAL_SCOPE_ATTR}]`) ?? top.ownerDocument.body;
|
|
22939
|
+
const levels = [];
|
|
22940
|
+
let node = top;
|
|
22941
|
+
while (node !== scope && node.parentElement) {
|
|
22942
|
+
const parent = node.parentElement;
|
|
22943
|
+
levels.push(parent);
|
|
22944
|
+
for (const sibling of Array.from(parent.children)) {
|
|
22945
|
+
if (sibling === node || SKIP.has(sibling.tagName) || sibling.hasAttribute("inert")) continue;
|
|
22946
|
+
sibling.setAttribute("inert", "");
|
|
22947
|
+
madeInert.add(sibling);
|
|
22948
|
+
}
|
|
22949
|
+
node = parent;
|
|
22950
|
+
}
|
|
22951
|
+
const Observer = top.ownerDocument.defaultView?.MutationObserver;
|
|
22952
|
+
if (Observer && levels.length) {
|
|
22953
|
+
watcher = new Observer(() => sync());
|
|
22954
|
+
for (const level of levels) watcher.observe(level, { childList: true });
|
|
22955
|
+
}
|
|
22956
|
+
}
|
|
22957
|
+
var MODAL_SCOPE_ATTR, SKIP, layers, madeInert, watcher;
|
|
22958
|
+
var init_modalStack = __esm({
|
|
22959
|
+
"../../core/web-renderer/src/a11y/modalStack.ts"() {
|
|
22960
|
+
MODAL_SCOPE_ATTR = "data-himi-modal-scope";
|
|
22961
|
+
SKIP = /* @__PURE__ */ new Set(["SCRIPT", "STYLE", "LINK", "META", "TEMPLATE", "NOSCRIPT", "HEAD"]);
|
|
22962
|
+
layers = [];
|
|
22963
|
+
madeInert = /* @__PURE__ */ new Set();
|
|
22964
|
+
watcher = null;
|
|
22965
|
+
}
|
|
22966
|
+
});
|
|
22967
|
+
|
|
22910
22968
|
// ../../core/web-renderer/src/listGestures.tsx
|
|
22911
22969
|
import { useRef, useState as useState2 } from "react";
|
|
22912
22970
|
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
@@ -24158,8 +24216,8 @@ function autoGrowBox(contentHeight, lineHeight, verticalPadding, maxLines) {
|
|
|
24158
24216
|
const cap = Math.max(floor, lineHeight * lines + verticalPadding);
|
|
24159
24217
|
return { height: Math.max(floor, Math.min(contentHeight, cap)), scrolls: contentHeight > cap };
|
|
24160
24218
|
}
|
|
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;
|
|
24219
|
+
function wrapModalMenu(modal, label2, placement, ref, menu) {
|
|
24220
|
+
return modal ? /* @__PURE__ */ jsx6("div", { ref, role: "dialog", "aria-modal": "true", "aria-label": label2, style: placement, children: menu }) : menu;
|
|
24163
24221
|
}
|
|
24164
24222
|
function bindMediaSlot(value, sessionId) {
|
|
24165
24223
|
if (typeof value === "string") {
|
|
@@ -24774,9 +24832,37 @@ function ensureInitialFocusRuntime() {
|
|
|
24774
24832
|
restoreFocusOnDismiss(presentedScope, active);
|
|
24775
24833
|
}
|
|
24776
24834
|
el.focus();
|
|
24835
|
+
if (document.activeElement === el) enterAuthoredOrderOnTab(el);
|
|
24777
24836
|
}
|
|
24778
24837
|
}, 0);
|
|
24779
24838
|
}
|
|
24839
|
+
function enterAuthoredOrderOnTab(target) {
|
|
24840
|
+
const doc = target.ownerDocument;
|
|
24841
|
+
const scope = target.closest(PRESENTED_SCOPE);
|
|
24842
|
+
const root = scope ?? doc;
|
|
24843
|
+
const onKeyDown = (e) => {
|
|
24844
|
+
if (e.key !== "Tab" || e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.defaultPrevented || e.target !== target) return;
|
|
24845
|
+
if (target.tabIndex > 0) return;
|
|
24846
|
+
const ordered = Array.from(root.querySelectorAll("[tabindex]")).filter((c) => c.tabIndex > 0 && c.closest(PRESENTED_SCOPE) === scope).sort((a, b) => a.tabIndex - b.tabIndex);
|
|
24847
|
+
for (const c of ordered) {
|
|
24848
|
+
c.focus();
|
|
24849
|
+
if (doc.activeElement === c) {
|
|
24850
|
+
e.preventDefault();
|
|
24851
|
+
e.stopPropagation();
|
|
24852
|
+
return;
|
|
24853
|
+
}
|
|
24854
|
+
}
|
|
24855
|
+
};
|
|
24856
|
+
const onBlur = () => setTimeout(() => {
|
|
24857
|
+
if (doc.activeElement !== target) disarm();
|
|
24858
|
+
}, 0);
|
|
24859
|
+
const disarm = () => {
|
|
24860
|
+
target.removeEventListener("keydown", onKeyDown);
|
|
24861
|
+
target.removeEventListener("blur", onBlur);
|
|
24862
|
+
};
|
|
24863
|
+
target.addEventListener("keydown", onKeyDown);
|
|
24864
|
+
target.addEventListener("blur", onBlur);
|
|
24865
|
+
}
|
|
24780
24866
|
function ariaModal(modal, dflt) {
|
|
24781
24867
|
const on3 = modal === true || modal === false ? modal : dflt;
|
|
24782
24868
|
return on3 ? "true" : void 0;
|
|
@@ -25745,6 +25831,7 @@ var init_renderNode = __esm({
|
|
|
25745
25831
|
init_icons();
|
|
25746
25832
|
init_icon_catalog_generated();
|
|
25747
25833
|
init_controls();
|
|
25834
|
+
init_modalStack();
|
|
25748
25835
|
init_listGestures();
|
|
25749
25836
|
init_worker_subtree();
|
|
25750
25837
|
init_preview_surfaces();
|
|
@@ -26275,6 +26362,7 @@ var init_renderNode = __esm({
|
|
|
26275
26362
|
const popupPlacement = { position: "absolute", top: "100%", right: 0, zIndex: 20, marginTop: 4 };
|
|
26276
26363
|
const anchorRef = React5.useRef(null);
|
|
26277
26364
|
const menuRef = React5.useRef(null);
|
|
26365
|
+
const dialogRef = React5.useRef(null);
|
|
26278
26366
|
const itemsKey = items.map((it, i) => `${it?.id ?? i}:${it?.disabled ? 0 : 1}`).join("|");
|
|
26279
26367
|
React5.useEffect(() => {
|
|
26280
26368
|
if (!open || !modal) return;
|
|
@@ -26284,7 +26372,9 @@ var init_renderNode = __esm({
|
|
|
26284
26372
|
}, [open, modal, itemsKey]);
|
|
26285
26373
|
React5.useEffect(() => {
|
|
26286
26374
|
if (!open || !modal) return;
|
|
26375
|
+
const layer = pushModalLayer(() => dialogRef.current);
|
|
26287
26376
|
return () => {
|
|
26377
|
+
layer.release();
|
|
26288
26378
|
const active = document.activeElement;
|
|
26289
26379
|
if (active == null || active === document.body || !document.contains(active)) anchorRef.current?.focus();
|
|
26290
26380
|
};
|
|
@@ -26322,11 +26412,11 @@ var init_renderNode = __esm({
|
|
|
26322
26412
|
setOpen((v) => !v);
|
|
26323
26413
|
}
|
|
26324
26414
|
},
|
|
26325
|
-
style: { display: "inline-flex", alignItems: "center", cursor: "pointer" },
|
|
26415
|
+
style: { display: "inline-flex", alignItems: "center", justifyContent: "center", minWidth: 44, minHeight: 44, cursor: "pointer" },
|
|
26326
26416
|
children: props.anchor ? renderNode(props.anchor, ctx) : iconSvg("more", { size: 20, color: C("textSecondary", "#636b78") })
|
|
26327
26417
|
}
|
|
26328
26418
|
),
|
|
26329
|
-
open && wrapModalMenu(modal, anchorLabel, popupPlacement, /* @__PURE__ */ jsx6(
|
|
26419
|
+
open && wrapModalMenu(modal, anchorLabel, popupPlacement, dialogRef, /* @__PURE__ */ jsx6(
|
|
26330
26420
|
"div",
|
|
26331
26421
|
{
|
|
26332
26422
|
ref: menuRef,
|
|
@@ -27388,7 +27478,7 @@ var init_renderNode = __esm({
|
|
|
27388
27478
|
const tAlign = props.textAlign === "center" ? "center" : props.textAlign === "trailing" ? "right" : props.textAlign === "justify" ? "justify" : props.textAlign === "leading" ? "left" : void 0;
|
|
27389
27479
|
const tDecor = props.decoration === "strikethrough" ? "line-through" : props.decoration === "underline" ? "underline" : void 0;
|
|
27390
27480
|
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 });
|
|
27481
|
+
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
27482
|
});
|
|
27393
27483
|
ImageNode = withExtras("ImageNode", ({ props, ctx, wrap }) => {
|
|
27394
27484
|
const C = ctx.color;
|
|
@@ -28264,18 +28354,23 @@ var init_renderNode = __esm({
|
|
|
28264
28354
|
const next = multiSelect ? isSel ? selected.filter((x) => x !== id) : [...selected, id] : isSel ? [] : [id];
|
|
28265
28355
|
ctx.onAction({ ...onChange, args: { ...onChange.args ?? {}, selectedIds: next } });
|
|
28266
28356
|
};
|
|
28267
|
-
return
|
|
28268
|
-
|
|
28269
|
-
|
|
28270
|
-
|
|
28271
|
-
|
|
28272
|
-
|
|
28273
|
-
|
|
28274
|
-
|
|
28275
|
-
|
|
28276
|
-
|
|
28277
|
-
|
|
28278
|
-
|
|
28357
|
+
return (
|
|
28358
|
+
// ONE horizontally scrolling row, like the iOS ScrollView(.horizontal) and the
|
|
28359
|
+
// Android LazyRow. Wrapping here turned a long filter set into a ragged grid and
|
|
28360
|
+
// pushed a sibling count onto two lines (#3080, #3004).
|
|
28361
|
+
/* @__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) => {
|
|
28362
|
+
const on3 = selected.includes(c.id);
|
|
28363
|
+
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 };
|
|
28364
|
+
const inner = /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
28365
|
+
asText2(c.label),
|
|
28366
|
+
c.count != null && /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
28367
|
+
" ",
|
|
28368
|
+
/* @__PURE__ */ jsx6("span", { style: { opacity: 0.7, fontSize: 11 }, children: c.count })
|
|
28369
|
+
] })
|
|
28370
|
+
] });
|
|
28371
|
+
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);
|
|
28372
|
+
}) })
|
|
28373
|
+
);
|
|
28279
28374
|
});
|
|
28280
28375
|
TILE_PX = 256;
|
|
28281
28376
|
MAX_MERCATOR_LAT = 85.05112878;
|
|
@@ -32789,18 +32884,18 @@ function startBundleArtifactWatcher(state) {
|
|
|
32789
32884
|
});
|
|
32790
32885
|
};
|
|
32791
32886
|
try {
|
|
32792
|
-
const
|
|
32887
|
+
const watcher2 = watch(TIER5_ROOT2, { persistent: false }, (_event, filename) => {
|
|
32793
32888
|
const bundle = builtBundleName(filename);
|
|
32794
32889
|
if (!bundle) return;
|
|
32795
32890
|
pending.add(bundle);
|
|
32796
32891
|
if (timer) clearTimeout(timer);
|
|
32797
32892
|
timer = setTimeout(flush, 120);
|
|
32798
32893
|
});
|
|
32799
|
-
|
|
32894
|
+
watcher2.on("error", (err) => {
|
|
32800
32895
|
console.warn(`[himalaya-dev] bundle watcher stopped: ${err.message}`);
|
|
32801
32896
|
});
|
|
32802
32897
|
console.log(`[himalaya-dev] watching built bundles: ${TIER5_ROOT2}`);
|
|
32803
|
-
return
|
|
32898
|
+
return watcher2;
|
|
32804
32899
|
} catch (err) {
|
|
32805
32900
|
console.warn(`[himalaya-dev] bundle watcher unavailable: ${err.message}`);
|
|
32806
32901
|
return void 0;
|
|
@@ -32835,7 +32930,7 @@ function startBundleSourceWatcher(state) {
|
|
|
32835
32930
|
building = false;
|
|
32836
32931
|
};
|
|
32837
32932
|
try {
|
|
32838
|
-
const
|
|
32933
|
+
const watcher2 = watch(TIER5_SRC_ROOT, { persistent: false, recursive: true }, (_event, filename) => {
|
|
32839
32934
|
if (!filename || !/\.(ts|tsx)$/.test(filename)) return;
|
|
32840
32935
|
const name = filename.split(sep7)[0];
|
|
32841
32936
|
if (!name || name.startsWith(".")) return;
|
|
@@ -32843,11 +32938,11 @@ function startBundleSourceWatcher(state) {
|
|
|
32843
32938
|
if (timer) clearTimeout(timer);
|
|
32844
32939
|
timer = setTimeout(flush, 200);
|
|
32845
32940
|
});
|
|
32846
|
-
|
|
32941
|
+
watcher2.on("error", (err) => {
|
|
32847
32942
|
console.warn(`[himalaya-dev] bundle source watcher stopped: ${err.message}`);
|
|
32848
32943
|
});
|
|
32849
32944
|
console.log(`[himalaya-dev] watching T5 bundle sources: ${TIER5_SRC_ROOT}`);
|
|
32850
|
-
return
|
|
32945
|
+
return watcher2;
|
|
32851
32946
|
} catch (err) {
|
|
32852
32947
|
console.warn(`[himalaya-dev] bundle source watcher unavailable: ${err.message}`);
|
|
32853
32948
|
return void 0;
|
|
@@ -33015,7 +33110,7 @@ function startAppSourceWatcher(state) {
|
|
|
33015
33110
|
}
|
|
33016
33111
|
};
|
|
33017
33112
|
try {
|
|
33018
|
-
const
|
|
33113
|
+
const watcher2 = watch(appDir2, { persistent: false, recursive: true }, (_event, filename) => {
|
|
33019
33114
|
if (!filename) return;
|
|
33020
33115
|
const rel = String(filename).split(sep7).join("/");
|
|
33021
33116
|
if (!classifyAppPath(rel)) return;
|
|
@@ -33023,11 +33118,11 @@ function startAppSourceWatcher(state) {
|
|
|
33023
33118
|
if (timer) clearTimeout(timer);
|
|
33024
33119
|
timer = setTimeout(flush, 200);
|
|
33025
33120
|
});
|
|
33026
|
-
|
|
33121
|
+
watcher2.on("error", (err) => {
|
|
33027
33122
|
console.warn(`[himalaya-dev] app source watcher stopped: ${err.message}`);
|
|
33028
33123
|
});
|
|
33029
33124
|
console.log(`[himalaya-dev] watching app source: ${appDir2}`);
|
|
33030
|
-
return
|
|
33125
|
+
return watcher2;
|
|
33031
33126
|
} catch (err) {
|
|
33032
33127
|
console.warn(`[himalaya-dev] app source watcher unavailable: ${err.message}`);
|
|
33033
33128
|
return void 0;
|
|
@@ -35697,10 +35792,10 @@ function cmsAnswer(seed2, method, bare, body) {
|
|
|
35697
35792
|
pagingMetadata: { count: rows.length, tooManyToCount: false }
|
|
35698
35793
|
};
|
|
35699
35794
|
}
|
|
35700
|
-
function layeredTransport(
|
|
35701
|
-
const rules =
|
|
35702
|
-
const cms =
|
|
35703
|
-
const canned =
|
|
35795
|
+
function layeredTransport(layers2) {
|
|
35796
|
+
const rules = layers2.rules?.length ? [...layers2.rules] : null;
|
|
35797
|
+
const cms = layers2.cmsSeed && Object.keys(layers2.cmsSeed).length ? layers2.cmsSeed : null;
|
|
35798
|
+
const canned = layers2.canned && Object.keys(layers2.canned).length ? layers2.canned : null;
|
|
35704
35799
|
const label2 = [rules && "mocked", cms && "cms", canned && "canned"].filter(Boolean).join("+") || "offline";
|
|
35705
35800
|
const call = async (method, path2, body) => {
|
|
35706
35801
|
const m = String(method).toUpperCase();
|
|
@@ -39030,6 +39125,332 @@ var init_net_freeze = __esm({
|
|
|
39030
39125
|
}
|
|
39031
39126
|
});
|
|
39032
39127
|
|
|
39128
|
+
// src/studio-page.ts
|
|
39129
|
+
function renderStudioHtml(initial) {
|
|
39130
|
+
const accent = initial.app.palette.find((p) => p.name === "accentPrimary")?.hex ?? "#3b6fd8";
|
|
39131
|
+
return `<!doctype html>
|
|
39132
|
+
<html lang="en">
|
|
39133
|
+
<head>
|
|
39134
|
+
<meta charset="utf-8">
|
|
39135
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
39136
|
+
<title>${escapeHtml(initial.app.name)} \xB7 build board</title>
|
|
39137
|
+
<link rel="icon" id="fav" href="data:,">
|
|
39138
|
+
<style>
|
|
39139
|
+
: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)}
|
|
39140
|
+
@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}}
|
|
39141
|
+
*{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}
|
|
39142
|
+
.wrap{max-width:1180px;margin:0 auto;padding:20px 20px 60px}
|
|
39143
|
+
header{display:flex;align-items:center;gap:12px;margin-bottom:16px}
|
|
39144
|
+
.icon{width:40px;height:40px;border-radius:10px;background:var(--accent);object-fit:cover;flex:none}
|
|
39145
|
+
h1{font-size:20px;font-weight:600;margin:0}.sub{color:var(--muted);font-size:13px}
|
|
39146
|
+
.right{margin-left:auto;text-align:right}.clock{font-size:22px;font-variant-numeric:tabular-nums;font-weight:600}
|
|
39147
|
+
.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)}
|
|
39148
|
+
.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)}
|
|
39149
|
+
.step .lbl{font-size:11px;color:var(--faint);margin-top:4px;text-transform:capitalize}.step.cur .lbl{color:var(--ink);font-weight:600}
|
|
39150
|
+
.card{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:14px 16px;box-shadow:var(--shadow)}
|
|
39151
|
+
.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}
|
|
39152
|
+
.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}}
|
|
39153
|
+
h2{font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;margin:0 0 10px}
|
|
39154
|
+
.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}
|
|
39155
|
+
.phone img,.phone iframe{width:100%;height:100%;object-fit:cover;object-position:top;border:0;display:block;cursor:zoom-in}
|
|
39156
|
+
.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}
|
|
39157
|
+
.cap{text-align:center;color:var(--muted);font-size:12px;margin-top:8px}
|
|
39158
|
+
.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}
|
|
39159
|
+
.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)}
|
|
39160
|
+
.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}
|
|
39161
|
+
.wall{display:grid;grid-template-columns:repeat(auto-fill,minmax(112px,1fr));gap:14px}
|
|
39162
|
+
.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}
|
|
39163
|
+
.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)}
|
|
39164
|
+
.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}
|
|
39165
|
+
.sw{display:flex;gap:6px}.sw span{width:22px;height:22px;border-radius:50%;border:1px solid var(--line)}
|
|
39166
|
+
.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)}
|
|
39167
|
+
.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}
|
|
39168
|
+
.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}
|
|
39169
|
+
.empty{color:var(--faint);font-size:13px;padding:8px 0}
|
|
39170
|
+
#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}
|
|
39171
|
+
.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}}
|
|
39172
|
+
.changed .frame{animation:chg .9s ease both}@keyframes chg{35%{opacity:.25;transform:scale(.96)}100%{opacity:1;transform:none}}
|
|
39173
|
+
.step.fresh .bar{animation:fill .7s ease both;transform-origin:left}@keyframes fill{from{transform:scaleX(0)}to{transform:scaleX(1)}}
|
|
39174
|
+
.slidein{animation:slide .45s cubic-bezier(.2,.8,.2,1) both}@keyframes slide{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
|
|
39175
|
+
.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}}
|
|
39176
|
+
.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}}
|
|
39177
|
+
.icon,.step.cur .bar{transition:background-color .8s}.sw.pop span{animation:pop .6s ease both}@keyframes pop{50%{transform:scale(1.25)}}
|
|
39178
|
+
.quiet{color:var(--warn)}.quiet .dot{background:var(--warn)}.idle .dot{background:var(--faint)}
|
|
39179
|
+
.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)}
|
|
39180
|
+
#fx{position:fixed;inset:0;width:100%;height:100%;pointer-events:none;z-index:8}
|
|
39181
|
+
@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}}
|
|
39182
|
+
.scrub{display:flex;align-items:center;gap:8px;margin:-6px 0 4px}.scrub[hidden]{display:none}.scrub input{flex:1;min-width:0}
|
|
39183
|
+
.scrub .rd{font-size:12px;color:var(--muted);min-width:160px;font-variant-numeric:tabular-nums}
|
|
39184
|
+
.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)}
|
|
39185
|
+
.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}
|
|
39186
|
+
.newdot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--bad);margin-left:6px;vertical-align:middle}.newdot[hidden]{display:none}
|
|
39187
|
+
#focus[hidden],#still[hidden]{display:none}
|
|
39188
|
+
.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}
|
|
39189
|
+
.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}
|
|
39190
|
+
.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)}
|
|
39191
|
+
.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}
|
|
39192
|
+
.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)}
|
|
39193
|
+
@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}}
|
|
39194
|
+
</style>
|
|
39195
|
+
</head>
|
|
39196
|
+
<body>
|
|
39197
|
+
<div class="wrap">
|
|
39198
|
+
<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>
|
|
39199
|
+
<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>
|
|
39200
|
+
<div><span class="live idle" id="agent"><span class="dot"></span><span id="agentt">Waiting for the agent</span></span></div>
|
|
39201
|
+
<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>
|
|
39202
|
+
<div class="steps" id="steps"></div>
|
|
39203
|
+
<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>
|
|
39204
|
+
<div class="marks" id="marks"></div>
|
|
39205
|
+
<div class="viewing" id="viewing" hidden>Viewing <span id="viewingt"></span> \xB7 <a href="#" id="backlive">Back to live</a></div>
|
|
39206
|
+
<div class="card now"><div style="flex:1"><div class="meta" id="nowmeta">Now</div><div class="msg" id="nowmsg"></div></div></div>
|
|
39207
|
+
<div class="grid">
|
|
39208
|
+
<div><div class="card"><h2 id="focuslbl">Latest</h2><div id="focus"></div><div id="still" hidden></div><div class="film" id="film"></div>
|
|
39209
|
+
<button class="tog" id="pop" type="button" hidden>Pop out phone</button></div></div>
|
|
39210
|
+
<div>
|
|
39211
|
+
<div class="chips" id="chips"></div>
|
|
39212
|
+
<div class="card section"><h2>Screens</h2><div class="wall" id="wall"></div></div>
|
|
39213
|
+
<div class="card section" id="brandcard"><h2>Brand</h2><div class="brand" id="brand"></div></div>
|
|
39214
|
+
<div class="card section" id="navcard"><h2>Navigation the test crawl followed</h2><div class="nav" id="nav"></div></div>
|
|
39215
|
+
<div class="card section"><h2>Postcards</h2><ul class="log" id="log"></ul></div>
|
|
39216
|
+
</div></div></div>
|
|
39217
|
+
<div id="lb"><img alt=""></div>
|
|
39218
|
+
<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>
|
|
39219
|
+
<canvas id="fx" aria-hidden="true"></canvas>
|
|
39220
|
+
<script>window.__himiInitial = ${scriptJson(initial)};</script>
|
|
39221
|
+
<script>
|
|
39222
|
+
(function(){
|
|
39223
|
+
var cur=null, lastSeen=Date.now();
|
|
39224
|
+
function $(id){return document.getElementById(id)}
|
|
39225
|
+
function el(tag,cls,txt){var e=document.createElement(tag);if(cls)e.className=cls;if(txt!=null)e.textContent=txt;return e}
|
|
39226
|
+
function clear(e){while(e.firstChild)e.removeChild(e.firstChild)}
|
|
39227
|
+
function nowMs(){return asOf||Date.now()}
|
|
39228
|
+
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"}
|
|
39229
|
+
function hhmm(ts){var d=new Date(ts);return d.toLocaleTimeString([], {hour:"2-digit",minute:"2-digit"})}
|
|
39230
|
+
function recent(ts){return nowMs()-Date.parse(ts)<10*60*1000}
|
|
39231
|
+
function zoomable(img){img.addEventListener("click",function(){var lb=$("lb");lb.firstChild.src=img.src;lb.style.display="flex"})}
|
|
39232
|
+
function img(src,cls){var i=el("img",cls);i.src=src;i.alt="";i.loading="lazy";zoomable(i);return i}
|
|
39233
|
+
function chip(txt,kind){return el("span","chip"+(kind?" "+kind:""),txt)}
|
|
39234
|
+
function render(s){
|
|
39235
|
+
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;
|
|
39236
|
+
if(s.app.icon){$("icon").src=s.app.icon}else{$("icon").removeAttribute("src")}
|
|
39237
|
+
var steps=$("steps");clear(steps);var n=s.current?s.current.stepNumber:0;
|
|
39238
|
+
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)});
|
|
39239
|
+
var last=s.journal[0];
|
|
39240
|
+
$("nowmsg").textContent=last?last.message:"Waiting for the first postcard.";
|
|
39241
|
+
$("nowmeta").textContent=last?("Now \xB7 "+(last.step?("step "+last.stepNumber+" of 8, "+last.step+" \xB7 "):"")+ago(last.ts)):"Now";
|
|
39242
|
+
var film=$("film");clear(film);
|
|
39243
|
+
if(!rewinding){var n0=s.timelineFrames||0;$("scrub").hidden=n0<2;$("slider").max=String(Math.max(1,n0-1));$("slider").value=$("slider").max}
|
|
39244
|
+
if(rewinding){paintStill(s)}else{$("still").hidden=true;$("focus").hidden=false;var focus=$("focus");
|
|
39245
|
+
/* The live frame is KEPT across renders while its URL and its run are unchanged (a restarted run on
|
|
39246
|
+
the same port is a different server, and the old frame would never see its builds). A new iframe is a full page
|
|
39247
|
+
load of the preview: every postcard, rebuild and the once-a-minute re-render used to throw away
|
|
39248
|
+
the in-place repaint, the preview's scroll and wherever the owner had navigated inside it. */
|
|
39249
|
+
if(pip&&(!s.live||pip.frame.getAttribute("src")!==s.live.url||pip.frame.getAttribute("data-run")!==s.live.runId))bringBack();
|
|
39250
|
+
if(pip){paintStrip(s)}else{
|
|
39251
|
+
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;
|
|
39252
|
+
if(kept){while(focus.lastChild&&focus.lastChild!==kept.parentNode)focus.removeChild(focus.lastChild)}else clear(focus);
|
|
39253
|
+
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))}
|
|
39254
|
+
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"))}
|
|
39255
|
+
else{$("focuslbl").textContent="Latest";focus.appendChild(el("div","empty","The first render appears here."))}
|
|
39256
|
+
if(s.focus&&s.focus.frames.length>1)s.focus.frames.forEach(function(fm){film.appendChild(img(fm.img))});}}
|
|
39257
|
+
var chips=$("chips");clear(chips);var h=s.health;
|
|
39258
|
+
if(h.validate)chips.appendChild(chip(h.validate.ok?"Validate passing":"Validate: "+h.validate.errors+" errors",h.validate.ok?"ok":"bad"));
|
|
39259
|
+
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)}
|
|
39260
|
+
h.ux.forEach(function(u){chips.appendChild(chip("UX drive "+u.platform+": "+u.status,u.status==="passed"?"ok":u.status==="failed"?"bad":"warn"))});
|
|
39261
|
+
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"));
|
|
39262
|
+
if(!chips.firstChild)chips.appendChild(chip("Checks appear here as validate, test and push run"));
|
|
39263
|
+
var wall=$("wall");clear(wall);
|
|
39264
|
+
if(!s.screens.length)wall.appendChild(el("div","empty","Screens appear here as they render."));
|
|
39265
|
+
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));
|
|
39266
|
+
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)});
|
|
39267
|
+
var brand=$("brand");clear(brand);$("brandcard").style.display=(s.brand.site||s.app.palette.length)?"":"none";
|
|
39268
|
+
if(s.brand.site){var si=img(s.brand.site,"site");brand.appendChild(si)}
|
|
39269
|
+
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)}
|
|
39270
|
+
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)}
|
|
39271
|
+
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))});
|
|
39272
|
+
var log=$("log");clear(log);if(!s.journal.length)log.appendChild(el("li","empty","Postcards the agent journals appear here."));
|
|
39273
|
+
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));
|
|
39274
|
+
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)});
|
|
39275
|
+
paintPop(s);
|
|
39276
|
+
}
|
|
39277
|
+
/* Motion, sound and notices answer a CHANGE, never a redraw: effects() compares what is on the page
|
|
39278
|
+
now with what it showed last, so opening the board, the once-a-minute redraw and the two-second
|
|
39279
|
+
poll of an unchanged state do nothing, and each effect names a real event. */
|
|
39280
|
+
var seen=null,actx=null,sound=false,notices=false;
|
|
39281
|
+
var tlStates=null,rewinding=false,replaying=false,asOf=0,replayTimer=null;
|
|
39282
|
+
function foldAll(frames){var out=[],st=null,meta={};(frames||[]).forEach(function(f){
|
|
39283
|
+
var ns={step:null,now:null,screens:{},palette:[],checks:{validate:null,test:null,push:null},build:null};
|
|
39284
|
+
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}
|
|
39285
|
+
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;
|
|
39286
|
+
var sc=f.screens||{};for(var id in sc){if(sc[id]===null)delete ns.screens[id];else ns.screens[id]=sc[id]}
|
|
39287
|
+
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++}}
|
|
39288
|
+
var copy={};for(var q in meta)copy[q]={first:meta[q].first,changed:meta[q].changed,n:meta[q].n};
|
|
39289
|
+
ns.meta=copy;ns.ts=f.ts;ns.reveal=f.reveal||null;out.push(ns);st=ns});return out}
|
|
39290
|
+
function viewAt(i){var st=tlStates[i],b=cur;
|
|
39291
|
+
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}});
|
|
39292
|
+
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}}
|
|
39293
|
+
var fid=b.focus?b.focus.id:null,fimg=fid&&st.screens[fid];
|
|
39294
|
+
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,
|
|
39295
|
+
current:st.step?{step:st.step.name,stepNumber:st.step.n,of:8}:null,startedAt:b.startedAt,
|
|
39296
|
+
journal:journalAt(st,b),screens:screens,focus:fimg?{id:fid,frames:[{ts:st.ts,img:fimg}]}:null,
|
|
39297
|
+
health:{validate:st.checks.validate?{ok:st.checks.validate.ok,errors:st.checks.validate.errors,warnings:0,at:st.ts}:null,
|
|
39298
|
+
test:t?{ok:t.ok,screens:t.screens,actions:t.actions,gaps:t.gaps,prevGaps:prevGaps,errors:0,at:st.ts}:null,ux:[],
|
|
39299
|
+
push:st.checks.push?{app:"",releaseId:st.checks.push.releaseId,draft:st.checks.push.draft,at:st.ts}:null},
|
|
39300
|
+
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}}
|
|
39301
|
+
/* The board keeps only the newest postcards; the timeline remembers the one showing at each moment. */
|
|
39302
|
+
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}
|
|
39303
|
+
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)}
|
|
39304
|
+
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"}
|
|
39305
|
+
function marks(){var m=$("marks");clear(m);var n=tlStates.length;tlStates.forEach(function(st,i){var p=tlStates[i-1],kind=null;
|
|
39306
|
+
if(st.build&&st.build.ok===false&&(!p||p.build!==st.build))kind="bad";
|
|
39307
|
+
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";
|
|
39308
|
+
else if(st.now&&(!p||!p.now||p.now.ts!==st.now.ts))kind="";
|
|
39309
|
+
if(kind===null)return;var d=el("span",kind||null);d.style.left=(n>1?i/(n-1)*100:0)+"%";m.appendChild(d)})}
|
|
39310
|
+
function paintStill(s){$("focus").hidden=true;var still=$("still");still.hidden=false;clear(still);$("focuslbl").textContent="Home at "+hhmm(s.generatedAt);
|
|
39311
|
+
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."))}
|
|
39312
|
+
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);
|
|
39313
|
+
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);
|
|
39314
|
+
$("viewing").hidden=false;$("viewingt").textContent=hhmm(tlStates[i].ts);var s=viewAt(i);render(s);return s}
|
|
39315
|
+
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)})}
|
|
39316
|
+
function stopReplay(){replaying=false;if(replayTimer){clearTimeout(replayTimer);replayTimer=null}$("replay").textContent="Replay"}
|
|
39317
|
+
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)}
|
|
39318
|
+
/* The replay plan: about 30 s whatever the build's length. Frames that carry a milestone (a step,
|
|
39319
|
+
a draft, a failed build, the reveal) always play; the rest are sampled down to 120 moments; gaps
|
|
39320
|
+
follow real time, 150 ms-1.5 s each, and are scaled down so the whole never runs past 30 s. */
|
|
39321
|
+
function replayPlan(){var n=tlStates.length,keep={0:1};keep[n-1]=1;
|
|
39322
|
+
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}
|
|
39323
|
+
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})}
|
|
39324
|
+
var t0=Date.parse(tlStates[0].ts),span=Math.max(1,Date.parse(tlStates[n-1].ts)-t0),gaps=[],sum=0;
|
|
39325
|
+
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}
|
|
39326
|
+
var f=sum>30000?30000/sum:1;return{idx:idx,gaps:gaps.map(function(x){return x*f}),total:sum*f}}
|
|
39327
|
+
function replay(){loadTimeline(function(){if(!tlStates||tlStates.length<2)return;marks();replaying=true;$("replay").textContent="Pause";
|
|
39328
|
+
var scale=window.__himiReplayScale!=null?window.__himiReplayScale:1,plan=replayPlan();window.__himiReplayPlan={idx:plan.idx,totalMs:plan.total};
|
|
39329
|
+
seen=snap(rewindTo(0));var q=0;
|
|
39330
|
+
(function next(){if(!replaying)return;q++;if(q>=plan.idx.length){toLive();return}
|
|
39331
|
+
replayTimer=setTimeout(function(){var s=rewindTo(plan.idx[q]);if(s)effects(s);next()},plan.gaps[q-1]*scale)})()})}
|
|
39332
|
+
/* The floating phone: the ONE live frame moves into an always-on-top window (Document Picture-in-
|
|
39333
|
+
Picture; a small ordinary window elsewhere) and back. Two copies would run the app twice and
|
|
39334
|
+
drift apart as the owner taps; the cost of moving is one reload per move. */
|
|
39335
|
+
var pip=null;
|
|
39336
|
+
function canPip(){return !!window.documentPictureInPicture}
|
|
39337
|
+
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:""}
|
|
39338
|
+
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)+")"}
|
|
39339
|
+
function mountPip(w,fr){var d=w.document;d.title=cur.app.name+" \xB7 phone";
|
|
39340
|
+
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}";
|
|
39341
|
+
d.head.appendChild(st);var box=d.createElement("div");box.className="pp";d.body.appendChild(box);
|
|
39342
|
+
var home=fr.parentNode;box.appendChild(fr);
|
|
39343
|
+
var strip=d.createElement("div");strip.className="strip";strip.appendChild(d.createElement("div"));strip.appendChild(d.createElement("div"));d.body.appendChild(strip);
|
|
39344
|
+
pip={w:w,box:box,frame:fr,strip:strip,home:home};
|
|
39345
|
+
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);
|
|
39346
|
+
w.addEventListener("resize",fitPip);w.addEventListener("pagehide",bringBack);fitPip();paintStrip(cur);paintPop(cur)}
|
|
39347
|
+
var pipRefused=false;
|
|
39348
|
+
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)}
|
|
39349
|
+
/* A browser can expose Document PiP and still refuse the window (an embedded webview does): fall
|
|
39350
|
+
back to the small window rather than a click that does nothing and says nothing. The refusal may
|
|
39351
|
+
have spent the click's user activation, so a popup opened from it can be blocked: then the button
|
|
39352
|
+
offers the window, and the next click opens it directly with an activation of its own. */
|
|
39353
|
+
function popOut(){var fr=$("focus").querySelector("iframe.vp");if(!fr||pip)return;
|
|
39354
|
+
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)})}
|
|
39355
|
+
else openWindow(fr)}
|
|
39356
|
+
function bringBack(){if(!pip)return;var p=pip;pip=null;var away=document.getElementById("away");if(away&&away.parentNode)away.parentNode.removeChild(away);
|
|
39357
|
+
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)}
|
|
39358
|
+
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"}
|
|
39359
|
+
/* The brand reveal (decided board-side, played here only when it ARRIVES as a change) and opt-in
|
|
39360
|
+
read aloud: postcards and milestones, never rebuild messages, the newer cancelling the older. */
|
|
39361
|
+
var revealTimer=null,speakOn=false;try{speakOn=localStorage.getItem("himiStudioSpeak")==="1"}catch(e){}
|
|
39362
|
+
function fig(cap,cls){var f=el("figure",cls||null);f.appendChild(el("figcaption",null,cap));return f}
|
|
39363
|
+
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}
|
|
39364
|
+
function showReveal(r){var row=$("rvrow"),rv=$("rv");clear(row);rv.classList.remove("on");
|
|
39365
|
+
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)}
|
|
39366
|
+
var same=!r.before||r.before===r.after;
|
|
39367
|
+
if(same){var f1=fig("Your app, your brand");f1.appendChild(phoneImg([[r.after]]));row.appendChild(f1)}
|
|
39368
|
+
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)}
|
|
39369
|
+
else{var fw=fig("Your app");fw.appendChild(phoneImg([[r.before],[r.after,"after"]]));row.appendChild(fw);setTimeout(function(){rv.classList.add("on")},700)}
|
|
39370
|
+
var box=$("reveal");box.hidden=false;box.setAttribute("data-shown",String((+box.getAttribute("data-shown")||0)+1));clearTimeout(revealTimer);revealTimer=setTimeout(hideReveal,6000)}
|
|
39371
|
+
function hideReveal(){$("reveal").hidden=true;clearTimeout(revealTimer)}
|
|
39372
|
+
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){}
|
|
39373
|
+
var raf=window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(f){return setTimeout(function(){f(Date.now())},16)};
|
|
39374
|
+
function now(){return window.performance&&performance.now?performance.now():Date.now()}
|
|
39375
|
+
function reduced(){try{return matchMedia("(prefers-reduced-motion: reduce)").matches}catch(e){return false}}
|
|
39376
|
+
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){}}
|
|
39377
|
+
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")}};
|
|
39378
|
+
/* Notices are the BOARD's opt-in, not just the browser's: a permission granted to this origin once
|
|
39379
|
+
(an earlier board, another run) must not switch them on, and the toggle must switch them off. */
|
|
39380
|
+
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){}}
|
|
39381
|
+
function accentNow(){return (getComputedStyle(document.documentElement).getPropertyValue("--accent")||"").trim()||"#3b6fd8"}
|
|
39382
|
+
/* The preview lays out at a real phone's viewport (390 x 844 CSS px) and is scaled into the frame.
|
|
39383
|
+
Sized to the frame itself it was ~280px wide: narrower than any phone, so screens overflowed
|
|
39384
|
+
sideways and scrolled horizontally. */
|
|
39385
|
+
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)))}
|
|
39386
|
+
window.addEventListener("resize",fit);
|
|
39387
|
+
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){}}
|
|
39388
|
+
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)})()}
|
|
39389
|
+
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)})()}
|
|
39390
|
+
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}}
|
|
39391
|
+
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}
|
|
39392
|
+
function effects(s){var is=snap(s),was=seen;seen=is;if(is.accent)document.documentElement.style.setProperty("--accent",is.accent);
|
|
39393
|
+
/* The phone (kept across renders) and the Now line outlive a render: clear what they played last. */
|
|
39394
|
+
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;
|
|
39395
|
+
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();
|
|
39396
|
+
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()}
|
|
39397
|
+
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])}
|
|
39398
|
+
/* A rebuild is a later build of the SAME run: a run appearing, or restarting, records its first
|
|
39399
|
+
build too, and nothing was rebuilt then. */
|
|
39400
|
+
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||"")}}
|
|
39401
|
+
if(was.gaps!=null&&is.gaps!=null&&is.gaps!==was.gaps)countTo($("gapn"),was.gaps,is.gaps);
|
|
39402
|
+
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))}
|
|
39403
|
+
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")}
|
|
39404
|
+
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}
|
|
39405
|
+
if((published||handed)&&!said)speak(published?"Your draft is ready to open on your phone.":"Your app is handed over.");
|
|
39406
|
+
if(is.reveal&&is.reveal!==was.reveal)showReveal(s.reveal);
|
|
39407
|
+
}
|
|
39408
|
+
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}
|
|
39409
|
+
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))}
|
|
39410
|
+
function setNotices(v){notices=v;try{localStorage.setItem("himiStudioNotify",v?"1":"0")}catch(e){}paintToggles()}
|
|
39411
|
+
$("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()});
|
|
39412
|
+
/* The click acts on what the button SAYS (the effective state), so a remembered opt-in whose browser
|
|
39413
|
+
permission was since reset reads "off" and one click asks for permission, not two. */
|
|
39414
|
+
$("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){}});
|
|
39415
|
+
document.addEventListener("click",function(){try{if(actx&&actx.state==="suspended")actx.resume()}catch(e){}},{once:true});
|
|
39416
|
+
paintToggles();
|
|
39417
|
+
$("slider").addEventListener("input",function(){var i=+this.value;if(replaying)stopReplay();if(!rewinding||!tlStates)enterRewind(i);else rewindTo(i)});
|
|
39418
|
+
$("replay").addEventListener("click",function(){if(replaying){stopReplay();return}replay()});
|
|
39419
|
+
$("golive").addEventListener("click",toLive);
|
|
39420
|
+
$("rvx").addEventListener("click",hideReveal);$("reveal").addEventListener("click",function(e){if(e.target===this)hideReveal()});
|
|
39421
|
+
$("say").addEventListener("click",function(){speakOn=!speakOn;try{localStorage.setItem("himiStudioSpeak",speakOn?"1":"0")}catch(e){}paintToggles();if(speakOn)speak("Read aloud is on.")});
|
|
39422
|
+
$("pop").addEventListener("click",function(){if(pip)bringBack();else popOut()});
|
|
39423
|
+
$("backlive").addEventListener("click",function(e){e.preventDefault();toLive()});
|
|
39424
|
+
document.addEventListener("keydown",function(e){if($("scrub").hidden)return;var tg=e.target,tn=tg&&tg.tagName;
|
|
39425
|
+
if(e.key==="Escape"&&rewinding){toLive();return}
|
|
39426
|
+
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()}
|
|
39427
|
+
if(e.key===" "&&tn!=="BUTTON"&&tn!=="INPUT"){e.preventDefault();$("replay").click()}});
|
|
39428
|
+
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}};
|
|
39429
|
+
$("lb").addEventListener("click",function(){this.style.display="none"});
|
|
39430
|
+
window.__himiStudio(window.__himiInitial);
|
|
39431
|
+
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);
|
|
39432
|
+
var ticks=0;
|
|
39433
|
+
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;
|
|
39434
|
+
$("clock").textContent=(hh?hh+":":"")+(mm<10&&hh?"0":"")+mm+":"+(ss<10?"0":"")+ss;
|
|
39435
|
+
$("updated").textContent="updated "+ago(cur.generatedAt);$("live").className="live"+(Date.now()-lastSeen>10000?" stale":"");
|
|
39436
|
+
var a=activityAt(cur),q=a?Date.now()-a:0,done=cur.current&&cur.current.stepNumber===8;
|
|
39437
|
+
$("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);
|
|
39438
|
+
})();
|
|
39439
|
+
</script>
|
|
39440
|
+
</body>
|
|
39441
|
+
</html>
|
|
39442
|
+
`;
|
|
39443
|
+
}
|
|
39444
|
+
function escapeHtml(s) {
|
|
39445
|
+
return s.replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]);
|
|
39446
|
+
}
|
|
39447
|
+
var scriptJson;
|
|
39448
|
+
var init_studio_page = __esm({
|
|
39449
|
+
"src/studio-page.ts"() {
|
|
39450
|
+
scriptJson = (value) => JSON.stringify(value).replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
39451
|
+
}
|
|
39452
|
+
});
|
|
39453
|
+
|
|
39033
39454
|
// src/progress.ts
|
|
39034
39455
|
var progress_exports = {};
|
|
39035
39456
|
__export(progress_exports, {
|
|
@@ -39276,6 +39697,152 @@ var init_progress = __esm({
|
|
|
39276
39697
|
}
|
|
39277
39698
|
});
|
|
39278
39699
|
|
|
39700
|
+
// src/studio-timeline.ts
|
|
39701
|
+
import { existsSync as existsSync39, readFileSync as readFileSync42 } from "node:fs";
|
|
39702
|
+
import { join as join36 } from "node:path";
|
|
39703
|
+
function stateOf(view) {
|
|
39704
|
+
const j = view.journal[0];
|
|
39705
|
+
const h = view.health;
|
|
39706
|
+
const b = view.live?.lastBuild ?? null;
|
|
39707
|
+
return {
|
|
39708
|
+
step: view.current ? { n: view.current.stepNumber, name: view.current.step } : null,
|
|
39709
|
+
now: j ? { ts: j.ts, message: j.message, images: j.images } : null,
|
|
39710
|
+
screens: Object.fromEntries(view.screens.map((s) => [s.id, s.img])),
|
|
39711
|
+
palette: view.app.palette.map((p) => [p.name, p.hex]),
|
|
39712
|
+
checks: {
|
|
39713
|
+
validate: h.validate ? { ok: h.validate.ok, errors: h.validate.errors } : null,
|
|
39714
|
+
test: h.test ? { screens: h.test.screens, actions: h.test.actions, gaps: h.test.gaps, ok: h.test.ok } : null,
|
|
39715
|
+
push: h.push ? { draft: h.push.draft, releaseId: h.push.releaseId } : null
|
|
39716
|
+
},
|
|
39717
|
+
build: b && view.live ? { ok: b.ok, ms: b.ms, screens: b.screens, at: b.at, run: view.live.runId } : null
|
|
39718
|
+
};
|
|
39719
|
+
}
|
|
39720
|
+
function frameFor(state, prev, ts2, v, key2) {
|
|
39721
|
+
if (key2 || !prev) return { ts: ts2, v, key: true, ...state };
|
|
39722
|
+
const f = { ts: ts2, v };
|
|
39723
|
+
if (!same(state.step, prev.step)) f.step = state.step;
|
|
39724
|
+
if (!same(state.now, prev.now)) f.now = state.now;
|
|
39725
|
+
const screens = {};
|
|
39726
|
+
for (const [id, img] of Object.entries(state.screens)) if (prev.screens[id] !== img) screens[id] = img;
|
|
39727
|
+
for (const id of Object.keys(prev.screens)) if (!(id in state.screens)) screens[id] = null;
|
|
39728
|
+
if (Object.keys(screens).length) f.screens = screens;
|
|
39729
|
+
if (!same(state.palette, prev.palette)) f.palette = state.palette;
|
|
39730
|
+
if (!same(state.checks, prev.checks)) f.checks = state.checks;
|
|
39731
|
+
if (!same(state.build, prev.build)) f.build = state.build;
|
|
39732
|
+
return f;
|
|
39733
|
+
}
|
|
39734
|
+
function fold(prev, f) {
|
|
39735
|
+
const base = f.key || !prev ? EMPTY : prev;
|
|
39736
|
+
const screens = f.key ? {} : { ...base.screens };
|
|
39737
|
+
for (const [id, img] of Object.entries(f.screens ?? {})) {
|
|
39738
|
+
if (img === null) delete screens[id];
|
|
39739
|
+
else screens[id] = img;
|
|
39740
|
+
}
|
|
39741
|
+
return {
|
|
39742
|
+
step: "step" in f ? f.step ?? null : base.step,
|
|
39743
|
+
now: "now" in f ? f.now ?? null : base.now,
|
|
39744
|
+
screens,
|
|
39745
|
+
palette: f.palette ?? base.palette,
|
|
39746
|
+
checks: f.checks ?? base.checks,
|
|
39747
|
+
build: "build" in f ? f.build ?? null : base.build
|
|
39748
|
+
};
|
|
39749
|
+
}
|
|
39750
|
+
function validFrame(f) {
|
|
39751
|
+
if (!isObj(f) || !isStr(f.ts) || !isStr(f.v)) return false;
|
|
39752
|
+
if (f.key !== void 0 && f.key !== true) return false;
|
|
39753
|
+
if ("step" in f && !nullOr(f.step, (x) => typeof x.n === "number" && isStr(x.name))) return false;
|
|
39754
|
+
if ("now" in f && !nullOr(f.now, (x) => isStr(x.ts) && isStr(x.message) && strs(x.images))) return false;
|
|
39755
|
+
if ("screens" in f && !(isObj(f.screens) && Object.values(f.screens).every((x) => x === null || isStr(x)))) return false;
|
|
39756
|
+
if ("palette" in f && !(Array.isArray(f.palette) && f.palette.every((p) => Array.isArray(p) && p.length === 2 && p.every(isStr)))) return false;
|
|
39757
|
+
if ("checks" in f) {
|
|
39758
|
+
const c = f.checks;
|
|
39759
|
+
if (!isObj(c)) return false;
|
|
39760
|
+
if (!nullOr(c.validate ?? null, (x) => typeof x.ok === "boolean" && typeof x.errors === "number")) return false;
|
|
39761
|
+
if (!nullOr(c.test ?? null, (x) => ["screens", "actions", "gaps"].every((k) => typeof x[k] === "number") && typeof x.ok === "boolean")) return false;
|
|
39762
|
+
if (!nullOr(c.push ?? null, (x) => typeof x.draft === "boolean" && isStr(x.releaseId))) return false;
|
|
39763
|
+
}
|
|
39764
|
+
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;
|
|
39765
|
+
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;
|
|
39766
|
+
return true;
|
|
39767
|
+
}
|
|
39768
|
+
function readTimeline(dir) {
|
|
39769
|
+
const file = join36(dir, TIMELINE_FILE);
|
|
39770
|
+
if (!existsSync39(file)) return [];
|
|
39771
|
+
const out = [];
|
|
39772
|
+
for (const line of readFileSync42(file, "utf8").split("\n")) {
|
|
39773
|
+
if (!line.trim()) continue;
|
|
39774
|
+
try {
|
|
39775
|
+
const f = JSON.parse(line);
|
|
39776
|
+
if (validFrame(f)) out.push(f);
|
|
39777
|
+
} catch {
|
|
39778
|
+
}
|
|
39779
|
+
}
|
|
39780
|
+
const first = out.findIndex((f) => f.key === true);
|
|
39781
|
+
return first < 0 ? [] : out.slice(first);
|
|
39782
|
+
}
|
|
39783
|
+
function trim(frames) {
|
|
39784
|
+
if (frames.length <= MAX_FRAMES) return frames;
|
|
39785
|
+
for (let i = 1; i < frames.length; i++) if (frames[i].key && frames.length - i <= MAX_FRAMES) return frames.slice(i);
|
|
39786
|
+
return frames.slice(-MAX_FRAMES);
|
|
39787
|
+
}
|
|
39788
|
+
function writeTimelineJs(dir, frames) {
|
|
39789
|
+
writeFileAtomic(join36(dir, TIMELINE_JS), `window.__himiTimeline && window.__himiTimeline(${scriptJson(frames)});
|
|
39790
|
+
`);
|
|
39791
|
+
}
|
|
39792
|
+
function appendFrame(dir, view, reveal = null) {
|
|
39793
|
+
const frames = readTimeline(dir);
|
|
39794
|
+
const last = frames[frames.length - 1];
|
|
39795
|
+
if (last && last.v === view.v && !reveal) {
|
|
39796
|
+
if (!existsSync39(join36(dir, TIMELINE_JS))) writeTimelineJs(dir, frames);
|
|
39797
|
+
return frames.length;
|
|
39798
|
+
}
|
|
39799
|
+
let prev = null;
|
|
39800
|
+
for (const f of frames) prev = fold(prev, f);
|
|
39801
|
+
const frame = frameFor(stateOf(view), prev, view.generatedAt, view.v, frames.length % KEYFRAME_EVERY === 0);
|
|
39802
|
+
if (reveal) frame.reveal = reveal;
|
|
39803
|
+
const kept = trim([...frames, frame]);
|
|
39804
|
+
writeFileAtomic(join36(dir, TIMELINE_FILE), kept.map((f) => JSON.stringify(f)).join("\n") + "\n");
|
|
39805
|
+
writeTimelineJs(dir, kept);
|
|
39806
|
+
return kept.length;
|
|
39807
|
+
}
|
|
39808
|
+
function brandLanded(view, first) {
|
|
39809
|
+
const was = accentOf(first?.palette);
|
|
39810
|
+
const is = accentOf(view.app.palette);
|
|
39811
|
+
return was !== null && is !== null && was !== is || view.journal.some((j) => j.step === "brand");
|
|
39812
|
+
}
|
|
39813
|
+
function revealFor(view, memory) {
|
|
39814
|
+
if (memory.revealedAt || !memory.brandSeenAt || !view.focus || !view.focus.frames.length) return null;
|
|
39815
|
+
const latest = view.focus.frames[view.focus.frames.length - 1];
|
|
39816
|
+
if (latest.ts < memory.brandSeenAt) return null;
|
|
39817
|
+
const firstVersion = memory.timeline.find((t) => t.id === view.focus.id);
|
|
39818
|
+
const before = firstVersion ? `../history/${firstVersion.sha}.${firstVersion.ext}` : latest.img;
|
|
39819
|
+
return { site: view.brand.site, before, after: latest.img };
|
|
39820
|
+
}
|
|
39821
|
+
var TIMELINE_FILE, TIMELINE_JS, MAX_FRAMES, KEYFRAME_EVERY, same, EMPTY, isStr, isObj, strs, nullOr, accentOf;
|
|
39822
|
+
var init_studio_timeline = __esm({
|
|
39823
|
+
"src/studio-timeline.ts"() {
|
|
39824
|
+
init_progress();
|
|
39825
|
+
init_studio_page();
|
|
39826
|
+
TIMELINE_FILE = join36(".himi", "studio", "timeline.jsonl");
|
|
39827
|
+
TIMELINE_JS = join36(".himi", "studio", "timeline.js");
|
|
39828
|
+
MAX_FRAMES = 2e3;
|
|
39829
|
+
KEYFRAME_EVERY = 50;
|
|
39830
|
+
same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
39831
|
+
EMPTY = { step: null, now: null, screens: {}, palette: [], checks: { validate: null, test: null, push: null }, build: null };
|
|
39832
|
+
isStr = (x) => typeof x === "string";
|
|
39833
|
+
isObj = (x) => typeof x === "object" && x !== null && !Array.isArray(x);
|
|
39834
|
+
strs = (x) => Array.isArray(x) && x.every(isStr);
|
|
39835
|
+
nullOr = (x, ok) => x === null || isObj(x) && ok(x);
|
|
39836
|
+
accentOf = (palette2) => {
|
|
39837
|
+
for (const p of palette2 ?? []) {
|
|
39838
|
+
const [name, hex2] = Array.isArray(p) ? p : [p.name, p.hex];
|
|
39839
|
+
if (name === "accentPrimary") return hex2;
|
|
39840
|
+
}
|
|
39841
|
+
return null;
|
|
39842
|
+
};
|
|
39843
|
+
}
|
|
39844
|
+
});
|
|
39845
|
+
|
|
39279
39846
|
// src/studio.ts
|
|
39280
39847
|
var studio_exports = {};
|
|
39281
39848
|
__export(studio_exports, {
|
|
@@ -39294,8 +39861,8 @@ __export(studio_exports, {
|
|
|
39294
39861
|
writeStudioRecord: () => writeStudioRecord
|
|
39295
39862
|
});
|
|
39296
39863
|
import { createHash as createHash20 } from "node:crypto";
|
|
39297
|
-
import { existsSync as
|
|
39298
|
-
import { basename as basename9, extname as extname3, join as
|
|
39864
|
+
import { existsSync as existsSync40, readdirSync as readdirSync20, readFileSync as readFileSync43, realpathSync as realpathSync4, statSync as statSync8 } from "node:fs";
|
|
39865
|
+
import { basename as basename9, extname as extname3, join as join37, relative as relative6, resolve as resolve33, sep as sep9 } from "node:path";
|
|
39299
39866
|
import { pathToFileURL as pathToFileURL7 } from "node:url";
|
|
39300
39867
|
function realInside(dir, abs) {
|
|
39301
39868
|
try {
|
|
@@ -39320,12 +39887,12 @@ function archiveFile(dir, memory, abs) {
|
|
|
39320
39887
|
if (size === 0) return null;
|
|
39321
39888
|
const key2 = relative6(dir, abs);
|
|
39322
39889
|
const hit = memory.files?.[key2];
|
|
39323
|
-
if (hit && hit.size === size && hit.mtimeMs === mtimeMs && hit.ino === ino &&
|
|
39890
|
+
if (hit && hit.size === size && hit.mtimeMs === mtimeMs && hit.ino === ino && existsSync40(join37(dir, HISTORY_DIR, `${hit.sha}.${hit.ext}`))) {
|
|
39324
39891
|
return { sha: hit.sha, ext: hit.ext, file: `${hit.sha}.${hit.ext}` };
|
|
39325
39892
|
}
|
|
39326
39893
|
let archived;
|
|
39327
39894
|
try {
|
|
39328
|
-
archived = archiveBytes(dir,
|
|
39895
|
+
archived = archiveBytes(dir, readFileSync43(real));
|
|
39329
39896
|
} catch {
|
|
39330
39897
|
return null;
|
|
39331
39898
|
}
|
|
@@ -39334,17 +39901,17 @@ function archiveFile(dir, memory, abs) {
|
|
|
39334
39901
|
return { sha: archived.sha256, ext: archived.ext, file: `${archived.sha256}.${archived.ext}` };
|
|
39335
39902
|
}
|
|
39336
39903
|
function loadMemory(dir, now) {
|
|
39337
|
-
const raw = obj(readJson2(
|
|
39904
|
+
const raw = obj(readJson2(join37(dir, MEMORY_FILE)));
|
|
39338
39905
|
if (raw && raw.version === 1 && obj(raw.shots) && Array.isArray(raw.timeline)) return raw;
|
|
39339
39906
|
return { version: 1, createdAt: now, shots: {}, timeline: [] };
|
|
39340
39907
|
}
|
|
39341
39908
|
function observeShots(dir, memory, now) {
|
|
39342
|
-
const shotsDir =
|
|
39909
|
+
const shotsDir = join37(dir, ".himi", "shots");
|
|
39343
39910
|
const seen = /* @__PURE__ */ new Set();
|
|
39344
|
-
const files =
|
|
39911
|
+
const files = existsSync40(shotsDir) ? readdirSync20(shotsDir).filter((f) => /\.(png|jpe?g)$/i.test(f)).sort() : [];
|
|
39345
39912
|
for (const f of files) {
|
|
39346
39913
|
const id = basename9(f, extname3(f));
|
|
39347
|
-
const archived = archiveFile(dir, memory,
|
|
39914
|
+
const archived = archiveFile(dir, memory, join37(shotsDir, f));
|
|
39348
39915
|
if (!archived) continue;
|
|
39349
39916
|
seen.add(id);
|
|
39350
39917
|
const { sha, ext } = archived;
|
|
@@ -39359,14 +39926,14 @@ function observeShots(dir, memory, now) {
|
|
|
39359
39926
|
memory.shots[id] = { ...prev, present: true };
|
|
39360
39927
|
}
|
|
39361
39928
|
}
|
|
39362
|
-
if (
|
|
39929
|
+
if (existsSync40(shotsDir)) {
|
|
39363
39930
|
for (const [id, shot] of Object.entries(memory.shots)) if (!seen.has(id) && shot.present) memory.shots[id] = { ...shot, present: false };
|
|
39364
39931
|
}
|
|
39365
39932
|
if (memory.timeline.length > MAX_TIMELINE) memory.timeline = memory.timeline.slice(-MAX_TIMELINE);
|
|
39366
39933
|
return memory;
|
|
39367
39934
|
}
|
|
39368
39935
|
function palette(dir) {
|
|
39369
|
-
const colors = obj(obj(readJson2(
|
|
39936
|
+
const colors = obj(obj(readJson2(join37(dir, "tokens.json")))?.colors);
|
|
39370
39937
|
if (!colors) return [];
|
|
39371
39938
|
const pick2 = (key2) => {
|
|
39372
39939
|
const v = colors[key2];
|
|
@@ -39376,7 +39943,7 @@ function palette(dir) {
|
|
|
39376
39943
|
return ["accentPrimary", "accentSecondary", "accentSurface", "surfacePrimary", "textPrimary"].map(pick2).filter((x) => !!x);
|
|
39377
39944
|
}
|
|
39378
39945
|
function appIdentity(dir) {
|
|
39379
|
-
const manifest = obj(readJson2(
|
|
39946
|
+
const manifest = obj(readJson2(join37(dir, "himalaya.content.json")));
|
|
39380
39947
|
const name = text(manifest?.name) ?? basename9(resolve33(dir));
|
|
39381
39948
|
const icon = text(manifest?.icon)?.trim();
|
|
39382
39949
|
const iconPath = icon ? resolve33(dir, icon) : null;
|
|
@@ -39384,12 +39951,12 @@ function appIdentity(dir) {
|
|
|
39384
39951
|
return { name, iconFile: real && statSync8(real).isFile() ? iconPath : null };
|
|
39385
39952
|
}
|
|
39386
39953
|
function testRuns(dir) {
|
|
39387
|
-
const att =
|
|
39388
|
-
if (!
|
|
39954
|
+
const att = join37(dir, ".himi", "attestations");
|
|
39955
|
+
if (!existsSync40(att)) return [];
|
|
39389
39956
|
const runs = [];
|
|
39390
39957
|
for (const f of readdirSync20(att)) {
|
|
39391
39958
|
if (!f.endsWith(".json") || f === "latest.json") continue;
|
|
39392
|
-
const r = obj(readJson2(
|
|
39959
|
+
const r = obj(readJson2(join37(att, f)));
|
|
39393
39960
|
if (!r || r.tool !== "himi-test" || typeof r.runId !== "string") continue;
|
|
39394
39961
|
const report2 = obj(r.report);
|
|
39395
39962
|
const coverage = obj(r.coverage);
|
|
@@ -39405,20 +39972,20 @@ function testRuns(dir) {
|
|
|
39405
39972
|
return runs.sort((a, b) => a.runId.localeCompare(b.runId));
|
|
39406
39973
|
}
|
|
39407
39974
|
function siteHome(dir) {
|
|
39408
|
-
for (const pages of [
|
|
39409
|
-
if (!
|
|
39975
|
+
for (const pages of [join37(dir, ".himi", "business-book", "evidence", "pages"), join37(dir, "evidence", "pages")]) {
|
|
39976
|
+
if (!existsSync40(pages)) continue;
|
|
39410
39977
|
const home = readdirSync20(pages).filter((f) => /^home.*\.(png|jpe?g)$/i.test(f)).sort()[0];
|
|
39411
|
-
if (home) return
|
|
39978
|
+
if (home) return join37(pages, home);
|
|
39412
39979
|
}
|
|
39413
39980
|
return null;
|
|
39414
39981
|
}
|
|
39415
39982
|
function uxStatuses(dir) {
|
|
39416
|
-
const platforms = obj(obj(readJson2(
|
|
39983
|
+
const platforms = obj(obj(readJson2(join37(dir, ".himi", "ux-audit.json")))?.platforms);
|
|
39417
39984
|
if (!platforms) return [];
|
|
39418
39985
|
return Object.entries(platforms).map(([platform, rec]) => ({ platform, status: text(obj(rec)?.status) ?? "" })).filter((p) => p.status);
|
|
39419
39986
|
}
|
|
39420
39987
|
function liveRun(dir) {
|
|
39421
|
-
const rec = obj(readJson2(
|
|
39988
|
+
const rec = obj(readJson2(join37(dir, RUN_RECORD)));
|
|
39422
39989
|
const url = text(rec?.url);
|
|
39423
39990
|
const pid = rec?.pid;
|
|
39424
39991
|
if (!url || !/^https?:\/\//i.test(url) || typeof pid !== "number") return null;
|
|
@@ -39468,9 +40035,9 @@ function buildView(dir, memory, now) {
|
|
|
39468
40035
|
const runs = testRuns(dir);
|
|
39469
40036
|
const last = runs[runs.length - 1];
|
|
39470
40037
|
const prev = runs[runs.length - 2];
|
|
39471
|
-
const validate3 = obj(readJson2(
|
|
39472
|
-
const push = obj(readJson2(
|
|
39473
|
-
const edges = readJson2(
|
|
40038
|
+
const validate3 = obj(readJson2(join37(dir, VALIDATE_RECORD)));
|
|
40039
|
+
const push = obj(readJson2(join37(dir, PUSH_RECORD)));
|
|
40040
|
+
const edges = readJson2(join37(dir, EDGES_RECORD));
|
|
39474
40041
|
const nav = [];
|
|
39475
40042
|
if (Array.isArray(edges)) {
|
|
39476
40043
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -39508,9 +40075,11 @@ function buildView(dir, memory, now) {
|
|
|
39508
40075
|
},
|
|
39509
40076
|
brand: { site: siteImg },
|
|
39510
40077
|
nav,
|
|
39511
|
-
live: liveRun(dir)
|
|
40078
|
+
live: liveRun(dir),
|
|
40079
|
+
timelineFrames: 0,
|
|
40080
|
+
reveal: memory.reveal ?? null
|
|
39512
40081
|
};
|
|
39513
|
-
const { generatedAt: _ignored, ...stable } = view;
|
|
40082
|
+
const { generatedAt: _ignored, timelineFrames: _count, ...stable } = view;
|
|
39514
40083
|
const v = createHash20("sha256").update(JSON.stringify(stable)).digest("hex").slice(0, 16);
|
|
39515
40084
|
return { v, ...view };
|
|
39516
40085
|
}
|
|
@@ -39521,16 +40090,33 @@ function writeBoard(dir, now) {
|
|
|
39521
40090
|
if (!realDirIn(dir, STUDIO_DIR)) throw new UnsafeHimiDirError(STUDIO_DIR);
|
|
39522
40091
|
if (!realDirIn(dir, HISTORY_DIR)) throw new UnsafeHimiDirError(HISTORY_DIR);
|
|
39523
40092
|
const memory = observeShots(dir, loadMemory(dir, now), now);
|
|
39524
|
-
|
|
39525
|
-
|
|
39526
|
-
|
|
40093
|
+
let view = buildView(dir, memory, now);
|
|
40094
|
+
let reveal = null;
|
|
40095
|
+
try {
|
|
40096
|
+
if (!memory.brandSeenAt && brandLanded(view, readTimeline(dir)[0])) memory.brandSeenAt = now;
|
|
40097
|
+
reveal = revealFor(view, memory);
|
|
40098
|
+
if (reveal) {
|
|
40099
|
+
memory.revealedAt = now;
|
|
40100
|
+
memory.reveal = { at: now, ...reveal };
|
|
40101
|
+
view = buildView(dir, memory, now);
|
|
40102
|
+
}
|
|
40103
|
+
} catch {
|
|
40104
|
+
reveal = null;
|
|
40105
|
+
}
|
|
40106
|
+
try {
|
|
40107
|
+
view.timelineFrames = appendFrame(dir, view, reveal);
|
|
40108
|
+
} catch {
|
|
40109
|
+
view.timelineFrames = 0;
|
|
40110
|
+
}
|
|
40111
|
+
writeAtomic(join37(dir, MEMORY_FILE), JSON.stringify(memory));
|
|
40112
|
+
writeAtomic(join37(dir, STATE_FILE), `window.__himiStudio && window.__himiStudio(${scriptJson(view)});
|
|
39527
40113
|
`);
|
|
39528
|
-
writeAtomic(
|
|
40114
|
+
writeAtomic(join37(dir, STUDIO_PAGE), renderStudioHtml(view));
|
|
39529
40115
|
return view;
|
|
39530
40116
|
}
|
|
39531
40117
|
function refreshStudio(dir, now = /* @__PURE__ */ new Date()) {
|
|
39532
40118
|
try {
|
|
39533
|
-
if (!
|
|
40119
|
+
if (!existsSync40(join37(dir, STUDIO_PAGE))) return { refreshed: false };
|
|
39534
40120
|
return { refreshed: true, view: writeBoard(dir, now.toISOString()) };
|
|
39535
40121
|
} catch {
|
|
39536
40122
|
return { refreshed: false };
|
|
@@ -39538,225 +40124,38 @@ function refreshStudio(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
39538
40124
|
}
|
|
39539
40125
|
function openStudio(dir, now = /* @__PURE__ */ new Date()) {
|
|
39540
40126
|
const view = writeBoard(dir, now.toISOString());
|
|
39541
|
-
const page =
|
|
40127
|
+
const page = join37(dir, STUDIO_PAGE);
|
|
39542
40128
|
return { page, url: pathToFileURL7(page).href, view };
|
|
39543
40129
|
}
|
|
39544
40130
|
function writeStudioRecord(dir, record2, value) {
|
|
39545
40131
|
try {
|
|
39546
40132
|
if (!realDirIn(dir, ".himi")) return;
|
|
39547
|
-
writeAtomic(
|
|
40133
|
+
writeAtomic(join37(dir, record2), `${JSON.stringify(value, null, 2)}
|
|
39548
40134
|
`);
|
|
39549
40135
|
} catch {
|
|
39550
40136
|
}
|
|
39551
40137
|
}
|
|
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;
|
|
40138
|
+
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
40139
|
var init_studio = __esm({
|
|
39744
40140
|
"src/studio.ts"() {
|
|
40141
|
+
init_studio_page();
|
|
40142
|
+
init_studio_timeline();
|
|
39745
40143
|
init_progress();
|
|
39746
|
-
|
|
39747
|
-
|
|
39748
|
-
|
|
39749
|
-
|
|
39750
|
-
|
|
39751
|
-
|
|
39752
|
-
|
|
39753
|
-
|
|
40144
|
+
init_studio_page();
|
|
40145
|
+
STUDIO_DIR = join37(".himi", "studio");
|
|
40146
|
+
STUDIO_PAGE = join37(STUDIO_DIR, "index.html");
|
|
40147
|
+
STATE_FILE = join37(STUDIO_DIR, "state.js");
|
|
40148
|
+
MEMORY_FILE = join37(STUDIO_DIR, "memory.json");
|
|
40149
|
+
VALIDATE_RECORD = join37(".himi", "validate.json");
|
|
40150
|
+
PUSH_RECORD = join37(".himi", "last-push.json");
|
|
40151
|
+
EDGES_RECORD = join37(".himi", "test-edges.json");
|
|
40152
|
+
RUN_RECORD = join37(".himi", "run.json");
|
|
39754
40153
|
MAX_TIMELINE = 500;
|
|
39755
40154
|
MAX_JOURNAL = 80;
|
|
39756
40155
|
MAX_NAV_EDGES = 40;
|
|
39757
40156
|
readJson2 = (file) => {
|
|
39758
40157
|
try {
|
|
39759
|
-
return JSON.parse(
|
|
40158
|
+
return JSON.parse(readFileSync43(file, "utf8"));
|
|
39760
40159
|
} catch {
|
|
39761
40160
|
return null;
|
|
39762
40161
|
}
|
|
@@ -39766,7 +40165,6 @@ var init_studio = __esm({
|
|
|
39766
40165
|
text = (v) => typeof v === "string" && v ? v : null;
|
|
39767
40166
|
historyUrl = (fileName) => `../history/${fileName}`;
|
|
39768
40167
|
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
40168
|
}
|
|
39771
40169
|
});
|
|
39772
40170
|
|
|
@@ -40245,11 +40643,11 @@ __export(captcha_exports, {
|
|
|
40245
40643
|
captchaContentInput: () => captchaContentInput,
|
|
40246
40644
|
runCaptcha: () => runCaptcha
|
|
40247
40645
|
});
|
|
40248
|
-
import { readFileSync as
|
|
40646
|
+
import { readFileSync as readFileSync44 } from "node:fs";
|
|
40249
40647
|
import { resolve as resolve34 } from "node:path";
|
|
40250
40648
|
function readObject(path2) {
|
|
40251
40649
|
try {
|
|
40252
|
-
return JSON.parse(
|
|
40650
|
+
return JSON.parse(readFileSync44(path2, "utf8"));
|
|
40253
40651
|
} catch {
|
|
40254
40652
|
return {};
|
|
40255
40653
|
}
|
|
@@ -40393,11 +40791,11 @@ var init_push_setup_apple_credentials = __esm({
|
|
|
40393
40791
|
});
|
|
40394
40792
|
|
|
40395
40793
|
// src/push-onboarding.ts
|
|
40396
|
-
import { existsSync as
|
|
40397
|
-
import { basename as basename10, dirname as dirname22, join as
|
|
40794
|
+
import { existsSync as existsSync41, mkdirSync as mkdirSync18, readFileSync as readFileSync45, statSync as statSync9, writeFileSync as writeFileSync14, chmodSync as chmodSync2 } from "node:fs";
|
|
40795
|
+
import { basename as basename10, dirname as dirname22, join as join38, resolve as resolve35 } from "node:path";
|
|
40398
40796
|
function readJson3(path2) {
|
|
40399
40797
|
try {
|
|
40400
|
-
const parsed = JSON.parse(
|
|
40798
|
+
const parsed = JSON.parse(readFileSync45(path2, "utf8"));
|
|
40401
40799
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
40402
40800
|
} catch {
|
|
40403
40801
|
return {};
|
|
@@ -40405,9 +40803,9 @@ function readJson3(path2) {
|
|
|
40405
40803
|
}
|
|
40406
40804
|
function pushInputsFromContent(dir) {
|
|
40407
40805
|
const root = resolve35(dir);
|
|
40408
|
-
if (!
|
|
40409
|
-
const content = readJson3(
|
|
40410
|
-
const provisioning = readJson3(
|
|
40806
|
+
if (!existsSync41(join38(root, "himalaya.content.json"))) return { initialized: false };
|
|
40807
|
+
const content = readJson3(join38(root, "himalaya.content.json"));
|
|
40808
|
+
const provisioning = readJson3(join38(root, "provisioning.json"));
|
|
40411
40809
|
const native = provisioning.native ?? {};
|
|
40412
40810
|
return {
|
|
40413
40811
|
initialized: true,
|
|
@@ -40482,7 +40880,7 @@ function readKeyFile(path2) {
|
|
|
40482
40880
|
}
|
|
40483
40881
|
let body;
|
|
40484
40882
|
try {
|
|
40485
|
-
body =
|
|
40883
|
+
body = readFileSync45(path2, "utf8");
|
|
40486
40884
|
} catch {
|
|
40487
40885
|
return { ok: false, code: "key_file_unreadable", reason: "cannot read the selected key file; check its path and file permissions" };
|
|
40488
40886
|
}
|
|
@@ -40536,13 +40934,13 @@ function buildPushSetupBody(i, keys) {
|
|
|
40536
40934
|
};
|
|
40537
40935
|
}
|
|
40538
40936
|
function readPushOnboarding(dir) {
|
|
40539
|
-
const path2 =
|
|
40540
|
-
if (!
|
|
40937
|
+
const path2 = join38(resolve35(dir), PUSH_ONBOARDING_PATH);
|
|
40938
|
+
if (!existsSync41(path2)) return { version: 1 };
|
|
40541
40939
|
const parsed = readJson3(path2);
|
|
40542
40940
|
return { version: 1, ...parsed };
|
|
40543
40941
|
}
|
|
40544
40942
|
function writeFile(dir, file) {
|
|
40545
|
-
const path2 =
|
|
40943
|
+
const path2 = join38(resolve35(dir), PUSH_ONBOARDING_PATH);
|
|
40546
40944
|
mkdirSync18(dirname22(path2), { recursive: true, mode: 448 });
|
|
40547
40945
|
writeFileSync14(path2, JSON.stringify(file, null, 2) + "\n", { mode: 384 });
|
|
40548
40946
|
try {
|
|
@@ -40571,8 +40969,8 @@ function recordPushDeferral(dir, d) {
|
|
|
40571
40969
|
return push;
|
|
40572
40970
|
}
|
|
40573
40971
|
function clearPushDeferral(dir) {
|
|
40574
|
-
const path2 =
|
|
40575
|
-
if (!
|
|
40972
|
+
const path2 = join38(resolve35(dir), PUSH_ONBOARDING_PATH);
|
|
40973
|
+
if (!existsSync41(path2)) return;
|
|
40576
40974
|
const { push: _dropped, ...rest } = readPushOnboarding(dir);
|
|
40577
40975
|
writeFile(dir, { ...rest, version: 1 });
|
|
40578
40976
|
}
|
|
@@ -41305,8 +41703,8 @@ __export(template_trim_exports, {
|
|
|
41305
41703
|
routeMatcher: () => routeMatcher,
|
|
41306
41704
|
runTemplateTrim: () => runTemplateTrim
|
|
41307
41705
|
});
|
|
41308
|
-
import { cpSync, existsSync as
|
|
41309
|
-
import { dirname as dirname23, join as
|
|
41706
|
+
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";
|
|
41707
|
+
import { dirname as dirname23, join as join39 } from "node:path";
|
|
41310
41708
|
function routeMatcher(pattern) {
|
|
41311
41709
|
const detail = /^\^([A-Za-z0-9_]+)\(\?:\[_\/\]\(\.\+\)\)\?\$$/.exec(pattern);
|
|
41312
41710
|
if (detail) {
|
|
@@ -42000,20 +42398,20 @@ function homeModulesPass(app, kept, edited) {
|
|
|
42000
42398
|
return { text: patched.src, dropped: patched.droppedModules };
|
|
42001
42399
|
}
|
|
42002
42400
|
function listWorkers(dir) {
|
|
42003
|
-
const root =
|
|
42004
|
-
if (!
|
|
42005
|
-
const dirs = readdirSync21(root).filter((n) => statSync10(
|
|
42401
|
+
const root = join39(dir, "tier5-src");
|
|
42402
|
+
if (!existsSync42(root)) return { dirs: [], files: {} };
|
|
42403
|
+
const dirs = readdirSync21(root).filter((n) => statSync10(join39(root, n)).isDirectory()).sort();
|
|
42006
42404
|
const files = {};
|
|
42007
42405
|
const walk2 = (abs, rel) => {
|
|
42008
42406
|
for (const name of readdirSync21(abs)) {
|
|
42009
42407
|
if (name === "node_modules") continue;
|
|
42010
|
-
const p =
|
|
42408
|
+
const p = join39(abs, name);
|
|
42011
42409
|
const r = `${rel}/${name}`;
|
|
42012
42410
|
if (statSync10(p).isDirectory()) walk2(p, r);
|
|
42013
|
-
else if (/\.(?:[cm]?[jt]sx?|json)$/.test(name)) files[r] =
|
|
42411
|
+
else if (/\.(?:[cm]?[jt]sx?|json)$/.test(name)) files[r] = readFileSync46(p, "utf8");
|
|
42014
42412
|
}
|
|
42015
42413
|
};
|
|
42016
|
-
for (const d of dirs) walk2(
|
|
42414
|
+
for (const d of dirs) walk2(join39(root, d), `tier5-src/${d}`);
|
|
42017
42415
|
return { dirs, files };
|
|
42018
42416
|
}
|
|
42019
42417
|
function csv(v) {
|
|
@@ -42036,16 +42434,16 @@ async function runTemplateTrim(req, deps) {
|
|
|
42036
42434
|
links = req.links;
|
|
42037
42435
|
}
|
|
42038
42436
|
const dir = req.dir;
|
|
42039
|
-
const devPath =
|
|
42040
|
-
const configPath =
|
|
42041
|
-
if (!
|
|
42437
|
+
const devPath = join39(dir, "dev/index.ts");
|
|
42438
|
+
const configPath = join39(dir, "config.ts");
|
|
42439
|
+
if (!existsSync42(devPath) || !existsSync42(configPath)) {
|
|
42042
42440
|
return refuse3(new TrimRefusal(`${dir} has no dev/index.ts + config.ts \u2014 point --content at an app scaffolded with \`himi init --template\``));
|
|
42043
42441
|
}
|
|
42044
42442
|
if (isTemplateSourceTree(dir)) {
|
|
42045
42443
|
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
42444
|
}
|
|
42047
|
-
const dev =
|
|
42048
|
-
const config =
|
|
42445
|
+
const dev = readFileSync46(devPath, "utf8");
|
|
42446
|
+
const config = readFileSync46(configPath, "utf8");
|
|
42049
42447
|
const workers = listWorkers(dir);
|
|
42050
42448
|
let plan;
|
|
42051
42449
|
try {
|
|
@@ -42055,22 +42453,22 @@ async function runTemplateTrim(req, deps) {
|
|
|
42055
42453
|
throw e;
|
|
42056
42454
|
}
|
|
42057
42455
|
if (req.dryRun) return { code: 0, result: { ok: true, dryRun: true, ...plan.report, validate: null } };
|
|
42058
|
-
const hadHimi =
|
|
42059
|
-
const backupRel =
|
|
42060
|
-
const backup =
|
|
42456
|
+
const hadHimi = existsSync42(join39(dir, ".himi"));
|
|
42457
|
+
const backupRel = join39(".himi", "trim-backup", (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-"));
|
|
42458
|
+
const backup = join39(dir, backupRel);
|
|
42061
42459
|
const originals = [[devPath, "dev/index.ts"], [configPath, "config.ts"]];
|
|
42062
42460
|
const moved = [];
|
|
42063
42461
|
const restore = () => {
|
|
42064
42462
|
for (const [path2, rel] of originals) {
|
|
42065
|
-
const original =
|
|
42066
|
-
if (!
|
|
42463
|
+
const original = readFileSync46(join39(backup, rel));
|
|
42464
|
+
if (!existsSync42(path2) || !readFileSync46(path2).equals(original)) writeFileSync15(path2, original);
|
|
42067
42465
|
}
|
|
42068
|
-
for (const name of [...moved].reverse()) renameSync4(
|
|
42466
|
+
for (const name of [...moved].reverse()) renameSync4(join39(backup, "tier5-src", name), join39(dir, "tier5-src", name));
|
|
42069
42467
|
};
|
|
42070
42468
|
const dropBackup = () => {
|
|
42071
42469
|
rmSync8(backup, { recursive: true, force: true });
|
|
42072
|
-
for (const d of [dirname23(backup),
|
|
42073
|
-
if (d ===
|
|
42470
|
+
for (const d of [dirname23(backup), join39(dir, ".himi")]) {
|
|
42471
|
+
if (d === join39(dir, ".himi") && hadHimi) break;
|
|
42074
42472
|
try {
|
|
42075
42473
|
if (!readdirSync21(d).length) rmSync8(d, { recursive: true });
|
|
42076
42474
|
} catch {
|
|
@@ -42096,9 +42494,9 @@ async function runTemplateTrim(req, deps) {
|
|
|
42096
42494
|
return { code: 1, result: { ok: false, error: `${error} (${message}); every file was restored`, rolledBack: true, ...base(validate4) } };
|
|
42097
42495
|
};
|
|
42098
42496
|
try {
|
|
42099
|
-
mkdirSync19(
|
|
42100
|
-
for (const [path2, rel] of originals) cpSync(path2,
|
|
42101
|
-
if (plan.removedWorkers.length) mkdirSync19(
|
|
42497
|
+
mkdirSync19(join39(backup, "dev"), { recursive: true });
|
|
42498
|
+
for (const [path2, rel] of originals) cpSync(path2, join39(backup, rel));
|
|
42499
|
+
if (plan.removedWorkers.length) mkdirSync19(join39(backup, "tier5-src"), { recursive: true });
|
|
42102
42500
|
} catch (e) {
|
|
42103
42501
|
dropBackup();
|
|
42104
42502
|
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 +42504,7 @@ async function runTemplateTrim(req, deps) {
|
|
|
42106
42504
|
try {
|
|
42107
42505
|
const moveDir = deps.moveDir ?? renameSync4;
|
|
42108
42506
|
for (const name of plan.removedWorkers) {
|
|
42109
|
-
moveDir(
|
|
42507
|
+
moveDir(join39(dir, "tier5-src", name), join39(backup, "tier5-src", name));
|
|
42110
42508
|
moved.push(name);
|
|
42111
42509
|
}
|
|
42112
42510
|
if (plan.dev !== dev) writeFileSync15(devPath, plan.dev);
|
|
@@ -42117,7 +42515,7 @@ async function runTemplateTrim(req, deps) {
|
|
|
42117
42515
|
let failure;
|
|
42118
42516
|
let validate3;
|
|
42119
42517
|
try {
|
|
42120
|
-
const written = parseApp(
|
|
42518
|
+
const written = parseApp(readFileSync46(devPath, "utf8"), readFileSync46(configPath, "utf8"));
|
|
42121
42519
|
const leftovers = leftoverNavRefs(written.nav.value, plan.removedIds);
|
|
42122
42520
|
if (leftovers.length) failure = { error: "navigation still names screens this trim removed", leftovers };
|
|
42123
42521
|
else {
|
|
@@ -42811,8 +43209,8 @@ __export(pack_exports, {
|
|
|
42811
43209
|
});
|
|
42812
43210
|
import { createHash as createHash21 } from "node:crypto";
|
|
42813
43211
|
import { deflateRawSync, inflateRawSync } from "node:zlib";
|
|
42814
|
-
import { existsSync as
|
|
42815
|
-
import { dirname as dirname24, join as
|
|
43212
|
+
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";
|
|
43213
|
+
import { dirname as dirname24, join as join40, resolve as resolve37 } from "node:path";
|
|
42816
43214
|
function writeZip(entries) {
|
|
42817
43215
|
const sorted2 = entries.slice().sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
42818
43216
|
const total = sorted2.reduce((n, e) => n + e.bytes.length, 0);
|
|
@@ -42906,13 +43304,13 @@ function inflateEntry(buf, entry) {
|
|
|
42906
43304
|
return bytes2;
|
|
42907
43305
|
}
|
|
42908
43306
|
function readIf(path2) {
|
|
42909
|
-
return
|
|
43307
|
+
return existsSync43(path2) && statSync11(path2).isFile() ? readFileSync47(path2) : null;
|
|
42910
43308
|
}
|
|
42911
43309
|
function listDir(dir) {
|
|
42912
|
-
return
|
|
43310
|
+
return existsSync43(dir) ? readdirSync22(dir).filter((f) => statSync11(join40(dir, f)).isFile()) : [];
|
|
42913
43311
|
}
|
|
42914
43312
|
function gatherReleaseEntries(appDir2) {
|
|
42915
|
-
const manifestPath =
|
|
43313
|
+
const manifestPath = join40(appDir2, HIMI_PACKAGE_MANIFEST_PATH);
|
|
42916
43314
|
const manifestBytes = readIf(manifestPath);
|
|
42917
43315
|
if (!manifestBytes) throw new Error(`no ${HIMI_PACKAGE_MANIFEST_PATH} in ${appDir2} \u2014 build a release there first`);
|
|
42918
43316
|
const manifest = JSON.parse(manifestBytes.toString("utf8"));
|
|
@@ -42936,7 +43334,7 @@ function gatherReleaseEntries(appDir2) {
|
|
|
42936
43334
|
}
|
|
42937
43335
|
const missing = [];
|
|
42938
43336
|
for (const rel of wanted) {
|
|
42939
|
-
const bytes2 = readIf(
|
|
43337
|
+
const bytes2 = readIf(join40(appDir2, rel));
|
|
42940
43338
|
if (bytes2) entries.push({ path: rel, bytes: bytes2 });
|
|
42941
43339
|
else missing.push(rel);
|
|
42942
43340
|
}
|
|
@@ -42947,12 +43345,12 @@ function gatherReleaseEntries(appDir2) {
|
|
|
42947
43345
|
);
|
|
42948
43346
|
}
|
|
42949
43347
|
for (const name of SINGLETONS) {
|
|
42950
|
-
const bytes2 = readIf(
|
|
43348
|
+
const bytes2 = readIf(join40(appDir2, name));
|
|
42951
43349
|
if (bytes2) entries.push({ path: name, bytes: bytes2 });
|
|
42952
43350
|
}
|
|
42953
43351
|
const skipped = [];
|
|
42954
43352
|
for (const sub of ["screens", "bundles", "assets", "widgets"]) {
|
|
42955
|
-
for (const f of listDir(
|
|
43353
|
+
for (const f of listDir(join40(appDir2, sub))) {
|
|
42956
43354
|
if (!wanted.has(`${sub}/${f}`)) skipped.push(`${sub}/${f}`);
|
|
42957
43355
|
}
|
|
42958
43356
|
}
|
|
@@ -42985,18 +43383,18 @@ function buildEntries(appDir2, app, opts) {
|
|
|
42985
43383
|
return { all, header, manifest, skipped };
|
|
42986
43384
|
}
|
|
42987
43385
|
function packRelease(releaseRoot, app, out, opts = {}) {
|
|
42988
|
-
const appDir2 =
|
|
43386
|
+
const appDir2 = join40(resolve37(releaseRoot), app);
|
|
42989
43387
|
const { all, header, skipped } = buildEntries(appDir2, app, opts);
|
|
42990
43388
|
const buf = writeZip(all);
|
|
42991
|
-
const isDir2 =
|
|
42992
|
-
const outFile = isDir2 ?
|
|
43389
|
+
const isDir2 = existsSync43(out) && statSync11(out).isDirectory();
|
|
43390
|
+
const outFile = isDir2 ? join40(resolve37(out), packageFileName(app, header.releaseId)) : resolve37(out);
|
|
42993
43391
|
mkdirSync20(dirname24(outFile), { recursive: true });
|
|
42994
43392
|
writeFileSync16(outFile, buf);
|
|
42995
43393
|
return { app, releaseId: header.releaseId, header, out: outFile, bytes: buf.length, entryCount: all.length, skipped };
|
|
42996
43394
|
}
|
|
42997
43395
|
function resolvePackageDirDest(outDir, app, releaseId) {
|
|
42998
43396
|
const packagedApp = (dir) => {
|
|
42999
|
-
const bytes2 = readIf(
|
|
43397
|
+
const bytes2 = readIf(join40(dir, HIMI_PACKAGE_HEADER_PATH));
|
|
43000
43398
|
if (!bytes2) return void 0;
|
|
43001
43399
|
try {
|
|
43002
43400
|
return JSON.parse(bytes2.toString("utf8")).app;
|
|
@@ -43005,15 +43403,15 @@ function resolvePackageDirDest(outDir, app, releaseId) {
|
|
|
43005
43403
|
}
|
|
43006
43404
|
};
|
|
43007
43405
|
const replaceable = (dir) => {
|
|
43008
|
-
if (!
|
|
43406
|
+
if (!existsSync43(dir)) return true;
|
|
43009
43407
|
if (!statSync11(dir).isDirectory()) return false;
|
|
43010
43408
|
return readdirSync22(dir).length === 0 || packagedApp(dir) === app;
|
|
43011
43409
|
};
|
|
43012
|
-
if (
|
|
43410
|
+
if (existsSync43(outDir) && !statSync11(outDir).isDirectory()) {
|
|
43013
43411
|
throw new Error(`refusing to write a package tree over ${outDir} \u2014 it is a file, not a directory`);
|
|
43014
43412
|
}
|
|
43015
43413
|
if (replaceable(outDir)) return outDir;
|
|
43016
|
-
const child =
|
|
43414
|
+
const child = join40(outDir, packageDirName(app, releaseId));
|
|
43017
43415
|
if (!replaceable(child)) {
|
|
43018
43416
|
throw new Error(
|
|
43019
43417
|
`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 +43425,13 @@ function packReleaseToDir(releaseRoot, app, outDir, opts = {}) {
|
|
|
43027
43425
|
"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
43426
|
);
|
|
43029
43427
|
}
|
|
43030
|
-
const appDir2 =
|
|
43428
|
+
const appDir2 = join40(resolve37(releaseRoot), app);
|
|
43031
43429
|
const { all, header, skipped } = buildEntries(appDir2, app, opts);
|
|
43032
43430
|
const dest = resolvePackageDirDest(resolve37(outDir), app, header.releaseId);
|
|
43033
43431
|
rmSync9(dest, { recursive: true, force: true });
|
|
43034
43432
|
let bytes2 = 0;
|
|
43035
43433
|
for (const entry of all) {
|
|
43036
|
-
const target =
|
|
43434
|
+
const target = join40(dest, entry.path);
|
|
43037
43435
|
mkdirSync20(dirname24(target), { recursive: true });
|
|
43038
43436
|
writeFileSync16(target, entry.bytes);
|
|
43039
43437
|
bytes2 += entry.bytes.length;
|
|
@@ -43056,21 +43454,21 @@ function openPackageBuffer(buf) {
|
|
|
43056
43454
|
return openFromEntries(readZip(buf), { requireHeader: true });
|
|
43057
43455
|
}
|
|
43058
43456
|
function openPackageFile(file) {
|
|
43059
|
-
return openPackageBuffer(
|
|
43457
|
+
return openPackageBuffer(readFileSync47(file));
|
|
43060
43458
|
}
|
|
43061
43459
|
function openPackageDir(dir) {
|
|
43062
43460
|
const root = resolve37(dir);
|
|
43063
43461
|
const entries = /* @__PURE__ */ new Map();
|
|
43064
43462
|
const walk2 = (rel) => {
|
|
43065
|
-
const abs = rel ?
|
|
43463
|
+
const abs = rel ? join40(root, rel) : root;
|
|
43066
43464
|
for (const name of readdirSync22(abs)) {
|
|
43067
43465
|
const childRel = rel ? `${rel}/${name}` : name;
|
|
43068
|
-
const childAbs =
|
|
43466
|
+
const childAbs = join40(abs, name);
|
|
43069
43467
|
if (statSync11(childAbs).isDirectory()) walk2(childRel);
|
|
43070
|
-
else if (isSafeEntryName(childRel)) entries.set(childRel,
|
|
43468
|
+
else if (isSafeEntryName(childRel)) entries.set(childRel, readFileSync47(childAbs));
|
|
43071
43469
|
}
|
|
43072
43470
|
};
|
|
43073
|
-
if (!
|
|
43471
|
+
if (!existsSync43(root)) throw new Error(`no such package directory: ${root}`);
|
|
43074
43472
|
walk2("");
|
|
43075
43473
|
const manifestBytes = entries.get(HIMI_PACKAGE_MANIFEST_PATH);
|
|
43076
43474
|
if (manifestBytes) {
|
|
@@ -43112,10 +43510,10 @@ function unpackTo(buf, dest, appFallback) {
|
|
|
43112
43510
|
if (!app) throw new Error("package declares no app id (no himi-package.json and no manifest.app)");
|
|
43113
43511
|
if (!isSafeAppId(app)) throw new Error(`package declares an unsafe app id ${JSON.stringify(app)} \u2014 refusing to unpack it`);
|
|
43114
43512
|
const root = resolve37(dest);
|
|
43115
|
-
const appDir2 =
|
|
43513
|
+
const appDir2 = join40(root, app);
|
|
43116
43514
|
rmSync9(appDir2, { recursive: true, force: true });
|
|
43117
43515
|
for (const [rel, bytes2] of entries) {
|
|
43118
|
-
const target =
|
|
43516
|
+
const target = join40(appDir2, rel);
|
|
43119
43517
|
mkdirSync20(dirname24(target), { recursive: true });
|
|
43120
43518
|
writeFileSync16(target, bytes2);
|
|
43121
43519
|
}
|
|
@@ -43151,20 +43549,20 @@ __export(app_source_exports, {
|
|
|
43151
43549
|
writeConflicts: () => writeConflicts,
|
|
43152
43550
|
zipAppSource: () => zipAppSource
|
|
43153
43551
|
});
|
|
43154
|
-
import { readdirSync as readdirSync23, lstatSync as lstatSync6, readFileSync as
|
|
43155
|
-
import { join as
|
|
43552
|
+
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";
|
|
43553
|
+
import { join as join41, resolve as resolve38, sep as sep10 } from "node:path";
|
|
43156
43554
|
import { deflateRawSync as deflateRawSync2 } from "node:zlib";
|
|
43157
43555
|
function walkSourceTree(dir, file, skip) {
|
|
43158
43556
|
const walk2 = (relDir) => {
|
|
43159
|
-
for (const name of readdirSync23(
|
|
43160
|
-
const rel = relDir ?
|
|
43161
|
-
const st = lstatSync6(
|
|
43557
|
+
for (const name of readdirSync23(join41(dir, relDir))) {
|
|
43558
|
+
const rel = relDir ? join41(relDir, name) : name;
|
|
43559
|
+
const st = lstatSync6(join41(dir, rel));
|
|
43162
43560
|
if (st.isSymbolicLink()) {
|
|
43163
43561
|
skip(rel);
|
|
43164
43562
|
continue;
|
|
43165
43563
|
}
|
|
43166
43564
|
if (st.isDirectory()) {
|
|
43167
|
-
if (isDeniedSourceDir(name, relDir) ||
|
|
43565
|
+
if (isDeniedSourceDir(name, relDir) || existsSync44(join41(dir, rel, PACKAGE_DIR_MARKER))) skip(rel);
|
|
43168
43566
|
else walk2(rel);
|
|
43169
43567
|
continue;
|
|
43170
43568
|
}
|
|
@@ -43182,7 +43580,7 @@ function collectAppSource(dir) {
|
|
|
43182
43580
|
const skipped = [];
|
|
43183
43581
|
walkSourceTree(
|
|
43184
43582
|
dir,
|
|
43185
|
-
(archivePath, hostRel) => entries.push({ path: archivePath, bytes:
|
|
43583
|
+
(archivePath, hostRel) => entries.push({ path: archivePath, bytes: readFileSync48(join41(dir, hostRel)) }),
|
|
43186
43584
|
(hostRel) => skipped.push(hostRel)
|
|
43187
43585
|
);
|
|
43188
43586
|
entries.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
@@ -43236,13 +43634,13 @@ function writeAppSource(entries, destDir) {
|
|
|
43236
43634
|
const segments = entry.path.split("/");
|
|
43237
43635
|
let dir = root;
|
|
43238
43636
|
for (const segment of segments.slice(0, -1)) {
|
|
43239
|
-
dir =
|
|
43637
|
+
dir = join41(dir, segment);
|
|
43240
43638
|
const kind = pathKind(dir);
|
|
43241
43639
|
if (kind?.isSymbolicLink()) unlinkSync3(dir);
|
|
43242
43640
|
else if (kind) continue;
|
|
43243
43641
|
mkdirSync21(dir);
|
|
43244
43642
|
}
|
|
43245
|
-
const target =
|
|
43643
|
+
const target = join41(root, ...segments);
|
|
43246
43644
|
if (pathKind(target)?.isSymbolicLink()) unlinkSync3(target);
|
|
43247
43645
|
writeFileSync17(target, entry.bytes);
|
|
43248
43646
|
written.push(entry.path);
|
|
@@ -43250,7 +43648,7 @@ function writeAppSource(entries, destDir) {
|
|
|
43250
43648
|
return written;
|
|
43251
43649
|
}
|
|
43252
43650
|
function staleSourcePaths(entries, destDir) {
|
|
43253
|
-
if (!
|
|
43651
|
+
if (!existsSync44(destDir)) return [];
|
|
43254
43652
|
const archived = new Set(entries.map((e) => e.path));
|
|
43255
43653
|
const stale = [];
|
|
43256
43654
|
walkSourceTree(destDir, (archivePath) => {
|
|
@@ -43277,7 +43675,7 @@ function writeConflicts(entries, destDir) {
|
|
|
43277
43675
|
let dir = root;
|
|
43278
43676
|
let stop = false;
|
|
43279
43677
|
for (const [i, segment] of segments.slice(0, -1).entries()) {
|
|
43280
|
-
dir =
|
|
43678
|
+
dir = join41(dir, segment);
|
|
43281
43679
|
const kind2 = pathKind(dir);
|
|
43282
43680
|
if (!kind2 || kind2.isSymbolicLink()) {
|
|
43283
43681
|
stop = true;
|
|
@@ -43289,7 +43687,7 @@ function writeConflicts(entries, destDir) {
|
|
|
43289
43687
|
break;
|
|
43290
43688
|
}
|
|
43291
43689
|
if (stop) continue;
|
|
43292
|
-
const kind = pathKind(
|
|
43690
|
+
const kind = pathKind(join41(root, ...segments));
|
|
43293
43691
|
if (kind && !kind.isSymbolicLink() && kind.isDirectory()) {
|
|
43294
43692
|
say(entry.path, "is a directory here, but the release has a file at that path");
|
|
43295
43693
|
}
|
|
@@ -43299,22 +43697,22 @@ function writeConflicts(entries, destDir) {
|
|
|
43299
43697
|
function removeStaleSource(entries, destDir) {
|
|
43300
43698
|
const root = resolve38(destDir);
|
|
43301
43699
|
const removed = staleSourcePaths(entries, root);
|
|
43302
|
-
for (const rel of removed) rmSync10(
|
|
43700
|
+
for (const rel of removed) rmSync10(join41(root, ...rel.split("/")), { force: true });
|
|
43303
43701
|
const needed = /* @__PURE__ */ new Set();
|
|
43304
43702
|
for (const entry of entries) {
|
|
43305
43703
|
if (isDeniedSourcePath(entry.path)) continue;
|
|
43306
43704
|
const segments = entry.path.split("/");
|
|
43307
43705
|
for (let i = 1; i < segments.length; i++) needed.add(segments.slice(0, i).join("/"));
|
|
43308
43706
|
}
|
|
43309
|
-
if (
|
|
43707
|
+
if (existsSync44(root)) pruneEmptyDirs(root, "", needed, removed);
|
|
43310
43708
|
return removed.sort();
|
|
43311
43709
|
}
|
|
43312
43710
|
function pruneEmptyDirs(root, rel, needed, removed) {
|
|
43313
43711
|
let empty = true;
|
|
43314
|
-
for (const name of readdirSync23(rel ?
|
|
43315
|
-
const childRel = rel ?
|
|
43712
|
+
for (const name of readdirSync23(rel ? join41(root, rel) : root)) {
|
|
43713
|
+
const childRel = rel ? join41(rel, name) : name;
|
|
43316
43714
|
const posix3 = childRel.split(sep10).join("/");
|
|
43317
|
-
const kind = lstatSync6(
|
|
43715
|
+
const kind = lstatSync6(join41(root, childRel));
|
|
43318
43716
|
if (kind.isSymbolicLink() || !kind.isDirectory() || isDeniedSourceDir(name, rel)) {
|
|
43319
43717
|
empty = false;
|
|
43320
43718
|
continue;
|
|
@@ -43324,7 +43722,7 @@ function pruneEmptyDirs(root, rel, needed, removed) {
|
|
|
43324
43722
|
empty = false;
|
|
43325
43723
|
continue;
|
|
43326
43724
|
}
|
|
43327
|
-
rmdirSync(
|
|
43725
|
+
rmdirSync(join41(root, childRel));
|
|
43328
43726
|
removed.push(`${posix3}/`);
|
|
43329
43727
|
}
|
|
43330
43728
|
return empty;
|
|
@@ -43379,13 +43777,13 @@ __export(eject_exports, {
|
|
|
43379
43777
|
EJECTABLE: () => EJECTABLE,
|
|
43380
43778
|
ejectModule: () => ejectModule
|
|
43381
43779
|
});
|
|
43382
|
-
import { existsSync as
|
|
43383
|
-
import { dirname as dirname25, join as
|
|
43780
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync22, readFileSync as readFileSync49, writeFileSync as writeFileSync18 } from "node:fs";
|
|
43781
|
+
import { dirname as dirname25, join as join42, relative as relative7, resolve as resolve39, sep as sep11 } from "node:path";
|
|
43384
43782
|
function locate(repoRootOrCwd, mod) {
|
|
43385
43783
|
const inRepo = resolve39(repoRootOrCwd, `stdlib/flows/${mod}/src/index.ts`);
|
|
43386
|
-
if (
|
|
43784
|
+
if (existsSync45(inRepo)) return { path: inRepo, form: "source" };
|
|
43387
43785
|
const dist = resolve39(repoRootOrCwd, `node_modules/@wix/himalaya/dist/${mod}.mjs`);
|
|
43388
|
-
if (
|
|
43786
|
+
if (existsSync45(dist)) return { path: dist, form: "bundle" };
|
|
43389
43787
|
return null;
|
|
43390
43788
|
}
|
|
43391
43789
|
function specifiersFor(mod) {
|
|
@@ -43409,7 +43807,7 @@ function ejectModule(opts) {
|
|
|
43409
43807
|
};
|
|
43410
43808
|
}
|
|
43411
43809
|
const ext = found.form === "source" ? "ts" : "mjs";
|
|
43412
|
-
const target =
|
|
43810
|
+
const target = join42(contentDir2, "tier5-src", "_ejected", `${mod}.${ext}`);
|
|
43413
43811
|
mkdirSync22(dirname25(target), { recursive: true });
|
|
43414
43812
|
const banner = `// EJECTED from @wix/himalaya/${mod}. This app owns this file now.
|
|
43415
43813
|
//
|
|
@@ -43423,15 +43821,15 @@ function ejectModule(opts) {
|
|
|
43423
43821
|
// gate still applies. Ejecting buys layout and flow, never the floor.
|
|
43424
43822
|
|
|
43425
43823
|
`;
|
|
43426
|
-
const normalized =
|
|
43824
|
+
const normalized = readFileSync49(found.path, "utf8").replace(
|
|
43427
43825
|
/(["'])@himalaya\/([a-z0-9-]+(?:\/[a-z0-9-]+)?)\1/g,
|
|
43428
43826
|
(_m, q, sub) => `${q}@wix/himalaya/${sub}${q}`
|
|
43429
43827
|
);
|
|
43430
43828
|
writeFileSync18(target, banner + normalized);
|
|
43431
43829
|
const rewired = [];
|
|
43432
43830
|
for (const f of files) {
|
|
43433
|
-
if (!
|
|
43434
|
-
const before =
|
|
43831
|
+
if (!existsSync45(f)) continue;
|
|
43832
|
+
const before = readFileSync49(f, "utf8");
|
|
43435
43833
|
let after = before;
|
|
43436
43834
|
let rel = relative7(dirname25(f), target).split(sep11).join("/").replace(/\.tsx?$/, ".js");
|
|
43437
43835
|
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
@@ -43479,14 +43877,14 @@ __export(test_exports, {
|
|
|
43479
43877
|
scopeDescriptors: () => scopeDescriptors,
|
|
43480
43878
|
writeRecordedMocks: () => writeRecordedMocks
|
|
43481
43879
|
});
|
|
43482
|
-
import { existsSync as
|
|
43483
|
-
import { join as
|
|
43880
|
+
import { existsSync as existsSync46, mkdirSync as mkdirSync23, readFileSync as readFileSync50, writeFileSync as writeFileSync19 } from "node:fs";
|
|
43881
|
+
import { join as join43, resolve as resolve40 } from "node:path";
|
|
43484
43882
|
function readTestConfig(dir) {
|
|
43485
43883
|
const p = resolve40(dir, TEST_CONFIG_FILE);
|
|
43486
|
-
if (!
|
|
43884
|
+
if (!existsSync46(p)) return {};
|
|
43487
43885
|
let parsed;
|
|
43488
43886
|
try {
|
|
43489
|
-
parsed = JSON.parse(
|
|
43887
|
+
parsed = JSON.parse(readFileSync50(p, "utf8"));
|
|
43490
43888
|
} catch (e) {
|
|
43491
43889
|
throw new Error(`${TEST_CONFIG_FILE} is not valid JSON \u2014 ${e.message}`);
|
|
43492
43890
|
}
|
|
@@ -43529,7 +43927,7 @@ function readTestConfig(dir) {
|
|
|
43529
43927
|
function readNetRules(path2) {
|
|
43530
43928
|
let parsed;
|
|
43531
43929
|
try {
|
|
43532
|
-
parsed = JSON.parse(
|
|
43930
|
+
parsed = JSON.parse(readFileSync50(path2, "utf8"));
|
|
43533
43931
|
} catch (e) {
|
|
43534
43932
|
throw new Error(`--net ${path2} could not be read as JSON \u2014 ${e.message}`);
|
|
43535
43933
|
}
|
|
@@ -43550,7 +43948,7 @@ function readNetRules(path2) {
|
|
|
43550
43948
|
function defaultNetRules(dir) {
|
|
43551
43949
|
for (const rel of ["dev/net-mocks.json", "tests/net-mocks.json"]) {
|
|
43552
43950
|
const p = resolve40(dir, rel);
|
|
43553
|
-
if (
|
|
43951
|
+
if (existsSync46(p)) {
|
|
43554
43952
|
const rules = readNetRules(p);
|
|
43555
43953
|
if (rules.length) return { rules, from: rel };
|
|
43556
43954
|
}
|
|
@@ -43566,7 +43964,7 @@ function readCannedResponses() {
|
|
|
43566
43964
|
];
|
|
43567
43965
|
for (const url of candidates) {
|
|
43568
43966
|
try {
|
|
43569
|
-
const parsed = JSON.parse(
|
|
43967
|
+
const parsed = JSON.parse(readFileSync50(url, "utf8"));
|
|
43570
43968
|
const byKey = {};
|
|
43571
43969
|
for (const [k, v] of Object.entries(parsed)) {
|
|
43572
43970
|
if (!k.startsWith("//")) byKey[k] = v;
|
|
@@ -43658,8 +44056,8 @@ function writeRecordedMocks(opts) {
|
|
|
43658
44056
|
mkdir: (p) => mkdirSync23(p, { recursive: true }),
|
|
43659
44057
|
write: (p, s) => writeFileSync19(p, s)
|
|
43660
44058
|
};
|
|
43661
|
-
fs.mkdir(
|
|
43662
|
-
fs.write(
|
|
44059
|
+
fs.mkdir(join43(opts.dir, "dev"));
|
|
44060
|
+
fs.write(join43(opts.dir, "dev", "net-mocks.json"), JSON.stringify(opts.mocks, null, 2) + "\n");
|
|
43663
44061
|
return { ok: true, rules, to: "dev/net-mocks.json" };
|
|
43664
44062
|
}
|
|
43665
44063
|
function scopeDescriptors(descriptors, requestedIds, invalidScreens) {
|
|
@@ -43973,12 +44371,12 @@ async function runCrawl(opts) {
|
|
|
43973
44371
|
};
|
|
43974
44372
|
}
|
|
43975
44373
|
function describeTransport(net, opts, ran) {
|
|
43976
|
-
const
|
|
43977
|
-
if (net)
|
|
44374
|
+
const layers2 = [];
|
|
44375
|
+
if (net) layers2.push(`mocked (${net.from})`);
|
|
43978
44376
|
const cmsCount = Object.keys(opts.cmsSeed ?? {}).length;
|
|
43979
|
-
if (cmsCount)
|
|
43980
|
-
if (opts.canned?.count)
|
|
43981
|
-
const base =
|
|
44377
|
+
if (cmsCount) layers2.push(`cms (${cmsCount} seeded collection${cmsCount === 1 ? "" : "s"})`);
|
|
44378
|
+
if (opts.canned?.count) layers2.push(`canned (${opts.canned.count} frozen endpoints, ${opts.canned.from} \u2014 exercises code paths, not API-contract truth)`);
|
|
44379
|
+
const base = layers2.length ? layers2.join(" + ") : "offline (no net fixture \u2014 screens are crawled against a rejecting transport, which exercises their failure UI)";
|
|
43982
44380
|
const hostile = ran.hostile ? " + hostile boot passes (empty-lists, all-500)" : "";
|
|
43983
44381
|
const relations = ran.relations ? " + relations" : "";
|
|
43984
44382
|
const deep = ran.deep ? ` + deep chains (depth ${opts.deep})` : "";
|
|
@@ -44116,14 +44514,14 @@ var mobile_ux_lint_exports = {};
|
|
|
44116
44514
|
__export(mobile_ux_lint_exports, {
|
|
44117
44515
|
mobileUxIssues: () => mobileUxIssues
|
|
44118
44516
|
});
|
|
44119
|
-
import { existsSync as
|
|
44120
|
-
import { join as
|
|
44517
|
+
import { existsSync as existsSync47, readFileSync as readFileSync51 } from "node:fs";
|
|
44518
|
+
import { join as join44 } from "node:path";
|
|
44121
44519
|
function mobileUxIssues(dir, strict) {
|
|
44122
|
-
const file =
|
|
44123
|
-
if (!
|
|
44520
|
+
const file = join44(dir, "MOBILE-UX.md");
|
|
44521
|
+
if (!existsSync47(file)) return [];
|
|
44124
44522
|
let text5;
|
|
44125
44523
|
try {
|
|
44126
|
-
text5 =
|
|
44524
|
+
text5 = readFileSync51(file, "utf8");
|
|
44127
44525
|
} catch {
|
|
44128
44526
|
return [];
|
|
44129
44527
|
}
|
|
@@ -45798,8 +46196,8 @@ __export(functions_exports, {
|
|
|
45798
46196
|
resolveFunctionsTarget: () => resolveFunctionsTarget,
|
|
45799
46197
|
runRemoteFunctionOperation: () => runRemoteFunctionOperation
|
|
45800
46198
|
});
|
|
45801
|
-
import { readFileSync as
|
|
45802
|
-
import { join as
|
|
46199
|
+
import { readFileSync as readFileSync52, existsSync as existsSync48 } from "node:fs";
|
|
46200
|
+
import { join as join45, resolve as resolve41 } from "node:path";
|
|
45803
46201
|
function resolveFunctionsTarget(input) {
|
|
45804
46202
|
const explicitUrl = input.functionsUrl?.trim();
|
|
45805
46203
|
if (explicitUrl) return { mode: "remote", baseUrl: explicitUrl };
|
|
@@ -45818,9 +46216,9 @@ async function loadFunctionsApp(dir) {
|
|
|
45818
46216
|
}
|
|
45819
46217
|
const sources = {};
|
|
45820
46218
|
for (const definition of config.functions.functions) {
|
|
45821
|
-
const source = [".ts", ".js", ".mts", ".mjs"].map((extension) =>
|
|
46219
|
+
const source = [".ts", ".js", ".mts", ".mjs"].map((extension) => join45(loaded.dir, "functions", `${definition.name}${extension}`)).find(existsSync48);
|
|
45822
46220
|
if (!source) throw new Error(`missing source for function ${definition.name}; expected functions/${definition.name}.ts`);
|
|
45823
|
-
sources[definition.name] =
|
|
46221
|
+
sources[definition.name] = readFileSync52(source, "utf8");
|
|
45824
46222
|
}
|
|
45825
46223
|
const data = config.cms || config.data ? mergeDataResources(config) : void 0;
|
|
45826
46224
|
const dataErrors = validateDataResources(data, loaded.name).filter((issue2) => issue2.severity === "error");
|
|
@@ -45972,14 +46370,14 @@ __export(studio_reel_exports, {
|
|
|
45972
46370
|
utcDay: () => utcDay
|
|
45973
46371
|
});
|
|
45974
46372
|
import { createHash as createHash24 } from "node:crypto";
|
|
45975
|
-
import { lstatSync as lstatSync7, readFileSync as
|
|
45976
|
-
import { basename as basename11, join as
|
|
46373
|
+
import { lstatSync as lstatSync7, readFileSync as readFileSync53 } from "node:fs";
|
|
46374
|
+
import { basename as basename11, join as join46 } from "node:path";
|
|
45977
46375
|
function loadMemory2(dir) {
|
|
45978
|
-
const m = readJson4(
|
|
45979
|
-
if (!
|
|
46376
|
+
const m = readJson4(join46(dir, ".himi", "studio", "memory.json"));
|
|
46377
|
+
if (!isObj2(m) || m.version !== 1 || !isObj2(m.shots) || !Array.isArray(m.timeline)) return null;
|
|
45980
46378
|
const shots = [];
|
|
45981
46379
|
for (const [id, s] of Object.entries(m.shots)) {
|
|
45982
|
-
if (!
|
|
46380
|
+
if (!isObj2(s)) continue;
|
|
45983
46381
|
const file = historyName(s.sha, s.ext);
|
|
45984
46382
|
const firstSeen = str(s.firstSeen);
|
|
45985
46383
|
if (!file || !firstSeen) continue;
|
|
@@ -45988,7 +46386,7 @@ function loadMemory2(dir) {
|
|
|
45988
46386
|
}
|
|
45989
46387
|
const timeline = [];
|
|
45990
46388
|
for (const t of m.timeline) {
|
|
45991
|
-
if (!
|
|
46389
|
+
if (!isObj2(t)) continue;
|
|
45992
46390
|
const file = historyName(t.sha, t.ext);
|
|
45993
46391
|
const ts2 = str(t.ts);
|
|
45994
46392
|
const id = str(t.id);
|
|
@@ -46012,8 +46410,8 @@ function planReel(dir) {
|
|
|
46012
46410
|
const memory = loadMemory2(dir);
|
|
46013
46411
|
const { entries } = readProgress(dir);
|
|
46014
46412
|
const summary = summarizeProgress(entries);
|
|
46015
|
-
const manifest = readJson4(
|
|
46016
|
-
const tokens = readJson4(
|
|
46413
|
+
const manifest = readJson4(join46(dir, "himalaya.content.json"));
|
|
46414
|
+
const tokens = readJson4(join46(dir, "tokens.json"));
|
|
46017
46415
|
const accentToken = tokens?.colors?.accentPrimary;
|
|
46018
46416
|
const accentRaw = typeof accentToken === "string" ? accentToken : accentToken?.light;
|
|
46019
46417
|
const accent = typeof accentRaw === "string" && ACCENT.test(accentRaw) ? accentRaw : DEFAULT_ACCENT;
|
|
@@ -46028,7 +46426,7 @@ function planReel(dir) {
|
|
|
46028
46426
|
ts: e.ts,
|
|
46029
46427
|
message: e.message,
|
|
46030
46428
|
step: str(e.step),
|
|
46031
|
-
files: (Array.isArray(e.images) ? e.images : []).map((i) =>
|
|
46429
|
+
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
46430
|
}));
|
|
46033
46431
|
const times = [summary.startedAt, ...timeline.map((t) => t.ts), memory?.createdAt].filter((x) => !!x).sort();
|
|
46034
46432
|
const startedAt = times[0] ?? null;
|
|
@@ -46055,10 +46453,10 @@ function inlineImages(dir, plan, budget = REEL_BUDGET_BYTES) {
|
|
|
46055
46453
|
const verified = (f) => {
|
|
46056
46454
|
if (!HISTORY_NAME.test(f)) return null;
|
|
46057
46455
|
try {
|
|
46058
|
-
const path2 =
|
|
46456
|
+
const path2 = join46(dir, HISTORY_DIR, f);
|
|
46059
46457
|
const st = lstatSync7(path2);
|
|
46060
46458
|
if (!st.isFile() || st.nlink !== 1) return null;
|
|
46061
|
-
const bytes2 =
|
|
46459
|
+
const bytes2 = readFileSync53(path2);
|
|
46062
46460
|
return createHash24("sha256").update(bytes2).digest("hex") === f.slice(0, 64) && imageExtension(bytes2) === f.slice(65) ? bytes2 : null;
|
|
46063
46461
|
} catch {
|
|
46064
46462
|
return null;
|
|
@@ -46178,7 +46576,7 @@ function buildReel(dir, budget = REEL_BUDGET_BYTES) {
|
|
|
46178
46576
|
const { plan, images } = inlineImages(dir, planReel(dir), budget);
|
|
46179
46577
|
return { html: renderReel(plan, images), plan };
|
|
46180
46578
|
}
|
|
46181
|
-
var REEL_BUDGET_BYTES, MAX_FLIP_FRAMES, DEFAULT_ACCENT, ACCENT, HISTORY_NAME, MIME2, mimeOf, readJson4,
|
|
46579
|
+
var REEL_BUDGET_BYTES, MAX_FLIP_FRAMES, DEFAULT_ACCENT, ACCENT, HISTORY_NAME, MIME2, mimeOf, readJson4, isObj2, str, historyName, cited;
|
|
46182
46580
|
var init_studio_reel = __esm({
|
|
46183
46581
|
"src/studio-reel.ts"() {
|
|
46184
46582
|
init_progress();
|
|
@@ -46192,12 +46590,12 @@ var init_studio_reel = __esm({
|
|
|
46192
46590
|
mimeOf = (file) => MIME2[file.slice(65)] ?? "image/png";
|
|
46193
46591
|
readJson4 = (file) => {
|
|
46194
46592
|
try {
|
|
46195
|
-
return JSON.parse(
|
|
46593
|
+
return JSON.parse(readFileSync53(file, "utf8"));
|
|
46196
46594
|
} catch {
|
|
46197
46595
|
return null;
|
|
46198
46596
|
}
|
|
46199
46597
|
};
|
|
46200
|
-
|
|
46598
|
+
isObj2 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
46201
46599
|
str = (v) => typeof v === "string" && v ? v : null;
|
|
46202
46600
|
historyName = (sha, ext) => typeof sha === "string" && typeof ext === "string" && HISTORY_NAME.test(`${sha}.${ext}`) ? `${sha}.${ext}` : null;
|
|
46203
46601
|
cited = (p) => [
|
|
@@ -46223,9 +46621,9 @@ __export(native_decode_exports, {
|
|
|
46223
46621
|
runNativeDecode: () => runNativeDecode
|
|
46224
46622
|
});
|
|
46225
46623
|
import { execFileSync as execFileSync5, spawnSync as spawnSync2 } from "node:child_process";
|
|
46226
|
-
import { existsSync as
|
|
46624
|
+
import { existsSync as existsSync49, mkdtempSync as mkdtempSync2, readFileSync as readFileSync54, rmSync as rmSync11, writeFileSync as writeFileSync20 } from "node:fs";
|
|
46227
46625
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
46228
|
-
import { join as
|
|
46626
|
+
import { join as join47 } from "node:path";
|
|
46229
46627
|
import { fileURLToPath as fileURLToPath20 } from "node:url";
|
|
46230
46628
|
function nativeDecodePackageDir() {
|
|
46231
46629
|
return fileURLToPath20(new URL("../../../core/runtime/ios/HimalayaCore/", import.meta.url));
|
|
@@ -46235,8 +46633,8 @@ function nativeDecodeAndroidHarnessDir() {
|
|
|
46235
46633
|
}
|
|
46236
46634
|
function nativeOracleShipped() {
|
|
46237
46635
|
return {
|
|
46238
|
-
ios:
|
|
46239
|
-
android:
|
|
46636
|
+
ios: existsSync49(join47(nativeDecodePackageDir(), "Package.swift")),
|
|
46637
|
+
android: existsSync49(join47(nativeDecodeAndroidHarnessDir(), "gradlew"))
|
|
46240
46638
|
};
|
|
46241
46639
|
}
|
|
46242
46640
|
function detectNativeDecode(options = {}) {
|
|
@@ -46247,7 +46645,7 @@ function detectNativeDecode(options = {}) {
|
|
|
46247
46645
|
return { platform: "ios", available: false, reason: `the iOS decoder oracle requires macOS (darwin); this host is ${hostPlatform}` };
|
|
46248
46646
|
}
|
|
46249
46647
|
if (!swiftAvailable) return { platform: "ios", available: false, reason: "swift is not on PATH" };
|
|
46250
|
-
const packageAvailable = options.packageAvailable ??
|
|
46648
|
+
const packageAvailable = options.packageAvailable ?? existsSync49(join47(packageDir, "Package.swift"));
|
|
46251
46649
|
if (!packageAvailable) {
|
|
46252
46650
|
return {
|
|
46253
46651
|
platform: "ios",
|
|
@@ -46259,7 +46657,7 @@ function detectNativeDecode(options = {}) {
|
|
|
46259
46657
|
}
|
|
46260
46658
|
function localPropertiesSdk(harnessDir) {
|
|
46261
46659
|
try {
|
|
46262
|
-
const match =
|
|
46660
|
+
const match = readFileSync54(join47(harnessDir, "local.properties"), "utf8").match(/^sdk\.dir\s*=\s*(.+)$/m);
|
|
46263
46661
|
return match?.[1]?.trim().replace(/\\([ :\\])/g, "$1") ?? null;
|
|
46264
46662
|
} catch {
|
|
46265
46663
|
return null;
|
|
@@ -46267,8 +46665,8 @@ function localPropertiesSdk(harnessDir) {
|
|
|
46267
46665
|
}
|
|
46268
46666
|
function detectAndroidNativeDecode(options = {}) {
|
|
46269
46667
|
const harnessDir = options.harnessDir ?? nativeDecodeAndroidHarnessDir();
|
|
46270
|
-
const gradlew =
|
|
46271
|
-
const gradlewAvailable = options.gradlewAvailable ??
|
|
46668
|
+
const gradlew = join47(harnessDir, "gradlew");
|
|
46669
|
+
const gradlewAvailable = options.gradlewAvailable ?? existsSync49(gradlew);
|
|
46272
46670
|
if (!gradlewAvailable) {
|
|
46273
46671
|
return {
|
|
46274
46672
|
platform: "android",
|
|
@@ -46278,7 +46676,7 @@ function detectAndroidNativeDecode(options = {}) {
|
|
|
46278
46676
|
}
|
|
46279
46677
|
const androidHome = options.androidHome ?? process.env.ANDROID_HOME ?? "";
|
|
46280
46678
|
const sdk = androidHome.trim() || (options.localPropertiesSdk !== void 0 ? options.localPropertiesSdk : localPropertiesSdk(harnessDir));
|
|
46281
|
-
const sdkAvailable = options.sdkAvailable ?? (typeof sdk === "string" && sdk.length > 0 &&
|
|
46679
|
+
const sdkAvailable = options.sdkAvailable ?? (typeof sdk === "string" && sdk.length > 0 && existsSync49(sdk));
|
|
46282
46680
|
if (!sdkAvailable) {
|
|
46283
46681
|
return {
|
|
46284
46682
|
platform: "android",
|
|
@@ -46350,14 +46748,14 @@ function parseNativeDecodeOutput(stdout, expectedScreenIds, platform = "ios") {
|
|
|
46350
46748
|
return verdicts;
|
|
46351
46749
|
}
|
|
46352
46750
|
function runNativeDecode(options) {
|
|
46353
|
-
const descriptorDir = mkdtempSync2(
|
|
46751
|
+
const descriptorDir = mkdtempSync2(join47(tmpdir3(), "himi-native-decode-"));
|
|
46354
46752
|
const startedAt = Date.now();
|
|
46355
46753
|
try {
|
|
46356
46754
|
for (const descriptor of options.descriptors) {
|
|
46357
46755
|
if (typeof descriptor.descriptorJson !== "string") {
|
|
46358
46756
|
throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
|
|
46359
46757
|
}
|
|
46360
|
-
writeFileSync20(
|
|
46758
|
+
writeFileSync20(join47(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
|
|
46361
46759
|
}
|
|
46362
46760
|
options.progress?.("building cached Swift oracle");
|
|
46363
46761
|
execFileSync5("swift", ["build", "--package-path", options.packageDir, "--product", "himi-decode-oracle"], {
|
|
@@ -46369,7 +46767,7 @@ function runNativeDecode(options) {
|
|
|
46369
46767
|
encoding: "utf8"
|
|
46370
46768
|
}).trim();
|
|
46371
46769
|
options.progress?.(`running real Swift decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
|
|
46372
|
-
const stdout = execFileSync5(
|
|
46770
|
+
const stdout = execFileSync5(join47(binPath, "himi-decode-oracle"), ["--dir", descriptorDir], {
|
|
46373
46771
|
stdio: ["ignore", "pipe", "pipe"],
|
|
46374
46772
|
encoding: "utf8"
|
|
46375
46773
|
});
|
|
@@ -46387,15 +46785,15 @@ function runNativeDecode(options) {
|
|
|
46387
46785
|
}
|
|
46388
46786
|
}
|
|
46389
46787
|
function runAndroidNativeDecode(options) {
|
|
46390
|
-
const descriptorDir = mkdtempSync2(
|
|
46391
|
-
const outputPath =
|
|
46788
|
+
const descriptorDir = mkdtempSync2(join47(tmpdir3(), "himi-native-decode-android-"));
|
|
46789
|
+
const outputPath = join47(descriptorDir, "verdicts.ndjson");
|
|
46392
46790
|
const startedAt = Date.now();
|
|
46393
46791
|
try {
|
|
46394
46792
|
for (const descriptor of options.descriptors) {
|
|
46395
46793
|
if (typeof descriptor.descriptorJson !== "string") {
|
|
46396
46794
|
throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
|
|
46397
46795
|
}
|
|
46398
|
-
writeFileSync20(
|
|
46796
|
+
writeFileSync20(join47(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
|
|
46399
46797
|
}
|
|
46400
46798
|
options.progress?.(`running real Kotlin decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
|
|
46401
46799
|
execFileSync5(options.gradlew, [
|
|
@@ -46410,7 +46808,7 @@ function runAndroidNativeDecode(options) {
|
|
|
46410
46808
|
stdio: ["ignore", "ignore", "pipe"],
|
|
46411
46809
|
encoding: "utf8"
|
|
46412
46810
|
});
|
|
46413
|
-
const stdout =
|
|
46811
|
+
const stdout = readFileSync54(outputPath, "utf8");
|
|
46414
46812
|
return {
|
|
46415
46813
|
platform: "android",
|
|
46416
46814
|
verdicts: parseNativeDecodeOutput(stdout, options.descriptors.map((descriptor) => descriptor.screenId), "android"),
|
|
@@ -46480,13 +46878,13 @@ __export(browser_authoring_exports, {
|
|
|
46480
46878
|
});
|
|
46481
46879
|
import { createServer as createServer3 } from "node:http";
|
|
46482
46880
|
import { createHash as createHash25, randomBytes as randomBytes4 } from "node:crypto";
|
|
46483
|
-
import { existsSync as
|
|
46484
|
-
import { join as
|
|
46881
|
+
import { existsSync as existsSync50, readdirSync as readdirSync24, readFileSync as readFileSync55, realpathSync as realpathSync5, statSync as statSync12 } from "node:fs";
|
|
46882
|
+
import { join as join48, posix, relative as relative8, sep as sep12 } from "node:path";
|
|
46485
46883
|
function humanMs(ms) {
|
|
46486
46884
|
return ms < 1e3 ? `${ms}ms` : `${Math.round(ms / 1e3)}s`;
|
|
46487
46885
|
}
|
|
46488
46886
|
function collectWorkerSources(tier5SrcDir, bundleName) {
|
|
46489
|
-
const root =
|
|
46887
|
+
const root = join48(tier5SrcDir, bundleName);
|
|
46490
46888
|
const files = {};
|
|
46491
46889
|
const visitedDirs = /* @__PURE__ */ new Set();
|
|
46492
46890
|
const walk2 = (abs, rel) => {
|
|
@@ -46494,16 +46892,16 @@ function collectWorkerSources(tier5SrcDir, bundleName) {
|
|
|
46494
46892
|
if (visitedDirs.has(real)) return;
|
|
46495
46893
|
visitedDirs.add(real);
|
|
46496
46894
|
for (const name of readdirSync24(abs).sort()) {
|
|
46497
|
-
const childAbs =
|
|
46895
|
+
const childAbs = join48(abs, name);
|
|
46498
46896
|
const childRel = posix.join(rel, name);
|
|
46499
46897
|
if (statSync12(childAbs).isDirectory()) {
|
|
46500
46898
|
walk2(childAbs, childRel);
|
|
46501
46899
|
} else if (/\.(ts|tsx|js|mjs|json)$/.test(name)) {
|
|
46502
|
-
files[childRel] =
|
|
46900
|
+
files[childRel] = readFileSync55(childAbs, "utf8");
|
|
46503
46901
|
}
|
|
46504
46902
|
}
|
|
46505
46903
|
};
|
|
46506
|
-
if (!
|
|
46904
|
+
if (!existsSync50(root)) return null;
|
|
46507
46905
|
walk2(root, `/tier5-src/${bundleName}`);
|
|
46508
46906
|
const entry = [`/tier5-src/${bundleName}/index.ts`, `/tier5-src/${bundleName}/index.js`].find((p) => p in files);
|
|
46509
46907
|
if (!entry) return null;
|
|
@@ -46520,20 +46918,20 @@ function collectRelativeSiblings(files, tier5SrcDir) {
|
|
|
46520
46918
|
const spec = m[1];
|
|
46521
46919
|
const virtual = posix.normalize(posix.join(dir, spec));
|
|
46522
46920
|
if (!virtual.startsWith("/tier5-src/")) continue;
|
|
46523
|
-
const onDisk =
|
|
46921
|
+
const onDisk = join48(tier5SrcDir, virtual.slice("/tier5-src/".length));
|
|
46524
46922
|
const candidates = [
|
|
46525
46923
|
onDisk,
|
|
46526
46924
|
`${onDisk}.ts`,
|
|
46527
46925
|
`${onDisk}.js`,
|
|
46528
46926
|
onDisk.replace(/\.js$/, ".ts"),
|
|
46529
|
-
|
|
46530
|
-
|
|
46927
|
+
join48(onDisk, "index.ts"),
|
|
46928
|
+
join48(onDisk, "index.js")
|
|
46531
46929
|
];
|
|
46532
46930
|
for (const abs of candidates) {
|
|
46533
|
-
if (!
|
|
46931
|
+
if (!existsSync50(abs) || statSync12(abs).isDirectory()) continue;
|
|
46534
46932
|
const key2 = `/tier5-src/${relative8(tier5SrcDir, abs).split(sep12).join(posix.sep)}`;
|
|
46535
46933
|
if (key2 in files) break;
|
|
46536
|
-
files[key2] =
|
|
46934
|
+
files[key2] = readFileSync55(abs, "utf8");
|
|
46537
46935
|
queue.push(key2);
|
|
46538
46936
|
break;
|
|
46539
46937
|
}
|
|
@@ -46568,7 +46966,7 @@ function collectSdkModules(files, resolveSubpath) {
|
|
|
46568
46966
|
function sdkSubpathReader(resolve48) {
|
|
46569
46967
|
return (sub) => {
|
|
46570
46968
|
try {
|
|
46571
|
-
return
|
|
46969
|
+
return readFileSync55(resolve48(`@wix/himalaya/${sub}`), "utf8");
|
|
46572
46970
|
} catch {
|
|
46573
46971
|
return null;
|
|
46574
46972
|
}
|
|
@@ -46740,8 +47138,8 @@ __export(coverage_exports, {
|
|
|
46740
47138
|
suppressedNativeKeys: () => suppressedNativeKeys,
|
|
46741
47139
|
trendAndStore: () => trendAndStore
|
|
46742
47140
|
});
|
|
46743
|
-
import { existsSync as
|
|
46744
|
-
import { dirname as dirname26, join as
|
|
47141
|
+
import { existsSync as existsSync51, mkdirSync as mkdirSync24, readFileSync as readFileSync56, writeFileSync as writeFileSync21 } from "node:fs";
|
|
47142
|
+
import { dirname as dirname26, join as join49 } from "node:path";
|
|
46745
47143
|
function suppressedNativeKeys(oracle) {
|
|
46746
47144
|
return [...oracle.ios ? [] : ["native-decode|ios"], ...oracle.android ? [] : ["native-decode|android"]];
|
|
46747
47145
|
}
|
|
@@ -46921,11 +47319,11 @@ function assembleLedger(r, options = {}) {
|
|
|
46921
47319
|
return out;
|
|
46922
47320
|
}
|
|
46923
47321
|
function trendAndStore(dir, entries, suppressed) {
|
|
46924
|
-
const p =
|
|
47322
|
+
const p = join49(dir, LEDGER_FILE);
|
|
46925
47323
|
let previous = null;
|
|
46926
47324
|
try {
|
|
46927
|
-
if (
|
|
46928
|
-
const parsed = JSON.parse(
|
|
47325
|
+
if (existsSync51(p)) {
|
|
47326
|
+
const parsed = JSON.parse(readFileSync56(p, "utf8"));
|
|
46929
47327
|
if (Array.isArray(parsed.keys)) previous = parsed.keys.filter((k) => typeof k === "string");
|
|
46930
47328
|
}
|
|
46931
47329
|
} catch {
|
|
@@ -46964,11 +47362,11 @@ function formatLedger(entries, trend) {
|
|
|
46964
47362
|
return out.join("\n");
|
|
46965
47363
|
}
|
|
46966
47364
|
function diffAndStoreObservations(dir, current) {
|
|
46967
|
-
const p =
|
|
47365
|
+
const p = join49(dir, OBS_FILE);
|
|
46968
47366
|
let previous = null;
|
|
46969
47367
|
try {
|
|
46970
|
-
if (
|
|
46971
|
-
const parsed = JSON.parse(
|
|
47368
|
+
if (existsSync51(p)) {
|
|
47369
|
+
const parsed = JSON.parse(readFileSync56(p, "utf8"));
|
|
46972
47370
|
if (parsed.screens && typeof parsed.screens === "object" && !Array.isArray(parsed.screens) && Object.values(parsed.screens).every(
|
|
46973
47371
|
(v) => Array.isArray(v) && v.every((l) => typeof l === "string")
|
|
46974
47372
|
)) {
|
|
@@ -47017,8 +47415,8 @@ var LEDGER_FILE, OBS_FILE;
|
|
|
47017
47415
|
var init_coverage = __esm({
|
|
47018
47416
|
"src/coverage.ts"() {
|
|
47019
47417
|
init_native_decode();
|
|
47020
|
-
LEDGER_FILE =
|
|
47021
|
-
OBS_FILE =
|
|
47418
|
+
LEDGER_FILE = join49(".himi", "test-ledger.json");
|
|
47419
|
+
OBS_FILE = join49(".himi", "test-observations.json");
|
|
47022
47420
|
}
|
|
47023
47421
|
});
|
|
47024
47422
|
|
|
@@ -47029,11 +47427,11 @@ __export(design_kits_exports, {
|
|
|
47029
47427
|
kitsDir: () => kitsDir,
|
|
47030
47428
|
listKits: () => listKits2
|
|
47031
47429
|
});
|
|
47032
|
-
import { existsSync as
|
|
47033
|
-
import { join as
|
|
47430
|
+
import { existsSync as existsSync52, readFileSync as readFileSync57, readdirSync as readdirSync25 } from "node:fs";
|
|
47431
|
+
import { join as join50, basename as basename12 } from "node:path";
|
|
47034
47432
|
import { fileURLToPath as fileURLToPath21 } from "node:url";
|
|
47035
47433
|
function kitsDir() {
|
|
47036
|
-
return KIT_DIR_CANDIDATES.find((p) =>
|
|
47434
|
+
return KIT_DIR_CANDIDATES.find((p) => existsSync52(p));
|
|
47037
47435
|
}
|
|
47038
47436
|
function listKits2() {
|
|
47039
47437
|
const dir = kitsDir();
|
|
@@ -47057,7 +47455,7 @@ In a published @wix/himalaya-cli this is a packaging bug \u2014 the kits should
|
|
|
47057
47455
|
if (!kits.includes(name)) {
|
|
47058
47456
|
return { ok: false, kit: name, kits, problems: [`no design kit named "${name}". Available: ${kits.join(", ")}`] };
|
|
47059
47457
|
}
|
|
47060
|
-
const raw =
|
|
47458
|
+
const raw = readFileSync57(join50(dir, `${name}.json`), "utf8");
|
|
47061
47459
|
let parsed;
|
|
47062
47460
|
try {
|
|
47063
47461
|
parsed = JSON.parse(raw);
|
|
@@ -47081,9 +47479,9 @@ var init_design_kits = __esm({
|
|
|
47081
47479
|
"src/design-kits.ts"() {
|
|
47082
47480
|
KIT_DIR_CANDIDATES = [
|
|
47083
47481
|
// in-repo: tools/himi-cli/src/design-kits.ts → <repo>/stdlib/design-kits/
|
|
47084
|
-
|
|
47482
|
+
join50(fileURLToPath21(new URL("../../..", import.meta.url)), "stdlib", "design-kits"),
|
|
47085
47483
|
// published CLI: <pkg>/dist/cli.mjs → <pkg>/stdlib/design-kits/
|
|
47086
|
-
|
|
47484
|
+
join50(fileURLToPath21(new URL("..", import.meta.url)), "stdlib", "design-kits")
|
|
47087
47485
|
];
|
|
47088
47486
|
}
|
|
47089
47487
|
});
|
|
@@ -47097,11 +47495,11 @@ __export(assets_exports, {
|
|
|
47097
47495
|
removeAssetPayload: () => removeAssetPayload,
|
|
47098
47496
|
verifyReport: () => verifyReport
|
|
47099
47497
|
});
|
|
47100
|
-
import { readFileSync as
|
|
47498
|
+
import { readFileSync as readFileSync58 } from "node:fs";
|
|
47101
47499
|
import { basename as basename13 } from "node:path";
|
|
47102
47500
|
function declaredAssets(dir) {
|
|
47103
47501
|
return collectAssets(dir).map((a) => {
|
|
47104
|
-
const bytes2 =
|
|
47502
|
+
const bytes2 = readFileSync58(a.path);
|
|
47105
47503
|
return {
|
|
47106
47504
|
name: a.name,
|
|
47107
47505
|
sha256: assetSha256(bytes2),
|
|
@@ -47178,7 +47576,7 @@ function verifyReport(dir, app, manifest) {
|
|
|
47178
47576
|
};
|
|
47179
47577
|
}
|
|
47180
47578
|
function addAssetPayload(manifest, filePath, opts) {
|
|
47181
|
-
const bytes2 =
|
|
47579
|
+
const bytes2 = readFileSync58(filePath);
|
|
47182
47580
|
const name = opts.name ?? basename13(filePath);
|
|
47183
47581
|
const sha2565 = assetSha256(bytes2);
|
|
47184
47582
|
const record2 = {
|
|
@@ -48780,21 +49178,21 @@ var init_preview_assets_generated = __esm({
|
|
|
48780
49178
|
"../../packages/serve/src/preview-assets.generated.ts"() {
|
|
48781
49179
|
init_preview_assets_format();
|
|
48782
49180
|
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:
|
|
49181
|
+
{ key: "assets/index-BvsDhZYW.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1043409, sha256: "98882914dcb360867c5f265e3d6542774f18c0b0c8f18813b66b304a122c1b01" },
|
|
49182
|
+
{ key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 1043417, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
|
|
49183
|
+
{ key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 1048027, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
|
|
49184
|
+
{ key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1536611, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
|
|
49185
|
+
{ key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1627535, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
|
|
49186
|
+
{ key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1718519, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
|
|
49187
|
+
{ key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1809499, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
|
|
49188
|
+
{ key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1900371, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
|
|
49189
|
+
{ key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1991351, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
|
|
49190
|
+
{ key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 2099987, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
|
|
49191
|
+
{ key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 2209071, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
|
|
49192
|
+
{ key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 2318119, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
|
|
49193
|
+
{ key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 2425819, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
|
|
49194
|
+
{ key: "index.html", contentType: "text/html; charset=utf-8", offset: 2513927, length: 4947, sha256: "3dd02534fef5e0c2bb40b6c6a6c994641728fde306921e66ffab3e9a7dfa6bbe" },
|
|
49195
|
+
{ key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 2518874, length: 17209, sha256: "dffc9718e2faa63ae2cc919e0a842f585ed565aaaa7c53778e90379442c731b6" }
|
|
48798
49196
|
];
|
|
48799
49197
|
}
|
|
48800
49198
|
});
|
|
@@ -48810,9 +49208,9 @@ __export(run_exports, {
|
|
|
48810
49208
|
runPackage: () => runPackage,
|
|
48811
49209
|
withoutProdServe: () => withoutProdServe
|
|
48812
49210
|
});
|
|
48813
|
-
import { cpSync as cpSync2, existsSync as
|
|
49211
|
+
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
49212
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
48815
|
-
import { dirname as dirname27, join as
|
|
49213
|
+
import { dirname as dirname27, join as join51 } from "node:path";
|
|
48816
49214
|
import { fileURLToPath as fileURLToPath22 } from "node:url";
|
|
48817
49215
|
function makePackageRunHandler(opts) {
|
|
48818
49216
|
return makeRunHandler({
|
|
@@ -48831,9 +49229,9 @@ async function fetchBytes(url) {
|
|
|
48831
49229
|
}
|
|
48832
49230
|
async function resolvePackage(source, workDir) {
|
|
48833
49231
|
const isUrl2 = /^https?:\/\//i.test(source);
|
|
48834
|
-
if (!isUrl2 &&
|
|
48835
|
-
const appDirManifest =
|
|
48836
|
-
if (
|
|
49232
|
+
if (!isUrl2 && existsSync53(source) && statSync13(source).isDirectory()) {
|
|
49233
|
+
const appDirManifest = join51(source, "release-manifest.json");
|
|
49234
|
+
if (existsSync53(appDirManifest)) {
|
|
48837
49235
|
const opened2 = openPackageDir(source);
|
|
48838
49236
|
if (!opened2.validation.ok) {
|
|
48839
49237
|
throw new Error(`package is not valid:
|
|
@@ -48842,9 +49240,9 @@ async function resolvePackage(source, workDir) {
|
|
|
48842
49240
|
const app2 = opened2.header?.app ?? opened2.manifest?.app;
|
|
48843
49241
|
if (!app2) throw new Error(`${source} has no app id (no himi-package.json and no manifest.app)`);
|
|
48844
49242
|
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 (
|
|
49243
|
+
const root2 = workDir ?? mkdtempSync3(join51(tmpdir4(), "himi-run-"));
|
|
49244
|
+
const target = join51(root2, app2);
|
|
49245
|
+
if (join51(source) !== target) {
|
|
48848
49246
|
mkdirSync25(root2, { recursive: true });
|
|
48849
49247
|
rmSync12(target, { recursive: true, force: true });
|
|
48850
49248
|
cpSync2(source, target, { recursive: true });
|
|
@@ -48861,8 +49259,8 @@ async function resolvePackage(source, workDir) {
|
|
|
48861
49259
|
}
|
|
48862
49260
|
throw new Error(`${source} is a directory but has no release-manifest.json \u2014 is it a package?`);
|
|
48863
49261
|
}
|
|
48864
|
-
const bytes2 = isUrl2 ? await fetchBytes(source) :
|
|
48865
|
-
const root = workDir ?? mkdtempSync3(
|
|
49262
|
+
const bytes2 = isUrl2 ? await fetchBytes(source) : readFileSync59(source);
|
|
49263
|
+
const root = workDir ?? mkdtempSync3(join51(tmpdir4(), "himi-run-"));
|
|
48866
49264
|
const { app, appDir: appDir2 } = unpackTo(bytes2, root);
|
|
48867
49265
|
const opened = openPackageDir(appDir2);
|
|
48868
49266
|
if (!opened.validation.ok) {
|
|
@@ -48885,14 +49283,14 @@ async function loadPreviewAssets() {
|
|
|
48885
49283
|
const mod = await Promise.resolve().then(() => (init_preview_assets_generated(), preview_assets_generated_exports));
|
|
48886
49284
|
const here = dirname27(fileURLToPath22(import.meta.url));
|
|
48887
49285
|
const candidates = [
|
|
48888
|
-
|
|
49286
|
+
join51(here, "preview-assets.generated.bin"),
|
|
48889
49287
|
// published: copied next to the bundled CLI
|
|
48890
|
-
|
|
49288
|
+
join51(here, "../../../packages/serve/src/preview-assets.generated.bin")
|
|
48891
49289
|
// in-repo checkout
|
|
48892
49290
|
];
|
|
48893
49291
|
for (const path2 of candidates) {
|
|
48894
|
-
if (!
|
|
48895
|
-
const blob =
|
|
49292
|
+
if (!existsSync53(path2)) continue;
|
|
49293
|
+
const blob = readFileSync59(path2);
|
|
48896
49294
|
return mod.assemblePreviewAssetsFromBlob(new Uint8Array(blob.buffer, blob.byteOffset, blob.byteLength));
|
|
48897
49295
|
}
|
|
48898
49296
|
return /* @__PURE__ */ new Map();
|
|
@@ -48987,9 +49385,9 @@ __export(run_watch_exports, {
|
|
|
48987
49385
|
watchedContentDir: () => watchedContentDir,
|
|
48988
49386
|
writeRunRecord: () => writeRunRecord
|
|
48989
49387
|
});
|
|
48990
|
-
import { closeSync as closeSync2, constants, existsSync as
|
|
49388
|
+
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
49389
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
48992
|
-
import { extname as extname4, join as
|
|
49390
|
+
import { extname as extname4, join as join52, resolve as resolve42, sep as sep13 } from "node:path";
|
|
48993
49391
|
function diffReleases(prev, next) {
|
|
48994
49392
|
const bundles = Object.keys(next.bundles).filter((b) => prev.bundles[b]?.sha256 !== next.bundles[b].sha256).sort();
|
|
48995
49393
|
const changedBundles = new Set(bundles);
|
|
@@ -49028,8 +49426,8 @@ function watchContent(dir, onChange, opts = {}) {
|
|
|
49028
49426
|
const watch2 = opts.watch ?? ((p, o, l) => fsWatch(p, o, (event, file) => l(event, file === null ? null : String(file))));
|
|
49029
49427
|
let timer = null;
|
|
49030
49428
|
const pending = /* @__PURE__ */ new Set();
|
|
49031
|
-
const
|
|
49032
|
-
if (!file || ignoredChange(file, (rel) => isDir(
|
|
49429
|
+
const watcher2 = watch2(dir, { recursive: true }, (_event, file) => {
|
|
49430
|
+
if (!file || ignoredChange(file, (rel) => isDir(join52(dir, rel)))) return;
|
|
49033
49431
|
pending.add(file);
|
|
49034
49432
|
if (timer) clearTimeout(timer);
|
|
49035
49433
|
timer = setTimeout(() => {
|
|
@@ -49042,7 +49440,7 @@ function watchContent(dir, onChange, opts = {}) {
|
|
|
49042
49440
|
return {
|
|
49043
49441
|
close() {
|
|
49044
49442
|
if (timer) clearTimeout(timer);
|
|
49045
|
-
|
|
49443
|
+
watcher2.close();
|
|
49046
49444
|
}
|
|
49047
49445
|
};
|
|
49048
49446
|
}
|
|
@@ -49050,7 +49448,7 @@ function watchedContentDir(source) {
|
|
|
49050
49448
|
if (!source || /^https?:\/\//i.test(source)) return null;
|
|
49051
49449
|
const dir = resolve42(source);
|
|
49052
49450
|
try {
|
|
49053
|
-
return statSync14(dir).isDirectory() &&
|
|
49451
|
+
return statSync14(dir).isDirectory() && existsSync54(join52(dir, "himalaya.content.json")) ? dir : null;
|
|
49054
49452
|
} catch {
|
|
49055
49453
|
return null;
|
|
49056
49454
|
}
|
|
@@ -49107,7 +49505,7 @@ function serialize(task) {
|
|
|
49107
49505
|
});
|
|
49108
49506
|
}
|
|
49109
49507
|
function himiDir(dir) {
|
|
49110
|
-
const root =
|
|
49508
|
+
const root = join52(dir, ".himi");
|
|
49111
49509
|
try {
|
|
49112
49510
|
return lstatSync8(root).isDirectory() ? root : null;
|
|
49113
49511
|
} catch (e) {
|
|
@@ -49119,11 +49517,11 @@ function himiDir(dir) {
|
|
|
49119
49517
|
function writeRunRecord(dir, record2) {
|
|
49120
49518
|
const root = himiDir(dir);
|
|
49121
49519
|
if (!root) return false;
|
|
49122
|
-
const tmp =
|
|
49520
|
+
const tmp = join52(root, `.run.json.${process.pid}.${randomUUID3()}.tmp`);
|
|
49123
49521
|
try {
|
|
49124
49522
|
writeFileSync22(tmp, `${JSON.stringify(record2, null, 2)}
|
|
49125
49523
|
`, { flag: "wx" });
|
|
49126
|
-
renameSync5(tmp,
|
|
49524
|
+
renameSync5(tmp, join52(root, "run.json"));
|
|
49127
49525
|
} catch (e) {
|
|
49128
49526
|
rmSync13(tmp, { force: true });
|
|
49129
49527
|
throw e;
|
|
@@ -49131,7 +49529,7 @@ function writeRunRecord(dir, record2) {
|
|
|
49131
49529
|
return true;
|
|
49132
49530
|
}
|
|
49133
49531
|
function removeRunRecord(dir, owner) {
|
|
49134
|
-
const root =
|
|
49532
|
+
const root = join52(dir, ".himi");
|
|
49135
49533
|
try {
|
|
49136
49534
|
if (!lstatSync8(root).isDirectory()) return;
|
|
49137
49535
|
} catch {
|
|
@@ -49146,15 +49544,16 @@ function removeRunRecord(dir, owner) {
|
|
|
49146
49544
|
}
|
|
49147
49545
|
if (typeof pid === "number" && pid !== owner) return;
|
|
49148
49546
|
}
|
|
49149
|
-
rmSync13(
|
|
49547
|
+
rmSync13(join52(root, "run.json"), { force: true });
|
|
49150
49548
|
}
|
|
49151
49549
|
function boardFile(dir, pathname) {
|
|
49152
49550
|
let rel = null;
|
|
49153
|
-
if (pathname === "/__himi/studio/" || pathname === "/__himi/studio/index.html") rel =
|
|
49154
|
-
else if (pathname === "/__himi/studio/state.js") rel =
|
|
49551
|
+
if (pathname === "/__himi/studio/" || pathname === "/__himi/studio/index.html") rel = join52("studio", "index.html");
|
|
49552
|
+
else if (pathname === "/__himi/studio/state.js") rel = join52("studio", "state.js");
|
|
49553
|
+
else if (pathname === "/__himi/studio/timeline.js") rel = join52("studio", "timeline.js");
|
|
49155
49554
|
else {
|
|
49156
49555
|
const m = /^\/__himi\/history\/([0-9a-f]{64}\.(png|jpg|gif|webp))$/.exec(pathname);
|
|
49157
|
-
if (m) rel =
|
|
49556
|
+
if (m) rel = join52("history", m[1]);
|
|
49158
49557
|
}
|
|
49159
49558
|
if (!rel) return null;
|
|
49160
49559
|
const bytes2 = readConfined(resolve42(dir, ".himi"), rel);
|
|
@@ -49170,7 +49569,7 @@ function readConfined(root, rel) {
|
|
|
49170
49569
|
const parts = rel.split(sep13);
|
|
49171
49570
|
let at = root;
|
|
49172
49571
|
for (let i = 0; i < parts.length; i++) {
|
|
49173
|
-
at =
|
|
49572
|
+
at = join52(at, parts[i]);
|
|
49174
49573
|
const st = lstatSync8(at);
|
|
49175
49574
|
if (st.isSymbolicLink() || !(i === parts.length - 1 ? st.isFile() : st.isDirectory())) return null;
|
|
49176
49575
|
}
|
|
@@ -49179,7 +49578,7 @@ function readConfined(root, rel) {
|
|
|
49179
49578
|
const fd = openSync2(at, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
49180
49579
|
try {
|
|
49181
49580
|
if (!fstatSync(fd).isFile()) return null;
|
|
49182
|
-
return
|
|
49581
|
+
return readFileSync60(fd);
|
|
49183
49582
|
} finally {
|
|
49184
49583
|
closeSync2(fd);
|
|
49185
49584
|
}
|
|
@@ -49230,7 +49629,7 @@ __export(run_browser_exports, {
|
|
|
49230
49629
|
runInBrowser: () => runInBrowser
|
|
49231
49630
|
});
|
|
49232
49631
|
import { createServer as createServer5 } from "node:http";
|
|
49233
|
-
import { existsSync as
|
|
49632
|
+
import { existsSync as existsSync55, readFileSync as readFileSync61 } from "node:fs";
|
|
49234
49633
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
49235
49634
|
import { dirname as dirname28, resolve as resolve43 } from "node:path";
|
|
49236
49635
|
import { fileURLToPath as fileURLToPath23 } from "node:url";
|
|
@@ -49238,7 +49637,7 @@ function stagedDir() {
|
|
|
49238
49637
|
return process.env.HIMI_BROWSER_PLANE_OUT ? resolve43(process.env.HIMI_BROWSER_PLANE_OUT) : resolve43(REPO, "packages", "serve", "dist", "browser-plane");
|
|
49239
49638
|
}
|
|
49240
49639
|
function missingStaged() {
|
|
49241
|
-
return [...SERVED].filter((f) => !
|
|
49640
|
+
return [...SERVED].filter((f) => !existsSync55(resolve43(stagedDir(), f))).sort();
|
|
49242
49641
|
}
|
|
49243
49642
|
function ensureBrowserPlaneStaged() {
|
|
49244
49643
|
if (missingStaged().length === 0) return { ok: true, detail: "already staged" };
|
|
@@ -49328,7 +49727,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
|
|
|
49328
49727
|
}
|
|
49329
49728
|
const name = path2 === "/" || path2 === "/index.html" ? "host.html" : path2.slice(1);
|
|
49330
49729
|
if (SERVED.has(name)) {
|
|
49331
|
-
if (!
|
|
49730
|
+
if (!existsSync55(resolve43(stagedDir(), name))) {
|
|
49332
49731
|
const restaged = ensureBrowserPlaneStaged();
|
|
49333
49732
|
if (!restaged.ok) {
|
|
49334
49733
|
res.writeHead(503, { "content-type": "application/json" });
|
|
@@ -49338,7 +49737,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
|
|
|
49338
49737
|
}
|
|
49339
49738
|
let bytes2;
|
|
49340
49739
|
try {
|
|
49341
|
-
bytes2 =
|
|
49740
|
+
bytes2 = readFileSync61(resolve43(stagedDir(), name));
|
|
49342
49741
|
} catch (e) {
|
|
49343
49742
|
res.writeHead(503, { "content-type": "application/json" });
|
|
49344
49743
|
res.end(JSON.stringify({ error: "browser_plane_unstaged", file: name, detail: String(e) }));
|
|
@@ -49798,7 +50197,7 @@ __export(preflight_exports, {
|
|
|
49798
50197
|
parseStoreConfig: () => parseStoreConfig,
|
|
49799
50198
|
requireEnv: () => requireEnv
|
|
49800
50199
|
});
|
|
49801
|
-
import { existsSync as
|
|
50200
|
+
import { existsSync as existsSync56, readFileSync as readFileSync62 } from "node:fs";
|
|
49802
50201
|
import { isAbsolute as isAbsolute3, relative as relative9, resolve as resolve44 } from "node:path";
|
|
49803
50202
|
function isInsideRepo(p) {
|
|
49804
50203
|
const rel = relative9(REPO_ROOT3, resolve44(p));
|
|
@@ -49855,10 +50254,10 @@ function parseStoreConfig(text5) {
|
|
|
49855
50254
|
}
|
|
49856
50255
|
function loadStoreConfig(app) {
|
|
49857
50256
|
const p = storeConfigPath(app);
|
|
49858
|
-
if (!
|
|
50257
|
+
if (!existsSync56(p)) {
|
|
49859
50258
|
throw new Error(`No store config at ${p}. Create apps/${app}/store/store.config.yaml first (see /setup-store-signing).`);
|
|
49860
50259
|
}
|
|
49861
|
-
return parseStoreConfig(
|
|
50260
|
+
return parseStoreConfig(readFileSync62(p, "utf8"));
|
|
49862
50261
|
}
|
|
49863
50262
|
var init_preflight = __esm({
|
|
49864
50263
|
"../store-release/preflight.ts"() {
|
|
@@ -49877,19 +50276,19 @@ __export(credential_profile_exports, {
|
|
|
49877
50276
|
profilePath: () => profilePath,
|
|
49878
50277
|
resolveStoreCredentials: () => resolveStoreCredentials
|
|
49879
50278
|
});
|
|
49880
|
-
import { existsSync as
|
|
50279
|
+
import { existsSync as existsSync57, readFileSync as readFileSync63 } from "node:fs";
|
|
49881
50280
|
import { homedir as homedir5 } from "node:os";
|
|
49882
|
-
import { join as
|
|
50281
|
+
import { join as join53 } from "node:path";
|
|
49883
50282
|
function credentialsDir(home = homedir5()) {
|
|
49884
|
-
return
|
|
50283
|
+
return join53(home, ".himalaya", "store-credentials");
|
|
49885
50284
|
}
|
|
49886
50285
|
function profilePath(name, home = homedir5()) {
|
|
49887
50286
|
if (!PROFILE_NAME.test(name)) {
|
|
49888
50287
|
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 ${
|
|
50288
|
+
`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
50289
|
);
|
|
49891
50290
|
}
|
|
49892
|
-
return
|
|
50291
|
+
return join53(credentialsDir(home), `${name}.json`);
|
|
49893
50292
|
}
|
|
49894
50293
|
function parseProfile(text5, label2) {
|
|
49895
50294
|
let doc;
|
|
@@ -49920,8 +50319,8 @@ function resolveStoreCredentials(opts) {
|
|
|
49920
50319
|
const { app, cfg } = opts;
|
|
49921
50320
|
const env = opts.env ?? process.env;
|
|
49922
50321
|
const home = opts.home ?? homedir5();
|
|
49923
|
-
const read = opts.readProfile ?? ((p) =>
|
|
49924
|
-
const exists = opts.profileExists ??
|
|
50322
|
+
const read = opts.readProfile ?? ((p) => readFileSync63(p, "utf8"));
|
|
50323
|
+
const exists = opts.profileExists ?? existsSync57;
|
|
49925
50324
|
const ios = cfg.ios ?? {};
|
|
49926
50325
|
const flagName = opts.profileFlag?.trim();
|
|
49927
50326
|
const named = namedProfile(cfg, opts.profileFlag);
|
|
@@ -50001,9 +50400,9 @@ __export(preflight_app_exports, {
|
|
|
50001
50400
|
preflightApp: () => preflightApp,
|
|
50002
50401
|
profileAccount: () => profileAccount
|
|
50003
50402
|
});
|
|
50004
|
-
import { readFileSync as
|
|
50403
|
+
import { readFileSync as readFileSync64, existsSync as existsSync58, readdirSync as readdirSync26, statSync as statSync15 } from "node:fs";
|
|
50005
50404
|
import { createHash as createHash26 } from "node:crypto";
|
|
50006
|
-
import { join as
|
|
50405
|
+
import { join as join54 } from "node:path";
|
|
50007
50406
|
function analyze(projectYml, storeConfig, icon, account) {
|
|
50008
50407
|
const f = [];
|
|
50009
50408
|
const has = (re, s) => re.test(s);
|
|
@@ -50067,13 +50466,13 @@ function profileAccount(app, storeConfig, opts = {}) {
|
|
|
50067
50466
|
}
|
|
50068
50467
|
}
|
|
50069
50468
|
async function preflightApp(app, opts = {}) {
|
|
50070
|
-
const projectYml =
|
|
50071
|
-
const storeConfig =
|
|
50469
|
+
const projectYml = existsSync58(iosProjectYml(app)) ? readFileSync64(iosProjectYml(app), "utf8") : "";
|
|
50470
|
+
const storeConfig = existsSync58(storeConfigPath(app)) ? readFileSync64(storeConfigPath(app), "utf8") : "";
|
|
50072
50471
|
if (!storeConfig) return [{ level: "error", message: `no apps/${app}/store/store.config.yaml \u2014 run /setup-store-signing first.` }];
|
|
50073
50472
|
const findings = analyze(
|
|
50074
50473
|
projectYml,
|
|
50075
50474
|
storeConfig,
|
|
50076
|
-
await appIconState(
|
|
50475
|
+
await appIconState(join54(appDir(app), "ios")),
|
|
50077
50476
|
profileAccount(app, storeConfig, opts)
|
|
50078
50477
|
);
|
|
50079
50478
|
findings.push(...analyzeListing(metadataFilesPresent(app), listScreenshots(app)));
|
|
@@ -50102,17 +50501,17 @@ function analyzeSubmissionRecord(appLevel, review, opts) {
|
|
|
50102
50501
|
return f;
|
|
50103
50502
|
}
|
|
50104
50503
|
function appLevelMetadataFiles(app, locale = "en-US") {
|
|
50105
|
-
const root =
|
|
50504
|
+
const root = join54(storeDir(app), "metadata");
|
|
50106
50505
|
const out = /* @__PURE__ */ new Set();
|
|
50107
|
-
if (
|
|
50506
|
+
if (existsSync58(root)) {
|
|
50108
50507
|
for (const n of readdirSync26(root)) if (n.endsWith(".txt")) out.add(n);
|
|
50109
50508
|
}
|
|
50110
|
-
if (
|
|
50509
|
+
if (existsSync58(join54(root, locale, "privacy_url.txt"))) out.add("privacy_url.txt");
|
|
50111
50510
|
return out;
|
|
50112
50511
|
}
|
|
50113
50512
|
function reviewInfoFiles(app) {
|
|
50114
|
-
const dir =
|
|
50115
|
-
if (!
|
|
50513
|
+
const dir = join54(storeDir(app), "review_information");
|
|
50514
|
+
if (!existsSync58(dir)) return /* @__PURE__ */ new Set();
|
|
50116
50515
|
return new Set(readdirSync26(dir).filter((n) => n.endsWith(".txt")));
|
|
50117
50516
|
}
|
|
50118
50517
|
function isValidAppStoreSize(w, h) {
|
|
@@ -50222,12 +50621,12 @@ function analyzePlayListing(assets) {
|
|
|
50222
50621
|
return f;
|
|
50223
50622
|
}
|
|
50224
50623
|
function playListingAssets(app, locale = "en-US") {
|
|
50225
|
-
const dir =
|
|
50624
|
+
const dir = join54(storeDir(app), "play", locale, "images");
|
|
50226
50625
|
const read = (names) => {
|
|
50227
50626
|
for (const name of names) {
|
|
50228
|
-
const p =
|
|
50627
|
+
const p = join54(dir, name);
|
|
50229
50628
|
try {
|
|
50230
|
-
if (statSync15(p).isFile()) return { name, bytes:
|
|
50629
|
+
if (statSync15(p).isFile()) return { name, bytes: readFileSync64(p) };
|
|
50231
50630
|
} catch {
|
|
50232
50631
|
}
|
|
50233
50632
|
}
|
|
@@ -50258,26 +50657,26 @@ function analyzeListing(metaFiles, shots) {
|
|
|
50258
50657
|
return f;
|
|
50259
50658
|
}
|
|
50260
50659
|
function metadataFilesPresent(app, locale = "en-US") {
|
|
50261
|
-
const dir =
|
|
50262
|
-
if (!
|
|
50660
|
+
const dir = join54(storeDir(app), "metadata", locale);
|
|
50661
|
+
if (!existsSync58(dir)) return /* @__PURE__ */ new Set();
|
|
50263
50662
|
return new Set(readdirSync26(dir).filter((n) => n.endsWith(".txt")));
|
|
50264
50663
|
}
|
|
50265
50664
|
function listScreenshots(app, locale = "en-US") {
|
|
50266
50665
|
const out = [];
|
|
50267
|
-
const flat =
|
|
50268
|
-
if (
|
|
50666
|
+
const flat = join54(storeDir(app), "screenshots", locale);
|
|
50667
|
+
if (existsSync58(flat)) {
|
|
50269
50668
|
for (const png of readdirSync26(flat).filter((n) => n.endsWith(".png"))) {
|
|
50270
|
-
const sz = pngSize(
|
|
50669
|
+
const sz = pngSize(readFileSync64(join54(flat, png)));
|
|
50271
50670
|
if (sz) out.push({ name: png, w: sz.w, h: sz.h });
|
|
50272
50671
|
}
|
|
50273
50672
|
}
|
|
50274
|
-
const legacy =
|
|
50275
|
-
if (
|
|
50673
|
+
const legacy = join54(storeDir(app), "metadata", locale, "screenshots");
|
|
50674
|
+
if (existsSync58(legacy)) {
|
|
50276
50675
|
for (const deviceDir of readdirSync26(legacy)) {
|
|
50277
|
-
const d =
|
|
50676
|
+
const d = join54(legacy, deviceDir);
|
|
50278
50677
|
if (!statSync15(d).isDirectory()) continue;
|
|
50279
50678
|
for (const png of readdirSync26(d).filter((n) => n.endsWith(".png"))) {
|
|
50280
|
-
const sz = pngSize(
|
|
50679
|
+
const sz = pngSize(readFileSync64(join54(d, png)));
|
|
50281
50680
|
if (sz) out.push({ name: `${deviceDir}/${png}`, w: sz.w, h: sz.h });
|
|
50282
50681
|
}
|
|
50283
50682
|
}
|
|
@@ -50285,13 +50684,13 @@ function listScreenshots(app, locale = "en-US") {
|
|
|
50285
50684
|
return out;
|
|
50286
50685
|
}
|
|
50287
50686
|
function placeholderHashes2() {
|
|
50288
|
-
const templateIos =
|
|
50289
|
-
if (!
|
|
50687
|
+
const templateIos = join54(appDir("_template"), "ios");
|
|
50688
|
+
if (!existsSync58(templateIos)) return [LEGACY_PLACEHOLDER_SHA2562];
|
|
50290
50689
|
for (const target of readdirSync26(templateIos)) {
|
|
50291
|
-
const p =
|
|
50690
|
+
const p = join54(templateIos, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
|
|
50292
50691
|
try {
|
|
50293
50692
|
if (!statSync15(p).isFile()) continue;
|
|
50294
|
-
return [LEGACY_PLACEHOLDER_SHA2562, createHash26("sha256").update(
|
|
50693
|
+
return [LEGACY_PLACEHOLDER_SHA2562, createHash26("sha256").update(readFileSync64(p)).digest("hex")];
|
|
50295
50694
|
} catch {
|
|
50296
50695
|
}
|
|
50297
50696
|
}
|
|
@@ -50322,12 +50721,12 @@ async function pixelIssues(bytes2) {
|
|
|
50322
50721
|
}
|
|
50323
50722
|
}
|
|
50324
50723
|
async function appIconState(iosDir) {
|
|
50325
|
-
if (!
|
|
50724
|
+
if (!existsSync58(iosDir)) return { exists: false, isPlaceholder: false, storeIssues: [] };
|
|
50326
50725
|
for (const target of readdirSync26(iosDir)) {
|
|
50327
|
-
const p =
|
|
50726
|
+
const p = join54(iosDir, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
|
|
50328
50727
|
try {
|
|
50329
50728
|
if (!statSync15(p).isFile()) continue;
|
|
50330
|
-
const bytes2 =
|
|
50729
|
+
const bytes2 = readFileSync64(p);
|
|
50331
50730
|
const hash = createHash26("sha256").update(bytes2).digest("hex");
|
|
50332
50731
|
const pixels = await pixelIssues(bytes2);
|
|
50333
50732
|
return {
|
|
@@ -50399,7 +50798,7 @@ __export(version_exports, {
|
|
|
50399
50798
|
setAndroidVersion: () => setAndroidVersion,
|
|
50400
50799
|
setIosVersion: () => setIosVersion
|
|
50401
50800
|
});
|
|
50402
|
-
import { readFileSync as
|
|
50801
|
+
import { readFileSync as readFileSync65, writeFileSync as writeFileSync23 } from "node:fs";
|
|
50403
50802
|
function readIosVersion(projectYml) {
|
|
50404
50803
|
const marketing = matchScalar(projectYml, "CFBundleShortVersionString");
|
|
50405
50804
|
const build2 = matchScalar(projectYml, "CFBundleVersion");
|
|
@@ -50457,8 +50856,8 @@ function setAndroidVersion(gradle, v) {
|
|
|
50457
50856
|
function bumpVersion(app, opts) {
|
|
50458
50857
|
const iosPath = iosProjectYml(app);
|
|
50459
50858
|
const gradlePath = androidGradle(app);
|
|
50460
|
-
const iosYml =
|
|
50461
|
-
const gradle =
|
|
50859
|
+
const iosYml = readFileSync65(iosPath, "utf8");
|
|
50860
|
+
const gradle = readFileSync65(gradlePath, "utf8");
|
|
50462
50861
|
const current = readIosVersion(iosYml);
|
|
50463
50862
|
const next = {
|
|
50464
50863
|
marketing: opts.marketing ?? current.marketing,
|
|
@@ -50475,7 +50874,7 @@ var init_version = __esm({
|
|
|
50475
50874
|
});
|
|
50476
50875
|
|
|
50477
50876
|
// ../store-release/register-bundle.ts
|
|
50478
|
-
import { readFileSync as
|
|
50877
|
+
import { readFileSync as readFileSync66 } from "node:fs";
|
|
50479
50878
|
import { createPrivateKey as createPrivateKey2, sign } from "node:crypto";
|
|
50480
50879
|
function b64url2(b) {
|
|
50481
50880
|
return Buffer.from(b).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
@@ -50493,7 +50892,7 @@ function bundleIdBody(identifier, name, platform = "IOS") {
|
|
|
50493
50892
|
async function registerBundleId(opts) {
|
|
50494
50893
|
const env = requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
|
|
50495
50894
|
assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
|
|
50496
|
-
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID,
|
|
50895
|
+
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync66(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
|
|
50497
50896
|
const res = await fetch(`${ASC_API}/v1/bundleIds`, {
|
|
50498
50897
|
method: "POST",
|
|
50499
50898
|
headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
|
|
@@ -50547,7 +50946,7 @@ __export(asc_status_exports, {
|
|
|
50547
50946
|
ascStatus: () => ascStatus,
|
|
50548
50947
|
buildVerdict: () => buildVerdict
|
|
50549
50948
|
});
|
|
50550
|
-
import { readFileSync as
|
|
50949
|
+
import { readFileSync as readFileSync67 } from "node:fs";
|
|
50551
50950
|
function buildVerdict(builds) {
|
|
50552
50951
|
if (!builds.length) {
|
|
50553
50952
|
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 +50960,7 @@ function buildVerdict(builds) {
|
|
|
50561
50960
|
function client(creds) {
|
|
50562
50961
|
const env = creds ?? requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
|
|
50563
50962
|
assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
|
|
50564
|
-
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID,
|
|
50963
|
+
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync67(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
|
|
50565
50964
|
return async (path2) => {
|
|
50566
50965
|
const r = await fetch(`${ASC}${path2}`, { headers: { Authorization: `Bearer ${jwt}` } });
|
|
50567
50966
|
return { status: r.status, json: await r.json().catch(() => ({})) };
|
|
@@ -50721,7 +51120,7 @@ __export(secrets_exports, {
|
|
|
50721
51120
|
runRemoteSecretsCommand: () => runRemoteSecretsCommand,
|
|
50722
51121
|
runSecretsCommand: () => runSecretsCommand
|
|
50723
51122
|
});
|
|
50724
|
-
import { readFileSync as
|
|
51123
|
+
import { readFileSync as readFileSync68 } from "node:fs";
|
|
50725
51124
|
function environment(value) {
|
|
50726
51125
|
if (value === "preview" || value === "production") return value;
|
|
50727
51126
|
throw new Error("--environment must be preview or production");
|
|
@@ -50752,7 +51151,7 @@ async function runSecretsCommand(operation, flags, io, options = {}) {
|
|
|
50752
51151
|
io.log(JSON.stringify(await vault.list({ app, environment: env })));
|
|
50753
51152
|
return 0;
|
|
50754
51153
|
}
|
|
50755
|
-
const value = options.readValue ? options.readValue() :
|
|
51154
|
+
const value = options.readValue ? options.readValue() : readFileSync68(0, "utf8").replace(/\r?\n$/, "");
|
|
50756
51155
|
if (operation === "set") await vault.set({ app, environment: env, name, value });
|
|
50757
51156
|
else if (operation === "rotate") await vault.rotate({ app, environment: env, name, value });
|
|
50758
51157
|
else throw new Error(`unknown secrets operation ${operation}`);
|
|
@@ -50781,7 +51180,7 @@ async function runRemoteSecretsCommand(operation, flags, io, options) {
|
|
|
50781
51180
|
}
|
|
50782
51181
|
let body;
|
|
50783
51182
|
if (operation !== "list") {
|
|
50784
|
-
const value = options.readValue ? options.readValue() :
|
|
51183
|
+
const value = options.readValue ? options.readValue() : readFileSync68(0, "utf8").replace(/\r?\n$/, "");
|
|
50785
51184
|
body = JSON.stringify({ value });
|
|
50786
51185
|
}
|
|
50787
51186
|
const response = await (options.fetchImpl ?? fetch)(url, { method: operation === "list" ? "GET" : operation === "set" ? "PUT" : "POST", headers: headers2, body });
|
|
@@ -50817,15 +51216,15 @@ __export(notify_exports, {
|
|
|
50817
51216
|
runNotify: () => runNotify,
|
|
50818
51217
|
saveAdminSession: () => saveAdminSession
|
|
50819
51218
|
});
|
|
50820
|
-
import { chmodSync as chmodSync3, mkdirSync as mkdirSync27, readFileSync as
|
|
51219
|
+
import { chmodSync as chmodSync3, mkdirSync as mkdirSync27, readFileSync as readFileSync69, writeFileSync as writeFileSync24 } from "node:fs";
|
|
50821
51220
|
import { homedir as homedir6 } from "node:os";
|
|
50822
|
-
import { dirname as dirname30, join as
|
|
51221
|
+
import { dirname as dirname30, join as join55 } from "node:path";
|
|
50823
51222
|
function defaultSessionsPath() {
|
|
50824
|
-
return process.env.HIMI_ADMIN_SESSIONS_FILE ??
|
|
51223
|
+
return process.env.HIMI_ADMIN_SESSIONS_FILE ?? join55(homedir6(), ".himalaya", "admin-sessions.json");
|
|
50825
51224
|
}
|
|
50826
51225
|
function loadSessionsFile(path2 = defaultSessionsPath()) {
|
|
50827
51226
|
try {
|
|
50828
|
-
return JSON.parse(
|
|
51227
|
+
return JSON.parse(readFileSync69(path2, "utf8"));
|
|
50829
51228
|
} catch {
|
|
50830
51229
|
return {};
|
|
50831
51230
|
}
|
|
@@ -54383,7 +54782,7 @@ var init_brand_font = __esm({
|
|
|
54383
54782
|
|
|
54384
54783
|
// src/site-analyze/write-artifacts.ts
|
|
54385
54784
|
import { mkdirSync as mkdirSync28, writeFileSync as writeFileSync25 } from "node:fs";
|
|
54386
|
-
import { join as
|
|
54785
|
+
import { join as join56 } from "node:path";
|
|
54387
54786
|
function attachVeloSources(book, sources, put) {
|
|
54388
54787
|
const byPath = new Map((sources ?? []).map((s) => [s.path, s.text]));
|
|
54389
54788
|
for (const f of book.velo.files) {
|
|
@@ -54538,12 +54937,12 @@ async function downloadMedia(book, fetchImpl, put) {
|
|
|
54538
54937
|
}
|
|
54539
54938
|
async function writeBusinessBook(result, opts) {
|
|
54540
54939
|
const out = opts.outDir;
|
|
54541
|
-
mkdirSync28(
|
|
54542
|
-
mkdirSync28(
|
|
54940
|
+
mkdirSync28(join56(out, "evidence/pages"), { recursive: true });
|
|
54941
|
+
mkdirSync28(join56(out, "media/catalog"), { recursive: true });
|
|
54543
54942
|
const files = [];
|
|
54544
54943
|
const put = (rel, body) => {
|
|
54545
|
-
const p =
|
|
54546
|
-
mkdirSync28(
|
|
54944
|
+
const p = join56(out, rel);
|
|
54945
|
+
mkdirSync28(join56(p, ".."), { recursive: true });
|
|
54547
54946
|
writeFileSync25(p, body);
|
|
54548
54947
|
files.push(rel);
|
|
54549
54948
|
};
|
|
@@ -54637,8 +55036,8 @@ var init_customer_build = __esm({
|
|
|
54637
55036
|
});
|
|
54638
55037
|
|
|
54639
55038
|
// src/site-analyze/apply.ts
|
|
54640
|
-
import { existsSync as
|
|
54641
|
-
import { dirname as dirname31, isAbsolute as isAbsolute4, join as
|
|
55039
|
+
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";
|
|
55040
|
+
import { dirname as dirname31, isAbsolute as isAbsolute4, join as join57, resolve as resolve45, sep as sep14 } from "node:path";
|
|
54642
55041
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
54643
55042
|
function unpairedRedirectNote(overlay) {
|
|
54644
55043
|
if (!overlay.wix?.clientId || overlay.wix.redirectUri) return void 0;
|
|
@@ -54653,7 +55052,7 @@ function committedShellProvisioning(path2) {
|
|
|
54653
55052
|
function findRepoRoot(cwd) {
|
|
54654
55053
|
let dir = cwd;
|
|
54655
55054
|
for (let i = 0; i < 8; i++) {
|
|
54656
|
-
if (SHELL_NAMES2.some((name) =>
|
|
55055
|
+
if (SHELL_NAMES2.some((name) => existsSync59(join57(dir, shellAppDir(name), "package.json")))) return dir;
|
|
54657
55056
|
const next = dirname31(dir);
|
|
54658
55057
|
if (next === dir) break;
|
|
54659
55058
|
dir = next;
|
|
@@ -54721,11 +55120,11 @@ function mergeCustomerOwned(committed, overlay) {
|
|
|
54721
55120
|
}
|
|
54722
55121
|
function buildMergedContract(options) {
|
|
54723
55122
|
const { appDir: appDir2, packageDir, overlay } = options;
|
|
54724
|
-
const committedPath =
|
|
54725
|
-
if (!
|
|
55123
|
+
const committedPath = join57(appDir2, "provisioning.json");
|
|
55124
|
+
if (!existsSync59(committedPath)) {
|
|
54726
55125
|
throw new Error(`shell has no committed provisioning.json at ${committedPath} to build a contract from`);
|
|
54727
55126
|
}
|
|
54728
|
-
const committed = JSON.parse(
|
|
55127
|
+
const committed = JSON.parse(readFileSync70(committedPath, "utf8"));
|
|
54729
55128
|
const merged = mergeCustomerOwned(committed, overlay);
|
|
54730
55129
|
const overlayFontFamily = (overlay.branding ?? {}).fontFamily;
|
|
54731
55130
|
const branding = merged.branding ?? {};
|
|
@@ -54737,8 +55136,8 @@ function buildMergedContract(options) {
|
|
|
54737
55136
|
};
|
|
54738
55137
|
const stage = (fromRel, toRel) => {
|
|
54739
55138
|
const from = contained(packageDir, fromRel);
|
|
54740
|
-
const to = contained(
|
|
54741
|
-
if (!from || !to || !
|
|
55139
|
+
const to = contained(join57(appDir2, STAGED), toRel.slice(STAGED.length + 1));
|
|
55140
|
+
if (!from || !to || !existsSync59(from)) return void 0;
|
|
54742
55141
|
let real;
|
|
54743
55142
|
let realRoot;
|
|
54744
55143
|
try {
|
|
@@ -54760,11 +55159,11 @@ function buildMergedContract(options) {
|
|
|
54760
55159
|
};
|
|
54761
55160
|
const icon = stage("media/icon.png", `${STAGED}/icon.png`);
|
|
54762
55161
|
if (icon) branding.appIconPath = icon;
|
|
54763
|
-
const facesPath =
|
|
54764
|
-
if (
|
|
55162
|
+
const facesPath = join57(packageDir, "media/fonts/faces.json");
|
|
55163
|
+
if (existsSync59(facesPath)) {
|
|
54765
55164
|
let faces = [];
|
|
54766
55165
|
try {
|
|
54767
|
-
const parsed = JSON.parse(
|
|
55166
|
+
const parsed = JSON.parse(readFileSync70(facesPath, "utf8"));
|
|
54768
55167
|
faces = Array.isArray(parsed) ? parsed : [];
|
|
54769
55168
|
} catch {
|
|
54770
55169
|
faces = [];
|
|
@@ -54785,9 +55184,9 @@ function buildMergedContract(options) {
|
|
|
54785
55184
|
merged.branding = branding;
|
|
54786
55185
|
const body = `${JSON.stringify(merged, null, 2)}
|
|
54787
55186
|
`;
|
|
54788
|
-
const path2 =
|
|
55187
|
+
const path2 = join57(packageDir, "provisioning.contract.json");
|
|
54789
55188
|
writeFileSync26(path2, body);
|
|
54790
|
-
const localPath =
|
|
55189
|
+
const localPath = join57(appDir2, LOCAL_CONTRACT_REL);
|
|
54791
55190
|
mkdirSync29(dirname31(localPath), { recursive: true });
|
|
54792
55191
|
writeFileSync26(localPath, body);
|
|
54793
55192
|
staged.push(localPath);
|
|
@@ -54797,8 +55196,8 @@ async function applyOverlays(input) {
|
|
|
54797
55196
|
const cwd = resolve45(input.cwd);
|
|
54798
55197
|
const shell = input.shell ?? DEFAULT_BRANDABLE_SHELL;
|
|
54799
55198
|
assertKnownShell(shell);
|
|
54800
|
-
const overlay = JSON.parse(
|
|
54801
|
-
const tokens = JSON.parse(
|
|
55199
|
+
const overlay = JSON.parse(readFileSync70(input.overlayPath, "utf8"));
|
|
55200
|
+
const tokens = JSON.parse(readFileSync70(input.tokensPath, "utf8"));
|
|
54802
55201
|
const wrote = [];
|
|
54803
55202
|
const notes = [];
|
|
54804
55203
|
const repoRoot2 = findRepoRoot(cwd);
|
|
@@ -54808,7 +55207,7 @@ async function applyOverlays(input) {
|
|
|
54808
55207
|
`shell "${shell}" cannot bake a customer brand \u2014 it ships no prepare:customer script`
|
|
54809
55208
|
);
|
|
54810
55209
|
}
|
|
54811
|
-
const appDir2 =
|
|
55210
|
+
const appDir2 = join57(repoRoot2, shellAppDir(shell));
|
|
54812
55211
|
const packageDir = dirname31(resolve45(input.overlayPath));
|
|
54813
55212
|
const { path: contract, staged } = buildMergedContract({ appDir: appDir2, packageDir, overlay });
|
|
54814
55213
|
wrote.push(...staged);
|
|
@@ -54830,10 +55229,10 @@ async function applyOverlays(input) {
|
|
|
54830
55229
|
note: `prepare:customer --contract with a merged contract (committed provisioning.json untouched)${unpairedInRepo ? ` \xB7 ${unpairedInRepo}` : ""}`
|
|
54831
55230
|
};
|
|
54832
55231
|
}
|
|
54833
|
-
const pkgProv =
|
|
55232
|
+
const pkgProv = join57(cwd, "provisioning.json");
|
|
54834
55233
|
assertNotCommitted(pkgProv, input.forbiddenProvisioning);
|
|
54835
|
-
if (
|
|
54836
|
-
const cur = JSON.parse(
|
|
55234
|
+
if (existsSync59(pkgProv)) {
|
|
55235
|
+
const cur = JSON.parse(readFileSync70(pkgProv, "utf8"));
|
|
54837
55236
|
const merged = deepMerge4(cur, overlay);
|
|
54838
55237
|
writeFileSync26(pkgProv, JSON.stringify(merged, null, 2) + "\n");
|
|
54839
55238
|
wrote.push(pkgProv);
|
|
@@ -54841,9 +55240,9 @@ async function applyOverlays(input) {
|
|
|
54841
55240
|
writeFileSync26(pkgProv, JSON.stringify(overlay, null, 2) + "\n");
|
|
54842
55241
|
wrote.push(pkgProv);
|
|
54843
55242
|
}
|
|
54844
|
-
const pkgTokens =
|
|
54845
|
-
if (
|
|
54846
|
-
const cur = JSON.parse(
|
|
55243
|
+
const pkgTokens = join57(cwd, "tokens.json");
|
|
55244
|
+
if (existsSync59(pkgTokens) && (tokens.colors || tokens.typography)) {
|
|
55245
|
+
const cur = JSON.parse(readFileSync70(pkgTokens, "utf8"));
|
|
54847
55246
|
const merged = deepMerge4(cur, tokens);
|
|
54848
55247
|
const mergedColors = merged.colors;
|
|
54849
55248
|
if (mergedColors && typeof mergedColors === "object" && !Array.isArray(mergedColors)) {
|
|
@@ -54862,9 +55261,9 @@ async function applyOverlays(input) {
|
|
|
54862
55261
|
wrote.push(pkgTokens);
|
|
54863
55262
|
}
|
|
54864
55263
|
const homeAction = homeRefreshActionId(shell);
|
|
54865
|
-
const homeSrc =
|
|
54866
|
-
if (homeAction &&
|
|
54867
|
-
const prev =
|
|
55264
|
+
const homeSrc = join57(cwd, "dev/index.ts");
|
|
55265
|
+
if (homeAction && existsSync59(homeSrc)) {
|
|
55266
|
+
const prev = readFileSync70(homeSrc, "utf8");
|
|
54868
55267
|
const patched = patchBrandParams(prev, overlay, homeAction);
|
|
54869
55268
|
let next = patched.src;
|
|
54870
55269
|
if (!patched.foreign && overlay.installedVerticals?.length) {
|
|
@@ -54887,13 +55286,13 @@ async function applyOverlays(input) {
|
|
|
54887
55286
|
notes.push(`${patched.unparsed} onAppear params block(s) in ${homeSrc} could not be read \u2014 any brand values inside them were not applied`);
|
|
54888
55287
|
}
|
|
54889
55288
|
}
|
|
54890
|
-
if (!input.iconPath || !
|
|
55289
|
+
if (!input.iconPath || !existsSync59(input.iconPath)) {
|
|
54891
55290
|
const book = input.iconPath ? dirname31(dirname31(resolve45(input.iconPath))) : void 0;
|
|
54892
55291
|
notes.push(
|
|
54893
55292
|
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
55293
|
);
|
|
54895
55294
|
}
|
|
54896
|
-
if (input.iconPath &&
|
|
55295
|
+
if (input.iconPath && existsSync59(input.iconPath)) {
|
|
54897
55296
|
try {
|
|
54898
55297
|
const installed = await installIcon(cwd, input.iconPath, { derivePlay: true });
|
|
54899
55298
|
wrote.push(...installed.wrote);
|
|
@@ -59048,7 +59447,7 @@ __export(cli_exports, {
|
|
|
59048
59447
|
runSiteAnalyze: () => runSiteAnalyze,
|
|
59049
59448
|
runSiteFunctionCli: () => runSiteFunctionCli
|
|
59050
59449
|
});
|
|
59051
|
-
import { readFileSync as
|
|
59450
|
+
import { readFileSync as readFileSync71 } from "node:fs";
|
|
59052
59451
|
import { resolve as resolve46 } from "node:path";
|
|
59053
59452
|
function assetFetchFor(_opts) {
|
|
59054
59453
|
return pinnedFetch2;
|
|
@@ -59135,7 +59534,7 @@ async function runSiteFunctionCli(opts) {
|
|
|
59135
59534
|
let source;
|
|
59136
59535
|
if (opts.sourcePath) {
|
|
59137
59536
|
const p = resolve46(opts.cwd ?? process.cwd(), opts.sourcePath);
|
|
59138
|
-
source =
|
|
59537
|
+
source = readFileSync71(p, "utf8");
|
|
59139
59538
|
}
|
|
59140
59539
|
let body;
|
|
59141
59540
|
if (opts.bodyRaw != null) {
|
|
@@ -59392,7 +59791,7 @@ __export(site_create_exports, {
|
|
|
59392
59791
|
runSiteList: () => runSiteList,
|
|
59393
59792
|
writeProvisioningBinding: () => writeProvisioningBinding
|
|
59394
59793
|
});
|
|
59395
|
-
import { existsSync as
|
|
59794
|
+
import { existsSync as existsSync60, readFileSync as readFileSync72, writeFileSync as writeFileSync27 } from "node:fs";
|
|
59396
59795
|
import { resolve as resolvePath2 } from "node:path";
|
|
59397
59796
|
function oauthClientName(projectName) {
|
|
59398
59797
|
return `${projectName} client`;
|
|
@@ -59541,7 +59940,7 @@ async function runSiteCreate(opts) {
|
|
|
59541
59940
|
if (!wantOauthApp) return { ...base, nextSteps: nextSteps(metaSiteId) };
|
|
59542
59941
|
return { ...base, clientId, redirectUri, nextSteps: nextSteps(metaSiteId, clientId) };
|
|
59543
59942
|
}
|
|
59544
|
-
function writeProvisioningBinding(target, binding2, fs = { existsSync:
|
|
59943
|
+
function writeProvisioningBinding(target, binding2, fs = { existsSync: existsSync60, readFileSync: readFileSync72, writeFileSync: writeFileSync27 }) {
|
|
59545
59944
|
const msid = binding2.siteId;
|
|
59546
59945
|
const path2 = resolvePath2(target);
|
|
59547
59946
|
const committed = committedShellProvisioning(path2);
|
|
@@ -60214,11 +60613,11 @@ var init_context = __esm({
|
|
|
60214
60613
|
});
|
|
60215
60614
|
|
|
60216
60615
|
// src/cli.ts
|
|
60217
|
-
import { mkdtempSync as mkdtempSync4, readFileSync as
|
|
60616
|
+
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
60617
|
import { execFile, execFileSync as execFileSync7, spawnSync as spawnSync5, spawn as spawn6 } from "node:child_process";
|
|
60219
60618
|
import { createHash as createHash27, randomUUID as randomUUID5 } from "node:crypto";
|
|
60220
60619
|
import { tmpdir as tmpdir5, homedir as homedir7, hostname } from "node:os";
|
|
60221
|
-
import { join as
|
|
60620
|
+
import { join as join58, resolve as resolve47, relative as relative10, basename as basename14, dirname as dirname32 } from "node:path";
|
|
60222
60621
|
import { fileURLToPath as fileURLToPath24 } from "node:url";
|
|
60223
60622
|
|
|
60224
60623
|
// ../serve-cli/src/client.ts
|
|
@@ -63494,8 +63893,8 @@ var str6 = (v) => typeof v === "string" ? v : void 0;
|
|
|
63494
63893
|
var num2 = (v) => typeof v === "string" && v !== "" && Number.isFinite(Number(v)) ? Number(v) : void 0;
|
|
63495
63894
|
function embeddedTemplateCatalog() {
|
|
63496
63895
|
return availableTemplates().map((name) => {
|
|
63497
|
-
const path2 =
|
|
63498
|
-
const meta = JSON.parse(
|
|
63896
|
+
const path2 = join58(templateSourceDir(name), TEMPLATE_META_FILE);
|
|
63897
|
+
const meta = JSON.parse(readFileSync73(path2, "utf8"));
|
|
63499
63898
|
if (!meta || typeof meta.title !== "string" || typeof meta.description !== "string" || !Array.isArray(meta.tags)) {
|
|
63500
63899
|
throw new Error(`${path2} must be { title: string, description: string, tags: string[], category?: string }`);
|
|
63501
63900
|
}
|
|
@@ -64164,7 +64563,7 @@ var COMMANDS = [
|
|
|
64164
64563
|
];
|
|
64165
64564
|
function cliVersion() {
|
|
64166
64565
|
try {
|
|
64167
|
-
return JSON.parse(
|
|
64566
|
+
return JSON.parse(readFileSync73(new URL("../package.json", import.meta.url), "utf8")).version ?? "unknown";
|
|
64168
64567
|
} catch {
|
|
64169
64568
|
return "unknown";
|
|
64170
64569
|
}
|
|
@@ -64282,7 +64681,7 @@ function ageInDays(publishedAt, now = Date.now()) {
|
|
|
64282
64681
|
}
|
|
64283
64682
|
function packageVersion(path2) {
|
|
64284
64683
|
try {
|
|
64285
|
-
const version2 = JSON.parse(
|
|
64684
|
+
const version2 = JSON.parse(readFileSync73(path2, "utf8")).version;
|
|
64286
64685
|
return typeof version2 === "string" && version2 ? version2 : void 0;
|
|
64287
64686
|
} catch {
|
|
64288
64687
|
return void 0;
|
|
@@ -64291,7 +64690,7 @@ function packageVersion(path2) {
|
|
|
64291
64690
|
function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("./authoring-runtime/node_modules/@wix/himalaya/package.json", import.meta.url)) {
|
|
64292
64691
|
let dir = resolve47(fromDir);
|
|
64293
64692
|
for (; ; ) {
|
|
64294
|
-
const version2 = packageVersion(
|
|
64693
|
+
const version2 = packageVersion(join58(dir, "node_modules", "@wix", "himalaya", "package.json"));
|
|
64295
64694
|
if (version2) return { version: version2, source: "local" };
|
|
64296
64695
|
const parent = dirname32(dir);
|
|
64297
64696
|
if (parent === dir) break;
|
|
@@ -64301,7 +64700,7 @@ function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("
|
|
|
64301
64700
|
if (bundled) return { version: bundled, source: "bundled" };
|
|
64302
64701
|
try {
|
|
64303
64702
|
const root = execFileSync7("npm", ["root", "-g"], { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
64304
|
-
const version2 = root ? packageVersion(
|
|
64703
|
+
const version2 = root ? packageVersion(join58(root, "@wix", "himalaya", "package.json")) : void 0;
|
|
64305
64704
|
return version2 ? { version: version2, source: "global" } : {};
|
|
64306
64705
|
} catch {
|
|
64307
64706
|
return {};
|
|
@@ -64348,11 +64747,11 @@ var UPDATE_RETRY_AFTER_FAILURE_MS = 60 * 60 * 1e3;
|
|
|
64348
64747
|
var UPDATE_SNOOZE_MS = 24 * 60 * 60 * 1e3;
|
|
64349
64748
|
var UPDATE_REEXEC_ENV = "HIMI_UPDATED_ONCE";
|
|
64350
64749
|
function updateCachePath(env = process.env) {
|
|
64351
|
-
return env.HIMI_UPDATE_CACHE_FILE ??
|
|
64750
|
+
return env.HIMI_UPDATE_CACHE_FILE ?? join58(homedir7(), ".himalaya", "update-check.json");
|
|
64352
64751
|
}
|
|
64353
64752
|
function readUpdateCache(path2) {
|
|
64354
64753
|
try {
|
|
64355
|
-
const parsed = JSON.parse(
|
|
64754
|
+
const parsed = JSON.parse(readFileSync73(path2, "utf8"));
|
|
64356
64755
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
64357
64756
|
} catch {
|
|
64358
64757
|
return {};
|
|
@@ -64420,12 +64819,12 @@ function createUpdateRunner(spawn7 = spawnSync5) {
|
|
|
64420
64819
|
},
|
|
64421
64820
|
installedVersion: () => {
|
|
64422
64821
|
const root = globalNodeModulesRoot();
|
|
64423
|
-
return root ? packageVersion(
|
|
64822
|
+
return root ? packageVersion(join58(root, "@wix", "himalaya-cli", "package.json")) : void 0;
|
|
64424
64823
|
},
|
|
64425
64824
|
reexec: (argv) => {
|
|
64426
64825
|
const root = globalNodeModulesRoot();
|
|
64427
|
-
const entry = root ?
|
|
64428
|
-
if (!entry || !
|
|
64826
|
+
const entry = root ? join58(root, "@wix", "himalaya-cli", "dist", "cli.mjs") : void 0;
|
|
64827
|
+
if (!entry || !existsSync61(entry)) return void 0;
|
|
64429
64828
|
const result = spawnSync5(process.execPath, [entry, ...argv], {
|
|
64430
64829
|
// inherit keeps PIPED STDIN working — commands that read stdin must survive a re-exec.
|
|
64431
64830
|
stdio: "inherit",
|
|
@@ -64472,7 +64871,7 @@ function staleUpdateLockFile(cachePath, now) {
|
|
|
64472
64871
|
for (const path2 of [`${cachePath}.lock.break`, `${cachePath}.lock`]) {
|
|
64473
64872
|
let content;
|
|
64474
64873
|
try {
|
|
64475
|
-
content =
|
|
64874
|
+
content = readFileSync73(path2, "utf8");
|
|
64476
64875
|
} catch {
|
|
64477
64876
|
continue;
|
|
64478
64877
|
}
|
|
@@ -64495,7 +64894,7 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
|
|
|
64495
64894
|
const mine = lockStamp(now);
|
|
64496
64895
|
const readLock = (path2) => {
|
|
64497
64896
|
try {
|
|
64498
|
-
return
|
|
64897
|
+
return readFileSync73(path2, "utf8");
|
|
64499
64898
|
} catch {
|
|
64500
64899
|
return void 0;
|
|
64501
64900
|
}
|
|
@@ -64792,9 +65191,9 @@ function diagnoseBody(body) {
|
|
|
64792
65191
|
const out = {};
|
|
64793
65192
|
const emptied = [];
|
|
64794
65193
|
for (const [key2, value] of Object.entries(body)) {
|
|
64795
|
-
const
|
|
64796
|
-
if (
|
|
64797
|
-
out[key2] =
|
|
65194
|
+
const fold2 = (key2 === "issues" || key2 === "failures" || key2 === "warnings") && folded(value);
|
|
65195
|
+
if (fold2) emptied.push(key2);
|
|
65196
|
+
out[key2] = fold2 ? [] : value;
|
|
64798
65197
|
}
|
|
64799
65198
|
if (emptied.length) out.foldedIntoFindings = emptied;
|
|
64800
65199
|
return out;
|
|
@@ -65033,7 +65432,7 @@ function executableOnPath(name, env = process.env) {
|
|
|
65033
65432
|
const suffixes = process.platform === "win32" ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
|
|
65034
65433
|
for (const dir of entries) {
|
|
65035
65434
|
for (const suffix of suffixes) {
|
|
65036
|
-
const candidate =
|
|
65435
|
+
const candidate = join58(dir, `${name}${suffix}`);
|
|
65037
65436
|
try {
|
|
65038
65437
|
if (!statSync17(candidate).isFile()) continue;
|
|
65039
65438
|
if (process.platform !== "win32") accessSync(candidate, constants2.X_OK);
|
|
@@ -65142,7 +65541,7 @@ async function nativeConfigAdvisories(app, configSource) {
|
|
|
65142
65541
|
const { iosProjectYml: iosProjectYml2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
65143
65542
|
const { androidOptedIn: androidOptedIn3, LABEL_IOS_SPLASH: LABEL_IOS_SPLASH2 } = await Promise.resolve().then(() => (init_splash(), splash_exports));
|
|
65144
65543
|
const iosYmlPath = iosProjectYml2(app);
|
|
65145
|
-
const iosYml =
|
|
65544
|
+
const iosYml = existsSync61(iosYmlPath) ? readFileSync73(iosYmlPath, "utf8") : "";
|
|
65146
65545
|
let optedIn = iosYml.includes(LABEL_IOS_SPLASH2);
|
|
65147
65546
|
if (!optedIn) {
|
|
65148
65547
|
const { androidManifestPath: androidManifestPath3 } = await Promise.resolve().then(() => (init_gen_native_config(), gen_native_config_exports));
|
|
@@ -65156,7 +65555,7 @@ async function nativeConfigAdvisories(app, configSource) {
|
|
|
65156
65555
|
}
|
|
65157
65556
|
function readConfigSource(dir) {
|
|
65158
65557
|
try {
|
|
65159
|
-
return
|
|
65558
|
+
return readFileSync73(join58(dir, "config.ts"), "utf8");
|
|
65160
65559
|
} catch {
|
|
65161
65560
|
return null;
|
|
65162
65561
|
}
|
|
@@ -65168,7 +65567,7 @@ function writePngFile(path2, base64) {
|
|
|
65168
65567
|
}
|
|
65169
65568
|
async function initFromRemoteTemplate(name, parentDir, template, c) {
|
|
65170
65569
|
const dir = resolve47(parentDir, name);
|
|
65171
|
-
if (
|
|
65570
|
+
if (existsSync61(join58(dir, "himalaya.content.json"))) {
|
|
65172
65571
|
throw new Error(`content package already exists at ${dir}`);
|
|
65173
65572
|
}
|
|
65174
65573
|
const r = await c.fetchTemplateSource(TEMPLATE_APP_PREFIX + template);
|
|
@@ -65211,7 +65610,7 @@ function symlinkDestinationIssue(dest) {
|
|
|
65211
65610
|
function restoreDestinationIssue(dest, force) {
|
|
65212
65611
|
const link = symlinkDestinationIssue(dest);
|
|
65213
65612
|
if (link) return link;
|
|
65214
|
-
if (!
|
|
65613
|
+
if (!existsSync61(dest)) return null;
|
|
65215
65614
|
if (!statSync17(dest).isDirectory()) {
|
|
65216
65615
|
return { error: `${dest} exists and is not a directory`, hint: "pass --out/--name to land somewhere else, or remove the file" };
|
|
65217
65616
|
}
|
|
@@ -65226,7 +65625,7 @@ function restoreDestinationIssue(dest, force) {
|
|
|
65226
65625
|
function isHimalayaMonorepoCheckout(start) {
|
|
65227
65626
|
let dir = resolve47(start);
|
|
65228
65627
|
for (; ; ) {
|
|
65229
|
-
if (
|
|
65628
|
+
if (existsSync61(join58(dir, "tools", "himi-cli", "src", "cli.ts")) && existsSync61(join58(dir, "core", "serve", "src", "server.ts"))) return true;
|
|
65230
65629
|
const parent = dirname32(dir);
|
|
65231
65630
|
if (parent === dir) return false;
|
|
65232
65631
|
dir = parent;
|
|
@@ -65269,7 +65668,7 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
65269
65668
|
Object.entries(files).map(([rel, body]) => [rel, rel === "himalaya.content.json" ? substituteIdentity(body, slug) : body])
|
|
65270
65669
|
);
|
|
65271
65670
|
const repoRoot2 = resolve47(fileURLToPath24(new URL("../../..", import.meta.url)));
|
|
65272
|
-
const root =
|
|
65671
|
+
const root = join58(repoRoot2, "node_modules", ".cache", "himi-template-preview");
|
|
65273
65672
|
const stillRunning = (pid) => {
|
|
65274
65673
|
try {
|
|
65275
65674
|
process.kill(pid, 0);
|
|
@@ -65283,12 +65682,12 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
65283
65682
|
if (!entry.isDirectory()) continue;
|
|
65284
65683
|
const pid = Number(entry.name.startsWith(`${slug}-`) ? entry.name.slice(slug.length + 1) : NaN);
|
|
65285
65684
|
if (Number.isInteger(pid) && pid > 0 && pid !== process.pid && !stillRunning(pid)) {
|
|
65286
|
-
rmSync14(
|
|
65685
|
+
rmSync14(join58(root, entry.name), { recursive: true, force: true });
|
|
65287
65686
|
}
|
|
65288
65687
|
}
|
|
65289
65688
|
} catch {
|
|
65290
65689
|
}
|
|
65291
|
-
const dest =
|
|
65690
|
+
const dest = join58(root, `${slug}-${process.pid}`);
|
|
65292
65691
|
rmSync14(dest, { recursive: true, force: true });
|
|
65293
65692
|
mkdirSync30(dest, { recursive: true });
|
|
65294
65693
|
materializeSource(forBuild, displayName, dest, slug);
|
|
@@ -65296,8 +65695,8 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
65296
65695
|
}
|
|
65297
65696
|
async function appId(dir) {
|
|
65298
65697
|
try {
|
|
65299
|
-
const { readFileSync:
|
|
65300
|
-
const m = JSON.parse(
|
|
65698
|
+
const { readFileSync: readFileSync74 } = await import("node:fs");
|
|
65699
|
+
const m = JSON.parse(readFileSync74(join58(dir, "himalaya.content.json"), "utf8"));
|
|
65301
65700
|
if (m.name) return m.name;
|
|
65302
65701
|
} catch {
|
|
65303
65702
|
}
|
|
@@ -65305,8 +65704,8 @@ async function appId(dir) {
|
|
|
65305
65704
|
}
|
|
65306
65705
|
async function contentVisibility(dir) {
|
|
65307
65706
|
try {
|
|
65308
|
-
const { readFileSync:
|
|
65309
|
-
const m = JSON.parse(
|
|
65707
|
+
const { readFileSync: readFileSync74 } = await import("node:fs");
|
|
65708
|
+
const m = JSON.parse(readFileSync74(join58(dir, "himalaya.content.json"), "utf8"));
|
|
65310
65709
|
if (m.visibility === "public" || m.visibility === "unlisted") return m.visibility;
|
|
65311
65710
|
} catch {
|
|
65312
65711
|
}
|
|
@@ -65530,7 +65929,7 @@ async function recordedReleaseForContentQuietly(dir, resolution, onDrift) {
|
|
|
65530
65929
|
try {
|
|
65531
65930
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
65532
65931
|
const bres = await buildContentForValidation2(dir, { resolution });
|
|
65533
|
-
out = mkdtempSync4(
|
|
65932
|
+
out = mkdtempSync4(join58(tmpdir5(), "himi-ux-record-"));
|
|
65534
65933
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
65535
65934
|
const outcome = await buildReleaseFromContent2(dir, out, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {}, collect: { lint: true } });
|
|
65536
65935
|
const releaseId = outcome.manifest.releaseId;
|
|
@@ -65708,7 +66107,7 @@ async function producedWidgetFamilies(dir) {
|
|
|
65708
66107
|
let js;
|
|
65709
66108
|
for (const candidate of [`${name}.bundle.js`, `${name}.js`, name]) {
|
|
65710
66109
|
try {
|
|
65711
|
-
js =
|
|
66110
|
+
js = readFileSync73(join58(outDir, candidate), "utf8");
|
|
65712
66111
|
break;
|
|
65713
66112
|
} catch {
|
|
65714
66113
|
}
|
|
@@ -65739,7 +66138,7 @@ async function producedWidgetFamilies(dir) {
|
|
|
65739
66138
|
}
|
|
65740
66139
|
return { families, source: "dist/bundles" };
|
|
65741
66140
|
}
|
|
65742
|
-
var boardOpen = (dir) =>
|
|
66141
|
+
var boardOpen = (dir) => existsSync61(join58(dir, ".himi", "studio", "index.html"));
|
|
65743
66142
|
var BOARD_REFRESHERS = /* @__PURE__ */ new Set(["render", "test", "validate", "build", "push", "icon", "site", "ux", "progress"]);
|
|
65744
66143
|
async function leaveForBoard(dir, record2, value) {
|
|
65745
66144
|
if (!boardOpen(dir)) return;
|
|
@@ -66127,7 +66526,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66127
66526
|
const sourceDir = resolve47(str6(flags["source-dir"]) ?? appDir2);
|
|
66128
66527
|
let meta;
|
|
66129
66528
|
try {
|
|
66130
|
-
meta = JSON.parse(
|
|
66529
|
+
meta = JSON.parse(readFileSync73(join58(sourceDir, TEMPLATE_META_FILE), "utf8"));
|
|
66131
66530
|
} catch {
|
|
66132
66531
|
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
66532
|
return 2;
|
|
@@ -66137,7 +66536,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66137
66536
|
return 2;
|
|
66138
66537
|
}
|
|
66139
66538
|
try {
|
|
66140
|
-
const appearance = extractTemplateAppearance(JSON.parse(
|
|
66539
|
+
const appearance = extractTemplateAppearance(JSON.parse(readFileSync73(join58(sourceDir, "tokens.json"), "utf8")));
|
|
66141
66540
|
meta = { ...appearance, ...meta };
|
|
66142
66541
|
} catch {
|
|
66143
66542
|
}
|
|
@@ -66149,7 +66548,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66149
66548
|
const force = flags.force === true;
|
|
66150
66549
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
66151
66550
|
const bres = await buildContentForValidation2(buildDir, { resolution: resolutionFlag(flags) });
|
|
66152
|
-
const out = mkdtempSync4(
|
|
66551
|
+
const out = mkdtempSync4(join58(tmpdir5(), "himi-template-"));
|
|
66153
66552
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
66154
66553
|
const outcome = await buildReleaseFromContent2(buildDir, out, {
|
|
66155
66554
|
...hasWorkers ? { tier5Dir: bundleOutDir2(buildDir) } : {},
|
|
@@ -66202,7 +66601,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66202
66601
|
let iconHash;
|
|
66203
66602
|
if (iconPath) {
|
|
66204
66603
|
try {
|
|
66205
|
-
const bytes2 =
|
|
66604
|
+
const bytes2 = readFileSync73(iconPath);
|
|
66206
66605
|
payload.icon = bytes2.toString("base64");
|
|
66207
66606
|
iconHash = createHash27("sha256").update(bytes2).digest("hex");
|
|
66208
66607
|
} catch {
|
|
@@ -66435,7 +66834,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66435
66834
|
const { navIssues: navIssues2 } = await Promise.resolve().then(() => (init_nav_lint(), nav_lint_exports));
|
|
66436
66835
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
66437
66836
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
66438
|
-
const out = mkdtempSync4(
|
|
66837
|
+
const out = mkdtempSync4(join58(tmpdir5(), "himi-validate-"));
|
|
66439
66838
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
66440
66839
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
66441
66840
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -66478,7 +66877,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66478
66877
|
const path2 = dpxSessionTokenPath();
|
|
66479
66878
|
let raw;
|
|
66480
66879
|
try {
|
|
66481
|
-
raw =
|
|
66880
|
+
raw = readFileSync73(path2, "utf8");
|
|
66482
66881
|
} catch {
|
|
66483
66882
|
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
66883
|
}
|
|
@@ -66598,13 +66997,13 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66598
66997
|
case "studio": {
|
|
66599
66998
|
const { openStudio: openStudio2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
|
|
66600
66999
|
const dir = contentDir(flags);
|
|
66601
|
-
if (!
|
|
67000
|
+
if (!existsSync61(join58(dir, "himalaya.content.json"))) {
|
|
66602
67001
|
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
67002
|
return 2;
|
|
66604
67003
|
}
|
|
66605
67004
|
if (pos[1] === "reel") {
|
|
66606
67005
|
const { buildReel: buildReel2 } = await Promise.resolve().then(() => (init_studio_reel(), studio_reel_exports));
|
|
66607
|
-
const out = resolve47(str6(flags.out) ??
|
|
67006
|
+
const out = resolve47(str6(flags.out) ?? join58(dir, ".himi", "making-of.html"));
|
|
66608
67007
|
const { html, plan } = buildReel2(dir);
|
|
66609
67008
|
mkdirSync30(dirname32(out), { recursive: true });
|
|
66610
67009
|
writeFileSync28(out, html);
|
|
@@ -66654,7 +67053,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66654
67053
|
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
67054
|
const dir = contentDir(flags);
|
|
66656
67055
|
const journal = journalPath2(dir);
|
|
66657
|
-
const hint =
|
|
67056
|
+
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
67057
|
const message = pos.slice(1).join(" ").trim();
|
|
66659
67058
|
if (!message) {
|
|
66660
67059
|
if (flags.step !== void 0 || flags.image !== void 0 || flags.notify === true) {
|
|
@@ -66746,7 +67145,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66746
67145
|
case "test": {
|
|
66747
67146
|
const dir = contentDir(flags);
|
|
66748
67147
|
const structuredOutput = flags.json === true || io.isTTY !== true;
|
|
66749
|
-
if (
|
|
67148
|
+
if (existsSync61(join58(dir, "functions"))) {
|
|
66750
67149
|
const { invokeLocalFunction: invokeLocalFunction2, loadFunctionsApp: loadFunctionsApp2 } = await Promise.resolve().then(() => (init_functions(), functions_exports));
|
|
66751
67150
|
const loaded = await loadFunctionsApp2(dir);
|
|
66752
67151
|
const results = [];
|
|
@@ -66833,7 +67232,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66833
67232
|
}
|
|
66834
67233
|
}
|
|
66835
67234
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
66836
|
-
const out = mkdtempSync4(
|
|
67235
|
+
const out = mkdtempSync4(join58(tmpdir5(), "himi-test-"));
|
|
66837
67236
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
66838
67237
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
66839
67238
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -66878,7 +67277,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66878
67277
|
io.error(JSON.stringify({ error: `screen "${screen.screenId}" has no Tier-5 worker, so there is nothing for the browser loop to build` }));
|
|
66879
67278
|
return 2;
|
|
66880
67279
|
}
|
|
66881
|
-
const sources = collectWorkerSources2(
|
|
67280
|
+
const sources = collectWorkerSources2(join58(dir, "tier5-src"), screen.bundleName);
|
|
66882
67281
|
if (!sources) {
|
|
66883
67282
|
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
67283
|
return 2;
|
|
@@ -67039,7 +67438,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67039
67438
|
const sp = await runShotsPass2({
|
|
67040
67439
|
descriptors: scopeDescriptors2(outcome.descriptors ?? [], pos.slice(1), invalidScreens),
|
|
67041
67440
|
tokens: outcome.tokens,
|
|
67042
|
-
outDir:
|
|
67441
|
+
outDir: join58(dir, ".himi", "shots"),
|
|
67043
67442
|
width: 390,
|
|
67044
67443
|
layers: { rules: shotRules, ...cmsSeed ? { cmsSeed } : {}, ...canned ? { canned: canned.byKey } : {} },
|
|
67045
67444
|
...budgetMs ? { budgetMs } : {},
|
|
@@ -67077,7 +67476,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67077
67476
|
releaseId: result.releaseId,
|
|
67078
67477
|
releasePayload: release,
|
|
67079
67478
|
descriptors: attestedDescriptors,
|
|
67080
|
-
screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""),
|
|
67479
|
+
screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""), join58(dir, ".himi", "shots", name)])),
|
|
67081
67480
|
coverage: {
|
|
67082
67481
|
screens: crawledScreens.size,
|
|
67083
67482
|
actionsDispatched: result.actions.exercised,
|
|
@@ -67167,7 +67566,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67167
67566
|
return 2;
|
|
67168
67567
|
}
|
|
67169
67568
|
try {
|
|
67170
|
-
const raw = stateArg.trim().startsWith("{") ? stateArg :
|
|
67569
|
+
const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync73(stateArg.replace(/^@/, ""), "utf8");
|
|
67171
67570
|
injectedState = JSON.parse(raw);
|
|
67172
67571
|
} catch (e) {
|
|
67173
67572
|
io.error(JSON.stringify({ error: `--state must be inline JSON or a path to a .json file \u2014 ${e.message}` }));
|
|
@@ -67182,7 +67581,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67182
67581
|
return 2;
|
|
67183
67582
|
}
|
|
67184
67583
|
try {
|
|
67185
|
-
const raw = inputArg.trim().startsWith("{") ? inputArg :
|
|
67584
|
+
const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync73(inputArg.replace(/^@/, ""), "utf8");
|
|
67186
67585
|
const parsed = JSON.parse(raw);
|
|
67187
67586
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("must be a JSON object");
|
|
67188
67587
|
injectedInput = parsed;
|
|
@@ -67231,7 +67630,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67231
67630
|
}
|
|
67232
67631
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
67233
67632
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
67234
|
-
const out = mkdtempSync4(
|
|
67633
|
+
const out = mkdtempSync4(join58(tmpdir5(), "himi-render-"));
|
|
67235
67634
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
67236
67635
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
67237
67636
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -67245,7 +67644,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67245
67644
|
const diagnostics = (outcome.lint ?? []).find((s) => s.screenId === screenId)?.issues ?? [];
|
|
67246
67645
|
let pngFile;
|
|
67247
67646
|
let attestationPngFile;
|
|
67248
|
-
const shotPath =
|
|
67647
|
+
const shotPath = join58(dir, ".himi", "shots", `${screenId}.png`);
|
|
67249
67648
|
const pngTarget = typeof flags.png === "string" ? str6(flags.png) : flags.png === true ? shotPath : void 0;
|
|
67250
67649
|
if (pngTarget && r.pngBase64) {
|
|
67251
67650
|
pngFile = writePngFile(pngTarget, r.pngBase64);
|
|
@@ -67581,7 +67980,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
67581
67980
|
io.error(JSON.stringify(linked));
|
|
67582
67981
|
return 1;
|
|
67583
67982
|
}
|
|
67584
|
-
if (
|
|
67983
|
+
if (existsSync61(dest)) {
|
|
67585
67984
|
if (!statSync17(dest).isDirectory()) {
|
|
67586
67985
|
io.error(JSON.stringify({
|
|
67587
67986
|
error: `${dest} exists and is not a directory`,
|
|
@@ -67594,7 +67993,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
67594
67993
|
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
67994
|
return 1;
|
|
67596
67995
|
}
|
|
67597
|
-
if (replace && occupied && !
|
|
67996
|
+
if (replace && occupied && !existsSync61(join58(dest, "himalaya.content.json"))) {
|
|
67598
67997
|
io.error(JSON.stringify({
|
|
67599
67998
|
error: `${dest} is not a content package \u2014 refusing to --replace it`,
|
|
67600
67999
|
hint: "--replace only clears a directory that holds himalaya.content.json. Check --out/--name, or pass --force to merge into it instead."
|
|
@@ -67733,7 +68132,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
67733
68132
|
const force = flags.force === true;
|
|
67734
68133
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
67735
68134
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
67736
|
-
const out = mkdtempSync4(
|
|
68135
|
+
const out = mkdtempSync4(join58(tmpdir5(), "himi-push-"));
|
|
67737
68136
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
67738
68137
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
67739
68138
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -68254,7 +68653,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68254
68653
|
}
|
|
68255
68654
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
68256
68655
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
68257
|
-
const built = mkdtempSync4(
|
|
68656
|
+
const built = mkdtempSync4(join58(tmpdir5(), "himi-pack-"));
|
|
68258
68657
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
68259
68658
|
const outcome = await buildReleaseFromContent2(dir, built, {
|
|
68260
68659
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -68457,7 +68856,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68457
68856
|
}));
|
|
68458
68857
|
return 1;
|
|
68459
68858
|
}
|
|
68460
|
-
const archive =
|
|
68859
|
+
const archive = readFileSync73(resolve47(file));
|
|
68461
68860
|
const result = await client2().createPackageShare({
|
|
68462
68861
|
app: opened.header.app,
|
|
68463
68862
|
releaseId: opened.header.releaseId,
|
|
@@ -68511,11 +68910,11 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68511
68910
|
const app = await appId(dir2);
|
|
68512
68911
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
68513
68912
|
const bres = await buildContentBundles2(dir2, { resolution: resolutionFlag(flags) });
|
|
68514
|
-
temp = mkdtempSync4(
|
|
68913
|
+
temp = mkdtempSync4(join58(tmpdir5(), "himi-run-build-"));
|
|
68515
68914
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
68516
68915
|
const initial = await buildReleaseFromContent2(dir2, temp, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir2) } : {} });
|
|
68517
68916
|
servedMissing = initial.missingBundles;
|
|
68518
|
-
source =
|
|
68917
|
+
source = join58(temp, app);
|
|
68519
68918
|
}
|
|
68520
68919
|
const chromeArg = str6(flags.chrome) ?? "preview";
|
|
68521
68920
|
if (chromeArg !== "preview" && chromeArg !== "app") {
|
|
@@ -68551,7 +68950,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68551
68950
|
if (!recordKit) return;
|
|
68552
68951
|
startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
68553
68952
|
const failure = record2(served2, { ok: true, at: startedAt });
|
|
68554
|
-
if (!recorded) io.error(JSON.stringify({ run: "run_record_skipped", message: `${failure ?? `${
|
|
68953
|
+
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
68954
|
await refreshBoard();
|
|
68556
68955
|
};
|
|
68557
68956
|
const retract = async () => {
|
|
@@ -68582,7 +68981,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68582
68981
|
}
|
|
68583
68982
|
const watchKit = watch2 ? await Promise.resolve().then(() => (init_run_watch(), run_watch_exports)) : null;
|
|
68584
68983
|
const bus = watchKit ? new watchKit.ReloadBus() : void 0;
|
|
68585
|
-
if (watch2) served = mkdtempSync4(
|
|
68984
|
+
if (watch2) served = mkdtempSync4(join58(tmpdir5(), "himi-run-served-"));
|
|
68586
68985
|
const running = await runPackage2(source, {
|
|
68587
68986
|
port,
|
|
68588
68987
|
chrome: chromeArg,
|
|
@@ -68594,15 +68993,15 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68594
68993
|
...recordKit ? { extraRoutes: (request) => recordKit.boardFile(dir, new URL(request.url).pathname) } : {},
|
|
68595
68994
|
...watchKit && served && bus ? { workDir: served, screenEvents: bus } : {}
|
|
68596
68995
|
});
|
|
68597
|
-
let
|
|
68996
|
+
let watcher2;
|
|
68598
68997
|
let rebuild;
|
|
68599
68998
|
let stopping = false;
|
|
68600
68999
|
try {
|
|
68601
69000
|
await announce(running);
|
|
68602
69001
|
if (watchKit && bus) {
|
|
68603
69002
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
68604
|
-
const live2 =
|
|
68605
|
-
const manifestOf = (tree) => JSON.parse(
|
|
69003
|
+
const live2 = join58(running.releaseRoot, running.app);
|
|
69004
|
+
const manifestOf = (tree) => JSON.parse(readFileSync73(join58(tree, "release-manifest.json"), "utf8"));
|
|
68606
69005
|
let current = manifestOf(live2);
|
|
68607
69006
|
const failed2 = async (message) => {
|
|
68608
69007
|
if (stopping) return;
|
|
@@ -68613,7 +69012,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68613
69012
|
};
|
|
68614
69013
|
rebuild = watchKit.serialize(async () => {
|
|
68615
69014
|
const t0 = Date.now();
|
|
68616
|
-
const next = mkdtempSync4(
|
|
69015
|
+
const next = mkdtempSync4(join58(tmpdir5(), "himi-run-build-"));
|
|
68617
69016
|
try {
|
|
68618
69017
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
68619
69018
|
if (bres.compileErrors.length) {
|
|
@@ -68630,14 +69029,14 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68630
69029
|
return;
|
|
68631
69030
|
}
|
|
68632
69031
|
if (stopping) return;
|
|
68633
|
-
const fresh = manifestOf(
|
|
69032
|
+
const fresh = manifestOf(join58(next, running.app));
|
|
68634
69033
|
const diff = watchKit.diffReleases(current, fresh);
|
|
68635
69034
|
const retired = `${live2}.retired-${Date.now()}`;
|
|
68636
69035
|
renameSync6(live2, retired);
|
|
68637
69036
|
try {
|
|
68638
|
-
renameSync6(
|
|
69037
|
+
renameSync6(join58(next, running.app), live2);
|
|
68639
69038
|
} catch {
|
|
68640
|
-
cpSync3(
|
|
69039
|
+
cpSync3(join58(next, running.app), live2, { recursive: true });
|
|
68641
69040
|
}
|
|
68642
69041
|
rmSync14(retired, { recursive: true, force: true });
|
|
68643
69042
|
current = fresh;
|
|
@@ -68652,7 +69051,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68652
69051
|
rmSync14(next, { recursive: true, force: true });
|
|
68653
69052
|
}
|
|
68654
69053
|
});
|
|
68655
|
-
|
|
69054
|
+
watcher2 = watchKit.watchContent(dir, () => rebuild?.());
|
|
68656
69055
|
}
|
|
68657
69056
|
} catch (e) {
|
|
68658
69057
|
await retract().catch(() => {
|
|
@@ -68674,7 +69073,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68674
69073
|
await new Promise((done) => {
|
|
68675
69074
|
const stop = async () => {
|
|
68676
69075
|
stopping = true;
|
|
68677
|
-
|
|
69076
|
+
watcher2?.close();
|
|
68678
69077
|
try {
|
|
68679
69078
|
await rebuild?.stop();
|
|
68680
69079
|
await retract();
|
|
@@ -69235,7 +69634,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69235
69634
|
io.error(JSON.stringify({ error: `patch ${kind} needs --file`, usage: PATCH_USAGE }));
|
|
69236
69635
|
return 2;
|
|
69237
69636
|
}
|
|
69238
|
-
if (!
|
|
69637
|
+
if (!existsSync61(file)) {
|
|
69239
69638
|
io.error(JSON.stringify({ error: `no such file: ${file}` }));
|
|
69240
69639
|
return 2;
|
|
69241
69640
|
}
|
|
@@ -69291,7 +69690,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69291
69690
|
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
69691
|
};
|
|
69293
69692
|
if (kind === "tokens" || kind === "app-config") {
|
|
69294
|
-
const body =
|
|
69693
|
+
const body = readFileSync73(file, "utf8");
|
|
69295
69694
|
const patch2 = kind === "tokens" ? { tokens: body } : { appConfig: body };
|
|
69296
69695
|
return runReleasePatch({
|
|
69297
69696
|
...common,
|
|
@@ -69306,7 +69705,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69306
69705
|
io.error(JSON.stringify({ error: "patch screen needs a <screenId>", usage: PATCH_USAGE }));
|
|
69307
69706
|
return 2;
|
|
69308
69707
|
}
|
|
69309
|
-
const descriptor =
|
|
69708
|
+
const descriptor = readFileSync73(file, "utf8");
|
|
69310
69709
|
try {
|
|
69311
69710
|
JSON.parse(descriptor);
|
|
69312
69711
|
} catch (e) {
|
|
@@ -69346,7 +69745,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69346
69745
|
extra: { kind, screen: id, file: { path: file, bytes: Buffer.byteLength(descriptor, "utf8") } }
|
|
69347
69746
|
});
|
|
69348
69747
|
}
|
|
69349
|
-
const bytes2 =
|
|
69748
|
+
const bytes2 = readFileSync73(file);
|
|
69350
69749
|
const sha = createHash27("sha256").update(bytes2).digest("hex");
|
|
69351
69750
|
const forScreens = (str6(flags["for-screen"]) ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
69352
69751
|
if (flags["no-rebind"] !== void 0 && flags["no-rebind"] !== true) {
|
|
@@ -69490,7 +69889,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69490
69889
|
}
|
|
69491
69890
|
let def;
|
|
69492
69891
|
try {
|
|
69493
|
-
const parsed = JSON.parse(arg.startsWith("@") ?
|
|
69892
|
+
const parsed = JSON.parse(arg.startsWith("@") ? readFileSync73(arg.slice(1), "utf8") : arg);
|
|
69494
69893
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
69495
69894
|
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
69895
|
return 2;
|
|
@@ -69954,7 +70353,7 @@ ${label2}`);
|
|
|
69954
70353
|
const platform = str6(flags.platform)?.split(",").map((p) => p.trim()).filter(Boolean);
|
|
69955
70354
|
{
|
|
69956
70355
|
const distDir = contentDir(flags);
|
|
69957
|
-
if (
|
|
70356
|
+
if (existsSync61(join58(distDir, "himalaya.content.json"))) {
|
|
69958
70357
|
const issues = await iconIssues(distDir, flags.strict === true, { requireDeclared: true, requireVerified: true });
|
|
69959
70358
|
const errors = issues.filter((i) => i.severity === "error");
|
|
69960
70359
|
for (const i of issues.filter((i2) => i2.severity === "warning")) {
|
|
@@ -70223,7 +70622,7 @@ ${label2}`);
|
|
|
70223
70622
|
const dpxPath = dpxSessionTokenPath();
|
|
70224
70623
|
let dpx;
|
|
70225
70624
|
try {
|
|
70226
|
-
dpx =
|
|
70625
|
+
dpx = readFileSync73(dpxPath, "utf8").trim();
|
|
70227
70626
|
} catch {
|
|
70228
70627
|
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
70628
|
return 1;
|
|
@@ -70625,7 +71024,7 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
|
|
|
70625
71024
|
const path2 = dpxSessionTokenPath();
|
|
70626
71025
|
let raw;
|
|
70627
71026
|
try {
|
|
70628
|
-
raw =
|
|
71027
|
+
raw = readFileSync73(path2, "utf8");
|
|
70629
71028
|
} catch {
|
|
70630
71029
|
io.error(JSON.stringify({ error: `no DPX BO session at ${path2}` }));
|
|
70631
71030
|
return 1;
|