@preprio/toolkit 0.5.0-rc.1 → 0.5.0-rc.11
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 +430 -23
- package/dist/astro/index.cjs +1290 -1
- package/dist/astro/index.d.cts +47 -1
- package/dist/astro/index.d.ts +47 -1
- package/dist/astro/index.js +1297 -1
- package/dist/{chunk-4JNKYIEV.js → chunk-6423Q744.js} +1449 -642
- package/dist/chunk-AOHA5INA.js +26 -0
- package/dist/chunk-IPMB32AZ.js +246 -0
- package/dist/chunk-KD3GK6TO.js +1221 -0
- package/dist/chunk-QSXIHRH4.js +184 -0
- package/dist/chunk-S3VT4UWM.js +75 -0
- package/dist/chunk-URXSDJOU.js +356 -0
- package/dist/codegen/index.cjs +82 -0
- package/dist/codegen/index.d.cts +70 -0
- package/dist/codegen/index.d.ts +70 -0
- package/dist/codegen/index.js +64 -0
- package/dist/index.cjs +3367 -416
- package/dist/index.d.cts +276 -5
- package/dist/index.d.ts +276 -5
- package/dist/index.js +307 -144
- package/dist/live-preview-DLXGXRE5.js +18 -0
- package/dist/nextjs/components.cjs +1608 -386
- package/dist/nextjs/components.d.cts +1 -1
- package/dist/nextjs/components.d.ts +1 -1
- package/dist/nextjs/components.js +4 -1
- package/dist/nextjs/index.cjs +1181 -6
- package/dist/nextjs/index.d.cts +83 -3
- package/dist/nextjs/index.d.ts +83 -3
- package/dist/nextjs/index.js +1179 -7
- package/dist/nextjs/live-action.cjs +285 -0
- package/dist/nextjs/live-action.d.cts +12 -0
- package/dist/nextjs/live-action.d.ts +12 -0
- package/dist/nextjs/live-action.js +68 -0
- package/dist/nextjs/live.cjs +1899 -0
- package/dist/nextjs/live.d.cts +54 -0
- package/dist/nextjs/live.d.ts +54 -0
- package/dist/nextjs/live.js +268 -0
- package/dist/nuxt/chunk-BWPGO25E.js +340 -0
- package/dist/nuxt/index.cjs +1 -1
- package/dist/nuxt/index.js +1 -1
- package/dist/nuxt/live-preview-2RCU35W5.js +1189 -0
- package/dist/nuxt/live.cjs +1816 -0
- package/dist/nuxt/live.d.cts +43 -0
- package/dist/nuxt/live.d.ts +43 -0
- package/dist/nuxt/live.js +198 -0
- package/dist/{pixel-e1fUWl2Y.d.cts → pixel-CX422dCO.d.cts} +18 -3
- package/dist/{pixel-e1fUWl2Y.d.ts → pixel-CX422dCO.d.ts} +18 -3
- package/dist/react/components.cjs +1608 -386
- package/dist/react/components.d.cts +17 -2
- package/dist/react/components.d.ts +17 -2
- package/dist/react/components.js +1608 -386
- package/dist/sveltekit/chunk-BWPGO25E.js +340 -0
- package/dist/sveltekit/index.cjs +1 -1
- package/dist/sveltekit/index.js +1 -1
- package/dist/sveltekit/live-preview-2RCU35W5.js +1189 -0
- package/dist/sveltekit/live.cjs +1830 -0
- package/dist/sveltekit/live.d.cts +59 -0
- package/dist/sveltekit/live.d.ts +59 -0
- package/dist/sveltekit/live.js +204 -0
- package/package.json +37 -11
- package/src/astro/PreprToolbar.astro +7 -1
package/dist/index.js
CHANGED
|
@@ -4,185 +4,341 @@ import {
|
|
|
4
4
|
COOKIE_SEGMENT,
|
|
5
5
|
COOKIE_UID,
|
|
6
6
|
COOKIE_VARIANT,
|
|
7
|
+
HEADER_LIVE_RENDER,
|
|
7
8
|
ONE_YEAR_SECONDS,
|
|
8
9
|
PARAM_HIDE_BAR,
|
|
9
10
|
PARAM_SEGMENT,
|
|
10
11
|
PARAM_VARIANT,
|
|
11
12
|
PreprToolbarElement,
|
|
12
|
-
VERSION,
|
|
13
13
|
createPreprPreview,
|
|
14
14
|
createToolbarStore,
|
|
15
|
+
decodeStega,
|
|
15
16
|
definePreprToolbar,
|
|
16
17
|
loadTrackingPixel,
|
|
17
|
-
resolveFeatures,
|
|
18
18
|
setTrackingParam,
|
|
19
19
|
stegaClean,
|
|
20
20
|
trackEvent
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-6423Q744.js";
|
|
22
|
+
import {
|
|
23
|
+
PreprError,
|
|
24
|
+
extractAccessToken,
|
|
25
|
+
getActiveSegmentFromHeaders,
|
|
26
|
+
getActiveVariantFromHeaders,
|
|
27
|
+
getPreprEnvironmentSegments,
|
|
28
|
+
getPreprHeadersFromHeaders,
|
|
29
|
+
getPreprUUIDFromHeaders,
|
|
30
|
+
getToolbarPropsFromHeaders,
|
|
31
|
+
validatePreprToken
|
|
32
|
+
} from "./chunk-QSXIHRH4.js";
|
|
33
|
+
import {
|
|
34
|
+
VERSION,
|
|
35
|
+
resolveFeatures
|
|
36
|
+
} from "./chunk-AOHA5INA.js";
|
|
37
|
+
import {
|
|
38
|
+
createLiveBridge,
|
|
39
|
+
createLiveStore
|
|
40
|
+
} from "./chunk-IPMB32AZ.js";
|
|
41
|
+
import "./chunk-URXSDJOU.js";
|
|
42
|
+
import {
|
|
43
|
+
collectFields,
|
|
44
|
+
normalizeQuery,
|
|
45
|
+
parsePatchLog,
|
|
46
|
+
readQueryDocument
|
|
47
|
+
} from "./chunk-KD3GK6TO.js";
|
|
48
|
+
import {
|
|
49
|
+
createScopedLogger
|
|
50
|
+
} from "./chunk-S3VT4UWM.js";
|
|
22
51
|
|
|
23
|
-
// src/core/
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
this.name = "PreprError";
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
function getPreprUUIDFromHeaders(headers) {
|
|
34
|
-
return headers.get("prepr-customer-id");
|
|
35
|
-
}
|
|
36
|
-
function getActiveSegmentFromHeaders(headers) {
|
|
37
|
-
return headers.get("Prepr-Segments");
|
|
38
|
-
}
|
|
39
|
-
function getActiveVariantFromHeaders(headers) {
|
|
40
|
-
return headers.get("Prepr-ABtesting");
|
|
41
|
-
}
|
|
42
|
-
var PREPR_HEADER_KEYS = [
|
|
43
|
-
"prepr-customer-id",
|
|
44
|
-
"Prepr-Segments",
|
|
45
|
-
"Prepr-ABtesting",
|
|
46
|
-
"Prepr-Preview-Bar",
|
|
47
|
-
"Prepr-Context-utm_source",
|
|
48
|
-
"Prepr-Context-utm_medium",
|
|
49
|
-
"Prepr-Context-utm_term",
|
|
50
|
-
"Prepr-Context-utm_content",
|
|
51
|
-
"Prepr-Context-utm_campaign",
|
|
52
|
-
"Prepr-Context-initial_referral",
|
|
53
|
-
"Prepr-Visitor-IP",
|
|
54
|
-
"Prepr-Hubspot-Id",
|
|
55
|
-
"Prepr-Customer-Id-Created",
|
|
56
|
-
"User-Agent",
|
|
57
|
-
"Prepr-Package"
|
|
58
|
-
];
|
|
59
|
-
function getPreprHeadersFromHeaders(headers) {
|
|
60
|
-
const preprHeaders = {};
|
|
61
|
-
const copy = (key) => {
|
|
62
|
-
const value = headers.get(key);
|
|
63
|
-
if (value !== null) {
|
|
64
|
-
preprHeaders[key] = value;
|
|
65
|
-
}
|
|
52
|
+
// src/core/preview-attrs.ts
|
|
53
|
+
function previewAttrs(target, options) {
|
|
54
|
+
if (!options.enabled || !target?.id || !target.field) return {};
|
|
55
|
+
const attrs = {
|
|
56
|
+
"data-prepr-encoded": "",
|
|
57
|
+
"data-prepr-id": target.id,
|
|
58
|
+
"data-prepr-field": target.field
|
|
66
59
|
};
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
return preprHeaders;
|
|
60
|
+
if (target.locale) attrs["data-prepr-locale"] = target.locale;
|
|
61
|
+
if (target.entryId) attrs["data-prepr-entry-id"] = target.entryId;
|
|
62
|
+
return attrs;
|
|
71
63
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
);
|
|
64
|
+
var URL_BASE = "https://prepr.invalid";
|
|
65
|
+
function stegaTarget(value, options = {}) {
|
|
66
|
+
const decoded = value ? decodeStega(value) : null;
|
|
67
|
+
if (!decoded) return null;
|
|
68
|
+
let url;
|
|
69
|
+
try {
|
|
70
|
+
url = new URL(decoded.href, URL_BASE);
|
|
71
|
+
} catch {
|
|
72
|
+
return null;
|
|
79
73
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
)
|
|
74
|
+
const id = decodeURIComponent(url.pathname.split("/").pop() ?? "");
|
|
75
|
+
const field = url.searchParams.get("field");
|
|
76
|
+
if (!id || !field) return null;
|
|
77
|
+
return {
|
|
78
|
+
id,
|
|
79
|
+
field: options.field ? `${field.slice(0, field.lastIndexOf(".") + 1)}${options.field}` : field,
|
|
80
|
+
locale: url.searchParams.get("locale")
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// src/core/live-preview/edit-links.ts
|
|
85
|
+
import {
|
|
86
|
+
vercelStegaCombine,
|
|
87
|
+
vercelStegaDecode,
|
|
88
|
+
vercelStegaSplit
|
|
89
|
+
} from "@vercel/stega";
|
|
90
|
+
var ENTRY_PARAM = "entry";
|
|
91
|
+
var TOP_LEVEL_ENTRY = /^[A-Za-z0-9_]+\.\d+$/;
|
|
92
|
+
function entryIdOf(element) {
|
|
93
|
+
if (!isRecord(element)) return void 0;
|
|
94
|
+
if (typeof element._id === "string") return element._id;
|
|
95
|
+
if (element.__typename !== "Assets" || !Array.isArray(element.items)) {
|
|
96
|
+
return void 0;
|
|
86
97
|
}
|
|
98
|
+
const first = element.items[0];
|
|
99
|
+
return isRecord(first) && typeof first._id === "string" ? first._id : void 0;
|
|
87
100
|
}
|
|
88
|
-
function
|
|
89
|
-
|
|
101
|
+
function isRecord(value) {
|
|
102
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
103
|
+
}
|
|
104
|
+
function annotate(value, ctx) {
|
|
105
|
+
if (!ctx.entryId) return value;
|
|
106
|
+
const { cleaned, encoded } = vercelStegaSplit(value);
|
|
107
|
+
if (!encoded) return value;
|
|
108
|
+
let payload;
|
|
90
109
|
try {
|
|
91
|
-
|
|
92
|
-
} catch
|
|
93
|
-
|
|
94
|
-
"Token must be a valid URL",
|
|
95
|
-
"INVALID_TOKEN",
|
|
96
|
-
"extractAccessToken",
|
|
97
|
-
error instanceof Error ? error : new Error(String(error))
|
|
98
|
-
);
|
|
110
|
+
payload = vercelStegaDecode(encoded);
|
|
111
|
+
} catch {
|
|
112
|
+
return value;
|
|
99
113
|
}
|
|
100
|
-
if (
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
114
|
+
if (typeof payload?.href !== "string") return value;
|
|
115
|
+
let url;
|
|
116
|
+
try {
|
|
117
|
+
url = new URL(payload.href);
|
|
118
|
+
} catch {
|
|
119
|
+
return value;
|
|
106
120
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
"INVALID_TOKEN",
|
|
113
|
-
"extractAccessToken"
|
|
114
|
-
);
|
|
121
|
+
if (url.searchParams.has(ENTRY_PARAM)) return value;
|
|
122
|
+
url.searchParams.set(ENTRY_PARAM, ctx.entryId);
|
|
123
|
+
const itemId = decodeURIComponent(url.pathname.split("/").pop() ?? "");
|
|
124
|
+
if (!url.searchParams.has("field") && ctx.entryField && TOP_LEVEL_ENTRY.test(ctx.entryField) && itemId === ctx.entryOwnerId) {
|
|
125
|
+
url.searchParams.set("field", ctx.entryField);
|
|
115
126
|
}
|
|
116
|
-
return
|
|
127
|
+
return vercelStegaCombine(
|
|
128
|
+
cleaned,
|
|
129
|
+
{ ...payload, href: url.toString() },
|
|
130
|
+
false
|
|
131
|
+
);
|
|
117
132
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
"
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
133
|
+
function walk(value, selections, ctx) {
|
|
134
|
+
if (typeof value === "string") return annotate(value, ctx);
|
|
135
|
+
if (Array.isArray(value)) {
|
|
136
|
+
let changed2 = false;
|
|
137
|
+
const next2 = value.map((element, index) => {
|
|
138
|
+
const path = [...ctx.path, String(index)];
|
|
139
|
+
const entryId = ctx.inAssets ? void 0 : entryIdOf(element);
|
|
140
|
+
const entry = entryId ? {
|
|
141
|
+
entryId,
|
|
142
|
+
entryField: ctx.ownerId ? path.join(".") : void 0,
|
|
143
|
+
entryOwnerId: ctx.ownerId,
|
|
144
|
+
inAssets: isRecord(element) && element._id === void 0
|
|
145
|
+
} : {};
|
|
146
|
+
const out = walk(element, selections, { ...ctx, ...entry, path });
|
|
147
|
+
if (out !== element) changed2 = true;
|
|
148
|
+
return out;
|
|
149
|
+
});
|
|
150
|
+
return changed2 ? next2 : value;
|
|
151
|
+
}
|
|
152
|
+
if (!isRecord(value)) return value;
|
|
153
|
+
const id = typeof value._id === "string" ? value._id : void 0;
|
|
154
|
+
const typename = typeof value.__typename === "string" ? value.__typename : void 0;
|
|
155
|
+
const fields = ctx.doc && selections ? collectFields(selections, typename, ctx.doc) : null;
|
|
156
|
+
let changed = false;
|
|
157
|
+
const next = {};
|
|
158
|
+
for (const [key, child] of Object.entries(value)) {
|
|
159
|
+
const field = fields?.get(key);
|
|
160
|
+
const name = field?.name ?? key;
|
|
161
|
+
const out = walk(child, field?.selections ?? null, {
|
|
162
|
+
...ctx,
|
|
163
|
+
ownerId: id ?? ctx.ownerId,
|
|
164
|
+
path: id ? [name] : [...ctx.path, name]
|
|
139
165
|
});
|
|
140
|
-
if (
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
166
|
+
if (out !== child) changed = true;
|
|
167
|
+
next[key] = out;
|
|
168
|
+
}
|
|
169
|
+
return changed ? next : value;
|
|
170
|
+
}
|
|
171
|
+
function annotateEditLinks(result, query, operationName) {
|
|
172
|
+
let doc = null;
|
|
173
|
+
if (query !== void 0) {
|
|
174
|
+
try {
|
|
175
|
+
doc = readQueryDocument(query, operationName);
|
|
176
|
+
} catch {
|
|
177
|
+
doc = null;
|
|
146
178
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
179
|
+
}
|
|
180
|
+
return walk(result, doc?.operation ?? null, { doc, path: [] });
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// src/core/live-preview/morph.ts
|
|
184
|
+
function morphElement(current, next) {
|
|
185
|
+
syncAttributes(current, next);
|
|
186
|
+
morphChildren(current, next);
|
|
187
|
+
}
|
|
188
|
+
var SKIP_ATTR = "data-prepr-morph-skip";
|
|
189
|
+
var RUNTIME_ATTR_PREFIXES = ["data-prepr-"];
|
|
190
|
+
function isRuntimeAttribute(name) {
|
|
191
|
+
return RUNTIME_ATTR_PREFIXES.some((prefix) => name.startsWith(prefix));
|
|
192
|
+
}
|
|
193
|
+
function syncAttributes(current, next) {
|
|
194
|
+
for (const { name } of Array.from(current.attributes)) {
|
|
195
|
+
if (!next.hasAttribute(name) && !isRuntimeAttribute(name)) {
|
|
196
|
+
current.removeAttribute(name);
|
|
154
197
|
}
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
if (
|
|
158
|
-
|
|
198
|
+
}
|
|
199
|
+
for (const { name, value } of Array.from(next.attributes)) {
|
|
200
|
+
if (current.getAttribute(name) !== value) current.setAttribute(name, value);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
function isSkipped(node) {
|
|
204
|
+
return node.nodeType === Node.ELEMENT_NODE && (node.hasAttribute(SKIP_ATTR) || node.localName === "prepr-toolbar");
|
|
205
|
+
}
|
|
206
|
+
function sameKind(a, b) {
|
|
207
|
+
if (a.nodeType !== b.nodeType) return false;
|
|
208
|
+
if (a.nodeType !== Node.ELEMENT_NODE) return true;
|
|
209
|
+
const ea = a;
|
|
210
|
+
const eb = b;
|
|
211
|
+
return ea.localName === eb.localName && ea.id === eb.id;
|
|
212
|
+
}
|
|
213
|
+
function morphChildren(current, next) {
|
|
214
|
+
const wanted = Array.from(next.childNodes).filter((n) => !isSkipped(n));
|
|
215
|
+
const existing = Array.from(current.childNodes).filter((n) => !isSkipped(n));
|
|
216
|
+
wanted.forEach((target, i) => {
|
|
217
|
+
const node = existing[i];
|
|
218
|
+
if (node && sameKind(node, target)) {
|
|
219
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
220
|
+
const element = node;
|
|
221
|
+
if (element.localName === "script") return;
|
|
222
|
+
if (element.localName === "astro-island" && !element.isEqualNode(target)) {
|
|
223
|
+
element.replaceWith(adopt(target, current));
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
morphElement(element, target);
|
|
227
|
+
} else if (node.nodeValue !== target.nodeValue) {
|
|
228
|
+
node.nodeValue = target.nodeValue;
|
|
229
|
+
}
|
|
230
|
+
return;
|
|
159
231
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
232
|
+
const replacement = adopt(target, current);
|
|
233
|
+
if (node) node.replaceWith(replacement);
|
|
234
|
+
else current.appendChild(replacement);
|
|
235
|
+
});
|
|
236
|
+
for (const extra of existing.slice(wanted.length)) extra.remove();
|
|
237
|
+
}
|
|
238
|
+
function adopt(node, parent) {
|
|
239
|
+
const copy = parent.ownerDocument.importNode(node, true);
|
|
240
|
+
if (copy.nodeType === Node.ELEMENT_NODE) {
|
|
241
|
+
const element = copy;
|
|
242
|
+
const scripts = element.localName === "script" ? [element] : Array.from(element.querySelectorAll("script"));
|
|
243
|
+
scripts.forEach((s) => s.setAttribute("data-prepr-morphed", ""));
|
|
166
244
|
}
|
|
245
|
+
return copy;
|
|
167
246
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
247
|
+
|
|
248
|
+
// src/core/live-preview/html-live.ts
|
|
249
|
+
var debug = createScopedLogger("live-preview:html");
|
|
250
|
+
var COMPLETE_DOCUMENT = /<\/html>\s*$/i;
|
|
251
|
+
var SYNC_DEBOUNCE_MS = 150;
|
|
252
|
+
function startHtmlLivePreview(options = {}) {
|
|
253
|
+
if (typeof window === "undefined" || window.self === window.top) {
|
|
254
|
+
return { stop() {
|
|
255
|
+
} };
|
|
256
|
+
}
|
|
257
|
+
const store = createLiveStore();
|
|
258
|
+
const bridge = createLiveBridge(store, {
|
|
259
|
+
allowedEditorOrigins: () => options.allowedEditorOrigins,
|
|
260
|
+
strictMode: () => options.strictMode
|
|
261
|
+
});
|
|
262
|
+
bridge.start();
|
|
263
|
+
let timer = null;
|
|
264
|
+
let inFlight = false;
|
|
265
|
+
let pending = null;
|
|
266
|
+
let stopped = false;
|
|
267
|
+
const render = async (log) => {
|
|
268
|
+
inFlight = true;
|
|
172
269
|
try {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
270
|
+
const response = await fetch(window.location.href, {
|
|
271
|
+
method: log.length ? "POST" : "GET",
|
|
272
|
+
headers: log.length ? { "Content-Type": "application/json", [HEADER_LIVE_RENDER]: "1" } : {},
|
|
273
|
+
body: log.length ? JSON.stringify({ log }) : void 0,
|
|
274
|
+
credentials: "same-origin",
|
|
275
|
+
cache: "no-store"
|
|
276
|
+
});
|
|
277
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
278
|
+
const html = await response.text();
|
|
279
|
+
if (stopped) return;
|
|
280
|
+
if (!COMPLETE_DOCUMENT.test(html)) {
|
|
281
|
+
throw new Error("incomplete page; a component failed to render");
|
|
282
|
+
}
|
|
283
|
+
const next = new DOMParser().parseFromString(html, "text/html");
|
|
284
|
+
if (next.title && next.title !== document.title)
|
|
285
|
+
document.title = next.title;
|
|
286
|
+
morphElement(document.body, next.body);
|
|
287
|
+
} catch (error) {
|
|
288
|
+
debug.log("re-render failed", error);
|
|
289
|
+
} finally {
|
|
290
|
+
inFlight = false;
|
|
176
291
|
}
|
|
177
|
-
|
|
292
|
+
if (pending && !stopped) {
|
|
293
|
+
const queued = pending;
|
|
294
|
+
pending = null;
|
|
295
|
+
void render(queued);
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
const schedule = (log) => {
|
|
299
|
+
if (timer) clearTimeout(timer);
|
|
300
|
+
timer = setTimeout(() => {
|
|
301
|
+
timer = null;
|
|
302
|
+
if (inFlight) pending = log;
|
|
303
|
+
else void render(log);
|
|
304
|
+
}, SYNC_DEBOUNCE_MS);
|
|
305
|
+
};
|
|
306
|
+
const offLog = store.onLogChange((log) => {
|
|
307
|
+
if (log.length) schedule(log);
|
|
308
|
+
});
|
|
309
|
+
const offInvalidate = store.onInvalidate(() => schedule([]));
|
|
178
310
|
return {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
311
|
+
stop() {
|
|
312
|
+
stopped = true;
|
|
313
|
+
if (timer) clearTimeout(timer);
|
|
314
|
+
offLog();
|
|
315
|
+
offInvalidate();
|
|
316
|
+
bridge.stop();
|
|
317
|
+
}
|
|
183
318
|
};
|
|
184
319
|
}
|
|
185
320
|
|
|
321
|
+
// src/core/live-preview/live-request.ts
|
|
322
|
+
var MAX_BODY_BYTES = 1e6;
|
|
323
|
+
async function readLiveLogFromRequest(request) {
|
|
324
|
+
try {
|
|
325
|
+
if (request.method !== "POST") return [];
|
|
326
|
+
if (request.headers.get(HEADER_LIVE_RENDER) !== "1") return [];
|
|
327
|
+
const origin = request.headers.get("origin");
|
|
328
|
+
if (!origin || origin !== new URL(request.url).origin) return [];
|
|
329
|
+
const type = request.headers.get("content-type") ?? "";
|
|
330
|
+
if (!type.toLowerCase().startsWith("application/json")) return [];
|
|
331
|
+
const length = Number(request.headers.get("content-length") ?? "0");
|
|
332
|
+
if (length > MAX_BODY_BYTES) return [];
|
|
333
|
+
const text = await request.clone().text();
|
|
334
|
+
if (text.length > MAX_BODY_BYTES) return [];
|
|
335
|
+
const body = JSON.parse(text);
|
|
336
|
+
return parsePatchLog(body?.log);
|
|
337
|
+
} catch {
|
|
338
|
+
return [];
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
186
342
|
// src/core/middleware.ts
|
|
187
343
|
var UTM_PARAMS = [
|
|
188
344
|
"utm_source",
|
|
@@ -341,6 +497,7 @@ export {
|
|
|
341
497
|
PreprError,
|
|
342
498
|
PreprToolbarElement,
|
|
343
499
|
VERSION,
|
|
500
|
+
annotateEditLinks,
|
|
344
501
|
createPreprPreview,
|
|
345
502
|
createToolbarStore,
|
|
346
503
|
definePreprToolbar,
|
|
@@ -352,10 +509,16 @@ export {
|
|
|
352
509
|
getPreprUUIDFromHeaders,
|
|
353
510
|
getToolbarPropsFromHeaders,
|
|
354
511
|
loadTrackingPixel,
|
|
512
|
+
normalizeQuery,
|
|
513
|
+
parsePatchLog,
|
|
514
|
+
previewAttrs,
|
|
355
515
|
processPreprRequest,
|
|
516
|
+
readLiveLogFromRequest,
|
|
356
517
|
resolveFeatures,
|
|
357
518
|
setTrackingParam,
|
|
519
|
+
startHtmlLivePreview,
|
|
358
520
|
stegaClean,
|
|
521
|
+
stegaTarget,
|
|
359
522
|
trackEvent,
|
|
360
523
|
validatePreprToken
|
|
361
524
|
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createLiveBridge,
|
|
3
|
+
createLiveStore
|
|
4
|
+
} from "./chunk-IPMB32AZ.js";
|
|
5
|
+
import "./chunk-URXSDJOU.js";
|
|
6
|
+
import {
|
|
7
|
+
applyPatchLog,
|
|
8
|
+
normalizeQuery,
|
|
9
|
+
parsePatchLog
|
|
10
|
+
} from "./chunk-KD3GK6TO.js";
|
|
11
|
+
import "./chunk-S3VT4UWM.js";
|
|
12
|
+
export {
|
|
13
|
+
applyPatchLog,
|
|
14
|
+
createLiveBridge,
|
|
15
|
+
createLiveStore,
|
|
16
|
+
normalizeQuery,
|
|
17
|
+
parsePatchLog
|
|
18
|
+
};
|