@salesforce/storefront-next-runtime 0.4.2 → 1.0.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.
- package/README.md +9 -3
- package/dist/ComponentContext.js +199 -4
- package/dist/ComponentContext.js.map +1 -1
- package/dist/DesignComponent.js +2 -2
- package/dist/DesignRegion.js +2 -2
- package/dist/RegionContext.js +9 -0
- package/dist/RegionContext.js.map +1 -0
- package/dist/component.types.d.ts +1 -1
- package/dist/config.d.ts +34 -221
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +35 -116
- package/dist/config.js.map +1 -1
- package/dist/data-store.d.ts +185 -15
- package/dist/data-store.d.ts.map +1 -1
- package/dist/data-store.js +412 -10
- package/dist/data-store.js.map +1 -1
- package/dist/defaults.d.ts +106 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/defaults.js +67 -0
- package/dist/defaults.js.map +1 -0
- package/dist/design-data.d.ts +238 -356
- package/dist/design-data.d.ts.map +1 -1
- package/dist/design-data.js +459 -30
- package/dist/design-data.js.map +1 -1
- package/dist/design-mode.d.ts +3 -2
- package/dist/design-mode.d.ts.map +1 -1
- package/dist/design-react-core.d.ts +5 -15
- package/dist/design-react-core.d.ts.map +1 -1
- package/dist/design-react-core.js +2 -2
- package/dist/design-react.d.ts +2 -2
- package/dist/design.d.ts +2 -2
- package/dist/events.d.ts +32 -6
- package/dist/events.d.ts.map +1 -1
- package/dist/i18n-client.d.ts.map +1 -1
- package/dist/i18n-client.js.map +1 -1
- package/dist/i18n.d.ts +1 -2
- package/dist/i18n.d.ts.map +1 -1
- package/dist/modeDetection.js +0 -18
- package/dist/modeDetection.js.map +1 -1
- package/dist/scapi.d.ts +2185 -466
- package/dist/scapi.d.ts.map +1 -1
- package/dist/scapi.js +1 -1
- package/dist/scapi.js.map +1 -1
- package/dist/schema.d.ts +17 -15
- package/dist/schema.d.ts.map +1 -1
- package/dist/security-react.d.ts +34 -0
- package/dist/security-react.d.ts.map +1 -0
- package/dist/security-react.js +21 -0
- package/dist/security-react.js.map +1 -0
- package/dist/security.d.ts +61 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +304 -0
- package/dist/security.js.map +1 -0
- package/dist/site-context.d.ts +43 -27
- package/dist/site-context.d.ts.map +1 -1
- package/dist/site-context.js +2 -2
- package/dist/site-context2.js +41 -31
- package/dist/site-context2.js.map +1 -1
- package/dist/types.d.ts +19 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types2.d.ts +89 -63
- package/dist/types2.d.ts.map +1 -1
- package/dist/types3.d.ts +1 -35
- package/dist/types3.d.ts.map +1 -1
- package/package.json +15 -20
- package/dist/DesignFrame.js +0 -204
- package/dist/DesignFrame.js.map +0 -1
- package/dist/custom-global-preferences.d.ts +0 -20
- package/dist/custom-global-preferences.d.ts.map +0 -1
- package/dist/custom-global-preferences.js +0 -31
- package/dist/custom-global-preferences.js.map +0 -1
- package/dist/custom-site-preferences.d.ts +0 -20
- package/dist/custom-site-preferences.d.ts.map +0 -1
- package/dist/custom-site-preferences.js +0 -31
- package/dist/custom-site-preferences.js.map +0 -1
- package/dist/data-store-custom-global-preferences.d.ts +0 -2
- package/dist/data-store-custom-global-preferences.js +0 -6
- package/dist/data-store-custom-site-preferences.d.ts +0 -2
- package/dist/data-store-custom-site-preferences.js +0 -6
- package/dist/data-store-gcp-preferences.d.ts +0 -2
- package/dist/data-store-gcp-preferences.js +0 -6
- package/dist/gcp-preferences.d.ts +0 -52
- package/dist/gcp-preferences.d.ts.map +0 -1
- package/dist/gcp-preferences.js +0 -64
- package/dist/gcp-preferences.js.map +0 -1
- package/dist/utils.js +0 -90
- package/dist/utils.js.map +0 -1
package/dist/design-data.d.ts
CHANGED
|
@@ -1,5 +1,133 @@
|
|
|
1
1
|
import { r as ShopperExperience } from "./types2.js";
|
|
2
2
|
|
|
3
|
+
//#region src/design/data/page/attribute-resolution.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Per-request resolution surface. Storefront-next builds one of these from
|
|
7
|
+
* the request URL + site config; Page Designer preview builds one against
|
|
8
|
+
* the BM origin. Both surfaces inject URL-building utilities so this module
|
|
9
|
+
* stays platform-neutral.
|
|
10
|
+
*/
|
|
11
|
+
interface AttributeResolutionContext {
|
|
12
|
+
/**
|
|
13
|
+
* Storefront origin used to absolutize URLs, e.g.
|
|
14
|
+
* `"https://www.shop.example"`. Page Designer preview supplies the BM
|
|
15
|
+
* origin instead.
|
|
16
|
+
*/
|
|
17
|
+
host: string;
|
|
18
|
+
/**
|
|
19
|
+
* Builds a static-content URL for a media-file path inside a library.
|
|
20
|
+
* Mirrors ECOM's `MediaFile.getAbsURL()` chain, parameterized by the
|
|
21
|
+
* storefront request rather than a JVM `Request`.
|
|
22
|
+
*
|
|
23
|
+
* The {@code locale} hint is optional — when omitted, the resolver
|
|
24
|
+
* substitutes `"default"` so URLs still resolve.
|
|
25
|
+
*/
|
|
26
|
+
resolveMediaUrl: (ref: {
|
|
27
|
+
libraryDomain: string;
|
|
28
|
+
path: string;
|
|
29
|
+
locale?: string;
|
|
30
|
+
}) => string;
|
|
31
|
+
/**
|
|
32
|
+
* Resolves a library-relative path inside markup (`?$staticlink$`).
|
|
33
|
+
* When omitted, falls back to {@link resolveMediaUrl}.
|
|
34
|
+
*/
|
|
35
|
+
staticLinkFor?: (ref: {
|
|
36
|
+
libraryDomain: string;
|
|
37
|
+
path: string;
|
|
38
|
+
locale?: string;
|
|
39
|
+
}) => string;
|
|
40
|
+
/**
|
|
41
|
+
* Default library media domain used when rewriting `?$staticlink$`
|
|
42
|
+
* references inside markup attributes. Sourced from
|
|
43
|
+
* {@code manifest.pageLibraryDomain} and threaded through by the
|
|
44
|
+
* caller. Optional — when omitted, `?$staticlink$` placeholders inside
|
|
45
|
+
* markup are left untouched and a one-time warning fires.
|
|
46
|
+
*/
|
|
47
|
+
pageLibraryDomain?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Locale hint forwarded to {@link resolveMediaUrl}. Page Designer
|
|
50
|
+
* preview may omit this when the editor session has no locale; the
|
|
51
|
+
* resolver substitutes `"default"` in that case.
|
|
52
|
+
*/
|
|
53
|
+
locale?: string;
|
|
54
|
+
/**
|
|
55
|
+
* Optional handler invoked when the resolver encounters a recoverable
|
|
56
|
+
* problem — malformed envelopes, unknown attribute types, depth limits
|
|
57
|
+
* exceeded. Lets the consumer route these into its own logger / metric
|
|
58
|
+
* pipeline instead of the SDK calling `console.warn` directly.
|
|
59
|
+
*
|
|
60
|
+
* The runtime dedupes calls to {@code onWarn} per
|
|
61
|
+
* `(typeId, attrId, attrType)` triple so a misshapen value processed
|
|
62
|
+
* many times only fires the handler once per process.
|
|
63
|
+
*
|
|
64
|
+
* When omitted the runtime stays silent — fits unit tests and Page
|
|
65
|
+
* Designer preview where stderr noise is undesirable. Production
|
|
66
|
+
* callers should supply a handler that forwards to their structured
|
|
67
|
+
* logger.
|
|
68
|
+
*/
|
|
69
|
+
onWarn?: (warning: AttributeResolutionWarning) => void;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Payload passed to {@link AttributeResolutionContext.onWarn}. Keep this
|
|
73
|
+
* shape stable — consumers may pattern-match on `kind` to decide log
|
|
74
|
+
* level, attach extra metadata, etc.
|
|
75
|
+
*/
|
|
76
|
+
interface AttributeResolutionWarning {
|
|
77
|
+
/**
|
|
78
|
+
* Identifier for the kind of issue, useful for routing or grouping in
|
|
79
|
+
* downstream logging:
|
|
80
|
+
*
|
|
81
|
+
* - `malformed-image` / `malformed-file` / `malformed-cms-record` —
|
|
82
|
+
* the manifest envelope didn't match the expected shape and the
|
|
83
|
+
* value is being passed through unchanged.
|
|
84
|
+
* - `unknown-attribute-type` — the runtime saw an attribute type it
|
|
85
|
+
* doesn't recognize (forward-compat from a newer ECOM).
|
|
86
|
+
* - `cms-record-depth-exceeded` — recursive cms_record nesting hit
|
|
87
|
+
* the resolver's safety limit.
|
|
88
|
+
* - `staticlink-rewrite-skipped` — markup contains `?$staticlink$`
|
|
89
|
+
* placeholders but `ctx.pageLibraryDomain` was not configured, so
|
|
90
|
+
* the placeholder is left in the source. Fires once per process
|
|
91
|
+
* regardless of how many markup attributes hit it (tracked via the
|
|
92
|
+
* {@code typeId}/{@code attrId} fields, both empty strings, in the
|
|
93
|
+
* {@code warnOnce} dedup key).
|
|
94
|
+
*/
|
|
95
|
+
kind: 'malformed-image' | 'malformed-file' | 'malformed-cms-record' | 'cms-record-depth-exceeded' | 'unknown-attribute-type' | 'staticlink-rewrite-skipped';
|
|
96
|
+
/** Human-readable message — safe to log directly. */
|
|
97
|
+
message: string;
|
|
98
|
+
/** Component type id the offending attribute belongs to. */
|
|
99
|
+
typeId: string;
|
|
100
|
+
/** Attribute id within the component. */
|
|
101
|
+
attrId: string;
|
|
102
|
+
/** The attribute's declared type, when known. Empty for inner cms_record entries that don't carry a type. */
|
|
103
|
+
attrType: string;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Slim attribute definition used by the resolver to dispatch by type.
|
|
107
|
+
* Mirrors the fields {@code AttributeDefinition} ships in SCAPI's
|
|
108
|
+
* `componentTypes` map. Defined here so the resolver doesn't take a
|
|
109
|
+
* dependency on the larger SCAPI generated types.
|
|
110
|
+
*/
|
|
111
|
+
interface AttributeDefinition {
|
|
112
|
+
/** Attribute identifier as authored by the merchant (e.g. `"hero"`). */
|
|
113
|
+
id: string;
|
|
114
|
+
/**
|
|
115
|
+
* Lower-case attribute type identifier matching ECOM's
|
|
116
|
+
* {@code AttributeDefinition.Type#getID}. Examples:
|
|
117
|
+
* `"string"`, `"text"`, `"image"`, `"markup"`, `"file"`, `"cms_record"`.
|
|
118
|
+
*/
|
|
119
|
+
type: string;
|
|
120
|
+
/**
|
|
121
|
+
* Default value declared on the attribute definition. Used by component
|
|
122
|
+
* data composition as a fallback when neither the active locale nor the
|
|
123
|
+
* fallback locale has a value for this attribute (see
|
|
124
|
+
* {@code processPage}'s `visitComponent`). The shape is whatever the
|
|
125
|
+
* attribute's `type` would normally hold — a string for `string`/`text`,
|
|
126
|
+
* an envelope for `image`/`file`, etc.
|
|
127
|
+
*/
|
|
128
|
+
defaultValue?: unknown;
|
|
129
|
+
}
|
|
130
|
+
//#endregion
|
|
3
131
|
//#region src/design/data/types.d.ts
|
|
4
132
|
|
|
5
133
|
/**
|
|
@@ -19,6 +147,22 @@ interface PageManifest {
|
|
|
19
147
|
variations: Record<string, VariationEntry>;
|
|
20
148
|
/** The variation ID to use when no other variation's rule matches. */
|
|
21
149
|
defaultVariation: string;
|
|
150
|
+
/**
|
|
151
|
+
* Per-component-type attribute definitions hoisted from the page layout
|
|
152
|
+
* by the manifest builder, deduped by `typeId`. Used by the MRT
|
|
153
|
+
* attribute resolver to dispatch by attribute type without round-tripping
|
|
154
|
+
* to ECOM. Optional — older manifests may not include this field.
|
|
155
|
+
*/
|
|
156
|
+
componentTypes?: Record<string, {
|
|
157
|
+
attributeDefinitions: Record<string, AttributeDefinition>;
|
|
158
|
+
}>;
|
|
159
|
+
/**
|
|
160
|
+
* Media-file domain name of the page's owning library. Used by the markup
|
|
161
|
+
* URL rewriter to resolve `?$staticlink$` placeholders at request time.
|
|
162
|
+
* Set by the manifest builder from `library.getMediaFileDomain().getDomainName()`.
|
|
163
|
+
* Optional — older manifests may not include this field.
|
|
164
|
+
*/
|
|
165
|
+
pageLibraryDomain?: string;
|
|
22
166
|
/**
|
|
23
167
|
* Component visibility rule definitions extracted from the page layout.
|
|
24
168
|
* Maps each component ID to its array of rule objects and a flag indicating
|
|
@@ -27,7 +171,7 @@ interface PageManifest {
|
|
|
27
171
|
componentInfo: {
|
|
28
172
|
[componentId: string]: {
|
|
29
173
|
/** The visibility rules for this component. */
|
|
30
|
-
visibilityRules
|
|
174
|
+
visibilityRules?: VisibilityRuleDef[];
|
|
31
175
|
/**
|
|
32
176
|
* Locale-specific content attributes for this component. Keyed by locale
|
|
33
177
|
* (e.g. `"en_US"`), each entry contains attribute values that are merged
|
|
@@ -36,10 +180,16 @@ interface PageManifest {
|
|
|
36
180
|
content?: {
|
|
37
181
|
[locale: string]: Record<string, unknown>;
|
|
38
182
|
};
|
|
39
|
-
/** Data binding metadata for this component
|
|
40
|
-
dataBinding?: ComponentDataBinding
|
|
183
|
+
/** Data binding metadata for this component. Omitted when the component has no bindings. */
|
|
184
|
+
dataBinding?: ComponentDataBinding;
|
|
185
|
+
/** Whether this component is a fragment (a reusable, externally-managed content asset). */
|
|
186
|
+
fragment?: boolean;
|
|
187
|
+
/** Custom component data produced by the type's serialize script. Omitted when the component has no custom data. */
|
|
188
|
+
custom?: Record<string, unknown>;
|
|
189
|
+
/** Display name of the component. Omitted when the component has no name. */
|
|
190
|
+
name?: string;
|
|
41
191
|
/** Region-level configuration (e.g. maxComponents limits), keyed by region ID. */
|
|
42
|
-
regions
|
|
192
|
+
regions?: {
|
|
43
193
|
[regionId: string]: RegionInfo;
|
|
44
194
|
};
|
|
45
195
|
};
|
|
@@ -48,13 +198,13 @@ interface PageManifest {
|
|
|
48
198
|
/** Region-level configuration extracted from the page manifest, including type filters and component limits. */
|
|
49
199
|
interface RegionInfo {
|
|
50
200
|
/** The name of the region. */
|
|
51
|
-
name
|
|
201
|
+
name?: string;
|
|
52
202
|
/** The component type exclusions for the region. */
|
|
53
|
-
componentTypeExclusions
|
|
203
|
+
componentTypeExclusions?: string[];
|
|
54
204
|
/** The component type inclusions for the region. */
|
|
55
|
-
componentTypeInclusions
|
|
56
|
-
/** Maximum number of visible components to render in this region
|
|
57
|
-
maxComponents
|
|
205
|
+
componentTypeInclusions?: string[];
|
|
206
|
+
/** Maximum number of visible components to render in this region. Omitted when there is no limit. */
|
|
207
|
+
maxComponents?: number;
|
|
58
208
|
}
|
|
59
209
|
/**
|
|
60
210
|
* Site-wide manifest containing content assignments that map product and category
|
|
@@ -152,13 +302,52 @@ interface VariationEntry {
|
|
|
152
302
|
ruleRequiresContext: boolean;
|
|
153
303
|
/** The visibility rule that must pass for this variation to be selected. Undefined for the default variation. */
|
|
154
304
|
visibilityRule?: VisibilityRuleDef;
|
|
155
|
-
/**
|
|
305
|
+
/**
|
|
306
|
+
* The full page data for this variation. Includes the SCAPI-shape page
|
|
307
|
+
* metadata fields (`name`, `aspectTypeId`, `description`, `pageTitle`,
|
|
308
|
+
* `pageDescription`, `pageKeywords`) populated from the default-locale
|
|
309
|
+
* `Page` by the manifest builder. Non-default-locale overrides for
|
|
310
|
+
* these fields live in {@link pageContent}.
|
|
311
|
+
*/
|
|
156
312
|
page: ShopperExperience.schemas['Page'];
|
|
313
|
+
/**
|
|
314
|
+
* Per-locale overlay for the variation's page metadata. When the request
|
|
315
|
+
* locale is not the default and the page metadata differs, the manifest
|
|
316
|
+
* builder writes the **full set** of locale-specific page metadata fields
|
|
317
|
+
* here (full replacement, not diff — see Q6 of the design plan).
|
|
318
|
+
*
|
|
319
|
+
* Each entry is a partial `Page` carrying only the metadata fields that
|
|
320
|
+
* may be locale-overridden (`name`, `aspectTypeId`, `description`,
|
|
321
|
+
* `pageTitle`, `pageDescription`, `pageKeywords`); structural fields
|
|
322
|
+
* (`id`, `typeId`, `regions`) live on {@link page} and are never
|
|
323
|
+
* locale-overlaid.
|
|
324
|
+
*
|
|
325
|
+
* Absent or missing entries fall back to the default-locale page
|
|
326
|
+
* metadata. Optional — older manifests may not include this field.
|
|
327
|
+
*/
|
|
328
|
+
pageContent?: {
|
|
329
|
+
[locale: string]: PageMetadataOverlay;
|
|
330
|
+
};
|
|
157
331
|
/** Page-level region configuration for this variation, keyed by region ID. These are top-level regions owned by the page itself, not nested under a component. */
|
|
158
332
|
regions: {
|
|
159
333
|
[regionId: string]: RegionInfo;
|
|
160
334
|
};
|
|
161
335
|
}
|
|
336
|
+
/**
|
|
337
|
+
* Subset of {@link ShopperExperience.schemas#Page} fields that the manifest
|
|
338
|
+
* builder may locale-overlay. Stored on
|
|
339
|
+
* {@link VariationEntry.pageContent} keyed by locale ID. Structural fields
|
|
340
|
+
* (`id`, `typeId`, `regions`) are intentionally excluded — they are not
|
|
341
|
+
* locale-scoped.
|
|
342
|
+
*/
|
|
343
|
+
interface PageMetadataOverlay {
|
|
344
|
+
name?: string;
|
|
345
|
+
aspectTypeId?: string;
|
|
346
|
+
description?: string;
|
|
347
|
+
pageTitle?: string;
|
|
348
|
+
pageDescription?: string;
|
|
349
|
+
pageKeywords?: string;
|
|
350
|
+
}
|
|
162
351
|
/**
|
|
163
352
|
* A visibility rule definition that controls when a page variation or component
|
|
164
353
|
* is shown. All conditions within a rule use AND logic — every specified
|
|
@@ -185,12 +374,6 @@ interface VisibilityRuleDef {
|
|
|
185
374
|
* is typically resolved lazily — only fetched when a rule actually needs it.
|
|
186
375
|
*/
|
|
187
376
|
type QualifierContext = ShopperExperience.schemas['QualifierResolveResponse'];
|
|
188
|
-
/**
|
|
189
|
-
* A resolved data binding object containing the fields returned by the data
|
|
190
|
-
* provider for a specific record. For example, a resolved `content_asset`
|
|
191
|
-
* might contain `{ title: "Winter Sale", body: "<div>…</div>" }`.
|
|
192
|
-
*/
|
|
193
|
-
type ResolvedDataBinding = ShopperExperience.schemas['ResolvedDataBinding'];
|
|
194
377
|
/**
|
|
195
378
|
* The type of identifier used to look up a page. Determines how the ID is
|
|
196
379
|
* resolved to a page manifest:
|
|
@@ -231,6 +414,24 @@ interface PageProcessorContext {
|
|
|
231
414
|
};
|
|
232
415
|
/** The locale to use when resolving locale-specific component content (e.g. `"en_US"`). */
|
|
233
416
|
locale: string;
|
|
417
|
+
/** The site's default locale, used as a fallback when the current locale has no content entry (e.g. `"en_US"`). */
|
|
418
|
+
defaultLocale: string;
|
|
419
|
+
/**
|
|
420
|
+
* Per-request resolution surface used by {@link resolveAttributeValues} to
|
|
421
|
+
* convert manifest envelopes into the wire shape SCAPI `getPage` would have
|
|
422
|
+
* returned. The storefront-next middleware builds it once per request and
|
|
423
|
+
* Page Designer preview supplies an editor-mode equivalent.
|
|
424
|
+
*/
|
|
425
|
+
attrCtx: AttributeResolutionContext;
|
|
426
|
+
/**
|
|
427
|
+
* Per-component-type attribute definitions hoisted by the manifest builder.
|
|
428
|
+
* Keyed by `typeId`. Optional — when omitted, the resolver falls back to
|
|
429
|
+
* structural detection for the image envelope and passes everything else
|
|
430
|
+
* through.
|
|
431
|
+
*/
|
|
432
|
+
componentTypes?: Record<string, {
|
|
433
|
+
attributeDefinitions: Record<string, AttributeDefinition>;
|
|
434
|
+
}>;
|
|
234
435
|
/**
|
|
235
436
|
* When `true` (default), invisible components are removed from the tree and
|
|
236
437
|
* regions are truncated to their `maxComponents` limit. When `false`, invisible
|
|
@@ -239,57 +440,6 @@ interface PageProcessorContext {
|
|
|
239
440
|
*/
|
|
240
441
|
pruneInvisible?: boolean;
|
|
241
442
|
}
|
|
242
|
-
/**
|
|
243
|
-
* Filters a page's components based on their visibility rules and resolves
|
|
244
|
-
* data binding expressions in a single traversal. Traverses the page tree
|
|
245
|
-
* using the visitor pattern and:
|
|
246
|
-
*
|
|
247
|
-
* 1. Removes any component whose visibility rules do not pass against the
|
|
248
|
-
* shopper's qualifier context.
|
|
249
|
-
* 2. Resolves data binding expressions in each surviving component's `data`
|
|
250
|
-
* attributes using the resolved data bindings from context resolution.
|
|
251
|
-
*
|
|
252
|
-
* A component is visible if **any** of its visibility rules pass (OR logic).
|
|
253
|
-
* If a component has rules and none of them pass, it is removed. Components
|
|
254
|
-
* without rules are always included.
|
|
255
|
-
*
|
|
256
|
-
* @param page - The page to process.
|
|
257
|
-
* @param context - The processing context with qualifier data, visibility rules, and resolved data bindings.
|
|
258
|
-
* @returns A new page with invisible components filtered out and data binding expressions resolved.
|
|
259
|
-
*
|
|
260
|
-
* @example
|
|
261
|
-
* ```ts
|
|
262
|
-
* import { processPage } from '@salesforce/storefront-next-runtime/design/data';
|
|
263
|
-
*
|
|
264
|
-
* const page = {
|
|
265
|
-
* id: 'homepage',
|
|
266
|
-
* typeId: 'storePage',
|
|
267
|
-
* regions: [{
|
|
268
|
-
* id: 'main',
|
|
269
|
-
* components: [
|
|
270
|
-
* { id: 'public-banner', typeId: 'commerce_assets.heroBanner', regions: [] },
|
|
271
|
-
* { id: 'loyalty-offer', typeId: 'commerce_assets.promoTile', regions: [] },
|
|
272
|
-
* ],
|
|
273
|
-
* }],
|
|
274
|
-
* };
|
|
275
|
-
*
|
|
276
|
-
* // The "loyalty-offer" component requires the shopper to be in "loyalty-members"
|
|
277
|
-
* const componentInfo = {
|
|
278
|
-
* 'public-banner': { visibilityRules: [] },
|
|
279
|
-
* 'loyalty-offer': {
|
|
280
|
-
* visibilityRules: [{ customerGroups: ['loyalty-members'] }],
|
|
281
|
-
* },
|
|
282
|
-
* };
|
|
283
|
-
*
|
|
284
|
-
* // Guest shopper — not in any customer group
|
|
285
|
-
* const filtered = processPage(page, {
|
|
286
|
-
* qualifiers: { customerGroups: {}, campaignQualifiers: {} },
|
|
287
|
-
* componentInfo,
|
|
288
|
-
* });
|
|
289
|
-
* // filtered.regions[0].components has only "public-banner"
|
|
290
|
-
* // "loyalty-offer" was removed because the shopper isn't a loyalty member
|
|
291
|
-
* ```
|
|
292
|
-
*/
|
|
293
443
|
declare function processPage(page: ShopperExperience.schemas['Page'], processorContext: PageProcessorContext): ShopperExperience.schemas['Page'];
|
|
294
444
|
//#endregion
|
|
295
445
|
//#region src/design/data/page/transform.d.ts
|
|
@@ -576,88 +726,6 @@ declare class RequiredError extends Error {
|
|
|
576
726
|
static assert<TValue>(value: TValue, message: string, isEmpty?: (value: TValue) => boolean): asserts value is NonNullable<TValue>;
|
|
577
727
|
}
|
|
578
728
|
//#endregion
|
|
579
|
-
//#region src/design/data/page/resolve-data-bindings.d.ts
|
|
580
|
-
/**
|
|
581
|
-
* Parses a binding expression string into its provider type and field name.
|
|
582
|
-
* Supports the bare `type.field` format.
|
|
583
|
-
*
|
|
584
|
-
* @param expression - The expression string to parse.
|
|
585
|
-
* @returns The parsed type and field, or `null` if the expression is invalid.
|
|
586
|
-
*
|
|
587
|
-
* @example
|
|
588
|
-
* ```ts
|
|
589
|
-
* parseExpression('content_asset.title'); // { type: 'content_asset', field: 'title' }
|
|
590
|
-
* parseExpression('invalid'); // null
|
|
591
|
-
* ```
|
|
592
|
-
*/
|
|
593
|
-
declare function parseExpression(expression: string): {
|
|
594
|
-
type: string;
|
|
595
|
-
field: string;
|
|
596
|
-
} | null;
|
|
597
|
-
/**
|
|
598
|
-
* Resolves a single binding expression against the component's data contexts
|
|
599
|
-
* and the resolved data bindings from context resolution.
|
|
600
|
-
*
|
|
601
|
-
* Returns the resolved field value, or an empty string if the expression is
|
|
602
|
-
* invalid, the matching context or record is not found, or the field does not
|
|
603
|
-
* exist on the resolved record.
|
|
604
|
-
*
|
|
605
|
-
* @param expression - The expression string (e.g. `"content_asset.body"`).
|
|
606
|
-
* @param contexts - The component's data binding contexts.
|
|
607
|
-
* @param dataBindings - The resolved data bindings from {@link QualifierContext}.
|
|
608
|
-
* @returns The resolved value, or `''` if resolution fails.
|
|
609
|
-
*/
|
|
610
|
-
declare function resolveExpression(expression: string, contexts: DataBindingRequirement[], dataBindings: NonNullable<QualifierContext['dataBindings']>): unknown;
|
|
611
|
-
/**
|
|
612
|
-
* Resolves data binding expressions for a single component. Replaces attribute
|
|
613
|
-
* values in the component's `data` with the resolved values from context
|
|
614
|
-
* resolution. Attributes without a matching expression are preserved as-is.
|
|
615
|
-
* When an expression cannot be resolved, the attribute value is set to an
|
|
616
|
-
* empty string.
|
|
617
|
-
*
|
|
618
|
-
* Returns the component unchanged if it has no data binding metadata or if
|
|
619
|
-
* `dataBindings` is `undefined`.
|
|
620
|
-
*
|
|
621
|
-
* @param component - The component to resolve data bindings for.
|
|
622
|
-
* @param binding - The component's data binding metadata from the page manifest's `componentInfo`, or `null`/`undefined` if not bound.
|
|
623
|
-
* @param dataBindings - The resolved data bindings from {@link QualifierContext}, or `undefined` if no bindings were resolved.
|
|
624
|
-
* @returns The component with resolved attribute values, or the original component if no bindings apply.
|
|
625
|
-
*
|
|
626
|
-
* @example
|
|
627
|
-
* ```ts
|
|
628
|
-
* import { resolveComponentDataBindings } from '@salesforce/storefront-next-runtime/design/data';
|
|
629
|
-
*
|
|
630
|
-
* const component = {
|
|
631
|
-
* id: 'banner',
|
|
632
|
-
* typeId: 'commerce_assets.contentBanner',
|
|
633
|
-
* data: { heading: 'Fallback Title', body: 'Fallback Body' },
|
|
634
|
-
* regions: [],
|
|
635
|
-
* };
|
|
636
|
-
*
|
|
637
|
-
* const binding = {
|
|
638
|
-
* expressions: {
|
|
639
|
-
* heading: 'content_asset.title',
|
|
640
|
-
* body: 'content_asset.body',
|
|
641
|
-
* },
|
|
642
|
-
* contexts: [{ type: 'content_asset', id: 'winter-sale-uuid' }],
|
|
643
|
-
* };
|
|
644
|
-
*
|
|
645
|
-
* const dataBindings = {
|
|
646
|
-
* content_asset: {
|
|
647
|
-
* 'winter-sale-uuid': {
|
|
648
|
-
* title: 'Winter Sale',
|
|
649
|
-
* body: '<div>Free Shipping on all orders!</div>',
|
|
650
|
-
* },
|
|
651
|
-
* },
|
|
652
|
-
* };
|
|
653
|
-
*
|
|
654
|
-
* const resolved = resolveComponentDataBindings(component, binding, dataBindings);
|
|
655
|
-
* // resolved.data.heading === 'Winter Sale'
|
|
656
|
-
* // resolved.data.body === '<div>Free Shipping on all orders!</div>'
|
|
657
|
-
* ```
|
|
658
|
-
*/
|
|
659
|
-
declare function resolveComponentDataBindings(component: ShopperExperience.schemas['Component'], binding: ComponentDataBinding | null | undefined, dataBindings: QualifierContext['dataBindings']): ShopperExperience.schemas['Component'];
|
|
660
|
-
//#endregion
|
|
661
729
|
//#region src/design/data/page/resolve-page.d.ts
|
|
662
730
|
/**
|
|
663
731
|
* Main entry point for the page resolution pipeline. Orchestrates the full flow:
|
|
@@ -679,6 +747,7 @@ declare function resolveComponentDataBindings(component: ShopperExperience.schem
|
|
|
679
747
|
* @param options.manifestStorage - Storage implementation for fetching manifests.
|
|
680
748
|
* @param options.contextResolver - Optional async function that returns the shopper's qualifier context. Only called if a visibility rule needs it.
|
|
681
749
|
* @param options.aspectType - The aspect type to resolve the page for when the identifier type is `'product'` or `'category'`.
|
|
750
|
+
* @param options.categoryId - Optional fallback category ID (or a Promise resolving to one) used only when `identifierType` is `'product'` and the product has no content assignment for the requested aspect type. The promise is awaited lazily — the happy path never pays for it.
|
|
682
751
|
* @param options.pruneInvisible - When `true` (default), invisible and overflow components are removed. When `false`, they are kept but marked `visible: false` for design/preview mode.
|
|
683
752
|
* @returns The fully resolved and filtered page, or `null`.
|
|
684
753
|
*
|
|
@@ -720,226 +789,39 @@ declare function resolvePage({
|
|
|
720
789
|
id,
|
|
721
790
|
identifierType,
|
|
722
791
|
aspectType,
|
|
792
|
+
categoryId,
|
|
723
793
|
locale,
|
|
794
|
+
defaultLocale,
|
|
724
795
|
manifestStorage,
|
|
725
796
|
contextResolver,
|
|
797
|
+
attrCtx,
|
|
726
798
|
pruneInvisible
|
|
727
799
|
}: {
|
|
728
800
|
id: string;
|
|
729
801
|
identifierType: IdentifierType;
|
|
730
802
|
aspectType?: string;
|
|
803
|
+
/**
|
|
804
|
+
* Fallback category ID (or a Promise resolving to one) consulted only
|
|
805
|
+
* when `identifierType === 'product'` and the product has no content
|
|
806
|
+
* assignment for the requested aspect type. Awaited lazily — the happy
|
|
807
|
+
* path skips it.
|
|
808
|
+
*/
|
|
809
|
+
categoryId?: string | Promise<string | null | undefined> | null;
|
|
731
810
|
locale: string;
|
|
811
|
+
defaultLocale: string;
|
|
732
812
|
manifestStorage: ManifestStorage;
|
|
733
813
|
contextResolver?: ContextResolver;
|
|
814
|
+
/**
|
|
815
|
+
* Per-request resolution surface for attribute envelope rewriting. Built
|
|
816
|
+
* once per request by the storefront-next middleware (or Page Designer
|
|
817
|
+
* preview). The `componentTypes` map travels on the
|
|
818
|
+
* {@link PageManifest} itself and is read off the manifest below before
|
|
819
|
+
* being threaded into {@link processPage}.
|
|
820
|
+
*/
|
|
821
|
+
attrCtx: AttributeResolutionContext;
|
|
734
822
|
pruneInvisible?: boolean;
|
|
735
823
|
}): Promise<ShopperExperience.schemas['Page'] | null>;
|
|
736
824
|
//#endregion
|
|
737
|
-
//#region src/design/data/manifest/resolve-dynamic-page-id.d.ts
|
|
738
|
-
/**
|
|
739
|
-
* Converts a product or category identifier into a page ID by looking up
|
|
740
|
-
* content assignments in the site manifest. For categories, the lookup
|
|
741
|
-
* traverses the category hierarchy from the given category up to the root,
|
|
742
|
-
* returning the first matching assignment.
|
|
743
|
-
*
|
|
744
|
-
* Returns `null` if no content assignment is found for the identifier or if
|
|
745
|
-
* the identifier type has no registered resolver.
|
|
746
|
-
*
|
|
747
|
-
* @param options - The resolution options.
|
|
748
|
-
* @param options.id - The identifier to resolve (product ID, category ID, or page ID).
|
|
749
|
-
* @param options.identifierType - The type of identifier: `'product'`, `'category'`, or `'page'`.
|
|
750
|
-
* @param options.siteManifest - The site manifest containing content assignments and category hierarchy.
|
|
751
|
-
* @returns The resolved page ID, or `null` if no assignment was found.
|
|
752
|
-
*
|
|
753
|
-
* @example
|
|
754
|
-
* ```ts
|
|
755
|
-
* import { resolveDynamicPageId } from '@salesforce/storefront-next-runtime/design/data';
|
|
756
|
-
*
|
|
757
|
-
* const siteManifest = {
|
|
758
|
-
* contentObjectAssignments: {
|
|
759
|
-
* plp: {
|
|
760
|
-
* category: {
|
|
761
|
-
* 'mens-shoes': {
|
|
762
|
-
* lookupMode: 'category-explicit',
|
|
763
|
-
* contentId: 'page-mens-shoes-plp',
|
|
764
|
-
* },
|
|
765
|
-
* },
|
|
766
|
-
* },
|
|
767
|
-
* },
|
|
768
|
-
* categories: {
|
|
769
|
-
* 'mens-running-shoes': { name: 'Running Shoes', parentCategory: 'mens-shoes' },
|
|
770
|
-
* 'mens-shoes': { name: "Men's Shoes" },
|
|
771
|
-
* },
|
|
772
|
-
* };
|
|
773
|
-
*
|
|
774
|
-
* // Direct match
|
|
775
|
-
* resolveDynamicPageId({ id: 'mens-shoes', identifierType: 'category', siteManifest });
|
|
776
|
-
* // => 'page-mens-shoes-plp'
|
|
777
|
-
*
|
|
778
|
-
* // Inherited from parent category
|
|
779
|
-
* resolveDynamicPageId({ id: 'mens-running-shoes', identifierType: 'category', siteManifest });
|
|
780
|
-
* // => 'page-mens-shoes-plp' (found via parent traversal)
|
|
781
|
-
*
|
|
782
|
-
* // No assignment found
|
|
783
|
-
* resolveDynamicPageId({ id: 'womens-shoes', identifierType: 'category', siteManifest });
|
|
784
|
-
* // => null
|
|
785
|
-
* ```
|
|
786
|
-
*/
|
|
787
|
-
declare function resolveDynamicPageId<TIdentifier extends IdentifierType = IdentifierType>({
|
|
788
|
-
id,
|
|
789
|
-
identifierType,
|
|
790
|
-
siteManifest,
|
|
791
|
-
aspectType
|
|
792
|
-
}: {
|
|
793
|
-
id: string;
|
|
794
|
-
identifierType: TIdentifier;
|
|
795
|
-
aspectType: string;
|
|
796
|
-
siteManifest?: SiteManifest | null;
|
|
797
|
-
}): string | null;
|
|
798
|
-
//#endregion
|
|
799
|
-
//#region src/design/data/manifest/get-page.d.ts
|
|
800
|
-
/**
|
|
801
|
-
* Selects the appropriate page variation from a manifest by evaluating each
|
|
802
|
-
* variation's visibility rule in order. Returns the first variation whose rule
|
|
803
|
-
* passes, or falls back to the manifest's default variation.
|
|
804
|
-
*
|
|
805
|
-
* The qualifier context is resolved lazily — the `contextResolver` is only
|
|
806
|
-
* called when a variation's `ruleRequiresContext` flag is `true`, and only
|
|
807
|
-
* once (the result is cached for subsequent variations).
|
|
808
|
-
*
|
|
809
|
-
* @param manifest - The page manifest containing all variations.
|
|
810
|
-
* @param options - Resolution options.
|
|
811
|
-
* @param options.contextResolver - Optional async function that returns the shopper's qualifier context. Only called if a variation's rule needs it.
|
|
812
|
-
* @param options.locale - The current locale (e.g. `"en_US"`). Used to evaluate locale-based visibility rules.
|
|
813
|
-
* @returns The selected variation entry and resolved context, or `null` if no variation (including default) exists.
|
|
814
|
-
*
|
|
815
|
-
* @example
|
|
816
|
-
* ```ts
|
|
817
|
-
* import { getPageFromManifest } from '@salesforce/storefront-next-runtime/design/data';
|
|
818
|
-
*
|
|
819
|
-
* const manifest = {
|
|
820
|
-
* pageId: 'homepage',
|
|
821
|
-
* context: { campaignQualifiers: [], customerGroups: ['vip-customers'], dataBindings: [] },
|
|
822
|
-
* variationOrder: ['vip-homepage', 'holiday-homepage'],
|
|
823
|
-
* variations: {
|
|
824
|
-
* 'vip-homepage': {
|
|
825
|
-
* ruleRequiresContext: true,
|
|
826
|
-
* pageRequiresContext: false,
|
|
827
|
-
* visibilityRule: { activeLocales: ['en-US'], customerGroups: ['vip-customers'] },
|
|
828
|
-
* page: { id: 'homepage', typeId: 'storePage', regions: [] },
|
|
829
|
-
* regions: {},
|
|
830
|
-
* },
|
|
831
|
-
* 'holiday-homepage': {
|
|
832
|
-
* ruleRequiresContext: false,
|
|
833
|
-
* pageRequiresContext: false,
|
|
834
|
-
* visibilityRule: {
|
|
835
|
-
* activeLocales: ['en-US'],
|
|
836
|
-
* schedule: {
|
|
837
|
-
* start: new Date('2026-12-01').toISOString(),
|
|
838
|
-
* end: new Date('2026-12-31').toISOString(),
|
|
839
|
-
* },
|
|
840
|
-
* },
|
|
841
|
-
* page: { id: 'homepage', typeId: 'storePage', regions: [] },
|
|
842
|
-
* regions: {},
|
|
843
|
-
* },
|
|
844
|
-
* 'default-homepage': {
|
|
845
|
-
* ruleRequiresContext: false,
|
|
846
|
-
* pageRequiresContext: false,
|
|
847
|
-
* page: { id: 'homepage', typeId: 'storePage', regions: [] },
|
|
848
|
-
* regions: {},
|
|
849
|
-
* },
|
|
850
|
-
* },
|
|
851
|
-
* defaultVariation: 'default-homepage',
|
|
852
|
-
* componentInfo: {},
|
|
853
|
-
* };
|
|
854
|
-
*
|
|
855
|
-
* // VIP shopper — matches first variation
|
|
856
|
-
* const result = await getPageFromManifest(manifest, {
|
|
857
|
-
* locale: 'en-US',
|
|
858
|
-
* contextResolver: async () => ({
|
|
859
|
-
* customerGroups: { 'vip-customers': true },
|
|
860
|
-
* campaignQualifiers: {},
|
|
861
|
-
* }),
|
|
862
|
-
* });
|
|
863
|
-
* // result.entry === manifest.variations['vip-homepage']
|
|
864
|
-
*
|
|
865
|
-
* // Non-VIP shopper outside holiday window — falls back to default
|
|
866
|
-
* const fallback = await getPageFromManifest(manifest, {
|
|
867
|
-
* locale: 'en-US',
|
|
868
|
-
* contextResolver: async () => ({
|
|
869
|
-
* customerGroups: {},
|
|
870
|
-
* campaignQualifiers: {},
|
|
871
|
-
* }),
|
|
872
|
-
* });
|
|
873
|
-
* // fallback.entry === manifest.variations['default-homepage']
|
|
874
|
-
* ```
|
|
875
|
-
*/
|
|
876
|
-
declare function getPageFromManifest(manifest: PageManifest, {
|
|
877
|
-
contextResolver,
|
|
878
|
-
locale
|
|
879
|
-
}: {
|
|
880
|
-
contextResolver?: ContextResolver;
|
|
881
|
-
locale: string;
|
|
882
|
-
}): Promise<{
|
|
883
|
-
entry: VariationEntry;
|
|
884
|
-
context: QualifierContext | null;
|
|
885
|
-
} | null>;
|
|
886
|
-
//#endregion
|
|
887
|
-
//#region src/design/data/manifest/content-assignment-resolvers.d.ts
|
|
888
|
-
/**
|
|
889
|
-
* The result of resolving an identifier through a content assignment resolver.
|
|
890
|
-
* Contains the object type, aspect type, and ordered list of keys to search
|
|
891
|
-
* in the site manifest's content assignments.
|
|
892
|
-
*/
|
|
893
|
-
interface ResolvedContentAssignmentLookup {
|
|
894
|
-
/** The type of commerce object (e.g. `'product'`, `'category'`). */
|
|
895
|
-
objectType: string;
|
|
896
|
-
/** Ordered list of object IDs to search in the site manifest's content assignments. */
|
|
897
|
-
keys: string[];
|
|
898
|
-
}
|
|
899
|
-
/**
|
|
900
|
-
* A function that converts an identifier key (e.g., a product or category ID)
|
|
901
|
-
* into a {@link ResolvedContentAssignmentLookup} describing where to search
|
|
902
|
-
* in the site manifest for the assigned page ID.
|
|
903
|
-
*/
|
|
904
|
-
type ContentAssignmentResolver = (key: string, manifest?: SiteManifest | null) => ResolvedContentAssignmentLookup;
|
|
905
|
-
/**
|
|
906
|
-
* Registry of content assignment resolvers keyed by {@link IdentifierType}.
|
|
907
|
-
* Each resolver knows how to convert its identifier type into a set of lookup
|
|
908
|
-
* keys for the site manifest.
|
|
909
|
-
*
|
|
910
|
-
* Built-in resolvers:
|
|
911
|
-
* - **`'product'`** — Maps a product ID to a single PDP lookup key.
|
|
912
|
-
* - **`'category'`** — Maps a category ID to an ordered list of keys that
|
|
913
|
-
* traverses the category hierarchy from child to root, enabling inherited
|
|
914
|
-
* page assignments.
|
|
915
|
-
*
|
|
916
|
-
* The `'page'` identifier type has no resolver — page IDs are used directly.
|
|
917
|
-
*
|
|
918
|
-
* @example
|
|
919
|
-
* ```ts
|
|
920
|
-
* import { ContentAssignmentResolvers } from '@salesforce/storefront-next-runtime/design/data';
|
|
921
|
-
*
|
|
922
|
-
* // Resolve a product identifier for PDP lookup
|
|
923
|
-
* const productResolver = ContentAssignmentResolvers.get('product');
|
|
924
|
-
* productResolver('nike-air-max-90');
|
|
925
|
-
* // => { objectType: 'product', aspectType: 'pdp', keys: ['nike-air-max-90'] }
|
|
926
|
-
*
|
|
927
|
-
* // Resolve a category identifier — traverses hierarchy to find inherited assignments
|
|
928
|
-
* const categoryResolver = ContentAssignmentResolvers.get('category');
|
|
929
|
-
* const siteManifest = {
|
|
930
|
-
* categories: {
|
|
931
|
-
* 'mens-running-shoes': { name: 'Running Shoes', parentCategory: 'mens-shoes' },
|
|
932
|
-
* 'mens-shoes': { name: "Men's Shoes", parentCategory: 'mens' },
|
|
933
|
-
* 'mens': { name: 'Men' },
|
|
934
|
-
* },
|
|
935
|
-
* contentObjectAssignments: {},
|
|
936
|
-
* };
|
|
937
|
-
* categoryResolver('mens-running-shoes', siteManifest);
|
|
938
|
-
* // => { objectType: 'category', aspectType: 'plp', keys: ['mens-running-shoes', 'mens-shoes', 'mens'] }
|
|
939
|
-
* ```
|
|
940
|
-
*/
|
|
941
|
-
declare const ContentAssignmentResolvers: Map<string, ContentAssignmentResolver>;
|
|
942
|
-
//#endregion
|
|
943
825
|
//#region src/design/data/validate-rule.d.ts
|
|
944
826
|
/**
|
|
945
827
|
* Evaluates a visibility rule against a shopper's qualifier context.
|
|
@@ -986,5 +868,5 @@ declare const ContentAssignmentResolvers: Map<string, ContentAssignmentResolver>
|
|
|
986
868
|
*/
|
|
987
869
|
declare function validateRule(rule: VisibilityRuleDef, locale: string, context?: QualifierContext | null): boolean;
|
|
988
870
|
//#endregion
|
|
989
|
-
export {
|
|
871
|
+
export { type AttributeResolutionContext, type AttributeResolutionWarning, type ContextResolver, type IdentifierType, type InferNodeFromType, type ManifestStorage, type PageManifest, type PageProcessorContext, type PageVisitor, type QualifierContext, RequiredError, type SiteManifest, type VisibilityRuleDef, type VisitorContext, type VisitorContextType, processPage, resolvePage, transformComponent, transformPage, transformRegion, validateRule };
|
|
990
872
|
//# sourceMappingURL=design-data.d.ts.map
|