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

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-3EXK2LHI.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-OQGEL4TV.js → chunk-3QGWCYTL.js} +1 -1
  10. package/dist/{chunk-W6AVX6FI.js → chunk-PFJO4TYL.js} +52 -5
  11. package/dist/{chunk-Y7DWVOOY.js → chunk-U7TRFVK7.js} +1 -1
  12. package/dist/{chunk-NSQOGI5K.js → chunk-VQIPTUN4.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-CZK7SMBD.js} +58 -53
  24. package/dist/nextjs/components.cjs +175 -242
  25. package/dist/nextjs/components.d.cts +25 -21
  26. package/dist/nextjs/components.d.ts +25 -21
  27. package/dist/nextjs/components.js +167 -236
  28. package/dist/nextjs/graphql.cjs +372 -509
  29. package/dist/nextjs/graphql.d.cts +131 -135
  30. package/dist/nextjs/graphql.d.ts +131 -135
  31. package/dist/nextjs/graphql.js +307 -456
  32. package/dist/nextjs/index.cjs +114 -54
  33. package/dist/nextjs/index.d.cts +57 -33
  34. package/dist/nextjs/index.d.ts +57 -33
  35. package/dist/nextjs/index.js +108 -5
  36. package/dist/nuxt/{chunk-PF6GVWHV.js → chunk-JL33ENCM.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-S7S276V7.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
@@ -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
  getPreprHeadersFromLocals,
5
5
  isPersonalizedResponse,
6
6
  validatePreprToken
7
- } from "./chunk-5K7HWMIF.js";
7
+ } from "./chunk-S7S276V7.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(sveltekit_exports, {
36
36
  module.exports = __toCommonJS(sveltekit_exports);
37
37
 
38
38
  // src/version.ts
39
- var VERSION = "0.6.0-alpha.6";
39
+ var VERSION = "0.6.0-alpha.7";
40
40
 
41
41
  // src/core/constants.ts
42
42
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";
@@ -11,7 +11,7 @@ import {
11
11
  isPersonalizedResponse,
12
12
  preprHandle,
13
13
  validatePreprToken
14
- } from "./chunk-5K7HWMIF.js";
14
+ } from "./chunk-S7S276V7.js";
15
15
 
16
16
  // src/sveltekit/server.ts
17
17
  function getPreprUUID(headers) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@preprio/toolkit",
3
- "version": "0.6.0-alpha.6",
3
+ "version": "0.6.0-alpha.7",
4
4
  "description": "Prepr personalization, A/B testing and preview toolkit for React, Next.js, Nuxt, Astro, SvelteKit and Express",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Prepr B.V. (https://prepr.io)",