@prisma/compute-sdk 0.14.0 → 0.16.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.
@@ -0,0 +1,14 @@
1
+ import type { BuildArtifact, BuildStrategy } from "./build-strategy.ts";
2
+ /**
3
+ * Build strategy for Astro applications using the @astrojs/node adapter
4
+ * in standalone mode. Runs `astro build` and produces an artifact from `dist/`.
5
+ */
6
+ export declare class AstroBuild implements BuildStrategy {
7
+ #private;
8
+ constructor(options: {
9
+ appPath: string;
10
+ });
11
+ canBuild(): Promise<boolean>;
12
+ execute(): Promise<BuildArtifact>;
13
+ }
14
+ //# sourceMappingURL=astro-build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"astro-build.d.ts","sourceRoot":"","sources":["../src/astro-build.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAexE;;;GAGG;AACH,qBAAa,UAAW,YAAW,aAAa;;gBAGlC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE;IAIlC,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAO5B,OAAO,IAAI,OAAO,CAAC,aAAa,CAAC;CAuCxC"}
@@ -0,0 +1,59 @@
1
+ import { cp, mkdtemp, rm, stat } from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { hasPackageDependency, hasRootFile, runPackageCli, } from "./build-strategy.js";
5
+ const ASTRO_CONFIG_FILENAMES = [
6
+ "astro.config.js",
7
+ "astro.config.mjs",
8
+ "astro.config.cjs",
9
+ "astro.config.ts",
10
+ "astro.config.mts",
11
+ ];
12
+ /**
13
+ * Build strategy for Astro applications using the @astrojs/node adapter
14
+ * in standalone mode. Runs `astro build` and produces an artifact from `dist/`.
15
+ */
16
+ export class AstroBuild {
17
+ #appPath;
18
+ constructor(options) {
19
+ this.#appPath = options.appPath;
20
+ }
21
+ async canBuild() {
22
+ return ((await hasRootFile(this.#appPath, ASTRO_CONFIG_FILENAMES)) ||
23
+ (await hasPackageDependency(this.#appPath, ["astro"])));
24
+ }
25
+ async execute() {
26
+ await runPackageCli({
27
+ appPath: this.#appPath,
28
+ cliName: "astro",
29
+ args: ["build"],
30
+ failurePrefix: "Astro",
31
+ missingMessage: "Could not find the Astro CLI. Install it with `npm install astro` or ensure npx/bunx is available.",
32
+ });
33
+ const distDir = path.join(this.#appPath, "dist");
34
+ const entryPath = path.join(distDir, "server", "entry.mjs");
35
+ const entryStat = await stat(entryPath).catch(() => null);
36
+ if (!entryStat?.isFile()) {
37
+ throw new Error('Astro build did not produce a standalone server entrypoint. Install @astrojs/node and configure it with adapter: node({ mode: "standalone" }) in your astro.config file.');
38
+ }
39
+ const outDir = await mkdtemp(path.join(os.tmpdir(), "compute-build-"));
40
+ try {
41
+ const artifactDir = path.join(outDir, "app");
42
+ await cp(distDir, artifactDir, {
43
+ recursive: true,
44
+ verbatimSymlinks: true,
45
+ });
46
+ return {
47
+ directory: artifactDir,
48
+ entrypoint: "server/entry.mjs",
49
+ defaultPortMapping: { http: 4321 },
50
+ cleanup: () => rm(outDir, { recursive: true, force: true }),
51
+ };
52
+ }
53
+ catch (error) {
54
+ await rm(outDir, { recursive: true, force: true });
55
+ throw error;
56
+ }
57
+ }
58
+ }
59
+ //# sourceMappingURL=astro-build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"astro-build.js","sourceRoot":"","sources":["../src/astro-build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,aAAa,GACd,MAAM,qBAAqB,CAAC;AAE7B,MAAM,sBAAsB,GAAG;IAC7B,iBAAiB;IACjB,kBAAkB;IAClB,kBAAkB;IAClB,iBAAiB;IACjB,kBAAkB;CACnB,CAAC;AAEF;;;GAGG;AACH,MAAM,OAAO,UAAU;IACZ,QAAQ,CAAS;IAE1B,YAAY,OAA4B;QACtC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,OAAO,CACL,CAAC,MAAM,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,sBAAsB,CAAC,CAAC;YAC1D,CAAC,MAAM,oBAAoB,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CACvD,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,aAAa,CAAC;YAClB,OAAO,EAAE,IAAI,CAAC,QAAQ;YACtB,OAAO,EAAE,OAAO;YAChB,IAAI,EAAE,CAAC,OAAO,CAAC;YACf,aAAa,EAAE,OAAO;YACtB,cAAc,EACZ,oGAAoG;SACvG,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACjD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;QAC5D,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAC1D,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CACb,0KAA0K,CAC3K,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAC;QAEvE,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAC7C,MAAM,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE;gBAC7B,SAAS,EAAE,IAAI;gBACf,gBAAgB,EAAE,IAAI;aACvB,CAAC,CAAC;YAEH,OAAO;gBACL,SAAS,EAAE,WAAW;gBACtB,UAAU,EAAE,kBAAkB;gBAC9B,kBAAkB,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;gBAClC,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;aAC5D,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACnD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"auto-build.d.ts","sourceRoot":"","sources":["../src/auto-build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIxE;;;GAGG;AACH,qBAAa,SAAU,YAAW,aAAa;;gBAGjC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE;IAUvD,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAS5B,OAAO,IAAI,OAAO,CAAC,aAAa,CAAC;CAQxC"}
1
+ {"version":3,"file":"auto-build.d.ts","sourceRoot":"","sources":["../src/auto-build.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAMxE;;;GAGG;AACH,qBAAa,SAAU,YAAW,aAAa;;gBAGjC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE;IAavD,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAS5B,OAAO,IAAI,OAAO,CAAC,aAAa,CAAC;CAQxC"}
@@ -1,5 +1,8 @@
1
+ import { AstroBuild } from "./astro-build.js";
1
2
  import { BunBuild } from "./bun-build.js";
2
3
  import { NextjsBuild } from "./nextjs-build.js";
4
+ import { NuxtBuild } from "./nuxt-build.js";
5
+ import { TanstackStartBuild } from "./tanstack-start-build.js";
3
6
  /**
4
7
  * Meta-strategy that auto-detects the appropriate build strategy.
5
8
  * Iterates over candidates and delegates to the first one that can handle the app.
@@ -9,6 +12,9 @@ export class AutoBuild {
9
12
  constructor(options) {
10
13
  this.#strategies = [
11
14
  new NextjsBuild({ appPath: options.appPath }),
15
+ new NuxtBuild({ appPath: options.appPath }),
16
+ new AstroBuild({ appPath: options.appPath }),
17
+ new TanstackStartBuild({ appPath: options.appPath }),
12
18
  new BunBuild({
13
19
  appPath: options.appPath,
14
20
  entrypoint: options.entrypoint,
@@ -1 +1 @@
1
- {"version":3,"file":"auto-build.js","sourceRoot":"","sources":["../src/auto-build.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD;;;GAGG;AACH,MAAM,OAAO,SAAS;IACX,WAAW,CAAkB;IAEtC,YAAY,OAAiD;QAC3D,IAAI,CAAC,WAAW,GAAG;YACjB,IAAI,WAAW,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;YAC7C,IAAI,QAAQ,CAAC;gBACX,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,UAAU,EAAE,OAAO,CAAC,UAAU;aAC/B,CAAC;SACH,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACxC,IAAI,MAAM,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC;gBAC9B,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK,CAAC,OAAO;QACX,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACxC,IAAI,MAAM,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC;gBAC9B,OAAO,QAAQ,CAAC,OAAO,EAAE,CAAC;YAC5B,CAAC;QACH,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAC3E,CAAC;CACF"}
1
+ {"version":3,"file":"auto-build.js","sourceRoot":"","sources":["../src/auto-build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D;;;GAGG;AACH,MAAM,OAAO,SAAS;IACX,WAAW,CAAkB;IAEtC,YAAY,OAAiD;QAC3D,IAAI,CAAC,WAAW,GAAG;YACjB,IAAI,WAAW,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;YAC7C,IAAI,SAAS,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;YAC3C,IAAI,UAAU,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;YAC5C,IAAI,kBAAkB,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;YACpD,IAAI,QAAQ,CAAC;gBACX,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,UAAU,EAAE,OAAO,CAAC,UAAU;aAC/B,CAAC;SACH,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACxC,IAAI,MAAM,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC;gBAC9B,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK,CAAC,OAAO;QACX,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACxC,IAAI,MAAM,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC;gBAC9B,OAAO,QAAQ,CAAC,OAAO,EAAE,CAAC;YAC5B,CAAC;QACH,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAC3E,CAAC;CACF"}
@@ -40,4 +40,34 @@ export declare class PreBuilt implements BuildStrategy {
40
40
  canBuild(): Promise<boolean>;
41
41
  execute(): Promise<BuildArtifact>;
42
42
  }
43
+ /**
44
+ * True if any of `filenames` exists at the root of `appPath`. Swallows
45
+ * readdir errors (missing/unreadable dir) and returns false.
46
+ */
47
+ export declare function hasRootFile(appPath: string, filenames: readonly string[]): Promise<boolean>;
48
+ /**
49
+ * True if any of `packageNames` is listed in `package.json`'s `dependencies`
50
+ * or `devDependencies`. Swallows missing-file / invalid-JSON errors and
51
+ * returns false.
52
+ */
53
+ export declare function hasPackageDependency(appPath: string, packageNames: readonly string[]): Promise<boolean>;
54
+ /**
55
+ * Run a package's CLI inside `appPath`. Tries the project-local bin first,
56
+ * then `npx <cliName>`, then `bunx <cliName>`. Each candidate that fails
57
+ * with ENOENT is skipped; other failures (e.g., build errors) re-throw
58
+ * with stderr surfaced.
59
+ *
60
+ * Throws with `missingMessage` if none of the launchers is available.
61
+ */
62
+ export declare function runPackageCli(opts: {
63
+ appPath: string;
64
+ /** Executable name, e.g. "astro", "next", "nuxt", "vite". */
65
+ cliName: string;
66
+ /** Args passed to the CLI, e.g. ["build"]. */
67
+ args: string[];
68
+ /** Prefix used when surfacing a build failure, e.g. "Astro". */
69
+ failurePrefix: string;
70
+ /** Thrown when no launcher is available. */
71
+ missingMessage: string;
72
+ }): Promise<void>;
43
73
  //# sourceMappingURL=build-strategy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-strategy.d.ts","sourceRoot":"","sources":["../src/build-strategy.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAC;IAElB,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAC;IAEnB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,WAAW,CAAC;IAEjC;;;;OAIG;IACH,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,OAAO,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC;CACnC;AAED;;;GAGG;AACH,qBAAa,QAAS,YAAW,aAAa;;gBAIhC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE;IAKtD,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAI5B,OAAO,IAAI,OAAO,CAAC,aAAa,CAAC;CAwBxC"}
1
+ {"version":3,"file":"build-strategy.d.ts","sourceRoot":"","sources":["../src/build-strategy.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAC;IAElB,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAC;IAEnB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,WAAW,CAAC;IAEjC;;;;OAIG;IACH,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,OAAO,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC;CACnC;AAED;;;GAGG;AACH,qBAAa,QAAS,YAAW,aAAa;;gBAIhC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE;IAKtD,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAI5B,OAAO,IAAI,OAAO,CAAC,aAAa,CAAC;CAwBxC;AAQD;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,SAAS,MAAM,EAAE,GAC3B,OAAO,CAAC,OAAO,CAAC,CAQlB;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,SAAS,MAAM,EAAE,GAC9B,OAAO,CAAC,OAAO,CAAC,CAwBlB;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,gEAAgE;IAChE,aAAa,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,cAAc,EAAE,MAAM,CAAC;CACxB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBhB"}
@@ -1,4 +1,5 @@
1
- import { stat } from "node:fs/promises";
1
+ import { execFile } from "node:child_process";
2
+ import { readdir, readFile, stat } from "node:fs/promises";
2
3
  import path from "node:path";
3
4
  /**
4
5
  * Reads directly from a pre-built application directory without copying.
@@ -33,4 +34,103 @@ export class PreBuilt {
33
34
  };
34
35
  }
35
36
  }
37
+ // ---------------------------------------------------------------------------
38
+ // Shared helpers used by framework strategies (Next, Nuxt, Astro, TanStack
39
+ // Start). Live here because they're tightly tied to the BuildStrategy surface
40
+ // (framework detection + CLI dispatch) and don't justify their own module.
41
+ // ---------------------------------------------------------------------------
42
+ /**
43
+ * True if any of `filenames` exists at the root of `appPath`. Swallows
44
+ * readdir errors (missing/unreadable dir) and returns false.
45
+ */
46
+ export async function hasRootFile(appPath, filenames) {
47
+ let entries;
48
+ try {
49
+ entries = await readdir(appPath);
50
+ }
51
+ catch {
52
+ return false;
53
+ }
54
+ return entries.some((entry) => filenames.includes(entry));
55
+ }
56
+ /**
57
+ * True if any of `packageNames` is listed in `package.json`'s `dependencies`
58
+ * or `devDependencies`. Swallows missing-file / invalid-JSON errors and
59
+ * returns false.
60
+ */
61
+ export async function hasPackageDependency(appPath, packageNames) {
62
+ let content;
63
+ try {
64
+ content = await readFile(path.join(appPath, "package.json"), "utf-8");
65
+ }
66
+ catch {
67
+ return false;
68
+ }
69
+ let parsed;
70
+ try {
71
+ parsed = JSON.parse(content);
72
+ }
73
+ catch {
74
+ return false;
75
+ }
76
+ const deps = isRecord(parsed.dependencies) ? parsed.dependencies : {};
77
+ const devDeps = isRecord(parsed.devDependencies)
78
+ ? parsed.devDependencies
79
+ : {};
80
+ return packageNames.some((name) => name in deps || name in devDeps);
81
+ }
82
+ /**
83
+ * Run a package's CLI inside `appPath`. Tries the project-local bin first,
84
+ * then `npx <cliName>`, then `bunx <cliName>`. Each candidate that fails
85
+ * with ENOENT is skipped; other failures (e.g., build errors) re-throw
86
+ * with stderr surfaced.
87
+ *
88
+ * Throws with `missingMessage` if none of the launchers is available.
89
+ */
90
+ export async function runPackageCli(opts) {
91
+ const localBin = path.join(opts.appPath, "node_modules", ".bin", opts.cliName);
92
+ const candidates = [
93
+ { command: localBin, args: opts.args },
94
+ { command: "npx", args: [opts.cliName, ...opts.args] },
95
+ { command: "bunx", args: [opts.cliName, ...opts.args] },
96
+ ];
97
+ for (const { command, args } of candidates) {
98
+ try {
99
+ await exec(command, args, opts.appPath, opts.failurePrefix);
100
+ return;
101
+ }
102
+ catch (error) {
103
+ if (isENOENT(error))
104
+ continue;
105
+ throw error;
106
+ }
107
+ }
108
+ throw new Error(opts.missingMessage);
109
+ }
110
+ function isRecord(value) {
111
+ return typeof value === "object" && value !== null;
112
+ }
113
+ function isENOENT(error) {
114
+ return (error instanceof Error &&
115
+ "code" in error &&
116
+ error.code === "ENOENT");
117
+ }
118
+ function exec(command, args, cwd, failurePrefix) {
119
+ return new Promise((resolve, reject) => {
120
+ execFile(command, args, { cwd }, (error, _stdout, stderr) => {
121
+ if (error) {
122
+ if ("code" in error && error.code === "ENOENT") {
123
+ reject(Object.assign(new Error(`${command} not found`), {
124
+ code: "ENOENT",
125
+ }));
126
+ return;
127
+ }
128
+ const message = stderr.trim() || error.message;
129
+ reject(new Error(`${failurePrefix} build failed:\n${message}`));
130
+ return;
131
+ }
132
+ resolve();
133
+ });
134
+ });
135
+ }
36
136
  //# sourceMappingURL=build-strategy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-strategy.js","sourceRoot":"","sources":["../src/build-strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,IAAI,MAAM,WAAW,CAAC;AAoC7B;;;GAGG;AACH,MAAM,OAAO,QAAQ;IACV,QAAQ,CAAS;IACjB,WAAW,CAAS;IAE7B,YAAY,OAAgD;QAC1D,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;QAChC,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAEpD,IAAI,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACxD,CAAC;QAED,IAAI,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;QAC1E,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QACtD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACrD,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CACb,+CAA+C,IAAI,CAAC,WAAW,EAAE,CAClE,CAAC;QACJ,CAAC;QAED,OAAO;YACL,SAAS,EAAE,IAAI,CAAC,QAAQ;YACxB,UAAU,EAAE,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;SACjD,CAAC;IACJ,CAAC;CACF"}
1
+ {"version":3,"file":"build-strategy.js","sourceRoot":"","sources":["../src/build-strategy.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { Err, matchError, matchErrorPartial, Ok, type Result, TaggedError, } from "better-result";
2
+ export { AstroBuild } from "./astro-build.ts";
2
3
  export { AutoBuild } from "./auto-build.ts";
3
4
  export type { BuildArtifact, BuildStrategy } from "./build-strategy.ts";
4
5
  export { PreBuilt } from "./build-strategy.ts";
@@ -11,6 +12,8 @@ export { ApiError, ArtifactError, AuthenticationError, BuildError, CancelledErro
11
12
  export type { LogRecord, LogStreamOptions, StreamLogsError, StreamRecord, StreamResult, TerminalRecord, } from "./log-stream.ts";
12
13
  export { streamLogs } from "./log-stream.ts";
13
14
  export { NextjsBuild } from "./nextjs-build.ts";
15
+ export { NuxtBuild } from "./nuxt-build.ts";
16
+ export { TanstackStartBuild } from "./tanstack-start-build.ts";
14
17
  export type { CreateProjectResult, DatabaseInfo, PortMapping, ProjectInfo, RegionInfo, ResolvedConfig, ServiceDetail, ServiceInfo, VersionDetail, VersionInfo, } from "./types.ts";
15
18
  export { KNOWN_REGION_IDS, REGIONS } from "./types.ts";
16
19
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,GAAG,EACH,UAAU,EACV,iBAAiB,EACjB,EAAE,EACF,KAAK,MAAM,EACX,WAAW,GACZ,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,YAAY,EACV,iBAAiB,EACjB,cAAc,EACd,sBAAsB,EACtB,yBAAyB,EACzB,sBAAsB,EACtB,eAAe,EACf,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,aAAa,EACb,YAAY,EACZ,qBAAqB,EACrB,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EACV,eAAe,EACf,WAAW,EACX,mBAAmB,EACnB,mBAAmB,EACnB,YAAY,EACZ,cAAc,EACd,qBAAqB,GACtB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,QAAQ,EACR,aAAa,EACb,mBAAmB,EACnB,UAAU,EACV,cAAc,EACd,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,EACpB,YAAY,EACZ,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,SAAS,EACT,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,cAAc,GACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EACV,mBAAmB,EACnB,YAAY,EACZ,WAAW,EACX,WAAW,EACX,UAAU,EACV,cAAc,EACd,aAAa,EACb,WAAW,EACX,aAAa,EACb,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,GAAG,EACH,UAAU,EACV,iBAAiB,EACjB,EAAE,EACF,KAAK,MAAM,EACX,WAAW,GACZ,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,YAAY,EACV,iBAAiB,EACjB,cAAc,EACd,sBAAsB,EACtB,yBAAyB,EACzB,sBAAsB,EACtB,eAAe,EACf,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,aAAa,EACb,YAAY,EACZ,qBAAqB,EACrB,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EACV,eAAe,EACf,WAAW,EACX,mBAAmB,EACnB,mBAAmB,EACnB,YAAY,EACZ,cAAc,EACd,qBAAqB,GACtB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,QAAQ,EACR,aAAa,EACb,mBAAmB,EACnB,UAAU,EACV,cAAc,EACd,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,EACpB,YAAY,EACZ,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,SAAS,EACT,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,cAAc,GACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,YAAY,EACV,mBAAmB,EACnB,YAAY,EACZ,WAAW,EACX,WAAW,EACX,UAAU,EACV,cAAc,EACd,aAAa,EACb,WAAW,EACX,aAAa,EACb,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // Re-export Result utilities so consumers don't need a direct better-result dependency
2
2
  export { Err, matchError, matchErrorPartial, Ok, TaggedError, } from "better-result";
3
+ export { AstroBuild } from "./astro-build.js";
3
4
  export { AutoBuild } from "./auto-build.js";
4
5
  export { PreBuilt } from "./build-strategy.js";
5
6
  export { BunBuild } from "./bun-build.js";
@@ -7,5 +8,7 @@ export { ComputeClient } from "./compute-client.js";
7
8
  export { ApiError, ArtifactError, AuthenticationError, BuildError, CancelledError, DestroyAggregateError, InvalidOptionsError, LogStreamError, MissingArgumentError, NoExistingVersionError, NoVersionsFoundError, TimeoutError, VersionFailedError, } from "./errors.js";
8
9
  export { streamLogs } from "./log-stream.js";
9
10
  export { NextjsBuild } from "./nextjs-build.js";
11
+ export { NuxtBuild } from "./nuxt-build.js";
12
+ export { TanstackStartBuild } from "./tanstack-start-build.js";
10
13
  export { KNOWN_REGION_IDS, REGIONS } from "./types.js";
11
14
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,OAAO,EACL,GAAG,EACH,UAAU,EACV,iBAAiB,EACjB,EAAE,EAEF,WAAW,GACZ,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAiC1C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAUpD,OAAO,EACL,QAAQ,EACR,aAAa,EACb,mBAAmB,EACnB,UAAU,EACV,cAAc,EACd,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,EACpB,YAAY,EACZ,kBAAkB,GACnB,MAAM,aAAa,CAAC;AASrB,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAahD,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,OAAO,EACL,GAAG,EACH,UAAU,EACV,iBAAiB,EACjB,EAAE,EAEF,WAAW,GACZ,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAiC1C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAUpD,OAAO,EACL,QAAQ,EACR,aAAa,EACb,mBAAmB,EACnB,UAAU,EACV,cAAc,EACd,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,EACpB,YAAY,EACZ,kBAAkB,GACnB,MAAM,aAAa,CAAC;AASrB,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAa/D,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"nextjs-build.d.ts","sourceRoot":"","sources":["../src/nextjs-build.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AASxE;;;GAGG;AACH,qBAAa,WAAY,YAAW,aAAa;;gBAGnC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE;IAIlC,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAI5B,OAAO,IAAI,OAAO,CAAC,aAAa,CAAC;CAkJxC"}
1
+ {"version":3,"file":"nextjs-build.d.ts","sourceRoot":"","sources":["../src/nextjs-build.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAcxE;;;GAGG;AACH,qBAAa,WAAY,YAAW,aAAa;;gBAGnC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE;IAIlC,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAO5B,OAAO,IAAI,OAAO,CAAC,aAAa,CAAC;CAuDxC"}
@@ -1,7 +1,7 @@
1
- import { execFile } from "node:child_process";
2
- import { cp, mkdtemp, readdir, readFile, rm, stat } from "node:fs/promises";
1
+ import { cp, mkdtemp, rm, stat } from "node:fs/promises";
3
2
  import os from "node:os";
4
3
  import path from "node:path";
4
+ import { hasPackageDependency, hasRootFile, runPackageCli, } from "./build-strategy.js";
5
5
  const NEXT_CONFIG_FILENAMES = [
6
6
  "next.config.js",
7
7
  "next.config.mjs",
@@ -18,10 +18,17 @@ export class NextjsBuild {
18
18
  this.#appPath = options.appPath;
19
19
  }
20
20
  async canBuild() {
21
- return (await this.#hasNextConfig()) || (await this.#hasNextDependency());
21
+ return ((await hasRootFile(this.#appPath, NEXT_CONFIG_FILENAMES)) ||
22
+ (await hasPackageDependency(this.#appPath, ["next"])));
22
23
  }
23
24
  async execute() {
24
- await this.#runBuild();
25
+ await runPackageCli({
26
+ appPath: this.#appPath,
27
+ cliName: "next",
28
+ args: ["build"],
29
+ failurePrefix: "Next.js",
30
+ missingMessage: "Could not find the Next.js CLI. Install it with `npm install next` or ensure npx/bunx is available.",
31
+ });
25
32
  const standaloneDir = path.join(this.#appPath, ".next", "standalone");
26
33
  const standaloneStat = await stat(standaloneDir).catch(() => null);
27
34
  if (!standaloneStat?.isDirectory()) {
@@ -30,17 +37,22 @@ export class NextjsBuild {
30
37
  const outDir = await mkdtemp(path.join(os.tmpdir(), "compute-build-"));
31
38
  try {
32
39
  const artifactDir = path.join(outDir, "app");
33
- await cp(standaloneDir, artifactDir, { recursive: true });
40
+ await cp(standaloneDir, artifactDir, {
41
+ recursive: true,
42
+ verbatimSymlinks: true,
43
+ });
34
44
  const publicDir = path.join(this.#appPath, "public");
35
- if (await this.#directoryExists(publicDir)) {
45
+ if (await directoryExists(publicDir)) {
36
46
  await cp(publicDir, path.join(artifactDir, "public"), {
37
47
  recursive: true,
48
+ verbatimSymlinks: true,
38
49
  });
39
50
  }
40
51
  const staticDir = path.join(this.#appPath, ".next", "static");
41
- if (await this.#directoryExists(staticDir)) {
52
+ if (await directoryExists(staticDir)) {
42
53
  await cp(staticDir, path.join(artifactDir, ".next", "static"), {
43
54
  recursive: true,
55
+ verbatimSymlinks: true,
44
56
  });
45
57
  }
46
58
  return {
@@ -55,85 +67,9 @@ export class NextjsBuild {
55
67
  throw error;
56
68
  }
57
69
  }
58
- async #hasNextConfig() {
59
- let entries;
60
- try {
61
- entries = await readdir(this.#appPath);
62
- }
63
- catch {
64
- return false;
65
- }
66
- return entries.some((entry) => NEXT_CONFIG_FILENAMES.includes(entry));
67
- }
68
- async #hasNextDependency() {
69
- const packageJsonPath = path.join(this.#appPath, "package.json");
70
- let content;
71
- try {
72
- content = await readFile(packageJsonPath, "utf-8");
73
- }
74
- catch {
75
- return false;
76
- }
77
- let parsed;
78
- try {
79
- parsed = JSON.parse(content);
80
- }
81
- catch {
82
- return false;
83
- }
84
- const deps = typeof parsed.dependencies === "object" && parsed.dependencies !== null
85
- ? parsed.dependencies
86
- : {};
87
- const devDeps = typeof parsed.devDependencies === "object" &&
88
- parsed.devDependencies !== null
89
- ? parsed.devDependencies
90
- : {};
91
- return "next" in deps || "next" in devDeps;
92
- }
93
- async #runBuild() {
94
- const localBin = path.join(this.#appPath, "node_modules", ".bin", "next");
95
- const candidates = [
96
- { command: localBin, args: ["build"] },
97
- { command: "npx", args: ["next", "build"] },
98
- { command: "bunx", args: ["next", "build"] },
99
- ];
100
- for (const { command, args } of candidates) {
101
- try {
102
- await this.#exec(command, args);
103
- return;
104
- }
105
- catch (error) {
106
- if (error instanceof Error &&
107
- "code" in error &&
108
- error.code === "ENOENT") {
109
- continue;
110
- }
111
- throw error;
112
- }
113
- }
114
- throw new Error("Could not find the Next.js CLI. Install it with `npm install next` or ensure npx/bunx is available.");
115
- }
116
- #exec(command, args) {
117
- return new Promise((resolve, reject) => {
118
- execFile(command, args, { cwd: this.#appPath }, (error, _stdout, stderr) => {
119
- if (error) {
120
- if ("code" in error && error.code === "ENOENT") {
121
- reject(Object.assign(new Error(`${command} not found`), {
122
- code: "ENOENT",
123
- }));
124
- return;
125
- }
126
- const message = stderr.trim() || error.message;
127
- reject(new Error(`Next.js build failed:\n${message}`));
128
- return;
129
- }
130
- resolve();
131
- });
132
- });
133
- }
134
- async #directoryExists(dirPath) {
135
- const s = await stat(dirPath).catch(() => null);
136
- return s?.isDirectory() ?? false;
137
- }
70
+ }
71
+ async function directoryExists(dirPath) {
72
+ const s = await stat(dirPath).catch(() => null);
73
+ return s?.isDirectory() ?? false;
138
74
  }
139
75
  //# sourceMappingURL=nextjs-build.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"nextjs-build.js","sourceRoot":"","sources":["../src/nextjs-build.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"nextjs-build.js","sourceRoot":"","sources":["../src/nextjs-build.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { BuildArtifact, BuildStrategy } from "./build-strategy.ts";
2
+ /**
3
+ * Build strategy for Nuxt applications using the Nitro `node-server` preset
4
+ * (the default). Runs `nuxt build` and produces an artifact from `.output/`.
5
+ */
6
+ export declare class NuxtBuild implements BuildStrategy {
7
+ #private;
8
+ constructor(options: {
9
+ appPath: string;
10
+ });
11
+ canBuild(): Promise<boolean>;
12
+ execute(): Promise<BuildArtifact>;
13
+ }
14
+ //# sourceMappingURL=nuxt-build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nuxt-build.d.ts","sourceRoot":"","sources":["../src/nuxt-build.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAexE;;;GAGG;AACH,qBAAa,SAAU,YAAW,aAAa;;gBAGjC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE;IAIlC,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAO5B,OAAO,IAAI,OAAO,CAAC,aAAa,CAAC;CAuCxC"}
@@ -0,0 +1,59 @@
1
+ import { cp, mkdtemp, rm, stat } from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { hasPackageDependency, hasRootFile, runPackageCli, } from "./build-strategy.js";
5
+ const NUXT_CONFIG_FILENAMES = [
6
+ "nuxt.config.js",
7
+ "nuxt.config.mjs",
8
+ "nuxt.config.cjs",
9
+ "nuxt.config.ts",
10
+ "nuxt.config.mts",
11
+ ];
12
+ /**
13
+ * Build strategy for Nuxt applications using the Nitro `node-server` preset
14
+ * (the default). Runs `nuxt build` and produces an artifact from `.output/`.
15
+ */
16
+ export class NuxtBuild {
17
+ #appPath;
18
+ constructor(options) {
19
+ this.#appPath = options.appPath;
20
+ }
21
+ async canBuild() {
22
+ return ((await hasRootFile(this.#appPath, NUXT_CONFIG_FILENAMES)) ||
23
+ (await hasPackageDependency(this.#appPath, ["nuxt"])));
24
+ }
25
+ async execute() {
26
+ await runPackageCli({
27
+ appPath: this.#appPath,
28
+ cliName: "nuxt",
29
+ args: ["build"],
30
+ failurePrefix: "Nuxt",
31
+ missingMessage: "Could not find the Nuxt CLI. Install it with `npm install nuxt` or ensure npx/bunx is available.",
32
+ });
33
+ const outputDir = path.join(this.#appPath, ".output");
34
+ const entryPath = path.join(outputDir, "server", "index.mjs");
35
+ const entryStat = await stat(entryPath).catch(() => null);
36
+ if (!entryStat?.isFile()) {
37
+ throw new Error("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.");
38
+ }
39
+ const outDir = await mkdtemp(path.join(os.tmpdir(), "compute-build-"));
40
+ try {
41
+ const artifactDir = path.join(outDir, "app");
42
+ await cp(outputDir, artifactDir, {
43
+ recursive: true,
44
+ verbatimSymlinks: true,
45
+ });
46
+ return {
47
+ directory: artifactDir,
48
+ entrypoint: "server/index.mjs",
49
+ defaultPortMapping: { http: 3000 },
50
+ cleanup: () => rm(outDir, { recursive: true, force: true }),
51
+ };
52
+ }
53
+ catch (error) {
54
+ await rm(outDir, { recursive: true, force: true });
55
+ throw error;
56
+ }
57
+ }
58
+ }
59
+ //# sourceMappingURL=nuxt-build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nuxt-build.js","sourceRoot":"","sources":["../src/nuxt-build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,aAAa,GACd,MAAM,qBAAqB,CAAC;AAE7B,MAAM,qBAAqB,GAAG;IAC5B,gBAAgB;IAChB,iBAAiB;IACjB,iBAAiB;IACjB,gBAAgB;IAChB,iBAAiB;CAClB,CAAC;AAEF;;;GAGG;AACH,MAAM,OAAO,SAAS;IACX,QAAQ,CAAS;IAE1B,YAAY,OAA4B;QACtC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,OAAO,CACL,CAAC,MAAM,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,qBAAqB,CAAC,CAAC;YACzD,CAAC,MAAM,oBAAoB,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CACtD,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,aAAa,CAAC;YAClB,OAAO,EAAE,IAAI,CAAC,QAAQ;YACtB,OAAO,EAAE,MAAM;YACf,IAAI,EAAE,CAAC,OAAO,CAAC;YACf,aAAa,EAAE,MAAM;YACrB,cAAc,EACZ,kGAAkG;SACrG,CAAC,CAAC;QAEH,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACtD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;QAC9D,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAC1D,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CACb,wNAAwN,CACzN,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAC;QAEvE,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAC7C,MAAM,EAAE,CAAC,SAAS,EAAE,WAAW,EAAE;gBAC/B,SAAS,EAAE,IAAI;gBACf,gBAAgB,EAAE,IAAI;aACvB,CAAC,CAAC;YAEH,OAAO;gBACL,SAAS,EAAE,WAAW;gBACtB,UAAU,EAAE,kBAAkB;gBAC9B,kBAAkB,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;gBAClC,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;aAC5D,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACnD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,14 @@
1
+ import type { BuildArtifact, BuildStrategy } from "./build-strategy.ts";
2
+ /**
3
+ * Build strategy for TanStack Start applications targeting the Nitro node
4
+ * preset. Runs `vite build` and produces an artifact from `.output/`.
5
+ */
6
+ export declare class TanstackStartBuild implements BuildStrategy {
7
+ #private;
8
+ constructor(options: {
9
+ appPath: string;
10
+ });
11
+ canBuild(): Promise<boolean>;
12
+ execute(): Promise<BuildArtifact>;
13
+ }
14
+ //# sourceMappingURL=tanstack-start-build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tanstack-start-build.d.ts","sourceRoot":"","sources":["../src/tanstack-start-build.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAQxE;;;GAGG;AACH,qBAAa,kBAAmB,YAAW,aAAa;;gBAG1C,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE;IAIlC,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAI5B,OAAO,IAAI,OAAO,CAAC,aAAa,CAAC;CAuCxC"}
@@ -0,0 +1,55 @@
1
+ import { cp, mkdtemp, rm, stat } from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { hasPackageDependency, runPackageCli } from "./build-strategy.js";
5
+ const TANSTACK_START_PACKAGES = [
6
+ "@tanstack/react-start",
7
+ "@tanstack/solid-start",
8
+ ];
9
+ /**
10
+ * Build strategy for TanStack Start applications targeting the Nitro node
11
+ * preset. Runs `vite build` and produces an artifact from `.output/`.
12
+ */
13
+ export class TanstackStartBuild {
14
+ #appPath;
15
+ constructor(options) {
16
+ this.#appPath = options.appPath;
17
+ }
18
+ async canBuild() {
19
+ return hasPackageDependency(this.#appPath, TANSTACK_START_PACKAGES);
20
+ }
21
+ async execute() {
22
+ await runPackageCli({
23
+ appPath: this.#appPath,
24
+ cliName: "vite",
25
+ args: ["build"],
26
+ failurePrefix: "TanStack Start",
27
+ missingMessage: "Could not find the Vite CLI. Install it with `npm install vite` or ensure npx/bunx is available.",
28
+ });
29
+ const outputDir = path.join(this.#appPath, ".output");
30
+ const entryPath = path.join(outputDir, "server", "index.mjs");
31
+ const entryStat = await stat(entryPath).catch(() => null);
32
+ if (!entryStat?.isFile()) {
33
+ throw new Error("TanStack Start build did not produce a Nitro node server entrypoint at .output/server/index.mjs. Ensure your vite.config includes the tanstackStart() and nitro() plugins with the default node preset.");
34
+ }
35
+ const outDir = await mkdtemp(path.join(os.tmpdir(), "compute-build-"));
36
+ try {
37
+ const artifactDir = path.join(outDir, "app");
38
+ await cp(outputDir, artifactDir, {
39
+ recursive: true,
40
+ verbatimSymlinks: true,
41
+ });
42
+ return {
43
+ directory: artifactDir,
44
+ entrypoint: "server/index.mjs",
45
+ defaultPortMapping: { http: 3000 },
46
+ cleanup: () => rm(outDir, { recursive: true, force: true }),
47
+ };
48
+ }
49
+ catch (error) {
50
+ await rm(outDir, { recursive: true, force: true });
51
+ throw error;
52
+ }
53
+ }
54
+ }
55
+ //# sourceMappingURL=tanstack-start-build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tanstack-start-build.js","sourceRoot":"","sources":["../src/tanstack-start-build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE1E,MAAM,uBAAuB,GAAG;IAC9B,uBAAuB;IACvB,uBAAuB;CACxB,CAAC;AAEF;;;GAGG;AACH,MAAM,OAAO,kBAAkB;IACpB,QAAQ,CAAS;IAE1B,YAAY,OAA4B;QACtC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,OAAO,oBAAoB,CAAC,IAAI,CAAC,QAAQ,EAAE,uBAAuB,CAAC,CAAC;IACtE,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,aAAa,CAAC;YAClB,OAAO,EAAE,IAAI,CAAC,QAAQ;YACtB,OAAO,EAAE,MAAM;YACf,IAAI,EAAE,CAAC,OAAO,CAAC;YACf,aAAa,EAAE,gBAAgB;YAC/B,cAAc,EACZ,kGAAkG;SACrG,CAAC,CAAC;QAEH,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACtD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;QAC9D,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAC1D,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CACb,yMAAyM,CAC1M,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAC;QAEvE,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAC7C,MAAM,EAAE,CAAC,SAAS,EAAE,WAAW,EAAE;gBAC/B,SAAS,EAAE,IAAI;gBACf,gBAAgB,EAAE,IAAI;aACvB,CAAC,CAAC;YAEH,OAAO;gBACL,SAAS,EAAE,WAAW;gBACtB,UAAU,EAAE,kBAAkB;gBAC9B,kBAAkB,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;gBAClC,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;aAC5D,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACnD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/compute-sdk",
3
- "version": "0.14.0",
3
+ "version": "0.16.0",
4
4
  "description": "TypeScript SDK for deploying and managing applications on Prisma Compute",
5
5
  "license": "Apache-2.0",
6
6
  "repository": "prisma/project-compute",
@@ -0,0 +1,76 @@
1
+ import { cp, mkdtemp, rm, stat } from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import type { BuildArtifact, BuildStrategy } from "./build-strategy.ts";
5
+ import {
6
+ hasPackageDependency,
7
+ hasRootFile,
8
+ runPackageCli,
9
+ } from "./build-strategy.ts";
10
+
11
+ const ASTRO_CONFIG_FILENAMES = [
12
+ "astro.config.js",
13
+ "astro.config.mjs",
14
+ "astro.config.cjs",
15
+ "astro.config.ts",
16
+ "astro.config.mts",
17
+ ];
18
+
19
+ /**
20
+ * Build strategy for Astro applications using the @astrojs/node adapter
21
+ * in standalone mode. Runs `astro build` and produces an artifact from `dist/`.
22
+ */
23
+ export class AstroBuild implements BuildStrategy {
24
+ readonly #appPath: string;
25
+
26
+ constructor(options: { appPath: string }) {
27
+ this.#appPath = options.appPath;
28
+ }
29
+
30
+ async canBuild(): Promise<boolean> {
31
+ return (
32
+ (await hasRootFile(this.#appPath, ASTRO_CONFIG_FILENAMES)) ||
33
+ (await hasPackageDependency(this.#appPath, ["astro"]))
34
+ );
35
+ }
36
+
37
+ async execute(): Promise<BuildArtifact> {
38
+ await runPackageCli({
39
+ appPath: this.#appPath,
40
+ cliName: "astro",
41
+ args: ["build"],
42
+ failurePrefix: "Astro",
43
+ missingMessage:
44
+ "Could not find the Astro CLI. Install it with `npm install astro` or ensure npx/bunx is available.",
45
+ });
46
+
47
+ const distDir = path.join(this.#appPath, "dist");
48
+ const entryPath = path.join(distDir, "server", "entry.mjs");
49
+ const entryStat = await stat(entryPath).catch(() => null);
50
+ if (!entryStat?.isFile()) {
51
+ throw new Error(
52
+ 'Astro build did not produce a standalone server entrypoint. Install @astrojs/node and configure it with adapter: node({ mode: "standalone" }) in your astro.config file.',
53
+ );
54
+ }
55
+
56
+ const outDir = await mkdtemp(path.join(os.tmpdir(), "compute-build-"));
57
+
58
+ try {
59
+ const artifactDir = path.join(outDir, "app");
60
+ await cp(distDir, artifactDir, {
61
+ recursive: true,
62
+ verbatimSymlinks: true,
63
+ });
64
+
65
+ return {
66
+ directory: artifactDir,
67
+ entrypoint: "server/entry.mjs",
68
+ defaultPortMapping: { http: 4321 },
69
+ cleanup: () => rm(outDir, { recursive: true, force: true }),
70
+ };
71
+ } catch (error) {
72
+ await rm(outDir, { recursive: true, force: true });
73
+ throw error;
74
+ }
75
+ }
76
+ }
package/src/auto-build.ts CHANGED
@@ -1,6 +1,9 @@
1
+ import { AstroBuild } from "./astro-build.ts";
1
2
  import type { BuildArtifact, BuildStrategy } from "./build-strategy.ts";
2
3
  import { BunBuild } from "./bun-build.ts";
3
4
  import { NextjsBuild } from "./nextjs-build.ts";
5
+ import { NuxtBuild } from "./nuxt-build.ts";
6
+ import { TanstackStartBuild } from "./tanstack-start-build.ts";
4
7
 
5
8
  /**
6
9
  * Meta-strategy that auto-detects the appropriate build strategy.
@@ -12,6 +15,9 @@ export class AutoBuild implements BuildStrategy {
12
15
  constructor(options: { appPath: string; entrypoint?: string }) {
13
16
  this.#strategies = [
14
17
  new NextjsBuild({ appPath: options.appPath }),
18
+ new NuxtBuild({ appPath: options.appPath }),
19
+ new AstroBuild({ appPath: options.appPath }),
20
+ new TanstackStartBuild({ appPath: options.appPath }),
15
21
  new BunBuild({
16
22
  appPath: options.appPath,
17
23
  entrypoint: options.entrypoint,
@@ -1,4 +1,5 @@
1
- import { stat } from "node:fs/promises";
1
+ import { execFile } from "node:child_process";
2
+ import { readdir, readFile, stat } from "node:fs/promises";
2
3
  import path from "node:path";
3
4
  import type { PortMapping } from "./types.ts";
4
5
 
@@ -77,3 +78,142 @@ export class PreBuilt implements BuildStrategy {
77
78
  };
78
79
  }
79
80
  }
81
+
82
+ // ---------------------------------------------------------------------------
83
+ // Shared helpers used by framework strategies (Next, Nuxt, Astro, TanStack
84
+ // Start). Live here because they're tightly tied to the BuildStrategy surface
85
+ // (framework detection + CLI dispatch) and don't justify their own module.
86
+ // ---------------------------------------------------------------------------
87
+
88
+ /**
89
+ * True if any of `filenames` exists at the root of `appPath`. Swallows
90
+ * readdir errors (missing/unreadable dir) and returns false.
91
+ */
92
+ export async function hasRootFile(
93
+ appPath: string,
94
+ filenames: readonly string[],
95
+ ): Promise<boolean> {
96
+ let entries: string[];
97
+ try {
98
+ entries = await readdir(appPath);
99
+ } catch {
100
+ return false;
101
+ }
102
+ return entries.some((entry) => filenames.includes(entry));
103
+ }
104
+
105
+ /**
106
+ * True if any of `packageNames` is listed in `package.json`'s `dependencies`
107
+ * or `devDependencies`. Swallows missing-file / invalid-JSON errors and
108
+ * returns false.
109
+ */
110
+ export async function hasPackageDependency(
111
+ appPath: string,
112
+ packageNames: readonly string[],
113
+ ): Promise<boolean> {
114
+ let content: string;
115
+ try {
116
+ content = await readFile(path.join(appPath, "package.json"), "utf-8");
117
+ } catch {
118
+ return false;
119
+ }
120
+
121
+ let parsed: { dependencies?: unknown; devDependencies?: unknown };
122
+ try {
123
+ parsed = JSON.parse(content) as {
124
+ dependencies?: unknown;
125
+ devDependencies?: unknown;
126
+ };
127
+ } catch {
128
+ return false;
129
+ }
130
+
131
+ const deps = isRecord(parsed.dependencies) ? parsed.dependencies : {};
132
+ const devDeps = isRecord(parsed.devDependencies)
133
+ ? parsed.devDependencies
134
+ : {};
135
+
136
+ return packageNames.some((name) => name in deps || name in devDeps);
137
+ }
138
+
139
+ /**
140
+ * Run a package's CLI inside `appPath`. Tries the project-local bin first,
141
+ * then `npx <cliName>`, then `bunx <cliName>`. Each candidate that fails
142
+ * with ENOENT is skipped; other failures (e.g., build errors) re-throw
143
+ * with stderr surfaced.
144
+ *
145
+ * Throws with `missingMessage` if none of the launchers is available.
146
+ */
147
+ export async function runPackageCli(opts: {
148
+ appPath: string;
149
+ /** Executable name, e.g. "astro", "next", "nuxt", "vite". */
150
+ cliName: string;
151
+ /** Args passed to the CLI, e.g. ["build"]. */
152
+ args: string[];
153
+ /** Prefix used when surfacing a build failure, e.g. "Astro". */
154
+ failurePrefix: string;
155
+ /** Thrown when no launcher is available. */
156
+ missingMessage: string;
157
+ }): Promise<void> {
158
+ const localBin = path.join(
159
+ opts.appPath,
160
+ "node_modules",
161
+ ".bin",
162
+ opts.cliName,
163
+ );
164
+ const candidates: Array<{ command: string; args: string[] }> = [
165
+ { command: localBin, args: opts.args },
166
+ { command: "npx", args: [opts.cliName, ...opts.args] },
167
+ { command: "bunx", args: [opts.cliName, ...opts.args] },
168
+ ];
169
+
170
+ for (const { command, args } of candidates) {
171
+ try {
172
+ await exec(command, args, opts.appPath, opts.failurePrefix);
173
+ return;
174
+ } catch (error) {
175
+ if (isENOENT(error)) continue;
176
+ throw error;
177
+ }
178
+ }
179
+
180
+ throw new Error(opts.missingMessage);
181
+ }
182
+
183
+ function isRecord(value: unknown): value is Record<string, unknown> {
184
+ return typeof value === "object" && value !== null;
185
+ }
186
+
187
+ function isENOENT(error: unknown): boolean {
188
+ return (
189
+ error instanceof Error &&
190
+ "code" in error &&
191
+ (error as { code?: string }).code === "ENOENT"
192
+ );
193
+ }
194
+
195
+ function exec(
196
+ command: string,
197
+ args: string[],
198
+ cwd: string,
199
+ failurePrefix: string,
200
+ ): Promise<void> {
201
+ return new Promise((resolve, reject) => {
202
+ execFile(command, args, { cwd }, (error, _stdout, stderr) => {
203
+ if (error) {
204
+ if ("code" in error && error.code === "ENOENT") {
205
+ reject(
206
+ Object.assign(new Error(`${command} not found`), {
207
+ code: "ENOENT",
208
+ }),
209
+ );
210
+ return;
211
+ }
212
+ const message = stderr.trim() || error.message;
213
+ reject(new Error(`${failurePrefix} build failed:\n${message}`));
214
+ return;
215
+ }
216
+ resolve();
217
+ });
218
+ });
219
+ }
package/src/index.ts CHANGED
@@ -7,6 +7,7 @@ export {
7
7
  type Result,
8
8
  TaggedError,
9
9
  } from "better-result";
10
+ export { AstroBuild } from "./astro-build.ts";
10
11
  export { AutoBuild } from "./auto-build.ts";
11
12
  export type { BuildArtifact, BuildStrategy } from "./build-strategy.ts";
12
13
  export { PreBuilt } from "./build-strategy.ts";
@@ -78,6 +79,8 @@ export type {
78
79
  } from "./log-stream.ts";
79
80
  export { streamLogs } from "./log-stream.ts";
80
81
  export { NextjsBuild } from "./nextjs-build.ts";
82
+ export { NuxtBuild } from "./nuxt-build.ts";
83
+ export { TanstackStartBuild } from "./tanstack-start-build.ts";
81
84
  export type {
82
85
  CreateProjectResult,
83
86
  DatabaseInfo,
@@ -1,8 +1,12 @@
1
- import { execFile } from "node:child_process";
2
- import { cp, mkdtemp, readdir, readFile, rm, stat } from "node:fs/promises";
1
+ import { cp, mkdtemp, rm, stat } from "node:fs/promises";
3
2
  import os from "node:os";
4
3
  import path from "node:path";
5
4
  import type { BuildArtifact, BuildStrategy } from "./build-strategy.ts";
5
+ import {
6
+ hasPackageDependency,
7
+ hasRootFile,
8
+ runPackageCli,
9
+ } from "./build-strategy.ts";
6
10
 
7
11
  const NEXT_CONFIG_FILENAMES = [
8
12
  "next.config.js",
@@ -23,11 +27,21 @@ export class NextjsBuild implements BuildStrategy {
23
27
  }
24
28
 
25
29
  async canBuild(): Promise<boolean> {
26
- return (await this.#hasNextConfig()) || (await this.#hasNextDependency());
30
+ return (
31
+ (await hasRootFile(this.#appPath, NEXT_CONFIG_FILENAMES)) ||
32
+ (await hasPackageDependency(this.#appPath, ["next"]))
33
+ );
27
34
  }
28
35
 
29
36
  async execute(): Promise<BuildArtifact> {
30
- await this.#runBuild();
37
+ await runPackageCli({
38
+ appPath: this.#appPath,
39
+ cliName: "next",
40
+ args: ["build"],
41
+ failurePrefix: "Next.js",
42
+ missingMessage:
43
+ "Could not find the Next.js CLI. Install it with `npm install next` or ensure npx/bunx is available.",
44
+ });
31
45
 
32
46
  const standaloneDir = path.join(this.#appPath, ".next", "standalone");
33
47
  const standaloneStat = await stat(standaloneDir).catch(() => null);
@@ -42,19 +56,24 @@ export class NextjsBuild implements BuildStrategy {
42
56
  try {
43
57
  const artifactDir = path.join(outDir, "app");
44
58
 
45
- await cp(standaloneDir, artifactDir, { recursive: true });
59
+ await cp(standaloneDir, artifactDir, {
60
+ recursive: true,
61
+ verbatimSymlinks: true,
62
+ });
46
63
 
47
64
  const publicDir = path.join(this.#appPath, "public");
48
- if (await this.#directoryExists(publicDir)) {
65
+ if (await directoryExists(publicDir)) {
49
66
  await cp(publicDir, path.join(artifactDir, "public"), {
50
67
  recursive: true,
68
+ verbatimSymlinks: true,
51
69
  });
52
70
  }
53
71
 
54
72
  const staticDir = path.join(this.#appPath, ".next", "static");
55
- if (await this.#directoryExists(staticDir)) {
73
+ if (await directoryExists(staticDir)) {
56
74
  await cp(staticDir, path.join(artifactDir, ".next", "static"), {
57
75
  recursive: true,
76
+ verbatimSymlinks: true,
58
77
  });
59
78
  }
60
79
 
@@ -69,107 +88,9 @@ export class NextjsBuild implements BuildStrategy {
69
88
  throw error;
70
89
  }
71
90
  }
91
+ }
72
92
 
73
- async #hasNextConfig(): Promise<boolean> {
74
- let entries: string[];
75
- try {
76
- entries = await readdir(this.#appPath);
77
- } catch {
78
- return false;
79
- }
80
- return entries.some((entry) => NEXT_CONFIG_FILENAMES.includes(entry));
81
- }
82
-
83
- async #hasNextDependency(): Promise<boolean> {
84
- const packageJsonPath = path.join(this.#appPath, "package.json");
85
-
86
- let content: string;
87
- try {
88
- content = await readFile(packageJsonPath, "utf-8");
89
- } catch {
90
- return false;
91
- }
92
-
93
- let parsed: { dependencies?: unknown; devDependencies?: unknown };
94
- try {
95
- parsed = JSON.parse(content) as {
96
- dependencies?: unknown;
97
- devDependencies?: unknown;
98
- };
99
- } catch {
100
- return false;
101
- }
102
-
103
- const deps =
104
- typeof parsed.dependencies === "object" && parsed.dependencies !== null
105
- ? parsed.dependencies
106
- : {};
107
- const devDeps =
108
- typeof parsed.devDependencies === "object" &&
109
- parsed.devDependencies !== null
110
- ? parsed.devDependencies
111
- : {};
112
-
113
- return "next" in deps || "next" in devDeps;
114
- }
115
-
116
- async #runBuild(): Promise<void> {
117
- const localBin = path.join(this.#appPath, "node_modules", ".bin", "next");
118
- const candidates: Array<{ command: string; args: string[] }> = [
119
- { command: localBin, args: ["build"] },
120
- { command: "npx", args: ["next", "build"] },
121
- { command: "bunx", args: ["next", "build"] },
122
- ];
123
-
124
- for (const { command, args } of candidates) {
125
- try {
126
- await this.#exec(command, args);
127
- return;
128
- } catch (error) {
129
- if (
130
- error instanceof Error &&
131
- "code" in error &&
132
- error.code === "ENOENT"
133
- ) {
134
- continue;
135
- }
136
- throw error;
137
- }
138
- }
139
-
140
- throw new Error(
141
- "Could not find the Next.js CLI. Install it with `npm install next` or ensure npx/bunx is available.",
142
- );
143
- }
144
-
145
- #exec(command: string, args: string[]): Promise<void> {
146
- return new Promise((resolve, reject) => {
147
- execFile(
148
- command,
149
- args,
150
- { cwd: this.#appPath },
151
- (error, _stdout, stderr) => {
152
- if (error) {
153
- if ("code" in error && error.code === "ENOENT") {
154
- reject(
155
- Object.assign(new Error(`${command} not found`), {
156
- code: "ENOENT",
157
- }),
158
- );
159
- return;
160
- }
161
- const message = stderr.trim() || error.message;
162
- reject(new Error(`Next.js build failed:\n${message}`));
163
- return;
164
- }
165
- resolve();
166
- },
167
- );
168
- });
169
- }
170
-
171
- async #directoryExists(dirPath: string): Promise<boolean> {
172
- const s = await stat(dirPath).catch(() => null);
173
- return s?.isDirectory() ?? false;
174
- }
93
+ async function directoryExists(dirPath: string): Promise<boolean> {
94
+ const s = await stat(dirPath).catch(() => null);
95
+ return s?.isDirectory() ?? false;
175
96
  }
@@ -0,0 +1,76 @@
1
+ import { cp, mkdtemp, rm, stat } from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import type { BuildArtifact, BuildStrategy } from "./build-strategy.ts";
5
+ import {
6
+ hasPackageDependency,
7
+ hasRootFile,
8
+ runPackageCli,
9
+ } from "./build-strategy.ts";
10
+
11
+ const NUXT_CONFIG_FILENAMES = [
12
+ "nuxt.config.js",
13
+ "nuxt.config.mjs",
14
+ "nuxt.config.cjs",
15
+ "nuxt.config.ts",
16
+ "nuxt.config.mts",
17
+ ];
18
+
19
+ /**
20
+ * Build strategy for Nuxt applications using the Nitro `node-server` preset
21
+ * (the default). Runs `nuxt build` and produces an artifact from `.output/`.
22
+ */
23
+ export class NuxtBuild implements BuildStrategy {
24
+ readonly #appPath: string;
25
+
26
+ constructor(options: { appPath: string }) {
27
+ this.#appPath = options.appPath;
28
+ }
29
+
30
+ async canBuild(): Promise<boolean> {
31
+ return (
32
+ (await hasRootFile(this.#appPath, NUXT_CONFIG_FILENAMES)) ||
33
+ (await hasPackageDependency(this.#appPath, ["nuxt"]))
34
+ );
35
+ }
36
+
37
+ async execute(): Promise<BuildArtifact> {
38
+ await runPackageCli({
39
+ appPath: this.#appPath,
40
+ cliName: "nuxt",
41
+ args: ["build"],
42
+ failurePrefix: "Nuxt",
43
+ missingMessage:
44
+ "Could not find the Nuxt CLI. Install it with `npm install nuxt` or ensure npx/bunx is available.",
45
+ });
46
+
47
+ const outputDir = path.join(this.#appPath, ".output");
48
+ const entryPath = path.join(outputDir, "server", "index.mjs");
49
+ const entryStat = await stat(entryPath).catch(() => null);
50
+ if (!entryStat?.isFile()) {
51
+ throw new Error(
52
+ "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.",
53
+ );
54
+ }
55
+
56
+ const outDir = await mkdtemp(path.join(os.tmpdir(), "compute-build-"));
57
+
58
+ try {
59
+ const artifactDir = path.join(outDir, "app");
60
+ await cp(outputDir, artifactDir, {
61
+ recursive: true,
62
+ verbatimSymlinks: true,
63
+ });
64
+
65
+ return {
66
+ directory: artifactDir,
67
+ entrypoint: "server/index.mjs",
68
+ defaultPortMapping: { http: 3000 },
69
+ cleanup: () => rm(outDir, { recursive: true, force: true }),
70
+ };
71
+ } catch (error) {
72
+ await rm(outDir, { recursive: true, force: true });
73
+ throw error;
74
+ }
75
+ }
76
+ }
@@ -0,0 +1,66 @@
1
+ import { cp, mkdtemp, rm, stat } from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import type { BuildArtifact, BuildStrategy } from "./build-strategy.ts";
5
+ import { hasPackageDependency, runPackageCli } from "./build-strategy.ts";
6
+
7
+ const TANSTACK_START_PACKAGES = [
8
+ "@tanstack/react-start",
9
+ "@tanstack/solid-start",
10
+ ];
11
+
12
+ /**
13
+ * Build strategy for TanStack Start applications targeting the Nitro node
14
+ * preset. Runs `vite build` and produces an artifact from `.output/`.
15
+ */
16
+ export class TanstackStartBuild implements BuildStrategy {
17
+ readonly #appPath: string;
18
+
19
+ constructor(options: { appPath: string }) {
20
+ this.#appPath = options.appPath;
21
+ }
22
+
23
+ async canBuild(): Promise<boolean> {
24
+ return hasPackageDependency(this.#appPath, TANSTACK_START_PACKAGES);
25
+ }
26
+
27
+ async execute(): Promise<BuildArtifact> {
28
+ await runPackageCli({
29
+ appPath: this.#appPath,
30
+ cliName: "vite",
31
+ args: ["build"],
32
+ failurePrefix: "TanStack Start",
33
+ missingMessage:
34
+ "Could not find the Vite CLI. Install it with `npm install vite` or ensure npx/bunx is available.",
35
+ });
36
+
37
+ const outputDir = path.join(this.#appPath, ".output");
38
+ const entryPath = path.join(outputDir, "server", "index.mjs");
39
+ const entryStat = await stat(entryPath).catch(() => null);
40
+ if (!entryStat?.isFile()) {
41
+ throw new Error(
42
+ "TanStack Start build did not produce a Nitro node server entrypoint at .output/server/index.mjs. Ensure your vite.config includes the tanstackStart() and nitro() plugins with the default node preset.",
43
+ );
44
+ }
45
+
46
+ const outDir = await mkdtemp(path.join(os.tmpdir(), "compute-build-"));
47
+
48
+ try {
49
+ const artifactDir = path.join(outDir, "app");
50
+ await cp(outputDir, artifactDir, {
51
+ recursive: true,
52
+ verbatimSymlinks: true,
53
+ });
54
+
55
+ return {
56
+ directory: artifactDir,
57
+ entrypoint: "server/index.mjs",
58
+ defaultPortMapping: { http: 3000 },
59
+ cleanup: () => rm(outDir, { recursive: true, force: true }),
60
+ };
61
+ } catch (error) {
62
+ await rm(outDir, { recursive: true, force: true });
63
+ throw error;
64
+ }
65
+ }
66
+ }