@geekmidas/cli 10.0.0-alpha.6 → 10.0.0-alpha.61
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/README.md +225 -268
- package/bin/adjacent-tsconfig.mjs +97 -0
- package/bin/gkm.mjs +16 -2
- package/bin/owning-tsconfig-jsx-register.mjs +18 -0
- package/bin/owning-tsconfig-jsx.mjs +108 -0
- package/dist/{HostingerProvider-h3EbEp-Z.cjs → HostingerProvider-CgDaD8VR.cjs} +21 -22
- package/dist/HostingerProvider-CgDaD8VR.cjs.map +1 -0
- package/dist/{HostingerProvider-Cft7lEYr.mjs → HostingerProvider-DI_Pr2VE.mjs} +20 -21
- package/dist/HostingerProvider-DI_Pr2VE.mjs.map +1 -0
- package/dist/LegacyStateStore-C7vFAxbu.mjs +89 -0
- package/dist/LegacyStateStore-C7vFAxbu.mjs.map +1 -0
- package/dist/LegacyStateStore-JbBVFp_2.cjs +89 -0
- package/dist/LegacyStateStore-JbBVFp_2.cjs.map +1 -0
- package/dist/LocalStateStore-DHj_-CQB.cjs +176 -0
- package/dist/LocalStateStore-DHj_-CQB.cjs.map +1 -0
- package/dist/LocalStateStore-DfUwQsL8.mjs +165 -0
- package/dist/LocalStateStore-DfUwQsL8.mjs.map +1 -0
- package/dist/{openapi-D-dx9Akj.cjs → OpenApiTsGenerator-BSrgw7B0.cjs} +360 -470
- package/dist/OpenApiTsGenerator-BSrgw7B0.cjs.map +1 -0
- package/dist/{openapi-Bw8DWFWz.mjs → OpenApiTsGenerator-q5B0z8Xg.mjs} +325 -404
- package/dist/OpenApiTsGenerator-q5B0z8Xg.mjs.map +1 -0
- package/dist/{Route53Provider-RdpUDJQk.mjs → Route53Provider-Cvj40A8I.mjs} +12 -12
- package/dist/Route53Provider-Cvj40A8I.mjs.map +1 -0
- package/dist/{Route53Provider-di2fMM5N.cjs → Route53Provider-DVILBsvV.cjs} +20 -21
- package/dist/Route53Provider-DVILBsvV.cjs.map +1 -0
- package/dist/S3StateStore-Dq6hHtzY.mjs +161 -0
- package/dist/S3StateStore-Dq6hHtzY.mjs.map +1 -0
- package/dist/S3StateStore-xqnpUrzy.cjs +160 -0
- package/dist/S3StateStore-xqnpUrzy.cjs.map +1 -0
- package/dist/SSMStateStore-5dBRwVlJ.cjs +153 -0
- package/dist/SSMStateStore-5dBRwVlJ.cjs.map +1 -0
- package/dist/SSMStateStore-SUmvAbLi.mjs +154 -0
- package/dist/SSMStateStore-SUmvAbLi.mjs.map +1 -0
- package/dist/appPorts-C9z9Pzn9.mjs +223 -0
- package/dist/appPorts-C9z9Pzn9.mjs.map +1 -0
- package/dist/appPorts-Cu79hJF6.cjs +264 -0
- package/dist/appPorts-Cu79hJF6.cjs.map +1 -0
- package/dist/aws-DkHdTV-p.cjs +61 -0
- package/dist/aws-DkHdTV-p.cjs.map +1 -0
- package/dist/aws-DojzQnLd.mjs +61 -0
- package/dist/aws-DojzQnLd.mjs.map +1 -0
- package/dist/{backup-provisioner-BrsHwYG0.cjs → backup-provisioner-BmhIO_Yr.cjs} +21 -19
- package/dist/backup-provisioner-BmhIO_Yr.cjs.map +1 -0
- package/dist/{backup-provisioner-Bgj5Vi_L.mjs → backup-provisioner-DIVCbfee.mjs} +10 -7
- package/dist/backup-provisioner-DIVCbfee.mjs.map +1 -0
- package/dist/{bundler-Be8Zg4Wd.mjs → bundler-B5VsKW-_.mjs} +18 -29
- package/dist/bundler-B5VsKW-_.mjs.map +1 -0
- package/dist/{bundler-BY1OmV1e.cjs → bundler-DXATpO1T.cjs} +20 -32
- package/dist/bundler-DXATpO1T.cjs.map +1 -0
- package/dist/cli-DEA_J3Sa.mjs +69 -0
- package/dist/cli-DEA_J3Sa.mjs.map +1 -0
- package/dist/cli-DQdrVkj2.cjs +69 -0
- package/dist/cli-DQdrVkj2.cjs.map +1 -0
- package/dist/{config-CxP7P-qG.mjs → config-C5-EEdmr.mjs} +144 -127
- package/dist/config-C5-EEdmr.mjs.map +1 -0
- package/dist/{config-CNz5KaSR.cjs → config-DXnkCEq0.cjs} +212 -184
- package/dist/config-DXnkCEq0.cjs.map +1 -0
- package/dist/config.cjs +9 -6
- package/dist/config.d.cts +124 -33
- package/dist/config.d.cts.map +1 -1
- package/dist/config.d.mts +124 -33
- package/dist/config.d.mts.map +1 -1
- package/dist/config.mjs +3 -5
- package/dist/deploy/public.cjs +22 -0
- package/dist/deploy/public.d.cts +459 -0
- package/dist/deploy/public.d.cts.map +1 -0
- package/dist/deploy/public.d.mts +459 -0
- package/dist/deploy/public.d.mts.map +1 -0
- package/dist/deploy/public.mjs +5 -0
- package/dist/deploy/sniffer-envkit-patch.cjs +18 -10
- package/dist/deploy/sniffer-envkit-patch.cjs.map +1 -1
- package/dist/deploy/sniffer-envkit-patch.d.cts +0 -2
- package/dist/deploy/sniffer-envkit-patch.d.cts.map +1 -1
- package/dist/deploy/sniffer-envkit-patch.d.mts +0 -2
- package/dist/deploy/sniffer-envkit-patch.d.mts.map +1 -1
- package/dist/deploy/sniffer-envkit-patch.mjs +10 -2
- package/dist/deploy/sniffer-envkit-patch.mjs.map +1 -1
- package/dist/deploy/sniffer-hooks.cjs +13 -7
- package/dist/deploy/sniffer-hooks.cjs.map +1 -1
- package/dist/deploy/sniffer-hooks.d.cts +1 -2
- package/dist/deploy/sniffer-hooks.d.cts.map +1 -1
- package/dist/deploy/sniffer-hooks.d.mts +1 -2
- package/dist/deploy/sniffer-hooks.d.mts.map +1 -1
- package/dist/deploy/sniffer-hooks.mjs +10 -3
- package/dist/deploy/sniffer-hooks.mjs.map +1 -1
- package/dist/deploy/sniffer-loader.cjs +16 -7
- package/dist/deploy/sniffer-loader.cjs.map +1 -1
- package/dist/deploy/sniffer-loader.d.cts +1 -1
- package/dist/deploy/sniffer-loader.d.mts +1 -1
- package/dist/deploy/sniffer-loader.mjs +14 -3
- package/dist/deploy/sniffer-loader.mjs.map +1 -1
- package/dist/deploy/sniffer-routes-worker.cjs +11 -11
- package/dist/deploy/sniffer-routes-worker.cjs.map +1 -1
- package/dist/deploy/sniffer-routes-worker.d.cts +1 -1
- package/dist/deploy/sniffer-routes-worker.d.mts +1 -1
- package/dist/deploy/sniffer-routes-worker.mjs +3 -3
- package/dist/deploy/sniffer-routes-worker.mjs.map +1 -1
- package/dist/deploy/sniffer-worker.cjs +15 -6
- package/dist/deploy/sniffer-worker.cjs.map +1 -1
- package/dist/deploy/sniffer-worker.d.cts +1 -3
- package/dist/deploy/sniffer-worker.d.cts.map +1 -1
- package/dist/deploy/sniffer-worker.d.mts +1 -3
- package/dist/deploy/sniffer-worker.d.mts.map +1 -1
- package/dist/deploy/sniffer-worker.mjs +15 -4
- package/dist/deploy/sniffer-worker.mjs.map +1 -1
- package/dist/deploy-BJcLmVTc.mjs +3282 -0
- package/dist/deploy-BJcLmVTc.mjs.map +1 -0
- package/dist/deploy-BbJdgQ2b.cjs +3365 -0
- package/dist/deploy-BbJdgQ2b.cjs.map +1 -0
- package/dist/{discover-DTmFeloL.cjs → discover-Bc-4eA_p.cjs} +131 -103
- package/dist/discover-Bc-4eA_p.cjs.map +1 -0
- package/dist/{discover-CAlFgYec.mjs → discover-FrYvzkeC.mjs} +91 -58
- package/dist/discover-FrYvzkeC.mjs.map +1 -0
- package/dist/{emit-CiZS_5Ub.mjs → emit-C1e8qD08.mjs} +13 -26
- package/dist/emit-C1e8qD08.mjs.map +1 -0
- package/dist/{emit-CbcRolsa.cjs → emit-Dmc1nvdS.cjs} +31 -57
- package/dist/emit-Dmc1nvdS.cjs.map +1 -0
- package/dist/encryption-DaA9gRXr.mjs +90 -0
- package/dist/encryption-DaA9gRXr.mjs.map +1 -0
- package/dist/encryption-ojzUo7-z.cjs +91 -0
- package/dist/encryption-ojzUo7-z.cjs.map +1 -0
- package/dist/fakes-C9RiT6XG.mjs +125 -0
- package/dist/fakes-C9RiT6XG.mjs.map +1 -0
- package/dist/fakes-zW-jNAbQ.cjs +148 -0
- package/dist/fakes-zW-jNAbQ.cjs.map +1 -0
- package/dist/github-Cq57poPj.cjs +213 -0
- package/dist/github-Cq57poPj.cjs.map +1 -0
- package/dist/github-DmCj2u95.mjs +213 -0
- package/dist/github-DmCj2u95.mjs.map +1 -0
- package/dist/home-DOzBaWaL.cjs +33 -0
- package/dist/home-DOzBaWaL.cjs.map +1 -0
- package/dist/home-GI7pJl1M.mjs +22 -0
- package/dist/home-GI7pJl1M.mjs.map +1 -0
- package/dist/{index-DEbaleny.d.mts → index-Da1-oa9W.d.mts} +4 -23
- package/dist/index-Da1-oa9W.d.mts.map +1 -0
- package/dist/{index-BGGdjueF.d.cts → index-UiWCaGzU.d.cts} +4 -23
- package/dist/index-UiWCaGzU.d.cts.map +1 -0
- package/dist/index.cjs +10712 -12248
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +10480 -12040
- package/dist/index.mjs.map +1 -1
- package/dist/migrate-5_J5JySj.mjs +265 -0
- package/dist/migrate-5_J5JySj.mjs.map +1 -0
- package/dist/migrate-BScRpCEx.cjs +270 -0
- package/dist/migrate-BScRpCEx.cjs.map +1 -0
- package/dist/openapi.cjs +198 -10
- package/dist/openapi.cjs.map +1 -0
- package/dist/openapi.d.cts +21 -19
- package/dist/openapi.d.cts.map +1 -1
- package/dist/openapi.d.mts +21 -19
- package/dist/openapi.d.mts.map +1 -1
- package/dist/openapi.mjs +193 -5
- package/dist/openapi.mjs.map +1 -0
- package/dist/ready-DQIy21W5.mjs +760 -0
- package/dist/ready-DQIy21W5.mjs.map +1 -0
- package/dist/ready-XlNx-Gbo.cjs +807 -0
- package/dist/ready-XlNx-Gbo.cjs.map +1 -0
- package/dist/reconcile/public.cjs +3 -5
- package/dist/reconcile/public.d.cts +30 -33
- package/dist/reconcile/public.d.cts.map +1 -1
- package/dist/reconcile/public.d.mts +30 -33
- package/dist/reconcile/public.d.mts.map +1 -1
- package/dist/reconcile/public.mjs +3 -4
- package/dist/{reconcile-CFs8C_1a.mjs → reconcile--I7V4Klj.mjs} +4 -7
- package/dist/reconcile--I7V4Klj.mjs.map +1 -0
- package/dist/{reconcile-D0pimNiy.cjs → reconcile-CuCQBa5-.cjs} +5 -8
- package/dist/reconcile-CuCQBa5-.cjs.map +1 -0
- package/dist/rolldown-runtime-BhDjJH2R.mjs +15 -0
- package/dist/{chunk-CUT6urMc.cjs → rolldown-runtime-C0BPl7ul.cjs} +23 -10
- package/dist/sniffer-CQmJnNJM.cjs +7115 -0
- package/dist/sniffer-CQmJnNJM.cjs.map +1 -0
- package/dist/sniffer-bdleks5l.mjs +6561 -0
- package/dist/sniffer-bdleks5l.mjs.map +1 -0
- package/dist/storage-BzaUxmqe.mjs +124 -0
- package/dist/storage-BzaUxmqe.mjs.map +1 -0
- package/dist/storage-CSGoC3bK.cjs +152 -0
- package/dist/storage-CSGoC3bK.cjs.map +1 -0
- package/dist/store-BS8A7NcA.mjs +415 -0
- package/dist/store-BS8A7NcA.mjs.map +1 -0
- package/dist/store-KvNQwYaB.cjs +510 -0
- package/dist/store-KvNQwYaB.cjs.map +1 -0
- package/dist/types-Bp1mVxG0.d.mts +6410 -0
- package/dist/types-Bp1mVxG0.d.mts.map +1 -0
- package/dist/types-efNLu9xu.d.cts +6411 -0
- package/dist/types-efNLu9xu.d.cts.map +1 -0
- package/dist/vitest.cjs +65 -0
- package/dist/vitest.cjs.map +1 -0
- package/dist/vitest.d.cts +29 -0
- package/dist/vitest.d.cts.map +1 -0
- package/dist/vitest.d.mts +29 -0
- package/dist/vitest.d.mts.map +1 -0
- package/dist/vitest.mjs +65 -0
- package/dist/vitest.mjs.map +1 -0
- package/dist/workspace/index.cjs +3 -4
- package/dist/workspace/index.d.cts +3 -3
- package/dist/workspace/index.d.mts +3 -3
- package/dist/workspace/index.mjs +2 -3
- package/dist/{workspace-LKiNyaDy.cjs → workspace-B64Xk1Mb.cjs} +1070 -1118
- package/dist/workspace-B64Xk1Mb.cjs.map +1 -0
- package/dist/{workspace-DIuZx-cc.mjs → workspace-Bp1xVaOz.mjs} +901 -972
- package/dist/workspace-Bp1xVaOz.mjs.map +1 -0
- package/package.json +38 -20
- package/dist/CachedStateProvider-BLo7zv7S.cjs +0 -3
- package/dist/CachedStateProvider-BxoAm-B2.mjs +0 -3
- package/dist/CachedStateProvider-CqPdW7CB.cjs +0 -60
- package/dist/CachedStateProvider-CqPdW7CB.cjs.map +0 -1
- package/dist/CachedStateProvider-DTniehMP.mjs +0 -54
- package/dist/CachedStateProvider-DTniehMP.mjs.map +0 -1
- package/dist/HostingerProvider-Cft7lEYr.mjs.map +0 -1
- package/dist/HostingerProvider-h3EbEp-Z.cjs.map +0 -1
- package/dist/LocalStateProvider-Bn6tS-oL.mjs +0 -42
- package/dist/LocalStateProvider-Bn6tS-oL.mjs.map +0 -1
- package/dist/LocalStateProvider-Db9SEjyH.cjs +0 -43
- package/dist/LocalStateProvider-Db9SEjyH.cjs.map +0 -1
- package/dist/Route53Provider-RdpUDJQk.mjs.map +0 -1
- package/dist/Route53Provider-di2fMM5N.cjs.map +0 -1
- package/dist/SSMStateProvider-BRt2py-A.mjs +0 -66
- package/dist/SSMStateProvider-BRt2py-A.mjs.map +0 -1
- package/dist/SSMStateProvider-DyX8s9HI.cjs +0 -66
- package/dist/SSMStateProvider-DyX8s9HI.cjs.map +0 -1
- package/dist/backup-provisioner-Bgj5Vi_L.mjs.map +0 -1
- package/dist/backup-provisioner-BrsHwYG0.cjs.map +0 -1
- package/dist/bundler-BY1OmV1e.cjs.map +0 -1
- package/dist/bundler-Be8Zg4Wd.mjs.map +0 -1
- package/dist/chunk-Duj1WY3L.mjs +0 -7
- package/dist/config-CNz5KaSR.cjs.map +0 -1
- package/dist/config-CxP7P-qG.mjs.map +0 -1
- package/dist/credentials-B5zRHdAl.mjs +0 -141
- package/dist/credentials-B5zRHdAl.mjs.map +0 -1
- package/dist/credentials-BK3Z93MX.mjs +0 -2548
- package/dist/credentials-BK3Z93MX.mjs.map +0 -1
- package/dist/credentials-BapzjyV5.cjs +0 -195
- package/dist/credentials-BapzjyV5.cjs.map +0 -1
- package/dist/credentials-DzsXZzkx.cjs +0 -2680
- package/dist/credentials-DzsXZzkx.cjs.map +0 -1
- package/dist/discover-CAlFgYec.mjs.map +0 -1
- package/dist/discover-DTmFeloL.cjs.map +0 -1
- package/dist/dokploy-api-BS2xnJLZ.mjs +0 -3
- package/dist/dokploy-api-BsVH0y_s.cjs +0 -718
- package/dist/dokploy-api-BsVH0y_s.cjs.map +0 -1
- package/dist/dokploy-api-BuxDRo3l.cjs +0 -3
- package/dist/dokploy-api-aTFPz7_4.mjs +0 -706
- package/dist/dokploy-api-aTFPz7_4.mjs.map +0 -1
- package/dist/emit-CbcRolsa.cjs.map +0 -1
- package/dist/emit-CiZS_5Ub.mjs.map +0 -1
- package/dist/encryption-C6jaU0hE.cjs +0 -54
- package/dist/encryption-C6jaU0hE.cjs.map +0 -1
- package/dist/encryption-CHzzeR8a.cjs +0 -4
- package/dist/encryption-CQUncu7v.mjs +0 -3
- package/dist/encryption-D-abyhZx.mjs +0 -42
- package/dist/encryption-D-abyhZx.mjs.map +0 -1
- package/dist/fullstack-secrets-C-GGohke.cjs +0 -111
- package/dist/fullstack-secrets-C-GGohke.cjs.map +0 -1
- package/dist/fullstack-secrets-D1o9-G5l.mjs +0 -87
- package/dist/fullstack-secrets-D1o9-G5l.mjs.map +0 -1
- package/dist/generator-CNzBw7g5.cjs +0 -289
- package/dist/generator-CNzBw7g5.cjs.map +0 -1
- package/dist/generator-VE2JrFlY.mjs +0 -253
- package/dist/generator-VE2JrFlY.mjs.map +0 -1
- package/dist/index-BGGdjueF.d.cts.map +0 -1
- package/dist/index-DEbaleny.d.mts.map +0 -1
- package/dist/openapi-Bw8DWFWz.mjs.map +0 -1
- package/dist/openapi-D-dx9Akj.cjs.map +0 -1
- package/dist/openapi-react-query-Byltvm_7.mjs +0 -167
- package/dist/openapi-react-query-Byltvm_7.mjs.map +0 -1
- package/dist/openapi-react-query-CmJ1xDbn.cjs +0 -173
- package/dist/openapi-react-query-CmJ1xDbn.cjs.map +0 -1
- package/dist/openapi-react-query.cjs +0 -4
- package/dist/openapi-react-query.d.cts +0 -11
- package/dist/openapi-react-query.d.cts.map +0 -1
- package/dist/openapi-react-query.d.mts +0 -11
- package/dist/openapi-react-query.d.mts.map +0 -1
- package/dist/openapi-react-query.mjs +0 -4
- package/dist/reconcile-CFs8C_1a.mjs.map +0 -1
- package/dist/reconcile-D0pimNiy.cjs.map +0 -1
- package/dist/setup-8IWPsRIN.cjs +0 -11
- package/dist/setup-BWMhbW-p.mjs +0 -443
- package/dist/setup-BWMhbW-p.mjs.map +0 -1
- package/dist/setup-D7L4BgBT.cjs +0 -473
- package/dist/setup-D7L4BgBT.cjs.map +0 -1
- package/dist/setup-DGIPd2fh.mjs +0 -11
- package/dist/storage-BJmzYxt8.cjs +0 -363
- package/dist/storage-BJmzYxt8.cjs.map +0 -1
- package/dist/storage-BM9hGpgv.cjs +0 -7
- package/dist/storage-Bi24WfoW.mjs +0 -297
- package/dist/storage-Bi24WfoW.mjs.map +0 -1
- package/dist/storage-CYlGwWTj.mjs +0 -3
- package/dist/sync-CmEuNZsB.mjs +0 -76
- package/dist/sync-CmEuNZsB.mjs.map +0 -1
- package/dist/sync-D306yOWu.cjs +0 -4
- package/dist/sync-SizaChmC.cjs +0 -93
- package/dist/sync-SizaChmC.cjs.map +0 -1
- package/dist/sync-hOqAWHR6.mjs +0 -3
- package/dist/types-BLSNdrk0.d.cts +0 -2176
- package/dist/types-BLSNdrk0.d.cts.map +0 -1
- package/dist/types-C3POXhw3.d.mts +0 -2176
- package/dist/types-C3POXhw3.d.mts.map +0 -1
- package/dist/workspace-CGaUAw5A.cjs +0 -9
- package/dist/workspace-CnTqIlB3.mjs +0 -8
- package/dist/workspace-DIuZx-cc.mjs.map +0 -1
- package/dist/workspace-LKiNyaDy.cjs.map +0 -1
|
@@ -1,21 +1,16 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const node_child_process = require_chunk.__toESM(require("node:child_process"));
|
|
8
|
-
const __geekmidas_constructs_endpoints = require_chunk.__toESM(require("@geekmidas/constructs/endpoints"));
|
|
9
|
-
const node_url = require_chunk.__toESM(require("node:url"));
|
|
10
|
-
const __geekmidas_schema_conversion = require_chunk.__toESM(require("@geekmidas/schema/conversion"));
|
|
11
|
-
|
|
1
|
+
const require_discover = require("./discover-Bc-4eA_p.cjs");
|
|
2
|
+
let node_path = require("node:path");
|
|
3
|
+
let node_fs = require("node:fs");
|
|
4
|
+
let node_fs_promises = require("node:fs/promises");
|
|
5
|
+
let _geekmidas_constructs_endpoints = require("@geekmidas/constructs/endpoints");
|
|
6
|
+
let _geekmidas_schema_conversion = require("@geekmidas/schema/conversion");
|
|
12
7
|
//#region src/build/endpoint-analyzer.ts
|
|
13
8
|
/**
|
|
14
9
|
* Analyze an endpoint to extract its features
|
|
15
10
|
*/
|
|
16
11
|
function analyzeEndpointFeatures(endpoint) {
|
|
17
12
|
return {
|
|
18
|
-
hasAuth: !!endpoint.authorizer,
|
|
13
|
+
hasAuth: !!endpoint.authorizer || endpoint.hasSession === true,
|
|
19
14
|
hasServices: endpoint.services.length > 0,
|
|
20
15
|
hasDatabase: !!endpoint.databaseService,
|
|
21
16
|
hasBodyValidation: !!endpoint.input?.body,
|
|
@@ -85,7 +80,6 @@ function summarizeAnalysis(analyses) {
|
|
|
85
80
|
byFeature
|
|
86
81
|
};
|
|
87
82
|
}
|
|
88
|
-
|
|
89
83
|
//#endregion
|
|
90
84
|
//#region src/build/handler-templates.ts
|
|
91
85
|
/**
|
|
@@ -107,8 +101,7 @@ function generateMinimalHandler(analysis) {
|
|
|
107
101
|
const { exportName, features } = analysis;
|
|
108
102
|
const method = analysis.method.toLowerCase();
|
|
109
103
|
const validators = generateValidators(exportName, features);
|
|
110
|
-
|
|
111
|
-
if (!hasValidators && !features.hasOutputValidation) return `
|
|
104
|
+
if (!(validators.length > 0) && !features.hasOutputValidation) return `
|
|
112
105
|
// Minimal handler: ${analysis.route} (${analysis.method})
|
|
113
106
|
app.${method}('${analysis.route}', async (c) => {
|
|
114
107
|
const result = await ${exportName}.handler(
|
|
@@ -256,10 +249,10 @@ function generateValidatorsFile(analyses) {
|
|
|
256
249
|
const needsQuery = analyses.some((a) => a.features.hasQueryValidation);
|
|
257
250
|
const needsParams = analyses.some((a) => a.features.hasParamValidation);
|
|
258
251
|
if (!needsBody && !needsQuery && !needsParams) return `// No validators needed for this build\nexport {};\n`;
|
|
259
|
-
const exports
|
|
252
|
+
const exports = [];
|
|
260
253
|
const factories = [];
|
|
261
254
|
if (needsBody) {
|
|
262
|
-
exports
|
|
255
|
+
exports.push("validateBody");
|
|
263
256
|
factories.push(`
|
|
264
257
|
export const validateBody = (endpoint: any) =>
|
|
265
258
|
validator('json', async (value, c) => {
|
|
@@ -270,7 +263,7 @@ export const validateBody = (endpoint: any) =>
|
|
|
270
263
|
});`);
|
|
271
264
|
}
|
|
272
265
|
if (needsQuery) {
|
|
273
|
-
exports
|
|
266
|
+
exports.push("validateQuery");
|
|
274
267
|
factories.push(`
|
|
275
268
|
export const validateQuery = (endpoint: any) =>
|
|
276
269
|
validator('query', async (_, c) => {
|
|
@@ -282,7 +275,7 @@ export const validateQuery = (endpoint: any) =>
|
|
|
282
275
|
});`);
|
|
283
276
|
}
|
|
284
277
|
if (needsParams) {
|
|
285
|
-
exports
|
|
278
|
+
exports.push("validateParams");
|
|
286
279
|
factories.push(`
|
|
287
280
|
export const validateParams = (endpoint: any) =>
|
|
288
281
|
validator('param', async (params, c) => {
|
|
@@ -306,8 +299,7 @@ ${factories.join("\n")}
|
|
|
306
299
|
*/
|
|
307
300
|
function generateMinimalEndpointFile(analysis, endpointImport) {
|
|
308
301
|
const { exportName, features } = analysis;
|
|
309
|
-
const
|
|
310
|
-
const validatorImport = needsValidators ? generateValidatorImportsForEndpoint(analysis) : "";
|
|
302
|
+
const validatorImport = features.hasBodyValidation || features.hasQueryValidation || features.hasParamValidation ? generateValidatorImportsForEndpoint(analysis) : "";
|
|
311
303
|
const handler = generateMinimalHandler(analysis);
|
|
312
304
|
return `/**
|
|
313
305
|
* Minimal endpoint: ${analysis.route} (${analysis.method})
|
|
@@ -332,8 +324,7 @@ ${handler}
|
|
|
332
324
|
*/
|
|
333
325
|
function generateStandardEndpointFile(analysis, endpointImport) {
|
|
334
326
|
const { exportName, features } = analysis;
|
|
335
|
-
const
|
|
336
|
-
const validatorImport = needsValidators ? generateValidatorImportsForEndpoint(analysis) : "";
|
|
327
|
+
const validatorImport = features.hasBodyValidation || features.hasQueryValidation || features.hasParamValidation ? generateValidatorImportsForEndpoint(analysis) : "";
|
|
337
328
|
const eventsImport = features.hasEvents ? `import { publishConstructEvents } from '@geekmidas/constructs/endpoints';` : "";
|
|
338
329
|
const handler = generateStandardHandler(analysis);
|
|
339
330
|
return `/**
|
|
@@ -425,7 +416,7 @@ export function setupFullEndpoints(
|
|
|
425
416
|
}
|
|
426
417
|
const imports = tierEndpoints.map((a) => `import { setup${capitalize(a.exportName)} } from './${a.exportName}.js';`).join("\n");
|
|
427
418
|
if (tier === "minimal") {
|
|
428
|
-
const calls
|
|
419
|
+
const calls = tierEndpoints.map((a) => ` setup${capitalize(a.exportName)}(app, logger);`).join("\n");
|
|
429
420
|
return `/**
|
|
430
421
|
* Minimal-tier endpoint index (${tierEndpoints.length} endpoints)
|
|
431
422
|
* Near-raw-Hono performance
|
|
@@ -438,12 +429,12 @@ export function setupMinimalEndpoints(
|
|
|
438
429
|
app: Hono,
|
|
439
430
|
logger: Logger,
|
|
440
431
|
): void {
|
|
441
|
-
${calls
|
|
432
|
+
${calls}
|
|
442
433
|
}
|
|
443
434
|
`;
|
|
444
435
|
}
|
|
445
436
|
if (tier === "standard") {
|
|
446
|
-
const calls
|
|
437
|
+
const calls = tierEndpoints.map((a) => ` setup${capitalize(a.exportName)}(app, serviceDiscovery, logger);`).join("\n");
|
|
447
438
|
return `/**
|
|
448
439
|
* Standard-tier endpoint index (${tierEndpoints.length} endpoints)
|
|
449
440
|
* Auth and/or services enabled
|
|
@@ -458,7 +449,7 @@ export function setupStandardEndpoints(
|
|
|
458
449
|
serviceDiscovery: ServiceDiscovery<any, any>,
|
|
459
450
|
logger: Logger,
|
|
460
451
|
): void {
|
|
461
|
-
${calls
|
|
452
|
+
${calls}
|
|
462
453
|
}
|
|
463
454
|
`;
|
|
464
455
|
}
|
|
@@ -528,9 +519,7 @@ function generateEndpointFilesNested(analyses, endpointImports) {
|
|
|
528
519
|
case "standard":
|
|
529
520
|
files[fileName] = generateStandardEndpointFile(analysis, endpointImport);
|
|
530
521
|
break;
|
|
531
|
-
case "full":
|
|
532
|
-
files[fileName] = generateFullEndpointFile(analysis, endpointImport);
|
|
533
|
-
break;
|
|
522
|
+
case "full": files[fileName] = generateFullEndpointFile(analysis, endpointImport);
|
|
534
523
|
}
|
|
535
524
|
}
|
|
536
525
|
return files;
|
|
@@ -587,7 +576,142 @@ export async function setupEndpoints(
|
|
|
587
576
|
}
|
|
588
577
|
`;
|
|
589
578
|
}
|
|
579
|
+
//#endregion
|
|
580
|
+
//#region src/generators/telemetry.ts
|
|
581
|
+
/**
|
|
582
|
+
* Every package `@geekmidas/telescope/instrumentation` loads at runtime.
|
|
583
|
+
*
|
|
584
|
+
* All of them, rather than one as a proxy: the production bundle follows each
|
|
585
|
+
* import, and a single missing one fails the build rather than the telemetry.
|
|
586
|
+
*/
|
|
587
|
+
const TELEMETRY_PACKAGES = [
|
|
588
|
+
"@opentelemetry/api",
|
|
589
|
+
"@opentelemetry/auto-instrumentations-node",
|
|
590
|
+
"@opentelemetry/exporter-logs-otlp-http",
|
|
591
|
+
"@opentelemetry/exporter-trace-otlp-http",
|
|
592
|
+
"@opentelemetry/instrumentation-pino",
|
|
593
|
+
"@opentelemetry/resources",
|
|
594
|
+
"@opentelemetry/sdk-logs",
|
|
595
|
+
"@opentelemetry/sdk-node",
|
|
596
|
+
"@opentelemetry/sdk-trace-base",
|
|
597
|
+
"@opentelemetry/sdk-trace-node",
|
|
598
|
+
"@opentelemetry/semantic-conventions"
|
|
599
|
+
];
|
|
600
|
+
/**
|
|
601
|
+
* The directory of `name` as `node_modules` lookup finds it from `fromDir`,
|
|
602
|
+
* symlinks resolved — or undefined.
|
|
603
|
+
*
|
|
604
|
+
* The directory walk alone, not `require.resolve`: that also searches
|
|
605
|
+
* `NODE_PATH`, which a package manager's bin shim sets to its own store, so a
|
|
606
|
+
* `gkm build` run through one would find packages the app never installed —
|
|
607
|
+
* and the bundler, which does not look there, would then fail on them.
|
|
608
|
+
*/
|
|
609
|
+
function packageDir(fromDir, name) {
|
|
610
|
+
for (let dir = (0, node_path.resolve)(fromDir);; dir = (0, node_path.dirname)(dir)) {
|
|
611
|
+
const candidate = (0, node_path.join)(dir, "node_modules", name);
|
|
612
|
+
if ((0, node_fs.existsSync)((0, node_path.join)(candidate, "package.json"))) return (0, node_fs.realpathSync)(candidate);
|
|
613
|
+
if ((0, node_path.dirname)(dir) === dir) return void 0;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Whether the telemetry packages resolve the way the bundler will resolve them:
|
|
618
|
+
* telescope from the app, and the OpenTelemetry packages from telescope —
|
|
619
|
+
* where a peer is linked under pnpm, which need not be where the app sees it.
|
|
620
|
+
*/
|
|
621
|
+
function telemetryResolvesFrom(appRoot) {
|
|
622
|
+
const telescope = packageDir(appRoot, "@geekmidas/telescope");
|
|
623
|
+
if (!telescope) return false;
|
|
624
|
+
return TELEMETRY_PACKAGES.every((pkg) => packageDir(telescope, pkg));
|
|
625
|
+
}
|
|
626
|
+
/** The telemetry half of a build context. */
|
|
627
|
+
function telemetryFor(options) {
|
|
628
|
+
return {
|
|
629
|
+
serviceName: options.surfaceId ?? (0, node_path.basename)(options.appRoot),
|
|
630
|
+
...options.workspaceName && { serviceNamespace: options.workspaceName },
|
|
631
|
+
available: telemetryResolvesFrom(options.appRoot)
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
const HEADER = `/**
|
|
635
|
+
* Generated by 'gkm build --production'.
|
|
636
|
+
*
|
|
637
|
+
* Starts OpenTelemetry when OTEL_EXPORTER_OTLP_ENDPOINT names a collector, and
|
|
638
|
+
* does nothing otherwise: without it, the telemetry packages are not loaded.
|
|
639
|
+
* The standard OTEL_* variables (OTEL_TRACES_SAMPLER, OTEL_TRACES_SAMPLER_ARG,
|
|
640
|
+
* OTEL_EXPORTER_OTLP_HEADERS, OTEL_RESOURCE_ATTRIBUTES, OTEL_SERVICE_NAME)
|
|
641
|
+
* configure the rest.
|
|
642
|
+
*/
|
|
643
|
+
|
|
644
|
+
/** Telemetry was asked for and cannot start. The server runs without it. */
|
|
645
|
+
export class TelemetryUnavailable extends Error {
|
|
646
|
+
constructor(readonly reason: string, options?: { cause?: unknown }) {
|
|
647
|
+
super(
|
|
648
|
+
\`OTEL_EXPORTER_OTLP_ENDPOINT is set, but \${reason} This server exports no traces or logs until that is fixed.\`,
|
|
649
|
+
options,
|
|
650
|
+
);
|
|
651
|
+
this.name = 'TelemetryUnavailable';
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
`;
|
|
655
|
+
/**
|
|
656
|
+
* The entry's `telemetry.ts`: a `startTelemetry()` the server awaits before it
|
|
657
|
+
* imports the app, so the libraries the app loads are instrumented.
|
|
658
|
+
*
|
|
659
|
+
* Failing to start telemetry warns (a named `TelemetryUnavailable`, through
|
|
660
|
+
* `process.emitWarning`) and never stops the server: an outage in observability
|
|
661
|
+
* is not a reason to have an outage in the service.
|
|
662
|
+
*/
|
|
663
|
+
function generateTelemetryModule(telemetry) {
|
|
664
|
+
if (!telemetry?.available) return `${HEADER}
|
|
665
|
+
export async function startTelemetry(): Promise<void> {
|
|
666
|
+
if (!process.env.OTEL_EXPORTER_OTLP_ENDPOINT) return;
|
|
667
|
+
|
|
668
|
+
process.emitWarning(
|
|
669
|
+
new TelemetryUnavailable(
|
|
670
|
+
'this server was built without @geekmidas/telescope and the @opentelemetry packages it needs. Add them to the app and rebuild.',
|
|
671
|
+
),
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
`;
|
|
675
|
+
const options = [
|
|
676
|
+
`serviceName: ${JSON.stringify(telemetry.serviceName)},`,
|
|
677
|
+
...telemetry.serviceNamespace ? [`serviceNamespace: ${JSON.stringify(telemetry.serviceNamespace)},`] : [],
|
|
678
|
+
"deploymentEnvironment: process.env.STAGE,",
|
|
679
|
+
"handleSignals: false,"
|
|
680
|
+
];
|
|
681
|
+
return `${HEADER}
|
|
682
|
+
export async function startTelemetry(): Promise<void> {
|
|
683
|
+
if (!process.env.OTEL_EXPORTER_OTLP_ENDPOINT) return;
|
|
684
|
+
|
|
685
|
+
let instrumentation;
|
|
686
|
+
try {
|
|
687
|
+
instrumentation = await import('@geekmidas/telescope/instrumentation');
|
|
688
|
+
} catch (cause) {
|
|
689
|
+
process.emitWarning(
|
|
690
|
+
new TelemetryUnavailable(
|
|
691
|
+
'@geekmidas/telescope/instrumentation or an @opentelemetry package it needs could not be loaded. Install them in the app and rebuild.',
|
|
692
|
+
{ cause },
|
|
693
|
+
),
|
|
694
|
+
);
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
instrumentation.setupTelemetry({
|
|
699
|
+
${options.join("\n ")}
|
|
700
|
+
});
|
|
590
701
|
|
|
702
|
+
// Flush what is buffered when the process is told to stop. When nothing
|
|
703
|
+
// else handles the signal, re-raise it once flushed, so the process still
|
|
704
|
+
// stops the way it would have without this listener.
|
|
705
|
+
for (const signal of ['SIGTERM', 'SIGINT'] as const) {
|
|
706
|
+
process.once(signal, () => {
|
|
707
|
+
void instrumentation.flushTelemetry().finally(() => {
|
|
708
|
+
if (process.listenerCount(signal) === 0) process.kill(process.pid, signal);
|
|
709
|
+
});
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
`;
|
|
714
|
+
}
|
|
591
715
|
//#endregion
|
|
592
716
|
//#region src/generators/EndpointGenerator.ts
|
|
593
717
|
/**
|
|
@@ -605,11 +729,11 @@ export async function setupEndpoints(
|
|
|
605
729
|
* Falls back to the configured paths for an app that declares no surface.
|
|
606
730
|
*/
|
|
607
731
|
function runtimeFor(context, fromDir, owner) {
|
|
608
|
-
const module
|
|
609
|
-
if (module
|
|
610
|
-
const specifier = importSpecifier(fromDir, module
|
|
732
|
+
const module = owner ? context.owners?.[owner] ?? context.surface?.module : context.surface?.module;
|
|
733
|
+
if (module) {
|
|
734
|
+
const specifier = importSpecifier(fromDir, module.specifier);
|
|
611
735
|
return {
|
|
612
|
-
imports: `import { ${module
|
|
736
|
+
imports: `import { ${module.exportName} as __surface } from '${specifier}';`,
|
|
613
737
|
bindings: [
|
|
614
738
|
"// What this construct was declared with. Objects, not module paths:",
|
|
615
739
|
"// the entry imports the owner, so there is nothing to print.",
|
|
@@ -677,48 +801,35 @@ function corsFor(surface) {
|
|
|
677
801
|
}
|
|
678
802
|
var EndpointGenerator = class extends require_discover.ConstructGenerator {
|
|
679
803
|
isConstruct(value) {
|
|
680
|
-
return
|
|
804
|
+
return _geekmidas_constructs_endpoints.Endpoint.isEndpoint(value);
|
|
681
805
|
}
|
|
682
806
|
async build(context, constructs, outputDir, options) {
|
|
683
|
-
const
|
|
807
|
+
const target = options?.target ?? "aws";
|
|
808
|
+
const root = options?.root ?? process.cwd();
|
|
684
809
|
const enableOpenApi = options?.enableOpenApi || false;
|
|
685
810
|
const logger = console;
|
|
686
811
|
const routes = [];
|
|
687
812
|
if (constructs.length === 0) return routes;
|
|
688
|
-
if (
|
|
813
|
+
if (target === "server") {
|
|
689
814
|
await this.generateEndpointsFile(outputDir, constructs, context);
|
|
690
815
|
const appFile = await this.generateAppFile(outputDir, context);
|
|
691
816
|
routes.push({
|
|
692
817
|
path: "*",
|
|
693
818
|
method: "ALL",
|
|
694
|
-
handler: (0, node_path.relative)(
|
|
819
|
+
handler: (0, node_path.relative)(root, appFile),
|
|
695
820
|
authorizer: "none"
|
|
696
821
|
});
|
|
697
822
|
logger.log(`Generated server with ${constructs.length} endpoints${enableOpenApi ? " (OpenAPI enabled)" : ""}`);
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
path: construct._path,
|
|
705
|
-
method: construct.method,
|
|
706
|
-
handler: (0, node_path.relative)(process.cwd(), handlerFile).replace(/\.ts$/, ".handler"),
|
|
707
|
-
timeout: construct.timeout,
|
|
708
|
-
memorySize: construct.memorySize,
|
|
709
|
-
environment: await construct.getEnvironment({ markOptional: context.markOptional }),
|
|
710
|
-
dependencies: construct.constructs,
|
|
711
|
-
authorizer: construct.authorizer?.name ?? "none"
|
|
712
|
-
};
|
|
713
|
-
routes.push(routeInfo);
|
|
714
|
-
logger.log(`Generated handler for ${routeInfo.method} ${routeInfo.path}`);
|
|
715
|
-
}
|
|
716
|
-
} else for (const { key, construct, path } of constructs) {
|
|
717
|
-
const handlerFile = await this.generateHandlerFile(outputDir, path.relative, key, provider, construct, context);
|
|
823
|
+
return routes;
|
|
824
|
+
}
|
|
825
|
+
const routesDir = (0, node_path.join)(outputDir, "routes");
|
|
826
|
+
await (0, node_fs_promises.mkdir)(routesDir, { recursive: true });
|
|
827
|
+
for (const { key, construct, path } of constructs) {
|
|
828
|
+
const handlerFile = await this.generateHandlerFile(routesDir, path.relative, key, context);
|
|
718
829
|
const routeInfo = {
|
|
719
830
|
path: construct._path,
|
|
720
831
|
method: construct.method,
|
|
721
|
-
handler: (0, node_path.relative)(
|
|
832
|
+
handler: (0, node_path.relative)(root, handlerFile).replace(/\.ts$/, ".handler"),
|
|
722
833
|
timeout: construct.timeout,
|
|
723
834
|
memorySize: construct.memorySize,
|
|
724
835
|
environment: await construct.getEnvironment({ markOptional: context.markOptional }),
|
|
@@ -730,38 +841,21 @@ var EndpointGenerator = class extends require_discover.ConstructGenerator {
|
|
|
730
841
|
}
|
|
731
842
|
return routes;
|
|
732
843
|
}
|
|
733
|
-
async generateHandlerFile(outputDir, sourceFile, exportName,
|
|
734
|
-
const
|
|
735
|
-
const
|
|
736
|
-
|
|
737
|
-
const importPath = relativePath.replace(/\.ts$/, ".js");
|
|
738
|
-
let content;
|
|
739
|
-
switch (provider) {
|
|
740
|
-
case "aws-apigatewayv1":
|
|
741
|
-
content = this.generateAWSApiGatewayV1Handler(importPath, exportName, context.storageDrivers);
|
|
742
|
-
break;
|
|
743
|
-
case "aws-apigatewayv2":
|
|
744
|
-
content = this.generateAWSApiGatewayV2Handler(importPath, exportName, context.storageDrivers);
|
|
745
|
-
break;
|
|
746
|
-
case "server":
|
|
747
|
-
content = this.generateServerHandler(importPath, exportName);
|
|
748
|
-
break;
|
|
749
|
-
default: throw new Error(`Unsupported provider: ${provider}`);
|
|
750
|
-
}
|
|
751
|
-
await (0, node_fs_promises.writeFile)(handlerPath, content);
|
|
844
|
+
async generateHandlerFile(outputDir, sourceFile, exportName, context) {
|
|
845
|
+
const handlerPath = (0, node_path.join)(outputDir, `${exportName}.ts`);
|
|
846
|
+
const importPath = (0, node_path.relative)((0, node_path.dirname)(handlerPath), sourceFile).replace(/\.ts$/, ".js");
|
|
847
|
+
await (0, node_fs_promises.writeFile)(handlerPath, this.generateAWSApiGatewayV2Handler(importPath, exportName, context.storageDrivers));
|
|
752
848
|
return handlerPath;
|
|
753
849
|
}
|
|
754
850
|
async generateEndpointsFile(outputDir, endpoints, context) {
|
|
755
|
-
const
|
|
756
|
-
const endpointsPath = (0, node_path.join)(outputDir, endpointsFileName);
|
|
851
|
+
const endpointsPath = (0, node_path.join)(outputDir, "endpoints.ts");
|
|
757
852
|
const importsByFile = /* @__PURE__ */ new Map();
|
|
758
853
|
for (const { path, key } of endpoints) {
|
|
759
|
-
const
|
|
760
|
-
const importPath = relativePath.replace(/\.ts$/, ".js");
|
|
854
|
+
const importPath = (0, node_path.relative)((0, node_path.dirname)(endpointsPath), path.relative).replace(/\.ts$/, ".js");
|
|
761
855
|
if (!importsByFile.has(importPath)) importsByFile.set(importPath, []);
|
|
762
856
|
importsByFile.get(importPath)?.push(key);
|
|
763
857
|
}
|
|
764
|
-
const endpointImports = Array.from(importsByFile.entries()).map(([importPath, exports
|
|
858
|
+
const endpointImports = Array.from(importsByFile.entries()).map(([importPath, exports]) => `import { ${exports.join(", ")} } from '${importPath}';`).join("\n");
|
|
765
859
|
const allExportNames = endpoints.map(({ key }) => key);
|
|
766
860
|
if (context.production?.enabled && context.production.optimizedHandlers) return this.generateOptimizedEndpointsFile(endpointsPath, endpoints, endpointImports, allExportNames);
|
|
767
861
|
const content = `import type { EnvironmentParser } from '@geekmidas/envkit';
|
|
@@ -772,7 +866,7 @@ import { ServiceDiscovery } from '@geekmidas/services';
|
|
|
772
866
|
import type { Hono } from 'hono';
|
|
773
867
|
${endpointImports}
|
|
774
868
|
|
|
775
|
-
export const endpoints: Endpoint<any, any, any, any, any, any, any, any, any, any, any, any
|
|
869
|
+
export const endpoints: Endpoint<any, any, any, any, any, any, any, any, any, any, any, any>[] = [
|
|
776
870
|
${allExportNames.join(",\n ")}
|
|
777
871
|
];
|
|
778
872
|
|
|
@@ -823,11 +917,9 @@ export async function setupEndpoints(
|
|
|
823
917
|
const analyses = endpoints.map(({ key, construct }) => analyzeEndpoint(construct, key));
|
|
824
918
|
const endpointImports = endpoints.map(({ key, path }) => {
|
|
825
919
|
const tierDir = (0, node_path.join)(endpointsDir, "standard");
|
|
826
|
-
const relativePath = (0, node_path.relative)(tierDir, path.relative);
|
|
827
|
-
const importPath = relativePath.replace(/\.ts$/, ".js");
|
|
828
920
|
return {
|
|
829
921
|
exportName: key,
|
|
830
|
-
importPath
|
|
922
|
+
importPath: (0, node_path.relative)(tierDir, path.relative).replace(/\.ts$/, ".js")
|
|
831
923
|
};
|
|
832
924
|
});
|
|
833
925
|
const summary = summarizeAnalysis(analyses);
|
|
@@ -849,43 +941,33 @@ export async function setupEndpoints(
|
|
|
849
941
|
}
|
|
850
942
|
async generateAppFile(outputDir, context) {
|
|
851
943
|
if (context.production?.enabled) return this.generateProductionAppFile(outputDir, context);
|
|
852
|
-
const
|
|
853
|
-
const appPath = (0, node_path.join)(outputDir, appFileName);
|
|
944
|
+
const appPath = (0, node_path.join)(outputDir, "app.ts");
|
|
854
945
|
const runtime = runtimeFor(context, (0, node_path.dirname)(appPath));
|
|
855
946
|
const telescopeEnabled = context.telescope?.enabled;
|
|
856
947
|
const telescopeWebSocketEnabled = context.telescope?.websocket;
|
|
857
948
|
const usesExternalTelescope = !!context.telescope?.telescopePath;
|
|
858
|
-
const studioEnabled = context.studio?.enabled;
|
|
859
|
-
const usesExternalStudio = !!context.studio?.studioPath;
|
|
860
|
-
const studioFromDatabase = !usesExternalStudio && !!context.studio?.database;
|
|
861
949
|
const telescopeFromSurface = !!context.surface?.module && !usesExternalTelescope;
|
|
862
950
|
let telescopeImports = "";
|
|
863
|
-
if (telescopeEnabled)
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
import {
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
import {
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
studioImports = `import { snifferContext } from '@geekmidas/constructs';
|
|
878
|
-
import { Direction, InMemoryMonitoringStorage, Studio } from '@geekmidas/studio';
|
|
879
|
-
import { ${context.studio.database.exportName} as __studioDb } from '${dbSpecifier}';
|
|
880
|
-
import { createStudioApp } from '@geekmidas/studio/server/hono';`;
|
|
881
|
-
} else studioImports = "";
|
|
951
|
+
if (telescopeEnabled) {
|
|
952
|
+
if (telescopeFromSurface) telescopeImports = `import { Telescope, InMemoryStorage } from '@geekmidas/telescope';
|
|
953
|
+
import { createApi, createMiddleware } from '@geekmidas/telescope/hono';`;
|
|
954
|
+
else if (usesExternalTelescope) {
|
|
955
|
+
const relativeTelescopePath = (0, node_path.relative)((0, node_path.dirname)(appPath), context.telescope?.telescopePath);
|
|
956
|
+
telescopeImports = `import ${context.telescope?.telescopeImportPattern} from '${relativeTelescopePath}';
|
|
957
|
+
import { createApi, createMiddleware } from '@geekmidas/telescope/hono';`;
|
|
958
|
+
} else telescopeImports = `import { Telescope, InMemoryStorage } from '@geekmidas/telescope';
|
|
959
|
+
import { createApi, createMiddleware } from '@geekmidas/telescope/hono';`;
|
|
960
|
+
}
|
|
961
|
+
const databaseApi = context.databaseApi;
|
|
962
|
+
const databaseApiImports = databaseApi ? `import { snifferContext } from '@geekmidas/constructs';
|
|
963
|
+
import { createIntrospectionHandler } from '@geekmidas/db/introspect';
|
|
964
|
+
import { ${databaseApi.database.exportName} as __introspectedDb } from '${importSpecifier((0, node_path.dirname)(appPath), databaseApi.database.specifier)}';` : "";
|
|
882
965
|
const cors = corsFor(context.surface);
|
|
883
966
|
let hooksImports = "";
|
|
884
967
|
let beforeSetupCall = "";
|
|
885
968
|
let afterSetupCall = "";
|
|
886
969
|
if (context.hooks?.serverHooksPath) {
|
|
887
|
-
|
|
888
|
-
hooksImports = `import * as serverHooks from '${relativeHooksPath}';`;
|
|
970
|
+
hooksImports = `import * as serverHooks from '${(0, node_path.relative)((0, node_path.dirname)(appPath), context.hooks.serverHooksPath)}';`;
|
|
889
971
|
beforeSetupCall = `
|
|
890
972
|
// Call beforeSetup hook if defined
|
|
891
973
|
if (typeof serverHooks.beforeSetup === 'function') {
|
|
@@ -931,16 +1013,17 @@ import { createStudioApp } from '@geekmidas/studio/server/hono';`;
|
|
|
931
1013
|
}
|
|
932
1014
|
` : "";
|
|
933
1015
|
let telescopeSetup = "";
|
|
934
|
-
if (telescopeEnabled)
|
|
1016
|
+
if (telescopeEnabled) {
|
|
1017
|
+
if (telescopeFromSurface || usesExternalTelescope) telescopeSetup = `
|
|
935
1018
|
${telescopeWebSocketSetupCode}
|
|
936
1019
|
// Add telescope middleware (before endpoints to capture all requests)
|
|
937
1020
|
honoApp.use('*', createMiddleware(telescope));
|
|
938
1021
|
|
|
939
|
-
// Mount
|
|
940
|
-
const
|
|
941
|
-
honoApp.route('${context.telescope?.path}',
|
|
1022
|
+
// Mount Telescope's JSON API
|
|
1023
|
+
const telescopeApi = createApi(telescope);
|
|
1024
|
+
honoApp.route('${context.telescope?.path}', telescopeApi);
|
|
942
1025
|
`;
|
|
943
|
-
|
|
1026
|
+
else telescopeSetup = `
|
|
944
1027
|
// Setup Telescope for debugging/monitoring
|
|
945
1028
|
const telescopeStorage = new InMemoryStorage({ maxEntries: ${context.telescope?.maxEntries} });
|
|
946
1029
|
const telescope = new Telescope({
|
|
@@ -954,31 +1037,21 @@ ${telescopeWebSocketSetupCode}
|
|
|
954
1037
|
// Add telescope middleware (before endpoints to capture all requests)
|
|
955
1038
|
honoApp.use('*', createMiddleware(telescope));
|
|
956
1039
|
|
|
957
|
-
// Mount
|
|
958
|
-
const
|
|
959
|
-
honoApp.route('${context.telescope?.path}',
|
|
1040
|
+
// Mount Telescope's JSON API
|
|
1041
|
+
const telescopeApi = createApi(telescope);
|
|
1042
|
+
honoApp.route('${context.telescope?.path}', telescopeApi);
|
|
960
1043
|
`;
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
//
|
|
964
|
-
//
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
cursor: { field: 'id', direction: Direction.Desc },
|
|
970
|
-
},
|
|
971
|
-
enabled: true,
|
|
1044
|
+
}
|
|
1045
|
+
const databaseApiSetup = databaseApi ? `
|
|
1046
|
+
// The database's structure and rows as JSON, read-only, for whatever tool
|
|
1047
|
+
// the developer points at it. Dev only: it answers anyone who can reach the
|
|
1048
|
+
// port.
|
|
1049
|
+
const databaseApi = createIntrospectionHandler({
|
|
1050
|
+
db: await __introspectedDb.service.register({ envParser, context: snifferContext }),
|
|
1051
|
+
basePath: '${databaseApi.path}',
|
|
972
1052
|
});
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
honoApp.route('${context.studio?.path}', studioApp);
|
|
976
|
-
`;
|
|
977
|
-
else if (studioEnabled && usesExternalStudio) studioSetup = `
|
|
978
|
-
// Mount Studio data browser UI
|
|
979
|
-
const studioApp = createStudioApp(studio);
|
|
980
|
-
honoApp.route('${context.studio?.path}', studioApp);
|
|
981
|
-
`;
|
|
1053
|
+
honoApp.all('${databaseApi.path}/*', (c) => databaseApi(c.req.raw));
|
|
1054
|
+
` : "";
|
|
982
1055
|
const content = `/**
|
|
983
1056
|
* Generated server application
|
|
984
1057
|
*
|
|
@@ -994,24 +1067,37 @@ import { setupQueues } from './queues.js';
|
|
|
994
1067
|
import { setupCrons } from './crons.js';
|
|
995
1068
|
${runtime.imports}
|
|
996
1069
|
${telescopeImports}
|
|
997
|
-
${
|
|
1070
|
+
${databaseApiImports}
|
|
998
1071
|
${hooksImports}
|
|
999
1072
|
${cors.imports}
|
|
1000
1073
|
${context.storageDrivers?.imports ?? ""}
|
|
1001
1074
|
|
|
1002
1075
|
${runtime.bindings}
|
|
1003
|
-
${telescopeFromSurface ?
|
|
1076
|
+
${telescopeEnabled && telescopeFromSurface ? `// The surface's own Telescope, or the one \`telescope\` config describes.
|
|
1077
|
+
const telescope =
|
|
1078
|
+
__surface.telescope ??
|
|
1079
|
+
new Telescope({
|
|
1080
|
+
enabled: true,
|
|
1081
|
+
path: '${context.telescope?.path}',
|
|
1082
|
+
ignorePatterns: ${JSON.stringify(context.telescope?.ignore)},
|
|
1083
|
+
recordBody: ${context.telescope?.recordBody},
|
|
1084
|
+
storage: new InMemoryStorage({ maxEntries: ${context.telescope?.maxEntries} }),
|
|
1085
|
+
});` : ""}
|
|
1004
1086
|
|
|
1005
1087
|
${context.storageDrivers?.setup ? `// Which storage drivers exist is the entry point's decision: the scheme in
|
|
1006
1088
|
// each injected URL picks one, so no construct and no application module names
|
|
1007
1089
|
// a provider.
|
|
1008
1090
|
${context.storageDrivers.setup}
|
|
1009
1091
|
` : ""}
|
|
1010
|
-
|
|
1092
|
+
${context.surface ? `// Who this server is to Postgres: application_name on every connection.
|
|
1093
|
+
process.env.GKM_APP_NAME ??= ${JSON.stringify(context.surface.id)};
|
|
1094
|
+
|
|
1095
|
+
` : ""}export interface ServerApp {
|
|
1011
1096
|
app: HonoType;
|
|
1012
1097
|
start: (options?: {
|
|
1013
1098
|
port?: number;
|
|
1014
|
-
|
|
1099
|
+
/** Returns the server, so a shutdown can stop it taking requests. */
|
|
1100
|
+
serve: (app: HonoType, port: number) => unknown;
|
|
1015
1101
|
}) => Promise<void>;
|
|
1016
1102
|
}
|
|
1017
1103
|
|
|
@@ -1051,7 +1137,7 @@ export interface ServerApp {
|
|
|
1051
1137
|
*/
|
|
1052
1138
|
export async function createApp(app?: HonoType, enableOpenApi: boolean = true): Promise<ServerApp> {
|
|
1053
1139
|
const honoApp = app || new Hono();
|
|
1054
|
-
${telescopeSetup}${cors.setup}${beforeSetupCall}${
|
|
1140
|
+
${telescopeSetup}${cors.setup}${beforeSetupCall}${databaseApiSetup}
|
|
1055
1141
|
// Setup HTTP endpoints
|
|
1056
1142
|
await setupEndpoints(honoApp, envParser, logger, enableOpenApi);
|
|
1057
1143
|
${afterSetupCall}
|
|
@@ -1069,9 +1155,11 @@ ${afterSetupCall}
|
|
|
1069
1155
|
|
|
1070
1156
|
const port = options.port ?? 3000;
|
|
1071
1157
|
|
|
1072
|
-
//
|
|
1073
|
-
|
|
1158
|
+
// Mount pushed subscribers' routes and start polled ones. What comes
|
|
1159
|
+
// back subscribes the routes, once the server can answer them.
|
|
1160
|
+
const subscribeForPush = await setupSubscribers(honoApp, envParser, logger).catch((error) => {
|
|
1074
1161
|
logger.error({ error }, 'Failed to start subscribers');
|
|
1162
|
+
return async (_port: number) => {};
|
|
1075
1163
|
});
|
|
1076
1164
|
|
|
1077
1165
|
// Start queue workers in background (non-blocking, local development only)
|
|
@@ -1091,6 +1179,8 @@ ${afterSetupCall}
|
|
|
1091
1179
|
await options.serve(honoApp, port);
|
|
1092
1180
|
|
|
1093
1181
|
logger.info({ port }, 'Server started');
|
|
1182
|
+
|
|
1183
|
+
await subscribeForPush(port);
|
|
1094
1184
|
}
|
|
1095
1185
|
};
|
|
1096
1186
|
}
|
|
@@ -1111,26 +1201,6 @@ export default createApp;
|
|
|
1111
1201
|
* object. Nothing has to be printed now, which is also why nothing has to be
|
|
1112
1202
|
* named in config.
|
|
1113
1203
|
*/
|
|
1114
|
-
generateAWSApiGatewayV1Handler(importPath, exportName, drivers) {
|
|
1115
|
-
return `import { AmazonApiGatewayV1Endpoint } from '@geekmidas/constructs/aws';
|
|
1116
|
-
import { ${exportName} } from '${importPath}';
|
|
1117
|
-
${drivers?.imports ?? ""}
|
|
1118
|
-
${drivers?.setup ? `\n// The handler registers the drivers its target needs.\n${drivers.setup}\n` : ""}
|
|
1119
|
-
const adapter = new AmazonApiGatewayV1Endpoint(${exportName});
|
|
1120
|
-
|
|
1121
|
-
export const handler = adapter.handler;
|
|
1122
|
-
`;
|
|
1123
|
-
}
|
|
1124
|
-
/**
|
|
1125
|
-
* One Lambda, one endpoint — and no environment import.
|
|
1126
|
-
*
|
|
1127
|
-
* The endpoint was built from its surface, so it carries the parser the
|
|
1128
|
-
* adaptor needs. This used to read
|
|
1129
|
-
* `import { envParser } from '../../config/env'`, a line the build wrote
|
|
1130
|
-
* because a generator can print a module specifier and cannot print an
|
|
1131
|
-
* object. Nothing has to be printed now, which is also why nothing has to be
|
|
1132
|
-
* named in config.
|
|
1133
|
-
*/
|
|
1134
1204
|
generateAWSApiGatewayV2Handler(importPath, exportName, drivers) {
|
|
1135
1205
|
return `import { AmazonApiGatewayV2Endpoint } from '@geekmidas/constructs/aws';
|
|
1136
1206
|
import { ${exportName} } from '${importPath}';
|
|
@@ -1139,13 +1209,6 @@ ${drivers?.setup ? `\n// The handler registers the drivers its target needs.\n${
|
|
|
1139
1209
|
const adapter = new AmazonApiGatewayV2Endpoint(${exportName});
|
|
1140
1210
|
|
|
1141
1211
|
export const handler = adapter.handler;
|
|
1142
|
-
`;
|
|
1143
|
-
}
|
|
1144
|
-
generateServerHandler(importPath, exportName) {
|
|
1145
|
-
return `import { ${exportName} } from '${importPath}';
|
|
1146
|
-
|
|
1147
|
-
// Server handler - implement based on your server framework
|
|
1148
|
-
export const handler = ${exportName};
|
|
1149
1212
|
`;
|
|
1150
1213
|
}
|
|
1151
1214
|
/**
|
|
@@ -1153,8 +1216,7 @@ export const handler = ${exportName};
|
|
|
1153
1216
|
* No dev tools (Telescope, Studio, WebSocket), includes health checks and graceful shutdown
|
|
1154
1217
|
*/
|
|
1155
1218
|
async generateProductionAppFile(outputDir, context) {
|
|
1156
|
-
const
|
|
1157
|
-
const appPath = (0, node_path.join)(outputDir, appFileName);
|
|
1219
|
+
const appPath = (0, node_path.join)(outputDir, "app.ts");
|
|
1158
1220
|
const runtime = runtimeFor(context, (0, node_path.dirname)(appPath));
|
|
1159
1221
|
const production = context.production;
|
|
1160
1222
|
const healthCheckPath = production.healthCheck;
|
|
@@ -1166,8 +1228,7 @@ export const handler = ${exportName};
|
|
|
1166
1228
|
let beforeSetupCall = "";
|
|
1167
1229
|
let afterSetupCall = "";
|
|
1168
1230
|
if (context.hooks?.serverHooksPath) {
|
|
1169
|
-
|
|
1170
|
-
hooksImports = `import * as serverHooks from '${relativeHooksPath}';`;
|
|
1231
|
+
hooksImports = `import * as serverHooks from '${(0, node_path.relative)((0, node_path.dirname)(appPath), context.hooks.serverHooksPath)}';`;
|
|
1171
1232
|
beforeSetupCall = `
|
|
1172
1233
|
// Call beforeSetup hook if defined
|
|
1173
1234
|
if (typeof serverHooks.beforeSetup === 'function') {
|
|
@@ -1182,9 +1243,11 @@ export const handler = ${exportName};
|
|
|
1182
1243
|
`;
|
|
1183
1244
|
}
|
|
1184
1245
|
const subscriberSetup = includeSubscribers ? `
|
|
1185
|
-
//
|
|
1186
|
-
|
|
1246
|
+
// Mount pushed subscribers' routes and start polled ones. What comes
|
|
1247
|
+
// back subscribes the routes, once the server can answer them.
|
|
1248
|
+
const subscribeForPush = await setupSubscribers(honoApp, envParser, logger).catch((error) => {
|
|
1187
1249
|
logger.error({ error }, 'Failed to start subscribers');
|
|
1250
|
+
return async (_port: number) => {};
|
|
1188
1251
|
});
|
|
1189
1252
|
|
|
1190
1253
|
// Start queue workers in background
|
|
@@ -1202,15 +1265,29 @@ export const handler = ${exportName};
|
|
|
1202
1265
|
import { setupQueues } from './queues.js';
|
|
1203
1266
|
import { setupCrons } from './crons.js';` : "";
|
|
1204
1267
|
const gracefulShutdownCode = enableGracefulShutdown ? `
|
|
1205
|
-
// Graceful shutdown
|
|
1268
|
+
// Graceful shutdown: stop taking requests, let in-flight ones finish, then
|
|
1269
|
+
// close what constructs opened (database pools) — so a rolling deploy does
|
|
1270
|
+
// not leave the old task holding connections. Bounded by
|
|
1271
|
+
// GKM_SHUTDOWN_TIMEOUT_MS, 8s by default: under Docker's 10s stop timeout,
|
|
1272
|
+
// so the process exits on its own terms rather than being killed mid-drain.
|
|
1206
1273
|
let isShuttingDown = false;
|
|
1207
1274
|
|
|
1208
1275
|
const shutdown = async () => {
|
|
1209
1276
|
if (isShuttingDown) return;
|
|
1210
1277
|
isShuttingDown = true;
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
setTimeout(() =>
|
|
1278
|
+
const deadline = Number(process.env.GKM_SHUTDOWN_TIMEOUT_MS) || 8000;
|
|
1279
|
+
logger.info({ deadline }, 'Graceful shutdown initiated');
|
|
1280
|
+
setTimeout(() => {
|
|
1281
|
+
logger.warn({ deadline }, 'Shutdown deadline reached, exiting');
|
|
1282
|
+
process.exit(1);
|
|
1283
|
+
}, deadline).unref();
|
|
1284
|
+
await new Promise<void>((resolve) => {
|
|
1285
|
+
const close = (server as { close?: (done: () => void) => void } | undefined)?.close;
|
|
1286
|
+
if (typeof close === 'function') close.call(server, () => resolve());
|
|
1287
|
+
else resolve();
|
|
1288
|
+
});
|
|
1289
|
+
await runShutdownHooks((error) => logger.error({ error }, 'Shutdown hook failed'));
|
|
1290
|
+
process.exit(0);
|
|
1214
1291
|
};
|
|
1215
1292
|
|
|
1216
1293
|
process.on('SIGTERM', shutdown);
|
|
@@ -1228,7 +1305,7 @@ import { setupCrons } from './crons.js';` : "";
|
|
|
1228
1305
|
*/
|
|
1229
1306
|
import { Hono } from 'hono';
|
|
1230
1307
|
import type { Hono as HonoType } from 'hono';
|
|
1231
|
-
import { setupEndpoints } from '${endpointsImportPath}';
|
|
1308
|
+
${enableGracefulShutdown ? "import { runShutdownHooks } from '@geekmidas/constructs';\n" : ""}import { setupEndpoints } from '${endpointsImportPath}';
|
|
1232
1309
|
${subscriberImport}
|
|
1233
1310
|
${runtime.imports}
|
|
1234
1311
|
${runtime.bindings}
|
|
@@ -1239,7 +1316,10 @@ ${context.storageDrivers?.imports ?? ""}
|
|
|
1239
1316
|
${context.storageDrivers?.setup ? `// The entry point registers the drivers its target needs.
|
|
1240
1317
|
${context.storageDrivers.setup}
|
|
1241
1318
|
` : ""}
|
|
1242
|
-
|
|
1319
|
+
${context.surface ? `// Who this server is to Postgres: application_name on every connection.
|
|
1320
|
+
process.env.GKM_APP_NAME ??= ${JSON.stringify(context.surface.id)};
|
|
1321
|
+
|
|
1322
|
+
` : ""}export interface ServerApp {
|
|
1243
1323
|
app: HonoType;
|
|
1244
1324
|
start: (options?: {
|
|
1245
1325
|
port?: number;
|
|
@@ -1256,6 +1336,35 @@ export async function createApp(app?: HonoType): Promise<ServerApp> {
|
|
|
1256
1336
|
// Health check endpoint (always first)
|
|
1257
1337
|
honoApp.get('${healthCheckPath}', (c) => c.json({ status: 'ok', timestamp: Date.now() }));
|
|
1258
1338
|
honoApp.get('/ready', (c) => c.json({ ready: true }));
|
|
1339
|
+
|
|
1340
|
+
// An HttpError a handler or a session callback throws — a 401, a 404 —
|
|
1341
|
+
// answers with its own status, as it does under gkm dev. The optimized
|
|
1342
|
+
// handlers do not catch, so without this every one of them was a 500.
|
|
1343
|
+
// Anything else is a 500 that says nothing about why, and is logged.
|
|
1344
|
+
honoApp.onError((error, c) => {
|
|
1345
|
+
const http = error as {
|
|
1346
|
+
isHttpError?: boolean;
|
|
1347
|
+
statusCode?: number;
|
|
1348
|
+
statusMessage?: string;
|
|
1349
|
+
code?: string;
|
|
1350
|
+
details?: unknown;
|
|
1351
|
+
};
|
|
1352
|
+
if (http.isHttpError === true && typeof http.statusCode === 'number') {
|
|
1353
|
+
return c.json(
|
|
1354
|
+
{
|
|
1355
|
+
name: error.name,
|
|
1356
|
+
message: error.message,
|
|
1357
|
+
statusCode: http.statusCode,
|
|
1358
|
+
statusMessage: http.statusMessage,
|
|
1359
|
+
code: http.code,
|
|
1360
|
+
details: http.details,
|
|
1361
|
+
},
|
|
1362
|
+
http.statusCode as 500,
|
|
1363
|
+
);
|
|
1364
|
+
}
|
|
1365
|
+
logger.error({ error }, 'Unhandled error');
|
|
1366
|
+
return c.json({ message: 'Internal Server Error' }, 500);
|
|
1367
|
+
});
|
|
1259
1368
|
${cors.setup}${beforeSetupCall}
|
|
1260
1369
|
// Setup HTTP endpoints (OpenAPI: ${enableOpenApi})
|
|
1261
1370
|
await setupEndpoints(honoApp, envParser, logger, ${enableOpenApi});
|
|
@@ -1272,13 +1381,15 @@ ${afterSetupCall}
|
|
|
1272
1381
|
}
|
|
1273
1382
|
|
|
1274
1383
|
const port = options.port ?? Number(process.env.PORT) ?? 3000;
|
|
1384
|
+
let server: unknown;
|
|
1275
1385
|
${gracefulShutdownCode}${subscriberSetup}
|
|
1276
1386
|
logger.info({ port }, 'Starting production server');
|
|
1277
1387
|
|
|
1278
1388
|
// Start HTTP server using provided serve function
|
|
1279
|
-
await options.serve(honoApp, port);
|
|
1389
|
+
server = await options.serve(honoApp, port);
|
|
1280
1390
|
|
|
1281
1391
|
logger.info({ port }, 'Production server started');
|
|
1392
|
+
${includeSubscribers ? "\n await subscribeForPush(port);" : ""}
|
|
1282
1393
|
}
|
|
1283
1394
|
};
|
|
1284
1395
|
}
|
|
@@ -1287,21 +1398,27 @@ ${gracefulShutdownCode}${subscriberSetup}
|
|
|
1287
1398
|
export default createApp;
|
|
1288
1399
|
`;
|
|
1289
1400
|
await (0, node_fs_promises.writeFile)(appPath, content);
|
|
1290
|
-
await this.generateProductionServerEntry(outputDir);
|
|
1401
|
+
await this.generateProductionServerEntry(outputDir, context);
|
|
1291
1402
|
return appPath;
|
|
1292
1403
|
}
|
|
1293
1404
|
/**
|
|
1294
1405
|
* Generate production server.ts entry point
|
|
1295
1406
|
*/
|
|
1296
|
-
async generateProductionServerEntry(outputDir) {
|
|
1407
|
+
async generateProductionServerEntry(outputDir, context) {
|
|
1297
1408
|
const serverPath = (0, node_path.join)(outputDir, "server.ts");
|
|
1298
|
-
|
|
1409
|
+
await (0, node_fs_promises.writeFile)((0, node_path.join)(outputDir, "telemetry.ts"), generateTelemetryModule(context.telemetry));
|
|
1410
|
+
await (0, node_fs_promises.writeFile)(serverPath, `#!/usr/bin/env node
|
|
1299
1411
|
/**
|
|
1300
1412
|
* Production server entry point
|
|
1301
|
-
* Generated by 'gkm build --
|
|
1413
|
+
* Generated by 'gkm build --production'
|
|
1302
1414
|
*/
|
|
1303
1415
|
import { serve } from '@hono/node-server';
|
|
1304
|
-
import {
|
|
1416
|
+
import { startTelemetry } from './telemetry.js';
|
|
1417
|
+
|
|
1418
|
+
// Before the app is imported, so the libraries it loads are instrumented.
|
|
1419
|
+
await startTelemetry();
|
|
1420
|
+
|
|
1421
|
+
const { createApp } = await import('./app.js');
|
|
1305
1422
|
|
|
1306
1423
|
const port = Number(process.env.PORT) || 3000;
|
|
1307
1424
|
|
|
@@ -1309,13 +1426,11 @@ const { start } = await createApp();
|
|
|
1309
1426
|
|
|
1310
1427
|
await start({
|
|
1311
1428
|
port,
|
|
1312
|
-
serve: (app, port) =>
|
|
1429
|
+
serve: (app, port) => serve({ fetch: app.fetch, port }),
|
|
1313
1430
|
});
|
|
1314
|
-
|
|
1315
|
-
await (0, node_fs_promises.writeFile)(serverPath, content);
|
|
1431
|
+
`);
|
|
1316
1432
|
}
|
|
1317
1433
|
};
|
|
1318
|
-
|
|
1319
1434
|
//#endregion
|
|
1320
1435
|
//#region src/generators/OpenApiTsGenerator.ts
|
|
1321
1436
|
/**
|
|
@@ -1466,11 +1581,11 @@ var OpenApiTsGenerator = class {
|
|
|
1466
1581
|
}
|
|
1467
1582
|
}
|
|
1468
1583
|
}
|
|
1469
|
-
const registrySchemas = await (0,
|
|
1584
|
+
const registrySchemas = await (0, _geekmidas_schema_conversion.getRegisteredZodJsonSchemas)();
|
|
1470
1585
|
for (const [rawName, rawSchema] of Object.entries(registrySchemas)) {
|
|
1471
1586
|
const defName = this.pascalCase(rawName);
|
|
1472
1587
|
if (collectedDefs.has(defName) || generatedNames.has(defName)) continue;
|
|
1473
|
-
const { id: _id, $defs: _defs
|
|
1588
|
+
const { id: _id, $defs: _defs, ...rest } = rawSchema;
|
|
1474
1589
|
collectedDefs.set(defName, rest);
|
|
1475
1590
|
}
|
|
1476
1591
|
for (const [defName, defSchema] of collectedDefs) if (!generatedNames.has(defName)) {
|
|
@@ -1486,7 +1601,7 @@ var OpenApiTsGenerator = class {
|
|
|
1486
1601
|
*/
|
|
1487
1602
|
async getSchemaName(schema, defaultName) {
|
|
1488
1603
|
try {
|
|
1489
|
-
const metadata = await (0,
|
|
1604
|
+
const metadata = await (0, _geekmidas_schema_conversion.getSchemaMetadata)(schema);
|
|
1490
1605
|
if (metadata?.id) return this.pascalCase(metadata.id);
|
|
1491
1606
|
} catch {}
|
|
1492
1607
|
return defaultName;
|
|
@@ -1506,17 +1621,17 @@ var OpenApiTsGenerator = class {
|
|
|
1506
1621
|
async schemaToInterfaceWithDefs(schema, name, collectedDefs) {
|
|
1507
1622
|
try {
|
|
1508
1623
|
const vendor = schema["~standard"]?.vendor;
|
|
1509
|
-
if (!vendor || !(vendor in
|
|
1510
|
-
const toJsonSchema =
|
|
1624
|
+
if (!vendor || !(vendor in _geekmidas_schema_conversion.StandardSchemaJsonSchema)) return unknownType(name);
|
|
1625
|
+
const toJsonSchema = _geekmidas_schema_conversion.StandardSchemaJsonSchema[vendor];
|
|
1511
1626
|
const jsonSchema = await toJsonSchema(schema);
|
|
1512
|
-
if (!jsonSchema) return
|
|
1627
|
+
if (!jsonSchema) return unknownType(name);
|
|
1513
1628
|
if (jsonSchema.$defs && typeof jsonSchema.$defs === "object") {
|
|
1514
1629
|
for (const [defName, defSchema] of Object.entries(jsonSchema.$defs)) if (!collectedDefs.has(defName)) {
|
|
1515
|
-
const { id
|
|
1630
|
+
const { id, ...schemaWithoutId } = defSchema;
|
|
1516
1631
|
collectedDefs.set(defName, schemaWithoutId);
|
|
1517
1632
|
}
|
|
1518
1633
|
}
|
|
1519
|
-
const { $defs
|
|
1634
|
+
const { $defs, ...schemaWithoutDefs } = jsonSchema;
|
|
1520
1635
|
const ref = schemaWithoutDefs.$ref;
|
|
1521
1636
|
if (ref && Object.keys(schemaWithoutDefs).every((k) => k === "$ref" || k === "$schema")) {
|
|
1522
1637
|
const target = ref.split("/").pop();
|
|
@@ -1524,14 +1639,11 @@ var OpenApiTsGenerator = class {
|
|
|
1524
1639
|
}
|
|
1525
1640
|
return this.jsonSchemaToInterface(schemaWithoutDefs, name);
|
|
1526
1641
|
} catch {
|
|
1527
|
-
return
|
|
1642
|
+
return unknownType(name);
|
|
1528
1643
|
}
|
|
1529
1644
|
}
|
|
1530
1645
|
jsonSchemaToInterface(schema, name) {
|
|
1531
|
-
if (schema.type !== "object" || !schema.properties) {
|
|
1532
|
-
const typeStr = this.jsonSchemaTypeToTs(schema);
|
|
1533
|
-
return `export type ${name} = ${typeStr};`;
|
|
1534
|
-
}
|
|
1646
|
+
if (schema.type !== "object" || !schema.properties) return `export type ${name} = ${this.jsonSchemaTypeToTs(schema)};`;
|
|
1535
1647
|
const props = [];
|
|
1536
1648
|
const required = new Set(schema.required || []);
|
|
1537
1649
|
for (const [propName, propSchema] of Object.entries(schema.properties)) {
|
|
@@ -1544,13 +1656,15 @@ var OpenApiTsGenerator = class {
|
|
|
1544
1656
|
}
|
|
1545
1657
|
jsonSchemaTypeToTs(schema) {
|
|
1546
1658
|
if (!schema) return "unknown";
|
|
1547
|
-
if (schema.$ref)
|
|
1548
|
-
|
|
1549
|
-
return refName;
|
|
1550
|
-
}
|
|
1659
|
+
if (schema.$ref) return schema.$ref.split("/").pop() || "unknown";
|
|
1660
|
+
if (schema.const !== void 0) return typeof schema.const === "string" ? `'${schema.const}'` : String(schema.const);
|
|
1551
1661
|
if (schema.anyOf) return schema.anyOf.map((s) => this.jsonSchemaTypeToTs(s)).join(" | ");
|
|
1552
1662
|
if (schema.oneOf) return schema.oneOf.map((s) => this.jsonSchemaTypeToTs(s)).join(" | ");
|
|
1553
1663
|
if (schema.allOf) return schema.allOf.map((s) => this.jsonSchemaTypeToTs(s)).join(" & ");
|
|
1664
|
+
if (Array.isArray(schema.type)) return schema.type.map((type) => this.jsonSchemaTypeToTs({
|
|
1665
|
+
...schema,
|
|
1666
|
+
type
|
|
1667
|
+
})).join(" | ");
|
|
1554
1668
|
switch (schema.type) {
|
|
1555
1669
|
case "string":
|
|
1556
1670
|
if (schema.enum) return schema.enum.map((e) => `'${e}'`).join(" | ");
|
|
@@ -1574,10 +1688,7 @@ var OpenApiTsGenerator = class {
|
|
|
1574
1688
|
}
|
|
1575
1689
|
return `{ ${props.join("; ")} }`;
|
|
1576
1690
|
}
|
|
1577
|
-
if (schema.additionalProperties) {
|
|
1578
|
-
const valueType = this.jsonSchemaTypeToTs(schema.additionalProperties);
|
|
1579
|
-
return `Record<string, ${valueType}>`;
|
|
1580
|
-
}
|
|
1691
|
+
if (schema.additionalProperties) return `Record<string, ${this.jsonSchemaTypeToTs(schema.additionalProperties)}>`;
|
|
1581
1692
|
return "Record<string, unknown>";
|
|
1582
1693
|
default: return "unknown";
|
|
1583
1694
|
}
|
|
@@ -1598,10 +1709,7 @@ var OpenApiTsGenerator = class {
|
|
|
1598
1709
|
}
|
|
1599
1710
|
const firstWithParams = infos.find((i) => i.input?.params);
|
|
1600
1711
|
let paramsEntry = "";
|
|
1601
|
-
if (firstWithParams?.input?.params) {
|
|
1602
|
-
const paramsName = await this.getSchemaName(firstWithParams.input.params, `${this.getSchemaBaseName(firstWithParams)}Params`);
|
|
1603
|
-
paramsEntry = `\n parameters: {\n path: ${paramsName};\n };`;
|
|
1604
|
-
}
|
|
1712
|
+
if (firstWithParams?.input?.params) paramsEntry = `\n parameters: {\n path: ${await this.getSchemaName(firstWithParams.input.params, `${this.getSchemaBaseName(firstWithParams)}Params`)};\n };`;
|
|
1605
1713
|
pathEntries.push(` '${route}': {${paramsEntry}\n${methodEntries.join("\n")}\n };`);
|
|
1606
1714
|
}
|
|
1607
1715
|
return `export interface paths {\n${pathEntries.join("\n")}\n}`;
|
|
@@ -1640,8 +1748,7 @@ var OpenApiTsGenerator = class {
|
|
|
1640
1748
|
return acc;
|
|
1641
1749
|
}, {});
|
|
1642
1750
|
const schemeNames = securitySchemes.map((s) => `'${s.name}'`).join(" | ");
|
|
1643
|
-
const
|
|
1644
|
-
const createApiSection = hasSecuritySchemes ? `
|
|
1751
|
+
const createApiSection = schemeNames.length > 0 ? `
|
|
1645
1752
|
// ============================================================
|
|
1646
1753
|
// API Client Factory
|
|
1647
1754
|
// ============================================================
|
|
@@ -1665,6 +1772,8 @@ export interface CreateApiOptions {
|
|
|
1665
1772
|
queryClient?: QueryClient;
|
|
1666
1773
|
/** Optional request interceptor */
|
|
1667
1774
|
onRequest?: (config: RequestInit) => RequestInit | Promise<RequestInit>;
|
|
1775
|
+
/** The \`fetch\` requests go out on — a test browser's, for one */
|
|
1776
|
+
fetch?: typeof fetch;
|
|
1668
1777
|
}
|
|
1669
1778
|
|
|
1670
1779
|
/**
|
|
@@ -1694,6 +1803,7 @@ export function createApi(options: CreateApiOptions) {
|
|
|
1694
1803
|
securitySchemes,
|
|
1695
1804
|
authStrategies: options.authStrategies,
|
|
1696
1805
|
onRequest: options.onRequest,
|
|
1806
|
+
...(options.fetch ? { fetch: options.fetch } : {}),
|
|
1697
1807
|
});
|
|
1698
1808
|
|
|
1699
1809
|
const hooks = createEndpointHooks<paths>(fetcher, { queryClient: options.queryClient });
|
|
@@ -1818,258 +1928,38 @@ ${createApiSection}
|
|
|
1818
1928
|
`;
|
|
1819
1929
|
}
|
|
1820
1930
|
};
|
|
1821
|
-
|
|
1822
|
-
//#endregion
|
|
1823
|
-
//#region src/workspace/client-generator.ts
|
|
1824
1931
|
/**
|
|
1825
|
-
*
|
|
1826
|
-
*
|
|
1827
|
-
*
|
|
1932
|
+
* The declaration for a schema that cannot be converted — a vendor with no
|
|
1933
|
+
* converter, or one that fails. The paths interface names it either way, so
|
|
1934
|
+
* leaving it undeclared made the generated client fail to compile.
|
|
1828
1935
|
*/
|
|
1829
|
-
function
|
|
1830
|
-
|
|
1831
|
-
if (require_discover.isPartitionedRoutes(routes)) return Array.isArray(routes.paths) ? routes.paths : [routes.paths];
|
|
1832
|
-
return Array.isArray(routes) ? routes : [routes];
|
|
1936
|
+
function unknownType(name) {
|
|
1937
|
+
return `export type ${name} = unknown;`;
|
|
1833
1938
|
}
|
|
1834
|
-
|
|
1835
1939
|
//#endregion
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
const OPENAPI_OUTPUT_PATH = "./.gkm/openapi.ts";
|
|
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
|
-
/**
|
|
1852
|
-
* Resolve OpenAPI config from GkmConfig
|
|
1853
|
-
*/
|
|
1854
|
-
function resolveOpenApiConfig(config) {
|
|
1855
|
-
if (config.openapi === false) return { enabled: false };
|
|
1856
|
-
if (config.openapi === true || config.openapi === void 0) return {
|
|
1857
|
-
enabled: true,
|
|
1858
|
-
title: "API Documentation",
|
|
1859
|
-
version: "1.0.0",
|
|
1860
|
-
description: "Auto-generated API documentation from endpoints"
|
|
1861
|
-
};
|
|
1862
|
-
return {
|
|
1863
|
-
enabled: config.openapi.enabled !== false,
|
|
1864
|
-
title: config.openapi.title || "API Documentation",
|
|
1865
|
-
version: config.openapi.version || "1.0.0",
|
|
1866
|
-
description: config.openapi.description || "Auto-generated API documentation from endpoints"
|
|
1867
|
-
};
|
|
1868
|
-
}
|
|
1869
|
-
/**
|
|
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
|
|
1890
|
-
*/
|
|
1891
|
-
async function generateOpenApi(endpoints, options = {}) {
|
|
1892
|
-
const logger = options.silent ? { log: () => {} } : console;
|
|
1893
|
-
const openApiConfig = resolveOpenApiConfig({ openapi: options.openapi });
|
|
1894
|
-
if (!openApiConfig.enabled) return null;
|
|
1895
|
-
if (endpoints.length === 0) {
|
|
1896
|
-
logger.log("No valid endpoints found for OpenAPI generation");
|
|
1897
|
-
return null;
|
|
1898
|
-
}
|
|
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
|
-
}
|
|
1911
|
-
const tsGenerator = new OpenApiTsGenerator();
|
|
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)`);
|
|
1940
|
+
Object.defineProperty(exports, "EndpointGenerator", {
|
|
1941
|
+
enumerable: true,
|
|
1942
|
+
get: function() {
|
|
1943
|
+
return EndpointGenerator;
|
|
1925
1944
|
}
|
|
1926
|
-
return {
|
|
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
|
|
1930
|
-
};
|
|
1931
|
-
}
|
|
1932
|
-
async function openapiCommand(options = {}) {
|
|
1933
|
-
const logger = console;
|
|
1934
|
-
try {
|
|
1935
|
-
const loadedConfig = await require_config.loadWorkspaceConfig(options.cwd);
|
|
1936
|
-
if (loadedConfig.type === "single") {
|
|
1937
|
-
const config = loadedConfig.raw;
|
|
1938
|
-
if (!config.openapi) config.openapi = { enabled: true };
|
|
1939
|
-
const result = await generateOpenApiFrom(config.constructs, { openapi: config.openapi });
|
|
1940
|
-
if (result) logger.log(`Found ${result.endpointCount} endpoints`);
|
|
1941
|
-
} else {
|
|
1942
|
-
const { workspace } = loadedConfig;
|
|
1943
|
-
const workspaceRoot = workspace.root;
|
|
1944
|
-
const backendApps = Object.entries(workspace.apps).filter(([_, app]) => app.type === "backend" && app.openapi !== false && (typeof app.openapi !== "object" || app.openapi.enabled !== false));
|
|
1945
|
-
if (backendApps.length === 0) {
|
|
1946
|
-
logger.log("No backend apps with OpenAPI enabled found");
|
|
1947
|
-
return;
|
|
1948
|
-
}
|
|
1949
|
-
if (options.app) {
|
|
1950
|
-
const entry = backendApps.find(([name]) => name === options.app);
|
|
1951
|
-
if (!entry) throw new Error(`App "${options.app}" not found or has OpenAPI disabled`);
|
|
1952
|
-
const [appName, app] = entry;
|
|
1953
|
-
const result = await generateOpenApiForApp(workspaceRoot, appName, app);
|
|
1954
|
-
if (result) logger.log(`📄 [${appName}] Generated OpenAPI (${result.endpointCount} endpoints)`);
|
|
1955
|
-
return;
|
|
1956
|
-
}
|
|
1957
|
-
for (const [appName, app] of backendApps) {
|
|
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
|
-
}
|
|
1964
|
-
await runOpenApiInSubprocess(appPath, appName);
|
|
1965
|
-
}
|
|
1966
|
-
}
|
|
1967
|
-
} catch (error) {
|
|
1968
|
-
throw new Error(`OpenAPI generation failed: ${error.message}`);
|
|
1969
|
-
}
|
|
1970
|
-
}
|
|
1971
|
-
/**
|
|
1972
|
-
* Generate OpenAPI for a single named app within a workspace.
|
|
1973
|
-
* Runs in-process. The caller is responsible for ensuring `process.cwd()`
|
|
1974
|
-
* is the app's directory so tsx loads the app's tsconfig path aliases.
|
|
1975
|
-
*/
|
|
1976
|
-
async function generateOpenApiForApp(workspaceRoot, _appName, app, silent = true) {
|
|
1977
|
-
if (app.type !== "backend") return null;
|
|
1978
|
-
const appPath = (0, node_path.join)(workspaceRoot, app.path);
|
|
1979
|
-
const globs = [(0, node_path.join)(appPath, "**/*.ts")];
|
|
1980
|
-
return generateOpenApiFrom(globs, {
|
|
1981
|
-
openapi: app.openapi ?? { enabled: true },
|
|
1982
|
-
silent
|
|
1983
|
-
});
|
|
1984
|
-
}
|
|
1985
|
-
/**
|
|
1986
|
-
* Resolve the gkm bin path. Tests can override via `GKM_BIN_PATH` env var
|
|
1987
|
-
* to avoid depending on the built dist.
|
|
1988
|
-
*/
|
|
1989
|
-
function resolveGkmBinPath() {
|
|
1990
|
-
if (process.env.GKM_BIN_PATH) return process.env.GKM_BIN_PATH;
|
|
1991
|
-
return (0, node_url.fileURLToPath)(new URL("../bin/gkm.mjs", require("url").pathToFileURL(__filename).href));
|
|
1992
|
-
}
|
|
1993
|
-
/**
|
|
1994
|
-
* Spawn a subprocess that runs `gkm openapi --app <name>` with `cwd` set to
|
|
1995
|
-
* the app's directory. Inherits `NODE_OPTIONS` (which already contains
|
|
1996
|
-
* `--import tsx`), so the child gets a fresh tsx instance whose tsconfig
|
|
1997
|
-
* discovery picks up the app's tsconfig path aliases.
|
|
1998
|
-
*/
|
|
1999
|
-
async function runOpenApiInSubprocess(appCwd, appName) {
|
|
2000
|
-
const binPath = resolveGkmBinPath();
|
|
2001
|
-
await new Promise((resolve$1, reject) => {
|
|
2002
|
-
const child = (0, node_child_process.spawn)(process.execPath, [
|
|
2003
|
-
binPath,
|
|
2004
|
-
"openapi",
|
|
2005
|
-
"--app",
|
|
2006
|
-
appName
|
|
2007
|
-
], {
|
|
2008
|
-
cwd: appCwd,
|
|
2009
|
-
stdio: "inherit",
|
|
2010
|
-
env: process.env
|
|
2011
|
-
});
|
|
2012
|
-
child.on("error", reject);
|
|
2013
|
-
child.on("close", (code) => {
|
|
2014
|
-
if (code === 0) resolve$1();
|
|
2015
|
-
else reject(new Error(`OpenAPI generation for app "${appName}" exited with code ${code}`));
|
|
2016
|
-
});
|
|
2017
|
-
});
|
|
2018
|
-
}
|
|
2019
|
-
|
|
2020
|
-
//#endregion
|
|
2021
|
-
Object.defineProperty(exports, 'EndpointGenerator', {
|
|
2022
|
-
enumerable: true,
|
|
2023
|
-
get: function () {
|
|
2024
|
-
return EndpointGenerator;
|
|
2025
|
-
}
|
|
2026
|
-
});
|
|
2027
|
-
Object.defineProperty(exports, 'OPENAPI_OUTPUT_PATH', {
|
|
2028
|
-
enumerable: true,
|
|
2029
|
-
get: function () {
|
|
2030
|
-
return OPENAPI_OUTPUT_PATH;
|
|
2031
|
-
}
|
|
2032
1945
|
});
|
|
2033
|
-
Object.defineProperty(exports,
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
});
|
|
2039
|
-
Object.defineProperty(exports, 'generateOpenApiFrom', {
|
|
2040
|
-
enumerable: true,
|
|
2041
|
-
get: function () {
|
|
2042
|
-
return generateOpenApiFrom;
|
|
2043
|
-
}
|
|
2044
|
-
});
|
|
2045
|
-
Object.defineProperty(exports, 'normalizeRoutes', {
|
|
2046
|
-
enumerable: true,
|
|
2047
|
-
get: function () {
|
|
2048
|
-
return normalizeRoutes;
|
|
2049
|
-
}
|
|
2050
|
-
});
|
|
2051
|
-
Object.defineProperty(exports, 'openApiPathFor', {
|
|
2052
|
-
enumerable: true,
|
|
2053
|
-
get: function () {
|
|
2054
|
-
return openApiPathFor;
|
|
2055
|
-
}
|
|
2056
|
-
});
|
|
2057
|
-
Object.defineProperty(exports, 'openapiCommand', {
|
|
2058
|
-
enumerable: true,
|
|
2059
|
-
get: function () {
|
|
2060
|
-
return openapiCommand;
|
|
2061
|
-
}
|
|
1946
|
+
Object.defineProperty(exports, "OpenApiTsGenerator", {
|
|
1947
|
+
enumerable: true,
|
|
1948
|
+
get: function() {
|
|
1949
|
+
return OpenApiTsGenerator;
|
|
1950
|
+
}
|
|
2062
1951
|
});
|
|
2063
|
-
Object.defineProperty(exports,
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
1952
|
+
Object.defineProperty(exports, "runtimeFor", {
|
|
1953
|
+
enumerable: true,
|
|
1954
|
+
get: function() {
|
|
1955
|
+
return runtimeFor;
|
|
1956
|
+
}
|
|
2068
1957
|
});
|
|
2069
|
-
Object.defineProperty(exports,
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
1958
|
+
Object.defineProperty(exports, "telemetryFor", {
|
|
1959
|
+
enumerable: true,
|
|
1960
|
+
get: function() {
|
|
1961
|
+
return telemetryFor;
|
|
1962
|
+
}
|
|
2074
1963
|
});
|
|
2075
|
-
|
|
1964
|
+
|
|
1965
|
+
//# sourceMappingURL=OpenApiTsGenerator-BSrgw7B0.cjs.map
|