@prisma/compute-sdk 0.25.0 → 0.27.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.
- package/dist/artifact-stage.d.ts +24 -0
- package/dist/artifact-stage.d.ts.map +1 -0
- package/dist/artifact-stage.js +165 -0
- package/dist/artifact-stage.js.map +1 -0
- package/dist/astro-build.d.ts +2 -0
- package/dist/astro-build.d.ts.map +1 -1
- package/dist/astro-build.js +10 -1
- package/dist/astro-build.js.map +1 -1
- package/dist/auto-build.d.ts +7 -4
- package/dist/auto-build.d.ts.map +1 -1
- package/dist/auto-build.js +25 -33
- package/dist/auto-build.js.map +1 -1
- package/dist/build-settings.d.ts +55 -0
- package/dist/build-settings.d.ts.map +1 -0
- package/dist/build-settings.js +301 -0
- package/dist/build-settings.js.map +1 -0
- package/dist/build-strategy.d.ts +4 -0
- package/dist/build-strategy.d.ts.map +1 -1
- package/dist/build-strategy.js +13 -20
- package/dist/build-strategy.js.map +1 -1
- package/dist/build.d.ts +45 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +86 -0
- package/dist/build.js.map +1 -0
- package/dist/bun-build.d.ts +8 -0
- package/dist/bun-build.d.ts.map +1 -1
- package/dist/bun-build.js +49 -23
- package/dist/bun-build.js.map +1 -1
- package/dist/config/frameworks.d.ts +8 -1
- package/dist/config/frameworks.d.ts.map +1 -1
- package/dist/config/frameworks.js +28 -0
- package/dist/config/frameworks.js.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/nextjs-build.d.ts +12 -2
- package/dist/nextjs-build.d.ts.map +1 -1
- package/dist/nextjs-build.js +158 -76
- package/dist/nextjs-build.js.map +1 -1
- package/dist/nuxt-build.d.ts +2 -0
- package/dist/nuxt-build.d.ts.map +1 -1
- package/dist/nuxt-build.js +10 -1
- package/dist/nuxt-build.js.map +1 -1
- package/dist/tanstack-start-build.d.ts +6 -1
- package/dist/tanstack-start-build.d.ts.map +1 -1
- package/dist/tanstack-start-build.js +39 -16
- package/dist/tanstack-start-build.js.map +1 -1
- package/dist/workspace.d.ts +90 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +205 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +4 -3
- package/src/artifact-stage.ts +280 -0
- package/src/astro-build.ts +13 -2
- package/src/auto-build.ts +28 -34
- package/src/build-settings.ts +430 -0
- package/src/build-strategy.ts +22 -29
- package/src/build.ts +124 -0
- package/src/bun-build.ts +62 -27
- package/src/config/frameworks.ts +38 -0
- package/src/config/index.ts +1 -0
- package/src/index.ts +28 -0
- package/src/nextjs-build.ts +208 -104
- package/src/nuxt-build.ts +13 -2
- package/src/tanstack-start-build.ts +48 -19
- package/src/workspace.ts +319 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { readFile, stat } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { sourceRootLineage } from "./config/source-root.js";
|
|
5
|
+
/**
|
|
6
|
+
* Detects the package manager governing `appPath` by walking from the app up
|
|
7
|
+
* to the source root: the nearest `packageManager` field wins, then the
|
|
8
|
+
* nearest lockfile. Workspace repos keep both at the root, so a package
|
|
9
|
+
* deep in a monorepo still resolves correctly. Returns undefined when no
|
|
10
|
+
* signal is found.
|
|
11
|
+
*/
|
|
12
|
+
export async function resolvePackageManager(appPath, signal) {
|
|
13
|
+
for (const directory of await sourceRootLineage(appPath, signal)) {
|
|
14
|
+
const manifest = await readPackageManifest(directory, signal);
|
|
15
|
+
const fromField = packageManagerFromField(manifest?.packageManager);
|
|
16
|
+
if (fromField) {
|
|
17
|
+
return fromField;
|
|
18
|
+
}
|
|
19
|
+
if ((await pathExists(path.join(directory, "bun.lock"), signal)) ||
|
|
20
|
+
(await pathExists(path.join(directory, "bun.lockb"), signal))) {
|
|
21
|
+
return "bun";
|
|
22
|
+
}
|
|
23
|
+
if (await pathExists(path.join(directory, "pnpm-lock.yaml"), signal)) {
|
|
24
|
+
return "pnpm";
|
|
25
|
+
}
|
|
26
|
+
if (await pathExists(path.join(directory, "yarn.lock"), signal)) {
|
|
27
|
+
return "yarn";
|
|
28
|
+
}
|
|
29
|
+
if (await pathExists(path.join(directory, "package-lock.json"), signal)) {
|
|
30
|
+
return "npm";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Build environment for `appPath`: every `node_modules/.bin` between the app
|
|
37
|
+
* and its source root, prepended to PATH. Workspace repos hoist binaries like
|
|
38
|
+
* `next` to the workspace root, so a build run from a package directory still
|
|
39
|
+
* finds them. The returned object is suitable as the `env` for a child build
|
|
40
|
+
* process.
|
|
41
|
+
*/
|
|
42
|
+
export async function buildCommandEnv(appPath, baseEnv, signal) {
|
|
43
|
+
const binDirs = (await sourceRootLineage(appPath, signal)).map((directory) => path.join(directory, "node_modules", ".bin"));
|
|
44
|
+
return {
|
|
45
|
+
...baseEnv,
|
|
46
|
+
PATH: [...binDirs, baseEnv.PATH].filter(Boolean).join(path.delimiter),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Runs a build command string inside `appPath`, with every ancestor
|
|
51
|
+
* `node_modules/.bin` on PATH so workspace-hoisted binaries resolve. Rejects
|
|
52
|
+
* with the framework prefix and captured output on a non-zero exit.
|
|
53
|
+
*/
|
|
54
|
+
export async function runBuildCommand(options) {
|
|
55
|
+
const env = await buildCommandEnv(options.appPath, { ...process.env, ...options.env }, options.signal);
|
|
56
|
+
// `shell: true` preserves the platform shell so a command string like
|
|
57
|
+
// `pnpm run build` works the same as the CLI's previous `exec`.
|
|
58
|
+
await runChildProcess({
|
|
59
|
+
command: options.command,
|
|
60
|
+
args: [],
|
|
61
|
+
cwd: options.appPath,
|
|
62
|
+
env,
|
|
63
|
+
shell: true,
|
|
64
|
+
failurePrefix: options.failurePrefix,
|
|
65
|
+
onOutput: options.onOutput,
|
|
66
|
+
signal: options.signal,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Spawns a child build process, streaming each output line to `onOutput` and
|
|
71
|
+
* keeping a bounded tail for the failure message instead of buffering the whole
|
|
72
|
+
* build. Resolves on a zero exit; rejects on a non-zero exit (with the prefix,
|
|
73
|
+
* exit code, and tail) or a spawn error (whose `code`, e.g. ENOENT, is
|
|
74
|
+
* preserved on the rejection so a launcher ladder can branch on it).
|
|
75
|
+
*
|
|
76
|
+
* Shared by `runBuildCommand` (a shell command string) and `runPackageCli`
|
|
77
|
+
* (an explicit binary + args).
|
|
78
|
+
*/
|
|
79
|
+
export function runChildProcess(options) {
|
|
80
|
+
return new Promise((resolve, reject) => {
|
|
81
|
+
const tail = createBoundedTail();
|
|
82
|
+
const child = spawn(options.command, [...options.args], {
|
|
83
|
+
cwd: options.cwd,
|
|
84
|
+
env: options.env,
|
|
85
|
+
signal: options.signal,
|
|
86
|
+
shell: options.shell ?? false,
|
|
87
|
+
});
|
|
88
|
+
const streamed = Promise.all([
|
|
89
|
+
streamLines(child.stdout, "stdout", tail, options.onOutput),
|
|
90
|
+
streamLines(child.stderr, "stderr", tail, options.onOutput),
|
|
91
|
+
]);
|
|
92
|
+
child.on("error", (error) => {
|
|
93
|
+
// Preserve `code` (e.g. ENOENT) so a launcher ladder can fall through.
|
|
94
|
+
reject(Object.assign(new Error(`${options.failurePrefix} build failed:\n${error.message}`), { code: error.code }));
|
|
95
|
+
});
|
|
96
|
+
child.on("close", (code) => {
|
|
97
|
+
streamed.then(() => {
|
|
98
|
+
if (code === 0) {
|
|
99
|
+
resolve();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const detail = tail.text().trim();
|
|
103
|
+
const exit = code != null ? ` (exit code ${code})` : "";
|
|
104
|
+
reject(new Error(`${options.failurePrefix} build failed${exit}${detail ? `:\n${detail}` : "."}`));
|
|
105
|
+
}, reject);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/** Splits a child stream into lines, taps each, and records it in the tail. */
|
|
110
|
+
function streamLines(stream, source, tail, onOutput) {
|
|
111
|
+
return new Promise((resolve) => {
|
|
112
|
+
if (!stream) {
|
|
113
|
+
resolve();
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
stream.setEncoding("utf8");
|
|
117
|
+
let buffer = "";
|
|
118
|
+
const emit = (line) => {
|
|
119
|
+
tail.push(line);
|
|
120
|
+
onOutput?.(line, source);
|
|
121
|
+
};
|
|
122
|
+
stream.on("data", (chunk) => {
|
|
123
|
+
buffer += chunk;
|
|
124
|
+
let newline = buffer.indexOf("\n");
|
|
125
|
+
while (newline !== -1) {
|
|
126
|
+
emit(buffer.slice(0, newline));
|
|
127
|
+
buffer = buffer.slice(newline + 1);
|
|
128
|
+
newline = buffer.indexOf("\n");
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
stream.on("end", () => {
|
|
132
|
+
if (buffer.length > 0) {
|
|
133
|
+
emit(buffer);
|
|
134
|
+
}
|
|
135
|
+
resolve();
|
|
136
|
+
});
|
|
137
|
+
// A stream error surfaces through the child's own error/close handlers.
|
|
138
|
+
stream.on("error", () => resolve());
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/** A ring of the most recent output lines, for the failure message. */
|
|
142
|
+
function createBoundedTail(maxLines = 200) {
|
|
143
|
+
const lines = [];
|
|
144
|
+
return {
|
|
145
|
+
push(line) {
|
|
146
|
+
lines.push(line);
|
|
147
|
+
if (lines.length > maxLines) {
|
|
148
|
+
lines.shift();
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
text() {
|
|
152
|
+
return lines.join("\n");
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/** Reads and parses `appPath/package.json`, returning null on any failure. */
|
|
157
|
+
export async function readPackageManifest(appPath, signal) {
|
|
158
|
+
signal?.throwIfAborted();
|
|
159
|
+
try {
|
|
160
|
+
const content = await readFile(path.join(appPath, "package.json"), {
|
|
161
|
+
encoding: "utf-8",
|
|
162
|
+
signal,
|
|
163
|
+
});
|
|
164
|
+
const parsed = JSON.parse(content);
|
|
165
|
+
return isRecord(parsed) ? parsed : null;
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
// A missing file or invalid JSON is expected; an abort must propagate.
|
|
169
|
+
if (signal?.aborted)
|
|
170
|
+
throw error;
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/** The trimmed `scripts.build` string, or null when absent or empty. */
|
|
175
|
+
export function readBuildScript(manifest) {
|
|
176
|
+
const build = manifest?.scripts?.build;
|
|
177
|
+
if (typeof build !== "string") {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
const trimmed = build.trim();
|
|
181
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
182
|
+
}
|
|
183
|
+
function packageManagerFromField(value) {
|
|
184
|
+
if (typeof value !== "string") {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
const name = value.split("@")[0];
|
|
188
|
+
return name === "bun" || name === "pnpm" || name === "yarn" || name === "npm"
|
|
189
|
+
? name
|
|
190
|
+
: null;
|
|
191
|
+
}
|
|
192
|
+
async function pathExists(targetPath, signal) {
|
|
193
|
+
signal?.throwIfAborted();
|
|
194
|
+
try {
|
|
195
|
+
await stat(targetPath);
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function isRecord(value) {
|
|
203
|
+
return typeof value === "object" && value !== null;
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=workspace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma/compute-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.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",
|
|
@@ -38,10 +38,11 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"better-result": "^2.7.0",
|
|
41
|
+
"jiti": "^2.7.0",
|
|
42
|
+
"magicast": "^0.5.3",
|
|
41
43
|
"tar-stream": "^3.1.8",
|
|
42
44
|
"tiny-invariant": "1.3.3",
|
|
43
|
-
"ws": "^8.20.0"
|
|
44
|
-
"jiti": "^2.7.0"
|
|
45
|
+
"ws": "^8.20.0"
|
|
45
46
|
},
|
|
46
47
|
"peerDependencies": {
|
|
47
48
|
"@prisma/management-api-sdk": ">=1.36.0"
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import {
|
|
2
|
+
chmod,
|
|
3
|
+
copyFile,
|
|
4
|
+
lstat,
|
|
5
|
+
mkdir,
|
|
6
|
+
readdir,
|
|
7
|
+
readlink,
|
|
8
|
+
stat,
|
|
9
|
+
} from "node:fs/promises";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
|
|
12
|
+
import { resolveSourceRoot } from "./config/source-root.ts";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Stages a framework's standalone output (e.g. Next.js `.next/standalone`)
|
|
16
|
+
* into a deployable artifact directory, materializing the symlinks the output
|
|
17
|
+
* carries into the workspace `node_modules` and hoisting isolated-store
|
|
18
|
+
* dependencies (pnpm `.pnpm`, bun `.bun`) so Node resolution works once the
|
|
19
|
+
* artifact is unpacked elsewhere.
|
|
20
|
+
*
|
|
21
|
+
* Location-agnostic: the workspace boundary is resolved from `appPath`, not
|
|
22
|
+
* the current working directory.
|
|
23
|
+
*/
|
|
24
|
+
export async function stageStandaloneArtifact(options: {
|
|
25
|
+
standaloneDir: string;
|
|
26
|
+
artifactDir: string;
|
|
27
|
+
appPath: string;
|
|
28
|
+
signal?: AbortSignal;
|
|
29
|
+
}): Promise<void> {
|
|
30
|
+
const standaloneRoot = path.resolve(options.standaloneDir);
|
|
31
|
+
const artifactRoot = path.resolve(options.artifactDir);
|
|
32
|
+
const appRoot = path.resolve(options.appPath);
|
|
33
|
+
const sourceRoot = await resolveSourceRoot(appRoot, options.signal);
|
|
34
|
+
|
|
35
|
+
await copyPathMaterializingSymlinks(standaloneRoot, artifactRoot, {
|
|
36
|
+
standaloneRoot,
|
|
37
|
+
appRoot,
|
|
38
|
+
sourceRoot,
|
|
39
|
+
signal: options.signal,
|
|
40
|
+
});
|
|
41
|
+
await hoistIsolatedStoreDependencies(
|
|
42
|
+
path.join(artifactRoot, "node_modules"),
|
|
43
|
+
options.signal,
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Options shared by the symlink-materializing copy walk. */
|
|
48
|
+
interface MaterializeOptions {
|
|
49
|
+
/** Root of the standalone output being copied (for fallback resolution). */
|
|
50
|
+
standaloneRoot: string;
|
|
51
|
+
/** The app directory; symlink targets here are materialized. */
|
|
52
|
+
appRoot: string;
|
|
53
|
+
/** The workspace/source root; targets in its node_modules are materialized. */
|
|
54
|
+
sourceRoot: string;
|
|
55
|
+
signal?: AbortSignal;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* pnpm and bun (isolated linker) both keep packages in a virtual store with a
|
|
60
|
+
* shared symlink farm (`.pnpm/node_modules`, `.bun/node_modules`). Hoist the
|
|
61
|
+
* farm entries to the artifact's `node_modules` root so Node-style resolution
|
|
62
|
+
* works after symlinks are materialized.
|
|
63
|
+
*/
|
|
64
|
+
export async function hoistIsolatedStoreDependencies(
|
|
65
|
+
nodeModulesDir: string,
|
|
66
|
+
signal?: AbortSignal,
|
|
67
|
+
): Promise<void> {
|
|
68
|
+
await hoistStoreDependencies(
|
|
69
|
+
nodeModulesDir,
|
|
70
|
+
path.join(nodeModulesDir, ".pnpm", "node_modules"),
|
|
71
|
+
signal,
|
|
72
|
+
);
|
|
73
|
+
await hoistStoreDependencies(
|
|
74
|
+
nodeModulesDir,
|
|
75
|
+
path.join(nodeModulesDir, ".bun", "node_modules"),
|
|
76
|
+
signal,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function hoistStoreDependencies(
|
|
81
|
+
nodeModulesDir: string,
|
|
82
|
+
storeNodeModulesDir: string,
|
|
83
|
+
signal?: AbortSignal,
|
|
84
|
+
): Promise<void> {
|
|
85
|
+
if (!(await directoryExists(storeNodeModulesDir, signal))) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const entries = await readEntries(storeNodeModulesDir, signal);
|
|
90
|
+
for (const entry of entries) {
|
|
91
|
+
const sourcePath = path.join(storeNodeModulesDir, entry.name);
|
|
92
|
+
|
|
93
|
+
if (entry.name.startsWith("@") && entry.isDirectory()) {
|
|
94
|
+
const scopedEntries = await readEntries(sourcePath, signal);
|
|
95
|
+
for (const scopedEntry of scopedEntries) {
|
|
96
|
+
const scopedDestination = path.join(
|
|
97
|
+
nodeModulesDir,
|
|
98
|
+
entry.name,
|
|
99
|
+
scopedEntry.name,
|
|
100
|
+
);
|
|
101
|
+
if (await pathExists(scopedDestination, signal)) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
signal?.throwIfAborted();
|
|
105
|
+
await mkdir(path.dirname(scopedDestination), { recursive: true });
|
|
106
|
+
await copyPathMaterializingSymlinks(
|
|
107
|
+
path.join(sourcePath, scopedEntry.name),
|
|
108
|
+
scopedDestination,
|
|
109
|
+
storeMaterializeOptions(storeNodeModulesDir, nodeModulesDir, signal),
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const destinationPath = path.join(nodeModulesDir, entry.name);
|
|
116
|
+
if (await pathExists(destinationPath, signal)) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
await copyPathMaterializingSymlinks(
|
|
121
|
+
sourcePath,
|
|
122
|
+
destinationPath,
|
|
123
|
+
storeMaterializeOptions(storeNodeModulesDir, nodeModulesDir, signal),
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function storeMaterializeOptions(
|
|
129
|
+
storeNodeModulesDir: string,
|
|
130
|
+
nodeModulesDir: string,
|
|
131
|
+
signal?: AbortSignal,
|
|
132
|
+
): MaterializeOptions {
|
|
133
|
+
return {
|
|
134
|
+
standaloneRoot: storeNodeModulesDir,
|
|
135
|
+
appRoot: nodeModulesDir,
|
|
136
|
+
sourceRoot: nodeModulesDir,
|
|
137
|
+
signal,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async function copyPathMaterializingSymlinks(
|
|
142
|
+
sourcePath: string,
|
|
143
|
+
destinationPath: string,
|
|
144
|
+
options: MaterializeOptions,
|
|
145
|
+
): Promise<void> {
|
|
146
|
+
options.signal?.throwIfAborted();
|
|
147
|
+
const sourceStat = await lstat(sourcePath);
|
|
148
|
+
|
|
149
|
+
if (sourceStat.isSymbolicLink()) {
|
|
150
|
+
const resolvedTarget = await resolveSymlinkTarget(sourcePath, options);
|
|
151
|
+
if (resolvedTarget === null) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
await copyPathMaterializingSymlinks(
|
|
155
|
+
resolvedTarget,
|
|
156
|
+
destinationPath,
|
|
157
|
+
options,
|
|
158
|
+
);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (sourceStat.isDirectory()) {
|
|
163
|
+
await mkdir(destinationPath, { recursive: true });
|
|
164
|
+
const entries = await readEntries(sourcePath, options.signal);
|
|
165
|
+
for (const entry of entries) {
|
|
166
|
+
await copyPathMaterializingSymlinks(
|
|
167
|
+
path.join(sourcePath, entry.name),
|
|
168
|
+
path.join(destinationPath, entry.name),
|
|
169
|
+
options,
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (sourceStat.isFile()) {
|
|
176
|
+
await mkdir(path.dirname(destinationPath), { recursive: true });
|
|
177
|
+
await copyFile(sourcePath, destinationPath);
|
|
178
|
+
await chmod(destinationPath, sourceStat.mode);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async function resolveSymlinkTarget(
|
|
183
|
+
symlinkPath: string,
|
|
184
|
+
options: MaterializeOptions,
|
|
185
|
+
): Promise<string | null> {
|
|
186
|
+
options.signal?.throwIfAborted();
|
|
187
|
+
const linkTarget = await readlink(symlinkPath);
|
|
188
|
+
const resolvedTarget = path.resolve(path.dirname(symlinkPath), linkTarget);
|
|
189
|
+
|
|
190
|
+
if (await pathExists(resolvedTarget, options.signal)) {
|
|
191
|
+
if (
|
|
192
|
+
!isPathWithin(options.appRoot, resolvedTarget) &&
|
|
193
|
+
!isPathWithinWorkspaceDependency(options.sourceRoot, resolvedTarget)
|
|
194
|
+
) {
|
|
195
|
+
throw new Error(
|
|
196
|
+
`Build artifact symlink escapes the app directory: ${resolvedTarget}`,
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
return resolvedTarget;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (isPathWithin(options.standaloneRoot, resolvedTarget)) {
|
|
203
|
+
const fallbackTarget = path.join(
|
|
204
|
+
options.appRoot,
|
|
205
|
+
path.relative(options.standaloneRoot, resolvedTarget),
|
|
206
|
+
);
|
|
207
|
+
if (await pathExists(fallbackTarget, options.signal)) {
|
|
208
|
+
return fallbackTarget;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// pnpm's hoist layer (.pnpm/node_modules/*) contains speculative links that
|
|
213
|
+
// are routinely dangling — Next's tracer doesn't always align with what pnpm
|
|
214
|
+
// populated. Drop these silently. Dangling links elsewhere still throw so a
|
|
215
|
+
// real missing dep doesn't get masked.
|
|
216
|
+
if (isPnpmHoistLink(symlinkPath)) {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
throw new Error(
|
|
221
|
+
`Standalone symlink target is missing: ${symlinkPath} -> ${linkTarget} (resolved to ${resolvedTarget})`,
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function isPnpmHoistLink(symlinkPath: string): boolean {
|
|
226
|
+
const parts = path.dirname(symlinkPath).split(path.sep);
|
|
227
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
228
|
+
if (parts[i] === ".pnpm" && parts[i + 1] === "node_modules") {
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function isPathWithin(rootPath: string, candidatePath: string): boolean {
|
|
236
|
+
const relativePath = path.relative(rootPath, candidatePath);
|
|
237
|
+
return (
|
|
238
|
+
relativePath === "" ||
|
|
239
|
+
(!relativePath.startsWith(`..${path.sep}`) &&
|
|
240
|
+
relativePath !== ".." &&
|
|
241
|
+
!path.isAbsolute(relativePath))
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function isPathWithinWorkspaceDependency(
|
|
246
|
+
sourceRoot: string,
|
|
247
|
+
candidatePath: string,
|
|
248
|
+
): boolean {
|
|
249
|
+
return isPathWithin(path.join(sourceRoot, "node_modules"), candidatePath);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async function readEntries(directory: string, signal?: AbortSignal) {
|
|
253
|
+
signal?.throwIfAborted();
|
|
254
|
+
return readdir(directory, { withFileTypes: true });
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
async function pathExists(
|
|
258
|
+
targetPath: string,
|
|
259
|
+
signal?: AbortSignal,
|
|
260
|
+
): Promise<boolean> {
|
|
261
|
+
signal?.throwIfAborted();
|
|
262
|
+
try {
|
|
263
|
+
await stat(targetPath);
|
|
264
|
+
return true;
|
|
265
|
+
} catch {
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
async function directoryExists(
|
|
271
|
+
targetPath: string,
|
|
272
|
+
signal?: AbortSignal,
|
|
273
|
+
): Promise<boolean> {
|
|
274
|
+
signal?.throwIfAborted();
|
|
275
|
+
try {
|
|
276
|
+
return (await stat(targetPath)).isDirectory();
|
|
277
|
+
} catch {
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
}
|
package/src/astro-build.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { cp, mkdtemp, rm, stat } from "node:fs/promises";
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
import { normalizeArtifactSymlinks } from "./artifact-postprocess.ts";
|
|
4
6
|
import type { BuildArtifact, BuildStrategy } from "./build-strategy.ts";
|
|
5
7
|
import {
|
|
6
8
|
hasPackageDependency,
|
|
7
9
|
hasRootFile,
|
|
8
10
|
runPackageCli,
|
|
9
11
|
} from "./build-strategy.ts";
|
|
12
|
+
import { defaultHttpPortForBuildType } from "./config/frameworks.ts";
|
|
13
|
+
import type { BuildCommandIo } from "./workspace.ts";
|
|
10
14
|
|
|
11
15
|
const ASTRO_CONFIG_FILENAMES = [
|
|
12
16
|
"astro.config.js",
|
|
@@ -22,9 +26,11 @@ const ASTRO_CONFIG_FILENAMES = [
|
|
|
22
26
|
*/
|
|
23
27
|
export class AstroBuild implements BuildStrategy {
|
|
24
28
|
readonly #appPath: string;
|
|
29
|
+
readonly #io?: BuildCommandIo;
|
|
25
30
|
|
|
26
|
-
constructor(options: { appPath: string }) {
|
|
31
|
+
constructor(options: { appPath: string; io?: BuildCommandIo }) {
|
|
27
32
|
this.#appPath = options.appPath;
|
|
33
|
+
this.#io = options.io;
|
|
28
34
|
}
|
|
29
35
|
|
|
30
36
|
async canBuild(signal?: AbortSignal): Promise<boolean> {
|
|
@@ -43,6 +49,8 @@ export class AstroBuild implements BuildStrategy {
|
|
|
43
49
|
failurePrefix: "Astro",
|
|
44
50
|
missingMessage:
|
|
45
51
|
"Could not find the Astro CLI. Install it with `npm install astro` or ensure npx/bunx is available.",
|
|
52
|
+
env: this.#io?.env,
|
|
53
|
+
onOutput: this.#io?.onOutput,
|
|
46
54
|
signal,
|
|
47
55
|
});
|
|
48
56
|
|
|
@@ -63,11 +71,14 @@ export class AstroBuild implements BuildStrategy {
|
|
|
63
71
|
recursive: true,
|
|
64
72
|
verbatimSymlinks: true,
|
|
65
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);
|
|
66
77
|
|
|
67
78
|
return {
|
|
68
79
|
directory: artifactDir,
|
|
69
80
|
entrypoint: "server/entry.mjs",
|
|
70
|
-
defaultPortMapping: { http:
|
|
81
|
+
defaultPortMapping: { http: defaultHttpPortForBuildType("astro") },
|
|
71
82
|
cleanup: () => rm(outDir, { recursive: true, force: true }),
|
|
72
83
|
};
|
|
73
84
|
} catch (error) {
|
package/src/auto-build.ts
CHANGED
|
@@ -1,47 +1,41 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type BuildStrategyHooks, resolveBuildStrategy } from "./build.ts";
|
|
2
2
|
import type { BuildArtifact, BuildStrategy } from "./build-strategy.ts";
|
|
3
|
-
import { BunBuild } from "./bun-build.ts";
|
|
4
|
-
import { NextjsBuild } from "./nextjs-build.ts";
|
|
5
|
-
import { NuxtBuild } from "./nuxt-build.ts";
|
|
6
|
-
import { TanstackStartBuild } from "./tanstack-start-build.ts";
|
|
7
3
|
|
|
8
4
|
/**
|
|
9
|
-
* Meta-strategy that auto-detects the appropriate build strategy
|
|
10
|
-
*
|
|
5
|
+
* Meta-strategy that auto-detects the appropriate framework build strategy and
|
|
6
|
+
* delegates to it. Detection runs in registry order with bun as the universal
|
|
7
|
+
* fallback, so a buildable strategy always resolves. Use `resolveBuildStrategy`
|
|
8
|
+
* directly when the resolved build type is also needed.
|
|
11
9
|
*/
|
|
12
10
|
export class AutoBuild implements BuildStrategy {
|
|
13
|
-
readonly #
|
|
11
|
+
readonly #appPath: string;
|
|
12
|
+
readonly #entrypoint?: string;
|
|
13
|
+
readonly #hooks: BuildStrategyHooks;
|
|
14
14
|
|
|
15
|
-
constructor(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}),
|
|
25
|
-
];
|
|
15
|
+
constructor(
|
|
16
|
+
options: { appPath: string; entrypoint?: string } & BuildStrategyHooks,
|
|
17
|
+
) {
|
|
18
|
+
this.#appPath = options.appPath;
|
|
19
|
+
this.#entrypoint = options.entrypoint;
|
|
20
|
+
this.#hooks = {
|
|
21
|
+
io: options.io,
|
|
22
|
+
requireStandalone: options.requireStandalone,
|
|
23
|
+
};
|
|
26
24
|
}
|
|
27
25
|
|
|
28
|
-
async canBuild(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (await strategy.canBuild(signal)) {
|
|
32
|
-
return true;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return false;
|
|
26
|
+
async canBuild(_signal?: AbortSignal): Promise<boolean> {
|
|
27
|
+
// Detection always resolves (bun is the universal fallback).
|
|
28
|
+
return true;
|
|
36
29
|
}
|
|
37
30
|
|
|
38
31
|
async execute(signal?: AbortSignal): Promise<BuildArtifact> {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
32
|
+
const { strategy } = await resolveBuildStrategy({
|
|
33
|
+
appPath: this.#appPath,
|
|
34
|
+
entrypoint: this.#entrypoint,
|
|
35
|
+
buildType: "auto",
|
|
36
|
+
signal,
|
|
37
|
+
...this.#hooks,
|
|
38
|
+
});
|
|
39
|
+
return strategy.execute(signal);
|
|
46
40
|
}
|
|
47
41
|
}
|