@codemation/cli 0.0.4 → 0.0.7
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/README.md +20 -26
- package/dist/{CliBin-900C8Din.js → CliBin-Bx1lFBi5.js} +1125 -340
- package/dist/bin.js +1 -1
- package/dist/index.d.ts +669 -197
- package/dist/index.js +1 -1
- package/package.json +9 -6
- package/src/CliProgramFactory.ts +23 -8
- package/src/Program.ts +7 -3
- package/src/bootstrap/CodemationCliApplicationSession.ts +17 -19
- package/src/commands/DevCommand.ts +302 -158
- package/src/commands/ServeWebCommand.ts +26 -1
- package/src/commands/ServeWorkerCommand.ts +46 -30
- package/src/commands/devCommandLifecycle.types.ts +7 -9
- package/src/database/ConsumerDatabaseConnectionResolver.ts +55 -9
- package/src/database/DatabaseMigrationsApplyService.ts +2 -2
- package/src/dev/Builder.ts +3 -14
- package/src/dev/CliDevProxyServer.ts +447 -0
- package/src/dev/CliDevProxyServerFactory.ts +7 -0
- package/src/dev/DevApiRuntimeFactory.ts +44 -0
- package/src/dev/DevApiRuntimeHost.ts +130 -0
- package/src/dev/DevApiRuntimeServer.ts +107 -0
- package/src/dev/DevApiRuntimeTypes.ts +24 -0
- package/src/dev/DevAuthSettingsLoader.ts +9 -3
- package/src/dev/DevBootstrapSummaryFetcher.ts +1 -1
- package/src/dev/DevHttpProbe.ts +8 -4
- package/src/dev/DevNextHostEnvironmentBuilder.ts +65 -3
- package/src/dev/DevRebuildQueue.ts +54 -0
- package/src/dev/DevRebuildQueueFactory.ts +7 -0
- package/src/dev/DevSessionPortsResolver.ts +2 -2
- package/src/dev/DevSessionServices.ts +2 -4
- package/src/dev/DevSourceChangeClassifier.ts +59 -0
- package/src/dev/WatchRootsResolver.ts +6 -4
- package/src/runtime/NextHostConsumerServerCommandFactory.ts +11 -2
- package/src/runtime/TypeScriptRuntimeConfigurator.ts +7 -0
- package/src/user/CliDatabaseUrlDescriptor.ts +2 -2
- package/src/user/UserAdminCliBootstrap.ts +9 -21
- package/codemation-cli-0.0.3.tgz +0 -0
- package/src/dev/DevSourceRestartCoordinator.ts +0 -48
- package/src/dev/DevelopmentGatewayNotifier.ts +0 -35
- package/src/dev/RuntimeToolEntrypointResolver.ts +0 -47
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import process$1 from "node:process";
|
|
3
|
-
import { CodemationConsumerConfigLoader, CodemationPluginDiscovery, WorkflowDiscoveryPathSegmentsComputer, WorkflowModulePathFinder } from "@codemation/host/server";
|
|
4
|
-
import {
|
|
3
|
+
import { AppConfigLoader, CodemationConsumerConfigLoader, CodemationFrontendAuthSnapshotFactory, CodemationPluginDiscovery, FrontendAppConfigJsonCodec, WorkflowDiscoveryPathSegmentsComputer, WorkflowModulePathFinder } from "@codemation/host/server";
|
|
4
|
+
import { ApiPaths, AppContainerFactory, AppContainerLifecycle, ApplicationTokens, CodemationFrontendAuthSnapshotFactory as CodemationFrontendAuthSnapshotFactory$1, DatabaseMigrations, FrontendAppConfigJsonCodec as FrontendAppConfigJsonCodec$1, ListUserAccountsQuery, PrismaClient, UpsertLocalBootstrapUserCommand, WorkerRuntime } from "@codemation/host";
|
|
5
|
+
import { AppContainerFactory as AppContainerFactory$1, AppContainerLifecycle as AppContainerLifecycle$1, CodemationHonoApiApp, CodemationPluginListMerger, FrontendRuntime, ServerLoggerFactory, logLevelPolicyFactory } from "@codemation/host/next/server";
|
|
5
6
|
import { randomUUID } from "node:crypto";
|
|
6
7
|
import { access, copyFile, cp, mkdir, open, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
7
8
|
import path from "node:path";
|
|
8
9
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
9
10
|
import { spawn } from "node:child_process";
|
|
10
|
-
import { ApiPaths, ApplicationTokens, CodemationApplication, CodemationBootstrapRequest, ListUserAccountsQuery, PrismaClient, UpsertLocalBootstrapUserCommand } from "@codemation/host";
|
|
11
11
|
import { existsSync, readFileSync } from "node:fs";
|
|
12
12
|
import { config, parse } from "dotenv";
|
|
13
13
|
import { watch } from "chokidar";
|
|
14
14
|
import ts from "typescript";
|
|
15
|
-
import {
|
|
15
|
+
import { PrismaMigrationDeployer } from "@codemation/host/persistence";
|
|
16
16
|
import boxen from "boxen";
|
|
17
17
|
import chalk from "chalk";
|
|
18
18
|
import figlet from "figlet";
|
|
19
|
+
import { createServer } from "node:http";
|
|
20
|
+
import httpProxy from "http-proxy";
|
|
21
|
+
import { WebSocket, WebSocketServer } from "ws";
|
|
22
|
+
import { serve } from "@hono/node-server";
|
|
23
|
+
import { Hono } from "hono";
|
|
19
24
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
20
|
-
import { createServer } from "node:net";
|
|
25
|
+
import { createServer as createServer$1 } from "node:net";
|
|
21
26
|
import { Command } from "commander";
|
|
22
27
|
|
|
23
28
|
//#region src/build/ConsumerBuildArtifactsPublisher.ts
|
|
@@ -120,9 +125,8 @@ var DbMigrateCommand = class {
|
|
|
120
125
|
//#region src/commands/DevCommand.ts
|
|
121
126
|
var DevCommand = class {
|
|
122
127
|
require = createRequire(import.meta.url);
|
|
123
|
-
constructor(pathResolver,
|
|
128
|
+
constructor(pathResolver, tsRuntime, devLockFactory, devSourceWatcherFactory, cliLogger, session, databaseMigrationsApplyService, devBootstrapSummaryFetcher, devCliBannerRenderer, devConsumerPublishBootstrap, consumerEnvDotenvFilePredicate, devTrackedProcessTreeKiller, nextHostConsumerServerCommandFactory, devApiRuntimeFactory, cliDevProxyServerFactory, devRebuildQueueFactory) {
|
|
124
129
|
this.pathResolver = pathResolver;
|
|
125
|
-
this.pluginDiscovery = pluginDiscovery;
|
|
126
130
|
this.tsRuntime = tsRuntime;
|
|
127
131
|
this.devLockFactory = devLockFactory;
|
|
128
132
|
this.devSourceWatcherFactory = devSourceWatcherFactory;
|
|
@@ -135,14 +139,17 @@ var DevCommand = class {
|
|
|
135
139
|
this.consumerEnvDotenvFilePredicate = consumerEnvDotenvFilePredicate;
|
|
136
140
|
this.devTrackedProcessTreeKiller = devTrackedProcessTreeKiller;
|
|
137
141
|
this.nextHostConsumerServerCommandFactory = nextHostConsumerServerCommandFactory;
|
|
142
|
+
this.devApiRuntimeFactory = devApiRuntimeFactory;
|
|
143
|
+
this.cliDevProxyServerFactory = cliDevProxyServerFactory;
|
|
144
|
+
this.devRebuildQueueFactory = devRebuildQueueFactory;
|
|
138
145
|
}
|
|
139
|
-
async execute(
|
|
140
|
-
const paths = await this.pathResolver.resolve(consumerRoot);
|
|
146
|
+
async execute(args) {
|
|
147
|
+
const paths = await this.pathResolver.resolve(args.consumerRoot);
|
|
141
148
|
this.devCliBannerRenderer.renderBrandHeader();
|
|
142
149
|
this.tsRuntime.configure(paths.repoRoot);
|
|
143
150
|
await this.databaseMigrationsApplyService.applyForConsumer(paths.consumerRoot);
|
|
144
151
|
await this.devConsumerPublishBootstrap.ensurePublished(paths);
|
|
145
|
-
const devMode = this.
|
|
152
|
+
const devMode = this.resolveDevMode(args);
|
|
146
153
|
const { nextPort, gatewayPort } = await this.session.sessionPorts.resolve({
|
|
147
154
|
devMode,
|
|
148
155
|
portEnv: process$1.env.PORT,
|
|
@@ -151,66 +158,56 @@ var DevCommand = class {
|
|
|
151
158
|
const devLock = this.devLockFactory.create();
|
|
152
159
|
await devLock.acquire({
|
|
153
160
|
consumerRoot: paths.consumerRoot,
|
|
154
|
-
nextPort: devMode === "framework" ? nextPort : gatewayPort
|
|
161
|
+
nextPort: devMode === "watch-framework" ? nextPort : gatewayPort
|
|
155
162
|
});
|
|
156
163
|
const authSettings = await this.session.devAuthLoader.loadForConsumer(paths.consumerRoot);
|
|
157
164
|
const watcher = this.devSourceWatcherFactory.create();
|
|
165
|
+
const processState = this.createInitialProcessState();
|
|
166
|
+
let proxyServer = null;
|
|
158
167
|
try {
|
|
159
168
|
const prepared = await this.prepareDevRuntime(paths, devMode, nextPort, gatewayPort, authSettings);
|
|
160
|
-
const processState = this.createInitialProcessState();
|
|
161
169
|
const stopPromise = this.wireStopPromise(processState);
|
|
162
|
-
const uiProxyBase = await this.
|
|
170
|
+
const uiProxyBase = await this.startPackagedUiWhenNeeded(prepared, processState);
|
|
171
|
+
proxyServer = await this.startProxyServer(prepared.gatewayPort, uiProxyBase);
|
|
163
172
|
const gatewayBaseUrl = this.gatewayBaseHttpUrl(gatewayPort);
|
|
164
|
-
await this.
|
|
173
|
+
await this.bootInitialRuntime(prepared, processState, proxyServer);
|
|
165
174
|
await this.session.devHttpProbe.waitUntilBootstrapSummaryReady(gatewayBaseUrl);
|
|
166
175
|
const initialSummary = await this.devBootstrapSummaryFetcher.fetch(gatewayBaseUrl);
|
|
167
176
|
if (initialSummary) this.devCliBannerRenderer.renderRuntimeSummary(initialSummary);
|
|
168
|
-
this.bindShutdownSignalsToChildProcesses(processState);
|
|
169
|
-
this.
|
|
170
|
-
await this.startWatcherForSourceRestart(prepared, watcher, devMode, gatewayBaseUrl);
|
|
171
|
-
this.
|
|
177
|
+
this.bindShutdownSignalsToChildProcesses(processState, proxyServer);
|
|
178
|
+
await this.spawnDevUiWhenNeeded(prepared, processState, gatewayBaseUrl);
|
|
179
|
+
await this.startWatcherForSourceRestart(prepared, processState, watcher, devMode, gatewayBaseUrl, proxyServer);
|
|
180
|
+
this.logPackagedUiDevHintWhenNeeded(devMode, gatewayPort);
|
|
172
181
|
await stopPromise;
|
|
173
182
|
} finally {
|
|
183
|
+
processState.stopRequested = true;
|
|
184
|
+
await this.stopLiveProcesses(processState, proxyServer);
|
|
174
185
|
await watcher.stop();
|
|
175
186
|
await devLock.release();
|
|
176
187
|
}
|
|
177
188
|
}
|
|
178
|
-
|
|
179
|
-
|
|
189
|
+
resolveDevMode(args) {
|
|
190
|
+
if (args.watchFramework === true || process$1.env.CODEMATION_DEV_MODE === "framework") return "watch-framework";
|
|
191
|
+
return "packaged-ui";
|
|
180
192
|
}
|
|
181
193
|
async prepareDevRuntime(paths, devMode, nextPort, gatewayPort, authSettings) {
|
|
182
|
-
const developmentServerToken = this.session.devAuthLoader.resolveDevelopmentServerToken(process$1.env.CODEMATION_DEV_SERVER_TOKEN);
|
|
183
|
-
const gatewayEntrypoint = await this.session.runtimeEntrypointResolver.resolve({
|
|
184
|
-
packageName: "@codemation/dev-gateway",
|
|
185
|
-
repoRoot: paths.repoRoot,
|
|
186
|
-
sourceEntrypoint: "packages/dev-gateway/src/bin.ts"
|
|
187
|
-
});
|
|
188
|
-
const runtimeEntrypoint = await this.session.runtimeEntrypointResolver.resolve({
|
|
189
|
-
packageName: "@codemation/runtime-dev",
|
|
190
|
-
repoRoot: paths.repoRoot,
|
|
191
|
-
sourceEntrypoint: "packages/runtime-dev/src/bin.ts"
|
|
192
|
-
});
|
|
193
|
-
const runtimeWorkingDirectory = paths.repoRoot ?? paths.consumerRoot;
|
|
194
|
-
const consumerEnv = this.session.consumerEnvLoader.load(paths.consumerRoot);
|
|
195
194
|
return {
|
|
196
195
|
paths,
|
|
197
196
|
devMode,
|
|
198
197
|
nextPort,
|
|
199
198
|
gatewayPort,
|
|
200
199
|
authSettings,
|
|
201
|
-
developmentServerToken,
|
|
202
|
-
|
|
203
|
-
runtimeEntrypoint,
|
|
204
|
-
runtimeWorkingDirectory,
|
|
205
|
-
discoveredPluginPackagesJson: JSON.stringify(await this.pluginDiscovery.discover(paths.consumerRoot)),
|
|
206
|
-
consumerEnv
|
|
200
|
+
developmentServerToken: this.session.devAuthLoader.resolveDevelopmentServerToken(process$1.env.CODEMATION_DEV_SERVER_TOKEN),
|
|
201
|
+
consumerEnv: this.session.consumerEnvLoader.load(paths.consumerRoot)
|
|
207
202
|
};
|
|
208
203
|
}
|
|
209
204
|
createInitialProcessState() {
|
|
210
205
|
return {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
206
|
+
currentDevUi: null,
|
|
207
|
+
currentPackagedUi: null,
|
|
208
|
+
currentPackagedUiBaseUrl: null,
|
|
209
|
+
currentRuntime: null,
|
|
210
|
+
isRestartingUi: false,
|
|
214
211
|
stopRequested: false,
|
|
215
212
|
stopResolve: null,
|
|
216
213
|
stopReject: null
|
|
@@ -225,92 +222,64 @@ var DevCommand = class {
|
|
|
225
222
|
gatewayBaseHttpUrl(gatewayPort) {
|
|
226
223
|
return `http://127.0.0.1:${gatewayPort}`;
|
|
227
224
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
* Framework mode: no separate UI child (Next runs in dev later).
|
|
231
|
-
*/
|
|
232
|
-
async startConsumerUiProxyWhenNeeded(prepared, state) {
|
|
233
|
-
if (prepared.devMode !== "consumer") return "";
|
|
225
|
+
async startPackagedUiWhenNeeded(prepared, state) {
|
|
226
|
+
if (prepared.devMode !== "packaged-ui") return "";
|
|
234
227
|
const websocketPort = prepared.gatewayPort;
|
|
235
|
-
const
|
|
236
|
-
|
|
228
|
+
const uiProxyBase = state.currentPackagedUiBaseUrl ?? `http://127.0.0.1:${await this.session.loopbackPortAllocator.allocate()}`;
|
|
229
|
+
state.currentPackagedUiBaseUrl = uiProxyBase;
|
|
230
|
+
await this.spawnPackagedUi(prepared, state, prepared.authSettings, websocketPort, uiProxyBase);
|
|
231
|
+
return uiProxyBase;
|
|
232
|
+
}
|
|
233
|
+
async spawnPackagedUi(prepared, state, authSettings, websocketPort, uiProxyBase) {
|
|
237
234
|
const nextHostPackageJsonPath = this.require.resolve("@codemation/next-host/package.json");
|
|
238
235
|
const nextHostRoot = path.dirname(nextHostPackageJsonPath);
|
|
239
236
|
const nextHostCommand = await this.nextHostConsumerServerCommandFactory.create({ nextHostRoot });
|
|
240
237
|
const consumerOutputManifestPath = path.resolve(prepared.paths.consumerRoot, ".codemation", "output", "current.json");
|
|
241
|
-
|
|
238
|
+
const uiPort = Number(new URL(uiProxyBase).port);
|
|
239
|
+
const nextHostEnvironment = this.session.nextHostEnvBuilder.buildConsumerUiProxy({
|
|
240
|
+
authConfigJson: authSettings.authConfigJson,
|
|
241
|
+
authSecret: authSettings.authSecret,
|
|
242
|
+
consumerRoot: prepared.paths.consumerRoot,
|
|
243
|
+
consumerOutputManifestPath,
|
|
244
|
+
developmentServerToken: prepared.developmentServerToken,
|
|
245
|
+
nextPort: uiPort,
|
|
246
|
+
publicBaseUrl: this.gatewayBaseHttpUrl(prepared.gatewayPort),
|
|
247
|
+
runtimeDevUrl: this.gatewayBaseHttpUrl(prepared.gatewayPort),
|
|
248
|
+
skipUiAuth: authSettings.skipUiAuth,
|
|
249
|
+
websocketPort
|
|
250
|
+
});
|
|
251
|
+
state.currentPackagedUi = spawn(nextHostCommand.command, nextHostCommand.args, {
|
|
242
252
|
cwd: nextHostCommand.cwd,
|
|
243
253
|
...this.devDetachedChildSpawnOptions(),
|
|
244
|
-
env:
|
|
245
|
-
...process$1.env,
|
|
246
|
-
...prepared.consumerEnv,
|
|
247
|
-
PORT: String(uiPort),
|
|
248
|
-
CODEMATION_AUTH_CONFIG_JSON: prepared.authSettings.authConfigJson,
|
|
249
|
-
CODEMATION_CONSUMER_ROOT: prepared.paths.consumerRoot,
|
|
250
|
-
CODEMATION_CONSUMER_OUTPUT_MANIFEST_PATH: consumerOutputManifestPath,
|
|
251
|
-
CODEMATION_SKIP_UI_AUTH: prepared.authSettings.skipUiAuth ? "true" : "false",
|
|
252
|
-
AUTH_SECRET: prepared.authSettings.authSecret,
|
|
253
|
-
NEXTAUTH_SECRET: prepared.authSettings.authSecret,
|
|
254
|
-
NEXT_PUBLIC_CODEMATION_SKIP_UI_AUTH: prepared.authSettings.skipUiAuth ? "true" : "false",
|
|
255
|
-
CODEMATION_WS_PORT: String(websocketPort),
|
|
256
|
-
NEXT_PUBLIC_CODEMATION_WS_PORT: String(websocketPort),
|
|
257
|
-
CODEMATION_DEV_SERVER_TOKEN: prepared.developmentServerToken,
|
|
258
|
-
NODE_OPTIONS: this.session.sourceMapNodeOptions.appendToNodeOptions(process$1.env.NODE_OPTIONS),
|
|
259
|
-
WS_NO_BUFFER_UTIL: "1",
|
|
260
|
-
WS_NO_UTF_8_VALIDATE: "1"
|
|
261
|
-
}
|
|
254
|
+
env: nextHostEnvironment
|
|
262
255
|
});
|
|
263
|
-
state.
|
|
264
|
-
if (
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
}
|
|
256
|
+
state.currentPackagedUi.on("error", (error) => {
|
|
257
|
+
if (state.stopRequested || state.isRestartingUi) return;
|
|
258
|
+
state.stopRequested = true;
|
|
259
|
+
state.stopReject?.(error instanceof Error ? error : new Error(String(error)));
|
|
268
260
|
});
|
|
269
|
-
state.
|
|
270
|
-
if (state.stopRequested) return;
|
|
261
|
+
state.currentPackagedUi.on("exit", (code) => {
|
|
262
|
+
if (state.stopRequested || state.isRestartingUi) return;
|
|
271
263
|
state.stopRequested = true;
|
|
272
|
-
|
|
273
|
-
state.stopReject?.(/* @__PURE__ */ new Error(`next start (consumer UI) exited unexpectedly with code ${code ?? 0}.`));
|
|
264
|
+
state.stopReject?.(/* @__PURE__ */ new Error(`next start (packaged UI) exited unexpectedly with code ${code ?? 0}.`));
|
|
274
265
|
});
|
|
275
266
|
await this.session.devHttpProbe.waitUntilUrlRespondsOk(`${uiProxyBase}/`);
|
|
276
|
-
return uiProxyBase;
|
|
277
267
|
}
|
|
278
|
-
async
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
CODEMATION_CONSUMER_ROOT: prepared.paths.consumerRoot,
|
|
292
|
-
CODEMATION_DISCOVERED_PLUGIN_PACKAGES_JSON: prepared.discoveredPluginPackagesJson,
|
|
293
|
-
CODEMATION_PREFER_PLUGIN_SOURCE_ENTRY: "true",
|
|
294
|
-
CODEMATION_DEV_SERVER_TOKEN: prepared.developmentServerToken,
|
|
295
|
-
CODEMATION_SKIP_STARTUP_MIGRATIONS: "true",
|
|
296
|
-
NODE_OPTIONS: this.session.sourceMapNodeOptions.appendToNodeOptions(process$1.env.NODE_OPTIONS),
|
|
297
|
-
WS_NO_BUFFER_UTIL: "1",
|
|
298
|
-
WS_NO_UTF_8_VALIDATE: "1",
|
|
299
|
-
...uiProxyBase.length > 0 ? { CODEMATION_DEV_UI_PROXY_TARGET: uiProxyBase } : {}
|
|
300
|
-
}
|
|
301
|
-
});
|
|
302
|
-
state.currentGateway.on("error", (error) => {
|
|
303
|
-
if (!state.stopRequested) {
|
|
304
|
-
state.stopRequested = true;
|
|
305
|
-
state.stopReject?.(error instanceof Error ? error : new Error(String(error)));
|
|
306
|
-
}
|
|
307
|
-
});
|
|
308
|
-
state.currentGateway.on("exit", (code) => {
|
|
309
|
-
if (state.stopRequested) return;
|
|
310
|
-
state.stopRequested = true;
|
|
311
|
-
state.stopReject?.(/* @__PURE__ */ new Error(`codemation dev-gateway exited unexpectedly with code ${code ?? 0}.`));
|
|
268
|
+
async startProxyServer(gatewayPort, uiProxyBase) {
|
|
269
|
+
const proxyServer = this.cliDevProxyServerFactory.create(gatewayPort);
|
|
270
|
+
proxyServer.setUiProxyTarget(uiProxyBase.length > 0 ? uiProxyBase : null);
|
|
271
|
+
await proxyServer.start();
|
|
272
|
+
await this.session.devHttpProbe.waitUntilGatewayHealthy(this.gatewayBaseHttpUrl(gatewayPort));
|
|
273
|
+
return proxyServer;
|
|
274
|
+
}
|
|
275
|
+
async bootInitialRuntime(prepared, state, proxyServer) {
|
|
276
|
+
const runtime = await this.createRuntime(prepared);
|
|
277
|
+
state.currentRuntime = runtime;
|
|
278
|
+
await proxyServer.activateRuntime({
|
|
279
|
+
httpPort: runtime.httpPort,
|
|
280
|
+
workflowWebSocketPort: runtime.workflowWebSocketPort
|
|
312
281
|
});
|
|
313
|
-
|
|
282
|
+
proxyServer.setBuildStatus("idle");
|
|
314
283
|
}
|
|
315
284
|
devDetachedChildSpawnOptions() {
|
|
316
285
|
return process$1.platform === "win32" ? {
|
|
@@ -322,20 +291,14 @@ var DevCommand = class {
|
|
|
322
291
|
detached: true
|
|
323
292
|
};
|
|
324
293
|
}
|
|
325
|
-
bindShutdownSignalsToChildProcesses(state) {
|
|
294
|
+
bindShutdownSignalsToChildProcesses(state, proxyServer) {
|
|
326
295
|
let shutdownInProgress = false;
|
|
327
296
|
const runShutdown = async () => {
|
|
328
297
|
if (shutdownInProgress) return;
|
|
329
298
|
shutdownInProgress = true;
|
|
330
299
|
state.stopRequested = true;
|
|
331
300
|
process$1.stdout.write("\n[codemation] Stopping..\n");
|
|
332
|
-
|
|
333
|
-
for (const child of [
|
|
334
|
-
state.currentUiNext,
|
|
335
|
-
state.currentNextHost,
|
|
336
|
-
state.currentGateway
|
|
337
|
-
]) if (child && child.exitCode === null && child.signalCode === null) children.push(child);
|
|
338
|
-
await Promise.all(children.map((child) => this.devTrackedProcessTreeKiller.killProcessTreeRootedAt(child)));
|
|
301
|
+
await this.stopLiveProcesses(state, proxyServer);
|
|
339
302
|
process$1.stdout.write("[codemation] Stopped.\n");
|
|
340
303
|
state.stopResolve?.();
|
|
341
304
|
};
|
|
@@ -347,24 +310,24 @@ var DevCommand = class {
|
|
|
347
310
|
runShutdown();
|
|
348
311
|
});
|
|
349
312
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
313
|
+
async spawnDevUiWhenNeeded(prepared, state, gatewayBaseUrl) {
|
|
314
|
+
if (prepared.devMode !== "watch-framework") return;
|
|
315
|
+
await this.spawnDevUi(prepared, state, gatewayBaseUrl, prepared.authSettings);
|
|
316
|
+
}
|
|
317
|
+
async spawnDevUi(prepared, state, gatewayBaseUrl, authSettings) {
|
|
355
318
|
const websocketPort = prepared.gatewayPort;
|
|
356
319
|
const nextHostPackageJsonPath = this.require.resolve("@codemation/next-host/package.json");
|
|
357
320
|
const nextHostRoot = path.dirname(nextHostPackageJsonPath);
|
|
358
321
|
const nextHostEnvironment = this.session.nextHostEnvBuilder.build({
|
|
359
|
-
authConfigJson:
|
|
322
|
+
authConfigJson: authSettings.authConfigJson,
|
|
360
323
|
consumerRoot: prepared.paths.consumerRoot,
|
|
361
324
|
developmentServerToken: prepared.developmentServerToken,
|
|
362
325
|
nextPort: prepared.nextPort,
|
|
363
|
-
skipUiAuth:
|
|
326
|
+
skipUiAuth: authSettings.skipUiAuth,
|
|
364
327
|
websocketPort,
|
|
365
328
|
runtimeDevUrl: gatewayBaseUrl
|
|
366
329
|
});
|
|
367
|
-
state.
|
|
330
|
+
state.currentDevUi = spawn("pnpm", [
|
|
368
331
|
"exec",
|
|
369
332
|
"next",
|
|
370
333
|
"dev"
|
|
@@ -373,26 +336,28 @@ var DevCommand = class {
|
|
|
373
336
|
...this.devDetachedChildSpawnOptions(),
|
|
374
337
|
env: nextHostEnvironment
|
|
375
338
|
});
|
|
376
|
-
state.
|
|
339
|
+
state.currentDevUi.on("exit", (code) => {
|
|
377
340
|
const normalizedCode = code ?? 0;
|
|
378
|
-
if (state.stopRequested) return;
|
|
341
|
+
if (state.stopRequested || state.isRestartingUi) return;
|
|
379
342
|
if (normalizedCode === 0) {
|
|
380
343
|
state.stopRequested = true;
|
|
381
|
-
if (state.currentGateway?.exitCode === null) this.devTrackedProcessTreeKiller.killProcessTreeRootedAt(state.currentGateway);
|
|
382
344
|
state.stopResolve?.();
|
|
383
345
|
return;
|
|
384
346
|
}
|
|
385
347
|
state.stopRequested = true;
|
|
386
348
|
state.stopReject?.(/* @__PURE__ */ new Error(`next host exited with code ${normalizedCode}.`));
|
|
387
349
|
});
|
|
388
|
-
state.
|
|
389
|
-
if (
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
}
|
|
350
|
+
state.currentDevUi.on("error", (error) => {
|
|
351
|
+
if (state.stopRequested || state.isRestartingUi) return;
|
|
352
|
+
state.stopRequested = true;
|
|
353
|
+
state.stopReject?.(error instanceof Error ? error : new Error(String(error)));
|
|
393
354
|
});
|
|
355
|
+
await this.session.devHttpProbe.waitUntilUrlRespondsOk(`http://127.0.0.1:${prepared.nextPort}/`);
|
|
394
356
|
}
|
|
395
|
-
async startWatcherForSourceRestart(prepared, watcher, devMode, gatewayBaseUrl) {
|
|
357
|
+
async startWatcherForSourceRestart(prepared, state, watcher, devMode, gatewayBaseUrl, proxyServer) {
|
|
358
|
+
const rebuildQueue = this.devRebuildQueueFactory.create({ run: async (request) => {
|
|
359
|
+
await this.runQueuedRebuild(prepared, state, gatewayBaseUrl, proxyServer, request);
|
|
360
|
+
} });
|
|
396
361
|
await watcher.start({
|
|
397
362
|
roots: this.session.watchRootsResolver.resolve({
|
|
398
363
|
consumerRoot: prepared.paths.consumerRoot,
|
|
@@ -401,22 +366,119 @@ var DevCommand = class {
|
|
|
401
366
|
}),
|
|
402
367
|
onChange: async ({ changedPaths }) => {
|
|
403
368
|
if (changedPaths.length > 0 && changedPaths.every((p) => this.consumerEnvDotenvFilePredicate.matches(p))) {
|
|
404
|
-
process$1.stdout.write("\n[codemation] Consumer environment file changed (e.g. .env). Restart the `codemation dev` process so the
|
|
369
|
+
process$1.stdout.write("\n[codemation] Consumer environment file changed (e.g. .env). Restart the `codemation dev` process so the runtime picks up updated variables (host `process.env` does not hot-reload).\n");
|
|
405
370
|
return;
|
|
406
371
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
372
|
+
try {
|
|
373
|
+
const shouldRepublishConsumerOutput = this.session.sourceChangeClassifier.shouldRepublishConsumerOutput({
|
|
374
|
+
changedPaths,
|
|
375
|
+
consumerRoot: prepared.paths.consumerRoot
|
|
376
|
+
});
|
|
377
|
+
const shouldRestartUi = this.session.sourceChangeClassifier.requiresUiRestart({
|
|
378
|
+
changedPaths,
|
|
379
|
+
consumerRoot: prepared.paths.consumerRoot
|
|
380
|
+
});
|
|
381
|
+
process$1.stdout.write(shouldRestartUi ? "\n[codemation] Source change detected — rebuilding consumer, restarting the runtime, and restarting the UI…\n" : "\n[codemation] Source change detected — rebuilding consumer and restarting the runtime…\n");
|
|
382
|
+
await rebuildQueue.enqueue({
|
|
383
|
+
changedPaths,
|
|
384
|
+
shouldRepublishConsumerOutput,
|
|
385
|
+
shouldRestartUi
|
|
386
|
+
});
|
|
387
|
+
} catch (error) {
|
|
388
|
+
await this.failDevSessionAfterIrrecoverableSourceError(state, proxyServer, error);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
async runQueuedRebuild(prepared, state, gatewayBaseUrl, proxyServer, request) {
|
|
394
|
+
proxyServer.setBuildStatus("building");
|
|
395
|
+
proxyServer.broadcastBuildStarted();
|
|
396
|
+
try {
|
|
397
|
+
if (request.shouldRepublishConsumerOutput) await this.devConsumerPublishBootstrap.ensurePublished(prepared.paths);
|
|
398
|
+
await this.stopCurrentRuntime(state, proxyServer);
|
|
399
|
+
process$1.stdout.write("[codemation] Waiting for runtime to accept traffic…\n");
|
|
400
|
+
const runtime = await this.createRuntime(prepared);
|
|
401
|
+
state.currentRuntime = runtime;
|
|
402
|
+
await proxyServer.activateRuntime({
|
|
403
|
+
httpPort: runtime.httpPort,
|
|
404
|
+
workflowWebSocketPort: runtime.workflowWebSocketPort
|
|
405
|
+
});
|
|
406
|
+
if (request.shouldRestartUi) await this.restartUiAfterSourceChange(prepared, state, gatewayBaseUrl);
|
|
407
|
+
await this.session.devHttpProbe.waitUntilBootstrapSummaryReady(gatewayBaseUrl);
|
|
408
|
+
const json = await this.devBootstrapSummaryFetcher.fetch(gatewayBaseUrl);
|
|
409
|
+
if (json) this.devCliBannerRenderer.renderCompact(json);
|
|
410
|
+
proxyServer.setBuildStatus("idle");
|
|
411
|
+
proxyServer.broadcastBuildCompleted(runtime.buildVersion);
|
|
412
|
+
process$1.stdout.write("[codemation] Runtime ready.\n");
|
|
413
|
+
} catch (error) {
|
|
414
|
+
proxyServer.setBuildStatus("idle");
|
|
415
|
+
proxyServer.broadcastBuildFailed(error instanceof Error ? error.message : String(error));
|
|
416
|
+
throw error;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
async restartUiAfterSourceChange(prepared, state, gatewayBaseUrl) {
|
|
420
|
+
const refreshedAuthSettings = await this.session.devAuthLoader.loadForConsumer(prepared.paths.consumerRoot);
|
|
421
|
+
process$1.stdout.write("[codemation] Restarting the UI process to apply source changes…\n");
|
|
422
|
+
state.isRestartingUi = true;
|
|
423
|
+
try {
|
|
424
|
+
if (prepared.devMode === "packaged-ui") {
|
|
425
|
+
await this.restartPackagedUi(prepared, state, refreshedAuthSettings);
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
await this.restartDevUi(prepared, state, gatewayBaseUrl, refreshedAuthSettings);
|
|
429
|
+
} finally {
|
|
430
|
+
state.isRestartingUi = false;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
async restartPackagedUi(prepared, state, authSettings) {
|
|
434
|
+
if (state.currentPackagedUi && state.currentPackagedUi.exitCode === null && state.currentPackagedUi.signalCode === null) await this.devTrackedProcessTreeKiller.killProcessTreeRootedAt(state.currentPackagedUi);
|
|
435
|
+
state.currentPackagedUi = null;
|
|
436
|
+
const uiProxyBaseUrl = state.currentPackagedUiBaseUrl;
|
|
437
|
+
if (!uiProxyBaseUrl) throw new Error("Packaged UI proxy base URL is missing during UI restart.");
|
|
438
|
+
await this.spawnPackagedUi(prepared, state, authSettings, prepared.gatewayPort, uiProxyBaseUrl);
|
|
439
|
+
}
|
|
440
|
+
async restartDevUi(prepared, state, gatewayBaseUrl, authSettings) {
|
|
441
|
+
if (state.currentDevUi && state.currentDevUi.exitCode === null && state.currentDevUi.signalCode === null) await this.devTrackedProcessTreeKiller.killProcessTreeRootedAt(state.currentDevUi);
|
|
442
|
+
state.currentDevUi = null;
|
|
443
|
+
await this.spawnDevUi(prepared, state, gatewayBaseUrl, authSettings);
|
|
444
|
+
}
|
|
445
|
+
async failDevSessionAfterIrrecoverableSourceError(state, proxyServer, error) {
|
|
446
|
+
const exception = error instanceof Error ? error : new Error(String(error));
|
|
447
|
+
state.stopRequested = true;
|
|
448
|
+
await this.stopLiveProcesses(state, proxyServer);
|
|
449
|
+
state.stopReject?.(exception);
|
|
450
|
+
}
|
|
451
|
+
async stopLiveProcesses(state, proxyServer) {
|
|
452
|
+
await this.stopCurrentRuntime(state, proxyServer);
|
|
453
|
+
const children = [];
|
|
454
|
+
for (const child of [state.currentPackagedUi, state.currentDevUi]) if (child && child.exitCode === null && child.signalCode === null) children.push(child);
|
|
455
|
+
await Promise.all(children.map((child) => this.devTrackedProcessTreeKiller.killProcessTreeRootedAt(child)));
|
|
456
|
+
if (proxyServer) await proxyServer.stop();
|
|
457
|
+
}
|
|
458
|
+
async stopCurrentRuntime(state, proxyServer) {
|
|
459
|
+
const runtime = state.currentRuntime;
|
|
460
|
+
state.currentRuntime = null;
|
|
461
|
+
if (proxyServer) await proxyServer.activateRuntime(null);
|
|
462
|
+
if (runtime) await runtime.stop();
|
|
463
|
+
}
|
|
464
|
+
async createRuntime(prepared) {
|
|
465
|
+
const runtimeEnvironment = this.session.consumerEnvLoader.mergeIntoProcessEnvironment(process$1.env, prepared.consumerEnv);
|
|
466
|
+
return await this.devApiRuntimeFactory.create({
|
|
467
|
+
consumerRoot: prepared.paths.consumerRoot,
|
|
468
|
+
runtimeWorkingDirectory: process$1.cwd(),
|
|
469
|
+
env: {
|
|
470
|
+
...runtimeEnvironment,
|
|
471
|
+
CODEMATION_DEV_SERVER_TOKEN: prepared.developmentServerToken,
|
|
472
|
+
CODEMATION_SKIP_STARTUP_MIGRATIONS: "true",
|
|
473
|
+
NODE_OPTIONS: this.session.sourceMapNodeOptions.appendToNodeOptions(process$1.env.NODE_OPTIONS),
|
|
474
|
+
WS_NO_BUFFER_UTIL: "1",
|
|
475
|
+
WS_NO_UTF_8_VALIDATE: "1"
|
|
414
476
|
}
|
|
415
477
|
});
|
|
416
478
|
}
|
|
417
|
-
|
|
418
|
-
if (devMode !== "
|
|
419
|
-
this.cliLogger.info(`codemation dev
|
|
479
|
+
logPackagedUiDevHintWhenNeeded(devMode, gatewayPort) {
|
|
480
|
+
if (devMode !== "packaged-ui") return;
|
|
481
|
+
this.cliLogger.info(`codemation dev: open http://127.0.0.1:${gatewayPort} — this uses the packaged @codemation/next-host UI. Use \`codemation dev --watch-framework\` only when working on the framework UI itself.`);
|
|
420
482
|
}
|
|
421
483
|
};
|
|
422
484
|
|
|
@@ -424,8 +486,9 @@ var DevCommand = class {
|
|
|
424
486
|
//#region src/commands/ServeWebCommand.ts
|
|
425
487
|
var ServeWebCommand = class {
|
|
426
488
|
require = createRequire(import.meta.url);
|
|
427
|
-
constructor(pathResolver, pluginDiscovery, artifactsPublisher, tsRuntime, sourceMapNodeOptions, outputBuilderLoader, envLoader, listenPortResolver, nextHostConsumerServerCommandFactory) {
|
|
489
|
+
constructor(pathResolver, configLoader, pluginDiscovery, artifactsPublisher, tsRuntime, sourceMapNodeOptions, outputBuilderLoader, envLoader, listenPortResolver, nextHostConsumerServerCommandFactory, frontendAuthSnapshotFactory, frontendAppConfigJsonCodec) {
|
|
428
490
|
this.pathResolver = pathResolver;
|
|
491
|
+
this.configLoader = configLoader;
|
|
429
492
|
this.pluginDiscovery = pluginDiscovery;
|
|
430
493
|
this.artifactsPublisher = artifactsPublisher;
|
|
431
494
|
this.tsRuntime = tsRuntime;
|
|
@@ -434,6 +497,8 @@ var ServeWebCommand = class {
|
|
|
434
497
|
this.envLoader = envLoader;
|
|
435
498
|
this.listenPortResolver = listenPortResolver;
|
|
436
499
|
this.nextHostConsumerServerCommandFactory = nextHostConsumerServerCommandFactory;
|
|
500
|
+
this.frontendAuthSnapshotFactory = frontendAuthSnapshotFactory;
|
|
501
|
+
this.frontendAppConfigJsonCodec = frontendAppConfigJsonCodec;
|
|
437
502
|
}
|
|
438
503
|
async execute(consumerRoot, buildOptions) {
|
|
439
504
|
const paths = await this.pathResolver.resolve(consumerRoot);
|
|
@@ -444,6 +509,15 @@ var ServeWebCommand = class {
|
|
|
444
509
|
const nextHostRoot = path.dirname(this.require.resolve("@codemation/next-host/package.json"));
|
|
445
510
|
const nextHostCommand = await this.nextHostConsumerServerCommandFactory.create({ nextHostRoot });
|
|
446
511
|
const consumerEnv = this.envLoader.load(paths.consumerRoot);
|
|
512
|
+
const configResolution = await this.configLoader.load({ consumerRoot: paths.consumerRoot });
|
|
513
|
+
const frontendAuthSnapshot = this.frontendAuthSnapshotFactory.createFromResolvedInputs({
|
|
514
|
+
authConfig: configResolution.config.auth,
|
|
515
|
+
env: {
|
|
516
|
+
...process$1.env,
|
|
517
|
+
...consumerEnv
|
|
518
|
+
},
|
|
519
|
+
uiAuthEnabled: !(consumerEnv.NODE_ENV !== "production" && configResolution.config.auth?.allowUnauthenticatedInDevelopment === true)
|
|
520
|
+
});
|
|
447
521
|
const nextPort = this.listenPortResolver.resolvePrimaryApplicationPort(process$1.env.PORT);
|
|
448
522
|
const websocketPort = this.listenPortResolver.resolveWebsocketPortRelativeToHttp({
|
|
449
523
|
nextPort,
|
|
@@ -457,6 +531,11 @@ var ServeWebCommand = class {
|
|
|
457
531
|
...process$1.env,
|
|
458
532
|
...consumerEnv,
|
|
459
533
|
PORT: String(nextPort),
|
|
534
|
+
CODEMATION_FRONTEND_APP_CONFIG_JSON: this.frontendAppConfigJsonCodec.serialize({
|
|
535
|
+
auth: frontendAuthSnapshot,
|
|
536
|
+
productName: "Codemation",
|
|
537
|
+
logoUrl: null
|
|
538
|
+
}),
|
|
460
539
|
CODEMATION_CONSUMER_OUTPUT_MANIFEST_PATH: manifest.manifestPath,
|
|
461
540
|
CODEMATION_CONSUMER_ROOT: paths.consumerRoot,
|
|
462
541
|
CODEMATION_WS_PORT: String(websocketPort),
|
|
@@ -482,34 +561,46 @@ var ServeWebCommand = class {
|
|
|
482
561
|
//#endregion
|
|
483
562
|
//#region src/commands/ServeWorkerCommand.ts
|
|
484
563
|
var ServeWorkerCommand = class {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
this.
|
|
564
|
+
constructor(pathResolver, appConfigLoader, appContainerFactory) {
|
|
565
|
+
this.pathResolver = pathResolver;
|
|
566
|
+
this.appConfigLoader = appConfigLoader;
|
|
567
|
+
this.appContainerFactory = appContainerFactory;
|
|
488
568
|
}
|
|
489
569
|
async execute(consumerRoot, configPathOverride) {
|
|
490
|
-
const
|
|
491
|
-
const
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
stdio: "inherit",
|
|
497
|
-
env: {
|
|
498
|
-
...process$1.env,
|
|
499
|
-
NODE_OPTIONS: this.sourceMapNodeOptions.appendToNodeOptions(process$1.env.NODE_OPTIONS)
|
|
500
|
-
}
|
|
570
|
+
const paths = await this.pathResolver.resolve(consumerRoot);
|
|
571
|
+
const loadResult = await this.appConfigLoader.load({
|
|
572
|
+
consumerRoot,
|
|
573
|
+
repoRoot: paths.repoRoot,
|
|
574
|
+
env: process$1.env,
|
|
575
|
+
configPathOverride
|
|
501
576
|
});
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
577
|
+
if (loadResult.appConfig.scheduler.kind !== "bullmq") throw new Error("Worker mode requires runtime.scheduler.kind = \"bullmq\".");
|
|
578
|
+
const container = await this.appContainerFactory.create({
|
|
579
|
+
appConfig: loadResult.appConfig,
|
|
580
|
+
sharedWorkflowWebsocketServer: null
|
|
581
|
+
});
|
|
582
|
+
const workerQueues = loadResult.appConfig.scheduler.workerQueues.length > 0 ? loadResult.appConfig.scheduler.workerQueues : ["default"];
|
|
583
|
+
const handle = await container.resolve(WorkerRuntime).start(workerQueues);
|
|
584
|
+
await new Promise((resolve) => {
|
|
585
|
+
this.bindSignals(handle.stop, resolve);
|
|
511
586
|
});
|
|
512
587
|
}
|
|
588
|
+
bindSignals(stop, resolve) {
|
|
589
|
+
let stopping = false;
|
|
590
|
+
const onSignal = async () => {
|
|
591
|
+
if (stopping) return;
|
|
592
|
+
stopping = true;
|
|
593
|
+
try {
|
|
594
|
+
await stop();
|
|
595
|
+
} finally {
|
|
596
|
+
resolve();
|
|
597
|
+
process$1.exit(0);
|
|
598
|
+
}
|
|
599
|
+
};
|
|
600
|
+
process$1.on("SIGINT", () => void onSignal());
|
|
601
|
+
process$1.on("SIGTERM", () => void onSignal());
|
|
602
|
+
process$1.on("SIGQUIT", () => void onSignal());
|
|
603
|
+
}
|
|
513
604
|
};
|
|
514
605
|
|
|
515
606
|
//#endregion
|
|
@@ -1210,13 +1301,36 @@ var ConsumerOutputBuilderLoader = class {
|
|
|
1210
1301
|
* Resolves TCP PostgreSQL vs PGlite vs none from env + {@link CodemationConfig} (same rules as the host runtime).
|
|
1211
1302
|
*/
|
|
1212
1303
|
var ConsumerDatabaseConnectionResolver = class {
|
|
1213
|
-
resolver = new DatabasePersistenceResolver();
|
|
1214
1304
|
resolve(processEnv, config$1, consumerRoot) {
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1305
|
+
const database = config$1.runtime?.database;
|
|
1306
|
+
if (!database) return { kind: "none" };
|
|
1307
|
+
if (this.resolveDatabaseKind(database.kind, database.url, processEnv) === "postgresql") {
|
|
1308
|
+
const databaseUrl = database.url?.trim() ?? "";
|
|
1309
|
+
if (!databaseUrl) throw new Error("runtime.database.kind is \"postgresql\" but no database URL was set (runtime.database.url).");
|
|
1310
|
+
return {
|
|
1311
|
+
kind: "postgresql",
|
|
1312
|
+
databaseUrl
|
|
1313
|
+
};
|
|
1314
|
+
}
|
|
1315
|
+
return {
|
|
1316
|
+
kind: "pglite",
|
|
1317
|
+
dataDir: this.resolvePgliteDataDir(database.pgliteDataDir, processEnv, consumerRoot)
|
|
1318
|
+
};
|
|
1319
|
+
}
|
|
1320
|
+
resolveDatabaseKind(configuredKind, databaseUrl, env) {
|
|
1321
|
+
const kindFromEnv = env.CODEMATION_DATABASE_KIND?.trim();
|
|
1322
|
+
if (kindFromEnv === "postgresql" || kindFromEnv === "pglite") return kindFromEnv;
|
|
1323
|
+
if (configuredKind) return configuredKind;
|
|
1324
|
+
const trimmedUrl = databaseUrl?.trim();
|
|
1325
|
+
if (trimmedUrl && (trimmedUrl.startsWith("postgresql://") || trimmedUrl.startsWith("postgres://"))) return "postgresql";
|
|
1326
|
+
return "pglite";
|
|
1327
|
+
}
|
|
1328
|
+
resolvePgliteDataDir(configuredPath, env, consumerRoot) {
|
|
1329
|
+
const envPath = env.CODEMATION_PGLITE_DATA_DIR?.trim();
|
|
1330
|
+
if (envPath && envPath.length > 0) return path.isAbsolute(envPath) ? envPath : path.resolve(consumerRoot, envPath);
|
|
1331
|
+
const trimmedConfiguredPath = configuredPath?.trim();
|
|
1332
|
+
if (trimmedConfiguredPath && trimmedConfiguredPath.length > 0) return path.isAbsolute(trimmedConfiguredPath) ? trimmedConfiguredPath : path.resolve(consumerRoot, trimmedConfiguredPath);
|
|
1333
|
+
return path.resolve(consumerRoot, ".codemation", "pglite");
|
|
1220
1334
|
}
|
|
1221
1335
|
};
|
|
1222
1336
|
|
|
@@ -1292,7 +1406,7 @@ var HostPackageRootResolver = class {
|
|
|
1292
1406
|
//#endregion
|
|
1293
1407
|
//#region src/dev/DevBootstrapSummaryFetcher.ts
|
|
1294
1408
|
/**
|
|
1295
|
-
* Fetches {@link DevBootstrapSummaryJson} from the
|
|
1409
|
+
* Fetches {@link DevBootstrapSummaryJson} from the stable CLI-owned dev endpoint.
|
|
1296
1410
|
*/
|
|
1297
1411
|
var DevBootstrapSummaryFetcher = class {
|
|
1298
1412
|
async fetch(gatewayBaseUrl) {
|
|
@@ -1442,6 +1556,710 @@ var DevConsumerPublishBootstrap = class {
|
|
|
1442
1556
|
}
|
|
1443
1557
|
};
|
|
1444
1558
|
|
|
1559
|
+
//#endregion
|
|
1560
|
+
//#region src/dev/CliDevProxyServer.ts
|
|
1561
|
+
var CliDevProxyServer = class {
|
|
1562
|
+
proxy = httpProxy.createProxyServer({
|
|
1563
|
+
ws: true,
|
|
1564
|
+
xfwd: true
|
|
1565
|
+
});
|
|
1566
|
+
devClients = /* @__PURE__ */ new Set();
|
|
1567
|
+
devWss = new WebSocketServer({ noServer: true });
|
|
1568
|
+
workflowClients = /* @__PURE__ */ new Set();
|
|
1569
|
+
workflowWss = new WebSocketServer({ noServer: true });
|
|
1570
|
+
roomIdsByWorkflowClient = /* @__PURE__ */ new Map();
|
|
1571
|
+
workflowClientCountByRoomId = /* @__PURE__ */ new Map();
|
|
1572
|
+
activeRuntime = null;
|
|
1573
|
+
activeBuildStatus = "idle";
|
|
1574
|
+
childWorkflowSocket = null;
|
|
1575
|
+
server = null;
|
|
1576
|
+
uiProxyTarget = null;
|
|
1577
|
+
constructor(listenPort) {
|
|
1578
|
+
this.listenPort = listenPort;
|
|
1579
|
+
}
|
|
1580
|
+
async start() {
|
|
1581
|
+
if (this.server) return;
|
|
1582
|
+
this.bindDevWebSocket();
|
|
1583
|
+
this.bindWorkflowWebSocket();
|
|
1584
|
+
this.proxy.on("error", (error, _req, res) => {
|
|
1585
|
+
if (res && "writeHead" in res && typeof res.writeHead === "function") {
|
|
1586
|
+
const serverResponse = res;
|
|
1587
|
+
if (!serverResponse.headersSent) {
|
|
1588
|
+
serverResponse.writeHead(502, { "content-type": "text/plain" });
|
|
1589
|
+
serverResponse.end(`Bad gateway: ${error.message}`);
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
});
|
|
1593
|
+
const server = createServer((req, res) => {
|
|
1594
|
+
this.handleHttpRequest(req, res);
|
|
1595
|
+
});
|
|
1596
|
+
server.on("upgrade", (request, socket, head) => {
|
|
1597
|
+
this.handleUpgrade(request, socket, head);
|
|
1598
|
+
});
|
|
1599
|
+
await new Promise((resolve, reject) => {
|
|
1600
|
+
server.once("error", reject);
|
|
1601
|
+
server.listen(this.listenPort, "127.0.0.1", () => {
|
|
1602
|
+
resolve();
|
|
1603
|
+
});
|
|
1604
|
+
});
|
|
1605
|
+
this.server = server;
|
|
1606
|
+
}
|
|
1607
|
+
async stop() {
|
|
1608
|
+
await this.disconnectChildWorkflowSocket();
|
|
1609
|
+
this.activeRuntime = null;
|
|
1610
|
+
const server = this.server;
|
|
1611
|
+
this.server = null;
|
|
1612
|
+
for (const client of this.devClients) client.terminate();
|
|
1613
|
+
this.devClients.clear();
|
|
1614
|
+
for (const client of this.workflowClients) client.terminate();
|
|
1615
|
+
this.workflowClients.clear();
|
|
1616
|
+
this.roomIdsByWorkflowClient.clear();
|
|
1617
|
+
this.workflowClientCountByRoomId.clear();
|
|
1618
|
+
if (!server) return;
|
|
1619
|
+
await new Promise((resolve, reject) => {
|
|
1620
|
+
server.close((error) => {
|
|
1621
|
+
if (error) {
|
|
1622
|
+
reject(error);
|
|
1623
|
+
return;
|
|
1624
|
+
}
|
|
1625
|
+
resolve();
|
|
1626
|
+
});
|
|
1627
|
+
});
|
|
1628
|
+
}
|
|
1629
|
+
setUiProxyTarget(target) {
|
|
1630
|
+
this.uiProxyTarget = target?.trim() ? target.trim() : null;
|
|
1631
|
+
}
|
|
1632
|
+
async activateRuntime(target) {
|
|
1633
|
+
this.activeRuntime = target;
|
|
1634
|
+
await this.connectChildWorkflowSocket();
|
|
1635
|
+
}
|
|
1636
|
+
setBuildStatus(status) {
|
|
1637
|
+
this.activeBuildStatus = status;
|
|
1638
|
+
}
|
|
1639
|
+
broadcastBuildStarted() {
|
|
1640
|
+
this.broadcastDev({ kind: "devBuildStarted" });
|
|
1641
|
+
this.broadcastWorkflowLifecycleToSubscribedRooms((roomId) => ({
|
|
1642
|
+
kind: "devBuildStarted",
|
|
1643
|
+
workflowId: roomId
|
|
1644
|
+
}));
|
|
1645
|
+
}
|
|
1646
|
+
broadcastBuildCompleted(buildVersion) {
|
|
1647
|
+
this.broadcastDev({
|
|
1648
|
+
kind: "devBuildCompleted",
|
|
1649
|
+
buildVersion
|
|
1650
|
+
});
|
|
1651
|
+
this.broadcastWorkflowLifecycleToSubscribedRooms((roomId) => ({
|
|
1652
|
+
kind: "devBuildCompleted",
|
|
1653
|
+
workflowId: roomId,
|
|
1654
|
+
buildVersion
|
|
1655
|
+
}));
|
|
1656
|
+
}
|
|
1657
|
+
broadcastBuildFailed(message) {
|
|
1658
|
+
this.broadcastDev({
|
|
1659
|
+
kind: "devBuildFailed",
|
|
1660
|
+
message
|
|
1661
|
+
});
|
|
1662
|
+
this.broadcastWorkflowLifecycleToSubscribedRooms((roomId) => ({
|
|
1663
|
+
kind: "devBuildFailed",
|
|
1664
|
+
workflowId: roomId,
|
|
1665
|
+
message
|
|
1666
|
+
}));
|
|
1667
|
+
}
|
|
1668
|
+
bindDevWebSocket() {
|
|
1669
|
+
this.devWss.on("connection", (socket) => {
|
|
1670
|
+
this.devClients.add(socket);
|
|
1671
|
+
socket.on("close", () => {
|
|
1672
|
+
this.devClients.delete(socket);
|
|
1673
|
+
});
|
|
1674
|
+
});
|
|
1675
|
+
}
|
|
1676
|
+
bindWorkflowWebSocket() {
|
|
1677
|
+
this.workflowWss.on("connection", (socket) => {
|
|
1678
|
+
this.connectWorkflowClient(socket);
|
|
1679
|
+
});
|
|
1680
|
+
}
|
|
1681
|
+
async handleHttpRequest(req, res) {
|
|
1682
|
+
const pathname = this.safePathname(req.url ?? "");
|
|
1683
|
+
const uiProxyTarget = this.uiProxyTarget;
|
|
1684
|
+
const activeRuntimeTarget = this.activeRuntime ? `http://127.0.0.1:${this.activeRuntime.httpPort}` : void 0;
|
|
1685
|
+
if (pathname === "/api/dev/health" && req.method === "GET") {
|
|
1686
|
+
res.writeHead(200, { "content-type": "application/json" });
|
|
1687
|
+
res.end(JSON.stringify({
|
|
1688
|
+
ok: true,
|
|
1689
|
+
runtime: { status: this.activeRuntime ? this.activeBuildStatus === "building" ? "building" : "ready" : "stopped" }
|
|
1690
|
+
}));
|
|
1691
|
+
return;
|
|
1692
|
+
}
|
|
1693
|
+
if (pathname === "/api/dev/bootstrap-summary") {
|
|
1694
|
+
if (!activeRuntimeTarget) {
|
|
1695
|
+
res.writeHead(503, { "content-type": "text/plain" });
|
|
1696
|
+
res.end("Runtime is rebuilding.");
|
|
1697
|
+
return;
|
|
1698
|
+
}
|
|
1699
|
+
this.proxy.web(req, res, { target: activeRuntimeTarget });
|
|
1700
|
+
return;
|
|
1701
|
+
}
|
|
1702
|
+
if (uiProxyTarget && pathname.startsWith("/api/auth/")) {
|
|
1703
|
+
this.proxy.web(req, res, { target: uiProxyTarget.replace(/\/$/, "") });
|
|
1704
|
+
return;
|
|
1705
|
+
}
|
|
1706
|
+
if (pathname.startsWith("/api/")) {
|
|
1707
|
+
if (this.activeBuildStatus === "building" || !this.activeRuntime) {
|
|
1708
|
+
res.writeHead(503, { "content-type": "text/plain" });
|
|
1709
|
+
res.end("Runtime is rebuilding.");
|
|
1710
|
+
return;
|
|
1711
|
+
}
|
|
1712
|
+
this.proxy.web(req, res, { target: activeRuntimeTarget });
|
|
1713
|
+
return;
|
|
1714
|
+
}
|
|
1715
|
+
if (uiProxyTarget) {
|
|
1716
|
+
this.proxy.web(req, res, { target: uiProxyTarget.replace(/\/$/, "") });
|
|
1717
|
+
return;
|
|
1718
|
+
}
|
|
1719
|
+
res.writeHead(404, { "content-type": "text/plain" });
|
|
1720
|
+
res.end("Not found.");
|
|
1721
|
+
}
|
|
1722
|
+
handleUpgrade(request, socket, head) {
|
|
1723
|
+
const pathname = this.safePathname(request.url ?? "");
|
|
1724
|
+
if (pathname === ApiPaths.devGatewaySocket()) {
|
|
1725
|
+
this.devWss.handleUpgrade(request, socket, head, (ws) => {
|
|
1726
|
+
this.devWss.emit("connection", ws, request);
|
|
1727
|
+
});
|
|
1728
|
+
return;
|
|
1729
|
+
}
|
|
1730
|
+
if (pathname === ApiPaths.workflowWebsocket()) {
|
|
1731
|
+
this.workflowWss.handleUpgrade(request, socket, head, (ws) => {
|
|
1732
|
+
this.workflowWss.emit("connection", ws, request);
|
|
1733
|
+
});
|
|
1734
|
+
return;
|
|
1735
|
+
}
|
|
1736
|
+
const uiProxyTarget = this.uiProxyTarget;
|
|
1737
|
+
if (uiProxyTarget && !pathname.startsWith("/api/")) {
|
|
1738
|
+
this.proxy.ws(request, socket, head, { target: uiProxyTarget.replace(/\/$/, "") });
|
|
1739
|
+
return;
|
|
1740
|
+
}
|
|
1741
|
+
socket.destroy();
|
|
1742
|
+
}
|
|
1743
|
+
safePathname(url) {
|
|
1744
|
+
try {
|
|
1745
|
+
return new URL(url, "http://127.0.0.1").pathname;
|
|
1746
|
+
} catch {
|
|
1747
|
+
return url.split("?")[0] ?? url;
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
broadcastDev(message) {
|
|
1751
|
+
const text = JSON.stringify(message);
|
|
1752
|
+
for (const client of this.devClients) if (client.readyState === WebSocket.OPEN) client.send(text);
|
|
1753
|
+
}
|
|
1754
|
+
broadcastWorkflowLifecycleToSubscribedRooms(createMessage) {
|
|
1755
|
+
for (const roomId of this.workflowClientCountByRoomId.keys()) this.broadcastWorkflowTextToRoom(roomId, JSON.stringify(createMessage(roomId)));
|
|
1756
|
+
}
|
|
1757
|
+
async connectWorkflowClient(socket) {
|
|
1758
|
+
this.workflowClients.add(socket);
|
|
1759
|
+
this.roomIdsByWorkflowClient.set(socket, /* @__PURE__ */ new Set());
|
|
1760
|
+
socket.send(JSON.stringify({ kind: "ready" }));
|
|
1761
|
+
socket.on("message", (rawData) => {
|
|
1762
|
+
this.handleWorkflowClientMessage(socket, rawData);
|
|
1763
|
+
});
|
|
1764
|
+
socket.on("close", () => {
|
|
1765
|
+
this.disconnectWorkflowClient(socket);
|
|
1766
|
+
});
|
|
1767
|
+
socket.on("error", () => {
|
|
1768
|
+
this.disconnectWorkflowClient(socket);
|
|
1769
|
+
});
|
|
1770
|
+
}
|
|
1771
|
+
disconnectWorkflowClient(socket) {
|
|
1772
|
+
const roomIds = this.roomIdsByWorkflowClient.get(socket);
|
|
1773
|
+
if (roomIds) for (const roomId of roomIds) this.releaseWorkflowRoom(roomId);
|
|
1774
|
+
this.roomIdsByWorkflowClient.delete(socket);
|
|
1775
|
+
this.workflowClients.delete(socket);
|
|
1776
|
+
}
|
|
1777
|
+
async handleWorkflowClientMessage(socket, rawData) {
|
|
1778
|
+
try {
|
|
1779
|
+
const message = this.parseWorkflowClientMessage(rawData);
|
|
1780
|
+
if (message.kind === "subscribe") {
|
|
1781
|
+
const roomIds$1 = this.roomIdsByWorkflowClient.get(socket);
|
|
1782
|
+
if (!roomIds$1) return;
|
|
1783
|
+
if (!roomIds$1.has(message.roomId)) {
|
|
1784
|
+
roomIds$1.add(message.roomId);
|
|
1785
|
+
this.retainWorkflowRoom(message.roomId);
|
|
1786
|
+
}
|
|
1787
|
+
socket.send(JSON.stringify({
|
|
1788
|
+
kind: "subscribed",
|
|
1789
|
+
roomId: message.roomId
|
|
1790
|
+
}));
|
|
1791
|
+
return;
|
|
1792
|
+
}
|
|
1793
|
+
const roomIds = this.roomIdsByWorkflowClient.get(socket);
|
|
1794
|
+
if (!roomIds) return;
|
|
1795
|
+
if (roomIds.delete(message.roomId)) this.releaseWorkflowRoom(message.roomId);
|
|
1796
|
+
socket.send(JSON.stringify({
|
|
1797
|
+
kind: "unsubscribed",
|
|
1798
|
+
roomId: message.roomId
|
|
1799
|
+
}));
|
|
1800
|
+
} catch (error) {
|
|
1801
|
+
const exception = error instanceof Error ? error : new Error(String(error));
|
|
1802
|
+
if (socket.readyState === WebSocket.OPEN) socket.send(JSON.stringify({
|
|
1803
|
+
kind: "error",
|
|
1804
|
+
message: exception.message
|
|
1805
|
+
}));
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
parseWorkflowClientMessage(rawData) {
|
|
1809
|
+
const value = typeof rawData === "string" ? rawData : Buffer.isBuffer(rawData) ? rawData.toString("utf8") : "";
|
|
1810
|
+
const message = JSON.parse(value);
|
|
1811
|
+
if (message.kind === "subscribe" && typeof message.roomId === "string") return {
|
|
1812
|
+
kind: "subscribe",
|
|
1813
|
+
roomId: message.roomId
|
|
1814
|
+
};
|
|
1815
|
+
if (message.kind === "unsubscribe" && typeof message.roomId === "string") return {
|
|
1816
|
+
kind: "unsubscribe",
|
|
1817
|
+
roomId: message.roomId
|
|
1818
|
+
};
|
|
1819
|
+
throw new Error("Unsupported websocket client message.");
|
|
1820
|
+
}
|
|
1821
|
+
retainWorkflowRoom(roomId) {
|
|
1822
|
+
const nextCount = (this.workflowClientCountByRoomId.get(roomId) ?? 0) + 1;
|
|
1823
|
+
this.workflowClientCountByRoomId.set(roomId, nextCount);
|
|
1824
|
+
if (nextCount === 1) this.sendToChildWorkflowSocket({
|
|
1825
|
+
kind: "subscribe",
|
|
1826
|
+
roomId
|
|
1827
|
+
});
|
|
1828
|
+
}
|
|
1829
|
+
releaseWorkflowRoom(roomId) {
|
|
1830
|
+
const currentCount = this.workflowClientCountByRoomId.get(roomId) ?? 0;
|
|
1831
|
+
if (currentCount <= 1) {
|
|
1832
|
+
this.workflowClientCountByRoomId.delete(roomId);
|
|
1833
|
+
this.sendToChildWorkflowSocket({
|
|
1834
|
+
kind: "unsubscribe",
|
|
1835
|
+
roomId
|
|
1836
|
+
});
|
|
1837
|
+
return;
|
|
1838
|
+
}
|
|
1839
|
+
this.workflowClientCountByRoomId.set(roomId, currentCount - 1);
|
|
1840
|
+
}
|
|
1841
|
+
sendToChildWorkflowSocket(message) {
|
|
1842
|
+
if (!this.childWorkflowSocket || this.childWorkflowSocket.readyState !== WebSocket.OPEN) return;
|
|
1843
|
+
this.childWorkflowSocket.send(JSON.stringify(message));
|
|
1844
|
+
}
|
|
1845
|
+
async connectChildWorkflowSocket() {
|
|
1846
|
+
await this.disconnectChildWorkflowSocket();
|
|
1847
|
+
if (!this.activeRuntime || this.activeBuildStatus === "building") return;
|
|
1848
|
+
const childWorkflowSocket = await this.openChildWorkflowSocket(this.activeRuntime.workflowWebSocketPort);
|
|
1849
|
+
this.childWorkflowSocket = childWorkflowSocket;
|
|
1850
|
+
childWorkflowSocket.on("message", (rawData) => {
|
|
1851
|
+
this.handleChildWorkflowSocketMessage(rawData);
|
|
1852
|
+
});
|
|
1853
|
+
childWorkflowSocket.on("close", () => {
|
|
1854
|
+
if (this.childWorkflowSocket === childWorkflowSocket) this.childWorkflowSocket = null;
|
|
1855
|
+
});
|
|
1856
|
+
childWorkflowSocket.on("error", () => {
|
|
1857
|
+
if (this.childWorkflowSocket === childWorkflowSocket) this.childWorkflowSocket = null;
|
|
1858
|
+
});
|
|
1859
|
+
for (const roomId of this.workflowClientCountByRoomId.keys()) this.sendToChildWorkflowSocket({
|
|
1860
|
+
kind: "subscribe",
|
|
1861
|
+
roomId
|
|
1862
|
+
});
|
|
1863
|
+
}
|
|
1864
|
+
openChildWorkflowSocket(workflowWebSocketPort) {
|
|
1865
|
+
return new Promise((resolve, reject) => {
|
|
1866
|
+
const socket = new WebSocket(`ws://127.0.0.1:${workflowWebSocketPort}${ApiPaths.workflowWebsocket()}`);
|
|
1867
|
+
socket.once("open", () => {
|
|
1868
|
+
resolve(socket);
|
|
1869
|
+
});
|
|
1870
|
+
socket.once("error", (error) => {
|
|
1871
|
+
socket.close();
|
|
1872
|
+
reject(error);
|
|
1873
|
+
});
|
|
1874
|
+
});
|
|
1875
|
+
}
|
|
1876
|
+
async disconnectChildWorkflowSocket() {
|
|
1877
|
+
if (!this.childWorkflowSocket) return;
|
|
1878
|
+
const socket = this.childWorkflowSocket;
|
|
1879
|
+
this.childWorkflowSocket = null;
|
|
1880
|
+
await new Promise((resolve) => {
|
|
1881
|
+
socket.once("close", () => {
|
|
1882
|
+
resolve();
|
|
1883
|
+
});
|
|
1884
|
+
socket.close();
|
|
1885
|
+
});
|
|
1886
|
+
}
|
|
1887
|
+
handleChildWorkflowSocketMessage(rawData) {
|
|
1888
|
+
const text = typeof rawData === "string" ? rawData : Buffer.isBuffer(rawData) ? rawData.toString("utf8") : "";
|
|
1889
|
+
if (text.trim().length === 0) return;
|
|
1890
|
+
try {
|
|
1891
|
+
const message = JSON.parse(text);
|
|
1892
|
+
if (message.kind === "event" && typeof message.event?.workflowId === "string") {
|
|
1893
|
+
this.broadcastWorkflowTextToRoom(message.event.workflowId, text);
|
|
1894
|
+
return;
|
|
1895
|
+
}
|
|
1896
|
+
if ((message.kind === "workflowChanged" || message.kind === "devBuildStarted" || message.kind === "devBuildCompleted" || message.kind === "devBuildFailed") && typeof message.workflowId === "string") {
|
|
1897
|
+
this.broadcastWorkflowTextToRoom(message.workflowId, text);
|
|
1898
|
+
return;
|
|
1899
|
+
}
|
|
1900
|
+
if (message.kind === "error" && typeof message.message === "string") this.broadcastWorkflowTextToAll(text);
|
|
1901
|
+
} catch {}
|
|
1902
|
+
}
|
|
1903
|
+
broadcastWorkflowTextToRoom(roomId, text) {
|
|
1904
|
+
for (const [client, roomIds] of this.roomIdsByWorkflowClient) {
|
|
1905
|
+
if (client.readyState !== WebSocket.OPEN || !roomIds.has(roomId)) continue;
|
|
1906
|
+
client.send(text);
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1909
|
+
broadcastWorkflowTextToAll(text) {
|
|
1910
|
+
for (const client of this.workflowClients) if (client.readyState === WebSocket.OPEN) client.send(text);
|
|
1911
|
+
}
|
|
1912
|
+
};
|
|
1913
|
+
|
|
1914
|
+
//#endregion
|
|
1915
|
+
//#region src/dev/CliDevProxyServerFactory.ts
|
|
1916
|
+
var CliDevProxyServerFactory = class {
|
|
1917
|
+
create(gatewayPort) {
|
|
1918
|
+
return new CliDevProxyServer(gatewayPort);
|
|
1919
|
+
}
|
|
1920
|
+
};
|
|
1921
|
+
|
|
1922
|
+
//#endregion
|
|
1923
|
+
//#region ../host/src/presentation/server/CodemationTsyringeParamInfoReader.ts
|
|
1924
|
+
var CodemationTsyringeParamInfoReader = class {
|
|
1925
|
+
static injectionTokenMetadataKey = "injectionTokens";
|
|
1926
|
+
static designParamTypesMetadataKey = "design:paramtypes";
|
|
1927
|
+
static read(target) {
|
|
1928
|
+
const designParamTypes = this.readDesignParamTypes(target);
|
|
1929
|
+
const injectionTokens = this.readInjectionTokens(target);
|
|
1930
|
+
Object.keys(injectionTokens).forEach((key) => {
|
|
1931
|
+
designParamTypes[Number(key)] = injectionTokens[key];
|
|
1932
|
+
});
|
|
1933
|
+
return designParamTypes;
|
|
1934
|
+
}
|
|
1935
|
+
static readDesignParamTypes(target) {
|
|
1936
|
+
const reflected = Reflect.getMetadata?.(this.designParamTypesMetadataKey, target);
|
|
1937
|
+
return Array.isArray(reflected) ? [...reflected] : [];
|
|
1938
|
+
}
|
|
1939
|
+
static readInjectionTokens(target) {
|
|
1940
|
+
const reflected = Reflect.getOwnMetadata?.(this.injectionTokenMetadataKey, target);
|
|
1941
|
+
if (!reflected || typeof reflected !== "object") return {};
|
|
1942
|
+
return reflected;
|
|
1943
|
+
}
|
|
1944
|
+
};
|
|
1945
|
+
|
|
1946
|
+
//#endregion
|
|
1947
|
+
//#region ../host/src/presentation/server/CodemationTsyringeTypeInfoRegistrar.ts
|
|
1948
|
+
var CodemationTsyringeTypeInfoRegistrar = class {
|
|
1949
|
+
visitedTokens = /* @__PURE__ */ new Set();
|
|
1950
|
+
visitedConfigObjects = /* @__PURE__ */ new Set();
|
|
1951
|
+
constructor(container) {
|
|
1952
|
+
this.container = container;
|
|
1953
|
+
}
|
|
1954
|
+
registerWorkflowDefinitions(workflows) {
|
|
1955
|
+
for (const workflow of workflows) for (const node of workflow.nodes) {
|
|
1956
|
+
this.registerTypeToken(node.type);
|
|
1957
|
+
this.registerConfigTokens(node.config);
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
registerTypeToken(token) {
|
|
1961
|
+
if (typeof token !== "function" || this.visitedTokens.has(token)) return;
|
|
1962
|
+
this.visitedTokens.add(token);
|
|
1963
|
+
const paramInfo = CodemationTsyringeParamInfoReader.read(token);
|
|
1964
|
+
for (const dependency of paramInfo) this.registerDependency(dependency);
|
|
1965
|
+
this.registerFactoryProvider(token, paramInfo);
|
|
1966
|
+
}
|
|
1967
|
+
registerDependency(dependency) {
|
|
1968
|
+
const token = this.resolveDependencyToken(dependency);
|
|
1969
|
+
if (typeof token !== "function") return;
|
|
1970
|
+
if (!this.container.isRegistered(token, true)) return;
|
|
1971
|
+
this.registerTypeToken(token);
|
|
1972
|
+
}
|
|
1973
|
+
registerConfigTokens(value) {
|
|
1974
|
+
if (Array.isArray(value)) {
|
|
1975
|
+
value.forEach((entry) => this.registerConfigTokens(entry));
|
|
1976
|
+
return;
|
|
1977
|
+
}
|
|
1978
|
+
if (!value || typeof value !== "object") return;
|
|
1979
|
+
if (this.visitedConfigObjects.has(value)) return;
|
|
1980
|
+
this.visitedConfigObjects.add(value);
|
|
1981
|
+
if ("type" in value && typeof value.type === "function") this.registerTypeToken(value.type);
|
|
1982
|
+
Object.values(value).forEach((entry) => this.registerConfigTokens(entry));
|
|
1983
|
+
}
|
|
1984
|
+
registerFactoryProvider(token, paramInfo) {
|
|
1985
|
+
if (this.container.isRegistered(token, true)) return;
|
|
1986
|
+
const classToken = token;
|
|
1987
|
+
const constructorToken = token;
|
|
1988
|
+
this.container.register(classToken, { useFactory: (dependencyContainer) => {
|
|
1989
|
+
return new constructorToken(...paramInfo.map((dependency) => this.resolveFactoryDependency(dependencyContainer, dependency)));
|
|
1990
|
+
} });
|
|
1991
|
+
}
|
|
1992
|
+
resolveDependencyToken(dependency) {
|
|
1993
|
+
if (this.isInjectionDescriptor(dependency)) return dependency.token;
|
|
1994
|
+
return dependency;
|
|
1995
|
+
}
|
|
1996
|
+
resolveFactoryDependency(dependencyContainer, dependency) {
|
|
1997
|
+
const token = this.resolveDependencyToken(dependency);
|
|
1998
|
+
if (typeof token === "function") {
|
|
1999
|
+
if (dependencyContainer.isRegistered(token, true)) try {
|
|
2000
|
+
return dependencyContainer.resolve(token);
|
|
2001
|
+
} catch (error) {
|
|
2002
|
+
if (!this.isMissingTypeInfoError(error)) throw error;
|
|
2003
|
+
}
|
|
2004
|
+
this.registerTypeToken(token);
|
|
2005
|
+
return new token(...CodemationTsyringeParamInfoReader.read(token).map((entry) => this.resolveFactoryDependency(dependencyContainer, entry)));
|
|
2006
|
+
}
|
|
2007
|
+
return dependencyContainer.resolve(token);
|
|
2008
|
+
}
|
|
2009
|
+
isInjectionDescriptor(value) {
|
|
2010
|
+
return value !== null && typeof value === "object" && "token" in value;
|
|
2011
|
+
}
|
|
2012
|
+
isMissingTypeInfoError(error) {
|
|
2013
|
+
return error instanceof Error && error.message.includes("TypeInfo not known for");
|
|
2014
|
+
}
|
|
2015
|
+
};
|
|
2016
|
+
|
|
2017
|
+
//#endregion
|
|
2018
|
+
//#region src/dev/DevApiRuntimeHost.ts
|
|
2019
|
+
var DevApiRuntimeHost = class {
|
|
2020
|
+
pluginListMerger = new CodemationPluginListMerger();
|
|
2021
|
+
contextPromise = null;
|
|
2022
|
+
constructor(configLoader, pluginDiscovery, args) {
|
|
2023
|
+
this.configLoader = configLoader;
|
|
2024
|
+
this.pluginDiscovery = pluginDiscovery;
|
|
2025
|
+
this.args = args;
|
|
2026
|
+
}
|
|
2027
|
+
async prepare() {
|
|
2028
|
+
if (!this.contextPromise) this.contextPromise = this.createContext();
|
|
2029
|
+
return await this.contextPromise;
|
|
2030
|
+
}
|
|
2031
|
+
async stop() {
|
|
2032
|
+
const contextPromise = this.contextPromise;
|
|
2033
|
+
this.contextPromise = null;
|
|
2034
|
+
if (!contextPromise) return;
|
|
2035
|
+
await (await contextPromise).container.resolve(AppContainerLifecycle$1).stop();
|
|
2036
|
+
}
|
|
2037
|
+
async createContext() {
|
|
2038
|
+
const consumerRoot = path.resolve(this.args.consumerRoot);
|
|
2039
|
+
const repoRoot = await this.detectWorkspaceRoot(consumerRoot);
|
|
2040
|
+
const prismaCliOverride = await this.resolvePrismaCliOverride();
|
|
2041
|
+
const hostPackageRoot = path.resolve(repoRoot, "packages", "host");
|
|
2042
|
+
const env = { ...this.args.env };
|
|
2043
|
+
if (prismaCliOverride) env.CODEMATION_PRISMA_CLI_PATH = prismaCliOverride;
|
|
2044
|
+
env.CODEMATION_HOST_PACKAGE_ROOT = hostPackageRoot;
|
|
2045
|
+
env.CODEMATION_PRISMA_CONFIG_PATH = path.resolve(hostPackageRoot, "prisma.config.ts");
|
|
2046
|
+
env.CODEMATION_CONSUMER_ROOT = consumerRoot;
|
|
2047
|
+
const configResolution = await this.configLoader.load({
|
|
2048
|
+
consumerRoot,
|
|
2049
|
+
repoRoot,
|
|
2050
|
+
env
|
|
2051
|
+
});
|
|
2052
|
+
const discoveredPlugins = await this.loadDiscoveredPlugins(consumerRoot);
|
|
2053
|
+
const appConfig = {
|
|
2054
|
+
...configResolution.appConfig,
|
|
2055
|
+
env,
|
|
2056
|
+
plugins: discoveredPlugins.length > 0 ? this.pluginListMerger.merge(configResolution.appConfig.plugins, discoveredPlugins) : configResolution.appConfig.plugins
|
|
2057
|
+
};
|
|
2058
|
+
const container = await new AppContainerFactory$1().create({
|
|
2059
|
+
appConfig,
|
|
2060
|
+
sharedWorkflowWebsocketServer: null
|
|
2061
|
+
});
|
|
2062
|
+
new CodemationTsyringeTypeInfoRegistrar(container).registerWorkflowDefinitions(appConfig.workflows ?? []);
|
|
2063
|
+
await container.resolve(FrontendRuntime).start();
|
|
2064
|
+
return {
|
|
2065
|
+
buildVersion: this.createBuildVersion(),
|
|
2066
|
+
container,
|
|
2067
|
+
consumerRoot,
|
|
2068
|
+
repoRoot,
|
|
2069
|
+
workflowIds: appConfig.workflows.map((workflow) => workflow.id),
|
|
2070
|
+
workflowSources: appConfig.workflowSources
|
|
2071
|
+
};
|
|
2072
|
+
}
|
|
2073
|
+
async loadDiscoveredPlugins(consumerRoot) {
|
|
2074
|
+
return (await this.pluginDiscovery.resolvePlugins(consumerRoot)).map((resolvedPackage) => resolvedPackage.plugin);
|
|
2075
|
+
}
|
|
2076
|
+
async detectWorkspaceRoot(startDirectory) {
|
|
2077
|
+
let currentDirectory = path.resolve(startDirectory);
|
|
2078
|
+
while (true) {
|
|
2079
|
+
if (await this.exists(path.resolve(currentDirectory, "pnpm-workspace.yaml"))) return currentDirectory;
|
|
2080
|
+
const parentDirectory = path.dirname(currentDirectory);
|
|
2081
|
+
if (parentDirectory === currentDirectory) return startDirectory;
|
|
2082
|
+
currentDirectory = parentDirectory;
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
async resolvePrismaCliOverride() {
|
|
2086
|
+
const candidate = path.resolve(this.args.runtimeWorkingDirectory, "node_modules", "prisma", "build", "index.js");
|
|
2087
|
+
return await this.exists(candidate) ? candidate : null;
|
|
2088
|
+
}
|
|
2089
|
+
createBuildVersion() {
|
|
2090
|
+
return `${Date.now()}-${process$1.pid}`;
|
|
2091
|
+
}
|
|
2092
|
+
async exists(filePath) {
|
|
2093
|
+
try {
|
|
2094
|
+
await access(filePath);
|
|
2095
|
+
return true;
|
|
2096
|
+
} catch {
|
|
2097
|
+
return false;
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
};
|
|
2101
|
+
|
|
2102
|
+
//#endregion
|
|
2103
|
+
//#region src/dev/DevApiRuntimeServer.ts
|
|
2104
|
+
var DevApiRuntimeServer = class {
|
|
2105
|
+
bootstrapLogger = new ServerLoggerFactory(logLevelPolicyFactory).create("codemation-cli.dev-runtime");
|
|
2106
|
+
server = null;
|
|
2107
|
+
constructor(httpPort, workflowWebSocketPort, host) {
|
|
2108
|
+
this.httpPort = httpPort;
|
|
2109
|
+
this.workflowWebSocketPort = workflowWebSocketPort;
|
|
2110
|
+
this.host = host;
|
|
2111
|
+
}
|
|
2112
|
+
async start() {
|
|
2113
|
+
const root = new Hono();
|
|
2114
|
+
root.get("/health", (c) => c.json({ ok: true }));
|
|
2115
|
+
root.all("*", async (c) => {
|
|
2116
|
+
return (await this.host.prepare()).container.resolve(CodemationHonoApiApp).fetch(c.req.raw);
|
|
2117
|
+
});
|
|
2118
|
+
await this.listen(root);
|
|
2119
|
+
try {
|
|
2120
|
+
return await this.host.prepare();
|
|
2121
|
+
} catch (error) {
|
|
2122
|
+
await this.stop();
|
|
2123
|
+
throw error;
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
async stop() {
|
|
2127
|
+
const server = this.server;
|
|
2128
|
+
this.server = null;
|
|
2129
|
+
const failures = [];
|
|
2130
|
+
if (server) try {
|
|
2131
|
+
await this.closeServer(server);
|
|
2132
|
+
} catch (error) {
|
|
2133
|
+
failures.push(this.normalizeError(error));
|
|
2134
|
+
}
|
|
2135
|
+
try {
|
|
2136
|
+
await this.host.stop();
|
|
2137
|
+
} catch (error) {
|
|
2138
|
+
failures.push(this.normalizeError(error));
|
|
2139
|
+
}
|
|
2140
|
+
if (failures.length > 0) throw failures[0];
|
|
2141
|
+
}
|
|
2142
|
+
async listen(root) {
|
|
2143
|
+
if (this.server) return;
|
|
2144
|
+
await new Promise((resolve, reject) => {
|
|
2145
|
+
let resolved = false;
|
|
2146
|
+
const server = serve({
|
|
2147
|
+
fetch: root.fetch,
|
|
2148
|
+
port: this.httpPort,
|
|
2149
|
+
hostname: "127.0.0.1"
|
|
2150
|
+
}, () => {
|
|
2151
|
+
resolved = true;
|
|
2152
|
+
this.server = server;
|
|
2153
|
+
resolve();
|
|
2154
|
+
});
|
|
2155
|
+
server.on("error", (error) => {
|
|
2156
|
+
if (resolved) {
|
|
2157
|
+
this.bootstrapLogger.error("runtime HTTP server error", this.normalizeError(error));
|
|
2158
|
+
return;
|
|
2159
|
+
}
|
|
2160
|
+
reject(error);
|
|
2161
|
+
});
|
|
2162
|
+
});
|
|
2163
|
+
this.bootstrapLogger.debug(`runtime listening httpPort=${this.httpPort} workflowWebSocketPort=${this.workflowWebSocketPort}`);
|
|
2164
|
+
}
|
|
2165
|
+
closeServer(server) {
|
|
2166
|
+
return new Promise((resolve, reject) => {
|
|
2167
|
+
server.close((error) => {
|
|
2168
|
+
if (error) {
|
|
2169
|
+
reject(error);
|
|
2170
|
+
return;
|
|
2171
|
+
}
|
|
2172
|
+
resolve();
|
|
2173
|
+
});
|
|
2174
|
+
});
|
|
2175
|
+
}
|
|
2176
|
+
normalizeError(error) {
|
|
2177
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
2178
|
+
}
|
|
2179
|
+
};
|
|
2180
|
+
|
|
2181
|
+
//#endregion
|
|
2182
|
+
//#region src/dev/DevApiRuntimeFactory.ts
|
|
2183
|
+
var DevApiRuntimeFactory = class {
|
|
2184
|
+
constructor(portAllocator, configLoader, pluginDiscovery) {
|
|
2185
|
+
this.portAllocator = portAllocator;
|
|
2186
|
+
this.configLoader = configLoader;
|
|
2187
|
+
this.pluginDiscovery = pluginDiscovery;
|
|
2188
|
+
}
|
|
2189
|
+
async create(args) {
|
|
2190
|
+
const httpPort = await this.portAllocator.allocate();
|
|
2191
|
+
const workflowWebSocketPort = await this.portAllocator.allocate();
|
|
2192
|
+
const runtime = new DevApiRuntimeServer(httpPort, workflowWebSocketPort, new DevApiRuntimeHost(this.configLoader, this.pluginDiscovery, {
|
|
2193
|
+
consumerRoot: args.consumerRoot,
|
|
2194
|
+
env: {
|
|
2195
|
+
...args.env,
|
|
2196
|
+
CODEMATION_WS_PORT: String(workflowWebSocketPort),
|
|
2197
|
+
NEXT_PUBLIC_CODEMATION_WS_PORT: String(workflowWebSocketPort)
|
|
2198
|
+
},
|
|
2199
|
+
runtimeWorkingDirectory: args.runtimeWorkingDirectory
|
|
2200
|
+
}));
|
|
2201
|
+
const context = await runtime.start();
|
|
2202
|
+
return {
|
|
2203
|
+
buildVersion: context.buildVersion,
|
|
2204
|
+
httpPort,
|
|
2205
|
+
stop: async () => {
|
|
2206
|
+
await runtime.stop();
|
|
2207
|
+
},
|
|
2208
|
+
workflowIds: context.workflowIds,
|
|
2209
|
+
workflowWebSocketPort
|
|
2210
|
+
};
|
|
2211
|
+
}
|
|
2212
|
+
};
|
|
2213
|
+
|
|
2214
|
+
//#endregion
|
|
2215
|
+
//#region src/dev/DevRebuildQueue.ts
|
|
2216
|
+
var DevRebuildQueue = class {
|
|
2217
|
+
pendingRequest = null;
|
|
2218
|
+
drainPromise = null;
|
|
2219
|
+
constructor(handler) {
|
|
2220
|
+
this.handler = handler;
|
|
2221
|
+
}
|
|
2222
|
+
async enqueue(request) {
|
|
2223
|
+
this.pendingRequest = this.mergePendingRequest(this.pendingRequest, request);
|
|
2224
|
+
if (!this.drainPromise) this.drainPromise = this.drain();
|
|
2225
|
+
return await this.drainPromise;
|
|
2226
|
+
}
|
|
2227
|
+
async drain() {
|
|
2228
|
+
try {
|
|
2229
|
+
while (this.pendingRequest) {
|
|
2230
|
+
const nextRequest = this.pendingRequest;
|
|
2231
|
+
this.pendingRequest = null;
|
|
2232
|
+
await this.handler.run(nextRequest);
|
|
2233
|
+
}
|
|
2234
|
+
} finally {
|
|
2235
|
+
this.drainPromise = null;
|
|
2236
|
+
if (this.pendingRequest) {
|
|
2237
|
+
this.drainPromise = this.drain();
|
|
2238
|
+
await this.drainPromise;
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
mergePendingRequest(current, next) {
|
|
2243
|
+
if (!current) return {
|
|
2244
|
+
...next,
|
|
2245
|
+
changedPaths: [...next.changedPaths]
|
|
2246
|
+
};
|
|
2247
|
+
return {
|
|
2248
|
+
changedPaths: [...new Set([...current.changedPaths, ...next.changedPaths])],
|
|
2249
|
+
shouldRepublishConsumerOutput: current.shouldRepublishConsumerOutput || next.shouldRepublishConsumerOutput,
|
|
2250
|
+
shouldRestartUi: current.shouldRestartUi || next.shouldRestartUi
|
|
2251
|
+
};
|
|
2252
|
+
}
|
|
2253
|
+
};
|
|
2254
|
+
|
|
2255
|
+
//#endregion
|
|
2256
|
+
//#region src/dev/DevRebuildQueueFactory.ts
|
|
2257
|
+
var DevRebuildQueueFactory = class {
|
|
2258
|
+
create(handler) {
|
|
2259
|
+
return new DevRebuildQueue(handler);
|
|
2260
|
+
}
|
|
2261
|
+
};
|
|
2262
|
+
|
|
1445
2263
|
//#endregion
|
|
1446
2264
|
//#region src/runtime/ListenPortResolver.ts
|
|
1447
2265
|
/**
|
|
@@ -1476,36 +2294,13 @@ var SourceMapNodeOptions = class {
|
|
|
1476
2294
|
}
|
|
1477
2295
|
};
|
|
1478
2296
|
|
|
1479
|
-
//#endregion
|
|
1480
|
-
//#region src/dev/DevelopmentGatewayNotifier.ts
|
|
1481
|
-
var DevelopmentGatewayNotifier = class {
|
|
1482
|
-
constructor(cliLogger) {
|
|
1483
|
-
this.cliLogger = cliLogger;
|
|
1484
|
-
}
|
|
1485
|
-
async notify(args) {
|
|
1486
|
-
const targetUrl = `${args.gatewayBaseUrl.replace(/\/$/, "")}${ApiPaths.devGatewayNotify()}`;
|
|
1487
|
-
try {
|
|
1488
|
-
const response = await fetch(targetUrl, {
|
|
1489
|
-
method: "POST",
|
|
1490
|
-
headers: {
|
|
1491
|
-
"content-type": "application/json",
|
|
1492
|
-
"x-codemation-dev-token": args.developmentServerToken
|
|
1493
|
-
},
|
|
1494
|
-
body: JSON.stringify(args.payload)
|
|
1495
|
-
});
|
|
1496
|
-
if (!response.ok) this.cliLogger.warn(`failed to notify dev gateway status=${response.status}`);
|
|
1497
|
-
} catch (error) {
|
|
1498
|
-
this.cliLogger.warn(`failed to notify dev gateway: ${error instanceof Error ? error.message : String(error)}`);
|
|
1499
|
-
}
|
|
1500
|
-
}
|
|
1501
|
-
};
|
|
1502
|
-
|
|
1503
2297
|
//#endregion
|
|
1504
2298
|
//#region src/dev/DevAuthSettingsLoader.ts
|
|
1505
2299
|
var DevAuthSettingsLoader = class DevAuthSettingsLoader {
|
|
1506
2300
|
static defaultDevelopmentAuthSecret = "codemation-dev-auth-secret-not-for-production";
|
|
1507
|
-
constructor(configLoader) {
|
|
2301
|
+
constructor(configLoader, consumerEnvLoader) {
|
|
1508
2302
|
this.configLoader = configLoader;
|
|
2303
|
+
this.consumerEnvLoader = consumerEnvLoader;
|
|
1509
2304
|
}
|
|
1510
2305
|
resolveDevelopmentServerToken(rawToken) {
|
|
1511
2306
|
if (rawToken && rawToken.trim().length > 0) return rawToken;
|
|
@@ -1513,14 +2308,15 @@ var DevAuthSettingsLoader = class DevAuthSettingsLoader {
|
|
|
1513
2308
|
}
|
|
1514
2309
|
async loadForConsumer(consumerRoot) {
|
|
1515
2310
|
const resolution = await this.configLoader.load({ consumerRoot });
|
|
2311
|
+
const envForAuthSecret = this.consumerEnvLoader.mergeConsumerRootIntoProcessEnvironment(consumerRoot, process.env);
|
|
1516
2312
|
return {
|
|
1517
2313
|
authConfigJson: JSON.stringify(resolution.config.auth ?? null),
|
|
1518
|
-
authSecret: this.resolveDevelopmentAuthSecret(
|
|
2314
|
+
authSecret: this.resolveDevelopmentAuthSecret(envForAuthSecret),
|
|
1519
2315
|
skipUiAuth: resolution.config.auth?.allowUnauthenticatedInDevelopment === true
|
|
1520
2316
|
};
|
|
1521
2317
|
}
|
|
1522
2318
|
resolveDevelopmentAuthSecret(env) {
|
|
1523
|
-
const configuredSecret = env.AUTH_SECRET
|
|
2319
|
+
const configuredSecret = env.AUTH_SECRET;
|
|
1524
2320
|
if (configuredSecret && configuredSecret.trim().length > 0) return configuredSecret;
|
|
1525
2321
|
return DevAuthSettingsLoader.defaultDevelopmentAuthSecret;
|
|
1526
2322
|
}
|
|
@@ -1532,8 +2328,8 @@ var DevHttpProbe = class {
|
|
|
1532
2328
|
async waitUntilUrlRespondsOk(url) {
|
|
1533
2329
|
for (let attempt = 0; attempt < 200; attempt += 1) {
|
|
1534
2330
|
try {
|
|
1535
|
-
const response = await fetch(url);
|
|
1536
|
-
if (response.ok || response.status === 404) return;
|
|
2331
|
+
const response = await fetch(url, { redirect: "manual" });
|
|
2332
|
+
if (response.ok || response.status === 404 || this.isRedirectStatus(response.status)) return;
|
|
1537
2333
|
} catch {}
|
|
1538
2334
|
await setTimeout$1(50);
|
|
1539
2335
|
}
|
|
@@ -1547,10 +2343,10 @@ var DevHttpProbe = class {
|
|
|
1547
2343
|
} catch {}
|
|
1548
2344
|
await setTimeout$1(50);
|
|
1549
2345
|
}
|
|
1550
|
-
throw new Error("Timed out waiting for dev
|
|
2346
|
+
throw new Error("Timed out waiting for the stable dev HTTP health check.");
|
|
1551
2347
|
}
|
|
1552
2348
|
/**
|
|
1553
|
-
* Polls until the runtime
|
|
2349
|
+
* Polls until the active disposable runtime serves bootstrap summary through the stable CLI dev endpoint.
|
|
1554
2350
|
*/
|
|
1555
2351
|
async waitUntilBootstrapSummaryReady(gatewayBaseUrl) {
|
|
1556
2352
|
const url = `${gatewayBaseUrl.replace(/\/$/, "")}/api/dev/bootstrap-summary`;
|
|
@@ -1562,26 +2358,60 @@ var DevHttpProbe = class {
|
|
|
1562
2358
|
}
|
|
1563
2359
|
throw new Error("Timed out waiting for dev runtime bootstrap summary.");
|
|
1564
2360
|
}
|
|
2361
|
+
isRedirectStatus(status) {
|
|
2362
|
+
return status >= 300 && status < 400;
|
|
2363
|
+
}
|
|
1565
2364
|
};
|
|
1566
2365
|
|
|
1567
2366
|
//#endregion
|
|
1568
2367
|
//#region src/dev/DevNextHostEnvironmentBuilder.ts
|
|
1569
2368
|
var DevNextHostEnvironmentBuilder = class {
|
|
1570
|
-
constructor(consumerEnvLoader, sourceMapNodeOptions) {
|
|
2369
|
+
constructor(consumerEnvLoader, sourceMapNodeOptions, frontendAuthSnapshotFactory = new CodemationFrontendAuthSnapshotFactory$1(), frontendAppConfigJsonCodec = new FrontendAppConfigJsonCodec$1()) {
|
|
1571
2370
|
this.consumerEnvLoader = consumerEnvLoader;
|
|
1572
2371
|
this.sourceMapNodeOptions = sourceMapNodeOptions;
|
|
2372
|
+
this.frontendAuthSnapshotFactory = frontendAuthSnapshotFactory;
|
|
2373
|
+
this.frontendAppConfigJsonCodec = frontendAppConfigJsonCodec;
|
|
2374
|
+
}
|
|
2375
|
+
buildConsumerUiProxy(args) {
|
|
2376
|
+
return {
|
|
2377
|
+
...this.build({
|
|
2378
|
+
authConfigJson: args.authConfigJson,
|
|
2379
|
+
authSecret: args.authSecret,
|
|
2380
|
+
consumerRoot: args.consumerRoot,
|
|
2381
|
+
developmentServerToken: args.developmentServerToken,
|
|
2382
|
+
nextPort: args.nextPort,
|
|
2383
|
+
runtimeDevUrl: args.runtimeDevUrl,
|
|
2384
|
+
skipUiAuth: args.skipUiAuth,
|
|
2385
|
+
websocketPort: args.websocketPort,
|
|
2386
|
+
consumerOutputManifestPath: args.consumerOutputManifestPath
|
|
2387
|
+
}),
|
|
2388
|
+
HOSTNAME: "127.0.0.1",
|
|
2389
|
+
AUTH_SECRET: args.authSecret,
|
|
2390
|
+
AUTH_URL: args.publicBaseUrl
|
|
2391
|
+
};
|
|
1573
2392
|
}
|
|
1574
2393
|
build(args) {
|
|
1575
2394
|
const merged = this.consumerEnvLoader.mergeConsumerRootIntoProcessEnvironment(args.consumerRoot, process$1.env);
|
|
1576
2395
|
const manifestPath = args.consumerOutputManifestPath ?? path.resolve(args.consumerRoot, ".codemation", "output", "current.json");
|
|
2396
|
+
const authSecret = args.authSecret ?? merged.AUTH_SECRET;
|
|
2397
|
+
const authSnapshot = this.frontendAuthSnapshotFactory.createFromResolvedInputs({
|
|
2398
|
+
authConfig: this.parseAuthConfig(args.authConfigJson),
|
|
2399
|
+
env: {
|
|
2400
|
+
...merged,
|
|
2401
|
+
...typeof authSecret === "string" && authSecret.trim().length > 0 ? { AUTH_SECRET: authSecret } : {}
|
|
2402
|
+
},
|
|
2403
|
+
uiAuthEnabled: !args.skipUiAuth
|
|
2404
|
+
});
|
|
1577
2405
|
return {
|
|
1578
2406
|
...merged,
|
|
1579
2407
|
PORT: String(args.nextPort),
|
|
1580
|
-
CODEMATION_AUTH_CONFIG_JSON: args.authConfigJson,
|
|
1581
2408
|
CODEMATION_CONSUMER_ROOT: args.consumerRoot,
|
|
1582
2409
|
CODEMATION_CONSUMER_OUTPUT_MANIFEST_PATH: manifestPath,
|
|
1583
|
-
|
|
1584
|
-
|
|
2410
|
+
CODEMATION_FRONTEND_APP_CONFIG_JSON: this.frontendAppConfigJsonCodec.serialize({
|
|
2411
|
+
auth: authSnapshot,
|
|
2412
|
+
productName: "Codemation",
|
|
2413
|
+
logoUrl: null
|
|
2414
|
+
}),
|
|
1585
2415
|
CODEMATION_WS_PORT: String(args.websocketPort),
|
|
1586
2416
|
NEXT_PUBLIC_CODEMATION_WS_PORT: String(args.websocketPort),
|
|
1587
2417
|
CODEMATION_DEV_SERVER_TOKEN: args.developmentServerToken,
|
|
@@ -1592,6 +2422,10 @@ var DevNextHostEnvironmentBuilder = class {
|
|
|
1592
2422
|
...args.runtimeDevUrl !== void 0 && args.runtimeDevUrl.trim().length > 0 ? { CODEMATION_RUNTIME_DEV_URL: args.runtimeDevUrl.trim() } : {}
|
|
1593
2423
|
};
|
|
1594
2424
|
}
|
|
2425
|
+
parseAuthConfig(authConfigJson) {
|
|
2426
|
+
if (authConfigJson.trim().length === 0) return;
|
|
2427
|
+
return JSON.parse(authConfigJson) ?? void 0;
|
|
2428
|
+
}
|
|
1595
2429
|
};
|
|
1596
2430
|
|
|
1597
2431
|
//#endregion
|
|
@@ -1605,7 +2439,7 @@ var DevSessionPortsResolver = class {
|
|
|
1605
2439
|
const nextPort = this.listenPorts.resolvePrimaryApplicationPort(args.portEnv);
|
|
1606
2440
|
return {
|
|
1607
2441
|
nextPort,
|
|
1608
|
-
gatewayPort: this.listenPorts.parsePositiveInteger(args.gatewayPortEnv) ?? (args.devMode === "
|
|
2442
|
+
gatewayPort: this.listenPorts.parsePositiveInteger(args.gatewayPortEnv) ?? (args.devMode === "packaged-ui" ? nextPort : await this.loopbackPorts.allocate())
|
|
1609
2443
|
};
|
|
1610
2444
|
}
|
|
1611
2445
|
};
|
|
@@ -1616,58 +2450,48 @@ var DevSessionPortsResolver = class {
|
|
|
1616
2450
|
* Bundles dependencies for {@link DevCommand} so the command stays a thin orchestrator.
|
|
1617
2451
|
*/
|
|
1618
2452
|
var DevSessionServices = class {
|
|
1619
|
-
constructor(consumerEnvLoader, sourceMapNodeOptions, sessionPorts, loopbackPortAllocator, devHttpProbe,
|
|
2453
|
+
constructor(consumerEnvLoader, sourceMapNodeOptions, sessionPorts, loopbackPortAllocator, devHttpProbe, devAuthLoader, nextHostEnvBuilder, watchRootsResolver, sourceChangeClassifier) {
|
|
1620
2454
|
this.consumerEnvLoader = consumerEnvLoader;
|
|
1621
2455
|
this.sourceMapNodeOptions = sourceMapNodeOptions;
|
|
1622
2456
|
this.sessionPorts = sessionPorts;
|
|
1623
2457
|
this.loopbackPortAllocator = loopbackPortAllocator;
|
|
1624
2458
|
this.devHttpProbe = devHttpProbe;
|
|
1625
|
-
this.runtimeEntrypointResolver = runtimeEntrypointResolver;
|
|
1626
2459
|
this.devAuthLoader = devAuthLoader;
|
|
1627
2460
|
this.nextHostEnvBuilder = nextHostEnvBuilder;
|
|
1628
2461
|
this.watchRootsResolver = watchRootsResolver;
|
|
1629
|
-
this.
|
|
2462
|
+
this.sourceChangeClassifier = sourceChangeClassifier;
|
|
1630
2463
|
}
|
|
1631
2464
|
};
|
|
1632
2465
|
|
|
1633
2466
|
//#endregion
|
|
1634
|
-
//#region src/dev/
|
|
1635
|
-
var
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
const
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
gatewayBaseUrl,
|
|
1663
|
-
developmentServerToken,
|
|
1664
|
-
payload: {
|
|
1665
|
-
kind: "buildFailed",
|
|
1666
|
-
message: exception.message
|
|
1667
|
-
}
|
|
1668
|
-
});
|
|
1669
|
-
this.cliLogger.error("source-based runtime restart request failed", exception);
|
|
1670
|
-
}
|
|
2467
|
+
//#region src/dev/DevSourceChangeClassifier.ts
|
|
2468
|
+
var DevSourceChangeClassifier = class DevSourceChangeClassifier {
|
|
2469
|
+
static configFileNames = new Set([
|
|
2470
|
+
"codemation.config.ts",
|
|
2471
|
+
"codemation.config.js",
|
|
2472
|
+
"codemation.config.mjs"
|
|
2473
|
+
]);
|
|
2474
|
+
shouldRepublishConsumerOutput(args) {
|
|
2475
|
+
const resolvedConsumerRoot = path.resolve(args.consumerRoot);
|
|
2476
|
+
return args.changedPaths.some((changedPath) => this.isPathInsideDirectory(changedPath, resolvedConsumerRoot));
|
|
2477
|
+
}
|
|
2478
|
+
requiresUiRestart(args) {
|
|
2479
|
+
const resolvedConsumerRoot = path.resolve(args.consumerRoot);
|
|
2480
|
+
return args.changedPaths.some((changedPath) => this.pathRequiresUiRestart(path.resolve(changedPath), resolvedConsumerRoot));
|
|
2481
|
+
}
|
|
2482
|
+
isPathInsideDirectory(filePath, directoryPath) {
|
|
2483
|
+
const resolvedFilePath = path.resolve(filePath);
|
|
2484
|
+
const relativePath = path.relative(directoryPath, resolvedFilePath);
|
|
2485
|
+
return relativePath.length === 0 || !relativePath.startsWith("..") && !path.isAbsolute(relativePath);
|
|
2486
|
+
}
|
|
2487
|
+
pathRequiresUiRestart(resolvedPath, consumerRoot) {
|
|
2488
|
+
if (!this.isPathInsideDirectory(resolvedPath, consumerRoot)) return false;
|
|
2489
|
+
const relativePath = path.relative(consumerRoot, resolvedPath);
|
|
2490
|
+
if (DevSourceChangeClassifier.configFileNames.has(path.basename(relativePath))) return true;
|
|
2491
|
+
if (relativePath.startsWith(path.join("src", "workflows"))) return false;
|
|
2492
|
+
if (relativePath.startsWith(path.join("src", "plugins"))) return false;
|
|
2493
|
+
if (relativePath.includes("credential")) return true;
|
|
2494
|
+
return false;
|
|
1671
2495
|
}
|
|
1672
2496
|
};
|
|
1673
2497
|
|
|
@@ -1676,7 +2500,7 @@ var DevSourceRestartCoordinator = class {
|
|
|
1676
2500
|
var LoopbackPortAllocator = class {
|
|
1677
2501
|
async allocate() {
|
|
1678
2502
|
return await new Promise((resolve, reject) => {
|
|
1679
|
-
const server = createServer();
|
|
2503
|
+
const server = createServer$1();
|
|
1680
2504
|
server.once("error", reject);
|
|
1681
2505
|
server.listen(0, "127.0.0.1", () => {
|
|
1682
2506
|
const address = server.address();
|
|
@@ -1692,52 +2516,20 @@ var LoopbackPortAllocator = class {
|
|
|
1692
2516
|
}
|
|
1693
2517
|
};
|
|
1694
2518
|
|
|
1695
|
-
//#endregion
|
|
1696
|
-
//#region src/dev/RuntimeToolEntrypointResolver.ts
|
|
1697
|
-
var RuntimeToolEntrypointResolver = class {
|
|
1698
|
-
require = createRequire(import.meta.url);
|
|
1699
|
-
async resolve(args) {
|
|
1700
|
-
const sourceEntrypointPath = path.resolve(args.repoRoot, args.sourceEntrypoint);
|
|
1701
|
-
if (await this.exists(sourceEntrypointPath)) return {
|
|
1702
|
-
command: process$1.execPath,
|
|
1703
|
-
args: [
|
|
1704
|
-
"--import",
|
|
1705
|
-
"tsx",
|
|
1706
|
-
sourceEntrypointPath
|
|
1707
|
-
],
|
|
1708
|
-
env: { TSX_TSCONFIG_PATH: path.resolve(args.repoRoot, "tsconfig.codemation-tsx.json") }
|
|
1709
|
-
};
|
|
1710
|
-
return {
|
|
1711
|
-
command: process$1.execPath,
|
|
1712
|
-
args: [this.require.resolve(args.packageName)],
|
|
1713
|
-
env: {}
|
|
1714
|
-
};
|
|
1715
|
-
}
|
|
1716
|
-
async exists(filePath) {
|
|
1717
|
-
try {
|
|
1718
|
-
await access(filePath);
|
|
1719
|
-
return true;
|
|
1720
|
-
} catch {
|
|
1721
|
-
return false;
|
|
1722
|
-
}
|
|
1723
|
-
}
|
|
1724
|
-
};
|
|
1725
|
-
|
|
1726
2519
|
//#endregion
|
|
1727
2520
|
//#region src/dev/WatchRootsResolver.ts
|
|
1728
2521
|
var WatchRootsResolver = class {
|
|
1729
2522
|
resolve(args) {
|
|
1730
|
-
if (args.devMode === "
|
|
2523
|
+
if (args.devMode === "packaged-ui") return [args.consumerRoot];
|
|
1731
2524
|
return [
|
|
1732
2525
|
args.consumerRoot,
|
|
2526
|
+
path.resolve(args.repoRoot, "packages", "cli"),
|
|
1733
2527
|
path.resolve(args.repoRoot, "packages", "core"),
|
|
1734
2528
|
path.resolve(args.repoRoot, "packages", "core-nodes"),
|
|
1735
2529
|
path.resolve(args.repoRoot, "packages", "core-nodes-gmail"),
|
|
1736
2530
|
path.resolve(args.repoRoot, "packages", "eventbus-redis"),
|
|
1737
2531
|
path.resolve(args.repoRoot, "packages", "host"),
|
|
1738
|
-
path.resolve(args.repoRoot, "packages", "node-example")
|
|
1739
|
-
path.resolve(args.repoRoot, "packages", "queue-bullmq"),
|
|
1740
|
-
path.resolve(args.repoRoot, "packages", "runtime-dev")
|
|
2532
|
+
path.resolve(args.repoRoot, "packages", "node-example")
|
|
1741
2533
|
];
|
|
1742
2534
|
}
|
|
1743
2535
|
};
|
|
@@ -1745,16 +2537,12 @@ var WatchRootsResolver = class {
|
|
|
1745
2537
|
//#endregion
|
|
1746
2538
|
//#region src/dev/Builder.ts
|
|
1747
2539
|
var DevSessionServicesBuilder = class {
|
|
1748
|
-
constructor(loggerFactory$1) {
|
|
1749
|
-
this.loggerFactory = loggerFactory$1;
|
|
1750
|
-
}
|
|
1751
2540
|
build() {
|
|
1752
2541
|
const consumerEnvLoader = new ConsumerEnvLoader();
|
|
1753
2542
|
const sourceMapNodeOptions = new SourceMapNodeOptions();
|
|
1754
2543
|
const listenPortResolver = new ListenPortResolver();
|
|
1755
2544
|
const loopbackPortAllocator = new LoopbackPortAllocator();
|
|
1756
|
-
|
|
1757
|
-
return new DevSessionServices(consumerEnvLoader, sourceMapNodeOptions, new DevSessionPortsResolver(listenPortResolver, loopbackPortAllocator), loopbackPortAllocator, new DevHttpProbe(), new RuntimeToolEntrypointResolver(), new DevAuthSettingsLoader(new CodemationConsumerConfigLoader()), new DevNextHostEnvironmentBuilder(consumerEnvLoader, sourceMapNodeOptions), new WatchRootsResolver(), new DevSourceRestartCoordinator(new DevelopmentGatewayNotifier(cliLogger), this.loggerFactory.createPerformanceDiagnostics("codemation-cli.performance"), cliLogger));
|
|
2545
|
+
return new DevSessionServices(consumerEnvLoader, sourceMapNodeOptions, new DevSessionPortsResolver(listenPortResolver, loopbackPortAllocator), loopbackPortAllocator, new DevHttpProbe(), new DevAuthSettingsLoader(new CodemationConsumerConfigLoader(), consumerEnvLoader), new DevNextHostEnvironmentBuilder(consumerEnvLoader, sourceMapNodeOptions), new WatchRootsResolver(), new DevSourceChangeClassifier());
|
|
1758
2546
|
}
|
|
1759
2547
|
};
|
|
1760
2548
|
|
|
@@ -2027,14 +2815,17 @@ var CliProgram = class {
|
|
|
2027
2815
|
program.command("build").description("Build consumer workflows/plugins output and write the manifest.").option("--consumer-root <path>", "Path to the consumer project root (defaults to cwd)").option("--no-source-maps", "Disable .js.map files for emitted workflow modules (recommended for locked-down production bundles).").option("--target <es2020|es2022>", "ECMAScript language version for emitted workflow JavaScript (default: es2022).", "es2022").action(async (opts) => {
|
|
2028
2816
|
await this.buildCommand.execute(resolveConsumerRoot(opts.consumerRoot), this.buildOptionsParser.parse(opts));
|
|
2029
2817
|
});
|
|
2030
|
-
program.command("dev", { isDefault: true }).description("Start the dev
|
|
2031
|
-
await this.devCommand.execute(
|
|
2818
|
+
program.command("dev", { isDefault: true }).description("Start the stable dev endpoint and disposable API runtime. Uses the packaged Codemation UI by default.").option("--consumer-root <path>", "Path to the consumer project root (defaults to cwd)").option("--watch-framework", "Use Next dev HMR for framework UI work inside this repository.").action(async (opts) => {
|
|
2819
|
+
await this.devCommand.execute({
|
|
2820
|
+
consumerRoot: resolveConsumerRoot(opts.consumerRoot),
|
|
2821
|
+
watchFramework: opts.watchFramework === true
|
|
2822
|
+
});
|
|
2032
2823
|
});
|
|
2033
|
-
const serve = program.command("serve").description("Run production web or worker processes (no dev watchers).");
|
|
2034
|
-
serve.command("web").description("Start the packaged Codemation web host.").option("--consumer-root <path>", "Path to the consumer project root (defaults to cwd)").option("--no-source-maps", "Disable .js.map files for emitted workflow modules when this command runs the consumer build step.").option("--target <es2020|es2022>", "ECMAScript language version for emitted workflow JavaScript when building consumer output (default: es2022).", "es2022").action(async (opts) => {
|
|
2824
|
+
const serve$1 = program.command("serve").description("Run production web or worker processes (no dev watchers).");
|
|
2825
|
+
serve$1.command("web").description("Start the packaged Codemation web host.").option("--consumer-root <path>", "Path to the consumer project root (defaults to cwd)").option("--no-source-maps", "Disable .js.map files for emitted workflow modules when this command runs the consumer build step.").option("--target <es2020|es2022>", "ECMAScript language version for emitted workflow JavaScript when building consumer output (default: es2022).", "es2022").action(async (opts) => {
|
|
2035
2826
|
await this.serveWebCommand.execute(resolveConsumerRoot(opts.consumerRoot), this.buildOptionsParser.parse(opts));
|
|
2036
2827
|
});
|
|
2037
|
-
serve.command("worker").description("Start the Codemation worker process.").option("--consumer-root <path>", "Path to the consumer project root (defaults to cwd)").option("--config <path>", "Override path to codemation.config.ts / .js").action(async (opts) => {
|
|
2828
|
+
serve$1.command("worker").description("Start the Codemation worker process.").option("--consumer-root <path>", "Path to the consumer project root (defaults to cwd)").option("--config <path>", "Override path to codemation.config.ts / .js").action(async (opts) => {
|
|
2038
2829
|
await this.serveWorkerCommand.execute(resolveConsumerRoot(opts.consumerRoot), opts.config);
|
|
2039
2830
|
});
|
|
2040
2831
|
program.command("db").description("Database utilities (PostgreSQL / Prisma).").command("migrate").description("Apply pending Prisma migrations using the consumer database URL (DATABASE_URL in `.env`, or CodemationConfig.runtime.database.url).").option("--consumer-root <path>", "Path to the consumer project root (defaults to cwd)").option("--config <path>", "Override path to codemation.config.ts / .js").action(async (opts) => {
|
|
@@ -2107,7 +2898,9 @@ var NextHostConsumerServerCommandFactory = class {
|
|
|
2107
2898
|
args: [
|
|
2108
2899
|
"exec",
|
|
2109
2900
|
"next",
|
|
2110
|
-
"start"
|
|
2901
|
+
"start",
|
|
2902
|
+
"-H",
|
|
2903
|
+
"127.0.0.1"
|
|
2111
2904
|
],
|
|
2112
2905
|
cwd: args.nextHostRoot
|
|
2113
2906
|
};
|
|
@@ -2126,8 +2919,12 @@ var NextHostConsumerServerCommandFactory = class {
|
|
|
2126
2919
|
//#region src/runtime/TypeScriptRuntimeConfigurator.ts
|
|
2127
2920
|
var TypeScriptRuntimeConfigurator = class {
|
|
2128
2921
|
configure(repoRoot) {
|
|
2922
|
+
if (this.hasExplicitOverride()) return;
|
|
2129
2923
|
process$1.env.CODEMATION_TSCONFIG_PATH = path.resolve(repoRoot, "tsconfig.base.json");
|
|
2130
2924
|
}
|
|
2925
|
+
hasExplicitOverride() {
|
|
2926
|
+
return typeof process$1.env.CODEMATION_TSCONFIG_PATH === "string" && process$1.env.CODEMATION_TSCONFIG_PATH.length > 0;
|
|
2927
|
+
}
|
|
2131
2928
|
};
|
|
2132
2929
|
|
|
2133
2930
|
//#endregion
|
|
@@ -2179,22 +2976,20 @@ var CliDatabaseUrlDescriptor = class {
|
|
|
2179
2976
|
//#endregion
|
|
2180
2977
|
//#region src/bootstrap/CodemationCliApplicationSession.ts
|
|
2181
2978
|
/**
|
|
2182
|
-
* Opens
|
|
2979
|
+
* Opens an app container with persistence + command/query buses (no HTTP/WebSocket servers),
|
|
2183
2980
|
* for CLI tools that dispatch application commands or queries (e.g. user admin).
|
|
2184
2981
|
*/
|
|
2185
2982
|
var CodemationCliApplicationSession = class CodemationCliApplicationSession {
|
|
2186
|
-
constructor(
|
|
2187
|
-
this.
|
|
2983
|
+
constructor(container) {
|
|
2984
|
+
this.container = container;
|
|
2188
2985
|
}
|
|
2189
2986
|
static async open(args) {
|
|
2190
|
-
const
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
}));
|
|
2197
|
-
return new CodemationCliApplicationSession(app);
|
|
2987
|
+
const container = await new AppContainerFactory().create({
|
|
2988
|
+
appConfig: args.appConfig,
|
|
2989
|
+
sharedWorkflowWebsocketServer: null
|
|
2990
|
+
});
|
|
2991
|
+
if (args.appConfig.env.CODEMATION_SKIP_STARTUP_MIGRATIONS !== "true") await container.resolve(DatabaseMigrations).migrate();
|
|
2992
|
+
return new CodemationCliApplicationSession(container);
|
|
2198
2993
|
}
|
|
2199
2994
|
getPrismaClient() {
|
|
2200
2995
|
const container = this.getContainer();
|
|
@@ -2208,10 +3003,10 @@ var CodemationCliApplicationSession = class CodemationCliApplicationSession {
|
|
|
2208
3003
|
return this.getContainer().resolve(ApplicationTokens.QueryBus);
|
|
2209
3004
|
}
|
|
2210
3005
|
async close() {
|
|
2211
|
-
await this.
|
|
3006
|
+
await this.container.resolve(AppContainerLifecycle).stop({ stopWebsocketServer: false });
|
|
2212
3007
|
}
|
|
2213
3008
|
getContainer() {
|
|
2214
|
-
return this.
|
|
3009
|
+
return this.container;
|
|
2215
3010
|
}
|
|
2216
3011
|
};
|
|
2217
3012
|
|
|
@@ -2221,37 +3016,26 @@ var CodemationCliApplicationSession = class CodemationCliApplicationSession {
|
|
|
2221
3016
|
* Shared env/config/session wiring for `codemation user *` commands (local auth + database).
|
|
2222
3017
|
*/
|
|
2223
3018
|
var UserAdminCliBootstrap = class {
|
|
2224
|
-
constructor(
|
|
2225
|
-
this.
|
|
3019
|
+
constructor(appConfigLoader, pathResolver, consumerDotenvLoader, tsconfigPreparation) {
|
|
3020
|
+
this.appConfigLoader = appConfigLoader;
|
|
2226
3021
|
this.pathResolver = pathResolver;
|
|
2227
3022
|
this.consumerDotenvLoader = consumerDotenvLoader;
|
|
2228
3023
|
this.tsconfigPreparation = tsconfigPreparation;
|
|
2229
|
-
this.databasePersistenceResolver = databasePersistenceResolver;
|
|
2230
3024
|
}
|
|
2231
3025
|
async withSession(options, fn) {
|
|
2232
3026
|
const consumerRoot = options.consumerRoot ?? process.cwd();
|
|
2233
3027
|
this.consumerDotenvLoader.load(consumerRoot);
|
|
2234
3028
|
this.tsconfigPreparation.applyWorkspaceTsconfigForTsxIfPresent(consumerRoot);
|
|
2235
|
-
const
|
|
3029
|
+
const paths = await this.pathResolver.resolve(consumerRoot);
|
|
3030
|
+
const loadResult = await this.appConfigLoader.load({
|
|
2236
3031
|
consumerRoot,
|
|
2237
|
-
|
|
2238
|
-
});
|
|
2239
|
-
if (resolution.config.auth?.kind !== "local") throw new Error("Codemation user commands require CodemationConfig.auth.kind to be \"local\".");
|
|
2240
|
-
if (this.databasePersistenceResolver.resolve({
|
|
2241
|
-
runtimeConfig: resolution.config.runtime ?? {},
|
|
3032
|
+
repoRoot: paths.repoRoot,
|
|
2242
3033
|
env: process.env,
|
|
2243
|
-
|
|
2244
|
-
}).kind === "none") throw new Error("Database persistence is not configured. Set CodemationConfig.runtime.database (postgresql URL or PGlite).");
|
|
2245
|
-
const paths = await this.pathResolver.resolve(consumerRoot);
|
|
2246
|
-
const session = await CodemationCliApplicationSession.open({
|
|
2247
|
-
resolution,
|
|
2248
|
-
bootstrap: new CodemationBootstrapRequest({
|
|
2249
|
-
repoRoot: paths.repoRoot,
|
|
2250
|
-
consumerRoot,
|
|
2251
|
-
env: process.env,
|
|
2252
|
-
workflowSources: resolution.workflowSources
|
|
2253
|
-
})
|
|
3034
|
+
configPathOverride: options.configPath
|
|
2254
3035
|
});
|
|
3036
|
+
if (loadResult.appConfig.auth?.kind !== "local") throw new Error("Codemation user commands require CodemationConfig.auth.kind to be \"local\".");
|
|
3037
|
+
if (loadResult.appConfig.persistence.kind === "none") throw new Error("Database persistence is not configured. Set CodemationConfig.runtime.database (postgresql URL or PGlite).");
|
|
3038
|
+
const session = await CodemationCliApplicationSession.open({ appConfig: loadResult.appConfig });
|
|
2255
3039
|
try {
|
|
2256
3040
|
return await fn(session);
|
|
2257
3041
|
} finally {
|
|
@@ -2305,6 +3089,7 @@ const loggerFactory = new ServerLoggerFactory(logLevelPolicyFactory);
|
|
|
2305
3089
|
var CliProgramFactory = class {
|
|
2306
3090
|
create() {
|
|
2307
3091
|
const cliLogger = loggerFactory.create("codemation-cli");
|
|
3092
|
+
const appConfigLoader = new AppConfigLoader();
|
|
2308
3093
|
const pathResolver = new CliPathResolver();
|
|
2309
3094
|
const pluginDiscovery = new CodemationPluginDiscovery();
|
|
2310
3095
|
const artifactsPublisher = new ConsumerBuildArtifactsPublisher();
|
|
@@ -2312,15 +3097,15 @@ var CliProgramFactory = class {
|
|
|
2312
3097
|
const outputBuilderLoader = new ConsumerOutputBuilderLoader();
|
|
2313
3098
|
const sourceMapNodeOptions = new SourceMapNodeOptions();
|
|
2314
3099
|
const nextHostConsumerServerCommandFactory = new NextHostConsumerServerCommandFactory();
|
|
3100
|
+
const devSessionServices = new DevSessionServicesBuilder().build();
|
|
2315
3101
|
const tsconfigPreparation = new ConsumerCliTsconfigPreparation();
|
|
2316
|
-
const
|
|
2317
|
-
const userAdminBootstrap = new UserAdminCliBootstrap(new CodemationConsumerConfigLoader(), pathResolver, new UserAdminConsumerDotenvLoader(), tsconfigPreparation, databasePersistenceResolver);
|
|
3102
|
+
const userAdminBootstrap = new UserAdminCliBootstrap(appConfigLoader, pathResolver, new UserAdminConsumerDotenvLoader(), tsconfigPreparation);
|
|
2318
3103
|
const hostPackageRoot = new HostPackageRootResolver().resolveHostPackageRoot();
|
|
2319
3104
|
const userAdminCliOptionsParser = new UserAdminCliOptionsParser();
|
|
2320
3105
|
const databaseMigrationsApplyService = new DatabaseMigrationsApplyService(cliLogger, new UserAdminConsumerDotenvLoader(), tsconfigPreparation, new CodemationConsumerConfigLoader(), new ConsumerDatabaseConnectionResolver(), new CliDatabaseUrlDescriptor(), hostPackageRoot, new PrismaMigrationDeployer());
|
|
2321
3106
|
const buildOptionsParser = new ConsumerBuildOptionsParser();
|
|
2322
3107
|
const devConsumerPublishBootstrap = new DevConsumerPublishBootstrap(cliLogger, pluginDiscovery, artifactsPublisher, outputBuilderLoader, buildOptionsParser);
|
|
2323
|
-
return new CliProgram(buildOptionsParser, new BuildCommand(cliLogger, pathResolver, pluginDiscovery, artifactsPublisher, tsRuntime, outputBuilderLoader), new DevCommand(pathResolver,
|
|
3108
|
+
return new CliProgram(buildOptionsParser, new BuildCommand(cliLogger, pathResolver, pluginDiscovery, artifactsPublisher, tsRuntime, outputBuilderLoader), new DevCommand(pathResolver, tsRuntime, new DevLockFactory(), new DevSourceWatcherFactory(), cliLogger, devSessionServices, databaseMigrationsApplyService, new DevBootstrapSummaryFetcher(), new DevCliBannerRenderer(), devConsumerPublishBootstrap, new ConsumerEnvDotenvFilePredicate(), new DevTrackedProcessTreeKiller(), nextHostConsumerServerCommandFactory, new DevApiRuntimeFactory(devSessionServices.loopbackPortAllocator, appConfigLoader, pluginDiscovery), new CliDevProxyServerFactory(), new DevRebuildQueueFactory()), new ServeWebCommand(pathResolver, new CodemationConsumerConfigLoader(), pluginDiscovery, artifactsPublisher, tsRuntime, sourceMapNodeOptions, outputBuilderLoader, new ConsumerEnvLoader(), new ListenPortResolver(), nextHostConsumerServerCommandFactory, new CodemationFrontendAuthSnapshotFactory(), new FrontendAppConfigJsonCodec()), new ServeWorkerCommand(pathResolver, appConfigLoader, new AppContainerFactory()), new DbMigrateCommand(databaseMigrationsApplyService), new UserCreateCommand(new LocalUserCreator(userAdminBootstrap), userAdminCliOptionsParser), new UserListCommand(cliLogger, userAdminBootstrap, new CliDatabaseUrlDescriptor(), userAdminCliOptionsParser));
|
|
2324
3109
|
}
|
|
2325
3110
|
};
|
|
2326
3111
|
|