@wix/web5-core 1.63.44 → 1.63.46

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 (49) hide show
  1. package/dist/cjs/client/applyThemeOverrides.js +47 -30
  2. package/dist/cjs/client/applyThemeOverrides.js.map +1 -1
  3. package/dist/cjs/index.js +12 -13
  4. package/dist/cjs/index.js.map +1 -1
  5. package/dist/cjs/privacy/consentGate.js +32 -178
  6. package/dist/cjs/privacy/consentGate.js.map +1 -1
  7. package/dist/cjs/privacy/index.js +2 -9
  8. package/dist/cjs/privacy/index.js.map +1 -1
  9. package/dist/cjs/styles/base-tokens.css +19 -0
  10. package/dist/cjs/styles/tailwind-theme.css +12 -0
  11. package/dist/cjs/theme/chromeTokens.js +60 -0
  12. package/dist/cjs/theme/chromeTokens.js.map +1 -0
  13. package/dist/cjs/theme/themeScheme.js +64 -50
  14. package/dist/cjs/theme/themeScheme.js.map +1 -1
  15. package/dist/cjs/utils/analyticsEvents.js +16 -37
  16. package/dist/cjs/utils/analyticsEvents.js.map +1 -1
  17. package/dist/esm/client/applyThemeOverrides.js +55 -30
  18. package/dist/esm/client/applyThemeOverrides.js.map +1 -1
  19. package/dist/esm/index.js +5 -4
  20. package/dist/esm/index.js.map +1 -1
  21. package/dist/esm/privacy/consentGate.js +30 -173
  22. package/dist/esm/privacy/consentGate.js.map +1 -1
  23. package/dist/esm/privacy/index.js +1 -1
  24. package/dist/esm/privacy/index.js.map +1 -1
  25. package/dist/esm/styles/base-tokens.css +19 -0
  26. package/dist/esm/styles/tailwind-theme.css +12 -0
  27. package/dist/esm/theme/chromeTokens.js +53 -0
  28. package/dist/esm/theme/chromeTokens.js.map +1 -0
  29. package/dist/esm/theme/themeScheme.js +70 -51
  30. package/dist/esm/theme/themeScheme.js.map +1 -1
  31. package/dist/esm/utils/analyticsEvents.js +16 -36
  32. package/dist/esm/utils/analyticsEvents.js.map +1 -1
  33. package/dist/types/client/applyThemeOverrides.d.ts +11 -0
  34. package/dist/types/client/applyThemeOverrides.d.ts.map +1 -1
  35. package/dist/types/index.d.ts +6 -5
  36. package/dist/types/index.d.ts.map +1 -1
  37. package/dist/types/privacy/consentGate.d.ts +28 -61
  38. package/dist/types/privacy/consentGate.d.ts.map +1 -1
  39. package/dist/types/privacy/index.d.ts +1 -1
  40. package/dist/types/privacy/index.d.ts.map +1 -1
  41. package/dist/types/theme/chromeTokens.d.ts +46 -0
  42. package/dist/types/theme/chromeTokens.d.ts.map +1 -0
  43. package/dist/types/theme/themeScheme.d.ts +30 -12
  44. package/dist/types/theme/themeScheme.d.ts.map +1 -1
  45. package/dist/types/utils/analyticsEvents.d.ts +0 -10
  46. package/dist/types/utils/analyticsEvents.d.ts.map +1 -1
  47. package/package.json +2 -2
  48. package/src/styles/base-tokens.css +19 -0
  49. package/src/styles/tailwind-theme.css +12 -0
@@ -1,93 +1,65 @@
1
1
  "use strict";
2
2
 
3
3
  exports.__esModule = true;
4
- exports.unlockOnUserAction = exports.transmit = exports.subscribeToConsent = exports.setConsentBufferLimit = exports.resetConsentGateForTests = exports.mayTransmit = exports.mayPersistIdentity = exports.isUserEngaged = exports.installConsentProvider = exports.getInstalledProviderName = exports.getGateView = exports.getConsentSnapshot = exports.getConsentGateStats = void 0;
4
+ exports.unlockOnUserAction = exports.subscribeToConsent = exports.resetConsentGateForTests = exports.mayPersistToken = exports.installConsentProvider = exports.getConsentSnapshot = void 0;
5
5
  var _types = require("./types");
6
6
  /**
7
- * The consent gate — DL #218.
7
+ * The consent gate — DL #218 (revised).
8
8
  *
9
- * Every BI, telemetry and analytics emitter in web5 goes through `transmit()`
10
- * instead of calling its transport directly. The gate exists because the
11
- * consent signal resolves *after* the events that need it: Shopify's consent
12
- * API is not on the page by default and has to be requested, and the fedops
13
- * app-load pair fires inside that window. A boolean checked at each call site
14
- * can only ever drop an event that is already in flight; the gate can hold it.
9
+ * Legal cleared analytics/BI transmission to need no consent gate, so the old
10
+ * `transmit()` + buffer machinery is gone. What analytics emitters used to route
11
+ * through the gate now goes straight to the wire.
15
12
  *
16
- * Two independent unlocks, and they do not compose as a plain "either/or":
13
+ * Analytics AND performance telemetry both go straight to the wire now, so there
14
+ * is nothing left to "transmit"-gate. What remains is the consent SIGNAL —
15
+ * snapshot, engagement, provider — behind a single predicate:
17
16
  *
18
- * | consent | engaged | result |
19
- * |-----------|---------|---------------------------------|
20
- * | granted | either | transmit |
21
- * | unknown | no | hold in the buffer |
22
- * | unknown | yes | transmit, and flush what's held |
23
- * | denied | yes | still nothing |
17
+ * - `mayPersistToken()` whether the visitor's OAuth token may be written to
18
+ * localStorage. Persisting the token persists a cross-visit visitor identity
19
+ * (its refresh token), which is the one thing consent still governs. Truth
20
+ * table: granted → yes; denied → never; unknown only once the visitor
21
+ * engaged.
24
22
  *
25
- * Denied outranks engaged. A visitor who refused analytics in the banner does
26
- * not re-enable tracking by typing a question.
23
+ * Engagement (`unlockOnUserAction`, fired when the visitor submits a prompt)
24
+ * resolves the `unknown` case typing a question is a reason to remember this
25
+ * visitor for the session — but it never overrides a `denied`.
27
26
  */
28
27
 
29
- /** Held events are dropped past this many — a runaway emitter must not become a leak. */
30
- const DEFAULT_BUFFER_LIMIT = 50;
31
-
32
- /**
33
- * One prefix for the whole consent trail, so `[w5-consent]` in the console
34
- * filter shows the full story: which CMP was found, what it answered, and for
35
- * every event whether it was sent, held, dropped or replayed.
36
- */
37
28
  const LOG_PREFIX = '[w5-consent]';
38
29
  const log = (...args) => {
39
30
  try {
40
31
  console.debug(LOG_PREFIX, ...args);
41
32
  } catch {
42
- // A console that throws must never break a send.
33
+ // A console that throws must never break anything.
43
34
  }
44
35
  };
45
36
  const describe = s => `analytics=${s.analytics} performance=${s.performance} marketing=${s.marketing}`;
46
37
  let snapshot = _types.UNKNOWN_CONSENT;
47
38
  let engaged = false;
48
- let provider = null;
49
39
  let unsubscribeProvider = null;
50
- let buffer = [];
51
- let bufferLimit = DEFAULT_BUFFER_LIMIT;
52
- let droppedFromOverflow = 0;
53
40
  const listeners = new Set();
54
-
55
- /**
56
- * Cached so `getGateView` is referentially stable between changes —
57
- * `useSyncExternalStore` re-renders forever if the snapshot is a fresh object
58
- * on every read.
59
- */
60
- let view = Object.freeze({
61
- consent: _types.UNKNOWN_CONSENT,
62
- engaged: false
63
- });
64
- const rebuildView = () => {
65
- view = Object.freeze({
66
- consent: snapshot,
67
- engaged
68
- });
69
- };
70
41
  const notify = () => {
71
42
  for (const listener of listeners) {
72
43
  try {
73
44
  listener();
74
45
  } catch {
75
- // A subscriber that throws must not stop the others, or stop a flush.
46
+ // A subscriber that throws must not stop the others.
76
47
  }
77
48
  }
78
49
  };
79
50
 
80
51
  /**
81
- * Whether an event for `purpose` may go on the wire right now.
52
+ * Whether the visitor's OAuth token may be persisted to `localStorage`.
82
53
  *
83
- * `necessary` is always allowed. For everything else: explicit consent wins in
84
- * both directions, and engagement resolves only the `unknown` case.
54
+ * Persisting the token persists a cross-visit visitor identity (the refresh
55
+ * token re-identifies the visitor on their next visit), so it answers to
56
+ * consent — the one thing that still does. Explicit consent wins in both
57
+ * directions; engagement resolves only the `unknown` case. The token still
58
+ * lives in memory for the session regardless — only the write to storage is
59
+ * gated.
85
60
  */
86
- const mayTransmit = purpose => {
87
- if (purpose === 'necessary') {
88
- return true;
89
- }
90
- const state = snapshot[purpose];
61
+ const mayPersistToken = () => {
62
+ const state = snapshot.analytics;
91
63
  if (state === 'denied') {
92
64
  return false;
93
65
  }
@@ -98,116 +70,22 @@ const mayTransmit = purpose => {
98
70
  };
99
71
 
100
72
  /**
101
- * Release everything the gate is holding that is now allowed, and drop
102
- * everything that is now refused. Anything still `unknown` stays held.
103
- *
104
- * Order is preserved among released events, but a flush necessarily emits them
105
- * later than they were raised — a held app-load event reaches the wire after
106
- * the prompt that unlocked it. Anything reading these as a timeline has to
107
- * know that.
108
- */
109
- exports.mayTransmit = mayTransmit;
110
- const settleBuffer = () => {
111
- if (buffer.length === 0) {
112
- return;
113
- }
114
- const stillHeld = [];
115
- const releasing = [];
116
- for (const held of buffer) {
117
- if (mayTransmit(held.purpose)) {
118
- releasing.push(held);
119
- } else if (snapshot[held.purpose] === 'denied') {
120
- // dropped on the floor, deliberately and permanently
121
- } else {
122
- stillHeld.push(held);
123
- }
124
- }
125
- const dropped = buffer.length - stillHeld.length - releasing.length;
126
- buffer = stillHeld;
127
- if (releasing.length || dropped) {
128
- log(`settle — releasing ${releasing.length}` + (dropped ? `, dropping ${dropped} (refused)` : '') + (stillHeld.length ? `, still holding ${stillHeld.length}` : ''));
129
- }
130
- for (const held of releasing) {
131
- try {
132
- log(` ↳ REPLAY ${held.label} (${held.purpose})`);
133
- held.send();
134
- } catch {
135
- // A failed send must not strand the rest of the flush.
136
- }
137
- }
138
- };
139
-
140
- /**
141
- * The single entry point for anything that would put a request on the wire.
142
- *
143
- * Allowed → sent now. Refused → dropped. Not yet known → held until an unlock
144
- * settles it, or discarded with the page.
73
+ * The visitor did something deliberate submitted a prompt so we may remember
74
+ * them for the session even though no CMP has answered. Unlocks the `unknown`
75
+ * case only; it cannot override a `denied`.
145
76
  */
146
- const transmit = (purpose, send, label = 'event') => {
147
- if (mayTransmit(purpose)) {
148
- log(`SEND ${label} (${purpose}) — allowed`);
149
- send();
150
- return;
151
- }
152
- if (purpose !== 'necessary' && snapshot[purpose] === 'denied') {
153
- log(`DROP ${label} (${purpose}) — visitor refused`);
154
- return;
155
- }
156
- if (buffer.length >= bufferLimit) {
157
- droppedFromOverflow += 1;
158
- log(`DROP ${label} (${purpose}) — buffer full at ${bufferLimit}, ${droppedFromOverflow} lost`);
159
- return;
160
- }
161
- buffer.push({
162
- purpose: purpose,
163
- send,
164
- label
165
- });
166
- log(`HOLD ${label} (${purpose}) — no answer yet, ${buffer.length} held`);
167
- };
168
-
169
- /**
170
- * The visitor did something deliberate — submitted a prompt — so the session
171
- * may be measured even though no CMP has answered.
172
- *
173
- * This is the unlock that keeps web5 measurable at all: on a Shopify store
174
- * with no privacy configuration the consent API never loads, consent stays
175
- * `unknown` forever, and without this every store would report nothing.
176
- *
177
- * It unlocks **transmission only**. Persistent identity stays gated on real
178
- * consent (see `mayPersistIdentity`) — typing a question is a reason to
179
- * measure the session, not a reason to persist an identifier across visits.
180
- * It also cannot override a `denied`.
181
- */
182
- exports.transmit = transmit;
77
+ exports.mayPersistToken = mayPersistToken;
183
78
  const unlockOnUserAction = () => {
184
79
  if (engaged) {
185
80
  return;
186
81
  }
187
82
  engaged = true;
188
- log(`UNLOCK — visitor submitted a prompt; ${buffer.length} held event(s) to settle`);
189
- rebuildView();
190
- settleBuffer();
83
+ log('UNLOCK — visitor submitted a prompt');
191
84
  notify();
192
85
  };
193
-
194
- /** Whether the visitor has taken the deliberate action that unlocks the session. */
195
86
  exports.unlockOnUserAction = unlockOnUserAction;
196
- const isUserEngaged = () => engaged;
197
-
198
- /**
199
- * Persistent, cross-visit storage of a visitor identifier requires real
200
- * consent — engagement is deliberately not enough.
201
- */
202
- exports.isUserEngaged = isUserEngaged;
203
- const mayPersistIdentity = () => snapshot.analytics === 'granted';
204
- exports.mayPersistIdentity = mayPersistIdentity;
205
87
  const getConsentSnapshot = () => snapshot;
206
-
207
- /** Referentially stable between changes, for `useSyncExternalStore`. */
208
88
  exports.getConsentSnapshot = getConsentSnapshot;
209
- const getGateView = () => view;
210
- exports.getGateView = getGateView;
211
89
  const subscribeToConsent = listener => {
212
90
  listeners.add(listener);
213
91
  return () => {
@@ -223,8 +101,6 @@ const applySnapshot = next => {
223
101
  snapshot = Object.freeze({
224
102
  ...next
225
103
  });
226
- rebuildView();
227
- settleBuffer();
228
104
  notify();
229
105
  };
230
106
 
@@ -236,40 +112,18 @@ const applySnapshot = next => {
236
112
  */
237
113
  const installConsentProvider = next => {
238
114
  unsubscribeProvider == null || unsubscribeProvider();
239
- provider = next;
240
115
  const initial = next.read();
241
116
  log(`provider installed: ${next.name} — reads ${describe(initial)}`);
242
117
  applySnapshot(initial);
243
118
  unsubscribeProvider = next.subscribe(applySnapshot);
244
119
  };
245
120
  exports.installConsentProvider = installConsentProvider;
246
- const getInstalledProviderName = () => {
247
- var _provider;
248
- return ((_provider = provider) == null ? void 0 : _provider.name) ?? null;
249
- };
250
- exports.getInstalledProviderName = getInstalledProviderName;
251
- const setConsentBufferLimit = limit => {
252
- bufferLimit = Math.max(0, limit);
253
- };
254
-
255
- /** Diagnostics only — how much the gate is holding, and what it had to drop. */
256
- exports.setConsentBufferLimit = setConsentBufferLimit;
257
- const getConsentGateStats = () => ({
258
- held: buffer.length,
259
- droppedFromOverflow
260
- });
261
- exports.getConsentGateStats = getConsentGateStats;
262
121
  const resetConsentGateForTests = () => {
263
122
  unsubscribeProvider == null || unsubscribeProvider();
264
123
  unsubscribeProvider = null;
265
- provider = null;
266
124
  snapshot = _types.UNKNOWN_CONSENT;
267
125
  engaged = false;
268
- buffer = [];
269
- bufferLimit = DEFAULT_BUFFER_LIMIT;
270
- droppedFromOverflow = 0;
271
126
  listeners.clear();
272
- rebuildView();
273
127
  };
274
128
  exports.resetConsentGateForTests = resetConsentGateForTests;
275
129
  //# sourceMappingURL=consentGate.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["_types","require","DEFAULT_BUFFER_LIMIT","LOG_PREFIX","log","args","console","debug","describe","s","analytics","performance","marketing","snapshot","UNKNOWN_CONSENT","engaged","provider","unsubscribeProvider","buffer","bufferLimit","droppedFromOverflow","listeners","Set","view","Object","freeze","consent","rebuildView","notify","listener","mayTransmit","purpose","state","exports","settleBuffer","length","stillHeld","releasing","held","push","dropped","label","send","transmit","unlockOnUserAction","isUserEngaged","mayPersistIdentity","getConsentSnapshot","getGateView","subscribeToConsent","add","delete","applySnapshot","next","installConsentProvider","initial","read","name","subscribe","getInstalledProviderName","_provider","setConsentBufferLimit","limit","Math","max","getConsentGateStats","resetConsentGateForTests","clear"],"sources":["../../../src/privacy/consentGate.ts"],"sourcesContent":["/**\n * The consent gate — DL #218.\n *\n * Every BI, telemetry and analytics emitter in web5 goes through `transmit()`\n * instead of calling its transport directly. The gate exists because the\n * consent signal resolves *after* the events that need it: Shopify's consent\n * API is not on the page by default and has to be requested, and the fedops\n * app-load pair fires inside that window. A boolean checked at each call site\n * can only ever drop an event that is already in flight; the gate can hold it.\n *\n * Two independent unlocks, and they do not compose as a plain \"either/or\":\n *\n * | consent | engaged | result |\n * |-----------|---------|---------------------------------|\n * | granted | either | transmit |\n * | unknown | no | hold in the buffer |\n * | unknown | yes | transmit, and flush what's held |\n * | denied | yes | still nothing |\n *\n * Denied outranks engaged. A visitor who refused analytics in the banner does\n * not re-enable tracking by typing a question.\n */\n\nimport {\n UNKNOWN_CONSENT,\n type ConsentProvider,\n type ConsentPurpose,\n type ConsentSnapshot,\n type GatedPurpose,\n} from './types';\n\n/** Held events are dropped past this many — a runaway emitter must not become a leak. */\nconst DEFAULT_BUFFER_LIMIT = 50;\n\n/**\n * One prefix for the whole consent trail, so `[w5-consent]` in the console\n * filter shows the full story: which CMP was found, what it answered, and for\n * every event whether it was sent, held, dropped or replayed.\n */\nconst LOG_PREFIX = '[w5-consent]';\n\nconst log = (...args: unknown[]): void => {\n try {\n console.debug(LOG_PREFIX, ...args);\n } catch {\n // A console that throws must never break a send.\n }\n};\n\nconst describe = (s: ConsentSnapshot): string =>\n `analytics=${s.analytics} performance=${s.performance} marketing=${s.marketing}`;\n\ninterface HeldEvent {\n purpose: GatedPurpose;\n send: () => void;\n label: string;\n}\n\nexport interface GateView {\n consent: ConsentSnapshot;\n engaged: boolean;\n}\n\ntype Listener = () => void;\n\nlet snapshot: ConsentSnapshot = UNKNOWN_CONSENT;\nlet engaged = false;\nlet provider: ConsentProvider | null = null;\nlet unsubscribeProvider: (() => void) | null = null;\nlet buffer: HeldEvent[] = [];\nlet bufferLimit = DEFAULT_BUFFER_LIMIT;\nlet droppedFromOverflow = 0;\n\nconst listeners = new Set<Listener>();\n\n/**\n * Cached so `getGateView` is referentially stable between changes —\n * `useSyncExternalStore` re-renders forever if the snapshot is a fresh object\n * on every read.\n */\nlet view: GateView = Object.freeze({\n consent: UNKNOWN_CONSENT,\n engaged: false,\n});\n\nconst rebuildView = (): void => {\n view = Object.freeze({ consent: snapshot, engaged });\n};\n\nconst notify = (): void => {\n for (const listener of listeners) {\n try {\n listener();\n } catch {\n // A subscriber that throws must not stop the others, or stop a flush.\n }\n }\n};\n\n/**\n * Whether an event for `purpose` may go on the wire right now.\n *\n * `necessary` is always allowed. For everything else: explicit consent wins in\n * both directions, and engagement resolves only the `unknown` case.\n */\nexport const mayTransmit = (purpose: ConsentPurpose): boolean => {\n if (purpose === 'necessary') {\n return true;\n }\n const state = snapshot[purpose];\n if (state === 'denied') {\n return false;\n }\n if (state === 'granted') {\n return true;\n }\n return engaged;\n};\n\n/**\n * Release everything the gate is holding that is now allowed, and drop\n * everything that is now refused. Anything still `unknown` stays held.\n *\n * Order is preserved among released events, but a flush necessarily emits them\n * later than they were raised — a held app-load event reaches the wire after\n * the prompt that unlocked it. Anything reading these as a timeline has to\n * know that.\n */\nconst settleBuffer = (): void => {\n if (buffer.length === 0) {\n return;\n }\n const stillHeld: HeldEvent[] = [];\n const releasing: HeldEvent[] = [];\n\n for (const held of buffer) {\n if (mayTransmit(held.purpose)) {\n releasing.push(held);\n } else if (snapshot[held.purpose] === 'denied') {\n // dropped on the floor, deliberately and permanently\n } else {\n stillHeld.push(held);\n }\n }\n\n const dropped = buffer.length - stillHeld.length - releasing.length;\n buffer = stillHeld;\n\n if (releasing.length || dropped) {\n log(\n `settle — releasing ${releasing.length}` +\n (dropped ? `, dropping ${dropped} (refused)` : '') +\n (stillHeld.length ? `, still holding ${stillHeld.length}` : ''),\n );\n }\n\n for (const held of releasing) {\n try {\n log(` ↳ REPLAY ${held.label} (${held.purpose})`);\n held.send();\n } catch {\n // A failed send must not strand the rest of the flush.\n }\n }\n};\n\n/**\n * The single entry point for anything that would put a request on the wire.\n *\n * Allowed → sent now. Refused → dropped. Not yet known → held until an unlock\n * settles it, or discarded with the page.\n */\nexport const transmit = (\n purpose: ConsentPurpose,\n send: () => void,\n label = 'event',\n): void => {\n if (mayTransmit(purpose)) {\n log(`SEND ${label} (${purpose}) — allowed`);\n send();\n return;\n }\n if (purpose !== 'necessary' && snapshot[purpose] === 'denied') {\n log(`DROP ${label} (${purpose}) — visitor refused`);\n return;\n }\n if (buffer.length >= bufferLimit) {\n droppedFromOverflow += 1;\n log(\n `DROP ${label} (${purpose}) — buffer full at ${bufferLimit}, ${droppedFromOverflow} lost`,\n );\n return;\n }\n buffer.push({ purpose: purpose as GatedPurpose, send, label });\n log(`HOLD ${label} (${purpose}) — no answer yet, ${buffer.length} held`);\n};\n\n/**\n * The visitor did something deliberate — submitted a prompt — so the session\n * may be measured even though no CMP has answered.\n *\n * This is the unlock that keeps web5 measurable at all: on a Shopify store\n * with no privacy configuration the consent API never loads, consent stays\n * `unknown` forever, and without this every store would report nothing.\n *\n * It unlocks **transmission only**. Persistent identity stays gated on real\n * consent (see `mayPersistIdentity`) — typing a question is a reason to\n * measure the session, not a reason to persist an identifier across visits.\n * It also cannot override a `denied`.\n */\nexport const unlockOnUserAction = (): void => {\n if (engaged) {\n return;\n }\n engaged = true;\n log(\n `UNLOCK — visitor submitted a prompt; ${buffer.length} held event(s) to settle`,\n );\n rebuildView();\n settleBuffer();\n notify();\n};\n\n/** Whether the visitor has taken the deliberate action that unlocks the session. */\nexport const isUserEngaged = (): boolean => engaged;\n\n/**\n * Persistent, cross-visit storage of a visitor identifier requires real\n * consent — engagement is deliberately not enough.\n */\nexport const mayPersistIdentity = (): boolean =>\n snapshot.analytics === 'granted';\n\nexport const getConsentSnapshot = (): ConsentSnapshot => snapshot;\n\n/** Referentially stable between changes, for `useSyncExternalStore`. */\nexport const getGateView = (): GateView => view;\n\nexport const subscribeToConsent = (listener: Listener): (() => void) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n};\n\nconst applySnapshot = (next: ConsentSnapshot): void => {\n if (\n next.analytics === snapshot.analytics &&\n next.marketing === snapshot.marketing &&\n next.performance === snapshot.performance\n ) {\n return;\n }\n log(`ANSWER — ${describe(snapshot)} → ${describe(next)}`);\n snapshot = Object.freeze({ ...next });\n rebuildView();\n settleBuffer();\n notify();\n};\n\n/**\n * Install the host's provider. Reads its current state immediately, *then*\n * subscribes — DL #217: a listener registered into an already-rendered page is\n * bound to an event that may have fired long before the bundle executed, so\n * subscribing alone would leave the gate permanently at `unknown`.\n */\nexport const installConsentProvider = (next: ConsentProvider): void => {\n unsubscribeProvider?.();\n provider = next;\n const initial = next.read();\n log(`provider installed: ${next.name} — reads ${describe(initial)}`);\n applySnapshot(initial);\n unsubscribeProvider = next.subscribe(applySnapshot);\n};\n\nexport const getInstalledProviderName = (): string | null =>\n provider?.name ?? null;\n\nexport const setConsentBufferLimit = (limit: number): void => {\n bufferLimit = Math.max(0, limit);\n};\n\n/** Diagnostics only — how much the gate is holding, and what it had to drop. */\nexport const getConsentGateStats = (): {\n held: number;\n droppedFromOverflow: number;\n} => ({ held: buffer.length, droppedFromOverflow });\n\nexport const resetConsentGateForTests = (): void => {\n unsubscribeProvider?.();\n unsubscribeProvider = null;\n provider = null;\n snapshot = UNKNOWN_CONSENT;\n engaged = false;\n buffer = [];\n bufferLimit = DEFAULT_BUFFER_LIMIT;\n droppedFromOverflow = 0;\n listeners.clear();\n rebuildView();\n};\n"],"mappings":";;;;AAuBA,IAAAA,MAAA,GAAAC,OAAA;AAvBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAUA;AACA,MAAMC,oBAAoB,GAAG,EAAE;;AAE/B;AACA;AACA;AACA;AACA;AACA,MAAMC,UAAU,GAAG,cAAc;AAEjC,MAAMC,GAAG,GAAGA,CAAC,GAAGC,IAAe,KAAW;EACxC,IAAI;IACFC,OAAO,CAACC,KAAK,CAACJ,UAAU,EAAE,GAAGE,IAAI,CAAC;EACpC,CAAC,CAAC,MAAM;IACN;EAAA;AAEJ,CAAC;AAED,MAAMG,QAAQ,GAAIC,CAAkB,IAClC,aAAaA,CAAC,CAACC,SAAS,gBAAgBD,CAAC,CAACE,WAAW,cAAcF,CAAC,CAACG,SAAS,EAAE;AAelF,IAAIC,QAAyB,GAAGC,sBAAe;AAC/C,IAAIC,OAAO,GAAG,KAAK;AACnB,IAAIC,QAAgC,GAAG,IAAI;AAC3C,IAAIC,mBAAwC,GAAG,IAAI;AACnD,IAAIC,MAAmB,GAAG,EAAE;AAC5B,IAAIC,WAAW,GAAGjB,oBAAoB;AACtC,IAAIkB,mBAAmB,GAAG,CAAC;AAE3B,MAAMC,SAAS,GAAG,IAAIC,GAAG,CAAW,CAAC;;AAErC;AACA;AACA;AACA;AACA;AACA,IAAIC,IAAc,GAAGC,MAAM,CAACC,MAAM,CAAC;EACjCC,OAAO,EAAEZ,sBAAe;EACxBC,OAAO,EAAE;AACX,CAAC,CAAC;AAEF,MAAMY,WAAW,GAAGA,CAAA,KAAY;EAC9BJ,IAAI,GAAGC,MAAM,CAACC,MAAM,CAAC;IAAEC,OAAO,EAAEb,QAAQ;IAAEE;EAAQ,CAAC,CAAC;AACtD,CAAC;AAED,MAAMa,MAAM,GAAGA,CAAA,KAAY;EACzB,KAAK,MAAMC,QAAQ,IAAIR,SAAS,EAAE;IAChC,IAAI;MACFQ,QAAQ,CAAC,CAAC;IACZ,CAAC,CAAC,MAAM;MACN;IAAA;EAEJ;AACF,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACO,MAAMC,WAAW,GAAIC,OAAuB,IAAc;EAC/D,IAAIA,OAAO,KAAK,WAAW,EAAE;IAC3B,OAAO,IAAI;EACb;EACA,MAAMC,KAAK,GAAGnB,QAAQ,CAACkB,OAAO,CAAC;EAC/B,IAAIC,KAAK,KAAK,QAAQ,EAAE;IACtB,OAAO,KAAK;EACd;EACA,IAAIA,KAAK,KAAK,SAAS,EAAE;IACvB,OAAO,IAAI;EACb;EACA,OAAOjB,OAAO;AAChB,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AARAkB,OAAA,CAAAH,WAAA,GAAAA,WAAA;AASA,MAAMI,YAAY,GAAGA,CAAA,KAAY;EAC/B,IAAIhB,MAAM,CAACiB,MAAM,KAAK,CAAC,EAAE;IACvB;EACF;EACA,MAAMC,SAAsB,GAAG,EAAE;EACjC,MAAMC,SAAsB,GAAG,EAAE;EAEjC,KAAK,MAAMC,IAAI,IAAIpB,MAAM,EAAE;IACzB,IAAIY,WAAW,CAACQ,IAAI,CAACP,OAAO,CAAC,EAAE;MAC7BM,SAAS,CAACE,IAAI,CAACD,IAAI,CAAC;IACtB,CAAC,MAAM,IAAIzB,QAAQ,CAACyB,IAAI,CAACP,OAAO,CAAC,KAAK,QAAQ,EAAE;MAC9C;IAAA,CACD,MAAM;MACLK,SAAS,CAACG,IAAI,CAACD,IAAI,CAAC;IACtB;EACF;EAEA,MAAME,OAAO,GAAGtB,MAAM,CAACiB,MAAM,GAAGC,SAAS,CAACD,MAAM,GAAGE,SAAS,CAACF,MAAM;EACnEjB,MAAM,GAAGkB,SAAS;EAElB,IAAIC,SAAS,CAACF,MAAM,IAAIK,OAAO,EAAE;IAC/BpC,GAAG,CACD,sBAAsBiC,SAAS,CAACF,MAAM,EAAE,IACrCK,OAAO,GAAG,cAAcA,OAAO,YAAY,GAAG,EAAE,CAAC,IACjDJ,SAAS,CAACD,MAAM,GAAG,mBAAmBC,SAAS,CAACD,MAAM,EAAE,GAAG,EAAE,CAClE,CAAC;EACH;EAEA,KAAK,MAAMG,IAAI,IAAID,SAAS,EAAE;IAC5B,IAAI;MACFjC,GAAG,CAAC,cAAckC,IAAI,CAACG,KAAK,KAAKH,IAAI,CAACP,OAAO,GAAG,CAAC;MACjDO,IAAI,CAACI,IAAI,CAAC,CAAC;IACb,CAAC,CAAC,MAAM;MACN;IAAA;EAEJ;AACF,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACO,MAAMC,QAAQ,GAAGA,CACtBZ,OAAuB,EACvBW,IAAgB,EAChBD,KAAK,GAAG,OAAO,KACN;EACT,IAAIX,WAAW,CAACC,OAAO,CAAC,EAAE;IACxB3B,GAAG,CAAC,QAAQqC,KAAK,KAAKV,OAAO,aAAa,CAAC;IAC3CW,IAAI,CAAC,CAAC;IACN;EACF;EACA,IAAIX,OAAO,KAAK,WAAW,IAAIlB,QAAQ,CAACkB,OAAO,CAAC,KAAK,QAAQ,EAAE;IAC7D3B,GAAG,CAAC,QAAQqC,KAAK,KAAKV,OAAO,qBAAqB,CAAC;IACnD;EACF;EACA,IAAIb,MAAM,CAACiB,MAAM,IAAIhB,WAAW,EAAE;IAChCC,mBAAmB,IAAI,CAAC;IACxBhB,GAAG,CACD,QAAQqC,KAAK,KAAKV,OAAO,sBAAsBZ,WAAW,KAAKC,mBAAmB,OACpF,CAAC;IACD;EACF;EACAF,MAAM,CAACqB,IAAI,CAAC;IAAER,OAAO,EAAEA,OAAuB;IAAEW,IAAI;IAAED;EAAM,CAAC,CAAC;EAC9DrC,GAAG,CAAC,QAAQqC,KAAK,KAAKV,OAAO,sBAAsBb,MAAM,CAACiB,MAAM,OAAO,CAAC;AAC1E,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAZAF,OAAA,CAAAU,QAAA,GAAAA,QAAA;AAaO,MAAMC,kBAAkB,GAAGA,CAAA,KAAY;EAC5C,IAAI7B,OAAO,EAAE;IACX;EACF;EACAA,OAAO,GAAG,IAAI;EACdX,GAAG,CACD,wCAAwCc,MAAM,CAACiB,MAAM,0BACvD,CAAC;EACDR,WAAW,CAAC,CAAC;EACbO,YAAY,CAAC,CAAC;EACdN,MAAM,CAAC,CAAC;AACV,CAAC;;AAED;AAAAK,OAAA,CAAAW,kBAAA,GAAAA,kBAAA;AACO,MAAMC,aAAa,GAAGA,CAAA,KAAe9B,OAAO;;AAEnD;AACA;AACA;AACA;AAHAkB,OAAA,CAAAY,aAAA,GAAAA,aAAA;AAIO,MAAMC,kBAAkB,GAAGA,CAAA,KAChCjC,QAAQ,CAACH,SAAS,KAAK,SAAS;AAACuB,OAAA,CAAAa,kBAAA,GAAAA,kBAAA;AAE5B,MAAMC,kBAAkB,GAAGA,CAAA,KAAuBlC,QAAQ;;AAEjE;AAAAoB,OAAA,CAAAc,kBAAA,GAAAA,kBAAA;AACO,MAAMC,WAAW,GAAGA,CAAA,KAAgBzB,IAAI;AAACU,OAAA,CAAAe,WAAA,GAAAA,WAAA;AAEzC,MAAMC,kBAAkB,GAAIpB,QAAkB,IAAmB;EACtER,SAAS,CAAC6B,GAAG,CAACrB,QAAQ,CAAC;EACvB,OAAO,MAAM;IACXR,SAAS,CAAC8B,MAAM,CAACtB,QAAQ,CAAC;EAC5B,CAAC;AACH,CAAC;AAACI,OAAA,CAAAgB,kBAAA,GAAAA,kBAAA;AAEF,MAAMG,aAAa,GAAIC,IAAqB,IAAW;EACrD,IACEA,IAAI,CAAC3C,SAAS,KAAKG,QAAQ,CAACH,SAAS,IACrC2C,IAAI,CAACzC,SAAS,KAAKC,QAAQ,CAACD,SAAS,IACrCyC,IAAI,CAAC1C,WAAW,KAAKE,QAAQ,CAACF,WAAW,EACzC;IACA;EACF;EACAP,GAAG,CAAC,YAAYI,QAAQ,CAACK,QAAQ,CAAC,QAAQL,QAAQ,CAAC6C,IAAI,CAAC,EAAE,CAAC;EAC3DxC,QAAQ,GAAGW,MAAM,CAACC,MAAM,CAAC;IAAE,GAAG4B;EAAK,CAAC,CAAC;EACrC1B,WAAW,CAAC,CAAC;EACbO,YAAY,CAAC,CAAC;EACdN,MAAM,CAAC,CAAC;AACV,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACO,MAAM0B,sBAAsB,GAAID,IAAqB,IAAW;EACrEpC,mBAAmB,YAAnBA,mBAAmB,CAAG,CAAC;EACvBD,QAAQ,GAAGqC,IAAI;EACf,MAAME,OAAO,GAAGF,IAAI,CAACG,IAAI,CAAC,CAAC;EAC3BpD,GAAG,CAAC,uBAAuBiD,IAAI,CAACI,IAAI,YAAYjD,QAAQ,CAAC+C,OAAO,CAAC,EAAE,CAAC;EACpEH,aAAa,CAACG,OAAO,CAAC;EACtBtC,mBAAmB,GAAGoC,IAAI,CAACK,SAAS,CAACN,aAAa,CAAC;AACrD,CAAC;AAACnB,OAAA,CAAAqB,sBAAA,GAAAA,sBAAA;AAEK,MAAMK,wBAAwB,GAAGA,CAAA;EAAA,IAAAC,SAAA;EAAA,OACtC,EAAAA,SAAA,GAAA5C,QAAQ,qBAAR4C,SAAA,CAAUH,IAAI,KAAI,IAAI;AAAA;AAACxB,OAAA,CAAA0B,wBAAA,GAAAA,wBAAA;AAElB,MAAME,qBAAqB,GAAIC,KAAa,IAAW;EAC5D3C,WAAW,GAAG4C,IAAI,CAACC,GAAG,CAAC,CAAC,EAAEF,KAAK,CAAC;AAClC,CAAC;;AAED;AAAA7B,OAAA,CAAA4B,qBAAA,GAAAA,qBAAA;AACO,MAAMI,mBAAmB,GAAGA,CAAA,MAG7B;EAAE3B,IAAI,EAAEpB,MAAM,CAACiB,MAAM;EAAEf;AAAoB,CAAC,CAAC;AAACa,OAAA,CAAAgC,mBAAA,GAAAA,mBAAA;AAE7C,MAAMC,wBAAwB,GAAGA,CAAA,KAAY;EAClDjD,mBAAmB,YAAnBA,mBAAmB,CAAG,CAAC;EACvBA,mBAAmB,GAAG,IAAI;EAC1BD,QAAQ,GAAG,IAAI;EACfH,QAAQ,GAAGC,sBAAe;EAC1BC,OAAO,GAAG,KAAK;EACfG,MAAM,GAAG,EAAE;EACXC,WAAW,GAAGjB,oBAAoB;EAClCkB,mBAAmB,GAAG,CAAC;EACvBC,SAAS,CAAC8C,KAAK,CAAC,CAAC;EACjBxC,WAAW,CAAC,CAAC;AACf,CAAC;AAACM,OAAA,CAAAiC,wBAAA,GAAAA,wBAAA","ignoreList":[]}
1
+ {"version":3,"names":["_types","require","LOG_PREFIX","log","args","console","debug","describe","s","analytics","performance","marketing","snapshot","UNKNOWN_CONSENT","engaged","unsubscribeProvider","listeners","Set","notify","listener","mayPersistToken","state","exports","unlockOnUserAction","getConsentSnapshot","subscribeToConsent","add","delete","applySnapshot","next","Object","freeze","installConsentProvider","initial","read","name","subscribe","resetConsentGateForTests","clear"],"sources":["../../../src/privacy/consentGate.ts"],"sourcesContent":["/**\n * The consent gate — DL #218 (revised).\n *\n * Legal cleared analytics/BI transmission to need no consent gate, so the old\n * `transmit()` + buffer machinery is gone. What analytics emitters used to route\n * through the gate now goes straight to the wire.\n *\n * Analytics AND performance telemetry both go straight to the wire now, so there\n * is nothing left to \"transmit\"-gate. What remains is the consent SIGNAL —\n * snapshot, engagement, provider — behind a single predicate:\n *\n * - `mayPersistToken()` — whether the visitor's OAuth token may be written to\n * localStorage. Persisting the token persists a cross-visit visitor identity\n * (its refresh token), which is the one thing consent still governs. Truth\n * table: granted → yes; denied → never; unknown → only once the visitor\n * engaged.\n *\n * Engagement (`unlockOnUserAction`, fired when the visitor submits a prompt)\n * resolves the `unknown` case — typing a question is a reason to remember this\n * visitor for the session — but it never overrides a `denied`.\n */\n\nimport {\n UNKNOWN_CONSENT,\n type ConsentProvider,\n type ConsentSnapshot,\n} from './types';\n\nconst LOG_PREFIX = '[w5-consent]';\n\nconst log = (...args: unknown[]): void => {\n try {\n console.debug(LOG_PREFIX, ...args);\n } catch {\n // A console that throws must never break anything.\n }\n};\n\nconst describe = (s: ConsentSnapshot): string =>\n `analytics=${s.analytics} performance=${s.performance} marketing=${s.marketing}`;\n\ntype Listener = () => void;\n\nlet snapshot: ConsentSnapshot = UNKNOWN_CONSENT;\nlet engaged = false;\nlet unsubscribeProvider: (() => void) | null = null;\n\nconst listeners = new Set<Listener>();\n\nconst notify = (): void => {\n for (const listener of listeners) {\n try {\n listener();\n } catch {\n // A subscriber that throws must not stop the others.\n }\n }\n};\n\n/**\n * Whether the visitor's OAuth token may be persisted to `localStorage`.\n *\n * Persisting the token persists a cross-visit visitor identity (the refresh\n * token re-identifies the visitor on their next visit), so it answers to\n * consent — the one thing that still does. Explicit consent wins in both\n * directions; engagement resolves only the `unknown` case. The token still\n * lives in memory for the session regardless — only the write to storage is\n * gated.\n */\nexport const mayPersistToken = (): boolean => {\n const state = snapshot.analytics;\n if (state === 'denied') {\n return false;\n }\n if (state === 'granted') {\n return true;\n }\n return engaged;\n};\n\n/**\n * The visitor did something deliberate — submitted a prompt — so we may remember\n * them for the session even though no CMP has answered. Unlocks the `unknown`\n * case only; it cannot override a `denied`.\n */\nexport const unlockOnUserAction = (): void => {\n if (engaged) {\n return;\n }\n engaged = true;\n log('UNLOCK — visitor submitted a prompt');\n notify();\n};\n\nexport const getConsentSnapshot = (): ConsentSnapshot => snapshot;\n\nexport const subscribeToConsent = (listener: Listener): (() => void) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n};\n\nconst applySnapshot = (next: ConsentSnapshot): void => {\n if (\n next.analytics === snapshot.analytics &&\n next.marketing === snapshot.marketing &&\n next.performance === snapshot.performance\n ) {\n return;\n }\n log(`ANSWER — ${describe(snapshot)} → ${describe(next)}`);\n snapshot = Object.freeze({ ...next });\n notify();\n};\n\n/**\n * Install the host's provider. Reads its current state immediately, *then*\n * subscribes — DL #217: a listener registered into an already-rendered page is\n * bound to an event that may have fired long before the bundle executed, so\n * subscribing alone would leave the gate permanently at `unknown`.\n */\nexport const installConsentProvider = (next: ConsentProvider): void => {\n unsubscribeProvider?.();\n const initial = next.read();\n log(`provider installed: ${next.name} — reads ${describe(initial)}`);\n applySnapshot(initial);\n unsubscribeProvider = next.subscribe(applySnapshot);\n};\n\nexport const resetConsentGateForTests = (): void => {\n unsubscribeProvider?.();\n unsubscribeProvider = null;\n snapshot = UNKNOWN_CONSENT;\n engaged = false;\n listeners.clear();\n};\n"],"mappings":"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","ignoreList":[]}
@@ -1,22 +1,15 @@
1
1
  "use strict";
2
2
 
3
3
  exports.__esModule = true;
4
- exports.unlockOnUserAction = exports.transmit = exports.subscribeToConsent = exports.setConsentOverride = exports.setConsentBufferLimit = exports.resetConsentGateForTests = exports.publishHostConsent = exports.mayTransmit = exports.mayPersistIdentity = exports.isUserEngaged = exports.isShopifyHost = exports.isOneTrustHost = exports.installConsentProvider = exports.initConsentGate = exports.hasHostSuppliedConsent = exports.getInstalledProviderName = exports.getGateView = exports.getConsentSnapshot = exports.getConsentOverride = exports.getConsentGateStats = exports.detectConsentProvider = exports.createShopifyConsentProvider = exports.createOneTrustConsentProvider = exports.createHostSuppliedConsentProvider = exports.UNKNOWN_CONSENT = exports.HOST_CONSENT_GLOBAL = exports.CONSENT_OVERRIDE_QUERY_PARAM = exports.CONSENT_OVERRIDE_KEY = void 0;
4
+ exports.unlockOnUserAction = exports.subscribeToConsent = exports.setConsentOverride = exports.resetConsentGateForTests = exports.publishHostConsent = exports.mayPersistToken = exports.isShopifyHost = exports.isOneTrustHost = exports.installConsentProvider = exports.initConsentGate = exports.hasHostSuppliedConsent = exports.getConsentSnapshot = exports.getConsentOverride = exports.detectConsentProvider = exports.createShopifyConsentProvider = exports.createOneTrustConsentProvider = exports.createHostSuppliedConsentProvider = exports.UNKNOWN_CONSENT = exports.HOST_CONSENT_GLOBAL = exports.CONSENT_OVERRIDE_QUERY_PARAM = exports.CONSENT_OVERRIDE_KEY = void 0;
5
5
  var _types = require("./types");
6
6
  exports.UNKNOWN_CONSENT = _types.UNKNOWN_CONSENT;
7
7
  var _consentGate = require("./consentGate");
8
- exports.transmit = _consentGate.transmit;
9
- exports.mayTransmit = _consentGate.mayTransmit;
10
8
  exports.unlockOnUserAction = _consentGate.unlockOnUserAction;
11
- exports.isUserEngaged = _consentGate.isUserEngaged;
12
- exports.mayPersistIdentity = _consentGate.mayPersistIdentity;
9
+ exports.mayPersistToken = _consentGate.mayPersistToken;
13
10
  exports.getConsentSnapshot = _consentGate.getConsentSnapshot;
14
- exports.getGateView = _consentGate.getGateView;
15
11
  exports.subscribeToConsent = _consentGate.subscribeToConsent;
16
12
  exports.installConsentProvider = _consentGate.installConsentProvider;
17
- exports.getInstalledProviderName = _consentGate.getInstalledProviderName;
18
- exports.setConsentBufferLimit = _consentGate.setConsentBufferLimit;
19
- exports.getConsentGateStats = _consentGate.getConsentGateStats;
20
13
  exports.resetConsentGateForTests = _consentGate.resetConsentGateForTests;
21
14
  var _detectProvider = require("./detectProvider");
22
15
  exports.detectConsentProvider = _detectProvider.detectConsentProvider;
@@ -1 +1 @@
1
- {"version":3,"names":["_types","require","exports","UNKNOWN_CONSENT","_consentGate","transmit","mayTransmit","unlockOnUserAction","isUserEngaged","mayPersistIdentity","getConsentSnapshot","getGateView","subscribeToConsent","installConsentProvider","getInstalledProviderName","setConsentBufferLimit","getConsentGateStats","resetConsentGateForTests","_detectProvider","detectConsentProvider","initConsentGate","_consentOverride","CONSENT_OVERRIDE_KEY","CONSENT_OVERRIDE_QUERY_PARAM","getConsentOverride","setConsentOverride","_shopifyProvider","createShopifyConsentProvider","isShopifyHost","_oneTrustProvider","createOneTrustConsentProvider","isOneTrustHost","_hostSuppliedProvider","HOST_CONSENT_GLOBAL","createHostSuppliedConsentProvider","hasHostSuppliedConsent","publishHostConsent"],"sources":["../../../src/privacy/index.ts"],"sourcesContent":["export {\n type ConsentState,\n type ConsentPurpose,\n type GatedPurpose,\n type ConsentSnapshot,\n type ConsentProvider,\n UNKNOWN_CONSENT,\n} from './types';\n\nexport {\n type GateView,\n transmit,\n mayTransmit,\n unlockOnUserAction,\n isUserEngaged,\n mayPersistIdentity,\n getConsentSnapshot,\n getGateView,\n subscribeToConsent,\n installConsentProvider,\n getInstalledProviderName,\n setConsentBufferLimit,\n getConsentGateStats,\n resetConsentGateForTests,\n} from './consentGate';\n\nexport { detectConsentProvider, initConsentGate } from './detectProvider';\n\nexport {\n CONSENT_OVERRIDE_KEY,\n CONSENT_OVERRIDE_QUERY_PARAM,\n getConsentOverride,\n setConsentOverride,\n} from './consentOverride';\n\nexport {\n createShopifyConsentProvider,\n isShopifyHost,\n} from './providers/shopifyProvider';\nexport {\n createOneTrustConsentProvider,\n isOneTrustHost,\n} from './providers/oneTrustProvider';\nexport {\n type HostConsentInput,\n HOST_CONSENT_GLOBAL,\n createHostSuppliedConsentProvider,\n hasHostSuppliedConsent,\n publishHostConsent,\n} from './providers/hostSuppliedProvider';\n"],"mappings":";;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AAOiBC,OAAA,CAAAC,eAAA,GAAAH,MAAA,CAAAG,eAAA;AAEjB,IAAAC,YAAA,GAAAH,OAAA;AAeuBC,OAAA,CAAAG,QAAA,GAAAD,YAAA,CAAAC,QAAA;AAAAH,OAAA,CAAAI,WAAA,GAAAF,YAAA,CAAAE,WAAA;AAAAJ,OAAA,CAAAK,kBAAA,GAAAH,YAAA,CAAAG,kBAAA;AAAAL,OAAA,CAAAM,aAAA,GAAAJ,YAAA,CAAAI,aAAA;AAAAN,OAAA,CAAAO,kBAAA,GAAAL,YAAA,CAAAK,kBAAA;AAAAP,OAAA,CAAAQ,kBAAA,GAAAN,YAAA,CAAAM,kBAAA;AAAAR,OAAA,CAAAS,WAAA,GAAAP,YAAA,CAAAO,WAAA;AAAAT,OAAA,CAAAU,kBAAA,GAAAR,YAAA,CAAAQ,kBAAA;AAAAV,OAAA,CAAAW,sBAAA,GAAAT,YAAA,CAAAS,sBAAA;AAAAX,OAAA,CAAAY,wBAAA,GAAAV,YAAA,CAAAU,wBAAA;AAAAZ,OAAA,CAAAa,qBAAA,GAAAX,YAAA,CAAAW,qBAAA;AAAAb,OAAA,CAAAc,mBAAA,GAAAZ,YAAA,CAAAY,mBAAA;AAAAd,OAAA,CAAAe,wBAAA,GAAAb,YAAA,CAAAa,wBAAA;AAEvB,IAAAC,eAAA,GAAAjB,OAAA;AAA0EC,OAAA,CAAAiB,qBAAA,GAAAD,eAAA,CAAAC,qBAAA;AAAAjB,OAAA,CAAAkB,eAAA,GAAAF,eAAA,CAAAE,eAAA;AAE1E,IAAAC,gBAAA,GAAApB,OAAA;AAK2BC,OAAA,CAAAoB,oBAAA,GAAAD,gBAAA,CAAAC,oBAAA;AAAApB,OAAA,CAAAqB,4BAAA,GAAAF,gBAAA,CAAAE,4BAAA;AAAArB,OAAA,CAAAsB,kBAAA,GAAAH,gBAAA,CAAAG,kBAAA;AAAAtB,OAAA,CAAAuB,kBAAA,GAAAJ,gBAAA,CAAAI,kBAAA;AAE3B,IAAAC,gBAAA,GAAAzB,OAAA;AAGqCC,OAAA,CAAAyB,4BAAA,GAAAD,gBAAA,CAAAC,4BAAA;AAAAzB,OAAA,CAAA0B,aAAA,GAAAF,gBAAA,CAAAE,aAAA;AACrC,IAAAC,iBAAA,GAAA5B,OAAA;AAGsCC,OAAA,CAAA4B,6BAAA,GAAAD,iBAAA,CAAAC,6BAAA;AAAA5B,OAAA,CAAA6B,cAAA,GAAAF,iBAAA,CAAAE,cAAA;AACtC,IAAAC,qBAAA,GAAA/B,OAAA;AAM0CC,OAAA,CAAA+B,mBAAA,GAAAD,qBAAA,CAAAC,mBAAA;AAAA/B,OAAA,CAAAgC,iCAAA,GAAAF,qBAAA,CAAAE,iCAAA;AAAAhC,OAAA,CAAAiC,sBAAA,GAAAH,qBAAA,CAAAG,sBAAA;AAAAjC,OAAA,CAAAkC,kBAAA,GAAAJ,qBAAA,CAAAI,kBAAA","ignoreList":[]}
1
+ {"version":3,"names":["_types","require","exports","UNKNOWN_CONSENT","_consentGate","unlockOnUserAction","mayPersistToken","getConsentSnapshot","subscribeToConsent","installConsentProvider","resetConsentGateForTests","_detectProvider","detectConsentProvider","initConsentGate","_consentOverride","CONSENT_OVERRIDE_KEY","CONSENT_OVERRIDE_QUERY_PARAM","getConsentOverride","setConsentOverride","_shopifyProvider","createShopifyConsentProvider","isShopifyHost","_oneTrustProvider","createOneTrustConsentProvider","isOneTrustHost","_hostSuppliedProvider","HOST_CONSENT_GLOBAL","createHostSuppliedConsentProvider","hasHostSuppliedConsent","publishHostConsent"],"sources":["../../../src/privacy/index.ts"],"sourcesContent":["export {\n type ConsentState,\n type ConsentPurpose,\n type GatedPurpose,\n type ConsentSnapshot,\n type ConsentProvider,\n UNKNOWN_CONSENT,\n} from './types';\n\nexport {\n unlockOnUserAction,\n mayPersistToken,\n getConsentSnapshot,\n subscribeToConsent,\n installConsentProvider,\n resetConsentGateForTests,\n} from './consentGate';\n\nexport { detectConsentProvider, initConsentGate } from './detectProvider';\n\nexport {\n CONSENT_OVERRIDE_KEY,\n CONSENT_OVERRIDE_QUERY_PARAM,\n getConsentOverride,\n setConsentOverride,\n} from './consentOverride';\n\nexport {\n createShopifyConsentProvider,\n isShopifyHost,\n} from './providers/shopifyProvider';\nexport {\n createOneTrustConsentProvider,\n isOneTrustHost,\n} from './providers/oneTrustProvider';\nexport {\n type HostConsentInput,\n HOST_CONSENT_GLOBAL,\n createHostSuppliedConsentProvider,\n hasHostSuppliedConsent,\n publishHostConsent,\n} from './providers/hostSuppliedProvider';\n"],"mappings":";;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AAOiBC,OAAA,CAAAC,eAAA,GAAAH,MAAA,CAAAG,eAAA;AAEjB,IAAAC,YAAA,GAAAH,OAAA;AAOuBC,OAAA,CAAAG,kBAAA,GAAAD,YAAA,CAAAC,kBAAA;AAAAH,OAAA,CAAAI,eAAA,GAAAF,YAAA,CAAAE,eAAA;AAAAJ,OAAA,CAAAK,kBAAA,GAAAH,YAAA,CAAAG,kBAAA;AAAAL,OAAA,CAAAM,kBAAA,GAAAJ,YAAA,CAAAI,kBAAA;AAAAN,OAAA,CAAAO,sBAAA,GAAAL,YAAA,CAAAK,sBAAA;AAAAP,OAAA,CAAAQ,wBAAA,GAAAN,YAAA,CAAAM,wBAAA;AAEvB,IAAAC,eAAA,GAAAV,OAAA;AAA0EC,OAAA,CAAAU,qBAAA,GAAAD,eAAA,CAAAC,qBAAA;AAAAV,OAAA,CAAAW,eAAA,GAAAF,eAAA,CAAAE,eAAA;AAE1E,IAAAC,gBAAA,GAAAb,OAAA;AAK2BC,OAAA,CAAAa,oBAAA,GAAAD,gBAAA,CAAAC,oBAAA;AAAAb,OAAA,CAAAc,4BAAA,GAAAF,gBAAA,CAAAE,4BAAA;AAAAd,OAAA,CAAAe,kBAAA,GAAAH,gBAAA,CAAAG,kBAAA;AAAAf,OAAA,CAAAgB,kBAAA,GAAAJ,gBAAA,CAAAI,kBAAA;AAE3B,IAAAC,gBAAA,GAAAlB,OAAA;AAGqCC,OAAA,CAAAkB,4BAAA,GAAAD,gBAAA,CAAAC,4BAAA;AAAAlB,OAAA,CAAAmB,aAAA,GAAAF,gBAAA,CAAAE,aAAA;AACrC,IAAAC,iBAAA,GAAArB,OAAA;AAGsCC,OAAA,CAAAqB,6BAAA,GAAAD,iBAAA,CAAAC,6BAAA;AAAArB,OAAA,CAAAsB,cAAA,GAAAF,iBAAA,CAAAE,cAAA;AACtC,IAAAC,qBAAA,GAAAxB,OAAA;AAM0CC,OAAA,CAAAwB,mBAAA,GAAAD,qBAAA,CAAAC,mBAAA;AAAAxB,OAAA,CAAAyB,iCAAA,GAAAF,qBAAA,CAAAE,iCAAA;AAAAzB,OAAA,CAAA0B,sBAAA,GAAAH,qBAAA,CAAAG,sBAAA;AAAA1B,OAAA,CAAA2B,kBAAA,GAAAJ,qBAAA,CAAAI,kBAAA","ignoreList":[]}
@@ -31,6 +31,25 @@
31
31
  --input: 0 0% 89.8%;
32
32
  --ring: 0 0% 3.9%;
33
33
 
34
+ /* Owner chrome tokens — HSL triplets. The Customize panel's own greys (ADR
35
+ * 0243), held apart from the store's palette ON PURPOSE: the panel edits and
36
+ * previews `--background`, `--card` and the rest, so chrome painted with them
37
+ * repaints itself — a dark scheme turned the panel black and its labels
38
+ * unreadable. Nothing writes these: they are not in THEME_TOKEN_CONTRACT, no
39
+ * store import, scheme or owner override carries them, and an unknown key
40
+ * from a flat map lands on its `--web5-host-*` alias, never here. Light only
41
+ * (no `.dark` twin) — admin chrome, not themed. */
42
+ --web5-chrome-surface: 0 0% 100%;
43
+ --web5-chrome-foreground: 0 0% 18.8%;
44
+ --web5-chrome-muted-foreground: 0 0% 38%;
45
+ --web5-chrome-subtle-foreground: 210 4.5% 56.9%;
46
+ --web5-chrome-border: 0 0% 89%;
47
+ --web5-chrome-border-strong: 0 0% 71%;
48
+ --web5-chrome-tint: 0 0% 98%;
49
+ --web5-chrome-accent: 0 0% 18.8%;
50
+ --web5-chrome-accent-foreground: 0 0% 100%;
51
+ --web5-chrome-destructive: 9 72.2% 44.9%;
52
+
34
53
  /* Typography tokens */
35
54
  --font-sans: ui-sans-serif, system-ui, sans-serif;
36
55
  --font-serif: serif;
@@ -47,6 +47,18 @@
47
47
  --color-text-accent-hover: var(--text-accent-hover);
48
48
  --color-accent-border: var(--accent-border);
49
49
 
50
+ /* Owner chrome — the Customize panel's store-independent greys */
51
+ --color-web5-chrome-surface: hsl(var(--web5-chrome-surface));
52
+ --color-web5-chrome-foreground: hsl(var(--web5-chrome-foreground));
53
+ --color-web5-chrome-muted-foreground: hsl(var(--web5-chrome-muted-foreground));
54
+ --color-web5-chrome-subtle-foreground: hsl(var(--web5-chrome-subtle-foreground));
55
+ --color-web5-chrome-border: hsl(var(--web5-chrome-border));
56
+ --color-web5-chrome-border-strong: hsl(var(--web5-chrome-border-strong));
57
+ --color-web5-chrome-tint: hsl(var(--web5-chrome-tint));
58
+ --color-web5-chrome-accent: hsl(var(--web5-chrome-accent));
59
+ --color-web5-chrome-accent-foreground: hsl(var(--web5-chrome-accent-foreground));
60
+ --color-web5-chrome-destructive: hsl(var(--web5-chrome-destructive));
61
+
50
62
  --radius-sm: calc(var(--radius) - 4px);
51
63
  --radius-md: calc(var(--radius) - 2px);
52
64
  --radius-lg: var(--radius);
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.WEB5_CHROME_TOKENS = void 0;
5
+ exports.web5ChromeProperties = web5ChromeProperties;
6
+ exports.web5ChromeProperty = void 0;
7
+ /**
8
+ * The owner panel's own chrome colours (`--web5-chrome-*`).
9
+ *
10
+ * The Customize panel edits and previews the store's colour tokens, so its
11
+ * chrome cannot be painted with them: a dark scheme would turn its labels
12
+ * dark-on-dark and a cream card colour would turn the whole panel cream. It
13
+ * takes these instead — light, neutral, and written by nothing the store or the
14
+ * merchant controls.
15
+ *
16
+ * WHY A CONSTANT AND NOT ONLY CSS. `base-tokens.css` declares the same values,
17
+ * but that stylesheet reaches a page through the CLIENT bundle, and every
18
+ * client bundle pins the core version it was built against. A storefront whose
19
+ * template predates these tokens would leave the panel's `hsl(var(...))`
20
+ * invalid — a transparent panel inheriting the scheme's text colour. The panel
21
+ * lives in web50-server-ui, which bundles its own core, so it writes each value
22
+ * as the `var()` fallback (`hsl(var(--web5-chrome-surface, 0 0% 100%))`, see
23
+ * `chrome()` in the TemplatePicker) and never depends on the client's CSS.
24
+ * `chromeTokens.spec.ts` keeps this map and `base-tokens.css` equal.
25
+ *
26
+ * Bare HSL triplets, like every colour token: callers wrap them in `hsl()`.
27
+ * A leaf module (no CSS imports), for the reason `tokenContract.ts` gives.
28
+ */
29
+
30
+ /** Token name (without the `--web5-chrome-` prefix) → bare HSL triplet. */
31
+ const WEB5_CHROME_TOKENS = exports.WEB5_CHROME_TOKENS = Object.freeze({
32
+ surface: '0 0% 100%',
33
+ foreground: '0 0% 18.8%',
34
+ 'muted-foreground': '0 0% 38%',
35
+ 'subtle-foreground': '210 4.5% 56.9%',
36
+ border: '0 0% 89%',
37
+ 'border-strong': '0 0% 71%',
38
+ tint: '0 0% 98%',
39
+ accent: '0 0% 18.8%',
40
+ 'accent-foreground': '0 0% 100%',
41
+ destructive: '9 72.2% 44.9%'
42
+ });
43
+ /** `surface` → `--web5-chrome-surface`. */
44
+ const web5ChromeProperty = token => `--web5-chrome-${token}`;
45
+
46
+ /**
47
+ * Every chrome token as custom properties, ready to spread into an element's
48
+ * inline style (`style={{ ...web5ChromeProperties(), ... }}`), so the element
49
+ * and everything inside it resolve `var(--web5-chrome-*)` without any
50
+ * stylesheet.
51
+ */
52
+ exports.web5ChromeProperty = web5ChromeProperty;
53
+ function web5ChromeProperties() {
54
+ const out = {};
55
+ for (const [token, value] of Object.entries(WEB5_CHROME_TOKENS)) {
56
+ out[web5ChromeProperty(token)] = value;
57
+ }
58
+ return out;
59
+ }
60
+ //# sourceMappingURL=chromeTokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["WEB5_CHROME_TOKENS","exports","Object","freeze","surface","foreground","border","tint","accent","destructive","web5ChromeProperty","token","web5ChromeProperties","out","value","entries"],"sources":["../../../src/theme/chromeTokens.ts"],"sourcesContent":["/**\n * The owner panel's own chrome colours (`--web5-chrome-*`).\n *\n * The Customize panel edits and previews the store's colour tokens, so its\n * chrome cannot be painted with them: a dark scheme would turn its labels\n * dark-on-dark and a cream card colour would turn the whole panel cream. It\n * takes these instead — light, neutral, and written by nothing the store or the\n * merchant controls.\n *\n * WHY A CONSTANT AND NOT ONLY CSS. `base-tokens.css` declares the same values,\n * but that stylesheet reaches a page through the CLIENT bundle, and every\n * client bundle pins the core version it was built against. A storefront whose\n * template predates these tokens would leave the panel's `hsl(var(...))`\n * invalid — a transparent panel inheriting the scheme's text colour. The panel\n * lives in web50-server-ui, which bundles its own core, so it writes each value\n * as the `var()` fallback (`hsl(var(--web5-chrome-surface, 0 0% 100%))`, see\n * `chrome()` in the TemplatePicker) and never depends on the client's CSS.\n * `chromeTokens.spec.ts` keeps this map and `base-tokens.css` equal.\n *\n * Bare HSL triplets, like every colour token: callers wrap them in `hsl()`.\n * A leaf module (no CSS imports), for the reason `tokenContract.ts` gives.\n */\n\n/** Token name (without the `--web5-chrome-` prefix) → bare HSL triplet. */\nexport const WEB5_CHROME_TOKENS = Object.freeze({\n surface: '0 0% 100%',\n foreground: '0 0% 18.8%',\n 'muted-foreground': '0 0% 38%',\n 'subtle-foreground': '210 4.5% 56.9%',\n border: '0 0% 89%',\n 'border-strong': '0 0% 71%',\n tint: '0 0% 98%',\n accent: '0 0% 18.8%',\n 'accent-foreground': '0 0% 100%',\n destructive: '9 72.2% 44.9%',\n} as const);\n\nexport type Web5ChromeToken = keyof typeof WEB5_CHROME_TOKENS;\n\n/** `surface` → `--web5-chrome-surface`. */\nexport const web5ChromeProperty = (token: Web5ChromeToken): `--web5-chrome-${string}` =>\n `--web5-chrome-${token}`;\n\n/**\n * Every chrome token as custom properties, ready to spread into an element's\n * inline style (`style={{ ...web5ChromeProperties(), ... }}`), so the element\n * and everything inside it resolve `var(--web5-chrome-*)` without any\n * stylesheet.\n */\nexport function web5ChromeProperties(): Record<`--web5-chrome-${string}`, string> {\n const out = {} as Record<`--web5-chrome-${string}`, string>;\n for (const [token, value] of Object.entries(WEB5_CHROME_TOKENS)) {\n out[web5ChromeProperty(token as Web5ChromeToken)] = value;\n }\n return out;\n}\n"],"mappings":";;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACO,MAAMA,kBAAkB,GAAAC,OAAA,CAAAD,kBAAA,GAAGE,MAAM,CAACC,MAAM,CAAC;EAC9CC,OAAO,EAAE,WAAW;EACpBC,UAAU,EAAE,YAAY;EACxB,kBAAkB,EAAE,UAAU;EAC9B,mBAAmB,EAAE,gBAAgB;EACrCC,MAAM,EAAE,UAAU;EAClB,eAAe,EAAE,UAAU;EAC3BC,IAAI,EAAE,UAAU;EAChBC,MAAM,EAAE,YAAY;EACpB,mBAAmB,EAAE,WAAW;EAChCC,WAAW,EAAE;AACf,CAAU,CAAC;AAIX;AACO,MAAMC,kBAAkB,GAAIC,KAAsB,IACvD,iBAAiBA,KAAK,EAAE;;AAE1B;AACA;AACA;AACA;AACA;AACA;AALAV,OAAA,CAAAS,kBAAA,GAAAA,kBAAA;AAMO,SAASE,oBAAoBA,CAAA,EAA8C;EAChF,MAAMC,GAAG,GAAG,CAAC,CAA8C;EAC3D,KAAK,MAAM,CAACF,KAAK,EAAEG,KAAK,CAAC,IAAIZ,MAAM,CAACa,OAAO,CAACf,kBAAkB,CAAC,EAAE;IAC/Da,GAAG,CAACH,kBAAkB,CAACC,KAAwB,CAAC,CAAC,GAAGG,KAAK;EAC3D;EACA,OAAOD,GAAG;AACZ","ignoreList":[]}