@wix/himalaya-cli 0.1045.0 → 0.1047.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/sdk/wix-platform/src/index.d.ts +2 -2
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-platform.mjs +6 -67
- package/dist/cli.mjs +393 -179
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/sdk-reference.json +4 -4
- package/guides/wix-platform-usage.md +1 -1
- package/package.json +2 -2
- package/templates/branded-lite/dev/index.ts +2 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-faq/index.ts +65 -4
|
@@ -19,7 +19,7 @@ export interface ExperimentResult {
|
|
|
19
19
|
variant: string;
|
|
20
20
|
}
|
|
21
21
|
export declare const experiments: {
|
|
22
|
-
/**
|
|
22
|
+
/** The app's served variant for `spec` (`himi flags`), or `fallback` when none is assigned. */
|
|
23
23
|
conduct(spec: string, fallback?: string): Promise<ExperimentResult>;
|
|
24
24
|
/** Boolean convenience — true when the variant is exactly "true". */
|
|
25
25
|
isEnabled(spec: string): Promise<boolean>;
|
|
@@ -32,7 +32,7 @@ export declare const experiments: {
|
|
|
32
32
|
}>;
|
|
33
33
|
};
|
|
34
34
|
export declare const flags: {
|
|
35
|
-
/** Whether
|
|
35
|
+
/** Whether the app's served flag `spec` is ON (variant `on`/`true`/`new`), else `fallback`. */
|
|
36
36
|
isEnabled(spec: string, fallback?: boolean): Promise<boolean>;
|
|
37
37
|
/** A toggle's raw value (variant string) for non-boolean specs. */
|
|
38
38
|
value(spec: string, fallback?: string): Promise<string>;
|
|
@@ -62,40 +62,15 @@ function flights() {
|
|
|
62
62
|
function dropConductFlights() {
|
|
63
63
|
flights()?.inflight.clear();
|
|
64
64
|
}
|
|
65
|
-
var conductedReal = (value) => ({ value, cacheable: true });
|
|
66
|
-
var conductedSeam = (value) => ({ value, cacheable: false });
|
|
67
|
-
async function l2Get(ns, spec) {
|
|
68
|
-
try {
|
|
69
|
-
const r = await call("conductedGet", { door: ns, spec });
|
|
70
|
-
return {
|
|
71
|
-
value: r?.hit && typeof r.value === "string" && r.value.length > 0 ? r.value : null,
|
|
72
|
-
scope: typeof r?.scope === "string" && r.scope.length > 0 ? r.scope : null
|
|
73
|
-
};
|
|
74
|
-
} catch {
|
|
75
|
-
return { value: null, scope: null };
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
async function l2Put(ns, spec, value, scope) {
|
|
79
|
-
try {
|
|
80
|
-
await call("conductedPut", { door: ns, spec, value, scope });
|
|
81
|
-
} catch {
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
65
|
async function conductCached(ns, spec, fallback, resolve) {
|
|
85
66
|
const f = flights();
|
|
86
|
-
if (!f) return
|
|
67
|
+
if (!f) return resolve();
|
|
87
68
|
const flightKey = JSON.stringify([ns, spec, fallback]);
|
|
88
69
|
const pending = f.inflight.get(flightKey);
|
|
89
70
|
if (pending) return pending;
|
|
90
71
|
const task = (async () => {
|
|
91
72
|
try {
|
|
92
|
-
|
|
93
|
-
if (cached !== null) return cached;
|
|
94
|
-
const { value, cacheable } = await resolve();
|
|
95
|
-
if (cacheable && value !== null && value.length > 0 && scope !== null) {
|
|
96
|
-
await l2Put(ns, spec, value, scope);
|
|
97
|
-
}
|
|
98
|
-
return value;
|
|
73
|
+
return await resolve();
|
|
99
74
|
} finally {
|
|
100
75
|
f.inflight.delete(flightKey);
|
|
101
76
|
}
|
|
@@ -103,31 +78,16 @@ async function conductCached(ns, spec, fallback, resolve) {
|
|
|
103
78
|
f.inflight.set(flightKey, task);
|
|
104
79
|
return task;
|
|
105
80
|
}
|
|
106
|
-
var PETRI_CONDUCT = "/_api/wix-petri-webapp/v1/conductExperiment";
|
|
107
81
|
async function resolveExperiment(spec, fallback) {
|
|
108
|
-
if (isMemberReal("experiments")) {
|
|
109
|
-
try {
|
|
110
|
-
const r2 = await realWix("POST", PETRI_CONDUCT, { key: spec, fallbackValue: fallback });
|
|
111
|
-
if (typeof r2?.value === "string") return conductedReal(r2.value);
|
|
112
|
-
} catch {
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
82
|
const r = await call("experimentsConduct", { spec, fallback });
|
|
116
|
-
return
|
|
83
|
+
return typeof r?.variant === "string" ? r.variant : null;
|
|
117
84
|
}
|
|
118
85
|
async function resolveFlag(spec, fallback) {
|
|
119
|
-
if (isMemberReal("flags")) {
|
|
120
|
-
try {
|
|
121
|
-
const r2 = await realWix("POST", PETRI_CONDUCT, { key: spec, fallbackValue: String(fallback) });
|
|
122
|
-
if (typeof r2?.value === "string") return conductedReal(r2.value);
|
|
123
|
-
} catch {
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
86
|
const r = await call("flagsIsEnabled", { spec, fallback });
|
|
127
|
-
return
|
|
87
|
+
return typeof r?.enabled === "boolean" ? String(r.enabled) : null;
|
|
128
88
|
}
|
|
129
89
|
var experiments = {
|
|
130
|
-
/**
|
|
90
|
+
/** The app's served variant for `spec` (`himi flags`), or `fallback` when none is assigned. */
|
|
131
91
|
async conduct(spec, fallback = "false") {
|
|
132
92
|
const resolved = await conductCached("experiments", spec, fallback, () => resolveExperiment(spec, fallback));
|
|
133
93
|
return { spec, variant: resolved ?? fallback };
|
|
@@ -146,7 +106,7 @@ var experiments = {
|
|
|
146
106
|
}
|
|
147
107
|
};
|
|
148
108
|
var flags = {
|
|
149
|
-
/** Whether
|
|
109
|
+
/** Whether the app's served flag `spec` is ON (variant `on`/`true`/`new`), else `fallback`. */
|
|
150
110
|
async isEnabled(spec, fallback = false) {
|
|
151
111
|
const resolved = await conductCached("flags", spec, String(fallback), () => resolveFlag(spec, fallback));
|
|
152
112
|
if (resolved === null) return fallback;
|
|
@@ -186,25 +146,11 @@ var i18n = {
|
|
|
186
146
|
var ping = {
|
|
187
147
|
/** Register the device's push token with Wix Ping. */
|
|
188
148
|
async register() {
|
|
189
|
-
if (isMemberReal("ping")) {
|
|
190
|
-
try {
|
|
191
|
-
const r2 = await realWix("POST", "/_api/ping-webapp/v1/registrations", {});
|
|
192
|
-
if (r2 && typeof r2.registered === "boolean") return { registered: r2.registered, token: r2.token ?? "" };
|
|
193
|
-
} catch {
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
149
|
const r = await call("pingRegister");
|
|
197
150
|
return { registered: r?.registered ?? false, token: r?.token ?? "" };
|
|
198
151
|
},
|
|
199
152
|
/** Current Ping registration status (no network). */
|
|
200
153
|
async status() {
|
|
201
|
-
if (isMemberReal("ping")) {
|
|
202
|
-
try {
|
|
203
|
-
const r2 = await realWix("GET", "/_api/ping-webapp/v1/registrations");
|
|
204
|
-
if (r2 && typeof r2.registered === "boolean") return { registered: r2.registered, token: r2.token ?? "" };
|
|
205
|
-
} catch {
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
154
|
const r = await call("pingStatus");
|
|
209
155
|
return { registered: r?.registered ?? false, token: r?.token ?? "" };
|
|
210
156
|
}
|
|
@@ -212,13 +158,6 @@ var ping = {
|
|
|
212
158
|
var deeplink = {
|
|
213
159
|
/** Resolve a deferred (post-install) deep link via Wix Jot. Null when none. */
|
|
214
160
|
async resolveDeferred() {
|
|
215
|
-
if (isMemberReal("deeplink")) {
|
|
216
|
-
try {
|
|
217
|
-
const r2 = await realWix("GET", "/_api/app-link-server/v1/deferred-deep-link");
|
|
218
|
-
if (r2) return { link: r2.link && r2.link.length > 0 ? r2.link : null };
|
|
219
|
-
} catch {
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
161
|
const r = await call("deeplinkResolveDeferred");
|
|
223
162
|
return { link: r?.link && r.link.length > 0 ? r.link : null };
|
|
224
163
|
}
|
package/dist/cli.mjs
CHANGED
|
@@ -18830,6 +18830,204 @@ ${cookieHeader}`);
|
|
|
18830
18830
|
}
|
|
18831
18831
|
});
|
|
18832
18832
|
|
|
18833
|
+
// ../../core/ts/src/flags-engine.ts
|
|
18834
|
+
function bucket(key2) {
|
|
18835
|
+
const digest2 = sha1(key2);
|
|
18836
|
+
const n = (digest2[0] << 24 | digest2[1] << 16 | digest2[2] << 8 | digest2[3]) >>> 0;
|
|
18837
|
+
return n % 1e4;
|
|
18838
|
+
}
|
|
18839
|
+
function attrValue(ctx, attribute) {
|
|
18840
|
+
switch (attribute) {
|
|
18841
|
+
case "platform":
|
|
18842
|
+
return ctx.platform;
|
|
18843
|
+
case "appVersion":
|
|
18844
|
+
return ctx.appVersion;
|
|
18845
|
+
case "locale":
|
|
18846
|
+
return ctx.locale;
|
|
18847
|
+
case "appId":
|
|
18848
|
+
return ctx.appId;
|
|
18849
|
+
case "userId":
|
|
18850
|
+
return ctx.userId;
|
|
18851
|
+
default:
|
|
18852
|
+
return ctx.custom?.[attribute];
|
|
18853
|
+
}
|
|
18854
|
+
}
|
|
18855
|
+
function clauseMatches(ctx, c) {
|
|
18856
|
+
const v = attrValue(ctx, c.attribute);
|
|
18857
|
+
switch (c.op) {
|
|
18858
|
+
case "eq":
|
|
18859
|
+
return v !== void 0 && c.values.includes(v);
|
|
18860
|
+
case "neq":
|
|
18861
|
+
return v === void 0 || !c.values.includes(v);
|
|
18862
|
+
case "in":
|
|
18863
|
+
return v !== void 0 && c.values.includes(v);
|
|
18864
|
+
case "contains":
|
|
18865
|
+
return v !== void 0 && c.values.some((needle) => v.includes(needle));
|
|
18866
|
+
default:
|
|
18867
|
+
return false;
|
|
18868
|
+
}
|
|
18869
|
+
}
|
|
18870
|
+
function ruleMatches(ctx, rule) {
|
|
18871
|
+
return rule.clauses.length > 0 && rule.clauses.every((c) => clauseMatches(ctx, c));
|
|
18872
|
+
}
|
|
18873
|
+
function variantForBucket(def, b) {
|
|
18874
|
+
const total = def.variants.reduce((s, v) => s + Math.max(0, v.weight), 0);
|
|
18875
|
+
if (total <= 0) return def.defaultVariant;
|
|
18876
|
+
const target = b / 1e4 * total;
|
|
18877
|
+
let acc = 0;
|
|
18878
|
+
for (const v of def.variants) {
|
|
18879
|
+
acc += Math.max(0, v.weight);
|
|
18880
|
+
if (target < acc) return v.key;
|
|
18881
|
+
}
|
|
18882
|
+
return def.variants[def.variants.length - 1].key;
|
|
18883
|
+
}
|
|
18884
|
+
function evaluate(def, ctx, override) {
|
|
18885
|
+
const base = { key: def.key, experimentId: def.experiment?.id };
|
|
18886
|
+
if (override) return { ...base, variant: override, reason: "override" };
|
|
18887
|
+
if (!def.enabled) return { ...base, variant: def.defaultVariant, reason: "disabled" };
|
|
18888
|
+
for (const rule of def.targeting ?? []) {
|
|
18889
|
+
if (ruleMatches(ctx, rule)) return { ...base, variant: rule.variant, reason: "targeting" };
|
|
18890
|
+
}
|
|
18891
|
+
const id = ctx.userId ?? ctx.sessionId;
|
|
18892
|
+
const seed2 = def.seed ?? def.key;
|
|
18893
|
+
const rollout = def.rolloutPercentage ?? 100;
|
|
18894
|
+
if (rollout < 100) {
|
|
18895
|
+
const gate = bucket(`${id}:${seed2}:rollout`);
|
|
18896
|
+
if (gate >= rollout * 100) return { ...base, variant: def.defaultVariant, reason: "default" };
|
|
18897
|
+
}
|
|
18898
|
+
const variant = variantForBucket(def, bucket(`${id}:${seed2}`));
|
|
18899
|
+
return { ...base, variant, reason: "rollout" };
|
|
18900
|
+
}
|
|
18901
|
+
function evaluateAll(defs, ctx, overrides) {
|
|
18902
|
+
const out = {};
|
|
18903
|
+
for (const def of defs) out[def.key] = evaluate(def, ctx, overrides?.[def.key]);
|
|
18904
|
+
return out;
|
|
18905
|
+
}
|
|
18906
|
+
function utf8(input) {
|
|
18907
|
+
return new TextEncoder().encode(input);
|
|
18908
|
+
}
|
|
18909
|
+
function sha1(input) {
|
|
18910
|
+
const bytes2 = typeof input === "string" ? utf8(input) : input;
|
|
18911
|
+
const bitLen = bytes2.length * 8;
|
|
18912
|
+
const padded = new Uint8Array(((bytes2.length + 9 + 63) / 64 | 0) * 64);
|
|
18913
|
+
padded.set(bytes2);
|
|
18914
|
+
padded[bytes2.length] = 128;
|
|
18915
|
+
const view = new DataView(padded.buffer);
|
|
18916
|
+
view.setUint32(padded.length - 8, Math.floor(bitLen / 4294967296));
|
|
18917
|
+
view.setUint32(padded.length - 4, bitLen >>> 0);
|
|
18918
|
+
let h0 = 1732584193, h1 = 4023233417, h2 = 2562383102, h3 = 271733878, h4 = 3285377520;
|
|
18919
|
+
const w = new Uint32Array(80);
|
|
18920
|
+
for (let off = 0; off < padded.length; off += 64) {
|
|
18921
|
+
for (let i = 0; i < 16; i++) w[i] = view.getUint32(off + i * 4);
|
|
18922
|
+
for (let i = 16; i < 80; i++) {
|
|
18923
|
+
const v = w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16];
|
|
18924
|
+
w[i] = (v << 1 | v >>> 31) >>> 0;
|
|
18925
|
+
}
|
|
18926
|
+
let a = h0, b = h1, c = h2, d = h3, e = h4;
|
|
18927
|
+
for (let i = 0; i < 80; i++) {
|
|
18928
|
+
let f;
|
|
18929
|
+
let k;
|
|
18930
|
+
if (i < 20) {
|
|
18931
|
+
f = b & c | ~b & d;
|
|
18932
|
+
k = 1518500249;
|
|
18933
|
+
} else if (i < 40) {
|
|
18934
|
+
f = b ^ c ^ d;
|
|
18935
|
+
k = 1859775393;
|
|
18936
|
+
} else if (i < 60) {
|
|
18937
|
+
f = b & c | b & d | c & d;
|
|
18938
|
+
k = 2400959708;
|
|
18939
|
+
} else {
|
|
18940
|
+
f = b ^ c ^ d;
|
|
18941
|
+
k = 3395469782;
|
|
18942
|
+
}
|
|
18943
|
+
const t = ((a << 5 | a >>> 27) >>> 0) + (f >>> 0) + e + k + w[i] >>> 0;
|
|
18944
|
+
e = d;
|
|
18945
|
+
d = c;
|
|
18946
|
+
c = (b << 30 | b >>> 2) >>> 0;
|
|
18947
|
+
b = a;
|
|
18948
|
+
a = t;
|
|
18949
|
+
}
|
|
18950
|
+
h0 = h0 + a >>> 0;
|
|
18951
|
+
h1 = h1 + b >>> 0;
|
|
18952
|
+
h2 = h2 + c >>> 0;
|
|
18953
|
+
h3 = h3 + d >>> 0;
|
|
18954
|
+
h4 = h4 + e >>> 0;
|
|
18955
|
+
}
|
|
18956
|
+
const out = new Uint8Array(20);
|
|
18957
|
+
const outView = new DataView(out.buffer);
|
|
18958
|
+
outView.setUint32(0, h0);
|
|
18959
|
+
outView.setUint32(4, h1);
|
|
18960
|
+
outView.setUint32(8, h2);
|
|
18961
|
+
outView.setUint32(12, h3);
|
|
18962
|
+
outView.setUint32(16, h4);
|
|
18963
|
+
return out;
|
|
18964
|
+
}
|
|
18965
|
+
var init_flags_engine = __esm({
|
|
18966
|
+
"../../core/ts/src/flags-engine.ts"() {
|
|
18967
|
+
}
|
|
18968
|
+
});
|
|
18969
|
+
|
|
18970
|
+
// ../../core/serve-runtime/src/flag-assignments.ts
|
|
18971
|
+
function bad(error) {
|
|
18972
|
+
return new Response(JSON.stringify({ error }), { status: 400, headers: { "content-type": JSON_CT, "cache-control": "no-store" } });
|
|
18973
|
+
}
|
|
18974
|
+
function flagAssignmentsBody(app, defs, ctx, overrides, ttlSeconds = FLAG_ASSIGNMENTS_TTL_SECONDS) {
|
|
18975
|
+
const evalCtx = {
|
|
18976
|
+
sessionId: ctx.id,
|
|
18977
|
+
appId: app,
|
|
18978
|
+
...ctx.platform ? { platform: ctx.platform } : {},
|
|
18979
|
+
...ctx.appVersion ? { appVersion: ctx.appVersion } : {},
|
|
18980
|
+
...ctx.locale ? { locale: ctx.locale } : {}
|
|
18981
|
+
};
|
|
18982
|
+
const byKey = new Map(defs.map((d) => [d.key, d]));
|
|
18983
|
+
const assignments = {};
|
|
18984
|
+
for (const [key2, a] of Object.entries(evaluateAll(defs, evalCtx, overrides))) {
|
|
18985
|
+
const value = byKey.get(key2)?.variants.find((v) => v.key === a.variant)?.value;
|
|
18986
|
+
assignments[key2] = {
|
|
18987
|
+
variant: a.variant,
|
|
18988
|
+
reason: a.reason,
|
|
18989
|
+
...a.experimentId ? { experimentId: a.experimentId } : {},
|
|
18990
|
+
...value !== void 0 ? { value } : {}
|
|
18991
|
+
};
|
|
18992
|
+
}
|
|
18993
|
+
return { app, id: ctx.id, assignments, ttlSeconds };
|
|
18994
|
+
}
|
|
18995
|
+
function flagAssignmentsResponse(request, app, defs, overrides, ttlSeconds = FLAG_ASSIGNMENTS_TTL_SECONDS) {
|
|
18996
|
+
if (request.method !== "GET" && request.method !== "HEAD") {
|
|
18997
|
+
return new Response(JSON.stringify({ error: "method_not_allowed" }), { status: 405, headers: { "content-type": JSON_CT } });
|
|
18998
|
+
}
|
|
18999
|
+
const url = new URL(request.url);
|
|
19000
|
+
const id = url.searchParams.get("id") ?? "";
|
|
19001
|
+
if (!id) return bad("missing_id");
|
|
19002
|
+
if (id.length > MAX_ID_LENGTH) return bad("id_too_long");
|
|
19003
|
+
const q = (k) => url.searchParams.get(k) || void 0;
|
|
19004
|
+
const body = JSON.stringify(flagAssignmentsBody(app, defs.filter(isEvaluable), {
|
|
19005
|
+
id,
|
|
19006
|
+
platform: q("platform"),
|
|
19007
|
+
appVersion: q("appVersion"),
|
|
19008
|
+
locale: q("locale")
|
|
19009
|
+
}, overrides, ttlSeconds));
|
|
19010
|
+
const etag = strongEtag(body);
|
|
19011
|
+
const headers2 = { "content-type": JSON_CT, etag, "cache-control": `private, max-age=${Math.min(ttlSeconds, 60)}` };
|
|
19012
|
+
if (request.headers.get("if-none-match") === etag) return new Response(null, { status: 304, headers: headers2 });
|
|
19013
|
+
return new Response(request.method === "HEAD" ? null : body, { status: 200, headers: headers2 });
|
|
19014
|
+
}
|
|
19015
|
+
function isEvaluable(d) {
|
|
19016
|
+
const x = d;
|
|
19017
|
+
return !!x && typeof x.key === "string" && Array.isArray(x.variants) && typeof x.defaultVariant === "string";
|
|
19018
|
+
}
|
|
19019
|
+
var FLAG_ASSIGNMENTS_PATH, FLAG_ASSIGNMENTS_TTL_SECONDS, MAX_ID_LENGTH, JSON_CT;
|
|
19020
|
+
var init_flag_assignments = __esm({
|
|
19021
|
+
"../../core/serve-runtime/src/flag-assignments.ts"() {
|
|
19022
|
+
init_flags_engine();
|
|
19023
|
+
init_contract();
|
|
19024
|
+
FLAG_ASSIGNMENTS_PATH = /^\/v1\/flags\/([^/]+)\/assignments$/;
|
|
19025
|
+
FLAG_ASSIGNMENTS_TTL_SECONDS = 300;
|
|
19026
|
+
MAX_ID_LENGTH = 256;
|
|
19027
|
+
JSON_CT = "application/json; charset=utf-8";
|
|
19028
|
+
}
|
|
19029
|
+
});
|
|
19030
|
+
|
|
18833
19031
|
// ../../core/dev-server/src/images.ts
|
|
18834
19032
|
import { createHash as createHash11 } from "node:crypto";
|
|
18835
19033
|
function svgFor(productId, title, sku) {
|
|
@@ -32031,143 +32229,6 @@ var init_flags = __esm({
|
|
|
32031
32229
|
}
|
|
32032
32230
|
});
|
|
32033
32231
|
|
|
32034
|
-
// ../../core/ts/src/flags-engine.ts
|
|
32035
|
-
function bucket(key2) {
|
|
32036
|
-
const digest2 = sha1(key2);
|
|
32037
|
-
const n = (digest2[0] << 24 | digest2[1] << 16 | digest2[2] << 8 | digest2[3]) >>> 0;
|
|
32038
|
-
return n % 1e4;
|
|
32039
|
-
}
|
|
32040
|
-
function attrValue(ctx, attribute) {
|
|
32041
|
-
switch (attribute) {
|
|
32042
|
-
case "platform":
|
|
32043
|
-
return ctx.platform;
|
|
32044
|
-
case "appVersion":
|
|
32045
|
-
return ctx.appVersion;
|
|
32046
|
-
case "locale":
|
|
32047
|
-
return ctx.locale;
|
|
32048
|
-
case "appId":
|
|
32049
|
-
return ctx.appId;
|
|
32050
|
-
case "userId":
|
|
32051
|
-
return ctx.userId;
|
|
32052
|
-
default:
|
|
32053
|
-
return ctx.custom?.[attribute];
|
|
32054
|
-
}
|
|
32055
|
-
}
|
|
32056
|
-
function clauseMatches(ctx, c) {
|
|
32057
|
-
const v = attrValue(ctx, c.attribute);
|
|
32058
|
-
switch (c.op) {
|
|
32059
|
-
case "eq":
|
|
32060
|
-
return v !== void 0 && c.values.includes(v);
|
|
32061
|
-
case "neq":
|
|
32062
|
-
return v === void 0 || !c.values.includes(v);
|
|
32063
|
-
case "in":
|
|
32064
|
-
return v !== void 0 && c.values.includes(v);
|
|
32065
|
-
case "contains":
|
|
32066
|
-
return v !== void 0 && c.values.some((needle) => v.includes(needle));
|
|
32067
|
-
default:
|
|
32068
|
-
return false;
|
|
32069
|
-
}
|
|
32070
|
-
}
|
|
32071
|
-
function ruleMatches(ctx, rule) {
|
|
32072
|
-
return rule.clauses.length > 0 && rule.clauses.every((c) => clauseMatches(ctx, c));
|
|
32073
|
-
}
|
|
32074
|
-
function variantForBucket(def, b) {
|
|
32075
|
-
const total = def.variants.reduce((s, v) => s + Math.max(0, v.weight), 0);
|
|
32076
|
-
if (total <= 0) return def.defaultVariant;
|
|
32077
|
-
const target = b / 1e4 * total;
|
|
32078
|
-
let acc = 0;
|
|
32079
|
-
for (const v of def.variants) {
|
|
32080
|
-
acc += Math.max(0, v.weight);
|
|
32081
|
-
if (target < acc) return v.key;
|
|
32082
|
-
}
|
|
32083
|
-
return def.variants[def.variants.length - 1].key;
|
|
32084
|
-
}
|
|
32085
|
-
function evaluate(def, ctx, override) {
|
|
32086
|
-
const base = { key: def.key, experimentId: def.experiment?.id };
|
|
32087
|
-
if (override) return { ...base, variant: override, reason: "override" };
|
|
32088
|
-
if (!def.enabled) return { ...base, variant: def.defaultVariant, reason: "disabled" };
|
|
32089
|
-
for (const rule of def.targeting ?? []) {
|
|
32090
|
-
if (ruleMatches(ctx, rule)) return { ...base, variant: rule.variant, reason: "targeting" };
|
|
32091
|
-
}
|
|
32092
|
-
const id = ctx.userId ?? ctx.sessionId;
|
|
32093
|
-
const seed2 = def.seed ?? def.key;
|
|
32094
|
-
const rollout = def.rolloutPercentage ?? 100;
|
|
32095
|
-
if (rollout < 100) {
|
|
32096
|
-
const gate = bucket(`${id}:${seed2}:rollout`);
|
|
32097
|
-
if (gate >= rollout * 100) return { ...base, variant: def.defaultVariant, reason: "default" };
|
|
32098
|
-
}
|
|
32099
|
-
const variant = variantForBucket(def, bucket(`${id}:${seed2}`));
|
|
32100
|
-
return { ...base, variant, reason: "rollout" };
|
|
32101
|
-
}
|
|
32102
|
-
function evaluateAll(defs, ctx, overrides) {
|
|
32103
|
-
const out = {};
|
|
32104
|
-
for (const def of defs) out[def.key] = evaluate(def, ctx, overrides?.[def.key]);
|
|
32105
|
-
return out;
|
|
32106
|
-
}
|
|
32107
|
-
function utf8(input) {
|
|
32108
|
-
return new TextEncoder().encode(input);
|
|
32109
|
-
}
|
|
32110
|
-
function sha1(input) {
|
|
32111
|
-
const bytes2 = typeof input === "string" ? utf8(input) : input;
|
|
32112
|
-
const bitLen = bytes2.length * 8;
|
|
32113
|
-
const padded = new Uint8Array(((bytes2.length + 9 + 63) / 64 | 0) * 64);
|
|
32114
|
-
padded.set(bytes2);
|
|
32115
|
-
padded[bytes2.length] = 128;
|
|
32116
|
-
const view = new DataView(padded.buffer);
|
|
32117
|
-
view.setUint32(padded.length - 8, Math.floor(bitLen / 4294967296));
|
|
32118
|
-
view.setUint32(padded.length - 4, bitLen >>> 0);
|
|
32119
|
-
let h0 = 1732584193, h1 = 4023233417, h2 = 2562383102, h3 = 271733878, h4 = 3285377520;
|
|
32120
|
-
const w = new Uint32Array(80);
|
|
32121
|
-
for (let off = 0; off < padded.length; off += 64) {
|
|
32122
|
-
for (let i = 0; i < 16; i++) w[i] = view.getUint32(off + i * 4);
|
|
32123
|
-
for (let i = 16; i < 80; i++) {
|
|
32124
|
-
const v = w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16];
|
|
32125
|
-
w[i] = (v << 1 | v >>> 31) >>> 0;
|
|
32126
|
-
}
|
|
32127
|
-
let a = h0, b = h1, c = h2, d = h3, e = h4;
|
|
32128
|
-
for (let i = 0; i < 80; i++) {
|
|
32129
|
-
let f;
|
|
32130
|
-
let k;
|
|
32131
|
-
if (i < 20) {
|
|
32132
|
-
f = b & c | ~b & d;
|
|
32133
|
-
k = 1518500249;
|
|
32134
|
-
} else if (i < 40) {
|
|
32135
|
-
f = b ^ c ^ d;
|
|
32136
|
-
k = 1859775393;
|
|
32137
|
-
} else if (i < 60) {
|
|
32138
|
-
f = b & c | b & d | c & d;
|
|
32139
|
-
k = 2400959708;
|
|
32140
|
-
} else {
|
|
32141
|
-
f = b ^ c ^ d;
|
|
32142
|
-
k = 3395469782;
|
|
32143
|
-
}
|
|
32144
|
-
const t = ((a << 5 | a >>> 27) >>> 0) + (f >>> 0) + e + k + w[i] >>> 0;
|
|
32145
|
-
e = d;
|
|
32146
|
-
d = c;
|
|
32147
|
-
c = (b << 30 | b >>> 2) >>> 0;
|
|
32148
|
-
b = a;
|
|
32149
|
-
a = t;
|
|
32150
|
-
}
|
|
32151
|
-
h0 = h0 + a >>> 0;
|
|
32152
|
-
h1 = h1 + b >>> 0;
|
|
32153
|
-
h2 = h2 + c >>> 0;
|
|
32154
|
-
h3 = h3 + d >>> 0;
|
|
32155
|
-
h4 = h4 + e >>> 0;
|
|
32156
|
-
}
|
|
32157
|
-
const out = new Uint8Array(20);
|
|
32158
|
-
const outView = new DataView(out.buffer);
|
|
32159
|
-
outView.setUint32(0, h0);
|
|
32160
|
-
outView.setUint32(4, h1);
|
|
32161
|
-
outView.setUint32(8, h2);
|
|
32162
|
-
outView.setUint32(12, h3);
|
|
32163
|
-
outView.setUint32(16, h4);
|
|
32164
|
-
return out;
|
|
32165
|
-
}
|
|
32166
|
-
var init_flags_engine = __esm({
|
|
32167
|
-
"../../core/ts/src/flags-engine.ts"() {
|
|
32168
|
-
}
|
|
32169
|
-
});
|
|
32170
|
-
|
|
32171
32232
|
// ../../core/ts/src/launch-manifest.ts
|
|
32172
32233
|
import Ajv2 from "ajv";
|
|
32173
32234
|
var directiveObject, LAUNCH_MANIFEST_SCHEMA;
|
|
@@ -36233,6 +36294,23 @@ function createDevServer(opts = {}) {
|
|
|
36233
36294
|
const k = readKit(kitM[1]);
|
|
36234
36295
|
return k ? sendJson(res, 200, k, { "access-control-allow-origin": "*" }) : sendJson(res, 404, { error: "unknown_kit", id: kitM[1] }, { "access-control-allow-origin": "*" });
|
|
36235
36296
|
}
|
|
36297
|
+
const flagAssignM = /^\/v1\/flags\/([^/?]+)\/assignments(?:\?|$)/.exec(url);
|
|
36298
|
+
if (flagAssignM && (req.method === "GET" || req.method === "HEAD")) {
|
|
36299
|
+
await state.flagSync.refresh(state.app?.dir, state.flagStore, Date.now());
|
|
36300
|
+
const ours = flagAssignM[1] === state.appName;
|
|
36301
|
+
const answer = flagAssignmentsResponse(
|
|
36302
|
+
new Request(`http://dev-server${url}`, {
|
|
36303
|
+
method: req.method,
|
|
36304
|
+
headers: typeof req.headers["if-none-match"] === "string" ? { "if-none-match": req.headers["if-none-match"] } : {}
|
|
36305
|
+
}),
|
|
36306
|
+
flagAssignM[1],
|
|
36307
|
+
ours ? state.flagStore.list() : [],
|
|
36308
|
+
ours ? currentFlagConfig(state)?.overrides : void 0
|
|
36309
|
+
);
|
|
36310
|
+
res.writeHead(answer.status, { ...Object.fromEntries(answer.headers), "access-control-allow-origin": "*" });
|
|
36311
|
+
res.end(answer.status === 200 && req.method === "GET" ? await answer.text() : void 0);
|
|
36312
|
+
return;
|
|
36313
|
+
}
|
|
36236
36314
|
if (url.startsWith("/v1/revocations") && req.method === "GET") {
|
|
36237
36315
|
let revoked = [];
|
|
36238
36316
|
if (state.app) {
|
|
@@ -36455,6 +36533,7 @@ var init_src6 = __esm({
|
|
|
36455
36533
|
init_wix_gateway();
|
|
36456
36534
|
init_wix_member_login();
|
|
36457
36535
|
init_wix_bridge();
|
|
36536
|
+
init_flag_assignments();
|
|
36458
36537
|
init_images();
|
|
36459
36538
|
init_l10n();
|
|
36460
36539
|
init_l10n_catalog();
|
|
@@ -42759,7 +42838,7 @@ function serializeAt(node, src, open) {
|
|
|
42759
42838
|
const indent = lineIndent(src, open);
|
|
42760
42839
|
return JSON.stringify(node, null, 2).split("\n").map((line, i) => i === 0 ? line : indent + line).join("\n");
|
|
42761
42840
|
}
|
|
42762
|
-
function patchGrids(src, installed, patch) {
|
|
42841
|
+
function patchGrids(src, installed, patch, keepFaq = false, dropFaq = false) {
|
|
42763
42842
|
const OPEN = /"id": "([A-Za-z_0-9]+(?:\.[A-Za-z_0-9]+)*\.verticals)"/g;
|
|
42764
42843
|
let out = "";
|
|
42765
42844
|
let cursor = 0;
|
|
@@ -42780,12 +42859,17 @@ function patchGrids(src, installed, patch) {
|
|
|
42780
42859
|
const prefix = m[1].slice(0, -".verticals".length);
|
|
42781
42860
|
const baked = /* @__PURE__ */ new Map();
|
|
42782
42861
|
const foreignCells = [];
|
|
42783
|
-
|
|
42784
|
-
|
|
42785
|
-
const
|
|
42862
|
+
let faqCell;
|
|
42863
|
+
const claimOf = (item) => {
|
|
42864
|
+
const id = item?.id;
|
|
42865
|
+
const legacy = item?.modifiers?.accessibilityLabel;
|
|
42786
42866
|
const claim = typeof id === "string" && id ? id : typeof legacy === "string" ? legacy : "";
|
|
42787
|
-
|
|
42867
|
+
return claim.startsWith(`${prefix}.`) ? claim.slice(prefix.length + 1) : "";
|
|
42868
|
+
};
|
|
42869
|
+
for (const item of items) {
|
|
42870
|
+
const vertical = claimOf(item);
|
|
42788
42871
|
if (isKnown(vertical)) baked.set(vertical, item);
|
|
42872
|
+
else if (vertical === "faq" && keepFaq) faqCell = item;
|
|
42789
42873
|
else if (!GRID_VERTICAL_LABELS.has(vertical)) foreignCells.push(item);
|
|
42790
42874
|
}
|
|
42791
42875
|
const wanted = [];
|
|
@@ -42803,10 +42887,36 @@ function patchGrids(src, installed, patch) {
|
|
|
42803
42887
|
wanted.push(vertical);
|
|
42804
42888
|
}
|
|
42805
42889
|
const shape = baked.values().next().value ?? items[0];
|
|
42890
|
+
const bakedFaq = faqCell;
|
|
42891
|
+
if (keepFaq && !faqCell && hasScreen(src, FAQ_CARD.screenId)) {
|
|
42892
|
+
faqCell = cloneCell(shape, prefix, "faq", FAQ_CARD);
|
|
42893
|
+
}
|
|
42894
|
+
if (!installed.size) {
|
|
42895
|
+
if (dropFaq) {
|
|
42896
|
+
const kept = items.filter((item) => claimOf(item) !== "faq");
|
|
42897
|
+
if (kept.length !== items.length && kept.length > 0) {
|
|
42898
|
+
node.body.props.items = kept;
|
|
42899
|
+
out += src.slice(cursor, open) + serializeAt(node, src, open);
|
|
42900
|
+
cursor = close;
|
|
42901
|
+
OPEN.lastIndex = close;
|
|
42902
|
+
}
|
|
42903
|
+
continue;
|
|
42904
|
+
}
|
|
42905
|
+
const lastIsVertical = GRID_VERTICAL_LABELS.has(claimOf(items[items.length - 1]));
|
|
42906
|
+
if (!bakedFaq && faqCell && (items.length < EXPLORE_MAX_CELLS || lastIsVertical)) {
|
|
42907
|
+
if (items.length >= EXPLORE_MAX_CELLS) items.pop();
|
|
42908
|
+
items.push(faqCell);
|
|
42909
|
+
out += src.slice(cursor, open) + serializeAt(node, src, open);
|
|
42910
|
+
cursor = close;
|
|
42911
|
+
OPEN.lastIndex = close;
|
|
42912
|
+
}
|
|
42913
|
+
continue;
|
|
42914
|
+
}
|
|
42915
|
+
const cap = faqCell ? EXPLORE_MAX_CELLS - 1 : EXPLORE_MAX_CELLS;
|
|
42806
42916
|
const next = [...foreignCells];
|
|
42807
42917
|
const cells = [];
|
|
42808
42918
|
for (const vertical of wanted) {
|
|
42809
|
-
if (next.length >=
|
|
42919
|
+
if (next.length >= cap) break;
|
|
42810
42920
|
const bakedCell = baked.get(vertical);
|
|
42811
42921
|
if (bakedCell) {
|
|
42812
42922
|
next.push(bakedCell);
|
|
@@ -42822,6 +42932,7 @@ function patchGrids(src, installed, patch) {
|
|
|
42822
42932
|
cells.push(vertical);
|
|
42823
42933
|
patch.added.push(vertical);
|
|
42824
42934
|
}
|
|
42935
|
+
if (faqCell && next.length < EXPLORE_MAX_CELLS) next.push(faqCell);
|
|
42825
42936
|
if (!cells.length) continue;
|
|
42826
42937
|
patch.cells = cells;
|
|
42827
42938
|
node.body.props.items = next;
|
|
@@ -42936,16 +43047,19 @@ function patchStoreCtas(src, verticals, homeActionId) {
|
|
|
42936
43047
|
dropped
|
|
42937
43048
|
};
|
|
42938
43049
|
}
|
|
42939
|
-
function patchHomeForVerticals(src, verticals, homeActionId) {
|
|
43050
|
+
function patchHomeForVerticals(src, verticals, homeActionId, opts = {}) {
|
|
42940
43051
|
const installed = new Set(verticals.filter(isKnown));
|
|
42941
43052
|
const patch = { src, cells: [], added: [], droppedModules: [], droppedCtas: [], unreachable: [] };
|
|
42942
|
-
if (!installed.size)
|
|
42943
|
-
|
|
43053
|
+
if (!installed.size) {
|
|
43054
|
+
if (opts.keepFaq || opts.dropFaq) patch.src = patchGrids(src, installed, patch, !!opts.keepFaq, !opts.keepFaq && !!opts.dropFaq);
|
|
43055
|
+
return patch;
|
|
43056
|
+
}
|
|
43057
|
+
const ctas = patchStoreCtas(patchModules(patchGrids(src, installed, patch, opts.keepFaq), installed, patch), [...installed], homeActionId);
|
|
42944
43058
|
patch.src = ctas.src;
|
|
42945
43059
|
patch.droppedCtas = ctas.dropped;
|
|
42946
43060
|
return patch;
|
|
42947
43061
|
}
|
|
42948
|
-
var EXPLORE_CARDS, EXPLORE_ORDER, EXPLORE_MAX_CELLS, MODULE_SOURCE_VERTICALS, isKnown, GRID_VERTICAL_LABELS, escapeRe2, textProps, STORE_SCREENS, isStoreScreen, screenDeclarations, isNode2;
|
|
43062
|
+
var EXPLORE_CARDS, EXPLORE_ORDER, EXPLORE_MAX_CELLS, MODULE_SOURCE_VERTICALS, isKnown, GRID_VERTICAL_LABELS, FAQ_CARD, escapeRe2, textProps, STORE_SCREENS, isStoreScreen, screenDeclarations, isNode2;
|
|
42949
43063
|
var init_home_descriptor = __esm({
|
|
42950
43064
|
"src/site-analyze/home-descriptor.ts"() {
|
|
42951
43065
|
init_types2();
|
|
@@ -43017,6 +43131,7 @@ var init_home_descriptor = __esm({
|
|
|
43017
43131
|
};
|
|
43018
43132
|
isKnown = (v) => KNOWN_VERTICALS.includes(v);
|
|
43019
43133
|
GRID_VERTICAL_LABELS = /* @__PURE__ */ new Set([...KNOWN_VERTICALS, "faq"]);
|
|
43134
|
+
FAQ_CARD = { icon: "help", screenId: "himi_faq", title: "FAQ", body: "Find answers to common questions." };
|
|
43020
43135
|
escapeRe2 = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
43021
43136
|
textProps = (n) => n?.body?.props;
|
|
43022
43137
|
STORE_SCREENS = /* @__PURE__ */ new Set([
|
|
@@ -49467,7 +49582,7 @@ var init_wix_member_auth = __esm({
|
|
|
49467
49582
|
|
|
49468
49583
|
// ../../core/serve/src/server.ts
|
|
49469
49584
|
function json3(status, body, headers2 = {}) {
|
|
49470
|
-
return new Response(JSON.stringify(body), { status, headers: { "content-type":
|
|
49585
|
+
return new Response(JSON.stringify(body), { status, headers: { "content-type": JSON_CT2, ...headers2 } });
|
|
49471
49586
|
}
|
|
49472
49587
|
function isCookieAuthorizedPath(path2) {
|
|
49473
49588
|
return path2 === "/v1/__webwix/call" || path2 === "/v1/owner" || path2.startsWith("/v1/owner/") || path2 === "/v1/__webwix/identity" || path2 === "/v1/__webwix/login" || path2 === "/v1/__webwix/register" || path2 === "/v1/__webwix/logout" || path2 === MEMBER_CALLBACK_PATH;
|
|
@@ -49627,7 +49742,7 @@ ${releaseId}`;
|
|
|
49627
49742
|
if (request.headers.get("if-none-match") === etag) {
|
|
49628
49743
|
return new Response(null, { status: 304, headers: { etag, "cache-control": cache, ...vary } });
|
|
49629
49744
|
}
|
|
49630
|
-
return new Response(body, { status: 200, headers: { "content-type":
|
|
49745
|
+
return new Response(body, { status: 200, headers: { "content-type": JSON_CT2, etag, "cache-control": cache, ...vary } });
|
|
49631
49746
|
}
|
|
49632
49747
|
async function authorizePinnedRead(request, url, app, releaseId, screenId) {
|
|
49633
49748
|
const denied = await checkPinnedRead({
|
|
@@ -49822,7 +49937,7 @@ ${releaseId}`;
|
|
|
49822
49937
|
});
|
|
49823
49938
|
}
|
|
49824
49939
|
if ((request.method === "GET" || request.method === "HEAD") && path2 === "/v1/__webwix/identity") {
|
|
49825
|
-
const headers2 = { "content-type":
|
|
49940
|
+
const headers2 = { "content-type": JSON_CT2, "cache-control": "no-store" };
|
|
49826
49941
|
if (request.method === "HEAD") return new Response(null, { status: 200, headers: headers2 });
|
|
49827
49942
|
const webwixDirect = opts.webwixDirect ? await opts.webwixDirect() === true : opts.webwixBridge !== false;
|
|
49828
49943
|
if (memberAuthOn()) {
|
|
@@ -50050,7 +50165,7 @@ ${releaseId}`;
|
|
|
50050
50165
|
}
|
|
50051
50166
|
return new Response(listBody, {
|
|
50052
50167
|
status: 200,
|
|
50053
|
-
headers: { "content-type":
|
|
50168
|
+
headers: { "content-type": JSON_CT2, ...listHeaders }
|
|
50054
50169
|
});
|
|
50055
50170
|
}
|
|
50056
50171
|
if (path2 === "/v1/templates") {
|
|
@@ -50107,7 +50222,7 @@ ${releaseId}`;
|
|
|
50107
50222
|
}
|
|
50108
50223
|
return new Response(bytes2, {
|
|
50109
50224
|
status: 200,
|
|
50110
|
-
headers: { "content-type":
|
|
50225
|
+
headers: { "content-type": JSON_CT2, etag, ...cache, "x-himalaya-app": app }
|
|
50111
50226
|
});
|
|
50112
50227
|
}
|
|
50113
50228
|
if (path2 === "/v1/authoring-docs" || /^\/v1\/authoring-docs\/(spec|mobile-ux)$/.test(path2)) {
|
|
@@ -50372,7 +50487,7 @@ ${releaseId}`;
|
|
|
50372
50487
|
if (request.headers.get("if-none-match") === etag2) return new Response(null, { status: 304, headers: headers2 });
|
|
50373
50488
|
const body2 = await pinnedBody(app, meta2.descriptorHash, () => store.getScreen(app, screenId));
|
|
50374
50489
|
if (!body2) return json3(404, { error: "screen_not_found", screenId });
|
|
50375
|
-
return new Response(body2, { status: 200, headers: { "content-type":
|
|
50490
|
+
return new Response(body2, { status: 200, headers: { "content-type": JSON_CT2, ...headers2, "x-himalaya-app": app } });
|
|
50376
50491
|
}
|
|
50377
50492
|
const m = await manifest(app);
|
|
50378
50493
|
const meta = m?.screens[screenId];
|
|
@@ -50385,7 +50500,7 @@ ${releaseId}`;
|
|
|
50385
50500
|
if (!body) return json3(404, { error: "screen_not_found", screenId });
|
|
50386
50501
|
return new Response(body, {
|
|
50387
50502
|
status: 200,
|
|
50388
|
-
headers: { "content-type":
|
|
50503
|
+
headers: { "content-type": JSON_CT2, etag, "cache-control": DOC_CACHE_CONTROL, "x-himalaya-app": app }
|
|
50389
50504
|
});
|
|
50390
50505
|
}
|
|
50391
50506
|
if (path2 === "/v1/widgets") {
|
|
@@ -50413,7 +50528,7 @@ ${releaseId}`;
|
|
|
50413
50528
|
if (!body) return json3(404, { error: "widget_not_found", widgetId });
|
|
50414
50529
|
return new Response(body, {
|
|
50415
50530
|
status: 200,
|
|
50416
|
-
headers: { "content-type":
|
|
50531
|
+
headers: { "content-type": JSON_CT2, etag, "cache-control": cache, ...vary, "x-himalaya-app": app }
|
|
50417
50532
|
});
|
|
50418
50533
|
}
|
|
50419
50534
|
return json3(404, { error: "not_found" });
|
|
@@ -50440,7 +50555,7 @@ ${releaseId}`;
|
|
|
50440
50555
|
return withCors(request, response);
|
|
50441
50556
|
};
|
|
50442
50557
|
}
|
|
50443
|
-
var
|
|
50558
|
+
var JSON_CT2;
|
|
50444
50559
|
var init_server = __esm({
|
|
50445
50560
|
"../../core/serve/src/server.ts"() {
|
|
50446
50561
|
init_sha256();
|
|
@@ -50451,7 +50566,7 @@ var init_server = __esm({
|
|
|
50451
50566
|
init_package_share();
|
|
50452
50567
|
init_wix_bridge();
|
|
50453
50568
|
init_wix_member_auth();
|
|
50454
|
-
|
|
50569
|
+
JSON_CT2 = "application/json; charset=utf-8";
|
|
50455
50570
|
}
|
|
50456
50571
|
});
|
|
50457
50572
|
|
|
@@ -50632,6 +50747,8 @@ function makeRunHandler(opts) {
|
|
|
50632
50747
|
{ "cache-control": "max-age=30" }
|
|
50633
50748
|
);
|
|
50634
50749
|
}
|
|
50750
|
+
const flagAssign = FLAG_ASSIGNMENTS_PATH.exec(path2);
|
|
50751
|
+
if (flagAssign) return flagAssignmentsResponse(request, flagAssign[1], []);
|
|
50635
50752
|
if (path2.startsWith("/v1/flags/")) {
|
|
50636
50753
|
return json4(200, { app: opts.app, definitions: {} }, { "cache-control": "no-store" });
|
|
50637
50754
|
}
|
|
@@ -50703,6 +50820,7 @@ var json4;
|
|
|
50703
50820
|
var init_run_handler = __esm({
|
|
50704
50821
|
"../../core/serve/src/run-handler.ts"() {
|
|
50705
50822
|
init_server();
|
|
50823
|
+
init_flag_assignments();
|
|
50706
50824
|
init_preview2();
|
|
50707
50825
|
init_himi_package();
|
|
50708
50826
|
json4 = (status, body, headers2 = {}) => new Response(JSON.stringify(body), {
|
|
@@ -50841,21 +50959,21 @@ var init_preview_assets_generated = __esm({
|
|
|
50841
50959
|
"../../packages/serve/src/preview-assets.generated.ts"() {
|
|
50842
50960
|
init_preview_assets_format();
|
|
50843
50961
|
PREVIEW_ASSET_MANIFEST = [
|
|
50844
|
-
{ key: "assets/index-
|
|
50845
|
-
{ key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset:
|
|
50846
|
-
{ key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset:
|
|
50847
|
-
{ key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset:
|
|
50848
|
-
{ key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset:
|
|
50849
|
-
{ key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset:
|
|
50850
|
-
{ key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset:
|
|
50851
|
-
{ key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset:
|
|
50852
|
-
{ key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset:
|
|
50853
|
-
{ key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset:
|
|
50854
|
-
{ key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset:
|
|
50855
|
-
{ key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset:
|
|
50856
|
-
{ key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset:
|
|
50857
|
-
{ key: "index.html", contentType: "text/html; charset=utf-8", offset:
|
|
50858
|
-
{ key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset:
|
|
50962
|
+
{ key: "assets/index-DT6bRpY_.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1055972, sha256: "3a52c8395a6509cfe2cae8036024b987cd3361095ff5450bfd7a9efa0123850b" },
|
|
50963
|
+
{ key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 1055980, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
|
|
50964
|
+
{ key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 1060590, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
|
|
50965
|
+
{ key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1549174, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
|
|
50966
|
+
{ key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1640098, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
|
|
50967
|
+
{ key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1731082, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
|
|
50968
|
+
{ key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1822062, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
|
|
50969
|
+
{ key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1912934, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
|
|
50970
|
+
{ key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 2003914, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
|
|
50971
|
+
{ key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 2112550, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
|
|
50972
|
+
{ key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 2221634, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
|
|
50973
|
+
{ key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 2330682, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
|
|
50974
|
+
{ key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 2438382, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
|
|
50975
|
+
{ key: "index.html", contentType: "text/html; charset=utf-8", offset: 2526490, length: 4947, sha256: "a9dcd2ec33b7ea5cee46b0a1f37f926678dd6939b442e3d50bff0101f0fe63ba" },
|
|
50976
|
+
{ key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 2531437, length: 17209, sha256: "dffc9718e2faa63ae2cc919e0a842f585ed565aaaa7c53778e90379442c731b6" }
|
|
50859
50977
|
];
|
|
50860
50978
|
}
|
|
50861
50979
|
});
|
|
@@ -54059,7 +54177,28 @@ function deriveTailoring(ctx, overrides = {}, revision = "site-derived") {
|
|
|
54059
54177
|
};
|
|
54060
54178
|
return { appName, iconSource: deriveIconSource(ctx), provisioning, missing };
|
|
54061
54179
|
}
|
|
54062
|
-
|
|
54180
|
+
function bounded(s, max) {
|
|
54181
|
+
if (s.length <= max) return s;
|
|
54182
|
+
const cut = s.slice(0, max - 1);
|
|
54183
|
+
const space = cut.lastIndexOf(" ");
|
|
54184
|
+
return `${(space > max * 0.6 ? cut.slice(0, space) : cut).trimEnd()}\u2026`;
|
|
54185
|
+
}
|
|
54186
|
+
function deriveStaticFaq(faq) {
|
|
54187
|
+
if (!Array.isArray(faq)) return [];
|
|
54188
|
+
const out = [];
|
|
54189
|
+
const seen = /* @__PURE__ */ new Set();
|
|
54190
|
+
for (const raw of faq) {
|
|
54191
|
+
if (out.length >= STATIC_FAQ_LIMITS.pairs) break;
|
|
54192
|
+
const pair = raw && typeof raw === "object" ? raw : {};
|
|
54193
|
+
const q = bounded(oneLine(pair.q), STATIC_FAQ_LIMITS.question);
|
|
54194
|
+
const a = bounded(oneLine(pair.a), STATIC_FAQ_LIMITS.answer);
|
|
54195
|
+
if (!q || !a || seen.has(q.toLowerCase())) continue;
|
|
54196
|
+
seen.add(q.toLowerCase());
|
|
54197
|
+
out.push({ q, a });
|
|
54198
|
+
}
|
|
54199
|
+
return out;
|
|
54200
|
+
}
|
|
54201
|
+
var clean, ID_MAX, NAME_MAX, TYPE_MAX, CONTROL_CHARS, HAS_CONTROL_CHAR, plain, shown, STATIC_FAQ_LIMITS, oneLine;
|
|
54063
54202
|
var init_derive = __esm({
|
|
54064
54203
|
"src/site-analyze/derive.ts"() {
|
|
54065
54204
|
init_types2();
|
|
@@ -54071,6 +54210,8 @@ var init_derive = __esm({
|
|
|
54071
54210
|
HAS_CONTROL_CHAR = /[\u0000-\u001F\u007F]/;
|
|
54072
54211
|
plain = (value, max) => (value ?? "").replace(CONTROL_CHARS, "").trim().slice(0, max);
|
|
54073
54212
|
shown = (value) => (typeof value === "string" ? JSON.stringify(value) : String(value)).slice(0, 64);
|
|
54213
|
+
STATIC_FAQ_LIMITS = { pairs: 20, question: 200, answer: 1500 };
|
|
54214
|
+
oneLine = (s) => typeof s === "string" ? s.replace(/[\u0000-\u001F\u007F\s]+/g, " ").trim() : "";
|
|
54074
54215
|
}
|
|
54075
54216
|
});
|
|
54076
54217
|
|
|
@@ -57129,7 +57270,8 @@ function mergeCustomerOwned(committed, overlay) {
|
|
|
57129
57270
|
"navigation",
|
|
57130
57271
|
"locale",
|
|
57131
57272
|
"wix",
|
|
57132
|
-
"copy"
|
|
57273
|
+
"copy",
|
|
57274
|
+
"faq"
|
|
57133
57275
|
];
|
|
57134
57276
|
const customer = {};
|
|
57135
57277
|
for (const key2 of CUSTOMER_OWNED) {
|
|
@@ -57223,12 +57365,56 @@ function buildMergedContract(options) {
|
|
|
57223
57365
|
staged.push(localPath);
|
|
57224
57366
|
return { path: path2, staged };
|
|
57225
57367
|
}
|
|
57368
|
+
function catalogTypography(overlay, template) {
|
|
57369
|
+
const typography = {};
|
|
57370
|
+
const notes = [];
|
|
57371
|
+
const base = template && typeof template === "object" ? template : {};
|
|
57372
|
+
const usable = (family) => typeof family === "string" && family.trim() !== "" && (family === SYSTEM_FONT_FAMILY || canonicalFamilyName(family) !== void 0);
|
|
57373
|
+
for (const [role, token] of Object.entries(overlay ?? {})) {
|
|
57374
|
+
const family = token?.family;
|
|
57375
|
+
if (typeof family !== "string" || family.trim() === "") {
|
|
57376
|
+
typography[role] = token;
|
|
57377
|
+
continue;
|
|
57378
|
+
}
|
|
57379
|
+
if (family === SYSTEM_FONT_FAMILY) {
|
|
57380
|
+
typography[role] = token;
|
|
57381
|
+
continue;
|
|
57382
|
+
}
|
|
57383
|
+
const canonical3 = canonicalFamilyName(family.trim());
|
|
57384
|
+
if (canonical3) {
|
|
57385
|
+
typography[role] = { ...token, family: canonical3 };
|
|
57386
|
+
continue;
|
|
57387
|
+
}
|
|
57388
|
+
const kept = base[role]?.family;
|
|
57389
|
+
const using = usable(kept) ? `the template's ${kept}` : `the template's default (${TIER1_FLOOR[0]})`;
|
|
57390
|
+
notes.push(`site font "${family}" (${role}) isn't in the font catalog; using ${using}`);
|
|
57391
|
+
}
|
|
57392
|
+
return { typography, notes };
|
|
57393
|
+
}
|
|
57394
|
+
function staticFaqFor(overlay, overlayPath) {
|
|
57395
|
+
const own3 = overlay.faq;
|
|
57396
|
+
if (own3 !== void 0) return deriveStaticFaq(own3);
|
|
57397
|
+
const bookPath = join59(dirname32(resolve45(overlayPath)), "book.json");
|
|
57398
|
+
if (!existsSync61(bookPath)) return void 0;
|
|
57399
|
+
try {
|
|
57400
|
+
const book = JSON.parse(readFileSync72(bookPath, "utf8"));
|
|
57401
|
+
const copy = book?.copy;
|
|
57402
|
+
if (!copy || typeof copy !== "object" || copy.unavailable) return void 0;
|
|
57403
|
+
const pairs = deriveStaticFaq(copy.faq);
|
|
57404
|
+
if (!pairs.length && copy.partial) return void 0;
|
|
57405
|
+
return pairs;
|
|
57406
|
+
} catch {
|
|
57407
|
+
return void 0;
|
|
57408
|
+
}
|
|
57409
|
+
}
|
|
57226
57410
|
async function applyOverlays(input) {
|
|
57227
57411
|
const cwd = resolve45(input.cwd);
|
|
57228
57412
|
const shell = input.shell ?? DEFAULT_BRANDABLE_SHELL;
|
|
57229
57413
|
assertKnownShell(shell);
|
|
57230
57414
|
const overlay = JSON.parse(readFileSync72(input.overlayPath, "utf8"));
|
|
57231
57415
|
const tokens = JSON.parse(readFileSync72(input.tokensPath, "utf8"));
|
|
57416
|
+
const faq = staticFaqFor(overlay, input.overlayPath);
|
|
57417
|
+
if (faq !== void 0) overlay.faq = faq;
|
|
57232
57418
|
const wrote = [];
|
|
57233
57419
|
const notes = [];
|
|
57234
57420
|
const repoRoot2 = findRepoRoot(cwd);
|
|
@@ -57262,9 +57448,11 @@ async function applyOverlays(input) {
|
|
|
57262
57448
|
}
|
|
57263
57449
|
const pkgProv = join59(cwd, "provisioning.json");
|
|
57264
57450
|
assertNotCommitted(pkgProv, input.forbiddenProvisioning);
|
|
57451
|
+
let packageFaq = faq;
|
|
57265
57452
|
if (existsSync61(pkgProv)) {
|
|
57266
57453
|
const cur = JSON.parse(readFileSync72(pkgProv, "utf8"));
|
|
57267
57454
|
const merged = deepMerge4(cur, overlay);
|
|
57455
|
+
packageFaq = merged.faq;
|
|
57268
57456
|
writeFileSync27(pkgProv, JSON.stringify(merged, null, 2) + "\n");
|
|
57269
57457
|
wrote.push(pkgProv);
|
|
57270
57458
|
} else {
|
|
@@ -57274,7 +57462,13 @@ async function applyOverlays(input) {
|
|
|
57274
57462
|
const pkgTokens = join59(cwd, "tokens.json");
|
|
57275
57463
|
if (existsSync61(pkgTokens) && (tokens.colors || tokens.typography)) {
|
|
57276
57464
|
const cur = JSON.parse(readFileSync72(pkgTokens, "utf8"));
|
|
57277
|
-
|
|
57465
|
+
let tokensIn = tokens;
|
|
57466
|
+
if (tokens.typography) {
|
|
57467
|
+
const fonts = catalogTypography(tokens.typography, cur.typography);
|
|
57468
|
+
notes.push(...fonts.notes);
|
|
57469
|
+
tokensIn = { ...tokens, typography: fonts.typography };
|
|
57470
|
+
}
|
|
57471
|
+
const merged = deepMerge4(cur, tokensIn);
|
|
57278
57472
|
const mergedColors = merged.colors;
|
|
57279
57473
|
if (mergedColors && typeof mergedColors === "object" && !Array.isArray(mergedColors)) {
|
|
57280
57474
|
merged.colors = alignAccentsToSurfaces(mergedColors, tokens.colors);
|
|
@@ -57297,8 +57491,16 @@ async function applyOverlays(input) {
|
|
|
57297
57491
|
const prev = readFileSync72(homeSrc, "utf8");
|
|
57298
57492
|
const patched = patchBrandParams(prev, overlay, homeAction);
|
|
57299
57493
|
let next = patched.src;
|
|
57300
|
-
if (!patched.foreign &&
|
|
57301
|
-
|
|
57494
|
+
if (!patched.foreign && faq?.length && prev.includes('"tier5.himiBrandedFaq.load"') && !prev.includes('"staticFaq"')) {
|
|
57495
|
+
notes.push(
|
|
57496
|
+
"the site's FAQ pairs were saved to provisioning.json, but this package's FAQ screen predates the site-FAQ fallback and will not show them \u2014 re-scaffold from the current template to pick it up"
|
|
57497
|
+
);
|
|
57498
|
+
}
|
|
57499
|
+
const keepFaq = Array.isArray(packageFaq) && packageFaq.length > 0;
|
|
57500
|
+
const dropFaq = Array.isArray(faq) && faq.length === 0;
|
|
57501
|
+
const ownsHome = prev.includes(`"actionId": "${homeAction}"`);
|
|
57502
|
+
if (ownsHome && !patched.foreign && (overlay.installedVerticals?.length || keepFaq || dropFaq)) {
|
|
57503
|
+
const home = patchHomeForVerticals(next, overlay.installedVerticals ?? [], homeAction, { keepFaq, dropFaq });
|
|
57302
57504
|
next = home.src;
|
|
57303
57505
|
if (home.droppedCtas.length) {
|
|
57304
57506
|
notes.push(`removed the home's store call(s) to action (${home.droppedCtas.join(", ")}) \u2014 this site has no store`);
|
|
@@ -57344,10 +57546,18 @@ function patchBrandParams(src, overlay, homeActionId) {
|
|
|
57344
57546
|
const layout = overlay.appearance?.homeLayout;
|
|
57345
57547
|
const accent = overlay.branding?.primaryColor;
|
|
57346
57548
|
const verts = overlay.installedVerticals;
|
|
57549
|
+
const faq = overlay.faq;
|
|
57347
57550
|
const edits = [
|
|
57348
57551
|
...layout ? [{ pattern: /"ownerDefaultLayout": "[^"]*"/g, replacement: `"ownerDefaultLayout": ${JSON.stringify(layout)}` }] : [],
|
|
57349
57552
|
...accent ? [{ pattern: /"brandAccent": "[^"]*"/g, replacement: `"brandAccent": ${JSON.stringify(accent)}` }] : [],
|
|
57350
|
-
...verts?.length ? [{ pattern: /"verticals": "\[[^\]]*\]"/g, replacement: `"verticals": ${JSON.stringify(JSON.stringify(verts))}` }] : []
|
|
57553
|
+
...verts?.length ? [{ pattern: /"verticals": "\[[^\]]*\]"/g, replacement: `"verticals": ${JSON.stringify(JSON.stringify(verts))}` }] : [],
|
|
57554
|
+
// The FAQ screen's fallback pairs (#3276), a JSON STRING like `verticals` because action
|
|
57555
|
+
// params are string-valued. The pattern matches any escaped string, so re-applying a
|
|
57556
|
+
// package whose pairs are already written replaces them instead of missing. A function
|
|
57557
|
+
// replacement, because the pairs are customer text and may contain `$&`. Patched whenever
|
|
57558
|
+
// the analysis SAID something, `[]` included, so a re-apply clears pairs an earlier one
|
|
57559
|
+
// baked in rather than leaving the worker another site's FAQ.
|
|
57560
|
+
...faq ? [{ pattern: /"staticFaq": "(?:[^"\\]|\\.)*"/g, replacement: `"staticFaq": ${JSON.stringify(JSON.stringify(faq))}` }] : []
|
|
57351
57561
|
];
|
|
57352
57562
|
if (!edits.length) return { src, applied: 0, unparsed: 0, foreign: false };
|
|
57353
57563
|
if (!src.includes(`"actionId": "${homeActionId}"`)) {
|
|
@@ -57392,7 +57602,7 @@ function patchBrandParams(src, overlay, homeActionId) {
|
|
|
57392
57602
|
pattern.lastIndex = 0;
|
|
57393
57603
|
if (!pattern.test(block)) continue;
|
|
57394
57604
|
pattern.lastIndex = 0;
|
|
57395
|
-
block = block.replace(pattern, replacement);
|
|
57605
|
+
block = block.replace(pattern, () => replacement);
|
|
57396
57606
|
applied += 1;
|
|
57397
57607
|
}
|
|
57398
57608
|
out += src.slice(cursor, open) + block;
|
|
@@ -57410,6 +57620,10 @@ var init_apply2 = __esm({
|
|
|
57410
57620
|
init_branding_derive();
|
|
57411
57621
|
init_brand_color_math();
|
|
57412
57622
|
init_home_descriptor();
|
|
57623
|
+
init_derive();
|
|
57624
|
+
init_catalog();
|
|
57625
|
+
init_plan_fonts();
|
|
57626
|
+
init_tokens();
|
|
57413
57627
|
STAGED = ".himi/brand";
|
|
57414
57628
|
}
|
|
57415
57629
|
});
|
|
Binary file
|
|
@@ -3463,13 +3463,13 @@
|
|
|
3463
3463
|
"name": "experiments",
|
|
3464
3464
|
"kind": "const",
|
|
3465
3465
|
"jsdoc": "",
|
|
3466
|
-
"decl": "export const experiments = {\n /**
|
|
3466
|
+
"decl": "export const experiments = {\n /** The app's served variant for `spec` (`himi flags`), or `fallback` when none is assigned. */\n async conduct(spec: string, fallback = \"false\"): Promise<ExperimentResult> {\n const resolved = await conductCached(\"experiments\", spec, fallback, () => resolveExperiment(spec, fallback));\n return { spec, variant: resolved ?? fallback };\n },\n /** Boolean convenience — true when the variant is exactly \"true\". */\n async isEnabled(spec: string): Promise<boolean> {\n return (await experiments.conduct(spec, \"false\")).variant === \"true\";\n },\n /** Report A/B exposure for `spec`/`variant` — emits the platform's\n * `experiment_exposed` telemetry so outcome events attribute to the variant.\n * (Symphony relies on server-side conduction; this is the generalized app-side\n * exposure hook.) */\n async exposure(spec: string, variant: string): Promise<{ ok: boolean }> {\n const r = await call<{ ok?: boolean }>(\"experimentsExposure\", { spec, variant });\n return { ok: r?.ok ?? false };\n },\n};"
|
|
3467
3467
|
},
|
|
3468
3468
|
{
|
|
3469
3469
|
"name": "flags",
|
|
3470
3470
|
"kind": "const",
|
|
3471
3471
|
"jsdoc": "",
|
|
3472
|
-
"decl": "export const flags = {\n /** Whether
|
|
3472
|
+
"decl": "export const flags = {\n /** Whether the app's served flag `spec` is ON (variant `on`/`true`/`new`), else `fallback`. */\n async isEnabled(spec: string, fallback = false): Promise<boolean> {\n const resolved = await conductCached(\"flags\", spec, String(fallback), () => resolveFlag(spec, fallback));\n if (resolved === null) return fallback;\n return resolved === \"true\" || resolved === \"new\";\n },\n /** A toggle's raw value (variant string) for non-boolean specs. */\n async value(spec: string, fallback = \"\"): Promise<string> {\n const r = await call<{ value?: string }>(\"flagsValue\", { spec, fallback });\n return r?.value ?? fallback;\n },\n /** All known toggle states (dev/diagnostic). */\n async all(): Promise<Record<string, string>> {\n const r = await call<{ flags?: Record<string, string> }>(\"flagsAll\");\n return r?.flags && typeof r.flags === \"object\" ? r.flags : {};\n },\n};"
|
|
3473
3473
|
},
|
|
3474
3474
|
{
|
|
3475
3475
|
"name": "i18n",
|
|
@@ -3487,13 +3487,13 @@
|
|
|
3487
3487
|
"name": "ping",
|
|
3488
3488
|
"kind": "const",
|
|
3489
3489
|
"jsdoc": "",
|
|
3490
|
-
"decl": "export const ping = {\n /** Register the device's push token with Wix Ping. */\n async register(): Promise<PingRegistration> {\n
|
|
3490
|
+
"decl": "export const ping = {\n /** Register the device's push token with Wix Ping. */\n async register(): Promise<PingRegistration> {\n const r = await call<{ registered?: boolean; token?: string }>(\"pingRegister\");\n return { registered: r?.registered ?? false, token: r?.token ?? \"\" };\n },\n /** Current Ping registration status (no network). */\n async status(): Promise<PingRegistration> {\n const r = await call<{ registered?: boolean; token?: string }>(\"pingStatus\");\n return { registered: r?.registered ?? false, token: r?.token ?? \"\" };\n },\n};"
|
|
3491
3491
|
},
|
|
3492
3492
|
{
|
|
3493
3493
|
"name": "deeplink",
|
|
3494
3494
|
"kind": "const",
|
|
3495
3495
|
"jsdoc": "",
|
|
3496
|
-
"decl": "export const deeplink = {\n /** Resolve a deferred (post-install) deep link via Wix Jot. Null when none. */\n async resolveDeferred(): Promise<{ link: string | null }> {\n
|
|
3496
|
+
"decl": "export const deeplink = {\n /** Resolve a deferred (post-install) deep link via Wix Jot. Null when none. */\n async resolveDeferred(): Promise<{ link: string | null }> {\n const r = await call<{ link?: string }>(\"deeplinkResolveDeferred\");\n return { link: r?.link && r.link.length > 0 ? r.link : null };\n },\n};"
|
|
3497
3497
|
},
|
|
3498
3498
|
{
|
|
3499
3499
|
"name": "SignedInstanceStatus",
|
|
@@ -26,7 +26,7 @@ import { bi, experiments, flags, i18n, auth, monitoring } from "@himalaya/wix-pl
|
|
|
26
26
|
await bi.pageView("home");
|
|
27
27
|
await bi.click("cta_start", "home");
|
|
28
28
|
|
|
29
|
-
// experiments (
|
|
29
|
+
// experiments / flags — the app's served flags (`himi flags`), never Wix Petri
|
|
30
30
|
const variant = await experiments.conduct("specs.ai", "false"); // → { spec, variant }
|
|
31
31
|
if (await flags.isEnabled("specs.newCheckout")) { /* … */ }
|
|
32
32
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1047.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": [
|
|
@@ -65,5 +65,5 @@
|
|
|
65
65
|
"artifactId": "himalaya-cli"
|
|
66
66
|
}
|
|
67
67
|
},
|
|
68
|
-
"falconPackageHash": "
|
|
68
|
+
"falconPackageHash": "9a5f5cd39f2e85af3f506141935613aebbda4942b8cb91683db7492f"
|
|
69
69
|
}
|
|
@@ -58239,7 +58239,8 @@ const SCREENS = runtimeSetting({
|
|
|
58239
58239
|
"onAppear": {
|
|
58240
58240
|
"actionId": "tier5.himiBrandedFaq.load",
|
|
58241
58241
|
"params": {
|
|
58242
|
-
"otherCategory": "Other"
|
|
58242
|
+
"otherCategory": "Other",
|
|
58243
|
+
"staticFaq": "[]"
|
|
58243
58244
|
}
|
|
58244
58245
|
}
|
|
58245
58246
|
}
|
|
@@ -58,6 +58,55 @@ interface FaqState {
|
|
|
58
58
|
|
|
59
59
|
const PAGE_SIZE = 100;
|
|
60
60
|
|
|
61
|
+
/** Caps on the static pairs, matching `BRANDED_LITE_FAQ_LIMITS` in the app contract. The
|
|
62
|
+
* param is re-bounded here because a worker must not trust a descriptor it did not build. */
|
|
63
|
+
const STATIC_LIMITS = { pairs: 20, question: 200, answer: 1500 } as const;
|
|
64
|
+
const STATIC_CATEGORY: FaqCategory = { id: "himi-static-faq", title: "" };
|
|
65
|
+
|
|
66
|
+
/** The site's own FAQ pairs — questions it publishes as page sections rather than
|
|
67
|
+
* through the Wix FAQ app, carried in by `site analyze --apply` as the `staticFaq` onAppear
|
|
68
|
+
* param (a JSON string: action params are string-valued). They are the FALLBACK: shown only
|
|
69
|
+
* when the FAQ app yields no visible question, so an owner-edited Wix FAQ always wins. */
|
|
70
|
+
let staticQuestions: FaqQuestion[] = [];
|
|
71
|
+
|
|
72
|
+
function parseStaticFaq(raw: unknown): FaqQuestion[] {
|
|
73
|
+
let pairs: unknown = raw;
|
|
74
|
+
if (typeof raw === "string") {
|
|
75
|
+
try {
|
|
76
|
+
pairs = JSON.parse(raw);
|
|
77
|
+
} catch {
|
|
78
|
+
// A malformed param is a DESCRIPTOR bug, not an empty FAQ: there is no fallback to
|
|
79
|
+
// offer, so the screen shows exactly what the Wix FAQ read says — its content, its
|
|
80
|
+
// empty card, or its error card — rather than pretending the site has no questions.
|
|
81
|
+
pairs = undefined;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (!Array.isArray(pairs)) return [];
|
|
85
|
+
const out: FaqQuestion[] = [];
|
|
86
|
+
for (const pair of pairs) {
|
|
87
|
+
if (out.length >= STATIC_LIMITS.pairs) break;
|
|
88
|
+
const row = pair && typeof pair === "object" ? pair as { q?: unknown; a?: unknown } : {};
|
|
89
|
+
const question = typeof row.q === "string" ? row.q.trim().slice(0, STATIC_LIMITS.question) : "";
|
|
90
|
+
const answer = typeof row.a === "string" ? row.a.trim().slice(0, STATIC_LIMITS.answer) : "";
|
|
91
|
+
if (!question || !answer) continue;
|
|
92
|
+
out.push({
|
|
93
|
+
id: `himi-static-faq-${out.length}`,
|
|
94
|
+
categoryId: STATIC_CATEGORY.id,
|
|
95
|
+
question,
|
|
96
|
+
answer,
|
|
97
|
+
sortOrder: out.length,
|
|
98
|
+
status: "VISIBLE",
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return out;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** The site's pairs as a ready state, or undefined when there are none to fall back to. */
|
|
105
|
+
function staticFallback(state: FaqState): FaqState | undefined {
|
|
106
|
+
if (!staticQuestions.length) return undefined;
|
|
107
|
+
return ready({ ...state, categories: [STATIC_CATEGORY], questions: staticQuestions });
|
|
108
|
+
}
|
|
109
|
+
|
|
61
110
|
function sortByWixOrder<T extends { id: string; sortOrder?: number }>(left: T, right: T): number {
|
|
62
111
|
const a = Number.isFinite(left.sortOrder) ? left.sortOrder! : Number.POSITIVE_INFINITY;
|
|
63
112
|
const b = Number.isFinite(right.sortOrder) ? right.sortOrder! : Number.POSITIVE_INFINITY;
|
|
@@ -101,7 +150,8 @@ function ready(state: FaqState): FaqState {
|
|
|
101
150
|
const rows = sections.flatMap((section) => section.questions.map((question, index) => ({
|
|
102
151
|
...question,
|
|
103
152
|
categoryTitle: section.title,
|
|
104
|
-
|
|
153
|
+
// An untitled section (the static fallback's) has no header to show.
|
|
154
|
+
categoryHeaderHidden: index !== 0 || !section.title,
|
|
105
155
|
})));
|
|
106
156
|
return {
|
|
107
157
|
...state,
|
|
@@ -218,17 +268,28 @@ function commit(state: FaqState): FaqState {
|
|
|
218
268
|
return state;
|
|
219
269
|
}
|
|
220
270
|
|
|
221
|
-
async function loadFaq(state: FaqState, arg?: { otherCategory?: string }): Promise<FaqState> {
|
|
271
|
+
async function loadFaq(state: FaqState, arg?: { otherCategory?: string; staticFaq?: unknown }): Promise<FaqState> {
|
|
222
272
|
latestState = state;
|
|
273
|
+
// Only when the caller passed the param: `retry` is dispatched with no params and must keep
|
|
274
|
+
// the pairs the screen's onAppear delivered.
|
|
275
|
+
if (arg && "staticFaq" in arg) staticQuestions = parseStaticFaq(arg.staticFaq);
|
|
223
276
|
const generation = ++loadGeneration;
|
|
224
277
|
try {
|
|
225
278
|
const [categories, questions] = await Promise.all([allCategories(), allQuestions()]);
|
|
226
279
|
if (generation !== loadGeneration) return latestState;
|
|
227
280
|
const otherTitle = String(arg?.otherCategory ?? latestState.otherTitle).trim() || latestState.otherTitle;
|
|
228
|
-
|
|
281
|
+
const live = ready({ ...latestState, categories, questions, otherTitle });
|
|
282
|
+
// The Wix FAQ app answered but holds nothing a visitor can see — the site's own pairs,
|
|
283
|
+
// when it has any, instead of an empty state over a site whose FAQ is right there.
|
|
284
|
+
if (questions.length === 0) return commit(staticFallback(live) ?? live);
|
|
285
|
+
return commit(live);
|
|
229
286
|
} catch (error) {
|
|
230
287
|
if (generation !== loadGeneration) return latestState;
|
|
231
288
|
const status = httpStatus(error);
|
|
289
|
+
// No FAQ app (428), no visitor access (403) or a failed read: a site whose FAQ is page
|
|
290
|
+
// content still has an FAQ to show, so its pairs replace the failure card.
|
|
291
|
+
const fallback = staticFallback(latestState);
|
|
292
|
+
if (fallback) return commit(fallback);
|
|
232
293
|
return commit(failure(latestState, status === 403 ? "forbidden" : status === 428 ? "notInstalled" : "error"));
|
|
233
294
|
}
|
|
234
295
|
}
|
|
@@ -250,4 +311,4 @@ const svc = defineService("himiBrandedFaq", {
|
|
|
250
311
|
},
|
|
251
312
|
});
|
|
252
313
|
|
|
253
|
-
export { svc, sectionsFor, httpStatus };
|
|
314
|
+
export { svc, sectionsFor, httpStatus, parseStaticFaq };
|