@fayz-ai/storefront 0.82.0 → 0.83.1

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.
Files changed (36) hide show
  1. package/dist/analytics/meta-pixel.d.ts.map +1 -1
  2. package/dist/analytics/posthog.d.ts +3 -0
  3. package/dist/analytics/posthog.d.ts.map +1 -1
  4. package/dist/app/router.d.ts +2 -2
  5. package/dist/chunk-4REZOGGW.js +153 -0
  6. package/dist/chunk-4REZOGGW.js.map +1 -0
  7. package/dist/{chunk-UJHCVRK3.js → chunk-7N5HKQBM.js} +2 -2
  8. package/dist/{chunk-UJHCVRK3.js.map → chunk-7N5HKQBM.js.map} +1 -1
  9. package/dist/{chunk-GI5BTJK6.js → chunk-G2R6OJQA.js} +4 -4
  10. package/dist/{chunk-GI5BTJK6.js.map → chunk-G2R6OJQA.js.map} +1 -1
  11. package/dist/{chunk-RYWQGQ4M.js → chunk-OV6DVQMB.js} +128 -115
  12. package/dist/chunk-OV6DVQMB.js.map +1 -0
  13. package/dist/components/delivery/StoreCover.d.ts +0 -17
  14. package/dist/components/delivery/StoreCover.d.ts.map +1 -1
  15. package/dist/document/config.d.ts +7 -5
  16. package/dist/document/config.d.ts.map +1 -1
  17. package/dist/edge.d.ts +1 -1
  18. package/dist/edge.d.ts.map +1 -1
  19. package/dist/edge.js +16 -26
  20. package/dist/edge.js.map +1 -1
  21. package/dist/experiments/assign.d.ts +41 -53
  22. package/dist/experiments/assign.d.ts.map +1 -1
  23. package/dist/experiments/react.d.ts +4 -3
  24. package/dist/experiments/react.d.ts.map +1 -1
  25. package/dist/host/edge-handler.d.ts +15 -12
  26. package/dist/host/edge-handler.d.ts.map +1 -1
  27. package/dist/host.js +4 -4
  28. package/dist/index.js +7 -7
  29. package/dist/lib/theme.d.ts +2 -0
  30. package/dist/lib/theme.d.ts.map +1 -1
  31. package/dist/render.js +4 -4
  32. package/dist/tanstack.js +3 -3
  33. package/package.json +4 -4
  34. package/dist/chunk-746BEU7H.js +0 -160
  35. package/dist/chunk-746BEU7H.js.map +0 -1
  36. package/dist/chunk-RYWQGQ4M.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"meta-pixel.d.ts","sourceRoot":"","sources":["../../src/analytics/meta-pixel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwC,KAAK,eAAe,EAAE,MAAM,OAAO,CAAA;AAElF;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,yBAAyB;IACxC,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,KAAK,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC,GAAG;IAC1C,UAAU,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IACzC,KAAK,EAAE,OAAO,EAAE,CAAA;IAChB,IAAI,EAAE,OAAO,CAAA;IACb,MAAM,EAAE,OAAO,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,GAAG,CAAC,EAAE,GAAG,CAAA;QACT,IAAI,CAAC,EAAE,GAAG,CAAA;KACX;CACF;AAED,eAAO,MAAM,aAAa,QAAmB,CAAA;AAE7C,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,aAAa,GAAG,WAAW,GAAG,kBAAkB,GAAG,gBAAgB,GAAG,UAAU,CAAA;IACtF,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAKD,0FAA0F;AAC1F,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAyCvF;AAuCD;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,yBAAyB,EAAE,OAAO,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAqB/G;AAED,8FAA8F;AAC9F,wBAAgB,iBAAiB,IAAI,IAAI,CAGxC;AAED,iBAAiB;AACjB,wBAAgB,wBAAwB,IAAI,IAAI,CAG/C"}
1
+ {"version":3,"file":"meta-pixel.d.ts","sourceRoot":"","sources":["../../src/analytics/meta-pixel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwC,KAAK,eAAe,EAAE,MAAM,OAAO,CAAA;AAElF;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,yBAAyB;IACxC,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,KAAK,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC,GAAG;IAC1C,UAAU,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IACzC,KAAK,EAAE,OAAO,EAAE,CAAA;IAChB,IAAI,EAAE,OAAO,CAAA;IACb,MAAM,EAAE,OAAO,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,GAAG,CAAC,EAAE,GAAG,CAAA;QACT,IAAI,CAAC,EAAE,GAAG,CAAA;KACX;CACF;AAED,eAAO,MAAM,aAAa,QAAmB,CAAA;AAE7C,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,aAAa,GAAG,WAAW,GAAG,kBAAkB,GAAG,gBAAgB,GAAG,UAAU,CAAA;IACtF,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAKD,0FAA0F;AAC1F,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAyCvF;AAsDD;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,yBAAyB,EAAE,OAAO,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAqB/G;AAED,8FAA8F;AAC9F,wBAAgB,iBAAiB,IAAI,IAAI,CAGxC;AAED,iBAAiB;AACjB,wBAAgB,wBAAwB,IAAI,IAAI,CAG/C"}
@@ -9,6 +9,9 @@ export interface StorefrontPostHogConfig {
9
9
  uiHost?: string;
10
10
  /** Session replay. Default on; inputs are always masked. */
11
11
  replay?: boolean;
12
+ /** PostHog surveys. Default off: no store runs one, and the client fetched
13
+ * surveys.js (~38 KB) on every page view to find that out. */
14
+ surveys?: boolean;
12
15
  }
13
16
  export interface StorefrontAnalyticsConfig {
14
17
  posthog?: StorefrontPostHogConfig;
@@ -1 +1 @@
1
- {"version":3,"file":"posthog.d.ts","sourceRoot":"","sources":["../../src/analytics/posthog.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,uBAAuB;IACtC,8EAA8E;IAC9E,GAAG,EAAE,MAAM,CAAA;IACX,sFAAsF;IACtF,OAAO,EAAE,MAAM,CAAA;IACf,6FAA6F;IAC7F,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,4DAA4D;IAC5D,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,CAAC,EAAE,uBAAuB,CAAA;IACjC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,cAAc,EAAE,yBAAyB,CAAA;CAC7D;AAED,UAAU,YAAY;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;CACrB;AAID;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,uBAAuB,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CA2EnH"}
1
+ {"version":3,"file":"posthog.d.ts","sourceRoot":"","sources":["../../src/analytics/posthog.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,uBAAuB;IACtC,8EAA8E;IAC9E,GAAG,EAAE,MAAM,CAAA;IACX,sFAAsF;IACtF,OAAO,EAAE,MAAM,CAAA;IACf,6FAA6F;IAC7F,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,4DAA4D;IAC5D,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB;mEAC+D;IAC/D,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,CAAC,EAAE,uBAAuB,CAAA;IACjC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,cAAc,EAAE,yBAAyB,CAAA;CAC7D;AAED,UAAU,YAAY;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;CACrB;AAID;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,uBAAuB,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CA4EnH"}
@@ -40,12 +40,12 @@ export declare function Link({ to, children, onClick, target, ...rest }: LinkPro
40
40
  style?: React.CSSProperties | undefined;
41
41
  title?: string | undefined | undefined;
42
42
  prefix?: string | undefined | undefined;
43
- referrerPolicy?: React.HTMLAttributeReferrerPolicy | undefined;
44
- type?: string | undefined | undefined;
45
43
  download?: any;
46
44
  hrefLang?: string | undefined | undefined;
47
45
  media?: string | undefined | undefined;
48
46
  ping?: string | undefined | undefined;
47
+ type?: string | undefined | undefined;
48
+ referrerPolicy?: React.HTMLAttributeReferrerPolicy | undefined;
49
49
  defaultChecked?: boolean | undefined | undefined;
50
50
  defaultValue?: string | number | readonly string[] | undefined;
51
51
  suppressContentEditableWarning?: boolean | undefined | undefined;
@@ -0,0 +1,153 @@
1
+ // src/experiments/assign.ts
2
+ var CONTROL = "control";
3
+ var EXPERIMENT_HEADER = "x-fayz-experiments";
4
+ var VISITOR_COOKIE = "fz_vid";
5
+ var NO_ASSIGNMENTS = Object.freeze({ flags: {} });
6
+ var FLAG_KEY = /^[A-Za-z0-9_-]{1,100}$/;
7
+ function validateExperiments(experiments) {
8
+ const issues = [];
9
+ for (const [key, experiment] of Object.entries(experiments ?? {})) {
10
+ const at = `experiments.${key}`;
11
+ if (!FLAG_KEY.test(key)) issues.push(`${at}: the key must be a PostHog flag key (letters, digits, - and _)`);
12
+ const variants = experiment?.variants ?? [];
13
+ if (!variants.includes(CONTROL)) issues.push(`${at}: variants must include "${CONTROL}"`);
14
+ if (variants.length < 2) issues.push(`${at}: an experiment needs at least two variants`);
15
+ if (new Set(variants).size !== variants.length) issues.push(`${at}: variants repeat`);
16
+ for (const variant of variants) {
17
+ if (!FLAG_KEY.test(variant)) issues.push(`${at}: variant "${variant}" is not a valid variant key`);
18
+ }
19
+ const status = experiment?.status;
20
+ if (status !== void 0 && status !== "running" && status !== "off") {
21
+ issues.push(`${at}.status: must be "running" or "off"`);
22
+ }
23
+ if (experiment?.split) {
24
+ const keys = Object.keys(experiment.split);
25
+ const missing = variants.filter((v) => !keys.includes(v));
26
+ const extra = keys.filter((k) => !variants.includes(k));
27
+ if (missing.length || extra.length) {
28
+ issues.push(`${at}.split: keys must be exactly the variants (missing: ${missing.join(", ") || "\u2014"}; unknown: ${extra.join(", ") || "\u2014"})`);
29
+ }
30
+ const values = Object.values(experiment.split);
31
+ if (values.some((n) => typeof n !== "number" || !Number.isFinite(n) || n < 0 || n > 100)) {
32
+ issues.push(`${at}.split: each share is a percentage from 0 to 100`);
33
+ } else if (Math.abs(values.reduce((a, b) => a + b, 0) - 100) > 1e-9) {
34
+ issues.push(`${at}.split: shares must sum to 100`);
35
+ }
36
+ }
37
+ const rollout = experiment?.rollout;
38
+ if (rollout !== void 0 && (typeof rollout !== "number" || !Number.isFinite(rollout) || rollout < 0 || rollout > 100)) {
39
+ issues.push(`${at}.rollout: a percentage from 0 to 100`);
40
+ }
41
+ }
42
+ return issues;
43
+ }
44
+ var BOT_UA = /bot\b|crawler|spider|crawling|slurp|bingpreview|facebookexternalhit|facebot|meta-externalagent|whatsapp|telegrambot|twitterbot|linkedinbot|discordbot|slackbot|embedly|pinterest|google-inspectiontool|googleother|lighthouse|headlesschrome|pagespeed|uptime|pingdom|curl\/|wget\/|python-requests|node-fetch|axios\//i;
45
+ function isBotUserAgent(userAgent) {
46
+ if (!userAgent) return true;
47
+ return BOT_UA.test(userAgent);
48
+ }
49
+ function readCookie(header, name) {
50
+ if (!header) return void 0;
51
+ for (const part of header.split(";")) {
52
+ const eq = part.indexOf("=");
53
+ if (eq < 0) continue;
54
+ if (part.slice(0, eq).trim() === name) return part.slice(eq + 1).trim();
55
+ }
56
+ return void 0;
57
+ }
58
+ function readVisitorId(cookieHeader, posthogKey) {
59
+ const own = readPinnedVisitorId(cookieHeader);
60
+ if (own) return own;
61
+ const posthog = readCookie(cookieHeader, `ph_${posthogKey}_posthog`);
62
+ if (posthog) {
63
+ try {
64
+ const id = JSON.parse(decodeURIComponent(posthog)).distinct_id;
65
+ if (typeof id === "string" && id) return id;
66
+ } catch {
67
+ }
68
+ }
69
+ return void 0;
70
+ }
71
+ var PINNABLE_ID = /^[A-Za-z0-9-]{8,64}$/;
72
+ function readPinnedVisitorId(cookieHeader) {
73
+ const own = readCookie(cookieHeader, VISITOR_COOKIE);
74
+ return own && PINNABLE_ID.test(own) ? own : void 0;
75
+ }
76
+ function isPinnableVisitorId(id) {
77
+ return PINNABLE_ID.test(id);
78
+ }
79
+ function visitorCookie(id, secure = true) {
80
+ return `${VISITOR_COOKIE}=${id}; Path=/; Max-Age=31536000; SameSite=Lax${secure ? "; Secure" : ""}`;
81
+ }
82
+ var LONG_SCALE = 1152921504606847e3;
83
+ async function sha1Hex(text) {
84
+ const digest = await crypto.subtle.digest("SHA-1", new TextEncoder().encode(text));
85
+ return Array.from(new Uint8Array(digest), (b) => b.toString(16).padStart(2, "0")).join("");
86
+ }
87
+ async function posthogHash(key, distinctId, salt = "") {
88
+ const hex = await sha1Hex(`${key}.${distinctId}${salt}`);
89
+ return parseInt(hex.slice(0, 15), 16) / LONG_SCALE;
90
+ }
91
+ async function inPosthogRollout(key, distinctId, rolloutPercentage) {
92
+ return !(await posthogHash(key, distinctId) > rolloutPercentage / 100);
93
+ }
94
+ async function posthogVariant(key, distinctId, variants) {
95
+ const hash = await posthogHash(key, distinctId, "variant");
96
+ let min = 0;
97
+ for (const variant of variants) {
98
+ const max = min + variant.rollout_percentage / 100;
99
+ if (hash >= min && hash < max) return variant.key;
100
+ min = max;
101
+ }
102
+ return void 0;
103
+ }
104
+ function experimentVariantTable(experiment) {
105
+ const variants = experiment.variants;
106
+ if (experiment.split) return variants.map((key) => ({ key, rollout_percentage: experiment.split[key] ?? 0 }));
107
+ const share = Math.floor(100 / variants.length);
108
+ return variants.map((key, i) => ({ key, rollout_percentage: share + (i === 0 ? 100 - share * variants.length : 0) }));
109
+ }
110
+ function runningExperiments(experiments) {
111
+ return Object.fromEntries(Object.entries(experiments ?? {}).filter(([, e]) => e.status === "running"));
112
+ }
113
+ async function assignExperiments(input) {
114
+ const flags = {};
115
+ for (const [key, experiment] of Object.entries(runningExperiments(input.experiments))) {
116
+ if (!await inPosthogRollout(key, input.distinctId, experiment.rollout ?? 100)) continue;
117
+ const variant = await posthogVariant(key, input.distinctId, experimentVariantTable(experiment));
118
+ if (variant && experiment.variants.includes(variant)) flags[key] = { variant };
119
+ }
120
+ return { distinctId: input.distinctId, flags };
121
+ }
122
+ function variantOf(assignments, key) {
123
+ return assignments?.flags[key]?.variant ?? CONTROL;
124
+ }
125
+ function experimentCacheSuffix(assignments, keys) {
126
+ return [...keys].sort().map((key) => [key, variantOf(assignments, key)]).filter(([, variant]) => variant !== CONTROL).map(([key, variant]) => `${key}:${variant}`).join(",");
127
+ }
128
+ function encodeExperimentHeader(assignments) {
129
+ return encodeURIComponent(JSON.stringify(assignments));
130
+ }
131
+ function decodeExperimentHeader(value) {
132
+ if (!value) return null;
133
+ try {
134
+ const parsed = JSON.parse(decodeURIComponent(value));
135
+ if (!parsed || typeof parsed !== "object" || typeof parsed.flags !== "object" || parsed.flags === null) return null;
136
+ const flags = {};
137
+ for (const [key, a] of Object.entries(parsed.flags)) {
138
+ if (a && typeof a === "object" && typeof a.variant === "string") {
139
+ flags[key] = a;
140
+ }
141
+ }
142
+ return {
143
+ ...typeof parsed.distinctId === "string" && parsed.distinctId ? { distinctId: parsed.distinctId } : {},
144
+ flags
145
+ };
146
+ } catch {
147
+ return null;
148
+ }
149
+ }
150
+
151
+ export { CONTROL, EXPERIMENT_HEADER, NO_ASSIGNMENTS, VISITOR_COOKIE, assignExperiments, decodeExperimentHeader, encodeExperimentHeader, experimentCacheSuffix, experimentVariantTable, inPosthogRollout, isBotUserAgent, isPinnableVisitorId, posthogHash, posthogVariant, readPinnedVisitorId, readVisitorId, runningExperiments, validateExperiments, visitorCookie };
152
+ //# sourceMappingURL=chunk-4REZOGGW.js.map
153
+ //# sourceMappingURL=chunk-4REZOGGW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/experiments/assign.ts"],"names":[],"mappings":"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","file":"chunk-4REZOGGW.js","sourcesContent":["// ---------------------------------------------------------------------------\n// Experiment assignment, decided before the page renders — locally.\n//\n// The variant is computed at the edge from a stable anonymous id with PostHog's\n// own bucketing (sha1 of `<flag>.<id>`, the same rollout and variant tables),\n// so the result equals what PostHog's flag answers for that id while making no\n// network call: a new visitor no longer waits on a flags round trip before the\n// first byte. The store config is the source of truth for who sees what; the\n// PostHog Experiment over the same flag key is where the results are read.\n//\n// Every visitor who is not in a running experiment gets 'control' and is not\n// counted: experiments that are off, crawlers, visitors outside the rollout.\n// ---------------------------------------------------------------------------\n\n/** The variant every visitor gets when nothing else can be decided. */\nexport const CONTROL = 'control'\n\n/** Request header the edge hands the assignment to the renderer in. */\nexport const EXPERIMENT_HEADER = 'x-fayz-experiments'\n\n/** First-party cookie holding the anonymous id when PostHog has not set one yet. */\nexport const VISITOR_COOKIE = 'fz_vid'\n\n/** One experiment the store runs. */\nexport interface StorefrontExperiment {\n /**\n * The variant keys, in the order the PostHog flag lists them (the order\n * buckets are laid out in). Must include 'control'.\n */\n variants: readonly string[]\n /**\n * 'running' assigns visitors; 'off' (the default) shows everyone control and\n * counts no one. Launching or stopping a test is flipping this and deploying.\n */\n status?: 'running' | 'off'\n /** Percent of visitors per variant, summing to 100. Default: even, remainder to the first. */\n split?: Readonly<Record<string, number>>\n /** Percent of visitors in the experiment at all (the rest see control, uncounted). Default 100. */\n rollout?: number\n /** What is being tested and why — for whoever reads the config next. */\n description?: string\n}\n\n/** What a visitor sees for one experiment. */\nexport interface ExperimentAssignment {\n variant: string\n /** Reserved for per-variant data. Local assignment does not set it. */\n payload?: unknown\n}\n\n/** Everything the edge decided for one request. */\nexport interface ExperimentAssignments {\n /** The id the variants were computed for. Kept at the edge: it never\n * travels into the rendered (and cached) page — see `withAssignment`. */\n distinctId?: string\n /**\n * By flag key, ONLY the experiments this visitor is in — 'control' included\n * when bucketed into control. A declared key missing here renders control\n * but reports no exposure: the visitor is outside the experiment.\n */\n flags: Record<string, ExperimentAssignment>\n}\n\n/** The empty decision: every experiment at control. */\nexport const NO_ASSIGNMENTS: ExperimentAssignments = Object.freeze({ flags: {} }) as ExperimentAssignments\n\nconst FLAG_KEY = /^[A-Za-z0-9_-]{1,100}$/\n\n/**\n * Problems with a store's experiment declarations, empty when valid. Checked\n * when the host is created, so a typo fails the build rather than silently\n * running a page with no variants.\n */\nexport function validateExperiments(experiments: Record<string, StorefrontExperiment> | undefined): string[] {\n const issues: string[] = []\n for (const [key, experiment] of Object.entries(experiments ?? {})) {\n const at = `experiments.${key}`\n if (!FLAG_KEY.test(key)) issues.push(`${at}: the key must be a PostHog flag key (letters, digits, - and _)`)\n const variants = experiment?.variants ?? []\n if (!variants.includes(CONTROL)) issues.push(`${at}: variants must include \"${CONTROL}\"`)\n if (variants.length < 2) issues.push(`${at}: an experiment needs at least two variants`)\n if (new Set(variants).size !== variants.length) issues.push(`${at}: variants repeat`)\n for (const variant of variants) {\n if (!FLAG_KEY.test(variant)) issues.push(`${at}: variant \"${variant}\" is not a valid variant key`)\n }\n const status = experiment?.status\n if (status !== undefined && status !== 'running' && status !== 'off') {\n issues.push(`${at}.status: must be \"running\" or \"off\"`)\n }\n if (experiment?.split) {\n const keys = Object.keys(experiment.split)\n const missing = variants.filter((v) => !keys.includes(v))\n const extra = keys.filter((k) => !variants.includes(k))\n if (missing.length || extra.length) {\n issues.push(`${at}.split: keys must be exactly the variants (missing: ${missing.join(', ') || '—'}; unknown: ${extra.join(', ') || '—'})`)\n }\n const values = Object.values(experiment.split)\n if (values.some((n) => typeof n !== 'number' || !Number.isFinite(n) || n < 0 || n > 100)) {\n issues.push(`${at}.split: each share is a percentage from 0 to 100`)\n } else if (Math.abs(values.reduce((a, b) => a + b, 0) - 100) > 1e-9) {\n issues.push(`${at}.split: shares must sum to 100`)\n }\n }\n const rollout = experiment?.rollout\n if (rollout !== undefined && (typeof rollout !== 'number' || !Number.isFinite(rollout) || rollout < 0 || rollout > 100)) {\n issues.push(`${at}.rollout: a percentage from 0 to 100`)\n }\n }\n return issues\n}\n\n// Crawlers, link unfurlers and monitors. They always see control: what is\n// indexed and what a share card shows must not depend on a coin flip, and a\n// bot must not count as an exposure.\nconst BOT_UA =\n /bot\\b|crawler|spider|crawling|slurp|bingpreview|facebookexternalhit|facebot|meta-externalagent|whatsapp|telegrambot|twitterbot|linkedinbot|discordbot|slackbot|embedly|pinterest|google-inspectiontool|googleother|lighthouse|headlesschrome|pagespeed|uptime|pingdom|curl\\/|wget\\/|python-requests|node-fetch|axios\\//i\n\nexport function isBotUserAgent(userAgent: string | null | undefined): boolean {\n if (!userAgent) return true\n return BOT_UA.test(userAgent)\n}\n\nfunction readCookie(header: string | null | undefined, name: string): string | undefined {\n if (!header) return undefined\n for (const part of header.split(';')) {\n const eq = part.indexOf('=')\n if (eq < 0) continue\n if (part.slice(0, eq).trim() === name) return part.slice(eq + 1).trim()\n }\n return undefined\n}\n\n/**\n * The visitor's stable anonymous id, if the browser already has one:\n * posthog-js's own cookie first (so the edge evaluates flags for the very id\n * the browser reports events under), then the store's first-party cookie.\n */\nexport function readVisitorId(cookieHeader: string | null | undefined, posthogKey: string): string | undefined {\n // The store's own pinned id first: it never changes, while PostHog's\n // distinct_id does the moment a buyer identifies (e-mail at checkout) — and a\n // bucket computed from that would move a returning buyer to the other variant.\n const own = readPinnedVisitorId(cookieHeader)\n if (own) return own\n const posthog = readCookie(cookieHeader, `ph_${posthogKey}_posthog`)\n if (posthog) {\n try {\n const id = (JSON.parse(decodeURIComponent(posthog)) as { distinct_id?: unknown }).distinct_id\n if (typeof id === 'string' && id) return id\n } catch {\n /* unreadable cookie: no id */\n }\n }\n return undefined\n}\n\nconst PINNABLE_ID = /^[A-Za-z0-9-]{8,64}$/\n\n/** The `fz_vid` the edge pinned for this browser, if any. */\nexport function readPinnedVisitorId(cookieHeader: string | null | undefined): string | undefined {\n const own = readCookie(cookieHeader, VISITOR_COOKIE)\n return own && PINNABLE_ID.test(own) ? own : undefined\n}\n\n/** Whether an id may be stored in `fz_vid` (an anonymous id, never an e-mail). */\nexport function isPinnableVisitorId(id: string): boolean {\n return PINNABLE_ID.test(id)\n}\n\n/** `Set-Cookie` for a newly minted visitor id: a year, first-party, not readable cross-site. */\nexport function visitorCookie(id: string, secure = true): string {\n return `${VISITOR_COOKIE}=${id}; Path=/; Max-Age=31536000; SameSite=Lax${secure ? '; Secure' : ''}`\n}\n\n// --- PostHog's bucketing -----------------------------------------------------\n//\n// Exactly PostHog's local evaluation (@posthog/core featureFlagLocalEvaluation:\n// getFeatureFlagHash / getFeatureFlagVariantLookupTable; posthog-python's\n// `_hash` and `get_matching_variant`). Pinned against PostHog's own SDK test\n// vectors in test/experiments/posthog-bucketing.test.ts — change nothing here\n// without those passing, or the variant a shopper sees stops being the variant\n// PostHog counts them in.\n\n/** Larger than Number.MAX_SAFE_INTEGER on purpose: PostHog's rounding is part of the contract. */\n// oxlint-disable-next-line no-loss-of-precision\nconst LONG_SCALE = 0xfffffffffffffff\n\nasync function sha1Hex(text: string): Promise<string> {\n const digest = await crypto.subtle.digest('SHA-1', new TextEncoder().encode(text))\n return Array.from(new Uint8Array(digest), (b) => b.toString(16).padStart(2, '0')).join('')\n}\n\n/** PostHog's bucket for `key` and `distinctId`, in [0, 1]. */\nexport async function posthogHash(key: string, distinctId: string, salt = ''): Promise<number> {\n const hex = await sha1Hex(`${key}.${distinctId}${salt}`)\n return parseInt(hex.slice(0, 15), 16) / LONG_SCALE\n}\n\n/** In the rollout when the bucket is at or below the percentage — PostHog's `>` check, inverted. */\nexport async function inPosthogRollout(key: string, distinctId: string, rolloutPercentage: number): Promise<boolean> {\n return !((await posthogHash(key, distinctId)) > rolloutPercentage / 100)\n}\n\n/** PostHog's variant for a bucketed visitor: the `[min, max)` range its 'variant' hash falls in. */\nexport async function posthogVariant(\n key: string,\n distinctId: string,\n variants: ReadonlyArray<{ key: string; rollout_percentage: number }>,\n): Promise<string | undefined> {\n const hash = await posthogHash(key, distinctId, 'variant')\n let min = 0\n for (const variant of variants) {\n const max = min + variant.rollout_percentage / 100\n if (hash >= min && hash < max) return variant.key\n min = max\n }\n return undefined\n}\n\n/** The split as PostHog's variant list: declared order, even by default (remainder to the first). */\nexport function experimentVariantTable(experiment: StorefrontExperiment): Array<{ key: string; rollout_percentage: number }> {\n const variants = experiment.variants\n if (experiment.split) return variants.map((key) => ({ key, rollout_percentage: experiment.split![key] ?? 0 }))\n const share = Math.floor(100 / variants.length)\n return variants.map((key, i) => ({ key, rollout_percentage: share + (i === 0 ? 100 - share * variants.length : 0) }))\n}\n\n/** Experiments that assign anyone. */\nexport function runningExperiments(experiments: Record<string, StorefrontExperiment> | undefined): Record<string, StorefrontExperiment> {\n return Object.fromEntries(Object.entries(experiments ?? {}).filter(([, e]) => e.status === 'running'))\n}\n\n/**\n * This visitor's variants, computed locally. Only running experiments the\n * visitor's bucket falls inside the rollout of appear in `flags`.\n */\nexport async function assignExperiments(input: {\n experiments: Record<string, StorefrontExperiment> | undefined\n distinctId: string\n}): Promise<ExperimentAssignments> {\n const flags: Record<string, ExperimentAssignment> = {}\n for (const [key, experiment] of Object.entries(runningExperiments(input.experiments))) {\n if (!(await inPosthogRollout(key, input.distinctId, experiment.rollout ?? 100))) continue\n const variant = await posthogVariant(key, input.distinctId, experimentVariantTable(experiment))\n if (variant && experiment.variants.includes(variant)) flags[key] = { variant }\n }\n return { distinctId: input.distinctId, flags }\n}\n\n/** The variant of `key`, control when unassigned. */\nexport function variantOf(assignments: ExperimentAssignments | null | undefined, key: string): string {\n return assignments?.flags[key]?.variant ?? CONTROL\n}\n\n/**\n * The part of the edge cache key that depends on the visitor: one entry per\n * combination of variants, in a fixed order. Control-only visitors (and every\n * crawler) share the plain key with the page as it was before any experiment.\n */\nexport function experimentCacheSuffix(assignments: ExperimentAssignments, keys: readonly string[]): string {\n return [...keys]\n .sort()\n .map((key) => [key, variantOf(assignments, key)] as const)\n .filter(([, variant]) => variant !== CONTROL)\n .map(([key, variant]) => `${key}:${variant}`)\n .join(',')\n}\n\n/** The assignment as a header value (URI-encoded JSON: payloads may carry any text). */\nexport function encodeExperimentHeader(assignments: ExperimentAssignments): string {\n return encodeURIComponent(JSON.stringify(assignments))\n}\n\n/** The renderer's side: never throws, garbage reads as no assignment. */\nexport function decodeExperimentHeader(value: string | null | undefined): ExperimentAssignments | null {\n if (!value) return null\n try {\n const parsed = JSON.parse(decodeURIComponent(value)) as Partial<ExperimentAssignments>\n if (!parsed || typeof parsed !== 'object' || typeof parsed.flags !== 'object' || parsed.flags === null) return null\n const flags: Record<string, ExperimentAssignment> = {}\n for (const [key, a] of Object.entries(parsed.flags)) {\n if (a && typeof a === 'object' && typeof (a as ExperimentAssignment).variant === 'string') {\n flags[key] = a as ExperimentAssignment\n }\n }\n return {\n ...(typeof parsed.distinctId === 'string' && parsed.distinctId ? { distinctId: parsed.distinctId } : {}),\n flags,\n }\n } catch {\n return null\n }\n}\n\n"]}
@@ -1180,5 +1180,5 @@ function menuDataNeeds() {
1180
1180
  }
1181
1181
 
1182
1182
  export { BLOCK_STRUCTURAL_KEYS, BlockDataError, CATALOG_BODY_BLOCK, Link, MENU_DATA_NEEDS, MESSAGES, PRODUCT_BODY_BLOCK, PageDataScope, StorefrontConfigProvider, StorefrontRouterProvider, blockInstanceId, checkPageBlocks, collectDataNeeds, contentPagePath, currentStaticRenderPass, defaultPageBlocks, getStorefrontComponents, isKnownPath, isNestedBlockRef, isPublicPath, matchContentPage, matchPath, menuDataNeeds, menuJsonLd, menuSeo, mergePageTheme, navigateTo, normalizeLanguage, pageSeo, pageThemeSelector, primaryImageUrl, productJsonLd, productSeo, resolveConfig, resolveDataParams, resolvePageData, resolvePageDataNeed, resolveStorefrontRoute, routePathParams, shellRouterAdapter, storefrontPaths, toBlockNodes, translate, useBlockData, useHashPath, useLoader, useNavigate, useRoutePath, useRouterAdapter, useScrollToTopOnNavigate, useStorefrontConfig, useStorefrontConfigOptional, withStaticRenderPass };
1183
- //# sourceMappingURL=chunk-UJHCVRK3.js.map
1184
- //# sourceMappingURL=chunk-UJHCVRK3.js.map
1183
+ //# sourceMappingURL=chunk-7N5HKQBM.js.map
1184
+ //# sourceMappingURL=chunk-7N5HKQBM.js.map