@geekmidas/cli 1.10.27 → 1.10.29

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 (29) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/{fullstack-secrets-CsxU84eN.cjs → fullstack-secrets-Bchl2MDd.cjs} +2 -1
  3. package/dist/{fullstack-secrets-CsxU84eN.cjs.map → fullstack-secrets-Bchl2MDd.cjs.map} +1 -1
  4. package/dist/{fullstack-secrets-BDE7Sk93.mjs → fullstack-secrets-P84v8zWn.mjs} +2 -1
  5. package/dist/{fullstack-secrets-BDE7Sk93.mjs.map → fullstack-secrets-P84v8zWn.mjs.map} +1 -1
  6. package/dist/index.cjs +76 -74
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.mjs +76 -74
  9. package/dist/index.mjs.map +1 -1
  10. package/dist/{openapi-BXuCY14q.cjs → openapi-CBU4TEi-.cjs} +23 -130
  11. package/dist/openapi-CBU4TEi-.cjs.map +1 -0
  12. package/dist/{openapi-DeG0ffQ8.mjs → openapi-CQCoLuzh.mjs} +24 -113
  13. package/dist/openapi-CQCoLuzh.mjs.map +1 -0
  14. package/dist/openapi.cjs +1 -1
  15. package/dist/openapi.mjs +1 -1
  16. package/dist/{reconcile-DF8t4HC7.cjs → reconcile-CZtzdrnc.cjs} +2 -2
  17. package/dist/{reconcile-DF8t4HC7.cjs.map → reconcile-CZtzdrnc.cjs.map} +1 -1
  18. package/dist/{reconcile-BjWhjfSp.mjs → reconcile-DAAKa0YR.mjs} +2 -2
  19. package/dist/{reconcile-BjWhjfSp.mjs.map → reconcile-DAAKa0YR.mjs.map} +1 -1
  20. package/package.json +5 -5
  21. package/src/dev/index.ts +5 -100
  22. package/src/init/__tests__/generators.spec.ts +5 -3
  23. package/src/init/generators/monorepo.ts +0 -3
  24. package/src/init/generators/package.ts +2 -4
  25. package/src/init/generators/test.ts +61 -17
  26. package/src/init/generators/web.ts +7 -3
  27. package/src/setup/fullstack-secrets.ts +11 -0
  28. package/dist/openapi-BXuCY14q.cjs.map +0 -1
  29. package/dist/openapi-DeG0ffQ8.mjs.map +0 -1
package/dist/index.mjs CHANGED
@@ -3,9 +3,9 @@ import { __require } from "./chunk-Duj1WY3L.mjs";
3
3
  import { getAppBuildOrder, getDependencyEnvVars, getDeployTargetError, isDeployTargetSupported } from "./workspace-D4z4A4cq.mjs";
4
4
  import { getAppNameFromCwd, loadAppConfig, loadConfig, loadWorkspaceAppInfo, loadWorkspaceConfig, parseModuleConfig } from "./config-jsRYHOHU.mjs";
5
5
  import { getCredentialsPath, getDokployCredentials, getDokployRegistryId, getDokployToken, removeDokployCredentials, storeDokployCredentials, storeDokployRegistryId } from "./credentials-s1kLcIzK.mjs";
6
- import { createStageSecrets, generateConnectionUrls, generateDbPassword, generateDbUrl, generateFullstackCustomSecrets, generateLocalStackCredentials, generatePgBossUrl, generateSecurePassword, generateServiceCredentials, rotateServicePassword, writeDockerEnvFromSecrets } from "./fullstack-secrets-BDE7Sk93.mjs";
6
+ import { createStageSecrets, generateConnectionUrls, generateDbPassword, generateDbUrl, generateFullstackCustomSecrets, generateLocalStackCredentials, generatePgBossUrl, generateSecurePassword, generateServiceCredentials, rotateServicePassword, writeDockerEnvFromSecrets } from "./fullstack-secrets-P84v8zWn.mjs";
7
7
  import { getKeyPath, maskPassword, readStageSecrets, secretsExist, setCustomSecret, toEmbeddableSecrets, writeStageSecrets } from "./storage-dbb9RyBl.mjs";
8
- import { ConstructGenerator, EndpointGenerator, OPENAPI_OUTPUT_PATH, copyAllClients, copyClientToFrontends, generateOpenApi, getBackendOpenApiPath, isPartitionedRoutes, normalizeRoutes, openapiCommand, resolveOpenApiConfig } from "./openapi-DeG0ffQ8.mjs";
8
+ import { ConstructGenerator, EndpointGenerator, OPENAPI_OUTPUT_PATH, generateOpenApi, isPartitionedRoutes, normalizeRoutes, openapiCommand, resolveOpenApiConfig } from "./openapi-CQCoLuzh.mjs";
9
9
  import { DokployApi } from "./dokploy-api-BIT0683o.mjs";
10
10
  import { encryptSecrets } from "./encryption-DSkIlEZ6.mjs";
11
11
  import { CachedStateProvider } from "./CachedStateProvider-C8A-cCm5.mjs";
@@ -35,7 +35,7 @@ import prompts from "prompts";
35
35
 
36
36
  //#region package.json
37
37
  var name = "@geekmidas/cli";
38
- var version = "1.10.26";
38
+ var version = "1.10.28";
39
39
  var description = "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs";
40
40
  var private$1 = false;
41
41
  var type = "module";
@@ -1558,11 +1558,6 @@ async function workspaceDevCommand(workspace, options) {
1558
1558
  if (hasErrors) throw new Error("Frontend app validation failed. Fix the issues above and try again.");
1559
1559
  logger$11.log("✅ Frontend apps validated");
1560
1560
  }
1561
- if (frontendApps.length > 0 && backendApps.length > 0) {
1562
- const clientResults = await copyAllClients(workspace);
1563
- const copiedCount = clientResults.filter((r) => r.success).length;
1564
- if (copiedCount > 0) logger$11.log(`\n📦 Copied ${copiedCount} API client(s)`);
1565
- }
1566
1561
  const resolvedPorts = await resolveServicePorts(workspace.root);
1567
1562
  const rawSecrets = await loadDevSecrets(workspace);
1568
1563
  await startWorkspaceServices(workspace, resolvedPorts.dockerEnv, rawSecrets);
@@ -1625,50 +1620,11 @@ async function workspaceDevCommand(workspace, options) {
1625
1620
  env: turboEnv,
1626
1621
  detached: true
1627
1622
  });
1628
- let openApiWatcher = null;
1629
- if (frontendApps.length > 0 && backendApps.length > 0) {
1630
- const openApiPaths = [];
1631
- for (const [appName] of backendApps) {
1632
- const openApiPath = getBackendOpenApiPath(workspace, appName);
1633
- if (openApiPath) openApiPaths.push({
1634
- path: openApiPath,
1635
- appName
1636
- });
1637
- }
1638
- if (openApiPaths.length > 0) {
1639
- logger$11.log(`\n👀 Watching ${openApiPaths.length} backend OpenAPI spec(s) for changes`);
1640
- const pathToApp = new Map(openApiPaths.map((p) => [p.path, p.appName]));
1641
- openApiWatcher = chokidar.watch(openApiPaths.map((p) => p.path), {
1642
- persistent: true,
1643
- ignoreInitial: true,
1644
- depth: 0
1645
- });
1646
- let copyTimeout = null;
1647
- const handleChange = async (changedPath) => {
1648
- if (copyTimeout) clearTimeout(copyTimeout);
1649
- copyTimeout = setTimeout(async () => {
1650
- const backendAppName = pathToApp.get(changedPath);
1651
- if (!backendAppName) return;
1652
- logger$11.log(`\n🔄 OpenAPI spec changed for ${backendAppName}`);
1653
- try {
1654
- const results = await copyClientToFrontends(workspace, backendAppName, { silent: true });
1655
- for (const result of results) if (result.success) logger$11.log(` 📦 Copied client to ${result.frontendApp} (${result.endpointCount} endpoints)`);
1656
- else if (result.error) logger$11.error(` ❌ Failed to copy client to ${result.frontendApp}: ${result.error}`);
1657
- } catch (error) {
1658
- logger$11.error(` ❌ Failed to copy clients: ${error.message}`);
1659
- }
1660
- }, 200);
1661
- };
1662
- openApiWatcher.on("change", handleChange);
1663
- openApiWatcher.on("add", handleChange);
1664
- }
1665
- }
1666
1623
  let isShuttingDown = false;
1667
1624
  const shutdown = () => {
1668
1625
  if (isShuttingDown) return;
1669
1626
  isShuttingDown = true;
1670
1627
  logger$11.log("\n🛑 Shutting down workspace...");
1671
- if (openApiWatcher) openApiWatcher.close().catch(() => {});
1672
1628
  const pid = turboProcess.pid;
1673
1629
  if (pid) try {
1674
1630
  process.kill(-pid, "SIGTERM");
@@ -1696,7 +1652,6 @@ async function workspaceDevCommand(workspace, options) {
1696
1652
  reject(error);
1697
1653
  });
1698
1654
  turboProcess.on("exit", (code) => {
1699
- if (openApiWatcher) openApiWatcher.close().catch(() => {});
1700
1655
  if (code !== null && code !== 0) reject(new Error(`Turbo exited with code ${code}`));
1701
1656
  else resolve$1();
1702
1657
  });
@@ -8104,9 +8059,6 @@ export default defineWorkspace({
8104
8059
  client: './src/config/client.ts',
8105
8060
  server: './src/config/server.ts',
8106
8061
  },
8107
- client: {
8108
- output: './src/api',
8109
- },
8110
8062
  },
8111
8063
  },
8112
8064
  shared: {
@@ -9155,6 +9107,7 @@ function generatePackageJson(options, template) {
9155
9107
  devDependencies$1["@types/pg"] = "~8.15.0";
9156
9108
  devDependencies$1["@geekmidas/testkit"] = GEEKMIDAS_VERSIONS["@geekmidas/testkit"];
9157
9109
  devDependencies$1["@faker-js/faker"] = "~9.8.0";
9110
+ devDependencies$1["kysely-ctl"] = "~0.10.0";
9158
9111
  devDependencies$1["vite-tsconfig-paths"] = "~5.1.0";
9159
9112
  }
9160
9113
  if (monorepo) {
@@ -9179,10 +9132,7 @@ function generatePackageJson(options, template) {
9179
9132
  version: "0.0.1",
9180
9133
  private: true,
9181
9134
  type: "module",
9182
- exports: { "./client": {
9183
- types: OPENAPI_OUTPUT_PATH$1,
9184
- import: OPENAPI_OUTPUT_PATH$1
9185
- } },
9135
+ exports: { "./client": OPENAPI_OUTPUT_PATH$1 },
9186
9136
  scripts: scripts$1,
9187
9137
  dependencies: sortObject(dependencies$1),
9188
9138
  devDependencies: sortObject(devDependencies$1)
@@ -9212,6 +9162,29 @@ function generateSourceFiles(options, template) {
9212
9162
  function generateTestFiles(options, _template) {
9213
9163
  if (!options.database) return [];
9214
9164
  return [
9165
+ {
9166
+ path: "kysely.config.ts",
9167
+ content: `import { Credentials } from '@geekmidas/envkit/credentials';
9168
+ import { PostgresDialect } from 'kysely';
9169
+ import { defineConfig } from 'kysely-ctl';
9170
+ import pg from 'pg';
9171
+
9172
+ export default defineConfig({
9173
+ dialect: new PostgresDialect({
9174
+ pool: new pg.Pool({
9175
+ password: Credentials.POSTGRES_PASSWORD,
9176
+ user: Credentials.POSTGRES_USER,
9177
+ database: Credentials.POSTGRES_DB,
9178
+ port: Number(Credentials.POSTGRES_PORT),
9179
+ host: Credentials.POSTGRES_HOST,
9180
+ }),
9181
+ }),
9182
+ migrations: {
9183
+ migrationFolder: './src/db/migrations',
9184
+ },
9185
+ });
9186
+ `
9187
+ },
9215
9188
  {
9216
9189
  path: "test/config.ts",
9217
9190
  content: `import { it as itVitest } from 'vitest';
@@ -9233,30 +9206,52 @@ export const it = wrapVitestKyselyTransaction<Database>(itVitest, {
9233
9206
  },
9234
9207
  {
9235
9208
  path: "test/globalSetup.ts",
9236
- content: `import { Kysely, PostgresDialect } from 'kysely';
9237
- import pg from 'pg';
9209
+ content: `import fs from 'node:fs/promises';
9210
+ import path from 'node:path';
9211
+ import { Credentials } from '@geekmidas/envkit/credentials';
9238
9212
  import { PostgresKyselyMigrator } from '@geekmidas/testkit/kysely';
9239
- import type { Database } from '~/services/database.ts';
9213
+ import { runInitScript } from '@geekmidas/testkit/postgres';
9214
+ import { FileMigrationProvider, Kysely, PostgresDialect } from 'kysely';
9215
+ import pg from 'pg';
9240
9216
 
9241
- export async function setup() {
9242
- const testUrl = process.env.DATABASE_URL;
9243
- if (!testUrl) throw new Error('DATABASE_URL is required for tests');
9217
+ export default async function globalSetup() {
9218
+ const databaseUrl = Credentials.DATABASE_URL!;
9219
+ const migrationFolder = path.resolve(import.meta.dirname, '../db/migrations');
9244
9220
 
9245
- // Run migrations on the test database
9246
- // (gkm test already rewrites DATABASE_URL to point to the _test database)
9247
- const db = new Kysely<Database>({
9221
+ const db = new Kysely({
9248
9222
  dialect: new PostgresDialect({
9249
- pool: new pg.Pool({ connectionString: testUrl }),
9223
+ pool: new pg.Pool({ connectionString: databaseUrl }),
9250
9224
  }),
9251
9225
  });
9252
9226
 
9253
9227
  const migrator = new PostgresKyselyMigrator({
9228
+ uri: databaseUrl,
9254
9229
  db,
9255
- migrationsPath: './src/migrations',
9230
+ afterCreate: async (uri) => {
9231
+ const initScriptPath = path.resolve(process.cwd(), 'docker/postgres/init.sh');
9232
+ const dbUrl = new URL(Credentials.DATABASE_URL!);
9233
+ const apiUrl = new URL(Credentials.API_DATABASE_URL!);
9234
+ const authUrl = new URL(Credentials.AUTH_DATABASE_URL!);
9235
+
9236
+ const env = {
9237
+ POSTGRES_USER: dbUrl.username,
9238
+ POSTGRES_DB: dbUrl.pathname.slice(1),
9239
+ API_DB_PASSWORD: decodeURIComponent(apiUrl.password),
9240
+ AUTH_DB_PASSWORD: decodeURIComponent(authUrl.password),
9241
+ PGBOSS_DB_PASSWORD: Credentials.PGBOSS_DB_PASSWORD ?? 'pgboss-dev-password',
9242
+ };
9243
+
9244
+ await runInitScript(initScriptPath, uri, env);
9245
+ },
9246
+ provider: new FileMigrationProvider({
9247
+ fs,
9248
+ path,
9249
+ migrationFolder,
9250
+ }),
9256
9251
  });
9257
9252
 
9258
- await migrator.migrateToLatest();
9259
- await db.destroy();
9253
+ const teardown = await migrator.start();
9254
+ return teardown;
9260
9255
  }
9261
9256
  `
9262
9257
  },
@@ -10736,6 +10731,7 @@ storybook-static/
10736
10731
  function generateWebAppFiles(options) {
10737
10732
  if (!options.monorepo || options.template !== "fullstack") return [];
10738
10733
  const packageName = `@${options.name}/web`;
10734
+ const apiPackage = `@${options.name}/api`;
10739
10735
  const modelsPackage = `@${options.name}/models`;
10740
10736
  const uiPackage = `@${options.name}/ui`;
10741
10737
  const packageJson = {
@@ -10750,6 +10746,7 @@ function generateWebAppFiles(options) {
10750
10746
  typecheck: "tsc --noEmit"
10751
10747
  },
10752
10748
  dependencies: {
10749
+ [apiPackage]: "workspace:*",
10753
10750
  [modelsPackage]: "workspace:*",
10754
10751
  [uiPackage]: "workspace:*",
10755
10752
  "@geekmidas/client": GEEKMIDAS_VERSIONS["@geekmidas/client"],
@@ -10776,7 +10773,7 @@ function generateWebAppFiles(options) {
10776
10773
  const nextConfig: NextConfig = {
10777
10774
  output: 'standalone',
10778
10775
  reactStrictMode: true,
10779
- transpilePackages: ['${modelsPackage}', '${uiPackage}'],
10776
+ transpilePackages: ['${apiPackage}', '${modelsPackage}', '${uiPackage}'],
10780
10777
  };
10781
10778
 
10782
10779
  export default nextConfig;
@@ -10811,6 +10808,7 @@ export default nextConfig;
10811
10808
  baseUrl: ".",
10812
10809
  paths: {
10813
10810
  "~/*": ["./src/*", "../../packages/ui/src/*"],
10811
+ [`${apiPackage}/client`]: ["../../apps/api/.gkm/openapi.ts"],
10814
10812
  [`${modelsPackage}`]: ["../../packages/models/src"],
10815
10813
  [`${modelsPackage}/*`]: ["../../packages/models/src/*"],
10816
10814
  [`${uiPackage}`]: ["../../packages/ui/src"],
@@ -10824,7 +10822,11 @@ export default nextConfig;
10824
10822
  ".next/types/**/*.ts"
10825
10823
  ],
10826
10824
  exclude: ["node_modules"],
10827
- references: [{ path: "../../packages/ui" }, { path: "../../packages/models" }]
10825
+ references: [
10826
+ { path: "../../apps/api" },
10827
+ { path: "../../packages/ui" },
10828
+ { path: "../../packages/models" }
10829
+ ]
10828
10830
  };
10829
10831
  const queryClientTs = `import { QueryClient } from '@tanstack/react-query';
10830
10832
 
@@ -10903,7 +10905,7 @@ export function Providers({ children }: { children: React.ReactNode }) {
10903
10905
  );
10904
10906
  }
10905
10907
  `;
10906
- const apiIndexTs = `import { createApi } from './api.ts';
10908
+ const apiIndexTs = `import { createApi } from '${apiPackage}/client';
10907
10909
  import { getQueryClient } from '~/lib/query-client.ts';
10908
10910
  import { clientConfig } from '~/config/client.ts';
10909
10911
 
@@ -12428,7 +12430,7 @@ program.command("secrets:push").description("Push secrets to remote provider (SS
12428
12430
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
12429
12431
  const { loadWorkspaceConfig: loadWorkspaceConfig$1 } = await import("./config.mjs");
12430
12432
  const { pushSecrets: pushSecrets$1 } = await import("./sync-COnAugP-.mjs");
12431
- const { reconcileMissingSecrets } = await import("./reconcile-BjWhjfSp.mjs");
12433
+ const { reconcileMissingSecrets } = await import("./reconcile-DAAKa0YR.mjs");
12432
12434
  const { readStageSecrets: readStageSecrets$1, writeStageSecrets: writeStageSecrets$1 } = await import("./storage-Cs4WBsc4.mjs");
12433
12435
  const { workspace } = await loadWorkspaceConfig$1();
12434
12436
  const secrets = await readStageSecrets$1(options.stage, workspace.root);
@@ -12454,7 +12456,7 @@ program.command("secrets:pull").description("Pull secrets from remote provider (
12454
12456
  const { loadWorkspaceConfig: loadWorkspaceConfig$1 } = await import("./config.mjs");
12455
12457
  const { pullSecrets: pullSecrets$1 } = await import("./sync-COnAugP-.mjs");
12456
12458
  const { writeStageSecrets: writeStageSecrets$1 } = await import("./storage-Cs4WBsc4.mjs");
12457
- const { reconcileMissingSecrets } = await import("./reconcile-BjWhjfSp.mjs");
12459
+ const { reconcileMissingSecrets } = await import("./reconcile-DAAKa0YR.mjs");
12458
12460
  const { workspace } = await loadWorkspaceConfig$1();
12459
12461
  let secrets = await pullSecrets$1(options.stage, workspace);
12460
12462
  if (!secrets) {
@@ -12479,7 +12481,7 @@ program.command("secrets:reconcile").description("Backfill missing custom secret
12479
12481
  const globalOptions = program.opts();
12480
12482
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
12481
12483
  const { loadWorkspaceConfig: loadWorkspaceConfig$1 } = await import("./config.mjs");
12482
- const { reconcileMissingSecrets } = await import("./reconcile-BjWhjfSp.mjs");
12484
+ const { reconcileMissingSecrets } = await import("./reconcile-DAAKa0YR.mjs");
12483
12485
  const { readStageSecrets: readStageSecrets$1, writeStageSecrets: writeStageSecrets$1 } = await import("./storage-Cs4WBsc4.mjs");
12484
12486
  const { workspace } = await loadWorkspaceConfig$1();
12485
12487
  const secrets = await readStageSecrets$1(options.stage, workspace.root);