@salesforce/storefront-next-runtime 0.4.0-alpha.1 → 0.4.0-alpha.2

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.
@@ -1,7 +1,7 @@
1
1
  import { n as Site$1, r as Url, t as Locale$1 } from "./types.js";
2
2
  import { PropsWithChildren } from "react";
3
- import * as react_jsx_runtime0 from "react/jsx-runtime";
4
- import * as react_router6 from "react-router";
3
+ import * as react_jsx_runtime1 from "react/jsx-runtime";
4
+ import * as react_router9 from "react-router";
5
5
  import { Cookie, CookieOptions, MiddlewareFunction, RouterContextProvider } from "react-router";
6
6
  import { RouteConfigEntry } from "@react-router/dev/routes";
7
7
 
@@ -102,7 +102,7 @@ declare function SiteProvider({
102
102
  language,
103
103
  currency,
104
104
  children
105
- }: PropsWithChildren<SiteContextValue>): react_jsx_runtime0.JSX.Element;
105
+ }: PropsWithChildren<SiteContextValue>): react_jsx_runtime1.JSX.Element;
106
106
  /**
107
107
  * React hook to get the current site context.
108
108
  * Returns `{ site, locale, language, currency }`.
@@ -182,7 +182,7 @@ declare function buildUrl({
182
182
  }): string;
183
183
  //#endregion
184
184
  //#region src/site-context/middleware.d.ts
185
- declare const siteContext: react_router6.RouterContext<SiteContext | null>;
185
+ declare const siteContext: react_router9.RouterContext<SiteContext | null>;
186
186
  /**
187
187
  * Resolved site context result from {@link resolveSiteContext}.
188
188
  */
@@ -230,9 +230,9 @@ declare function resolveSiteContext(request: Request, settings: SiteSettings): P
230
230
  * ```
231
231
  */
232
232
  declare function getSiteContextCookies(context: Readonly<RouterContextProvider>): {
233
- siteCookie: react_router6.Cookie;
234
- localeCookie: react_router6.Cookie;
235
- currencyCookie: react_router6.Cookie;
233
+ siteCookie: react_router9.Cookie;
234
+ localeCookie: react_router9.Cookie;
235
+ currencyCookie: react_router9.Cookie;
236
236
  } | null;
237
237
  /**
238
238
  * Creates a site context middleware that resolves the current site from
package/dist/utils.js CHANGED
@@ -1,73 +1,7 @@
1
1
  import { i as siteContext } from "./site-context2.js";
2
2
  import { createContext } from "react-router";
3
- import { DataStore, DataStoreNotFoundError, DataStoreServiceError, DataStoreUnavailableError } from "@salesforce/mrt-utilities/middleware";
3
+ import { DataStore, DataStoreNotFoundError, DataStoreServiceError, DataStoreUnavailableError } from "@salesforce/mrt-utilities/data-store";
4
4
 
5
- //#region src/data-store/provider.ts
6
- let providerPromise = null;
7
- /**
8
- * Resolve the default data-store provider based on MRT environment variables.
9
- *
10
- * Environment variables:
11
- * - `AWS_REGION` (required for MRT): AWS region for the data store table (e.g., "us-east-1")
12
- * - `MOBIFY_PROPERTY_ID` (required for MRT): MRT property identifier (e.g., "abcd1234")
13
- * - `DEPLOY_TARGET` (required for MRT): MRT deploy target (e.g., "production")
14
- * - `SFNEXT_DATA_STORE_ALLOW_LOCAL` (optional): allow local provider outside development ("true")
15
- * - `CI` (optional): allow local provider when set to "true"
16
- *
17
- * @returns Provider promise resolved for the current environment.
18
- * @example
19
- * const provider = await getDefaultDataStoreProvider();
20
- * const entry = await provider.getEntry('custom-global-preferences');
21
- */
22
- function getDefaultDataStoreProvider() {
23
- if (providerPromise) return providerPromise;
24
- providerPromise = hasMrtEnvironment() ? Promise.resolve(createMrtDataStoreProvider()) : resolveNonMrtProvider();
25
- return providerPromise;
26
- }
27
- /**
28
- * Create the MRT data-store provider.
29
- *
30
- * @returns MRT provider backed by `@salesforce/mrt-utilities`.
31
- * @example
32
- * const provider = createMrtDataStoreProvider();
33
- * await provider.getEntry('custom-global-preferences');
34
- */
35
- function createMrtDataStoreProvider() {
36
- return {
37
- kind: "mrt",
38
- getEntry: async (key) => await DataStore.getDataStore().getEntry(key)
39
- };
40
- }
41
- /**
42
- * Load the local data-store provider for development.
43
- *
44
- * @returns Local provider loaded via dynamic import.
45
- * @example
46
- * const provider = await loadLocalDataStoreProvider();
47
- * await provider.getEntry('custom-global-preferences');
48
- */
49
- async function loadLocalDataStoreProvider() {
50
- const module = await tryImportLocalProvider();
51
- if (typeof module.createLocalDataStoreProvider !== "function") throw new Error("Missing createLocalDataStoreProvider export.");
52
- return module.createLocalDataStoreProvider();
53
- }
54
- /**
55
- * Resolve the non-MRT provider based on environment.
56
- *
57
- * Environment variables:
58
- * - `SFNEXT_DATA_STORE_ALLOW_LOCAL` (optional): allow local provider outside development ("true")
59
- * - `CI` (optional): allow local provider when set to "true"
60
- *
61
- * @returns Local provider in development, otherwise throws.
62
- * @example
63
- * const provider = await resolveNonMrtProvider();
64
- */
65
- async function resolveNonMrtProvider() {
66
- if (isDevelopmentEnvironment() || process.env.SFNEXT_DATA_STORE_ALLOW_LOCAL === "true" || process.env.CI === "true") return loadLocalDataStoreProvider();
67
- throw new Error("Data store is unavailable. Ensure AWS_REGION, MOBIFY_PROPERTY_ID, and DEPLOY_TARGET are set.");
68
- }
69
-
70
- //#endregion
71
5
  //#region src/data-store/utils.ts
72
6
  /**
73
7
  * Creates a typed React Router context for data store entries.
@@ -92,20 +26,27 @@ function createDataStoreContext() {
92
26
  * @returns React Router middleware for server requests
93
27
  */
94
28
  function createDataStoreMiddleware(options) {
95
- const { entryKey, context: contextKey } = options;
29
+ const { entryKey, context: contextKey, onUnavailable = "throw", fallbackValue } = options;
96
30
  const transform = options.transform ?? ((value) => value);
97
- const providerPromise$1 = options.provider ? Promise.resolve(options.provider) : getDefaultDataStoreProvider();
98
31
  const dataStoreMiddleware = async ({ context }, next) => {
99
32
  const resolvedEntryKey = typeof entryKey === "function" ? entryKey(context) : entryKey;
100
33
  try {
101
- const entry = await (await providerPromise$1).getEntry(resolvedEntryKey);
34
+ const entry = await getDataStoreEntry(resolvedEntryKey);
102
35
  if (!entry?.value || typeof entry.value !== "object") {
103
36
  console.warn(`Data store entry '${resolvedEntryKey}' not found or invalid.`);
104
37
  return next();
105
38
  }
106
39
  context.set(contextKey, transform(entry.value));
107
40
  } catch (error) {
108
- if (error instanceof DataStoreUnavailableError) throw new Error("Data store is unavailable. Ensure AWS_REGION, MOBIFY_PROPERTY_ID, and DEPLOY_TARGET are set.");
41
+ if (error instanceof DataStoreUnavailableError) {
42
+ if (onUnavailable === "fallback" && typeof fallbackValue !== "undefined") {
43
+ const resolvedFallbackValue = typeof fallbackValue === "function" ? fallbackValue(context) : fallbackValue;
44
+ context.set(contextKey, resolvedFallbackValue);
45
+ console.warn(`Data store unavailable for '${resolvedEntryKey}'. Using configured fallback value.`);
46
+ return next();
47
+ }
48
+ throw new Error("Data store is unavailable. Ensure AWS_REGION, MOBIFY_PROPERTY_ID, and DEPLOY_TARGET are set.");
49
+ }
109
50
  if (error instanceof DataStoreNotFoundError) {
110
51
  console.warn(`Data store entry '${resolvedEntryKey}' not found.`);
111
52
  return next();
@@ -118,47 +59,17 @@ function createDataStoreMiddleware(options) {
118
59
  return dataStoreMiddleware;
119
60
  }
120
61
  /**
121
- * Check whether MRT environment variables are present.
122
- *
123
- * @returns True when all MRT environment variables are set.
124
- * @example
125
- * if (hasMrtEnvironment()) {
126
- * // Use MRT provider
127
- * }
128
- */
129
- function hasMrtEnvironment() {
130
- return Boolean(process.env.AWS_REGION && process.env.MOBIFY_PROPERTY_ID && process.env.DEPLOY_TARGET);
131
- }
132
- /**
133
- * Check whether the runtime is in a development environment.
134
- *
135
- * @returns True when NODE_ENV is not "production".
136
- * @example
137
- * if (isDevelopmentEnvironment()) {
138
- * // Load local provider
139
- * }
140
- */
141
- function isDevelopmentEnvironment() {
142
- return process.env.NODE_ENV !== "production";
143
- }
144
- /**
145
- * Attempt to import the local provider from the dev package or workspace path.
62
+ * Read a data-store entry through the singleton MRT utilities API.
63
+ * The underlying implementation (production DynamoDB vs development pseudo store)
64
+ * is resolved by `@salesforce/mrt-utilities/data-store` export conditions.
146
65
  *
147
- * @returns Local provider module.
148
- * @throws Error when the provider cannot be resolved.
149
- * @example
150
- * const module = await tryImportLocalProvider();
151
- * const provider = module.createLocalDataStoreProvider();
66
+ * @param key - Data-store entry key
67
+ * @returns Data-store entry or null when missing/invalid shape
152
68
  */
153
- async function tryImportLocalProvider() {
154
- try {
155
- return await import(
156
- /* @vite-ignore */
157
- "@salesforce/storefront-next-dev/data-store/local-provider"
158
- );
159
- } catch (error) {
160
- throw new Error("Failed to load local data-store provider. Ensure @salesforce/storefront-next-dev is installed.", { cause: error });
161
- }
69
+ async function getDataStoreEntry(key) {
70
+ const entry = await DataStore.getDataStore().getEntry(key);
71
+ if (!entry || typeof entry !== "object") return null;
72
+ return entry;
162
73
  }
163
74
  /**
164
75
  * Creates an entryKey function that prefixes the given suffix with the current site ID.
@@ -175,5 +86,5 @@ function prefixWithSiteId(suffix) {
175
86
  }
176
87
 
177
88
  //#endregion
178
- export { getDefaultDataStoreProvider as i, createDataStoreMiddleware as n, prefixWithSiteId as r, createDataStoreContext as t };
89
+ export { prefixWithSiteId as i, createDataStoreMiddleware as n, getDataStoreEntry as r, createDataStoreContext as t };
179
90
  //# sourceMappingURL=utils.js.map
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","names":["providerPromise: Promise<DataStoreProvider> | null","providerPromise","dataStoreMiddleware: MiddlewareFunction<Response>"],"sources":["../src/data-store/provider.ts","../src/data-store/utils.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\nimport { DataStore } from '@salesforce/mrt-utilities/middleware';\nimport { hasMrtEnvironment, isDevelopmentEnvironment, tryImportLocalProvider } from './utils';\n\nexport type DataStoreEntry<TValue = unknown> = {\n value?: TValue;\n};\n\nexport type DataStoreProvider = {\n kind: 'mrt' | 'local';\n getEntry: <TValue = unknown>(key: string) => Promise<DataStoreEntry<TValue> | null>;\n};\n\nlet providerPromise: Promise<DataStoreProvider> | null = null;\n\n/**\n * Reset the cached provider promise.\n *\n * Intended for tests to ensure isolated provider resolution.\n */\nexport function resetDataStoreProviderCache(): void {\n providerPromise = null;\n}\n\n/**\n * Resolve the default data-store provider based on MRT environment variables.\n *\n * Environment variables:\n * - `AWS_REGION` (required for MRT): AWS region for the data store table (e.g., \"us-east-1\")\n * - `MOBIFY_PROPERTY_ID` (required for MRT): MRT property identifier (e.g., \"abcd1234\")\n * - `DEPLOY_TARGET` (required for MRT): MRT deploy target (e.g., \"production\")\n * - `SFNEXT_DATA_STORE_ALLOW_LOCAL` (optional): allow local provider outside development (\"true\")\n * - `CI` (optional): allow local provider when set to \"true\"\n *\n * @returns Provider promise resolved for the current environment.\n * @example\n * const provider = await getDefaultDataStoreProvider();\n * const entry = await provider.getEntry('custom-global-preferences');\n */\nexport function getDefaultDataStoreProvider(): Promise<DataStoreProvider> {\n if (providerPromise) {\n return providerPromise;\n }\n\n providerPromise = hasMrtEnvironment() ? Promise.resolve(createMrtDataStoreProvider()) : resolveNonMrtProvider();\n\n return providerPromise;\n}\n\n/**\n * Create the MRT data-store provider.\n *\n * @returns MRT provider backed by `@salesforce/mrt-utilities`.\n * @example\n * const provider = createMrtDataStoreProvider();\n * await provider.getEntry('custom-global-preferences');\n */\nfunction createMrtDataStoreProvider(): DataStoreProvider {\n return {\n kind: 'mrt',\n getEntry: async <TValue = unknown>(key: string) =>\n (await DataStore.getDataStore().getEntry(key)) as DataStoreEntry<TValue> | null,\n };\n}\n\n/**\n * Load the local data-store provider for development.\n *\n * @returns Local provider loaded via dynamic import.\n * @example\n * const provider = await loadLocalDataStoreProvider();\n * await provider.getEntry('custom-global-preferences');\n */\nasync function loadLocalDataStoreProvider(): Promise<DataStoreProvider> {\n const module = await tryImportLocalProvider();\n if (typeof module.createLocalDataStoreProvider !== 'function') {\n throw new Error('Missing createLocalDataStoreProvider export.');\n }\n return module.createLocalDataStoreProvider();\n}\n\n/**\n * Resolve the non-MRT provider based on environment.\n *\n * Environment variables:\n * - `SFNEXT_DATA_STORE_ALLOW_LOCAL` (optional): allow local provider outside development (\"true\")\n * - `CI` (optional): allow local provider when set to \"true\"\n *\n * @returns Local provider in development, otherwise throws.\n * @example\n * const provider = await resolveNonMrtProvider();\n */\nasync function resolveNonMrtProvider(): Promise<DataStoreProvider> {\n const allowLocalProvider =\n isDevelopmentEnvironment() || process.env.SFNEXT_DATA_STORE_ALLOW_LOCAL === 'true' || process.env.CI === 'true';\n\n if (allowLocalProvider) {\n return loadLocalDataStoreProvider();\n }\n\n throw new Error('Data store is unavailable. Ensure AWS_REGION, MOBIFY_PROPERTY_ID, and DEPLOY_TARGET are set.');\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, type RouterContextProvider, createContext } from 'react-router';\nimport {\n DataStoreNotFoundError,\n DataStoreServiceError,\n DataStoreUnavailableError,\n} from '@salesforce/mrt-utilities/middleware';\nimport { getDefaultDataStoreProvider, type DataStoreProvider } from './provider';\nimport { siteContext } from '../site-context';\n\nexport type DataStoreContextKey<T> = ReturnType<typeof createContext<T | null>>;\n\nexport type DataStoreEntryKey = string | ((context: Readonly<RouterContextProvider>) => string);\n\nexport type DataStoreMiddlewareOptions<T> = {\n entryKey: DataStoreEntryKey;\n context: DataStoreContextKey<T>;\n transform?: (value: Record<string, unknown>) => T;\n provider?: DataStoreProvider | Promise<DataStoreProvider>;\n};\n\n/**\n * Creates a typed React Router context for data store entries.\n *\n * Initializes the context with `null` so middleware can populate it during requests.\n *\n * @returns React Router context key for data store values\n */\nexport function createDataStoreContext<T>(): DataStoreContextKey<T> {\n return createContext<T | null>(null);\n}\n\n/**\n * Creates a data-store middleware that fetches site preferences from MRT data access layer\n * and stores them in the router context.\n *\n * Environment variables:\n * - `AWS_REGION` (required): AWS region for the data store table (e.g., \"us-east-1\")\n * - `MOBIFY_PROPERTY_ID` (required): MRT property identifier (e.g., \"abcd1234\")\n * - `DEPLOY_TARGET` (required): MRT deploy target (e.g., \"production\")\n *\n * @param options - Middleware options for data store entry and context\n * @returns React Router middleware for server requests\n */\nexport function createDataStoreMiddleware<T>(options: DataStoreMiddlewareOptions<T>): MiddlewareFunction<Response> {\n const { entryKey, context: contextKey } = options;\n const transform = options.transform ?? ((value: Record<string, unknown>) => value as T);\n const providerPromise = options.provider ? Promise.resolve(options.provider) : getDefaultDataStoreProvider();\n\n const dataStoreMiddleware: MiddlewareFunction<Response> = async ({ context }, next) => {\n const resolvedEntryKey = typeof entryKey === 'function' ? entryKey(context) : entryKey;\n try {\n const provider = await providerPromise;\n const entry = await provider.getEntry(resolvedEntryKey);\n\n if (!entry?.value || typeof entry.value !== 'object') {\n // eslint-disable-next-line no-console\n console.warn(`Data store entry '${resolvedEntryKey}' not found or invalid.`);\n return next();\n }\n context.set(contextKey, transform(entry.value as Record<string, unknown>));\n } catch (error) {\n if (error instanceof DataStoreUnavailableError) {\n throw new Error(\n 'Data store is unavailable. Ensure AWS_REGION, MOBIFY_PROPERTY_ID, and DEPLOY_TARGET are set.'\n );\n }\n if (error instanceof DataStoreNotFoundError) {\n // eslint-disable-next-line no-console\n console.warn(`Data store entry '${resolvedEntryKey}' not found.`);\n return next();\n }\n if (error instanceof DataStoreServiceError) {\n throw new Error(`Data store request failed for '${resolvedEntryKey}'.`);\n }\n throw error;\n }\n\n return next();\n };\n\n return dataStoreMiddleware;\n}\n\n/**\n * Check whether MRT environment variables are present.\n *\n * @returns True when all MRT environment variables are set.\n * @example\n * if (hasMrtEnvironment()) {\n * // Use MRT provider\n * }\n */\nexport function hasMrtEnvironment(): boolean {\n return Boolean(process.env.AWS_REGION && process.env.MOBIFY_PROPERTY_ID && process.env.DEPLOY_TARGET);\n}\n\n/**\n * Check whether the runtime is in a development environment.\n *\n * @returns True when NODE_ENV is not \"production\".\n * @example\n * if (isDevelopmentEnvironment()) {\n * // Load local provider\n * }\n */\nexport function isDevelopmentEnvironment(): boolean {\n return process.env.NODE_ENV !== 'production';\n}\n\n/**\n * Attempt to import the local provider from the dev package or workspace path.\n *\n * @returns Local provider module.\n * @throws Error when the provider cannot be resolved.\n * @example\n * const module = await tryImportLocalProvider();\n * const provider = module.createLocalDataStoreProvider();\n */\nexport async function tryImportLocalProvider() {\n try {\n // @ts-expect-error - resolved at runtime from dev package\n return await import(/* @vite-ignore */ '@salesforce/storefront-next-dev/data-store/local-provider');\n } catch (error) {\n throw new Error(\n 'Failed to load local data-store provider. Ensure @salesforce/storefront-next-dev is installed.',\n { cause: error }\n );\n }\n}\n\n/**\n * Creates an entryKey function that prefixes the given suffix with the current site ID.\n *\n * @param suffix - The entry key suffix (e.g., \"custom-site-preferences\")\n * @returns A function compatible with `DataStoreMiddlewareOptions.entryKey`\n */\nexport function prefixWithSiteId(suffix: string): (context: Readonly<RouterContextProvider>) => string {\n return (context) => {\n const siteId = context.get(siteContext)?.site?.id;\n if (!siteId)\n throw new Error('Site id not found. Ensure site context middleware runs before data-store middleware.');\n return `${siteId}-${suffix}`;\n };\n}\n"],"mappings":";;;;;AA4BA,IAAIA,kBAAqD;;;;;;;;;;;;;;;;AA0BzD,SAAgB,8BAA0D;AACtE,KAAI,gBACA,QAAO;AAGX,mBAAkB,mBAAmB,GAAG,QAAQ,QAAQ,4BAA4B,CAAC,GAAG,uBAAuB;AAE/G,QAAO;;;;;;;;;;AAWX,SAAS,6BAAgD;AACrD,QAAO;EACH,MAAM;EACN,UAAU,OAAyB,QAC9B,MAAM,UAAU,cAAc,CAAC,SAAS,IAAI;EACpD;;;;;;;;;;AAWL,eAAe,6BAAyD;CACpE,MAAM,SAAS,MAAM,wBAAwB;AAC7C,KAAI,OAAO,OAAO,iCAAiC,WAC/C,OAAM,IAAI,MAAM,+CAA+C;AAEnE,QAAO,OAAO,8BAA8B;;;;;;;;;;;;;AAchD,eAAe,wBAAoD;AAI/D,KAFI,0BAA0B,IAAI,QAAQ,IAAI,kCAAkC,UAAU,QAAQ,IAAI,OAAO,OAGzG,QAAO,4BAA4B;AAGvC,OAAM,IAAI,MAAM,+FAA+F;;;;;;;;;;;;ACxEnH,SAAgB,yBAAoD;AAChE,QAAO,cAAwB,KAAK;;;;;;;;;;;;;;AAexC,SAAgB,0BAA6B,SAAsE;CAC/G,MAAM,EAAE,UAAU,SAAS,eAAe;CAC1C,MAAM,YAAY,QAAQ,eAAe,UAAmC;CAC5E,MAAMC,oBAAkB,QAAQ,WAAW,QAAQ,QAAQ,QAAQ,SAAS,GAAG,6BAA6B;CAE5G,MAAMC,sBAAoD,OAAO,EAAE,WAAW,SAAS;EACnF,MAAM,mBAAmB,OAAO,aAAa,aAAa,SAAS,QAAQ,GAAG;AAC9E,MAAI;GAEA,MAAM,QAAQ,OADG,MAAMD,mBACM,SAAS,iBAAiB;AAEvD,OAAI,CAAC,OAAO,SAAS,OAAO,MAAM,UAAU,UAAU;AAElD,YAAQ,KAAK,qBAAqB,iBAAiB,yBAAyB;AAC5E,WAAO,MAAM;;AAEjB,WAAQ,IAAI,YAAY,UAAU,MAAM,MAAiC,CAAC;WACrE,OAAO;AACZ,OAAI,iBAAiB,0BACjB,OAAM,IAAI,MACN,+FACH;AAEL,OAAI,iBAAiB,wBAAwB;AAEzC,YAAQ,KAAK,qBAAqB,iBAAiB,cAAc;AACjE,WAAO,MAAM;;AAEjB,OAAI,iBAAiB,sBACjB,OAAM,IAAI,MAAM,kCAAkC,iBAAiB,IAAI;AAE3E,SAAM;;AAGV,SAAO,MAAM;;AAGjB,QAAO;;;;;;;;;;;AAYX,SAAgB,oBAA6B;AACzC,QAAO,QAAQ,QAAQ,IAAI,cAAc,QAAQ,IAAI,sBAAsB,QAAQ,IAAI,cAAc;;;;;;;;;;;AAYzG,SAAgB,2BAAoC;AAChD,QAAO,QAAQ,IAAI,aAAa;;;;;;;;;;;AAYpC,eAAsB,yBAAyB;AAC3C,KAAI;AAEA,SAAO,MAAM;;GAA0B;;UAClC,OAAO;AACZ,QAAM,IAAI,MACN,kGACA,EAAE,OAAO,OAAO,CACnB;;;;;;;;;AAUT,SAAgB,iBAAiB,QAAsE;AACnG,SAAQ,YAAY;EAChB,MAAM,SAAS,QAAQ,IAAI,YAAY,EAAE,MAAM;AAC/C,MAAI,CAAC,OACD,OAAM,IAAI,MAAM,uFAAuF;AAC3G,SAAO,GAAG,OAAO,GAAG"}
1
+ {"version":3,"file":"utils.js","names":["dataStoreMiddleware: MiddlewareFunction<Response>"],"sources":["../src/data-store/utils.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\nimport { type MiddlewareFunction, type RouterContextProvider, createContext } from 'react-router';\nimport {\n DataStore,\n DataStoreNotFoundError,\n DataStoreServiceError,\n DataStoreUnavailableError,\n} from '@salesforce/mrt-utilities/data-store';\nimport { siteContext } from '../site-context';\n\nexport type DataStoreContextKey<T> = ReturnType<typeof createContext<T | null>>;\n\nexport type DataStoreEntryKey = string | ((context: Readonly<RouterContextProvider>) => string);\n\nexport type DataStoreEntry<TValue = unknown> = {\n value?: TValue;\n};\n\nexport type DataStoreMiddlewareOptions<T> = {\n entryKey: DataStoreEntryKey;\n context: DataStoreContextKey<T>;\n transform?: (value: Record<string, unknown>) => T;\n onUnavailable?: 'throw' | 'fallback';\n fallbackValue?: T | ((context: Readonly<RouterContextProvider>) => T);\n};\n\n/**\n * Creates a typed React Router context for data store entries.\n *\n * Initializes the context with `null` so middleware can populate it during requests.\n *\n * @returns React Router context key for data store values\n */\nexport function createDataStoreContext<T>(): DataStoreContextKey<T> {\n return createContext<T | null>(null);\n}\n\n/**\n * Creates a data-store middleware that fetches site preferences from MRT data access layer\n * and stores them in the router context.\n *\n * Environment variables:\n * - `AWS_REGION` (required): AWS region for the data store table (e.g., \"us-east-1\")\n * - `MOBIFY_PROPERTY_ID` (required): MRT property identifier (e.g., \"abcd1234\")\n * - `DEPLOY_TARGET` (required): MRT deploy target (e.g., \"production\")\n *\n * @param options - Middleware options for data store entry and context\n * @returns React Router middleware for server requests\n */\nexport function createDataStoreMiddleware<T>(options: DataStoreMiddlewareOptions<T>): MiddlewareFunction<Response> {\n const { entryKey, context: contextKey, onUnavailable = 'throw', fallbackValue } = options;\n const transform = options.transform ?? ((value: Record<string, unknown>) => value as T);\n\n const dataStoreMiddleware: MiddlewareFunction<Response> = async ({ context }, next) => {\n const resolvedEntryKey = typeof entryKey === 'function' ? entryKey(context) : entryKey;\n try {\n const entry = await getDataStoreEntry(resolvedEntryKey);\n\n if (!entry?.value || typeof entry.value !== 'object') {\n // eslint-disable-next-line no-console\n console.warn(`Data store entry '${resolvedEntryKey}' not found or invalid.`);\n return next();\n }\n context.set(contextKey, transform(entry.value as Record<string, unknown>));\n } catch (error) {\n if (error instanceof DataStoreUnavailableError) {\n if (onUnavailable === 'fallback' && typeof fallbackValue !== 'undefined') {\n const resolvedFallbackValue =\n typeof fallbackValue === 'function'\n ? (fallbackValue as (ctx: Readonly<RouterContextProvider>) => T)(context)\n : fallbackValue;\n context.set(contextKey, resolvedFallbackValue);\n // eslint-disable-next-line no-console\n console.warn(`Data store unavailable for '${resolvedEntryKey}'. Using configured fallback value.`);\n return next();\n }\n throw new Error(\n 'Data store is unavailable. Ensure AWS_REGION, MOBIFY_PROPERTY_ID, and DEPLOY_TARGET are set.'\n );\n }\n if (error instanceof DataStoreNotFoundError) {\n // eslint-disable-next-line no-console\n console.warn(`Data store entry '${resolvedEntryKey}' not found.`);\n return next();\n }\n if (error instanceof DataStoreServiceError) {\n throw new Error(`Data store request failed for '${resolvedEntryKey}'.`);\n }\n throw error;\n }\n\n return next();\n };\n\n return dataStoreMiddleware;\n}\n\n/**\n * Read a data-store entry through the singleton MRT utilities API.\n * The underlying implementation (production DynamoDB vs development pseudo store)\n * is resolved by `@salesforce/mrt-utilities/data-store` export conditions.\n *\n * @param key - Data-store entry key\n * @returns Data-store entry or null when missing/invalid shape\n */\nexport async function getDataStoreEntry<TValue = unknown>(key: string): Promise<DataStoreEntry<TValue> | null> {\n const entry = (await DataStore.getDataStore().getEntry(key)) as DataStoreEntry<TValue> | undefined;\n if (!entry || typeof entry !== 'object') {\n return null;\n }\n return entry;\n}\n\n/**\n * Creates an entryKey function that prefixes the given suffix with the current site ID.\n *\n * @param suffix - The entry key suffix (e.g., \"custom-site-preferences\")\n * @returns A function compatible with `DataStoreMiddlewareOptions.entryKey`\n */\nexport function prefixWithSiteId(suffix: string): (context: Readonly<RouterContextProvider>) => string {\n return (context) => {\n const siteId = context.get(siteContext)?.site?.id;\n if (!siteId)\n throw new Error('Site id not found. Ensure site context middleware runs before data-store middleware.');\n return `${siteId}-${suffix}`;\n };\n}\n"],"mappings":";;;;;;;;;;;;AAgDA,SAAgB,yBAAoD;AAChE,QAAO,cAAwB,KAAK;;;;;;;;;;;;;;AAexC,SAAgB,0BAA6B,SAAsE;CAC/G,MAAM,EAAE,UAAU,SAAS,YAAY,gBAAgB,SAAS,kBAAkB;CAClF,MAAM,YAAY,QAAQ,eAAe,UAAmC;CAE5E,MAAMA,sBAAoD,OAAO,EAAE,WAAW,SAAS;EACnF,MAAM,mBAAmB,OAAO,aAAa,aAAa,SAAS,QAAQ,GAAG;AAC9E,MAAI;GACA,MAAM,QAAQ,MAAM,kBAAkB,iBAAiB;AAEvD,OAAI,CAAC,OAAO,SAAS,OAAO,MAAM,UAAU,UAAU;AAElD,YAAQ,KAAK,qBAAqB,iBAAiB,yBAAyB;AAC5E,WAAO,MAAM;;AAEjB,WAAQ,IAAI,YAAY,UAAU,MAAM,MAAiC,CAAC;WACrE,OAAO;AACZ,OAAI,iBAAiB,2BAA2B;AAC5C,QAAI,kBAAkB,cAAc,OAAO,kBAAkB,aAAa;KACtE,MAAM,wBACF,OAAO,kBAAkB,aAClB,cAA8D,QAAQ,GACvE;AACV,aAAQ,IAAI,YAAY,sBAAsB;AAE9C,aAAQ,KAAK,+BAA+B,iBAAiB,qCAAqC;AAClG,YAAO,MAAM;;AAEjB,UAAM,IAAI,MACN,+FACH;;AAEL,OAAI,iBAAiB,wBAAwB;AAEzC,YAAQ,KAAK,qBAAqB,iBAAiB,cAAc;AACjE,WAAO,MAAM;;AAEjB,OAAI,iBAAiB,sBACjB,OAAM,IAAI,MAAM,kCAAkC,iBAAiB,IAAI;AAE3E,SAAM;;AAGV,SAAO,MAAM;;AAGjB,QAAO;;;;;;;;;;AAWX,eAAsB,kBAAoC,KAAqD;CAC3G,MAAM,QAAS,MAAM,UAAU,cAAc,CAAC,SAAS,IAAI;AAC3D,KAAI,CAAC,SAAS,OAAO,UAAU,SAC3B,QAAO;AAEX,QAAO;;;;;;;;AASX,SAAgB,iBAAiB,QAAsE;AACnG,SAAQ,YAAY;EAChB,MAAM,SAAS,QAAQ,IAAI,YAAY,EAAE,MAAM;AAC/C,MAAI,CAAC,OACD,OAAM,IAAI,MAAM,uFAAuF;AAC3G,SAAO,GAAG,OAAO,GAAG"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/storefront-next-runtime",
3
- "version": "0.4.0-alpha.1",
3
+ "version": "0.4.0-alpha.2",
4
4
  "description": "Runtime agnostic libraries for SFCC Storefront Next",
5
5
  "type": "module",
6
6
  "exports": {