@prisma/compute-sdk 0.28.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist/astro-build.d.ts +2 -0
  2. package/dist/astro-build.d.ts.map +1 -1
  3. package/dist/astro-build.js +31 -39
  4. package/dist/astro-build.js.map +1 -1
  5. package/dist/build-settings.d.ts +3 -0
  6. package/dist/build-settings.d.ts.map +1 -1
  7. package/dist/build-settings.js +13 -0
  8. package/dist/build-settings.js.map +1 -1
  9. package/dist/build-strategy.d.ts +20 -0
  10. package/dist/build-strategy.d.ts.map +1 -1
  11. package/dist/build-strategy.js +33 -1
  12. package/dist/build-strategy.js.map +1 -1
  13. package/dist/build.d.ts +2 -1
  14. package/dist/build.d.ts.map +1 -1
  15. package/dist/build.js +16 -4
  16. package/dist/build.js.map +1 -1
  17. package/dist/bun-build.d.ts +1 -1
  18. package/dist/bun-build.d.ts.map +1 -1
  19. package/dist/bun-build.js +25 -9
  20. package/dist/bun-build.js.map +1 -1
  21. package/dist/config/frameworks.d.ts +4 -8
  22. package/dist/config/frameworks.d.ts.map +1 -1
  23. package/dist/config/frameworks.js +17 -5
  24. package/dist/config/frameworks.js.map +1 -1
  25. package/dist/config/normalize.d.ts +6 -0
  26. package/dist/config/normalize.d.ts.map +1 -1
  27. package/dist/config/normalize.js +53 -12
  28. package/dist/config/normalize.js.map +1 -1
  29. package/dist/config/types.d.ts +3 -1
  30. package/dist/config/types.d.ts.map +1 -1
  31. package/dist/config/types.js +1 -0
  32. package/dist/config/types.js.map +1 -1
  33. package/dist/configured-artifact.d.ts +20 -0
  34. package/dist/configured-artifact.d.ts.map +1 -0
  35. package/dist/configured-artifact.js +104 -0
  36. package/dist/configured-artifact.js.map +1 -0
  37. package/dist/custom-build.d.ts +20 -0
  38. package/dist/custom-build.d.ts.map +1 -0
  39. package/dist/custom-build.js +53 -0
  40. package/dist/custom-build.js.map +1 -0
  41. package/dist/index.d.ts +1 -0
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +1 -0
  44. package/dist/index.js.map +1 -1
  45. package/dist/nestjs-build.d.ts.map +1 -1
  46. package/dist/nestjs-build.js +28 -29
  47. package/dist/nestjs-build.js.map +1 -1
  48. package/dist/nextjs-build.d.ts +1 -1
  49. package/dist/nextjs-build.d.ts.map +1 -1
  50. package/dist/nextjs-build.js +25 -14
  51. package/dist/nextjs-build.js.map +1 -1
  52. package/dist/nuxt-build.d.ts +2 -0
  53. package/dist/nuxt-build.d.ts.map +1 -1
  54. package/dist/nuxt-build.js +31 -39
  55. package/dist/nuxt-build.js.map +1 -1
  56. package/dist/tanstack-start-build.d.ts +1 -1
  57. package/dist/tanstack-start-build.d.ts.map +1 -1
  58. package/dist/tanstack-start-build.js +26 -47
  59. package/dist/tanstack-start-build.js.map +1 -1
  60. package/package.json +1 -1
  61. package/src/astro-build.ts +39 -46
  62. package/src/build-settings.ts +16 -0
  63. package/src/build-strategy.ts +56 -1
  64. package/src/build.ts +16 -4
  65. package/src/bun-build.ts +39 -10
  66. package/src/config/frameworks.ts +18 -5
  67. package/src/config/normalize.ts +74 -13
  68. package/src/config/types.ts +3 -0
  69. package/src/configured-artifact.ts +169 -0
  70. package/src/custom-build.ts +73 -0
  71. package/src/index.ts +1 -0
  72. package/src/nestjs-build.ts +36 -33
  73. package/src/nextjs-build.ts +31 -14
  74. package/src/nuxt-build.ts +39 -46
  75. package/src/tanstack-start-build.ts +31 -53
@@ -0,0 +1,169 @@
1
+ import { cp, mkdtemp, realpath, rm, stat } from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+
5
+ import { normalizeArtifactSymlinks } from "./artifact-postprocess.ts";
6
+ import type { BuildArtifact } from "./build-strategy.ts";
7
+ import {
8
+ defaultHttpPortForBuildType,
9
+ type FrameworkBuildType,
10
+ } from "./config/frameworks.ts";
11
+
12
+ export async function stageConfiguredArtifact(options: {
13
+ appPath: string;
14
+ outputDirectory: string;
15
+ entrypoint: string;
16
+ buildType: FrameworkBuildType;
17
+ label: string;
18
+ missingEntrypointMessage?: string;
19
+ signal?: AbortSignal;
20
+ }): Promise<BuildArtifact> {
21
+ options.signal?.throwIfAborted();
22
+ const outputDir = resolvePathInside(
23
+ options.appPath,
24
+ options.outputDirectory,
25
+ `${options.label} build output directory must be a relative path inside the app directory`,
26
+ );
27
+ const outputStat = await stat(outputDir).catch(() => null);
28
+ if (!outputStat?.isDirectory()) {
29
+ throw new Error(
30
+ `${options.label} build output directory does not exist: ${options.outputDirectory}`,
31
+ );
32
+ }
33
+
34
+ const [realAppPath, realOutputDir] = await Promise.all([
35
+ realpath(path.resolve(options.appPath)),
36
+ realpath(outputDir),
37
+ ]);
38
+ if (!isPathWithin(realAppPath, realOutputDir)) {
39
+ throw new Error(
40
+ `${options.label} build output directory must stay inside the app directory`,
41
+ );
42
+ }
43
+
44
+ const entrypoint = await resolveConfiguredArtifactEntrypoint({
45
+ directory: realOutputDir,
46
+ entrypoint: options.entrypoint,
47
+ label: options.label,
48
+ displayDirectory: options.outputDirectory,
49
+ missingEntrypointMessage: options.missingEntrypointMessage,
50
+ });
51
+
52
+ const outDir = await mkdtemp(path.join(os.tmpdir(), "compute-build-"));
53
+ try {
54
+ const artifactDir = path.join(outDir, "app");
55
+ await cp(realOutputDir, artifactDir, {
56
+ recursive: true,
57
+ verbatimSymlinks: true,
58
+ });
59
+ await normalizeArtifactSymlinks(
60
+ artifactDir,
61
+ options.appPath,
62
+ options.signal,
63
+ );
64
+
65
+ return {
66
+ directory: artifactDir,
67
+ entrypoint,
68
+ defaultPortMapping: {
69
+ http: defaultHttpPortForBuildType(options.buildType),
70
+ },
71
+ cleanup: () => rm(outDir, { recursive: true, force: true }),
72
+ };
73
+ } catch (error) {
74
+ await rm(outDir, { recursive: true, force: true });
75
+ throw error;
76
+ }
77
+ }
78
+
79
+ export async function resolveConfiguredArtifactEntrypoint(options: {
80
+ directory: string;
81
+ entrypoint: string;
82
+ label: string;
83
+ displayDirectory?: string;
84
+ missingEntrypointMessage?: string;
85
+ }): Promise<string> {
86
+ const entrypoint = normalizeConfiguredArtifactEntrypoint(
87
+ options.entrypoint,
88
+ options.label,
89
+ );
90
+ const entryPath = path.join(options.directory, entrypoint);
91
+ const entryStat = await stat(entryPath).catch(() => null);
92
+ if (!entryStat?.isFile()) {
93
+ if (options.missingEntrypointMessage) {
94
+ throw new Error(options.missingEntrypointMessage);
95
+ }
96
+ const directory = options.displayDirectory ?? options.directory;
97
+ throw new Error(
98
+ `${options.label} build entrypoint does not exist: ${directory}/${entrypoint}`,
99
+ );
100
+ }
101
+ return entrypoint;
102
+ }
103
+
104
+ export function normalizeConfiguredArtifactEntrypoint(
105
+ entrypoint: string,
106
+ label: string,
107
+ ): string {
108
+ const normalized = path.posix.normalize(
109
+ entrypoint.trim().replace(/\\/g, "/"),
110
+ );
111
+ if (
112
+ normalized.length === 0 ||
113
+ normalized === "." ||
114
+ normalized === ".." ||
115
+ normalized.startsWith("../") ||
116
+ normalized.includes("/../") ||
117
+ path.win32.isAbsolute(entrypoint) ||
118
+ path.posix.isAbsolute(normalized) ||
119
+ /^[A-Za-z]:/.test(normalized)
120
+ ) {
121
+ throw new Error(
122
+ `${label} build entrypoint must be a relative path inside the output directory`,
123
+ );
124
+ }
125
+
126
+ return normalized;
127
+ }
128
+
129
+ function resolvePathInside(
130
+ root: string,
131
+ relativePath: string,
132
+ errorMessage: string,
133
+ ): string {
134
+ const raw = relativePath.trim().replace(/\\/g, "/");
135
+ const normalized = path.posix.normalize(raw);
136
+ if (
137
+ raw.length === 0 ||
138
+ normalized === ".." ||
139
+ normalized.startsWith("../") ||
140
+ normalized.includes("/../") ||
141
+ path.win32.isAbsolute(relativePath) ||
142
+ path.posix.isAbsolute(normalized) ||
143
+ /^[A-Za-z]:/.test(normalized)
144
+ ) {
145
+ throw new Error(errorMessage);
146
+ }
147
+
148
+ const resolved = path.resolve(root, normalized);
149
+ const relative = path.relative(root, resolved);
150
+ if (
151
+ relative === ".." ||
152
+ relative.startsWith(`..${path.sep}`) ||
153
+ path.isAbsolute(relative)
154
+ ) {
155
+ throw new Error(errorMessage);
156
+ }
157
+
158
+ return resolved;
159
+ }
160
+
161
+ function isPathWithin(root: string, candidate: string): boolean {
162
+ const relative = path.relative(root, candidate);
163
+ return (
164
+ relative === "" ||
165
+ (!relative.startsWith(`..${path.sep}`) &&
166
+ relative !== ".." &&
167
+ !path.isAbsolute(relative))
168
+ );
169
+ }
@@ -0,0 +1,73 @@
1
+ import { type BuildSettings, resolveBuildSettings } from "./build-settings.ts";
2
+ import {
3
+ type BuildArtifact,
4
+ type BuildStrategy,
5
+ runBuildSettingsCommand,
6
+ } from "./build-strategy.ts";
7
+ import {
8
+ normalizeConfiguredArtifactEntrypoint,
9
+ stageConfiguredArtifact,
10
+ } from "./configured-artifact.ts";
11
+ import type { BuildCommandIo } from "./workspace.ts";
12
+
13
+ /**
14
+ * Generic artifact strategy for frameworks the SDK does not know about yet.
15
+ * Runs an optional command, stages a configured output directory as-is, and
16
+ * starts the configured entrypoint from inside that artifact.
17
+ */
18
+ export class CustomBuild implements BuildStrategy {
19
+ readonly #appPath: string;
20
+ readonly #entrypoint?: string;
21
+ readonly #buildSettings?: BuildSettings;
22
+ readonly #io?: BuildCommandIo;
23
+
24
+ constructor(options: {
25
+ appPath: string;
26
+ entrypoint?: string;
27
+ buildSettings?: BuildSettings;
28
+ io?: BuildCommandIo;
29
+ }) {
30
+ this.#appPath = options.appPath;
31
+ this.#entrypoint = options.entrypoint;
32
+ this.#buildSettings = options.buildSettings;
33
+ this.#io = options.io;
34
+ }
35
+
36
+ async canBuild(_signal?: AbortSignal): Promise<boolean> {
37
+ return Boolean(this.#entrypoint ?? this.#buildSettings?.entrypoint);
38
+ }
39
+
40
+ async execute(signal?: AbortSignal): Promise<BuildArtifact> {
41
+ signal?.throwIfAborted();
42
+ const settings =
43
+ this.#buildSettings ??
44
+ (await resolveBuildSettings({
45
+ appPath: this.#appPath,
46
+ buildType: "custom",
47
+ signal,
48
+ }));
49
+
50
+ const entrypoint = this.#entrypoint ?? settings.entrypoint;
51
+ if (!entrypoint) {
52
+ throw new Error("Custom build entrypoint is required");
53
+ }
54
+ normalizeConfiguredArtifactEntrypoint(entrypoint, "Custom");
55
+
56
+ await runBuildSettingsCommand({
57
+ appPath: this.#appPath,
58
+ settings,
59
+ failurePrefix: "Custom",
60
+ io: this.#io,
61
+ signal,
62
+ });
63
+
64
+ return stageConfiguredArtifact({
65
+ appPath: this.#appPath,
66
+ outputDirectory: settings.outputDirectory,
67
+ entrypoint,
68
+ buildType: "custom",
69
+ label: "Custom",
70
+ signal,
71
+ });
72
+ }
73
+ }
package/src/index.ts CHANGED
@@ -70,6 +70,7 @@ export type {
70
70
  UpdateEnvResult,
71
71
  } from "./compute-client.ts";
72
72
  export { ComputeClient } from "./compute-client.ts";
73
+ export { CustomBuild } from "./custom-build.ts";
73
74
  export type {
74
75
  DetectedSchema,
75
76
  MigrationCommand,
@@ -24,15 +24,11 @@ import type { BuildArtifact, BuildStrategy } from "./build-strategy.ts";
24
24
  import {
25
25
  hasPackageDependency,
26
26
  hasRootFile,
27
- runPackageCli,
27
+ runBuildSettingsCommand,
28
28
  } from "./build-strategy.ts";
29
29
  import { defaultHttpPortForBuildType } from "./config/frameworks.ts";
30
30
  import { resolveSourceRoot } from "./config/source-root.ts";
31
- import {
32
- type BuildCommandIo,
33
- readPackageManifest,
34
- runBuildCommand,
35
- } from "./workspace.ts";
31
+ import { type BuildCommandIo, readPackageManifest } from "./workspace.ts";
36
32
 
37
33
  const NEST_CLI_FILENAME = "nest-cli.json";
38
34
 
@@ -81,37 +77,26 @@ export class NestjsBuild implements BuildStrategy {
81
77
  signal,
82
78
  }));
83
79
 
84
- // `resolveBuildSettings` always returns a non-null `nest build` fallback, so
85
- // route by source: a user `build` script runs as-is, the framework default
86
- // goes through the launcher ladder (local bin -> npx -> bunx).
87
- const usingFrameworkDefault =
88
- settings.buildCommand === null ||
89
- settings.buildCommandSource === "NestJS default";
90
- if (!usingFrameworkDefault && settings.buildCommand) {
91
- await runBuildCommand({
92
- appPath: this.#appPath,
93
- command: settings.buildCommand,
94
- failurePrefix: "NestJS",
95
- env: this.#io?.env,
96
- onOutput: this.#io?.onOutput,
97
- signal,
98
- });
99
- } else {
100
- await runPackageCli({
101
- appPath: this.#appPath,
80
+ await runBuildSettingsCommand({
81
+ appPath: this.#appPath,
82
+ settings,
83
+ failurePrefix: "NestJS",
84
+ defaultCli: {
85
+ source: "NestJS default",
102
86
  cliName: "nest",
103
87
  args: ["build"],
104
- failurePrefix: "NestJS",
105
88
  missingMessage:
106
89
  "Could not find the Nest CLI. Add a `build` script to package.json, install @nestjs/cli, or ensure npx/bunx is available.",
107
- env: this.#io?.env,
108
- onOutput: this.#io?.onOutput,
109
- signal,
110
- });
111
- }
90
+ },
91
+ io: this.#io,
92
+ signal,
93
+ });
112
94
 
113
95
  signal?.throwIfAborted();
114
- const compiledEntry = await this.#resolveCompiledEntrypoint(signal);
96
+ const compiledEntry = await this.#resolveCompiledEntrypoint(
97
+ settings,
98
+ signal,
99
+ );
115
100
 
116
101
  const outDir = await mkdtemp(path.join(os.tmpdir(), "compute-build-"));
117
102
  try {
@@ -140,9 +125,16 @@ export class NestjsBuild implements BuildStrategy {
140
125
  * separators. Prefers `package.json` `main`, then the path computed from
141
126
  * `nest-cli.json` and the tsconfig `outDir`, then the common defaults.
142
127
  */
143
- async #resolveCompiledEntrypoint(signal?: AbortSignal): Promise<string> {
128
+ async #resolveCompiledEntrypoint(
129
+ settings: BuildSettings,
130
+ signal?: AbortSignal,
131
+ ): Promise<string> {
144
132
  const candidates: string[] = [];
145
133
 
134
+ if (settings.entrypoint) {
135
+ candidates.push(joinPosix(settings.outputDirectory, settings.entrypoint));
136
+ }
137
+
146
138
  const fromMain = await this.#mainFieldEntrypoint(signal);
147
139
  if (fromMain) {
148
140
  candidates.push(fromMain);
@@ -153,7 +145,7 @@ export class NestjsBuild implements BuildStrategy {
153
145
  candidates.push(fromConfig);
154
146
  }
155
147
 
156
- candidates.push(...DEFAULT_COMPILED_ENTRYPOINTS);
148
+ candidates.push(...compiledEntrypointDefaults(settings.outputDirectory));
157
149
 
158
150
  for (const candidate of candidates) {
159
151
  signal?.throwIfAborted();
@@ -195,6 +187,17 @@ export class NestjsBuild implements BuildStrategy {
195
187
  }
196
188
  }
197
189
 
190
+ function compiledEntrypointDefaults(outputDirectory: string): string[] {
191
+ if (outputDirectory === "dist") {
192
+ return DEFAULT_COMPILED_ENTRYPOINTS;
193
+ }
194
+ return [
195
+ joinPosix(outputDirectory, "src/main.js"),
196
+ joinPosix(outputDirectory, "main.js"),
197
+ ...DEFAULT_COMPILED_ENTRYPOINTS,
198
+ ];
199
+ }
200
+
198
201
  interface NestCliConfig {
199
202
  sourceRoot?: string;
200
203
  entryFile?: string;
@@ -9,9 +9,14 @@ import {
9
9
  resolveBuildSettings,
10
10
  } from "./build-settings.ts";
11
11
  import type { BuildArtifact, BuildStrategy } from "./build-strategy.ts";
12
- import { hasPackageDependency, hasRootFile } from "./build-strategy.ts";
12
+ import {
13
+ hasPackageDependency,
14
+ hasRootFile,
15
+ runBuildSettingsCommand,
16
+ } from "./build-strategy.ts";
13
17
  import { defaultHttpPortForBuildType } from "./config/frameworks.ts";
14
- import { type BuildCommandIo, runBuildCommand } from "./workspace.ts";
18
+ import { resolveConfiguredArtifactEntrypoint } from "./configured-artifact.ts";
19
+ import type { BuildCommandIo } from "./workspace.ts";
15
20
 
16
21
  const NEXT_CONFIG_FILENAMES = [
17
22
  "next.config.js",
@@ -63,20 +68,24 @@ export class NextjsBuild implements BuildStrategy {
63
68
  buildType: "nextjs",
64
69
  signal,
65
70
  }));
66
- if (settings.buildCommand) {
67
- await runBuildCommand({
68
- appPath: this.#appPath,
69
- command: settings.buildCommand,
70
- failurePrefix: "Next.js",
71
- env: this.#io?.env,
72
- onOutput: this.#io?.onOutput,
73
- signal,
74
- });
75
- }
71
+ await runBuildSettingsCommand({
72
+ appPath: this.#appPath,
73
+ settings,
74
+ failurePrefix: "Next.js",
75
+ defaultCli: {
76
+ source: "Next.js default",
77
+ cliName: "next",
78
+ args: ["build"],
79
+ missingMessage:
80
+ "Could not find the Next.js CLI. Install it with `npm install next` or ensure npx/bunx is available.",
81
+ },
82
+ io: this.#io,
83
+ signal,
84
+ });
76
85
 
77
86
  const standaloneDir = path.join(this.#appPath, settings.outputDirectory);
78
87
  if (!(await directoryExists(standaloneDir))) {
79
- if (this.#requireStandalone) {
88
+ if (this.#requireStandalone || settings.entrypoint) {
80
89
  throw new Error(
81
90
  `Next.js build did not produce standalone output at ${settings.outputDirectory}. ` +
82
91
  'Set output: "standalone" in your next.config; this deploy target requires it.',
@@ -97,7 +106,15 @@ export class NextjsBuild implements BuildStrategy {
97
106
  appPath: this.#appPath,
98
107
  signal,
99
108
  });
100
- const entrypoint = await findStandaloneEntrypoint(artifactDir);
109
+ const entrypoint = settings.entrypoint
110
+ ? await resolveConfiguredArtifactEntrypoint({
111
+ directory: artifactDir,
112
+ entrypoint: settings.entrypoint,
113
+ label: "Next.js",
114
+ displayDirectory: settings.outputDirectory,
115
+ missingEntrypointMessage: `Next.js standalone output did not contain configured entrypoint ${settings.outputDirectory}/${settings.entrypoint}.`,
116
+ })
117
+ : await findStandaloneEntrypoint(artifactDir);
101
118
  await copyStaticAssets({
102
119
  appPath: this.#appPath,
103
120
  artifactDir,
package/src/nuxt-build.ts CHANGED
@@ -1,15 +1,11 @@
1
- import { cp, mkdtemp, rm, stat } from "node:fs/promises";
2
- import os from "node:os";
3
- import path from "node:path";
4
-
5
- import { normalizeArtifactSymlinks } from "./artifact-postprocess.ts";
1
+ import { type BuildSettings, resolveBuildSettings } from "./build-settings.ts";
6
2
  import type { BuildArtifact, BuildStrategy } from "./build-strategy.ts";
7
3
  import {
8
4
  hasPackageDependency,
9
5
  hasRootFile,
10
- runPackageCli,
6
+ runBuildSettingsCommand,
11
7
  } from "./build-strategy.ts";
12
- import { defaultHttpPortForBuildType } from "./config/frameworks.ts";
8
+ import { stageConfiguredArtifact } from "./configured-artifact.ts";
13
9
  import type { BuildCommandIo } from "./workspace.ts";
14
10
 
15
11
  const NUXT_CONFIG_FILENAMES = [
@@ -26,10 +22,16 @@ const NUXT_CONFIG_FILENAMES = [
26
22
  */
27
23
  export class NuxtBuild implements BuildStrategy {
28
24
  readonly #appPath: string;
25
+ readonly #buildSettings?: BuildSettings;
29
26
  readonly #io?: BuildCommandIo;
30
27
 
31
- constructor(options: { appPath: string; io?: BuildCommandIo }) {
28
+ constructor(options: {
29
+ appPath: string;
30
+ buildSettings?: BuildSettings;
31
+ io?: BuildCommandIo;
32
+ }) {
32
33
  this.#appPath = options.appPath;
34
+ this.#buildSettings = options.buildSettings;
33
35
  this.#io = options.io;
34
36
  }
35
37
 
@@ -42,48 +44,39 @@ export class NuxtBuild implements BuildStrategy {
42
44
 
43
45
  async execute(signal?: AbortSignal): Promise<BuildArtifact> {
44
46
  signal?.throwIfAborted();
45
- await runPackageCli({
47
+ const settings =
48
+ this.#buildSettings ??
49
+ (await resolveBuildSettings({
50
+ appPath: this.#appPath,
51
+ buildType: "nuxt",
52
+ signal,
53
+ }));
54
+
55
+ await runBuildSettingsCommand({
46
56
  appPath: this.#appPath,
47
- cliName: "nuxt",
48
- args: ["build"],
57
+ settings,
49
58
  failurePrefix: "Nuxt",
50
- missingMessage:
51
- "Could not find the Nuxt CLI. Install it with `npm install nuxt` or ensure npx/bunx is available.",
52
- env: this.#io?.env,
53
- onOutput: this.#io?.onOutput,
59
+ defaultCli: {
60
+ source: "Nuxt default",
61
+ cliName: "nuxt",
62
+ args: ["build"],
63
+ missingMessage:
64
+ "Could not find the Nuxt CLI. Install it with `npm install nuxt` or ensure npx/bunx is available.",
65
+ },
66
+ io: this.#io,
54
67
  signal,
55
68
  });
56
69
 
57
- const outputDir = path.join(this.#appPath, ".output");
58
- const entryPath = path.join(outputDir, "server", "index.mjs");
59
- const entryStat = await stat(entryPath).catch(() => null);
60
- if (!entryStat?.isFile()) {
61
- throw new Error(
62
- "Nuxt build did not produce a Nitro node server entrypoint at .output/server/index.mjs. Ensure nitro.preset is 'node-server' (the default) — set NITRO_PRESET=node-server or remove any custom preset from nuxt.config.",
63
- );
64
- }
65
-
66
- const outDir = await mkdtemp(path.join(os.tmpdir(), "compute-build-"));
67
-
68
- try {
69
- const artifactDir = path.join(outDir, "app");
70
- await cp(outputDir, artifactDir, {
71
- recursive: true,
72
- verbatimSymlinks: true,
73
- });
74
- // Materialize any symlinks into the app/workspace node_modules so the
75
- // artifact is self-contained once unpacked elsewhere.
76
- await normalizeArtifactSymlinks(artifactDir, this.#appPath, signal);
77
-
78
- return {
79
- directory: artifactDir,
80
- entrypoint: "server/index.mjs",
81
- defaultPortMapping: { http: defaultHttpPortForBuildType("nuxt") },
82
- cleanup: () => rm(outDir, { recursive: true, force: true }),
83
- };
84
- } catch (error) {
85
- await rm(outDir, { recursive: true, force: true });
86
- throw error;
87
- }
70
+ return stageConfiguredArtifact({
71
+ appPath: this.#appPath,
72
+ outputDirectory: settings.outputDirectory,
73
+ entrypoint: settings.entrypoint ?? "server/index.mjs",
74
+ buildType: "nuxt",
75
+ label: "Nuxt",
76
+ missingEntrypointMessage: settings.entrypoint
77
+ ? undefined
78
+ : `Nuxt build did not produce a Nitro node server entrypoint at ${settings.outputDirectory}/server/index.mjs. Ensure nitro.preset is 'node-server' (the default) - set NITRO_PRESET=node-server or remove any custom preset from nuxt.config.`,
79
+ signal,
80
+ });
88
81
  }
89
82
  }
@@ -1,13 +1,11 @@
1
- import { cp, mkdtemp, rm, stat } from "node:fs/promises";
2
- import os from "node:os";
3
- import path from "node:path";
4
-
5
- import { normalizeArtifactSymlinks } from "./artifact-postprocess.ts";
6
1
  import { type BuildSettings, resolveBuildSettings } from "./build-settings.ts";
7
2
  import type { BuildArtifact, BuildStrategy } from "./build-strategy.ts";
8
- import { hasPackageDependency } from "./build-strategy.ts";
9
- import { defaultHttpPortForBuildType } from "./config/frameworks.ts";
10
- import { type BuildCommandIo, runBuildCommand } from "./workspace.ts";
3
+ import {
4
+ hasPackageDependency,
5
+ runBuildSettingsCommand,
6
+ } from "./build-strategy.ts";
7
+ import { stageConfiguredArtifact } from "./configured-artifact.ts";
8
+ import type { BuildCommandIo } from "./workspace.ts";
11
9
 
12
10
  const TANSTACK_START_PACKAGES = [
13
11
  "@tanstack/react-start",
@@ -47,51 +45,31 @@ export class TanstackStartBuild implements BuildStrategy {
47
45
  buildType: "tanstack-start",
48
46
  signal,
49
47
  }));
50
- if (settings.buildCommand) {
51
- await runBuildCommand({
52
- appPath: this.#appPath,
53
- command: settings.buildCommand,
54
- failurePrefix: "TanStack Start",
55
- env: this.#io?.env,
56
- onOutput: this.#io?.onOutput,
57
- signal,
58
- });
59
- }
60
-
61
- const outputDir = path.join(this.#appPath, settings.outputDirectory);
62
- const entrypoint = "server/index.mjs";
63
- const entryStat = await stat(path.join(outputDir, entrypoint)).catch(
64
- () => null,
65
- );
66
- if (!entryStat?.isFile()) {
67
- throw new Error(
68
- `TanStack Start build did not produce a Nitro node server entrypoint at ${settings.outputDirectory}/${entrypoint}. ` +
69
- "Ensure your vite.config includes the tanstackStart() and nitro() plugins with the default node preset.",
70
- );
71
- }
72
-
73
- const outDir = await mkdtemp(path.join(os.tmpdir(), "compute-build-"));
74
- try {
75
- const artifactDir = path.join(outDir, "app");
76
- await cp(outputDir, artifactDir, {
77
- recursive: true,
78
- verbatimSymlinks: true,
79
- });
80
- // Materialize any symlinks into the app/workspace node_modules so the
81
- // artifact is self-contained once unpacked elsewhere.
82
- await normalizeArtifactSymlinks(artifactDir, this.#appPath, signal);
48
+ await runBuildSettingsCommand({
49
+ appPath: this.#appPath,
50
+ settings,
51
+ failurePrefix: "TanStack Start",
52
+ defaultCli: {
53
+ source: "TanStack Start default",
54
+ cliName: "vite",
55
+ args: ["build"],
56
+ missingMessage:
57
+ "Could not find the Vite CLI. Install it with `npm install vite` or ensure npx/bunx is available.",
58
+ },
59
+ io: this.#io,
60
+ signal,
61
+ });
83
62
 
84
- return {
85
- directory: artifactDir,
86
- entrypoint,
87
- defaultPortMapping: {
88
- http: defaultHttpPortForBuildType("tanstack-start"),
89
- },
90
- cleanup: () => rm(outDir, { recursive: true, force: true }),
91
- };
92
- } catch (error) {
93
- await rm(outDir, { recursive: true, force: true });
94
- throw error;
95
- }
63
+ return stageConfiguredArtifact({
64
+ appPath: this.#appPath,
65
+ outputDirectory: settings.outputDirectory,
66
+ entrypoint: settings.entrypoint ?? "server/index.mjs",
67
+ buildType: "tanstack-start",
68
+ label: "TanStack Start",
69
+ missingEntrypointMessage: settings.entrypoint
70
+ ? undefined
71
+ : `TanStack Start build did not produce a Nitro node server entrypoint at ${settings.outputDirectory}/server/index.mjs. Ensure your vite.config includes the tanstackStart() and nitro() plugins with the default node preset.`,
72
+ signal,
73
+ });
96
74
  }
97
75
  }