@scayle/storefront-nuxt 7.67.1 → 7.68.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 +35 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +1 -1
- package/dist/runtime/server/middleware/bootstrap.mjs +50 -22
- package/dist/runtime/server/middleware/bootstrap.utils.d.ts +7 -1
- package/dist/runtime/server/middleware/bootstrap.utils.mjs +13 -14
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# @scayle/storefront-nuxt
|
|
2
2
|
|
|
3
|
+
## 7.68.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Use unique session cookie names for each shop
|
|
8
|
+
|
|
9
|
+
To simplify the implementation and improve the stability of session handling, we now use a differently named cookie for each shop instead of depending on the `Path` attribute.
|
|
10
|
+
|
|
11
|
+
This is a change only to the framework internals, and should not have any visible impact or require any code changes.
|
|
12
|
+
|
|
13
|
+
Before: `Set-Cookie: $session=s:fa3746f9-88c8-4065-a6c9-0c7bee473dd8.pSoaN6Q7iFHHyWKE7s9gQAqdDzGb9fS8a478P7PHLxw; Path=/de`
|
|
14
|
+
|
|
15
|
+
After: `Set-Cookie: $session-1001=s:fa3746f9-88c8-4065-a6c9-0c7bee473dd8.pSoaN6Q7iFHHyWKE7s9gQAqdDzGb9fS8a478P7PHLxw; Path=/`
|
|
16
|
+
|
|
17
|
+
When a cookie is found that uses the old format, it will be migrated to the new.
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- We stop bootstrapping requests where we can't determine a shop based on the request parameters.
|
|
22
|
+
Previously, we fell back to the first shop configuration, which has now been removed.
|
|
23
|
+
|
|
24
|
+
In this case, no `$rpcContext` is available during the request event.
|
|
25
|
+
|
|
26
|
+
We also bootstrap the Nuxt Error Page with the correct shop config now.
|
|
27
|
+
|
|
28
|
+
- Updated dependencies
|
|
29
|
+
- @scayle/h3-session@0.4.0
|
|
30
|
+
|
|
31
|
+
## 7.67.2
|
|
32
|
+
|
|
33
|
+
### Patch Changes
|
|
34
|
+
|
|
35
|
+
- Updated dependencies
|
|
36
|
+
- @scayle/storefront-core@7.49.3
|
|
37
|
+
|
|
3
38
|
## 7.67.1
|
|
4
39
|
|
|
5
40
|
### Patch Changes
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,24 +1,20 @@
|
|
|
1
|
-
import { defineEventHandler,
|
|
1
|
+
import { defineEventHandler, getCookie, deleteCookie } from "h3";
|
|
2
2
|
import { decodeJwt } from "jose";
|
|
3
3
|
import { randomUUID } from "uncrypto";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
useSession,
|
|
6
|
+
unsignCookie
|
|
7
|
+
} from "@scayle/h3-session";
|
|
5
8
|
import { buildContext } from "../../context.mjs";
|
|
6
9
|
import { useCacheStorage, useSessionStorage } from "../utils/cacheStorage.mjs";
|
|
7
10
|
import {
|
|
8
11
|
convertStoresToList,
|
|
9
|
-
|
|
10
|
-
getPublicShopData
|
|
12
|
+
getCurrentShopConfigForRequest,
|
|
13
|
+
getPublicShopData,
|
|
14
|
+
getBootstrapPath
|
|
11
15
|
} from "./bootstrap.utils.mjs";
|
|
12
16
|
import { useRedirects } from "./redirects.mjs";
|
|
13
17
|
import { useRuntimeConfig } from "#imports";
|
|
14
|
-
const getShopConfig = (event, config) => {
|
|
15
|
-
const storefrontConfig = config.storefront;
|
|
16
|
-
const $shopConfig = getCurrentShopForRequest(
|
|
17
|
-
event,
|
|
18
|
-
storefrontConfig
|
|
19
|
-
);
|
|
20
|
-
return $shopConfig;
|
|
21
|
-
};
|
|
22
18
|
const generateSessionId = (event) => {
|
|
23
19
|
let userId;
|
|
24
20
|
if (event?.context.session?.data?.accessToken) {
|
|
@@ -27,6 +23,16 @@ const generateSessionId = (event) => {
|
|
|
27
23
|
}
|
|
28
24
|
return userId ? `${userId}:${randomUUID()}` : randomUUID();
|
|
29
25
|
};
|
|
26
|
+
async function getOldSessionData(event, cookieName, store, secret) {
|
|
27
|
+
const rawCookie = getCookie(event, cookieName);
|
|
28
|
+
const normalizedSecrets = Array.isArray(secret) ? secret : [secret];
|
|
29
|
+
const sessionId = rawCookie ? await unsignCookie(rawCookie, normalizedSecrets) : null;
|
|
30
|
+
if (sessionId) {
|
|
31
|
+
const sessionData = await store.get(sessionId);
|
|
32
|
+
await store.destroy(sessionId);
|
|
33
|
+
return sessionData;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
30
36
|
async function bootstrap(event, $shopConfig, $storefrontConfig, apiBasePath, config) {
|
|
31
37
|
const log = event.context.$log;
|
|
32
38
|
const bootstrapLog = log.space("bootstrap");
|
|
@@ -53,6 +59,14 @@ async function bootstrap(event, $shopConfig, $storefrontConfig, apiBasePath, con
|
|
|
53
59
|
);
|
|
54
60
|
bootstrapLog.debug("Attaching session to request");
|
|
55
61
|
try {
|
|
62
|
+
const cookieName = sessionConfig?.cookieName ?? "$session";
|
|
63
|
+
const secret = sessionConfig?.secret ?? "current-secret";
|
|
64
|
+
const oldSessionData = await getOldSessionData(
|
|
65
|
+
event,
|
|
66
|
+
cookieName,
|
|
67
|
+
sessionStorage,
|
|
68
|
+
secret
|
|
69
|
+
);
|
|
56
70
|
await useSession(event, {
|
|
57
71
|
...sessionConfig,
|
|
58
72
|
store: sessionStorage,
|
|
@@ -62,12 +76,21 @@ async function bootstrap(event, $shopConfig, $storefrontConfig, apiBasePath, con
|
|
|
62
76
|
maxAge: sessionConfig?.maxAge,
|
|
63
77
|
// secure: sessionConfig.isHttps, TODO
|
|
64
78
|
sameSite: sessionConfig.sameSite,
|
|
65
|
-
domain: sessionConfig?.domain
|
|
66
|
-
path: $storefrontConfig.shopSelector === "path" && $shopConfig.path ? `/${$shopConfig.path}` : void 0
|
|
79
|
+
domain: sessionConfig?.domain
|
|
67
80
|
},
|
|
68
|
-
name:
|
|
69
|
-
secret
|
|
81
|
+
name: `${cookieName}-${$shopConfig.shopId}`,
|
|
82
|
+
secret
|
|
70
83
|
});
|
|
84
|
+
if (oldSessionData) {
|
|
85
|
+
event.context.session.data = oldSessionData;
|
|
86
|
+
event.context.session.save();
|
|
87
|
+
}
|
|
88
|
+
const oldSessionCookie = getCookie(event, cookieName);
|
|
89
|
+
if (oldSessionCookie) {
|
|
90
|
+
deleteCookie(event, cookieName, {
|
|
91
|
+
path: $storefrontConfig.shopSelector === "path" && $shopConfig.path ? `/${$shopConfig.path}` : void 0
|
|
92
|
+
});
|
|
93
|
+
}
|
|
71
94
|
} catch (e) {
|
|
72
95
|
bootstrapLog.error("Error attaching session: ", e);
|
|
73
96
|
}
|
|
@@ -102,11 +125,6 @@ async function bootstrap(event, $shopConfig, $storefrontConfig, apiBasePath, con
|
|
|
102
125
|
event
|
|
103
126
|
});
|
|
104
127
|
}
|
|
105
|
-
function getBootstrapPath(event) {
|
|
106
|
-
const url = getRequestURL(event);
|
|
107
|
-
const path = url.pathname === "/__nuxt_error" ? url.searchParams.get("url") ?? url.pathname : url.pathname;
|
|
108
|
-
return { path, originalPath: url.pathname };
|
|
109
|
-
}
|
|
110
128
|
export default defineEventHandler(async (event) => {
|
|
111
129
|
try {
|
|
112
130
|
const { path, originalPath } = getBootstrapPath(event);
|
|
@@ -121,7 +139,17 @@ export default defineEventHandler(async (event) => {
|
|
|
121
139
|
if (path === `${$storefrontConfig.apiBasePath ?? "/api"}/up`) {
|
|
122
140
|
return;
|
|
123
141
|
}
|
|
124
|
-
const $shopConfig =
|
|
142
|
+
const $shopConfig = getCurrentShopConfigForRequest(
|
|
143
|
+
event,
|
|
144
|
+
$storefrontConfig
|
|
145
|
+
);
|
|
146
|
+
if (!$shopConfig) {
|
|
147
|
+
event.context.$log.debug(
|
|
148
|
+
"Could not find shop config for this request",
|
|
149
|
+
path
|
|
150
|
+
);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
125
153
|
const apiBasePath = ($storefrontConfig.shopSelector === "path" && $shopConfig.path ? `/${$shopConfig.path}` : "") + ($shopConfig.apiBasePath || $storefrontConfig.apiBasePath || "/api");
|
|
126
154
|
if (!event.context.$rpcContext) {
|
|
127
155
|
event.context.$log.debug("Bootstrapping request: " + path);
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { type H3Event } from 'h3';
|
|
2
2
|
import type { ModuleOptions, PublicShopConfig, ShopConfig, ShopConfigIndexed } from '../../../module';
|
|
3
|
+
type BootstrapPath = {
|
|
4
|
+
path: string;
|
|
5
|
+
originalPath: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function getBootstrapPath(event: H3Event): BootstrapPath;
|
|
3
8
|
export declare const convertStoresToList: (stores: ShopConfig[] | ShopConfigIndexed) => ShopConfig[];
|
|
4
|
-
export declare function
|
|
9
|
+
export declare function getCurrentShopConfigForRequest(event: H3Event, config: Pick<ModuleOptions, 'stores' | 'shopSelector'>): ShopConfig | undefined;
|
|
5
10
|
export declare function getPublicShopData(data: ShopConfig, currentShopId: number, apiBasePath: string, publicShopData?: (keyof ShopConfig)[]): PublicShopConfig & {
|
|
6
11
|
isActive: boolean;
|
|
7
12
|
};
|
|
13
|
+
export {};
|
|
@@ -1,18 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
getRequestHeaders,
|
|
3
|
+
getRequestHost,
|
|
4
|
+
getRequestURL
|
|
5
|
+
} from "h3";
|
|
2
6
|
import { isArray, listify } from "radash";
|
|
7
|
+
export function getBootstrapPath(event) {
|
|
8
|
+
const url = getRequestURL(event);
|
|
9
|
+
const path = url.pathname === "/__nuxt_error" ? url.searchParams.get("url") ?? url.pathname : url.pathname;
|
|
10
|
+
return { path, originalPath: url.pathname };
|
|
11
|
+
}
|
|
3
12
|
const getStoreByDomain = (event, stores) => {
|
|
4
13
|
const host = getRequestHost(event, { xForwardedHost: true });
|
|
5
14
|
return stores.find((s) => s.domain === host);
|
|
6
15
|
};
|
|
7
16
|
const getStoreByPath = (event, stores) => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
const url = new URL(
|
|
12
|
-
event.path,
|
|
13
|
-
`https://${getRequestHost(event, { xForwardedHost: true })}`
|
|
14
|
-
);
|
|
15
|
-
const prefix = url.pathname.split("/")[1];
|
|
17
|
+
const { path } = getBootstrapPath(event);
|
|
18
|
+
const prefix = path.split("/")[1];
|
|
16
19
|
return stores.find((shop) => prefix === shop.path);
|
|
17
20
|
};
|
|
18
21
|
export const convertStoresToList = (stores) => {
|
|
@@ -21,7 +24,7 @@ export const convertStoresToList = (stores) => {
|
|
|
21
24
|
}
|
|
22
25
|
return listify(stores, (_key, value) => ({ ...value }));
|
|
23
26
|
};
|
|
24
|
-
export function
|
|
27
|
+
export function getCurrentShopConfigForRequest(event, config) {
|
|
25
28
|
let $shopConfig;
|
|
26
29
|
const { shopSelector, stores } = config;
|
|
27
30
|
const storesList = convertStoresToList(stores);
|
|
@@ -34,10 +37,6 @@ export function getCurrentShopForRequest(event, config) {
|
|
|
34
37
|
} else if (shopSelector === "path") {
|
|
35
38
|
$shopConfig = getStoreByPath(event, storesList);
|
|
36
39
|
}
|
|
37
|
-
$shopConfig = $shopConfig || storesList[0];
|
|
38
|
-
if (!$shopConfig) {
|
|
39
|
-
throw new Error("Could not find shop config");
|
|
40
|
-
}
|
|
41
40
|
return $shopConfig;
|
|
42
41
|
}
|
|
43
42
|
export function getPublicShopData(data, currentShopId, apiBasePath, publicShopData = []) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scayle/storefront-nuxt",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "7.
|
|
4
|
+
"version": "7.68.0",
|
|
5
5
|
"description": "Nuxt integration for the SCAYLE Commerce Engine and Storefront API",
|
|
6
6
|
"author": "SCAYLE Commerce Engine",
|
|
7
7
|
"license": "MIT",
|
|
@@ -62,8 +62,8 @@
|
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"@nuxt/kit": "3.11.1",
|
|
64
64
|
"@opentelemetry/api": "1.8.0",
|
|
65
|
-
"@scayle/h3-session": "0.
|
|
66
|
-
"@scayle/storefront-core": "7.49.
|
|
65
|
+
"@scayle/h3-session": "0.4.0",
|
|
66
|
+
"@scayle/storefront-core": "7.49.3",
|
|
67
67
|
"@scayle/unstorage-compression-driver": "0.1.3",
|
|
68
68
|
"@vueuse/core": "10.9.0",
|
|
69
69
|
"consola": "3.2.3",
|
|
@@ -80,23 +80,23 @@
|
|
|
80
80
|
"yn": "5.0.0"
|
|
81
81
|
},
|
|
82
82
|
"devDependencies": {
|
|
83
|
-
"@nuxt/eslint": "0.3.
|
|
83
|
+
"@nuxt/eslint": "0.3.12",
|
|
84
84
|
"@nuxt/module-builder": "0.5.5",
|
|
85
85
|
"@nuxt/schema": "3.11.1",
|
|
86
86
|
"@nuxt/test-utils": "3.12.1",
|
|
87
87
|
"@scayle/eslint-config-storefront": "4.1.0",
|
|
88
88
|
"@scayle/eslint-plugin-vue-composable": "0.1.1",
|
|
89
|
-
"@types/node": "20.12.
|
|
89
|
+
"@types/node": "20.12.10",
|
|
90
90
|
"dprint": "0.45.1",
|
|
91
|
-
"eslint": "9.
|
|
91
|
+
"eslint": "9.2.0",
|
|
92
92
|
"eslint-formatter-gitlab": "5.1.0",
|
|
93
93
|
"h3": "1.11.1",
|
|
94
94
|
"node-mocks-http": "1.14.1",
|
|
95
95
|
"nuxi": "3.11.1",
|
|
96
96
|
"nuxt": "3.11.1",
|
|
97
97
|
"publint": "0.2.7",
|
|
98
|
-
"vitest": "1.
|
|
99
|
-
"vue-tsc": "2.0.
|
|
98
|
+
"vitest": "1.6.0",
|
|
99
|
+
"vue-tsc": "2.0.17"
|
|
100
100
|
},
|
|
101
101
|
"peerDependencies": {
|
|
102
102
|
"h3": "^1.10.0",
|