@pack/react 4.4.0 → 4.6.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/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/pack/consent.d.ts +25 -0
- package/dist/pack/consent.d.ts.map +1 -0
- package/dist/pack/consent.js +171 -0
- package/dist/pack/pack-context.d.ts +2 -10
- package/dist/pack/pack-context.d.ts.map +1 -1
- package/dist/pack/pack-context.js +4 -2
- package/dist/pack/pack-debug.d.ts +1 -0
- package/dist/pack/pack-debug.d.ts.map +1 -1
- package/dist/pack/pack-debug.js +45 -9
- package/dist/pack/preview-toolbar.d.ts +47 -0
- package/dist/pack/preview-toolbar.d.ts.map +1 -0
- package/dist/pack/preview-toolbar.js +730 -0
- package/dist/use-customizer-shell.d.ts.map +1 -1
- package/dist/use-customizer-shell.js +20 -9
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/dist/pack/preview-toast.d.ts +0 -20
- package/dist/pack/preview-toast.d.ts.map +0 -1
- package/dist/pack/preview-toast.js +0 -140
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { useOverlayScript } from "./use-overlay-script";
|
|
|
7
7
|
import { usePlaybookCart } from "./use-playbook-cart";
|
|
8
8
|
import { registerSection } from "./register-section";
|
|
9
9
|
import { registerStorefrontSettingsSchema } from "./register-storefront-settings-schema";
|
|
10
|
-
|
|
10
|
+
import { setPackConsent } from "./pack/consent";
|
|
11
|
+
export { PackProvider, PreviewProvider, RenderSection, RenderSections, registerSection, registerStorefrontSettingsSchema, setPackConsent, useLocale, useOverlayScript, usePackContext, usePlaybookCart, useSections, useSiteSettings, };
|
|
11
12
|
export type { PlaybookCartAdd, PlaybookCartInput } from "./use-playbook-cart";
|
|
12
13
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,cAAc,EACd,WAAW,EACZ,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,gCAAgC,EAAE,MAAM,uCAAuC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,cAAc,EACd,WAAW,EACZ,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,gCAAgC,EAAE,MAAM,uCAAuC,CAAC;AACzF,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,EACL,YAAY,EACZ,eAAe,EACf,aAAa,EACb,cAAc,EACd,eAAe,EACf,gCAAgC,EAChC,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,WAAW,EACX,eAAe,GAChB,CAAC;AAEF,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -7,4 +7,5 @@ import { useOverlayScript } from "./use-overlay-script";
|
|
|
7
7
|
import { usePlaybookCart } from "./use-playbook-cart";
|
|
8
8
|
import { registerSection } from "./register-section";
|
|
9
9
|
import { registerStorefrontSettingsSchema } from "./register-storefront-settings-schema";
|
|
10
|
-
|
|
10
|
+
import { setPackConsent } from "./pack/consent";
|
|
11
|
+
export { PackProvider, PreviewProvider, RenderSection, RenderSections, registerSection, registerStorefrontSettingsSchema, setPackConsent, useLocale, useOverlayScript, usePackContext, usePlaybookCart, useSections, useSiteSettings, };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
declare const PURPOSES: readonly ["analytics", "marketing", "preferences", "saleOfData"];
|
|
2
|
+
export type ConsentPurpose = (typeof PURPOSES)[number];
|
|
3
|
+
/** A consent update, per purpose. Omitted purposes keep their current state. */
|
|
4
|
+
export type PackConsentUpdate = Partial<Record<ConsentPurpose, boolean>>;
|
|
5
|
+
export declare const UNSUPPORTED_RETRY_MS: number;
|
|
6
|
+
/**
|
|
7
|
+
* Record the visitor's consent with Pack, for themes whose banner is not
|
|
8
|
+
* Shopify's (OneTrust, Cookiebot, ...). The server sets
|
|
9
|
+
* `__pack_user_consent`; purposes that already match are not re-sent.
|
|
10
|
+
*
|
|
11
|
+
* Stops for 30 minutes, then retries, once the answer can't be Pack's
|
|
12
|
+
* endpoint: a 404 or 405, a redirect, or a 2xx that isn't JSON. A tab left open
|
|
13
|
+
* across an upgrade to `@pack/hydrogen` 4.0 records again after the retry.
|
|
14
|
+
*/
|
|
15
|
+
export declare function setPackConsent(update: PackConsentUpdate): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Forward the visitor's answer to Shopify's privacy banner to Pack.
|
|
18
|
+
*
|
|
19
|
+
* Reads Shopify's Customer Privacy API once it is loaded and again whenever
|
|
20
|
+
* the visitor answers the banner. An unanswered purpose is never sent, so the
|
|
21
|
+
* server keeps treating it as unknown.
|
|
22
|
+
*/
|
|
23
|
+
export declare function usePackConsentBridge(): void;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=consent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consent.d.ts","sourceRoot":"","sources":["../../src/pack/consent.ts"],"names":[],"mappings":"AAMA,QAAA,MAAM,QAAQ,kEAAmE,CAAC;AAQlF,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;AAIvD,gFAAgF;AAChF,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC;AAwCzE,eAAO,MAAM,oBAAoB,QAAiB,CAAC;AAuBnD;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqC7E;AAkCD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CA0B3C"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
// Must mirror @pack/hydrogen/src/session/consent.ts (cookie name, keys and
|
|
3
|
+
// value format) and consent-endpoint.ts (path).
|
|
4
|
+
const CONSENT_COOKIE = "__pack_user_consent";
|
|
5
|
+
const CONSENT_PATH = "/pack/consent";
|
|
6
|
+
const PURPOSES = ["analytics", "marketing", "preferences", "saleOfData"];
|
|
7
|
+
const COOKIE_KEYS = {
|
|
8
|
+
analytics: "a",
|
|
9
|
+
marketing: "m",
|
|
10
|
+
preferences: "p",
|
|
11
|
+
saleOfData: "s",
|
|
12
|
+
};
|
|
13
|
+
function readConsentCookie() {
|
|
14
|
+
const consent = {
|
|
15
|
+
analytics: "unknown",
|
|
16
|
+
marketing: "unknown",
|
|
17
|
+
preferences: "unknown",
|
|
18
|
+
saleOfData: "unknown",
|
|
19
|
+
};
|
|
20
|
+
let raw;
|
|
21
|
+
try {
|
|
22
|
+
const entry = document.cookie
|
|
23
|
+
.split("; ")
|
|
24
|
+
.find((part) => part.startsWith(`${CONSENT_COOKIE}=`));
|
|
25
|
+
raw = entry && decodeURIComponent(entry.slice(CONSENT_COOKIE.length + 1));
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return consent;
|
|
29
|
+
}
|
|
30
|
+
if (!raw)
|
|
31
|
+
return consent;
|
|
32
|
+
if (raw === "true" || raw === "false") {
|
|
33
|
+
consent.analytics = raw === "true" ? "granted" : "denied";
|
|
34
|
+
return consent;
|
|
35
|
+
}
|
|
36
|
+
const params = new URLSearchParams(raw);
|
|
37
|
+
for (const purpose of PURPOSES) {
|
|
38
|
+
const value = params.get(COOKIE_KEYS[purpose]);
|
|
39
|
+
if (value === "1")
|
|
40
|
+
consent[purpose] = "granted";
|
|
41
|
+
else if (value === "0")
|
|
42
|
+
consent[purpose] = "denied";
|
|
43
|
+
}
|
|
44
|
+
return consent;
|
|
45
|
+
}
|
|
46
|
+
// A server without the endpoint (@pack/hydrogen before 4.0, or another
|
|
47
|
+
// framework) never writes the cookie, so without this every answer and every
|
|
48
|
+
// page load would post again. Retried after a while so a tab left open across
|
|
49
|
+
// an upgrade to 4.0 starts recording again.
|
|
50
|
+
const UNSUPPORTED_KEY = "__pack_consent_unsupported";
|
|
51
|
+
export const UNSUPPORTED_RETRY_MS = 30 * 60 * 1000;
|
|
52
|
+
let unsupportedAtInMemory;
|
|
53
|
+
function isEndpointUnsupported() {
|
|
54
|
+
let since = unsupportedAtInMemory;
|
|
55
|
+
if (since === undefined) {
|
|
56
|
+
try {
|
|
57
|
+
const stored = Number(sessionStorage.getItem(UNSUPPORTED_KEY));
|
|
58
|
+
if (stored > 0)
|
|
59
|
+
since = stored;
|
|
60
|
+
}
|
|
61
|
+
catch { }
|
|
62
|
+
}
|
|
63
|
+
return since !== undefined && Date.now() - since < UNSUPPORTED_RETRY_MS;
|
|
64
|
+
}
|
|
65
|
+
function markEndpointUnsupported() {
|
|
66
|
+
const now = Date.now();
|
|
67
|
+
try {
|
|
68
|
+
sessionStorage.setItem(UNSUPPORTED_KEY, String(now));
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
unsupportedAtInMemory = now;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Record the visitor's consent with Pack, for themes whose banner is not
|
|
76
|
+
* Shopify's (OneTrust, Cookiebot, ...). The server sets
|
|
77
|
+
* `__pack_user_consent`; purposes that already match are not re-sent.
|
|
78
|
+
*
|
|
79
|
+
* Stops for 30 minutes, then retries, once the answer can't be Pack's
|
|
80
|
+
* endpoint: a 404 or 405, a redirect, or a 2xx that isn't JSON. A tab left open
|
|
81
|
+
* across an upgrade to `@pack/hydrogen` 4.0 records again after the retry.
|
|
82
|
+
*/
|
|
83
|
+
export async function setPackConsent(update) {
|
|
84
|
+
if (isEndpointUnsupported())
|
|
85
|
+
return;
|
|
86
|
+
const current = readConsentCookie();
|
|
87
|
+
const changed = {};
|
|
88
|
+
for (const purpose of PURPOSES) {
|
|
89
|
+
const value = update[purpose];
|
|
90
|
+
if (typeof value !== "boolean")
|
|
91
|
+
continue;
|
|
92
|
+
if (current[purpose] !== (value ? "granted" : "denied")) {
|
|
93
|
+
changed[purpose] = value;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (!Object.keys(changed).length)
|
|
97
|
+
return;
|
|
98
|
+
try {
|
|
99
|
+
const response = await fetch(CONSENT_PATH, {
|
|
100
|
+
method: "POST",
|
|
101
|
+
headers: { "Content-Type": "application/json" },
|
|
102
|
+
body: JSON.stringify(changed),
|
|
103
|
+
credentials: "same-origin",
|
|
104
|
+
keepalive: true,
|
|
105
|
+
});
|
|
106
|
+
const isPackEndpoint = response.status !== 404 &&
|
|
107
|
+
response.status !== 405 &&
|
|
108
|
+
!response.redirected &&
|
|
109
|
+
(!response.ok ||
|
|
110
|
+
!!response.headers
|
|
111
|
+
.get("Content-Type")
|
|
112
|
+
?.toLowerCase()
|
|
113
|
+
.includes("application/json"));
|
|
114
|
+
if (!isPackEndpoint)
|
|
115
|
+
markEndpointUnsupported();
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
console.error("Error hit /pack/consent: ", error?.message);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function fromShopifyValue(value) {
|
|
122
|
+
if (value === "yes")
|
|
123
|
+
return true;
|
|
124
|
+
if (value === "no")
|
|
125
|
+
return false;
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
function readShopifyConsent() {
|
|
129
|
+
const customerPrivacy = window.Shopify?.customerPrivacy;
|
|
130
|
+
const consent = customerPrivacy?.currentVisitorConsent?.();
|
|
131
|
+
if (!consent)
|
|
132
|
+
return undefined;
|
|
133
|
+
return {
|
|
134
|
+
analytics: fromShopifyValue(consent.analytics),
|
|
135
|
+
marketing: fromShopifyValue(consent.marketing),
|
|
136
|
+
preferences: fromShopifyValue(consent.preferences),
|
|
137
|
+
saleOfData: fromShopifyValue(consent.sale_of_data),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Forward the visitor's answer to Shopify's privacy banner to Pack.
|
|
142
|
+
*
|
|
143
|
+
* Reads Shopify's Customer Privacy API once it is loaded and again whenever
|
|
144
|
+
* the visitor answers the banner. An unanswered purpose is never sent, so the
|
|
145
|
+
* server keeps treating it as unknown.
|
|
146
|
+
*/
|
|
147
|
+
export function usePackConsentBridge() {
|
|
148
|
+
useEffect(() => {
|
|
149
|
+
const syncFromApi = () => {
|
|
150
|
+
const consent = readShopifyConsent();
|
|
151
|
+
if (consent)
|
|
152
|
+
setPackConsent(consent);
|
|
153
|
+
};
|
|
154
|
+
const onCollected = (event) => {
|
|
155
|
+
const detail = event.detail || {};
|
|
156
|
+
setPackConsent({
|
|
157
|
+
analytics: detail.analyticsAllowed,
|
|
158
|
+
marketing: detail.marketingAllowed,
|
|
159
|
+
preferences: detail.preferencesAllowed,
|
|
160
|
+
saleOfData: detail.saleOfDataAllowed,
|
|
161
|
+
});
|
|
162
|
+
};
|
|
163
|
+
document.addEventListener("visitorConsentCollected", onCollected);
|
|
164
|
+
document.addEventListener("consentTrackingApiLoaded", syncFromApi);
|
|
165
|
+
syncFromApi();
|
|
166
|
+
return () => {
|
|
167
|
+
document.removeEventListener("visitorConsentCollected", onCollected);
|
|
168
|
+
document.removeEventListener("consentTrackingApiLoaded", syncFromApi);
|
|
169
|
+
};
|
|
170
|
+
}, []);
|
|
171
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { type ReactNode } from "react";
|
|
2
|
+
import { type PreviewContext } from "./preview-toolbar";
|
|
2
3
|
import "./pack-debug";
|
|
3
4
|
type PackContextValue = {
|
|
4
5
|
isPreview: boolean;
|
|
@@ -7,16 +8,7 @@ type PackContextValue = {
|
|
|
7
8
|
src?: string;
|
|
8
9
|
version?: string;
|
|
9
10
|
};
|
|
10
|
-
previewContext?:
|
|
11
|
-
linkName?: string;
|
|
12
|
-
releaseId?: string;
|
|
13
|
-
releaseName?: string;
|
|
14
|
-
locale?: string;
|
|
15
|
-
pageDraft?: string;
|
|
16
|
-
siteSettingsDraft?: string;
|
|
17
|
-
testHandle?: string;
|
|
18
|
-
testVariantHandle?: string;
|
|
19
|
-
};
|
|
11
|
+
previewContext?: PreviewContext;
|
|
20
12
|
[key: string]: any;
|
|
21
13
|
};
|
|
22
14
|
siteSettings: any;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pack-context.d.ts","sourceRoot":"","sources":["../../src/pack/pack-context.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAKZ,KAAK,SAAS,EAEf,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"pack-context.d.ts","sourceRoot":"","sources":["../../src/pack/pack-context.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAKZ,KAAK,SAAS,EAEf,MAAM,OAAO,CAAC;AAGf,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxE,OAAO,cAAc,CAAC;AAEtB,KAAK,gBAAgB,GAAG;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE;QACf,OAAO,CAAC,EAAE;YACR,GAAG,CAAC,EAAE,MAAM,CAAC;YACb,OAAO,CAAC,EAAE,MAAM,CAAC;SAClB,CAAC;QACF,cAAc,CAAC,EAAE,cAAc,CAAC;QAChC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,CAAC;IACF,YAAY,EAAE,GAAG,CAAC;IAClB,eAAe,EAAE,CAAC,YAAY,EAAE,GAAG,KAAK,IAAI,CAAC;IAC7C,WAAW,EAAE,GAAG,CAAC;IACjB,cAAc,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,CAAC;IACvC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;KACjB,GAAG,IAAI,CAAC;IACT,SAAS,EAAE,CACT,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;KACjB,GAAG,IAAI,KACL,IAAI,CAAC;CACX,CAAC;AAEF,eAAO,MAAM,WAAW,iCAUtB,CAAC;AAEH,eAAO,MAAM,cAAc,wBAAgC,CAAC;AAE5D,UAAU,gBAAgB;IACxB,QAAQ,EAAE,SAAS,CAAC;IACpB,YAAY,EAAE,GAAG,CAAC;IAClB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,cAAc,CAAC,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;IACpD,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE;QACP,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;KACjB,GAAG,IAAI,CAAC;IACT,WAAW,CAAC,EAAE,GAAG,CAAC;CACnB;AAUD,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,oBAA4B,EAC5B,YAAY,EAAE,yBAAyB,EACvC,cAAc,EACd,kBAAuB,EACvB,MAAM,EAAE,aAAoB,GAC7B,EAAE,gBAAgB,qBAwDlB;AAED,eAAO,MAAM,eAAe,qBAAe,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { createContext, useContext, useState, useMemo, useEffect, } from "react";
|
|
2
2
|
import { usePackTrack } from "./pack-analytics";
|
|
3
|
-
import {
|
|
3
|
+
import { usePackConsentBridge } from "./consent";
|
|
4
|
+
import { PreviewToolbar } from "./preview-toolbar";
|
|
4
5
|
import { useOverlayScript } from "../use-overlay-script";
|
|
5
6
|
import { useCustomizerShell } from "../use-customizer-shell";
|
|
6
7
|
import "./pack-debug";
|
|
@@ -53,9 +54,10 @@ export function PackProvider({ children, isPreviewModeEnabled = false, siteSetti
|
|
|
53
54
|
setSiteSettings(previewStorefrontSettings);
|
|
54
55
|
}, [previewStorefrontSettings]);
|
|
55
56
|
usePackTrack();
|
|
57
|
+
usePackConsentBridge();
|
|
56
58
|
return (React.createElement(PackContext.Provider, { value: value },
|
|
57
59
|
React.createElement(CustomizerShell, null),
|
|
58
60
|
children,
|
|
59
|
-
React.createElement(
|
|
61
|
+
React.createElement(PreviewToolbar, { isPreviewModeEnabled: !!isPreviewModeEnabled, environment: value.contentEnvironment, previewContext: customizerMeta?.previewContext })));
|
|
60
62
|
}
|
|
61
63
|
export const PreviewProvider = PackProvider;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pack-debug.d.ts","sourceRoot":"","sources":["../../src/pack/pack-debug.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pack-debug.d.ts","sourceRoot":"","sources":["../../src/pack/pack-debug.ts"],"names":[],"mappings":"AA2BA,UAAU,kBAAkB;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,UAAU,4BAA4B;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,UAAU,gBAAgB;IACxB,WAAW,IAAI,kBAAkB,GAAG,IAAI,CAAC;IACzC,YAAY,IAAI,kBAAkB,EAAE,CAAC;IACrC,qBAAqB,IAAI,4BAA4B,GAAG,IAAI,CAAC;CAC9D;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,SAAS,CAAC,EAAE,gBAAgB,CAAC;KAC9B;CACF;AAwKD,OAAO,EAAE,CAAC"}
|
package/dist/pack/pack-debug.js
CHANGED
|
@@ -57,18 +57,53 @@ function parseTestSessionCookie(cookieHeader) {
|
|
|
57
57
|
}
|
|
58
58
|
return null;
|
|
59
59
|
}
|
|
60
|
-
function
|
|
61
|
-
const
|
|
62
|
-
const
|
|
63
|
-
const variant = payload?.test_data?.testVariant?.handle;
|
|
60
|
+
function toStorefrontTestInfo(assignment, expiresAt) {
|
|
61
|
+
const test = assignment?.handle;
|
|
62
|
+
const variant = assignment?.testVariant?.handle;
|
|
64
63
|
if (!test || !variant) {
|
|
65
64
|
return null;
|
|
66
65
|
}
|
|
67
|
-
return {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
return { test, variant, expiresAt };
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Every test the visitor is currently bucketed into, oldest assignment first.
|
|
70
|
+
*
|
|
71
|
+
* Read from the session cookie, so this is what the visitor is *assigned* to —
|
|
72
|
+
* not which of those tests is serving the current page. Which assignment supplies
|
|
73
|
+
* content is decided per request on the server from the page's targeting rules
|
|
74
|
+
* and is never persisted; check the CMS request log or `useAbTest()` for that.
|
|
75
|
+
*
|
|
76
|
+
* Falls back to the pre-4.0 single-slot payload for sessions written by an older
|
|
77
|
+
* SDK that have not been migrated yet.
|
|
78
|
+
*/
|
|
79
|
+
function getStorefrontTestInfos() {
|
|
80
|
+
const payload = parseTestSessionCookie(document.cookie || "");
|
|
81
|
+
const expiresAt = payload?.test_expire_at || null;
|
|
82
|
+
const assignments = payload?.test_data_map;
|
|
83
|
+
if (assignments && typeof assignments === "object") {
|
|
84
|
+
// Ordered the way the SDK picks its primary: oldest first, ties broken on
|
|
85
|
+
// test id. Every assignment made in one request shares a millisecond, so the
|
|
86
|
+
// tie-break decides the common case — without it `getTestInfo()` can name a
|
|
87
|
+
// different test than `pack.abTest` does. The map is keyed by test id, so
|
|
88
|
+
// the key stands in when a hand-edited entry has none.
|
|
89
|
+
return Object.entries(assignments)
|
|
90
|
+
.sort(([idA, a], [idB, b]) => (a?.assignedAt ?? 0) - (b?.assignedAt ?? 0) ||
|
|
91
|
+
(a?.id ?? idA).localeCompare(b?.id ?? idB))
|
|
92
|
+
.map(([, assignment]) => toStorefrontTestInfo(assignment, expiresAt))
|
|
93
|
+
.filter((info) => info !== null);
|
|
94
|
+
}
|
|
95
|
+
const legacy = toStorefrontTestInfo(payload?.test_data, expiresAt);
|
|
96
|
+
return legacy ? [legacy] : [];
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The oldest assignment on the session.
|
|
100
|
+
*
|
|
101
|
+
* Deliberately not "the test serving this page": a visitor can be assigned to
|
|
102
|
+
* several tests at once, and the one supplying content varies by page. Kept for
|
|
103
|
+
* back-compat with the single-test debug surface — prefer `getTestInfos()`.
|
|
104
|
+
*/
|
|
105
|
+
function getStorefrontTestInfo() {
|
|
106
|
+
return getStorefrontTestInfos()[0] || null;
|
|
72
107
|
}
|
|
73
108
|
function getStorefrontTestRulesCacheInfo() {
|
|
74
109
|
const payload = parseTestSessionCookie(document.cookie || "");
|
|
@@ -98,6 +133,7 @@ function initializePackDebugHelpers() {
|
|
|
98
133
|
window.packDebug = {
|
|
99
134
|
...window.packDebug,
|
|
100
135
|
getTestInfo: getStorefrontTestInfo,
|
|
136
|
+
getTestInfos: getStorefrontTestInfos,
|
|
101
137
|
getTestRulesCacheInfo: getStorefrontTestRulesCacheInfo,
|
|
102
138
|
};
|
|
103
139
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type CSSProperties } from "react";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
export interface PreviewContext {
|
|
4
|
+
linkName?: string;
|
|
5
|
+
releaseId?: string;
|
|
6
|
+
releaseName?: string;
|
|
7
|
+
locale?: string;
|
|
8
|
+
pageDraft?: string;
|
|
9
|
+
siteSettingsDraft?: string;
|
|
10
|
+
testHandle?: string;
|
|
11
|
+
testVariantHandle?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface PreviewToolbarProps {
|
|
14
|
+
isPreviewModeEnabled: boolean;
|
|
15
|
+
environment?: string;
|
|
16
|
+
previewContext?: PreviewContext;
|
|
17
|
+
}
|
|
18
|
+
export type PreviewDetail = {
|
|
19
|
+
label: string;
|
|
20
|
+
value: string;
|
|
21
|
+
};
|
|
22
|
+
type ToolbarEdge = "top" | "right" | "bottom" | "left";
|
|
23
|
+
type ToolbarRect = {
|
|
24
|
+
top: number;
|
|
25
|
+
left: number;
|
|
26
|
+
right: number;
|
|
27
|
+
bottom: number;
|
|
28
|
+
};
|
|
29
|
+
type ToolbarViewport = {
|
|
30
|
+
width: number;
|
|
31
|
+
height: number;
|
|
32
|
+
};
|
|
33
|
+
export declare function buildPreviewDetails(environment?: string, previewContext?: PreviewContext): PreviewDetail[];
|
|
34
|
+
export declare function buildPreviewSummary(environment?: string, previewContext?: PreviewContext): string;
|
|
35
|
+
export declare function getConstrainedPillPosition(position: {
|
|
36
|
+
left: number;
|
|
37
|
+
top: number;
|
|
38
|
+
}, viewport: ToolbarViewport): CSSProperties;
|
|
39
|
+
export declare function getPanelPosition(edge: ToolbarEdge, pillRect: ToolbarRect | null, viewport: ToolbarViewport): CSSProperties;
|
|
40
|
+
/**
|
|
41
|
+
* Thin gate so production storefront pages (preview off) mount no listeners,
|
|
42
|
+
* timers, storage reads, or effects. The top-window check is a hydration-safe
|
|
43
|
+
* client-only snapshot; it renders nothing on the server and during hydration.
|
|
44
|
+
*/
|
|
45
|
+
export declare const PreviewToolbar: ({ isPreviewModeEnabled, environment, previewContext, }: PreviewToolbarProps) => React.JSX.Element | null;
|
|
46
|
+
export {};
|
|
47
|
+
//# sourceMappingURL=preview-toolbar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-toolbar.d.ts","sourceRoot":"","sources":["../../src/pack/preview-toolbar.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAUnB,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,oBAAoB,EAAE,OAAO,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAUF,KAAK,WAAW,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEvD,KAAK,WAAW,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAChF,KAAK,eAAe,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AA4CzD,wBAAgB,mBAAmB,CACjC,WAAW,CAAC,EAAE,MAAM,EACpB,cAAc,CAAC,EAAE,cAAc,GAC9B,aAAa,EAAE,CA2CjB;AAED,wBAAgB,mBAAmB,CACjC,WAAW,CAAC,EAAE,MAAM,EACpB,cAAc,CAAC,EAAE,cAAc,UAqBhC;AAsID,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EACvC,QAAQ,EAAE,eAAe,GACxB,aAAa,CAOf;AA0DD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,WAAW,EACjB,QAAQ,EAAE,WAAW,GAAG,IAAI,EAC5B,QAAQ,EAAE,eAAe,GACxB,aAAa,CA6Cf;AAorBD;;;;GAIG;AACH,eAAO,MAAM,cAAc,2DAIxB,mBAAmB,6BAerB,CAAC"}
|