@salesforce/storefront-next-runtime 0.1.1-alpha.0 → 0.2.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/DesignComponent.js +150 -0
- package/dist/DesignComponent.js.map +1 -0
- package/dist/DesignFrame.js +196 -0
- package/dist/DesignFrame.js.map +1 -0
- package/dist/DesignRegion.js +83 -0
- package/dist/DesignRegion.js.map +1 -0
- package/dist/apply-url-config.js +130 -0
- package/dist/apply-url-config.js.map +1 -0
- package/dist/component.types.d.ts +87 -0
- package/dist/component.types.d.ts.map +1 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.js +0 -0
- package/dist/design-data.d.ts +983 -0
- package/dist/design-data.d.ts.map +1 -0
- package/dist/design-data.js +908 -0
- package/dist/design-data.js.map +1 -0
- package/dist/design-messaging.d.ts +2 -2
- package/dist/design-react-core.d.ts +50 -5
- package/dist/design-react-core.d.ts.map +1 -1
- package/dist/design-react-core.js +81 -2
- package/dist/design-react-core.js.map +1 -1
- package/dist/design-react.d.ts +20 -95
- package/dist/design-react.d.ts.map +1 -1
- package/dist/design-react.js +3 -485
- package/dist/design-styles.css +2 -1
- package/dist/design.d.ts +110 -2
- package/dist/design.d.ts.map +1 -0
- package/dist/events.d.ts +1 -1
- package/dist/index.d.ts +1110 -154
- package/dist/index.d.ts.map +1 -1
- package/dist/multi-site.d.ts +154 -0
- package/dist/multi-site.d.ts.map +1 -0
- package/dist/multi-site.js +393 -0
- package/dist/multi-site.js.map +1 -0
- package/dist/routing-app-wrapper.d.ts +18 -0
- package/dist/routing-app-wrapper.d.ts.map +1 -0
- package/dist/routing-app-wrapper.js +21 -0
- package/dist/routing-app-wrapper.js.map +1 -0
- package/dist/routing.d.ts +42 -0
- package/dist/routing.d.ts.map +1 -0
- package/dist/routing.js +171 -0
- package/dist/routing.js.map +1 -0
- package/dist/scapi.d.ts +69 -5
- package/dist/scapi.d.ts.map +1 -1
- package/dist/scapi.js +1 -1
- package/dist/scapi.js.map +1 -1
- package/dist/types.d.ts +40 -13289
- package/dist/types.d.ts.map +1 -1
- package/dist/types2.d.ts +13293 -0
- package/dist/types2.d.ts.map +1 -0
- package/dist/types3.d.ts +110 -0
- package/dist/types3.d.ts.map +1 -0
- package/dist/workspace.d.ts +46 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +52 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +44 -2
- package/dist/design-react.js.map +0 -1
- package/dist/index2.d.ts +0 -1171
- package/dist/index2.d.ts.map +0 -1
- /package/{LICENSE.txt → LICENSE} +0 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
2
|
+
|
|
3
|
+
//#region src/routing/app-wrapper.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A pass-through wrapper component that renders an `<Outlet />`.
|
|
7
|
+
*
|
|
8
|
+
* Used as the parent route component when URL configuration wraps routes under
|
|
9
|
+
* a prefix (e.g. `/:siteId/:localeId`). React Router requires a component for
|
|
10
|
+
* every route entry — this satisfies that requirement without adding any UI.
|
|
11
|
+
*
|
|
12
|
+
* Customers re-export this from their own `routes/app-wrapper.tsx` so the file
|
|
13
|
+
* lives inside `appDirectory` and React Router generates correct type references.
|
|
14
|
+
*/
|
|
15
|
+
declare function AppWrapper(): react_jsx_runtime0.JSX.Element;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { AppWrapper as default };
|
|
18
|
+
//# sourceMappingURL=routing-app-wrapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routing-app-wrapper.d.ts","names":[],"sources":["../src/routing/app-wrapper.tsx"],"sourcesContent":[],"mappings":";;;;;;;AA2BkC;;;;;;;iBAAV,UAAA,CAAA,GAAU,kBAAA,CAAA,GAAA,CAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Outlet } from "react-router";
|
|
3
|
+
|
|
4
|
+
//#region src/routing/app-wrapper.tsx
|
|
5
|
+
/**
|
|
6
|
+
* A pass-through wrapper component that renders an `<Outlet />`.
|
|
7
|
+
*
|
|
8
|
+
* Used as the parent route component when URL configuration wraps routes under
|
|
9
|
+
* a prefix (e.g. `/:siteId/:localeId`). React Router requires a component for
|
|
10
|
+
* every route entry — this satisfies that requirement without adding any UI.
|
|
11
|
+
*
|
|
12
|
+
* Customers re-export this from their own `routes/app-wrapper.tsx` so the file
|
|
13
|
+
* lives inside `appDirectory` and React Router generates correct type references.
|
|
14
|
+
*/
|
|
15
|
+
function AppWrapper() {
|
|
16
|
+
return /* @__PURE__ */ jsx(Outlet, {});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
//#endregion
|
|
20
|
+
export { AppWrapper as default };
|
|
21
|
+
//# sourceMappingURL=routing-app-wrapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routing-app-wrapper.js","names":[],"sources":["../src/routing/app-wrapper.tsx"],"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 { Outlet } from 'react-router';\n\n/**\n * A pass-through wrapper component that renders an `<Outlet />`.\n *\n * Used as the parent route component when URL configuration wraps routes under\n * a prefix (e.g. `/:siteId/:localeId`). React Router requires a component for\n * every route entry — this satisfies that requirement without adding any UI.\n *\n * Customers re-export this from their own `routes/app-wrapper.tsx` so the file\n * lives inside `appDirectory` and React Router generates correct type references.\n */\nexport default function AppWrapper() {\n return <Outlet />;\n}\n"],"mappings":";;;;;;;;;;;;;;AA2BA,SAAwB,aAAa;AACjC,QAAO,oBAAC,WAAS"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { RouteConfigEntry } from "@react-router/dev/routes";
|
|
2
|
+
|
|
3
|
+
//#region src/routing/flat-routes.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Discovers all file-based routes, merges extension routes, and applies multi-site
|
|
7
|
+
* URL configuration if defined in the project's `config.server.ts`.
|
|
8
|
+
*
|
|
9
|
+
* 1. Discover routes from the filesystem using React Router's `flatRoutes`.
|
|
10
|
+
* 2. Scans `src/extensions/` for extension routes and merges them into the route tree.
|
|
11
|
+
* 3. Load `config.server.ts` from the project root and, if `app.url` is configured,
|
|
12
|
+
* wraps routes under the URL prefix (e.g. `/:siteId/:localeId`).
|
|
13
|
+
*
|
|
14
|
+
* @param options.ignoredRouteFiles - Glob patterns for files to ignore. Defaults to test files.
|
|
15
|
+
* @param options.rootDirectory - Root directory for route discovery, relative to appDirectory.
|
|
16
|
+
* @returns The final route config entries for React Router.
|
|
17
|
+
*/
|
|
18
|
+
declare function flatRoutes(options?: {
|
|
19
|
+
ignoredRouteFiles?: string[];
|
|
20
|
+
rootDirectory?: string;
|
|
21
|
+
}): Promise<RouteConfigEntry[]>;
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/routing/merge-routes.d.ts
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Merges extension routes into the main routes array, handling route nesting.
|
|
27
|
+
* Routes without IDs are added directly to the routes array. Routes with IDs are processed
|
|
28
|
+
* to remove the extension prefix and are either:
|
|
29
|
+
* - Added as children of existing routes (if a nearest route is found via prefix matching)
|
|
30
|
+
* - Replace existing routes (if an exact match is found)
|
|
31
|
+
* - Added directly to the routes array (if no matching route exists)
|
|
32
|
+
*
|
|
33
|
+
* When adding as a child, the parent route's path is clipped from the child route's path.
|
|
34
|
+
*
|
|
35
|
+
* @param routes - The main routes array to merge into (mutated in place)
|
|
36
|
+
* @param extensionRoutes - The extension routes to merge
|
|
37
|
+
* @param extensionIdPrefix - The prefix to remove from extension route IDs (e.g., "extensions/store-locator/")
|
|
38
|
+
*/
|
|
39
|
+
declare function mergeRoutes(routes: RouteConfigEntry[], extensionRoutes: RouteConfigEntry[], extensionIdPrefix: string): void;
|
|
40
|
+
//#endregion
|
|
41
|
+
export { flatRoutes, mergeRoutes };
|
|
42
|
+
//# sourceMappingURL=routing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routing.d.ts","names":[],"sources":["../src/routing/flat-routes.ts","../src/routing/merge-routes.ts"],"sourcesContent":[],"mappings":";;;;;;AAwEA;;;;ACTA;;;;;;;iBDSsB,UAAA;;;IAGlB,QAAQ;;;;;;;;;;;;;;;;;;iBCZI,WAAA,SACJ,qCACS"}
|
package/dist/routing.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { t as applyUrlConfig } from "./apply-url-config.js";
|
|
2
|
+
import { flatRoutes as flatRoutes$1 } from "@react-router/fs-routes";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import fs$1 from "node:fs";
|
|
6
|
+
import { pathToFileURL } from "node:url";
|
|
7
|
+
|
|
8
|
+
//#region src/routing/merge-routes.ts
|
|
9
|
+
/**
|
|
10
|
+
* Find the nearest route by its ID in the route tree
|
|
11
|
+
* @param routes - The route subtree to search
|
|
12
|
+
* @param layoutId - The route ID to find (e.g., "routes/_app" or "routes/_app.account")
|
|
13
|
+
* @param rootPath - The full route path from the root to the current route (default: '')
|
|
14
|
+
* @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
|
|
15
|
+
*/
|
|
16
|
+
function findNearestRoute(routes, layoutId, rootPath = "") {
|
|
17
|
+
for (let i = 0; i < routes.length; i++) {
|
|
18
|
+
const route = routes[i];
|
|
19
|
+
const path$1 = route.path ? `${rootPath}/${route.path}` : rootPath;
|
|
20
|
+
if (route.id === layoutId) return {
|
|
21
|
+
routes,
|
|
22
|
+
routeIndex: i,
|
|
23
|
+
path: path$1
|
|
24
|
+
};
|
|
25
|
+
if (route.children) {
|
|
26
|
+
const found = findNearestRoute(route.children, layoutId, path$1);
|
|
27
|
+
if (found) return found;
|
|
28
|
+
}
|
|
29
|
+
if (route.id && layoutId.startsWith(route.id)) return {
|
|
30
|
+
routes,
|
|
31
|
+
routeIndex: i,
|
|
32
|
+
path: path$1
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Merges extension routes into the main routes array, handling route nesting.
|
|
39
|
+
* Routes without IDs are added directly to the routes array. Routes with IDs are processed
|
|
40
|
+
* to remove the extension prefix and are either:
|
|
41
|
+
* - Added as children of existing routes (if a nearest route is found via prefix matching)
|
|
42
|
+
* - Replace existing routes (if an exact match is found)
|
|
43
|
+
* - Added directly to the routes array (if no matching route exists)
|
|
44
|
+
*
|
|
45
|
+
* When adding as a child, the parent route's path is clipped from the child route's path.
|
|
46
|
+
*
|
|
47
|
+
* @param routes - The main routes array to merge into (mutated in place)
|
|
48
|
+
* @param extensionRoutes - The extension routes to merge
|
|
49
|
+
* @param extensionIdPrefix - The prefix to remove from extension route IDs (e.g., "extensions/store-locator/")
|
|
50
|
+
*/
|
|
51
|
+
function mergeRoutes(routes, extensionRoutes, extensionIdPrefix) {
|
|
52
|
+
for (const route of extensionRoutes) {
|
|
53
|
+
if (!route.id) {
|
|
54
|
+
routes.unshift(route);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const routeId = route.id.replace(extensionIdPrefix, "");
|
|
58
|
+
const nearestRouteResult = findNearestRoute(routes, routeId);
|
|
59
|
+
if (nearestRouteResult) {
|
|
60
|
+
const nearestRoute = nearestRouteResult.routes[nearestRouteResult.routeIndex];
|
|
61
|
+
if (nearestRoute.id === routeId) nearestRouteResult.routes[nearestRouteResult.routeIndex].file = route.file;
|
|
62
|
+
else {
|
|
63
|
+
let path$1 = route.path?.slice(nearestRouteResult.path.length);
|
|
64
|
+
if (path$1?.startsWith("/")) path$1 = path$1.slice(1);
|
|
65
|
+
path$1 = path$1 ? path$1 : void 0;
|
|
66
|
+
if (!nearestRoute.children) nearestRoute.children = [];
|
|
67
|
+
nearestRoute.children.unshift({
|
|
68
|
+
...route,
|
|
69
|
+
id: routeId,
|
|
70
|
+
path: path$1
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
} else routes.unshift({
|
|
74
|
+
...route,
|
|
75
|
+
id: routeId
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
//#endregion
|
|
81
|
+
//#region src/config/load-config.ts
|
|
82
|
+
/**
|
|
83
|
+
* Dynamically imports `config.server.ts` from the project root (CWD) and returns
|
|
84
|
+
* the `app` configuration object. This runs at route discovery time under vite-node
|
|
85
|
+
* (typegen, dev, build), which handles the TS transformation.
|
|
86
|
+
*
|
|
87
|
+
* - If the config file is missing, warns and returns an empty config.
|
|
88
|
+
* - If the config file exists but fails to import, throws with the original error as cause.
|
|
89
|
+
*
|
|
90
|
+
* @returns The `app` configuration object, or an empty object if not available.
|
|
91
|
+
*/
|
|
92
|
+
async function loadConfig() {
|
|
93
|
+
const configPath = path.resolve(process.cwd(), "config.server.ts");
|
|
94
|
+
if (!fs$1.existsSync(configPath)) {
|
|
95
|
+
console.warn(`[storefront-next-runtime] config.server.ts not found at ${configPath}. Returning empty config.`);
|
|
96
|
+
return {};
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
const mod = await import(
|
|
100
|
+
/* @vite-ignore */
|
|
101
|
+
pathToFileURL(configPath).href
|
|
102
|
+
);
|
|
103
|
+
return (mod.default ?? mod)?.app ?? {};
|
|
104
|
+
} catch (error) {
|
|
105
|
+
throw new Error(`[storefront-next-runtime] Found config.server.ts at ${configPath} but failed to import it.`, { cause: error });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region src/routing/flat-routes.ts
|
|
111
|
+
const APP_SRC_DIR = "src";
|
|
112
|
+
const EXTENSIONS_DIR = "extensions";
|
|
113
|
+
const APP_WRAPPER_FILE = "app-wrapper.tsx";
|
|
114
|
+
/**
|
|
115
|
+
* Scans `src/extensions/` for extension route directories and merges any discovered
|
|
116
|
+
* routes into the base route tree. Mutates `routes` in place via `mergeRoutes`.
|
|
117
|
+
*/
|
|
118
|
+
async function discoverExtensionRoutes(ignoredRouteFiles, routes) {
|
|
119
|
+
const extensionsDir = path.join(".", APP_SRC_DIR, EXTENSIONS_DIR);
|
|
120
|
+
const extensions = await fs.readdir(extensionsDir).then((entries) => entries.sort(), () => []);
|
|
121
|
+
for (const ext of extensions) {
|
|
122
|
+
const routesDir = `${EXTENSIONS_DIR}/${ext}/routes`;
|
|
123
|
+
const routesDirFull = path.join(".", APP_SRC_DIR, EXTENSIONS_DIR, ext, "routes");
|
|
124
|
+
try {
|
|
125
|
+
await fs.access(routesDirFull);
|
|
126
|
+
mergeRoutes(routes, await flatRoutes$1({
|
|
127
|
+
ignoredRouteFiles,
|
|
128
|
+
rootDirectory: routesDir
|
|
129
|
+
}), `${EXTENSIONS_DIR}/${ext}/`);
|
|
130
|
+
} catch {}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Discovers all file-based routes, merges extension routes, and applies multi-site
|
|
135
|
+
* URL configuration if defined in the project's `config.server.ts`.
|
|
136
|
+
*
|
|
137
|
+
* 1. Discover routes from the filesystem using React Router's `flatRoutes`.
|
|
138
|
+
* 2. Scans `src/extensions/` for extension routes and merges them into the route tree.
|
|
139
|
+
* 3. Load `config.server.ts` from the project root and, if `app.url` is configured,
|
|
140
|
+
* wraps routes under the URL prefix (e.g. `/:siteId/:localeId`).
|
|
141
|
+
*
|
|
142
|
+
* @param options.ignoredRouteFiles - Glob patterns for files to ignore. Defaults to test files.
|
|
143
|
+
* @param options.rootDirectory - Root directory for route discovery, relative to appDirectory.
|
|
144
|
+
* @returns The final route config entries for React Router.
|
|
145
|
+
*/
|
|
146
|
+
async function flatRoutes(options) {
|
|
147
|
+
const { ignoredRouteFiles = ["**/*.test.{ts,tsx}"], rootDirectory } = options ?? {};
|
|
148
|
+
const routes = await flatRoutes$1({
|
|
149
|
+
ignoredRouteFiles,
|
|
150
|
+
rootDirectory
|
|
151
|
+
});
|
|
152
|
+
await discoverExtensionRoutes(ignoredRouteFiles, routes);
|
|
153
|
+
const { url: urlConfig } = await loadConfig();
|
|
154
|
+
if (urlConfig?.prefix) {
|
|
155
|
+
try {
|
|
156
|
+
await fs.access(path.join(".", APP_SRC_DIR, APP_WRAPPER_FILE));
|
|
157
|
+
} catch {
|
|
158
|
+
throw new Error(`[storefront-next-runtime] URL prefix "${urlConfig.prefix}" is configured but "${APP_SRC_DIR}/${APP_WRAPPER_FILE}" does not exist. Create this file with: export { default } from '@salesforce/storefront-next-runtime/routing/app-wrapper';`);
|
|
159
|
+
}
|
|
160
|
+
return applyUrlConfig({
|
|
161
|
+
routes,
|
|
162
|
+
urlConfig,
|
|
163
|
+
wrapperFile: APP_WRAPPER_FILE
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
return routes;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
//#endregion
|
|
170
|
+
export { flatRoutes, mergeRoutes };
|
|
171
|
+
//# sourceMappingURL=routing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routing.js","names":["path","fs","_flatRoutes"],"sources":["../src/routing/merge-routes.ts","../src/config/load-config.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 fs from 'node:fs';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\n/**\n * Dynamically imports `config.server.ts` from the project root (CWD) and returns\n * the `app` configuration object. This runs at route discovery time under vite-node\n * (typegen, dev, build), which handles the TS transformation.\n *\n * - If the config file is missing, warns and returns an empty config.\n * - If the config file exists but fails to import, throws with the original error as cause.\n *\n * @returns The `app` configuration object, or an empty object if not available.\n */\n// TODO: add a proper type when config schema is moved to runtime from the template\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function loadConfig(): Promise<Record<string, any>> {\n const configPath = path.resolve(process.cwd(), 'config.server.ts');\n\n if (!fs.existsSync(configPath)) {\n console.warn(\n `[storefront-next-runtime] config.server.ts not found at ${configPath}. ` + `Returning empty config.`\n );\n return {};\n }\n\n try {\n // The @vite-ignore comment suppresses Vite's \"dynamic import cannot be analyzed\" warning.\n // It must be placed on the variable value (not inside import()) so that rolldown's\n // single-use variable inlining carries it into the import() expression in the built output.\n // See: https://github.com/nicolo-ribaudo/rolldown/issues/6263\n const importPath = /* @vite-ignore */ pathToFileURL(configPath).href;\n\n const mod = await import(importPath);\n const config = mod.default ?? mod;\n return config?.app ?? {};\n } catch (error) {\n throw new Error(`[storefront-next-runtime] Found config.server.ts at ${configPath} but failed to import it.`, {\n cause: error,\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';\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 { url: urlConfig } = await loadConfig();\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":"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"}
|
package/dist/scapi.d.ts
CHANGED
|
@@ -27805,6 +27805,8 @@ interface AuthConfig {
|
|
|
27805
27805
|
siteId: string;
|
|
27806
27806
|
/** Base URL for Commerce API (e.g., 'https://{shortCode}.api.commercecloud.salesforce.com') */
|
|
27807
27807
|
baseUrl: string;
|
|
27808
|
+
/** Direct SCAPI proxy URL for workspace environments. When set, guest login uses client_credentials grant directly. */
|
|
27809
|
+
proxyHost?: string;
|
|
27808
27810
|
}
|
|
27809
27811
|
/**
|
|
27810
27812
|
* Options for guest login.
|
|
@@ -27846,6 +27848,13 @@ interface LogoutOptions {
|
|
|
27846
27848
|
/** The current refresh token */
|
|
27847
27849
|
refreshToken: string;
|
|
27848
27850
|
}
|
|
27851
|
+
/**
|
|
27852
|
+
* Delivery modes for passwordless login and password reset.
|
|
27853
|
+
* - 'callback': SLAS calls your callback URL with the token (requires Marketing Cloud for email)
|
|
27854
|
+
* - 'sms': SLAS sends an SMS with the code directly
|
|
27855
|
+
* - 'email': SLAS sends an email with the OTP code directly (no Marketing Cloud needed)
|
|
27856
|
+
*/
|
|
27857
|
+
type PasswordActionMode = 'callback' | 'sms' | 'email';
|
|
27849
27858
|
/**
|
|
27850
27859
|
* Options for initiating passwordless login.
|
|
27851
27860
|
*/
|
|
@@ -27856,8 +27865,22 @@ interface PasswordlessAuthorizeOptions {
|
|
|
27856
27865
|
callbackUri?: string;
|
|
27857
27866
|
/** Unique Shopper Identifier to link to a previous session */
|
|
27858
27867
|
usid?: string;
|
|
27859
|
-
/**
|
|
27860
|
-
mode
|
|
27868
|
+
/** Method to receive OTP */
|
|
27869
|
+
mode: PasswordActionMode;
|
|
27870
|
+
/** Locale of the template */
|
|
27871
|
+
locale?: string;
|
|
27872
|
+
/** When true, creates a new customer profile if one doesn't exist */
|
|
27873
|
+
registerCustomer?: boolean;
|
|
27874
|
+
/** User's last name (required when registerCustomer is true) */
|
|
27875
|
+
lastName?: string;
|
|
27876
|
+
/** User's email address (required when registerCustomer is true and userId is not an email) */
|
|
27877
|
+
email?: string;
|
|
27878
|
+
/** User's first name (optional when registerCustomer is true) */
|
|
27879
|
+
firstName?: string;
|
|
27880
|
+
/** User's phone number (optional when registerCustomer is true) */
|
|
27881
|
+
phoneNumber?: string;
|
|
27882
|
+
/** Customer number to assign (optional when registerCustomer is true) */
|
|
27883
|
+
customerNo?: string;
|
|
27861
27884
|
}
|
|
27862
27885
|
/**
|
|
27863
27886
|
* Options for exchanging a passwordless login token for access tokens.
|
|
@@ -27877,7 +27900,11 @@ interface PasswordRequestResetOptions {
|
|
|
27877
27900
|
/** User's email address */
|
|
27878
27901
|
userId: string;
|
|
27879
27902
|
/** Callback URI for the password reset link */
|
|
27880
|
-
callbackUri
|
|
27903
|
+
callbackUri?: string;
|
|
27904
|
+
/** Locale of the template */
|
|
27905
|
+
locale?: string;
|
|
27906
|
+
/** Method to receive OTP */
|
|
27907
|
+
mode: PasswordActionMode;
|
|
27881
27908
|
}
|
|
27882
27909
|
/**
|
|
27883
27910
|
* Options for resetting a password with a token.
|
|
@@ -29016,6 +29043,16 @@ interface CommerceApiClientConfig extends ClientOptions {
|
|
|
29016
29043
|
clientSecret?: string;
|
|
29017
29044
|
/** OAuth redirect URI - must be registered in SLAS configuration */
|
|
29018
29045
|
redirectUri: string;
|
|
29046
|
+
/** Optional callback when access token is invalidated */
|
|
29047
|
+
onAuthTokenInvalid?: (response: Response) => void;
|
|
29048
|
+
/**
|
|
29049
|
+
* Direct SCAPI proxy URL for workspace environments (e.g., 'https://scw:25010').
|
|
29050
|
+
* When set, the SDK automatically:
|
|
29051
|
+
* - Strips 'f_ecom_' prefix from organizationId for SLAS auth endpoints
|
|
29052
|
+
* - Rewrites org IDs back to full form for product/search API endpoints
|
|
29053
|
+
* - Uses client_credentials grant for guest login (no PKCE)
|
|
29054
|
+
*/
|
|
29055
|
+
proxyHost?: string;
|
|
29019
29056
|
}
|
|
29020
29057
|
type Clients = {
|
|
29021
29058
|
shopperBasketsV1: ProxyClient<Client<ShopperBasketsV1.endpoints>, typeof operations>;
|
|
@@ -29043,6 +29080,13 @@ type Clients = {
|
|
|
29043
29080
|
declare function createCommerceApiClients(config: CommerceApiClientConfig): Clients;
|
|
29044
29081
|
//#endregion
|
|
29045
29082
|
//#region src/scapi-client/createClient.d.ts
|
|
29083
|
+
/**
|
|
29084
|
+
* Optional hooks for client behavior.
|
|
29085
|
+
*/
|
|
29086
|
+
interface CreateClientOptions {
|
|
29087
|
+
/** Callback invoked when an auth token is deemed invalid */
|
|
29088
|
+
onAuthTokenInvalid?: (response: Response) => void;
|
|
29089
|
+
}
|
|
29046
29090
|
/**
|
|
29047
29091
|
* Global request parameters that are automatically merged into every API call.
|
|
29048
29092
|
*
|
|
@@ -29109,7 +29153,7 @@ interface GlobalRequestParameters {
|
|
|
29109
29153
|
* });
|
|
29110
29154
|
* ```
|
|
29111
29155
|
*/
|
|
29112
|
-
declare function createClient<TClient extends Client<any, any>, TOperations extends OperationMap>(client: TClient, operations: TOperations, globalParams?: GlobalRequestParameters): ProxyClient<TClient, TOperations>;
|
|
29156
|
+
declare function createClient<TClient extends Client<any, any>, TOperations extends OperationMap>(client: TClient, operations: TOperations, globalParams?: GlobalRequestParameters, options?: CreateClientOptions): ProxyClient<TClient, TOperations>;
|
|
29113
29157
|
//#endregion
|
|
29114
29158
|
//#region src/scapi-client/ApiError.d.ts
|
|
29115
29159
|
/**
|
|
@@ -29240,6 +29284,26 @@ declare class ApiError extends Error {
|
|
|
29240
29284
|
};
|
|
29241
29285
|
}
|
|
29242
29286
|
//#endregion
|
|
29287
|
+
//#region src/scapi-client/AuthTokenInvalidError.d.ts
|
|
29288
|
+
/**
|
|
29289
|
+
* Copyright 2026 Salesforce, Inc.
|
|
29290
|
+
*
|
|
29291
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
29292
|
+
* you may not use this file except in compliance with the License.
|
|
29293
|
+
* You may obtain a copy of the License at
|
|
29294
|
+
*
|
|
29295
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
29296
|
+
*
|
|
29297
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
29298
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
29299
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
29300
|
+
* See the License for the specific language governing permissions and
|
|
29301
|
+
* limitations under the License.
|
|
29302
|
+
*/
|
|
29303
|
+
declare class AuthTokenInvalidError extends Error {
|
|
29304
|
+
constructor(message?: string);
|
|
29305
|
+
}
|
|
29306
|
+
//#endregion
|
|
29243
29307
|
//#region src/scapi-client/constants.d.ts
|
|
29244
29308
|
/**
|
|
29245
29309
|
* Copyright 2026 Salesforce, Inc.
|
|
@@ -29274,5 +29338,5 @@ declare class ApiError extends Error {
|
|
|
29274
29338
|
*/
|
|
29275
29339
|
declare const SLAS_AUTH_ENDPOINTS: readonly ["/oauth2/token", "/oauth2/authorize", "/oauth2/logout", "/oauth2/login", "/oauth2/passwordless", "/oauth2/password", "/oauth2/session-bridge", "/oauth2/trusted-agent", "/oauth2/trusted-system", "/oauth2/revoke", "/oauth2/introspect"];
|
|
29276
29340
|
//#endregion
|
|
29277
|
-
export { ApiError, type AuthConfig, type AuthNamespace, type AuthResponse, type Basket, type BasketHelpersConfig, type BasketHelpersNamespace, Clients, CommerceApiClientConfig, type ErrorDetail, type GetOrCreateBasketOptions, GlobalRequestParameters, type LoginAsGuestOptions, type LoginWithCredentialsOptions, type LogoutOptions, type OperationMethodsOnly, type PasswordRequestResetOptions, type PasswordResetOptions, type PasswordlessAuthorizeOptions, type PasswordlessExchangeTokenOptions, type RefreshTokenOptions, SLAS_AUTH_ENDPOINTS, ShopperBasketsV1, ShopperBasketsV2, type ShopperBasketsV2Client, ShopperConfigurations, ShopperConsents, ShopperContext, ShopperCustomers, ShopperExperience, ShopperGiftCertificates, ShopperLogin, ShopperOrders, ShopperPayments, ShopperProducts, ShopperPromotions, ShopperSearch, ShopperSeo, ShopperStores, type SocialAuthorizationUrlResult, type SocialExchangeCodeOptions, type SocialGetAuthorizationUrlOptions, type TokenResponse, createBasketHelpers, createClient, createCommerceApiClients };
|
|
29341
|
+
export { ApiError, type AuthConfig, type AuthNamespace, type AuthResponse, AuthTokenInvalidError, type Basket, type BasketHelpersConfig, type BasketHelpersNamespace, Clients, CommerceApiClientConfig, CreateClientOptions, type ErrorDetail, type GetOrCreateBasketOptions, GlobalRequestParameters, type LoginAsGuestOptions, type LoginWithCredentialsOptions, type LogoutOptions, type OperationMethodsOnly, type PasswordRequestResetOptions, type PasswordResetOptions, type PasswordlessAuthorizeOptions, type PasswordlessExchangeTokenOptions, type RefreshTokenOptions, SLAS_AUTH_ENDPOINTS, ShopperBasketsV1, ShopperBasketsV2, type ShopperBasketsV2Client, ShopperConfigurations, ShopperConsents, ShopperContext, ShopperCustomers, ShopperExperience, ShopperGiftCertificates, ShopperLogin, ShopperOrders, ShopperPayments, ShopperProducts, ShopperPromotions, ShopperSearch, ShopperSeo, ShopperStores, type SocialAuthorizationUrlResult, type SocialExchangeCodeOptions, type SocialGetAuthorizationUrlOptions, type TokenResponse, createBasketHelpers, createClient, createCommerceApiClients };
|
|
29278
29342
|
//# sourceMappingURL=scapi.d.ts.map
|