@geekmidas/cli 10.0.0-alpha.53 → 10.0.0-alpha.55

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.
Files changed (90) hide show
  1. package/README.md +2 -2
  2. package/dist/{HostingerProvider-GF6NAZAK.mjs → HostingerProvider-cL-6oQ5r.mjs} +2 -2
  3. package/dist/{HostingerProvider-GF6NAZAK.mjs.map → HostingerProvider-cL-6oQ5r.mjs.map} +1 -1
  4. package/dist/LegacyStateStore-ByRWQ9s1.mjs +89 -0
  5. package/dist/LegacyStateStore-ByRWQ9s1.mjs.map +1 -0
  6. package/dist/LegacyStateStore-C_OFs1gN.cjs +89 -0
  7. package/dist/LegacyStateStore-C_OFs1gN.cjs.map +1 -0
  8. package/dist/LocalStateStore-BupdV-VN.mjs +163 -0
  9. package/dist/LocalStateStore-BupdV-VN.mjs.map +1 -0
  10. package/dist/LocalStateStore-DDDU0HkI.cjs +163 -0
  11. package/dist/LocalStateStore-DDDU0HkI.cjs.map +1 -0
  12. package/dist/{OpenApiTsGenerator-BzIGy8KE.mjs → OpenApiTsGenerator-DKmAorGX.mjs} +34 -11
  13. package/dist/{OpenApiTsGenerator-BzIGy8KE.mjs.map → OpenApiTsGenerator-DKmAorGX.mjs.map} +1 -1
  14. package/dist/{OpenApiTsGenerator-BN0PIZxd.cjs → OpenApiTsGenerator-WlUHjimW.cjs} +34 -11
  15. package/dist/{OpenApiTsGenerator-BN0PIZxd.cjs.map → OpenApiTsGenerator-WlUHjimW.cjs.map} +1 -1
  16. package/dist/S3StateStore-C7eBae0G.cjs +160 -0
  17. package/dist/S3StateStore-C7eBae0G.cjs.map +1 -0
  18. package/dist/S3StateStore-FhzyENrN.mjs +161 -0
  19. package/dist/S3StateStore-FhzyENrN.mjs.map +1 -0
  20. package/dist/SSMStateStore-DD7jKrCO.cjs +146 -0
  21. package/dist/SSMStateStore-DD7jKrCO.cjs.map +1 -0
  22. package/dist/SSMStateStore-oda9xOGc.mjs +147 -0
  23. package/dist/SSMStateStore-oda9xOGc.mjs.map +1 -0
  24. package/dist/{backends-Dfeu5Dgc.mjs → backends-BNrMPlJb.mjs} +2 -2
  25. package/dist/{backends-Dfeu5Dgc.mjs.map → backends-BNrMPlJb.mjs.map} +1 -1
  26. package/dist/{backends-D5aDWxuA.cjs → backends-nBauiBkt.cjs} +2 -2
  27. package/dist/{backends-D5aDWxuA.cjs.map → backends-nBauiBkt.cjs.map} +1 -1
  28. package/dist/{bundler--fyybf1N.mjs → bundler-URImKj-A.mjs} +2 -2
  29. package/dist/{bundler--fyybf1N.mjs.map → bundler-URImKj-A.mjs.map} +1 -1
  30. package/dist/{config-Cvr5fCbn.cjs → config-C7NZG2tr.cjs} +2 -2
  31. package/dist/{config-Cvr5fCbn.cjs.map → config-C7NZG2tr.cjs.map} +1 -1
  32. package/dist/{config-SOkDH-n1.mjs → config-XEd-dKVX.mjs} +2 -2
  33. package/dist/{config-SOkDH-n1.mjs.map → config-XEd-dKVX.mjs.map} +1 -1
  34. package/dist/config.cjs +2 -2
  35. package/dist/config.d.cts +2 -2
  36. package/dist/config.d.mts +2 -2
  37. package/dist/config.mjs +2 -2
  38. package/dist/{encryption-O-XdeNxe.mjs → encryption-Bc1cMdeY.mjs} +4 -4
  39. package/dist/{encryption-O-XdeNxe.mjs.map → encryption-Bc1cMdeY.mjs.map} +1 -1
  40. package/dist/{encryption-tB4LqLKN.cjs → encryption-DSHYN5ap.cjs} +4 -4
  41. package/dist/{encryption-tB4LqLKN.cjs.map → encryption-DSHYN5ap.cjs.map} +1 -1
  42. package/dist/{github-BGx4U61b.cjs → github-CWflxaV4.cjs} +3 -3
  43. package/dist/{github-BGx4U61b.cjs.map → github-CWflxaV4.cjs.map} +1 -1
  44. package/dist/{github-U_frvZgD.mjs → github-DWHXTcwL.mjs} +3 -3
  45. package/dist/{github-U_frvZgD.mjs.map → github-DWHXTcwL.mjs.map} +1 -1
  46. package/dist/{index-fU3qHy7c.d.cts → index-B8nraKvg.d.mts} +2 -2
  47. package/dist/{index-DYh5TrsZ.d.mts.map → index-B8nraKvg.d.mts.map} +1 -1
  48. package/dist/{index-DYh5TrsZ.d.mts → index-BvBQS89a.d.cts} +2 -2
  49. package/dist/{index-fU3qHy7c.d.cts.map → index-BvBQS89a.d.cts.map} +1 -1
  50. package/dist/index.cjs +993 -215
  51. package/dist/index.cjs.map +1 -1
  52. package/dist/index.mjs +991 -221
  53. package/dist/index.mjs.map +1 -1
  54. package/dist/{migrate-SDIRUyY5.cjs → migrate-DHMRgnP6.cjs} +4 -4
  55. package/dist/{migrate-SDIRUyY5.cjs.map → migrate-DHMRgnP6.cjs.map} +1 -1
  56. package/dist/{migrate-CHQyNzj-.mjs → migrate-PcQg692O.mjs} +4 -4
  57. package/dist/{migrate-CHQyNzj-.mjs.map → migrate-PcQg692O.mjs.map} +1 -1
  58. package/dist/openapi.cjs +3 -3
  59. package/dist/openapi.d.cts +1 -1
  60. package/dist/openapi.d.mts +1 -1
  61. package/dist/openapi.mjs +3 -3
  62. package/dist/{ready-VkNwfJu7.cjs → ready-BefA4mM0.cjs} +2 -2
  63. package/dist/{ready-VkNwfJu7.cjs.map → ready-BefA4mM0.cjs.map} +1 -1
  64. package/dist/{ready-C8wG_d0v.mjs → ready-bES_Jk5v.mjs} +2 -2
  65. package/dist/{ready-C8wG_d0v.mjs.map → ready-bES_Jk5v.mjs.map} +1 -1
  66. package/dist/reconcile/public.d.cts +1 -1
  67. package/dist/reconcile/public.d.mts +1 -1
  68. package/dist/{types-DYDT4FfE.d.cts → types-Cgj-cq2m.d.mts} +136 -5
  69. package/dist/types-Cgj-cq2m.d.mts.map +1 -0
  70. package/dist/{types-CT0ymlBk.d.mts → types-CmxMhLGp.d.cts} +137 -4
  71. package/dist/types-CmxMhLGp.d.cts.map +1 -0
  72. package/dist/vitest.cjs +1 -1
  73. package/dist/vitest.mjs +1 -1
  74. package/dist/workspace/index.cjs +1 -1
  75. package/dist/workspace/index.d.cts +2 -2
  76. package/dist/workspace/index.d.mts +2 -2
  77. package/dist/workspace/index.mjs +1 -1
  78. package/dist/{workspace-qcva2dTt.mjs → workspace-BE0WHPw9.mjs} +9 -9
  79. package/dist/workspace-BE0WHPw9.mjs.map +1 -0
  80. package/dist/{workspace-P_V5t4Uk.cjs → workspace-CXvYabDJ.cjs} +7 -7
  81. package/dist/workspace-CXvYabDJ.cjs.map +1 -0
  82. package/dist/{workspace-bOsks1uk.mjs → workspace-DHK2N1mq.mjs} +22 -3
  83. package/dist/{workspace-bOsks1uk.mjs.map → workspace-DHK2N1mq.mjs.map} +1 -1
  84. package/dist/{workspace-BcCiLzTO.cjs → workspace-DL_99LJC.cjs} +22 -3
  85. package/dist/{workspace-BcCiLzTO.cjs.map → workspace-DL_99LJC.cjs.map} +1 -1
  86. package/package.json +14 -14
  87. package/dist/types-CT0ymlBk.d.mts.map +0 -1
  88. package/dist/types-DYDT4FfE.d.cts.map +0 -1
  89. package/dist/workspace-P_V5t4Uk.cjs.map +0 -1
  90. package/dist/workspace-qcva2dTt.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LocalStateStore-DDDU0HkI.cjs","names":["DocumentStateStore","join","readFile","contentVersion","StateVersionConflict","randomUUID","open","rename","rm","writeFile","StateLocked","mkdir","unlink","StateStoreBusy","stat"],"sources":["../src/deploy/LocalStateStore.ts"],"sourcesContent":["/**\n * Local filesystem state store.\n *\n * `.gkm/deploy-<stage>.json` holds the state, `.gkm/deploy-<stage>.lock` the\n * lock. Every file is mode 0600: state holds database passwords and IAM keys.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport {\n\tmkdir,\n\topen,\n\treadFile,\n\trename,\n\trm,\n\tstat,\n\tunlink,\n\twriteFile,\n} from 'node:fs/promises';\nimport { join } from 'node:path';\nimport {\n\tcontentVersion,\n\tDocumentStateStore,\n\ttype LockHolder,\n\ttype RawState,\n\tStateLocked,\n\tStateStoreBusy,\n\ttype StateVersion,\n\tStateVersionConflict,\n} from './StateStore';\n\nconst FILE_MODE = 0o600;\n\n/** How long a write waits for another process's write to finish. */\nconst MUTEX_TIMEOUT_MS = 5_000;\n/**\n * A write holds the mutex for milliseconds, so one this old was left by a\n * process that died mid-write and is safe to take over.\n */\nconst MUTEX_STALE_MS = 30_000;\n\nfunction isCode(error: unknown, code: string): boolean {\n\treturn (error as NodeJS.ErrnoException)?.code === code;\n}\n\nexport class LocalStateStore extends DocumentStateStore {\n\tconstructor(readonly workspaceRoot: string) {\n\t\tsuper();\n\t}\n\n\tprivate get dir(): string {\n\t\treturn join(this.workspaceRoot, '.gkm');\n\t}\n\n\tstatePath(stage: string): string {\n\t\treturn join(this.dir, `deploy-${stage}.json`);\n\t}\n\n\tlockPath(stage: string): string {\n\t\treturn join(this.dir, `deploy-${stage}.lock`);\n\t}\n\n\tbackupPath(stage: string): string {\n\t\treturn join(this.dir, `deploy-${stage}.v1.json`);\n\t}\n\n\tprivate mutexPath(stage: string): string {\n\t\treturn join(this.dir, `deploy-${stage}.json.mutex`);\n\t}\n\n\tprotected location(stage: string): string {\n\t\treturn this.statePath(stage);\n\t}\n\n\tprotected async readRaw(stage: string): Promise<RawState | null> {\n\t\ttry {\n\t\t\tconst body = await readFile(this.statePath(stage), 'utf-8');\n\t\t\treturn { body, version: contentVersion(body) };\n\t\t} catch (error) {\n\t\t\tif (isCode(error, 'ENOENT')) return null;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprotected async writeRaw(\n\t\tstage: string,\n\t\tbody: string,\n\t\texpectedVersion: StateVersion | null,\n\t): Promise<StateVersion> {\n\t\tawait this.ensureDir();\n\t\treturn this.withMutex(stage, async () => {\n\t\t\tconst current = await this.readRaw(stage);\n\t\t\tconst actual = current?.version ?? null;\n\t\t\tif (actual !== expectedVersion) {\n\t\t\t\tthrow new StateVersionConflict(stage, expectedVersion, actual);\n\t\t\t}\n\n\t\t\t// Written beside the target and renamed over it: a reader sees the\n\t\t\t// old file or the new one, never half of either.\n\t\t\tconst target = this.statePath(stage);\n\t\t\tconst temp = `${target}.${randomUUID()}.tmp`;\n\t\t\ttry {\n\t\t\t\tconst handle = await open(temp, 'wx', FILE_MODE);\n\t\t\t\ttry {\n\t\t\t\t\tawait handle.writeFile(body);\n\t\t\t\t\tawait handle.sync();\n\t\t\t\t} finally {\n\t\t\t\t\tawait handle.close();\n\t\t\t\t}\n\t\t\t\tawait rename(temp, target);\n\t\t\t} catch (error) {\n\t\t\t\tawait rm(temp, { force: true });\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn contentVersion(body);\n\t\t});\n\t}\n\n\tprotected async writeV1Backup(stage: string, body: string): Promise<void> {\n\t\ttry {\n\t\t\tawait writeFile(this.backupPath(stage), body, {\n\t\t\t\tflag: 'wx',\n\t\t\t\tmode: FILE_MODE,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\t// The first migration's backup is the one worth keeping.\n\t\t\tif (!isCode(error, 'EEXIST')) throw error;\n\t\t}\n\t}\n\n\tprotected async createLock(stage: string, holder: LockHolder): Promise<void> {\n\t\tawait this.ensureDir();\n\t\tlet handle: Awaited<ReturnType<typeof open>>;\n\t\ttry {\n\t\t\thandle = await open(this.lockPath(stage), 'wx', FILE_MODE);\n\t\t} catch (error) {\n\t\t\tif (isCode(error, 'EEXIST')) {\n\t\t\t\tthrow new StateLocked(\n\t\t\t\t\tstage,\n\t\t\t\t\tawait this.readLock(stage),\n\t\t\t\t\tthis.lockPath(stage),\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\ttry {\n\t\t\tawait handle.writeFile(JSON.stringify(holder, null, 2));\n\t\t} finally {\n\t\t\tawait handle.close();\n\t\t}\n\t}\n\n\tprotected async readLock(stage: string): Promise<LockHolder | null> {\n\t\ttry {\n\t\t\treturn JSON.parse(\n\t\t\t\tawait readFile(this.lockPath(stage), 'utf-8'),\n\t\t\t) as LockHolder;\n\t\t} catch {\n\t\t\t// Missing, or created by a process that died before writing to it.\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprotected async removeLock(\n\t\tstage: string,\n\t\tholder: LockHolder | null,\n\t): Promise<void> {\n\t\tif (holder) {\n\t\t\tconst current = await this.readLock(stage);\n\t\t\tif (current?.id !== holder.id) return;\n\t\t}\n\t\tawait rm(this.lockPath(stage), { force: true });\n\t}\n\n\tprivate async ensureDir(): Promise<void> {\n\t\tawait mkdir(this.dir, { recursive: true, mode: 0o700 });\n\t}\n\n\t/**\n\t * Serialises the check-then-rename of a conditional write across\n\t * processes. The stage lock is for whole runs; this is for the instant of\n\t * a single write, so even writers that skip the lock never interleave.\n\t */\n\tprivate async withMutex<T>(stage: string, fn: () => Promise<T>): Promise<T> {\n\t\tconst path = this.mutexPath(stage);\n\t\tconst deadline = Date.now() + MUTEX_TIMEOUT_MS;\n\n\t\tfor (;;) {\n\t\t\ttry {\n\t\t\t\tconst handle = await open(path, 'wx', FILE_MODE);\n\t\t\t\tawait handle.close();\n\t\t\t\tbreak;\n\t\t\t} catch (error) {\n\t\t\t\tif (!isCode(error, 'EEXIST')) throw error;\n\t\t\t\tif (await this.isStale(path)) {\n\t\t\t\t\tawait unlink(path).catch(() => {});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (Date.now() > deadline) throw new StateStoreBusy(stage, path);\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 10));\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\treturn await fn();\n\t\t} finally {\n\t\t\tawait rm(path, { force: true });\n\t\t}\n\t}\n\n\tprivate async isStale(path: string): Promise<boolean> {\n\t\ttry {\n\t\t\treturn Date.now() - (await stat(path)).mtimeMs > MUTEX_STALE_MS;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n}\n"],"mappings":"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"}
@@ -976,11 +976,15 @@ ${context.storageDrivers?.setup ? `// Which storage drivers exist is the entry p
976
976
  // a provider.
977
977
  ${context.storageDrivers.setup}
978
978
  ` : ""}
979
- export interface ServerApp {
979
+ ${context.surface ? `// Who this server is to Postgres: application_name on every connection.
980
+ process.env.GKM_APP_NAME ??= ${JSON.stringify(context.surface.id)};
981
+
982
+ ` : ""}export interface ServerApp {
980
983
  app: HonoType;
981
984
  start: (options?: {
982
985
  port?: number;
983
- serve: (app: HonoType, port: number) => void | Promise<void>;
986
+ /** Returns the server, so a shutdown can stop it taking requests. */
987
+ serve: (app: HonoType, port: number) => unknown;
984
988
  }) => Promise<void>;
985
989
  }
986
990
 
@@ -1148,20 +1152,35 @@ export const handler = adapter.handler;
1148
1152
  import { setupQueues } from './queues.js';
1149
1153
  import { setupCrons } from './crons.js';` : "";
1150
1154
  const gracefulShutdownCode = enableGracefulShutdown ? `
1151
- // Graceful shutdown handling
1155
+ // Graceful shutdown: stop taking requests, let in-flight ones finish, then
1156
+ // close what constructs opened (database pools) — so a rolling deploy does
1157
+ // not leave the old task holding connections. Bounded by
1158
+ // GKM_SHUTDOWN_TIMEOUT_MS, 8s by default: under Docker's 10s stop timeout,
1159
+ // so the process exits on its own terms rather than being killed mid-drain.
1152
1160
  let isShuttingDown = false;
1153
1161
 
1154
1162
  const shutdown = async () => {
1155
1163
  if (isShuttingDown) return;
1156
1164
  isShuttingDown = true;
1157
- logger.info('Graceful shutdown initiated');
1158
- // Allow in-flight requests to complete (30s timeout)
1159
- setTimeout(() => process.exit(0), 30000);
1165
+ const deadline = Number(process.env.GKM_SHUTDOWN_TIMEOUT_MS) || 8000;
1166
+ logger.info({ deadline }, 'Graceful shutdown initiated');
1167
+ setTimeout(() => {
1168
+ logger.warn({ deadline }, 'Shutdown deadline reached, exiting');
1169
+ process.exit(1);
1170
+ }, deadline).unref();
1171
+ await new Promise<void>((resolve) => {
1172
+ const close = (server as { close?: (done: () => void) => void } | undefined)?.close;
1173
+ if (typeof close === 'function') close.call(server, () => resolve());
1174
+ else resolve();
1175
+ });
1176
+ await runShutdownHooks((error) => logger.error({ error }, 'Shutdown hook failed'));
1177
+ process.exit(0);
1160
1178
  };
1161
1179
 
1162
1180
  process.on('SIGTERM', shutdown);
1163
1181
  process.on('SIGINT', shutdown);
1164
1182
  ` : "";
1183
+ const endpointsImportPath = production.optimizedHandlers ? "./endpoints/index.js" : "./endpoints.js";
1165
1184
  const content = `/**
1166
1185
  * Generated production server application
1167
1186
  *
@@ -1173,7 +1192,7 @@ import { setupCrons } from './crons.js';` : "";
1173
1192
  */
1174
1193
  import { Hono } from 'hono';
1175
1194
  import type { Hono as HonoType } from 'hono';
1176
- import { setupEndpoints } from '${production.optimizedHandlers ? "./endpoints/index.js" : "./endpoints.js"}';
1195
+ ${enableGracefulShutdown ? "import { runShutdownHooks } from '@geekmidas/constructs';\n" : ""}import { setupEndpoints } from '${endpointsImportPath}';
1177
1196
  ${subscriberImport}
1178
1197
  ${runtime.imports}
1179
1198
  ${runtime.bindings}
@@ -1184,7 +1203,10 @@ ${context.storageDrivers?.imports ?? ""}
1184
1203
  ${context.storageDrivers?.setup ? `// The entry point registers the drivers its target needs.
1185
1204
  ${context.storageDrivers.setup}
1186
1205
  ` : ""}
1187
- export interface ServerApp {
1206
+ ${context.surface ? `// Who this server is to Postgres: application_name on every connection.
1207
+ process.env.GKM_APP_NAME ??= ${JSON.stringify(context.surface.id)};
1208
+
1209
+ ` : ""}export interface ServerApp {
1188
1210
  app: HonoType;
1189
1211
  start: (options?: {
1190
1212
  port?: number;
@@ -1217,11 +1239,12 @@ ${afterSetupCall}
1217
1239
  }
1218
1240
 
1219
1241
  const port = options.port ?? Number(process.env.PORT) ?? 3000;
1242
+ let server: unknown;
1220
1243
  ${gracefulShutdownCode}${subscriberSetup}
1221
1244
  logger.info({ port }, 'Starting production server');
1222
1245
 
1223
1246
  // Start HTTP server using provided serve function
1224
- await options.serve(honoApp, port);
1247
+ server = await options.serve(honoApp, port);
1225
1248
 
1226
1249
  logger.info({ port }, 'Production server started');
1227
1250
  ${includeSubscribers ? "\n await subscribeForPush(port);" : ""}
@@ -1255,7 +1278,7 @@ const { start } = await createApp();
1255
1278
 
1256
1279
  await start({
1257
1280
  port,
1258
- serve: (app, port) => { serve({ fetch: app.fetch, port }); },
1281
+ serve: (app, port) => serve({ fetch: app.fetch, port }),
1259
1282
  });
1260
1283
  `);
1261
1284
  }
@@ -1768,4 +1791,4 @@ function unknownType(name) {
1768
1791
  //#endregion
1769
1792
  export { EndpointGenerator as n, runtimeFor as r, OpenApiTsGenerator as t };
1770
1793
 
1771
- //# sourceMappingURL=OpenApiTsGenerator-BzIGy8KE.mjs.map
1794
+ //# sourceMappingURL=OpenApiTsGenerator-DKmAorGX.mjs.map