@scayle/storefront-nuxt 8.24.2 → 8.25.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,6 +1,58 @@
1
1
  # @scayle/storefront-nuxt
2
2
 
3
- ## 8.24.2
3
+ ## 8.25.0
4
+
5
+ ### Minor Changes
6
+
7
+ - This change introduces the ability for the host application to define its own storage mounts, enhancing the flexibility of managing cache and session storage options within the Nuxt project.
8
+ To provide preconfigured storage mounts, the host application needs to mount storage drivers with specific names. The names `storefront-session` and `storefront-cache` are used for general cache and session storage, respectively. Additionally, shop-specific cache and session drivers can be configured by appending `:<shopId>` to the name, such as `storefront-session:1001` and `storefront-cache:1001`.
9
+
10
+ Preconfigured storage mounts can be implemented via a Nuxt server plugin within `./server/plugins`. If necessary, the `runtimeConfig` can be utilized to store the drivers' configuration:
11
+
12
+ ```ts
13
+ import fsDriver from 'unstorage/drivers/fs'
14
+ import compressionDriver from "@scayle/unstorage-compression-driver"
15
+ import { defineNitroPlugin, useStorage } from '#imports'
16
+
17
+ export default defineNitroPlugin(() => {
18
+ const storage = useStorage()
19
+ const config = useRuntimeConfig()
20
+ // Configure global storage (used as base config for all shops)
21
+ storage.mount('storefront-session', fsDriver({
22
+ base: config.sessionStorageBase,
23
+ }))
24
+ storage.mount('storefront-cache', fsDriver({
25
+ base: './cache',
26
+ }))
27
+
28
+ // The storage configuration can be overwritten on shop level if needed
29
+ storage.mount('storefront-cache:1001', compressionDriver(
30
+ encoding: 'brotli',
31
+ passthroughDriver: fsDriver({ base: './cache_1001' })
32
+ ))
33
+ })
34
+ ```
35
+
36
+ In scenarios where the build must not be runtime agnostic, the storage can also be configured statically in the `nuxt.config.ts` file. However, this is not the recommended approach:
37
+
38
+ ```ts
39
+ export default defineNuxtConfig({
40
+ nitro: {
41
+ storage: {
42
+ redis: {
43
+ driver: 'redis',
44
+ host: 'localhost',
45
+ },
46
+ db: {
47
+ driver: 'fs',
48
+ base: './.data/db',
49
+ },
50
+ },
51
+ },
52
+ })
53
+ ```
54
+
55
+ With the introduction of the new approach for configuring storefront storage mounts, the global and shop-specific `storage` option within the `@scayle/storefront-nuxt` runtime configuration has been deprecated.
4
56
 
5
57
  ### Patch Changes
6
58
 
@@ -11,7 +63,7 @@
11
63
 
12
64
  - Updated dependency to @scayle/h3-session@0.6.1
13
65
 
14
- **@scayle/storefront-core v8.24.2**
66
+ **@scayle/storefront-core v8.25.0**
15
67
 
16
68
  - Patch
17
69
  - **\[Code Style\]** Refactored brands and navigation tree RPCs to avoid destructuring the RPC context within function signatures
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scayle/storefront-nuxt",
3
- "version": "8.24.2",
3
+ "version": "8.25.0",
4
4
  "configKey": "storefront",
5
5
  "compatibility": {
6
6
  "nuxt": "^3.9.0"
package/dist/module.mjs CHANGED
@@ -54,7 +54,7 @@ export default {
54
54
  }`;
55
55
  }
56
56
  const PACKAGE_NAME = "@scayle/storefront-nuxt";
57
- const PACKAGE_VERSION = "8.24.2";
57
+ const PACKAGE_VERSION = "8.25.0";
58
58
  const logger = createConsola({
59
59
  fancy: true,
60
60
  formatOptions: {
@@ -89,7 +89,7 @@ function createRpcMethodTypeDeclaration(customRpcImports) {
89
89
  }
90
90
  export {}`;
91
91
  }
92
- async function nitroSetup(nitroConfig, config) {
92
+ async function nitroSetup(nitroConfig, config, moduleOptions) {
93
93
  const { resolve, resolvePath } = createResolver(import.meta.url);
94
94
  const { apiBasePath, customRpcImports, coreMethodNames, usedDrivers } = config;
95
95
  nitroConfig.replace = nitroConfig.replace || {};
@@ -139,9 +139,13 @@ async function nitroSetup(nitroConfig, config) {
139
139
  nitroConfig.plugins = nitroConfig.plugins ?? [];
140
140
  nitroConfig.plugins.push(resolve("./runtime/nitro/plugins/nitroLogger"));
141
141
  nitroConfig.plugins.push(resolve("./runtime/nitro/plugins/redirectOnError"));
142
- nitroConfig.plugins.push(
143
- resolve("./runtime/nitro/plugins/nitroRuntimeStorageConfig")
144
- );
142
+ if (!!moduleOptions?.storage || Object.values(moduleOptions?.shops || {}).some(
143
+ (shopConfig) => !!shopConfig.storage
144
+ )) {
145
+ nitroConfig.plugins.push(
146
+ resolve("./runtime/nitro/plugins/nitroLegacyStorageConfig")
147
+ );
148
+ }
145
149
  nitroConfig.plugins.push(
146
150
  resolve("./runtime/nitro/plugins/internalFetch")
147
151
  );
@@ -179,6 +183,16 @@ async function nitroSetup(nitroConfig, config) {
179
183
  nitroConfig.externals.inline = nitroConfig.externals.inline ?? [];
180
184
  nitroConfig.externals.inline.push(...tracedImports);
181
185
  }
186
+ async function nitroPostInit(moduleOptions, nitroApp) {
187
+ const { resolve } = createResolver(import.meta.url);
188
+ if (!moduleOptions?.storage && !Object.values(moduleOptions?.shops || {}).some(
189
+ (shopConfig) => !!shopConfig.storage
190
+ )) {
191
+ nitroApp.options.plugins.push(
192
+ resolve("./runtime/nitro/plugins/nitroStorageConfig")
193
+ );
194
+ }
195
+ }
182
196
  function validateRpcMethodOverrides(rpcMethodOverrides, customRpcNames, coreRpcNames) {
183
197
  const overriddenRPCMethodNames = new Set(rpcMethodOverrides);
184
198
  for (const rpcMethodName of customRpcNames) {
@@ -340,9 +354,10 @@ const module = defineNuxtModule({
340
354
  customRpcImports,
341
355
  coreMethodNames: [...rpcMethodNames],
342
356
  usedDrivers: getUsedDrivers(nuxt.options.runtimeConfig.storefront)
343
- });
357
+ }, nuxt.options.runtimeConfig.storefront);
344
358
  });
345
- nuxt.hooks.hook("nitro:init", (nitro) => {
359
+ nuxt.hooks.hook("nitro:init", async (nitro) => {
360
+ await nitroPostInit(nuxt.options.runtimeConfig.storefront, nitro);
346
361
  nitro.hooks.hook("rollup:before", (_nitro, rollupConfig) => {
347
362
  const existingHandler = rollupConfig.onwarn;
348
363
  rollupConfig.onwarn = (warning, handler) => {
@@ -9,6 +9,7 @@ import drivers from "#virtual/storage-drivers";
9
9
  import { defineNitroPlugin } from "nitropack/runtime/plugin";
10
10
  import { useStorage } from "nitropack/runtime/storage";
11
11
  import { useRuntimeConfig } from "#imports";
12
+ import { getAvailableMounts } from "../../utils/storage.js";
12
13
  function createMountDriver(options) {
13
14
  if (options?.driver) {
14
15
  const compression = options?.compression;
@@ -25,7 +26,7 @@ function createMountDriver(options) {
25
26
  }
26
27
  function mountStorage(storage, options) {
27
28
  const { config, base } = options;
28
- const mounts = storage.getMounts().map((existingMount) => existingMount.base.replace(":", ""));
29
+ const mounts = getAvailableMounts(storage);
29
30
  if (!mounts.includes(base)) {
30
31
  if (config) {
31
32
  storage.mount(base, createMountDriver(config));
@@ -0,0 +1,7 @@
1
+ /**
2
+ * This plugin expects a `storefront-cache` and `storefront-session` mount point to be provided.
3
+ * It will then mount a shop-specific storage mounts for each shop in the configuration.
4
+ * When a shop-specific mount is already provided, it will not be overridden.
5
+ */
6
+ declare const _default: import("nitropack").NitroAppPlugin;
7
+ export default _default;
@@ -0,0 +1,57 @@
1
+ import { createConsola } from "consola";
2
+ import {
3
+ STORAGE_MOUNT_CACHE,
4
+ STORAGE_MOUNT_SESSION
5
+ } from "../../server/utils/cacheStorage.js";
6
+ import createLog from "../../createLog.js";
7
+ import { JSONReporter } from "../../JSONReporter.js";
8
+ import { defineNitroPlugin } from "nitropack/runtime/plugin";
9
+ import { useStorage } from "nitropack/runtime/storage";
10
+ import { useRuntimeConfig } from "#imports";
11
+ import { getAvailableMounts, mountStorage } from "../../utils/storage.js";
12
+ export default defineNitroPlugin(async () => {
13
+ const storage = useStorage();
14
+ const config = useRuntimeConfig();
15
+ const { shops } = config.storefront;
16
+ const logConfig = config.public.storefront.log;
17
+ const log = createLog(
18
+ (opts) => createConsola({
19
+ ...logConfig.json ? { reporters: [new JSONReporter()] } : void 0,
20
+ stderr: logConfig.output === "stdout" ? process.stdout : process.stderr,
21
+ stdout: logConfig.output === "stderr" ? process.stderr : process.stdout,
22
+ ...opts
23
+ }),
24
+ logConfig.name,
25
+ logConfig.level
26
+ );
27
+ const availableMounts = getAvailableMounts(storage);
28
+ if (!availableMounts.includes(STORAGE_MOUNT_SESSION)) {
29
+ log.warn(
30
+ `${STORAGE_MOUNT_SESSION} storage mount not provided. Falling back to memory driver.`
31
+ );
32
+ }
33
+ if (!availableMounts.includes(STORAGE_MOUNT_CACHE)) {
34
+ log.warn(
35
+ `${STORAGE_MOUNT_CACHE} storage mount not provided. Falling back to memory driver.`
36
+ );
37
+ }
38
+ const mountShopStorage = async (shopId, mount) => {
39
+ try {
40
+ if (!availableMounts.includes(mount)) {
41
+ await mountStorage(storage, mount);
42
+ }
43
+ } catch (error) {
44
+ log.error(
45
+ `Unable to create required storage mount '${mount}'.`,
46
+ error
47
+ );
48
+ }
49
+ };
50
+ for (const shop of Object.values(shops)) {
51
+ await mountShopStorage(shop.shopId, `${STORAGE_MOUNT_CACHE}:${shop.shopId}`);
52
+ await mountShopStorage(
53
+ shop.shopId,
54
+ `${STORAGE_MOUNT_SESSION}:${shop.shopId}`
55
+ );
56
+ }
57
+ });
@@ -0,0 +1,19 @@
1
+ import type { Storage } from 'unstorage';
2
+ /**
3
+ * Returns a list of available mount points for the provided storage instance.
4
+ * The mount points are normalized by removing the tailing `:`.
5
+ * @param storage - The storage instance.
6
+ * @returns List of available mount points.
7
+ */
8
+ export declare const getAvailableMounts: (storage: Storage) => string[];
9
+ /**
10
+ * Mounts a {@link Storage | storage}.
11
+ *
12
+ * It checks if a mount with the given base path already exists and
13
+ * mounts a new storage instance if not. It prioritizes a provided configuration,
14
+ * falling back to the default memory driver.
15
+ *
16
+ * @param storage - The storage instance to mount to.
17
+ * @param mount - Mount name.
18
+ */
19
+ export declare const mountStorage: (storage: Storage, mount: string) => Promise<void>;
@@ -0,0 +1,13 @@
1
+ export const getAvailableMounts = (storage) => {
2
+ return storage.getMounts().map((existingMount) => existingMount.base.replace(/:$/, ""));
3
+ };
4
+ export const mountStorage = async (storage, mount) => {
5
+ const mounts = getAvailableMounts(storage);
6
+ if (!mounts.includes(mount)) {
7
+ const { driver: baseDriver } = storage.getMount(mount);
8
+ storage.mount(
9
+ mount,
10
+ baseDriver
11
+ );
12
+ }
13
+ };
@@ -251,6 +251,7 @@ declare const ShopConfigSchema: z.ZodObject<{
251
251
  host: string;
252
252
  token: string;
253
253
  }>>;
254
+ /** @deprecated The `storage` option within `shopConfig` is deprecated. Consider using nuxt storage configuration instead. */
254
255
  storage: z.ZodOptional<z.ZodObject<{
255
256
  session: z.ZodOptional<z.ZodDiscriminatedUnion<"driver", [z.ZodObject<{
256
257
  driver: z.ZodEnum<[BuiltinDriverName, ...BuiltinDriverName[]]>;
@@ -615,6 +616,7 @@ declare const StorefrontConfigSchema: z.ZodObject<{
615
616
  secret?: string | string[] | undefined;
616
617
  domain?: string | undefined;
617
618
  }>>;
619
+ /** @deprecated The `storage` option within `storefront` is deprecated. Consider using nuxt storage configuration instead. */
618
620
  storage: z.ZodOptional<z.ZodObject<{
619
621
  session: z.ZodOptional<z.ZodDiscriminatedUnion<"driver", [z.ZodObject<{
620
622
  driver: z.ZodEnum<[BuiltinDriverName, ...BuiltinDriverName[]]>;
@@ -1194,6 +1196,7 @@ export declare const RuntimeConfigSchema: z.ZodObject<{
1194
1196
  host: string;
1195
1197
  token: string;
1196
1198
  }>>;
1199
+ /** @deprecated The `storage` option within `shopConfig` is deprecated. Consider using nuxt storage configuration instead. */
1197
1200
  storage: z.ZodOptional<z.ZodObject<{
1198
1201
  session: z.ZodOptional<z.ZodDiscriminatedUnion<"driver", [z.ZodObject<{
1199
1202
  driver: z.ZodEnum<[BuiltinDriverName, ...BuiltinDriverName[]]>;
@@ -1726,6 +1729,7 @@ export declare const RuntimeConfigSchema: z.ZodObject<{
1726
1729
  secret?: string | string[] | undefined;
1727
1730
  domain?: string | undefined;
1728
1731
  }>>;
1732
+ /** @deprecated The `storage` option within `storefront` is deprecated. Consider using nuxt storage configuration instead. */
1729
1733
  storage: z.ZodOptional<z.ZodObject<{
1730
1734
  session: z.ZodOptional<z.ZodDiscriminatedUnion<"driver", [z.ZodObject<{
1731
1735
  driver: z.ZodEnum<[BuiltinDriverName, ...BuiltinDriverName[]]>;
@@ -102,6 +102,7 @@ const ShopConfigSchema = z.object({
102
102
  isEnabled: z.boolean().optional(),
103
103
  sessionConfig: SessionSchema.optional(),
104
104
  sapi: SapiSchema.optional(),
105
+ /** @deprecated The `storage` option within `shopConfig` is deprecated. Consider using nuxt storage configuration instead. */
105
106
  storage: z.object({
106
107
  session: StorageSchema.optional(),
107
108
  cache: StorageSchema.optional()
@@ -118,6 +119,7 @@ const CacheSchema = z.object({
118
119
  const ShopSelectorSchema = z.enum(["path", "domain", "path_or_default"]);
119
120
  const StorefrontConfigSchema = z.object({
120
121
  session: SessionSchema.optional(),
122
+ /** @deprecated The `storage` option within `storefront` is deprecated. Consider using nuxt storage configuration instead. */
121
123
  storage: z.object({
122
124
  session: StorageSchema.optional(),
123
125
  cache: StorageSchema.optional()
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@scayle/storefront-nuxt",
3
3
  "type": "module",
4
- "version": "8.24.2",
4
+ "version": "8.25.0",
5
5
  "description": "Nuxt integration for the SCAYLE Commerce Engine and Storefront API",
6
6
  "author": "SCAYLE Commerce Engine",
7
7
  "license": "MIT",
@@ -81,7 +81,7 @@
81
81
  "dependencies": {
82
82
  "@opentelemetry/api": "^1.9.0",
83
83
  "@scayle/h3-session": "0.6.1",
84
- "@scayle/storefront-core": "8.24.2",
84
+ "@scayle/storefront-core": "8.25.0",
85
85
  "@scayle/unstorage-compression-driver": "^0.2.6",
86
86
  "@vercel/nft": "0.29.2",
87
87
  "@vueuse/core": "13.1.0",