@salesforce/storefront-next-runtime 0.4.2 → 1.0.0-alpha.0
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/config.d.ts +33 -221
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +34 -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/design-data.d.ts +266 -62
- package/dist/design-data.d.ts.map +1 -1
- package/dist/design-data.js +399 -14
- 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 +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/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/package.json +1 -19
- 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/README.md
CHANGED
|
@@ -55,9 +55,15 @@ Utilities and middleware for reading scoped entries from the MRT data access lay
|
|
|
55
55
|
- `AWS_REGION` (required): AWS region for the data store table (e.g., `us-east-1`)
|
|
56
56
|
- `MOBIFY_PROPERTY_ID` (required): MRT property identifier (e.g., `abcd1234`)
|
|
57
57
|
- `DEPLOY_TARGET` (required): MRT deploy target (e.g., `production`)
|
|
58
|
-
- `SFNEXT_DATA_STORE_UNAVAILABLE_MODE` (optional): controls middleware behavior when
|
|
59
|
-
|
|
60
|
-
- `fallback
|
|
58
|
+
- `SFNEXT_DATA_STORE_UNAVAILABLE_MODE` (optional): controls built-in middleware behavior when the
|
|
59
|
+
MRT data store is unavailable or returns a service error
|
|
60
|
+
- `fallback` (default): use middleware-defined safe fallback values and continue request execution
|
|
61
|
+
- `throw`: opt back into fail-fast behavior — middleware throws and the request errors out
|
|
62
|
+
|
|
63
|
+
Applies to the four built-in middlewares (`customSitePreferencesMiddleware`,
|
|
64
|
+
`customGlobalPreferencesMiddleware`, `gcpPreferencesMiddleware`, `loginPreferencesMiddleware`).
|
|
65
|
+
Customer-authored middlewares created via `createDataStoreMiddleware` default to `'throw'`; pass
|
|
66
|
+
`onUnavailable: 'fallback'` and a `fallbackValue` to opt into graceful degradation.
|
|
61
67
|
|
|
62
68
|
These are managed by Managed Runtime and are not typically set by SDK consumers directly.
|
|
63
69
|
|
package/dist/config.d.ts
CHANGED
|
@@ -1,61 +1,30 @@
|
|
|
1
1
|
import { n as Site, r as Url, t as Locale } from "./types.js";
|
|
2
2
|
import { n as DefineConfigOptions, r as defineConfig, t as BaseConfig } from "./schema.js";
|
|
3
|
-
import * as react0 from "react";
|
|
4
3
|
import { ReactNode } from "react";
|
|
5
|
-
import * as
|
|
6
|
-
import * as
|
|
7
|
-
import {
|
|
4
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
5
|
+
import * as react_router0 from "react-router";
|
|
6
|
+
import { RouterContextProvider } from "react-router";
|
|
8
7
|
|
|
9
|
-
//#region src/config/get-config.d.ts
|
|
10
|
-
|
|
11
|
-
declare global {
|
|
12
|
-
interface Window {
|
|
13
|
-
__APP_CONFIG__?: Record<string, unknown>;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Get configuration in loaders, actions, and utilities.
|
|
18
|
-
*
|
|
19
|
-
* Pass context parameter in server loaders/actions.
|
|
20
|
-
* Omit context parameter in client loaders (uses window.__APP_CONFIG__).
|
|
21
|
-
*
|
|
22
|
-
* @param context - Router context for server loaders/actions
|
|
23
|
-
* @returns App configuration
|
|
24
|
-
*/
|
|
25
|
-
declare function getConfig<T extends Record<string, unknown> = Record<string, unknown>>(context?: Readonly<RouterContextProvider>): T;
|
|
26
|
-
/**
|
|
27
|
-
* Get configuration in React components.
|
|
28
|
-
*
|
|
29
|
-
* Must use this hook (not getConfig) because React Context requires useContext().
|
|
30
|
-
*
|
|
31
|
-
* @returns App configuration
|
|
32
|
-
*/
|
|
33
|
-
declare function useConfig<T extends Record<string, unknown> = Record<string, unknown>>(): T;
|
|
34
|
-
//#endregion
|
|
35
8
|
//#region src/config/context.d.ts
|
|
9
|
+
|
|
36
10
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
|
|
42
|
-
declare const appConfigContext: react_router11.RouterContext<Record<string, unknown>>;
|
|
43
|
-
/**
|
|
44
|
-
* React context for application configuration.
|
|
45
|
-
*
|
|
46
|
-
* Used by the `useConfig()` hook in React components.
|
|
47
|
-
* Populated by `ConfigProvider` in the component tree.
|
|
11
|
+
* Augmentation hook for typing `getConfig()` / `useConfig()` /
|
|
12
|
+
* `appConfigContext`. Templates augment once via `declare module` so call
|
|
13
|
+
* sites don't need a per-call generic. Without augmentation, property
|
|
14
|
+
* accesses type to `unknown`. See README-CONFIG.md for the augmentation
|
|
15
|
+
* snippet and the multi-template caveat.
|
|
48
16
|
*/
|
|
49
|
-
|
|
17
|
+
interface AppConfigShape {
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
}
|
|
50
20
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* @returns The `app` section of the config
|
|
21
|
+
* Router context for application configuration. Populated by the template's
|
|
22
|
+
* app-config middleware; read via `context.get(appConfigContext)` in loaders,
|
|
23
|
+
* actions, and other middleware. Returns the augmented `AppConfigShape`.
|
|
55
24
|
*/
|
|
56
|
-
declare
|
|
25
|
+
declare const appConfigContext: react_router0.RouterContext<AppConfigShape>;
|
|
57
26
|
interface ConfigProviderProps {
|
|
58
|
-
config:
|
|
27
|
+
config: AppConfigShape;
|
|
59
28
|
children: ReactNode;
|
|
60
29
|
}
|
|
61
30
|
/**
|
|
@@ -67,183 +36,26 @@ interface ConfigProviderProps {
|
|
|
67
36
|
declare function ConfigProvider({
|
|
68
37
|
config,
|
|
69
38
|
children
|
|
70
|
-
}: ConfigProviderProps):
|
|
71
|
-
//#endregion
|
|
72
|
-
//#region src/config/middleware.d.ts
|
|
73
|
-
/**
|
|
74
|
-
* Create app config middleware for both server and client.
|
|
75
|
-
*
|
|
76
|
-
* Follows the same factory pattern as `createSiteContextMiddleware`.
|
|
77
|
-
*
|
|
78
|
-
* The server middleware:
|
|
79
|
-
* - Validates required Commerce API fields on first request (one-time)
|
|
80
|
-
* - Sets `appConfigContext` in router context with `config.app`
|
|
81
|
-
*
|
|
82
|
-
* The client middleware:
|
|
83
|
-
* - Reads `window.__APP_CONFIG__` (injected during SSR)
|
|
84
|
-
* - Sets `appConfigContext` in router context
|
|
85
|
-
*
|
|
86
|
-
* Environment variables:
|
|
87
|
-
* - `SCAPI_PROXY_HOST` (optional): When set, skips `shortCode` validation
|
|
88
|
-
* (workspace environments route through a proxy that doesn't require shortCode)
|
|
89
|
-
* - `NODE_ENV` (optional): When set to 'test', skips validation entirely
|
|
90
|
-
*
|
|
91
|
-
* @param config - The full config object (output of `defineConfig()`)
|
|
92
|
-
* @returns Object with `server` and `client` middleware functions
|
|
93
|
-
*
|
|
94
|
-
* @example
|
|
95
|
-
* import { createAppConfigMiddleware } from '@salesforce/storefront-next-runtime/config';
|
|
96
|
-
* import config from '@/config/server';
|
|
97
|
-
*
|
|
98
|
-
* const appConfigMiddleware = createAppConfigMiddleware(config);
|
|
99
|
-
*
|
|
100
|
-
* export const middleware = [appConfigMiddleware.server, ...otherMiddleware];
|
|
101
|
-
* export const clientMiddleware = [appConfigMiddleware.client, ...otherClientMiddleware];
|
|
102
|
-
*/
|
|
103
|
-
declare function createAppConfigMiddleware<T extends BaseConfig>(config: T): {
|
|
104
|
-
server: MiddlewareFunction<Response>;
|
|
105
|
-
client: MiddlewareFunction<Record<string, unknown>>;
|
|
106
|
-
};
|
|
39
|
+
}: ConfigProviderProps): react_jsx_runtime0.JSX.Element;
|
|
107
40
|
//#endregion
|
|
108
|
-
//#region src/config/
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
* You may obtain a copy of the License at
|
|
115
|
-
*
|
|
116
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
117
|
-
*
|
|
118
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
119
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
120
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
121
|
-
* See the License for the specific language governing permissions and
|
|
122
|
-
* limitations under the License.
|
|
123
|
-
*/
|
|
124
|
-
/**
|
|
125
|
-
* Deep merge two objects, with source values overriding target values
|
|
126
|
-
* Arrays are replaced, not merged
|
|
127
|
-
*
|
|
128
|
-
* @param target - The base object
|
|
129
|
-
* @param source - The object with values to merge in
|
|
130
|
-
* @returns A new merged object
|
|
131
|
-
*
|
|
132
|
-
* @example
|
|
133
|
-
* deepMerge(
|
|
134
|
-
* { a: { b: 1, c: 2 } },
|
|
135
|
-
* { a: { b: 3, d: 4 } }
|
|
136
|
-
* )
|
|
137
|
-
* // Returns: { a: { b: 3, c: 2, d: 4 } }
|
|
138
|
-
*/
|
|
139
|
-
declare const deepMerge: <T extends Record<string, unknown>>(target: T, source: Record<string, unknown>) => T;
|
|
140
|
-
/**
|
|
141
|
-
* Convert a path string with double underscore separators to a nested object
|
|
142
|
-
* Normalizes keys to match baseConfig casing (case-insensitive lookup, preserves baseConfig case)
|
|
143
|
-
*
|
|
144
|
-
* @param path - The path string (e.g., 'app__pages__cart__quantityUpdateDebounce')
|
|
145
|
-
* @param value - The value to set at the path
|
|
146
|
-
* @param baseConfig - Optional base config for case normalization
|
|
147
|
-
* @returns A nested object
|
|
148
|
-
*
|
|
149
|
-
* @example
|
|
150
|
-
* pathToObject('app__pages__cart__maxQuantity', 999)
|
|
151
|
-
* // Returns: { app: { pages: { cart: { maxQuantity: 999 } } } }
|
|
152
|
-
*
|
|
153
|
-
* @example
|
|
154
|
-
* // With baseConfig normalization:
|
|
155
|
-
* pathToObject('APP__SITE__LOCALE', 'en-GB', { app: { site: { locale: 'en-GB' } } })
|
|
156
|
-
* // Returns: { app: { site: { locale: 'en-GB' } } } (normalized to baseConfig casing)
|
|
157
|
-
*/
|
|
158
|
-
declare const pathToObject: (path: string, value: unknown, baseConfig?: Record<string, unknown>) => Record<string, unknown>;
|
|
159
|
-
/**
|
|
160
|
-
* Parse environment variable value with optimistic JSON parsing
|
|
161
|
-
* Tries to parse as JSON first, falls back to string if invalid
|
|
162
|
-
* Supports multi-line formatted JSON by normalizing whitespace before parsing
|
|
163
|
-
*
|
|
164
|
-
* @param varValue - The environment variable value
|
|
165
|
-
* @param varName - Optional variable name for better error messages
|
|
166
|
-
* @returns The parsed value (JSON type if valid JSON, otherwise string)
|
|
167
|
-
*
|
|
168
|
-
* @example
|
|
169
|
-
* // Primitives
|
|
170
|
-
* parseEnvValue('42') // → 42 (number)
|
|
171
|
-
* parseEnvValue('true') // → true (boolean)
|
|
172
|
-
* parseEnvValue('hello') // → 'hello' (string)
|
|
173
|
-
*
|
|
174
|
-
* @example
|
|
175
|
-
* // Single-line JSON
|
|
176
|
-
* parseEnvValue('["Apple","Google"]') // → ['Apple', 'Google'] (array)
|
|
177
|
-
* parseEnvValue('{"key":"value"}') // → {key: 'value'} (object)
|
|
178
|
-
*
|
|
179
|
-
* @example
|
|
180
|
-
* // Multi-line formatted JSON (whitespace normalized automatically)
|
|
181
|
-
* parseEnvValue('[
|
|
182
|
-
* {"id": "en-GB"},
|
|
183
|
-
* {"id": "fr-FR"}
|
|
184
|
-
* ]') // → [{id: 'en-GB'}, {id: 'fr-FR'}] (array)
|
|
185
|
-
*/
|
|
186
|
-
declare const parseEnvValue: (varValue: string, varName?: string) => unknown;
|
|
187
|
-
/**
|
|
188
|
-
* Extract all valid paths from a config object (recursively traverses the object structure)
|
|
189
|
-
* Returns paths in lowercase with double underscore separators
|
|
190
|
-
*
|
|
191
|
-
* @param obj - The config object to extract paths from
|
|
192
|
-
* @param prefix - Current path prefix (used for recursion)
|
|
193
|
-
* @returns Array of valid config paths
|
|
194
|
-
*
|
|
195
|
-
* @example
|
|
196
|
-
* extractValidPaths({ app: { site: { locale: 'en-GB' } } })
|
|
197
|
-
* // Returns: ['app__site__locale']
|
|
198
|
-
*/
|
|
199
|
-
declare const extractValidPaths: (obj: unknown, prefix?: string) => string[];
|
|
41
|
+
//#region src/config/get-config.d.ts
|
|
42
|
+
declare global {
|
|
43
|
+
interface Window {
|
|
44
|
+
__APP_CONFIG__?: Record<string, unknown>;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
200
47
|
/**
|
|
201
|
-
*
|
|
48
|
+
* Get configuration in loaders, actions, and utilities. Pass `context` on the
|
|
49
|
+
* server; omit it on the client (reads `window.__APP_CONFIG__`). Returns the
|
|
50
|
+
* augmented `AppConfigShape` — pass an explicit generic only for narrower or
|
|
51
|
+
* unrelated shapes (rare).
|
|
202
52
|
*/
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Config paths that cannot be overridden by environment variables.
|
|
206
|
-
* Paths are matched case-insensitively with double underscore separators.
|
|
207
|
-
* Any env var targeting a protected path or a sub-path of it will throw an error.
|
|
208
|
-
*
|
|
209
|
-
* @example ['app__engagement'] — prevents PUBLIC__app__engagement__* from being set via env
|
|
210
|
-
*/
|
|
211
|
-
protectedPaths?: string[];
|
|
212
|
-
}
|
|
53
|
+
declare function getConfig<T extends Record<string, unknown> = AppConfigShape>(context?: Readonly<RouterContextProvider>): T;
|
|
213
54
|
/**
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
* Uses double underscore (__) to target nested config paths.
|
|
217
|
-
* All PUBLIC__ prefixed variables are exposed to the client (bundled into window.__APP_CONFIG__).
|
|
218
|
-
*
|
|
219
|
-
* Server-only secrets should NEVER use this — read them directly from process.env in server code.
|
|
220
|
-
*
|
|
221
|
-
* Environment variables:
|
|
222
|
-
* - `PUBLIC__<path>` (optional): Override any config path. e.g. `PUBLIC__app__commerce__api__clientId=abc123`
|
|
223
|
-
* - `NODE_ENV` (optional): When set to 'development', enables conflict warnings for overlapping paths
|
|
224
|
-
*
|
|
225
|
-
* @param env - Environment variables object (defaults to process.env)
|
|
226
|
-
* @param baseConfig - Optional base config for strict path validation and case normalization
|
|
227
|
-
* @param options - Optional configuration including protected paths
|
|
228
|
-
* @returns Object with overrides to merge into base config
|
|
229
|
-
*
|
|
230
|
-
* @example
|
|
231
|
-
* // Environment variables:
|
|
232
|
-
* // PUBLIC__app__commerce__api__clientId=abc123
|
|
233
|
-
* // PUBLIC__app__pages__cart__quantityUpdateDebounce=1000
|
|
234
|
-
* // PUBLIC__app__features__socialLogin__providers=["Apple","Google"]
|
|
235
|
-
*
|
|
236
|
-
* mergeEnvConfig()
|
|
237
|
-
* // Returns:
|
|
238
|
-
* // {
|
|
239
|
-
* // app: {
|
|
240
|
-
* // commerce: { api: { clientId: 'abc123' } },
|
|
241
|
-
* // pages: { cart: { quantityUpdateDebounce: 1000 } },
|
|
242
|
-
* // features: { socialLogin: { providers: ['Apple', 'Google'] } }
|
|
243
|
-
* // }
|
|
244
|
-
* // }
|
|
55
|
+
* Get configuration in React components (use this instead of `getConfig` —
|
|
56
|
+
* React Context requires `useContext`). Returns the augmented `AppConfigShape`.
|
|
245
57
|
*/
|
|
246
|
-
declare
|
|
58
|
+
declare function useConfig<T extends Record<string, unknown> = AppConfigShape>(): T;
|
|
247
59
|
//#endregion
|
|
248
|
-
export { type
|
|
60
|
+
export { type AppConfigShape, type BaseConfig, ConfigProvider, type DefineConfigOptions, type Locale, type Site, type Url, appConfigContext, defineConfig, getConfig, useConfig };
|
|
249
61
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","names":[],"sources":["../src/config/
|
|
1
|
+
{"version":3,"file":"config.d.ts","names":[],"sources":["../src/config/context.tsx","../src/config/get-config.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;AC4EA;;AAA8D,UDtC7C,cAAA,CCsC6C;EAAmB,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;;;;;;;cD5BpE,kBAAgB,aAAA,CAAA,cAAA;UAWnB,mBAAA;UACE;YACE;;;;;;;;iBASE,cAAA;;;GAAqC,sBAAmB,kBAAA,CAAA,GAAA,CAAA;;;;;ICtCzC,cAAA,CAAA,EAIN,MAJM,CAAA,MAAA,EAAA,OAAA,CAAA;EAAA;;;;AAc/B;;;;AACc,iBADE,SACF,CAAA,UADsB,MACtB,CAAA,MAAA,EAAA,OAAA,CAAA,GADgD,cAChD,CAAA,CAAA,OAAA,CAAA,EAAA,QAAA,CAAS,qBAAT,CAAA,CAAA,EACX,CADW;;;AA6Bd;;AAA8D,iBAA9C,SAA8C,CAAA,UAA1B,MAA0B,CAAA,MAAA,EAAA,OAAA,CAAA,GAAA,cAAA,CAAA,CAAA,CAAA,EAAmB,CAAnB"}
|
package/dist/config.js
CHANGED
|
@@ -182,18 +182,20 @@ const extractValidPaths = (obj, prefix = "") => {
|
|
|
182
182
|
* @returns Object with overrides to merge into base config
|
|
183
183
|
*
|
|
184
184
|
* @example
|
|
185
|
-
* // Environment variables:
|
|
186
|
-
* //
|
|
187
|
-
* //
|
|
188
|
-
* //
|
|
185
|
+
* // Environment variables (template-specific paths shown):
|
|
186
|
+
* // PUBLIC__app__some__nested__value=abc123
|
|
187
|
+
* // PUBLIC__app__some__numericKnob=1000
|
|
188
|
+
* // PUBLIC__app__some__listKnob=["A","B"]
|
|
189
189
|
*
|
|
190
190
|
* mergeEnvConfig()
|
|
191
191
|
* // Returns:
|
|
192
192
|
* // {
|
|
193
193
|
* // app: {
|
|
194
|
-
* //
|
|
195
|
-
* //
|
|
196
|
-
* //
|
|
194
|
+
* // some: {
|
|
195
|
+
* // nested: { value: 'abc123' },
|
|
196
|
+
* // numericKnob: 1000,
|
|
197
|
+
* // listKnob: ['A', 'B']
|
|
198
|
+
* // }
|
|
197
199
|
* // }
|
|
198
200
|
* // }
|
|
199
201
|
*/
|
|
@@ -214,7 +216,7 @@ const mergeEnvConfig = (env = typeof process !== "undefined" ? process.env : {},
|
|
|
214
216
|
const depth = path.split("__").length;
|
|
215
217
|
if (depth > MAX_DEPTH) throw new Error(`Environment variable "${varName}" exceeds maximum path depth of ${MAX_DEPTH}. Current depth: ${depth}. Consider consolidating with JSON values or reducing nesting levels.`);
|
|
216
218
|
const normalizedPath = path.toLowerCase();
|
|
217
|
-
if (protectedPaths.some((protectedPath) => normalizedPath === protectedPath || normalizedPath.startsWith(`${protectedPath}__`))) throw new Error(`Environment variable "${varName}" attempts to override protected config path "${path}".\n\
|
|
219
|
+
if (protectedPaths.some((protectedPath) => normalizedPath === protectedPath || normalizedPath.startsWith(`${protectedPath}__`))) throw new Error(`Environment variable "${varName}" attempts to override protected config path "${path}".\n\nProtected paths cannot be overridden via environment variables. Update config.server.ts directly, or remove the path from \`protectedPaths\` if env override is intended.`);
|
|
218
220
|
if (baseConfig && validPaths.length > 0) {
|
|
219
221
|
if (!validPaths.includes(normalizedPath)) {
|
|
220
222
|
console.warn(`[Config Warning] Ignoring environment variable "${varName}": Config path "${path}" does not exist in config.server.ts.`);
|
|
@@ -256,15 +258,18 @@ const mergeEnvConfig = (env = typeof process !== "undefined" ? process.env : {},
|
|
|
256
258
|
/**
|
|
257
259
|
* Define a type-safe storefront configuration with IDE autocomplete.
|
|
258
260
|
*
|
|
259
|
-
*
|
|
260
|
-
*
|
|
261
|
-
*
|
|
261
|
+
* Reads `process.env` at call time and merges any `PUBLIC__`-prefixed
|
|
262
|
+
* variables into the config (validated against the base config structure —
|
|
263
|
+
* env vars targeting paths that don't exist in the base config are ignored
|
|
264
|
+
* with a warning). This is a server-only side effect by design; calling
|
|
265
|
+
* `defineConfig` from a browser bundle silently no-ops because `PUBLIC__`
|
|
266
|
+
* vars are not present in the client environment.
|
|
262
267
|
*
|
|
263
268
|
* Environment variables:
|
|
264
269
|
* - `PUBLIC__<path>` (optional): Override any config path using double underscore separators.
|
|
265
|
-
* e.g. `
|
|
266
|
-
* -
|
|
267
|
-
*
|
|
270
|
+
* e.g. `PUBLIC__app__some__nested__value=abc123` maps to `config.app.some.nested.value`
|
|
271
|
+
* - JSON values are parsed optimistically: numbers, booleans, arrays, and objects all work.
|
|
272
|
+
* `PUBLIC__app__features__providers=["A","B"]` parses to an array.
|
|
268
273
|
*
|
|
269
274
|
* @param config - The base configuration object with all defaults
|
|
270
275
|
* @param options - Optional settings (e.g., protectedPaths to prevent env var overrides)
|
|
@@ -277,10 +282,9 @@ const mergeEnvConfig = (env = typeof process !== "undefined" ? process.env : {},
|
|
|
277
282
|
* export default defineConfig({
|
|
278
283
|
* metadata: { projectName: 'My Store', projectSlug: 'my-store' },
|
|
279
284
|
* app: {
|
|
280
|
-
*
|
|
281
|
-
* defaultSiteId: 'RefArch',
|
|
285
|
+
* // template-specific shape
|
|
282
286
|
* },
|
|
283
|
-
* }, { protectedPaths: ['
|
|
287
|
+
* }, { protectedPaths: ['app__analytics'] });
|
|
284
288
|
*/
|
|
285
289
|
function defineConfig(config, options) {
|
|
286
290
|
return deepMerge(config, mergeEnvConfig(process.env, config, { protectedPaths: options?.protectedPaths }));
|
|
@@ -289,29 +293,19 @@ function defineConfig(config, options) {
|
|
|
289
293
|
//#endregion
|
|
290
294
|
//#region src/config/context.tsx
|
|
291
295
|
/**
|
|
292
|
-
* Router context for application configuration.
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
* Accessible in loaders, actions, and middleware via `context.get(appConfigContext)`.
|
|
296
|
+
* Router context for application configuration. Populated by the template's
|
|
297
|
+
* app-config middleware; read via `context.get(appConfigContext)` in loaders,
|
|
298
|
+
* actions, and other middleware. Returns the augmented `AppConfigShape`.
|
|
296
299
|
*/
|
|
297
300
|
const appConfigContext = createContext$1();
|
|
298
301
|
/**
|
|
299
|
-
* React context
|
|
302
|
+
* Internal React context backing `useConfig()`.
|
|
300
303
|
*
|
|
301
|
-
*
|
|
302
|
-
*
|
|
304
|
+
* Not exported from the public barrel — components must read config via
|
|
305
|
+
* `useConfig()` so the React tree has a single source of truth.
|
|
303
306
|
*/
|
|
304
307
|
const ConfigContext = createContext(null);
|
|
305
308
|
/**
|
|
306
|
-
* Extract the `app` section from a full config object.
|
|
307
|
-
*
|
|
308
|
-
* @param staticConfig - The full config object (output of `defineConfig()`)
|
|
309
|
-
* @returns The `app` section of the config
|
|
310
|
-
*/
|
|
311
|
-
function createAppConfig(staticConfig) {
|
|
312
|
-
return staticConfig.app;
|
|
313
|
-
}
|
|
314
|
-
/**
|
|
315
309
|
* React context provider for application configuration.
|
|
316
310
|
*
|
|
317
311
|
* Wrap your component tree with this to enable `useConfig()` in child components.
|
|
@@ -327,13 +321,10 @@ function ConfigProvider({ config, children }) {
|
|
|
327
321
|
//#endregion
|
|
328
322
|
//#region src/config/get-config.ts
|
|
329
323
|
/**
|
|
330
|
-
* Get configuration in loaders, actions, and utilities.
|
|
331
|
-
*
|
|
332
|
-
*
|
|
333
|
-
*
|
|
334
|
-
*
|
|
335
|
-
* @param context - Router context for server loaders/actions
|
|
336
|
-
* @returns App configuration
|
|
324
|
+
* Get configuration in loaders, actions, and utilities. Pass `context` on the
|
|
325
|
+
* server; omit it on the client (reads `window.__APP_CONFIG__`). Returns the
|
|
326
|
+
* augmented `AppConfigShape` — pass an explicit generic only for narrower or
|
|
327
|
+
* unrelated shapes (rare).
|
|
337
328
|
*/
|
|
338
329
|
function getConfig(context) {
|
|
339
330
|
if (context) {
|
|
@@ -345,11 +336,8 @@ function getConfig(context) {
|
|
|
345
336
|
throw new Error("Configuration not available. This can happen if:\n1. Server: Pass context parameter: getConfig(context)\n2. Client: Ensure window.__APP_CONFIG__ was injected during SSR\n3. React component: Use useConfig() hook instead of getConfig()");
|
|
346
337
|
}
|
|
347
338
|
/**
|
|
348
|
-
* Get configuration in React components
|
|
349
|
-
*
|
|
350
|
-
* Must use this hook (not getConfig) because React Context requires useContext().
|
|
351
|
-
*
|
|
352
|
-
* @returns App configuration
|
|
339
|
+
* Get configuration in React components (use this instead of `getConfig` —
|
|
340
|
+
* React Context requires `useContext`). Returns the augmented `AppConfigShape`.
|
|
353
341
|
*/
|
|
354
342
|
function useConfig() {
|
|
355
343
|
const config = useContext(ConfigContext);
|
|
@@ -358,75 +346,5 @@ function useConfig() {
|
|
|
358
346
|
}
|
|
359
347
|
|
|
360
348
|
//#endregion
|
|
361
|
-
|
|
362
|
-
/**
|
|
363
|
-
* Create app config middleware for both server and client.
|
|
364
|
-
*
|
|
365
|
-
* Follows the same factory pattern as `createSiteContextMiddleware`.
|
|
366
|
-
*
|
|
367
|
-
* The server middleware:
|
|
368
|
-
* - Validates required Commerce API fields on first request (one-time)
|
|
369
|
-
* - Sets `appConfigContext` in router context with `config.app`
|
|
370
|
-
*
|
|
371
|
-
* The client middleware:
|
|
372
|
-
* - Reads `window.__APP_CONFIG__` (injected during SSR)
|
|
373
|
-
* - Sets `appConfigContext` in router context
|
|
374
|
-
*
|
|
375
|
-
* Environment variables:
|
|
376
|
-
* - `SCAPI_PROXY_HOST` (optional): When set, skips `shortCode` validation
|
|
377
|
-
* (workspace environments route through a proxy that doesn't require shortCode)
|
|
378
|
-
* - `NODE_ENV` (optional): When set to 'test', skips validation entirely
|
|
379
|
-
*
|
|
380
|
-
* @param config - The full config object (output of `defineConfig()`)
|
|
381
|
-
* @returns Object with `server` and `client` middleware functions
|
|
382
|
-
*
|
|
383
|
-
* @example
|
|
384
|
-
* import { createAppConfigMiddleware } from '@salesforce/storefront-next-runtime/config';
|
|
385
|
-
* import config from '@/config/server';
|
|
386
|
-
*
|
|
387
|
-
* const appConfigMiddleware = createAppConfigMiddleware(config);
|
|
388
|
-
*
|
|
389
|
-
* export const middleware = [appConfigMiddleware.server, ...otherMiddleware];
|
|
390
|
-
* export const clientMiddleware = [appConfigMiddleware.client, ...otherClientMiddleware];
|
|
391
|
-
*/
|
|
392
|
-
function createAppConfigMiddleware(config) {
|
|
393
|
-
let validationRun = false;
|
|
394
|
-
function validateConfig() {
|
|
395
|
-
if (validationRun || process.env.NODE_ENV === "test") return;
|
|
396
|
-
const api = config.app.commerce?.api;
|
|
397
|
-
const required = {
|
|
398
|
-
clientId: api?.clientId ?? "",
|
|
399
|
-
organizationId: api?.organizationId ?? ""
|
|
400
|
-
};
|
|
401
|
-
if (!process.env.SCAPI_PROXY_HOST) required.shortCode = api?.shortCode ?? "";
|
|
402
|
-
const missing = Object.entries(required).filter(([_, value]) => !value).map(([key]) => key);
|
|
403
|
-
if (missing.length > 0) {
|
|
404
|
-
const envVarMap = {
|
|
405
|
-
clientId: "PUBLIC__app__commerce__api__clientId",
|
|
406
|
-
organizationId: "PUBLIC__app__commerce__api__organizationId",
|
|
407
|
-
shortCode: "PUBLIC__app__commerce__api__shortCode"
|
|
408
|
-
};
|
|
409
|
-
throw new Error(`Missing required Commerce API configuration: ${missing.join(", ")}\n\nSet these environment variables in your MRT deployment or .env file:\n${missing.map((key) => ` ${envVarMap[key]}=your-value`).join("\n")}\n\nExample .env file:\nPUBLIC__app__commerce__api__clientId=your-client-id\nPUBLIC__app__commerce__api__organizationId=your-org-id\nPUBLIC__app__commerce__api__shortCode=your-short-code\n\nSee docs/README-CONFIG.md for complete configuration documentation.`);
|
|
410
|
-
}
|
|
411
|
-
validationRun = true;
|
|
412
|
-
}
|
|
413
|
-
const server = ({ context }, next) => {
|
|
414
|
-
validateConfig();
|
|
415
|
-
context.set(appConfigContext, config.app);
|
|
416
|
-
return next();
|
|
417
|
-
};
|
|
418
|
-
const client = async ({ context }, next) => {
|
|
419
|
-
const appConfig = typeof window !== "undefined" ? window.__APP_CONFIG__ : void 0;
|
|
420
|
-
if (!appConfig) throw new Error("window.__APP_CONFIG__ not available. Check that server loader is injecting config into HTML via Layout component.");
|
|
421
|
-
context.set(appConfigContext, appConfig);
|
|
422
|
-
return next();
|
|
423
|
-
};
|
|
424
|
-
return {
|
|
425
|
-
server,
|
|
426
|
-
client
|
|
427
|
-
};
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
//#endregion
|
|
431
|
-
export { ConfigContext, ConfigProvider, appConfigContext, createAppConfig, createAppConfigMiddleware, deepMerge, defineConfig, extractValidPaths, getConfig, mergeEnvConfig, parseEnvValue, pathToObject, useConfig };
|
|
349
|
+
export { ConfigProvider, appConfigContext, defineConfig, getConfig, useConfig };
|
|
432
350
|
//# sourceMappingURL=config.js.map
|