@codemation/cli 0.0.5 → 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-C3ar49fj.js → CliBin-Bx1lFBi5.js} +1041 -365
- package/dist/bin.js +1 -1
- package/dist/index.d.ts +644 -207
- 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 +202 -171
- package/src/commands/ServeWebCommand.ts +26 -1
- package/src/commands/ServeWorkerCommand.ts +46 -30
- package/src/commands/devCommandLifecycle.types.ts +7 -11
- package/src/database/ConsumerDatabaseConnectionResolver.ts +55 -9
- package/src/database/DatabaseMigrationsApplyService.ts +2 -2
- package/src/dev/Builder.ts +1 -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 +2 -2
- package/src/dev/DevNextHostEnvironmentBuilder.ts +35 -5
- 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 +0 -4
- package/src/dev/DevSourceChangeClassifier.ts +33 -13
- 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,70 +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();
|
|
158
165
|
const processState = this.createInitialProcessState();
|
|
166
|
+
let proxyServer = null;
|
|
159
167
|
try {
|
|
160
168
|
const prepared = await this.prepareDevRuntime(paths, devMode, nextPort, gatewayPort, authSettings);
|
|
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
|
-
await this.
|
|
170
|
-
await this.startWatcherForSourceRestart(prepared, processState, 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 {
|
|
174
183
|
processState.stopRequested = true;
|
|
175
|
-
await this.
|
|
184
|
+
await this.stopLiveProcesses(processState, proxyServer);
|
|
176
185
|
await watcher.stop();
|
|
177
186
|
await devLock.release();
|
|
178
187
|
}
|
|
179
188
|
}
|
|
180
|
-
|
|
181
|
-
|
|
189
|
+
resolveDevMode(args) {
|
|
190
|
+
if (args.watchFramework === true || process$1.env.CODEMATION_DEV_MODE === "framework") return "watch-framework";
|
|
191
|
+
return "packaged-ui";
|
|
182
192
|
}
|
|
183
193
|
async prepareDevRuntime(paths, devMode, nextPort, gatewayPort, authSettings) {
|
|
184
|
-
const developmentServerToken = this.session.devAuthLoader.resolveDevelopmentServerToken(process$1.env.CODEMATION_DEV_SERVER_TOKEN);
|
|
185
|
-
const gatewayEntrypoint = await this.session.runtimeEntrypointResolver.resolve({
|
|
186
|
-
packageName: "@codemation/dev-gateway",
|
|
187
|
-
repoRoot: paths.repoRoot,
|
|
188
|
-
sourceEntrypoint: "packages/dev-gateway/src/bin.ts"
|
|
189
|
-
});
|
|
190
|
-
const runtimeEntrypoint = await this.session.runtimeEntrypointResolver.resolve({
|
|
191
|
-
packageName: "@codemation/runtime-dev",
|
|
192
|
-
repoRoot: paths.repoRoot,
|
|
193
|
-
sourceEntrypoint: "packages/runtime-dev/src/bin.ts"
|
|
194
|
-
});
|
|
195
|
-
const runtimeWorkingDirectory = paths.repoRoot ?? paths.consumerRoot;
|
|
196
|
-
const consumerEnv = this.session.consumerEnvLoader.load(paths.consumerRoot);
|
|
197
194
|
return {
|
|
198
195
|
paths,
|
|
199
196
|
devMode,
|
|
200
197
|
nextPort,
|
|
201
198
|
gatewayPort,
|
|
202
199
|
authSettings,
|
|
203
|
-
developmentServerToken,
|
|
204
|
-
|
|
205
|
-
runtimeEntrypoint,
|
|
206
|
-
runtimeWorkingDirectory,
|
|
207
|
-
discoveredPluginPackagesJson: JSON.stringify(await this.pluginDiscovery.discover(paths.consumerRoot)),
|
|
208
|
-
consumerEnv
|
|
200
|
+
developmentServerToken: this.session.devAuthLoader.resolveDevelopmentServerToken(process$1.env.CODEMATION_DEV_SERVER_TOKEN),
|
|
201
|
+
consumerEnv: this.session.consumerEnvLoader.load(paths.consumerRoot)
|
|
209
202
|
};
|
|
210
203
|
}
|
|
211
204
|
createInitialProcessState() {
|
|
212
205
|
return {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
206
|
+
currentDevUi: null,
|
|
207
|
+
currentPackagedUi: null,
|
|
208
|
+
currentPackagedUiBaseUrl: null,
|
|
209
|
+
currentRuntime: null,
|
|
210
|
+
isRestartingUi: false,
|
|
218
211
|
stopRequested: false,
|
|
219
212
|
stopResolve: null,
|
|
220
213
|
stopReject: null
|
|
@@ -229,19 +222,15 @@ var DevCommand = class {
|
|
|
229
222
|
gatewayBaseHttpUrl(gatewayPort) {
|
|
230
223
|
return `http://127.0.0.1:${gatewayPort}`;
|
|
231
224
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
* Framework mode: no separate UI child (Next runs in dev later).
|
|
235
|
-
*/
|
|
236
|
-
async startConsumerUiProxyWhenNeeded(prepared, state) {
|
|
237
|
-
if (prepared.devMode !== "consumer") return "";
|
|
225
|
+
async startPackagedUiWhenNeeded(prepared, state) {
|
|
226
|
+
if (prepared.devMode !== "packaged-ui") return "";
|
|
238
227
|
const websocketPort = prepared.gatewayPort;
|
|
239
|
-
const uiProxyBase = state.
|
|
240
|
-
state.
|
|
241
|
-
await this.
|
|
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);
|
|
242
231
|
return uiProxyBase;
|
|
243
232
|
}
|
|
244
|
-
async
|
|
233
|
+
async spawnPackagedUi(prepared, state, authSettings, websocketPort, uiProxyBase) {
|
|
245
234
|
const nextHostPackageJsonPath = this.require.resolve("@codemation/next-host/package.json");
|
|
246
235
|
const nextHostRoot = path.dirname(nextHostPackageJsonPath);
|
|
247
236
|
const nextHostCommand = await this.nextHostConsumerServerCommandFactory.create({ nextHostRoot });
|
|
@@ -259,60 +248,38 @@ var DevCommand = class {
|
|
|
259
248
|
skipUiAuth: authSettings.skipUiAuth,
|
|
260
249
|
websocketPort
|
|
261
250
|
});
|
|
262
|
-
state.
|
|
251
|
+
state.currentPackagedUi = spawn(nextHostCommand.command, nextHostCommand.args, {
|
|
263
252
|
cwd: nextHostCommand.cwd,
|
|
264
253
|
...this.devDetachedChildSpawnOptions(),
|
|
265
254
|
env: nextHostEnvironment
|
|
266
255
|
});
|
|
267
|
-
state.
|
|
268
|
-
if (state.stopRequested || state.
|
|
256
|
+
state.currentPackagedUi.on("error", (error) => {
|
|
257
|
+
if (state.stopRequested || state.isRestartingUi) return;
|
|
269
258
|
state.stopRequested = true;
|
|
270
259
|
state.stopReject?.(error instanceof Error ? error : new Error(String(error)));
|
|
271
260
|
});
|
|
272
|
-
state.
|
|
273
|
-
if (state.stopRequested || state.
|
|
261
|
+
state.currentPackagedUi.on("exit", (code) => {
|
|
262
|
+
if (state.stopRequested || state.isRestartingUi) return;
|
|
274
263
|
state.stopRequested = true;
|
|
275
|
-
|
|
276
|
-
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}.`));
|
|
277
265
|
});
|
|
278
266
|
await this.session.devHttpProbe.waitUntilUrlRespondsOk(`${uiProxyBase}/`);
|
|
279
267
|
}
|
|
280
|
-
async
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
CODEMATION_CONSUMER_ROOT: prepared.paths.consumerRoot,
|
|
294
|
-
CODEMATION_DISCOVERED_PLUGIN_PACKAGES_JSON: prepared.discoveredPluginPackagesJson,
|
|
295
|
-
CODEMATION_PREFER_PLUGIN_SOURCE_ENTRY: "true",
|
|
296
|
-
CODEMATION_DEV_SERVER_TOKEN: prepared.developmentServerToken,
|
|
297
|
-
CODEMATION_SKIP_STARTUP_MIGRATIONS: "true",
|
|
298
|
-
NODE_OPTIONS: this.session.sourceMapNodeOptions.appendToNodeOptions(process$1.env.NODE_OPTIONS),
|
|
299
|
-
WS_NO_BUFFER_UTIL: "1",
|
|
300
|
-
WS_NO_UTF_8_VALIDATE: "1",
|
|
301
|
-
...uiProxyBase.length > 0 ? { CODEMATION_DEV_UI_PROXY_TARGET: uiProxyBase } : {}
|
|
302
|
-
}
|
|
303
|
-
});
|
|
304
|
-
state.currentGateway.on("error", (error) => {
|
|
305
|
-
if (!state.stopRequested) {
|
|
306
|
-
state.stopRequested = true;
|
|
307
|
-
state.stopReject?.(error instanceof Error ? error : new Error(String(error)));
|
|
308
|
-
}
|
|
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
|
|
309
281
|
});
|
|
310
|
-
|
|
311
|
-
if (state.stopRequested) return;
|
|
312
|
-
state.stopRequested = true;
|
|
313
|
-
state.stopReject?.(/* @__PURE__ */ new Error(`codemation dev-gateway exited unexpectedly with code ${code ?? 0}.`));
|
|
314
|
-
});
|
|
315
|
-
await this.session.devHttpProbe.waitUntilGatewayHealthy(gatewayBaseUrl);
|
|
282
|
+
proxyServer.setBuildStatus("idle");
|
|
316
283
|
}
|
|
317
284
|
devDetachedChildSpawnOptions() {
|
|
318
285
|
return process$1.platform === "win32" ? {
|
|
@@ -324,20 +291,14 @@ var DevCommand = class {
|
|
|
324
291
|
detached: true
|
|
325
292
|
};
|
|
326
293
|
}
|
|
327
|
-
bindShutdownSignalsToChildProcesses(state) {
|
|
294
|
+
bindShutdownSignalsToChildProcesses(state, proxyServer) {
|
|
328
295
|
let shutdownInProgress = false;
|
|
329
296
|
const runShutdown = async () => {
|
|
330
297
|
if (shutdownInProgress) return;
|
|
331
298
|
shutdownInProgress = true;
|
|
332
299
|
state.stopRequested = true;
|
|
333
300
|
process$1.stdout.write("\n[codemation] Stopping..\n");
|
|
334
|
-
|
|
335
|
-
for (const child of [
|
|
336
|
-
state.currentUiNext,
|
|
337
|
-
state.currentNextHost,
|
|
338
|
-
state.currentGateway
|
|
339
|
-
]) if (child && child.exitCode === null && child.signalCode === null) children.push(child);
|
|
340
|
-
await Promise.all(children.map((child) => this.devTrackedProcessTreeKiller.killProcessTreeRootedAt(child)));
|
|
301
|
+
await this.stopLiveProcesses(state, proxyServer);
|
|
341
302
|
process$1.stdout.write("[codemation] Stopped.\n");
|
|
342
303
|
state.stopResolve?.();
|
|
343
304
|
};
|
|
@@ -349,14 +310,11 @@ var DevCommand = class {
|
|
|
349
310
|
runShutdown();
|
|
350
311
|
});
|
|
351
312
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
async spawnFrameworkNextHostWhenNeeded(prepared, state, gatewayBaseUrl) {
|
|
356
|
-
if (prepared.devMode !== "framework") return;
|
|
357
|
-
await this.spawnFrameworkNextHost(prepared, state, gatewayBaseUrl, prepared.authSettings);
|
|
313
|
+
async spawnDevUiWhenNeeded(prepared, state, gatewayBaseUrl) {
|
|
314
|
+
if (prepared.devMode !== "watch-framework") return;
|
|
315
|
+
await this.spawnDevUi(prepared, state, gatewayBaseUrl, prepared.authSettings);
|
|
358
316
|
}
|
|
359
|
-
async
|
|
317
|
+
async spawnDevUi(prepared, state, gatewayBaseUrl, authSettings) {
|
|
360
318
|
const websocketPort = prepared.gatewayPort;
|
|
361
319
|
const nextHostPackageJsonPath = this.require.resolve("@codemation/next-host/package.json");
|
|
362
320
|
const nextHostRoot = path.dirname(nextHostPackageJsonPath);
|
|
@@ -369,7 +327,7 @@ var DevCommand = class {
|
|
|
369
327
|
websocketPort,
|
|
370
328
|
runtimeDevUrl: gatewayBaseUrl
|
|
371
329
|
});
|
|
372
|
-
state.
|
|
330
|
+
state.currentDevUi = spawn("pnpm", [
|
|
373
331
|
"exec",
|
|
374
332
|
"next",
|
|
375
333
|
"dev"
|
|
@@ -378,26 +336,28 @@ var DevCommand = class {
|
|
|
378
336
|
...this.devDetachedChildSpawnOptions(),
|
|
379
337
|
env: nextHostEnvironment
|
|
380
338
|
});
|
|
381
|
-
state.
|
|
339
|
+
state.currentDevUi.on("exit", (code) => {
|
|
382
340
|
const normalizedCode = code ?? 0;
|
|
383
|
-
if (state.stopRequested || state.
|
|
341
|
+
if (state.stopRequested || state.isRestartingUi) return;
|
|
384
342
|
if (normalizedCode === 0) {
|
|
385
343
|
state.stopRequested = true;
|
|
386
|
-
if (state.currentGateway?.exitCode === null) this.devTrackedProcessTreeKiller.killProcessTreeRootedAt(state.currentGateway);
|
|
387
344
|
state.stopResolve?.();
|
|
388
345
|
return;
|
|
389
346
|
}
|
|
390
347
|
state.stopRequested = true;
|
|
391
348
|
state.stopReject?.(/* @__PURE__ */ new Error(`next host exited with code ${normalizedCode}.`));
|
|
392
349
|
});
|
|
393
|
-
state.
|
|
394
|
-
if (state.stopRequested || state.
|
|
350
|
+
state.currentDevUi.on("error", (error) => {
|
|
351
|
+
if (state.stopRequested || state.isRestartingUi) return;
|
|
395
352
|
state.stopRequested = true;
|
|
396
353
|
state.stopReject?.(error instanceof Error ? error : new Error(String(error)));
|
|
397
354
|
});
|
|
398
355
|
await this.session.devHttpProbe.waitUntilUrlRespondsOk(`http://127.0.0.1:${prepared.nextPort}/`);
|
|
399
356
|
}
|
|
400
|
-
async startWatcherForSourceRestart(prepared, state, 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
|
+
} });
|
|
401
361
|
await watcher.start({
|
|
402
362
|
roots: this.session.watchRootsResolver.resolve({
|
|
403
363
|
consumerRoot: prepared.paths.consumerRoot,
|
|
@@ -406,7 +366,7 @@ var DevCommand = class {
|
|
|
406
366
|
}),
|
|
407
367
|
onChange: async ({ changedPaths }) => {
|
|
408
368
|
if (changedPaths.length > 0 && changedPaths.every((p) => this.consumerEnvDotenvFilePredicate.matches(p))) {
|
|
409
|
-
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");
|
|
410
370
|
return;
|
|
411
371
|
}
|
|
412
372
|
try {
|
|
@@ -414,69 +374,111 @@ var DevCommand = class {
|
|
|
414
374
|
changedPaths,
|
|
415
375
|
consumerRoot: prepared.paths.consumerRoot
|
|
416
376
|
});
|
|
417
|
-
const
|
|
377
|
+
const shouldRestartUi = this.session.sourceChangeClassifier.requiresUiRestart({
|
|
418
378
|
changedPaths,
|
|
419
379
|
consumerRoot: prepared.paths.consumerRoot
|
|
420
380
|
});
|
|
421
|
-
process$1.stdout.write(
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
const json = await this.devBootstrapSummaryFetcher.fetch(gatewayBaseUrl);
|
|
428
|
-
if (json) this.devCliBannerRenderer.renderCompact(json);
|
|
429
|
-
process$1.stdout.write("[codemation] Runtime ready.\n");
|
|
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
|
+
});
|
|
430
387
|
} catch (error) {
|
|
431
|
-
await this.failDevSessionAfterIrrecoverableSourceError(state, error);
|
|
388
|
+
await this.failDevSessionAfterIrrecoverableSourceError(state, proxyServer, error);
|
|
432
389
|
}
|
|
433
390
|
}
|
|
434
391
|
});
|
|
435
392
|
}
|
|
436
|
-
async
|
|
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) {
|
|
437
420
|
const refreshedAuthSettings = await this.session.devAuthLoader.loadForConsumer(prepared.paths.consumerRoot);
|
|
438
|
-
process$1.stdout.write("[codemation] Restarting
|
|
439
|
-
state.
|
|
421
|
+
process$1.stdout.write("[codemation] Restarting the UI process to apply source changes…\n");
|
|
422
|
+
state.isRestartingUi = true;
|
|
440
423
|
try {
|
|
441
|
-
if (prepared.devMode === "
|
|
442
|
-
await this.
|
|
424
|
+
if (prepared.devMode === "packaged-ui") {
|
|
425
|
+
await this.restartPackagedUi(prepared, state, refreshedAuthSettings);
|
|
443
426
|
return;
|
|
444
427
|
}
|
|
445
|
-
await this.
|
|
428
|
+
await this.restartDevUi(prepared, state, gatewayBaseUrl, refreshedAuthSettings);
|
|
446
429
|
} finally {
|
|
447
|
-
state.
|
|
430
|
+
state.isRestartingUi = false;
|
|
448
431
|
}
|
|
449
432
|
}
|
|
450
|
-
async
|
|
451
|
-
if (state.
|
|
452
|
-
state.
|
|
453
|
-
const uiProxyBaseUrl = state.
|
|
454
|
-
if (!uiProxyBaseUrl) throw new Error("
|
|
455
|
-
await this.
|
|
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);
|
|
456
439
|
}
|
|
457
|
-
async
|
|
458
|
-
if (state.
|
|
459
|
-
state.
|
|
460
|
-
await this.
|
|
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);
|
|
461
444
|
}
|
|
462
|
-
async failDevSessionAfterIrrecoverableSourceError(state, error) {
|
|
445
|
+
async failDevSessionAfterIrrecoverableSourceError(state, proxyServer, error) {
|
|
463
446
|
const exception = error instanceof Error ? error : new Error(String(error));
|
|
464
447
|
state.stopRequested = true;
|
|
465
|
-
await this.
|
|
448
|
+
await this.stopLiveProcesses(state, proxyServer);
|
|
466
449
|
state.stopReject?.(exception);
|
|
467
450
|
}
|
|
468
|
-
async
|
|
451
|
+
async stopLiveProcesses(state, proxyServer) {
|
|
452
|
+
await this.stopCurrentRuntime(state, proxyServer);
|
|
469
453
|
const children = [];
|
|
470
|
-
for (const child of [
|
|
471
|
-
state.currentUiNext,
|
|
472
|
-
state.currentNextHost,
|
|
473
|
-
state.currentGateway
|
|
474
|
-
]) if (child && child.exitCode === null && child.signalCode === null) children.push(child);
|
|
454
|
+
for (const child of [state.currentPackagedUi, state.currentDevUi]) if (child && child.exitCode === null && child.signalCode === null) children.push(child);
|
|
475
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"
|
|
476
|
+
}
|
|
477
|
+
});
|
|
476
478
|
}
|
|
477
|
-
|
|
478
|
-
if (devMode !== "
|
|
479
|
-
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.`);
|
|
480
482
|
}
|
|
481
483
|
};
|
|
482
484
|
|
|
@@ -484,8 +486,9 @@ var DevCommand = class {
|
|
|
484
486
|
//#region src/commands/ServeWebCommand.ts
|
|
485
487
|
var ServeWebCommand = class {
|
|
486
488
|
require = createRequire(import.meta.url);
|
|
487
|
-
constructor(pathResolver, pluginDiscovery, artifactsPublisher, tsRuntime, sourceMapNodeOptions, outputBuilderLoader, envLoader, listenPortResolver, nextHostConsumerServerCommandFactory) {
|
|
489
|
+
constructor(pathResolver, configLoader, pluginDiscovery, artifactsPublisher, tsRuntime, sourceMapNodeOptions, outputBuilderLoader, envLoader, listenPortResolver, nextHostConsumerServerCommandFactory, frontendAuthSnapshotFactory, frontendAppConfigJsonCodec) {
|
|
488
490
|
this.pathResolver = pathResolver;
|
|
491
|
+
this.configLoader = configLoader;
|
|
489
492
|
this.pluginDiscovery = pluginDiscovery;
|
|
490
493
|
this.artifactsPublisher = artifactsPublisher;
|
|
491
494
|
this.tsRuntime = tsRuntime;
|
|
@@ -494,6 +497,8 @@ var ServeWebCommand = class {
|
|
|
494
497
|
this.envLoader = envLoader;
|
|
495
498
|
this.listenPortResolver = listenPortResolver;
|
|
496
499
|
this.nextHostConsumerServerCommandFactory = nextHostConsumerServerCommandFactory;
|
|
500
|
+
this.frontendAuthSnapshotFactory = frontendAuthSnapshotFactory;
|
|
501
|
+
this.frontendAppConfigJsonCodec = frontendAppConfigJsonCodec;
|
|
497
502
|
}
|
|
498
503
|
async execute(consumerRoot, buildOptions) {
|
|
499
504
|
const paths = await this.pathResolver.resolve(consumerRoot);
|
|
@@ -504,6 +509,15 @@ var ServeWebCommand = class {
|
|
|
504
509
|
const nextHostRoot = path.dirname(this.require.resolve("@codemation/next-host/package.json"));
|
|
505
510
|
const nextHostCommand = await this.nextHostConsumerServerCommandFactory.create({ nextHostRoot });
|
|
506
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
|
+
});
|
|
507
521
|
const nextPort = this.listenPortResolver.resolvePrimaryApplicationPort(process$1.env.PORT);
|
|
508
522
|
const websocketPort = this.listenPortResolver.resolveWebsocketPortRelativeToHttp({
|
|
509
523
|
nextPort,
|
|
@@ -517,6 +531,11 @@ var ServeWebCommand = class {
|
|
|
517
531
|
...process$1.env,
|
|
518
532
|
...consumerEnv,
|
|
519
533
|
PORT: String(nextPort),
|
|
534
|
+
CODEMATION_FRONTEND_APP_CONFIG_JSON: this.frontendAppConfigJsonCodec.serialize({
|
|
535
|
+
auth: frontendAuthSnapshot,
|
|
536
|
+
productName: "Codemation",
|
|
537
|
+
logoUrl: null
|
|
538
|
+
}),
|
|
520
539
|
CODEMATION_CONSUMER_OUTPUT_MANIFEST_PATH: manifest.manifestPath,
|
|
521
540
|
CODEMATION_CONSUMER_ROOT: paths.consumerRoot,
|
|
522
541
|
CODEMATION_WS_PORT: String(websocketPort),
|
|
@@ -542,34 +561,46 @@ var ServeWebCommand = class {
|
|
|
542
561
|
//#endregion
|
|
543
562
|
//#region src/commands/ServeWorkerCommand.ts
|
|
544
563
|
var ServeWorkerCommand = class {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
this.
|
|
564
|
+
constructor(pathResolver, appConfigLoader, appContainerFactory) {
|
|
565
|
+
this.pathResolver = pathResolver;
|
|
566
|
+
this.appConfigLoader = appConfigLoader;
|
|
567
|
+
this.appContainerFactory = appContainerFactory;
|
|
548
568
|
}
|
|
549
569
|
async execute(consumerRoot, configPathOverride) {
|
|
550
|
-
const
|
|
551
|
-
const
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
stdio: "inherit",
|
|
557
|
-
env: {
|
|
558
|
-
...process$1.env,
|
|
559
|
-
NODE_OPTIONS: this.sourceMapNodeOptions.appendToNodeOptions(process$1.env.NODE_OPTIONS)
|
|
560
|
-
}
|
|
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
|
|
561
576
|
});
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
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);
|
|
571
586
|
});
|
|
572
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
|
+
}
|
|
573
604
|
};
|
|
574
605
|
|
|
575
606
|
//#endregion
|
|
@@ -1270,13 +1301,36 @@ var ConsumerOutputBuilderLoader = class {
|
|
|
1270
1301
|
* Resolves TCP PostgreSQL vs PGlite vs none from env + {@link CodemationConfig} (same rules as the host runtime).
|
|
1271
1302
|
*/
|
|
1272
1303
|
var ConsumerDatabaseConnectionResolver = class {
|
|
1273
|
-
resolver = new DatabasePersistenceResolver();
|
|
1274
1304
|
resolve(processEnv, config$1, consumerRoot) {
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
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");
|
|
1280
1334
|
}
|
|
1281
1335
|
};
|
|
1282
1336
|
|
|
@@ -1352,7 +1406,7 @@ var HostPackageRootResolver = class {
|
|
|
1352
1406
|
//#endregion
|
|
1353
1407
|
//#region src/dev/DevBootstrapSummaryFetcher.ts
|
|
1354
1408
|
/**
|
|
1355
|
-
* Fetches {@link DevBootstrapSummaryJson} from the
|
|
1409
|
+
* Fetches {@link DevBootstrapSummaryJson} from the stable CLI-owned dev endpoint.
|
|
1356
1410
|
*/
|
|
1357
1411
|
var DevBootstrapSummaryFetcher = class {
|
|
1358
1412
|
async fetch(gatewayBaseUrl) {
|
|
@@ -1502,6 +1556,710 @@ var DevConsumerPublishBootstrap = class {
|
|
|
1502
1556
|
}
|
|
1503
1557
|
};
|
|
1504
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
|
+
|
|
1505
2263
|
//#endregion
|
|
1506
2264
|
//#region src/runtime/ListenPortResolver.ts
|
|
1507
2265
|
/**
|
|
@@ -1536,36 +2294,13 @@ var SourceMapNodeOptions = class {
|
|
|
1536
2294
|
}
|
|
1537
2295
|
};
|
|
1538
2296
|
|
|
1539
|
-
//#endregion
|
|
1540
|
-
//#region src/dev/DevelopmentGatewayNotifier.ts
|
|
1541
|
-
var DevelopmentGatewayNotifier = class {
|
|
1542
|
-
constructor(cliLogger) {
|
|
1543
|
-
this.cliLogger = cliLogger;
|
|
1544
|
-
}
|
|
1545
|
-
async notify(args) {
|
|
1546
|
-
const targetUrl = `${args.gatewayBaseUrl.replace(/\/$/, "")}${ApiPaths.devGatewayNotify()}`;
|
|
1547
|
-
try {
|
|
1548
|
-
const response = await fetch(targetUrl, {
|
|
1549
|
-
method: "POST",
|
|
1550
|
-
headers: {
|
|
1551
|
-
"content-type": "application/json",
|
|
1552
|
-
"x-codemation-dev-token": args.developmentServerToken
|
|
1553
|
-
},
|
|
1554
|
-
body: JSON.stringify(args.payload)
|
|
1555
|
-
});
|
|
1556
|
-
if (!response.ok) this.cliLogger.warn(`failed to notify dev gateway status=${response.status}`);
|
|
1557
|
-
} catch (error) {
|
|
1558
|
-
this.cliLogger.warn(`failed to notify dev gateway: ${error instanceof Error ? error.message : String(error)}`);
|
|
1559
|
-
}
|
|
1560
|
-
}
|
|
1561
|
-
};
|
|
1562
|
-
|
|
1563
2297
|
//#endregion
|
|
1564
2298
|
//#region src/dev/DevAuthSettingsLoader.ts
|
|
1565
2299
|
var DevAuthSettingsLoader = class DevAuthSettingsLoader {
|
|
1566
2300
|
static defaultDevelopmentAuthSecret = "codemation-dev-auth-secret-not-for-production";
|
|
1567
|
-
constructor(configLoader) {
|
|
2301
|
+
constructor(configLoader, consumerEnvLoader) {
|
|
1568
2302
|
this.configLoader = configLoader;
|
|
2303
|
+
this.consumerEnvLoader = consumerEnvLoader;
|
|
1569
2304
|
}
|
|
1570
2305
|
resolveDevelopmentServerToken(rawToken) {
|
|
1571
2306
|
if (rawToken && rawToken.trim().length > 0) return rawToken;
|
|
@@ -1573,14 +2308,15 @@ var DevAuthSettingsLoader = class DevAuthSettingsLoader {
|
|
|
1573
2308
|
}
|
|
1574
2309
|
async loadForConsumer(consumerRoot) {
|
|
1575
2310
|
const resolution = await this.configLoader.load({ consumerRoot });
|
|
2311
|
+
const envForAuthSecret = this.consumerEnvLoader.mergeConsumerRootIntoProcessEnvironment(consumerRoot, process.env);
|
|
1576
2312
|
return {
|
|
1577
2313
|
authConfigJson: JSON.stringify(resolution.config.auth ?? null),
|
|
1578
|
-
authSecret: this.resolveDevelopmentAuthSecret(
|
|
2314
|
+
authSecret: this.resolveDevelopmentAuthSecret(envForAuthSecret),
|
|
1579
2315
|
skipUiAuth: resolution.config.auth?.allowUnauthenticatedInDevelopment === true
|
|
1580
2316
|
};
|
|
1581
2317
|
}
|
|
1582
2318
|
resolveDevelopmentAuthSecret(env) {
|
|
1583
|
-
const configuredSecret = env.AUTH_SECRET
|
|
2319
|
+
const configuredSecret = env.AUTH_SECRET;
|
|
1584
2320
|
if (configuredSecret && configuredSecret.trim().length > 0) return configuredSecret;
|
|
1585
2321
|
return DevAuthSettingsLoader.defaultDevelopmentAuthSecret;
|
|
1586
2322
|
}
|
|
@@ -1607,10 +2343,10 @@ var DevHttpProbe = class {
|
|
|
1607
2343
|
} catch {}
|
|
1608
2344
|
await setTimeout$1(50);
|
|
1609
2345
|
}
|
|
1610
|
-
throw new Error("Timed out waiting for dev
|
|
2346
|
+
throw new Error("Timed out waiting for the stable dev HTTP health check.");
|
|
1611
2347
|
}
|
|
1612
2348
|
/**
|
|
1613
|
-
* Polls until the runtime
|
|
2349
|
+
* Polls until the active disposable runtime serves bootstrap summary through the stable CLI dev endpoint.
|
|
1614
2350
|
*/
|
|
1615
2351
|
async waitUntilBootstrapSummaryReady(gatewayBaseUrl) {
|
|
1616
2352
|
const url = `${gatewayBaseUrl.replace(/\/$/, "")}/api/dev/bootstrap-summary`;
|
|
@@ -1630,14 +2366,17 @@ var DevHttpProbe = class {
|
|
|
1630
2366
|
//#endregion
|
|
1631
2367
|
//#region src/dev/DevNextHostEnvironmentBuilder.ts
|
|
1632
2368
|
var DevNextHostEnvironmentBuilder = class {
|
|
1633
|
-
constructor(consumerEnvLoader, sourceMapNodeOptions) {
|
|
2369
|
+
constructor(consumerEnvLoader, sourceMapNodeOptions, frontendAuthSnapshotFactory = new CodemationFrontendAuthSnapshotFactory$1(), frontendAppConfigJsonCodec = new FrontendAppConfigJsonCodec$1()) {
|
|
1634
2370
|
this.consumerEnvLoader = consumerEnvLoader;
|
|
1635
2371
|
this.sourceMapNodeOptions = sourceMapNodeOptions;
|
|
2372
|
+
this.frontendAuthSnapshotFactory = frontendAuthSnapshotFactory;
|
|
2373
|
+
this.frontendAppConfigJsonCodec = frontendAppConfigJsonCodec;
|
|
1636
2374
|
}
|
|
1637
2375
|
buildConsumerUiProxy(args) {
|
|
1638
2376
|
return {
|
|
1639
2377
|
...this.build({
|
|
1640
2378
|
authConfigJson: args.authConfigJson,
|
|
2379
|
+
authSecret: args.authSecret,
|
|
1641
2380
|
consumerRoot: args.consumerRoot,
|
|
1642
2381
|
developmentServerToken: args.developmentServerToken,
|
|
1643
2382
|
nextPort: args.nextPort,
|
|
@@ -1646,23 +2385,33 @@ var DevNextHostEnvironmentBuilder = class {
|
|
|
1646
2385
|
websocketPort: args.websocketPort,
|
|
1647
2386
|
consumerOutputManifestPath: args.consumerOutputManifestPath
|
|
1648
2387
|
}),
|
|
2388
|
+
HOSTNAME: "127.0.0.1",
|
|
1649
2389
|
AUTH_SECRET: args.authSecret,
|
|
1650
|
-
AUTH_URL: args.publicBaseUrl
|
|
1651
|
-
NEXTAUTH_SECRET: args.authSecret,
|
|
1652
|
-
NEXTAUTH_URL: args.publicBaseUrl
|
|
2390
|
+
AUTH_URL: args.publicBaseUrl
|
|
1653
2391
|
};
|
|
1654
2392
|
}
|
|
1655
2393
|
build(args) {
|
|
1656
2394
|
const merged = this.consumerEnvLoader.mergeConsumerRootIntoProcessEnvironment(args.consumerRoot, process$1.env);
|
|
1657
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
|
+
});
|
|
1658
2405
|
return {
|
|
1659
2406
|
...merged,
|
|
1660
2407
|
PORT: String(args.nextPort),
|
|
1661
|
-
CODEMATION_AUTH_CONFIG_JSON: args.authConfigJson,
|
|
1662
2408
|
CODEMATION_CONSUMER_ROOT: args.consumerRoot,
|
|
1663
2409
|
CODEMATION_CONSUMER_OUTPUT_MANIFEST_PATH: manifestPath,
|
|
1664
|
-
|
|
1665
|
-
|
|
2410
|
+
CODEMATION_FRONTEND_APP_CONFIG_JSON: this.frontendAppConfigJsonCodec.serialize({
|
|
2411
|
+
auth: authSnapshot,
|
|
2412
|
+
productName: "Codemation",
|
|
2413
|
+
logoUrl: null
|
|
2414
|
+
}),
|
|
1666
2415
|
CODEMATION_WS_PORT: String(args.websocketPort),
|
|
1667
2416
|
NEXT_PUBLIC_CODEMATION_WS_PORT: String(args.websocketPort),
|
|
1668
2417
|
CODEMATION_DEV_SERVER_TOKEN: args.developmentServerToken,
|
|
@@ -1673,6 +2422,10 @@ var DevNextHostEnvironmentBuilder = class {
|
|
|
1673
2422
|
...args.runtimeDevUrl !== void 0 && args.runtimeDevUrl.trim().length > 0 ? { CODEMATION_RUNTIME_DEV_URL: args.runtimeDevUrl.trim() } : {}
|
|
1674
2423
|
};
|
|
1675
2424
|
}
|
|
2425
|
+
parseAuthConfig(authConfigJson) {
|
|
2426
|
+
if (authConfigJson.trim().length === 0) return;
|
|
2427
|
+
return JSON.parse(authConfigJson) ?? void 0;
|
|
2428
|
+
}
|
|
1676
2429
|
};
|
|
1677
2430
|
|
|
1678
2431
|
//#endregion
|
|
@@ -1686,7 +2439,7 @@ var DevSessionPortsResolver = class {
|
|
|
1686
2439
|
const nextPort = this.listenPorts.resolvePrimaryApplicationPort(args.portEnv);
|
|
1687
2440
|
return {
|
|
1688
2441
|
nextPort,
|
|
1689
|
-
gatewayPort: this.listenPorts.parsePositiveInteger(args.gatewayPortEnv) ?? (args.devMode === "
|
|
2442
|
+
gatewayPort: this.listenPorts.parsePositiveInteger(args.gatewayPortEnv) ?? (args.devMode === "packaged-ui" ? nextPort : await this.loopbackPorts.allocate())
|
|
1690
2443
|
};
|
|
1691
2444
|
}
|
|
1692
2445
|
};
|
|
@@ -1697,86 +2450,48 @@ var DevSessionPortsResolver = class {
|
|
|
1697
2450
|
* Bundles dependencies for {@link DevCommand} so the command stays a thin orchestrator.
|
|
1698
2451
|
*/
|
|
1699
2452
|
var DevSessionServices = class {
|
|
1700
|
-
constructor(consumerEnvLoader, sourceMapNodeOptions, sessionPorts, loopbackPortAllocator, devHttpProbe,
|
|
2453
|
+
constructor(consumerEnvLoader, sourceMapNodeOptions, sessionPorts, loopbackPortAllocator, devHttpProbe, devAuthLoader, nextHostEnvBuilder, watchRootsResolver, sourceChangeClassifier) {
|
|
1701
2454
|
this.consumerEnvLoader = consumerEnvLoader;
|
|
1702
2455
|
this.sourceMapNodeOptions = sourceMapNodeOptions;
|
|
1703
2456
|
this.sessionPorts = sessionPorts;
|
|
1704
2457
|
this.loopbackPortAllocator = loopbackPortAllocator;
|
|
1705
2458
|
this.devHttpProbe = devHttpProbe;
|
|
1706
|
-
this.runtimeEntrypointResolver = runtimeEntrypointResolver;
|
|
1707
2459
|
this.devAuthLoader = devAuthLoader;
|
|
1708
2460
|
this.nextHostEnvBuilder = nextHostEnvBuilder;
|
|
1709
2461
|
this.watchRootsResolver = watchRootsResolver;
|
|
1710
2462
|
this.sourceChangeClassifier = sourceChangeClassifier;
|
|
1711
|
-
this.sourceRestartCoordinator = sourceRestartCoordinator;
|
|
1712
2463
|
}
|
|
1713
2464
|
};
|
|
1714
2465
|
|
|
1715
2466
|
//#endregion
|
|
1716
2467
|
//#region src/dev/DevSourceChangeClassifier.ts
|
|
1717
|
-
var DevSourceChangeClassifier = class {
|
|
2468
|
+
var DevSourceChangeClassifier = class DevSourceChangeClassifier {
|
|
2469
|
+
static configFileNames = new Set([
|
|
2470
|
+
"codemation.config.ts",
|
|
2471
|
+
"codemation.config.js",
|
|
2472
|
+
"codemation.config.mjs"
|
|
2473
|
+
]);
|
|
1718
2474
|
shouldRepublishConsumerOutput(args) {
|
|
1719
2475
|
const resolvedConsumerRoot = path.resolve(args.consumerRoot);
|
|
1720
2476
|
return args.changedPaths.some((changedPath) => this.isPathInsideDirectory(changedPath, resolvedConsumerRoot));
|
|
1721
2477
|
}
|
|
1722
|
-
|
|
1723
|
-
const
|
|
1724
|
-
return args.changedPaths.some((changedPath) =>
|
|
1725
|
-
}
|
|
1726
|
-
resolveConfigPaths(consumerRoot) {
|
|
1727
|
-
const resolvedConsumerRoot = path.resolve(consumerRoot);
|
|
1728
|
-
return [
|
|
1729
|
-
path.resolve(resolvedConsumerRoot, "codemation.config.ts"),
|
|
1730
|
-
path.resolve(resolvedConsumerRoot, "codemation.config.js"),
|
|
1731
|
-
path.resolve(resolvedConsumerRoot, "src", "codemation.config.ts"),
|
|
1732
|
-
path.resolve(resolvedConsumerRoot, "src", "codemation.config.js")
|
|
1733
|
-
];
|
|
2478
|
+
requiresUiRestart(args) {
|
|
2479
|
+
const resolvedConsumerRoot = path.resolve(args.consumerRoot);
|
|
2480
|
+
return args.changedPaths.some((changedPath) => this.pathRequiresUiRestart(path.resolve(changedPath), resolvedConsumerRoot));
|
|
1734
2481
|
}
|
|
1735
2482
|
isPathInsideDirectory(filePath, directoryPath) {
|
|
1736
2483
|
const resolvedFilePath = path.resolve(filePath);
|
|
1737
2484
|
const relativePath = path.relative(directoryPath, resolvedFilePath);
|
|
1738
2485
|
return relativePath.length === 0 || !relativePath.startsWith("..") && !path.isAbsolute(relativePath);
|
|
1739
2486
|
}
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
this.cliLogger = cliLogger;
|
|
1749
|
-
}
|
|
1750
|
-
async runHandshakeAfterSourceChange(gatewayBaseUrl, developmentServerToken) {
|
|
1751
|
-
const restartStarted = performance.now();
|
|
1752
|
-
try {
|
|
1753
|
-
await this.gatewayNotifier.notify({
|
|
1754
|
-
gatewayBaseUrl,
|
|
1755
|
-
developmentServerToken,
|
|
1756
|
-
payload: { kind: "buildStarted" }
|
|
1757
|
-
});
|
|
1758
|
-
await this.gatewayNotifier.notify({
|
|
1759
|
-
gatewayBaseUrl,
|
|
1760
|
-
developmentServerToken,
|
|
1761
|
-
payload: {
|
|
1762
|
-
kind: "buildCompleted",
|
|
1763
|
-
buildVersion: `${Date.now()}-${process$1.pid}`
|
|
1764
|
-
}
|
|
1765
|
-
});
|
|
1766
|
-
const totalMs = performance.now() - restartStarted;
|
|
1767
|
-
this.performanceDiagnosticsLogger.info(`triggered source-based runtime restart timingMs={total:${totalMs.toFixed(1)}}`);
|
|
1768
|
-
} catch (error) {
|
|
1769
|
-
const exception = error instanceof Error ? error : new Error(String(error));
|
|
1770
|
-
await this.gatewayNotifier.notify({
|
|
1771
|
-
gatewayBaseUrl,
|
|
1772
|
-
developmentServerToken,
|
|
1773
|
-
payload: {
|
|
1774
|
-
kind: "buildFailed",
|
|
1775
|
-
message: exception.message
|
|
1776
|
-
}
|
|
1777
|
-
});
|
|
1778
|
-
this.cliLogger.error("source-based runtime restart request failed", exception);
|
|
1779
|
-
}
|
|
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;
|
|
1780
2495
|
}
|
|
1781
2496
|
};
|
|
1782
2497
|
|
|
@@ -1785,7 +2500,7 @@ var DevSourceRestartCoordinator = class {
|
|
|
1785
2500
|
var LoopbackPortAllocator = class {
|
|
1786
2501
|
async allocate() {
|
|
1787
2502
|
return await new Promise((resolve, reject) => {
|
|
1788
|
-
const server = createServer();
|
|
2503
|
+
const server = createServer$1();
|
|
1789
2504
|
server.once("error", reject);
|
|
1790
2505
|
server.listen(0, "127.0.0.1", () => {
|
|
1791
2506
|
const address = server.address();
|
|
@@ -1801,52 +2516,20 @@ var LoopbackPortAllocator = class {
|
|
|
1801
2516
|
}
|
|
1802
2517
|
};
|
|
1803
2518
|
|
|
1804
|
-
//#endregion
|
|
1805
|
-
//#region src/dev/RuntimeToolEntrypointResolver.ts
|
|
1806
|
-
var RuntimeToolEntrypointResolver = class {
|
|
1807
|
-
require = createRequire(import.meta.url);
|
|
1808
|
-
async resolve(args) {
|
|
1809
|
-
const sourceEntrypointPath = path.resolve(args.repoRoot, args.sourceEntrypoint);
|
|
1810
|
-
if (await this.exists(sourceEntrypointPath)) return {
|
|
1811
|
-
command: process$1.execPath,
|
|
1812
|
-
args: [
|
|
1813
|
-
"--import",
|
|
1814
|
-
"tsx",
|
|
1815
|
-
sourceEntrypointPath
|
|
1816
|
-
],
|
|
1817
|
-
env: { TSX_TSCONFIG_PATH: path.resolve(args.repoRoot, "tsconfig.codemation-tsx.json") }
|
|
1818
|
-
};
|
|
1819
|
-
return {
|
|
1820
|
-
command: process$1.execPath,
|
|
1821
|
-
args: [this.require.resolve(args.packageName)],
|
|
1822
|
-
env: {}
|
|
1823
|
-
};
|
|
1824
|
-
}
|
|
1825
|
-
async exists(filePath) {
|
|
1826
|
-
try {
|
|
1827
|
-
await access(filePath);
|
|
1828
|
-
return true;
|
|
1829
|
-
} catch {
|
|
1830
|
-
return false;
|
|
1831
|
-
}
|
|
1832
|
-
}
|
|
1833
|
-
};
|
|
1834
|
-
|
|
1835
2519
|
//#endregion
|
|
1836
2520
|
//#region src/dev/WatchRootsResolver.ts
|
|
1837
2521
|
var WatchRootsResolver = class {
|
|
1838
2522
|
resolve(args) {
|
|
1839
|
-
if (args.devMode === "
|
|
2523
|
+
if (args.devMode === "packaged-ui") return [args.consumerRoot];
|
|
1840
2524
|
return [
|
|
1841
2525
|
args.consumerRoot,
|
|
2526
|
+
path.resolve(args.repoRoot, "packages", "cli"),
|
|
1842
2527
|
path.resolve(args.repoRoot, "packages", "core"),
|
|
1843
2528
|
path.resolve(args.repoRoot, "packages", "core-nodes"),
|
|
1844
2529
|
path.resolve(args.repoRoot, "packages", "core-nodes-gmail"),
|
|
1845
2530
|
path.resolve(args.repoRoot, "packages", "eventbus-redis"),
|
|
1846
2531
|
path.resolve(args.repoRoot, "packages", "host"),
|
|
1847
|
-
path.resolve(args.repoRoot, "packages", "node-example")
|
|
1848
|
-
path.resolve(args.repoRoot, "packages", "queue-bullmq"),
|
|
1849
|
-
path.resolve(args.repoRoot, "packages", "runtime-dev")
|
|
2532
|
+
path.resolve(args.repoRoot, "packages", "node-example")
|
|
1850
2533
|
];
|
|
1851
2534
|
}
|
|
1852
2535
|
};
|
|
@@ -1854,16 +2537,12 @@ var WatchRootsResolver = class {
|
|
|
1854
2537
|
//#endregion
|
|
1855
2538
|
//#region src/dev/Builder.ts
|
|
1856
2539
|
var DevSessionServicesBuilder = class {
|
|
1857
|
-
constructor(loggerFactory$1) {
|
|
1858
|
-
this.loggerFactory = loggerFactory$1;
|
|
1859
|
-
}
|
|
1860
2540
|
build() {
|
|
1861
2541
|
const consumerEnvLoader = new ConsumerEnvLoader();
|
|
1862
2542
|
const sourceMapNodeOptions = new SourceMapNodeOptions();
|
|
1863
2543
|
const listenPortResolver = new ListenPortResolver();
|
|
1864
2544
|
const loopbackPortAllocator = new LoopbackPortAllocator();
|
|
1865
|
-
|
|
1866
|
-
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 DevSourceChangeClassifier(), 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());
|
|
1867
2546
|
}
|
|
1868
2547
|
};
|
|
1869
2548
|
|
|
@@ -2136,14 +2815,17 @@ var CliProgram = class {
|
|
|
2136
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) => {
|
|
2137
2816
|
await this.buildCommand.execute(resolveConsumerRoot(opts.consumerRoot), this.buildOptionsParser.parse(opts));
|
|
2138
2817
|
});
|
|
2139
|
-
program.command("dev", { isDefault: true }).description("Start the dev
|
|
2140
|
-
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
|
+
});
|
|
2141
2823
|
});
|
|
2142
|
-
const serve = program.command("serve").description("Run production web or worker processes (no dev watchers).");
|
|
2143
|
-
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) => {
|
|
2144
2826
|
await this.serveWebCommand.execute(resolveConsumerRoot(opts.consumerRoot), this.buildOptionsParser.parse(opts));
|
|
2145
2827
|
});
|
|
2146
|
-
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) => {
|
|
2147
2829
|
await this.serveWorkerCommand.execute(resolveConsumerRoot(opts.consumerRoot), opts.config);
|
|
2148
2830
|
});
|
|
2149
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) => {
|
|
@@ -2216,7 +2898,9 @@ var NextHostConsumerServerCommandFactory = class {
|
|
|
2216
2898
|
args: [
|
|
2217
2899
|
"exec",
|
|
2218
2900
|
"next",
|
|
2219
|
-
"start"
|
|
2901
|
+
"start",
|
|
2902
|
+
"-H",
|
|
2903
|
+
"127.0.0.1"
|
|
2220
2904
|
],
|
|
2221
2905
|
cwd: args.nextHostRoot
|
|
2222
2906
|
};
|
|
@@ -2235,8 +2919,12 @@ var NextHostConsumerServerCommandFactory = class {
|
|
|
2235
2919
|
//#region src/runtime/TypeScriptRuntimeConfigurator.ts
|
|
2236
2920
|
var TypeScriptRuntimeConfigurator = class {
|
|
2237
2921
|
configure(repoRoot) {
|
|
2922
|
+
if (this.hasExplicitOverride()) return;
|
|
2238
2923
|
process$1.env.CODEMATION_TSCONFIG_PATH = path.resolve(repoRoot, "tsconfig.base.json");
|
|
2239
2924
|
}
|
|
2925
|
+
hasExplicitOverride() {
|
|
2926
|
+
return typeof process$1.env.CODEMATION_TSCONFIG_PATH === "string" && process$1.env.CODEMATION_TSCONFIG_PATH.length > 0;
|
|
2927
|
+
}
|
|
2240
2928
|
};
|
|
2241
2929
|
|
|
2242
2930
|
//#endregion
|
|
@@ -2288,22 +2976,20 @@ var CliDatabaseUrlDescriptor = class {
|
|
|
2288
2976
|
//#endregion
|
|
2289
2977
|
//#region src/bootstrap/CodemationCliApplicationSession.ts
|
|
2290
2978
|
/**
|
|
2291
|
-
* Opens
|
|
2979
|
+
* Opens an app container with persistence + command/query buses (no HTTP/WebSocket servers),
|
|
2292
2980
|
* for CLI tools that dispatch application commands or queries (e.g. user admin).
|
|
2293
2981
|
*/
|
|
2294
2982
|
var CodemationCliApplicationSession = class CodemationCliApplicationSession {
|
|
2295
|
-
constructor(
|
|
2296
|
-
this.
|
|
2983
|
+
constructor(container) {
|
|
2984
|
+
this.container = container;
|
|
2297
2985
|
}
|
|
2298
2986
|
static async open(args) {
|
|
2299
|
-
const
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
}));
|
|
2306
|
-
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);
|
|
2307
2993
|
}
|
|
2308
2994
|
getPrismaClient() {
|
|
2309
2995
|
const container = this.getContainer();
|
|
@@ -2317,10 +3003,10 @@ var CodemationCliApplicationSession = class CodemationCliApplicationSession {
|
|
|
2317
3003
|
return this.getContainer().resolve(ApplicationTokens.QueryBus);
|
|
2318
3004
|
}
|
|
2319
3005
|
async close() {
|
|
2320
|
-
await this.
|
|
3006
|
+
await this.container.resolve(AppContainerLifecycle).stop({ stopWebsocketServer: false });
|
|
2321
3007
|
}
|
|
2322
3008
|
getContainer() {
|
|
2323
|
-
return this.
|
|
3009
|
+
return this.container;
|
|
2324
3010
|
}
|
|
2325
3011
|
};
|
|
2326
3012
|
|
|
@@ -2330,37 +3016,26 @@ var CodemationCliApplicationSession = class CodemationCliApplicationSession {
|
|
|
2330
3016
|
* Shared env/config/session wiring for `codemation user *` commands (local auth + database).
|
|
2331
3017
|
*/
|
|
2332
3018
|
var UserAdminCliBootstrap = class {
|
|
2333
|
-
constructor(
|
|
2334
|
-
this.
|
|
3019
|
+
constructor(appConfigLoader, pathResolver, consumerDotenvLoader, tsconfigPreparation) {
|
|
3020
|
+
this.appConfigLoader = appConfigLoader;
|
|
2335
3021
|
this.pathResolver = pathResolver;
|
|
2336
3022
|
this.consumerDotenvLoader = consumerDotenvLoader;
|
|
2337
3023
|
this.tsconfigPreparation = tsconfigPreparation;
|
|
2338
|
-
this.databasePersistenceResolver = databasePersistenceResolver;
|
|
2339
3024
|
}
|
|
2340
3025
|
async withSession(options, fn) {
|
|
2341
3026
|
const consumerRoot = options.consumerRoot ?? process.cwd();
|
|
2342
3027
|
this.consumerDotenvLoader.load(consumerRoot);
|
|
2343
3028
|
this.tsconfigPreparation.applyWorkspaceTsconfigForTsxIfPresent(consumerRoot);
|
|
2344
|
-
const
|
|
3029
|
+
const paths = await this.pathResolver.resolve(consumerRoot);
|
|
3030
|
+
const loadResult = await this.appConfigLoader.load({
|
|
2345
3031
|
consumerRoot,
|
|
2346
|
-
|
|
2347
|
-
});
|
|
2348
|
-
if (resolution.config.auth?.kind !== "local") throw new Error("Codemation user commands require CodemationConfig.auth.kind to be \"local\".");
|
|
2349
|
-
if (this.databasePersistenceResolver.resolve({
|
|
2350
|
-
runtimeConfig: resolution.config.runtime ?? {},
|
|
3032
|
+
repoRoot: paths.repoRoot,
|
|
2351
3033
|
env: process.env,
|
|
2352
|
-
|
|
2353
|
-
}).kind === "none") throw new Error("Database persistence is not configured. Set CodemationConfig.runtime.database (postgresql URL or PGlite).");
|
|
2354
|
-
const paths = await this.pathResolver.resolve(consumerRoot);
|
|
2355
|
-
const session = await CodemationCliApplicationSession.open({
|
|
2356
|
-
resolution,
|
|
2357
|
-
bootstrap: new CodemationBootstrapRequest({
|
|
2358
|
-
repoRoot: paths.repoRoot,
|
|
2359
|
-
consumerRoot,
|
|
2360
|
-
env: process.env,
|
|
2361
|
-
workflowSources: resolution.workflowSources
|
|
2362
|
-
})
|
|
3034
|
+
configPathOverride: options.configPath
|
|
2363
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 });
|
|
2364
3039
|
try {
|
|
2365
3040
|
return await fn(session);
|
|
2366
3041
|
} finally {
|
|
@@ -2414,6 +3089,7 @@ const loggerFactory = new ServerLoggerFactory(logLevelPolicyFactory);
|
|
|
2414
3089
|
var CliProgramFactory = class {
|
|
2415
3090
|
create() {
|
|
2416
3091
|
const cliLogger = loggerFactory.create("codemation-cli");
|
|
3092
|
+
const appConfigLoader = new AppConfigLoader();
|
|
2417
3093
|
const pathResolver = new CliPathResolver();
|
|
2418
3094
|
const pluginDiscovery = new CodemationPluginDiscovery();
|
|
2419
3095
|
const artifactsPublisher = new ConsumerBuildArtifactsPublisher();
|
|
@@ -2421,15 +3097,15 @@ var CliProgramFactory = class {
|
|
|
2421
3097
|
const outputBuilderLoader = new ConsumerOutputBuilderLoader();
|
|
2422
3098
|
const sourceMapNodeOptions = new SourceMapNodeOptions();
|
|
2423
3099
|
const nextHostConsumerServerCommandFactory = new NextHostConsumerServerCommandFactory();
|
|
3100
|
+
const devSessionServices = new DevSessionServicesBuilder().build();
|
|
2424
3101
|
const tsconfigPreparation = new ConsumerCliTsconfigPreparation();
|
|
2425
|
-
const
|
|
2426
|
-
const userAdminBootstrap = new UserAdminCliBootstrap(new CodemationConsumerConfigLoader(), pathResolver, new UserAdminConsumerDotenvLoader(), tsconfigPreparation, databasePersistenceResolver);
|
|
3102
|
+
const userAdminBootstrap = new UserAdminCliBootstrap(appConfigLoader, pathResolver, new UserAdminConsumerDotenvLoader(), tsconfigPreparation);
|
|
2427
3103
|
const hostPackageRoot = new HostPackageRootResolver().resolveHostPackageRoot();
|
|
2428
3104
|
const userAdminCliOptionsParser = new UserAdminCliOptionsParser();
|
|
2429
3105
|
const databaseMigrationsApplyService = new DatabaseMigrationsApplyService(cliLogger, new UserAdminConsumerDotenvLoader(), tsconfigPreparation, new CodemationConsumerConfigLoader(), new ConsumerDatabaseConnectionResolver(), new CliDatabaseUrlDescriptor(), hostPackageRoot, new PrismaMigrationDeployer());
|
|
2430
3106
|
const buildOptionsParser = new ConsumerBuildOptionsParser();
|
|
2431
3107
|
const devConsumerPublishBootstrap = new DevConsumerPublishBootstrap(cliLogger, pluginDiscovery, artifactsPublisher, outputBuilderLoader, buildOptionsParser);
|
|
2432
|
-
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));
|
|
2433
3109
|
}
|
|
2434
3110
|
};
|
|
2435
3111
|
|