@preprio/toolkit 0.6.0-alpha.1 → 0.6.0-alpha.10
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 +163 -61
- package/dist/astro/{chunk-O7N6GPAH.js → chunk-CG2QBHNU.js} +1 -1
- package/dist/astro/graphql.cjs +58 -10
- package/dist/astro/graphql.d.cts +33 -38
- package/dist/astro/graphql.d.ts +33 -38
- package/dist/astro/graphql.js +59 -11
- package/dist/astro/index.cjs +1 -1
- package/dist/astro/index.js +1 -1
- package/dist/{chunk-VI6QZTBM.js → chunk-LIDUJWWJ.js} +1 -1
- package/dist/{chunk-TBKSBXGH.js → chunk-M3RBYJ5J.js} +52 -5
- package/dist/{chunk-3JLWZQ37.js → chunk-SF6TN4JR.js} +1 -1
- package/dist/{chunk-YWIKKWBR.js → chunk-TN6SNAR2.js} +1 -1
- package/dist/graphql/codegen.cjs +51 -4
- package/dist/graphql/codegen.js +3 -3
- package/dist/graphql.cjs +89 -10
- package/dist/graphql.d.cts +69 -39
- package/dist/graphql.d.ts +69 -39
- package/dist/graphql.js +38 -9
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -3
- package/dist/nextjs/chunk-B4GVZEOL.js +549 -0
- package/dist/nextjs/components.cjs +297 -81
- package/dist/nextjs/components.d.cts +26 -11
- package/dist/nextjs/components.d.ts +26 -11
- package/dist/nextjs/components.js +288 -73
- package/dist/nextjs/graphql.cjs +856 -266
- package/dist/nextjs/graphql.d.cts +184 -116
- package/dist/nextjs/graphql.d.ts +184 -116
- package/dist/nextjs/graphql.js +543 -266
- package/dist/nextjs/index.cjs +116 -54
- package/dist/nextjs/index.d.cts +61 -23
- package/dist/nextjs/index.d.ts +61 -23
- package/dist/nextjs/index.js +97 -299
- package/dist/nextjs/{server-CjpELYvq.d.ts → server-BL-sqZvu.d.cts} +1 -1
- package/dist/nextjs/{server-CjpELYvq.d.cts → server-BL-sqZvu.d.ts} +1 -1
- package/dist/nuxt/{chunk-IQDSBPDN.js → chunk-FMC3DP7N.js} +1 -1
- package/dist/nuxt/graphql.cjs +58 -10
- package/dist/nuxt/graphql.d.cts +33 -38
- package/dist/nuxt/graphql.d.ts +33 -38
- package/dist/nuxt/graphql.js +59 -11
- package/dist/nuxt/index.cjs +1 -1
- package/dist/nuxt/index.js +1 -1
- package/dist/react/components.cjs +1 -1
- package/dist/react/components.js +1 -1
- package/dist/sveltekit/{chunk-OKYZ6HPH.js → chunk-AJPKBAHO.js} +1 -1
- package/dist/sveltekit/graphql.cjs +58 -10
- package/dist/sveltekit/graphql.d.cts +33 -38
- package/dist/sveltekit/graphql.d.ts +33 -38
- package/dist/sveltekit/graphql.js +59 -11
- package/dist/sveltekit/index.cjs +1 -1
- package/dist/sveltekit/index.js +1 -1
- package/package.json +1 -1
- package/dist/nextjs/chunk-BQ6IGSH6.js +0 -231
package/dist/nextjs/index.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
+
PREPR_ANY_ITEM_TAG,
|
|
3
|
+
PREPR_SCHEMA_TAG,
|
|
2
4
|
PreprError,
|
|
3
|
-
|
|
5
|
+
createPreprDraftRoute,
|
|
6
|
+
createPreprMiddleware,
|
|
4
7
|
extractAccessToken,
|
|
5
8
|
getActiveSegment,
|
|
6
9
|
getActiveVariant,
|
|
@@ -8,332 +11,128 @@ import {
|
|
|
8
11
|
getPreprUUID,
|
|
9
12
|
getToolbarProps,
|
|
10
13
|
isPersonalizedResponse,
|
|
11
|
-
|
|
14
|
+
preprDraftRedirect,
|
|
15
|
+
preprItemTag,
|
|
16
|
+
preprModelTag,
|
|
12
17
|
validatePreprToken
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
|
|
15
|
-
// src/nextjs/middleware.ts
|
|
16
|
-
import { NextResponse } from "next/server";
|
|
18
|
+
} from "./chunk-B4GVZEOL.js";
|
|
17
19
|
|
|
18
|
-
// src/
|
|
19
|
-
|
|
20
|
-
var
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
var
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (!header) return cookies2;
|
|
46
|
-
for (const part of header.split(";")) {
|
|
47
|
-
const eq = part.indexOf("=");
|
|
48
|
-
if (eq === -1) continue;
|
|
49
|
-
const name = part.slice(0, eq).trim();
|
|
50
|
-
const value = part.slice(eq + 1).trim();
|
|
51
|
-
if (!name) continue;
|
|
52
|
-
try {
|
|
53
|
-
cookies2.set(name, decodeURIComponent(value));
|
|
54
|
-
} catch {
|
|
55
|
-
cookies2.set(name, value);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return cookies2;
|
|
59
|
-
}
|
|
60
|
-
function processFrameworkRequest(request, opts, framework) {
|
|
61
|
-
const requestHeaders = new Headers(request.headers);
|
|
62
|
-
const responseCookies = [];
|
|
63
|
-
const inboundPreprHeaders = [];
|
|
64
|
-
requestHeaders.forEach((_value, key) => {
|
|
65
|
-
if (key.toLowerCase().startsWith("prepr-")) {
|
|
66
|
-
inboundPreprHeaders.push(key);
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
for (const key of inboundPreprHeaders) {
|
|
70
|
-
requestHeaders.delete(key);
|
|
71
|
-
}
|
|
72
|
-
const requestCookies = parseCookies(request);
|
|
73
|
-
const url = new URL(request.url);
|
|
74
|
-
const searchParams = url.searchParams;
|
|
75
|
-
const forwardedProto = request.headers.get("x-forwarded-proto")?.split(",")[0]?.trim();
|
|
76
|
-
const isSecure = forwardedProto ? forwardedProto === "https" : url.protocol === "https:";
|
|
77
|
-
const crossSite = isSecure ? { sameSite: "None", secure: true } : {};
|
|
78
|
-
for (const key of UTM_PARAMS) {
|
|
79
|
-
const value = searchParams.get(key);
|
|
80
|
-
if (value !== null) {
|
|
81
|
-
requestHeaders.set(`Prepr-Context-${key}`, sanitizeHeaderValue(value));
|
|
20
|
+
// src/nextjs/webhook.ts
|
|
21
|
+
import { revalidateTag } from "next/cache";
|
|
22
|
+
var CONTENT_EVENTS = /* @__PURE__ */ new Set([
|
|
23
|
+
"content_item.published",
|
|
24
|
+
"content_item.unpublished",
|
|
25
|
+
"content_item.deleted",
|
|
26
|
+
"content_item.invalidated",
|
|
27
|
+
"asset.changed",
|
|
28
|
+
"asset.deleted"
|
|
29
|
+
]);
|
|
30
|
+
var MODEL_EVENTS = /* @__PURE__ */ new Set([
|
|
31
|
+
"content_item.published",
|
|
32
|
+
"content_item.unpublished",
|
|
33
|
+
"content_item.deleted"
|
|
34
|
+
]);
|
|
35
|
+
var MAX_AGE_MS = 5 * 60 * 1e3;
|
|
36
|
+
var HEX_SIGNATURE = /^[0-9a-f]{64}$/i;
|
|
37
|
+
var BASE64_SIGNATURE = /^[A-Za-z0-9+/]{43}=$/;
|
|
38
|
+
var SIGNATURE_PREFIX = /^sha256=/i;
|
|
39
|
+
var MAX_ID_LENGTH = 200;
|
|
40
|
+
var text = (body, status) => new Response(body, { status, headers: { "Content-Type": "text/plain" } });
|
|
41
|
+
function signatureBytes(header) {
|
|
42
|
+
const value = header.trim().replace(SIGNATURE_PREFIX, "");
|
|
43
|
+
if (HEX_SIGNATURE.test(value)) {
|
|
44
|
+
const bytes = new Uint8Array(32);
|
|
45
|
+
for (let i = 0; i < 32; i++) {
|
|
46
|
+
bytes[i] = parseInt(value.slice(i * 2, i * 2 + 2), 16);
|
|
82
47
|
}
|
|
48
|
+
return bytes;
|
|
83
49
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
requestHeaders.set(
|
|
87
|
-
"Prepr-Context-initial_referral",
|
|
88
|
-
sanitizeHeaderValue(referer)
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
const userAgent = request.headers.get("user-agent");
|
|
92
|
-
if (userAgent) {
|
|
93
|
-
requestHeaders.set("User-Agent", sanitizeHeaderValue(userAgent));
|
|
94
|
-
}
|
|
95
|
-
const packageParts = [`@preprio/toolkit@${opts?.version ?? VERSION}`];
|
|
96
|
-
if (framework) packageParts.push(`framework=${framework}`);
|
|
97
|
-
packageParts.push(`preview=${opts?.preview ? "true" : "false"}`);
|
|
98
|
-
requestHeaders.set("Prepr-Package", packageParts.join("; "));
|
|
99
|
-
const ip = request.headers.get("Cf-Connecting-Ip") ?? request.headers.get("x-real-ip");
|
|
100
|
-
if (ip) {
|
|
101
|
-
requestHeaders.set("Prepr-Visitor-IP", sanitizeHeaderValue(ip));
|
|
102
|
-
}
|
|
103
|
-
const hutkCookie = requestCookies.get(COOKIE_HUBSPOT);
|
|
104
|
-
if (hutkCookie) {
|
|
105
|
-
requestHeaders.set("Prepr-Hubspot-Id", sanitizeHeaderValue(hutkCookie));
|
|
106
|
-
}
|
|
107
|
-
let uid = sanitizeHeaderValue(requestCookies.get(COOKIE_UID) ?? "");
|
|
108
|
-
if (!uid) {
|
|
109
|
-
uid = crypto.randomUUID();
|
|
110
|
-
responseCookies.push({
|
|
111
|
-
name: COOKIE_UID,
|
|
112
|
-
value: uid,
|
|
113
|
-
maxAge: ONE_YEAR_SECONDS,
|
|
114
|
-
path: "/"
|
|
115
|
-
});
|
|
116
|
-
requestHeaders.set("Prepr-Customer-Id-Created", "true");
|
|
117
|
-
}
|
|
118
|
-
requestHeaders.set("Prepr-Customer-Id", uid);
|
|
119
|
-
if (!opts?.preview) {
|
|
120
|
-
return { requestHeaders, responseCookies };
|
|
121
|
-
}
|
|
122
|
-
const features = resolveFeatures(opts?.features);
|
|
123
|
-
const hasPreviewParams = features.segments && searchParams.has(PARAM_SEGMENT) || features.abTesting && searchParams.has(PARAM_VARIANT);
|
|
124
|
-
if (!hasPreviewParams) {
|
|
125
|
-
const previewModeCookie = requestCookies.get(COOKIE_PREVIEW_MODE);
|
|
126
|
-
const previewModeEnabled = previewModeCookie !== "false";
|
|
127
|
-
if (!previewModeEnabled) {
|
|
128
|
-
return { requestHeaders, responseCookies };
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
requestHeaders.set("Prepr-Preview-Bar", "true");
|
|
132
|
-
const isLivePreview = searchParams.get(PARAM_HIDE_BAR) === "true";
|
|
133
|
-
if (!isLivePreview && !requestCookies.has(COOKIE_PREVIEW_MODE)) {
|
|
134
|
-
responseCookies.push({
|
|
135
|
-
name: COOKIE_PREVIEW_MODE,
|
|
136
|
-
value: "true",
|
|
137
|
-
maxAge: ONE_YEAR_SECONDS,
|
|
138
|
-
path: "/",
|
|
139
|
-
...crossSite
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
if (!isLivePreview) {
|
|
143
|
-
const segmentCookie = features.segments ? requestCookies.get(COOKIE_SEGMENT) : void 0;
|
|
144
|
-
if (segmentCookie) {
|
|
145
|
-
requestHeaders.set("Prepr-Segments", sanitizeHeaderValue(segmentCookie));
|
|
146
|
-
}
|
|
147
|
-
const abCookie = features.abTesting ? requestCookies.get(COOKIE_VARIANT) : void 0;
|
|
148
|
-
if (abCookie) {
|
|
149
|
-
requestHeaders.set("Prepr-ABtesting", sanitizeHeaderValue(abCookie));
|
|
150
|
-
}
|
|
50
|
+
if (BASE64_SIGNATURE.test(value)) {
|
|
51
|
+
return Uint8Array.from(atob(value), (char) => char.charCodeAt(0));
|
|
151
52
|
}
|
|
152
|
-
|
|
153
|
-
if (previewAb !== null) {
|
|
154
|
-
requestHeaders.set("Prepr-ABtesting", sanitizeHeaderValue(previewAb));
|
|
155
|
-
if (!isLivePreview) {
|
|
156
|
-
responseCookies.push({
|
|
157
|
-
name: COOKIE_VARIANT,
|
|
158
|
-
value: previewAb,
|
|
159
|
-
maxAge: ONE_YEAR_SECONDS,
|
|
160
|
-
path: "/",
|
|
161
|
-
...crossSite
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
const previewSegment = features.segments ? searchParams.get(PARAM_SEGMENT) : null;
|
|
166
|
-
if (previewSegment !== null) {
|
|
167
|
-
requestHeaders.set("Prepr-Segments", sanitizeHeaderValue(previewSegment));
|
|
168
|
-
if (!isLivePreview) {
|
|
169
|
-
responseCookies.push({
|
|
170
|
-
name: COOKIE_SEGMENT,
|
|
171
|
-
value: previewSegment,
|
|
172
|
-
maxAge: ONE_YEAR_SECONDS,
|
|
173
|
-
path: "/",
|
|
174
|
-
...crossSite
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
if (requestHeaders.has("Prepr-Segments")) {
|
|
179
|
-
requestHeaders.delete("Prepr-Customer-Id");
|
|
180
|
-
requestHeaders.delete("Prepr-Customer-Id-Created");
|
|
181
|
-
}
|
|
182
|
-
return { requestHeaders, responseCookies };
|
|
53
|
+
return null;
|
|
183
54
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
options = maybeOptions;
|
|
192
|
-
} else {
|
|
193
|
-
options = responseOrOptions;
|
|
194
|
-
}
|
|
195
|
-
const { requestHeaders, responseCookies } = processFrameworkRequest(
|
|
196
|
-
request,
|
|
197
|
-
options,
|
|
198
|
-
"nextjs"
|
|
55
|
+
async function verify(secret, signature, body) {
|
|
56
|
+
const key = await crypto.subtle.importKey(
|
|
57
|
+
"raw",
|
|
58
|
+
new TextEncoder().encode(secret),
|
|
59
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
60
|
+
false,
|
|
61
|
+
["verify"]
|
|
199
62
|
);
|
|
200
|
-
|
|
201
|
-
if (chainedResponse) {
|
|
202
|
-
const existing = response.headers.get("x-middleware-override-headers");
|
|
203
|
-
const names = new Set(
|
|
204
|
-
existing ? existing.split(",").map((name) => name.trim()).filter(Boolean) : []
|
|
205
|
-
);
|
|
206
|
-
requestHeaders.forEach((value, key) => {
|
|
207
|
-
names.add(key);
|
|
208
|
-
response.headers.set(`x-middleware-request-${key}`, value);
|
|
209
|
-
});
|
|
210
|
-
response.headers.set("x-middleware-override-headers", [...names].join(","));
|
|
211
|
-
}
|
|
212
|
-
for (const cookie of responseCookies) {
|
|
213
|
-
response.cookies.set(cookie.name, cookie.value, {
|
|
214
|
-
maxAge: cookie.maxAge,
|
|
215
|
-
path: cookie.path,
|
|
216
|
-
// Lower-cased: Next's cookie API expects 'none' | 'lax' | 'strict'.
|
|
217
|
-
...cookie.sameSite ? {
|
|
218
|
-
sameSite: cookie.sameSite.toLowerCase()
|
|
219
|
-
} : {},
|
|
220
|
-
...cookie.secure ? { secure: true } : {}
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
return response;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// src/nextjs/bucket.ts
|
|
227
|
-
var PREPR_BUCKET_COOKIE = "prepr_ab_bucket";
|
|
228
|
-
var isBucket = (value) => value === "A" || value === "B";
|
|
229
|
-
function setBucketCookie(request, response, bucket) {
|
|
230
|
-
response.cookies.set(PREPR_BUCKET_COOKIE, bucket, {
|
|
231
|
-
path: "/",
|
|
232
|
-
sameSite: "lax",
|
|
233
|
-
// Readable on purpose: PreprStack's inline switch reads it before first
|
|
234
|
-
// paint. It holds only "A" or "B".
|
|
235
|
-
httpOnly: false,
|
|
236
|
-
secure: request.nextUrl.protocol === "https:",
|
|
237
|
-
maxAge: 60 * 60 * 24 * 365
|
|
238
|
-
});
|
|
63
|
+
return crypto.subtle.verify("HMAC", key, signature, body);
|
|
239
64
|
}
|
|
240
|
-
|
|
241
|
-
const stored = request.cookies.get(PREPR_BUCKET_COOKIE)?.value;
|
|
242
|
-
const forced = response.headers.get("x-middleware-request-prepr-abtesting") ?? request.cookies.get(COOKIE_VARIANT)?.value;
|
|
243
|
-
if (options.preview && isBucket(forced)) {
|
|
244
|
-
if (forced !== stored) setBucketCookie(request, response, forced);
|
|
245
|
-
return forced;
|
|
246
|
-
}
|
|
247
|
-
if (isBucket(stored)) return stored;
|
|
248
|
-
if (options.onlyIf) {
|
|
249
|
-
const needed = await Promise.resolve().then(options.onlyIf).catch(() => true);
|
|
250
|
-
if (!needed) return "A";
|
|
251
|
-
}
|
|
252
|
-
const customerId = request.cookies.get(COOKIE_UID)?.value ?? response.cookies.get(COOKIE_UID)?.value;
|
|
253
|
-
if (!customerId) return "A";
|
|
65
|
+
function parse(body) {
|
|
254
66
|
try {
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
headers: {
|
|
258
|
-
"Content-Type": "application/json",
|
|
259
|
-
"Prepr-Customer-Id": customerId
|
|
260
|
-
},
|
|
261
|
-
body: JSON.stringify({ query: "{ __typename }" }),
|
|
262
|
-
cache: "no-store",
|
|
263
|
-
signal: AbortSignal.timeout(options.timeoutMs ?? 1500)
|
|
264
|
-
});
|
|
265
|
-
const bucket = res.headers.get("x-prepr-customer-bucket");
|
|
266
|
-
if (isBucket(bucket)) {
|
|
267
|
-
setBucketCookie(request, response, bucket);
|
|
268
|
-
return bucket;
|
|
269
|
-
}
|
|
67
|
+
const value = JSON.parse(new TextDecoder().decode(body));
|
|
68
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
270
69
|
} catch {
|
|
70
|
+
return null;
|
|
271
71
|
}
|
|
272
|
-
return "A";
|
|
273
72
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
var DEFAULT_ROUTE = "/api/prepr/draft";
|
|
282
|
-
function preprDraftRedirect(request, options) {
|
|
283
|
-
if (!options.preview) return null;
|
|
284
|
-
if (request.method !== "GET" && request.method !== "HEAD") return null;
|
|
285
|
-
const url = request.nextUrl;
|
|
286
|
-
if (url.pathname === (options.route ?? DEFAULT_ROUTE)) return null;
|
|
287
|
-
if (request.cookies.has(DRAFT_COOKIE)) {
|
|
288
|
-
if (!url.searchParams.has(RETURN_PARAM)) return null;
|
|
289
|
-
const clean = url.clone();
|
|
290
|
-
clean.searchParams.delete(RETURN_PARAM);
|
|
291
|
-
return NextResponse2.redirect(clean, 307);
|
|
292
|
-
}
|
|
293
|
-
if (url.searchParams.has(RETURN_PARAM)) return null;
|
|
294
|
-
const target = new URL(options.route ?? DEFAULT_ROUTE, request.url);
|
|
295
|
-
target.searchParams.set("to", url.pathname + url.search);
|
|
296
|
-
return NextResponse2.redirect(target, 307);
|
|
73
|
+
function eventTime(value) {
|
|
74
|
+
if (typeof value === "number") return value * 1e3;
|
|
75
|
+
if (typeof value === "string") return Date.parse(value);
|
|
76
|
+
return NaN;
|
|
77
|
+
}
|
|
78
|
+
function field(value, key) {
|
|
79
|
+
return typeof value === "object" && value !== null ? value[key] : void 0;
|
|
297
80
|
}
|
|
298
|
-
|
|
81
|
+
var usable = (value) => typeof value === "string" && value !== "" && value.length <= MAX_ID_LENGTH;
|
|
82
|
+
function tagsFor(event) {
|
|
83
|
+
const name = event.event;
|
|
84
|
+
if (name === "schema.changed") return [PREPR_SCHEMA_TAG];
|
|
85
|
+
if (typeof name !== "string" || !CONTENT_EVENTS.has(name)) return [];
|
|
86
|
+
const tags = [PREPR_ANY_ITEM_TAG];
|
|
87
|
+
const id = field(event.payload, "id");
|
|
88
|
+
if (usable(id)) tags.push(preprItemTag(id));
|
|
89
|
+
const model = field(field(event.payload, "model"), "body_singular");
|
|
90
|
+
if (MODEL_EVENTS.has(name) && usable(model)) tags.push(preprModelTag(model));
|
|
91
|
+
return tags;
|
|
92
|
+
}
|
|
93
|
+
function createPreprWebhookRoute(options) {
|
|
94
|
+
const { profile = { expire: 0 } } = options;
|
|
299
95
|
return async (request) => {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
const
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
96
|
+
const { secret } = options;
|
|
97
|
+
if (!secret) return text("Webhook secret not configured", 500);
|
|
98
|
+
const signature = signatureBytes(
|
|
99
|
+
request.headers.get("prepr-signature") ?? ""
|
|
100
|
+
);
|
|
101
|
+
let body;
|
|
102
|
+
try {
|
|
103
|
+
body = await request.arrayBuffer();
|
|
104
|
+
} catch {
|
|
105
|
+
return text("Unreadable body", 400);
|
|
106
|
+
}
|
|
107
|
+
if (!signature || !await verify(secret, signature, body)) {
|
|
108
|
+
return text("Invalid signature", 401);
|
|
109
|
+
}
|
|
110
|
+
const event = parse(body);
|
|
111
|
+
if (!event) return text("Invalid body", 400);
|
|
112
|
+
const sentAt = eventTime(event.created_on);
|
|
113
|
+
if (Number.isFinite(sentAt) && Math.abs(Date.now() - sentAt) > MAX_AGE_MS) {
|
|
114
|
+
return text("Expired", 401);
|
|
317
115
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
redirect(to.pathname + to.search);
|
|
116
|
+
const tags = tagsFor(event);
|
|
117
|
+
for (const tag of tags) revalidateTag(tag, profile);
|
|
118
|
+
return Response.json({ revalidated: tags });
|
|
322
119
|
};
|
|
323
120
|
}
|
|
324
121
|
|
|
325
122
|
// src/nextjs/index.ts
|
|
326
123
|
import {
|
|
124
|
+
PreprPersonalizationSwitch,
|
|
327
125
|
PreprToolbar,
|
|
328
126
|
PreprTrackingPixel
|
|
329
127
|
} from "./components.js";
|
|
330
128
|
export {
|
|
331
|
-
PREPR_BUCKET_COOKIE,
|
|
332
129
|
PreprError,
|
|
130
|
+
PreprPersonalizationSwitch,
|
|
333
131
|
PreprToolbar,
|
|
334
132
|
PreprTrackingPixel,
|
|
335
133
|
createPreprDraftRoute,
|
|
336
134
|
createPreprMiddleware,
|
|
135
|
+
createPreprWebhookRoute,
|
|
337
136
|
extractAccessToken,
|
|
338
137
|
getActiveSegment,
|
|
339
138
|
getActiveVariant,
|
|
@@ -342,6 +141,5 @@ export {
|
|
|
342
141
|
getToolbarProps,
|
|
343
142
|
isPersonalizedResponse,
|
|
344
143
|
preprDraftRedirect,
|
|
345
|
-
resolvePreprBucket,
|
|
346
144
|
validatePreprToken
|
|
347
145
|
};
|
|
@@ -153,4 +153,4 @@ declare function validatePreprToken(token: string): void;
|
|
|
153
153
|
*/
|
|
154
154
|
declare function extractAccessToken(graphqlUrl: string): string;
|
|
155
155
|
|
|
156
|
-
export { type PreprHeaders as P,
|
|
156
|
+
export { type PreprHeaders as P, type PreprFeatures as a, PreprError as b, type PreprToolbarProps as c, type PreprToolbarComponentProps as d, extractAccessToken as e, isPersonalizedResponse as i, validatePreprToken as v };
|
|
@@ -153,4 +153,4 @@ declare function validatePreprToken(token: string): void;
|
|
|
153
153
|
*/
|
|
154
154
|
declare function extractAccessToken(graphqlUrl: string): string;
|
|
155
155
|
|
|
156
|
-
export { type PreprHeaders as P,
|
|
156
|
+
export { type PreprHeaders as P, type PreprFeatures as a, PreprError as b, type PreprToolbarProps as c, type PreprToolbarComponentProps as d, extractAccessToken as e, isPersonalizedResponse as i, validatePreprToken as v };
|
package/dist/nuxt/graphql.cjs
CHANGED
|
@@ -178,7 +178,10 @@ function decisionSelectionSet(set, typeName, path, ctx) {
|
|
|
178
178
|
path,
|
|
179
179
|
ctx
|
|
180
180
|
);
|
|
181
|
-
if (pruned)
|
|
181
|
+
if (!pruned) continue;
|
|
182
|
+
if (fragment.typeCondition.name.value === typeName) {
|
|
183
|
+
selections.push(...pruned.selections);
|
|
184
|
+
} else {
|
|
182
185
|
selections.push(
|
|
183
186
|
inlineFragment(fragment.typeCondition.name.value, [
|
|
184
187
|
...pruned.selections
|
|
@@ -188,13 +191,19 @@ function decisionSelectionSet(set, typeName, path, ctx) {
|
|
|
188
191
|
continue;
|
|
189
192
|
}
|
|
190
193
|
if (selection.kind === "InlineFragment") {
|
|
194
|
+
const condition = selection.typeCondition?.name.value ?? typeName;
|
|
191
195
|
const pruned = decisionSelectionSet(
|
|
192
196
|
selection.selectionSet,
|
|
193
|
-
|
|
197
|
+
condition,
|
|
194
198
|
path,
|
|
195
199
|
ctx
|
|
196
200
|
);
|
|
197
|
-
if (pruned)
|
|
201
|
+
if (!pruned) continue;
|
|
202
|
+
if (condition === typeName && !selection.directives?.length) {
|
|
203
|
+
selections.push(...pruned.selections);
|
|
204
|
+
} else {
|
|
205
|
+
selections.push({ ...selection, selectionSet: pruned });
|
|
206
|
+
}
|
|
198
207
|
continue;
|
|
199
208
|
}
|
|
200
209
|
if (!selection.selectionSet) continue;
|
|
@@ -268,20 +277,58 @@ function toDecisionDocument(document2, schema, groupPaths, options) {
|
|
|
268
277
|
const used = /* @__PURE__ */ new Set();
|
|
269
278
|
collectVariables(pruned, used);
|
|
270
279
|
collectVariables(operation.directives, used);
|
|
280
|
+
const shared = sharedContextFragment(schema);
|
|
271
281
|
return {
|
|
272
282
|
kind: "Document",
|
|
273
283
|
definitions: [
|
|
284
|
+
...shared ? [shared.definition] : [],
|
|
274
285
|
{
|
|
275
286
|
...operation,
|
|
276
287
|
name: operation.name && name(`${operation.name.value}Decision`),
|
|
277
288
|
variableDefinitions: (operation.variableDefinitions ?? []).filter(
|
|
278
289
|
(definition) => used.has(definition.variable.name.value)
|
|
279
290
|
),
|
|
280
|
-
selectionSet: pruned
|
|
291
|
+
selectionSet: shared ? shared.apply(pruned) : pruned
|
|
281
292
|
}
|
|
282
293
|
]
|
|
283
294
|
};
|
|
284
295
|
}
|
|
296
|
+
function sharedContextFragment(schema) {
|
|
297
|
+
const contextTypes = new Set(
|
|
298
|
+
Object.values(schema.types).flatMap(
|
|
299
|
+
(type) => type.hasContext ? [type.fields._context.type] : []
|
|
300
|
+
)
|
|
301
|
+
);
|
|
302
|
+
if (contextTypes.size !== 1) return null;
|
|
303
|
+
const [contextType] = contextTypes;
|
|
304
|
+
const fragmentName = "c";
|
|
305
|
+
const definition = {
|
|
306
|
+
kind: "FragmentDefinition",
|
|
307
|
+
name: name(fragmentName),
|
|
308
|
+
typeCondition: { kind: "NamedType", name: name(contextType) },
|
|
309
|
+
selectionSet: selectionSet(
|
|
310
|
+
["kind", "group_id", "variant_id"].map(
|
|
311
|
+
(field) => ({ kind: "Field", name: name(field) })
|
|
312
|
+
)
|
|
313
|
+
)
|
|
314
|
+
};
|
|
315
|
+
const spread = {
|
|
316
|
+
kind: "FragmentSpread",
|
|
317
|
+
name: name(fragmentName)
|
|
318
|
+
};
|
|
319
|
+
const apply = (set) => selectionSet(
|
|
320
|
+
set.selections.map((selection) => {
|
|
321
|
+
if (selection.kind === "Field" && selection.alias?.value === PREPR_CONTEXT_ALIAS) {
|
|
322
|
+
return { ...selection, selectionSet: selectionSet([spread]) };
|
|
323
|
+
}
|
|
324
|
+
return "selectionSet" in selection && selection.selectionSet ? {
|
|
325
|
+
...selection,
|
|
326
|
+
selectionSet: apply(selection.selectionSet)
|
|
327
|
+
} : selection;
|
|
328
|
+
})
|
|
329
|
+
);
|
|
330
|
+
return { definition, apply };
|
|
331
|
+
}
|
|
285
332
|
|
|
286
333
|
// src/core/variants/probe-document.ts
|
|
287
334
|
function probeSelectionSet(set, fragments) {
|
|
@@ -862,6 +909,7 @@ function createVaryProbe(run, options) {
|
|
|
862
909
|
}
|
|
863
910
|
|
|
864
911
|
// src/core/graphql/client.ts
|
|
912
|
+
var clientSchemas = /* @__PURE__ */ new WeakMap();
|
|
865
913
|
function isParseableUrl(url) {
|
|
866
914
|
try {
|
|
867
915
|
new URL(url);
|
|
@@ -898,7 +946,7 @@ function createPreprClient(options) {
|
|
|
898
946
|
));
|
|
899
947
|
const variantsDocuments = /* @__PURE__ */ new Map();
|
|
900
948
|
const decisionDocuments = /* @__PURE__ */ new Map();
|
|
901
|
-
|
|
949
|
+
const client = {
|
|
902
950
|
async query(document2, variables, queryOptions = {}) {
|
|
903
951
|
const { variants, ...rest } = queryOptions;
|
|
904
952
|
if (!variants) return run(document2, variables, rest);
|
|
@@ -910,10 +958,10 @@ function createPreprClient(options) {
|
|
|
910
958
|
return run(derived, variables, rest);
|
|
911
959
|
},
|
|
912
960
|
async decide(document2, variables, queryOptions = {}) {
|
|
913
|
-
const { from,
|
|
961
|
+
const { from, ...rest } = queryOptions;
|
|
914
962
|
const paths = from === void 0 ? void 0 : personalizationPaths(from);
|
|
915
963
|
if (paths && paths.size === 0) return /* @__PURE__ */ new Map();
|
|
916
|
-
const signature = paths ? [...paths].map(([path, types]) => `${path}:${[...types].sort().join(",")}`).sort().join("|") :
|
|
964
|
+
const signature = paths ? [...paths].map(([path, types]) => `${path}:${[...types].sort().join(",")}`).sort().join("|") : "*";
|
|
917
965
|
let byPaths = decisionDocuments.get(document2);
|
|
918
966
|
if (!byPaths) {
|
|
919
967
|
byPaths = /* @__PURE__ */ new Map();
|
|
@@ -921,9 +969,7 @@ function createPreprClient(options) {
|
|
|
921
969
|
}
|
|
922
970
|
let derived = byPaths.get(signature);
|
|
923
971
|
if (derived === void 0) {
|
|
924
|
-
derived = toDecisionDocument(document2, await loadSchema(), paths
|
|
925
|
-
topLevelOnly: !paths && topLevelOnly
|
|
926
|
-
});
|
|
972
|
+
derived = toDecisionDocument(document2, await loadSchema(), paths);
|
|
927
973
|
byPaths.set(signature, derived);
|
|
928
974
|
}
|
|
929
975
|
if (!derived) return /* @__PURE__ */ new Map();
|
|
@@ -937,6 +983,8 @@ function createPreprClient(options) {
|
|
|
937
983
|
(vary) => vary === null || SEGMENTS_VARY.test(vary)
|
|
938
984
|
)
|
|
939
985
|
};
|
|
986
|
+
clientSchemas.set(client, loadSchema);
|
|
987
|
+
return client;
|
|
940
988
|
}
|
|
941
989
|
|
|
942
990
|
// src/core/graphql/event-client.ts
|