@preprio/toolkit 0.5.0-rc.2 → 0.6.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +415 -27
  2. package/dist/astro/chunk-O7N6GPAH.js +173 -0
  3. package/dist/astro/graphql.cjs +1030 -0
  4. package/dist/astro/graphql.d.cts +305 -0
  5. package/dist/astro/graphql.d.ts +305 -0
  6. package/dist/astro/graphql.js +936 -0
  7. package/dist/astro/index-XT_z-RYT.d.cts +130 -0
  8. package/dist/astro/index-XT_z-RYT.d.ts +130 -0
  9. package/dist/astro/index.cjs +14 -1
  10. package/dist/astro/index.d.cts +1 -120
  11. package/dist/astro/index.d.ts +1 -120
  12. package/dist/astro/index.js +15 -153
  13. package/dist/chunk-3JLWZQ37.js +179 -0
  14. package/dist/chunk-3NCEVJJ3.js +10 -0
  15. package/dist/chunk-S5RWVMDJ.js +148 -0
  16. package/dist/chunk-TBKSBXGH.js +452 -0
  17. package/dist/{chunk-FLPNN3CV.js → chunk-VI6QZTBM.js} +73 -276
  18. package/dist/chunk-YWIKKWBR.js +26 -0
  19. package/dist/graphql/codegen.cjs +510 -0
  20. package/dist/graphql/codegen.d.cts +23 -0
  21. package/dist/graphql/codegen.d.ts +23 -0
  22. package/dist/graphql/codegen.js +99 -0
  23. package/dist/graphql.cjs +941 -0
  24. package/dist/graphql.d.cts +305 -0
  25. package/dist/graphql.d.ts +305 -0
  26. package/dist/graphql.js +419 -0
  27. package/dist/index.cjs +76 -119
  28. package/dist/index.d.cts +12 -64
  29. package/dist/index.d.ts +12 -64
  30. package/dist/index.js +27 -167
  31. package/dist/nextjs/chunk-BQ6IGSH6.js +231 -0
  32. package/dist/nextjs/components.cjs +190 -122
  33. package/dist/nextjs/components.d.cts +33 -2
  34. package/dist/nextjs/components.d.ts +33 -2
  35. package/dist/nextjs/components.js +133 -4
  36. package/dist/nextjs/graphql.cjs +1362 -0
  37. package/dist/nextjs/graphql.d.cts +435 -0
  38. package/dist/nextjs/graphql.d.ts +435 -0
  39. package/dist/nextjs/graphql.js +1261 -0
  40. package/dist/nextjs/index.cjs +126 -6
  41. package/dist/nextjs/index.d.cts +53 -147
  42. package/dist/nextjs/index.d.ts +53 -147
  43. package/dist/nextjs/index.js +113 -203
  44. package/dist/nextjs/server-CjpELYvq.d.cts +156 -0
  45. package/dist/nextjs/server-CjpELYvq.d.ts +156 -0
  46. package/dist/nuxt/chunk-IQDSBPDN.js +417 -0
  47. package/dist/nuxt/graphql.cjs +1037 -0
  48. package/dist/nuxt/graphql.d.cts +302 -0
  49. package/dist/nuxt/graphql.d.ts +302 -0
  50. package/dist/nuxt/graphql.js +937 -0
  51. package/dist/nuxt/index.cjs +14 -1
  52. package/dist/nuxt/index.d.cts +3 -148
  53. package/dist/nuxt/index.d.ts +3 -148
  54. package/dist/nuxt/index.js +15 -391
  55. package/dist/nuxt/server-8v6OHbsw.d.cts +158 -0
  56. package/dist/nuxt/server-8v6OHbsw.d.ts +158 -0
  57. package/dist/pixel-DwW7cXJm.d.cts +49 -0
  58. package/dist/pixel-DwW7cXJm.d.ts +49 -0
  59. package/dist/react/components.cjs +88 -120
  60. package/dist/react/components.d.cts +2 -8
  61. package/dist/react/components.d.ts +2 -8
  62. package/dist/react/components.js +88 -120
  63. package/dist/server-Brr1UgtW.d.ts +59 -0
  64. package/dist/server-DJuS3YU0.d.cts +59 -0
  65. package/dist/sveltekit/chunk-OKYZ6HPH.js +413 -0
  66. package/dist/sveltekit/graphql.cjs +1043 -0
  67. package/dist/sveltekit/graphql.d.cts +307 -0
  68. package/dist/sveltekit/graphql.d.ts +307 -0
  69. package/dist/sveltekit/graphql.js +943 -0
  70. package/dist/sveltekit/index.cjs +14 -1
  71. package/dist/sveltekit/index.d.cts +3 -88
  72. package/dist/sveltekit/index.d.ts +3 -88
  73. package/dist/sveltekit/index.js +15 -387
  74. package/dist/sveltekit/server-CO847mEV.d.cts +98 -0
  75. package/dist/sveltekit/server-CO847mEV.d.ts +98 -0
  76. package/dist/{pixel-B3oQNbZ3.d.cts → types-BYH9XqmN.d.cts} +4 -58
  77. package/dist/{pixel-B3oQNbZ3.d.ts → types-BYH9XqmN.d.ts} +4 -58
  78. package/package.json +36 -1
package/dist/index.cjs CHANGED
@@ -33,6 +33,7 @@ __export(src_exports, {
33
33
  getPreprHeadersFromHeaders: () => getPreprHeadersFromHeaders,
34
34
  getPreprUUIDFromHeaders: () => getPreprUUIDFromHeaders,
35
35
  getToolbarPropsFromHeaders: () => getToolbarPropsFromHeaders,
36
+ isPersonalizedResponse: () => isPersonalizedResponse,
36
37
  loadTrackingPixel: () => loadTrackingPixel,
37
38
  processPreprRequest: () => processPreprRequest,
38
39
  resolveFeatures: () => resolveFeatures,
@@ -44,7 +45,7 @@ __export(src_exports, {
44
45
  module.exports = __toCommonJS(src_exports);
45
46
 
46
47
  // src/version.ts
47
- var VERSION = "0.5.0-rc.2";
48
+ var VERSION = "0.6.0-alpha.1";
48
49
 
49
50
  // src/core/features.ts
50
51
  function isEnabled(config) {
@@ -312,13 +313,9 @@ function createElementCache(query, ttl = 1e3) {
312
313
  }
313
314
 
314
315
  // src/core/iframe-bridge.ts
315
- var debug = createScopedLogger("iframe-bridge");
316
316
  var EDITOR_BASE_DOMAIN = "prepr.io";
317
317
  function isAllowedEditorOrigin(origin, allowed) {
318
- if (allowed) {
319
- if (allowed.includes("*")) return origin !== "null";
320
- return allowed.includes(origin);
321
- }
318
+ if (allowed) return allowed.includes(origin);
322
319
  let url;
323
320
  try {
324
321
  url = new URL(origin);
@@ -333,7 +330,6 @@ function isAllowedEditorOrigin(origin, allowed) {
333
330
  }
334
331
  function createIframeBridge(store, options = {}) {
335
332
  const allowedOrigins = options.allowedEditorOrigins;
336
- const onScrollToField = options.onScrollToField;
337
333
  let parentOrigin = null;
338
334
  const onKeyDown = (event) => {
339
335
  const key = event.key.toLowerCase();
@@ -343,10 +339,7 @@ function createIframeBridge(store, options = {}) {
343
339
  const onMessage = (evt) => {
344
340
  const data = evt?.data;
345
341
  if (data?.event === "prepr:initVE" && !parentOrigin) {
346
- if (!isAllowedEditorOrigin(evt.origin, allowedOrigins)) {
347
- debug.warn("ignored editor handshake from origin", evt.origin);
348
- return;
349
- }
342
+ if (!isAllowedEditorOrigin(evt.origin, allowedOrigins)) return;
350
343
  parentOrigin = evt.origin;
351
344
  setTrustedParentOrigin(parentOrigin);
352
345
  if (data.scrollPosition != null) {
@@ -360,15 +353,6 @@ function createIframeBridge(store, options = {}) {
360
353
  const currentScrollY = window.scrollY || document.documentElement.scrollTop;
361
354
  sendPreprEvent("getScrollPosition", { value: currentScrollY });
362
355
  }
363
- if (data?.event === "prepr:scrollToField") {
364
- if (typeof data.field !== "string" || !data.field) return;
365
- if (data.id !== void 0 && typeof data.id !== "string") return;
366
- try {
367
- onScrollToField?.({ field: data.field, id: data.id });
368
- } catch (error) {
369
- debug.warn("scrollToField handler failed", error);
370
- }
371
- }
372
356
  };
373
357
  return {
374
358
  start() {
@@ -393,7 +377,7 @@ var import_stega2 = require("@vercel/stega");
393
377
 
394
378
  // src/core/stega/clean.ts
395
379
  var import_stega = require("@vercel/stega");
396
- var debug2 = createScopedLogger("stega:clean");
380
+ var debug = createScopedLogger("stega:clean");
397
381
  function stegaClean(text) {
398
382
  if (!text) return text;
399
383
  return (0, import_stega.vercelStegaClean)(text);
@@ -406,7 +390,7 @@ function decodeStega(str) {
406
390
  return decoded;
407
391
  }
408
392
  } catch (error) {
409
- debug2.log("error decoding stega data", error);
393
+ debug.log("error decoding stega data", error);
410
394
  const match = str.match(/{"origin.*?}/);
411
395
  if (match) {
412
396
  try {
@@ -415,7 +399,7 @@ function decodeStega(str) {
415
399
  return decodedMatch;
416
400
  }
417
401
  } catch (innerError) {
418
- debug2.log("error decoding stega regex match", innerError);
402
+ debug.log("error decoding stega regex match", innerError);
419
403
  }
420
404
  }
421
405
  }
@@ -451,37 +435,15 @@ function isRenderedElement(element) {
451
435
  if (!style) return true;
452
436
  return style.visibility !== "hidden" && style.display !== "none";
453
437
  }
454
- function parseEditHref(href) {
455
- try {
456
- const url = new URL(href, window.location.origin);
457
- return {
458
- id: url.pathname.split("/").pop() || void 0,
459
- field: url.searchParams.get("field") || void 0,
460
- locale: url.searchParams.get("locale") || void 0
461
- };
462
- } catch {
463
- return {};
464
- }
465
- }
466
- function setOrRemove(element, name, value) {
467
- if (value) {
468
- element.setAttribute(name, value);
469
- } else {
470
- element.removeAttribute(name);
471
- }
472
- }
473
438
  function tagEncodedElement(element, decoded) {
474
439
  element.setAttribute("data-prepr-encoded", "");
475
440
  element.setAttribute("data-prepr-href", decoded.href);
476
441
  element.setAttribute("data-prepr-origin", decoded.origin);
477
- const { id, field, locale } = parseEditHref(decoded.href);
478
- setOrRemove(element, "data-prepr-id", id);
479
- setOrRemove(element, "data-prepr-field", field);
480
- setOrRemove(element, "data-prepr-locale", locale);
481
442
  }
482
443
 
483
444
  // src/core/stega/auto-clean.ts
484
- var debug3 = createScopedLogger("stega:auto-clean");
445
+ var debug2 = createScopedLogger("stega:auto-clean");
446
+ var HYDRATION_RETRY_MS = 100;
485
447
  function createStegaAutoClean(options) {
486
448
  const stripText = options?.enabled ?? true;
487
449
  let observer = null;
@@ -490,8 +452,29 @@ function createStegaAutoClean(options) {
490
452
  let pendingHidden = /* @__PURE__ */ new Set();
491
453
  let pendingDirty = /* @__PURE__ */ new Set();
492
454
  let debounceTimeout = null;
455
+ const isHydrated = options?.isHydrated;
456
+ let pendingHydration = /* @__PURE__ */ new Set();
457
+ let hydrationTimeout = null;
458
+ function retryPendingHydration() {
459
+ hydrationTimeout = null;
460
+ processing = true;
461
+ const batch = [...pendingHydration];
462
+ pendingHydration.clear();
463
+ batch.forEach((textNode) => {
464
+ if (textNode.isConnected) cleanTextNode(textNode);
465
+ });
466
+ processing = false;
467
+ }
493
468
  function cleanTextNode(textNode) {
494
469
  if (isIgnoredTextNode(textNode)) return false;
470
+ if (isHydrated && !isHydrated(textNode)) {
471
+ pendingHydration.add(textNode);
472
+ hydrationTimeout ?? (hydrationTimeout = setTimeout(
473
+ retryPendingHydration,
474
+ HYDRATION_RETRY_MS
475
+ ));
476
+ return false;
477
+ }
495
478
  const textContent = textNode.textContent;
496
479
  const info = cleaned.get(textNode);
497
480
  const settled = stripText ? info?.cleaned : info?.original;
@@ -524,7 +507,7 @@ function createStegaAutoClean(options) {
524
507
  }
525
508
  pendingHidden.add(textNode);
526
509
  } catch (error) {
527
- debug3.log("error cleaning text node", error);
510
+ debug2.log("error cleaning text node", error);
528
511
  }
529
512
  return false;
530
513
  }
@@ -610,13 +593,17 @@ function createStegaAutoClean(options) {
610
593
  if (observer || typeof window === "undefined") return;
611
594
  scanAndClean();
612
595
  setupObserver();
613
- debug3.log("stega auto-clean started");
596
+ debug2.log("stega auto-clean started");
614
597
  }
615
598
  function stop() {
616
599
  if (debounceTimeout) {
617
600
  clearTimeout(debounceTimeout);
618
601
  debounceTimeout = null;
619
602
  }
603
+ if (hydrationTimeout) {
604
+ clearTimeout(hydrationTimeout);
605
+ hydrationTimeout = null;
606
+ }
620
607
  if (observer) {
621
608
  observer.disconnect();
622
609
  observer = null;
@@ -624,13 +611,14 @@ function createStegaAutoClean(options) {
624
611
  cleaned = /* @__PURE__ */ new WeakMap();
625
612
  pendingHidden = /* @__PURE__ */ new Set();
626
613
  pendingDirty = /* @__PURE__ */ new Set();
627
- debug3.log("stega auto-clean stopped");
614
+ pendingHydration = /* @__PURE__ */ new Set();
615
+ debug2.log("stega auto-clean stopped");
628
616
  }
629
617
  return { start, stop };
630
618
  }
631
619
 
632
620
  // src/core/stega/elements.ts
633
- var debug4 = createScopedLogger("stega:elements");
621
+ var debug3 = createScopedLogger("stega:elements");
634
622
  var StegaElements = class {
635
623
  constructor(decode = decodeStega) {
636
624
  this.observer = null;
@@ -675,7 +663,7 @@ var StegaElements = class {
675
663
  walkTextNodes(document.body, (textNode) => {
676
664
  if (this.tagFromTextNode(textNode)) encodedCount++;
677
665
  });
678
- debug4.log("document scan complete, encoded", encodedCount, "elements");
666
+ debug3.log("document scan complete, encoded", encodedCount, "elements");
679
667
  this.elements = document.querySelectorAll("[data-prepr-encoded]");
680
668
  }
681
669
  /** `onUpdate` fires after each debounced batch, for refreshing derived state. */
@@ -731,9 +719,6 @@ var StegaElements = class {
731
719
  element.removeAttribute("data-prepr-encoded");
732
720
  element.removeAttribute("data-prepr-href");
733
721
  element.removeAttribute("data-prepr-origin");
734
- element.removeAttribute("data-prepr-id");
735
- element.removeAttribute("data-prepr-field");
736
- element.removeAttribute("data-prepr-locale");
737
722
  element.classList.remove("prepr-overlay-active");
738
723
  });
739
724
  this.elements = void 0;
@@ -741,7 +726,7 @@ var StegaElements = class {
741
726
  };
742
727
 
743
728
  // src/core/stega/overlay.ts
744
- var debug5 = createScopedLogger("stega:overlay");
729
+ var debug4 = createScopedLogger("stega:overlay");
745
730
  var StegaOverlay = class {
746
731
  constructor(onEdit) {
747
732
  this.overlay = null;
@@ -786,8 +771,7 @@ var StegaOverlay = class {
786
771
  const origin = element.getAttribute("data-prepr-origin");
787
772
  const id = element.getAttribute("data-prepr-id") ?? void 0;
788
773
  const field = element.getAttribute("data-prepr-field") ?? void 0;
789
- const locale = element.getAttribute("data-prepr-locale") ?? void 0;
790
- debug5.log("showing overlay", { href, origin });
774
+ debug4.log("showing overlay", { href, origin });
791
775
  const overlay = this.overlay;
792
776
  overlay.style.display = "block";
793
777
  overlay.style.top = `${rect.top + window.scrollY - 2}px`;
@@ -819,7 +803,7 @@ var StegaOverlay = class {
819
803
  tooltip.style.left = `${left}px`;
820
804
  });
821
805
  tooltip.onclick = () => {
822
- this.onEdit({ href, origin, id, field, locale });
806
+ this.onEdit({ href, origin, id, field });
823
807
  };
824
808
  }
825
809
  this.currentElement = element;
@@ -859,7 +843,7 @@ var StegaOverlay = class {
859
843
  };
860
844
 
861
845
  // src/core/stega/proximity.ts
862
- var debug6 = createScopedLogger("stega:proximity");
846
+ var debug5 = createScopedLogger("stega:proximity");
863
847
  var StegaProximity = class {
864
848
  constructor() {
865
849
  this.highlighted = /* @__PURE__ */ new Set();
@@ -894,9 +878,9 @@ var StegaProximity = class {
894
878
  );
895
879
  const nodes = this.getEncodedElements();
896
880
  nodes.forEach((el) => this.observer.observe(el));
897
- debug6.log("observing", nodes.length, "encoded elements");
881
+ debug5.log("observing", nodes.length, "encoded elements");
898
882
  } catch (error) {
899
- debug6.log("error setting up IntersectionObserver", error);
883
+ debug5.log("error setting up IntersectionObserver", error);
900
884
  }
901
885
  }
902
886
  stopObserving() {
@@ -966,7 +950,7 @@ function removeStegaStyles() {
966
950
  }
967
951
 
968
952
  // src/core/stega/scan.ts
969
- var debug7 = createScopedLogger("stega:scan");
953
+ var debug6 = createScopedLogger("stega:scan");
970
954
  var EDITOR_MODE_STYLES = "[data-prepr-encoded]{cursor:pointer}";
971
955
  function createStegaController(opts) {
972
956
  const tooltipEnabled = opts.tooltip ?? true;
@@ -999,13 +983,12 @@ function createStegaController(opts) {
999
983
  href: encoded.getAttribute("data-prepr-href") ?? "",
1000
984
  origin: encoded.getAttribute("data-prepr-origin") ?? "",
1001
985
  id: encoded.getAttribute("data-prepr-id") ?? void 0,
1002
- field: encoded.getAttribute("data-prepr-field") ?? void 0,
1003
- locale: encoded.getAttribute("data-prepr-locale") ?? void 0
986
+ field: encoded.getAttribute("data-prepr-field") ?? void 0
1004
987
  });
1005
988
  };
1006
989
  const start = () => {
1007
990
  if (initialized) {
1008
- debug7.log("already initialized, skipping setup");
991
+ debug6.log("already initialized, skipping setup");
1009
992
  return;
1010
993
  }
1011
994
  if (!tooltipEnabled) {
@@ -1015,7 +998,7 @@ function createStegaController(opts) {
1015
998
  });
1016
999
  document.addEventListener("click", handleClick, { capture: true });
1017
1000
  initialized = true;
1018
- debug7.log("stega controller started (editor mode)");
1001
+ debug6.log("stega controller started (editor mode)");
1019
1002
  return;
1020
1003
  }
1021
1004
  injectStegaStyles();
@@ -1046,7 +1029,7 @@ function createStegaController(opts) {
1046
1029
  passive: true
1047
1030
  });
1048
1031
  initialized = true;
1049
- debug7.log("stega controller started");
1032
+ debug6.log("stega controller started");
1050
1033
  };
1051
1034
  const stop = () => {
1052
1035
  if (!initialized) return;
@@ -1055,7 +1038,7 @@ function createStegaController(opts) {
1055
1038
  elements.cleanup();
1056
1039
  removeStegaStyles();
1057
1040
  initialized = false;
1058
- debug7.log("stega controller stopped (editor mode)");
1041
+ debug6.log("stega controller stopped (editor mode)");
1059
1042
  return;
1060
1043
  }
1061
1044
  if (throttledMouseMove) {
@@ -1075,43 +1058,11 @@ function createStegaController(opts) {
1075
1058
  elements.cleanup();
1076
1059
  removeStegaStyles();
1077
1060
  initialized = false;
1078
- debug7.log("stega controller stopped");
1061
+ debug6.log("stega controller stopped");
1079
1062
  };
1080
1063
  return { start, stop };
1081
1064
  }
1082
1065
 
1083
- // src/core/stega/scroll-to-field.ts
1084
- var debug8 = createScopedLogger("stega:scroll");
1085
- var FLASH_DURATION_MS = 1200;
1086
- var flashTimeout = null;
1087
- function scrollToField(request) {
1088
- const { field, id } = request;
1089
- if (!field) return false;
1090
- const candidates = document.querySelectorAll(
1091
- "[data-prepr-encoded]"
1092
- );
1093
- let target = null;
1094
- for (const candidate of candidates) {
1095
- if (candidate.getAttribute("data-prepr-field") !== field) continue;
1096
- if (id && candidate.getAttribute("data-prepr-id") !== id) continue;
1097
- target = candidate;
1098
- break;
1099
- }
1100
- if (!target) {
1101
- debug8.log("no element found for field", field);
1102
- return false;
1103
- }
1104
- target.scrollIntoView({ behavior: "smooth", block: "center" });
1105
- if (flashTimeout) clearTimeout(flashTimeout);
1106
- document.querySelectorAll(".prepr-overlay-active").forEach((el) => el.classList.remove("prepr-overlay-active"));
1107
- target.classList.add("prepr-overlay-active");
1108
- flashTimeout = setTimeout(() => {
1109
- target.classList.remove("prepr-overlay-active");
1110
- flashTimeout = null;
1111
- }, FLASH_DURATION_MS);
1112
- return true;
1113
- }
1114
-
1115
1066
  // src/core/store.ts
1116
1067
  var DEFAULT_STATE = {
1117
1068
  locale: "en",
@@ -2224,7 +2175,7 @@ function definePreprToolbar() {
2224
2175
  }
2225
2176
 
2226
2177
  // src/core/create-preview.ts
2227
- var debug9 = createScopedLogger("create-preview");
2178
+ var debug7 = createScopedLogger("create-preview");
2228
2179
  var controllerStores = /* @__PURE__ */ new WeakMap();
2229
2180
  function defaultNavigation() {
2230
2181
  return {
@@ -2266,7 +2217,7 @@ function createPreprPreview(opts = {}) {
2266
2217
  const search = new URLSearchParams(window.location.search);
2267
2218
  const hideBar = search.get(PARAM_HIDE_BAR) === "true";
2268
2219
  if (hideBar) {
2269
- debug9.log(`${PARAM_HIDE_BAR}=true \u2014 no visible toolbar`);
2220
+ debug7.log(`${PARAM_HIDE_BAR}=true \u2014 no visible toolbar`);
2270
2221
  }
2271
2222
  const mountUi = (options?.ui ?? true) && !isIframe && !hideBar;
2272
2223
  const locale = resolveLocale(options);
@@ -2302,17 +2253,18 @@ function createPreprPreview(opts = {}) {
2302
2253
  tooltip: mountUi,
2303
2254
  // In the editor, ask the parent to focus the field instead of opening a new
2304
2255
  // tab. Standalone previews keep the window.open behaviour.
2305
- onEdit: ({ href, id, field, locale: contentLocale }) => {
2256
+ onEdit: ({ href, origin, id, field }) => {
2306
2257
  const safeHref = href ? safeEditUrl(href) : null;
2307
2258
  if (href && !safeHref) {
2308
- debug9.warn("ignored edit request with unsupported href scheme");
2259
+ debug7.warn("ignored edit request with unsupported href scheme");
2309
2260
  return;
2310
2261
  }
2311
2262
  if (isIframe) {
2312
2263
  sendPreprEvent("field_edit_requested", {
2264
+ href: safeHref ?? void 0,
2265
+ origin,
2313
2266
  id,
2314
- field,
2315
- locale: contentLocale
2267
+ field
2316
2268
  });
2317
2269
  } else if (safeHref) {
2318
2270
  window.open(safeHref, "_blank", "noopener,noreferrer");
@@ -2320,7 +2272,8 @@ function createPreprPreview(opts = {}) {
2320
2272
  }
2321
2273
  });
2322
2274
  const autoClean = createStegaAutoClean({
2323
- enabled: options?.autoClean
2275
+ enabled: options?.autoClean,
2276
+ isHydrated: opts.isHydrated
2324
2277
  });
2325
2278
  autoClean.start();
2326
2279
  const handleChange = createChangeHandler({
@@ -2339,15 +2292,7 @@ function createPreprPreview(opts = {}) {
2339
2292
  handleChange(before, state);
2340
2293
  });
2341
2294
  const bridge = createIframeBridge(store, {
2342
- allowedEditorOrigins: options?.allowedEditorOrigins,
2343
- // The editor selecting a field scrolls the matching element into view. The
2344
- // lookup relies on the attributes the stega scan writes, so it finds
2345
- // nothing until encoded content has been tagged.
2346
- onScrollToField: ({ field, id }) => {
2347
- if (!scrollToField({ field, id })) {
2348
- debug9.log("no element on this page renders field", field);
2349
- }
2350
- }
2295
+ allowedEditorOrigins: options?.allowedEditorOrigins
2351
2296
  });
2352
2297
  sendPreprEvent(
2353
2298
  "getScrollPosition",
@@ -2367,13 +2312,20 @@ function createPreprPreview(opts = {}) {
2367
2312
  bridge.stop();
2368
2313
  }
2369
2314
  el?.remove();
2370
- debug9.log("preview destroyed");
2315
+ debug7.log("preview destroyed");
2371
2316
  }
2372
2317
  const controller = { destroy };
2373
2318
  controllerStores.set(controller, store);
2374
2319
  return controller;
2375
2320
  }
2376
2321
 
2322
+ // src/core/personalization.ts
2323
+ var PERSONALIZED_VARY = /\bPrepr-(Segments|ABTesting)/i;
2324
+ function isPersonalizedResponse(source) {
2325
+ const headers = "headers" in source ? source.headers : source;
2326
+ return PERSONALIZED_VARY.test(headers.get("vary") ?? "");
2327
+ }
2328
+
2377
2329
  // src/core/server.ts
2378
2330
  var PreprError = class extends Error {
2379
2331
  constructor(message, code, context, originalError) {
@@ -2689,6 +2641,10 @@ function processFrameworkRequest(request, opts, framework) {
2689
2641
  });
2690
2642
  }
2691
2643
  }
2644
+ if (requestHeaders.has("Prepr-Segments")) {
2645
+ requestHeaders.delete("Prepr-Customer-Id");
2646
+ requestHeaders.delete("Prepr-Customer-Id-Created");
2647
+ }
2692
2648
  return { requestHeaders, responseCookies };
2693
2649
  }
2694
2650
 
@@ -2771,6 +2727,7 @@ function setTrackingParam(key, value) {
2771
2727
  getPreprHeadersFromHeaders,
2772
2728
  getPreprUUIDFromHeaders,
2773
2729
  getToolbarPropsFromHeaders,
2730
+ isPersonalizedResponse,
2774
2731
  loadTrackingPixel,
2775
2732
  processPreprRequest,
2776
2733
  resolveFeatures,
package/dist/index.d.cts CHANGED
@@ -1,11 +1,13 @@
1
- import { P as PreprFeatures, R as ResolvedPreprFeatures, L as Locale, a as PreprSegment, b as PreprVariant, c as PreprToolbarProps, d as PreprPreviewOptions, e as PreprErrorCode, f as PreprHeaders } from './pixel-B3oQNbZ3.cjs';
2
- export { g as PreprEnvironment, h as PreprEventType, i as PreprFeatureConfig, j as PreprHeaderName, k as PreprPixelConfig, l as PreprToolbarComponentProps, m as PreprToolbarOptions, n as loadTrackingPixel, s as setTrackingParam, t as trackEvent } from './pixel-B3oQNbZ3.cjs';
1
+ import { b as PreprFeatures, R as ResolvedPreprFeatures, L as Locale, c as PreprSegment, d as PreprVariant, e as PreprToolbarProps, f as PreprPreviewOptions } from './types-BYH9XqmN.cjs';
2
+ export { g as PreprEnvironment, a as PreprErrorCode, h as PreprEventType, i as PreprFeatureConfig, j as PreprHeaderName, P as PreprHeaders, k as PreprToolbarComponentProps, l as PreprToolbarOptions } from './types-BYH9XqmN.cjs';
3
+ export { P as PreprError, e as extractAccessToken, g as getActiveSegmentFromHeaders, a as getActiveVariantFromHeaders, b as getPreprEnvironmentSegments, c as getPreprHeadersFromHeaders, d as getPreprUUIDFromHeaders, f as getToolbarPropsFromHeaders, i as isPersonalizedResponse, v as validatePreprToken } from './server-DJuS3YU0.cjs';
4
+ export { P as PreprPixelConfig, l as loadTrackingPixel, s as setTrackingParam, t as trackEvent } from './pixel-DwW7cXJm.cjs';
3
5
 
4
6
  /**
5
7
  * Package version; must match package.json. Lives in its own leaf module so
6
8
  * core can import it without cycling through the barrel.
7
9
  */
8
- declare const VERSION = "0.5.0-rc.2";
10
+ declare const VERSION = "0.6.0-alpha.1";
9
11
 
10
12
  /**
11
13
  * Resolve a `PreprFeatures` bag to plain booleans, defaulting every omitted key
@@ -65,6 +67,11 @@ interface CreatePreprPreviewOptions {
65
67
  props?: PreprToolbarProps;
66
68
  options?: PreprPreviewOptions;
67
69
  navigation?: PreprNavigationAdapter;
70
+ /**
71
+ * @internal Supplied by framework wrappers so stega stripping waits until
72
+ * the framework has hydrated the text it would change.
73
+ */
74
+ isHydrated?: (node: Text) => boolean;
68
75
  }
69
76
  interface PreprPreviewController {
70
77
  destroy(): void;
@@ -137,73 +144,14 @@ declare class PreprToolbarElement extends HTMLElementBase {
137
144
  /** Idempotent, including across bundles that each try to define the element. */
138
145
  declare function definePreprToolbar(): void;
139
146
 
140
- /** Which field the editor asked the preview to bring on screen. */
141
- interface ScrollToFieldMessage {
142
- field: string;
143
- id?: string;
144
- }
145
147
  interface IframeBridgeOptions {
146
148
  /**
147
149
  * Replace the `*.prepr.io` wildcard with an exact origin list. Intended for
148
- * self-hosted editors; when set, the wildcard no longer applies. `['*']`
149
- * accepts any editor origin — see `PreprPreviewOptions.allowedEditorOrigins`.
150
+ * self-hosted editors; when set, the wildcard no longer applies.
150
151
  */
151
152
  allowedEditorOrigins?: string[];
152
- /**
153
- * Called when the editor selects a field and wants the preview to scroll to
154
- * it. Only fires for messages from the handshaked editor origin. The bridge
155
- * stays free of DOM lookups: the preview runtime supplies `scrollToField`.
156
- */
157
- onScrollToField?: (message: ScrollToFieldMessage) => void;
158
153
  }
159
154
 
160
- /** Error thrown by the token helpers and the segments fetch. */
161
- declare class PreprError extends Error {
162
- readonly code: PreprErrorCode;
163
- readonly context?: string | undefined;
164
- readonly originalError?: Error | undefined;
165
- constructor(message: string, code: PreprErrorCode, context?: string | undefined, originalError?: Error | undefined);
166
- }
167
- /** Prepr Customer ID, or null if the middleware did not run for this request. */
168
- declare function getPreprUUIDFromHeaders(headers: Headers): string | null;
169
- /** Active segment ID, or null when no segment is selected. */
170
- declare function getActiveSegmentFromHeaders(headers: Headers): string | null;
171
- /** Active A/B variant (`'A'`/`'B'`), or null when no test is running. */
172
- declare function getActiveVariantFromHeaders(headers: Headers): string | null;
173
- /**
174
- * Collect the Prepr headers into a `PreprHeaders`. Lookups are case-insensitive
175
- * per the Fetch spec, but the returned keys use the declared casing.
176
- */
177
- declare function getPreprHeadersFromHeaders(headers: Headers): PreprHeaders;
178
- /**
179
- * Asserts `token` is the full `https://graphql.prepr.io/<token>` URL.
180
- * @throws PreprError if the token is missing or not an HTTPS URL.
181
- */
182
- declare function validatePreprToken(token: string): void;
183
- /**
184
- * Pulls the access token out of a GraphQL URL: `https://graphql.prepr.io/abc123`
185
- * -> `abc123`.
186
- * @throws PreprError if the URL is not a valid `graphql.prepr.io` URL.
187
- */
188
- declare function extractAccessToken(graphqlUrl: string): string;
189
- /**
190
- * Fetches the environment's segments from the Prepr API.
191
- *
192
- * `token` must be a Prepr GraphQL URL with scope 'segments'.
193
- * @throws PreprError if the token is invalid or the request fails.
194
- */
195
- declare function getPreprEnvironmentSegments(token: string): Promise<PreprSegment[]>;
196
- /**
197
- * Never throws: a failed segments fetch yields an empty list so the toolbar
198
- * still renders. The list is returned under both `segments` and the deprecated
199
- * `data` alias.
200
- *
201
- * Pass the same `features` object you give the toolbar and the middleware: with
202
- * segments disabled the `_Segments` request is skipped entirely, saving a
203
- * round-trip per page.
204
- */
205
- declare function getToolbarPropsFromHeaders(headers: Headers, token: string, features?: PreprFeatures): Promise<PreprToolbarProps>;
206
-
207
155
  interface CookieSpec {
208
156
  name: string;
209
157
  value: string;
@@ -242,4 +190,4 @@ interface PreprMiddlewareOptions {
242
190
  */
243
191
  declare function processPreprRequest(request: Request, opts?: PreprMiddlewareOptions): PreprMiddlewareResult;
244
192
 
245
- export { type CookieSpec, type CreatePreprPreviewOptions, type IframeBridgeOptions, PreprError, PreprErrorCode, PreprFeatures, PreprHeaders, type PreprMiddlewareOptions, type PreprMiddlewareResult, type PreprNavigationAdapter, type PreprPreviewController, PreprPreviewOptions, PreprSegment, PreprToolbarElement, PreprToolbarProps, PreprVariant, ResolvedPreprFeatures, type ToolbarState, type ToolbarStore, VERSION, createPreprPreview, createToolbarStore, definePreprToolbar, extractAccessToken, getActiveSegmentFromHeaders, getActiveVariantFromHeaders, getPreprEnvironmentSegments, getPreprHeadersFromHeaders, getPreprUUIDFromHeaders, getToolbarPropsFromHeaders, processPreprRequest, resolveFeatures, stegaClean, validatePreprToken };
193
+ export { type CookieSpec, type CreatePreprPreviewOptions, type IframeBridgeOptions, PreprFeatures, type PreprMiddlewareOptions, type PreprMiddlewareResult, type PreprNavigationAdapter, type PreprPreviewController, PreprPreviewOptions, PreprSegment, PreprToolbarElement, PreprToolbarProps, PreprVariant, ResolvedPreprFeatures, type ToolbarState, type ToolbarStore, VERSION, createPreprPreview, createToolbarStore, definePreprToolbar, processPreprRequest, resolveFeatures, stegaClean };