@salesforce/storefront-next-runtime 0.1.1 → 0.2.0-alpha.1

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 (62) hide show
  1. package/dist/DesignComponent.js +150 -0
  2. package/dist/DesignComponent.js.map +1 -0
  3. package/dist/DesignFrame.js +196 -0
  4. package/dist/DesignFrame.js.map +1 -0
  5. package/dist/DesignRegion.js +83 -0
  6. package/dist/DesignRegion.js.map +1 -0
  7. package/dist/apply-url-config.js +130 -0
  8. package/dist/apply-url-config.js.map +1 -0
  9. package/dist/component.types.d.ts +87 -0
  10. package/dist/component.types.d.ts.map +1 -0
  11. package/dist/config.d.ts +2 -0
  12. package/dist/config.js +0 -0
  13. package/dist/design-data.d.ts +983 -0
  14. package/dist/design-data.d.ts.map +1 -0
  15. package/dist/design-data.js +908 -0
  16. package/dist/design-data.js.map +1 -0
  17. package/dist/design-messaging.d.ts +2 -2
  18. package/dist/design-react-core.d.ts +48 -3
  19. package/dist/design-react-core.d.ts.map +1 -1
  20. package/dist/design-react-core.js +81 -2
  21. package/dist/design-react-core.js.map +1 -1
  22. package/dist/design-react.d.ts +20 -95
  23. package/dist/design-react.d.ts.map +1 -1
  24. package/dist/design-react.js +3 -485
  25. package/dist/design-styles.css +2 -1
  26. package/dist/design.d.ts +110 -2
  27. package/dist/design.d.ts.map +1 -0
  28. package/dist/events.d.ts +1 -1
  29. package/dist/events.d.ts.map +1 -1
  30. package/dist/index.d.ts +1110 -154
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/multi-site.d.ts +154 -0
  33. package/dist/multi-site.d.ts.map +1 -0
  34. package/dist/multi-site.js +393 -0
  35. package/dist/multi-site.js.map +1 -0
  36. package/dist/routing-app-wrapper.d.ts +18 -0
  37. package/dist/routing-app-wrapper.d.ts.map +1 -0
  38. package/dist/routing-app-wrapper.js +21 -0
  39. package/dist/routing-app-wrapper.js.map +1 -0
  40. package/dist/routing.d.ts +42 -0
  41. package/dist/routing.d.ts.map +1 -0
  42. package/dist/routing.js +175 -0
  43. package/dist/routing.js.map +1 -0
  44. package/dist/scapi.d.ts +69 -5
  45. package/dist/scapi.d.ts.map +1 -1
  46. package/dist/scapi.js +1 -1
  47. package/dist/scapi.js.map +1 -1
  48. package/dist/types.d.ts +40 -13289
  49. package/dist/types.d.ts.map +1 -1
  50. package/dist/types2.d.ts +13293 -0
  51. package/dist/types2.d.ts.map +1 -0
  52. package/dist/types3.d.ts +110 -0
  53. package/dist/types3.d.ts.map +1 -0
  54. package/dist/workspace.d.ts +46 -0
  55. package/dist/workspace.d.ts.map +1 -0
  56. package/dist/workspace.js +52 -0
  57. package/dist/workspace.js.map +1 -0
  58. package/package.json +45 -2
  59. package/dist/design-react.js.map +0 -1
  60. package/dist/index2.d.ts +0 -1171
  61. package/dist/index2.d.ts.map +0 -1
  62. /package/{LICENSE.txt → LICENSE} +0 -0
@@ -0,0 +1,983 @@
1
+ import { r as ShopperExperience } from "./types2.js";
2
+
3
+ //#region src/design/data/types.d.ts
4
+
5
+ /**
6
+ * A manifest containing all variations of a single Page Designer page for a
7
+ * specific locale. Variations are evaluated in {@link variationOrder} sequence;
8
+ * the first whose visibility rule passes is selected. If none match, the
9
+ * {@link defaultVariation} is used as a fallback.
10
+ */
11
+ interface PageManifest {
12
+ /** The unique identifier of the page this manifest represents. */
13
+ pageId: string;
14
+ /** The locale this manifest applies to (e.g. `"en-US"`). */
15
+ locale: string;
16
+ /** Campaigns and customer groups referenced across all variations in this manifest. */
17
+ context: PageManifestContext;
18
+ /** Ordered list of variation IDs defining the evaluation sequence. */
19
+ variationOrder: string[];
20
+ /** Map of variation ID to its entry data. */
21
+ variations: Record<string, VariationEntry>;
22
+ /** The variation ID to use when no other variation's rule matches. */
23
+ defaultVariation: string;
24
+ /**
25
+ * Component visibility rule definitions extracted from the page layout.
26
+ * Maps each component ID to its array of rule objects and a flag indicating
27
+ * if any rules are defined for that component.
28
+ */
29
+ componentInfo: {
30
+ [componentId: string]: {
31
+ /** The visibility rules for this component. */
32
+ visibilityRules: VisibilityRuleDef[];
33
+ /** Whether this component or any of its descendants have visibility rules. */
34
+ hasAnyDescendantVisibilityRules: boolean;
35
+ /** Whether this component or any of its descendants has data bindings. */
36
+ hasAnyDescendantDataBindings: boolean;
37
+ };
38
+ };
39
+ }
40
+ /**
41
+ * Site-wide manifest containing content assignments that map product and category
42
+ * identifiers to page IDs, plus the category hierarchy used for parent-category
43
+ * traversal during lookup.
44
+ */
45
+ interface SiteManifest {
46
+ /**
47
+ * Nested mapping of content assignments.
48
+ * Structure: `aspectType -> objectType -> objectId -> assignment`.
49
+ *
50
+ * For example, a PDP assignment for product "nike-air-max-90":
51
+ * `contentObjectAssignments.pdp.product["nike-air-max-90"].contentId`
52
+ */
53
+ contentObjectAssignments: {
54
+ [aspectType: string]: {
55
+ [objectType: string]: {
56
+ [objectId: string]: {
57
+ /** Whether this assignment was explicitly set or inherited from a parent category. */
58
+ lookupMode: 'category-implicit' | 'category-explicit';
59
+ /** The page ID assigned to this object. */
60
+ contentId: string;
61
+ };
62
+ };
63
+ };
64
+ };
65
+ /**
66
+ * Category hierarchy used to traverse from child to parent when resolving
67
+ * category-based content assignments.
68
+ */
69
+ categories: {
70
+ [categoryId: string]: {
71
+ /** Display name of the category. */
72
+ name: string;
73
+ /** ID of the parent category, or undefined for root categories. */
74
+ parentCategory?: string;
75
+ };
76
+ };
77
+ }
78
+ /**
79
+ * A campaign and promotion pair used in visibility rules. Both the campaign and
80
+ * the specific promotion within it must be active in the shopper's context for
81
+ * the qualifier to match.
82
+ */
83
+ interface CampaignQualifier {
84
+ /** The campaign identifier. */
85
+ campaignId: string;
86
+ /** The promotion identifier within the campaign. */
87
+ promotionId: string;
88
+ }
89
+ /**
90
+ * Metadata extracted from all variation rules in a {@link PageManifest}. Lists
91
+ * every campaign qualifier and customer group referenced, so the runtime knows
92
+ * which context values may be needed without inspecting each rule individually.
93
+ */
94
+ interface PageManifestContext {
95
+ /** All campaign/promotion pairs referenced by any variation's visibility rule. */
96
+ campaignQualifiers: CampaignQualifier[];
97
+ /** All customer group IDs referenced by any variation's visibility rule. */
98
+ customerGroups: string[];
99
+ /** All data bindings required by components on this page, hoisted for batch resolution. */
100
+ dataBindings: DataBindingRequirement[];
101
+ }
102
+ /**
103
+ * A single data binding requirement declared by a component. The `type`
104
+ * identifies the data provider (e.g. `"content_asset"`, `"product"`) and the
105
+ * `id` identifies the specific record within that provider.
106
+ *
107
+ * These requirements are hoisted into {@link PageManifestContext} so MRT can
108
+ * request all required external data in a single batch during context resolution.
109
+ */
110
+ interface DataBindingRequirement {
111
+ /** The data provider type (e.g. `"content_asset"`, `"product"`, `"personalization"`). */
112
+ type: string;
113
+ /** The UUID or identifier of the specific record. */
114
+ id: string;
115
+ }
116
+ /**
117
+ * A single page variation within a {@link PageManifest}. Each variation holds
118
+ * the full page data and flags indicating whether qualifier context is needed
119
+ * for selection or component-level processing.
120
+ */
121
+ interface VariationEntry {
122
+ /**
123
+ * Whether this variation's page contains components with visibility rules
124
+ * that require qualifier context. When `true`, the context resolver is called
125
+ * before processing the page's components.
126
+ */
127
+ pageRequiresContext: boolean;
128
+ /**
129
+ * Whether this variation's own visibility rule requires qualifier context
130
+ * to evaluate. When `true`, the context resolver is called before checking
131
+ * the variation-level rule.
132
+ */
133
+ ruleRequiresContext: boolean;
134
+ /** The visibility rule that must pass for this variation to be selected. Undefined for the default variation. */
135
+ visibilityRule?: VisibilityRuleDef;
136
+ /** The full page data for this variation. */
137
+ page: ShopperExperience.schemas['Page'];
138
+ }
139
+ /**
140
+ * A visibility rule definition that controls when a page variation or component
141
+ * is shown. All conditions within a rule use AND logic — every specified
142
+ * condition must pass for the rule to be satisfied.
143
+ */
144
+ interface VisibilityRuleDef {
145
+ /** Customer groups that the shopper must belong to. All groups must match. */
146
+ customerGroups?: string[];
147
+ /** Campaign/promotion pairs that must be active. All qualifiers must match. */
148
+ campaignQualifiers?: CampaignQualifier[];
149
+ /** Time window during which the rule is active, as ISO 8601 UTC strings. */
150
+ schedule?: {
151
+ /** Start time as an ISO 8601 UTC string. Rule fails before this time. */
152
+ start?: string;
153
+ /** End time as an ISO 8601 UTC string. Rule fails after this time. */
154
+ end?: string;
155
+ };
156
+ /** Whether this rule is active for the locale of the manifest. */
157
+ isActiveForLocale: boolean;
158
+ }
159
+ /**
160
+ * Runtime context representing the current shopper's active qualifiers.
161
+ * Passed to {@link validateRule} to evaluate visibility rules. This context
162
+ * is typically resolved lazily — only fetched when a rule actually needs it.
163
+ */
164
+ interface QualifierContext {
165
+ /**
166
+ * Active campaign qualifiers. Outer key is campaign ID, inner key is
167
+ * promotion ID. A value of `true` means the qualifier is active.
168
+ */
169
+ campaignQualifiers: {
170
+ [campaignId: string]: {
171
+ [promotionId: string]: boolean;
172
+ };
173
+ };
174
+ /**
175
+ * Customer group memberships. Key is the customer group ID, value of
176
+ * `true` means the shopper belongs to that group.
177
+ */
178
+ customerGroups: {
179
+ [customerGroupId: string]: boolean;
180
+ };
181
+ /**
182
+ * Resolved data binding objects returned from context resolution. Grouped
183
+ * by provider type, then by record ID. The `ExpressionResolver` uses this
184
+ * to evaluate attribute expressions like `content_asset.body`.
185
+ */
186
+ dataBindings?: {
187
+ [type: string]: {
188
+ [id: string]: ResolvedDataBinding;
189
+ };
190
+ };
191
+ }
192
+ /**
193
+ * A resolved data binding object containing the fields returned by the data
194
+ * provider for a specific record. For example, a resolved `content_asset`
195
+ * might contain `{ title: "Winter Sale", body: "<div>…</div>" }`.
196
+ */
197
+ interface ResolvedDataBinding {
198
+ [field: string]: unknown;
199
+ }
200
+ /**
201
+ * The type of identifier used to look up a page. Determines how the ID is
202
+ * resolved to a page manifest:
203
+ * - `'page'` — Direct page ID, used as-is
204
+ * - `'category'` — Category ID, resolved via content assignments with parent traversal
205
+ * - `'product'` — Product ID, resolved via content assignments
206
+ */
207
+ type IdentifierType = 'page' | 'category' | 'product';
208
+ /**
209
+ * Storage interface for fetching page and site manifests. Implementations
210
+ * decouple the page resolution logic from the underlying data source (e.g.,
211
+ * filesystem, CDN, database).
212
+ */
213
+ interface ManifestStorage {
214
+ /** Fetch the page manifest for a given page ID and locale. */
215
+ getPageManifest(id: string, locale: string): Promise<PageManifest>;
216
+ /** Fetch the site-wide manifest for a given locale. */
217
+ getSiteManifest(locale: string): Promise<SiteManifest>;
218
+ }
219
+ type VisitorContextType = 'page' | 'region' | 'component' | 'root';
220
+ type InferNodeFromType<TType extends VisitorContextType> = TType extends 'page' ? ShopperExperience.schemas['Page'] : TType extends 'region' ? ShopperExperience.schemas['Region'] : ShopperExperience.schemas['Component'];
221
+ //#endregion
222
+ //#region src/design/data/page/process-page.d.ts
223
+ /**
224
+ * Context required for page processing. Contains the shopper's runtime
225
+ * qualifiers and the component-level visibility rules from the page manifest.
226
+ */
227
+ interface PageProcessorContext {
228
+ /** The shopper's active qualifiers (campaigns, customer groups), or `null` if not resolved. */
229
+ qualifiers: QualifierContext | null;
230
+ /** Component visibility rule definitions extracted from the page layout. */
231
+ componentInfo: PageManifest['componentInfo'];
232
+ }
233
+ /**
234
+ * Filters a page's components based on their visibility rules and resolves
235
+ * data binding expressions in a single traversal. Traverses the page tree
236
+ * using the visitor pattern and:
237
+ *
238
+ * 1. Removes any component whose visibility rules do not pass against the
239
+ * shopper's qualifier context.
240
+ * 2. Resolves data binding expressions in each surviving component's `data`
241
+ * attributes using the resolved data bindings from context resolution.
242
+ *
243
+ * A component is visible if **any** of its visibility rules pass (OR logic).
244
+ * If a component has rules and none of them pass, it is removed. Components
245
+ * without rules are always included.
246
+ *
247
+ * @param page - The page to process.
248
+ * @param context - The processing context with qualifier data, visibility rules, and resolved data bindings.
249
+ * @returns A new page with invisible components filtered out and data binding expressions resolved.
250
+ *
251
+ * @example
252
+ * ```ts
253
+ * import { processPage } from '@salesforce/storefront-next-runtime/design/data';
254
+ *
255
+ * const page = {
256
+ * id: 'homepage',
257
+ * typeId: 'storePage',
258
+ * regions: [{
259
+ * id: 'main',
260
+ * components: [
261
+ * { id: 'public-banner', typeId: 'commerce_assets.heroBanner', regions: [] },
262
+ * { id: 'loyalty-offer', typeId: 'commerce_assets.promoTile', regions: [] },
263
+ * ],
264
+ * }],
265
+ * };
266
+ *
267
+ * // The "loyalty-offer" component requires the shopper to be in "loyalty-members"
268
+ * const componentInfo = {
269
+ * 'public-banner': { visibilityRules: [], hasVisibilityRules: false },
270
+ * 'loyalty-offer': {
271
+ * visibilityRules: [{ customerGroups: ['loyalty-members'] }],
272
+ * hasVisibilityRules: true,
273
+ * },
274
+ * };
275
+ *
276
+ * // Guest shopper — not in any customer group
277
+ * const filtered = processPage(page, {
278
+ * qualifiers: { customerGroups: {}, campaignQualifiers: {} },
279
+ * componentInfo,
280
+ * });
281
+ * // filtered.regions[0].components has only "public-banner"
282
+ * // "loyalty-offer" was removed because the shopper isn't a loyalty member
283
+ * ```
284
+ */
285
+ declare function processPage(page: ShopperExperience.schemas['Page'], processorContext: PageProcessorContext): ShopperExperience.schemas['Page'];
286
+ //#endregion
287
+ //#region src/design/data/page/transform.d.ts
288
+ /**
289
+ * Context object passed to {@link PageVisitor} handler methods during page tree
290
+ * traversal. Provides access to the current node via {@link node}, the tree
291
+ * position via {@link page}, {@link parentRegion}, and {@link parentComponent},
292
+ * and traversal methods ({@link visitRegions}, {@link visitComponents}) for
293
+ * continuing into child nodes.
294
+ *
295
+ * When a visitor handler is defined, the handler is responsible for traversing
296
+ * into children by calling the appropriate context method. If the handler does
297
+ * not call these methods, children will not be visited.
298
+ */
299
+ declare class VisitorContext<TNode> {
300
+ private readonly context;
301
+ constructor(context: {
302
+ /** The current node being visited. */
303
+ node: TNode;
304
+ /** The node type */
305
+ type: VisitorContextType;
306
+ /** The visitor being used to transform the page tree. */
307
+ visitor: PageVisitor;
308
+ /** The root page being traversed. */
309
+ page?: ShopperExperience.schemas['Page'];
310
+ /** The parent region of the current node, if traversing within a region. */
311
+ parentRegion?: ShopperExperience.schemas['Region'];
312
+ /** The parent component of the current node, if traversing within a component's nested regions. */
313
+ parentComponent?: ShopperExperience.schemas['Component'];
314
+ });
315
+ get type(): VisitorContextType;
316
+ /**
317
+ * The current node being visited.
318
+ */
319
+ get node(): TNode;
320
+ /**
321
+ * The root page being traversed.
322
+ */
323
+ get page(): ShopperExperience.schemas['Page'] | undefined;
324
+ /**
325
+ * The parent region of the current node, if traversing within a region.
326
+ */
327
+ get parentRegion(): ShopperExperience.schemas['Region'] | undefined;
328
+ /**
329
+ * The parent component of the current node, if traversing within a component's nested regions.
330
+ */
331
+ get parentComponent(): ShopperExperience.schemas['Component'] | undefined;
332
+ /**
333
+ * Traverses an array of regions, invoking the visitor's `visitRegion` handler
334
+ * on each one. Regions for which the handler returns `null` are excluded from
335
+ * the result. Call this from within a `visitPage` or `visitComponent` handler
336
+ * to continue traversal into child regions.
337
+ *
338
+ * @param regions - The regions to traverse.
339
+ * @returns The filtered array of transformed regions.
340
+ *
341
+ * @example
342
+ * ```ts
343
+ * transformPage(page, {
344
+ * visitPage(context) {
345
+ * // Traverse into regions explicitly
346
+ * const regions = context.visitRegions(context.node.regions);
347
+ * return { ...context.node, regions };
348
+ * },
349
+ * });
350
+ * ```
351
+ */
352
+ visitRegions(regions?: ShopperExperience.schemas['Region'][]): ShopperExperience.schemas['Region'][];
353
+ /**
354
+ * Traverses a single region. If the visitor has a `visitRegion` handler, the
355
+ * handler is called with a new {@link VisitorContext} for the region. Otherwise,
356
+ * the region's child components are traversed automatically.
357
+ *
358
+ * @param region - The region to visit.
359
+ * @returns The transformed region, or `null` to exclude it.
360
+ */
361
+ visitRegion(region: ShopperExperience.schemas['Region']): ShopperExperience.schemas['Region'] | null;
362
+ /**
363
+ * Traverses an array of components, invoking the visitor's `visitComponent`
364
+ * handler on each one. Components for which the handler returns `null` are
365
+ * excluded from the result. Call this from within a `visitRegion` handler to
366
+ * continue traversal into child components.
367
+ *
368
+ * @param components - The components to traverse.
369
+ * @returns The filtered array of transformed components.
370
+ *
371
+ * @example
372
+ * ```ts
373
+ * transformPage(page, {
374
+ * visitRegion(context) {
375
+ * // Traverse into components explicitly
376
+ * const components = context.visitComponents(context.node.components);
377
+ * return { ...context.node, components };
378
+ * },
379
+ * });
380
+ * ```
381
+ */
382
+ visitComponents(components?: ShopperExperience.schemas['Component'][]): ShopperExperience.schemas['Component'][];
383
+ /**
384
+ * Traverses a single component. If the visitor has a `visitComponent` handler,
385
+ * the handler is called with a new {@link VisitorContext} for the component.
386
+ * Otherwise, the component's nested regions are traversed automatically.
387
+ *
388
+ * @param component - The component to visit.
389
+ * @returns The transformed component, or `null` to exclude it.
390
+ */
391
+ visitComponent(component: ShopperExperience.schemas['Component']): ShopperExperience.schemas['Component'] | null;
392
+ /**
393
+ * Traverses a single page. If the visitor has a `visitPage` handler, the
394
+ * handler is called with a new {@link VisitorContext} for the page. Otherwise,
395
+ * the page's regions are traversed automatically.
396
+ *
397
+ * @param page - The page to visit.
398
+ * @returns The transformed page, or `null` to exclude it.
399
+ */
400
+ visitPage(page: ShopperExperience.schemas['Page']): ShopperExperience.schemas['Page'] | null;
401
+ private toChildContext;
402
+ }
403
+ /**
404
+ * Visitor interface for traversing and transforming a Page Designer page tree.
405
+ * Implement any combination of visit methods to intercept pages, regions, or
406
+ * components during traversal. Return `null` from `visitRegion` or
407
+ * `visitComponent` to remove that element from the tree.
408
+ */
409
+ interface PageVisitor {
410
+ visitPage?(context: VisitorContext<ShopperExperience.schemas['Page']>): ShopperExperience.schemas['Page'];
411
+ visitRegion?(context: VisitorContext<ShopperExperience.schemas['Region']>): ShopperExperience.schemas['Region'] | null;
412
+ visitComponent?(component: VisitorContext<ShopperExperience.schemas['Component']>): ShopperExperience.schemas['Component'] | null;
413
+ }
414
+ /**
415
+ * Traverses a page tree using the visitor pattern, applying the visitor's
416
+ * callbacks to the page, its regions, and their nested components. This is
417
+ * the top-level entry point for page tree transformation.
418
+ *
419
+ * When a visitor handler is defined, it receives a {@link VisitorContext} and
420
+ * is responsible for traversing into children using the context's traversal
421
+ * methods (`visitRegions`, `visitComponents`). If the handler does not call
422
+ * these methods, children will not be visited. When no handler is defined for
423
+ * a node type, children are traversed automatically.
424
+ *
425
+ * Returning `null` from a `visitRegion` or `visitComponent` callback removes
426
+ * that element and its children from the resulting tree.
427
+ *
428
+ * @param page - The page to traverse.
429
+ * @param visitor - The visitor with callbacks to apply at each tree node.
430
+ * @returns A new page with visitor transformations applied, or `null`.
431
+ *
432
+ * @example
433
+ * ```ts
434
+ * import { transformPage } from '@salesforce/storefront-next-runtime/design/data';
435
+ *
436
+ * const page = { id: 'homepage', typeId: 'storePage', regions: [
437
+ * { id: 'header', components: [
438
+ * { id: 'hero-banner', typeId: 'commerce_assets.heroBanner', regions: [] },
439
+ * { id: 'promo-tile', typeId: 'commerce_assets.promoTile', regions: [] },
440
+ * ]},
441
+ * ]};
442
+ *
443
+ * // When only visitComponent is defined, regions are traversed automatically.
444
+ * // The handler receives a VisitorContext — use context.node to access the component.
445
+ * transformPage(page, {
446
+ * visitComponent(context) {
447
+ * console.log(`Component: ${context.node.typeId} in region ${context.parentRegion?.id}`);
448
+ * return context.node;
449
+ * },
450
+ * });
451
+ *
452
+ * // When visitRegion is defined, the handler must traverse into children explicitly.
453
+ * // Without calling context.visitComponents(), components inside the region are skipped.
454
+ * transformPage(page, {
455
+ * visitRegion(context) {
456
+ * console.log(`Entering region: ${context.node.id}`);
457
+ * const components = context.visitComponents(context.node.components);
458
+ * return { ...context.node, components };
459
+ * },
460
+ * visitComponent(context) {
461
+ * console.log(` Component: ${context.node.typeId}`);
462
+ * return context.node;
463
+ * },
464
+ * });
465
+ * ```
466
+ */
467
+ declare function transformPage(page: ShopperExperience.schemas['Page'], visitor: PageVisitor): ShopperExperience.schemas['Page'] | null;
468
+ /**
469
+ * Applies the visitor to a single component. If the visitor's `visitComponent`
470
+ * handler is defined, it receives a {@link VisitorContext} and is responsible
471
+ * for traversing into the component's nested regions using `context.visitRegions()`.
472
+ * If no `visitComponent` handler is defined, nested regions are traversed
473
+ * automatically. Returns `null` to exclude the component from the result.
474
+ *
475
+ * @param component - The component to transform.
476
+ * @param visitor - The visitor with callbacks.
477
+ * @returns The transformed component, or `null` to exclude it.
478
+ *
479
+ * @example
480
+ * ```ts
481
+ * import { transformComponent } from '@salesforce/storefront-next-runtime/design/data';
482
+ *
483
+ * // Replace the image URL in a hero banner component and traverse its nested regions
484
+ * const heroBanner = {
485
+ * id: 'hero-1',
486
+ * typeId: 'commerce_assets.heroBanner',
487
+ * data: { imageUrl: '/images/summer-sale.jpg' },
488
+ * regions: [{ id: 'banner-content', components: [] }],
489
+ * };
490
+ *
491
+ * const result = transformComponent(heroBanner, {
492
+ * visitComponent(context) {
493
+ * // Traverse into nested regions using the context API
494
+ * const regions = context.visitRegions(context.node.regions);
495
+ *
496
+ * if (context.node.typeId === 'commerce_assets.heroBanner') {
497
+ * return { ...context.node, regions, data: { ...context.node.data, imageUrl: '/images/winter-sale.jpg' } };
498
+ * }
499
+ * return { ...context.node, regions };
500
+ * },
501
+ * });
502
+ * ```
503
+ */
504
+ declare function transformComponent(component: ShopperExperience.schemas['Component'], visitor: PageVisitor): ShopperExperience.schemas['Component'] | null;
505
+ /**
506
+ * Applies the visitor to a single region. If the visitor's `visitRegion`
507
+ * handler is defined, it receives a {@link VisitorContext} and is responsible
508
+ * for traversing into the region's child components using `context.visitComponents()`.
509
+ * If no `visitRegion` handler is defined, child components are traversed
510
+ * automatically. Returns `null` to exclude the region and all its children
511
+ * from the result.
512
+ *
513
+ * @param region - The region to transform.
514
+ * @param visitor - The visitor with callbacks.
515
+ * @returns The transformed region, or `null` to exclude it.
516
+ *
517
+ * @example
518
+ * ```ts
519
+ * import { transformRegion } from '@salesforce/storefront-next-runtime/design/data';
520
+ *
521
+ * // Filter empty regions and traverse into non-empty ones
522
+ * const emptyRegion = { id: 'sidebar', components: [] };
523
+ * const populatedRegion = { id: 'main', components: [
524
+ * { id: 'product-grid', typeId: 'commerce_assets.productGrid', regions: [] },
525
+ * ]};
526
+ *
527
+ * const visitor = {
528
+ * visitRegion(context) {
529
+ * if (!context.node.components?.length) {
530
+ * return null; // Remove empty regions
531
+ * }
532
+ * // Traverse into child components using the context API
533
+ * const components = context.visitComponents(context.node.components);
534
+ * return { ...context.node, components };
535
+ * },
536
+ * };
537
+ *
538
+ * transformRegion(emptyRegion, visitor); // => null (removed)
539
+ * transformRegion(populatedRegion, visitor); // => { id: 'main', components: [...] }
540
+ * ```
541
+ */
542
+ declare function transformRegion(region: ShopperExperience.schemas['Region'], visitor: PageVisitor): ShopperExperience.schemas['Region'] | null;
543
+ //#endregion
544
+ //#region src/design/data/errors/required.d.ts
545
+ /**
546
+ * Copyright 2026 Salesforce, Inc.
547
+ *
548
+ * Licensed under the Apache License, Version 2.0 (the "License");
549
+ * you may not use this file except in compliance with the License.
550
+ * You may obtain a copy of the License at
551
+ *
552
+ * http://www.apache.org/licenses/LICENSE-2.0
553
+ *
554
+ * Unless required by applicable law or agreed to in writing, software
555
+ * distributed under the License is distributed on an "AS IS" BASIS,
556
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
557
+ * See the License for the specific language governing permissions and
558
+ * limitations under the License.
559
+ */
560
+ declare class RequiredError extends Error {
561
+ constructor(message: string);
562
+ static assert<TValue>(value: TValue, message: string, isEmpty?: (value: TValue) => boolean): asserts value is NonNullable<TValue>;
563
+ }
564
+ //#endregion
565
+ //#region src/design/data/page/resolve-data-bindings.d.ts
566
+ /**
567
+ * Data binding metadata attached to a component instance. Stored in the
568
+ * component's `custom.dataBinding` field by ECOM when the author binds a
569
+ * data source to the component in Page Designer.
570
+ */
571
+ interface ComponentDataBinding {
572
+ /** Maps attribute names to expression strings (e.g. `"content_asset.body"`). */
573
+ expressions: Record<string, string>;
574
+ /** The data contexts bound to this component, identifying the records to resolve against. */
575
+ contexts: DataBindingContext[];
576
+ }
577
+ /**
578
+ * A data context reference on a component instance, identifying a specific
579
+ * record from a data provider.
580
+ */
581
+ interface DataBindingContext {
582
+ /** The data provider type (e.g. `"content_asset"`). */
583
+ type: string;
584
+ /** The record identifier (e.g. a content asset UUID). */
585
+ id: string;
586
+ }
587
+ /**
588
+ * Parses a binding expression string into its provider type and field name.
589
+ * Supports the bare `type.field` format.
590
+ *
591
+ * @param expression - The expression string to parse.
592
+ * @returns The parsed type and field, or `null` if the expression is invalid.
593
+ *
594
+ * @example
595
+ * ```ts
596
+ * parseExpression('content_asset.title'); // { type: 'content_asset', field: 'title' }
597
+ * parseExpression('invalid'); // null
598
+ * ```
599
+ */
600
+ declare function parseExpression(expression: string): {
601
+ type: string;
602
+ field: string;
603
+ } | null;
604
+ /**
605
+ * Resolves a single binding expression against the component's data contexts
606
+ * and the resolved data bindings from context resolution.
607
+ *
608
+ * Returns the resolved field value, or an empty string if the expression is
609
+ * invalid, the matching context or record is not found, or the field does not
610
+ * exist on the resolved record.
611
+ *
612
+ * @param expression - The expression string (e.g. `"content_asset.body"`).
613
+ * @param contexts - The component's data binding contexts.
614
+ * @param dataBindings - The resolved data bindings from {@link QualifierContext}.
615
+ * @returns The resolved value, or `''` if resolution fails.
616
+ */
617
+ declare function resolveExpression(expression: string, contexts: DataBindingContext[], dataBindings: NonNullable<QualifierContext['dataBindings']>): unknown;
618
+ /**
619
+ * Resolves data binding expressions for a single component. Replaces attribute
620
+ * values in the component's `data` with the resolved values from context
621
+ * resolution. Attributes without a matching expression are preserved as-is.
622
+ * When an expression cannot be resolved, the attribute value is set to an
623
+ * empty string.
624
+ *
625
+ * Returns the component unchanged if it has no data binding metadata or if
626
+ * `dataBindings` is `undefined`.
627
+ *
628
+ * @param component - The component to resolve data bindings for.
629
+ * @param dataBindings - The resolved data bindings from {@link QualifierContext}, or `undefined` if no bindings were resolved.
630
+ * @returns The component with resolved attribute values, or the original component if no bindings apply.
631
+ *
632
+ * @example
633
+ * ```ts
634
+ * import { resolveComponentDataBindings } from '@salesforce/storefront-next-runtime/design/data';
635
+ *
636
+ * const component = {
637
+ * id: 'banner',
638
+ * typeId: 'commerce_assets.contentBanner',
639
+ * data: { heading: 'Fallback Title', body: 'Fallback Body' },
640
+ * custom: {
641
+ * dataBinding: {
642
+ * expressions: {
643
+ * heading: 'content_asset.title',
644
+ * body: 'content_asset.body',
645
+ * },
646
+ * contexts: [{ type: 'content_asset', id: 'winter-sale-uuid' }],
647
+ * },
648
+ * },
649
+ * regions: [],
650
+ * };
651
+ *
652
+ * const dataBindings = {
653
+ * content_asset: {
654
+ * 'winter-sale-uuid': {
655
+ * title: 'Winter Sale',
656
+ * body: '<div>Free Shipping on all orders!</div>',
657
+ * },
658
+ * },
659
+ * };
660
+ *
661
+ * const resolved = resolveComponentDataBindings(component, dataBindings);
662
+ * // resolved.data.heading === 'Winter Sale'
663
+ * // resolved.data.body === '<div>Free Shipping on all orders!</div>'
664
+ * ```
665
+ */
666
+ declare function resolveComponentDataBindings(component: ShopperExperience.schemas['Component'], dataBindings: QualifierContext['dataBindings']): ShopperExperience.schemas['Component'];
667
+ //#endregion
668
+ //#region src/design/data/page/resolve-page.d.ts
669
+ /**
670
+ * Main entry point for the page resolution pipeline. Orchestrates the full flow:
671
+ *
672
+ * 1. **Resolve dynamic page ID** — For product/category identifiers, looks up
673
+ * the assigned page ID via content assignments in the site manifest.
674
+ * 2. **Fetch page manifest** — Loads all variations for the resolved page.
675
+ * 3. **Select variation** — Evaluates visibility rules to pick the right variation.
676
+ * 4. **Load qualifier context** — Lazily fetches the shopper's context only if needed.
677
+ * 5. **Process page** — Filters out components that fail visibility rules.
678
+ *
679
+ * Returns `null` if the page ID cannot be resolved, the manifest doesn't exist,
680
+ * or no variation is available.
681
+ *
682
+ * @param options - The resolution options.
683
+ * @param options.id - The identifier to resolve (product ID, category ID, or page ID).
684
+ * @param options.identifierType - The type of identifier: `'product'`, `'category'`, or `'page'`.
685
+ * @param options.locale - The locale to resolve the page for (e.g. `"en-US"`).
686
+ * @param options.manifestStorage - Storage implementation for fetching manifests.
687
+ * @param options.contextResolver - Optional async function that returns the shopper's qualifier context. Only called if a visibility rule needs it.
688
+ * @param options.aspectType - The aspect type to resolve the page for when the identifier type is `'product'` or `'category'`.
689
+ * @returns The fully resolved and filtered page, or `null`.
690
+ *
691
+ * @example
692
+ * ```ts
693
+ * import { resolvePage } from '@salesforce/storefront-next-runtime/design/data';
694
+ *
695
+ * // Resolve the PDP page for a specific product with an active holiday campaign
696
+ * const page = await resolvePage({
697
+ * id: 'nike-air-max-90',
698
+ * identifierType: 'product',
699
+ * aspectType: 'pdp',
700
+ * locale: 'en-US',
701
+ * manifestStorage: {
702
+ * async getPageManifest(id, locale) {
703
+ * // Fetch from CDN, filesystem, or database
704
+ * return fetchManifest(`/manifests/${locale}/${id}.json`);
705
+ * },
706
+ * async getSiteManifest(locale) {
707
+ * return fetchManifest(`/manifests/${locale}/site.json`);
708
+ * },
709
+ * },
710
+ * contextResolver: async () => ({
711
+ * customerGroups: { 'vip-customers': true },
712
+ * campaignQualifiers: {
713
+ * 'holiday-sale-2026': { 'free-shipping': true },
714
+ * },
715
+ * }),
716
+ * });
717
+ *
718
+ * if (page) {
719
+ * // page.regions contains only components visible to this VIP shopper
720
+ * // during the holiday sale campaign
721
+ * renderPage(page);
722
+ * }
723
+ * ```
724
+ */
725
+ declare function resolvePage({
726
+ id,
727
+ identifierType,
728
+ aspectType,
729
+ locale,
730
+ manifestStorage,
731
+ contextResolver
732
+ }: {
733
+ id: string;
734
+ identifierType: IdentifierType;
735
+ aspectType?: string;
736
+ locale: string;
737
+ manifestStorage: ManifestStorage;
738
+ contextResolver?: () => Promise<QualifierContext>;
739
+ }): Promise<ShopperExperience.schemas['Page'] | null>;
740
+ //#endregion
741
+ //#region src/design/data/manifest/resolve-dynamic-page-id.d.ts
742
+ /**
743
+ * Converts a product or category identifier into a page ID by looking up
744
+ * content assignments in the site manifest. For categories, the lookup
745
+ * traverses the category hierarchy from the given category up to the root,
746
+ * returning the first matching assignment.
747
+ *
748
+ * Returns `null` if no content assignment is found for the identifier or if
749
+ * the identifier type has no registered resolver.
750
+ *
751
+ * @param options - The resolution options.
752
+ * @param options.id - The identifier to resolve (product ID, category ID, or page ID).
753
+ * @param options.identifierType - The type of identifier: `'product'`, `'category'`, or `'page'`.
754
+ * @param options.siteManifest - The site manifest containing content assignments and category hierarchy.
755
+ * @returns The resolved page ID, or `null` if no assignment was found.
756
+ *
757
+ * @example
758
+ * ```ts
759
+ * import { resolveDynamicPageId } from '@salesforce/storefront-next-runtime/design/data';
760
+ *
761
+ * const siteManifest = {
762
+ * contentObjectAssignments: {
763
+ * plp: {
764
+ * category: {
765
+ * 'mens-shoes': {
766
+ * lookupMode: 'category-explicit',
767
+ * contentId: 'page-mens-shoes-plp',
768
+ * },
769
+ * },
770
+ * },
771
+ * },
772
+ * categories: {
773
+ * 'mens-running-shoes': { name: 'Running Shoes', parentCategory: 'mens-shoes' },
774
+ * 'mens-shoes': { name: "Men's Shoes" },
775
+ * },
776
+ * };
777
+ *
778
+ * // Direct match
779
+ * resolveDynamicPageId({ id: 'mens-shoes', identifierType: 'category', siteManifest });
780
+ * // => 'page-mens-shoes-plp'
781
+ *
782
+ * // Inherited from parent category
783
+ * resolveDynamicPageId({ id: 'mens-running-shoes', identifierType: 'category', siteManifest });
784
+ * // => 'page-mens-shoes-plp' (found via parent traversal)
785
+ *
786
+ * // No assignment found
787
+ * resolveDynamicPageId({ id: 'womens-shoes', identifierType: 'category', siteManifest });
788
+ * // => null
789
+ * ```
790
+ */
791
+ declare function resolveDynamicPageId<TIdentifier extends IdentifierType = IdentifierType>({
792
+ id,
793
+ identifierType,
794
+ siteManifest,
795
+ aspectType
796
+ }: {
797
+ id: string;
798
+ identifierType: TIdentifier;
799
+ aspectType: string;
800
+ siteManifest?: SiteManifest;
801
+ }): string | null;
802
+ //#endregion
803
+ //#region src/design/data/manifest/get-page.d.ts
804
+ /**
805
+ * Selects the appropriate page variation from a manifest by evaluating each
806
+ * variation's visibility rule in order. Returns the first variation whose rule
807
+ * passes, or falls back to the manifest's default variation.
808
+ *
809
+ * The qualifier context is resolved lazily — the `contextResolver` is only
810
+ * called when a variation's `ruleRequiresContext` flag is `true`, and only
811
+ * once (the result is cached for subsequent variations).
812
+ *
813
+ * @param manifest - The page manifest containing all variations.
814
+ * @param options - Resolution options.
815
+ * @param options.contextResolver - Optional async function that returns the shopper's qualifier context. Only called if a variation's rule needs it.
816
+ * @returns The selected variation entry and resolved context, or `null` if no variation (including default) exists.
817
+ *
818
+ * @example
819
+ * ```ts
820
+ * import { getPageFromManifest } from '@salesforce/storefront-next-runtime/design/data';
821
+ *
822
+ * const manifest = {
823
+ * pageId: 'homepage',
824
+ * locale: 'en-US',
825
+ * context: { campaignQualifiers: [], customerGroups: ['vip-customers'], dataBindings: [] },
826
+ * variationOrder: ['vip-homepage', 'holiday-homepage'],
827
+ * variations: {
828
+ * 'vip-homepage': {
829
+ * ruleRequiresContext: true,
830
+ * pageRequiresContext: false,
831
+ * visibilityRule: { customerGroups: ['vip-customers'] },
832
+ * page: { id: 'homepage', typeId: 'storePage', regions: [] },
833
+ * },
834
+ * 'holiday-homepage': {
835
+ * ruleRequiresContext: false,
836
+ * pageRequiresContext: false,
837
+ * visibilityRule: {
838
+ * schedule: {
839
+ * start: new Date('2026-12-01').getTime(),
840
+ * end: new Date('2026-12-31').getTime(),
841
+ * },
842
+ * },
843
+ * page: { id: 'homepage', typeId: 'storePage', regions: [] },
844
+ * },
845
+ * 'default-homepage': {
846
+ * ruleRequiresContext: false,
847
+ * pageRequiresContext: false,
848
+ * page: { id: 'homepage', typeId: 'storePage', regions: [] },
849
+ * },
850
+ * },
851
+ * defaultVariation: 'default-homepage',
852
+ * visibilityRules: {},
853
+ * };
854
+ *
855
+ * // VIP shopper — matches first variation
856
+ * const result = await getPageFromManifest(manifest, {
857
+ * contextResolver: async () => ({
858
+ * customerGroups: { 'vip-customers': true },
859
+ * campaignQualifiers: {},
860
+ * }),
861
+ * });
862
+ * // result.entry === manifest.variations['vip-homepage']
863
+ *
864
+ * // Non-VIP shopper outside holiday window — falls back to default
865
+ * const fallback = await getPageFromManifest(manifest, {
866
+ * contextResolver: async () => ({
867
+ * customerGroups: {},
868
+ * campaignQualifiers: {},
869
+ * }),
870
+ * });
871
+ * // fallback.entry === manifest.variations['default-homepage']
872
+ * ```
873
+ */
874
+ declare function getPageFromManifest(manifest: PageManifest, {
875
+ contextResolver
876
+ }: {
877
+ contextResolver?: () => Promise<QualifierContext>;
878
+ }): Promise<{
879
+ entry: VariationEntry;
880
+ context: QualifierContext | null;
881
+ } | null>;
882
+ //#endregion
883
+ //#region src/design/data/manifest/content-assignment-resolvers.d.ts
884
+ /**
885
+ * The result of resolving an identifier through a content assignment resolver.
886
+ * Contains the object type, aspect type, and ordered list of keys to search
887
+ * in the site manifest's content assignments.
888
+ */
889
+ interface ResolvedContentAssignmentLookup {
890
+ /** The type of commerce object (e.g. `'product'`, `'category'`). */
891
+ objectType: string;
892
+ /** Ordered list of object IDs to search in the site manifest's content assignments. */
893
+ keys: string[];
894
+ }
895
+ /**
896
+ * A function that converts an identifier key (e.g., a product or category ID)
897
+ * into a {@link ResolvedContentAssignmentLookup} describing where to search
898
+ * in the site manifest for the assigned page ID.
899
+ */
900
+ type ContentAssignmentResolver = (key: string, manifest?: SiteManifest) => ResolvedContentAssignmentLookup;
901
+ /**
902
+ * Registry of content assignment resolvers keyed by {@link IdentifierType}.
903
+ * Each resolver knows how to convert its identifier type into a set of lookup
904
+ * keys for the site manifest.
905
+ *
906
+ * Built-in resolvers:
907
+ * - **`'product'`** — Maps a product ID to a single PDP lookup key.
908
+ * - **`'category'`** — Maps a category ID to an ordered list of keys that
909
+ * traverses the category hierarchy from child to root, enabling inherited
910
+ * page assignments.
911
+ *
912
+ * The `'page'` identifier type has no resolver — page IDs are used directly.
913
+ *
914
+ * @example
915
+ * ```ts
916
+ * import { ContentAssignmentResolvers } from '@salesforce/storefront-next-runtime/design/data';
917
+ *
918
+ * // Resolve a product identifier for PDP lookup
919
+ * const productResolver = ContentAssignmentResolvers.get('product');
920
+ * productResolver('nike-air-max-90');
921
+ * // => { objectType: 'product', aspectType: 'pdp', keys: ['nike-air-max-90'] }
922
+ *
923
+ * // Resolve a category identifier — traverses hierarchy to find inherited assignments
924
+ * const categoryResolver = ContentAssignmentResolvers.get('category');
925
+ * const siteManifest = {
926
+ * categories: {
927
+ * 'mens-running-shoes': { name: 'Running Shoes', parentCategory: 'mens-shoes' },
928
+ * 'mens-shoes': { name: "Men's Shoes", parentCategory: 'mens' },
929
+ * 'mens': { name: 'Men' },
930
+ * },
931
+ * contentObjectAssignments: {},
932
+ * };
933
+ * categoryResolver('mens-running-shoes', siteManifest);
934
+ * // => { objectType: 'category', aspectType: 'plp', keys: ['mens-running-shoes', 'mens-shoes', 'mens'] }
935
+ * ```
936
+ */
937
+ declare const ContentAssignmentResolvers: Map<string, ContentAssignmentResolver>;
938
+ //#endregion
939
+ //#region src/design/data/validate-rule.d.ts
940
+ /**
941
+ * Evaluates a visibility rule against a shopper's qualifier context.
942
+ *
943
+ * Campaign-based and non-campaign rules are **mutually exclusive** paths,
944
+ * matching the server's `VisibilityDefinition.isVisible()` logic:
945
+ *
946
+ * - **Campaign-based rule** (has `campaignQualifiers`): only the campaign
947
+ * qualifiers are checked. Schedule and customer-group fields are ignored
948
+ * because the campaign qualification already incorporates those checks
949
+ * server-side.
950
+ * - **Non-campaign rule**: schedule AND customer groups are checked. All
951
+ * specified conditions must pass.
952
+ *
953
+ * When no context is provided and the rule requires campaign or customer group
954
+ * checks, those checks will fail (returning `false`). Schedule checks do not
955
+ * require context and are evaluated against `Date.now()`.
956
+ *
957
+ * @param rule - The visibility rule to evaluate.
958
+ * @param context - The shopper's active qualifiers, or `null`/`undefined` if not yet resolved.
959
+ * @returns `true` if the rule's conditions pass, `false` otherwise.
960
+ *
961
+ * @example
962
+ * ```ts
963
+ * import { validateRule } from '@salesforce/storefront-next-runtime/design/data';
964
+ *
965
+ * // Campaign-based rule — only campaign qualifiers are evaluated
966
+ * const campaignRule = {
967
+ * campaignQualifiers: [{ campaignId: 'holiday-sale-2026', promotionId: 'free-shipping' }],
968
+ * };
969
+ *
970
+ * // Non-campaign rule — schedule AND customer groups are evaluated
971
+ * const segmentRule = {
972
+ * customerGroups: ['vip-customers'],
973
+ * schedule: {
974
+ * start: new Date('2026-12-01').toISOString(),
975
+ * end: new Date('2026-12-31').toISOString(),
976
+ * },
977
+ * };
978
+ * ```
979
+ */
980
+ declare function validateRule(rule: VisibilityRuleDef, context?: QualifierContext | null): boolean;
981
+ //#endregion
982
+ export { CampaignQualifier, type ComponentDataBinding, ContentAssignmentResolvers, type DataBindingContext, DataBindingRequirement, IdentifierType, InferNodeFromType, ManifestStorage, PageManifest, PageManifestContext, type PageProcessorContext, type PageVisitor, QualifierContext, RequiredError, ResolvedDataBinding, SiteManifest, VariationEntry, VisibilityRuleDef, type VisitorContext, VisitorContextType, getPageFromManifest, parseExpression, processPage, resolveComponentDataBindings, resolveDynamicPageId, resolveExpression, resolvePage, transformComponent, transformPage, transformRegion, validateRule };
983
+ //# sourceMappingURL=design-data.d.ts.map