@prisma/compute-sdk 0.31.0 → 0.33.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 +19 -0
- package/dist/artifact-stage.d.ts.map +1 -1
- package/dist/artifact-stage.js +24 -10
- package/dist/artifact-stage.js.map +1 -1
- package/dist/astro-build.d.ts.map +1 -1
- package/dist/astro-build.js +1 -0
- package/dist/astro-build.js.map +1 -1
- package/dist/config/index.d.ts +3 -2
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +3 -2
- package/dist/config/index.js.map +1 -1
- package/dist/config/json-schema.d.ts +229 -0
- package/dist/config/json-schema.d.ts.map +1 -0
- package/dist/config/json-schema.js +128 -0
- package/dist/config/json-schema.js.map +1 -0
- package/dist/config/load.d.ts +2 -1
- package/dist/config/load.d.ts.map +1 -1
- package/dist/config/load.js +26 -4
- package/dist/config/load.js.map +1 -1
- package/dist/config/normalize.d.ts +4 -0
- package/dist/config/normalize.d.ts.map +1 -1
- package/dist/config/normalize.js +9 -4
- package/dist/config/normalize.js.map +1 -1
- package/dist/config/serialize.d.ts +15 -0
- package/dist/config/serialize.d.ts.map +1 -1
- package/dist/config/serialize.js +14 -0
- package/dist/config/serialize.js.map +1 -1
- package/dist/configured-artifact-trace.d.ts +15 -0
- package/dist/configured-artifact-trace.d.ts.map +1 -0
- package/dist/configured-artifact-trace.js +58 -0
- package/dist/configured-artifact-trace.js.map +1 -0
- package/dist/configured-artifact.d.ts +1 -0
- package/dist/configured-artifact.d.ts.map +1 -1
- package/dist/configured-artifact.js +10 -0
- package/dist/configured-artifact.js.map +1 -1
- package/package.json +1 -1
- package/src/artifact-stage.ts +38 -18
- package/src/astro-build.ts +1 -0
- package/src/config/index.ts +9 -1
- package/src/config/json-schema.ts +147 -0
- package/src/config/load.ts +38 -7
- package/src/config/normalize.ts +9 -4
- package/src/config/serialize.ts +27 -0
- package/src/configured-artifact-trace.ts +98 -0
- package/src/configured-artifact.ts +11 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON Schema for `prisma.compute.json`, built from the same constants as the
|
|
3
|
+
* runtime validator so enums and key sets cannot drift.
|
|
4
|
+
*
|
|
5
|
+
* The schema exists for editor assistance ($schema autocomplete/validation)
|
|
6
|
+
* and static tooling. It encodes structure, enums, and ranges; cross-field
|
|
7
|
+
* rules (e.g. the custom framework requiring build output settings) stay in
|
|
8
|
+
* `normalizeComputeConfig`, which remains the authority for every format.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { COMPUTE_FRAMEWORKS, COMPUTE_REGIONS } from "./types.ts";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Intended publish location of the compute config JSON Schema. The URL does
|
|
15
|
+
* not resolve yet, so serializers omit `$schema` by default; once the schema
|
|
16
|
+
* is hosted here, pass this constant to `serializeComputeConfigJson` to emit
|
|
17
|
+
* it in generated configs.
|
|
18
|
+
*/
|
|
19
|
+
export const COMPUTE_CONFIG_JSON_SCHEMA_URL =
|
|
20
|
+
"https://schemas.prisma.io/compute.schema.json";
|
|
21
|
+
|
|
22
|
+
const ENV_SCHEMA = {
|
|
23
|
+
description:
|
|
24
|
+
"Environment variables for the deploy. A string is shorthand for a dotenv file path.",
|
|
25
|
+
oneOf: [
|
|
26
|
+
{ type: "string", minLength: 1 },
|
|
27
|
+
{
|
|
28
|
+
type: "object",
|
|
29
|
+
additionalProperties: false,
|
|
30
|
+
properties: {
|
|
31
|
+
file: {
|
|
32
|
+
description:
|
|
33
|
+
"Dotenv file path(s) resolved relative to the config file directory.",
|
|
34
|
+
oneOf: [
|
|
35
|
+
{ type: "string", minLength: 1 },
|
|
36
|
+
{ type: "array", items: { type: "string", minLength: 1 } },
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
vars: {
|
|
40
|
+
description:
|
|
41
|
+
"Inline environment variable assignments. This file is committed — keep secrets in platform branch config.",
|
|
42
|
+
type: "object",
|
|
43
|
+
additionalProperties: { type: "string", minLength: 1 },
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
} as const;
|
|
49
|
+
|
|
50
|
+
const BUILD_SCHEMA = {
|
|
51
|
+
description:
|
|
52
|
+
"Build settings. When present, these own the app's build configuration.",
|
|
53
|
+
type: "object",
|
|
54
|
+
additionalProperties: false,
|
|
55
|
+
properties: {
|
|
56
|
+
command: {
|
|
57
|
+
description:
|
|
58
|
+
"Build command run in the app root. null skips the build step.",
|
|
59
|
+
type: ["string", "null"],
|
|
60
|
+
},
|
|
61
|
+
outputDirectory: {
|
|
62
|
+
description:
|
|
63
|
+
'Framework output path relative to the app root, e.g. ".next/standalone".',
|
|
64
|
+
type: "string",
|
|
65
|
+
minLength: 1,
|
|
66
|
+
},
|
|
67
|
+
entrypoint: {
|
|
68
|
+
description:
|
|
69
|
+
"Entrypoint for the built artifact, relative to outputDirectory when one is set.",
|
|
70
|
+
type: "string",
|
|
71
|
+
minLength: 1,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
} as const;
|
|
75
|
+
|
|
76
|
+
const APP_SCHEMA = {
|
|
77
|
+
type: "object",
|
|
78
|
+
additionalProperties: false,
|
|
79
|
+
properties: {
|
|
80
|
+
name: {
|
|
81
|
+
description: "Deployed app name. Defaults to inference.",
|
|
82
|
+
type: "string",
|
|
83
|
+
minLength: 1,
|
|
84
|
+
},
|
|
85
|
+
region: {
|
|
86
|
+
description: "App region override. Defaults to the project region.",
|
|
87
|
+
enum: COMPUTE_REGIONS,
|
|
88
|
+
},
|
|
89
|
+
root: {
|
|
90
|
+
description:
|
|
91
|
+
"App directory relative to the config file. Defaults to the config file directory.",
|
|
92
|
+
type: "string",
|
|
93
|
+
minLength: 1,
|
|
94
|
+
},
|
|
95
|
+
framework: {
|
|
96
|
+
description:
|
|
97
|
+
"Framework to deploy. Defaults to detection from the app directory.",
|
|
98
|
+
enum: COMPUTE_FRAMEWORKS,
|
|
99
|
+
},
|
|
100
|
+
entry: {
|
|
101
|
+
description:
|
|
102
|
+
"Entrypoint path for Bun (and Hono) deploys, relative to the app root.",
|
|
103
|
+
type: "string",
|
|
104
|
+
minLength: 1,
|
|
105
|
+
},
|
|
106
|
+
httpPort: {
|
|
107
|
+
description:
|
|
108
|
+
"HTTP port the deployed app listens on. Defaults to the framework default.",
|
|
109
|
+
type: "integer",
|
|
110
|
+
minimum: 1,
|
|
111
|
+
maximum: 65535,
|
|
112
|
+
},
|
|
113
|
+
env: ENV_SCHEMA,
|
|
114
|
+
build: BUILD_SCHEMA,
|
|
115
|
+
},
|
|
116
|
+
} as const;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* The compute config JSON Schema document (draft-07 for the broadest editor
|
|
120
|
+
* support). Publish this at `COMPUTE_CONFIG_JSON_SCHEMA_URL`.
|
|
121
|
+
*/
|
|
122
|
+
export const COMPUTE_CONFIG_JSON_SCHEMA = {
|
|
123
|
+
$schema: "http://json-schema.org/draft-07/schema#",
|
|
124
|
+
$id: COMPUTE_CONFIG_JSON_SCHEMA_URL,
|
|
125
|
+
title: "Prisma Compute config",
|
|
126
|
+
description:
|
|
127
|
+
"Static serialization of the Prisma Compute config. Define app for a single-app repository or apps for a multi-app repository.",
|
|
128
|
+
type: "object",
|
|
129
|
+
additionalProperties: false,
|
|
130
|
+
properties: {
|
|
131
|
+
$schema: { type: "string" },
|
|
132
|
+
region: {
|
|
133
|
+
description:
|
|
134
|
+
"Default region used when creating new apps. Existing apps keep their current region.",
|
|
135
|
+
enum: COMPUTE_REGIONS,
|
|
136
|
+
},
|
|
137
|
+
app: APP_SCHEMA,
|
|
138
|
+
apps: {
|
|
139
|
+
description: "Apps keyed by deploy target name.",
|
|
140
|
+
type: "object",
|
|
141
|
+
minProperties: 1,
|
|
142
|
+
additionalProperties: APP_SCHEMA,
|
|
143
|
+
propertyNames: { minLength: 1 },
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
oneOf: [{ required: ["app"] }, { required: ["apps"] }],
|
|
147
|
+
} as const;
|
package/src/config/load.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import { access } from "node:fs/promises";
|
|
2
|
+
import { access, readFile } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
|
|
@@ -14,15 +14,18 @@ import {
|
|
|
14
14
|
import { sourceRootLineage } from "./source-root.ts";
|
|
15
15
|
|
|
16
16
|
export const COMPUTE_CONFIG_FILENAME = "prisma.compute.ts";
|
|
17
|
+
export const COMPUTE_CONFIG_JSON_FILENAME = "prisma.compute.json";
|
|
17
18
|
|
|
18
|
-
//
|
|
19
|
-
//
|
|
19
|
+
// One config schema, two serializations: TypeScript (and its JS variants) for
|
|
20
|
+
// programmatic configs, JSON for static dependency-free configs that any tool
|
|
21
|
+
// can read and write without executing code. Exactly one file may exist.
|
|
20
22
|
export const COMPUTE_CONFIG_FILENAMES = [
|
|
21
23
|
"prisma.compute.ts",
|
|
22
24
|
"prisma.compute.mts",
|
|
23
25
|
"prisma.compute.js",
|
|
24
26
|
"prisma.compute.mjs",
|
|
25
27
|
"prisma.compute.cjs",
|
|
28
|
+
"prisma.compute.json",
|
|
26
29
|
] as const;
|
|
27
30
|
|
|
28
31
|
// Config files import the typed helper through this specifier; it aliases
|
|
@@ -137,10 +140,13 @@ export async function loadComputeConfig(
|
|
|
137
140
|
|
|
138
141
|
const configPath = candidates[0] as string;
|
|
139
142
|
signal?.throwIfAborted();
|
|
140
|
-
const imported =
|
|
141
|
-
configPath
|
|
142
|
-
|
|
143
|
-
|
|
143
|
+
const imported =
|
|
144
|
+
path.extname(configPath) === ".json"
|
|
145
|
+
? await readComputeConfigJson(configPath)
|
|
146
|
+
: await importComputeConfigModule(
|
|
147
|
+
configPath,
|
|
148
|
+
options?.configModuleAlias,
|
|
149
|
+
);
|
|
144
150
|
if (imported.isErr()) {
|
|
145
151
|
return Result.err(imported.error);
|
|
146
152
|
}
|
|
@@ -150,6 +156,31 @@ export async function loadComputeConfig(
|
|
|
150
156
|
return Result.ok(null);
|
|
151
157
|
}
|
|
152
158
|
|
|
159
|
+
async function readComputeConfigJson(
|
|
160
|
+
configPath: string,
|
|
161
|
+
): Promise<Result<unknown, ComputeConfigLoadError>> {
|
|
162
|
+
return Result.tryPromise({
|
|
163
|
+
try: async () => {
|
|
164
|
+
const parsed: unknown = JSON.parse(await readFile(configPath, "utf8"));
|
|
165
|
+
// "$schema" is editor tooling metadata, not config; drop it before
|
|
166
|
+
// validation so JSON and TS configs share one schema exactly.
|
|
167
|
+
if (
|
|
168
|
+
parsed !== null &&
|
|
169
|
+
typeof parsed === "object" &&
|
|
170
|
+
!Array.isArray(parsed)
|
|
171
|
+
) {
|
|
172
|
+
const { $schema: _schema, ...config } = parsed as Record<
|
|
173
|
+
string,
|
|
174
|
+
unknown
|
|
175
|
+
>;
|
|
176
|
+
return config;
|
|
177
|
+
}
|
|
178
|
+
return parsed;
|
|
179
|
+
},
|
|
180
|
+
catch: (cause) => new ComputeConfigLoadError(configPath, cause),
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
153
184
|
async function importComputeConfigModule(
|
|
154
185
|
configPath: string,
|
|
155
186
|
configModuleAlias: string | undefined,
|
package/src/config/normalize.ts
CHANGED
|
@@ -107,7 +107,8 @@ export type ComputeConfigTargetError =
|
|
|
107
107
|
| ComputeConfigTargetRequiredError
|
|
108
108
|
| ComputeConfigTargetUnknownError;
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
// Exported so the JSON Schema (and its tests) provably cover the same keys.
|
|
111
|
+
export const KNOWN_APP_KEYS = [
|
|
111
112
|
"name",
|
|
112
113
|
"region",
|
|
113
114
|
"root",
|
|
@@ -117,9 +118,13 @@ const KNOWN_APP_KEYS = [
|
|
|
117
118
|
"env",
|
|
118
119
|
"build",
|
|
119
120
|
] as const;
|
|
120
|
-
const KNOWN_TOP_LEVEL_KEYS = ["app", "apps", "region"] as const;
|
|
121
|
-
const KNOWN_ENV_KEYS = ["file", "vars"] as const;
|
|
122
|
-
const KNOWN_BUILD_KEYS = [
|
|
121
|
+
export const KNOWN_TOP_LEVEL_KEYS = ["app", "apps", "region"] as const;
|
|
122
|
+
export const KNOWN_ENV_KEYS = ["file", "vars"] as const;
|
|
123
|
+
export const KNOWN_BUILD_KEYS = [
|
|
124
|
+
"command",
|
|
125
|
+
"outputDirectory",
|
|
126
|
+
"entrypoint",
|
|
127
|
+
] as const;
|
|
123
128
|
|
|
124
129
|
/**
|
|
125
130
|
* Validates and normalizes a config module's default export. Reports every
|
package/src/config/serialize.ts
CHANGED
|
@@ -29,6 +29,33 @@ export function serializeComputeConfig(
|
|
|
29
29
|
].join("\n");
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Renders a `prisma.compute.json` source file for a config — the same
|
|
34
|
+
* serialization as `serializeComputeConfig` in the dependency-free static
|
|
35
|
+
* format. Output round-trips through `normalizeComputeConfig` and is stable
|
|
36
|
+
* for committing to a repository.
|
|
37
|
+
*/
|
|
38
|
+
export function serializeComputeConfigJson(
|
|
39
|
+
config: ComputeConfig,
|
|
40
|
+
options?: {
|
|
41
|
+
/**
|
|
42
|
+
* `$schema` URL emitted for editor validation. Omitted by default:
|
|
43
|
+
* generated configs must not point editors at a URL that does not
|
|
44
|
+
* resolve, so pass `COMPUTE_CONFIG_JSON_SCHEMA_URL` explicitly once the
|
|
45
|
+
* schema is actually published there.
|
|
46
|
+
*/
|
|
47
|
+
schemaUrl?: string | null;
|
|
48
|
+
},
|
|
49
|
+
): string {
|
|
50
|
+
const schemaUrl = options?.schemaUrl ?? null;
|
|
51
|
+
const serializable = {
|
|
52
|
+
...(schemaUrl === null ? {} : { $schema: schemaUrl }),
|
|
53
|
+
...serializableComputeConfig(config),
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
return `${JSON.stringify(serializable, null, 2)}\n`;
|
|
57
|
+
}
|
|
58
|
+
|
|
32
59
|
function serializableComputeConfig(
|
|
33
60
|
config: ComputeConfig,
|
|
34
61
|
): SerializableComputeConfig {
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { realpath } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
import { nodeFileTrace } from "@vercel/nft";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
copyPathMaterializingSymlinks,
|
|
8
|
+
hoistIsolatedStoreDependencies,
|
|
9
|
+
isPathWithin,
|
|
10
|
+
} from "./artifact-stage.ts";
|
|
11
|
+
import { resolveSourceRoot } from "./config/source-root.ts";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Configured artifacts copy an output directory's contents to the artifact
|
|
15
|
+
* root. Runtime dependencies traced from that output need the same relocation:
|
|
16
|
+
* app-local node_modules become artifact-root node_modules, while hoisted
|
|
17
|
+
* workspace deps and workspace packages keep enough source-root layout for
|
|
18
|
+
* bare imports and package symlinks to resolve after unpacking.
|
|
19
|
+
*/
|
|
20
|
+
export async function stageConfiguredArtifactDependencies(options: {
|
|
21
|
+
appPath: string;
|
|
22
|
+
artifactDir: string;
|
|
23
|
+
outputDirectory: string;
|
|
24
|
+
entrypoint: string;
|
|
25
|
+
signal?: AbortSignal;
|
|
26
|
+
}): Promise<void> {
|
|
27
|
+
const [appRoot, outputRoot] = await Promise.all([
|
|
28
|
+
realpath(path.resolve(options.appPath)),
|
|
29
|
+
realpath(path.resolve(options.outputDirectory)),
|
|
30
|
+
]);
|
|
31
|
+
const sourceRoot = await resolveSourceRoot(appRoot, options.signal);
|
|
32
|
+
const entrypointPath = path.join(outputRoot, options.entrypoint);
|
|
33
|
+
|
|
34
|
+
options.signal?.throwIfAborted();
|
|
35
|
+
const { fileList } = await nodeFileTrace([entrypointPath], {
|
|
36
|
+
base: sourceRoot,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
for (const relativePath of fileList) {
|
|
40
|
+
options.signal?.throwIfAborted();
|
|
41
|
+
const sourcePath = path.join(sourceRoot, relativePath);
|
|
42
|
+
if (isPathWithin(outputRoot, sourcePath)) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
await copyPathMaterializingSymlinks(
|
|
47
|
+
sourcePath,
|
|
48
|
+
path.join(
|
|
49
|
+
options.artifactDir,
|
|
50
|
+
artifactRelativePathForTrace(sourcePath, {
|
|
51
|
+
appRoot,
|
|
52
|
+
sourceRoot,
|
|
53
|
+
}),
|
|
54
|
+
),
|
|
55
|
+
{
|
|
56
|
+
appRoot,
|
|
57
|
+
sourceRoot,
|
|
58
|
+
allowedSymlinkTargetRoots: [appRoot, sourceRoot],
|
|
59
|
+
ignoreMissingSource: true,
|
|
60
|
+
signal: options.signal,
|
|
61
|
+
},
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
await hoistIsolatedStoreDependencies(
|
|
66
|
+
path.join(options.artifactDir, "node_modules"),
|
|
67
|
+
options.signal,
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function artifactRelativePathForTrace(
|
|
72
|
+
sourcePath: string,
|
|
73
|
+
options: { appRoot: string; sourceRoot: string },
|
|
74
|
+
): string {
|
|
75
|
+
const resolvedSource = path.resolve(sourcePath);
|
|
76
|
+
const appNodeModules = path.join(options.appRoot, "node_modules");
|
|
77
|
+
const sourceNodeModules = path.join(options.sourceRoot, "node_modules");
|
|
78
|
+
|
|
79
|
+
if (isPathWithin(appNodeModules, resolvedSource)) {
|
|
80
|
+
return path.join(
|
|
81
|
+
"node_modules",
|
|
82
|
+
path.relative(appNodeModules, resolvedSource),
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (isPathWithin(options.appRoot, resolvedSource)) {
|
|
87
|
+
return path.relative(options.appRoot, resolvedSource);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (isPathWithin(sourceNodeModules, resolvedSource)) {
|
|
91
|
+
return path.join(
|
|
92
|
+
"node_modules",
|
|
93
|
+
path.relative(sourceNodeModules, resolvedSource),
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return path.relative(options.sourceRoot, resolvedSource);
|
|
98
|
+
}
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
defaultHttpPortForBuildType,
|
|
9
9
|
type FrameworkBuildType,
|
|
10
10
|
} from "./config/frameworks.ts";
|
|
11
|
+
import { stageConfiguredArtifactDependencies } from "./configured-artifact-trace.ts";
|
|
11
12
|
|
|
12
13
|
export async function stageConfiguredArtifact(options: {
|
|
13
14
|
appPath: string;
|
|
@@ -16,6 +17,7 @@ export async function stageConfiguredArtifact(options: {
|
|
|
16
17
|
buildType: FrameworkBuildType;
|
|
17
18
|
label: string;
|
|
18
19
|
missingEntrypointMessage?: string;
|
|
20
|
+
traceDependencies?: boolean;
|
|
19
21
|
signal?: AbortSignal;
|
|
20
22
|
}): Promise<BuildArtifact> {
|
|
21
23
|
options.signal?.throwIfAborted();
|
|
@@ -61,6 +63,15 @@ export async function stageConfiguredArtifact(options: {
|
|
|
61
63
|
options.appPath,
|
|
62
64
|
options.signal,
|
|
63
65
|
);
|
|
66
|
+
if (options.traceDependencies) {
|
|
67
|
+
await stageConfiguredArtifactDependencies({
|
|
68
|
+
appPath: realAppPath,
|
|
69
|
+
artifactDir,
|
|
70
|
+
outputDirectory: realOutputDir,
|
|
71
|
+
entrypoint,
|
|
72
|
+
signal: options.signal,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
64
75
|
|
|
65
76
|
return {
|
|
66
77
|
directory: artifactDir,
|