@geekmidas/cli 10.0.0-alpha.5 → 10.0.0-alpha.6

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 (65) hide show
  1. package/dist/{config-C21ocYNd.cjs → config-CNz5KaSR.cjs} +16 -45
  2. package/dist/config-CNz5KaSR.cjs.map +1 -0
  3. package/dist/{config-WRdsQYZK.mjs → config-CxP7P-qG.mjs} +17 -46
  4. package/dist/config-CxP7P-qG.mjs.map +1 -0
  5. package/dist/config.cjs +2 -2
  6. package/dist/config.d.cts +2 -2
  7. package/dist/config.d.mts +2 -2
  8. package/dist/config.mjs +2 -2
  9. package/dist/{credentials-BBIRJVp4.mjs → credentials-BK3Z93MX.mjs} +5 -5
  10. package/dist/credentials-BK3Z93MX.mjs.map +1 -0
  11. package/dist/{credentials-G1JwBoXH.cjs → credentials-DzsXZzkx.cjs} +5 -5
  12. package/dist/credentials-DzsXZzkx.cjs.map +1 -0
  13. package/dist/discover-CAlFgYec.mjs.map +1 -1
  14. package/dist/discover-DTmFeloL.cjs.map +1 -1
  15. package/dist/{index-BThUzEIp.d.mts → index-BGGdjueF.d.cts} +2 -2
  16. package/dist/index-BGGdjueF.d.cts.map +1 -0
  17. package/dist/{index-CHB4tSzX.d.cts → index-DEbaleny.d.mts} +2 -2
  18. package/dist/index-DEbaleny.d.mts.map +1 -0
  19. package/dist/index.cjs +307 -121
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.mjs +307 -121
  22. package/dist/index.mjs.map +1 -1
  23. package/dist/{openapi-kkQbsRVj.mjs → openapi-Bw8DWFWz.mjs} +104 -50
  24. package/dist/openapi-Bw8DWFWz.mjs.map +1 -0
  25. package/dist/{openapi-CA0yJUTN.cjs → openapi-D-dx9Akj.cjs} +122 -50
  26. package/dist/openapi-D-dx9Akj.cjs.map +1 -0
  27. package/dist/openapi.cjs +5 -3
  28. package/dist/openapi.d.cts +46 -10
  29. package/dist/openapi.d.cts.map +1 -1
  30. package/dist/openapi.d.mts +46 -10
  31. package/dist/openapi.d.mts.map +1 -1
  32. package/dist/openapi.mjs +4 -4
  33. package/dist/reconcile/public.d.cts +1 -1
  34. package/dist/reconcile/public.d.mts +1 -1
  35. package/dist/setup-8IWPsRIN.cjs +11 -0
  36. package/dist/{setup-DXvRLTZN.mjs → setup-BWMhbW-p.mjs} +3 -3
  37. package/dist/{setup-DXvRLTZN.mjs.map → setup-BWMhbW-p.mjs.map} +1 -1
  38. package/dist/{setup-Cm2UnAdh.cjs → setup-D7L4BgBT.cjs} +3 -3
  39. package/dist/{setup-Cm2UnAdh.cjs.map → setup-D7L4BgBT.cjs.map} +1 -1
  40. package/dist/{setup-ZijS4qeC.mjs → setup-DGIPd2fh.mjs} +4 -4
  41. package/dist/{types-C-arnQ1r.d.mts → types-BLSNdrk0.d.cts} +5 -13
  42. package/dist/{types-C-arnQ1r.d.mts.map → types-BLSNdrk0.d.cts.map} +1 -1
  43. package/dist/{types-abJQuk7m.d.cts → types-C3POXhw3.d.mts} +2 -10
  44. package/dist/{types-abJQuk7m.d.cts.map → types-C3POXhw3.d.mts.map} +1 -1
  45. package/dist/workspace/index.cjs +1 -1
  46. package/dist/workspace/index.d.cts +2 -2
  47. package/dist/workspace/index.d.mts +2 -2
  48. package/dist/workspace/index.mjs +1 -1
  49. package/dist/{workspace-DdJss8I6.cjs → workspace-CGaUAw5A.cjs} +3 -3
  50. package/dist/workspace-CnTqIlB3.mjs +8 -0
  51. package/dist/{workspace-BFMrAKqI.mjs → workspace-DIuZx-cc.mjs} +1 -17
  52. package/dist/{workspace-BFMrAKqI.mjs.map → workspace-DIuZx-cc.mjs.map} +1 -1
  53. package/dist/{workspace-BcucjwvA.cjs → workspace-LKiNyaDy.cjs} +1 -17
  54. package/dist/{workspace-BcucjwvA.cjs.map → workspace-LKiNyaDy.cjs.map} +1 -1
  55. package/package.json +11 -11
  56. package/dist/config-C21ocYNd.cjs.map +0 -1
  57. package/dist/config-WRdsQYZK.mjs.map +0 -1
  58. package/dist/credentials-BBIRJVp4.mjs.map +0 -1
  59. package/dist/credentials-G1JwBoXH.cjs.map +0 -1
  60. package/dist/index-BThUzEIp.d.mts.map +0 -1
  61. package/dist/index-CHB4tSzX.d.cts.map +0 -1
  62. package/dist/openapi-CA0yJUTN.cjs.map +0 -1
  63. package/dist/openapi-kkQbsRVj.mjs.map +0 -1
  64. package/dist/setup-B5_oHHUj.cjs +0 -11
  65. package/dist/workspace-k4l3rsFh.mjs +0 -8
@@ -1,7 +1,8 @@
1
1
  const require_chunk = require('./chunk-CUT6urMc.cjs');
2
2
  const require_discover = require('./discover-DTmFeloL.cjs');
3
- const require_config = require('./config-C21ocYNd.cjs');
3
+ const require_config = require('./config-CNz5KaSR.cjs');
4
4
  const node_path = require_chunk.__toESM(require("node:path"));
5
+ const __geekmidas_manifest = require_chunk.__toESM(require("@geekmidas/manifest"));
5
6
  const node_fs_promises = require_chunk.__toESM(require("node:fs/promises"));
6
7
  const node_child_process = require_chunk.__toESM(require("node:child_process"));
7
8
  const __geekmidas_constructs_endpoints = require_chunk.__toESM(require("@geekmidas/constructs/endpoints"));
@@ -603,24 +604,21 @@ export async function setupEndpoints(
603
604
  *
604
605
  * Falls back to the configured paths for an app that declares no surface.
605
606
  */
606
- function runtimeFor(context, fromDir) {
607
- const module$1 = context.surface?.module;
607
+ function runtimeFor(context, fromDir, owner) {
608
+ const module$1 = owner ? context.owners?.[owner] ?? context.surface?.module : context.surface?.module;
608
609
  if (module$1) {
609
610
  const specifier = importSpecifier(fromDir, module$1.specifier);
610
611
  return {
611
612
  imports: `import { ${module$1.exportName} as __surface } from '${specifier}';`,
612
613
  bindings: [
613
- "// What this surface was declared with. Objects, not module paths:",
614
- "// the entry imports the surface, so there is nothing to print.",
614
+ "// What this construct was declared with. Objects, not module paths:",
615
+ "// the entry imports the owner, so there is nothing to print.",
615
616
  "const envParser = __surface.envParser;",
616
617
  "const logger = __surface.logger;"
617
618
  ].join("\n")
618
619
  };
619
620
  }
620
- return {
621
- imports: [`import ${context.envParserImportPattern} from '${importSpecifier(fromDir, context.envParserPath)}';`, `import ${context.loggerImportPattern} from '${importSpecifier(fromDir, context.loggerPath)}';`].join("\n"),
622
- bindings: ""
623
- };
621
+ throw new Error(`No owner to take a logger and an environment parser from${owner ? ` for "${owner}"` : ""}. Build it from a \`RestApi\` or a \`Worker\`.`);
624
622
  }
625
623
  /** A relative specifier ESM will accept: always prefixed, never bare. */
626
624
  function importSpecifier(fromDir, target) {
@@ -993,6 +991,7 @@ import type { Hono as HonoType } from 'hono';
993
991
  import { setupEndpoints } from './endpoints.js';
994
992
  import { setupSubscribers } from './subscribers.js';
995
993
  import { setupQueues } from './queues.js';
994
+ import { setupCrons } from './crons.js';
996
995
  ${runtime.imports}
997
996
  ${telescopeImports}
998
997
  ${studioImports}
@@ -1080,6 +1079,12 @@ ${afterSetupCall}
1080
1079
  logger.error({ error }, 'Failed to start queue workers');
1081
1080
  });
1082
1081
 
1082
+ // Schedule this app's crons. Caught like the others: a scheduler that
1083
+ // cannot start is not a reason for the HTTP server not to.
1084
+ await setupCrons(envParser, logger).catch((error) => {
1085
+ logger.error({ error }, 'Failed to schedule crons');
1086
+ });
1087
+
1083
1088
  logger.info({ port }, 'Starting server');
1084
1089
 
1085
1090
  // Start HTTP server using provided serve function
@@ -1150,8 +1155,7 @@ export const handler = ${exportName};
1150
1155
  async generateProductionAppFile(outputDir, context) {
1151
1156
  const appFileName = "app.ts";
1152
1157
  const appPath = (0, node_path.join)(outputDir, appFileName);
1153
- const relativeLoggerPath = (0, node_path.relative)((0, node_path.dirname)(appPath), context.loggerPath);
1154
- const relativeEnvParserPath = (0, node_path.relative)((0, node_path.dirname)(appPath), context.envParserPath);
1158
+ const runtime = runtimeFor(context, (0, node_path.dirname)(appPath));
1155
1159
  const production = context.production;
1156
1160
  const healthCheckPath = production.healthCheck;
1157
1161
  const enableGracefulShutdown = production.gracefulShutdown;
@@ -1187,9 +1191,16 @@ export const handler = ${exportName};
1187
1191
  await setupQueues(envParser, logger).catch((error) => {
1188
1192
  logger.error({ error }, 'Failed to start queue workers');
1189
1193
  });
1194
+
1195
+ // Schedule this app's crons. Caught like the others: a scheduler that
1196
+ // cannot start is not a reason for the HTTP server not to.
1197
+ await setupCrons(envParser, logger).catch((error) => {
1198
+ logger.error({ error }, 'Failed to schedule crons');
1199
+ });
1190
1200
  ` : "";
1191
1201
  const subscriberImport = includeSubscribers ? `import { setupSubscribers } from './subscribers.js';
1192
- import { setupQueues } from './queues.js';` : "";
1202
+ import { setupQueues } from './queues.js';
1203
+ import { setupCrons } from './crons.js';` : "";
1193
1204
  const gracefulShutdownCode = enableGracefulShutdown ? `
1194
1205
  // Graceful shutdown handling
1195
1206
  let isShuttingDown = false;
@@ -1219,8 +1230,8 @@ import { Hono } from 'hono';
1219
1230
  import type { Hono as HonoType } from 'hono';
1220
1231
  import { setupEndpoints } from '${endpointsImportPath}';
1221
1232
  ${subscriberImport}
1222
- import ${context.envParserImportPattern} from '${relativeEnvParserPath}';
1223
- import ${context.loggerImportPattern} from '${relativeLoggerPath}';
1233
+ ${runtime.imports}
1234
+ ${runtime.bindings}
1224
1235
  ${hooksImports}
1225
1236
  ${cors.imports}
1226
1237
  ${context.storageDrivers?.imports ?? ""}
@@ -1828,6 +1839,16 @@ function normalizeRoutes(routes) {
1828
1839
  */
1829
1840
  const OPENAPI_OUTPUT_PATH = "./.gkm/openapi.ts";
1830
1841
  /**
1842
+ * Where a surface's generated client lands.
1843
+ *
1844
+ * Named from the surface, so `new RestApi('Webhooks')` writes
1845
+ * `.gkm/openapi/webhooks.ts` — the same kebab form that gives it its container
1846
+ * name and its `WEBHOOKS_URL`.
1847
+ */
1848
+ function openApiPathFor(surfaceId) {
1849
+ return `./.gkm/openapi/${(0, __geekmidas_manifest.kebabCase)(surfaceId)}.ts`;
1850
+ }
1851
+ /**
1831
1852
  * Resolve OpenAPI config from GkmConfig
1832
1853
  */
1833
1854
  function resolveOpenApiConfig(config) {
@@ -1846,33 +1867,66 @@ function resolveOpenApiConfig(config) {
1846
1867
  };
1847
1868
  }
1848
1869
  /**
1849
- * Generate OpenAPI spec from endpoints
1850
- * @returns Object with output path and endpoint count, or null if disabled
1870
+ * Load endpoints from a glob, then generate.
1871
+ *
1872
+ * For the callers that have no endpoints in hand — `gkm openapi`, and `gkm dev`
1873
+ * regenerating on reload. The glob is the app's derived one, off `AppSpec.code`,
1874
+ * not a `routes` field anybody wrote.
1875
+ */
1876
+ async function generateOpenApiFrom(routes, options = {}) {
1877
+ const loaded = await new EndpointGenerator().load(routes, void 0, options.bustCache);
1878
+ return generateOpenApi(loaded.map(({ construct }) => construct), options);
1879
+ }
1880
+ /**
1881
+ * Generate an OpenAPI spec for each surface these endpoints name.
1882
+ *
1883
+ * Takes the endpoints, not a glob to find them with. The build has already
1884
+ * loaded every one of them to generate handlers, so globbing again was a second
1885
+ * discovery pass over the same files — and the reason this function needed a
1886
+ * `routes` to be told where to look, which is how a retired config field stayed
1887
+ * load-bearing.
1888
+ *
1889
+ * @returns What was written, or null if disabled or there were none
1851
1890
  */
1852
- async function generateOpenApi(config, options = {}) {
1891
+ async function generateOpenApi(endpoints, options = {}) {
1853
1892
  const logger = options.silent ? { log: () => {} } : console;
1854
- const openApiConfig = resolveOpenApiConfig(config);
1893
+ const openApiConfig = resolveOpenApiConfig({ openapi: options.openapi });
1855
1894
  if (!openApiConfig.enabled) return null;
1856
- const endpointGenerator = new EndpointGenerator();
1857
- const loadedEndpoints = await endpointGenerator.load(config.routes, void 0, options.bustCache);
1858
- if (loadedEndpoints.length === 0) {
1895
+ if (endpoints.length === 0) {
1859
1896
  logger.log("No valid endpoints found for OpenAPI generation");
1860
1897
  return null;
1861
1898
  }
1862
- const endpoints = loadedEndpoints.map(({ construct }) => construct);
1863
- const outputPath = (0, node_path.join)(process.cwd(), OPENAPI_OUTPUT_PATH);
1864
- await (0, node_fs_promises.mkdir)((0, node_path.dirname)(outputPath), { recursive: true });
1899
+ const bySurface = /* @__PURE__ */ new Map();
1900
+ for (const endpoint of endpoints) {
1901
+ const owner = endpoint.owner ?? endpoint.surface?.id;
1902
+ if (!owner) continue;
1903
+ const existing = bySurface.get(owner);
1904
+ if (existing) existing.push(endpoint);
1905
+ else bySurface.set(owner, [endpoint]);
1906
+ }
1907
+ if (bySurface.size === 0) {
1908
+ logger.log("No endpoints named a surface, so no OpenAPI was generated");
1909
+ return null;
1910
+ }
1865
1911
  const tsGenerator = new OpenApiTsGenerator();
1866
- const tsContent = await tsGenerator.generate(endpoints, {
1867
- title: openApiConfig.title,
1868
- version: openApiConfig.version,
1869
- description: openApiConfig.description
1870
- });
1871
- await (0, node_fs_promises.writeFile)(outputPath, tsContent);
1872
- logger.log(`📄 OpenAPI client generated: ${OPENAPI_OUTPUT_PATH}`);
1912
+ const written = [];
1913
+ for (const [surfaceId, surfaceEndpoints] of bySurface) {
1914
+ const relative$1 = openApiPathFor(surfaceId);
1915
+ const outputPath = (0, node_path.join)(process.cwd(), relative$1);
1916
+ await (0, node_fs_promises.mkdir)((0, node_path.dirname)(outputPath), { recursive: true });
1917
+ const tsContent = await tsGenerator.generate(surfaceEndpoints, {
1918
+ title: openApiConfig.title ?? surfaceId,
1919
+ version: openApiConfig.version,
1920
+ description: openApiConfig.description
1921
+ });
1922
+ await (0, node_fs_promises.writeFile)(outputPath, tsContent);
1923
+ written.push(relative$1);
1924
+ logger.log(`📄 OpenAPI client generated: ${relative$1} (${surfaceEndpoints.length} endpoints)`);
1925
+ }
1873
1926
  return {
1874
- outputPath,
1875
- endpointCount: loadedEndpoints.length
1927
+ outputPath: (0, node_path.join)(process.cwd(), written[0]),
1928
+ outputPaths: written.map((r) => (0, node_path.join)(process.cwd(), r)),
1929
+ endpointCount: endpoints.length
1876
1930
  };
1877
1931
  }
1878
1932
  async function openapiCommand(options = {}) {
@@ -1882,12 +1936,12 @@ async function openapiCommand(options = {}) {
1882
1936
  if (loadedConfig.type === "single") {
1883
1937
  const config = loadedConfig.raw;
1884
1938
  if (!config.openapi) config.openapi = { enabled: true };
1885
- const result = await generateOpenApi(config);
1939
+ const result = await generateOpenApiFrom(config.constructs, { openapi: config.openapi });
1886
1940
  if (result) logger.log(`Found ${result.endpointCount} endpoints`);
1887
1941
  } else {
1888
1942
  const { workspace } = loadedConfig;
1889
1943
  const workspaceRoot = workspace.root;
1890
- const backendApps = Object.entries(workspace.apps).filter(([_, app]) => app.type === "backend" && app.routes !== void 0 && app.openapi !== false && (typeof app.openapi !== "object" || app.openapi.enabled !== false));
1944
+ const backendApps = Object.entries(workspace.apps).filter(([_, app]) => app.type === "backend" && app.openapi !== false && (typeof app.openapi !== "object" || app.openapi.enabled !== false));
1891
1945
  if (backendApps.length === 0) {
1892
1946
  logger.log("No backend apps with OpenAPI enabled found");
1893
1947
  return;
@@ -1901,8 +1955,12 @@ async function openapiCommand(options = {}) {
1901
1955
  return;
1902
1956
  }
1903
1957
  for (const [appName, app] of backendApps) {
1904
- if (app.type !== "backend" || !app.routes) continue;
1905
1958
  const appPath = (0, node_path.join)(workspaceRoot, app.path);
1959
+ if ((0, node_path.resolve)(appPath) === (0, node_path.resolve)(workspaceRoot)) {
1960
+ const result = await generateOpenApiForApp(workspaceRoot, appName, app, false);
1961
+ if (result) logger.log(`Found ${result.endpointCount} endpoints`);
1962
+ continue;
1963
+ }
1906
1964
  await runOpenApiInSubprocess(appPath, appName);
1907
1965
  }
1908
1966
  }
@@ -1915,18 +1973,14 @@ async function openapiCommand(options = {}) {
1915
1973
  * Runs in-process. The caller is responsible for ensuring `process.cwd()`
1916
1974
  * is the app's directory so tsx loads the app's tsconfig path aliases.
1917
1975
  */
1918
- async function generateOpenApiForApp(workspaceRoot, _appName, app) {
1919
- if (app.type !== "backend" || !app.routes) return null;
1976
+ async function generateOpenApiForApp(workspaceRoot, _appName, app, silent = true) {
1977
+ if (app.type !== "backend") return null;
1920
1978
  const appPath = (0, node_path.join)(workspaceRoot, app.path);
1921
- const routes = normalizeRoutes(app.routes);
1922
- const routesGlob = routes.map((r) => (0, node_path.join)(appPath, r));
1923
- const gkmConfig = {
1924
- routes: routesGlob,
1925
- envParser: app.envParser || "",
1926
- logger: app.logger || "",
1927
- openapi: app.openapi
1928
- };
1929
- return generateOpenApi(gkmConfig, { silent: true });
1979
+ const globs = [(0, node_path.join)(appPath, "**/*.ts")];
1980
+ return generateOpenApiFrom(globs, {
1981
+ openapi: app.openapi ?? { enabled: true },
1982
+ silent
1983
+ });
1930
1984
  }
1931
1985
  /**
1932
1986
  * Resolve the gkm bin path. Tests can override via `GKM_BIN_PATH` env var
@@ -1944,7 +1998,7 @@ function resolveGkmBinPath() {
1944
1998
  */
1945
1999
  async function runOpenApiInSubprocess(appCwd, appName) {
1946
2000
  const binPath = resolveGkmBinPath();
1947
- await new Promise((resolve, reject) => {
2001
+ await new Promise((resolve$1, reject) => {
1948
2002
  const child = (0, node_child_process.spawn)(process.execPath, [
1949
2003
  binPath,
1950
2004
  "openapi",
@@ -1957,7 +2011,7 @@ async function runOpenApiInSubprocess(appCwd, appName) {
1957
2011
  });
1958
2012
  child.on("error", reject);
1959
2013
  child.on("close", (code) => {
1960
- if (code === 0) resolve();
2014
+ if (code === 0) resolve$1();
1961
2015
  else reject(new Error(`OpenAPI generation for app "${appName}" exited with code ${code}`));
1962
2016
  });
1963
2017
  });
@@ -1982,12 +2036,24 @@ Object.defineProperty(exports, 'generateOpenApi', {
1982
2036
  return generateOpenApi;
1983
2037
  }
1984
2038
  });
2039
+ Object.defineProperty(exports, 'generateOpenApiFrom', {
2040
+ enumerable: true,
2041
+ get: function () {
2042
+ return generateOpenApiFrom;
2043
+ }
2044
+ });
1985
2045
  Object.defineProperty(exports, 'normalizeRoutes', {
1986
2046
  enumerable: true,
1987
2047
  get: function () {
1988
2048
  return normalizeRoutes;
1989
2049
  }
1990
2050
  });
2051
+ Object.defineProperty(exports, 'openApiPathFor', {
2052
+ enumerable: true,
2053
+ get: function () {
2054
+ return openApiPathFor;
2055
+ }
2056
+ });
1991
2057
  Object.defineProperty(exports, 'openapiCommand', {
1992
2058
  enumerable: true,
1993
2059
  get: function () {
@@ -2000,4 +2066,10 @@ Object.defineProperty(exports, 'resolveOpenApiConfig', {
2000
2066
  return resolveOpenApiConfig;
2001
2067
  }
2002
2068
  });
2003
- //# sourceMappingURL=openapi-CA0yJUTN.cjs.map
2069
+ Object.defineProperty(exports, 'runtimeFor', {
2070
+ enumerable: true,
2071
+ get: function () {
2072
+ return runtimeFor;
2073
+ }
2074
+ });
2075
+ //# sourceMappingURL=openapi-D-dx9Akj.cjs.map