@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
@@ -2,7 +2,7 @@
2
2
  import { NextResponse } from "next/server";
3
3
 
4
4
  // src/version.ts
5
- var VERSION = "0.5.0-rc.4";
5
+ var VERSION = "0.5.0-rc.6";
6
6
 
7
7
  // src/core/constants.ts
8
8
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -302,14 +302,14 @@ function indexSnapshot(data) {
302
302
  const index = /* @__PURE__ */ new Map();
303
303
  const visited = /* @__PURE__ */ new WeakSet();
304
304
  const path = [];
305
- function walk(node) {
305
+ function walk2(node) {
306
306
  if (node === null || typeof node !== "object") return;
307
307
  if (visited.has(node)) return;
308
308
  visited.add(node);
309
309
  if (Array.isArray(node)) {
310
310
  for (let i = 0; i < node.length; i++) {
311
311
  path.push(i);
312
- walk(node[i]);
312
+ walk2(node[i]);
313
313
  path.pop();
314
314
  }
315
315
  return;
@@ -327,11 +327,11 @@ function indexSnapshot(data) {
327
327
  for (const key in record) {
328
328
  if (!Object.prototype.hasOwnProperty.call(record, key)) continue;
329
329
  path.push(key);
330
- walk(record[key]);
330
+ walk2(record[key]);
331
331
  path.pop();
332
332
  }
333
333
  }
334
- walk(data);
334
+ walk2(data);
335
335
  return index;
336
336
  }
337
337
 
@@ -788,12 +788,12 @@ function resolveFields(selections, typename, doc, options) {
788
788
  }
789
789
  };
790
790
  const applies = (on, list) => conditionMatches(on, typename) || typename !== void 0 && typeConditions(list, doc).includes(typename);
791
- const walk = (list, matched) => {
791
+ const walk2 = (list, matched) => {
792
792
  for (const s of list) {
793
793
  if (s.kind === "field") {
794
794
  add(matched ? exact : loose, s);
795
795
  } else if (s.kind === "inline") {
796
- walk(s.selections, matched && applies(s.on, s.selections));
796
+ walk2(s.selections, matched && applies(s.on, s.selections));
797
797
  } else {
798
798
  const fragment = doc.fragments.get(s.name);
799
799
  if (!fragment) continue;
@@ -801,11 +801,11 @@ function resolveFields(selections, typename, doc, options) {
801
801
  if (walkedMatched.has(fragment)) continue;
802
802
  if (!asMatched && walkedLoose.has(fragment)) continue;
803
803
  (asMatched ? walkedMatched : walkedLoose).add(fragment);
804
- walk(fragment.selections, asMatched);
804
+ walk2(fragment.selections, asMatched);
805
805
  }
806
806
  }
807
807
  };
808
- walk(selections, true);
808
+ walk2(selections, true);
809
809
  if (!options.strict) {
810
810
  for (const [key, field] of loose) {
811
811
  if (!exact.has(key)) exact.set(key, field);
@@ -822,21 +822,21 @@ function typeConditions(selections, doc) {
822
822
  if (hit) return hit;
823
823
  const names = /* @__PURE__ */ new Set();
824
824
  const seen = /* @__PURE__ */ new Set();
825
- const walk = (list) => {
825
+ const walk2 = (list) => {
826
826
  for (const s of list) {
827
827
  if (s.kind === "inline") {
828
828
  if (s.on) names.add(s.on);
829
- walk(s.selections);
829
+ walk2(s.selections);
830
830
  } else if (s.kind === "spread") {
831
831
  const fragment = doc.fragments.get(s.name);
832
832
  if (!fragment || seen.has(fragment)) continue;
833
833
  seen.add(fragment);
834
834
  names.add(fragment.on);
835
- walk(fragment.selections);
835
+ walk2(fragment.selections);
836
836
  }
837
837
  }
838
838
  };
839
- walk(selections);
839
+ walk2(selections);
840
840
  const conditions = [...names];
841
841
  conditionsCache.set(selections, conditions);
842
842
  return conditions;
@@ -988,7 +988,7 @@ function resolveTargets(root, doc, ownerPath, segments) {
988
988
  let current = root;
989
989
  const out = [];
990
990
  const plain = /* @__PURE__ */ new Set();
991
- const walk = (node, sel, i, path) => {
991
+ const walk2 = (node, sel, i, path) => {
992
992
  if (i === segments.length) {
993
993
  out.push(path);
994
994
  return;
@@ -998,10 +998,10 @@ function resolveTargets(root, doc, ownerPath, segments) {
998
998
  if (INDEX_SEGMENT.test(segment)) {
999
999
  const position = Number(segment);
1000
1000
  if (position < node.length) {
1001
- walk(node[position], sel, i + 1, [...path, position]);
1001
+ walk2(node[position], sel, i + 1, [...path, position]);
1002
1002
  }
1003
1003
  } else if (segment === "items") {
1004
- walk(node, sel, i + 1, path);
1004
+ walk2(node, sel, i + 1, path);
1005
1005
  }
1006
1006
  return;
1007
1007
  }
@@ -1034,11 +1034,11 @@ function resolveTargets(root, doc, ownerPath, segments) {
1034
1034
  current = writeAtPath(current, fieldPath, value);
1035
1035
  }
1036
1036
  }
1037
- walk(value, field.selections, i + 1, fieldPath);
1037
+ walk2(value, field.selections, i + 1, fieldPath);
1038
1038
  }
1039
- if (!matched && segment === "items") walk(node, sel, i + 1, path);
1039
+ if (!matched && segment === "items") walk2(node, sel, i + 1, path);
1040
1040
  };
1041
- walk(owner, selections, 0, ownerPath);
1041
+ walk2(owner, selections, 0, ownerPath);
1042
1042
  return { root: current, targets: out, plain };
1043
1043
  }
1044
1044
  var NON_ALPHANUMERIC = /[^a-z0-9]/gi;
@@ -1161,11 +1161,11 @@ function listKeysIn(result) {
1161
1161
  if (!byType) {
1162
1162
  byType = /* @__PURE__ */ new Map();
1163
1163
  const seen = /* @__PURE__ */ new WeakSet();
1164
- const walk = (node) => {
1164
+ const walk2 = (node) => {
1165
1165
  if (node === null || typeof node !== "object" || seen.has(node)) return;
1166
1166
  seen.add(node);
1167
1167
  if (Array.isArray(node)) {
1168
- node.forEach(walk);
1168
+ node.forEach(walk2);
1169
1169
  return;
1170
1170
  }
1171
1171
  const record = node;
@@ -1176,10 +1176,10 @@ function listKeysIn(result) {
1176
1176
  if (!keys) byType.set(type, keys = /* @__PURE__ */ new Set());
1177
1177
  keys.add(key);
1178
1178
  }
1179
- walk(value);
1179
+ walk2(value);
1180
1180
  }
1181
1181
  };
1182
- walk(result);
1182
+ walk2(result);
1183
1183
  listKeysCache.set(result, byType);
1184
1184
  }
1185
1185
  return byType.get(typename) ?? NO_KEYS;
@@ -1221,7 +1221,7 @@ function findEditLink(root) {
1221
1221
  if (linkCache.has(root)) return linkCache.get(root) ?? null;
1222
1222
  let found = null;
1223
1223
  const seen = /* @__PURE__ */ new WeakSet();
1224
- const walk = (node) => {
1224
+ const walk2 = (node) => {
1225
1225
  if (found) return;
1226
1226
  if (typeof node === "string") {
1227
1227
  if (!vercelStegaSplit2(node).encoded) return;
@@ -1236,13 +1236,112 @@ function findEditLink(root) {
1236
1236
  }
1237
1237
  if (node === null || typeof node !== "object" || seen.has(node)) return;
1238
1238
  seen.add(node);
1239
- for (const value of Object.values(node)) walk(value);
1239
+ for (const value of Object.values(node)) walk2(value);
1240
1240
  };
1241
- walk(root);
1241
+ walk2(root);
1242
1242
  linkCache.set(root, found);
1243
1243
  return found;
1244
1244
  }
1245
1245
 
1246
+ // src/core/live-preview/edit-links.ts
1247
+ import {
1248
+ vercelStegaCombine as vercelStegaCombine2,
1249
+ vercelStegaDecode as vercelStegaDecode2,
1250
+ vercelStegaSplit as vercelStegaSplit3
1251
+ } from "@vercel/stega";
1252
+ var ENTRY_PARAM = "entry";
1253
+ var TOP_LEVEL_ENTRY = /^[A-Za-z0-9_]+\.\d+$/;
1254
+ function entryIdOf(element) {
1255
+ if (!isRecord(element)) return void 0;
1256
+ if (typeof element._id === "string") return element._id;
1257
+ if (element.__typename !== "Assets" || !Array.isArray(element.items)) {
1258
+ return void 0;
1259
+ }
1260
+ const first = element.items[0];
1261
+ return isRecord(first) && typeof first._id === "string" ? first._id : void 0;
1262
+ }
1263
+ function isRecord(value) {
1264
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1265
+ }
1266
+ function annotate(value, ctx) {
1267
+ if (!ctx.entryId) return value;
1268
+ const { cleaned, encoded } = vercelStegaSplit3(value);
1269
+ if (!encoded) return value;
1270
+ let payload;
1271
+ try {
1272
+ payload = vercelStegaDecode2(encoded);
1273
+ } catch {
1274
+ return value;
1275
+ }
1276
+ if (typeof payload?.href !== "string") return value;
1277
+ let url;
1278
+ try {
1279
+ url = new URL(payload.href);
1280
+ } catch {
1281
+ return value;
1282
+ }
1283
+ if (url.searchParams.has(ENTRY_PARAM)) return value;
1284
+ url.searchParams.set(ENTRY_PARAM, ctx.entryId);
1285
+ const itemId = decodeURIComponent(url.pathname.split("/").pop() ?? "");
1286
+ if (!url.searchParams.has("field") && ctx.entryField && TOP_LEVEL_ENTRY.test(ctx.entryField) && itemId === ctx.entryOwnerId) {
1287
+ url.searchParams.set("field", ctx.entryField);
1288
+ }
1289
+ return vercelStegaCombine2(
1290
+ cleaned,
1291
+ { ...payload, href: url.toString() },
1292
+ false
1293
+ );
1294
+ }
1295
+ function walk(value, selections, ctx) {
1296
+ if (typeof value === "string") return annotate(value, ctx);
1297
+ if (Array.isArray(value)) {
1298
+ let changed2 = false;
1299
+ const next2 = value.map((element, index) => {
1300
+ const path = [...ctx.path, String(index)];
1301
+ const entryId = ctx.inAssets ? void 0 : entryIdOf(element);
1302
+ const entry = entryId ? {
1303
+ entryId,
1304
+ entryField: ctx.ownerId ? path.join(".") : void 0,
1305
+ entryOwnerId: ctx.ownerId,
1306
+ inAssets: isRecord(element) && element._id === void 0
1307
+ } : {};
1308
+ const out = walk(element, selections, { ...ctx, ...entry, path });
1309
+ if (out !== element) changed2 = true;
1310
+ return out;
1311
+ });
1312
+ return changed2 ? next2 : value;
1313
+ }
1314
+ if (!isRecord(value)) return value;
1315
+ const id = typeof value._id === "string" ? value._id : void 0;
1316
+ const typename = typeof value.__typename === "string" ? value.__typename : void 0;
1317
+ const fields = ctx.doc && selections ? collectFields(selections, typename, ctx.doc) : null;
1318
+ let changed = false;
1319
+ const next = {};
1320
+ for (const [key, child] of Object.entries(value)) {
1321
+ const field = fields?.get(key);
1322
+ const name = field?.name ?? key;
1323
+ const out = walk(child, field?.selections ?? null, {
1324
+ ...ctx,
1325
+ ownerId: id ?? ctx.ownerId,
1326
+ path: id ? [name] : [...ctx.path, name]
1327
+ });
1328
+ if (out !== child) changed = true;
1329
+ next[key] = out;
1330
+ }
1331
+ return changed ? next : value;
1332
+ }
1333
+ function annotateEditLinks(result, query, operationName) {
1334
+ let doc = null;
1335
+ if (query !== void 0) {
1336
+ try {
1337
+ doc = readQueryDocument(query, operationName);
1338
+ } catch {
1339
+ doc = null;
1340
+ }
1341
+ }
1342
+ return walk(result, doc?.operation ?? null, { doc, path: [] });
1343
+ }
1344
+
1246
1345
  // src/nextjs/server.ts
1247
1346
  import * as React from "react";
1248
1347
 
@@ -1483,9 +1582,10 @@ var getPreprLiveLog = cacheForRender(
1483
1582
  );
1484
1583
  async function normalizeQuery(query, result, options = {}) {
1485
1584
  if (!options.enabled) return result;
1585
+ const annotated = annotateEditLinks(result, query, options.operationName);
1486
1586
  const log = await getPreprLiveLog();
1487
- if (!log.length) return result;
1488
- return applyPatchLog(query, result, log, options.operationName);
1587
+ if (!log.length) return annotated;
1588
+ return applyPatchLog(query, annotated, log, options.operationName);
1489
1589
  }
1490
1590
 
1491
1591
  // src/nextjs/index.ts
@@ -1,11 +1,11 @@
1
1
  "use server";
2
2
  import {
3
3
  isPreviewFromHeaders
4
- } from "../chunk-AHBN6FQP.js";
5
- import "../chunk-46ISDRHT.js";
4
+ } from "../chunk-KZIRM54F.js";
5
+ import "../chunk-WHZNCYUS.js";
6
6
  import {
7
7
  parsePatchLog
8
- } from "../chunk-74KY5EAM.js";
8
+ } from "../chunk-KD3GK6TO.js";
9
9
  import "../chunk-S3VT4UWM.js";
10
10
 
11
11
  // src/nextjs/live-action.ts
@@ -1722,12 +1722,15 @@ function useLive(data, opts) {
1722
1722
  }
1723
1723
  function PreprRefresh({
1724
1724
  enabled = false,
1725
+ allowedEditorOrigins: origins,
1725
1726
  strictMode: strict = false
1726
1727
  }) {
1727
1728
  const router = (0, import_navigation.useRouter)();
1729
+ const originsKey = origins?.join(" ");
1728
1730
  (0, import_react.useEffect)(() => {
1729
1731
  if (!enabled || !isFramed()) return;
1730
1732
  if (strict) strictMode = true;
1733
+ if (originsKey) allowedEditorOrigins = originsKey.split(" ");
1731
1734
  const sync = createLogSync();
1732
1735
  let unsubscribe = null;
1733
1736
  let active = true;
@@ -1748,7 +1751,7 @@ function PreprRefresh({
1748
1751
  unsubscribe?.();
1749
1752
  sync.cancel();
1750
1753
  };
1751
- }, [enabled, strict, router]);
1754
+ }, [enabled, originsKey, strict, router]);
1752
1755
  return null;
1753
1756
  }
1754
1757
  var STEGA_CHARS = /[\u200b-\u200d\u2060-\u2064\ufeff]/;
@@ -19,6 +19,8 @@ interface LivePreviewConfig {
19
19
  interface PreprRefreshProps {
20
20
  /** Pass your preview flag; never `true` on a production deployment. */
21
21
  enabled?: boolean;
22
+ /** Exact editor origins, replacing the `*.prepr.io` default. */
23
+ allowedEditorOrigins?: string[];
22
24
  /** Your preview token uses GraphQL strict mode; see the toolbar option. */
23
25
  strictMode?: boolean;
24
26
  }
@@ -47,6 +49,6 @@ declare function useLive<T>(data: T, opts?: UseLiveOptions): T;
47
49
  * Use this or `useLive` with a `query`, not both: a save would refetch and
48
50
  * refresh.
49
51
  */
50
- declare function PreprRefresh({ enabled, strictMode: strict, }: PreprRefreshProps): null;
52
+ declare function PreprRefresh({ enabled, allowedEditorOrigins: origins, strictMode: strict, }: PreprRefreshProps): null;
51
53
 
52
54
  export { type LivePreviewConfig, PreprRefresh, type PreprRefreshProps, type UseLiveOptions, initLivePreview, useLive };
@@ -19,6 +19,8 @@ interface LivePreviewConfig {
19
19
  interface PreprRefreshProps {
20
20
  /** Pass your preview flag; never `true` on a production deployment. */
21
21
  enabled?: boolean;
22
+ /** Exact editor origins, replacing the `*.prepr.io` default. */
23
+ allowedEditorOrigins?: string[];
22
24
  /** Your preview token uses GraphQL strict mode; see the toolbar option. */
23
25
  strictMode?: boolean;
24
26
  }
@@ -47,6 +49,6 @@ declare function useLive<T>(data: T, opts?: UseLiveOptions): T;
47
49
  * Use this or `useLive` with a `query`, not both: a save would refetch and
48
50
  * refresh.
49
51
  */
50
- declare function PreprRefresh({ enabled, strictMode: strict, }: PreprRefreshProps): null;
52
+ declare function PreprRefresh({ enabled, allowedEditorOrigins: origins, strictMode: strict, }: PreprRefreshProps): null;
51
53
 
52
54
  export { type LivePreviewConfig, PreprRefresh, type PreprRefreshProps, type UseLiveOptions, initLivePreview, useLive };
@@ -27,7 +27,7 @@ function isFramed() {
27
27
  return typeof window !== "undefined" && window.self !== window.top;
28
28
  }
29
29
  function startLive() {
30
- starting ?? (starting = import("../live-preview-H4643QYF.js").then(
30
+ starting ?? (starting = import("../live-preview-DLXGXRE5.js").then(
31
31
  ({ createLiveBridge, createLiveStore }) => {
32
32
  const skipped = new Set(quarantined());
33
33
  const started = createLiveStore({
@@ -92,12 +92,15 @@ function useLive(data, opts) {
92
92
  }
93
93
  function PreprRefresh({
94
94
  enabled = false,
95
+ allowedEditorOrigins: origins,
95
96
  strictMode: strict = false
96
97
  }) {
97
98
  const router = useRouter();
99
+ const originsKey = origins?.join(" ");
98
100
  useEffect(() => {
99
101
  if (!enabled || !isFramed()) return;
100
102
  if (strict) strictMode = true;
103
+ if (originsKey) allowedEditorOrigins = originsKey.split(" ");
101
104
  const sync = createLogSync();
102
105
  let unsubscribe = null;
103
106
  let active = true;
@@ -118,7 +121,7 @@ function PreprRefresh({
118
121
  unsubscribe?.();
119
122
  sync.cancel();
120
123
  };
121
- }, [enabled, strict, router]);
124
+ }, [enabled, originsKey, strict, router]);
122
125
  return null;
123
126
  }
124
127
  var STEGA_CHARS = /[\u200b-\u200d\u2060-\u2064\ufeff]/;