@scayle/storefront-nuxt 8.44.2 → 8.45.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/CHANGELOG.md CHANGED
@@ -1,5 +1,76 @@
1
1
  # @scayle/storefront-nuxt
2
2
 
3
+ ## 8.45.0
4
+
5
+ ### Minor Changes
6
+
7
+ - The API routes structure was updated for multi-shop environments. The `apiBasePath` option was removed from per-shop configuration but remains configurable at the module level.
8
+
9
+ NOTE: Update your `nuxt.config.ts` to ensure `routeRules` for `/api/**` uses the manually set `apiBasePath` value to prevent caching issues with session-related RPC's and potentially failing requests!
10
+
11
+ **Before (per-shop apiBasePath):**
12
+
13
+ ```typescript
14
+ // This configuration is no longer supported
15
+ runtimeConfig: {
16
+ storefront: {
17
+ shops: {
18
+ 1001: {
19
+ shopId: 1001,
20
+ path: 'de',
21
+ apiBasePath: '/custom-api', // ❌ No longer supported
22
+ // ... other shop config
23
+ },
24
+ 1002: {
25
+ shopId: 1002,
26
+ path: 'en',
27
+ apiBasePath: '/different-api', // ❌ No longer supported
28
+ // ... other shop config
29
+ }
30
+ }
31
+ }
32
+ }
33
+ ```
34
+
35
+ **After (module-level apiBasePath):**
36
+
37
+ ```typescript
38
+ // nuxt.config.ts
39
+ export default defineNuxtConfig({
40
+ storefront: {
41
+ apiBasePath: '/custom-api', // ✅ Configure globally for all shops
42
+ },
43
+ runtimeConfig: {
44
+ storefront: {
45
+ shops: {
46
+ 1001: {
47
+ shopId: 1001,
48
+ path: 'de',
49
+ // ✅ apiBasePath removed from shop config
50
+ // ... other shop config
51
+ },
52
+ 1002: {
53
+ shopId: 1002,
54
+ path: 'en',
55
+ // ✅ apiBasePath removed from shop config
56
+ // ... other shop config
57
+ },
58
+ },
59
+ },
60
+ },
61
+ })
62
+ ```
63
+
64
+ Additionally, the types for the Storefront module options and Storefront runtime configuration have been cleaned up to properly reflect which settings can be set at runtime and which cannot. This clarifies the distinction between configuration that is static (set at build/module level) and configuration that is dynamic (set at runtime), improving type safety and developer experience.
65
+
66
+ ### Patch Changes
67
+
68
+ **Dependencies**
69
+
70
+ **@scayle/storefront-core v8.45.0**
71
+
72
+ - No changes in this release.
73
+
3
74
  ## 8.44.2
4
75
 
5
76
  ### Patch Changes
package/dist/module.d.mts CHANGED
@@ -1,6 +1,5 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
2
  import { HookResult } from '@nuxt/schema';
3
- import { ModuleBaseOptions } from '../dist/runtime/types/module.js';
4
3
  export * from '../dist/runtime/types/module.js';
5
4
 
6
5
  /**
@@ -52,7 +51,17 @@ declare module '@nuxt/schema' {
52
51
  *
53
52
  * @returns The Nuxt module.
54
53
  */
55
- declare const _default: _nuxt_schema.NuxtModule<ModuleBaseOptions, ModuleBaseOptions, false>;
54
+ declare const _default: _nuxt_schema.NuxtModule<{
55
+ rpcDir?: string | undefined;
56
+ rpcMethodNames?: string[] | undefined;
57
+ rpcMethodOverrides?: ("getProductById" | "getProductsByIds" | "getProductsByReferenceKeys" | "getProductsCount" | "fetchAllFiltersForCategory" | "getFilters" | "getProductsByCategory" | "oauthForgetPassword" | "oauthGuestLogin" | "oauthLogin" | "oauthRegister" | "oauthRevokeToken" | "refreshAccessToken" | "updatePasswordByHash" | "addItemToBasket" | "addItemsToBasket" | "getBasket" | "removeItemFromBasket" | "clearBasket" | "mergeBaskets" | "updateBasketItem" | "getApplicablePromotionsByCode" | "updatePromotions" | "getBrands" | "getBrandById" | "getRootCategories" | "getCategoryByPath" | "getCategoriesByPath" | "getCategoryById" | "getCategoryTree" | "getCampaign" | "getCampaignKey" | "getOrderDataByCbd" | "getSearchSuggestions" | "resolveSearch" | "getShopConfiguration" | "getUser" | "fetchUser" | "refreshUser" | "getAccessToken" | "getWishlist" | "addItemToWishlist" | "removeItemFromWishlist" | "clearWishlist" | "getOrderById" | "getShopUserAddresses" | "updateShopUser" | "updatePassword" | "getCheckoutToken" | "getVariantById" | "fetchAllNavigationTrees" | "fetchNavigationTreeById" | "fetchNavigationTreeByName" | "getPromotions" | "getCurrentPromotions" | "getPromotionsByIds" | "getExternalIdpRedirect" | "handleIDPLoginCallback")[] | undefined;
58
+ apiBasePath?: string | undefined;
59
+ }, {
60
+ rpcDir?: string | undefined;
61
+ rpcMethodNames?: string[] | undefined;
62
+ rpcMethodOverrides?: ("getProductById" | "getProductsByIds" | "getProductsByReferenceKeys" | "getProductsCount" | "fetchAllFiltersForCategory" | "getFilters" | "getProductsByCategory" | "oauthForgetPassword" | "oauthGuestLogin" | "oauthLogin" | "oauthRegister" | "oauthRevokeToken" | "refreshAccessToken" | "updatePasswordByHash" | "addItemToBasket" | "addItemsToBasket" | "getBasket" | "removeItemFromBasket" | "clearBasket" | "mergeBaskets" | "updateBasketItem" | "getApplicablePromotionsByCode" | "updatePromotions" | "getBrands" | "getBrandById" | "getRootCategories" | "getCategoryByPath" | "getCategoriesByPath" | "getCategoryById" | "getCategoryTree" | "getCampaign" | "getCampaignKey" | "getOrderDataByCbd" | "getSearchSuggestions" | "resolveSearch" | "getShopConfiguration" | "getUser" | "fetchUser" | "refreshUser" | "getAccessToken" | "getWishlist" | "addItemToWishlist" | "removeItemFromWishlist" | "clearWishlist" | "getOrderById" | "getShopUserAddresses" | "updateShopUser" | "updatePassword" | "getCheckoutToken" | "getVariantById" | "fetchAllNavigationTrees" | "fetchNavigationTreeById" | "fetchNavigationTreeByName" | "getPromotions" | "getCurrentPromotions" | "getPromotionsByIds" | "getExternalIdpRedirect" | "handleIDPLoginCallback")[] | undefined;
63
+ apiBasePath?: string | undefined;
64
+ }, false>;
56
65
 
57
66
  export { _default as default };
58
67
  export type { ModuleHooks };
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scayle/storefront-nuxt",
3
- "version": "8.44.2",
3
+ "version": "8.45.0",
4
4
  "configKey": "storefront",
5
5
  "compatibility": {
6
6
  "nuxt": "^3.9.0"
package/dist/module.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { existsSync } from 'node:fs';
2
- import { defineNuxtModule, createResolver, extendViteConfig, addTypeTemplate, addPlugin, addImportsDir } from '@nuxt/kit';
2
+ import { defineNuxtModule, createResolver, addServerTemplate, addTypeTemplate, extendViteConfig, addPlugin, addImportsDir } from '@nuxt/kit';
3
3
  import { rpcMethods } from '@scayle/storefront-core';
4
4
  import { defu } from 'defu';
5
5
  import { genExport, genImport, genSafeVariableName } from 'knitwork';
@@ -54,7 +54,7 @@ export default {
54
54
  }`;
55
55
  }
56
56
  const PACKAGE_NAME = "@scayle/storefront-nuxt";
57
- const PACKAGE_VERSION = "8.44.2";
57
+ const PACKAGE_VERSION = "8.45.0";
58
58
  const logger = createConsola({
59
59
  fancy: true,
60
60
  formatOptions: {
@@ -228,49 +228,73 @@ const module = defineNuxtModule({
228
228
  },
229
229
  // Default configuration options of the Nuxt module
230
230
  defaults: {
231
- // TODO: Nuxt is making us give a default for each options
232
- // How do we mark some as required?
233
- session: {
234
- cookieName: "$session",
235
- sameSite: "lax"
236
- // TODO: If we give a default value here, nuxt will generate the runtime type incorrectly
237
- // secret needs to be typed as string | string[]
238
- // secret: 'current-secret',
239
- // if we set maxAge explicitly to undefined `useRuntimeConfig` will set it default to '' which leads to no sessions not being saved
240
- // maxAge: undefined,
241
- },
242
- shopSelector: "domain",
243
- oauth: {
244
- apiHost: "",
245
- clientId: "",
246
- clientSecret: ""
247
- },
248
- idp: {
249
- enabled: false,
250
- idpKeys: [],
251
- idpRedirectURL: ""
252
- },
253
- appKeys: {
254
- wishlistKey: "wishlist_{shopId}_{userId}",
255
- basketKey: "basket_{shopId}_{userId}",
256
- hashAlgorithm: "sha256"
257
- },
258
- legacy: {
259
- enableSessionMigration: false
260
- },
261
- /**
262
- * The internal access header.
263
- *
264
- * @hidden
265
- */
266
- internalAccessHeader: ""
231
+ rpcDir: void 0,
232
+ rpcMethodNames: void 0,
233
+ rpcMethodOverrides: void 0,
234
+ apiBasePath: "/api"
267
235
  },
268
236
  async setup(options, nuxt) {
269
237
  const { resolve } = createResolver(import.meta.url);
270
238
  const { resolve: appResolve } = createResolver(nuxt.options.rootDir);
239
+ addServerTemplate({
240
+ filename: "#internal/storefront-options.mjs",
241
+ getContents: () => `
242
+ export const apiBasePath = '${options.apiBasePath}'
243
+ export const rpcMethodNames = ${options.rpcMethodNames ? JSON.stringify(options.rpcMethodNames, null, 2) : "undefined"}
244
+ export const rpcMethodOverrides = ${options.rpcMethodOverrides ? JSON.stringify(options.rpcMethodOverrides, null, 2) : "undefined"}
245
+ `
246
+ });
247
+ addTypeTemplate({
248
+ filename: "types/storefront-options.d.ts",
249
+ getContents: () => `
250
+ declare module '#internal/storefront-options.mjs' {
251
+ export const apiBasePath: string
252
+ export const rpcMethodNames: string[] | undefined
253
+ export const rpcMethodOverrides: string[] | undefined
254
+ }
255
+ `
256
+ });
257
+ const runtimeConfigDefaults = {
258
+ // TODO: Nuxt is making us give a default for each options
259
+ // How do we mark some as required?
260
+ session: {
261
+ cookieName: "$session",
262
+ sameSite: "lax"
263
+ // TODO: If we give a default value here, nuxt will generate the runtime type incorrectly
264
+ // secret needs to be typed as string | string[]
265
+ // secret: 'current-secret',
266
+ // if we set maxAge explicitly to undefined `useRuntimeConfig` will set it default to '' which leads to no sessions not being saved
267
+ // maxAge: undefined,
268
+ },
269
+ shopSelector: "domain",
270
+ oauth: {
271
+ apiHost: "",
272
+ clientId: "",
273
+ clientSecret: ""
274
+ },
275
+ idp: {
276
+ enabled: false,
277
+ idpKeys: [],
278
+ idpRedirectURL: ""
279
+ },
280
+ appKeys: {
281
+ wishlistKey: "wishlist_{shopId}_{userId}",
282
+ basketKey: "basket_{shopId}_{userId}",
283
+ hashAlgorithm: "sha256"
284
+ },
285
+ legacy: {
286
+ enableSessionMigration: false
287
+ },
288
+ internalAccessHeader: "",
289
+ shops: {},
290
+ sapi: {
291
+ host: "",
292
+ token: ""
293
+ }
294
+ };
271
295
  nuxt.options.runtimeConfig.storefront = defu(
272
296
  nuxt.options.runtimeConfig.storefront,
273
- options
297
+ runtimeConfigDefaults
274
298
  );
275
299
  nuxt.options.runtimeConfig.public.storefront = defu(nuxt.options.runtimeConfig.public.storefront, {
276
300
  log: {
@@ -3,14 +3,15 @@ import type { RuntimeConfig } from '@nuxt/schema';
3
3
  import type { H3Event } from 'h3';
4
4
  import type { Log, RpcContext, Cache as CacheInterface } from '@scayle/storefront-core';
5
5
  import { StorefrontAPIClient } from '@scayle/storefront-core';
6
- import type { ShopConfig, StorefrontConfig } from '../module.js';
6
+ import type { ShopConfig } from '../module.js';
7
+ import type { StorefrontRuntimeConfigType } from './utils/zodSchema.js';
7
8
  /**
8
9
  * Interface defining the options for the context builder.
9
10
  */
10
11
  export interface ContextBuilderOptions {
11
12
  $cache: CacheInterface;
12
13
  $shopConfig: ShopConfig;
13
- $storefront: StorefrontConfig;
14
+ $storefront: StorefrontRuntimeConfigType;
14
15
  $log: Log;
15
16
  sessionId?: string;
16
17
  session?: Session;
@@ -10,6 +10,7 @@ import { useNitroApp } from "nitropack/runtime";
10
10
  import { getCachedFunction } from "./cached.js";
11
11
  import { getApiBasePath } from "./server/middleware/bootstrap-utils.js";
12
12
  import { fetchCampaignKey } from "./campaignKey.js";
13
+ import * as moduleOptions from "#internal/storefront-options.mjs";
13
14
  async function getWishlistKey(appKeys, session, $log, $shopConfig) {
14
15
  return session.data.user ? await generateWishlistKey({
15
16
  keyTemplate: appKeys.wishlistKey,
@@ -69,7 +70,7 @@ export const buildContext = async (context) => {
69
70
  const callRpc = buildRpcCall(
70
71
  context.event,
71
72
  $shopConfig,
72
- getApiBasePath($storefront, "/")
73
+ getApiBasePath(moduleOptions, "/")
73
74
  );
74
75
  const rpcContext = {
75
76
  cached,
@@ -1,6 +1,7 @@
1
1
  import type { H3Event } from 'h3';
2
- import type { ModuleBaseOptions, PublicShopConfig, ShopConfig, ShopConfigIndexed } from '../../../module.js';
2
+ import type { ModuleOptions, PublicShopConfig, ShopConfig, ShopConfigIndexed } from '../../../module.js';
3
3
  import type { NitroRuntimeConfigApp } from 'nitropack';
4
+ import type { StorefrontRuntimeConfigType } from '../../utils/zodSchema.js';
4
5
  /**
5
6
  * Represents the bootstrapped path information.
6
7
  */
@@ -39,7 +40,7 @@ export declare const getShopByPath: (event: H3Event, shops: ShopConfig[], appBas
39
40
  *
40
41
  * @returns The shops as an array.
41
42
  */
42
- export declare const convertShopsToList: (shops: ShopConfig[] | ShopConfigIndexed) => ShopConfig[];
43
+ export declare const convertShopsToList: (shops: ShopConfig[] | ShopConfigIndexed | StorefrontRuntimeConfigType["shops"]) => ShopConfig[];
43
44
  /**
44
45
  * Gets the API base path.
45
46
  *
@@ -48,7 +49,7 @@ export declare const convertShopsToList: (shops: ShopConfig[] | ShopConfigIndexe
48
49
  *
49
50
  * @returns The API base path.
50
51
  */
51
- export declare function getApiBasePath(storefrontConfig: Pick<ModuleBaseOptions, 'apiBasePath'>, baseUrl: string): string;
52
+ export declare function getApiBasePath(storefrontConfig: Pick<ModuleOptions, 'apiBasePath'>, baseUrl: string): string;
52
53
  /**
53
54
  * Retrieves the current shop configuration for a given request.
54
55
  *
@@ -58,7 +59,7 @@ export declare function getApiBasePath(storefrontConfig: Pick<ModuleBaseOptions,
58
59
  *
59
60
  * @returns The shop config for the current request if found or undefined.
60
61
  */
61
- export declare function getCurrentShopConfigForRequest(event: H3Event, storefrontConfig: Pick<ModuleBaseOptions, 'shops' | 'shopSelector'>, runtimeConfig: NitroRuntimeConfigApp): ShopConfig | undefined;
62
+ export declare function getCurrentShopConfigForRequest(event: H3Event, storefrontConfig: Pick<StorefrontRuntimeConfigType, 'shops' | 'shopSelector'>, runtimeConfig: NitroRuntimeConfigApp): ShopConfig | undefined;
62
63
  /**
63
64
  * Transforms shop configuration data into a public representation, including active status.
64
65
  *
@@ -15,6 +15,7 @@ import {
15
15
  } from "./bootstrap-utils.js";
16
16
  import { useRedirects } from "./redirects.js";
17
17
  import { useRuntimeConfig } from "#imports";
18
+ import * as moduleOptions from "#internal/storefront-options.mjs";
18
19
  const generateSessionId = (event) => {
19
20
  let userId;
20
21
  if (event?.context.session?.data?.accessToken) {
@@ -147,7 +148,7 @@ export default defineEventHandler(async (event) => {
147
148
  return;
148
149
  }
149
150
  const $storefrontConfig = config.storefront;
150
- if (path === `${$storefrontConfig.apiBasePath ?? "/api"}/up`) {
151
+ if (path === `${getApiBasePath(moduleOptions, "/")}/up`) {
151
152
  return;
152
153
  }
153
154
  const $shopConfig = getCurrentShopConfigForRequest(
@@ -163,7 +164,7 @@ export default defineEventHandler(async (event) => {
163
164
  return;
164
165
  }
165
166
  const apiBasePath = getApiBasePath(
166
- $storefrontConfig,
167
+ moduleOptions,
167
168
  config.app.baseURL
168
169
  );
169
170
  if (!event.context.$rpcContext) {
@@ -1,7 +1,7 @@
1
- import type { HashAlgorithm, ShopUser, WithParams, rpcMethods, StorefrontHooks, RpcMethodName, RpcContext } from '@scayle/storefront-core';
1
+ import type { HashAlgorithm, ShopUser, StorefrontHooks, RpcMethodName, RpcContext } from '@scayle/storefront-core';
2
2
  import type { CompressionEncodings } from '@scayle/unstorage-compression-driver';
3
3
  import type { BuiltinDriverName, BuiltinDriverOptions } from 'unstorage';
4
- import type { CheckoutShopConfigType, SessionType, StorageType, SapiConfigType, ShopConfigType, StorefrontConfigType, ShopSelectorType, ModulePublicRuntimeConfigType, RedirectType, IdpType } from '../utils/zodSchema.js';
4
+ import type { CheckoutShopConfigType, SessionType, StorageType, SapiConfigType, ShopConfigType, StorefrontRuntimeConfigType, StorefrontPublicRuntimeConfigType, IdpType, ModuleOptionType } from '../utils/zodSchema.js';
5
5
  import type { HookResult } from '@nuxt/schema';
6
6
  export type { LogLevel } from '@scayle/storefront-core';
7
7
  /**
@@ -117,93 +117,11 @@ export interface PublicShopConfig extends Pick<ShopConfig, 'shopId' | 'domain' |
117
117
  /**
118
118
  * Storefront configuration.
119
119
  */
120
- export type StorefrontConfig = StorefrontConfigType & {
121
- /**
122
- * Default "with" parameters for Storefront API requests. These are used as defaults
123
- * within composables like `useWishlist` and can be overridden if needed. Some
124
- * composables also enforce minimum "with" parameters.
125
- *
126
- * @example
127
- * // Default `with` parameters for product listings.
128
- * withParams: {
129
- * items: {
130
- * product: {
131
- * attributes: "all",
132
- * advancedAttributes: "all",
133
- * variants: {
134
- * attributes: "all",
135
- * advancedAttributes: "all",
136
- * },
137
- * images: "all",
138
- * categories: {
139
- * properties: "all"
140
- * },
141
- * priceRange: boolean
142
- * },
143
- * variant: {
144
- * attributes: "all",
145
- * },
146
- * },
147
- * }
148
- * @see https://scayle.dev/en/storefront-guide/support-and-resources/upgrade-guides/nuxt-3/storefront-core-changes#withparameters
149
- */
150
- withParams?: WithParams;
151
- };
152
- /**
153
- * Nuxt module options.
154
- */
155
- type ModuleOption = {
156
- /**
157
- * Shop selector.
158
- *
159
- * This determines how the application identifies and switches between different shops.
160
- * It influences how the `domain` and `path` properties are used within the `shops` configuration.
161
- *
162
- * @see https://scayle.dev/en/storefront-guide/developer-guide/basic-setup/introduction#path-and-domain
163
- */
164
- shopSelector: ShopSelectorType;
165
- /**
166
- * Redirects configuration.
167
- *
168
- * This controls how the application handles URL redirects by leveraging the Storefront API,
169
- * which is synchronized with the SCAYLE Panel. When enabled,
170
- * the Storefront Core intercepts requests and checks for potential
171
- * redirects via the Storefront API. If a match is found, a 30x HTTP response
172
- * is returned with the target in the `Location` header and the appropriate
173
- * status code.
174
- *
175
- * @see https://scayle.dev/en/storefront-guide/developer-guide/basic-setup/redirects
176
- */
177
- redirects?: RedirectType;
178
- /**
179
- * Shops configuration indexed by shop ID.
180
- *
181
- * Storefront applications typically support multiple shops for different regions or languages.
182
- * This configuration specifies the shops to use from your SCAYLE tenant space.
183
- *
184
- * @see https://scayle.dev/en/storefront-guide/developer-guide/basic-setup/introduction#shops
185
- */
186
- shops: ShopConfigIndexed;
187
- };
188
120
  export type SupportedDriverName = BuiltinDriverName | 'scayleKv';
189
121
  /**
190
122
  * Module base options. Extends `StorefrontConfig` and `ModuleOption`.
191
123
  */
192
- export type ModuleBaseOptions = StorefrontConfig & ModuleOption & {
193
- /**
194
- * The RPC directory where the custom application RPCs are defined.
195
- * The directory should have an `index.ts` file where all RPCs are exported using their name.
196
- * By default this will be `./rpcMethods`.
197
- */
198
- rpcDir?: string;
199
- /**
200
- * The RPC method names which are exported from the `rpcDir`.
201
- * Usually this can just be `Object.keys(rpcMethodsDir)`.
202
- */
203
- rpcMethodNames?: string[];
204
- /** Specify explicitly overridden RPC methods that are provided by the Storefront Core package. */
205
- rpcMethodOverrides?: Array<keyof typeof rpcMethods>;
206
- };
124
+ export type ModuleOptions = ModuleOptionType;
207
125
  /**
208
126
  * Checkout event used for tracking with Google Tag Manager.
209
127
  *
@@ -237,11 +155,11 @@ export interface CheckoutEvent {
237
155
  status: 'successful' | 'error';
238
156
  };
239
157
  }
240
- export interface ModulePublicRuntimeConfig extends ModulePublicRuntimeConfigType {
158
+ export interface ModulePublicRuntimeConfig extends StorefrontPublicRuntimeConfigType {
241
159
  }
242
160
  declare module '@nuxt/schema' {
243
161
  interface RuntimeConfig {
244
- storefront: ModuleBaseOptions;
162
+ storefront: StorefrontRuntimeConfigType;
245
163
  }
246
164
  interface PublicRuntimeConfig {
247
165
  storefront: ModulePublicRuntimeConfig;