@contentful/optimization-node 0.1.0-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (C) 2026 Contentful Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,289 @@
1
+ <p align="center">
2
+ <a href="https://www.contentful.com/developers/docs/personalization/">
3
+ <img alt="Contentful Logo" title="Contentful" src="../../../contentful-icon.png" width="150">
4
+ </a>
5
+ </p>
6
+
7
+ <h1 align="center">Contentful Personalization & Analytics</h1>
8
+
9
+ <h3 align="center">Optimization Node SDK</h3>
10
+
11
+ <div align="center">
12
+
13
+ [Readme](./README.md) · [Reference](https://contentful.github.io/optimization) ·
14
+ [Contributing](/CONTRIBUTING.md)
15
+
16
+ </div>
17
+
18
+ > [!WARNING]
19
+ >
20
+ > The Optimization SDK Suite is currently ALPHA! Breaking changes may be published at any time.
21
+
22
+ The Optimization Node SDK implements functionality specific to Node environments, based on the
23
+ [Optimization Core Library](/universal/core/README.md). This SDK is part of the
24
+ [Contentful Optimization SDK Suite](/README.md).
25
+
26
+ <details>
27
+ <summary>Table of Contents</summary>
28
+ <!-- mtoc-start -->
29
+
30
+ - [Getting Started](#getting-started)
31
+ - [Reference Implementations](#reference-implementations)
32
+ - [Configuration](#configuration)
33
+ - [Top-level Configuration Options](#top-level-configuration-options)
34
+ - [Analytics Options](#analytics-options)
35
+ - [Event Builder Options](#event-builder-options)
36
+ - [Fetch Options](#fetch-options)
37
+ - [Personalization Options](#personalization-options)
38
+ - [Optimization Methods](#optimization-methods)
39
+ - [Personalization Data Resolution Methods](#personalization-data-resolution-methods)
40
+ - [`getCustomFlag`](#getcustomflag)
41
+ - [`personalizeEntry`](#personalizeentry)
42
+ - [`getMergeTagValue`](#getmergetagvalue)
43
+ - [Personalization and Analytics Event Methods](#personalization-and-analytics-event-methods)
44
+ - [`identify`](#identify)
45
+ - [`page`](#page)
46
+ - [`track`](#track)
47
+ - [`trackComponentView`](#trackcomponentview)
48
+ - [`trackFlagView`](#trackflagview)
49
+ - [Interceptors](#interceptors)
50
+ - [Life-cycle Interceptors](#life-cycle-interceptors)
51
+
52
+ <!-- mtoc-end -->
53
+ </details>
54
+
55
+ ## Getting Started
56
+
57
+ Install using an NPM-compatible package manager, pnpm for example:
58
+
59
+ ```sh
60
+ pnpm install @contentful/optimization-node
61
+ ```
62
+
63
+ Import the Optimization class; both CJS and ESM module systems are supported, ESM preferred:
64
+
65
+ ```ts
66
+ import Optimization from '@contentful/optimization-node'
67
+ ```
68
+
69
+ Configure and initialize the Optimization Node SDK:
70
+
71
+ ```ts
72
+ const optimization = new Optimization({ clientId: 'abc123' })
73
+ ```
74
+
75
+ ## Reference Implementations
76
+
77
+ Reference implementations illustrate how the SDK may be used under common scenarios, as well as
78
+ select less-common scenarios, with the most basic example solution possible.
79
+
80
+ - [Node SSR Only](/implementations/node-ssr-only/README.md): Example application that uses the Node
81
+ SDK to render a personalized Web page
82
+ - [Node SSR + Web Vanilla](/implementations/node-ssr-web-vanilla/README.md): Example application
83
+ demonstrating simple profile synchronization between the Node and [Web](../web/README.md) SDKs via
84
+ cookie
85
+
86
+ ## Configuration
87
+
88
+ ### Top-level Configuration Options
89
+
90
+ | Option | Required? | Default | Description |
91
+ | ----------------- | --------- | ----------------------------- | ------------------------------------------------------------------------------ |
92
+ | `analytics` | No | See "Analytics Options" | Configuration specific to the Analytics/Insights API |
93
+ | `app` | No | `undefined` | The application definition used to attribute events to a specific consumer app |
94
+ | `clientId` | Yes | N/A | The Ninetailed API Key which can be found in the Ninetailed Admin app |
95
+ | `environment` | No | `'main'` | The Ninetailed environment configured in the Ninetailed Admin app |
96
+ | `eventBuilder` | No | See "Event Builder Options" | Event builder configuration (channel/library metadata, etc.) |
97
+ | `fetchOptions` | No | See "Fetch Options" | Configuration for Fetch timeout and retry functionality |
98
+ | `logLevel` | No | `'error'` | Minimum log level for the default console sin |
99
+ | `personalization` | No | See "Personalization Options" | Configuration specific to the Personalization/Experience API |
100
+
101
+ ### Analytics Options
102
+
103
+ | Option | Required? | Default | Description |
104
+ | --------- | --------- | ------------------------------------------ | ----------------------------- |
105
+ | `baseUrl` | No | `'https://ingest.insights.ninetailed.co/'` | Base URL for the Insights API |
106
+
107
+ ### Event Builder Options
108
+
109
+ Event builder options should only be supplied when building an SDK on top of the Optimization Node
110
+ SDK or any of its descendent SDKs.
111
+
112
+ | Option | Required? | Default | Description |
113
+ | --------- | --------- | ----------------------------------------------------- | ---------------------------------------------------------------------------------- |
114
+ | `channel` | No | `'server'` | The channel that identifies where events originate from (e.g. `'web'`, `'mobile'`) |
115
+ | `library` | No | `{ name: 'Optimization Node API', version: '0.0.0' }` | The client library metadata that is attached to all events |
116
+
117
+ ### Fetch Options
118
+
119
+ Fetch options allow for configuration of a Fetch API-compatible fetch method and the retry/timeout
120
+ logic integrated into the Optimization API Client. Specify the `fetchMethod` when the host
121
+ application environment does not offer a `fetch` method that is compatible with the standard Fetch
122
+ API in its global scope.
123
+
124
+ | Option | Required? | Default | Description |
125
+ | ------------------ | --------- | ----------- | --------------------------------------------------------------------- |
126
+ | `fetchMethod` | No | `undefined` | Signature of a fetch method used by the API clients |
127
+ | `intervalTimeout` | No | `0` | Delay (in milliseconds) between retry attempts |
128
+ | `onFailedAttempt` | No | `undefined` | Callback invoked whenever a retry attempt fails |
129
+ | `onRequestTimeout` | No | `undefined` | Callback invoked when a request exceeds the configured timeout |
130
+ | `requestTimeout` | No | `3000` | Maximum time (in milliseconds) to wait for a response before aborting |
131
+ | `retries` | No | `1` | Maximum number of retry attempts |
132
+
133
+ Configuration method signatures:
134
+
135
+ - `fetchMethod`: `(url: string | URL, init: RequestInit) => Promise<Response>`
136
+ - `onFailedAttempt` and `onRequestTimeout`: `(options: FetchMethodCallbackOptions) => void`
137
+
138
+ ### Personalization Options
139
+
140
+ | Option | Required? | Default | Description |
141
+ | ----------------- | --------- | ------------------------------------- | ------------------------------------------------------------------- |
142
+ | `baseUrl` | No | `'https://experience.ninetailed.co/'` | Base URL for the Experience API |
143
+ | `enabledFeatures` | No | `['ip-enrichment', 'location']` | Enabled features which the API may use for each request |
144
+ | `ip` | No | `undefined` | IP address to override the API behavior for IP analysis |
145
+ | `locale` | No | `'en-US'` (in API) | Locale used to translate `location.city` and `location.country` |
146
+ | `plainText` | No | `false` | Sends performance-critical endpoints in plain text |
147
+ | `preflight` | No | `false` | Instructs the API to aggregate a new profile state but not store it |
148
+
149
+ ## Optimization Methods
150
+
151
+ Arguments marked with an asterisk (\*) are always required.
152
+
153
+ ### Personalization Data Resolution Methods
154
+
155
+ #### `getCustomFlag`
156
+
157
+ Get the specified Custom Flag's value from the provided changes array.
158
+
159
+ Arguments:
160
+
161
+ - `name`\*: The name/key of the Custom Flag
162
+ - `changes`: Changes array
163
+
164
+ Returns:
165
+
166
+ - The resolved value for the specified Custom Flag, or `undefined` if it cannot be found.
167
+
168
+ > [!NOTE]
169
+ >
170
+ > If the `changes` argument is omitted, the method will return `undefined`.
171
+
172
+ #### `personalizeEntry`
173
+
174
+ Resolve a baseline Contentful entry to a personalized variant using the provided selected
175
+ personalizations.
176
+
177
+ Type arguments:
178
+
179
+ - `S`: Entry skeleton type
180
+ - `M`: Chain modifiers
181
+ - `L`: Locale code
182
+
183
+ Arguments:
184
+
185
+ - `entry`\*: The entry to personalize
186
+ - `personalizations`: Selected personalizations
187
+
188
+ Returns:
189
+
190
+ - The resolved personalized entry variant, or the supplied baseline entry if baseline is the
191
+ selected variant or a variant cannot be found.
192
+
193
+ > [!NOTE]
194
+ >
195
+ > If the `personalizations` argument is omitted, the method will return the baseline entry.
196
+
197
+ #### `getMergeTagValue`
198
+
199
+ Resolve a "Merge Tag" to a value based on the provided profile. A "Merge Tag" is a special Rich Text
200
+ fragment supported by Contentful that specifies a profile data member to be injected into the Rich
201
+ Text when rendered.
202
+
203
+ Arguments:
204
+
205
+ - `embeddedNodeEntryTarget`\*: The merge tag entry node to resolve
206
+ - `profile`: The user profile
207
+
208
+ > [!NOTE]
209
+ >
210
+ > If the `profile` argument is omitted, the method will return the merge tag's fallback value.
211
+
212
+ ### Personalization and Analytics Event Methods
213
+
214
+ Each method except `trackFlagView` may return an `OptimizationData` object containing:
215
+
216
+ - `changes`: Currently used for Custom Flags
217
+ - `personalizations`: Selected personalizations for the profile
218
+ - `profile`: Profile associated with the evaluated events
219
+
220
+ #### `identify`
221
+
222
+ Identify the current profile/visitor to associate traits with a profile.
223
+
224
+ Arguments:
225
+
226
+ - `payload`\*: Identify event builder arguments object, including an optional `profile` property
227
+ with a `PartialProfile` value that requires only an `id`
228
+
229
+ #### `page`
230
+
231
+ Record a personalization page view.
232
+
233
+ Arguments:
234
+
235
+ - `payload`\*: Page view event builder arguments object, including an optional `profile` property
236
+ with a `PartialProfile` value that requires only an `id`
237
+
238
+ #### `track`
239
+
240
+ Record a personalization custom track event.
241
+
242
+ Arguments:
243
+
244
+ - `payload`\*: Track event builder arguments object, including an optional `profile` property with a
245
+ `PartialProfile` value that requires only an `id`
246
+
247
+ #### `trackComponentView`
248
+
249
+ Record an analytics component view event. When the payload marks the component as "sticky", an
250
+ additional personalization component view is recorded. This method only returns `OptimizationData`
251
+ when the component is marked as "sticky".
252
+
253
+ Arguments:
254
+
255
+ - `payload`\*: Component view event builder arguments object, including an optional `profile`
256
+ property with a `PartialProfile` value that requires only an `id`
257
+
258
+ #### `trackFlagView`
259
+
260
+ Track a feature flag view via analytics. This is functionally the same as a non-sticky component
261
+ view event.
262
+
263
+ Arguments:
264
+
265
+ - `payload`\*: Component view event builder arguments object, including an optional `profile`
266
+ property with a `PartialProfile` value that requires only an `id`
267
+
268
+ ## Interceptors
269
+
270
+ Interceptors may be used to read and/or modify data flowing through the Core SDK.
271
+
272
+ ### Life-cycle Interceptors
273
+
274
+ - `event`: Intercepts an event's data _before_ it is queued and/or emitted
275
+ - `state`: Intercepts state data retrieved from an Experience API call _before_ updating the SDK's
276
+ internal state
277
+
278
+ Example interceptor usage:
279
+
280
+ ```ts
281
+ optimization.interceptors.event((event) => {
282
+ event.properties.timestamp = new Date().toISOString()
283
+ })
284
+ ```
285
+
286
+ > [!WARNING]
287
+ >
288
+ > Interceptors are intended to enable low-level interoperability; to simply read and react to
289
+ > Optimization SDK events, use the `states` observables.
package/dist/index.cjs ADDED
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ var __webpack_modules__ = {
3
+ "./src/Optimization.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
4
+ __webpack_require__.d(__webpack_exports__, {
5
+ A: ()=>src_Optimization
6
+ });
7
+ var optimization_core_ = __webpack_require__("@contentful/optimization-core");
8
+ const external_es_toolkit_namespaceObject = require("es-toolkit");
9
+ var global_constants = __webpack_require__("./src/global-constants.ts");
10
+ function mergeConfig(config) {
11
+ const { app, ...restConfig } = config;
12
+ const defaultConfig = {
13
+ eventBuilder: {
14
+ app,
15
+ channel: 'server',
16
+ library: {
17
+ name: 'Optimization Node API',
18
+ version: global_constants.R
19
+ }
20
+ }
21
+ };
22
+ return (0, external_es_toolkit_namespaceObject.merge)(defaultConfig, restConfig);
23
+ }
24
+ class Optimization extends optimization_core_.CoreStateless {
25
+ constructor(config){
26
+ const mergedConfig = mergeConfig(config);
27
+ super(mergedConfig);
28
+ }
29
+ }
30
+ const src_Optimization = Optimization;
31
+ },
32
+ "./src/global-constants.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
33
+ __webpack_require__.d(__webpack_exports__, {
34
+ R: ()=>OPTIMIZATION_NODE_SDK_VERSION,
35
+ T: ()=>_contentful_optimization_core__rspack_import_0.ANONYMOUS_ID_COOKIE
36
+ });
37
+ var _contentful_optimization_core__rspack_import_0 = __webpack_require__("@contentful/optimization-core");
38
+ const OPTIMIZATION_NODE_SDK_VERSION = "0.1.0-alpha";
39
+ },
40
+ "@contentful/optimization-core" (module) {
41
+ module.exports = require("@contentful/optimization-core");
42
+ }
43
+ };
44
+ var __webpack_module_cache__ = {};
45
+ function __webpack_require__(moduleId) {
46
+ var cachedModule = __webpack_module_cache__[moduleId];
47
+ if (void 0 !== cachedModule) return cachedModule.exports;
48
+ var module = __webpack_module_cache__[moduleId] = {
49
+ exports: {}
50
+ };
51
+ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
52
+ return module.exports;
53
+ }
54
+ (()=>{
55
+ __webpack_require__.n = (module)=>{
56
+ var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
57
+ __webpack_require__.d(getter, {
58
+ a: getter
59
+ });
60
+ return getter;
61
+ };
62
+ })();
63
+ (()=>{
64
+ __webpack_require__.d = (exports1, definition)=>{
65
+ for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
66
+ enumerable: true,
67
+ get: definition[key]
68
+ });
69
+ };
70
+ })();
71
+ (()=>{
72
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
73
+ })();
74
+ (()=>{
75
+ __webpack_require__.r = (exports1)=>{
76
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
77
+ value: 'Module'
78
+ });
79
+ Object.defineProperty(exports1, '__esModule', {
80
+ value: true
81
+ });
82
+ };
83
+ })();
84
+ var __webpack_exports__ = {};
85
+ (()=>{
86
+ __webpack_require__.r(__webpack_exports__);
87
+ __webpack_require__.d(__webpack_exports__, {
88
+ ANONYMOUS_ID_COOKIE: ()=>_global_constants__rspack_import_2.T,
89
+ OPTIMIZATION_NODE_SDK_VERSION: ()=>_global_constants__rspack_import_2.R,
90
+ default: ()=>__rspack_default_export
91
+ });
92
+ var _Optimization__rspack_import_0 = __webpack_require__("./src/Optimization.ts");
93
+ var _contentful_optimization_core__rspack_import_1 = __webpack_require__("@contentful/optimization-core");
94
+ var __rspack_reexport = {};
95
+ for(const __rspack_import_key in _contentful_optimization_core__rspack_import_1)if ("default" !== __rspack_import_key) __rspack_reexport[__rspack_import_key] = ()=>_contentful_optimization_core__rspack_import_1[__rspack_import_key];
96
+ __webpack_require__.d(__webpack_exports__, __rspack_reexport);
97
+ var _global_constants__rspack_import_2 = __webpack_require__("./src/global-constants.ts");
98
+ const __rspack_default_export = _Optimization__rspack_import_0.A;
99
+ })();
100
+ exports.ANONYMOUS_ID_COOKIE = __webpack_exports__.ANONYMOUS_ID_COOKIE;
101
+ exports.OPTIMIZATION_NODE_SDK_VERSION = __webpack_exports__.OPTIMIZATION_NODE_SDK_VERSION;
102
+ exports["default"] = __webpack_exports__["default"];
103
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
104
+ "ANONYMOUS_ID_COOKIE",
105
+ "OPTIMIZATION_NODE_SDK_VERSION",
106
+ "default"
107
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
108
+ Object.defineProperty(exports, '__esModule', {
109
+ value: true
110
+ });
111
+
112
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../src/Optimization.ts","../src/global-constants.ts","webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../src/index.ts"],"sourcesContent":["import { type App, type CoreStatelessConfig, CoreStateless } from '@contentful/optimization-core'\nimport { merge } from 'es-toolkit'\nimport { OPTIMIZATION_NODE_SDK_VERSION } from './global-constants'\n\n/**\n * Configuration for the Node-specific Optimization SDK.\n *\n * @public\n * @remarks\n * This configuration extends {@link CoreConfig} but allows partial overrides\n * of the event-builder configuration. SDKs commonly inject their own library\n * metadata or channel definitions.\n */\nexport interface OptimizationNodeConfig extends Omit<CoreStatelessConfig, 'eventBuilder'> {\n /**\n * The application definition used to attribute events to a specific consumer app.\n *\n * @remarks\n * When not provided, events will not contain app metadata in their context.\n */\n app?: App\n\n /**\n * Partial overrides for the event builder configuration.\n *\n * @remarks\n * Any provided fields are merged with the default Node SDK metadata.\n * This differs from {@link CoreConfig.eventBuilder}, which expects a\n * full configuration object.\n */\n eventBuilder?: Partial<Omit<CoreStatelessConfig['eventBuilder'], 'app'>>\n}\n\n/**\n * Merge user-supplied configuration with defaults for the Node SDK.\n *\n * @param config - The input configuration supplied by the caller.\n * @returns A fully composed {@link CoreConfig} object suitable for\n * constructing the core runtime.\n *\n * @internal\n * @remarks\n * Ensures that the Node SDK always identifies itself via a `server` channel\n * and a `library` metadata block unless explicitly overridden.\n */\nfunction mergeConfig(config: OptimizationNodeConfig): CoreStatelessConfig {\n const { app, ...restConfig } = config\n\n const defaultConfig: Partial<CoreStatelessConfig> = {\n eventBuilder: {\n app,\n channel: 'server',\n library: { name: 'Optimization Node API', version: OPTIMIZATION_NODE_SDK_VERSION },\n },\n }\n return merge(defaultConfig, restConfig)\n}\n\n/**\n * Node-specific Optimization SDK built on {@link CoreStateless}.\n *\n * @public\n * @remarks\n * This class adapts the stateless Optimization Core for Node runtimes by\n * applying environment-appropriate defaults (e.g., server channel, Node SDK\n * library metadata). No analytics or personalization behavior is modified—\n * only configuration defaults differ.\n *\n * @example\n * ```ts\n * import Optimization from '@contentful/optimization-node'\n *\n * const sdk = new Optimization({\n * clientId: 'abc-123',\n * environment: 'main',\n * logLevel: 'info',\n * })\n *\n * await sdk.track({ event: 'server_event', properties: { id: 1 } })\n * ```\n */\nclass Optimization extends CoreStateless {\n /**\n * Create an instance of the Node SDK with merged defaults.\n *\n * @param config - Partial Node-specific configuration. Any eventBuilder\n * fields provided are merged with Node's defaults.\n */\n constructor(config: OptimizationNodeConfig) {\n const mergedConfig: CoreStatelessConfig = mergeConfig(config)\n\n super(mergedConfig)\n }\n}\n\nexport default Optimization\n","// eslint-disable-next-line @typescript-eslint/naming-convention -- Replaced at build-time\ndeclare const __OPTIMIZATION_VERSION__: string | undefined\n\nexport const OPTIMIZATION_NODE_SDK_VERSION =\n typeof __OPTIMIZATION_VERSION__ === 'string' ? __OPTIMIZATION_VERSION__ : '0.0.0'\n\n/**\n * Re-export of the anonymous-ID cookie name used by the Optimization Core.\n *\n * @public\n * @remarks\n * This constant is surfaced here to provide a stable import path for Node SDK\n * consumers. It represents the cookie key used by the Optimization Framework\n * to persist an anonymous identifier for tracking personalization and analytics\n * events when no explicit profile is known.\n *\n * @see {@link ANONYMOUS_ID_COOKIE} in `@contentful/optimization-core` for the\n * authoritative definition and documentation.\n *\n * @example\n * ```ts\n * import { ANONYMOUS_ID_COOKIE } from '@contentful/optimization-node'\n * const id = request.cookies[ANONYMOUS_ID_COOKIE]\n * ```\n */\nexport { ANONYMOUS_ID_COOKIE } from '@contentful/optimization-core'\n","// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import Optimization from './Optimization'\n\nexport * from '@contentful/optimization-core'\n\nexport * from './global-constants'\nexport * from './Optimization'\n\nexport default Optimization\n"],"names":["mergeConfig","config","app","restConfig","defaultConfig","OPTIMIZATION_NODE_SDK_VERSION","merge","Optimization","CoreStateless","mergedConfig","__OPTIMIZATION_VERSION__","__webpack_require__","module","getter","definition","key","Object","obj","prop","Symbol"],"mappings":";;;;;;;;;QA6CA,SAASA,YAAYC,MAA8B;YACjD,MAAM,EAAEC,GAAG,EAAE,GAAGC,YAAY,GAAGF;YAE/B,MAAMG,gBAA8C;gBAClD,cAAc;oBACZF;oBACA,SAAS;oBACT,SAAS;wBAAE,MAAM;wBAAyB,SAASG,iBAAAA,CAA6BA;oBAAC;gBACnF;YACF;YACA,OAAOC,AAAAA,IAAAA,oCAAAA,KAAAA,AAAAA,EAAMF,eAAeD;QAC9B;QAyBA,MAAMI,qBAAqBC,mBAAAA,aAAaA;YAOtC,YAAYP,MAA8B,CAAE;gBAC1C,MAAMQ,eAAoCT,YAAYC;gBAEtD,KAAK,CAACQ;YACR;QACF;QAEA,yBAAeF;;;;;;;;QC5FR,MAAMF,gCACoCK;;;;;;;;;;;;;;;;;ICHjDC,oBAAoB,CAAC,GAAG,CAACC;QACxB,IAAIC,SAASD,UAAUA,OAAO,UAAU,GACvC,IAAOA,MAAM,CAAC,UAAU,GACxB,IAAOA;QACRD,oBAAoB,CAAC,CAACE,QAAQ;YAAE,GAAGA;QAAO;QAC1C,OAAOA;IACR;;;ICPAF,oBAAoB,CAAC,GAAG,CAAC,UAASG;QACjC,IAAI,IAAIC,OAAOD,WACR,IAAGH,oBAAoB,CAAC,CAACG,YAAYC,QAAQ,CAACJ,oBAAoB,CAAC,CAAC,UAASI,MACzEC,OAAO,cAAc,CAAC,UAASD,KAAK;YAAE,YAAY;YAAM,KAAKD,UAAU,CAACC,IAAI;QAAC;IAGzF;;;ICNAJ,oBAAoB,CAAC,GAAG,CAACM,KAAKC,OAAUF,OAAO,SAAS,CAAC,cAAc,CAAC,IAAI,CAACC,KAAKC;;;ICClFP,oBAAoB,CAAC,GAAG,CAAC;QACxB,IAAG,AAAkB,MAAlB,OAAOQ,UAA0BA,OAAO,WAAW,EACrDH,OAAO,cAAc,CAAC,UAASG,OAAO,WAAW,EAAE;YAAE,OAAO;QAAS;QAEtEH,OAAO,cAAc,CAAC,UAAS,cAAc;YAAE,OAAO;QAAK;IAC5D;;;;;;;;;;;;;;;;ICCA,gCAAeT,+BAAAA,CAAYA"}
@@ -0,0 +1,75 @@
1
+ import { ANONYMOUS_ID_COOKIE } from '@contentful/optimization-core';
2
+ import { App } from '@contentful/optimization-core';
3
+ import { CoreStateless } from '@contentful/optimization-core';
4
+ import { CoreStatelessConfig } from '@contentful/optimization-core';
5
+
6
+ export { ANONYMOUS_ID_COOKIE }
7
+
8
+ /**
9
+ * Node-specific Optimization SDK built on {@link CoreStateless}.
10
+ *
11
+ * @public
12
+ * @remarks
13
+ * This class adapts the stateless Optimization Core for Node runtimes by
14
+ * applying environment-appropriate defaults (e.g., server channel, Node SDK
15
+ * library metadata). No analytics or personalization behavior is modified—
16
+ * only configuration defaults differ.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import Optimization from '@contentful/optimization-node'
21
+ *
22
+ * const sdk = new Optimization({
23
+ * clientId: 'abc-123',
24
+ * environment: 'main',
25
+ * logLevel: 'info',
26
+ * })
27
+ *
28
+ * await sdk.track({ event: 'server_event', properties: { id: 1 } })
29
+ * ```
30
+ */
31
+ declare class Optimization extends CoreStateless {
32
+ /**
33
+ * Create an instance of the Node SDK with merged defaults.
34
+ *
35
+ * @param config - Partial Node-specific configuration. Any eventBuilder
36
+ * fields provided are merged with Node's defaults.
37
+ */
38
+ constructor(config: OptimizationNodeConfig);
39
+ }
40
+ export default Optimization;
41
+
42
+ export declare const OPTIMIZATION_NODE_SDK_VERSION: string;
43
+
44
+ /**
45
+ * Configuration for the Node-specific Optimization SDK.
46
+ *
47
+ * @public
48
+ * @remarks
49
+ * This configuration extends {@link CoreConfig} but allows partial overrides
50
+ * of the event-builder configuration. SDKs commonly inject their own library
51
+ * metadata or channel definitions.
52
+ */
53
+ export declare interface OptimizationNodeConfig extends Omit<CoreStatelessConfig, 'eventBuilder'> {
54
+ /**
55
+ * The application definition used to attribute events to a specific consumer app.
56
+ *
57
+ * @remarks
58
+ * When not provided, events will not contain app metadata in their context.
59
+ */
60
+ app?: App;
61
+ /**
62
+ * Partial overrides for the event builder configuration.
63
+ *
64
+ * @remarks
65
+ * Any provided fields are merged with the default Node SDK metadata.
66
+ * This differs from {@link CoreConfig.eventBuilder}, which expects a
67
+ * full configuration object.
68
+ */
69
+ eventBuilder?: Partial<Omit<CoreStatelessConfig['eventBuilder'], 'app'>>;
70
+ }
71
+
72
+
73
+ export * from "@contentful/optimization-core";
74
+
75
+ export { }
package/dist/index.mjs ADDED
@@ -0,0 +1,31 @@
1
+ import * as __rspack_external__contentful_optimization_core_7d4758c6 from "@contentful/optimization-core";
2
+ import { merge } from "es-toolkit";
3
+ const OPTIMIZATION_NODE_SDK_VERSION = "0.1.0-alpha";
4
+ function mergeConfig(config) {
5
+ const { app, ...restConfig } = config;
6
+ const defaultConfig = {
7
+ eventBuilder: {
8
+ app,
9
+ channel: 'server',
10
+ library: {
11
+ name: 'Optimization Node API',
12
+ version: OPTIMIZATION_NODE_SDK_VERSION
13
+ }
14
+ }
15
+ };
16
+ return merge(defaultConfig, restConfig);
17
+ }
18
+ class Optimization extends __rspack_external__contentful_optimization_core_7d4758c6.CoreStateless {
19
+ constructor(config){
20
+ const mergedConfig = mergeConfig(config);
21
+ super(mergedConfig);
22
+ }
23
+ }
24
+ const src_Optimization = Optimization;
25
+ const src = src_Optimization;
26
+ var ANONYMOUS_ID_COOKIE = __rspack_external__contentful_optimization_core_7d4758c6.ANONYMOUS_ID_COOKIE;
27
+ export * from "@contentful/optimization-core";
28
+ export default src;
29
+ export { ANONYMOUS_ID_COOKIE, OPTIMIZATION_NODE_SDK_VERSION };
30
+
31
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":["../src/global-constants.ts","../src/Optimization.ts","../src/index.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/naming-convention -- Replaced at build-time\ndeclare const __OPTIMIZATION_VERSION__: string | undefined\n\nexport const OPTIMIZATION_NODE_SDK_VERSION =\n typeof __OPTIMIZATION_VERSION__ === 'string' ? __OPTIMIZATION_VERSION__ : '0.0.0'\n\n/**\n * Re-export of the anonymous-ID cookie name used by the Optimization Core.\n *\n * @public\n * @remarks\n * This constant is surfaced here to provide a stable import path for Node SDK\n * consumers. It represents the cookie key used by the Optimization Framework\n * to persist an anonymous identifier for tracking personalization and analytics\n * events when no explicit profile is known.\n *\n * @see {@link ANONYMOUS_ID_COOKIE} in `@contentful/optimization-core` for the\n * authoritative definition and documentation.\n *\n * @example\n * ```ts\n * import { ANONYMOUS_ID_COOKIE } from '@contentful/optimization-node'\n * const id = request.cookies[ANONYMOUS_ID_COOKIE]\n * ```\n */\nexport { ANONYMOUS_ID_COOKIE } from '@contentful/optimization-core'\n","import { type App, type CoreStatelessConfig, CoreStateless } from '@contentful/optimization-core'\nimport { merge } from 'es-toolkit'\nimport { OPTIMIZATION_NODE_SDK_VERSION } from './global-constants'\n\n/**\n * Configuration for the Node-specific Optimization SDK.\n *\n * @public\n * @remarks\n * This configuration extends {@link CoreConfig} but allows partial overrides\n * of the event-builder configuration. SDKs commonly inject their own library\n * metadata or channel definitions.\n */\nexport interface OptimizationNodeConfig extends Omit<CoreStatelessConfig, 'eventBuilder'> {\n /**\n * The application definition used to attribute events to a specific consumer app.\n *\n * @remarks\n * When not provided, events will not contain app metadata in their context.\n */\n app?: App\n\n /**\n * Partial overrides for the event builder configuration.\n *\n * @remarks\n * Any provided fields are merged with the default Node SDK metadata.\n * This differs from {@link CoreConfig.eventBuilder}, which expects a\n * full configuration object.\n */\n eventBuilder?: Partial<Omit<CoreStatelessConfig['eventBuilder'], 'app'>>\n}\n\n/**\n * Merge user-supplied configuration with defaults for the Node SDK.\n *\n * @param config - The input configuration supplied by the caller.\n * @returns A fully composed {@link CoreConfig} object suitable for\n * constructing the core runtime.\n *\n * @internal\n * @remarks\n * Ensures that the Node SDK always identifies itself via a `server` channel\n * and a `library` metadata block unless explicitly overridden.\n */\nfunction mergeConfig(config: OptimizationNodeConfig): CoreStatelessConfig {\n const { app, ...restConfig } = config\n\n const defaultConfig: Partial<CoreStatelessConfig> = {\n eventBuilder: {\n app,\n channel: 'server',\n library: { name: 'Optimization Node API', version: OPTIMIZATION_NODE_SDK_VERSION },\n },\n }\n return merge(defaultConfig, restConfig)\n}\n\n/**\n * Node-specific Optimization SDK built on {@link CoreStateless}.\n *\n * @public\n * @remarks\n * This class adapts the stateless Optimization Core for Node runtimes by\n * applying environment-appropriate defaults (e.g., server channel, Node SDK\n * library metadata). No analytics or personalization behavior is modified—\n * only configuration defaults differ.\n *\n * @example\n * ```ts\n * import Optimization from '@contentful/optimization-node'\n *\n * const sdk = new Optimization({\n * clientId: 'abc-123',\n * environment: 'main',\n * logLevel: 'info',\n * })\n *\n * await sdk.track({ event: 'server_event', properties: { id: 1 } })\n * ```\n */\nclass Optimization extends CoreStateless {\n /**\n * Create an instance of the Node SDK with merged defaults.\n *\n * @param config - Partial Node-specific configuration. Any eventBuilder\n * fields provided are merged with Node's defaults.\n */\n constructor(config: OptimizationNodeConfig) {\n const mergedConfig: CoreStatelessConfig = mergeConfig(config)\n\n super(mergedConfig)\n }\n}\n\nexport default Optimization\n","import Optimization from './Optimization'\n\nexport * from '@contentful/optimization-core'\n\nexport * from './global-constants'\nexport * from './Optimization'\n\nexport default Optimization\n"],"names":["OPTIMIZATION_NODE_SDK_VERSION","__OPTIMIZATION_VERSION__","mergeConfig","config","app","restConfig","defaultConfig","merge","Optimization","CoreStateless","mergedConfig"],"mappings":";;AAGO,MAAMA,gCACoCC;ACyCjD,SAASC,YAAYC,MAA8B;IACjD,MAAM,EAAEC,GAAG,EAAE,GAAGC,YAAY,GAAGF;IAE/B,MAAMG,gBAA8C;QAClD,cAAc;YACZF;YACA,SAAS;YACT,SAAS;gBAAE,MAAM;gBAAyB,SAASJ;YAA8B;QACnF;IACF;IACA,OAAOO,MAAMD,eAAeD;AAC9B;AAyBA,MAAMG,qBAAqBC,yDAAAA,aAAaA;IAOtC,YAAYN,MAA8B,CAAE;QAC1C,MAAMO,eAAoCR,YAAYC;QAEtD,KAAK,CAACO;IACR;AACF;AAEA,yBAAeF;ACxFf,YAAeA"}
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@contentful/optimization-node",
3
+ "version": "0.1.0-alpha",
4
+ "license": "MIT",
5
+ "type": "commonjs",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.mjs",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "require": "./dist/index.cjs",
13
+ "import": "./dist/index.mjs"
14
+ },
15
+ "./package.json": "./package.json"
16
+ },
17
+ "files": [
18
+ "dist/**/*"
19
+ ],
20
+ "dependencies": {
21
+ "es-toolkit": "^1.39.10",
22
+ "@contentful/optimization-core": "0.1.0-alpha"
23
+ }
24
+ }