@xenia-martech/sdk-js 1.2.0-dev.2 → 1.2.0-dev.4
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 +112 -3
- package/dist/{actions-BcdlokGO.d.cts → actions-C18Kv-4w.d.cts} +50 -2
- package/dist/{actions-BcdlokGO.d.ts → actions-C18Kv-4w.d.ts} +50 -2
- package/dist/{api-CktVQ6Gl.d.ts → api-0IycTYJR.d.cts} +4 -2
- package/dist/{api-BEPW0Uan.d.cts → api-COXWLL5L.d.ts} +4 -2
- package/dist/{chunk-3PYPPIUM.cjs → chunk-2DR5AVPX.cjs} +11 -46
- package/dist/chunk-2DR5AVPX.cjs.map +1 -0
- package/dist/chunk-BQ5PJCZ7.js +179 -0
- package/dist/chunk-BQ5PJCZ7.js.map +1 -0
- package/dist/{chunk-DWFVDNU5.js → chunk-GWRDZIVA.js} +5 -37
- package/dist/chunk-GWRDZIVA.js.map +1 -0
- package/dist/{chunk-7NGJC7CF.js → chunk-LW5AEJ6K.js} +20 -183
- package/dist/chunk-LW5AEJ6K.js.map +1 -0
- package/dist/chunk-N5M4PI7C.cjs +192 -0
- package/dist/chunk-N5M4PI7C.cjs.map +1 -0
- package/dist/chunk-OMMIRSPK.js +336 -0
- package/dist/chunk-OMMIRSPK.js.map +1 -0
- package/dist/chunk-QEYONKWY.js +42 -0
- package/dist/chunk-QEYONKWY.js.map +1 -0
- package/dist/{chunk-IBNIRT7J.cjs → chunk-RWE2OCQL.cjs} +20 -194
- package/dist/chunk-RWE2OCQL.cjs.map +1 -0
- package/dist/chunk-WHGK55JP.cjs +46 -0
- package/dist/chunk-WHGK55JP.cjs.map +1 -0
- package/dist/chunk-YLMMTKQL.cjs +358 -0
- package/dist/chunk-YLMMTKQL.cjs.map +1 -0
- package/dist/client/index.cjs +320 -31
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +15 -4
- package/dist/client/index.d.ts +15 -4
- package/dist/client/index.js +320 -31
- package/dist/client/index.js.map +1 -1
- package/dist/client/react/index.cjs +731 -34
- package/dist/client/react/index.cjs.map +1 -1
- package/dist/client/react/index.d.cts +32 -3
- package/dist/client/react/index.d.ts +32 -3
- package/dist/client/react/index.js +732 -37
- package/dist/client/react/index.js.map +1 -1
- package/dist/cms/contentful.cjs +2 -1
- package/dist/cms/contentful.cjs.map +1 -1
- package/dist/cms/contentful.d.cts +2 -1
- package/dist/cms/contentful.d.ts +2 -1
- package/dist/cms/contentful.js +2 -1
- package/dist/cms/contentful.js.map +1 -1
- package/dist/consent-Cemn91j3.d.ts +248 -0
- package/dist/consent-DgWdjsSy.d.cts +248 -0
- package/dist/{cookie-names-CLqtmGBM.d.ts → cookie-names-BvUaW3uo.d.ts} +1 -1
- package/dist/{cookie-names-BACctagz.d.cts → cookie-names-CnL65Oly.d.cts} +1 -1
- package/dist/edge/index.cjs +280 -0
- package/dist/edge/index.cjs.map +1 -0
- package/dist/edge/index.d.cts +61 -0
- package/dist/edge/index.d.ts +61 -0
- package/dist/edge/index.js +191 -0
- package/dist/edge/index.js.map +1 -0
- package/dist/index.cjs +41 -40
- package/dist/index.d.cts +5 -4
- package/dist/index.d.ts +5 -4
- package/dist/index.js +2 -1
- package/dist/next/index.cjs +320 -15
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.d.cts +180 -6
- package/dist/next/index.d.ts +180 -6
- package/dist/next/index.js +309 -9
- package/dist/next/index.js.map +1 -1
- package/dist/personalize-content-c2DDAV6g.d.ts +140 -0
- package/dist/personalize-content-ghZPKlf1.d.cts +140 -0
- package/dist/server/index.cjs +34 -32
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +6 -5
- package/dist/server/index.d.ts +6 -5
- package/dist/server/index.js +5 -3
- package/dist/server/index.js.map +1 -1
- package/dist/{personalize-content-Clc1oMYY.d.ts → types-DgVHS4Qw.d.cts} +7 -127
- package/dist/{personalize-content-Clc1oMYY.d.cts → types-DgVHS4Qw.d.ts} +7 -127
- package/dist/xenia-sdk.iife.js +3 -3
- package/dist/xenia-sdk.iife.js.map +1 -1
- package/dist/{xenia-server-o_wDOcei.d.cts → xenia-server-C3O-cWQT.d.cts} +3 -2
- package/dist/{xenia-server-BWhWD0La.d.ts → xenia-server-DV8Sjmoo.d.ts} +3 -2
- package/package.json +14 -1
- package/dist/chunk-3PYPPIUM.cjs.map +0 -1
- package/dist/chunk-7NGJC7CF.js.map +0 -1
- package/dist/chunk-DWFVDNU5.js.map +0 -1
- package/dist/chunk-IBNIRT7J.cjs.map +0 -1
package/dist/next/index.d.cts
CHANGED
|
@@ -1,7 +1,183 @@
|
|
|
1
1
|
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
-
import { V as VisitorCookieOptions,
|
|
3
|
-
import { X as XeniaServer } from '../xenia-server-
|
|
4
|
-
import '../
|
|
2
|
+
import { V as VisitorCookieOptions, d as ConsentState, x as XeniaConfig } from '../types-DgVHS4Qw.cjs';
|
|
3
|
+
import { X as XeniaServer } from '../xenia-server-C3O-cWQT.cjs';
|
|
4
|
+
import { j as ViewerGeo, T as TrailView, E as EdgeConsent, f as EdgeFacts, a as DecideOutcome, X as XeniaEdge, G as GeoHeader, h as ManifestKey, e as EdgeDecision, S as SwapGroup } from '../consent-DgWdjsSy.cjs';
|
|
5
|
+
import '../api-0IycTYJR.cjs';
|
|
6
|
+
import '../personalize-content-ghZPKlf1.cjs';
|
|
7
|
+
|
|
8
|
+
/** Request header the proxy stamps with the URL being served (a Server Component can't see its own). */
|
|
9
|
+
declare const URL_HEADER = "x-xenia-url";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The edge decide flow in one proxy call: which page views need Xenia, the facts Xenia decides on,
|
|
13
|
+
* and the rewrite to the variant page. Every failure ends in base content.
|
|
14
|
+
*
|
|
15
|
+
* Cost per request:
|
|
16
|
+
* - page no journey targets → an in-memory manifest lookup, no Xenia call
|
|
17
|
+
* - targeted page, returning visitor → an in-memory decision-cache hit
|
|
18
|
+
* - targeted page, first view this session → one `/decide` call, capped at the budget
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/** What the proxy knows about this page view. `prepare` may change the fields marked so. */
|
|
22
|
+
interface EdgeRequestContext {
|
|
23
|
+
request: NextRequest;
|
|
24
|
+
host: string | null;
|
|
25
|
+
path: string;
|
|
26
|
+
/** The visitor this view is decided for (changeable in `prepare`, e.g. a profile's own visitor). */
|
|
27
|
+
visitorId: string;
|
|
28
|
+
/** The visitor cookie the browser sent, if any. */
|
|
29
|
+
existingVisitorId?: string;
|
|
30
|
+
/** Where the visitor is (changeable in `prepare`, e.g. a QA city). */
|
|
31
|
+
geo?: ViewerGeo;
|
|
32
|
+
/** Which source supplied `geo` (see `viewerGeo`). */
|
|
33
|
+
geoVia: string;
|
|
34
|
+
/** While a QA city stands in for `geo`: what the edge really detected (for the debug panel). */
|
|
35
|
+
detectedGeo?: ViewerGeo;
|
|
36
|
+
device: "mobile" | "tablet" | "desktop";
|
|
37
|
+
/** First-touch campaign and referrer (changeable in `prepare`). */
|
|
38
|
+
landing: Record<string, string>;
|
|
39
|
+
/** Recent views before this one (changeable in `prepare`). */
|
|
40
|
+
previousTrail: TrailView[];
|
|
41
|
+
/** The trail with this view first — set after `prepare`. */
|
|
42
|
+
trail: TrailView[];
|
|
43
|
+
consent: EdgeConsent;
|
|
44
|
+
/** "Now" for local-time facts: the real time, or a QA date (changeable in `prepare`). */
|
|
45
|
+
now: Date;
|
|
46
|
+
}
|
|
47
|
+
/** `error`: something threw (a hook, the edge client) — base content was served. */
|
|
48
|
+
type EdgeExit = "skipped" | "not-targeted" | "no-consent" | "decided" | "error";
|
|
49
|
+
interface EdgeDecisionInfo<S = unknown> {
|
|
50
|
+
ctx: EdgeRequestContext;
|
|
51
|
+
exit: EdgeExit;
|
|
52
|
+
/** The facts sent to `/decide` (standard ones with the site's on top); absent when skipped. */
|
|
53
|
+
facts?: EdgeFacts;
|
|
54
|
+
outcome?: DecideOutcome;
|
|
55
|
+
side?: S;
|
|
56
|
+
/** The response about to be returned — set cookies on it here. */
|
|
57
|
+
response: NextResponse;
|
|
58
|
+
}
|
|
59
|
+
interface XeniaEdgeProxyOptions<S = unknown> {
|
|
60
|
+
/** One client per instance: `createXeniaEdge(…)` from `/edge`. */
|
|
61
|
+
edge: XeniaEdge;
|
|
62
|
+
/** Server-only secret the variant token is signed with. */
|
|
63
|
+
variantSecret: string;
|
|
64
|
+
/** Where variant pages live. Default `/xv` (`/xv/<token>/women`). */
|
|
65
|
+
variantPrefix?: string;
|
|
66
|
+
/** Must match the browser client's `config.prefix`, if you set one. */
|
|
67
|
+
prefix?: string;
|
|
68
|
+
cookie?: VisitorCookieOptions;
|
|
69
|
+
/**
|
|
70
|
+
* The location headers your host (or edge function) sets and overwrites, e.g.
|
|
71
|
+
* `["x-vercel-ip-country"]` — see `viewerGeo`. Default none: a visitor can send any header.
|
|
72
|
+
*/
|
|
73
|
+
geoHeaders?: readonly GeoHeader[];
|
|
74
|
+
/** Treat `Sec-GPC` / `DNT` as analytics off. Default true. */
|
|
75
|
+
respectDnt?: boolean;
|
|
76
|
+
/** Paths with no variant page (app routes): their views join the trail, but they're never decided. */
|
|
77
|
+
skip?: (path: string) => boolean;
|
|
78
|
+
/** Adjust the context before facts are built: the visitor, geo, landing or earlier trail. */
|
|
79
|
+
prepare?: (ctx: EdgeRequestContext) => void | Promise<void>;
|
|
80
|
+
/** The site's own facts, on top of the standard ones. */
|
|
81
|
+
facts?: (ctx: EdgeRequestContext) => EdgeFacts | Promise<EdgeFacts>;
|
|
82
|
+
/** What else makes this visitor's decision different (a new value → a fresh decision). */
|
|
83
|
+
cacheFacts?: (ctx: EdgeRequestContext) => EdgeFacts | Promise<EdgeFacts>;
|
|
84
|
+
/** This view's `/decide` budget, instead of the client's (e.g. a journey that calls a back office). */
|
|
85
|
+
budgetMs?: (ctx: EdgeRequestContext) => number | undefined;
|
|
86
|
+
/** Work started before `/decide` and awaited after it; its result reaches the hooks below as `side`. */
|
|
87
|
+
alongside?: (ctx: EdgeRequestContext, keys: ManifestKey[]) => Promise<S>;
|
|
88
|
+
filterDecisions?: (decisions: EdgeDecision[], ctx: EdgeRequestContext, side: S | undefined, outcome: DecideOutcome) => EdgeDecision[];
|
|
89
|
+
/**
|
|
90
|
+
* Where to render this view: a URL to rewrite to, `null` for the page itself, `undefined` for the
|
|
91
|
+
* default (the signed variant page when anything was swapped). Called on every exit but `skipped`;
|
|
92
|
+
* `outcome` is absent when Xenia wasn't asked.
|
|
93
|
+
*/
|
|
94
|
+
rewrite?: (ctx: EdgeRequestContext, groups: SwapGroup[], side: S | undefined, outcome: DecideOutcome | undefined) => URL | null | undefined | Promise<URL | null | undefined>;
|
|
95
|
+
/** Carried in the variant token beside the swaps (left out if it would make the token too long). */
|
|
96
|
+
extra?: (ctx: EdgeRequestContext, side: S | undefined, outcome: DecideOutcome) => unknown;
|
|
97
|
+
/** Called on every exit, with the response about to be returned. */
|
|
98
|
+
onDecision?: (info: EdgeDecisionInfo<S>) => void | Promise<void>;
|
|
99
|
+
/** Anything that threw on the way (base content was served instead). Default: nothing. */
|
|
100
|
+
onError?: (error: unknown) => void;
|
|
101
|
+
/**
|
|
102
|
+
* Write what was decided for each page to the `<prefix>_debug` cookie `<XeniaDebugPanel>` reads.
|
|
103
|
+
* For development and QA only — turn it on with `process.env.NODE_ENV === "development"` or a flag.
|
|
104
|
+
*/
|
|
105
|
+
debug?: boolean;
|
|
106
|
+
/** Fields of your own for the panel (or replacements for the SDK's), per page view. */
|
|
107
|
+
debugInfo?: (info: EdgeDecisionInfo<S>) => Record<string, unknown>;
|
|
108
|
+
/**
|
|
109
|
+
* QA overrides for development and QA only: `?xn_geo=<city>` (`QA_CITIES`, or your own `cities`),
|
|
110
|
+
* `?xn_date=YYYY-MM-DD`, `?xn_geo=off` to forget them, and `?xn_country=GB` under `next dev`.
|
|
111
|
+
*/
|
|
112
|
+
qa?: boolean | {
|
|
113
|
+
cities?: Record<string, ViewerGeo>;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Next.js `proxy.ts`/`middleware.ts` step for edge personalization: ensures the visitor cookie
|
|
118
|
+
* (like `xeniaProxy()`), keeps the landing campaign and page trail, decides targeted pages with
|
|
119
|
+
* Xenia within the budget and rewrites a personalized view to its signed variant page
|
|
120
|
+
* (`decodeVariant` there). Respects consent (see `edgeConsent`).
|
|
121
|
+
*
|
|
122
|
+
* ```ts
|
|
123
|
+
* const edge = createXeniaEdge({ baseUrl, token: process.env.XENIA_SDK_TOKEN! });
|
|
124
|
+
* export const proxy = (request: NextRequest) =>
|
|
125
|
+
* xeniaEdgeProxy(request, { edge, variantSecret: process.env.XENIA_VARIANT_SECRET! });
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
declare function xeniaEdgeProxy<S = unknown>(request: NextRequest, opts: XeniaEdgeProxyOptions<S>): Promise<NextResponse>;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* `GET` for a public, CDN-cached copy of the manifest (version + targeted page patterns only — no
|
|
132
|
+
* content keys or rules), so a cold proxy instance reads it from the nearby CDN instead of waiting on
|
|
133
|
+
* Xenia, and the server token never leaves the server. Point the edge client's `manifestUrl` at it.
|
|
134
|
+
* At build time an unreachable Xenia serves an empty manifest instead of failing the deploy; at
|
|
135
|
+
* runtime it throws, so the cache keeps the last good copy.
|
|
136
|
+
*
|
|
137
|
+
* ```ts
|
|
138
|
+
* // app/api/xenia/manifest/route.ts
|
|
139
|
+
* export const revalidate = 36000; // a safety net — the storefront webhook regenerates it at once
|
|
140
|
+
* export const GET = createManifestRoute({ token: process.env.XENIA_SDK_TOKEN, revalidate });
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
declare function createManifestRoute(opts: {
|
|
144
|
+
token?: string;
|
|
145
|
+
baseUrl?: string;
|
|
146
|
+
revalidate?: number;
|
|
147
|
+
}): () => Promise<Response>;
|
|
148
|
+
/**
|
|
149
|
+
* `POST` for Xenia's storefront webhook (Journey Orchestrator → Storefront webhook): verifies the
|
|
150
|
+
* signature (`verifyWebhook`), answers `ping`, and on `manifest.changed` regenerates `paths` (the
|
|
151
|
+
* manifest route) at once, then runs `onManifestChanged` (e.g. a rebuild hook) and merges what it
|
|
152
|
+
* returns into the response.
|
|
153
|
+
*/
|
|
154
|
+
declare function createRevalidateRoute(opts: {
|
|
155
|
+
secret?: string;
|
|
156
|
+
paths: string[];
|
|
157
|
+
onManifestChanged?: () => Promise<Record<string, unknown>> | Record<string, unknown>;
|
|
158
|
+
}): (request: Request) => Promise<Response>;
|
|
159
|
+
|
|
160
|
+
/** One page's entry in the edge debug cookie (written by `xeniaEdgeProxy({ debug })`, read by `<XeniaDebugPanel>`). */
|
|
161
|
+
type DebugEntry = Record<string, unknown> & {
|
|
162
|
+
page: string;
|
|
163
|
+
};
|
|
164
|
+
/** The debug cookie's pages (it may arrive encoded once or twice); anything unreadable is none. */
|
|
165
|
+
declare function readDebugEntries(raw: string | undefined | null): Record<string, DebugEntry>;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* QA and debugging for the edge flow (`xeniaEdgeProxy`'s `qa` and `debug` options):
|
|
169
|
+
* - QA overrides: `?xn_geo=<city>` places the visitor in a QA city, `?xn_date=YYYY-MM-DD` decides
|
|
170
|
+
* as of that day (midday in the US), `?xn_geo=off` forgets them; kept for the visit in a cookie;
|
|
171
|
+
* - the debug cookie: what was decided for each of the last few pages, read by `<XeniaDebugPanel>`.
|
|
172
|
+
* A cookie rather than the HTML, because variant pages are cached and shared.
|
|
173
|
+
*/
|
|
174
|
+
|
|
175
|
+
/** Cities a QA visitor can be placed in, with what an edge would report for them. */
|
|
176
|
+
declare const QA_CITIES: Record<string, ViewerGeo>;
|
|
177
|
+
interface QaState {
|
|
178
|
+
geo?: string;
|
|
179
|
+
date?: string;
|
|
180
|
+
}
|
|
5
181
|
|
|
6
182
|
/**
|
|
7
183
|
* `@xenia-martech/sdk-js/next` — Next.js (App Router, 15+) glue for the server SDK.
|
|
@@ -13,8 +189,6 @@ import '../api-BEPW0Uan.cjs';
|
|
|
13
189
|
* visitor id).
|
|
14
190
|
*/
|
|
15
191
|
|
|
16
|
-
/** Request header `xeniaProxy()` stamps with the URL being served. */
|
|
17
|
-
declare const URL_HEADER = "x-xenia-url";
|
|
18
192
|
interface XeniaProxyOptions {
|
|
19
193
|
/** Request headers to forward (e.g. your own additions); defaults to the incoming ones. */
|
|
20
194
|
headers?: Headers;
|
|
@@ -71,4 +245,4 @@ declare function consentFromNext(prefix?: string): Promise<ConsentState>;
|
|
|
71
245
|
*/
|
|
72
246
|
declare function personalizeOnce<T>(key: string, personalize: () => Promise<T>): Promise<T>;
|
|
73
247
|
|
|
74
|
-
export { URL_HEADER, type XeniaProxyOptions, consentFromNext, personalizeOnce, xeniaProxy, xeniaServerFromNext };
|
|
248
|
+
export { type DebugEntry, type EdgeDecisionInfo, type EdgeExit, type EdgeRequestContext, QA_CITIES, type QaState, URL_HEADER, type XeniaEdgeProxyOptions, type XeniaProxyOptions, consentFromNext, createManifestRoute, createRevalidateRoute, personalizeOnce, readDebugEntries, xeniaEdgeProxy, xeniaProxy, xeniaServerFromNext };
|
package/dist/next/index.d.ts
CHANGED
|
@@ -1,7 +1,183 @@
|
|
|
1
1
|
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
-
import { V as VisitorCookieOptions,
|
|
3
|
-
import { X as XeniaServer } from '../xenia-server-
|
|
4
|
-
import '../
|
|
2
|
+
import { V as VisitorCookieOptions, d as ConsentState, x as XeniaConfig } from '../types-DgVHS4Qw.js';
|
|
3
|
+
import { X as XeniaServer } from '../xenia-server-DV8Sjmoo.js';
|
|
4
|
+
import { j as ViewerGeo, T as TrailView, E as EdgeConsent, f as EdgeFacts, a as DecideOutcome, X as XeniaEdge, G as GeoHeader, h as ManifestKey, e as EdgeDecision, S as SwapGroup } from '../consent-Cemn91j3.js';
|
|
5
|
+
import '../api-COXWLL5L.js';
|
|
6
|
+
import '../personalize-content-c2DDAV6g.js';
|
|
7
|
+
|
|
8
|
+
/** Request header the proxy stamps with the URL being served (a Server Component can't see its own). */
|
|
9
|
+
declare const URL_HEADER = "x-xenia-url";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The edge decide flow in one proxy call: which page views need Xenia, the facts Xenia decides on,
|
|
13
|
+
* and the rewrite to the variant page. Every failure ends in base content.
|
|
14
|
+
*
|
|
15
|
+
* Cost per request:
|
|
16
|
+
* - page no journey targets → an in-memory manifest lookup, no Xenia call
|
|
17
|
+
* - targeted page, returning visitor → an in-memory decision-cache hit
|
|
18
|
+
* - targeted page, first view this session → one `/decide` call, capped at the budget
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/** What the proxy knows about this page view. `prepare` may change the fields marked so. */
|
|
22
|
+
interface EdgeRequestContext {
|
|
23
|
+
request: NextRequest;
|
|
24
|
+
host: string | null;
|
|
25
|
+
path: string;
|
|
26
|
+
/** The visitor this view is decided for (changeable in `prepare`, e.g. a profile's own visitor). */
|
|
27
|
+
visitorId: string;
|
|
28
|
+
/** The visitor cookie the browser sent, if any. */
|
|
29
|
+
existingVisitorId?: string;
|
|
30
|
+
/** Where the visitor is (changeable in `prepare`, e.g. a QA city). */
|
|
31
|
+
geo?: ViewerGeo;
|
|
32
|
+
/** Which source supplied `geo` (see `viewerGeo`). */
|
|
33
|
+
geoVia: string;
|
|
34
|
+
/** While a QA city stands in for `geo`: what the edge really detected (for the debug panel). */
|
|
35
|
+
detectedGeo?: ViewerGeo;
|
|
36
|
+
device: "mobile" | "tablet" | "desktop";
|
|
37
|
+
/** First-touch campaign and referrer (changeable in `prepare`). */
|
|
38
|
+
landing: Record<string, string>;
|
|
39
|
+
/** Recent views before this one (changeable in `prepare`). */
|
|
40
|
+
previousTrail: TrailView[];
|
|
41
|
+
/** The trail with this view first — set after `prepare`. */
|
|
42
|
+
trail: TrailView[];
|
|
43
|
+
consent: EdgeConsent;
|
|
44
|
+
/** "Now" for local-time facts: the real time, or a QA date (changeable in `prepare`). */
|
|
45
|
+
now: Date;
|
|
46
|
+
}
|
|
47
|
+
/** `error`: something threw (a hook, the edge client) — base content was served. */
|
|
48
|
+
type EdgeExit = "skipped" | "not-targeted" | "no-consent" | "decided" | "error";
|
|
49
|
+
interface EdgeDecisionInfo<S = unknown> {
|
|
50
|
+
ctx: EdgeRequestContext;
|
|
51
|
+
exit: EdgeExit;
|
|
52
|
+
/** The facts sent to `/decide` (standard ones with the site's on top); absent when skipped. */
|
|
53
|
+
facts?: EdgeFacts;
|
|
54
|
+
outcome?: DecideOutcome;
|
|
55
|
+
side?: S;
|
|
56
|
+
/** The response about to be returned — set cookies on it here. */
|
|
57
|
+
response: NextResponse;
|
|
58
|
+
}
|
|
59
|
+
interface XeniaEdgeProxyOptions<S = unknown> {
|
|
60
|
+
/** One client per instance: `createXeniaEdge(…)` from `/edge`. */
|
|
61
|
+
edge: XeniaEdge;
|
|
62
|
+
/** Server-only secret the variant token is signed with. */
|
|
63
|
+
variantSecret: string;
|
|
64
|
+
/** Where variant pages live. Default `/xv` (`/xv/<token>/women`). */
|
|
65
|
+
variantPrefix?: string;
|
|
66
|
+
/** Must match the browser client's `config.prefix`, if you set one. */
|
|
67
|
+
prefix?: string;
|
|
68
|
+
cookie?: VisitorCookieOptions;
|
|
69
|
+
/**
|
|
70
|
+
* The location headers your host (or edge function) sets and overwrites, e.g.
|
|
71
|
+
* `["x-vercel-ip-country"]` — see `viewerGeo`. Default none: a visitor can send any header.
|
|
72
|
+
*/
|
|
73
|
+
geoHeaders?: readonly GeoHeader[];
|
|
74
|
+
/** Treat `Sec-GPC` / `DNT` as analytics off. Default true. */
|
|
75
|
+
respectDnt?: boolean;
|
|
76
|
+
/** Paths with no variant page (app routes): their views join the trail, but they're never decided. */
|
|
77
|
+
skip?: (path: string) => boolean;
|
|
78
|
+
/** Adjust the context before facts are built: the visitor, geo, landing or earlier trail. */
|
|
79
|
+
prepare?: (ctx: EdgeRequestContext) => void | Promise<void>;
|
|
80
|
+
/** The site's own facts, on top of the standard ones. */
|
|
81
|
+
facts?: (ctx: EdgeRequestContext) => EdgeFacts | Promise<EdgeFacts>;
|
|
82
|
+
/** What else makes this visitor's decision different (a new value → a fresh decision). */
|
|
83
|
+
cacheFacts?: (ctx: EdgeRequestContext) => EdgeFacts | Promise<EdgeFacts>;
|
|
84
|
+
/** This view's `/decide` budget, instead of the client's (e.g. a journey that calls a back office). */
|
|
85
|
+
budgetMs?: (ctx: EdgeRequestContext) => number | undefined;
|
|
86
|
+
/** Work started before `/decide` and awaited after it; its result reaches the hooks below as `side`. */
|
|
87
|
+
alongside?: (ctx: EdgeRequestContext, keys: ManifestKey[]) => Promise<S>;
|
|
88
|
+
filterDecisions?: (decisions: EdgeDecision[], ctx: EdgeRequestContext, side: S | undefined, outcome: DecideOutcome) => EdgeDecision[];
|
|
89
|
+
/**
|
|
90
|
+
* Where to render this view: a URL to rewrite to, `null` for the page itself, `undefined` for the
|
|
91
|
+
* default (the signed variant page when anything was swapped). Called on every exit but `skipped`;
|
|
92
|
+
* `outcome` is absent when Xenia wasn't asked.
|
|
93
|
+
*/
|
|
94
|
+
rewrite?: (ctx: EdgeRequestContext, groups: SwapGroup[], side: S | undefined, outcome: DecideOutcome | undefined) => URL | null | undefined | Promise<URL | null | undefined>;
|
|
95
|
+
/** Carried in the variant token beside the swaps (left out if it would make the token too long). */
|
|
96
|
+
extra?: (ctx: EdgeRequestContext, side: S | undefined, outcome: DecideOutcome) => unknown;
|
|
97
|
+
/** Called on every exit, with the response about to be returned. */
|
|
98
|
+
onDecision?: (info: EdgeDecisionInfo<S>) => void | Promise<void>;
|
|
99
|
+
/** Anything that threw on the way (base content was served instead). Default: nothing. */
|
|
100
|
+
onError?: (error: unknown) => void;
|
|
101
|
+
/**
|
|
102
|
+
* Write what was decided for each page to the `<prefix>_debug` cookie `<XeniaDebugPanel>` reads.
|
|
103
|
+
* For development and QA only — turn it on with `process.env.NODE_ENV === "development"` or a flag.
|
|
104
|
+
*/
|
|
105
|
+
debug?: boolean;
|
|
106
|
+
/** Fields of your own for the panel (or replacements for the SDK's), per page view. */
|
|
107
|
+
debugInfo?: (info: EdgeDecisionInfo<S>) => Record<string, unknown>;
|
|
108
|
+
/**
|
|
109
|
+
* QA overrides for development and QA only: `?xn_geo=<city>` (`QA_CITIES`, or your own `cities`),
|
|
110
|
+
* `?xn_date=YYYY-MM-DD`, `?xn_geo=off` to forget them, and `?xn_country=GB` under `next dev`.
|
|
111
|
+
*/
|
|
112
|
+
qa?: boolean | {
|
|
113
|
+
cities?: Record<string, ViewerGeo>;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Next.js `proxy.ts`/`middleware.ts` step for edge personalization: ensures the visitor cookie
|
|
118
|
+
* (like `xeniaProxy()`), keeps the landing campaign and page trail, decides targeted pages with
|
|
119
|
+
* Xenia within the budget and rewrites a personalized view to its signed variant page
|
|
120
|
+
* (`decodeVariant` there). Respects consent (see `edgeConsent`).
|
|
121
|
+
*
|
|
122
|
+
* ```ts
|
|
123
|
+
* const edge = createXeniaEdge({ baseUrl, token: process.env.XENIA_SDK_TOKEN! });
|
|
124
|
+
* export const proxy = (request: NextRequest) =>
|
|
125
|
+
* xeniaEdgeProxy(request, { edge, variantSecret: process.env.XENIA_VARIANT_SECRET! });
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
declare function xeniaEdgeProxy<S = unknown>(request: NextRequest, opts: XeniaEdgeProxyOptions<S>): Promise<NextResponse>;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* `GET` for a public, CDN-cached copy of the manifest (version + targeted page patterns only — no
|
|
132
|
+
* content keys or rules), so a cold proxy instance reads it from the nearby CDN instead of waiting on
|
|
133
|
+
* Xenia, and the server token never leaves the server. Point the edge client's `manifestUrl` at it.
|
|
134
|
+
* At build time an unreachable Xenia serves an empty manifest instead of failing the deploy; at
|
|
135
|
+
* runtime it throws, so the cache keeps the last good copy.
|
|
136
|
+
*
|
|
137
|
+
* ```ts
|
|
138
|
+
* // app/api/xenia/manifest/route.ts
|
|
139
|
+
* export const revalidate = 36000; // a safety net — the storefront webhook regenerates it at once
|
|
140
|
+
* export const GET = createManifestRoute({ token: process.env.XENIA_SDK_TOKEN, revalidate });
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
declare function createManifestRoute(opts: {
|
|
144
|
+
token?: string;
|
|
145
|
+
baseUrl?: string;
|
|
146
|
+
revalidate?: number;
|
|
147
|
+
}): () => Promise<Response>;
|
|
148
|
+
/**
|
|
149
|
+
* `POST` for Xenia's storefront webhook (Journey Orchestrator → Storefront webhook): verifies the
|
|
150
|
+
* signature (`verifyWebhook`), answers `ping`, and on `manifest.changed` regenerates `paths` (the
|
|
151
|
+
* manifest route) at once, then runs `onManifestChanged` (e.g. a rebuild hook) and merges what it
|
|
152
|
+
* returns into the response.
|
|
153
|
+
*/
|
|
154
|
+
declare function createRevalidateRoute(opts: {
|
|
155
|
+
secret?: string;
|
|
156
|
+
paths: string[];
|
|
157
|
+
onManifestChanged?: () => Promise<Record<string, unknown>> | Record<string, unknown>;
|
|
158
|
+
}): (request: Request) => Promise<Response>;
|
|
159
|
+
|
|
160
|
+
/** One page's entry in the edge debug cookie (written by `xeniaEdgeProxy({ debug })`, read by `<XeniaDebugPanel>`). */
|
|
161
|
+
type DebugEntry = Record<string, unknown> & {
|
|
162
|
+
page: string;
|
|
163
|
+
};
|
|
164
|
+
/** The debug cookie's pages (it may arrive encoded once or twice); anything unreadable is none. */
|
|
165
|
+
declare function readDebugEntries(raw: string | undefined | null): Record<string, DebugEntry>;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* QA and debugging for the edge flow (`xeniaEdgeProxy`'s `qa` and `debug` options):
|
|
169
|
+
* - QA overrides: `?xn_geo=<city>` places the visitor in a QA city, `?xn_date=YYYY-MM-DD` decides
|
|
170
|
+
* as of that day (midday in the US), `?xn_geo=off` forgets them; kept for the visit in a cookie;
|
|
171
|
+
* - the debug cookie: what was decided for each of the last few pages, read by `<XeniaDebugPanel>`.
|
|
172
|
+
* A cookie rather than the HTML, because variant pages are cached and shared.
|
|
173
|
+
*/
|
|
174
|
+
|
|
175
|
+
/** Cities a QA visitor can be placed in, with what an edge would report for them. */
|
|
176
|
+
declare const QA_CITIES: Record<string, ViewerGeo>;
|
|
177
|
+
interface QaState {
|
|
178
|
+
geo?: string;
|
|
179
|
+
date?: string;
|
|
180
|
+
}
|
|
5
181
|
|
|
6
182
|
/**
|
|
7
183
|
* `@xenia-martech/sdk-js/next` — Next.js (App Router, 15+) glue for the server SDK.
|
|
@@ -13,8 +189,6 @@ import '../api-CktVQ6Gl.js';
|
|
|
13
189
|
* visitor id).
|
|
14
190
|
*/
|
|
15
191
|
|
|
16
|
-
/** Request header `xeniaProxy()` stamps with the URL being served. */
|
|
17
|
-
declare const URL_HEADER = "x-xenia-url";
|
|
18
192
|
interface XeniaProxyOptions {
|
|
19
193
|
/** Request headers to forward (e.g. your own additions); defaults to the incoming ones. */
|
|
20
194
|
headers?: Headers;
|
|
@@ -71,4 +245,4 @@ declare function consentFromNext(prefix?: string): Promise<ConsentState>;
|
|
|
71
245
|
*/
|
|
72
246
|
declare function personalizeOnce<T>(key: string, personalize: () => Promise<T>): Promise<T>;
|
|
73
247
|
|
|
74
|
-
export { URL_HEADER, type XeniaProxyOptions, consentFromNext, personalizeOnce, xeniaProxy, xeniaServerFromNext };
|
|
248
|
+
export { type DebugEntry, type EdgeDecisionInfo, type EdgeExit, type EdgeRequestContext, QA_CITIES, type QaState, URL_HEADER, type XeniaEdgeProxyOptions, type XeniaProxyOptions, consentFromNext, createManifestRoute, createRevalidateRoute, personalizeOnce, readDebugEntries, xeniaEdgeProxy, xeniaProxy, xeniaServerFromNext };
|