@preprio/toolkit 0.6.0-alpha.2 → 0.6.0-alpha.3

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 (42) hide show
  1. package/README.md +46 -30
  2. package/dist/astro/{chunk-U7VUQL57.js → chunk-CUDYSNJD.js} +1 -1
  3. package/dist/astro/graphql.js +1 -1
  4. package/dist/astro/index.cjs +1 -1
  5. package/dist/astro/index.js +1 -1
  6. package/dist/{chunk-DS3QA3HF.js → chunk-3YZANSVY.js} +1 -1
  7. package/dist/{chunk-7HSMUULV.js → chunk-FC53KN4H.js} +1 -1
  8. package/dist/{chunk-UYYTYSOD.js → chunk-UH2OK4XC.js} +1 -1
  9. package/dist/{chunk-VV4PRH7W.js → chunk-VY5D3IED.js} +1 -1
  10. package/dist/graphql/codegen.js +3 -3
  11. package/dist/graphql.js +3 -3
  12. package/dist/index.cjs +1 -1
  13. package/dist/index.d.cts +1 -1
  14. package/dist/index.d.ts +1 -1
  15. package/dist/index.js +3 -3
  16. package/dist/nextjs/chunk-5XGJJVGX.js +544 -0
  17. package/dist/nextjs/components.cjs +155 -2
  18. package/dist/nextjs/components.d.cts +31 -3
  19. package/dist/nextjs/components.d.ts +31 -3
  20. package/dist/nextjs/components.js +155 -3
  21. package/dist/nextjs/graphql.cjs +588 -50
  22. package/dist/nextjs/graphql.d.cts +95 -28
  23. package/dist/nextjs/graphql.d.ts +95 -28
  24. package/dist/nextjs/graphql.js +287 -50
  25. package/dist/nextjs/index.cjs +3 -1
  26. package/dist/nextjs/index.d.cts +32 -3
  27. package/dist/nextjs/index.d.ts +32 -3
  28. package/dist/nextjs/index.js +8 -313
  29. package/dist/nextjs/{server-CjpELYvq.d.cts → server-BL-sqZvu.d.cts} +1 -1
  30. package/dist/nextjs/{server-CjpELYvq.d.ts → server-BL-sqZvu.d.ts} +1 -1
  31. package/dist/nuxt/{chunk-GMWF6PQ5.js → chunk-KROR7RXW.js} +1 -1
  32. package/dist/nuxt/graphql.js +1 -1
  33. package/dist/nuxt/index.cjs +1 -1
  34. package/dist/nuxt/index.js +1 -1
  35. package/dist/react/components.cjs +1 -1
  36. package/dist/react/components.js +1 -1
  37. package/dist/sveltekit/{chunk-5SQUG2L4.js → chunk-INDMNPEM.js} +1 -1
  38. package/dist/sveltekit/graphql.js +1 -1
  39. package/dist/sveltekit/index.cjs +1 -1
  40. package/dist/sveltekit/index.js +1 -1
  41. package/package.json +1 -1
  42. package/dist/nextjs/chunk-ZIUKEGEN.js +0 -231
@@ -1,7 +1,7 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
2
  import { DocumentNode } from 'graphql';
3
- import { P as PreprHeaders } from './server-CjpELYvq.cjs';
4
- export { a as PreprError, i as isPersonalizedResponse } from './server-CjpELYvq.cjs';
3
+ import { P as PreprHeaders, a as PreprFeatures } from './server-BL-sqZvu.cjs';
4
+ export { b as PreprError, i as isPersonalizedResponse } from './server-BL-sqZvu.cjs';
5
5
  import { ReactNode, ReactElement } from 'react';
6
6
 
7
7
  /** Prepr's variant id for visitors outside every targeted segment. */
@@ -257,6 +257,74 @@ declare function loadPreprSchema(url: string, options?: {
257
257
 
258
258
  /** The cookie `resolveDecisions` writes and the `PreprStack` switch reads. */
259
259
  declare const PREPR_DECISIONS_COOKIE = "prepr_decisions";
260
+ interface ResolveDecisionsOptions {
261
+ /** Give up after this many ms; the default variant shows. Default 1000. */
262
+ timeoutMs?: number;
263
+ /**
264
+ * Keep the stored decision for this many ms instead of asking Prepr again.
265
+ * Default 10 000; `0` asks on every request. Background refreshes by
266
+ * `PreprPersonalizationSwitch` keep it fresh, so a page view rarely waits.
267
+ */
268
+ freshFor?: number;
269
+ /** Skip the decision when this resolves to false. */
270
+ onlyIf?: () => boolean | Promise<boolean>;
271
+ }
272
+
273
+ /** The query a page renders, as `createPreprProxy`'s `page` returns it. */
274
+ interface PreprProxyPage<TVariables = unknown> {
275
+ document: PreprDocument<unknown, TVariables>;
276
+ variables?: TVariables;
277
+ }
278
+ interface PreprProxyOptions {
279
+ /** A client made with this package's Next `createPreprClient`. */
280
+ client: PreprNextClient;
281
+ /**
282
+ * The query the page at `url` renders with `variants: true`, or `null` for
283
+ * a URL that is not a CMS page. Sites that route every page through one
284
+ * query need one line:
285
+ * `(url) => ({ document: PageDocument, variables: { slug: url.pathname } })`.
286
+ */
287
+ page: (url: URL) => PreprProxyPage<any> | null | undefined;
288
+ /** Whether this deployment serves preview content (draft mode, toolbar overrides). */
289
+ preview?: boolean;
290
+ /** Features disabled app-wide, as for `createPreprMiddleware`. */
291
+ features?: PreprFeatures;
292
+ /** See `resolveDecisions`. Default 10 000 ms. */
293
+ freshFor?: number;
294
+ /** Give up on Prepr after this many ms; the default variant shows. Default 1000. */
295
+ timeoutMs?: number;
296
+ /**
297
+ * Skip the A/B bucket lookup and segment decisions (page requests and
298
+ * refreshes) when this resolves to false, for example for crawlers: they
299
+ * carry no cookies, so every crawler request is a first visit that waits
300
+ * for Prepr. Those requests get the default variants.
301
+ */
302
+ onlyIf?: (request: NextRequest) => boolean | Promise<boolean>;
303
+ }
304
+ /**
305
+ * Everything Prepr needs in the proxy (`proxy.ts`), in one call: the visitor's
306
+ * Prepr headers and customer id (`createPreprMiddleware`), the draft-mode
307
+ * redirect in preview, the A/B bucket, and the segment variants of the groups
308
+ * at the top of each page, so `PreprStack` shows them before first paint.
309
+ *
310
+ * It also answers the background refreshes `PreprPersonalizationSwitch`
311
+ * sends: those return `204` with fresh decision cookies and never render a
312
+ * page. Add your own cookies or headers to the response it returns.
313
+ *
314
+ * @example
315
+ * const handlePrepr = createPreprProxy({
316
+ * client: prepr,
317
+ * page: (url) => ({ document: PageDocument, variables: { slug: url.pathname } }),
318
+ * preview: process.env.PREPR_ENV === 'preview',
319
+ * });
320
+ * export function proxy(request: NextRequest) {
321
+ * return handlePrepr(request);
322
+ * }
323
+ *
324
+ * @throws PreprError `CONTEXT_ERROR` when `client` was not made by the Next
325
+ * `createPreprClient`.
326
+ */
327
+ declare function createPreprProxy(options: PreprProxyOptions): (request: NextRequest) => Promise<NextResponse>;
260
328
 
261
329
  interface PreprStackProps<T> {
262
330
  /** A stack (e.g. `page.content`) from a query run with `variants: true`. */
@@ -277,10 +345,17 @@ interface PreprStackProps<T> {
277
345
  * variant of a segment group (the default variant, shown until the
278
346
  * decision streams in). Leave `data-prepr-variant-key` off it: the tracking
279
347
  * pixel would count an impression of a variant the visitor may never get.
348
+ *
349
+ * `defaultVariant` is false for the variants that are in the page but
350
+ * hidden unless the visitor gets them: the other buckets of an A/B test and
351
+ * the other segment variants above the fold. Give only the default variant
352
+ * `priority` images, and the others `loading="lazy"`: the browser downloads
353
+ * a hidden eager image anyway, but skips a hidden lazy one.
280
354
  */
281
355
  render: (items: T[], position: {
282
356
  index: number;
283
357
  placeholder: boolean;
358
+ defaultVariant: boolean;
284
359
  }) => ReactNode;
285
360
  /**
286
361
  * The visitor's A/B bucket, when the route already knows it (for example
@@ -305,14 +380,17 @@ interface PreprStackProps<T> {
305
380
  trackVariants?: boolean;
306
381
  /**
307
382
  * How many blocks, from the top, are on screen before the visitor scrolls.
308
- * Default `0`.
383
+ * Default `1`; set it higher when more sections fit on the first screen
384
+ * (take the larger screen when it differs per device), or `0` to stream
385
+ * every segment group.
309
386
  *
310
387
  * Their segment groups do not stream: every variant is in the cached page,
311
388
  * and the variant the proxy decided (`prepr.resolveDecisions`) shows before
312
389
  * first paint, so nothing on screen changes while the page loads. Without
313
390
  * a decision (no cookie yet, or the proxy's lookup failed) the default
314
- * variant shows. Costs the HTML of the other variants; images in them still
315
- * download. An item with a segment group nested inside it keeps streaming.
391
+ * variant shows. Costs the HTML of the other variants; see `defaultVariant`
392
+ * in `render` to keep their images from downloading. An item with a
393
+ * segment group nested inside it keeps streaming.
316
394
  */
317
395
  aboveTheFold?: number;
318
396
  }
@@ -388,31 +466,20 @@ interface PreprNextClient {
388
466
  hasAbTests<TVariables>(document: PreprDocument<unknown, TVariables>, variables?: TVariables): Promise<boolean>;
389
467
  /**
390
468
  * In middleware (`proxy.ts`): asks Prepr which segment variant this visitor
391
- * gets for each personalization group on the page, and stores the answer in
392
- * the `prepr_decisions` cookie on `response`. `PreprStack` with
393
- * `aboveTheFold` then shows those variants before first paint instead of
394
- * streaming them in.
469
+ * gets for each personalization group at the top of the page, and stores
470
+ * the answer in the `prepr_decisions` cookie on `response`. `PreprStack`
471
+ * then shows those variants before first paint instead of streaming them
472
+ * in. `createPreprProxy` calls this for you.
395
473
  *
396
474
  * Call it after `createPreprMiddleware`, whose visitor headers (customer id,
397
- * UTM parameters, IP, HubSpot id) it forwards. A decision is an uncached
398
- * Prepr request, made once per visit by default (see `reuse`); limit it
399
- * with `onlyIf` to pages whose personalized content is above the fold.
400
- * Pages without segment groups are skipped after a cached check. Never throws and gives up after `timeoutMs`
401
- * (default 1000): the default variant shows instead.
475
+ * UTM parameters, IP, HubSpot id) it forwards. A stored decision that
476
+ * covers the page is kept for `freshFor` (default 10 s); a first visit, UTM
477
+ * parameters and a segment forced in preview always ask again. Pages
478
+ * without segment groups at the top are skipped after a cached check.
479
+ * Never throws and gives up after `timeoutMs` (default 1000): the default
480
+ * variant shows instead.
402
481
  */
403
- resolveDecisions<TVariables>(request: NextRequest, response: NextResponse, document: PreprDocument<unknown, TVariables>, variables?: TVariables, options?: {
404
- timeoutMs?: number;
405
- /**
406
- * Reuse the stored decision for the rest of the visit instead of asking
407
- * Prepr on every page view. Default `true`. Asks again when UTM
408
- * parameters arrive, on a first visit, and when preview forces a
409
- * segment. A visitor who joins a segment mid-visit (say, by submitting
410
- * a form) sees the change from their next asked request.
411
- */
412
- reuse?: boolean;
413
- /** Skip the decision when this resolves to false, e.g. for pages without a personalized hero. */
414
- onlyIf?: () => boolean | Promise<boolean>;
415
- }): Promise<void>;
482
+ resolveDecisions<TVariables>(request: NextRequest, response: NextResponse, document: PreprDocument<unknown, TVariables>, variables?: TVariables, options?: ResolveDecisionsOptions): Promise<void>;
416
483
  }
417
484
  /**
418
485
  * Prepr GraphQL client for Next.js (App Router, server only).
@@ -432,4 +499,4 @@ interface PreprNextClient {
432
499
  */
433
500
  declare function createPreprClient(options: PreprNextClientOptions): PreprNextClient;
434
501
 
435
- export { PREPR_DECISIONS_COOKIE, PREPR_DEFAULT_VARIANT, type PreprDecideOptions, type PreprDecisions, type PreprDocument, type PreprNextClient, type PreprNextClientOptions, type PreprNextQueryOptions, type PreprQueryResult, type PreprSchema, PreprStack, type PreprStackBlock, type PreprStackProps, type PreprStegaMode, type PreprVariantProps, type ResolveVariantsOptions, createPreprClient, decisionsFrom, loadPreprSchema, preprVariantProps, resolveVariants, splitStack, toDecisionQuery, toVariantsQuery };
502
+ export { PREPR_DECISIONS_COOKIE, PREPR_DEFAULT_VARIANT, type PreprDecideOptions, type PreprDecisions, type PreprDocument, type PreprNextClient, type PreprNextClientOptions, type PreprNextQueryOptions, type PreprProxyOptions, type PreprProxyPage, type PreprQueryResult, type PreprSchema, PreprStack, type PreprStackBlock, type PreprStackProps, type PreprStegaMode, type PreprVariantProps, type ResolveDecisionsOptions, type ResolveVariantsOptions, createPreprClient, createPreprProxy, decisionsFrom, loadPreprSchema, preprVariantProps, resolveVariants, splitStack, toDecisionQuery, toVariantsQuery };
@@ -1,7 +1,7 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
2
  import { DocumentNode } from 'graphql';
3
- import { P as PreprHeaders } from './server-CjpELYvq.js';
4
- export { a as PreprError, i as isPersonalizedResponse } from './server-CjpELYvq.js';
3
+ import { P as PreprHeaders, a as PreprFeatures } from './server-BL-sqZvu.js';
4
+ export { b as PreprError, i as isPersonalizedResponse } from './server-BL-sqZvu.js';
5
5
  import { ReactNode, ReactElement } from 'react';
6
6
 
7
7
  /** Prepr's variant id for visitors outside every targeted segment. */
@@ -257,6 +257,74 @@ declare function loadPreprSchema(url: string, options?: {
257
257
 
258
258
  /** The cookie `resolveDecisions` writes and the `PreprStack` switch reads. */
259
259
  declare const PREPR_DECISIONS_COOKIE = "prepr_decisions";
260
+ interface ResolveDecisionsOptions {
261
+ /** Give up after this many ms; the default variant shows. Default 1000. */
262
+ timeoutMs?: number;
263
+ /**
264
+ * Keep the stored decision for this many ms instead of asking Prepr again.
265
+ * Default 10 000; `0` asks on every request. Background refreshes by
266
+ * `PreprPersonalizationSwitch` keep it fresh, so a page view rarely waits.
267
+ */
268
+ freshFor?: number;
269
+ /** Skip the decision when this resolves to false. */
270
+ onlyIf?: () => boolean | Promise<boolean>;
271
+ }
272
+
273
+ /** The query a page renders, as `createPreprProxy`'s `page` returns it. */
274
+ interface PreprProxyPage<TVariables = unknown> {
275
+ document: PreprDocument<unknown, TVariables>;
276
+ variables?: TVariables;
277
+ }
278
+ interface PreprProxyOptions {
279
+ /** A client made with this package's Next `createPreprClient`. */
280
+ client: PreprNextClient;
281
+ /**
282
+ * The query the page at `url` renders with `variants: true`, or `null` for
283
+ * a URL that is not a CMS page. Sites that route every page through one
284
+ * query need one line:
285
+ * `(url) => ({ document: PageDocument, variables: { slug: url.pathname } })`.
286
+ */
287
+ page: (url: URL) => PreprProxyPage<any> | null | undefined;
288
+ /** Whether this deployment serves preview content (draft mode, toolbar overrides). */
289
+ preview?: boolean;
290
+ /** Features disabled app-wide, as for `createPreprMiddleware`. */
291
+ features?: PreprFeatures;
292
+ /** See `resolveDecisions`. Default 10 000 ms. */
293
+ freshFor?: number;
294
+ /** Give up on Prepr after this many ms; the default variant shows. Default 1000. */
295
+ timeoutMs?: number;
296
+ /**
297
+ * Skip the A/B bucket lookup and segment decisions (page requests and
298
+ * refreshes) when this resolves to false, for example for crawlers: they
299
+ * carry no cookies, so every crawler request is a first visit that waits
300
+ * for Prepr. Those requests get the default variants.
301
+ */
302
+ onlyIf?: (request: NextRequest) => boolean | Promise<boolean>;
303
+ }
304
+ /**
305
+ * Everything Prepr needs in the proxy (`proxy.ts`), in one call: the visitor's
306
+ * Prepr headers and customer id (`createPreprMiddleware`), the draft-mode
307
+ * redirect in preview, the A/B bucket, and the segment variants of the groups
308
+ * at the top of each page, so `PreprStack` shows them before first paint.
309
+ *
310
+ * It also answers the background refreshes `PreprPersonalizationSwitch`
311
+ * sends: those return `204` with fresh decision cookies and never render a
312
+ * page. Add your own cookies or headers to the response it returns.
313
+ *
314
+ * @example
315
+ * const handlePrepr = createPreprProxy({
316
+ * client: prepr,
317
+ * page: (url) => ({ document: PageDocument, variables: { slug: url.pathname } }),
318
+ * preview: process.env.PREPR_ENV === 'preview',
319
+ * });
320
+ * export function proxy(request: NextRequest) {
321
+ * return handlePrepr(request);
322
+ * }
323
+ *
324
+ * @throws PreprError `CONTEXT_ERROR` when `client` was not made by the Next
325
+ * `createPreprClient`.
326
+ */
327
+ declare function createPreprProxy(options: PreprProxyOptions): (request: NextRequest) => Promise<NextResponse>;
260
328
 
261
329
  interface PreprStackProps<T> {
262
330
  /** A stack (e.g. `page.content`) from a query run with `variants: true`. */
@@ -277,10 +345,17 @@ interface PreprStackProps<T> {
277
345
  * variant of a segment group (the default variant, shown until the
278
346
  * decision streams in). Leave `data-prepr-variant-key` off it: the tracking
279
347
  * pixel would count an impression of a variant the visitor may never get.
348
+ *
349
+ * `defaultVariant` is false for the variants that are in the page but
350
+ * hidden unless the visitor gets them: the other buckets of an A/B test and
351
+ * the other segment variants above the fold. Give only the default variant
352
+ * `priority` images, and the others `loading="lazy"`: the browser downloads
353
+ * a hidden eager image anyway, but skips a hidden lazy one.
280
354
  */
281
355
  render: (items: T[], position: {
282
356
  index: number;
283
357
  placeholder: boolean;
358
+ defaultVariant: boolean;
284
359
  }) => ReactNode;
285
360
  /**
286
361
  * The visitor's A/B bucket, when the route already knows it (for example
@@ -305,14 +380,17 @@ interface PreprStackProps<T> {
305
380
  trackVariants?: boolean;
306
381
  /**
307
382
  * How many blocks, from the top, are on screen before the visitor scrolls.
308
- * Default `0`.
383
+ * Default `1`; set it higher when more sections fit on the first screen
384
+ * (take the larger screen when it differs per device), or `0` to stream
385
+ * every segment group.
309
386
  *
310
387
  * Their segment groups do not stream: every variant is in the cached page,
311
388
  * and the variant the proxy decided (`prepr.resolveDecisions`) shows before
312
389
  * first paint, so nothing on screen changes while the page loads. Without
313
390
  * a decision (no cookie yet, or the proxy's lookup failed) the default
314
- * variant shows. Costs the HTML of the other variants; images in them still
315
- * download. An item with a segment group nested inside it keeps streaming.
391
+ * variant shows. Costs the HTML of the other variants; see `defaultVariant`
392
+ * in `render` to keep their images from downloading. An item with a
393
+ * segment group nested inside it keeps streaming.
316
394
  */
317
395
  aboveTheFold?: number;
318
396
  }
@@ -388,31 +466,20 @@ interface PreprNextClient {
388
466
  hasAbTests<TVariables>(document: PreprDocument<unknown, TVariables>, variables?: TVariables): Promise<boolean>;
389
467
  /**
390
468
  * In middleware (`proxy.ts`): asks Prepr which segment variant this visitor
391
- * gets for each personalization group on the page, and stores the answer in
392
- * the `prepr_decisions` cookie on `response`. `PreprStack` with
393
- * `aboveTheFold` then shows those variants before first paint instead of
394
- * streaming them in.
469
+ * gets for each personalization group at the top of the page, and stores
470
+ * the answer in the `prepr_decisions` cookie on `response`. `PreprStack`
471
+ * then shows those variants before first paint instead of streaming them
472
+ * in. `createPreprProxy` calls this for you.
395
473
  *
396
474
  * Call it after `createPreprMiddleware`, whose visitor headers (customer id,
397
- * UTM parameters, IP, HubSpot id) it forwards. A decision is an uncached
398
- * Prepr request, made once per visit by default (see `reuse`); limit it
399
- * with `onlyIf` to pages whose personalized content is above the fold.
400
- * Pages without segment groups are skipped after a cached check. Never throws and gives up after `timeoutMs`
401
- * (default 1000): the default variant shows instead.
475
+ * UTM parameters, IP, HubSpot id) it forwards. A stored decision that
476
+ * covers the page is kept for `freshFor` (default 10 s); a first visit, UTM
477
+ * parameters and a segment forced in preview always ask again. Pages
478
+ * without segment groups at the top are skipped after a cached check.
479
+ * Never throws and gives up after `timeoutMs` (default 1000): the default
480
+ * variant shows instead.
402
481
  */
403
- resolveDecisions<TVariables>(request: NextRequest, response: NextResponse, document: PreprDocument<unknown, TVariables>, variables?: TVariables, options?: {
404
- timeoutMs?: number;
405
- /**
406
- * Reuse the stored decision for the rest of the visit instead of asking
407
- * Prepr on every page view. Default `true`. Asks again when UTM
408
- * parameters arrive, on a first visit, and when preview forces a
409
- * segment. A visitor who joins a segment mid-visit (say, by submitting
410
- * a form) sees the change from their next asked request.
411
- */
412
- reuse?: boolean;
413
- /** Skip the decision when this resolves to false, e.g. for pages without a personalized hero. */
414
- onlyIf?: () => boolean | Promise<boolean>;
415
- }): Promise<void>;
482
+ resolveDecisions<TVariables>(request: NextRequest, response: NextResponse, document: PreprDocument<unknown, TVariables>, variables?: TVariables, options?: ResolveDecisionsOptions): Promise<void>;
416
483
  }
417
484
  /**
418
485
  * Prepr GraphQL client for Next.js (App Router, server only).
@@ -432,4 +499,4 @@ interface PreprNextClient {
432
499
  */
433
500
  declare function createPreprClient(options: PreprNextClientOptions): PreprNextClient;
434
501
 
435
- export { PREPR_DECISIONS_COOKIE, PREPR_DEFAULT_VARIANT, type PreprDecideOptions, type PreprDecisions, type PreprDocument, type PreprNextClient, type PreprNextClientOptions, type PreprNextQueryOptions, type PreprQueryResult, type PreprSchema, PreprStack, type PreprStackBlock, type PreprStackProps, type PreprStegaMode, type PreprVariantProps, type ResolveVariantsOptions, createPreprClient, decisionsFrom, loadPreprSchema, preprVariantProps, resolveVariants, splitStack, toDecisionQuery, toVariantsQuery };
502
+ export { PREPR_DECISIONS_COOKIE, PREPR_DEFAULT_VARIANT, type PreprDecideOptions, type PreprDecisions, type PreprDocument, type PreprNextClient, type PreprNextClientOptions, type PreprNextQueryOptions, type PreprProxyOptions, type PreprProxyPage, type PreprQueryResult, type PreprSchema, PreprStack, type PreprStackBlock, type PreprStackProps, type PreprStegaMode, type PreprVariantProps, type ResolveDecisionsOptions, type ResolveVariantsOptions, createPreprClient, createPreprProxy, decisionsFrom, loadPreprSchema, preprVariantProps, resolveVariants, splitStack, toDecisionQuery, toVariantsQuery };