@akinon/next 2.0.0-beta.20 → 2.0.0-beta.22
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 +25 -0
- package/api/auth.ts +292 -60
- package/bin/pz-install-plugins.js +1 -1
- package/package.json +3 -3
- package/types/index.ts +19 -6
- package/types/next-auth.d.ts +1 -1
- package/with-pz-config.js +8 -1
- package/components/theme-editor/blocks/accordion-block.tsx +0 -136
- package/components/theme-editor/blocks/block-renderer-registry.tsx +0 -77
- package/components/theme-editor/blocks/button-block.tsx +0 -593
- package/components/theme-editor/blocks/counter-block.tsx +0 -348
- package/components/theme-editor/blocks/divider-block.tsx +0 -20
- package/components/theme-editor/blocks/embed-block.tsx +0 -208
- package/components/theme-editor/blocks/group-block.tsx +0 -116
- package/components/theme-editor/blocks/hotspot-block.tsx +0 -147
- package/components/theme-editor/blocks/icon-block.tsx +0 -230
- package/components/theme-editor/blocks/image-block.tsx +0 -137
- package/components/theme-editor/blocks/image-gallery-block.tsx +0 -269
- package/components/theme-editor/blocks/input-block.tsx +0 -123
- package/components/theme-editor/blocks/link-block.tsx +0 -216
- package/components/theme-editor/blocks/lottie-block.tsx +0 -325
- package/components/theme-editor/blocks/map-block.tsx +0 -89
- package/components/theme-editor/blocks/slider-block.tsx +0 -595
- package/components/theme-editor/blocks/tab-block.tsx +0 -10
- package/components/theme-editor/blocks/text-block.tsx +0 -52
- package/components/theme-editor/blocks/video-block.tsx +0 -122
- package/components/theme-editor/components/action-toolbar.tsx +0 -305
- package/components/theme-editor/components/designer-overlay.tsx +0 -74
- package/components/theme-editor/components/with-designer-features.tsx +0 -142
- package/components/theme-editor/dynamic-font-loader.tsx +0 -79
- package/components/theme-editor/hooks/use-designer-features.tsx +0 -100
- package/components/theme-editor/hooks/use-external-designer.tsx +0 -95
- package/components/theme-editor/hooks/use-native-widget-data.ts +0 -188
- package/components/theme-editor/hooks/use-visibility-context.ts +0 -27
- package/components/theme-editor/placeholder-registry.ts +0 -31
- package/components/theme-editor/sections/before-after-section.tsx +0 -245
- package/components/theme-editor/sections/contact-form-section.tsx +0 -563
- package/components/theme-editor/sections/countdown-campaign-banner-section.tsx +0 -433
- package/components/theme-editor/sections/coupon-banner-section.tsx +0 -710
- package/components/theme-editor/sections/divider-section.tsx +0 -62
- package/components/theme-editor/sections/featured-product-spotlight-section.tsx +0 -507
- package/components/theme-editor/sections/find-in-store-section.tsx +0 -1995
- package/components/theme-editor/sections/hover-showcase-section.tsx +0 -326
- package/components/theme-editor/sections/image-hotspot-section.tsx +0 -142
- package/components/theme-editor/sections/installment-options-section.tsx +0 -1065
- package/components/theme-editor/sections/notification-banner-section.tsx +0 -173
- package/components/theme-editor/sections/order-tracking-lookup-section.tsx +0 -1379
- package/components/theme-editor/sections/posts-slider-section.tsx +0 -472
- package/components/theme-editor/sections/pre-order-launch-banner-section.tsx +0 -663
- package/components/theme-editor/sections/section-renderer-registry.tsx +0 -89
- package/components/theme-editor/sections/section-wrapper.tsx +0 -135
- package/components/theme-editor/sections/shipping-threshold-progress-section.tsx +0 -586
- package/components/theme-editor/sections/stats-counter-section.tsx +0 -486
- package/components/theme-editor/sections/tabs-section.tsx +0 -578
- package/components/theme-editor/theme-block.tsx +0 -102
- package/components/theme-editor/theme-placeholder-client.tsx +0 -218
- package/components/theme-editor/theme-placeholder-wrapper.tsx +0 -732
- package/components/theme-editor/theme-placeholder.tsx +0 -288
- package/components/theme-editor/theme-section.tsx +0 -1224
- package/components/theme-editor/theme-settings-context.tsx +0 -13
- package/components/theme-editor/utils/index.ts +0 -792
- package/components/theme-editor/utils/iterator-utils.ts +0 -234
- package/components/theme-editor/utils/publish-window.ts +0 -86
- package/components/theme-editor/utils/visibility-rules.ts +0 -188
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @akinon/next
|
|
2
2
|
|
|
3
|
+
## 2.0.0-beta.22
|
|
4
|
+
|
|
5
|
+
## 2.0.0-beta.21
|
|
6
|
+
|
|
7
|
+
### Patch Changes
|
|
8
|
+
|
|
9
|
+
- 5d44ff77: ZERO-4312: Extract ThemePlaceholder system into new @akinon/pz-theme package and strip native widget code
|
|
10
|
+
|
|
11
|
+
Introduce a dedicated `@akinon/pz-theme` package that contains the ThemePlaceholder system (CMS-driven sections/blocks, designer features, utilities). Remove native widget registration infrastructure from both `@akinon/pz-theme` and `projectzeronext` so the beta branch can be merged to main with only stable ThemePlaceholder functionality. Native widget integrations will be reintroduced via `@akinon/pz-theme` once they stabilize on the `theme-editor` branch.
|
|
12
|
+
|
|
13
|
+
Consumers should update imports:
|
|
14
|
+
|
|
15
|
+
- `@akinon/next/components/theme-editor/*` -> `@akinon/pz-theme/src/*`
|
|
16
|
+
- Add `@akinon/pz-theme` to package.json dependencies (matching `@akinon/next` version)
|
|
17
|
+
|
|
3
18
|
## 2.0.0-beta.20
|
|
4
19
|
|
|
5
20
|
### Minor Changes
|
|
@@ -10,6 +25,16 @@
|
|
|
10
25
|
- 1d10dde2: ZERO-3553: Add alignment style for image components
|
|
11
26
|
- 74c6a237: ZERO-3060: Drag and drop functionality on the site implemented
|
|
12
27
|
|
|
28
|
+
## 1.126.0
|
|
29
|
+
|
|
30
|
+
## 1.125.2
|
|
31
|
+
|
|
32
|
+
## 1.125.1
|
|
33
|
+
|
|
34
|
+
### Patch Changes
|
|
35
|
+
|
|
36
|
+
- 06da9a95: ZERO-4241: Upgrade Next.js from 14.2.25 to 14.2.35 to fix security vulnerabilities (CVE-2025-55184, CVE-2025-67779)
|
|
37
|
+
|
|
13
38
|
## 1.125.0
|
|
14
39
|
|
|
15
40
|
### Minor Changes
|
package/api/auth.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import NextAuth, { Session
|
|
1
|
+
import NextAuth, { Session } from 'next-auth';
|
|
2
2
|
import Credentials from 'next-auth/providers/credentials';
|
|
3
3
|
import { ROUTES } from 'routes';
|
|
4
4
|
import { URLS, user } from '../data/urls';
|
|
@@ -10,16 +10,7 @@ import getRootHostname from '../utils/get-root-hostname';
|
|
|
10
10
|
import { LocaleUrlStrategy } from '../localization';
|
|
11
11
|
import { cookies, headers } from 'next/headers';
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class PzCredentialsError extends CredentialsSignin {
|
|
16
|
-
code = 'credentials';
|
|
17
|
-
constructor(errors: AuthError[]) {
|
|
18
|
-
super();
|
|
19
|
-
this.code = JSON.stringify(errors);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
13
|
+
// Shared helper
|
|
23
14
|
async function getCurrentUser(sessionId: string, currency = '') {
|
|
24
15
|
const reqHeaders = {
|
|
25
16
|
'Content-Type': 'application/json',
|
|
@@ -52,16 +43,56 @@ async function getCurrentUser(sessionId: string, currency = '') {
|
|
|
52
43
|
};
|
|
53
44
|
}
|
|
54
45
|
|
|
55
|
-
|
|
46
|
+
// Runtime-detected error throwing: uses CredentialsSignin on v5, plain Error on v4
|
|
47
|
+
function throwAuthError(errors: AuthError[]): never {
|
|
48
|
+
const nextAuthModule = require('next-auth');
|
|
49
|
+
if (nextAuthModule.CredentialsSignin) {
|
|
50
|
+
class PzCredentialsError extends nextAuthModule.CredentialsSignin {
|
|
51
|
+
code = 'credentials';
|
|
52
|
+
constructor(errs: AuthError[]) {
|
|
53
|
+
super();
|
|
54
|
+
this.code = JSON.stringify(errs);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
throw new PzCredentialsError(errors);
|
|
58
|
+
}
|
|
59
|
+
throw new Error(JSON.stringify(errors));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Shared credential config used by both v4 and v5 error handling
|
|
63
|
+
function buildFieldErrors(response: any) {
|
|
64
|
+
const errors = [] as AuthError[];
|
|
65
|
+
|
|
66
|
+
const fieldErrors = Object.keys(response ?? {})
|
|
67
|
+
.filter((key) => key !== 'non_field_errors')
|
|
68
|
+
.map((key) => ({
|
|
69
|
+
name: key,
|
|
70
|
+
value: response[key]
|
|
71
|
+
}));
|
|
72
|
+
|
|
73
|
+
if (response.redirect_url?.includes('captcha')) {
|
|
74
|
+
errors.push({ type: 'captcha' });
|
|
75
|
+
} else if (fieldErrors.length) {
|
|
76
|
+
errors.push({ type: 'field_errors', data: fieldErrors });
|
|
77
|
+
} else if (response.non_field_errors) {
|
|
78
|
+
errors.push({ type: 'non_field_errors', data: response.non_field_errors });
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return errors;
|
|
82
|
+
}
|
|
56
83
|
|
|
57
|
-
|
|
84
|
+
// ============================================================
|
|
85
|
+
// v5 (App Router / next-auth v5) — named export for new brands
|
|
86
|
+
// ============================================================
|
|
87
|
+
|
|
88
|
+
const getDefaultAuthConfig = () => {
|
|
58
89
|
return {
|
|
59
90
|
providers: [
|
|
60
91
|
Credentials({
|
|
61
92
|
id: 'oauth',
|
|
62
93
|
name: 'credentials',
|
|
63
94
|
credentials: {},
|
|
64
|
-
authorize: async (credentials) => {
|
|
95
|
+
authorize: async (credentials: any) => {
|
|
65
96
|
const cookieStore = await cookies();
|
|
66
97
|
const sessionId = cookieStore.get('osessionid')?.value;
|
|
67
98
|
|
|
@@ -90,13 +121,13 @@ const getDefaultAuthConfig = (): NextAuthConfig => {
|
|
|
90
121
|
locale: {},
|
|
91
122
|
captchaValidated: {}
|
|
92
123
|
},
|
|
93
|
-
authorize: async (credentials) => {
|
|
124
|
+
authorize: async (credentials: any) => {
|
|
94
125
|
const cookieStore = await cookies();
|
|
95
126
|
const headerStore = await headers();
|
|
96
127
|
|
|
97
128
|
const reqHeaders: HeadersInit = new Headers();
|
|
98
129
|
const language = Settings.localization.locales.find(
|
|
99
|
-
(item) => item.value ===
|
|
130
|
+
(item: any) => item.value === credentials.locale
|
|
100
131
|
).apiValue;
|
|
101
132
|
const userIp = headerStore.get('x-forwarded-for') ?? '';
|
|
102
133
|
|
|
@@ -119,7 +150,7 @@ const getDefaultAuthConfig = (): NextAuthConfig => {
|
|
|
119
150
|
);
|
|
120
151
|
|
|
121
152
|
logger.debug('Trying to login/register', {
|
|
122
|
-
formType:
|
|
153
|
+
formType: credentials.formType,
|
|
123
154
|
userIp
|
|
124
155
|
});
|
|
125
156
|
|
|
@@ -139,7 +170,7 @@ const getDefaultAuthConfig = (): NextAuthConfig => {
|
|
|
139
170
|
}
|
|
140
171
|
|
|
141
172
|
const apiRequest = await fetch(
|
|
142
|
-
`${Settings.commerceUrl}${user[
|
|
173
|
+
`${Settings.commerceUrl}${user[credentials.formType]}`,
|
|
143
174
|
{
|
|
144
175
|
method: 'POST',
|
|
145
176
|
headers: reqHeaders,
|
|
@@ -173,7 +204,7 @@ const getDefaultAuthConfig = (): NextAuthConfig => {
|
|
|
173
204
|
}
|
|
174
205
|
|
|
175
206
|
if (sessionId) {
|
|
176
|
-
const maxAge = 30 * 24 * 60 * 60;
|
|
207
|
+
const maxAge = 30 * 24 * 60 * 60;
|
|
177
208
|
const { localeUrlStrategy } = Settings.localization;
|
|
178
209
|
|
|
179
210
|
const fallbackHost =
|
|
@@ -199,44 +230,14 @@ const getDefaultAuthConfig = (): NextAuthConfig => {
|
|
|
199
230
|
}
|
|
200
231
|
|
|
201
232
|
if (!response.key) {
|
|
202
|
-
const errors =
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
.
|
|
206
|
-
.map((key) => {
|
|
207
|
-
return {
|
|
208
|
-
name: key,
|
|
209
|
-
value: response[key]
|
|
210
|
-
};
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
if (response.redirect_url?.includes('captcha')) {
|
|
214
|
-
errors.push({
|
|
215
|
-
type: 'captcha'
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
logger.debug('Captcha required', {
|
|
219
|
-
email: (credentials as any).email,
|
|
220
|
-
formType: (credentials as any).formType
|
|
221
|
-
});
|
|
222
|
-
} else if (apiRequest.status === 202) {
|
|
223
|
-
errors.push({
|
|
224
|
-
type: 'otp'
|
|
225
|
-
});
|
|
226
|
-
} else if (fieldErrors.length) {
|
|
227
|
-
errors.push({
|
|
228
|
-
type: 'field_errors',
|
|
229
|
-
data: fieldErrors
|
|
230
|
-
});
|
|
231
|
-
} else if (response.non_field_errors) {
|
|
232
|
-
errors.push({
|
|
233
|
-
type: 'non_field_errors',
|
|
234
|
-
data: response.non_field_errors
|
|
235
|
-
});
|
|
233
|
+
const errors = buildFieldErrors(response);
|
|
234
|
+
|
|
235
|
+
if (apiRequest.status === 202) {
|
|
236
|
+
errors.push({ type: 'otp' });
|
|
236
237
|
}
|
|
237
238
|
|
|
238
239
|
if (errors.length) {
|
|
239
|
-
|
|
240
|
+
throwAuthError(errors);
|
|
240
241
|
}
|
|
241
242
|
}
|
|
242
243
|
|
|
@@ -249,14 +250,14 @@ const getDefaultAuthConfig = (): NextAuthConfig => {
|
|
|
249
250
|
})
|
|
250
251
|
],
|
|
251
252
|
callbacks: {
|
|
252
|
-
jwt: async ({ token, user }) => {
|
|
253
|
+
jwt: async ({ token, user }: any) => {
|
|
253
254
|
if (user) {
|
|
254
255
|
token.user = user;
|
|
255
256
|
}
|
|
256
257
|
|
|
257
258
|
return token;
|
|
258
259
|
},
|
|
259
|
-
async session({ session, token }) {
|
|
260
|
+
async session({ session, token }: any) {
|
|
260
261
|
session.user = token.user as any;
|
|
261
262
|
return session;
|
|
262
263
|
},
|
|
@@ -300,11 +301,11 @@ const getDefaultAuthConfig = (): NextAuthConfig => {
|
|
|
300
301
|
};
|
|
301
302
|
};
|
|
302
303
|
|
|
303
|
-
export const createAuth = (customOptions?:
|
|
304
|
+
export const createAuth = (customOptions?: () => Partial<any>) => {
|
|
304
305
|
const baseConfig = getDefaultAuthConfig();
|
|
305
306
|
const customConfig = customOptions ? customOptions() : {};
|
|
306
307
|
|
|
307
|
-
const mergedConfig
|
|
308
|
+
const mergedConfig = {
|
|
308
309
|
trustHost: true,
|
|
309
310
|
...baseConfig,
|
|
310
311
|
...customConfig,
|
|
@@ -326,7 +327,238 @@ export const createAuth = (customOptions?: CustomNextAuthOptions) => {
|
|
|
326
327
|
}
|
|
327
328
|
};
|
|
328
329
|
|
|
329
|
-
return NextAuth(mergedConfig);
|
|
330
|
+
return (NextAuth as any)(mergedConfig);
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
// ============================================================
|
|
334
|
+
// v4 (Pages Router / next-auth v4) — default export for backward compat
|
|
335
|
+
// ============================================================
|
|
336
|
+
|
|
337
|
+
const defaultNextAuthOptionsV4 = (req: any, res: any) => {
|
|
338
|
+
return {
|
|
339
|
+
providers: [
|
|
340
|
+
Credentials({
|
|
341
|
+
id: 'oauth',
|
|
342
|
+
name: 'credentials',
|
|
343
|
+
credentials: {},
|
|
344
|
+
authorize: async () => {
|
|
345
|
+
const sessionId = req.cookies['osessionid'];
|
|
346
|
+
|
|
347
|
+
if (!sessionId) {
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const currentUser = await getCurrentUser(
|
|
352
|
+
sessionId,
|
|
353
|
+
req.cookies['pz-currency'] ?? ''
|
|
354
|
+
);
|
|
355
|
+
return currentUser;
|
|
356
|
+
}
|
|
357
|
+
}),
|
|
358
|
+
Credentials({
|
|
359
|
+
id: 'default',
|
|
360
|
+
name: 'credentials',
|
|
361
|
+
credentials: {
|
|
362
|
+
email: { label: 'Email', type: 'email', placeholder: 'Email' },
|
|
363
|
+
password: {
|
|
364
|
+
label: 'Password',
|
|
365
|
+
type: 'password',
|
|
366
|
+
placeholder: 'Password'
|
|
367
|
+
},
|
|
368
|
+
formType: {},
|
|
369
|
+
locale: {},
|
|
370
|
+
captchaValidated: {}
|
|
371
|
+
},
|
|
372
|
+
authorize: async (credentials: any) => {
|
|
373
|
+
const reqHeaders: HeadersInit = new Headers();
|
|
374
|
+
const language = Settings.localization.locales.find(
|
|
375
|
+
(item: any) => item.value === credentials.locale
|
|
376
|
+
).apiValue;
|
|
377
|
+
const userIp = req.headers['x-forwarded-for']?.toString() ?? '';
|
|
378
|
+
|
|
379
|
+
reqHeaders.set('Content-Type', 'application/json');
|
|
380
|
+
reqHeaders.set('cookie', `${req.headers.cookie}`);
|
|
381
|
+
reqHeaders.set('Accept-Language', `${language}`);
|
|
382
|
+
reqHeaders.set('x-currency', req.cookies['pz-currency'] ?? '');
|
|
383
|
+
reqHeaders.set('x-forwarded-for', userIp);
|
|
384
|
+
reqHeaders.set(
|
|
385
|
+
'x-app-device',
|
|
386
|
+
req.headers['x-app-device']?.toString() ?? ''
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
reqHeaders.set('x-frontend-id', req.cookies['pz-frontend-id'] || '');
|
|
390
|
+
|
|
391
|
+
logger.debug('Trying to login/register', {
|
|
392
|
+
formType: credentials.formType,
|
|
393
|
+
userIp
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
const checkCurrentUser = await getCurrentUser(
|
|
397
|
+
req.cookies['osessionid'] ?? '',
|
|
398
|
+
req.cookies['pz-currency'] ?? ''
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
if (checkCurrentUser?.pk) {
|
|
402
|
+
const sessionCookie = reqHeaders
|
|
403
|
+
.get('cookie')
|
|
404
|
+
?.match(/osessionid=\w+/)?.[0]
|
|
405
|
+
.replace(/osessionid=/, '');
|
|
406
|
+
if (sessionCookie) {
|
|
407
|
+
reqHeaders.set('cookie', sessionCookie);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const apiRequest = await fetch(
|
|
412
|
+
`${Settings.commerceUrl}${user[credentials.formType]}`,
|
|
413
|
+
{
|
|
414
|
+
method: 'POST',
|
|
415
|
+
headers: reqHeaders,
|
|
416
|
+
body: JSON.stringify(credentials)
|
|
417
|
+
}
|
|
418
|
+
);
|
|
419
|
+
|
|
420
|
+
logger.info(`Login/Register request result: ${apiRequest.status}`, {
|
|
421
|
+
userIp
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
const response = (await apiRequest.json()) as {
|
|
425
|
+
key: string;
|
|
426
|
+
non_field_errors: string[];
|
|
427
|
+
redirect_url: string;
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
logger.debug(`Login/Register response: ${JSON.stringify(response)}`);
|
|
431
|
+
|
|
432
|
+
let sessionId = '';
|
|
433
|
+
const setCookieHeader = apiRequest.headers.get('set-cookie');
|
|
434
|
+
if (setCookieHeader) {
|
|
435
|
+
sessionId =
|
|
436
|
+
setCookieHeader
|
|
437
|
+
.match(/osessionid=\w+/)?.[0]
|
|
438
|
+
.replace(/osessionid=/, '') || '';
|
|
439
|
+
|
|
440
|
+
logger.debug(`Login/Register session id: ${sessionId}`);
|
|
441
|
+
} else {
|
|
442
|
+
logger.warn('No set-cookie header found in response');
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (sessionId) {
|
|
446
|
+
const maxAge = 30 * 24 * 60 * 60;
|
|
447
|
+
const { localeUrlStrategy } = Settings.localization;
|
|
448
|
+
|
|
449
|
+
const fallbackHost =
|
|
450
|
+
req.headers['x-forwarded-host']?.toString() ||
|
|
451
|
+
req.headers.host?.toString();
|
|
452
|
+
const hostname =
|
|
453
|
+
process.env.NEXT_PUBLIC_URL || `https://${fallbackHost}`;
|
|
454
|
+
const rootHostname =
|
|
455
|
+
localeUrlStrategy === LocaleUrlStrategy.Subdomain
|
|
456
|
+
? getRootHostname(hostname)
|
|
457
|
+
: null;
|
|
458
|
+
const domainOption = rootHostname ? `Domain=${rootHostname};` : '';
|
|
459
|
+
const cookieOptions = `Path=/; HttpOnly; Secure; Max-Age=${maxAge}; ${domainOption}`;
|
|
460
|
+
|
|
461
|
+
res.setHeader('Set-Cookie', [
|
|
462
|
+
`osessionid=${sessionId}; ${cookieOptions}`,
|
|
463
|
+
`sessionid=${sessionId}; ${cookieOptions}`
|
|
464
|
+
]);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
if (!response.key) {
|
|
468
|
+
const errors = buildFieldErrors(response);
|
|
469
|
+
|
|
470
|
+
if (apiRequest.status === 202) {
|
|
471
|
+
errors.push({ type: 'otp' });
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
if (errors.length) {
|
|
475
|
+
throwAuthError(errors);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const currentUser = await getCurrentUser(
|
|
480
|
+
sessionId,
|
|
481
|
+
req.cookies['pz-currency'] ?? ''
|
|
482
|
+
);
|
|
483
|
+
return currentUser;
|
|
484
|
+
}
|
|
485
|
+
})
|
|
486
|
+
],
|
|
487
|
+
callbacks: {
|
|
488
|
+
jwt: async ({ token, user }: any) => {
|
|
489
|
+
if (user) {
|
|
490
|
+
token.user = user;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
return token;
|
|
494
|
+
},
|
|
495
|
+
async session({ session, user, token }: any) {
|
|
496
|
+
session.user = token.user as Session['user'];
|
|
497
|
+
return session;
|
|
498
|
+
},
|
|
499
|
+
async redirect({ url, baseUrl }: { url: string; baseUrl: string }) {
|
|
500
|
+
const pathname = url.startsWith('/') ? url : url.replace(baseUrl, '');
|
|
501
|
+
const pathnameWithoutLocale = pathname.replace(
|
|
502
|
+
urlLocaleMatcherRegex,
|
|
503
|
+
''
|
|
504
|
+
);
|
|
505
|
+
|
|
506
|
+
const localeResults = req.headers.referer
|
|
507
|
+
?.replace(baseUrl, '')
|
|
508
|
+
?.match(urlLocaleMatcherRegex);
|
|
509
|
+
|
|
510
|
+
return `${baseUrl}${localeResults?.[0] || ''}${pathnameWithoutLocale}`;
|
|
511
|
+
}
|
|
512
|
+
},
|
|
513
|
+
events: {
|
|
514
|
+
signIn: () => {
|
|
515
|
+
logger.debug('Successfully signed in');
|
|
516
|
+
},
|
|
517
|
+
signOut: () => {
|
|
518
|
+
res.setHeader('Set-Cookie', [
|
|
519
|
+
`osessionid=; Path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT`,
|
|
520
|
+
`sessionid=; Path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT`
|
|
521
|
+
]);
|
|
522
|
+
logger.debug('Successfully signed out');
|
|
523
|
+
}
|
|
524
|
+
},
|
|
525
|
+
pages: {
|
|
526
|
+
signIn: ROUTES.AUTH,
|
|
527
|
+
error: ROUTES.AUTH
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
const Auth = (
|
|
533
|
+
req: any,
|
|
534
|
+
res: any,
|
|
535
|
+
customOptions?: (req: any, res: any) => Partial<any>
|
|
536
|
+
) => {
|
|
537
|
+
const baseOptions = defaultNextAuthOptionsV4(req, res);
|
|
538
|
+
const customOptionsResult = customOptions ? customOptions(req, res) : {};
|
|
539
|
+
|
|
540
|
+
const mergedOptions = {
|
|
541
|
+
...baseOptions,
|
|
542
|
+
...customOptionsResult,
|
|
543
|
+
providers: [
|
|
544
|
+
...baseOptions.providers,
|
|
545
|
+
...(customOptionsResult.providers || [])
|
|
546
|
+
],
|
|
547
|
+
callbacks: {
|
|
548
|
+
...baseOptions.callbacks,
|
|
549
|
+
...customOptionsResult.callbacks
|
|
550
|
+
},
|
|
551
|
+
events: {
|
|
552
|
+
...baseOptions.events,
|
|
553
|
+
...customOptionsResult.events
|
|
554
|
+
},
|
|
555
|
+
pages: {
|
|
556
|
+
...baseOptions.pages,
|
|
557
|
+
...customOptionsResult.pages
|
|
558
|
+
}
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
return (NextAuth as any)(req, res, mergedOptions);
|
|
330
562
|
};
|
|
331
563
|
|
|
332
|
-
export default
|
|
564
|
+
export default Auth;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akinon/next",
|
|
3
3
|
"description": "Core package for Project Zero Next",
|
|
4
|
-
"version": "2.0.0-beta.
|
|
4
|
+
"version": "2.0.0-beta.22",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"bin": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"@opentelemetry/sdk-node": "0.46.0",
|
|
25
25
|
"@opentelemetry/sdk-trace-node": "1.19.0",
|
|
26
26
|
"@opentelemetry/semantic-conventions": "1.19.0",
|
|
27
|
-
"@reduxjs/toolkit": "
|
|
27
|
+
"@reduxjs/toolkit": "1.9.7",
|
|
28
28
|
"@sentry/nextjs": "10.39.0",
|
|
29
29
|
"cross-spawn": "7.0.3",
|
|
30
30
|
"generic-pool": "3.9.0",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"set-cookie-parser": "2.6.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@akinon/eslint-plugin-projectzero": "2.0.0-beta.
|
|
40
|
+
"@akinon/eslint-plugin-projectzero": "2.0.0-beta.22",
|
|
41
41
|
"@babel/core": "7.26.10",
|
|
42
42
|
"@babel/preset-env": "7.26.9",
|
|
43
43
|
"@babel/preset-typescript": "7.27.0",
|
package/types/index.ts
CHANGED
|
@@ -275,17 +275,20 @@ export interface PzSegmentsConfig {
|
|
|
275
275
|
segments: PzSegmentDefinition[];
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
-
//
|
|
278
|
+
// Search params type compatible with both Next.js resolved searchParams and URLSearchParams
|
|
279
|
+
export type SearchParams = Record<string, string | string[] | undefined> | URLSearchParams;
|
|
280
|
+
|
|
281
|
+
// Page/Layout props — sync params for backward compatibility with v1 brands
|
|
279
282
|
export interface PageProps<T = any> {
|
|
280
|
-
params:
|
|
283
|
+
params: T & {
|
|
281
284
|
pz?: string;
|
|
282
285
|
commerce?: string;
|
|
283
286
|
locale?: string;
|
|
284
287
|
currency?: string;
|
|
285
288
|
url?: string;
|
|
286
289
|
[key: string]: any;
|
|
287
|
-
}
|
|
288
|
-
searchParams:
|
|
290
|
+
};
|
|
291
|
+
searchParams: SearchParams;
|
|
289
292
|
}
|
|
290
293
|
|
|
291
294
|
export interface LayoutProps<T = any> extends PageProps<T> {
|
|
@@ -299,8 +302,18 @@ export interface RootLayoutProps<T = any> extends LayoutProps<T> {
|
|
|
299
302
|
};
|
|
300
303
|
}
|
|
301
304
|
|
|
302
|
-
//
|
|
303
|
-
export
|
|
305
|
+
// Async versions for Next.js 16 generateMetadata and internal use
|
|
306
|
+
export interface AsyncPageProps<T = any> {
|
|
307
|
+
params: Promise<T & {
|
|
308
|
+
pz?: string;
|
|
309
|
+
commerce?: string;
|
|
310
|
+
locale?: string;
|
|
311
|
+
currency?: string;
|
|
312
|
+
url?: string;
|
|
313
|
+
[key: string]: any;
|
|
314
|
+
}>;
|
|
315
|
+
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
|
|
316
|
+
}
|
|
304
317
|
|
|
305
318
|
// Resolved (sync) versions for inner components after withSegmentDefaults resolves props
|
|
306
319
|
export interface ResolvedPageProps<T = any> {
|
package/types/next-auth.d.ts
CHANGED
package/with-pz-config.js
CHANGED
|
@@ -5,7 +5,7 @@ const deepMerge = require('./utils/deep-merge');
|
|
|
5
5
|
/** @type {import('next').NextConfig} */
|
|
6
6
|
const defaultConfig = {
|
|
7
7
|
reactStrictMode: true,
|
|
8
|
-
transpilePackages: ['@akinon/next', ...pzPlugins.map((p) => `@akinon/${p}`)],
|
|
8
|
+
transpilePackages: ['@akinon/next', '@akinon/pz-theme', ...pzPlugins.map((p) => `@akinon/${p}`)],
|
|
9
9
|
skipTrailingSlashRedirect: true,
|
|
10
10
|
poweredByHeader: false,
|
|
11
11
|
cacheMaxMemorySize: 0,
|
|
@@ -70,6 +70,13 @@ const defaultConfig = {
|
|
|
70
70
|
}, {}),
|
|
71
71
|
translations: false
|
|
72
72
|
};
|
|
73
|
+
// Ensure webpack can resolve deps from the app's node_modules when
|
|
74
|
+
// compiling transpiled packages (e.g. @akinon/next) whose imports
|
|
75
|
+
// may not be hoisted to the monorepo root.
|
|
76
|
+
const appNodeModules = path.resolve(process.cwd(), 'node_modules');
|
|
77
|
+
if (!config.resolve.modules.includes(appNodeModules)) {
|
|
78
|
+
config.resolve.modules.push(appNodeModules);
|
|
79
|
+
}
|
|
73
80
|
return config;
|
|
74
81
|
}
|
|
75
82
|
};
|