@salesforce/storefront-next-runtime 0.3.0-alpha.0 → 0.3.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/dist/apply-url-config.js +4 -4
- package/dist/apply-url-config.js.map +1 -1
- package/dist/config.d.ts +3 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +5 -2
- package/dist/config.js.map +1 -1
- package/dist/design-react-core.d.ts +2 -2
- package/dist/events.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/load-config.js +2 -1
- package/dist/load-config.js.map +1 -1
- package/dist/routing.d.ts +1 -1
- package/dist/routing.js +1 -1
- package/dist/routing.js.map +1 -1
- package/dist/scapi.d.ts.map +1 -1
- package/dist/{multi-site.d.ts → site-context.d.ts} +21 -21
- package/dist/site-context.d.ts.map +1 -0
- package/dist/{multi-site.js → site-context.js} +32 -32
- package/dist/site-context.js.map +1 -0
- package/package.json +4 -4
- package/dist/multi-site.d.ts.map +0 -1
- package/dist/multi-site.js.map +0 -1
package/dist/apply-url-config.js
CHANGED
|
@@ -31,7 +31,7 @@ function createPatternMatcher(patterns) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
//#endregion
|
|
34
|
-
//#region src/
|
|
34
|
+
//#region src/site-context/apply-url-config.ts
|
|
35
35
|
const DEFAULT_EXCLUDED_ROUTES = ["/resource/**", "/action/**"];
|
|
36
36
|
/**
|
|
37
37
|
* Separates routes into excluded (stay at root) and included (go under prefix).
|
|
@@ -61,11 +61,11 @@ function normalizeRoutePaths(routes) {
|
|
|
61
61
|
}));
|
|
62
62
|
}
|
|
63
63
|
/**
|
|
64
|
-
* Creates the `
|
|
64
|
+
* Creates the `site-context-wrapper` parent route entry with the given prefix.
|
|
65
65
|
*/
|
|
66
66
|
function createPrefixWrapper(prefix, children, wrapperFile) {
|
|
67
67
|
return {
|
|
68
|
-
id: "
|
|
68
|
+
id: "site-context-wrapper",
|
|
69
69
|
file: wrapperFile,
|
|
70
70
|
path: prefix.slice(1),
|
|
71
71
|
children
|
|
@@ -97,7 +97,7 @@ function cloneRootIndexRoutes(routes) {
|
|
|
97
97
|
return duplicates;
|
|
98
98
|
}
|
|
99
99
|
/**
|
|
100
|
-
* Applies
|
|
100
|
+
* Applies site context URL configuration to a set of route entries.
|
|
101
101
|
*
|
|
102
102
|
* Wraps non-excluded routes under a parent route with the configured URL prefix
|
|
103
103
|
* (e.g. `/:siteId/:localeId`), while keeping excluded routes (action/resource by default)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply-url-config.js","names":["prefixPatterns: string[]","excludedRoutes: RouteConfigEntry[]","includedRoutes: RouteConfigEntry[]","duplicates: RouteConfigEntry[]"],"sources":["../src/utils/index.ts","../src/
|
|
1
|
+
{"version":3,"file":"apply-url-config.js","names":["prefixPatterns: string[]","excludedRoutes: RouteConfigEntry[]","includedRoutes: RouteConfigEntry[]","duplicates: RouteConfigEntry[]"],"sources":["../src/utils/index.ts","../src/site-context/apply-url-config.ts"],"sourcesContent":["/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Creates a matcher function from an array of path patterns.\n * Supports `/**` suffix wildcards (e.g. '/resource/**', '/action/**').\n * Exact paths without wildcards are matched literally.\n */\nexport function createPatternMatcher(patterns: string[]): (path: string) => boolean {\n const exactMatches = new Set<string>();\n const prefixPatterns: string[] = [];\n\n for (const pattern of patterns) {\n if (pattern.endsWith('/**')) {\n prefixPatterns.push(pattern.slice(0, -3));\n } else {\n exactMatches.add(pattern);\n }\n }\n\n return (path: string) => {\n if (exactMatches.has(path)) return true;\n return prefixPatterns.some((prefix) => path === prefix || path.startsWith(`${prefix}/`));\n };\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport type { RouteConfigEntry } from '@react-router/dev/routes';\nimport { createPatternMatcher } from '../utils';\nimport type { Url } from '../config/types';\n\nconst DEFAULT_EXCLUDED_ROUTES = ['/resource/**', '/action/**'];\n\n/**\n * Separates routes into excluded (stay at root) and included (go under prefix).\n */\nexport function partitionRoutes(\n routes: RouteConfigEntry[],\n excludePatterns: string[]\n): { excludedRoutes: RouteConfigEntry[]; includedRoutes: RouteConfigEntry[] } {\n const isExcluded = createPatternMatcher(excludePatterns);\n const excludedRoutes: RouteConfigEntry[] = [];\n const includedRoutes: RouteConfigEntry[] = [];\n\n for (const route of routes) {\n // Normalize path for matching — ensure leading slash so patterns like '/resource/**' work\n // regardless of whether the route path comes with or without a leading slash.\n // E.g Some routes comes from React Router flatRoutes objects where the path has no leading splash\n const matchPath = route.path?.startsWith('/') ? route.path : `/${route.path}`;\n if (route.path && isExcluded(matchPath)) {\n excludedRoutes.push(route);\n } else {\n includedRoutes.push(route);\n }\n }\n\n return { excludedRoutes, includedRoutes };\n}\n\n/**\n * Normalizes route paths by stripping leading `/` so they're relative under a\n * parent route (React Router requirement).\n */\nexport function normalizeRoutePaths(routes: RouteConfigEntry[]): RouteConfigEntry[] {\n return routes.map((route) => ({\n ...route,\n // Check for leading splash because React Router route object can contain no leading splash for a child route\n // E.g Some routes comes from React Router flatRoutes objects where the path has no leading splash\n path: route.path?.startsWith('/') ? route.path.slice(1) : route.path,\n }));\n}\n\n/**\n * Creates the `site-context-wrapper` parent route entry with the given prefix.\n */\nexport function createPrefixWrapper(\n prefix: string,\n children: RouteConfigEntry[],\n wrapperFile: string\n): RouteConfigEntry {\n return {\n id: 'site-context-wrapper',\n file: wrapperFile,\n path: prefix.slice(1),\n children,\n };\n}\n\n/**\n * Finds the root index route (`/`) and duplicates it with its parent layout.\n * Looks at the top level for pathless layouts whose direct children include an index route.\n * e.g. _app (pathless) → _app._index (index: true)\n * Returns: _app--root-duplicate → _app._index--root-duplicate\n */\nexport function cloneRootIndexRoutes(routes: RouteConfigEntry[]): RouteConfigEntry[] {\n const duplicates: RouteConfigEntry[] = [];\n\n for (const route of routes) {\n if (route.index === true) {\n duplicates.push({\n ...route,\n id: `${route.id}--root-duplicate`,\n });\n } else if (!route.path && route.children) {\n const indexChild = route.children.find((child) => child.index === true);\n if (indexChild) {\n duplicates.push({\n ...route,\n id: `${route.id}--root-duplicate`,\n children: [{ ...indexChild, id: `${indexChild.id}--root-duplicate` }],\n });\n }\n }\n }\n\n return duplicates;\n}\n\n/**\n * Applies site context URL configuration to a set of route entries.\n *\n * Wraps non-excluded routes under a parent route with the configured URL prefix\n * (e.g. `/:siteId/:localeId`), while keeping excluded routes (action/resource by default)\n * at the root level. The homepage index route (and its parent layout) is always\n * duplicated at `/` so the root URL still serves content.\n *\n * @param options - Configuration for URL customisation.\n * @param options.routes - The flat route entries discovered from the filesystem.\n * @param options.urlConfig - URL customisation configuration (prefix, excludeRoutes).\n * @param options.wrapperFile - Path to the wrapper component file, relative to appDirectory.\n * @returns The transformed route entries with prefix wrapping applied.\n */\nexport function applyUrlConfig(options: {\n routes: RouteConfigEntry[];\n urlConfig?: Url;\n wrapperFile: string;\n}): RouteConfigEntry[] {\n const { routes, urlConfig, wrapperFile } = options;\n if (!urlConfig) return routes;\n if (!urlConfig.prefix?.startsWith('/')) {\n throw new Error(`urlConfig.prefix must start with a leading slash (\"/\"). Received: \"${urlConfig.prefix}\"`);\n }\n if (urlConfig.prefix === '/') return routes;\n\n const excludePatterns = urlConfig.excludeRoutes ?? DEFAULT_EXCLUDED_ROUTES;\n\n const { excludedRoutes, includedRoutes } = partitionRoutes(routes, excludePatterns);\n\n const wrappableRoutes = normalizeRoutePaths(includedRoutes);\n // the route that wraps the included routes under prefix\n const wrapperRoute = createPrefixWrapper(urlConfig.prefix, wrappableRoutes, wrapperFile);\n\n // duplicate the app root index to keep app homepage to server at '/'\n const rootDuplicates = cloneRootIndexRoutes(includedRoutes);\n\n return [...rootDuplicates, wrapperRoute, ...excludedRoutes];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,qBAAqB,UAA+C;CAChF,MAAM,+BAAe,IAAI,KAAa;CACtC,MAAMA,iBAA2B,EAAE;AAEnC,MAAK,MAAM,WAAW,SAClB,KAAI,QAAQ,SAAS,MAAM,CACvB,gBAAe,KAAK,QAAQ,MAAM,GAAG,GAAG,CAAC;KAEzC,cAAa,IAAI,QAAQ;AAIjC,SAAQ,SAAiB;AACrB,MAAI,aAAa,IAAI,KAAK,CAAE,QAAO;AACnC,SAAO,eAAe,MAAM,WAAW,SAAS,UAAU,KAAK,WAAW,GAAG,OAAO,GAAG,CAAC;;;;;;AChBhG,MAAM,0BAA0B,CAAC,gBAAgB,aAAa;;;;AAK9D,SAAgB,gBACZ,QACA,iBAC0E;CAC1E,MAAM,aAAa,qBAAqB,gBAAgB;CACxD,MAAMC,iBAAqC,EAAE;CAC7C,MAAMC,iBAAqC,EAAE;AAE7C,MAAK,MAAM,SAAS,QAAQ;EAIxB,MAAM,YAAY,MAAM,MAAM,WAAW,IAAI,GAAG,MAAM,OAAO,IAAI,MAAM;AACvE,MAAI,MAAM,QAAQ,WAAW,UAAU,CACnC,gBAAe,KAAK,MAAM;MAE1B,gBAAe,KAAK,MAAM;;AAIlC,QAAO;EAAE;EAAgB;EAAgB;;;;;;AAO7C,SAAgB,oBAAoB,QAAgD;AAChF,QAAO,OAAO,KAAK,WAAW;EAC1B,GAAG;EAGH,MAAM,MAAM,MAAM,WAAW,IAAI,GAAG,MAAM,KAAK,MAAM,EAAE,GAAG,MAAM;EACnE,EAAE;;;;;AAMP,SAAgB,oBACZ,QACA,UACA,aACgB;AAChB,QAAO;EACH,IAAI;EACJ,MAAM;EACN,MAAM,OAAO,MAAM,EAAE;EACrB;EACH;;;;;;;;AASL,SAAgB,qBAAqB,QAAgD;CACjF,MAAMC,aAAiC,EAAE;AAEzC,MAAK,MAAM,SAAS,OAChB,KAAI,MAAM,UAAU,KAChB,YAAW,KAAK;EACZ,GAAG;EACH,IAAI,GAAG,MAAM,GAAG;EACnB,CAAC;UACK,CAAC,MAAM,QAAQ,MAAM,UAAU;EACtC,MAAM,aAAa,MAAM,SAAS,MAAM,UAAU,MAAM,UAAU,KAAK;AACvE,MAAI,WACA,YAAW,KAAK;GACZ,GAAG;GACH,IAAI,GAAG,MAAM,GAAG;GAChB,UAAU,CAAC;IAAE,GAAG;IAAY,IAAI,GAAG,WAAW,GAAG;IAAmB,CAAC;GACxE,CAAC;;AAKd,QAAO;;;;;;;;;;;;;;;;AAiBX,SAAgB,eAAe,SAIR;CACnB,MAAM,EAAE,QAAQ,WAAW,gBAAgB;AAC3C,KAAI,CAAC,UAAW,QAAO;AACvB,KAAI,CAAC,UAAU,QAAQ,WAAW,IAAI,CAClC,OAAM,IAAI,MAAM,sEAAsE,UAAU,OAAO,GAAG;AAE9G,KAAI,UAAU,WAAW,IAAK,QAAO;CAIrC,MAAM,EAAE,gBAAgB,mBAAmB,gBAAgB,QAFnC,UAAU,iBAAiB,wBAEgC;CAEnF,MAAM,kBAAkB,oBAAoB,eAAe;CAE3D,MAAM,eAAe,oBAAoB,UAAU,QAAQ,iBAAiB,YAAY;AAKxF,QAAO;EAAC,GAFe,qBAAqB,eAAe;EAEhC;EAAc,GAAG;EAAe"}
|
package/dist/config.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ 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
3
|
import * as react0 from "react";
|
|
4
4
|
import { ReactNode } from "react";
|
|
5
|
-
import * as
|
|
5
|
+
import * as react_jsx_runtime2 from "react/jsx-runtime";
|
|
6
6
|
import * as react_router2 from "react-router";
|
|
7
7
|
import { MiddlewareFunction, RouterContextProvider } from "react-router";
|
|
8
8
|
|
|
@@ -67,13 +67,13 @@ interface ConfigProviderProps {
|
|
|
67
67
|
declare function ConfigProvider({
|
|
68
68
|
config,
|
|
69
69
|
children
|
|
70
|
-
}: ConfigProviderProps):
|
|
70
|
+
}: ConfigProviderProps): react_jsx_runtime2.JSX.Element;
|
|
71
71
|
//#endregion
|
|
72
72
|
//#region src/config/middleware.d.ts
|
|
73
73
|
/**
|
|
74
74
|
* Create app config middleware for both server and client.
|
|
75
75
|
*
|
|
76
|
-
* Follows the same factory pattern as `
|
|
76
|
+
* Follows the same factory pattern as `createSiteContextMiddleware`.
|
|
77
77
|
*
|
|
78
78
|
* The server middleware:
|
|
79
79
|
* - Validates required Commerce API fields on first request (one-time)
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","names":[],"sources":["../src/config/get-config.ts","../src/config/context.tsx","../src/config/middleware.ts","../src/config/utils.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;QA2C8D,MAAA,CAAA;EACvC,UAAA,MAAA,CAAA;IAAT,cAAA,CAAA,EAdW,MAcX,CAAA,MAAA,EAAA,OAAA,CAAA;EACX;;AA+BH;;;;;;;;AC1CA;AASa,iBDAG,SCAU,CAAA,UDAU,MCAV,CAAA,MAAA,EAAA,OAAA,CAAA,GDAoC,MCApC,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,CAAA,OAAA,CAAA,EDCZ,QCDY,CDCH,qBCDG,CAAA,CAAA,EDEvB,CCFuB;AAS1B;;;;;AAEC;AAaD;AAAiC,iBDSjB,SCTiB,CAAA,UDSG,MCTH,CAAA,MAAA,EAAA,OAAA,CAAA,GDS6B,MCT7B,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,CAAA,CAAA,EDSyD,CCTzD;;;;;;;;;AAjCpB,cAAA,gBAAgB,EAAA,aAAA,CAAA,aAAA,CAAA,MAAA,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA;AAS7B;AASA;;;;;AAIU,cAbG,aAagB,EAbH,MAAA,CAAA,OAeH,CAfG,MAeH,CAAA,MAAA,EAAA,OAAA,CAAA,GAAA,IAAA,CAAA;AASvB;;;;;;iBAfgB,0BAA0B,0BAA0B,IAAI;UAI9D,mBAAA;UACE;ECPI,QAAA,EDQF,SCRE;;;;;;;;iBDiBA,cAAA;;;GAAqC,sBAAmB,kBAAA,CAAA,GAAA,CAAA;;;;;;;ADSxE;;;;;;;;AC1CA;AASA;AASA;;;;;AAEC;AAaD;;;;;;;;;ACjBA;AAAoD,iBAApC,yBAAoC,CAAA,UAAA,UAAA,CAAA,CAAA,MAAA,EACxC,CADwC,CAAA,EAAA;EACxC,MAAA,EAEA,kBAFA,CAEmB,QAFnB,CAAA;EAEmB,MAAA,EACnB,kBADmB,CACA,MADA,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA;CAAnB;;;;;;;;;;;;AF5B8C;;;;;AAkB1D;;;;;;;AAiCA;;;;;;;;AC1CA;AASa,cELA,SFKmE,
|
|
1
|
+
{"version":3,"file":"config.d.ts","names":[],"sources":["../src/config/get-config.ts","../src/config/context.tsx","../src/config/middleware.ts","../src/config/utils.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;QA2C8D,MAAA,CAAA;EACvC,UAAA,MAAA,CAAA;IAAT,cAAA,CAAA,EAdW,MAcX,CAAA,MAAA,EAAA,OAAA,CAAA;EACX;;AA+BH;;;;;;;;AC1CA;AASa,iBDAG,SCAU,CAAA,UDAU,MCAV,CAAA,MAAA,EAAA,OAAA,CAAA,GDAoC,MCApC,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,CAAA,OAAA,CAAA,EDCZ,QCDY,CDCH,qBCDG,CAAA,CAAA,EDEvB,CCFuB;AAS1B;;;;;AAEC;AAaD;AAAiC,iBDSjB,SCTiB,CAAA,UDSG,MCTH,CAAA,MAAA,EAAA,OAAA,CAAA,GDS6B,MCT7B,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,CAAA,CAAA,EDSyD,CCTzD;;;;;;;;;AAjCpB,cAAA,gBAAgB,EAAA,aAAA,CAAA,aAAA,CAAA,MAAA,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA;AAS7B;AASA;;;;;AAIU,cAbG,aAagB,EAbH,MAAA,CAAA,OAeH,CAfG,MAeH,CAAA,MAAA,EAAA,OAAA,CAAA,GAAA,IAAA,CAAA;AASvB;;;;;;iBAfgB,0BAA0B,0BAA0B,IAAI;UAI9D,mBAAA;UACE;ECPI,QAAA,EDQF,SCRE;;;;;;;;iBDiBA,cAAA;;;GAAqC,sBAAmB,kBAAA,CAAA,GAAA,CAAA;;;;;;;ADSxE;;;;;;;;AC1CA;AASA;AASA;;;;;AAEC;AAaD;;;;;;;;;ACjBA;AAAoD,iBAApC,yBAAoC,CAAA,UAAA,UAAA,CAAA,CAAA,MAAA,EACxC,CADwC,CAAA,EAAA;EACxC,MAAA,EAEA,kBAFA,CAEmB,QAFnB,CAAA;EAEmB,MAAA,EACnB,kBADmB,CACA,MADA,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA;CAAnB;;;;;;;;;;;;AF5B8C;;;;;AAkB1D;;;;;;;AAiCA;;;;;;;;AC1CA;AASa,cELA,SFKmE,EAAA,CAAtD,UELU,MFKV,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA,CAAA,MAAA,EEL2C,CFK3C,EAAA,MAAA,EELsD,MFKtD,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,GELgF,CFKhF;AAS1B;;;;;AAEC;AAaD;;;;;;;;;ACjBA;;;AAG+B,cCoBlB,YDpBkB,EAAA,CAAA,IAAA,EAAA,MAAA,EAAA,KAAA,EAAA,OAAA,EAAA,UAAA,CAAA,ECuBd,MDvBc,CAAA,MAAA,EAAA,OAAA,CAAA,EAAA,GCwB5B,MDxB4B,CAAA,MAAA,EAAA,OAAA,CAAA;;;;;;;;ACf/B;;;;;;AAmCA;AAqEA;AAqCA;AAiCA;AA4CA;;;;;;;;;;cAlHa;;;;;;;;;;;;;cAqCA;;;;UAiCI,qBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA4CJ,uBACJ,iDACQ,mCACH,0BACX"}
|
package/dist/config.js
CHANGED
|
@@ -216,7 +216,10 @@ const mergeEnvConfig = (env = typeof process !== "undefined" ? process.env : {},
|
|
|
216
216
|
const normalizedPath = path.toLowerCase();
|
|
217
217
|
if (protectedPaths.some((protectedPath) => normalizedPath === protectedPath || normalizedPath.startsWith(`${protectedPath}__`))) throw new Error(`Environment variable "${varName}" attempts to override protected config path "${path}".\n\nThe engagement configuration cannot be overridden via environment variables. Update config.server.ts directly to change engagement settings.`);
|
|
218
218
|
if (baseConfig && validPaths.length > 0) {
|
|
219
|
-
if (!validPaths.includes(normalizedPath))
|
|
219
|
+
if (!validPaths.includes(normalizedPath)) {
|
|
220
|
+
console.warn(`[Config Warning] Ignoring environment variable "${varName}": Config path "${path}" does not exist in config.server.ts.`);
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
220
223
|
}
|
|
221
224
|
totalValueSize += varValue.length;
|
|
222
225
|
envVars.push({
|
|
@@ -359,7 +362,7 @@ function useConfig() {
|
|
|
359
362
|
/**
|
|
360
363
|
* Create app config middleware for both server and client.
|
|
361
364
|
*
|
|
362
|
-
* Follows the same factory pattern as `
|
|
365
|
+
* Follows the same factory pattern as `createSiteContextMiddleware`.
|
|
363
366
|
*
|
|
364
367
|
* The server middleware:
|
|
365
368
|
* - Validates required Commerce API fields on first request (one-time)
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","names":["result: Record<string, unknown>","configCurrent: unknown","paths: string[]","envVars: EnvVar[]","conflicts: Array<{ parent: string; child: string }>","merged: Record<string, unknown>","createRouterContext","required: Record<string, string>","envVarMap: Record<string, string>","server: MiddlewareFunction<Response>","client: MiddlewareFunction<Record<string, unknown>>"],"sources":["../src/config/utils.ts","../src/config/schema.ts","../src/config/context.tsx","../src/config/get-config.ts","../src/config/middleware.ts"],"sourcesContent":["/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Type guard to check if value is a plain object (not array, null, or other types)\n */\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n};\n\n/**\n * Deep merge two objects, with source values overriding target values\n * Arrays are replaced, not merged\n *\n * @param target - The base object\n * @param source - The object with values to merge in\n * @returns A new merged object\n *\n * @example\n * deepMerge(\n * { a: { b: 1, c: 2 } },\n * { a: { b: 3, d: 4 } }\n * )\n * // Returns: { a: { b: 3, c: 2, d: 4 } }\n */\nexport const deepMerge = <T extends Record<string, unknown>>(target: T, source: Record<string, unknown>): T => {\n const result: Record<string, unknown> = { ...target };\n\n for (const key in source) {\n const sourceValue = source[key];\n const targetValue = result[key];\n\n if (isPlainObject(sourceValue) && isPlainObject(targetValue)) {\n result[key] = deepMerge(targetValue, sourceValue);\n } else {\n result[key] = sourceValue;\n }\n }\n\n return result as T;\n};\n\n/**\n * Convert a path string with double underscore separators to a nested object\n * Normalizes keys to match baseConfig casing (case-insensitive lookup, preserves baseConfig case)\n *\n * @param path - The path string (e.g., 'app__pages__cart__quantityUpdateDebounce')\n * @param value - The value to set at the path\n * @param baseConfig - Optional base config for case normalization\n * @returns A nested object\n *\n * @example\n * pathToObject('app__pages__cart__maxQuantity', 999)\n * // Returns: { app: { pages: { cart: { maxQuantity: 999 } } } }\n *\n * @example\n * // With baseConfig normalization:\n * pathToObject('APP__SITE__LOCALE', 'en-GB', { app: { site: { locale: 'en-GB' } } })\n * // Returns: { app: { site: { locale: 'en-GB' } } } (normalized to baseConfig casing)\n */\nexport const pathToObject = (\n path: string,\n value: unknown,\n baseConfig?: Record<string, unknown>\n): Record<string, unknown> => {\n const keys = path.split('__');\n const result: Record<string, unknown> = {};\n\n let current = result;\n let configCurrent: unknown = baseConfig;\n\n for (let i = 0; i < keys.length - 1; i++) {\n const key = keys[i];\n\n let normalizedKey = key;\n if (configCurrent && typeof configCurrent === 'object' && !Array.isArray(configCurrent)) {\n const actualKey = Object.keys(configCurrent).find((k) => k.toLowerCase() === key.toLowerCase());\n if (actualKey) {\n normalizedKey = actualKey;\n configCurrent = (configCurrent as Record<string, unknown>)[actualKey];\n } else {\n configCurrent = null;\n }\n }\n\n current[normalizedKey] = {};\n current = current[normalizedKey] as Record<string, unknown>;\n }\n\n const lastKey = keys[keys.length - 1];\n let normalizedLastKey = lastKey;\n if (configCurrent && typeof configCurrent === 'object' && !Array.isArray(configCurrent)) {\n const actualKey = Object.keys(configCurrent).find((k) => k.toLowerCase() === lastKey.toLowerCase());\n if (actualKey) {\n normalizedLastKey = actualKey;\n }\n }\n\n current[normalizedLastKey] = value;\n return result;\n};\n\n/**\n * Parse environment variable value with optimistic JSON parsing\n * Tries to parse as JSON first, falls back to string if invalid\n * Supports multi-line formatted JSON by normalizing whitespace before parsing\n *\n * @param varValue - The environment variable value\n * @param varName - Optional variable name for better error messages\n * @returns The parsed value (JSON type if valid JSON, otherwise string)\n *\n * @example\n * // Primitives\n * parseEnvValue('42') // → 42 (number)\n * parseEnvValue('true') // → true (boolean)\n * parseEnvValue('hello') // → 'hello' (string)\n *\n * @example\n * // Single-line JSON\n * parseEnvValue('[\"Apple\",\"Google\"]') // → ['Apple', 'Google'] (array)\n * parseEnvValue('{\"key\":\"value\"}') // → {key: 'value'} (object)\n *\n * @example\n * // Multi-line formatted JSON (whitespace normalized automatically)\n * parseEnvValue('[\n * {\"id\": \"en-GB\"},\n * {\"id\": \"fr-FR\"}\n * ]') // → [{id: 'en-GB'}, {id: 'fr-FR'}] (array)\n */\nexport const parseEnvValue = (varValue: string, varName?: string): unknown => {\n try {\n return JSON.parse(varValue);\n } catch {\n const trimmed = varValue.trim();\n if (trimmed.startsWith('{') || trimmed.startsWith('[')) {\n try {\n const normalized = varValue.replace(/\\s+/g, ' ').trim();\n return JSON.parse(normalized);\n } catch {\n if (process.env.NODE_ENV === 'development') {\n const preview = varValue.length > 50 ? `${varValue.substring(0, 50)}...` : varValue;\n const varInfo = varName ? ` in \"${varName}\"` : '';\n // eslint-disable-next-line no-console\n console.warn(\n `[Config Warning] Value${varInfo} looks like JSON but failed to parse: \"${preview}\". ` +\n `Using as string instead. Check for syntax errors if this was meant to be JSON.`\n );\n }\n }\n }\n return varValue;\n }\n};\n\n/**\n * Extract all valid paths from a config object (recursively traverses the object structure)\n * Returns paths in lowercase with double underscore separators\n *\n * @param obj - The config object to extract paths from\n * @param prefix - Current path prefix (used for recursion)\n * @returns Array of valid config paths\n *\n * @example\n * extractValidPaths({ app: { site: { locale: 'en-GB' } } })\n * // Returns: ['app__site__locale']\n */\nexport const extractValidPaths = (obj: unknown, prefix = ''): string[] => {\n if (!isPlainObject(obj)) {\n return prefix ? [prefix] : [];\n }\n\n const paths: string[] = [];\n for (const [key, value] of Object.entries(obj)) {\n const normalizedKey = key.toLowerCase();\n const currentPath = prefix ? `${prefix}__${normalizedKey}` : normalizedKey;\n\n if (isPlainObject(value)) {\n paths.push(currentPath); // Allow setting whole object (e.g. PUBLIC__app__commerceAgent)\n // Recursively extract paths from nested objects\n paths.push(...extractValidPaths(value, currentPath));\n } else {\n // Leaf node - this is a valid config path\n paths.push(currentPath);\n }\n }\n\n return paths;\n};\n\ninterface EnvVar {\n name: string;\n path: string;\n value: string;\n depth: number;\n}\n\n/**\n * Options for mergeEnvConfig\n */\nexport interface MergeEnvConfigOptions {\n /**\n * Config paths that cannot be overridden by environment variables.\n * Paths are matched case-insensitively with double underscore separators.\n * Any env var targeting a protected path or a sub-path of it will throw an error.\n *\n * @example ['app__engagement'] — prevents PUBLIC__app__engagement__* from being set via env\n */\n protectedPaths?: string[];\n}\n\n/**\n * Merge environment variables with PUBLIC__ prefix into config.\n *\n * Uses double underscore (__) to target nested config paths.\n * All PUBLIC__ prefixed variables are exposed to the client (bundled into window.__APP_CONFIG__).\n *\n * Server-only secrets should NEVER use this — read them directly from process.env in server code.\n *\n * Environment variables:\n * - `PUBLIC__<path>` (optional): Override any config path. e.g. `PUBLIC__app__commerce__api__clientId=abc123`\n * - `NODE_ENV` (optional): When set to 'development', enables conflict warnings for overlapping paths\n *\n * @param env - Environment variables object (defaults to process.env)\n * @param baseConfig - Optional base config for strict path validation and case normalization\n * @param options - Optional configuration including protected paths\n * @returns Object with overrides to merge into base config\n *\n * @example\n * // Environment variables:\n * // PUBLIC__app__commerce__api__clientId=abc123\n * // PUBLIC__app__pages__cart__quantityUpdateDebounce=1000\n * // PUBLIC__app__features__socialLogin__providers=[\"Apple\",\"Google\"]\n *\n * mergeEnvConfig()\n * // Returns:\n * // {\n * // app: {\n * // commerce: { api: { clientId: 'abc123' } },\n * // pages: { cart: { quantityUpdateDebounce: 1000 } },\n * // features: { socialLogin: { providers: ['Apple', 'Google'] } }\n * // }\n * // }\n */\nexport const mergeEnvConfig = (\n env: Record<string, string | undefined> = typeof process !== 'undefined' ? process.env : {},\n baseConfig?: Record<string, unknown>,\n options?: MergeEnvConfigOptions\n): Record<string, unknown> => {\n const PUBLIC_PREFIX = 'PUBLIC__';\n const MAX_VAR_NAME_LENGTH = 512; // MRT limit: 512 characters\n const MAX_TOTAL_VALUE_SIZE = 32 * 1024; // MRT limit: 32 KB\n const MAX_DEPTH = 10;\n\n const protectedPaths = options?.protectedPaths ?? [];\n const validPaths = baseConfig ? extractValidPaths(baseConfig) : [];\n\n const envVars: EnvVar[] = [];\n let totalValueSize = 0;\n\n for (const [varName, varValue] of Object.entries(env)) {\n if (varValue === undefined || varValue === null || !varName.startsWith(PUBLIC_PREFIX)) continue;\n\n if (varName.length > MAX_VAR_NAME_LENGTH) {\n throw new Error(\n `Environment variable name \"${varName}\" exceeds MRT limit of ${MAX_VAR_NAME_LENGTH} characters. ` +\n `Current length: ${varName.length} characters. ` +\n `Consider using shorter paths or consolidating configuration using JSON values.`\n );\n }\n\n const path = varName.substring(PUBLIC_PREFIX.length);\n\n if (!path) {\n throw new Error(\n `Invalid environment variable \"${varName}\": Path cannot be empty after PUBLIC__ prefix. ` +\n `Expected format: PUBLIC__path__to__value (e.g., PUBLIC__app__site__locale)`\n );\n }\n\n const depth = path.split('__').length;\n if (depth > MAX_DEPTH) {\n throw new Error(\n `Environment variable \"${varName}\" exceeds maximum path depth of ${MAX_DEPTH}. ` +\n `Current depth: ${depth}. ` +\n `Consider consolidating with JSON values or reducing nesting levels.`\n );\n }\n\n const normalizedPath = path.toLowerCase();\n const isProtected = protectedPaths.some(\n (protectedPath) => normalizedPath === protectedPath || normalizedPath.startsWith(`${protectedPath}__`)\n );\n\n if (isProtected) {\n throw new Error(\n `Environment variable \"${varName}\" attempts to override protected config path \"${path}\".\\n\\n` +\n `The engagement configuration cannot be overridden via environment variables. ` +\n `Update config.server.ts directly to change engagement settings.`\n );\n }\n\n if (baseConfig && validPaths.length > 0) {\n if (!validPaths.includes(normalizedPath)) {\n throw new Error(\n `Invalid environment variable \"${varName}\": Config path \"${path}\" does not exist in config.server.ts.\\n\\n` +\n `Check your config.server.ts for available configuration paths, or add this path to your base configuration.`\n );\n }\n }\n\n totalValueSize += varValue.length;\n\n envVars.push({\n name: varName,\n path,\n value: varValue,\n depth: path.split('__').length,\n });\n }\n\n if (totalValueSize > MAX_TOTAL_VALUE_SIZE) {\n throw new Error(\n `Total size of PUBLIC__ environment variable values exceeds MRT limit of ${MAX_TOTAL_VALUE_SIZE} bytes (32 KB). ` +\n `Current size: ${totalValueSize} bytes. ` +\n `Consider consolidating configuration using JSON values to reduce the number of variables, ` +\n `or move non-essential configuration to defaults in config.server.ts.`\n );\n }\n\n envVars.sort((a, b) => a.depth - b.depth);\n\n const conflicts: Array<{ parent: string; child: string }> = [];\n for (let i = 0; i < envVars.length; i++) {\n for (let j = i + 1; j < envVars.length; j++) {\n const shorter = envVars[i].path;\n const longer = envVars[j].path;\n if (longer.startsWith(`${shorter}__`)) {\n conflicts.push({\n parent: envVars[i].name,\n child: envVars[j].name,\n });\n }\n }\n }\n\n if (conflicts.length > 0 && process.env.NODE_ENV === 'development') {\n // eslint-disable-next-line no-console\n console.warn(\n `[Config Warning] Conflicting environment variables detected. More specific paths will override parent paths:\\n${conflicts\n .map((c) => ` ${c.parent} ← overridden by → ${c.child}`)\n .join('\\n')}`\n );\n }\n\n let merged: Record<string, unknown> = {};\n\n for (const envVar of envVars) {\n try {\n const parsedValue = parseEnvValue(envVar.value, envVar.name);\n const pathObject = pathToObject(envVar.path, parsedValue, baseConfig);\n merged = deepMerge(merged, pathObject);\n } catch (error) {\n throw new Error(\n `Failed to process environment variable \"${envVar.name}\" with value \"${envVar.value}\": ` +\n `${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n return merged;\n};\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { deepMerge, mergeEnvConfig } from './utils';\n\n/**\n * Base configuration type for storefront-next projects.\n *\n * Generic parameter `App` represents the template's application config shape.\n * The SDK does not prescribe what fields `app` must contain — templates define\n * their own `AppConfig` type with SCAPI credentials, pages, features, etc.\n * and pass it as `BaseConfig<AppConfig>`.\n *\n * The SDK accesses specific `app` fields (e.g., `commerce.api.clientId`) at\n * runtime via the middleware validation, not via compile-time type constraints.\n *\n * @typeParam App - The template's application config shape (defaults to `Record<string, unknown>`)\n *\n * @example\n * // In the template's types file:\n * type AppConfig = { commerce: { api: {...} }; pages: {...}; features: {...} };\n * type Config = BaseConfig<AppConfig>;\n *\n * // In config.server.ts:\n * export default defineConfig<Config>({ metadata: {...}, app: {...} });\n */\nexport type BaseConfig<App extends Record<string, unknown> = Record<string, unknown>> = {\n metadata: {\n projectName: string;\n projectSlug: string;\n };\n runtime?: {\n defaultMrtProject?: string;\n defaultMrtTarget?: string;\n ssrOnly?: string[];\n ssrShared?: string[];\n ssrParameters?: Record<string, string | number | boolean>;\n };\n app: App;\n};\n\nexport interface DefineConfigOptions {\n /**\n * Config paths that cannot be overridden by environment variables.\n * Paths use double underscore separators and are matched case-insensitively.\n *\n * @example ['app__engagement'] — prevents PUBLIC__app__engagement__* from being set via env\n */\n protectedPaths?: string[];\n}\n\n/**\n * Define a type-safe storefront configuration with IDE autocomplete.\n *\n * Automatically merges `PUBLIC__` prefixed environment variables into the config\n * at load time. Validates env vars against the base config structure (strict mode —\n * only allows overriding existing paths).\n *\n * Environment variables:\n * - `PUBLIC__<path>` (optional): Override any config path using double underscore separators.\n * e.g. `PUBLIC__app__commerce__api__clientId=abc123` maps to `config.app.commerce.api.clientId`\n * - `PUBLIC__app__pages__cart__quantityUpdateDebounce=1000` maps to a number (optimistic JSON parsing)\n * - `PUBLIC__app__features__socialLogin__providers=[\"Apple\",\"Google\"]` maps to an array\n *\n * @param config - The base configuration object with all defaults\n * @param options - Optional settings (e.g., protectedPaths to prevent env var overrides)\n * @returns The config with environment variable overrides merged in\n *\n * @example\n * // In config.server.ts:\n * import { defineConfig } from '@salesforce/storefront-next-runtime/config';\n *\n * export default defineConfig({\n * metadata: { projectName: 'My Store', projectSlug: 'my-store' },\n * app: {\n * commerce: { api: { clientId: '', organizationId: '', shortCode: '' }, sites: [] },\n * defaultSiteId: 'RefArch',\n * },\n * }, { protectedPaths: ['app__engagement'] });\n */\nexport function defineConfig<T extends BaseConfig>(config: T, options?: DefineConfigOptions): T {\n const envOverrides = mergeEnvConfig(process.env, config as unknown as Record<string, unknown>, {\n protectedPaths: options?.protectedPaths,\n });\n return deepMerge(config, envOverrides);\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Configuration Context and Provider\n *\n * Provides configuration access throughout the application using React Router's\n * context system. Supports both server and client rendering with proper hydration.\n */\n\nimport { createContext, type ReactNode } from 'react';\nimport { createContext as createRouterContext } from 'react-router';\nimport type { BaseConfig } from './schema';\n\n/**\n * Router context for application configuration.\n *\n * Populated by `createAppConfigMiddleware` with the `app` section of config.\n * Accessible in loaders, actions, and middleware via `context.get(appConfigContext)`.\n */\n// eslint-disable-next-line react-refresh/only-export-components\nexport const appConfigContext = createRouterContext<Record<string, unknown>>();\n\n/**\n * React context for application configuration.\n *\n * Used by the `useConfig()` hook in React components.\n * Populated by `ConfigProvider` in the component tree.\n */\n// eslint-disable-next-line react-refresh/only-export-components\nexport const ConfigContext = createContext<Record<string, unknown> | null>(null);\n\n/**\n * Extract the `app` section from a full config object.\n *\n * @param staticConfig - The full config object (output of `defineConfig()`)\n * @returns The `app` section of the config\n */\n// eslint-disable-next-line react-refresh/only-export-components\nexport function createAppConfig<T extends BaseConfig>(staticConfig: T): T['app'] {\n return staticConfig.app;\n}\n\ninterface ConfigProviderProps {\n config: Record<string, unknown>;\n children: ReactNode;\n}\n\n/**\n * React context provider for application configuration.\n *\n * Wrap your component tree with this to enable `useConfig()` in child components.\n * Typically placed in the root layout component.\n */\nexport function ConfigProvider({ config, children }: ConfigProviderProps) {\n return <ConfigContext.Provider value={config}>{children}</ConfigContext.Provider>;\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Configuration access for loaders, actions, utilities, and React components.\n *\n * Two functions:\n * - `getConfig()` — For loaders, actions, and utilities\n * - `useConfig()` — For React components (hook required for React Context)\n */\n\nimport { useContext } from 'react';\nimport type { RouterContextProvider } from 'react-router';\nimport { ConfigContext, appConfigContext } from './context';\n\ndeclare global {\n interface Window {\n __APP_CONFIG__?: Record<string, unknown>;\n }\n}\n\n/**\n * Get configuration in loaders, actions, and utilities.\n *\n * Pass context parameter in server loaders/actions.\n * Omit context parameter in client loaders (uses window.__APP_CONFIG__).\n *\n * @param context - Router context for server loaders/actions\n * @returns App configuration\n */\nexport function getConfig<T extends Record<string, unknown> = Record<string, unknown>>(\n context?: Readonly<RouterContextProvider>\n): T {\n if (context) {\n const config = context.get(appConfigContext);\n if (!config) {\n throw new Error(\n 'Configuration not available in router context. ' +\n 'Ensure appConfigMiddleware.server runs before other middleware.'\n );\n }\n return config as T;\n }\n\n if (typeof window !== 'undefined' && window.__APP_CONFIG__) {\n return window.__APP_CONFIG__ as T;\n }\n\n throw new Error(\n 'Configuration not available. This can happen if:\\n' +\n '1. Server: Pass context parameter: getConfig(context)\\n' +\n '2. Client: Ensure window.__APP_CONFIG__ was injected during SSR\\n' +\n '3. React component: Use useConfig() hook instead of getConfig()'\n );\n}\n\n/**\n * Get configuration in React components.\n *\n * Must use this hook (not getConfig) because React Context requires useContext().\n *\n * @returns App configuration\n */\nexport function useConfig<T extends Record<string, unknown> = Record<string, unknown>>(): T {\n const config = useContext(ConfigContext);\n if (!config) {\n throw new Error(\n 'useConfig must be used within ConfigProvider. ' +\n 'Ensure ConfigProvider wraps your component tree in root.tsx'\n );\n }\n return config as T;\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { MiddlewareFunction } from 'react-router';\nimport { appConfigContext } from './context';\nimport type { BaseConfig } from './schema';\n\n/**\n * Create app config middleware for both server and client.\n *\n * Follows the same factory pattern as `createMultiSiteMiddleware`.\n *\n * The server middleware:\n * - Validates required Commerce API fields on first request (one-time)\n * - Sets `appConfigContext` in router context with `config.app`\n *\n * The client middleware:\n * - Reads `window.__APP_CONFIG__` (injected during SSR)\n * - Sets `appConfigContext` in router context\n *\n * Environment variables:\n * - `SCAPI_PROXY_HOST` (optional): When set, skips `shortCode` validation\n * (workspace environments route through a proxy that doesn't require shortCode)\n * - `NODE_ENV` (optional): When set to 'test', skips validation entirely\n *\n * @param config - The full config object (output of `defineConfig()`)\n * @returns Object with `server` and `client` middleware functions\n *\n * @example\n * import { createAppConfigMiddleware } from '@salesforce/storefront-next-runtime/config';\n * import config from '@/config/server';\n *\n * const appConfigMiddleware = createAppConfigMiddleware(config);\n *\n * export const middleware = [appConfigMiddleware.server, ...otherMiddleware];\n * export const clientMiddleware = [appConfigMiddleware.client, ...otherClientMiddleware];\n */\nexport function createAppConfigMiddleware<T extends BaseConfig>(\n config: T\n): {\n server: MiddlewareFunction<Response>;\n client: MiddlewareFunction<Record<string, unknown>>;\n} {\n let validationRun = false;\n\n function validateConfig(): void {\n if (validationRun || process.env.NODE_ENV === 'test') {\n return;\n }\n\n const api = (config.app as Record<string, unknown> & { commerce?: { api?: Record<string, string> } }).commerce\n ?.api;\n\n const required: Record<string, string> = {\n clientId: api?.clientId ?? '',\n organizationId: api?.organizationId ?? '',\n };\n\n if (!process.env.SCAPI_PROXY_HOST) {\n required.shortCode = api?.shortCode ?? '';\n }\n\n const missing = Object.entries(required)\n .filter(([_, value]) => !value)\n .map(([key]) => key);\n\n if (missing.length > 0) {\n const envVarMap: Record<string, string> = {\n clientId: 'PUBLIC__app__commerce__api__clientId',\n organizationId: 'PUBLIC__app__commerce__api__organizationId',\n shortCode: 'PUBLIC__app__commerce__api__shortCode',\n };\n\n throw new Error(\n `Missing required Commerce API configuration: ${missing.join(', ')}\\n\\n` +\n `Set these environment variables in your MRT deployment or .env file:\\n${missing\n .map((key) => ` ${envVarMap[key]}=your-value`)\n .join('\\n')}\\n\\n` +\n `Example .env file:\\n` +\n `PUBLIC__app__commerce__api__clientId=your-client-id\\n` +\n `PUBLIC__app__commerce__api__organizationId=your-org-id\\n` +\n `PUBLIC__app__commerce__api__shortCode=your-short-code\\n\\n` +\n `See docs/README-CONFIG.md for complete configuration documentation.`\n );\n }\n\n validationRun = true;\n }\n\n const server: MiddlewareFunction<Response> = ({ context }, next) => {\n validateConfig();\n context.set(appConfigContext, config.app);\n return next();\n };\n\n const client: MiddlewareFunction<Record<string, unknown>> = async ({ context }, next) => {\n const appConfig = typeof window !== 'undefined' ? window.__APP_CONFIG__ : undefined;\n\n if (!appConfig) {\n throw new Error(\n 'window.__APP_CONFIG__ not available. ' +\n 'Check that server loader is injecting config into HTML via Layout component.'\n );\n }\n\n context.set(appConfigContext, appConfig);\n\n return next();\n };\n\n return { server, client };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"config.js","names":["result: Record<string, unknown>","configCurrent: unknown","paths: string[]","envVars: EnvVar[]","conflicts: Array<{ parent: string; child: string }>","merged: Record<string, unknown>","createRouterContext","required: Record<string, string>","envVarMap: Record<string, string>","server: MiddlewareFunction<Response>","client: MiddlewareFunction<Record<string, unknown>>"],"sources":["../src/config/utils.ts","../src/config/schema.ts","../src/config/context.tsx","../src/config/get-config.ts","../src/config/middleware.ts"],"sourcesContent":["/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Type guard to check if value is a plain object (not array, null, or other types)\n */\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n};\n\n/**\n * Deep merge two objects, with source values overriding target values\n * Arrays are replaced, not merged\n *\n * @param target - The base object\n * @param source - The object with values to merge in\n * @returns A new merged object\n *\n * @example\n * deepMerge(\n * { a: { b: 1, c: 2 } },\n * { a: { b: 3, d: 4 } }\n * )\n * // Returns: { a: { b: 3, c: 2, d: 4 } }\n */\nexport const deepMerge = <T extends Record<string, unknown>>(target: T, source: Record<string, unknown>): T => {\n const result: Record<string, unknown> = { ...target };\n\n for (const key in source) {\n const sourceValue = source[key];\n const targetValue = result[key];\n\n if (isPlainObject(sourceValue) && isPlainObject(targetValue)) {\n result[key] = deepMerge(targetValue, sourceValue);\n } else {\n result[key] = sourceValue;\n }\n }\n\n return result as T;\n};\n\n/**\n * Convert a path string with double underscore separators to a nested object\n * Normalizes keys to match baseConfig casing (case-insensitive lookup, preserves baseConfig case)\n *\n * @param path - The path string (e.g., 'app__pages__cart__quantityUpdateDebounce')\n * @param value - The value to set at the path\n * @param baseConfig - Optional base config for case normalization\n * @returns A nested object\n *\n * @example\n * pathToObject('app__pages__cart__maxQuantity', 999)\n * // Returns: { app: { pages: { cart: { maxQuantity: 999 } } } }\n *\n * @example\n * // With baseConfig normalization:\n * pathToObject('APP__SITE__LOCALE', 'en-GB', { app: { site: { locale: 'en-GB' } } })\n * // Returns: { app: { site: { locale: 'en-GB' } } } (normalized to baseConfig casing)\n */\nexport const pathToObject = (\n path: string,\n value: unknown,\n baseConfig?: Record<string, unknown>\n): Record<string, unknown> => {\n const keys = path.split('__');\n const result: Record<string, unknown> = {};\n\n let current = result;\n let configCurrent: unknown = baseConfig;\n\n for (let i = 0; i < keys.length - 1; i++) {\n const key = keys[i];\n\n let normalizedKey = key;\n if (configCurrent && typeof configCurrent === 'object' && !Array.isArray(configCurrent)) {\n const actualKey = Object.keys(configCurrent).find((k) => k.toLowerCase() === key.toLowerCase());\n if (actualKey) {\n normalizedKey = actualKey;\n configCurrent = (configCurrent as Record<string, unknown>)[actualKey];\n } else {\n configCurrent = null;\n }\n }\n\n current[normalizedKey] = {};\n current = current[normalizedKey] as Record<string, unknown>;\n }\n\n const lastKey = keys[keys.length - 1];\n let normalizedLastKey = lastKey;\n if (configCurrent && typeof configCurrent === 'object' && !Array.isArray(configCurrent)) {\n const actualKey = Object.keys(configCurrent).find((k) => k.toLowerCase() === lastKey.toLowerCase());\n if (actualKey) {\n normalizedLastKey = actualKey;\n }\n }\n\n current[normalizedLastKey] = value;\n return result;\n};\n\n/**\n * Parse environment variable value with optimistic JSON parsing\n * Tries to parse as JSON first, falls back to string if invalid\n * Supports multi-line formatted JSON by normalizing whitespace before parsing\n *\n * @param varValue - The environment variable value\n * @param varName - Optional variable name for better error messages\n * @returns The parsed value (JSON type if valid JSON, otherwise string)\n *\n * @example\n * // Primitives\n * parseEnvValue('42') // → 42 (number)\n * parseEnvValue('true') // → true (boolean)\n * parseEnvValue('hello') // → 'hello' (string)\n *\n * @example\n * // Single-line JSON\n * parseEnvValue('[\"Apple\",\"Google\"]') // → ['Apple', 'Google'] (array)\n * parseEnvValue('{\"key\":\"value\"}') // → {key: 'value'} (object)\n *\n * @example\n * // Multi-line formatted JSON (whitespace normalized automatically)\n * parseEnvValue('[\n * {\"id\": \"en-GB\"},\n * {\"id\": \"fr-FR\"}\n * ]') // → [{id: 'en-GB'}, {id: 'fr-FR'}] (array)\n */\nexport const parseEnvValue = (varValue: string, varName?: string): unknown => {\n try {\n return JSON.parse(varValue);\n } catch {\n const trimmed = varValue.trim();\n if (trimmed.startsWith('{') || trimmed.startsWith('[')) {\n try {\n const normalized = varValue.replace(/\\s+/g, ' ').trim();\n return JSON.parse(normalized);\n } catch {\n if (process.env.NODE_ENV === 'development') {\n const preview = varValue.length > 50 ? `${varValue.substring(0, 50)}...` : varValue;\n const varInfo = varName ? ` in \"${varName}\"` : '';\n // eslint-disable-next-line no-console\n console.warn(\n `[Config Warning] Value${varInfo} looks like JSON but failed to parse: \"${preview}\". ` +\n `Using as string instead. Check for syntax errors if this was meant to be JSON.`\n );\n }\n }\n }\n return varValue;\n }\n};\n\n/**\n * Extract all valid paths from a config object (recursively traverses the object structure)\n * Returns paths in lowercase with double underscore separators\n *\n * @param obj - The config object to extract paths from\n * @param prefix - Current path prefix (used for recursion)\n * @returns Array of valid config paths\n *\n * @example\n * extractValidPaths({ app: { site: { locale: 'en-GB' } } })\n * // Returns: ['app__site__locale']\n */\nexport const extractValidPaths = (obj: unknown, prefix = ''): string[] => {\n if (!isPlainObject(obj)) {\n return prefix ? [prefix] : [];\n }\n\n const paths: string[] = [];\n for (const [key, value] of Object.entries(obj)) {\n const normalizedKey = key.toLowerCase();\n const currentPath = prefix ? `${prefix}__${normalizedKey}` : normalizedKey;\n\n if (isPlainObject(value)) {\n paths.push(currentPath); // Allow setting whole object (e.g. PUBLIC__app__commerceAgent)\n // Recursively extract paths from nested objects\n paths.push(...extractValidPaths(value, currentPath));\n } else {\n // Leaf node - this is a valid config path\n paths.push(currentPath);\n }\n }\n\n return paths;\n};\n\ninterface EnvVar {\n name: string;\n path: string;\n value: string;\n depth: number;\n}\n\n/**\n * Options for mergeEnvConfig\n */\nexport interface MergeEnvConfigOptions {\n /**\n * Config paths that cannot be overridden by environment variables.\n * Paths are matched case-insensitively with double underscore separators.\n * Any env var targeting a protected path or a sub-path of it will throw an error.\n *\n * @example ['app__engagement'] — prevents PUBLIC__app__engagement__* from being set via env\n */\n protectedPaths?: string[];\n}\n\n/**\n * Merge environment variables with PUBLIC__ prefix into config.\n *\n * Uses double underscore (__) to target nested config paths.\n * All PUBLIC__ prefixed variables are exposed to the client (bundled into window.__APP_CONFIG__).\n *\n * Server-only secrets should NEVER use this — read them directly from process.env in server code.\n *\n * Environment variables:\n * - `PUBLIC__<path>` (optional): Override any config path. e.g. `PUBLIC__app__commerce__api__clientId=abc123`\n * - `NODE_ENV` (optional): When set to 'development', enables conflict warnings for overlapping paths\n *\n * @param env - Environment variables object (defaults to process.env)\n * @param baseConfig - Optional base config for strict path validation and case normalization\n * @param options - Optional configuration including protected paths\n * @returns Object with overrides to merge into base config\n *\n * @example\n * // Environment variables:\n * // PUBLIC__app__commerce__api__clientId=abc123\n * // PUBLIC__app__pages__cart__quantityUpdateDebounce=1000\n * // PUBLIC__app__features__socialLogin__providers=[\"Apple\",\"Google\"]\n *\n * mergeEnvConfig()\n * // Returns:\n * // {\n * // app: {\n * // commerce: { api: { clientId: 'abc123' } },\n * // pages: { cart: { quantityUpdateDebounce: 1000 } },\n * // features: { socialLogin: { providers: ['Apple', 'Google'] } }\n * // }\n * // }\n */\nexport const mergeEnvConfig = (\n env: Record<string, string | undefined> = typeof process !== 'undefined' ? process.env : {},\n baseConfig?: Record<string, unknown>,\n options?: MergeEnvConfigOptions\n): Record<string, unknown> => {\n const PUBLIC_PREFIX = 'PUBLIC__';\n const MAX_VAR_NAME_LENGTH = 512; // MRT limit: 512 characters\n const MAX_TOTAL_VALUE_SIZE = 32 * 1024; // MRT limit: 32 KB\n const MAX_DEPTH = 10;\n\n const protectedPaths = options?.protectedPaths ?? [];\n const validPaths = baseConfig ? extractValidPaths(baseConfig) : [];\n\n const envVars: EnvVar[] = [];\n let totalValueSize = 0;\n\n for (const [varName, varValue] of Object.entries(env)) {\n if (varValue === undefined || varValue === null || !varName.startsWith(PUBLIC_PREFIX)) continue;\n\n if (varName.length > MAX_VAR_NAME_LENGTH) {\n throw new Error(\n `Environment variable name \"${varName}\" exceeds MRT limit of ${MAX_VAR_NAME_LENGTH} characters. ` +\n `Current length: ${varName.length} characters. ` +\n `Consider using shorter paths or consolidating configuration using JSON values.`\n );\n }\n\n const path = varName.substring(PUBLIC_PREFIX.length);\n\n if (!path) {\n throw new Error(\n `Invalid environment variable \"${varName}\": Path cannot be empty after PUBLIC__ prefix. ` +\n `Expected format: PUBLIC__path__to__value (e.g., PUBLIC__app__site__locale)`\n );\n }\n\n const depth = path.split('__').length;\n if (depth > MAX_DEPTH) {\n throw new Error(\n `Environment variable \"${varName}\" exceeds maximum path depth of ${MAX_DEPTH}. ` +\n `Current depth: ${depth}. ` +\n `Consider consolidating with JSON values or reducing nesting levels.`\n );\n }\n\n const normalizedPath = path.toLowerCase();\n const isProtected = protectedPaths.some(\n (protectedPath) => normalizedPath === protectedPath || normalizedPath.startsWith(`${protectedPath}__`)\n );\n\n if (isProtected) {\n throw new Error(\n `Environment variable \"${varName}\" attempts to override protected config path \"${path}\".\\n\\n` +\n `The engagement configuration cannot be overridden via environment variables. ` +\n `Update config.server.ts directly to change engagement settings.`\n );\n }\n\n if (baseConfig && validPaths.length > 0) {\n if (!validPaths.includes(normalizedPath)) {\n // eslint-disable-next-line no-console\n console.warn(\n `[Config Warning] Ignoring environment variable \"${varName}\": Config path \"${path}\" does not exist in config.server.ts.`\n );\n continue;\n }\n }\n\n totalValueSize += varValue.length;\n\n envVars.push({\n name: varName,\n path,\n value: varValue,\n depth: path.split('__').length,\n });\n }\n\n if (totalValueSize > MAX_TOTAL_VALUE_SIZE) {\n throw new Error(\n `Total size of PUBLIC__ environment variable values exceeds MRT limit of ${MAX_TOTAL_VALUE_SIZE} bytes (32 KB). ` +\n `Current size: ${totalValueSize} bytes. ` +\n `Consider consolidating configuration using JSON values to reduce the number of variables, ` +\n `or move non-essential configuration to defaults in config.server.ts.`\n );\n }\n\n envVars.sort((a, b) => a.depth - b.depth);\n\n const conflicts: Array<{ parent: string; child: string }> = [];\n for (let i = 0; i < envVars.length; i++) {\n for (let j = i + 1; j < envVars.length; j++) {\n const shorter = envVars[i].path;\n const longer = envVars[j].path;\n if (longer.startsWith(`${shorter}__`)) {\n conflicts.push({\n parent: envVars[i].name,\n child: envVars[j].name,\n });\n }\n }\n }\n\n if (conflicts.length > 0 && process.env.NODE_ENV === 'development') {\n // eslint-disable-next-line no-console\n console.warn(\n `[Config Warning] Conflicting environment variables detected. More specific paths will override parent paths:\\n${conflicts\n .map((c) => ` ${c.parent} ← overridden by → ${c.child}`)\n .join('\\n')}`\n );\n }\n\n let merged: Record<string, unknown> = {};\n\n for (const envVar of envVars) {\n try {\n const parsedValue = parseEnvValue(envVar.value, envVar.name);\n const pathObject = pathToObject(envVar.path, parsedValue, baseConfig);\n merged = deepMerge(merged, pathObject);\n } catch (error) {\n throw new Error(\n `Failed to process environment variable \"${envVar.name}\" with value \"${envVar.value}\": ` +\n `${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n return merged;\n};\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { deepMerge, mergeEnvConfig } from './utils';\n\n/**\n * Base configuration type for storefront-next projects.\n *\n * Generic parameter `App` represents the template's application config shape.\n * The SDK does not prescribe what fields `app` must contain — templates define\n * their own `AppConfig` type with SCAPI credentials, pages, features, etc.\n * and pass it as `BaseConfig<AppConfig>`.\n *\n * The SDK accesses specific `app` fields (e.g., `commerce.api.clientId`) at\n * runtime via the middleware validation, not via compile-time type constraints.\n *\n * @typeParam App - The template's application config shape (defaults to `Record<string, unknown>`)\n *\n * @example\n * // In the template's types file:\n * type AppConfig = { commerce: { api: {...} }; pages: {...}; features: {...} };\n * type Config = BaseConfig<AppConfig>;\n *\n * // In config.server.ts:\n * export default defineConfig<Config>({ metadata: {...}, app: {...} });\n */\nexport type BaseConfig<App extends Record<string, unknown> = Record<string, unknown>> = {\n metadata: {\n projectName: string;\n projectSlug: string;\n };\n runtime?: {\n defaultMrtProject?: string;\n defaultMrtTarget?: string;\n ssrOnly?: string[];\n ssrShared?: string[];\n ssrParameters?: Record<string, string | number | boolean>;\n };\n app: App;\n};\n\nexport interface DefineConfigOptions {\n /**\n * Config paths that cannot be overridden by environment variables.\n * Paths use double underscore separators and are matched case-insensitively.\n *\n * @example ['app__engagement'] — prevents PUBLIC__app__engagement__* from being set via env\n */\n protectedPaths?: string[];\n}\n\n/**\n * Define a type-safe storefront configuration with IDE autocomplete.\n *\n * Automatically merges `PUBLIC__` prefixed environment variables into the config\n * at load time. Validates env vars against the base config structure (strict mode —\n * only allows overriding existing paths).\n *\n * Environment variables:\n * - `PUBLIC__<path>` (optional): Override any config path using double underscore separators.\n * e.g. `PUBLIC__app__commerce__api__clientId=abc123` maps to `config.app.commerce.api.clientId`\n * - `PUBLIC__app__pages__cart__quantityUpdateDebounce=1000` maps to a number (optimistic JSON parsing)\n * - `PUBLIC__app__features__socialLogin__providers=[\"Apple\",\"Google\"]` maps to an array\n *\n * @param config - The base configuration object with all defaults\n * @param options - Optional settings (e.g., protectedPaths to prevent env var overrides)\n * @returns The config with environment variable overrides merged in\n *\n * @example\n * // In config.server.ts:\n * import { defineConfig } from '@salesforce/storefront-next-runtime/config';\n *\n * export default defineConfig({\n * metadata: { projectName: 'My Store', projectSlug: 'my-store' },\n * app: {\n * commerce: { api: { clientId: '', organizationId: '', shortCode: '' }, sites: [] },\n * defaultSiteId: 'RefArch',\n * },\n * }, { protectedPaths: ['app__engagement'] });\n */\nexport function defineConfig<T extends BaseConfig>(config: T, options?: DefineConfigOptions): T {\n const envOverrides = mergeEnvConfig(process.env, config as unknown as Record<string, unknown>, {\n protectedPaths: options?.protectedPaths,\n });\n return deepMerge(config, envOverrides);\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Configuration Context and Provider\n *\n * Provides configuration access throughout the application using React Router's\n * context system. Supports both server and client rendering with proper hydration.\n */\n\nimport { createContext, type ReactNode } from 'react';\nimport { createContext as createRouterContext } from 'react-router';\nimport type { BaseConfig } from './schema';\n\n/**\n * Router context for application configuration.\n *\n * Populated by `createAppConfigMiddleware` with the `app` section of config.\n * Accessible in loaders, actions, and middleware via `context.get(appConfigContext)`.\n */\n// eslint-disable-next-line react-refresh/only-export-components\nexport const appConfigContext = createRouterContext<Record<string, unknown>>();\n\n/**\n * React context for application configuration.\n *\n * Used by the `useConfig()` hook in React components.\n * Populated by `ConfigProvider` in the component tree.\n */\n// eslint-disable-next-line react-refresh/only-export-components\nexport const ConfigContext = createContext<Record<string, unknown> | null>(null);\n\n/**\n * Extract the `app` section from a full config object.\n *\n * @param staticConfig - The full config object (output of `defineConfig()`)\n * @returns The `app` section of the config\n */\n// eslint-disable-next-line react-refresh/only-export-components\nexport function createAppConfig<T extends BaseConfig>(staticConfig: T): T['app'] {\n return staticConfig.app;\n}\n\ninterface ConfigProviderProps {\n config: Record<string, unknown>;\n children: ReactNode;\n}\n\n/**\n * React context provider for application configuration.\n *\n * Wrap your component tree with this to enable `useConfig()` in child components.\n * Typically placed in the root layout component.\n */\nexport function ConfigProvider({ config, children }: ConfigProviderProps) {\n return <ConfigContext.Provider value={config}>{children}</ConfigContext.Provider>;\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Configuration access for loaders, actions, utilities, and React components.\n *\n * Two functions:\n * - `getConfig()` — For loaders, actions, and utilities\n * - `useConfig()` — For React components (hook required for React Context)\n */\n\nimport { useContext } from 'react';\nimport type { RouterContextProvider } from 'react-router';\nimport { ConfigContext, appConfigContext } from './context';\n\ndeclare global {\n interface Window {\n __APP_CONFIG__?: Record<string, unknown>;\n }\n}\n\n/**\n * Get configuration in loaders, actions, and utilities.\n *\n * Pass context parameter in server loaders/actions.\n * Omit context parameter in client loaders (uses window.__APP_CONFIG__).\n *\n * @param context - Router context for server loaders/actions\n * @returns App configuration\n */\nexport function getConfig<T extends Record<string, unknown> = Record<string, unknown>>(\n context?: Readonly<RouterContextProvider>\n): T {\n if (context) {\n const config = context.get(appConfigContext);\n if (!config) {\n throw new Error(\n 'Configuration not available in router context. ' +\n 'Ensure appConfigMiddleware.server runs before other middleware.'\n );\n }\n return config as T;\n }\n\n if (typeof window !== 'undefined' && window.__APP_CONFIG__) {\n return window.__APP_CONFIG__ as T;\n }\n\n throw new Error(\n 'Configuration not available. This can happen if:\\n' +\n '1. Server: Pass context parameter: getConfig(context)\\n' +\n '2. Client: Ensure window.__APP_CONFIG__ was injected during SSR\\n' +\n '3. React component: Use useConfig() hook instead of getConfig()'\n );\n}\n\n/**\n * Get configuration in React components.\n *\n * Must use this hook (not getConfig) because React Context requires useContext().\n *\n * @returns App configuration\n */\nexport function useConfig<T extends Record<string, unknown> = Record<string, unknown>>(): T {\n const config = useContext(ConfigContext);\n if (!config) {\n throw new Error(\n 'useConfig must be used within ConfigProvider. ' +\n 'Ensure ConfigProvider wraps your component tree in root.tsx'\n );\n }\n return config as T;\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { MiddlewareFunction } from 'react-router';\nimport { appConfigContext } from './context';\nimport type { BaseConfig } from './schema';\n\n/**\n * Create app config middleware for both server and client.\n *\n * Follows the same factory pattern as `createSiteContextMiddleware`.\n *\n * The server middleware:\n * - Validates required Commerce API fields on first request (one-time)\n * - Sets `appConfigContext` in router context with `config.app`\n *\n * The client middleware:\n * - Reads `window.__APP_CONFIG__` (injected during SSR)\n * - Sets `appConfigContext` in router context\n *\n * Environment variables:\n * - `SCAPI_PROXY_HOST` (optional): When set, skips `shortCode` validation\n * (workspace environments route through a proxy that doesn't require shortCode)\n * - `NODE_ENV` (optional): When set to 'test', skips validation entirely\n *\n * @param config - The full config object (output of `defineConfig()`)\n * @returns Object with `server` and `client` middleware functions\n *\n * @example\n * import { createAppConfigMiddleware } from '@salesforce/storefront-next-runtime/config';\n * import config from '@/config/server';\n *\n * const appConfigMiddleware = createAppConfigMiddleware(config);\n *\n * export const middleware = [appConfigMiddleware.server, ...otherMiddleware];\n * export const clientMiddleware = [appConfigMiddleware.client, ...otherClientMiddleware];\n */\nexport function createAppConfigMiddleware<T extends BaseConfig>(\n config: T\n): {\n server: MiddlewareFunction<Response>;\n client: MiddlewareFunction<Record<string, unknown>>;\n} {\n let validationRun = false;\n\n function validateConfig(): void {\n if (validationRun || process.env.NODE_ENV === 'test') {\n return;\n }\n\n const api = (config.app as Record<string, unknown> & { commerce?: { api?: Record<string, string> } }).commerce\n ?.api;\n\n const required: Record<string, string> = {\n clientId: api?.clientId ?? '',\n organizationId: api?.organizationId ?? '',\n };\n\n if (!process.env.SCAPI_PROXY_HOST) {\n required.shortCode = api?.shortCode ?? '';\n }\n\n const missing = Object.entries(required)\n .filter(([_, value]) => !value)\n .map(([key]) => key);\n\n if (missing.length > 0) {\n const envVarMap: Record<string, string> = {\n clientId: 'PUBLIC__app__commerce__api__clientId',\n organizationId: 'PUBLIC__app__commerce__api__organizationId',\n shortCode: 'PUBLIC__app__commerce__api__shortCode',\n };\n\n throw new Error(\n `Missing required Commerce API configuration: ${missing.join(', ')}\\n\\n` +\n `Set these environment variables in your MRT deployment or .env file:\\n${missing\n .map((key) => ` ${envVarMap[key]}=your-value`)\n .join('\\n')}\\n\\n` +\n `Example .env file:\\n` +\n `PUBLIC__app__commerce__api__clientId=your-client-id\\n` +\n `PUBLIC__app__commerce__api__organizationId=your-org-id\\n` +\n `PUBLIC__app__commerce__api__shortCode=your-short-code\\n\\n` +\n `See docs/README-CONFIG.md for complete configuration documentation.`\n );\n }\n\n validationRun = true;\n }\n\n const server: MiddlewareFunction<Response> = ({ context }, next) => {\n validateConfig();\n context.set(appConfigContext, config.app);\n return next();\n };\n\n const client: MiddlewareFunction<Record<string, unknown>> = async ({ context }, next) => {\n const appConfig = typeof window !== 'undefined' ? window.__APP_CONFIG__ : undefined;\n\n if (!appConfig) {\n throw new Error(\n 'window.__APP_CONFIG__ not available. ' +\n 'Check that server loader is injecting config into HTML via Layout component.'\n );\n }\n\n context.set(appConfigContext, appConfig);\n\n return next();\n };\n\n return { server, client };\n}\n"],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ import { n as ComponentModule, o as FrameworkAdapter } from "./types3.js";
|
|
|
3
3
|
import { g as IsomorphicConfiguration } from "./index.js";
|
|
4
4
|
import { i as RegionDecoratorProps, t as ComponentDecoratorProps } from "./component.types.js";
|
|
5
5
|
import React$1 from "react";
|
|
6
|
-
import * as
|
|
6
|
+
import * as react_jsx_runtime1 from "react/jsx-runtime";
|
|
7
7
|
|
|
8
8
|
//#region src/design/react/core/PageDesignerProvider.d.ts
|
|
9
9
|
type PageDesignerContextType = {
|
|
@@ -49,7 +49,7 @@ declare function PageDesignerPageMetadataProvider({
|
|
|
49
49
|
children
|
|
50
50
|
}: React.PropsWithChildren<{
|
|
51
51
|
page: ShopperExperience.schemas['Page'];
|
|
52
|
-
}>):
|
|
52
|
+
}>): react_jsx_runtime1.JSX.Element;
|
|
53
53
|
//#endregion
|
|
54
54
|
//#region src/design/react/core/RegionContext.d.ts
|
|
55
55
|
interface RegionContextType {
|
package/dist/events.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","names":[],"sources":["../src/events/types.ts","../src/events/events.ts","../src/events/mediator.ts"],"sourcesContent":[],"mappings":";;;;;KAmBK,iBAAA,GAAoB,gBAAA,CAAiB,OAqEQ,CAAA,aAAA,CAAA,GArEiB,gBAAA,CAAiB,OAqElC,CAAA,aAAA,CAAA;AAQlD,KA5EK,MAAA,GAAS,gBAAA,CAAiB,OA4EI,CAAA,QAAA,CAAA,GA5EgB,gBAAA,CAAiB,OA4EjC,CAAA,QAAA,CAAA;;;;;;AAQnC;AAOA;;;;;AAMA;AAMA;AAOA;;AAEe,UA3FE,aAAA,CA2FF;EAF2B,QAAA,EAAA,YAAA,GAAA,OAAA;EAAS,IAAA,CAAA,EAAA,MAAA;EAKlC,GAAA,CAAA,EAAA,MAAA;EAKA,SAAA,CAAA,EAAA,MAAA;EAOA,UAAA,CAAA,EAAA,MAAA;EAMA,UAAA,CAAA,EAAA,MAAA;EAoBA,SAAA,CAAA,EAAA,MAAA;EASL,QAAA,CAAA,EAAA,MAAc;EACpB,KAAA,CAAA,EAAA,MAAA;;;;;;AAMA,UAnIW,UAAA,CAmIX;;;;;AAMA,KAjIM,gBAAA,GAAmB,aAiIzB,GAjIyC,UAiIzC;AACA,KA5HM,SAAA,GA4HN;EAA+B,SAAA,EAAA,MAAA;EAAwB,OAAA,EA1HhD,gBA0HgD;EAKjD,UAAA,CAAA,EAAA,MAAY;CACd;AAAkB,UA5HX,aAAA,SAAsB,SA4HX,CAAA;EAAiB,SAAA,EAAA,WAAA;EAAC,IAAA,EAAA,MAAA;AAM9C;AAAmC,UA7HlB,gBAAA,SAAyB,SA6HP,CAAA;EAAoC,SAAA,EAAA,cAAA;EAAa,OAAA,EA3HvE,eAAA,CAAgB,OA2HuD,CAAA,SAAA,CAAA;;AACvE,UAzHI,eAAA,SAAwB,SAyH5B,CAAA;EAAgB,SAAA,EAAA,aAAA;EAQjB,eAAA,EAAa,MAAA;EASR,aAAA,EAvIE,aAAA,CAAc,OAuIJ,CAAA,kBAAA,CAAA,EAAA;EAEL,IAAA,EAAA,MAAA;EAA2B,WAAA,EAvIlC,aAAA,CAAc,OAuIoB,CAAA,qBAAA,CAAA,CAAA,qBAAA,CAAA;;AAAyB,UApI3D,iBAAA,SAA0B,SAoIiC,CAAA;EAOhE,SAAA,EAAA,eAAa;YAzIX,eAAA,CAAgB;iBACX,aAAA,CAAc;;ECnEjB,WAAA,EDqEC,aAAA,CAAc,OCrEJ,CAAA,qBAAA,CAAA,CAAA,qBAAA,CAAA;;AACZ,UDuEE,oBAAA,SAA6B,SCvE/B,CAAA;EACQ,SAAA,EAAA,kBAAA;EAAb,aAAA,EAAA,MAAA;EACP,eAAA,EAAA,MAAA;EAAa,QAAA,EDyEF,aAAA,CAAc,OCzEZ,CAAA,kBAAA,CAAA,EAAA;;AAgBA,UD4DC,2BAAA,SAAoC,SC5DpB,CAAA;EAAQ,SAAA,EAAA,2BAAA;EAA8B,QAAA,ED8DzD,eAAA,CAAgB,OC9DyC,CAAA,UAAA,CAAA;EAA0B,OAAA,ED+DpF,aAAA,CAAc,OC/DsE,CAAA,kBAAA,CAAA;;UDkEhF,yBAAA,SAAkC;;;EEhEnC,OAAA,EFmEH,aAAA,CAAc,
|
|
1
|
+
{"version":3,"file":"events.d.ts","names":[],"sources":["../src/events/types.ts","../src/events/events.ts","../src/events/mediator.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/design/messaging-api/domain-types.ts","../src/design/messaging-api/api-types.ts","../src/design/messaging-api/client.ts","../src/design/messaging-api/host.ts"],"sourcesContent":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/design/messaging-api/domain-types.ts","../src/design/messaging-api/api-types.ts","../src/design/messaging-api/client.ts","../src/design/messaging-api/host.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/load-config.js
CHANGED
|
@@ -32,7 +32,8 @@ async function loadConfig() {
|
|
|
32
32
|
}).import(configPath);
|
|
33
33
|
return mod.default ?? mod;
|
|
34
34
|
} catch (error) {
|
|
35
|
-
|
|
35
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
36
|
+
throw new Error(`[storefront-next-runtime] Found config.server.ts at ${configPath} but failed to import it.\n${reason}`, { cause: error });
|
|
36
37
|
}
|
|
37
38
|
}
|
|
38
39
|
|
package/dist/load-config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load-config.js","names":[],"sources":["../src/config/load-config.ts"],"sourcesContent":["/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport type { BaseConfig } from './schema';\n\n/**\n * Dynamically imports `config.server.ts` from the project root (CWD) and returns\n * the full configuration object. This runs at route discovery time under vite-node\n * (typegen, dev, build), which handles the TS transformation.\n *\n * Uses jiti to transpile TypeScript on the fly, which works regardless of whether\n * the caller runs under vite-node, a plain Node process, or any other runtime.\n * This avoids the fragile assumption that vite-node will intercept dynamic imports\n * from pre-compiled npm packages (it won't — Vite externalizes node_modules).\n *\n * Returns the full config including `metadata`, `runtime`, and `app` sections.\n * Callers that only need `app` can destructure: `const { app } = await loadConfig()`.\n *\n * - If the config file is missing, throws with a clear message.\n * - If the config file exists but fails to import, throws with the original error as cause.\n *\n * @returns The full configuration object.\n * @throws If `config.server.ts` is not found or fails to import.\n */\nexport async function loadConfig<T extends BaseConfig = BaseConfig>(): Promise<T> {\n const configPath = path.resolve(process.cwd(), 'config.server.ts');\n\n if (!fs.existsSync(configPath)) {\n throw new Error(\n `[storefront-next-runtime] config.server.ts is required but not found at ${configPath}. ` +\n `Create this file with defineConfig() to configure your storefront application.`\n );\n }\n\n try {\n const { createJiti } = await import('jiti');\n\n const jiti = createJiti(import.meta.url, {\n fsCache: false,\n interopDefault: true,\n });\n\n const mod = await jiti.import(configPath);\n const config = (mod as Record<string, unknown>).default ?? mod;\n return config as T;\n } catch (error) {\n throw new Error(`[storefront-next-runtime] Found config.server.ts at ${configPath} but failed to import it
|
|
1
|
+
{"version":3,"file":"load-config.js","names":[],"sources":["../src/config/load-config.ts"],"sourcesContent":["/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport type { BaseConfig } from './schema';\n\n/**\n * Dynamically imports `config.server.ts` from the project root (CWD) and returns\n * the full configuration object. This runs at route discovery time under vite-node\n * (typegen, dev, build), which handles the TS transformation.\n *\n * Uses jiti to transpile TypeScript on the fly, which works regardless of whether\n * the caller runs under vite-node, a plain Node process, or any other runtime.\n * This avoids the fragile assumption that vite-node will intercept dynamic imports\n * from pre-compiled npm packages (it won't — Vite externalizes node_modules).\n *\n * Returns the full config including `metadata`, `runtime`, and `app` sections.\n * Callers that only need `app` can destructure: `const { app } = await loadConfig()`.\n *\n * - If the config file is missing, throws with a clear message.\n * - If the config file exists but fails to import, throws with the original error as cause.\n *\n * @returns The full configuration object.\n * @throws If `config.server.ts` is not found or fails to import.\n */\nexport async function loadConfig<T extends BaseConfig = BaseConfig>(): Promise<T> {\n const configPath = path.resolve(process.cwd(), 'config.server.ts');\n\n if (!fs.existsSync(configPath)) {\n throw new Error(\n `[storefront-next-runtime] config.server.ts is required but not found at ${configPath}. ` +\n `Create this file with defineConfig() to configure your storefront application.`\n );\n }\n\n try {\n const { createJiti } = await import('jiti');\n\n const jiti = createJiti(import.meta.url, {\n fsCache: false,\n interopDefault: true,\n });\n\n const mod = await jiti.import(configPath);\n const config = (mod as Record<string, unknown>).default ?? mod;\n return config as T;\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n throw new Error(\n `[storefront-next-runtime] Found config.server.ts at ${configPath} but failed to import it.\\n${reason}`,\n {\n cause: error,\n }\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAsCA,eAAsB,aAA4D;CAC9E,MAAM,aAAa,KAAK,QAAQ,QAAQ,KAAK,EAAE,mBAAmB;AAElE,KAAI,CAAC,GAAG,WAAW,WAAW,CAC1B,OAAM,IAAI,MACN,2EAA2E,WAAW,kFAEzF;AAGL,KAAI;EACA,MAAM,EAAE,eAAe,MAAM,OAAO;EAOpC,MAAM,MAAM,MALC,WAAW,OAAO,KAAK,KAAK;GACrC,SAAS;GACT,gBAAgB;GACnB,CAAC,CAEqB,OAAO,WAAW;AAEzC,SADgB,IAAgC,WAAW;UAEtD,OAAO;EACZ,MAAM,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACrE,QAAM,IAAI,MACN,uDAAuD,WAAW,6BAA6B,UAC/F,EACI,OAAO,OACV,CACJ"}
|
package/dist/routing.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { RouteConfigEntry } from "@react-router/dev/routes";
|
|
|
3
3
|
//#region src/routing/flat-routes.d.ts
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Discovers all file-based routes, merges extension routes, and applies
|
|
6
|
+
* Discovers all file-based routes, merges extension routes, and applies site context
|
|
7
7
|
* URL configuration if defined in the project's `config.server.ts`.
|
|
8
8
|
*
|
|
9
9
|
* 1. Discover routes from the filesystem using React Router's `flatRoutes`.
|
package/dist/routing.js
CHANGED
|
@@ -101,7 +101,7 @@ async function discoverExtensionRoutes(ignoredRouteFiles, routes) {
|
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
/**
|
|
104
|
-
* Discovers all file-based routes, merges extension routes, and applies
|
|
104
|
+
* Discovers all file-based routes, merges extension routes, and applies site context
|
|
105
105
|
* URL configuration if defined in the project's `config.server.ts`.
|
|
106
106
|
*
|
|
107
107
|
* 1. Discover routes from the filesystem using React Router's `flatRoutes`.
|
package/dist/routing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routing.js","names":["path","_flatRoutes"],"sources":["../src/routing/merge-routes.ts","../src/routing/flat-routes.ts"],"sourcesContent":["/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { type RouteConfigEntry } from '@react-router/dev/routes';\n\n/**\n * Find the nearest route by its ID in the route tree\n * @param routes - The route subtree to search\n * @param layoutId - The route ID to find (e.g., \"routes/_app\" or \"routes/_app.account\")\n * @param rootPath - The full route path from the root to the current route (default: '')\n * @returns An object with routes array, routeIndex, and path, or null if not found. Returns exact match if found, otherwise returns route where route.id is a prefix of layoutId\n */\nfunction findNearestRoute(\n routes: RouteConfigEntry[],\n layoutId: string,\n rootPath: string = ''\n): { routes: RouteConfigEntry[]; routeIndex: number; path: string } | null {\n for (let i = 0; i < routes.length; i++) {\n const route = routes[i];\n const path = route.path ? `${rootPath}/${route.path}` : rootPath;\n if (route.id === layoutId) {\n return { routes, routeIndex: i, path };\n }\n if (route.children) {\n const found = findNearestRoute(route.children, layoutId, path);\n if (found) {\n return found;\n }\n }\n // Check if route.id is a prefix of layoutId, indicating a nested route\n if (route.id && layoutId.startsWith(route.id)) {\n return { routes, routeIndex: i, path };\n }\n }\n return null;\n}\n\n/**\n * Merges extension routes into the main routes array, handling route nesting.\n * Routes without IDs are added directly to the routes array. Routes with IDs are processed\n * to remove the extension prefix and are either:\n * - Added as children of existing routes (if a nearest route is found via prefix matching)\n * - Replace existing routes (if an exact match is found)\n * - Added directly to the routes array (if no matching route exists)\n *\n * When adding as a child, the parent route's path is clipped from the child route's path.\n *\n * @param routes - The main routes array to merge into (mutated in place)\n * @param extensionRoutes - The extension routes to merge\n * @param extensionIdPrefix - The prefix to remove from extension route IDs (e.g., \"extensions/store-locator/\")\n */\nexport function mergeRoutes(\n routes: RouteConfigEntry[],\n extensionRoutes: RouteConfigEntry[],\n extensionIdPrefix: string\n): void {\n for (const route of extensionRoutes) {\n if (!route.id) {\n routes.unshift(route);\n continue;\n }\n const routeId = route.id.replace(extensionIdPrefix, '');\n const nearestRouteResult = findNearestRoute(routes, routeId);\n if (nearestRouteResult) {\n const nearestRoute = nearestRouteResult.routes[nearestRouteResult.routeIndex];\n if (nearestRoute.id === routeId) {\n // Replacing an existing route, we assume we can just swap out the implementation\n nearestRouteResult.routes[nearestRouteResult.routeIndex].file = route.file;\n } else {\n // This is a new child of an existing route, insert it at the beginning of the children array\n // and clip out the parent path from the route path\n let path = route.path?.slice(nearestRouteResult.path.length);\n if (path?.startsWith('/')) {\n path = path.slice(1);\n }\n path = path ? path : undefined;\n if (!nearestRoute.children) {\n nearestRoute.children = [];\n }\n nearestRoute.children.unshift({\n ...route,\n id: routeId,\n path,\n });\n }\n } else {\n // This is a new route, insert it at the beginning of the routes array\n routes.unshift({\n ...route,\n id: routeId,\n });\n }\n }\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { flatRoutes as _flatRoutes } from '@react-router/fs-routes';\nimport type { RouteConfigEntry } from '@react-router/dev/routes';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { mergeRoutes } from './merge-routes';\nimport { applyUrlConfig } from '../multi-site/apply-url-config';\nimport { loadConfig } from '../config/load-config';\nimport type { Url } from '../config/types';\n\nconst APP_SRC_DIR = 'src';\nconst EXTENSIONS_DIR = 'extensions';\n// This file must live at the root of `appDirectory` (src/app-wrapper.tsx) and must NOT\n// be moved into a subdirectory. React Router's typegen resolves route module types using\n// paths relative to `appDirectory` — placing it elsewhere breaks generated type references.\nconst APP_WRAPPER_FILE = 'app-wrapper.tsx';\n\n/**\n * Scans `src/extensions/` for extension route directories and merges any discovered\n * routes into the base route tree. Mutates `routes` in place via `mergeRoutes`.\n */\nasync function discoverExtensionRoutes(ignoredRouteFiles: string[], routes: RouteConfigEntry[]): Promise<void> {\n const extensionsDir = path.join('.', APP_SRC_DIR, EXTENSIONS_DIR);\n\n // Sort to ensure deterministic route order across platforms (readdir order is filesystem-dependent)\n const extensions = await fs.readdir(extensionsDir).then(\n (entries) => entries.sort(),\n () => []\n );\n for (const ext of extensions) {\n // React Router rootDirectory uses forward slashes regardless of OS\n const routesDir = `${EXTENSIONS_DIR}/${ext}/routes`;\n const routesDirFull = path.join('.', APP_SRC_DIR, EXTENSIONS_DIR, ext, 'routes');\n try {\n await fs.access(routesDirFull);\n const extensionRoutes = await _flatRoutes({\n ignoredRouteFiles,\n rootDirectory: routesDir,\n });\n mergeRoutes(routes, extensionRoutes, `${EXTENSIONS_DIR}/${ext}/`);\n } catch {\n // Extension has no routes directory — skip\n }\n }\n}\n\n/**\n * Discovers all file-based routes, merges extension routes, and applies multi-site\n * URL configuration if defined in the project's `config.server.ts`.\n *\n * 1. Discover routes from the filesystem using React Router's `flatRoutes`.\n * 2. Scans `src/extensions/` for extension routes and merges them into the route tree.\n * 3. Load `config.server.ts` from the project root and, if `app.url` is configured,\n * wraps routes under the URL prefix (e.g. `/:siteId/:localeId`).\n *\n * @param options.ignoredRouteFiles - Glob patterns for files to ignore. Defaults to test files.\n * @param options.rootDirectory - Root directory for route discovery, relative to appDirectory.\n * @returns The final route config entries for React Router.\n */\nexport async function flatRoutes(options?: {\n ignoredRouteFiles?: string[];\n rootDirectory?: string;\n}): Promise<RouteConfigEntry[]> {\n const { ignoredRouteFiles = ['**/*.test.{ts,tsx}'], rootDirectory } = options ?? {};\n\n // 1. Discover base routes from filesystem\n const routes = await _flatRoutes({ ignoredRouteFiles, rootDirectory });\n\n // 2. Discover and merge extension routes\n await discoverExtensionRoutes(ignoredRouteFiles, routes);\n\n // 3. Try to load URL config from template's config file\n const { app } = await loadConfig();\n const urlConfig = app?.url as Url | undefined;\n if (urlConfig?.prefix) {\n try {\n await fs.access(path.join('.', APP_SRC_DIR, APP_WRAPPER_FILE));\n } catch {\n throw new Error(\n `[storefront-next-runtime] URL prefix \"${urlConfig.prefix}\" is configured but ` +\n `\"${APP_SRC_DIR}/${APP_WRAPPER_FILE}\" does not exist. ` +\n `Create this file with: export { default } from '@salesforce/storefront-next-runtime/routing/app-wrapper';`\n );\n }\n\n return applyUrlConfig({\n routes,\n urlConfig,\n wrapperFile: APP_WRAPPER_FILE,\n });\n }\n\n return routes;\n}\n"],"mappings":";;;;;;;;;;;;;;AAwBA,SAAS,iBACL,QACA,UACA,WAAmB,IACoD;AACvE,MAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;EACpC,MAAM,QAAQ,OAAO;EACrB,MAAMA,SAAO,MAAM,OAAO,GAAG,SAAS,GAAG,MAAM,SAAS;AACxD,MAAI,MAAM,OAAO,SACb,QAAO;GAAE;GAAQ,YAAY;GAAG;GAAM;AAE1C,MAAI,MAAM,UAAU;GAChB,MAAM,QAAQ,iBAAiB,MAAM,UAAU,UAAUA,OAAK;AAC9D,OAAI,MACA,QAAO;;AAIf,MAAI,MAAM,MAAM,SAAS,WAAW,MAAM,GAAG,CACzC,QAAO;GAAE;GAAQ,YAAY;GAAG;GAAM;;AAG9C,QAAO;;;;;;;;;;;;;;;;AAiBX,SAAgB,YACZ,QACA,iBACA,mBACI;AACJ,MAAK,MAAM,SAAS,iBAAiB;AACjC,MAAI,CAAC,MAAM,IAAI;AACX,UAAO,QAAQ,MAAM;AACrB;;EAEJ,MAAM,UAAU,MAAM,GAAG,QAAQ,mBAAmB,GAAG;EACvD,MAAM,qBAAqB,iBAAiB,QAAQ,QAAQ;AAC5D,MAAI,oBAAoB;GACpB,MAAM,eAAe,mBAAmB,OAAO,mBAAmB;AAClE,OAAI,aAAa,OAAO,QAEpB,oBAAmB,OAAO,mBAAmB,YAAY,OAAO,MAAM;QACnE;IAGH,IAAIA,SAAO,MAAM,MAAM,MAAM,mBAAmB,KAAK,OAAO;AAC5D,QAAIA,QAAM,WAAW,IAAI,CACrB,UAAOA,OAAK,MAAM,EAAE;AAExB,aAAOA,SAAOA,SAAO;AACrB,QAAI,CAAC,aAAa,SACd,cAAa,WAAW,EAAE;AAE9B,iBAAa,SAAS,QAAQ;KAC1B,GAAG;KACH,IAAI;KACJ;KACH,CAAC;;QAIN,QAAO,QAAQ;GACX,GAAG;GACH,IAAI;GACP,CAAC;;;;;;AC9Ed,MAAM,cAAc;AACpB,MAAM,iBAAiB;AAIvB,MAAM,mBAAmB;;;;;AAMzB,eAAe,wBAAwB,mBAA6B,QAA2C;CAC3G,MAAM,gBAAgB,KAAK,KAAK,KAAK,aAAa,eAAe;CAGjE,MAAM,aAAa,MAAM,GAAG,QAAQ,cAAc,CAAC,MAC9C,YAAY,QAAQ,MAAM,QACrB,EAAE,CACX;AACD,MAAK,MAAM,OAAO,YAAY;EAE1B,MAAM,YAAY,GAAG,eAAe,GAAG,IAAI;EAC3C,MAAM,gBAAgB,KAAK,KAAK,KAAK,aAAa,gBAAgB,KAAK,SAAS;AAChF,MAAI;AACA,SAAM,GAAG,OAAO,cAAc;AAK9B,eAAY,QAJY,MAAMC,aAAY;IACtC;IACA,eAAe;IAClB,CAAC,EACmC,GAAG,eAAe,GAAG,IAAI,GAAG;UAC7D;;;;;;;;;;;;;;;;AAmBhB,eAAsB,WAAW,SAGD;CAC5B,MAAM,EAAE,oBAAoB,CAAC,qBAAqB,EAAE,kBAAkB,WAAW,EAAE;CAGnF,MAAM,SAAS,MAAMA,aAAY;EAAE;EAAmB;EAAe,CAAC;AAGtE,OAAM,wBAAwB,mBAAmB,OAAO;CAGxD,MAAM,EAAE,QAAQ,MAAM,YAAY;CAClC,MAAM,YAAY,KAAK;AACvB,KAAI,WAAW,QAAQ;AACnB,MAAI;AACA,SAAM,GAAG,OAAO,KAAK,KAAK,KAAK,aAAa,iBAAiB,CAAC;UAC1D;AACJ,SAAM,IAAI,MACN,yCAAyC,UAAU,OAAO,uBAClD,YAAY,GAAG,iBAAiB,6HAE3C;;AAGL,SAAO,eAAe;GAClB;GACA;GACA,aAAa;GAChB,CAAC;;AAGN,QAAO"}
|
|
1
|
+
{"version":3,"file":"routing.js","names":["path","_flatRoutes"],"sources":["../src/routing/merge-routes.ts","../src/routing/flat-routes.ts"],"sourcesContent":["/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { type RouteConfigEntry } from '@react-router/dev/routes';\n\n/**\n * Find the nearest route by its ID in the route tree\n * @param routes - The route subtree to search\n * @param layoutId - The route ID to find (e.g., \"routes/_app\" or \"routes/_app.account\")\n * @param rootPath - The full route path from the root to the current route (default: '')\n * @returns An object with routes array, routeIndex, and path, or null if not found. Returns exact match if found, otherwise returns route where route.id is a prefix of layoutId\n */\nfunction findNearestRoute(\n routes: RouteConfigEntry[],\n layoutId: string,\n rootPath: string = ''\n): { routes: RouteConfigEntry[]; routeIndex: number; path: string } | null {\n for (let i = 0; i < routes.length; i++) {\n const route = routes[i];\n const path = route.path ? `${rootPath}/${route.path}` : rootPath;\n if (route.id === layoutId) {\n return { routes, routeIndex: i, path };\n }\n if (route.children) {\n const found = findNearestRoute(route.children, layoutId, path);\n if (found) {\n return found;\n }\n }\n // Check if route.id is a prefix of layoutId, indicating a nested route\n if (route.id && layoutId.startsWith(route.id)) {\n return { routes, routeIndex: i, path };\n }\n }\n return null;\n}\n\n/**\n * Merges extension routes into the main routes array, handling route nesting.\n * Routes without IDs are added directly to the routes array. Routes with IDs are processed\n * to remove the extension prefix and are either:\n * - Added as children of existing routes (if a nearest route is found via prefix matching)\n * - Replace existing routes (if an exact match is found)\n * - Added directly to the routes array (if no matching route exists)\n *\n * When adding as a child, the parent route's path is clipped from the child route's path.\n *\n * @param routes - The main routes array to merge into (mutated in place)\n * @param extensionRoutes - The extension routes to merge\n * @param extensionIdPrefix - The prefix to remove from extension route IDs (e.g., \"extensions/store-locator/\")\n */\nexport function mergeRoutes(\n routes: RouteConfigEntry[],\n extensionRoutes: RouteConfigEntry[],\n extensionIdPrefix: string\n): void {\n for (const route of extensionRoutes) {\n if (!route.id) {\n routes.unshift(route);\n continue;\n }\n const routeId = route.id.replace(extensionIdPrefix, '');\n const nearestRouteResult = findNearestRoute(routes, routeId);\n if (nearestRouteResult) {\n const nearestRoute = nearestRouteResult.routes[nearestRouteResult.routeIndex];\n if (nearestRoute.id === routeId) {\n // Replacing an existing route, we assume we can just swap out the implementation\n nearestRouteResult.routes[nearestRouteResult.routeIndex].file = route.file;\n } else {\n // This is a new child of an existing route, insert it at the beginning of the children array\n // and clip out the parent path from the route path\n let path = route.path?.slice(nearestRouteResult.path.length);\n if (path?.startsWith('/')) {\n path = path.slice(1);\n }\n path = path ? path : undefined;\n if (!nearestRoute.children) {\n nearestRoute.children = [];\n }\n nearestRoute.children.unshift({\n ...route,\n id: routeId,\n path,\n });\n }\n } else {\n // This is a new route, insert it at the beginning of the routes array\n routes.unshift({\n ...route,\n id: routeId,\n });\n }\n }\n}\n","/**\n * Copyright 2026 Salesforce, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { flatRoutes as _flatRoutes } from '@react-router/fs-routes';\nimport type { RouteConfigEntry } from '@react-router/dev/routes';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { mergeRoutes } from './merge-routes';\nimport { applyUrlConfig } from '../site-context/apply-url-config';\nimport { loadConfig } from '../config/load-config';\nimport type { Url } from '../config/types';\n\nconst APP_SRC_DIR = 'src';\nconst EXTENSIONS_DIR = 'extensions';\n// This file must live at the root of `appDirectory` (src/app-wrapper.tsx) and must NOT\n// be moved into a subdirectory. React Router's typegen resolves route module types using\n// paths relative to `appDirectory` — placing it elsewhere breaks generated type references.\nconst APP_WRAPPER_FILE = 'app-wrapper.tsx';\n\n/**\n * Scans `src/extensions/` for extension route directories and merges any discovered\n * routes into the base route tree. Mutates `routes` in place via `mergeRoutes`.\n */\nasync function discoverExtensionRoutes(ignoredRouteFiles: string[], routes: RouteConfigEntry[]): Promise<void> {\n const extensionsDir = path.join('.', APP_SRC_DIR, EXTENSIONS_DIR);\n\n // Sort to ensure deterministic route order across platforms (readdir order is filesystem-dependent)\n const extensions = await fs.readdir(extensionsDir).then(\n (entries) => entries.sort(),\n () => []\n );\n for (const ext of extensions) {\n // React Router rootDirectory uses forward slashes regardless of OS\n const routesDir = `${EXTENSIONS_DIR}/${ext}/routes`;\n const routesDirFull = path.join('.', APP_SRC_DIR, EXTENSIONS_DIR, ext, 'routes');\n try {\n await fs.access(routesDirFull);\n const extensionRoutes = await _flatRoutes({\n ignoredRouteFiles,\n rootDirectory: routesDir,\n });\n mergeRoutes(routes, extensionRoutes, `${EXTENSIONS_DIR}/${ext}/`);\n } catch {\n // Extension has no routes directory — skip\n }\n }\n}\n\n/**\n * Discovers all file-based routes, merges extension routes, and applies site context\n * URL configuration if defined in the project's `config.server.ts`.\n *\n * 1. Discover routes from the filesystem using React Router's `flatRoutes`.\n * 2. Scans `src/extensions/` for extension routes and merges them into the route tree.\n * 3. Load `config.server.ts` from the project root and, if `app.url` is configured,\n * wraps routes under the URL prefix (e.g. `/:siteId/:localeId`).\n *\n * @param options.ignoredRouteFiles - Glob patterns for files to ignore. Defaults to test files.\n * @param options.rootDirectory - Root directory for route discovery, relative to appDirectory.\n * @returns The final route config entries for React Router.\n */\nexport async function flatRoutes(options?: {\n ignoredRouteFiles?: string[];\n rootDirectory?: string;\n}): Promise<RouteConfigEntry[]> {\n const { ignoredRouteFiles = ['**/*.test.{ts,tsx}'], rootDirectory } = options ?? {};\n\n // 1. Discover base routes from filesystem\n const routes = await _flatRoutes({ ignoredRouteFiles, rootDirectory });\n\n // 2. Discover and merge extension routes\n await discoverExtensionRoutes(ignoredRouteFiles, routes);\n\n // 3. Try to load URL config from template's config file\n const { app } = await loadConfig();\n const urlConfig = app?.url as Url | undefined;\n if (urlConfig?.prefix) {\n try {\n await fs.access(path.join('.', APP_SRC_DIR, APP_WRAPPER_FILE));\n } catch {\n throw new Error(\n `[storefront-next-runtime] URL prefix \"${urlConfig.prefix}\" is configured but ` +\n `\"${APP_SRC_DIR}/${APP_WRAPPER_FILE}\" does not exist. ` +\n `Create this file with: export { default } from '@salesforce/storefront-next-runtime/routing/app-wrapper';`\n );\n }\n\n return applyUrlConfig({\n routes,\n urlConfig,\n wrapperFile: APP_WRAPPER_FILE,\n });\n }\n\n return routes;\n}\n"],"mappings":";;;;;;;;;;;;;;AAwBA,SAAS,iBACL,QACA,UACA,WAAmB,IACoD;AACvE,MAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;EACpC,MAAM,QAAQ,OAAO;EACrB,MAAMA,SAAO,MAAM,OAAO,GAAG,SAAS,GAAG,MAAM,SAAS;AACxD,MAAI,MAAM,OAAO,SACb,QAAO;GAAE;GAAQ,YAAY;GAAG;GAAM;AAE1C,MAAI,MAAM,UAAU;GAChB,MAAM,QAAQ,iBAAiB,MAAM,UAAU,UAAUA,OAAK;AAC9D,OAAI,MACA,QAAO;;AAIf,MAAI,MAAM,MAAM,SAAS,WAAW,MAAM,GAAG,CACzC,QAAO;GAAE;GAAQ,YAAY;GAAG;GAAM;;AAG9C,QAAO;;;;;;;;;;;;;;;;AAiBX,SAAgB,YACZ,QACA,iBACA,mBACI;AACJ,MAAK,MAAM,SAAS,iBAAiB;AACjC,MAAI,CAAC,MAAM,IAAI;AACX,UAAO,QAAQ,MAAM;AACrB;;EAEJ,MAAM,UAAU,MAAM,GAAG,QAAQ,mBAAmB,GAAG;EACvD,MAAM,qBAAqB,iBAAiB,QAAQ,QAAQ;AAC5D,MAAI,oBAAoB;GACpB,MAAM,eAAe,mBAAmB,OAAO,mBAAmB;AAClE,OAAI,aAAa,OAAO,QAEpB,oBAAmB,OAAO,mBAAmB,YAAY,OAAO,MAAM;QACnE;IAGH,IAAIA,SAAO,MAAM,MAAM,MAAM,mBAAmB,KAAK,OAAO;AAC5D,QAAIA,QAAM,WAAW,IAAI,CACrB,UAAOA,OAAK,MAAM,EAAE;AAExB,aAAOA,SAAOA,SAAO;AACrB,QAAI,CAAC,aAAa,SACd,cAAa,WAAW,EAAE;AAE9B,iBAAa,SAAS,QAAQ;KAC1B,GAAG;KACH,IAAI;KACJ;KACH,CAAC;;QAIN,QAAO,QAAQ;GACX,GAAG;GACH,IAAI;GACP,CAAC;;;;;;AC9Ed,MAAM,cAAc;AACpB,MAAM,iBAAiB;AAIvB,MAAM,mBAAmB;;;;;AAMzB,eAAe,wBAAwB,mBAA6B,QAA2C;CAC3G,MAAM,gBAAgB,KAAK,KAAK,KAAK,aAAa,eAAe;CAGjE,MAAM,aAAa,MAAM,GAAG,QAAQ,cAAc,CAAC,MAC9C,YAAY,QAAQ,MAAM,QACrB,EAAE,CACX;AACD,MAAK,MAAM,OAAO,YAAY;EAE1B,MAAM,YAAY,GAAG,eAAe,GAAG,IAAI;EAC3C,MAAM,gBAAgB,KAAK,KAAK,KAAK,aAAa,gBAAgB,KAAK,SAAS;AAChF,MAAI;AACA,SAAM,GAAG,OAAO,cAAc;AAK9B,eAAY,QAJY,MAAMC,aAAY;IACtC;IACA,eAAe;IAClB,CAAC,EACmC,GAAG,eAAe,GAAG,IAAI,GAAG;UAC7D;;;;;;;;;;;;;;;;AAmBhB,eAAsB,WAAW,SAGD;CAC5B,MAAM,EAAE,oBAAoB,CAAC,qBAAqB,EAAE,kBAAkB,WAAW,EAAE;CAGnF,MAAM,SAAS,MAAMA,aAAY;EAAE;EAAmB;EAAe,CAAC;AAGtE,OAAM,wBAAwB,mBAAmB,OAAO;CAGxD,MAAM,EAAE,QAAQ,MAAM,YAAY;CAClC,MAAM,YAAY,KAAK;AACvB,KAAI,WAAW,QAAQ;AACnB,MAAI;AACA,SAAM,GAAG,OAAO,KAAK,KAAK,KAAK,aAAa,iBAAiB,CAAC;UAC1D;AACJ,SAAM,IAAI,MACN,yCAAyC,UAAU,OAAO,uBAClD,YAAY,GAAG,iBAAiB,6HAE3C;;AAGL,SAAO,eAAe;GAClB;GACA;GACA,aAAa;GAChB,CAAC;;AAGN,QAAO"}
|