@wix/himalaya-cli 0.1603.0 → 0.1605.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/define-app.d.ts +7 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/push-routes.d.ts +7 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-bi.mjs +10 -1
- package/dist/cli.mjs +500 -135
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/hhp.md +2 -2
- package/guides/push-cli-onboarding.md +36 -0
- package/package.json +2 -2
package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/define-app.d.ts
CHANGED
|
@@ -624,6 +624,13 @@ export interface PushConfig {
|
|
|
624
624
|
* account-level app that is not about any single site. Only the "wix-ping"
|
|
625
625
|
* registrar reads it. */
|
|
626
626
|
pingScope?: "site" | "user";
|
|
627
|
+
/** Extra link prefixes stripped before `routes` match (#4709), for an app inheriting a
|
|
628
|
+
* legacy link space: e.g. `["legacyapp://", "https://legacy.example.com/app/"]` turns
|
|
629
|
+
* `legacyapp://widget/42` into the residual `widget/42`. Tried after the "wix-ping"
|
|
630
|
+
* rules; the longest matching prefix wins; scheme and host compare case-insensitively,
|
|
631
|
+
* the path exactly, and a prefix ends at `/`, `?` or `#`. A relative link (`/widget/42`)
|
|
632
|
+
* is a residual without any prefix. */
|
|
633
|
+
linkPrefixes?: string[];
|
|
627
634
|
/** Token registrar. "generic" ⇒ POST the token to `registerUrl`; "wix-ping"
|
|
628
635
|
* ⇒ the native Wix Ping registrar. */
|
|
629
636
|
registrar: PushRegistrar;
|
package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/push-routes.d.ts
CHANGED
|
@@ -49,8 +49,13 @@ export interface AdaptedLink {
|
|
|
49
49
|
* link through unchanged rather than failing, so an older binary served a config
|
|
50
50
|
* naming an adapter it has never heard of degrades to today's behavior instead of
|
|
51
51
|
* dropping every notification (invariants 6/8).
|
|
52
|
+
*
|
|
53
|
+
* #4709 — `linkPrefixes` (`PushConfig.linkPrefixes`). In order: the "wix-ping" rules
|
|
54
|
+
* (when that is the adapter); then the LONGEST configured prefix the link starts with
|
|
55
|
+
* is stripped; then a relative link (`/widget/7`) is a residual as is. Anything else
|
|
56
|
+
* passes through unchanged. Only a Wix link yields a `metaSiteId`.
|
|
52
57
|
*/
|
|
53
|
-
export declare function adaptPayloadLink(link: string, adapter?: string): AdaptedLink;
|
|
58
|
+
export declare function adaptPayloadLink(link: string, adapter?: string, linkPrefixes?: readonly string[]): AdaptedLink;
|
|
54
59
|
/**
|
|
55
60
|
* The himi link the first matching route produces, or null when nothing matches.
|
|
56
61
|
*
|
|
@@ -67,6 +72,7 @@ export declare function matchPushRoute(residual: string, routes: readonly PushRo
|
|
|
67
72
|
export declare function resolvePushRoute(link: string, config: {
|
|
68
73
|
routes?: readonly PushRoute[];
|
|
69
74
|
payloadAdapter?: string;
|
|
75
|
+
linkPrefixes?: readonly string[];
|
|
70
76
|
} | undefined, payload?: PushPayloadContext): {
|
|
71
77
|
link: string | null;
|
|
72
78
|
params: Record<string, string>;
|
|
@@ -45,8 +45,17 @@ function redactFrogParam(value) {
|
|
|
45
45
|
return value;
|
|
46
46
|
}
|
|
47
47
|
var BARE_ENDPOINT = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
48
|
+
function onConfigOrigin(name, configEndpoint) {
|
|
49
|
+
if (!configEndpoint || !configEndpoint.includes("://")) return name;
|
|
50
|
+
try {
|
|
51
|
+
const url = new URL(configEndpoint);
|
|
52
|
+
return `${url.protocol}//${url.host}/${name}`;
|
|
53
|
+
} catch {
|
|
54
|
+
return name;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
48
57
|
function eventEndpoint(eventEndpointValue, configEndpoint) {
|
|
49
|
-
return frogEndpointUrl(eventEndpointValue && BARE_ENDPOINT.test(eventEndpointValue) ? eventEndpointValue : configEndpoint);
|
|
58
|
+
return frogEndpointUrl(eventEndpointValue && BARE_ENDPOINT.test(eventEndpointValue) ? onConfigOrigin(eventEndpointValue, configEndpoint) : configEndpoint);
|
|
50
59
|
}
|
|
51
60
|
function frogEndpointUrl(endpoint) {
|
|
52
61
|
const e = (endpoint ?? "").trim() || ONEAPP_DEFAULT_ENDPOINT;
|
package/dist/cli.mjs
CHANGED
|
@@ -1187,14 +1187,14 @@ var init_start_prompt = __esm({
|
|
|
1187
1187
|
// src/source-deny.ts
|
|
1188
1188
|
import { sep } from "node:path";
|
|
1189
1189
|
function isDeniedSourcePath(relPath) {
|
|
1190
|
-
const
|
|
1191
|
-
if (
|
|
1192
|
-
const dirs =
|
|
1190
|
+
const segments2 = relPath.split(/[\\/]/).filter(Boolean);
|
|
1191
|
+
if (segments2.length === 0) return false;
|
|
1192
|
+
const dirs = segments2.slice(0, -1);
|
|
1193
1193
|
if (dirs.some((seg2) => DENY_DIRS.has(seg2))) return true;
|
|
1194
1194
|
if (dirs.length > 0 && DENY_ROOT_DIRS.has(dirs[0])) return true;
|
|
1195
|
-
if (
|
|
1196
|
-
if (MCP_HOST_CONFIG_FILES.includes(
|
|
1197
|
-
return DENY_FILES.some((re2) => re2.test(
|
|
1195
|
+
if (segments2.length === 1 && segments2[0] === "HIMALAYA.md") return true;
|
|
1196
|
+
if (MCP_HOST_CONFIG_FILES.includes(segments2.join("/"))) return true;
|
|
1197
|
+
return DENY_FILES.some((re2) => re2.test(segments2[segments2.length - 1]));
|
|
1198
1198
|
}
|
|
1199
1199
|
function isDeniedSourceDir(name, parentRel) {
|
|
1200
1200
|
const base = name.split(sep).pop() ?? name;
|
|
@@ -17190,8 +17190,8 @@ function wireKind(value2) {
|
|
|
17190
17190
|
}
|
|
17191
17191
|
function jsonPointer(dotted) {
|
|
17192
17192
|
if (dotted === "") return "";
|
|
17193
|
-
const
|
|
17194
|
-
return `/${
|
|
17193
|
+
const segments2 = dotted.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean).map((s2) => s2.replace(/~/g, "~0").replace(/\//g, "~1"));
|
|
17194
|
+
return `/${segments2.join("/")}`;
|
|
17195
17195
|
}
|
|
17196
17196
|
function componentPropFindings(descriptor) {
|
|
17197
17197
|
const out2 = [];
|
|
@@ -18126,10 +18126,10 @@ function validateScreenDescriptor(screenId, descriptor, opts = {}) {
|
|
|
18126
18126
|
const lbIntegrity = descriptor?.logicBundle?.integrity;
|
|
18127
18127
|
const schemaIssuesAt = /* @__PURE__ */ new Map();
|
|
18128
18128
|
const dottedCandidates = (pointer3) => {
|
|
18129
|
-
const
|
|
18130
|
-
if (
|
|
18129
|
+
const segments2 = pointer3.split("/").filter(Boolean).map((s2) => s2.replace(/~1/g, "/").replace(/~0/g, "~"));
|
|
18130
|
+
if (segments2.filter((s2) => /^\d+$/.test(s2)).length > 3) return [];
|
|
18131
18131
|
let out2 = [""];
|
|
18132
|
-
for (const seg2 of
|
|
18132
|
+
for (const seg2 of segments2) {
|
|
18133
18133
|
const spellings = /^\d+$/.test(seg2) ? [`[${seg2}]`, `.${seg2}`] : [`.${seg2}`];
|
|
18134
18134
|
out2 = out2.flatMap((acc) => spellings.map((s2) => acc === "" && s2.startsWith(".") ? s2.slice(1) : acc + s2));
|
|
18135
18135
|
}
|
|
@@ -21785,7 +21785,7 @@ function ensureTemplates({
|
|
|
21785
21785
|
root = REPO2,
|
|
21786
21786
|
env = process.env,
|
|
21787
21787
|
log = (m2) => console.error(m2),
|
|
21788
|
-
spawn:
|
|
21788
|
+
spawn: spawn11 = spawnSync3,
|
|
21789
21789
|
generator = GENERATOR,
|
|
21790
21790
|
waitMs = 10 * 6e4
|
|
21791
21791
|
} = {}) {
|
|
@@ -21801,7 +21801,7 @@ function ensureTemplates({
|
|
|
21801
21801
|
if (!refresh) log(`ensure-templates: generating ${TEMPLATES_REL} (gitignored; ~10s) \u2026`);
|
|
21802
21802
|
rmSync5(stampPath(out2), { force: true });
|
|
21803
21803
|
const { HIMI_TEMPLATES_OUT: _scratch, ...childEnv } = env;
|
|
21804
|
-
const r3 =
|
|
21804
|
+
const r3 = spawn11(process.execPath, ["--import", "tsx", generator], {
|
|
21805
21805
|
cwd: root,
|
|
21806
21806
|
env: childEnv,
|
|
21807
21807
|
encoding: "utf8",
|
|
@@ -21866,7 +21866,7 @@ function ensureBundles({
|
|
|
21866
21866
|
root = REPO3,
|
|
21867
21867
|
env = process.env,
|
|
21868
21868
|
log = (m2) => console.error(m2),
|
|
21869
|
-
spawn:
|
|
21869
|
+
spawn: spawn11 = spawnSync4,
|
|
21870
21870
|
waitMs = 10 * 6e4
|
|
21871
21871
|
} = {}) {
|
|
21872
21872
|
if (env[BUNDLES_FRESH]) return false;
|
|
@@ -21880,7 +21880,7 @@ function ensureBundles({
|
|
|
21880
21880
|
if (waited && bundlesReady(root)) return false;
|
|
21881
21881
|
if (!refresh) log(`ensure-bundles: building ${BUNDLES_REL} (gitignored; a few seconds) \u2026`);
|
|
21882
21882
|
rmSync6(stampPath(out2), { force: true });
|
|
21883
|
-
const r3 =
|
|
21883
|
+
const r3 = spawn11(process.execPath, [GENERATOR2], {
|
|
21884
21884
|
cwd: root,
|
|
21885
21885
|
env: { ...env, [BUNDLES_LOCK_HELD]: "1" },
|
|
21886
21886
|
encoding: "utf8",
|
|
@@ -33273,9 +33273,9 @@ var init_wix_member_login = __esm({
|
|
|
33273
33273
|
// ../../core/dev-server/src/wix-gateway.ts
|
|
33274
33274
|
import { readFileSync as readFileSync29, existsSync as existsSync29 } from "node:fs";
|
|
33275
33275
|
function isSensitiveBodyName(name) {
|
|
33276
|
-
const
|
|
33277
|
-
for (let i2 = 0; i2 <
|
|
33278
|
-
const tail = normKey(
|
|
33276
|
+
const segments2 = name.split(/[^A-Za-z0-9]+/).filter(Boolean);
|
|
33277
|
+
for (let i2 = 0; i2 < segments2.length; i2++) {
|
|
33278
|
+
const tail = normKey(segments2.slice(i2).join(""));
|
|
33279
33279
|
for (const k2 of SECRET_BODY_KEYS) if (tail.startsWith(k2)) return true;
|
|
33280
33280
|
}
|
|
33281
33281
|
return false;
|
|
@@ -45382,7 +45382,7 @@ var init_pdf = __esm({
|
|
|
45382
45382
|
var defineProperty = Object.defineProperty;
|
|
45383
45383
|
var stringSlice = uncurryThis("".slice);
|
|
45384
45384
|
var replace = uncurryThis("".replace);
|
|
45385
|
-
var
|
|
45385
|
+
var join137 = uncurryThis([].join);
|
|
45386
45386
|
var CONFIGURABLE_LENGTH = DESCRIPTORS && !fails(function() {
|
|
45387
45387
|
return defineProperty(function() {
|
|
45388
45388
|
}, "length", { value: 8 }).length !== 8;
|
|
@@ -45409,7 +45409,7 @@ var init_pdf = __esm({
|
|
|
45409
45409
|
}
|
|
45410
45410
|
var state = enforceInternalState(value2);
|
|
45411
45411
|
if (!hasOwn(state, "source")) {
|
|
45412
|
-
state.source =
|
|
45412
|
+
state.source = join137(TEMPLATE, typeof name == "string" ? name : "");
|
|
45413
45413
|
}
|
|
45414
45414
|
return value2;
|
|
45415
45415
|
};
|
|
@@ -46449,10 +46449,10 @@ var init_pdf = __esm({
|
|
|
46449
46449
|
if (stringLength % 2 !== 0) throw new SyntaxError2("String should be an even number of characters");
|
|
46450
46450
|
var maxLength = into ? min(into.length, stringLength / 2) : stringLength / 2;
|
|
46451
46451
|
var bytes2 = into || new Uint8Array2(maxLength);
|
|
46452
|
-
var
|
|
46452
|
+
var segments2 = stringMatch(string7, /[\S\s]{2}/g);
|
|
46453
46453
|
var written = 0;
|
|
46454
46454
|
for (; written < maxLength; written++) {
|
|
46455
|
-
var result = +("0x" +
|
|
46455
|
+
var result = +("0x" + segments2[written] + "0");
|
|
46456
46456
|
if (result !== result) {
|
|
46457
46457
|
throw new SyntaxError2("String should only contain hex characters");
|
|
46458
46458
|
}
|
|
@@ -47932,7 +47932,7 @@ var init_pdf = __esm({
|
|
|
47932
47932
|
var charAt = uncurryThis("".charAt);
|
|
47933
47933
|
var Uint8Array2 = globalThis2.Uint8Array;
|
|
47934
47934
|
var $Array = globalThis2.Array;
|
|
47935
|
-
var
|
|
47935
|
+
var join137 = uncurryThis([].join);
|
|
47936
47936
|
var INCORRECT_BEHAVIOR_OR_DOESNT_EXISTS = !Uint8Array2 || !Uint8Array2.prototype.toBase64 || !(function() {
|
|
47937
47937
|
try {
|
|
47938
47938
|
var target = new Uint8Array2();
|
|
@@ -47978,7 +47978,7 @@ var init_pdf = __esm({
|
|
|
47978
47978
|
result[written++] = "=";
|
|
47979
47979
|
}
|
|
47980
47980
|
}
|
|
47981
|
-
return
|
|
47981
|
+
return join137(result, "");
|
|
47982
47982
|
}
|
|
47983
47983
|
});
|
|
47984
47984
|
},
|
|
@@ -47990,7 +47990,7 @@ var init_pdf = __esm({
|
|
|
47990
47990
|
var anUint8Array = __webpack_require__3(4154);
|
|
47991
47991
|
var notDetached = __webpack_require__3(5169);
|
|
47992
47992
|
var numberToString2 = uncurryThis(1.1.toString);
|
|
47993
|
-
var
|
|
47993
|
+
var join137 = uncurryThis([].join);
|
|
47994
47994
|
var $Array = Array;
|
|
47995
47995
|
var Uint8Array2 = globalThis2.Uint8Array;
|
|
47996
47996
|
var INCORRECT_BEHAVIOR_OR_DOESNT_EXISTS = !Uint8Array2 || !Uint8Array2.prototype.toHex || !(function() {
|
|
@@ -48010,7 +48010,7 @@ var init_pdf = __esm({
|
|
|
48010
48010
|
var hex2 = numberToString2(this[i2], 16);
|
|
48011
48011
|
result[i2] = hex2.length === 1 ? "0" + hex2 : hex2;
|
|
48012
48012
|
}
|
|
48013
|
-
return
|
|
48013
|
+
return join137(result, "");
|
|
48014
48014
|
}
|
|
48015
48015
|
});
|
|
48016
48016
|
},
|
|
@@ -124646,12 +124646,12 @@ function parseShapeKind(raw) {
|
|
|
124646
124646
|
if (k2 === "polygon" || k2 === "circle") return k2;
|
|
124647
124647
|
return "unknown";
|
|
124648
124648
|
}
|
|
124649
|
-
function circleRing(centreLat, centreLng, radiusM,
|
|
124650
|
-
if (!(radiusM > 0) ||
|
|
124649
|
+
function circleRing(centreLat, centreLng, radiusM, segments2 = CIRCLE_SEGMENTS) {
|
|
124650
|
+
if (!(radiusM > 0) || segments2 < 3) return [];
|
|
124651
124651
|
const dLat = radiusM / METRES_PER_DEG_LAT;
|
|
124652
124652
|
const dLng = radiusM / (METRES_PER_DEG_LAT * Math.max(0.01, Math.abs(Math.cos(centreLat * Math.PI / 180))));
|
|
124653
|
-
return Array.from({ length:
|
|
124654
|
-
const theta = 2 * Math.PI * i2 /
|
|
124653
|
+
return Array.from({ length: segments2 }, (_2, i2) => {
|
|
124654
|
+
const theta = 2 * Math.PI * i2 / segments2;
|
|
124655
124655
|
return { latitude: centreLat + dLat * Math.sin(theta), longitude: centreLng + dLng * Math.cos(theta) };
|
|
124656
124656
|
});
|
|
124657
124657
|
}
|
|
@@ -145351,8 +145351,8 @@ function materializeForPreview(appDir3, slug, displayName3) {
|
|
|
145351
145351
|
}
|
|
145352
145352
|
async function appId(dir) {
|
|
145353
145353
|
try {
|
|
145354
|
-
const { readFileSync:
|
|
145355
|
-
const m2 = JSON.parse(
|
|
145354
|
+
const { readFileSync: readFileSync142 } = await import("node:fs");
|
|
145355
|
+
const m2 = JSON.parse(readFileSync142(join34(dir, "himalaya.content.json"), "utf8"));
|
|
145356
145356
|
if (m2.name) return m2.name;
|
|
145357
145357
|
} catch {
|
|
145358
145358
|
}
|
|
@@ -145814,12 +145814,12 @@ function npmInstallArgs(registry2, version5) {
|
|
|
145814
145814
|
const pinned = `${normalizeRegistry(registry2) ?? registry2}/`;
|
|
145815
145815
|
return ["i", "-g", `${CLI_PACKAGE}@${version5}`, `--registry=${pinned}`, `--@wix:registry=${pinned}`];
|
|
145816
145816
|
}
|
|
145817
|
-
function createUpdateRunner(
|
|
145817
|
+
function createUpdateRunner(spawn11 = spawnSync6) {
|
|
145818
145818
|
return {
|
|
145819
145819
|
install: async (registry2, version5) => {
|
|
145820
145820
|
if (!isTrustedRegistry(registry2)) return { ok: false, detail: `refusing untrusted registry ${registry2}` };
|
|
145821
145821
|
if (!INSTALLABLE_SPEC.test(version5)) return { ok: false, detail: `refusing install spec ${JSON.stringify(version5)}` };
|
|
145822
|
-
const result =
|
|
145822
|
+
const result = spawn11("npm", npmInstallArgs(registry2, version5), {
|
|
145823
145823
|
// npm's stdout goes to OUR stderr: in `himi <cmd> --json | jq` (and `himi upgrade --json`) its
|
|
145824
145824
|
// "added 212 packages" would otherwise land in stdout ahead of the envelope and break the
|
|
145825
145825
|
// parse — the agent case this whole feature exists for (#2985 review). And no stdin: an
|
|
@@ -150245,21 +150245,21 @@ var init_Expression = __esm({
|
|
|
150245
150245
|
* @returns {Array} Array of segment objects
|
|
150246
150246
|
*/
|
|
150247
150247
|
_parse(pattern) {
|
|
150248
|
-
const
|
|
150248
|
+
const segments2 = [];
|
|
150249
150249
|
let i2 = 0;
|
|
150250
150250
|
let currentPart = "";
|
|
150251
150251
|
while (i2 < pattern.length) {
|
|
150252
150252
|
if (pattern[i2] === this.separator) {
|
|
150253
150253
|
if (i2 + 1 < pattern.length && pattern[i2 + 1] === this.separator) {
|
|
150254
150254
|
if (currentPart.trim()) {
|
|
150255
|
-
|
|
150255
|
+
segments2.push(this._parseSegment(currentPart.trim()));
|
|
150256
150256
|
currentPart = "";
|
|
150257
150257
|
}
|
|
150258
|
-
|
|
150258
|
+
segments2.push({ type: "deep-wildcard" });
|
|
150259
150259
|
i2 += 2;
|
|
150260
150260
|
} else {
|
|
150261
150261
|
if (currentPart.trim()) {
|
|
150262
|
-
|
|
150262
|
+
segments2.push(this._parseSegment(currentPart.trim()));
|
|
150263
150263
|
}
|
|
150264
150264
|
currentPart = "";
|
|
150265
150265
|
i2++;
|
|
@@ -150270,9 +150270,9 @@ var init_Expression = __esm({
|
|
|
150270
150270
|
}
|
|
150271
150271
|
}
|
|
150272
150272
|
if (currentPart.trim()) {
|
|
150273
|
-
|
|
150273
|
+
segments2.push(this._parseSegment(currentPart.trim()));
|
|
150274
150274
|
}
|
|
150275
|
-
return
|
|
150275
|
+
return segments2;
|
|
150276
150276
|
}
|
|
150277
150277
|
/**
|
|
150278
150278
|
* Parse a single segment
|
|
@@ -150853,24 +150853,24 @@ var init_Matcher = __esm({
|
|
|
150853
150853
|
* @returns {boolean}
|
|
150854
150854
|
*/
|
|
150855
150855
|
matches(expression) {
|
|
150856
|
-
const
|
|
150857
|
-
if (
|
|
150856
|
+
const segments2 = expression.segments;
|
|
150857
|
+
if (segments2.length === 0) {
|
|
150858
150858
|
return false;
|
|
150859
150859
|
}
|
|
150860
150860
|
if (expression.hasDeepWildcard()) {
|
|
150861
|
-
return this._matchWithDeepWildcard(
|
|
150861
|
+
return this._matchWithDeepWildcard(segments2);
|
|
150862
150862
|
}
|
|
150863
|
-
return this._matchSimple(
|
|
150863
|
+
return this._matchSimple(segments2);
|
|
150864
150864
|
}
|
|
150865
150865
|
/**
|
|
150866
150866
|
* @private
|
|
150867
150867
|
*/
|
|
150868
|
-
_matchSimple(
|
|
150869
|
-
if (this.path.length !==
|
|
150868
|
+
_matchSimple(segments2) {
|
|
150869
|
+
if (this.path.length !== segments2.length) {
|
|
150870
150870
|
return false;
|
|
150871
150871
|
}
|
|
150872
|
-
for (let i2 = 0; i2 <
|
|
150873
|
-
if (!this._matchSegment(
|
|
150872
|
+
for (let i2 = 0; i2 < segments2.length; i2++) {
|
|
150873
|
+
if (!this._matchSegment(segments2[i2], this.path[i2], i2 === this.path.length - 1)) {
|
|
150874
150874
|
return false;
|
|
150875
150875
|
}
|
|
150876
150876
|
}
|
|
@@ -150879,17 +150879,17 @@ var init_Matcher = __esm({
|
|
|
150879
150879
|
/**
|
|
150880
150880
|
* @private
|
|
150881
150881
|
*/
|
|
150882
|
-
_matchWithDeepWildcard(
|
|
150882
|
+
_matchWithDeepWildcard(segments2) {
|
|
150883
150883
|
let pathIdx = this.path.length - 1;
|
|
150884
|
-
let segIdx =
|
|
150884
|
+
let segIdx = segments2.length - 1;
|
|
150885
150885
|
while (segIdx >= 0 && pathIdx >= 0) {
|
|
150886
|
-
const segment =
|
|
150886
|
+
const segment = segments2[segIdx];
|
|
150887
150887
|
if (segment.type === "deep-wildcard") {
|
|
150888
150888
|
segIdx--;
|
|
150889
150889
|
if (segIdx < 0) {
|
|
150890
150890
|
return true;
|
|
150891
150891
|
}
|
|
150892
|
-
const nextSeg =
|
|
150892
|
+
const nextSeg = segments2[segIdx];
|
|
150893
150893
|
let found = false;
|
|
150894
150894
|
for (let i2 = pathIdx; i2 >= 0; i2--) {
|
|
150895
150895
|
if (this._matchSegment(nextSeg, this.path[i2], i2 === this.path.length - 1)) {
|
|
@@ -158149,16 +158149,16 @@ function writeAppSource(entries, destDir) {
|
|
|
158149
158149
|
const written = [];
|
|
158150
158150
|
for (const entry of entries) {
|
|
158151
158151
|
if (isDeniedSourcePath(entry.path)) continue;
|
|
158152
|
-
const
|
|
158152
|
+
const segments2 = entry.path.split("/");
|
|
158153
158153
|
let dir = root;
|
|
158154
|
-
for (const segment of
|
|
158154
|
+
for (const segment of segments2.slice(0, -1)) {
|
|
158155
158155
|
dir = join42(dir, segment);
|
|
158156
158156
|
const kind = pathKind(dir);
|
|
158157
158157
|
if (kind?.isSymbolicLink()) unlinkSync3(dir);
|
|
158158
158158
|
else if (kind) continue;
|
|
158159
158159
|
mkdirSync27(dir);
|
|
158160
158160
|
}
|
|
158161
|
-
const target = join42(root, ...
|
|
158161
|
+
const target = join42(root, ...segments2);
|
|
158162
158162
|
if (pathKind(target)?.isSymbolicLink()) unlinkSync3(target);
|
|
158163
158163
|
writeFileSync21(target, entry.bytes);
|
|
158164
158164
|
written.push(entry.path);
|
|
@@ -158189,10 +158189,10 @@ function writeConflicts(entries, destDir) {
|
|
|
158189
158189
|
};
|
|
158190
158190
|
for (const entry of entries) {
|
|
158191
158191
|
if (isDeniedSourcePath(entry.path)) continue;
|
|
158192
|
-
const
|
|
158192
|
+
const segments2 = entry.path.split("/");
|
|
158193
158193
|
let dir = root;
|
|
158194
158194
|
let stop = false;
|
|
158195
|
-
for (const [i2, segment] of
|
|
158195
|
+
for (const [i2, segment] of segments2.slice(0, -1).entries()) {
|
|
158196
158196
|
dir = join42(dir, segment);
|
|
158197
158197
|
const kind2 = pathKind(dir);
|
|
158198
158198
|
if (!kind2 || kind2.isSymbolicLink()) {
|
|
@@ -158200,12 +158200,12 @@ function writeConflicts(entries, destDir) {
|
|
|
158200
158200
|
break;
|
|
158201
158201
|
}
|
|
158202
158202
|
if (kind2.isDirectory()) continue;
|
|
158203
|
-
say(
|
|
158203
|
+
say(segments2.slice(0, i2 + 1).join("/"), "is a file here, but the release has a directory at that path");
|
|
158204
158204
|
stop = true;
|
|
158205
158205
|
break;
|
|
158206
158206
|
}
|
|
158207
158207
|
if (stop) continue;
|
|
158208
|
-
const kind = pathKind(join42(root, ...
|
|
158208
|
+
const kind = pathKind(join42(root, ...segments2));
|
|
158209
158209
|
if (kind && !kind.isSymbolicLink() && kind.isDirectory()) {
|
|
158210
158210
|
say(entry.path, "is a directory here, but the release has a file at that path");
|
|
158211
158211
|
}
|
|
@@ -158219,8 +158219,8 @@ function removeStaleSource(entries, destDir) {
|
|
|
158219
158219
|
const needed = /* @__PURE__ */ new Set();
|
|
158220
158220
|
for (const entry of entries) {
|
|
158221
158221
|
if (isDeniedSourcePath(entry.path)) continue;
|
|
158222
|
-
const
|
|
158223
|
-
for (let i2 = 1; i2 <
|
|
158222
|
+
const segments2 = entry.path.split("/");
|
|
158223
|
+
for (let i2 = 1; i2 < segments2.length; i2++) needed.add(segments2.slice(0, i2).join("/"));
|
|
158224
158224
|
}
|
|
158225
158225
|
if (existsSync49(root)) pruneEmptyDirs(root, "", needed, removed);
|
|
158226
158226
|
return removed.sort();
|
|
@@ -161316,14 +161316,14 @@ function scoreOverlays(verticals, layout) {
|
|
|
161316
161316
|
function pagePathForRole(url) {
|
|
161317
161317
|
try {
|
|
161318
161318
|
const u2 = new URL(url);
|
|
161319
|
-
const
|
|
161319
|
+
const segments2 = u2.pathname.split("/").filter(Boolean);
|
|
161320
161320
|
const wixHost = /(^|\.)(wixsite\.com|wixstudio\.com)$/i.test(u2.hostname);
|
|
161321
161321
|
if (wixHost) {
|
|
161322
|
-
const page =
|
|
161322
|
+
const page = segments2.slice(1);
|
|
161323
161323
|
return { path: "/" + page.join("/"), isHome: page.length === 0 };
|
|
161324
161324
|
}
|
|
161325
|
-
const leaf =
|
|
161326
|
-
const isHome =
|
|
161325
|
+
const leaf = segments2[segments2.length - 1] ?? "";
|
|
161326
|
+
const isHome = segments2.length === 0 || /^(home|index)$/i.test(leaf);
|
|
161327
161327
|
return { path: u2.pathname.replace(/\/+$/, "") || "/", isHome };
|
|
161328
161328
|
} catch {
|
|
161329
161329
|
return { path: url, isHome: false };
|
|
@@ -168171,6 +168171,119 @@ var init_nav_slots = __esm({
|
|
|
168171
168171
|
}
|
|
168172
168172
|
});
|
|
168173
168173
|
|
|
168174
|
+
// ../../core/ts/src/push-routes.ts
|
|
168175
|
+
function adaptPayloadLink(link, adapter, linkPrefixes) {
|
|
168176
|
+
const raw = (link ?? "").trim();
|
|
168177
|
+
if (!raw) return { residual: raw, adapted: false };
|
|
168178
|
+
if (adapter === "wix-ping") {
|
|
168179
|
+
const wix = adaptWixLink(raw);
|
|
168180
|
+
if (wix) return wix;
|
|
168181
|
+
}
|
|
168182
|
+
const rest = stripLinkPrefix(raw, linkPrefixes);
|
|
168183
|
+
if (rest !== void 0) return { residual: stripLeadingSlashes(rest), adapted: true };
|
|
168184
|
+
if (raw.startsWith("/")) return { residual: stripLeadingSlashes(raw), adapted: true };
|
|
168185
|
+
return { residual: raw, adapted: false };
|
|
168186
|
+
}
|
|
168187
|
+
function stripLinkPrefix(raw, prefixes) {
|
|
168188
|
+
let best;
|
|
168189
|
+
let bestLength = -1;
|
|
168190
|
+
for (const entry of Array.isArray(prefixes) ? prefixes : []) {
|
|
168191
|
+
const prefix = typeof entry === "string" ? entry.trim() : "";
|
|
168192
|
+
if (!prefix || prefix.length <= bestLength || !startsWithLinkPrefix(raw, prefix)) continue;
|
|
168193
|
+
best = raw.slice(prefix.length);
|
|
168194
|
+
bestLength = prefix.length;
|
|
168195
|
+
}
|
|
168196
|
+
return best;
|
|
168197
|
+
}
|
|
168198
|
+
function startsWithLinkPrefix(raw, prefix) {
|
|
168199
|
+
if (raw.length < prefix.length) return false;
|
|
168200
|
+
const head3 = caseInsensitiveHeadLength(prefix);
|
|
168201
|
+
if (raw.slice(0, head3).toLowerCase() !== prefix.slice(0, head3).toLowerCase()) return false;
|
|
168202
|
+
if (raw.slice(head3, prefix.length) !== prefix.slice(head3)) return false;
|
|
168203
|
+
if (prefix.endsWith("/") || linkPrefixSchemeLength(prefix) === prefix.length || raw.length === prefix.length) return true;
|
|
168204
|
+
return "/?#".includes(raw.charAt(prefix.length));
|
|
168205
|
+
}
|
|
168206
|
+
function caseInsensitiveHeadLength(prefix) {
|
|
168207
|
+
const scheme = linkPrefixSchemeLength(prefix);
|
|
168208
|
+
if (scheme === 0 || !prefix.startsWith("//", scheme)) return scheme;
|
|
168209
|
+
const slash = prefix.indexOf("/", scheme + 2);
|
|
168210
|
+
return slash < 0 ? prefix.length : slash;
|
|
168211
|
+
}
|
|
168212
|
+
function linkPrefixSchemeLength(prefix) {
|
|
168213
|
+
for (let i2 = 0; i2 < prefix.length; i2++) {
|
|
168214
|
+
const c2 = prefix.charAt(i2);
|
|
168215
|
+
if (c2 === ":") return i2 > 0 ? i2 + 1 : 0;
|
|
168216
|
+
const letter = c2 >= "a" && c2 <= "z" || c2 >= "A" && c2 <= "Z";
|
|
168217
|
+
const later2 = c2 >= "0" && c2 <= "9" || c2 === "+" || c2 === "-" || c2 === ".";
|
|
168218
|
+
if (!letter && !(i2 > 0 && later2)) return 0;
|
|
168219
|
+
}
|
|
168220
|
+
return 0;
|
|
168221
|
+
}
|
|
168222
|
+
function adaptWixLink(raw) {
|
|
168223
|
+
let rest;
|
|
168224
|
+
if (raw.toLowerCase().startsWith(WIX_SCHEME_PREFIX)) {
|
|
168225
|
+
rest = raw.slice(WIX_SCHEME_PREFIX.length);
|
|
168226
|
+
} else {
|
|
168227
|
+
const host = hostOf(raw);
|
|
168228
|
+
if (!host || !WIX_UNIVERSAL_HOST.test(host)) return void 0;
|
|
168229
|
+
rest = raw.slice(raw.toLowerCase().indexOf(host) + host.length);
|
|
168230
|
+
}
|
|
168231
|
+
const [pathPart, queryPart = ""] = splitOnce(stripLeadingSlashes(rest), "?");
|
|
168232
|
+
const kept = [];
|
|
168233
|
+
let metaSiteId;
|
|
168234
|
+
for (const pair of queryPart.split("&")) {
|
|
168235
|
+
if (!pair) continue;
|
|
168236
|
+
const [key3, value2 = ""] = splitOnce(pair, "=");
|
|
168237
|
+
if (key3 === "metaSiteId") metaSiteId = decodeMaybe(value2);
|
|
168238
|
+
if (PING_BOOKKEEPING_KEYS.has(key3)) continue;
|
|
168239
|
+
kept.push(pair);
|
|
168240
|
+
}
|
|
168241
|
+
const residual = kept.length ? `${pathPart}?${kept.join("&")}` : pathPart;
|
|
168242
|
+
return { residual, metaSiteId: metaSiteId ?? siteFromPath(pathPart), adapted: true };
|
|
168243
|
+
}
|
|
168244
|
+
function siteFromPath(pathPart) {
|
|
168245
|
+
const site = siteSegment(segments(pathPart));
|
|
168246
|
+
return site ? decodeMaybe(site, false) : void 0;
|
|
168247
|
+
}
|
|
168248
|
+
function siteSegment(segs) {
|
|
168249
|
+
if (segs[0] === "my-account" && segs[1] && segs[1] !== "app") return segs[1];
|
|
168250
|
+
if (segs[0] === "shared-gallery" && segs[1]) return segs[1];
|
|
168251
|
+
if (segs[0] === "lists" && segs[1]) return segs[1];
|
|
168252
|
+
if (segs[0] === "spaces" && segs[1] === "lists" && segs[2]) return segs[2];
|
|
168253
|
+
if (segs[0] === "notifications" && segs[1] === "list" && segs[2]) return segs[2];
|
|
168254
|
+
return void 0;
|
|
168255
|
+
}
|
|
168256
|
+
function hostOf(url) {
|
|
168257
|
+
const m2 = /^[A-Za-z][A-Za-z0-9+.-]*:\/\/([^/?#]+)/.exec(url);
|
|
168258
|
+
return m2 ? m2[1].toLowerCase() : null;
|
|
168259
|
+
}
|
|
168260
|
+
function splitOnce(s2, sep26) {
|
|
168261
|
+
const i2 = s2.indexOf(sep26);
|
|
168262
|
+
return i2 < 0 ? [s2, void 0] : [s2.slice(0, i2), s2.slice(i2 + sep26.length)];
|
|
168263
|
+
}
|
|
168264
|
+
function stripLeadingSlashes(s2) {
|
|
168265
|
+
return s2.replace(/^\/+/, "");
|
|
168266
|
+
}
|
|
168267
|
+
function segments(path2) {
|
|
168268
|
+
return path2.split("/").filter((s2) => s2.length > 0);
|
|
168269
|
+
}
|
|
168270
|
+
function decodeMaybe(value2, plusAsSpace = true) {
|
|
168271
|
+
try {
|
|
168272
|
+
return decodeURIComponent(plusAsSpace ? value2.replace(/\+/g, " ") : value2);
|
|
168273
|
+
} catch {
|
|
168274
|
+
return value2;
|
|
168275
|
+
}
|
|
168276
|
+
}
|
|
168277
|
+
var WIX_UNIVERSAL_HOST, WIX_SCHEME_PREFIX, PING_BOOKKEEPING_KEYS;
|
|
168278
|
+
var init_push_routes = __esm({
|
|
168279
|
+
"../../core/ts/src/push-routes.ts"() {
|
|
168280
|
+
init_define_HHP_CATALOG();
|
|
168281
|
+
WIX_UNIVERSAL_HOST = /^(?:manage\.wix\.app|www\.wix\.app|m-[A-Za-z0-9-]+\.branded\.wix\.app)$/;
|
|
168282
|
+
WIX_SCHEME_PREFIX = "wix:/";
|
|
168283
|
+
PING_BOOKKEEPING_KEYS = /* @__PURE__ */ new Set(["metaSiteId", "d"]);
|
|
168284
|
+
}
|
|
168285
|
+
});
|
|
168286
|
+
|
|
168174
168287
|
// src/nav-lint.ts
|
|
168175
168288
|
var nav_lint_exports = {};
|
|
168176
168289
|
__export(nav_lint_exports, {
|
|
@@ -168209,6 +168322,7 @@ async function navIssues(dir, strict) {
|
|
|
168209
168322
|
pushScreenMapIssues(cfg.push, provisioning, warn3);
|
|
168210
168323
|
pushAuthIssues(cfg.push, cfg.auth, provisioning, warn3);
|
|
168211
168324
|
pushFamilyIssues(cfg.push, warn3);
|
|
168325
|
+
pushLinkPrefixIssues(cfg.push, provisioning, warn3);
|
|
168212
168326
|
const captcha = provisioning.siteId && !placeholderLogin(cfg.auth) ? captchaAuthFinding(cfg.auth, provisioning.siteId) : void 0;
|
|
168213
168327
|
if (captcha && captcha.code !== "captcha_auth_site_case" && !issues.some((i2) => i2.ruleCode === "push-auth-site"))
|
|
168214
168328
|
push("warning", "auth-captcha-site", captcha.message);
|
|
@@ -168375,6 +168489,51 @@ function pushRouteIssues(push, nav, provisioning, warn3) {
|
|
|
168375
168489
|
}
|
|
168376
168490
|
}
|
|
168377
168491
|
}
|
|
168492
|
+
function pushLinkPrefixIssues(push, provisioning, warn3) {
|
|
168493
|
+
if (!isPlainObject2(push) || push.linkPrefixes === void 0) return;
|
|
168494
|
+
if (!Array.isArray(push.linkPrefixes)) {
|
|
168495
|
+
warn3(
|
|
168496
|
+
"push-link-prefixes-invalid",
|
|
168497
|
+
`push.linkPrefixes must be a list of non-empty strings, e.g. ["legacyapp://", "https://legacy.example.com/app/"]; the device reads anything else as no prefixes.`
|
|
168498
|
+
);
|
|
168499
|
+
return;
|
|
168500
|
+
}
|
|
168501
|
+
const prefixes = push.linkPrefixes.filter((p2) => typeof p2 === "string" && !!p2.trim());
|
|
168502
|
+
const skipped = push.linkPrefixes.length - prefixes.length;
|
|
168503
|
+
if (skipped > 0) {
|
|
168504
|
+
warn3(
|
|
168505
|
+
"push-link-prefixes-invalid",
|
|
168506
|
+
`push.linkPrefixes must hold non-empty strings only; the device skips ${skipped === 1 ? "the 1 entry" : `the ${skipped} entries`} that ${skipped === 1 ? "is" : "are"} not one and keeps the other prefixes.`
|
|
168507
|
+
);
|
|
168508
|
+
}
|
|
168509
|
+
for (const raw of prefixes) {
|
|
168510
|
+
const prefix = raw.trim();
|
|
168511
|
+
if (push.payloadAdapter === "wix-ping" && wixLinkSpacePrefix(prefix)) {
|
|
168512
|
+
warn3(
|
|
168513
|
+
"push-link-prefix-shadowed",
|
|
168514
|
+
`push.linkPrefixes: "${prefix}" is in the Wix link space, which the "wix-ping" adapter already strips first, so this prefix never applies. Remove it.`
|
|
168515
|
+
);
|
|
168516
|
+
}
|
|
168517
|
+
}
|
|
168518
|
+
const authored2 = Array.isArray(push.routes) && push.routes.length > 0;
|
|
168519
|
+
if (prefixes.length > 0 && !authored2 && derivesWixPushRoutes(push, provisioning.installedVerticals)) {
|
|
168520
|
+
warn3(
|
|
168521
|
+
"push-link-prefixes-derived-routes",
|
|
168522
|
+
`push.linkPrefixes is set, but the only push routes are the ones derived from the site's verticals, so a stripped link is matched against the Wix notification paths alone (e.g. "my-account/:site/stores/orders/:orderId"). If your legacy links use paths of their own, declare push.routes for them \u2014 a declared table replaces the derived one, so list the Wix routes you still need there too.`
|
|
168523
|
+
);
|
|
168524
|
+
return;
|
|
168525
|
+
}
|
|
168526
|
+
if (prefixes.length > 0 && !authored2 && push.payloadAdapter !== "wix-ping") {
|
|
168527
|
+
warn3(
|
|
168528
|
+
"push-link-prefixes-unrouted",
|
|
168529
|
+
`push.linkPrefixes is set but push.routes is empty, so a stripped link matches nothing and still opens the home screen. Declare a route for each destination, e.g. { match: "widget/:id", link: "<scheme>://screen/<screen>?id={id}" }.`
|
|
168530
|
+
);
|
|
168531
|
+
}
|
|
168532
|
+
}
|
|
168533
|
+
function wixLinkSpacePrefix(prefix) {
|
|
168534
|
+
const probe2 = `${prefix}/x`;
|
|
168535
|
+
return adaptPayloadLink(probe2, "wix-ping").adapted && !adaptPayloadLink(probe2, "").adapted;
|
|
168536
|
+
}
|
|
168378
168537
|
function pushScreenMapIssues(push, provisioning, warn3) {
|
|
168379
168538
|
if (!isPlainObject2(push) || !isPlainObject2(push.screens)) return;
|
|
168380
168539
|
const destinations = WIX_MEMBER_PUSH_DESTINATIONS.map((d2) => d2.id);
|
|
@@ -168468,6 +168627,7 @@ var init_nav_lint = __esm({
|
|
|
168468
168627
|
init_nav_slots();
|
|
168469
168628
|
init_home_screen_id();
|
|
168470
168629
|
init_wix_push_links();
|
|
168630
|
+
init_push_routes();
|
|
168471
168631
|
init_captcha_auth();
|
|
168472
168632
|
init_wix_placeholders();
|
|
168473
168633
|
init_preview_surfaces();
|
|
@@ -183640,44 +183800,44 @@ var init_preview_assets_generated = __esm({
|
|
|
183640
183800
|
init_define_HHP_CATALOG();
|
|
183641
183801
|
init_preview_assets_format();
|
|
183642
183802
|
PREVIEW_ASSET_MANIFEST = [
|
|
183643
|
-
{ key: "assets/DashboardHost
|
|
183644
|
-
{ key: "assets/DevDrawer-
|
|
183645
|
-
{ key: "assets/IdiomCompare-
|
|
183646
|
-
{ key: "assets/LightboxViewer-
|
|
183647
|
-
{ key: "assets/OfflineReadingBar-
|
|
183648
|
-
{ key: "assets/PhonePreviewControl-
|
|
183649
|
-
{ key: "assets/SchemeCompare-
|
|
183650
|
-
{ key: "assets/WixFrogTelemetrySink-
|
|
183803
|
+
{ key: "assets/DashboardHost-9DNxqqDG.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 2971, sha256: "bbf3367d0bf795b6fb7f04af299fc0f2d2dfd84094b6ab4c539c0736abd7bdd8" },
|
|
183804
|
+
{ key: "assets/DevDrawer-Cmh2ysMu.js", contentType: "application/javascript; charset=utf-8", offset: 2979, length: 16783, sha256: "fb1652e4b957a01ded1022dc0a02f81c2faec1606656de9b57297d4e5bdebfaa" },
|
|
183805
|
+
{ key: "assets/IdiomCompare-BHtvykNO.js", contentType: "application/javascript; charset=utf-8", offset: 19762, length: 1926, sha256: "17d6259fb33c335533cbd8ea94bd0e01d6dc374e2f5454d9beee6d5b23ad17b2" },
|
|
183806
|
+
{ key: "assets/LightboxViewer-Cmoy48tR.js", contentType: "application/javascript; charset=utf-8", offset: 21688, length: 8171, sha256: "695647ddc5fb3608d85a4bf6b5e5acbc8de30f42f120a9c40edaec0e0053a8c8" },
|
|
183807
|
+
{ key: "assets/OfflineReadingBar-Bw5bdmJt.js", contentType: "application/javascript; charset=utf-8", offset: 29859, length: 1707, sha256: "da3d456b2baa48201ea6167f0a50d88c01a6c9d25204e6863f7070626a7e1291" },
|
|
183808
|
+
{ key: "assets/PhonePreviewControl-BkrZTlvl.js", contentType: "application/javascript; charset=utf-8", offset: 31566, length: 37768, sha256: "6165cb9fcdde37ee2fb87db56138723942c699e11bd2939224c49ba21f599e3f" },
|
|
183809
|
+
{ key: "assets/SchemeCompare-XfjOTAcV.js", contentType: "application/javascript; charset=utf-8", offset: 69334, length: 1858, sha256: "01af835c94531703c0b6ebd2db65fe3bfe4d3bdf690224886f44db50a6248e7f" },
|
|
183810
|
+
{ key: "assets/WixFrogTelemetrySink-CApx41Xu.js", contentType: "application/javascript; charset=utf-8", offset: 71192, length: 3165, sha256: "498d0d2204dde31676c08ceb8d861795054e08c312a45b693cb32bcffe8e43ea" },
|
|
183651
183811
|
{ key: "assets/calendar-ics-BvfIYWjG.js", contentType: "application/javascript; charset=utf-8", offset: 74357, length: 2192, sha256: "1636167041e9829ceccd3544297b86b8475c38bd2f759c4dbc17c813dc6e9254" },
|
|
183652
|
-
{ key: "assets/files-transfer-
|
|
183812
|
+
{ key: "assets/files-transfer-B16povVM.js", contentType: "application/javascript; charset=utf-8", offset: 76549, length: 6446, sha256: "58c3a02040a2839394dfa54d986e02a388f88c561a7b083ddf6fffbd886f5667" },
|
|
183653
183813
|
{ key: "assets/glassPreviewBrowser-DONaOehd.js", contentType: "application/javascript; charset=utf-8", offset: 82995, length: 6578, sha256: "4402c4cddd2a564e7466cdf1e12a0e0277c0400b288e1e5eda1d23e797599d31" },
|
|
183654
183814
|
{ key: "assets/image-preparation-Cj4gldm6.js", contentType: "application/javascript; charset=utf-8", offset: 89573, length: 2704, sha256: "32944ea587c2f3b84389b66b50a850437560238f1c8d33b6275973ee04eee865" },
|
|
183655
|
-
{ key: "assets/index-
|
|
183656
|
-
{ key: "assets/jsx-runtime-CY_jTiqj.js", contentType: "application/javascript; charset=utf-8", offset:
|
|
183657
|
-
{ key: "assets/pdf-
|
|
183658
|
-
{ key: "assets/pdf.worker.min-BQa_JDET.js", contentType: "application/javascript; charset=utf-8", offset:
|
|
183659
|
-
{ key: "assets/pdf.worker.min-BmVo14Nb.mjs", contentType: "application/javascript; charset=utf-8", offset:
|
|
183660
|
-
{ key: "assets/pdfDocument-
|
|
183661
|
-
{ key: "assets/pdfFetch-Cc8i1I1h.js", contentType: "application/javascript; charset=utf-8", offset:
|
|
183662
|
-
{ key: "assets/webviewBridgeHost-
|
|
183663
|
-
{ key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset:
|
|
183664
|
-
{ key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset:
|
|
183665
|
-
{ key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset:
|
|
183666
|
-
{ key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset:
|
|
183667
|
-
{ key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset:
|
|
183668
|
-
{ key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset:
|
|
183669
|
-
{ key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset:
|
|
183670
|
-
{ key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset:
|
|
183671
|
-
{ key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset:
|
|
183672
|
-
{ key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset:
|
|
183673
|
-
{ key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset:
|
|
183674
|
-
{ key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset:
|
|
183675
|
-
{ key: "himi-sw.js", contentType: "application/javascript; charset=utf-8", offset:
|
|
183676
|
-
{ key: "index.html", contentType: "text/html; charset=utf-8", offset:
|
|
183677
|
-
{ key: "ios-glass-preview.css", contentType: "text/css; charset=utf-8", offset:
|
|
183678
|
-
{ key: "kit-tab-bar.css", contentType: "text/css; charset=utf-8", offset:
|
|
183679
|
-
{ key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset:
|
|
183680
|
-
{ key: "t5-worker-frame.html", contentType: "text/html; charset=utf-8", offset:
|
|
183815
|
+
{ key: "assets/index-CBa0lcxE.js", contentType: "application/javascript; charset=utf-8", offset: 92277, length: 1494927, sha256: "ecfa1358d3abde5ba96556d4ea67c2f2ace4a1ffb31e1a3bafd087f315c88c5b" },
|
|
183816
|
+
{ key: "assets/jsx-runtime-CY_jTiqj.js", contentType: "application/javascript; charset=utf-8", offset: 1587204, length: 7624, sha256: "29dfba5b56f79a0b84d6b04d84d87617454baeba03c225f682ab2ab7ae2d5016" },
|
|
183817
|
+
{ key: "assets/pdf-B5S5rA7m.js", contentType: "application/javascript; charset=utf-8", offset: 1594828, length: 488199, sha256: "57205a426b281c8b74d84aee045430ebe8260850f1a05e30b426d690fcf14283" },
|
|
183818
|
+
{ key: "assets/pdf.worker.min-BQa_JDET.js", contentType: "application/javascript; charset=utf-8", offset: 2083027, length: 73, sha256: "41bcfda4f3c8c0a81c785ea87c69afc8e7d0ed8c333324aee94c273d881bb6aa" },
|
|
183819
|
+
{ key: "assets/pdf.worker.min-BmVo14Nb.mjs", contentType: "application/javascript; charset=utf-8", offset: 2083100, length: 1317034, sha256: "a33cfe728c584fdba4fcc1fd54bcdc2f9f2f13889ddbb5b2bd1d0f8cbe49b84e" },
|
|
183820
|
+
{ key: "assets/pdfDocument-CPQ1aH4D.js", contentType: "application/javascript; charset=utf-8", offset: 3400134, length: 3453, sha256: "864e6d5df5d41a73ffdf0e676596b6e45c687d156ae3796bd98052784c2743ab" },
|
|
183821
|
+
{ key: "assets/pdfFetch-Cc8i1I1h.js", contentType: "application/javascript; charset=utf-8", offset: 3403587, length: 2266, sha256: "1d21ad008921942217c9eac0c35b1713773b9d89c71e3ab4412781f7bb88f463" },
|
|
183822
|
+
{ key: "assets/webviewBridgeHost-C4Tz75W3.js", contentType: "application/javascript; charset=utf-8", offset: 3405853, length: 9888, sha256: "0949bca7def30f0f3604493df6f4dc25df2d63bc827fb629f1662cbd31c7a6b8" },
|
|
183823
|
+
{ key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 3415741, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
|
|
183824
|
+
{ key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 3420351, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
|
|
183825
|
+
{ key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 3908935, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
|
|
183826
|
+
{ key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 3999859, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
|
|
183827
|
+
{ key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 4090843, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
|
|
183828
|
+
{ key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 4181823, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
|
|
183829
|
+
{ key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 4272695, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
|
|
183830
|
+
{ key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 4363675, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
|
|
183831
|
+
{ key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 4472311, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
|
|
183832
|
+
{ key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 4581395, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
|
|
183833
|
+
{ key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 4690443, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
|
|
183834
|
+
{ key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 4798143, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
|
|
183835
|
+
{ key: "himi-sw.js", contentType: "application/javascript; charset=utf-8", offset: 4886251, length: 6818, sha256: "835250c3d8004f27c2b67f9b471984351ba6df07b916d97e33b43c691200a18c" },
|
|
183836
|
+
{ key: "index.html", contentType: "text/html; charset=utf-8", offset: 4893069, length: 5037, sha256: "933eef2941ba1a0dd6fda31c92e24e68ac50bbeb35a95419311b18032f30f59a" },
|
|
183837
|
+
{ key: "ios-glass-preview.css", contentType: "text/css; charset=utf-8", offset: 4898106, length: 11457, sha256: "6cb2b75264fa5fa2b4d28851878a5eab0712900e8b3a6c2370cc661d6d820805" },
|
|
183838
|
+
{ key: "kit-tab-bar.css", contentType: "text/css; charset=utf-8", offset: 4909563, length: 1171, sha256: "9e2c3a0faaf05d5471badf167a4d3bdf1c4e6dd65c432eea6d254158bfd99585" },
|
|
183839
|
+
{ key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 4910734, length: 23047, sha256: "20d1459e3f896f344e478e613d0c979a0de02e81a929a45d3a0ef6a53af36441" },
|
|
183840
|
+
{ key: "t5-worker-frame.html", contentType: "text/html; charset=utf-8", offset: 4933781, length: 23064, sha256: "8655cfe9c74212ec5dafecb49d2fdeb48b19f1bd8a710091e3e55631f9b4ab06" }
|
|
183681
183841
|
];
|
|
183682
183842
|
}
|
|
183683
183843
|
});
|
|
@@ -189678,7 +189838,7 @@ function expandVars(value2, vars) {
|
|
|
189678
189838
|
}
|
|
189679
189839
|
return out2;
|
|
189680
189840
|
}
|
|
189681
|
-
function
|
|
189841
|
+
function hostOf2(entry) {
|
|
189682
189842
|
const h2 = entry.split("?")[0].toLowerCase();
|
|
189683
189843
|
const bracketed = /^\[([^\]]*)\]/.exec(h2);
|
|
189684
189844
|
if (bracketed) return bracketed[1];
|
|
@@ -190088,7 +190248,7 @@ var init_preflight_app = __esm({
|
|
|
190088
190248
|
init_credential_profile();
|
|
190089
190249
|
init_app_icon_rules();
|
|
190090
190250
|
LOOPBACK_HOST = /^(?:localhost|127(?:\.\d{1,3}){3}|0\.0\.0\.0|\[?::1\]?)$/i;
|
|
190091
|
-
isLoopback2 = (entry) => LOOPBACK_HOST.test(
|
|
190251
|
+
isLoopback2 = (entry) => LOOPBACK_HOST.test(hostOf2(entry));
|
|
190092
190252
|
unquote3 = (v2) => v2.trim().replace(/^["']|["']$/g, "");
|
|
190093
190253
|
APP_STORE_SIZES = [
|
|
190094
190254
|
[1320, 2868],
|
|
@@ -190676,13 +190836,6 @@ var init_push_send = __esm({
|
|
|
190676
190836
|
}
|
|
190677
190837
|
});
|
|
190678
190838
|
|
|
190679
|
-
// ../../core/ts/src/push-routes.ts
|
|
190680
|
-
var init_push_routes = __esm({
|
|
190681
|
-
"../../core/ts/src/push-routes.ts"() {
|
|
190682
|
-
init_define_HHP_CATALOG();
|
|
190683
|
-
}
|
|
190684
|
-
});
|
|
190685
|
-
|
|
190686
190839
|
// ../../core/serve-control/src/push-send-service.ts
|
|
190687
190840
|
var PUSH_SEND_ERROR_CODES, PushSendError;
|
|
190688
190841
|
var init_push_send_service = __esm({
|
|
@@ -198491,10 +198644,10 @@ function ricosVideoUrl(src) {
|
|
|
198491
198644
|
const { url, id } = src;
|
|
198492
198645
|
if (typeof url === "string" && url.trim() !== "") {
|
|
198493
198646
|
const link = cleanLink(url);
|
|
198494
|
-
const linkHost = link === void 0 ? void 0 :
|
|
198647
|
+
const linkHost = link === void 0 ? void 0 : hostOf3(link);
|
|
198495
198648
|
if (link !== void 0 && linkHost !== void 0 && VIDEO_CARD_HOST.test(linkHost)) return link;
|
|
198496
198649
|
const media = normalizeMediaRef(url);
|
|
198497
|
-
const mediaHost =
|
|
198650
|
+
const mediaHost = hostOf3(media);
|
|
198498
198651
|
return HTTPS.test(media) && !(mediaHost !== void 0 && VIDEO_CARD_HOST.test(mediaHost)) ? media : "";
|
|
198499
198652
|
}
|
|
198500
198653
|
const ref = typeof id === "string" ? id.trim().replace(/^video\//, "") : "";
|
|
@@ -198502,7 +198655,7 @@ function ricosVideoUrl(src) {
|
|
|
198502
198655
|
if (/^\w[\w~.-]*\/[\w~./-]+$/.test(ref)) return `https://video.wixstatic.com/video/${ref}`;
|
|
198503
198656
|
return "";
|
|
198504
198657
|
}
|
|
198505
|
-
var HTTPS, LINK3, HTTP_HOST, VIDEO_CARD_HOST,
|
|
198658
|
+
var HTTPS, LINK3, HTTP_HOST, VIDEO_CARD_HOST, hostOf3;
|
|
198506
198659
|
var init_display = __esm({
|
|
198507
198660
|
"../../stdlib/wix-sdk/rich-content/src/display.ts"() {
|
|
198508
198661
|
init_define_HHP_CATALOG();
|
|
@@ -198511,7 +198664,7 @@ var init_display = __esm({
|
|
|
198511
198664
|
LINK3 = /^(https?:\/\/[^\s/?#]\S*|mailto:\S+|tel:\S+)$/i;
|
|
198512
198665
|
HTTP_HOST = /^https?:\/\/([^\s/?#]+)/i;
|
|
198513
198666
|
VIDEO_CARD_HOST = /^(?:(?:www\.|m\.)?youtube\.com|youtu\.be|(?:www\.|player\.)?vimeo\.com)$/;
|
|
198514
|
-
|
|
198667
|
+
hostOf3 = (url) => HTTP_HOST.exec(url)?.[1]?.toLowerCase().replace(/:\d+$/, "");
|
|
198515
198668
|
}
|
|
198516
198669
|
});
|
|
198517
198670
|
|
|
@@ -201022,21 +201175,21 @@ function siteNameFromTitle(title, pageName) {
|
|
|
201022
201175
|
if (!full || !page) return full;
|
|
201023
201176
|
const parts = full.split(TITLE_SEPARATOR);
|
|
201024
201177
|
if (parts.length < 3) return full;
|
|
201025
|
-
const
|
|
201178
|
+
const segments2 = [];
|
|
201026
201179
|
const separators = [];
|
|
201027
201180
|
for (let i2 = 0; i2 < parts.length; i2++) {
|
|
201028
|
-
(i2 % 2 === 0 ?
|
|
201181
|
+
(i2 % 2 === 0 ? segments2 : separators).push(parts[i2]);
|
|
201029
201182
|
}
|
|
201030
|
-
const last =
|
|
201031
|
-
const head3 = norm(
|
|
201032
|
-
const tail = norm(
|
|
201183
|
+
const last = segments2.length - 1;
|
|
201184
|
+
const head3 = norm(segments2[0]) === page;
|
|
201185
|
+
const tail = norm(segments2[last]) === page;
|
|
201033
201186
|
if (head3 && tail) return full;
|
|
201034
201187
|
const drop2 = head3 ? 0 : tail ? last : -1;
|
|
201035
201188
|
if (drop2 === -1) return full;
|
|
201036
|
-
const kept =
|
|
201189
|
+
const kept = segments2.map((_2, i2) => i2).filter((i2) => i2 !== drop2);
|
|
201037
201190
|
if (kept.length === 0) return full;
|
|
201038
|
-
let out2 =
|
|
201039
|
-
for (const i2 of kept.slice(1)) out2 += `${separators[i2 - 1]}${
|
|
201191
|
+
let out2 = segments2[kept[0]];
|
|
201192
|
+
for (const i2 of kept.slice(1)) out2 += `${separators[i2 - 1]}${segments2[i2]}`;
|
|
201040
201193
|
return out2.trim() || full;
|
|
201041
201194
|
}
|
|
201042
201195
|
function identityFromCrawl(siteUrl, title, description, pageName) {
|
|
@@ -205744,6 +205897,7 @@ async function runFidelity(root, opts = {}) {
|
|
|
205744
205897
|
}
|
|
205745
205898
|
} finally {
|
|
205746
205899
|
await session?.close();
|
|
205900
|
+
await native?.restore?.();
|
|
205747
205901
|
}
|
|
205748
205902
|
const report4 = { app: basename30(root), run: run2, dir, rows, status: worst(rows) };
|
|
205749
205903
|
writeFileSync58(join134(dir, "report.json"), JSON.stringify(report4, null, 2) + "\n");
|
|
@@ -205786,6 +205940,186 @@ var init_run2 = __esm({
|
|
|
205786
205940
|
}
|
|
205787
205941
|
});
|
|
205788
205942
|
|
|
205943
|
+
// src/fidelity/native.ts
|
|
205944
|
+
var native_exports = {};
|
|
205945
|
+
__export(native_exports, {
|
|
205946
|
+
defaultRunner: () => defaultRunner3,
|
|
205947
|
+
deviceFor: () => deviceFor,
|
|
205948
|
+
nativeCapture: () => nativeCapture,
|
|
205949
|
+
parseAppLocales: () => parseAppLocales,
|
|
205950
|
+
parseNightMode: () => parseNightMode,
|
|
205951
|
+
parsePlistArray: () => parsePlistArray,
|
|
205952
|
+
screenLink: () => screenLink
|
|
205953
|
+
});
|
|
205954
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
205955
|
+
import { readFileSync as readFileSync141, writeFileSync as writeFileSync59 } from "node:fs";
|
|
205956
|
+
import { join as join135 } from "node:path";
|
|
205957
|
+
function deviceFor(devices, platform, variant) {
|
|
205958
|
+
if (variant === "tablet") return platform === "ios" ? devices.iosTablet : devices.androidTablet;
|
|
205959
|
+
return platform === "ios" ? devices.ios : devices.android;
|
|
205960
|
+
}
|
|
205961
|
+
function screenLink(appId2, screen, entry, release2) {
|
|
205962
|
+
const query = new URLSearchParams();
|
|
205963
|
+
for (const [key3, value2] of Object.entries(entry.params ?? {})) {
|
|
205964
|
+
query.set(key3, typeof value2 === "string" ? value2 : JSON.stringify(value2));
|
|
205965
|
+
}
|
|
205966
|
+
if (release2) query.set("release", release2);
|
|
205967
|
+
const qs2 = query.toString();
|
|
205968
|
+
return `himi://app/${encodeURIComponent(appId2)}/screen/${encodeURIComponent(screen)}${qs2 ? `?${qs2}` : ""}`;
|
|
205969
|
+
}
|
|
205970
|
+
function nativeCapture(devices, opts) {
|
|
205971
|
+
const run2 = opts.run ?? defaultRunner3;
|
|
205972
|
+
const read = opts.readFile ?? ((p2) => readFileSync141(p2));
|
|
205973
|
+
const sleep = opts.sleep ?? ((ms2) => new Promise((r3) => setTimeout(r3, ms2)));
|
|
205974
|
+
const settleMs = opts.settleMs ?? 1e3;
|
|
205975
|
+
const maxWaitMs = opts.maxWaitMs ?? 3e4;
|
|
205976
|
+
const iosBundle = opts.iosBundleId ?? "dev.himalaya.player.dev";
|
|
205977
|
+
const androidPackage = opts.androidPackage ?? "dev.himalaya.player.dev";
|
|
205978
|
+
const rtl = opts.rtlLanguage ?? "he";
|
|
205979
|
+
const picker = opts.pickerAppId ?? "himi-player";
|
|
205980
|
+
const blackFraction = opts.blackFraction ?? (async (file2) => {
|
|
205981
|
+
const r3 = await run2("magick", [file2, "-colorspace", "Gray", "-threshold", "5%", "-format", "%[fx:1-mean]", "info:"]);
|
|
205982
|
+
return r3.code === 0 ? Number(r3.stdout.toString().trim()) || 0 : 0;
|
|
205983
|
+
});
|
|
205984
|
+
const saved = /* @__PURE__ */ new Map();
|
|
205985
|
+
const applied = /* @__PURE__ */ new Map();
|
|
205986
|
+
const ok3 = async (cmd, args) => {
|
|
205987
|
+
const r3 = await run2(cmd, args);
|
|
205988
|
+
if (r3.code !== 0) throw new Error(`${cmd} ${args.join(" ")} exited ${r3.code}`);
|
|
205989
|
+
return r3.stdout.toString().trim();
|
|
205990
|
+
};
|
|
205991
|
+
async function remember(platform, id) {
|
|
205992
|
+
const key3 = `${platform}:${id}`;
|
|
205993
|
+
if (saved.has(key3)) return;
|
|
205994
|
+
if (platform === "ios") {
|
|
205995
|
+
const appearance = await ok3("xcrun", ["simctl", "ui", id, "appearance"]);
|
|
205996
|
+
const languages = await run2("xcrun", ["simctl", "spawn", id, "defaults", "read", "-g", "AppleLanguages"]);
|
|
205997
|
+
saved.set(key3, { appearance, language: languages.code === 0 ? languages.stdout.toString().trim() : void 0 });
|
|
205998
|
+
} else {
|
|
205999
|
+
const night = await ok3("adb", ["-s", id, "shell", "cmd", "uimode", "night"]);
|
|
206000
|
+
const locales = await run2("adb", ["-s", id, "shell", "cmd", "locale", "get-app-locales", androidPackage]);
|
|
206001
|
+
saved.set(key3, { appearance: parseNightMode(night), language: locales.code === 0 ? parseAppLocales(locales.stdout.toString()) : void 0 });
|
|
206002
|
+
}
|
|
206003
|
+
}
|
|
206004
|
+
async function apply(platform, id, variant) {
|
|
206005
|
+
const key3 = `${platform}:${id}`;
|
|
206006
|
+
const want = variant === "dark" ? "dark" : variant === "rtl" ? "rtl" : "light";
|
|
206007
|
+
if (applied.get(key3) === want) return;
|
|
206008
|
+
await remember(platform, id);
|
|
206009
|
+
const dark = want === "dark", right = want === "rtl";
|
|
206010
|
+
if (platform === "ios") {
|
|
206011
|
+
await ok3("xcrun", ["simctl", "ui", id, "appearance", dark ? "dark" : "light"]);
|
|
206012
|
+
await ok3("xcrun", ["simctl", "spawn", id, "defaults", "write", "-g", "AppleLanguages", "-array", right ? rtl : "en"]);
|
|
206013
|
+
await run2("xcrun", ["simctl", "terminate", id, iosBundle]);
|
|
206014
|
+
} else {
|
|
206015
|
+
await ok3("adb", ["-s", id, "shell", "cmd", "uimode", "night", dark ? "yes" : "no"]);
|
|
206016
|
+
const wasRtl = applied.get(key3) === "rtl";
|
|
206017
|
+
if (right || wasRtl) await ok3("adb", ["-s", id, "shell", "cmd", "locale", "set-app-locales", androidPackage, "--locales", right ? rtl : ""]);
|
|
206018
|
+
}
|
|
206019
|
+
applied.set(key3, want);
|
|
206020
|
+
}
|
|
206021
|
+
async function screenshot(platform, id, file2) {
|
|
206022
|
+
if (platform === "ios") {
|
|
206023
|
+
await ok3("xcrun", ["simctl", "io", id, "screenshot", file2]);
|
|
206024
|
+
return read(file2);
|
|
206025
|
+
}
|
|
206026
|
+
const r3 = await run2("adb", ["-s", id, "exec-out", "screencap", "-p"]);
|
|
206027
|
+
if (r3.code !== 0) throw new Error(`adb -s ${id} exec-out screencap -p exited ${r3.code}`);
|
|
206028
|
+
writeFileSync59(file2, r3.stdout);
|
|
206029
|
+
return r3.stdout;
|
|
206030
|
+
}
|
|
206031
|
+
async function settle2(platform, id, file2, notFrame) {
|
|
206032
|
+
let previous;
|
|
206033
|
+
for (let waited = 0; ; waited += settleMs) {
|
|
206034
|
+
const frame = await screenshot(platform, id, file2);
|
|
206035
|
+
if (previous && frame.equals(previous) && !(notFrame && frame.equals(notFrame))) return frame;
|
|
206036
|
+
if (waited >= maxWaitMs) return frame;
|
|
206037
|
+
previous = frame;
|
|
206038
|
+
await sleep(settleMs);
|
|
206039
|
+
}
|
|
206040
|
+
}
|
|
206041
|
+
async function open(platform, id, link) {
|
|
206042
|
+
if (platform === "ios") await ok3("xcrun", ["simctl", "openurl", id, link]);
|
|
206043
|
+
else await ok3("adb", ["-s", id, "shell", "am", "start", "-W", "-a", "android.intent.action.VIEW", "-d", `'${link.replace(/'/g, "%27")}'`]);
|
|
206044
|
+
}
|
|
206045
|
+
const capture = (async (screen, entry, variant, outDir) => {
|
|
206046
|
+
const frames = [];
|
|
206047
|
+
for (const platform of ["ios", "android"]) {
|
|
206048
|
+
const id = deviceFor(devices, platform, variant);
|
|
206049
|
+
if (!id) {
|
|
206050
|
+
const flag = variant === "tablet" ? `--${platform}-tablet` : `--${platform}`;
|
|
206051
|
+
frames.push({ surface: platform, screen, variant, skipped: { reason: `no ${platform}${variant === "tablet" ? " tablet" : ""} device passed (${flag})` } });
|
|
206052
|
+
continue;
|
|
206053
|
+
}
|
|
206054
|
+
if (Object.keys(entry.params ?? {}).length) {
|
|
206055
|
+
frames.push({ surface: platform, screen, variant, skipped: { reason: "screen params are not carried by the Player's deep link yet (#5377)" } });
|
|
206056
|
+
continue;
|
|
206057
|
+
}
|
|
206058
|
+
try {
|
|
206059
|
+
await apply(platform, id, variant);
|
|
206060
|
+
await open(platform, id, `himi://app/${encodeURIComponent(picker)}`);
|
|
206061
|
+
const file2 = join135(outDir, `${screen}.${variant}.${platform}.png`);
|
|
206062
|
+
const pickerFrame = await settle2(platform, id, file2);
|
|
206063
|
+
await open(platform, id, screenLink(opts.appId, screen, entry, opts.release));
|
|
206064
|
+
await settle2(platform, id, file2, pickerFrame);
|
|
206065
|
+
if (platform === "android" && await blackFraction(file2) > 0.95) {
|
|
206066
|
+
await settle2(platform, id, file2);
|
|
206067
|
+
if (await blackFraction(file2) > 0.95) {
|
|
206068
|
+
frames.push({ surface: platform, screen, variant, skipped: { reason: "black frame" } });
|
|
206069
|
+
continue;
|
|
206070
|
+
}
|
|
206071
|
+
}
|
|
206072
|
+
frames.push({ surface: platform, screen, variant, file: file2 });
|
|
206073
|
+
} catch (e2) {
|
|
206074
|
+
frames.push({ surface: platform, screen, variant, skipped: { reason: `capture failed: ${e2.message}` } });
|
|
206075
|
+
}
|
|
206076
|
+
}
|
|
206077
|
+
return frames;
|
|
206078
|
+
});
|
|
206079
|
+
capture.restore = async () => {
|
|
206080
|
+
for (const [key3, was] of saved) {
|
|
206081
|
+
const [platform, id] = [key3.slice(0, key3.indexOf(":")), key3.slice(key3.indexOf(":") + 1)];
|
|
206082
|
+
try {
|
|
206083
|
+
if (platform === "ios") {
|
|
206084
|
+
if (was.appearance) await run2("xcrun", ["simctl", "ui", id, "appearance", was.appearance]);
|
|
206085
|
+
if (was.language) await run2("xcrun", ["simctl", "spawn", id, "defaults", "write", "-g", "AppleLanguages", "-array", ...parsePlistArray(was.language)]);
|
|
206086
|
+
else await run2("xcrun", ["simctl", "spawn", id, "defaults", "delete", "-g", "AppleLanguages"]);
|
|
206087
|
+
await run2("xcrun", ["simctl", "terminate", id, iosBundle]);
|
|
206088
|
+
} else {
|
|
206089
|
+
if (was.appearance) await run2("adb", ["-s", id, "shell", "cmd", "uimode", "night", was.appearance]);
|
|
206090
|
+
await run2("adb", ["-s", id, "shell", "cmd", "locale", "set-app-locales", androidPackage, "--locales", was.language ?? ""]);
|
|
206091
|
+
}
|
|
206092
|
+
} catch {
|
|
206093
|
+
}
|
|
206094
|
+
}
|
|
206095
|
+
saved.clear();
|
|
206096
|
+
applied.clear();
|
|
206097
|
+
};
|
|
206098
|
+
return capture;
|
|
206099
|
+
}
|
|
206100
|
+
function parseNightMode(out2) {
|
|
206101
|
+
return out2.match(/Night mode:\s*([a-z_]+)/i)?.[1]?.toLowerCase() ?? (/yes/i.test(out2) ? "yes" : "no");
|
|
206102
|
+
}
|
|
206103
|
+
function parseAppLocales(out2) {
|
|
206104
|
+
return out2.match(/\[([^\]]*)\]/)?.[1]?.trim() ?? "";
|
|
206105
|
+
}
|
|
206106
|
+
function parsePlistArray(out2) {
|
|
206107
|
+
return out2.replace(/^\s*\(|\)\s*$/g, "").split(",").map((s2) => s2.trim().replace(/^"|"$/g, "")).filter(Boolean);
|
|
206108
|
+
}
|
|
206109
|
+
var defaultRunner3;
|
|
206110
|
+
var init_native = __esm({
|
|
206111
|
+
"src/fidelity/native.ts"() {
|
|
206112
|
+
init_define_HHP_CATALOG();
|
|
206113
|
+
defaultRunner3 = (cmd, args) => new Promise((resolve94) => {
|
|
206114
|
+
const child = spawn9(cmd, args, { stdio: ["ignore", "pipe", "ignore"] });
|
|
206115
|
+
const chunks = [];
|
|
206116
|
+
child.stdout.on("data", (c2) => chunks.push(c2));
|
|
206117
|
+
child.on("error", () => resolve94({ code: 127, stdout: Buffer.alloc(0) }));
|
|
206118
|
+
child.on("close", (code) => resolve94({ code: code ?? 1, stdout: Buffer.concat(chunks) }));
|
|
206119
|
+
});
|
|
206120
|
+
}
|
|
206121
|
+
});
|
|
206122
|
+
|
|
205789
206123
|
// src/fidelity/post.ts
|
|
205790
206124
|
var post_exports = {};
|
|
205791
206125
|
__export(post_exports, {
|
|
@@ -205819,7 +206153,7 @@ __export(fidelity_exports, {
|
|
|
205819
206153
|
});
|
|
205820
206154
|
import { execFileSync as execFileSync10 } from "node:child_process";
|
|
205821
206155
|
import { existsSync as existsSync122, realpathSync as realpathSync19 } from "node:fs";
|
|
205822
|
-
import { join as
|
|
206156
|
+
import { join as join136, relative as relative26, sep as sep25 } from "node:path";
|
|
205823
206157
|
function himalayaRepoRoot(dir) {
|
|
205824
206158
|
let top;
|
|
205825
206159
|
try {
|
|
@@ -205827,7 +206161,7 @@ function himalayaRepoRoot(dir) {
|
|
|
205827
206161
|
} catch {
|
|
205828
206162
|
return null;
|
|
205829
206163
|
}
|
|
205830
|
-
if (!existsSync122(
|
|
206164
|
+
if (!existsSync122(join136(top, "tools/judges/fidelity/JUDGE.md"))) return null;
|
|
205831
206165
|
const rel = relative26(realpathSync19(top), realpathSync19(dir));
|
|
205832
206166
|
return rel.startsWith(`..${sep25}`) || rel === ".." ? null : top;
|
|
205833
206167
|
}
|
|
@@ -205860,10 +206194,41 @@ async function fidelityCommand(ctx) {
|
|
|
205860
206194
|
return 2;
|
|
205861
206195
|
}
|
|
205862
206196
|
const { runFidelity: runFidelity2, prCommentBody: prCommentBody2 } = await Promise.resolve().then(() => (init_run2(), run_exports2));
|
|
205863
|
-
const judgeDir =
|
|
206197
|
+
const judgeDir = join136(repo, "tools/judges/fidelity");
|
|
206198
|
+
const deviceFlags = { ios: "ios", android: "android", iosTablet: "ios-tablet", androidTablet: "android-tablet" };
|
|
206199
|
+
const bare = Object.values(deviceFlags).filter((f2) => flags[f2] !== void 0 && !str3(flags[f2]));
|
|
206200
|
+
if (bare.length) {
|
|
206201
|
+
io2.error(failure2("fidelity_bad_flag", `a device flag needs a UDID or serial: --${bare.join(", --")}`));
|
|
206202
|
+
return 2;
|
|
206203
|
+
}
|
|
206204
|
+
const bareValue = ["release", "app-id"].filter((f2) => flags[f2] !== void 0 && !str3(flags[f2]));
|
|
206205
|
+
if (bareValue.length) {
|
|
206206
|
+
io2.error(failure2("fidelity_bad_flag", `--${bareValue.join(", --")} needs a value`));
|
|
206207
|
+
return 2;
|
|
206208
|
+
}
|
|
206209
|
+
const devices = Object.fromEntries(Object.entries(deviceFlags).map(([k2, f2]) => [k2, flags[f2] === void 0 ? void 0 : str3(flags[f2])]));
|
|
206210
|
+
const named = Object.entries(devices).filter(([, id]) => id !== void 0);
|
|
206211
|
+
if (named.length && flags["no-native"] === true) {
|
|
206212
|
+
io2.error(failure2("fidelity_bad_flag", "--no-native cannot be combined with a device flag"));
|
|
206213
|
+
return 2;
|
|
206214
|
+
}
|
|
206215
|
+
let native;
|
|
206216
|
+
if (flags["no-native"] === true) native = false;
|
|
206217
|
+
else if (named.length) {
|
|
206218
|
+
const { nativeCapture: nativeCapture2 } = await Promise.resolve().then(() => (init_native(), native_exports));
|
|
206219
|
+
const app = (flags["app-id"] === void 0 ? void 0 : str3(flags["app-id"])) || await appId(dir);
|
|
206220
|
+
const release2 = flags.release === void 0 ? void 0 : str3(flags.release);
|
|
206221
|
+
const capture = nativeCapture2(devices, { appId: app, ...release2 ? { release: release2 } : {} });
|
|
206222
|
+
native = capture;
|
|
206223
|
+
const onSignal = () => {
|
|
206224
|
+
void capture.restore().finally(() => process.exit(130));
|
|
206225
|
+
};
|
|
206226
|
+
process.once("SIGINT", onSignal);
|
|
206227
|
+
process.once("SIGTERM", onSignal);
|
|
206228
|
+
}
|
|
205864
206229
|
let report4;
|
|
205865
206230
|
try {
|
|
205866
|
-
report4 = await runFidelity2(dir, { judgeDir, screens: list(flags.screen), variants, ...
|
|
206231
|
+
report4 = await runFidelity2(dir, { judgeDir, screens: list(flags.screen), variants, ...native !== void 0 ? { native } : {} });
|
|
205867
206232
|
} catch (e2) {
|
|
205868
206233
|
const code = e2.code;
|
|
205869
206234
|
if (code === "fidelity_not_hhp" || code === "fidelity_unknown_screen") {
|
|
@@ -205887,7 +206252,7 @@ async function fidelityCommand(ctx) {
|
|
|
205887
206252
|
else {
|
|
205888
206253
|
for (const r3 of report4.rows) io2.log(`${r3.status.padEnd(4)} ${r3.screen}/${r3.variant} design=${r3.judge.design} parity=${r3.judge.parity}${r3.reasons.length ? ` \u2014 ${r3.reasons[0]}` : ""}`);
|
|
205889
206254
|
io2.log(`
|
|
205890
|
-
${report4.status.toUpperCase()} \u2014 report: ${
|
|
206255
|
+
${report4.status.toUpperCase()} \u2014 report: ${join136(report4.dir, "report.json")}`);
|
|
205891
206256
|
}
|
|
205892
206257
|
return report4.status === "fail" ? 1 : 0;
|
|
205893
206258
|
}
|
|
@@ -205977,8 +206342,8 @@ async function publishSizeCommand(ctx) {
|
|
|
205977
206342
|
}
|
|
205978
206343
|
const dir = contentDir2(flags);
|
|
205979
206344
|
const { existsSync: existsSync123 } = await import("node:fs");
|
|
205980
|
-
const { join:
|
|
205981
|
-
if (!existsSync123(
|
|
206345
|
+
const { join: join137 } = await import("node:path");
|
|
206346
|
+
if (!existsSync123(join137(dir, "dev", "index.ts"))) return fail7("build_failed", "expected a content package with dev/index.ts; pass --content <dir>");
|
|
205982
206347
|
const declared = await appId2(dir);
|
|
205983
206348
|
const app = typeof flags.app === "string" ? flags.app : declared;
|
|
205984
206349
|
if (!isValidAppId(app)) return fail7("invalid_usage", "declared app is not a valid publish ID; pass --app <valid-slug>", { app }, 2);
|
|
@@ -206065,7 +206430,7 @@ init_define_HHP_CATALOG();
|
|
|
206065
206430
|
init_client();
|
|
206066
206431
|
init_config();
|
|
206067
206432
|
import { rmSync as rmSync42 } from "node:fs";
|
|
206068
|
-
import { spawn as
|
|
206433
|
+
import { spawn as spawn10 } from "node:child_process";
|
|
206069
206434
|
import { homedir as homedir16 } from "node:os";
|
|
206070
206435
|
import { resolve as resolve93 } from "node:path";
|
|
206071
206436
|
import { fileURLToPath as fileURLToPath39 } from "node:url";
|
|
@@ -206423,7 +206788,7 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
|
|
|
206423
206788
|
at its catalog viewport width (himi surfaces lists them);
|
|
206424
206789
|
a widget family is NOT a device \u2014 fetch /v1/widget/<widgetId>;
|
|
206425
206790
|
--rtl sets ambient direction (dir=rtl + $env:isRTL)
|
|
206426
|
-
himi fidelity [--content <dir>] [--screen <id,\u2026>] [--variant <light,dark,rtl,tablet>] [--no-native] [--json] [--post-pr <n>]
|
|
206791
|
+
himi fidelity [--content <dir>] [--screen <id,\u2026>] [--variant <light,dark,rtl,tablet>] [--ios <udid>] [--android <serial>] [--ios-tablet <udid>] [--android-tablet <serial>] [--app-id <id>] [--release <id>] [--no-native] [--json] [--post-pr <n>]
|
|
206427
206792
|
does each HHP screen look like its mockup? judge + SSIM per screen \xD7 variant (repo-only)
|
|
206428
206793
|
himi icons [--json] the valid Icon.name vocabulary (offline)
|
|
206429
206794
|
himi tokens kit [<name>] list the shipped design kits, or print one. himi docs
|
|
@@ -207086,7 +207451,7 @@ var COMMANDS = [
|
|
|
207086
207451
|
{ name: "progress", summary: 'the build JOURNAL an agent keeps for the owner while it works. `himi progress "<what changed>" --step <1-8|name> --image <png>` appends one postcard to .himi/progress.jsonl \u2014 the step is one of the customer journey\'s eight (discover, classify, plan, implement, brand, validate, review, download) \u2014 and COPIES each image, content-addressed, into .himi/history/, because .himi/shots/ is overwritten by every render and cleared by every full `himi test`, so a path into it would later show a different picture than the one the owner was sent. --image repeats. With NO --image, the home screen\'s current shot is attached automatically, only when it is no older than the last source change and not the picture the latest journaled postcard already shows \u2014 and never a shot that landed on loading placeholders, an empty or an error state (.himi/shot-states.json): then the newest home picture of the current source that shows content goes on instead (its .himi/history copy, `imageNote` saying so), or none \u2014 except on the HANDOVER card (`--step review`), where a repeat is the point and it attaches anyway; that card\'s output also names the making-of (`makingOf`, .himi/making-of.html, rebuilt when missing or older than the journal so it ends on this card) and its `next` says to hand it to the owner beside the preview link; `imageAttached` in the output says whether the postcard carries a picture (with `imageNote` saying why not, or which picture went on instead), and `--no-image` sends a text-only postcard. --notify also raises a best-effort desktop notification for an owner who stepped away. A bare `himi progress` prints the journal with the current step and elapsed time \u2014 also how an agent recovers its place after its context was compacted. APPROVALS: `--approve <gate> "<what>"` records one the customer just gave (gates: site-create, connect, private-data, draft, promote, push-signing, qa-build) in .himi/approvals.jsonl, and `--done <gate>` / `--drop <gate>` closes it \u2014 an approval is owed until then, and the chat that held it does not survive a new session. `--brief` prints plain text for a session start: the current step, the last postcard, every open approval, and whether this app\'s agent files are stale \u2014 the SessionStart hook `himi agent-init` installs runs exactly this. The CLI also journals milestones by itself \u2014 the first PNG render of the home screen (for an app a current `himi init` started: once as the template\'s "Starting point" while the source is what init wrote, then once as "First look at your app" after it diverges, Markdown edits not counting; once per app otherwise), a `himi test` crawl whose outcome changed since the last one (its counts or its home picture; an identical re-run writes none, and a repeat names what changed: "The home screen changed since the last crawl." or the changed counts, was \u2192 now), every draft push (with the home picture only when that shot is newer than the last source edit \u2014 otherwise the postcard says why and names `himi render <home> --png`), and ONE rule for a long silence: a successful home `render --png` more than ten minutes after the newest postcard of any kind, with a picture the latest postcard does not show, journals "Still building: here\'s the home screen now." with it (never twice within the window). When a crawl\'s or a draft\'s home picture is the first of an app whose source diverged, "First look at your app" is journaled first, from that shot, once. All are marked `"by": "himi"`; they never move the journey step, carry no link or credential, and step aside (folded out of every reader) when the agent journals the same step or picture within five minutes. Local only: nothing is sent anywhere.', required: '["<message>" [--step <1-8|name>] [--image <png>]\u2026 [--no-image] [--notify]] [--content <dir>] | --approve|--done|--drop <gate> ["<note>"] | --brief' },
|
|
207087
207452
|
{ name: "studio", summary: "open the BUILD BOARD \u2014 one local page the owner can leave open while an agent builds their app, which fills itself in: every screen as it renders (NEW/CHANGED badges, and each earlier version kept for a filmstrip), the journey stepper and the latest postcard from `himi progress`, the validate/test/UX/draft checks as they run, the site next to the app's home screen with its palette, and the navigation the test crawl followed. Writes .himi/studio/index.html and opens it; the page re-reads its state every two seconds, so nothing needs to be served. OPT-IN BY EXISTENCE: until this command (or `himi init`, which makes the board for every app it creates, without opening a browser) has run, no other command touches .himi/studio/ \u2014 after it, render/test/validate/push/icon/site/ux/progress each refresh the board as they finish (best-effort; never fails a command). Every image is a content-addressed copy in .himi/history/, never a live path into .himi/shots/. Local only, no secrets: it never reads a preview token, handover code or control token. --no-open prints the path instead (SSH, CI). `himi studio reel` writes the MAKING-OF: one self-contained HTML file (every image inlined, nothing fetched) with a flipbook of the home screen version by version, captioned by the postcard in effect at the time, the final screens, and every postcard \u2014 sized to stay attachable, thinning frames first. Defaults to .himi/making-of.html (never archived by push), which every successful `himi push --draft` also rebuilds and names as `reel` in its output; --out to put it elsewhere. The output names that file as the one to hand the owner (`handover: {file, hint}` in JSON; two plain lines at a terminal) \u2014 beside the preview link, never instead of it.", required: "[--content <dir>] [--no-open] | reel [--out <file>] [--no-open]" },
|
|
207088
207453
|
{ name: "render", summary: "headless-render a screen with the web renderer: render-tree + diagnostics, optional --png [<file>] (bare: .himi/shots/<id>.png, what the build board shows), --scheme dark, --tree. Local by default (content dir). Pass --remote --app --release to hit GET /v1/preview/\u2026/render on the serve plane after a push. Boots the worker so $service bindings resolve; --static raw bindings; --live real Wix fetches; --mocks (the DEFAULT whenever the app has recorded data; --no-mocks for the offline initial state) runs load() against the app's own recorded data (dev/net-mocks.json from `himi test --record`, then the config's cms seed rows, and the Base44 layer `himi test` uses \u2014 base44.entities seed rows and the analyze book's sample rows \u2014 hermetic, never a request; with neither it paints the initial state, and `mocks: {used: false}` says why), which is what the automatic pictures use, so they show the app's content instead of its offline placeholders; --state injects worker state; --input supplies pre-boot navigation params; --width/--device for PNG viewport; --rtl for dir=rtl + $env:isRTL.", required: "<screenId> [--content <dir>] [--scheme dark] [--png [<file>]] [--tree] [--static] [--live] [--mocks | --no-mocks] [--state <json|file>] [--input <json|file>] [--width <px> | --device <name>] [--rtl] [--remote --app --release]" },
|
|
207089
|
-
{ name: "fidelity", summary: "does each HHP screen look like the mockup it was designed from? Per screen and variant (light, dark, rtl, tablet) it captures the free-HTML mockup (hhp.json `mockup`) and the web render with the app's recorded data, scores mockup\u2194web (ImageMagick SSIM, global + worst tile), and asks a fresh model (tools/judges/fidelity) two questions: design (web vs mockup) and parity (native vs web,
|
|
207454
|
+
{ name: "fidelity", summary: "does each HHP screen look like the mockup it was designed from? Per screen and variant (light, dark, rtl, tablet) it captures the free-HTML mockup (hhp.json `mockup`) and the web render with the app's recorded data, scores mockup\u2194web (ImageMagick SSIM, global + worst tile), and asks a fresh model (tools/judges/fidelity) two questions: design (web vs mockup) and parity (native vs web). Native frames come from Himi Player on the devices passed with --ios/--android (and --ios-tablet/--android-tablet for the tablet variant), opened by `himi://app/<app-id>/screen/<screen>`; only those devices are touched, their appearance and language are restored afterwards, and a variant with no device is reported skipped. pass/warn/fail per row; exit 1 if any row fails. Writes .himi/fidelity/<run>/report.json and a strip PNG per row. --post-pr <n> keeps one plain PR comment up to date. Advisory, not a merge gate; repo-only for now (refuses with code fidelity_outside_repo elsewhere).", required: "[--content <dir>] [--screen <id,\u2026>] [--variant <light,dark,rtl,tablet>] [--ios <udid>] [--android <serial>] [--ios-tablet <udid>] [--android-tablet <serial>] [--app-id <id>] [--release <id>] [--no-native] [--json] [--post-pr <n>]" },
|
|
207090
207455
|
{ name: "l10n", summary: "import translations into per-app RFC 0054 catalogs (`apps/<app>/l10n/<tag>.json`). `import --format oneapp <dir>` converts OneApp `messages_<locale>.json` files (flat OneApp key \u2192 ICU MessageFormat string): the OneApp key becomes the catalog row's `key` (what a descriptor references as `$t:<KEY>`), the row id is the extractor's content hash of the source-locale string, and `{{x}}` placeholders become ICU `{x}`. Messages using constructs outside the supported ICU subset (selectordinal, number/date skeletons, plural offset, HTML tags) are kept VERBATIM and listed in the report with key and locale. Merges with an existing catalog \u2014 manual translations and keys survive unless --overwrite; rows the import does not touch survive always. Default locales: every messages_<tag>.json found; --source (default en) names the locale supplying each row's `source` string. Warns when the app's `locale` config does not declare an imported tag, printing the config line to add. Deterministic output: re-running over the same inputs produces no diff.", required: "import --format oneapp <dir> (--app <slug> | --content <app dir>) [--locales en,he] [--source en] [--overwrite] [--json]" },
|
|
207091
207456
|
{ name: "cms", summary: "inspect, provision, and seed the app's CMS (Wix Data) collections, declared as a `cms` block in config.ts. `query` is READ-ONLY \u2014 by default it fetches ONLY the physical ids `config.ts` declares (item counts + schema drift) and reports `siteScanned: false`; it never lists the site, so an UNDECLARED `himi_<app>_` collection this app owns is not reached without `--all`. `--all` SCANS the site \u2014 every collection it lists is labeled `owned`/`adopted`/`foreign`, and it describes every foreign one \u2014 id, non-system field keys + types, and the site's read role \u2014 so an app with no `cms` block at all can DISCOVER a collection to adopt (`--all` is the one case where a missing `cms` block is not 'nothing to do'). Foreign collections are described up to a cap and are never item-counted (`itemCount: null`), because a row count is one query each; `foreign.count` is how many the scan LISTED \u2014 it follows the list endpoint's pages, and `listingIncomplete: true` says when the walk stopped short of the end, with `unlistedCollections` counting what it left out when Wix gave a paging total \u2014 and `foreign.truncated` says how many of those went undescribed, each still NAMED in `foreign.others` (id + displayName), so a collection the site already has is never hidden behind the cap. The scan is OWNER-scoped \u2014 it needs --site <msid> (or WIX_SITE_ID) plus owner auth via `wix token`; a visitor token can read a public collection's ITEMS but can never enumerate collections, so there is no tokenless discovery path. `create` reconciles declared collections additively and idempotently, and REFUSES any id outside the app's `himi_<app>_` namespace, so it is safe against a production site. It reports declared-vs-site `permissionDrift` but never writes permissions unless asked with --apply-permissions, so a field reconcile can't silently revert access control changed in the dashboard. `seed` inserts the git-tracked `seed:` rows into EMPTY owned collections (--force to add to a non-empty one; --ai writes placeholder rows plus a refinement prompt for you to review). Adopted collections (declared by `wixId`) are read-only and never created, updated, or seeded. Site from --site <msid> or WIX_SITE_ID; owner auth via `wix token`.", required: "query|create|seed [--site <msid>] [--content <dir>] [--all] [--dry-run] [--force] [--allow-destructive] [--apply-permissions] [--only <id>] [--ai] [--count <n>]" },
|
|
207092
207457
|
{ name: "data", summary: "read-only plan or explicitly provision/seed declared KV and Wix Data resources. Preview and production are separate scopes. KV administration uses the operator data plane from --data-url/HIMI_DATA_ADMIN_URL and HIMI_DATA_ADMIN_TOKEN; draft push never calls it.", required: "plan|create|seed [--site <msid>] [--environment preview|production] [--content <dir>] [--data-url <url>] [--dry-run] [--force]" },
|
|
@@ -209715,8 +210080,8 @@ function pushAuthHint(status, token, target, hasOwnerIssuer = true) {
|
|
|
209715
210080
|
}
|
|
209716
210081
|
async function contentVisibility(dir) {
|
|
209717
210082
|
try {
|
|
209718
|
-
const { readFileSync:
|
|
209719
|
-
const m2 = JSON.parse(
|
|
210083
|
+
const { readFileSync: readFileSync142 } = await import("node:fs");
|
|
210084
|
+
const m2 = JSON.parse(readFileSync142(join96(dir, "himalaya.content.json"), "utf8"));
|
|
209720
210085
|
if (m2.visibility === "public" || m2.visibility === "unlisted") return m2.visibility;
|
|
209721
210086
|
} catch {
|
|
209722
210087
|
}
|
|
@@ -215835,7 +216200,7 @@ init_owner_claim();
|
|
|
215835
216200
|
init_wix_placeholders();
|
|
215836
216201
|
var defaultIO = { log: (l2) => console.log(l2), error: (l2) => console.error(l2), isTTY: process.stdout.isTTY === true };
|
|
215837
216202
|
var CLI_ENTRY = fileURLToPath39(import.meta.url);
|
|
215838
|
-
function createUpdateRefreshSpawner(spawnFn =
|
|
216203
|
+
function createUpdateRefreshSpawner(spawnFn = spawn10, execArgv = process.execArgv) {
|
|
215839
216204
|
return () => {
|
|
215840
216205
|
try {
|
|
215841
216206
|
const child = spawnFn(process.execPath, [...loaderArgs(execArgv), fileURLToPath39(import.meta.url), UPDATE_REFRESH_COMMAND], {
|
|
@@ -215852,7 +216217,7 @@ function createUpdateRefreshSpawner(spawnFn = spawn9, execArgv = process.execArg
|
|
|
215852
216217
|
};
|
|
215853
216218
|
}
|
|
215854
216219
|
var spawnUpdateRefresh = createUpdateRefreshSpawner();
|
|
215855
|
-
function createTrimValidator(deps = {}, spawnFn =
|
|
216220
|
+
function createTrimValidator(deps = {}, spawnFn = spawn10) {
|
|
215856
216221
|
const outcome = (code, report4, said) => {
|
|
215857
216222
|
let counts;
|
|
215858
216223
|
let errors;
|
|
Binary file
|
package/guides/hhp.md
CHANGED
|
@@ -210,13 +210,13 @@ Declare the mockup each screen was designed from in `hhp.json`:
|
|
|
210
210
|
A screen may also carry `params` (the navigation input a device opens it with, used by native capture, #4935) and `fidelity: { "warn": 80, "fail": 60 }`. Thresholds can also be set app-wide at the top level.
|
|
211
211
|
|
|
212
212
|
```bash
|
|
213
|
-
himi fidelity --content <dir> [--screen a,b] [--variant light,dark,rtl,tablet] [--no-native] [--json] [--post-pr <n>]
|
|
213
|
+
himi fidelity --content <dir> [--screen a,b] [--variant light,dark,rtl,tablet] [--ios <udid>] [--android <serial>] [--ios-tablet <udid>] [--android-tablet <serial>] [--app-id <id>] [--release <id>] [--no-native] [--json] [--post-pr <n>]
|
|
214
214
|
```
|
|
215
215
|
|
|
216
216
|
For each screen and variant (`light`, `dark`, `rtl`, `tablet`), the command does four things:
|
|
217
217
|
|
|
218
218
|
1. **Captures the mockup.** It draws the page in Chromium at the variant's width. Dark mode is drawn by emulating `prefers-color-scheme`. RTL is drawn by setting `dir=rtl` on the page.
|
|
219
|
-
2. **Captures the web render** from the app's recorded data, as `himi render` does by default. Native frames come
|
|
219
|
+
2. **Captures the web render** from the app's recorded data, as `himi render` does by default. Native frames come from Himi Player on the devices you pass: `--ios <udid>` and `--android <serial>`, plus `--ios-tablet` and `--android-tablet` for the tablet variant. Only those devices are touched. For each variant the command sets dark or light appearance and, for `rtl`, the Hebrew language (iOS `AppleLanguages`, Android per-app locale, API 33+). It opens `himi://app/<app>/screen/<screen>` and captures once two frames match. Every setting it changed is restored afterwards, also on Ctrl-C. A variant with no device is reported `skipped`, never passed. Without `--release <id>` the Player shows the app's **live** release, not your working copy. A screen that declares `params` is skipped natively for now, because the Player's deep link does not carry them yet. On a fresh iOS simulator, open one `himi://` link by hand first and accept iOS's "Open in Himi Player?" prompt: the command cannot answer it, and until it is accepted every iOS capture shows the prompt.
|
|
220
220
|
3. **Scores mockup↔web** with ImageMagick SSIM, globally and per tile. The worst tile says where the screens differ most.
|
|
221
221
|
4. **Asks a fresh model** two questions, using the repo's fidelity judge prompt. The model never ran in the session that wrote the app.
|
|
222
222
|
- **Design:** does WEB look like the MOCKUP? This judges the port.
|
|
@@ -203,6 +203,42 @@ routes: [
|
|
|
203
203
|
A notification whose link matches no route opens the app without navigating. `himi validate`
|
|
204
204
|
warns when a declared route names a screen the app does not declare.
|
|
205
205
|
|
|
206
|
+
#### Links from a legacy link space
|
|
207
|
+
|
|
208
|
+
An app that replaces an older one may still receive that app's links: its old custom scheme
|
|
209
|
+
(`legacyapp://widget/42`) or an old web host (`https://legacy.example.com/app/widget/42`).
|
|
210
|
+
Declare those prefixes and route the rest:
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
push: {
|
|
214
|
+
linkPrefixes: ["legacyapp://", "https://legacy.example.com/app/"],
|
|
215
|
+
routes: [{ match: "widget/:id", link: "<scheme>://screen/<widget-screen>?id={id}" }],
|
|
216
|
+
},
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Before matching, the device strips a configured prefix from the link, so `widget/42` is matched
|
|
220
|
+
against the routes. It applies these rules in order:
|
|
221
|
+
|
|
222
|
+
1. With `payloadAdapter: "wix-ping"`, a Wix link is handled first, so a prefix inside the Wix link
|
|
223
|
+
space never applies.
|
|
224
|
+
2. Otherwise the **longest** matching prefix is stripped. When a prefix starts with a scheme
|
|
225
|
+
(`legacyapp://`, `https://…`), its scheme and host match in any case and the rest matches
|
|
226
|
+
exactly. A prefix with no scheme (`legacy.example.com/app/`, `/app/`) matches exactly.
|
|
227
|
+
3. A prefix only matches up to a `/`, `?` or `#`, so `https://old.example.com/m` does not strip
|
|
228
|
+
`https://old.example.com/mobile/…`.
|
|
229
|
+
4. A relative link (`/widget/42`) is matched as is, with no prefix needed.
|
|
230
|
+
5. Any other link passes through unchanged.
|
|
231
|
+
|
|
232
|
+
`himi validate` warns about a prefix that can never apply: one inside the Wix link space under
|
|
233
|
+
`wix-ping`, or a prefix list with no routes. It does not judge a prefix by its shape. A schemeless
|
|
234
|
+
prefix strips links written without a scheme, and a dotted custom scheme strips its own links.
|
|
235
|
+
|
|
236
|
+
With `wix-ping` and no `routes`, the build derives the routes from the site's verticals. A
|
|
237
|
+
stripped link is then matched against those Wix notification paths only
|
|
238
|
+
(`my-account/:site/stores/orders/:orderId`, …). If your legacy links use paths of their own,
|
|
239
|
+
declare `routes` for them. A declared table replaces the derived one, so list the Wix routes you
|
|
240
|
+
still need there too. `himi validate` warns when prefixes meet only derived routes.
|
|
241
|
+
|
|
206
242
|
### Notification action buttons
|
|
207
243
|
|
|
208
244
|
Declare actionable categories in the app's source `config.ts`. The native shells render one
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1605.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "himi — the Himalaya authoring CLI. Build a Tier-5 content package on your own machine, push it to the production serve as a draft, preview it on web + Himi Player, and read worker logs back — the remote dev loop. Wraps @himalaya/serve-cli for transport.",
|
|
6
6
|
"keywords": [
|
|
@@ -72,5 +72,5 @@
|
|
|
72
72
|
"artifactId": "himalaya-cli"
|
|
73
73
|
}
|
|
74
74
|
},
|
|
75
|
-
"falconPackageHash": "
|
|
75
|
+
"falconPackageHash": "7b39098c802108e32f8d425c56a0265a2f503b5e56f77b0b0dadff7b"
|
|
76
76
|
}
|