@wix/himalaya-cli 0.1036.0 → 0.1038.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/genie-chat/src/index.d.ts +119 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/portfolio/src/index.d.ts +46 -9
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-genie-chat.mjs +51 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-portfolio.mjs +14 -2
- package/dist/cli.mjs +1323 -492
- package/dist/preview-assets.generated.bin +0 -0
- package/fixtures/wix-canned.json +51 -2
- package/guides/headless-loop.md +7 -0
- package/guides/himi-test.md +66 -1
- package/guides/sdk-reference.json +90 -12
- package/guides/trim-a-template.md +5 -0
- package/guides/wix-business-context.md +13 -1
- package/guides/wix-site-to-himi-app.md +10 -1
- package/package.json +2 -2
- package/templates/beauty-salon/tier5-src/himi-booking-bookings/index.ts +14 -8
- package/templates/beauty-salon/tier5-src/himi-branded-lite-home/index.ts +12 -1
- package/templates/beauty-salon-owner/dev/index.ts +2148 -1262
- package/templates/beauty-salon-owner/tier5-src/_shared/aria-chat.ts +338 -26
- package/templates/beauty-salon-owner/tier5-src/_shared/aria-mentions.ts +202 -0
- package/templates/beauty-salon-owner/tier5-src/_shared/owner-module-data.ts +2 -2
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-appointments/index.ts +4 -1
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-aria/index.ts +29 -0
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-ask/index.ts +6 -0
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-manage/index.ts +64 -6
- package/templates/branded-lite/tier5-src/himi-booking-bookings/index.ts +14 -8
- package/templates/branded-lite/tier5-src/himi-branded-lite-home/index.ts +12 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-portfolio/index.ts +2 -2
- package/templates/branded-lite/tier5-src/himi-branded-lite-portfolio-project/index.ts +3 -3
- package/templates/community-club/tier5-src/himi-branded-lite-home/index.ts +12 -1
- package/templates/community-club-owner/dev/index.ts +2151 -1265
- package/templates/community-club-owner/tier5-src/_shared/aria-chat.ts +338 -26
- package/templates/community-club-owner/tier5-src/_shared/aria-mentions.ts +202 -0
- package/templates/community-club-owner/tier5-src/_shared/owner-module-data.ts +2 -2
- package/templates/community-club-owner/tier5-src/himi-owner-lite-aria/index.ts +29 -0
- package/templates/community-club-owner/tier5-src/himi-owner-lite-ask/index.ts +6 -0
- package/templates/community-club-owner/tier5-src/himi-owner-lite-manage/index.ts +64 -6
- package/templates/events-meetups/tier5-src/himi-branded-lite-home/index.ts +12 -1
- package/templates/events-meetups-owner/dev/index.ts +2151 -1265
- package/templates/events-meetups-owner/tier5-src/_shared/aria-chat.ts +338 -26
- package/templates/events-meetups-owner/tier5-src/_shared/aria-mentions.ts +202 -0
- package/templates/events-meetups-owner/tier5-src/_shared/owner-module-data.ts +2 -2
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-aria/index.ts +29 -0
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-ask/index.ts +6 -0
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-manage/index.ts +64 -6
- package/templates/gym-fitness/tier5-src/himi-booking-bookings/index.ts +14 -8
- package/templates/gym-fitness/tier5-src/himi-branded-lite-home/index.ts +12 -1
- package/templates/gym-fitness-owner/dev/index.ts +2148 -1262
- package/templates/gym-fitness-owner/tier5-src/_shared/aria-chat.ts +338 -26
- package/templates/gym-fitness-owner/tier5-src/_shared/aria-mentions.ts +202 -0
- package/templates/gym-fitness-owner/tier5-src/_shared/owner-module-data.ts +2 -2
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-appointments/index.ts +4 -1
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-aria/index.ts +29 -0
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-ask/index.ts +6 -0
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-manage/index.ts +64 -6
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-home/index.ts +12 -1
- package/templates/nonprofit-cause-owner/dev/index.ts +2148 -1262
- package/templates/nonprofit-cause-owner/tier5-src/_shared/aria-chat.ts +338 -26
- package/templates/nonprofit-cause-owner/tier5-src/_shared/aria-mentions.ts +202 -0
- package/templates/nonprofit-cause-owner/tier5-src/_shared/owner-module-data.ts +2 -2
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-appointments/index.ts +4 -1
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-aria/index.ts +29 -0
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-ask/index.ts +6 -0
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-manage/index.ts +64 -6
- package/templates/owner-lite/dev/index.ts +2145 -1259
- package/templates/owner-lite/tier5-src/_shared/aria-chat.ts +338 -26
- package/templates/owner-lite/tier5-src/_shared/aria-mentions.ts +202 -0
- package/templates/owner-lite/tier5-src/_shared/owner-module-data.ts +2 -2
- package/templates/owner-lite/tier5-src/himi-owner-lite-appointments/index.ts +4 -1
- package/templates/owner-lite/tier5-src/himi-owner-lite-aria/index.ts +29 -0
- package/templates/owner-lite/tier5-src/himi-owner-lite-ask/index.ts +6 -0
- package/templates/owner-lite/tier5-src/himi-owner-lite-manage/index.ts +64 -6
- package/templates/podcast-creator/tier5-src/himi-branded-lite-home/index.ts +12 -1
- package/templates/podcast-creator-owner/dev/index.ts +2151 -1265
- package/templates/podcast-creator-owner/tier5-src/_shared/aria-chat.ts +338 -26
- package/templates/podcast-creator-owner/tier5-src/_shared/aria-mentions.ts +202 -0
- package/templates/podcast-creator-owner/tier5-src/_shared/owner-module-data.ts +2 -2
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-aria/index.ts +29 -0
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-ask/index.ts +6 -0
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-manage/index.ts +64 -6
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-home/index.ts +12 -1
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-portfolio/index.ts +2 -2
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-portfolio-project/index.ts +3 -3
- package/templates/portfolio-creative-owner/dev/index.ts +2148 -1262
- package/templates/portfolio-creative-owner/tier5-src/_shared/aria-chat.ts +338 -26
- package/templates/portfolio-creative-owner/tier5-src/_shared/aria-mentions.ts +202 -0
- package/templates/portfolio-creative-owner/tier5-src/_shared/owner-module-data.ts +2 -2
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-appointments/index.ts +4 -1
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-aria/index.ts +29 -0
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-ask/index.ts +6 -0
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-manage/index.ts +64 -6
- package/templates/restaurant/tier5-src/himi-branded-lite-home/index.ts +12 -1
- package/templates/restaurant-owner/dev/index.ts +2148 -1262
- package/templates/restaurant-owner/tier5-src/_shared/aria-chat.ts +338 -26
- package/templates/restaurant-owner/tier5-src/_shared/aria-mentions.ts +202 -0
- package/templates/restaurant-owner/tier5-src/_shared/owner-module-data.ts +2 -2
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-appointments/index.ts +4 -1
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-aria/index.ts +29 -0
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-ask/index.ts +6 -0
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-manage/index.ts +64 -6
- package/templates/retail-store/tier5-src/himi-branded-lite-home/index.ts +12 -1
- package/templates/retail-store-owner/dev/index.ts +2151 -1265
- package/templates/retail-store-owner/tier5-src/_shared/aria-chat.ts +338 -26
- package/templates/retail-store-owner/tier5-src/_shared/aria-mentions.ts +202 -0
- package/templates/retail-store-owner/tier5-src/_shared/owner-module-data.ts +2 -2
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-aria/index.ts +29 -0
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-ask/index.ts +6 -0
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-manage/index.ts +64 -6
- package/templates/yoga-studio/tier5-src/himi-booking-bookings/index.ts +14 -8
- package/templates/yoga-studio/tier5-src/himi-branded-lite-home/index.ts +12 -1
- package/templates/yoga-studio-owner/dev/index.ts +2148 -1262
- package/templates/yoga-studio-owner/tier5-src/_shared/aria-chat.ts +338 -26
- package/templates/yoga-studio-owner/tier5-src/_shared/aria-mentions.ts +202 -0
- package/templates/yoga-studio-owner/tier5-src/_shared/owner-module-data.ts +2 -2
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-appointments/index.ts +4 -1
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-aria/index.ts +29 -0
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-ask/index.ts +6 -0
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-manage/index.ts +64 -6
package/dist/cli.mjs
CHANGED
|
@@ -1123,6 +1123,14 @@ var init_mobile_ux_contract = __esm({
|
|
|
1123
1123
|
| Screen | Job | Primary action | Data | Notes |
|
|
1124
1124
|
| --- | --- | --- | --- | --- |
|
|
1125
1125
|
|
|
1126
|
+
## Data access
|
|
1127
|
+
<!-- \`himi test\` checks every write to Wix it sees against this table. One row per screen id (and
|
|
1128
|
+
role); \`Wix writes\` is \`none\`, or the approved writes named by action (\`bookSelected\`),
|
|
1129
|
+
endpoint (\`POST /bookings/v2/bookings\`), capability (\`registerDirect\`) or kind (\`payment\`).
|
|
1130
|
+
\`himi docs himi-test\` -> "Writes to Wix". -->
|
|
1131
|
+
| Screen | Role | Reads | Wix writes | Prohibited |
|
|
1132
|
+
| --- | --- | --- | --- | --- |
|
|
1133
|
+
|
|
1126
1134
|
## Platform envelope
|
|
1127
1135
|
- Required: iOS, Android
|
|
1128
1136
|
- Optional: web, desktop, watch, widgets
|
|
@@ -1528,7 +1536,9 @@ export default defineService("home", {
|
|
|
1528
1536
|
surfaceTertiary: { light: "#eef1f4", dark: "#1c2128" },
|
|
1529
1537
|
textPrimary: { light: "#1f2328", dark: "#e6edf3" },
|
|
1530
1538
|
textSecondary: { light: "#57606a", dark: "#9198a1" },
|
|
1531
|
-
|
|
1539
|
+
// Dark ink on the dark arm: white on #388bfd is 3.34:1 and fails AA, which the tokens
|
|
1540
|
+
// pass now warns about (#3275); #0d1117 on it is 5.66:1.
|
|
1541
|
+
textOnAccent: { light: "#ffffff", dark: "#0d1117" },
|
|
1532
1542
|
accentPrimary: { light: "#0969da", dark: "#388bfd" },
|
|
1533
1543
|
border: { light: "#d0d7de", dark: "#30363d" },
|
|
1534
1544
|
danger: { light: "#cf222e", dark: "#f85149" },
|
|
@@ -3056,14 +3066,14 @@ function confinementMatcher(contentRoot, extraRoots = []) {
|
|
|
3056
3066
|
linked = [];
|
|
3057
3067
|
const scanned = /* @__PURE__ */ new Set();
|
|
3058
3068
|
const queue = [...roots];
|
|
3059
|
-
const
|
|
3069
|
+
const CAP5 = 4096;
|
|
3060
3070
|
const take = (abs) => {
|
|
3061
3071
|
const target = realpathOrSelf(abs);
|
|
3062
|
-
if (scanned.has(target) || linked.length >=
|
|
3072
|
+
if (scanned.has(target) || linked.length >= CAP5) return;
|
|
3063
3073
|
linked.push(target);
|
|
3064
3074
|
queue.push(target);
|
|
3065
3075
|
};
|
|
3066
|
-
while (queue.length && linked.length <
|
|
3076
|
+
while (queue.length && linked.length < CAP5) {
|
|
3067
3077
|
const r = queue.shift();
|
|
3068
3078
|
for (const nm of [r, join12(r, "node_modules")]) {
|
|
3069
3079
|
if (scanned.has(nm)) continue;
|
|
@@ -8206,8 +8216,8 @@ function findSkipDerive(bundleJs) {
|
|
|
8206
8216
|
if (touchedBase.length === 0) continue;
|
|
8207
8217
|
const missingDerived = [...outputUnion].filter((o) => !keySet.has(o));
|
|
8208
8218
|
if (missingDerived.length === 0) continue;
|
|
8209
|
-
const
|
|
8210
|
-
findings.push({ touchedBase, missingDerived, snippet: `{ ${
|
|
8219
|
+
const snippet3 = objBody.replace(/\s+/g, " ").trim();
|
|
8220
|
+
findings.push({ touchedBase, missingDerived, snippet: `{ ${snippet3.slice(0, 70)}${snippet3.length > 70 ? " \u2026" : ""} }` });
|
|
8211
8221
|
}
|
|
8212
8222
|
return findings;
|
|
8213
8223
|
} catch {
|
|
@@ -8812,8 +8822,8 @@ function validateScreenDescriptor(screenId, descriptor, opts = {}) {
|
|
|
8812
8822
|
if (a11yMode !== "off") {
|
|
8813
8823
|
const severity = a11yMode === "warn" && !strict ? "warning" : "error";
|
|
8814
8824
|
const gaps = accessibleNameGaps(descriptor);
|
|
8815
|
-
const
|
|
8816
|
-
for (const gap of gaps.slice(0,
|
|
8825
|
+
const CAP5 = 20;
|
|
8826
|
+
for (const gap of gaps.slice(0, CAP5)) {
|
|
8817
8827
|
const row = Object.prototype.hasOwnProperty.call(A11Y_CONTRACT, gap.type) ? A11Y_CONTRACT[gap.type] : void 0;
|
|
8818
8828
|
const why = gap.reason === "interactive" ? `it carries an \`onTap\`/\`onLongPress\`/\`onDoubleTap\`, which promotes ANY node to a control that owes a name (RFC 0058 \xA73.4)` : `RFC 0058 \xA73.3 requires a name for \`${gap.type}\` (announced as \`${gap.role}\`)`;
|
|
8819
8829
|
const fix = gap.reason === "contract" ? `Give it \`modifiers.accessibilityLabel\`, or copy on a descendant \u2014 or, if it really is presentational, say so with \`modifiers.accessibilityRole: "decorative"\` (node-local) or \`modifiers.accessibilityHidden: true\` (whole subtree).` : `Give it \`modifiers.accessibilityLabel\`, or put readable copy on a descendant. An icon-only control names itself with \`Icon.contentDescription\`. \`decorative\` does not silence a control${row?.decorative ? ` \u2014 a tappable \`${gap.type}\` is one` : ""}.`;
|
|
@@ -8824,11 +8834,11 @@ function validateScreenDescriptor(screenId, descriptor, opts = {}) {
|
|
|
8824
8834
|
message: `${gap.type} renders no accessible name anywhere in its subtree, and ${why}. A screen reader announces this node as an unnamed \`${gap.role}\`. ${fix}`
|
|
8825
8835
|
});
|
|
8826
8836
|
}
|
|
8827
|
-
if (gaps.length >
|
|
8837
|
+
if (gaps.length > CAP5) {
|
|
8828
8838
|
issues.push({
|
|
8829
8839
|
severity,
|
|
8830
8840
|
pass: "a11y",
|
|
8831
|
-
message: `+${gaps.length -
|
|
8841
|
+
message: `+${gaps.length - CAP5} more node(s) on this screen render no accessible name (${gaps.length} in total). Fix the ${CAP5} above and re-run to see the rest.`
|
|
8832
8842
|
});
|
|
8833
8843
|
}
|
|
8834
8844
|
}
|
|
@@ -11088,6 +11098,74 @@ var init_token_colors = __esm({
|
|
|
11088
11098
|
}
|
|
11089
11099
|
});
|
|
11090
11100
|
|
|
11101
|
+
// ../../core/ts/src/idiom.ts
|
|
11102
|
+
function authored(overlays, name) {
|
|
11103
|
+
return typeof name === "string" && overlays !== void 0 && Object.hasOwn(overlays, name) && overlays[name] !== null && typeof overlays[name] === "object" && !Array.isArray(overlays[name]);
|
|
11104
|
+
}
|
|
11105
|
+
function selectIdiomOverlay(doc, ctx = {}) {
|
|
11106
|
+
const policy = doc.idiomPolicy;
|
|
11107
|
+
const overlays = doc.idiom;
|
|
11108
|
+
const isRecord3 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
11109
|
+
if (!isRecord3(policy) || !isRecord3(overlays)) return void 0;
|
|
11110
|
+
const kind = policy.policy ?? "follow-surface";
|
|
11111
|
+
if (kind === "none") return void 0;
|
|
11112
|
+
if (kind === "pinned") return authored(overlays, policy.pin) ? policy.pin : void 0;
|
|
11113
|
+
if (kind !== "follow-surface") return void 0;
|
|
11114
|
+
const surfaces = policy.surfaces;
|
|
11115
|
+
const candidates = [
|
|
11116
|
+
ctx.surface !== void 0 && isRecord3(surfaces) && Object.hasOwn(surfaces, ctx.surface) ? surfaces[ctx.surface] : void 0,
|
|
11117
|
+
...ctx.native ?? [],
|
|
11118
|
+
policy.fallback
|
|
11119
|
+
];
|
|
11120
|
+
return candidates.find((c) => authored(overlays, c));
|
|
11121
|
+
}
|
|
11122
|
+
function isPlainObject(v) {
|
|
11123
|
+
return v !== null && typeof v === "object" && !Array.isArray(v);
|
|
11124
|
+
}
|
|
11125
|
+
function deepMerge(base, overlay) {
|
|
11126
|
+
if (!isPlainObject(overlay) || !isPlainObject(base)) return overlay;
|
|
11127
|
+
const out = { ...base };
|
|
11128
|
+
for (const [key2, value] of Object.entries(overlay)) {
|
|
11129
|
+
if (UNSAFE_KEYS.has(key2)) continue;
|
|
11130
|
+
out[key2] = Object.hasOwn(base, key2) ? deepMerge(base[key2], value) : value;
|
|
11131
|
+
}
|
|
11132
|
+
return out;
|
|
11133
|
+
}
|
|
11134
|
+
function mergeIdiomOverlay(base, overlay) {
|
|
11135
|
+
const merged = deepMerge(base, overlay);
|
|
11136
|
+
const baseColors = base.colors;
|
|
11137
|
+
const overlayColors = overlay.colors;
|
|
11138
|
+
if (isPlainObject(baseColors) && isPlainObject(overlayColors)) {
|
|
11139
|
+
const colors = { ...merged.colors };
|
|
11140
|
+
for (const [name, value] of Object.entries(overlayColors)) {
|
|
11141
|
+
if (UNSAFE_KEYS.has(name)) continue;
|
|
11142
|
+
const was = Object.hasOwn(baseColors, name) ? baseColors[name] : void 0;
|
|
11143
|
+
if (typeof was === "string" && isPlainObject(value)) colors[name] = { light: was, ...value };
|
|
11144
|
+
}
|
|
11145
|
+
merged.colors = colors;
|
|
11146
|
+
}
|
|
11147
|
+
return merged;
|
|
11148
|
+
}
|
|
11149
|
+
function resolveIdiom(tokens, ctx = {}) {
|
|
11150
|
+
const doc = tokens;
|
|
11151
|
+
const name = selectIdiomOverlay(doc, ctx);
|
|
11152
|
+
if (name === void 0) return tokens;
|
|
11153
|
+
const merged = mergeIdiomOverlay(tokens, doc.idiom[name]);
|
|
11154
|
+
const { idiomPolicy: _applied, ...final } = merged;
|
|
11155
|
+
return final;
|
|
11156
|
+
}
|
|
11157
|
+
var IDIOM_CONTEXTS, UNSAFE_KEYS;
|
|
11158
|
+
var init_idiom = __esm({
|
|
11159
|
+
"../../core/ts/src/idiom.ts"() {
|
|
11160
|
+
IDIOM_CONTEXTS = {
|
|
11161
|
+
ios: { native: ["ios"] },
|
|
11162
|
+
android: { native: ["material"] },
|
|
11163
|
+
mac: { native: ["desktop", "ios"], surface: "mac" }
|
|
11164
|
+
};
|
|
11165
|
+
UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
11166
|
+
}
|
|
11167
|
+
});
|
|
11168
|
+
|
|
11091
11169
|
// src/token-lint.ts
|
|
11092
11170
|
import { existsSync as existsSync13, readFileSync as readFileSync14 } from "node:fs";
|
|
11093
11171
|
import { join as join16 } from "node:path";
|
|
@@ -11178,11 +11256,109 @@ function tokenColorIssues(dir, tokensPathOverride) {
|
|
|
11178
11256
|
`${tokensPath}: colors.${problem.path} is ${problem.value} \u2014 the native runtimes parse only #RRGGBB or #RRGGBBAA` + (problem.suggestion ? `. Write ${problem.suggestion}.` : `, and this value names no colour that can be converted for you. Write the hex it should be.`)
|
|
11179
11257
|
);
|
|
11180
11258
|
}
|
|
11259
|
+
const base = contrastFindings(colors);
|
|
11260
|
+
for (const f of base) warn(`${tokensPath}: ${f.render(f.schemes)}`);
|
|
11261
|
+
if (idiom !== null && typeof idiom === "object" && !Array.isArray(idiom)) {
|
|
11262
|
+
const seen = new Set(base.flatMap((f) => f.schemes.map((s) => `${f.key}|${s}`)));
|
|
11263
|
+
for (const [overlay, layer] of Object.entries(idiom)) {
|
|
11264
|
+
const layerColors = layer?.colors;
|
|
11265
|
+
if (layerColors === null || typeof layerColors !== "object" || Array.isArray(layerColors)) continue;
|
|
11266
|
+
const merged = mergeIdiomOverlay({ colors }, { colors: layerColors }).colors;
|
|
11267
|
+
for (const f of contrastFindings(merged)) {
|
|
11268
|
+
const added = f.schemes.filter((s) => !seen.has(`${f.key}|${s}`));
|
|
11269
|
+
if (added.length) warn(`${tokensPath}: under the idiom.${overlay} overlay, ${f.render(added)}`);
|
|
11270
|
+
}
|
|
11271
|
+
}
|
|
11272
|
+
}
|
|
11181
11273
|
return issues;
|
|
11182
11274
|
}
|
|
11275
|
+
function schemeValue(token, scheme) {
|
|
11276
|
+
let v = token;
|
|
11277
|
+
if (token !== null && typeof token === "object" && !Array.isArray(token)) {
|
|
11278
|
+
const o = token;
|
|
11279
|
+
v = scheme === "highContrast" ? o.highContrast ?? o.dark ?? o.light : scheme === "dark" ? o.dark ?? o.light : o.light;
|
|
11280
|
+
}
|
|
11281
|
+
return typeof v === "string" && isCanonicalHex(v) ? v.trim().toUpperCase() : void 0;
|
|
11282
|
+
}
|
|
11283
|
+
function paintedOver(fg, bg) {
|
|
11284
|
+
if (bg.length === 9 && bg.slice(7) !== "FF") return void 0;
|
|
11285
|
+
if (fg.length === 9) return mixHex(fg.slice(0, 7), bg.slice(0, 7), parseInt(fg.slice(7), 16) / 255);
|
|
11286
|
+
return fg;
|
|
11287
|
+
}
|
|
11288
|
+
function sameHueForContrast(fg, bg, target = AA_TEXT) {
|
|
11289
|
+
const base = fg.slice(0, 7);
|
|
11290
|
+
const opaqueBg = bg.slice(0, 7);
|
|
11291
|
+
const pole = contrastRatio("#000000", opaqueBg) >= contrastRatio("#FFFFFF", opaqueBg) ? "#000000" : "#FFFFFF";
|
|
11292
|
+
for (let step = 0; step <= 100; step++) {
|
|
11293
|
+
const candidate = mixHex(base, pole, 1 - step / 100);
|
|
11294
|
+
if (contrastRatio(candidate, opaqueBg) >= target) return candidate;
|
|
11295
|
+
}
|
|
11296
|
+
return void 0;
|
|
11297
|
+
}
|
|
11298
|
+
function contrastFindings(colors) {
|
|
11299
|
+
const declared = /* @__PURE__ */ new Set(["light"]);
|
|
11300
|
+
for (const v of Object.values(colors)) {
|
|
11301
|
+
if (v === null || typeof v !== "object" || Array.isArray(v)) continue;
|
|
11302
|
+
for (const s of SCHEMES) if (s in v) declared.add(s);
|
|
11303
|
+
}
|
|
11304
|
+
const findings = /* @__PURE__ */ new Map();
|
|
11305
|
+
for (const pair of CONTRAST_PAIRS) {
|
|
11306
|
+
const fgName = pair.fg;
|
|
11307
|
+
if (colors[fgName] === void 0 || colors[pair.bg] === void 0) continue;
|
|
11308
|
+
for (const scheme of SCHEMES) {
|
|
11309
|
+
if (!declared.has(scheme)) continue;
|
|
11310
|
+
const fg = schemeValue(colors[fgName], scheme);
|
|
11311
|
+
const bg = schemeValue(colors[pair.bg], scheme);
|
|
11312
|
+
if (!fg || !bg) continue;
|
|
11313
|
+
const painted = paintedOver(fg, bg);
|
|
11314
|
+
if (!painted) continue;
|
|
11315
|
+
const opaqueBg = bg.slice(0, 7);
|
|
11316
|
+
const ratio = contrastRatio(painted, opaqueBg);
|
|
11317
|
+
if (ratio >= AA_TEXT) continue;
|
|
11318
|
+
const key2 = `${fgName}|${pair.bg}|${fg}|${bg}`;
|
|
11319
|
+
const same2 = findings.get(key2);
|
|
11320
|
+
if (same2) {
|
|
11321
|
+
same2.schemes.push(scheme);
|
|
11322
|
+
continue;
|
|
11323
|
+
}
|
|
11324
|
+
const darker = contrastRatio("#000000", opaqueBg) >= contrastRatio("#FFFFFF", opaqueBg);
|
|
11325
|
+
const ink = darker ? "#000000" : "#FFFFFF";
|
|
11326
|
+
const suggestion = pair.suggest === "same-hue" ? sameHueForContrast(painted, opaqueBg) : pair.suggest === "ink" && contrastRatio(ink, opaqueBg) >= AA_TEXT ? ink : void 0;
|
|
11327
|
+
const fix = !suggestion ? ` Pick a ${fgName} that clears ${AA_TEXT}:1 against ${pair.bg}.` : pair.suggest === "same-hue" ? ` A ${darker ? "darker" : "lighter"} ${fgName} of the same hue that clears it is ${suggestion} (${contrastRatio(suggestion, opaqueBg).toFixed(2)}:1).` : ` ${suggestion} clears it (${contrastRatio(suggestion, opaqueBg).toFixed(2)}:1).`;
|
|
11328
|
+
findings.set(key2, {
|
|
11329
|
+
key: key2,
|
|
11330
|
+
schemes: [scheme],
|
|
11331
|
+
render: (schemes) => `colors.${fgName} (${fg}) on colors.${pair.bg} (${bg}) is ${ratio.toFixed(2)}:1 in ${schemes.join(" / ")} \u2014 below the WCAG AA ${AA_TEXT}:1 for text. ${fgName} is ${pair.use}, so that text is hard to read.${fix}`
|
|
11332
|
+
});
|
|
11333
|
+
}
|
|
11334
|
+
}
|
|
11335
|
+
return [...findings.values()];
|
|
11336
|
+
}
|
|
11337
|
+
var AA_TEXT, CONTRAST_PAIRS, SCHEMES, channels, toHex, mixHex;
|
|
11183
11338
|
var init_token_lint = __esm({
|
|
11184
11339
|
"src/token-lint.ts"() {
|
|
11185
11340
|
init_token_colors();
|
|
11341
|
+
init_idiom();
|
|
11342
|
+
AA_TEXT = 4.5;
|
|
11343
|
+
CONTRAST_PAIRS = [
|
|
11344
|
+
{
|
|
11345
|
+
fg: "accentPrimary",
|
|
11346
|
+
bg: "surfacePrimary",
|
|
11347
|
+
use: "the text colour of secondary, plain and link buttons, selected tab labels and inline action text",
|
|
11348
|
+
suggest: "same-hue"
|
|
11349
|
+
},
|
|
11350
|
+
{ fg: "accentText", bg: "surfacePrimary", use: "the dedicated colour for accent-coloured text", suggest: "same-hue" },
|
|
11351
|
+
{ fg: "textOnAccent", bg: "accentPrimary", use: "the label on filled (primary) buttons and selected chips", suggest: "ink" },
|
|
11352
|
+
{ fg: "textPrimary", bg: "surfacePrimary", use: "body and title text" },
|
|
11353
|
+
{ fg: "textSecondary", bg: "surfacePrimary", use: "secondary text (subtitles, captions, metadata)" }
|
|
11354
|
+
];
|
|
11355
|
+
SCHEMES = ["light", "dark", "highContrast"];
|
|
11356
|
+
channels = (hex2) => [1, 3, 5].map((i) => parseInt(hex2.slice(i, i + 2), 16));
|
|
11357
|
+
toHex = (rgb) => `#${rgb.map((c) => Math.round(Math.min(255, Math.max(0, c))).toString(16).padStart(2, "0")).join("")}`.toUpperCase();
|
|
11358
|
+
mixHex = (a, b, w) => {
|
|
11359
|
+
const [ca, cb] = [channels(a), channels(b)];
|
|
11360
|
+
return toHex(ca.map((c, i) => c * w + cb[i] * (1 - w)));
|
|
11361
|
+
};
|
|
11186
11362
|
}
|
|
11187
11363
|
});
|
|
11188
11364
|
|
|
@@ -11841,8 +12017,8 @@ async function sharpOrThrow() {
|
|
|
11841
12017
|
async function inspectIconPixels(png) {
|
|
11842
12018
|
const sharp = await sharpOrThrow();
|
|
11843
12019
|
const { data, info } = await sharp(png).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
11844
|
-
const { width, height, channels:
|
|
11845
|
-
if (
|
|
12020
|
+
const { width, height, channels: channels3 } = info;
|
|
12021
|
+
if (channels3 !== 4) throw new Error(`app-icons: expected RGBA after ensureAlpha, got ${channels3} channels`);
|
|
11846
12022
|
let minAlpha = 255;
|
|
11847
12023
|
let transparent = 0;
|
|
11848
12024
|
for (let i = 3; i < data.length; i += 4) {
|
|
@@ -12691,75 +12867,6 @@ var init_face_source = __esm({
|
|
|
12691
12867
|
}
|
|
12692
12868
|
});
|
|
12693
12869
|
|
|
12694
|
-
// ../../core/ts/src/idiom.ts
|
|
12695
|
-
function authored(overlays, name) {
|
|
12696
|
-
return typeof name === "string" && overlays !== void 0 && Object.hasOwn(overlays, name) && overlays[name] !== null && typeof overlays[name] === "object" && !Array.isArray(overlays[name]);
|
|
12697
|
-
}
|
|
12698
|
-
function selectIdiomOverlay(doc, ctx = {}) {
|
|
12699
|
-
const policy = doc.idiomPolicy;
|
|
12700
|
-
const overlays = doc.idiom;
|
|
12701
|
-
const isRecord3 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
12702
|
-
if (!isRecord3(policy) || !isRecord3(overlays)) return void 0;
|
|
12703
|
-
const kind = policy.policy ?? "follow-surface";
|
|
12704
|
-
if (kind === "none") return void 0;
|
|
12705
|
-
if (kind === "pinned") return authored(overlays, policy.pin) ? policy.pin : void 0;
|
|
12706
|
-
if (kind !== "follow-surface") return void 0;
|
|
12707
|
-
const surfaces = policy.surfaces;
|
|
12708
|
-
const candidates = [
|
|
12709
|
-
ctx.surface !== void 0 && isRecord3(surfaces) && Object.hasOwn(surfaces, ctx.surface) ? surfaces[ctx.surface] : void 0,
|
|
12710
|
-
...ctx.native ?? [],
|
|
12711
|
-
policy.fallback
|
|
12712
|
-
];
|
|
12713
|
-
return candidates.find((c) => authored(overlays, c));
|
|
12714
|
-
}
|
|
12715
|
-
function isPlainObject(v) {
|
|
12716
|
-
return v !== null && typeof v === "object" && !Array.isArray(v);
|
|
12717
|
-
}
|
|
12718
|
-
function deepMerge(base, overlay) {
|
|
12719
|
-
if (!isPlainObject(overlay) || !isPlainObject(base)) return overlay;
|
|
12720
|
-
const out = { ...base };
|
|
12721
|
-
for (const [key2, value] of Object.entries(overlay)) {
|
|
12722
|
-
if (UNSAFE_KEYS.has(key2)) continue;
|
|
12723
|
-
out[key2] = Object.hasOwn(base, key2) ? deepMerge(base[key2], value) : value;
|
|
12724
|
-
}
|
|
12725
|
-
return out;
|
|
12726
|
-
}
|
|
12727
|
-
function mergeIdiomOverlay(base, overlay) {
|
|
12728
|
-
const merged = deepMerge(base, overlay);
|
|
12729
|
-
const baseColors = base.colors;
|
|
12730
|
-
const overlayColors = overlay.colors;
|
|
12731
|
-
if (isPlainObject(baseColors) && isPlainObject(overlayColors)) {
|
|
12732
|
-
const colors = { ...merged.colors };
|
|
12733
|
-
for (const [name, value] of Object.entries(overlayColors)) {
|
|
12734
|
-
if (UNSAFE_KEYS.has(name)) continue;
|
|
12735
|
-
const was = Object.hasOwn(baseColors, name) ? baseColors[name] : void 0;
|
|
12736
|
-
if (typeof was === "string" && isPlainObject(value)) colors[name] = { light: was, ...value };
|
|
12737
|
-
}
|
|
12738
|
-
merged.colors = colors;
|
|
12739
|
-
}
|
|
12740
|
-
return merged;
|
|
12741
|
-
}
|
|
12742
|
-
function resolveIdiom(tokens, ctx = {}) {
|
|
12743
|
-
const doc = tokens;
|
|
12744
|
-
const name = selectIdiomOverlay(doc, ctx);
|
|
12745
|
-
if (name === void 0) return tokens;
|
|
12746
|
-
const merged = mergeIdiomOverlay(tokens, doc.idiom[name]);
|
|
12747
|
-
const { idiomPolicy: _applied, ...final } = merged;
|
|
12748
|
-
return final;
|
|
12749
|
-
}
|
|
12750
|
-
var IDIOM_CONTEXTS, UNSAFE_KEYS;
|
|
12751
|
-
var init_idiom = __esm({
|
|
12752
|
-
"../../core/ts/src/idiom.ts"() {
|
|
12753
|
-
"use strict";
|
|
12754
|
-
IDIOM_CONTEXTS = {
|
|
12755
|
-
ios: { native: ["ios"] },
|
|
12756
|
-
android: { native: ["material"] },
|
|
12757
|
-
mac: { native: ["desktop", "ios"], surface: "mac" }
|
|
12758
|
-
};
|
|
12759
|
-
UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
12760
|
-
}
|
|
12761
|
-
});
|
|
12762
|
-
|
|
12763
12870
|
// ../../core/web-renderer/src/idiom-controls.ts
|
|
12764
12871
|
function pickRole(colors, role) {
|
|
12765
12872
|
if (typeof role === "string") return role;
|
|
@@ -13417,12 +13524,12 @@ async function checkReport(appDir2, opts = {}) {
|
|
|
13417
13524
|
function resolveFamilyName(input) {
|
|
13418
13525
|
const catalog = loadCatalog();
|
|
13419
13526
|
if (renderableFamilies(catalog).has(input)) return input;
|
|
13420
|
-
const
|
|
13527
|
+
const norm3 = input.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
13421
13528
|
for (const name of renderableFamilies(catalog)) {
|
|
13422
|
-
if (name.toLowerCase().replace(/[^a-z0-9]/g, "") ===
|
|
13529
|
+
if (name.toLowerCase().replace(/[^a-z0-9]/g, "") === norm3) return name;
|
|
13423
13530
|
}
|
|
13424
13531
|
for (const [name, fam] of [...Object.entries(catalog.families), ...Object.entries(catalog.bundled)]) {
|
|
13425
|
-
if ((fam.aliases ?? []).some((a) => a.toLowerCase().replace(/[^a-z0-9]/g, "") ===
|
|
13532
|
+
if ((fam.aliases ?? []).some((a) => a.toLowerCase().replace(/[^a-z0-9]/g, "") === norm3)) return name;
|
|
13426
13533
|
}
|
|
13427
13534
|
return void 0;
|
|
13428
13535
|
}
|
|
@@ -26851,7 +26958,7 @@ var init_renderNode = __esm({
|
|
|
26851
26958
|
const hostRef = React5.useRef(null);
|
|
26852
26959
|
const autoplayConsumed = React5.useRef(false);
|
|
26853
26960
|
const item = resolvedItems[index];
|
|
26854
|
-
const
|
|
26961
|
+
const mediaKey2 = `${index}:${item?.id ?? item?.url ?? ""}`;
|
|
26855
26962
|
React5.useEffect(() => {
|
|
26856
26963
|
const outgoing = mediaRef.current;
|
|
26857
26964
|
return () => {
|
|
@@ -26860,7 +26967,7 @@ var init_renderNode = __esm({
|
|
|
26860
26967
|
} catch {
|
|
26861
26968
|
}
|
|
26862
26969
|
};
|
|
26863
|
-
}, [
|
|
26970
|
+
}, [mediaKey2]);
|
|
26864
26971
|
const sessionId = String(props.sessionId || nodeId || "media");
|
|
26865
26972
|
const provider = String(item?.provider || "direct").toLowerCase();
|
|
26866
26973
|
const isYouTube = provider === "youtube";
|
|
@@ -27217,7 +27324,7 @@ var init_renderNode = __esm({
|
|
|
27217
27324
|
provider,
|
|
27218
27325
|
"."
|
|
27219
27326
|
] })
|
|
27220
|
-
] }) : isYouTube ? /* @__PURE__ */ jsx6("iframe", { title: String(item?.title ?? "YouTube video"), src: `https://www.youtube-nocookie.com/embed/${encodeURIComponent(youtubeId(item))}?playsinline=1&autoplay=${props.autoplay === "never" ? 0 : 1}&mute=${props.muted === true ? 1 : 0}&controls=${chrome === "none" ? 0 : 1}`, allow: "autoplay; encrypted-media; picture-in-picture; fullscreen", allowFullScreen: true, style: { border: 0, width: "100%", flex: 1, minHeight: 0 } },
|
|
27327
|
+
] }) : isYouTube ? /* @__PURE__ */ jsx6("iframe", { title: String(item?.title ?? "YouTube video"), src: `https://www.youtube-nocookie.com/embed/${encodeURIComponent(youtubeId(item))}?playsinline=1&autoplay=${props.autoplay === "never" ? 0 : 1}&mute=${props.muted === true ? 1 : 0}&controls=${chrome === "none" ? 0 : 1}`, allow: "autoplay; encrypted-media; picture-in-picture; fullscreen", allowFullScreen: true, style: { border: 0, width: "100%", flex: 1, minHeight: 0 } }, mediaKey2) : isAudio ? /* @__PURE__ */ jsxs3("div", { style: { position: "relative", flex: 1, minHeight: 0, display: "grid", gridTemplateColumns: props.presentation === "compact" || props.presentation === "mini" ? "72px 1fr" : "1fr", alignItems: "center", gap: 16, padding: hidden ? 0 : 16, boxSizing: "border-box" }, children: [
|
|
27221
27328
|
poster && /* @__PURE__ */ jsx6("img", { src: poster, alt: "", style: chrome === "custom" ? { position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover", opacity: 0.62 } : { width: props.presentation === "compact" || props.presentation === "mini" ? 72 : "min(55%, 260px)", aspectRatio: "1", objectFit: "cover", borderRadius: ctx.radius("md", 8), justifySelf: "center" } }),
|
|
27222
27329
|
chrome === "custom" && /* @__PURE__ */ jsx6("div", { style: { position: "absolute", inset: 0, background: "linear-gradient(transparent,rgba(0,0,0,.75))" } }),
|
|
27223
27330
|
!hidden && chrome !== "custom" && /* @__PURE__ */ jsxs3("div", { style: { textAlign: props.presentation === "compact" || props.presentation === "mini" ? "left" : "center", minWidth: 0 }, children: [
|
|
@@ -27226,10 +27333,10 @@ var init_renderNode = __esm({
|
|
|
27226
27333
|
] }),
|
|
27227
27334
|
/* @__PURE__ */ jsx6("audio", { ref: (el) => {
|
|
27228
27335
|
mediaRef.current = el;
|
|
27229
|
-
}, ...commonMedia, children: renderMediaTracks() },
|
|
27336
|
+
}, ...commonMedia, children: renderMediaTracks() }, mediaKey2)
|
|
27230
27337
|
] }) : /* @__PURE__ */ jsx6("video", { ref: (el) => {
|
|
27231
27338
|
mediaRef.current = el;
|
|
27232
|
-
}, poster: poster || void 0, ...commonMedia, style: { width: "100%", flex: 1, minHeight: 0, display: "block", objectFit: props.contentMode === "fill" ? "cover" : "contain", background: "#000" }, children: renderMediaTracks() },
|
|
27339
|
+
}, poster: poster || void 0, ...commonMedia, style: { width: "100%", flex: 1, minHeight: 0, display: "block", objectFit: props.contentMode === "fill" ? "cover" : "contain", background: "#000" }, children: renderMediaTracks() }, mediaKey2),
|
|
27233
27340
|
status === "idle" && slot("poster"),
|
|
27234
27341
|
slot("overlay"),
|
|
27235
27342
|
status === "loading" && slot("loading"),
|
|
@@ -36625,6 +36732,8 @@ async function bootScreenWorker(opts) {
|
|
|
36625
36732
|
...opts.inputOverride ?? {}
|
|
36626
36733
|
};
|
|
36627
36734
|
const appear = opts.skipAppear ? null : rootOnAppear(opts.descriptor);
|
|
36735
|
+
const hostCalls = [];
|
|
36736
|
+
const host = hostDispatch(opts.localDbSchema, declaredCapabilitiesOf(opts.descriptor), opts.capabilitySuccess === true, opts.clock ?? CRAWL_CLOCK);
|
|
36628
36737
|
const w = await bootBundleWorker(opts.bundleJs, {
|
|
36629
36738
|
wixCall: opts.wixCall,
|
|
36630
36739
|
input,
|
|
@@ -36633,7 +36742,10 @@ async function bootScreenWorker(opts) {
|
|
|
36633
36742
|
// while the worker believed it was 2026, so a modelled session carried a timestamp fifty-six
|
|
36634
36743
|
// years before the "now" the app computes against — inconsistent rendered dates, and any
|
|
36635
36744
|
// time-dependent branch taking the wrong arm.
|
|
36636
|
-
dispatch:
|
|
36745
|
+
dispatch: (action, params) => {
|
|
36746
|
+
hostCalls.push(String(action));
|
|
36747
|
+
return host(action, params);
|
|
36748
|
+
},
|
|
36637
36749
|
deviceParity: true,
|
|
36638
36750
|
clock: opts.clock ?? CRAWL_CLOCK,
|
|
36639
36751
|
seed: opts.seed ?? 1,
|
|
@@ -36656,7 +36768,12 @@ async function bootScreenWorker(opts) {
|
|
|
36656
36768
|
}
|
|
36657
36769
|
for (let i = 0; i < 20; i++) await yieldMacrotask();
|
|
36658
36770
|
const { state, defects } = snapshot(w);
|
|
36659
|
-
return { ...w, state: Object.keys(state).length ? state : w.services, defects, ...deadLifecycle ? { deadLifecycle } : {} };
|
|
36771
|
+
return { ...w, hostCalls, state: Object.keys(state).length ? state : w.services, defects, ...deadLifecycle ? { deadLifecycle } : {} };
|
|
36772
|
+
}
|
|
36773
|
+
function effectSince(w, mark, action, componentId) {
|
|
36774
|
+
const wix = w.calls.slice(mark.wix);
|
|
36775
|
+
const host = w.hostCalls.slice(mark.host);
|
|
36776
|
+
return wix.length || host.length ? { action, componentId, wix, host } : null;
|
|
36660
36777
|
}
|
|
36661
36778
|
function resolveSiteRows(itemsPath, valueOf) {
|
|
36662
36779
|
if (!itemsPath || itemsPath === UNTRACKED_ITEMS) return void 0;
|
|
@@ -36717,7 +36834,10 @@ async function crawlScreenCapabilitySuccess(opts) {
|
|
|
36717
36834
|
const r = await crawlScreenInner({ ...opts, capabilitySuccess: true });
|
|
36718
36835
|
return {
|
|
36719
36836
|
findings: r.findings.map((f) => ({ ...f, axis: f.axis ? `capability:success+${f.axis}` : "capability:success" })),
|
|
36720
|
-
modelled: modelled.length
|
|
36837
|
+
modelled: modelled.length,
|
|
36838
|
+
// The success arm is where a paid flow goes on past `isAvailable` to `proceedToPayment`, so
|
|
36839
|
+
// its effects are the write inventory's too — unlike its counts, they cannot double anything.
|
|
36840
|
+
...r.effects?.length ? { effects: r.effects } : {}
|
|
36721
36841
|
};
|
|
36722
36842
|
});
|
|
36723
36843
|
}
|
|
@@ -36757,6 +36877,9 @@ async function crawlScreenJourney(opts) {
|
|
|
36757
36877
|
});
|
|
36758
36878
|
const sites = actionSitesForDescriptor(opts.descriptor);
|
|
36759
36879
|
let stepsExercised = 0;
|
|
36880
|
+
const effects = [];
|
|
36881
|
+
const bootEffect = effectSince(worker, { wix: 0, host: 0 }, "boot", null);
|
|
36882
|
+
if (bootEffect) effects.push(bootEffect);
|
|
36760
36883
|
for (const step of opts.journey.steps) {
|
|
36761
36884
|
const declared = sites.find((site2) => site2.actionId === step.action && (step.component === void 0 || site2.componentId === step.component));
|
|
36762
36885
|
if (!declared) {
|
|
@@ -36779,6 +36902,7 @@ async function crawlScreenJourney(opts) {
|
|
|
36779
36902
|
fail2(`journey "${opts.journey.name}" names unavailable worker action ${step.action}`, step);
|
|
36780
36903
|
continue;
|
|
36781
36904
|
}
|
|
36905
|
+
const mark = { wix: worker.calls.length, host: worker.hostCalls.length };
|
|
36782
36906
|
try {
|
|
36783
36907
|
await handle.dispatch(parsed.action, ...workerArgs({ params: { ...site.params ?? {}, ...site.args ?? {}, ...step.params ?? {} } }));
|
|
36784
36908
|
for (let i = 0; i < 8; i++) await yieldMacrotask();
|
|
@@ -36786,6 +36910,8 @@ async function crawlScreenJourney(opts) {
|
|
|
36786
36910
|
} catch (error) {
|
|
36787
36911
|
fail2(`journey "${opts.journey.name}" step ${step.action} threw: ${errText(error)}`, step);
|
|
36788
36912
|
}
|
|
36913
|
+
const stepEffect = effectSince(worker, mark, site.actionId, site.componentId);
|
|
36914
|
+
if (stepEffect) effects.push(stepEffect);
|
|
36789
36915
|
}
|
|
36790
36916
|
const settled = snapshot(worker);
|
|
36791
36917
|
if (worker.errors.length) {
|
|
@@ -36795,7 +36921,7 @@ async function crawlScreenJourney(opts) {
|
|
|
36795
36921
|
for (const expected of opts.journey.expectText) {
|
|
36796
36922
|
if (!values.includes(expected)) fail2(`journey "${opts.journey.name}" never rendered its expected visible result: ${JSON.stringify(expected)}`);
|
|
36797
36923
|
}
|
|
36798
|
-
return { screen: opts.screenId, journey: opts.journey.name, stepsExercised, findings };
|
|
36924
|
+
return { screen: opts.screenId, journey: opts.journey.name, stepsExercised, findings, ...effects.length ? { effects } : {} };
|
|
36799
36925
|
});
|
|
36800
36926
|
}
|
|
36801
36927
|
async function crawlScreenInner(opts) {
|
|
@@ -36810,6 +36936,7 @@ async function crawlScreenInner(opts) {
|
|
|
36810
36936
|
const actionsSkipped = [];
|
|
36811
36937
|
const navEdges = [];
|
|
36812
36938
|
const unobservedActions = [];
|
|
36939
|
+
const effects = [];
|
|
36813
36940
|
let observations;
|
|
36814
36941
|
let seedWords = [];
|
|
36815
36942
|
const harvestStaticEdges = (state) => {
|
|
@@ -37093,6 +37220,8 @@ async function crawlScreenInner(opts) {
|
|
|
37093
37220
|
harvestStaticEdges(first.state);
|
|
37094
37221
|
drainWorkerEdges(first, "worker:boot");
|
|
37095
37222
|
drainPollDirectives(first, "boot");
|
|
37223
|
+
const bootEffect = effectSince(first, { wix: 0, host: 0 }, "boot", null);
|
|
37224
|
+
if (bootEffect) effects.push(bootEffect);
|
|
37096
37225
|
if (/\bwixApi\b/.test(bundleJs) && first.calls.length === 0) {
|
|
37097
37226
|
const inputGated = /himalaya\??\.input\b|\binput\s*[.?]/.test(bundleJs);
|
|
37098
37227
|
findings.push({
|
|
@@ -37178,6 +37307,7 @@ async function crawlScreenInner(opts) {
|
|
|
37178
37307
|
const dispatched = typed ? { ...effective, args: { ...effective.args ?? {}, [typed.key]: typed.value } } : effective;
|
|
37179
37308
|
const before = JSON.stringify(preState);
|
|
37180
37309
|
const callsBefore = w.calls.length;
|
|
37310
|
+
const hostBefore = w.hostCalls.length;
|
|
37181
37311
|
const errors = [];
|
|
37182
37312
|
try {
|
|
37183
37313
|
await handle.dispatch(parsed.action, ...workerArgs(dispatched));
|
|
@@ -37190,6 +37320,8 @@ async function crawlScreenInner(opts) {
|
|
|
37190
37320
|
const navCountBefore = navEdges.length;
|
|
37191
37321
|
drainWorkerEdges(w, `worker:${site.actionId}`);
|
|
37192
37322
|
drainPollDirectives(w, trigger);
|
|
37323
|
+
const tapEffect = effectSince(w, { wix: callsBefore, host: hostBefore }, site.actionId, site.componentId);
|
|
37324
|
+
if (tapEffect) effects.push(tapEffect);
|
|
37193
37325
|
if (!errors.length && navEdges.length === navCountBefore && w.calls.length === callsBefore && JSON.stringify(state) === before) {
|
|
37194
37326
|
if (typed) {
|
|
37195
37327
|
findings.push({
|
|
@@ -37254,6 +37386,7 @@ async function crawlScreenInner(opts) {
|
|
|
37254
37386
|
actionsExercised: exercised,
|
|
37255
37387
|
actionsSkipped,
|
|
37256
37388
|
navEdges: edges,
|
|
37389
|
+
...effects.length ? { effects } : {},
|
|
37257
37390
|
...observations ? { observations } : {},
|
|
37258
37391
|
...unobservedActions.length ? { unobservedActions } : {},
|
|
37259
37392
|
findings: dedupe(findings),
|
|
@@ -37472,6 +37605,7 @@ async function crawlScreenDeep(opts, deep) {
|
|
|
37472
37605
|
const queue = [[]];
|
|
37473
37606
|
let dispatches = 0;
|
|
37474
37607
|
let capped = false;
|
|
37608
|
+
const effects = [];
|
|
37475
37609
|
const boot = () => bootScreenWorker({
|
|
37476
37610
|
bundleJs,
|
|
37477
37611
|
descriptor,
|
|
@@ -37492,6 +37626,13 @@ async function crawlScreenDeep(opts, deep) {
|
|
|
37492
37626
|
}
|
|
37493
37627
|
const path2 = queue.shift();
|
|
37494
37628
|
const w = await boot();
|
|
37629
|
+
let pending = null;
|
|
37630
|
+
const flushStep = () => {
|
|
37631
|
+
if (!pending) return;
|
|
37632
|
+
const e = effectSince(w, pending.mark, pending.site.actionId, pending.site.componentId);
|
|
37633
|
+
if (e) effects.push(e);
|
|
37634
|
+
pending = null;
|
|
37635
|
+
};
|
|
37495
37636
|
try {
|
|
37496
37637
|
let threwAt = null;
|
|
37497
37638
|
for (const [step, siteIdx] of path2.entries()) {
|
|
@@ -37513,6 +37654,8 @@ async function crawlScreenDeep(opts, deep) {
|
|
|
37513
37654
|
break;
|
|
37514
37655
|
}
|
|
37515
37656
|
dispatches += 1;
|
|
37657
|
+
flushStep();
|
|
37658
|
+
pending = { mark: { wix: w.calls.length, host: w.hostCalls.length }, site };
|
|
37516
37659
|
try {
|
|
37517
37660
|
await handle.dispatch(parsed.action, ...workerArgs(effective));
|
|
37518
37661
|
} catch (e) {
|
|
@@ -37533,8 +37676,12 @@ async function crawlScreenDeep(opts, deep) {
|
|
|
37533
37676
|
break;
|
|
37534
37677
|
}
|
|
37535
37678
|
}
|
|
37536
|
-
if (threwAt)
|
|
37679
|
+
if (threwAt) {
|
|
37680
|
+
flushStep();
|
|
37681
|
+
continue;
|
|
37682
|
+
}
|
|
37537
37683
|
for (let i = 0; i < 20; i++) await yieldMacrotask();
|
|
37684
|
+
flushStep();
|
|
37538
37685
|
const { state, defects } = snapshot(w);
|
|
37539
37686
|
const hash = deepStateSignature(state, defects);
|
|
37540
37687
|
if (visited.has(hash)) continue;
|
|
@@ -37579,7 +37726,7 @@ async function crawlScreenDeep(opts, deep) {
|
|
|
37579
37726
|
w.dispose();
|
|
37580
37727
|
}
|
|
37581
37728
|
}
|
|
37582
|
-
return { findings: dedupe(findings), nodesVisited: visited.size, dispatches, capped };
|
|
37729
|
+
return { findings: dedupe(findings), nodesVisited: visited.size, dispatches, capped, ...effects.length ? { effects } : {} };
|
|
37583
37730
|
});
|
|
37584
37731
|
}
|
|
37585
37732
|
function effectiveSiteForRow(site, row) {
|
|
@@ -40894,11 +41041,11 @@ function notCarriedDiff(local, base) {
|
|
|
40894
41041
|
const CARRIED = /* @__PURE__ */ new Set(["screens", "bundles", "tokensHash", "appConfigHash"]);
|
|
40895
41042
|
const PROVENANCE = /* @__PURE__ */ new Set(["releaseId", "gitSha", "shellSha", "label", "notes", "publishedAt", "publishedBy", "attestation", "forcedPastErrors", "app", "appSourceHash"]);
|
|
40896
41043
|
const REPORTED_IN_DETAIL = /* @__PURE__ */ new Set(["assets", "minBinaryVersion", "iconHash"]);
|
|
40897
|
-
const
|
|
41044
|
+
const comparable2 = (key2, value) => key2 === "widgets" ? stableWidgets(value) : value;
|
|
40898
41045
|
for (const key2 of /* @__PURE__ */ new Set([...Object.keys(local), ...Object.keys(base)])) {
|
|
40899
41046
|
if (CARRIED.has(key2) || PROVENANCE.has(key2) || REPORTED_IN_DETAIL.has(key2)) continue;
|
|
40900
|
-
const l =
|
|
40901
|
-
const b =
|
|
41047
|
+
const l = comparable2(key2, local[key2] ?? null);
|
|
41048
|
+
const b = comparable2(key2, base[key2] ?? null);
|
|
40902
41049
|
const ls = JSON.stringify(l) ?? "null";
|
|
40903
41050
|
const bs = JSON.stringify(b) ?? "null";
|
|
40904
41051
|
if (ls === bs) continue;
|
|
@@ -41685,7 +41832,7 @@ function assertRedirectUri(value) {
|
|
|
41685
41832
|
}
|
|
41686
41833
|
return trimmed;
|
|
41687
41834
|
}
|
|
41688
|
-
var BOOK_SCHEMA_VERSION, KNOWN_VERTICALS;
|
|
41835
|
+
var BOOK_SCHEMA_VERSION, KNOWN_VERTICALS, REDIRECT_NEEDS_CLIENT;
|
|
41689
41836
|
var init_types2 = __esm({
|
|
41690
41837
|
"src/site-analyze/types.ts"() {
|
|
41691
41838
|
BOOK_SCHEMA_VERSION = 2;
|
|
@@ -41719,6 +41866,7 @@ var init_types2 = __esm({
|
|
|
41719
41866
|
"galleries",
|
|
41720
41867
|
"inbox"
|
|
41721
41868
|
];
|
|
41869
|
+
REDIRECT_NEEDS_CLIENT = "--redirect-uri is the redirect REGISTERED on --client-id, so it needs --client-id too";
|
|
41722
41870
|
}
|
|
41723
41871
|
});
|
|
41724
41872
|
|
|
@@ -42064,6 +42212,7 @@ var init_home_descriptor = __esm({
|
|
|
42064
42212
|
var template_trim_exports = {};
|
|
42065
42213
|
__export(template_trim_exports, {
|
|
42066
42214
|
TrimRefusal: () => TrimRefusal,
|
|
42215
|
+
compareErrors: () => compareErrors,
|
|
42067
42216
|
leftoverNavRefs: () => leftoverNavRefs,
|
|
42068
42217
|
linearSafePattern: () => linearSafePattern,
|
|
42069
42218
|
parseApp: () => parseApp,
|
|
@@ -42832,6 +42981,16 @@ async function runTemplateTrim(req, deps) {
|
|
|
42832
42981
|
if (!existsSync42(path2) || !readFileSync46(path2).equals(original)) writeFileSync15(path2, original);
|
|
42833
42982
|
}
|
|
42834
42983
|
for (const name of [...moved].reverse()) renameSync4(join39(backup, "tier5-src", name), join39(dir, "tier5-src", name));
|
|
42984
|
+
moved.length = 0;
|
|
42985
|
+
};
|
|
42986
|
+
const apply = () => {
|
|
42987
|
+
const moveDir = deps.moveDir ?? renameSync4;
|
|
42988
|
+
for (const name of plan.removedWorkers) {
|
|
42989
|
+
moveDir(join39(dir, "tier5-src", name), join39(backup, "tier5-src", name));
|
|
42990
|
+
moved.push(name);
|
|
42991
|
+
}
|
|
42992
|
+
if (plan.dev !== dev) writeFileSync15(devPath, plan.dev);
|
|
42993
|
+
if (plan.config !== config) writeFileSync15(configPath, plan.config);
|
|
42835
42994
|
};
|
|
42836
42995
|
const dropBackup = () => {
|
|
42837
42996
|
rmSync8(backup, { recursive: true, force: true });
|
|
@@ -42870,13 +43029,7 @@ async function runTemplateTrim(req, deps) {
|
|
|
42870
43029
|
return { code: 1, result: { ok: false, error: `could not back up the app before trimming it (${e.message}); nothing was changed`, rolledBack: true, ...base() } };
|
|
42871
43030
|
}
|
|
42872
43031
|
try {
|
|
42873
|
-
|
|
42874
|
-
for (const name of plan.removedWorkers) {
|
|
42875
|
-
moveDir(join39(dir, "tier5-src", name), join39(backup, "tier5-src", name));
|
|
42876
|
-
moved.push(name);
|
|
42877
|
-
}
|
|
42878
|
-
if (plan.dev !== dev) writeFileSync15(devPath, plan.dev);
|
|
42879
|
-
if (plan.config !== config) writeFileSync15(configPath, plan.config);
|
|
43032
|
+
apply();
|
|
42880
43033
|
} catch (e) {
|
|
42881
43034
|
return abort("the trim failed while writing", e);
|
|
42882
43035
|
}
|
|
@@ -42893,9 +43046,53 @@ async function runTemplateTrim(req, deps) {
|
|
|
42893
43046
|
} catch (e) {
|
|
42894
43047
|
return abort("the trim could not be checked", e, validate3);
|
|
42895
43048
|
}
|
|
43049
|
+
let compared;
|
|
43050
|
+
if (failure && validate3 && validate3.code !== 0 && comparable(validate3)) {
|
|
43051
|
+
try {
|
|
43052
|
+
restore();
|
|
43053
|
+
} catch (e) {
|
|
43054
|
+
return abort(String(failure.error), e, validate3);
|
|
43055
|
+
}
|
|
43056
|
+
let original;
|
|
43057
|
+
try {
|
|
43058
|
+
original = await deps.validate(dir, { fresh: true });
|
|
43059
|
+
} catch {
|
|
43060
|
+
}
|
|
43061
|
+
if (original && comparable(original)) {
|
|
43062
|
+
compared = compareErrors(validate3.errors ?? [], original.code === 0 ? [] : original.errors ?? []);
|
|
43063
|
+
}
|
|
43064
|
+
const clean2 = compared !== void 0 && compared.introduced.length === 0;
|
|
43065
|
+
if (clean2 || req.force) {
|
|
43066
|
+
try {
|
|
43067
|
+
apply();
|
|
43068
|
+
} catch (e) {
|
|
43069
|
+
return abort("the trim failed while re-applying it after validating the untrimmed app", e, validate3);
|
|
43070
|
+
}
|
|
43071
|
+
}
|
|
43072
|
+
if (clean2) failure = void 0;
|
|
43073
|
+
else if (compared) {
|
|
43074
|
+
failure = {
|
|
43075
|
+
...failure,
|
|
43076
|
+
error: `himi validate --strict failed on the trimmed app \u2014 the trim introduced ${plural(compared.introduced.length, "error")} the untrimmed app does not have: ${summarize3(compared.introduced)}`,
|
|
43077
|
+
introducedErrors: compared.introduced,
|
|
43078
|
+
preExistingErrors: compared.preExisting
|
|
43079
|
+
};
|
|
43080
|
+
}
|
|
43081
|
+
}
|
|
42896
43082
|
if (!failure) {
|
|
42897
43083
|
dropBackup();
|
|
42898
|
-
|
|
43084
|
+
const preExisting = compared?.preExisting ?? [];
|
|
43085
|
+
return {
|
|
43086
|
+
code: 0,
|
|
43087
|
+
result: {
|
|
43088
|
+
ok: true,
|
|
43089
|
+
...base(validate3),
|
|
43090
|
+
...preExisting.length ? {
|
|
43091
|
+
preExistingErrors: preExisting,
|
|
43092
|
+
note: `trimmed; ${plural(preExisting.length, "error")} ${preExisting.length === 1 ? "was" : "were"} already present before trim: ${summarize3(preExisting)}`
|
|
43093
|
+
} : {}
|
|
43094
|
+
}
|
|
43095
|
+
};
|
|
42899
43096
|
}
|
|
42900
43097
|
if (req.force) {
|
|
42901
43098
|
return {
|
|
@@ -42914,7 +43111,36 @@ async function runTemplateTrim(req, deps) {
|
|
|
42914
43111
|
result: { ok: false, ...failure, rolledBack: true, hint: "nothing changed \u2014 fix what validate reports (or keep more screens) and trim again, or pass --force to keep the trimmed tree anyway", ...base(validate3) }
|
|
42915
43112
|
};
|
|
42916
43113
|
}
|
|
42917
|
-
|
|
43114
|
+
function comparable(v) {
|
|
43115
|
+
if (v.code === 0) return true;
|
|
43116
|
+
if (!v.errors?.length) return false;
|
|
43117
|
+
return v.counts === void 0 || v.counts.errors === v.errors.length;
|
|
43118
|
+
}
|
|
43119
|
+
function compareErrors(trimmed, original) {
|
|
43120
|
+
const left = /* @__PURE__ */ new Map();
|
|
43121
|
+
for (const e of original) left.set(e.id, (left.get(e.id) ?? 0) + 1);
|
|
43122
|
+
const out = { preExisting: [], introduced: [] };
|
|
43123
|
+
for (const e of trimmed) {
|
|
43124
|
+
const n = left.get(e.id) ?? 0;
|
|
43125
|
+
if (n > 0) {
|
|
43126
|
+
left.set(e.id, n - 1);
|
|
43127
|
+
out.preExisting.push(e);
|
|
43128
|
+
} else out.introduced.push(e);
|
|
43129
|
+
}
|
|
43130
|
+
return out;
|
|
43131
|
+
}
|
|
43132
|
+
function summarize3(errors) {
|
|
43133
|
+
const one = (e) => {
|
|
43134
|
+
const rule = e.pass ? e.ruleCode && e.ruleCode !== e.pass ? `${e.pass}/${e.ruleCode}` : e.pass : e.ruleCode;
|
|
43135
|
+
const place = e.screen ? `on ${e.screen}` : e.path ? `in ${e.path}` : void 0;
|
|
43136
|
+
const where = [rule, place].filter(Boolean).join(" ");
|
|
43137
|
+
const msg = e.message.length > 160 ? `${e.message.slice(0, 157)}...` : e.message;
|
|
43138
|
+
return where ? `${where}: ${msg}` : msg;
|
|
43139
|
+
};
|
|
43140
|
+
const shown2 = errors.slice(0, 5).map(one).join("; ");
|
|
43141
|
+
return errors.length > 5 ? `${shown2}; and ${errors.length - 5} more` : shown2;
|
|
43142
|
+
}
|
|
43143
|
+
var TrimRefusal, LIT, ATOM, QUANT, CAP, SAFE_ROUTE_PATTERN, lineOf, isStatic, entryLabel, isNode3, asItems, NAV_SCREEN_KEYS, sorted, refuse3, plural;
|
|
42918
43144
|
var init_template_trim = __esm({
|
|
42919
43145
|
"src/template-trim.ts"() {
|
|
42920
43146
|
init_validate_descriptor();
|
|
@@ -42948,6 +43174,7 @@ var init_template_trim = __esm({
|
|
|
42948
43174
|
NAV_SCREEN_KEYS = /* @__PURE__ */ new Set(["screenId", "parentScreenId", "contentScreenId", "badgeScreenId"]);
|
|
42949
43175
|
sorted = (xs) => [...new Set(xs)].sort();
|
|
42950
43176
|
refuse3 = (e) => ({ code: 2, result: { ok: false, error: e.message, ...e.detail } });
|
|
43177
|
+
plural = (n, word) => `${n} ${word}${n === 1 ? "" : "s"}`;
|
|
42951
43178
|
}
|
|
42952
43179
|
});
|
|
42953
43180
|
|
|
@@ -44229,6 +44456,184 @@ var init_eject = __esm({
|
|
|
44229
44456
|
}
|
|
44230
44457
|
});
|
|
44231
44458
|
|
|
44459
|
+
// src/wix-writes.ts
|
|
44460
|
+
import { existsSync as existsSync46, readFileSync as readFileSync50 } from "node:fs";
|
|
44461
|
+
import { join as join43 } from "node:path";
|
|
44462
|
+
function isProvenRead(method, path2) {
|
|
44463
|
+
if (/[#\x00-\x1F\x7F]/.test(path2)) return false;
|
|
44464
|
+
const verb = method.toUpperCase();
|
|
44465
|
+
if (verb === "GET") return true;
|
|
44466
|
+
const bare = path2.split("?")[0].replace(/\/+$/, "");
|
|
44467
|
+
return verb === "POST" && /\/(query|search|list[^/]*|get[^/]*|count|aggregate|facets|connections)$/i.test(bare);
|
|
44468
|
+
}
|
|
44469
|
+
function nativeWriteOf(verb) {
|
|
44470
|
+
const exact = NATIVE_WRITES[verb];
|
|
44471
|
+
if (exact) return { canonical: verb, ...exact };
|
|
44472
|
+
const member = MEMBER_VERB.exec(verb);
|
|
44473
|
+
if (member) return { canonical: `himi.wix.${member[1]}`, ...NATIVE_WRITES[`himi.wix.${member[1]}`] };
|
|
44474
|
+
return null;
|
|
44475
|
+
}
|
|
44476
|
+
function writesFromEffects(screen, effects) {
|
|
44477
|
+
const out = [];
|
|
44478
|
+
for (const e of effects ?? []) {
|
|
44479
|
+
const base = { screen, action: e.action, ...e.componentId ? { component: e.componentId } : {} };
|
|
44480
|
+
for (const call of e.wix) {
|
|
44481
|
+
const sp = call.indexOf(" ");
|
|
44482
|
+
const method = (sp < 0 ? call : call.slice(0, sp)).toUpperCase();
|
|
44483
|
+
const path2 = sp < 0 ? "" : call.slice(sp + 1);
|
|
44484
|
+
if (isProvenRead(method, path2)) continue;
|
|
44485
|
+
out.push({ ...base, via: "wix", method, path: path2.split("?")[0] });
|
|
44486
|
+
}
|
|
44487
|
+
for (const verb of e.host) {
|
|
44488
|
+
const native = nativeWriteOf(verb);
|
|
44489
|
+
if (native) out.push({ ...base, via: "native", capability: verb, kind: native.kind, what: native.what });
|
|
44490
|
+
}
|
|
44491
|
+
}
|
|
44492
|
+
return dedupeWrites(out);
|
|
44493
|
+
}
|
|
44494
|
+
function dedupeWrites(list) {
|
|
44495
|
+
const seen = /* @__PURE__ */ new Set();
|
|
44496
|
+
const out = [];
|
|
44497
|
+
for (const w of list) {
|
|
44498
|
+
const k = writeKey(w);
|
|
44499
|
+
if (seen.has(k)) continue;
|
|
44500
|
+
seen.add(k);
|
|
44501
|
+
out.push(w);
|
|
44502
|
+
}
|
|
44503
|
+
return out;
|
|
44504
|
+
}
|
|
44505
|
+
function unreachedNativeWrites(screen, bundleJs, observed) {
|
|
44506
|
+
if (!bundleJs) return [];
|
|
44507
|
+
const seen = new Set(observed.filter((w) => w.screen === screen && w.via === "native").map((w) => nativeWriteOf(w.capability)?.canonical));
|
|
44508
|
+
const out = [];
|
|
44509
|
+
for (const [verb, native] of Object.entries(NATIVE_WRITES)) {
|
|
44510
|
+
if (seen.has(verb)) continue;
|
|
44511
|
+
if (!BUNDLE_TEXT[verb].test(bundleJs)) continue;
|
|
44512
|
+
out.push({ screen, action: "unreached", via: "native", capability: verb, kind: native.kind, what: native.what });
|
|
44513
|
+
}
|
|
44514
|
+
return out;
|
|
44515
|
+
}
|
|
44516
|
+
function parseDataAccess(text5, from) {
|
|
44517
|
+
const body = text5.replace(/<!--[\s\S]*?(?:-->|$)/g, "");
|
|
44518
|
+
const heading = new RegExp(`(?:^|\\n)##[ \\t]+${DATA_ACCESS_HEADING}\\b[^\\n]*([\\s\\S]*?)(?=\\n##[ \\t]|$)`, "i").exec(body);
|
|
44519
|
+
if (!heading) return null;
|
|
44520
|
+
const lines = heading[1].split("\n").map((l) => l.trim()).filter((l) => l.startsWith("|"));
|
|
44521
|
+
if (lines.length < 2) return null;
|
|
44522
|
+
const cells = (line) => line.replace(/^\|/, "").replace(/\|\s*$/, "").split("|").map((c) => c.trim());
|
|
44523
|
+
const header = cells(lines[0]).map((c) => unquote(c).toLowerCase());
|
|
44524
|
+
const screenCol = header.findIndex((h) => /^screens?$/.test(h));
|
|
44525
|
+
let writesCol = header.findIndex((h) => /^wix writes?$/.test(h));
|
|
44526
|
+
if (writesCol < 0) writesCol = header.findIndex((h) => /^writes?$/.test(h));
|
|
44527
|
+
if (screenCol < 0 || writesCol < 0) return null;
|
|
44528
|
+
const rows = [];
|
|
44529
|
+
for (const line of lines.slice(1)) {
|
|
44530
|
+
if (/^\|?\s*:?-+:?\s*(\|\s*:?-+:?\s*)*\|?$/.test(line)) continue;
|
|
44531
|
+
const row = cells(line);
|
|
44532
|
+
const screen = unquote(row[screenCol] ?? "");
|
|
44533
|
+
if (!screen) continue;
|
|
44534
|
+
const cell = unquote(row[writesCol] ?? "");
|
|
44535
|
+
const entries = cell.split(/[,;]/).map((e) => e.trim()).filter((e) => e && !NONE.test(e));
|
|
44536
|
+
rows.push({ screen, allowed: NONE.test(cell) || !entries.length ? null : entries });
|
|
44537
|
+
}
|
|
44538
|
+
return rows.length ? { from, rows } : null;
|
|
44539
|
+
}
|
|
44540
|
+
function readDataAccess(dir) {
|
|
44541
|
+
for (const name of ["SPEC.md", "MOBILE-UX.md"]) {
|
|
44542
|
+
const p = join43(dir, name);
|
|
44543
|
+
if (!existsSync46(p)) continue;
|
|
44544
|
+
let text5;
|
|
44545
|
+
try {
|
|
44546
|
+
text5 = readFileSync50(p, "utf8");
|
|
44547
|
+
} catch {
|
|
44548
|
+
continue;
|
|
44549
|
+
}
|
|
44550
|
+
const plan = parseDataAccess(text5, name);
|
|
44551
|
+
if (plan) return plan;
|
|
44552
|
+
}
|
|
44553
|
+
return null;
|
|
44554
|
+
}
|
|
44555
|
+
function entryApproves(entry, w) {
|
|
44556
|
+
const e = entry.trim();
|
|
44557
|
+
const lower = e.toLowerCase();
|
|
44558
|
+
const actionTail = w.action.split(".").pop() ?? w.action;
|
|
44559
|
+
if (e === w.action || e === actionTail) return true;
|
|
44560
|
+
if (w.via === "native") {
|
|
44561
|
+
const tail = w.capability.split(".").pop();
|
|
44562
|
+
if (e === w.capability || e === tail || e === nativeWriteOf(w.capability)?.canonical) return true;
|
|
44563
|
+
if (w.kind === "payment" && /^payments?$/.test(lower)) return true;
|
|
44564
|
+
if (w.kind === "member-signup" && /^(sign-?up|register|registration|member[- ]signup)$/.test(lower)) return true;
|
|
44565
|
+
return false;
|
|
44566
|
+
}
|
|
44567
|
+
const m = /^(?:(GET|POST|PUT|PATCH|DELETE)\s+)?(\/\S*|https?:\/\/\S+)$/i.exec(e);
|
|
44568
|
+
if (!m) return false;
|
|
44569
|
+
if (m[1] && m[1].toUpperCase() !== w.method) return false;
|
|
44570
|
+
return pathPattern(m[2]).test(w.path);
|
|
44571
|
+
}
|
|
44572
|
+
function pathPattern(p) {
|
|
44573
|
+
const body = p.replace(/\/+$/, "").split("*").map((part) => part.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).join("[^/]+");
|
|
44574
|
+
return new RegExp(`^${body}/?$`);
|
|
44575
|
+
}
|
|
44576
|
+
function unapprovedWriteFindings(writes, plan) {
|
|
44577
|
+
if (!plan) return [];
|
|
44578
|
+
const byScreen = /* @__PURE__ */ new Map();
|
|
44579
|
+
for (const row of plan.rows) {
|
|
44580
|
+
const list = byScreen.get(row.screen) ?? [];
|
|
44581
|
+
list.push(row);
|
|
44582
|
+
byScreen.set(row.screen, list);
|
|
44583
|
+
}
|
|
44584
|
+
const findings = [];
|
|
44585
|
+
for (const w of writes) {
|
|
44586
|
+
const rows = byScreen.get(w.screen) ?? byScreen.get("*");
|
|
44587
|
+
const unreached = w.action === "unreached";
|
|
44588
|
+
const trigger = w.action === "boot" || unreached ? "boot" : { tap: w.component ?? null, key: "write", action: w.action };
|
|
44589
|
+
const does = unreached ? `can write to Wix (${writeLabel(w)} \u2014 its worker bundle calls it, on a path this crawl did not reach)` : `writes to Wix (${writeLabel(w)})`;
|
|
44590
|
+
const hint = `Before publishing, reconcile this with the owner-approved plan: remove the action (or trim the screen with \`himi template trim\`) if the owner did not approve it, or name the write in ${plan.from}'s \`## ${DATA_ACCESS_HEADING}\` table \u2014 ` + (unreached ? "" : `its action (\`${w.action.split(".").pop()}\`), `) + (w.via === "wix" ? `its endpoint (\`${w.method} ${w.path}\`)` : `its capability (\`${w.capability.split(".").pop()}\`)`) + ` \u2014 once they have.`;
|
|
44591
|
+
if (!rows) {
|
|
44592
|
+
findings.push({
|
|
44593
|
+
screen: w.screen,
|
|
44594
|
+
trigger,
|
|
44595
|
+
invariant: "write-not-approved",
|
|
44596
|
+
severity: "warning",
|
|
44597
|
+
message: `${does}, and ${plan.from}'s data-access table has no row for this screen`,
|
|
44598
|
+
hint
|
|
44599
|
+
});
|
|
44600
|
+
continue;
|
|
44601
|
+
}
|
|
44602
|
+
const allowed2 = rows.flatMap((r) => r.allowed ?? []);
|
|
44603
|
+
if (allowed2.some((entry) => entryApproves(entry, w))) continue;
|
|
44604
|
+
findings.push({
|
|
44605
|
+
screen: w.screen,
|
|
44606
|
+
trigger,
|
|
44607
|
+
invariant: "write-not-approved",
|
|
44608
|
+
severity: "warning",
|
|
44609
|
+
message: allowed2.length ? `${does}, which ${plan.from}'s data-access table does not name for this screen (approved: ${allowed2.join(", ")})` : `${does}, but ${plan.from}'s data-access table approves no writes on this screen`,
|
|
44610
|
+
hint
|
|
44611
|
+
});
|
|
44612
|
+
}
|
|
44613
|
+
return findings;
|
|
44614
|
+
}
|
|
44615
|
+
var NATIVE_WRITES, MEMBER_VERB, BUNDLE_TEXT, writeKey, writeLabel, DATA_ACCESS_HEADING, NONE, unquote;
|
|
44616
|
+
var init_wix_writes = __esm({
|
|
44617
|
+
"src/wix-writes.ts"() {
|
|
44618
|
+
NATIVE_WRITES = {
|
|
44619
|
+
"himi.wix.registerDirect": { kind: "member-signup", what: "creates a site member" },
|
|
44620
|
+
"himi.wix.resetPassword": { kind: "member-account", what: "sends a site member a password-reset email" },
|
|
44621
|
+
"capability.wix_cashier.proceedToPayment": { kind: "payment", what: "charges the customer through the Wix cashier" }
|
|
44622
|
+
};
|
|
44623
|
+
MEMBER_VERB = /^[a-z_]+\.wix\.(registerDirect|resetPassword)$/;
|
|
44624
|
+
BUNDLE_TEXT = {
|
|
44625
|
+
"himi.wix.registerDirect": /["'`][a-z_]+\.wix\.registerDirect["'`]|\}(?:\.wix)?\.registerDirect`/,
|
|
44626
|
+
"himi.wix.resetPassword": /["'`][a-z_]+\.wix\.resetPassword["'`]|\}(?:\.wix)?\.resetPassword`/,
|
|
44627
|
+
"capability.wix_cashier.proceedToPayment": /capability\.wix_cashier\.proceedToPayment["'`]/
|
|
44628
|
+
};
|
|
44629
|
+
writeKey = (w) => [w.screen, w.action, w.via, w.method ?? "", w.path ?? "", w.capability ?? ""].join("|");
|
|
44630
|
+
writeLabel = (w) => w.via === "wix" ? `${w.method} ${w.path}` : `${w.capability} (${w.what})`;
|
|
44631
|
+
DATA_ACCESS_HEADING = "Data access";
|
|
44632
|
+
NONE = /^(|-+|—|–|none|no|nothing|n\/a|na|read[- ]only|reads? only|✗|×)$/i;
|
|
44633
|
+
unquote = (cell) => cell.replace(/`/g, "").trim();
|
|
44634
|
+
}
|
|
44635
|
+
});
|
|
44636
|
+
|
|
44232
44637
|
// src/test.ts
|
|
44233
44638
|
var test_exports = {};
|
|
44234
44639
|
__export(test_exports, {
|
|
@@ -44245,14 +44650,14 @@ __export(test_exports, {
|
|
|
44245
44650
|
scopeDescriptors: () => scopeDescriptors,
|
|
44246
44651
|
writeRecordedMocks: () => writeRecordedMocks
|
|
44247
44652
|
});
|
|
44248
|
-
import { existsSync as
|
|
44249
|
-
import { join as
|
|
44653
|
+
import { existsSync as existsSync47, mkdirSync as mkdirSync23, readFileSync as readFileSync51, writeFileSync as writeFileSync19 } from "node:fs";
|
|
44654
|
+
import { join as join44, resolve as resolve40 } from "node:path";
|
|
44250
44655
|
function readTestConfig(dir) {
|
|
44251
44656
|
const p = resolve40(dir, TEST_CONFIG_FILE);
|
|
44252
|
-
if (!
|
|
44657
|
+
if (!existsSync47(p)) return {};
|
|
44253
44658
|
let parsed;
|
|
44254
44659
|
try {
|
|
44255
|
-
parsed = JSON.parse(
|
|
44660
|
+
parsed = JSON.parse(readFileSync51(p, "utf8"));
|
|
44256
44661
|
} catch (e) {
|
|
44257
44662
|
throw new Error(`${TEST_CONFIG_FILE} is not valid JSON \u2014 ${e.message}`);
|
|
44258
44663
|
}
|
|
@@ -44285,6 +44690,10 @@ function readTestConfig(dir) {
|
|
|
44285
44690
|
if (step.component !== void 0 && typeof step.component !== "string") throw new Error(`${TEST_CONFIG_FILE}: journeys[${i}].steps[${stepIndex}].component must be a string`);
|
|
44286
44691
|
if (step.params !== void 0 && (!step.params || typeof step.params !== "object" || Array.isArray(step.params))) throw new Error(`${TEST_CONFIG_FILE}: journeys[${i}].steps[${stepIndex}].params must be an object`);
|
|
44287
44692
|
});
|
|
44693
|
+
const input = journey.input;
|
|
44694
|
+
if (input !== void 0 && (!input || typeof input !== "object" || Array.isArray(input) || Object.values(input).some((v) => typeof v !== "string"))) {
|
|
44695
|
+
throw new Error(`${TEST_CONFIG_FILE}: journeys[${i}].input must be an object of string values \u2014 the screen input a nav edge would send, e.g. { "id": "svc-0001" }`);
|
|
44696
|
+
}
|
|
44288
44697
|
if (!Array.isArray(journey.expectText) || !journey.expectText.length || journey.expectText.some((text5) => typeof text5 !== "string" || !text5.trim())) {
|
|
44289
44698
|
throw new Error(`${TEST_CONFIG_FILE}: journeys[${i}] needs non-empty expectText values that prove a visible result`);
|
|
44290
44699
|
}
|
|
@@ -44295,7 +44704,7 @@ function readTestConfig(dir) {
|
|
|
44295
44704
|
function readNetRules(path2) {
|
|
44296
44705
|
let parsed;
|
|
44297
44706
|
try {
|
|
44298
|
-
parsed = JSON.parse(
|
|
44707
|
+
parsed = JSON.parse(readFileSync51(path2, "utf8"));
|
|
44299
44708
|
} catch (e) {
|
|
44300
44709
|
throw new Error(`--net ${path2} could not be read as JSON \u2014 ${e.message}`);
|
|
44301
44710
|
}
|
|
@@ -44316,7 +44725,7 @@ function readNetRules(path2) {
|
|
|
44316
44725
|
function defaultNetRules(dir) {
|
|
44317
44726
|
for (const rel of ["dev/net-mocks.json", "tests/net-mocks.json"]) {
|
|
44318
44727
|
const p = resolve40(dir, rel);
|
|
44319
|
-
if (
|
|
44728
|
+
if (existsSync47(p)) {
|
|
44320
44729
|
const rules = readNetRules(p);
|
|
44321
44730
|
if (rules.length) return { rules, from: rel };
|
|
44322
44731
|
}
|
|
@@ -44332,7 +44741,7 @@ function readCannedResponses() {
|
|
|
44332
44741
|
];
|
|
44333
44742
|
for (const url of candidates) {
|
|
44334
44743
|
try {
|
|
44335
|
-
const parsed = JSON.parse(
|
|
44744
|
+
const parsed = JSON.parse(readFileSync51(url, "utf8"));
|
|
44336
44745
|
const byKey = {};
|
|
44337
44746
|
for (const [k, v] of Object.entries(parsed)) {
|
|
44338
44747
|
if (!k.startsWith("//")) byKey[k] = v;
|
|
@@ -44354,9 +44763,7 @@ function makeRecordingWixCall(send2, token, app) {
|
|
|
44354
44763
|
refused.push(`${verb} ${path2}`);
|
|
44355
44764
|
throw new Error(`--record refused ${verb} ${path2}: the path carries a fragment or control character \u2014 not a provable read`);
|
|
44356
44765
|
}
|
|
44357
|
-
|
|
44358
|
-
const readShaped = verb === "GET" || verb === "POST" && /\/(query|search|list[^/]*|get[^/]*|count|aggregate|facets|connections)$/i.test(bare);
|
|
44359
|
-
if (!readShaped) {
|
|
44766
|
+
if (!isProvenRead(verb, path2)) {
|
|
44360
44767
|
refused.push(`${verb} ${path2}`);
|
|
44361
44768
|
throw new Error(`--record refused ${verb} ${path2}: recording sends only proven reads (GET, or POST ending in /query, /search, /list*, /get*, /count, /aggregate, /facets, /connections) \u2014 if this IS a read, add its rule to dev/net-mocks.json by hand`);
|
|
44362
44769
|
}
|
|
@@ -44424,8 +44831,8 @@ function writeRecordedMocks(opts) {
|
|
|
44424
44831
|
mkdir: (p) => mkdirSync23(p, { recursive: true }),
|
|
44425
44832
|
write: (p, s) => writeFileSync19(p, s)
|
|
44426
44833
|
};
|
|
44427
|
-
fs.mkdir(
|
|
44428
|
-
fs.write(
|
|
44834
|
+
fs.mkdir(join44(opts.dir, "dev"));
|
|
44835
|
+
fs.write(join44(opts.dir, "dev", "net-mocks.json"), JSON.stringify(opts.mocks, null, 2) + "\n");
|
|
44429
44836
|
return { ok: true, rules, to: "dev/net-mocks.json" };
|
|
44430
44837
|
}
|
|
44431
44838
|
function scopeDescriptors(descriptors, requestedIds, invalidScreens) {
|
|
@@ -44493,6 +44900,7 @@ async function runCrawl(opts) {
|
|
|
44493
44900
|
const suppressed = [];
|
|
44494
44901
|
const matchSuppression = (screen, actionId, componentId, invariant) => suppressions.find((s) => (s.screen === void 0 || s.screen === screen) && (s.action === void 0 || s.action === actionId) && (s.component === void 0 || s.component === componentId) && (s.invariant === void 0 || s.invariant === invariant));
|
|
44495
44902
|
const results = [];
|
|
44903
|
+
const writes = [];
|
|
44496
44904
|
const uncoveredByScreen = /* @__PURE__ */ new Map();
|
|
44497
44905
|
const coverageFns = /* @__PURE__ */ new Map();
|
|
44498
44906
|
const bundleOf = new Map(descriptors.map((d) => [d.screenId, d]));
|
|
@@ -44530,18 +44938,21 @@ async function runCrawl(opts) {
|
|
|
44530
44938
|
const cov = baked.bundleJs && deps.startWorkerCoverage ? await deps.startWorkerCoverage() : null;
|
|
44531
44939
|
const r = await deps.crawlScreen(args);
|
|
44532
44940
|
results.push(r);
|
|
44941
|
+
writes.push(...writesFromEffects(baked.screenId, r.effects));
|
|
44533
44942
|
for (const journey of opts.config?.journeys?.filter((candidate) => candidate.screen === baked.screenId) ?? []) {
|
|
44534
44943
|
if (!deps.crawlScreenJourney) {
|
|
44535
44944
|
journeyFindings.push({ screen: baked.screenId, trigger: "boot", invariant: "journey-failed", severity: "error", message: `journey "${journey.name}" cannot run because this CLI's crawl engine is too old`, hint: "Upgrade @wix/himalaya-cli so typed journeys run instead of being silently skipped." });
|
|
44536
44945
|
journeyResults.push({ name: journey.name, screen: baked.screenId, stepsExercised: 0, ok: false });
|
|
44537
44946
|
continue;
|
|
44538
44947
|
}
|
|
44539
|
-
const jr = await deps.crawlScreenJourney({ ...args, journey });
|
|
44948
|
+
const jr = await deps.crawlScreenJourney({ ...args, ...journey.input ? { inputOverride: journey.input } : {}, journey });
|
|
44949
|
+
writes.push(...writesFromEffects(baked.screenId, jr.effects));
|
|
44540
44950
|
journeyFindings.push(...jr.findings);
|
|
44541
44951
|
journeyResults.push({ name: journey.name, screen: baked.screenId, stepsExercised: jr.stepsExercised, ok: jr.findings.length === 0 });
|
|
44542
44952
|
}
|
|
44543
44953
|
if (opts.deep && opts.deep >= 2 && deps.crawlScreenDeep && baked.bundleJs) {
|
|
44544
44954
|
const dr = await deps.crawlScreenDeep(args, { depth: opts.deep });
|
|
44955
|
+
writes.push(...writesFromEffects(baked.screenId, dr.effects));
|
|
44545
44956
|
deepTotals.nodesVisited += dr.nodesVisited;
|
|
44546
44957
|
deepTotals.dispatches += dr.dispatches;
|
|
44547
44958
|
deepTotals.capped = deepTotals.capped || dr.capped;
|
|
@@ -44581,6 +44992,7 @@ async function runCrawl(opts) {
|
|
|
44581
44992
|
}
|
|
44582
44993
|
if (deps.crawlScreenCapabilitySuccess && baked.bundleJs) {
|
|
44583
44994
|
const cr = await deps.crawlScreenCapabilitySuccess(args);
|
|
44995
|
+
writes.push(...writesFromEffects(baked.screenId, cr.effects));
|
|
44584
44996
|
capabilityModelled += cr.modelled;
|
|
44585
44997
|
const keyOfC = deps.findingKey ?? ((f) => `${f.invariant}|${f.at ?? ""}|${f.screen}|${f.message}`);
|
|
44586
44998
|
const seen = new Set([...r.findings, ...relationFindings].map(keyOfC));
|
|
@@ -44657,6 +45069,7 @@ async function runCrawl(opts) {
|
|
|
44657
45069
|
list.push(...fns);
|
|
44658
45070
|
coverageFns.set(target, list);
|
|
44659
45071
|
}
|
|
45072
|
+
writes.push(...writesFromEffects(target, er.effects));
|
|
44660
45073
|
edgesFollowed.push({ target, from: shape.from, params: shape.params, via: shape.via });
|
|
44661
45074
|
if (!er.findings.some((f) => f.invariant === "no-request-issued") && !opts.tabRoots?.has(target) && !fetchProven.has(target)) {
|
|
44662
45075
|
fetchProven.set(target, { from: shape.from, params: shape.params });
|
|
@@ -44681,7 +45094,11 @@ async function runCrawl(opts) {
|
|
|
44681
45094
|
if (uncovered.length) uncoveredByScreen.set(screen, uncovered);
|
|
44682
45095
|
}
|
|
44683
45096
|
}
|
|
44684
|
-
const
|
|
45097
|
+
const inventory = dedupeWrites(writes);
|
|
45098
|
+
const unreachedWrites = targets.flatMap((d) => unreachedNativeWrites(d.screenId, d.bundleJs, inventory));
|
|
45099
|
+
const plan = readDataAccess(opts.dir);
|
|
45100
|
+
const writeFindings = unapprovedWriteFindings([...inventory, ...unreachedWrites], plan);
|
|
45101
|
+
const all = [...results.flatMap((r) => r.findings), ...hostileFindings, ...deepFindings, ...journeyFindings, ...edgeFindings, ...relationFindings, ...writeFindings].filter((f) => {
|
|
44685
45102
|
if (f.invariant === "no-request-issued" && !f.axis && fetchProven.has(f.screen)) {
|
|
44686
45103
|
const by = fetchProven.get(f.screen);
|
|
44687
45104
|
if (!retired.some((x) => x.screen === f.screen)) retired.push({ screen: f.screen, from: by.from, params: by.params });
|
|
@@ -44735,6 +45152,9 @@ async function runCrawl(opts) {
|
|
|
44735
45152
|
...deps.crawlScreenRelations ? { relations: { checked: relationsChecked, byKind: relationsByKind } } : {},
|
|
44736
45153
|
...deps.crawlScreenCapabilitySuccess ? { capabilities: { modelled: capabilityModelled } } : {},
|
|
44737
45154
|
...journeyResults.length ? { journeys: journeyResults } : {},
|
|
45155
|
+
writes: inventory,
|
|
45156
|
+
...unreachedWrites.length ? { unreachedWrites } : {},
|
|
45157
|
+
...plan ? { writesPlan: { from: plan.from, rows: plan.rows.length } } : {},
|
|
44738
45158
|
...results.some((r) => r.observations) ? { observations: Object.fromEntries(results.filter((r) => r.observations).map((r) => [r.screen, r.observations])) } : {}
|
|
44739
45159
|
};
|
|
44740
45160
|
}
|
|
@@ -44820,6 +45240,17 @@ function formatReport(r) {
|
|
|
44820
45240
|
}
|
|
44821
45241
|
out.push("");
|
|
44822
45242
|
}
|
|
45243
|
+
if (r.writes?.length || r.unreachedWrites?.length) {
|
|
45244
|
+
out.push(` Writes to Wix (${r.writes.length}) \u2014 every write the crawl saw a worker attempt (none reached Wix). A write behind a form or a selection shows only under --deep or a journey:`);
|
|
45245
|
+
const byScreenW = /* @__PURE__ */ new Map();
|
|
45246
|
+
for (const w of r.writes) byScreenW.set(w.screen, [...byScreenW.get(w.screen) ?? [], w]);
|
|
45247
|
+
for (const [screen, list] of [...byScreenW].sort(([a], [b]) => a.localeCompare(b))) {
|
|
45248
|
+
for (const w of list) out.push(` ${screen} ${w.action === "boot" ? "on appear" : w.action} ${writeLabel(w)}`);
|
|
45249
|
+
}
|
|
45250
|
+
for (const w of r.unreachedWrites ?? []) out.push(` ${w.screen} (not reached \u2014 in its worker bundle) ${writeLabel(w)}`);
|
|
45251
|
+
out.push(r.writesPlan ? ` checked against ${r.writesPlan.from}'s \`## ${DATA_ACCESS_HEADING}\` table (${r.writesPlan.rows} row${r.writesPlan.rows === 1 ? "" : "s"}) \u2014 unapproved writes are write-not-approved warnings above` : ` no \`## ${DATA_ACCESS_HEADING}\` table (Screen + Wix writes columns) in SPEC.md or MOBILE-UX.md, so nothing checked these against the approved plan \u2014 \`himi docs himi-test\` \u2192 "Writes to Wix"`);
|
|
45252
|
+
out.push("");
|
|
45253
|
+
}
|
|
44823
45254
|
if (r.shots?.written && r.shots.dir) {
|
|
44824
45255
|
out.push(` ${r.shots.written} screenshot${r.shots.written === 1 ? "" : "s"} \u2192 ${r.shots.dir}/`);
|
|
44825
45256
|
}
|
|
@@ -44872,6 +45303,7 @@ var init_test = __esm({
|
|
|
44872
45303
|
"src/test.ts"() {
|
|
44873
45304
|
init_wix_gateway_rules();
|
|
44874
45305
|
init_crawl_layers();
|
|
45306
|
+
init_wix_writes();
|
|
44875
45307
|
TEST_CONFIG_FILE = "himi-test.json";
|
|
44876
45308
|
triggerLabel = (f) => (f.trigger === "boot" ? "on appear" : `${f.trigger.key} ${f.trigger.tap ?? "(no id)"} \u2192 ${f.trigger.action}`) + (f.axis ? ` [${f.axis}]` : "");
|
|
44877
45309
|
}
|
|
@@ -44882,14 +45314,14 @@ var mobile_ux_lint_exports = {};
|
|
|
44882
45314
|
__export(mobile_ux_lint_exports, {
|
|
44883
45315
|
mobileUxIssues: () => mobileUxIssues
|
|
44884
45316
|
});
|
|
44885
|
-
import { existsSync as
|
|
44886
|
-
import { join as
|
|
45317
|
+
import { existsSync as existsSync48, readFileSync as readFileSync52 } from "node:fs";
|
|
45318
|
+
import { join as join45 } from "node:path";
|
|
44887
45319
|
function mobileUxIssues(dir, strict) {
|
|
44888
|
-
const file =
|
|
44889
|
-
if (!
|
|
45320
|
+
const file = join45(dir, "MOBILE-UX.md");
|
|
45321
|
+
if (!existsSync48(file)) return [];
|
|
44890
45322
|
let text5;
|
|
44891
45323
|
try {
|
|
44892
|
-
text5 =
|
|
45324
|
+
text5 = readFileSync52(file, "utf8");
|
|
44893
45325
|
} catch {
|
|
44894
45326
|
return [];
|
|
44895
45327
|
}
|
|
@@ -46564,8 +46996,8 @@ __export(functions_exports, {
|
|
|
46564
46996
|
resolveFunctionsTarget: () => resolveFunctionsTarget,
|
|
46565
46997
|
runRemoteFunctionOperation: () => runRemoteFunctionOperation
|
|
46566
46998
|
});
|
|
46567
|
-
import { readFileSync as
|
|
46568
|
-
import { join as
|
|
46999
|
+
import { readFileSync as readFileSync53, existsSync as existsSync49 } from "node:fs";
|
|
47000
|
+
import { join as join46, resolve as resolve41 } from "node:path";
|
|
46569
47001
|
function resolveFunctionsTarget(input) {
|
|
46570
47002
|
const explicitUrl = input.functionsUrl?.trim();
|
|
46571
47003
|
if (explicitUrl) return { mode: "remote", baseUrl: explicitUrl };
|
|
@@ -46584,9 +47016,9 @@ async function loadFunctionsApp(dir) {
|
|
|
46584
47016
|
}
|
|
46585
47017
|
const sources = {};
|
|
46586
47018
|
for (const definition of config.functions.functions) {
|
|
46587
|
-
const source = [".ts", ".js", ".mts", ".mjs"].map((extension) =>
|
|
47019
|
+
const source = [".ts", ".js", ".mts", ".mjs"].map((extension) => join46(loaded.dir, "functions", `${definition.name}${extension}`)).find(existsSync49);
|
|
46588
47020
|
if (!source) throw new Error(`missing source for function ${definition.name}; expected functions/${definition.name}.ts`);
|
|
46589
|
-
sources[definition.name] =
|
|
47021
|
+
sources[definition.name] = readFileSync53(source, "utf8");
|
|
46590
47022
|
}
|
|
46591
47023
|
const data = config.cms || config.data ? mergeDataResources(config) : void 0;
|
|
46592
47024
|
const dataErrors = validateDataResources(data, loaded.name).filter((issue2) => issue2.severity === "error");
|
|
@@ -46738,10 +47170,10 @@ __export(studio_reel_exports, {
|
|
|
46738
47170
|
utcDay: () => utcDay
|
|
46739
47171
|
});
|
|
46740
47172
|
import { createHash as createHash24 } from "node:crypto";
|
|
46741
|
-
import { lstatSync as lstatSync7, readFileSync as
|
|
46742
|
-
import { basename as basename11, join as
|
|
47173
|
+
import { lstatSync as lstatSync7, readFileSync as readFileSync54 } from "node:fs";
|
|
47174
|
+
import { basename as basename11, join as join47 } from "node:path";
|
|
46743
47175
|
function loadMemory2(dir) {
|
|
46744
|
-
const m = readJson4(
|
|
47176
|
+
const m = readJson4(join47(dir, ".himi", "studio", "memory.json"));
|
|
46745
47177
|
if (!isObj2(m) || m.version !== 1 || !isObj2(m.shots) || !Array.isArray(m.timeline)) return null;
|
|
46746
47178
|
const shots = [];
|
|
46747
47179
|
for (const [id, s] of Object.entries(m.shots)) {
|
|
@@ -46778,8 +47210,8 @@ function planReel(dir) {
|
|
|
46778
47210
|
const memory = loadMemory2(dir);
|
|
46779
47211
|
const { entries } = readProgress(dir);
|
|
46780
47212
|
const summary = summarizeProgress(entries);
|
|
46781
|
-
const manifest = readJson4(
|
|
46782
|
-
const tokens = readJson4(
|
|
47213
|
+
const manifest = readJson4(join47(dir, "himalaya.content.json"));
|
|
47214
|
+
const tokens = readJson4(join47(dir, "tokens.json"));
|
|
46783
47215
|
const accentToken = tokens?.colors?.accentPrimary;
|
|
46784
47216
|
const accentRaw = typeof accentToken === "string" ? accentToken : accentToken?.light;
|
|
46785
47217
|
const accent = typeof accentRaw === "string" && ACCENT.test(accentRaw) ? accentRaw : DEFAULT_ACCENT;
|
|
@@ -46821,10 +47253,10 @@ function inlineImages(dir, plan, budget = REEL_BUDGET_BYTES) {
|
|
|
46821
47253
|
const verified = (f) => {
|
|
46822
47254
|
if (!HISTORY_NAME.test(f)) return null;
|
|
46823
47255
|
try {
|
|
46824
|
-
const path2 =
|
|
47256
|
+
const path2 = join47(dir, HISTORY_DIR, f);
|
|
46825
47257
|
const st = lstatSync7(path2);
|
|
46826
47258
|
if (!st.isFile() || st.nlink !== 1) return null;
|
|
46827
|
-
const bytes2 =
|
|
47259
|
+
const bytes2 = readFileSync54(path2);
|
|
46828
47260
|
return createHash24("sha256").update(bytes2).digest("hex") === f.slice(0, 64) && imageExtension(bytes2) === f.slice(65) ? bytes2 : null;
|
|
46829
47261
|
} catch {
|
|
46830
47262
|
return null;
|
|
@@ -46958,7 +47390,7 @@ var init_studio_reel = __esm({
|
|
|
46958
47390
|
mimeOf = (file) => MIME2[file.slice(65)] ?? "image/png";
|
|
46959
47391
|
readJson4 = (file) => {
|
|
46960
47392
|
try {
|
|
46961
|
-
return JSON.parse(
|
|
47393
|
+
return JSON.parse(readFileSync54(file, "utf8"));
|
|
46962
47394
|
} catch {
|
|
46963
47395
|
return null;
|
|
46964
47396
|
}
|
|
@@ -46989,9 +47421,9 @@ __export(native_decode_exports, {
|
|
|
46989
47421
|
runNativeDecode: () => runNativeDecode
|
|
46990
47422
|
});
|
|
46991
47423
|
import { execFileSync as execFileSync5, spawnSync as spawnSync2 } from "node:child_process";
|
|
46992
|
-
import { existsSync as
|
|
47424
|
+
import { existsSync as existsSync50, mkdtempSync as mkdtempSync2, readFileSync as readFileSync55, rmSync as rmSync11, writeFileSync as writeFileSync20 } from "node:fs";
|
|
46993
47425
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
46994
|
-
import { join as
|
|
47426
|
+
import { join as join48 } from "node:path";
|
|
46995
47427
|
import { fileURLToPath as fileURLToPath20 } from "node:url";
|
|
46996
47428
|
function nativeDecodePackageDir() {
|
|
46997
47429
|
return fileURLToPath20(new URL("../../../core/runtime/ios/HimalayaCore/", import.meta.url));
|
|
@@ -47001,8 +47433,8 @@ function nativeDecodeAndroidHarnessDir() {
|
|
|
47001
47433
|
}
|
|
47002
47434
|
function nativeOracleShipped() {
|
|
47003
47435
|
return {
|
|
47004
|
-
ios:
|
|
47005
|
-
android:
|
|
47436
|
+
ios: existsSync50(join48(nativeDecodePackageDir(), "Package.swift")),
|
|
47437
|
+
android: existsSync50(join48(nativeDecodeAndroidHarnessDir(), "gradlew"))
|
|
47006
47438
|
};
|
|
47007
47439
|
}
|
|
47008
47440
|
function detectNativeDecode(options = {}) {
|
|
@@ -47013,7 +47445,7 @@ function detectNativeDecode(options = {}) {
|
|
|
47013
47445
|
return { platform: "ios", available: false, reason: `the iOS decoder oracle requires macOS (darwin); this host is ${hostPlatform}` };
|
|
47014
47446
|
}
|
|
47015
47447
|
if (!swiftAvailable) return { platform: "ios", available: false, reason: "swift is not on PATH" };
|
|
47016
|
-
const packageAvailable = options.packageAvailable ??
|
|
47448
|
+
const packageAvailable = options.packageAvailable ?? existsSync50(join48(packageDir, "Package.swift"));
|
|
47017
47449
|
if (!packageAvailable) {
|
|
47018
47450
|
return {
|
|
47019
47451
|
platform: "ios",
|
|
@@ -47025,7 +47457,7 @@ function detectNativeDecode(options = {}) {
|
|
|
47025
47457
|
}
|
|
47026
47458
|
function localPropertiesSdk(harnessDir) {
|
|
47027
47459
|
try {
|
|
47028
|
-
const match =
|
|
47460
|
+
const match = readFileSync55(join48(harnessDir, "local.properties"), "utf8").match(/^sdk\.dir\s*=\s*(.+)$/m);
|
|
47029
47461
|
return match?.[1]?.trim().replace(/\\([ :\\])/g, "$1") ?? null;
|
|
47030
47462
|
} catch {
|
|
47031
47463
|
return null;
|
|
@@ -47033,8 +47465,8 @@ function localPropertiesSdk(harnessDir) {
|
|
|
47033
47465
|
}
|
|
47034
47466
|
function detectAndroidNativeDecode(options = {}) {
|
|
47035
47467
|
const harnessDir = options.harnessDir ?? nativeDecodeAndroidHarnessDir();
|
|
47036
|
-
const gradlew =
|
|
47037
|
-
const gradlewAvailable = options.gradlewAvailable ??
|
|
47468
|
+
const gradlew = join48(harnessDir, "gradlew");
|
|
47469
|
+
const gradlewAvailable = options.gradlewAvailable ?? existsSync50(gradlew);
|
|
47038
47470
|
if (!gradlewAvailable) {
|
|
47039
47471
|
return {
|
|
47040
47472
|
platform: "android",
|
|
@@ -47044,7 +47476,7 @@ function detectAndroidNativeDecode(options = {}) {
|
|
|
47044
47476
|
}
|
|
47045
47477
|
const androidHome = options.androidHome ?? process.env.ANDROID_HOME ?? "";
|
|
47046
47478
|
const sdk = androidHome.trim() || (options.localPropertiesSdk !== void 0 ? options.localPropertiesSdk : localPropertiesSdk(harnessDir));
|
|
47047
|
-
const sdkAvailable = options.sdkAvailable ?? (typeof sdk === "string" && sdk.length > 0 &&
|
|
47479
|
+
const sdkAvailable = options.sdkAvailable ?? (typeof sdk === "string" && sdk.length > 0 && existsSync50(sdk));
|
|
47048
47480
|
if (!sdkAvailable) {
|
|
47049
47481
|
return {
|
|
47050
47482
|
platform: "android",
|
|
@@ -47116,14 +47548,14 @@ function parseNativeDecodeOutput(stdout, expectedScreenIds, platform = "ios") {
|
|
|
47116
47548
|
return verdicts;
|
|
47117
47549
|
}
|
|
47118
47550
|
function runNativeDecode(options) {
|
|
47119
|
-
const descriptorDir = mkdtempSync2(
|
|
47551
|
+
const descriptorDir = mkdtempSync2(join48(tmpdir3(), "himi-native-decode-"));
|
|
47120
47552
|
const startedAt = Date.now();
|
|
47121
47553
|
try {
|
|
47122
47554
|
for (const descriptor of options.descriptors) {
|
|
47123
47555
|
if (typeof descriptor.descriptorJson !== "string") {
|
|
47124
47556
|
throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
|
|
47125
47557
|
}
|
|
47126
|
-
writeFileSync20(
|
|
47558
|
+
writeFileSync20(join48(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
|
|
47127
47559
|
}
|
|
47128
47560
|
options.progress?.("building cached Swift oracle");
|
|
47129
47561
|
execFileSync5("swift", ["build", "--package-path", options.packageDir, "--product", "himi-decode-oracle"], {
|
|
@@ -47135,7 +47567,7 @@ function runNativeDecode(options) {
|
|
|
47135
47567
|
encoding: "utf8"
|
|
47136
47568
|
}).trim();
|
|
47137
47569
|
options.progress?.(`running real Swift decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
|
|
47138
|
-
const stdout = execFileSync5(
|
|
47570
|
+
const stdout = execFileSync5(join48(binPath, "himi-decode-oracle"), ["--dir", descriptorDir], {
|
|
47139
47571
|
stdio: ["ignore", "pipe", "pipe"],
|
|
47140
47572
|
encoding: "utf8"
|
|
47141
47573
|
});
|
|
@@ -47153,15 +47585,15 @@ function runNativeDecode(options) {
|
|
|
47153
47585
|
}
|
|
47154
47586
|
}
|
|
47155
47587
|
function runAndroidNativeDecode(options) {
|
|
47156
|
-
const descriptorDir = mkdtempSync2(
|
|
47157
|
-
const outputPath =
|
|
47588
|
+
const descriptorDir = mkdtempSync2(join48(tmpdir3(), "himi-native-decode-android-"));
|
|
47589
|
+
const outputPath = join48(descriptorDir, "verdicts.ndjson");
|
|
47158
47590
|
const startedAt = Date.now();
|
|
47159
47591
|
try {
|
|
47160
47592
|
for (const descriptor of options.descriptors) {
|
|
47161
47593
|
if (typeof descriptor.descriptorJson !== "string") {
|
|
47162
47594
|
throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
|
|
47163
47595
|
}
|
|
47164
|
-
writeFileSync20(
|
|
47596
|
+
writeFileSync20(join48(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
|
|
47165
47597
|
}
|
|
47166
47598
|
options.progress?.(`running real Kotlin decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
|
|
47167
47599
|
execFileSync5(options.gradlew, [
|
|
@@ -47176,7 +47608,7 @@ function runAndroidNativeDecode(options) {
|
|
|
47176
47608
|
stdio: ["ignore", "ignore", "pipe"],
|
|
47177
47609
|
encoding: "utf8"
|
|
47178
47610
|
});
|
|
47179
|
-
const stdout =
|
|
47611
|
+
const stdout = readFileSync55(outputPath, "utf8");
|
|
47180
47612
|
return {
|
|
47181
47613
|
platform: "android",
|
|
47182
47614
|
verdicts: parseNativeDecodeOutput(stdout, options.descriptors.map((descriptor) => descriptor.screenId), "android"),
|
|
@@ -47246,13 +47678,13 @@ __export(browser_authoring_exports, {
|
|
|
47246
47678
|
});
|
|
47247
47679
|
import { createServer as createServer3 } from "node:http";
|
|
47248
47680
|
import { createHash as createHash25, randomBytes as randomBytes4 } from "node:crypto";
|
|
47249
|
-
import { existsSync as
|
|
47250
|
-
import { join as
|
|
47681
|
+
import { existsSync as existsSync51, readdirSync as readdirSync24, readFileSync as readFileSync56, realpathSync as realpathSync5, statSync as statSync12 } from "node:fs";
|
|
47682
|
+
import { join as join49, posix, relative as relative8, sep as sep12 } from "node:path";
|
|
47251
47683
|
function humanMs(ms) {
|
|
47252
47684
|
return ms < 1e3 ? `${ms}ms` : `${Math.round(ms / 1e3)}s`;
|
|
47253
47685
|
}
|
|
47254
47686
|
function collectWorkerSources(tier5SrcDir, bundleName) {
|
|
47255
|
-
const root =
|
|
47687
|
+
const root = join49(tier5SrcDir, bundleName);
|
|
47256
47688
|
const files = {};
|
|
47257
47689
|
const visitedDirs = /* @__PURE__ */ new Set();
|
|
47258
47690
|
const walk2 = (abs, rel) => {
|
|
@@ -47260,16 +47692,16 @@ function collectWorkerSources(tier5SrcDir, bundleName) {
|
|
|
47260
47692
|
if (visitedDirs.has(real)) return;
|
|
47261
47693
|
visitedDirs.add(real);
|
|
47262
47694
|
for (const name of readdirSync24(abs).sort()) {
|
|
47263
|
-
const childAbs =
|
|
47695
|
+
const childAbs = join49(abs, name);
|
|
47264
47696
|
const childRel = posix.join(rel, name);
|
|
47265
47697
|
if (statSync12(childAbs).isDirectory()) {
|
|
47266
47698
|
walk2(childAbs, childRel);
|
|
47267
47699
|
} else if (/\.(ts|tsx|js|mjs|json)$/.test(name)) {
|
|
47268
|
-
files[childRel] =
|
|
47700
|
+
files[childRel] = readFileSync56(childAbs, "utf8");
|
|
47269
47701
|
}
|
|
47270
47702
|
}
|
|
47271
47703
|
};
|
|
47272
|
-
if (!
|
|
47704
|
+
if (!existsSync51(root)) return null;
|
|
47273
47705
|
walk2(root, `/tier5-src/${bundleName}`);
|
|
47274
47706
|
const entry = [`/tier5-src/${bundleName}/index.ts`, `/tier5-src/${bundleName}/index.js`].find((p) => p in files);
|
|
47275
47707
|
if (!entry) return null;
|
|
@@ -47286,20 +47718,20 @@ function collectRelativeSiblings(files, tier5SrcDir) {
|
|
|
47286
47718
|
const spec = m[1];
|
|
47287
47719
|
const virtual = posix.normalize(posix.join(dir, spec));
|
|
47288
47720
|
if (!virtual.startsWith("/tier5-src/")) continue;
|
|
47289
|
-
const onDisk =
|
|
47721
|
+
const onDisk = join49(tier5SrcDir, virtual.slice("/tier5-src/".length));
|
|
47290
47722
|
const candidates = [
|
|
47291
47723
|
onDisk,
|
|
47292
47724
|
`${onDisk}.ts`,
|
|
47293
47725
|
`${onDisk}.js`,
|
|
47294
47726
|
onDisk.replace(/\.js$/, ".ts"),
|
|
47295
|
-
|
|
47296
|
-
|
|
47727
|
+
join49(onDisk, "index.ts"),
|
|
47728
|
+
join49(onDisk, "index.js")
|
|
47297
47729
|
];
|
|
47298
47730
|
for (const abs of candidates) {
|
|
47299
|
-
if (!
|
|
47731
|
+
if (!existsSync51(abs) || statSync12(abs).isDirectory()) continue;
|
|
47300
47732
|
const key2 = `/tier5-src/${relative8(tier5SrcDir, abs).split(sep12).join(posix.sep)}`;
|
|
47301
47733
|
if (key2 in files) break;
|
|
47302
|
-
files[key2] =
|
|
47734
|
+
files[key2] = readFileSync56(abs, "utf8");
|
|
47303
47735
|
queue.push(key2);
|
|
47304
47736
|
break;
|
|
47305
47737
|
}
|
|
@@ -47334,7 +47766,7 @@ function collectSdkModules(files, resolveSubpath) {
|
|
|
47334
47766
|
function sdkSubpathReader(resolve48) {
|
|
47335
47767
|
return (sub) => {
|
|
47336
47768
|
try {
|
|
47337
|
-
return
|
|
47769
|
+
return readFileSync56(resolve48(`@wix/himalaya/${sub}`), "utf8");
|
|
47338
47770
|
} catch {
|
|
47339
47771
|
return null;
|
|
47340
47772
|
}
|
|
@@ -47506,8 +47938,8 @@ __export(coverage_exports, {
|
|
|
47506
47938
|
suppressedNativeKeys: () => suppressedNativeKeys,
|
|
47507
47939
|
trendAndStore: () => trendAndStore
|
|
47508
47940
|
});
|
|
47509
|
-
import { existsSync as
|
|
47510
|
-
import { dirname as dirname26, join as
|
|
47941
|
+
import { existsSync as existsSync52, mkdirSync as mkdirSync24, readFileSync as readFileSync57, writeFileSync as writeFileSync21 } from "node:fs";
|
|
47942
|
+
import { dirname as dirname26, join as join50 } from "node:path";
|
|
47511
47943
|
function suppressedNativeKeys(oracle) {
|
|
47512
47944
|
return [...oracle.ios ? [] : ["native-decode|ios"], ...oracle.android ? [] : ["native-decode|android"]];
|
|
47513
47945
|
}
|
|
@@ -47687,11 +48119,11 @@ function assembleLedger(r, options = {}) {
|
|
|
47687
48119
|
return out;
|
|
47688
48120
|
}
|
|
47689
48121
|
function trendAndStore(dir, entries, suppressed) {
|
|
47690
|
-
const p =
|
|
48122
|
+
const p = join50(dir, LEDGER_FILE);
|
|
47691
48123
|
let previous = null;
|
|
47692
48124
|
try {
|
|
47693
|
-
if (
|
|
47694
|
-
const parsed = JSON.parse(
|
|
48125
|
+
if (existsSync52(p)) {
|
|
48126
|
+
const parsed = JSON.parse(readFileSync57(p, "utf8"));
|
|
47695
48127
|
if (Array.isArray(parsed.keys)) previous = parsed.keys.filter((k) => typeof k === "string");
|
|
47696
48128
|
}
|
|
47697
48129
|
} catch {
|
|
@@ -47730,11 +48162,11 @@ function formatLedger(entries, trend) {
|
|
|
47730
48162
|
return out.join("\n");
|
|
47731
48163
|
}
|
|
47732
48164
|
function diffAndStoreObservations(dir, current) {
|
|
47733
|
-
const p =
|
|
48165
|
+
const p = join50(dir, OBS_FILE);
|
|
47734
48166
|
let previous = null;
|
|
47735
48167
|
try {
|
|
47736
|
-
if (
|
|
47737
|
-
const parsed = JSON.parse(
|
|
48168
|
+
if (existsSync52(p)) {
|
|
48169
|
+
const parsed = JSON.parse(readFileSync57(p, "utf8"));
|
|
47738
48170
|
if (parsed.screens && typeof parsed.screens === "object" && !Array.isArray(parsed.screens) && Object.values(parsed.screens).every(
|
|
47739
48171
|
(v) => Array.isArray(v) && v.every((l) => typeof l === "string")
|
|
47740
48172
|
)) {
|
|
@@ -47783,8 +48215,8 @@ var LEDGER_FILE, OBS_FILE;
|
|
|
47783
48215
|
var init_coverage = __esm({
|
|
47784
48216
|
"src/coverage.ts"() {
|
|
47785
48217
|
init_native_decode();
|
|
47786
|
-
LEDGER_FILE =
|
|
47787
|
-
OBS_FILE =
|
|
48218
|
+
LEDGER_FILE = join50(".himi", "test-ledger.json");
|
|
48219
|
+
OBS_FILE = join50(".himi", "test-observations.json");
|
|
47788
48220
|
}
|
|
47789
48221
|
});
|
|
47790
48222
|
|
|
@@ -47795,11 +48227,11 @@ __export(design_kits_exports, {
|
|
|
47795
48227
|
kitsDir: () => kitsDir,
|
|
47796
48228
|
listKits: () => listKits2
|
|
47797
48229
|
});
|
|
47798
|
-
import { existsSync as
|
|
47799
|
-
import { join as
|
|
48230
|
+
import { existsSync as existsSync53, readFileSync as readFileSync58, readdirSync as readdirSync25 } from "node:fs";
|
|
48231
|
+
import { join as join51, basename as basename12 } from "node:path";
|
|
47800
48232
|
import { fileURLToPath as fileURLToPath21 } from "node:url";
|
|
47801
48233
|
function kitsDir() {
|
|
47802
|
-
return KIT_DIR_CANDIDATES.find((p) =>
|
|
48234
|
+
return KIT_DIR_CANDIDATES.find((p) => existsSync53(p));
|
|
47803
48235
|
}
|
|
47804
48236
|
function listKits2() {
|
|
47805
48237
|
const dir = kitsDir();
|
|
@@ -47823,7 +48255,7 @@ In a published @wix/himalaya-cli this is a packaging bug \u2014 the kits should
|
|
|
47823
48255
|
if (!kits.includes(name)) {
|
|
47824
48256
|
return { ok: false, kit: name, kits, problems: [`no design kit named "${name}". Available: ${kits.join(", ")}`] };
|
|
47825
48257
|
}
|
|
47826
|
-
const raw =
|
|
48258
|
+
const raw = readFileSync58(join51(dir, `${name}.json`), "utf8");
|
|
47827
48259
|
let parsed;
|
|
47828
48260
|
try {
|
|
47829
48261
|
parsed = JSON.parse(raw);
|
|
@@ -47847,9 +48279,9 @@ var init_design_kits = __esm({
|
|
|
47847
48279
|
"src/design-kits.ts"() {
|
|
47848
48280
|
KIT_DIR_CANDIDATES = [
|
|
47849
48281
|
// in-repo: tools/himi-cli/src/design-kits.ts → <repo>/stdlib/design-kits/
|
|
47850
|
-
|
|
48282
|
+
join51(fileURLToPath21(new URL("../../..", import.meta.url)), "stdlib", "design-kits"),
|
|
47851
48283
|
// published CLI: <pkg>/dist/cli.mjs → <pkg>/stdlib/design-kits/
|
|
47852
|
-
|
|
48284
|
+
join51(fileURLToPath21(new URL("..", import.meta.url)), "stdlib", "design-kits")
|
|
47853
48285
|
];
|
|
47854
48286
|
}
|
|
47855
48287
|
});
|
|
@@ -47863,11 +48295,11 @@ __export(assets_exports, {
|
|
|
47863
48295
|
removeAssetPayload: () => removeAssetPayload,
|
|
47864
48296
|
verifyReport: () => verifyReport
|
|
47865
48297
|
});
|
|
47866
|
-
import { readFileSync as
|
|
48298
|
+
import { readFileSync as readFileSync59 } from "node:fs";
|
|
47867
48299
|
import { basename as basename13 } from "node:path";
|
|
47868
48300
|
function declaredAssets(dir) {
|
|
47869
48301
|
return collectAssets(dir).map((a) => {
|
|
47870
|
-
const bytes2 =
|
|
48302
|
+
const bytes2 = readFileSync59(a.path);
|
|
47871
48303
|
return {
|
|
47872
48304
|
name: a.name,
|
|
47873
48305
|
sha256: assetSha256(bytes2),
|
|
@@ -47944,7 +48376,7 @@ function verifyReport(dir, app, manifest) {
|
|
|
47944
48376
|
};
|
|
47945
48377
|
}
|
|
47946
48378
|
function addAssetPayload(manifest, filePath, opts) {
|
|
47947
|
-
const bytes2 =
|
|
48379
|
+
const bytes2 = readFileSync59(filePath);
|
|
47948
48380
|
const name = opts.name ?? basename13(filePath);
|
|
47949
48381
|
const sha2565 = assetSha256(bytes2);
|
|
47950
48382
|
const record2 = {
|
|
@@ -49340,8 +49772,7 @@ async function localizeConfigResponse(res, kind, header) {
|
|
|
49340
49772
|
}
|
|
49341
49773
|
function makeRunHandler(opts) {
|
|
49342
49774
|
const mount = opts.chrome === "app" ? "/app" : "/preview";
|
|
49343
|
-
const
|
|
49344
|
-
store: opts.store,
|
|
49775
|
+
const serveOpts = {
|
|
49345
49776
|
defaultApp: opts.app,
|
|
49346
49777
|
// A local plane is a pin: nothing mutates, and the owner rungs cannot work anyway — a service
|
|
49347
49778
|
// worker never sees a `Cookie` header (it is a forbidden request header in both directions), so
|
|
@@ -49356,7 +49787,9 @@ function makeRunHandler(opts) {
|
|
|
49356
49787
|
webwixBridge: Boolean(opts.serve?.webwixFetch),
|
|
49357
49788
|
manifestCacheTtlMs: 0,
|
|
49358
49789
|
...opts.serve
|
|
49359
|
-
}
|
|
49790
|
+
};
|
|
49791
|
+
const serve = makeServeHandler({ store: opts.store, ...serveOpts });
|
|
49792
|
+
const ownerRungOn = serveOpts.webwixOwnerRung !== false;
|
|
49360
49793
|
return async (request) => {
|
|
49361
49794
|
const url = new URL(request.url);
|
|
49362
49795
|
const path2 = url.pathname;
|
|
@@ -49377,6 +49810,10 @@ function makeRunHandler(opts) {
|
|
|
49377
49810
|
if (path2.startsWith("/v1/flags/")) {
|
|
49378
49811
|
return json4(200, { app: opts.app, definitions: {} }, { "cache-control": "no-store" });
|
|
49379
49812
|
}
|
|
49813
|
+
if (path2 === "/v1/owner/sites" && !ownerRungOn && (request.method === "GET" || request.method === "HEAD")) {
|
|
49814
|
+
const headers2 = { "cache-control": "no-store" };
|
|
49815
|
+
return request.method === "HEAD" ? new Response(null, { status: 200, headers: { "content-type": "application/json; charset=utf-8", ...headers2 } }) : json4(200, { sites: [] }, headers2);
|
|
49816
|
+
}
|
|
49380
49817
|
if (path2 === "/v1/telemetry/ingest") {
|
|
49381
49818
|
if (request.method !== "POST") return json4(405, { error: "method_not_allowed" });
|
|
49382
49819
|
try {
|
|
@@ -49579,21 +50016,21 @@ var init_preview_assets_generated = __esm({
|
|
|
49579
50016
|
"../../packages/serve/src/preview-assets.generated.ts"() {
|
|
49580
50017
|
init_preview_assets_format();
|
|
49581
50018
|
PREVIEW_ASSET_MANIFEST = [
|
|
49582
|
-
{ key: "assets/index-
|
|
49583
|
-
{ key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset:
|
|
49584
|
-
{ key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset:
|
|
49585
|
-
{ key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset:
|
|
49586
|
-
{ key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset:
|
|
49587
|
-
{ key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset:
|
|
49588
|
-
{ key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset:
|
|
49589
|
-
{ key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset:
|
|
49590
|
-
{ key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset:
|
|
49591
|
-
{ key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset:
|
|
49592
|
-
{ key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset:
|
|
49593
|
-
{ key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset:
|
|
49594
|
-
{ key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset:
|
|
49595
|
-
{ key: "index.html", contentType: "text/html; charset=utf-8", offset:
|
|
49596
|
-
{ key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset:
|
|
50019
|
+
{ key: "assets/index-BJFiKWYO.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1051133, sha256: "99b754e0231cb82ad2cafbca64ba3cd3bdc74aa53d8351f6a57828034c3a3f44" },
|
|
50020
|
+
{ key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 1051141, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
|
|
50021
|
+
{ key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 1055751, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
|
|
50022
|
+
{ key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1544335, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
|
|
50023
|
+
{ key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1635259, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
|
|
50024
|
+
{ key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1726243, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
|
|
50025
|
+
{ key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1817223, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
|
|
50026
|
+
{ key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1908095, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
|
|
50027
|
+
{ key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1999075, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
|
|
50028
|
+
{ key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 2107711, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
|
|
50029
|
+
{ key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 2216795, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
|
|
50030
|
+
{ key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 2325843, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
|
|
50031
|
+
{ key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 2433543, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
|
|
50032
|
+
{ key: "index.html", contentType: "text/html; charset=utf-8", offset: 2521651, length: 4947, sha256: "1c4dfb3d465449d6a73677293df29d93b1c236b46602b553a58ef6e89c52de11" },
|
|
50033
|
+
{ key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 2526598, length: 17209, sha256: "dffc9718e2faa63ae2cc919e0a842f585ed565aaaa7c53778e90379442c731b6" }
|
|
49597
50034
|
];
|
|
49598
50035
|
}
|
|
49599
50036
|
});
|
|
@@ -49609,9 +50046,9 @@ __export(run_exports, {
|
|
|
49609
50046
|
runPackage: () => runPackage,
|
|
49610
50047
|
withoutProdServe: () => withoutProdServe
|
|
49611
50048
|
});
|
|
49612
|
-
import { cpSync as cpSync2, existsSync as
|
|
50049
|
+
import { cpSync as cpSync2, existsSync as existsSync54, mkdirSync as mkdirSync25, mkdtempSync as mkdtempSync3, readFileSync as readFileSync60, rmSync as rmSync12, statSync as statSync13 } from "node:fs";
|
|
49613
50050
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
49614
|
-
import { dirname as dirname27, join as
|
|
50051
|
+
import { dirname as dirname27, join as join52 } from "node:path";
|
|
49615
50052
|
import { fileURLToPath as fileURLToPath22 } from "node:url";
|
|
49616
50053
|
function makePackageRunHandler(opts) {
|
|
49617
50054
|
const store = new FileReleaseStore(opts.releaseRoot);
|
|
@@ -49639,9 +50076,9 @@ async function fetchBytes(url) {
|
|
|
49639
50076
|
}
|
|
49640
50077
|
async function resolvePackage(source, workDir) {
|
|
49641
50078
|
const isUrl2 = /^https?:\/\//i.test(source);
|
|
49642
|
-
if (!isUrl2 &&
|
|
49643
|
-
const appDirManifest =
|
|
49644
|
-
if (
|
|
50079
|
+
if (!isUrl2 && existsSync54(source) && statSync13(source).isDirectory()) {
|
|
50080
|
+
const appDirManifest = join52(source, "release-manifest.json");
|
|
50081
|
+
if (existsSync54(appDirManifest)) {
|
|
49645
50082
|
const opened2 = openPackageDir(source);
|
|
49646
50083
|
if (!opened2.validation.ok) {
|
|
49647
50084
|
throw new Error(`package is not valid:
|
|
@@ -49650,9 +50087,9 @@ async function resolvePackage(source, workDir) {
|
|
|
49650
50087
|
const app2 = opened2.header?.app ?? opened2.manifest?.app;
|
|
49651
50088
|
if (!app2) throw new Error(`${source} has no app id (no himi-package.json and no manifest.app)`);
|
|
49652
50089
|
if (!isSafeAppId(app2)) throw new Error(`${source} declares an unsafe app id ${JSON.stringify(app2)} \u2014 refusing to open it`);
|
|
49653
|
-
const root2 = workDir ?? mkdtempSync3(
|
|
49654
|
-
const target =
|
|
49655
|
-
if (
|
|
50090
|
+
const root2 = workDir ?? mkdtempSync3(join52(tmpdir4(), "himi-run-"));
|
|
50091
|
+
const target = join52(root2, app2);
|
|
50092
|
+
if (join52(source) !== target) {
|
|
49656
50093
|
mkdirSync25(root2, { recursive: true });
|
|
49657
50094
|
rmSync12(target, { recursive: true, force: true });
|
|
49658
50095
|
cpSync2(source, target, { recursive: true });
|
|
@@ -49669,8 +50106,8 @@ async function resolvePackage(source, workDir) {
|
|
|
49669
50106
|
}
|
|
49670
50107
|
throw new Error(`${source} is a directory but has no release-manifest.json \u2014 is it a package?`);
|
|
49671
50108
|
}
|
|
49672
|
-
const bytes2 = isUrl2 ? await fetchBytes(source) :
|
|
49673
|
-
const root = workDir ?? mkdtempSync3(
|
|
50109
|
+
const bytes2 = isUrl2 ? await fetchBytes(source) : readFileSync60(source);
|
|
50110
|
+
const root = workDir ?? mkdtempSync3(join52(tmpdir4(), "himi-run-"));
|
|
49674
50111
|
const { app, appDir: appDir2 } = unpackTo(bytes2, root);
|
|
49675
50112
|
const opened = openPackageDir(appDir2);
|
|
49676
50113
|
if (!opened.validation.ok) {
|
|
@@ -49693,14 +50130,14 @@ async function loadPreviewAssets() {
|
|
|
49693
50130
|
const mod = await Promise.resolve().then(() => (init_preview_assets_generated(), preview_assets_generated_exports));
|
|
49694
50131
|
const here = dirname27(fileURLToPath22(import.meta.url));
|
|
49695
50132
|
const candidates = [
|
|
49696
|
-
|
|
50133
|
+
join52(here, "preview-assets.generated.bin"),
|
|
49697
50134
|
// published: copied next to the bundled CLI
|
|
49698
|
-
|
|
50135
|
+
join52(here, "../../../packages/serve/src/preview-assets.generated.bin")
|
|
49699
50136
|
// in-repo checkout
|
|
49700
50137
|
];
|
|
49701
50138
|
for (const path2 of candidates) {
|
|
49702
|
-
if (!
|
|
49703
|
-
const blob =
|
|
50139
|
+
if (!existsSync54(path2)) continue;
|
|
50140
|
+
const blob = readFileSync60(path2);
|
|
49704
50141
|
return mod.assemblePreviewAssetsFromBlob(new Uint8Array(blob.buffer, blob.byteOffset, blob.byteLength));
|
|
49705
50142
|
}
|
|
49706
50143
|
return /* @__PURE__ */ new Map();
|
|
@@ -49797,9 +50234,9 @@ __export(run_watch_exports, {
|
|
|
49797
50234
|
watchedContentDir: () => watchedContentDir,
|
|
49798
50235
|
writeRunRecord: () => writeRunRecord
|
|
49799
50236
|
});
|
|
49800
|
-
import { closeSync as closeSync2, constants, existsSync as
|
|
50237
|
+
import { closeSync as closeSync2, constants, existsSync as existsSync55, fstatSync, lstatSync as lstatSync8, statSync as statSync14, mkdirSync as mkdirSync26, openSync as openSync2, readFileSync as readFileSync61, realpathSync as realpathSync6, renameSync as renameSync5, rmSync as rmSync13, writeFileSync as writeFileSync22, watch as fsWatch } from "node:fs";
|
|
49801
50238
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
49802
|
-
import { extname as extname4, join as
|
|
50239
|
+
import { extname as extname4, join as join53, resolve as resolve42, sep as sep13 } from "node:path";
|
|
49803
50240
|
function diffReleases(prev, next) {
|
|
49804
50241
|
const bundles = Object.keys(next.bundles).filter((b) => prev.bundles[b]?.sha256 !== next.bundles[b].sha256).sort();
|
|
49805
50242
|
const changedBundles = new Set(bundles);
|
|
@@ -49839,7 +50276,7 @@ function watchContent(dir, onChange, opts = {}) {
|
|
|
49839
50276
|
let timer = null;
|
|
49840
50277
|
const pending = /* @__PURE__ */ new Set();
|
|
49841
50278
|
const watcher2 = watch2(dir, { recursive: true }, (_event, file) => {
|
|
49842
|
-
if (!file || ignoredChange(file, (rel) => isDir(
|
|
50279
|
+
if (!file || ignoredChange(file, (rel) => isDir(join53(dir, rel)))) return;
|
|
49843
50280
|
pending.add(file);
|
|
49844
50281
|
if (timer) clearTimeout(timer);
|
|
49845
50282
|
timer = setTimeout(() => {
|
|
@@ -49860,7 +50297,7 @@ function watchedContentDir(source) {
|
|
|
49860
50297
|
if (!source || /^https?:\/\//i.test(source)) return null;
|
|
49861
50298
|
const dir = resolve42(source);
|
|
49862
50299
|
try {
|
|
49863
|
-
return statSync14(dir).isDirectory() &&
|
|
50300
|
+
return statSync14(dir).isDirectory() && existsSync55(join53(dir, "himalaya.content.json")) ? dir : null;
|
|
49864
50301
|
} catch {
|
|
49865
50302
|
return null;
|
|
49866
50303
|
}
|
|
@@ -49917,7 +50354,7 @@ function serialize(task) {
|
|
|
49917
50354
|
});
|
|
49918
50355
|
}
|
|
49919
50356
|
function himiDir(dir) {
|
|
49920
|
-
const root =
|
|
50357
|
+
const root = join53(dir, ".himi");
|
|
49921
50358
|
try {
|
|
49922
50359
|
return lstatSync8(root).isDirectory() ? root : null;
|
|
49923
50360
|
} catch (e) {
|
|
@@ -49929,11 +50366,11 @@ function himiDir(dir) {
|
|
|
49929
50366
|
function writeRunRecord(dir, record2) {
|
|
49930
50367
|
const root = himiDir(dir);
|
|
49931
50368
|
if (!root) return false;
|
|
49932
|
-
const tmp =
|
|
50369
|
+
const tmp = join53(root, `.run.json.${process.pid}.${randomUUID3()}.tmp`);
|
|
49933
50370
|
try {
|
|
49934
50371
|
writeFileSync22(tmp, `${JSON.stringify(record2, null, 2)}
|
|
49935
50372
|
`, { flag: "wx" });
|
|
49936
|
-
renameSync5(tmp,
|
|
50373
|
+
renameSync5(tmp, join53(root, "run.json"));
|
|
49937
50374
|
} catch (e) {
|
|
49938
50375
|
rmSync13(tmp, { force: true });
|
|
49939
50376
|
throw e;
|
|
@@ -49941,7 +50378,7 @@ function writeRunRecord(dir, record2) {
|
|
|
49941
50378
|
return true;
|
|
49942
50379
|
}
|
|
49943
50380
|
function removeRunRecord(dir, owner) {
|
|
49944
|
-
const root =
|
|
50381
|
+
const root = join53(dir, ".himi");
|
|
49945
50382
|
try {
|
|
49946
50383
|
if (!lstatSync8(root).isDirectory()) return;
|
|
49947
50384
|
} catch {
|
|
@@ -49956,16 +50393,16 @@ function removeRunRecord(dir, owner) {
|
|
|
49956
50393
|
}
|
|
49957
50394
|
if (typeof pid === "number" && pid !== owner) return;
|
|
49958
50395
|
}
|
|
49959
|
-
rmSync13(
|
|
50396
|
+
rmSync13(join53(root, "run.json"), { force: true });
|
|
49960
50397
|
}
|
|
49961
50398
|
function boardFile(dir, pathname) {
|
|
49962
50399
|
let rel = null;
|
|
49963
|
-
if (pathname === "/__himi/studio/" || pathname === "/__himi/studio/index.html") rel =
|
|
49964
|
-
else if (pathname === "/__himi/studio/state.js") rel =
|
|
49965
|
-
else if (pathname === "/__himi/studio/timeline.js") rel =
|
|
50400
|
+
if (pathname === "/__himi/studio/" || pathname === "/__himi/studio/index.html") rel = join53("studio", "index.html");
|
|
50401
|
+
else if (pathname === "/__himi/studio/state.js") rel = join53("studio", "state.js");
|
|
50402
|
+
else if (pathname === "/__himi/studio/timeline.js") rel = join53("studio", "timeline.js");
|
|
49966
50403
|
else {
|
|
49967
50404
|
const m = /^\/__himi\/history\/([0-9a-f]{64}\.(png|jpg|gif|webp))$/.exec(pathname);
|
|
49968
|
-
if (m) rel =
|
|
50405
|
+
if (m) rel = join53("history", m[1]);
|
|
49969
50406
|
}
|
|
49970
50407
|
if (!rel) return null;
|
|
49971
50408
|
const bytes2 = readConfined(resolve42(dir, ".himi"), rel);
|
|
@@ -49981,7 +50418,7 @@ function readConfined(root, rel) {
|
|
|
49981
50418
|
const parts = rel.split(sep13);
|
|
49982
50419
|
let at = root;
|
|
49983
50420
|
for (let i = 0; i < parts.length; i++) {
|
|
49984
|
-
at =
|
|
50421
|
+
at = join53(at, parts[i]);
|
|
49985
50422
|
const st = lstatSync8(at);
|
|
49986
50423
|
if (st.isSymbolicLink() || !(i === parts.length - 1 ? st.isFile() : st.isDirectory())) return null;
|
|
49987
50424
|
}
|
|
@@ -49990,7 +50427,7 @@ function readConfined(root, rel) {
|
|
|
49990
50427
|
const fd = openSync2(at, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
49991
50428
|
try {
|
|
49992
50429
|
if (!fstatSync(fd).isFile()) return null;
|
|
49993
|
-
return
|
|
50430
|
+
return readFileSync61(fd);
|
|
49994
50431
|
} finally {
|
|
49995
50432
|
closeSync2(fd);
|
|
49996
50433
|
}
|
|
@@ -50041,7 +50478,7 @@ __export(run_browser_exports, {
|
|
|
50041
50478
|
runInBrowser: () => runInBrowser
|
|
50042
50479
|
});
|
|
50043
50480
|
import { createServer as createServer5 } from "node:http";
|
|
50044
|
-
import { existsSync as
|
|
50481
|
+
import { existsSync as existsSync56, readFileSync as readFileSync62 } from "node:fs";
|
|
50045
50482
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
50046
50483
|
import { dirname as dirname28, resolve as resolve43 } from "node:path";
|
|
50047
50484
|
import { fileURLToPath as fileURLToPath23 } from "node:url";
|
|
@@ -50049,7 +50486,7 @@ function stagedDir() {
|
|
|
50049
50486
|
return process.env.HIMI_BROWSER_PLANE_OUT ? resolve43(process.env.HIMI_BROWSER_PLANE_OUT) : resolve43(REPO, "packages", "serve", "dist", "browser-plane");
|
|
50050
50487
|
}
|
|
50051
50488
|
function missingStaged() {
|
|
50052
|
-
return [...SERVED].filter((f) => !
|
|
50489
|
+
return [...SERVED].filter((f) => !existsSync56(resolve43(stagedDir(), f))).sort();
|
|
50053
50490
|
}
|
|
50054
50491
|
function ensureBrowserPlaneStaged() {
|
|
50055
50492
|
if (missingStaged().length === 0) return { ok: true, detail: "already staged" };
|
|
@@ -50134,7 +50571,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
|
|
|
50134
50571
|
}
|
|
50135
50572
|
const name = path2 === "/" || path2 === "/index.html" ? "host.html" : path2.slice(1);
|
|
50136
50573
|
if (SERVED.has(name)) {
|
|
50137
|
-
if (!
|
|
50574
|
+
if (!existsSync56(resolve43(stagedDir(), name))) {
|
|
50138
50575
|
const restaged = ensureBrowserPlaneStaged();
|
|
50139
50576
|
if (!restaged.ok) {
|
|
50140
50577
|
res.writeHead(503, { "content-type": "application/json" });
|
|
@@ -50144,7 +50581,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
|
|
|
50144
50581
|
}
|
|
50145
50582
|
let bytes2;
|
|
50146
50583
|
try {
|
|
50147
|
-
bytes2 =
|
|
50584
|
+
bytes2 = readFileSync62(resolve43(stagedDir(), name));
|
|
50148
50585
|
} catch (e) {
|
|
50149
50586
|
res.writeHead(503, { "content-type": "application/json" });
|
|
50150
50587
|
res.end(JSON.stringify({ error: "browser_plane_unstaged", file: name, detail: String(e) }));
|
|
@@ -50605,7 +51042,7 @@ __export(preflight_exports, {
|
|
|
50605
51042
|
parseStoreConfig: () => parseStoreConfig,
|
|
50606
51043
|
requireEnv: () => requireEnv
|
|
50607
51044
|
});
|
|
50608
|
-
import { existsSync as
|
|
51045
|
+
import { existsSync as existsSync57, readFileSync as readFileSync63 } from "node:fs";
|
|
50609
51046
|
import { isAbsolute as isAbsolute3, relative as relative9, resolve as resolve44 } from "node:path";
|
|
50610
51047
|
function isInsideRepo(p) {
|
|
50611
51048
|
const rel = relative9(REPO_ROOT3, resolve44(p));
|
|
@@ -50662,10 +51099,10 @@ function parseStoreConfig(text5) {
|
|
|
50662
51099
|
}
|
|
50663
51100
|
function loadStoreConfig(app) {
|
|
50664
51101
|
const p = storeConfigPath(app);
|
|
50665
|
-
if (!
|
|
51102
|
+
if (!existsSync57(p)) {
|
|
50666
51103
|
throw new Error(`No store config at ${p}. Create apps/${app}/store/store.config.yaml first (see /setup-store-signing).`);
|
|
50667
51104
|
}
|
|
50668
|
-
return parseStoreConfig(
|
|
51105
|
+
return parseStoreConfig(readFileSync63(p, "utf8"));
|
|
50669
51106
|
}
|
|
50670
51107
|
var init_preflight = __esm({
|
|
50671
51108
|
"../store-release/preflight.ts"() {
|
|
@@ -50684,19 +51121,19 @@ __export(credential_profile_exports, {
|
|
|
50684
51121
|
profilePath: () => profilePath,
|
|
50685
51122
|
resolveStoreCredentials: () => resolveStoreCredentials
|
|
50686
51123
|
});
|
|
50687
|
-
import { existsSync as
|
|
51124
|
+
import { existsSync as existsSync58, readFileSync as readFileSync64 } from "node:fs";
|
|
50688
51125
|
import { homedir as homedir5 } from "node:os";
|
|
50689
|
-
import { join as
|
|
51126
|
+
import { join as join54 } from "node:path";
|
|
50690
51127
|
function credentialsDir(home = homedir5()) {
|
|
50691
|
-
return
|
|
51128
|
+
return join54(home, ".himalaya", "store-credentials");
|
|
50692
51129
|
}
|
|
50693
51130
|
function profilePath(name, home = homedir5()) {
|
|
50694
51131
|
if (!PROFILE_NAME.test(name)) {
|
|
50695
51132
|
throw new Error(
|
|
50696
|
-
`credential profile ${JSON.stringify(name)} is not a profile name \u2014 use letters, digits, ".", "_" or "-" starting with a letter or digit. It names ${
|
|
51133
|
+
`credential profile ${JSON.stringify(name)} is not a profile name \u2014 use letters, digits, ".", "_" or "-" starting with a letter or digit. It names ${join54(credentialsDir(home), "<name>.json")}; it is never a path.`
|
|
50697
51134
|
);
|
|
50698
51135
|
}
|
|
50699
|
-
return
|
|
51136
|
+
return join54(credentialsDir(home), `${name}.json`);
|
|
50700
51137
|
}
|
|
50701
51138
|
function parseProfile(text5, label2) {
|
|
50702
51139
|
let doc;
|
|
@@ -50727,8 +51164,8 @@ function resolveStoreCredentials(opts) {
|
|
|
50727
51164
|
const { app, cfg } = opts;
|
|
50728
51165
|
const env = opts.env ?? process.env;
|
|
50729
51166
|
const home = opts.home ?? homedir5();
|
|
50730
|
-
const read = opts.readProfile ?? ((p) =>
|
|
50731
|
-
const exists = opts.profileExists ??
|
|
51167
|
+
const read = opts.readProfile ?? ((p) => readFileSync64(p, "utf8"));
|
|
51168
|
+
const exists = opts.profileExists ?? existsSync58;
|
|
50732
51169
|
const ios = cfg.ios ?? {};
|
|
50733
51170
|
const flagName = opts.profileFlag?.trim();
|
|
50734
51171
|
const named = namedProfile(cfg, opts.profileFlag);
|
|
@@ -50808,9 +51245,9 @@ __export(preflight_app_exports, {
|
|
|
50808
51245
|
preflightApp: () => preflightApp,
|
|
50809
51246
|
profileAccount: () => profileAccount
|
|
50810
51247
|
});
|
|
50811
|
-
import { readFileSync as
|
|
51248
|
+
import { readFileSync as readFileSync65, existsSync as existsSync59, readdirSync as readdirSync26, statSync as statSync15 } from "node:fs";
|
|
50812
51249
|
import { createHash as createHash26 } from "node:crypto";
|
|
50813
|
-
import { join as
|
|
51250
|
+
import { join as join55 } from "node:path";
|
|
50814
51251
|
function analyze(projectYml, storeConfig, icon, account) {
|
|
50815
51252
|
const f = [];
|
|
50816
51253
|
const has = (re, s) => re.test(s);
|
|
@@ -50874,13 +51311,13 @@ function profileAccount(app, storeConfig, opts = {}) {
|
|
|
50874
51311
|
}
|
|
50875
51312
|
}
|
|
50876
51313
|
async function preflightApp(app, opts = {}) {
|
|
50877
|
-
const projectYml =
|
|
50878
|
-
const storeConfig =
|
|
51314
|
+
const projectYml = existsSync59(iosProjectYml(app)) ? readFileSync65(iosProjectYml(app), "utf8") : "";
|
|
51315
|
+
const storeConfig = existsSync59(storeConfigPath(app)) ? readFileSync65(storeConfigPath(app), "utf8") : "";
|
|
50879
51316
|
if (!storeConfig) return [{ level: "error", message: `no apps/${app}/store/store.config.yaml \u2014 run /setup-store-signing first.` }];
|
|
50880
51317
|
const findings = analyze(
|
|
50881
51318
|
projectYml,
|
|
50882
51319
|
storeConfig,
|
|
50883
|
-
await appIconState(
|
|
51320
|
+
await appIconState(join55(appDir(app), "ios")),
|
|
50884
51321
|
profileAccount(app, storeConfig, opts)
|
|
50885
51322
|
);
|
|
50886
51323
|
findings.push(...analyzeListing(metadataFilesPresent(app), listScreenshots(app)));
|
|
@@ -50909,17 +51346,17 @@ function analyzeSubmissionRecord(appLevel, review, opts) {
|
|
|
50909
51346
|
return f;
|
|
50910
51347
|
}
|
|
50911
51348
|
function appLevelMetadataFiles(app, locale = "en-US") {
|
|
50912
|
-
const root =
|
|
51349
|
+
const root = join55(storeDir(app), "metadata");
|
|
50913
51350
|
const out = /* @__PURE__ */ new Set();
|
|
50914
|
-
if (
|
|
51351
|
+
if (existsSync59(root)) {
|
|
50915
51352
|
for (const n of readdirSync26(root)) if (n.endsWith(".txt")) out.add(n);
|
|
50916
51353
|
}
|
|
50917
|
-
if (
|
|
51354
|
+
if (existsSync59(join55(root, locale, "privacy_url.txt"))) out.add("privacy_url.txt");
|
|
50918
51355
|
return out;
|
|
50919
51356
|
}
|
|
50920
51357
|
function reviewInfoFiles(app) {
|
|
50921
|
-
const dir =
|
|
50922
|
-
if (!
|
|
51358
|
+
const dir = join55(storeDir(app), "review_information");
|
|
51359
|
+
if (!existsSync59(dir)) return /* @__PURE__ */ new Set();
|
|
50923
51360
|
return new Set(readdirSync26(dir).filter((n) => n.endsWith(".txt")));
|
|
50924
51361
|
}
|
|
50925
51362
|
function isValidAppStoreSize(w, h) {
|
|
@@ -51029,12 +51466,12 @@ function analyzePlayListing(assets) {
|
|
|
51029
51466
|
return f;
|
|
51030
51467
|
}
|
|
51031
51468
|
function playListingAssets(app, locale = "en-US") {
|
|
51032
|
-
const dir =
|
|
51469
|
+
const dir = join55(storeDir(app), "play", locale, "images");
|
|
51033
51470
|
const read = (names) => {
|
|
51034
51471
|
for (const name of names) {
|
|
51035
|
-
const p =
|
|
51472
|
+
const p = join55(dir, name);
|
|
51036
51473
|
try {
|
|
51037
|
-
if (statSync15(p).isFile()) return { name, bytes:
|
|
51474
|
+
if (statSync15(p).isFile()) return { name, bytes: readFileSync65(p) };
|
|
51038
51475
|
} catch {
|
|
51039
51476
|
}
|
|
51040
51477
|
}
|
|
@@ -51065,26 +51502,26 @@ function analyzeListing(metaFiles, shots) {
|
|
|
51065
51502
|
return f;
|
|
51066
51503
|
}
|
|
51067
51504
|
function metadataFilesPresent(app, locale = "en-US") {
|
|
51068
|
-
const dir =
|
|
51069
|
-
if (!
|
|
51505
|
+
const dir = join55(storeDir(app), "metadata", locale);
|
|
51506
|
+
if (!existsSync59(dir)) return /* @__PURE__ */ new Set();
|
|
51070
51507
|
return new Set(readdirSync26(dir).filter((n) => n.endsWith(".txt")));
|
|
51071
51508
|
}
|
|
51072
51509
|
function listScreenshots(app, locale = "en-US") {
|
|
51073
51510
|
const out = [];
|
|
51074
|
-
const flat =
|
|
51075
|
-
if (
|
|
51511
|
+
const flat = join55(storeDir(app), "screenshots", locale);
|
|
51512
|
+
if (existsSync59(flat)) {
|
|
51076
51513
|
for (const png of readdirSync26(flat).filter((n) => n.endsWith(".png"))) {
|
|
51077
|
-
const sz = pngSize(
|
|
51514
|
+
const sz = pngSize(readFileSync65(join55(flat, png)));
|
|
51078
51515
|
if (sz) out.push({ name: png, w: sz.w, h: sz.h });
|
|
51079
51516
|
}
|
|
51080
51517
|
}
|
|
51081
|
-
const legacy =
|
|
51082
|
-
if (
|
|
51518
|
+
const legacy = join55(storeDir(app), "metadata", locale, "screenshots");
|
|
51519
|
+
if (existsSync59(legacy)) {
|
|
51083
51520
|
for (const deviceDir of readdirSync26(legacy)) {
|
|
51084
|
-
const d =
|
|
51521
|
+
const d = join55(legacy, deviceDir);
|
|
51085
51522
|
if (!statSync15(d).isDirectory()) continue;
|
|
51086
51523
|
for (const png of readdirSync26(d).filter((n) => n.endsWith(".png"))) {
|
|
51087
|
-
const sz = pngSize(
|
|
51524
|
+
const sz = pngSize(readFileSync65(join55(d, png)));
|
|
51088
51525
|
if (sz) out.push({ name: `${deviceDir}/${png}`, w: sz.w, h: sz.h });
|
|
51089
51526
|
}
|
|
51090
51527
|
}
|
|
@@ -51092,13 +51529,13 @@ function listScreenshots(app, locale = "en-US") {
|
|
|
51092
51529
|
return out;
|
|
51093
51530
|
}
|
|
51094
51531
|
function placeholderHashes2() {
|
|
51095
|
-
const templateIos =
|
|
51096
|
-
if (!
|
|
51532
|
+
const templateIos = join55(appDir("_template"), "ios");
|
|
51533
|
+
if (!existsSync59(templateIos)) return [LEGACY_PLACEHOLDER_SHA2562];
|
|
51097
51534
|
for (const target of readdirSync26(templateIos)) {
|
|
51098
|
-
const p =
|
|
51535
|
+
const p = join55(templateIos, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
|
|
51099
51536
|
try {
|
|
51100
51537
|
if (!statSync15(p).isFile()) continue;
|
|
51101
|
-
return [LEGACY_PLACEHOLDER_SHA2562, createHash26("sha256").update(
|
|
51538
|
+
return [LEGACY_PLACEHOLDER_SHA2562, createHash26("sha256").update(readFileSync65(p)).digest("hex")];
|
|
51102
51539
|
} catch {
|
|
51103
51540
|
}
|
|
51104
51541
|
}
|
|
@@ -51129,12 +51566,12 @@ async function pixelIssues(bytes2) {
|
|
|
51129
51566
|
}
|
|
51130
51567
|
}
|
|
51131
51568
|
async function appIconState(iosDir) {
|
|
51132
|
-
if (!
|
|
51569
|
+
if (!existsSync59(iosDir)) return { exists: false, isPlaceholder: false, storeIssues: [] };
|
|
51133
51570
|
for (const target of readdirSync26(iosDir)) {
|
|
51134
|
-
const p =
|
|
51571
|
+
const p = join55(iosDir, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
|
|
51135
51572
|
try {
|
|
51136
51573
|
if (!statSync15(p).isFile()) continue;
|
|
51137
|
-
const bytes2 =
|
|
51574
|
+
const bytes2 = readFileSync65(p);
|
|
51138
51575
|
const hash = createHash26("sha256").update(bytes2).digest("hex");
|
|
51139
51576
|
const pixels = await pixelIssues(bytes2);
|
|
51140
51577
|
return {
|
|
@@ -51206,7 +51643,7 @@ __export(version_exports, {
|
|
|
51206
51643
|
setAndroidVersion: () => setAndroidVersion,
|
|
51207
51644
|
setIosVersion: () => setIosVersion
|
|
51208
51645
|
});
|
|
51209
|
-
import { readFileSync as
|
|
51646
|
+
import { readFileSync as readFileSync66, writeFileSync as writeFileSync23 } from "node:fs";
|
|
51210
51647
|
function readIosVersion(projectYml) {
|
|
51211
51648
|
const marketing = matchScalar(projectYml, "CFBundleShortVersionString");
|
|
51212
51649
|
const build2 = matchScalar(projectYml, "CFBundleVersion");
|
|
@@ -51264,8 +51701,8 @@ function setAndroidVersion(gradle, v) {
|
|
|
51264
51701
|
function bumpVersion(app, opts) {
|
|
51265
51702
|
const iosPath = iosProjectYml(app);
|
|
51266
51703
|
const gradlePath = androidGradle(app);
|
|
51267
|
-
const iosYml =
|
|
51268
|
-
const gradle =
|
|
51704
|
+
const iosYml = readFileSync66(iosPath, "utf8");
|
|
51705
|
+
const gradle = readFileSync66(gradlePath, "utf8");
|
|
51269
51706
|
const current = readIosVersion(iosYml);
|
|
51270
51707
|
const next = {
|
|
51271
51708
|
marketing: opts.marketing ?? current.marketing,
|
|
@@ -51282,7 +51719,7 @@ var init_version = __esm({
|
|
|
51282
51719
|
});
|
|
51283
51720
|
|
|
51284
51721
|
// ../store-release/register-bundle.ts
|
|
51285
|
-
import { readFileSync as
|
|
51722
|
+
import { readFileSync as readFileSync67 } from "node:fs";
|
|
51286
51723
|
import { createPrivateKey as createPrivateKey2, sign } from "node:crypto";
|
|
51287
51724
|
function b64url2(b) {
|
|
51288
51725
|
return Buffer.from(b).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
@@ -51300,7 +51737,7 @@ function bundleIdBody(identifier, name, platform = "IOS") {
|
|
|
51300
51737
|
async function registerBundleId(opts) {
|
|
51301
51738
|
const env = requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
|
|
51302
51739
|
assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
|
|
51303
|
-
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID,
|
|
51740
|
+
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync67(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
|
|
51304
51741
|
const res = await fetch(`${ASC_API}/v1/bundleIds`, {
|
|
51305
51742
|
method: "POST",
|
|
51306
51743
|
headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
|
|
@@ -51354,7 +51791,7 @@ __export(asc_status_exports, {
|
|
|
51354
51791
|
ascStatus: () => ascStatus,
|
|
51355
51792
|
buildVerdict: () => buildVerdict
|
|
51356
51793
|
});
|
|
51357
|
-
import { readFileSync as
|
|
51794
|
+
import { readFileSync as readFileSync68 } from "node:fs";
|
|
51358
51795
|
function buildVerdict(builds) {
|
|
51359
51796
|
if (!builds.length) {
|
|
51360
51797
|
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).";
|
|
@@ -51368,7 +51805,7 @@ function buildVerdict(builds) {
|
|
|
51368
51805
|
function client(creds) {
|
|
51369
51806
|
const env = creds ?? requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
|
|
51370
51807
|
assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
|
|
51371
|
-
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID,
|
|
51808
|
+
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync68(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
|
|
51372
51809
|
return async (path2) => {
|
|
51373
51810
|
const r = await fetch(`${ASC}${path2}`, { headers: { Authorization: `Bearer ${jwt}` } });
|
|
51374
51811
|
return { status: r.status, json: await r.json().catch(() => ({})) };
|
|
@@ -51528,7 +51965,7 @@ __export(secrets_exports, {
|
|
|
51528
51965
|
runRemoteSecretsCommand: () => runRemoteSecretsCommand,
|
|
51529
51966
|
runSecretsCommand: () => runSecretsCommand
|
|
51530
51967
|
});
|
|
51531
|
-
import { readFileSync as
|
|
51968
|
+
import { readFileSync as readFileSync69 } from "node:fs";
|
|
51532
51969
|
function environment(value) {
|
|
51533
51970
|
if (value === "preview" || value === "production") return value;
|
|
51534
51971
|
throw new Error("--environment must be preview or production");
|
|
@@ -51559,7 +51996,7 @@ async function runSecretsCommand(operation, flags, io, options = {}) {
|
|
|
51559
51996
|
io.log(JSON.stringify(await vault.list({ app, environment: env })));
|
|
51560
51997
|
return 0;
|
|
51561
51998
|
}
|
|
51562
|
-
const value = options.readValue ? options.readValue() :
|
|
51999
|
+
const value = options.readValue ? options.readValue() : readFileSync69(0, "utf8").replace(/\r?\n$/, "");
|
|
51563
52000
|
if (operation === "set") await vault.set({ app, environment: env, name, value });
|
|
51564
52001
|
else if (operation === "rotate") await vault.rotate({ app, environment: env, name, value });
|
|
51565
52002
|
else throw new Error(`unknown secrets operation ${operation}`);
|
|
@@ -51588,7 +52025,7 @@ async function runRemoteSecretsCommand(operation, flags, io, options) {
|
|
|
51588
52025
|
}
|
|
51589
52026
|
let body;
|
|
51590
52027
|
if (operation !== "list") {
|
|
51591
|
-
const value = options.readValue ? options.readValue() :
|
|
52028
|
+
const value = options.readValue ? options.readValue() : readFileSync69(0, "utf8").replace(/\r?\n$/, "");
|
|
51592
52029
|
body = JSON.stringify({ value });
|
|
51593
52030
|
}
|
|
51594
52031
|
const response = await (options.fetchImpl ?? fetch)(url, { method: operation === "list" ? "GET" : operation === "set" ? "PUT" : "POST", headers: headers2, body });
|
|
@@ -51624,15 +52061,15 @@ __export(notify_exports, {
|
|
|
51624
52061
|
runNotify: () => runNotify,
|
|
51625
52062
|
saveAdminSession: () => saveAdminSession
|
|
51626
52063
|
});
|
|
51627
|
-
import { chmodSync as chmodSync3, mkdirSync as mkdirSync27, readFileSync as
|
|
52064
|
+
import { chmodSync as chmodSync3, mkdirSync as mkdirSync27, readFileSync as readFileSync70, writeFileSync as writeFileSync24 } from "node:fs";
|
|
51628
52065
|
import { homedir as homedir6 } from "node:os";
|
|
51629
|
-
import { dirname as dirname30, join as
|
|
52066
|
+
import { dirname as dirname30, join as join56 } from "node:path";
|
|
51630
52067
|
function defaultSessionsPath() {
|
|
51631
|
-
return process.env.HIMI_ADMIN_SESSIONS_FILE ??
|
|
52068
|
+
return process.env.HIMI_ADMIN_SESSIONS_FILE ?? join56(homedir6(), ".himalaya", "admin-sessions.json");
|
|
51632
52069
|
}
|
|
51633
52070
|
function loadSessionsFile(path2 = defaultSessionsPath()) {
|
|
51634
52071
|
try {
|
|
51635
|
-
return JSON.parse(
|
|
52072
|
+
return JSON.parse(readFileSync70(path2, "utf8"));
|
|
51636
52073
|
} catch {
|
|
51637
52074
|
return {};
|
|
51638
52075
|
}
|
|
@@ -52043,14 +52480,17 @@ var init_visitor_auth = __esm({
|
|
|
52043
52480
|
});
|
|
52044
52481
|
|
|
52045
52482
|
// src/site-analyze/copy-clean.ts
|
|
52483
|
+
function isTemplatePlaceholder(text5) {
|
|
52484
|
+
return PLACEHOLDER_RE.test(text5);
|
|
52485
|
+
}
|
|
52046
52486
|
function cleanText(raw, cap) {
|
|
52047
52487
|
const s = String(raw ?? "").replace(/[\u0000-\u001F\u007F]/g, " ").replace(/\s+/g, " ").trim();
|
|
52048
52488
|
return s.length > cap ? `${s.slice(0, cap - 1).trimEnd()}\u2026` : s;
|
|
52049
52489
|
}
|
|
52050
52490
|
function stripPii(text5) {
|
|
52051
52491
|
return text5.replace(EMAIL_RE2, "").replace(PHONE_SHAPE_RE, (m) => {
|
|
52052
|
-
const
|
|
52053
|
-
return
|
|
52492
|
+
const digits2 = (m.match(ANY_DIGIT_RE) ?? []).length;
|
|
52493
|
+
return digits2 >= PHONE_MIN_DIGITS && PHONE_DIGIT_RUN_RE.test(m) ? "" : m;
|
|
52054
52494
|
}).replace(/\s+/g, " ").trim();
|
|
52055
52495
|
}
|
|
52056
52496
|
function isBoilerplate(text5) {
|
|
@@ -52086,7 +52526,7 @@ var init_copy_clean = __esm({
|
|
|
52086
52526
|
PHONE_DIGIT_RUN_RE = new RegExp(`[${DIGIT}]{3}`);
|
|
52087
52527
|
ANY_DIGIT_RE = new RegExp(`[${DIGIT}]`, "g");
|
|
52088
52528
|
BOILERPLATE_RE = /powered by wix|this site was designed with|wix\.com|all rights reserved|©|\(c\)\s*\d{4}|privacy policy|terms (of use|and conditions)|accessibility statement|cookie (policy|settings|preferences)|accept all|manage preferences|do not sell/i;
|
|
52089
|
-
PLACEHOLDER_RE = /i'?m a (paragraph|title|description)|click here to add|add your own text|double click to edit|this is a great (place|space)|tell your visitors|lorem ipsum|service title|item title|your paragraph text/i;
|
|
52529
|
+
PLACEHOLDER_RE = /i'?m a (paragraph|title|description)|click here to add|add your own text|double click to edit|this is a great (place|space)|tell your visitors|lorem ipsum|service title|item title|your paragraph text|tell clients about what you['’]?re offering|to add a description,? click|click manage services|booking settings\s*>\s*booking polic|in your dashboard,? go to|go to booking settings/i;
|
|
52090
52530
|
ABOUT_HEADING_RE_SOURCE = "^(?:about\\b|who we are|who are we|our story|our mission|\u05DE\u05D9 \u05D0\u05E0\u05D7\u05E0\u05D5)";
|
|
52091
52531
|
}
|
|
52092
52532
|
});
|
|
@@ -52158,6 +52598,49 @@ function planDetail(p) {
|
|
|
52158
52598
|
const bits = [cycle, perks.slice(0, 4).join("; ")].filter(Boolean);
|
|
52159
52599
|
return bits.length ? bits.join(" \xB7 ") : void 0;
|
|
52160
52600
|
}
|
|
52601
|
+
function moneyText(m) {
|
|
52602
|
+
if (!m || typeof m !== "object") return void 0;
|
|
52603
|
+
const o = m;
|
|
52604
|
+
const formatted = str4(o.formattedValue ?? o.formatted);
|
|
52605
|
+
if (formatted.trim()) return formatted.trim();
|
|
52606
|
+
const raw = o.value ?? o.amount;
|
|
52607
|
+
const value = typeof raw === "number" ? String(raw) : str4(raw);
|
|
52608
|
+
if (!value.trim()) return void 0;
|
|
52609
|
+
return [value.trim(), str4(o.currency).trim()].filter(Boolean).join(" ");
|
|
52610
|
+
}
|
|
52611
|
+
function servicePrice(s) {
|
|
52612
|
+
const payment = s.payment && typeof s.payment === "object" ? s.payment : void 0;
|
|
52613
|
+
if (!payment) return void 0;
|
|
52614
|
+
const rate = str4(payment.rateType).toUpperCase();
|
|
52615
|
+
const fixed = payment.fixed;
|
|
52616
|
+
const varied = payment.varied;
|
|
52617
|
+
const custom = payment.custom;
|
|
52618
|
+
if (rate === "NO_FEE") return void 0;
|
|
52619
|
+
if (rate === "VARIED" || !rate && varied) {
|
|
52620
|
+
const min = moneyText(varied?.minPrice);
|
|
52621
|
+
return moneyText(varied?.defaultPrice) ?? (min ? `from ${min}` : void 0);
|
|
52622
|
+
}
|
|
52623
|
+
if (rate === "CUSTOM" || !rate && custom) {
|
|
52624
|
+
return copyOrDrop(custom?.description, 80) || void 0;
|
|
52625
|
+
}
|
|
52626
|
+
const legacy = typeof payment.price === "number" || typeof payment.price === "string" ? moneyText({ value: payment.price, currency: payment.currency ?? s.currency }) : moneyText(payment.price);
|
|
52627
|
+
return moneyText(fixed?.price) ?? legacy;
|
|
52628
|
+
}
|
|
52629
|
+
function serviceDetail(s) {
|
|
52630
|
+
const payment = s.payment && typeof s.payment === "object" ? s.payment : void 0;
|
|
52631
|
+
if (!payment) return void 0;
|
|
52632
|
+
if (str4(payment.rateType).toUpperCase() === "NO_FEE") return "free";
|
|
52633
|
+
const options = payment.options && typeof payment.options === "object" ? payment.options : {};
|
|
52634
|
+
const hasPlanIds = asArr(payment.pricingPlanIds).length > 0;
|
|
52635
|
+
const modes = [
|
|
52636
|
+
options.online === true && "online",
|
|
52637
|
+
options.inPerson === true && "in person",
|
|
52638
|
+
(options.pricingPlan === true || hasPlanIds) && "with a pricing plan"
|
|
52639
|
+
].filter((m) => !!m);
|
|
52640
|
+
if (!modes.length) return void 0;
|
|
52641
|
+
const how = modes.length === 1 ? `pay ${modes[0]} only` : `pay ${modes.slice(0, -1).join(", ")} or ${modes[modes.length - 1]}`;
|
|
52642
|
+
return options.deposit === true ? `${how} (deposit)` : how;
|
|
52643
|
+
}
|
|
52161
52644
|
function formLabels(x, depth = 0, out = []) {
|
|
52162
52645
|
if (x == null || depth > 5) return out;
|
|
52163
52646
|
if (Array.isArray(x)) {
|
|
@@ -52178,7 +52661,7 @@ function formDetail(f) {
|
|
|
52178
52661
|
return names.length ? names.join(", ") : void 0;
|
|
52179
52662
|
}
|
|
52180
52663
|
function side(call, def) {
|
|
52181
|
-
if (!call) return Promise.resolve({ status: "
|
|
52664
|
+
if (!call) return Promise.resolve({ status: "skipped", count: 0, note: "no-auth", items: [] });
|
|
52182
52665
|
const attempts = [
|
|
52183
52666
|
{ method: def.method, path: def.path, body: def.body, itemsOf: def.itemsOf },
|
|
52184
52667
|
...def.fallbacks ?? []
|
|
@@ -52208,14 +52691,20 @@ function side(call, def) {
|
|
|
52208
52691
|
})();
|
|
52209
52692
|
}
|
|
52210
52693
|
function toItems(def, raw) {
|
|
52211
|
-
return raw.slice(0, 12).map((it, i) =>
|
|
52212
|
-
|
|
52213
|
-
|
|
52214
|
-
|
|
52215
|
-
|
|
52216
|
-
|
|
52217
|
-
|
|
52218
|
-
|
|
52694
|
+
return raw.slice(0, 12).map((it, i) => {
|
|
52695
|
+
const rawDescription = def.descriptionOf ? def.descriptionOf(it) : genericDescription(it);
|
|
52696
|
+
const description = copyOrDrop(rawDescription, 240) || void 0;
|
|
52697
|
+
const template = rawDescription && !description && isTemplatePlaceholder(rawDescription) ? stripPii(cleanText(rawDescription, 90)) : void 0;
|
|
52698
|
+
return {
|
|
52699
|
+
id: str4((def.idOf ? def.idOf(it) : it.id) ?? `row-${i}`),
|
|
52700
|
+
title: def.titleOf(it) || "(untitled)",
|
|
52701
|
+
imageUrl: def.imageOf?.(it),
|
|
52702
|
+
price: def.priceOf?.(it) || str4(it.price?.formatted) || str4(it.formattedPrice) || void 0,
|
|
52703
|
+
detail: def.detailOf?.(it),
|
|
52704
|
+
description,
|
|
52705
|
+
...template ? { templateText: template } : {}
|
|
52706
|
+
};
|
|
52707
|
+
});
|
|
52219
52708
|
}
|
|
52220
52709
|
async function runDualProbes(owner, visitor, definitions2 = ALL) {
|
|
52221
52710
|
const rows = await Promise.all(definitions2.map(async (def) => {
|
|
@@ -52225,7 +52714,10 @@ async function runDualProbes(owner, visitor, definitions2 = ALL) {
|
|
|
52225
52714
|
vertical: def.vertical,
|
|
52226
52715
|
owner: { status: o.status, count: o.count, httpStatus: o.httpStatus, note: o.note },
|
|
52227
52716
|
visitor: { status: vis.status, count: vis.count, httpStatus: vis.httpStatus, note: vis.note },
|
|
52228
|
-
|
|
52717
|
+
// Only a visitor request that was actually MADE can show the app cannot see a row. With no
|
|
52718
|
+
// client id (#3269) the visitor side is `skipped`, and every owner-visible vertical would
|
|
52719
|
+
// otherwise read APP-INVISIBLE off a request nobody sent (codebot review on #3283).
|
|
52720
|
+
appInvisible: o.count > 0 && vis.count === 0 && vis.status !== "wrong-path" && vis.status !== "skipped",
|
|
52229
52721
|
imageless,
|
|
52230
52722
|
items: toItems(def, o.items.length ? o.items : vis.items)
|
|
52231
52723
|
};
|
|
@@ -52416,7 +52908,9 @@ var init_probes = __esm({
|
|
|
52416
52908
|
body: { query: { paging: { limit: 50 } } },
|
|
52417
52909
|
itemsOf: (d) => asArr(d.services),
|
|
52418
52910
|
titleOf: (s) => str4(s.name),
|
|
52419
|
-
imageOf: serviceImage
|
|
52911
|
+
imageOf: serviceImage,
|
|
52912
|
+
priceOf: servicePrice,
|
|
52913
|
+
detailOf: serviceDetail
|
|
52420
52914
|
},
|
|
52421
52915
|
{
|
|
52422
52916
|
vertical: "events",
|
|
@@ -52953,7 +53447,7 @@ var init_traits = __esm({
|
|
|
52953
53447
|
});
|
|
52954
53448
|
|
|
52955
53449
|
// src/site-analyze/tokens.ts
|
|
52956
|
-
function
|
|
53450
|
+
function channels2(css) {
|
|
52957
53451
|
const canonical3 = canonicalHex(css);
|
|
52958
53452
|
if (!canonical3) return null;
|
|
52959
53453
|
return [
|
|
@@ -52963,11 +53457,11 @@ function channels(css) {
|
|
|
52963
53457
|
];
|
|
52964
53458
|
}
|
|
52965
53459
|
function isNearWhite(css) {
|
|
52966
|
-
const c =
|
|
53460
|
+
const c = channels2(css);
|
|
52967
53461
|
return !!c && c[0] >= 240 && c[1] >= 240 && c[2] >= 240;
|
|
52968
53462
|
}
|
|
52969
53463
|
function isNearBlack(css) {
|
|
52970
|
-
const c =
|
|
53464
|
+
const c = channels2(css);
|
|
52971
53465
|
return !!c && c[0] <= 80 && c[1] <= 80 && c[2] <= 80;
|
|
52972
53466
|
}
|
|
52973
53467
|
function usableCssColor(v) {
|
|
@@ -53106,12 +53600,12 @@ var init_tokens3 = __esm({
|
|
|
53106
53600
|
function channel2(hex2, offset) {
|
|
53107
53601
|
return Number.parseInt(hex2.slice(offset, offset + 2), 16);
|
|
53108
53602
|
}
|
|
53109
|
-
function
|
|
53603
|
+
function toHex2(r, g, b) {
|
|
53110
53604
|
return `#${[r, g, b].map((value) => Math.round(value).toString(16).padStart(2, "0")).join("")}`.toUpperCase();
|
|
53111
53605
|
}
|
|
53112
53606
|
function mix2(color, background, colorWeight) {
|
|
53113
53607
|
const values = [1, 3, 5].map((offset) => channel2(color, offset) * colorWeight + channel2(background, offset) * (1 - colorWeight));
|
|
53114
|
-
return
|
|
53608
|
+
return toHex2(values[0], values[1], values[2]);
|
|
53115
53609
|
}
|
|
53116
53610
|
function relativeLuminance2(color) {
|
|
53117
53611
|
const linear = [1, 3, 5].map((offset) => {
|
|
@@ -53855,6 +54349,10 @@ function taglineFrom(identity, pages, published) {
|
|
|
53855
54349
|
const hero = copyOrDrop(home?.heroCopy, CAP2.tagline);
|
|
53856
54350
|
return hero ? { text: hero, source: "hero" } : null;
|
|
53857
54351
|
}
|
|
54352
|
+
function tabLabel(label2) {
|
|
54353
|
+
const trimmed = label2.replace(/\s+page$/i, "").trim();
|
|
54354
|
+
return trimmed && trimmed !== label2.trim() && !/^(front|landing|title|web)$/i.test(trimmed) ? trimmed : label2;
|
|
54355
|
+
}
|
|
53858
54356
|
function suggestKeys(args) {
|
|
53859
54357
|
const { nav, sections, tagline, installedVerticals } = args;
|
|
53860
54358
|
const out = {};
|
|
@@ -53868,7 +54366,7 @@ function suggestKeys(args) {
|
|
|
53868
54366
|
const allowed2 = (rule) => !rule.vertical || installed.has(rule.vertical);
|
|
53869
54367
|
for (const label2 of nav) {
|
|
53870
54368
|
for (const rule of KEY_RULES) {
|
|
53871
|
-
if (rule.tab && allowed2(rule) && rule.re.test(label2)) set(rule.tab, label2);
|
|
54369
|
+
if (rule.tab && allowed2(rule) && rule.re.test(label2)) set(rule.tab, tabLabel(label2));
|
|
53872
54370
|
}
|
|
53873
54371
|
}
|
|
53874
54372
|
for (const section2 of sections) {
|
|
@@ -54458,6 +54956,234 @@ var init_net_guard = __esm({
|
|
|
54458
54956
|
}
|
|
54459
54957
|
});
|
|
54460
54958
|
|
|
54959
|
+
// src/site-analyze/placeholders.ts
|
|
54960
|
+
function textFields(look) {
|
|
54961
|
+
if (look.unavailable) return [];
|
|
54962
|
+
const out = [];
|
|
54963
|
+
const add = (text5, where, narrative = false) => {
|
|
54964
|
+
if (text5 && text5.trim()) out.push({ text: text5, where, narrative });
|
|
54965
|
+
};
|
|
54966
|
+
for (const label2 of look.navLabels) add(label2, "nav");
|
|
54967
|
+
for (const p of look.pages) {
|
|
54968
|
+
for (const label2 of p.navLabels) add(label2, "nav");
|
|
54969
|
+
add(p.title, `${p.url} (title)`);
|
|
54970
|
+
add(p.heroCopy, p.url, true);
|
|
54971
|
+
for (const h of p.headings) add(h, p.url);
|
|
54972
|
+
for (const c of p.ctaLabels ?? []) add(c, p.url);
|
|
54973
|
+
for (const s of p.sections ?? []) {
|
|
54974
|
+
add(s.heading, p.url);
|
|
54975
|
+
add(s.body, p.url, true);
|
|
54976
|
+
}
|
|
54977
|
+
for (const f of p.faq ?? []) {
|
|
54978
|
+
add(f.q, `${p.url} (faq)`, true);
|
|
54979
|
+
add(f.a, `${p.url} (faq)`, true);
|
|
54980
|
+
}
|
|
54981
|
+
for (const t of p.testimonials ?? []) add(t, `${p.url} (testimonials)`, true);
|
|
54982
|
+
add(p.about, `${p.url} (about)`, true);
|
|
54983
|
+
add(p.meta?.ogTitle, `${p.url} (og:title)`);
|
|
54984
|
+
add(p.meta?.description, `${p.url} (meta)`, true);
|
|
54985
|
+
for (const t of p.templateText ?? []) add(t, p.url);
|
|
54986
|
+
}
|
|
54987
|
+
return out;
|
|
54988
|
+
}
|
|
54989
|
+
function pushWhere(map, key2, value, where) {
|
|
54990
|
+
const row = map.get(key2) ?? { value, where: [] };
|
|
54991
|
+
if (!row.where.includes(where) && row.where.length < CAP3.where) row.where.push(where);
|
|
54992
|
+
map.set(key2, row);
|
|
54993
|
+
}
|
|
54994
|
+
function templateContacts(identity, fields) {
|
|
54995
|
+
const hits = /* @__PURE__ */ new Map();
|
|
54996
|
+
const phone = identity.contact.phone ?? "";
|
|
54997
|
+
if (phone && TEMPLATE_PHONES.has(digits(phone))) pushWhere(hits, `p:${digits(phone)}`, phone.trim(), "identity.contact.phone");
|
|
54998
|
+
const email = identity.contact.email ?? "";
|
|
54999
|
+
if (email && TEMPLATE_EMAIL_RE.test(email)) pushWhere(hits, `e:${email.toLowerCase()}`, email.trim(), "identity.contact.email");
|
|
55000
|
+
const address = identity.contact.address ?? "";
|
|
55001
|
+
if (address && TEMPLATE_ADDRESS_RE.test(address)) pushWhere(hits, "a:terry", "500 Terry Francine Street", "identity.contact.address");
|
|
55002
|
+
for (const f of fields) {
|
|
55003
|
+
for (const m of f.text.matchAll(PHONE_IN_TEXT_RE)) {
|
|
55004
|
+
const d = digits(m[0]);
|
|
55005
|
+
if (TEMPLATE_PHONES.has(d)) pushWhere(hits, `p:${d}`, m[0].trim(), f.where);
|
|
55006
|
+
}
|
|
55007
|
+
const e = f.text.match(TEMPLATE_EMAIL_RE)?.[0];
|
|
55008
|
+
if (e) pushWhere(hits, `e:${e.toLowerCase()}`, e, f.where);
|
|
55009
|
+
if (TEMPLATE_ADDRESS_RE.test(f.text)) pushWhere(hits, "a:terry", "500 Terry Francine Street", f.where);
|
|
55010
|
+
}
|
|
55011
|
+
return [...hits.values()].slice(0, CAP3.perKind).map((h) => ({
|
|
55012
|
+
kind: "template-contact",
|
|
55013
|
+
value: h.value,
|
|
55014
|
+
where: h.where,
|
|
55015
|
+
note: "a Wix template's sample contact detail, not the business's \u2014 get the real one before any screen shows it"
|
|
55016
|
+
}));
|
|
55017
|
+
}
|
|
55018
|
+
function editorText(fields, probes) {
|
|
55019
|
+
const hits = /* @__PURE__ */ new Map();
|
|
55020
|
+
const all = [
|
|
55021
|
+
...fields,
|
|
55022
|
+
...probes.flatMap((p) => p.items.flatMap((it) => [
|
|
55023
|
+
{ text: it.title, where: `catalog:${p.vertical}` },
|
|
55024
|
+
{ text: it.description ?? "", where: `catalog:${p.vertical}` },
|
|
55025
|
+
// Already dropped from `description` by `copyOrDrop`; `toItems` kept the fact.
|
|
55026
|
+
{ text: it.templateText ?? "", where: `catalog:${p.vertical}` }
|
|
55027
|
+
]))
|
|
55028
|
+
];
|
|
55029
|
+
for (const f of all) {
|
|
55030
|
+
if (!f.text || !isTemplatePlaceholder(f.text)) continue;
|
|
55031
|
+
const value = snippet(stripPii(f.text));
|
|
55032
|
+
pushWhere(hits, value.toLowerCase(), value, f.where);
|
|
55033
|
+
}
|
|
55034
|
+
return [...hits.values()].slice(0, CAP3.perKind).map((h) => ({
|
|
55035
|
+
kind: "editor-text",
|
|
55036
|
+
value: h.value,
|
|
55037
|
+
where: h.where,
|
|
55038
|
+
note: "unedited Wix template/editor text the published site still shows \u2014 dropped from book.copy; do not ship it, and tell the owner the site shows it"
|
|
55039
|
+
}));
|
|
55040
|
+
}
|
|
55041
|
+
function stripLead(name) {
|
|
55042
|
+
const [left = "", ...rest] = name.split(/\s+&\s+/);
|
|
55043
|
+
const words = left.split(/\s+/);
|
|
55044
|
+
let cut = 0;
|
|
55045
|
+
words.forEach((w, i) => {
|
|
55046
|
+
if (LEAD_STOPWORDS.has(w.toLowerCase())) cut = i + 1;
|
|
55047
|
+
});
|
|
55048
|
+
const kept = words.slice(cut).join(" ");
|
|
55049
|
+
return kept ? [kept, ...rest].join(" & ") : "";
|
|
55050
|
+
}
|
|
55051
|
+
function nameMismatches(identity, look, fields) {
|
|
55052
|
+
const name = (identity.businessName || identity.siteDisplayName || "").trim();
|
|
55053
|
+
const n = norm2(name);
|
|
55054
|
+
if (n.length < 3) return [];
|
|
55055
|
+
const pageNames = /* @__PURE__ */ new Set([
|
|
55056
|
+
...(look.sitePages ?? []).map((p) => norm2(p.title)),
|
|
55057
|
+
...look.navLabels.map(norm2)
|
|
55058
|
+
]);
|
|
55059
|
+
const differs = (candidate) => {
|
|
55060
|
+
const c = norm2(candidate);
|
|
55061
|
+
return c.length >= 3 && c !== n && !c.includes(n) && !n.includes(c) && !pageNames.has(c);
|
|
55062
|
+
};
|
|
55063
|
+
const hits = /* @__PURE__ */ new Map();
|
|
55064
|
+
for (const f of fields) {
|
|
55065
|
+
if (/\((?:og:)?title\)$/.test(f.where)) {
|
|
55066
|
+
const parts = f.text.split(TITLE_SPLIT_RE).map((s) => s.trim()).filter(Boolean);
|
|
55067
|
+
const site = parts.length >= 2 ? parts[parts.length - 1] : "";
|
|
55068
|
+
if (site && differs(site)) pushWhere(hits, norm2(site), site, f.where);
|
|
55069
|
+
}
|
|
55070
|
+
for (const m of f.text.matchAll(COPYRIGHT_BY_RE)) {
|
|
55071
|
+
const who = m[1].trim();
|
|
55072
|
+
if (differs(who)) pushWhere(hits, norm2(who), who, f.where);
|
|
55073
|
+
}
|
|
55074
|
+
if (!f.narrative) continue;
|
|
55075
|
+
for (const m of f.text.matchAll(AMP_NAME_RE)) {
|
|
55076
|
+
const who = stripLead(m[1].trim());
|
|
55077
|
+
if (who.includes("&") && differs(who)) pushWhere(hits, norm2(who), who, f.where);
|
|
55078
|
+
}
|
|
55079
|
+
}
|
|
55080
|
+
return [...hits.values()].slice(0, CAP3.perKind).map((h) => ({
|
|
55081
|
+
kind: "name-mismatch",
|
|
55082
|
+
value: h.value,
|
|
55083
|
+
where: h.where,
|
|
55084
|
+
note: `the business is "${name}" but the site also calls itself "${h.value}" \u2014 likely the template's name left in the copy; confirm with the owner which is theirs before reusing any sentence that says it`
|
|
55085
|
+
}));
|
|
55086
|
+
}
|
|
55087
|
+
function mediaKey(url) {
|
|
55088
|
+
return wixMediaFileId(url) ?? url.split(/[?#]/)[0];
|
|
55089
|
+
}
|
|
55090
|
+
function duplicateMedia(look, probes) {
|
|
55091
|
+
const out = [];
|
|
55092
|
+
const scan = (urls, where) => {
|
|
55093
|
+
const counts = /* @__PURE__ */ new Map();
|
|
55094
|
+
for (const u of urls) {
|
|
55095
|
+
if (!u) continue;
|
|
55096
|
+
const k = mediaKey(u);
|
|
55097
|
+
counts.set(k, (counts.get(k) ?? 0) + 1);
|
|
55098
|
+
}
|
|
55099
|
+
for (const [k, count] of counts) {
|
|
55100
|
+
if (count < DUPLICATE_MEDIA_MIN || out.length >= CAP3.perKind) continue;
|
|
55101
|
+
out.push({
|
|
55102
|
+
kind: "duplicate-media",
|
|
55103
|
+
value: k.slice(0, 80),
|
|
55104
|
+
where: [where],
|
|
55105
|
+
note: `the same image is used ${count} times here \u2014 template filler, not ${count} distinct photos; do not present it as the business's gallery`
|
|
55106
|
+
});
|
|
55107
|
+
}
|
|
55108
|
+
};
|
|
55109
|
+
if (!look.unavailable) for (const p of look.pages) scan(p.imageUrls, p.url);
|
|
55110
|
+
for (const p of probes) scan(p.items.map((it) => it.imageUrl ?? ""), `catalog:${p.vertical}`);
|
|
55111
|
+
return out;
|
|
55112
|
+
}
|
|
55113
|
+
function detectPlaceholders(args) {
|
|
55114
|
+
const fields = textFields(args.look);
|
|
55115
|
+
return [
|
|
55116
|
+
...templateContacts(args.identity, fields),
|
|
55117
|
+
...editorText(fields, args.probes),
|
|
55118
|
+
...nameMismatches(args.identity, args.look, fields),
|
|
55119
|
+
...duplicateMedia(args.look, args.probes)
|
|
55120
|
+
];
|
|
55121
|
+
}
|
|
55122
|
+
function placeholderWarnings(findings) {
|
|
55123
|
+
const byKind = /* @__PURE__ */ new Map();
|
|
55124
|
+
for (const f of findings) byKind.set(f.kind, [...byKind.get(f.kind) ?? [], f]);
|
|
55125
|
+
const quote = (rows) => rows.slice(0, 3).map((r) => `"${r.value}"`).join(", ");
|
|
55126
|
+
const out = [];
|
|
55127
|
+
const contact = byKind.get("template-contact");
|
|
55128
|
+
if (contact) out.push(`template placeholder contact details on the site: ${quote(contact)} \u2014 the Wix template's samples, not the business's; get the real ones before any screen shows them (book.placeholders)`);
|
|
55129
|
+
const editor = byKind.get("editor-text");
|
|
55130
|
+
if (editor) out.push(`${editor.length} unedited Wix editor/template string(s) on the published site, e.g. ${quote(editor.slice(0, 1))} \u2014 dropped from book.copy, never ship them (book.placeholders)`);
|
|
55131
|
+
const names = byKind.get("name-mismatch");
|
|
55132
|
+
if (names) out.push(`the site names the business inconsistently \u2014 it also says ${quote(names)}; likely the template's name left in the copy, so confirm with the owner (book.placeholders)`);
|
|
55133
|
+
const media = byKind.get("duplicate-media");
|
|
55134
|
+
if (media) out.push(`${media.length} place(s) repeat one image ${DUPLICATE_MEDIA_MIN}+ times (${media.slice(0, 3).map((m) => m.where[0]).join(", ")}) \u2014 template filler, not real photos (book.placeholders)`);
|
|
55135
|
+
return out;
|
|
55136
|
+
}
|
|
55137
|
+
var TEMPLATE_PHONES, TEMPLATE_EMAIL_RE, TEMPLATE_ADDRESS_RE, PHONE_IN_TEXT_RE, DUPLICATE_MEDIA_MIN, CAP3, digits, norm2, snippet, LEAD_STOPWORDS, AMP_NAME_RE, COPYRIGHT_BY_RE, TITLE_SPLIT_RE;
|
|
55138
|
+
var init_placeholders = __esm({
|
|
55139
|
+
"src/site-analyze/placeholders.ts"() {
|
|
55140
|
+
init_copy_clean();
|
|
55141
|
+
init_rest();
|
|
55142
|
+
TEMPLATE_PHONES = /* @__PURE__ */ new Set(["1234567890", "11234567890", "5555555555", "15555555555", "0000000000"]);
|
|
55143
|
+
TEMPLATE_EMAIL_RE = /[\w.+-]+@(?:my-?site|my-?domain|mydomain|your-?domain|your-?site|example|domain)\.(?:com|org|net|co)\b/i;
|
|
55144
|
+
TEMPLATE_ADDRESS_RE = /\b500 Terry Franc(?:ine|ois)\b/i;
|
|
55145
|
+
PHONE_IN_TEXT_RE = /\+?\d[\d\s().-]{6,}\d/g;
|
|
55146
|
+
DUPLICATE_MEDIA_MIN = 3;
|
|
55147
|
+
CAP3 = { perKind: 6, where: 6, snippet: 90 };
|
|
55148
|
+
digits = (s) => s.replace(/\D/g, "");
|
|
55149
|
+
norm2 = (s) => s.toLowerCase().normalize("NFKD").replace(/[^\p{L}\p{N}]+/gu, "");
|
|
55150
|
+
snippet = (s) => {
|
|
55151
|
+
const t = s.replace(/\s+/g, " ").trim();
|
|
55152
|
+
return t.length > CAP3.snippet ? `${t.slice(0, CAP3.snippet - 1).trimEnd()}\u2026` : t;
|
|
55153
|
+
};
|
|
55154
|
+
LEAD_STOPWORDS = /* @__PURE__ */ new Set([
|
|
55155
|
+
"at",
|
|
55156
|
+
"by",
|
|
55157
|
+
"with",
|
|
55158
|
+
"from",
|
|
55159
|
+
"choose",
|
|
55160
|
+
"call",
|
|
55161
|
+
"contact",
|
|
55162
|
+
"welcome",
|
|
55163
|
+
"about",
|
|
55164
|
+
"to",
|
|
55165
|
+
"for",
|
|
55166
|
+
"in",
|
|
55167
|
+
"on",
|
|
55168
|
+
"our",
|
|
55169
|
+
"why",
|
|
55170
|
+
"is",
|
|
55171
|
+
"are",
|
|
55172
|
+
"do",
|
|
55173
|
+
"does",
|
|
55174
|
+
"the",
|
|
55175
|
+
"and",
|
|
55176
|
+
"meet",
|
|
55177
|
+
"join",
|
|
55178
|
+
"trust",
|
|
55179
|
+
"hire"
|
|
55180
|
+
]);
|
|
55181
|
+
AMP_NAME_RE = new RegExp("(\\p{Lu}[\\p{L}'\u2019]*(?:\\s+\\p{Lu}[\\p{L}'\u2019]*){0,2}\\s+&\\s+\\p{Lu}[\\p{L}'\u2019]*(?:\\s+\\p{Lu}[\\p{L}'\u2019]*){0,1})", "gu");
|
|
55182
|
+
COPYRIGHT_BY_RE = /©\s*\d{4}\s+by\s+([^.|\n©]{2,40})/giu;
|
|
55183
|
+
TITLE_SPLIT_RE = /\s+[|–—]\s+|\s+-\s+/;
|
|
55184
|
+
}
|
|
55185
|
+
});
|
|
55186
|
+
|
|
54461
55187
|
// src/site-analyze/analyze.ts
|
|
54462
55188
|
function siteFetchFor(ports) {
|
|
54463
55189
|
return ports.siteFetch ?? guardedSiteFetch;
|
|
@@ -54468,14 +55194,15 @@ function localeFromSiteLanguage(languageCode) {
|
|
|
54468
55194
|
return void 0;
|
|
54469
55195
|
}
|
|
54470
55196
|
async function analyzeSite(input, ports) {
|
|
54471
|
-
const clientId = input.clientId
|
|
55197
|
+
const clientId = input.clientId?.trim() || void 0;
|
|
54472
55198
|
const siteUrl = input.siteUrl.trim();
|
|
54473
|
-
if (!clientId) throw new Error("clientId is required");
|
|
54474
55199
|
if (!siteUrl) throw new Error("siteUrl is required");
|
|
54475
55200
|
assertPublicSiteUrl(siteUrl);
|
|
54476
55201
|
const redirectUri = input.redirectUri?.trim() ? assertRedirectUri(input.redirectUri) : void 0;
|
|
54477
|
-
|
|
54478
|
-
|
|
55202
|
+
if (redirectUri && !clientId) {
|
|
55203
|
+
throw Object.assign(new Error(REDIRECT_NEEDS_CLIENT), { exit: 2 });
|
|
55204
|
+
}
|
|
55205
|
+
const visitor = clientId ? visitorTransportFrom(ports.fetch, await mintVisitorToken(ports.fetch, clientId), input.msid ?? ports.ownerAuth?.msid) : void 0;
|
|
54479
55206
|
const owner = ports.ownerAuth ? ownerTransportFrom(ports.fetch, ports.ownerAuth) : void 0;
|
|
54480
55207
|
const lookP = (ports.browser ? ports.browser.crawl({ siteUrl, budget: 12 }) : Promise.resolve({
|
|
54481
55208
|
unavailable: ports.lookUnavailableReason ?? "no_browser_on_plane",
|
|
@@ -54613,12 +55340,14 @@ async function analyzeSite(input, ports) {
|
|
|
54613
55340
|
});
|
|
54614
55341
|
plan.provisioning.appearance = { homeLayout: traits.homeLayout.id };
|
|
54615
55342
|
plan.provisioning.navigation = { navKind: traits.navKind.id };
|
|
54616
|
-
|
|
54617
|
-
|
|
54618
|
-
|
|
54619
|
-
|
|
54620
|
-
|
|
54621
|
-
|
|
55343
|
+
if (clientId) {
|
|
55344
|
+
plan.provisioning.wix = {
|
|
55345
|
+
clientId,
|
|
55346
|
+
siteUrl,
|
|
55347
|
+
// Already validated and trimmed at the top of this function, with the other input guards.
|
|
55348
|
+
...redirectUri ? { redirectUri } : {}
|
|
55349
|
+
};
|
|
55350
|
+
}
|
|
54622
55351
|
const locale = localeFromSiteLanguage(identity.locale.languageCode || identity.language?.site || "");
|
|
54623
55352
|
if (locale) plan.provisioning.locale = locale;
|
|
54624
55353
|
const velo = buildVeloChapter({ look, owner: ownerVelo });
|
|
@@ -54638,7 +55367,7 @@ async function analyzeSite(input, ports) {
|
|
|
54638
55367
|
const book = {
|
|
54639
55368
|
schemaVersion: BOOK_SCHEMA_VERSION,
|
|
54640
55369
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
54641
|
-
input: { clientId, siteUrl, msid: input.msid, hasOwner: !!owner },
|
|
55370
|
+
input: { ...clientId ? { clientId } : {}, siteUrl, msid: input.msid, hasOwner: !!owner },
|
|
54642
55371
|
identity,
|
|
54643
55372
|
probes,
|
|
54644
55373
|
media: mergeMedia(media, look, identity.logoUrl),
|
|
@@ -54653,7 +55382,10 @@ async function analyzeSite(input, ports) {
|
|
|
54653
55382
|
velo,
|
|
54654
55383
|
taxonomy,
|
|
54655
55384
|
traits,
|
|
54656
|
-
permissions
|
|
55385
|
+
permissions,
|
|
55386
|
+
// Template leftovers, recorded in the BOOK (the durable artifact the next agent reads) and
|
|
55387
|
+
// repeated as warnings below for whoever is watching this run (#3276).
|
|
55388
|
+
placeholders: detectPlaceholders({ identity, look, probes })
|
|
54657
55389
|
};
|
|
54658
55390
|
if (Object.keys(book.copy.suggestedCopyKeys).length) {
|
|
54659
55391
|
plan.provisioning.copy = { ...book.copy.suggestedCopyKeys };
|
|
@@ -54680,6 +55412,12 @@ async function analyzeSite(input, ports) {
|
|
|
54680
55412
|
`${cmsRead.truncated} further CMS collection(s) were not read \u2014 the listing stops at ${CMS_LIST_LIMIT}, so the applied app ships only the ones above.`
|
|
54681
55413
|
);
|
|
54682
55414
|
}
|
|
55415
|
+
warnings.push(...placeholderWarnings(book.placeholders));
|
|
55416
|
+
if (!clientId) {
|
|
55417
|
+
warnings.push(
|
|
55418
|
+
owner ? "no --client-id: the VISITOR side of every vertical probe was skipped, so the book cannot say what a shipped app will see, and there is no `wix` binding to --apply. Re-run with --client-id (`himi site client list --site <msid>`) for both." : "no --client-id: this was the URL-only pass (published pages, look, copy). The vertical probes were skipped, so the catalog has no counts, and there is no `wix` binding to --apply. Re-run with --client-id (`himi site client list --site <msid>`) for both."
|
|
55419
|
+
);
|
|
55420
|
+
}
|
|
54683
55421
|
return {
|
|
54684
55422
|
book,
|
|
54685
55423
|
provisioningOverlay: plan.provisioning,
|
|
@@ -54797,6 +55535,7 @@ var init_analyze = __esm({
|
|
|
54797
55535
|
init_permissions();
|
|
54798
55536
|
init_published_html();
|
|
54799
55537
|
init_net_guard();
|
|
55538
|
+
init_placeholders();
|
|
54800
55539
|
SCREENSHOT_NAME = /^(home|shop|book|menu|blog|about|contact|events|gallery|plans|faq|library|members|other)-\d+\.png$/i;
|
|
54801
55540
|
}
|
|
54802
55541
|
});
|
|
@@ -54868,7 +55607,7 @@ function renderBookMarkdown(book) {
|
|
|
54868
55607
|
lines.push(`# Business book`);
|
|
54869
55608
|
lines.push("");
|
|
54870
55609
|
lines.push(`schema ${book.schemaVersion} \xB7 generated ${book.generatedAt}`);
|
|
54871
|
-
lines.push(`site: ${yn(book.input.siteUrl)} \xB7 msid: ${yn(book.input.msid)} \xB7 owner: ${book.input.hasOwner}`);
|
|
55610
|
+
lines.push(`site: ${yn(book.input.siteUrl)} \xB7 msid: ${yn(book.input.msid)} \xB7 owner: ${book.input.hasOwner}` + (book.input.clientId ? "" : book.input.hasOwner ? " \xB7 client: none \u2014 visitor-side probes skipped (owner side ran)" : " \xB7 client: none \u2014 URL-only pass, vertical probes skipped"));
|
|
54872
55611
|
lines.push("");
|
|
54873
55612
|
lines.push(`## Identity`);
|
|
54874
55613
|
lines.push(`- name: ${yn(id.businessName)} (${yn(id.siteDisplayName)})`);
|
|
@@ -54877,13 +55616,29 @@ function renderBookMarkdown(book) {
|
|
|
54877
55616
|
lines.push(`- language: site=${yn(id.language.site)} \xB7 business=${yn(id.language.business)}${id.language.site && id.language.business && id.language.site !== id.language.business ? " (mismatch)" : ""}`);
|
|
54878
55617
|
lines.push(`- locale: ${yn(id.locale.languageCode)}/${yn(id.locale.country)} ${yn(id.locale.currency)} ${yn(id.locale.timeZone)}`);
|
|
54879
55618
|
lines.push(`- logo: ${yn(id.logoUrl)}`);
|
|
54880
|
-
|
|
55619
|
+
const templated = new Set(
|
|
55620
|
+
(book.placeholders ?? []).filter((f) => f.kind === "template-contact").flatMap((f) => f.where).filter((w) => w.startsWith("identity.contact."))
|
|
55621
|
+
);
|
|
55622
|
+
const contactFlag = (field) => !id.contact[field] ? "no" : templated.has(`identity.contact.${field}`) ? "TEMPLATE PLACEHOLDER (not the business's)" : "yes";
|
|
55623
|
+
lines.push(`- contact (PII, do not log): address=${contactFlag("address")} email=${contactFlag("email")} phone=${contactFlag("phone")}`);
|
|
54881
55624
|
lines.push(`- source: ${id.source}`);
|
|
54882
55625
|
if (id.source === "crawl") {
|
|
54883
55626
|
lines.push(`- NAME IS A GUESS: no owner token, so the name above was read off the crawled page`);
|
|
54884
55627
|
lines.push(` \`<title>\` rather than the owner-entered business name. Verify it before it ships.`);
|
|
54885
55628
|
}
|
|
54886
55629
|
lines.push("");
|
|
55630
|
+
lines.push(`## Placeholders`);
|
|
55631
|
+
const placeholders = book.placeholders ?? [];
|
|
55632
|
+
if (!placeholders.length) {
|
|
55633
|
+
lines.push(!book.placeholders ? `- not checked (book written before this chapter existed)` : look.unavailable ? `- page text NOT checked \u2014 the crawl did not run (${look.unavailable}); only identity and catalog fields were scanned, and they showed none` : `- none detected (template contact values, editor text, a second business name, repeated images)`);
|
|
55634
|
+
} else {
|
|
55635
|
+
lines.push(`The site still carries TEMPLATE content. None of it is the business's \u2014 keep it out of the`);
|
|
55636
|
+
lines.push(`app, and tell the owner their site shows it. Sample content is never the deliverable.`);
|
|
55637
|
+
for (const f of placeholders) {
|
|
55638
|
+
lines.push(`- ${f.kind}: "${f.value}" \u2014 ${f.note} (${f.where.join(", ")})`);
|
|
55639
|
+
}
|
|
55640
|
+
}
|
|
55641
|
+
lines.push("");
|
|
54887
55642
|
lines.push(`## Copy`);
|
|
54888
55643
|
lines.push(`The customer's OWN words. Reuse these before inventing any \u2014 screen titles, tab`);
|
|
54889
55644
|
lines.push(`labels, section headings, CTA text, empty states. Write in \`${yn(copy.language)}\`.`);
|
|
@@ -55190,7 +55945,7 @@ var init_brand_font = __esm({
|
|
|
55190
55945
|
|
|
55191
55946
|
// src/site-analyze/write-artifacts.ts
|
|
55192
55947
|
import { mkdirSync as mkdirSync28, writeFileSync as writeFileSync25 } from "node:fs";
|
|
55193
|
-
import { join as
|
|
55948
|
+
import { join as join57 } from "node:path";
|
|
55194
55949
|
function attachVeloSources(book, sources, put) {
|
|
55195
55950
|
const byPath = new Map((sources ?? []).map((s) => [s.path, s.text]));
|
|
55196
55951
|
for (const f of book.velo.files) {
|
|
@@ -55345,12 +56100,12 @@ async function downloadMedia(book, fetchImpl, put) {
|
|
|
55345
56100
|
}
|
|
55346
56101
|
async function writeBusinessBook(result, opts) {
|
|
55347
56102
|
const out = opts.outDir;
|
|
55348
|
-
mkdirSync28(
|
|
55349
|
-
mkdirSync28(
|
|
56103
|
+
mkdirSync28(join57(out, "evidence/pages"), { recursive: true });
|
|
56104
|
+
mkdirSync28(join57(out, "media/catalog"), { recursive: true });
|
|
55350
56105
|
const files = [];
|
|
55351
56106
|
const put = (rel, body) => {
|
|
55352
|
-
const p =
|
|
55353
|
-
mkdirSync28(
|
|
56107
|
+
const p = join57(out, rel);
|
|
56108
|
+
mkdirSync28(join57(p, ".."), { recursive: true });
|
|
55354
56109
|
writeFileSync25(p, body);
|
|
55355
56110
|
files.push(rel);
|
|
55356
56111
|
};
|
|
@@ -55444,8 +56199,8 @@ var init_customer_build = __esm({
|
|
|
55444
56199
|
});
|
|
55445
56200
|
|
|
55446
56201
|
// src/site-analyze/apply.ts
|
|
55447
|
-
import { existsSync as
|
|
55448
|
-
import { dirname as dirname31, isAbsolute as isAbsolute4, join as
|
|
56202
|
+
import { existsSync as existsSync60, readFileSync as readFileSync71, writeFileSync as writeFileSync26, copyFileSync as copyFileSync3, mkdirSync as mkdirSync29, realpathSync as realpathSync7, statSync as statSync16 } from "node:fs";
|
|
56203
|
+
import { dirname as dirname31, isAbsolute as isAbsolute4, join as join58, resolve as resolve45, sep as sep14 } from "node:path";
|
|
55449
56204
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
55450
56205
|
function unpairedRedirectNote(overlay) {
|
|
55451
56206
|
if (!overlay.wix?.clientId || overlay.wix.redirectUri) return void 0;
|
|
@@ -55460,7 +56215,7 @@ function committedShellProvisioning(path2) {
|
|
|
55460
56215
|
function findRepoRoot(cwd) {
|
|
55461
56216
|
let dir = cwd;
|
|
55462
56217
|
for (let i = 0; i < 8; i++) {
|
|
55463
|
-
if (SHELL_NAMES2.some((name) =>
|
|
56218
|
+
if (SHELL_NAMES2.some((name) => existsSync60(join58(dir, shellAppDir(name), "package.json")))) return dir;
|
|
55464
56219
|
const next = dirname31(dir);
|
|
55465
56220
|
if (next === dir) break;
|
|
55466
56221
|
dir = next;
|
|
@@ -55528,11 +56283,11 @@ function mergeCustomerOwned(committed, overlay) {
|
|
|
55528
56283
|
}
|
|
55529
56284
|
function buildMergedContract(options) {
|
|
55530
56285
|
const { appDir: appDir2, packageDir, overlay } = options;
|
|
55531
|
-
const committedPath =
|
|
55532
|
-
if (!
|
|
56286
|
+
const committedPath = join58(appDir2, "provisioning.json");
|
|
56287
|
+
if (!existsSync60(committedPath)) {
|
|
55533
56288
|
throw new Error(`shell has no committed provisioning.json at ${committedPath} to build a contract from`);
|
|
55534
56289
|
}
|
|
55535
|
-
const committed = JSON.parse(
|
|
56290
|
+
const committed = JSON.parse(readFileSync71(committedPath, "utf8"));
|
|
55536
56291
|
const merged = mergeCustomerOwned(committed, overlay);
|
|
55537
56292
|
const overlayFontFamily = (overlay.branding ?? {}).fontFamily;
|
|
55538
56293
|
const branding = merged.branding ?? {};
|
|
@@ -55544,8 +56299,8 @@ function buildMergedContract(options) {
|
|
|
55544
56299
|
};
|
|
55545
56300
|
const stage = (fromRel, toRel) => {
|
|
55546
56301
|
const from = contained(packageDir, fromRel);
|
|
55547
|
-
const to = contained(
|
|
55548
|
-
if (!from || !to || !
|
|
56302
|
+
const to = contained(join58(appDir2, STAGED), toRel.slice(STAGED.length + 1));
|
|
56303
|
+
if (!from || !to || !existsSync60(from)) return void 0;
|
|
55549
56304
|
let real;
|
|
55550
56305
|
let realRoot;
|
|
55551
56306
|
try {
|
|
@@ -55567,11 +56322,11 @@ function buildMergedContract(options) {
|
|
|
55567
56322
|
};
|
|
55568
56323
|
const icon = stage("media/icon.png", `${STAGED}/icon.png`);
|
|
55569
56324
|
if (icon) branding.appIconPath = icon;
|
|
55570
|
-
const facesPath =
|
|
55571
|
-
if (
|
|
56325
|
+
const facesPath = join58(packageDir, "media/fonts/faces.json");
|
|
56326
|
+
if (existsSync60(facesPath)) {
|
|
55572
56327
|
let faces = [];
|
|
55573
56328
|
try {
|
|
55574
|
-
const parsed = JSON.parse(
|
|
56329
|
+
const parsed = JSON.parse(readFileSync71(facesPath, "utf8"));
|
|
55575
56330
|
faces = Array.isArray(parsed) ? parsed : [];
|
|
55576
56331
|
} catch {
|
|
55577
56332
|
faces = [];
|
|
@@ -55592,9 +56347,9 @@ function buildMergedContract(options) {
|
|
|
55592
56347
|
merged.branding = branding;
|
|
55593
56348
|
const body = `${JSON.stringify(merged, null, 2)}
|
|
55594
56349
|
`;
|
|
55595
|
-
const path2 =
|
|
56350
|
+
const path2 = join58(packageDir, "provisioning.contract.json");
|
|
55596
56351
|
writeFileSync26(path2, body);
|
|
55597
|
-
const localPath =
|
|
56352
|
+
const localPath = join58(appDir2, LOCAL_CONTRACT_REL);
|
|
55598
56353
|
mkdirSync29(dirname31(localPath), { recursive: true });
|
|
55599
56354
|
writeFileSync26(localPath, body);
|
|
55600
56355
|
staged.push(localPath);
|
|
@@ -55604,8 +56359,8 @@ async function applyOverlays(input) {
|
|
|
55604
56359
|
const cwd = resolve45(input.cwd);
|
|
55605
56360
|
const shell = input.shell ?? DEFAULT_BRANDABLE_SHELL;
|
|
55606
56361
|
assertKnownShell(shell);
|
|
55607
|
-
const overlay = JSON.parse(
|
|
55608
|
-
const tokens = JSON.parse(
|
|
56362
|
+
const overlay = JSON.parse(readFileSync71(input.overlayPath, "utf8"));
|
|
56363
|
+
const tokens = JSON.parse(readFileSync71(input.tokensPath, "utf8"));
|
|
55609
56364
|
const wrote = [];
|
|
55610
56365
|
const notes = [];
|
|
55611
56366
|
const repoRoot2 = findRepoRoot(cwd);
|
|
@@ -55615,7 +56370,7 @@ async function applyOverlays(input) {
|
|
|
55615
56370
|
`shell "${shell}" cannot bake a customer brand \u2014 it ships no prepare:customer script`
|
|
55616
56371
|
);
|
|
55617
56372
|
}
|
|
55618
|
-
const appDir2 =
|
|
56373
|
+
const appDir2 = join58(repoRoot2, shellAppDir(shell));
|
|
55619
56374
|
const packageDir = dirname31(resolve45(input.overlayPath));
|
|
55620
56375
|
const { path: contract, staged } = buildMergedContract({ appDir: appDir2, packageDir, overlay });
|
|
55621
56376
|
wrote.push(...staged);
|
|
@@ -55637,10 +56392,10 @@ async function applyOverlays(input) {
|
|
|
55637
56392
|
note: `prepare:customer --contract with a merged contract (committed provisioning.json untouched)${unpairedInRepo ? ` \xB7 ${unpairedInRepo}` : ""}`
|
|
55638
56393
|
};
|
|
55639
56394
|
}
|
|
55640
|
-
const pkgProv =
|
|
56395
|
+
const pkgProv = join58(cwd, "provisioning.json");
|
|
55641
56396
|
assertNotCommitted(pkgProv, input.forbiddenProvisioning);
|
|
55642
|
-
if (
|
|
55643
|
-
const cur = JSON.parse(
|
|
56397
|
+
if (existsSync60(pkgProv)) {
|
|
56398
|
+
const cur = JSON.parse(readFileSync71(pkgProv, "utf8"));
|
|
55644
56399
|
const merged = deepMerge4(cur, overlay);
|
|
55645
56400
|
writeFileSync26(pkgProv, JSON.stringify(merged, null, 2) + "\n");
|
|
55646
56401
|
wrote.push(pkgProv);
|
|
@@ -55648,9 +56403,9 @@ async function applyOverlays(input) {
|
|
|
55648
56403
|
writeFileSync26(pkgProv, JSON.stringify(overlay, null, 2) + "\n");
|
|
55649
56404
|
wrote.push(pkgProv);
|
|
55650
56405
|
}
|
|
55651
|
-
const pkgTokens =
|
|
55652
|
-
if (
|
|
55653
|
-
const cur = JSON.parse(
|
|
56406
|
+
const pkgTokens = join58(cwd, "tokens.json");
|
|
56407
|
+
if (existsSync60(pkgTokens) && (tokens.colors || tokens.typography)) {
|
|
56408
|
+
const cur = JSON.parse(readFileSync71(pkgTokens, "utf8"));
|
|
55654
56409
|
const merged = deepMerge4(cur, tokens);
|
|
55655
56410
|
const mergedColors = merged.colors;
|
|
55656
56411
|
if (mergedColors && typeof mergedColors === "object" && !Array.isArray(mergedColors)) {
|
|
@@ -55669,9 +56424,9 @@ async function applyOverlays(input) {
|
|
|
55669
56424
|
wrote.push(pkgTokens);
|
|
55670
56425
|
}
|
|
55671
56426
|
const homeAction = homeRefreshActionId(shell);
|
|
55672
|
-
const homeSrc =
|
|
55673
|
-
if (homeAction &&
|
|
55674
|
-
const prev =
|
|
56427
|
+
const homeSrc = join58(cwd, "dev/index.ts");
|
|
56428
|
+
if (homeAction && existsSync60(homeSrc)) {
|
|
56429
|
+
const prev = readFileSync71(homeSrc, "utf8");
|
|
55675
56430
|
const patched = patchBrandParams(prev, overlay, homeAction);
|
|
55676
56431
|
let next = patched.src;
|
|
55677
56432
|
if (!patched.foreign && overlay.installedVerticals?.length) {
|
|
@@ -55694,13 +56449,13 @@ async function applyOverlays(input) {
|
|
|
55694
56449
|
notes.push(`${patched.unparsed} onAppear params block(s) in ${homeSrc} could not be read \u2014 any brand values inside them were not applied`);
|
|
55695
56450
|
}
|
|
55696
56451
|
}
|
|
55697
|
-
if (!input.iconPath || !
|
|
56452
|
+
if (!input.iconPath || !existsSync60(input.iconPath)) {
|
|
55698
56453
|
const book = input.iconPath ? dirname31(dirname31(resolve45(input.iconPath))) : void 0;
|
|
55699
56454
|
notes.push(
|
|
55700
56455
|
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"
|
|
55701
56456
|
);
|
|
55702
56457
|
}
|
|
55703
|
-
if (input.iconPath &&
|
|
56458
|
+
if (input.iconPath && existsSync60(input.iconPath)) {
|
|
55704
56459
|
try {
|
|
55705
56460
|
const installed = await installIcon(cwd, input.iconPath, { derivePlay: true });
|
|
55706
56461
|
wrote.push(...installed.wrote);
|
|
@@ -58713,31 +59468,47 @@ function ctasOf(texts) {
|
|
|
58713
59468
|
return out.slice(0, 8);
|
|
58714
59469
|
}
|
|
58715
59470
|
function copyFromEval(evaled) {
|
|
59471
|
+
const templateText = dedupe2(
|
|
59472
|
+
[
|
|
59473
|
+
...(evaled.sections ?? []).flatMap((s) => [s?.heading, s?.body]),
|
|
59474
|
+
...(evaled.faq ?? []).flatMap((f) => [f?.q, f?.a]),
|
|
59475
|
+
...evaled.ctaLabels ?? [],
|
|
59476
|
+
...evaled.testimonials ?? [],
|
|
59477
|
+
evaled.about,
|
|
59478
|
+
evaled.meta?.description,
|
|
59479
|
+
evaled.meta?.ogTitle,
|
|
59480
|
+
evaled.meta?.ogDescription
|
|
59481
|
+
].map((raw) => {
|
|
59482
|
+
const text5 = cleanText(raw, 400);
|
|
59483
|
+
return text5 && isTemplatePlaceholder(text5) ? stripPii(cleanText(text5, 90)) : "";
|
|
59484
|
+
}),
|
|
59485
|
+
8
|
|
59486
|
+
);
|
|
58716
59487
|
const sections = [];
|
|
58717
59488
|
for (const raw of evaled.sections ?? []) {
|
|
58718
|
-
const heading = copyOrDrop(raw?.heading,
|
|
59489
|
+
const heading = copyOrDrop(raw?.heading, CAP4.heading);
|
|
58719
59490
|
if (!heading) continue;
|
|
58720
|
-
const body = copyOrDrop(raw?.body,
|
|
59491
|
+
const body = copyOrDrop(raw?.body, CAP4.body);
|
|
58721
59492
|
sections.push(body ? { heading, body } : { heading });
|
|
58722
|
-
if (sections.length >=
|
|
59493
|
+
if (sections.length >= CAP4.sections) break;
|
|
58723
59494
|
}
|
|
58724
59495
|
const faq = [];
|
|
58725
59496
|
for (const raw of evaled.faq ?? []) {
|
|
58726
|
-
const q = copyOrDrop(raw?.q,
|
|
58727
|
-
const a = copyOrDrop(raw?.a,
|
|
59497
|
+
const q = copyOrDrop(raw?.q, CAP4.q);
|
|
59498
|
+
const a = copyOrDrop(raw?.a, CAP4.a);
|
|
58728
59499
|
if (q && a && q !== a) faq.push({ q, a });
|
|
58729
|
-
if (faq.length >=
|
|
59500
|
+
if (faq.length >= CAP4.faq) break;
|
|
58730
59501
|
}
|
|
58731
|
-
const ctaLabels = dedupe2((evaled.ctaLabels ?? []).map((c) => copyOrDrop(c,
|
|
59502
|
+
const ctaLabels = dedupe2((evaled.ctaLabels ?? []).map((c) => copyOrDrop(c, CAP4.cta)), CAP4.ctas);
|
|
58732
59503
|
const testimonials = dedupe2(
|
|
58733
|
-
(evaled.testimonials ?? []).map((t) => copyOrDrop(t,
|
|
58734
|
-
|
|
59504
|
+
(evaled.testimonials ?? []).map((t) => copyOrDrop(t, CAP4.testimonial)),
|
|
59505
|
+
CAP4.testimonials
|
|
58735
59506
|
);
|
|
58736
|
-
const about = copyOrDrop(evaled.about,
|
|
59507
|
+
const about = copyOrDrop(evaled.about, CAP4.about);
|
|
58737
59508
|
const meta = {};
|
|
58738
|
-
const description = copyOrDrop(evaled.meta?.description,
|
|
58739
|
-
const ogTitle = copyOrDrop(evaled.meta?.ogTitle,
|
|
58740
|
-
const ogDescription = copyOrDrop(evaled.meta?.ogDescription,
|
|
59509
|
+
const description = copyOrDrop(evaled.meta?.description, CAP4.meta);
|
|
59510
|
+
const ogTitle = copyOrDrop(evaled.meta?.ogTitle, CAP4.meta);
|
|
59511
|
+
const ogDescription = copyOrDrop(evaled.meta?.ogDescription, CAP4.meta);
|
|
58741
59512
|
if (description) meta.description = description;
|
|
58742
59513
|
if (ogTitle) meta.ogTitle = ogTitle;
|
|
58743
59514
|
if (ogDescription) meta.ogDescription = ogDescription;
|
|
@@ -58747,7 +59518,8 @@ function copyFromEval(evaled) {
|
|
|
58747
59518
|
...faq.length ? { faq } : {},
|
|
58748
59519
|
...testimonials.length ? { testimonials } : {},
|
|
58749
59520
|
...about ? { about } : {},
|
|
58750
|
-
...Object.keys(meta).length ? { meta } : {}
|
|
59521
|
+
...Object.keys(meta).length ? { meta } : {},
|
|
59522
|
+
...templateText.length ? { templateText } : {}
|
|
58751
59523
|
};
|
|
58752
59524
|
}
|
|
58753
59525
|
function forwardedRequestHeaders(all) {
|
|
@@ -59011,7 +59783,7 @@ async function createPlaywrightBrowser(load = () => import("playwright"), siteFe
|
|
|
59011
59783
|
};
|
|
59012
59784
|
return { port, screenshots, siteFetch, pin };
|
|
59013
59785
|
}
|
|
59014
|
-
var PLAYWRIGHT_HINT, PAGE_EVAL,
|
|
59786
|
+
var PLAYWRIGHT_HINT, PAGE_EVAL, CAP4, DOCUMENT_FETCH_TIMEOUT_MS, MAX_DOCUMENT_BYTES, SUBRESOURCE_PIN_TIMEOUT_MS, NON_NETWORK_SCHEMES, FORWARDED_REQUEST_HEADERS;
|
|
59015
59787
|
var init_crawl_look = __esm({
|
|
59016
59788
|
"src/site-analyze/crawl-look.ts"() {
|
|
59017
59789
|
init_dist();
|
|
@@ -59206,7 +59978,7 @@ var init_crawl_look = __esm({
|
|
|
59206
59978
|
} catch (e4) {}
|
|
59207
59979
|
return { wst, nav, headings, hero, imgs, hrefs, buttons, html, htmlLang, velo, sections, ctaLabels, faq, testimonials, about, meta };
|
|
59208
59980
|
})()`;
|
|
59209
|
-
|
|
59981
|
+
CAP4 = {
|
|
59210
59982
|
heading: 120,
|
|
59211
59983
|
body: 300,
|
|
59212
59984
|
cta: 80,
|
|
@@ -59604,7 +60376,7 @@ async function veloCall(fetchImpl, method, url, opts = {}) {
|
|
|
59604
60376
|
}
|
|
59605
60377
|
return { status: res.status, json: json5, text: text5 };
|
|
59606
60378
|
}
|
|
59607
|
-
function
|
|
60379
|
+
function snippet2(x, cap = 180) {
|
|
59608
60380
|
const s = typeof x === "string" ? x : JSON.stringify(x) ?? "";
|
|
59609
60381
|
return s.replace(/\s+/g, " ").slice(0, cap);
|
|
59610
60382
|
}
|
|
@@ -59627,7 +60399,7 @@ async function resolveGridAppId(fetchImpl, token, msid, siteUrl) {
|
|
|
59627
60399
|
return { gridAppId: app.id, source: "lifecycle-provision", mutable: app.mutable !== false };
|
|
59628
60400
|
}
|
|
59629
60401
|
if (publishedId) return { gridAppId: publishedId, source: "published-html", mutable: false };
|
|
59630
|
-
return { source: `provision ${provisioned.status}: ${
|
|
60402
|
+
return { source: `provision ${provisioned.status}: ${snippet2(provisioned.json ?? provisioned.text)}` };
|
|
59631
60403
|
}
|
|
59632
60404
|
function sameVeloPath(listed, wanted) {
|
|
59633
60405
|
const n = (p) => p.replace(/^\.?\//, "");
|
|
@@ -59724,7 +60496,7 @@ async function runSiteFunction(opts) {
|
|
|
59724
60496
|
revision: snap.revision,
|
|
59725
60497
|
codeAppId: snap.codeAppId,
|
|
59726
60498
|
publish: { revision: httpOk(snap.rev), rc: httpOk(snap.rc), live: httpOk(snap.live), status: snap.live?.status },
|
|
59727
|
-
error: ok ? void 0 :
|
|
60499
|
+
error: ok ? void 0 : snippet2(snap.live?.json ?? snap.rev.json)
|
|
59728
60500
|
};
|
|
59729
60501
|
}
|
|
59730
60502
|
const { id, listed } = await withGrid(fetchImpl, opts.token, opts.msid, opts.siteUrl);
|
|
@@ -59769,7 +60541,7 @@ async function runSiteFunction(opts) {
|
|
|
59769
60541
|
next
|
|
59770
60542
|
);
|
|
59771
60543
|
if (!httpOk(patched)) {
|
|
59772
|
-
return { ...base, error: `UpdateFiles ${patched.status}: ${
|
|
60544
|
+
return { ...base, error: `UpdateFiles ${patched.status}: ${snippet2(patched.json ?? patched.text)}` };
|
|
59773
60545
|
}
|
|
59774
60546
|
let report2 = {
|
|
59775
60547
|
...base,
|
|
@@ -59786,7 +60558,7 @@ async function runSiteFunction(opts) {
|
|
|
59786
60558
|
revision: snap.revision,
|
|
59787
60559
|
codeAppId: snap.codeAppId,
|
|
59788
60560
|
publish: { revision: httpOk(snap.rev), rc: httpOk(snap.rc), live: httpOk(snap.live), status: snap.live?.status },
|
|
59789
|
-
error: pubOk ? report2.error :
|
|
60561
|
+
error: pubOk ? report2.error : snippet2(snap.live?.json ?? snap.rev.json)
|
|
59790
60562
|
};
|
|
59791
60563
|
}
|
|
59792
60564
|
if (opts.invoke) {
|
|
@@ -59823,8 +60595,8 @@ async function invokeAndReport(fetchImpl, opts, base, name, method) {
|
|
|
59823
60595
|
return {
|
|
59824
60596
|
...base,
|
|
59825
60597
|
ok,
|
|
59826
|
-
invoke: { url: hit.url, status: hit.r.status, body: hit.r.json ??
|
|
59827
|
-
error: ok ? void 0 : `invoke ${hit.r.status}: ${
|
|
60598
|
+
invoke: { url: hit.url, status: hit.r.status, body: hit.r.json ?? snippet2(hit.r.text) },
|
|
60599
|
+
error: ok ? void 0 : `invoke ${hit.r.status}: ${snippet2(hit.r.json ?? hit.r.text)}`
|
|
59828
60600
|
};
|
|
59829
60601
|
}
|
|
59830
60602
|
var HTTP_METHODS2, WRITE_LAYOUTS, VELO_PROVISION_URL, SITE_PUBLISH_URL, PUBLISH_RC_URL, SITE_FUNCTION_USAGE, NAME_RE, EXPORT_HEAD, WIX_HTTP_IMPORT_LINE;
|
|
@@ -59849,18 +60621,31 @@ var init_site_function = __esm({
|
|
|
59849
60621
|
// src/site-analyze/cli.ts
|
|
59850
60622
|
var cli_exports = {};
|
|
59851
60623
|
__export(cli_exports, {
|
|
60624
|
+
APPLY_NEEDS_CLIENT: () => APPLY_NEEDS_CLIENT,
|
|
60625
|
+
REDIRECT_NEEDS_CLIENT: () => REDIRECT_NEEDS_CLIENT,
|
|
59852
60626
|
SITE_FUNCTION_USAGE: () => SITE_FUNCTION_USAGE,
|
|
59853
60627
|
assetFetchFor: () => assetFetchFor,
|
|
59854
60628
|
noteWithWarnings: () => noteWithWarnings,
|
|
60629
|
+
ownerSiteFor: () => ownerSiteFor,
|
|
59855
60630
|
runSiteAnalyze: () => runSiteAnalyze,
|
|
59856
60631
|
runSiteFunctionCli: () => runSiteFunctionCli
|
|
59857
60632
|
});
|
|
59858
|
-
import { readFileSync as
|
|
60633
|
+
import { readFileSync as readFileSync72 } from "node:fs";
|
|
59859
60634
|
import { resolve as resolve46 } from "node:path";
|
|
59860
60635
|
function assetFetchFor(_opts) {
|
|
59861
60636
|
return pinnedFetch2;
|
|
59862
60637
|
}
|
|
60638
|
+
function ownerSiteFor(opts, env = process.env) {
|
|
60639
|
+
const flag = opts.siteFlag?.trim();
|
|
60640
|
+
if (flag) return flag;
|
|
60641
|
+
if (!opts.clientId?.trim() || opts.explicitClient !== true) return void 0;
|
|
60642
|
+
return env.WIX_SITE_ID?.trim() || void 0;
|
|
60643
|
+
}
|
|
59863
60644
|
async function runSiteAnalyze(opts) {
|
|
60645
|
+
if (!opts.clientId?.trim()) {
|
|
60646
|
+
if (opts.apply) throw Object.assign(new Error(APPLY_NEEDS_CLIENT), { exit: 2 });
|
|
60647
|
+
if (opts.redirectUri?.trim()) throw Object.assign(new Error(REDIRECT_NEEDS_CLIENT), { exit: 2 });
|
|
60648
|
+
}
|
|
59864
60649
|
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
59865
60650
|
const assetFetch = assetFetchFor(opts);
|
|
59866
60651
|
const siteFetch = guardedSiteFetch;
|
|
@@ -59868,9 +60653,11 @@ async function runSiteAnalyze(opts) {
|
|
|
59868
60653
|
const outDir = resolve46(cwd, opts.outDir ?? ".himi/business-book");
|
|
59869
60654
|
let ownerAuth;
|
|
59870
60655
|
let msid;
|
|
60656
|
+
const ownerSite = ownerSiteFor(opts);
|
|
59871
60657
|
try {
|
|
59872
|
-
|
|
59873
|
-
const token = await siteToken(
|
|
60658
|
+
if (!ownerSite) throw new Error("no owner site for this run");
|
|
60659
|
+
const token = await siteToken(ownerSite);
|
|
60660
|
+
msid = ownerSite;
|
|
59874
60661
|
ownerAuth = { token, msid };
|
|
59875
60662
|
} catch {
|
|
59876
60663
|
msid = opts.siteFlag?.trim() || void 0;
|
|
@@ -59942,7 +60729,7 @@ async function runSiteFunctionCli(opts) {
|
|
|
59942
60729
|
let source;
|
|
59943
60730
|
if (opts.sourcePath) {
|
|
59944
60731
|
const p = resolve46(opts.cwd ?? process.cwd(), opts.sourcePath);
|
|
59945
|
-
source =
|
|
60732
|
+
source = readFileSync72(p, "utf8");
|
|
59946
60733
|
}
|
|
59947
60734
|
let body;
|
|
59948
60735
|
if (opts.bodyRaw != null) {
|
|
@@ -59969,7 +60756,7 @@ async function runSiteFunctionCli(opts) {
|
|
|
59969
60756
|
fetchImpl: opts.fetchImpl
|
|
59970
60757
|
});
|
|
59971
60758
|
}
|
|
59972
|
-
var FUNCTION_OPS;
|
|
60759
|
+
var APPLY_NEEDS_CLIENT, FUNCTION_OPS;
|
|
59973
60760
|
var init_cli = __esm({
|
|
59974
60761
|
"src/site-analyze/cli.ts"() {
|
|
59975
60762
|
init_analyze();
|
|
@@ -59980,6 +60767,8 @@ var init_cli = __esm({
|
|
|
59980
60767
|
init_rest();
|
|
59981
60768
|
init_wix_owner();
|
|
59982
60769
|
init_site_function();
|
|
60770
|
+
init_types2();
|
|
60771
|
+
APPLY_NEEDS_CLIENT = "--apply needs --client-id: the applied app must be bound to the site's own Headless client, and a URL-only run has none. `himi site client list --site <msid>` shows the site's clients (`himi site client ensure --site <msid> --yes` mints one); WIX_CLIENT_ID is read as a fallback.";
|
|
59983
60772
|
FUNCTION_OPS = ["list", "get", "put", "publish", "invoke"];
|
|
59984
60773
|
}
|
|
59985
60774
|
});
|
|
@@ -60199,7 +60988,7 @@ __export(site_create_exports, {
|
|
|
60199
60988
|
runSiteList: () => runSiteList,
|
|
60200
60989
|
writeProvisioningBinding: () => writeProvisioningBinding
|
|
60201
60990
|
});
|
|
60202
|
-
import { existsSync as
|
|
60991
|
+
import { existsSync as existsSync61, readFileSync as readFileSync73, writeFileSync as writeFileSync27 } from "node:fs";
|
|
60203
60992
|
import { resolve as resolvePath2 } from "node:path";
|
|
60204
60993
|
function oauthClientName(projectName) {
|
|
60205
60994
|
return `${projectName} client`;
|
|
@@ -60348,7 +61137,7 @@ async function runSiteCreate(opts) {
|
|
|
60348
61137
|
if (!wantOauthApp) return { ...base, nextSteps: nextSteps(metaSiteId) };
|
|
60349
61138
|
return { ...base, clientId, redirectUri, nextSteps: nextSteps(metaSiteId, clientId) };
|
|
60350
61139
|
}
|
|
60351
|
-
function writeProvisioningBinding(target, binding2, fs = { existsSync:
|
|
61140
|
+
function writeProvisioningBinding(target, binding2, fs = { existsSync: existsSync61, readFileSync: readFileSync73, writeFileSync: writeFileSync27 }) {
|
|
60352
61141
|
const msid = binding2.siteId;
|
|
60353
61142
|
const path2 = resolvePath2(target);
|
|
60354
61143
|
const committed = committedShellProvisioning(path2);
|
|
@@ -61021,11 +61810,11 @@ var init_context = __esm({
|
|
|
61021
61810
|
});
|
|
61022
61811
|
|
|
61023
61812
|
// src/cli.ts
|
|
61024
|
-
import { mkdtempSync as mkdtempSync4, readFileSync as
|
|
61813
|
+
import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync74, mkdirSync as mkdirSync30, writeFileSync as writeFileSync28, existsSync as existsSync62, rmSync as rmSync14, readdirSync as readdirSync27, statSync as statSync17, lstatSync as lstatSync9, accessSync, constants as constants2, renameSync as renameSync6, cpSync as cpSync3 } from "node:fs";
|
|
61025
61814
|
import { execFile, execFileSync as execFileSync7, spawnSync as spawnSync5, spawn as spawn6 } from "node:child_process";
|
|
61026
61815
|
import { createHash as createHash27, randomUUID as randomUUID5 } from "node:crypto";
|
|
61027
61816
|
import { tmpdir as tmpdir5, homedir as homedir7, hostname } from "node:os";
|
|
61028
|
-
import { join as
|
|
61817
|
+
import { join as join59, resolve as resolve47, relative as relative10, basename as basename14, dirname as dirname32 } from "node:path";
|
|
61029
61818
|
import { fileURLToPath as fileURLToPath24 } from "node:url";
|
|
61030
61819
|
|
|
61031
61820
|
// ../serve-cli/src/client.ts
|
|
@@ -64318,8 +65107,8 @@ var str6 = (v) => typeof v === "string" ? v : void 0;
|
|
|
64318
65107
|
var num2 = (v) => typeof v === "string" && v !== "" && Number.isFinite(Number(v)) ? Number(v) : void 0;
|
|
64319
65108
|
function embeddedTemplateCatalog() {
|
|
64320
65109
|
return availableTemplates().map((name) => {
|
|
64321
|
-
const path2 =
|
|
64322
|
-
const meta = JSON.parse(
|
|
65110
|
+
const path2 = join59(templateSourceDir(name), TEMPLATE_META_FILE);
|
|
65111
|
+
const meta = JSON.parse(readFileSync74(path2, "utf8"));
|
|
64323
65112
|
if (!meta || typeof meta.title !== "string" || typeof meta.description !== "string" || !Array.isArray(meta.tags)) {
|
|
64324
65113
|
throw new Error(`${path2} must be { title: string, description: string, tags: string[], category?: string }`);
|
|
64325
65114
|
}
|
|
@@ -64833,11 +65622,14 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
|
|
|
64833
65622
|
refuses a WEB client \u2014 so a WEB one carrying your
|
|
64834
65623
|
redirect looks right and is not a candidate.
|
|
64835
65624
|
himi site analyze --read-only --site <msid> [--client-id <id>] [--json]
|
|
64836
|
-
himi site analyze --
|
|
65625
|
+
himi site analyze --url <https://\u2026> [--client-id <id>] [--site <msid>] [--out <dir>] [--apply]
|
|
64837
65626
|
[--shell ${SHELL_ENUM}]
|
|
64838
65627
|
collect a Wix business book (APIs + Playwright look) and
|
|
64839
65628
|
optionally bake identity/verticals/palette/homeLayout into
|
|
64840
|
-
a brandable shell's content package. --
|
|
65629
|
+
a brandable shell's content package. --url alone is the
|
|
65630
|
+
visitor-only pass (published pages, look, copy); --client-id
|
|
65631
|
+
adds the vertical catalog counts and the app binding, and
|
|
65632
|
+
--apply requires it. --shell takes the same
|
|
64841
65633
|
names 'himi dist --shell' does; default branded-lite. Owner token: WIX_TEST_TOKEN
|
|
64842
65634
|
or 'wix token --site'. Look/screenshots need Chromium:
|
|
64843
65635
|
npx playwright install chromium.
|
|
@@ -64948,7 +65740,7 @@ var COMMANDS = [
|
|
|
64948
65740
|
{ name: "login", summary: "obtain a scoped serve-control token from Wix identity and store it in ~/.himalaya/serve-targets.json (so push/promote need no hand-pasted token). Three modes: --browser (your own Wix account, no VPN/BO), --wix (HEADLESS \u2014 the machine's own Wix CLI credential; the mode a CI pod or agent container can satisfy), --dpx (Wix employee, reads ~/.dpx/session/token). RFC 0026 WS3.", required: "[--browser|--wix|--dpx] [--target <t>] [--issue-url <url>]" },
|
|
64949
65741
|
{ name: "logout", summary: "remove the stored control token for a target", required: "[--target <t>]" },
|
|
64950
65742
|
{ name: "notify", summary: "`setup` optionally configures Branded/Ping from local customer key files; `status --refresh` reads live backend readiness. Setup may be deferred while building. These use serve-control and require owner plus Wix account authentication. `send`, `tokens`, `doctor`: send a REAL push notification to registered devices (RFC 0036 WS5) \u2014 APNs .p8 over HTTP/2 for iOS, FCM v1 for Android. `send` targets one device (--token / --device <registry id>) or fans out to the whole app (--all), reporting a per-device result; a token the provider says is uninstalled (APNs 410 Unregistered / FCM UNREGISTERED) is auto-disabled, while a merely wrong one (BadDeviceToken \u2014 usually a sandbox/production mismatch) is recorded and left enabled. `tokens` lists the registry. `doctor` reports which credentials resolve and which sender each platform picks. Talks to the admin-server via --admin-url/HIMALAYA_ADMIN_URL, authenticated with --admin-session/HIMALAYA_ADMIN_SESSION. NOT `himi push`, which publishes a release.", required: "setup|status [--content <dir>] [--target <t>] [--refresh] [--yes] [--no-push-setup] | send|tokens|doctor [--app <a>] [--token <t> | --device <id> | --all] [--title <s>] [--body <s>] [--link <url>] [--platform ios|android] [--badge <n>] [--channel <id>] [--silent] [--dry-run] [--json]" },
|
|
64951
|
-
{ name: "site", summary: "PROVISION a Wix project, then analyze or extend it. `create` is the one door that makes a site instead of adopting one: POST /funnel/projects/v1/create (a WIX site, a HEADLESS backend, a BRANDED_APP, or a VIBE site), and for headless it also mints the OAuth app whose id IS the `WIX_CLIENT_ID` \u2014 with --redirect-uri already registered, because an unregistered redirect makes native signInDirect fail at redirect-session. `--verticals` REQUIRES `--template` and reports only what Wix confirmed: measured, installing onto a project created from the BLANK template returns 200 while the vertical's API answers 428 forever, because there is no site for it to attach to (the install asks for CREATE_SITE). A real template ships its verticals installed and populated, and installing further ones onto it then works. It MUTATES your Wix account and needs --yes; without it you get the payload and nothing is sent. `list` is the read-only site inventory (with each site's premium flag, which is what explains an installed-but-428 vertical). Auth is the account-scoped `wix token` (no --site), falling back to WIX_API_KEY + WIX_ACCOUNT_ID. `client` is the same OAuth step for a site that ALREADY exists \u2014 the one himi adopts rather than makes \u2014 so a clientId no longer means a manual trip to the dashboard: `client ensure` reconciles rather than mints, because a site can already carry a client with NO registered redirect and shipping that one fails signInDirect at runtime; it reuses a client that carries --redirect-uri, PATCHes one that matches --name but lacks it (unioning, so another app's redirect survives), and creates only when there is nothing to reuse (--new forces a fresh one). --name IS the idempotency key. `client` auth is SITE-scoped (`wix token --site <msid>`) because minting is owner-of-that-site, and --yes gates every mutation: a site that already has a usable client resolves WITHOUT it, but --write-provisioning needs --yes even then because it rewrites a manifest on disk (the dry run's planned.provisioning names the file). That query endpoint IGNORES paging (measured: query.paging, cursorPaging and a top-level paging all return the full set at offset 0), so when pagingMetadata reports more clients than came back, `ensure` REFUSES EVERY outcome \u2014 create, patch AND reuse. Reuse is refused too because pickClient breaks ties on the OLDEST createdDate, so an omitted older same-named MOBILE client with the same redirect would win a later complete read and the resolved clientId would MOVE between runs \u2014 and it gets written into provisioning.json; convergence is what makes a stray duplicate untidy rather than harmful. --name cannot narrow the query (no filter is sent; the name is applied to the rows after they arrive), so the recovery is the dashboard; --new skips the query entirely. A `patched` result is verified against what Wix STORED \u2014 the redirect list is read off the PATCH response, and re-read via GET when the response omits it, because falling back to the list himi just sent would make the guard pass vacuously on exactly the silent no-op it exists to catch. `client list` is the read-only inventory of a site's clients: act on its `shippable` column rather than `hasRedirect`, because shippable ALSO requires a MOBILE applicationType and `ensure` refuses a WEB client \u2014 a WEB one carrying your redirect looks right and is not a candidate \u2014 and it sets truncated:true rather than presenting a partial inventory as the whole one. `analyze --read-only` returns API-only generation context as JSON (identity, access probes, CMS permissions and selected redacted Velo source); it needs no URL/browser and never uploads or applies anything. `analyze` reads a site into a business-book folder (REST + Playwright, GET-only); `site function` list/get/put/publish/invokes that site's Velo HTTP functions and is not `himi functions` (serve-plane jobs). `--apply` bakes into a brandable shell; `--shell` takes the same names `himi dist --shell` does and defaults to branded-lite, and a shell that ships no prepare:customer is refused by name rather than half-built. It never overwrites any shell's committed apps/<shell>/provisioning.json.", required: "create <name> [--type wix|headless|branded-app|vibe] [--template <guid>] [--verticals stores,bookings,\u2026] [--folder <guid>] [--redirect-uri <uri>] [--no-oauth-app] [--write-provisioning [path]] [--site-url <url>] [--json] --yes | list | client ensure|list --site <msid> [--name <name>] [--redirect-uri <uri>] [--new] [--write-provisioning [path]] [--site-url <url>] [--json] --yes | analyze --read-only [--site <msid>] [--client-id <id>] [--json] | analyze --
|
|
65743
|
+
{ name: "site", summary: "PROVISION a Wix project, then analyze or extend it. `create` is the one door that makes a site instead of adopting one: POST /funnel/projects/v1/create (a WIX site, a HEADLESS backend, a BRANDED_APP, or a VIBE site), and for headless it also mints the OAuth app whose id IS the `WIX_CLIENT_ID` \u2014 with --redirect-uri already registered, because an unregistered redirect makes native signInDirect fail at redirect-session. `--verticals` REQUIRES `--template` and reports only what Wix confirmed: measured, installing onto a project created from the BLANK template returns 200 while the vertical's API answers 428 forever, because there is no site for it to attach to (the install asks for CREATE_SITE). A real template ships its verticals installed and populated, and installing further ones onto it then works. It MUTATES your Wix account and needs --yes; without it you get the payload and nothing is sent. `list` is the read-only site inventory (with each site's premium flag, which is what explains an installed-but-428 vertical). Auth is the account-scoped `wix token` (no --site), falling back to WIX_API_KEY + WIX_ACCOUNT_ID. `client` is the same OAuth step for a site that ALREADY exists \u2014 the one himi adopts rather than makes \u2014 so a clientId no longer means a manual trip to the dashboard: `client ensure` reconciles rather than mints, because a site can already carry a client with NO registered redirect and shipping that one fails signInDirect at runtime; it reuses a client that carries --redirect-uri, PATCHes one that matches --name but lacks it (unioning, so another app's redirect survives), and creates only when there is nothing to reuse (--new forces a fresh one). --name IS the idempotency key. `client` auth is SITE-scoped (`wix token --site <msid>`) because minting is owner-of-that-site, and --yes gates every mutation: a site that already has a usable client resolves WITHOUT it, but --write-provisioning needs --yes even then because it rewrites a manifest on disk (the dry run's planned.provisioning names the file). That query endpoint IGNORES paging (measured: query.paging, cursorPaging and a top-level paging all return the full set at offset 0), so when pagingMetadata reports more clients than came back, `ensure` REFUSES EVERY outcome \u2014 create, patch AND reuse. Reuse is refused too because pickClient breaks ties on the OLDEST createdDate, so an omitted older same-named MOBILE client with the same redirect would win a later complete read and the resolved clientId would MOVE between runs \u2014 and it gets written into provisioning.json; convergence is what makes a stray duplicate untidy rather than harmful. --name cannot narrow the query (no filter is sent; the name is applied to the rows after they arrive), so the recovery is the dashboard; --new skips the query entirely. A `patched` result is verified against what Wix STORED \u2014 the redirect list is read off the PATCH response, and re-read via GET when the response omits it, because falling back to the list himi just sent would make the guard pass vacuously on exactly the silent no-op it exists to catch. `client list` is the read-only inventory of a site's clients: act on its `shippable` column rather than `hasRedirect`, because shippable ALSO requires a MOBILE applicationType and `ensure` refuses a WEB client \u2014 a WEB one carrying your redirect looks right and is not a candidate \u2014 and it sets truncated:true rather than presenting a partial inventory as the whole one. `analyze --read-only` returns API-only generation context as JSON (identity, access probes, CMS permissions and selected redacted Velo source); it needs no URL/browser and never uploads or applies anything. `analyze` reads a site into a business-book folder (REST + Playwright, GET-only); `--url` alone is the visitor-only pass over the published pages, and `--client-id` adds the vertical probes and the app binding `--apply` requires; `site function` list/get/put/publish/invokes that site's Velo HTTP functions and is not `himi functions` (serve-plane jobs). `--apply` bakes into a brandable shell; `--shell` takes the same names `himi dist --shell` does and defaults to branded-lite, and a shell that ships no prepare:customer is refused by name rather than half-built. It never overwrites any shell's committed apps/<shell>/provisioning.json.", required: "create <name> [--type wix|headless|branded-app|vibe] [--template <guid>] [--verticals stores,bookings,\u2026] [--folder <guid>] [--redirect-uri <uri>] [--no-oauth-app] [--write-provisioning [path]] [--site-url <url>] [--json] --yes | list | client ensure|list --site <msid> [--name <name>] [--redirect-uri <uri>] [--new] [--write-provisioning [path]] [--site-url <url>] [--json] --yes | analyze --read-only [--site <msid>] [--client-id <id>] [--json] | analyze --url <https> [--client-id <id>] [--site <msid>] [--out <dir>] [--redirect-uri <uri>] [--apply] [--shell " + SHELL_ENUM + "] | function list|get|put|publish|invoke [--site <msid>] [--url <https>] [--method GET|POST|PUT|DELETE] [--source <file>] [--body <json>] [--publish] [--invoke]" },
|
|
64952
65744
|
{ name: "doctor", summary: 'off-VPN preflight in one shot: probe the PUBLIC data plane (www.wixapis.com \u2014 reachable off-VPN), the INTERNAL serve/control plane for the selected target (VPN-gated), and report auth state (dpx session on disk + stored control token). --dpx additionally runs a live, EADDRINUSE-safe `dpx whoami`. Machine-readable with --json (an unreachable internal plane carries a stable code:"needs_vpn" so an agent branches on the code, not the prose); human-readable otherwise. Never loads the authoring runtime \u2014 works off-repo.', required: "[--target <t>] [--dpx] [--json] [--data-url <url>] [--timeout <ms>]" },
|
|
64953
65745
|
{ name: "upgrade", summary: "install the newest published CLI (`npm i -g @wix/himalaya-cli@latest`) and report what moved. This is the explicit door: himi also updates itself when the running build is more than a week old \u2014 unattended it just does it and re-runs your command, at a terminal it asks first \u2014 and `HIMI_NO_UPDATE_CHECK=1` turns that off, leaving this command as the way to catch up. Reports `unchanged` rather than claiming success when npm exits 0 without moving the version, which is what a registry mirror serving its own pinned copy looks like.", required: "[--json]" },
|
|
64954
65746
|
{ name: "push", summary: "lint + build + publish a release (default --draft: servable via ?release= but NOT live). REFUSES to publish on any error unless --force; --strict promotes warnings. Prints preview + agent-context links. The published slug is NAMESPACED per owner \u2014 `<ownerPrefix>.<name>`, composed offline from the control token's ownerPrefix claim, so the CLI and the server derive the identical string and himalaya.content.json is NOT rewritten (a legacy token with no ownerPrefix publishes the declared name unchanged). An app claimed BEFORE namespacing is stored under its FLAT slug, so the claim route answers `alreadyYours` naming that slug and the push adopts it \u2014 reported as `adoptedSlug`, since it is the one case where the published `app` differs from what the declared name composes to. `--no-claim` skips the route that knows this, so a pre-namespacing app pushed with it still fails 403. --visibility public|unlisted decides whether /v1/apps + the Himi Player picker LIST the app (also declarable as `visibility` in himalaya.content.json; omitted, a brand-new app defaults to unlisted \u2014 share by link \u2014 and an existing setting is kept). --account-id names which account owns the app when your Wix session resolves to several (the auto-claim of a brand-new slug cannot guess \u2014 without it a multi-account caller is told to name one). An unforced push of a release that carries SCREENS also refuses when `.himi/ux-audit.json` holds no mobile-UX drive recorded against that release id, or holds one that FAILED (#2955) \u2014 a published draft IS the owner-private preview a customer is handed; `himi ux record` clears it and `--force` overrides it, which the success envelope then says out loud. `--only <selector>` publishes ONLY the named items as a release derived from the app's live release (or `--from-release <id>`), running the identical build + lint gate and simply publishing less; it requires an explicit `--draft` or `--live` because a partial publish has no safe default, never claims a slug, and carries neither attestation nor a source archive (both named in the output). Selectors are comma-separated in ONE `--only`: `changed` (every item whose bytes differ from the base), `screen:<id|glob>`, `bundle:<name>`, `tokens`, `app-config` \u2014 a selected screen drags its logic bundle and a selected bundle drags the screens that reference it, or the bytes land under a key nothing reads.", required: "[--content <dir>] [--draft] [--live] [--force] [--strict] [--label] [--notes] [--visibility public|unlisted] [--no-claim] [--account-id <id>] [--only <selector>] [--from-release <id>] [--accept-regressions] [--accept-partial] [--app <slug>] (--control-token)" },
|
|
@@ -64988,7 +65780,7 @@ var COMMANDS = [
|
|
|
64988
65780
|
];
|
|
64989
65781
|
function cliVersion() {
|
|
64990
65782
|
try {
|
|
64991
|
-
return JSON.parse(
|
|
65783
|
+
return JSON.parse(readFileSync74(new URL("../package.json", import.meta.url), "utf8")).version ?? "unknown";
|
|
64992
65784
|
} catch {
|
|
64993
65785
|
return "unknown";
|
|
64994
65786
|
}
|
|
@@ -65106,7 +65898,7 @@ function ageInDays(publishedAt, now = Date.now()) {
|
|
|
65106
65898
|
}
|
|
65107
65899
|
function packageVersion(path2) {
|
|
65108
65900
|
try {
|
|
65109
|
-
const version2 = JSON.parse(
|
|
65901
|
+
const version2 = JSON.parse(readFileSync74(path2, "utf8")).version;
|
|
65110
65902
|
return typeof version2 === "string" && version2 ? version2 : void 0;
|
|
65111
65903
|
} catch {
|
|
65112
65904
|
return void 0;
|
|
@@ -65115,7 +65907,7 @@ function packageVersion(path2) {
|
|
|
65115
65907
|
function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("./authoring-runtime/node_modules/@wix/himalaya/package.json", import.meta.url)) {
|
|
65116
65908
|
let dir = resolve47(fromDir);
|
|
65117
65909
|
for (; ; ) {
|
|
65118
|
-
const version2 = packageVersion(
|
|
65910
|
+
const version2 = packageVersion(join59(dir, "node_modules", "@wix", "himalaya", "package.json"));
|
|
65119
65911
|
if (version2) return { version: version2, source: "local" };
|
|
65120
65912
|
const parent = dirname32(dir);
|
|
65121
65913
|
if (parent === dir) break;
|
|
@@ -65125,7 +65917,7 @@ function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("
|
|
|
65125
65917
|
if (bundled) return { version: bundled, source: "bundled" };
|
|
65126
65918
|
try {
|
|
65127
65919
|
const root = execFileSync7("npm", ["root", "-g"], { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
65128
|
-
const version2 = root ? packageVersion(
|
|
65920
|
+
const version2 = root ? packageVersion(join59(root, "@wix", "himalaya", "package.json")) : void 0;
|
|
65129
65921
|
return version2 ? { version: version2, source: "global" } : {};
|
|
65130
65922
|
} catch {
|
|
65131
65923
|
return {};
|
|
@@ -65172,11 +65964,11 @@ var UPDATE_RETRY_AFTER_FAILURE_MS = 60 * 60 * 1e3;
|
|
|
65172
65964
|
var UPDATE_SNOOZE_MS = 24 * 60 * 60 * 1e3;
|
|
65173
65965
|
var UPDATE_REEXEC_ENV = "HIMI_UPDATED_ONCE";
|
|
65174
65966
|
function updateCachePath(env = process.env) {
|
|
65175
|
-
return env.HIMI_UPDATE_CACHE_FILE ??
|
|
65967
|
+
return env.HIMI_UPDATE_CACHE_FILE ?? join59(homedir7(), ".himalaya", "update-check.json");
|
|
65176
65968
|
}
|
|
65177
65969
|
function readUpdateCache(path2) {
|
|
65178
65970
|
try {
|
|
65179
|
-
const parsed = JSON.parse(
|
|
65971
|
+
const parsed = JSON.parse(readFileSync74(path2, "utf8"));
|
|
65180
65972
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
65181
65973
|
} catch {
|
|
65182
65974
|
return {};
|
|
@@ -65244,12 +66036,12 @@ function createUpdateRunner(spawn7 = spawnSync5) {
|
|
|
65244
66036
|
},
|
|
65245
66037
|
installedVersion: () => {
|
|
65246
66038
|
const root = globalNodeModulesRoot();
|
|
65247
|
-
return root ? packageVersion(
|
|
66039
|
+
return root ? packageVersion(join59(root, "@wix", "himalaya-cli", "package.json")) : void 0;
|
|
65248
66040
|
},
|
|
65249
66041
|
reexec: (argv) => {
|
|
65250
66042
|
const root = globalNodeModulesRoot();
|
|
65251
|
-
const entry = root ?
|
|
65252
|
-
if (!entry || !
|
|
66043
|
+
const entry = root ? join59(root, "@wix", "himalaya-cli", "dist", "cli.mjs") : void 0;
|
|
66044
|
+
if (!entry || !existsSync62(entry)) return void 0;
|
|
65253
66045
|
const result = spawnSync5(process.execPath, [entry, ...argv], {
|
|
65254
66046
|
// inherit keeps PIPED STDIN working — commands that read stdin must survive a re-exec.
|
|
65255
66047
|
stdio: "inherit",
|
|
@@ -65296,7 +66088,7 @@ function staleUpdateLockFile(cachePath, now) {
|
|
|
65296
66088
|
for (const path2 of [`${cachePath}.lock.break`, `${cachePath}.lock`]) {
|
|
65297
66089
|
let content;
|
|
65298
66090
|
try {
|
|
65299
|
-
content =
|
|
66091
|
+
content = readFileSync74(path2, "utf8");
|
|
65300
66092
|
} catch {
|
|
65301
66093
|
continue;
|
|
65302
66094
|
}
|
|
@@ -65319,7 +66111,7 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
|
|
|
65319
66111
|
const mine = lockStamp(now);
|
|
65320
66112
|
const readLock = (path2) => {
|
|
65321
66113
|
try {
|
|
65322
|
-
return
|
|
66114
|
+
return readFileSync74(path2, "utf8");
|
|
65323
66115
|
} catch {
|
|
65324
66116
|
return void 0;
|
|
65325
66117
|
}
|
|
@@ -65430,6 +66222,52 @@ function loaderArgs(execArgv) {
|
|
|
65430
66222
|
return out;
|
|
65431
66223
|
}
|
|
65432
66224
|
var spawnUpdateRefresh = createUpdateRefreshSpawner();
|
|
66225
|
+
function createTrimValidator(deps = {}, spawnFn = spawn6) {
|
|
66226
|
+
const outcome = (code, report2, said) => {
|
|
66227
|
+
let counts;
|
|
66228
|
+
let errors;
|
|
66229
|
+
try {
|
|
66230
|
+
const parsed = JSON.parse(report2);
|
|
66231
|
+
counts = parsed.counts;
|
|
66232
|
+
if (Array.isArray(parsed.findings)) {
|
|
66233
|
+
const text5 = (v) => typeof v === "string" && v ? v : void 0;
|
|
66234
|
+
errors = parsed.findings.filter((f) => f && f.severity === "error" && typeof f.id === "string").map((f) => ({
|
|
66235
|
+
id: f.id,
|
|
66236
|
+
message: text5(f.message) ?? "",
|
|
66237
|
+
...text5(f.pass) ? { pass: text5(f.pass) } : {},
|
|
66238
|
+
...text5(f.screen) ? { screen: text5(f.screen) } : {},
|
|
66239
|
+
...text5(f.path) ? { path: text5(f.path) } : {},
|
|
66240
|
+
...text5(f.ruleCode) ? { ruleCode: text5(f.ruleCode) } : {}
|
|
66241
|
+
}));
|
|
66242
|
+
}
|
|
66243
|
+
} catch {
|
|
66244
|
+
}
|
|
66245
|
+
return { code, counts, ...errors ? { errors } : {}, ...code !== 0 ? { tail: said.slice(-4e3) } : {} };
|
|
66246
|
+
};
|
|
66247
|
+
return async (dir, opts = {}) => {
|
|
66248
|
+
const argv = ["validate", "--content", resolve47(dir), "--strict", "--skip-version-check"];
|
|
66249
|
+
if (!opts.fresh) {
|
|
66250
|
+
const out = [];
|
|
66251
|
+
const err = [];
|
|
66252
|
+
const code2 = await run(argv, { log: (l) => out.push(l), error: (l) => err.push(l) }, deps);
|
|
66253
|
+
return outcome(code2, out[out.length - 1] ?? "", [...out, ...err].join("\n"));
|
|
66254
|
+
}
|
|
66255
|
+
const { code, stdout, stderr } = await new Promise((done) => {
|
|
66256
|
+
const chunks = { out: [], err: [] };
|
|
66257
|
+
const child = spawnFn(process.execPath, [...loaderArgs(process.execArgv), fileURLToPath24(import.meta.url), ...argv], {
|
|
66258
|
+
cwd: process.cwd(),
|
|
66259
|
+
env: process.env,
|
|
66260
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
66261
|
+
});
|
|
66262
|
+
child.stdout?.on("data", (b) => chunks.out.push(b));
|
|
66263
|
+
child.stderr?.on("data", (b) => chunks.err.push(b));
|
|
66264
|
+
child.on("error", (e) => done({ code: 2, stdout: "", stderr: String(e) }));
|
|
66265
|
+
child.on("close", (c) => done({ code: c ?? 1, stdout: Buffer.concat(chunks.out).toString("utf8"), stderr: Buffer.concat(chunks.err).toString("utf8") }));
|
|
66266
|
+
});
|
|
66267
|
+
return outcome(code, stdout.trim(), `${stdout}
|
|
66268
|
+
${stderr}`);
|
|
66269
|
+
};
|
|
66270
|
+
}
|
|
65433
66271
|
async function maybeSelfUpdate(argv, io, opts = {}) {
|
|
65434
66272
|
const env = opts.env ?? process.env;
|
|
65435
66273
|
const running = opts.running ?? cliVersion();
|
|
@@ -65857,7 +66695,7 @@ function executableOnPath(name, env = process.env) {
|
|
|
65857
66695
|
const suffixes = process.platform === "win32" ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
|
|
65858
66696
|
for (const dir of entries) {
|
|
65859
66697
|
for (const suffix of suffixes) {
|
|
65860
|
-
const candidate =
|
|
66698
|
+
const candidate = join59(dir, `${name}${suffix}`);
|
|
65861
66699
|
try {
|
|
65862
66700
|
if (!statSync17(candidate).isFile()) continue;
|
|
65863
66701
|
if (process.platform !== "win32") accessSync(candidate, constants2.X_OK);
|
|
@@ -65966,7 +66804,7 @@ async function nativeConfigAdvisories(app, configSource) {
|
|
|
65966
66804
|
const { iosProjectYml: iosProjectYml2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
65967
66805
|
const { androidOptedIn: androidOptedIn3, LABEL_IOS_SPLASH: LABEL_IOS_SPLASH2 } = await Promise.resolve().then(() => (init_splash(), splash_exports));
|
|
65968
66806
|
const iosYmlPath = iosProjectYml2(app);
|
|
65969
|
-
const iosYml =
|
|
66807
|
+
const iosYml = existsSync62(iosYmlPath) ? readFileSync74(iosYmlPath, "utf8") : "";
|
|
65970
66808
|
let optedIn = iosYml.includes(LABEL_IOS_SPLASH2);
|
|
65971
66809
|
if (!optedIn) {
|
|
65972
66810
|
const { androidManifestPath: androidManifestPath3 } = await Promise.resolve().then(() => (init_gen_native_config(), gen_native_config_exports));
|
|
@@ -65980,7 +66818,7 @@ async function nativeConfigAdvisories(app, configSource) {
|
|
|
65980
66818
|
}
|
|
65981
66819
|
function readConfigSource(dir) {
|
|
65982
66820
|
try {
|
|
65983
|
-
return
|
|
66821
|
+
return readFileSync74(join59(dir, "config.ts"), "utf8");
|
|
65984
66822
|
} catch {
|
|
65985
66823
|
return null;
|
|
65986
66824
|
}
|
|
@@ -65996,7 +66834,7 @@ function keptPlan(kept) {
|
|
|
65996
66834
|
}
|
|
65997
66835
|
async function initFromRemoteTemplate(name, parentDir, template, c) {
|
|
65998
66836
|
const dir = resolve47(parentDir, name);
|
|
65999
|
-
if (
|
|
66837
|
+
if (existsSync62(join59(dir, "himalaya.content.json"))) {
|
|
66000
66838
|
throw new Error(`content package already exists at ${dir}`);
|
|
66001
66839
|
}
|
|
66002
66840
|
const r = await c.fetchTemplateSource(TEMPLATE_APP_PREFIX + template);
|
|
@@ -66039,7 +66877,7 @@ function symlinkDestinationIssue(dest) {
|
|
|
66039
66877
|
function restoreDestinationIssue(dest, force) {
|
|
66040
66878
|
const link = symlinkDestinationIssue(dest);
|
|
66041
66879
|
if (link) return link;
|
|
66042
|
-
if (!
|
|
66880
|
+
if (!existsSync62(dest)) return null;
|
|
66043
66881
|
if (!statSync17(dest).isDirectory()) {
|
|
66044
66882
|
return { error: `${dest} exists and is not a directory`, hint: "pass --out/--name to land somewhere else, or remove the file" };
|
|
66045
66883
|
}
|
|
@@ -66054,7 +66892,7 @@ function restoreDestinationIssue(dest, force) {
|
|
|
66054
66892
|
function isHimalayaMonorepoCheckout(start) {
|
|
66055
66893
|
let dir = resolve47(start);
|
|
66056
66894
|
for (; ; ) {
|
|
66057
|
-
if (
|
|
66895
|
+
if (existsSync62(join59(dir, "tools", "himi-cli", "src", "cli.ts")) && existsSync62(join59(dir, "core", "serve", "src", "server.ts"))) return true;
|
|
66058
66896
|
const parent = dirname32(dir);
|
|
66059
66897
|
if (parent === dir) return false;
|
|
66060
66898
|
dir = parent;
|
|
@@ -66097,7 +66935,7 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
66097
66935
|
Object.entries(files).map(([rel, body]) => [rel, rel === "himalaya.content.json" ? substituteIdentity(body, slug) : body])
|
|
66098
66936
|
);
|
|
66099
66937
|
const repoRoot2 = resolve47(fileURLToPath24(new URL("../../..", import.meta.url)));
|
|
66100
|
-
const root =
|
|
66938
|
+
const root = join59(repoRoot2, "node_modules", ".cache", "himi-template-preview");
|
|
66101
66939
|
const stillRunning = (pid) => {
|
|
66102
66940
|
try {
|
|
66103
66941
|
process.kill(pid, 0);
|
|
@@ -66111,12 +66949,12 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
66111
66949
|
if (!entry.isDirectory()) continue;
|
|
66112
66950
|
const pid = Number(entry.name.startsWith(`${slug}-`) ? entry.name.slice(slug.length + 1) : NaN);
|
|
66113
66951
|
if (Number.isInteger(pid) && pid > 0 && pid !== process.pid && !stillRunning(pid)) {
|
|
66114
|
-
rmSync14(
|
|
66952
|
+
rmSync14(join59(root, entry.name), { recursive: true, force: true });
|
|
66115
66953
|
}
|
|
66116
66954
|
}
|
|
66117
66955
|
} catch {
|
|
66118
66956
|
}
|
|
66119
|
-
const dest =
|
|
66957
|
+
const dest = join59(root, `${slug}-${process.pid}`);
|
|
66120
66958
|
rmSync14(dest, { recursive: true, force: true });
|
|
66121
66959
|
mkdirSync30(dest, { recursive: true });
|
|
66122
66960
|
materializeSource(forBuild, displayName, dest, slug);
|
|
@@ -66124,8 +66962,8 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
66124
66962
|
}
|
|
66125
66963
|
async function appId(dir) {
|
|
66126
66964
|
try {
|
|
66127
|
-
const { readFileSync:
|
|
66128
|
-
const m = JSON.parse(
|
|
66965
|
+
const { readFileSync: readFileSync75 } = await import("node:fs");
|
|
66966
|
+
const m = JSON.parse(readFileSync75(join59(dir, "himalaya.content.json"), "utf8"));
|
|
66129
66967
|
if (m.name) return m.name;
|
|
66130
66968
|
} catch {
|
|
66131
66969
|
}
|
|
@@ -66133,8 +66971,8 @@ async function appId(dir) {
|
|
|
66133
66971
|
}
|
|
66134
66972
|
async function contentVisibility(dir) {
|
|
66135
66973
|
try {
|
|
66136
|
-
const { readFileSync:
|
|
66137
|
-
const m = JSON.parse(
|
|
66974
|
+
const { readFileSync: readFileSync75 } = await import("node:fs");
|
|
66975
|
+
const m = JSON.parse(readFileSync75(join59(dir, "himalaya.content.json"), "utf8"));
|
|
66138
66976
|
if (m.visibility === "public" || m.visibility === "unlisted") return m.visibility;
|
|
66139
66977
|
} catch {
|
|
66140
66978
|
}
|
|
@@ -66358,7 +67196,7 @@ async function recordedReleaseForContentQuietly(dir, resolution, onDrift) {
|
|
|
66358
67196
|
try {
|
|
66359
67197
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
66360
67198
|
const bres = await buildContentForValidation2(dir, { resolution });
|
|
66361
|
-
out = mkdtempSync4(
|
|
67199
|
+
out = mkdtempSync4(join59(tmpdir5(), "himi-ux-record-"));
|
|
66362
67200
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
66363
67201
|
const outcome = await buildReleaseFromContent2(dir, out, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {}, collect: { lint: true } });
|
|
66364
67202
|
const releaseId = outcome.manifest.releaseId;
|
|
@@ -66536,7 +67374,7 @@ async function producedWidgetFamilies(dir) {
|
|
|
66536
67374
|
let js;
|
|
66537
67375
|
for (const candidate of [`${name}.bundle.js`, `${name}.js`, name]) {
|
|
66538
67376
|
try {
|
|
66539
|
-
js =
|
|
67377
|
+
js = readFileSync74(join59(outDir, candidate), "utf8");
|
|
66540
67378
|
break;
|
|
66541
67379
|
} catch {
|
|
66542
67380
|
}
|
|
@@ -66567,7 +67405,7 @@ async function producedWidgetFamilies(dir) {
|
|
|
66567
67405
|
}
|
|
66568
67406
|
return { families, source: "dist/bundles" };
|
|
66569
67407
|
}
|
|
66570
|
-
var boardOpen = (dir) =>
|
|
67408
|
+
var boardOpen = (dir) => existsSync62(join59(dir, ".himi", "studio", "index.html"));
|
|
66571
67409
|
var BOARD_REFRESHERS = /* @__PURE__ */ new Set(["render", "test", "validate", "build", "push", "icon", "site", "ux", "progress"]);
|
|
66572
67410
|
async function leaveForBoard(dir, record2, value) {
|
|
66573
67411
|
if (!boardOpen(dir)) return;
|
|
@@ -66932,19 +67770,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66932
67770
|
const { runTemplateTrim: runTemplateTrim2 } = await Promise.resolve().then(() => (init_template_trim(), template_trim_exports));
|
|
66933
67771
|
const outcome = await runTemplateTrim2(
|
|
66934
67772
|
{ dir: contentDir(flags), keep: flags.keep, links: flags.links, dryRun: flags["dry-run"] === true, force: flags.force === true },
|
|
66935
|
-
{
|
|
66936
|
-
validate: async (dir) => {
|
|
66937
|
-
const out = [];
|
|
66938
|
-
const err = [];
|
|
66939
|
-
const code = await run(["validate", "--content", dir, "--strict"], { log: (l) => out.push(l), error: (l) => err.push(l) }, deps);
|
|
66940
|
-
let counts;
|
|
66941
|
-
try {
|
|
66942
|
-
counts = JSON.parse(out[out.length - 1] ?? "").counts;
|
|
66943
|
-
} catch {
|
|
66944
|
-
}
|
|
66945
|
-
return { code, counts, ...code !== 0 ? { tail: [...out, ...err].join("\n").slice(-4e3) } : {} };
|
|
66946
|
-
}
|
|
66947
|
-
}
|
|
67773
|
+
{ validate: createTrimValidator(deps) }
|
|
66948
67774
|
);
|
|
66949
67775
|
if (outcome.code === 2) io.error(JSON.stringify(outcome.result));
|
|
66950
67776
|
else print(outcome.result);
|
|
@@ -66955,7 +67781,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66955
67781
|
const sourceDir = resolve47(str6(flags["source-dir"]) ?? appDir2);
|
|
66956
67782
|
let meta;
|
|
66957
67783
|
try {
|
|
66958
|
-
meta = JSON.parse(
|
|
67784
|
+
meta = JSON.parse(readFileSync74(join59(sourceDir, TEMPLATE_META_FILE), "utf8"));
|
|
66959
67785
|
} catch {
|
|
66960
67786
|
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>)` }));
|
|
66961
67787
|
return 2;
|
|
@@ -66965,7 +67791,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66965
67791
|
return 2;
|
|
66966
67792
|
}
|
|
66967
67793
|
try {
|
|
66968
|
-
const appearance = extractTemplateAppearance(JSON.parse(
|
|
67794
|
+
const appearance = extractTemplateAppearance(JSON.parse(readFileSync74(join59(sourceDir, "tokens.json"), "utf8")));
|
|
66969
67795
|
meta = { ...appearance, ...meta };
|
|
66970
67796
|
} catch {
|
|
66971
67797
|
}
|
|
@@ -66977,7 +67803,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66977
67803
|
const force = flags.force === true;
|
|
66978
67804
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
66979
67805
|
const bres = await buildContentForValidation2(buildDir, { resolution: resolutionFlag(flags) });
|
|
66980
|
-
const out = mkdtempSync4(
|
|
67806
|
+
const out = mkdtempSync4(join59(tmpdir5(), "himi-template-"));
|
|
66981
67807
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
66982
67808
|
const outcome = await buildReleaseFromContent2(buildDir, out, {
|
|
66983
67809
|
...hasWorkers ? { tier5Dir: bundleOutDir2(buildDir) } : {},
|
|
@@ -67030,7 +67856,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67030
67856
|
let iconHash;
|
|
67031
67857
|
if (iconPath) {
|
|
67032
67858
|
try {
|
|
67033
|
-
const bytes2 =
|
|
67859
|
+
const bytes2 = readFileSync74(iconPath);
|
|
67034
67860
|
payload.icon = bytes2.toString("base64");
|
|
67035
67861
|
iconHash = createHash27("sha256").update(bytes2).digest("hex");
|
|
67036
67862
|
} catch {
|
|
@@ -67263,7 +68089,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67263
68089
|
const { navIssues: navIssues2 } = await Promise.resolve().then(() => (init_nav_lint(), nav_lint_exports));
|
|
67264
68090
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
67265
68091
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
67266
|
-
const out = mkdtempSync4(
|
|
68092
|
+
const out = mkdtempSync4(join59(tmpdir5(), "himi-validate-"));
|
|
67267
68093
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
67268
68094
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
67269
68095
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -67306,7 +68132,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67306
68132
|
const path2 = dpxSessionTokenPath();
|
|
67307
68133
|
let raw;
|
|
67308
68134
|
try {
|
|
67309
|
-
raw =
|
|
68135
|
+
raw = readFileSync74(path2, "utf8");
|
|
67310
68136
|
} catch {
|
|
67311
68137
|
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`);
|
|
67312
68138
|
}
|
|
@@ -67426,13 +68252,13 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67426
68252
|
case "studio": {
|
|
67427
68253
|
const { openStudio: openStudio2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
|
|
67428
68254
|
const dir = contentDir(flags);
|
|
67429
|
-
if (!
|
|
68255
|
+
if (!existsSync62(join59(dir, "himalaya.content.json"))) {
|
|
67430
68256
|
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/" }));
|
|
67431
68257
|
return 2;
|
|
67432
68258
|
}
|
|
67433
68259
|
if (pos[1] === "reel") {
|
|
67434
68260
|
const { buildReel: buildReel2 } = await Promise.resolve().then(() => (init_studio_reel(), studio_reel_exports));
|
|
67435
|
-
const out = resolve47(str6(flags.out) ??
|
|
68261
|
+
const out = resolve47(str6(flags.out) ?? join59(dir, ".himi", "making-of.html"));
|
|
67436
68262
|
const { html, plan } = buildReel2(dir);
|
|
67437
68263
|
mkdirSync30(dirname32(out), { recursive: true });
|
|
67438
68264
|
writeFileSync28(out, html);
|
|
@@ -67482,7 +68308,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67482
68308
|
const { appendProgress: appendProgress2, readProgress: readProgress2, summarizeProgress: summarizeProgress2, parseStep: parseStep2, notifyDesktop: notifyDesktop2, appLabel: appLabel2, journalPath: journalPath2, ProgressError: ProgressError2, JOURNEY_STEPS: JOURNEY_STEPS2 } = await Promise.resolve().then(() => (init_progress(), progress_exports));
|
|
67483
68309
|
const dir = contentDir(flags);
|
|
67484
68310
|
const journal = journalPath2(dir);
|
|
67485
|
-
const hint =
|
|
68311
|
+
const hint = existsSync62(join59(dir, "himalaya.content.json")) ? {} : { hint: "no himalaya.content.json here \u2014 run from the app directory (or pass --content <dir>) so the build board finds this journal" };
|
|
67486
68312
|
const message = pos.slice(1).join(" ").trim();
|
|
67487
68313
|
if (!message) {
|
|
67488
68314
|
if (flags.step !== void 0 || flags.image !== void 0 || flags.notify === true) {
|
|
@@ -67574,7 +68400,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67574
68400
|
case "test": {
|
|
67575
68401
|
const dir = contentDir(flags);
|
|
67576
68402
|
const structuredOutput = flags.json === true || io.isTTY !== true;
|
|
67577
|
-
if (
|
|
68403
|
+
if (existsSync62(join59(dir, "functions"))) {
|
|
67578
68404
|
const { invokeLocalFunction: invokeLocalFunction2, loadFunctionsApp: loadFunctionsApp2 } = await Promise.resolve().then(() => (init_functions(), functions_exports));
|
|
67579
68405
|
const loaded = await loadFunctionsApp2(dir);
|
|
67580
68406
|
const results = [];
|
|
@@ -67661,7 +68487,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67661
68487
|
}
|
|
67662
68488
|
}
|
|
67663
68489
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
67664
|
-
const out = mkdtempSync4(
|
|
68490
|
+
const out = mkdtempSync4(join59(tmpdir5(), "himi-test-"));
|
|
67665
68491
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
67666
68492
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
67667
68493
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -67706,7 +68532,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67706
68532
|
io.error(JSON.stringify({ error: `screen "${screen.screenId}" has no Tier-5 worker, so there is nothing for the browser loop to build` }));
|
|
67707
68533
|
return 2;
|
|
67708
68534
|
}
|
|
67709
|
-
const sources = collectWorkerSources2(
|
|
68535
|
+
const sources = collectWorkerSources2(join59(dir, "tier5-src"), screen.bundleName);
|
|
67710
68536
|
if (!sources) {
|
|
67711
68537
|
io.error(JSON.stringify({ error: `no worker source found at tier5-src/${screen.bundleName} \u2014 the browser loop compiles SOURCE, not the built bundle` }));
|
|
67712
68538
|
return 2;
|
|
@@ -67867,7 +68693,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67867
68693
|
const sp = await runShotsPass2({
|
|
67868
68694
|
descriptors: scopeDescriptors2(outcome.descriptors ?? [], pos.slice(1), invalidScreens),
|
|
67869
68695
|
tokens: outcome.tokens,
|
|
67870
|
-
outDir:
|
|
68696
|
+
outDir: join59(dir, ".himi", "shots"),
|
|
67871
68697
|
width: 390,
|
|
67872
68698
|
layers: { rules: shotRules, ...cmsSeed ? { cmsSeed } : {}, ...canned ? { canned: canned.byKey } : {} },
|
|
67873
68699
|
...budgetMs ? { budgetMs } : {},
|
|
@@ -67905,7 +68731,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67905
68731
|
releaseId: result.releaseId,
|
|
67906
68732
|
releasePayload: release,
|
|
67907
68733
|
descriptors: attestedDescriptors,
|
|
67908
|
-
screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""),
|
|
68734
|
+
screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""), join59(dir, ".himi", "shots", name)])),
|
|
67909
68735
|
coverage: {
|
|
67910
68736
|
screens: crawledScreens.size,
|
|
67911
68737
|
actionsDispatched: result.actions.exercised,
|
|
@@ -67995,7 +68821,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67995
68821
|
return 2;
|
|
67996
68822
|
}
|
|
67997
68823
|
try {
|
|
67998
|
-
const raw = stateArg.trim().startsWith("{") ? stateArg :
|
|
68824
|
+
const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync74(stateArg.replace(/^@/, ""), "utf8");
|
|
67999
68825
|
injectedState = JSON.parse(raw);
|
|
68000
68826
|
} catch (e) {
|
|
68001
68827
|
io.error(JSON.stringify({ error: `--state must be inline JSON or a path to a .json file \u2014 ${e.message}` }));
|
|
@@ -68010,7 +68836,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
68010
68836
|
return 2;
|
|
68011
68837
|
}
|
|
68012
68838
|
try {
|
|
68013
|
-
const raw = inputArg.trim().startsWith("{") ? inputArg :
|
|
68839
|
+
const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync74(inputArg.replace(/^@/, ""), "utf8");
|
|
68014
68840
|
const parsed = JSON.parse(raw);
|
|
68015
68841
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("must be a JSON object");
|
|
68016
68842
|
injectedInput = parsed;
|
|
@@ -68059,7 +68885,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
68059
68885
|
}
|
|
68060
68886
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
68061
68887
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
68062
|
-
const out = mkdtempSync4(
|
|
68888
|
+
const out = mkdtempSync4(join59(tmpdir5(), "himi-render-"));
|
|
68063
68889
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
68064
68890
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
68065
68891
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -68073,7 +68899,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
68073
68899
|
const diagnostics = (outcome.lint ?? []).find((s) => s.screenId === screenId)?.issues ?? [];
|
|
68074
68900
|
let pngFile;
|
|
68075
68901
|
let attestationPngFile;
|
|
68076
|
-
const shotPath =
|
|
68902
|
+
const shotPath = join59(dir, ".himi", "shots", `${screenId}.png`);
|
|
68077
68903
|
const pngTarget = typeof flags.png === "string" ? str6(flags.png) : flags.png === true ? shotPath : void 0;
|
|
68078
68904
|
if (pngTarget && r.pngBase64) {
|
|
68079
68905
|
pngFile = writePngFile(pngTarget, r.pngBase64);
|
|
@@ -68203,7 +69029,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
68203
69029
|
installIcon: installIcon2,
|
|
68204
69030
|
siteBookIcon: siteBookIcon2,
|
|
68205
69031
|
siteLogoAbsence: siteLogoAbsence2,
|
|
68206
|
-
summarize:
|
|
69032
|
+
summarize: summarize4
|
|
68207
69033
|
} = await Promise.resolve().then(() => (init_icon(), icon_exports));
|
|
68208
69034
|
const requireVerified = sub === "check";
|
|
68209
69035
|
const report2 = async (status, extra = {}) => {
|
|
@@ -68228,11 +69054,11 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
68228
69054
|
}))
|
|
68229
69055
|
];
|
|
68230
69056
|
if (flags.json === true) {
|
|
68231
|
-
print({ ok: !blocksRelease2(status, { requireVerified }), ...extra, ...status, findings, summary:
|
|
69057
|
+
print({ ok: !blocksRelease2(status, { requireVerified }), ...extra, ...status, findings, summary: summarize4(status) });
|
|
68232
69058
|
return blocksRelease2(status, { requireVerified }) ? 1 : 0;
|
|
68233
69059
|
}
|
|
68234
69060
|
for (const [k, v] of Object.entries(extra)) io.log(`${k}: ${Array.isArray(v) ? v.join(", ") : String(v)}`);
|
|
68235
|
-
io.log(`launcher icon: ${
|
|
69061
|
+
io.log(`launcher icon: ${summarize4(status)}`);
|
|
68236
69062
|
if (status.path) io.log(` file: ${status.path}${status.header ? ` (${status.header.width}x${status.header.height})` : ""}`);
|
|
68237
69063
|
for (const f of findings) io.log(` ${f.level === "error" ? "\u2717" : "\u26A0"} ${f.message}`);
|
|
68238
69064
|
if (status.verdict === "ok" || status.verdict === "unverified") {
|
|
@@ -68409,7 +69235,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68409
69235
|
io.error(JSON.stringify(linked));
|
|
68410
69236
|
return 1;
|
|
68411
69237
|
}
|
|
68412
|
-
if (
|
|
69238
|
+
if (existsSync62(dest)) {
|
|
68413
69239
|
if (!statSync17(dest).isDirectory()) {
|
|
68414
69240
|
io.error(JSON.stringify({
|
|
68415
69241
|
error: `${dest} exists and is not a directory`,
|
|
@@ -68422,7 +69248,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68422
69248
|
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" }));
|
|
68423
69249
|
return 1;
|
|
68424
69250
|
}
|
|
68425
|
-
if (replace && occupied && !
|
|
69251
|
+
if (replace && occupied && !existsSync62(join59(dest, "himalaya.content.json"))) {
|
|
68426
69252
|
io.error(JSON.stringify({
|
|
68427
69253
|
error: `${dest} is not a content package \u2014 refusing to --replace it`,
|
|
68428
69254
|
hint: "--replace only clears a directory that holds himalaya.content.json. Check --out/--name, or pass --force to merge into it instead."
|
|
@@ -68561,7 +69387,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68561
69387
|
const force = flags.force === true;
|
|
68562
69388
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
68563
69389
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
68564
|
-
const out = mkdtempSync4(
|
|
69390
|
+
const out = mkdtempSync4(join59(tmpdir5(), "himi-push-"));
|
|
68565
69391
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
68566
69392
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
68567
69393
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -69082,7 +69908,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69082
69908
|
}
|
|
69083
69909
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
69084
69910
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
69085
|
-
const built = mkdtempSync4(
|
|
69911
|
+
const built = mkdtempSync4(join59(tmpdir5(), "himi-pack-"));
|
|
69086
69912
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
69087
69913
|
const outcome = await buildReleaseFromContent2(dir, built, {
|
|
69088
69914
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -69285,7 +70111,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69285
70111
|
}));
|
|
69286
70112
|
return 1;
|
|
69287
70113
|
}
|
|
69288
|
-
const archive =
|
|
70114
|
+
const archive = readFileSync74(resolve47(file));
|
|
69289
70115
|
const result = await client2().createPackageShare({
|
|
69290
70116
|
app: opened.header.app,
|
|
69291
70117
|
releaseId: opened.header.releaseId,
|
|
@@ -69339,11 +70165,11 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69339
70165
|
const app = await appId(dir2);
|
|
69340
70166
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
69341
70167
|
const bres = await buildContentBundles2(dir2, { resolution: resolutionFlag(flags) });
|
|
69342
|
-
temp = mkdtempSync4(
|
|
70168
|
+
temp = mkdtempSync4(join59(tmpdir5(), "himi-run-build-"));
|
|
69343
70169
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
69344
70170
|
const initial = await buildReleaseFromContent2(dir2, temp, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir2) } : {} });
|
|
69345
70171
|
servedMissing = initial.missingBundles;
|
|
69346
|
-
source =
|
|
70172
|
+
source = join59(temp, app);
|
|
69347
70173
|
}
|
|
69348
70174
|
const chromeArg = str6(flags.chrome) ?? "preview";
|
|
69349
70175
|
if (chromeArg !== "preview" && chromeArg !== "app") {
|
|
@@ -69379,7 +70205,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69379
70205
|
if (!recordKit) return;
|
|
69380
70206
|
startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
69381
70207
|
const failure = record2(served2, { ok: true, at: startedAt });
|
|
69382
|
-
if (!recorded) io.error(JSON.stringify({ run: "run_record_skipped", message: `${failure ?? `${
|
|
70208
|
+
if (!recorded) io.error(JSON.stringify({ run: "run_record_skipped", message: `${failure ?? `${join59(dir, ".himi")} is not a real directory`}, so the build board will not frame this preview.` }));
|
|
69383
70209
|
await refreshBoard();
|
|
69384
70210
|
};
|
|
69385
70211
|
const retract = async () => {
|
|
@@ -69410,7 +70236,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69410
70236
|
}
|
|
69411
70237
|
const watchKit = watch2 ? await Promise.resolve().then(() => (init_run_watch(), run_watch_exports)) : null;
|
|
69412
70238
|
const bus = watchKit ? new watchKit.ReloadBus() : void 0;
|
|
69413
|
-
if (watch2) served = mkdtempSync4(
|
|
70239
|
+
if (watch2) served = mkdtempSync4(join59(tmpdir5(), "himi-run-served-"));
|
|
69414
70240
|
const running = await runPackage2(source, {
|
|
69415
70241
|
port,
|
|
69416
70242
|
chrome: chromeArg,
|
|
@@ -69431,8 +70257,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69431
70257
|
await announce(running);
|
|
69432
70258
|
if (watchKit && bus) {
|
|
69433
70259
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
69434
|
-
const live2 =
|
|
69435
|
-
const manifestOf = (tree) => JSON.parse(
|
|
70260
|
+
const live2 = join59(running.releaseRoot, running.app);
|
|
70261
|
+
const manifestOf = (tree) => JSON.parse(readFileSync74(join59(tree, "release-manifest.json"), "utf8"));
|
|
69436
70262
|
let current = manifestOf(live2);
|
|
69437
70263
|
const failed2 = async (message) => {
|
|
69438
70264
|
if (stopping) return;
|
|
@@ -69443,7 +70269,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69443
70269
|
};
|
|
69444
70270
|
rebuild = watchKit.serialize(async () => {
|
|
69445
70271
|
const t0 = Date.now();
|
|
69446
|
-
const next = mkdtempSync4(
|
|
70272
|
+
const next = mkdtempSync4(join59(tmpdir5(), "himi-run-build-"));
|
|
69447
70273
|
try {
|
|
69448
70274
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
69449
70275
|
if (bres.compileErrors.length) {
|
|
@@ -69460,14 +70286,14 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69460
70286
|
return;
|
|
69461
70287
|
}
|
|
69462
70288
|
if (stopping) return;
|
|
69463
|
-
const fresh = manifestOf(
|
|
70289
|
+
const fresh = manifestOf(join59(next, running.app));
|
|
69464
70290
|
const diff = watchKit.diffReleases(current, fresh);
|
|
69465
70291
|
const retired = `${live2}.retired-${Date.now()}`;
|
|
69466
70292
|
renameSync6(live2, retired);
|
|
69467
70293
|
try {
|
|
69468
|
-
renameSync6(
|
|
70294
|
+
renameSync6(join59(next, running.app), live2);
|
|
69469
70295
|
} catch {
|
|
69470
|
-
cpSync3(
|
|
70296
|
+
cpSync3(join59(next, running.app), live2, { recursive: true });
|
|
69471
70297
|
}
|
|
69472
70298
|
rmSync14(retired, { recursive: true, force: true });
|
|
69473
70299
|
current = fresh;
|
|
@@ -70065,7 +70891,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
70065
70891
|
io.error(JSON.stringify({ error: `patch ${kind} needs --file`, usage: PATCH_USAGE }));
|
|
70066
70892
|
return 2;
|
|
70067
70893
|
}
|
|
70068
|
-
if (!
|
|
70894
|
+
if (!existsSync62(file)) {
|
|
70069
70895
|
io.error(JSON.stringify({ error: `no such file: ${file}` }));
|
|
70070
70896
|
return 2;
|
|
70071
70897
|
}
|
|
@@ -70121,7 +70947,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
70121
70947
|
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."
|
|
70122
70948
|
};
|
|
70123
70949
|
if (kind === "tokens" || kind === "app-config") {
|
|
70124
|
-
const body =
|
|
70950
|
+
const body = readFileSync74(file, "utf8");
|
|
70125
70951
|
const patch2 = kind === "tokens" ? { tokens: body } : { appConfig: body };
|
|
70126
70952
|
return runReleasePatch({
|
|
70127
70953
|
...common,
|
|
@@ -70136,7 +70962,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
70136
70962
|
io.error(JSON.stringify({ error: "patch screen needs a <screenId>", usage: PATCH_USAGE }));
|
|
70137
70963
|
return 2;
|
|
70138
70964
|
}
|
|
70139
|
-
const descriptor =
|
|
70965
|
+
const descriptor = readFileSync74(file, "utf8");
|
|
70140
70966
|
try {
|
|
70141
70967
|
JSON.parse(descriptor);
|
|
70142
70968
|
} catch (e) {
|
|
@@ -70176,7 +71002,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
70176
71002
|
extra: { kind, screen: id, file: { path: file, bytes: Buffer.byteLength(descriptor, "utf8") } }
|
|
70177
71003
|
});
|
|
70178
71004
|
}
|
|
70179
|
-
const bytes2 =
|
|
71005
|
+
const bytes2 = readFileSync74(file);
|
|
70180
71006
|
const sha = createHash27("sha256").update(bytes2).digest("hex");
|
|
70181
71007
|
const forScreens = (str6(flags["for-screen"]) ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
70182
71008
|
if (flags["no-rebind"] !== void 0 && flags["no-rebind"] !== true) {
|
|
@@ -70320,7 +71146,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
70320
71146
|
}
|
|
70321
71147
|
let def;
|
|
70322
71148
|
try {
|
|
70323
|
-
const parsed = JSON.parse(arg.startsWith("@") ?
|
|
71149
|
+
const parsed = JSON.parse(arg.startsWith("@") ? readFileSync74(arg.slice(1), "utf8") : arg);
|
|
70324
71150
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
70325
71151
|
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}`] }));
|
|
70326
71152
|
return 2;
|
|
@@ -70784,7 +71610,7 @@ ${label2}`);
|
|
|
70784
71610
|
const platform = str6(flags.platform)?.split(",").map((p) => p.trim()).filter(Boolean);
|
|
70785
71611
|
{
|
|
70786
71612
|
const distDir = contentDir(flags);
|
|
70787
|
-
if (
|
|
71613
|
+
if (existsSync62(join59(distDir, "himalaya.content.json"))) {
|
|
70788
71614
|
const issues = await iconIssues(distDir, flags.strict === true, { requireDeclared: true, requireVerified: true });
|
|
70789
71615
|
const errors = issues.filter((i) => i.severity === "error");
|
|
70790
71616
|
for (const i of issues.filter((i2) => i2.severity === "warning")) {
|
|
@@ -71053,7 +71879,7 @@ ${label2}`);
|
|
|
71053
71879
|
const dpxPath = dpxSessionTokenPath();
|
|
71054
71880
|
let dpx;
|
|
71055
71881
|
try {
|
|
71056
|
-
dpx =
|
|
71882
|
+
dpx = readFileSync74(dpxPath, "utf8").trim();
|
|
71057
71883
|
} catch {
|
|
71058
71884
|
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` }));
|
|
71059
71885
|
return 1;
|
|
@@ -71455,7 +72281,7 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
|
|
|
71455
72281
|
const path2 = dpxSessionTokenPath();
|
|
71456
72282
|
let raw;
|
|
71457
72283
|
try {
|
|
71458
|
-
raw =
|
|
72284
|
+
raw = readFileSync74(path2, "utf8");
|
|
71459
72285
|
} catch {
|
|
71460
72286
|
io.error(JSON.stringify({ error: `no DPX BO session at ${path2}` }));
|
|
71461
72287
|
return 1;
|
|
@@ -71722,10 +72548,11 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
|
|
|
71722
72548
|
}
|
|
71723
72549
|
}
|
|
71724
72550
|
if (sub !== "analyze") {
|
|
71725
|
-
io.error(JSON.stringify({ error: sub ? `unknown site subcommand "${sub}"` : "site needs a subcommand", usage: `himi site create <name> [--type wix|headless|branded-app|vibe] --yes | himi site list | himi site client ensure|list --site <msid> | himi site analyze --
|
|
72551
|
+
io.error(JSON.stringify({ error: sub ? `unknown site subcommand "${sub}"` : "site needs a subcommand", usage: `himi site create <name> [--type wix|headless|branded-app|vibe] --yes | himi site list | himi site client ensure|list --site <msid> | himi site analyze --url <https://\u2026> [--client-id <id>] [--site <msid>] [--out <dir>] [--apply [--shell <id>]] | himi site function list|get|put|publish|invoke \u2026` }));
|
|
71726
72552
|
return 2;
|
|
71727
72553
|
}
|
|
71728
|
-
const
|
|
72554
|
+
const clientFlag = str6(flags["client-id"]);
|
|
72555
|
+
const clientId = clientFlag ?? process.env.WIX_CLIENT_ID;
|
|
71729
72556
|
const siteUrl = str6(flags.url) ?? str6(flags["site-url"]);
|
|
71730
72557
|
if (flags["read-only"] === true) {
|
|
71731
72558
|
if (flags.apply || flags.out || flags.shell || flags["redirect-uri"]) {
|
|
@@ -71755,24 +72582,27 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
|
|
|
71755
72582
|
print({ ok: true, context });
|
|
71756
72583
|
return 0;
|
|
71757
72584
|
}
|
|
71758
|
-
|
|
72585
|
+
const analyzeUsage = "himi site analyze --url https://\u2026 [--client-id <headless-oauth-client-id>] [--site <msid>] [--out .himi/business-book] [--redirect-uri <uri>] [--apply [--shell " + SHELL_ENUM + "]]";
|
|
72586
|
+
if (!siteUrl) {
|
|
72587
|
+
io.error(JSON.stringify({ error: "himi site analyze needs --url", usage: analyzeUsage }));
|
|
72588
|
+
return 2;
|
|
72589
|
+
}
|
|
72590
|
+
const redirectFlag = str6(flags["redirect-uri"]);
|
|
72591
|
+
if (!clientId && (flags.apply === true || redirectFlag)) {
|
|
72592
|
+
const { APPLY_NEEDS_CLIENT: APPLY_NEEDS_CLIENT2, REDIRECT_NEEDS_CLIENT: REDIRECT_NEEDS_CLIENT2 } = await Promise.resolve().then(() => (init_cli(), cli_exports));
|
|
71759
72593
|
io.error(JSON.stringify({
|
|
71760
|
-
error:
|
|
71761
|
-
|
|
71762
|
-
// be a dead end that named only the dashboard. Name the command that resolves
|
|
71763
|
-
// it instead — that is what lets an unattended loop start from a site it did
|
|
71764
|
-
// not create.
|
|
71765
|
-
...clientId ? {} : {
|
|
71766
|
-
hint: "no --client-id? `himi site client ensure --site <msid> --yes` resolves (or mints) the site's Headless client and prints it; `himi site client list --site <msid>` shows what the site already has. WIX_CLIENT_ID is read as a fallback."
|
|
71767
|
-
},
|
|
71768
|
-
usage: "himi site analyze --client-id <headless-oauth-client-id> --url https://\u2026 [--site <msid>] [--out .himi/business-book] [--redirect-uri <uri>] [--apply [--shell " + SHELL_ENUM + "]]"
|
|
72594
|
+
error: flags.apply === true ? APPLY_NEEDS_CLIENT2 : REDIRECT_NEEDS_CLIENT2,
|
|
72595
|
+
usage: analyzeUsage
|
|
71769
72596
|
}));
|
|
71770
72597
|
return 2;
|
|
71771
72598
|
}
|
|
71772
72599
|
try {
|
|
71773
72600
|
const { runSiteAnalyze: runSiteAnalyze2 } = await Promise.resolve().then(() => (init_cli(), cli_exports));
|
|
71774
72601
|
const r = await runSiteAnalyze2({
|
|
71775
|
-
clientId,
|
|
72602
|
+
...clientId ? { clientId } : {},
|
|
72603
|
+
// The AMBIENT `WIX_SITE_ID` selects owner mode only beside an explicit --client-id,
|
|
72604
|
+
// so exported env vars cannot turn a bare `--url` run into an owner read (#3283).
|
|
72605
|
+
explicitClient: !!clientFlag,
|
|
71776
72606
|
siteUrl,
|
|
71777
72607
|
siteFlag: str6(flags.site),
|
|
71778
72608
|
outDir: str6(flags.out),
|
|
@@ -71782,14 +72612,14 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
|
|
|
71782
72612
|
// Analyze cannot discover it (GET-only; the registered list lives behind
|
|
71783
72613
|
// `oauth-app/v1`), and the shell refuses to reuse its own default once a customer
|
|
71784
72614
|
// client is in play — so it is passed in by whoever registered it.
|
|
71785
|
-
redirectUri:
|
|
72615
|
+
redirectUri: redirectFlag,
|
|
71786
72616
|
cwd: str6(flags.content) ?? process.cwd()
|
|
71787
72617
|
});
|
|
71788
72618
|
print({ ok: true, ...r });
|
|
71789
72619
|
return 0;
|
|
71790
72620
|
} catch (e) {
|
|
71791
72621
|
io.error(JSON.stringify({ error: e.message }));
|
|
71792
|
-
return 1;
|
|
72622
|
+
return e.exit === 2 ? 2 : 1;
|
|
71793
72623
|
}
|
|
71794
72624
|
}
|
|
71795
72625
|
default:
|
|
@@ -71840,6 +72670,7 @@ export {
|
|
|
71840
72670
|
buildDoctorReport,
|
|
71841
72671
|
compareVersions2 as compareVersions,
|
|
71842
72672
|
createScopedRegistryResolver,
|
|
72673
|
+
createTrimValidator,
|
|
71843
72674
|
createUpdateRefreshSpawner,
|
|
71844
72675
|
createUpdateRunner,
|
|
71845
72676
|
credentialKind,
|