@geekmidas/cli 10.0.0-alpha.6 → 10.0.0-alpha.60
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-BTZd2u0f.cjs} +21 -22
- package/dist/HostingerProvider-BTZd2u0f.cjs.map +1 -0
- package/dist/{HostingerProvider-Cft7lEYr.mjs → HostingerProvider-DgzKa_Tj.mjs} +20 -21
- package/dist/HostingerProvider-DgzKa_Tj.mjs.map +1 -0
- package/dist/LegacyStateStore-CToa2hga.mjs +89 -0
- package/dist/LegacyStateStore-CToa2hga.mjs.map +1 -0
- package/dist/LegacyStateStore-CidlPT0N.cjs +89 -0
- package/dist/LegacyStateStore-CidlPT0N.cjs.map +1 -0
- package/dist/LocalStateStore-BFLiOocU.mjs +165 -0
- package/dist/LocalStateStore-BFLiOocU.mjs.map +1 -0
- package/dist/LocalStateStore-Dpuqka1N.cjs +176 -0
- package/dist/LocalStateStore-Dpuqka1N.cjs.map +1 -0
- package/dist/{openapi-D-dx9Akj.cjs → OpenApiTsGenerator-BTuUumsV.cjs} +330 -469
- package/dist/OpenApiTsGenerator-BTuUumsV.cjs.map +1 -0
- package/dist/{openapi-Bw8DWFWz.mjs → OpenApiTsGenerator-CvVr1Ilz.mjs} +295 -403
- package/dist/OpenApiTsGenerator-CvVr1Ilz.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-aaGkjcxO.mjs +161 -0
- package/dist/S3StateStore-aaGkjcxO.mjs.map +1 -0
- package/dist/S3StateStore-cnm813Xn.cjs +160 -0
- package/dist/S3StateStore-cnm813Xn.cjs.map +1 -0
- package/dist/SSMStateStore-BllaJKGo.mjs +154 -0
- package/dist/SSMStateStore-BllaJKGo.mjs.map +1 -0
- package/dist/SSMStateStore-DwaGprVX.cjs +153 -0
- package/dist/SSMStateStore-DwaGprVX.cjs.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-BY1OmV1e.cjs → bundler-CzXZPSBJ.cjs} +20 -32
- package/dist/bundler-CzXZPSBJ.cjs.map +1 -0
- package/dist/{bundler-Be8Zg4Wd.mjs → bundler-DJVR4QlW.mjs} +18 -29
- package/dist/bundler-DJVR4QlW.mjs.map +1 -0
- package/dist/cli-D_qTl20Z.cjs +69 -0
- package/dist/cli-D_qTl20Z.cjs.map +1 -0
- package/dist/cli-DzR1hpum.mjs +69 -0
- package/dist/cli-DzR1hpum.mjs.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-0fBVeWO-.cjs +3518 -0
- package/dist/deploy-0fBVeWO-.cjs.map +1 -0
- package/dist/deploy-D6Q09OkA.mjs +3429 -0
- package/dist/deploy-D6Q09OkA.mjs.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-CML4UaPi.cjs +91 -0
- package/dist/encryption-CML4UaPi.cjs.map +1 -0
- package/dist/encryption-aDA2AzVx.mjs +90 -0
- package/dist/encryption-aDA2AzVx.mjs.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 +9096 -12213
- 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 +9067 -12192
- package/dist/index.mjs.map +1 -1
- package/dist/migrate-BTqIflwc.cjs +743 -0
- package/dist/migrate-BTqIflwc.cjs.map +1 -0
- package/dist/migrate-B_6KofUo.mjs +736 -0
- package/dist/migrate-B_6KofUo.mjs.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-CCLIAkwR.cjs +807 -0
- package/dist/ready-CCLIAkwR.cjs.map +1 -0
- package/dist/ready-CIHpnUc5.mjs +760 -0
- package/dist/ready-CIHpnUc5.mjs.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-BM8fpCas.mjs +6321 -0
- package/dist/sniffer-BM8fpCas.mjs.map +1 -0
- package/dist/sniffer-DIv12ncU.cjs +6707 -0
- package/dist/sniffer-DIv12ncU.cjs.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
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ A powerful CLI tool for building and managing TypeScript-based backend APIs with
|
|
|
7
7
|
- **Project Scaffolding**: Interactive `init` command to bootstrap new projects with templates
|
|
8
8
|
- **Multi-Provider Support**: Generate handlers for AWS Lambda (API Gateway v1/v2) and server applications
|
|
9
9
|
- **Development Server**: Hot-reload development server with file watching
|
|
10
|
-
- **Telescope Integration**: Laravel-style
|
|
10
|
+
- **Telescope Integration**: Laravel-style recording of requests, logs and exceptions, served as JSON
|
|
11
11
|
- **OpenAPI Generation**: Auto-generate OpenAPI 3.0 specifications from your endpoints
|
|
12
12
|
- **Docker Support**: Generate optimized Dockerfiles with multi-stage builds, turbo prune for monorepos
|
|
13
13
|
- **Secrets Management**: Secure credential generation, encryption, and stage-based secrets storage
|
|
@@ -54,6 +54,7 @@ Create a `gkm.config.ts` file in your project root:
|
|
|
54
54
|
import { defineConfig } from '@geekmidas/cli/config';
|
|
55
55
|
|
|
56
56
|
export default defineConfig({
|
|
57
|
+
stages: { local: 'dev', deployed: ['prod'] },
|
|
57
58
|
// Glob pattern to find endpoint files
|
|
58
59
|
routes: 'src/routes/**/*.ts',
|
|
59
60
|
|
|
@@ -72,7 +73,7 @@ export default defineConfig({
|
|
|
72
73
|
// Logger configuration
|
|
73
74
|
logger: './src/logger.ts#logger',
|
|
74
75
|
|
|
75
|
-
// Optional: Telescope
|
|
76
|
+
// Optional: Telescope request recording (enabled by default in dev)
|
|
76
77
|
telescope: {
|
|
77
78
|
enabled: true,
|
|
78
79
|
path: '/__telescope',
|
|
@@ -142,36 +143,32 @@ export const createUser = api
|
|
|
142
143
|
|
|
143
144
|
### 5. Create Subscribers (Optional)
|
|
144
145
|
|
|
145
|
-
|
|
146
|
+
Declare the topic once, and a worker to run what has no port; a subscriber is
|
|
147
|
+
built from the worker and binds to the topic:
|
|
146
148
|
|
|
147
149
|
```typescript
|
|
150
|
+
// src/constructs/topics.ts
|
|
151
|
+
import { Topic } from '@geekmidas/constructs/topic';
|
|
152
|
+
import { z } from 'zod';
|
|
153
|
+
|
|
154
|
+
export const users = new Topic('Users', {
|
|
155
|
+
events: {
|
|
156
|
+
'user.created': z.object({ userId: z.string(), email: z.email() }),
|
|
157
|
+
'user.updated': z.object({ userId: z.string() }),
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// src/constructs/worker.ts
|
|
162
|
+
import { Worker } from '@geekmidas/constructs/worker';
|
|
163
|
+
|
|
164
|
+
export const worker = new Worker('Jobs', { logger });
|
|
165
|
+
|
|
148
166
|
// src/subscribers/userSubscriber.ts
|
|
149
|
-
import {
|
|
150
|
-
import
|
|
151
|
-
import type { EventPublisher, PublishableMessage } from '@geekmidas/events';
|
|
152
|
-
import type { EnvironmentParser } from '@geekmidas/envkit';
|
|
153
|
-
|
|
154
|
-
// Define event types
|
|
155
|
-
type UserEvents =
|
|
156
|
-
| PublishableMessage<'user.created', { userId: string; email: string }>
|
|
157
|
-
| PublishableMessage<'user.updated', { userId: string }>;
|
|
158
|
-
|
|
159
|
-
// Create event publisher service
|
|
160
|
-
const userEventPublisher = {
|
|
161
|
-
serviceName: 'userEventPublisher' as const,
|
|
162
|
-
async register(envParser: EnvironmentParser<{}>) {
|
|
163
|
-
const config = envParser.create((get) => ({
|
|
164
|
-
publisherUrl: get('EVENT_PUBLISHER_URL').string()
|
|
165
|
-
})).parse();
|
|
166
|
-
|
|
167
|
-
const { Publisher } = await import('@geekmidas/events');
|
|
168
|
-
return Publisher.fromConnectionString<UserEvents>(config.publisherUrl);
|
|
169
|
-
}
|
|
170
|
-
} satisfies Service<'userEventPublisher', EventPublisher<UserEvents>>;
|
|
167
|
+
import { users } from '../constructs/topics';
|
|
168
|
+
import { worker } from '../constructs/worker';
|
|
171
169
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
.publisher(userEventPublisher)
|
|
170
|
+
export const userCreatedSubscriber = worker
|
|
171
|
+
.topic(users)
|
|
175
172
|
.subscribe(['user.created'])
|
|
176
173
|
.handle(async ({ events, logger }) => {
|
|
177
174
|
for (const event of events) {
|
|
@@ -181,11 +178,16 @@ export const userCreatedSubscriber = new SubscriberBuilder()
|
|
|
181
178
|
});
|
|
182
179
|
```
|
|
183
180
|
|
|
181
|
+
An endpoint publishes to the topic with `.event(users, { type: 'user.created',
|
|
182
|
+
payload: (user) => ({ userId: user.id, email: user.email }) })`. Declaring the
|
|
183
|
+
topic is what puts a broker in the local plan and resolves
|
|
184
|
+
`USERS_PUBLISHER_CONNECTION_STRING` for whatever publishes to it.
|
|
185
|
+
|
|
184
186
|
### 6. Build Handlers
|
|
185
187
|
|
|
186
188
|
```bash
|
|
187
|
-
#
|
|
188
|
-
npx gkm build
|
|
189
|
+
# Build for where gkm.config.ts deploys (AWS for `deploy: { default: 'sst' }`)
|
|
190
|
+
npx gkm build
|
|
189
191
|
|
|
190
192
|
# Generate server application
|
|
191
193
|
npx gkm build --provider server
|
|
@@ -224,7 +226,7 @@ When run without `--yes`, the command will ask:
|
|
|
224
226
|
- `api` - Full API with auth, database, services
|
|
225
227
|
- `serverless` - AWS Lambda handlers
|
|
226
228
|
- `worker` - Background job processing
|
|
227
|
-
3. **Telescope** - Include
|
|
229
|
+
3. **Telescope** - Include request, exception and log recording (default: yes)
|
|
228
230
|
4. **Database** - Include Kysely database support (default: yes)
|
|
229
231
|
5. **Logger** - Choose logger implementation:
|
|
230
232
|
- `pino` - Fast JSON logger for production (recommended)
|
|
@@ -309,17 +311,20 @@ Generate handlers from your endpoints.
|
|
|
309
311
|
gkm build [options]
|
|
310
312
|
```
|
|
311
313
|
|
|
314
|
+
By default it builds for where the project deploys: `deploy: { default: 'sst' }`
|
|
315
|
+
builds for AWS, one Lambda per construct; `dokploy` (the default when nothing
|
|
316
|
+
is declared) builds a server.
|
|
317
|
+
|
|
312
318
|
**Options:**
|
|
313
|
-
- `--provider <provider>`:
|
|
314
|
-
- `aws
|
|
315
|
-
- `aws-apigatewayv2`: AWS API Gateway v2 Lambda handlers
|
|
319
|
+
- `--provider <provider>`: Override the deploy target
|
|
320
|
+
- `aws`: One Lambda handler per construct (API Gateway v2 for endpoints)
|
|
316
321
|
- `server`: Server application with Hono
|
|
317
322
|
- `--production`: Generate production-optimized bundle (server provider only)
|
|
318
323
|
|
|
319
324
|
**Example:**
|
|
320
325
|
```bash
|
|
321
|
-
#
|
|
322
|
-
gkm build
|
|
326
|
+
# Build for where gkm.config.ts deploys
|
|
327
|
+
gkm build
|
|
323
328
|
|
|
324
329
|
# Generate server application
|
|
325
330
|
gkm build --provider server
|
|
@@ -443,7 +448,7 @@ gkm docker [options]
|
|
|
443
448
|
|
|
444
449
|
**Generated Files:**
|
|
445
450
|
- `.gkm/docker/Dockerfile` - Multi-stage or slim Dockerfile
|
|
446
|
-
-
|
|
451
|
+
- `docker-compose.constructs.yml` - the containers the constructs imply, and the app (project root)
|
|
447
452
|
- `.gkm/docker/docker-entrypoint.sh` - Entrypoint script
|
|
448
453
|
- `.dockerignore` - Docker ignore file (project root)
|
|
449
454
|
|
|
@@ -490,6 +495,7 @@ Configure Docker settings in `gkm.config.ts`:
|
|
|
490
495
|
import { defineConfig } from '@geekmidas/cli/config';
|
|
491
496
|
|
|
492
497
|
export default defineConfig({
|
|
498
|
+
stages: { local: 'dev', deployed: ['prod'] },
|
|
493
499
|
routes: 'src/routes/**/*.ts',
|
|
494
500
|
envParser: './src/env.ts',
|
|
495
501
|
logger: './src/logger.ts',
|
|
@@ -503,38 +509,20 @@ export default defineConfig({
|
|
|
503
509
|
baseImage: 'node:22-alpine',
|
|
504
510
|
// Port to expose (default: 3000)
|
|
505
511
|
port: 3000,
|
|
506
|
-
// Docker Compose services
|
|
507
|
-
compose: {
|
|
508
|
-
services: {
|
|
509
|
-
postgres: { image: 'postgis/postgis:16-3.4-alpine' }, // Custom image
|
|
510
|
-
redis: true, // Default version
|
|
511
|
-
rabbitmq: { version: '3.12-management-alpine' }, // Custom version
|
|
512
|
-
},
|
|
513
|
-
},
|
|
514
512
|
},
|
|
515
513
|
});
|
|
516
514
|
```
|
|
517
515
|
|
|
518
|
-
**
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
```typescript
|
|
523
|
-
// Object format (recommended)
|
|
524
|
-
services: {
|
|
525
|
-
postgres: { version: '15-alpine' }, // Custom version
|
|
526
|
-
redis: true, // Default: redis:7-alpine
|
|
527
|
-
rabbitmq: { version: '3.12-management-alpine' },
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
// Custom images (e.g., PostGIS, Redis Stack)
|
|
531
|
-
services: {
|
|
532
|
-
postgres: { image: 'postgis/postgis:16-3.4-alpine' }, // Full image reference
|
|
533
|
-
redis: { image: 'redis/redis-stack:latest' },
|
|
534
|
-
}
|
|
516
|
+
**Compose:** there is no `compose` option. `gkm docker` writes
|
|
517
|
+
`docker-compose.constructs.yml` at the project root from the declared
|
|
518
|
+
constructs; an image pin or an extra service goes in your own
|
|
519
|
+
`docker-compose.yml`, which is merged over it:
|
|
535
520
|
|
|
536
|
-
|
|
537
|
-
|
|
521
|
+
```yaml
|
|
522
|
+
# docker-compose.yml
|
|
523
|
+
services:
|
|
524
|
+
postgres:
|
|
525
|
+
image: postgis/postgis:16-3.4-alpine
|
|
538
526
|
```
|
|
539
527
|
|
|
540
528
|
**Service Configuration Options:**
|
|
@@ -557,7 +545,7 @@ services: ['postgres', 'redis', 'rabbitmq']
|
|
|
557
545
|
|
|
558
546
|
### `gkm dev`
|
|
559
547
|
|
|
560
|
-
Start a development server with hot-reload and optional Telescope
|
|
548
|
+
Start a development server with hot-reload and optional Telescope recording.
|
|
561
549
|
|
|
562
550
|
```bash
|
|
563
551
|
gkm dev [options]
|
|
@@ -569,7 +557,8 @@ gkm dev [options]
|
|
|
569
557
|
**Features:**
|
|
570
558
|
- Hot-reload on file changes (endpoints, functions, crons, subscribers)
|
|
571
559
|
- Automatic port switching if requested port is in use
|
|
572
|
-
- Telescope
|
|
560
|
+
- Telescope JSON API at `/__telescope/api` (enabled by default)
|
|
561
|
+
- The declared database, read-only, as JSON at `/__gkm/db`
|
|
573
562
|
- Real-time WebSocket updates in Telescope
|
|
574
563
|
|
|
575
564
|
**Example:**
|
|
@@ -682,8 +671,8 @@ gkm secrets:init --stage production --force
|
|
|
682
671
|
```
|
|
683
672
|
|
|
684
673
|
**Generated:**
|
|
685
|
-
-
|
|
686
|
-
|
|
674
|
+
- Custom secrets for the stage; the containers' credentials are provisioned by
|
|
675
|
+
reconcile from the declared constructs, not stored here
|
|
687
676
|
- Stored in `.gkm/secrets/<stage>.json` (gitignored)
|
|
688
677
|
|
|
689
678
|
### `gkm secrets:set`
|
|
@@ -797,7 +786,7 @@ Store credentials locally to avoid setting environment variables for every comma
|
|
|
797
786
|
|
|
798
787
|
### `gkm login`
|
|
799
788
|
|
|
800
|
-
Authenticate with a deployment service. Credentials are stored in `~/.gkm/credentials.json
|
|
789
|
+
Authenticate with a deployment service. Credentials are stored in `~/.gkm/credentials.json` (`$GKM_HOME/credentials.json` when `GKM_HOME` is set).
|
|
801
790
|
|
|
802
791
|
```bash
|
|
803
792
|
gkm login [options]
|
|
@@ -883,6 +872,20 @@ gkm deploy --provider <provider> --stage <stage> [options]
|
|
|
883
872
|
- `--tag <tag>`: Image tag (default: `stage-timestamp`)
|
|
884
873
|
- `--skip-push`: Skip pushing image to registry
|
|
885
874
|
- `--skip-build`: Skip build step (use existing build)
|
|
875
|
+
- `--json`: Write the deploy's events as JSON lines on stdout instead of progress; never prompts
|
|
876
|
+
- `--dry-run`: Show what would be created or reused, and change, build and push nothing
|
|
877
|
+
|
|
878
|
+
At a terminal a missing Dokploy or registry login is asked for (and the Dokploy one stored). With `--json` or without a terminal nothing is asked: the deploy stops with `MissingCredential` and exits 1.
|
|
879
|
+
|
|
880
|
+
**From a program:** the same deploy is `deploy()` from `@geekmidas/cli/deploy` — explicit `cwd`, an injected `CredentialProvider`, a logger and an `AbortSignal`; it returns a run you iterate for JSON events, plus a `result` promise. It never prompts, prints or exits.
|
|
881
|
+
|
|
882
|
+
```typescript
|
|
883
|
+
import { deploy } from '@geekmidas/cli/deploy';
|
|
884
|
+
|
|
885
|
+
const run = deploy({ cwd: '/srv/shop', stage: 'production', signal });
|
|
886
|
+
for await (const event of run) console.log(event.type);
|
|
887
|
+
const result = await run.result;
|
|
888
|
+
```
|
|
886
889
|
|
|
887
890
|
**Examples:**
|
|
888
891
|
```bash
|
|
@@ -929,6 +932,7 @@ This allows the CLI to validate that all required secrets are configured before
|
|
|
929
932
|
```typescript
|
|
930
933
|
// gkm.config.ts
|
|
931
934
|
export default defineConfig({
|
|
935
|
+
stages: { local: 'dev', deployed: ['prod'] },
|
|
932
936
|
routes: 'src/endpoints/**/*.ts',
|
|
933
937
|
envParser: './src/env.ts',
|
|
934
938
|
logger: './src/logger.ts',
|
|
@@ -937,25 +941,19 @@ export default defineConfig({
|
|
|
937
941
|
registry: 'ghcr.io/myorg',
|
|
938
942
|
imageName: 'my-api',
|
|
939
943
|
},
|
|
940
|
-
|
|
941
|
-
// For Dokploy deployments
|
|
942
|
-
providers: {
|
|
943
|
-
dokploy: {
|
|
944
|
-
endpoint: 'https://dokploy.example.com',
|
|
945
|
-
projectId: 'proj_xxx',
|
|
946
|
-
applicationId: 'app_xxx',
|
|
947
|
-
},
|
|
948
|
-
},
|
|
949
944
|
});
|
|
950
945
|
```
|
|
951
946
|
|
|
952
947
|
**Environment Variables:**
|
|
953
948
|
- `DOKPLOY_API_TOKEN`: API token for Dokploy (not needed if logged in via `gkm login`)
|
|
954
|
-
- `
|
|
949
|
+
- `DOKPLOY_ENDPOINT`: Dokploy URL, if neither the stored login nor `deploy.dokploy.endpoint` gives one
|
|
950
|
+
- `DOCKER_REGISTRY_USERNAME` / `DOCKER_REGISTRY_PASSWORD`: a registry login, used only when Dokploy has no registry for `deploy.dokploy.registry` and one has to be created
|
|
951
|
+
- `GKM_HOME`: where stage keys and stored logins live (default `~/.gkm`)
|
|
952
|
+
- `GKM_MASTER_KEY`: Automatically set by Dokploy, or manually for Docker deployments — from `.gkm/server/master.key`, which `gkm build --stage` writes (the key is never printed; output shows its fingerprint)
|
|
955
953
|
|
|
956
954
|
### `gkm deploy:init`
|
|
957
955
|
|
|
958
|
-
Initialize a new Dokploy deployment by creating a project and application via the Dokploy API.
|
|
956
|
+
Initialize a new Dokploy deployment by creating a project and application via the Dokploy API. Nothing is written to `gkm.config.ts`: the ids are rediscovered by name on each run and kept in the deploy state file.
|
|
959
957
|
|
|
960
958
|
```bash
|
|
961
959
|
gkm deploy:init --project <name> --app <name> [options]
|
|
@@ -990,8 +988,7 @@ gkm deploy:init \
|
|
|
990
988
|
1. Searches for existing project by name, or creates a new one
|
|
991
989
|
2. Creates a new application in the project
|
|
992
990
|
3. Configures registry if `--registry-id` is provided
|
|
993
|
-
4.
|
|
994
|
-
5. Shows next steps for secrets and deployment
|
|
991
|
+
4. Shows next steps for secrets and deployment
|
|
995
992
|
|
|
996
993
|
### `gkm deploy:list`
|
|
997
994
|
|
|
@@ -1040,7 +1037,7 @@ export const envParser = new EnvironmentParser({...process.env, ...Credentials})
|
|
|
1040
1037
|
|
|
1041
1038
|
**How it works:**
|
|
1042
1039
|
- At build time, secrets are encrypted with AES-256-GCM and embedded in the bundle
|
|
1043
|
-
- An ephemeral master key is generated per build
|
|
1040
|
+
- An ephemeral master key is generated per build and written to `.gkm/server/master.key` (mode `0600`); the build prints its path and fingerprint, never the key
|
|
1044
1041
|
- At runtime, `Credentials` decrypts using `GKM_MASTER_KEY` environment variable
|
|
1045
1042
|
- In development (no embedded secrets), `Credentials` returns `{}`
|
|
1046
1043
|
|
|
@@ -1059,28 +1056,23 @@ The following commands are planned for future releases:
|
|
|
1059
1056
|
The `gkm.config.ts` file defines how the CLI discovers and processes your endpoints:
|
|
1060
1057
|
|
|
1061
1058
|
```typescript
|
|
1062
|
-
// Construct types accept a
|
|
1063
|
-
type Routes = string | string[]
|
|
1064
|
-
|
|
1065
|
-
interface PartitionedRoutes {
|
|
1066
|
-
paths: string | string[];
|
|
1067
|
-
partition: (filepath: string) => string;
|
|
1068
|
-
}
|
|
1059
|
+
// Construct types accept a glob string or an array of them
|
|
1060
|
+
type Routes = string | string[];
|
|
1069
1061
|
|
|
1070
1062
|
interface GkmConfig {
|
|
1071
|
-
routes: Routes; // Glob patterns
|
|
1063
|
+
routes: Routes; // Glob patterns
|
|
1072
1064
|
envParser: string; // Path to environment parser
|
|
1073
1065
|
logger: string; // Path to logger configuration
|
|
1074
|
-
functions?: Routes; // Glob patterns
|
|
1075
|
-
crons?: Routes; // Glob patterns
|
|
1076
|
-
subscribers?: Routes; // Glob patterns
|
|
1066
|
+
functions?: Routes; // Glob patterns
|
|
1067
|
+
crons?: Routes; // Glob patterns
|
|
1068
|
+
subscribers?: Routes; // Glob patterns
|
|
1077
1069
|
runtime?: 'node' | 'bun'; // Runtime environment (default: 'node')
|
|
1078
1070
|
telescope?: boolean | TelescopeConfig; // Telescope debugging config
|
|
1079
1071
|
}
|
|
1080
1072
|
|
|
1081
1073
|
interface TelescopeConfig {
|
|
1082
1074
|
enabled?: boolean; // Enable/disable (default: true in dev)
|
|
1083
|
-
path?: string; //
|
|
1075
|
+
path?: string; // Where the JSON API is mounted (default: '/__telescope')
|
|
1084
1076
|
ignore?: string[]; // URL patterns to ignore
|
|
1085
1077
|
recordBody?: boolean; // Record request/response bodies (default: true)
|
|
1086
1078
|
maxEntries?: number; // Max entries to keep (default: 1000)
|
|
@@ -1092,7 +1084,7 @@ interface TelescopeConfig {
|
|
|
1092
1084
|
|
|
1093
1085
|
#### `routes`
|
|
1094
1086
|
|
|
1095
|
-
Glob pattern(s) to discover endpoint files. Can be a single pattern
|
|
1087
|
+
Glob pattern(s) to discover endpoint files. Can be a single pattern or an array of patterns:
|
|
1096
1088
|
|
|
1097
1089
|
```typescript
|
|
1098
1090
|
// Single pattern
|
|
@@ -1104,19 +1096,8 @@ routes: [
|
|
|
1104
1096
|
'src/api/**/*.ts',
|
|
1105
1097
|
'src/handlers/**/*.ts'
|
|
1106
1098
|
]
|
|
1107
|
-
|
|
1108
|
-
// Partitioned — groups constructs in the generated manifest
|
|
1109
|
-
routes: {
|
|
1110
|
-
paths: './src/endpoints/**/*.ts',
|
|
1111
|
-
partition: (filepath) => {
|
|
1112
|
-
const match = filepath.match(/endpoints\/([^/]+)\//);
|
|
1113
|
-
return match?.[1] ?? 'default';
|
|
1114
|
-
},
|
|
1115
|
-
}
|
|
1116
1099
|
```
|
|
1117
1100
|
|
|
1118
|
-
The same partitioned format works for `functions`, `crons`, and `subscribers`. When a `partition` callback is provided, the generated manifest groups constructs by partition name (e.g., `manifest.routes.admin`). Without it, manifest fields remain flat arrays.
|
|
1119
|
-
|
|
1120
1101
|
#### `envParser`
|
|
1121
1102
|
|
|
1122
1103
|
Path to your environment parser configuration. Supports both default and named exports.
|
|
@@ -1149,7 +1130,7 @@ logger: './src/utils.ts#appLogger'
|
|
|
1149
1130
|
|
|
1150
1131
|
#### `telescope`
|
|
1151
1132
|
|
|
1152
|
-
Configuration for
|
|
1133
|
+
Configuration for Telescope, which records requests, logs and exceptions and serves them as JSON. Telescope is enabled by default when using `gkm dev`.
|
|
1153
1134
|
|
|
1154
1135
|
```typescript
|
|
1155
1136
|
// Disable telescope
|
|
@@ -1174,7 +1155,7 @@ telescope: {
|
|
|
1174
1155
|
| Option | Type | Default | Description |
|
|
1175
1156
|
|--------|------|---------|-------------|
|
|
1176
1157
|
| `enabled` | `boolean` | `true` | Enable/disable Telescope |
|
|
1177
|
-
| `path` | `string` | `/__telescope` |
|
|
1158
|
+
| `path` | `string` | `/__telescope` | Where the JSON API is mounted |
|
|
1178
1159
|
| `ignore` | `string[]` | `[]` | URL patterns to exclude from recording |
|
|
1179
1160
|
| `recordBody` | `boolean` | `true` | Record request/response bodies |
|
|
1180
1161
|
| `maxEntries` | `number` | `1000` | Maximum entries per type to keep |
|
|
@@ -1216,6 +1197,7 @@ import { defineWorkspace } from '@geekmidas/cli/config';
|
|
|
1216
1197
|
|
|
1217
1198
|
export default defineWorkspace({
|
|
1218
1199
|
name: 'my-project',
|
|
1200
|
+
stages: { local: 'dev', deployed: ['prod'] },
|
|
1219
1201
|
constructs: './constructs/**/*.ts',
|
|
1220
1202
|
shared: {
|
|
1221
1203
|
packages: ['packages/*'],
|
|
@@ -1239,7 +1221,7 @@ them out of the manifest; none of them is listed in config.
|
|
|
1239
1221
|
|
|
1240
1222
|
```typescript
|
|
1241
1223
|
// constructs/api.ts
|
|
1242
|
-
export const api = new RestApi('Api', { defaultAuthorizer: 'none', logger });
|
|
1224
|
+
export const api = new RestApi('Api', { path: 'apps/api', defaultAuthorizer: 'none', logger });
|
|
1243
1225
|
```
|
|
1244
1226
|
|
|
1245
1227
|
`gkm build --provider server` generates a Hono server from the endpoints built
|
|
@@ -1253,6 +1235,7 @@ An auth server mounts a wildcard, so there is nothing for a glob to find:
|
|
|
1253
1235
|
```typescript
|
|
1254
1236
|
// constructs/auth.ts
|
|
1255
1237
|
export const auth = new BetterAuth('Auth', {
|
|
1238
|
+
path: 'apps/auth',
|
|
1256
1239
|
database: authDb,
|
|
1257
1240
|
basePath: '/api/auth',
|
|
1258
1241
|
});
|
|
@@ -1271,8 +1254,8 @@ from being read by it.
|
|
|
1271
1254
|
|
|
1272
1255
|
```typescript
|
|
1273
1256
|
// constructs/site.ts
|
|
1274
|
-
export const web = new StaticSite('Web').dependsOn([api, auth]);
|
|
1275
|
-
export const admin = new StaticSite('Admin', { variant: 'next' }).dependsOn([api]);
|
|
1257
|
+
export const web = new StaticSite('Web', { path: 'apps/web' }).dependsOn([api, auth]);
|
|
1258
|
+
export const admin = new StaticSite('Admin', { path: 'apps/admin', variant: 'next' }).dependsOn([api]);
|
|
1276
1259
|
```
|
|
1277
1260
|
|
|
1278
1261
|
`.dependsOn()` is the single fact behind four things that are hand-maintained
|
|
@@ -1291,7 +1274,7 @@ gkm docker
|
|
|
1291
1274
|
- `.gkm/docker/Dockerfile.api` - Routes-based backend (uses `gkm build`)
|
|
1292
1275
|
- `.gkm/docker/Dockerfile.auth` - Entry-based backend (uses esbuild bundling)
|
|
1293
1276
|
- `.gkm/docker/Dockerfile.web` - Next.js standalone output
|
|
1294
|
-
-
|
|
1277
|
+
- `docker-compose.constructs.yml` - every container the constructs imply, and each app behind the `apps` profile (project root)
|
|
1295
1278
|
- `.dockerignore` - Optimized ignore patterns
|
|
1296
1279
|
|
|
1297
1280
|
**Dockerfile types by app:**
|
|
@@ -1358,12 +1341,10 @@ interface WorkspaceConfig {
|
|
|
1358
1341
|
What an app is comes from the declaration, not from here:
|
|
1359
1342
|
|
|
1360
1343
|
```typescript
|
|
1361
|
-
/**
|
|
1344
|
+
/** How a site is built and run. A surface declares only its `path`. */
|
|
1362
1345
|
interface AppSpec {
|
|
1363
|
-
/**
|
|
1364
|
-
path
|
|
1365
|
-
/** Default: the conventional directories under `path`. */
|
|
1366
|
-
code?: string;
|
|
1346
|
+
/** Required: where the app lives, relative to the workspace root. */
|
|
1347
|
+
path: string;
|
|
1367
1348
|
/** Default: assigned in a stable order, so adding an app renumbers nothing. */
|
|
1368
1349
|
port?: number;
|
|
1369
1350
|
entry?: string;
|
|
@@ -1371,42 +1352,24 @@ interface AppSpec {
|
|
|
1371
1352
|
}
|
|
1372
1353
|
```
|
|
1373
1354
|
|
|
1374
|
-
##
|
|
1375
|
-
|
|
1376
|
-
### AWS API Gateway v1
|
|
1377
|
-
|
|
1378
|
-
Generates Lambda handlers compatible with AWS API Gateway v1 (REST API).
|
|
1379
|
-
|
|
1380
|
-
```bash
|
|
1381
|
-
gkm build --provider aws-apigatewayv1
|
|
1382
|
-
```
|
|
1383
|
-
|
|
1384
|
-
**Generated Handler:**
|
|
1385
|
-
```typescript
|
|
1386
|
-
import { AmazonApiGatewayV1Endpoint } from '@geekmidas/constructs/aws';
|
|
1387
|
-
import { myEndpoint } from '../src/routes/example.js';
|
|
1388
|
-
import { envParser } from '../src/env.js';
|
|
1355
|
+
## Build Targets
|
|
1389
1356
|
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
export const handler = adapter.handler;
|
|
1393
|
-
```
|
|
1357
|
+
### AWS
|
|
1394
1358
|
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
Generates Lambda handlers compatible with AWS API Gateway v2 (HTTP API).
|
|
1359
|
+
Generates one Lambda handler per construct. Endpoints get an API Gateway v2
|
|
1360
|
+
(HTTP API) adapter.
|
|
1398
1361
|
|
|
1399
1362
|
```bash
|
|
1400
|
-
gkm build
|
|
1363
|
+
gkm build # with deploy: { default: 'sst' }
|
|
1364
|
+
gkm build --provider aws # whatever the deploy target
|
|
1401
1365
|
```
|
|
1402
1366
|
|
|
1403
1367
|
**Generated Handler:**
|
|
1404
1368
|
```typescript
|
|
1405
1369
|
import { AmazonApiGatewayV2Endpoint } from '@geekmidas/constructs/aws';
|
|
1406
|
-
import { myEndpoint } from '
|
|
1407
|
-
import { envParser } from '../src/env.js';
|
|
1370
|
+
import { myEndpoint } from '../../../src/routes/example.js';
|
|
1408
1371
|
|
|
1409
|
-
const adapter = new AmazonApiGatewayV2Endpoint(
|
|
1372
|
+
const adapter = new AmazonApiGatewayV2Endpoint(myEndpoint);
|
|
1410
1373
|
|
|
1411
1374
|
export const handler = adapter.handler;
|
|
1412
1375
|
```
|
|
@@ -1448,139 +1411,141 @@ export default createApp;
|
|
|
1448
1411
|
|
|
1449
1412
|
## Output Structure
|
|
1450
1413
|
|
|
1451
|
-
|
|
1414
|
+
Handlers are generated beside the app, in `<app>/.gkm/<target>`; the manifest
|
|
1415
|
+
at the workspace root, where `sst.config.ts` runs:
|
|
1452
1416
|
|
|
1453
1417
|
```
|
|
1454
|
-
|
|
1455
|
-
├──
|
|
1456
|
-
│ ├──
|
|
1457
|
-
│
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
│ ├──
|
|
1461
|
-
├──
|
|
1462
|
-
│ ├──
|
|
1463
|
-
│
|
|
1464
|
-
└──
|
|
1418
|
+
<root>/
|
|
1419
|
+
├── .gkm/manifest/
|
|
1420
|
+
│ ├── aws.ts # AWS manifest with types
|
|
1421
|
+
│ └── server.ts # Server manifest with types
|
|
1422
|
+
└── apps/api/.gkm/
|
|
1423
|
+
├── aws/
|
|
1424
|
+
│ ├── routes/getUsers.ts # One Lambda handler per endpoint
|
|
1425
|
+
│ ├── functions/
|
|
1426
|
+
│ ├── crons/
|
|
1427
|
+
│ ├── queues/
|
|
1428
|
+
│ └── subscribers/
|
|
1429
|
+
└── server/
|
|
1430
|
+
├── app.ts # Server application
|
|
1431
|
+
└── endpoints.ts # Endpoint exports
|
|
1465
1432
|
```
|
|
1466
1433
|
|
|
1467
1434
|
### Build Manifest
|
|
1468
1435
|
|
|
1469
|
-
The
|
|
1436
|
+
The manifest is the application's, not an app's: the root `gkm build` builds
|
|
1437
|
+
every backend and writes it once, to `.gkm/manifest/aws.ts` or
|
|
1438
|
+
`.gkm/manifest/server.ts` at the workspace root. An app's own build writes no
|
|
1439
|
+
manifest. Every handler path in it is relative to the workspace root. `gkm init`
|
|
1440
|
+
adds a root tsconfig alias for the manifest, `@<project>/manifest`.
|
|
1470
1441
|
|
|
1471
|
-
|
|
1442
|
+
It exports two values — every declared construct keyed by id, and the backends
|
|
1443
|
+
the build resolved — and the types derived from them:
|
|
1472
1444
|
|
|
1473
1445
|
```typescript
|
|
1474
|
-
export const
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1446
|
+
export const constructs = {
|
|
1447
|
+
Database: { id: 'Database', kind: 'database' },
|
|
1448
|
+
Api: {
|
|
1449
|
+
id: 'Api',
|
|
1450
|
+
kind: 'rest-api',
|
|
1451
|
+
path: 'apps/api',
|
|
1452
|
+
endpoints: [
|
|
1453
|
+
{
|
|
1454
|
+
id: 'ApiGET/users',
|
|
1455
|
+
method: 'GET',
|
|
1456
|
+
path: '/users',
|
|
1457
|
+
handler: 'apps/api/.gkm/aws/routes/getUsers.handler',
|
|
1458
|
+
dependencies: [{ target: 'Database', kind: 'database' }],
|
|
1459
|
+
authorizer: 'iam',
|
|
1460
|
+
},
|
|
1461
|
+
],
|
|
1462
|
+
},
|
|
1463
|
+
ProcessData: {
|
|
1464
|
+
id: 'ProcessData',
|
|
1465
|
+
kind: 'function',
|
|
1466
|
+
handler: 'apps/api/.gkm/aws/functions/processData.handler',
|
|
1467
|
+
dependencies: [],
|
|
1468
|
+
},
|
|
1469
|
+
DailyCleanup: {
|
|
1470
|
+
id: 'DailyCleanup',
|
|
1471
|
+
kind: 'cron',
|
|
1472
|
+
handler: 'apps/api/.gkm/aws/crons/dailyCleanup.handler',
|
|
1473
|
+
schedule: 'rate(1 day)',
|
|
1474
|
+
dependencies: [{ target: 'Database', kind: 'database' }],
|
|
1475
|
+
},
|
|
1476
|
+
Emails: {
|
|
1477
|
+
id: 'Emails',
|
|
1478
|
+
kind: 'queue',
|
|
1479
|
+
// The queue's consumer is nested in it
|
|
1480
|
+
worker: {
|
|
1481
|
+
id: 'emails',
|
|
1482
|
+
handler: 'apps/api/.gkm/aws/queues/emails.handler',
|
|
1483
|
+
dependencies: [],
|
|
1504
1484
|
},
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1485
|
+
},
|
|
1486
|
+
Users: {
|
|
1487
|
+
id: 'Users',
|
|
1488
|
+
kind: 'topic',
|
|
1489
|
+
events: ['user.created'],
|
|
1490
|
+
// As are a topic's subscribers
|
|
1491
|
+
subscribers: [
|
|
1492
|
+
{
|
|
1493
|
+
id: 'onUser',
|
|
1494
|
+
handler: 'apps/api/.gkm/aws/subscribers/onUser.handler',
|
|
1495
|
+
events: ['user.created'],
|
|
1496
|
+
dependencies: [],
|
|
1497
|
+
},
|
|
1498
|
+
],
|
|
1499
|
+
},
|
|
1500
|
+
} as const satisfies ConstructManifest;
|
|
1501
|
+
|
|
1502
|
+
export const backends = { cache: 'upstash', email: 'ses' } as const;
|
|
1508
1503
|
|
|
1509
1504
|
// Derived types
|
|
1510
|
-
export type
|
|
1511
|
-
export type
|
|
1512
|
-
export type
|
|
1513
|
-
export type Subscriber = (typeof manifest.subscribers)[number];
|
|
1505
|
+
export type Ids = IdsOf<typeof constructs>;
|
|
1506
|
+
export type Construct<Id extends Ids> = DeclarationOf<typeof constructs, Id>;
|
|
1507
|
+
export type Kind = Construct<Ids>['kind'];
|
|
1514
1508
|
|
|
1515
1509
|
// Useful union types
|
|
1516
|
-
export type
|
|
1517
|
-
export type
|
|
1518
|
-
export type
|
|
1510
|
+
export type ProvidedKeys = AllProvidedKeys<typeof constructs>;
|
|
1511
|
+
export type Surfaces = IdsOfKind<typeof constructs, 'rest-api'>;
|
|
1512
|
+
export type CacheBackend = (typeof backends)['cache'];
|
|
1513
|
+
export type EmailBackend = (typeof backends)['email'];
|
|
1519
1514
|
```
|
|
1520
1515
|
|
|
1521
|
-
|
|
1516
|
+
A `RestApi` carries its endpoints, each with its method, path, handler, the
|
|
1517
|
+
dependencies it declared and its authorizer. On AWS the handler is the
|
|
1518
|
+
endpoint's own Lambda (`apps/api/.gkm/aws/routes/<export>.handler`); in the
|
|
1519
|
+
server manifest every endpoint's handler is the app entry
|
|
1520
|
+
(`apps/api/.gkm/server/app.ts`). Functions and crons are top-level
|
|
1521
|
+
declarations; a queue's worker and a topic's subscribers are nested in the
|
|
1522
|
+
queue or topic.
|
|
1522
1523
|
|
|
1523
|
-
|
|
1524
|
-
export const manifest = {
|
|
1525
|
-
routes: {
|
|
1526
|
-
"admin": [{ path: '/admin/users', method: 'GET', handler: '...', authorizer: 'jwt' }],
|
|
1527
|
-
"default": [{ path: '/users', method: 'GET', handler: '...', authorizer: 'jwt' }],
|
|
1528
|
-
},
|
|
1529
|
-
functions: [...], // flat if not partitioned
|
|
1530
|
-
} as const;
|
|
1524
|
+
#### Using the Manifest
|
|
1531
1525
|
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
export type Route<P extends RoutePartition = RoutePartition> =
|
|
1535
|
-
(typeof manifest.routes)[P][number];
|
|
1536
|
-
```
|
|
1537
|
-
|
|
1538
|
-
#### Server Manifest (`.gkm/manifest/server.ts`)
|
|
1526
|
+
On AWS, `fromManifest` from `@geekmidas/cloud/sst` provisions all of it —
|
|
1527
|
+
resources, each API's endpoints, queue consumers, functions and crons:
|
|
1539
1528
|
|
|
1540
1529
|
```typescript
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
endpoints: '.gkm/server/endpoints.ts',
|
|
1545
|
-
},
|
|
1546
|
-
routes: [
|
|
1547
|
-
{ path: '/users', method: 'GET', authorizer: 'jwt' },
|
|
1548
|
-
{ path: '/users', method: 'POST', authorizer: 'jwt' },
|
|
1549
|
-
],
|
|
1550
|
-
subscribers: [
|
|
1551
|
-
{ name: 'orderHandler', subscribedEvents: ['order.created'] },
|
|
1552
|
-
],
|
|
1553
|
-
} as const;
|
|
1530
|
+
// sst.config.ts
|
|
1531
|
+
const { App, fromManifest, Stack } = await import('@geekmidas/cloud/sst');
|
|
1532
|
+
const { backends, constructs } = await import('./.gkm/manifest/aws.js');
|
|
1554
1533
|
|
|
1555
|
-
|
|
1556
|
-
export type Route = (typeof manifest.routes)[number];
|
|
1557
|
-
export type Subscriber = (typeof manifest.subscribers)[number];
|
|
1558
|
-
|
|
1559
|
-
// Useful union types
|
|
1560
|
-
export type Authorizer = Route['authorizer'];
|
|
1561
|
-
export type HttpMethod = Route['method'];
|
|
1562
|
-
export type RoutePath = Route['path'];
|
|
1534
|
+
fromManifest(new Stack(app, 'Shop'), constructs, { Database: { vpc } }, backends);
|
|
1563
1535
|
```
|
|
1564
1536
|
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
Import the manifest types for type-safe infrastructure configuration:
|
|
1537
|
+
The types narrow to what was declared:
|
|
1568
1538
|
|
|
1569
1539
|
```typescript
|
|
1570
|
-
import {
|
|
1540
|
+
import { constructs, type Construct, type Surfaces } from './.gkm/manifest/aws';
|
|
1571
1541
|
|
|
1572
|
-
|
|
1573
|
-
for (const route of manifest.routes) {
|
|
1574
|
-
console.log(`${route.method} ${route.path} -> ${route.handler}`);
|
|
1575
|
-
}
|
|
1542
|
+
const api: Construct<'Api'> = constructs.Api;
|
|
1576
1543
|
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
return manifest.routes.some((r) => r.method === method);
|
|
1544
|
+
for (const endpoint of api.endpoints) {
|
|
1545
|
+
console.log(`${endpoint.method} ${endpoint.path} -> ${endpoint.handler}`);
|
|
1580
1546
|
}
|
|
1581
1547
|
|
|
1582
|
-
//
|
|
1583
|
-
const authorizers = new Set(manifest.routes.map((r) => r.authorizer));
|
|
1548
|
+
const surface: Surfaces = 'Api'; // any other id is a type error
|
|
1584
1549
|
```
|
|
1585
1550
|
|
|
1586
1551
|
## OpenAPI Generation
|
|
@@ -1675,17 +1640,17 @@ provider:
|
|
|
1675
1640
|
|
|
1676
1641
|
functions:
|
|
1677
1642
|
getUsers:
|
|
1678
|
-
handler: .gkm/aws
|
|
1643
|
+
handler: .gkm/aws/routes/getUsers.handler
|
|
1679
1644
|
events:
|
|
1680
|
-
-
|
|
1681
|
-
path: users
|
|
1645
|
+
- httpApi:
|
|
1646
|
+
path: /users
|
|
1682
1647
|
method: get
|
|
1683
|
-
|
|
1648
|
+
|
|
1684
1649
|
createUser:
|
|
1685
|
-
handler: .gkm/aws
|
|
1650
|
+
handler: .gkm/aws/routes/createUser.handler
|
|
1686
1651
|
events:
|
|
1687
|
-
-
|
|
1688
|
-
path: users
|
|
1652
|
+
- httpApi:
|
|
1653
|
+
path: /users
|
|
1689
1654
|
method: post
|
|
1690
1655
|
```
|
|
1691
1656
|
|
|
@@ -1883,6 +1848,7 @@ Configure multiple patterns for complex project structures:
|
|
|
1883
1848
|
import { defineConfig } from '@geekmidas/cli/config';
|
|
1884
1849
|
|
|
1885
1850
|
export default defineConfig({
|
|
1851
|
+
stages: { local: 'dev', deployed: ['prod'] },
|
|
1886
1852
|
routes: [
|
|
1887
1853
|
'src/routes/**/*.ts',
|
|
1888
1854
|
'src/api/v1/**/*.ts',
|
|
@@ -1935,7 +1901,7 @@ Error: OpenAPI generation failed: Invalid endpoint schema
|
|
|
1935
1901
|
"dev": "gkm dev",
|
|
1936
1902
|
"dev:port": "gkm dev --port 8080",
|
|
1937
1903
|
"build": "gkm build",
|
|
1938
|
-
"build:lambda": "gkm build --provider aws
|
|
1904
|
+
"build:lambda": "gkm build --provider aws",
|
|
1939
1905
|
"build:server": "gkm build --provider server",
|
|
1940
1906
|
"docs": "gkm openapi --output src/api.ts"
|
|
1941
1907
|
}
|
|
@@ -2029,8 +1995,8 @@ DEBUG=gkm:* npx gkm build
|
|
|
2029
1995
|
### Types
|
|
2030
1996
|
|
|
2031
1997
|
```typescript
|
|
2032
|
-
//
|
|
2033
|
-
type Provider = '
|
|
1998
|
+
// Build targets
|
|
1999
|
+
type Provider = 'aws' | 'server';
|
|
2034
2000
|
|
|
2035
2001
|
// Runtime options
|
|
2036
2002
|
type Runtime = 'node' | 'bun';
|
|
@@ -2054,17 +2020,8 @@ interface DockerConfig {
|
|
|
2054
2020
|
imageName?: string; // Image name (defaults to package.json name)
|
|
2055
2021
|
baseImage?: string; // Base image (default: node:22-alpine)
|
|
2056
2022
|
port?: number; // Port to expose (default: 3000)
|
|
2057
|
-
compose?: {
|
|
2058
|
-
services?: ComposeServicesConfig | ComposeServiceName[];
|
|
2059
|
-
};
|
|
2060
2023
|
}
|
|
2061
2024
|
|
|
2062
|
-
// Service configuration for docker-compose
|
|
2063
|
-
type ComposeServiceName = 'postgres' | 'redis' | 'rabbitmq';
|
|
2064
|
-
type ComposeServicesConfig = {
|
|
2065
|
-
[K in ComposeServiceName]?: boolean | { version?: string };
|
|
2066
|
-
};
|
|
2067
|
-
|
|
2068
2025
|
// Telescope configuration
|
|
2069
2026
|
interface TelescopeConfig {
|
|
2070
2027
|
enabled?: boolean;
|
|
@@ -2077,7 +2034,7 @@ interface TelescopeConfig {
|
|
|
2077
2034
|
|
|
2078
2035
|
// Build options
|
|
2079
2036
|
interface BuildOptions {
|
|
2080
|
-
provider
|
|
2037
|
+
provider?: Provider; // default: where gkm.config.ts deploys
|
|
2081
2038
|
}
|
|
2082
2039
|
|
|
2083
2040
|
// Dev options
|