@wix/himalaya-cli 0.1059.0 → 0.1061.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/app-config.d.ts +11 -4
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/wix-platform/src/index.d.ts +3 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-platform.mjs +3 -8
- package/dist/cli.mjs +992 -542
- package/guides/headless-loop.md +6 -1
- package/guides/himi-test.md +17 -0
- package/guides/sdk-reference.json +1 -1
- package/guides/wix-platform-usage.md +14 -9
- package/package.json +2 -2
- package/templates/surface-showcase/dev/index.ts +3 -1
package/dist/cli.mjs
CHANGED
|
@@ -2699,7 +2699,7 @@ function isAttestationV2(value) {
|
|
|
2699
2699
|
const a = value;
|
|
2700
2700
|
const coverage = a.coverage;
|
|
2701
2701
|
const report2 = a.report;
|
|
2702
|
-
return a.attestation === 2 && typeof a.runId === "string" && ["himi-test", "himi-render", "himi-shots"].includes(a.tool) && [a.app, a.contentDir, a.gitDiffHash, a.gitUntrackedHash, a.releaseId, a.releaseHash, a.selfHash].every((item) => typeof item === "string" && item.length > 0) && stringRecord(a.descriptorHashes) && stringRecord(a.screenshots) && !!coverage && [coverage.screens, coverage.actionsDispatched, coverage.uncoveredFns, coverage.gaps].every((
|
|
2702
|
+
return a.attestation === 2 && typeof a.runId === "string" && ["himi-test", "himi-render", "himi-shots"].includes(a.tool) && [a.app, a.contentDir, a.gitDiffHash, a.gitUntrackedHash, a.releaseId, a.releaseHash, a.selfHash].every((item) => typeof item === "string" && item.length > 0) && stringRecord(a.descriptorHashes) && stringRecord(a.screenshots) && !!coverage && [coverage.screens, coverage.actionsDispatched, coverage.uncoveredFns, coverage.gaps].every((count2) => typeof count2 === "number" && Number.isFinite(count2) && count2 >= 0) && typeof report2?.ok === "boolean" && !!report2.counts && [report2.counts.errors, report2.counts.warnings, report2.counts.gaps].every((count2) => typeof count2 === "number" && Number.isFinite(count2) && count2 >= 0) && (a.prev === null || typeof a.prev === "string");
|
|
2703
2703
|
}
|
|
2704
2704
|
function readLatestAttestation(contentDir2) {
|
|
2705
2705
|
try {
|
|
@@ -6657,6 +6657,7 @@ function walk(node, registry, path2, out) {
|
|
|
6657
6657
|
var SYSTEM_FONT_FAMILY, TONAL_ELEVATION_ALPHA;
|
|
6658
6658
|
var init_tokens = __esm({
|
|
6659
6659
|
"../../core/ts/src/tokens.ts"() {
|
|
6660
|
+
"use strict";
|
|
6660
6661
|
SYSTEM_FONT_FAMILY = "$system";
|
|
6661
6662
|
TONAL_ELEVATION_ALPHA = [0, 0.05, 0.08, 0.11, 0.12, 0.14];
|
|
6662
6663
|
}
|
|
@@ -12326,8 +12327,8 @@ function canonicalHex(value) {
|
|
|
12326
12327
|
function tokenColorProblems(colors) {
|
|
12327
12328
|
const problems = [];
|
|
12328
12329
|
for (const [name, value] of Object.entries(colors ?? {})) {
|
|
12329
|
-
const
|
|
12330
|
-
for (const [path2, raw] of
|
|
12330
|
+
const leaves2 = typeof value === "object" && value !== null && !Array.isArray(value) ? Object.entries(value).map(([variant, raw]) => [`${name}.${variant}`, raw]) : [[name, value]];
|
|
12331
|
+
for (const [path2, raw] of leaves2) {
|
|
12331
12332
|
if (typeof raw !== "string") {
|
|
12332
12333
|
problems.push({ path: path2, value: JSON.stringify(raw) ?? String(raw) });
|
|
12333
12334
|
continue;
|
|
@@ -15099,6 +15100,20 @@ async function tabRootScreens(dir) {
|
|
|
15099
15100
|
(nav?.tabBar?.items ?? []).map((i) => i?.screenId).filter((s) => typeof s === "string" && !!s)
|
|
15100
15101
|
);
|
|
15101
15102
|
}
|
|
15103
|
+
async function navEntryScreens(dir, homeScreenId) {
|
|
15104
|
+
const nav = (await loadContentConfigQuietly(dir))?.navigation;
|
|
15105
|
+
const out = /* @__PURE__ */ new Set();
|
|
15106
|
+
if (homeScreenId) out.add(homeScreenId);
|
|
15107
|
+
const walk2 = (v, depth) => {
|
|
15108
|
+
if (depth > 6 || typeof v !== "object" || v === null) return;
|
|
15109
|
+
for (const [k, x] of Object.entries(v)) {
|
|
15110
|
+
if ((k === "screenId" || k === "contentScreenId") && typeof x === "string" && x) out.add(x);
|
|
15111
|
+
else walk2(x, depth + 1);
|
|
15112
|
+
}
|
|
15113
|
+
};
|
|
15114
|
+
for (const chrome of ["tabBar", "drawer", "sidebar", "topBarDefault"]) walk2(nav?.[chrome], 0);
|
|
15115
|
+
return out;
|
|
15116
|
+
}
|
|
15102
15117
|
async function localDbEntities(dir) {
|
|
15103
15118
|
const schema = (await loadContentConfigQuietly(dir))?.dataSchema;
|
|
15104
15119
|
const names = (schema?.entities ?? []).map((e) => e?.name).filter((n) => typeof n === "string" && n.length > 0);
|
|
@@ -16834,9 +16849,9 @@ function hostFromProject(project) {
|
|
|
16834
16849
|
const blocks = project.split(/(?=^ [A-Za-z0-9_]+:\s*$)/m);
|
|
16835
16850
|
const host = blocks.find((block) => /^ type: application\s*$/m.test(block));
|
|
16836
16851
|
if (!host) throw new Error("Live Activity generation requires an iOS application target");
|
|
16837
|
-
const
|
|
16852
|
+
const scalar4 = (key2, indent) => new RegExp(`^ {${indent}}${key2}:\\s*(.+)$`, "m").exec(host)?.[1]?.trim().replace(/^['"]|['"]$/g, "");
|
|
16838
16853
|
const name = /^ ([A-Za-z0-9_]+):/m.exec(host)?.[1];
|
|
16839
|
-
const bundleId =
|
|
16854
|
+
const bundleId = scalar4("PRODUCT_BUNDLE_IDENTIFIER", 8) ?? scalar4("bundleId", 4);
|
|
16840
16855
|
const scheme = /CFBundleURLSchemes:\s*\n\s*-\s*(.+)/.exec(host)?.[1]?.trim().replace(/^['"]|['"]$/g, "");
|
|
16841
16856
|
if (!name || !bundleId || !scheme) throw new Error("Live Activity generation requires host name, bundleId and URL scheme");
|
|
16842
16857
|
const configs = /^ configFiles:\s*\n((?: .+\n)+)/m.exec(host)?.[1]?.trimEnd().split("\n").map((line) => line.trim()) ?? [];
|
|
@@ -16845,9 +16860,9 @@ function hostFromProject(project) {
|
|
|
16845
16860
|
bundleId,
|
|
16846
16861
|
scheme,
|
|
16847
16862
|
configs,
|
|
16848
|
-
displayName:
|
|
16849
|
-
version:
|
|
16850
|
-
build:
|
|
16863
|
+
displayName: scalar4("CFBundleDisplayName", 8) ?? name,
|
|
16864
|
+
version: scalar4("CFBundleShortVersionString", 8) ?? scalar4("MARKETING_VERSION", 8) ?? "1.0",
|
|
16865
|
+
build: scalar4("CFBundleVersion", 8) ?? scalar4("CURRENT_PROJECT_VERSION", 8) ?? "1"
|
|
16851
16866
|
};
|
|
16852
16867
|
}
|
|
16853
16868
|
function liveActivityPlan(project, enabled, deferredActions = false) {
|
|
@@ -18941,8 +18956,8 @@ var init_store2 = __esm({
|
|
|
18941
18956
|
`);
|
|
18942
18957
|
}
|
|
18943
18958
|
seedNotesIfEmpty() {
|
|
18944
|
-
const
|
|
18945
|
-
if (
|
|
18959
|
+
const count2 = this.db.prepare("SELECT COUNT(*) as c FROM notes").get();
|
|
18960
|
+
if (count2.c > 0) return;
|
|
18946
18961
|
const seedNotes = [
|
|
18947
18962
|
{
|
|
18948
18963
|
id: "n_001",
|
|
@@ -18982,8 +18997,8 @@ var init_store2 = __esm({
|
|
|
18982
18997
|
}
|
|
18983
18998
|
}
|
|
18984
18999
|
seedProductsIfEmpty() {
|
|
18985
|
-
const
|
|
18986
|
-
if (
|
|
19000
|
+
const count2 = this.db.prepare("SELECT COUNT(*) as c FROM products").get();
|
|
19001
|
+
if (count2.c > 0) return;
|
|
18987
19002
|
const now = Math.floor(Date.now() / 1e3);
|
|
18988
19003
|
const seed2 = [
|
|
18989
19004
|
{ id: "p_001", sku: "MNT-CAP-01", title: "Summit cap", description: "Wool-blend beanie. Charcoal. One size, packs flat.", price_cents: 2900, currency: "USD", category: "apparel", inventory: 28, status: "active" },
|
|
@@ -20560,6 +20575,23 @@ function forEachChildComponent(node, cb) {
|
|
|
20560
20575
|
};
|
|
20561
20576
|
visit(node.body.props);
|
|
20562
20577
|
}
|
|
20578
|
+
function visitComponents(root, cb) {
|
|
20579
|
+
const visit = (value) => {
|
|
20580
|
+
if (isNode(value)) {
|
|
20581
|
+
cb(value);
|
|
20582
|
+
visit(value.body.props);
|
|
20583
|
+
return;
|
|
20584
|
+
}
|
|
20585
|
+
if (Array.isArray(value)) {
|
|
20586
|
+
for (const entry of value) visit(entry);
|
|
20587
|
+
return;
|
|
20588
|
+
}
|
|
20589
|
+
if (typeof value === "object" && value !== null) {
|
|
20590
|
+
for (const entry of Object.values(value)) visit(entry);
|
|
20591
|
+
}
|
|
20592
|
+
};
|
|
20593
|
+
visit(root);
|
|
20594
|
+
}
|
|
20563
20595
|
function assignStableIds(descriptor) {
|
|
20564
20596
|
const used = /* @__PURE__ */ new Set();
|
|
20565
20597
|
const uniquify = (base) => {
|
|
@@ -26171,8 +26203,8 @@ function componentShape(value) {
|
|
|
26171
26203
|
if (!isRecord(value) || typeof value.id !== "string" || !isRecord(value.body)) return false;
|
|
26172
26204
|
return typeof value.body.package === "string" && typeof value.body.type === "string" && isRecord(value.body.props);
|
|
26173
26205
|
}
|
|
26174
|
-
function rotateRight(value,
|
|
26175
|
-
return value >>>
|
|
26206
|
+
function rotateRight(value, count2) {
|
|
26207
|
+
return value >>> count2 | value << 32 - count2;
|
|
26176
26208
|
}
|
|
26177
26209
|
function workerSubtreeSha256(raw) {
|
|
26178
26210
|
const input = new TextEncoder().encode(raw);
|
|
@@ -27337,14 +27369,14 @@ function dataTableCells(row, columns) {
|
|
|
27337
27369
|
if (Array.isArray(o.cells)) return columns.map((_, i) => o.cells[i] == null ? "" : String(o.cells[i]));
|
|
27338
27370
|
return columns.map((c) => c.key && o[c.key] != null ? String(o[c.key]) : "");
|
|
27339
27371
|
}
|
|
27340
|
-
function resampleWaveform(samples,
|
|
27372
|
+
function resampleWaveform(samples, count2) {
|
|
27341
27373
|
const clean2 = samples.map((n) => Number.isFinite(n) ? Math.min(Math.max(n, 0), 1) : 0);
|
|
27342
|
-
if (
|
|
27343
|
-
if (clean2.length <=
|
|
27374
|
+
if (count2 <= 0 || clean2.length === 0) return [];
|
|
27375
|
+
if (clean2.length <= count2) return clean2;
|
|
27344
27376
|
const out = [];
|
|
27345
|
-
for (let i = 0; i <
|
|
27346
|
-
const lo = Math.floor(i * clean2.length /
|
|
27347
|
-
const hi = Math.min(Math.max(lo + 1, Math.floor((i + 1) * clean2.length /
|
|
27377
|
+
for (let i = 0; i < count2; i++) {
|
|
27378
|
+
const lo = Math.floor(i * clean2.length / count2);
|
|
27379
|
+
const hi = Math.min(Math.max(lo + 1, Math.floor((i + 1) * clean2.length / count2)), clean2.length);
|
|
27348
27380
|
let sum = 0;
|
|
27349
27381
|
for (let j = lo; j < hi; j++) sum += clean2[j];
|
|
27350
27382
|
out.push(sum / (hi - lo));
|
|
@@ -28541,10 +28573,10 @@ function renderInner(node, ctx) {
|
|
|
28541
28573
|
case "Agenda":
|
|
28542
28574
|
return /* @__PURE__ */ jsx6(AgendaNode, { props, ctx, wrap });
|
|
28543
28575
|
case "PageControl": {
|
|
28544
|
-
const
|
|
28576
|
+
const count2 = props.count ?? 0;
|
|
28545
28577
|
const cur = props.currentIndex ?? 0;
|
|
28546
28578
|
const accent = C("accentPrimary", "#116DFF");
|
|
28547
|
-
return /* @__PURE__ */ jsx6("div", { style: { display: "inline-flex", alignItems: "center", gap: 8, ...wrap }, children: Array.from({ length:
|
|
28579
|
+
return /* @__PURE__ */ jsx6("div", { style: { display: "inline-flex", alignItems: "center", gap: 8, ...wrap }, children: Array.from({ length: count2 }).map((_, i) => /* @__PURE__ */ jsx6("span", { style: { width: i === cur ? 22 : 9, height: 9, borderRadius: 999, background: i === cur ? accent : C("textTertiary", "#aab2bd"), transition: "width .2s" } }, i)) });
|
|
28548
28580
|
}
|
|
28549
28581
|
// ───────────── pickers & inputs (RFC 0033) ─────────────
|
|
28550
28582
|
case "WheelPicker":
|
|
@@ -28649,9 +28681,9 @@ function renderInner(node, ctx) {
|
|
|
28649
28681
|
case "WorkerSubtree":
|
|
28650
28682
|
return /* @__PURE__ */ jsx6(WorkerSubtreeNode, { props, ctx, wrap, nodeId: node.id });
|
|
28651
28683
|
case "Skeleton": {
|
|
28652
|
-
const
|
|
28653
|
-
if (
|
|
28654
|
-
return /* @__PURE__ */ jsx6("div", { style: { display: "flex", flexDirection: "column", gap: 10, width: "100%", ...wrap }, children: Array.from({ length:
|
|
28684
|
+
const count2 = typeof props.count === "number" ? props.count : 1;
|
|
28685
|
+
if (count2 <= 1) return /* @__PURE__ */ jsx6("div", { style: { width: props.width ?? "100%", height: props.height ?? 14, borderRadius: props.cornerRadius ?? 6, background: C("surfaceTertiary", "#f0f0f3"), flex: "none", ...wrap } });
|
|
28686
|
+
return /* @__PURE__ */ jsx6("div", { style: { display: "flex", flexDirection: "column", gap: 10, width: "100%", ...wrap }, children: Array.from({ length: count2 }).map((_, i) => /* @__PURE__ */ jsx6("div", { style: { height: props.height ?? 22, width: `${100 - i * 8}%`, borderRadius: props.cornerRadius ?? 8, background: C("surfaceTertiary", "#f0f0f3") } }, i)) });
|
|
28655
28687
|
}
|
|
28656
28688
|
// ───────────── search & filter ─────────────
|
|
28657
28689
|
case "SearchField":
|
|
@@ -30879,8 +30911,8 @@ var init_renderNode = __esm({
|
|
|
30879
30911
|
const overflow = props.overflowCount || Math.max(0, avatars.length - maxVisible);
|
|
30880
30912
|
const shift = Math.round(size * (1 - (props.overlapRatio ?? 0.67)));
|
|
30881
30913
|
const caption = useBoundString(props.caption, ctx).trim();
|
|
30882
|
-
const
|
|
30883
|
-
const countText =
|
|
30914
|
+
const count2 = shown2.length + overflow;
|
|
30915
|
+
const countText = count2 > 0 ? `${count2} ${count2 === 1 ? "person" : "people"}` : "";
|
|
30884
30916
|
const groupName = [caption, countText].filter(Boolean).join(", ");
|
|
30885
30917
|
return /* @__PURE__ */ jsxs3("div", { role: "group", "aria-label": groupName || void 0, "data-a11y-value": countText || void 0, ...{ [SELF_RENDERED_LEAF]: true }, style: { width: "100%", ...wrap }, children: [
|
|
30886
30918
|
/* @__PURE__ */ jsxs3("div", { style: { display: "flex" }, children: [
|
|
@@ -31195,7 +31227,7 @@ var init_renderNode = __esm({
|
|
|
31195
31227
|
const W = 100, H = 100;
|
|
31196
31228
|
const slot = bars.length > 0 ? W / bars.length : W;
|
|
31197
31229
|
const barW = Math.max(0.6, slot * 0.58);
|
|
31198
|
-
const
|
|
31230
|
+
const cut2 = progress * W;
|
|
31199
31231
|
const rates = Array.isArray(props.rates) ? props.rates.map(Number).filter((n) => n > 0) : [];
|
|
31200
31232
|
const [pickedRate, setPickedRate] = React5.useState(null);
|
|
31201
31233
|
React5.useEffect(() => {
|
|
@@ -31306,7 +31338,7 @@ var init_renderNode = __esm({
|
|
|
31306
31338
|
height: bh,
|
|
31307
31339
|
rx: barW / 2,
|
|
31308
31340
|
fill: accent,
|
|
31309
|
-
opacity: cx <=
|
|
31341
|
+
opacity: cx <= cut2 ? isPlayable ? 1 : 0.45 : isPlayable ? 0.28 : 0.16
|
|
31310
31342
|
},
|
|
31311
31343
|
i
|
|
31312
31344
|
);
|
|
@@ -36222,7 +36254,7 @@ async function handleWebWix(req, res, state) {
|
|
|
36222
36254
|
const session = webWixSession(req, res, state);
|
|
36223
36255
|
const auth = resolveWebWixAuth(state.app);
|
|
36224
36256
|
const path2 = new URL(req.url ?? "", "http://localhost").pathname;
|
|
36225
|
-
const
|
|
36257
|
+
const readJson6 = async () => {
|
|
36226
36258
|
const chunks = [];
|
|
36227
36259
|
for await (const c of req) chunks.push(c);
|
|
36228
36260
|
const t = Buffer.concat(chunks).toString("utf8");
|
|
@@ -36239,7 +36271,7 @@ async function handleWebWix(req, res, state) {
|
|
|
36239
36271
|
res.end(JSON.stringify(obj3));
|
|
36240
36272
|
};
|
|
36241
36273
|
if (path2 === "/v1/__webwix/login" && req.method === "POST") {
|
|
36242
|
-
const b = await
|
|
36274
|
+
const b = await readJson6();
|
|
36243
36275
|
try {
|
|
36244
36276
|
const { memberToken, visitorToken } = await memberDirectLogin(
|
|
36245
36277
|
auth.clientId,
|
|
@@ -36256,7 +36288,7 @@ async function handleWebWix(req, res, state) {
|
|
|
36256
36288
|
}
|
|
36257
36289
|
}
|
|
36258
36290
|
if (path2 === "/v1/__webwix/call" && req.method === "POST") {
|
|
36259
|
-
const b = await
|
|
36291
|
+
const b = await readJson6();
|
|
36260
36292
|
const ownerRung = b.ownerMsid !== void 0 || b.checkOwnerSession === true;
|
|
36261
36293
|
const msid = String(b.ownerMsid ?? "");
|
|
36262
36294
|
const cookie = req.headers.cookie ?? "";
|
|
@@ -36404,7 +36436,7 @@ async function handleWebWix(req, res, state) {
|
|
|
36404
36436
|
});
|
|
36405
36437
|
}
|
|
36406
36438
|
if (path2 === "/v1/__webwix/register" && req.method === "POST") {
|
|
36407
|
-
const b = await
|
|
36439
|
+
const b = await readJson6();
|
|
36408
36440
|
try {
|
|
36409
36441
|
const { memberToken, visitorToken } = await memberDirectRegister(
|
|
36410
36442
|
auth.clientId,
|
|
@@ -39403,10 +39435,10 @@ function effectSince(w, mark, action, componentId) {
|
|
|
39403
39435
|
}
|
|
39404
39436
|
function resolveSiteRows(itemsPath, valueOf) {
|
|
39405
39437
|
if (!itemsPath || itemsPath === UNTRACKED_ITEMS) return void 0;
|
|
39406
|
-
const
|
|
39407
|
-
if (
|
|
39408
|
-
const outer = valueOf(itemsPath.slice(0,
|
|
39409
|
-
const field = itemsPath.slice(
|
|
39438
|
+
const cut2 = itemsPath.indexOf(NESTED_ITEMS_SEP);
|
|
39439
|
+
if (cut2 < 0) return valueOf(itemsPath);
|
|
39440
|
+
const outer = valueOf(itemsPath.slice(0, cut2));
|
|
39441
|
+
const field = itemsPath.slice(cut2 + NESTED_ITEMS_SEP.length);
|
|
39410
39442
|
const first = Array.isArray(outer) ? outer[0] : void 0;
|
|
39411
39443
|
return first && typeof first === "object" ? first[field] : void 0;
|
|
39412
39444
|
}
|
|
@@ -39561,6 +39593,7 @@ async function crawlScreenInner(opts) {
|
|
|
39561
39593
|
const findings = [];
|
|
39562
39594
|
const actionsSkipped = [];
|
|
39563
39595
|
const navEdges = [];
|
|
39596
|
+
const navUnfollowed = /* @__PURE__ */ new Set();
|
|
39564
39597
|
const unobservedActions = [];
|
|
39565
39598
|
const effects = [];
|
|
39566
39599
|
let observations;
|
|
@@ -39583,7 +39616,10 @@ async function crawlScreenInner(opts) {
|
|
|
39583
39616
|
return pathValue(row0, path2);
|
|
39584
39617
|
};
|
|
39585
39618
|
const target = resolveItem(merged.screenId);
|
|
39586
|
-
if (typeof target !== "string" || !target || target.includes("$"))
|
|
39619
|
+
if (typeof target !== "string" || !target || target.includes("$")) {
|
|
39620
|
+
navUnfollowed.add(`tap:${site.componentId ?? JSON.stringify(site.params ?? {})}`);
|
|
39621
|
+
continue;
|
|
39622
|
+
}
|
|
39587
39623
|
const params = {};
|
|
39588
39624
|
for (const [k, v] of Object.entries(merged)) {
|
|
39589
39625
|
if (k === "screenId" || k === "presentation") continue;
|
|
@@ -39596,7 +39632,10 @@ async function crawlScreenInner(opts) {
|
|
|
39596
39632
|
};
|
|
39597
39633
|
const drainWorkerEdges = (w, via) => {
|
|
39598
39634
|
for (const d of w.navDirectives.splice(0)) {
|
|
39599
|
-
if (!d.screenId || d.screenId.includes("$"))
|
|
39635
|
+
if (!d.screenId || d.screenId.includes("$")) {
|
|
39636
|
+
navUnfollowed.add(`${via}:${d.screenId ?? ""}`);
|
|
39637
|
+
continue;
|
|
39638
|
+
}
|
|
39600
39639
|
const params = {};
|
|
39601
39640
|
for (const [k, v] of Object.entries(d.args)) if (!v.includes("$")) params[k] = v;
|
|
39602
39641
|
navEdges.push({ target: d.screenId, params, via });
|
|
@@ -39977,7 +40016,7 @@ async function crawlScreenInner(opts) {
|
|
|
39977
40016
|
const edges = dedupeEdges(navEdges);
|
|
39978
40017
|
if (linkableScreenIds?.size && !opts.capabilitySuccess) {
|
|
39979
40018
|
const linkable = linkableScreenIds;
|
|
39980
|
-
const
|
|
40019
|
+
const resolvesToLinkable2 = (target) => {
|
|
39981
40020
|
if (linkable.has(target)) return true;
|
|
39982
40021
|
for (const base of linkable) {
|
|
39983
40022
|
if (target.length > base.length + 1 && target.startsWith(base)) {
|
|
@@ -39991,7 +40030,7 @@ async function crawlScreenInner(opts) {
|
|
|
39991
40030
|
for (const e of edges) {
|
|
39992
40031
|
if (e.target === screenId) continue;
|
|
39993
40032
|
if (reported.has(e.target)) continue;
|
|
39994
|
-
if (knownScreenIds.has(e.target) ||
|
|
40033
|
+
if (knownScreenIds.has(e.target) || resolvesToLinkable2(e.target)) continue;
|
|
39995
40034
|
reported.add(e.target);
|
|
39996
40035
|
findings.push({
|
|
39997
40036
|
screen: screenId,
|
|
@@ -40012,6 +40051,7 @@ async function crawlScreenInner(opts) {
|
|
|
40012
40051
|
actionsExercised: exercised,
|
|
40013
40052
|
actionsSkipped,
|
|
40014
40053
|
navEdges: edges,
|
|
40054
|
+
...navUnfollowed.size ? { navUnfollowed: navUnfollowed.size } : {},
|
|
40015
40055
|
...effects.length ? { effects } : {},
|
|
40016
40056
|
...observations ? { observations } : {},
|
|
40017
40057
|
...unobservedActions.length ? { unobservedActions } : {},
|
|
@@ -42067,6 +42107,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
42067
42107
|
...collect2?.lint ? { lint, workers } : {},
|
|
42068
42108
|
...collect2?.render ? { renders } : {},
|
|
42069
42109
|
...collect2?.descriptors ? { descriptors: baked, linkableScreenIds: [...linkable] } : {},
|
|
42110
|
+
...collect2?.descriptors && typeof preloaded.meta.homeScreenId === "string" && preloaded.meta.homeScreenId ? { homeScreenId: preloaded.meta.homeScreenId } : {},
|
|
42070
42111
|
...renderTokens !== void 0 ? { tokens: renderTokens } : {},
|
|
42071
42112
|
...preloaded.meta.surfaces ? { surfaceNav: preloaded.meta.surfaces } : {},
|
|
42072
42113
|
auth: (() => {
|
|
@@ -42332,6 +42373,27 @@ h2{font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;le
|
|
|
42332
42373
|
.lant{font-weight:600}
|
|
42333
42374
|
.lanu{font-size:12px;word-break:break-all}
|
|
42334
42375
|
.lanh{color:var(--muted);font-size:12px;margin-top:4px}
|
|
42376
|
+
.mbox{overflow-x:auto}
|
|
42377
|
+
.msum{color:var(--muted);font-size:12px;margin-bottom:8px}
|
|
42378
|
+
.mnode rect{fill:var(--card);stroke:var(--line);stroke-width:1.2}
|
|
42379
|
+
.mnode text{font-size:11px;fill:var(--ink)}
|
|
42380
|
+
.mnode.ok rect{fill:var(--okbg);stroke:var(--ok)}
|
|
42381
|
+
.mnode.failed rect{fill:var(--badbg);stroke:var(--bad)}
|
|
42382
|
+
.mnode.pending rect{stroke-dasharray:4 3}
|
|
42383
|
+
.mnode.skipped text{fill:var(--muted)}
|
|
42384
|
+
.mnode.entry rect{stroke-width:2.4}
|
|
42385
|
+
.mnode.unreached rect{fill:var(--warnbg);stroke:var(--warn);stroke-dasharray:4 3}
|
|
42386
|
+
.medge{fill:none;stroke:var(--faint);stroke-width:1.2}
|
|
42387
|
+
.mbroken{font-size:11px;fill:var(--bad)}
|
|
42388
|
+
.mrow{font-size:11px;fill:var(--warn)}
|
|
42389
|
+
.mfollow{font-size:9px;fill:var(--warn)}
|
|
42390
|
+
.mnode.unfollowed rect{stroke:var(--warn)}
|
|
42391
|
+
.changes{margin-top:12px;padding:10px 12px;border:1px solid var(--line);border-radius:12px;font-size:12px}
|
|
42392
|
+
.changes .cht{font-weight:600;margin-bottom:4px}
|
|
42393
|
+
.changes ul{margin:0;padding-left:16px}
|
|
42394
|
+
.changes li{margin:2px 0;word-break:break-word}
|
|
42395
|
+
.changes .sw{display:inline-block;width:10px;height:10px;border-radius:3px;margin-left:6px;vertical-align:middle;border:1px solid var(--line)}
|
|
42396
|
+
.changes .chm{color:var(--muted);margin-top:2px}
|
|
42335
42397
|
.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}
|
|
42336
42398
|
.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)}
|
|
42337
42399
|
.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}
|
|
@@ -42389,6 +42451,7 @@ h2{font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;le
|
|
|
42389
42451
|
<div class="card section"><h2>Screens</h2><div class="wall" id="wall"></div></div>
|
|
42390
42452
|
<div class="card section" id="brandcard"><h2>Brand</h2><div class="brand" id="brand"></div></div>
|
|
42391
42453
|
<div class="card section" id="navcard"><h2>Navigation the test crawl followed</h2><div class="nav" id="nav"></div></div>
|
|
42454
|
+
<div class="card section" id="appmap" hidden><h2>App map</h2><div class="msum" id="msum"></div><div class="mbox" id="mapbox"></div></div>
|
|
42392
42455
|
<div class="card section"><h2>Postcards</h2><ul class="log" id="log"></ul></div>
|
|
42393
42456
|
</div></div></div>
|
|
42394
42457
|
<div id="lb"><img alt=""></div>
|
|
@@ -42400,6 +42463,48 @@ h2{font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;le
|
|
|
42400
42463
|
var cur=null, lastSeen=Date.now();
|
|
42401
42464
|
function $(id){return document.getElementById(id)}
|
|
42402
42465
|
function el(tag,cls,txt){var e=document.createElement(tag);if(cls)e.className=cls;if(txt!=null)e.textContent=txt;return e}
|
|
42466
|
+
/* #3342 \u2014 the app map. Layers are the distance from an entry (tab roots, or the first screen), the
|
|
42467
|
+
screens nothing leads to sit in their own last row, a link to a screen that does not exist is a red
|
|
42468
|
+
stub naming it. Built with DOM calls: a screen id is SVG text, never markup. Past 60 screens only
|
|
42469
|
+
the ones worth looking at are drawn (unreached, failed) and the summary carries the rest. */
|
|
42470
|
+
function drawMap(m){var card=$("appmap"),box=$("mapbox");clear(box);if(!m){card.hidden=true;return}card.hidden=false;
|
|
42471
|
+
var un=m.screens.filter(function(x){return !x.reached});
|
|
42472
|
+
/* "Nothing leads here" only when the crawl saw every link: a link built from list data (a feed's rows,
|
|
42473
|
+
a home grid) has a target it cannot resolve, and one of those may well open the screen. */
|
|
42474
|
+
var gone=!m.done?" not reached yet \xB7 ":m.unfollowed?" not seen linked \xB7 ":" unreached \xB7 ";
|
|
42475
|
+
$("msum").textContent=m.screens.length+" screens \xB7 "+un.length+gone+m.broken.length+" broken link"+(m.broken.length===1?"":"s")+(m.unfollowed?" \xB7 "+m.unfollowed+" link"+(m.unfollowed===1?"":"s")+" the crawl could not follow":"")+(m.edgesDropped?" \xB7 "+m.edgesDropped+" more link"+(m.edgesDropped===1?"":"s")+" not drawn":"")+(m.done?"":" \xB7 crawling");
|
|
42476
|
+
var show=m.screens.length>60?m.screens.filter(function(x){return !x.reached||x.status==="failed"}):m.screens,on={};show.forEach(function(x){on[x.id]=1});
|
|
42477
|
+
var out={},depth={},q=[];m.edges.forEach(function(e){if(on[e.from]&&on[e.to])(out[e.from]=out[e.from]||[]).push(e.to)});
|
|
42478
|
+
show.forEach(function(x){if(x.entry){depth[x.id]=0;q.push(x.id)}});
|
|
42479
|
+
while(q.length){var c=q.shift();(out[c]||[]).forEach(function(t){if(depth[t]==null){depth[t]=depth[c]+1;q.push(t)}})}
|
|
42480
|
+
var maxd=0;show.forEach(function(x){if(depth[x.id]>maxd)maxd=depth[x.id]});
|
|
42481
|
+
var rows=[];show.forEach(function(x){var r=!x.reached?maxd+2:depth[x.id]!=null?depth[x.id]:maxd+1;(rows[r]=rows[r]||[]).push(x)});
|
|
42482
|
+
/* Nodes are as wide as the longest id drawn needs (up to 300px): an id cut to its first letters
|
|
42483
|
+
cannot be told from its template siblings, which differ only at the end. Past that, the middle
|
|
42484
|
+
goes and both ends stay; the full id is always in the node's title. */
|
|
42485
|
+
var CW=6.5,longest=0;show.forEach(function(x){longest=Math.max(longest,x.id.length)});
|
|
42486
|
+
var W=Math.round(Math.min(300,Math.max(124,longest*CW+20))),H=28,HG=12,VG=36,P=10,ns="http://www.w3.org/2000/svg",pos={},y=P,width=0,unRow=maxd+2;
|
|
42487
|
+
function lab(id){var k=Math.floor((W-20)/CW);if(id.length<=k)return id;var a=Math.ceil((k-1)/2),b=Math.floor((k-1)/2);return id.slice(0,a)+"\u2026"+id.slice(id.length-b)}
|
|
42488
|
+
var svg=document.createElementNS(ns,"svg"),edgesG=document.createElementNS(ns,"g"),nodesG=document.createElementNS(ns,"g");svg.appendChild(edgesG);svg.appendChild(nodesG);
|
|
42489
|
+
function sv(tag,attrs,txt){var e=document.createElementNS(ns,tag);for(var k in attrs)e.setAttribute(k,String(attrs[k]));if(txt!=null)e.textContent=txt;return e}
|
|
42490
|
+
for(var r=0;r<rows.length;r++){var row=rows[r];if(!row)continue;
|
|
42491
|
+
if(r===unRow){nodesG.appendChild(sv("text",{x:P,y:y+10,"class":"mrow"},!m.done?"Not reached yet \u2014 no link to these seen so far":m.unfollowed?"Not seen linked \u2014 "+m.unfollowed+" link"+(m.unfollowed===1?"":"s")+" built from list data could not be followed":"Unreached \u2014 nothing leads here"));y+=16}
|
|
42492
|
+
row.forEach(function(x,i){var nx=P+i*(W+HG);pos[x.id]={x:nx,y:y};width=Math.max(width,nx+W+P);
|
|
42493
|
+
var g=sv("g",{"class":"mnode "+x.status+(x.entry?" entry":"")+(x.reached?"":" unreached")+(x.unfollowed?" unfollowed":""),"data-id":x.id});
|
|
42494
|
+
g.appendChild(sv("rect",{x:nx,y:y,width:W,height:H,rx:7}));g.appendChild(sv("text",{x:nx+W/2,y:y+H/2+4,"text-anchor":"middle"},lab(x.id)));
|
|
42495
|
+
g.appendChild(sv("title",{},x.id+" \xB7 "+x.status+(x.entry?" \xB7 entry":"")+(x.reached?"":" \xB7 unreached")+(x.unfollowed?" \xB7 "+x.unfollowed+" links the crawl could not follow":"")));
|
|
42496
|
+
if(x.unfollowed)g.appendChild(sv("text",{x:nx+W-6,y:y+10,"text-anchor":"end","class":"mfollow"},"+"+x.unfollowed+"?"));nodesG.appendChild(g)});
|
|
42497
|
+
y+=H+VG}
|
|
42498
|
+
m.edges.forEach(function(e){var a=pos[e.from],b=pos[e.to];if(!a||!b)return;var x1=a.x+W/2,y1=a.y+H,x2=b.x+W/2,y2=b.y,my=(y1+y2)/2;
|
|
42499
|
+
edgesG.appendChild(sv("path",{"class":"medge",d:"M"+x1+" "+y1+" C"+x1+" "+my+" "+x2+" "+my+" "+x2+" "+y2}))});
|
|
42500
|
+
var by=y;m.broken.forEach(function(e,i){var a=pos[e.from];if(!a)return;var bx=a.x+W+4,yy=a.y+H/2+4+i%2*10;
|
|
42501
|
+
nodesG.appendChild(sv("text",{x:bx,y:yy,"class":"mbroken"},"\u2192 missing: "+e.to));width=Math.max(width,bx+170)});
|
|
42502
|
+
svg.setAttribute("width",String(Math.max(width,200)));svg.setAttribute("height",String(Math.max(by,40)));svg.setAttribute("role","img");svg.setAttribute("aria-label","App map: "+$("msum").textContent);box.appendChild(svg)}
|
|
42503
|
+
/* #3342 \u2014 what the last rebuild changed, one line each, already text (studio.ts formats it); a hex
|
|
42504
|
+
token gets old/new swatches, painted through style, never markup. */
|
|
42505
|
+
function changesCard(b){var d=el("div","changes");d.appendChild(el("div","cht","What changed \xB7 "+hhmm(b.at)));var ul=document.createElement("ul");
|
|
42506
|
+
b.changes.lines.forEach(function(l){var li=el("li",null,l.text);if(l.from){var a=el("span","sw");a.style.background=l.from;li.appendChild(a)}if(l.to){var z=el("span","sw");z.style.background=l.to;li.appendChild(z)}ul.appendChild(li)});
|
|
42507
|
+
d.appendChild(ul);if(b.changes.more)d.appendChild(el("div","chm","+"+b.changes.more+" more"));return d}
|
|
42403
42508
|
/* #3250 \u2014 a --lan run's way onto the owner's phone. The QR arrives as rows of 1/0 modules and is drawn
|
|
42404
42509
|
as ONE path of unit squares: built with DOM calls, so nothing in the URL can become markup. */
|
|
42405
42510
|
function lanCard(lan){var d=el("div","lan");d.appendChild(el("div","lant","Open on your phone"));
|
|
@@ -42435,7 +42540,7 @@ function render(s){
|
|
|
42435
42540
|
if(pip){paintStrip(s)}else{
|
|
42436
42541
|
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;
|
|
42437
42542
|
if(kept){while(focus.lastChild&&focus.lastChild!==kept.parentNode)focus.removeChild(focus.lastChild)}else clear(focus);
|
|
42438
|
-
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));if(s.live.lan)focus.appendChild(lanCard(s.live.lan))}
|
|
42543
|
+
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));if(s.live.lan)focus.appendChild(lanCard(s.live.lan));if(s.live.lastBuild&&s.live.lastBuild.changes)focus.appendChild(changesCard(s.live.lastBuild))}
|
|
42439
42544
|
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"))}
|
|
42440
42545
|
else{$("focuslbl").textContent="Latest";focus.appendChild(el("div","empty","The first render appears here."))}
|
|
42441
42546
|
if(s.focus&&s.focus.frames.length>1)s.focus.frames.forEach(function(fm){film.appendChild(img(fm.img))});}}
|
|
@@ -42453,7 +42558,7 @@ function render(s){
|
|
|
42453
42558
|
if(s.brand.site){var si=img(s.brand.site,"site");brand.appendChild(si)}
|
|
42454
42559
|
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)}
|
|
42455
42560
|
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)}
|
|
42456
|
-
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))});
|
|
42561
|
+
var nav=$("nav");clear(nav);$("navcard").style.display=s.nav.length&&!s.map?"":"none";drawMap(s.map);s.nav.forEach(function(e){nav.appendChild(el("span",null,e.from+" \u2192 "+e.to))});
|
|
42457
42562
|
var log=$("log");clear(log);if(!s.journal.length)log.appendChild(el("li","empty","Postcards the agent journals appear here."));
|
|
42458
42563
|
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));
|
|
42459
42564
|
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)});
|
|
@@ -42573,7 +42678,7 @@ function favicon(n,bad){try{var c=document.createElement("canvas");c.width=c.hei
|
|
|
42573
42678
|
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)})()}
|
|
42574
42679
|
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)})()}
|
|
42575
42680
|
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}}
|
|
42576
|
-
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}
|
|
42681
|
+
function buildLine(b){if(!b.ok)return "Build failed \xB7 still showing the last good version";var what=b.headline?b.headline: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}
|
|
42577
42682
|
function effects(s){var is=snap(s),was=seen;seen=is;if(is.accent)document.documentElement.style.setProperty("--accent",is.accent);
|
|
42578
42683
|
/* The phone (kept across renders) and the Now line outlive a render: clear what they played last. */
|
|
42579
42684
|
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;
|
|
@@ -42636,9 +42741,174 @@ var init_studio_page = __esm({
|
|
|
42636
42741
|
}
|
|
42637
42742
|
});
|
|
42638
42743
|
|
|
42639
|
-
// src/
|
|
42640
|
-
|
|
42744
|
+
// src/build-changes.ts
|
|
42745
|
+
var build_changes_exports = {};
|
|
42746
|
+
__export(build_changes_exports, {
|
|
42747
|
+
boardLines: () => boardLines,
|
|
42748
|
+
describeChanges: () => describeChanges,
|
|
42749
|
+
diffDescriptors: () => diffDescriptors,
|
|
42750
|
+
diffTokens: () => diffTokens,
|
|
42751
|
+
headline: () => headline
|
|
42752
|
+
});
|
|
42753
|
+
import { existsSync as existsSync40, readdirSync as readdirSync22, readFileSync as readFileSync43 } from "node:fs";
|
|
42641
42754
|
import { join as join38 } from "node:path";
|
|
42755
|
+
function componentsOf(descriptor) {
|
|
42756
|
+
const out = /* @__PURE__ */ new Map();
|
|
42757
|
+
visitComponents(descriptor, (n) => {
|
|
42758
|
+
if (typeof n.id !== "string" || out.has(n.id)) return;
|
|
42759
|
+
const props = typeof n.body.props === "object" && n.body.props !== null ? n.body.props : {};
|
|
42760
|
+
out.set(n.id, { type: n.body.type, props });
|
|
42761
|
+
});
|
|
42762
|
+
return out;
|
|
42763
|
+
}
|
|
42764
|
+
function diffDescriptors(screen, before, after) {
|
|
42765
|
+
const a = componentsOf(before);
|
|
42766
|
+
const b = componentsOf(after);
|
|
42767
|
+
const props = [];
|
|
42768
|
+
const added = [];
|
|
42769
|
+
for (const [id, now] of b) {
|
|
42770
|
+
const was = a.get(id);
|
|
42771
|
+
if (!was) {
|
|
42772
|
+
added.push({ kind: "added", screen, node: id, type: now.type });
|
|
42773
|
+
continue;
|
|
42774
|
+
}
|
|
42775
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(was.props), ...Object.keys(now.props)]);
|
|
42776
|
+
for (const key2 of keys) {
|
|
42777
|
+
const x = was.props[key2];
|
|
42778
|
+
const y = now.props[key2];
|
|
42779
|
+
if (!scalar2(x) && !scalar2(y)) continue;
|
|
42780
|
+
if (x === y) continue;
|
|
42781
|
+
props.push({
|
|
42782
|
+
kind: TEXT_PROPS.has(key2) ? "text" : "prop",
|
|
42783
|
+
screen,
|
|
42784
|
+
node: id,
|
|
42785
|
+
path: key2,
|
|
42786
|
+
...scalar2(x) ? { from: cut(String(x)) } : {},
|
|
42787
|
+
...scalar2(y) ? { to: cut(String(y)) } : {}
|
|
42788
|
+
});
|
|
42789
|
+
}
|
|
42790
|
+
}
|
|
42791
|
+
const removed = [];
|
|
42792
|
+
for (const [id, was] of a) if (!b.has(id)) removed.push({ kind: "removed", screen, node: id, type: was.type });
|
|
42793
|
+
return [...props.filter((c) => c.kind === "text"), ...added, ...removed, ...props.filter((c) => c.kind === "prop")];
|
|
42794
|
+
}
|
|
42795
|
+
function leaves(value, prefix, out) {
|
|
42796
|
+
if (scalar2(value)) {
|
|
42797
|
+
out.set(prefix, String(value));
|
|
42798
|
+
return;
|
|
42799
|
+
}
|
|
42800
|
+
if (typeof value !== "object" || value === null) return;
|
|
42801
|
+
for (const [k, v] of Object.entries(value)) leaves(v, prefix ? `${prefix}.${k}` : k, out);
|
|
42802
|
+
}
|
|
42803
|
+
function diffTokens(before, after) {
|
|
42804
|
+
const a = /* @__PURE__ */ new Map();
|
|
42805
|
+
const b = /* @__PURE__ */ new Map();
|
|
42806
|
+
leaves(before, "", a);
|
|
42807
|
+
leaves(after, "", b);
|
|
42808
|
+
const paths = [.../* @__PURE__ */ new Set([...a.keys(), ...b.keys()])].sort();
|
|
42809
|
+
const out = [];
|
|
42810
|
+
for (const path2 of paths) {
|
|
42811
|
+
const x = a.get(path2);
|
|
42812
|
+
const y = b.get(path2);
|
|
42813
|
+
if (x === y) continue;
|
|
42814
|
+
out.push({ kind: "token", path: path2, ...x !== void 0 ? { from: cut(x) } : {}, ...y !== void 0 ? { to: cut(y) } : {} });
|
|
42815
|
+
}
|
|
42816
|
+
return out;
|
|
42817
|
+
}
|
|
42818
|
+
function describeChanges(oldTree, newTree, diff, opts = {}) {
|
|
42819
|
+
if (!existsSync40(oldTree) || !existsSync40(newTree)) return { items: [], more: 0 };
|
|
42820
|
+
const all = [];
|
|
42821
|
+
const before = screensIn(oldTree);
|
|
42822
|
+
const after = screensIn(newTree);
|
|
42823
|
+
for (const id of diff.screens) {
|
|
42824
|
+
if (!after.has(id) || !before.has(id)) continue;
|
|
42825
|
+
const was = readJson2(join38(oldTree, "screens", `${id}.json`));
|
|
42826
|
+
const now = readJson2(join38(newTree, "screens", `${id}.json`));
|
|
42827
|
+
const changes = diffDescriptors(id, was, now);
|
|
42828
|
+
if (changes.length) all.push(...changes);
|
|
42829
|
+
else all.push({ kind: JSON.stringify(was) === JSON.stringify(now) ? "logic" : "descriptor", screen: id });
|
|
42830
|
+
}
|
|
42831
|
+
if (diff.tokens) all.push(...diffTokens(readJson2(join38(oldTree, "tokens.json")), readJson2(join38(newTree, "tokens.json"))));
|
|
42832
|
+
for (const id of [...after].sort()) if (!before.has(id)) all.push({ kind: "screen-added", screen: id });
|
|
42833
|
+
for (const id of [...before].sort()) if (!after.has(id)) all.push({ kind: "screen-removed", screen: id });
|
|
42834
|
+
const ranked = all.map((c, i) => ({ c, i })).sort((x, y) => RANK[x.c.kind] - RANK[y.c.kind] || x.i - y.i).map((x) => x.c);
|
|
42835
|
+
const max = opts.max ?? MAX_ITEMS;
|
|
42836
|
+
return { items: ranked.slice(0, max), more: Math.max(0, ranked.length - max) };
|
|
42837
|
+
}
|
|
42838
|
+
function headline(changes) {
|
|
42839
|
+
const c = changes.items[0];
|
|
42840
|
+
return c ? lineOf(c) : null;
|
|
42841
|
+
}
|
|
42842
|
+
function boardLines(changes) {
|
|
42843
|
+
const lines = [];
|
|
42844
|
+
for (const c of changes.items) {
|
|
42845
|
+
const text5 = lineOf(c);
|
|
42846
|
+
const same2 = lines.find((l) => l.text === text5);
|
|
42847
|
+
if (same2) {
|
|
42848
|
+
same2.n++;
|
|
42849
|
+
continue;
|
|
42850
|
+
}
|
|
42851
|
+
lines.push({
|
|
42852
|
+
text: text5,
|
|
42853
|
+
n: 1,
|
|
42854
|
+
...c.kind === "token" && c.from && HEX.test(c.from) ? { from: c.from } : {},
|
|
42855
|
+
...c.kind === "token" && c.to && HEX.test(c.to) ? { to: c.to } : {}
|
|
42856
|
+
});
|
|
42857
|
+
}
|
|
42858
|
+
return { lines: lines.map(({ n, ...l }) => n > 1 ? { ...l, text: `${l.text} (\xD7${n})` } : l), more: changes.more };
|
|
42859
|
+
}
|
|
42860
|
+
function lineOf(c) {
|
|
42861
|
+
switch (c.kind) {
|
|
42862
|
+
case "text":
|
|
42863
|
+
case "prop":
|
|
42864
|
+
return `${c.screen}: \u201C${c.from ?? ""}\u201D \u2192 \u201C${c.to ?? ""}\u201D`;
|
|
42865
|
+
case "added":
|
|
42866
|
+
return `${c.screen}: + ${c.type}`;
|
|
42867
|
+
case "removed":
|
|
42868
|
+
return `${c.screen}: \u2212 ${c.type}`;
|
|
42869
|
+
case "token":
|
|
42870
|
+
return `${c.path} ${c.from ?? "(new)"} \u2192 ${c.to ?? "(removed)"}`;
|
|
42871
|
+
case "descriptor":
|
|
42872
|
+
return `${c.screen}: descriptor changed`;
|
|
42873
|
+
case "logic":
|
|
42874
|
+
return `${c.screen}: logic changed`;
|
|
42875
|
+
case "screen-added":
|
|
42876
|
+
return `new screen: ${c.screen}`;
|
|
42877
|
+
case "screen-removed":
|
|
42878
|
+
return `screen removed: ${c.screen}`;
|
|
42879
|
+
}
|
|
42880
|
+
}
|
|
42881
|
+
var TEXT_PROPS, RANK, MAX_TEXT, MAX_ITEMS, cut, scalar2, readJson2, screensIn, HEX;
|
|
42882
|
+
var init_build_changes = __esm({
|
|
42883
|
+
"src/build-changes.ts"() {
|
|
42884
|
+
init_stable_ids();
|
|
42885
|
+
TEXT_PROPS = /* @__PURE__ */ new Set(["text", "template", "title", "subtitle", "label", "placeholder", "caption", "message", "value", "hint", "description"]);
|
|
42886
|
+
RANK = { text: 0, added: 1, removed: 1, token: 2, prop: 3, "screen-added": 4, "screen-removed": 4, descriptor: 5, logic: 5 };
|
|
42887
|
+
MAX_TEXT = 60;
|
|
42888
|
+
MAX_ITEMS = 12;
|
|
42889
|
+
cut = (s) => s.length > MAX_TEXT ? `${s.slice(0, MAX_TEXT - 1)}\u2026` : s;
|
|
42890
|
+
scalar2 = (v) => typeof v === "string" || typeof v === "number" || typeof v === "boolean";
|
|
42891
|
+
readJson2 = (path2) => {
|
|
42892
|
+
try {
|
|
42893
|
+
return JSON.parse(readFileSync43(path2, "utf8"));
|
|
42894
|
+
} catch {
|
|
42895
|
+
return void 0;
|
|
42896
|
+
}
|
|
42897
|
+
};
|
|
42898
|
+
screensIn = (tree) => {
|
|
42899
|
+
try {
|
|
42900
|
+
return new Set(readdirSync22(join38(tree, "screens")).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -5)));
|
|
42901
|
+
} catch {
|
|
42902
|
+
return /* @__PURE__ */ new Set();
|
|
42903
|
+
}
|
|
42904
|
+
};
|
|
42905
|
+
HEX = /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;
|
|
42906
|
+
}
|
|
42907
|
+
});
|
|
42908
|
+
|
|
42909
|
+
// src/studio-timeline.ts
|
|
42910
|
+
import { existsSync as existsSync41, readFileSync as readFileSync44 } from "node:fs";
|
|
42911
|
+
import { join as join39 } from "node:path";
|
|
42642
42912
|
function stateOf(view) {
|
|
42643
42913
|
const j = view.journal[0];
|
|
42644
42914
|
const h = view.health;
|
|
@@ -42705,10 +42975,10 @@ function validFrame(f) {
|
|
|
42705
42975
|
return true;
|
|
42706
42976
|
}
|
|
42707
42977
|
function readTimeline(dir) {
|
|
42708
|
-
const file =
|
|
42709
|
-
if (!
|
|
42978
|
+
const file = join39(dir, TIMELINE_FILE);
|
|
42979
|
+
if (!existsSync41(file)) return [];
|
|
42710
42980
|
const out = [];
|
|
42711
|
-
for (const line of
|
|
42981
|
+
for (const line of readFileSync44(file, "utf8").split("\n")) {
|
|
42712
42982
|
if (!line.trim()) continue;
|
|
42713
42983
|
try {
|
|
42714
42984
|
const f = JSON.parse(line);
|
|
@@ -42725,22 +42995,23 @@ function trim(frames) {
|
|
|
42725
42995
|
return frames.slice(-MAX_FRAMES);
|
|
42726
42996
|
}
|
|
42727
42997
|
function writeTimelineJs(dir, frames) {
|
|
42728
|
-
writeFileAtomic(
|
|
42998
|
+
writeFileAtomic(join39(dir, TIMELINE_JS), `window.__himiTimeline && window.__himiTimeline(${scriptJson(frames)});
|
|
42729
42999
|
`);
|
|
42730
43000
|
}
|
|
42731
43001
|
function appendFrame(dir, view, reveal = null) {
|
|
42732
43002
|
const frames = readTimeline(dir);
|
|
42733
43003
|
const last = frames[frames.length - 1];
|
|
42734
43004
|
if (last && last.v === view.v && !reveal) {
|
|
42735
|
-
if (!
|
|
43005
|
+
if (!existsSync41(join39(dir, TIMELINE_JS))) writeTimelineJs(dir, frames);
|
|
42736
43006
|
return frames.length;
|
|
42737
43007
|
}
|
|
42738
43008
|
let prev = null;
|
|
42739
43009
|
for (const f of frames) prev = fold(prev, f);
|
|
42740
43010
|
const frame = frameFor(stateOf(view), prev, view.generatedAt, view.v, frames.length % KEYFRAME_EVERY === 0);
|
|
43011
|
+
if (!frame.key && !reveal && Object.keys(frame).every((k) => k === "ts" || k === "v")) return frames.length;
|
|
42741
43012
|
if (reveal) frame.reveal = reveal;
|
|
42742
43013
|
const kept = trim([...frames, frame]);
|
|
42743
|
-
writeFileAtomic(
|
|
43014
|
+
writeFileAtomic(join39(dir, TIMELINE_FILE), kept.map((f) => JSON.stringify(f)).join("\n") + "\n");
|
|
42744
43015
|
writeTimelineJs(dir, kept);
|
|
42745
43016
|
return kept.length;
|
|
42746
43017
|
}
|
|
@@ -42762,8 +43033,8 @@ var init_studio_timeline = __esm({
|
|
|
42762
43033
|
"src/studio-timeline.ts"() {
|
|
42763
43034
|
init_progress();
|
|
42764
43035
|
init_studio_page();
|
|
42765
|
-
TIMELINE_FILE =
|
|
42766
|
-
TIMELINE_JS =
|
|
43036
|
+
TIMELINE_FILE = join39(".himi", "studio", "timeline.jsonl");
|
|
43037
|
+
TIMELINE_JS = join39(".himi", "studio", "timeline.js");
|
|
42767
43038
|
MAX_FRAMES = 2e3;
|
|
42768
43039
|
KEYFRAME_EVERY = 50;
|
|
42769
43040
|
same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
@@ -42786,6 +43057,7 @@ var init_studio_timeline = __esm({
|
|
|
42786
43057
|
var studio_exports = {};
|
|
42787
43058
|
__export(studio_exports, {
|
|
42788
43059
|
EDGES_RECORD: () => EDGES_RECORD,
|
|
43060
|
+
MAP_RECORD: () => MAP_RECORD,
|
|
42789
43061
|
PUSH_RECORD: () => PUSH_RECORD,
|
|
42790
43062
|
RUN_RECORD: () => RUN_RECORD,
|
|
42791
43063
|
STUDIO_DIR: () => STUDIO_DIR,
|
|
@@ -42800,8 +43072,8 @@ __export(studio_exports, {
|
|
|
42800
43072
|
writeStudioRecord: () => writeStudioRecord
|
|
42801
43073
|
});
|
|
42802
43074
|
import { createHash as createHash21 } from "node:crypto";
|
|
42803
|
-
import { existsSync as
|
|
42804
|
-
import { basename as basename10, extname as extname3, join as
|
|
43075
|
+
import { existsSync as existsSync42, readdirSync as readdirSync23, readFileSync as readFileSync45, realpathSync as realpathSync5, statSync as statSync8 } from "node:fs";
|
|
43076
|
+
import { basename as basename10, extname as extname3, join as join40, relative as relative7, resolve as resolve33, sep as sep9 } from "node:path";
|
|
42805
43077
|
import { pathToFileURL as pathToFileURL7 } from "node:url";
|
|
42806
43078
|
function realInside(dir, abs) {
|
|
42807
43079
|
try {
|
|
@@ -42826,12 +43098,12 @@ function archiveFile(dir, memory, abs) {
|
|
|
42826
43098
|
if (size === 0) return null;
|
|
42827
43099
|
const key2 = relative7(dir, abs);
|
|
42828
43100
|
const hit = memory.files?.[key2];
|
|
42829
|
-
if (hit && hit.size === size && hit.mtimeMs === mtimeMs && hit.ino === ino &&
|
|
43101
|
+
if (hit && hit.size === size && hit.mtimeMs === mtimeMs && hit.ino === ino && existsSync42(join40(dir, HISTORY_DIR, `${hit.sha}.${hit.ext}`))) {
|
|
42830
43102
|
return { sha: hit.sha, ext: hit.ext, file: `${hit.sha}.${hit.ext}` };
|
|
42831
43103
|
}
|
|
42832
43104
|
let archived;
|
|
42833
43105
|
try {
|
|
42834
|
-
archived = archiveBytes(dir,
|
|
43106
|
+
archived = archiveBytes(dir, readFileSync45(real));
|
|
42835
43107
|
} catch {
|
|
42836
43108
|
return null;
|
|
42837
43109
|
}
|
|
@@ -42840,17 +43112,17 @@ function archiveFile(dir, memory, abs) {
|
|
|
42840
43112
|
return { sha: archived.sha256, ext: archived.ext, file: `${archived.sha256}.${archived.ext}` };
|
|
42841
43113
|
}
|
|
42842
43114
|
function loadMemory(dir, now) {
|
|
42843
|
-
const raw = obj(
|
|
43115
|
+
const raw = obj(readJson3(join40(dir, MEMORY_FILE)));
|
|
42844
43116
|
if (raw && raw.version === 1 && obj(raw.shots) && Array.isArray(raw.timeline)) return raw;
|
|
42845
43117
|
return { version: 1, createdAt: now, shots: {}, timeline: [] };
|
|
42846
43118
|
}
|
|
42847
43119
|
function observeShots(dir, memory, now) {
|
|
42848
|
-
const shotsDir =
|
|
43120
|
+
const shotsDir = join40(dir, ".himi", "shots");
|
|
42849
43121
|
const seen = /* @__PURE__ */ new Set();
|
|
42850
|
-
const files =
|
|
43122
|
+
const files = existsSync42(shotsDir) ? readdirSync23(shotsDir).filter((f) => /\.(png|jpe?g)$/i.test(f)).sort() : [];
|
|
42851
43123
|
for (const f of files) {
|
|
42852
43124
|
const id = basename10(f, extname3(f));
|
|
42853
|
-
const archived = archiveFile(dir, memory,
|
|
43125
|
+
const archived = archiveFile(dir, memory, join40(shotsDir, f));
|
|
42854
43126
|
if (!archived) continue;
|
|
42855
43127
|
seen.add(id);
|
|
42856
43128
|
const { sha, ext } = archived;
|
|
@@ -42865,14 +43137,14 @@ function observeShots(dir, memory, now) {
|
|
|
42865
43137
|
memory.shots[id] = { ...prev, present: true };
|
|
42866
43138
|
}
|
|
42867
43139
|
}
|
|
42868
|
-
if (
|
|
43140
|
+
if (existsSync42(shotsDir)) {
|
|
42869
43141
|
for (const [id, shot] of Object.entries(memory.shots)) if (!seen.has(id) && shot.present) memory.shots[id] = { ...shot, present: false };
|
|
42870
43142
|
}
|
|
42871
43143
|
if (memory.timeline.length > MAX_TIMELINE) memory.timeline = memory.timeline.slice(-MAX_TIMELINE);
|
|
42872
43144
|
return memory;
|
|
42873
43145
|
}
|
|
42874
43146
|
function palette(dir) {
|
|
42875
|
-
const colors = obj(obj(
|
|
43147
|
+
const colors = obj(obj(readJson3(join40(dir, "tokens.json")))?.colors);
|
|
42876
43148
|
if (!colors) return [];
|
|
42877
43149
|
const pick2 = (key2) => {
|
|
42878
43150
|
const v = colors[key2];
|
|
@@ -42882,7 +43154,7 @@ function palette(dir) {
|
|
|
42882
43154
|
return ["accentPrimary", "accentSecondary", "accentSurface", "surfacePrimary", "textPrimary"].map(pick2).filter((x) => !!x);
|
|
42883
43155
|
}
|
|
42884
43156
|
function appIdentity(dir) {
|
|
42885
|
-
const manifest = obj(
|
|
43157
|
+
const manifest = obj(readJson3(join40(dir, "himalaya.content.json")));
|
|
42886
43158
|
const name = text(manifest?.name) ?? basename10(resolve33(dir));
|
|
42887
43159
|
const icon = text(manifest?.icon)?.trim();
|
|
42888
43160
|
const iconPath = icon ? resolve33(dir, icon) : null;
|
|
@@ -42890,12 +43162,12 @@ function appIdentity(dir) {
|
|
|
42890
43162
|
return { name, iconFile: real && statSync8(real).isFile() ? iconPath : null };
|
|
42891
43163
|
}
|
|
42892
43164
|
function testRuns(dir) {
|
|
42893
|
-
const att =
|
|
42894
|
-
if (!
|
|
43165
|
+
const att = join40(dir, ".himi", "attestations");
|
|
43166
|
+
if (!existsSync42(att)) return [];
|
|
42895
43167
|
const runs = [];
|
|
42896
|
-
for (const f of
|
|
43168
|
+
for (const f of readdirSync23(att)) {
|
|
42897
43169
|
if (!f.endsWith(".json") || f === "latest.json") continue;
|
|
42898
|
-
const r = obj(
|
|
43170
|
+
const r = obj(readJson3(join40(att, f)));
|
|
42899
43171
|
if (!r || r.tool !== "himi-test" || typeof r.runId !== "string") continue;
|
|
42900
43172
|
const report2 = obj(r.report);
|
|
42901
43173
|
const coverage = obj(r.coverage);
|
|
@@ -42911,20 +43183,20 @@ function testRuns(dir) {
|
|
|
42911
43183
|
return runs.sort((a, b) => a.runId.localeCompare(b.runId));
|
|
42912
43184
|
}
|
|
42913
43185
|
function siteHome(dir) {
|
|
42914
|
-
for (const pages of [
|
|
42915
|
-
if (!
|
|
42916
|
-
const home =
|
|
42917
|
-
if (home) return
|
|
43186
|
+
for (const pages of [join40(dir, ".himi", "business-book", "evidence", "pages"), join40(dir, "evidence", "pages")]) {
|
|
43187
|
+
if (!existsSync42(pages)) continue;
|
|
43188
|
+
const home = readdirSync23(pages).filter((f) => /^home.*\.(png|jpe?g)$/i.test(f)).sort()[0];
|
|
43189
|
+
if (home) return join40(pages, home);
|
|
42918
43190
|
}
|
|
42919
43191
|
return null;
|
|
42920
43192
|
}
|
|
42921
43193
|
function uxStatuses(dir) {
|
|
42922
|
-
const platforms = obj(obj(
|
|
43194
|
+
const platforms = obj(obj(readJson3(join40(dir, ".himi", "ux-audit.json")))?.platforms);
|
|
42923
43195
|
if (!platforms) return [];
|
|
42924
43196
|
return Object.entries(platforms).map(([platform, rec]) => ({ platform, status: text(obj(rec)?.status) ?? "" })).filter((p) => p.status);
|
|
42925
43197
|
}
|
|
42926
43198
|
function liveRun(dir) {
|
|
42927
|
-
const rec = obj(
|
|
43199
|
+
const rec = obj(readJson3(join40(dir, RUN_RECORD)));
|
|
42928
43200
|
const url = text(rec?.url);
|
|
42929
43201
|
const pid = rec?.pid;
|
|
42930
43202
|
if (!url || !/^https?:\/\//i.test(url) || typeof pid !== "number") return null;
|
|
@@ -42945,7 +43217,8 @@ function liveRun(dir) {
|
|
|
42945
43217
|
ms: typeof build2.ms === "number" && Number.isFinite(build2.ms) ? Math.max(0, Math.round(build2.ms)) : null,
|
|
42946
43218
|
screens: (Array.isArray(build2.screens) ? build2.screens : []).filter((x) => typeof x === "string").slice(0, 20),
|
|
42947
43219
|
tokens: build2.tokens === true,
|
|
42948
|
-
config: build2.config === true
|
|
43220
|
+
config: build2.config === true,
|
|
43221
|
+
...changesOf(build2.changes)
|
|
42949
43222
|
} : null,
|
|
42950
43223
|
lan: lanOf(rec?.lanUrl)
|
|
42951
43224
|
};
|
|
@@ -42953,6 +43226,47 @@ function liveRun(dir) {
|
|
|
42953
43226
|
return null;
|
|
42954
43227
|
}
|
|
42955
43228
|
}
|
|
43229
|
+
function mapOf(value) {
|
|
43230
|
+
const raw = obj(value);
|
|
43231
|
+
if (!raw || !Array.isArray(raw.screens)) return null;
|
|
43232
|
+
const screens = [];
|
|
43233
|
+
const ids = /* @__PURE__ */ new Set();
|
|
43234
|
+
for (const it of raw.screens.slice(0, 300)) {
|
|
43235
|
+
const o = obj(it);
|
|
43236
|
+
const id = typeof o?.id === "string" ? o.id.slice(0, 120) : null;
|
|
43237
|
+
if (!o || !id || ids.has(id) || typeof o.status !== "string" || !MAP_STATUSES.has(o.status)) continue;
|
|
43238
|
+
ids.add(id);
|
|
43239
|
+
screens.push({ id, entry: o.entry === true, reached: o.reached === true, status: o.status, unfollowed: count(o.unfollowed) });
|
|
43240
|
+
}
|
|
43241
|
+
if (!screens.length) return null;
|
|
43242
|
+
const link = (it, needTo) => {
|
|
43243
|
+
const o = obj(it);
|
|
43244
|
+
const from = typeof o?.from === "string" ? o.from.slice(0, 120) : null;
|
|
43245
|
+
const to = typeof o?.to === "string" ? o.to.slice(0, 120) : null;
|
|
43246
|
+
if (!from || !to || !ids.has(from) || needTo && !ids.has(to)) return null;
|
|
43247
|
+
return { from, to, via: typeof o?.via === "string" ? o.via.slice(0, 120) : "" };
|
|
43248
|
+
};
|
|
43249
|
+
const edges = (Array.isArray(raw.edges) ? raw.edges.slice(0, 600) : []).map((e) => link(e, true)).filter((e) => !!e);
|
|
43250
|
+
const broken = (Array.isArray(raw.broken) ? raw.broken.slice(0, 100) : []).map((e) => link(e, false)).filter((e) => !!e);
|
|
43251
|
+
return { screens, edges, broken, unfollowed: count(raw.unfollowed), edgesDropped: count(raw.edgesDropped), done: raw.done === true };
|
|
43252
|
+
}
|
|
43253
|
+
function changesOf(value) {
|
|
43254
|
+
const raw = obj(value);
|
|
43255
|
+
const items = [];
|
|
43256
|
+
for (const it of Array.isArray(raw?.items) ? raw.items.slice(0, 12) : []) {
|
|
43257
|
+
const o = obj(it);
|
|
43258
|
+
if (!o || typeof o.kind !== "string" || !CHANGE_KINDS.has(o.kind)) continue;
|
|
43259
|
+
const c = { kind: o.kind };
|
|
43260
|
+
for (const k of ["screen", "node", "type", "path", "from", "to"]) {
|
|
43261
|
+
if (typeof o[k] === "string") c[k] = o[k].slice(0, 80);
|
|
43262
|
+
}
|
|
43263
|
+
items.push(c);
|
|
43264
|
+
}
|
|
43265
|
+
if (!items.length) return { headline: null, changes: null };
|
|
43266
|
+
const more = typeof raw?.more === "number" && Number.isFinite(raw.more) ? Math.max(0, Math.round(raw.more)) : 0;
|
|
43267
|
+
const changes = { items, more };
|
|
43268
|
+
return { headline: headline(changes), changes: boardLines(changes) };
|
|
43269
|
+
}
|
|
42956
43270
|
function lanOf(value) {
|
|
42957
43271
|
const raw = text(value);
|
|
42958
43272
|
if (!raw) return null;
|
|
@@ -42992,9 +43306,9 @@ function buildView(dir, memory, now) {
|
|
|
42992
43306
|
const runs = testRuns(dir);
|
|
42993
43307
|
const last = runs[runs.length - 1];
|
|
42994
43308
|
const prev = runs[runs.length - 2];
|
|
42995
|
-
const validate3 = obj(
|
|
42996
|
-
const push = obj(
|
|
42997
|
-
const edges =
|
|
43309
|
+
const validate3 = obj(readJson3(join40(dir, VALIDATE_RECORD)));
|
|
43310
|
+
const push = obj(readJson3(join40(dir, PUSH_RECORD)));
|
|
43311
|
+
const edges = readJson3(join40(dir, EDGES_RECORD));
|
|
42998
43312
|
const nav = [];
|
|
42999
43313
|
if (Array.isArray(edges)) {
|
|
43000
43314
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -43032,6 +43346,7 @@ function buildView(dir, memory, now) {
|
|
|
43032
43346
|
},
|
|
43033
43347
|
brand: { site: siteImg },
|
|
43034
43348
|
nav,
|
|
43349
|
+
map: mapOf(readJson3(join40(dir, MAP_RECORD))),
|
|
43035
43350
|
live: liveRun(dir),
|
|
43036
43351
|
timelineFrames: 0,
|
|
43037
43352
|
reveal: memory.reveal ?? null
|
|
@@ -43065,15 +43380,15 @@ function writeBoard(dir, now) {
|
|
|
43065
43380
|
} catch {
|
|
43066
43381
|
view.timelineFrames = 0;
|
|
43067
43382
|
}
|
|
43068
|
-
writeAtomic(
|
|
43069
|
-
writeAtomic(
|
|
43383
|
+
writeAtomic(join40(dir, MEMORY_FILE), JSON.stringify(memory));
|
|
43384
|
+
writeAtomic(join40(dir, STATE_FILE), `window.__himiStudio && window.__himiStudio(${scriptJson(view)});
|
|
43070
43385
|
`);
|
|
43071
|
-
writeAtomic(
|
|
43386
|
+
writeAtomic(join40(dir, STUDIO_PAGE), renderStudioHtml(view));
|
|
43072
43387
|
return view;
|
|
43073
43388
|
}
|
|
43074
43389
|
function refreshStudio(dir, now = /* @__PURE__ */ new Date()) {
|
|
43075
43390
|
try {
|
|
43076
|
-
if (!
|
|
43391
|
+
if (!existsSync42(join40(dir, STUDIO_PAGE))) return { refreshed: false };
|
|
43077
43392
|
return { refreshed: true, view: writeBoard(dir, now.toISOString()) };
|
|
43078
43393
|
} catch {
|
|
43079
43394
|
return { refreshed: false };
|
|
@@ -43081,39 +43396,41 @@ function refreshStudio(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
43081
43396
|
}
|
|
43082
43397
|
function openStudio(dir, now = /* @__PURE__ */ new Date()) {
|
|
43083
43398
|
const view = writeBoard(dir, now.toISOString());
|
|
43084
|
-
const page =
|
|
43399
|
+
const page = join40(dir, STUDIO_PAGE);
|
|
43085
43400
|
return { page, url: pathToFileURL7(page).href, view };
|
|
43086
43401
|
}
|
|
43087
43402
|
function writeStudioRecord(dir, record2, value) {
|
|
43088
43403
|
try {
|
|
43089
43404
|
if (!realDirIn(dir, ".himi")) return;
|
|
43090
|
-
writeAtomic(
|
|
43405
|
+
writeAtomic(join40(dir, record2), `${JSON.stringify(value, null, 2)}
|
|
43091
43406
|
`);
|
|
43092
43407
|
} catch {
|
|
43093
43408
|
}
|
|
43094
43409
|
}
|
|
43095
|
-
var STUDIO_DIR, STUDIO_PAGE, STATE_FILE, MEMORY_FILE, VALIDATE_RECORD, PUSH_RECORD, EDGES_RECORD, RUN_RECORD, MAX_TIMELINE, MAX_JOURNAL, MAX_NAV_EDGES,
|
|
43410
|
+
var STUDIO_DIR, STUDIO_PAGE, STATE_FILE, MEMORY_FILE, VALIDATE_RECORD, PUSH_RECORD, EDGES_RECORD, MAP_RECORD, RUN_RECORD, MAX_TIMELINE, MAX_JOURNAL, MAX_NAV_EDGES, readJson3, obj, num, text, historyUrl, runTime, MAP_STATUSES, count, CHANGE_KINDS;
|
|
43096
43411
|
var init_studio = __esm({
|
|
43097
43412
|
"src/studio.ts"() {
|
|
43098
43413
|
init_studio_page();
|
|
43099
43414
|
init_qr();
|
|
43415
|
+
init_build_changes();
|
|
43100
43416
|
init_studio_timeline();
|
|
43101
43417
|
init_progress();
|
|
43102
43418
|
init_studio_page();
|
|
43103
|
-
STUDIO_DIR =
|
|
43104
|
-
STUDIO_PAGE =
|
|
43105
|
-
STATE_FILE =
|
|
43106
|
-
MEMORY_FILE =
|
|
43107
|
-
VALIDATE_RECORD =
|
|
43108
|
-
PUSH_RECORD =
|
|
43109
|
-
EDGES_RECORD =
|
|
43110
|
-
|
|
43419
|
+
STUDIO_DIR = join40(".himi", "studio");
|
|
43420
|
+
STUDIO_PAGE = join40(STUDIO_DIR, "index.html");
|
|
43421
|
+
STATE_FILE = join40(STUDIO_DIR, "state.js");
|
|
43422
|
+
MEMORY_FILE = join40(STUDIO_DIR, "memory.json");
|
|
43423
|
+
VALIDATE_RECORD = join40(".himi", "validate.json");
|
|
43424
|
+
PUSH_RECORD = join40(".himi", "last-push.json");
|
|
43425
|
+
EDGES_RECORD = join40(".himi", "test-edges.json");
|
|
43426
|
+
MAP_RECORD = join40(".himi", "test-map.json");
|
|
43427
|
+
RUN_RECORD = join40(".himi", "run.json");
|
|
43111
43428
|
MAX_TIMELINE = 500;
|
|
43112
43429
|
MAX_JOURNAL = 80;
|
|
43113
43430
|
MAX_NAV_EDGES = 40;
|
|
43114
|
-
|
|
43431
|
+
readJson3 = (file) => {
|
|
43115
43432
|
try {
|
|
43116
|
-
return JSON.parse(
|
|
43433
|
+
return JSON.parse(readFileSync45(file, "utf8"));
|
|
43117
43434
|
} catch {
|
|
43118
43435
|
return null;
|
|
43119
43436
|
}
|
|
@@ -43123,6 +43440,9 @@ var init_studio = __esm({
|
|
|
43123
43440
|
text = (v) => typeof v === "string" && v ? v : null;
|
|
43124
43441
|
historyUrl = (fileName) => `../history/${fileName}`;
|
|
43125
43442
|
runTime = (runId) => runId.replace(/-[0-9a-f]+$/i, "");
|
|
43443
|
+
MAP_STATUSES = /* @__PURE__ */ new Set(["ok", "failed", "pending", "skipped"]);
|
|
43444
|
+
count = (v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? Math.min(Math.round(v), 1e5) : 0;
|
|
43445
|
+
CHANGE_KINDS = /* @__PURE__ */ new Set(["text", "prop", "added", "removed", "token", "descriptor", "logic", "screen-added", "screen-removed"]);
|
|
43126
43446
|
}
|
|
43127
43447
|
});
|
|
43128
43448
|
|
|
@@ -43412,16 +43732,16 @@ function regressionDiff(base, live2, touched) {
|
|
|
43412
43732
|
rows.push({ item: `screen:${id}`, live: resolveBundleSha(live2, l.bundle), base: resolveBundleSha(base, b.bundle), effect: `${id} rebinds to its ${base.releaseId} worker bundle` });
|
|
43413
43733
|
}
|
|
43414
43734
|
}
|
|
43415
|
-
const
|
|
43735
|
+
const scalar4 = (key2, item, what) => {
|
|
43416
43736
|
if (moves.has(item)) return;
|
|
43417
43737
|
const l = live2[key2] ?? null;
|
|
43418
43738
|
const b = base[key2] ?? null;
|
|
43419
43739
|
if (l !== b) rows.push({ item, live: l, base: b, effect: `${what} reverts to ${base.releaseId}` });
|
|
43420
43740
|
};
|
|
43421
|
-
|
|
43422
|
-
|
|
43423
|
-
|
|
43424
|
-
|
|
43741
|
+
scalar4("tokensHash", "tokens", "design tokens");
|
|
43742
|
+
scalar4("appConfigHash", "app-config", "app-config");
|
|
43743
|
+
scalar4("iconHash", "icon", "the launcher icon");
|
|
43744
|
+
scalar4("minBinaryVersion", "minBinaryVersion", "the minimum binary version");
|
|
43425
43745
|
for (const name of /* @__PURE__ */ new Set([...Object.keys(live2.assets ?? {}), ...Object.keys(base.assets ?? {})])) {
|
|
43426
43746
|
const l = live2.assets?.[name]?.sha256 ?? null;
|
|
43427
43747
|
const b = base.assets?.[name]?.sha256 ?? null;
|
|
@@ -43601,11 +43921,11 @@ __export(captcha_exports, {
|
|
|
43601
43921
|
captchaContentInput: () => captchaContentInput,
|
|
43602
43922
|
runCaptcha: () => runCaptcha
|
|
43603
43923
|
});
|
|
43604
|
-
import { readFileSync as
|
|
43924
|
+
import { readFileSync as readFileSync46 } from "node:fs";
|
|
43605
43925
|
import { resolve as resolve34 } from "node:path";
|
|
43606
43926
|
function readObject(path2) {
|
|
43607
43927
|
try {
|
|
43608
|
-
return JSON.parse(
|
|
43928
|
+
return JSON.parse(readFileSync46(path2, "utf8"));
|
|
43609
43929
|
} catch {
|
|
43610
43930
|
return {};
|
|
43611
43931
|
}
|
|
@@ -43749,11 +44069,11 @@ var init_push_setup_apple_credentials = __esm({
|
|
|
43749
44069
|
});
|
|
43750
44070
|
|
|
43751
44071
|
// src/push-onboarding.ts
|
|
43752
|
-
import { existsSync as
|
|
43753
|
-
import { basename as basename11, dirname as dirname24, join as
|
|
43754
|
-
function
|
|
44072
|
+
import { existsSync as existsSync43, mkdirSync as mkdirSync19, readFileSync as readFileSync47, statSync as statSync9, writeFileSync as writeFileSync15, chmodSync as chmodSync2 } from "node:fs";
|
|
44073
|
+
import { basename as basename11, dirname as dirname24, join as join41, resolve as resolve35 } from "node:path";
|
|
44074
|
+
function readJson4(path2) {
|
|
43755
44075
|
try {
|
|
43756
|
-
const parsed = JSON.parse(
|
|
44076
|
+
const parsed = JSON.parse(readFileSync47(path2, "utf8"));
|
|
43757
44077
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
43758
44078
|
} catch {
|
|
43759
44079
|
return {};
|
|
@@ -43761,9 +44081,9 @@ function readJson3(path2) {
|
|
|
43761
44081
|
}
|
|
43762
44082
|
function pushInputsFromContent(dir) {
|
|
43763
44083
|
const root = resolve35(dir);
|
|
43764
|
-
if (!
|
|
43765
|
-
const content =
|
|
43766
|
-
const provisioning =
|
|
44084
|
+
if (!existsSync43(join41(root, "himalaya.content.json"))) return { initialized: false };
|
|
44085
|
+
const content = readJson4(join41(root, "himalaya.content.json"));
|
|
44086
|
+
const provisioning = readJson4(join41(root, "provisioning.json"));
|
|
43767
44087
|
const native = provisioning.native ?? {};
|
|
43768
44088
|
return {
|
|
43769
44089
|
initialized: true,
|
|
@@ -43838,7 +44158,7 @@ function readKeyFile(path2) {
|
|
|
43838
44158
|
}
|
|
43839
44159
|
let body;
|
|
43840
44160
|
try {
|
|
43841
|
-
body =
|
|
44161
|
+
body = readFileSync47(path2, "utf8");
|
|
43842
44162
|
} catch {
|
|
43843
44163
|
return { ok: false, code: "key_file_unreadable", reason: "cannot read the selected key file; check its path and file permissions" };
|
|
43844
44164
|
}
|
|
@@ -43892,13 +44212,13 @@ function buildPushSetupBody(i, keys) {
|
|
|
43892
44212
|
};
|
|
43893
44213
|
}
|
|
43894
44214
|
function readPushOnboarding(dir) {
|
|
43895
|
-
const path2 =
|
|
43896
|
-
if (!
|
|
43897
|
-
const parsed =
|
|
44215
|
+
const path2 = join41(resolve35(dir), PUSH_ONBOARDING_PATH);
|
|
44216
|
+
if (!existsSync43(path2)) return { version: 1 };
|
|
44217
|
+
const parsed = readJson4(path2);
|
|
43898
44218
|
return { version: 1, ...parsed };
|
|
43899
44219
|
}
|
|
43900
44220
|
function writeFile(dir, file) {
|
|
43901
|
-
const path2 =
|
|
44221
|
+
const path2 = join41(resolve35(dir), PUSH_ONBOARDING_PATH);
|
|
43902
44222
|
mkdirSync19(dirname24(path2), { recursive: true, mode: 448 });
|
|
43903
44223
|
writeFileSync15(path2, JSON.stringify(file, null, 2) + "\n", { mode: 384 });
|
|
43904
44224
|
try {
|
|
@@ -43927,8 +44247,8 @@ function recordPushDeferral(dir, d) {
|
|
|
43927
44247
|
return push;
|
|
43928
44248
|
}
|
|
43929
44249
|
function clearPushDeferral(dir) {
|
|
43930
|
-
const path2 =
|
|
43931
|
-
if (!
|
|
44250
|
+
const path2 = join41(resolve35(dir), PUSH_ONBOARDING_PATH);
|
|
44251
|
+
if (!existsSync43(path2)) return;
|
|
43932
44252
|
const { push: _dropped, ...rest } = readPushOnboarding(dir);
|
|
43933
44253
|
writeFile(dir, { ...rest, version: 1 });
|
|
43934
44254
|
}
|
|
@@ -44699,8 +45019,8 @@ __export(template_trim_exports, {
|
|
|
44699
45019
|
routeMatcher: () => routeMatcher,
|
|
44700
45020
|
runTemplateTrim: () => runTemplateTrim
|
|
44701
45021
|
});
|
|
44702
|
-
import { cpSync, existsSync as
|
|
44703
|
-
import { dirname as dirname25, join as
|
|
45022
|
+
import { cpSync, existsSync as existsSync44, mkdirSync as mkdirSync20, readdirSync as readdirSync24, readFileSync as readFileSync48, renameSync as renameSync5, rmSync as rmSync8, statSync as statSync10, writeFileSync as writeFileSync16 } from "node:fs";
|
|
45023
|
+
import { dirname as dirname25, join as join42 } from "node:path";
|
|
44704
45024
|
function routeMatcher(pattern) {
|
|
44705
45025
|
const detail = /^\^([A-Za-z0-9_]+)\(\?:\[_\/\]\(\.\+\)\)\?\$$/.exec(pattern);
|
|
44706
45026
|
if (detail) {
|
|
@@ -44815,8 +45135,8 @@ function parseApp(dev, config) {
|
|
|
44815
45135
|
while (!dev.startsWith("})", pos)) {
|
|
44816
45136
|
ENTRY.lastIndex = pos;
|
|
44817
45137
|
const m = ENTRY.exec(dev);
|
|
44818
|
-
if (!m) throw new TrimRefusal(`dev/index.ts line ${
|
|
44819
|
-
const id = jsonString(m[1], `dev/index.ts line ${
|
|
45138
|
+
if (!m) throw new TrimRefusal(`dev/index.ts line ${lineOf2(dev, pos)}: expected a \`"<screenId>": {\` entry of the SCREENS map`);
|
|
45139
|
+
const id = jsonString(m[1], `dev/index.ts line ${lineOf2(dev, pos)}: the SCREENS key`);
|
|
44820
45140
|
const open = pos + m[0].length - 1;
|
|
44821
45141
|
const close = objectEnd(dev, open);
|
|
44822
45142
|
if (close < 0 || dev.slice(close, close + 2) !== ",\n") {
|
|
@@ -44845,9 +45165,9 @@ function parseApp(dev, config) {
|
|
|
44845
45165
|
if (dev.startsWith("];", pos) || dev.startsWith("\n];", pos)) break;
|
|
44846
45166
|
TENTRY.lastIndex = pos;
|
|
44847
45167
|
const m = TENTRY.exec(dev);
|
|
44848
|
-
if (!m) throw new TrimRefusal(`dev/index.ts line ${
|
|
44849
|
-
const pattern = jsonString(m[1], `dev/index.ts line ${
|
|
44850
|
-
const display = jsonString(m[2], `dev/index.ts line ${
|
|
45168
|
+
if (!m) throw new TrimRefusal(`dev/index.ts line ${lineOf2(dev, pos)}: expected a \`{ pattern: \u2026, display: \u2026, template: {\u2026} },\` entry of TEMPLATED`);
|
|
45169
|
+
const pattern = jsonString(m[1], `dev/index.ts line ${lineOf2(dev, pos)}: the TEMPLATED pattern`);
|
|
45170
|
+
const display = jsonString(m[2], `dev/index.ts line ${lineOf2(dev, pos)}: the TEMPLATED display`);
|
|
44851
45171
|
const lineEnd = dev.indexOf("\n", pos);
|
|
44852
45172
|
const tk = dev.indexOf("template: {", pos);
|
|
44853
45173
|
if (tk < 0 || tk > lineEnd) throw new TrimRefusal(`dev/index.ts: the templated route ${display} has no \`template: {\` on its first line`);
|
|
@@ -45319,7 +45639,7 @@ function planTrim(src, keepIds, links) {
|
|
|
45319
45639
|
const homeModules = links === "drop" ? homeModulesPass(app, kept, edited) : void 0;
|
|
45320
45640
|
let dev = "";
|
|
45321
45641
|
let cursor = 0;
|
|
45322
|
-
const
|
|
45642
|
+
const cut2 = (from, to, replacement = "") => {
|
|
45323
45643
|
dev += app.dev.slice(cursor, from) + replacement;
|
|
45324
45644
|
cursor = to;
|
|
45325
45645
|
};
|
|
@@ -45328,15 +45648,15 @@ function planTrim(src, keepIds, links) {
|
|
|
45328
45648
|
for (const r of app.routes) {
|
|
45329
45649
|
if (templatedEmptied && r.kind === "templated") continue;
|
|
45330
45650
|
if (!kept.has(r)) {
|
|
45331
|
-
|
|
45651
|
+
cut2(r.lineStart, r.end);
|
|
45332
45652
|
continue;
|
|
45333
45653
|
}
|
|
45334
45654
|
const block = edited.get(r);
|
|
45335
45655
|
let text5 = block ? serializeAt(block, app.dev, r.open) : void 0;
|
|
45336
45656
|
if (r === app.home && homeModules?.text !== void 0) text5 = homeModules.text;
|
|
45337
|
-
if (text5 !== void 0)
|
|
45657
|
+
if (text5 !== void 0) cut2(r.open, r.close, text5);
|
|
45338
45658
|
}
|
|
45339
|
-
if (templatedEmptied)
|
|
45659
|
+
if (templatedEmptied) cut2(templatedEmptied[0], templatedEmptied[1], "\n");
|
|
45340
45660
|
dev += app.dev.slice(cursor);
|
|
45341
45661
|
let config = app.config;
|
|
45342
45662
|
const edits = [];
|
|
@@ -45394,20 +45714,20 @@ function homeModulesPass(app, kept, edited) {
|
|
|
45394
45714
|
return { text: patched.src, dropped: patched.droppedModules };
|
|
45395
45715
|
}
|
|
45396
45716
|
function listWorkers(dir) {
|
|
45397
|
-
const root =
|
|
45398
|
-
if (!
|
|
45399
|
-
const dirs =
|
|
45717
|
+
const root = join42(dir, "tier5-src");
|
|
45718
|
+
if (!existsSync44(root)) return { dirs: [], files: {} };
|
|
45719
|
+
const dirs = readdirSync24(root).filter((n) => statSync10(join42(root, n)).isDirectory()).sort();
|
|
45400
45720
|
const files = {};
|
|
45401
45721
|
const walk2 = (abs, rel) => {
|
|
45402
|
-
for (const name of
|
|
45722
|
+
for (const name of readdirSync24(abs)) {
|
|
45403
45723
|
if (name === "node_modules") continue;
|
|
45404
|
-
const p =
|
|
45724
|
+
const p = join42(abs, name);
|
|
45405
45725
|
const r = `${rel}/${name}`;
|
|
45406
45726
|
if (statSync10(p).isDirectory()) walk2(p, r);
|
|
45407
|
-
else if (/\.(?:[cm]?[jt]sx?|json)$/.test(name)) files[r] =
|
|
45727
|
+
else if (/\.(?:[cm]?[jt]sx?|json)$/.test(name)) files[r] = readFileSync48(p, "utf8");
|
|
45408
45728
|
}
|
|
45409
45729
|
};
|
|
45410
|
-
for (const d of dirs) walk2(
|
|
45730
|
+
for (const d of dirs) walk2(join42(root, d), `tier5-src/${d}`);
|
|
45411
45731
|
return { dirs, files };
|
|
45412
45732
|
}
|
|
45413
45733
|
function csv(v) {
|
|
@@ -45430,16 +45750,16 @@ async function runTemplateTrim(req, deps) {
|
|
|
45430
45750
|
links = req.links;
|
|
45431
45751
|
}
|
|
45432
45752
|
const dir = req.dir;
|
|
45433
|
-
const devPath =
|
|
45434
|
-
const configPath =
|
|
45435
|
-
if (!
|
|
45753
|
+
const devPath = join42(dir, "dev/index.ts");
|
|
45754
|
+
const configPath = join42(dir, "config.ts");
|
|
45755
|
+
if (!existsSync44(devPath) || !existsSync44(configPath)) {
|
|
45436
45756
|
return refuse3(new TrimRefusal(`${dir} has no dev/index.ts + config.ts \u2014 point --content at an app scaffolded with \`himi init --template\``));
|
|
45437
45757
|
}
|
|
45438
45758
|
if (isTemplateSourceTree(dir)) {
|
|
45439
45759
|
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`));
|
|
45440
45760
|
}
|
|
45441
|
-
const dev =
|
|
45442
|
-
const config =
|
|
45761
|
+
const dev = readFileSync48(devPath, "utf8");
|
|
45762
|
+
const config = readFileSync48(configPath, "utf8");
|
|
45443
45763
|
const workers = listWorkers(dir);
|
|
45444
45764
|
let plan;
|
|
45445
45765
|
try {
|
|
@@ -45449,23 +45769,23 @@ async function runTemplateTrim(req, deps) {
|
|
|
45449
45769
|
throw e;
|
|
45450
45770
|
}
|
|
45451
45771
|
if (req.dryRun) return { code: 0, result: { ok: true, dryRun: true, ...plan.report, validate: null } };
|
|
45452
|
-
const hadHimi =
|
|
45453
|
-
const backupRel =
|
|
45454
|
-
const backup =
|
|
45772
|
+
const hadHimi = existsSync44(join42(dir, ".himi"));
|
|
45773
|
+
const backupRel = join42(".himi", "trim-backup", (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-"));
|
|
45774
|
+
const backup = join42(dir, backupRel);
|
|
45455
45775
|
const originals = [[devPath, "dev/index.ts"], [configPath, "config.ts"]];
|
|
45456
45776
|
const moved = [];
|
|
45457
45777
|
const restore = () => {
|
|
45458
45778
|
for (const [path2, rel] of originals) {
|
|
45459
|
-
const original =
|
|
45460
|
-
if (!
|
|
45779
|
+
const original = readFileSync48(join42(backup, rel));
|
|
45780
|
+
if (!existsSync44(path2) || !readFileSync48(path2).equals(original)) writeFileSync16(path2, original);
|
|
45461
45781
|
}
|
|
45462
|
-
for (const name of [...moved].reverse()) renameSync5(
|
|
45782
|
+
for (const name of [...moved].reverse()) renameSync5(join42(backup, "tier5-src", name), join42(dir, "tier5-src", name));
|
|
45463
45783
|
moved.length = 0;
|
|
45464
45784
|
};
|
|
45465
45785
|
const apply = () => {
|
|
45466
45786
|
const moveDir = deps.moveDir ?? renameSync5;
|
|
45467
45787
|
for (const name of plan.removedWorkers) {
|
|
45468
|
-
moveDir(
|
|
45788
|
+
moveDir(join42(dir, "tier5-src", name), join42(backup, "tier5-src", name));
|
|
45469
45789
|
moved.push(name);
|
|
45470
45790
|
}
|
|
45471
45791
|
if (plan.dev !== dev) writeFileSync16(devPath, plan.dev);
|
|
@@ -45473,10 +45793,10 @@ async function runTemplateTrim(req, deps) {
|
|
|
45473
45793
|
};
|
|
45474
45794
|
const dropBackup = () => {
|
|
45475
45795
|
rmSync8(backup, { recursive: true, force: true });
|
|
45476
|
-
for (const d of [dirname25(backup),
|
|
45477
|
-
if (d ===
|
|
45796
|
+
for (const d of [dirname25(backup), join42(dir, ".himi")]) {
|
|
45797
|
+
if (d === join42(dir, ".himi") && hadHimi) break;
|
|
45478
45798
|
try {
|
|
45479
|
-
if (!
|
|
45799
|
+
if (!readdirSync24(d).length) rmSync8(d, { recursive: true });
|
|
45480
45800
|
} catch {
|
|
45481
45801
|
}
|
|
45482
45802
|
}
|
|
@@ -45500,9 +45820,9 @@ async function runTemplateTrim(req, deps) {
|
|
|
45500
45820
|
return { code: 1, result: { ok: false, error: `${error} (${message}); every file was restored`, rolledBack: true, ...base(validate4) } };
|
|
45501
45821
|
};
|
|
45502
45822
|
try {
|
|
45503
|
-
mkdirSync20(
|
|
45504
|
-
for (const [path2, rel] of originals) cpSync(path2,
|
|
45505
|
-
if (plan.removedWorkers.length) mkdirSync20(
|
|
45823
|
+
mkdirSync20(join42(backup, "dev"), { recursive: true });
|
|
45824
|
+
for (const [path2, rel] of originals) cpSync(path2, join42(backup, rel));
|
|
45825
|
+
if (plan.removedWorkers.length) mkdirSync20(join42(backup, "tier5-src"), { recursive: true });
|
|
45506
45826
|
} catch (e) {
|
|
45507
45827
|
dropBackup();
|
|
45508
45828
|
return { code: 1, result: { ok: false, error: `could not back up the app before trimming it (${e.message}); nothing was changed`, rolledBack: true, ...base() } };
|
|
@@ -45515,7 +45835,7 @@ async function runTemplateTrim(req, deps) {
|
|
|
45515
45835
|
let failure;
|
|
45516
45836
|
let validate3;
|
|
45517
45837
|
try {
|
|
45518
|
-
const written = parseApp(
|
|
45838
|
+
const written = parseApp(readFileSync48(devPath, "utf8"), readFileSync48(configPath, "utf8"));
|
|
45519
45839
|
const leftovers = leftoverNavRefs(written.nav.value, plan.removedIds);
|
|
45520
45840
|
if (leftovers.length) failure = { error: "navigation still names screens this trim removed", leftovers };
|
|
45521
45841
|
else {
|
|
@@ -45619,7 +45939,7 @@ function summarize3(errors) {
|
|
|
45619
45939
|
const shown2 = errors.slice(0, 5).map(one).join("; ");
|
|
45620
45940
|
return errors.length > 5 ? `${shown2}; and ${errors.length - 5} more` : shown2;
|
|
45621
45941
|
}
|
|
45622
|
-
var TrimRefusal, LIT, ATOM, QUANT, CAP, SAFE_ROUTE_PATTERN,
|
|
45942
|
+
var TrimRefusal, LIT, ATOM, QUANT, CAP, SAFE_ROUTE_PATTERN, lineOf2, isStatic, entryLabel, isNode3, asItems, NAV_SCREEN_KEYS, sorted, refuse3, plural;
|
|
45623
45943
|
var init_template_trim = __esm({
|
|
45624
45944
|
"src/template-trim.ts"() {
|
|
45625
45945
|
init_validate_descriptor();
|
|
@@ -45639,7 +45959,7 @@ var init_template_trim = __esm({
|
|
|
45639
45959
|
SAFE_ROUTE_PATTERN = new RegExp(
|
|
45640
45960
|
String.raw`^\^${LIT}(?:${CAP}${LIT}|\(\?:(?:${LIT}|\[(?:[^\]\\[]|\\.)+\])${CAP}\)\?)?\$$`
|
|
45641
45961
|
);
|
|
45642
|
-
|
|
45962
|
+
lineOf2 = (src, at) => src.slice(0, at).split("\n").length;
|
|
45643
45963
|
isStatic = (id) => typeof id === "string" && id !== "" && !id.startsWith("$");
|
|
45644
45964
|
entryLabel = (entry) => {
|
|
45645
45965
|
const id = entry?.id;
|
|
@@ -46188,10 +46508,10 @@ function parseZipEntries(buf) {
|
|
|
46188
46508
|
}
|
|
46189
46509
|
}
|
|
46190
46510
|
if (eocd < 0) throw new Error("not a zip archive (no end-of-central-directory record)");
|
|
46191
|
-
const
|
|
46511
|
+
const count2 = u16(eocd + 10);
|
|
46192
46512
|
let p = u32(eocd + 16);
|
|
46193
46513
|
const out = [];
|
|
46194
|
-
for (let i = 0; i <
|
|
46514
|
+
for (let i = 0; i < count2; i++) {
|
|
46195
46515
|
if (p + 46 > buf.length || u32(p) !== ZIP_CENTRAL_SIG) throw new Error("corrupt zip central directory");
|
|
46196
46516
|
const method = u16(p + 10);
|
|
46197
46517
|
const crc = u32(p + 16);
|
|
@@ -46283,8 +46603,8 @@ __export(pack_exports, {
|
|
|
46283
46603
|
});
|
|
46284
46604
|
import { createHash as createHash22 } from "node:crypto";
|
|
46285
46605
|
import { deflateRawSync, inflateRawSync } from "node:zlib";
|
|
46286
|
-
import { existsSync as
|
|
46287
|
-
import { dirname as dirname26, join as
|
|
46606
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync21, readFileSync as readFileSync49, readdirSync as readdirSync25, rmSync as rmSync9, statSync as statSync11, writeFileSync as writeFileSync17 } from "node:fs";
|
|
46607
|
+
import { dirname as dirname26, join as join43, resolve as resolve37 } from "node:path";
|
|
46288
46608
|
function writeZip(entries) {
|
|
46289
46609
|
const sorted2 = entries.slice().sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
46290
46610
|
const total = sorted2.reduce((n, e) => n + e.bytes.length, 0);
|
|
@@ -46378,13 +46698,13 @@ function inflateEntry(buf, entry) {
|
|
|
46378
46698
|
return bytes2;
|
|
46379
46699
|
}
|
|
46380
46700
|
function readIf(path2) {
|
|
46381
|
-
return
|
|
46701
|
+
return existsSync45(path2) && statSync11(path2).isFile() ? readFileSync49(path2) : null;
|
|
46382
46702
|
}
|
|
46383
46703
|
function listDir(dir) {
|
|
46384
|
-
return
|
|
46704
|
+
return existsSync45(dir) ? readdirSync25(dir).filter((f) => statSync11(join43(dir, f)).isFile()) : [];
|
|
46385
46705
|
}
|
|
46386
46706
|
function gatherReleaseEntries(appDir2) {
|
|
46387
|
-
const manifestPath =
|
|
46707
|
+
const manifestPath = join43(appDir2, HIMI_PACKAGE_MANIFEST_PATH);
|
|
46388
46708
|
const manifestBytes = readIf(manifestPath);
|
|
46389
46709
|
if (!manifestBytes) throw new Error(`no ${HIMI_PACKAGE_MANIFEST_PATH} in ${appDir2} \u2014 build a release there first`);
|
|
46390
46710
|
const manifest = JSON.parse(manifestBytes.toString("utf8"));
|
|
@@ -46408,7 +46728,7 @@ function gatherReleaseEntries(appDir2) {
|
|
|
46408
46728
|
}
|
|
46409
46729
|
const missing = [];
|
|
46410
46730
|
for (const rel of wanted) {
|
|
46411
|
-
const bytes2 = readIf(
|
|
46731
|
+
const bytes2 = readIf(join43(appDir2, rel));
|
|
46412
46732
|
if (bytes2) entries.push({ path: rel, bytes: bytes2 });
|
|
46413
46733
|
else missing.push(rel);
|
|
46414
46734
|
}
|
|
@@ -46419,12 +46739,12 @@ function gatherReleaseEntries(appDir2) {
|
|
|
46419
46739
|
);
|
|
46420
46740
|
}
|
|
46421
46741
|
for (const name of SINGLETONS) {
|
|
46422
|
-
const bytes2 = readIf(
|
|
46742
|
+
const bytes2 = readIf(join43(appDir2, name));
|
|
46423
46743
|
if (bytes2) entries.push({ path: name, bytes: bytes2 });
|
|
46424
46744
|
}
|
|
46425
46745
|
const skipped = [];
|
|
46426
46746
|
for (const sub of ["screens", "bundles", "assets", "widgets"]) {
|
|
46427
|
-
for (const f of listDir(
|
|
46747
|
+
for (const f of listDir(join43(appDir2, sub))) {
|
|
46428
46748
|
if (!wanted.has(`${sub}/${f}`)) skipped.push(`${sub}/${f}`);
|
|
46429
46749
|
}
|
|
46430
46750
|
}
|
|
@@ -46457,18 +46777,18 @@ function buildEntries(appDir2, app, opts) {
|
|
|
46457
46777
|
return { all, header, manifest, skipped };
|
|
46458
46778
|
}
|
|
46459
46779
|
function packRelease(releaseRoot, app, out, opts = {}) {
|
|
46460
|
-
const appDir2 =
|
|
46780
|
+
const appDir2 = join43(resolve37(releaseRoot), app);
|
|
46461
46781
|
const { all, header, skipped } = buildEntries(appDir2, app, opts);
|
|
46462
46782
|
const buf = writeZip(all);
|
|
46463
|
-
const isDir2 =
|
|
46464
|
-
const outFile = isDir2 ?
|
|
46783
|
+
const isDir2 = existsSync45(out) && statSync11(out).isDirectory();
|
|
46784
|
+
const outFile = isDir2 ? join43(resolve37(out), packageFileName(app, header.releaseId)) : resolve37(out);
|
|
46465
46785
|
mkdirSync21(dirname26(outFile), { recursive: true });
|
|
46466
46786
|
writeFileSync17(outFile, buf);
|
|
46467
46787
|
return { app, releaseId: header.releaseId, header, out: outFile, bytes: buf.length, entryCount: all.length, skipped };
|
|
46468
46788
|
}
|
|
46469
46789
|
function resolvePackageDirDest(outDir, app, releaseId) {
|
|
46470
46790
|
const packagedApp = (dir) => {
|
|
46471
|
-
const bytes2 = readIf(
|
|
46791
|
+
const bytes2 = readIf(join43(dir, HIMI_PACKAGE_HEADER_PATH));
|
|
46472
46792
|
if (!bytes2) return void 0;
|
|
46473
46793
|
try {
|
|
46474
46794
|
return JSON.parse(bytes2.toString("utf8")).app;
|
|
@@ -46477,15 +46797,15 @@ function resolvePackageDirDest(outDir, app, releaseId) {
|
|
|
46477
46797
|
}
|
|
46478
46798
|
};
|
|
46479
46799
|
const replaceable = (dir) => {
|
|
46480
|
-
if (!
|
|
46800
|
+
if (!existsSync45(dir)) return true;
|
|
46481
46801
|
if (!statSync11(dir).isDirectory()) return false;
|
|
46482
|
-
return
|
|
46802
|
+
return readdirSync25(dir).length === 0 || packagedApp(dir) === app;
|
|
46483
46803
|
};
|
|
46484
|
-
if (
|
|
46804
|
+
if (existsSync45(outDir) && !statSync11(outDir).isDirectory()) {
|
|
46485
46805
|
throw new Error(`refusing to write a package tree over ${outDir} \u2014 it is a file, not a directory`);
|
|
46486
46806
|
}
|
|
46487
46807
|
if (replaceable(outDir)) return outDir;
|
|
46488
|
-
const child =
|
|
46808
|
+
const child = join43(outDir, packageDirName(app, releaseId));
|
|
46489
46809
|
if (!replaceable(child)) {
|
|
46490
46810
|
throw new Error(
|
|
46491
46811
|
`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.`
|
|
@@ -46499,13 +46819,13 @@ function packReleaseToDir(releaseRoot, app, outDir, opts = {}) {
|
|
|
46499
46819
|
"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."
|
|
46500
46820
|
);
|
|
46501
46821
|
}
|
|
46502
|
-
const appDir2 =
|
|
46822
|
+
const appDir2 = join43(resolve37(releaseRoot), app);
|
|
46503
46823
|
const { all, header, skipped } = buildEntries(appDir2, app, opts);
|
|
46504
46824
|
const dest = resolvePackageDirDest(resolve37(outDir), app, header.releaseId);
|
|
46505
46825
|
rmSync9(dest, { recursive: true, force: true });
|
|
46506
46826
|
let bytes2 = 0;
|
|
46507
46827
|
for (const entry of all) {
|
|
46508
|
-
const target =
|
|
46828
|
+
const target = join43(dest, entry.path);
|
|
46509
46829
|
mkdirSync21(dirname26(target), { recursive: true });
|
|
46510
46830
|
writeFileSync17(target, entry.bytes);
|
|
46511
46831
|
bytes2 += entry.bytes.length;
|
|
@@ -46528,21 +46848,21 @@ function openPackageBuffer(buf) {
|
|
|
46528
46848
|
return openFromEntries(readZip(buf), { requireHeader: true });
|
|
46529
46849
|
}
|
|
46530
46850
|
function openPackageFile(file) {
|
|
46531
|
-
return openPackageBuffer(
|
|
46851
|
+
return openPackageBuffer(readFileSync49(file));
|
|
46532
46852
|
}
|
|
46533
46853
|
function openPackageDir(dir) {
|
|
46534
46854
|
const root = resolve37(dir);
|
|
46535
46855
|
const entries = /* @__PURE__ */ new Map();
|
|
46536
46856
|
const walk2 = (rel) => {
|
|
46537
|
-
const abs = rel ?
|
|
46538
|
-
for (const name of
|
|
46857
|
+
const abs = rel ? join43(root, rel) : root;
|
|
46858
|
+
for (const name of readdirSync25(abs)) {
|
|
46539
46859
|
const childRel = rel ? `${rel}/${name}` : name;
|
|
46540
|
-
const childAbs =
|
|
46860
|
+
const childAbs = join43(abs, name);
|
|
46541
46861
|
if (statSync11(childAbs).isDirectory()) walk2(childRel);
|
|
46542
|
-
else if (isSafeEntryName(childRel)) entries.set(childRel,
|
|
46862
|
+
else if (isSafeEntryName(childRel)) entries.set(childRel, readFileSync49(childAbs));
|
|
46543
46863
|
}
|
|
46544
46864
|
};
|
|
46545
|
-
if (!
|
|
46865
|
+
if (!existsSync45(root)) throw new Error(`no such package directory: ${root}`);
|
|
46546
46866
|
walk2("");
|
|
46547
46867
|
const manifestBytes = entries.get(HIMI_PACKAGE_MANIFEST_PATH);
|
|
46548
46868
|
if (manifestBytes) {
|
|
@@ -46584,10 +46904,10 @@ function unpackTo(buf, dest, appFallback) {
|
|
|
46584
46904
|
if (!app) throw new Error("package declares no app id (no himi-package.json and no manifest.app)");
|
|
46585
46905
|
if (!isSafeAppId(app)) throw new Error(`package declares an unsafe app id ${JSON.stringify(app)} \u2014 refusing to unpack it`);
|
|
46586
46906
|
const root = resolve37(dest);
|
|
46587
|
-
const appDir2 =
|
|
46907
|
+
const appDir2 = join43(root, app);
|
|
46588
46908
|
rmSync9(appDir2, { recursive: true, force: true });
|
|
46589
46909
|
for (const [rel, bytes2] of entries) {
|
|
46590
|
-
const target =
|
|
46910
|
+
const target = join43(appDir2, rel);
|
|
46591
46911
|
mkdirSync21(dirname26(target), { recursive: true });
|
|
46592
46912
|
writeFileSync17(target, bytes2);
|
|
46593
46913
|
}
|
|
@@ -46623,20 +46943,20 @@ __export(app_source_exports, {
|
|
|
46623
46943
|
writeConflicts: () => writeConflicts,
|
|
46624
46944
|
zipAppSource: () => zipAppSource
|
|
46625
46945
|
});
|
|
46626
|
-
import { readdirSync as
|
|
46627
|
-
import { join as
|
|
46946
|
+
import { readdirSync as readdirSync26, lstatSync as lstatSync8, readFileSync as readFileSync50, mkdirSync as mkdirSync22, writeFileSync as writeFileSync18, existsSync as existsSync46, rmSync as rmSync10, rmdirSync as rmdirSync2, unlinkSync as unlinkSync3 } from "node:fs";
|
|
46947
|
+
import { join as join44, resolve as resolve38, sep as sep10 } from "node:path";
|
|
46628
46948
|
import { deflateRawSync as deflateRawSync2 } from "node:zlib";
|
|
46629
46949
|
function walkSourceTree(dir, file, skip) {
|
|
46630
46950
|
const walk2 = (relDir) => {
|
|
46631
|
-
for (const name of
|
|
46632
|
-
const rel = relDir ?
|
|
46633
|
-
const st = lstatSync8(
|
|
46951
|
+
for (const name of readdirSync26(join44(dir, relDir))) {
|
|
46952
|
+
const rel = relDir ? join44(relDir, name) : name;
|
|
46953
|
+
const st = lstatSync8(join44(dir, rel));
|
|
46634
46954
|
if (st.isSymbolicLink()) {
|
|
46635
46955
|
skip(rel);
|
|
46636
46956
|
continue;
|
|
46637
46957
|
}
|
|
46638
46958
|
if (st.isDirectory()) {
|
|
46639
|
-
if (isDeniedSourceDir(name, relDir) ||
|
|
46959
|
+
if (isDeniedSourceDir(name, relDir) || existsSync46(join44(dir, rel, PACKAGE_DIR_MARKER))) skip(rel);
|
|
46640
46960
|
else walk2(rel);
|
|
46641
46961
|
continue;
|
|
46642
46962
|
}
|
|
@@ -46654,7 +46974,7 @@ function collectAppSource(dir) {
|
|
|
46654
46974
|
const skipped = [];
|
|
46655
46975
|
walkSourceTree(
|
|
46656
46976
|
dir,
|
|
46657
|
-
(archivePath, hostRel) => entries.push({ path: archivePath, bytes:
|
|
46977
|
+
(archivePath, hostRel) => entries.push({ path: archivePath, bytes: readFileSync50(join44(dir, hostRel)) }),
|
|
46658
46978
|
(hostRel) => skipped.push(hostRel)
|
|
46659
46979
|
);
|
|
46660
46980
|
entries.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
@@ -46708,13 +47028,13 @@ function writeAppSource(entries, destDir) {
|
|
|
46708
47028
|
const segments = entry.path.split("/");
|
|
46709
47029
|
let dir = root;
|
|
46710
47030
|
for (const segment of segments.slice(0, -1)) {
|
|
46711
|
-
dir =
|
|
47031
|
+
dir = join44(dir, segment);
|
|
46712
47032
|
const kind = pathKind(dir);
|
|
46713
47033
|
if (kind?.isSymbolicLink()) unlinkSync3(dir);
|
|
46714
47034
|
else if (kind) continue;
|
|
46715
47035
|
mkdirSync22(dir);
|
|
46716
47036
|
}
|
|
46717
|
-
const target =
|
|
47037
|
+
const target = join44(root, ...segments);
|
|
46718
47038
|
if (pathKind(target)?.isSymbolicLink()) unlinkSync3(target);
|
|
46719
47039
|
writeFileSync18(target, entry.bytes);
|
|
46720
47040
|
written.push(entry.path);
|
|
@@ -46722,7 +47042,7 @@ function writeAppSource(entries, destDir) {
|
|
|
46722
47042
|
return written;
|
|
46723
47043
|
}
|
|
46724
47044
|
function staleSourcePaths(entries, destDir) {
|
|
46725
|
-
if (!
|
|
47045
|
+
if (!existsSync46(destDir)) return [];
|
|
46726
47046
|
const archived = new Set(entries.map((e) => e.path));
|
|
46727
47047
|
const stale = [];
|
|
46728
47048
|
walkSourceTree(destDir, (archivePath) => {
|
|
@@ -46749,7 +47069,7 @@ function writeConflicts(entries, destDir) {
|
|
|
46749
47069
|
let dir = root;
|
|
46750
47070
|
let stop = false;
|
|
46751
47071
|
for (const [i, segment] of segments.slice(0, -1).entries()) {
|
|
46752
|
-
dir =
|
|
47072
|
+
dir = join44(dir, segment);
|
|
46753
47073
|
const kind2 = pathKind(dir);
|
|
46754
47074
|
if (!kind2 || kind2.isSymbolicLink()) {
|
|
46755
47075
|
stop = true;
|
|
@@ -46761,7 +47081,7 @@ function writeConflicts(entries, destDir) {
|
|
|
46761
47081
|
break;
|
|
46762
47082
|
}
|
|
46763
47083
|
if (stop) continue;
|
|
46764
|
-
const kind = pathKind(
|
|
47084
|
+
const kind = pathKind(join44(root, ...segments));
|
|
46765
47085
|
if (kind && !kind.isSymbolicLink() && kind.isDirectory()) {
|
|
46766
47086
|
say(entry.path, "is a directory here, but the release has a file at that path");
|
|
46767
47087
|
}
|
|
@@ -46771,22 +47091,22 @@ function writeConflicts(entries, destDir) {
|
|
|
46771
47091
|
function removeStaleSource(entries, destDir) {
|
|
46772
47092
|
const root = resolve38(destDir);
|
|
46773
47093
|
const removed = staleSourcePaths(entries, root);
|
|
46774
|
-
for (const rel of removed) rmSync10(
|
|
47094
|
+
for (const rel of removed) rmSync10(join44(root, ...rel.split("/")), { force: true });
|
|
46775
47095
|
const needed = /* @__PURE__ */ new Set();
|
|
46776
47096
|
for (const entry of entries) {
|
|
46777
47097
|
if (isDeniedSourcePath(entry.path)) continue;
|
|
46778
47098
|
const segments = entry.path.split("/");
|
|
46779
47099
|
for (let i = 1; i < segments.length; i++) needed.add(segments.slice(0, i).join("/"));
|
|
46780
47100
|
}
|
|
46781
|
-
if (
|
|
47101
|
+
if (existsSync46(root)) pruneEmptyDirs(root, "", needed, removed);
|
|
46782
47102
|
return removed.sort();
|
|
46783
47103
|
}
|
|
46784
47104
|
function pruneEmptyDirs(root, rel, needed, removed) {
|
|
46785
47105
|
let empty = true;
|
|
46786
|
-
for (const name of
|
|
46787
|
-
const childRel = rel ?
|
|
47106
|
+
for (const name of readdirSync26(rel ? join44(root, rel) : root)) {
|
|
47107
|
+
const childRel = rel ? join44(rel, name) : name;
|
|
46788
47108
|
const posix4 = childRel.split(sep10).join("/");
|
|
46789
|
-
const kind = lstatSync8(
|
|
47109
|
+
const kind = lstatSync8(join44(root, childRel));
|
|
46790
47110
|
if (kind.isSymbolicLink() || !kind.isDirectory() || isDeniedSourceDir(name, rel)) {
|
|
46791
47111
|
empty = false;
|
|
46792
47112
|
continue;
|
|
@@ -46796,7 +47116,7 @@ function pruneEmptyDirs(root, rel, needed, removed) {
|
|
|
46796
47116
|
empty = false;
|
|
46797
47117
|
continue;
|
|
46798
47118
|
}
|
|
46799
|
-
rmdirSync2(
|
|
47119
|
+
rmdirSync2(join44(root, childRel));
|
|
46800
47120
|
removed.push(`${posix4}/`);
|
|
46801
47121
|
}
|
|
46802
47122
|
return empty;
|
|
@@ -46851,13 +47171,13 @@ __export(eject_exports, {
|
|
|
46851
47171
|
EJECTABLE: () => EJECTABLE,
|
|
46852
47172
|
ejectModule: () => ejectModule
|
|
46853
47173
|
});
|
|
46854
|
-
import { existsSync as
|
|
46855
|
-
import { dirname as dirname27, join as
|
|
47174
|
+
import { existsSync as existsSync47, mkdirSync as mkdirSync23, readFileSync as readFileSync51, writeFileSync as writeFileSync19 } from "node:fs";
|
|
47175
|
+
import { dirname as dirname27, join as join45, relative as relative8, resolve as resolve39, sep as sep11 } from "node:path";
|
|
46856
47176
|
function locate(repoRootOrCwd, mod) {
|
|
46857
47177
|
const inRepo = resolve39(repoRootOrCwd, `stdlib/flows/${mod}/src/index.ts`);
|
|
46858
|
-
if (
|
|
47178
|
+
if (existsSync47(inRepo)) return { path: inRepo, form: "source" };
|
|
46859
47179
|
const dist = resolve39(repoRootOrCwd, `node_modules/@wix/himalaya/dist/${mod}.mjs`);
|
|
46860
|
-
if (
|
|
47180
|
+
if (existsSync47(dist)) return { path: dist, form: "bundle" };
|
|
46861
47181
|
return null;
|
|
46862
47182
|
}
|
|
46863
47183
|
function specifiersFor(mod) {
|
|
@@ -46881,7 +47201,7 @@ function ejectModule(opts) {
|
|
|
46881
47201
|
};
|
|
46882
47202
|
}
|
|
46883
47203
|
const ext = found.form === "source" ? "ts" : "mjs";
|
|
46884
|
-
const target =
|
|
47204
|
+
const target = join45(contentDir2, "tier5-src", "_ejected", `${mod}.${ext}`);
|
|
46885
47205
|
mkdirSync23(dirname27(target), { recursive: true });
|
|
46886
47206
|
const banner = `// EJECTED from @wix/himalaya/${mod}. This app owns this file now.
|
|
46887
47207
|
//
|
|
@@ -46895,15 +47215,15 @@ function ejectModule(opts) {
|
|
|
46895
47215
|
// gate still applies. Ejecting buys layout and flow, never the floor.
|
|
46896
47216
|
|
|
46897
47217
|
`;
|
|
46898
|
-
const normalized =
|
|
47218
|
+
const normalized = readFileSync51(found.path, "utf8").replace(
|
|
46899
47219
|
/(["'])@himalaya\/([a-z0-9-]+(?:\/[a-z0-9-]+)?)\1/g,
|
|
46900
47220
|
(_m, q, sub) => `${q}@wix/himalaya/${sub}${q}`
|
|
46901
47221
|
);
|
|
46902
47222
|
writeFileSync19(target, banner + normalized);
|
|
46903
47223
|
const rewired = [];
|
|
46904
47224
|
for (const f of files) {
|
|
46905
|
-
if (!
|
|
46906
|
-
const before =
|
|
47225
|
+
if (!existsSync47(f)) continue;
|
|
47226
|
+
const before = readFileSync51(f, "utf8");
|
|
46907
47227
|
let after = before;
|
|
46908
47228
|
let rel = relative8(dirname27(f), target).split(sep11).join("/").replace(/\.tsx?$/, ".js");
|
|
46909
47229
|
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
@@ -46935,9 +47255,96 @@ var init_eject = __esm({
|
|
|
46935
47255
|
}
|
|
46936
47256
|
});
|
|
46937
47257
|
|
|
47258
|
+
// src/app-map.ts
|
|
47259
|
+
function buildAppMap(input) {
|
|
47260
|
+
const declared = [...new Set(input.declared)].slice(0, MAX_SCREENS);
|
|
47261
|
+
const known = new Set(declared);
|
|
47262
|
+
let entries = [...new Set(input.entries)].filter((id) => known.has(id));
|
|
47263
|
+
if (!entries.length && declared.length) entries = [declared[0]];
|
|
47264
|
+
const entrySet = new Set(entries);
|
|
47265
|
+
const all = [];
|
|
47266
|
+
const broken = [];
|
|
47267
|
+
const seen = /* @__PURE__ */ new Set();
|
|
47268
|
+
const crawled = /* @__PURE__ */ new Map();
|
|
47269
|
+
const unfollowed = /* @__PURE__ */ new Map();
|
|
47270
|
+
for (const r of input.results) {
|
|
47271
|
+
crawled.set(r.screen, (crawled.get(r.screen) ?? false) || r.failed);
|
|
47272
|
+
if (r.navUnfollowed) unfollowed.set(r.screen, Math.max(unfollowed.get(r.screen) ?? 0, r.navUnfollowed));
|
|
47273
|
+
for (const e of r.navEdges ?? []) {
|
|
47274
|
+
const to = known.has(e.target) ? e.target : baseOf(e.target, input.linkable, known);
|
|
47275
|
+
if (!to) {
|
|
47276
|
+
const key3 = `${r.screen}>!${e.target}`;
|
|
47277
|
+
if (input.linkable?.size && !resolvesToLinkable(e.target, input.linkable) && !seen.has(key3)) {
|
|
47278
|
+
seen.add(key3);
|
|
47279
|
+
broken.push({ from: r.screen, to: e.target, via: e.via });
|
|
47280
|
+
}
|
|
47281
|
+
continue;
|
|
47282
|
+
}
|
|
47283
|
+
const key2 = `${r.screen}>${to}`;
|
|
47284
|
+
if (seen.has(key2)) continue;
|
|
47285
|
+
seen.add(key2);
|
|
47286
|
+
all.push({ from: r.screen, to, via: e.via });
|
|
47287
|
+
}
|
|
47288
|
+
}
|
|
47289
|
+
const reached = new Set(entries);
|
|
47290
|
+
const out = /* @__PURE__ */ new Map();
|
|
47291
|
+
for (const e of all) {
|
|
47292
|
+
const next = out.get(e.from);
|
|
47293
|
+
if (next) next.push(e.to);
|
|
47294
|
+
else out.set(e.from, [e.to]);
|
|
47295
|
+
}
|
|
47296
|
+
for (const queue = [...entries]; queue.length; ) {
|
|
47297
|
+
for (const next of out.get(queue.shift()) ?? []) {
|
|
47298
|
+
if (reached.has(next)) continue;
|
|
47299
|
+
reached.add(next);
|
|
47300
|
+
queue.push(next);
|
|
47301
|
+
}
|
|
47302
|
+
}
|
|
47303
|
+
const screens = declared.map((id) => ({
|
|
47304
|
+
id,
|
|
47305
|
+
entry: entrySet.has(id),
|
|
47306
|
+
reached: reached.has(id),
|
|
47307
|
+
status: crawled.has(id) ? crawled.get(id) ? "failed" : "ok" : input.done ? "skipped" : "pending",
|
|
47308
|
+
unfollowed: unfollowed.get(id) ?? 0
|
|
47309
|
+
}));
|
|
47310
|
+
const totalUnfollowed = [...unfollowed.values()].reduce((a, b) => a + b, 0);
|
|
47311
|
+
return {
|
|
47312
|
+
screens,
|
|
47313
|
+
edges: all.slice(0, MAX_EDGES),
|
|
47314
|
+
broken,
|
|
47315
|
+
unreached: declared.filter((id) => !reached.has(id)),
|
|
47316
|
+
unfollowed: totalUnfollowed,
|
|
47317
|
+
edgesDropped: Math.max(0, all.length - MAX_EDGES),
|
|
47318
|
+
done: input.done
|
|
47319
|
+
};
|
|
47320
|
+
}
|
|
47321
|
+
function resolvesToLinkable(target, linkable) {
|
|
47322
|
+
if (linkable.has(target)) return true;
|
|
47323
|
+
for (const base of linkable) {
|
|
47324
|
+
if (target.length > base.length + 1 && target.startsWith(base) && (target[base.length] === "_" || target[base.length] === "/")) return true;
|
|
47325
|
+
}
|
|
47326
|
+
return false;
|
|
47327
|
+
}
|
|
47328
|
+
function baseOf(target, linkable, known) {
|
|
47329
|
+
let best = null;
|
|
47330
|
+
for (const base of linkable ?? []) {
|
|
47331
|
+
if (!known.has(base) || target.length <= base.length + 1 || !target.startsWith(base)) continue;
|
|
47332
|
+
const sep15 = target[base.length];
|
|
47333
|
+
if ((sep15 === "_" || sep15 === "/") && (!best || base.length > best.length)) best = base;
|
|
47334
|
+
}
|
|
47335
|
+
return best;
|
|
47336
|
+
}
|
|
47337
|
+
var MAX_SCREENS, MAX_EDGES;
|
|
47338
|
+
var init_app_map = __esm({
|
|
47339
|
+
"src/app-map.ts"() {
|
|
47340
|
+
MAX_SCREENS = 300;
|
|
47341
|
+
MAX_EDGES = 600;
|
|
47342
|
+
}
|
|
47343
|
+
});
|
|
47344
|
+
|
|
46938
47345
|
// src/wix-writes.ts
|
|
46939
|
-
import { existsSync as
|
|
46940
|
-
import { join as
|
|
47346
|
+
import { existsSync as existsSync48, readFileSync as readFileSync52 } from "node:fs";
|
|
47347
|
+
import { join as join46 } from "node:path";
|
|
46941
47348
|
function isProvenRead(method, path2) {
|
|
46942
47349
|
if (/[#\x00-\x1F\x7F]/.test(path2)) return false;
|
|
46943
47350
|
const verb = method.toUpperCase();
|
|
@@ -47018,11 +47425,11 @@ function parseDataAccess(text5, from) {
|
|
|
47018
47425
|
}
|
|
47019
47426
|
function readDataAccess(dir) {
|
|
47020
47427
|
for (const name of ["SPEC.md", "MOBILE-UX.md"]) {
|
|
47021
|
-
const p =
|
|
47022
|
-
if (!
|
|
47428
|
+
const p = join46(dir, name);
|
|
47429
|
+
if (!existsSync48(p)) continue;
|
|
47023
47430
|
let text5;
|
|
47024
47431
|
try {
|
|
47025
|
-
text5 =
|
|
47432
|
+
text5 = readFileSync52(p, "utf8");
|
|
47026
47433
|
} catch {
|
|
47027
47434
|
continue;
|
|
47028
47435
|
}
|
|
@@ -47129,14 +47536,14 @@ __export(test_exports, {
|
|
|
47129
47536
|
scopeDescriptors: () => scopeDescriptors,
|
|
47130
47537
|
writeRecordedMocks: () => writeRecordedMocks
|
|
47131
47538
|
});
|
|
47132
|
-
import { existsSync as
|
|
47133
|
-
import { join as
|
|
47539
|
+
import { existsSync as existsSync49, mkdirSync as mkdirSync24, readFileSync as readFileSync53, writeFileSync as writeFileSync20 } from "node:fs";
|
|
47540
|
+
import { join as join47, resolve as resolve40 } from "node:path";
|
|
47134
47541
|
function readTestConfig(dir) {
|
|
47135
47542
|
const p = resolve40(dir, TEST_CONFIG_FILE);
|
|
47136
|
-
if (!
|
|
47543
|
+
if (!existsSync49(p)) return {};
|
|
47137
47544
|
let parsed;
|
|
47138
47545
|
try {
|
|
47139
|
-
parsed = JSON.parse(
|
|
47546
|
+
parsed = JSON.parse(readFileSync53(p, "utf8"));
|
|
47140
47547
|
} catch (e) {
|
|
47141
47548
|
throw new Error(`${TEST_CONFIG_FILE} is not valid JSON \u2014 ${e.message}`);
|
|
47142
47549
|
}
|
|
@@ -47183,7 +47590,7 @@ function readTestConfig(dir) {
|
|
|
47183
47590
|
function readNetRules(path2) {
|
|
47184
47591
|
let parsed;
|
|
47185
47592
|
try {
|
|
47186
|
-
parsed = JSON.parse(
|
|
47593
|
+
parsed = JSON.parse(readFileSync53(path2, "utf8"));
|
|
47187
47594
|
} catch (e) {
|
|
47188
47595
|
throw new Error(`--net ${path2} could not be read as JSON \u2014 ${e.message}`);
|
|
47189
47596
|
}
|
|
@@ -47204,7 +47611,7 @@ function readNetRules(path2) {
|
|
|
47204
47611
|
function defaultNetRules(dir) {
|
|
47205
47612
|
for (const rel of ["dev/net-mocks.json", "tests/net-mocks.json"]) {
|
|
47206
47613
|
const p = resolve40(dir, rel);
|
|
47207
|
-
if (
|
|
47614
|
+
if (existsSync49(p)) {
|
|
47208
47615
|
const rules = readNetRules(p);
|
|
47209
47616
|
if (rules.length) return { rules, from: rel };
|
|
47210
47617
|
}
|
|
@@ -47220,13 +47627,13 @@ function readCannedResponses() {
|
|
|
47220
47627
|
];
|
|
47221
47628
|
for (const url of candidates) {
|
|
47222
47629
|
try {
|
|
47223
|
-
const parsed = JSON.parse(
|
|
47630
|
+
const parsed = JSON.parse(readFileSync53(url, "utf8"));
|
|
47224
47631
|
const byKey = {};
|
|
47225
47632
|
for (const [k, v] of Object.entries(parsed)) {
|
|
47226
47633
|
if (!k.startsWith("//")) byKey[k] = v;
|
|
47227
47634
|
}
|
|
47228
|
-
const
|
|
47229
|
-
if (
|
|
47635
|
+
const count2 = Object.keys(byKey).length;
|
|
47636
|
+
if (count2) return { byKey, count: count2, from: url.pathname.includes("web-renderer") ? "in-repo fixture" : "bundled fixture" };
|
|
47230
47637
|
} catch {
|
|
47231
47638
|
}
|
|
47232
47639
|
}
|
|
@@ -47310,8 +47717,8 @@ function writeRecordedMocks(opts) {
|
|
|
47310
47717
|
mkdir: (p) => mkdirSync24(p, { recursive: true }),
|
|
47311
47718
|
write: (p, s) => writeFileSync20(p, s)
|
|
47312
47719
|
};
|
|
47313
|
-
fs.mkdir(
|
|
47314
|
-
fs.write(
|
|
47720
|
+
fs.mkdir(join47(opts.dir, "dev"));
|
|
47721
|
+
fs.write(join47(opts.dir, "dev", "net-mocks.json"), JSON.stringify(opts.mocks, null, 2) + "\n");
|
|
47315
47722
|
return { ok: true, rules, to: "dev/net-mocks.json" };
|
|
47316
47723
|
}
|
|
47317
47724
|
function scopeDescriptors(descriptors, requestedIds, invalidScreens) {
|
|
@@ -47348,6 +47755,15 @@ async function runShotsPass(opts) {
|
|
|
47348
47755
|
}
|
|
47349
47756
|
return { dir: opts.outDir, written };
|
|
47350
47757
|
}
|
|
47758
|
+
function withCovered(rows, coveredBy) {
|
|
47759
|
+
const byScreen = new Map(rows.map((r) => [r.screen, r]));
|
|
47760
|
+
const out = [...rows];
|
|
47761
|
+
for (const [instance, representative] of coveredBy) {
|
|
47762
|
+
const r = byScreen.get(representative);
|
|
47763
|
+
if (r && !byScreen.has(instance)) out.push({ ...r, screen: instance, navEdges: [], navUnfollowed: 0 });
|
|
47764
|
+
}
|
|
47765
|
+
return out;
|
|
47766
|
+
}
|
|
47351
47767
|
async function runCrawl(opts) {
|
|
47352
47768
|
const { descriptors, deps } = opts;
|
|
47353
47769
|
const localDbSchema = await localDbEntities(opts.dir);
|
|
@@ -47358,6 +47774,7 @@ async function runCrawl(opts) {
|
|
|
47358
47774
|
const notCrawled = descriptors.filter((d) => (!only || only.has(d.screenId)) && invalid.has(d.screenId)).map((d) => ({ screen: d.screenId, why: "descriptor fails `himi validate` \u2014 fix that first, then this screen is crawled too" }));
|
|
47359
47775
|
const requested = descriptors.filter((d) => (!only || only.has(d.screenId)) && !invalid.has(d.screenId));
|
|
47360
47776
|
const collapsed = [];
|
|
47777
|
+
const coveredBy = /* @__PURE__ */ new Map();
|
|
47361
47778
|
let targets = requested;
|
|
47362
47779
|
if (!opts.allScreens) {
|
|
47363
47780
|
const groups = /* @__PURE__ */ new Map();
|
|
@@ -47372,6 +47789,7 @@ async function runCrawl(opts) {
|
|
|
47372
47789
|
const rep = list.find((d) => Object.keys(d.descriptor?.input ?? {}).length > 0) ?? list[0];
|
|
47373
47790
|
targets.push(rep);
|
|
47374
47791
|
if (list.length > 1) collapsed.push({ representative: rep.screenId, instances: list.length });
|
|
47792
|
+
for (const d of list) if (d.screenId !== rep.screenId) coveredBy.set(d.screenId, rep.screenId);
|
|
47375
47793
|
}
|
|
47376
47794
|
}
|
|
47377
47795
|
const net = opts.offline ? null : opts.netPath ? { rules: readNetRules(resolve40(opts.netPath)), from: opts.netPath } : defaultNetRules(opts.dir);
|
|
@@ -47417,6 +47835,12 @@ async function runCrawl(opts) {
|
|
|
47417
47835
|
const cov = baked.bundleJs && deps.startWorkerCoverage ? await deps.startWorkerCoverage() : null;
|
|
47418
47836
|
const r = await deps.crawlScreen(args);
|
|
47419
47837
|
results.push(r);
|
|
47838
|
+
if (opts.onScreen) {
|
|
47839
|
+
try {
|
|
47840
|
+
opts.onScreen(buildAppMap({ declared: [...knownScreenIds], entries: opts.mapEntries ?? opts.tabRoots ?? [], ...opts.linkableScreenIds?.size ? { linkable: opts.linkableScreenIds } : {}, results: withCovered(results.map(mapResult), coveredBy), done: false }));
|
|
47841
|
+
} catch {
|
|
47842
|
+
}
|
|
47843
|
+
}
|
|
47420
47844
|
writes.push(...writesFromEffects(baked.screenId, r.effects));
|
|
47421
47845
|
for (const journey of opts.config?.journeys?.filter((candidate) => candidate.screen === baked.screenId) ?? []) {
|
|
47422
47846
|
if (!deps.crawlScreenJourney) {
|
|
@@ -47625,6 +48049,8 @@ async function runCrawl(opts) {
|
|
|
47625
48049
|
...bundleOf.get(r.screen)?.bundleMapWhy ? { sourcemap: bundleOf.get(r.screen).bundleMapWhy } : {}
|
|
47626
48050
|
})),
|
|
47627
48051
|
...edgesFollowed.length ? { edges: edgesFollowed } : {},
|
|
48052
|
+
// Final statuses come from the whole run's failures (hostile, deep, journeys), not one pass.
|
|
48053
|
+
navGraph: buildAppMap({ declared: [...knownScreenIds], entries: opts.mapEntries ?? opts.tabRoots ?? [], ...opts.linkableScreenIds?.size ? { linkable: opts.linkableScreenIds } : {}, results: withCovered(results.map((r) => ({ ...mapResult(r), failed: failedScreens.has(r.screen) })), coveredBy), done: true }),
|
|
47628
48054
|
...edgesCapped.length ? { edgesCapped } : {},
|
|
47629
48055
|
...retired.length ? { retired } : {},
|
|
47630
48056
|
...opts.deep && opts.deep >= 2 ? { deep: { depth: opts.deep, ...deepTotals } } : {},
|
|
@@ -47777,13 +48203,15 @@ function formatReport(r) {
|
|
|
47777
48203
|
}
|
|
47778
48204
|
return out.join("\n");
|
|
47779
48205
|
}
|
|
47780
|
-
var TEST_CONFIG_FILE, triggerLabel;
|
|
48206
|
+
var TEST_CONFIG_FILE, mapResult, triggerLabel;
|
|
47781
48207
|
var init_test = __esm({
|
|
47782
48208
|
"src/test.ts"() {
|
|
48209
|
+
init_app_map();
|
|
47783
48210
|
init_wix_gateway_rules();
|
|
47784
48211
|
init_crawl_layers();
|
|
47785
48212
|
init_wix_writes();
|
|
47786
48213
|
TEST_CONFIG_FILE = "himi-test.json";
|
|
48214
|
+
mapResult = (r) => ({ screen: r.screen, navEdges: r.navEdges ?? [], navUnfollowed: r.navUnfollowed ?? 0, failed: (r.findings ?? []).some((x) => x.severity === "error") });
|
|
47787
48215
|
triggerLabel = (f) => (f.trigger === "boot" ? "on appear" : `${f.trigger.key} ${f.trigger.tap ?? "(no id)"} \u2192 ${f.trigger.action}`) + (f.axis ? ` [${f.axis}]` : "");
|
|
47788
48216
|
}
|
|
47789
48217
|
});
|
|
@@ -47793,14 +48221,14 @@ var mobile_ux_lint_exports = {};
|
|
|
47793
48221
|
__export(mobile_ux_lint_exports, {
|
|
47794
48222
|
mobileUxIssues: () => mobileUxIssues
|
|
47795
48223
|
});
|
|
47796
|
-
import { existsSync as
|
|
47797
|
-
import { join as
|
|
48224
|
+
import { existsSync as existsSync50, readFileSync as readFileSync54 } from "node:fs";
|
|
48225
|
+
import { join as join48 } from "node:path";
|
|
47798
48226
|
function mobileUxIssues(dir, strict) {
|
|
47799
|
-
const file =
|
|
47800
|
-
if (!
|
|
48227
|
+
const file = join48(dir, "MOBILE-UX.md");
|
|
48228
|
+
if (!existsSync50(file)) return [];
|
|
47801
48229
|
let text5;
|
|
47802
48230
|
try {
|
|
47803
|
-
text5 =
|
|
48231
|
+
text5 = readFileSync54(file, "utf8");
|
|
47804
48232
|
} catch {
|
|
47805
48233
|
return [];
|
|
47806
48234
|
}
|
|
@@ -49475,8 +49903,8 @@ __export(functions_exports, {
|
|
|
49475
49903
|
resolveFunctionsTarget: () => resolveFunctionsTarget,
|
|
49476
49904
|
runRemoteFunctionOperation: () => runRemoteFunctionOperation
|
|
49477
49905
|
});
|
|
49478
|
-
import { readFileSync as
|
|
49479
|
-
import { join as
|
|
49906
|
+
import { readFileSync as readFileSync55, existsSync as existsSync51 } from "node:fs";
|
|
49907
|
+
import { join as join49, resolve as resolve41 } from "node:path";
|
|
49480
49908
|
function resolveFunctionsTarget(input) {
|
|
49481
49909
|
const explicitUrl = input.functionsUrl?.trim();
|
|
49482
49910
|
if (explicitUrl) return { mode: "remote", baseUrl: explicitUrl };
|
|
@@ -49495,9 +49923,9 @@ async function loadFunctionsApp(dir) {
|
|
|
49495
49923
|
}
|
|
49496
49924
|
const sources = {};
|
|
49497
49925
|
for (const definition of config.functions.functions) {
|
|
49498
|
-
const source = [".ts", ".js", ".mts", ".mjs"].map((extension) =>
|
|
49926
|
+
const source = [".ts", ".js", ".mts", ".mjs"].map((extension) => join49(loaded.dir, "functions", `${definition.name}${extension}`)).find(existsSync51);
|
|
49499
49927
|
if (!source) throw new Error(`missing source for function ${definition.name}; expected functions/${definition.name}.ts`);
|
|
49500
|
-
sources[definition.name] =
|
|
49928
|
+
sources[definition.name] = readFileSync55(source, "utf8");
|
|
49501
49929
|
}
|
|
49502
49930
|
const data = config.cms || config.data ? mergeDataResources(config) : void 0;
|
|
49503
49931
|
const dataErrors = validateDataResources(data, loaded.name).filter((issue2) => issue2.severity === "error");
|
|
@@ -49657,10 +50085,10 @@ __export(studio_reel_exports, {
|
|
|
49657
50085
|
utcDay: () => utcDay
|
|
49658
50086
|
});
|
|
49659
50087
|
import { createHash as createHash25 } from "node:crypto";
|
|
49660
|
-
import { lstatSync as lstatSync9, readFileSync as
|
|
49661
|
-
import { basename as basename12, join as
|
|
50088
|
+
import { lstatSync as lstatSync9, readFileSync as readFileSync56 } from "node:fs";
|
|
50089
|
+
import { basename as basename12, join as join50 } from "node:path";
|
|
49662
50090
|
function loadMemory2(dir) {
|
|
49663
|
-
const m =
|
|
50091
|
+
const m = readJson5(join50(dir, ".himi", "studio", "memory.json"));
|
|
49664
50092
|
if (!isObj2(m) || m.version !== 1 || !isObj2(m.shots) || !Array.isArray(m.timeline)) return null;
|
|
49665
50093
|
const shots = [];
|
|
49666
50094
|
for (const [id, s] of Object.entries(m.shots)) {
|
|
@@ -49697,8 +50125,8 @@ function planReel(dir) {
|
|
|
49697
50125
|
const memory = loadMemory2(dir);
|
|
49698
50126
|
const { entries } = readProgress(dir);
|
|
49699
50127
|
const summary = summarizeProgress(entries);
|
|
49700
|
-
const manifest =
|
|
49701
|
-
const tokens =
|
|
50128
|
+
const manifest = readJson5(join50(dir, "himalaya.content.json"));
|
|
50129
|
+
const tokens = readJson5(join50(dir, "tokens.json"));
|
|
49702
50130
|
const accentToken = tokens?.colors?.accentPrimary;
|
|
49703
50131
|
const accentRaw = typeof accentToken === "string" ? accentToken : accentToken?.light;
|
|
49704
50132
|
const accent = typeof accentRaw === "string" && ACCENT.test(accentRaw) ? accentRaw : DEFAULT_ACCENT;
|
|
@@ -49740,10 +50168,10 @@ function inlineImages(dir, plan, budget = REEL_BUDGET_BYTES) {
|
|
|
49740
50168
|
const verified = (f) => {
|
|
49741
50169
|
if (!HISTORY_NAME.test(f)) return null;
|
|
49742
50170
|
try {
|
|
49743
|
-
const path2 =
|
|
50171
|
+
const path2 = join50(dir, HISTORY_DIR, f);
|
|
49744
50172
|
const st = lstatSync9(path2);
|
|
49745
50173
|
if (!st.isFile() || st.nlink !== 1) return null;
|
|
49746
|
-
const bytes2 =
|
|
50174
|
+
const bytes2 = readFileSync56(path2);
|
|
49747
50175
|
return createHash25("sha256").update(bytes2).digest("hex") === f.slice(0, 64) && imageExtension(bytes2) === f.slice(65) ? bytes2 : null;
|
|
49748
50176
|
} catch {
|
|
49749
50177
|
return null;
|
|
@@ -49816,7 +50244,7 @@ function sinceStart(start, ts2) {
|
|
|
49816
50244
|
}
|
|
49817
50245
|
function renderReel(plan, images) {
|
|
49818
50246
|
const img = (f, alt, cls = "") => f && images.has(f) ? `<img class="${cls}" src="${images.get(f)}" alt="${escapeHtml(alt)}">` : "";
|
|
49819
|
-
const
|
|
50247
|
+
const count2 = (n) => escapeHtml(String(Number.isSafeInteger(n) && n >= 0 ? n : 0));
|
|
49820
50248
|
const accent = ACCENT.test(plan.accent) ? plan.accent : DEFAULT_ACCENT;
|
|
49821
50249
|
const clock = (ts2) => sinceStart(plan.startedAt, ts2);
|
|
49822
50250
|
const frames = plan.frames.filter((f) => images.has(f.file));
|
|
@@ -49842,14 +50270,14 @@ figcaption{font-size:12px;color:var(--muted);margin-top:6px;word-break:break-all
|
|
|
49842
50270
|
footer{margin-top:48px;font-size:12px;color:var(--muted)}
|
|
49843
50271
|
</style></head><body><div class="wrap">
|
|
49844
50272
|
<h1>${escapeHtml(plan.app)}</h1><div class="muted">The making of \u2014 every version of the app as it was built${plan.startedAt ? `, ${escapeHtml(utcDay(plan.startedAt))}` : ""}</div>
|
|
49845
|
-
<div class="stats"><div><b>${duration(plan.stats.elapsedMs)}</b><span class="muted">from first picture to last</span></div><div><b>${
|
|
50273
|
+
<div class="stats"><div><b>${duration(plan.stats.elapsedMs)}</b><span class="muted">from first picture to last</span></div><div><b>${count2(plan.stats.screens)}</b><span class="muted">screens</span></div><div><b>${count2(plan.stats.versions)}</b><span class="muted">versions rendered</span></div><div><b>${count2(plan.stats.postcards)}</b><span class="muted">postcards</span></div></div>
|
|
49846
50274
|
<h2>${escapeHtml(plan.focusId ?? "The app")}, version by version</h2>
|
|
49847
50275
|
${flip}
|
|
49848
50276
|
<h2>Where it ended up</h2>
|
|
49849
50277
|
<div class="grid">${plan.finals.map((f) => `<figure>${img(f.file, f.id)}<figcaption>${escapeHtml(f.id)}</figcaption></figure>`).join("")}</div>
|
|
49850
50278
|
<h2>Postcards</h2>
|
|
49851
50279
|
<ul class="log">${plan.postcards.map((c) => `<li><div class="t">${clock(c.ts)}</div><div><div>${escapeHtml(c.message)}</div>${c.step ? `<div class="s">step ${JOURNEY_STEPS.indexOf(c.step) + 1} \xB7 ${escapeHtml(c.step)}</div>` : ""}${c.files.length ? `<div class="imgs">${c.files.map((f) => img(f, c.message)).join("")}</div>` : ""}</div></li>`).join("") || `<li class="muted">No postcards were journaled.</li>`}</ul>
|
|
49852
|
-
<footer>Built with himi.${plan.dropped ? ` ${
|
|
50280
|
+
<footer>Built with himi.${plan.dropped ? ` ${count2(plan.dropped)} pictures were left out to keep this file small.` : ""}</footer>
|
|
49853
50281
|
</div>
|
|
49854
50282
|
<script>
|
|
49855
50283
|
(function(){var F=${data};var imgs=document.querySelectorAll(".phone img");if(imgs.length<2)return;var i=0;
|
|
@@ -49863,7 +50291,7 @@ function buildReel(dir, budget = REEL_BUDGET_BYTES) {
|
|
|
49863
50291
|
const { plan, images } = inlineImages(dir, planReel(dir), budget);
|
|
49864
50292
|
return { html: renderReel(plan, images), plan };
|
|
49865
50293
|
}
|
|
49866
|
-
var REEL_BUDGET_BYTES, MAX_FLIP_FRAMES, DEFAULT_ACCENT, ACCENT, HISTORY_NAME, MIME2, mimeOf,
|
|
50294
|
+
var REEL_BUDGET_BYTES, MAX_FLIP_FRAMES, DEFAULT_ACCENT, ACCENT, HISTORY_NAME, MIME2, mimeOf, readJson5, isObj2, str, historyName, cited;
|
|
49867
50295
|
var init_studio_reel = __esm({
|
|
49868
50296
|
"src/studio-reel.ts"() {
|
|
49869
50297
|
init_progress();
|
|
@@ -49875,9 +50303,9 @@ var init_studio_reel = __esm({
|
|
|
49875
50303
|
HISTORY_NAME = /^[0-9a-f]{64}\.(png|jpg|gif|webp)$/;
|
|
49876
50304
|
MIME2 = { png: "image/png", jpg: "image/jpeg", gif: "image/gif", webp: "image/webp" };
|
|
49877
50305
|
mimeOf = (file) => MIME2[file.slice(65)] ?? "image/png";
|
|
49878
|
-
|
|
50306
|
+
readJson5 = (file) => {
|
|
49879
50307
|
try {
|
|
49880
|
-
return JSON.parse(
|
|
50308
|
+
return JSON.parse(readFileSync56(file, "utf8"));
|
|
49881
50309
|
} catch {
|
|
49882
50310
|
return null;
|
|
49883
50311
|
}
|
|
@@ -49908,9 +50336,9 @@ __export(native_decode_exports, {
|
|
|
49908
50336
|
runNativeDecode: () => runNativeDecode
|
|
49909
50337
|
});
|
|
49910
50338
|
import { execFileSync as execFileSync5, spawnSync as spawnSync2 } from "node:child_process";
|
|
49911
|
-
import { existsSync as
|
|
50339
|
+
import { existsSync as existsSync52, mkdtempSync as mkdtempSync2, readFileSync as readFileSync57, rmSync as rmSync11, writeFileSync as writeFileSync21 } from "node:fs";
|
|
49912
50340
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
49913
|
-
import { join as
|
|
50341
|
+
import { join as join51 } from "node:path";
|
|
49914
50342
|
import { fileURLToPath as fileURLToPath20 } from "node:url";
|
|
49915
50343
|
function nativeDecodePackageDir() {
|
|
49916
50344
|
return fileURLToPath20(new URL("../../../core/runtime/ios/HimalayaCore/", import.meta.url));
|
|
@@ -49920,8 +50348,8 @@ function nativeDecodeAndroidHarnessDir() {
|
|
|
49920
50348
|
}
|
|
49921
50349
|
function nativeOracleShipped() {
|
|
49922
50350
|
return {
|
|
49923
|
-
ios:
|
|
49924
|
-
android:
|
|
50351
|
+
ios: existsSync52(join51(nativeDecodePackageDir(), "Package.swift")),
|
|
50352
|
+
android: existsSync52(join51(nativeDecodeAndroidHarnessDir(), "gradlew"))
|
|
49925
50353
|
};
|
|
49926
50354
|
}
|
|
49927
50355
|
function detectNativeDecode(options = {}) {
|
|
@@ -49932,7 +50360,7 @@ function detectNativeDecode(options = {}) {
|
|
|
49932
50360
|
return { platform: "ios", available: false, reason: `the iOS decoder oracle requires macOS (darwin); this host is ${hostPlatform}` };
|
|
49933
50361
|
}
|
|
49934
50362
|
if (!swiftAvailable) return { platform: "ios", available: false, reason: "swift is not on PATH" };
|
|
49935
|
-
const packageAvailable = options.packageAvailable ??
|
|
50363
|
+
const packageAvailable = options.packageAvailable ?? existsSync52(join51(packageDir, "Package.swift"));
|
|
49936
50364
|
if (!packageAvailable) {
|
|
49937
50365
|
return {
|
|
49938
50366
|
platform: "ios",
|
|
@@ -49944,7 +50372,7 @@ function detectNativeDecode(options = {}) {
|
|
|
49944
50372
|
}
|
|
49945
50373
|
function localPropertiesSdk(harnessDir) {
|
|
49946
50374
|
try {
|
|
49947
|
-
const match =
|
|
50375
|
+
const match = readFileSync57(join51(harnessDir, "local.properties"), "utf8").match(/^sdk\.dir\s*=\s*(.+)$/m);
|
|
49948
50376
|
return match?.[1]?.trim().replace(/\\([ :\\])/g, "$1") ?? null;
|
|
49949
50377
|
} catch {
|
|
49950
50378
|
return null;
|
|
@@ -49952,8 +50380,8 @@ function localPropertiesSdk(harnessDir) {
|
|
|
49952
50380
|
}
|
|
49953
50381
|
function detectAndroidNativeDecode(options = {}) {
|
|
49954
50382
|
const harnessDir = options.harnessDir ?? nativeDecodeAndroidHarnessDir();
|
|
49955
|
-
const gradlew =
|
|
49956
|
-
const gradlewAvailable = options.gradlewAvailable ??
|
|
50383
|
+
const gradlew = join51(harnessDir, "gradlew");
|
|
50384
|
+
const gradlewAvailable = options.gradlewAvailable ?? existsSync52(gradlew);
|
|
49957
50385
|
if (!gradlewAvailable) {
|
|
49958
50386
|
return {
|
|
49959
50387
|
platform: "android",
|
|
@@ -49963,7 +50391,7 @@ function detectAndroidNativeDecode(options = {}) {
|
|
|
49963
50391
|
}
|
|
49964
50392
|
const androidHome = options.androidHome ?? process.env.ANDROID_HOME ?? "";
|
|
49965
50393
|
const sdk = androidHome.trim() || (options.localPropertiesSdk !== void 0 ? options.localPropertiesSdk : localPropertiesSdk(harnessDir));
|
|
49966
|
-
const sdkAvailable = options.sdkAvailable ?? (typeof sdk === "string" && sdk.length > 0 &&
|
|
50394
|
+
const sdkAvailable = options.sdkAvailable ?? (typeof sdk === "string" && sdk.length > 0 && existsSync52(sdk));
|
|
49967
50395
|
if (!sdkAvailable) {
|
|
49968
50396
|
return {
|
|
49969
50397
|
platform: "android",
|
|
@@ -50035,14 +50463,14 @@ function parseNativeDecodeOutput(stdout, expectedScreenIds, platform = "ios") {
|
|
|
50035
50463
|
return verdicts;
|
|
50036
50464
|
}
|
|
50037
50465
|
function runNativeDecode(options) {
|
|
50038
|
-
const descriptorDir = mkdtempSync2(
|
|
50466
|
+
const descriptorDir = mkdtempSync2(join51(tmpdir3(), "himi-native-decode-"));
|
|
50039
50467
|
const startedAt = Date.now();
|
|
50040
50468
|
try {
|
|
50041
50469
|
for (const descriptor of options.descriptors) {
|
|
50042
50470
|
if (typeof descriptor.descriptorJson !== "string") {
|
|
50043
50471
|
throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
|
|
50044
50472
|
}
|
|
50045
|
-
writeFileSync21(
|
|
50473
|
+
writeFileSync21(join51(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
|
|
50046
50474
|
}
|
|
50047
50475
|
options.progress?.("building cached Swift oracle");
|
|
50048
50476
|
execFileSync5("swift", ["build", "--package-path", options.packageDir, "--product", "himi-decode-oracle"], {
|
|
@@ -50054,7 +50482,7 @@ function runNativeDecode(options) {
|
|
|
50054
50482
|
encoding: "utf8"
|
|
50055
50483
|
}).trim();
|
|
50056
50484
|
options.progress?.(`running real Swift decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
|
|
50057
|
-
const stdout = execFileSync5(
|
|
50485
|
+
const stdout = execFileSync5(join51(binPath, "himi-decode-oracle"), ["--dir", descriptorDir], {
|
|
50058
50486
|
stdio: ["ignore", "pipe", "pipe"],
|
|
50059
50487
|
encoding: "utf8"
|
|
50060
50488
|
});
|
|
@@ -50072,15 +50500,15 @@ function runNativeDecode(options) {
|
|
|
50072
50500
|
}
|
|
50073
50501
|
}
|
|
50074
50502
|
function runAndroidNativeDecode(options) {
|
|
50075
|
-
const descriptorDir = mkdtempSync2(
|
|
50076
|
-
const outputPath =
|
|
50503
|
+
const descriptorDir = mkdtempSync2(join51(tmpdir3(), "himi-native-decode-android-"));
|
|
50504
|
+
const outputPath = join51(descriptorDir, "verdicts.ndjson");
|
|
50077
50505
|
const startedAt = Date.now();
|
|
50078
50506
|
try {
|
|
50079
50507
|
for (const descriptor of options.descriptors) {
|
|
50080
50508
|
if (typeof descriptor.descriptorJson !== "string") {
|
|
50081
50509
|
throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
|
|
50082
50510
|
}
|
|
50083
|
-
writeFileSync21(
|
|
50511
|
+
writeFileSync21(join51(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
|
|
50084
50512
|
}
|
|
50085
50513
|
options.progress?.(`running real Kotlin decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
|
|
50086
50514
|
execFileSync5(options.gradlew, [
|
|
@@ -50095,7 +50523,7 @@ function runAndroidNativeDecode(options) {
|
|
|
50095
50523
|
stdio: ["ignore", "ignore", "pipe"],
|
|
50096
50524
|
encoding: "utf8"
|
|
50097
50525
|
});
|
|
50098
|
-
const stdout =
|
|
50526
|
+
const stdout = readFileSync57(outputPath, "utf8");
|
|
50099
50527
|
return {
|
|
50100
50528
|
platform: "android",
|
|
50101
50529
|
verdicts: parseNativeDecodeOutput(stdout, options.descriptors.map((descriptor) => descriptor.screenId), "android"),
|
|
@@ -50165,30 +50593,30 @@ __export(browser_authoring_exports, {
|
|
|
50165
50593
|
});
|
|
50166
50594
|
import { createServer as createServer3 } from "node:http";
|
|
50167
50595
|
import { createHash as createHash26, randomBytes as randomBytes4 } from "node:crypto";
|
|
50168
|
-
import { existsSync as
|
|
50169
|
-
import { join as
|
|
50596
|
+
import { existsSync as existsSync53, readdirSync as readdirSync27, readFileSync as readFileSync58, realpathSync as realpathSync6, statSync as statSync12 } from "node:fs";
|
|
50597
|
+
import { join as join52, posix as posix2, relative as relative9, sep as sep12 } from "node:path";
|
|
50170
50598
|
function humanMs(ms) {
|
|
50171
50599
|
return ms < 1e3 ? `${ms}ms` : `${Math.round(ms / 1e3)}s`;
|
|
50172
50600
|
}
|
|
50173
50601
|
function collectWorkerSources(tier5SrcDir, bundleName) {
|
|
50174
|
-
const root =
|
|
50602
|
+
const root = join52(tier5SrcDir, bundleName);
|
|
50175
50603
|
const files = {};
|
|
50176
50604
|
const visitedDirs = /* @__PURE__ */ new Set();
|
|
50177
50605
|
const walk2 = (abs, rel) => {
|
|
50178
50606
|
const real = realpathSync6(abs);
|
|
50179
50607
|
if (visitedDirs.has(real)) return;
|
|
50180
50608
|
visitedDirs.add(real);
|
|
50181
|
-
for (const name of
|
|
50182
|
-
const childAbs =
|
|
50609
|
+
for (const name of readdirSync27(abs).sort()) {
|
|
50610
|
+
const childAbs = join52(abs, name);
|
|
50183
50611
|
const childRel = posix2.join(rel, name);
|
|
50184
50612
|
if (statSync12(childAbs).isDirectory()) {
|
|
50185
50613
|
walk2(childAbs, childRel);
|
|
50186
50614
|
} else if (/\.(ts|tsx|js|mjs|json)$/.test(name)) {
|
|
50187
|
-
files[childRel] =
|
|
50615
|
+
files[childRel] = readFileSync58(childAbs, "utf8");
|
|
50188
50616
|
}
|
|
50189
50617
|
}
|
|
50190
50618
|
};
|
|
50191
|
-
if (!
|
|
50619
|
+
if (!existsSync53(root)) return null;
|
|
50192
50620
|
walk2(root, `/tier5-src/${bundleName}`);
|
|
50193
50621
|
const entry = [`/tier5-src/${bundleName}/index.ts`, `/tier5-src/${bundleName}/index.js`].find((p) => p in files);
|
|
50194
50622
|
if (!entry) return null;
|
|
@@ -50205,20 +50633,20 @@ function collectRelativeSiblings(files, tier5SrcDir) {
|
|
|
50205
50633
|
const spec = m[1];
|
|
50206
50634
|
const virtual = posix2.normalize(posix2.join(dir, spec));
|
|
50207
50635
|
if (!virtual.startsWith("/tier5-src/")) continue;
|
|
50208
|
-
const onDisk =
|
|
50636
|
+
const onDisk = join52(tier5SrcDir, virtual.slice("/tier5-src/".length));
|
|
50209
50637
|
const candidates = [
|
|
50210
50638
|
onDisk,
|
|
50211
50639
|
`${onDisk}.ts`,
|
|
50212
50640
|
`${onDisk}.js`,
|
|
50213
50641
|
onDisk.replace(/\.js$/, ".ts"),
|
|
50214
|
-
|
|
50215
|
-
|
|
50642
|
+
join52(onDisk, "index.ts"),
|
|
50643
|
+
join52(onDisk, "index.js")
|
|
50216
50644
|
];
|
|
50217
50645
|
for (const abs of candidates) {
|
|
50218
|
-
if (!
|
|
50646
|
+
if (!existsSync53(abs) || statSync12(abs).isDirectory()) continue;
|
|
50219
50647
|
const key2 = `/tier5-src/${relative9(tier5SrcDir, abs).split(sep12).join(posix2.sep)}`;
|
|
50220
50648
|
if (key2 in files) break;
|
|
50221
|
-
files[key2] =
|
|
50649
|
+
files[key2] = readFileSync58(abs, "utf8");
|
|
50222
50650
|
queue.push(key2);
|
|
50223
50651
|
break;
|
|
50224
50652
|
}
|
|
@@ -50253,7 +50681,7 @@ function collectSdkModules(files, resolveSubpath) {
|
|
|
50253
50681
|
function sdkSubpathReader(resolve48) {
|
|
50254
50682
|
return (sub) => {
|
|
50255
50683
|
try {
|
|
50256
|
-
return
|
|
50684
|
+
return readFileSync58(resolve48(`@wix/himalaya/${sub}`), "utf8");
|
|
50257
50685
|
} catch {
|
|
50258
50686
|
return null;
|
|
50259
50687
|
}
|
|
@@ -50425,8 +50853,8 @@ __export(coverage_exports, {
|
|
|
50425
50853
|
suppressedNativeKeys: () => suppressedNativeKeys,
|
|
50426
50854
|
trendAndStore: () => trendAndStore
|
|
50427
50855
|
});
|
|
50428
|
-
import { existsSync as
|
|
50429
|
-
import { dirname as dirname28, join as
|
|
50856
|
+
import { existsSync as existsSync54, mkdirSync as mkdirSync25, readFileSync as readFileSync59, writeFileSync as writeFileSync22 } from "node:fs";
|
|
50857
|
+
import { dirname as dirname28, join as join53 } from "node:path";
|
|
50430
50858
|
function suppressedNativeKeys(oracle) {
|
|
50431
50859
|
return [...oracle.ios ? [] : ["native-decode|ios"], ...oracle.android ? [] : ["native-decode|android"]];
|
|
50432
50860
|
}
|
|
@@ -50606,11 +51034,11 @@ function assembleLedger(r, options = {}) {
|
|
|
50606
51034
|
return out;
|
|
50607
51035
|
}
|
|
50608
51036
|
function trendAndStore(dir, entries, suppressed) {
|
|
50609
|
-
const p =
|
|
51037
|
+
const p = join53(dir, LEDGER_FILE);
|
|
50610
51038
|
let previous = null;
|
|
50611
51039
|
try {
|
|
50612
|
-
if (
|
|
50613
|
-
const parsed = JSON.parse(
|
|
51040
|
+
if (existsSync54(p)) {
|
|
51041
|
+
const parsed = JSON.parse(readFileSync59(p, "utf8"));
|
|
50614
51042
|
if (Array.isArray(parsed.keys)) previous = parsed.keys.filter((k) => typeof k === "string");
|
|
50615
51043
|
}
|
|
50616
51044
|
} catch {
|
|
@@ -50649,11 +51077,11 @@ function formatLedger(entries, trend) {
|
|
|
50649
51077
|
return out.join("\n");
|
|
50650
51078
|
}
|
|
50651
51079
|
function diffAndStoreObservations(dir, current) {
|
|
50652
|
-
const p =
|
|
51080
|
+
const p = join53(dir, OBS_FILE);
|
|
50653
51081
|
let previous = null;
|
|
50654
51082
|
try {
|
|
50655
|
-
if (
|
|
50656
|
-
const parsed = JSON.parse(
|
|
51083
|
+
if (existsSync54(p)) {
|
|
51084
|
+
const parsed = JSON.parse(readFileSync59(p, "utf8"));
|
|
50657
51085
|
if (parsed.screens && typeof parsed.screens === "object" && !Array.isArray(parsed.screens) && Object.values(parsed.screens).every(
|
|
50658
51086
|
(v) => Array.isArray(v) && v.every((l) => typeof l === "string")
|
|
50659
51087
|
)) {
|
|
@@ -50702,8 +51130,8 @@ var LEDGER_FILE, OBS_FILE;
|
|
|
50702
51130
|
var init_coverage = __esm({
|
|
50703
51131
|
"src/coverage.ts"() {
|
|
50704
51132
|
init_native_decode();
|
|
50705
|
-
LEDGER_FILE =
|
|
50706
|
-
OBS_FILE =
|
|
51133
|
+
LEDGER_FILE = join53(".himi", "test-ledger.json");
|
|
51134
|
+
OBS_FILE = join53(".himi", "test-observations.json");
|
|
50707
51135
|
}
|
|
50708
51136
|
});
|
|
50709
51137
|
|
|
@@ -50714,16 +51142,16 @@ __export(design_kits_exports, {
|
|
|
50714
51142
|
kitsDir: () => kitsDir,
|
|
50715
51143
|
listKits: () => listKits2
|
|
50716
51144
|
});
|
|
50717
|
-
import { existsSync as
|
|
50718
|
-
import { join as
|
|
51145
|
+
import { existsSync as existsSync55, readFileSync as readFileSync60, readdirSync as readdirSync28 } from "node:fs";
|
|
51146
|
+
import { join as join54, basename as basename13 } from "node:path";
|
|
50719
51147
|
import { fileURLToPath as fileURLToPath21 } from "node:url";
|
|
50720
51148
|
function kitsDir() {
|
|
50721
|
-
return KIT_DIR_CANDIDATES.find((p) =>
|
|
51149
|
+
return KIT_DIR_CANDIDATES.find((p) => existsSync55(p));
|
|
50722
51150
|
}
|
|
50723
51151
|
function listKits2() {
|
|
50724
51152
|
const dir = kitsDir();
|
|
50725
51153
|
if (!dir) return [];
|
|
50726
|
-
return
|
|
51154
|
+
return readdirSync28(dir).filter((f) => f.endsWith(".json")).map((f) => basename13(f, ".json")).sort();
|
|
50727
51155
|
}
|
|
50728
51156
|
function kitReport(name) {
|
|
50729
51157
|
const dir = kitsDir();
|
|
@@ -50742,7 +51170,7 @@ In a published @wix/himalaya-cli this is a packaging bug \u2014 the kits should
|
|
|
50742
51170
|
if (!kits.includes(name)) {
|
|
50743
51171
|
return { ok: false, kit: name, kits, problems: [`no design kit named "${name}". Available: ${kits.join(", ")}`] };
|
|
50744
51172
|
}
|
|
50745
|
-
const raw =
|
|
51173
|
+
const raw = readFileSync60(join54(dir, `${name}.json`), "utf8");
|
|
50746
51174
|
let parsed;
|
|
50747
51175
|
try {
|
|
50748
51176
|
parsed = JSON.parse(raw);
|
|
@@ -50766,9 +51194,9 @@ var init_design_kits = __esm({
|
|
|
50766
51194
|
"src/design-kits.ts"() {
|
|
50767
51195
|
KIT_DIR_CANDIDATES = [
|
|
50768
51196
|
// in-repo: tools/himi-cli/src/design-kits.ts → <repo>/stdlib/design-kits/
|
|
50769
|
-
|
|
51197
|
+
join54(fileURLToPath21(new URL("../../..", import.meta.url)), "stdlib", "design-kits"),
|
|
50770
51198
|
// published CLI: <pkg>/dist/cli.mjs → <pkg>/stdlib/design-kits/
|
|
50771
|
-
|
|
51199
|
+
join54(fileURLToPath21(new URL("..", import.meta.url)), "stdlib", "design-kits")
|
|
50772
51200
|
];
|
|
50773
51201
|
}
|
|
50774
51202
|
});
|
|
@@ -50782,11 +51210,11 @@ __export(assets_exports, {
|
|
|
50782
51210
|
removeAssetPayload: () => removeAssetPayload,
|
|
50783
51211
|
verifyReport: () => verifyReport
|
|
50784
51212
|
});
|
|
50785
|
-
import { readFileSync as
|
|
51213
|
+
import { readFileSync as readFileSync61 } from "node:fs";
|
|
50786
51214
|
import { basename as basename14 } from "node:path";
|
|
50787
51215
|
function declaredAssets(dir) {
|
|
50788
51216
|
return collectAssets(dir).map((a) => {
|
|
50789
|
-
const bytes2 =
|
|
51217
|
+
const bytes2 = readFileSync61(a.path);
|
|
50790
51218
|
return {
|
|
50791
51219
|
name: a.name,
|
|
50792
51220
|
sha256: assetSha256(bytes2),
|
|
@@ -50863,7 +51291,7 @@ function verifyReport(dir, app, manifest) {
|
|
|
50863
51291
|
};
|
|
50864
51292
|
}
|
|
50865
51293
|
function addAssetPayload(manifest, filePath, opts) {
|
|
50866
|
-
const bytes2 =
|
|
51294
|
+
const bytes2 = readFileSync61(filePath);
|
|
50867
51295
|
const name = opts.name ?? basename14(filePath);
|
|
50868
51296
|
const sha2565 = assetSha256(bytes2);
|
|
50869
51297
|
const record2 = {
|
|
@@ -52538,9 +52966,9 @@ __export(run_exports, {
|
|
|
52538
52966
|
runPackage: () => runPackage,
|
|
52539
52967
|
withoutProdServe: () => withoutProdServe
|
|
52540
52968
|
});
|
|
52541
|
-
import { cpSync as cpSync2, existsSync as
|
|
52969
|
+
import { cpSync as cpSync2, existsSync as existsSync56, mkdirSync as mkdirSync26, mkdtempSync as mkdtempSync3, readFileSync as readFileSync62, rmSync as rmSync12, statSync as statSync13 } from "node:fs";
|
|
52542
52970
|
import { networkInterfaces as osNetworkInterfaces, tmpdir as tmpdir4 } from "node:os";
|
|
52543
|
-
import { dirname as dirname29, join as
|
|
52971
|
+
import { dirname as dirname29, join as join55 } from "node:path";
|
|
52544
52972
|
import { fileURLToPath as fileURLToPath22 } from "node:url";
|
|
52545
52973
|
function makePackageRunHandler(opts) {
|
|
52546
52974
|
const store = new FileReleaseStore(opts.releaseRoot);
|
|
@@ -52568,9 +52996,9 @@ async function fetchBytes(url) {
|
|
|
52568
52996
|
}
|
|
52569
52997
|
async function resolvePackage(source, workDir) {
|
|
52570
52998
|
const isUrl2 = /^https?:\/\//i.test(source);
|
|
52571
|
-
if (!isUrl2 &&
|
|
52572
|
-
const appDirManifest =
|
|
52573
|
-
if (
|
|
52999
|
+
if (!isUrl2 && existsSync56(source) && statSync13(source).isDirectory()) {
|
|
53000
|
+
const appDirManifest = join55(source, "release-manifest.json");
|
|
53001
|
+
if (existsSync56(appDirManifest)) {
|
|
52574
53002
|
const opened2 = openPackageDir(source);
|
|
52575
53003
|
if (!opened2.validation.ok) {
|
|
52576
53004
|
throw new Error(`package is not valid:
|
|
@@ -52579,9 +53007,9 @@ async function resolvePackage(source, workDir) {
|
|
|
52579
53007
|
const app2 = opened2.header?.app ?? opened2.manifest?.app;
|
|
52580
53008
|
if (!app2) throw new Error(`${source} has no app id (no himi-package.json and no manifest.app)`);
|
|
52581
53009
|
if (!isSafeAppId(app2)) throw new Error(`${source} declares an unsafe app id ${JSON.stringify(app2)} \u2014 refusing to open it`);
|
|
52582
|
-
const root2 = workDir ?? mkdtempSync3(
|
|
52583
|
-
const target =
|
|
52584
|
-
if (
|
|
53010
|
+
const root2 = workDir ?? mkdtempSync3(join55(tmpdir4(), "himi-run-"));
|
|
53011
|
+
const target = join55(root2, app2);
|
|
53012
|
+
if (join55(source) !== target) {
|
|
52585
53013
|
mkdirSync26(root2, { recursive: true });
|
|
52586
53014
|
rmSync12(target, { recursive: true, force: true });
|
|
52587
53015
|
cpSync2(source, target, { recursive: true });
|
|
@@ -52598,8 +53026,8 @@ async function resolvePackage(source, workDir) {
|
|
|
52598
53026
|
}
|
|
52599
53027
|
throw new Error(`${source} is a directory but has no release-manifest.json \u2014 is it a package?`);
|
|
52600
53028
|
}
|
|
52601
|
-
const bytes2 = isUrl2 ? await fetchBytes(source) :
|
|
52602
|
-
const root = workDir ?? mkdtempSync3(
|
|
53029
|
+
const bytes2 = isUrl2 ? await fetchBytes(source) : readFileSync62(source);
|
|
53030
|
+
const root = workDir ?? mkdtempSync3(join55(tmpdir4(), "himi-run-"));
|
|
52603
53031
|
const { app, appDir: appDir2 } = unpackTo(bytes2, root);
|
|
52604
53032
|
const opened = openPackageDir(appDir2);
|
|
52605
53033
|
if (!opened.validation.ok) {
|
|
@@ -52622,14 +53050,14 @@ async function loadPreviewAssets() {
|
|
|
52622
53050
|
const mod = await Promise.resolve().then(() => (init_preview_assets_generated(), preview_assets_generated_exports));
|
|
52623
53051
|
const here = dirname29(fileURLToPath22(import.meta.url));
|
|
52624
53052
|
const candidates = [
|
|
52625
|
-
|
|
53053
|
+
join55(here, "preview-assets.generated.bin"),
|
|
52626
53054
|
// published: copied next to the bundled CLI
|
|
52627
|
-
|
|
53055
|
+
join55(here, "../../../packages/serve/src/preview-assets.generated.bin")
|
|
52628
53056
|
// in-repo checkout
|
|
52629
53057
|
];
|
|
52630
53058
|
for (const path2 of candidates) {
|
|
52631
|
-
if (!
|
|
52632
|
-
const blob =
|
|
53059
|
+
if (!existsSync56(path2)) continue;
|
|
53060
|
+
const blob = readFileSync62(path2);
|
|
52633
53061
|
return mod.assemblePreviewAssetsFromBlob(new Uint8Array(blob.buffer, blob.byteOffset, blob.byteLength));
|
|
52634
53062
|
}
|
|
52635
53063
|
return /* @__PURE__ */ new Map();
|
|
@@ -52776,9 +53204,9 @@ __export(run_watch_exports, {
|
|
|
52776
53204
|
watchedContentDir: () => watchedContentDir,
|
|
52777
53205
|
writeRunRecord: () => writeRunRecord
|
|
52778
53206
|
});
|
|
52779
|
-
import { closeSync as closeSync2, constants, existsSync as
|
|
53207
|
+
import { closeSync as closeSync2, constants, existsSync as existsSync57, fstatSync, lstatSync as lstatSync10, statSync as statSync14, mkdirSync as mkdirSync27, openSync as openSync2, readFileSync as readFileSync63, realpathSync as realpathSync7, renameSync as renameSync6, rmSync as rmSync13, writeFileSync as writeFileSync23, watch as fsWatch } from "node:fs";
|
|
52780
53208
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
52781
|
-
import { extname as extname4, join as
|
|
53209
|
+
import { extname as extname4, join as join56, resolve as resolve42, sep as sep13 } from "node:path";
|
|
52782
53210
|
function diffReleases(prev, next) {
|
|
52783
53211
|
const bundles = Object.keys(next.bundles).filter((b) => prev.bundles[b]?.sha256 !== next.bundles[b].sha256).sort();
|
|
52784
53212
|
const changedBundles = new Set(bundles);
|
|
@@ -52819,7 +53247,7 @@ function watchContent(dir, onChange, opts = {}) {
|
|
|
52819
53247
|
let timer = null;
|
|
52820
53248
|
const pending = /* @__PURE__ */ new Set();
|
|
52821
53249
|
const watcher2 = watch2(dir, { recursive: true }, (_event, file) => {
|
|
52822
|
-
if (!file || ignoredChange(file, (rel) => isDir(
|
|
53250
|
+
if (!file || ignoredChange(file, (rel) => isDir(join56(dir, rel)))) return;
|
|
52823
53251
|
pending.add(file);
|
|
52824
53252
|
if (timer) clearTimeout(timer);
|
|
52825
53253
|
timer = setTimeout(() => {
|
|
@@ -52840,7 +53268,7 @@ function watchedContentDir(source) {
|
|
|
52840
53268
|
if (!source || /^https?:\/\//i.test(source)) return null;
|
|
52841
53269
|
const dir = resolve42(source);
|
|
52842
53270
|
try {
|
|
52843
|
-
return statSync14(dir).isDirectory() &&
|
|
53271
|
+
return statSync14(dir).isDirectory() && existsSync57(join56(dir, "himalaya.content.json")) ? dir : null;
|
|
52844
53272
|
} catch {
|
|
52845
53273
|
return null;
|
|
52846
53274
|
}
|
|
@@ -52897,7 +53325,7 @@ function serialize(task) {
|
|
|
52897
53325
|
});
|
|
52898
53326
|
}
|
|
52899
53327
|
function himiDir(dir) {
|
|
52900
|
-
const root =
|
|
53328
|
+
const root = join56(dir, ".himi");
|
|
52901
53329
|
try {
|
|
52902
53330
|
return lstatSync10(root).isDirectory() ? root : null;
|
|
52903
53331
|
} catch (e) {
|
|
@@ -52909,11 +53337,11 @@ function himiDir(dir) {
|
|
|
52909
53337
|
function writeRunRecord(dir, record2) {
|
|
52910
53338
|
const root = himiDir(dir);
|
|
52911
53339
|
if (!root) return false;
|
|
52912
|
-
const tmp =
|
|
53340
|
+
const tmp = join56(root, `.run.json.${process.pid}.${randomUUID3()}.tmp`);
|
|
52913
53341
|
try {
|
|
52914
53342
|
writeFileSync23(tmp, `${JSON.stringify(record2, null, 2)}
|
|
52915
53343
|
`, { flag: "wx" });
|
|
52916
|
-
renameSync6(tmp,
|
|
53344
|
+
renameSync6(tmp, join56(root, "run.json"));
|
|
52917
53345
|
} catch (e) {
|
|
52918
53346
|
rmSync13(tmp, { force: true });
|
|
52919
53347
|
throw e;
|
|
@@ -52921,7 +53349,7 @@ function writeRunRecord(dir, record2) {
|
|
|
52921
53349
|
return true;
|
|
52922
53350
|
}
|
|
52923
53351
|
function removeRunRecord(dir, owner) {
|
|
52924
|
-
const root =
|
|
53352
|
+
const root = join56(dir, ".himi");
|
|
52925
53353
|
try {
|
|
52926
53354
|
if (!lstatSync10(root).isDirectory()) return;
|
|
52927
53355
|
} catch {
|
|
@@ -52936,16 +53364,16 @@ function removeRunRecord(dir, owner) {
|
|
|
52936
53364
|
}
|
|
52937
53365
|
if (typeof pid === "number" && pid !== owner) return;
|
|
52938
53366
|
}
|
|
52939
|
-
rmSync13(
|
|
53367
|
+
rmSync13(join56(root, "run.json"), { force: true });
|
|
52940
53368
|
}
|
|
52941
53369
|
function boardFile(dir, pathname) {
|
|
52942
53370
|
let rel = null;
|
|
52943
|
-
if (pathname === "/__himi/studio/" || pathname === "/__himi/studio/index.html") rel =
|
|
52944
|
-
else if (pathname === "/__himi/studio/state.js") rel =
|
|
52945
|
-
else if (pathname === "/__himi/studio/timeline.js") rel =
|
|
53371
|
+
if (pathname === "/__himi/studio/" || pathname === "/__himi/studio/index.html") rel = join56("studio", "index.html");
|
|
53372
|
+
else if (pathname === "/__himi/studio/state.js") rel = join56("studio", "state.js");
|
|
53373
|
+
else if (pathname === "/__himi/studio/timeline.js") rel = join56("studio", "timeline.js");
|
|
52946
53374
|
else {
|
|
52947
53375
|
const m = /^\/__himi\/history\/([0-9a-f]{64}\.(png|jpg|gif|webp))$/.exec(pathname);
|
|
52948
|
-
if (m) rel =
|
|
53376
|
+
if (m) rel = join56("history", m[1]);
|
|
52949
53377
|
}
|
|
52950
53378
|
if (!rel) return null;
|
|
52951
53379
|
const bytes2 = readConfined(resolve42(dir, ".himi"), rel);
|
|
@@ -52961,7 +53389,7 @@ function readConfined(root, rel) {
|
|
|
52961
53389
|
const parts = rel.split(sep13);
|
|
52962
53390
|
let at = root;
|
|
52963
53391
|
for (let i = 0; i < parts.length; i++) {
|
|
52964
|
-
at =
|
|
53392
|
+
at = join56(at, parts[i]);
|
|
52965
53393
|
const st = lstatSync10(at);
|
|
52966
53394
|
if (st.isSymbolicLink() || !(i === parts.length - 1 ? st.isFile() : st.isDirectory())) return null;
|
|
52967
53395
|
}
|
|
@@ -52970,7 +53398,7 @@ function readConfined(root, rel) {
|
|
|
52970
53398
|
const fd = openSync2(at, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
52971
53399
|
try {
|
|
52972
53400
|
if (!fstatSync(fd).isFile()) return null;
|
|
52973
|
-
return
|
|
53401
|
+
return readFileSync63(fd);
|
|
52974
53402
|
} finally {
|
|
52975
53403
|
closeSync2(fd);
|
|
52976
53404
|
}
|
|
@@ -53022,7 +53450,7 @@ __export(run_browser_exports, {
|
|
|
53022
53450
|
runInBrowser: () => runInBrowser
|
|
53023
53451
|
});
|
|
53024
53452
|
import { createServer as createServer5 } from "node:http";
|
|
53025
|
-
import { existsSync as
|
|
53453
|
+
import { existsSync as existsSync58, readFileSync as readFileSync64 } from "node:fs";
|
|
53026
53454
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
53027
53455
|
import { dirname as dirname30, resolve as resolve43 } from "node:path";
|
|
53028
53456
|
import { fileURLToPath as fileURLToPath23 } from "node:url";
|
|
@@ -53030,7 +53458,7 @@ function stagedDir() {
|
|
|
53030
53458
|
return process.env.HIMI_BROWSER_PLANE_OUT ? resolve43(process.env.HIMI_BROWSER_PLANE_OUT) : resolve43(REPO, "packages", "serve", "dist", "browser-plane");
|
|
53031
53459
|
}
|
|
53032
53460
|
function missingStaged() {
|
|
53033
|
-
return [...SERVED].filter((f) => !
|
|
53461
|
+
return [...SERVED].filter((f) => !existsSync58(resolve43(stagedDir(), f))).sort();
|
|
53034
53462
|
}
|
|
53035
53463
|
function ensureBrowserPlaneStaged() {
|
|
53036
53464
|
if (missingStaged().length === 0) return { ok: true, detail: "already staged" };
|
|
@@ -53115,7 +53543,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
|
|
|
53115
53543
|
}
|
|
53116
53544
|
const name = path2 === "/" || path2 === "/index.html" ? "host.html" : path2.slice(1);
|
|
53117
53545
|
if (SERVED.has(name)) {
|
|
53118
|
-
if (!
|
|
53546
|
+
if (!existsSync58(resolve43(stagedDir(), name))) {
|
|
53119
53547
|
const restaged = ensureBrowserPlaneStaged();
|
|
53120
53548
|
if (!restaged.ok) {
|
|
53121
53549
|
res.writeHead(503, { "content-type": "application/json" });
|
|
@@ -53125,7 +53553,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
|
|
|
53125
53553
|
}
|
|
53126
53554
|
let bytes2;
|
|
53127
53555
|
try {
|
|
53128
|
-
bytes2 =
|
|
53556
|
+
bytes2 = readFileSync64(resolve43(stagedDir(), name));
|
|
53129
53557
|
} catch (e) {
|
|
53130
53558
|
res.writeHead(503, { "content-type": "application/json" });
|
|
53131
53559
|
res.end(JSON.stringify({ error: "browser_plane_unstaged", file: name, detail: String(e) }));
|
|
@@ -53586,7 +54014,7 @@ __export(preflight_exports, {
|
|
|
53586
54014
|
parseStoreConfig: () => parseStoreConfig,
|
|
53587
54015
|
requireEnv: () => requireEnv
|
|
53588
54016
|
});
|
|
53589
|
-
import { existsSync as
|
|
54017
|
+
import { existsSync as existsSync59, readFileSync as readFileSync65 } from "node:fs";
|
|
53590
54018
|
import { isAbsolute as isAbsolute3, relative as relative10, resolve as resolve44 } from "node:path";
|
|
53591
54019
|
function isInsideRepo(p) {
|
|
53592
54020
|
const rel = relative10(REPO_ROOT3, resolve44(p));
|
|
@@ -53610,7 +54038,7 @@ function strip2(line) {
|
|
|
53610
54038
|
const hash = line.indexOf("#");
|
|
53611
54039
|
return (hash >= 0 ? line.slice(0, hash) : line).replace(/\s+$/, "");
|
|
53612
54040
|
}
|
|
53613
|
-
function
|
|
54041
|
+
function scalar3(v) {
|
|
53614
54042
|
const t = v.trim();
|
|
53615
54043
|
if (t.startsWith('"') && t.endsWith('"') || t.startsWith("'") && t.endsWith("'")) {
|
|
53616
54044
|
return t.slice(1, -1);
|
|
@@ -53633,20 +54061,20 @@ function parseStoreConfig(text5) {
|
|
|
53633
54061
|
cfg[key2] = section2;
|
|
53634
54062
|
} else {
|
|
53635
54063
|
section2 = null;
|
|
53636
|
-
cfg[key2] =
|
|
54064
|
+
cfg[key2] = scalar3(rest);
|
|
53637
54065
|
}
|
|
53638
54066
|
} else if (section2) {
|
|
53639
|
-
section2[key2] =
|
|
54067
|
+
section2[key2] = scalar3(rest);
|
|
53640
54068
|
}
|
|
53641
54069
|
}
|
|
53642
54070
|
return cfg;
|
|
53643
54071
|
}
|
|
53644
54072
|
function loadStoreConfig(app) {
|
|
53645
54073
|
const p = storeConfigPath(app);
|
|
53646
|
-
if (!
|
|
54074
|
+
if (!existsSync59(p)) {
|
|
53647
54075
|
throw new Error(`No store config at ${p}. Create apps/${app}/store/store.config.yaml first (see /setup-store-signing).`);
|
|
53648
54076
|
}
|
|
53649
|
-
return parseStoreConfig(
|
|
54077
|
+
return parseStoreConfig(readFileSync65(p, "utf8"));
|
|
53650
54078
|
}
|
|
53651
54079
|
var init_preflight = __esm({
|
|
53652
54080
|
"../store-release/preflight.ts"() {
|
|
@@ -53665,19 +54093,19 @@ __export(credential_profile_exports, {
|
|
|
53665
54093
|
profilePath: () => profilePath,
|
|
53666
54094
|
resolveStoreCredentials: () => resolveStoreCredentials
|
|
53667
54095
|
});
|
|
53668
|
-
import { existsSync as
|
|
54096
|
+
import { existsSync as existsSync60, readFileSync as readFileSync66 } from "node:fs";
|
|
53669
54097
|
import { homedir as homedir5 } from "node:os";
|
|
53670
|
-
import { join as
|
|
54098
|
+
import { join as join57 } from "node:path";
|
|
53671
54099
|
function credentialsDir(home = homedir5()) {
|
|
53672
|
-
return
|
|
54100
|
+
return join57(home, ".himalaya", "store-credentials");
|
|
53673
54101
|
}
|
|
53674
54102
|
function profilePath(name, home = homedir5()) {
|
|
53675
54103
|
if (!PROFILE_NAME.test(name)) {
|
|
53676
54104
|
throw new Error(
|
|
53677
|
-
`credential profile ${JSON.stringify(name)} is not a profile name \u2014 use letters, digits, ".", "_" or "-" starting with a letter or digit. It names ${
|
|
54105
|
+
`credential profile ${JSON.stringify(name)} is not a profile name \u2014 use letters, digits, ".", "_" or "-" starting with a letter or digit. It names ${join57(credentialsDir(home), "<name>.json")}; it is never a path.`
|
|
53678
54106
|
);
|
|
53679
54107
|
}
|
|
53680
|
-
return
|
|
54108
|
+
return join57(credentialsDir(home), `${name}.json`);
|
|
53681
54109
|
}
|
|
53682
54110
|
function parseProfile(text5, label2) {
|
|
53683
54111
|
let doc;
|
|
@@ -53708,8 +54136,8 @@ function resolveStoreCredentials(opts) {
|
|
|
53708
54136
|
const { app, cfg } = opts;
|
|
53709
54137
|
const env = opts.env ?? process.env;
|
|
53710
54138
|
const home = opts.home ?? homedir5();
|
|
53711
|
-
const read = opts.readProfile ?? ((p) =>
|
|
53712
|
-
const exists = opts.profileExists ??
|
|
54139
|
+
const read = opts.readProfile ?? ((p) => readFileSync66(p, "utf8"));
|
|
54140
|
+
const exists = opts.profileExists ?? existsSync60;
|
|
53713
54141
|
const ios = cfg.ios ?? {};
|
|
53714
54142
|
const flagName = opts.profileFlag?.trim();
|
|
53715
54143
|
const named = namedProfile(cfg, opts.profileFlag);
|
|
@@ -53789,9 +54217,9 @@ __export(preflight_app_exports, {
|
|
|
53789
54217
|
preflightApp: () => preflightApp,
|
|
53790
54218
|
profileAccount: () => profileAccount
|
|
53791
54219
|
});
|
|
53792
|
-
import { readFileSync as
|
|
54220
|
+
import { readFileSync as readFileSync67, existsSync as existsSync61, readdirSync as readdirSync29, statSync as statSync15 } from "node:fs";
|
|
53793
54221
|
import { createHash as createHash27 } from "node:crypto";
|
|
53794
|
-
import { join as
|
|
54222
|
+
import { join as join58 } from "node:path";
|
|
53795
54223
|
function analyze(projectYml, storeConfig, icon, account) {
|
|
53796
54224
|
const f = [];
|
|
53797
54225
|
const has = (re, s) => re.test(s);
|
|
@@ -53855,13 +54283,13 @@ function profileAccount(app, storeConfig, opts = {}) {
|
|
|
53855
54283
|
}
|
|
53856
54284
|
}
|
|
53857
54285
|
async function preflightApp(app, opts = {}) {
|
|
53858
|
-
const projectYml =
|
|
53859
|
-
const storeConfig =
|
|
54286
|
+
const projectYml = existsSync61(iosProjectYml(app)) ? readFileSync67(iosProjectYml(app), "utf8") : "";
|
|
54287
|
+
const storeConfig = existsSync61(storeConfigPath(app)) ? readFileSync67(storeConfigPath(app), "utf8") : "";
|
|
53860
54288
|
if (!storeConfig) return [{ level: "error", message: `no apps/${app}/store/store.config.yaml \u2014 run /setup-store-signing first.` }];
|
|
53861
54289
|
const findings = analyze(
|
|
53862
54290
|
projectYml,
|
|
53863
54291
|
storeConfig,
|
|
53864
|
-
await appIconState(
|
|
54292
|
+
await appIconState(join58(appDir(app), "ios")),
|
|
53865
54293
|
profileAccount(app, storeConfig, opts)
|
|
53866
54294
|
);
|
|
53867
54295
|
findings.push(...analyzeListing(metadataFilesPresent(app), listScreenshots(app)));
|
|
@@ -53890,18 +54318,18 @@ function analyzeSubmissionRecord(appLevel, review, opts) {
|
|
|
53890
54318
|
return f;
|
|
53891
54319
|
}
|
|
53892
54320
|
function appLevelMetadataFiles(app, locale = "en-US") {
|
|
53893
|
-
const root =
|
|
54321
|
+
const root = join58(storeDir(app), "metadata");
|
|
53894
54322
|
const out = /* @__PURE__ */ new Set();
|
|
53895
|
-
if (
|
|
53896
|
-
for (const n of
|
|
54323
|
+
if (existsSync61(root)) {
|
|
54324
|
+
for (const n of readdirSync29(root)) if (n.endsWith(".txt")) out.add(n);
|
|
53897
54325
|
}
|
|
53898
|
-
if (
|
|
54326
|
+
if (existsSync61(join58(root, locale, "privacy_url.txt"))) out.add("privacy_url.txt");
|
|
53899
54327
|
return out;
|
|
53900
54328
|
}
|
|
53901
54329
|
function reviewInfoFiles(app) {
|
|
53902
|
-
const dir =
|
|
53903
|
-
if (!
|
|
53904
|
-
return new Set(
|
|
54330
|
+
const dir = join58(storeDir(app), "review_information");
|
|
54331
|
+
if (!existsSync61(dir)) return /* @__PURE__ */ new Set();
|
|
54332
|
+
return new Set(readdirSync29(dir).filter((n) => n.endsWith(".txt")));
|
|
53905
54333
|
}
|
|
53906
54334
|
function isValidAppStoreSize(w, h) {
|
|
53907
54335
|
return APP_STORE_SIZES.some(([a, b]) => w === a && h === b || w === b && h === a);
|
|
@@ -54010,12 +54438,12 @@ function analyzePlayListing(assets) {
|
|
|
54010
54438
|
return f;
|
|
54011
54439
|
}
|
|
54012
54440
|
function playListingAssets(app, locale = "en-US") {
|
|
54013
|
-
const dir =
|
|
54441
|
+
const dir = join58(storeDir(app), "play", locale, "images");
|
|
54014
54442
|
const read = (names) => {
|
|
54015
54443
|
for (const name of names) {
|
|
54016
|
-
const p =
|
|
54444
|
+
const p = join58(dir, name);
|
|
54017
54445
|
try {
|
|
54018
|
-
if (statSync15(p).isFile()) return { name, bytes:
|
|
54446
|
+
if (statSync15(p).isFile()) return { name, bytes: readFileSync67(p) };
|
|
54019
54447
|
} catch {
|
|
54020
54448
|
}
|
|
54021
54449
|
}
|
|
@@ -54046,26 +54474,26 @@ function analyzeListing(metaFiles, shots) {
|
|
|
54046
54474
|
return f;
|
|
54047
54475
|
}
|
|
54048
54476
|
function metadataFilesPresent(app, locale = "en-US") {
|
|
54049
|
-
const dir =
|
|
54050
|
-
if (!
|
|
54051
|
-
return new Set(
|
|
54477
|
+
const dir = join58(storeDir(app), "metadata", locale);
|
|
54478
|
+
if (!existsSync61(dir)) return /* @__PURE__ */ new Set();
|
|
54479
|
+
return new Set(readdirSync29(dir).filter((n) => n.endsWith(".txt")));
|
|
54052
54480
|
}
|
|
54053
54481
|
function listScreenshots(app, locale = "en-US") {
|
|
54054
54482
|
const out = [];
|
|
54055
|
-
const flat =
|
|
54056
|
-
if (
|
|
54057
|
-
for (const png of
|
|
54058
|
-
const sz = pngSize(
|
|
54483
|
+
const flat = join58(storeDir(app), "screenshots", locale);
|
|
54484
|
+
if (existsSync61(flat)) {
|
|
54485
|
+
for (const png of readdirSync29(flat).filter((n) => n.endsWith(".png"))) {
|
|
54486
|
+
const sz = pngSize(readFileSync67(join58(flat, png)));
|
|
54059
54487
|
if (sz) out.push({ name: png, w: sz.w, h: sz.h });
|
|
54060
54488
|
}
|
|
54061
54489
|
}
|
|
54062
|
-
const legacy =
|
|
54063
|
-
if (
|
|
54064
|
-
for (const deviceDir of
|
|
54065
|
-
const d =
|
|
54490
|
+
const legacy = join58(storeDir(app), "metadata", locale, "screenshots");
|
|
54491
|
+
if (existsSync61(legacy)) {
|
|
54492
|
+
for (const deviceDir of readdirSync29(legacy)) {
|
|
54493
|
+
const d = join58(legacy, deviceDir);
|
|
54066
54494
|
if (!statSync15(d).isDirectory()) continue;
|
|
54067
|
-
for (const png of
|
|
54068
|
-
const sz = pngSize(
|
|
54495
|
+
for (const png of readdirSync29(d).filter((n) => n.endsWith(".png"))) {
|
|
54496
|
+
const sz = pngSize(readFileSync67(join58(d, png)));
|
|
54069
54497
|
if (sz) out.push({ name: `${deviceDir}/${png}`, w: sz.w, h: sz.h });
|
|
54070
54498
|
}
|
|
54071
54499
|
}
|
|
@@ -54073,13 +54501,13 @@ function listScreenshots(app, locale = "en-US") {
|
|
|
54073
54501
|
return out;
|
|
54074
54502
|
}
|
|
54075
54503
|
function placeholderHashes2() {
|
|
54076
|
-
const templateIos =
|
|
54077
|
-
if (!
|
|
54078
|
-
for (const target of
|
|
54079
|
-
const p =
|
|
54504
|
+
const templateIos = join58(appDir("_template"), "ios");
|
|
54505
|
+
if (!existsSync61(templateIos)) return [LEGACY_PLACEHOLDER_SHA2562];
|
|
54506
|
+
for (const target of readdirSync29(templateIos)) {
|
|
54507
|
+
const p = join58(templateIos, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
|
|
54080
54508
|
try {
|
|
54081
54509
|
if (!statSync15(p).isFile()) continue;
|
|
54082
|
-
return [LEGACY_PLACEHOLDER_SHA2562, createHash27("sha256").update(
|
|
54510
|
+
return [LEGACY_PLACEHOLDER_SHA2562, createHash27("sha256").update(readFileSync67(p)).digest("hex")];
|
|
54083
54511
|
} catch {
|
|
54084
54512
|
}
|
|
54085
54513
|
}
|
|
@@ -54110,12 +54538,12 @@ async function pixelIssues(bytes2) {
|
|
|
54110
54538
|
}
|
|
54111
54539
|
}
|
|
54112
54540
|
async function appIconState(iosDir) {
|
|
54113
|
-
if (!
|
|
54114
|
-
for (const target of
|
|
54115
|
-
const p =
|
|
54541
|
+
if (!existsSync61(iosDir)) return { exists: false, isPlaceholder: false, storeIssues: [] };
|
|
54542
|
+
for (const target of readdirSync29(iosDir)) {
|
|
54543
|
+
const p = join58(iosDir, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
|
|
54116
54544
|
try {
|
|
54117
54545
|
if (!statSync15(p).isFile()) continue;
|
|
54118
|
-
const bytes2 =
|
|
54546
|
+
const bytes2 = readFileSync67(p);
|
|
54119
54547
|
const hash = createHash27("sha256").update(bytes2).digest("hex");
|
|
54120
54548
|
const pixels = await pixelIssues(bytes2);
|
|
54121
54549
|
return {
|
|
@@ -54187,7 +54615,7 @@ __export(version_exports, {
|
|
|
54187
54615
|
setAndroidVersion: () => setAndroidVersion,
|
|
54188
54616
|
setIosVersion: () => setIosVersion
|
|
54189
54617
|
});
|
|
54190
|
-
import { readFileSync as
|
|
54618
|
+
import { readFileSync as readFileSync68, writeFileSync as writeFileSync24 } from "node:fs";
|
|
54191
54619
|
function readIosVersion(projectYml) {
|
|
54192
54620
|
const marketing = matchScalar(projectYml, "CFBundleShortVersionString");
|
|
54193
54621
|
const build2 = matchScalar(projectYml, "CFBundleVersion");
|
|
@@ -54245,8 +54673,8 @@ function setAndroidVersion(gradle, v) {
|
|
|
54245
54673
|
function bumpVersion(app, opts) {
|
|
54246
54674
|
const iosPath = iosProjectYml(app);
|
|
54247
54675
|
const gradlePath = androidGradle(app);
|
|
54248
|
-
const iosYml =
|
|
54249
|
-
const gradle =
|
|
54676
|
+
const iosYml = readFileSync68(iosPath, "utf8");
|
|
54677
|
+
const gradle = readFileSync68(gradlePath, "utf8");
|
|
54250
54678
|
const current = readIosVersion(iosYml);
|
|
54251
54679
|
const next = {
|
|
54252
54680
|
marketing: opts.marketing ?? current.marketing,
|
|
@@ -54263,7 +54691,7 @@ var init_version = __esm({
|
|
|
54263
54691
|
});
|
|
54264
54692
|
|
|
54265
54693
|
// ../store-release/register-bundle.ts
|
|
54266
|
-
import { readFileSync as
|
|
54694
|
+
import { readFileSync as readFileSync69 } from "node:fs";
|
|
54267
54695
|
import { createPrivateKey as createPrivateKey2, sign } from "node:crypto";
|
|
54268
54696
|
function b64url2(b) {
|
|
54269
54697
|
return Buffer.from(b).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
@@ -54281,7 +54709,7 @@ function bundleIdBody(identifier, name, platform = "IOS") {
|
|
|
54281
54709
|
async function registerBundleId(opts) {
|
|
54282
54710
|
const env = requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
|
|
54283
54711
|
assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
|
|
54284
|
-
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID,
|
|
54712
|
+
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync69(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
|
|
54285
54713
|
const res = await fetch(`${ASC_API}/v1/bundleIds`, {
|
|
54286
54714
|
method: "POST",
|
|
54287
54715
|
headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
|
|
@@ -54335,7 +54763,7 @@ __export(asc_status_exports, {
|
|
|
54335
54763
|
ascStatus: () => ascStatus,
|
|
54336
54764
|
buildVerdict: () => buildVerdict
|
|
54337
54765
|
});
|
|
54338
|
-
import { readFileSync as
|
|
54766
|
+
import { readFileSync as readFileSync70 } from "node:fs";
|
|
54339
54767
|
function buildVerdict(builds) {
|
|
54340
54768
|
if (!builds.length) {
|
|
54341
54769
|
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).";
|
|
@@ -54349,7 +54777,7 @@ function buildVerdict(builds) {
|
|
|
54349
54777
|
function client(creds) {
|
|
54350
54778
|
const env = creds ?? requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
|
|
54351
54779
|
assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
|
|
54352
|
-
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID,
|
|
54780
|
+
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync70(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
|
|
54353
54781
|
return async (path2) => {
|
|
54354
54782
|
const r = await fetch(`${ASC}${path2}`, { headers: { Authorization: `Bearer ${jwt}` } });
|
|
54355
54783
|
return { status: r.status, json: await r.json().catch(() => ({})) };
|
|
@@ -54509,7 +54937,7 @@ __export(secrets_exports, {
|
|
|
54509
54937
|
runRemoteSecretsCommand: () => runRemoteSecretsCommand,
|
|
54510
54938
|
runSecretsCommand: () => runSecretsCommand
|
|
54511
54939
|
});
|
|
54512
|
-
import { readFileSync as
|
|
54940
|
+
import { readFileSync as readFileSync71 } from "node:fs";
|
|
54513
54941
|
function environment(value) {
|
|
54514
54942
|
if (value === "preview" || value === "production") return value;
|
|
54515
54943
|
throw new Error("--environment must be preview or production");
|
|
@@ -54540,7 +54968,7 @@ async function runSecretsCommand(operation, flags, io, options = {}) {
|
|
|
54540
54968
|
io.log(JSON.stringify(await vault.list({ app, environment: env })));
|
|
54541
54969
|
return 0;
|
|
54542
54970
|
}
|
|
54543
|
-
const value = options.readValue ? options.readValue() :
|
|
54971
|
+
const value = options.readValue ? options.readValue() : readFileSync71(0, "utf8").replace(/\r?\n$/, "");
|
|
54544
54972
|
if (operation === "set") await vault.set({ app, environment: env, name, value });
|
|
54545
54973
|
else if (operation === "rotate") await vault.rotate({ app, environment: env, name, value });
|
|
54546
54974
|
else throw new Error(`unknown secrets operation ${operation}`);
|
|
@@ -54569,7 +54997,7 @@ async function runRemoteSecretsCommand(operation, flags, io, options) {
|
|
|
54569
54997
|
}
|
|
54570
54998
|
let body;
|
|
54571
54999
|
if (operation !== "list") {
|
|
54572
|
-
const value = options.readValue ? options.readValue() :
|
|
55000
|
+
const value = options.readValue ? options.readValue() : readFileSync71(0, "utf8").replace(/\r?\n$/, "");
|
|
54573
55001
|
body = JSON.stringify({ value });
|
|
54574
55002
|
}
|
|
54575
55003
|
const response = await (options.fetchImpl ?? fetch)(url, { method: operation === "list" ? "GET" : operation === "set" ? "PUT" : "POST", headers: headers2, body });
|
|
@@ -54605,15 +55033,15 @@ __export(notify_exports, {
|
|
|
54605
55033
|
runNotify: () => runNotify,
|
|
54606
55034
|
saveAdminSession: () => saveAdminSession
|
|
54607
55035
|
});
|
|
54608
|
-
import { chmodSync as chmodSync3, mkdirSync as mkdirSync28, readFileSync as
|
|
55036
|
+
import { chmodSync as chmodSync3, mkdirSync as mkdirSync28, readFileSync as readFileSync72, writeFileSync as writeFileSync25 } from "node:fs";
|
|
54609
55037
|
import { homedir as homedir6 } from "node:os";
|
|
54610
|
-
import { dirname as dirname32, join as
|
|
55038
|
+
import { dirname as dirname32, join as join59 } from "node:path";
|
|
54611
55039
|
function defaultSessionsPath() {
|
|
54612
|
-
return process.env.HIMI_ADMIN_SESSIONS_FILE ??
|
|
55040
|
+
return process.env.HIMI_ADMIN_SESSIONS_FILE ?? join59(homedir6(), ".himalaya", "admin-sessions.json");
|
|
54613
55041
|
}
|
|
54614
55042
|
function loadSessionsFile(path2 = defaultSessionsPath()) {
|
|
54615
55043
|
try {
|
|
54616
|
-
return JSON.parse(
|
|
55044
|
+
return JSON.parse(readFileSync72(path2, "utf8"));
|
|
54617
55045
|
} catch {
|
|
54618
55046
|
return {};
|
|
54619
55047
|
}
|
|
@@ -54888,11 +55316,11 @@ function resolveWixUrl(path2) {
|
|
|
54888
55316
|
if (/^https?:\/\//i.test(path2)) return path2;
|
|
54889
55317
|
return `${WIX_API3}${path2}`;
|
|
54890
55318
|
}
|
|
54891
|
-
function classifyHttp(status,
|
|
55319
|
+
function classifyHttp(status, count2) {
|
|
54892
55320
|
if (status === 428) return "not-installed";
|
|
54893
55321
|
if (status === 404) return "wrong-path";
|
|
54894
55322
|
if (status && status >= 400) return "error";
|
|
54895
|
-
return
|
|
55323
|
+
return count2 > 0 ? "ok" : "empty";
|
|
54896
55324
|
}
|
|
54897
55325
|
function makeTransport(fetchImpl, auth, timeoutMs = DEFAULT_TIMEOUT_MS4) {
|
|
54898
55326
|
return async (method, path2, body) => {
|
|
@@ -55135,9 +55563,9 @@ function planDetail(p) {
|
|
|
55135
55563
|
const pricing = p.pricing && typeof p.pricing === "object" ? p.pricing : void 0;
|
|
55136
55564
|
const sub = pricing?.subscription && typeof pricing.subscription === "object" ? pricing.subscription : void 0;
|
|
55137
55565
|
const cycleDur = sub?.cycleDuration && typeof sub.cycleDuration === "object" ? sub.cycleDuration : void 0;
|
|
55138
|
-
const
|
|
55566
|
+
const count2 = cycleDur?.count;
|
|
55139
55567
|
const unit = str4(cycleDur?.unit ?? cycleDur?.period).toLowerCase();
|
|
55140
|
-
const cycle = typeof
|
|
55568
|
+
const cycle = typeof count2 === "number" && unit ? `${count2} ${unit}` : str4(sub?.cycle ?? pricing?.cycle ?? p.period ?? p.billingPeriod);
|
|
55141
55569
|
const perks = asArr(p.perks ?? p.benefits).map((x) => str4(x) || str4(x.name)).filter(Boolean);
|
|
55142
55570
|
const bits = [cycle, perks.slice(0, 4).join("; ")].filter(Boolean);
|
|
55143
55571
|
return bits.length ? bits.join(" \xB7 ") : void 0;
|
|
@@ -55778,9 +56206,9 @@ function deriveTailoring(ctx, overrides = {}, revision = "site-derived") {
|
|
|
55778
56206
|
}
|
|
55779
56207
|
function bounded(s, max) {
|
|
55780
56208
|
if (s.length <= max) return s;
|
|
55781
|
-
const
|
|
55782
|
-
const space =
|
|
55783
|
-
return `${(space > max * 0.6 ?
|
|
56209
|
+
const cut2 = s.slice(0, max - 1);
|
|
56210
|
+
const space = cut2.lastIndexOf(" ");
|
|
56211
|
+
return `${(space > max * 0.6 ? cut2.slice(0, space) : cut2).trimEnd()}\u2026`;
|
|
55784
56212
|
}
|
|
55785
56213
|
function deriveStaticFaq(faq) {
|
|
55786
56214
|
if (!Array.isArray(faq)) return [];
|
|
@@ -57478,11 +57906,11 @@ function editorText(fields, probes) {
|
|
|
57478
57906
|
function stripLead(name) {
|
|
57479
57907
|
const [left = "", ...rest] = name.split(/\s+&\s+/);
|
|
57480
57908
|
const words = left.split(/\s+/);
|
|
57481
|
-
let
|
|
57909
|
+
let cut2 = 0;
|
|
57482
57910
|
words.forEach((w, i) => {
|
|
57483
|
-
if (LEAD_STOPWORDS.has(w.toLowerCase()))
|
|
57911
|
+
if (LEAD_STOPWORDS.has(w.toLowerCase())) cut2 = i + 1;
|
|
57484
57912
|
});
|
|
57485
|
-
const kept = words.slice(
|
|
57913
|
+
const kept = words.slice(cut2).join(" ");
|
|
57486
57914
|
return kept ? [kept, ...rest].join(" & ") : "";
|
|
57487
57915
|
}
|
|
57488
57916
|
function nameMismatches(identity, look, fields) {
|
|
@@ -57533,13 +57961,13 @@ function duplicateMedia(look, probes) {
|
|
|
57533
57961
|
const k = mediaKey(u);
|
|
57534
57962
|
counts.set(k, (counts.get(k) ?? 0) + 1);
|
|
57535
57963
|
}
|
|
57536
|
-
for (const [k,
|
|
57537
|
-
if (
|
|
57964
|
+
for (const [k, count2] of counts) {
|
|
57965
|
+
if (count2 < DUPLICATE_MEDIA_MIN || out.length >= CAP3.perKind) continue;
|
|
57538
57966
|
out.push({
|
|
57539
57967
|
kind: "duplicate-media",
|
|
57540
57968
|
value: k.slice(0, 80),
|
|
57541
57969
|
where: [where],
|
|
57542
|
-
note: `the same image is used ${
|
|
57970
|
+
note: `the same image is used ${count2} times here \u2014 template filler, not ${count2} distinct photos; do not present it as the business's gallery`
|
|
57543
57971
|
});
|
|
57544
57972
|
}
|
|
57545
57973
|
};
|
|
@@ -58382,7 +58810,7 @@ var init_brand_font = __esm({
|
|
|
58382
58810
|
|
|
58383
58811
|
// src/site-analyze/write-artifacts.ts
|
|
58384
58812
|
import { mkdirSync as mkdirSync29, writeFileSync as writeFileSync26 } from "node:fs";
|
|
58385
|
-
import { join as
|
|
58813
|
+
import { join as join60 } from "node:path";
|
|
58386
58814
|
function attachVeloSources(book, sources, put) {
|
|
58387
58815
|
const byPath = new Map((sources ?? []).map((s) => [s.path, s.text]));
|
|
58388
58816
|
for (const f of book.velo.files) {
|
|
@@ -58537,12 +58965,12 @@ async function downloadMedia(book, fetchImpl, put) {
|
|
|
58537
58965
|
}
|
|
58538
58966
|
async function writeBusinessBook(result, opts) {
|
|
58539
58967
|
const out = opts.outDir;
|
|
58540
|
-
mkdirSync29(
|
|
58541
|
-
mkdirSync29(
|
|
58968
|
+
mkdirSync29(join60(out, "evidence/pages"), { recursive: true });
|
|
58969
|
+
mkdirSync29(join60(out, "media/catalog"), { recursive: true });
|
|
58542
58970
|
const files = [];
|
|
58543
58971
|
const put = (rel, body) => {
|
|
58544
|
-
const p =
|
|
58545
|
-
mkdirSync29(
|
|
58972
|
+
const p = join60(out, rel);
|
|
58973
|
+
mkdirSync29(join60(p, ".."), { recursive: true });
|
|
58546
58974
|
writeFileSync26(p, body);
|
|
58547
58975
|
files.push(rel);
|
|
58548
58976
|
};
|
|
@@ -58636,8 +59064,8 @@ var init_customer_build = __esm({
|
|
|
58636
59064
|
});
|
|
58637
59065
|
|
|
58638
59066
|
// src/site-analyze/apply.ts
|
|
58639
|
-
import { existsSync as
|
|
58640
|
-
import { dirname as dirname33, isAbsolute as isAbsolute4, join as
|
|
59067
|
+
import { existsSync as existsSync62, readFileSync as readFileSync73, writeFileSync as writeFileSync27, copyFileSync as copyFileSync3, mkdirSync as mkdirSync30, realpathSync as realpathSync8, statSync as statSync16 } from "node:fs";
|
|
59068
|
+
import { dirname as dirname33, isAbsolute as isAbsolute4, join as join61, resolve as resolve45, sep as sep14 } from "node:path";
|
|
58641
59069
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
58642
59070
|
function unpairedRedirectNote(overlay) {
|
|
58643
59071
|
if (!overlay.wix?.clientId || overlay.wix.redirectUri) return void 0;
|
|
@@ -58652,7 +59080,7 @@ function committedShellProvisioning(path2) {
|
|
|
58652
59080
|
function findRepoRoot(cwd) {
|
|
58653
59081
|
let dir = cwd;
|
|
58654
59082
|
for (let i = 0; i < 8; i++) {
|
|
58655
|
-
if (SHELL_NAMES2.some((name) =>
|
|
59083
|
+
if (SHELL_NAMES2.some((name) => existsSync62(join61(dir, shellAppDir(name), "package.json")))) return dir;
|
|
58656
59084
|
const next = dirname33(dir);
|
|
58657
59085
|
if (next === dir) break;
|
|
58658
59086
|
dir = next;
|
|
@@ -58721,11 +59149,11 @@ function mergeCustomerOwned(committed, overlay) {
|
|
|
58721
59149
|
}
|
|
58722
59150
|
function buildMergedContract(options) {
|
|
58723
59151
|
const { appDir: appDir2, packageDir, overlay } = options;
|
|
58724
|
-
const committedPath =
|
|
58725
|
-
if (!
|
|
59152
|
+
const committedPath = join61(appDir2, "provisioning.json");
|
|
59153
|
+
if (!existsSync62(committedPath)) {
|
|
58726
59154
|
throw new Error(`shell has no committed provisioning.json at ${committedPath} to build a contract from`);
|
|
58727
59155
|
}
|
|
58728
|
-
const committed = JSON.parse(
|
|
59156
|
+
const committed = JSON.parse(readFileSync73(committedPath, "utf8"));
|
|
58729
59157
|
const merged = mergeCustomerOwned(committed, overlay);
|
|
58730
59158
|
const overlayFontFamily = (overlay.branding ?? {}).fontFamily;
|
|
58731
59159
|
const branding = merged.branding ?? {};
|
|
@@ -58737,8 +59165,8 @@ function buildMergedContract(options) {
|
|
|
58737
59165
|
};
|
|
58738
59166
|
const stage = (fromRel, toRel) => {
|
|
58739
59167
|
const from = contained(packageDir, fromRel);
|
|
58740
|
-
const to = contained(
|
|
58741
|
-
if (!from || !to || !
|
|
59168
|
+
const to = contained(join61(appDir2, STAGED), toRel.slice(STAGED.length + 1));
|
|
59169
|
+
if (!from || !to || !existsSync62(from)) return void 0;
|
|
58742
59170
|
let real;
|
|
58743
59171
|
let realRoot;
|
|
58744
59172
|
try {
|
|
@@ -58760,11 +59188,11 @@ function buildMergedContract(options) {
|
|
|
58760
59188
|
};
|
|
58761
59189
|
const icon = stage("media/icon.png", `${STAGED}/icon.png`);
|
|
58762
59190
|
if (icon) branding.appIconPath = icon;
|
|
58763
|
-
const facesPath =
|
|
58764
|
-
if (
|
|
59191
|
+
const facesPath = join61(packageDir, "media/fonts/faces.json");
|
|
59192
|
+
if (existsSync62(facesPath)) {
|
|
58765
59193
|
let faces = [];
|
|
58766
59194
|
try {
|
|
58767
|
-
const parsed = JSON.parse(
|
|
59195
|
+
const parsed = JSON.parse(readFileSync73(facesPath, "utf8"));
|
|
58768
59196
|
faces = Array.isArray(parsed) ? parsed : [];
|
|
58769
59197
|
} catch {
|
|
58770
59198
|
faces = [];
|
|
@@ -58785,9 +59213,9 @@ function buildMergedContract(options) {
|
|
|
58785
59213
|
merged.branding = branding;
|
|
58786
59214
|
const body = `${JSON.stringify(merged, null, 2)}
|
|
58787
59215
|
`;
|
|
58788
|
-
const path2 =
|
|
59216
|
+
const path2 = join61(packageDir, "provisioning.contract.json");
|
|
58789
59217
|
writeFileSync27(path2, body);
|
|
58790
|
-
const localPath =
|
|
59218
|
+
const localPath = join61(appDir2, LOCAL_CONTRACT_REL);
|
|
58791
59219
|
mkdirSync30(dirname33(localPath), { recursive: true });
|
|
58792
59220
|
writeFileSync27(localPath, body);
|
|
58793
59221
|
staged.push(localPath);
|
|
@@ -58822,10 +59250,10 @@ function catalogTypography(overlay, template) {
|
|
|
58822
59250
|
function staticFaqFor(overlay, overlayPath) {
|
|
58823
59251
|
const own3 = overlay.faq;
|
|
58824
59252
|
if (own3 !== void 0) return deriveStaticFaq(own3);
|
|
58825
|
-
const bookPath =
|
|
58826
|
-
if (!
|
|
59253
|
+
const bookPath = join61(dirname33(resolve45(overlayPath)), "book.json");
|
|
59254
|
+
if (!existsSync62(bookPath)) return void 0;
|
|
58827
59255
|
try {
|
|
58828
|
-
const book = JSON.parse(
|
|
59256
|
+
const book = JSON.parse(readFileSync73(bookPath, "utf8"));
|
|
58829
59257
|
const copy = book?.copy;
|
|
58830
59258
|
if (!copy || typeof copy !== "object" || copy.unavailable) return void 0;
|
|
58831
59259
|
const pairs = deriveStaticFaq(copy.faq);
|
|
@@ -58839,8 +59267,8 @@ async function applyOverlays(input) {
|
|
|
58839
59267
|
const cwd = resolve45(input.cwd);
|
|
58840
59268
|
const shell = input.shell ?? DEFAULT_BRANDABLE_SHELL;
|
|
58841
59269
|
assertKnownShell(shell);
|
|
58842
|
-
const overlay = JSON.parse(
|
|
58843
|
-
const tokens = JSON.parse(
|
|
59270
|
+
const overlay = JSON.parse(readFileSync73(input.overlayPath, "utf8"));
|
|
59271
|
+
const tokens = JSON.parse(readFileSync73(input.tokensPath, "utf8"));
|
|
58844
59272
|
const faq = staticFaqFor(overlay, input.overlayPath);
|
|
58845
59273
|
if (faq !== void 0) overlay.faq = faq;
|
|
58846
59274
|
const wrote = [];
|
|
@@ -58852,7 +59280,7 @@ async function applyOverlays(input) {
|
|
|
58852
59280
|
`shell "${shell}" cannot bake a customer brand \u2014 it ships no prepare:customer script`
|
|
58853
59281
|
);
|
|
58854
59282
|
}
|
|
58855
|
-
const appDir2 =
|
|
59283
|
+
const appDir2 = join61(repoRoot2, shellAppDir(shell));
|
|
58856
59284
|
const packageDir = dirname33(resolve45(input.overlayPath));
|
|
58857
59285
|
const { path: contract, staged } = buildMergedContract({ appDir: appDir2, packageDir, overlay });
|
|
58858
59286
|
wrote.push(...staged);
|
|
@@ -58874,11 +59302,11 @@ async function applyOverlays(input) {
|
|
|
58874
59302
|
note: `prepare:customer --contract with a merged contract (committed provisioning.json untouched)${unpairedInRepo ? ` \xB7 ${unpairedInRepo}` : ""}`
|
|
58875
59303
|
};
|
|
58876
59304
|
}
|
|
58877
|
-
const pkgProv =
|
|
59305
|
+
const pkgProv = join61(cwd, "provisioning.json");
|
|
58878
59306
|
assertNotCommitted(pkgProv, input.forbiddenProvisioning);
|
|
58879
59307
|
let packageFaq = faq;
|
|
58880
|
-
if (
|
|
58881
|
-
const cur = JSON.parse(
|
|
59308
|
+
if (existsSync62(pkgProv)) {
|
|
59309
|
+
const cur = JSON.parse(readFileSync73(pkgProv, "utf8"));
|
|
58882
59310
|
const merged = deepMerge4(cur, overlay);
|
|
58883
59311
|
packageFaq = merged.faq;
|
|
58884
59312
|
writeFileSync27(pkgProv, JSON.stringify(merged, null, 2) + "\n");
|
|
@@ -58887,9 +59315,9 @@ async function applyOverlays(input) {
|
|
|
58887
59315
|
writeFileSync27(pkgProv, JSON.stringify(overlay, null, 2) + "\n");
|
|
58888
59316
|
wrote.push(pkgProv);
|
|
58889
59317
|
}
|
|
58890
|
-
const pkgTokens =
|
|
58891
|
-
if (
|
|
58892
|
-
const cur = JSON.parse(
|
|
59318
|
+
const pkgTokens = join61(cwd, "tokens.json");
|
|
59319
|
+
if (existsSync62(pkgTokens) && (tokens.colors || tokens.typography)) {
|
|
59320
|
+
const cur = JSON.parse(readFileSync73(pkgTokens, "utf8"));
|
|
58893
59321
|
let tokensIn = tokens;
|
|
58894
59322
|
if (tokens.typography) {
|
|
58895
59323
|
const fonts = catalogTypography(tokens.typography, cur.typography);
|
|
@@ -58914,9 +59342,9 @@ async function applyOverlays(input) {
|
|
|
58914
59342
|
wrote.push(pkgTokens);
|
|
58915
59343
|
}
|
|
58916
59344
|
const homeAction = homeRefreshActionId(shell);
|
|
58917
|
-
const homeSrc =
|
|
58918
|
-
if (homeAction &&
|
|
58919
|
-
const prev =
|
|
59345
|
+
const homeSrc = join61(cwd, "dev/index.ts");
|
|
59346
|
+
if (homeAction && existsSync62(homeSrc)) {
|
|
59347
|
+
const prev = readFileSync73(homeSrc, "utf8");
|
|
58920
59348
|
const patched = patchBrandParams(prev, overlay, homeAction);
|
|
58921
59349
|
let next = patched.src;
|
|
58922
59350
|
if (!patched.foreign && faq?.length && prev.includes('"tier5.himiBrandedFaq.load"') && !prev.includes('"staticFaq"')) {
|
|
@@ -58947,13 +59375,13 @@ async function applyOverlays(input) {
|
|
|
58947
59375
|
notes.push(`${patched.unparsed} onAppear params block(s) in ${homeSrc} could not be read \u2014 any brand values inside them were not applied`);
|
|
58948
59376
|
}
|
|
58949
59377
|
}
|
|
58950
|
-
if (!input.iconPath || !
|
|
59378
|
+
if (!input.iconPath || !existsSync62(input.iconPath)) {
|
|
58951
59379
|
const book = input.iconPath ? dirname33(dirname33(resolve45(input.iconPath))) : void 0;
|
|
58952
59380
|
notes.push(
|
|
58953
59381
|
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"
|
|
58954
59382
|
);
|
|
58955
59383
|
}
|
|
58956
|
-
if (input.iconPath &&
|
|
59384
|
+
if (input.iconPath && existsSync62(input.iconPath)) {
|
|
58957
59385
|
try {
|
|
58958
59386
|
const installed = await installIcon(cwd, input.iconPath, { derivePlay: true });
|
|
58959
59387
|
wrote.push(...installed.wrote);
|
|
@@ -63140,7 +63568,7 @@ __export(cli_exports, {
|
|
|
63140
63568
|
runSiteAnalyze: () => runSiteAnalyze,
|
|
63141
63569
|
runSiteFunctionCli: () => runSiteFunctionCli
|
|
63142
63570
|
});
|
|
63143
|
-
import { readFileSync as
|
|
63571
|
+
import { readFileSync as readFileSync74 } from "node:fs";
|
|
63144
63572
|
import { resolve as resolve46 } from "node:path";
|
|
63145
63573
|
function assetFetchFor(_opts) {
|
|
63146
63574
|
return pinnedFetch2;
|
|
@@ -63239,7 +63667,7 @@ async function runSiteFunctionCli(opts) {
|
|
|
63239
63667
|
let source;
|
|
63240
63668
|
if (opts.sourcePath) {
|
|
63241
63669
|
const p = resolve46(opts.cwd ?? process.cwd(), opts.sourcePath);
|
|
63242
|
-
source =
|
|
63670
|
+
source = readFileSync74(p, "utf8");
|
|
63243
63671
|
}
|
|
63244
63672
|
let body;
|
|
63245
63673
|
if (opts.bodyRaw != null) {
|
|
@@ -63498,7 +63926,7 @@ __export(site_create_exports, {
|
|
|
63498
63926
|
runSiteList: () => runSiteList,
|
|
63499
63927
|
writeProvisioningBinding: () => writeProvisioningBinding
|
|
63500
63928
|
});
|
|
63501
|
-
import { existsSync as
|
|
63929
|
+
import { existsSync as existsSync63, readFileSync as readFileSync75, writeFileSync as writeFileSync28 } from "node:fs";
|
|
63502
63930
|
import { resolve as resolvePath2 } from "node:path";
|
|
63503
63931
|
function oauthClientName(projectName) {
|
|
63504
63932
|
return `${projectName} client`;
|
|
@@ -63647,7 +64075,7 @@ async function runSiteCreate(opts) {
|
|
|
63647
64075
|
if (!wantOauthApp) return { ...base, nextSteps: nextSteps(metaSiteId) };
|
|
63648
64076
|
return { ...base, clientId, redirectUri, nextSteps: nextSteps(metaSiteId, clientId) };
|
|
63649
64077
|
}
|
|
63650
|
-
function writeProvisioningBinding(target, binding2, fs = { existsSync:
|
|
64078
|
+
function writeProvisioningBinding(target, binding2, fs = { existsSync: existsSync63, readFileSync: readFileSync75, writeFileSync: writeFileSync28 }) {
|
|
63651
64079
|
const msid = binding2.siteId;
|
|
63652
64080
|
const path2 = resolvePath2(target);
|
|
63653
64081
|
const committed = committedShellProvisioning(path2);
|
|
@@ -64320,11 +64748,11 @@ var init_context = __esm({
|
|
|
64320
64748
|
});
|
|
64321
64749
|
|
|
64322
64750
|
// src/cli.ts
|
|
64323
|
-
import { mkdtempSync as mkdtempSync4, readFileSync as
|
|
64751
|
+
import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync76, mkdirSync as mkdirSync31, writeFileSync as writeFileSync29, existsSync as existsSync64, rmSync as rmSync14, readdirSync as readdirSync30, statSync as statSync17, lstatSync as lstatSync11, accessSync, constants as constants2, renameSync as renameSync7, cpSync as cpSync3 } from "node:fs";
|
|
64324
64752
|
import { execFile, execFileSync as execFileSync7, spawnSync as spawnSync5, spawn as spawn6 } from "node:child_process";
|
|
64325
64753
|
import { createHash as createHash28, randomUUID as randomUUID5 } from "node:crypto";
|
|
64326
64754
|
import { tmpdir as tmpdir5, homedir as homedir7, hostname } from "node:os";
|
|
64327
|
-
import { join as
|
|
64755
|
+
import { join as join62, resolve as resolve47, relative as relative11, basename as basename15, dirname as dirname34 } from "node:path";
|
|
64328
64756
|
import { fileURLToPath as fileURLToPath24 } from "node:url";
|
|
64329
64757
|
|
|
64330
64758
|
// ../serve-cli/src/client.ts
|
|
@@ -65525,14 +65953,14 @@ async function seedCms(opts) {
|
|
|
65525
65953
|
report2.ok = false;
|
|
65526
65954
|
continue;
|
|
65527
65955
|
}
|
|
65528
|
-
const
|
|
65529
|
-
if (
|
|
65956
|
+
const count2 = await countItems(call, id);
|
|
65957
|
+
if (count2 === null && !force) {
|
|
65530
65958
|
report2.skipped.push({ collection: id, reason: "could not read the current row count, so seeding might bury existing content. Re-run, or pass --force if you are sure." });
|
|
65531
65959
|
report2.ok = false;
|
|
65532
65960
|
continue;
|
|
65533
65961
|
}
|
|
65534
|
-
if (
|
|
65535
|
-
report2.skipped.push({ collection: id, reason: `already has ${
|
|
65962
|
+
if (count2 !== null && count2 > 0 && !force) {
|
|
65963
|
+
report2.skipped.push({ collection: id, reason: `already has ${count2} items \u2014 seeding an already-populated collection needs --force so real content is never buried under sample rows` });
|
|
65536
65964
|
continue;
|
|
65537
65965
|
}
|
|
65538
65966
|
if (!dryRun) {
|
|
@@ -65623,7 +66051,7 @@ function placeholder(type, key2, i) {
|
|
|
65623
66051
|
}
|
|
65624
66052
|
}
|
|
65625
66053
|
async function writeSeedRows(opts) {
|
|
65626
|
-
const { app, cms, dir, count = 8 } = opts;
|
|
66054
|
+
const { app, cms, dir, count: count2 = 8 } = opts;
|
|
65627
66055
|
const file = join8(dir, "cms-seed.json");
|
|
65628
66056
|
const owned = (cms?.collections ?? []).filter((s) => s.id?.startsWith(namespacePrefix(app)));
|
|
65629
66057
|
if (!owned.length) {
|
|
@@ -65654,10 +66082,10 @@ async function writeSeedRows(opts) {
|
|
|
65654
66082
|
const collections = {};
|
|
65655
66083
|
for (const spec of owned) {
|
|
65656
66084
|
existing[spec.id] = Array.from(
|
|
65657
|
-
{ length:
|
|
66085
|
+
{ length: count2 },
|
|
65658
66086
|
(_, i) => Object.fromEntries(spec.fields.map((f) => [f.key, placeholder(f.type, f.displayName || f.key, i)]))
|
|
65659
66087
|
);
|
|
65660
|
-
collections[spec.id] =
|
|
66088
|
+
collections[spec.id] = count2;
|
|
65661
66089
|
}
|
|
65662
66090
|
writeFileSync6(file, `${JSON.stringify(existing, null, 2)}
|
|
65663
66091
|
`);
|
|
@@ -65672,7 +66100,7 @@ ${s.fields.map((f) => ` ${f.key} (${f.type})`).join("\n")}`
|
|
|
65672
66100
|
schema,
|
|
65673
66101
|
``,
|
|
65674
66102
|
`Rules:`,
|
|
65675
|
-
` - Keep the exact same JSON shape: one key per collection id, an array of ${
|
|
66103
|
+
` - Keep the exact same JSON shape: one key per collection id, an array of ${count2} row objects.`,
|
|
65676
66104
|
` - Use ONLY the field keys listed above, and keep each value's JSON type (TEXT\u2192string, NUMBER\u2192number, BOOLEAN\u2192boolean, DATE/DATETIME\u2192ISO string, IMAGE/VIDEO/AUDIO/DOCUMENT\u2192an https URL).`,
|
|
65677
66105
|
` - Make the content specific and plausible for this app's domain \u2014 real-sounding names, sensible prices, varied categories. No "Lorem ipsum", no "Sample item 1".`,
|
|
65678
66106
|
` - Leave any collection key already in the file that is not listed above untouched.`,
|
|
@@ -66440,8 +66868,8 @@ var str6 = (v) => typeof v === "string" ? v : void 0;
|
|
|
66440
66868
|
var num2 = (v) => typeof v === "string" && v !== "" && Number.isFinite(Number(v)) ? Number(v) : void 0;
|
|
66441
66869
|
function embeddedTemplateCatalog() {
|
|
66442
66870
|
return availableTemplates().map((name) => {
|
|
66443
|
-
const path2 =
|
|
66444
|
-
const meta = JSON.parse(
|
|
66871
|
+
const path2 = join62(templateSourceDir(name), TEMPLATE_META_FILE);
|
|
66872
|
+
const meta = JSON.parse(readFileSync76(path2, "utf8"));
|
|
66445
66873
|
if (!meta || typeof meta.title !== "string" || typeof meta.description !== "string" || !Array.isArray(meta.tags)) {
|
|
66446
66874
|
throw new Error(`${path2} must be { title: string, description: string, tags: string[], category?: string }`);
|
|
66447
66875
|
}
|
|
@@ -67120,7 +67548,7 @@ var COMMANDS = [
|
|
|
67120
67548
|
];
|
|
67121
67549
|
function cliVersion() {
|
|
67122
67550
|
try {
|
|
67123
|
-
return JSON.parse(
|
|
67551
|
+
return JSON.parse(readFileSync76(new URL("../package.json", import.meta.url), "utf8")).version ?? "unknown";
|
|
67124
67552
|
} catch {
|
|
67125
67553
|
return "unknown";
|
|
67126
67554
|
}
|
|
@@ -67238,7 +67666,7 @@ function ageInDays(publishedAt, now = Date.now()) {
|
|
|
67238
67666
|
}
|
|
67239
67667
|
function packageVersion(path2) {
|
|
67240
67668
|
try {
|
|
67241
|
-
const version2 = JSON.parse(
|
|
67669
|
+
const version2 = JSON.parse(readFileSync76(path2, "utf8")).version;
|
|
67242
67670
|
return typeof version2 === "string" && version2 ? version2 : void 0;
|
|
67243
67671
|
} catch {
|
|
67244
67672
|
return void 0;
|
|
@@ -67247,7 +67675,7 @@ function packageVersion(path2) {
|
|
|
67247
67675
|
function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("./authoring-runtime/node_modules/@wix/himalaya/package.json", import.meta.url)) {
|
|
67248
67676
|
let dir = resolve47(fromDir);
|
|
67249
67677
|
for (; ; ) {
|
|
67250
|
-
const version2 = packageVersion(
|
|
67678
|
+
const version2 = packageVersion(join62(dir, "node_modules", "@wix", "himalaya", "package.json"));
|
|
67251
67679
|
if (version2) return { version: version2, source: "local" };
|
|
67252
67680
|
const parent = dirname34(dir);
|
|
67253
67681
|
if (parent === dir) break;
|
|
@@ -67257,7 +67685,7 @@ function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("
|
|
|
67257
67685
|
if (bundled) return { version: bundled, source: "bundled" };
|
|
67258
67686
|
try {
|
|
67259
67687
|
const root = execFileSync7("npm", ["root", "-g"], { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
67260
|
-
const version2 = root ? packageVersion(
|
|
67688
|
+
const version2 = root ? packageVersion(join62(root, "@wix", "himalaya", "package.json")) : void 0;
|
|
67261
67689
|
return version2 ? { version: version2, source: "global" } : {};
|
|
67262
67690
|
} catch {
|
|
67263
67691
|
return {};
|
|
@@ -67304,11 +67732,11 @@ var UPDATE_RETRY_AFTER_FAILURE_MS = 60 * 60 * 1e3;
|
|
|
67304
67732
|
var UPDATE_SNOOZE_MS = 24 * 60 * 60 * 1e3;
|
|
67305
67733
|
var UPDATE_REEXEC_ENV = "HIMI_UPDATED_ONCE";
|
|
67306
67734
|
function updateCachePath(env = process.env) {
|
|
67307
|
-
return env.HIMI_UPDATE_CACHE_FILE ??
|
|
67735
|
+
return env.HIMI_UPDATE_CACHE_FILE ?? join62(homedir7(), ".himalaya", "update-check.json");
|
|
67308
67736
|
}
|
|
67309
67737
|
function readUpdateCache(path2) {
|
|
67310
67738
|
try {
|
|
67311
|
-
const parsed = JSON.parse(
|
|
67739
|
+
const parsed = JSON.parse(readFileSync76(path2, "utf8"));
|
|
67312
67740
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
67313
67741
|
} catch {
|
|
67314
67742
|
return {};
|
|
@@ -67376,12 +67804,12 @@ function createUpdateRunner(spawn7 = spawnSync5) {
|
|
|
67376
67804
|
},
|
|
67377
67805
|
installedVersion: () => {
|
|
67378
67806
|
const root = globalNodeModulesRoot();
|
|
67379
|
-
return root ? packageVersion(
|
|
67807
|
+
return root ? packageVersion(join62(root, "@wix", "himalaya-cli", "package.json")) : void 0;
|
|
67380
67808
|
},
|
|
67381
67809
|
reexec: (argv) => {
|
|
67382
67810
|
const root = globalNodeModulesRoot();
|
|
67383
|
-
const entry = root ?
|
|
67384
|
-
if (!entry || !
|
|
67811
|
+
const entry = root ? join62(root, "@wix", "himalaya-cli", "dist", "cli.mjs") : void 0;
|
|
67812
|
+
if (!entry || !existsSync64(entry)) return void 0;
|
|
67385
67813
|
const result = spawnSync5(process.execPath, [entry, ...argv], {
|
|
67386
67814
|
// inherit keeps PIPED STDIN working — commands that read stdin must survive a re-exec.
|
|
67387
67815
|
stdio: "inherit",
|
|
@@ -67428,7 +67856,7 @@ function staleUpdateLockFile(cachePath, now) {
|
|
|
67428
67856
|
for (const path2 of [`${cachePath}.lock.break`, `${cachePath}.lock`]) {
|
|
67429
67857
|
let content;
|
|
67430
67858
|
try {
|
|
67431
|
-
content =
|
|
67859
|
+
content = readFileSync76(path2, "utf8");
|
|
67432
67860
|
} catch {
|
|
67433
67861
|
continue;
|
|
67434
67862
|
}
|
|
@@ -67451,7 +67879,7 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
|
|
|
67451
67879
|
const mine = lockStamp(now);
|
|
67452
67880
|
const readLock = (path2) => {
|
|
67453
67881
|
try {
|
|
67454
|
-
return
|
|
67882
|
+
return readFileSync76(path2, "utf8");
|
|
67455
67883
|
} catch {
|
|
67456
67884
|
return void 0;
|
|
67457
67885
|
}
|
|
@@ -68035,7 +68463,7 @@ function executableOnPath(name, env = process.env) {
|
|
|
68035
68463
|
const suffixes = process.platform === "win32" ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
|
|
68036
68464
|
for (const dir of entries) {
|
|
68037
68465
|
for (const suffix of suffixes) {
|
|
68038
|
-
const candidate =
|
|
68466
|
+
const candidate = join62(dir, `${name}${suffix}`);
|
|
68039
68467
|
try {
|
|
68040
68468
|
if (!statSync17(candidate).isFile()) continue;
|
|
68041
68469
|
if (process.platform !== "win32") accessSync(candidate, constants2.X_OK);
|
|
@@ -68144,7 +68572,7 @@ async function nativeConfigAdvisories(app, configSource) {
|
|
|
68144
68572
|
const { iosProjectYml: iosProjectYml2 } = await Promise.resolve().then(() => (init_paths2(), paths_exports));
|
|
68145
68573
|
const { androidOptedIn: androidOptedIn3, LABEL_IOS_SPLASH: LABEL_IOS_SPLASH2 } = await Promise.resolve().then(() => (init_splash(), splash_exports));
|
|
68146
68574
|
const iosYmlPath = iosProjectYml2(app);
|
|
68147
|
-
const iosYml =
|
|
68575
|
+
const iosYml = existsSync64(iosYmlPath) ? readFileSync76(iosYmlPath, "utf8") : "";
|
|
68148
68576
|
let optedIn = iosYml.includes(LABEL_IOS_SPLASH2);
|
|
68149
68577
|
if (!optedIn) {
|
|
68150
68578
|
const { androidManifestPath: androidManifestPath3 } = await Promise.resolve().then(() => (init_gen_native_config(), gen_native_config_exports));
|
|
@@ -68158,7 +68586,7 @@ async function nativeConfigAdvisories(app, configSource) {
|
|
|
68158
68586
|
}
|
|
68159
68587
|
function readConfigSource(dir) {
|
|
68160
68588
|
try {
|
|
68161
|
-
return
|
|
68589
|
+
return readFileSync76(join62(dir, "config.ts"), "utf8");
|
|
68162
68590
|
} catch {
|
|
68163
68591
|
return null;
|
|
68164
68592
|
}
|
|
@@ -68194,7 +68622,7 @@ function keptPlan(kept) {
|
|
|
68194
68622
|
}
|
|
68195
68623
|
async function initFromRemoteTemplate(name, parentDir, template, c) {
|
|
68196
68624
|
const dir = resolve47(parentDir, name);
|
|
68197
|
-
if (
|
|
68625
|
+
if (existsSync64(join62(dir, "himalaya.content.json"))) {
|
|
68198
68626
|
throw new Error(`content package already exists at ${dir}`);
|
|
68199
68627
|
}
|
|
68200
68628
|
const r = await c.fetchTemplateSource(TEMPLATE_APP_PREFIX + template);
|
|
@@ -68237,11 +68665,11 @@ function symlinkDestinationIssue(dest) {
|
|
|
68237
68665
|
function restoreDestinationIssue(dest, force) {
|
|
68238
68666
|
const link = symlinkDestinationIssue(dest);
|
|
68239
68667
|
if (link) return link;
|
|
68240
|
-
if (!
|
|
68668
|
+
if (!existsSync64(dest)) return null;
|
|
68241
68669
|
if (!statSync17(dest).isDirectory()) {
|
|
68242
68670
|
return { error: `${dest} exists and is not a directory`, hint: "pass --out/--name to land somewhere else, or remove the file" };
|
|
68243
68671
|
}
|
|
68244
|
-
if (
|
|
68672
|
+
if (readdirSync30(dest).length > 0 && !force) {
|
|
68245
68673
|
return {
|
|
68246
68674
|
error: `${dest} already exists and is not empty`,
|
|
68247
68675
|
hint: "pass --force to write into it anyway, or --out/--name to land somewhere else"
|
|
@@ -68252,7 +68680,7 @@ function restoreDestinationIssue(dest, force) {
|
|
|
68252
68680
|
function isHimalayaMonorepoCheckout(start) {
|
|
68253
68681
|
let dir = resolve47(start);
|
|
68254
68682
|
for (; ; ) {
|
|
68255
|
-
if (
|
|
68683
|
+
if (existsSync64(join62(dir, "tools", "himi-cli", "src", "cli.ts")) && existsSync64(join62(dir, "core", "serve", "src", "server.ts"))) return true;
|
|
68256
68684
|
const parent = dirname34(dir);
|
|
68257
68685
|
if (parent === dir) return false;
|
|
68258
68686
|
dir = parent;
|
|
@@ -68313,7 +68741,7 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
68313
68741
|
Object.entries(files).map(([rel, body]) => [rel, rel === "himalaya.content.json" ? substituteIdentity(body, slug) : body])
|
|
68314
68742
|
);
|
|
68315
68743
|
const repoRoot2 = resolve47(fileURLToPath24(new URL("../../..", import.meta.url)));
|
|
68316
|
-
const root =
|
|
68744
|
+
const root = join62(repoRoot2, "node_modules", ".cache", "himi-template-preview");
|
|
68317
68745
|
const stillRunning = (pid) => {
|
|
68318
68746
|
try {
|
|
68319
68747
|
process.kill(pid, 0);
|
|
@@ -68323,16 +68751,16 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
68323
68751
|
}
|
|
68324
68752
|
};
|
|
68325
68753
|
try {
|
|
68326
|
-
for (const entry of
|
|
68754
|
+
for (const entry of readdirSync30(root, { withFileTypes: true })) {
|
|
68327
68755
|
if (!entry.isDirectory()) continue;
|
|
68328
68756
|
const pid = Number(entry.name.startsWith(`${slug}-`) ? entry.name.slice(slug.length + 1) : NaN);
|
|
68329
68757
|
if (Number.isInteger(pid) && pid > 0 && pid !== process.pid && !stillRunning(pid)) {
|
|
68330
|
-
rmSync14(
|
|
68758
|
+
rmSync14(join62(root, entry.name), { recursive: true, force: true });
|
|
68331
68759
|
}
|
|
68332
68760
|
}
|
|
68333
68761
|
} catch {
|
|
68334
68762
|
}
|
|
68335
|
-
const dest =
|
|
68763
|
+
const dest = join62(root, `${slug}-${process.pid}`);
|
|
68336
68764
|
rmSync14(dest, { recursive: true, force: true });
|
|
68337
68765
|
mkdirSync31(dest, { recursive: true });
|
|
68338
68766
|
try {
|
|
@@ -68345,8 +68773,8 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
68345
68773
|
}
|
|
68346
68774
|
async function appId(dir) {
|
|
68347
68775
|
try {
|
|
68348
|
-
const { readFileSync:
|
|
68349
|
-
const m = JSON.parse(
|
|
68776
|
+
const { readFileSync: readFileSync77 } = await import("node:fs");
|
|
68777
|
+
const m = JSON.parse(readFileSync77(join62(dir, "himalaya.content.json"), "utf8"));
|
|
68350
68778
|
if (m.name) return m.name;
|
|
68351
68779
|
} catch {
|
|
68352
68780
|
}
|
|
@@ -68354,8 +68782,8 @@ async function appId(dir) {
|
|
|
68354
68782
|
}
|
|
68355
68783
|
async function contentVisibility(dir) {
|
|
68356
68784
|
try {
|
|
68357
|
-
const { readFileSync:
|
|
68358
|
-
const m = JSON.parse(
|
|
68785
|
+
const { readFileSync: readFileSync77 } = await import("node:fs");
|
|
68786
|
+
const m = JSON.parse(readFileSync77(join62(dir, "himalaya.content.json"), "utf8"));
|
|
68359
68787
|
if (m.visibility === "public" || m.visibility === "unlisted") return m.visibility;
|
|
68360
68788
|
} catch {
|
|
68361
68789
|
}
|
|
@@ -68579,7 +69007,7 @@ Seed your coding agent with \`himi agent-init\`. Guides: ${idx.portalUrl}`);
|
|
|
68579
69007
|
...res.removed.length ? { removed: res.removed, note: "older copies at the app root, moved to .himi/legacy-agent-files/ (a backup, in case one became app code) \u2014 the current ones live in .agents/skills/himalaya/" } : {},
|
|
68580
69008
|
// In a git repo the refresh moves the diff identity an earlier `himi test` attested (that
|
|
68581
69009
|
// hash is shared with the repo gates and deliberately exempts nothing but its own metadata).
|
|
68582
|
-
...
|
|
69010
|
+
...existsSync64(join62(dir, ".himi", "attestations", "latest.json")) ? { next: "if `himi push` then refuses the attestation as stale, re-run `himi test` \u2014 in a git checkout this refresh changed the tree it covered" } : {},
|
|
68583
69011
|
...res.skipped.length ? { skipped: res.skipped } : {},
|
|
68584
69012
|
portalUrl: idx.portalUrl
|
|
68585
69013
|
});
|
|
@@ -68602,7 +69030,7 @@ async function recordedReleaseForContentQuietly(dir, resolution, onDrift) {
|
|
|
68602
69030
|
try {
|
|
68603
69031
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
68604
69032
|
const bres = await buildContentForValidation2(dir, { resolution });
|
|
68605
|
-
out = mkdtempSync4(
|
|
69033
|
+
out = mkdtempSync4(join62(tmpdir5(), "himi-ux-record-"));
|
|
68606
69034
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
68607
69035
|
const outcome = await buildReleaseFromContent2(dir, out, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {}, collect: { lint: true } });
|
|
68608
69036
|
const releaseId = outcome.manifest.releaseId;
|
|
@@ -68769,7 +69197,7 @@ async function producedWidgetFamilies(dir) {
|
|
|
68769
69197
|
}
|
|
68770
69198
|
const outDir = tier5Dir.bundleOutDir(dir);
|
|
68771
69199
|
try {
|
|
68772
|
-
|
|
69200
|
+
readdirSync30(outDir);
|
|
68773
69201
|
} catch {
|
|
68774
69202
|
return { families: void 0, source: "unbuilt" };
|
|
68775
69203
|
}
|
|
@@ -68780,7 +69208,7 @@ async function producedWidgetFamilies(dir) {
|
|
|
68780
69208
|
let js;
|
|
68781
69209
|
for (const candidate of [`${name}.bundle.js`, `${name}.js`, name]) {
|
|
68782
69210
|
try {
|
|
68783
|
-
js =
|
|
69211
|
+
js = readFileSync76(join62(outDir, candidate), "utf8");
|
|
68784
69212
|
break;
|
|
68785
69213
|
} catch {
|
|
68786
69214
|
}
|
|
@@ -68811,12 +69239,27 @@ async function producedWidgetFamilies(dir) {
|
|
|
68811
69239
|
}
|
|
68812
69240
|
return { families, source: "dist/bundles" };
|
|
68813
69241
|
}
|
|
68814
|
-
var boardOpen = (dir) =>
|
|
69242
|
+
var boardOpen = (dir) => existsSync64(join62(dir, ".himi", "studio", "index.html"));
|
|
68815
69243
|
var BOARD_REFRESHERS = /* @__PURE__ */ new Set(["render", "test", "validate", "build", "push", "icon", "site", "ux", "progress"]);
|
|
68816
69244
|
async function leaveForBoard(dir, record2, value) {
|
|
68817
69245
|
if (!boardOpen(dir)) return;
|
|
68818
|
-
const { writeStudioRecord: writeStudioRecord2, VALIDATE_RECORD: VALIDATE_RECORD2, PUSH_RECORD: PUSH_RECORD2, EDGES_RECORD: EDGES_RECORD2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
|
|
68819
|
-
writeStudioRecord2(dir, { validate: VALIDATE_RECORD2, push: PUSH_RECORD2, edges: EDGES_RECORD2 }[record2], value);
|
|
69246
|
+
const { writeStudioRecord: writeStudioRecord2, VALIDATE_RECORD: VALIDATE_RECORD2, PUSH_RECORD: PUSH_RECORD2, EDGES_RECORD: EDGES_RECORD2, MAP_RECORD: MAP_RECORD2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
|
|
69247
|
+
writeStudioRecord2(dir, { validate: VALIDATE_RECORD2, push: PUSH_RECORD2, edges: EDGES_RECORD2, map: MAP_RECORD2 }[record2], value);
|
|
69248
|
+
}
|
|
69249
|
+
async function liveMapFor(dir) {
|
|
69250
|
+
if (!boardOpen(dir)) return void 0;
|
|
69251
|
+
const { writeStudioRecord: writeStudioRecord2, refreshStudio: refreshStudio2, MAP_RECORD: MAP_RECORD2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
|
|
69252
|
+
let last = 0;
|
|
69253
|
+
return (map) => {
|
|
69254
|
+
const now = Date.now();
|
|
69255
|
+
if (now - last < 1e3) return;
|
|
69256
|
+
last = now;
|
|
69257
|
+
try {
|
|
69258
|
+
writeStudioRecord2(dir, MAP_RECORD2, map);
|
|
69259
|
+
refreshStudio2(dir);
|
|
69260
|
+
} catch {
|
|
69261
|
+
}
|
|
69262
|
+
};
|
|
68820
69263
|
}
|
|
68821
69264
|
async function run(argv, io = defaultIO, deps = {}) {
|
|
68822
69265
|
const code = await runCommand(argv, io, deps);
|
|
@@ -69091,7 +69534,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69091
69534
|
const owed = openApprovals2(readApprovals2(dir).events).length;
|
|
69092
69535
|
next.push(`carried the planning journal into the app (${carried.join(", ")}${owed ? `; ${owed} approval${owed === 1 ? "" : "s"} still owed` : ""}) \u2014 \`himi progress --brief\` there shows it`);
|
|
69093
69536
|
}
|
|
69094
|
-
const planInParent = ["SPEC.md", "MOBILE-UX.md"].filter((f) =>
|
|
69537
|
+
const planInParent = ["SPEC.md", "MOBILE-UX.md"].filter((f) => existsSync64(join62(parentDir, f)));
|
|
69095
69538
|
if (planInParent.length) {
|
|
69096
69539
|
next.push(`${planInParent.join(" and ")} in ${parentDir} ${planInParent.length > 1 ? "are" : "is"} not the app's \u2014 if that is the approved plan, move it over the template's boilerplate in ${dir}`);
|
|
69097
69540
|
}
|
|
@@ -69218,7 +69661,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69218
69661
|
const sourceDir = resolve47(str6(flags["source-dir"]) ?? appDir2);
|
|
69219
69662
|
let meta;
|
|
69220
69663
|
try {
|
|
69221
|
-
meta = JSON.parse(
|
|
69664
|
+
meta = JSON.parse(readFileSync76(join62(sourceDir, TEMPLATE_META_FILE), "utf8"));
|
|
69222
69665
|
} catch {
|
|
69223
69666
|
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>)` }));
|
|
69224
69667
|
return 2;
|
|
@@ -69228,7 +69671,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69228
69671
|
return 2;
|
|
69229
69672
|
}
|
|
69230
69673
|
try {
|
|
69231
|
-
const appearance = extractTemplateAppearance(JSON.parse(
|
|
69674
|
+
const appearance = extractTemplateAppearance(JSON.parse(readFileSync76(join62(sourceDir, "tokens.json"), "utf8")));
|
|
69232
69675
|
meta = { ...appearance, ...meta };
|
|
69233
69676
|
} catch {
|
|
69234
69677
|
}
|
|
@@ -69250,7 +69693,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69250
69693
|
const force = flags.force === true;
|
|
69251
69694
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
69252
69695
|
const bres = await buildContentForValidation2(buildDir, { resolution: resolutionFlag(flags) });
|
|
69253
|
-
const out = mkdtempSync4(
|
|
69696
|
+
const out = mkdtempSync4(join62(tmpdir5(), "himi-template-"));
|
|
69254
69697
|
publishScratch.push(out);
|
|
69255
69698
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
69256
69699
|
const outcome = await buildReleaseFromContent2(buildDir, out, {
|
|
@@ -69304,7 +69747,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69304
69747
|
let iconHash;
|
|
69305
69748
|
if (iconPath) {
|
|
69306
69749
|
try {
|
|
69307
|
-
const bytes2 =
|
|
69750
|
+
const bytes2 = readFileSync76(iconPath);
|
|
69308
69751
|
payload.icon = bytes2.toString("base64");
|
|
69309
69752
|
iconHash = createHash28("sha256").update(bytes2).digest("hex");
|
|
69310
69753
|
} catch {
|
|
@@ -69510,12 +69953,12 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69510
69953
|
print({ ok: false, error: "eject needs a module", hint: `one of: ${EJECTABLE2.join(", ")}` });
|
|
69511
69954
|
return 2;
|
|
69512
69955
|
}
|
|
69513
|
-
const { readdirSync:
|
|
69956
|
+
const { readdirSync: readdirSync31, existsSync: fileExists } = await import("node:fs");
|
|
69514
69957
|
const { join: pathJoin } = await import("node:path");
|
|
69515
69958
|
const targets = [];
|
|
69516
69959
|
const t5 = pathJoin(dir, "tier5-src");
|
|
69517
69960
|
if (fileExists(t5)) {
|
|
69518
|
-
for (const d of
|
|
69961
|
+
for (const d of readdirSync31(t5, { withFileTypes: true })) {
|
|
69519
69962
|
if (d.isDirectory()) targets.push(pathJoin(t5, d.name, "index.ts"));
|
|
69520
69963
|
}
|
|
69521
69964
|
}
|
|
@@ -69547,7 +69990,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69547
69990
|
const { navIssues: navIssues2 } = await Promise.resolve().then(() => (init_nav_lint(), nav_lint_exports));
|
|
69548
69991
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
69549
69992
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
69550
|
-
const out = mkdtempSync4(
|
|
69993
|
+
const out = mkdtempSync4(join62(tmpdir5(), "himi-validate-"));
|
|
69551
69994
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
69552
69995
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
69553
69996
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -69590,7 +70033,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69590
70033
|
const path2 = dpxSessionTokenPath();
|
|
69591
70034
|
let raw;
|
|
69592
70035
|
try {
|
|
69593
|
-
raw =
|
|
70036
|
+
raw = readFileSync76(path2, "utf8");
|
|
69594
70037
|
} catch {
|
|
69595
70038
|
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`);
|
|
69596
70039
|
}
|
|
@@ -69710,13 +70153,13 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69710
70153
|
case "studio": {
|
|
69711
70154
|
const { openStudio: openStudio2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
|
|
69712
70155
|
const dir = contentDir(flags);
|
|
69713
|
-
if (!
|
|
70156
|
+
if (!existsSync64(join62(dir, "himalaya.content.json"))) {
|
|
69714
70157
|
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/" }));
|
|
69715
70158
|
return 2;
|
|
69716
70159
|
}
|
|
69717
70160
|
if (pos[1] === "reel") {
|
|
69718
70161
|
const { buildReel: buildReel2 } = await Promise.resolve().then(() => (init_studio_reel(), studio_reel_exports));
|
|
69719
|
-
const out = resolve47(str6(flags.out) ??
|
|
70162
|
+
const out = resolve47(str6(flags.out) ?? join62(dir, ".himi", "making-of.html"));
|
|
69720
70163
|
const { html, plan } = buildReel2(dir);
|
|
69721
70164
|
mkdirSync31(dirname34(out), { recursive: true });
|
|
69722
70165
|
writeFileSync29(out, html);
|
|
@@ -69783,7 +70226,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69783
70226
|
} = await Promise.resolve().then(() => (init_progress(), progress_exports));
|
|
69784
70227
|
const dir = contentDir(flags);
|
|
69785
70228
|
const journal = journalPath2(dir);
|
|
69786
|
-
const isContentPackage =
|
|
70229
|
+
const isContentPackage = existsSync64(join62(dir, "himalaya.content.json"));
|
|
69787
70230
|
const hint = isContentPackage ? {} : { hint: "no himalaya.content.json here \u2014 run from the app directory (or pass --content <dir>) so the build board finds this journal" };
|
|
69788
70231
|
const message = pos.slice(1).join(" ").trim();
|
|
69789
70232
|
const approvalFlags = ["approve", "done", "drop"].filter((f) => flags[f] !== void 0);
|
|
@@ -69855,8 +70298,8 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69855
70298
|
try {
|
|
69856
70299
|
const entry = appendProgress2(dir, { message, ...step ? { step } : {}, images });
|
|
69857
70300
|
const notified = flags.notify === true ? await notifyDesktop2(`himi \xB7 ${appLabel2(dir) ?? "your app"}`, message) : void 0;
|
|
69858
|
-
const { count } = summarizeProgress2(readProgress2(dir).entries);
|
|
69859
|
-
print({ ok: true, entry, journal, count, ...notified === void 0 ? {} : { notified }, ...hint });
|
|
70301
|
+
const { count: count2 } = summarizeProgress2(readProgress2(dir).entries);
|
|
70302
|
+
print({ ok: true, entry, journal, count: count2, ...notified === void 0 ? {} : { notified }, ...hint });
|
|
69860
70303
|
return 0;
|
|
69861
70304
|
} catch (e) {
|
|
69862
70305
|
if (e instanceof ProgressError2) {
|
|
@@ -69919,7 +70362,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69919
70362
|
case "test": {
|
|
69920
70363
|
const dir = contentDir(flags);
|
|
69921
70364
|
const structuredOutput = flags.json === true || io.isTTY !== true;
|
|
69922
|
-
if (
|
|
70365
|
+
if (existsSync64(join62(dir, "functions"))) {
|
|
69923
70366
|
const { invokeLocalFunction: invokeLocalFunction2, loadFunctionsApp: loadFunctionsApp2 } = await Promise.resolve().then(() => (init_functions(), functions_exports));
|
|
69924
70367
|
const loaded = await loadFunctionsApp2(dir);
|
|
69925
70368
|
const results = [];
|
|
@@ -70006,7 +70449,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70006
70449
|
}
|
|
70007
70450
|
}
|
|
70008
70451
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
70009
|
-
const out = mkdtempSync4(
|
|
70452
|
+
const out = mkdtempSync4(join62(tmpdir5(), "himi-test-"));
|
|
70010
70453
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
70011
70454
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
70012
70455
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -70051,7 +70494,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70051
70494
|
io.error(JSON.stringify({ error: `screen "${screen.screenId}" has no Tier-5 worker, so there is nothing for the browser loop to build` }));
|
|
70052
70495
|
return 2;
|
|
70053
70496
|
}
|
|
70054
|
-
const sources = collectWorkerSources2(
|
|
70497
|
+
const sources = collectWorkerSources2(join62(dir, "tier5-src"), screen.bundleName);
|
|
70055
70498
|
if (!sources) {
|
|
70056
70499
|
io.error(JSON.stringify({ error: `no worker source found at tier5-src/${screen.bundleName} \u2014 the browser loop compiles SOURCE, not the built bundle` }));
|
|
70057
70500
|
return 2;
|
|
@@ -70152,6 +70595,8 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70152
70595
|
const cmsSeed = offline ? null : await cmsSeedRows(dir, app);
|
|
70153
70596
|
const canned = offline ? null : readCannedResponses2();
|
|
70154
70597
|
const tabRoots = await tabRootScreens(dir);
|
|
70598
|
+
const onScreen = await liveMapFor(dir);
|
|
70599
|
+
const mapEntries = await navEntryScreens(dir, outcome.homeScreenId);
|
|
70155
70600
|
let result;
|
|
70156
70601
|
try {
|
|
70157
70602
|
result = await runCrawl2({
|
|
@@ -70168,6 +70613,8 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70168
70613
|
...cmsSeed ? { cmsSeed } : {},
|
|
70169
70614
|
...canned ? { canned } : {},
|
|
70170
70615
|
...tabRoots.size ? { tabRoots } : {},
|
|
70616
|
+
...onScreen ? { onScreen } : {},
|
|
70617
|
+
...mapEntries.size ? { mapEntries } : {},
|
|
70171
70618
|
// The app's exact linkable set, straight off the build outcome (#2512) — arms the
|
|
70172
70619
|
// nav-target check. Omitted when the build reported none, so the crawl stays silent
|
|
70173
70620
|
// rather than judging every target against an empty set.
|
|
@@ -70212,7 +70659,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70212
70659
|
const sp = await runShotsPass2({
|
|
70213
70660
|
descriptors: scopeDescriptors2(outcome.descriptors ?? [], pos.slice(1), invalidScreens),
|
|
70214
70661
|
tokens: outcome.tokens,
|
|
70215
|
-
outDir:
|
|
70662
|
+
outDir: join62(dir, ".himi", "shots"),
|
|
70216
70663
|
width: 390,
|
|
70217
70664
|
layers: { rules: shotRules, ...cmsSeed ? { cmsSeed } : {}, ...canned ? { canned: canned.byKey } : {} },
|
|
70218
70665
|
...budgetMs ? { budgetMs } : {},
|
|
@@ -70250,11 +70697,11 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70250
70697
|
releaseId: result.releaseId,
|
|
70251
70698
|
releasePayload: release,
|
|
70252
70699
|
descriptors: attestedDescriptors,
|
|
70253
|
-
screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""),
|
|
70700
|
+
screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""), join62(dir, ".himi", "shots", name)])),
|
|
70254
70701
|
coverage: {
|
|
70255
70702
|
screens: crawledScreens.size,
|
|
70256
70703
|
actionsDispatched: result.actions.exercised,
|
|
70257
|
-
uncoveredFns: (result.crawled ?? []).reduce((
|
|
70704
|
+
uncoveredFns: (result.crawled ?? []).reduce((count2, screen) => count2 + (screen.uncoveredFunctions?.length ?? 0), 0),
|
|
70258
70705
|
gaps: ledger.length
|
|
70259
70706
|
},
|
|
70260
70707
|
report: {
|
|
@@ -70271,6 +70718,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70271
70718
|
}));
|
|
70272
70719
|
} else io.log(formatReport2(result) + formatDelta2(delta) + formatLedger2(ledger, trend));
|
|
70273
70720
|
await leaveForBoard(dir, "edges", result.edges ?? []);
|
|
70721
|
+
if (result.navGraph) await leaveForBoard(dir, "map", result.navGraph);
|
|
70274
70722
|
return result.ok ? 0 : 1;
|
|
70275
70723
|
}
|
|
70276
70724
|
case "render": {
|
|
@@ -70340,7 +70788,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70340
70788
|
return 2;
|
|
70341
70789
|
}
|
|
70342
70790
|
try {
|
|
70343
|
-
const raw = stateArg.trim().startsWith("{") ? stateArg :
|
|
70791
|
+
const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync76(stateArg.replace(/^@/, ""), "utf8");
|
|
70344
70792
|
injectedState = JSON.parse(raw);
|
|
70345
70793
|
} catch (e) {
|
|
70346
70794
|
io.error(JSON.stringify({ error: `--state must be inline JSON or a path to a .json file \u2014 ${e.message}` }));
|
|
@@ -70355,7 +70803,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70355
70803
|
return 2;
|
|
70356
70804
|
}
|
|
70357
70805
|
try {
|
|
70358
|
-
const raw = inputArg.trim().startsWith("{") ? inputArg :
|
|
70806
|
+
const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync76(inputArg.replace(/^@/, ""), "utf8");
|
|
70359
70807
|
const parsed = JSON.parse(raw);
|
|
70360
70808
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("must be a JSON object");
|
|
70361
70809
|
injectedInput = parsed;
|
|
@@ -70404,7 +70852,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70404
70852
|
}
|
|
70405
70853
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
70406
70854
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
70407
|
-
const out = mkdtempSync4(
|
|
70855
|
+
const out = mkdtempSync4(join62(tmpdir5(), "himi-render-"));
|
|
70408
70856
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
70409
70857
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
70410
70858
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -70418,7 +70866,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70418
70866
|
const diagnostics = (outcome.lint ?? []).find((s) => s.screenId === screenId)?.issues ?? [];
|
|
70419
70867
|
let pngFile;
|
|
70420
70868
|
let attestationPngFile;
|
|
70421
|
-
const shotPath =
|
|
70869
|
+
const shotPath = join62(dir, ".himi", "shots", `${screenId}.png`);
|
|
70422
70870
|
const pngTarget = typeof flags.png === "string" ? str6(flags.png) : flags.png === true ? shotPath : void 0;
|
|
70423
70871
|
if (pngTarget && r.pngBase64) {
|
|
70424
70872
|
pngFile = writePngFile(pngTarget, r.pngBase64);
|
|
@@ -70754,7 +71202,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
70754
71202
|
io.error(JSON.stringify(linked));
|
|
70755
71203
|
return 1;
|
|
70756
71204
|
}
|
|
70757
|
-
if (
|
|
71205
|
+
if (existsSync64(dest)) {
|
|
70758
71206
|
if (!statSync17(dest).isDirectory()) {
|
|
70759
71207
|
io.error(JSON.stringify({
|
|
70760
71208
|
error: `${dest} exists and is not a directory`,
|
|
@@ -70762,12 +71210,12 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
70762
71210
|
}));
|
|
70763
71211
|
return 1;
|
|
70764
71212
|
}
|
|
70765
|
-
const occupied =
|
|
71213
|
+
const occupied = readdirSync30(dest).length > 0;
|
|
70766
71214
|
if (occupied && !force) {
|
|
70767
71215
|
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" }));
|
|
70768
71216
|
return 1;
|
|
70769
71217
|
}
|
|
70770
|
-
if (replace && occupied && !
|
|
71218
|
+
if (replace && occupied && !existsSync64(join62(dest, "himalaya.content.json"))) {
|
|
70771
71219
|
io.error(JSON.stringify({
|
|
70772
71220
|
error: `${dest} is not a content package \u2014 refusing to --replace it`,
|
|
70773
71221
|
hint: "--replace only clears a directory that holds himalaya.content.json. Check --out/--name, or pass --force to merge into it instead."
|
|
@@ -70908,7 +71356,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
70908
71356
|
const force = flags.force === true;
|
|
70909
71357
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
70910
71358
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
70911
|
-
const out = mkdtempSync4(
|
|
71359
|
+
const out = mkdtempSync4(join62(tmpdir5(), "himi-push-"));
|
|
70912
71360
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
70913
71361
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
70914
71362
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -71429,7 +71877,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71429
71877
|
}
|
|
71430
71878
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
71431
71879
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
71432
|
-
const built = mkdtempSync4(
|
|
71880
|
+
const built = mkdtempSync4(join62(tmpdir5(), "himi-pack-"));
|
|
71433
71881
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
71434
71882
|
const outcome = await buildReleaseFromContent2(dir, built, {
|
|
71435
71883
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -71634,7 +72082,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71634
72082
|
}));
|
|
71635
72083
|
return 1;
|
|
71636
72084
|
}
|
|
71637
|
-
const archive =
|
|
72085
|
+
const archive = readFileSync76(resolve47(file));
|
|
71638
72086
|
const result = await client2().createPackageShare({
|
|
71639
72087
|
app: opened.header.app,
|
|
71640
72088
|
releaseId: opened.header.releaseId,
|
|
@@ -71694,11 +72142,11 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71694
72142
|
const app = await appId(dir2);
|
|
71695
72143
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
71696
72144
|
const bres = await buildContentBundles2(dir2, { resolution: resolutionFlag(flags) });
|
|
71697
|
-
temp = mkdtempSync4(
|
|
72145
|
+
temp = mkdtempSync4(join62(tmpdir5(), "himi-run-build-"));
|
|
71698
72146
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
71699
72147
|
const initial = await buildReleaseFromContent2(dir2, temp, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir2) } : {} });
|
|
71700
72148
|
servedMissing = initial.missingBundles;
|
|
71701
|
-
source =
|
|
72149
|
+
source = join62(temp, app);
|
|
71702
72150
|
}
|
|
71703
72151
|
const chromeArg = str6(flags.chrome) ?? "preview";
|
|
71704
72152
|
if (chromeArg !== "preview" && chromeArg !== "app") {
|
|
@@ -71734,7 +72182,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71734
72182
|
if (!recordKit) return;
|
|
71735
72183
|
startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
71736
72184
|
const failure = record2(served2, { ok: true, at: startedAt });
|
|
71737
|
-
if (!recorded) io.error(JSON.stringify({ run: "run_record_skipped", message: `${failure ?? `${
|
|
72185
|
+
if (!recorded) io.error(JSON.stringify({ run: "run_record_skipped", message: `${failure ?? `${join62(dir, ".himi")} is not a real directory`}, so the build board will not frame this preview.` }));
|
|
71738
72186
|
await refreshBoard();
|
|
71739
72187
|
};
|
|
71740
72188
|
const retract = async () => {
|
|
@@ -71765,7 +72213,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71765
72213
|
}
|
|
71766
72214
|
const watchKit = watch2 ? await Promise.resolve().then(() => (init_run_watch(), run_watch_exports)) : null;
|
|
71767
72215
|
const bus = watchKit ? new watchKit.ReloadBus() : void 0;
|
|
71768
|
-
if (watch2) served = mkdtempSync4(
|
|
72216
|
+
if (watch2) served = mkdtempSync4(join62(tmpdir5(), "himi-run-served-"));
|
|
71769
72217
|
const running = await runPackage2(source, {
|
|
71770
72218
|
port,
|
|
71771
72219
|
chrome: chromeArg,
|
|
@@ -71787,8 +72235,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71787
72235
|
await announce(running);
|
|
71788
72236
|
if (watchKit && bus) {
|
|
71789
72237
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
71790
|
-
const live2 =
|
|
71791
|
-
const manifestOf = (tree) => JSON.parse(
|
|
72238
|
+
const live2 = join62(running.releaseRoot, running.app);
|
|
72239
|
+
const manifestOf = (tree) => JSON.parse(readFileSync76(join62(tree, "release-manifest.json"), "utf8"));
|
|
71792
72240
|
let current = manifestOf(live2);
|
|
71793
72241
|
const failed2 = async (message) => {
|
|
71794
72242
|
if (stopping) return;
|
|
@@ -71799,7 +72247,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71799
72247
|
};
|
|
71800
72248
|
rebuild = watchKit.serialize(async () => {
|
|
71801
72249
|
const t0 = Date.now();
|
|
71802
|
-
const next = mkdtempSync4(
|
|
72250
|
+
const next = mkdtempSync4(join62(tmpdir5(), "himi-run-build-"));
|
|
71803
72251
|
try {
|
|
71804
72252
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
71805
72253
|
if (bres.compileErrors.length) {
|
|
@@ -71816,22 +72264,24 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71816
72264
|
return;
|
|
71817
72265
|
}
|
|
71818
72266
|
if (stopping) return;
|
|
71819
|
-
const fresh = manifestOf(
|
|
72267
|
+
const fresh = manifestOf(join62(next, running.app));
|
|
71820
72268
|
const diff = watchKit.diffReleases(current, fresh);
|
|
72269
|
+
const { describeChanges: describeChanges2, headline: headline2 } = await Promise.resolve().then(() => (init_build_changes(), build_changes_exports));
|
|
72270
|
+
const changes = describeChanges2(live2, join62(next, running.app), diff);
|
|
71821
72271
|
const retired = `${live2}.retired-${Date.now()}`;
|
|
71822
72272
|
renameSync7(live2, retired);
|
|
71823
72273
|
try {
|
|
71824
|
-
renameSync7(
|
|
72274
|
+
renameSync7(join62(next, running.app), live2);
|
|
71825
72275
|
} catch {
|
|
71826
|
-
cpSync3(
|
|
72276
|
+
cpSync3(join62(next, running.app), live2, { recursive: true });
|
|
71827
72277
|
}
|
|
71828
72278
|
rmSync14(retired, { recursive: true, force: true });
|
|
71829
72279
|
current = fresh;
|
|
71830
72280
|
servedMissing = outcome.missingBundles;
|
|
71831
72281
|
for (const [event, data] of watchKit.reloadEvents(diff)) bus.publish(event, data);
|
|
71832
|
-
record2(running, { ok: true, at: (/* @__PURE__ */ new Date()).toISOString(), ms: Date.now() - t0, screens: diff.screens, tokens: diff.tokens, config: diff.config });
|
|
72282
|
+
record2(running, { ok: true, at: (/* @__PURE__ */ new Date()).toISOString(), ms: Date.now() - t0, screens: diff.screens, tokens: diff.tokens, config: diff.config, changes });
|
|
71833
72283
|
await refreshBoard();
|
|
71834
|
-
io.error(JSON.stringify({ watch: "rebuilt", ms: Date.now() - t0, screens: diff.screens, tokens: diff.tokens, config: diff.config, tabs: bus.listeners }));
|
|
72284
|
+
io.error(JSON.stringify({ watch: "rebuilt", ms: Date.now() - t0, screens: diff.screens, tokens: diff.tokens, config: diff.config, ...changes.items.length ? { changed: headline2(changes), changes } : {}, tabs: bus.listeners }));
|
|
71835
72285
|
} catch (e) {
|
|
71836
72286
|
await failed2(e.message.split("\n")[0]);
|
|
71837
72287
|
} finally {
|
|
@@ -72433,7 +72883,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72433
72883
|
io.error(JSON.stringify({ error: `patch ${kind} needs --file`, usage: PATCH_USAGE }));
|
|
72434
72884
|
return 2;
|
|
72435
72885
|
}
|
|
72436
|
-
if (!
|
|
72886
|
+
if (!existsSync64(file)) {
|
|
72437
72887
|
io.error(JSON.stringify({ error: `no such file: ${file}` }));
|
|
72438
72888
|
return 2;
|
|
72439
72889
|
}
|
|
@@ -72489,7 +72939,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72489
72939
|
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."
|
|
72490
72940
|
};
|
|
72491
72941
|
if (kind === "tokens" || kind === "app-config") {
|
|
72492
|
-
const body =
|
|
72942
|
+
const body = readFileSync76(file, "utf8");
|
|
72493
72943
|
const patch2 = kind === "tokens" ? { tokens: body } : { appConfig: body };
|
|
72494
72944
|
return runReleasePatch({
|
|
72495
72945
|
...common,
|
|
@@ -72504,7 +72954,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72504
72954
|
io.error(JSON.stringify({ error: "patch screen needs a <screenId>", usage: PATCH_USAGE }));
|
|
72505
72955
|
return 2;
|
|
72506
72956
|
}
|
|
72507
|
-
const descriptor =
|
|
72957
|
+
const descriptor = readFileSync76(file, "utf8");
|
|
72508
72958
|
try {
|
|
72509
72959
|
JSON.parse(descriptor);
|
|
72510
72960
|
} catch (e) {
|
|
@@ -72544,7 +72994,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72544
72994
|
extra: { kind, screen: id, file: { path: file, bytes: Buffer.byteLength(descriptor, "utf8") } }
|
|
72545
72995
|
});
|
|
72546
72996
|
}
|
|
72547
|
-
const bytes2 =
|
|
72997
|
+
const bytes2 = readFileSync76(file);
|
|
72548
72998
|
const sha = createHash28("sha256").update(bytes2).digest("hex");
|
|
72549
72999
|
const forScreens = (str6(flags["for-screen"]) ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
72550
73000
|
if (flags["no-rebind"] !== void 0 && flags["no-rebind"] !== true) {
|
|
@@ -72688,7 +73138,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72688
73138
|
}
|
|
72689
73139
|
let def;
|
|
72690
73140
|
try {
|
|
72691
|
-
const parsed = JSON.parse(arg.startsWith("@") ?
|
|
73141
|
+
const parsed = JSON.parse(arg.startsWith("@") ? readFileSync76(arg.slice(1), "utf8") : arg);
|
|
72692
73142
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
72693
73143
|
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}`] }));
|
|
72694
73144
|
return 2;
|
|
@@ -73152,7 +73602,7 @@ ${label2}`);
|
|
|
73152
73602
|
const platform = str6(flags.platform)?.split(",").map((p) => p.trim()).filter(Boolean);
|
|
73153
73603
|
{
|
|
73154
73604
|
const distDir = contentDir(flags);
|
|
73155
|
-
if (
|
|
73605
|
+
if (existsSync64(join62(distDir, "himalaya.content.json"))) {
|
|
73156
73606
|
const issues = await iconIssues(distDir, flags.strict === true, { requireDeclared: true, requireVerified: true });
|
|
73157
73607
|
const errors = issues.filter((i) => i.severity === "error");
|
|
73158
73608
|
for (const i of issues.filter((i2) => i2.severity === "warning")) {
|
|
@@ -73421,7 +73871,7 @@ ${label2}`);
|
|
|
73421
73871
|
const dpxPath = dpxSessionTokenPath();
|
|
73422
73872
|
let dpx;
|
|
73423
73873
|
try {
|
|
73424
|
-
dpx =
|
|
73874
|
+
dpx = readFileSync76(dpxPath, "utf8").trim();
|
|
73425
73875
|
} catch {
|
|
73426
73876
|
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` }));
|
|
73427
73877
|
return 1;
|
|
@@ -73829,7 +74279,7 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
|
|
|
73829
74279
|
const path2 = dpxSessionTokenPath();
|
|
73830
74280
|
let raw;
|
|
73831
74281
|
try {
|
|
73832
|
-
raw =
|
|
74282
|
+
raw = readFileSync76(path2, "utf8");
|
|
73833
74283
|
} catch {
|
|
73834
74284
|
io.error(JSON.stringify({ error: `no DPX BO session at ${path2}` }));
|
|
73835
74285
|
return 1;
|