@preprio/toolkit 0.5.0-rc.3 → 0.5.0-rc.5
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.
- package/README.md +226 -151
- package/dist/astro/index.cjs +27 -7
- package/dist/astro/index.js +27 -7
- package/dist/{chunk-SXUDBGLZ.js → chunk-3X55JL52.js} +1 -1
- package/dist/{chunk-42Z2VW7G.js → chunk-74KY5EAM.js} +67 -9
- package/dist/{chunk-MDAV2FLM.js → chunk-CMUFTCG3.js} +1 -1
- package/dist/{chunk-PP3O7RB4.js → chunk-SBLZANL5.js} +1 -1
- package/dist/{chunk-6WY3MWCX.js → chunk-TG6N3C22.js} +1 -1
- package/dist/index.cjs +68 -10
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -5
- package/dist/{live-preview-EADA3ZL4.js → live-preview-H4643QYF.js} +2 -2
- package/dist/nextjs/components.cjs +1 -1
- package/dist/nextjs/components.js +2 -2
- package/dist/nextjs/index.cjs +27 -7
- package/dist/nextjs/index.d.cts +2 -0
- package/dist/nextjs/index.d.ts +2 -0
- package/dist/nextjs/index.js +27 -7
- package/dist/nextjs/live-action.js +3 -3
- package/dist/nextjs/live.cjs +73 -12
- package/dist/nextjs/live.d.cts +3 -1
- package/dist/nextjs/live.d.ts +3 -1
- package/dist/nextjs/live.js +5 -2
- package/dist/nuxt/index.cjs +1 -1
- package/dist/nuxt/index.js +1 -1
- package/dist/nuxt/{live-preview-PTEC3GPC.js → live-preview-O2ZTJNW4.js} +67 -9
- package/dist/nuxt/live.cjs +69 -11
- package/dist/nuxt/live.js +1 -1
- package/dist/react/components.cjs +1 -1
- package/dist/react/components.js +1 -1
- package/dist/sveltekit/index.cjs +1 -1
- package/dist/sveltekit/index.js +1 -1
- package/dist/sveltekit/live-preview-O2ZTJNW4.js +1520 -0
- package/dist/sveltekit/live.cjs +1731 -0
- package/dist/sveltekit/live.d.cts +59 -0
- package/dist/sveltekit/live.d.ts +59 -0
- package/dist/sveltekit/live.js +97 -0
- package/package.json +6 -1
package/dist/nextjs/index.d.ts
CHANGED
|
@@ -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
|
}
|
package/dist/nextjs/index.js
CHANGED
|
@@ -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.
|
|
5
|
+
var VERSION = "0.5.0-rc.5";
|
|
6
6
|
|
|
7
7
|
// src/core/constants.ts
|
|
8
8
|
var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
|
|
@@ -281,6 +281,20 @@ var UPPERCASE_BOUNDARY = /(.)(?=[A-Z])/g;
|
|
|
281
281
|
function graphqlFieldName(apiId) {
|
|
282
282
|
return apiId.replace(UPPERCASE_BOUNDARY, "$1_").toLowerCase();
|
|
283
283
|
}
|
|
284
|
+
var TEXT_BODY_FIELDS = [
|
|
285
|
+
{ name: "body", plain: false },
|
|
286
|
+
{ name: "html", plain: false },
|
|
287
|
+
{ name: "text", plain: true }
|
|
288
|
+
];
|
|
289
|
+
var TAG_PATTERN = /<[^>]+>/g;
|
|
290
|
+
function plainTextFromHtml(html) {
|
|
291
|
+
return html.replace(TAG_PATTERN, "");
|
|
292
|
+
}
|
|
293
|
+
function isTextEntry(record) {
|
|
294
|
+
const typename = record.__typename;
|
|
295
|
+
if (typeof typename === "string") return typename === "Text";
|
|
296
|
+
return "html" in record || "text" in record && "format" in record;
|
|
297
|
+
}
|
|
284
298
|
|
|
285
299
|
// src/core/live-preview/index-snapshot.ts
|
|
286
300
|
var debug = createScopedLogger("live-preview");
|
|
@@ -418,7 +432,6 @@ function listKeysOf(entry) {
|
|
|
418
432
|
}
|
|
419
433
|
return keys;
|
|
420
434
|
}
|
|
421
|
-
var TAG_PATTERN = /<[^>]+>/g;
|
|
422
435
|
function buildText(entry, template) {
|
|
423
436
|
const body = typeof entry.body === "string" ? entry.body : "";
|
|
424
437
|
const full = {
|
|
@@ -426,7 +439,7 @@ function buildText(entry, template) {
|
|
|
426
439
|
_id: entry._id,
|
|
427
440
|
body,
|
|
428
441
|
html: body,
|
|
429
|
-
text: body
|
|
442
|
+
text: plainTextFromHtml(body),
|
|
430
443
|
format: entry.format ?? null
|
|
431
444
|
};
|
|
432
445
|
if (!template) return full;
|
|
@@ -886,11 +899,13 @@ function applyPatch(root, index, patch, doc, result) {
|
|
|
886
899
|
const segments = patch.field.split(".");
|
|
887
900
|
if (segments.some((s) => !s || FORBIDDEN_SEGMENTS2.has(s))) return root;
|
|
888
901
|
const targets = [];
|
|
902
|
+
const plain = /* @__PURE__ */ new Set();
|
|
889
903
|
for (const ownerPath of ownerPaths) {
|
|
890
904
|
if (doc) {
|
|
891
905
|
const resolved = resolveTargets(root, doc, ownerPath, segments);
|
|
892
906
|
root = resolved.root;
|
|
893
907
|
targets.push(...resolved.targets);
|
|
908
|
+
resolved.plain.forEach((target) => plain.add(target));
|
|
894
909
|
} else {
|
|
895
910
|
targets.push([...ownerPath, ...segments.map(toPathSegment)]);
|
|
896
911
|
}
|
|
@@ -904,7 +919,8 @@ function applyPatch(root, index, patch, doc, result) {
|
|
|
904
919
|
}
|
|
905
920
|
if (patch.type === "field") {
|
|
906
921
|
for (const target of targets) {
|
|
907
|
-
|
|
922
|
+
const pushed = plain.has(target) && typeof patch.value === "string" ? plainTextFromHtml(patch.value) : patch.value;
|
|
923
|
+
let value = keepEditLink(readAtPath(root, target), pushed);
|
|
908
924
|
if (patch.edit && typeof value === "string" && !vercelStegaSplit2(value).encoded) {
|
|
909
925
|
value = editLinksFor(result, patch.edit.item)?.encode(
|
|
910
926
|
value,
|
|
@@ -968,9 +984,10 @@ function resolveTargets(root, doc, ownerPath, segments) {
|
|
|
968
984
|
owner = owner[step];
|
|
969
985
|
}
|
|
970
986
|
const selections = selectionsAt(root, doc, ownerPath);
|
|
971
|
-
if (!selections) return { root, targets: [] };
|
|
987
|
+
if (!selections) return { root, targets: [], plain: /* @__PURE__ */ new Set() };
|
|
972
988
|
let current = root;
|
|
973
989
|
const out = [];
|
|
990
|
+
const plain = /* @__PURE__ */ new Set();
|
|
974
991
|
const walk = (node, sel, i, path) => {
|
|
975
992
|
if (i === segments.length) {
|
|
976
993
|
out.push(path);
|
|
@@ -991,12 +1008,15 @@ function resolveTargets(root, doc, ownerPath, segments) {
|
|
|
991
1008
|
if (node === null || typeof node !== "object") return;
|
|
992
1009
|
const record = node;
|
|
993
1010
|
const wanted = graphqlFieldName(segment);
|
|
1011
|
+
const textBody = i === segments.length - 1 && segment === "body" && isTextEntry(record) ? TEXT_BODY_FIELDS : null;
|
|
994
1012
|
let matched = false;
|
|
995
1013
|
for (const field of collectFields(sel, typenameOf(node), doc).values()) {
|
|
996
|
-
|
|
1014
|
+
const alias = textBody?.find((f) => f.name === field.name);
|
|
1015
|
+
if (field.name !== segment && field.name !== wanted && !alias) continue;
|
|
997
1016
|
if (!Object.prototype.hasOwnProperty.call(record, field.key)) continue;
|
|
998
1017
|
matched = true;
|
|
999
1018
|
const fieldPath = [...path, field.key];
|
|
1019
|
+
if (alias?.plain) plain.add(fieldPath);
|
|
1000
1020
|
let value = record[field.key];
|
|
1001
1021
|
const next = segments[i + 1];
|
|
1002
1022
|
if (value === null && field.selections.length && next !== void 0 && next !== "items" && !INDEX_SEGMENT.test(next)) {
|
|
@@ -1019,7 +1039,7 @@ function resolveTargets(root, doc, ownerPath, segments) {
|
|
|
1019
1039
|
if (!matched && segment === "items") walk(node, sel, i + 1, path);
|
|
1020
1040
|
};
|
|
1021
1041
|
walk(owner, selections, 0, ownerPath);
|
|
1022
|
-
return { root: current, targets: out };
|
|
1042
|
+
return { root: current, targets: out, plain };
|
|
1023
1043
|
}
|
|
1024
1044
|
var NON_ALPHANUMERIC = /[^a-z0-9]/gi;
|
|
1025
1045
|
var typeKey = (name) => name.replace(NON_ALPHANUMERIC, "").toLowerCase();
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use server";
|
|
2
2
|
import {
|
|
3
3
|
isPreviewFromHeaders
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
4
|
+
} from "../chunk-3X55JL52.js";
|
|
5
|
+
import "../chunk-CMUFTCG3.js";
|
|
6
6
|
import {
|
|
7
7
|
parsePatchLog
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-74KY5EAM.js";
|
|
9
9
|
import "../chunk-S3VT4UWM.js";
|
|
10
10
|
|
|
11
11
|
// src/nextjs/live-action.ts
|
package/dist/nextjs/live.cjs
CHANGED
|
@@ -149,11 +149,25 @@ function fieldKeyIn(record, apiId) {
|
|
|
149
149
|
const name = graphqlFieldName(apiId);
|
|
150
150
|
return Object.prototype.hasOwnProperty.call(record, name) ? name : void 0;
|
|
151
151
|
}
|
|
152
|
-
|
|
152
|
+
function plainTextFromHtml(html) {
|
|
153
|
+
return html.replace(TAG_PATTERN, "");
|
|
154
|
+
}
|
|
155
|
+
function isTextEntry(record) {
|
|
156
|
+
const typename = record.__typename;
|
|
157
|
+
if (typeof typename === "string") return typename === "Text";
|
|
158
|
+
return "html" in record || "text" in record && "format" in record;
|
|
159
|
+
}
|
|
160
|
+
var UPPERCASE_BOUNDARY, TEXT_BODY_FIELDS, TAG_PATTERN;
|
|
153
161
|
var init_field_name = __esm({
|
|
154
162
|
"src/core/live-preview/field-name.ts"() {
|
|
155
163
|
"use strict";
|
|
156
164
|
UPPERCASE_BOUNDARY = /(.)(?=[A-Z])/g;
|
|
165
|
+
TEXT_BODY_FIELDS = [
|
|
166
|
+
{ name: "body", plain: false },
|
|
167
|
+
{ name: "html", plain: false },
|
|
168
|
+
{ name: "text", plain: true }
|
|
169
|
+
];
|
|
170
|
+
TAG_PATTERN = /<[^>]+>/g;
|
|
157
171
|
}
|
|
158
172
|
});
|
|
159
173
|
|
|
@@ -213,13 +227,51 @@ function patchSnapshot(snapshot, index, itemId, field, value) {
|
|
|
213
227
|
if (!paths?.length) return snapshot;
|
|
214
228
|
let root = snapshot;
|
|
215
229
|
let changed = false;
|
|
230
|
+
const markChanged = () => {
|
|
231
|
+
changed = true;
|
|
232
|
+
};
|
|
216
233
|
for (const path of paths) {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
234
|
+
for (const [target, targetValue] of expandTextBody(
|
|
235
|
+
root,
|
|
236
|
+
path,
|
|
237
|
+
field,
|
|
238
|
+
value
|
|
239
|
+
)) {
|
|
240
|
+
root = patchAtPath(root, path, target, targetValue, markChanged);
|
|
241
|
+
}
|
|
220
242
|
}
|
|
221
243
|
return changed ? root : snapshot;
|
|
222
244
|
}
|
|
245
|
+
function expandTextBody(root, path, field, value) {
|
|
246
|
+
const segments = field.split(".");
|
|
247
|
+
if (segments[segments.length - 1] !== "body" || typeof value !== "string") {
|
|
248
|
+
return [[field, value]];
|
|
249
|
+
}
|
|
250
|
+
let node = root;
|
|
251
|
+
for (const step of path) {
|
|
252
|
+
node = node[step];
|
|
253
|
+
}
|
|
254
|
+
for (const segment of segments.slice(0, -1)) {
|
|
255
|
+
if (node === null || typeof node !== "object") return [[field, value]];
|
|
256
|
+
const record2 = node;
|
|
257
|
+
node = INDEX_SEGMENT.test(segment) ? record2[Number(segment)] : record2[fieldKeyIn(record2, segment) ?? segment];
|
|
258
|
+
}
|
|
259
|
+
if (node === null || typeof node !== "object" || Array.isArray(node)) {
|
|
260
|
+
return [[field, value]];
|
|
261
|
+
}
|
|
262
|
+
const record = node;
|
|
263
|
+
if (!isTextEntry(record)) return [[field, value]];
|
|
264
|
+
const prefix = segments.slice(0, -1);
|
|
265
|
+
const writes = [];
|
|
266
|
+
for (const { name, plain } of TEXT_BODY_FIELDS) {
|
|
267
|
+
if (!(name in record)) continue;
|
|
268
|
+
writes.push([
|
|
269
|
+
[...prefix, name].join("."),
|
|
270
|
+
plain ? plainTextFromHtml(value) : value
|
|
271
|
+
]);
|
|
272
|
+
}
|
|
273
|
+
return writes.length ? writes : [[field, value]];
|
|
274
|
+
}
|
|
223
275
|
function patchAtPath(root, path, field, value, markChanged) {
|
|
224
276
|
const segments = field.split(".");
|
|
225
277
|
if (segments.some((s) => FORBIDDEN_SEGMENTS.has(s))) return root;
|
|
@@ -291,7 +343,7 @@ function buildText(entry, template) {
|
|
|
291
343
|
_id: entry._id,
|
|
292
344
|
body,
|
|
293
345
|
html: body,
|
|
294
|
-
text: body
|
|
346
|
+
text: plainTextFromHtml(body),
|
|
295
347
|
format: entry.format ?? null
|
|
296
348
|
};
|
|
297
349
|
if (!template) return full;
|
|
@@ -369,7 +421,7 @@ function keepEditLink(current, value) {
|
|
|
369
421
|
if (!encoded || (0, import_stega.vercelStegaSplit)(value).encoded) return value;
|
|
370
422
|
return value + encoded;
|
|
371
423
|
}
|
|
372
|
-
var import_stega, INDEX_SEGMENT, FORBIDDEN_SEGMENTS
|
|
424
|
+
var import_stega, INDEX_SEGMENT, FORBIDDEN_SEGMENTS;
|
|
373
425
|
var init_patch = __esm({
|
|
374
426
|
"src/core/live-preview/patch.ts"() {
|
|
375
427
|
"use strict";
|
|
@@ -377,7 +429,6 @@ var init_patch = __esm({
|
|
|
377
429
|
init_field_name();
|
|
378
430
|
INDEX_SEGMENT = /^\d+$/;
|
|
379
431
|
FORBIDDEN_SEGMENTS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
|
|
380
|
-
TAG_PATTERN = /<[^>]+>/g;
|
|
381
432
|
}
|
|
382
433
|
});
|
|
383
434
|
|
|
@@ -1193,11 +1244,13 @@ function applyPatch(root, index, patch, doc, result) {
|
|
|
1193
1244
|
const segments = patch.field.split(".");
|
|
1194
1245
|
if (segments.some((s) => !s || FORBIDDEN_SEGMENTS2.has(s))) return root;
|
|
1195
1246
|
const targets = [];
|
|
1247
|
+
const plain = /* @__PURE__ */ new Set();
|
|
1196
1248
|
for (const ownerPath of ownerPaths) {
|
|
1197
1249
|
if (doc) {
|
|
1198
1250
|
const resolved = resolveTargets(root, doc, ownerPath, segments);
|
|
1199
1251
|
root = resolved.root;
|
|
1200
1252
|
targets.push(...resolved.targets);
|
|
1253
|
+
resolved.plain.forEach((target) => plain.add(target));
|
|
1201
1254
|
} else {
|
|
1202
1255
|
targets.push([...ownerPath, ...segments.map(toPathSegment)]);
|
|
1203
1256
|
}
|
|
@@ -1211,7 +1264,8 @@ function applyPatch(root, index, patch, doc, result) {
|
|
|
1211
1264
|
}
|
|
1212
1265
|
if (patch.type === "field") {
|
|
1213
1266
|
for (const target of targets) {
|
|
1214
|
-
|
|
1267
|
+
const pushed = plain.has(target) && typeof patch.value === "string" ? plainTextFromHtml(patch.value) : patch.value;
|
|
1268
|
+
let value = keepEditLink(readAtPath(root, target), pushed);
|
|
1215
1269
|
if (patch.edit && typeof value === "string" && !(0, import_stega2.vercelStegaSplit)(value).encoded) {
|
|
1216
1270
|
value = editLinksFor(result, patch.edit.item)?.encode(
|
|
1217
1271
|
value,
|
|
@@ -1275,9 +1329,10 @@ function resolveTargets(root, doc, ownerPath, segments) {
|
|
|
1275
1329
|
owner = owner[step];
|
|
1276
1330
|
}
|
|
1277
1331
|
const selections = selectionsAt(root, doc, ownerPath);
|
|
1278
|
-
if (!selections) return { root, targets: [] };
|
|
1332
|
+
if (!selections) return { root, targets: [], plain: /* @__PURE__ */ new Set() };
|
|
1279
1333
|
let current = root;
|
|
1280
1334
|
const out = [];
|
|
1335
|
+
const plain = /* @__PURE__ */ new Set();
|
|
1281
1336
|
const walk = (node, sel, i, path) => {
|
|
1282
1337
|
if (i === segments.length) {
|
|
1283
1338
|
out.push(path);
|
|
@@ -1298,12 +1353,15 @@ function resolveTargets(root, doc, ownerPath, segments) {
|
|
|
1298
1353
|
if (node === null || typeof node !== "object") return;
|
|
1299
1354
|
const record = node;
|
|
1300
1355
|
const wanted = graphqlFieldName(segment);
|
|
1356
|
+
const textBody = i === segments.length - 1 && segment === "body" && isTextEntry(record) ? TEXT_BODY_FIELDS : null;
|
|
1301
1357
|
let matched = false;
|
|
1302
1358
|
for (const field of collectFields(sel, typenameOf(node), doc).values()) {
|
|
1303
|
-
|
|
1359
|
+
const alias = textBody?.find((f) => f.name === field.name);
|
|
1360
|
+
if (field.name !== segment && field.name !== wanted && !alias) continue;
|
|
1304
1361
|
if (!Object.prototype.hasOwnProperty.call(record, field.key)) continue;
|
|
1305
1362
|
matched = true;
|
|
1306
1363
|
const fieldPath = [...path, field.key];
|
|
1364
|
+
if (alias?.plain) plain.add(fieldPath);
|
|
1307
1365
|
let value = record[field.key];
|
|
1308
1366
|
const next = segments[i + 1];
|
|
1309
1367
|
if (value === null && field.selections.length && next !== void 0 && next !== "items" && !INDEX_SEGMENT2.test(next)) {
|
|
@@ -1326,7 +1384,7 @@ function resolveTargets(root, doc, ownerPath, segments) {
|
|
|
1326
1384
|
if (!matched && segment === "items") walk(node, sel, i + 1, path);
|
|
1327
1385
|
};
|
|
1328
1386
|
walk(owner, selections, 0, ownerPath);
|
|
1329
|
-
return { root: current, targets: out };
|
|
1387
|
+
return { root: current, targets: out, plain };
|
|
1330
1388
|
}
|
|
1331
1389
|
function resolveTypename(doc, selections, typename, typeName) {
|
|
1332
1390
|
const known = typeConditions(selections, doc);
|
|
@@ -1664,12 +1722,15 @@ function useLive(data, opts) {
|
|
|
1664
1722
|
}
|
|
1665
1723
|
function PreprRefresh({
|
|
1666
1724
|
enabled = false,
|
|
1725
|
+
allowedEditorOrigins: origins,
|
|
1667
1726
|
strictMode: strict = false
|
|
1668
1727
|
}) {
|
|
1669
1728
|
const router = (0, import_navigation.useRouter)();
|
|
1729
|
+
const originsKey = origins?.join(" ");
|
|
1670
1730
|
(0, import_react.useEffect)(() => {
|
|
1671
1731
|
if (!enabled || !isFramed()) return;
|
|
1672
1732
|
if (strict) strictMode = true;
|
|
1733
|
+
if (originsKey) allowedEditorOrigins = originsKey.split(" ");
|
|
1673
1734
|
const sync = createLogSync();
|
|
1674
1735
|
let unsubscribe = null;
|
|
1675
1736
|
let active = true;
|
|
@@ -1690,7 +1751,7 @@ function PreprRefresh({
|
|
|
1690
1751
|
unsubscribe?.();
|
|
1691
1752
|
sync.cancel();
|
|
1692
1753
|
};
|
|
1693
|
-
}, [enabled, strict, router]);
|
|
1754
|
+
}, [enabled, originsKey, strict, router]);
|
|
1694
1755
|
return null;
|
|
1695
1756
|
}
|
|
1696
1757
|
var STEGA_CHARS = /[\u200b-\u200d\u2060-\u2064\ufeff]/;
|
package/dist/nextjs/live.d.cts
CHANGED
|
@@ -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 };
|
package/dist/nextjs/live.d.ts
CHANGED
|
@@ -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 };
|
package/dist/nextjs/live.js
CHANGED
|
@@ -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-
|
|
30
|
+
starting ?? (starting = import("../live-preview-H4643QYF.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]/;
|
package/dist/nuxt/index.cjs
CHANGED
package/dist/nuxt/index.js
CHANGED
|
@@ -112,6 +112,20 @@ function fieldKeyIn(record, apiId) {
|
|
|
112
112
|
const name = graphqlFieldName(apiId);
|
|
113
113
|
return Object.prototype.hasOwnProperty.call(record, name) ? name : void 0;
|
|
114
114
|
}
|
|
115
|
+
var TEXT_BODY_FIELDS = [
|
|
116
|
+
{ name: "body", plain: false },
|
|
117
|
+
{ name: "html", plain: false },
|
|
118
|
+
{ name: "text", plain: true }
|
|
119
|
+
];
|
|
120
|
+
var TAG_PATTERN = /<[^>]+>/g;
|
|
121
|
+
function plainTextFromHtml(html) {
|
|
122
|
+
return html.replace(TAG_PATTERN, "");
|
|
123
|
+
}
|
|
124
|
+
function isTextEntry(record) {
|
|
125
|
+
const typename = record.__typename;
|
|
126
|
+
if (typeof typename === "string") return typename === "Text";
|
|
127
|
+
return "html" in record || "text" in record && "format" in record;
|
|
128
|
+
}
|
|
115
129
|
|
|
116
130
|
// src/core/live-preview/patch.ts
|
|
117
131
|
var INDEX_SEGMENT = /^\d+$/;
|
|
@@ -171,13 +185,51 @@ function patchSnapshot(snapshot, index, itemId, field, value) {
|
|
|
171
185
|
if (!paths?.length) return snapshot;
|
|
172
186
|
let root = snapshot;
|
|
173
187
|
let changed = false;
|
|
188
|
+
const markChanged = () => {
|
|
189
|
+
changed = true;
|
|
190
|
+
};
|
|
174
191
|
for (const path of paths) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
192
|
+
for (const [target, targetValue] of expandTextBody(
|
|
193
|
+
root,
|
|
194
|
+
path,
|
|
195
|
+
field,
|
|
196
|
+
value
|
|
197
|
+
)) {
|
|
198
|
+
root = patchAtPath(root, path, target, targetValue, markChanged);
|
|
199
|
+
}
|
|
178
200
|
}
|
|
179
201
|
return changed ? root : snapshot;
|
|
180
202
|
}
|
|
203
|
+
function expandTextBody(root, path, field, value) {
|
|
204
|
+
const segments = field.split(".");
|
|
205
|
+
if (segments[segments.length - 1] !== "body" || typeof value !== "string") {
|
|
206
|
+
return [[field, value]];
|
|
207
|
+
}
|
|
208
|
+
let node = root;
|
|
209
|
+
for (const step of path) {
|
|
210
|
+
node = node[step];
|
|
211
|
+
}
|
|
212
|
+
for (const segment of segments.slice(0, -1)) {
|
|
213
|
+
if (node === null || typeof node !== "object") return [[field, value]];
|
|
214
|
+
const record2 = node;
|
|
215
|
+
node = INDEX_SEGMENT.test(segment) ? record2[Number(segment)] : record2[fieldKeyIn(record2, segment) ?? segment];
|
|
216
|
+
}
|
|
217
|
+
if (node === null || typeof node !== "object" || Array.isArray(node)) {
|
|
218
|
+
return [[field, value]];
|
|
219
|
+
}
|
|
220
|
+
const record = node;
|
|
221
|
+
if (!isTextEntry(record)) return [[field, value]];
|
|
222
|
+
const prefix = segments.slice(0, -1);
|
|
223
|
+
const writes = [];
|
|
224
|
+
for (const { name, plain } of TEXT_BODY_FIELDS) {
|
|
225
|
+
if (!(name in record)) continue;
|
|
226
|
+
writes.push([
|
|
227
|
+
[...prefix, name].join("."),
|
|
228
|
+
plain ? plainTextFromHtml(value) : value
|
|
229
|
+
]);
|
|
230
|
+
}
|
|
231
|
+
return writes.length ? writes : [[field, value]];
|
|
232
|
+
}
|
|
181
233
|
function patchAtPath(root, path, field, value, markChanged) {
|
|
182
234
|
const segments = field.split(".");
|
|
183
235
|
if (segments.some((s) => FORBIDDEN_SEGMENTS.has(s))) return root;
|
|
@@ -242,7 +294,6 @@ function listKeysOf(entry) {
|
|
|
242
294
|
}
|
|
243
295
|
return keys;
|
|
244
296
|
}
|
|
245
|
-
var TAG_PATTERN = /<[^>]+>/g;
|
|
246
297
|
function buildText(entry, template) {
|
|
247
298
|
const body = typeof entry.body === "string" ? entry.body : "";
|
|
248
299
|
const full = {
|
|
@@ -250,7 +301,7 @@ function buildText(entry, template) {
|
|
|
250
301
|
_id: entry._id,
|
|
251
302
|
body,
|
|
252
303
|
html: body,
|
|
253
|
-
text: body
|
|
304
|
+
text: plainTextFromHtml(body),
|
|
254
305
|
format: entry.format ?? null
|
|
255
306
|
};
|
|
256
307
|
if (!template) return full;
|
|
@@ -1117,11 +1168,13 @@ function applyPatch(root, index, patch, doc, result) {
|
|
|
1117
1168
|
const segments = patch.field.split(".");
|
|
1118
1169
|
if (segments.some((s) => !s || FORBIDDEN_SEGMENTS2.has(s))) return root;
|
|
1119
1170
|
const targets = [];
|
|
1171
|
+
const plain = /* @__PURE__ */ new Set();
|
|
1120
1172
|
for (const ownerPath of ownerPaths) {
|
|
1121
1173
|
if (doc) {
|
|
1122
1174
|
const resolved = resolveTargets(root, doc, ownerPath, segments);
|
|
1123
1175
|
root = resolved.root;
|
|
1124
1176
|
targets.push(...resolved.targets);
|
|
1177
|
+
resolved.plain.forEach((target) => plain.add(target));
|
|
1125
1178
|
} else {
|
|
1126
1179
|
targets.push([...ownerPath, ...segments.map(toPathSegment)]);
|
|
1127
1180
|
}
|
|
@@ -1135,7 +1188,8 @@ function applyPatch(root, index, patch, doc, result) {
|
|
|
1135
1188
|
}
|
|
1136
1189
|
if (patch.type === "field") {
|
|
1137
1190
|
for (const target of targets) {
|
|
1138
|
-
|
|
1191
|
+
const pushed = plain.has(target) && typeof patch.value === "string" ? plainTextFromHtml(patch.value) : patch.value;
|
|
1192
|
+
let value = keepEditLink(readAtPath(root, target), pushed);
|
|
1139
1193
|
if (patch.edit && typeof value === "string" && !vercelStegaSplit2(value).encoded) {
|
|
1140
1194
|
value = editLinksFor(result, patch.edit.item)?.encode(
|
|
1141
1195
|
value,
|
|
@@ -1199,9 +1253,10 @@ function resolveTargets(root, doc, ownerPath, segments) {
|
|
|
1199
1253
|
owner = owner[step];
|
|
1200
1254
|
}
|
|
1201
1255
|
const selections = selectionsAt(root, doc, ownerPath);
|
|
1202
|
-
if (!selections) return { root, targets: [] };
|
|
1256
|
+
if (!selections) return { root, targets: [], plain: /* @__PURE__ */ new Set() };
|
|
1203
1257
|
let current = root;
|
|
1204
1258
|
const out = [];
|
|
1259
|
+
const plain = /* @__PURE__ */ new Set();
|
|
1205
1260
|
const walk = (node, sel, i, path) => {
|
|
1206
1261
|
if (i === segments.length) {
|
|
1207
1262
|
out.push(path);
|
|
@@ -1222,12 +1277,15 @@ function resolveTargets(root, doc, ownerPath, segments) {
|
|
|
1222
1277
|
if (node === null || typeof node !== "object") return;
|
|
1223
1278
|
const record = node;
|
|
1224
1279
|
const wanted = graphqlFieldName(segment);
|
|
1280
|
+
const textBody = i === segments.length - 1 && segment === "body" && isTextEntry(record) ? TEXT_BODY_FIELDS : null;
|
|
1225
1281
|
let matched = false;
|
|
1226
1282
|
for (const field of collectFields(sel, typenameOf(node), doc).values()) {
|
|
1227
|
-
|
|
1283
|
+
const alias = textBody?.find((f) => f.name === field.name);
|
|
1284
|
+
if (field.name !== segment && field.name !== wanted && !alias) continue;
|
|
1228
1285
|
if (!Object.prototype.hasOwnProperty.call(record, field.key)) continue;
|
|
1229
1286
|
matched = true;
|
|
1230
1287
|
const fieldPath = [...path, field.key];
|
|
1288
|
+
if (alias?.plain) plain.add(fieldPath);
|
|
1231
1289
|
let value = record[field.key];
|
|
1232
1290
|
const next = segments[i + 1];
|
|
1233
1291
|
if (value === null && field.selections.length && next !== void 0 && next !== "items" && !INDEX_SEGMENT2.test(next)) {
|
|
@@ -1250,7 +1308,7 @@ function resolveTargets(root, doc, ownerPath, segments) {
|
|
|
1250
1308
|
if (!matched && segment === "items") walk(node, sel, i + 1, path);
|
|
1251
1309
|
};
|
|
1252
1310
|
walk(owner, selections, 0, ownerPath);
|
|
1253
|
-
return { root: current, targets: out };
|
|
1311
|
+
return { root: current, targets: out, plain };
|
|
1254
1312
|
}
|
|
1255
1313
|
var NON_ALPHANUMERIC = /[^a-z0-9]/gi;
|
|
1256
1314
|
var typeKey = (name) => name.replace(NON_ALPHANUMERIC, "").toLowerCase();
|