@geekmidas/cli 1.5.0 → 1.5.1

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 (82) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/{HostingerProvider-B9N-TKbp.mjs → HostingerProvider-402UdK89.mjs} +34 -1
  3. package/dist/HostingerProvider-402UdK89.mjs.map +1 -0
  4. package/dist/{HostingerProvider-DUV9-Tzg.cjs → HostingerProvider-BiXdHjiq.cjs} +34 -1
  5. package/dist/HostingerProvider-BiXdHjiq.cjs.map +1 -0
  6. package/dist/{Route53Provider-C8mS0zY6.mjs → Route53Provider-DbBo7Uz5.mjs} +53 -1
  7. package/dist/Route53Provider-DbBo7Uz5.mjs.map +1 -0
  8. package/dist/{Route53Provider-Bs7Arms9.cjs → Route53Provider-kfJ77LmL.cjs} +53 -1
  9. package/dist/Route53Provider-kfJ77LmL.cjs.map +1 -0
  10. package/dist/backup-provisioner-B5e-F6zX.cjs +164 -0
  11. package/dist/backup-provisioner-B5e-F6zX.cjs.map +1 -0
  12. package/dist/backup-provisioner-BIArpmTr.mjs +163 -0
  13. package/dist/backup-provisioner-BIArpmTr.mjs.map +1 -0
  14. package/dist/{config-ZQM1vBoz.cjs → config-BYn5yUt5.cjs} +2 -2
  15. package/dist/{config-ZQM1vBoz.cjs.map → config-BYn5yUt5.cjs.map} +1 -1
  16. package/dist/{config-DfCJ29PQ.mjs → config-dLNQIvDR.mjs} +2 -2
  17. package/dist/{config-DfCJ29PQ.mjs.map → config-dLNQIvDR.mjs.map} +1 -1
  18. package/dist/config.cjs +2 -2
  19. package/dist/config.d.cts +1 -1
  20. package/dist/config.d.mts +2 -2
  21. package/dist/config.mjs +2 -2
  22. package/dist/{dokploy-api-z0833e7r.mjs → dokploy-api-2ldYoN3i.mjs} +131 -1
  23. package/dist/dokploy-api-2ldYoN3i.mjs.map +1 -0
  24. package/dist/dokploy-api-C93pveuy.mjs +3 -0
  25. package/dist/dokploy-api-CbDh4o93.cjs +3 -0
  26. package/dist/{dokploy-api-CQvhV6Hd.cjs → dokploy-api-DLgvEQlr.cjs} +131 -1
  27. package/dist/dokploy-api-DLgvEQlr.cjs.map +1 -0
  28. package/dist/{index-B58qjyBd.d.cts → index-Ba21_lNt.d.cts} +131 -29
  29. package/dist/index-Ba21_lNt.d.cts.map +1 -0
  30. package/dist/{index-C0SpUT9Y.d.mts → index-Bj5VNxEL.d.mts} +132 -30
  31. package/dist/index-Bj5VNxEL.d.mts.map +1 -0
  32. package/dist/index.cjs +119 -25
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.mjs +119 -25
  35. package/dist/index.mjs.map +1 -1
  36. package/dist/{openapi-BcSjLfWq.mjs → openapi-CMTyaIJJ.mjs} +2 -2
  37. package/dist/{openapi-BcSjLfWq.mjs.map → openapi-CMTyaIJJ.mjs.map} +1 -1
  38. package/dist/{openapi-D6Hcfov0.cjs → openapi-CqblwJZ4.cjs} +2 -2
  39. package/dist/{openapi-D6Hcfov0.cjs.map → openapi-CqblwJZ4.cjs.map} +1 -1
  40. package/dist/openapi.cjs +3 -3
  41. package/dist/openapi.d.mts +1 -1
  42. package/dist/openapi.mjs +3 -3
  43. package/dist/{types-B9UZ7fOG.d.mts → types-CZg5iUgD.d.mts} +1 -1
  44. package/dist/{types-B9UZ7fOG.d.mts.map → types-CZg5iUgD.d.mts.map} +1 -1
  45. package/dist/workspace/index.cjs +1 -1
  46. package/dist/workspace/index.d.cts +1 -1
  47. package/dist/workspace/index.d.mts +2 -2
  48. package/dist/workspace/index.mjs +1 -1
  49. package/dist/{workspace-2Do2YcGZ.cjs → workspace-DIMnYaYt.cjs} +16 -2
  50. package/dist/{workspace-2Do2YcGZ.cjs.map → workspace-DIMnYaYt.cjs.map} +1 -1
  51. package/dist/{workspace-BW2iU37P.mjs → workspace-Dy8k7Wru.mjs} +16 -2
  52. package/dist/{workspace-BW2iU37P.mjs.map → workspace-Dy8k7Wru.mjs.map} +1 -1
  53. package/examples/cron-example.ts +6 -6
  54. package/examples/function-example.ts +1 -1
  55. package/package.json +7 -5
  56. package/src/deploy/__tests__/backup-provisioner.spec.ts +428 -0
  57. package/src/deploy/__tests__/createDnsProvider.spec.ts +23 -0
  58. package/src/deploy/__tests__/env-resolver.spec.ts +1 -1
  59. package/src/deploy/__tests__/undeploy.spec.ts +758 -0
  60. package/src/deploy/backup-provisioner.ts +316 -0
  61. package/src/deploy/dns/DnsProvider.ts +39 -1
  62. package/src/deploy/dns/HostingerProvider.ts +74 -0
  63. package/src/deploy/dns/Route53Provider.ts +81 -0
  64. package/src/deploy/dns/index.ts +25 -0
  65. package/src/deploy/dokploy-api.ts +237 -0
  66. package/src/deploy/index.ts +71 -13
  67. package/src/deploy/state.ts +171 -0
  68. package/src/deploy/undeploy.ts +407 -0
  69. package/src/generators/FunctionGenerator.ts +1 -1
  70. package/src/init/versions.ts +2 -2
  71. package/src/workspace/schema.ts +26 -0
  72. package/src/workspace/types.ts +14 -37
  73. package/dist/HostingerProvider-B9N-TKbp.mjs.map +0 -1
  74. package/dist/HostingerProvider-DUV9-Tzg.cjs.map +0 -1
  75. package/dist/Route53Provider-Bs7Arms9.cjs.map +0 -1
  76. package/dist/Route53Provider-C8mS0zY6.mjs.map +0 -1
  77. package/dist/dokploy-api-CQvhV6Hd.cjs.map +0 -1
  78. package/dist/dokploy-api-CWc02yyg.cjs +0 -3
  79. package/dist/dokploy-api-DSJYNx88.mjs +0 -3
  80. package/dist/dokploy-api-z0833e7r.mjs.map +0 -1
  81. package/dist/index-B58qjyBd.d.cts.map +0 -1
  82. package/dist/index-C0SpUT9Y.d.mts.map +0 -1
package/dist/index.mjs CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env -S npx tsx
2
2
  import { __require } from "./chunk-Duj1WY3L.mjs";
3
- import { getAppBuildOrder, getDependencyEnvVars, getDeployTargetError, isDeployTargetSupported } from "./workspace-BW2iU37P.mjs";
4
- import { getAppNameFromCwd, loadAppConfig, loadConfig, loadWorkspaceConfig, parseModuleConfig } from "./config-DfCJ29PQ.mjs";
3
+ import { getAppBuildOrder, getDependencyEnvVars, getDeployTargetError, isDeployTargetSupported } from "./workspace-Dy8k7Wru.mjs";
4
+ import { getAppNameFromCwd, loadAppConfig, loadConfig, loadWorkspaceConfig, parseModuleConfig } from "./config-dLNQIvDR.mjs";
5
5
  import { getCredentialsPath, getDokployCredentials, getDokployRegistryId, getDokployToken, removeDokployCredentials, storeDokployCredentials, storeDokployRegistryId } from "./credentials-s1kLcIzK.mjs";
6
- import { ConstructGenerator, EndpointGenerator, OPENAPI_OUTPUT_PATH, generateOpenApi, openapiCommand, resolveOpenApiConfig } from "./openapi-BcSjLfWq.mjs";
6
+ import { ConstructGenerator, EndpointGenerator, OPENAPI_OUTPUT_PATH, generateOpenApi, openapiCommand, resolveOpenApiConfig } from "./openapi-CMTyaIJJ.mjs";
7
7
  import { getKeyPath, maskPassword, readStageSecrets, secretsExist, setCustomSecret, toEmbeddableSecrets, writeStageSecrets } from "./storage-DmCbr6DI.mjs";
8
- import { DokployApi } from "./dokploy-api-z0833e7r.mjs";
8
+ import { DokployApi } from "./dokploy-api-2ldYoN3i.mjs";
9
9
  import { encryptSecrets } from "./encryption-BOH5M-f-.mjs";
10
10
  import { CachedStateProvider } from "./CachedStateProvider-BDq5WqSy.mjs";
11
11
  import { generateReactQueryCommand } from "./openapi-react-query-DaTMSPD5.mjs";
@@ -32,7 +32,7 @@ import prompts from "prompts";
32
32
 
33
33
  //#region package.json
34
34
  var name = "@geekmidas/cli";
35
- var version = "1.4.0";
35
+ var version = "1.5.0";
36
36
  var description = "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs";
37
37
  var private$1 = false;
38
38
  var type = "module";
@@ -78,7 +78,9 @@ var repository = {
78
78
  };
79
79
  var dependencies = {
80
80
  "@apidevtools/swagger-parser": "^10.1.0",
81
+ "@aws-sdk/client-iam": "~3.971.0",
81
82
  "@aws-sdk/client-route-53": "~3.971.0",
83
+ "@aws-sdk/client-s3": "~3.971.0",
82
84
  "@aws-sdk/client-ssm": "~3.971.0",
83
85
  "@aws-sdk/credential-providers": "~3.971.0",
84
86
  "@geekmidas/constructs": "workspace:~",
@@ -132,7 +134,7 @@ const logger$11 = console;
132
134
  * Validate Dokploy token by making a test API call
133
135
  */
134
136
  async function validateDokployToken(endpoint, token) {
135
- const { DokployApi: DokployApi$1 } = await import("./dokploy-api-DSJYNx88.mjs");
137
+ const { DokployApi: DokployApi$1 } = await import("./dokploy-api-C93pveuy.mjs");
136
138
  const api = new DokployApi$1({
137
139
  baseUrl: endpoint,
138
140
  token
@@ -417,7 +419,7 @@ var FunctionGenerator = class extends ConstructGenerator {
417
419
  const importPath = relativePath.replace(/\.ts$/, ".js");
418
420
  const relativeEnvParserPath = relative(dirname(handlerPath), context.envParserPath);
419
421
  const relativeLoggerPath = relative(dirname(handlerPath), context.loggerPath);
420
- const content = `import { AWSLambdaFunction } from '@geekmidas/constructs/functions';
422
+ const content = `import { AWSLambdaFunction } from '@geekmidas/constructs/aws';
421
423
  import { ${exportName} } from '${importPath}';
422
424
  import ${context.envParserImportPattern} from '${relativeEnvParserPath}';
423
425
  import ${context.loggerImportPattern} from '${relativeLoggerPath}';
@@ -2176,6 +2178,41 @@ function isDnsVerified(state, hostname, serverIp) {
2176
2178
  const record = state?.dnsVerified?.[hostname];
2177
2179
  return record?.serverIp === serverIp;
2178
2180
  }
2181
+ /**
2182
+ * Get the key for a DNS record in state
2183
+ */
2184
+ function getDnsRecordKey(name$1, type$1) {
2185
+ return `${name$1}:${type$1}`;
2186
+ }
2187
+ /**
2188
+ * Set a created DNS record in state (mutates state)
2189
+ */
2190
+ function setDnsRecord(state, record) {
2191
+ if (!state.dnsRecords) state.dnsRecords = {};
2192
+ const key = getDnsRecordKey(record.name, record.type);
2193
+ state.dnsRecords[key] = {
2194
+ ...record,
2195
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
2196
+ };
2197
+ }
2198
+ /**
2199
+ * Get backup state from state
2200
+ */
2201
+ function getBackupState(state) {
2202
+ return state?.backups;
2203
+ }
2204
+ /**
2205
+ * Set backup state (mutates state)
2206
+ */
2207
+ function setBackupState(state, backupState) {
2208
+ state.backups = backupState;
2209
+ }
2210
+ /**
2211
+ * Set postgres backup ID in state (mutates state)
2212
+ */
2213
+ function setPostgresBackupId(state, backupId) {
2214
+ if (state.backups) state.backups.postgresBackupId = backupId;
2215
+ }
2179
2216
 
2180
2217
  //#endregion
2181
2218
  //#region src/deploy/dns/DnsProvider.ts
@@ -2183,7 +2220,7 @@ function isDnsVerified(state, hostname, serverIp) {
2183
2220
  * Check if value is a DnsProvider implementation.
2184
2221
  */
2185
2222
  function isDnsProvider(value) {
2186
- return typeof value === "object" && value !== null && typeof value.name === "string" && typeof value.getRecords === "function" && typeof value.upsertRecords === "function";
2223
+ return typeof value === "object" && value !== null && typeof value.name === "string" && typeof value.getRecords === "function" && typeof value.upsertRecords === "function" && typeof value.deleteRecords === "function";
2187
2224
  }
2188
2225
  /**
2189
2226
  * Create a DNS provider based on configuration.
@@ -2199,11 +2236,11 @@ async function createDnsProvider(options) {
2199
2236
  if (isDnsProvider(config$1.provider)) return config$1.provider;
2200
2237
  const provider = config$1.provider;
2201
2238
  if (provider === "hostinger") {
2202
- const { HostingerProvider } = await import("./HostingerProvider-B9N-TKbp.mjs");
2239
+ const { HostingerProvider } = await import("./HostingerProvider-402UdK89.mjs");
2203
2240
  return new HostingerProvider();
2204
2241
  }
2205
2242
  if (provider === "route53") {
2206
- const { Route53Provider } = await import("./Route53Provider-C8mS0zY6.mjs");
2243
+ const { Route53Provider } = await import("./Route53Provider-DbBo7Uz5.mjs");
2207
2244
  const route53Config = config$1;
2208
2245
  return new Route53Provider({
2209
2246
  region: route53Config.region,
@@ -2414,8 +2451,13 @@ async function createDnsRecordsForDomain(records, rootDomain, providerConfig) {
2414
2451
  * Supports both legacy single-domain format and new multi-domain format:
2415
2452
  * - Legacy: { provider: 'hostinger', domain: 'example.com' }
2416
2453
  * - Multi: { 'example.com': { provider: 'hostinger' }, 'example.dev': { provider: 'route53' } }
2454
+ *
2455
+ * @param appHostnames - Map of app names to hostnames
2456
+ * @param dnsConfig - DNS configuration (legacy or multi-domain)
2457
+ * @param dokployEndpoint - Dokploy server endpoint to resolve IP from
2458
+ * @param state - Optional state to save created records for later deletion
2417
2459
  */
2418
- async function orchestrateDns(appHostnames, dnsConfig, dokployEndpoint) {
2460
+ async function orchestrateDns(appHostnames, dnsConfig, dokployEndpoint, state) {
2419
2461
  if (!dnsConfig) return null;
2420
2462
  const normalizedConfig = normalizeDnsConfig(dnsConfig);
2421
2463
  logger$6.log("\n🌐 Setting up DNS records...");
@@ -2461,6 +2503,15 @@ async function orchestrateDns(appHostnames, dnsConfig, dokployEndpoint) {
2461
2503
  logger$6.log(` ⚠ ${failed} record(s) failed for ${rootDomain}`);
2462
2504
  hasFailures = true;
2463
2505
  }
2506
+ if (state) {
2507
+ for (const record of domainRecords) if (record.created || record.existed) setDnsRecord(state, {
2508
+ domain: rootDomain,
2509
+ name: record.subdomain,
2510
+ type: record.type,
2511
+ value: record.value,
2512
+ ttl: "ttl" in providerConfig && providerConfig.ttl ? providerConfig.ttl : 300
2513
+ });
2514
+ }
2464
2515
  printDnsRecordsTable(domainRecords, rootDomain);
2465
2516
  if (providerConfig.provider === "manual" || failed > 0) printDnsRecordsSimple(domainRecords.filter((r) => !r.created && !r.existed), rootDomain);
2466
2517
  }
@@ -5008,27 +5059,40 @@ async function initializePostgresUsers(api, postgres, serverHostname, users) {
5008
5059
  for (const user of users) {
5009
5060
  const schemaName = user.usePublicSchema ? "public" : user.name;
5010
5061
  logger$1.log(` Creating user "${user.name}" with schema "${schemaName}"...`);
5011
- await client.query(`
5012
- DO $$ BEGIN
5013
- IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '${user.name}') THEN
5014
- CREATE USER "${user.name}" WITH PASSWORD '${user.password}';
5015
- ELSE
5016
- ALTER USER "${user.name}" WITH PASSWORD '${user.password}';
5017
- END IF;
5018
- END $$;
5019
- `);
5020
- if (user.usePublicSchema) await client.query(`
5062
+ if (user.usePublicSchema) {
5063
+ await client.query(`
5064
+ DO $$ BEGIN
5065
+ IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '${user.name}') THEN
5066
+ CREATE USER "${user.name}" WITH PASSWORD '${user.password}';
5067
+ ELSE
5068
+ ALTER USER "${user.name}" WITH PASSWORD '${user.password}';
5069
+ END IF;
5070
+ END $$;
5071
+ `);
5072
+ await client.query(`
5021
5073
  GRANT ALL ON SCHEMA public TO "${user.name}";
5022
5074
  ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO "${user.name}";
5023
5075
  ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO "${user.name}";
5024
5076
  `);
5025
- else await client.query(`
5077
+ } else {
5078
+ await client.query(`
5079
+ DO $$ BEGIN
5080
+ IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '${user.name}') THEN
5081
+ CREATE USER "${user.name}" WITH PASSWORD '${user.password}';
5082
+ ELSE
5083
+ ALTER USER "${user.name}" WITH PASSWORD '${user.password}';
5084
+ END IF;
5085
+ -- Set search_path in same transaction to avoid tuple conflict
5086
+ ALTER USER "${user.name}" SET search_path TO "${schemaName}";
5087
+ END $$;
5088
+ `);
5089
+ await client.query(`
5026
5090
  CREATE SCHEMA IF NOT EXISTS "${schemaName}" AUTHORIZATION "${user.name}";
5027
- ALTER USER "${user.name}" SET search_path TO "${schemaName}";
5028
5091
  GRANT USAGE ON SCHEMA "${schemaName}" TO "${user.name}";
5029
5092
  GRANT ALL ON ALL TABLES IN SCHEMA "${schemaName}" TO "${user.name}";
5030
5093
  ALTER DEFAULT PRIVILEGES IN SCHEMA "${schemaName}" GRANT ALL ON TABLES TO "${user.name}";
5031
5094
  `);
5095
+ }
5032
5096
  logger$1.log(` ✓ User "${user.name}" configured`);
5033
5097
  }
5034
5098
  } finally {
@@ -5534,6 +5598,36 @@ async function workspaceDeployCommand(workspace, options) {
5534
5598
  await initializePostgresUsers(api, provisionedPostgres, serverHostname, usersToCreate);
5535
5599
  }
5536
5600
  }
5601
+ if (workspace.deploy?.backups && provisionedPostgres) {
5602
+ logger$1.log("\n💾 Provisioning backup destination...");
5603
+ const { provisionBackupDestination } = await import("./backup-provisioner-BIArpmTr.mjs");
5604
+ const backupState = await provisionBackupDestination({
5605
+ api,
5606
+ projectId: project.projectId,
5607
+ projectName: workspace.name,
5608
+ stage,
5609
+ config: workspace.deploy.backups,
5610
+ existingState: getBackupState(state),
5611
+ logger: logger$1
5612
+ });
5613
+ setBackupState(state, backupState);
5614
+ if (!backupState.postgresBackupId) {
5615
+ const backupSchedule = workspace.deploy.backups.schedule ?? "0 2 * * *";
5616
+ const backupRetention = workspace.deploy.backups.retention ?? 30;
5617
+ logger$1.log(" Creating postgres backup schedule...");
5618
+ const backup = await api.createPostgresBackup({
5619
+ schedule: backupSchedule,
5620
+ prefix: `${stage}/postgres`,
5621
+ destinationId: backupState.destinationId,
5622
+ database: provisionedPostgres.databaseName,
5623
+ postgresId: provisionedPostgres.postgresId,
5624
+ enabled: true,
5625
+ keepLatestCount: backupRetention
5626
+ });
5627
+ setPostgresBackupId(state, backup.backupId);
5628
+ logger$1.log(` ✓ Postgres backup schedule created (${backupSchedule})`);
5629
+ } else logger$1.log(" ✓ Using existing postgres backup schedule");
5630
+ }
5537
5631
  const publicUrls = {};
5538
5632
  const results = [];
5539
5633
  const dokployConfig = workspace.deploy.dokploy;
@@ -6275,10 +6369,10 @@ const GEEKMIDAS_VERSIONS = {
6275
6369
  "@geekmidas/cache": "~1.0.0",
6276
6370
  "@geekmidas/client": "~1.0.0",
6277
6371
  "@geekmidas/cloud": "~1.0.0",
6278
- "@geekmidas/constructs": "~1.0.0",
6372
+ "@geekmidas/constructs": "~1.0.4",
6279
6373
  "@geekmidas/db": "~1.0.0",
6280
6374
  "@geekmidas/emailkit": "~1.0.0",
6281
- "@geekmidas/envkit": "~1.0.0",
6375
+ "@geekmidas/envkit": "~1.0.1",
6282
6376
  "@geekmidas/errors": "~1.0.0",
6283
6377
  "@geekmidas/events": "~1.0.0",
6284
6378
  "@geekmidas/logger": "~1.0.0",