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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +300 -19
  2. package/dist/astro/chunk-3UVUDDNY.js +173 -0
  3. package/dist/astro/graphql.cjs +983 -0
  4. package/dist/astro/graphql.d.cts +231 -0
  5. package/dist/astro/graphql.d.ts +231 -0
  6. package/dist/astro/graphql.js +893 -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-4JNKYIEV.js → chunk-BJ2LBLWO.js} +69 -268
  14. package/dist/chunk-DGZA7KX7.js +172 -0
  15. package/dist/chunk-YR7P4IWE.js +187 -0
  16. package/dist/graphql.cjs +894 -0
  17. package/dist/graphql.d.cts +231 -0
  18. package/dist/graphql.d.ts +231 -0
  19. package/dist/graphql.js +787 -0
  20. package/dist/index.cjs +74 -111
  21. package/dist/index.d.cts +11 -62
  22. package/dist/index.d.ts +11 -62
  23. package/dist/index.js +23 -167
  24. package/dist/nextjs/chunk-U4HXENF7.js +231 -0
  25. package/dist/nextjs/components.cjs +188 -114
  26. package/dist/nextjs/components.d.cts +33 -2
  27. package/dist/nextjs/components.d.ts +33 -2
  28. package/dist/nextjs/components.js +132 -4
  29. package/dist/nextjs/graphql.cjs +1315 -0
  30. package/dist/nextjs/graphql.d.cts +361 -0
  31. package/dist/nextjs/graphql.d.ts +361 -0
  32. package/dist/nextjs/graphql.js +1218 -0
  33. package/dist/nextjs/index.cjs +126 -6
  34. package/dist/nextjs/index.d.cts +53 -141
  35. package/dist/nextjs/index.d.ts +53 -141
  36. package/dist/nextjs/index.js +113 -203
  37. package/dist/nextjs/server-CjpELYvq.d.cts +156 -0
  38. package/dist/nextjs/server-CjpELYvq.d.ts +156 -0
  39. package/dist/nuxt/chunk-P6ENNAEE.js +417 -0
  40. package/dist/nuxt/graphql.cjs +990 -0
  41. package/dist/nuxt/graphql.d.cts +228 -0
  42. package/dist/nuxt/graphql.d.ts +228 -0
  43. package/dist/nuxt/graphql.js +894 -0
  44. package/dist/nuxt/index.cjs +14 -1
  45. package/dist/nuxt/index.d.cts +3 -148
  46. package/dist/nuxt/index.d.ts +3 -148
  47. package/dist/nuxt/index.js +15 -391
  48. package/dist/nuxt/server-8v6OHbsw.d.cts +158 -0
  49. package/dist/nuxt/server-8v6OHbsw.d.ts +158 -0
  50. package/dist/pixel-DwW7cXJm.d.cts +49 -0
  51. package/dist/pixel-DwW7cXJm.d.ts +49 -0
  52. package/dist/react/components.cjs +86 -112
  53. package/dist/react/components.js +86 -112
  54. package/dist/server-Brr1UgtW.d.ts +59 -0
  55. package/dist/server-DJuS3YU0.d.cts +59 -0
  56. package/dist/sveltekit/chunk-FSARVMG5.js +413 -0
  57. package/dist/sveltekit/graphql.cjs +996 -0
  58. package/dist/sveltekit/graphql.d.cts +233 -0
  59. package/dist/sveltekit/graphql.d.ts +233 -0
  60. package/dist/sveltekit/graphql.js +900 -0
  61. package/dist/sveltekit/index.cjs +14 -1
  62. package/dist/sveltekit/index.d.cts +3 -88
  63. package/dist/sveltekit/index.d.ts +3 -88
  64. package/dist/sveltekit/index.js +15 -387
  65. package/dist/sveltekit/server-CO847mEV.d.cts +98 -0
  66. package/dist/sveltekit/server-CO847mEV.d.ts +98 -0
  67. package/dist/{pixel-e1fUWl2Y.d.cts → types-BYH9XqmN.d.cts} +2 -50
  68. package/dist/{pixel-e1fUWl2Y.d.ts → types-BYH9XqmN.d.ts} +2 -50
  69. package/package.json +31 -1
@@ -267,7 +267,6 @@ function createElementCache(query, ttl = 1e3) {
267
267
  }
268
268
 
269
269
  // src/core/iframe-bridge.ts
270
- var debug = createScopedLogger("iframe-bridge");
271
270
  var EDITOR_BASE_DOMAIN = "prepr.io";
272
271
  function isAllowedEditorOrigin(origin, allowed) {
273
272
  if (allowed) return allowed.includes(origin);
@@ -285,7 +284,6 @@ function isAllowedEditorOrigin(origin, allowed) {
285
284
  }
286
285
  function createIframeBridge(store, options = {}) {
287
286
  const allowedOrigins = options.allowedEditorOrigins;
288
- const onScrollToField = options.onScrollToField;
289
287
  let parentOrigin = null;
290
288
  const onKeyDown = (event) => {
291
289
  const key = event.key.toLowerCase();
@@ -309,15 +307,6 @@ function createIframeBridge(store, options = {}) {
309
307
  const currentScrollY = window.scrollY || document.documentElement.scrollTop;
310
308
  sendPreprEvent("getScrollPosition", { value: currentScrollY });
311
309
  }
312
- if (data?.event === "prepr:scrollToField") {
313
- if (typeof data.field !== "string" || !data.field) return;
314
- if (data.id !== void 0 && typeof data.id !== "string") return;
315
- try {
316
- onScrollToField?.({ field: data.field, id: data.id });
317
- } catch (error) {
318
- debug.warn("scrollToField handler failed", error);
319
- }
320
- }
321
310
  };
322
311
  return {
323
312
  start() {
@@ -342,7 +331,7 @@ import { vercelStegaSplit } from "@vercel/stega";
342
331
 
343
332
  // src/core/stega/clean.ts
344
333
  import { vercelStegaClean, vercelStegaDecode } from "@vercel/stega";
345
- var debug2 = createScopedLogger("stega:clean");
334
+ var debug = createScopedLogger("stega:clean");
346
335
  function decodeStega(str) {
347
336
  if (!str) return null;
348
337
  try {
@@ -351,7 +340,7 @@ function decodeStega(str) {
351
340
  return decoded;
352
341
  }
353
342
  } catch (error) {
354
- debug2.log("error decoding stega data", error);
343
+ debug.log("error decoding stega data", error);
355
344
  const match = str.match(/{"origin.*?}/);
356
345
  if (match) {
357
346
  try {
@@ -360,7 +349,7 @@ function decodeStega(str) {
360
349
  return decodedMatch;
361
350
  }
362
351
  } catch (innerError) {
363
- debug2.log("error decoding stega regex match", innerError);
352
+ debug.log("error decoding stega regex match", innerError);
364
353
  }
365
354
  }
366
355
  }
@@ -396,37 +385,15 @@ function isRenderedElement(element) {
396
385
  if (!style) return true;
397
386
  return style.visibility !== "hidden" && style.display !== "none";
398
387
  }
399
- function parseEditHref(href) {
400
- try {
401
- const url = new URL(href, window.location.origin);
402
- return {
403
- id: url.pathname.split("/").pop() || void 0,
404
- field: url.searchParams.get("field") || void 0,
405
- locale: url.searchParams.get("locale") || void 0
406
- };
407
- } catch {
408
- return {};
409
- }
410
- }
411
- function setOrRemove(element, name, value) {
412
- if (value) {
413
- element.setAttribute(name, value);
414
- } else {
415
- element.removeAttribute(name);
416
- }
417
- }
418
388
  function tagEncodedElement(element, decoded) {
419
389
  element.setAttribute("data-prepr-encoded", "");
420
390
  element.setAttribute("data-prepr-href", decoded.href);
421
391
  element.setAttribute("data-prepr-origin", decoded.origin);
422
- const { id, field, locale } = parseEditHref(decoded.href);
423
- setOrRemove(element, "data-prepr-id", id);
424
- setOrRemove(element, "data-prepr-field", field);
425
- setOrRemove(element, "data-prepr-locale", locale);
426
392
  }
427
393
 
428
394
  // src/core/stega/auto-clean.ts
429
- var debug3 = createScopedLogger("stega:auto-clean");
395
+ var debug2 = createScopedLogger("stega:auto-clean");
396
+ var HYDRATION_RETRY_MS = 100;
430
397
  function createStegaAutoClean(options) {
431
398
  const stripText = options?.enabled ?? true;
432
399
  let observer = null;
@@ -435,8 +402,29 @@ function createStegaAutoClean(options) {
435
402
  let pendingHidden = /* @__PURE__ */ new Set();
436
403
  let pendingDirty = /* @__PURE__ */ new Set();
437
404
  let debounceTimeout = null;
405
+ const isHydrated = options?.isHydrated;
406
+ let pendingHydration = /* @__PURE__ */ new Set();
407
+ let hydrationTimeout = null;
408
+ function retryPendingHydration() {
409
+ hydrationTimeout = null;
410
+ processing = true;
411
+ const batch = [...pendingHydration];
412
+ pendingHydration.clear();
413
+ batch.forEach((textNode) => {
414
+ if (textNode.isConnected) cleanTextNode(textNode);
415
+ });
416
+ processing = false;
417
+ }
438
418
  function cleanTextNode(textNode) {
439
419
  if (isIgnoredTextNode(textNode)) return false;
420
+ if (isHydrated && !isHydrated(textNode)) {
421
+ pendingHydration.add(textNode);
422
+ hydrationTimeout ?? (hydrationTimeout = setTimeout(
423
+ retryPendingHydration,
424
+ HYDRATION_RETRY_MS
425
+ ));
426
+ return false;
427
+ }
440
428
  const textContent = textNode.textContent;
441
429
  const info = cleaned.get(textNode);
442
430
  const settled = stripText ? info?.cleaned : info?.original;
@@ -469,7 +457,7 @@ function createStegaAutoClean(options) {
469
457
  }
470
458
  pendingHidden.add(textNode);
471
459
  } catch (error) {
472
- debug3.log("error cleaning text node", error);
460
+ debug2.log("error cleaning text node", error);
473
461
  }
474
462
  return false;
475
463
  }
@@ -555,13 +543,17 @@ function createStegaAutoClean(options) {
555
543
  if (observer || typeof window === "undefined") return;
556
544
  scanAndClean();
557
545
  setupObserver();
558
- debug3.log("stega auto-clean started");
546
+ debug2.log("stega auto-clean started");
559
547
  }
560
548
  function stop() {
561
549
  if (debounceTimeout) {
562
550
  clearTimeout(debounceTimeout);
563
551
  debounceTimeout = null;
564
552
  }
553
+ if (hydrationTimeout) {
554
+ clearTimeout(hydrationTimeout);
555
+ hydrationTimeout = null;
556
+ }
565
557
  if (observer) {
566
558
  observer.disconnect();
567
559
  observer = null;
@@ -569,13 +561,14 @@ function createStegaAutoClean(options) {
569
561
  cleaned = /* @__PURE__ */ new WeakMap();
570
562
  pendingHidden = /* @__PURE__ */ new Set();
571
563
  pendingDirty = /* @__PURE__ */ new Set();
572
- debug3.log("stega auto-clean stopped");
564
+ pendingHydration = /* @__PURE__ */ new Set();
565
+ debug2.log("stega auto-clean stopped");
573
566
  }
574
567
  return { start, stop };
575
568
  }
576
569
 
577
570
  // src/core/stega/elements.ts
578
- var debug4 = createScopedLogger("stega:elements");
571
+ var debug3 = createScopedLogger("stega:elements");
579
572
  var StegaElements = class {
580
573
  constructor(decode = decodeStega) {
581
574
  this.observer = null;
@@ -620,7 +613,7 @@ var StegaElements = class {
620
613
  walkTextNodes(document.body, (textNode) => {
621
614
  if (this.tagFromTextNode(textNode)) encodedCount++;
622
615
  });
623
- debug4.log("document scan complete, encoded", encodedCount, "elements");
616
+ debug3.log("document scan complete, encoded", encodedCount, "elements");
624
617
  this.elements = document.querySelectorAll("[data-prepr-encoded]");
625
618
  }
626
619
  /** `onUpdate` fires after each debounced batch, for refreshing derived state. */
@@ -676,9 +669,6 @@ var StegaElements = class {
676
669
  element.removeAttribute("data-prepr-encoded");
677
670
  element.removeAttribute("data-prepr-href");
678
671
  element.removeAttribute("data-prepr-origin");
679
- element.removeAttribute("data-prepr-id");
680
- element.removeAttribute("data-prepr-field");
681
- element.removeAttribute("data-prepr-locale");
682
672
  element.classList.remove("prepr-overlay-active");
683
673
  });
684
674
  this.elements = void 0;
@@ -686,7 +676,7 @@ var StegaElements = class {
686
676
  };
687
677
 
688
678
  // src/core/stega/overlay.ts
689
- var debug5 = createScopedLogger("stega:overlay");
679
+ var debug4 = createScopedLogger("stega:overlay");
690
680
  var StegaOverlay = class {
691
681
  constructor(onEdit) {
692
682
  this.overlay = null;
@@ -731,8 +721,7 @@ var StegaOverlay = class {
731
721
  const origin = element.getAttribute("data-prepr-origin");
732
722
  const id = element.getAttribute("data-prepr-id") ?? void 0;
733
723
  const field = element.getAttribute("data-prepr-field") ?? void 0;
734
- const locale = element.getAttribute("data-prepr-locale") ?? void 0;
735
- debug5.log("showing overlay", { href, origin });
724
+ debug4.log("showing overlay", { href, origin });
736
725
  const overlay = this.overlay;
737
726
  overlay.style.display = "block";
738
727
  overlay.style.top = `${rect.top + window.scrollY - 2}px`;
@@ -764,7 +753,7 @@ var StegaOverlay = class {
764
753
  tooltip.style.left = `${left}px`;
765
754
  });
766
755
  tooltip.onclick = () => {
767
- this.onEdit({ href, origin, id, field, locale });
756
+ this.onEdit({ href, origin, id, field });
768
757
  };
769
758
  }
770
759
  this.currentElement = element;
@@ -804,7 +793,7 @@ var StegaOverlay = class {
804
793
  };
805
794
 
806
795
  // src/core/stega/proximity.ts
807
- var debug6 = createScopedLogger("stega:proximity");
796
+ var debug5 = createScopedLogger("stega:proximity");
808
797
  var StegaProximity = class {
809
798
  constructor() {
810
799
  this.highlighted = /* @__PURE__ */ new Set();
@@ -839,9 +828,9 @@ var StegaProximity = class {
839
828
  );
840
829
  const nodes = this.getEncodedElements();
841
830
  nodes.forEach((el) => this.observer.observe(el));
842
- debug6.log("observing", nodes.length, "encoded elements");
831
+ debug5.log("observing", nodes.length, "encoded elements");
843
832
  } catch (error) {
844
- debug6.log("error setting up IntersectionObserver", error);
833
+ debug5.log("error setting up IntersectionObserver", error);
845
834
  }
846
835
  }
847
836
  stopObserving() {
@@ -911,7 +900,7 @@ function removeStegaStyles() {
911
900
  }
912
901
 
913
902
  // src/core/stega/scan.ts
914
- var debug7 = createScopedLogger("stega:scan");
903
+ var debug6 = createScopedLogger("stega:scan");
915
904
  var EDITOR_MODE_STYLES = "[data-prepr-encoded]{cursor:pointer}";
916
905
  function createStegaController(opts) {
917
906
  const tooltipEnabled = opts.tooltip ?? true;
@@ -944,13 +933,12 @@ function createStegaController(opts) {
944
933
  href: encoded.getAttribute("data-prepr-href") ?? "",
945
934
  origin: encoded.getAttribute("data-prepr-origin") ?? "",
946
935
  id: encoded.getAttribute("data-prepr-id") ?? void 0,
947
- field: encoded.getAttribute("data-prepr-field") ?? void 0,
948
- locale: encoded.getAttribute("data-prepr-locale") ?? void 0
936
+ field: encoded.getAttribute("data-prepr-field") ?? void 0
949
937
  });
950
938
  };
951
939
  const start = () => {
952
940
  if (initialized) {
953
- debug7.log("already initialized, skipping setup");
941
+ debug6.log("already initialized, skipping setup");
954
942
  return;
955
943
  }
956
944
  if (!tooltipEnabled) {
@@ -960,7 +948,7 @@ function createStegaController(opts) {
960
948
  });
961
949
  document.addEventListener("click", handleClick, { capture: true });
962
950
  initialized = true;
963
- debug7.log("stega controller started (editor mode)");
951
+ debug6.log("stega controller started (editor mode)");
964
952
  return;
965
953
  }
966
954
  injectStegaStyles();
@@ -991,7 +979,7 @@ function createStegaController(opts) {
991
979
  passive: true
992
980
  });
993
981
  initialized = true;
994
- debug7.log("stega controller started");
982
+ debug6.log("stega controller started");
995
983
  };
996
984
  const stop = () => {
997
985
  if (!initialized) return;
@@ -1000,7 +988,7 @@ function createStegaController(opts) {
1000
988
  elements.cleanup();
1001
989
  removeStegaStyles();
1002
990
  initialized = false;
1003
- debug7.log("stega controller stopped (editor mode)");
991
+ debug6.log("stega controller stopped (editor mode)");
1004
992
  return;
1005
993
  }
1006
994
  if (throttledMouseMove) {
@@ -1020,43 +1008,11 @@ function createStegaController(opts) {
1020
1008
  elements.cleanup();
1021
1009
  removeStegaStyles();
1022
1010
  initialized = false;
1023
- debug7.log("stega controller stopped");
1011
+ debug6.log("stega controller stopped");
1024
1012
  };
1025
1013
  return { start, stop };
1026
1014
  }
1027
1015
 
1028
- // src/core/stega/scroll-to-field.ts
1029
- var debug8 = createScopedLogger("stega:scroll");
1030
- var FLASH_DURATION_MS = 1200;
1031
- var flashTimeout = null;
1032
- function scrollToField(request) {
1033
- const { field, id } = request;
1034
- if (!field) return false;
1035
- const candidates = document.querySelectorAll(
1036
- "[data-prepr-encoded]"
1037
- );
1038
- let target = null;
1039
- for (const candidate of candidates) {
1040
- if (candidate.getAttribute("data-prepr-field") !== field) continue;
1041
- if (id && candidate.getAttribute("data-prepr-id") !== id) continue;
1042
- target = candidate;
1043
- break;
1044
- }
1045
- if (!target) {
1046
- debug8.log("no element found for field", field);
1047
- return false;
1048
- }
1049
- target.scrollIntoView({ behavior: "smooth", block: "center" });
1050
- if (flashTimeout) clearTimeout(flashTimeout);
1051
- document.querySelectorAll(".prepr-overlay-active").forEach((el) => el.classList.remove("prepr-overlay-active"));
1052
- target.classList.add("prepr-overlay-active");
1053
- flashTimeout = setTimeout(() => {
1054
- target.classList.remove("prepr-overlay-active");
1055
- flashTimeout = null;
1056
- }, FLASH_DURATION_MS);
1057
- return true;
1058
- }
1059
-
1060
1016
  // src/core/store.ts
1061
1017
  var DEFAULT_STATE = {
1062
1018
  locale: "en",
@@ -2169,7 +2125,7 @@ function definePreprToolbar() {
2169
2125
  }
2170
2126
 
2171
2127
  // src/core/create-preview.ts
2172
- var debug9 = createScopedLogger("create-preview");
2128
+ var debug7 = createScopedLogger("create-preview");
2173
2129
  var controllerStores = /* @__PURE__ */ new WeakMap();
2174
2130
  function defaultNavigation() {
2175
2131
  return {
@@ -2211,7 +2167,7 @@ function createPreprPreview(opts = {}) {
2211
2167
  const search = new URLSearchParams(window.location.search);
2212
2168
  const hideBar = search.get(PARAM_HIDE_BAR) === "true";
2213
2169
  if (hideBar) {
2214
- debug9.log(`${PARAM_HIDE_BAR}=true \u2014 no visible toolbar`);
2170
+ debug7.log(`${PARAM_HIDE_BAR}=true \u2014 no visible toolbar`);
2215
2171
  }
2216
2172
  const mountUi = (options?.ui ?? true) && !isIframe && !hideBar;
2217
2173
  const locale = resolveLocale(options);
@@ -2247,17 +2203,18 @@ function createPreprPreview(opts = {}) {
2247
2203
  tooltip: mountUi,
2248
2204
  // In the editor, ask the parent to focus the field instead of opening a new
2249
2205
  // tab. Standalone previews keep the window.open behaviour.
2250
- onEdit: ({ href, id, field, locale: contentLocale }) => {
2206
+ onEdit: ({ href, origin, id, field }) => {
2251
2207
  const safeHref = href ? safeEditUrl(href) : null;
2252
2208
  if (href && !safeHref) {
2253
- debug9.warn("ignored edit request with unsupported href scheme");
2209
+ debug7.warn("ignored edit request with unsupported href scheme");
2254
2210
  return;
2255
2211
  }
2256
2212
  if (isIframe) {
2257
2213
  sendPreprEvent("field_edit_requested", {
2214
+ href: safeHref ?? void 0,
2215
+ origin,
2258
2216
  id,
2259
- field,
2260
- locale: contentLocale
2217
+ field
2261
2218
  });
2262
2219
  } else if (safeHref) {
2263
2220
  window.open(safeHref, "_blank", "noopener,noreferrer");
@@ -2265,7 +2222,8 @@ function createPreprPreview(opts = {}) {
2265
2222
  }
2266
2223
  });
2267
2224
  const autoClean = createStegaAutoClean({
2268
- enabled: options?.autoClean
2225
+ enabled: options?.autoClean,
2226
+ isHydrated: opts.isHydrated
2269
2227
  });
2270
2228
  autoClean.start();
2271
2229
  const handleChange = createChangeHandler({
@@ -2284,15 +2242,7 @@ function createPreprPreview(opts = {}) {
2284
2242
  handleChange(before, state);
2285
2243
  });
2286
2244
  const bridge = createIframeBridge(store, {
2287
- allowedEditorOrigins: options?.allowedEditorOrigins,
2288
- // The editor selecting a field scrolls the matching element into view. The
2289
- // lookup relies on the attributes the stega scan writes, so it finds
2290
- // nothing until encoded content has been tagged.
2291
- onScrollToField: ({ field, id }) => {
2292
- if (!scrollToField({ field, id })) {
2293
- debug9.log("no element on this page renders field", field);
2294
- }
2295
- }
2245
+ allowedEditorOrigins: options?.allowedEditorOrigins
2296
2246
  });
2297
2247
  sendPreprEvent(
2298
2248
  "getScrollPosition",
@@ -2312,15 +2262,34 @@ function createPreprPreview(opts = {}) {
2312
2262
  bridge.stop();
2313
2263
  }
2314
2264
  el?.remove();
2315
- debug9.log("preview destroyed");
2265
+ debug7.log("preview destroyed");
2316
2266
  }
2317
2267
  const controller = { destroy };
2318
2268
  controllerStores.set(controller, store);
2319
2269
  return controller;
2320
2270
  }
2321
2271
 
2272
+ // src/react/hydration.ts
2273
+ var PROPS_KEY_PREFIX = "__reactProps$";
2274
+ function reactProps(element) {
2275
+ for (const key of Object.keys(element)) {
2276
+ if (key.startsWith(PROPS_KEY_PREFIX)) {
2277
+ return element[key];
2278
+ }
2279
+ }
2280
+ return void 0;
2281
+ }
2282
+ function isReactHydrated(text) {
2283
+ for (let el = text.parentElement; el; el = el.parentElement) {
2284
+ const props = reactProps(el);
2285
+ if (!props) continue;
2286
+ return el === text.parentElement || props.dangerouslySetInnerHTML != null;
2287
+ }
2288
+ return true;
2289
+ }
2290
+
2322
2291
  // src/version.ts
2323
- var VERSION = "0.5.0-rc.1";
2292
+ var VERSION = "0.6.0-alpha.0";
2324
2293
 
2325
2294
  // src/core/pixel.ts
2326
2295
  var PIXEL_SCRIPT_URL = "https://cdn.tracking.prepr.io/js/prepr.min.js";
@@ -2368,7 +2337,12 @@ function PreprPreview({
2368
2337
  ...props
2369
2338
  }) {
2370
2339
  useEffect(() => {
2371
- const preview = createPreprPreview({ props, options, navigation });
2340
+ const preview = createPreprPreview({
2341
+ props,
2342
+ options,
2343
+ navigation,
2344
+ isHydrated: isReactHydrated
2345
+ });
2372
2346
  return () => preview.destroy();
2373
2347
  }, []);
2374
2348
  return null;
@@ -0,0 +1,59 @@
1
+ import { a as PreprErrorCode, c as PreprSegment, P as PreprHeaders, b as PreprFeatures, e as PreprToolbarProps } from './types-BYH9XqmN.js';
2
+
3
+ /**
4
+ * Whether a Prepr GraphQL response differs per visitor, read from its `Vary`
5
+ * header. Use it when fetching with your own GraphQL client; the toolkit's
6
+ * `createPreprClient` already returns it as `personalized`.
7
+ *
8
+ * Never throws; a response without `Vary` is not personalized.
9
+ */
10
+ declare function isPersonalizedResponse(source: Response | Headers): boolean;
11
+
12
+ /** Error thrown by the token helpers and the segments fetch. */
13
+ declare class PreprError extends Error {
14
+ readonly code: PreprErrorCode;
15
+ readonly context?: string | undefined;
16
+ readonly originalError?: Error | undefined;
17
+ constructor(message: string, code: PreprErrorCode, context?: string | undefined, originalError?: Error | undefined);
18
+ }
19
+ /** Prepr Customer ID, or null if the middleware did not run for this request. */
20
+ declare function getPreprUUIDFromHeaders(headers: Headers): string | null;
21
+ /** Active segment ID, or null when no segment is selected. */
22
+ declare function getActiveSegmentFromHeaders(headers: Headers): string | null;
23
+ /** Active A/B variant (`'A'`/`'B'`), or null when no test is running. */
24
+ declare function getActiveVariantFromHeaders(headers: Headers): string | null;
25
+ /**
26
+ * Collect the Prepr headers into a `PreprHeaders`. Lookups are case-insensitive
27
+ * per the Fetch spec, but the returned keys use the declared casing.
28
+ */
29
+ declare function getPreprHeadersFromHeaders(headers: Headers): PreprHeaders;
30
+ /**
31
+ * Asserts `token` is the full `https://graphql.prepr.io/<token>` URL.
32
+ * @throws PreprError if the token is missing or not an HTTPS URL.
33
+ */
34
+ declare function validatePreprToken(token: string): void;
35
+ /**
36
+ * Pulls the access token out of a GraphQL URL: `https://graphql.prepr.io/abc123`
37
+ * -> `abc123`.
38
+ * @throws PreprError if the URL is not a valid `graphql.prepr.io` URL.
39
+ */
40
+ declare function extractAccessToken(graphqlUrl: string): string;
41
+ /**
42
+ * Fetches the environment's segments from the Prepr API.
43
+ *
44
+ * `token` must be a Prepr GraphQL URL with scope 'segments'.
45
+ * @throws PreprError if the token is invalid or the request fails.
46
+ */
47
+ declare function getPreprEnvironmentSegments(token: string): Promise<PreprSegment[]>;
48
+ /**
49
+ * Never throws: a failed segments fetch yields an empty list so the toolbar
50
+ * still renders. The list is returned under both `segments` and the deprecated
51
+ * `data` alias.
52
+ *
53
+ * Pass the same `features` object you give the toolbar and the middleware: with
54
+ * segments disabled the `_Segments` request is skipped entirely, saving a
55
+ * round-trip per page.
56
+ */
57
+ declare function getToolbarPropsFromHeaders(headers: Headers, token: string, features?: PreprFeatures): Promise<PreprToolbarProps>;
58
+
59
+ export { PreprError as P, getActiveVariantFromHeaders as a, getPreprEnvironmentSegments as b, getPreprHeadersFromHeaders as c, getPreprUUIDFromHeaders as d, extractAccessToken as e, getToolbarPropsFromHeaders as f, getActiveSegmentFromHeaders as g, isPersonalizedResponse as i, validatePreprToken as v };
@@ -0,0 +1,59 @@
1
+ import { a as PreprErrorCode, c as PreprSegment, P as PreprHeaders, b as PreprFeatures, e as PreprToolbarProps } from './types-BYH9XqmN.cjs';
2
+
3
+ /**
4
+ * Whether a Prepr GraphQL response differs per visitor, read from its `Vary`
5
+ * header. Use it when fetching with your own GraphQL client; the toolkit's
6
+ * `createPreprClient` already returns it as `personalized`.
7
+ *
8
+ * Never throws; a response without `Vary` is not personalized.
9
+ */
10
+ declare function isPersonalizedResponse(source: Response | Headers): boolean;
11
+
12
+ /** Error thrown by the token helpers and the segments fetch. */
13
+ declare class PreprError extends Error {
14
+ readonly code: PreprErrorCode;
15
+ readonly context?: string | undefined;
16
+ readonly originalError?: Error | undefined;
17
+ constructor(message: string, code: PreprErrorCode, context?: string | undefined, originalError?: Error | undefined);
18
+ }
19
+ /** Prepr Customer ID, or null if the middleware did not run for this request. */
20
+ declare function getPreprUUIDFromHeaders(headers: Headers): string | null;
21
+ /** Active segment ID, or null when no segment is selected. */
22
+ declare function getActiveSegmentFromHeaders(headers: Headers): string | null;
23
+ /** Active A/B variant (`'A'`/`'B'`), or null when no test is running. */
24
+ declare function getActiveVariantFromHeaders(headers: Headers): string | null;
25
+ /**
26
+ * Collect the Prepr headers into a `PreprHeaders`. Lookups are case-insensitive
27
+ * per the Fetch spec, but the returned keys use the declared casing.
28
+ */
29
+ declare function getPreprHeadersFromHeaders(headers: Headers): PreprHeaders;
30
+ /**
31
+ * Asserts `token` is the full `https://graphql.prepr.io/<token>` URL.
32
+ * @throws PreprError if the token is missing or not an HTTPS URL.
33
+ */
34
+ declare function validatePreprToken(token: string): void;
35
+ /**
36
+ * Pulls the access token out of a GraphQL URL: `https://graphql.prepr.io/abc123`
37
+ * -> `abc123`.
38
+ * @throws PreprError if the URL is not a valid `graphql.prepr.io` URL.
39
+ */
40
+ declare function extractAccessToken(graphqlUrl: string): string;
41
+ /**
42
+ * Fetches the environment's segments from the Prepr API.
43
+ *
44
+ * `token` must be a Prepr GraphQL URL with scope 'segments'.
45
+ * @throws PreprError if the token is invalid or the request fails.
46
+ */
47
+ declare function getPreprEnvironmentSegments(token: string): Promise<PreprSegment[]>;
48
+ /**
49
+ * Never throws: a failed segments fetch yields an empty list so the toolbar
50
+ * still renders. The list is returned under both `segments` and the deprecated
51
+ * `data` alias.
52
+ *
53
+ * Pass the same `features` object you give the toolbar and the middleware: with
54
+ * segments disabled the `_Segments` request is skipped entirely, saving a
55
+ * round-trip per page.
56
+ */
57
+ declare function getToolbarPropsFromHeaders(headers: Headers, token: string, features?: PreprFeatures): Promise<PreprToolbarProps>;
58
+
59
+ export { PreprError as P, getActiveVariantFromHeaders as a, getPreprEnvironmentSegments as b, getPreprHeadersFromHeaders as c, getPreprUUIDFromHeaders as d, extractAccessToken as e, getToolbarPropsFromHeaders as f, getActiveSegmentFromHeaders as g, isPersonalizedResponse as i, validatePreprToken as v };