@geekmidas/cli 10.0.0-alpha.25 → 10.0.0-alpha.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -3,13 +3,13 @@ import { n as __require, t as __exportAll } from "./rolldown-runtime-BhDjJH2R.mj
3
3
  import { i as DEFAULT_CACHE, r as ConstructGenerator, s as isPartitionedRoutes, t as discover } from "./discover-0fhCbnk0.mjs";
4
4
  import { i as loadConfig, l as derivedApps, n as getAppNameFromCwd, o as loadWorkspaceConfig, r as loadAppConfig, s as parseModuleConfig } from "./config-DBGpRTUy.mjs";
5
5
  import { A as stripPublicPrefix, C as InvalidStages, D as stageProblems, E as deployedProblems, T as assertDeployedStage, a as getAppBuildOrder, k as getPublicEnvPrefix, o as getAppGkmConfig, s as getDependencyEnvVars, t as allConstructGlobs, v as getDeployTargetError, w as TEST_STAGE, y as isDeployTargetSupported } from "./workspace-Bu3xNCej.mjs";
6
- import { C as providerOf, S as eventsBackendFor, _ as COMPOSE_PATH, a as loadEnvFiles, b as resourceName, c as resolveServicePorts, d as backendsOf, f as constructGlobs, h as usesConstructs, i as isPortAvailable, l as rewriteUrlsWithPorts, m as reconcileWorkspace, n as createEntryWrapper, o as loadSecretsForApp, p as derivedContainers, r as findAvailablePort, s as prepareEntryCredentials, t as createCredentialsPreload, u as startWorkspaceServices, v as LOCAL_CA_PATH, w as storageBackendFor, x as cacheBackendFor, y as applyPostgres } from "./credentials-BpoOUa74.mjs";
6
+ import { C as providerOf, S as eventsBackendFor, _ as COMPOSE_PATH, a as loadEnvFiles, b as resourceName, c as resolveServicePorts, d as backendsOf, f as constructGlobs, h as usesConstructs, i as isPortAvailable, l as rewriteUrlsWithPorts, m as reconcileWorkspace, n as createEntryWrapper, o as loadSecretsForApp, p as derivedContainers, r as findAvailablePort, s as prepareEntryCredentials, t as createCredentialsPreload, u as startWorkspaceServices, v as LOCAL_CA_PATH, w as storageBackendFor, x as cacheBackendFor, y as applyPostgres } from "./credentials-DI9kJcaP.mjs";
7
7
  import { a as generateServiceCredentials, i as generateSecurePassword, n as generateConnectionUrls, o as rotateServicePassword, t as createStageSecrets } from "./generator-LfZU7NlU.mjs";
8
8
  import { c as getKeyPath, i as setCustomSecret, n as readStageSecrets, o as toEmbeddableSecrets, r as secretsExist, s as writeStageSecrets, t as maskPassword } from "./storage-TP0x118M.mjs";
9
9
  import { a as openapiCommand, c as EndpointGenerator, l as runtimeFor, n as generateOpenApi, o as resolveOpenApiConfig, s as OpenApiTsGenerator, t as OPENAPI_OUTPUT_PATH$1 } from "./openapi-DHQlstv6.mjs";
10
10
  import { i as withRoutes, r as withCompute } from "./emit-Bzq7JsMP.mjs";
11
11
  import { i as writeDockerEnvFromSecrets, r as generateFullstackCustomSecrets } from "./reconcile-gb1lz1Dk.mjs";
12
- import { a as isRemoteStore, n as pullStageSecrets, r as pushStageSecrets, t as NoStoredSecrets } from "./transfer-B88fTvnh.mjs";
12
+ import { a as isRemoteStore, n as pullStageSecrets, r as pushStageSecrets, t as NoStoredSecrets } from "./transfer-CAJs_vhu.mjs";
13
13
  import { createRequire } from "node:module";
14
14
  import { Command } from "commander";
15
15
  import { stdin, stdout } from "node:process";
@@ -39,7 +39,7 @@ import prompts from "prompts";
39
39
  import { EnvironmentParser } from "@geekmidas/envkit";
40
40
  import { serviceContext } from "@geekmidas/services";
41
41
  //#region package.json
42
- var version = "10.0.0-alpha.25";
42
+ var version = "10.0.0-alpha.26";
43
43
  //#endregion
44
44
  //#region src/auth/credentials.ts
45
45
  /**
@@ -653,7 +653,7 @@ async function devCommand(options) {
653
653
  }
654
654
  if (workspace && workspaceAppName) {
655
655
  const depEnv = getDependencyEnvVars(workspace, workspaceAppName);
656
- Object.assign(appSecrets, depEnv);
656
+ for (const [key, value] of Object.entries(depEnv)) appSecrets[key] ??= value;
657
657
  }
658
658
  if (Object.keys(appSecrets).length > 0) {
659
659
  const secretsDir = join(secretsRoot, ".gkm");
@@ -663,7 +663,7 @@ async function devCommand(options) {
663
663
  await writeFile(secretsJsonPath, JSON.stringify(appSecrets, null, 2));
664
664
  logger$11.log(`🔐 Loaded ${Object.keys(appSecrets).length} secret(s)`);
665
665
  }
666
- const devServer = new DevServer(resolved.providers[0], options.port ?? workspaceAppPort ?? 3e3, options.portExplicit ?? false, enableOpenApi, telescope, studio, runtime, appRoot, secretsJsonPath, initial.selfServing !== void 0);
666
+ const devServer = new DevServer(resolved.providers[0], options.port ?? workspaceAppPort ?? 3e3, options.portExplicit ?? workspaceAppPort !== void 0, enableOpenApi, telescope, studio, runtime, appRoot, secretsJsonPath, initial.selfServing !== void 0);
667
667
  await devServer.start();
668
668
  const hooksFile = (config.hooks?.server?.split("#"))?.[0];
669
669
  const normalizedPatterns = [config.constructs, ...hooksFile ? [hooksFile.endsWith(".ts") ? hooksFile : `${hooksFile}.ts`] : []].flat().filter((p) => typeof p === "string").map((p) => p.startsWith("./") ? p.slice(2) : p);
@@ -960,6 +960,7 @@ async function workspaceDevCommand(workspace, options) {
960
960
  }
961
961
  const rawSecrets = await loadDevSecrets(workspace);
962
962
  let secretsEnv;
963
+ const appUrls = {};
963
964
  if (usesConstructs(workspace)) {
964
965
  const reconciled = await reconcileWorkspace(workspace, { stage: workspace.stages.local });
965
966
  if (reconciled.changed && reconciled.plan.containers.length > 0) {
@@ -970,13 +971,22 @@ async function workspaceDevCommand(workspace, options) {
970
971
  ...rawSecrets,
971
972
  ...reconciled.env
972
973
  };
974
+ for (const resource of reconciled.plan.resources) {
975
+ if (resource.kind !== "rest-api" && resource.kind !== "site") continue;
976
+ const address = reconciled.env[resource.envKey];
977
+ if (address) appUrls[resource.id] = address;
978
+ }
973
979
  } else {
974
980
  const resolvedPorts = await resolveServicePorts(workspace.root);
975
981
  await startWorkspaceServices(workspace, resolvedPorts.dockerEnv, rawSecrets);
976
982
  secretsEnv = rewriteUrlsWithPorts(rawSecrets, resolvedPorts);
977
983
  }
978
984
  if (Object.keys(secretsEnv).length > 0) logger$11.log(` Loaded ${Object.keys(secretsEnv).length} secret(s)`);
979
- const dependencyEnv = generateAllDependencyEnvVars(workspace);
985
+ if (Object.keys(appUrls).length > 0) {
986
+ logger$11.log("🔒 App URLs:");
987
+ for (const [id, address] of Object.entries(appUrls)) logger$11.log(` ${id}: ${address}`);
988
+ }
989
+ const dependencyEnv = Object.fromEntries(Object.entries(generateAllDependencyEnvVars(workspace)).filter(([key]) => secretsEnv[key] === void 0));
980
990
  if (Object.keys(dependencyEnv).length > 0) {
981
991
  logger$11.log("📡 Dependency URLs:");
982
992
  for (const [key, value] of Object.entries(dependencyEnv)) logger$11.log(` ${key}=${value}`);
@@ -1027,6 +1037,17 @@ async function workspaceDevCommand(workspace, options) {
1027
1037
  NODE_ENV: "development",
1028
1038
  ...configPath ? { GKM_CONFIG_PATH: configPath } : {}
1029
1039
  };
1040
+ const scoped = options.app ? [options.app] : options.filter ? [] : Object.keys(workspace.apps);
1041
+ const held = [];
1042
+ for (const appName of scoped) {
1043
+ const port = workspace.apps[appName]?.port;
1044
+ if (port && !await isPortAvailable(port)) held.push({
1045
+ app: appName,
1046
+ port,
1047
+ holder: listenerOn(port)
1048
+ });
1049
+ }
1050
+ if (held.length > 0) throw new WorkspacePortsInUse(held);
1030
1051
  logger$11.log("\n🏃 Starting turbo run dev...\n");
1031
1052
  const turboProcess = spawn("pnpm", [
1032
1053
  "turbo",
@@ -1204,6 +1225,19 @@ var EntryRunner = class {
1204
1225
  */
1205
1226
  function generateServerEntryContent(options) {
1206
1227
  const { secretsJsonPath, runtime = "node", enableOpenApi = false, appImportPath = "./app.js", selfServing = false } = options;
1228
+ const parentWatch = `// Exit when the gkm dev that started this server is gone.
1229
+ const __gkmDevPid = Number(process.env.GKM_DEV_PID);
1230
+ if (__gkmDevPid) {
1231
+ setInterval(() => {
1232
+ try {
1233
+ process.kill(__gkmDevPid, 0);
1234
+ } catch {
1235
+ process.exit(0);
1236
+ }
1237
+ }, 1000).unref();
1238
+ }
1239
+
1240
+ `;
1207
1241
  const credentialsInjection = secretsJsonPath ? `import { existsSync, readFileSync } from 'node:fs';
1208
1242
 
1209
1243
  // Inject dev secrets via globalThis (must happen before app import)
@@ -1234,8 +1268,7 @@ if (existsSync(secretsPath)) {
1234
1268
  * Development server entry point for a surface that serves itself
1235
1269
  * This file is auto-generated by 'gkm dev'
1236
1270
  */
1237
- ${credentialsInjection}
1238
- const port = process.argv.includes('--port')
1271
+ ${credentialsInjection}${parentWatch}const port = process.argv.includes('--port')
1239
1272
  ? Number.parseInt(process.argv[process.argv.indexOf('--port') + 1])
1240
1273
  : 3000;
1241
1274
 
@@ -1250,8 +1283,7 @@ console.log(\`Server started on port \${port}\`);
1250
1283
  * Development server entry point
1251
1284
  * This file is auto-generated by 'gkm dev'
1252
1285
  */
1253
- ${credentialsInjection}
1254
- const port = process.argv.includes('--port')
1286
+ ${credentialsInjection}${parentWatch}const port = process.argv.includes('--port')
1255
1287
  ? Number.parseInt(process.argv[process.argv.indexOf('--port') + 1])
1256
1288
  : 3000;
1257
1289
 
@@ -1273,6 +1305,44 @@ start({
1273
1305
  });
1274
1306
  `;
1275
1307
  }
1308
+ /** A port this app must serve on is held by something else. */
1309
+ var DevPortInUse = class extends Error {
1310
+ port;
1311
+ holder;
1312
+ constructor(port, holder) {
1313
+ super(`Port ${port} is already in use${holder ? ` by ${holder}` : ""}. It is the port this app is provisioned on — the one every other app and its CORS origins point at — so dev will not move off it. Stop what is holding it (often a dev server a previous run left behind), or pass -p/--port to run this app somewhere else.`);
1314
+ this.port = port;
1315
+ this.holder = holder;
1316
+ this.name = "DevPortInUse";
1317
+ }
1318
+ };
1319
+ /** Apps whose provisioned ports are held before the workspace starts. */
1320
+ var WorkspacePortsInUse = class extends Error {
1321
+ held;
1322
+ constructor(held) {
1323
+ super(`Ports this workspace's apps are provisioned on are already in use:\n${held.map(({ app, port, holder }) => ` ${app}: ${port}${holder ? ` — held by ${holder}` : ""}`).join("\n")}\nStop what is holding them (often dev servers a previous run left behind) and start again. Nothing was started.`);
1324
+ this.held = held;
1325
+ this.name = "WorkspacePortsInUse";
1326
+ }
1327
+ };
1328
+ /** What is listening on a port, as `command (pid N)`, if `lsof` can tell. */
1329
+ function listenerOn(port) {
1330
+ try {
1331
+ const out = execSync(`lsof -nP -iTCP:${port} -sTCP:LISTEN -Fpc`, {
1332
+ encoding: "utf8",
1333
+ stdio: [
1334
+ "ignore",
1335
+ "pipe",
1336
+ "ignore"
1337
+ ]
1338
+ });
1339
+ const pid = out.match(/^p(\d+)/m)?.[1];
1340
+ const command = out.match(/^c(.+)$/m)?.[1];
1341
+ return pid ? `${command ?? "a process"} (pid ${pid})` : void 0;
1342
+ } catch {
1343
+ return;
1344
+ }
1345
+ }
1276
1346
  var DevServer = class {
1277
1347
  provider;
1278
1348
  requestedPort;
@@ -1305,7 +1375,7 @@ var DevServer = class {
1305
1375
  this.startTime = Date.now();
1306
1376
  if (this.isRunning) await this.stop();
1307
1377
  if (this.portExplicit) {
1308
- if (!await isPortAvailable(this.requestedPort)) throw new Error(`Port ${this.requestedPort} is already in use. Either stop the process using that port or omit -p/--port to auto-select an available port.`);
1378
+ if (!await isPortAvailable(this.requestedPort)) throw new DevPortInUse(this.requestedPort, listenerOn(this.requestedPort));
1309
1379
  this.actualPort = this.requestedPort;
1310
1380
  } else {
1311
1381
  this.actualPort = await findAvailablePort(this.requestedPort);
@@ -1323,7 +1393,8 @@ var DevServer = class {
1323
1393
  stdio: "inherit",
1324
1394
  env: {
1325
1395
  ...process.env,
1326
- NODE_ENV: "development"
1396
+ NODE_ENV: "development",
1397
+ GKM_DEV_PID: String(process.pid)
1327
1398
  },
1328
1399
  detached: true
1329
1400
  });
@@ -8515,26 +8586,26 @@ function loadPackageJson() {
8515
8586
  * Run: pnpm --filter @geekmidas/cli sync-versions
8516
8587
  */
8517
8588
  const GEEKMIDAS_VERSIONS = {
8518
- "@geekmidas/audit": "~10.0.0-alpha.25",
8519
- "@geekmidas/auth": "~10.0.0-alpha.25",
8520
- "@geekmidas/cache": "~10.0.0-alpha.25",
8521
- "@geekmidas/client": "~10.0.0-alpha.25",
8522
- "@geekmidas/cloud": "~10.0.0-alpha.25",
8523
- "@geekmidas/constructs": "~10.0.0-alpha.25",
8524
- "@geekmidas/db": "~10.0.0-alpha.25",
8525
- "@geekmidas/emailkit": "~10.0.0-alpha.25",
8526
- "@geekmidas/envkit": "~10.0.0-alpha.25",
8527
- "@geekmidas/errors": "~10.0.0-alpha.25",
8528
- "@geekmidas/events": "~10.0.0-alpha.25",
8529
- "@geekmidas/logger": "~10.0.0-alpha.25",
8530
- "@geekmidas/manifest": "~10.0.0-alpha.25",
8531
- "@geekmidas/rate-limit": "~10.0.0-alpha.25",
8532
- "@geekmidas/schema": "~10.0.0-alpha.25",
8533
- "@geekmidas/services": "~10.0.0-alpha.25",
8534
- "@geekmidas/storage": "~10.0.0-alpha.25",
8535
- "@geekmidas/studio": "~10.0.0-alpha.25",
8536
- "@geekmidas/telescope": "~10.0.0-alpha.25",
8537
- "@geekmidas/testkit": "~10.0.0-alpha.25",
8589
+ "@geekmidas/audit": "~10.0.0-alpha.26",
8590
+ "@geekmidas/auth": "~10.0.0-alpha.26",
8591
+ "@geekmidas/cache": "~10.0.0-alpha.26",
8592
+ "@geekmidas/client": "~10.0.0-alpha.26",
8593
+ "@geekmidas/cloud": "~10.0.0-alpha.26",
8594
+ "@geekmidas/constructs": "~10.0.0-alpha.26",
8595
+ "@geekmidas/db": "~10.0.0-alpha.26",
8596
+ "@geekmidas/emailkit": "~10.0.0-alpha.26",
8597
+ "@geekmidas/envkit": "~10.0.0-alpha.26",
8598
+ "@geekmidas/errors": "~10.0.0-alpha.26",
8599
+ "@geekmidas/events": "~10.0.0-alpha.26",
8600
+ "@geekmidas/logger": "~10.0.0-alpha.26",
8601
+ "@geekmidas/manifest": "~10.0.0-alpha.26",
8602
+ "@geekmidas/rate-limit": "~10.0.0-alpha.26",
8603
+ "@geekmidas/schema": "~10.0.0-alpha.26",
8604
+ "@geekmidas/services": "~10.0.0-alpha.26",
8605
+ "@geekmidas/storage": "~10.0.0-alpha.26",
8606
+ "@geekmidas/studio": "~10.0.0-alpha.26",
8607
+ "@geekmidas/telescope": "~10.0.0-alpha.26",
8608
+ "@geekmidas/testkit": "~10.0.0-alpha.26",
8538
8609
  "@geekmidas/cli": `~${loadPackageJson().version}`
8539
8610
  };
8540
8611
  //#endregion
@@ -16108,7 +16179,7 @@ program.command("secrets:push").description("Send a deployed stage's secrets to
16108
16179
  const globalOptions = program.opts();
16109
16180
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16110
16181
  const { loadWorkspaceConfig } = await import("./config.mjs");
16111
- const { pushStageSecrets } = await import("./transfer-B88fTvnh.mjs").then((n) => n.i);
16182
+ const { pushStageSecrets } = await import("./transfer-CAJs_vhu.mjs").then((n) => n.i);
16112
16183
  const { workspace } = await loadWorkspaceConfig();
16113
16184
  const { addedKeys } = await pushStageSecrets(workspace, options.stage, { profile: options.profile });
16114
16185
  for (const key of addedKeys) console.log(` + ${key} (reconciled)`);
@@ -16123,7 +16194,7 @@ program.command("secrets:pull").description("Bring a deployed stage's secrets fr
16123
16194
  const globalOptions = program.opts();
16124
16195
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16125
16196
  const { loadWorkspaceConfig } = await import("./config.mjs");
16126
- const { pullStageSecrets } = await import("./transfer-B88fTvnh.mjs").then((n) => n.i);
16197
+ const { pullStageSecrets } = await import("./transfer-CAJs_vhu.mjs").then((n) => n.i);
16127
16198
  const { workspace } = await loadWorkspaceConfig();
16128
16199
  const { addedKeys } = await pullStageSecrets(workspace, options.stage, { profile: options.profile });
16129
16200
  for (const key of addedKeys) console.log(` + ${key} (reconciled)`);
@@ -16147,7 +16218,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
16147
16218
  console.error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
16148
16219
  process.exit(1);
16149
16220
  }
16150
- const { derivedContainers } = await import("./credentials-BpoOUa74.mjs").then((n) => n.g);
16221
+ const { derivedContainers } = await import("./credentials-DI9kJcaP.mjs").then((n) => n.g);
16151
16222
  const result = reconcileMissingSecrets(secrets, workspace, await derivedContainers(workspace, stage));
16152
16223
  if (!result) {
16153
16224
  console.log(`\n✓ Secrets for stage "${stage}" are up-to-date`);
@@ -16206,7 +16277,7 @@ program.command("deploy:github").description("Let GitHub Actions deploy a stage:
16206
16277
  try {
16207
16278
  const globalOptions = program.opts();
16208
16279
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16209
- const { deployGithubCommand } = await import("./github-BOaa3kQR.mjs");
16280
+ const { deployGithubCommand } = await import("./github-D5SBlOx5.mjs");
16210
16281
  await deployGithubCommand(options);
16211
16282
  } catch (error) {
16212
16283
  console.error(formatError(error));