@xenia-martech/sdk-js 1.2.0-dev.8 → 1.2.0-dev.9

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 (96) hide show
  1. package/README.md +69 -5
  2. package/dist/{actions-35V37IT0.d.cts → actions--1_9Z8ig.d.cts} +13 -2
  3. package/dist/{actions-35V37IT0.d.ts → actions--1_9Z8ig.d.ts} +13 -2
  4. package/dist/{api-0IycTYJR.d.cts → api-DbUxT38T.d.ts} +1 -1
  5. package/dist/{api-COXWLL5L.d.ts → api-DgzJ5s-k.d.cts} +1 -1
  6. package/dist/chunk-DPXINHQR.cjs +34 -0
  7. package/dist/chunk-DPXINHQR.cjs.map +1 -0
  8. package/dist/chunk-FSJMHXS6.js +432 -0
  9. package/dist/chunk-FSJMHXS6.js.map +1 -0
  10. package/dist/chunk-GXJLU3RE.cjs +448 -0
  11. package/dist/chunk-GXJLU3RE.cjs.map +1 -0
  12. package/dist/{chunk-2DR5AVPX.cjs → chunk-I5EHLRSR.cjs} +11 -10
  13. package/dist/chunk-I5EHLRSR.cjs.map +1 -0
  14. package/dist/{chunk-LW5AEJ6K.js → chunk-MEULT5X6.js} +4 -241
  15. package/dist/chunk-MEULT5X6.js.map +1 -0
  16. package/dist/{chunk-GWRDZIVA.js → chunk-NDRRSRTU.js} +4 -3
  17. package/dist/chunk-NDRRSRTU.js.map +1 -0
  18. package/dist/chunk-RC46KXDM.js +32 -0
  19. package/dist/chunk-RC46KXDM.js.map +1 -0
  20. package/dist/{chunk-RWE2OCQL.cjs → chunk-SU25SELD.cjs} +4 -244
  21. package/dist/chunk-SU25SELD.cjs.map +1 -0
  22. package/dist/{chunk-WHGK55JP.cjs → chunk-UUIKUU5W.cjs} +5 -5
  23. package/dist/{chunk-WHGK55JP.cjs.map → chunk-UUIKUU5W.cjs.map} +1 -1
  24. package/dist/{chunk-QEYONKWY.js → chunk-UVTFGQR6.js} +3 -3
  25. package/dist/{chunk-QEYONKWY.js.map → chunk-UVTFGQR6.js.map} +1 -1
  26. package/dist/{chunk-F3WZFXYK.js → chunk-V4EGU3PM.js} +45 -10
  27. package/dist/chunk-V4EGU3PM.js.map +1 -0
  28. package/dist/{chunk-IOY6IPUW.cjs → chunk-WMGCQPHY.cjs} +49 -12
  29. package/dist/chunk-WMGCQPHY.cjs.map +1 -0
  30. package/dist/client/index.cjs +26 -10
  31. package/dist/client/index.cjs.map +1 -1
  32. package/dist/client/index.d.cts +2 -2
  33. package/dist/client/index.d.ts +2 -2
  34. package/dist/client/index.js +26 -10
  35. package/dist/client/index.js.map +1 -1
  36. package/dist/client/react/index.cjs +73 -15
  37. package/dist/client/react/index.cjs.map +1 -1
  38. package/dist/client/react/index.d.cts +9 -3
  39. package/dist/client/react/index.d.ts +9 -3
  40. package/dist/client/react/index.js +73 -15
  41. package/dist/client/react/index.js.map +1 -1
  42. package/dist/cms/contentful.cjs +7 -24
  43. package/dist/cms/contentful.cjs.map +1 -1
  44. package/dist/cms/contentful.d.cts +5 -4
  45. package/dist/cms/contentful.d.ts +5 -4
  46. package/dist/cms/contentful.js +4 -23
  47. package/dist/cms/contentful.js.map +1 -1
  48. package/dist/cms/contentstack.cjs +120 -0
  49. package/dist/cms/contentstack.cjs.map +1 -0
  50. package/dist/cms/contentstack.d.cts +41 -0
  51. package/dist/cms/contentstack.d.ts +41 -0
  52. package/dist/cms/contentstack.js +117 -0
  53. package/dist/cms/contentstack.js.map +1 -0
  54. package/dist/{consent-DRCV0N0d.d.ts → consent-Dtiqzz2B.d.cts} +71 -11
  55. package/dist/{consent-BgAETCkL.d.cts → consent-byYiDMFr.d.ts} +71 -11
  56. package/dist/{cookie-names-DU3MtcNG.d.ts → cookie-names-B4hda2rX.d.cts} +1 -1
  57. package/dist/{cookie-names-DFItnSLK.d.cts → cookie-names-DioZXuV0.d.ts} +1 -1
  58. package/dist/edge/index.cjs +122 -29
  59. package/dist/edge/index.cjs.map +1 -1
  60. package/dist/edge/index.d.cts +41 -5
  61. package/dist/edge/index.d.ts +41 -5
  62. package/dist/edge/index.js +92 -9
  63. package/dist/edge/index.js.map +1 -1
  64. package/dist/index.cjs +31 -31
  65. package/dist/index.d.cts +4 -5
  66. package/dist/index.d.ts +4 -5
  67. package/dist/index.js +2 -2
  68. package/dist/next/index.cjs +34 -33
  69. package/dist/next/index.cjs.map +1 -1
  70. package/dist/next/index.d.cts +2 -3
  71. package/dist/next/index.d.ts +2 -3
  72. package/dist/next/index.js +8 -7
  73. package/dist/next/index.js.map +1 -1
  74. package/dist/{types-DgVHS4Qw.d.ts → personalize-content-D6xeBI7-.d.cts} +150 -1
  75. package/dist/{types-DgVHS4Qw.d.cts → personalize-content-D6xeBI7-.d.ts} +150 -1
  76. package/dist/server/index.cjs +30 -30
  77. package/dist/server/index.d.cts +5 -6
  78. package/dist/server/index.d.ts +5 -6
  79. package/dist/server/index.js +5 -5
  80. package/dist/xenia-sdk.iife.js +3 -3
  81. package/dist/xenia-sdk.iife.js.map +1 -1
  82. package/dist/{xenia-server-Cf24mL0c.d.ts → xenia-server-BcgeUHX4.d.ts} +2 -3
  83. package/dist/{xenia-server-D-bx14lw.d.cts → xenia-server-lv6LtJZP.d.cts} +2 -3
  84. package/package.json +14 -1
  85. package/dist/chunk-2DR5AVPX.cjs.map +0 -1
  86. package/dist/chunk-BQ5PJCZ7.js +0 -179
  87. package/dist/chunk-BQ5PJCZ7.js.map +0 -1
  88. package/dist/chunk-F3WZFXYK.js.map +0 -1
  89. package/dist/chunk-GWRDZIVA.js.map +0 -1
  90. package/dist/chunk-IOY6IPUW.cjs.map +0 -1
  91. package/dist/chunk-LW5AEJ6K.js.map +0 -1
  92. package/dist/chunk-N5M4PI7C.cjs +0 -192
  93. package/dist/chunk-N5M4PI7C.cjs.map +0 -1
  94. package/dist/chunk-RWE2OCQL.cjs.map +0 -1
  95. package/dist/personalize-content-Cwc2AomC.d.ts +0 -141
  96. package/dist/personalize-content-CxSdplMV.d.cts +0 -141
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
+ var chunkDPXINHQR_cjs = require('../chunk-DPXINHQR.cjs');
4
+
3
5
  // src/cms/contentful.ts
4
- var KINDS = /* @__PURE__ */ new Set(["static", "runtime"]);
5
- var OPS = /* @__PURE__ */ new Set(["replace", "expand", "items"]);
6
6
  function contentfulAdapter(options = {}) {
7
7
  const markerField = options.markerField ?? "xenia";
8
8
  const variantsField = options.variantsField ?? "xeniaVariants";
@@ -29,7 +29,7 @@ function contentfulAdapter(options = {}) {
29
29
  return sys && sys.type === "Entry" && typeof sys.id === "string" ? sys.id : void 0;
30
30
  },
31
31
  marker(entry) {
32
- return parseMarker(entry.fields?.[markerField]);
32
+ return chunkDPXINHQR_cjs.parseMarker(entry.fields?.[markerField]);
33
33
  },
34
34
  staticVariants(entry) {
35
35
  const v = entry.fields?.[variantsField];
@@ -65,26 +65,6 @@ function contentfulAdapter(options = {}) {
65
65
  }
66
66
  };
67
67
  }
68
- function parseMarker(raw) {
69
- let value = raw;
70
- if (typeof value === "string") {
71
- try {
72
- value = JSON.parse(value);
73
- } catch {
74
- return null;
75
- }
76
- }
77
- if (!value || typeof value !== "object") return null;
78
- const m = value;
79
- if (!KINDS.has(m.kind)) return null;
80
- return {
81
- kind: m.kind,
82
- op: OPS.has(m.op) ? m.op : "replace",
83
- field: typeof m.field === "string" && m.field ? m.field : 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
86
- };
87
- }
88
68
  function filterParam(f) {
89
69
  const path = /^(fields|sys|metadata)\./.test(f.field) ? f.field : `fields.${f.field}`;
90
70
  const op = f.op ?? "eq";
@@ -132,8 +112,11 @@ function resolveCollection(payload, asPage = false) {
132
112
  return { ...rest, items };
133
113
  }
134
114
 
115
+ Object.defineProperty(exports, "parseMarker", {
116
+ enumerable: true,
117
+ get: function () { return chunkDPXINHQR_cjs.parseMarker; }
118
+ });
135
119
  exports.contentfulAdapter = contentfulAdapter;
136
- exports.parseMarker = parseMarker;
137
120
  exports.resolveCollection = resolveCollection;
138
121
  //# sourceMappingURL=contentful.cjs.map
139
122
  //# sourceMappingURL=contentful.cjs.map
@@ -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,MAAA;AAAA,IAC/C,IAAA,EAAM,KAAA,CAAM,OAAA,CAAQ,CAAA,CAAE,IAAI,CAAA,GAAI,CAAA,CAAE,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,KAAmB,OAAO,CAAA,KAAM,QAAQ,CAAA,GAAI;AAAA,GAC3F;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.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
+ {"version":3,"sources":["../../src/cms/contentful.ts"],"names":["res","parseMarker"],"mappings":";;;;;AAyCO,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,OAAOC,6BAAA,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;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.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 } from \"../core/personalize-content\";\nimport { parseMarker } from \"./marker\";\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\nexport { parseMarker };\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/** 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,5 +1,7 @@
1
- import { CmsAdapter, XeniaMarker } from '../index.cjs';
2
- import '../types-DgVHS4Qw.cjs';
1
+ import { XeniaMarker, CmsAdapter } from '../index.cjs';
2
+
3
+ /** Parse a `xenia` marker field (object, or its JSON text). Unknown shapes → not personalized. */
4
+ declare function parseMarker(raw: unknown): XeniaMarker | null;
3
5
 
4
6
  /**
5
7
  * Contentful adapter for {@link personalizeContent}.
@@ -43,9 +45,8 @@ type Entry = {
43
45
  };
44
46
  fields: Record<string, unknown>;
45
47
  };
48
+
46
49
  declare function contentfulAdapter(options?: ContentfulAdapterOptions): CmsAdapter<Entry>;
47
- /** Parse the `xenia` field (object, or its JSON text). Unknown shapes → not personalized. */
48
- declare function parseMarker(raw: unknown): XeniaMarker | null;
49
50
  /**
50
51
  * Resolve CDA links in a raw collection response (`{ items, includes }`) into nested entries.
51
52
  * Shared entries become shared objects; a link back to an entry still being resolved (a cycle)
@@ -1,5 +1,7 @@
1
- import { CmsAdapter, XeniaMarker } from '../index.js';
2
- import '../types-DgVHS4Qw.js';
1
+ import { XeniaMarker, CmsAdapter } from '../index.js';
2
+
3
+ /** Parse a `xenia` marker field (object, or its JSON text). Unknown shapes → not personalized. */
4
+ declare function parseMarker(raw: unknown): XeniaMarker | null;
3
5
 
4
6
  /**
5
7
  * Contentful adapter for {@link personalizeContent}.
@@ -43,9 +45,8 @@ type Entry = {
43
45
  };
44
46
  fields: Record<string, unknown>;
45
47
  };
48
+
46
49
  declare function contentfulAdapter(options?: ContentfulAdapterOptions): CmsAdapter<Entry>;
47
- /** Parse the `xenia` field (object, or its JSON text). Unknown shapes → not personalized. */
48
- declare function parseMarker(raw: unknown): XeniaMarker | null;
49
50
  /**
50
51
  * Resolve CDA links in a raw collection response (`{ items, includes }`) into nested entries.
51
52
  * Shared entries become shared objects; a link back to an entry still being resolved (a cycle)
@@ -1,6 +1,7 @@
1
+ import { parseMarker } from '../chunk-RC46KXDM.js';
2
+ export { parseMarker } from '../chunk-RC46KXDM.js';
3
+
1
4
  // src/cms/contentful.ts
2
- var KINDS = /* @__PURE__ */ new Set(["static", "runtime"]);
3
- var OPS = /* @__PURE__ */ new Set(["replace", "expand", "items"]);
4
5
  function contentfulAdapter(options = {}) {
5
6
  const markerField = options.markerField ?? "xenia";
6
7
  const variantsField = options.variantsField ?? "xeniaVariants";
@@ -63,26 +64,6 @@ function contentfulAdapter(options = {}) {
63
64
  }
64
65
  };
65
66
  }
66
- function parseMarker(raw) {
67
- let value = raw;
68
- if (typeof value === "string") {
69
- try {
70
- value = JSON.parse(value);
71
- } catch {
72
- return null;
73
- }
74
- }
75
- if (!value || typeof value !== "object") return null;
76
- const m = value;
77
- if (!KINDS.has(m.kind)) return null;
78
- return {
79
- kind: m.kind,
80
- op: OPS.has(m.op) ? m.op : "replace",
81
- field: typeof m.field === "string" && m.field ? m.field : 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
84
- };
85
- }
86
67
  function filterParam(f) {
87
68
  const path = /^(fields|sys|metadata)\./.test(f.field) ? f.field : `fields.${f.field}`;
88
69
  const op = f.op ?? "eq";
@@ -130,6 +111,6 @@ function resolveCollection(payload, asPage = false) {
130
111
  return { ...rest, items };
131
112
  }
132
113
 
133
- export { contentfulAdapter, parseMarker, resolveCollection };
114
+ export { contentfulAdapter, resolveCollection };
134
115
  //# sourceMappingURL=contentful.js.map
135
116
  //# sourceMappingURL=contentful.js.map
@@ -1 +1 @@
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"]}
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 } from \"../core/personalize-content\";\nimport { parseMarker } from \"./marker\";\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\nexport { parseMarker };\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/** 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,120 @@
1
+ 'use strict';
2
+
3
+ var chunkDPXINHQR_cjs = require('../chunk-DPXINHQR.cjs');
4
+
5
+ // src/cms/contentstack.ts
6
+ var MAX_PER_QUERY = 100;
7
+ function cdnHost(region) {
8
+ const r = (region ?? "us").trim().toLowerCase();
9
+ return r === "us" || r === "na" || r === "" ? "cdn.contentstack.io" : `${r}-cdn.contentstack.com`;
10
+ }
11
+ function contentstackAdapter(options) {
12
+ const markerField = options.markerField ?? "xenia";
13
+ const depth = Math.min(Math.max(options.includeDepth ?? 3, 1), 5);
14
+ const host = options.host ?? cdnHost(options.region);
15
+ const entries = async (contentType, query, extra, locale) => {
16
+ const params = new URLSearchParams({
17
+ environment: options.environment,
18
+ include_all: "true",
19
+ include_all_depth: String(depth),
20
+ ...locale ? { locale } : {},
21
+ ...Object.keys(query).length ? { query: JSON.stringify(query) } : {},
22
+ ...extra
23
+ });
24
+ const url = `https://${host}/v3/content_types/${encodeURIComponent(contentType)}/entries?${params}`;
25
+ const res = await (options.fetch ?? fetch)(url, {
26
+ headers: {
27
+ api_key: options.apiKey,
28
+ access_token: options.deliveryToken,
29
+ ...options.branch ? { branch: options.branch } : {}
30
+ }
31
+ });
32
+ if (!res.ok) throw new Error(`Contentstack CDA ${res.status}`);
33
+ const body = await res.json();
34
+ return (body.entries ?? []).map((e) => e._content_type_uid ? e : { ...e, _content_type_uid: contentType });
35
+ };
36
+ return {
37
+ entryId(value) {
38
+ const v = value;
39
+ return v && typeof v.uid === "string" && typeof v._version === "number" && !("filename" in v) && !("is_dir" in v) ? v.uid : void 0;
40
+ },
41
+ marker: (entry) => chunkDPXINHQR_cjs.parseMarker(entry[markerField]),
42
+ // Static replacements travel in the marker (`ids`), never as pinned links.
43
+ staticVariants: () => [],
44
+ getField: (entry, field) => entry[field],
45
+ setField(entry, field, value) {
46
+ entry[field] = value;
47
+ },
48
+ mergeItems(entry, replacement) {
49
+ for (const [key, value] of Object.entries(replacement)) {
50
+ if (Array.isArray(value) && key !== "tags") entry[key] = value;
51
+ }
52
+ },
53
+ clearMarker(entry) {
54
+ delete entry[markerField];
55
+ },
56
+ async fetchEntries(ids, locale, types) {
57
+ const byType = /* @__PURE__ */ new Map();
58
+ for (const id of ids) {
59
+ const ct = types?.[id];
60
+ if (ct) byType.set(ct, [...byType.get(ct) ?? [], id]);
61
+ }
62
+ const results = await Promise.all(
63
+ [...byType].map(
64
+ ([ct, list]) => entries(ct, { uid: { $in: list } }, { limit: String(Math.min(list.length, MAX_PER_QUERY)) }, locale)
65
+ )
66
+ );
67
+ return results.flat();
68
+ },
69
+ queryEntries(query, locale) {
70
+ const q = {};
71
+ for (const f of query.filters ?? []) Object.assign(q, filterQuery(f));
72
+ const extra = { limit: String(Math.min(query.limit, MAX_PER_QUERY)) };
73
+ if (query.order) {
74
+ const desc = query.order.startsWith("-");
75
+ extra[desc ? "desc" : "asc"] = fieldPath(desc ? query.order.slice(1) : query.order);
76
+ }
77
+ return entries(query.contentType, q, extra, locale);
78
+ },
79
+ async fetchPage(ref, locale) {
80
+ if (typeof ref === "string") {
81
+ throw new Error("contentstackAdapter: a page ref needs its content type \u2014 pass { contentType, fields }");
82
+ }
83
+ const found = await entries(ref.contentType, { ...ref.fields }, { limit: "1" }, locale);
84
+ return found[0] ?? null;
85
+ }
86
+ };
87
+ }
88
+ function fieldPath(field) {
89
+ if (field.startsWith("sys.")) return field === "sys.id" ? "uid" : field.slice(4).replace(/At$/, "_at");
90
+ return field.replace(/^fields\./, "");
91
+ }
92
+ function filterQuery(f) {
93
+ const path = fieldPath(f.field);
94
+ const num = (v) => v.trim() !== "" && !Number.isNaN(Number(v)) ? Number(v) : v;
95
+ const list = () => f.value.split(",").map((v) => v.trim()).filter(Boolean);
96
+ switch (f.op ?? "eq") {
97
+ case "ne":
98
+ return { [path]: { $ne: f.value } };
99
+ case "in":
100
+ return { [path]: { $in: list() } };
101
+ case "nin":
102
+ return { [path]: { $nin: list() } };
103
+ case "exists":
104
+ return { [path]: { $exists: f.value !== "false" } };
105
+ case "lt":
106
+ case "lte":
107
+ case "gt":
108
+ case "gte":
109
+ return { [path]: { [`$${f.op}`]: num(f.value) } };
110
+ case "match":
111
+ return { [path]: { $regex: f.value, $options: "i" } };
112
+ default:
113
+ return { [path]: f.value };
114
+ }
115
+ }
116
+
117
+ exports.cdnHost = cdnHost;
118
+ exports.contentstackAdapter = contentstackAdapter;
119
+ //# sourceMappingURL=contentstack.cjs.map
120
+ //# sourceMappingURL=contentstack.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cms/contentstack.ts"],"names":["parseMarker"],"mappings":"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","file":"contentstack.cjs","sourcesContent":["/**\n * Contentstack adapter for {@link personalizeContent} / {@link personalizePage}.\n *\n * Talks to the Content Delivery API with plain `fetch` (no SDK dependency). Pages and replacements\n * are fetched with `include_all=true`, so references come back as nested entries at any depth up to\n * `includeDepth` — the page resolver walks them like any other content.\n *\n * Expects the one field Xenia adds to personalized content types: `xenia`, a single-line text field\n * holding the marker JSON. Static replacements are named in the marker (`ids` + `ct`) and fetched\n * from the delivery API in the same round as runtime ones — no Xenia call for them.\n */\n\nimport type { CmsAdapter, PageRef } from \"../core/personalize-content\";\nimport type { EntryFilter, EntryQuery } from \"../core/types\";\nimport { parseMarker } from \"./marker\";\n\nexport interface ContentstackAdapterOptions {\n /** The stack API key. */\n apiKey: string;\n deliveryToken: string;\n environment: string;\n /** `us` (default), `eu`, `au`, `azure-na`, `azure-eu`, `gcp-na`, `gcp-eu`. Ignored with `host`. */\n region?: string;\n /** Delivery host, e.g. `eu-cdn.contentstack.com` (overrides `region`). */\n host?: string;\n branch?: string;\n /** Reference depth fetched with pages and replacements (1-5). Default 3 — raise it for deeper pages. */\n includeDepth?: number;\n /** The marker field uid, if your content types name it differently. */\n markerField?: string;\n fetch?: typeof fetch;\n}\n\n/** A Contentstack entry as the delivery API returns it (fields sit on the entry itself). */\ntype Entry = Record<string, unknown> & { uid: string; _version?: number; _content_type_uid?: string };\n\nconst MAX_PER_QUERY = 100;\n\nexport function cdnHost(region?: string): string {\n const r = (region ?? \"us\").trim().toLowerCase();\n return r === \"us\" || r === \"na\" || r === \"\" ? \"cdn.contentstack.io\" : `${r}-cdn.contentstack.com`;\n}\n\nexport function contentstackAdapter(options: ContentstackAdapterOptions): CmsAdapter<Entry> {\n const markerField = options.markerField ?? \"xenia\";\n const depth = Math.min(Math.max(options.includeDepth ?? 3, 1), 5);\n const host = options.host ?? cdnHost(options.region);\n\n const entries = async (\n contentType: string,\n query: Record<string, unknown>,\n extra: Record<string, string>,\n locale?: string,\n ): Promise<Entry[]> => {\n const params = new URLSearchParams({\n environment: options.environment,\n include_all: \"true\",\n include_all_depth: String(depth),\n ...(locale ? { locale } : {}),\n ...(Object.keys(query).length ? { query: JSON.stringify(query) } : {}),\n ...extra,\n });\n const url = `https://${host}/v3/content_types/${encodeURIComponent(contentType)}/entries?${params}`;\n const res = await (options.fetch ?? fetch)(url, {\n headers: {\n api_key: options.apiKey,\n access_token: options.deliveryToken,\n ...(options.branch ? { branch: options.branch } : {}),\n },\n });\n if (!res.ok) throw new Error(`Contentstack CDA ${res.status}`);\n const body = (await res.json()) as { entries?: Entry[] };\n // A top-level entry has no `_content_type_uid`; stamp it so the walker and analytics can tell.\n return (body.entries ?? []).map((e) => (e._content_type_uid ? e : { ...e, _content_type_uid: contentType }));\n };\n\n return {\n entryId(value) {\n const v = value as Partial<Entry> | null;\n // Entries carry a version; reference stubs ({uid, _content_type_uid}) don't, assets have a file.\n return v && typeof v.uid === \"string\" && typeof v._version === \"number\" && !(\"filename\" in v) && !(\"is_dir\" in v)\n ? v.uid\n : undefined;\n },\n\n marker: (entry) => parseMarker(entry[markerField]),\n\n // Static replacements travel in the marker (`ids`), never as pinned links.\n staticVariants: () => [],\n\n getField: (entry, field) => entry[field],\n setField(entry, field, value) {\n entry[field] = value;\n },\n\n mergeItems(entry, replacement) {\n for (const [key, value] of Object.entries(replacement)) {\n if (Array.isArray(value) && key !== \"tags\") entry[key] = value;\n }\n },\n\n clearMarker(entry) {\n delete entry[markerField];\n },\n\n async fetchEntries(ids, locale, types) {\n const byType = new Map<string, string[]>();\n for (const id of ids) {\n const ct = types?.[id];\n if (ct) byType.set(ct, [...(byType.get(ct) ?? []), id]);\n }\n // ponytail: an id with no known content type is skipped (Contentstack can't fetch it); Xenia\n // sends the type for every replacement it knows, so this only hits swaps saved without one.\n const results = await Promise.all(\n [...byType].map(([ct, list]) =>\n entries(ct, { uid: { $in: list } }, { limit: String(Math.min(list.length, MAX_PER_QUERY)) }, locale),\n ),\n );\n return results.flat();\n },\n\n queryEntries(query: EntryQuery, locale) {\n const q: Record<string, unknown> = {};\n for (const f of query.filters ?? []) Object.assign(q, filterQuery(f));\n const extra: Record<string, string> = { limit: String(Math.min(query.limit, MAX_PER_QUERY)) };\n if (query.order) {\n const desc = query.order.startsWith(\"-\");\n extra[desc ? \"desc\" : \"asc\"] = fieldPath(desc ? query.order.slice(1) : query.order);\n }\n return entries(query.contentType, q, extra, locale);\n },\n\n async fetchPage(ref: PageRef, locale) {\n if (typeof ref === \"string\") {\n throw new Error(\"contentstackAdapter: a page ref needs its content type — pass { contentType, fields }\");\n }\n const found = await entries(ref.contentType, { ...ref.fields }, { limit: \"1\" }, locale);\n return found[0] ?? null;\n },\n };\n}\n\n/** CMS-neutral field path → Contentstack's (`fields.` / `sys.` prefixes from shared presets dropped). */\nfunction fieldPath(field: string): string {\n if (field.startsWith(\"sys.\")) return field === \"sys.id\" ? \"uid\" : field.slice(4).replace(/At$/, \"_at\");\n return field.replace(/^fields\\./, \"\");\n}\n\n/** CMS-neutral filter → Contentstack query operator (`{category: {$in: [...]}}`). */\nfunction filterQuery(f: EntryFilter): Record<string, unknown> {\n const path = fieldPath(f.field);\n const num = (v: string) => (v.trim() !== \"\" && !Number.isNaN(Number(v)) ? Number(v) : v);\n const list = () => f.value.split(\",\").map((v) => v.trim()).filter(Boolean);\n switch (f.op ?? \"eq\") {\n case \"ne\":\n return { [path]: { $ne: f.value } };\n case \"in\":\n return { [path]: { $in: list() } };\n case \"nin\":\n return { [path]: { $nin: list() } };\n case \"exists\":\n return { [path]: { $exists: f.value !== \"false\" } };\n case \"lt\":\n case \"lte\":\n case \"gt\":\n case \"gte\":\n return { [path]: { [`$${f.op}`]: num(f.value) } };\n case \"match\":\n return { [path]: { $regex: f.value, $options: \"i\" } };\n default:\n return { [path]: f.value };\n }\n}\n"]}
@@ -0,0 +1,41 @@
1
+ import { CmsAdapter } from '../index.cjs';
2
+
3
+ /**
4
+ * Contentstack adapter for {@link personalizeContent} / {@link personalizePage}.
5
+ *
6
+ * Talks to the Content Delivery API with plain `fetch` (no SDK dependency). Pages and replacements
7
+ * are fetched with `include_all=true`, so references come back as nested entries at any depth up to
8
+ * `includeDepth` — the page resolver walks them like any other content.
9
+ *
10
+ * Expects the one field Xenia adds to personalized content types: `xenia`, a single-line text field
11
+ * holding the marker JSON. Static replacements are named in the marker (`ids` + `ct`) and fetched
12
+ * from the delivery API in the same round as runtime ones — no Xenia call for them.
13
+ */
14
+
15
+ interface ContentstackAdapterOptions {
16
+ /** The stack API key. */
17
+ apiKey: string;
18
+ deliveryToken: string;
19
+ environment: string;
20
+ /** `us` (default), `eu`, `au`, `azure-na`, `azure-eu`, `gcp-na`, `gcp-eu`. Ignored with `host`. */
21
+ region?: string;
22
+ /** Delivery host, e.g. `eu-cdn.contentstack.com` (overrides `region`). */
23
+ host?: string;
24
+ branch?: string;
25
+ /** Reference depth fetched with pages and replacements (1-5). Default 3 — raise it for deeper pages. */
26
+ includeDepth?: number;
27
+ /** The marker field uid, if your content types name it differently. */
28
+ markerField?: string;
29
+ fetch?: typeof fetch;
30
+ }
31
+ /** A Contentstack entry as the delivery API returns it (fields sit on the entry itself). */
32
+ type Entry = Record<string, unknown> & {
33
+ uid: string;
34
+ _version?: number;
35
+ _content_type_uid?: string;
36
+ };
37
+ declare function cdnHost(region?: string): string;
38
+ declare function contentstackAdapter(options: ContentstackAdapterOptions): CmsAdapter<Entry>;
39
+
40
+ export { cdnHost, contentstackAdapter };
41
+ export type { ContentstackAdapterOptions };
@@ -0,0 +1,41 @@
1
+ import { CmsAdapter } from '../index.js';
2
+
3
+ /**
4
+ * Contentstack adapter for {@link personalizeContent} / {@link personalizePage}.
5
+ *
6
+ * Talks to the Content Delivery API with plain `fetch` (no SDK dependency). Pages and replacements
7
+ * are fetched with `include_all=true`, so references come back as nested entries at any depth up to
8
+ * `includeDepth` — the page resolver walks them like any other content.
9
+ *
10
+ * Expects the one field Xenia adds to personalized content types: `xenia`, a single-line text field
11
+ * holding the marker JSON. Static replacements are named in the marker (`ids` + `ct`) and fetched
12
+ * from the delivery API in the same round as runtime ones — no Xenia call for them.
13
+ */
14
+
15
+ interface ContentstackAdapterOptions {
16
+ /** The stack API key. */
17
+ apiKey: string;
18
+ deliveryToken: string;
19
+ environment: string;
20
+ /** `us` (default), `eu`, `au`, `azure-na`, `azure-eu`, `gcp-na`, `gcp-eu`. Ignored with `host`. */
21
+ region?: string;
22
+ /** Delivery host, e.g. `eu-cdn.contentstack.com` (overrides `region`). */
23
+ host?: string;
24
+ branch?: string;
25
+ /** Reference depth fetched with pages and replacements (1-5). Default 3 — raise it for deeper pages. */
26
+ includeDepth?: number;
27
+ /** The marker field uid, if your content types name it differently. */
28
+ markerField?: string;
29
+ fetch?: typeof fetch;
30
+ }
31
+ /** A Contentstack entry as the delivery API returns it (fields sit on the entry itself). */
32
+ type Entry = Record<string, unknown> & {
33
+ uid: string;
34
+ _version?: number;
35
+ _content_type_uid?: string;
36
+ };
37
+ declare function cdnHost(region?: string): string;
38
+ declare function contentstackAdapter(options: ContentstackAdapterOptions): CmsAdapter<Entry>;
39
+
40
+ export { cdnHost, contentstackAdapter };
41
+ export type { ContentstackAdapterOptions };
@@ -0,0 +1,117 @@
1
+ import { parseMarker } from '../chunk-RC46KXDM.js';
2
+
3
+ // src/cms/contentstack.ts
4
+ var MAX_PER_QUERY = 100;
5
+ function cdnHost(region) {
6
+ const r = (region ?? "us").trim().toLowerCase();
7
+ return r === "us" || r === "na" || r === "" ? "cdn.contentstack.io" : `${r}-cdn.contentstack.com`;
8
+ }
9
+ function contentstackAdapter(options) {
10
+ const markerField = options.markerField ?? "xenia";
11
+ const depth = Math.min(Math.max(options.includeDepth ?? 3, 1), 5);
12
+ const host = options.host ?? cdnHost(options.region);
13
+ const entries = async (contentType, query, extra, locale) => {
14
+ const params = new URLSearchParams({
15
+ environment: options.environment,
16
+ include_all: "true",
17
+ include_all_depth: String(depth),
18
+ ...locale ? { locale } : {},
19
+ ...Object.keys(query).length ? { query: JSON.stringify(query) } : {},
20
+ ...extra
21
+ });
22
+ const url = `https://${host}/v3/content_types/${encodeURIComponent(contentType)}/entries?${params}`;
23
+ const res = await (options.fetch ?? fetch)(url, {
24
+ headers: {
25
+ api_key: options.apiKey,
26
+ access_token: options.deliveryToken,
27
+ ...options.branch ? { branch: options.branch } : {}
28
+ }
29
+ });
30
+ if (!res.ok) throw new Error(`Contentstack CDA ${res.status}`);
31
+ const body = await res.json();
32
+ return (body.entries ?? []).map((e) => e._content_type_uid ? e : { ...e, _content_type_uid: contentType });
33
+ };
34
+ return {
35
+ entryId(value) {
36
+ const v = value;
37
+ return v && typeof v.uid === "string" && typeof v._version === "number" && !("filename" in v) && !("is_dir" in v) ? v.uid : void 0;
38
+ },
39
+ marker: (entry) => parseMarker(entry[markerField]),
40
+ // Static replacements travel in the marker (`ids`), never as pinned links.
41
+ staticVariants: () => [],
42
+ getField: (entry, field) => entry[field],
43
+ setField(entry, field, value) {
44
+ entry[field] = value;
45
+ },
46
+ mergeItems(entry, replacement) {
47
+ for (const [key, value] of Object.entries(replacement)) {
48
+ if (Array.isArray(value) && key !== "tags") entry[key] = value;
49
+ }
50
+ },
51
+ clearMarker(entry) {
52
+ delete entry[markerField];
53
+ },
54
+ async fetchEntries(ids, locale, types) {
55
+ const byType = /* @__PURE__ */ new Map();
56
+ for (const id of ids) {
57
+ const ct = types?.[id];
58
+ if (ct) byType.set(ct, [...byType.get(ct) ?? [], id]);
59
+ }
60
+ const results = await Promise.all(
61
+ [...byType].map(
62
+ ([ct, list]) => entries(ct, { uid: { $in: list } }, { limit: String(Math.min(list.length, MAX_PER_QUERY)) }, locale)
63
+ )
64
+ );
65
+ return results.flat();
66
+ },
67
+ queryEntries(query, locale) {
68
+ const q = {};
69
+ for (const f of query.filters ?? []) Object.assign(q, filterQuery(f));
70
+ const extra = { limit: String(Math.min(query.limit, MAX_PER_QUERY)) };
71
+ if (query.order) {
72
+ const desc = query.order.startsWith("-");
73
+ extra[desc ? "desc" : "asc"] = fieldPath(desc ? query.order.slice(1) : query.order);
74
+ }
75
+ return entries(query.contentType, q, extra, locale);
76
+ },
77
+ async fetchPage(ref, locale) {
78
+ if (typeof ref === "string") {
79
+ throw new Error("contentstackAdapter: a page ref needs its content type \u2014 pass { contentType, fields }");
80
+ }
81
+ const found = await entries(ref.contentType, { ...ref.fields }, { limit: "1" }, locale);
82
+ return found[0] ?? null;
83
+ }
84
+ };
85
+ }
86
+ function fieldPath(field) {
87
+ if (field.startsWith("sys.")) return field === "sys.id" ? "uid" : field.slice(4).replace(/At$/, "_at");
88
+ return field.replace(/^fields\./, "");
89
+ }
90
+ function filterQuery(f) {
91
+ const path = fieldPath(f.field);
92
+ const num = (v) => v.trim() !== "" && !Number.isNaN(Number(v)) ? Number(v) : v;
93
+ const list = () => f.value.split(",").map((v) => v.trim()).filter(Boolean);
94
+ switch (f.op ?? "eq") {
95
+ case "ne":
96
+ return { [path]: { $ne: f.value } };
97
+ case "in":
98
+ return { [path]: { $in: list() } };
99
+ case "nin":
100
+ return { [path]: { $nin: list() } };
101
+ case "exists":
102
+ return { [path]: { $exists: f.value !== "false" } };
103
+ case "lt":
104
+ case "lte":
105
+ case "gt":
106
+ case "gte":
107
+ return { [path]: { [`$${f.op}`]: num(f.value) } };
108
+ case "match":
109
+ return { [path]: { $regex: f.value, $options: "i" } };
110
+ default:
111
+ return { [path]: f.value };
112
+ }
113
+ }
114
+
115
+ export { cdnHost, contentstackAdapter };
116
+ //# sourceMappingURL=contentstack.js.map
117
+ //# sourceMappingURL=contentstack.js.map