@preprio/toolkit 0.5.0-rc.4 → 0.5.0-rc.6

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 (45) hide show
  1. package/README.md +337 -165
  2. package/dist/astro/index.cjs +126 -30
  3. package/dist/astro/index.js +130 -30
  4. package/dist/{chunk-TG6N3C22.js → chunk-IPMB32AZ.js} +1 -1
  5. package/dist/{chunk-74KY5EAM.js → chunk-KD3GK6TO.js} +2 -0
  6. package/dist/{chunk-AHBN6FQP.js → chunk-KZIRM54F.js} +1 -1
  7. package/dist/{chunk-PDNCNTDB.js → chunk-L3SDL6MP.js} +11 -3
  8. package/dist/{chunk-46ISDRHT.js → chunk-WHZNCYUS.js} +1 -1
  9. package/dist/codegen/index.cjs +79 -0
  10. package/dist/codegen/index.d.cts +46 -0
  11. package/dist/codegen/index.d.ts +46 -0
  12. package/dist/codegen/index.js +62 -0
  13. package/dist/index.cjs +133 -28
  14. package/dist/index.d.cts +14 -2
  15. package/dist/index.d.ts +14 -2
  16. package/dist/index.js +108 -6
  17. package/dist/{live-preview-H4643QYF.js → live-preview-DLXGXRE5.js} +2 -2
  18. package/dist/nextjs/components.cjs +11 -3
  19. package/dist/nextjs/components.js +2 -2
  20. package/dist/nextjs/index.cjs +124 -28
  21. package/dist/nextjs/index.d.cts +2 -0
  22. package/dist/nextjs/index.d.ts +2 -0
  23. package/dist/nextjs/index.js +128 -28
  24. package/dist/nextjs/live-action.js +3 -3
  25. package/dist/nextjs/live.cjs +4 -1
  26. package/dist/nextjs/live.d.cts +3 -1
  27. package/dist/nextjs/live.d.ts +3 -1
  28. package/dist/nextjs/live.js +5 -2
  29. package/dist/nuxt/chunk-BWPGO25E.js +340 -0
  30. package/dist/nuxt/index.cjs +1 -1
  31. package/dist/nuxt/index.js +1 -1
  32. package/dist/nuxt/{live-preview-O2ZTJNW4.js → live-preview-2RCU35W5.js} +6 -337
  33. package/dist/nuxt/live.cjs +1007 -911
  34. package/dist/nuxt/live.js +109 -5
  35. package/dist/react/components.cjs +11 -3
  36. package/dist/react/components.js +11 -3
  37. package/dist/sveltekit/chunk-BWPGO25E.js +340 -0
  38. package/dist/sveltekit/index.cjs +1 -1
  39. package/dist/sveltekit/index.js +1 -1
  40. package/dist/sveltekit/live-preview-2RCU35W5.js +1189 -0
  41. package/dist/sveltekit/live.cjs +1830 -0
  42. package/dist/sveltekit/live.d.cts +59 -0
  43. package/dist/sveltekit/live.d.ts +59 -0
  44. package/dist/sveltekit/live.js +204 -0
  45. package/package.json +16 -1
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  setTrackingParam,
18
18
  stegaClean,
19
19
  trackEvent
20
- } from "./chunk-PDNCNTDB.js";
20
+ } from "./chunk-L3SDL6MP.js";
21
21
  import {
22
22
  PreprError,
23
23
  extractAccessToken,
@@ -28,20 +28,22 @@ import {
28
28
  getPreprUUIDFromHeaders,
29
29
  getToolbarPropsFromHeaders,
30
30
  validatePreprToken
31
- } from "./chunk-AHBN6FQP.js";
31
+ } from "./chunk-KZIRM54F.js";
32
32
  import {
33
33
  VERSION,
34
34
  resolveFeatures
35
- } from "./chunk-46ISDRHT.js";
35
+ } from "./chunk-WHZNCYUS.js";
36
36
  import {
37
37
  createLiveBridge,
38
38
  createLiveStore
39
- } from "./chunk-TG6N3C22.js";
39
+ } from "./chunk-IPMB32AZ.js";
40
40
  import "./chunk-URXSDJOU.js";
41
41
  import {
42
+ collectFields,
42
43
  normalizeQuery,
43
- parsePatchLog
44
- } from "./chunk-74KY5EAM.js";
44
+ parsePatchLog,
45
+ readQueryDocument
46
+ } from "./chunk-KD3GK6TO.js";
45
47
  import {
46
48
  createScopedLogger
47
49
  } from "./chunk-S3VT4UWM.js";
@@ -59,6 +61,105 @@ function previewAttrs(target, options) {
59
61
  return attrs;
60
62
  }
61
63
 
64
+ // src/core/live-preview/edit-links.ts
65
+ import {
66
+ vercelStegaCombine,
67
+ vercelStegaDecode,
68
+ vercelStegaSplit
69
+ } from "@vercel/stega";
70
+ var ENTRY_PARAM = "entry";
71
+ var TOP_LEVEL_ENTRY = /^[A-Za-z0-9_]+\.\d+$/;
72
+ function entryIdOf(element) {
73
+ if (!isRecord(element)) return void 0;
74
+ if (typeof element._id === "string") return element._id;
75
+ if (element.__typename !== "Assets" || !Array.isArray(element.items)) {
76
+ return void 0;
77
+ }
78
+ const first = element.items[0];
79
+ return isRecord(first) && typeof first._id === "string" ? first._id : void 0;
80
+ }
81
+ function isRecord(value) {
82
+ return typeof value === "object" && value !== null && !Array.isArray(value);
83
+ }
84
+ function annotate(value, ctx) {
85
+ if (!ctx.entryId) return value;
86
+ const { cleaned, encoded } = vercelStegaSplit(value);
87
+ if (!encoded) return value;
88
+ let payload;
89
+ try {
90
+ payload = vercelStegaDecode(encoded);
91
+ } catch {
92
+ return value;
93
+ }
94
+ if (typeof payload?.href !== "string") return value;
95
+ let url;
96
+ try {
97
+ url = new URL(payload.href);
98
+ } catch {
99
+ return value;
100
+ }
101
+ if (url.searchParams.has(ENTRY_PARAM)) return value;
102
+ url.searchParams.set(ENTRY_PARAM, ctx.entryId);
103
+ const itemId = decodeURIComponent(url.pathname.split("/").pop() ?? "");
104
+ if (!url.searchParams.has("field") && ctx.entryField && TOP_LEVEL_ENTRY.test(ctx.entryField) && itemId === ctx.entryOwnerId) {
105
+ url.searchParams.set("field", ctx.entryField);
106
+ }
107
+ return vercelStegaCombine(
108
+ cleaned,
109
+ { ...payload, href: url.toString() },
110
+ false
111
+ );
112
+ }
113
+ function walk(value, selections, ctx) {
114
+ if (typeof value === "string") return annotate(value, ctx);
115
+ if (Array.isArray(value)) {
116
+ let changed2 = false;
117
+ const next2 = value.map((element, index) => {
118
+ const path = [...ctx.path, String(index)];
119
+ const entryId = ctx.inAssets ? void 0 : entryIdOf(element);
120
+ const entry = entryId ? {
121
+ entryId,
122
+ entryField: ctx.ownerId ? path.join(".") : void 0,
123
+ entryOwnerId: ctx.ownerId,
124
+ inAssets: isRecord(element) && element._id === void 0
125
+ } : {};
126
+ const out = walk(element, selections, { ...ctx, ...entry, path });
127
+ if (out !== element) changed2 = true;
128
+ return out;
129
+ });
130
+ return changed2 ? next2 : value;
131
+ }
132
+ if (!isRecord(value)) return value;
133
+ const id = typeof value._id === "string" ? value._id : void 0;
134
+ const typename = typeof value.__typename === "string" ? value.__typename : void 0;
135
+ const fields = ctx.doc && selections ? collectFields(selections, typename, ctx.doc) : null;
136
+ let changed = false;
137
+ const next = {};
138
+ for (const [key, child] of Object.entries(value)) {
139
+ const field = fields?.get(key);
140
+ const name = field?.name ?? key;
141
+ const out = walk(child, field?.selections ?? null, {
142
+ ...ctx,
143
+ ownerId: id ?? ctx.ownerId,
144
+ path: id ? [name] : [...ctx.path, name]
145
+ });
146
+ if (out !== child) changed = true;
147
+ next[key] = out;
148
+ }
149
+ return changed ? next : value;
150
+ }
151
+ function annotateEditLinks(result, query, operationName) {
152
+ let doc = null;
153
+ if (query !== void 0) {
154
+ try {
155
+ doc = readQueryDocument(query, operationName);
156
+ } catch {
157
+ doc = null;
158
+ }
159
+ }
160
+ return walk(result, doc?.operation ?? null, { doc, path: [] });
161
+ }
162
+
62
163
  // src/core/live-preview/morph.ts
63
164
  function morphElement(current, next) {
64
165
  syncAttributes(current, next);
@@ -376,6 +477,7 @@ export {
376
477
  PreprError,
377
478
  PreprToolbarElement,
378
479
  VERSION,
480
+ annotateEditLinks,
379
481
  createPreprPreview,
380
482
  createToolbarStore,
381
483
  definePreprToolbar,
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  createLiveBridge,
3
3
  createLiveStore
4
- } from "./chunk-TG6N3C22.js";
4
+ } from "./chunk-IPMB32AZ.js";
5
5
  import "./chunk-URXSDJOU.js";
6
6
  import {
7
7
  applyPatchLog,
8
8
  normalizeQuery,
9
9
  parsePatchLog
10
- } from "./chunk-74KY5EAM.js";
10
+ } from "./chunk-KD3GK6TO.js";
11
11
  import "./chunk-S3VT4UWM.js";
12
12
  export {
13
13
  applyPatchLog,
@@ -537,6 +537,7 @@ function decodeStega(str) {
537
537
 
538
538
  // src/core/stega/dom.ts
539
539
  var IGNORED_ANCESTORS = "script, style, noscript";
540
+ var AUTO_ENTRY_ATTR = "data-prepr-entry-auto";
540
541
  function isIgnoredTextNode(node) {
541
542
  if (node.parentElement?.closest(IGNORED_ANCESTORS)) return true;
542
543
  return !node.textContent?.trim();
@@ -570,7 +571,9 @@ function parseEditHref(href) {
570
571
  return {
571
572
  id: url.pathname.split("/").pop() || void 0,
572
573
  field: url.searchParams.get("field") || void 0,
573
- locale: url.searchParams.get("locale") || void 0
574
+ locale: url.searchParams.get("locale") || void 0,
575
+ // Added by the toolkit's `annotateEditLinks`, not by Prepr.
576
+ entry: url.searchParams.get("entry") || void 0
574
577
  };
575
578
  } catch {
576
579
  return {};
@@ -587,11 +590,16 @@ function tagEncodedElement(element, decoded) {
587
590
  element.setAttribute("data-prepr-encoded", "");
588
591
  element.setAttribute("data-prepr-href", decoded.href);
589
592
  element.setAttribute("data-prepr-origin", decoded.origin);
590
- const { id, field, locale } = parseEditHref(decoded.href);
593
+ const { id, field, locale, entry } = parseEditHref(decoded.href);
591
594
  setOrRemove(element, "data-prepr-id", id);
592
595
  const fieldHint = element.getAttribute("data-prepr-edit-target")?.trim() || void 0;
593
596
  setOrRemove(element, "data-prepr-field", field ?? fieldHint);
594
597
  setOrRemove(element, "data-prepr-locale", locale);
598
+ const siteEntry = element.hasAttribute("data-prepr-entry-id") && !element.hasAttribute(AUTO_ENTRY_ATTR);
599
+ if (!siteEntry) {
600
+ setOrRemove(element, "data-prepr-entry-id", entry);
601
+ setOrRemove(element, AUTO_ENTRY_ATTR, entry && "true");
602
+ }
595
603
  }
596
604
  function readEditPayload(element) {
597
605
  return {
@@ -3517,7 +3525,7 @@ function createPreprPreview(opts = {}) {
3517
3525
  var import_react = require("react");
3518
3526
 
3519
3527
  // src/version.ts
3520
- var VERSION = "0.5.0-rc.4";
3528
+ var VERSION = "0.5.0-rc.6";
3521
3529
 
3522
3530
  // src/core/pixel.ts
3523
3531
  var PIXEL_SCRIPT_URL = "https://cdn.tracking.prepr.io/js/prepr.min.js";
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  createPreprPreview,
4
4
  loadTrackingPixel
5
- } from "../chunk-PDNCNTDB.js";
6
- import "../chunk-46ISDRHT.js";
5
+ } from "../chunk-L3SDL6MP.js";
6
+ import "../chunk-WHZNCYUS.js";
7
7
  import "../chunk-URXSDJOU.js";
8
8
  import "../chunk-S3VT4UWM.js";
9
9
 
@@ -49,7 +49,7 @@ module.exports = __toCommonJS(nextjs_exports);
49
49
  var import_server = require("next/server");
50
50
 
51
51
  // src/version.ts
52
- var VERSION = "0.5.0-rc.4";
52
+ var VERSION = "0.5.0-rc.6";
53
53
 
54
54
  // src/core/constants.ts
55
55
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -345,14 +345,14 @@ function indexSnapshot(data) {
345
345
  const index = /* @__PURE__ */ new Map();
346
346
  const visited = /* @__PURE__ */ new WeakSet();
347
347
  const path = [];
348
- function walk(node) {
348
+ function walk2(node) {
349
349
  if (node === null || typeof node !== "object") return;
350
350
  if (visited.has(node)) return;
351
351
  visited.add(node);
352
352
  if (Array.isArray(node)) {
353
353
  for (let i = 0; i < node.length; i++) {
354
354
  path.push(i);
355
- walk(node[i]);
355
+ walk2(node[i]);
356
356
  path.pop();
357
357
  }
358
358
  return;
@@ -370,11 +370,11 @@ function indexSnapshot(data) {
370
370
  for (const key in record) {
371
371
  if (!Object.prototype.hasOwnProperty.call(record, key)) continue;
372
372
  path.push(key);
373
- walk(record[key]);
373
+ walk2(record[key]);
374
374
  path.pop();
375
375
  }
376
376
  }
377
- walk(data);
377
+ walk2(data);
378
378
  return index;
379
379
  }
380
380
 
@@ -831,12 +831,12 @@ function resolveFields(selections, typename, doc, options) {
831
831
  }
832
832
  };
833
833
  const applies = (on, list) => conditionMatches(on, typename) || typename !== void 0 && typeConditions(list, doc).includes(typename);
834
- const walk = (list, matched) => {
834
+ const walk2 = (list, matched) => {
835
835
  for (const s of list) {
836
836
  if (s.kind === "field") {
837
837
  add(matched ? exact : loose, s);
838
838
  } else if (s.kind === "inline") {
839
- walk(s.selections, matched && applies(s.on, s.selections));
839
+ walk2(s.selections, matched && applies(s.on, s.selections));
840
840
  } else {
841
841
  const fragment = doc.fragments.get(s.name);
842
842
  if (!fragment) continue;
@@ -844,11 +844,11 @@ function resolveFields(selections, typename, doc, options) {
844
844
  if (walkedMatched.has(fragment)) continue;
845
845
  if (!asMatched && walkedLoose.has(fragment)) continue;
846
846
  (asMatched ? walkedMatched : walkedLoose).add(fragment);
847
- walk(fragment.selections, asMatched);
847
+ walk2(fragment.selections, asMatched);
848
848
  }
849
849
  }
850
850
  };
851
- walk(selections, true);
851
+ walk2(selections, true);
852
852
  if (!options.strict) {
853
853
  for (const [key, field] of loose) {
854
854
  if (!exact.has(key)) exact.set(key, field);
@@ -865,21 +865,21 @@ function typeConditions(selections, doc) {
865
865
  if (hit) return hit;
866
866
  const names = /* @__PURE__ */ new Set();
867
867
  const seen = /* @__PURE__ */ new Set();
868
- const walk = (list) => {
868
+ const walk2 = (list) => {
869
869
  for (const s of list) {
870
870
  if (s.kind === "inline") {
871
871
  if (s.on) names.add(s.on);
872
- walk(s.selections);
872
+ walk2(s.selections);
873
873
  } else if (s.kind === "spread") {
874
874
  const fragment = doc.fragments.get(s.name);
875
875
  if (!fragment || seen.has(fragment)) continue;
876
876
  seen.add(fragment);
877
877
  names.add(fragment.on);
878
- walk(fragment.selections);
878
+ walk2(fragment.selections);
879
879
  }
880
880
  }
881
881
  };
882
- walk(selections);
882
+ walk2(selections);
883
883
  const conditions = [...names];
884
884
  conditionsCache.set(selections, conditions);
885
885
  return conditions;
@@ -1031,7 +1031,7 @@ function resolveTargets(root, doc, ownerPath, segments) {
1031
1031
  let current = root;
1032
1032
  const out = [];
1033
1033
  const plain = /* @__PURE__ */ new Set();
1034
- const walk = (node, sel, i, path) => {
1034
+ const walk2 = (node, sel, i, path) => {
1035
1035
  if (i === segments.length) {
1036
1036
  out.push(path);
1037
1037
  return;
@@ -1041,10 +1041,10 @@ function resolveTargets(root, doc, ownerPath, segments) {
1041
1041
  if (INDEX_SEGMENT.test(segment)) {
1042
1042
  const position = Number(segment);
1043
1043
  if (position < node.length) {
1044
- walk(node[position], sel, i + 1, [...path, position]);
1044
+ walk2(node[position], sel, i + 1, [...path, position]);
1045
1045
  }
1046
1046
  } else if (segment === "items") {
1047
- walk(node, sel, i + 1, path);
1047
+ walk2(node, sel, i + 1, path);
1048
1048
  }
1049
1049
  return;
1050
1050
  }
@@ -1077,11 +1077,11 @@ function resolveTargets(root, doc, ownerPath, segments) {
1077
1077
  current = writeAtPath(current, fieldPath, value);
1078
1078
  }
1079
1079
  }
1080
- walk(value, field.selections, i + 1, fieldPath);
1080
+ walk2(value, field.selections, i + 1, fieldPath);
1081
1081
  }
1082
- if (!matched && segment === "items") walk(node, sel, i + 1, path);
1082
+ if (!matched && segment === "items") walk2(node, sel, i + 1, path);
1083
1083
  };
1084
- walk(owner, selections, 0, ownerPath);
1084
+ walk2(owner, selections, 0, ownerPath);
1085
1085
  return { root: current, targets: out, plain };
1086
1086
  }
1087
1087
  var NON_ALPHANUMERIC = /[^a-z0-9]/gi;
@@ -1204,11 +1204,11 @@ function listKeysIn(result) {
1204
1204
  if (!byType) {
1205
1205
  byType = /* @__PURE__ */ new Map();
1206
1206
  const seen = /* @__PURE__ */ new WeakSet();
1207
- const walk = (node) => {
1207
+ const walk2 = (node) => {
1208
1208
  if (node === null || typeof node !== "object" || seen.has(node)) return;
1209
1209
  seen.add(node);
1210
1210
  if (Array.isArray(node)) {
1211
- node.forEach(walk);
1211
+ node.forEach(walk2);
1212
1212
  return;
1213
1213
  }
1214
1214
  const record = node;
@@ -1219,10 +1219,10 @@ function listKeysIn(result) {
1219
1219
  if (!keys) byType.set(type, keys = /* @__PURE__ */ new Set());
1220
1220
  keys.add(key);
1221
1221
  }
1222
- walk(value);
1222
+ walk2(value);
1223
1223
  }
1224
1224
  };
1225
- walk(result);
1225
+ walk2(result);
1226
1226
  listKeysCache.set(result, byType);
1227
1227
  }
1228
1228
  return byType.get(typename) ?? NO_KEYS;
@@ -1264,7 +1264,7 @@ function findEditLink(root) {
1264
1264
  if (linkCache.has(root)) return linkCache.get(root) ?? null;
1265
1265
  let found = null;
1266
1266
  const seen = /* @__PURE__ */ new WeakSet();
1267
- const walk = (node) => {
1267
+ const walk2 = (node) => {
1268
1268
  if (found) return;
1269
1269
  if (typeof node === "string") {
1270
1270
  if (!(0, import_stega2.vercelStegaSplit)(node).encoded) return;
@@ -1279,13 +1279,108 @@ function findEditLink(root) {
1279
1279
  }
1280
1280
  if (node === null || typeof node !== "object" || seen.has(node)) return;
1281
1281
  seen.add(node);
1282
- for (const value of Object.values(node)) walk(value);
1282
+ for (const value of Object.values(node)) walk2(value);
1283
1283
  };
1284
- walk(root);
1284
+ walk2(root);
1285
1285
  linkCache.set(root, found);
1286
1286
  return found;
1287
1287
  }
1288
1288
 
1289
+ // src/core/live-preview/edit-links.ts
1290
+ var import_stega3 = require("@vercel/stega");
1291
+ var ENTRY_PARAM = "entry";
1292
+ var TOP_LEVEL_ENTRY = /^[A-Za-z0-9_]+\.\d+$/;
1293
+ function entryIdOf(element) {
1294
+ if (!isRecord(element)) return void 0;
1295
+ if (typeof element._id === "string") return element._id;
1296
+ if (element.__typename !== "Assets" || !Array.isArray(element.items)) {
1297
+ return void 0;
1298
+ }
1299
+ const first = element.items[0];
1300
+ return isRecord(first) && typeof first._id === "string" ? first._id : void 0;
1301
+ }
1302
+ function isRecord(value) {
1303
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1304
+ }
1305
+ function annotate(value, ctx) {
1306
+ if (!ctx.entryId) return value;
1307
+ const { cleaned, encoded } = (0, import_stega3.vercelStegaSplit)(value);
1308
+ if (!encoded) return value;
1309
+ let payload;
1310
+ try {
1311
+ payload = (0, import_stega3.vercelStegaDecode)(encoded);
1312
+ } catch {
1313
+ return value;
1314
+ }
1315
+ if (typeof payload?.href !== "string") return value;
1316
+ let url;
1317
+ try {
1318
+ url = new URL(payload.href);
1319
+ } catch {
1320
+ return value;
1321
+ }
1322
+ if (url.searchParams.has(ENTRY_PARAM)) return value;
1323
+ url.searchParams.set(ENTRY_PARAM, ctx.entryId);
1324
+ const itemId = decodeURIComponent(url.pathname.split("/").pop() ?? "");
1325
+ if (!url.searchParams.has("field") && ctx.entryField && TOP_LEVEL_ENTRY.test(ctx.entryField) && itemId === ctx.entryOwnerId) {
1326
+ url.searchParams.set("field", ctx.entryField);
1327
+ }
1328
+ return (0, import_stega3.vercelStegaCombine)(
1329
+ cleaned,
1330
+ { ...payload, href: url.toString() },
1331
+ false
1332
+ );
1333
+ }
1334
+ function walk(value, selections, ctx) {
1335
+ if (typeof value === "string") return annotate(value, ctx);
1336
+ if (Array.isArray(value)) {
1337
+ let changed2 = false;
1338
+ const next2 = value.map((element, index) => {
1339
+ const path = [...ctx.path, String(index)];
1340
+ const entryId = ctx.inAssets ? void 0 : entryIdOf(element);
1341
+ const entry = entryId ? {
1342
+ entryId,
1343
+ entryField: ctx.ownerId ? path.join(".") : void 0,
1344
+ entryOwnerId: ctx.ownerId,
1345
+ inAssets: isRecord(element) && element._id === void 0
1346
+ } : {};
1347
+ const out = walk(element, selections, { ...ctx, ...entry, path });
1348
+ if (out !== element) changed2 = true;
1349
+ return out;
1350
+ });
1351
+ return changed2 ? next2 : value;
1352
+ }
1353
+ if (!isRecord(value)) return value;
1354
+ const id = typeof value._id === "string" ? value._id : void 0;
1355
+ const typename = typeof value.__typename === "string" ? value.__typename : void 0;
1356
+ const fields = ctx.doc && selections ? collectFields(selections, typename, ctx.doc) : null;
1357
+ let changed = false;
1358
+ const next = {};
1359
+ for (const [key, child] of Object.entries(value)) {
1360
+ const field = fields?.get(key);
1361
+ const name = field?.name ?? key;
1362
+ const out = walk(child, field?.selections ?? null, {
1363
+ ...ctx,
1364
+ ownerId: id ?? ctx.ownerId,
1365
+ path: id ? [name] : [...ctx.path, name]
1366
+ });
1367
+ if (out !== child) changed = true;
1368
+ next[key] = out;
1369
+ }
1370
+ return changed ? next : value;
1371
+ }
1372
+ function annotateEditLinks(result, query, operationName) {
1373
+ let doc = null;
1374
+ if (query !== void 0) {
1375
+ try {
1376
+ doc = readQueryDocument(query, operationName);
1377
+ } catch {
1378
+ doc = null;
1379
+ }
1380
+ }
1381
+ return walk(result, doc?.operation ?? null, { doc, path: [] });
1382
+ }
1383
+
1289
1384
  // src/nextjs/server.ts
1290
1385
  var React = __toESM(require("react"), 1);
1291
1386
 
@@ -1526,9 +1621,10 @@ var getPreprLiveLog = cacheForRender(
1526
1621
  );
1527
1622
  async function normalizeQuery(query, result, options = {}) {
1528
1623
  if (!options.enabled) return result;
1624
+ const annotated = annotateEditLinks(result, query, options.operationName);
1529
1625
  const log = await getPreprLiveLog();
1530
- if (!log.length) return result;
1531
- return applyPatchLog(query, result, log, options.operationName);
1626
+ if (!log.length) return annotated;
1627
+ return applyPatchLog(query, annotated, log, options.operationName);
1532
1628
  }
1533
1629
 
1534
1630
  // src/nextjs/index.ts
@@ -311,6 +311,8 @@ interface LivePreviewConfig {
311
311
  interface PreprRefreshProps {
312
312
  /** Pass your preview flag; never `true` on a production deployment. */
313
313
  enabled?: boolean;
314
+ /** Exact editor origins, replacing the `*.prepr.io` default. */
315
+ allowedEditorOrigins?: string[];
314
316
  /** Your preview token uses GraphQL strict mode; see the toolbar option. */
315
317
  strictMode?: boolean;
316
318
  }
@@ -311,6 +311,8 @@ interface LivePreviewConfig {
311
311
  interface PreprRefreshProps {
312
312
  /** Pass your preview flag; never `true` on a production deployment. */
313
313
  enabled?: boolean;
314
+ /** Exact editor origins, replacing the `*.prepr.io` default. */
315
+ allowedEditorOrigins?: string[];
314
316
  /** Your preview token uses GraphQL strict mode; see the toolbar option. */
315
317
  strictMode?: boolean;
316
318
  }