gencow 0.1.261 → 0.1.263
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/lib/app-response-error.mjs +8 -2
- package/lib/deploy-app-creation.mjs +2 -0
- package/lib/deploy-app-target.mjs +33 -0
- package/lib/deploy-package-runtime.mjs +16 -32
- package/lib/deploy-prod-target.mjs +2 -0
- package/lib/deploy-project-config-load.mjs +32 -0
- package/lib/deploy-runtime.mjs +3 -0
- package/lib/deploy-static-fullstack-runtime.mjs +8 -1
- package/lib/env-command.mjs +101 -19
- package/package.json +4 -4
- package/runtime/server.mjs +4 -7
- package/runtime/tooling.mjs +102 -50
- package/scripts/codegen-named-import-check.ts +8 -2
- package/scripts/tooling-codegen-runtime.ts +132 -55
package/runtime/tooling.mjs
CHANGED
|
@@ -6905,6 +6905,9 @@ function missingNamedImportsIn(ctx, file2) {
|
|
|
6905
6905
|
function isProjectSource(file2, projectRoot) {
|
|
6906
6906
|
return file2.startsWith(`${projectRoot}${sep2}`) && !file2.split(sep2).includes("node_modules") && SCRIPT_FILE.test(file2);
|
|
6907
6907
|
}
|
|
6908
|
+
function hasProjectTypeScript(projectRootInput) {
|
|
6909
|
+
return loadProjectTypeScript(resolve10(projectRootInput)) !== null;
|
|
6910
|
+
}
|
|
6908
6911
|
function findMissingNamedImports(inputFiles, projectRootInput) {
|
|
6909
6912
|
const projectRoot = resolve10(projectRootInput);
|
|
6910
6913
|
const ts = loadProjectTypeScript(projectRoot);
|
|
@@ -7014,34 +7017,39 @@ async function loadEsbuildModule() {
|
|
|
7014
7017
|
}
|
|
7015
7018
|
return { build: mod.build };
|
|
7016
7019
|
}
|
|
7020
|
+
function esbuildEntryOptions(entryPath) {
|
|
7021
|
+
return {
|
|
7022
|
+
entryPoints: [entryPath],
|
|
7023
|
+
bundle: true,
|
|
7024
|
+
format: "esm",
|
|
7025
|
+
platform: "node",
|
|
7026
|
+
target: "node20",
|
|
7027
|
+
sourcemap: false,
|
|
7028
|
+
logLevel: "silent",
|
|
7029
|
+
packages: "external",
|
|
7030
|
+
external: [...nodeBuiltinExternals, "bun", "bun:*"],
|
|
7031
|
+
metafile: true,
|
|
7032
|
+
banner: {
|
|
7033
|
+
js: [
|
|
7034
|
+
'import { createRequire as __gencowCreateRequire } from "node:module";',
|
|
7035
|
+
"const require = __gencowCreateRequire(import.meta.url);"
|
|
7036
|
+
].join("\n")
|
|
7037
|
+
}
|
|
7038
|
+
};
|
|
7039
|
+
}
|
|
7040
|
+
function bundledInputFiles(result) {
|
|
7041
|
+
const inputs = result?.metafile?.inputs;
|
|
7042
|
+
return Object.keys(inputs ?? {}).map((file2) => resolve11(file2));
|
|
7043
|
+
}
|
|
7017
7044
|
async function transpileTypescriptForNodeDefault(entryPath, context) {
|
|
7018
7045
|
const workDir = join7(resolve11(context.projectRoot), ".gencow");
|
|
7019
7046
|
await mkdir(workDir, { recursive: true });
|
|
7020
7047
|
const tempDir = await mkdtemp(join7(workDir, "codegen-extract-"));
|
|
7021
7048
|
const outFile = join7(tempDir, "index.mjs");
|
|
7022
|
-
let inputFiles
|
|
7049
|
+
let inputFiles;
|
|
7023
7050
|
try {
|
|
7024
7051
|
const { build } = await loadEsbuildModule();
|
|
7025
|
-
|
|
7026
|
-
entryPoints: [entryPath],
|
|
7027
|
-
outfile: outFile,
|
|
7028
|
-
bundle: true,
|
|
7029
|
-
format: "esm",
|
|
7030
|
-
platform: "node",
|
|
7031
|
-
target: "node20",
|
|
7032
|
-
sourcemap: false,
|
|
7033
|
-
logLevel: "silent",
|
|
7034
|
-
packages: "external",
|
|
7035
|
-
external: [...nodeBuiltinExternals, "bun", "bun:*"],
|
|
7036
|
-
metafile: true,
|
|
7037
|
-
banner: {
|
|
7038
|
-
js: [
|
|
7039
|
-
'import { createRequire as __gencowCreateRequire } from "node:module";',
|
|
7040
|
-
"const require = __gencowCreateRequire(import.meta.url);"
|
|
7041
|
-
].join("\n")
|
|
7042
|
-
}
|
|
7043
|
-
});
|
|
7044
|
-
inputFiles = Object.keys(result?.metafile?.inputs ?? {}).map((file2) => resolve11(file2));
|
|
7052
|
+
inputFiles = bundledInputFiles(await build({ ...esbuildEntryOptions(entryPath), outfile: outFile }));
|
|
7045
7053
|
} catch (error62) {
|
|
7046
7054
|
const details = error62 instanceof Error ? error62.message : String(error62);
|
|
7047
7055
|
throw new Error(
|
|
@@ -7053,27 +7061,55 @@ async function transpileTypescriptForNodeDefault(entryPath, context) {
|
|
|
7053
7061
|
].join("\n")
|
|
7054
7062
|
);
|
|
7055
7063
|
}
|
|
7056
|
-
const missingImports = formatMissingNamedImports(
|
|
7057
|
-
findMissingNamedImports(inputFiles, context.projectRoot),
|
|
7058
|
-
context.projectRoot
|
|
7059
|
-
);
|
|
7060
|
-
if (missingImports.length > 0) {
|
|
7061
|
-
throw new Error(
|
|
7062
|
-
[
|
|
7063
|
-
"Failed to transpile TypeScript entry for codegen extraction.",
|
|
7064
|
-
`Resolved entry: ${entryPath}`,
|
|
7065
|
-
`Transpile error: Build failed with ${missingImports.length} error${missingImports.length === 1 ? "" : "s"}:`,
|
|
7066
|
-
...missingImports
|
|
7067
|
-
].join("\n")
|
|
7068
|
-
);
|
|
7069
|
-
}
|
|
7070
7064
|
return {
|
|
7071
7065
|
modulePath: outFile,
|
|
7066
|
+
inputFiles,
|
|
7072
7067
|
cleanup: async () => {
|
|
7073
7068
|
await rm(tempDir, { recursive: true, force: true });
|
|
7074
7069
|
}
|
|
7075
7070
|
};
|
|
7076
7071
|
}
|
|
7072
|
+
var MISSING_EXPORT_DIAGNOSTIC = /No matching export in "/u;
|
|
7073
|
+
var NAMED_IMPORT_CHECK_SKIPPED_MESSAGE = "Warning: codegen skipped the named-import check because this project has no typescript package. Install typescript in the project (for example: npm install -D typescript) and rerun codegen.";
|
|
7074
|
+
function defaultWarn(message) {
|
|
7075
|
+
process.stderr.write(`${message}
|
|
7076
|
+
`);
|
|
7077
|
+
}
|
|
7078
|
+
function namedImportLoadFailure(appEntryAbs, runtime, transpileErrorLines) {
|
|
7079
|
+
return new Error(
|
|
7080
|
+
[
|
|
7081
|
+
"Failed to load app module for codegen extraction.",
|
|
7082
|
+
`Resolved entry: ${appEntryAbs}`,
|
|
7083
|
+
`Runtime: ${runtime}`,
|
|
7084
|
+
"Expected export: default defineApi({ procedures: { ... } }) or module object with procedures.",
|
|
7085
|
+
...transpileErrorLines
|
|
7086
|
+
].join("\n")
|
|
7087
|
+
);
|
|
7088
|
+
}
|
|
7089
|
+
async function assertNamedImportsResolve(input2) {
|
|
7090
|
+
if (!hasProjectTypeScript(input2.projectRoot)) {
|
|
7091
|
+
input2.warn(NAMED_IMPORT_CHECK_SKIPPED_MESSAGE);
|
|
7092
|
+
return;
|
|
7093
|
+
}
|
|
7094
|
+
let inputFiles = input2.inputFiles;
|
|
7095
|
+
if (!inputFiles) {
|
|
7096
|
+
try {
|
|
7097
|
+
const { build } = await loadEsbuildModule();
|
|
7098
|
+
inputFiles = bundledInputFiles(await build({ ...esbuildEntryOptions(input2.appEntryAbs), write: false }));
|
|
7099
|
+
} catch (error62) {
|
|
7100
|
+
const details = error62 instanceof Error ? error62.message : String(error62);
|
|
7101
|
+
if (input2.runtime === "bun" && !MISSING_EXPORT_DIAGNOSTIC.test(details)) return;
|
|
7102
|
+
throw namedImportLoadFailure(input2.appEntryAbs, input2.runtime, [`Transpile error: ${details}`]);
|
|
7103
|
+
}
|
|
7104
|
+
}
|
|
7105
|
+
const missing = findMissingNamedImports(inputFiles, input2.projectRoot);
|
|
7106
|
+
if (missing.length > 0) {
|
|
7107
|
+
throw namedImportLoadFailure(input2.appEntryAbs, input2.runtime, [
|
|
7108
|
+
`Transpile error: Build failed with ${missing.length} error${missing.length === 1 ? "" : "s"}:`,
|
|
7109
|
+
...formatMissingNamedImports(missing, input2.projectRoot)
|
|
7110
|
+
]);
|
|
7111
|
+
}
|
|
7112
|
+
}
|
|
7077
7113
|
function createCliRegistryExtractorDeps(options = {}) {
|
|
7078
7114
|
let collectors = null;
|
|
7079
7115
|
return {
|
|
@@ -7085,23 +7121,39 @@ function createCliRegistryExtractorDeps(options = {}) {
|
|
|
7085
7121
|
const legacyBeforeImport = coreModule.captureLegacyRealtimeChannels?.() ?? [];
|
|
7086
7122
|
let moduleImportPath = appEntryAbs;
|
|
7087
7123
|
let cleanup;
|
|
7088
|
-
if (
|
|
7124
|
+
if (appEntryAbs.endsWith(".ts")) {
|
|
7125
|
+
let inputFiles;
|
|
7126
|
+
if (runtime !== "bun") {
|
|
7127
|
+
try {
|
|
7128
|
+
const transpile = options.transpileTypescriptForNode ?? transpileTypescriptForNodeDefault;
|
|
7129
|
+
const transpiled = await transpile(appEntryAbs, { projectRoot: input2.projectRoot });
|
|
7130
|
+
moduleImportPath = transpiled.modulePath;
|
|
7131
|
+
cleanup = transpiled.cleanup;
|
|
7132
|
+
inputFiles = transpiled.inputFiles;
|
|
7133
|
+
} catch (error62) {
|
|
7134
|
+
const details = error62 instanceof Error ? error62.message : String(error62);
|
|
7135
|
+
throw new Error(
|
|
7136
|
+
[
|
|
7137
|
+
"Failed to load app module for codegen extraction.",
|
|
7138
|
+
`Resolved entry: ${appEntryAbs}`,
|
|
7139
|
+
`Runtime: ${runtime}`,
|
|
7140
|
+
"Node runtime requires a TypeScript loader adapter for in-process extraction.",
|
|
7141
|
+
`Transpile error: ${details}`
|
|
7142
|
+
].join("\n")
|
|
7143
|
+
);
|
|
7144
|
+
}
|
|
7145
|
+
}
|
|
7089
7146
|
try {
|
|
7090
|
-
|
|
7091
|
-
|
|
7092
|
-
|
|
7093
|
-
|
|
7147
|
+
await assertNamedImportsResolve({
|
|
7148
|
+
appEntryAbs,
|
|
7149
|
+
runtime,
|
|
7150
|
+
projectRoot: input2.projectRoot,
|
|
7151
|
+
inputFiles,
|
|
7152
|
+
warn: options.warn ?? defaultWarn
|
|
7153
|
+
});
|
|
7094
7154
|
} catch (error62) {
|
|
7095
|
-
|
|
7096
|
-
throw
|
|
7097
|
-
[
|
|
7098
|
-
"Failed to load app module for codegen extraction.",
|
|
7099
|
-
`Resolved entry: ${appEntryAbs}`,
|
|
7100
|
-
`Runtime: ${runtime}`,
|
|
7101
|
-
"Node runtime requires a TypeScript loader adapter for in-process extraction.",
|
|
7102
|
-
`Transpile error: ${details}`
|
|
7103
|
-
].join("\n")
|
|
7104
|
-
);
|
|
7155
|
+
await cleanup?.();
|
|
7156
|
+
throw error62;
|
|
7105
7157
|
}
|
|
7106
7158
|
}
|
|
7107
7159
|
let appModule;
|
|
@@ -3,8 +3,9 @@ import { join, relative, resolve, sep } from "node:path";
|
|
|
3
3
|
|
|
4
4
|
// esbuild drops an unused import of a missing name without a diagnostic, and it only
|
|
5
5
|
// warns for namespace member access. Codegen would then load a backend that names an
|
|
6
|
-
// export its module does not have. This check runs after
|
|
7
|
-
// project's own sources, and only for relative
|
|
6
|
+
// export its module does not have. This check runs after esbuild bundles the entry and before
|
|
7
|
+
// the module is imported, on every runtime, over the project's own sources, and only for relative
|
|
8
|
+
// named imports and re-exports. It reads
|
|
8
9
|
// the ASTs with the user project's `typescript` (the CLI does not depend on it), so the
|
|
9
10
|
// AST nodes are not statically typed here.
|
|
10
11
|
|
|
@@ -182,6 +183,11 @@ function isProjectSource(file: string, projectRoot: string): boolean {
|
|
|
182
183
|
);
|
|
183
184
|
}
|
|
184
185
|
|
|
186
|
+
// Whether the check can run for this project. Callers warn when it cannot, so a skipped check is visible.
|
|
187
|
+
export function hasProjectTypeScript(projectRootInput: string): boolean {
|
|
188
|
+
return loadProjectTypeScript(resolve(projectRootInput)) !== null;
|
|
189
|
+
}
|
|
190
|
+
|
|
185
191
|
// `inputFiles` are the files esbuild bundled (absolute paths). Returns every relative named
|
|
186
192
|
// import whose target module does not export the name. Any internal failure skips the check.
|
|
187
193
|
export function findMissingNamedImports(
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import {
|
|
14
14
|
findMissingNamedImports,
|
|
15
15
|
formatMissingNamedImports,
|
|
16
|
+
hasProjectTypeScript,
|
|
16
17
|
} from "./codegen-named-import-check.ts";
|
|
17
18
|
import {
|
|
18
19
|
collectCrudCodegenMeta,
|
|
@@ -44,7 +45,13 @@ type CliRegistryRuntimeOptions = {
|
|
|
44
45
|
transpileTypescriptForNode?: (
|
|
45
46
|
entryPath: string,
|
|
46
47
|
context: { projectRoot: string },
|
|
47
|
-
) => Promise<{
|
|
48
|
+
) => Promise<{
|
|
49
|
+
modulePath: string;
|
|
50
|
+
inputFiles?: string[];
|
|
51
|
+
cleanup?: (() => Promise<void>) | (() => void);
|
|
52
|
+
}>;
|
|
53
|
+
// Receives the one-line notice when the named-import check is skipped. Defaults to stderr.
|
|
54
|
+
warn?: (message: string) => void;
|
|
48
55
|
coreModule?: CoreModuleShape;
|
|
49
56
|
collectors?: Pick<RegistryRuntimeCollectors, "collectCrudCodegenMeta" | "collectProcedureRouteMaps">;
|
|
50
57
|
};
|
|
@@ -105,38 +112,46 @@ async function loadEsbuildModule(): Promise<{ build(options: Record<string, unkn
|
|
|
105
112
|
return { build: mod.build };
|
|
106
113
|
}
|
|
107
114
|
|
|
115
|
+
// Bundle options shared by the node transpile and the import check, so both see the same module graph.
|
|
116
|
+
function esbuildEntryOptions(entryPath: string): Record<string, unknown> {
|
|
117
|
+
return {
|
|
118
|
+
entryPoints: [entryPath],
|
|
119
|
+
bundle: true,
|
|
120
|
+
format: "esm",
|
|
121
|
+
platform: "node",
|
|
122
|
+
target: "node20",
|
|
123
|
+
sourcemap: false,
|
|
124
|
+
logLevel: "silent",
|
|
125
|
+
packages: "external",
|
|
126
|
+
external: [...nodeBuiltinExternals, "bun", "bun:*"],
|
|
127
|
+
metafile: true,
|
|
128
|
+
banner: {
|
|
129
|
+
js: [
|
|
130
|
+
'import { createRequire as __gencowCreateRequire } from "node:module";',
|
|
131
|
+
"const require = __gencowCreateRequire(import.meta.url);",
|
|
132
|
+
].join("\n"),
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// esbuild reports inputs relative to the process working directory (its default).
|
|
138
|
+
function bundledInputFiles(result: unknown): string[] {
|
|
139
|
+
const inputs = (result as { metafile?: { inputs?: Record<string, unknown> } } | undefined)?.metafile?.inputs;
|
|
140
|
+
return Object.keys(inputs ?? {}).map((file) => resolve(file));
|
|
141
|
+
}
|
|
142
|
+
|
|
108
143
|
async function transpileTypescriptForNodeDefault(
|
|
109
144
|
entryPath: string,
|
|
110
145
|
context: { projectRoot: string },
|
|
111
|
-
): Promise<{ modulePath: string; cleanup?: () => Promise<void> }> {
|
|
146
|
+
): Promise<{ modulePath: string; inputFiles: string[]; cleanup?: () => Promise<void> }> {
|
|
112
147
|
const workDir = join(resolve(context.projectRoot), ".gencow");
|
|
113
148
|
await mkdir(workDir, { recursive: true });
|
|
114
149
|
const tempDir = await mkdtemp(join(workDir, "codegen-extract-"));
|
|
115
150
|
const outFile = join(tempDir, "index.mjs");
|
|
116
|
-
let inputFiles: string[]
|
|
151
|
+
let inputFiles: string[];
|
|
117
152
|
try {
|
|
118
153
|
const { build } = await loadEsbuildModule();
|
|
119
|
-
|
|
120
|
-
entryPoints: [entryPath],
|
|
121
|
-
outfile: outFile,
|
|
122
|
-
bundle: true,
|
|
123
|
-
format: "esm",
|
|
124
|
-
platform: "node",
|
|
125
|
-
target: "node20",
|
|
126
|
-
sourcemap: false,
|
|
127
|
-
logLevel: "silent",
|
|
128
|
-
packages: "external",
|
|
129
|
-
external: [...nodeBuiltinExternals, "bun", "bun:*"],
|
|
130
|
-
metafile: true,
|
|
131
|
-
banner: {
|
|
132
|
-
js: [
|
|
133
|
-
'import { createRequire as __gencowCreateRequire } from "node:module";',
|
|
134
|
-
"const require = __gencowCreateRequire(import.meta.url);",
|
|
135
|
-
].join("\n"),
|
|
136
|
-
},
|
|
137
|
-
})) as { metafile?: { inputs?: Record<string, unknown> } } | undefined;
|
|
138
|
-
// esbuild reports inputs relative to the process working directory (its default).
|
|
139
|
-
inputFiles = Object.keys(result?.metafile?.inputs ?? {}).map((file) => resolve(file));
|
|
154
|
+
inputFiles = bundledInputFiles(await build({ ...esbuildEntryOptions(entryPath), outfile: outFile }));
|
|
140
155
|
} catch (error) {
|
|
141
156
|
const details = error instanceof Error ? error.message : String(error);
|
|
142
157
|
throw new Error(
|
|
@@ -148,30 +163,76 @@ async function transpileTypescriptForNodeDefault(
|
|
|
148
163
|
].join("\n"),
|
|
149
164
|
);
|
|
150
165
|
}
|
|
151
|
-
// esbuild accepts an unused or type-position import of a missing name; reject it here
|
|
152
|
-
// before codegen loads the module, in the same diagnostic shape as an esbuild error.
|
|
153
|
-
const missingImports = formatMissingNamedImports(
|
|
154
|
-
findMissingNamedImports(inputFiles, context.projectRoot),
|
|
155
|
-
context.projectRoot,
|
|
156
|
-
);
|
|
157
|
-
if (missingImports.length > 0) {
|
|
158
|
-
throw new Error(
|
|
159
|
-
[
|
|
160
|
-
"Failed to transpile TypeScript entry for codegen extraction.",
|
|
161
|
-
`Resolved entry: ${entryPath}`,
|
|
162
|
-
`Transpile error: Build failed with ${missingImports.length} error${missingImports.length === 1 ? "" : "s"}:`,
|
|
163
|
-
...missingImports,
|
|
164
|
-
].join("\n"),
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
166
|
return {
|
|
168
167
|
modulePath: outFile,
|
|
168
|
+
inputFiles,
|
|
169
169
|
cleanup: async () => {
|
|
170
170
|
await rm(tempDir, { recursive: true, force: true });
|
|
171
171
|
},
|
|
172
172
|
};
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
+
const MISSING_EXPORT_DIAGNOSTIC = /No matching export in "/u;
|
|
176
|
+
|
|
177
|
+
const NAMED_IMPORT_CHECK_SKIPPED_MESSAGE =
|
|
178
|
+
"Warning: codegen skipped the named-import check because this project has no typescript package. " +
|
|
179
|
+
"Install typescript in the project (for example: npm install -D typescript) and rerun codegen.";
|
|
180
|
+
|
|
181
|
+
function defaultWarn(message: string): void {
|
|
182
|
+
process.stderr.write(`${message}\n`);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function namedImportLoadFailure(appEntryAbs: string, runtime: string, transpileErrorLines: string[]): Error {
|
|
186
|
+
return new Error(
|
|
187
|
+
[
|
|
188
|
+
"Failed to load app module for codegen extraction.",
|
|
189
|
+
`Resolved entry: ${appEntryAbs}`,
|
|
190
|
+
`Runtime: ${runtime}`,
|
|
191
|
+
"Expected export: default defineApi({ procedures: { ... } }) or module object with procedures.",
|
|
192
|
+
...transpileErrorLines,
|
|
193
|
+
].join("\n"),
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Runs before the app module is imported, on every runtime. esbuild accepts an unused or
|
|
198
|
+
// type-position import of a missing name, and Bun rejects a used one without a location, so this
|
|
199
|
+
// check decides first. The bundle inputs come from the node transpile when it ran, otherwise from
|
|
200
|
+
// an in-memory esbuild bundle with the same options.
|
|
201
|
+
async function assertNamedImportsResolve(input: {
|
|
202
|
+
appEntryAbs: string;
|
|
203
|
+
runtime: string;
|
|
204
|
+
projectRoot: string;
|
|
205
|
+
inputFiles?: string[];
|
|
206
|
+
warn: (message: string) => void;
|
|
207
|
+
}): Promise<void> {
|
|
208
|
+
if (!hasProjectTypeScript(input.projectRoot)) {
|
|
209
|
+
input.warn(NAMED_IMPORT_CHECK_SKIPPED_MESSAGE);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
let inputFiles = input.inputFiles;
|
|
213
|
+
if (!inputFiles) {
|
|
214
|
+
try {
|
|
215
|
+
const { build } = await loadEsbuildModule();
|
|
216
|
+
inputFiles = bundledInputFiles(await build({ ...esbuildEntryOptions(input.appEntryAbs), write: false }));
|
|
217
|
+
} catch (error) {
|
|
218
|
+
const details = error instanceof Error ? error.message : String(error);
|
|
219
|
+
// Bun can run inputs esbuild rejects (for example `with { type: "text" }`). On bun those failures
|
|
220
|
+
// skip the check and bun's loader reports any real error. A missing import in such a backend is
|
|
221
|
+
// not caught here. A missing-export diagnostic is still reported, since it is this check's domain.
|
|
222
|
+
// On node the transpile already failed above, so this branch is bun-only in practice.
|
|
223
|
+
if (input.runtime === "bun" && !MISSING_EXPORT_DIAGNOSTIC.test(details)) return;
|
|
224
|
+
throw namedImportLoadFailure(input.appEntryAbs, input.runtime, [`Transpile error: ${details}`]);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
const missing = findMissingNamedImports(inputFiles, input.projectRoot);
|
|
228
|
+
if (missing.length > 0) {
|
|
229
|
+
throw namedImportLoadFailure(input.appEntryAbs, input.runtime, [
|
|
230
|
+
`Transpile error: Build failed with ${missing.length} error${missing.length === 1 ? "" : "s"}:`,
|
|
231
|
+
...formatMissingNamedImports(missing, input.projectRoot),
|
|
232
|
+
]);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
175
236
|
function createCliRegistryExtractorDeps(options: CliRegistryRuntimeOptions = {}): RegistryExtractorDeps {
|
|
176
237
|
let collectors: RegistryRuntimeCollectors | null = null;
|
|
177
238
|
return {
|
|
@@ -184,23 +245,39 @@ function createCliRegistryExtractorDeps(options: CliRegistryRuntimeOptions = {})
|
|
|
184
245
|
let moduleImportPath = appEntryAbs;
|
|
185
246
|
let cleanup: (() => Promise<void>) | (() => void) | undefined;
|
|
186
247
|
|
|
187
|
-
if (
|
|
248
|
+
if (appEntryAbs.endsWith(".ts")) {
|
|
249
|
+
let inputFiles: string[] | undefined;
|
|
250
|
+
if (runtime !== "bun") {
|
|
251
|
+
try {
|
|
252
|
+
const transpile = options.transpileTypescriptForNode ?? transpileTypescriptForNodeDefault;
|
|
253
|
+
const transpiled = await transpile(appEntryAbs, { projectRoot: input.projectRoot });
|
|
254
|
+
moduleImportPath = transpiled.modulePath;
|
|
255
|
+
cleanup = transpiled.cleanup;
|
|
256
|
+
inputFiles = transpiled.inputFiles;
|
|
257
|
+
} catch (error) {
|
|
258
|
+
const details = error instanceof Error ? error.message : String(error);
|
|
259
|
+
throw new Error(
|
|
260
|
+
[
|
|
261
|
+
"Failed to load app module for codegen extraction.",
|
|
262
|
+
`Resolved entry: ${appEntryAbs}`,
|
|
263
|
+
`Runtime: ${runtime}`,
|
|
264
|
+
"Node runtime requires a TypeScript loader adapter for in-process extraction.",
|
|
265
|
+
`Transpile error: ${details}`,
|
|
266
|
+
].join("\n"),
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
188
270
|
try {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
271
|
+
await assertNamedImportsResolve({
|
|
272
|
+
appEntryAbs,
|
|
273
|
+
runtime,
|
|
274
|
+
projectRoot: input.projectRoot,
|
|
275
|
+
inputFiles,
|
|
276
|
+
warn: options.warn ?? defaultWarn,
|
|
277
|
+
});
|
|
193
278
|
} catch (error) {
|
|
194
|
-
|
|
195
|
-
throw
|
|
196
|
-
[
|
|
197
|
-
"Failed to load app module for codegen extraction.",
|
|
198
|
-
`Resolved entry: ${appEntryAbs}`,
|
|
199
|
-
`Runtime: ${runtime}`,
|
|
200
|
-
"Node runtime requires a TypeScript loader adapter for in-process extraction.",
|
|
201
|
-
`Transpile error: ${details}`,
|
|
202
|
-
].join("\n"),
|
|
203
|
-
);
|
|
279
|
+
await cleanup?.();
|
|
280
|
+
throw error;
|
|
204
281
|
}
|
|
205
282
|
}
|
|
206
283
|
|