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