@prisma/compute-sdk 0.22.0 → 0.24.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/config/frameworks.d.ts +46 -0
- package/dist/config/frameworks.d.ts.map +1 -0
- package/dist/config/frameworks.js +129 -0
- package/dist/config/frameworks.js.map +1 -0
- package/dist/config/index.d.ts +15 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +15 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/load.d.ts +48 -0
- package/dist/config/load.d.ts.map +1 -0
- package/dist/config/load.js +138 -0
- package/dist/config/load.js.map +1 -0
- package/dist/config/normalize.d.ts +77 -0
- package/dist/config/normalize.d.ts.map +1 -0
- package/dist/config/normalize.js +366 -0
- package/dist/config/normalize.js.map +1 -0
- package/dist/config/serialize.d.ts +11 -0
- package/dist/config/serialize.d.ts.map +1 -0
- package/dist/config/serialize.js +55 -0
- package/dist/config/serialize.js.map +1 -0
- package/dist/config/source-root.d.ts +10 -0
- package/dist/config/source-root.d.ts.map +1 -0
- package/dist/config/source-root.js +72 -0
- package/dist/config/source-root.js.map +1 -0
- package/dist/config/types.d.ts +67 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +30 -0
- package/dist/config/types.js.map +1 -0
- package/package.json +10 -2
- package/src/config/frameworks.ts +187 -0
- package/src/config/index.ts +59 -0
- package/src/config/load.ts +198 -0
- package/src/config/normalize.ts +569 -0
- package/src/config/serialize.ts +76 -0
- package/src/config/source-root.ts +91 -0
- package/src/config/types.ts +78 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,QAAQ;IACR,MAAM;IACN,OAAO;IACP,MAAM;IACN,gBAAgB;IAChB,KAAK;CACG,CAAC;AAiDX;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAqB;IACvD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma/compute-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.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",
|
|
@@ -12,6 +12,13 @@
|
|
|
12
12
|
"types": "./dist/index.d.ts",
|
|
13
13
|
"default": "./dist/index.js"
|
|
14
14
|
}
|
|
15
|
+
},
|
|
16
|
+
"./config": {
|
|
17
|
+
"bun": "./src/config/index.ts",
|
|
18
|
+
"import": {
|
|
19
|
+
"types": "./dist/config/index.d.ts",
|
|
20
|
+
"default": "./dist/config/index.js"
|
|
21
|
+
}
|
|
15
22
|
}
|
|
16
23
|
},
|
|
17
24
|
"main": "./dist/index.js",
|
|
@@ -33,7 +40,8 @@
|
|
|
33
40
|
"better-result": "^2.7.0",
|
|
34
41
|
"tar-stream": "^3.1.8",
|
|
35
42
|
"tiny-invariant": "1.3.3",
|
|
36
|
-
"ws": "^8.20.0"
|
|
43
|
+
"ws": "^8.20.0",
|
|
44
|
+
"jiti": "^2.7.0"
|
|
37
45
|
},
|
|
38
46
|
"peerDependencies": {
|
|
39
47
|
"@prisma/management-api-sdk": ">=1.36.0"
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import type { ComputeFramework } from "./types.ts";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Framework capability registry — the single source of truth for what each
|
|
5
|
+
* supported framework is and can do. Commands, config validation, detection,
|
|
6
|
+
* and prompts all query this table; adding a framework means adding one
|
|
7
|
+
* entry here plus its build/run strategy implementation.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export type FrameworkBuildType =
|
|
11
|
+
| "nextjs"
|
|
12
|
+
| "nuxt"
|
|
13
|
+
| "astro"
|
|
14
|
+
| "tanstack-start"
|
|
15
|
+
| "bun";
|
|
16
|
+
|
|
17
|
+
export interface FrameworkDescriptor {
|
|
18
|
+
readonly key: ComputeFramework;
|
|
19
|
+
readonly displayName: string;
|
|
20
|
+
/** Build/deploy strategy this framework uses. */
|
|
21
|
+
readonly buildType: FrameworkBuildType;
|
|
22
|
+
/** Accepted user-facing spellings, lowercased, including the key. */
|
|
23
|
+
readonly aliases: readonly string[];
|
|
24
|
+
/** Dependencies whose presence detects this framework. */
|
|
25
|
+
readonly detectPackages: readonly string[];
|
|
26
|
+
/** Config files whose presence detects this framework. */
|
|
27
|
+
readonly detectConfigFiles: readonly string[];
|
|
28
|
+
/** Consumes a user-provided source entrypoint instead of build output. */
|
|
29
|
+
readonly usesEntrypoint: boolean;
|
|
30
|
+
/** Entrypoint assumed when the package defines none. */
|
|
31
|
+
readonly defaultEntrypoint: string | null;
|
|
32
|
+
/** Has a local dev server (`app run`) in the current preview. */
|
|
33
|
+
readonly hasLocalDevServer: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const NEXT_CONFIG_FILENAMES = [
|
|
37
|
+
"next.config.js",
|
|
38
|
+
"next.config.mjs",
|
|
39
|
+
"next.config.ts",
|
|
40
|
+
"next.config.mts",
|
|
41
|
+
] as const;
|
|
42
|
+
|
|
43
|
+
export const NUXT_CONFIG_FILENAMES = [
|
|
44
|
+
"nuxt.config.js",
|
|
45
|
+
"nuxt.config.mjs",
|
|
46
|
+
"nuxt.config.cjs",
|
|
47
|
+
"nuxt.config.ts",
|
|
48
|
+
"nuxt.config.mts",
|
|
49
|
+
] as const;
|
|
50
|
+
|
|
51
|
+
export const ASTRO_CONFIG_FILENAMES = [
|
|
52
|
+
"astro.config.js",
|
|
53
|
+
"astro.config.mjs",
|
|
54
|
+
"astro.config.cjs",
|
|
55
|
+
"astro.config.ts",
|
|
56
|
+
"astro.config.mts",
|
|
57
|
+
] as const;
|
|
58
|
+
|
|
59
|
+
// Detection checks frameworks in this order; keep more specific signals first.
|
|
60
|
+
export const FRAMEWORKS: readonly FrameworkDescriptor[] = [
|
|
61
|
+
{
|
|
62
|
+
key: "nextjs",
|
|
63
|
+
displayName: "Next.js",
|
|
64
|
+
buildType: "nextjs",
|
|
65
|
+
aliases: ["nextjs", "next", "next.js"],
|
|
66
|
+
detectPackages: ["next"],
|
|
67
|
+
detectConfigFiles: NEXT_CONFIG_FILENAMES,
|
|
68
|
+
usesEntrypoint: false,
|
|
69
|
+
defaultEntrypoint: null,
|
|
70
|
+
hasLocalDevServer: true,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
key: "nuxt",
|
|
74
|
+
displayName: "Nuxt",
|
|
75
|
+
buildType: "nuxt",
|
|
76
|
+
aliases: ["nuxt", "nuxtjs", "nuxt.js"],
|
|
77
|
+
detectPackages: ["nuxt"],
|
|
78
|
+
detectConfigFiles: NUXT_CONFIG_FILENAMES,
|
|
79
|
+
usesEntrypoint: false,
|
|
80
|
+
defaultEntrypoint: null,
|
|
81
|
+
hasLocalDevServer: false,
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
key: "astro",
|
|
85
|
+
displayName: "Astro",
|
|
86
|
+
buildType: "astro",
|
|
87
|
+
aliases: ["astro"],
|
|
88
|
+
detectPackages: ["astro"],
|
|
89
|
+
detectConfigFiles: ASTRO_CONFIG_FILENAMES,
|
|
90
|
+
usesEntrypoint: false,
|
|
91
|
+
defaultEntrypoint: null,
|
|
92
|
+
hasLocalDevServer: false,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
key: "hono",
|
|
96
|
+
displayName: "Hono",
|
|
97
|
+
buildType: "bun",
|
|
98
|
+
aliases: ["hono"],
|
|
99
|
+
detectPackages: ["hono"],
|
|
100
|
+
detectConfigFiles: [],
|
|
101
|
+
usesEntrypoint: true,
|
|
102
|
+
defaultEntrypoint: "src/index.ts",
|
|
103
|
+
hasLocalDevServer: true,
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
key: "tanstack-start",
|
|
107
|
+
displayName: "TanStack Start",
|
|
108
|
+
buildType: "tanstack-start",
|
|
109
|
+
aliases: [
|
|
110
|
+
"tanstack-start",
|
|
111
|
+
"tanstack",
|
|
112
|
+
"@tanstack/react-start",
|
|
113
|
+
"@tanstack/solid-start",
|
|
114
|
+
],
|
|
115
|
+
detectPackages: ["@tanstack/react-start", "@tanstack/solid-start"],
|
|
116
|
+
detectConfigFiles: [],
|
|
117
|
+
usesEntrypoint: false,
|
|
118
|
+
defaultEntrypoint: null,
|
|
119
|
+
hasLocalDevServer: false,
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
key: "bun",
|
|
123
|
+
displayName: "Bun",
|
|
124
|
+
buildType: "bun",
|
|
125
|
+
aliases: ["bun"],
|
|
126
|
+
detectPackages: [],
|
|
127
|
+
detectConfigFiles: [],
|
|
128
|
+
usesEntrypoint: true,
|
|
129
|
+
defaultEntrypoint: null,
|
|
130
|
+
hasLocalDevServer: true,
|
|
131
|
+
},
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
export const FRAMEWORK_KEYS = FRAMEWORKS.map((framework) => framework.key);
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Build types whose preview build consumes committed build settings. The
|
|
138
|
+
* others (nuxt, astro) run their framework CLI and stage fixed output, so a
|
|
139
|
+
* config `build` block has nothing to apply to.
|
|
140
|
+
*/
|
|
141
|
+
export const CONFIG_BACKED_BUILD_TYPES = [
|
|
142
|
+
"nextjs",
|
|
143
|
+
"tanstack-start",
|
|
144
|
+
"bun",
|
|
145
|
+
] as const satisfies readonly FrameworkBuildType[];
|
|
146
|
+
|
|
147
|
+
export type ConfigBackedBuildType = (typeof CONFIG_BACKED_BUILD_TYPES)[number];
|
|
148
|
+
|
|
149
|
+
/** Build types that consume a user-provided source entrypoint. */
|
|
150
|
+
export const ENTRYPOINT_BUILD_TYPES: readonly FrameworkBuildType[] = [
|
|
151
|
+
...new Set(
|
|
152
|
+
FRAMEWORKS.filter((framework) => framework.usesEntrypoint).map(
|
|
153
|
+
(framework) => framework.buildType,
|
|
154
|
+
),
|
|
155
|
+
),
|
|
156
|
+
];
|
|
157
|
+
|
|
158
|
+
/** Build types `app run` can start a local dev server for. */
|
|
159
|
+
export const LOCAL_DEV_BUILD_TYPES: readonly FrameworkBuildType[] = [
|
|
160
|
+
...new Set(
|
|
161
|
+
FRAMEWORKS.filter((framework) => framework.hasLocalDevServer).map(
|
|
162
|
+
(framework) => framework.buildType,
|
|
163
|
+
),
|
|
164
|
+
),
|
|
165
|
+
];
|
|
166
|
+
|
|
167
|
+
export function frameworkByKey(key: ComputeFramework): FrameworkDescriptor {
|
|
168
|
+
const framework = FRAMEWORKS.find((candidate) => candidate.key === key);
|
|
169
|
+
if (!framework) {
|
|
170
|
+
throw new Error(`Unknown framework key "${key}".`);
|
|
171
|
+
}
|
|
172
|
+
return framework;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export function frameworkFromAlias(value: string): FrameworkDescriptor | null {
|
|
176
|
+
const normalized = value.trim().toLowerCase();
|
|
177
|
+
return (
|
|
178
|
+
FRAMEWORKS.find((framework) => framework.aliases.includes(normalized)) ??
|
|
179
|
+
null
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function isConfigBackedBuildType(
|
|
184
|
+
value: string,
|
|
185
|
+
): value is ConfigBackedBuildType {
|
|
186
|
+
return (CONFIG_BACKED_BUILD_TYPES as readonly string[]).includes(value);
|
|
187
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The compute config contract and its tooling: types, validation, discovery,
|
|
3
|
+
* loading, and serialization for `prisma.compute.ts`.
|
|
4
|
+
*
|
|
5
|
+
* Consumers (CLI, build-runner, scaffolding) share this module so every part
|
|
6
|
+
* of the platform reads the same deploy graph. Consumer-specific concerns —
|
|
7
|
+
* project/branch resolution, prompts, flag precedence — stay with consumers.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
ASTRO_CONFIG_FILENAMES,
|
|
12
|
+
CONFIG_BACKED_BUILD_TYPES,
|
|
13
|
+
type ConfigBackedBuildType,
|
|
14
|
+
ENTRYPOINT_BUILD_TYPES,
|
|
15
|
+
FRAMEWORK_KEYS,
|
|
16
|
+
FRAMEWORKS,
|
|
17
|
+
type FrameworkBuildType,
|
|
18
|
+
type FrameworkDescriptor,
|
|
19
|
+
frameworkByKey,
|
|
20
|
+
frameworkFromAlias,
|
|
21
|
+
isConfigBackedBuildType,
|
|
22
|
+
LOCAL_DEV_BUILD_TYPES,
|
|
23
|
+
NEXT_CONFIG_FILENAMES,
|
|
24
|
+
NUXT_CONFIG_FILENAMES,
|
|
25
|
+
} from "./frameworks.ts";
|
|
26
|
+
export {
|
|
27
|
+
COMPUTE_CONFIG_FILENAME,
|
|
28
|
+
COMPUTE_CONFIG_FILENAMES,
|
|
29
|
+
ComputeConfigAmbiguousError,
|
|
30
|
+
type ComputeConfigError,
|
|
31
|
+
ComputeConfigLoadError,
|
|
32
|
+
findComputeConfigCandidates,
|
|
33
|
+
findComputeConfigDir,
|
|
34
|
+
loadComputeConfig,
|
|
35
|
+
} from "./load.ts";
|
|
36
|
+
export {
|
|
37
|
+
ComputeConfigInvalidError,
|
|
38
|
+
type ComputeConfigTargetError,
|
|
39
|
+
ComputeConfigTargetRequiredError,
|
|
40
|
+
ComputeConfigTargetUnknownError,
|
|
41
|
+
type ComputeDeployTarget,
|
|
42
|
+
type ComputeDeployTargetBuild,
|
|
43
|
+
computeTargetAppDir,
|
|
44
|
+
inferComputeTargetFromCwd,
|
|
45
|
+
type LoadedComputeConfig,
|
|
46
|
+
normalizeComputeConfig,
|
|
47
|
+
selectComputeDeployTarget,
|
|
48
|
+
} from "./normalize.ts";
|
|
49
|
+
export { serializeComputeConfig } from "./serialize.ts";
|
|
50
|
+
export { resolveSourceRoot, sourceRootLineage } from "./source-root.ts";
|
|
51
|
+
export {
|
|
52
|
+
COMPUTE_FRAMEWORKS,
|
|
53
|
+
type ComputeAppConfig,
|
|
54
|
+
type ComputeBuildConfig,
|
|
55
|
+
type ComputeConfig,
|
|
56
|
+
type ComputeEnvConfig,
|
|
57
|
+
type ComputeFramework,
|
|
58
|
+
defineComputeConfig,
|
|
59
|
+
} from "./types.ts";
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { access } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
import { Result, TaggedError } from "better-result";
|
|
7
|
+
import { createJiti } from "jiti";
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
type ComputeConfigInvalidError,
|
|
11
|
+
type LoadedComputeConfig,
|
|
12
|
+
normalizeComputeConfig,
|
|
13
|
+
} from "./normalize.ts";
|
|
14
|
+
import { sourceRootLineage } from "./source-root.ts";
|
|
15
|
+
|
|
16
|
+
export const COMPUTE_CONFIG_FILENAME = "prisma.compute.ts";
|
|
17
|
+
|
|
18
|
+
// Highest priority first. TypeScript is the canonical format; the rest exist
|
|
19
|
+
// so plain JavaScript projects are not forced into TypeScript.
|
|
20
|
+
export const COMPUTE_CONFIG_FILENAMES = [
|
|
21
|
+
"prisma.compute.ts",
|
|
22
|
+
"prisma.compute.mts",
|
|
23
|
+
"prisma.compute.js",
|
|
24
|
+
"prisma.compute.mjs",
|
|
25
|
+
"prisma.compute.cjs",
|
|
26
|
+
] as const;
|
|
27
|
+
|
|
28
|
+
// Config files import the typed helper through this specifier; it aliases
|
|
29
|
+
// to this module so configs load without a local install.
|
|
30
|
+
const CONFIG_MODULE_SPECIFIERS = ["@prisma/compute-sdk/config"] as const;
|
|
31
|
+
|
|
32
|
+
export class ComputeConfigAmbiguousError extends TaggedError(
|
|
33
|
+
"ComputeConfigAmbiguousError",
|
|
34
|
+
)<{
|
|
35
|
+
message: string;
|
|
36
|
+
configPaths: string[];
|
|
37
|
+
}>() {
|
|
38
|
+
constructor(configPaths: string[]) {
|
|
39
|
+
super({
|
|
40
|
+
message: `Multiple compute config files exist: ${configPaths.map((configPath) => path.basename(configPath)).join(", ")}. Keep exactly one.`,
|
|
41
|
+
configPaths,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export class ComputeConfigLoadError extends TaggedError(
|
|
47
|
+
"ComputeConfigLoadError",
|
|
48
|
+
)<{
|
|
49
|
+
message: string;
|
|
50
|
+
cause: unknown;
|
|
51
|
+
configPath: string;
|
|
52
|
+
}>() {
|
|
53
|
+
constructor(configPath: string, cause: unknown) {
|
|
54
|
+
super({
|
|
55
|
+
message: `Could not load ${path.basename(configPath)}: ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
56
|
+
cause,
|
|
57
|
+
configPath,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type ComputeConfigError =
|
|
63
|
+
| ComputeConfigAmbiguousError
|
|
64
|
+
| ComputeConfigLoadError
|
|
65
|
+
| ComputeConfigInvalidError;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Compute config files present in one directory, in filename priority order.
|
|
69
|
+
*/
|
|
70
|
+
export async function findComputeConfigCandidates(
|
|
71
|
+
directory: string,
|
|
72
|
+
signal?: AbortSignal,
|
|
73
|
+
): Promise<string[]> {
|
|
74
|
+
const candidates: string[] = [];
|
|
75
|
+
for (const filename of COMPUTE_CONFIG_FILENAMES) {
|
|
76
|
+
const configPath = path.join(directory, filename);
|
|
77
|
+
signal?.throwIfAborted();
|
|
78
|
+
try {
|
|
79
|
+
await access(configPath);
|
|
80
|
+
candidates.push(configPath);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
if (signal?.aborted) throw error;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
signal?.throwIfAborted();
|
|
86
|
+
|
|
87
|
+
return candidates;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Locates the nearest directory holding a compute config file, searching from
|
|
92
|
+
* `cwd` up to the source root. This is location-only discovery — the config
|
|
93
|
+
* is not loaded or validated — so it is safe to run in hot paths.
|
|
94
|
+
* Returns null when no config exists inside the repository boundary.
|
|
95
|
+
*/
|
|
96
|
+
export async function findComputeConfigDir(
|
|
97
|
+
cwd: string,
|
|
98
|
+
signal?: AbortSignal,
|
|
99
|
+
): Promise<string | null> {
|
|
100
|
+
for (const directory of await sourceRootLineage(cwd, signal)) {
|
|
101
|
+
const candidates = await findComputeConfigCandidates(directory, signal);
|
|
102
|
+
if (candidates.length > 0) {
|
|
103
|
+
return directory;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Loads the nearest compute config, searching from `cwd` up to the source
|
|
112
|
+
* root (repository or workspace boundary). Without such a boundary only
|
|
113
|
+
* `cwd` itself is checked, so discovery never escapes into unrelated
|
|
114
|
+
* directories.
|
|
115
|
+
*/
|
|
116
|
+
export async function loadComputeConfig(
|
|
117
|
+
cwd: string,
|
|
118
|
+
options?: {
|
|
119
|
+
signal?: AbortSignal;
|
|
120
|
+
/**
|
|
121
|
+
* Module path the config-helper import specifiers alias to. Defaults to
|
|
122
|
+
* this SDK's own config module; pass a path when the consumer ships its
|
|
123
|
+
* own copy of the contract (e.g. a bundled CLI).
|
|
124
|
+
*/
|
|
125
|
+
configModuleAlias?: string;
|
|
126
|
+
},
|
|
127
|
+
): Promise<Result<LoadedComputeConfig | null, ComputeConfigError>> {
|
|
128
|
+
const signal = options?.signal;
|
|
129
|
+
for (const directory of await sourceRootLineage(cwd, signal)) {
|
|
130
|
+
const candidates = await findComputeConfigCandidates(directory, signal);
|
|
131
|
+
if (candidates.length === 0) {
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (candidates.length > 1) {
|
|
135
|
+
return Result.err(new ComputeConfigAmbiguousError(candidates));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const configPath = candidates[0] as string;
|
|
139
|
+
signal?.throwIfAborted();
|
|
140
|
+
const imported = await importComputeConfigModule(
|
|
141
|
+
configPath,
|
|
142
|
+
options?.configModuleAlias,
|
|
143
|
+
);
|
|
144
|
+
if (imported.isErr()) {
|
|
145
|
+
return Result.err(imported.error);
|
|
146
|
+
}
|
|
147
|
+
return normalizeComputeConfig(imported.value, configPath);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return Result.ok(null);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function importComputeConfigModule(
|
|
154
|
+
configPath: string,
|
|
155
|
+
configModuleAlias: string | undefined,
|
|
156
|
+
): Promise<Result<unknown, ComputeConfigLoadError>> {
|
|
157
|
+
return Result.tryPromise({
|
|
158
|
+
try: async () => {
|
|
159
|
+
const aliasTarget = configModuleAlias ?? resolveOwnConfigModulePath();
|
|
160
|
+
const jiti = createJiti(import.meta.url, {
|
|
161
|
+
// Keep Node's standard interop so `.default` exists only for a real
|
|
162
|
+
// default export (ESM) or module.exports (CJS).
|
|
163
|
+
interopDefault: false,
|
|
164
|
+
// Re-import fresh so repeated loads in one process observe file edits.
|
|
165
|
+
moduleCache: false,
|
|
166
|
+
...(aliasTarget
|
|
167
|
+
? {
|
|
168
|
+
alias: Object.fromEntries(
|
|
169
|
+
CONFIG_MODULE_SPECIFIERS.map((specifier) => [
|
|
170
|
+
specifier,
|
|
171
|
+
aliasTarget,
|
|
172
|
+
]),
|
|
173
|
+
),
|
|
174
|
+
}
|
|
175
|
+
: {}),
|
|
176
|
+
});
|
|
177
|
+
const moduleNamespace =
|
|
178
|
+
await jiti.import<Record<string, unknown>>(configPath);
|
|
179
|
+
// Require an explicit default export instead of jiti's namespace
|
|
180
|
+
// interop so named-export configs fail with a clear message.
|
|
181
|
+
return moduleNamespace?.default;
|
|
182
|
+
},
|
|
183
|
+
catch: (cause) => new ComputeConfigLoadError(configPath, cause),
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function resolveOwnConfigModulePath(): string | null {
|
|
188
|
+
// dist layout: dist/config/load.js -> dist/config/index.js
|
|
189
|
+
// src layout (bun/tests): src/config/load.ts -> src/config/index.ts
|
|
190
|
+
for (const candidate of ["./index.js", "./index.ts"]) {
|
|
191
|
+
const candidatePath = fileURLToPath(new URL(candidate, import.meta.url));
|
|
192
|
+
if (existsSync(candidatePath)) {
|
|
193
|
+
return candidatePath;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return null;
|
|
198
|
+
}
|