@scayle/storefront-nuxt 8.6.0 → 8.7.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 +55 -0
- package/LICENSE +1 -1
- package/dist/module.d.mts +21 -1
- package/dist/module.d.ts +21 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +189 -115
- package/dist/runtime/api/purgeAll.js +10 -0
- package/dist/runtime/api/purgeTags.js +10 -0
- package/dist/runtime/api/rpcHandler.js +13 -7
- package/dist/runtime/handler.js +1 -1
- package/dist/runtime/plugin/shop.js +6 -2
- package/dist/runtime/server/middleware/bootstrap-utils.d.ts +1 -1
- package/dist/runtime/server/middleware/bootstrap-utils.js +5 -4
- package/dist/runtime/server/middleware/bootstrap.d.ts +1 -10
- package/dist/runtime/server/middleware/bootstrap.js +7 -5
- package/dist/runtime/server/middleware/redirects.js +3 -0
- package/dist/types.d.mts +2 -1
- package/dist/types.d.ts +2 -1
- package/package.json +9 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,60 @@
|
|
|
1
1
|
# @scayle/storefront-nuxt
|
|
2
2
|
|
|
3
|
+
## 8.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Introduce a flexible interface for registering custom RPC methods from other modules
|
|
8
|
+
|
|
9
|
+
Currently, applications can configure `rpcDir` and `rpcMethodNames` in the module configuration to register custom RPC methods, however this does not extend to modules.
|
|
10
|
+
This release adds a new module hook `storefront:custom-rpc:extend` which can be used to register custom RPC methods.
|
|
11
|
+
By registering a callback to this hook, other modules can add custom RPC methods to the application.
|
|
12
|
+
|
|
13
|
+
The hook functions similarly to `rpcDir` and `rpcMethodNames`. Hook registrants receive an array of custom RPC imports and can add their own. The import definition should include a `source` which defines the file to import the RPC methods from and a `names` array which controls the exports of this file which should be registered as RPC methods.
|
|
14
|
+
|
|
15
|
+
**rpc-methods.ts**
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import type { RpcContext, RpcHandler } from '@scayle/storefront-nuxt'
|
|
19
|
+
|
|
20
|
+
export const foo: RpcHandler<string, number> = function testing(
|
|
21
|
+
param: string,
|
|
22
|
+
_: RpcContext,
|
|
23
|
+
) {
|
|
24
|
+
return param.length
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**module.ts**
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
function setup() {
|
|
32
|
+
const resolver = createResolver(import.meta.url)
|
|
33
|
+
|
|
34
|
+
nuxt.hook('storefront:custom-rpc:extend', (customRpcImports) => {
|
|
35
|
+
customRpcImports.push({
|
|
36
|
+
source: resolver.resolve('./rpc-methods.ts'),
|
|
37
|
+
names: ['foo'],
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
As part of this change, the `RPCMethod` types are automatically extended with all custom RPC methods.
|
|
44
|
+
It is no longer necessary to extend `RpcMethodsStorefront`.
|
|
45
|
+
This applies both for the `rpcDir` + `rpcMethodNames` strategy as well as the new hook-based implementation.
|
|
46
|
+
|
|
47
|
+
### Patch Changes
|
|
48
|
+
|
|
49
|
+
- [RPC] Improve warning about missing RPC method overrides
|
|
50
|
+
- Improve error handling when bootstrapping fails due to a missing shop.
|
|
51
|
+
|
|
52
|
+
## 8.6.1
|
|
53
|
+
|
|
54
|
+
### Patch Changes
|
|
55
|
+
|
|
56
|
+
- Consider `baseURL` configuration when bootstrapping error pages. This ensures error pages have the correct `currentShop`.
|
|
57
|
+
|
|
3
58
|
## 8.6.0
|
|
4
59
|
|
|
5
60
|
### Minor Changes
|
package/LICENSE
CHANGED
package/dist/module.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
+
import { HookResult } from '@nuxt/schema';
|
|
2
3
|
import { M as ModuleBaseOptions } from './shared/storefront-nuxt.a816664e.mjs';
|
|
3
4
|
export { d as AdditionalShopConfig, A as AppKeys, h as CheckoutEvent, C as CheckoutShopConfig, i as ModulePublicRuntimeConfig, P as PublicShopConfig, c as SapiConfig, S as SessionConfig, e as ShopConfig, f as ShopConfigIndexed, b as StorageConfig, a as StorageEntity, g as StorefrontConfig } from './shared/storefront-nuxt.a816664e.mjs';
|
|
4
5
|
export { LogLevel } from '@scayle/storefront-core';
|
|
@@ -6,6 +7,25 @@ import '@scayle/unstorage-compression-driver';
|
|
|
6
7
|
import 'unstorage';
|
|
7
8
|
import '../dist/runtime/utils/zodSchema.js';
|
|
8
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Definition of a custom RPC import
|
|
12
|
+
*/
|
|
13
|
+
interface CustomRpcImport {
|
|
14
|
+
/** The location from which to import the RPC method(s) */
|
|
15
|
+
source: string;
|
|
16
|
+
/** The specifiers to import as RPC methods */
|
|
17
|
+
names: string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Build-time hooks used by the module
|
|
21
|
+
*/
|
|
22
|
+
interface ModuleHooks {
|
|
23
|
+
'storefront:custom-rpc:extend': (customRpcImports: CustomRpcImport[]) => HookResult;
|
|
24
|
+
}
|
|
25
|
+
declare module '@nuxt/schema' {
|
|
26
|
+
interface NuxtHooks extends ModuleHooks {
|
|
27
|
+
}
|
|
28
|
+
}
|
|
9
29
|
declare const _default: _nuxt_schema.NuxtModule<ModuleBaseOptions, ModuleBaseOptions, false>;
|
|
10
30
|
|
|
11
|
-
export { ModuleBaseOptions, _default as default };
|
|
31
|
+
export { ModuleBaseOptions, type ModuleHooks, _default as default };
|
package/dist/module.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
+
import { HookResult } from '@nuxt/schema';
|
|
2
3
|
import { M as ModuleBaseOptions } from './shared/storefront-nuxt.a816664e.js';
|
|
3
4
|
export { d as AdditionalShopConfig, A as AppKeys, h as CheckoutEvent, C as CheckoutShopConfig, i as ModulePublicRuntimeConfig, P as PublicShopConfig, c as SapiConfig, S as SessionConfig, e as ShopConfig, f as ShopConfigIndexed, b as StorageConfig, a as StorageEntity, g as StorefrontConfig } from './shared/storefront-nuxt.a816664e.js';
|
|
4
5
|
export { LogLevel } from '@scayle/storefront-core';
|
|
@@ -6,6 +7,25 @@ import '@scayle/unstorage-compression-driver';
|
|
|
6
7
|
import 'unstorage';
|
|
7
8
|
import '../dist/runtime/utils/zodSchema.js';
|
|
8
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Definition of a custom RPC import
|
|
12
|
+
*/
|
|
13
|
+
interface CustomRpcImport {
|
|
14
|
+
/** The location from which to import the RPC method(s) */
|
|
15
|
+
source: string;
|
|
16
|
+
/** The specifiers to import as RPC methods */
|
|
17
|
+
names: string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Build-time hooks used by the module
|
|
21
|
+
*/
|
|
22
|
+
interface ModuleHooks {
|
|
23
|
+
'storefront:custom-rpc:extend': (customRpcImports: CustomRpcImport[]) => HookResult;
|
|
24
|
+
}
|
|
25
|
+
declare module '@nuxt/schema' {
|
|
26
|
+
interface NuxtHooks extends ModuleHooks {
|
|
27
|
+
}
|
|
28
|
+
}
|
|
9
29
|
declare const _default: _nuxt_schema.NuxtModule<ModuleBaseOptions, ModuleBaseOptions, false>;
|
|
10
30
|
|
|
11
|
-
export { ModuleBaseOptions, _default as default };
|
|
31
|
+
export { ModuleBaseOptions, type ModuleHooks, _default as default };
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { defineNuxtModule, createResolver, extendViteConfig,
|
|
1
|
+
import { defineNuxtModule, createResolver, extendViteConfig, addTypeTemplate, addPlugin, addImportsDir } from '@nuxt/kit';
|
|
2
2
|
import { rpcMethods } from '@scayle/storefront-core';
|
|
3
3
|
import { defu } from 'defu';
|
|
4
|
-
import { genImport, genSafeVariableName } from 'knitwork';
|
|
4
|
+
import { genImport, genSafeVariableName, genExport } from 'knitwork';
|
|
5
5
|
import { builtinDrivers } from 'unstorage';
|
|
6
6
|
import { createConsola } from 'consola';
|
|
7
7
|
import { getApiBasePath } from '../dist/runtime/server/middleware/bootstrap-utils.js';
|
|
@@ -27,8 +27,7 @@ function getUsedDrivers(options) {
|
|
|
27
27
|
});
|
|
28
28
|
return Array.from(drivers);
|
|
29
29
|
}
|
|
30
|
-
function createVirtualDriverImport(
|
|
31
|
-
const usedDrivers = getUsedDrivers(options);
|
|
30
|
+
function createVirtualDriverImport(usedDrivers) {
|
|
32
31
|
const usesCompression = !stringToBoolean(
|
|
33
32
|
process.env.SFC_OMIT_COMPRESSION,
|
|
34
33
|
false
|
|
@@ -45,7 +44,7 @@ export default {
|
|
|
45
44
|
}`;
|
|
46
45
|
}
|
|
47
46
|
const PACKAGE_NAME = "@scayle/storefront-nuxt";
|
|
48
|
-
const PACKAGE_VERSION = "8.
|
|
47
|
+
const PACKAGE_VERSION = "8.7.0";
|
|
49
48
|
const logger = createConsola({
|
|
50
49
|
fancy: true,
|
|
51
50
|
formatOptions: {
|
|
@@ -59,6 +58,150 @@ const logger = createConsola({
|
|
|
59
58
|
// However when typechecking it will resolve to consola/browser which does have the fancy option
|
|
60
59
|
// This assertion avoids the typescript error
|
|
61
60
|
});
|
|
61
|
+
function createRpcMethodIndex(customRpcImports) {
|
|
62
|
+
return customRpcImports.map(({ source, names }) => genExport(source, names)).join(
|
|
63
|
+
"\n"
|
|
64
|
+
) + `
|
|
65
|
+
export {}`;
|
|
66
|
+
}
|
|
67
|
+
function createRpcMethodTypeDeclaration(customRpcImports) {
|
|
68
|
+
return `// Auto-generated
|
|
69
|
+
type RpcMethodsCustomType = {
|
|
70
|
+
${customRpcImports.reduce(
|
|
71
|
+
(lines, { source, names }) => lines.concat(
|
|
72
|
+
names.map((name) => `${name}: typeof import('${source}')['${name}'],`).join("\n")
|
|
73
|
+
),
|
|
74
|
+
[]
|
|
75
|
+
).join("\n")}
|
|
76
|
+
}
|
|
77
|
+
declare module '@scayle/storefront-nuxt' {
|
|
78
|
+
export interface RpcMethodsStorefront extends RpcMethodsCustomType {}
|
|
79
|
+
}
|
|
80
|
+
export {}`;
|
|
81
|
+
}
|
|
82
|
+
function nitroSetup(nitroConfig, config) {
|
|
83
|
+
const { resolve } = createResolver(import.meta.url);
|
|
84
|
+
const { apiBasePath, customRpcImports, coreMethodNames, usedDrivers } = config;
|
|
85
|
+
nitroConfig.externals = nitroConfig.externals || {};
|
|
86
|
+
nitroConfig.externals.inline = nitroConfig.externals.inline || [];
|
|
87
|
+
const runtimePaths = [
|
|
88
|
+
"handler",
|
|
89
|
+
"error/handler",
|
|
90
|
+
"campaignKey",
|
|
91
|
+
"cached",
|
|
92
|
+
"context",
|
|
93
|
+
"createLog",
|
|
94
|
+
"log",
|
|
95
|
+
"api/cacheAuth",
|
|
96
|
+
"rpc/rpcCall",
|
|
97
|
+
"rpc/rpcRequest",
|
|
98
|
+
"server/middleware/oauth",
|
|
99
|
+
"server/middleware/redirects",
|
|
100
|
+
"server/middleware/cache",
|
|
101
|
+
"server/utils/cacheStorage",
|
|
102
|
+
"utils/zodSchema",
|
|
103
|
+
"nitro/plugins/cacheRuntimeConfig",
|
|
104
|
+
"nitro/plugins/nitroLogger",
|
|
105
|
+
"nitro/plugins/nitroRuntimeStorageConfig",
|
|
106
|
+
"nitro/plugins/nitroSetXPoweredByHeader",
|
|
107
|
+
"nitro/plugins/configValidation"
|
|
108
|
+
];
|
|
109
|
+
runtimePaths.forEach((path) => {
|
|
110
|
+
const file = resolve(`./runtime/${path}`);
|
|
111
|
+
nitroConfig.externals?.inline?.push(file);
|
|
112
|
+
});
|
|
113
|
+
nitroConfig.replace = nitroConfig.replace || {};
|
|
114
|
+
nitroConfig.replace["process.env.SFC_OMIT_MD5"] = stringToBoolean(
|
|
115
|
+
process.env.SFC_OMIT_MD5
|
|
116
|
+
);
|
|
117
|
+
nitroConfig.replace.__sfc_version = PACKAGE_VERSION;
|
|
118
|
+
nitroConfig.virtual = {
|
|
119
|
+
...nitroConfig.virtual,
|
|
120
|
+
"#virtual/storage-drivers": createVirtualDriverImport(
|
|
121
|
+
usedDrivers
|
|
122
|
+
),
|
|
123
|
+
"#virtual/customRpcMethods": createRpcMethodIndex(
|
|
124
|
+
customRpcImports
|
|
125
|
+
)
|
|
126
|
+
};
|
|
127
|
+
nitroConfig.handlers = nitroConfig.handlers ?? [];
|
|
128
|
+
nitroConfig.handlers.unshift({
|
|
129
|
+
middleware: true,
|
|
130
|
+
handler: resolve("./runtime/server/middleware/bootstrap")
|
|
131
|
+
});
|
|
132
|
+
const allRpcNames = customRpcImports.reduce(
|
|
133
|
+
(acc, { names }) => acc.concat(names),
|
|
134
|
+
[]
|
|
135
|
+
).concat(coreMethodNames);
|
|
136
|
+
for (const methodName of allRpcNames) {
|
|
137
|
+
nitroConfig.handlers.push({
|
|
138
|
+
route: `${apiBasePath}/rpc/${methodName}`,
|
|
139
|
+
handler: resolve("./runtime/api/rpcHandler"),
|
|
140
|
+
method: "post"
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
nitroConfig.handlers.push({
|
|
144
|
+
route: `${apiBasePath}/purge/all`,
|
|
145
|
+
handler: resolve("./runtime/api/purgeAll"),
|
|
146
|
+
method: "post"
|
|
147
|
+
});
|
|
148
|
+
nitroConfig.handlers.push({
|
|
149
|
+
route: `${apiBasePath}/purge/tags`,
|
|
150
|
+
handler: resolve("./runtime/api/purgeTags"),
|
|
151
|
+
method: "post"
|
|
152
|
+
});
|
|
153
|
+
nitroConfig.handlers.push({
|
|
154
|
+
route: `${apiBasePath}/up`,
|
|
155
|
+
handler: resolve("./runtime/api/up")
|
|
156
|
+
});
|
|
157
|
+
nitroConfig.plugins = nitroConfig.plugins ?? [];
|
|
158
|
+
nitroConfig.plugins.push(resolve("./runtime/nitro/plugins/nitroLogger"));
|
|
159
|
+
nitroConfig.plugins.push(
|
|
160
|
+
resolve("./runtime/nitro/plugins/nitroRuntimeStorageConfig")
|
|
161
|
+
);
|
|
162
|
+
if (stringToBoolean(process.env.SFC_PLUGIN_CONFIG_VALIDATION_ENABLED, true)) {
|
|
163
|
+
logger.debug("Installing config validation plugin");
|
|
164
|
+
nitroConfig.plugins.push(
|
|
165
|
+
resolve("./runtime/nitro/plugins/configValidation")
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
if (stringToBoolean(process.env.SFC_PLUGIN_POWERED_BY_ENABLED, true)) {
|
|
169
|
+
logger.debug("Installing X-Powered-By plugin");
|
|
170
|
+
nitroConfig.plugins.push(
|
|
171
|
+
resolve("./runtime/nitro/plugins/nitroSetXPoweredByHeader")
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
if (stringToBoolean(process.env.SFC_PLUGIN_RUNTIME_PERFORMANCE_ENABLED, true)) {
|
|
175
|
+
logger.debug("Installing runtime performance plugin");
|
|
176
|
+
nitroConfig.plugins.push(
|
|
177
|
+
resolve("./runtime/nitro/plugins/cacheRuntimeConfig")
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function validateRpcMethodOverrides(rpcMethodOverrides, customRpcNames, coreRpcNames) {
|
|
182
|
+
const overridenRPCMethodNames = new Set(rpcMethodOverrides);
|
|
183
|
+
for (const rpcMethodName of customRpcNames) {
|
|
184
|
+
if (coreRpcNames.has(rpcMethodName) && !overridenRPCMethodNames.has(rpcMethodName)) {
|
|
185
|
+
logger.warn(`
|
|
186
|
+
Overriding RPC method '${rpcMethodName}' from '@scayle/storefront-nuxt' with a local custom implementation.
|
|
187
|
+
|
|
188
|
+
Should this be done on purpose, please be aware that this can lead to unexpected issues since the '@scayle/storefront-nuxt' package also uses this RPC method internally.
|
|
189
|
+
To silence this warning, you can add '${rpcMethodName}' to 'rpcMethodOverrides' in the '@scayle/storefront-nuxt' config.
|
|
190
|
+
|
|
191
|
+
In the future this will become an error where overrides need to be explicitly defined as an override.
|
|
192
|
+
`);
|
|
193
|
+
} else {
|
|
194
|
+
overridenRPCMethodNames.delete(rpcMethodName);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (overridenRPCMethodNames.size > 0) {
|
|
198
|
+
logger.warn(`
|
|
199
|
+
Detected RPC methods which were supposed to be overridden but are not. This indicates an incorrect configuration and should be adjusted. Check the 'rpcMethodOverrides' property.
|
|
200
|
+
|
|
201
|
+
Missing RPC Method Overrides: ${Array.from(overridenRPCMethodNames).map((name) => `'${name}'`).join(", ")}
|
|
202
|
+
`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
62
205
|
const module = defineNuxtModule({
|
|
63
206
|
meta: {
|
|
64
207
|
name: PACKAGE_NAME,
|
|
@@ -102,7 +245,7 @@ const module = defineNuxtModule({
|
|
|
102
245
|
},
|
|
103
246
|
internalAccessHeader: ""
|
|
104
247
|
},
|
|
105
|
-
setup(options, nuxt) {
|
|
248
|
+
async setup(options, nuxt) {
|
|
106
249
|
const { resolve } = createResolver(import.meta.url);
|
|
107
250
|
const { resolve: appResolve } = createResolver(nuxt.options.srcDir);
|
|
108
251
|
nuxt.options.runtimeConfig.storefront = defu(
|
|
@@ -125,55 +268,40 @@ const module = defineNuxtModule({
|
|
|
125
268
|
"slugify"
|
|
126
269
|
);
|
|
127
270
|
});
|
|
128
|
-
nuxt.options.serverHandlers.unshift({
|
|
129
|
-
middleware: true,
|
|
130
|
-
handler: resolve("./runtime/server/middleware/bootstrap")
|
|
131
|
-
});
|
|
132
271
|
const apiBasePath = getApiBasePath(options, "/");
|
|
133
272
|
const rpcMethodNames = new Set(Object.keys(rpcMethods));
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
273
|
+
const storefrontRpcMethodNames = options.rpcMethodNames ?? [];
|
|
274
|
+
const customRpcImports = [];
|
|
275
|
+
nuxt.hook("modules:done", async () => {
|
|
276
|
+
await nuxt.callHook("storefront:custom-rpc:extend", customRpcImports);
|
|
277
|
+
customRpcImports.forEach((customImport) => {
|
|
278
|
+
customImport.names.forEach((name) => {
|
|
279
|
+
if (rpcMethodNames.has(name)) {
|
|
280
|
+
throw new Error(
|
|
281
|
+
`Core RPC method '${name}' cannot be overriden via the 'storefront:custom-rpc:extend' hook`
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
customImport.names = customImport.names.filter(
|
|
286
|
+
(name) => !storefrontRpcMethodNames.includes(name)
|
|
287
|
+
);
|
|
288
|
+
});
|
|
289
|
+
customRpcImports.push({
|
|
290
|
+
source: appResolve(options.rpcDir ?? "./rpcMethods"),
|
|
291
|
+
names: storefrontRpcMethodNames
|
|
292
|
+
});
|
|
293
|
+
validateRpcMethodOverrides(
|
|
294
|
+
options.rpcMethodOverrides ?? [],
|
|
295
|
+
customRpcImports.reduce(
|
|
296
|
+
(acc, { names }) => acc.concat(names),
|
|
297
|
+
[]
|
|
298
|
+
),
|
|
299
|
+
rpcMethodNames
|
|
300
|
+
);
|
|
301
|
+
addTypeTemplate({
|
|
302
|
+
filename: "types/storefront-custom-rpc.d.ts",
|
|
303
|
+
getContents: () => createRpcMethodTypeDeclaration(customRpcImports)
|
|
162
304
|
});
|
|
163
|
-
});
|
|
164
|
-
addServerHandler({
|
|
165
|
-
route: `${apiBasePath}/purge/all`,
|
|
166
|
-
handler: resolve("./runtime/api/purgeAll"),
|
|
167
|
-
method: "post"
|
|
168
|
-
});
|
|
169
|
-
addServerHandler({
|
|
170
|
-
route: `${apiBasePath}/purge/tags`,
|
|
171
|
-
handler: resolve("./runtime/api/purgeTags"),
|
|
172
|
-
method: "post"
|
|
173
|
-
});
|
|
174
|
-
addServerHandler({
|
|
175
|
-
route: `${apiBasePath}/up`,
|
|
176
|
-
handler: resolve("./runtime/api/up")
|
|
177
305
|
});
|
|
178
306
|
addTypeTemplate({
|
|
179
307
|
filename: "types/storefront-bootstrap.d.ts",
|
|
@@ -183,10 +311,10 @@ Missing RPC Overrides: ${Array.from(overridenRPCMethodNames).map((name) => `'${n
|
|
|
183
311
|
import type { PublicShopConfig } from '@scayle/storefront-nuxt';
|
|
184
312
|
declare module 'h3' {
|
|
185
313
|
interface H3EventContext {
|
|
186
|
-
$rpcContext
|
|
187
|
-
$cache
|
|
188
|
-
$currentShop
|
|
189
|
-
$availableShops
|
|
314
|
+
$rpcContext?: RpcContext,
|
|
315
|
+
$cache?: Cache
|
|
316
|
+
$currentShop?: PublicShopConfig,
|
|
317
|
+
$availableShops?: PublicShopConfig[]
|
|
190
318
|
$log: Log
|
|
191
319
|
}
|
|
192
320
|
}
|
|
@@ -195,64 +323,13 @@ Missing RPC Overrides: ${Array.from(overridenRPCMethodNames).map((name) => `'${n
|
|
|
195
323
|
}
|
|
196
324
|
export {}`
|
|
197
325
|
});
|
|
198
|
-
addServerPlugin(resolve("./runtime/nitro/plugins/nitroLogger"));
|
|
199
|
-
addServerPlugin(
|
|
200
|
-
resolve("./runtime/nitro/plugins/nitroRuntimeStorageConfig")
|
|
201
|
-
);
|
|
202
|
-
if (stringToBoolean(process.env.SFC_PLUGIN_CONFIG_VALIDATION_ENABLED, true)) {
|
|
203
|
-
logger.debug("Installing config validation plugin");
|
|
204
|
-
addServerPlugin(resolve("./runtime/nitro/plugins/configValidation"));
|
|
205
|
-
}
|
|
206
|
-
if (stringToBoolean(process.env.SFC_PLUGIN_POWERED_BY_ENABLED, true)) {
|
|
207
|
-
logger.debug("Installing X-Powered-By plugin");
|
|
208
|
-
addServerPlugin(
|
|
209
|
-
resolve("./runtime/nitro/plugins/nitroSetXPoweredByHeader")
|
|
210
|
-
);
|
|
211
|
-
}
|
|
212
|
-
if (stringToBoolean(process.env.SFC_PLUGIN_RUNTIME_PERFORMANCE_ENABLED, true)) {
|
|
213
|
-
logger.debug("Installing runtime performance plugin");
|
|
214
|
-
addServerPlugin(resolve("./runtime/nitro/plugins/cacheRuntimeConfig"));
|
|
215
|
-
}
|
|
216
326
|
nuxt.hooks.hook("nitro:config", (nitroConfig) => {
|
|
217
|
-
nitroConfig
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
"campaignKey",
|
|
223
|
-
"cached",
|
|
224
|
-
"context",
|
|
225
|
-
"createLog",
|
|
226
|
-
"log",
|
|
227
|
-
"api/cacheAuth",
|
|
228
|
-
"rpc/rpcCall",
|
|
229
|
-
"rpc/rpcRequest",
|
|
230
|
-
"server/middleware/oauth",
|
|
231
|
-
"server/middleware/redirects",
|
|
232
|
-
"server/middleware/cache",
|
|
233
|
-
"server/utils/cacheStorage",
|
|
234
|
-
"utils/zodSchema",
|
|
235
|
-
"nitro/plugins/cacheRuntimeConfig",
|
|
236
|
-
"nitro/plugins/nitroLogger",
|
|
237
|
-
"nitro/plugins/nitroRuntimeStorageConfig",
|
|
238
|
-
"nitro/plugins/nitroSetXPoweredByHeader",
|
|
239
|
-
"nitro/plugins/configValidation"
|
|
240
|
-
];
|
|
241
|
-
runtimePaths.forEach((path) => {
|
|
242
|
-
const file = resolve(`./runtime/${path}`);
|
|
243
|
-
nitroConfig.externals?.inline?.push(file);
|
|
327
|
+
nitroSetup(nitroConfig, {
|
|
328
|
+
apiBasePath,
|
|
329
|
+
customRpcImports,
|
|
330
|
+
coreMethodNames: [...rpcMethodNames],
|
|
331
|
+
usedDrivers: getUsedDrivers(nuxt.options.runtimeConfig.storefront)
|
|
244
332
|
});
|
|
245
|
-
nitroConfig.replace = nitroConfig.replace || {};
|
|
246
|
-
nitroConfig.replace["process.env.SFC_OMIT_MD5"] = stringToBoolean(
|
|
247
|
-
process.env.SFC_OMIT_MD5
|
|
248
|
-
);
|
|
249
|
-
nitroConfig.replace.__sfc_version = PACKAGE_VERSION;
|
|
250
|
-
nitroConfig.virtual = {
|
|
251
|
-
...nitroConfig.virtual,
|
|
252
|
-
"#virtual/storage-drivers": createVirtualDriverImport(
|
|
253
|
-
nuxt.options.runtimeConfig.storefront
|
|
254
|
-
)
|
|
255
|
-
};
|
|
256
333
|
});
|
|
257
334
|
nuxt.hooks.hook("nitro:init", (nitro) => {
|
|
258
335
|
nitro.hooks.hook("rollup:before", (_nitro, rollupConfig) => {
|
|
@@ -269,9 +346,6 @@ Missing RPC Overrides: ${Array.from(overridenRPCMethodNames).map((name) => `'${n
|
|
|
269
346
|
};
|
|
270
347
|
});
|
|
271
348
|
});
|
|
272
|
-
nuxt.options.alias["#rpcMethods"] = appResolve(
|
|
273
|
-
options.rpcDir ?? "./rpcMethods"
|
|
274
|
-
);
|
|
275
349
|
nuxt.options.alias["#storefront/composables"] = resolve(
|
|
276
350
|
"./runtime/composables"
|
|
277
351
|
);
|
|
@@ -3,6 +3,16 @@ import { HttpStatusCode } from "@scayle/storefront-core";
|
|
|
3
3
|
import { eventHandlerWithCacheAuth } from "./cacheAuth.js";
|
|
4
4
|
export default eventHandlerWithCacheAuth(
|
|
5
5
|
defineEventHandler(async (event) => {
|
|
6
|
+
if (!event.context.$rpcContext) {
|
|
7
|
+
return new Response("No $rpcContext was found for the request", {
|
|
8
|
+
status: HttpStatusCode.INTERNAL_SERVER_ERROR
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
if (!event.context.$cache) {
|
|
12
|
+
return new Response("No $cache was found for the request", {
|
|
13
|
+
status: HttpStatusCode.INTERNAL_SERVER_ERROR
|
|
14
|
+
});
|
|
15
|
+
}
|
|
6
16
|
const logger = event.context.$rpcContext.log.space("purge-all");
|
|
7
17
|
try {
|
|
8
18
|
logger.debug("purging cache");
|
|
@@ -3,6 +3,16 @@ import { HttpStatusCode } from "@scayle/storefront-core";
|
|
|
3
3
|
import { eventHandlerWithCacheAuth } from "./cacheAuth.js";
|
|
4
4
|
export default eventHandlerWithCacheAuth(
|
|
5
5
|
defineEventHandler(async (event) => {
|
|
6
|
+
if (!event.context.$rpcContext) {
|
|
7
|
+
return new Response("No $rpcContext was found for the request", {
|
|
8
|
+
status: HttpStatusCode.INTERNAL_SERVER_ERROR
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
if (!event.context.$cache) {
|
|
12
|
+
return new Response("No $cache was found for the request", {
|
|
13
|
+
status: HttpStatusCode.INTERNAL_SERVER_ERROR
|
|
14
|
+
});
|
|
15
|
+
}
|
|
6
16
|
const tags = await readBody(event);
|
|
7
17
|
const logger = event.context.$rpcContext.log.space("purge-tags");
|
|
8
18
|
logger.debug(`purging tags: ${tags}`);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineEventHandler, readBody, createError, getRequestURL } from "h3";
|
|
2
|
-
import { purifySensitiveData } from "@scayle/storefront-core";
|
|
2
|
+
import { purifySensitiveData, HttpStatusCode } from "@scayle/storefront-core";
|
|
3
3
|
import { trace, SpanStatusCode } from "@opentelemetry/api";
|
|
4
4
|
import { handler } from "../handler.js";
|
|
5
5
|
import { resolveError } from "../error/handler.js";
|
|
@@ -9,6 +9,12 @@ const tracer = trace.getTracer(
|
|
|
9
9
|
"__sfc_version"
|
|
10
10
|
);
|
|
11
11
|
export default defineEventHandler(async (event) => {
|
|
12
|
+
const $rpcContext = event.context.$rpcContext;
|
|
13
|
+
if (!$rpcContext) {
|
|
14
|
+
return new Response("No $rpcContext was found for the request", {
|
|
15
|
+
status: HttpStatusCode.INTERNAL_SERVER_ERROR
|
|
16
|
+
});
|
|
17
|
+
}
|
|
12
18
|
const pathComponents = event.path.split("?")[0].split("/");
|
|
13
19
|
const method = pathComponents[pathComponents.length - 1];
|
|
14
20
|
const body = await readBody(event);
|
|
@@ -21,7 +27,7 @@ export default defineEventHandler(async (event) => {
|
|
|
21
27
|
typeof body?.payload !== "object" ? { [typeof body?.payload]: body?.payload } : body?.payload
|
|
22
28
|
)
|
|
23
29
|
);
|
|
24
|
-
|
|
30
|
+
$rpcContext.log.space("sfc").debug(`RPC Handler: ${method}, Payload: ${payloadToBeLogged}`);
|
|
25
31
|
const nitroApp = useNitroApp();
|
|
26
32
|
return await tracer.startActiveSpan(
|
|
27
33
|
`storefront-nuxt.rpc/${method}`,
|
|
@@ -41,14 +47,14 @@ export default defineEventHandler(async (event) => {
|
|
|
41
47
|
await nitroApp.hooks?.callHook(
|
|
42
48
|
"storefront:rpc:before",
|
|
43
49
|
method,
|
|
44
|
-
|
|
50
|
+
$rpcContext,
|
|
45
51
|
body?.payload
|
|
46
52
|
);
|
|
47
|
-
result = await handler(method, body?.payload,
|
|
53
|
+
result = await handler(method, body?.payload, $rpcContext);
|
|
48
54
|
await nitroApp.hooks.callHook(
|
|
49
55
|
"storefront:rpc:after",
|
|
50
56
|
method,
|
|
51
|
-
|
|
57
|
+
$rpcContext,
|
|
52
58
|
result
|
|
53
59
|
);
|
|
54
60
|
if (result instanceof Response && !result.ok) {
|
|
@@ -57,11 +63,11 @@ export default defineEventHandler(async (event) => {
|
|
|
57
63
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
58
64
|
}
|
|
59
65
|
} catch (e) {
|
|
60
|
-
|
|
66
|
+
$rpcContext.log.space("sfc").error(`RPC Handler failed: ${method}`, e);
|
|
61
67
|
await nitroApp.hooks.callHook(
|
|
62
68
|
"storefront:rpc:error",
|
|
63
69
|
method,
|
|
64
|
-
|
|
70
|
+
$rpcContext,
|
|
65
71
|
e
|
|
66
72
|
);
|
|
67
73
|
result = createError(resolveError(e));
|
package/dist/runtime/handler.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { rpcMethods as coreRpcMethods } from "@scayle/storefront-core";
|
|
2
|
-
import * as storefrontRpcMethods from "#
|
|
2
|
+
import * as storefrontRpcMethods from "#virtual/customRpcMethods";
|
|
3
3
|
export const handler = async (method, payload, rpcContext) => {
|
|
4
4
|
const rpcMethods = {
|
|
5
5
|
...coreRpcMethods,
|
|
@@ -5,8 +5,12 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|
|
5
5
|
const currentShop = useCurrentShop();
|
|
6
6
|
const availableShops = useAvailableShops();
|
|
7
7
|
if (import.meta.server && nuxtApp.ssrContext) {
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
if (nuxtApp.ssrContext.event.context.$currentShop) {
|
|
9
|
+
currentShop.value = nuxtApp.ssrContext.event.context.$currentShop;
|
|
10
|
+
}
|
|
11
|
+
if (nuxtApp.ssrContext.event.context.$availableShops) {
|
|
12
|
+
availableShops.value = nuxtApp.ssrContext.event.context.$availableShops;
|
|
13
|
+
}
|
|
10
14
|
}
|
|
11
15
|
return {
|
|
12
16
|
provide: {
|
|
@@ -5,7 +5,7 @@ type BootstrapPath = {
|
|
|
5
5
|
path: string;
|
|
6
6
|
originalPath: string;
|
|
7
7
|
};
|
|
8
|
-
export declare function getBootstrapPath(
|
|
8
|
+
export declare function getBootstrapPath(url: URL, baseUrl: string): BootstrapPath;
|
|
9
9
|
export declare const getShopByPath: (event: H3Event, shops: ShopConfig[], appBasePath: string) => ShopConfig | undefined;
|
|
10
10
|
export declare const convertShopsToList: (shops: ShopConfig[] | ShopConfigIndexed) => ShopConfig[];
|
|
11
11
|
export declare function getApiBasePath(storefrontConfig: ModuleBaseOptions, baseUrl: string): string;
|
|
@@ -4,9 +4,9 @@ import {
|
|
|
4
4
|
getRequestURL
|
|
5
5
|
} from "h3";
|
|
6
6
|
import { joinURL } from "ufo";
|
|
7
|
-
export function getBootstrapPath(
|
|
8
|
-
const
|
|
9
|
-
const path = url.pathname === "/__nuxt_error" ?
|
|
7
|
+
export function getBootstrapPath(url, baseUrl) {
|
|
8
|
+
const queryUrl = url.searchParams.get("url");
|
|
9
|
+
const path = url.pathname === joinURL(baseUrl, "/__nuxt_error") && queryUrl ? joinURL(baseUrl, queryUrl) : url.pathname;
|
|
10
10
|
return { path, originalPath: url.pathname };
|
|
11
11
|
}
|
|
12
12
|
const getShopByDomain = (event, shops) => {
|
|
@@ -14,7 +14,8 @@ const getShopByDomain = (event, shops) => {
|
|
|
14
14
|
return shops.find((s) => s.domain === host);
|
|
15
15
|
};
|
|
16
16
|
export const getShopByPath = (event, shops, appBasePath) => {
|
|
17
|
-
const
|
|
17
|
+
const url = getRequestURL(event);
|
|
18
|
+
const { path } = getBootstrapPath(url, appBasePath);
|
|
18
19
|
const localeIndex = appBasePath !== "/" ? 2 : 1;
|
|
19
20
|
const prefix = path.split("/")?.[localeIndex];
|
|
20
21
|
const matchesShopPrefix = (shop) => Array.isArray(shop.path) ? shop.path.includes(prefix) : shop.path === prefix;
|
|
@@ -1,13 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { PublicShopConfig } from '../../../module.js';
|
|
3
|
-
declare module 'h3' {
|
|
4
|
-
interface H3EventContext {
|
|
5
|
-
$rpcContext: RpcContext;
|
|
6
|
-
$cache: Cache;
|
|
7
|
-
$currentShop: PublicShopConfig;
|
|
8
|
-
$availableShops: PublicShopConfig[];
|
|
9
|
-
}
|
|
10
|
-
}
|
|
1
|
+
import type { ShopUser } from '@scayle/storefront-core';
|
|
11
2
|
export interface ShopSessionData {
|
|
12
3
|
user?: ShopUser;
|
|
13
4
|
accessToken?: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineEventHandler, getCookie, deleteCookie } from "h3";
|
|
1
|
+
import { defineEventHandler, getCookie, deleteCookie, getRequestURL } from "h3";
|
|
2
2
|
import { decodeJwt } from "jose";
|
|
3
3
|
import { randomUUID } from "uncrypto";
|
|
4
4
|
import {
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
unsignCookie
|
|
7
7
|
} from "@scayle/h3-session";
|
|
8
8
|
import { trace, SpanStatusCode } from "@opentelemetry/api";
|
|
9
|
+
import { joinURL } from "ufo";
|
|
9
10
|
import { buildContext } from "../../context.js";
|
|
10
11
|
import { useCacheStorage, useSessionStorage } from "../utils/cacheStorage.js";
|
|
11
12
|
import {
|
|
@@ -139,14 +140,15 @@ async function bootstrap(event, $shopConfig, $storefrontConfig, apiBasePath, con
|
|
|
139
140
|
});
|
|
140
141
|
}
|
|
141
142
|
export default defineEventHandler(async (event) => {
|
|
142
|
-
const
|
|
143
|
-
|
|
143
|
+
const config = useRuntimeConfig(event);
|
|
144
|
+
const url = getRequestURL(event);
|
|
145
|
+
const { path, originalPath } = getBootstrapPath(url, config.app.baseURL);
|
|
146
|
+
if (path.startsWith(joinURL(config.app.baseURL, "/__nuxt"))) {
|
|
144
147
|
return;
|
|
145
148
|
}
|
|
146
149
|
if (path === "/favicon.ico") {
|
|
147
150
|
return;
|
|
148
151
|
}
|
|
149
|
-
const config = useRuntimeConfig(event);
|
|
150
152
|
const $storefrontConfig = config.storefront;
|
|
151
153
|
if (path === `${$storefrontConfig.apiBasePath ?? "/api"}/up`) {
|
|
152
154
|
return;
|
|
@@ -187,7 +189,7 @@ export default defineEventHandler(async (event) => {
|
|
|
187
189
|
config
|
|
188
190
|
);
|
|
189
191
|
}
|
|
190
|
-
if ($storefrontConfig.redirects?.enabled && !path.startsWith(apiBasePath) && originalPath !== "/__nuxt_error") {
|
|
192
|
+
if ($storefrontConfig.redirects?.enabled && !path.startsWith(apiBasePath) && originalPath !== joinURL(config.app.baseURL, "/__nuxt_error")) {
|
|
191
193
|
await tracer.startActiveSpan(
|
|
192
194
|
`storefront-nuxt.middleware/redirects`,
|
|
193
195
|
{},
|
|
@@ -51,6 +51,9 @@ async function fetchRedirectWithCache(sourceUrl, storefrontAPIClient, redirectCa
|
|
|
51
51
|
return sapiResult;
|
|
52
52
|
}
|
|
53
53
|
export async function useRedirects(event) {
|
|
54
|
+
if (!event.context.$rpcContext) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
54
57
|
const config = useRuntimeConfig();
|
|
55
58
|
const $storefrontConfig = config.storefront;
|
|
56
59
|
const options = $storefrontConfig.redirects;
|
package/dist/types.d.mts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { NuxtModule } from '@nuxt/schema'
|
|
2
2
|
|
|
3
|
-
import type { default as Module, ModulePublicRuntimeConfig } from './module.js'
|
|
3
|
+
import type { default as Module, ModuleHooks, ModulePublicRuntimeConfig } from './module.js'
|
|
4
4
|
|
|
5
5
|
declare module '@nuxt/schema' {
|
|
6
|
+
interface NuxtHooks extends ModuleHooks {}
|
|
6
7
|
interface PublicRuntimeConfig extends ModulePublicRuntimeConfig {}
|
|
7
8
|
}
|
|
8
9
|
|
package/dist/types.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { NuxtModule } from '@nuxt/schema'
|
|
2
2
|
|
|
3
|
-
import type { default as Module, ModulePublicRuntimeConfig } from './module'
|
|
3
|
+
import type { default as Module, ModuleHooks, ModulePublicRuntimeConfig } from './module'
|
|
4
4
|
|
|
5
5
|
declare module '@nuxt/schema' {
|
|
6
|
+
interface NuxtHooks extends ModuleHooks {}
|
|
6
7
|
interface PublicRuntimeConfig extends ModulePublicRuntimeConfig {}
|
|
7
8
|
}
|
|
8
9
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scayle/storefront-nuxt",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "8.
|
|
4
|
+
"version": "8.7.0",
|
|
5
5
|
"description": "Nuxt integration for the SCAYLE Commerce Engine and Storefront API",
|
|
6
6
|
"author": "SCAYLE Commerce Engine",
|
|
7
7
|
"license": "MIT",
|
|
@@ -90,27 +90,27 @@
|
|
|
90
90
|
"schema-dts": "1.1.2"
|
|
91
91
|
},
|
|
92
92
|
"devDependencies": {
|
|
93
|
-
"@nuxt/eslint": "0.
|
|
93
|
+
"@nuxt/eslint": "1.0.0",
|
|
94
94
|
"@nuxt/kit": "3.14.1592",
|
|
95
95
|
"@nuxt/module-builder": "0.8.4",
|
|
96
96
|
"@nuxt/schema": "3.14.1592",
|
|
97
97
|
"@nuxt/test-utils": "3.15.4",
|
|
98
98
|
"@scayle/eslint-config-storefront": "4.4.1",
|
|
99
99
|
"@scayle/eslint-plugin-vue-composable": "0.2.1",
|
|
100
|
-
"@types/node": "22.
|
|
101
|
-
"dprint": "0.
|
|
102
|
-
"eslint": "9.
|
|
100
|
+
"@types/node": "22.13.1",
|
|
101
|
+
"dprint": "0.49.0",
|
|
102
|
+
"eslint": "9.19.0",
|
|
103
103
|
"eslint-formatter-gitlab": "5.1.0",
|
|
104
|
-
"fishery": "2.2.
|
|
104
|
+
"fishery": "2.2.3",
|
|
105
105
|
"h3": "1.14.0",
|
|
106
106
|
"nitropack": "2.9.7",
|
|
107
107
|
"node-mocks-http": "1.16.2",
|
|
108
|
-
"nuxi": "3.
|
|
108
|
+
"nuxi": "3.21.1",
|
|
109
109
|
"nuxt": "3.14.1592",
|
|
110
110
|
"publint": "0.2.12",
|
|
111
111
|
"typescript": "5.7.3",
|
|
112
112
|
"vue-tsc": "2.2.0",
|
|
113
|
-
"vitest": "2.1.
|
|
113
|
+
"vitest": "2.1.9"
|
|
114
114
|
},
|
|
115
115
|
"peerDependencies": {
|
|
116
116
|
"@nuxt/kit": "^3.12.2",
|
|
@@ -128,6 +128,6 @@
|
|
|
128
128
|
"@nuxt/schema": "3.14.1592"
|
|
129
129
|
},
|
|
130
130
|
"volta": {
|
|
131
|
-
"node": "22.13.
|
|
131
|
+
"node": "22.13.1"
|
|
132
132
|
}
|
|
133
133
|
}
|