@preprio/toolkit 0.2.0-beta.6 → 0.2.0-beta.9
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 +237 -471
- package/dist/astro/index.cjs +20 -6
- package/dist/astro/index.d.cts +1 -1
- package/dist/astro/index.d.ts +1 -1
- package/dist/astro/index.js +20 -6
- package/dist/{chunk-C6YEXA5G.js → chunk-JVUG6S4O.js} +42 -47
- package/dist/index.cjs +58 -52
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +17 -6
- package/dist/nextjs/components.cjs +45 -48
- package/dist/nextjs/components.js +5 -3
- package/dist/nextjs/image-loader.cjs +7 -2
- package/dist/nextjs/image-loader.d.cts +1 -1
- package/dist/nextjs/image-loader.d.ts +1 -1
- package/dist/nextjs/image-loader.js +7 -2
- package/dist/nextjs/index.cjs +31 -9
- package/dist/nextjs/index.d.cts +99 -2
- package/dist/nextjs/index.d.ts +99 -2
- package/dist/nextjs/index.js +31 -9
- package/dist/nuxt/index.cjs +20 -6
- package/dist/nuxt/index.js +20 -6
- package/dist/react/components.cjs +42 -47
- package/dist/react/components.js +42 -47
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.d.cts +1 -1
- package/dist/sveltekit/index.cjs +20 -6
- package/dist/sveltekit/index.js +20 -6
- package/package.json +14 -14
|
@@ -369,9 +369,7 @@ function decodeStega(str) {
|
|
|
369
369
|
const match = str.match(/{"origin.*?}/);
|
|
370
370
|
if (match) {
|
|
371
371
|
try {
|
|
372
|
-
const decodedMatch = (0, import_stega.vercelStegaDecode)(
|
|
373
|
-
match[0]
|
|
374
|
-
);
|
|
372
|
+
const decodedMatch = (0, import_stega.vercelStegaDecode)(match[0]);
|
|
375
373
|
if (decodedMatch?.href) {
|
|
376
374
|
return decodedMatch;
|
|
377
375
|
}
|
|
@@ -440,6 +438,8 @@ function createStegaAutoClean() {
|
|
|
440
438
|
function scanAndClean() {
|
|
441
439
|
processing = true;
|
|
442
440
|
walkTextNodes(document.body, cleanTextNode);
|
|
441
|
+
const title = (0, import_stega2.vercelStegaSplit)(document.title);
|
|
442
|
+
if (title.encoded) document.title = title.cleaned;
|
|
443
443
|
processing = false;
|
|
444
444
|
}
|
|
445
445
|
function collectAffected(mutations) {
|
|
@@ -485,15 +485,8 @@ function createStegaAutoClean() {
|
|
|
485
485
|
}
|
|
486
486
|
function start() {
|
|
487
487
|
if (observer || typeof window === "undefined") return;
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
setupObserver();
|
|
491
|
-
};
|
|
492
|
-
if ("requestIdleCallback" in window) {
|
|
493
|
-
window.requestIdleCallback(run);
|
|
494
|
-
} else {
|
|
495
|
-
setTimeout(run, 0);
|
|
496
|
-
}
|
|
488
|
+
scanAndClean();
|
|
489
|
+
setupObserver();
|
|
497
490
|
debug2.log("stega auto-clean started");
|
|
498
491
|
}
|
|
499
492
|
function stop() {
|
|
@@ -904,8 +897,13 @@ function createStegaController(opts) {
|
|
|
904
897
|
overlay.hide();
|
|
905
898
|
}
|
|
906
899
|
}, 16);
|
|
907
|
-
document.addEventListener("mousemove", throttledMouseMove
|
|
908
|
-
|
|
900
|
+
document.addEventListener("mousemove", throttledMouseMove, {
|
|
901
|
+
passive: true
|
|
902
|
+
});
|
|
903
|
+
window.addEventListener("scroll", handleScroll, {
|
|
904
|
+
capture: true,
|
|
905
|
+
passive: true
|
|
906
|
+
});
|
|
909
907
|
initialized = true;
|
|
910
908
|
debug6.log("stega controller started");
|
|
911
909
|
};
|
|
@@ -986,7 +984,7 @@ function cookieOpts() {
|
|
|
986
984
|
};
|
|
987
985
|
}
|
|
988
986
|
function createChangeHandler(deps) {
|
|
989
|
-
const { store, stega,
|
|
987
|
+
const { store, stega, features, editingEnabled } = deps;
|
|
990
988
|
function updateParams(patch) {
|
|
991
989
|
const [path, existing] = splitPath(deps.currentPath());
|
|
992
990
|
const params = new URLSearchParams(existing);
|
|
@@ -1048,17 +1046,20 @@ function createChangeHandler(deps) {
|
|
|
1048
1046
|
}
|
|
1049
1047
|
setCookie(COOKIE_PREVIEW_MODE, String(after.previewMode), cookieOpts());
|
|
1050
1048
|
setCookie(COOKIE_TOOLBAR_OPEN, "false", cookieOpts());
|
|
1051
|
-
sendPreprEvent("preview_mode_toggled", {
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
params
|
|
1057
|
-
params.
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1049
|
+
sendPreprEvent("preview_mode_toggled", {
|
|
1050
|
+
previewMode: after.previewMode
|
|
1051
|
+
});
|
|
1052
|
+
if (!after.isIframe) {
|
|
1053
|
+
const [path, existing] = splitPath(deps.currentPath());
|
|
1054
|
+
const params = new URLSearchParams(existing);
|
|
1055
|
+
if (params.has(PARAM_SEGMENT) || params.has(PARAM_VARIANT)) {
|
|
1056
|
+
params.delete(PARAM_SEGMENT);
|
|
1057
|
+
params.delete(PARAM_VARIANT);
|
|
1058
|
+
const query = params.toString();
|
|
1059
|
+
deps.navigate(query ? `${path}?${query}` : path);
|
|
1060
|
+
} else {
|
|
1061
|
+
deps.reload();
|
|
1062
|
+
}
|
|
1062
1063
|
}
|
|
1063
1064
|
}
|
|
1064
1065
|
if (before.toolbarOpen !== after.toolbarOpen) {
|
|
@@ -1368,7 +1369,10 @@ function u2(e2, t3, n2, o2, i2, u3) {
|
|
|
1368
1369
|
}
|
|
1369
1370
|
|
|
1370
1371
|
// src/core/ui/panel.tsx
|
|
1371
|
-
function RawSvg({
|
|
1372
|
+
function RawSvg({
|
|
1373
|
+
svg,
|
|
1374
|
+
className
|
|
1375
|
+
}) {
|
|
1372
1376
|
return /* @__PURE__ */ u2(
|
|
1373
1377
|
"span",
|
|
1374
1378
|
{
|
|
@@ -1939,9 +1943,7 @@ var PreprToolbarElement = class extends HTMLElementBase {
|
|
|
1939
1943
|
) ?? null;
|
|
1940
1944
|
}
|
|
1941
1945
|
optionsList() {
|
|
1942
|
-
return this.shadowRoot?.querySelector(
|
|
1943
|
-
'[data-prepr="options"]'
|
|
1944
|
-
) ?? null;
|
|
1946
|
+
return this.shadowRoot?.querySelector('[data-prepr="options"]') ?? null;
|
|
1945
1947
|
}
|
|
1946
1948
|
onListboxKeydown(event) {
|
|
1947
1949
|
const e2 = event;
|
|
@@ -2142,16 +2144,7 @@ function createPreprPreview(opts = {}) {
|
|
|
2142
2144
|
}
|
|
2143
2145
|
});
|
|
2144
2146
|
const autoClean = createStegaAutoClean();
|
|
2145
|
-
|
|
2146
|
-
function syncAutoClean(active) {
|
|
2147
|
-
if (active && !autoCleanActive) {
|
|
2148
|
-
autoClean.start();
|
|
2149
|
-
autoCleanActive = true;
|
|
2150
|
-
} else if (!active && autoCleanActive) {
|
|
2151
|
-
autoClean.stop();
|
|
2152
|
-
autoCleanActive = false;
|
|
2153
|
-
}
|
|
2154
|
-
}
|
|
2147
|
+
autoClean.start();
|
|
2155
2148
|
const handleChange = createChangeHandler({
|
|
2156
2149
|
store,
|
|
2157
2150
|
features,
|
|
@@ -2159,8 +2152,7 @@ function createPreprPreview(opts = {}) {
|
|
|
2159
2152
|
navigate: (url) => navigation.navigate(url),
|
|
2160
2153
|
currentPath: () => navigation.currentPath(),
|
|
2161
2154
|
reload: navigation.reload ?? (() => window.location.reload()),
|
|
2162
|
-
stega
|
|
2163
|
-
syncAutoClean
|
|
2155
|
+
stega
|
|
2164
2156
|
});
|
|
2165
2157
|
let prev = store.get();
|
|
2166
2158
|
const unsubscribe = store.subscribe((state) => {
|
|
@@ -2168,20 +2160,23 @@ function createPreprPreview(opts = {}) {
|
|
|
2168
2160
|
prev = state;
|
|
2169
2161
|
handleChange(before, state);
|
|
2170
2162
|
});
|
|
2171
|
-
syncAutoClean(store.get().previewMode);
|
|
2172
2163
|
const bridge = createIframeBridge(store, {
|
|
2173
2164
|
allowedEditorOrigins: options?.allowedEditorOrigins
|
|
2174
2165
|
});
|
|
2175
|
-
sendPreprEvent(
|
|
2176
|
-
|
|
2177
|
-
|
|
2166
|
+
sendPreprEvent(
|
|
2167
|
+
"getScrollPosition",
|
|
2168
|
+
{ value: 0 },
|
|
2169
|
+
{
|
|
2170
|
+
allowUntrustedTarget: true
|
|
2171
|
+
}
|
|
2172
|
+
);
|
|
2178
2173
|
if (isIframe) {
|
|
2179
2174
|
bridge.start();
|
|
2180
2175
|
}
|
|
2181
2176
|
function destroy() {
|
|
2182
2177
|
unsubscribe();
|
|
2183
2178
|
stega.stop();
|
|
2184
|
-
|
|
2179
|
+
autoClean.stop();
|
|
2185
2180
|
if (isIframe) {
|
|
2186
2181
|
bridge.stop();
|
|
2187
2182
|
}
|
|
@@ -2252,13 +2247,15 @@ function PreprToolbar({
|
|
|
2252
2247
|
}) {
|
|
2253
2248
|
const router = (0, import_navigation.useRouter)();
|
|
2254
2249
|
const pathname = (0, import_navigation.usePathname)();
|
|
2250
|
+
const pathnameRef = (0, import_react2.useRef)(pathname);
|
|
2251
|
+
pathnameRef.current = pathname;
|
|
2255
2252
|
(0, import_react2.useEffect)(() => {
|
|
2256
2253
|
const toolbar = createPreprPreview({
|
|
2257
2254
|
props,
|
|
2258
2255
|
options,
|
|
2259
2256
|
navigation: {
|
|
2260
2257
|
navigate: (url) => router.push(url),
|
|
2261
|
-
currentPath: () =>
|
|
2258
|
+
currentPath: () => pathnameRef.current + window.location.search
|
|
2262
2259
|
}
|
|
2263
2260
|
});
|
|
2264
2261
|
return () => toolbar.destroy();
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
import {
|
|
3
3
|
createPreprPreview,
|
|
4
4
|
loadTrackingPixel
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-JVUG6S4O.js";
|
|
6
6
|
|
|
7
7
|
// src/nextjs/components.ts
|
|
8
8
|
import { usePathname, useRouter } from "next/navigation";
|
|
9
|
-
import { useEffect as useEffect2 } from "react";
|
|
9
|
+
import { useEffect as useEffect2, useRef } from "react";
|
|
10
10
|
|
|
11
11
|
// src/react/components.ts
|
|
12
12
|
import { useEffect } from "react";
|
|
@@ -27,13 +27,15 @@ function PreprToolbar({
|
|
|
27
27
|
}) {
|
|
28
28
|
const router = useRouter();
|
|
29
29
|
const pathname = usePathname();
|
|
30
|
+
const pathnameRef = useRef(pathname);
|
|
31
|
+
pathnameRef.current = pathname;
|
|
30
32
|
useEffect2(() => {
|
|
31
33
|
const toolbar = createPreprPreview({
|
|
32
34
|
props,
|
|
33
35
|
options,
|
|
34
36
|
navigation: {
|
|
35
37
|
navigate: (url) => router.push(url),
|
|
36
|
-
currentPath: () =>
|
|
38
|
+
currentPath: () => pathnameRef.current + window.location.search
|
|
37
39
|
}
|
|
38
40
|
});
|
|
39
41
|
return () => toolbar.destroy();
|
|
@@ -25,7 +25,10 @@ __export(image_loader_exports, {
|
|
|
25
25
|
module.exports = __toCommonJS(image_loader_exports);
|
|
26
26
|
var TRANSFORM_SEGMENT = /\/([^/]*\bw_\d+[^/]*)\//;
|
|
27
27
|
var isPositiveInteger = (value) => /^\d+$/.test(value);
|
|
28
|
-
function preprImageLoader({
|
|
28
|
+
function preprImageLoader({
|
|
29
|
+
src,
|
|
30
|
+
width
|
|
31
|
+
}) {
|
|
29
32
|
return src.replace(TRANSFORM_SEGMENT, (match, segment) => {
|
|
30
33
|
const options = segment.split(",").map((pair) => {
|
|
31
34
|
const underscore = pair.indexOf("_");
|
|
@@ -36,7 +39,9 @@ function preprImageLoader({ src, width }) {
|
|
|
36
39
|
const emittedHeight = options.find(([key]) => key === "h");
|
|
37
40
|
if (emittedHeight && isPositiveInteger(emittedHeight[1])) {
|
|
38
41
|
emittedHeight[1] = String(
|
|
39
|
-
Math.round(
|
|
42
|
+
Math.round(
|
|
43
|
+
width * Number(emittedHeight[1]) / Number(emittedWidth[1])
|
|
44
|
+
)
|
|
40
45
|
);
|
|
41
46
|
}
|
|
42
47
|
emittedWidth[1] = String(width);
|
|
@@ -9,6 +9,6 @@ import { ImageLoaderProps } from 'next/image';
|
|
|
9
9
|
* neither of which is a ceiling on what the CDN can serve, so capping there
|
|
10
10
|
* would rule out retina.
|
|
11
11
|
*/
|
|
12
|
-
declare function preprImageLoader({ src, width }: ImageLoaderProps): string;
|
|
12
|
+
declare function preprImageLoader({ src, width, }: ImageLoaderProps): string;
|
|
13
13
|
|
|
14
14
|
export { preprImageLoader as default };
|
|
@@ -9,6 +9,6 @@ import { ImageLoaderProps } from 'next/image';
|
|
|
9
9
|
* neither of which is a ceiling on what the CDN can serve, so capping there
|
|
10
10
|
* would rule out retina.
|
|
11
11
|
*/
|
|
12
|
-
declare function preprImageLoader({ src, width }: ImageLoaderProps): string;
|
|
12
|
+
declare function preprImageLoader({ src, width, }: ImageLoaderProps): string;
|
|
13
13
|
|
|
14
14
|
export { preprImageLoader as default };
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
// src/nextjs/image-loader.ts
|
|
2
2
|
var TRANSFORM_SEGMENT = /\/([^/]*\bw_\d+[^/]*)\//;
|
|
3
3
|
var isPositiveInteger = (value) => /^\d+$/.test(value);
|
|
4
|
-
function preprImageLoader({
|
|
4
|
+
function preprImageLoader({
|
|
5
|
+
src,
|
|
6
|
+
width
|
|
7
|
+
}) {
|
|
5
8
|
return src.replace(TRANSFORM_SEGMENT, (match, segment) => {
|
|
6
9
|
const options = segment.split(",").map((pair) => {
|
|
7
10
|
const underscore = pair.indexOf("_");
|
|
@@ -12,7 +15,9 @@ function preprImageLoader({ src, width }) {
|
|
|
12
15
|
const emittedHeight = options.find(([key]) => key === "h");
|
|
13
16
|
if (emittedHeight && isPositiveInteger(emittedHeight[1])) {
|
|
14
17
|
emittedHeight[1] = String(
|
|
15
|
-
Math.round(
|
|
18
|
+
Math.round(
|
|
19
|
+
width * Number(emittedHeight[1]) / Number(emittedWidth[1])
|
|
20
|
+
)
|
|
16
21
|
);
|
|
17
22
|
}
|
|
18
23
|
emittedWidth[1] = String(width);
|
package/dist/nextjs/index.cjs
CHANGED
|
@@ -38,7 +38,7 @@ module.exports = __toCommonJS(nextjs_exports);
|
|
|
38
38
|
var import_server = require("next/server");
|
|
39
39
|
|
|
40
40
|
// src/version.ts
|
|
41
|
-
var VERSION = "0.2.0-beta.
|
|
41
|
+
var VERSION = "0.2.0-beta.9";
|
|
42
42
|
|
|
43
43
|
// src/core/constants.ts
|
|
44
44
|
var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
|
|
@@ -92,7 +92,11 @@ function parseCookies(request) {
|
|
|
92
92
|
const name = part.slice(0, eq).trim();
|
|
93
93
|
const value = part.slice(eq + 1).trim();
|
|
94
94
|
if (!name) continue;
|
|
95
|
-
|
|
95
|
+
try {
|
|
96
|
+
cookies.set(name, decodeURIComponent(value));
|
|
97
|
+
} catch {
|
|
98
|
+
cookies.set(name, value);
|
|
99
|
+
}
|
|
96
100
|
}
|
|
97
101
|
return cookies;
|
|
98
102
|
}
|
|
@@ -131,7 +135,10 @@ function processPreprRequest(request, opts) {
|
|
|
131
135
|
if (userAgent) {
|
|
132
136
|
requestHeaders.set("Prepr-User-Agent", sanitizeHeaderValue(userAgent));
|
|
133
137
|
}
|
|
134
|
-
requestHeaders.set(
|
|
138
|
+
requestHeaders.set(
|
|
139
|
+
"Prepr-Package",
|
|
140
|
+
`@preprio/toolkit@${opts?.version ?? VERSION}`
|
|
141
|
+
);
|
|
135
142
|
const ip = request.headers.get("Cf-Connecting-Ip") ?? request.headers.get("x-real-ip");
|
|
136
143
|
if (ip) {
|
|
137
144
|
requestHeaders.set("Prepr-Visitor-IP", sanitizeHeaderValue(ip));
|
|
@@ -140,7 +147,7 @@ function processPreprRequest(request, opts) {
|
|
|
140
147
|
if (hutkCookie) {
|
|
141
148
|
requestHeaders.set("Prepr-Hubspot-Id", sanitizeHeaderValue(hutkCookie));
|
|
142
149
|
}
|
|
143
|
-
let uid = requestCookies.get(COOKIE_UID);
|
|
150
|
+
let uid = sanitizeHeaderValue(requestCookies.get(COOKIE_UID) ?? "");
|
|
144
151
|
if (!uid) {
|
|
145
152
|
uid = crypto.randomUUID();
|
|
146
153
|
responseCookies.push({
|
|
@@ -224,19 +231,30 @@ function createPreprMiddleware(request, responseOrOptions, maybeOptions) {
|
|
|
224
231
|
} else {
|
|
225
232
|
options = responseOrOptions;
|
|
226
233
|
}
|
|
227
|
-
const { requestHeaders, responseCookies } = processPreprRequest(
|
|
234
|
+
const { requestHeaders, responseCookies } = processPreprRequest(
|
|
235
|
+
request,
|
|
236
|
+
options
|
|
237
|
+
);
|
|
228
238
|
const response = chainedResponse ?? import_server.NextResponse.next({ request: { headers: requestHeaders } });
|
|
229
239
|
if (chainedResponse) {
|
|
240
|
+
const existing = response.headers.get("x-middleware-override-headers");
|
|
241
|
+
const names = new Set(
|
|
242
|
+
existing ? existing.split(",").map((name) => name.trim()).filter(Boolean) : []
|
|
243
|
+
);
|
|
230
244
|
requestHeaders.forEach((value, key) => {
|
|
231
|
-
|
|
245
|
+
names.add(key);
|
|
246
|
+
response.headers.set(`x-middleware-request-${key}`, value);
|
|
232
247
|
});
|
|
248
|
+
response.headers.set("x-middleware-override-headers", [...names].join(","));
|
|
233
249
|
}
|
|
234
250
|
for (const cookie of responseCookies) {
|
|
235
251
|
response.cookies.set(cookie.name, cookie.value, {
|
|
236
252
|
maxAge: cookie.maxAge,
|
|
237
253
|
path: cookie.path,
|
|
238
254
|
// Lower-cased: Next's cookie API expects 'none' | 'lax' | 'strict'.
|
|
239
|
-
...cookie.sameSite ? {
|
|
255
|
+
...cookie.sameSite ? {
|
|
256
|
+
sameSite: cookie.sameSite.toLowerCase()
|
|
257
|
+
} : {},
|
|
240
258
|
...cookie.secure ? { secure: true } : {}
|
|
241
259
|
});
|
|
242
260
|
}
|
|
@@ -296,7 +314,11 @@ function getPreprHeadersFromHeaders(headers2) {
|
|
|
296
314
|
}
|
|
297
315
|
function validatePreprToken(token) {
|
|
298
316
|
if (!token) {
|
|
299
|
-
throw new PreprError(
|
|
317
|
+
throw new PreprError(
|
|
318
|
+
"Token is required",
|
|
319
|
+
"MISSING_TOKEN",
|
|
320
|
+
"validatePreprToken"
|
|
321
|
+
);
|
|
300
322
|
}
|
|
301
323
|
if (!token.startsWith("https://")) {
|
|
302
324
|
throw new PreprError(
|
|
@@ -426,7 +448,7 @@ async function getToolbarProps(token, features) {
|
|
|
426
448
|
}
|
|
427
449
|
|
|
428
450
|
// src/nextjs/index.ts
|
|
429
|
-
var import_components = require("./components");
|
|
451
|
+
var import_components = require("./components.cjs");
|
|
430
452
|
// Annotate the CommonJS export names for ESM import in node:
|
|
431
453
|
0 && (module.exports = {
|
|
432
454
|
PreprError,
|
package/dist/nextjs/index.d.cts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
type Dictionary = Record<string, unknown>;
|
|
4
|
+
declare const dictionaries: {
|
|
5
|
+
en: Dictionary;
|
|
6
|
+
nl: Dictionary;
|
|
7
|
+
};
|
|
8
|
+
type Locale = keyof typeof dictionaries;
|
|
3
9
|
|
|
4
10
|
interface PreprSegment {
|
|
5
11
|
readonly _id: string;
|
|
@@ -29,6 +35,36 @@ interface PreprFeatures {
|
|
|
29
35
|
*/
|
|
30
36
|
editMode?: PreprFeatureConfig;
|
|
31
37
|
}
|
|
38
|
+
interface PreprToolbarOptions {
|
|
39
|
+
debug?: boolean;
|
|
40
|
+
locale?: Locale;
|
|
41
|
+
/** Disable features app-wide. Pass the same object to the middleware. */
|
|
42
|
+
features?: PreprFeatures;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Options for the preview runtime. Two independent axes: `features` decides
|
|
46
|
+
* *what runs*, `ui` decides *whether the toolbar is visible*.
|
|
47
|
+
*/
|
|
48
|
+
interface PreprPreviewOptions extends PreprToolbarOptions {
|
|
49
|
+
/**
|
|
50
|
+
* Mount the visible `<prepr-toolbar>` element. Default `true`.
|
|
51
|
+
*
|
|
52
|
+
* `false` keeps every non-visual side effect wired — click-to-edit, the
|
|
53
|
+
* editor bridge, scroll restore, cookies and headers — with no chrome of its
|
|
54
|
+
* own. That is how a site gets live editing, or editor scroll restore, while
|
|
55
|
+
* rendering its own UI instead of the bar.
|
|
56
|
+
*
|
|
57
|
+
* Already implied inside the editor's iframe (the CMS owns the chrome there)
|
|
58
|
+
* and by `?prepr_hide_bar=true`, so this option is for consumers who want a
|
|
59
|
+
* headless preview by their own choice.
|
|
60
|
+
*/
|
|
61
|
+
ui?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Replace the `*.prepr.io` editor-origin wildcard with an exact list.
|
|
64
|
+
* Intended for self-hosted editors; when set, the wildcard no longer applies.
|
|
65
|
+
*/
|
|
66
|
+
allowedEditorOrigins?: string[];
|
|
67
|
+
}
|
|
32
68
|
interface PreprToolbarProps {
|
|
33
69
|
/**
|
|
34
70
|
* Server-resolved active segment. Optional: omit it with `segments`
|
|
@@ -47,6 +83,13 @@ interface PreprToolbarProps {
|
|
|
47
83
|
/** @deprecated Alias for `segments`. */
|
|
48
84
|
readonly data?: readonly PreprSegment[];
|
|
49
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Prop type for the framework `<PreprToolbar>` components: the toolbar data
|
|
88
|
+
* plus the options bag core `createPreprPreview` accepts.
|
|
89
|
+
*/
|
|
90
|
+
interface PreprToolbarComponentProps extends PreprToolbarProps {
|
|
91
|
+
options?: PreprPreviewOptions;
|
|
92
|
+
}
|
|
50
93
|
type PreprVariant = 'A' | 'B';
|
|
51
94
|
interface PreprHeaders {
|
|
52
95
|
readonly 'prepr-customer-id'?: string;
|
|
@@ -127,4 +170,58 @@ declare function validatePreprToken(token: string): void;
|
|
|
127
170
|
*/
|
|
128
171
|
declare function extractAccessToken(graphqlUrl: string): string;
|
|
129
172
|
|
|
130
|
-
|
|
173
|
+
/**
|
|
174
|
+
* Loader + typed facade for Prepr's CDN tracking pixel, so consumers don't have
|
|
175
|
+
* to paste a `<script>` tag. The pixel itself lives on the CDN; this only sets
|
|
176
|
+
* up the handoff.
|
|
177
|
+
*
|
|
178
|
+
* The CDN script expects a queue stub to already exist when it loads, so the
|
|
179
|
+
* contract must be reproduced exactly:
|
|
180
|
+
* - `window.prepr` pushes `arguments` onto `.queue` until the real script
|
|
181
|
+
* lands and replaces `.process`.
|
|
182
|
+
* - `.t` must be a `Date.now()` timestamp.
|
|
183
|
+
* - The tag is inserted async, `src` cache-busted every 24h via
|
|
184
|
+
* `Math.ceil(Date.now() / cacheTime) * cacheTime`.
|
|
185
|
+
*/
|
|
186
|
+
/** Config accepted by the CDN pixel. */
|
|
187
|
+
interface PreprPixelConfig {
|
|
188
|
+
destinations?: {
|
|
189
|
+
googleTagManager?: boolean;
|
|
190
|
+
};
|
|
191
|
+
variantImpressionThreshold?: number;
|
|
192
|
+
}
|
|
193
|
+
type PreprQueueArgs = unknown[];
|
|
194
|
+
interface PreprQueueFn {
|
|
195
|
+
(...args: PreprQueueArgs): void;
|
|
196
|
+
queue: PreprQueueArgs[];
|
|
197
|
+
t: number;
|
|
198
|
+
process?: (...args: PreprQueueArgs) => void;
|
|
199
|
+
}
|
|
200
|
+
declare global {
|
|
201
|
+
interface Window {
|
|
202
|
+
prepr?: PreprQueueFn;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
interface PreprTrackingPixelProps {
|
|
207
|
+
/** Prepr tracking/access token. */
|
|
208
|
+
id: string;
|
|
209
|
+
config?: PreprPixelConfig;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Loads Prepr's CDN tracking pixel on mount. Renders nothing.
|
|
213
|
+
*
|
|
214
|
+
* The pixel queues a single `pageload` event when it installs. Client-side
|
|
215
|
+
* route changes emit nothing on their own — call `trackEvent('pageload')` from
|
|
216
|
+
* the router to count them.
|
|
217
|
+
*/
|
|
218
|
+
declare function PreprTrackingPixel({ id, config, }: PreprTrackingPixelProps): null;
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Mounts the Prepr toolbar and wires it to the Next.js router so segment/variant
|
|
222
|
+
* switches navigate. Renders nothing — the toolbar UI is a custom element that
|
|
223
|
+
* `createPreprPreview` mounts imperatively.
|
|
224
|
+
*/
|
|
225
|
+
declare function PreprToolbar({ options, ...props }: PreprToolbarComponentProps): null;
|
|
226
|
+
|
|
227
|
+
export { PreprError, type PreprMiddlewareOptions, PreprToolbar, PreprTrackingPixel, type PreprTrackingPixelProps, createPreprMiddleware, extractAccessToken, getActiveSegment, getActiveVariant, getPreprHeaders, getPreprUUID, getToolbarProps, validatePreprToken };
|
package/dist/nextjs/index.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
type Dictionary = Record<string, unknown>;
|
|
4
|
+
declare const dictionaries: {
|
|
5
|
+
en: Dictionary;
|
|
6
|
+
nl: Dictionary;
|
|
7
|
+
};
|
|
8
|
+
type Locale = keyof typeof dictionaries;
|
|
3
9
|
|
|
4
10
|
interface PreprSegment {
|
|
5
11
|
readonly _id: string;
|
|
@@ -29,6 +35,36 @@ interface PreprFeatures {
|
|
|
29
35
|
*/
|
|
30
36
|
editMode?: PreprFeatureConfig;
|
|
31
37
|
}
|
|
38
|
+
interface PreprToolbarOptions {
|
|
39
|
+
debug?: boolean;
|
|
40
|
+
locale?: Locale;
|
|
41
|
+
/** Disable features app-wide. Pass the same object to the middleware. */
|
|
42
|
+
features?: PreprFeatures;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Options for the preview runtime. Two independent axes: `features` decides
|
|
46
|
+
* *what runs*, `ui` decides *whether the toolbar is visible*.
|
|
47
|
+
*/
|
|
48
|
+
interface PreprPreviewOptions extends PreprToolbarOptions {
|
|
49
|
+
/**
|
|
50
|
+
* Mount the visible `<prepr-toolbar>` element. Default `true`.
|
|
51
|
+
*
|
|
52
|
+
* `false` keeps every non-visual side effect wired — click-to-edit, the
|
|
53
|
+
* editor bridge, scroll restore, cookies and headers — with no chrome of its
|
|
54
|
+
* own. That is how a site gets live editing, or editor scroll restore, while
|
|
55
|
+
* rendering its own UI instead of the bar.
|
|
56
|
+
*
|
|
57
|
+
* Already implied inside the editor's iframe (the CMS owns the chrome there)
|
|
58
|
+
* and by `?prepr_hide_bar=true`, so this option is for consumers who want a
|
|
59
|
+
* headless preview by their own choice.
|
|
60
|
+
*/
|
|
61
|
+
ui?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Replace the `*.prepr.io` editor-origin wildcard with an exact list.
|
|
64
|
+
* Intended for self-hosted editors; when set, the wildcard no longer applies.
|
|
65
|
+
*/
|
|
66
|
+
allowedEditorOrigins?: string[];
|
|
67
|
+
}
|
|
32
68
|
interface PreprToolbarProps {
|
|
33
69
|
/**
|
|
34
70
|
* Server-resolved active segment. Optional: omit it with `segments`
|
|
@@ -47,6 +83,13 @@ interface PreprToolbarProps {
|
|
|
47
83
|
/** @deprecated Alias for `segments`. */
|
|
48
84
|
readonly data?: readonly PreprSegment[];
|
|
49
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Prop type for the framework `<PreprToolbar>` components: the toolbar data
|
|
88
|
+
* plus the options bag core `createPreprPreview` accepts.
|
|
89
|
+
*/
|
|
90
|
+
interface PreprToolbarComponentProps extends PreprToolbarProps {
|
|
91
|
+
options?: PreprPreviewOptions;
|
|
92
|
+
}
|
|
50
93
|
type PreprVariant = 'A' | 'B';
|
|
51
94
|
interface PreprHeaders {
|
|
52
95
|
readonly 'prepr-customer-id'?: string;
|
|
@@ -127,4 +170,58 @@ declare function validatePreprToken(token: string): void;
|
|
|
127
170
|
*/
|
|
128
171
|
declare function extractAccessToken(graphqlUrl: string): string;
|
|
129
172
|
|
|
130
|
-
|
|
173
|
+
/**
|
|
174
|
+
* Loader + typed facade for Prepr's CDN tracking pixel, so consumers don't have
|
|
175
|
+
* to paste a `<script>` tag. The pixel itself lives on the CDN; this only sets
|
|
176
|
+
* up the handoff.
|
|
177
|
+
*
|
|
178
|
+
* The CDN script expects a queue stub to already exist when it loads, so the
|
|
179
|
+
* contract must be reproduced exactly:
|
|
180
|
+
* - `window.prepr` pushes `arguments` onto `.queue` until the real script
|
|
181
|
+
* lands and replaces `.process`.
|
|
182
|
+
* - `.t` must be a `Date.now()` timestamp.
|
|
183
|
+
* - The tag is inserted async, `src` cache-busted every 24h via
|
|
184
|
+
* `Math.ceil(Date.now() / cacheTime) * cacheTime`.
|
|
185
|
+
*/
|
|
186
|
+
/** Config accepted by the CDN pixel. */
|
|
187
|
+
interface PreprPixelConfig {
|
|
188
|
+
destinations?: {
|
|
189
|
+
googleTagManager?: boolean;
|
|
190
|
+
};
|
|
191
|
+
variantImpressionThreshold?: number;
|
|
192
|
+
}
|
|
193
|
+
type PreprQueueArgs = unknown[];
|
|
194
|
+
interface PreprQueueFn {
|
|
195
|
+
(...args: PreprQueueArgs): void;
|
|
196
|
+
queue: PreprQueueArgs[];
|
|
197
|
+
t: number;
|
|
198
|
+
process?: (...args: PreprQueueArgs) => void;
|
|
199
|
+
}
|
|
200
|
+
declare global {
|
|
201
|
+
interface Window {
|
|
202
|
+
prepr?: PreprQueueFn;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
interface PreprTrackingPixelProps {
|
|
207
|
+
/** Prepr tracking/access token. */
|
|
208
|
+
id: string;
|
|
209
|
+
config?: PreprPixelConfig;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Loads Prepr's CDN tracking pixel on mount. Renders nothing.
|
|
213
|
+
*
|
|
214
|
+
* The pixel queues a single `pageload` event when it installs. Client-side
|
|
215
|
+
* route changes emit nothing on their own — call `trackEvent('pageload')` from
|
|
216
|
+
* the router to count them.
|
|
217
|
+
*/
|
|
218
|
+
declare function PreprTrackingPixel({ id, config, }: PreprTrackingPixelProps): null;
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Mounts the Prepr toolbar and wires it to the Next.js router so segment/variant
|
|
222
|
+
* switches navigate. Renders nothing — the toolbar UI is a custom element that
|
|
223
|
+
* `createPreprPreview` mounts imperatively.
|
|
224
|
+
*/
|
|
225
|
+
declare function PreprToolbar({ options, ...props }: PreprToolbarComponentProps): null;
|
|
226
|
+
|
|
227
|
+
export { PreprError, type PreprMiddlewareOptions, PreprToolbar, PreprTrackingPixel, type PreprTrackingPixelProps, createPreprMiddleware, extractAccessToken, getActiveSegment, getActiveVariant, getPreprHeaders, getPreprUUID, getToolbarProps, validatePreprToken };
|