@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.
Files changed (64) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/api/auth.ts +292 -60
  3. package/bin/pz-install-plugins.js +1 -1
  4. package/package.json +3 -3
  5. package/types/index.ts +19 -6
  6. package/types/next-auth.d.ts +1 -1
  7. package/with-pz-config.js +8 -1
  8. package/components/theme-editor/blocks/accordion-block.tsx +0 -136
  9. package/components/theme-editor/blocks/block-renderer-registry.tsx +0 -77
  10. package/components/theme-editor/blocks/button-block.tsx +0 -593
  11. package/components/theme-editor/blocks/counter-block.tsx +0 -348
  12. package/components/theme-editor/blocks/divider-block.tsx +0 -20
  13. package/components/theme-editor/blocks/embed-block.tsx +0 -208
  14. package/components/theme-editor/blocks/group-block.tsx +0 -116
  15. package/components/theme-editor/blocks/hotspot-block.tsx +0 -147
  16. package/components/theme-editor/blocks/icon-block.tsx +0 -230
  17. package/components/theme-editor/blocks/image-block.tsx +0 -137
  18. package/components/theme-editor/blocks/image-gallery-block.tsx +0 -269
  19. package/components/theme-editor/blocks/input-block.tsx +0 -123
  20. package/components/theme-editor/blocks/link-block.tsx +0 -216
  21. package/components/theme-editor/blocks/lottie-block.tsx +0 -325
  22. package/components/theme-editor/blocks/map-block.tsx +0 -89
  23. package/components/theme-editor/blocks/slider-block.tsx +0 -595
  24. package/components/theme-editor/blocks/tab-block.tsx +0 -10
  25. package/components/theme-editor/blocks/text-block.tsx +0 -52
  26. package/components/theme-editor/blocks/video-block.tsx +0 -122
  27. package/components/theme-editor/components/action-toolbar.tsx +0 -305
  28. package/components/theme-editor/components/designer-overlay.tsx +0 -74
  29. package/components/theme-editor/components/with-designer-features.tsx +0 -142
  30. package/components/theme-editor/dynamic-font-loader.tsx +0 -79
  31. package/components/theme-editor/hooks/use-designer-features.tsx +0 -100
  32. package/components/theme-editor/hooks/use-external-designer.tsx +0 -95
  33. package/components/theme-editor/hooks/use-native-widget-data.ts +0 -188
  34. package/components/theme-editor/hooks/use-visibility-context.ts +0 -27
  35. package/components/theme-editor/placeholder-registry.ts +0 -31
  36. package/components/theme-editor/sections/before-after-section.tsx +0 -245
  37. package/components/theme-editor/sections/contact-form-section.tsx +0 -563
  38. package/components/theme-editor/sections/countdown-campaign-banner-section.tsx +0 -433
  39. package/components/theme-editor/sections/coupon-banner-section.tsx +0 -710
  40. package/components/theme-editor/sections/divider-section.tsx +0 -62
  41. package/components/theme-editor/sections/featured-product-spotlight-section.tsx +0 -507
  42. package/components/theme-editor/sections/find-in-store-section.tsx +0 -1995
  43. package/components/theme-editor/sections/hover-showcase-section.tsx +0 -326
  44. package/components/theme-editor/sections/image-hotspot-section.tsx +0 -142
  45. package/components/theme-editor/sections/installment-options-section.tsx +0 -1065
  46. package/components/theme-editor/sections/notification-banner-section.tsx +0 -173
  47. package/components/theme-editor/sections/order-tracking-lookup-section.tsx +0 -1379
  48. package/components/theme-editor/sections/posts-slider-section.tsx +0 -472
  49. package/components/theme-editor/sections/pre-order-launch-banner-section.tsx +0 -663
  50. package/components/theme-editor/sections/section-renderer-registry.tsx +0 -89
  51. package/components/theme-editor/sections/section-wrapper.tsx +0 -135
  52. package/components/theme-editor/sections/shipping-threshold-progress-section.tsx +0 -586
  53. package/components/theme-editor/sections/stats-counter-section.tsx +0 -486
  54. package/components/theme-editor/sections/tabs-section.tsx +0 -578
  55. package/components/theme-editor/theme-block.tsx +0 -102
  56. package/components/theme-editor/theme-placeholder-client.tsx +0 -218
  57. package/components/theme-editor/theme-placeholder-wrapper.tsx +0 -732
  58. package/components/theme-editor/theme-placeholder.tsx +0 -288
  59. package/components/theme-editor/theme-section.tsx +0 -1224
  60. package/components/theme-editor/theme-settings-context.tsx +0 -13
  61. package/components/theme-editor/utils/index.ts +0 -792
  62. package/components/theme-editor/utils/iterator-utils.ts +0 -234
  63. package/components/theme-editor/utils/publish-window.ts +0 -86
  64. 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, CredentialsSignin } from 'next-auth';
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
- import type { NextAuthConfig } from 'next-auth';
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
- type CustomNextAuthOptions = () => Partial<NextAuthConfig>;
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
- const getDefaultAuthConfig = (): NextAuthConfig => {
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 === (credentials as any).locale
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: (credentials as any).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[(credentials as any).formType]}`,
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; // 30 days in seconds
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 = [] as AuthError[];
203
-
204
- const fieldErrors = Object.keys(response ?? {})
205
- .filter((key) => key !== 'non_field_errors')
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
- throw new PzCredentialsError(errors);
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?: CustomNextAuthOptions) => {
304
+ export const createAuth = (customOptions?: () => Partial<any>) => {
304
305
  const baseConfig = getDefaultAuthConfig();
305
306
  const customConfig = customOptions ? customOptions() : {};
306
307
 
307
- const mergedConfig: NextAuthConfig = {
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 createAuth;
564
+ export default Auth;
@@ -26,7 +26,7 @@ try {
26
26
  process.exit(1);
27
27
  }
28
28
 
29
- const protectedPackages = ['@akinon/next', 'next'];
29
+ const protectedPackages = ['@akinon/next', '@akinon/pz-theme', 'next'];
30
30
 
31
31
  const pluginsToRemove = Object.keys(packageJson.dependencies || {}).filter(
32
32
  (dep) =>
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.20",
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": "2.11.2",
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.20",
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
- // Next.js 16 async page/layout props (for exported page components and generateMetadata)
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: Promise<T & {
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: Promise<{ [key: string]: string | string[] | undefined }>;
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
- // Search params type compatible with both Next.js resolved searchParams and URLSearchParams
303
- export type SearchParams = Record<string, string | string[] | undefined> | URLSearchParams;
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> {
@@ -2,7 +2,7 @@ import 'next-auth';
2
2
 
3
3
  declare module 'next-auth' {
4
4
  interface User {
5
- id?: string;
5
+ id?: number | string;
6
6
  pk: number;
7
7
  firstName: string;
8
8
  lastName: string;
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
  };