@codemation/cli 0.0.5 → 0.0.11
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-BAnFX1wL.js} +1105 -366
- package/dist/bin.js +1 -1
- package/dist/index.d.ts +655 -207
- package/dist/index.js +1 -1
- package/package.json +14 -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 +203 -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 +457 -0
- package/src/dev/CliDevProxyServerFactory.ts +10 -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/ListenPortConflictDescriber.ts +83 -0
- package/src/dev/WatchRootsResolver.ts +6 -4
- package/src/runtime/NextHostConsumerServerCommandFactory.ts +11 -2
- 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,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
CodemationConsumerConfigLoader,
|
|
3
|
+
CodemationFrontendAuthSnapshotFactory,
|
|
4
|
+
CodemationPluginDiscovery,
|
|
5
|
+
FrontendAppConfigJsonCodec,
|
|
6
|
+
} from "@codemation/host/server";
|
|
2
7
|
import { spawn } from "node:child_process";
|
|
3
8
|
import { createRequire } from "node:module";
|
|
4
9
|
import path from "node:path";
|
|
@@ -19,6 +24,7 @@ export class ServeWebCommand {
|
|
|
19
24
|
|
|
20
25
|
constructor(
|
|
21
26
|
private readonly pathResolver: CliPathResolver,
|
|
27
|
+
private readonly configLoader: CodemationConsumerConfigLoader,
|
|
22
28
|
private readonly pluginDiscovery: CodemationPluginDiscovery,
|
|
23
29
|
private readonly artifactsPublisher: ConsumerBuildArtifactsPublisher,
|
|
24
30
|
private readonly tsRuntime: TypeScriptRuntimeConfigurator,
|
|
@@ -27,6 +33,8 @@ export class ServeWebCommand {
|
|
|
27
33
|
private readonly envLoader: ConsumerEnvLoader,
|
|
28
34
|
private readonly listenPortResolver: ListenPortResolver,
|
|
29
35
|
private readonly nextHostConsumerServerCommandFactory: NextHostConsumerServerCommandFactory,
|
|
36
|
+
private readonly frontendAuthSnapshotFactory: CodemationFrontendAuthSnapshotFactory,
|
|
37
|
+
private readonly frontendAppConfigJsonCodec: FrontendAppConfigJsonCodec,
|
|
30
38
|
) {}
|
|
31
39
|
|
|
32
40
|
async execute(consumerRoot: string, buildOptions: ConsumerBuildOptions): Promise<void> {
|
|
@@ -39,6 +47,18 @@ export class ServeWebCommand {
|
|
|
39
47
|
const nextHostRoot = path.dirname(this.require.resolve("@codemation/next-host/package.json"));
|
|
40
48
|
const nextHostCommand = await this.nextHostConsumerServerCommandFactory.create({ nextHostRoot });
|
|
41
49
|
const consumerEnv = this.envLoader.load(paths.consumerRoot);
|
|
50
|
+
const configResolution = await this.configLoader.load({ consumerRoot: paths.consumerRoot });
|
|
51
|
+
const frontendAuthSnapshot = this.frontendAuthSnapshotFactory.createFromResolvedInputs({
|
|
52
|
+
authConfig: configResolution.config.auth,
|
|
53
|
+
env: {
|
|
54
|
+
...process.env,
|
|
55
|
+
...consumerEnv,
|
|
56
|
+
},
|
|
57
|
+
uiAuthEnabled: !(
|
|
58
|
+
consumerEnv.NODE_ENV !== "production" &&
|
|
59
|
+
configResolution.config.auth?.allowUnauthenticatedInDevelopment === true
|
|
60
|
+
),
|
|
61
|
+
});
|
|
42
62
|
const nextPort = this.listenPortResolver.resolvePrimaryApplicationPort(process.env.PORT);
|
|
43
63
|
const websocketPort = this.listenPortResolver.resolveWebsocketPortRelativeToHttp({
|
|
44
64
|
nextPort,
|
|
@@ -52,6 +72,11 @@ export class ServeWebCommand {
|
|
|
52
72
|
...process.env,
|
|
53
73
|
...consumerEnv,
|
|
54
74
|
PORT: String(nextPort),
|
|
75
|
+
CODEMATION_FRONTEND_APP_CONFIG_JSON: this.frontendAppConfigJsonCodec.serialize({
|
|
76
|
+
auth: frontendAuthSnapshot,
|
|
77
|
+
productName: "Codemation",
|
|
78
|
+
logoUrl: null,
|
|
79
|
+
}),
|
|
55
80
|
CODEMATION_CONSUMER_OUTPUT_MANIFEST_PATH: manifest.manifestPath,
|
|
56
81
|
CODEMATION_CONSUMER_ROOT: paths.consumerRoot,
|
|
57
82
|
CODEMATION_WS_PORT: String(websocketPort),
|
|
@@ -1,40 +1,56 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import path from "node:path";
|
|
1
|
+
import { AppContainerFactory, WorkerRuntime } from "@codemation/host";
|
|
2
|
+
import { AppConfigLoader } from "@codemation/host/server";
|
|
4
3
|
import process from "node:process";
|
|
5
|
-
|
|
6
|
-
import { SourceMapNodeOptions } from "../runtime/SourceMapNodeOptions";
|
|
4
|
+
import { CliPathResolver } from "../path/CliPathResolver";
|
|
7
5
|
|
|
8
6
|
export class ServeWorkerCommand {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
constructor(
|
|
8
|
+
private readonly pathResolver: CliPathResolver,
|
|
9
|
+
private readonly appConfigLoader: AppConfigLoader,
|
|
10
|
+
private readonly appContainerFactory: AppContainerFactory,
|
|
11
|
+
) {}
|
|
12
12
|
|
|
13
13
|
async execute(consumerRoot: string, configPathOverride?: string): Promise<void> {
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
const paths = await this.pathResolver.resolve(consumerRoot);
|
|
15
|
+
const loadResult = await this.appConfigLoader.load({
|
|
16
|
+
consumerRoot,
|
|
17
|
+
repoRoot: paths.repoRoot,
|
|
18
|
+
env: process.env,
|
|
19
|
+
configPathOverride,
|
|
20
|
+
});
|
|
21
|
+
if (loadResult.appConfig.scheduler.kind !== "bullmq") {
|
|
22
|
+
throw new Error('Worker mode requires runtime.scheduler.kind = "bullmq".');
|
|
19
23
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
stdio: "inherit",
|
|
24
|
-
env: {
|
|
25
|
-
...process.env,
|
|
26
|
-
NODE_OPTIONS: this.sourceMapNodeOptions.appendToNodeOptions(process.env.NODE_OPTIONS),
|
|
27
|
-
},
|
|
24
|
+
const container = await this.appContainerFactory.create({
|
|
25
|
+
appConfig: loadResult.appConfig,
|
|
26
|
+
sharedWorkflowWebsocketServer: null,
|
|
28
27
|
});
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
});
|
|
37
|
-
child.on("error", reject);
|
|
28
|
+
const workerQueues =
|
|
29
|
+
loadResult.appConfig.scheduler.workerQueues.length > 0
|
|
30
|
+
? loadResult.appConfig.scheduler.workerQueues
|
|
31
|
+
: ["default"];
|
|
32
|
+
const handle = await container.resolve(WorkerRuntime).start(workerQueues);
|
|
33
|
+
await new Promise<void>((resolve) => {
|
|
34
|
+
this.bindSignals(handle.stop, resolve);
|
|
38
35
|
});
|
|
39
36
|
}
|
|
37
|
+
|
|
38
|
+
private bindSignals(stop: () => Promise<void>, resolve: () => void): void {
|
|
39
|
+
let stopping = false;
|
|
40
|
+
const onSignal = async (): Promise<void> => {
|
|
41
|
+
if (stopping) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
stopping = true;
|
|
45
|
+
try {
|
|
46
|
+
await stop();
|
|
47
|
+
} finally {
|
|
48
|
+
resolve();
|
|
49
|
+
process.exit(0);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
process.on("SIGINT", () => void onSignal());
|
|
53
|
+
process.on("SIGTERM", () => void onSignal());
|
|
54
|
+
process.on("SIGQUIT", () => void onSignal());
|
|
55
|
+
}
|
|
40
56
|
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import type { ChildProcess } from "node:child_process";
|
|
2
2
|
|
|
3
3
|
import type { DevResolvedAuthSettings } from "../dev/DevAuthSettingsLoader";
|
|
4
|
-
import type {
|
|
4
|
+
import type { DevApiRuntimeServerHandle } from "../dev/DevApiRuntimeFactory";
|
|
5
5
|
import type { CliPaths } from "../path/CliPathResolver";
|
|
6
6
|
|
|
7
|
-
export type DevMode = "
|
|
7
|
+
export type DevMode = "packaged-ui" | "watch-framework";
|
|
8
8
|
|
|
9
9
|
/** Mutable child process handles and stop coordination (shared across dev session helpers). */
|
|
10
10
|
export type DevMutableProcessState = {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
currentDevUi: ChildProcess | null;
|
|
12
|
+
currentPackagedUi: ChildProcess | null;
|
|
13
|
+
currentPackagedUiBaseUrl: string | null;
|
|
14
|
+
currentRuntime: DevApiRuntimeServerHandle | null;
|
|
15
|
+
isRestartingUi: boolean;
|
|
16
16
|
stopRequested: boolean;
|
|
17
17
|
stopResolve: (() => void) | null;
|
|
18
18
|
stopReject: ((error: Error) => void) | null;
|
|
@@ -26,9 +26,5 @@ export type DevPreparedRuntime = Readonly<{
|
|
|
26
26
|
gatewayPort: number;
|
|
27
27
|
authSettings: DevResolvedAuthSettings;
|
|
28
28
|
developmentServerToken: string;
|
|
29
|
-
gatewayEntrypoint: ResolvedRuntimeToolEntrypoint;
|
|
30
|
-
runtimeEntrypoint: ResolvedRuntimeToolEntrypoint;
|
|
31
|
-
runtimeWorkingDirectory: string;
|
|
32
|
-
discoveredPluginPackagesJson: string;
|
|
33
29
|
consumerEnv: Readonly<Record<string, string>>;
|
|
34
30
|
}>;
|
|
@@ -1,18 +1,64 @@
|
|
|
1
1
|
import type { CodemationConfig } from "@codemation/host";
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
2
|
+
import type { AppPersistenceConfig } from "@codemation/host/persistence";
|
|
3
|
+
import path from "node:path";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Resolves TCP PostgreSQL vs PGlite vs none from env + {@link CodemationConfig} (same rules as the host runtime).
|
|
7
7
|
*/
|
|
8
8
|
export class ConsumerDatabaseConnectionResolver {
|
|
9
|
-
|
|
9
|
+
resolve(processEnv: NodeJS.ProcessEnv, config: CodemationConfig, consumerRoot: string): AppPersistenceConfig {
|
|
10
|
+
const database = config.runtime?.database;
|
|
11
|
+
if (!database) {
|
|
12
|
+
return { kind: "none" };
|
|
13
|
+
}
|
|
14
|
+
const databaseKind = this.resolveDatabaseKind(database.kind, database.url, processEnv);
|
|
15
|
+
if (databaseKind === "postgresql") {
|
|
16
|
+
const databaseUrl = database.url?.trim() ?? "";
|
|
17
|
+
if (!databaseUrl) {
|
|
18
|
+
throw new Error('runtime.database.kind is "postgresql" but no database URL was set (runtime.database.url).');
|
|
19
|
+
}
|
|
20
|
+
return { kind: "postgresql", databaseUrl };
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
kind: "pglite",
|
|
24
|
+
dataDir: this.resolvePgliteDataDir(database.pgliteDataDir, processEnv, consumerRoot),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private resolveDatabaseKind(
|
|
29
|
+
configuredKind: "postgresql" | "pglite" | undefined,
|
|
30
|
+
databaseUrl: string | undefined,
|
|
31
|
+
env: NodeJS.ProcessEnv,
|
|
32
|
+
): "postgresql" | "pglite" {
|
|
33
|
+
const kindFromEnv = env.CODEMATION_DATABASE_KIND?.trim();
|
|
34
|
+
if (kindFromEnv === "postgresql" || kindFromEnv === "pglite") {
|
|
35
|
+
return kindFromEnv;
|
|
36
|
+
}
|
|
37
|
+
if (configuredKind) {
|
|
38
|
+
return configuredKind;
|
|
39
|
+
}
|
|
40
|
+
const trimmedUrl = databaseUrl?.trim();
|
|
41
|
+
if (trimmedUrl && (trimmedUrl.startsWith("postgresql://") || trimmedUrl.startsWith("postgres://"))) {
|
|
42
|
+
return "postgresql";
|
|
43
|
+
}
|
|
44
|
+
return "pglite";
|
|
45
|
+
}
|
|
10
46
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
47
|
+
private resolvePgliteDataDir(
|
|
48
|
+
configuredPath: string | undefined,
|
|
49
|
+
env: NodeJS.ProcessEnv,
|
|
50
|
+
consumerRoot: string,
|
|
51
|
+
): string {
|
|
52
|
+
const envPath = env.CODEMATION_PGLITE_DATA_DIR?.trim();
|
|
53
|
+
if (envPath && envPath.length > 0) {
|
|
54
|
+
return path.isAbsolute(envPath) ? envPath : path.resolve(consumerRoot, envPath);
|
|
55
|
+
}
|
|
56
|
+
const trimmedConfiguredPath = configuredPath?.trim();
|
|
57
|
+
if (trimmedConfiguredPath && trimmedConfiguredPath.length > 0) {
|
|
58
|
+
return path.isAbsolute(trimmedConfiguredPath)
|
|
59
|
+
? trimmedConfiguredPath
|
|
60
|
+
: path.resolve(consumerRoot, trimmedConfiguredPath);
|
|
61
|
+
}
|
|
62
|
+
return path.resolve(consumerRoot, ".codemation", "pglite");
|
|
17
63
|
}
|
|
18
64
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CodemationConsumerConfigLoader } from "@codemation/host/server";
|
|
2
|
-
import type {
|
|
2
|
+
import type { AppPersistenceConfig } from "@codemation/host/persistence";
|
|
3
3
|
import type { Logger } from "@codemation/host/next/server";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
|
|
@@ -9,7 +9,7 @@ import type { CliDatabaseUrlDescriptor } from "../user/CliDatabaseUrlDescriptor"
|
|
|
9
9
|
import type { UserAdminConsumerDotenvLoader } from "../user/UserAdminConsumerDotenvLoader";
|
|
10
10
|
|
|
11
11
|
export type DatabaseMigrationDeployer = {
|
|
12
|
-
deployPersistence(persistence:
|
|
12
|
+
deployPersistence(persistence: AppPersistenceConfig, env?: Readonly<NodeJS.ProcessEnv>): Promise<void>;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
/**
|
package/src/dev/Builder.ts
CHANGED
|
@@ -1,47 +1,34 @@
|
|
|
1
1
|
import { CodemationConsumerConfigLoader } from "@codemation/host/server";
|
|
2
|
-
import type { ServerLoggerFactory } from "@codemation/host/next/server";
|
|
3
2
|
|
|
4
3
|
import { ConsumerEnvLoader } from "../consumer/ConsumerEnvLoader";
|
|
5
4
|
import { ListenPortResolver } from "../runtime/ListenPortResolver";
|
|
6
5
|
import { SourceMapNodeOptions } from "../runtime/SourceMapNodeOptions";
|
|
7
6
|
|
|
8
|
-
import { DevelopmentGatewayNotifier } from "./DevelopmentGatewayNotifier";
|
|
9
7
|
import { DevAuthSettingsLoader } from "./DevAuthSettingsLoader";
|
|
10
8
|
import { DevHttpProbe } from "./DevHttpProbe";
|
|
11
9
|
import { DevNextHostEnvironmentBuilder } from "./DevNextHostEnvironmentBuilder";
|
|
12
10
|
import { DevSessionPortsResolver } from "./DevSessionPortsResolver";
|
|
13
11
|
import { DevSessionServices } from "./DevSessionServices";
|
|
14
12
|
import { DevSourceChangeClassifier } from "./DevSourceChangeClassifier";
|
|
15
|
-
import { DevSourceRestartCoordinator } from "./DevSourceRestartCoordinator";
|
|
16
13
|
import { LoopbackPortAllocator } from "./LoopbackPortAllocator";
|
|
17
|
-
import { RuntimeToolEntrypointResolver } from "./RuntimeToolEntrypointResolver";
|
|
18
14
|
import { WatchRootsResolver } from "./WatchRootsResolver";
|
|
19
15
|
|
|
20
16
|
export class DevSessionServicesBuilder {
|
|
21
|
-
constructor(private readonly loggerFactory: ServerLoggerFactory) {}
|
|
22
|
-
|
|
23
17
|
build(): DevSessionServices {
|
|
24
18
|
const consumerEnvLoader = new ConsumerEnvLoader();
|
|
25
19
|
const sourceMapNodeOptions = new SourceMapNodeOptions();
|
|
26
20
|
const listenPortResolver = new ListenPortResolver();
|
|
27
21
|
const loopbackPortAllocator = new LoopbackPortAllocator();
|
|
28
|
-
const cliLogger = this.loggerFactory.create("codemation-cli");
|
|
29
22
|
return new DevSessionServices(
|
|
30
23
|
consumerEnvLoader,
|
|
31
24
|
sourceMapNodeOptions,
|
|
32
25
|
new DevSessionPortsResolver(listenPortResolver, loopbackPortAllocator),
|
|
33
26
|
loopbackPortAllocator,
|
|
34
27
|
new DevHttpProbe(),
|
|
35
|
-
new
|
|
36
|
-
new DevAuthSettingsLoader(new CodemationConsumerConfigLoader()),
|
|
28
|
+
new DevAuthSettingsLoader(new CodemationConsumerConfigLoader(), consumerEnvLoader),
|
|
37
29
|
new DevNextHostEnvironmentBuilder(consumerEnvLoader, sourceMapNodeOptions),
|
|
38
30
|
new WatchRootsResolver(),
|
|
39
31
|
new DevSourceChangeClassifier(),
|
|
40
|
-
new DevSourceRestartCoordinator(
|
|
41
|
-
new DevelopmentGatewayNotifier(cliLogger),
|
|
42
|
-
this.loggerFactory.createPerformanceDiagnostics("codemation-cli.performance"),
|
|
43
|
-
cliLogger,
|
|
44
|
-
),
|
|
45
32
|
);
|
|
46
33
|
}
|
|
47
34
|
}
|