@preprio/toolkit 0.5.0-rc.1 → 0.6.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +300 -19
  2. package/dist/astro/chunk-3UVUDDNY.js +173 -0
  3. package/dist/astro/graphql.cjs +983 -0
  4. package/dist/astro/graphql.d.cts +231 -0
  5. package/dist/astro/graphql.d.ts +231 -0
  6. package/dist/astro/graphql.js +893 -0
  7. package/dist/astro/index-XT_z-RYT.d.cts +130 -0
  8. package/dist/astro/index-XT_z-RYT.d.ts +130 -0
  9. package/dist/astro/index.cjs +14 -1
  10. package/dist/astro/index.d.cts +1 -120
  11. package/dist/astro/index.d.ts +1 -120
  12. package/dist/astro/index.js +15 -153
  13. package/dist/{chunk-4JNKYIEV.js → chunk-BJ2LBLWO.js} +69 -268
  14. package/dist/chunk-DGZA7KX7.js +172 -0
  15. package/dist/chunk-YR7P4IWE.js +187 -0
  16. package/dist/graphql.cjs +894 -0
  17. package/dist/graphql.d.cts +231 -0
  18. package/dist/graphql.d.ts +231 -0
  19. package/dist/graphql.js +787 -0
  20. package/dist/index.cjs +74 -111
  21. package/dist/index.d.cts +11 -62
  22. package/dist/index.d.ts +11 -62
  23. package/dist/index.js +23 -167
  24. package/dist/nextjs/chunk-U4HXENF7.js +231 -0
  25. package/dist/nextjs/components.cjs +188 -114
  26. package/dist/nextjs/components.d.cts +33 -2
  27. package/dist/nextjs/components.d.ts +33 -2
  28. package/dist/nextjs/components.js +132 -4
  29. package/dist/nextjs/graphql.cjs +1315 -0
  30. package/dist/nextjs/graphql.d.cts +361 -0
  31. package/dist/nextjs/graphql.d.ts +361 -0
  32. package/dist/nextjs/graphql.js +1218 -0
  33. package/dist/nextjs/index.cjs +126 -6
  34. package/dist/nextjs/index.d.cts +53 -141
  35. package/dist/nextjs/index.d.ts +53 -141
  36. package/dist/nextjs/index.js +113 -203
  37. package/dist/nextjs/server-CjpELYvq.d.cts +156 -0
  38. package/dist/nextjs/server-CjpELYvq.d.ts +156 -0
  39. package/dist/nuxt/chunk-P6ENNAEE.js +417 -0
  40. package/dist/nuxt/graphql.cjs +990 -0
  41. package/dist/nuxt/graphql.d.cts +228 -0
  42. package/dist/nuxt/graphql.d.ts +228 -0
  43. package/dist/nuxt/graphql.js +894 -0
  44. package/dist/nuxt/index.cjs +14 -1
  45. package/dist/nuxt/index.d.cts +3 -148
  46. package/dist/nuxt/index.d.ts +3 -148
  47. package/dist/nuxt/index.js +15 -391
  48. package/dist/nuxt/server-8v6OHbsw.d.cts +158 -0
  49. package/dist/nuxt/server-8v6OHbsw.d.ts +158 -0
  50. package/dist/pixel-DwW7cXJm.d.cts +49 -0
  51. package/dist/pixel-DwW7cXJm.d.ts +49 -0
  52. package/dist/react/components.cjs +86 -112
  53. package/dist/react/components.js +86 -112
  54. package/dist/server-Brr1UgtW.d.ts +59 -0
  55. package/dist/server-DJuS3YU0.d.cts +59 -0
  56. package/dist/sveltekit/chunk-FSARVMG5.js +413 -0
  57. package/dist/sveltekit/graphql.cjs +996 -0
  58. package/dist/sveltekit/graphql.d.cts +233 -0
  59. package/dist/sveltekit/graphql.d.ts +233 -0
  60. package/dist/sveltekit/graphql.js +900 -0
  61. package/dist/sveltekit/index.cjs +14 -1
  62. package/dist/sveltekit/index.d.cts +3 -88
  63. package/dist/sveltekit/index.d.ts +3 -88
  64. package/dist/sveltekit/index.js +15 -387
  65. package/dist/sveltekit/server-CO847mEV.d.cts +98 -0
  66. package/dist/sveltekit/server-CO847mEV.d.ts +98 -0
  67. package/dist/{pixel-e1fUWl2Y.d.cts → types-BYH9XqmN.d.cts} +2 -50
  68. package/dist/{pixel-e1fUWl2Y.d.ts → types-BYH9XqmN.d.ts} +2 -50
  69. package/package.json +31 -1
@@ -0,0 +1,1218 @@
1
+ import {
2
+ PreprError,
3
+ getPreprHeaders,
4
+ getPreprHeadersFromHeaders,
5
+ isPersonalizedResponse,
6
+ validatePreprToken
7
+ } from "./chunk-U4HXENF7.js";
8
+
9
+ // src/core/variants/constants.ts
10
+ var PREPR_CONTEXT_ALIAS = "_preprContext";
11
+ var PREPR_TYPE_ALIAS = "_preprType";
12
+ var PREPR_DEFAULT_VARIANT = "ALL_OTHER_USERS";
13
+
14
+ // src/core/variants/ast.ts
15
+ import { parse } from "graphql/language/parser.js";
16
+ var name = (value) => ({ kind: "Name", value });
17
+ function selectionSet(selections) {
18
+ return { kind: "SelectionSet", selections };
19
+ }
20
+ function contextField(withKey) {
21
+ const fields = ["kind", "group_id", "variant_id"];
22
+ if (withKey) fields.push("variant_key");
23
+ return {
24
+ kind: "Field",
25
+ alias: name(PREPR_CONTEXT_ALIAS),
26
+ name: name("_context"),
27
+ selectionSet: selectionSet(
28
+ fields.map(
29
+ (field) => ({ kind: "Field", name: name(field) })
30
+ )
31
+ )
32
+ };
33
+ }
34
+ function typenameField() {
35
+ return {
36
+ kind: "Field",
37
+ alias: name(PREPR_TYPE_ALIAS),
38
+ name: name("__typename")
39
+ };
40
+ }
41
+ function inlineFragment(typeName, selections) {
42
+ return {
43
+ kind: "InlineFragment",
44
+ typeCondition: { kind: "NamedType", name: name(typeName) },
45
+ selectionSet: selectionSet(selections)
46
+ };
47
+ }
48
+ function contextSelections(typeName, schema, onlyTypes, withType = true) {
49
+ const fields = () => withType ? [contextField(true), typenameField()] : [contextField(false)];
50
+ const type = schema.types[typeName];
51
+ if (!type) return [];
52
+ if (type.possibleTypes.length > 0) {
53
+ return type.possibleTypes.filter(
54
+ (member) => schema.types[member]?.hasContext && (!onlyTypes || onlyTypes.has(member))
55
+ ).map((member) => inlineFragment(member, fields()));
56
+ }
57
+ return type.hasContext ? fields() : [];
58
+ }
59
+ function withoutPersonalizeArg(args = []) {
60
+ return args.filter((arg) => arg.name.value !== "personalize");
61
+ }
62
+ function documentOf(document2) {
63
+ if (typeof document2 === "string") return parse(document2);
64
+ if (document2 instanceof String) return parse(document2.toString());
65
+ return document2;
66
+ }
67
+ function collectVariables(node, used) {
68
+ if (!node || typeof node !== "object") return;
69
+ if (Array.isArray(node)) {
70
+ for (const item of node) collectVariables(item, used);
71
+ return;
72
+ }
73
+ const value = node;
74
+ if (value.kind === "Variable") {
75
+ used.add(value.name.value);
76
+ return;
77
+ }
78
+ for (const key of Object.keys(value)) {
79
+ if (key !== "loc") collectVariables(value[key], used);
80
+ }
81
+ }
82
+
83
+ // src/core/variants/decision-document.ts
84
+ function decisionSelectionSet(set, typeName, path, ctx) {
85
+ const selections = [];
86
+ for (const selection of set.selections) {
87
+ if (selection.kind === "FragmentSpread") {
88
+ const fragment = ctx.fragments[selection.name.value];
89
+ if (!fragment) continue;
90
+ const pruned = decisionSelectionSet(
91
+ fragment.selectionSet,
92
+ fragment.typeCondition.name.value,
93
+ path,
94
+ ctx
95
+ );
96
+ if (pruned) {
97
+ selections.push(
98
+ inlineFragment(fragment.typeCondition.name.value, [
99
+ ...pruned.selections
100
+ ])
101
+ );
102
+ }
103
+ continue;
104
+ }
105
+ if (selection.kind === "InlineFragment") {
106
+ const pruned = decisionSelectionSet(
107
+ selection.selectionSet,
108
+ selection.typeCondition?.name.value ?? typeName,
109
+ path,
110
+ ctx
111
+ );
112
+ if (pruned) selections.push({ ...selection, selectionSet: pruned });
113
+ continue;
114
+ }
115
+ if (!selection.selectionSet) continue;
116
+ const field = ctx.schema.types[typeName]?.fields[selection.name.value];
117
+ if (!field) continue;
118
+ const key = selection.alias?.value ?? selection.name.value;
119
+ const fieldPath = path ? `${path}.${key}` : key;
120
+ if (ctx.paths && !ctx.paths.prefixes.has(fieldPath)) continue;
121
+ const child = decisionSelectionSet(
122
+ selection.selectionSet,
123
+ field.type,
124
+ fieldPath,
125
+ ctx
126
+ );
127
+ const groupTypes = ctx.paths?.groups.get(fieldPath);
128
+ const holdsGroups = field.personalizable && (!ctx.paths || groupTypes !== void 0);
129
+ if (holdsGroups) {
130
+ selections.push({
131
+ ...selection,
132
+ arguments: withoutPersonalizeArg(selection.arguments),
133
+ selectionSet: selectionSet([
134
+ ...ctx.topLevelOnly ? [] : child?.selections ?? [],
135
+ ...contextSelections(
136
+ field.type,
137
+ ctx.schema,
138
+ groupTypes && !groupTypes.has("*") ? groupTypes : void 0,
139
+ false
140
+ )
141
+ ])
142
+ });
143
+ } else if (child) {
144
+ selections.push({
145
+ ...selection,
146
+ arguments: field.personalizable ? withoutPersonalizeArg(selection.arguments) : selection.arguments,
147
+ selectionSet: child
148
+ });
149
+ }
150
+ }
151
+ return selections.length > 0 ? selectionSet(selections) : null;
152
+ }
153
+ function toDecisionDocument(document2, schema, groupPaths, options) {
154
+ const doc = documentOf(document2);
155
+ const fragments = {};
156
+ for (const definition of doc.definitions) {
157
+ if (definition.kind === "FragmentDefinition") {
158
+ fragments[definition.name.value] = definition;
159
+ }
160
+ }
161
+ const operation = doc.definitions.find(
162
+ (definition) => definition.kind === "OperationDefinition"
163
+ );
164
+ if (!operation) return null;
165
+ let paths;
166
+ if (groupPaths) {
167
+ const prefixes = /* @__PURE__ */ new Set();
168
+ for (const groupPath of groupPaths.keys()) {
169
+ const parts = groupPath.split(".");
170
+ for (let i = 1; i <= parts.length; i++) {
171
+ prefixes.add(parts.slice(0, i).join("."));
172
+ }
173
+ }
174
+ paths = { groups: groupPaths, prefixes };
175
+ }
176
+ const pruned = decisionSelectionSet(
177
+ operation.selectionSet,
178
+ schema.queryType,
179
+ "",
180
+ { schema, fragments, paths, topLevelOnly: options?.topLevelOnly }
181
+ );
182
+ if (!pruned) return null;
183
+ const used = /* @__PURE__ */ new Set();
184
+ collectVariables(pruned, used);
185
+ collectVariables(operation.directives, used);
186
+ return {
187
+ kind: "Document",
188
+ definitions: [
189
+ {
190
+ ...operation,
191
+ name: operation.name && name(`${operation.name.value}Decision`),
192
+ variableDefinitions: (operation.variableDefinitions ?? []).filter(
193
+ (definition) => used.has(definition.variable.name.value)
194
+ ),
195
+ selectionSet: pruned
196
+ }
197
+ ]
198
+ };
199
+ }
200
+
201
+ // src/core/variants/probe-document.ts
202
+ function probeSelectionSet(set, fragments) {
203
+ const selections = [
204
+ { kind: "Field", name: name("__typename") }
205
+ ];
206
+ for (const selection of set.selections) {
207
+ if (selection.kind === "Field") {
208
+ if (!selection.selectionSet) continue;
209
+ selections.push({
210
+ ...selection,
211
+ selectionSet: probeSelectionSet(selection.selectionSet, fragments)
212
+ });
213
+ continue;
214
+ }
215
+ const fragment = selection.kind === "InlineFragment" ? selection : fragments[selection.name.value];
216
+ if (!fragment) continue;
217
+ const child = probeSelectionSet(fragment.selectionSet, fragments);
218
+ if (child.selections.length === 1) continue;
219
+ selections.push({
220
+ kind: "InlineFragment",
221
+ typeCondition: fragment.typeCondition,
222
+ directives: selection.directives,
223
+ selectionSet: child
224
+ });
225
+ }
226
+ return selectionSet(selections);
227
+ }
228
+ function toAbProbeDocument(document2) {
229
+ const doc = documentOf(document2);
230
+ const fragments = {};
231
+ for (const definition of doc.definitions) {
232
+ if (definition.kind === "FragmentDefinition") {
233
+ fragments[definition.name.value] = definition;
234
+ }
235
+ }
236
+ const operation = doc.definitions.find(
237
+ (definition) => definition.kind === "OperationDefinition"
238
+ );
239
+ if (!operation) return null;
240
+ const probe = probeSelectionSet(operation.selectionSet, fragments);
241
+ const used = /* @__PURE__ */ new Set();
242
+ collectVariables(probe, used);
243
+ collectVariables(operation.directives, used);
244
+ return {
245
+ kind: "Document",
246
+ definitions: [
247
+ {
248
+ ...operation,
249
+ name: operation.name && name(`${operation.name.value}AbCheck`),
250
+ variableDefinitions: (operation.variableDefinitions ?? []).filter(
251
+ (definition) => used.has(definition.variable.name.value)
252
+ ),
253
+ selectionSet: probe
254
+ }
255
+ ]
256
+ };
257
+ }
258
+
259
+ // src/core/variants/resolve.ts
260
+ function personalizationPaths(data) {
261
+ const paths = /* @__PURE__ */ new Map();
262
+ const walk = (value, path) => {
263
+ if (Array.isArray(value)) {
264
+ for (const item of value) {
265
+ if (contextOf(item)?.kind === "PERSONALIZATION") {
266
+ const record = item;
267
+ const type = record[PREPR_TYPE_ALIAS] ?? record.__typename;
268
+ const types = paths.get(path) ?? /* @__PURE__ */ new Set();
269
+ types.add(typeof type === "string" ? type : "*");
270
+ paths.set(path, types);
271
+ }
272
+ walk(item, path);
273
+ }
274
+ return;
275
+ }
276
+ if (!value || typeof value !== "object") return;
277
+ for (const [key, child] of Object.entries(value)) {
278
+ if (key !== PREPR_CONTEXT_ALIAS && key !== PREPR_TYPE_ALIAS)
279
+ walk(child, path ? `${path}.${key}` : key);
280
+ }
281
+ };
282
+ walk(data, "");
283
+ return paths;
284
+ }
285
+ function contextOf(item) {
286
+ if (!item || typeof item !== "object") return null;
287
+ const context = item[PREPR_CONTEXT_ALIAS];
288
+ const ctx = context;
289
+ return ctx?.kind && ctx.group_id ? ctx : null;
290
+ }
291
+ function decisionsFrom(data) {
292
+ const decisions = /* @__PURE__ */ new Map();
293
+ const walk = (value) => {
294
+ if (Array.isArray(value)) return value.forEach(walk);
295
+ if (!value || typeof value !== "object") return;
296
+ const ctx = contextOf(value);
297
+ if (ctx?.group_id && ctx.variant_id) {
298
+ const ids = decisions.get(ctx.group_id) ?? [];
299
+ if (!ids.includes(ctx.variant_id)) ids.push(ctx.variant_id);
300
+ decisions.set(ctx.group_id, ids);
301
+ }
302
+ Object.values(value).forEach(walk);
303
+ };
304
+ walk(data);
305
+ return decisions;
306
+ }
307
+ function chosenVariants(ctx, options) {
308
+ const decided = options.decisions?.get(ctx.group_id);
309
+ if (ctx.kind === "AB_TEST") {
310
+ return options.bucket ? [options.bucket] : decided ?? ["A"];
311
+ }
312
+ return decided ?? [PREPR_DEFAULT_VARIANT];
313
+ }
314
+ function resolveVariants(data, options = {}) {
315
+ const resolve = (value) => {
316
+ if (Array.isArray(value)) {
317
+ return value.filter((item) => {
318
+ const ctx = contextOf(item);
319
+ return !ctx || chosenVariants(ctx, options).includes(ctx.variant_id ?? "");
320
+ }).map(resolve);
321
+ }
322
+ if (!value || typeof value !== "object") return value;
323
+ const out = {};
324
+ for (const [key, child] of Object.entries(value)) out[key] = resolve(child);
325
+ return out;
326
+ };
327
+ return resolve(data);
328
+ }
329
+
330
+ // src/core/variants/schema.ts
331
+ var PREPR_SCHEMA_QUERY = `query PreprPersonalizationSchema {
332
+ __schema {
333
+ queryType { name }
334
+ types {
335
+ name
336
+ possibleTypes { name }
337
+ fields {
338
+ name
339
+ args { name }
340
+ type { name ofType { name ofType { name ofType { name ofType { name } } } } }
341
+ }
342
+ }
343
+ }
344
+ }`;
345
+ function namedType(ref) {
346
+ let current = ref;
347
+ while (current && !current.name) current = current.ofType;
348
+ return current?.name ?? "";
349
+ }
350
+ function toSchemaInfo(introspection) {
351
+ const types = {};
352
+ for (const type of introspection.__schema.types) {
353
+ if (type.name.startsWith("__")) continue;
354
+ const fields = {};
355
+ for (const field of type.fields ?? []) {
356
+ fields[field.name] = {
357
+ type: namedType(field.type),
358
+ personalizable: field.args.some((arg) => arg.name === "personalize")
359
+ };
360
+ }
361
+ types[type.name] = {
362
+ fields,
363
+ possibleTypes: (type.possibleTypes ?? []).map((t) => t.name),
364
+ hasContext: "_context" in fields
365
+ };
366
+ }
367
+ return { queryType: introspection.__schema.queryType.name, types };
368
+ }
369
+
370
+ // src/core/variants/stack.ts
371
+ function containsKind(value, kind) {
372
+ if (Array.isArray(value))
373
+ return value.some((item) => containsKind(item, kind));
374
+ if (!value || typeof value !== "object") return false;
375
+ if (contextOf(value)?.kind === kind) return true;
376
+ return Object.values(value).some((child) => containsKind(child, kind));
377
+ }
378
+ function splitStack(items) {
379
+ const blocks = [];
380
+ let position = 0;
381
+ const positionsOf = (block) => block.key.startsWith("group:") ? 1 : block.items.length;
382
+ items.forEach((item, index) => {
383
+ const ctx = contextOf(item);
384
+ const groupKey = ctx ? `group:${ctx.group_id}` : null;
385
+ const personalized = containsKind(item, "PERSONALIZATION");
386
+ const abTest = containsKind(item, "AB_TEST");
387
+ const last = blocks.at(-1);
388
+ const plain = !groupKey && !personalized && !abTest;
389
+ if (groupKey && last?.key === groupKey) {
390
+ last.personalized || (last.personalized = personalized);
391
+ last.abTest || (last.abTest = abTest);
392
+ last.items.push(item);
393
+ } else if (plain && last && !last.personalized && !last.abTest) {
394
+ last.items.push(item);
395
+ } else {
396
+ const last2 = blocks.at(-1);
397
+ if (last2) position = last2.index + positionsOf(last2);
398
+ blocks.push({
399
+ key: groupKey ?? `items:${index}`,
400
+ items: [item],
401
+ index: position,
402
+ personalized,
403
+ abTest
404
+ });
405
+ }
406
+ });
407
+ return blocks;
408
+ }
409
+
410
+ // src/core/variants/tracking.ts
411
+ function preprVariantProps(item) {
412
+ const key = contextOf(item)?.variant_key;
413
+ return key ? { "data-prepr-variant-key": key } : {};
414
+ }
415
+
416
+ // src/core/variants/variants-document.ts
417
+ function variantsSelectionSet(set, typeName, schema) {
418
+ const selections = set.selections.map((selection) => {
419
+ if (selection.kind === "InlineFragment") {
420
+ return {
421
+ ...selection,
422
+ selectionSet: variantsSelectionSet(
423
+ selection.selectionSet,
424
+ selection.typeCondition?.name.value ?? typeName,
425
+ schema
426
+ )
427
+ };
428
+ }
429
+ if (selection.kind !== "Field" || !selection.selectionSet) return selection;
430
+ const field = schema.types[typeName]?.fields[selection.name.value];
431
+ if (!field) return selection;
432
+ const child = variantsSelectionSet(
433
+ selection.selectionSet,
434
+ field.type,
435
+ schema
436
+ );
437
+ if (!field.personalizable) return { ...selection, selectionSet: child };
438
+ return {
439
+ ...selection,
440
+ arguments: [
441
+ ...withoutPersonalizeArg(selection.arguments),
442
+ {
443
+ kind: "Argument",
444
+ name: name("personalize"),
445
+ value: { kind: "BooleanValue", value: false }
446
+ }
447
+ ],
448
+ selectionSet: selectionSet([
449
+ ...child.selections,
450
+ ...contextSelections(field.type, schema)
451
+ ])
452
+ };
453
+ });
454
+ return { ...set, selections };
455
+ }
456
+ function toVariantsDocument(document2, schema) {
457
+ const doc = documentOf(document2);
458
+ return {
459
+ ...doc,
460
+ definitions: doc.definitions.map((definition) => {
461
+ if (definition.kind === "OperationDefinition") {
462
+ return {
463
+ ...definition,
464
+ selectionSet: variantsSelectionSet(
465
+ definition.selectionSet,
466
+ schema.queryType,
467
+ schema
468
+ )
469
+ };
470
+ }
471
+ if (definition.kind === "FragmentDefinition") {
472
+ return {
473
+ ...definition,
474
+ selectionSet: variantsSelectionSet(
475
+ definition.selectionSet,
476
+ definition.typeCondition.name.value,
477
+ schema
478
+ )
479
+ };
480
+ }
481
+ return definition;
482
+ })
483
+ };
484
+ }
485
+
486
+ // src/core/graphql/transport.ts
487
+ import { VERCEL_STEGA_REGEX } from "@vercel/stega";
488
+
489
+ // src/core/stega/clean.ts
490
+ import { vercelStegaClean, vercelStegaDecode } from "@vercel/stega";
491
+
492
+ // src/core/utils.ts
493
+ var DebugLogger = class {
494
+ constructor(options) {
495
+ this.options = {
496
+ prefix: "[Prepr]",
497
+ ...options
498
+ };
499
+ }
500
+ // A local `enabled` wins; otherwise defer to the global logger so scoped
501
+ // loggers created before initDebugLogger() still pick up the setting.
502
+ isEnabled() {
503
+ if (this.options.enabled !== void 0) {
504
+ return this.options.enabled;
505
+ }
506
+ return globalDebugLogger?.options?.enabled ?? false;
507
+ }
508
+ log(message, ...args) {
509
+ if (!this.isEnabled()) return;
510
+ const prefix = this.options.prefix;
511
+ console.log(`${prefix} ${message}`, ...args);
512
+ }
513
+ warn(message, ...args) {
514
+ if (!this.isEnabled()) return;
515
+ const prefix = this.options.prefix;
516
+ console.warn(`${prefix} ${message}`, ...args);
517
+ }
518
+ error(message, ...args) {
519
+ if (!this.isEnabled()) return;
520
+ const prefix = this.options.prefix;
521
+ console.error(`${prefix} ${message}`, ...args);
522
+ }
523
+ };
524
+ var globalDebugLogger = null;
525
+ function createScopedLogger(scopeName) {
526
+ return new DebugLogger({
527
+ prefix: `[Prepr][${scopeName}]`
528
+ });
529
+ }
530
+
531
+ // src/core/stega/clean.ts
532
+ var debug = createScopedLogger("stega:clean");
533
+ function stegaClean(text) {
534
+ if (!text) return text;
535
+ return vercelStegaClean(text);
536
+ }
537
+
538
+ // src/core/graphql/document.ts
539
+ import { print } from "graphql/language/printer.js";
540
+ import { stripIgnoredCharacters } from "graphql/utilities/stripIgnoredCharacters.js";
541
+ var printed = /* @__PURE__ */ new WeakMap();
542
+ function isDocumentNode(value) {
543
+ return typeof value === "object" && value !== null && value.kind === "Document" && Array.isArray(value.definitions);
544
+ }
545
+ function invalidDocument(originalError) {
546
+ return new PreprError(
547
+ "Expected a GraphQL query string, TypedDocumentString or DocumentNode",
548
+ "INVALID_DOCUMENT",
549
+ "createPreprClient",
550
+ originalError
551
+ );
552
+ }
553
+ var minified = /* @__PURE__ */ new Map();
554
+ var MINIFIED_CACHE_LIMIT = 500;
555
+ function minify(query) {
556
+ const cached = minified.get(query);
557
+ if (cached !== void 0) return cached;
558
+ let result = query;
559
+ try {
560
+ result = stripIgnoredCharacters(query);
561
+ } catch {
562
+ }
563
+ if (minified.size < MINIFIED_CACHE_LIMIT) minified.set(query, result);
564
+ return result;
565
+ }
566
+ function resolveQuery(document2) {
567
+ if (typeof document2 === "string") return minify(document2);
568
+ if (document2 instanceof String) return minify(document2.toString());
569
+ if (!isDocumentNode(document2)) throw invalidDocument();
570
+ let query = printed.get(document2);
571
+ if (query === void 0) {
572
+ try {
573
+ query = minify(print(document2));
574
+ } catch (error) {
575
+ throw invalidDocument(error instanceof Error ? error : void 0);
576
+ }
577
+ printed.set(document2, query);
578
+ }
579
+ return query;
580
+ }
581
+
582
+ // src/core/graphql/transport.ts
583
+ var OPERATION_NAME = /\b(?:query|mutation|subscription)\s+([_A-Za-z][_0-9A-Za-z]*)/;
584
+ var STEGA_RAW = new RegExp(
585
+ VERCEL_STEGA_REGEX.source,
586
+ VERCEL_STEGA_REGEX.flags.replace("g", "")
587
+ );
588
+ var STEGA_ESCAPED = /\\u(?:200[bcd]|206[0-3]|feff|d834)/i;
589
+ var URL_KEY = /(url|slug|link|href)$/i;
590
+ var FASTLY_QUERY_MAX = 96 * 1024;
591
+ function base64(text) {
592
+ const bytes = new TextEncoder().encode(text);
593
+ let binary = "";
594
+ for (let i = 0; i < bytes.length; i += 32768) {
595
+ binary += String.fromCharCode(...bytes.subarray(i, i + 32768));
596
+ }
597
+ return btoa(binary);
598
+ }
599
+ function cacheInit(init, noStore) {
600
+ const result = { ...init };
601
+ if (noStore) {
602
+ result.cache = "no-store";
603
+ delete result.next;
604
+ }
605
+ return result;
606
+ }
607
+ function isFrameworkSignal(error) {
608
+ return typeof error === "object" && error !== null && typeof error.digest === "string";
609
+ }
610
+ function mergePreprHeaders(base, extra) {
611
+ const merged = new Headers(base);
612
+ new Headers(extra).forEach((value, key) => {
613
+ merged.set(key, value);
614
+ });
615
+ return merged;
616
+ }
617
+ function cleanEveryString(_key, value) {
618
+ return typeof value === "string" ? stegaClean(value) : value;
619
+ }
620
+ function cleanUrlStrings(key, value) {
621
+ return typeof value === "string" && URL_KEY.test(key) ? stegaClean(value) : value;
622
+ }
623
+ function parseBody(text, stega) {
624
+ if (stega === "none" || !(STEGA_RAW.test(text) || STEGA_ESCAPED.test(text))) {
625
+ return JSON.parse(text);
626
+ }
627
+ return JSON.parse(text, stega === "all" ? cleanEveryString : cleanUrlStrings);
628
+ }
629
+ function createTransport(options) {
630
+ const { url, preview = false } = options;
631
+ const stega = options.stega ?? (preview ? "urls" : "all");
632
+ const clientHeaders = new Headers(options.headers);
633
+ return async (document2, variables, queryOptions = {}) => {
634
+ const query = resolveQuery(document2);
635
+ const operation = OPERATION_NAME.exec(query)?.[1] ?? "anonymous";
636
+ const headers = new Headers(clientHeaders);
637
+ for (const layer of [queryOptions.init?.headers, queryOptions.headers]) {
638
+ new Headers(layer).forEach((value, key) => {
639
+ headers.set(key, value);
640
+ });
641
+ }
642
+ headers.set("Content-Type", "application/json");
643
+ const perRequestHeaders = queryOptions.headers !== void 0 || queryOptions.init?.headers !== void 0;
644
+ const payload = JSON.stringify({ query, variables });
645
+ const fastly = options.fastlyQuery ? base64(payload) : null;
646
+ const viaGet = fastly !== null && fastly.length <= FASTLY_QUERY_MAX;
647
+ if (viaGet) headers.set("Fastly-Query", fastly);
648
+ const init = {
649
+ ...cacheInit(queryOptions.init, preview || perRequestHeaders),
650
+ method: viaGet ? "GET" : "POST",
651
+ headers,
652
+ body: viaGet ? void 0 : payload
653
+ };
654
+ const fetchImpl = queryOptions.fetch ?? options.fetch;
655
+ let response;
656
+ try {
657
+ response = await (fetchImpl ? fetchImpl(url, init) : fetch(url, init));
658
+ } catch (error) {
659
+ if (isFrameworkSignal(error)) throw error;
660
+ throw new PreprError(
661
+ `Prepr GraphQL request failed for ${operation}`,
662
+ "FETCH_ERROR",
663
+ operation,
664
+ error instanceof Error ? error : void 0
665
+ );
666
+ }
667
+ if (!response.ok) {
668
+ throw new PreprError(
669
+ `Prepr GraphQL HTTP ${response.status} for ${operation}${response.status === 412 ? " (Prepr rejects queries longer than 27,500 characters)" : ""}`,
670
+ "HTTP_ERROR",
671
+ operation
672
+ );
673
+ }
674
+ let body;
675
+ try {
676
+ body = parseBody(await response.text(), stega);
677
+ } catch (error) {
678
+ throw new PreprError(
679
+ `Prepr GraphQL response for ${operation} is not valid JSON`,
680
+ "INVALID_RESPONSE",
681
+ operation,
682
+ error instanceof Error ? error : void 0
683
+ );
684
+ }
685
+ if (typeof body !== "object" || body === null) {
686
+ throw new PreprError(
687
+ `Prepr GraphQL response for ${operation} is not an object`,
688
+ "INVALID_RESPONSE",
689
+ operation
690
+ );
691
+ }
692
+ const { data, errors } = body;
693
+ if (Array.isArray(errors) && errors.length > 0) {
694
+ const messages = errors.map((e) => String(e?.message ?? "Unknown error")).join("; ");
695
+ throw new PreprError(
696
+ `Prepr GraphQL errors for ${operation}: ${messages}`,
697
+ "GRAPHQL_ERROR",
698
+ operation
699
+ );
700
+ }
701
+ if (data === null || data === void 0) {
702
+ throw new PreprError(
703
+ `Prepr GraphQL response for ${operation} has no data`,
704
+ "INVALID_RESPONSE",
705
+ operation
706
+ );
707
+ }
708
+ return { data, personalized: isPersonalizedResponse(response) };
709
+ };
710
+ }
711
+
712
+ // src/core/graphql/probe.ts
713
+ var AB_TEST_VARY = /\bPrepr-ABTesting/i;
714
+ var SEGMENTS_VARY = /\bPrepr-Segments/i;
715
+ var AB_CHECK_TTL_MS = 6e4;
716
+ var AB_CHECK_MAX_ENTRIES = 1e3;
717
+ function createVaryProbe(run, options) {
718
+ const abProbes = /* @__PURE__ */ new Map();
719
+ const abChecks = /* @__PURE__ */ new Map();
720
+ return (document2, variables) => {
721
+ const key = JSON.stringify(variables ?? null);
722
+ let answers = abChecks.get(document2);
723
+ if (!answers) {
724
+ answers = /* @__PURE__ */ new Map();
725
+ abChecks.set(document2, answers);
726
+ }
727
+ const cached = answers.get(key);
728
+ if (cached && Date.now() - cached.at < AB_CHECK_TTL_MS) return cached.value;
729
+ const value = (async () => {
730
+ let probe = abProbes.get(document2);
731
+ if (probe === void 0) {
732
+ probe = toAbProbeDocument(document2);
733
+ abProbes.set(document2, probe);
734
+ }
735
+ if (!probe) return "";
736
+ let vary = "";
737
+ const send = options.fetch ?? fetch;
738
+ await run(probe, variables, {
739
+ fetch: async (input, init) => {
740
+ const response = await send(input, init);
741
+ vary = response.headers.get("vary") ?? "";
742
+ return response;
743
+ }
744
+ });
745
+ return vary;
746
+ })().catch((error) => {
747
+ if (isFrameworkSignal(error)) throw error;
748
+ answers.delete(key);
749
+ return null;
750
+ });
751
+ if (answers.size >= AB_CHECK_MAX_ENTRIES) {
752
+ answers.delete(answers.keys().next().value);
753
+ }
754
+ answers.set(key, { value, at: Date.now() });
755
+ return value;
756
+ };
757
+ }
758
+
759
+ // src/core/graphql/client.ts
760
+ function isParseableUrl(url) {
761
+ try {
762
+ new URL(url);
763
+ return true;
764
+ } catch {
765
+ return false;
766
+ }
767
+ }
768
+ function createPreprClient(options) {
769
+ const { url } = options;
770
+ validatePreprToken(url);
771
+ if (!isParseableUrl(url)) {
772
+ throw new PreprError(
773
+ "Prepr GraphQL URL is not a valid URL",
774
+ "INVALID_TOKEN",
775
+ "createPreprClient"
776
+ );
777
+ }
778
+ const run = createTransport(options);
779
+ const probeVary = createVaryProbe(run, options);
780
+ let schema;
781
+ const loadSchema = () => schema ?? (schema = run(
782
+ PREPR_SCHEMA_QUERY,
783
+ void 0,
784
+ { init: options.schemaInit }
785
+ ).then(
786
+ (result) => toSchemaInfo(result.data),
787
+ (error) => {
788
+ schema = void 0;
789
+ throw error;
790
+ }
791
+ ));
792
+ const variantsDocuments = /* @__PURE__ */ new Map();
793
+ const decisionDocuments = /* @__PURE__ */ new Map();
794
+ return {
795
+ async query(document2, variables, queryOptions = {}) {
796
+ const { variants, ...rest } = queryOptions;
797
+ if (!variants) return run(document2, variables, rest);
798
+ let derived = variantsDocuments.get(document2);
799
+ if (!derived) {
800
+ derived = toVariantsDocument(document2, await loadSchema());
801
+ variantsDocuments.set(document2, derived);
802
+ }
803
+ return run(derived, variables, rest);
804
+ },
805
+ async decide(document2, variables, queryOptions = {}) {
806
+ const { from, topLevelOnly, ...rest } = queryOptions;
807
+ const paths = from === void 0 ? void 0 : personalizationPaths(from);
808
+ if (paths && paths.size === 0) return /* @__PURE__ */ new Map();
809
+ const signature = paths ? [...paths].map(([path, types]) => `${path}:${[...types].sort().join(",")}`).sort().join("|") : topLevelOnly ? "top" : "*";
810
+ let byPaths = decisionDocuments.get(document2);
811
+ if (!byPaths) {
812
+ byPaths = /* @__PURE__ */ new Map();
813
+ decisionDocuments.set(document2, byPaths);
814
+ }
815
+ let derived = byPaths.get(signature);
816
+ if (derived === void 0) {
817
+ derived = toDecisionDocument(document2, await loadSchema(), paths, {
818
+ topLevelOnly: !paths && topLevelOnly
819
+ });
820
+ byPaths.set(signature, derived);
821
+ }
822
+ if (!derived) return /* @__PURE__ */ new Map();
823
+ const { data } = await run(derived, variables, rest);
824
+ return decisionsFrom(data);
825
+ },
826
+ hasAbTests: (document2, variables) => probeVary(document2, variables).then(
827
+ (vary) => vary === null || AB_TEST_VARY.test(vary)
828
+ ),
829
+ hasSegments: (document2, variables) => probeVary(document2, variables).then(
830
+ (vary) => vary === null || SEGMENTS_VARY.test(vary)
831
+ )
832
+ };
833
+ }
834
+
835
+ // src/nextjs/decisions.ts
836
+ var PREPR_DECISIONS_COOKIE = "prepr_decisions";
837
+ var DECISIONS_MAX_GROUPS = 40;
838
+ var SAFE_ID = /^[\w-]+$/;
839
+ var SEEN_MAX_PAGES = 1e3;
840
+ function parseDecisions(raw) {
841
+ const out = /* @__PURE__ */ new Map();
842
+ for (const pair of (raw ?? "").split("~")) {
843
+ const at = pair.indexOf(":");
844
+ const group = pair.slice(0, at);
845
+ if (at < 1 || !SAFE_ID.test(group)) continue;
846
+ out.set(
847
+ group,
848
+ pair.slice(at + 1).split("|").filter((variant) => SAFE_ID.test(variant))
849
+ );
850
+ }
851
+ return out;
852
+ }
853
+ function serializeDecisions(decisions) {
854
+ return [...decisions].slice(0, DECISIONS_MAX_GROUPS).map(([group, variants]) => `${group}:${variants.join("|")}`).join("~");
855
+ }
856
+ function forwardedHeaders(request, response) {
857
+ const overridden = response.headers.get("x-middleware-override-headers");
858
+ if (!overridden) return getPreprHeadersFromHeaders(request.headers);
859
+ const headers = new Headers();
860
+ for (const name2 of overridden.split(",")) {
861
+ const value = response.headers.get(`x-middleware-request-${name2.trim()}`);
862
+ if (value !== null) headers.set(name2.trim(), value);
863
+ }
864
+ return getPreprHeadersFromHeaders(headers);
865
+ }
866
+ async function resolveDecisionsWith(client, seenGroups, request, response, document2, variables, options) {
867
+ try {
868
+ if (options?.onlyIf && !await options.onlyIf()) return;
869
+ if (!await client.hasSegments(document2, variables)) return;
870
+ const headers = mergePreprHeaders(forwardedHeaders(request, response));
871
+ const stored = parseDecisions(
872
+ request.cookies.get(PREPR_DECISIONS_COOKIE)?.value
873
+ );
874
+ const pageKey = `${JSON.stringify(variables ?? null)}`;
875
+ let byVariables = seenGroups.get(document2);
876
+ if (!byVariables) {
877
+ byVariables = /* @__PURE__ */ new Map();
878
+ seenGroups.set(document2, byVariables);
879
+ }
880
+ const known = byVariables.get(pageKey);
881
+ const isNewVisitor = headers.get("Prepr-Customer-Id-Created") === "true";
882
+ const contextChanged = isNewVisitor || headers.has("Prepr-Segments") || [...request.nextUrl.searchParams.keys()].some(
883
+ (key) => key.startsWith("utm_")
884
+ );
885
+ if (options?.reuse !== false && !contextChanged && known && [...known].every((group) => stored.has(group))) {
886
+ return;
887
+ }
888
+ const decided = await client.decide(document2, variables, {
889
+ topLevelOnly: true,
890
+ headers,
891
+ init: { signal: AbortSignal.timeout(options?.timeoutMs ?? 1e3) }
892
+ });
893
+ if (!known && byVariables.size >= SEEN_MAX_PAGES) {
894
+ byVariables.delete(byVariables.keys().next().value);
895
+ }
896
+ const groups = known ?? /* @__PURE__ */ new Set();
897
+ for (const group of decided.keys()) groups.add(group);
898
+ byVariables.set(pageKey, groups);
899
+ const next = /* @__PURE__ */ new Map();
900
+ for (const [group, variants] of decided) {
901
+ if (SAFE_ID.test(group)) {
902
+ next.set(
903
+ group,
904
+ variants.filter((v) => SAFE_ID.test(v))
905
+ );
906
+ }
907
+ }
908
+ for (const [group, variants] of stored) {
909
+ if (!next.has(group)) next.set(group, variants);
910
+ }
911
+ if (next.size === 0) return;
912
+ response.cookies.set(PREPR_DECISIONS_COOKIE, serializeDecisions(next), {
913
+ path: "/",
914
+ sameSite: "lax",
915
+ // Read by the inline switch script before first paint.
916
+ httpOnly: false
917
+ });
918
+ } catch (error) {
919
+ if (isFrameworkSignal(error)) throw error;
920
+ }
921
+ }
922
+
923
+ // src/nextjs/stack.ts
924
+ import {
925
+ createElement,
926
+ Fragment,
927
+ Suspense
928
+ } from "react";
929
+
930
+ // src/nextjs/ab-switch.ts
931
+ function applyPreprAbBucket() {
932
+ const match = document.cookie.match(/(?:^|; )prepr_ab_bucket=([AB])(?:;|$)/);
933
+ const bucket = match ? match[1] : "A";
934
+ const state = window;
935
+ if (state.__preprAbBucket === bucket) return;
936
+ state.__preprAbBucket = bucket;
937
+ const css = bucket === "A" ? "" : '[data-prepr-ab="A"]{display:none!important}[data-prepr-ab="' + bucket + '"]{display:contents!important}';
938
+ try {
939
+ if (!state.__preprAbSheet) {
940
+ const sheet = new CSSStyleSheet();
941
+ document.adoptedStyleSheets = document.adoptedStyleSheets.concat(sheet);
942
+ state.__preprAbSheet = sheet;
943
+ }
944
+ state.__preprAbSheet.replaceSync(css);
945
+ } catch {
946
+ if (!state.__preprAbSheet) {
947
+ state.__preprAbSheet = document.createElement("style");
948
+ document.head.appendChild(state.__preprAbSheet);
949
+ }
950
+ state.__preprAbSheet.textContent = css;
951
+ }
952
+ }
953
+ function applyPreprDecisions() {
954
+ const match = document.cookie.match(/(?:^|; )prepr_decisions=([^;]*)/);
955
+ let raw;
956
+ try {
957
+ raw = match ? decodeURIComponent(match[1]) : "";
958
+ } catch {
959
+ raw = "";
960
+ }
961
+ const state = window;
962
+ if (state.__preprDecisions === raw) return;
963
+ state.__preprDecisions = raw;
964
+ const id = /^[\w-]+$/;
965
+ let css = "";
966
+ raw.split("~").forEach((pair) => {
967
+ const at = pair.indexOf(":");
968
+ const group = pair.slice(0, at);
969
+ if (at < 1 || !id.test(group)) return;
970
+ const selector = '[data-prepr-group="' + group + '"]';
971
+ css += selector + "{display:none!important}";
972
+ pair.slice(at + 1).split("|").forEach((variant) => {
973
+ if (id.test(variant)) {
974
+ css += selector + '[data-prepr-variant="' + variant + '"]{display:contents!important}';
975
+ }
976
+ });
977
+ });
978
+ try {
979
+ if (!state.__preprDecisionSheet) {
980
+ const sheet = new CSSStyleSheet();
981
+ document.adoptedStyleSheets = document.adoptedStyleSheets.concat(sheet);
982
+ state.__preprDecisionSheet = sheet;
983
+ }
984
+ state.__preprDecisionSheet.replaceSync(css);
985
+ } catch {
986
+ if (!state.__preprDecisionSheet) {
987
+ state.__preprDecisionSheet = document.createElement("style");
988
+ document.head.appendChild(state.__preprDecisionSheet);
989
+ }
990
+ state.__preprDecisionSheet.textContent = css;
991
+ }
992
+ }
993
+
994
+ // src/nextjs/stack.ts
995
+ import { PreprAbSwitch, PreprVariantTracking } from "./components.js";
996
+ var AB_ATTRIBUTE = "data-prepr-ab";
997
+ var AB_BUCKETS = ["A", "B"];
998
+ var AB_BASE_CSS = `[${AB_ATTRIBUTE}]{display:contents}[${AB_ATTRIBUTE}]:not([${AB_ATTRIBUTE}="A"]){display:none}`;
999
+ var AB_SWITCH_SCRIPT = `(${applyPreprAbBucket.toString()})();(${applyPreprDecisions.toString()})()`;
1000
+ var GROUP_ATTRIBUTE = "data-prepr-group";
1001
+ var VARIANT_ATTRIBUTE = "data-prepr-variant";
1002
+ var DEFAULT_ATTRIBUTE = "data-prepr-default";
1003
+ var GROUP_BASE_CSS = `[${GROUP_ATTRIBUTE}]{display:contents}[${GROUP_ATTRIBUTE}]:not([${DEFAULT_ATTRIBUTE}]){display:none}`;
1004
+ function variantKeysOf(items) {
1005
+ return items.flatMap((item) => {
1006
+ const key = preprVariantProps(item)["data-prepr-variant-key"];
1007
+ return key ? [key] : [];
1008
+ });
1009
+ }
1010
+ function renderBuckets(items, render, options) {
1011
+ const {
1012
+ bucket,
1013
+ decisions,
1014
+ abTest,
1015
+ index,
1016
+ track,
1017
+ placeholder = false
1018
+ } = options;
1019
+ const renderVariant = (variant, key) => {
1020
+ const resolved = resolveVariants(items, { decisions, bucket: variant });
1021
+ const content = render(resolved, { index, placeholder });
1022
+ const variantKeys = track ? variantKeysOf(resolved) : [];
1023
+ const ab = abTest && !bucket ? variant : void 0;
1024
+ if (variantKeys.length > 0) {
1025
+ return createElement(
1026
+ PreprVariantTracking,
1027
+ { key, variantKeys, ab },
1028
+ content
1029
+ );
1030
+ }
1031
+ if (ab) return createElement("div", { key, [AB_ATTRIBUTE]: ab }, content);
1032
+ return content;
1033
+ };
1034
+ if (!abTest || bucket) return renderVariant(bucket);
1035
+ return AB_BUCKETS.map((variant) => renderVariant(variant, variant));
1036
+ }
1037
+ function renderAllVariants(block, render, options) {
1038
+ const group = block.key.slice("group:".length);
1039
+ const variants = [
1040
+ ...new Set(
1041
+ block.items.flatMap((item) => {
1042
+ const ctx = item[PREPR_CONTEXT_ALIAS];
1043
+ return ctx?.variant_id ? [ctx.variant_id] : [];
1044
+ })
1045
+ )
1046
+ ];
1047
+ return variants.map(
1048
+ (variant) => createElement(
1049
+ "div",
1050
+ {
1051
+ key: variant,
1052
+ [GROUP_ATTRIBUTE]: group,
1053
+ [VARIANT_ATTRIBUTE]: variant,
1054
+ ...variant === PREPR_DEFAULT_VARIANT ? { [DEFAULT_ATTRIBUTE]: "" } : {}
1055
+ },
1056
+ renderBuckets(block.items, render, {
1057
+ bucket: options.bucket,
1058
+ decisions: /* @__PURE__ */ new Map([[group, [variant]]]),
1059
+ abTest: false,
1060
+ index: block.index,
1061
+ track: options.track
1062
+ })
1063
+ )
1064
+ );
1065
+ }
1066
+ async function PersonalizedBlock({
1067
+ items,
1068
+ decisions,
1069
+ bucket,
1070
+ abTest,
1071
+ index,
1072
+ render,
1073
+ track
1074
+ }) {
1075
+ const decided = await decisions.catch((error) => {
1076
+ if (isFrameworkSignal(error)) throw error;
1077
+ return void 0;
1078
+ });
1079
+ return renderBuckets(items, render, {
1080
+ bucket,
1081
+ decisions: decided,
1082
+ abTest,
1083
+ index,
1084
+ track
1085
+ });
1086
+ }
1087
+ function PreprStack({
1088
+ items,
1089
+ decisions,
1090
+ render,
1091
+ bucket,
1092
+ nonce,
1093
+ trackVariants = false,
1094
+ aboveTheFold = 0
1095
+ }) {
1096
+ decisions.catch(() => void 0);
1097
+ const blocks = splitStack(items);
1098
+ const decidedInProxy = (block) => block.index < aboveTheFold && block.personalized && !block.abTest && block.key.startsWith("group:");
1099
+ const hasDecided = blocks.some(decidedInProxy);
1100
+ const needsSwitch = !bucket && blocks.some((block) => block.abTest) || hasDecided;
1101
+ return createElement(
1102
+ Fragment,
1103
+ null,
1104
+ needsSwitch && createElement(
1105
+ Fragment,
1106
+ { key: "prepr-ab" },
1107
+ createElement("style", {
1108
+ nonce,
1109
+ dangerouslySetInnerHTML: {
1110
+ __html: AB_BASE_CSS + (hasDecided ? GROUP_BASE_CSS : "")
1111
+ }
1112
+ }),
1113
+ createElement("script", {
1114
+ nonce,
1115
+ dangerouslySetInnerHTML: { __html: AB_SWITCH_SCRIPT }
1116
+ }),
1117
+ createElement(PreprAbSwitch)
1118
+ ),
1119
+ ...blocks.map((block) => {
1120
+ if (decidedInProxy(block)) {
1121
+ return createElement(
1122
+ Fragment,
1123
+ { key: block.key },
1124
+ renderAllVariants(block, render, { bucket, track: trackVariants })
1125
+ );
1126
+ }
1127
+ const fallback = renderBuckets(block.items, render, {
1128
+ bucket,
1129
+ abTest: block.abTest,
1130
+ index: block.index,
1131
+ track: trackVariants && !block.personalized,
1132
+ placeholder: block.personalized
1133
+ });
1134
+ if (!block.personalized) {
1135
+ return createElement(Fragment, { key: block.key }, fallback);
1136
+ }
1137
+ return createElement(
1138
+ Suspense,
1139
+ { key: block.key, fallback },
1140
+ createElement(PersonalizedBlock, {
1141
+ items: block.items,
1142
+ decisions,
1143
+ bucket,
1144
+ abTest: block.abTest,
1145
+ index: block.index,
1146
+ render,
1147
+ track: trackVariants
1148
+ })
1149
+ );
1150
+ })
1151
+ );
1152
+ }
1153
+
1154
+ // src/nextjs/graphql.ts
1155
+ function createPreprClient2(options) {
1156
+ const { cacheTags = ["prepr"], revalidate, ...coreOptions } = options;
1157
+ const client = createPreprClient({
1158
+ // The schema introspection goes through the Data Cache: shared across
1159
+ // server instances, refreshed hourly and by revalidateTag on publish.
1160
+ schemaInit: {
1161
+ next: { tags: cacheTags, revalidate: 3600 }
1162
+ },
1163
+ ...coreOptions
1164
+ });
1165
+ const seenGroups = /* @__PURE__ */ new Map();
1166
+ return {
1167
+ async query(document2, variables, queryOptions = {}) {
1168
+ const { personalize = false, ...rest } = queryOptions;
1169
+ const init = rest.init;
1170
+ const tagged = {
1171
+ ...rest,
1172
+ init: {
1173
+ ...init,
1174
+ next: {
1175
+ tags: cacheTags,
1176
+ ...revalidate === void 0 ? {} : { revalidate },
1177
+ ...init?.next
1178
+ }
1179
+ }
1180
+ };
1181
+ if (!personalize) return client.query(document2, variables, tagged);
1182
+ return client.query(document2, variables, {
1183
+ ...tagged,
1184
+ headers: mergePreprHeaders(await getPreprHeaders(), rest.headers)
1185
+ });
1186
+ },
1187
+ async decide(document2, variables, queryOptions = {}) {
1188
+ return client.decide(document2, variables, {
1189
+ ...queryOptions,
1190
+ headers: mergePreprHeaders(
1191
+ await getPreprHeaders(),
1192
+ queryOptions.headers
1193
+ )
1194
+ });
1195
+ },
1196
+ hasAbTests: (document2, variables) => client.hasAbTests(document2, variables),
1197
+ resolveDecisions: (request, response, document2, variables, options2) => resolveDecisionsWith(
1198
+ client,
1199
+ seenGroups,
1200
+ request,
1201
+ response,
1202
+ document2,
1203
+ variables,
1204
+ options2
1205
+ )
1206
+ };
1207
+ }
1208
+ export {
1209
+ PREPR_DECISIONS_COOKIE,
1210
+ PREPR_DEFAULT_VARIANT,
1211
+ PreprError,
1212
+ PreprStack,
1213
+ createPreprClient2 as createPreprClient,
1214
+ isPersonalizedResponse,
1215
+ preprVariantProps,
1216
+ resolveVariants,
1217
+ splitStack
1218
+ };