@contentful/optimization-core 0.1.0-alpha10 → 0.1.0-alpha11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,17 +1,17 @@
1
1
  <p align="center">
2
2
  <a href="https://www.contentful.com/developers/docs/personalization/">
3
- <img alt="Contentful Logo" title="Contentful" src="../../contentful-icon.png" width="150">
3
+ <img alt="Contentful Logo" title="Contentful" src="https://raw.githubusercontent.com/contentful/optimization/v0.1.0-alpha11/contentful-icon.png" width="150">
4
4
  </a>
5
5
  </p>
6
6
 
7
- <h1 align="center">Contentful Personalization & Analytics</h1>
7
+ <h1 align="center">Contentful Optimization Core SDK</h1>
8
8
 
9
9
  <h3 align="center">Optimization Core SDK</h3>
10
10
 
11
11
  <div align="center">
12
12
 
13
- [Readme](./README.md) · [Reference](https://contentful.github.io/optimization) ·
14
- [Contributing](../../CONTRIBUTING.md)
13
+ [Guides](https://contentful.github.io/optimization/documents/Guides.html) ·
14
+ [Reference](https://contentful.github.io/optimization) · [Contributing](https://github.com/contentful/optimization/blob/v0.1.0-alpha11/CONTRIBUTING.md)
15
15
 
16
16
  </div>
17
17
 
@@ -31,22 +31,23 @@ other SDKs descend from the Core SDK.
31
31
  - [Working with Stateful Core](#working-with-stateful-core)
32
32
  - [Configuration](#configuration)
33
33
  - [Top-level Configuration Options](#top-level-configuration-options)
34
- - [Analytics Options](#analytics-options)
34
+ - [API Options](#api-options)
35
35
  - [Event Builder Options](#event-builder-options)
36
36
  - [Fetch Options](#fetch-options)
37
- - [Personalization Options](#personalization-options)
37
+ - [Queue Policy Options](#queue-policy-options)
38
38
  - [Core Methods](#core-methods)
39
- - [Personalization Data Resolution Methods](#personalization-data-resolution-methods)
40
- - [`getCustomFlag`](#getcustomflag)
41
- - [`personalizeEntry`](#personalizeentry)
39
+ - [Optimization Data Resolution Methods](#optimization-data-resolution-methods)
40
+ - [`getFlag`](#getflag)
41
+ - [`resolveOptimizedEntry`](#resolveoptimizedentry)
42
42
  - [`getMergeTagValue`](#getmergetagvalue)
43
- - [Personalization and Analytics Event Methods](#personalization-and-analytics-event-methods)
43
+ - [Event Methods](#event-methods)
44
44
  - [`identify`](#identify)
45
45
  - [`page`](#page)
46
46
  - [`screen`](#screen)
47
47
  - [`track`](#track)
48
- - [`trackComponentView`](#trackcomponentview)
49
- - [`trackComponentClick`](#trackcomponentclick)
48
+ - [`trackView`](#trackview)
49
+ - [`trackClick`](#trackclick)
50
+ - [`trackHover`](#trackhover)
50
51
  - [`trackFlagView`](#trackflagview)
51
52
  - [Stateful-only Core Methods](#stateful-only-core-methods)
52
53
  - [`consent`](#consent)
@@ -54,7 +55,7 @@ other SDKs descend from the Core SDK.
54
55
  - [`flush`](#flush)
55
56
  - [`destroy`](#destroy)
56
57
  - [`registerPreviewPanel` (preview tooling only)](#registerpreviewpanel-preview-tooling-only)
57
- - [Stateful-only Core Properties](#stateful-only-core-properties)
58
+ - [Core States (`CoreStateful` only)](#core-states-corestateful-only)
58
59
  - [Interceptors](#interceptors)
59
60
  - [Life-cycle Interceptors](#life-cycle-interceptors)
60
61
 
@@ -81,9 +82,9 @@ import { CoreStateless } from '@contentful/optimization-core'
81
82
  Configure and initialize the Core SDK:
82
83
 
83
84
  ```ts
84
- const optimization = new CoreStateful({ clientId: 'abc123' })
85
- // or
86
- const optimization = new CoreStateless({ clientId: 'abc123' })
85
+ const statefulOptimization = new CoreStateful({ clientId: 'abc123' })
86
+ const statelessOptimization = new CoreStateless({ clientId: 'abc123' })
87
+ const requestOptimization = statelessOptimization.forRequest()
87
88
  ```
88
89
 
89
90
  ## Working with Stateless Core
@@ -96,6 +97,9 @@ In stateless environments, Core will not maintain any internal state, which incl
96
97
  These concerns should be handled by consumers to fit their specific architectural and design
97
98
  specifications.
98
99
 
100
+ Request-emitting methods in `CoreStateless` are bound per request via
101
+ `optimization.forRequest(...)`.
102
+
99
103
  ## Working with Stateful Core
100
104
 
101
105
  The `CoreStateful` class is intended to be used as the basis for SDKs that would run in stateful
@@ -114,15 +118,14 @@ exposed externally as read-only observables.
114
118
 
115
119
  ### Top-level Configuration Options
116
120
 
117
- | Option | Required? | Default | Description |
118
- | ----------------- | --------- | ----------------------------- | ------------------------------------------------------------ |
119
- | `analytics` | No | See "Analytics Options" | Configuration specific to the Analytics/Insights API |
120
- | `clientId` | Yes | N/A | The Optimization API key |
121
- | `environment` | No | `'main'` | The environment identifier |
122
- | `eventBuilder` | No | See "Event Builder Options" | Event builder configuration (channel/library metadata, etc.) |
123
- | `fetchOptions` | No | See "Fetch Options" | Configuration for Fetch timeout and retry functionality |
124
- | `logLevel` | No | `'error'` | Minimum log level for the default console sink |
125
- | `personalization` | No | See "Personalization Options" | Configuration specific to the Personalization/Experience API |
121
+ | Option | Required? | Default | Description |
122
+ | -------------- | --------- | --------------------------- | ----------------------------------------------------------------------- |
123
+ | `api` | No | See "API Options" | Unified configuration for the Experience API and Insights API endpoints |
124
+ | `clientId` | Yes | N/A | Shared API key for Experience API and Insights API requests |
125
+ | `environment` | No | `'main'` | The environment identifier |
126
+ | `eventBuilder` | No | See "Event Builder Options" | Event builder configuration (channel/library metadata, etc.) |
127
+ | `fetchOptions` | No | See "Fetch Options" | Configuration for Fetch timeout and retry functionality |
128
+ | `logLevel` | No | `'error'` | Minimum log level for the default console sink |
126
129
 
127
130
  The following configuration options apply only in stateful environments:
128
131
 
@@ -132,32 +135,48 @@ The following configuration options apply only in stateful environments:
132
135
  | `defaults` | No | `undefined` | Set of default state values applied on initialization |
133
136
  | `getAnonymousId` | No | `undefined` | Function used to obtain an anonymous user identifier |
134
137
  | `onEventBlocked` | No | `undefined` | Callback invoked when an event call is blocked by guards |
138
+ | `queuePolicy` | No | See "Queue Policy Options" | Shared queue and retry configuration for stateful delivery |
135
139
 
136
140
  Configuration method signatures:
137
141
 
138
142
  - `getAnonymousId`: `() => string | undefined`
139
143
  - `onEventBlocked`: `(event: BlockedEvent) => void`
140
144
 
141
- ### Analytics Options
145
+ ### API Options
142
146
 
143
- | Option | Required? | Default | Description |
144
- | --------- | --------- | ------------------------------------------ | ----------------------------- |
145
- | `baseUrl` | No | `'https://ingest.insights.ninetailed.co/'` | Base URL for the Insights API |
147
+ | Option | Required? | Default | Description |
148
+ | ------------------- | --------- | ------------------------------------------ | ------------------------------------------------------------ |
149
+ | `experienceBaseUrl` | No | `'https://experience.ninetailed.co/'` | Base URL for the Experience API |
150
+ | `insightsBaseUrl` | No | `'https://ingest.insights.ninetailed.co/'` | Base URL for the Insights API |
151
+ | `enabledFeatures` | No | `['ip-enrichment', 'location']` | Enabled features the Experience API may use for each request |
146
152
 
147
- The following configuration options apply only in stateful environments:
153
+ The following configuration option applies only in stateful environments:
148
154
 
149
- | Option | Required? | Default | Description |
150
- | --------------- | --------- | --------------------- | ------------------------------------------------------------------------ |
151
- | `beaconHandler` | No | `undefined` | Handler used to enqueue events via the Beacon API or a similar mechanism |
152
- | `queuePolicy` | No | See method signatures | Queue flush retry/backoff/circuit policy for stateful analytics |
155
+ | Option | Required? | Default | Description |
156
+ | --------------- | --------- | ----------- | ------------------------------------------------------------------------------ |
157
+ | `beaconHandler` | No | `undefined` | Handler used to enqueue Insights API events via the Beacon API or equivalent |
158
+ | `ip` | No | `undefined` | IP address override used by the Experience API for location analysis |
159
+ | `locale` | No | `'en-US'` | Locale used to translate `location.city` and `location.country` |
160
+ | `plainText` | No | `false` | Sends performance-critical Experience API endpoints in plain text |
161
+ | `preflight` | No | `false` | Instructs the Experience API to aggregate a new profile state but not store it |
153
162
 
154
163
  Configuration method signatures:
155
164
 
156
165
  - `beaconHandler`: `(url: string | URL, data: BatchInsightsEventArray) => boolean`
157
- - `queuePolicy`:
158
166
 
159
- ```ts
160
- {
167
+ In stateless environments, bind `ip`, `locale`, `plainText`, and `preflight` per request with
168
+ `optimization.forRequest(...)` instead of constructor config.
169
+
170
+ ### Queue Policy Options
171
+
172
+ `queuePolicy` is available only in `CoreStateful` and combines shared flush retry settings with
173
+ Experience API offline buffering controls.
174
+
175
+ Configuration shape:
176
+
177
+ ```ts
178
+ {
179
+ flush?: {
161
180
  baseBackoffMs?: number,
162
181
  maxBackoffMs?: number,
163
182
  jitterRatio?: number,
@@ -166,29 +185,42 @@ Configuration method signatures:
166
185
  onFlushFailure?: (context: QueueFlushFailureContext) => void,
167
186
  onCircuitOpen?: (context: QueueFlushFailureContext) => void,
168
187
  onFlushRecovered?: (context: QueueFlushRecoveredContext) => void
169
- }
170
- ```
188
+ },
189
+ offlineMaxEvents?: number,
190
+ onOfflineDrop?: (context: ExperienceQueueDropContext) => void
191
+ }
192
+ ```
171
193
 
172
- Supporting callback payloads:
194
+ Supporting callback payloads:
173
195
 
174
- ```ts
175
- type QueueFlushFailureContext = {
176
- consecutiveFailures: number
177
- queuedBatches: number
178
- queuedEvents: number
179
- retryDelayMs: number
180
- }
196
+ ```ts
197
+ type ExperienceQueueDropContext = {
198
+ droppedCount: number
199
+ droppedEvents: ExperienceEventArray
200
+ maxEvents: number
201
+ queuedEvents: number
202
+ }
203
+
204
+ type QueueFlushFailureContext = {
205
+ consecutiveFailures: number
206
+ queuedBatches: number
207
+ queuedEvents: number
208
+ retryDelayMs: number
209
+ }
210
+
211
+ type QueueFlushRecoveredContext = {
212
+ consecutiveFailures: number
213
+ }
214
+ ```
181
215
 
182
- type QueueFlushRecoveredContext = {
183
- consecutiveFailures: number
184
- }
185
- ```
216
+ Notes:
186
217
 
187
- Notes:
188
- - Invalid numeric values fall back to defaults.
189
- - `jitterRatio` is clamped to `[0, 1]`.
190
- - `maxBackoffMs` is normalized to be at least `baseBackoffMs`.
191
- - Failed flush attempts include both `false` responses and thrown send errors.
218
+ - `flush` applies the same retry/backoff/circuit policy to both Insights API flushing and Experience
219
+ API offline replay.
220
+ - Invalid numeric values fall back to defaults.
221
+ - `jitterRatio` is clamped to `[0, 1]`.
222
+ - `maxBackoffMs` is normalized to be at least `baseBackoffMs`.
223
+ - Failed flush attempts include both `false` responses and thrown send errors.
192
224
 
193
225
  ### Event Builder Options
194
226
 
@@ -236,7 +268,7 @@ Configuration method signatures:
236
268
  ### Fetch Options
237
269
 
238
270
  Fetch options allow for configuration of a Fetch API-compatible fetch method and the retry/timeout
239
- logic integrated into the Optimization API Client. Specify the `fetchMethod` when the host
271
+ logic integrated into the SDK's bundled API clients. Specify the `fetchMethod` when the host
240
272
  application environment does not offer a `fetch` method that is compatible with the standard Fetch
241
273
  API in its global scope.
242
274
 
@@ -258,75 +290,9 @@ Configuration method signatures:
258
290
  >
259
291
  > Core inherits the API Client retry contract: default retries intentionally apply only to HTTP
260
292
  > `503` responses (`Service Unavailable`). This is deliberate and aligned with current Experience
261
- > and Insights API expectations; do not broaden retry status handling without an explicit API
293
+ > API and Insights API expectations; do not broaden retry status handling without an explicit API
262
294
  > contract change.
263
295
 
264
- ### Personalization Options
265
-
266
- | Option | Required? | Default | Description |
267
- | ----------------- | --------- | ------------------------------------- | ------------------------------------------------------------------- |
268
- | `baseUrl` | No | `'https://experience.ninetailed.co/'` | Base URL for the Experience API |
269
- | `enabledFeatures` | No | `['ip-enrichment', 'location']` | Enabled features which the API may use for each request |
270
- | `ip` | No | `undefined` | IP address to override the API behavior for IP analysis |
271
- | `locale` | No | `'en-US'` (in API) | Locale used to translate `location.city` and `location.country` |
272
- | `plainText` | No | `false` | Sends performance-critical endpoints in plain text |
273
- | `preflight` | No | `false` | Instructs the API to aggregate a new profile state but not store it |
274
-
275
- The following configuration options apply only in stateful environments:
276
-
277
- | Option | Required? | Default | Description |
278
- | ------------- | --------- | --------------------- | --------------------------------------------------------------------------- |
279
- | `queuePolicy` | No | See method signatures | Queue and flush-retry policy for stateful personalization offline buffering |
280
-
281
- Configuration method signatures:
282
-
283
- - `queuePolicy`:
284
-
285
- ```ts
286
- {
287
- maxEvents?: number,
288
- onDrop?: (context: PersonalizationOfflineQueueDropContext) => void,
289
- flushPolicy?: {
290
- baseBackoffMs?: number,
291
- maxBackoffMs?: number,
292
- jitterRatio?: number,
293
- maxConsecutiveFailures?: number,
294
- circuitOpenMs?: number,
295
- onFlushFailure?: (context: QueueFlushFailureContext) => void,
296
- onCircuitOpen?: (context: QueueFlushFailureContext) => void,
297
- onFlushRecovered?: (context: QueueFlushRecoveredContext) => void
298
- }
299
- }
300
- ```
301
-
302
- Supporting callback payloads:
303
-
304
- ```ts
305
- type PersonalizationOfflineQueueDropContext = {
306
- droppedCount: number
307
- droppedEvents: ExperienceEventArray
308
- maxEvents: number
309
- queuedEvents: number
310
- }
311
-
312
- type QueueFlushFailureContext = {
313
- consecutiveFailures: number
314
- queuedBatches: number
315
- queuedEvents: number
316
- retryDelayMs: number
317
- }
318
-
319
- type QueueFlushRecoveredContext = {
320
- consecutiveFailures: number
321
- }
322
- ```
323
-
324
- Notes:
325
- - Default `maxEvents` is `100`.
326
- - If the queue is full while offline, oldest events are dropped first.
327
- - `onDrop` is best-effort; callback errors are swallowed.
328
- - `flushPolicy` uses the same normalization semantics as `analytics.queuePolicy`.
329
-
330
296
  ## Core Methods
331
297
 
332
298
  The methods in this section are available in both stateful and stateless Core classes. However, be
@@ -335,9 +301,9 @@ implementations.
335
301
 
336
302
  Arguments marked with an asterisk (\*) are always required.
337
303
 
338
- ### Personalization Data Resolution Methods
304
+ ### Optimization Data Resolution Methods
339
305
 
340
- #### `getCustomFlag`
306
+ #### `getFlag`
341
307
 
342
308
  Get the specified Custom Flag's value from the provided changes array, or from the current internal
343
309
  state in stateful implementations.
@@ -351,15 +317,23 @@ Returns:
351
317
 
352
318
  - The resolved value for the specified Custom Flag, or `undefined` if it cannot be found.
353
319
 
320
+ Behavior notes:
321
+
322
+ - In `CoreStateful`, calling `getFlag(...)` automatically emits a flag view event via
323
+ `trackFlagView`.
324
+ - In `CoreStateless`, `getFlag(...)` does not auto-emit a flag view event.
325
+ - If full map resolution is needed for advanced use cases, use
326
+ `optimization.flagsResolver.resolve(changes)`.
327
+
354
328
  > [!NOTE]
355
329
  >
356
330
  > If the `changes` argument is omitted in stateless implementations, the method will return
357
331
  > `undefined`.
358
332
 
359
- #### `personalizeEntry`
333
+ #### `resolveOptimizedEntry`
360
334
 
361
- Resolve a baseline Contentful entry to a personalized variant using the provided selected
362
- personalizations, or from the current internal state in stateful implementations.
335
+ Resolve a baseline Contentful entry to an optimized variant using the provided selected
336
+ optimizations, or from the current internal state in stateful implementations.
363
337
 
364
338
  Type arguments:
365
339
 
@@ -369,18 +343,18 @@ Type arguments:
369
343
 
370
344
  Arguments:
371
345
 
372
- - `entry`\*: The entry to personalize
373
- - `personalizations`: Selected personalizations
346
+ - `entry`\*: The baseline entry to resolve
347
+ - `selectedOptimizations`: Selected optimizations
374
348
 
375
349
  Returns:
376
350
 
377
- - The resolved personalized entry variant, or the supplied baseline entry if baseline is the
378
- selected variant or a variant cannot be found.
351
+ - The resolved optimized entry variant, or the supplied baseline entry if baseline is the selected
352
+ variant or a variant cannot be found.
379
353
 
380
354
  > [!NOTE]
381
355
  >
382
- > If the `personalizations` argument is omitted in stateless implementations, the method will return
383
- > the baseline entry.
356
+ > If the `selectedOptimizations` argument is omitted in stateless implementations, the method will
357
+ > return the baseline entry.
384
358
 
385
359
  #### `getMergeTagValue`
386
360
 
@@ -398,7 +372,16 @@ Arguments:
398
372
  > If the `profile` argument is omitted in stateless implementations, the method will return the
399
373
  > merge tag's fallback value.
400
374
 
401
- ### Personalization and Analytics Event Methods
375
+ ### Event Methods
376
+
377
+ In `CoreStateful`, call these methods on the root instance. In `CoreStateless`, call them on the
378
+ request scope returned by `optimization.forRequest(...)`:
379
+
380
+ ```ts
381
+ const requestOptimization = optimization.forRequest({
382
+ locale: 'de-DE',
383
+ })
384
+ ```
402
385
 
403
386
  Only the following methods may return an `OptimizationData` object:
404
387
 
@@ -406,15 +389,20 @@ Only the following methods may return an `OptimizationData` object:
406
389
  - `page`
407
390
  - `screen`
408
391
  - `track`
409
- - `trackComponentView` (when `payload.sticky` is `true`)
392
+ - `trackView` (when `payload.sticky` is `true`)
410
393
 
411
- `trackComponentClick` and `trackFlagView` return no data. When returned, `OptimizationData`
394
+ `trackClick`, `trackHover`, and `trackFlagView` return no data. When returned, `OptimizationData`
412
395
  contains:
413
396
 
414
397
  - `changes`: Currently used for Custom Flags
415
- - `personalizations`: Selected personalizations for the profile
398
+ - `selectedOptimizations`: Selected optimizations for the profile
416
399
  - `profile`: Profile associated with the evaluated events
417
400
 
401
+ In stateless runtimes, Insights-backed methods require a profile for delivery. Non-sticky
402
+ `trackView`, `trackClick`, `trackHover`, and `trackFlagView` require `payload.profile.id`. Sticky
403
+ `trackView` may omit `profile`, because the returned Experience profile is reused for the paired
404
+ Insights event.
405
+
418
406
  #### `identify`
419
407
 
420
408
  Identify the current profile/visitor to associate traits with a profile.
@@ -426,7 +414,7 @@ Arguments:
426
414
 
427
415
  #### `page`
428
416
 
429
- Record a personalization page view.
417
+ Record an Experience API page view.
430
418
 
431
419
  Arguments:
432
420
 
@@ -435,7 +423,7 @@ Arguments:
435
423
 
436
424
  #### `screen`
437
425
 
438
- Record a personalization screen view.
426
+ Record an Experience API screen view.
439
427
 
440
428
  Arguments:
441
429
 
@@ -444,27 +432,41 @@ Arguments:
444
432
 
445
433
  #### `track`
446
434
 
447
- Record a personalization custom track event.
435
+ Record an Experience API custom track event.
448
436
 
449
437
  Arguments:
450
438
 
451
439
  - `payload`\*: Track event builder arguments object, including an optional `profile` property with a
452
440
  `PartialProfile` value that requires only an `id`
453
441
 
454
- #### `trackComponentView`
442
+ #### `trackView`
455
443
 
456
- Record an analytics component view event. When the payload marks the component as "sticky", an
457
- additional personalization component view is recorded. This method only returns `OptimizationData`
458
- when the component is marked as "sticky".
444
+ Record an Insights API entry view event. When the payload marks the entry as "sticky", an additional
445
+ Experience API entry view is recorded. This method only returns `OptimizationData` when the entry is
446
+ marked as "sticky".
447
+
448
+ Arguments:
449
+
450
+ - `payload`\*: Entry view event builder arguments object. When `payload.sticky` is `true`, `profile`
451
+ is optional and the returned Experience profile is reused for Insights delivery. Otherwise,
452
+ `profile` is required and must contain at least an `id`
453
+
454
+ #### `trackClick`
455
+
456
+ Record an Insights API entry click event.
457
+
458
+ Returns:
459
+
460
+ - `void`
459
461
 
460
462
  Arguments:
461
463
 
462
- - `payload`\*: Component view event builder arguments object, including an optional `profile`
463
- property with a `PartialProfile` value that requires only an `id`
464
+ - `payload`\*: Entry click event builder arguments object, including a required `profile` property
465
+ with a `PartialProfile` value that requires only an `id`
464
466
 
465
- #### `trackComponentClick`
467
+ #### `trackHover`
466
468
 
467
- Record an analytics component click event.
469
+ Record an Insights API entry hover event.
468
470
 
469
471
  Returns:
470
472
 
@@ -472,11 +474,12 @@ Returns:
472
474
 
473
475
  Arguments:
474
476
 
475
- - `payload`\*: Component click event builder arguments object
477
+ - `payload`\*: Entry hover event builder arguments object, including a required `profile` property
478
+ with a `PartialProfile` value that requires only an `id`
476
479
 
477
480
  #### `trackFlagView`
478
481
 
479
- Track a feature flag view via analytics. This is functionally the same as a non-sticky component
482
+ Track a feature flag view via the Insights API. This is functionally the same as a non-sticky flag
480
483
  view event.
481
484
 
482
485
  Returns:
@@ -485,7 +488,8 @@ Returns:
485
488
 
486
489
  Arguments:
487
490
 
488
- - `payload`\*: Component view event builder arguments object
491
+ - `payload`\*: Flag view event builder arguments object, including a required `profile` property
492
+ with a `PartialProfile` value that requires only an `id`
489
493
 
490
494
  ## Stateful-only Core Methods
491
495
 
@@ -503,8 +507,8 @@ Resets all internal state _except_ consent. This method expects no arguments and
503
507
 
504
508
  ### `flush`
505
509
 
506
- Flushes queued analytics and personalization events. This method expects no arguments and returns a
507
- `Promise<void>`.
510
+ Flushes queued Insights API and Experience API events. This method expects no arguments and returns
511
+ a `Promise<void>`.
508
512
 
509
513
  ### `destroy`
510
514
 
@@ -552,25 +556,67 @@ const signalFns = previewBridge[PREVIEW_PANEL_SIGNAL_FNS_SYMBOL]
552
556
  > interceptors) to apply immediate local overrides without network round-trips. This coupling is
553
557
  > deliberate and necessary for preview functionality.
554
558
 
555
- ## Stateful-only Core Properties
559
+ ## Core States (`CoreStateful` only)
560
+
561
+ `states` is available on `CoreStateful` and exposes signal-backed observables for runtime state.
562
+
563
+ Available state streams:
564
+
565
+ - `consent`: Current consent state (`boolean | undefined`)
566
+ - `blockedEventStream`: Latest blocked-call metadata (`BlockedEvent | undefined`)
567
+ - `eventStream`: Latest emitted Insights API or Experience API event
568
+ (`InsightsEvent | ExperienceEvent | undefined`)
569
+ - `flag(name)`: Key-scoped flag observable (`Observable<Json>`)
570
+ - `canOptimize`: Whether optimization selections are available (`boolean`;
571
+ `selectedOptimizations !== undefined`)
572
+ - `profile`: Current profile (`Profile | undefined`)
573
+ - `selectedOptimizations`: Current selected optimizations (`SelectedOptimizationArray | undefined`)
574
+ - `previewPanelAttached`: Preview panel attachment state (`boolean`)
575
+ - `previewPanelOpen`: Preview panel open state (`boolean`)
576
+
577
+ Each observable provides:
578
+
579
+ - `current`: Deep-cloned snapshot of the latest value
580
+ - `subscribe(next)`: Immediately emits `current`, then emits future updates
581
+ - `subscribeOnce(next)`: Emits the first non-nullish value, then auto-unsubscribes
582
+
583
+ `current` and callback payloads are deep-cloned snapshots, so local mutations do not affect Core's
584
+ internal signal state.
585
+
586
+ Update behavior:
556
587
 
557
- - `states`: Returns an object mapping of observables for all internal states
558
- - `consent`: The current state of user consent
559
- - `blockedEventStream`: The latest blocked event payload
560
- - `eventStream`: The latest event to be queued
561
- - `flags`: All current resolved Custom Flags
562
- - `profile`: The current user profile
563
- - `personalizations`: The current collection of selected personalizations
588
+ - `blockedEventStream` updates whenever a call is blocked by consent guards.
589
+ - `eventStream` updates when a valid event is accepted for send/queue.
590
+ - `flag(name)` updates when the resolved value for that key changes.
591
+ - `canOptimize` updates whenever `selectedOptimizations` becomes defined or `undefined`.
592
+ - `consent` updates from defaults and `optimization.consent(...)`.
593
+ - `previewPanelAttached` and `previewPanelOpen` are controlled by preview tooling and are preserved
594
+ across `reset()`.
564
595
 
565
- The `blockedEventStream` state is updated whenever a call is blocked by consent guards. Each state
566
- except `consent`, `eventStream`, and `blockedEventStream` is updated internally whenever a response
567
- from the Experience API contains a new or updated respective state.
596
+ Example: read the latest snapshot synchronously:
597
+
598
+ ```ts
599
+ const profile = optimization.states.profile.current
600
+ if (profile) console.log(`Current profile: ${profile.id}`)
601
+ ```
602
+
603
+ Example: subscribe and clean up:
604
+
605
+ ```ts
606
+ const sub = optimization.states.profile.subscribe((profile) => {
607
+ if (!profile) return
608
+ console.log(`Profile ${profile.id} updated`)
609
+ })
610
+
611
+ // later (component unmount / teardown)
612
+ sub.unsubscribe()
613
+ ```
568
614
 
569
- Example `states` observable usage:
615
+ Example: wait for first available profile:
570
616
 
571
617
  ```ts
572
- optimization.states.profile.subscribe((profile) => {
573
- console.log(`Profile ${profile.id} updated!`)
618
+ optimization.states.profile.subscribeOnce((profile) => {
619
+ console.log(`Profile ${profile.id} loaded`)
574
620
  })
575
621
  ```
576
622
 
package/dist/160.mjs ADDED
@@ -0,0 +1,3 @@
1
+ import * as __rspack_external__contentful_optimization_api_client_api_schemas_4192893e from "@contentful/optimization-api-client/api-schemas";
2
+ var PartialProfile = __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.PartialProfile;
3
+ export { PartialProfile, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e };
package/dist/260.mjs CHANGED
@@ -1,4 +1,4 @@
1
- const OPTIMIZATION_CORE_SDK_VERSION = "0.1.0-alpha10";
1
+ const OPTIMIZATION_CORE_SDK_VERSION = "0.1.0-alpha11";
2
2
  const OPTIMIZATION_CORE_SDK_NAME = "@contentful/optimization-core";
3
3
  const ANONYMOUS_ID_COOKIE = 'ctfl-opt-aid';
4
4
  const ANONYMOUS_ID_KEY = '__ctfl_opt_anonymous_id__';
@@ -6,9 +6,9 @@ const CONSENT_KEY = '__ctfl_opt_consent__';
6
6
  const CHANGES_CACHE_KEY = '__ctfl_opt_changes__';
7
7
  const DEBUG_FLAG_KEY = '__ctfl_opt_debug__';
8
8
  const PROFILE_CACHE_KEY = '__ctfl_opt_profile__';
9
- const PERSONALIZATIONS_CACHE_KEY = '__ctfl_opt_personalizations__';
9
+ const SELECTED_OPTIMIZATIONS_CACHE_KEY = '__ctfl_opt_selected-optimizations__';
10
10
  const ANONYMOUS_ID_COOKIE_LEGACY = 'ntaid';
11
11
  const ANONYMOUS_ID_KEY_LEGACY = '__nt_anonymous_id__';
12
- export { ANONYMOUS_ID_COOKIE, ANONYMOUS_ID_COOKIE_LEGACY, ANONYMOUS_ID_KEY, ANONYMOUS_ID_KEY_LEGACY, CHANGES_CACHE_KEY, CONSENT_KEY, DEBUG_FLAG_KEY, OPTIMIZATION_CORE_SDK_NAME, OPTIMIZATION_CORE_SDK_VERSION, PERSONALIZATIONS_CACHE_KEY, PROFILE_CACHE_KEY };
12
+ export { ANONYMOUS_ID_COOKIE, ANONYMOUS_ID_COOKIE_LEGACY, ANONYMOUS_ID_KEY, ANONYMOUS_ID_KEY_LEGACY, CHANGES_CACHE_KEY, CONSENT_KEY, DEBUG_FLAG_KEY, OPTIMIZATION_CORE_SDK_NAME, OPTIMIZATION_CORE_SDK_VERSION, PROFILE_CACHE_KEY, SELECTED_OPTIMIZATIONS_CACHE_KEY };
13
13
 
14
14
  //# sourceMappingURL=260.mjs.map
package/dist/260.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"260.mjs","sources":["../src/constants.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/naming-convention -- Replaced at build-time\ndeclare const __OPTIMIZATION_VERSION__: string | undefined\n// eslint-disable-next-line @typescript-eslint/naming-convention -- Replaced at build-time\ndeclare const __OPTIMIZATION_PACKAGE_NAME__: string | undefined\n\n/**\n * The current version of the Optimization Core SDK, injected at build time.\n *\n * @public\n */\nexport const OPTIMIZATION_CORE_SDK_VERSION =\n typeof __OPTIMIZATION_VERSION__ === 'string' ? __OPTIMIZATION_VERSION__ : '0.0.0'\n/**\n * The package name of the Optimization Core SDK, injected at build time.\n *\n * @public\n */\nexport const OPTIMIZATION_CORE_SDK_NAME =\n typeof __OPTIMIZATION_PACKAGE_NAME__ === 'string'\n ? __OPTIMIZATION_PACKAGE_NAME__\n : '@contentful/optimization-core'\n\n/**\n * Anonymous-ID cookie name used by the Optimization Core.\n *\n * @public\n * @remarks\n * This constant 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 * @example\n * ```ts\n * import { ANONYMOUS_ID_COOKIE } from '@contentful/optimization-core/constants'\n * const profileId = request.cookies[ANONYMOUS_ID_COOKIE]\n * ```\n */\nexport const ANONYMOUS_ID_COOKIE = 'ctfl-opt-aid'\n\n/**\n * Storage key for the anonymous identifier.\n *\n * @internal\n */\nexport const ANONYMOUS_ID_KEY = '__ctfl_opt_anonymous_id__'\n\n/**\n * Storage key for the persisted consent status.\n *\n * @internal\n */\nexport const CONSENT_KEY = '__ctfl_opt_consent__'\n\n/**\n * Storage key for cached Custom Flags.\n *\n * @internal\n */\nexport const CHANGES_CACHE_KEY = '__ctfl_opt_changes__'\n\n/**\n * Storage key for the debug flag toggle.\n *\n * @internal\n */\nexport const DEBUG_FLAG_KEY = '__ctfl_opt_debug__'\n\n/**\n * Storage key for cached profile data.\n *\n * @internal\n */\nexport const PROFILE_CACHE_KEY = '__ctfl_opt_profile__'\n\n/**\n * Storage key for cached selected personalizations.\n *\n * @internal\n */\nexport const PERSONALIZATIONS_CACHE_KEY = '__ctfl_opt_personalizations__'\n\n/**\n * Legacy anoynmous ID cookie key for migration from experience.js\n *\n * @internal\n */\nexport const ANONYMOUS_ID_COOKIE_LEGACY = 'ntaid'\n\n/**\n * Legacy anoynmous ID storage key for migration from experience.js\n *\n * @internal\n */\nexport const ANONYMOUS_ID_KEY_LEGACY = '__nt_anonymous_id__'\n"],"names":["OPTIMIZATION_CORE_SDK_VERSION","__OPTIMIZATION_VERSION__","OPTIMIZATION_CORE_SDK_NAME","__OPTIMIZATION_PACKAGE_NAME__","ANONYMOUS_ID_COOKIE","ANONYMOUS_ID_KEY","CONSENT_KEY","CHANGES_CACHE_KEY","DEBUG_FLAG_KEY","PROFILE_CACHE_KEY","PERSONALIZATIONS_CACHE_KEY","ANONYMOUS_ID_COOKIE_LEGACY","ANONYMOUS_ID_KEY_LEGACY"],"mappings":"AAUO,MAAMA,gCACoCC;AAM1C,MAAMC,6BAEPC;AAkBC,MAAMC,sBAAsB;AAO5B,MAAMC,mBAAmB;AAOzB,MAAMC,cAAc;AAOpB,MAAMC,oBAAoB;AAO1B,MAAMC,iBAAiB;AAOvB,MAAMC,oBAAoB;AAO1B,MAAMC,6BAA6B;AAOnC,MAAMC,6BAA6B;AAOnC,MAAMC,0BAA0B"}
1
+ {"version":3,"file":"260.mjs","sources":["../src/constants.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/naming-convention -- Replaced at build-time\ndeclare const __OPTIMIZATION_VERSION__: string | undefined\n// eslint-disable-next-line @typescript-eslint/naming-convention -- Replaced at build-time\ndeclare const __OPTIMIZATION_PACKAGE_NAME__: string | undefined\n\n/**\n * The current version of the Optimization Core SDK, injected at build time.\n *\n * @public\n */\nexport const OPTIMIZATION_CORE_SDK_VERSION =\n typeof __OPTIMIZATION_VERSION__ === 'string' ? __OPTIMIZATION_VERSION__ : '0.0.0'\n/**\n * The package name of the Optimization Core SDK, injected at build time.\n *\n * @public\n */\nexport const OPTIMIZATION_CORE_SDK_NAME =\n typeof __OPTIMIZATION_PACKAGE_NAME__ === 'string'\n ? __OPTIMIZATION_PACKAGE_NAME__\n : '@contentful/optimization-core'\n\n/**\n * Anonymous-ID cookie name used by the Optimization Core.\n *\n * @public\n * @remarks\n * This constant represents the cookie key used by the Optimization Framework\n * to persist an anonymous identifier for tracking optimization and insights\n * events when no explicit profile is known.\n *\n * @example\n * ```ts\n * import { ANONYMOUS_ID_COOKIE } from '@contentful/optimization-core/constants'\n * const profileId = request.cookies[ANONYMOUS_ID_COOKIE]\n * ```\n */\nexport const ANONYMOUS_ID_COOKIE = 'ctfl-opt-aid'\n\n/**\n * Storage key for the anonymous identifier.\n *\n * @internal\n */\nexport const ANONYMOUS_ID_KEY = '__ctfl_opt_anonymous_id__'\n\n/**\n * Storage key for the persisted consent status.\n *\n * @internal\n */\nexport const CONSENT_KEY = '__ctfl_opt_consent__'\n\n/**\n * Storage key for cached Custom Flags.\n *\n * @internal\n */\nexport const CHANGES_CACHE_KEY = '__ctfl_opt_changes__'\n\n/**\n * Storage key for the debug flag toggle.\n *\n * @internal\n */\nexport const DEBUG_FLAG_KEY = '__ctfl_opt_debug__'\n\n/**\n * Storage key for cached profile data.\n *\n * @internal\n */\nexport const PROFILE_CACHE_KEY = '__ctfl_opt_profile__'\n\n/**\n * Storage key for cached selected optimizations.\n *\n * @internal\n */\nexport const SELECTED_OPTIMIZATIONS_CACHE_KEY = '__ctfl_opt_selected-optimizations__'\n\n/**\n * Legacy anoynmous ID cookie key for migration from experience.js\n *\n * @internal\n */\nexport const ANONYMOUS_ID_COOKIE_LEGACY = 'ntaid'\n\n/**\n * Legacy anoynmous ID storage key for migration from experience.js\n *\n * @internal\n */\nexport const ANONYMOUS_ID_KEY_LEGACY = '__nt_anonymous_id__'\n"],"names":["OPTIMIZATION_CORE_SDK_VERSION","__OPTIMIZATION_VERSION__","OPTIMIZATION_CORE_SDK_NAME","__OPTIMIZATION_PACKAGE_NAME__","ANONYMOUS_ID_COOKIE","ANONYMOUS_ID_KEY","CONSENT_KEY","CHANGES_CACHE_KEY","DEBUG_FLAG_KEY","PROFILE_CACHE_KEY","SELECTED_OPTIMIZATIONS_CACHE_KEY","ANONYMOUS_ID_COOKIE_LEGACY","ANONYMOUS_ID_KEY_LEGACY"],"mappings":"AAUO,MAAMA,gCACoCC;AAM1C,MAAMC,6BAEPC;AAkBC,MAAMC,sBAAsB;AAO5B,MAAMC,mBAAmB;AAOzB,MAAMC,cAAc;AAOpB,MAAMC,oBAAoB;AAO1B,MAAMC,iBAAiB;AAOvB,MAAMC,oBAAoB;AAO1B,MAAMC,mCAAmC;AAOzC,MAAMC,6BAA6B;AAOnC,MAAMC,0BAA0B"}
@@ -52,7 +52,10 @@ var __webpack_exports__ = {};
52
52
  for(const __rspack_import_key in _contentful_optimization_api_client_api_schemas__rspack_import_0)if ("default" !== __rspack_import_key) __rspack_reexport[__rspack_import_key] = ()=>_contentful_optimization_api_client_api_schemas__rspack_import_0[__rspack_import_key];
53
53
  __webpack_require__.d(__webpack_exports__, __rspack_reexport);
54
54
  })();
55
- for(var __rspack_i in __webpack_exports__)exports[__rspack_i] = __webpack_exports__[__rspack_i];
55
+ exports.PartialProfile = __webpack_exports__.PartialProfile;
56
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
57
+ "PartialProfile"
58
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
56
59
  Object.defineProperty(exports, '__esModule', {
57
60
  value: true
58
61
  });