payload 4.0.0-internal.d927017 → 4.0.0-internal.e387174

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.
@@ -44,6 +44,14 @@ export type RouterAdapterRouter = {
44
44
  replace: (path: string, options?: {
45
45
  scroll?: boolean;
46
46
  }) => void;
47
+ /**
48
+ * Use this property to standardize behaviors across different router implementations.
49
+ * Set it up to sync client state to the URL without triggering a second server load.
50
+ *
51
+ * In Next.js, calling `window.history.replaceState` directly is sufficient, as Next.js does not observe history mutations.
52
+ * In TanStack Router, however, `history.replaceState` is monkeypatched to notify the router of changes.
53
+ */
54
+ replaceState?: (url: string) => void;
47
55
  };
48
56
  export type LinkAdapterProps = {
49
57
  children?: React.ReactNode;
@@ -1 +1 @@
1
- {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../../src/admin/adapters/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,MAAM,sBAAsB,GAAG,KAAK,CAAC,aAAa,CAAC;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,CAAC,CAAA;AAEvF,MAAM,MAAM,mBAAmB,GAAG;IAChC;;OAEG;IACH,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB;;OAEG;IACH,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAA;IAC5D;;OAEG;IACH,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB;;OAEG;IACH,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAA;CAChE,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAA;IAClC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,GAAG,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC,CAAA"}
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../../src/admin/adapters/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,MAAM,sBAAsB,GAAG,KAAK,CAAC,aAAa,CAAC;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,CAAC,CAAA;AAEvF,MAAM,MAAM,mBAAmB,GAAG;IAChC;;OAEG;IACH,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB;;OAEG;IACH,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAA;IAC5D;;OAEG;IACH,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB;;OAEG;IACH,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAA;IAC/D;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CACrC,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAA;IAClC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,GAAG,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/admin/adapters/router.ts"],"sourcesContent":["import type React from 'react'\n\n/**\n * Client-side router adapter to abstract away framework-specific routing implementations.\n * This way plugins and server components can use server-only APIs without directly importing any framework-specific modules.\n *\n * @example\n * ```tsx\n * // Next.js router adapter (simplified):\n * import { useRouter as useNextRouter, usePathname as useNextPathname } from 'next/navigation'\n *\n * const NextRouterAdapter: RouterAdapterComponent = ({ children }) => {\n * const router = useNextRouter()\n * const pathname = useNextPathname()\n *\n * return (\n * <RouterAdapterContext value={{ router, pathname, ... }}>\n * {children}\n * </RouterAdapterContext>\n * )\n * }\n * ```\n */\nexport type RouterAdapterComponent = React.ComponentType<{ children: React.ReactNode }>\n\nexport type RouterAdapterRouter = {\n /**\n * Navigate back to the previous page in the history stack.\n */\n back: () => void\n /**\n * Navigate to a new path.\n */\n push: (path: string, options?: { scroll?: boolean }) => void\n /**\n * Refresh the current route.\n */\n refresh: () => void\n /**\n * Replace the current path with a new one.\n */\n replace: (path: string, options?: { scroll?: boolean }) => void\n}\n\nexport type LinkAdapterProps = {\n children?: React.ReactNode\n href: string\n prefetch?: boolean\n ref?: React.Ref<HTMLAnchorElement>\n replace?: boolean\n scroll?: boolean\n} & Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'href'>\n"],"names":[],"mappings":"AA4CA,WAO+D"}
1
+ {"version":3,"sources":["../../../src/admin/adapters/router.ts"],"sourcesContent":["import type React from 'react'\n\n/**\n * Client-side router adapter to abstract away framework-specific routing implementations.\n * This way plugins and server components can use server-only APIs without directly importing any framework-specific modules.\n *\n * @example\n * ```tsx\n * // Next.js router adapter (simplified):\n * import { useRouter as useNextRouter, usePathname as useNextPathname } from 'next/navigation'\n *\n * const NextRouterAdapter: RouterAdapterComponent = ({ children }) => {\n * const router = useNextRouter()\n * const pathname = useNextPathname()\n *\n * return (\n * <RouterAdapterContext value={{ router, pathname, ... }}>\n * {children}\n * </RouterAdapterContext>\n * )\n * }\n * ```\n */\nexport type RouterAdapterComponent = React.ComponentType<{ children: React.ReactNode }>\n\nexport type RouterAdapterRouter = {\n /**\n * Navigate back to the previous page in the history stack.\n */\n back: () => void\n /**\n * Navigate to a new path.\n */\n push: (path: string, options?: { scroll?: boolean }) => void\n /**\n * Refresh the current route.\n */\n refresh: () => void\n /**\n * Replace the current path with a new one.\n */\n replace: (path: string, options?: { scroll?: boolean }) => void\n /**\n * Use this property to standardize behaviors across different router implementations.\n * Set it up to sync client state to the URL without triggering a second server load.\n *\n * In Next.js, calling `window.history.replaceState` directly is sufficient, as Next.js does not observe history mutations.\n * In TanStack Router, however, `history.replaceState` is monkeypatched to notify the router of changes.\n */\n replaceState?: (url: string) => void\n}\n\nexport type LinkAdapterProps = {\n children?: React.ReactNode\n href: string\n prefetch?: boolean\n ref?: React.Ref<HTMLAnchorElement>\n replace?: boolean\n scroll?: boolean\n} & Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'href'>\n"],"names":[],"mappings":"AAoDA,WAO+D"}
@@ -1,25 +1,49 @@
1
1
  import type { SanitizedConfig } from '../config/types.js';
2
+ type Framework = 'next' | 'tanstack-start';
2
3
  /**
3
4
  * `payload build` — generate the import map (and types) so they are on disk
4
- * before `next build` statically imports them, then run the project's Next.js
5
- * build, forwarding any extra CLI args verbatim.
5
+ * before the framework build statically imports them, then detect the project's
6
+ * framework (Next.js or TanStack Start) and run its build, forwarding any extra
7
+ * CLI args verbatim.
6
8
  *
7
- * Owns its own process lifecycle: it exits with `next build`'s exit code, or
8
- * exits 1 if pre-build generation fails (never builds against a stale map).
9
+ * Owns its own process lifecycle: it exits with the framework build's exit code,
10
+ * or exits 1 if pre-build generation or framework detection fails (never builds
11
+ * against a stale map or the wrong bundler).
9
12
  */
10
13
  export declare function build({ config }: {
11
14
  config: SanitizedConfig;
12
15
  }): Promise<void>;
13
16
  /**
14
- * Resolve the project's `next` binary from its own manifest, robust to a future
15
- * `exports` field and to internal layout changes. Resolving from `cwd` (not
16
- * PATH) works whether `payload build` runs via an npm script or `npx`.
17
+ * Determine whether the project builds with Next.js or TanStack Start. An explicit
18
+ * `PAYLOAD_FRAMEWORK` env wins; otherwise tries the most intentional signals first
19
+ * declared dependencies, then framework config files, then Payload's
20
+ * admin-route folder conventions — falling through when a layer is inconclusive.
21
+ * Throws with guidance for an unsupported override or when no single framework can
22
+ * be determined.
17
23
  */
24
+ export declare function detectFramework(cwd?: string): Framework;
25
+ /** Resolve the project's `next` binary — see {@link resolveBin}. */
18
26
  export declare function resolveNextBin(cwd?: string): string;
27
+ /** Resolve the project's `vite` binary — see {@link resolveBin}. */
28
+ export declare function resolveViteBin(cwd?: string): string;
19
29
  /**
20
- * Forward the raw args that follow the `build` subcommand to `next build`,
21
- * dropping payload-only flags. Uses raw argv (not minimist) so flags like
22
- * `--turbopack` or `--experimental-build-mode` pass through verbatim.
30
+ * Map a detected framework to the resolved binary and argument list to spawn.
31
+ * Both frameworks take the `build` subcommand followed by the forwarded args.
32
+ */
33
+ export declare function resolveBuildCommand({ cwd, forwardedArgs, framework, }: {
34
+ cwd?: string;
35
+ forwardedArgs: string[];
36
+ framework: Framework;
37
+ }): {
38
+ args: string[];
39
+ bin: string;
40
+ };
41
+ /**
42
+ * Forward the raw args that follow the `build` subcommand to the framework build
43
+ * (`next build` / `vite build`), dropping payload-only flags. Uses raw argv (not
44
+ * minimist) so flags like `--turbopack` (Next) or `--mode staging` (Vite) pass
45
+ * through verbatim.
23
46
  */
24
47
  export declare function getForwardedArgs(argv?: string[]): string[];
48
+ export {};
25
49
  //# sourceMappingURL=build.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/bin/build.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAKzD;;;;;;;GAOG;AACH,wBAAsB,KAAK,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,eAAe,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgClF;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,CAmBlE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,GAAE,MAAM,EAA0B,GAAG,MAAM,EAAE,CAIjF"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/bin/build.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAMzD,KAAK,SAAS,GAAG,MAAM,GAAG,gBAAgB,CAAA;AAY1C;;;;;;;;;GASG;AACH,wBAAsB,KAAK,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,eAAe,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuClF;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAsB,GAAG,SAAS,CAuDtE;AAED,oEAAoE;AACpE,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,CAElE;AAED,oEAAoE;AACpE,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,CAElE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,GAAmB,EACnB,aAAa,EACb,SAAS,GACV,EAAE;IACD,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,SAAS,EAAE,SAAS,CAAA;CACrB,GAAG;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAGlC;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,GAAE,MAAM,EAA0B,GAAG,MAAM,EAAE,CAIjF"}
package/dist/bin/build.js CHANGED
@@ -1,16 +1,33 @@
1
1
  /* eslint-disable no-console */ import { spawn } from 'node:child_process';
2
- import { readFileSync } from 'node:fs';
2
+ import fs, { readFileSync } from 'node:fs';
3
3
  import { createRequire } from 'node:module';
4
4
  import path from 'node:path';
5
+ import { NEXT_PAYLOAD_ROUTE_GROUP, TANSTACK_PAYLOAD_DIR } from './frameworkConventions.js';
5
6
  import { generateImportMap } from './generateImportMap/index.js';
6
7
  import { generateTypes } from './generateTypes.js';
8
+ const NEXT_CONFIG_FILES = [
9
+ 'next.config.js',
10
+ 'next.config.ts',
11
+ 'next.config.mjs',
12
+ 'next.config.cjs'
13
+ ];
14
+ const VITE_CONFIG_FILES = [
15
+ 'vite.config.js',
16
+ 'vite.config.ts',
17
+ 'vite.config.mjs',
18
+ 'vite.config.cjs',
19
+ 'vite.config.cts',
20
+ 'vite.config.mts'
21
+ ];
7
22
  /**
8
23
  * `payload build` — generate the import map (and types) so they are on disk
9
- * before `next build` statically imports them, then run the project's Next.js
10
- * build, forwarding any extra CLI args verbatim.
24
+ * before the framework build statically imports them, then detect the project's
25
+ * framework (Next.js or TanStack Start) and run its build, forwarding any extra
26
+ * CLI args verbatim.
11
27
  *
12
- * Owns its own process lifecycle: it exits with `next build`'s exit code, or
13
- * exits 1 if pre-build generation fails (never builds against a stale map).
28
+ * Owns its own process lifecycle: it exits with the framework build's exit code,
29
+ * or exits 1 if pre-build generation or framework detection fails (never builds
30
+ * against a stale map or the wrong bundler).
14
31
  */ export async function build({ config }) {
15
32
  const skipTypes = process.argv.includes('--no-types');
16
33
  try {
@@ -27,18 +44,27 @@ import { generateTypes } from './generateTypes.js';
27
44
  console.error(err);
28
45
  return process.exit(1);
29
46
  }
30
- const nextBin = resolveNextBin();
31
- const forwardedArgs = getForwardedArgs();
47
+ let bin;
48
+ let args;
49
+ try {
50
+ const framework = detectFramework();
51
+ ({ args, bin } = resolveBuildCommand({
52
+ forwardedArgs: getForwardedArgs(),
53
+ framework
54
+ }));
55
+ } catch (err) {
56
+ console.error(err instanceof Error ? err.message : err);
57
+ return process.exit(1);
58
+ }
32
59
  const exitCode = await new Promise((resolve)=>{
33
60
  const child = spawn(process.execPath, [
34
- nextBin,
35
- 'build',
36
- ...forwardedArgs
61
+ bin,
62
+ ...args
37
63
  ], {
38
64
  stdio: 'inherit'
39
65
  });
40
66
  child.on('error', (err)=>{
41
- console.error('Failed to run next build:');
67
+ console.error('Failed to run build:');
42
68
  console.error(err);
43
69
  resolve(1);
44
70
  });
@@ -49,32 +75,152 @@ import { generateTypes } from './generateTypes.js';
49
75
  process.exit(exitCode);
50
76
  }
51
77
  /**
52
- * Resolve the project's `next` binary from its own manifest, robust to a future
53
- * `exports` field and to internal layout changes. Resolving from `cwd` (not
54
- * PATH) works whether `payload build` runs via an npm script or `npx`.
55
- */ export function resolveNextBin(cwd = process.cwd()) {
56
- const require = createRequire(path.join(cwd, 'package.json'));
57
- let nextPkgPath;
58
- try {
59
- nextPkgPath = require.resolve('next/package.json');
60
- } catch {
61
- throw new Error('Could not resolve "next" from the current project. Is Next.js installed?');
78
+ * Determine whether the project builds with Next.js or TanStack Start. An explicit
79
+ * `PAYLOAD_FRAMEWORK` env wins; otherwise tries the most intentional signals first
80
+ * declared dependencies, then framework config files, then Payload's
81
+ * admin-route folder conventions falling through when a layer is inconclusive.
82
+ * Throws with guidance for an unsupported override or when no single framework can
83
+ * be determined.
84
+ */ export function detectFramework(cwd = process.cwd()) {
85
+ const override = process.env.PAYLOAD_FRAMEWORK;
86
+ if (override) {
87
+ if (isFramework(override)) {
88
+ return override;
89
+ }
90
+ throw new Error(`PAYLOAD_FRAMEWORK is set to "${override}", which is not supported. Use one of: next, tanstack-start.`);
62
91
  }
63
- const nextPkg = JSON.parse(readFileSync(nextPkgPath, 'utf8'));
64
- const binField = typeof nextPkg.bin === 'string' ? nextPkg.bin : nextPkg.bin?.next;
65
- if (!binField) {
66
- throw new Error('Could not determine the "next" binary path from next/package.json.');
92
+ const deps = readProjectDependencies(cwd);
93
+ const hasNextDep = Boolean(deps.next);
94
+ const hasTanstackDep = Boolean(deps['@tanstack/react-start']);
95
+ if (hasNextDep && !hasTanstackDep) {
96
+ return 'next';
67
97
  }
68
- return path.join(path.dirname(nextPkgPath), binField);
98
+ if (hasTanstackDep && !hasNextDep) {
99
+ return 'tanstack-start';
100
+ }
101
+ const hasNextConfig = NEXT_CONFIG_FILES.some((file)=>fs.existsSync(path.join(cwd, file)));
102
+ const hasViteConfig = VITE_CONFIG_FILES.some((file)=>fs.existsSync(path.join(cwd, file)));
103
+ if (hasNextConfig && !hasViteConfig) {
104
+ return 'next';
105
+ }
106
+ if (hasViteConfig && !hasNextConfig) {
107
+ return 'tanstack-start';
108
+ }
109
+ const hasNextFolder = [
110
+ path.join(cwd, 'app', NEXT_PAYLOAD_ROUTE_GROUP),
111
+ path.join(cwd, 'src', 'app', NEXT_PAYLOAD_ROUTE_GROUP)
112
+ ].some((dir)=>fs.existsSync(dir));
113
+ const hasTanstackFolder = [
114
+ path.join(cwd, 'app', TANSTACK_PAYLOAD_DIR),
115
+ path.join(cwd, 'src', 'app', TANSTACK_PAYLOAD_DIR)
116
+ ].some((dir)=>fs.existsSync(dir));
117
+ if (hasNextFolder && !hasTanstackFolder) {
118
+ return 'next';
119
+ }
120
+ if (hasTanstackFolder && !hasNextFolder) {
121
+ return 'tanstack-start';
122
+ }
123
+ throw new Error(buildDetectionError({
124
+ hasNextConfig,
125
+ hasNextDep,
126
+ hasNextFolder,
127
+ hasTanstackDep,
128
+ hasTanstackFolder,
129
+ hasViteConfig
130
+ }));
131
+ }
132
+ /** Resolve the project's `next` binary — see {@link resolveBin}. */ export function resolveNextBin(cwd = process.cwd()) {
133
+ return resolveBin({
134
+ cwd,
135
+ displayName: 'Next.js',
136
+ packageName: 'next'
137
+ });
138
+ }
139
+ /** Resolve the project's `vite` binary — see {@link resolveBin}. */ export function resolveViteBin(cwd = process.cwd()) {
140
+ return resolveBin({
141
+ cwd,
142
+ displayName: 'Vite',
143
+ packageName: 'vite'
144
+ });
145
+ }
146
+ /**
147
+ * Map a detected framework to the resolved binary and argument list to spawn.
148
+ * Both frameworks take the `build` subcommand followed by the forwarded args.
149
+ */ export function resolveBuildCommand({ cwd = process.cwd(), forwardedArgs, framework }) {
150
+ const bin = framework === 'next' ? resolveNextBin(cwd) : resolveViteBin(cwd);
151
+ return {
152
+ args: [
153
+ 'build',
154
+ ...forwardedArgs
155
+ ],
156
+ bin
157
+ };
69
158
  }
70
159
  /**
71
- * Forward the raw args that follow the `build` subcommand to `next build`,
72
- * dropping payload-only flags. Uses raw argv (not minimist) so flags like
73
- * `--turbopack` or `--experimental-build-mode` pass through verbatim.
160
+ * Forward the raw args that follow the `build` subcommand to the framework build
161
+ * (`next build` / `vite build`), dropping payload-only flags. Uses raw argv (not
162
+ * minimist) so flags like `--turbopack` (Next) or `--mode staging` (Vite) pass
163
+ * through verbatim.
74
164
  */ export function getForwardedArgs(argv = process.argv.slice(2)) {
75
165
  const buildIndex = argv.indexOf('build');
76
166
  const rest = buildIndex === -1 ? argv : argv.slice(buildIndex + 1);
77
167
  return rest.filter((arg)=>arg !== '--no-types');
78
168
  }
169
+ function isFramework(value) {
170
+ return value === 'next' || value === 'tanstack-start';
171
+ }
172
+ function readProjectDependencies(cwd) {
173
+ try {
174
+ const pkg = JSON.parse(readFileSync(path.join(cwd, 'package.json'), 'utf8'));
175
+ return {
176
+ ...pkg.dependencies,
177
+ ...pkg.devDependencies
178
+ };
179
+ } catch {
180
+ return {};
181
+ }
182
+ }
183
+ function buildDetectionError(signals) {
184
+ const conflicts = [];
185
+ if (signals.hasNextDep && signals.hasTanstackDep) {
186
+ conflicts.push('dependencies (`next` and `@tanstack/react-start`)');
187
+ }
188
+ if (signals.hasNextConfig && signals.hasViteConfig) {
189
+ conflicts.push('config files (next.config.* and vite.config.*)');
190
+ }
191
+ if (signals.hasNextFolder && signals.hasTanstackFolder) {
192
+ conflicts.push('app folders (app/(payload) and app/_payload)');
193
+ }
194
+ if (conflicts.length) {
195
+ return `Could not determine your framework for \`payload build\`: conflicting signals found in ${conflicts.join(', ')}. Resolve the conflict so only one framework is indicated.`;
196
+ }
197
+ return [
198
+ 'Could not determine your framework for `payload build`.',
199
+ 'Checked:',
200
+ ' • dependencies: no `next` or `@tanstack/react-start` in package.json',
201
+ ' • config files: no next.config.* or vite.config.*',
202
+ ' • app folders: no app/(payload) or app/_payload',
203
+ 'Install your framework (Next.js or TanStack Start) and try again.'
204
+ ].join('\n');
205
+ }
206
+ /**
207
+ * Resolve a framework's binary path from its own package manifest, robust to a
208
+ * future `exports` field and to internal layout changes. Resolving from `cwd`
209
+ * (not PATH) works whether `payload build` runs via an npm script or `npx`.
210
+ */ function resolveBin({ cwd, displayName, packageName }) {
211
+ const require = createRequire(path.join(cwd, 'package.json'));
212
+ let pkgPath;
213
+ try {
214
+ pkgPath = require.resolve(`${packageName}/package.json`);
215
+ } catch {
216
+ throw new Error(`Could not resolve "${packageName}" from the current project. Is ${displayName} installed?`);
217
+ }
218
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
219
+ const binField = typeof pkg.bin === 'string' ? pkg.bin : pkg.bin?.[packageName];
220
+ if (!binField) {
221
+ throw new Error(`Could not determine the "${packageName}" binary path from ${packageName}/package.json.`);
222
+ }
223
+ return path.join(path.dirname(pkgPath), binField);
224
+ }
79
225
 
80
226
  //# sourceMappingURL=build.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/bin/build.ts"],"sourcesContent":["/* eslint-disable no-console */\nimport { spawn } from 'node:child_process'\nimport { readFileSync } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport path from 'node:path'\n\nimport type { SanitizedConfig } from '../config/types.js'\n\nimport { generateImportMap } from './generateImportMap/index.js'\nimport { generateTypes } from './generateTypes.js'\n\n/**\n * `payload build` — generate the import map (and types) so they are on disk\n * before `next build` statically imports them, then run the project's Next.js\n * build, forwarding any extra CLI args verbatim.\n *\n * Owns its own process lifecycle: it exits with `next build`'s exit code, or\n * exits 1 if pre-build generation fails (never builds against a stale map).\n */\nexport async function build({ config }: { config: SanitizedConfig }): Promise<void> {\n const skipTypes = process.argv.includes('--no-types')\n\n try {\n await generateImportMap(config, { log: true })\n if (!skipTypes) {\n await generateTypes(config, { log: true })\n }\n } catch (err) {\n console.error('Pre-build generation failed:')\n console.error(err)\n return process.exit(1)\n }\n\n const nextBin = resolveNextBin()\n const forwardedArgs = getForwardedArgs()\n\n const exitCode = await new Promise<number>((resolve) => {\n const child = spawn(process.execPath, [nextBin, 'build', ...forwardedArgs], {\n stdio: 'inherit',\n })\n child.on('error', (err) => {\n console.error('Failed to run next build:')\n console.error(err)\n resolve(1)\n })\n child.on('exit', (code) => {\n resolve(code ?? 0)\n })\n })\n\n process.exit(exitCode)\n}\n\n/**\n * Resolve the project's `next` binary from its own manifest, robust to a future\n * `exports` field and to internal layout changes. Resolving from `cwd` (not\n * PATH) works whether `payload build` runs via an npm script or `npx`.\n */\nexport function resolveNextBin(cwd: string = process.cwd()): string {\n const require = createRequire(path.join(cwd, 'package.json'))\n\n let nextPkgPath: string\n try {\n nextPkgPath = require.resolve('next/package.json')\n } catch {\n throw new Error('Could not resolve \"next\" from the current project. Is Next.js installed?')\n }\n\n const nextPkg = JSON.parse(readFileSync(nextPkgPath, 'utf8')) as {\n bin?: Record<string, string> | string\n }\n const binField = typeof nextPkg.bin === 'string' ? nextPkg.bin : nextPkg.bin?.next\n if (!binField) {\n throw new Error('Could not determine the \"next\" binary path from next/package.json.')\n }\n\n return path.join(path.dirname(nextPkgPath), binField)\n}\n\n/**\n * Forward the raw args that follow the `build` subcommand to `next build`,\n * dropping payload-only flags. Uses raw argv (not minimist) so flags like\n * `--turbopack` or `--experimental-build-mode` pass through verbatim.\n */\nexport function getForwardedArgs(argv: string[] = process.argv.slice(2)): string[] {\n const buildIndex = argv.indexOf('build')\n const rest = buildIndex === -1 ? argv : argv.slice(buildIndex + 1)\n return rest.filter((arg) => arg !== '--no-types')\n}\n"],"names":["spawn","readFileSync","createRequire","path","generateImportMap","generateTypes","build","config","skipTypes","process","argv","includes","log","err","console","error","exit","nextBin","resolveNextBin","forwardedArgs","getForwardedArgs","exitCode","Promise","resolve","child","execPath","stdio","on","code","cwd","require","join","nextPkgPath","Error","nextPkg","JSON","parse","binField","bin","next","dirname","slice","buildIndex","indexOf","rest","filter","arg"],"mappings":"AAAA,6BAA6B,GAC7B,SAASA,KAAK,QAAQ,qBAAoB;AAC1C,SAASC,YAAY,QAAQ,UAAS;AACtC,SAASC,aAAa,QAAQ,cAAa;AAC3C,OAAOC,UAAU,YAAW;AAI5B,SAASC,iBAAiB,QAAQ,+BAA8B;AAChE,SAASC,aAAa,QAAQ,qBAAoB;AAElD;;;;;;;CAOC,GACD,OAAO,eAAeC,MAAM,EAAEC,MAAM,EAA+B;IACjE,MAAMC,YAAYC,QAAQC,IAAI,CAACC,QAAQ,CAAC;IAExC,IAAI;QACF,MAAMP,kBAAkBG,QAAQ;YAAEK,KAAK;QAAK;QAC5C,IAAI,CAACJ,WAAW;YACd,MAAMH,cAAcE,QAAQ;gBAAEK,KAAK;YAAK;QAC1C;IACF,EAAE,OAAOC,KAAK;QACZC,QAAQC,KAAK,CAAC;QACdD,QAAQC,KAAK,CAACF;QACd,OAAOJ,QAAQO,IAAI,CAAC;IACtB;IAEA,MAAMC,UAAUC;IAChB,MAAMC,gBAAgBC;IAEtB,MAAMC,WAAW,MAAM,IAAIC,QAAgB,CAACC;QAC1C,MAAMC,QAAQxB,MAAMS,QAAQgB,QAAQ,EAAE;YAACR;YAAS;eAAYE;SAAc,EAAE;YAC1EO,OAAO;QACT;QACAF,MAAMG,EAAE,CAAC,SAAS,CAACd;YACjBC,QAAQC,KAAK,CAAC;YACdD,QAAQC,KAAK,CAACF;YACdU,QAAQ;QACV;QACAC,MAAMG,EAAE,CAAC,QAAQ,CAACC;YAChBL,QAAQK,QAAQ;QAClB;IACF;IAEAnB,QAAQO,IAAI,CAACK;AACf;AAEA;;;;CAIC,GACD,OAAO,SAASH,eAAeW,MAAcpB,QAAQoB,GAAG,EAAE;IACxD,MAAMC,UAAU5B,cAAcC,KAAK4B,IAAI,CAACF,KAAK;IAE7C,IAAIG;IACJ,IAAI;QACFA,cAAcF,QAAQP,OAAO,CAAC;IAChC,EAAE,OAAM;QACN,MAAM,IAAIU,MAAM;IAClB;IAEA,MAAMC,UAAUC,KAAKC,KAAK,CAACnC,aAAa+B,aAAa;IAGrD,MAAMK,WAAW,OAAOH,QAAQI,GAAG,KAAK,WAAWJ,QAAQI,GAAG,GAAGJ,QAAQI,GAAG,EAAEC;IAC9E,IAAI,CAACF,UAAU;QACb,MAAM,IAAIJ,MAAM;IAClB;IAEA,OAAO9B,KAAK4B,IAAI,CAAC5B,KAAKqC,OAAO,CAACR,cAAcK;AAC9C;AAEA;;;;CAIC,GACD,OAAO,SAASjB,iBAAiBV,OAAiBD,QAAQC,IAAI,CAAC+B,KAAK,CAAC,EAAE;IACrE,MAAMC,aAAahC,KAAKiC,OAAO,CAAC;IAChC,MAAMC,OAAOF,eAAe,CAAC,IAAIhC,OAAOA,KAAK+B,KAAK,CAACC,aAAa;IAChE,OAAOE,KAAKC,MAAM,CAAC,CAACC,MAAQA,QAAQ;AACtC"}
1
+ {"version":3,"sources":["../../src/bin/build.ts"],"sourcesContent":["/* eslint-disable no-console */\nimport { spawn } from 'node:child_process'\nimport fs, { readFileSync } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport path from 'node:path'\n\nimport type { SanitizedConfig } from '../config/types.js'\n\nimport { NEXT_PAYLOAD_ROUTE_GROUP, TANSTACK_PAYLOAD_DIR } from './frameworkConventions.js'\nimport { generateImportMap } from './generateImportMap/index.js'\nimport { generateTypes } from './generateTypes.js'\n\ntype Framework = 'next' | 'tanstack-start'\n\nconst NEXT_CONFIG_FILES = ['next.config.js', 'next.config.ts', 'next.config.mjs', 'next.config.cjs']\nconst VITE_CONFIG_FILES = [\n 'vite.config.js',\n 'vite.config.ts',\n 'vite.config.mjs',\n 'vite.config.cjs',\n 'vite.config.cts',\n 'vite.config.mts',\n]\n\n/**\n * `payload build` — generate the import map (and types) so they are on disk\n * before the framework build statically imports them, then detect the project's\n * framework (Next.js or TanStack Start) and run its build, forwarding any extra\n * CLI args verbatim.\n *\n * Owns its own process lifecycle: it exits with the framework build's exit code,\n * or exits 1 if pre-build generation or framework detection fails (never builds\n * against a stale map or the wrong bundler).\n */\nexport async function build({ config }: { config: SanitizedConfig }): Promise<void> {\n const skipTypes = process.argv.includes('--no-types')\n\n try {\n await generateImportMap(config, { log: true })\n if (!skipTypes) {\n await generateTypes(config, { log: true })\n }\n } catch (err) {\n console.error('Pre-build generation failed:')\n console.error(err)\n return process.exit(1)\n }\n\n let bin: string\n let args: string[]\n try {\n const framework = detectFramework()\n ;({ args, bin } = resolveBuildCommand({ forwardedArgs: getForwardedArgs(), framework }))\n } catch (err) {\n console.error(err instanceof Error ? err.message : err)\n return process.exit(1)\n }\n\n const exitCode = await new Promise<number>((resolve) => {\n const child = spawn(process.execPath, [bin, ...args], {\n stdio: 'inherit',\n })\n child.on('error', (err) => {\n console.error('Failed to run build:')\n console.error(err)\n resolve(1)\n })\n child.on('exit', (code) => {\n resolve(code ?? 0)\n })\n })\n\n process.exit(exitCode)\n}\n\n/**\n * Determine whether the project builds with Next.js or TanStack Start. An explicit\n * `PAYLOAD_FRAMEWORK` env wins; otherwise tries the most intentional signals first\n * — declared dependencies, then framework config files, then Payload's\n * admin-route folder conventions — falling through when a layer is inconclusive.\n * Throws with guidance for an unsupported override or when no single framework can\n * be determined.\n */\nexport function detectFramework(cwd: string = process.cwd()): Framework {\n const override = process.env.PAYLOAD_FRAMEWORK\n if (override) {\n if (isFramework(override)) {\n return override\n }\n throw new Error(\n `PAYLOAD_FRAMEWORK is set to \"${override}\", which is not supported. Use one of: next, tanstack-start.`,\n )\n }\n\n const deps = readProjectDependencies(cwd)\n const hasNextDep = Boolean(deps.next)\n const hasTanstackDep = Boolean(deps['@tanstack/react-start'])\n if (hasNextDep && !hasTanstackDep) {\n return 'next'\n }\n if (hasTanstackDep && !hasNextDep) {\n return 'tanstack-start'\n }\n\n const hasNextConfig = NEXT_CONFIG_FILES.some((file) => fs.existsSync(path.join(cwd, file)))\n const hasViteConfig = VITE_CONFIG_FILES.some((file) => fs.existsSync(path.join(cwd, file)))\n if (hasNextConfig && !hasViteConfig) {\n return 'next'\n }\n if (hasViteConfig && !hasNextConfig) {\n return 'tanstack-start'\n }\n\n const hasNextFolder = [\n path.join(cwd, 'app', NEXT_PAYLOAD_ROUTE_GROUP),\n path.join(cwd, 'src', 'app', NEXT_PAYLOAD_ROUTE_GROUP),\n ].some((dir) => fs.existsSync(dir))\n const hasTanstackFolder = [\n path.join(cwd, 'app', TANSTACK_PAYLOAD_DIR),\n path.join(cwd, 'src', 'app', TANSTACK_PAYLOAD_DIR),\n ].some((dir) => fs.existsSync(dir))\n if (hasNextFolder && !hasTanstackFolder) {\n return 'next'\n }\n if (hasTanstackFolder && !hasNextFolder) {\n return 'tanstack-start'\n }\n\n throw new Error(\n buildDetectionError({\n hasNextConfig,\n hasNextDep,\n hasNextFolder,\n hasTanstackDep,\n hasTanstackFolder,\n hasViteConfig,\n }),\n )\n}\n\n/** Resolve the project's `next` binary — see {@link resolveBin}. */\nexport function resolveNextBin(cwd: string = process.cwd()): string {\n return resolveBin({ cwd, displayName: 'Next.js', packageName: 'next' })\n}\n\n/** Resolve the project's `vite` binary — see {@link resolveBin}. */\nexport function resolveViteBin(cwd: string = process.cwd()): string {\n return resolveBin({ cwd, displayName: 'Vite', packageName: 'vite' })\n}\n\n/**\n * Map a detected framework to the resolved binary and argument list to spawn.\n * Both frameworks take the `build` subcommand followed by the forwarded args.\n */\nexport function resolveBuildCommand({\n cwd = process.cwd(),\n forwardedArgs,\n framework,\n}: {\n cwd?: string\n forwardedArgs: string[]\n framework: Framework\n}): { args: string[]; bin: string } {\n const bin = framework === 'next' ? resolveNextBin(cwd) : resolveViteBin(cwd)\n return { args: ['build', ...forwardedArgs], bin }\n}\n\n/**\n * Forward the raw args that follow the `build` subcommand to the framework build\n * (`next build` / `vite build`), dropping payload-only flags. Uses raw argv (not\n * minimist) so flags like `--turbopack` (Next) or `--mode staging` (Vite) pass\n * through verbatim.\n */\nexport function getForwardedArgs(argv: string[] = process.argv.slice(2)): string[] {\n const buildIndex = argv.indexOf('build')\n const rest = buildIndex === -1 ? argv : argv.slice(buildIndex + 1)\n return rest.filter((arg) => arg !== '--no-types')\n}\n\nfunction isFramework(value: string): value is Framework {\n return value === 'next' || value === 'tanstack-start'\n}\n\nfunction readProjectDependencies(cwd: string): Record<string, string> {\n try {\n const pkg = JSON.parse(readFileSync(path.join(cwd, 'package.json'), 'utf8')) as {\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n }\n return { ...pkg.dependencies, ...pkg.devDependencies }\n } catch {\n return {}\n }\n}\n\nfunction buildDetectionError(signals: {\n hasNextConfig: boolean\n hasNextDep: boolean\n hasNextFolder: boolean\n hasTanstackDep: boolean\n hasTanstackFolder: boolean\n hasViteConfig: boolean\n}): string {\n const conflicts: string[] = []\n if (signals.hasNextDep && signals.hasTanstackDep) {\n conflicts.push('dependencies (`next` and `@tanstack/react-start`)')\n }\n if (signals.hasNextConfig && signals.hasViteConfig) {\n conflicts.push('config files (next.config.* and vite.config.*)')\n }\n if (signals.hasNextFolder && signals.hasTanstackFolder) {\n conflicts.push('app folders (app/(payload) and app/_payload)')\n }\n\n if (conflicts.length) {\n return `Could not determine your framework for \\`payload build\\`: conflicting signals found in ${conflicts.join(', ')}. Resolve the conflict so only one framework is indicated.`\n }\n\n return [\n 'Could not determine your framework for `payload build`.',\n 'Checked:',\n ' • dependencies: no `next` or `@tanstack/react-start` in package.json',\n ' • config files: no next.config.* or vite.config.*',\n ' • app folders: no app/(payload) or app/_payload',\n 'Install your framework (Next.js or TanStack Start) and try again.',\n ].join('\\n')\n}\n\n/**\n * Resolve a framework's binary path from its own package manifest, robust to a\n * future `exports` field and to internal layout changes. Resolving from `cwd`\n * (not PATH) works whether `payload build` runs via an npm script or `npx`.\n */\nfunction resolveBin({\n cwd,\n displayName,\n packageName,\n}: {\n cwd: string\n displayName: string\n packageName: string\n}): string {\n const require = createRequire(path.join(cwd, 'package.json'))\n\n let pkgPath: string\n try {\n pkgPath = require.resolve(`${packageName}/package.json`)\n } catch {\n throw new Error(\n `Could not resolve \"${packageName}\" from the current project. Is ${displayName} installed?`,\n )\n }\n\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as {\n bin?: Record<string, string> | string\n }\n const binField = typeof pkg.bin === 'string' ? pkg.bin : pkg.bin?.[packageName]\n if (!binField) {\n throw new Error(\n `Could not determine the \"${packageName}\" binary path from ${packageName}/package.json.`,\n )\n }\n\n return path.join(path.dirname(pkgPath), binField)\n}\n"],"names":["spawn","fs","readFileSync","createRequire","path","NEXT_PAYLOAD_ROUTE_GROUP","TANSTACK_PAYLOAD_DIR","generateImportMap","generateTypes","NEXT_CONFIG_FILES","VITE_CONFIG_FILES","build","config","skipTypes","process","argv","includes","log","err","console","error","exit","bin","args","framework","detectFramework","resolveBuildCommand","forwardedArgs","getForwardedArgs","Error","message","exitCode","Promise","resolve","child","execPath","stdio","on","code","cwd","override","env","PAYLOAD_FRAMEWORK","isFramework","deps","readProjectDependencies","hasNextDep","Boolean","next","hasTanstackDep","hasNextConfig","some","file","existsSync","join","hasViteConfig","hasNextFolder","dir","hasTanstackFolder","buildDetectionError","resolveNextBin","resolveBin","displayName","packageName","resolveViteBin","slice","buildIndex","indexOf","rest","filter","arg","value","pkg","JSON","parse","dependencies","devDependencies","signals","conflicts","push","length","require","pkgPath","binField","dirname"],"mappings":"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"}
@@ -1,3 +1,6 @@
1
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
1
4
  import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';
2
5
  // Default fake child auto-fires `exit(0)` synchronously so ordering/generation
3
6
  // tests resolve. Specific tests override via `mockReturnValueOnce` to drive the
@@ -22,7 +25,7 @@ vi.mock('./generateTypes.js', ()=>({
22
25
  generateTypes: generateTypesMock
23
26
  }));
24
27
  // Imported after mocks are registered
25
- const { build, getForwardedArgs, resolveNextBin } = await import('./build.js');
28
+ const { build, detectFramework, getForwardedArgs, resolveBuildCommand, resolveNextBin, resolveViteBin } = await import('./build.js');
26
29
  const fakeConfig = {};
27
30
  describe('getForwardedArgs', ()=>{
28
31
  it('returns args after the build token and strips --no-types', ()=>{
@@ -52,9 +55,73 @@ describe('resolveNextBin', ()=>{
52
55
  expect(()=>resolveNextBin('/nonexistent-project-root')).toThrow(/next/i);
53
56
  });
54
57
  });
58
+ describe('resolveViteBin', ()=>{
59
+ it('resolves the vite bin from the current project', ()=>{
60
+ // vite is installed at the repo root; resolving from cwd must succeed
61
+ const binPath = resolveViteBin(process.cwd());
62
+ expect(binPath).toMatch(/vite[\\/].*bin[\\/]vite\.js$/);
63
+ });
64
+ it('throws a clear error when vite cannot be resolved', async ()=>{
65
+ // Vitest injects its own transitive `vite` dep onto NODE_PATH, so resolving
66
+ // "vite" from any cwd would otherwise succeed in this test process even
67
+ // when the project under test has no vite installed. Mock module
68
+ // resolution itself to simulate a real "vite not installed" project.
69
+ vi.resetModules();
70
+ vi.doMock('node:module', async (importOriginal)=>{
71
+ const actual = await importOriginal();
72
+ return {
73
+ ...actual,
74
+ createRequire: ()=>({
75
+ resolve: ()=>{
76
+ throw new Error('Cannot find module');
77
+ }
78
+ })
79
+ };
80
+ });
81
+ const { resolveViteBin: resolveViteBinWithoutVite } = await import('./build.js');
82
+ expect(()=>resolveViteBinWithoutVite('/nonexistent-project-root')).toThrow(/vite/i);
83
+ vi.doUnmock('node:module');
84
+ vi.resetModules();
85
+ });
86
+ });
87
+ describe('resolveBuildCommand', ()=>{
88
+ it('maps next to the next bin and build args', ()=>{
89
+ const { args, bin } = resolveBuildCommand({
90
+ cwd: process.cwd(),
91
+ forwardedArgs: [
92
+ '--turbopack'
93
+ ],
94
+ framework: 'next'
95
+ });
96
+ expect(bin).toMatch(/next[\\/].*bin[\\/]next$/);
97
+ expect(args).toEqual([
98
+ 'build',
99
+ '--turbopack'
100
+ ]);
101
+ });
102
+ it('maps tanstack-start to the vite bin and build args', ()=>{
103
+ const { args, bin } = resolveBuildCommand({
104
+ cwd: process.cwd(),
105
+ forwardedArgs: [
106
+ '--mode',
107
+ 'staging'
108
+ ],
109
+ framework: 'tanstack-start'
110
+ });
111
+ expect(bin).toMatch(/vite[\\/].*bin[\\/]vite\.js$/);
112
+ expect(args).toEqual([
113
+ 'build',
114
+ '--mode',
115
+ 'staging'
116
+ ]);
117
+ });
118
+ });
55
119
  describe('build', ()=>{
56
120
  let exitMock;
57
121
  let originalArgv;
122
+ let originalFrameworkEnv;
123
+ let cwdSpy;
124
+ const buildTempDirs = [];
58
125
  beforeEach(()=>{
59
126
  spawnMock.mockClear();
60
127
  generateImportMapMock.mockClear();
@@ -66,10 +133,30 @@ describe('build', ()=>{
66
133
  'build'
67
134
  ];
68
135
  exitMock = vi.spyOn(process, 'exit').mockImplementation(()=>undefined);
136
+ originalFrameworkEnv = process.env.PAYLOAD_FRAMEWORK;
137
+ // Force next for the legacy tests so they don't depend on the repo-root
138
+ // package.json's ambient `next` dependency for auto-detection.
139
+ process.env.PAYLOAD_FRAMEWORK = 'next';
69
140
  });
70
141
  afterEach(()=>{
71
142
  process.argv = originalArgv;
72
143
  exitMock.mockRestore();
144
+ if (originalFrameworkEnv === undefined) {
145
+ delete process.env.PAYLOAD_FRAMEWORK;
146
+ } else {
147
+ process.env.PAYLOAD_FRAMEWORK = originalFrameworkEnv;
148
+ }
149
+ if (cwdSpy) {
150
+ cwdSpy.mockRestore();
151
+ cwdSpy = undefined;
152
+ }
153
+ for (const dir of buildTempDirs){
154
+ rmSync(dir, {
155
+ force: true,
156
+ recursive: true
157
+ });
158
+ }
159
+ buildTempDirs.length = 0;
73
160
  });
74
161
  it('generates the import map before spawning, and generates types by default', async ()=>{
75
162
  await build({
@@ -165,6 +252,254 @@ describe('build', ()=>{
165
252
  expect(resolved).toBe(true);
166
253
  expect(exitMock).toHaveBeenCalledWith(3);
167
254
  });
255
+ it('spawns vite build for a detected tanstack project', async ()=>{
256
+ delete process.env.PAYLOAD_FRAMEWORK;
257
+ process.argv = [
258
+ 'node',
259
+ 'payload',
260
+ 'build',
261
+ '--mode',
262
+ 'staging'
263
+ ];
264
+ const tanstackDir = mkdtempSync(path.join(os.tmpdir(), 'payload-build-ts-'));
265
+ buildTempDirs.push(tanstackDir);
266
+ writeFileSync(path.join(tanstackDir, 'package.json'), JSON.stringify({
267
+ dependencies: {
268
+ '@tanstack/react-start': '1.168.26'
269
+ }
270
+ }));
271
+ cwdSpy = vi.spyOn(process, 'cwd').mockReturnValue(tanstackDir);
272
+ await build({
273
+ config: fakeConfig
274
+ });
275
+ expect(spawnMock).toHaveBeenCalledTimes(1);
276
+ const [, spawnArgs] = spawnMock.mock.calls[0];
277
+ expect(spawnArgs[0]).toMatch(/vite[\\/].*bin[\\/]vite\.js$/);
278
+ expect(spawnArgs.slice(1)).toEqual([
279
+ 'build',
280
+ '--mode',
281
+ 'staging'
282
+ ]);
283
+ });
284
+ it('exits 1 and does not spawn when the framework cannot be detected', async ()=>{
285
+ delete process.env.PAYLOAD_FRAMEWORK;
286
+ const emptyDir = mkdtempSync(path.join(os.tmpdir(), 'payload-build-empty-'));
287
+ buildTempDirs.push(emptyDir);
288
+ writeFileSync(path.join(emptyDir, 'package.json'), JSON.stringify({}));
289
+ cwdSpy = vi.spyOn(process, 'cwd').mockReturnValue(emptyDir);
290
+ await build({
291
+ config: fakeConfig
292
+ });
293
+ expect(exitMock).toHaveBeenCalledWith(1);
294
+ expect(spawnMock).not.toHaveBeenCalled();
295
+ });
296
+ });
297
+ describe('detectFramework', ()=>{
298
+ const createdDirs = [];
299
+ let originalFrameworkEnv;
300
+ const makeProject = (files)=>{
301
+ const dir = mkdtempSync(path.join(os.tmpdir(), 'payload-build-'));
302
+ createdDirs.push(dir);
303
+ for (const file of files){
304
+ const full = path.join(dir, file.path);
305
+ mkdirSync(path.dirname(full), {
306
+ recursive: true
307
+ });
308
+ writeFileSync(full, file.contents ?? '');
309
+ }
310
+ return dir;
311
+ };
312
+ const pkg = (deps)=>JSON.stringify({
313
+ dependencies: deps
314
+ });
315
+ beforeEach(()=>{
316
+ originalFrameworkEnv = process.env.PAYLOAD_FRAMEWORK;
317
+ delete process.env.PAYLOAD_FRAMEWORK;
318
+ });
319
+ afterEach(()=>{
320
+ if (originalFrameworkEnv === undefined) {
321
+ delete process.env.PAYLOAD_FRAMEWORK;
322
+ } else {
323
+ process.env.PAYLOAD_FRAMEWORK = originalFrameworkEnv;
324
+ }
325
+ for (const dir of createdDirs){
326
+ rmSync(dir, {
327
+ force: true,
328
+ recursive: true
329
+ });
330
+ }
331
+ createdDirs.length = 0;
332
+ });
333
+ it('honors PAYLOAD_FRAMEWORK=tanstack-start over auto-detection', ()=>{
334
+ process.env.PAYLOAD_FRAMEWORK = 'tanstack-start';
335
+ const dir = makeProject([
336
+ {
337
+ contents: pkg({
338
+ next: '15.0.0'
339
+ }),
340
+ path: 'package.json'
341
+ }
342
+ ]);
343
+ expect(detectFramework(dir)).toBe('tanstack-start');
344
+ });
345
+ it('honors PAYLOAD_FRAMEWORK=next over auto-detection', ()=>{
346
+ process.env.PAYLOAD_FRAMEWORK = 'next';
347
+ const dir = makeProject([
348
+ {
349
+ contents: pkg({
350
+ '@tanstack/react-start': '1.168.26'
351
+ }),
352
+ path: 'package.json'
353
+ }
354
+ ]);
355
+ expect(detectFramework(dir)).toBe('next');
356
+ });
357
+ it('throws when PAYLOAD_FRAMEWORK is an unsupported value', ()=>{
358
+ process.env.PAYLOAD_FRAMEWORK = 'svelte';
359
+ const dir = makeProject([
360
+ {
361
+ contents: pkg({
362
+ next: '15.0.0'
363
+ }),
364
+ path: 'package.json'
365
+ }
366
+ ]);
367
+ expect(()=>detectFramework(dir)).toThrow(/PAYLOAD_FRAMEWORK/);
368
+ });
369
+ it('detects next from the next dependency', ()=>{
370
+ const dir = makeProject([
371
+ {
372
+ contents: pkg({
373
+ next: '15.0.0'
374
+ }),
375
+ path: 'package.json'
376
+ }
377
+ ]);
378
+ expect(detectFramework(dir)).toBe('next');
379
+ });
380
+ it('detects tanstack-start from the @tanstack/react-start dependency', ()=>{
381
+ const dir = makeProject([
382
+ {
383
+ contents: pkg({
384
+ '@tanstack/react-start': '1.168.26'
385
+ }),
386
+ path: 'package.json'
387
+ }
388
+ ]);
389
+ expect(detectFramework(dir)).toBe('tanstack-start');
390
+ });
391
+ it('falls back to next.config when deps are inconclusive', ()=>{
392
+ const dir = makeProject([
393
+ {
394
+ contents: pkg({}),
395
+ path: 'package.json'
396
+ },
397
+ {
398
+ path: 'next.config.ts'
399
+ }
400
+ ]);
401
+ expect(detectFramework(dir)).toBe('next');
402
+ });
403
+ it('falls back to vite.config when deps are inconclusive', ()=>{
404
+ const dir = makeProject([
405
+ {
406
+ contents: pkg({}),
407
+ path: 'package.json'
408
+ },
409
+ {
410
+ path: 'vite.config.ts'
411
+ }
412
+ ]);
413
+ expect(detectFramework(dir)).toBe('tanstack-start');
414
+ });
415
+ it('falls back to the (payload) folder convention', ()=>{
416
+ const dir = makeProject([
417
+ {
418
+ path: 'app/(payload)/admin/page.tsx'
419
+ }
420
+ ]);
421
+ expect(detectFramework(dir)).toBe('next');
422
+ });
423
+ it('falls back to the _payload folder convention', ()=>{
424
+ const dir = makeProject([
425
+ {
426
+ path: 'app/_payload/route.tsx'
427
+ }
428
+ ]);
429
+ expect(detectFramework(dir)).toBe('tanstack-start');
430
+ });
431
+ it('resolves ambiguous deps using the config-file layer', ()=>{
432
+ const dir = makeProject([
433
+ {
434
+ contents: pkg({
435
+ '@tanstack/react-start': '1.168.26',
436
+ next: '15.0.0'
437
+ }),
438
+ path: 'package.json'
439
+ },
440
+ {
441
+ path: 'next.config.ts'
442
+ }
443
+ ]);
444
+ expect(detectFramework(dir)).toBe('next');
445
+ });
446
+ it('resolves ambiguous deps to tanstack-start via the config-file layer', ()=>{
447
+ const dir = makeProject([
448
+ {
449
+ contents: pkg({
450
+ '@tanstack/react-start': '1.168.26',
451
+ next: '15.0.0'
452
+ }),
453
+ path: 'package.json'
454
+ },
455
+ {
456
+ path: 'vite.config.ts'
457
+ }
458
+ ]);
459
+ expect(detectFramework(dir)).toBe('tanstack-start');
460
+ });
461
+ it('resolves ambiguous deps and configs via the folder-convention layer', ()=>{
462
+ const dir = makeProject([
463
+ {
464
+ contents: pkg({
465
+ '@tanstack/react-start': '1.168.26',
466
+ next: '15.0.0'
467
+ }),
468
+ path: 'package.json'
469
+ },
470
+ {
471
+ path: 'app/_payload/route.tsx'
472
+ }
473
+ ]);
474
+ expect(detectFramework(dir)).toBe('tanstack-start');
475
+ });
476
+ it('throws a no-framework error when nothing is detected', ()=>{
477
+ const dir = makeProject([
478
+ {
479
+ contents: pkg({}),
480
+ path: 'package.json'
481
+ }
482
+ ]);
483
+ expect(()=>detectFramework(dir)).toThrow(/Could not determine your framework/);
484
+ });
485
+ it('throws a conflict error when signals stay ambiguous', ()=>{
486
+ const dir = makeProject([
487
+ {
488
+ contents: pkg({
489
+ '@tanstack/react-start': '1.168.26',
490
+ next: '15.0.0'
491
+ }),
492
+ path: 'package.json'
493
+ },
494
+ {
495
+ path: 'next.config.ts'
496
+ },
497
+ {
498
+ path: 'vite.config.ts'
499
+ }
500
+ ]);
501
+ expect(()=>detectFramework(dir)).toThrow(/conflicting signals/);
502
+ });
168
503
  });
169
504
 
170
505
  //# sourceMappingURL=build.spec.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/bin/build.spec.ts"],"sourcesContent":["import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest'\n\n// Default fake child auto-fires `exit(0)` synchronously so ordering/generation\n// tests resolve. Specific tests override via `mockReturnValueOnce` to drive the\n// exit/error handlers manually.\nconst spawnMock = vi.fn(() => ({\n on(event: string, cb: (arg?: never) => void) {\n if (event === 'exit') {\n cb(0 as never)\n }\n return this\n },\n}))\nconst generateImportMapMock = vi.fn(async () => {})\nconst generateTypesMock = vi.fn(async () => {})\n\nvi.mock('node:child_process', () => ({ spawn: spawnMock }))\nvi.mock('./generateImportMap/index.js', () => ({ generateImportMap: generateImportMapMock }))\nvi.mock('./generateTypes.js', () => ({ generateTypes: generateTypesMock }))\n\n// Imported after mocks are registered\nconst { build, getForwardedArgs, resolveNextBin } = await import('./build.js')\n\nconst fakeConfig = {} as never\n\ndescribe('getForwardedArgs', () => {\n it('returns args after the build token and strips --no-types', () => {\n expect(getForwardedArgs(['build', '--turbopack', '--no-types', 'foo'])).toEqual([\n '--turbopack',\n 'foo',\n ])\n })\n\n it('returns empty array when only build is present', () => {\n expect(getForwardedArgs(['build'])).toEqual([])\n })\n})\n\ndescribe('resolveNextBin', () => {\n it('resolves next bin from the current project', () => {\n // next is installed at the repo root; resolving from cwd must succeed\n const binPath = resolveNextBin(process.cwd())\n expect(binPath).toMatch(/next[\\\\/].*bin[\\\\/]next$/)\n })\n\n it('throws a clear error when next cannot be resolved', () => {\n expect(() => resolveNextBin('/nonexistent-project-root')).toThrow(/next/i)\n })\n})\n\ndescribe('build', () => {\n let exitMock: ReturnType<typeof vi.spyOn>\n let originalArgv: string[]\n\n beforeEach(() => {\n spawnMock.mockClear()\n generateImportMapMock.mockClear()\n generateTypesMock.mockClear()\n originalArgv = process.argv\n process.argv = ['node', 'payload', 'build']\n exitMock = vi.spyOn(process, 'exit').mockImplementation((() => undefined) as never)\n })\n\n afterEach(() => {\n process.argv = originalArgv\n exitMock.mockRestore()\n })\n\n it('generates the import map before spawning, and generates types by default', async () => {\n await build({ config: fakeConfig })\n\n expect(generateImportMapMock).toHaveBeenCalledTimes(1)\n expect(generateTypesMock).toHaveBeenCalledTimes(1)\n expect(spawnMock).toHaveBeenCalledTimes(1)\n expect(generateImportMapMock.mock.invocationCallOrder[0]).toBeLessThan(\n spawnMock.mock.invocationCallOrder[0],\n )\n })\n\n it('skips type generation with --no-types', async () => {\n process.argv = ['node', 'payload', 'build', '--no-types']\n\n await build({ config: fakeConfig })\n\n expect(generateImportMapMock).toHaveBeenCalledTimes(1)\n expect(generateTypesMock).not.toHaveBeenCalled()\n expect(spawnMock).toHaveBeenCalledTimes(1)\n })\n\n it('exits 1 and does not spawn when generation fails', async () => {\n generateImportMapMock.mockRejectedValueOnce(new Error('boom'))\n\n await build({ config: fakeConfig })\n\n expect(exitMock).toHaveBeenCalledWith(1)\n expect(spawnMock).not.toHaveBeenCalled()\n })\n\n it('spawns next build with forwarded args and propagates the child exit code', async () => {\n process.argv = ['node', 'payload', 'build', '--turbopack']\n let exitCb: ((code: number | null) => void) | undefined\n spawnMock.mockReturnValueOnce({\n on(event: string, cb: (code: number | null) => void) {\n if (event === 'exit') {\n exitCb = cb\n }\n return this\n },\n })\n\n const buildPromise = build({ config: fakeConfig })\n\n // generation awaits before spawn; let those microtasks settle\n await vi.waitFor(() => expect(spawnMock).toHaveBeenCalledTimes(1))\n const [execPath, spawnArgs, opts] = spawnMock.mock.calls[0]\n expect(execPath).toBe(process.execPath)\n expect(spawnArgs[1]).toBe('build')\n expect(spawnArgs).toContain('--turbopack')\n expect(opts).toEqual({ stdio: 'inherit' })\n\n // Simulate the child exiting with a non-zero code\n exitCb?.(2)\n await buildPromise\n expect(exitMock).toHaveBeenCalledWith(2)\n })\n\n it('does not exit until the spawned child exits, then propagates its code', async () => {\n let exitCb: ((code: number | null) => void) | undefined\n spawnMock.mockReturnValueOnce({\n on(event: string, cb: (code: number | null) => void) {\n if (event === 'exit') {\n exitCb = cb\n }\n return this\n },\n })\n\n let resolved = false\n const buildPromise = build({ config: fakeConfig }).then(() => {\n resolved = true\n })\n\n // Wait for generation to settle and the child to be spawned. build() must\n // still be pending because the child has not exited yet.\n await vi.waitFor(() => expect(exitCb).toBeDefined())\n // Flush all pending microtasks; the OLD (buggy) build() resolved here\n // without awaiting the child, so this assertion catches the race.\n await new Promise((r) => setTimeout(r, 0))\n expect(resolved).toBe(false)\n expect(exitMock).not.toHaveBeenCalled()\n\n // Child exits non-zero -> build() must exit with that exact code\n exitCb?.(3)\n await buildPromise\n expect(resolved).toBe(true)\n expect(exitMock).toHaveBeenCalledWith(3)\n })\n})\n"],"names":["describe","expect","it","vi","beforeEach","afterEach","spawnMock","fn","on","event","cb","generateImportMapMock","generateTypesMock","mock","spawn","generateImportMap","generateTypes","build","getForwardedArgs","resolveNextBin","fakeConfig","toEqual","binPath","process","cwd","toMatch","toThrow","exitMock","originalArgv","mockClear","argv","spyOn","mockImplementation","undefined","mockRestore","config","toHaveBeenCalledTimes","invocationCallOrder","toBeLessThan","not","toHaveBeenCalled","mockRejectedValueOnce","Error","toHaveBeenCalledWith","exitCb","mockReturnValueOnce","buildPromise","waitFor","execPath","spawnArgs","opts","calls","toBe","toContain","stdio","resolved","then","toBeDefined","Promise","r","setTimeout"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/bin/build.spec.ts"],"sourcesContent":["import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\n\nimport { describe, expect, it, vi, beforeEach, afterEach } from 'vitest'\n\n// Default fake child auto-fires `exit(0)` synchronously so ordering/generation\n// tests resolve. Specific tests override via `mockReturnValueOnce` to drive the\n// exit/error handlers manually.\nconst spawnMock = vi.fn(() => ({\n on(event: string, cb: (arg?: never) => void) {\n if (event === 'exit') {\n cb(0 as never)\n }\n return this\n },\n}))\nconst generateImportMapMock = vi.fn(async () => {})\nconst generateTypesMock = vi.fn(async () => {})\n\nvi.mock('node:child_process', () => ({ spawn: spawnMock }))\nvi.mock('./generateImportMap/index.js', () => ({ generateImportMap: generateImportMapMock }))\nvi.mock('./generateTypes.js', () => ({ generateTypes: generateTypesMock }))\n\n// Imported after mocks are registered\nconst {\n build,\n detectFramework,\n getForwardedArgs,\n resolveBuildCommand,\n resolveNextBin,\n resolveViteBin,\n} = await import('./build.js')\n\nconst fakeConfig = {} as never\n\ndescribe('getForwardedArgs', () => {\n it('returns args after the build token and strips --no-types', () => {\n expect(getForwardedArgs(['build', '--turbopack', '--no-types', 'foo'])).toEqual([\n '--turbopack',\n 'foo',\n ])\n })\n\n it('returns empty array when only build is present', () => {\n expect(getForwardedArgs(['build'])).toEqual([])\n })\n})\n\ndescribe('resolveNextBin', () => {\n it('resolves next bin from the current project', () => {\n // next is installed at the repo root; resolving from cwd must succeed\n const binPath = resolveNextBin(process.cwd())\n expect(binPath).toMatch(/next[\\\\/].*bin[\\\\/]next$/)\n })\n\n it('throws a clear error when next cannot be resolved', () => {\n expect(() => resolveNextBin('/nonexistent-project-root')).toThrow(/next/i)\n })\n})\n\ndescribe('resolveViteBin', () => {\n it('resolves the vite bin from the current project', () => {\n // vite is installed at the repo root; resolving from cwd must succeed\n const binPath = resolveViteBin(process.cwd())\n expect(binPath).toMatch(/vite[\\\\/].*bin[\\\\/]vite\\.js$/)\n })\n\n it('throws a clear error when vite cannot be resolved', async () => {\n // Vitest injects its own transitive `vite` dep onto NODE_PATH, so resolving\n // \"vite\" from any cwd would otherwise succeed in this test process even\n // when the project under test has no vite installed. Mock module\n // resolution itself to simulate a real \"vite not installed\" project.\n vi.resetModules()\n vi.doMock('node:module', async (importOriginal) => {\n const actual = await importOriginal<typeof import('node:module')>()\n return {\n ...actual,\n createRequire: () => ({\n resolve: () => {\n throw new Error('Cannot find module')\n },\n }),\n }\n })\n\n const { resolveViteBin: resolveViteBinWithoutVite } = await import('./build.js')\n expect(() => resolveViteBinWithoutVite('/nonexistent-project-root')).toThrow(/vite/i)\n\n vi.doUnmock('node:module')\n vi.resetModules()\n })\n})\n\ndescribe('resolveBuildCommand', () => {\n it('maps next to the next bin and build args', () => {\n const { args, bin } = resolveBuildCommand({\n cwd: process.cwd(),\n forwardedArgs: ['--turbopack'],\n framework: 'next',\n })\n expect(bin).toMatch(/next[\\\\/].*bin[\\\\/]next$/)\n expect(args).toEqual(['build', '--turbopack'])\n })\n\n it('maps tanstack-start to the vite bin and build args', () => {\n const { args, bin } = resolveBuildCommand({\n cwd: process.cwd(),\n forwardedArgs: ['--mode', 'staging'],\n framework: 'tanstack-start',\n })\n expect(bin).toMatch(/vite[\\\\/].*bin[\\\\/]vite\\.js$/)\n expect(args).toEqual(['build', '--mode', 'staging'])\n })\n})\n\ndescribe('build', () => {\n let exitMock: ReturnType<typeof vi.spyOn>\n let originalArgv: string[]\n let originalFrameworkEnv: string | undefined\n let cwdSpy: ReturnType<typeof vi.spyOn> | undefined\n const buildTempDirs: string[] = []\n\n beforeEach(() => {\n spawnMock.mockClear()\n generateImportMapMock.mockClear()\n generateTypesMock.mockClear()\n originalArgv = process.argv\n process.argv = ['node', 'payload', 'build']\n exitMock = vi.spyOn(process, 'exit').mockImplementation((() => undefined) as never)\n originalFrameworkEnv = process.env.PAYLOAD_FRAMEWORK\n // Force next for the legacy tests so they don't depend on the repo-root\n // package.json's ambient `next` dependency for auto-detection.\n process.env.PAYLOAD_FRAMEWORK = 'next'\n })\n\n afterEach(() => {\n process.argv = originalArgv\n exitMock.mockRestore()\n if (originalFrameworkEnv === undefined) {\n delete process.env.PAYLOAD_FRAMEWORK\n } else {\n process.env.PAYLOAD_FRAMEWORK = originalFrameworkEnv\n }\n if (cwdSpy) {\n cwdSpy.mockRestore()\n cwdSpy = undefined\n }\n for (const dir of buildTempDirs) {\n rmSync(dir, { force: true, recursive: true })\n }\n buildTempDirs.length = 0\n })\n\n it('generates the import map before spawning, and generates types by default', async () => {\n await build({ config: fakeConfig })\n\n expect(generateImportMapMock).toHaveBeenCalledTimes(1)\n expect(generateTypesMock).toHaveBeenCalledTimes(1)\n expect(spawnMock).toHaveBeenCalledTimes(1)\n expect(generateImportMapMock.mock.invocationCallOrder[0]).toBeLessThan(\n spawnMock.mock.invocationCallOrder[0],\n )\n })\n\n it('skips type generation with --no-types', async () => {\n process.argv = ['node', 'payload', 'build', '--no-types']\n\n await build({ config: fakeConfig })\n\n expect(generateImportMapMock).toHaveBeenCalledTimes(1)\n expect(generateTypesMock).not.toHaveBeenCalled()\n expect(spawnMock).toHaveBeenCalledTimes(1)\n })\n\n it('exits 1 and does not spawn when generation fails', async () => {\n generateImportMapMock.mockRejectedValueOnce(new Error('boom'))\n\n await build({ config: fakeConfig })\n\n expect(exitMock).toHaveBeenCalledWith(1)\n expect(spawnMock).not.toHaveBeenCalled()\n })\n\n it('spawns next build with forwarded args and propagates the child exit code', async () => {\n process.argv = ['node', 'payload', 'build', '--turbopack']\n let exitCb: ((code: number | null) => void) | undefined\n spawnMock.mockReturnValueOnce({\n on(event: string, cb: (code: number | null) => void) {\n if (event === 'exit') {\n exitCb = cb\n }\n return this\n },\n })\n\n const buildPromise = build({ config: fakeConfig })\n\n // generation awaits before spawn; let those microtasks settle\n await vi.waitFor(() => expect(spawnMock).toHaveBeenCalledTimes(1))\n const [execPath, spawnArgs, opts] = spawnMock.mock.calls[0]\n expect(execPath).toBe(process.execPath)\n expect(spawnArgs[1]).toBe('build')\n expect(spawnArgs).toContain('--turbopack')\n expect(opts).toEqual({ stdio: 'inherit' })\n\n // Simulate the child exiting with a non-zero code\n exitCb?.(2)\n await buildPromise\n expect(exitMock).toHaveBeenCalledWith(2)\n })\n\n it('does not exit until the spawned child exits, then propagates its code', async () => {\n let exitCb: ((code: number | null) => void) | undefined\n spawnMock.mockReturnValueOnce({\n on(event: string, cb: (code: number | null) => void) {\n if (event === 'exit') {\n exitCb = cb\n }\n return this\n },\n })\n\n let resolved = false\n const buildPromise = build({ config: fakeConfig }).then(() => {\n resolved = true\n })\n\n // Wait for generation to settle and the child to be spawned. build() must\n // still be pending because the child has not exited yet.\n await vi.waitFor(() => expect(exitCb).toBeDefined())\n // Flush all pending microtasks; the OLD (buggy) build() resolved here\n // without awaiting the child, so this assertion catches the race.\n await new Promise((r) => setTimeout(r, 0))\n expect(resolved).toBe(false)\n expect(exitMock).not.toHaveBeenCalled()\n\n // Child exits non-zero -> build() must exit with that exact code\n exitCb?.(3)\n await buildPromise\n expect(resolved).toBe(true)\n expect(exitMock).toHaveBeenCalledWith(3)\n })\n\n it('spawns vite build for a detected tanstack project', async () => {\n delete process.env.PAYLOAD_FRAMEWORK\n process.argv = ['node', 'payload', 'build', '--mode', 'staging']\n const tanstackDir = mkdtempSync(path.join(os.tmpdir(), 'payload-build-ts-'))\n buildTempDirs.push(tanstackDir)\n writeFileSync(\n path.join(tanstackDir, 'package.json'),\n JSON.stringify({ dependencies: { '@tanstack/react-start': '1.168.26' } }),\n )\n cwdSpy = vi.spyOn(process, 'cwd').mockReturnValue(tanstackDir)\n\n await build({ config: fakeConfig })\n\n expect(spawnMock).toHaveBeenCalledTimes(1)\n const [, spawnArgs] = spawnMock.mock.calls[0]\n expect(spawnArgs[0]).toMatch(/vite[\\\\/].*bin[\\\\/]vite\\.js$/)\n expect(spawnArgs.slice(1)).toEqual(['build', '--mode', 'staging'])\n })\n\n it('exits 1 and does not spawn when the framework cannot be detected', async () => {\n delete process.env.PAYLOAD_FRAMEWORK\n const emptyDir = mkdtempSync(path.join(os.tmpdir(), 'payload-build-empty-'))\n buildTempDirs.push(emptyDir)\n writeFileSync(path.join(emptyDir, 'package.json'), JSON.stringify({}))\n cwdSpy = vi.spyOn(process, 'cwd').mockReturnValue(emptyDir)\n\n await build({ config: fakeConfig })\n\n expect(exitMock).toHaveBeenCalledWith(1)\n expect(spawnMock).not.toHaveBeenCalled()\n })\n})\n\ndescribe('detectFramework', () => {\n const createdDirs: string[] = []\n let originalFrameworkEnv: string | undefined\n\n const makeProject = (files: { contents?: string; path: string }[]): string => {\n const dir = mkdtempSync(path.join(os.tmpdir(), 'payload-build-'))\n createdDirs.push(dir)\n for (const file of files) {\n const full = path.join(dir, file.path)\n mkdirSync(path.dirname(full), { recursive: true })\n writeFileSync(full, file.contents ?? '')\n }\n return dir\n }\n\n const pkg = (deps: Record<string, string>): string => JSON.stringify({ dependencies: deps })\n\n beforeEach(() => {\n originalFrameworkEnv = process.env.PAYLOAD_FRAMEWORK\n delete process.env.PAYLOAD_FRAMEWORK\n })\n\n afterEach(() => {\n if (originalFrameworkEnv === undefined) {\n delete process.env.PAYLOAD_FRAMEWORK\n } else {\n process.env.PAYLOAD_FRAMEWORK = originalFrameworkEnv\n }\n for (const dir of createdDirs) {\n rmSync(dir, { force: true, recursive: true })\n }\n createdDirs.length = 0\n })\n\n it('honors PAYLOAD_FRAMEWORK=tanstack-start over auto-detection', () => {\n process.env.PAYLOAD_FRAMEWORK = 'tanstack-start'\n const dir = makeProject([{ contents: pkg({ next: '15.0.0' }), path: 'package.json' }])\n expect(detectFramework(dir)).toBe('tanstack-start')\n })\n\n it('honors PAYLOAD_FRAMEWORK=next over auto-detection', () => {\n process.env.PAYLOAD_FRAMEWORK = 'next'\n const dir = makeProject([\n { contents: pkg({ '@tanstack/react-start': '1.168.26' }), path: 'package.json' },\n ])\n expect(detectFramework(dir)).toBe('next')\n })\n\n it('throws when PAYLOAD_FRAMEWORK is an unsupported value', () => {\n process.env.PAYLOAD_FRAMEWORK = 'svelte'\n const dir = makeProject([{ contents: pkg({ next: '15.0.0' }), path: 'package.json' }])\n expect(() => detectFramework(dir)).toThrow(/PAYLOAD_FRAMEWORK/)\n })\n\n it('detects next from the next dependency', () => {\n const dir = makeProject([{ contents: pkg({ next: '15.0.0' }), path: 'package.json' }])\n expect(detectFramework(dir)).toBe('next')\n })\n\n it('detects tanstack-start from the @tanstack/react-start dependency', () => {\n const dir = makeProject([\n { contents: pkg({ '@tanstack/react-start': '1.168.26' }), path: 'package.json' },\n ])\n expect(detectFramework(dir)).toBe('tanstack-start')\n })\n\n it('falls back to next.config when deps are inconclusive', () => {\n const dir = makeProject([\n { contents: pkg({}), path: 'package.json' },\n { path: 'next.config.ts' },\n ])\n expect(detectFramework(dir)).toBe('next')\n })\n\n it('falls back to vite.config when deps are inconclusive', () => {\n const dir = makeProject([\n { contents: pkg({}), path: 'package.json' },\n { path: 'vite.config.ts' },\n ])\n expect(detectFramework(dir)).toBe('tanstack-start')\n })\n\n it('falls back to the (payload) folder convention', () => {\n const dir = makeProject([{ path: 'app/(payload)/admin/page.tsx' }])\n expect(detectFramework(dir)).toBe('next')\n })\n\n it('falls back to the _payload folder convention', () => {\n const dir = makeProject([{ path: 'app/_payload/route.tsx' }])\n expect(detectFramework(dir)).toBe('tanstack-start')\n })\n\n it('resolves ambiguous deps using the config-file layer', () => {\n const dir = makeProject([\n {\n contents: pkg({ '@tanstack/react-start': '1.168.26', next: '15.0.0' }),\n path: 'package.json',\n },\n { path: 'next.config.ts' },\n ])\n expect(detectFramework(dir)).toBe('next')\n })\n\n it('resolves ambiguous deps to tanstack-start via the config-file layer', () => {\n const dir = makeProject([\n {\n contents: pkg({ '@tanstack/react-start': '1.168.26', next: '15.0.0' }),\n path: 'package.json',\n },\n { path: 'vite.config.ts' },\n ])\n expect(detectFramework(dir)).toBe('tanstack-start')\n })\n\n it('resolves ambiguous deps and configs via the folder-convention layer', () => {\n const dir = makeProject([\n {\n contents: pkg({ '@tanstack/react-start': '1.168.26', next: '15.0.0' }),\n path: 'package.json',\n },\n { path: 'app/_payload/route.tsx' },\n ])\n expect(detectFramework(dir)).toBe('tanstack-start')\n })\n\n it('throws a no-framework error when nothing is detected', () => {\n const dir = makeProject([{ contents: pkg({}), path: 'package.json' }])\n expect(() => detectFramework(dir)).toThrow(/Could not determine your framework/)\n })\n\n it('throws a conflict error when signals stay ambiguous', () => {\n const dir = makeProject([\n {\n contents: pkg({ '@tanstack/react-start': '1.168.26', next: '15.0.0' }),\n path: 'package.json',\n },\n { path: 'next.config.ts' },\n { path: 'vite.config.ts' },\n ])\n expect(() => detectFramework(dir)).toThrow(/conflicting signals/)\n })\n})\n"],"names":["mkdirSync","mkdtempSync","rmSync","writeFileSync","os","path","describe","expect","it","vi","beforeEach","afterEach","spawnMock","fn","on","event","cb","generateImportMapMock","generateTypesMock","mock","spawn","generateImportMap","generateTypes","build","detectFramework","getForwardedArgs","resolveBuildCommand","resolveNextBin","resolveViteBin","fakeConfig","toEqual","binPath","process","cwd","toMatch","toThrow","resetModules","doMock","importOriginal","actual","createRequire","resolve","Error","resolveViteBinWithoutVite","doUnmock","args","bin","forwardedArgs","framework","exitMock","originalArgv","originalFrameworkEnv","cwdSpy","buildTempDirs","mockClear","argv","spyOn","mockImplementation","undefined","env","PAYLOAD_FRAMEWORK","mockRestore","dir","force","recursive","length","config","toHaveBeenCalledTimes","invocationCallOrder","toBeLessThan","not","toHaveBeenCalled","mockRejectedValueOnce","toHaveBeenCalledWith","exitCb","mockReturnValueOnce","buildPromise","waitFor","execPath","spawnArgs","opts","calls","toBe","toContain","stdio","resolved","then","toBeDefined","Promise","r","setTimeout","tanstackDir","join","tmpdir","push","JSON","stringify","dependencies","mockReturnValue","slice","emptyDir","createdDirs","makeProject","files","file","full","dirname","contents","pkg","deps","next"],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Folder-name markers that distinguish the supported framework conventions.
3
+ * Shared between import-map resolution and `payload build` framework detection so
4
+ * the two cannot drift.
5
+ */
6
+ export declare const NEXT_PAYLOAD_ROUTE_GROUP = "(payload)";
7
+ export declare const TANSTACK_PAYLOAD_DIR = "_payload";
8
+ //# sourceMappingURL=frameworkConventions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frameworkConventions.d.ts","sourceRoot":"","sources":["../../src/bin/frameworkConventions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,cAAc,CAAA;AACnD,eAAO,MAAM,oBAAoB,aAAa,CAAA"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Folder-name markers that distinguish the supported framework conventions.
3
+ * Shared between import-map resolution and `payload build` framework detection so
4
+ * the two cannot drift.
5
+ */ export const NEXT_PAYLOAD_ROUTE_GROUP = '(payload)';
6
+ export const TANSTACK_PAYLOAD_DIR = '_payload';
7
+
8
+ //# sourceMappingURL=frameworkConventions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/bin/frameworkConventions.ts"],"sourcesContent":["/**\n * Folder-name markers that distinguish the supported framework conventions.\n * Shared between import-map resolution and `payload build` framework detection so\n * the two cannot drift.\n */\nexport const NEXT_PAYLOAD_ROUTE_GROUP = '(payload)'\nexport const TANSTACK_PAYLOAD_DIR = '_payload'\n"],"names":["NEXT_PAYLOAD_ROUTE_GROUP","TANSTACK_PAYLOAD_DIR"],"mappings":"AAAA;;;;CAIC,GACD,OAAO,MAAMA,2BAA2B,YAAW;AACnD,OAAO,MAAMC,uBAAuB,WAAU"}
@@ -1 +1 @@
1
- {"version":3,"file":"resolveImportMapFilePath.d.ts","sourceRoot":"","sources":["../../../../src/bin/generateImportMap/utilities/resolveImportMapFilePath.ts"],"names":[],"mappings":"AA6BA;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAAC,EAC7C,UAAqB,EACrB,oBAAoB,EACpB,aAAa,EACb,OAAO,GACR,EAAE;IACD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;CAChB,GAAG,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC,CAkC1B"}
1
+ {"version":3,"file":"resolveImportMapFilePath.d.ts","sourceRoot":"","sources":["../../../../src/bin/generateImportMap/utilities/resolveImportMapFilePath.ts"],"names":[],"mappings":"AA+BA;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAAC,EAC7C,UAAqB,EACrB,oBAAoB,EACpB,aAAa,EACb,OAAO,GACR,EAAE;IACD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;CAChB,GAAG,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC,CAkC1B"}
@@ -1,5 +1,6 @@
1
1
  import fs from 'fs/promises';
2
2
  import path from 'path';
3
+ import { NEXT_PAYLOAD_ROUTE_GROUP, TANSTACK_PAYLOAD_DIR } from '../../frameworkConventions.js';
3
4
  async function pathOrFileExists(path) {
4
5
  try {
5
6
  await fs.access(path);
@@ -17,11 +18,11 @@ async function pathOrFileExists(path) {
17
18
  * Adapters with a bespoke layout can still bypass this via `candidateDirectories`.
18
19
  */ const defaultCandidateDirectories = (rootDir, adminRoute)=>[
19
20
  // Next.js App Router: `(payload)` route group nested under the admin route
20
- path.resolve(rootDir, `app/(payload)${adminRoute}/`),
21
- path.resolve(rootDir, `src/app/(payload)${adminRoute}/`),
21
+ path.resolve(rootDir, `app/${NEXT_PAYLOAD_ROUTE_GROUP}${adminRoute}/`),
22
+ path.resolve(rootDir, `src/app/${NEXT_PAYLOAD_ROUTE_GROUP}${adminRoute}/`),
22
23
  // TanStack Start: `_payload` pathless route folder at the app root
23
- path.resolve(rootDir, `app/_payload/`),
24
- path.resolve(rootDir, `src/app/_payload/`)
24
+ path.resolve(rootDir, `app/${TANSTACK_PAYLOAD_DIR}/`),
25
+ path.resolve(rootDir, `src/app/${TANSTACK_PAYLOAD_DIR}/`)
25
26
  ];
26
27
  /**
27
28
  * Returns the path to the import map file. If the import map file is not found, it throws an error.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/bin/generateImportMap/utilities/resolveImportMapFilePath.ts"],"sourcesContent":["import fs from 'fs/promises'\nimport path from 'path'\n\nasync function pathOrFileExists(path: string): Promise<boolean> {\n try {\n await fs.access(path)\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Default directory patterns for import map resolution, covering the supported\n * framework conventions. Directories are probed in order and the first existing\n * one wins; the conventions are mutually exclusive in practice, so a Next.js app\n * never matches the TanStack patterns and vice versa.\n *\n * Adapters with a bespoke layout can still bypass this via `candidateDirectories`.\n */\nconst defaultCandidateDirectories = (rootDir: string, adminRoute: string): string[] => [\n // Next.js App Router: `(payload)` route group nested under the admin route\n path.resolve(rootDir, `app/(payload)${adminRoute}/`),\n path.resolve(rootDir, `src/app/(payload)${adminRoute}/`),\n // TanStack Start: `_payload` pathless route folder at the app root\n path.resolve(rootDir, `app/_payload/`),\n path.resolve(rootDir, `src/app/_payload/`),\n]\n\n/**\n * Returns the path to the import map file. If the import map file is not found, it throws an error.\n *\n * @param candidateDirectories - Optional array of directory paths to search for the import map.\n * Defaults to Next.js app directory convention. Framework adapters can provide their own.\n */\nexport async function resolveImportMapFilePath({\n adminRoute = '/admin',\n candidateDirectories,\n importMapFile,\n rootDir,\n}: {\n adminRoute?: string\n candidateDirectories?: string[]\n importMapFile?: string\n rootDir: string\n}): Promise<Error | string> {\n let importMapFilePath: string | undefined = undefined\n\n if (importMapFile?.length) {\n if (!(await pathOrFileExists(importMapFile))) {\n try {\n await fs.writeFile(importMapFile, '', { flag: 'wx' })\n } catch (err) {\n return new Error(\n `Could not find the import map file at ${importMapFile}${err instanceof Error && err?.message ? `: ${err.message}` : ''}`,\n )\n }\n }\n importMapFilePath = importMapFile\n } else {\n const directories = candidateDirectories ?? defaultCandidateDirectories(rootDir, adminRoute)\n\n for (const dir of directories) {\n if (await pathOrFileExists(dir)) {\n importMapFilePath = path.resolve(dir, 'importMap.js')\n if (!(await pathOrFileExists(importMapFilePath))) {\n await fs.writeFile(importMapFilePath, '', { flag: 'wx' })\n }\n break\n }\n }\n\n if (!importMapFilePath) {\n return new Error(\n `Could not find Payload import map folder. Looked in ${directories.join(' and ')}`,\n )\n }\n }\n return importMapFilePath\n}\n"],"names":["fs","path","pathOrFileExists","access","defaultCandidateDirectories","rootDir","adminRoute","resolve","resolveImportMapFilePath","candidateDirectories","importMapFile","importMapFilePath","undefined","length","writeFile","flag","err","Error","message","directories","dir","join"],"mappings":"AAAA,OAAOA,QAAQ,cAAa;AAC5B,OAAOC,UAAU,OAAM;AAEvB,eAAeC,iBAAiBD,IAAY;IAC1C,IAAI;QACF,MAAMD,GAAGG,MAAM,CAACF;QAChB,OAAO;IACT,EAAE,OAAM;QACN,OAAO;IACT;AACF;AAEA;;;;;;;CAOC,GACD,MAAMG,8BAA8B,CAACC,SAAiBC,aAAiC;QACrF,2EAA2E;QAC3EL,KAAKM,OAAO,CAACF,SAAS,CAAC,aAAa,EAAEC,WAAW,CAAC,CAAC;QACnDL,KAAKM,OAAO,CAACF,SAAS,CAAC,iBAAiB,EAAEC,WAAW,CAAC,CAAC;QACvD,mEAAmE;QACnEL,KAAKM,OAAO,CAACF,SAAS,CAAC,aAAa,CAAC;QACrCJ,KAAKM,OAAO,CAACF,SAAS,CAAC,iBAAiB,CAAC;KAC1C;AAED;;;;;CAKC,GACD,OAAO,eAAeG,yBAAyB,EAC7CF,aAAa,QAAQ,EACrBG,oBAAoB,EACpBC,aAAa,EACbL,OAAO,EAMR;IACC,IAAIM,oBAAwCC;IAE5C,IAAIF,eAAeG,QAAQ;QACzB,IAAI,CAAE,MAAMX,iBAAiBQ,gBAAiB;YAC5C,IAAI;gBACF,MAAMV,GAAGc,SAAS,CAACJ,eAAe,IAAI;oBAAEK,MAAM;gBAAK;YACrD,EAAE,OAAOC,KAAK;gBACZ,OAAO,IAAIC,MACT,CAAC,sCAAsC,EAAEP,gBAAgBM,eAAeC,SAASD,KAAKE,UAAU,CAAC,EAAE,EAAEF,IAAIE,OAAO,EAAE,GAAG,IAAI;YAE7H;QACF;QACAP,oBAAoBD;IACtB,OAAO;QACL,MAAMS,cAAcV,wBAAwBL,4BAA4BC,SAASC;QAEjF,KAAK,MAAMc,OAAOD,YAAa;YAC7B,IAAI,MAAMjB,iBAAiBkB,MAAM;gBAC/BT,oBAAoBV,KAAKM,OAAO,CAACa,KAAK;gBACtC,IAAI,CAAE,MAAMlB,iBAAiBS,oBAAqB;oBAChD,MAAMX,GAAGc,SAAS,CAACH,mBAAmB,IAAI;wBAAEI,MAAM;oBAAK;gBACzD;gBACA;YACF;QACF;QAEA,IAAI,CAACJ,mBAAmB;YACtB,OAAO,IAAIM,MACT,CAAC,oDAAoD,EAAEE,YAAYE,IAAI,CAAC,UAAU;QAEtF;IACF;IACA,OAAOV;AACT"}
1
+ {"version":3,"sources":["../../../../src/bin/generateImportMap/utilities/resolveImportMapFilePath.ts"],"sourcesContent":["import fs from 'fs/promises'\nimport path from 'path'\n\nimport { NEXT_PAYLOAD_ROUTE_GROUP, TANSTACK_PAYLOAD_DIR } from '../../frameworkConventions.js'\n\nasync function pathOrFileExists(path: string): Promise<boolean> {\n try {\n await fs.access(path)\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Default directory patterns for import map resolution, covering the supported\n * framework conventions. Directories are probed in order and the first existing\n * one wins; the conventions are mutually exclusive in practice, so a Next.js app\n * never matches the TanStack patterns and vice versa.\n *\n * Adapters with a bespoke layout can still bypass this via `candidateDirectories`.\n */\nconst defaultCandidateDirectories = (rootDir: string, adminRoute: string): string[] => [\n // Next.js App Router: `(payload)` route group nested under the admin route\n path.resolve(rootDir, `app/${NEXT_PAYLOAD_ROUTE_GROUP}${adminRoute}/`),\n path.resolve(rootDir, `src/app/${NEXT_PAYLOAD_ROUTE_GROUP}${adminRoute}/`),\n // TanStack Start: `_payload` pathless route folder at the app root\n path.resolve(rootDir, `app/${TANSTACK_PAYLOAD_DIR}/`),\n path.resolve(rootDir, `src/app/${TANSTACK_PAYLOAD_DIR}/`),\n]\n\n/**\n * Returns the path to the import map file. If the import map file is not found, it throws an error.\n *\n * @param candidateDirectories - Optional array of directory paths to search for the import map.\n * Defaults to Next.js app directory convention. Framework adapters can provide their own.\n */\nexport async function resolveImportMapFilePath({\n adminRoute = '/admin',\n candidateDirectories,\n importMapFile,\n rootDir,\n}: {\n adminRoute?: string\n candidateDirectories?: string[]\n importMapFile?: string\n rootDir: string\n}): Promise<Error | string> {\n let importMapFilePath: string | undefined = undefined\n\n if (importMapFile?.length) {\n if (!(await pathOrFileExists(importMapFile))) {\n try {\n await fs.writeFile(importMapFile, '', { flag: 'wx' })\n } catch (err) {\n return new Error(\n `Could not find the import map file at ${importMapFile}${err instanceof Error && err?.message ? `: ${err.message}` : ''}`,\n )\n }\n }\n importMapFilePath = importMapFile\n } else {\n const directories = candidateDirectories ?? defaultCandidateDirectories(rootDir, adminRoute)\n\n for (const dir of directories) {\n if (await pathOrFileExists(dir)) {\n importMapFilePath = path.resolve(dir, 'importMap.js')\n if (!(await pathOrFileExists(importMapFilePath))) {\n await fs.writeFile(importMapFilePath, '', { flag: 'wx' })\n }\n break\n }\n }\n\n if (!importMapFilePath) {\n return new Error(\n `Could not find Payload import map folder. Looked in ${directories.join(' and ')}`,\n )\n }\n }\n return importMapFilePath\n}\n"],"names":["fs","path","NEXT_PAYLOAD_ROUTE_GROUP","TANSTACK_PAYLOAD_DIR","pathOrFileExists","access","defaultCandidateDirectories","rootDir","adminRoute","resolve","resolveImportMapFilePath","candidateDirectories","importMapFile","importMapFilePath","undefined","length","writeFile","flag","err","Error","message","directories","dir","join"],"mappings":"AAAA,OAAOA,QAAQ,cAAa;AAC5B,OAAOC,UAAU,OAAM;AAEvB,SAASC,wBAAwB,EAAEC,oBAAoB,QAAQ,gCAA+B;AAE9F,eAAeC,iBAAiBH,IAAY;IAC1C,IAAI;QACF,MAAMD,GAAGK,MAAM,CAACJ;QAChB,OAAO;IACT,EAAE,OAAM;QACN,OAAO;IACT;AACF;AAEA;;;;;;;CAOC,GACD,MAAMK,8BAA8B,CAACC,SAAiBC,aAAiC;QACrF,2EAA2E;QAC3EP,KAAKQ,OAAO,CAACF,SAAS,CAAC,IAAI,EAAEL,2BAA2BM,WAAW,CAAC,CAAC;QACrEP,KAAKQ,OAAO,CAACF,SAAS,CAAC,QAAQ,EAAEL,2BAA2BM,WAAW,CAAC,CAAC;QACzE,mEAAmE;QACnEP,KAAKQ,OAAO,CAACF,SAAS,CAAC,IAAI,EAAEJ,qBAAqB,CAAC,CAAC;QACpDF,KAAKQ,OAAO,CAACF,SAAS,CAAC,QAAQ,EAAEJ,qBAAqB,CAAC,CAAC;KACzD;AAED;;;;;CAKC,GACD,OAAO,eAAeO,yBAAyB,EAC7CF,aAAa,QAAQ,EACrBG,oBAAoB,EACpBC,aAAa,EACbL,OAAO,EAMR;IACC,IAAIM,oBAAwCC;IAE5C,IAAIF,eAAeG,QAAQ;QACzB,IAAI,CAAE,MAAMX,iBAAiBQ,gBAAiB;YAC5C,IAAI;gBACF,MAAMZ,GAAGgB,SAAS,CAACJ,eAAe,IAAI;oBAAEK,MAAM;gBAAK;YACrD,EAAE,OAAOC,KAAK;gBACZ,OAAO,IAAIC,MACT,CAAC,sCAAsC,EAAEP,gBAAgBM,eAAeC,SAASD,KAAKE,UAAU,CAAC,EAAE,EAAEF,IAAIE,OAAO,EAAE,GAAG,IAAI;YAE7H;QACF;QACAP,oBAAoBD;IACtB,OAAO;QACL,MAAMS,cAAcV,wBAAwBL,4BAA4BC,SAASC;QAEjF,KAAK,MAAMc,OAAOD,YAAa;YAC7B,IAAI,MAAMjB,iBAAiBkB,MAAM;gBAC/BT,oBAAoBZ,KAAKQ,OAAO,CAACa,KAAK;gBACtC,IAAI,CAAE,MAAMlB,iBAAiBS,oBAAqB;oBAChD,MAAMb,GAAGgB,SAAS,CAACH,mBAAmB,IAAI;wBAAEI,MAAM;oBAAK;gBACzD;gBACA;YACF;QACF;QAEA,IAAI,CAACJ,mBAAmB;YACtB,OAAO,IAAIM,MACT,CAAC,oDAAoD,EAAEE,YAAYE,IAAI,CAAC,UAAU;QAEtF;IACF;IACA,OAAOV;AACT"}
@@ -10382,6 +10382,14 @@ type RouterAdapterRouter = {
10382
10382
  replace: (path: string, options?: {
10383
10383
  scroll?: boolean;
10384
10384
  }) => void;
10385
+ /**
10386
+ * Use this property to standardize behaviors across different router implementations.
10387
+ * Set it up to sync client state to the URL without triggering a second server load.
10388
+ *
10389
+ * In Next.js, calling `window.history.replaceState` directly is sufficient, as Next.js does not observe history mutations.
10390
+ * In TanStack Router, however, `history.replaceState` is monkeypatched to notify the router of changes.
10391
+ */
10392
+ replaceState?: (url: string) => void;
10385
10393
  };
10386
10394
  type LinkAdapterProps = {
10387
10395
  children?: React$1.ReactNode;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "payload",
3
- "version": "4.0.0-internal.d927017",
3
+ "version": "4.0.0-internal.e387174",
4
4
  "description": "Node, React, Headless CMS and Application Framework built on Next.js",
5
5
  "keywords": [
6
6
  "admin panel",
@@ -118,7 +118,7 @@
118
118
  "undici": "7.28.0",
119
119
  "uuid": "14.0.0",
120
120
  "ws": "^8.16.0",
121
- "@payloadcms/translations": "4.0.0-internal.d927017"
121
+ "@payloadcms/translations": "4.0.0-internal.e387174"
122
122
  },
123
123
  "devDependencies": {
124
124
  "@hyrious/esbuild-plugin-commonjs": "0.2.6",