@preprio/toolkit 0.6.0-alpha.0 → 0.6.0-alpha.10

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 (59) hide show
  1. package/README.md +268 -59
  2. package/dist/astro/{chunk-3UVUDDNY.js → chunk-CG2QBHNU.js} +1 -1
  3. package/dist/astro/graphql.cjs +154 -59
  4. package/dist/astro/graphql.d.cts +75 -6
  5. package/dist/astro/graphql.d.ts +75 -6
  6. package/dist/astro/graphql.js +150 -59
  7. package/dist/astro/index.cjs +1 -1
  8. package/dist/astro/index.js +1 -1
  9. package/dist/chunk-3NCEVJJ3.js +10 -0
  10. package/dist/{chunk-BJ2LBLWO.js → chunk-LIDUJWWJ.js} +6 -4
  11. package/dist/chunk-M3RBYJ5J.js +499 -0
  12. package/dist/{chunk-DGZA7KX7.js → chunk-S5RWVMDJ.js} +0 -24
  13. package/dist/{chunk-YR7P4IWE.js → chunk-SF6TN4JR.js} +1 -9
  14. package/dist/chunk-TN6SNAR2.js +26 -0
  15. package/dist/graphql/codegen.cjs +557 -0
  16. package/dist/graphql/codegen.d.cts +23 -0
  17. package/dist/graphql/codegen.d.ts +23 -0
  18. package/dist/graphql/codegen.js +99 -0
  19. package/dist/graphql.cjs +185 -59
  20. package/dist/graphql.d.cts +110 -6
  21. package/dist/graphql.d.ts +110 -6
  22. package/dist/graphql.js +91 -430
  23. package/dist/index.cjs +1 -1
  24. package/dist/index.d.cts +1 -1
  25. package/dist/index.d.ts +1 -1
  26. package/dist/index.js +10 -6
  27. package/dist/nextjs/chunk-B4GVZEOL.js +549 -0
  28. package/dist/nextjs/components.cjs +297 -81
  29. package/dist/nextjs/components.d.cts +26 -11
  30. package/dist/nextjs/components.d.ts +26 -11
  31. package/dist/nextjs/components.js +289 -73
  32. package/dist/nextjs/graphql.cjs +952 -315
  33. package/dist/nextjs/graphql.d.cts +225 -83
  34. package/dist/nextjs/graphql.d.ts +225 -83
  35. package/dist/nextjs/graphql.js +634 -314
  36. package/dist/nextjs/index.cjs +116 -54
  37. package/dist/nextjs/index.d.cts +61 -23
  38. package/dist/nextjs/index.d.ts +61 -23
  39. package/dist/nextjs/index.js +97 -299
  40. package/dist/nextjs/{server-CjpELYvq.d.ts → server-BL-sqZvu.d.cts} +1 -1
  41. package/dist/nextjs/{server-CjpELYvq.d.cts → server-BL-sqZvu.d.ts} +1 -1
  42. package/dist/nuxt/{chunk-P6ENNAEE.js → chunk-FMC3DP7N.js} +1 -1
  43. package/dist/nuxt/graphql.cjs +154 -59
  44. package/dist/nuxt/graphql.d.cts +75 -6
  45. package/dist/nuxt/graphql.d.ts +75 -6
  46. package/dist/nuxt/graphql.js +150 -59
  47. package/dist/nuxt/index.cjs +1 -1
  48. package/dist/nuxt/index.js +1 -1
  49. package/dist/react/components.cjs +1 -1
  50. package/dist/react/components.js +1 -1
  51. package/dist/sveltekit/{chunk-FSARVMG5.js → chunk-AJPKBAHO.js} +1 -1
  52. package/dist/sveltekit/graphql.cjs +154 -59
  53. package/dist/sveltekit/graphql.d.cts +75 -6
  54. package/dist/sveltekit/graphql.d.ts +75 -6
  55. package/dist/sveltekit/graphql.js +150 -59
  56. package/dist/sveltekit/index.cjs +1 -1
  57. package/dist/sveltekit/index.js +1 -1
  58. package/package.json +6 -1
  59. package/dist/nextjs/chunk-U4HXENF7.js +0 -231
@@ -2,8 +2,9 @@
2
2
  import {
3
3
  createPreprPreview,
4
4
  loadTrackingPixel
5
- } from "../chunk-BJ2LBLWO.js";
6
- import "../chunk-DGZA7KX7.js";
5
+ } from "../chunk-LIDUJWWJ.js";
6
+ import "../chunk-S5RWVMDJ.js";
7
+ import "../chunk-TN6SNAR2.js";
7
8
 
8
9
  // src/nextjs/components.ts
9
10
  import { usePathname, useRouter } from "next/navigation";
@@ -33,68 +34,149 @@ function isReactHydrated(text) {
33
34
  return true;
34
35
  }
35
36
 
36
- // src/nextjs/ab-switch.ts
37
- function applyPreprAbBucket() {
38
- const match = document.cookie.match(/(?:^|; )prepr_ab_bucket=([AB])(?:;|$)/);
39
- const bucket = match ? match[1] : "A";
37
+ // src/nextjs/decision-switch.ts
38
+ function applyPreprDecisions(decision, options = {}) {
40
39
  const state = window;
41
- if (state.__preprAbBucket === bucket) return;
42
- state.__preprAbBucket = bucket;
43
- const css = bucket === "A" ? "" : '[data-prepr-ab="A"]{display:none!important}[data-prepr-ab="' + bucket + '"]{display:contents!important}';
44
- try {
45
- if (!state.__preprAbSheet) {
46
- const sheet = new CSSStyleSheet();
47
- document.adoptedStyleSheets = document.adoptedStyleSheets.concat(sheet);
48
- state.__preprAbSheet = sheet;
49
- }
50
- state.__preprAbSheet.replaceSync(css);
51
- } catch {
52
- if (!state.__preprAbSheet) {
53
- state.__preprAbSheet = document.createElement("style");
54
- document.head.appendChild(state.__preprAbSheet);
55
- }
56
- state.__preprAbSheet.textContent = css;
57
- }
58
- }
59
- function applyPreprDecisions() {
60
- const match = document.cookie.match(/(?:^|; )prepr_decisions=([^;]*)/);
61
- let raw;
62
- try {
63
- raw = match ? decodeURIComponent(match[1]) : "";
64
- } catch {
65
- raw = "";
40
+ const key = location.pathname + location.search;
41
+ const previous = state.__preprDecision;
42
+ let value = decision;
43
+ if (value !== void 0 && value !== "*" && options.refresh && previous && previous.key === key && previous.value !== "*") {
44
+ const pairs = (from) => {
45
+ const out = {};
46
+ from.split("~").forEach((pair) => {
47
+ const colon = pair.indexOf(":");
48
+ if (colon > 0) out[pair.slice(0, colon)] = pair;
49
+ });
50
+ return out;
51
+ };
52
+ const before = pairs(previous.value);
53
+ const after = pairs(value);
54
+ document.querySelectorAll("[data-prepr-v][data-prepr-show]").forEach((element) => {
55
+ const range = document.createRange();
56
+ range.selectNodeContents(element);
57
+ if (range.getBoundingClientRect().top >= window.innerHeight) return;
58
+ (element.getAttribute("data-prepr-v") || "").split(" ").forEach((token) => {
59
+ const group = token.slice(0, token.indexOf(":"));
60
+ if (before[group]) after[group] = before[group];
61
+ });
62
+ });
63
+ value = Object.keys(after).map((group) => after[group]).join("~");
66
64
  }
67
- const state = window;
68
- if (state.__preprDecisions === raw) return;
69
- state.__preprDecisions = raw;
70
- const id = /^[\w-]+$/;
71
- let css = "";
72
- raw.split("~").forEach((pair) => {
73
- const at = pair.indexOf(":");
74
- const group = pair.slice(0, at);
75
- if (at < 1 || !id.test(group)) return;
76
- const selector = '[data-prepr-group="' + group + '"]';
77
- css += selector + "{display:none!important}";
78
- pair.slice(at + 1).split("|").forEach((variant) => {
79
- if (id.test(variant)) {
80
- css += selector + '[data-prepr-variant="' + variant + '"]{display:contents!important}';
81
- }
65
+ if (value !== void 0) state.__preprDecision = { key, value };
66
+ const current = state.__preprDecision;
67
+ if (!current || current.key !== key) return false;
68
+ document.querySelectorAll("[data-prepr-decision]").forEach((marker) => {
69
+ marker.setAttribute("data-prepr-decided", "");
70
+ });
71
+ const defaults = current.value === "*";
72
+ const chosen = {};
73
+ current.value.split("~").forEach((pair) => {
74
+ const colon = pair.indexOf(":");
75
+ if (colon > 0)
76
+ chosen[pair.slice(0, colon)] = pair.slice(colon + 1).split("|");
77
+ });
78
+ document.querySelectorAll("[data-prepr-v]").forEach((element) => {
79
+ const nested = element.hasAttribute("data-prepr-nested");
80
+ const show = defaults ? element.hasAttribute("data-prepr-default") : (element.getAttribute("data-prepr-v") || "").split(" ").every((token) => {
81
+ const colon = token.indexOf(":");
82
+ const variant = token.slice(colon + 1);
83
+ const variants = chosen[token.slice(0, colon)];
84
+ return !!variants && (nested ? variants[0] === variant : variants.indexOf(variant) >= 0);
82
85
  });
86
+ if (show) element.setAttribute("data-prepr-show", "");
87
+ else element.removeAttribute("data-prepr-show");
83
88
  });
84
- try {
85
- if (!state.__preprDecisionSheet) {
86
- const sheet = new CSSStyleSheet();
87
- document.adoptedStyleSheets = document.adoptedStyleSheets.concat(sheet);
88
- state.__preprDecisionSheet = sheet;
89
+ return true;
90
+ }
91
+ function requestPreprDecision(key, options = {}) {
92
+ const fresh = 1e4;
93
+ const keep = 18e5;
94
+ const keepStatic = 36e5;
95
+ const state = window;
96
+ const asking = state.__preprAsking = state.__preprAsking || {};
97
+ const read = () => {
98
+ const all = {};
99
+ try {
100
+ const match = document.cookie.match(/(?:^|; )prepr_decisions=([^;]*)/);
101
+ const parsed = match ? JSON.parse(decodeURIComponent(match[1])) : null;
102
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
103
+ Object.keys(parsed).forEach((stored) => {
104
+ const entry = parsed[stored];
105
+ if (stored.charAt(0) === "/" && Array.isArray(entry) && typeof entry[0] === "string" && typeof entry[1] === "number")
106
+ all[stored] = [entry[0], entry[1]];
107
+ });
108
+ } catch {
89
109
  }
90
- state.__preprDecisionSheet.replaceSync(css);
91
- } catch {
92
- if (!state.__preprDecisionSheet) {
93
- state.__preprDecisionSheet = document.createElement("style");
94
- document.head.appendChild(state.__preprDecisionSheet);
110
+ return all;
111
+ };
112
+ const usable = (entry, now) => {
113
+ if (!entry) return false;
114
+ const age = now - entry[1];
115
+ return age >= 0 && age < (entry[0] === "*" ? fresh : entry[0] === "" ? keepStatic : keep);
116
+ };
117
+ const store = (answer) => {
118
+ const all = read();
119
+ const now = Date.now();
120
+ const kept = all[key];
121
+ const entries = Object.keys(all).filter((stored) => stored !== key && usable(all[stored], now)).map((stored) => [stored, all[stored]]);
122
+ entries.push([
123
+ key,
124
+ answer === "*" && kept && usable(kept, now) && kept[0] !== "*" ? kept : [answer, now]
125
+ ]);
126
+ entries.sort((a, b) => b[1][1] - a[1][1]);
127
+ entries.length = Math.min(entries.length, 20);
128
+ const encode = () => {
129
+ const out = {};
130
+ entries.forEach((entry) => {
131
+ out[entry[0]] = entry[1];
132
+ });
133
+ return encodeURIComponent(JSON.stringify(out));
134
+ };
135
+ let value = encode();
136
+ while (entries.length > 1 && value.length > 3e3) {
137
+ entries.pop();
138
+ value = encode();
139
+ }
140
+ document.cookie = "prepr_decisions=" + value + "; path=/; max-age=3600; samesite=lax" + (location.protocol === "https:" ? "; secure" : "");
141
+ };
142
+ const ask = () => {
143
+ if (!asking[key]) {
144
+ asking[key] = fetch(key, {
145
+ headers: { "Prepr-Decide": "1" },
146
+ cache: "no-store",
147
+ credentials: "same-origin",
148
+ // The proxy gives up on Prepr after its own `timeoutMs`; this only
149
+ // covers a proxy that never answers.
150
+ signal: AbortSignal.timeout ? AbortSignal.timeout(6e3) : void 0
151
+ }).then((response) => response.ok ? response.text() : "*").catch(() => "*").then((answer) => {
152
+ delete asking[key];
153
+ try {
154
+ store(answer);
155
+ } catch {
156
+ }
157
+ return answer;
158
+ });
95
159
  }
96
- state.__preprDecisionSheet.textContent = css;
160
+ return asking[key];
161
+ };
162
+ const last = read()[key];
163
+ if (last && !(last[0] === "" && options.personalized) && usable(last, Date.now())) {
164
+ const value = last[0];
165
+ if (value !== "" && Date.now() - last[1] >= fresh) {
166
+ ask().then((answer) => {
167
+ if (answer !== "*" && answer !== value && options.onChange)
168
+ options.onChange(answer);
169
+ });
170
+ }
171
+ return { result: value, value: Promise.resolve(value) };
97
172
  }
173
+ const pending = {
174
+ value: ask()
175
+ };
176
+ pending.value.then((answer) => {
177
+ pending.result = answer;
178
+ });
179
+ return pending;
98
180
  }
99
181
 
100
182
  // src/react/components.ts
@@ -132,44 +214,178 @@ function PreprToolbar({
132
214
  }, []);
133
215
  return null;
134
216
  }
135
- function PreprAbSwitch() {
217
+ var shown = /* @__PURE__ */ new Map();
218
+ var historyStep = false;
219
+ var onPopState = () => {
220
+ historyStep = true;
221
+ };
222
+ function requestDecision(key, personalized = false) {
223
+ return requestPreprDecision(key, {
224
+ personalized,
225
+ onChange: (value) => {
226
+ if (location.pathname + location.search !== key) return;
227
+ applyPreprDecisions(value, { refresh: true });
228
+ const state = window.__preprDecision;
229
+ if (state) shown.set(key, state.value);
230
+ }
231
+ });
232
+ }
233
+ function linkTarget(event) {
234
+ const anchor = event.target?.closest?.("a[href]");
235
+ if (!(anchor instanceof HTMLAnchorElement)) return null;
236
+ if (anchor.target && anchor.target !== "_self" || anchor.hasAttribute("download")) {
237
+ return null;
238
+ }
239
+ const url = new URL(anchor.href, location.href);
240
+ const key = url.pathname + url.search;
241
+ if (url.origin !== location.origin || key === location.pathname + location.search) {
242
+ return null;
243
+ }
244
+ return key;
245
+ }
246
+ var HOVER_DELAY_MS = 65;
247
+ var hovering = null;
248
+ function onPointerOver(event) {
249
+ if (event.pointerType !== "mouse") return;
250
+ const key = linkTarget(event);
251
+ if (hovering?.key === key) return;
252
+ if (hovering) clearTimeout(hovering.timer);
253
+ hovering = key ? { key, timer: setTimeout(() => requestDecision(key), HOVER_DELAY_MS) } : null;
254
+ }
255
+ function onPointerDown(event) {
256
+ if (event.button !== 0) return;
257
+ const key = linkTarget(event);
258
+ if (key) requestDecision(key);
259
+ }
260
+ var replaying = null;
261
+ function onClick(event) {
262
+ const key = linkTarget(event);
263
+ if (!key) return;
264
+ const anchor = event.target.closest("a[href]");
265
+ if (replaying === anchor) {
266
+ replaying = null;
267
+ return;
268
+ }
269
+ if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
270
+ return;
271
+ }
272
+ const pending = requestDecision(key);
273
+ if (pending.result !== void 0) return;
274
+ event.preventDefault();
275
+ event.stopImmediatePropagation();
276
+ void pending.value.then(() => {
277
+ replaying = anchor;
278
+ anchor.click();
279
+ });
280
+ }
281
+ var listeners = 0;
282
+ function useDecisionRequests() {
283
+ useEffect2(() => {
284
+ if (listeners++ === 0) {
285
+ window.addEventListener("pointerover", onPointerOver, { passive: true });
286
+ window.addEventListener("pointerdown", onPointerDown, {
287
+ capture: true,
288
+ passive: true
289
+ });
290
+ window.addEventListener("click", onClick, true);
291
+ window.addEventListener("popstate", onPopState);
292
+ }
293
+ return () => {
294
+ if (--listeners === 0) {
295
+ window.removeEventListener("pointerover", onPointerOver);
296
+ window.removeEventListener("pointerdown", onPointerDown, true);
297
+ window.removeEventListener("click", onClick, true);
298
+ window.removeEventListener("popstate", onPopState);
299
+ }
300
+ };
301
+ }, []);
302
+ }
303
+ function PreprPersonalizationSwitch() {
304
+ useDecisionRequests();
305
+ return null;
306
+ }
307
+ function PreprDecisionApplier() {
308
+ useDecisionRequests();
136
309
  useLayoutEffect(() => {
137
- applyPreprAbBucket();
138
- applyPreprDecisions();
310
+ const key = location.pathname + location.search;
311
+ const remember = () => {
312
+ const state = window.__preprDecision;
313
+ if (state) shown.set(key, state.value);
314
+ };
315
+ const previous = historyStep ? shown.get(key) : void 0;
316
+ historyStep = false;
317
+ if (applyPreprDecisions(previous)) {
318
+ remember();
319
+ return;
320
+ }
321
+ const pending = requestDecision(key, true);
322
+ if (pending.result !== void 0) {
323
+ applyPreprDecisions(pending.result);
324
+ remember();
325
+ return;
326
+ }
327
+ let live = true;
328
+ void pending.value.then((value) => {
329
+ if (live && location.pathname + location.search === key) {
330
+ applyPreprDecisions(value);
331
+ remember();
332
+ }
333
+ });
334
+ return () => {
335
+ live = false;
336
+ };
139
337
  });
140
338
  return null;
141
339
  }
142
340
  var VARIANT_KEY_ATTRIBUTE = "data-prepr-variant-key";
143
341
  function PreprVariantTracking({
144
342
  variantKeys,
145
- ab,
146
343
  children
147
344
  }) {
148
345
  const ref = useRef(null);
149
346
  const keys = variantKeys.join(" ");
150
347
  useLayoutEffect(() => {
151
- const elements = [...ref.current?.children ?? []];
152
- const list = keys.split(" ");
153
- const pairs = elements.length === list.length ? elements.map((element, i) => [element, list[i]]) : elements.slice(0, 1).map((element) => [element, list[0]]);
154
- const tagged = pairs.filter(([element, key]) => {
155
- if (element.hasAttribute(VARIANT_KEY_ATTRIBUTE)) return false;
156
- element.setAttribute(VARIANT_KEY_ATTRIBUTE, key);
157
- return true;
348
+ let tagged = [];
349
+ const wrapper = ref.current?.closest("[data-prepr-v]");
350
+ const shown2 = () => !wrapper || wrapper.hasAttribute("data-prepr-show");
351
+ const untag = () => {
352
+ for (const [element] of tagged)
353
+ element.removeAttribute(VARIANT_KEY_ATTRIBUTE);
354
+ tagged = [];
355
+ };
356
+ const tag = () => {
357
+ if (!shown2()) return untag();
358
+ if (tagged.length > 0) return;
359
+ const elements = [...ref.current?.children ?? []];
360
+ const list = keys.split(" ");
361
+ const pairs = elements.length === list.length ? elements.map((element, i) => [element, list[i]]) : elements.slice(0, 1).map((element) => [element, list[0]]);
362
+ tagged = pairs.filter(([element, key]) => {
363
+ if (element.hasAttribute(VARIANT_KEY_ATTRIBUTE)) return false;
364
+ element.setAttribute(VARIANT_KEY_ATTRIBUTE, key);
365
+ return true;
366
+ });
367
+ };
368
+ const timer = setTimeout(tag);
369
+ const observer = wrapper && new MutationObserver(tag);
370
+ observer?.observe(wrapper, {
371
+ attributes: true,
372
+ attributeFilter: ["data-prepr-show"]
158
373
  });
159
374
  return () => {
160
- for (const [element] of tagged) {
161
- element.removeAttribute(VARIANT_KEY_ATTRIBUTE);
162
- }
375
+ clearTimeout(timer);
376
+ observer?.disconnect();
377
+ untag();
163
378
  };
164
379
  }, [keys]);
165
380
  return createElement(
166
381
  "div",
167
- ab === void 0 ? { ref, style: { display: "contents" } } : { ref, "data-prepr-ab": ab },
382
+ { ref, style: { display: "contents" } },
168
383
  children
169
384
  );
170
385
  }
171
386
  export {
172
- PreprAbSwitch,
387
+ PreprDecisionApplier,
388
+ PreprPersonalizationSwitch,
173
389
  PreprToolbar,
174
390
  PreprTrackingPixel,
175
391
  PreprVariantTracking