@preprio/toolkit 0.6.0-alpha.0 → 0.6.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +107 -0
- package/dist/astro/{chunk-3UVUDDNY.js → chunk-O7N6GPAH.js} +1 -1
- package/dist/astro/graphql.cjs +96 -49
- package/dist/astro/graphql.d.cts +75 -1
- package/dist/astro/graphql.d.ts +75 -1
- package/dist/astro/graphql.js +92 -49
- package/dist/astro/index.cjs +1 -1
- package/dist/astro/index.js +1 -1
- package/dist/{chunk-YR7P4IWE.js → chunk-3JLWZQ37.js} +1 -9
- package/dist/chunk-3NCEVJJ3.js +10 -0
- package/dist/{chunk-DGZA7KX7.js → chunk-S5RWVMDJ.js} +0 -24
- package/dist/chunk-TBKSBXGH.js +452 -0
- package/dist/{chunk-BJ2LBLWO.js → chunk-VI6QZTBM.js} +6 -4
- package/dist/chunk-YWIKKWBR.js +26 -0
- package/dist/graphql/codegen.cjs +510 -0
- package/dist/graphql/codegen.d.cts +23 -0
- package/dist/graphql/codegen.d.ts +23 -0
- package/dist/graphql/codegen.js +99 -0
- package/dist/graphql.cjs +96 -49
- package/dist/graphql.d.cts +75 -1
- package/dist/graphql.d.ts +75 -1
- package/dist/graphql.js +60 -428
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +10 -6
- package/dist/nextjs/{chunk-U4HXENF7.js → chunk-BQ6IGSH6.js} +1 -1
- package/dist/nextjs/components.cjs +1 -1
- package/dist/nextjs/components.js +3 -2
- package/dist/nextjs/graphql.cjs +96 -49
- package/dist/nextjs/graphql.d.cts +75 -1
- package/dist/nextjs/graphql.d.ts +75 -1
- package/dist/nextjs/graphql.js +92 -49
- package/dist/nextjs/index.cjs +1 -1
- package/dist/nextjs/index.js +1 -1
- package/dist/nuxt/{chunk-P6ENNAEE.js → chunk-IQDSBPDN.js} +1 -1
- package/dist/nuxt/graphql.cjs +96 -49
- package/dist/nuxt/graphql.d.cts +75 -1
- package/dist/nuxt/graphql.d.ts +75 -1
- package/dist/nuxt/graphql.js +92 -49
- package/dist/nuxt/index.cjs +1 -1
- package/dist/nuxt/index.js +1 -1
- package/dist/react/components.cjs +1 -1
- package/dist/react/components.js +1 -1
- package/dist/sveltekit/{chunk-FSARVMG5.js → chunk-OKYZ6HPH.js} +1 -1
- package/dist/sveltekit/graphql.cjs +96 -49
- package/dist/sveltekit/graphql.d.cts +75 -1
- package/dist/sveltekit/graphql.d.ts +75 -1
- package/dist/sveltekit/graphql.js +92 -49
- package/dist/sveltekit/index.cjs +1 -1
- package/dist/sveltekit/index.js +1 -1
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -424,6 +424,102 @@ Outside preview both do nothing (the route answers 404). Keep the route out of y
|
|
|
424
424
|
|
|
425
425
|
Do not catch and swallow errors from `query` without [`unstable_rethrow`](https://nextjs.org/docs/app/api-reference/functions/unstable_rethrow): Next.js signals dynamic rendering by throwing from inside `fetch`, and the client passes those signals through.
|
|
426
426
|
|
|
427
|
+
#### Using your own GraphQL client
|
|
428
|
+
|
|
429
|
+
Everything the toolkit's client does for personalization is two query rewrites and one helper. Use them with any client: Apollo, urql, or plain `fetch`.
|
|
430
|
+
|
|
431
|
+
1. **Variants query** (same for every visitor, cache it): `toVariantsQuery(query, schema)`.
|
|
432
|
+
2. **Decision query** (per visitor, never cached, with the visitor's Prepr headers): `toDecisionQuery(query, schema, { from: variantsData })`, then `decisionsFrom(data)`.
|
|
433
|
+
3. **Render** with `PreprStack` (Next.js) or `resolveVariants(data, { decisions, bucket })` anywhere.
|
|
434
|
+
|
|
435
|
+
The rewrites need to know which fields take `personalize`: `loadPreprSchema(url)` fetches that once and keeps it in memory.
|
|
436
|
+
|
|
437
|
+
```ts
|
|
438
|
+
import {
|
|
439
|
+
decisionsFrom,
|
|
440
|
+
loadPreprSchema,
|
|
441
|
+
resolveVariants,
|
|
442
|
+
toDecisionQuery,
|
|
443
|
+
toVariantsQuery,
|
|
444
|
+
} from '@preprio/toolkit/graphql';
|
|
445
|
+
|
|
446
|
+
const url = process.env.PREPR_GRAPHQL_URL!;
|
|
447
|
+
const schema = await loadPreprSchema(url);
|
|
448
|
+
|
|
449
|
+
async function post(
|
|
450
|
+
query: string,
|
|
451
|
+
variables: object,
|
|
452
|
+
headers: HeadersInit = {},
|
|
453
|
+
) {
|
|
454
|
+
const res = await fetch(url, {
|
|
455
|
+
method: 'POST',
|
|
456
|
+
headers: { 'Content-Type': 'application/json', ...headers },
|
|
457
|
+
body: JSON.stringify({ query, variables }),
|
|
458
|
+
});
|
|
459
|
+
const json = await res.json();
|
|
460
|
+
if (!res.ok || json.errors)
|
|
461
|
+
throw new Error(`Prepr GraphQL request failed (${res.status})`);
|
|
462
|
+
return json.data;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const variables = { slug: '/' };
|
|
466
|
+
const page = await post(toVariantsQuery(PAGE_QUERY, schema), variables); // cacheable
|
|
467
|
+
|
|
468
|
+
const decisionQuery = toDecisionQuery(PAGE_QUERY, schema, { from: page });
|
|
469
|
+
const decisions = decisionQuery
|
|
470
|
+
? decisionsFrom(await post(decisionQuery, variables, visitorPreprHeaders))
|
|
471
|
+
: new Map();
|
|
472
|
+
|
|
473
|
+
const content = resolveVariants(page.Page.content, { decisions, bucket });
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
`visitorPreprHeaders` are the headers the middleware forwards (`getPreprHeaders()` in Next.js); `bucket` is the visitor's A/B bucket (`resolvePreprBucket` stores it in a cookie).
|
|
477
|
+
|
|
478
|
+
With Apollo, parse the strings once and use them like any document:
|
|
479
|
+
|
|
480
|
+
```ts
|
|
481
|
+
import { gql } from '@apollo/client';
|
|
482
|
+
|
|
483
|
+
const PageVariants = gql(toVariantsQuery(PAGE_QUERY, schema));
|
|
484
|
+
const { data: page } = await client.query({ query: PageVariants, variables });
|
|
485
|
+
|
|
486
|
+
const decisionQuery = toDecisionQuery(PAGE_QUERY, schema, { from: page });
|
|
487
|
+
const decisions = decisionQuery
|
|
488
|
+
? decisionsFrom(
|
|
489
|
+
(
|
|
490
|
+
await client.query({
|
|
491
|
+
query: gql(decisionQuery),
|
|
492
|
+
variables,
|
|
493
|
+
context: { headers: visitorPreprHeaders },
|
|
494
|
+
fetchPolicy: 'no-cache', // per visitor: never from Apollo's cache
|
|
495
|
+
})
|
|
496
|
+
).data,
|
|
497
|
+
)
|
|
498
|
+
: new Map();
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
**At build time with graphql-codegen.** The plugin writes both queries per named query into a file, so nothing is rewritten and no schema is loaded at runtime:
|
|
502
|
+
|
|
503
|
+
```ts
|
|
504
|
+
// codegen.ts
|
|
505
|
+
generates: {
|
|
506
|
+
'src/gql/prepr-queries.ts': {
|
|
507
|
+
plugins: ['@preprio/toolkit/graphql/codegen'],
|
|
508
|
+
},
|
|
509
|
+
},
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
```ts
|
|
513
|
+
import {
|
|
514
|
+
GetPageBySlugDecisionQuery,
|
|
515
|
+
GetPageBySlugVariantsQuery,
|
|
516
|
+
} from './gql/prepr-queries';
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
Only named queries with personalizable fields get exports; two queries with the same name fail the run. The generated decision query asks about every personalizable list. When you have the variants result at hand, `toDecisionQuery(query, schema, { from })` is smaller and markedly faster for visitors Prepr has not seen before.
|
|
520
|
+
|
|
521
|
+
A/B tests need no decision query: render both variants and pick the visitor's bucket, as `PreprStack` and `resolvePreprBucket` do, or pass the bucket to `resolveVariants`.
|
|
522
|
+
|
|
427
523
|
### Image loader
|
|
428
524
|
|
|
429
525
|
Prepr's stream CDN resizes at the edge. Routing `next/image` through the bundled loader makes Next request the exact width it needs, instead of pulling the full-resolution original and re-encoding it through `/_next/image`.
|
|
@@ -825,6 +921,17 @@ Import `PreprError` from the same subpath as the client when checking `instanceo
|
|
|
825
921
|
|
|
826
922
|
`isPersonalizedResponse(response)`, exported from every entry point, reads the same verdict from a response fetched with your own client. It does not need `graphql`.
|
|
827
923
|
|
|
924
|
+
For your own GraphQL client (see [Using your own GraphQL client](#using-your-own-graphql-client)), every `/graphql` subpath also exports:
|
|
925
|
+
|
|
926
|
+
| Function | Returns |
|
|
927
|
+
| ---------------------------------------------------------- | -------------------------------------------------------------------------------------- |
|
|
928
|
+
| `loadPreprSchema(url, { fetch? })` | What the rewrites need from your schema, loaded once per URL. Failures are not cached. |
|
|
929
|
+
| `toVariantsQuery(query, schema)` | The variants query as a string: what `variants: true` sends. |
|
|
930
|
+
| `toDecisionQuery(query, schema, { from?, topLevelOnly? })` | The per-visitor decision query as a string, or `null` when there is nothing to decide. |
|
|
931
|
+
| `decisionsFrom(data)` | Decisions from a decision query's `data`, for `resolveVariants` or `PreprStack`. |
|
|
932
|
+
|
|
933
|
+
`@preprio/toolkit/graphql/codegen` is a graphql-codegen plugin that writes `<Name>VariantsQuery` and `<Name>DecisionQuery` for every named query with personalizable fields.
|
|
934
|
+
|
|
828
935
|
### Token helpers
|
|
829
936
|
|
|
830
937
|
Exported from every entry point, including the core.
|
package/dist/astro/graphql.cjs
CHANGED
|
@@ -23,10 +23,14 @@ __export(graphql_exports, {
|
|
|
23
23
|
PREPR_DEFAULT_VARIANT: () => PREPR_DEFAULT_VARIANT,
|
|
24
24
|
PreprError: () => PreprError,
|
|
25
25
|
createPreprClient: () => createPreprClient2,
|
|
26
|
+
decisionsFrom: () => decisionsFrom,
|
|
26
27
|
isPersonalizedResponse: () => isPersonalizedResponse,
|
|
28
|
+
loadPreprSchema: () => loadPreprSchema,
|
|
27
29
|
preprVariantProps: () => preprVariantProps,
|
|
28
30
|
resolveVariants: () => resolveVariants,
|
|
29
|
-
splitStack: () => splitStack
|
|
31
|
+
splitStack: () => splitStack,
|
|
32
|
+
toDecisionQuery: () => toDecisionQuery,
|
|
33
|
+
toVariantsQuery: () => toVariantsQuery
|
|
30
34
|
});
|
|
31
35
|
module.exports = __toCommonJS(graphql_exports);
|
|
32
36
|
|
|
@@ -564,6 +568,63 @@ function toVariantsDocument(document2, schema) {
|
|
|
564
568
|
};
|
|
565
569
|
}
|
|
566
570
|
|
|
571
|
+
// src/core/graphql/document.ts
|
|
572
|
+
var import_printer = require("graphql/language/printer.js");
|
|
573
|
+
var import_stripIgnoredCharacters = require("graphql/utilities/stripIgnoredCharacters.js");
|
|
574
|
+
var printed = /* @__PURE__ */ new WeakMap();
|
|
575
|
+
function isDocumentNode(value) {
|
|
576
|
+
return typeof value === "object" && value !== null && value.kind === "Document" && Array.isArray(value.definitions);
|
|
577
|
+
}
|
|
578
|
+
function invalidDocument(originalError) {
|
|
579
|
+
return new PreprError(
|
|
580
|
+
"Expected a GraphQL query string, TypedDocumentString or DocumentNode",
|
|
581
|
+
"INVALID_DOCUMENT",
|
|
582
|
+
"createPreprClient",
|
|
583
|
+
originalError
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
var minified = /* @__PURE__ */ new Map();
|
|
587
|
+
var MINIFIED_CACHE_LIMIT = 500;
|
|
588
|
+
function minify(query) {
|
|
589
|
+
const cached = minified.get(query);
|
|
590
|
+
if (cached !== void 0) return cached;
|
|
591
|
+
let result = query;
|
|
592
|
+
try {
|
|
593
|
+
result = (0, import_stripIgnoredCharacters.stripIgnoredCharacters)(query);
|
|
594
|
+
} catch {
|
|
595
|
+
}
|
|
596
|
+
if (minified.size < MINIFIED_CACHE_LIMIT) minified.set(query, result);
|
|
597
|
+
return result;
|
|
598
|
+
}
|
|
599
|
+
function resolveQuery(document2) {
|
|
600
|
+
if (typeof document2 === "string") return minify(document2);
|
|
601
|
+
if (document2 instanceof String) return minify(document2.toString());
|
|
602
|
+
if (!isDocumentNode(document2)) throw invalidDocument();
|
|
603
|
+
let query = printed.get(document2);
|
|
604
|
+
if (query === void 0) {
|
|
605
|
+
try {
|
|
606
|
+
query = minify((0, import_printer.print)(document2));
|
|
607
|
+
} catch (error) {
|
|
608
|
+
throw invalidDocument(error instanceof Error ? error : void 0);
|
|
609
|
+
}
|
|
610
|
+
printed.set(document2, query);
|
|
611
|
+
}
|
|
612
|
+
return query;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// src/core/variants/queries.ts
|
|
616
|
+
function toVariantsQuery(document2, schema) {
|
|
617
|
+
return resolveQuery(toVariantsDocument(document2, schema));
|
|
618
|
+
}
|
|
619
|
+
function toDecisionQuery(document2, schema, options = {}) {
|
|
620
|
+
const paths = options.from === void 0 ? void 0 : personalizationPaths(options.from);
|
|
621
|
+
if (paths && paths.size === 0) return null;
|
|
622
|
+
const decision = toDecisionDocument(document2, schema, paths, {
|
|
623
|
+
topLevelOnly: !paths && options.topLevelOnly
|
|
624
|
+
});
|
|
625
|
+
return decision ? resolveQuery(decision) : null;
|
|
626
|
+
}
|
|
627
|
+
|
|
567
628
|
// src/core/graphql/transport.ts
|
|
568
629
|
var import_stega2 = require("@vercel/stega");
|
|
569
630
|
|
|
@@ -623,50 +684,6 @@ function stegaClean(text) {
|
|
|
623
684
|
return (0, import_stega.vercelStegaClean)(text);
|
|
624
685
|
}
|
|
625
686
|
|
|
626
|
-
// src/core/graphql/document.ts
|
|
627
|
-
var import_printer = require("graphql/language/printer.js");
|
|
628
|
-
var import_stripIgnoredCharacters = require("graphql/utilities/stripIgnoredCharacters.js");
|
|
629
|
-
var printed = /* @__PURE__ */ new WeakMap();
|
|
630
|
-
function isDocumentNode(value) {
|
|
631
|
-
return typeof value === "object" && value !== null && value.kind === "Document" && Array.isArray(value.definitions);
|
|
632
|
-
}
|
|
633
|
-
function invalidDocument(originalError) {
|
|
634
|
-
return new PreprError(
|
|
635
|
-
"Expected a GraphQL query string, TypedDocumentString or DocumentNode",
|
|
636
|
-
"INVALID_DOCUMENT",
|
|
637
|
-
"createPreprClient",
|
|
638
|
-
originalError
|
|
639
|
-
);
|
|
640
|
-
}
|
|
641
|
-
var minified = /* @__PURE__ */ new Map();
|
|
642
|
-
var MINIFIED_CACHE_LIMIT = 500;
|
|
643
|
-
function minify(query) {
|
|
644
|
-
const cached = minified.get(query);
|
|
645
|
-
if (cached !== void 0) return cached;
|
|
646
|
-
let result = query;
|
|
647
|
-
try {
|
|
648
|
-
result = (0, import_stripIgnoredCharacters.stripIgnoredCharacters)(query);
|
|
649
|
-
} catch {
|
|
650
|
-
}
|
|
651
|
-
if (minified.size < MINIFIED_CACHE_LIMIT) minified.set(query, result);
|
|
652
|
-
return result;
|
|
653
|
-
}
|
|
654
|
-
function resolveQuery(document2) {
|
|
655
|
-
if (typeof document2 === "string") return minify(document2);
|
|
656
|
-
if (document2 instanceof String) return minify(document2.toString());
|
|
657
|
-
if (!isDocumentNode(document2)) throw invalidDocument();
|
|
658
|
-
let query = printed.get(document2);
|
|
659
|
-
if (query === void 0) {
|
|
660
|
-
try {
|
|
661
|
-
query = minify((0, import_printer.print)(document2));
|
|
662
|
-
} catch (error) {
|
|
663
|
-
throw invalidDocument(error instanceof Error ? error : void 0);
|
|
664
|
-
}
|
|
665
|
-
printed.set(document2, query);
|
|
666
|
-
}
|
|
667
|
-
return query;
|
|
668
|
-
}
|
|
669
|
-
|
|
670
687
|
// src/core/graphql/transport.ts
|
|
671
688
|
var OPERATION_NAME = /\b(?:query|mutation|subscription)\s+([_A-Za-z][_0-9A-Za-z]*)/;
|
|
672
689
|
var STEGA_RAW = new RegExp(
|
|
@@ -853,16 +870,18 @@ function isParseableUrl(url) {
|
|
|
853
870
|
return false;
|
|
854
871
|
}
|
|
855
872
|
}
|
|
856
|
-
function
|
|
857
|
-
const { url } = options;
|
|
873
|
+
function assertPreprUrl(url, source) {
|
|
858
874
|
validatePreprToken(url);
|
|
859
875
|
if (!isParseableUrl(url)) {
|
|
860
876
|
throw new PreprError(
|
|
861
877
|
"Prepr GraphQL URL is not a valid URL",
|
|
862
878
|
"INVALID_TOKEN",
|
|
863
|
-
|
|
879
|
+
source
|
|
864
880
|
);
|
|
865
881
|
}
|
|
882
|
+
}
|
|
883
|
+
function createPreprClient(options) {
|
|
884
|
+
assertPreprUrl(options.url, "createPreprClient");
|
|
866
885
|
const run = createTransport(options);
|
|
867
886
|
const probeVary = createVaryProbe(run, options);
|
|
868
887
|
let schema;
|
|
@@ -965,6 +984,30 @@ function createEventClient(options, adapter) {
|
|
|
965
984
|
};
|
|
966
985
|
}
|
|
967
986
|
|
|
987
|
+
// src/core/graphql/schema-loader.ts
|
|
988
|
+
var schemas = /* @__PURE__ */ new Map();
|
|
989
|
+
async function loadPreprSchema(url, options = {}) {
|
|
990
|
+
assertPreprUrl(url, "loadPreprSchema");
|
|
991
|
+
let schema = schemas.get(url);
|
|
992
|
+
if (!schema) {
|
|
993
|
+
const run = createTransport({ url, fetch: options.fetch, stega: "none" });
|
|
994
|
+
schema = run(
|
|
995
|
+
PREPR_SCHEMA_QUERY
|
|
996
|
+
).then((result) => toSchemaInfo(result.data)).catch((error) => {
|
|
997
|
+
schemas.delete(url);
|
|
998
|
+
if (error instanceof PreprError) throw error;
|
|
999
|
+
throw new PreprError(
|
|
1000
|
+
"Prepr schema response is not an introspection result",
|
|
1001
|
+
"INVALID_RESPONSE",
|
|
1002
|
+
"loadPreprSchema",
|
|
1003
|
+
error instanceof Error ? error : void 0
|
|
1004
|
+
);
|
|
1005
|
+
});
|
|
1006
|
+
schemas.set(url, schema);
|
|
1007
|
+
}
|
|
1008
|
+
return schema;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
968
1011
|
// src/astro/graphql.ts
|
|
969
1012
|
function createPreprClient2(options) {
|
|
970
1013
|
return createEventClient(options, {
|
|
@@ -976,8 +1019,12 @@ function createPreprClient2(options) {
|
|
|
976
1019
|
PREPR_DEFAULT_VARIANT,
|
|
977
1020
|
PreprError,
|
|
978
1021
|
createPreprClient,
|
|
1022
|
+
decisionsFrom,
|
|
979
1023
|
isPersonalizedResponse,
|
|
1024
|
+
loadPreprSchema,
|
|
980
1025
|
preprVariantProps,
|
|
981
1026
|
resolveVariants,
|
|
982
|
-
splitStack
|
|
1027
|
+
splitStack,
|
|
1028
|
+
toDecisionQuery,
|
|
1029
|
+
toVariantsQuery
|
|
983
1030
|
});
|
package/dist/astro/graphql.d.cts
CHANGED
|
@@ -7,6 +7,12 @@ declare const PREPR_DEFAULT_VARIANT = "ALL_OTHER_USERS";
|
|
|
7
7
|
|
|
8
8
|
/** The variant ids Prepr chose for one visitor, per personalization group. */
|
|
9
9
|
type PreprDecisions = ReadonlyMap<string, readonly string[]>;
|
|
10
|
+
/**
|
|
11
|
+
* Variant ids per group from a decision response, de-duplicated and in
|
|
12
|
+
* Prepr's order. A visitor in several segments can get more than one variant
|
|
13
|
+
* of the same group, so each entry is a list.
|
|
14
|
+
*/
|
|
15
|
+
declare function decisionsFrom(data: unknown): PreprDecisions;
|
|
10
16
|
interface ResolveVariantsOptions {
|
|
11
17
|
/**
|
|
12
18
|
* The visitor's per-group variants (from a decision query). Without it,
|
|
@@ -23,6 +29,24 @@ interface ResolveVariantsOptions {
|
|
|
23
29
|
*/
|
|
24
30
|
declare function resolveVariants<T>(data: T, options?: ResolveVariantsOptions): T;
|
|
25
31
|
|
|
32
|
+
interface FieldInfo {
|
|
33
|
+
/** Named type of the field, without list/non-null wrappers. */
|
|
34
|
+
type: string;
|
|
35
|
+
/** The field accepts Prepr's `personalize` argument (a stack). */
|
|
36
|
+
personalizable: boolean;
|
|
37
|
+
}
|
|
38
|
+
interface TypeInfo {
|
|
39
|
+
fields: Record<string, FieldInfo>;
|
|
40
|
+
/** Members of a union or implementations of an interface. */
|
|
41
|
+
possibleTypes: string[];
|
|
42
|
+
hasContext: boolean;
|
|
43
|
+
}
|
|
44
|
+
/** The slice of the schema the variant transforms need. */
|
|
45
|
+
interface PreprSchemaInfo {
|
|
46
|
+
queryType: string;
|
|
47
|
+
types: Record<string, TypeInfo>;
|
|
48
|
+
}
|
|
49
|
+
|
|
26
50
|
/** A run of stack items that renders the same way: see {@link splitStack}. */
|
|
27
51
|
interface PreprStackBlock<T> {
|
|
28
52
|
key: string;
|
|
@@ -71,6 +95,39 @@ interface PreprVariantProps {
|
|
|
71
95
|
*/
|
|
72
96
|
declare function preprVariantProps(item: unknown): PreprVariantProps;
|
|
73
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
|
+
|
|
74
131
|
/**
|
|
75
132
|
* A GraphQL document accepted by `query`: a plain string, graphql-codegen's
|
|
76
133
|
* `TypedDocumentString` (`documentMode: 'string'`), or any `DocumentNode`,
|
|
@@ -211,6 +268,23 @@ interface PreprEventClient<TEvent> {
|
|
|
211
268
|
}): Promise<PreprDecisions>;
|
|
212
269
|
}
|
|
213
270
|
|
|
271
|
+
/**
|
|
272
|
+
* Loads what `toVariantsQuery` and `toDecisionQuery` need to know about your
|
|
273
|
+
* Prepr schema (which fields take `personalize`, which types can hold
|
|
274
|
+
* variants) with one introspection request, kept in memory per URL. For a
|
|
275
|
+
* site that uses its own GraphQL client; `createPreprClient` does this
|
|
276
|
+
* itself.
|
|
277
|
+
*
|
|
278
|
+
* Load it once at startup or lazily before the first rewrite. Schema changes
|
|
279
|
+
* in Prepr take effect after a restart or redeploy.
|
|
280
|
+
*
|
|
281
|
+
* @throws PreprError when the URL is invalid or the request fails; the URL,
|
|
282
|
+
* which holds your access token, is never part of the message.
|
|
283
|
+
*/
|
|
284
|
+
declare function loadPreprSchema(url: string, options?: {
|
|
285
|
+
fetch?: typeof fetch;
|
|
286
|
+
}): Promise<PreprSchemaInfo>;
|
|
287
|
+
|
|
214
288
|
/** Error thrown by the token helpers and the segments fetch. */
|
|
215
289
|
declare class PreprError extends Error {
|
|
216
290
|
readonly code: PreprErrorCode;
|
|
@@ -228,4 +302,4 @@ declare class PreprError extends Error {
|
|
|
228
302
|
*/
|
|
229
303
|
declare function createPreprClient(options: PreprClientOptions): PreprEventClient<AstroLikeContext>;
|
|
230
304
|
|
|
231
|
-
export { AstroLikeContext, PREPR_DEFAULT_VARIANT, type PreprClientOptions, type PreprDecideOptions, type PreprDecisions, type PreprDocument, PreprError, type PreprEventClient, type PreprEventQueryOptions, type PreprQueryResult, type PreprStackBlock, type PreprStegaMode, type PreprVariantProps, type ResolveVariantsOptions, createPreprClient, preprVariantProps, resolveVariants, splitStack };
|
|
305
|
+
export { AstroLikeContext, PREPR_DEFAULT_VARIANT, type PreprClientOptions, type PreprDecideOptions, type PreprDecisions, type PreprDocument, PreprError, type PreprEventClient, type PreprEventQueryOptions, type PreprQueryResult, type PreprSchema, type PreprStackBlock, type PreprStegaMode, type PreprVariantProps, type ResolveVariantsOptions, createPreprClient, decisionsFrom, loadPreprSchema, preprVariantProps, resolveVariants, splitStack, toDecisionQuery, toVariantsQuery };
|
package/dist/astro/graphql.d.ts
CHANGED
|
@@ -7,6 +7,12 @@ declare const PREPR_DEFAULT_VARIANT = "ALL_OTHER_USERS";
|
|
|
7
7
|
|
|
8
8
|
/** The variant ids Prepr chose for one visitor, per personalization group. */
|
|
9
9
|
type PreprDecisions = ReadonlyMap<string, readonly string[]>;
|
|
10
|
+
/**
|
|
11
|
+
* Variant ids per group from a decision response, de-duplicated and in
|
|
12
|
+
* Prepr's order. A visitor in several segments can get more than one variant
|
|
13
|
+
* of the same group, so each entry is a list.
|
|
14
|
+
*/
|
|
15
|
+
declare function decisionsFrom(data: unknown): PreprDecisions;
|
|
10
16
|
interface ResolveVariantsOptions {
|
|
11
17
|
/**
|
|
12
18
|
* The visitor's per-group variants (from a decision query). Without it,
|
|
@@ -23,6 +29,24 @@ interface ResolveVariantsOptions {
|
|
|
23
29
|
*/
|
|
24
30
|
declare function resolveVariants<T>(data: T, options?: ResolveVariantsOptions): T;
|
|
25
31
|
|
|
32
|
+
interface FieldInfo {
|
|
33
|
+
/** Named type of the field, without list/non-null wrappers. */
|
|
34
|
+
type: string;
|
|
35
|
+
/** The field accepts Prepr's `personalize` argument (a stack). */
|
|
36
|
+
personalizable: boolean;
|
|
37
|
+
}
|
|
38
|
+
interface TypeInfo {
|
|
39
|
+
fields: Record<string, FieldInfo>;
|
|
40
|
+
/** Members of a union or implementations of an interface. */
|
|
41
|
+
possibleTypes: string[];
|
|
42
|
+
hasContext: boolean;
|
|
43
|
+
}
|
|
44
|
+
/** The slice of the schema the variant transforms need. */
|
|
45
|
+
interface PreprSchemaInfo {
|
|
46
|
+
queryType: string;
|
|
47
|
+
types: Record<string, TypeInfo>;
|
|
48
|
+
}
|
|
49
|
+
|
|
26
50
|
/** A run of stack items that renders the same way: see {@link splitStack}. */
|
|
27
51
|
interface PreprStackBlock<T> {
|
|
28
52
|
key: string;
|
|
@@ -71,6 +95,39 @@ interface PreprVariantProps {
|
|
|
71
95
|
*/
|
|
72
96
|
declare function preprVariantProps(item: unknown): PreprVariantProps;
|
|
73
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
|
+
|
|
74
131
|
/**
|
|
75
132
|
* A GraphQL document accepted by `query`: a plain string, graphql-codegen's
|
|
76
133
|
* `TypedDocumentString` (`documentMode: 'string'`), or any `DocumentNode`,
|
|
@@ -211,6 +268,23 @@ interface PreprEventClient<TEvent> {
|
|
|
211
268
|
}): Promise<PreprDecisions>;
|
|
212
269
|
}
|
|
213
270
|
|
|
271
|
+
/**
|
|
272
|
+
* Loads what `toVariantsQuery` and `toDecisionQuery` need to know about your
|
|
273
|
+
* Prepr schema (which fields take `personalize`, which types can hold
|
|
274
|
+
* variants) with one introspection request, kept in memory per URL. For a
|
|
275
|
+
* site that uses its own GraphQL client; `createPreprClient` does this
|
|
276
|
+
* itself.
|
|
277
|
+
*
|
|
278
|
+
* Load it once at startup or lazily before the first rewrite. Schema changes
|
|
279
|
+
* in Prepr take effect after a restart or redeploy.
|
|
280
|
+
*
|
|
281
|
+
* @throws PreprError when the URL is invalid or the request fails; the URL,
|
|
282
|
+
* which holds your access token, is never part of the message.
|
|
283
|
+
*/
|
|
284
|
+
declare function loadPreprSchema(url: string, options?: {
|
|
285
|
+
fetch?: typeof fetch;
|
|
286
|
+
}): Promise<PreprSchemaInfo>;
|
|
287
|
+
|
|
214
288
|
/** Error thrown by the token helpers and the segments fetch. */
|
|
215
289
|
declare class PreprError extends Error {
|
|
216
290
|
readonly code: PreprErrorCode;
|
|
@@ -228,4 +302,4 @@ declare class PreprError extends Error {
|
|
|
228
302
|
*/
|
|
229
303
|
declare function createPreprClient(options: PreprClientOptions): PreprEventClient<AstroLikeContext>;
|
|
230
304
|
|
|
231
|
-
export { AstroLikeContext, PREPR_DEFAULT_VARIANT, type PreprClientOptions, type PreprDecideOptions, type PreprDecisions, type PreprDocument, PreprError, type PreprEventClient, type PreprEventQueryOptions, type PreprQueryResult, type PreprStackBlock, type PreprStegaMode, type PreprVariantProps, type ResolveVariantsOptions, createPreprClient, preprVariantProps, resolveVariants, splitStack };
|
|
305
|
+
export { AstroLikeContext, PREPR_DEFAULT_VARIANT, type PreprClientOptions, type PreprDecideOptions, type PreprDecisions, type PreprDocument, PreprError, type PreprEventClient, type PreprEventQueryOptions, type PreprQueryResult, type PreprSchema, type PreprStackBlock, type PreprStegaMode, type PreprVariantProps, type ResolveVariantsOptions, createPreprClient, decisionsFrom, loadPreprSchema, preprVariantProps, resolveVariants, splitStack, toDecisionQuery, toVariantsQuery };
|