@preprio/toolkit 0.6.0-alpha.6 → 0.6.0-alpha.8

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 (52) hide show
  1. package/README.md +138 -52
  2. package/dist/astro/{chunk-MWRA3732.js → chunk-R2YPGDVU.js} +1 -1
  3. package/dist/astro/graphql.cjs +58 -10
  4. package/dist/astro/graphql.d.cts +33 -38
  5. package/dist/astro/graphql.d.ts +33 -38
  6. package/dist/astro/graphql.js +59 -11
  7. package/dist/astro/index.cjs +1 -1
  8. package/dist/astro/index.js +1 -1
  9. package/dist/{chunk-Y7DWVOOY.js → chunk-2QGUP7VQ.js} +1 -1
  10. package/dist/{chunk-NSQOGI5K.js → chunk-ATPB7GEC.js} +1 -1
  11. package/dist/{chunk-W6AVX6FI.js → chunk-OY7OKO6Q.js} +52 -5
  12. package/dist/{chunk-OQGEL4TV.js → chunk-T7ESBVBI.js} +1 -1
  13. package/dist/graphql/codegen.cjs +51 -4
  14. package/dist/graphql/codegen.js +3 -3
  15. package/dist/graphql.cjs +89 -10
  16. package/dist/graphql.d.cts +69 -39
  17. package/dist/graphql.d.ts +69 -39
  18. package/dist/graphql.js +38 -9
  19. package/dist/index.cjs +1 -1
  20. package/dist/index.d.cts +1 -1
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.js +3 -3
  23. package/dist/nextjs/{chunk-PIQF5ZI5.js → chunk-O2SBSBDG.js} +58 -53
  24. package/dist/nextjs/components.cjs +205 -236
  25. package/dist/nextjs/components.d.cts +27 -22
  26. package/dist/nextjs/components.d.ts +27 -22
  27. package/dist/nextjs/components.js +198 -231
  28. package/dist/nextjs/graphql.cjs +418 -508
  29. package/dist/nextjs/graphql.d.cts +131 -135
  30. package/dist/nextjs/graphql.d.ts +131 -135
  31. package/dist/nextjs/graphql.js +353 -455
  32. package/dist/nextjs/index.cjs +114 -54
  33. package/dist/nextjs/index.d.cts +59 -33
  34. package/dist/nextjs/index.d.ts +59 -33
  35. package/dist/nextjs/index.js +108 -5
  36. package/dist/nuxt/{chunk-PF6GVWHV.js → chunk-SX3MSVPK.js} +1 -1
  37. package/dist/nuxt/graphql.cjs +58 -10
  38. package/dist/nuxt/graphql.d.cts +33 -38
  39. package/dist/nuxt/graphql.d.ts +33 -38
  40. package/dist/nuxt/graphql.js +59 -11
  41. package/dist/nuxt/index.cjs +1 -1
  42. package/dist/nuxt/index.js +1 -1
  43. package/dist/react/components.cjs +1 -1
  44. package/dist/react/components.js +1 -1
  45. package/dist/sveltekit/{chunk-5K7HWMIF.js → chunk-UOASSHZO.js} +1 -1
  46. package/dist/sveltekit/graphql.cjs +58 -10
  47. package/dist/sveltekit/graphql.d.cts +33 -38
  48. package/dist/sveltekit/graphql.d.ts +33 -38
  49. package/dist/sveltekit/graphql.js +59 -11
  50. package/dist/sveltekit/index.cjs +1 -1
  51. package/dist/sveltekit/index.js +1 -1
  52. package/package.json +1 -1
@@ -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
- selection.typeCondition?.name.value ?? typeName,
197
+ condition,
194
198
  path,
195
199
  ctx
196
200
  );
197
- if (pruned) selections.push({ ...selection, selectionSet: 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
- return {
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, topLevelOnly, ...rest } = queryOptions;
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("|") : topLevelOnly ? "top" : "*";
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
@@ -95,39 +95,6 @@ interface PreprVariantProps {
95
95
  */
96
96
  declare function preprVariantProps(item: unknown): PreprVariantProps;
97
97
 
98
- /**
99
- * The schema facts the query rewrites need, from `loadPreprSchema`. Pass it
100
- * along; its shape is not part of the public API.
101
- */
102
- type PreprSchema = PreprSchemaInfo;
103
- /**
104
- * Your query, asking for every personalization and A/B variant: what
105
- * `query(..., { variants: true })` sends, as a string for your own GraphQL
106
- * client. The result is the same for every visitor, so cache it like any
107
- * other content query, and render it with `resolveVariants` or `PreprStack`.
108
- *
109
- * A query without personalizable fields comes back unchanged (minified).
110
- */
111
- declare function toVariantsQuery(document: PreprDocument<unknown, unknown> | string, schema: PreprSchema): string;
112
- /**
113
- * The per-visitor decision query for the same query: send it with the
114
- * visitor's Prepr headers, never cached, and pass the response's `data` to
115
- * `decisionsFrom`.
116
- *
117
- * Pass the variants result as `from` whenever you have it: the query then
118
- * asks only about the lists that hold segment groups on this page, which is
119
- * a few hundred bytes instead of the whole page and markedly faster for a
120
- * visitor Prepr has not seen before. Without `from` it asks about every
121
- * personalizable list. `topLevelOnly` stops at the first personalizable list
122
- * on each path, for middleware that decides only the top of a stack.
123
- *
124
- * Null when there is nothing to decide: send no request then.
125
- */
126
- declare function toDecisionQuery(document: PreprDocument<unknown, unknown> | string, schema: PreprSchema, options?: {
127
- from?: unknown;
128
- topLevelOnly?: boolean;
129
- }): string | null;
130
-
131
98
  /**
132
99
  * A GraphQL document accepted by `query`: a plain string, graphql-codegen's
133
100
  * `TypedDocumentString` (`documentMode: 'string'`), or any `DocumentNode`,
@@ -221,11 +188,6 @@ interface PreprDecideOptions extends Omit<PreprQueryOptions, 'variants'> {
221
188
  * none, e.g. on pages with only A/B tests or no personalization.
222
189
  */
223
190
  from?: unknown;
224
- /**
225
- * @internal Ask only about the first personalizable list on each path,
226
- * without `from`: what middleware needs for groups at the top of a stack.
227
- */
228
- topLevelOnly?: boolean;
229
191
  }
230
192
  interface PreprQueryResult<TResult> {
231
193
  data: TResult;
@@ -236,6 +198,39 @@ interface PreprQueryResult<TResult> {
236
198
  personalized: boolean;
237
199
  }
238
200
 
201
+ /**
202
+ * The schema facts the query rewrites need, from `loadPreprSchema`. Pass it
203
+ * along; its shape is not part of the public API.
204
+ */
205
+ type PreprSchema = PreprSchemaInfo;
206
+ /**
207
+ * Your query, asking for every personalization and A/B variant: what
208
+ * `query(..., { variants: true })` sends, as a string for your own GraphQL
209
+ * client. The result is the same for every visitor, so cache it like any
210
+ * other content query, and render it with `resolveVariants` or `PreprStack`.
211
+ *
212
+ * A query without personalizable fields comes back unchanged (minified).
213
+ */
214
+ declare function toVariantsQuery(document: PreprDocument<unknown, unknown> | string, schema: PreprSchema): string;
215
+ /**
216
+ * The per-visitor decision query for the same query: send it with the
217
+ * visitor's Prepr headers, never cached, and pass the response's `data` to
218
+ * `decisionsFrom`.
219
+ *
220
+ * Pass the variants result as `from` whenever you have it: the query then
221
+ * asks only about the lists that hold segment groups on this page, which is
222
+ * a few hundred bytes instead of the whole page and markedly faster for a
223
+ * visitor Prepr has not seen before. Without `from` it asks about every
224
+ * personalizable list. `topLevelOnly` stops at the first personalizable list
225
+ * on each path, for middleware that decides only the top of a stack.
226
+ *
227
+ * Null when there is nothing to decide: send no request then.
228
+ */
229
+ declare function toDecisionQuery(document: PreprDocument<unknown, unknown> | string, schema: PreprSchema, options?: {
230
+ from?: unknown;
231
+ topLevelOnly?: boolean;
232
+ }): string | null;
233
+
239
234
  /**
240
235
  * Query options for frameworks without an implicit request scope.
241
236
  * `personalize: true` requires the request `event`; the compiler enforces it.
@@ -95,39 +95,6 @@ interface PreprVariantProps {
95
95
  */
96
96
  declare function preprVariantProps(item: unknown): PreprVariantProps;
97
97
 
98
- /**
99
- * The schema facts the query rewrites need, from `loadPreprSchema`. Pass it
100
- * along; its shape is not part of the public API.
101
- */
102
- type PreprSchema = PreprSchemaInfo;
103
- /**
104
- * Your query, asking for every personalization and A/B variant: what
105
- * `query(..., { variants: true })` sends, as a string for your own GraphQL
106
- * client. The result is the same for every visitor, so cache it like any
107
- * other content query, and render it with `resolveVariants` or `PreprStack`.
108
- *
109
- * A query without personalizable fields comes back unchanged (minified).
110
- */
111
- declare function toVariantsQuery(document: PreprDocument<unknown, unknown> | string, schema: PreprSchema): string;
112
- /**
113
- * The per-visitor decision query for the same query: send it with the
114
- * visitor's Prepr headers, never cached, and pass the response's `data` to
115
- * `decisionsFrom`.
116
- *
117
- * Pass the variants result as `from` whenever you have it: the query then
118
- * asks only about the lists that hold segment groups on this page, which is
119
- * a few hundred bytes instead of the whole page and markedly faster for a
120
- * visitor Prepr has not seen before. Without `from` it asks about every
121
- * personalizable list. `topLevelOnly` stops at the first personalizable list
122
- * on each path, for middleware that decides only the top of a stack.
123
- *
124
- * Null when there is nothing to decide: send no request then.
125
- */
126
- declare function toDecisionQuery(document: PreprDocument<unknown, unknown> | string, schema: PreprSchema, options?: {
127
- from?: unknown;
128
- topLevelOnly?: boolean;
129
- }): string | null;
130
-
131
98
  /**
132
99
  * A GraphQL document accepted by `query`: a plain string, graphql-codegen's
133
100
  * `TypedDocumentString` (`documentMode: 'string'`), or any `DocumentNode`,
@@ -221,11 +188,6 @@ interface PreprDecideOptions extends Omit<PreprQueryOptions, 'variants'> {
221
188
  * none, e.g. on pages with only A/B tests or no personalization.
222
189
  */
223
190
  from?: unknown;
224
- /**
225
- * @internal Ask only about the first personalizable list on each path,
226
- * without `from`: what middleware needs for groups at the top of a stack.
227
- */
228
- topLevelOnly?: boolean;
229
191
  }
230
192
  interface PreprQueryResult<TResult> {
231
193
  data: TResult;
@@ -236,6 +198,39 @@ interface PreprQueryResult<TResult> {
236
198
  personalized: boolean;
237
199
  }
238
200
 
201
+ /**
202
+ * The schema facts the query rewrites need, from `loadPreprSchema`. Pass it
203
+ * along; its shape is not part of the public API.
204
+ */
205
+ type PreprSchema = PreprSchemaInfo;
206
+ /**
207
+ * Your query, asking for every personalization and A/B variant: what
208
+ * `query(..., { variants: true })` sends, as a string for your own GraphQL
209
+ * client. The result is the same for every visitor, so cache it like any
210
+ * other content query, and render it with `resolveVariants` or `PreprStack`.
211
+ *
212
+ * A query without personalizable fields comes back unchanged (minified).
213
+ */
214
+ declare function toVariantsQuery(document: PreprDocument<unknown, unknown> | string, schema: PreprSchema): string;
215
+ /**
216
+ * The per-visitor decision query for the same query: send it with the
217
+ * visitor's Prepr headers, never cached, and pass the response's `data` to
218
+ * `decisionsFrom`.
219
+ *
220
+ * Pass the variants result as `from` whenever you have it: the query then
221
+ * asks only about the lists that hold segment groups on this page, which is
222
+ * a few hundred bytes instead of the whole page and markedly faster for a
223
+ * visitor Prepr has not seen before. Without `from` it asks about every
224
+ * personalizable list. `topLevelOnly` stops at the first personalizable list
225
+ * on each path, for middleware that decides only the top of a stack.
226
+ *
227
+ * Null when there is nothing to decide: send no request then.
228
+ */
229
+ declare function toDecisionQuery(document: PreprDocument<unknown, unknown> | string, schema: PreprSchema, options?: {
230
+ from?: unknown;
231
+ topLevelOnly?: boolean;
232
+ }): string | null;
233
+
239
234
  /**
240
235
  * Query options for frameworks without an implicit request scope.
241
236
  * `personalize: true` requires the request `event`; the compiler enforces it.
@@ -4,7 +4,7 @@ import {
4
4
  getPreprHeadersFromHeaders,
5
5
  isPersonalizedResponse,
6
6
  validatePreprToken
7
- } from "./chunk-PF6GVWHV.js";
7
+ } from "./chunk-SX3MSVPK.js";
8
8
 
9
9
  // src/core/variants/constants.ts
10
10
  var PREPR_CONTEXT_ALIAS = "_preprContext";
@@ -93,7 +93,10 @@ function decisionSelectionSet(set, typeName, path, ctx) {
93
93
  path,
94
94
  ctx
95
95
  );
96
- if (pruned) {
96
+ if (!pruned) continue;
97
+ if (fragment.typeCondition.name.value === typeName) {
98
+ selections.push(...pruned.selections);
99
+ } else {
97
100
  selections.push(
98
101
  inlineFragment(fragment.typeCondition.name.value, [
99
102
  ...pruned.selections
@@ -103,13 +106,19 @@ function decisionSelectionSet(set, typeName, path, ctx) {
103
106
  continue;
104
107
  }
105
108
  if (selection.kind === "InlineFragment") {
109
+ const condition = selection.typeCondition?.name.value ?? typeName;
106
110
  const pruned = decisionSelectionSet(
107
111
  selection.selectionSet,
108
- selection.typeCondition?.name.value ?? typeName,
112
+ condition,
109
113
  path,
110
114
  ctx
111
115
  );
112
- if (pruned) selections.push({ ...selection, selectionSet: pruned });
116
+ if (!pruned) continue;
117
+ if (condition === typeName && !selection.directives?.length) {
118
+ selections.push(...pruned.selections);
119
+ } else {
120
+ selections.push({ ...selection, selectionSet: pruned });
121
+ }
113
122
  continue;
114
123
  }
115
124
  if (!selection.selectionSet) continue;
@@ -183,20 +192,58 @@ function toDecisionDocument(document2, schema, groupPaths, options) {
183
192
  const used = /* @__PURE__ */ new Set();
184
193
  collectVariables(pruned, used);
185
194
  collectVariables(operation.directives, used);
195
+ const shared = sharedContextFragment(schema);
186
196
  return {
187
197
  kind: "Document",
188
198
  definitions: [
199
+ ...shared ? [shared.definition] : [],
189
200
  {
190
201
  ...operation,
191
202
  name: operation.name && name(`${operation.name.value}Decision`),
192
203
  variableDefinitions: (operation.variableDefinitions ?? []).filter(
193
204
  (definition) => used.has(definition.variable.name.value)
194
205
  ),
195
- selectionSet: pruned
206
+ selectionSet: shared ? shared.apply(pruned) : pruned
196
207
  }
197
208
  ]
198
209
  };
199
210
  }
211
+ function sharedContextFragment(schema) {
212
+ const contextTypes = new Set(
213
+ Object.values(schema.types).flatMap(
214
+ (type) => type.hasContext ? [type.fields._context.type] : []
215
+ )
216
+ );
217
+ if (contextTypes.size !== 1) return null;
218
+ const [contextType] = contextTypes;
219
+ const fragmentName = "c";
220
+ const definition = {
221
+ kind: "FragmentDefinition",
222
+ name: name(fragmentName),
223
+ typeCondition: { kind: "NamedType", name: name(contextType) },
224
+ selectionSet: selectionSet(
225
+ ["kind", "group_id", "variant_id"].map(
226
+ (field) => ({ kind: "Field", name: name(field) })
227
+ )
228
+ )
229
+ };
230
+ const spread = {
231
+ kind: "FragmentSpread",
232
+ name: name(fragmentName)
233
+ };
234
+ const apply = (set) => selectionSet(
235
+ set.selections.map((selection) => {
236
+ if (selection.kind === "Field" && selection.alias?.value === PREPR_CONTEXT_ALIAS) {
237
+ return { ...selection, selectionSet: selectionSet([spread]) };
238
+ }
239
+ return "selectionSet" in selection && selection.selectionSet ? {
240
+ ...selection,
241
+ selectionSet: apply(selection.selectionSet)
242
+ } : selection;
243
+ })
244
+ );
245
+ return { definition, apply };
246
+ }
200
247
 
201
248
  // src/core/variants/probe-document.ts
202
249
  function probeSelectionSet(set, fragments) {
@@ -770,6 +817,7 @@ function createVaryProbe(run, options) {
770
817
  }
771
818
 
772
819
  // src/core/graphql/client.ts
820
+ var clientSchemas = /* @__PURE__ */ new WeakMap();
773
821
  function isParseableUrl(url) {
774
822
  try {
775
823
  new URL(url);
@@ -806,7 +854,7 @@ function createPreprClient(options) {
806
854
  ));
807
855
  const variantsDocuments = /* @__PURE__ */ new Map();
808
856
  const decisionDocuments = /* @__PURE__ */ new Map();
809
- return {
857
+ const client = {
810
858
  async query(document2, variables, queryOptions = {}) {
811
859
  const { variants, ...rest } = queryOptions;
812
860
  if (!variants) return run(document2, variables, rest);
@@ -818,10 +866,10 @@ function createPreprClient(options) {
818
866
  return run(derived, variables, rest);
819
867
  },
820
868
  async decide(document2, variables, queryOptions = {}) {
821
- const { from, topLevelOnly, ...rest } = queryOptions;
869
+ const { from, ...rest } = queryOptions;
822
870
  const paths = from === void 0 ? void 0 : personalizationPaths(from);
823
871
  if (paths && paths.size === 0) return /* @__PURE__ */ new Map();
824
- const signature = paths ? [...paths].map(([path, types]) => `${path}:${[...types].sort().join(",")}`).sort().join("|") : topLevelOnly ? "top" : "*";
872
+ const signature = paths ? [...paths].map(([path, types]) => `${path}:${[...types].sort().join(",")}`).sort().join("|") : "*";
825
873
  let byPaths = decisionDocuments.get(document2);
826
874
  if (!byPaths) {
827
875
  byPaths = /* @__PURE__ */ new Map();
@@ -829,9 +877,7 @@ function createPreprClient(options) {
829
877
  }
830
878
  let derived = byPaths.get(signature);
831
879
  if (derived === void 0) {
832
- derived = toDecisionDocument(document2, await loadSchema(), paths, {
833
- topLevelOnly: !paths && topLevelOnly
834
- });
880
+ derived = toDecisionDocument(document2, await loadSchema(), paths);
835
881
  byPaths.set(signature, derived);
836
882
  }
837
883
  if (!derived) return /* @__PURE__ */ new Map();
@@ -845,6 +891,8 @@ function createPreprClient(options) {
845
891
  (vary) => vary === null || SEGMENTS_VARY.test(vary)
846
892
  )
847
893
  };
894
+ clientSchemas.set(client, loadSchema);
895
+ return client;
848
896
  }
849
897
 
850
898
  // src/core/graphql/event-client.ts
@@ -36,7 +36,7 @@ __export(nuxt_exports, {
36
36
  module.exports = __toCommonJS(nuxt_exports);
37
37
 
38
38
  // src/version.ts
39
- var VERSION = "0.6.0-alpha.6";
39
+ var VERSION = "0.6.0-alpha.8";
40
40
 
41
41
  // src/core/constants.ts
42
42
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -11,7 +11,7 @@ import {
11
11
  handlePreprRequest,
12
12
  isPersonalizedResponse,
13
13
  validatePreprToken
14
- } from "./chunk-PF6GVWHV.js";
14
+ } from "./chunk-SX3MSVPK.js";
15
15
 
16
16
  // src/nuxt/server.ts
17
17
  function getPreprUUID(headers) {
@@ -2313,7 +2313,7 @@ function isReactHydrated(text) {
2313
2313
  }
2314
2314
 
2315
2315
  // src/version.ts
2316
- var VERSION = "0.6.0-alpha.6";
2316
+ var VERSION = "0.6.0-alpha.8";
2317
2317
 
2318
2318
  // src/core/pixel.ts
2319
2319
  var PIXEL_SCRIPT_URL = "https://cdn.tracking.prepr.io/js/prepr.min.js";
@@ -2289,7 +2289,7 @@ function isReactHydrated(text) {
2289
2289
  }
2290
2290
 
2291
2291
  // src/version.ts
2292
- var VERSION = "0.6.0-alpha.6";
2292
+ var VERSION = "0.6.0-alpha.8";
2293
2293
 
2294
2294
  // src/core/pixel.ts
2295
2295
  var PIXEL_SCRIPT_URL = "https://cdn.tracking.prepr.io/js/prepr.min.js";
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var VERSION = "0.6.0-alpha.6";
2
+ var VERSION = "0.6.0-alpha.8";
3
3
 
4
4
  // src/core/constants.ts
5
5
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -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
- selection.typeCondition?.name.value ?? typeName,
197
+ condition,
194
198
  path,
195
199
  ctx
196
200
  );
197
- if (pruned) selections.push({ ...selection, selectionSet: 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
- return {
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, topLevelOnly, ...rest } = queryOptions;
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("|") : topLevelOnly ? "top" : "*";
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