@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.
Files changed (82) hide show
  1. package/README.md +112 -3
  2. package/dist/{actions-BcdlokGO.d.cts → actions-C18Kv-4w.d.cts} +50 -2
  3. package/dist/{actions-BcdlokGO.d.ts → actions-C18Kv-4w.d.ts} +50 -2
  4. package/dist/{api-CktVQ6Gl.d.ts → api-0IycTYJR.d.cts} +4 -2
  5. package/dist/{api-BEPW0Uan.d.cts → api-COXWLL5L.d.ts} +4 -2
  6. package/dist/{chunk-3PYPPIUM.cjs → chunk-2DR5AVPX.cjs} +11 -46
  7. package/dist/chunk-2DR5AVPX.cjs.map +1 -0
  8. package/dist/chunk-BQ5PJCZ7.js +179 -0
  9. package/dist/chunk-BQ5PJCZ7.js.map +1 -0
  10. package/dist/{chunk-DWFVDNU5.js → chunk-GWRDZIVA.js} +5 -37
  11. package/dist/chunk-GWRDZIVA.js.map +1 -0
  12. package/dist/{chunk-7NGJC7CF.js → chunk-LW5AEJ6K.js} +20 -183
  13. package/dist/chunk-LW5AEJ6K.js.map +1 -0
  14. package/dist/chunk-N5M4PI7C.cjs +192 -0
  15. package/dist/chunk-N5M4PI7C.cjs.map +1 -0
  16. package/dist/chunk-OMMIRSPK.js +336 -0
  17. package/dist/chunk-OMMIRSPK.js.map +1 -0
  18. package/dist/chunk-QEYONKWY.js +42 -0
  19. package/dist/chunk-QEYONKWY.js.map +1 -0
  20. package/dist/{chunk-IBNIRT7J.cjs → chunk-RWE2OCQL.cjs} +20 -194
  21. package/dist/chunk-RWE2OCQL.cjs.map +1 -0
  22. package/dist/chunk-WHGK55JP.cjs +46 -0
  23. package/dist/chunk-WHGK55JP.cjs.map +1 -0
  24. package/dist/chunk-YLMMTKQL.cjs +358 -0
  25. package/dist/chunk-YLMMTKQL.cjs.map +1 -0
  26. package/dist/client/index.cjs +320 -31
  27. package/dist/client/index.cjs.map +1 -1
  28. package/dist/client/index.d.cts +15 -4
  29. package/dist/client/index.d.ts +15 -4
  30. package/dist/client/index.js +320 -31
  31. package/dist/client/index.js.map +1 -1
  32. package/dist/client/react/index.cjs +731 -34
  33. package/dist/client/react/index.cjs.map +1 -1
  34. package/dist/client/react/index.d.cts +32 -3
  35. package/dist/client/react/index.d.ts +32 -3
  36. package/dist/client/react/index.js +732 -37
  37. package/dist/client/react/index.js.map +1 -1
  38. package/dist/cms/contentful.cjs +2 -1
  39. package/dist/cms/contentful.cjs.map +1 -1
  40. package/dist/cms/contentful.d.cts +2 -1
  41. package/dist/cms/contentful.d.ts +2 -1
  42. package/dist/cms/contentful.js +2 -1
  43. package/dist/cms/contentful.js.map +1 -1
  44. package/dist/consent-Cemn91j3.d.ts +248 -0
  45. package/dist/consent-DgWdjsSy.d.cts +248 -0
  46. package/dist/{cookie-names-CLqtmGBM.d.ts → cookie-names-BvUaW3uo.d.ts} +1 -1
  47. package/dist/{cookie-names-BACctagz.d.cts → cookie-names-CnL65Oly.d.cts} +1 -1
  48. package/dist/edge/index.cjs +280 -0
  49. package/dist/edge/index.cjs.map +1 -0
  50. package/dist/edge/index.d.cts +61 -0
  51. package/dist/edge/index.d.ts +61 -0
  52. package/dist/edge/index.js +191 -0
  53. package/dist/edge/index.js.map +1 -0
  54. package/dist/index.cjs +41 -40
  55. package/dist/index.d.cts +5 -4
  56. package/dist/index.d.ts +5 -4
  57. package/dist/index.js +2 -1
  58. package/dist/next/index.cjs +320 -15
  59. package/dist/next/index.cjs.map +1 -1
  60. package/dist/next/index.d.cts +180 -6
  61. package/dist/next/index.d.ts +180 -6
  62. package/dist/next/index.js +309 -9
  63. package/dist/next/index.js.map +1 -1
  64. package/dist/personalize-content-c2DDAV6g.d.ts +140 -0
  65. package/dist/personalize-content-ghZPKlf1.d.cts +140 -0
  66. package/dist/server/index.cjs +34 -32
  67. package/dist/server/index.cjs.map +1 -1
  68. package/dist/server/index.d.cts +6 -5
  69. package/dist/server/index.d.ts +6 -5
  70. package/dist/server/index.js +5 -3
  71. package/dist/server/index.js.map +1 -1
  72. package/dist/{personalize-content-Clc1oMYY.d.ts → types-DgVHS4Qw.d.cts} +7 -127
  73. package/dist/{personalize-content-Clc1oMYY.d.cts → types-DgVHS4Qw.d.ts} +7 -127
  74. package/dist/xenia-sdk.iife.js +3 -3
  75. package/dist/xenia-sdk.iife.js.map +1 -1
  76. package/dist/{xenia-server-o_wDOcei.d.cts → xenia-server-C3O-cWQT.d.cts} +3 -2
  77. package/dist/{xenia-server-BWhWD0La.d.ts → xenia-server-DV8Sjmoo.d.ts} +3 -2
  78. package/package.json +14 -1
  79. package/dist/chunk-3PYPPIUM.cjs.map +0 -1
  80. package/dist/chunk-7NGJC7CF.js.map +0 -1
  81. package/dist/chunk-DWFVDNU5.js.map +0 -1
  82. package/dist/chunk-IBNIRT7J.cjs.map +0 -1
@@ -81,7 +81,8 @@ function parseMarker(raw) {
81
81
  kind: m.kind,
82
82
  op: OPS.has(m.op) ? m.op : "replace",
83
83
  field: typeof m.field === "string" && m.field ? m.field : void 0,
84
- limit: typeof m.limit === "number" ? m.limit : void 0
84
+ limit: typeof m.limit === "number" ? m.limit : void 0,
85
+ keys: Array.isArray(m.keys) ? m.keys.filter((k) => typeof k === "string") : void 0
85
86
  };
86
87
  }
87
88
  function filterParam(f) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cms/contentful.ts"],"names":["res"],"mappings":"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","file":"contentful.cjs","sourcesContent":["/**\n * Contentful adapter for {@link personalizeContent}.\n *\n * Works with either a contentful.js client (`createClient(...)`, links resolved by the client) or\n * raw Content Delivery API credentials (links resolved here). Pages can be passed as an entry, an\n * array of entries, or a raw CDA collection response (`{ items, includes }`).\n *\n * Expects the two fields Xenia adds to personalized content types: `xenia` (JSON marker) and\n * `xeniaVariants` (references, static replacements only). Single-locale payloads only — don't\n * fetch with `withAllLocales` / `locale=*`.\n */\n\nimport type { CmsAdapter, XeniaMarker } from \"../core/personalize-content\";\nimport type { EntryFilter } from \"../core/types\";\n\n/** The subset of a contentful.js client this adapter calls. */\nexport interface ContentfulClientLike {\n getEntries(query: Record<string, unknown>): Promise<{ items: unknown[]; includes?: unknown }>;\n}\n\nexport interface ContentfulAdapterOptions {\n /** A contentful.js client. Takes precedence over raw credentials. */\n client?: ContentfulClientLike;\n space?: string;\n accessToken?: string;\n environment?: string;\n /** `cdn.contentful.com` (default) or `preview.contentful.com`. */\n host?: string;\n /** Link depth fetched with pages and replacement entries (0-10). Default 4 — raise it for deeper pages. */\n include?: number;\n /** Marker field ids, if your content types name them differently. */\n markerField?: string;\n variantsField?: string;\n fetch?: typeof fetch;\n}\n\ntype Entry = { sys: { id: string; type: string; contentType?: unknown }; fields: Record<string, unknown> };\n\nconst KINDS = new Set([\"static\", \"runtime\"]);\nconst OPS = new Set([\"replace\", \"expand\", \"items\"]);\n\nexport function contentfulAdapter(options: ContentfulAdapterOptions = {}): CmsAdapter<Entry> {\n const markerField = options.markerField ?? \"xenia\";\n const variantsField = options.variantsField ?? \"xeniaVariants\";\n const include = options.include ?? 4;\n\n const getEntries = async (query: Record<string, unknown>, locale?: string): Promise<Entry[]> => {\n const q = { include, ...(locale ? { locale } : {}), ...query };\n if (options.client) {\n const res = await options.client.getEntries(q);\n return resolveCollection(res) as Entry[];\n }\n if (!options.space || !options.accessToken) {\n throw new Error(\"contentfulAdapter: pass `client` or `space` + `accessToken` to fetch replacements\");\n }\n const params = new URLSearchParams();\n for (const [k, v] of Object.entries(q)) if (v !== undefined) params.set(k, String(v));\n const url =\n `https://${options.host ?? \"cdn.contentful.com\"}/spaces/${encodeURIComponent(options.space)}` +\n `/environments/${encodeURIComponent(options.environment ?? \"master\")}/entries?${params}`;\n const res = await (options.fetch ?? fetch)(url, { headers: { Authorization: `Bearer ${options.accessToken}` } });\n if (!res.ok) throw new Error(`Contentful CDA ${res.status}`);\n return resolveCollection(await res.json()) as Entry[];\n };\n\n return {\n entryId(value) {\n const sys = (value as Entry | null)?.sys;\n return sys && sys.type === \"Entry\" && typeof sys.id === \"string\" ? sys.id : undefined;\n },\n\n marker(entry) {\n return parseMarker(entry.fields?.[markerField]);\n },\n\n staticVariants(entry) {\n const v = entry.fields?.[variantsField];\n return Array.isArray(v) ? v.filter((x): x is Entry => (x as Entry)?.sys?.type === \"Entry\") : [];\n },\n\n getField: (entry, field) => entry.fields?.[field],\n setField(entry, field, value) {\n entry.fields = entry.fields ?? {};\n entry.fields[field] = value;\n },\n\n mergeItems(entry, replacement) {\n for (const [key, value] of Object.entries(replacement.fields ?? {})) {\n if (Array.isArray(value)) entry.fields[key] = value;\n }\n },\n\n clearMarker(entry) {\n if (!entry.fields) return;\n delete entry.fields[markerField];\n delete entry.fields[variantsField];\n },\n\n prepare: (payload) => resolveCollection(payload, true),\n\n fetchEntries: (ids, locale) => getEntries({ \"sys.id[in]\": ids.join(\",\"), limit: ids.length }, locale),\n\n queryEntries(query, locale) {\n const q: Record<string, unknown> = { content_type: query.contentType, limit: query.limit };\n if (query.order) q.order = query.order;\n for (const f of query.filters ?? []) Object.assign(q, filterParam(f));\n return getEntries(q, locale);\n },\n\n async fetchPage(ref, locale) {\n const q: Record<string, unknown> =\n typeof ref === \"string\" ? { \"sys.id\": ref } : { content_type: ref.contentType };\n if (typeof ref !== \"string\") for (const [k, v] of Object.entries(ref.fields)) q[`fields.${k}`] = v;\n return (await getEntries({ ...q, limit: 1 }, locale))[0] ?? null;\n },\n };\n}\n\n/** Parse the `xenia` field (object, or its JSON text). Unknown shapes → not personalized. */\nexport function parseMarker(raw: unknown): XeniaMarker | null {\n let value = raw;\n if (typeof value === \"string\") {\n try {\n value = JSON.parse(value);\n } catch {\n return null;\n }\n }\n if (!value || typeof value !== \"object\") return null;\n const m = value as Record<string, unknown>;\n if (!KINDS.has(m.kind as string)) return null;\n return {\n kind: m.kind as XeniaMarker[\"kind\"],\n op: OPS.has(m.op as string) ? (m.op as XeniaMarker[\"op\"]) : \"replace\",\n field: typeof m.field === \"string\" && m.field ? m.field : undefined,\n limit: typeof m.limit === \"number\" ? m.limit : undefined,\n };\n}\n\n/** CMS-neutral filter → CDA query param (`fields.category[in]=a,b`). */\nfunction filterParam(f: EntryFilter): Record<string, string> {\n const path = /^(fields|sys|metadata)\\./.test(f.field) ? f.field : `fields.${f.field}`;\n const op = f.op ?? \"eq\";\n return { [op === \"eq\" ? path : `${path}[${op}]`]: f.value };\n}\n\n/**\n * Resolve CDA links in a raw collection response (`{ items, includes }`) into nested entries.\n * Shared entries become shared objects; a link back to an entry still being resolved (a cycle)\n * stays a link stub, so the result stays JSON-serializable (RSC props, caches). Anything that is\n * not a raw collection (an entry, an array, contentful.js output) is returned as-is. With\n * `asPage` the collection shape is kept (minus `includes`); otherwise just the resolved `items`.\n */\nexport function resolveCollection(payload: unknown, asPage = false): unknown {\n const p = payload as { items?: unknown[]; includes?: { Entry?: Entry[]; Asset?: unknown[] } } | null;\n if (!p || typeof p !== \"object\" || !Array.isArray(p.items)) return payload;\n if (!p.includes) return asPage ? payload : p.items;\n\n const index = new Map<string, unknown>();\n const key = (type: string, id: string) => `${type}:${id}`;\n for (const e of [...p.items, ...(p.includes.Entry ?? [])] as Entry[]) {\n if (e?.sys?.id) index.set(key(e.sys.type, e.sys.id), e);\n }\n for (const a of (p.includes.Asset ?? []) as Entry[]) if (a?.sys?.id) index.set(key(\"Asset\", a.sys.id), a);\n\n const done = new Map<unknown, unknown>();\n const inProgress = new Set<unknown>();\n\n const resolve = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(resolve);\n if (!value || typeof value !== \"object\") return value;\n const sys = (value as Entry).sys as { type?: string; linkType?: string; id?: string } | undefined;\n if (sys?.type === \"Link\" && sys.linkType && sys.id) {\n const target = index.get(key(sys.linkType, sys.id));\n if (!target || inProgress.has(target)) return value; // unresolvable or cyclic → keep the stub\n return resolveEntity(target);\n }\n if (sys && (sys.type === \"Entry\" || sys.type === \"Asset\")) return resolveEntity(value);\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value)) out[k] = resolve(v);\n return out;\n };\n\n const resolveEntity = (entity: unknown): unknown => {\n if (done.has(entity)) return done.get(entity);\n const e = entity as Entry;\n const copy: Entry = { ...e, fields: {} as Record<string, unknown> };\n done.set(entity, copy);\n inProgress.add(entity);\n for (const [k, v] of Object.entries(e.fields ?? {})) copy.fields[k] = resolve(v);\n inProgress.delete(entity);\n return copy;\n };\n\n const items = p.items.map(resolve);\n if (!asPage) return items;\n const { includes: _drop, ...rest } = p;\n return { ...rest, items };\n}\n\n"]}
1
+ {"version":3,"sources":["../../src/cms/contentful.ts"],"names":["res"],"mappings":"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","file":"contentful.cjs","sourcesContent":["/**\n * Contentful adapter for {@link personalizeContent}.\n *\n * Works with either a contentful.js client (`createClient(...)`, links resolved by the client) or\n * raw Content Delivery API credentials (links resolved here). Pages can be passed as an entry, an\n * array of entries, or a raw CDA collection response (`{ items, includes }`).\n *\n * Expects the two fields Xenia adds to personalized content types: `xenia` (JSON marker) and\n * `xeniaVariants` (references, static replacements only). Single-locale payloads only — don't\n * fetch with `withAllLocales` / `locale=*`.\n */\n\nimport type { CmsAdapter, XeniaMarker } from \"../core/personalize-content\";\nimport type { EntryFilter } from \"../core/types\";\n\n/** The subset of a contentful.js client this adapter calls. */\nexport interface ContentfulClientLike {\n getEntries(query: Record<string, unknown>): Promise<{ items: unknown[]; includes?: unknown }>;\n}\n\nexport interface ContentfulAdapterOptions {\n /** A contentful.js client. Takes precedence over raw credentials. */\n client?: ContentfulClientLike;\n space?: string;\n accessToken?: string;\n environment?: string;\n /** `cdn.contentful.com` (default) or `preview.contentful.com`. */\n host?: string;\n /** Link depth fetched with pages and replacement entries (0-10). Default 4 — raise it for deeper pages. */\n include?: number;\n /** Marker field ids, if your content types name them differently. */\n markerField?: string;\n variantsField?: string;\n fetch?: typeof fetch;\n}\n\ntype Entry = { sys: { id: string; type: string; contentType?: unknown }; fields: Record<string, unknown> };\n\nconst KINDS = new Set([\"static\", \"runtime\"]);\nconst OPS = new Set([\"replace\", \"expand\", \"items\"]);\n\nexport function contentfulAdapter(options: ContentfulAdapterOptions = {}): CmsAdapter<Entry> {\n const markerField = options.markerField ?? \"xenia\";\n const variantsField = options.variantsField ?? \"xeniaVariants\";\n const include = options.include ?? 4;\n\n const getEntries = async (query: Record<string, unknown>, locale?: string): Promise<Entry[]> => {\n const q = { include, ...(locale ? { locale } : {}), ...query };\n if (options.client) {\n const res = await options.client.getEntries(q);\n return resolveCollection(res) as Entry[];\n }\n if (!options.space || !options.accessToken) {\n throw new Error(\"contentfulAdapter: pass `client` or `space` + `accessToken` to fetch replacements\");\n }\n const params = new URLSearchParams();\n for (const [k, v] of Object.entries(q)) if (v !== undefined) params.set(k, String(v));\n const url =\n `https://${options.host ?? \"cdn.contentful.com\"}/spaces/${encodeURIComponent(options.space)}` +\n `/environments/${encodeURIComponent(options.environment ?? \"master\")}/entries?${params}`;\n const res = await (options.fetch ?? fetch)(url, { headers: { Authorization: `Bearer ${options.accessToken}` } });\n if (!res.ok) throw new Error(`Contentful CDA ${res.status}`);\n return resolveCollection(await res.json()) as Entry[];\n };\n\n return {\n entryId(value) {\n const sys = (value as Entry | null)?.sys;\n return sys && sys.type === \"Entry\" && typeof sys.id === \"string\" ? sys.id : undefined;\n },\n\n marker(entry) {\n return parseMarker(entry.fields?.[markerField]);\n },\n\n staticVariants(entry) {\n const v = entry.fields?.[variantsField];\n return Array.isArray(v) ? v.filter((x): x is Entry => (x as Entry)?.sys?.type === \"Entry\") : [];\n },\n\n getField: (entry, field) => entry.fields?.[field],\n setField(entry, field, value) {\n entry.fields = entry.fields ?? {};\n entry.fields[field] = value;\n },\n\n mergeItems(entry, replacement) {\n for (const [key, value] of Object.entries(replacement.fields ?? {})) {\n if (Array.isArray(value)) entry.fields[key] = value;\n }\n },\n\n clearMarker(entry) {\n if (!entry.fields) return;\n delete entry.fields[markerField];\n delete entry.fields[variantsField];\n },\n\n prepare: (payload) => resolveCollection(payload, true),\n\n fetchEntries: (ids, locale) => getEntries({ \"sys.id[in]\": ids.join(\",\"), limit: ids.length }, locale),\n\n queryEntries(query, locale) {\n const q: Record<string, unknown> = { content_type: query.contentType, limit: query.limit };\n if (query.order) q.order = query.order;\n for (const f of query.filters ?? []) Object.assign(q, filterParam(f));\n return getEntries(q, locale);\n },\n\n async fetchPage(ref, locale) {\n const q: Record<string, unknown> =\n typeof ref === \"string\" ? { \"sys.id\": ref } : { content_type: ref.contentType };\n if (typeof ref !== \"string\") for (const [k, v] of Object.entries(ref.fields)) q[`fields.${k}`] = v;\n return (await getEntries({ ...q, limit: 1 }, locale))[0] ?? null;\n },\n };\n}\n\n/** Parse the `xenia` field (object, or its JSON text). Unknown shapes → not personalized. */\nexport function parseMarker(raw: unknown): XeniaMarker | null {\n let value = raw;\n if (typeof value === \"string\") {\n try {\n value = JSON.parse(value);\n } catch {\n return null;\n }\n }\n if (!value || typeof value !== \"object\") return null;\n const m = value as Record<string, unknown>;\n if (!KINDS.has(m.kind as string)) return null;\n return {\n kind: m.kind as XeniaMarker[\"kind\"],\n op: OPS.has(m.op as string) ? (m.op as XeniaMarker[\"op\"]) : \"replace\",\n field: typeof m.field === \"string\" && m.field ? m.field : undefined,\n limit: typeof m.limit === \"number\" ? m.limit : undefined,\n keys: Array.isArray(m.keys) ? m.keys.filter((k): k is string => typeof k === \"string\") : undefined,\n };\n}\n\n/** CMS-neutral filter → CDA query param (`fields.category[in]=a,b`). */\nfunction filterParam(f: EntryFilter): Record<string, string> {\n const path = /^(fields|sys|metadata)\\./.test(f.field) ? f.field : `fields.${f.field}`;\n const op = f.op ?? \"eq\";\n return { [op === \"eq\" ? path : `${path}[${op}]`]: f.value };\n}\n\n/**\n * Resolve CDA links in a raw collection response (`{ items, includes }`) into nested entries.\n * Shared entries become shared objects; a link back to an entry still being resolved (a cycle)\n * stays a link stub, so the result stays JSON-serializable (RSC props, caches). Anything that is\n * not a raw collection (an entry, an array, contentful.js output) is returned as-is. With\n * `asPage` the collection shape is kept (minus `includes`); otherwise just the resolved `items`.\n */\nexport function resolveCollection(payload: unknown, asPage = false): unknown {\n const p = payload as { items?: unknown[]; includes?: { Entry?: Entry[]; Asset?: unknown[] } } | null;\n if (!p || typeof p !== \"object\" || !Array.isArray(p.items)) return payload;\n if (!p.includes) return asPage ? payload : p.items;\n\n const index = new Map<string, unknown>();\n const key = (type: string, id: string) => `${type}:${id}`;\n for (const e of [...p.items, ...(p.includes.Entry ?? [])] as Entry[]) {\n if (e?.sys?.id) index.set(key(e.sys.type, e.sys.id), e);\n }\n for (const a of (p.includes.Asset ?? []) as Entry[]) if (a?.sys?.id) index.set(key(\"Asset\", a.sys.id), a);\n\n const done = new Map<unknown, unknown>();\n const inProgress = new Set<unknown>();\n\n const resolve = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(resolve);\n if (!value || typeof value !== \"object\") return value;\n const sys = (value as Entry).sys as { type?: string; linkType?: string; id?: string } | undefined;\n if (sys?.type === \"Link\" && sys.linkType && sys.id) {\n const target = index.get(key(sys.linkType, sys.id));\n if (!target || inProgress.has(target)) return value; // unresolvable or cyclic → keep the stub\n return resolveEntity(target);\n }\n if (sys && (sys.type === \"Entry\" || sys.type === \"Asset\")) return resolveEntity(value);\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value)) out[k] = resolve(v);\n return out;\n };\n\n const resolveEntity = (entity: unknown): unknown => {\n if (done.has(entity)) return done.get(entity);\n const e = entity as Entry;\n const copy: Entry = { ...e, fields: {} as Record<string, unknown> };\n done.set(entity, copy);\n inProgress.add(entity);\n for (const [k, v] of Object.entries(e.fields ?? {})) copy.fields[k] = resolve(v);\n inProgress.delete(entity);\n return copy;\n };\n\n const items = p.items.map(resolve);\n if (!asPage) return items;\n const { includes: _drop, ...rest } = p;\n return { ...rest, items };\n}\n\n"]}
@@ -1,4 +1,5 @@
1
- import { C as CmsAdapter, X as XeniaMarker } from '../personalize-content-Clc1oMYY.cjs';
1
+ import { C as CmsAdapter, X as XeniaMarker } from '../personalize-content-ghZPKlf1.cjs';
2
+ import '../types-DgVHS4Qw.cjs';
2
3
 
3
4
  /**
4
5
  * Contentful adapter for {@link personalizeContent}.
@@ -1,4 +1,5 @@
1
- import { C as CmsAdapter, X as XeniaMarker } from '../personalize-content-Clc1oMYY.js';
1
+ import { C as CmsAdapter, X as XeniaMarker } from '../personalize-content-c2DDAV6g.js';
2
+ import '../types-DgVHS4Qw.js';
2
3
 
3
4
  /**
4
5
  * Contentful adapter for {@link personalizeContent}.
@@ -79,7 +79,8 @@ function parseMarker(raw) {
79
79
  kind: m.kind,
80
80
  op: OPS.has(m.op) ? m.op : "replace",
81
81
  field: typeof m.field === "string" && m.field ? m.field : void 0,
82
- limit: typeof m.limit === "number" ? m.limit : void 0
82
+ limit: typeof m.limit === "number" ? m.limit : void 0,
83
+ keys: Array.isArray(m.keys) ? m.keys.filter((k) => typeof k === "string") : void 0
83
84
  };
84
85
  }
85
86
  function filterParam(f) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cms/contentful.ts"],"names":["res"],"mappings":";AAsCA,IAAM,wBAAQ,IAAI,GAAA,CAAI,CAAC,QAAA,EAAU,SAAS,CAAC,CAAA;AAC3C,IAAM,sBAAM,IAAI,GAAA,CAAI,CAAC,SAAA,EAAW,QAAA,EAAU,OAAO,CAAC,CAAA;AAE3C,SAAS,iBAAA,CAAkB,OAAA,GAAoC,EAAC,EAAsB;AAC3F,EAAA,MAAM,WAAA,GAAc,QAAQ,WAAA,IAAe,OAAA;AAC3C,EAAA,MAAM,aAAA,GAAgB,QAAQ,aAAA,IAAiB,eAAA;AAC/C,EAAA,MAAM,OAAA,GAAU,QAAQ,OAAA,IAAW,CAAA;AAEnC,EAAA,MAAM,UAAA,GAAa,OAAO,KAAA,EAAgC,MAAA,KAAsC;AAC9F,IAAA,MAAM,CAAA,GAAI,EAAE,OAAA,EAAS,GAAI,MAAA,GAAS,EAAE,MAAA,EAAO,GAAI,EAAC,EAAI,GAAG,KAAA,EAAM;AAC7D,IAAA,IAAI,QAAQ,MAAA,EAAQ;AAClB,MAAA,MAAMA,IAAAA,GAAM,MAAM,OAAA,CAAQ,MAAA,CAAO,WAAW,CAAC,CAAA;AAC7C,MAAA,OAAO,kBAAkBA,IAAG,CAAA;AAAA,IAC9B;AACA,IAAA,IAAI,CAAC,OAAA,CAAQ,KAAA,IAAS,CAAC,QAAQ,WAAA,EAAa;AAC1C,MAAA,MAAM,IAAI,MAAM,mFAAmF,CAAA;AAAA,IACrG;AACA,IAAA,MAAM,MAAA,GAAS,IAAI,eAAA,EAAgB;AACnC,IAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,CAAA,IAAK,MAAA,CAAO,QAAQ,CAAC,CAAA,EAAG,IAAI,CAAA,KAAM,QAAW,MAAA,CAAO,GAAA,CAAI,CAAA,EAAG,MAAA,CAAO,CAAC,CAAC,CAAA;AACpF,IAAA,MAAM,MACJ,CAAA,QAAA,EAAW,OAAA,CAAQ,IAAA,IAAQ,oBAAoB,WAAW,kBAAA,CAAmB,OAAA,CAAQ,KAAK,CAAC,iBAC1E,kBAAA,CAAmB,OAAA,CAAQ,eAAe,QAAQ,CAAC,YAAY,MAAM,CAAA,CAAA;AACxF,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,OAAA,CAAQ,KAAA,IAAS,OAAO,GAAA,EAAK,EAAE,OAAA,EAAS,EAAE,eAAe,CAAA,OAAA,EAAU,OAAA,CAAQ,WAAW,CAAA,CAAA,IAAM,CAAA;AAC/G,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI,MAAM,IAAI,KAAA,CAAM,CAAA,eAAA,EAAkB,GAAA,CAAI,MAAM,CAAA,CAAE,CAAA;AAC3D,IAAA,OAAO,iBAAA,CAAkB,MAAM,GAAA,CAAI,IAAA,EAAM,CAAA;AAAA,EAC3C,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,QAAQ,KAAA,EAAO;AACb,MAAA,MAAM,MAAO,KAAA,EAAwB,GAAA;AACrC,MAAA,OAAO,GAAA,IAAO,IAAI,IAAA,KAAS,OAAA,IAAW,OAAO,GAAA,CAAI,EAAA,KAAO,QAAA,GAAW,GAAA,CAAI,EAAA,GAAK,MAAA;AAAA,IAC9E,CAAA;AAAA,IAEA,OAAO,KAAA,EAAO;AACZ,MAAA,OAAO,WAAA,CAAY,KAAA,CAAM,MAAA,GAAS,WAAW,CAAC,CAAA;AAAA,IAChD,CAAA;AAAA,IAEA,eAAe,KAAA,EAAO;AACpB,MAAA,MAAM,CAAA,GAAI,KAAA,CAAM,MAAA,GAAS,aAAa,CAAA;AACtC,MAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA,GAAI,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,KAAmB,CAAA,EAAa,GAAA,EAAK,IAAA,KAAS,OAAO,IAAI,EAAC;AAAA,IAChG,CAAA;AAAA,IAEA,UAAU,CAAC,KAAA,EAAO,KAAA,KAAU,KAAA,CAAM,SAAS,KAAK,CAAA;AAAA,IAChD,QAAA,CAAS,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO;AAC5B,MAAA,KAAA,CAAM,MAAA,GAAS,KAAA,CAAM,MAAA,IAAU,EAAC;AAChC,MAAA,KAAA,CAAM,MAAA,CAAO,KAAK,CAAA,GAAI,KAAA;AAAA,IACxB,CAAA;AAAA,IAEA,UAAA,CAAW,OAAO,WAAA,EAAa;AAC7B,MAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,CAAA,IAAK,MAAA,CAAO,QAAQ,WAAA,CAAY,MAAA,IAAU,EAAE,CAAA,EAAG;AACnE,QAAA,IAAI,MAAM,OAAA,CAAQ,KAAK,GAAG,KAAA,CAAM,MAAA,CAAO,GAAG,CAAA,GAAI,KAAA;AAAA,MAChD;AAAA,IACF,CAAA;AAAA,IAEA,YAAY,KAAA,EAAO;AACjB,MAAA,IAAI,CAAC,MAAM,MAAA,EAAQ;AACnB,MAAA,OAAO,KAAA,CAAM,OAAO,WAAW,CAAA;AAC/B,MAAA,OAAO,KAAA,CAAM,OAAO,aAAa,CAAA;AAAA,IACnC,CAAA;AAAA,IAEA,OAAA,EAAS,CAAC,OAAA,KAAY,iBAAA,CAAkB,SAAS,IAAI,CAAA;AAAA,IAErD,YAAA,EAAc,CAAC,GAAA,EAAK,MAAA,KAAW,WAAW,EAAE,YAAA,EAAc,GAAA,CAAI,IAAA,CAAK,GAAG,CAAA,EAAG,KAAA,EAAO,GAAA,CAAI,MAAA,IAAU,MAAM,CAAA;AAAA,IAEpG,YAAA,CAAa,OAAO,MAAA,EAAQ;AAC1B,MAAA,MAAM,IAA6B,EAAE,YAAA,EAAc,MAAM,WAAA,EAAa,KAAA,EAAO,MAAM,KAAA,EAAM;AACzF,MAAA,IAAI,KAAA,CAAM,KAAA,EAAO,CAAA,CAAE,KAAA,GAAQ,KAAA,CAAM,KAAA;AACjC,MAAA,KAAA,MAAW,CAAA,IAAK,KAAA,CAAM,OAAA,IAAW,EAAC,SAAU,MAAA,CAAO,CAAA,EAAG,WAAA,CAAY,CAAC,CAAC,CAAA;AACpE,MAAA,OAAO,UAAA,CAAW,GAAG,MAAM,CAAA;AAAA,IAC7B,CAAA;AAAA,IAEA,MAAM,SAAA,CAAU,GAAA,EAAK,MAAA,EAAQ;AAC3B,MAAA,MAAM,CAAA,GACJ,OAAO,GAAA,KAAQ,QAAA,GAAW,EAAE,QAAA,EAAU,GAAA,EAAI,GAAI,EAAE,YAAA,EAAc,GAAA,CAAI,WAAA,EAAY;AAChF,MAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,EAAU,KAAA,MAAW,CAAC,GAAG,CAAC,CAAA,IAAK,MAAA,CAAO,OAAA,CAAQ,IAAI,MAAM,CAAA,IAAK,CAAA,OAAA,EAAU,CAAC,EAAE,CAAA,GAAI,CAAA;AACjG,MAAA,OAAA,CAAQ,MAAM,UAAA,CAAW,EAAE,GAAG,CAAA,EAAG,KAAA,EAAO,CAAA,EAAE,EAAG,MAAM,CAAA,EAAG,CAAC,CAAA,IAAK,IAAA;AAAA,IAC9D;AAAA,GACF;AACF;AAGO,SAAS,YAAY,GAAA,EAAkC;AAC5D,EAAA,IAAI,KAAA,GAAQ,GAAA;AACZ,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,IAAI;AACF,MAAA,KAAA,GAAQ,IAAA,CAAK,MAAM,KAAK,CAAA;AAAA,IAC1B,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AACA,EAAA,IAAI,CAAC,KAAA,IAAS,OAAO,KAAA,KAAU,UAAU,OAAO,IAAA;AAChD,EAAA,MAAM,CAAA,GAAI,KAAA;AACV,EAAA,IAAI,CAAC,KAAA,CAAM,GAAA,CAAI,CAAA,CAAE,IAAc,GAAG,OAAO,IAAA;AACzC,EAAA,OAAO;AAAA,IACL,MAAM,CAAA,CAAE,IAAA;AAAA,IACR,IAAI,GAAA,CAAI,GAAA,CAAI,EAAE,EAAY,CAAA,GAAK,EAAE,EAAA,GAA2B,SAAA;AAAA,IAC5D,KAAA,EAAO,OAAO,CAAA,CAAE,KAAA,KAAU,YAAY,CAAA,CAAE,KAAA,GAAQ,EAAE,KAAA,GAAQ,MAAA;AAAA,IAC1D,OAAO,OAAO,CAAA,CAAE,KAAA,KAAU,QAAA,GAAW,EAAE,KAAA,GAAQ;AAAA,GACjD;AACF;AAGA,SAAS,YAAY,CAAA,EAAwC;AAC3D,EAAA,MAAM,IAAA,GAAO,0BAAA,CAA2B,IAAA,CAAK,CAAA,CAAE,KAAK,IAAI,CAAA,CAAE,KAAA,GAAQ,CAAA,OAAA,EAAU,CAAA,CAAE,KAAK,CAAA,CAAA;AACnF,EAAA,MAAM,EAAA,GAAK,EAAE,EAAA,IAAM,IAAA;AACnB,EAAA,OAAO,EAAE,CAAC,EAAA,KAAO,IAAA,GAAO,IAAA,GAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,EAAE,CAAA,CAAA,CAAG,GAAG,CAAA,CAAE,KAAA,EAAM;AAC5D;AASO,SAAS,iBAAA,CAAkB,OAAA,EAAkB,MAAA,GAAS,KAAA,EAAgB;AAC3E,EAAA,MAAM,CAAA,GAAI,OAAA;AACV,EAAA,IAAI,CAAC,CAAA,IAAK,OAAO,CAAA,KAAM,QAAA,IAAY,CAAC,KAAA,CAAM,OAAA,CAAQ,CAAA,CAAE,KAAK,CAAA,EAAG,OAAO,OAAA;AACnE,EAAA,IAAI,CAAC,CAAA,CAAE,QAAA,EAAU,OAAO,MAAA,GAAS,UAAU,CAAA,CAAE,KAAA;AAE7C,EAAA,MAAM,KAAA,uBAAY,GAAA,EAAqB;AACvC,EAAA,MAAM,MAAM,CAAC,IAAA,EAAc,OAAe,CAAA,EAAG,IAAI,IAAI,EAAE,CAAA,CAAA;AACvD,EAAA,KAAA,MAAW,CAAA,IAAK,CAAC,GAAG,CAAA,CAAE,KAAA,EAAO,GAAI,CAAA,CAAE,QAAA,CAAS,KAAA,IAAS,EAAG,CAAA,EAAc;AACpE,IAAA,IAAI,CAAA,EAAG,GAAA,EAAK,EAAA,EAAI,KAAA,CAAM,GAAA,CAAI,GAAA,CAAI,CAAA,CAAE,GAAA,CAAI,IAAA,EAAM,CAAA,CAAE,GAAA,CAAI,EAAE,GAAG,CAAC,CAAA;AAAA,EACxD;AACA,EAAA,KAAA,MAAW,KAAM,CAAA,CAAE,QAAA,CAAS,SAAS,EAAC,MAAmB,CAAA,EAAG,GAAA,EAAK,EAAA,EAAI,KAAA,CAAM,IAAI,GAAA,CAAI,OAAA,EAAS,EAAE,GAAA,CAAI,EAAE,GAAG,CAAC,CAAA;AAExG,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAsB;AACvC,EAAA,MAAM,UAAA,uBAAiB,GAAA,EAAa;AAEpC,EAAA,MAAM,OAAA,GAAU,CAAC,KAAA,KAA4B;AAC3C,IAAA,IAAI,MAAM,OAAA,CAAQ,KAAK,GAAG,OAAO,KAAA,CAAM,IAAI,OAAO,CAAA;AAClD,IAAA,IAAI,CAAC,KAAA,IAAS,OAAO,KAAA,KAAU,UAAU,OAAO,KAAA;AAChD,IAAA,MAAM,MAAO,KAAA,CAAgB,GAAA;AAC7B,IAAA,IAAI,KAAK,IAAA,KAAS,MAAA,IAAU,GAAA,CAAI,QAAA,IAAY,IAAI,EAAA,EAAI;AAClD,MAAA,MAAM,MAAA,GAAS,MAAM,GAAA,CAAI,GAAA,CAAI,IAAI,QAAA,EAAU,GAAA,CAAI,EAAE,CAAC,CAAA;AAClD,MAAA,IAAI,CAAC,MAAA,IAAU,UAAA,CAAW,GAAA,CAAI,MAAM,GAAG,OAAO,KAAA;AAC9C,MAAA,OAAO,cAAc,MAAM,CAAA;AAAA,IAC7B;AACA,IAAA,IAAI,GAAA,KAAQ,IAAI,IAAA,KAAS,OAAA,IAAW,IAAI,IAAA,KAAS,OAAA,CAAA,EAAU,OAAO,aAAA,CAAc,KAAK,CAAA;AACrF,IAAA,MAAM,MAA+B,EAAC;AACtC,IAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,CAAA,IAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG,GAAA,CAAI,CAAC,CAAA,GAAI,OAAA,CAAQ,CAAC,CAAA;AAC9D,IAAA,OAAO,GAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,aAAA,GAAgB,CAAC,MAAA,KAA6B;AAClD,IAAA,IAAI,KAAK,GAAA,CAAI,MAAM,GAAG,OAAO,IAAA,CAAK,IAAI,MAAM,CAAA;AAC5C,IAAA,MAAM,CAAA,GAAI,MAAA;AACV,IAAA,MAAM,OAAc,EAAE,GAAG,CAAA,EAAG,MAAA,EAAQ,EAAC,EAA6B;AAClE,IAAA,IAAA,CAAK,GAAA,CAAI,QAAQ,IAAI,CAAA;AACrB,IAAA,UAAA,CAAW,IAAI,MAAM,CAAA;AACrB,IAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,CAAA,IAAK,MAAA,CAAO,QAAQ,CAAA,CAAE,MAAA,IAAU,EAAE,GAAG,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,GAAI,QAAQ,CAAC,CAAA;AAC/E,IAAA,UAAA,CAAW,OAAO,MAAM,CAAA;AACxB,IAAA,OAAO,IAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,KAAA,CAAM,GAAA,CAAI,OAAO,CAAA;AACjC,EAAA,IAAI,CAAC,QAAQ,OAAO,KAAA;AACpB,EAAA,MAAM,EAAE,QAAA,EAAU,KAAA,EAAO,GAAG,MAAK,GAAI,CAAA;AACrC,EAAA,OAAO,EAAE,GAAG,IAAA,EAAM,KAAA,EAAM;AAC1B","file":"contentful.js","sourcesContent":["/**\n * Contentful adapter for {@link personalizeContent}.\n *\n * Works with either a contentful.js client (`createClient(...)`, links resolved by the client) or\n * raw Content Delivery API credentials (links resolved here). Pages can be passed as an entry, an\n * array of entries, or a raw CDA collection response (`{ items, includes }`).\n *\n * Expects the two fields Xenia adds to personalized content types: `xenia` (JSON marker) and\n * `xeniaVariants` (references, static replacements only). Single-locale payloads only — don't\n * fetch with `withAllLocales` / `locale=*`.\n */\n\nimport type { CmsAdapter, XeniaMarker } from \"../core/personalize-content\";\nimport type { EntryFilter } from \"../core/types\";\n\n/** The subset of a contentful.js client this adapter calls. */\nexport interface ContentfulClientLike {\n getEntries(query: Record<string, unknown>): Promise<{ items: unknown[]; includes?: unknown }>;\n}\n\nexport interface ContentfulAdapterOptions {\n /** A contentful.js client. Takes precedence over raw credentials. */\n client?: ContentfulClientLike;\n space?: string;\n accessToken?: string;\n environment?: string;\n /** `cdn.contentful.com` (default) or `preview.contentful.com`. */\n host?: string;\n /** Link depth fetched with pages and replacement entries (0-10). Default 4 — raise it for deeper pages. */\n include?: number;\n /** Marker field ids, if your content types name them differently. */\n markerField?: string;\n variantsField?: string;\n fetch?: typeof fetch;\n}\n\ntype Entry = { sys: { id: string; type: string; contentType?: unknown }; fields: Record<string, unknown> };\n\nconst KINDS = new Set([\"static\", \"runtime\"]);\nconst OPS = new Set([\"replace\", \"expand\", \"items\"]);\n\nexport function contentfulAdapter(options: ContentfulAdapterOptions = {}): CmsAdapter<Entry> {\n const markerField = options.markerField ?? \"xenia\";\n const variantsField = options.variantsField ?? \"xeniaVariants\";\n const include = options.include ?? 4;\n\n const getEntries = async (query: Record<string, unknown>, locale?: string): Promise<Entry[]> => {\n const q = { include, ...(locale ? { locale } : {}), ...query };\n if (options.client) {\n const res = await options.client.getEntries(q);\n return resolveCollection(res) as Entry[];\n }\n if (!options.space || !options.accessToken) {\n throw new Error(\"contentfulAdapter: pass `client` or `space` + `accessToken` to fetch replacements\");\n }\n const params = new URLSearchParams();\n for (const [k, v] of Object.entries(q)) if (v !== undefined) params.set(k, String(v));\n const url =\n `https://${options.host ?? \"cdn.contentful.com\"}/spaces/${encodeURIComponent(options.space)}` +\n `/environments/${encodeURIComponent(options.environment ?? \"master\")}/entries?${params}`;\n const res = await (options.fetch ?? fetch)(url, { headers: { Authorization: `Bearer ${options.accessToken}` } });\n if (!res.ok) throw new Error(`Contentful CDA ${res.status}`);\n return resolveCollection(await res.json()) as Entry[];\n };\n\n return {\n entryId(value) {\n const sys = (value as Entry | null)?.sys;\n return sys && sys.type === \"Entry\" && typeof sys.id === \"string\" ? sys.id : undefined;\n },\n\n marker(entry) {\n return parseMarker(entry.fields?.[markerField]);\n },\n\n staticVariants(entry) {\n const v = entry.fields?.[variantsField];\n return Array.isArray(v) ? v.filter((x): x is Entry => (x as Entry)?.sys?.type === \"Entry\") : [];\n },\n\n getField: (entry, field) => entry.fields?.[field],\n setField(entry, field, value) {\n entry.fields = entry.fields ?? {};\n entry.fields[field] = value;\n },\n\n mergeItems(entry, replacement) {\n for (const [key, value] of Object.entries(replacement.fields ?? {})) {\n if (Array.isArray(value)) entry.fields[key] = value;\n }\n },\n\n clearMarker(entry) {\n if (!entry.fields) return;\n delete entry.fields[markerField];\n delete entry.fields[variantsField];\n },\n\n prepare: (payload) => resolveCollection(payload, true),\n\n fetchEntries: (ids, locale) => getEntries({ \"sys.id[in]\": ids.join(\",\"), limit: ids.length }, locale),\n\n queryEntries(query, locale) {\n const q: Record<string, unknown> = { content_type: query.contentType, limit: query.limit };\n if (query.order) q.order = query.order;\n for (const f of query.filters ?? []) Object.assign(q, filterParam(f));\n return getEntries(q, locale);\n },\n\n async fetchPage(ref, locale) {\n const q: Record<string, unknown> =\n typeof ref === \"string\" ? { \"sys.id\": ref } : { content_type: ref.contentType };\n if (typeof ref !== \"string\") for (const [k, v] of Object.entries(ref.fields)) q[`fields.${k}`] = v;\n return (await getEntries({ ...q, limit: 1 }, locale))[0] ?? null;\n },\n };\n}\n\n/** Parse the `xenia` field (object, or its JSON text). Unknown shapes → not personalized. */\nexport function parseMarker(raw: unknown): XeniaMarker | null {\n let value = raw;\n if (typeof value === \"string\") {\n try {\n value = JSON.parse(value);\n } catch {\n return null;\n }\n }\n if (!value || typeof value !== \"object\") return null;\n const m = value as Record<string, unknown>;\n if (!KINDS.has(m.kind as string)) return null;\n return {\n kind: m.kind as XeniaMarker[\"kind\"],\n op: OPS.has(m.op as string) ? (m.op as XeniaMarker[\"op\"]) : \"replace\",\n field: typeof m.field === \"string\" && m.field ? m.field : undefined,\n limit: typeof m.limit === \"number\" ? m.limit : undefined,\n };\n}\n\n/** CMS-neutral filter → CDA query param (`fields.category[in]=a,b`). */\nfunction filterParam(f: EntryFilter): Record<string, string> {\n const path = /^(fields|sys|metadata)\\./.test(f.field) ? f.field : `fields.${f.field}`;\n const op = f.op ?? \"eq\";\n return { [op === \"eq\" ? path : `${path}[${op}]`]: f.value };\n}\n\n/**\n * Resolve CDA links in a raw collection response (`{ items, includes }`) into nested entries.\n * Shared entries become shared objects; a link back to an entry still being resolved (a cycle)\n * stays a link stub, so the result stays JSON-serializable (RSC props, caches). Anything that is\n * not a raw collection (an entry, an array, contentful.js output) is returned as-is. With\n * `asPage` the collection shape is kept (minus `includes`); otherwise just the resolved `items`.\n */\nexport function resolveCollection(payload: unknown, asPage = false): unknown {\n const p = payload as { items?: unknown[]; includes?: { Entry?: Entry[]; Asset?: unknown[] } } | null;\n if (!p || typeof p !== \"object\" || !Array.isArray(p.items)) return payload;\n if (!p.includes) return asPage ? payload : p.items;\n\n const index = new Map<string, unknown>();\n const key = (type: string, id: string) => `${type}:${id}`;\n for (const e of [...p.items, ...(p.includes.Entry ?? [])] as Entry[]) {\n if (e?.sys?.id) index.set(key(e.sys.type, e.sys.id), e);\n }\n for (const a of (p.includes.Asset ?? []) as Entry[]) if (a?.sys?.id) index.set(key(\"Asset\", a.sys.id), a);\n\n const done = new Map<unknown, unknown>();\n const inProgress = new Set<unknown>();\n\n const resolve = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(resolve);\n if (!value || typeof value !== \"object\") return value;\n const sys = (value as Entry).sys as { type?: string; linkType?: string; id?: string } | undefined;\n if (sys?.type === \"Link\" && sys.linkType && sys.id) {\n const target = index.get(key(sys.linkType, sys.id));\n if (!target || inProgress.has(target)) return value; // unresolvable or cyclic → keep the stub\n return resolveEntity(target);\n }\n if (sys && (sys.type === \"Entry\" || sys.type === \"Asset\")) return resolveEntity(value);\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value)) out[k] = resolve(v);\n return out;\n };\n\n const resolveEntity = (entity: unknown): unknown => {\n if (done.has(entity)) return done.get(entity);\n const e = entity as Entry;\n const copy: Entry = { ...e, fields: {} as Record<string, unknown> };\n done.set(entity, copy);\n inProgress.add(entity);\n for (const [k, v] of Object.entries(e.fields ?? {})) copy.fields[k] = resolve(v);\n inProgress.delete(entity);\n return copy;\n };\n\n const items = p.items.map(resolve);\n if (!asPage) return items;\n const { includes: _drop, ...rest } = p;\n return { ...rest, items };\n}\n\n"]}
1
+ {"version":3,"sources":["../../src/cms/contentful.ts"],"names":["res"],"mappings":"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","file":"contentful.js","sourcesContent":["/**\n * Contentful adapter for {@link personalizeContent}.\n *\n * Works with either a contentful.js client (`createClient(...)`, links resolved by the client) or\n * raw Content Delivery API credentials (links resolved here). Pages can be passed as an entry, an\n * array of entries, or a raw CDA collection response (`{ items, includes }`).\n *\n * Expects the two fields Xenia adds to personalized content types: `xenia` (JSON marker) and\n * `xeniaVariants` (references, static replacements only). Single-locale payloads only — don't\n * fetch with `withAllLocales` / `locale=*`.\n */\n\nimport type { CmsAdapter, XeniaMarker } from \"../core/personalize-content\";\nimport type { EntryFilter } from \"../core/types\";\n\n/** The subset of a contentful.js client this adapter calls. */\nexport interface ContentfulClientLike {\n getEntries(query: Record<string, unknown>): Promise<{ items: unknown[]; includes?: unknown }>;\n}\n\nexport interface ContentfulAdapterOptions {\n /** A contentful.js client. Takes precedence over raw credentials. */\n client?: ContentfulClientLike;\n space?: string;\n accessToken?: string;\n environment?: string;\n /** `cdn.contentful.com` (default) or `preview.contentful.com`. */\n host?: string;\n /** Link depth fetched with pages and replacement entries (0-10). Default 4 — raise it for deeper pages. */\n include?: number;\n /** Marker field ids, if your content types name them differently. */\n markerField?: string;\n variantsField?: string;\n fetch?: typeof fetch;\n}\n\ntype Entry = { sys: { id: string; type: string; contentType?: unknown }; fields: Record<string, unknown> };\n\nconst KINDS = new Set([\"static\", \"runtime\"]);\nconst OPS = new Set([\"replace\", \"expand\", \"items\"]);\n\nexport function contentfulAdapter(options: ContentfulAdapterOptions = {}): CmsAdapter<Entry> {\n const markerField = options.markerField ?? \"xenia\";\n const variantsField = options.variantsField ?? \"xeniaVariants\";\n const include = options.include ?? 4;\n\n const getEntries = async (query: Record<string, unknown>, locale?: string): Promise<Entry[]> => {\n const q = { include, ...(locale ? { locale } : {}), ...query };\n if (options.client) {\n const res = await options.client.getEntries(q);\n return resolveCollection(res) as Entry[];\n }\n if (!options.space || !options.accessToken) {\n throw new Error(\"contentfulAdapter: pass `client` or `space` + `accessToken` to fetch replacements\");\n }\n const params = new URLSearchParams();\n for (const [k, v] of Object.entries(q)) if (v !== undefined) params.set(k, String(v));\n const url =\n `https://${options.host ?? \"cdn.contentful.com\"}/spaces/${encodeURIComponent(options.space)}` +\n `/environments/${encodeURIComponent(options.environment ?? \"master\")}/entries?${params}`;\n const res = await (options.fetch ?? fetch)(url, { headers: { Authorization: `Bearer ${options.accessToken}` } });\n if (!res.ok) throw new Error(`Contentful CDA ${res.status}`);\n return resolveCollection(await res.json()) as Entry[];\n };\n\n return {\n entryId(value) {\n const sys = (value as Entry | null)?.sys;\n return sys && sys.type === \"Entry\" && typeof sys.id === \"string\" ? sys.id : undefined;\n },\n\n marker(entry) {\n return parseMarker(entry.fields?.[markerField]);\n },\n\n staticVariants(entry) {\n const v = entry.fields?.[variantsField];\n return Array.isArray(v) ? v.filter((x): x is Entry => (x as Entry)?.sys?.type === \"Entry\") : [];\n },\n\n getField: (entry, field) => entry.fields?.[field],\n setField(entry, field, value) {\n entry.fields = entry.fields ?? {};\n entry.fields[field] = value;\n },\n\n mergeItems(entry, replacement) {\n for (const [key, value] of Object.entries(replacement.fields ?? {})) {\n if (Array.isArray(value)) entry.fields[key] = value;\n }\n },\n\n clearMarker(entry) {\n if (!entry.fields) return;\n delete entry.fields[markerField];\n delete entry.fields[variantsField];\n },\n\n prepare: (payload) => resolveCollection(payload, true),\n\n fetchEntries: (ids, locale) => getEntries({ \"sys.id[in]\": ids.join(\",\"), limit: ids.length }, locale),\n\n queryEntries(query, locale) {\n const q: Record<string, unknown> = { content_type: query.contentType, limit: query.limit };\n if (query.order) q.order = query.order;\n for (const f of query.filters ?? []) Object.assign(q, filterParam(f));\n return getEntries(q, locale);\n },\n\n async fetchPage(ref, locale) {\n const q: Record<string, unknown> =\n typeof ref === \"string\" ? { \"sys.id\": ref } : { content_type: ref.contentType };\n if (typeof ref !== \"string\") for (const [k, v] of Object.entries(ref.fields)) q[`fields.${k}`] = v;\n return (await getEntries({ ...q, limit: 1 }, locale))[0] ?? null;\n },\n };\n}\n\n/** Parse the `xenia` field (object, or its JSON text). Unknown shapes → not personalized. */\nexport function parseMarker(raw: unknown): XeniaMarker | null {\n let value = raw;\n if (typeof value === \"string\") {\n try {\n value = JSON.parse(value);\n } catch {\n return null;\n }\n }\n if (!value || typeof value !== \"object\") return null;\n const m = value as Record<string, unknown>;\n if (!KINDS.has(m.kind as string)) return null;\n return {\n kind: m.kind as XeniaMarker[\"kind\"],\n op: OPS.has(m.op as string) ? (m.op as XeniaMarker[\"op\"]) : \"replace\",\n field: typeof m.field === \"string\" && m.field ? m.field : undefined,\n limit: typeof m.limit === \"number\" ? m.limit : undefined,\n keys: Array.isArray(m.keys) ? m.keys.filter((k): k is string => typeof k === \"string\") : undefined,\n };\n}\n\n/** CMS-neutral filter → CDA query param (`fields.category[in]=a,b`). */\nfunction filterParam(f: EntryFilter): Record<string, string> {\n const path = /^(fields|sys|metadata)\\./.test(f.field) ? f.field : `fields.${f.field}`;\n const op = f.op ?? \"eq\";\n return { [op === \"eq\" ? path : `${path}[${op}]`]: f.value };\n}\n\n/**\n * Resolve CDA links in a raw collection response (`{ items, includes }`) into nested entries.\n * Shared entries become shared objects; a link back to an entry still being resolved (a cycle)\n * stays a link stub, so the result stays JSON-serializable (RSC props, caches). Anything that is\n * not a raw collection (an entry, an array, contentful.js output) is returned as-is. With\n * `asPage` the collection shape is kept (minus `includes`); otherwise just the resolved `items`.\n */\nexport function resolveCollection(payload: unknown, asPage = false): unknown {\n const p = payload as { items?: unknown[]; includes?: { Entry?: Entry[]; Asset?: unknown[] } } | null;\n if (!p || typeof p !== \"object\" || !Array.isArray(p.items)) return payload;\n if (!p.includes) return asPage ? payload : p.items;\n\n const index = new Map<string, unknown>();\n const key = (type: string, id: string) => `${type}:${id}`;\n for (const e of [...p.items, ...(p.includes.Entry ?? [])] as Entry[]) {\n if (e?.sys?.id) index.set(key(e.sys.type, e.sys.id), e);\n }\n for (const a of (p.includes.Asset ?? []) as Entry[]) if (a?.sys?.id) index.set(key(\"Asset\", a.sys.id), a);\n\n const done = new Map<unknown, unknown>();\n const inProgress = new Set<unknown>();\n\n const resolve = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(resolve);\n if (!value || typeof value !== \"object\") return value;\n const sys = (value as Entry).sys as { type?: string; linkType?: string; id?: string } | undefined;\n if (sys?.type === \"Link\" && sys.linkType && sys.id) {\n const target = index.get(key(sys.linkType, sys.id));\n if (!target || inProgress.has(target)) return value; // unresolvable or cyclic → keep the stub\n return resolveEntity(target);\n }\n if (sys && (sys.type === \"Entry\" || sys.type === \"Asset\")) return resolveEntity(value);\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value)) out[k] = resolve(v);\n return out;\n };\n\n const resolveEntity = (entity: unknown): unknown => {\n if (done.has(entity)) return done.get(entity);\n const e = entity as Entry;\n const copy: Entry = { ...e, fields: {} as Record<string, unknown> };\n done.set(entity, copy);\n inProgress.add(entity);\n for (const [k, v] of Object.entries(e.fields ?? {})) copy.fields[k] = resolve(v);\n inProgress.delete(entity);\n return copy;\n };\n\n const items = p.items.map(resolve);\n if (!asPage) return items;\n const { includes: _drop, ...rest } = p;\n return { ...rest, items };\n}\n\n"]}
@@ -0,0 +1,248 @@
1
+ import { P as PersonalizationSwap } from './types-DgVHS4Qw.js';
2
+
3
+ /** Wire types of Xenia's `/api/personalization/edge` endpoints (see the backend's personalization-edge-api.md). */
4
+
5
+ /** `edge`: decidable from request data alone; `server`: needs a lookup, always decided by `/decide`. */
6
+ type EdgeMode = "edge" | "server" | "off";
7
+ interface ManifestKey {
8
+ contentKey: string;
9
+ mode: EdgeMode;
10
+ pages: string[];
11
+ }
12
+ /** Which content keys target which pages — the proxy's "call Xenia?" switch. */
13
+ interface Manifest {
14
+ version: string;
15
+ generatedAt: string;
16
+ keys: ManifestKey[];
17
+ }
18
+ /** A storefront's own, public copy of the manifest: just the targeted page patterns. */
19
+ interface PublicManifest {
20
+ version: string;
21
+ pages: string[];
22
+ }
23
+ /** What `/decide` decided for one content key. */
24
+ interface EdgeDecision {
25
+ contentKey: string;
26
+ mode: EdgeMode;
27
+ personalized: boolean;
28
+ /** `personalized` | `control`; set when Xenia recorded an exposure. */
29
+ bucket: string | null;
30
+ variant: string | null;
31
+ baseEntryId: string | null;
32
+ swaps: PersonalizationSwap[];
33
+ trace: Record<string, string>;
34
+ reason: string | null;
35
+ }
36
+ /** The visitor profile Xenia decided with (`profile.*` journey facts), when profiles are on. */
37
+ type ProfileFacts = Record<string, unknown>;
38
+ interface DecideResult {
39
+ version: string;
40
+ decisions: EdgeDecision[];
41
+ profileVersion?: number;
42
+ profile?: ProfileFacts | null;
43
+ }
44
+ /**
45
+ * A page the visitor viewed: path, when (epoch ms) and, once they've left it, the seconds spent
46
+ * there. Sent with `/decide` so profile rules see views whose analytics events haven't landed yet.
47
+ */
48
+ interface TrailView {
49
+ path: string;
50
+ at: number;
51
+ seconds?: number;
52
+ }
53
+ /** Request data journey rules can read (`utmCampaign`, `device`, `query.ref`, `geo.country`, …). */
54
+ type EdgeFacts = Record<string, string | number | boolean | Record<string, string>>;
55
+ /** Where a decision came from — surfaced in `Server-Timing`. */
56
+ type DecisionSource = "cache" | "xenia" | "timeout" | "error" | "no-manifest";
57
+ /** The visitor's location in Xenia's `ViewerGeo` shape — the only keys `/decide` accepts in `facts.geo`. */
58
+ type ViewerGeo = Partial<Record<"country" | "countryName" | "region" | "regionName" | "city" | "postalCode" | "timeZone" | "latitude" | "longitude" | "source", string>>;
59
+
60
+ /** What a visitor's cached decision holds: the decisions and the profile they were made with. */
61
+ type CachedDecision = {
62
+ decisions: EdgeDecision[];
63
+ profile?: ProfileFacts | null;
64
+ };
65
+ type DecisionCache = {
66
+ get(key: string): CachedDecision | undefined;
67
+ set(key: string, value: CachedDecision, ttlMs: number): void;
68
+ };
69
+ type XeniaEdgeConfig = {
70
+ /** Xenia engine base URL, e.g. `https://engine.xeniamartech.com/xenia`. */
71
+ baseUrl: string;
72
+ /** A server-type SDK token. Never expose it to the browser. */
73
+ token: string;
74
+ /** Hard deadline for one `/decide` call. Default 150 ms. */
75
+ budgetMs?: number;
76
+ /**
77
+ * Where to read the manifest. Default: Xenia's `/edge/manifest` (with the token). A storefront
78
+ * can serve its own CDN-cached copy instead (e.g. a Next.js ISR route) — then no token is sent.
79
+ */
80
+ manifestUrl?: string;
81
+ /**
82
+ * A manifest baked in at build time. An instance starts with it in memory, so a cold start never
83
+ * waits: the first request uses it and triggers a background refresh. Empty version = none.
84
+ */
85
+ initialManifest?: Manifest | PublicManifest;
86
+ /** How long a cold start waits for the first manifest (only without `initialManifest`). Default 300 ms. */
87
+ manifestWaitMs?: number;
88
+ /** Manifest refresh interval. Default 30 s. */
89
+ manifestTtlMs?: number;
90
+ /** How long a visitor keeps a decision. Default 30 min (a session). */
91
+ decisionTtlMs?: number;
92
+ /**
93
+ * How long a provisional decision is kept (see `provisional`): Jev's answer, or the visitor's first
94
+ * signals, usually land seconds later, so the next view should ask again. Default 15 s.
95
+ */
96
+ provisionalDecisionTtlMs?: number;
97
+ cache?: DecisionCache;
98
+ fetch?: typeof fetch;
99
+ onError?: (error: unknown, context: string) => void;
100
+ };
101
+ type DecideInput = {
102
+ host: string | null;
103
+ path: string;
104
+ visitorId: string;
105
+ facts: EdgeFacts;
106
+ /** Facts that identify this visitor's context for caching (e.g. landing UTM, device). */
107
+ cacheFacts?: EdgeFacts;
108
+ /** The visitor's recent page views, most recent first (see `TrailView`). */
109
+ trail?: TrailView[];
110
+ /** This call's time budget, instead of the client's (a decision that calls a back office). */
111
+ budgetMs?: number;
112
+ /** How long to keep this call's answer, from what it said, instead of the client's. */
113
+ ttlMs?: (answer: CachedDecision) => number;
114
+ };
115
+ type DecideOutcome = {
116
+ decisions: EdgeDecision[];
117
+ /** The profile Xenia decided with (also on cache hits), when profiles are on. */
118
+ profile?: ProfileFacts | null;
119
+ source: DecisionSource;
120
+ /** Time spent in Xenia, 0 on a cache hit. */
121
+ ms: number;
122
+ };
123
+ /** Bounded in-memory LRU with per-entry expiry. */
124
+ declare function memoryDecisionCache(maxEntries?: number): DecisionCache;
125
+ declare function createXeniaEdge(config: XeniaEdgeConfig): {
126
+ match: (host: string | null, path: string) => Promise<ManifestKey[] | null>;
127
+ decide: (keys: ManifestKey[], input: DecideInput) => Promise<DecideOutcome>;
128
+ refreshManifest: () => Promise<void>;
129
+ };
130
+ type XeniaEdge = ReturnType<typeof createXeniaEdge>;
131
+
132
+ /**
133
+ * The proxy hands a decision to the page as a signed token in the rewritten URL
134
+ * (`/xv/<token>/women`). The token is just the swaps — identical for every visitor in the same
135
+ * variant — so each variant renders once and is then served from the ISR/CDN cache like any static
136
+ * page. A site may carry its own data along (`extra`), e.g. what the page fills itself from.
137
+ *
138
+ * Signed (HMAC-SHA256) so nobody can craft a URL that renders arbitrary entries. Web Crypto only, so
139
+ * it runs in any runtime.
140
+ */
141
+
142
+ /**
143
+ * One swap: the base entry's field, the entry shown in its place, and the content key whose
144
+ * decision it is — so the page can report impressions and clicks per journey and entry.
145
+ */
146
+ type VariantSwap = [identifier: string, replacementEntryId: string, contentKey?: string];
147
+ /** Swaps for one base entry. */
148
+ interface SwapGroup {
149
+ base: string;
150
+ swaps: VariantSwap[];
151
+ }
152
+ /** The swap groups of the personalized decisions, in a stable order (stable cache keys). */
153
+ declare function swapGroups(decisions: EdgeDecision[]): SwapGroup[];
154
+ /**
155
+ * The token for a variant. An `extra` that would push it past the payload limit is left out — the
156
+ * page still renders its swaps — rather than making a token no page accepts.
157
+ */
158
+ declare function encodeVariant(groups: SwapGroup[], secret: string, extra?: unknown): Promise<string>;
159
+ /** The variant in a token, or `null` if it is malformed or not signed with `secret`. */
160
+ declare function decodeVariant<E = unknown>(token: string, secret: string): Promise<{
161
+ groups: SwapGroup[];
162
+ extra?: E;
163
+ } | null>;
164
+
165
+ /**
166
+ * Facts about a request that journey rules read — where the visitor is, on what device, where they
167
+ * came from, their local time — derived from a standard `Request` in any runtime.
168
+ */
169
+
170
+ /** The location headers `viewerGeo` can read, when trusted. */
171
+ type GeoHeader = "x-xn-geo" | "x-nf-geo" | "x-country" | "x-vercel-ip-country" | "cloudfront-viewer-country" | "cf-ipcountry";
172
+ /**
173
+ * The visitor's location as the hosting edge resolved it, and which source supplied it (`via`).
174
+ * Geo must come from the storefront's edge, never Xenia's: `/decide` is server to server. Tried in
175
+ * order — whichever the host provides:
176
+ * 1. Netlify's per-request `Netlify.context.geo` (can't be spoofed by the client, unlike a header)
177
+ * 2. `x-xn-geo` (URI-encoded JSON) from the site's own edge function
178
+ * 3. a `request.geo` some runtimes attach
179
+ * 4. Netlify's `x-nf-geo` header (base64 or URI-encoded JSON)
180
+ * 5. `x-country` (Netlify), `x-vercel-ip-*`, `cloudfront-viewer-*`, `cf-ipcountry`
181
+ * 6. `?xn_country=GB` — only with `devOverride`, for testing geo rules without an edge
182
+ *
183
+ * Headers (2, 4 and 5) are read only when named in `trust`: a visitor can send any header, and only
184
+ * the site knows which ones its own host or edge function sets (and overwrites). Name exactly those,
185
+ * e.g. `["x-vercel-ip-country"]` on Vercel, `["cf-ipcountry"]` behind Cloudflare,
186
+ * `["x-nf-geo", "x-country"]` on Netlify. 1 and 3 come from the runtime and are always used.
187
+ */
188
+ declare function viewerGeo(request: Request, opts?: {
189
+ devOverride?: boolean;
190
+ trust?: readonly GeoHeader[];
191
+ }): {
192
+ geo?: ViewerGeo;
193
+ via: string;
194
+ };
195
+ declare function deviceOf(headers: Headers): "mobile" | "tablet" | "desktop";
196
+ /** Crawlers and link-preview fetchers: never decided, never recorded. */
197
+ declare function isBot(userAgent: string | null | undefined): boolean;
198
+ /** Link prefetches pass through a proxy too; they aren't page views. */
199
+ declare function isPrefetch(headers: Headers): boolean;
200
+ /**
201
+ * Whether this is the browser loading a page (a full page load), by `Sec-Fetch-Dest`. Requests
202
+ * without it (old browsers, curl) count as page loads.
203
+ */
204
+ declare function isPageLoad(headers: Headers): boolean;
205
+ /**
206
+ * This session's landing context — first-touch attribution, so a campaign carries across pages:
207
+ * the UTMs (≤200 chars each) and an external referrer (≤500), refreshed when the visitor arrives
208
+ * from a new campaign. `saved` is the value kept from earlier (a cookie); `changed` says to save it.
209
+ */
210
+ declare function landingContext(url: URL, referrer: string | null | undefined, saved: string | undefined): {
211
+ ctx: Record<string, string>;
212
+ changed: boolean;
213
+ };
214
+ /** Meteorological seasons: Dec–Feb winter, Mar–May spring, Jun–Aug summer, Sep–Nov fall. */
215
+ declare function seasonOf(month: number, southernHemisphere?: boolean): string;
216
+ interface LocalTime {
217
+ local_weekday: string;
218
+ local_month: number;
219
+ local_hour: number;
220
+ is_weekend: boolean;
221
+ season: string;
222
+ }
223
+ /** Weekday, month, hour and season where the visitor is (their time zone; UTC when unknown). */
224
+ declare function localTime(geo: ViewerGeo | undefined, now: Date): LocalTime;
225
+
226
+ interface EdgeConsent {
227
+ /** Off: don't ask Xenia, serve base content. */
228
+ personalization: boolean;
229
+ /** Off: decide, but keep no trail or click cookies and send no trail. */
230
+ analytics: boolean;
231
+ }
232
+ /**
233
+ * What the edge flow may do for this request, from the consent cookie the browser client's
234
+ * `consent()` writes and the visitor's privacy signals:
235
+ * - no consent cookie (or an unreadable one) → no choice made: everything on, as before;
236
+ * - an explicit choice → followed (JSON `{analytics, personalization}`, or the scopes form
237
+ * `analytics,personalization` where an unlisted scope is refused);
238
+ * - `Sec-GPC: 1` / `DNT: 1` → analytics off, like the browser client's `respectDnt` (default on).
239
+ *
240
+ * Unlike `getConsent()`, an absent cookie isn't "all denied": the edge can't tell a visitor who
241
+ * refused from one who was never asked, and refusing both would change every first page view.
242
+ */
243
+ declare function edgeConsent(headers: Headers, opts?: {
244
+ prefix?: string;
245
+ respectDnt?: boolean;
246
+ }): EdgeConsent;
247
+
248
+ export { type CachedDecision as C, type DecideInput as D, type EdgeConsent as E, type GeoHeader as G, type LocalTime as L, type Manifest as M, type PublicManifest as P, type SwapGroup as S, type TrailView as T, type VariantSwap as V, type XeniaEdge as X, type DecideOutcome as a, type DecideResult as b, type DecisionCache as c, type DecisionSource as d, type EdgeDecision as e, type EdgeFacts as f, type EdgeMode as g, type ManifestKey as h, type ProfileFacts as i, type ViewerGeo as j, type XeniaEdgeConfig as k, createXeniaEdge as l, decodeVariant as m, deviceOf as n, edgeConsent as o, encodeVariant as p, isBot as q, isPageLoad as r, isPrefetch as s, landingContext as t, localTime as u, memoryDecisionCache as v, seasonOf as w, swapGroups as x, viewerGeo as y };