@geekmidas/cli 10.0.0-alpha.124 → 10.0.0-alpha.126
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/dist/{EndpointGenerator-B2MUa4M2.cjs → EndpointGenerator-BGxf9jWE.cjs} +8 -4
- package/dist/{EndpointGenerator-B2MUa4M2.cjs.map → EndpointGenerator-BGxf9jWE.cjs.map} +1 -1
- package/dist/{EndpointGenerator-Z_BUTocT.mjs → EndpointGenerator-errMeldx.mjs} +8 -4
- package/dist/{EndpointGenerator-Z_BUTocT.mjs.map → EndpointGenerator-errMeldx.mjs.map} +1 -1
- package/dist/{GoDaddyProvider-55x4o-4z.mjs → GoDaddyProvider-CvRVmN4W.mjs} +2 -2
- package/dist/{GoDaddyProvider-55x4o-4z.mjs.map → GoDaddyProvider-CvRVmN4W.mjs.map} +1 -1
- package/dist/{GoDaddyProvider-0z5RAN1k.cjs → GoDaddyProvider-DFfpzCOP.cjs} +2 -2
- package/dist/{GoDaddyProvider-0z5RAN1k.cjs.map → GoDaddyProvider-DFfpzCOP.cjs.map} +1 -1
- package/dist/{LegacyStateStore-DRpB-yC5.cjs → LegacyStateStore-BFrCHrFQ.cjs} +3 -3
- package/dist/{LegacyStateStore-DRpB-yC5.cjs.map → LegacyStateStore-BFrCHrFQ.cjs.map} +1 -1
- package/dist/{LegacyStateStore-C-vumKSN.mjs → LegacyStateStore-CgfENrXF.mjs} +3 -3
- package/dist/{LegacyStateStore-C-vumKSN.mjs.map → LegacyStateStore-CgfENrXF.mjs.map} +1 -1
- package/dist/{LocalStateStore-C3ummuDT.cjs → LocalStateStore-BU5z_IOE.cjs} +2 -2
- package/dist/{LocalStateStore-C3ummuDT.cjs.map → LocalStateStore-BU5z_IOE.cjs.map} +1 -1
- package/dist/{LocalStateStore-CtOjpV1w.mjs → LocalStateStore-DxoNpiBg.mjs} +2 -2
- package/dist/{LocalStateStore-CtOjpV1w.mjs.map → LocalStateStore-DxoNpiBg.mjs.map} +1 -1
- package/dist/{OpenApiTsGenerator-MtnMQL_g.mjs → OpenApiTsGenerator-W_HRXH1X.mjs} +2 -2
- package/dist/{OpenApiTsGenerator-MtnMQL_g.mjs.map → OpenApiTsGenerator-W_HRXH1X.mjs.map} +1 -1
- package/dist/{OpenApiTsGenerator-t3_E98Fi.cjs → OpenApiTsGenerator-cQgtxWQo.cjs} +2 -2
- package/dist/{OpenApiTsGenerator-t3_E98Fi.cjs.map → OpenApiTsGenerator-cQgtxWQo.cjs.map} +1 -1
- package/dist/{S3StateStore-BC4Jm3Tw.mjs → S3StateStore-CGMSDilh.mjs} +2 -2
- package/dist/{S3StateStore-BC4Jm3Tw.mjs.map → S3StateStore-CGMSDilh.mjs.map} +1 -1
- package/dist/{S3StateStore-BeArp0aF.cjs → S3StateStore-DiekMLpn.cjs} +2 -2
- package/dist/{S3StateStore-BeArp0aF.cjs.map → S3StateStore-DiekMLpn.cjs.map} +1 -1
- package/dist/{SSMStateStore-DcstR6cW.cjs → SSMStateStore-BDCOFdKq.cjs} +2 -2
- package/dist/{SSMStateStore-DcstR6cW.cjs.map → SSMStateStore-BDCOFdKq.cjs.map} +1 -1
- package/dist/{SSMStateStore-Crl76aYZ.mjs → SSMStateStore-Cq2H9MlF.mjs} +2 -2
- package/dist/{SSMStateStore-Crl76aYZ.mjs.map → SSMStateStore-Cq2H9MlF.mjs.map} +1 -1
- package/dist/{SubscriberGenerator-COAVPgM-.mjs → SubscriberGenerator-BALddfuW.mjs} +4 -62
- package/dist/SubscriberGenerator-BALddfuW.mjs.map +1 -0
- package/dist/{SubscriberGenerator-C3QTae-R.cjs → SubscriberGenerator-LgyTxZ8r.cjs} +3 -91
- package/dist/SubscriberGenerator-LgyTxZ8r.cjs.map +1 -0
- package/dist/{add-BFjb6mMq.cjs → add-BsiBYkAW.cjs} +6 -6
- package/dist/{add-BFjb6mMq.cjs.map → add-BsiBYkAW.cjs.map} +1 -1
- package/dist/{add-CIjmgzkb.mjs → add-CamA9Uqv.mjs} +6 -6
- package/dist/{add-CIjmgzkb.mjs.map → add-CamA9Uqv.mjs.map} +1 -1
- package/dist/{bundler-D6KFNpQk.mjs → bundler-2V2PR_E-.mjs} +5 -5
- package/dist/{bundler-D6KFNpQk.mjs.map → bundler-2V2PR_E-.mjs.map} +1 -1
- package/dist/{bundler-CiUoIsku.cjs → bundler-CijtdIZ2.cjs} +5 -5
- package/dist/{bundler-CiUoIsku.cjs.map → bundler-CijtdIZ2.cjs.map} +1 -1
- package/dist/{cli-r4eUr98C.cjs → cli-7gc1QG8X.cjs} +3 -3
- package/dist/{cli-r4eUr98C.cjs.map → cli-7gc1QG8X.cjs.map} +1 -1
- package/dist/{cli-DNtSTtMc.mjs → cli-PiyYqHGx.mjs} +3 -3
- package/dist/{cli-DNtSTtMc.mjs.map → cli-PiyYqHGx.mjs.map} +1 -1
- package/dist/{compose-BfXXWJSp.cjs → compose-8e2xJ61E.cjs} +236 -39
- package/dist/compose-8e2xJ61E.cjs.map +1 -0
- package/dist/{compose-DJvvmF3X.mjs → compose-CvHIjMDd.mjs} +235 -38
- package/dist/compose-CvHIjMDd.mjs.map +1 -0
- package/dist/{config-IgK6YaGp.d.cts → config-CdytFgSR.d.cts} +3 -3
- package/dist/{config-IgK6YaGp.d.cts.map → config-CdytFgSR.d.cts.map} +1 -1
- package/dist/{config-kE-p5hxq.d.mts → config-_y1FGBWR.d.mts} +3 -3
- package/dist/{config-kE-p5hxq.d.mts.map → config-_y1FGBWR.d.mts.map} +1 -1
- package/dist/config.cjs +2 -2
- package/dist/config.d.cts +3 -3
- package/dist/config.d.mts +3 -3
- package/dist/config.mjs +2 -2
- package/dist/{credentialSchemas-AhIBuQxQ.cjs → credentialSchemas-DFxvGEwa.cjs} +2 -2
- package/dist/{credentialSchemas-AhIBuQxQ.cjs.map → credentialSchemas-DFxvGEwa.cjs.map} +1 -1
- package/dist/{credentialSchemas-DLKbxYBy.mjs → credentialSchemas-DaMpt-Dx.mjs} +2 -2
- package/dist/{credentialSchemas-DLKbxYBy.mjs.map → credentialSchemas-DaMpt-Dx.mjs.map} +1 -1
- package/dist/{databases-BPOgTn1u.mjs → databases-6GD0tI2F.mjs} +65 -3
- package/dist/databases-6GD0tI2F.mjs.map +1 -0
- package/dist/{databases-fOaoBInm.cjs → databases-CuVGf7-M.cjs} +75 -1
- package/dist/databases-CuVGf7-M.cjs.map +1 -0
- package/dist/deploy/public.cjs +8 -8
- package/dist/deploy/public.d.cts +3 -3
- package/dist/deploy/public.d.cts.map +1 -1
- package/dist/deploy/public.d.mts +3 -3
- package/dist/deploy/public.d.mts.map +1 -1
- package/dist/deploy/public.mjs +8 -8
- package/dist/{deploy-CiRYwFmr.mjs → deploy-CIPwTJ47.mjs} +797 -25
- package/dist/deploy-CIPwTJ47.mjs.map +1 -0
- package/dist/{deploy-BbI1UMh3.cjs → deploy-wSlIRPn5.cjs} +796 -24
- package/dist/deploy-wSlIRPn5.cjs.map +1 -0
- package/dist/{discover-BvJOVsYG.mjs → discover-CzGM5P3p.mjs} +71 -1
- package/dist/discover-CzGM5P3p.mjs.map +1 -0
- package/dist/{discover-ojkcbxHw.cjs → discover-DL6h-J97.cjs} +71 -1
- package/dist/discover-DL6h-J97.cjs.map +1 -0
- package/dist/{dokploy-C0aQrCgs.cjs → dokploy-BKbUrz05.cjs} +2 -2
- package/dist/{dokploy-C0aQrCgs.cjs.map → dokploy-BKbUrz05.cjs.map} +1 -1
- package/dist/{dokploy-MM7c3IE0.mjs → dokploy-BZf1AHd0.mjs} +2 -2
- package/dist/{dokploy-MM7c3IE0.mjs.map → dokploy-BZf1AHd0.mjs.map} +1 -1
- package/dist/{drivers-CQ32PB5w.cjs → drivers-C47nm-wB.cjs} +91 -4
- package/dist/drivers-C47nm-wB.cjs.map +1 -0
- package/dist/{drivers-Chb5Akov.mjs → drivers-CDjpjakg.mjs} +60 -3
- package/dist/drivers-CDjpjakg.mjs.map +1 -0
- package/dist/{eas-1Ee6kql0.mjs → eas-CxX2RCE_.mjs} +2 -2
- package/dist/{eas-1Ee6kql0.mjs.map → eas-CxX2RCE_.mjs.map} +1 -1
- package/dist/{eas-CJoys9yh.cjs → eas-DzDMGzfc.cjs} +2 -2
- package/dist/{eas-CJoys9yh.cjs.map → eas-DzDMGzfc.cjs.map} +1 -1
- package/dist/{emit-qvHxMV9b.cjs → emit-CYloptRS.cjs} +18 -1
- package/dist/emit-CYloptRS.cjs.map +1 -0
- package/dist/{emit-CNpuV_6Q.mjs → emit-CiJGdy_f.mjs} +18 -1
- package/dist/emit-CiJGdy_f.mjs.map +1 -0
- package/dist/{encryption-B8Bk1Mvu.mjs → encryption-BFSrt89F.mjs} +3 -3
- package/dist/{encryption-B8Bk1Mvu.mjs.map → encryption-BFSrt89F.mjs.map} +1 -1
- package/dist/{encryption-Bo9VlRnl.cjs → encryption-RNcBnG4Z.cjs} +3 -3
- package/dist/{encryption-Bo9VlRnl.cjs.map → encryption-RNcBnG4Z.cjs.map} +1 -1
- package/dist/{engine-esxTxcIx.cjs → engine-Dqe9KQCm.cjs} +142 -15
- package/dist/engine-Dqe9KQCm.cjs.map +1 -0
- package/dist/{engine-BuinpJfS.mjs → engine-_0pjyCd_.mjs} +142 -15
- package/dist/engine-_0pjyCd_.mjs.map +1 -0
- package/dist/{github-BEA4K3_X.cjs → github-Csev5EFf.cjs} +41 -6
- package/dist/github-Csev5EFf.cjs.map +1 -0
- package/dist/{github-BUlKJfOV.mjs → github-Dck0nLW9.mjs} +41 -6
- package/dist/github-Dck0nLW9.mjs.map +1 -0
- package/dist/{googlePlay-CiqAS2ma.cjs → googlePlay-DBtDAGBk.cjs} +3 -3
- package/dist/{googlePlay-CiqAS2ma.cjs.map → googlePlay-DBtDAGBk.cjs.map} +1 -1
- package/dist/{googlePlay-CK05QiTq.mjs → googlePlay-DTuvDHi5.mjs} +3 -3
- package/dist/{googlePlay-CK05QiTq.mjs.map → googlePlay-DTuvDHi5.mjs.map} +1 -1
- package/dist/{index-DhUf0B0m.d.mts → index-DrkV7N5w.d.mts} +2 -2
- package/dist/{index-4CO0HD27.d.cts.map → index-DrkV7N5w.d.mts.map} +1 -1
- package/dist/{index-4CO0HD27.d.cts → index-yaXZ9m-J.d.cts} +2 -2
- package/dist/{index-DhUf0B0m.d.mts.map → index-yaXZ9m-J.d.cts.map} +1 -1
- package/dist/index.cjs +150 -67
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +149 -66
- package/dist/index.mjs.map +1 -1
- package/dist/{migrate-C-hmbjpG.cjs → migrate-3ZEoqx5q.cjs} +3 -3
- package/dist/{migrate-C-hmbjpG.cjs.map → migrate-3ZEoqx5q.cjs.map} +1 -1
- package/dist/{migrate-BzCHT9qs.mjs → migrate-BABIuzQj.mjs} +3 -3
- package/dist/{migrate-BzCHT9qs.mjs.map → migrate-BABIuzQj.mjs.map} +1 -1
- package/dist/{migrate-CnbvrVag.mjs → migrate-DZeNpuX2.mjs} +8 -6
- package/dist/migrate-DZeNpuX2.mjs.map +1 -0
- package/dist/{migrate-DeQJBexh.cjs → migrate-pGiUqvBi.cjs} +8 -6
- package/dist/migrate-pGiUqvBi.cjs.map +1 -0
- package/dist/openapi.cjs +3 -3
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/openapi.mjs +3 -3
- package/dist/{publish-BISBrrqR.mjs → publish-BsnDeOVL.mjs} +2 -2
- package/dist/{publish-BISBrrqR.mjs.map → publish-BsnDeOVL.mjs.map} +1 -1
- package/dist/{publish-DtSIB-hZ.cjs → publish-CS6xDvGT.cjs} +2 -2
- package/dist/{publish-DtSIB-hZ.cjs.map → publish-CS6xDvGT.cjs.map} +1 -1
- package/dist/{ready-IVGu-q18.cjs → ready-CxPJm0Hc.cjs} +6 -6
- package/dist/{ready-IVGu-q18.cjs.map → ready-CxPJm0Hc.cjs.map} +1 -1
- package/dist/{ready-DqsyadOs.mjs → ready-DrvaAwKv.mjs} +6 -6
- package/dist/{ready-DqsyadOs.mjs.map → ready-DrvaAwKv.mjs.map} +1 -1
- package/dist/reconcile/public.cjs +2 -2
- package/dist/reconcile/public.d.cts +1 -1
- package/dist/reconcile/public.d.cts.map +1 -1
- package/dist/reconcile/public.d.mts +1 -1
- package/dist/reconcile/public.d.mts.map +1 -1
- package/dist/reconcile/public.mjs +2 -2
- package/dist/{resolve-BT7fkPN5.mjs → resolve-fCGJmM-R.mjs} +3 -3
- package/dist/{resolve-BT7fkPN5.mjs.map → resolve-fCGJmM-R.mjs.map} +1 -1
- package/dist/{resolve-C7GKQcE4.cjs → resolve-zqCMFio0.cjs} +3 -3
- package/dist/{resolve-C7GKQcE4.cjs.map → resolve-zqCMFio0.cjs.map} +1 -1
- package/dist/{rollback-DbP0KuDw.mjs → rollback-BkhVrtAf.mjs} +5 -5
- package/dist/{rollback-DbP0KuDw.mjs.map → rollback-BkhVrtAf.mjs.map} +1 -1
- package/dist/{rollback-BEiB-Pje.cjs → rollback-qc79mj6L.cjs} +5 -5
- package/dist/{rollback-BEiB-Pje.cjs.map → rollback-qc79mj6L.cjs.map} +1 -1
- package/dist/{runtime-BFJQNqwd.d.mts → runtime-DCkfI2E7.d.mts} +2 -2
- package/dist/{runtime-BFJQNqwd.d.mts.map → runtime-DCkfI2E7.d.mts.map} +1 -1
- package/dist/{runtime-BJO-FFef.d.cts → runtime-Ie4znWIB.d.cts} +2 -2
- package/dist/{runtime-BJO-FFef.d.cts.map → runtime-Ie4znWIB.d.cts.map} +1 -1
- package/dist/{s3-B4FTQQkV.mjs → s3-BZzSnker.mjs} +2 -2
- package/dist/{s3-B4FTQQkV.mjs.map → s3-BZzSnker.mjs.map} +1 -1
- package/dist/{s3-DwKLXwUT.cjs → s3-pqgmCTOq.cjs} +2 -2
- package/dist/{s3-DwKLXwUT.cjs.map → s3-pqgmCTOq.cjs.map} +1 -1
- package/dist/sandbox/credentials-worker.cjs +2 -2
- package/dist/sandbox/credentials-worker.mjs +2 -2
- package/dist/sandbox/discover-worker.cjs +1 -1
- package/dist/sandbox/discover-worker.mjs +1 -1
- package/dist/sandbox/migrate-worker.cjs +5 -4
- package/dist/sandbox/migrate-worker.cjs.map +1 -1
- package/dist/sandbox/migrate-worker.mjs +5 -4
- package/dist/sandbox/migrate-worker.mjs.map +1 -1
- package/dist/{seeds-DOfxmDRO.cjs → seeds-3awh33Wz.cjs} +607 -45
- package/dist/seeds-3awh33Wz.cjs.map +1 -0
- package/dist/{seeds-rG-Evfz9.mjs → seeds-Cfejy8wj.mjs} +517 -39
- package/dist/seeds-Cfejy8wj.mjs.map +1 -0
- package/dist/{serverSetup-CWWVcU6Y.cjs → serverSetup-BFQuwUeL.cjs} +6 -6
- package/dist/{serverSetup-CWWVcU6Y.cjs.map → serverSetup-BFQuwUeL.cjs.map} +1 -1
- package/dist/{serverSetup-xGw1fxuZ.mjs → serverSetup-C8ZbHTm_.mjs} +6 -6
- package/dist/{serverSetup-xGw1fxuZ.mjs.map → serverSetup-C8ZbHTm_.mjs.map} +1 -1
- package/dist/{sniffer-DVPgfyHr.mjs → sniffer-CCkdzjiU.mjs} +8 -8
- package/dist/{sniffer-DVPgfyHr.mjs.map → sniffer-CCkdzjiU.mjs.map} +1 -1
- package/dist/{sniffer-C7O9Pna_.cjs → sniffer-Cq1nhxIB.cjs} +8 -8
- package/dist/{sniffer-C7O9Pna_.cjs.map → sniffer-Cq1nhxIB.cjs.map} +1 -1
- package/dist/{snsSubscriptions-CSkteK2J.cjs → snsSubscriptions-DYyYP0Xf.cjs} +15 -3
- package/dist/snsSubscriptions-DYyYP0Xf.cjs.map +1 -0
- package/dist/{snsSubscriptions-CvBIGGp0.mjs → snsSubscriptions-R_AKBZYK.mjs} +4 -4
- package/dist/snsSubscriptions-R_AKBZYK.mjs.map +1 -0
- package/dist/{stage-fRfFtLwj.cjs → stage-BkgbVJ9Z.cjs} +6 -6
- package/dist/{stage-fRfFtLwj.cjs.map → stage-BkgbVJ9Z.cjs.map} +1 -1
- package/dist/{stage-2EKpzPQ1.mjs → stage-DCaxqm-G.mjs} +6 -6
- package/dist/{stage-2EKpzPQ1.mjs.map → stage-DCaxqm-G.mjs.map} +1 -1
- package/dist/{stages-B7mCWI_R.cjs → stages-3yUZaZeA.cjs} +2 -2
- package/dist/{stages-B7mCWI_R.cjs.map → stages-3yUZaZeA.cjs.map} +1 -1
- package/dist/{stages-DSltTW2d.mjs → stages-DTTv0NZW.mjs} +2 -2
- package/dist/{stages-DSltTW2d.mjs.map → stages-DTTv0NZW.mjs.map} +1 -1
- package/dist/target/public.cjs +1 -1
- package/dist/target/public.d.cts +2 -2
- package/dist/target/public.d.mts +2 -2
- package/dist/target/public.mjs +1 -1
- package/dist/{terminal-D1aeTkgv.cjs → terminal-PKhPAajN.cjs} +2 -2
- package/dist/{terminal-D1aeTkgv.cjs.map → terminal-PKhPAajN.cjs.map} +1 -1
- package/dist/{terminal-BAVrDhhN.mjs → terminal-bqY33lpN.mjs} +2 -2
- package/dist/{terminal-BAVrDhhN.mjs.map → terminal-bqY33lpN.mjs.map} +1 -1
- package/dist/{types-CFU2uvrz.d.cts → types-Bmjs4jZV.d.mts} +8 -2
- package/dist/{types-D3BeGucy.d.mts.map → types-Bmjs4jZV.d.mts.map} +1 -1
- package/dist/{types-D3BeGucy.d.mts → types-D0IsQxES.d.cts} +9 -1
- package/dist/{types-CFU2uvrz.d.cts.map → types-D0IsQxES.d.cts.map} +1 -1
- package/dist/vitest.cjs +1 -1
- package/dist/vitest.mjs +1 -1
- package/dist/workspace/index.cjs +1 -1
- package/dist/workspace/index.d.cts +2 -2
- package/dist/workspace/index.d.mts +2 -2
- package/dist/workspace/index.mjs +1 -1
- package/dist/{workspace-DUnnVjqC.mjs → workspace-DBHF9Gba.mjs} +5 -3
- package/dist/workspace-DBHF9Gba.mjs.map +1 -0
- package/dist/{workspace-C82GLPnf.cjs → workspace-Du4Afb03.cjs} +5 -3
- package/dist/workspace-Du4Afb03.cjs.map +1 -0
- package/package.json +17 -15
- package/dist/SubscriberGenerator-C3QTae-R.cjs.map +0 -1
- package/dist/SubscriberGenerator-COAVPgM-.mjs.map +0 -1
- package/dist/compose-BfXXWJSp.cjs.map +0 -1
- package/dist/compose-DJvvmF3X.mjs.map +0 -1
- package/dist/databases-BPOgTn1u.mjs.map +0 -1
- package/dist/databases-fOaoBInm.cjs.map +0 -1
- package/dist/deploy-BbI1UMh3.cjs.map +0 -1
- package/dist/deploy-CiRYwFmr.mjs.map +0 -1
- package/dist/discover-BvJOVsYG.mjs.map +0 -1
- package/dist/discover-ojkcbxHw.cjs.map +0 -1
- package/dist/drivers-CQ32PB5w.cjs.map +0 -1
- package/dist/drivers-Chb5Akov.mjs.map +0 -1
- package/dist/emit-CNpuV_6Q.mjs.map +0 -1
- package/dist/emit-qvHxMV9b.cjs.map +0 -1
- package/dist/engine-BuinpJfS.mjs.map +0 -1
- package/dist/engine-esxTxcIx.cjs.map +0 -1
- package/dist/github-BEA4K3_X.cjs.map +0 -1
- package/dist/github-BUlKJfOV.mjs.map +0 -1
- package/dist/migrate-CnbvrVag.mjs.map +0 -1
- package/dist/migrate-DeQJBexh.cjs.map +0 -1
- package/dist/seeds-DOfxmDRO.cjs.map +0 -1
- package/dist/seeds-rG-Evfz9.mjs.map +0 -1
- package/dist/snsSubscriptions-CSkteK2J.cjs.map +0 -1
- package/dist/snsSubscriptions-CvBIGGp0.mjs.map +0 -1
- package/dist/workspace-C82GLPnf.cjs.map +0 -1
- package/dist/workspace-DUnnVjqC.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Lt as Sandbox, Wt as GkmError, b as NormalizedAppConfig, r as GkmConfig, v as LoadedConfig, x as NormalizedWorkspace } from "./types-
|
|
2
|
-
import "./index-
|
|
1
|
+
import { Lt as Sandbox, Wt as GkmError, b as NormalizedAppConfig, r as GkmConfig, v as LoadedConfig, x as NormalizedWorkspace } from "./types-D0IsQxES.cjs";
|
|
2
|
+
import "./index-yaXZ9m-J.cjs";
|
|
3
3
|
import { ConstructManifest } from "@geekmidas/manifest";
|
|
4
4
|
//#region src/dev/discovery.d.ts
|
|
5
5
|
/** Where an app is in its life. `stopped` is a server that exited on its own. */
|
|
@@ -265,4 +265,4 @@ interface WorkspaceAppInfo {
|
|
|
265
265
|
declare function loadWorkspaceAppInfo(cwd?: string): Promise<WorkspaceAppInfo>;
|
|
266
266
|
//#endregion
|
|
267
267
|
export { DiscoveredApp as C, DiscoveryResponse as D, DiscoveryEvent as E, DataApiKind as S, DiscoveredWorkspace as T, loadWorkspaceAppInfo as _, ConfigNotFound as a, parseModuleConfig as b, NotABackendApp as c, WorkspaceAppInfo as d, WorkspaceDeclaresNoConstructs as f, loadConfig as g, loadAppConfig as h, ConfigLoadFailed as i, NotInAnApp as l, findWorkspaceRoot as m, CONFIG_LOAD_TIMEOUT_MS as n, ConfigObjectNotSerializable as o, defineConfig as p, ConfigDiscoveryResult as r, LoadConfigOptions as s, AppConfigResult as t, ParsedModuleConfig as u, loadWorkspaceConfig as v, DiscoveredDataApi as w, AppStatus as x, loadWorkspaceSettings as y };
|
|
268
|
-
//# sourceMappingURL=config-
|
|
268
|
+
//# sourceMappingURL=config-CdytFgSR.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-
|
|
1
|
+
{"version":3,"file":"config-CdytFgSR.d.cts","names":[],"sources":["../src/dev/discovery.ts","../src/config.ts"],"mappings":";;;;;KAqFY;;KAGA;;;;;;UAyBK;;EAEhB;;EAEA;;UA8BgB;EAChB,MAAM;;EAEN;;EAEA;;EAEA;;UAGgB;EAChB;EACA;EACA;;EAEA;EACA;EACA,QAAQ;EACR;;EAEA;EACA,UAAU;;UAGM;;EAEhB;EACA;EACA;EACA;EACA,UAAU;;EAEV,WAAW;EACX,MAAM;;;UAIU;EAChB;;EAEA;IAAQ;IAAa;;;EAErB;EACA,YAAY;;;KAID;EACP;EAAkB,UAAU;;EAC5B;EAAiD;;EAEnD;EACA;EACA,KAAK;;;;;;;;;;;;;;;;;;;;;iBCpJQ,aAAa,QAAQ,YAAY;UAIhC;EAChB;EACA;;;;;;;;;;;;;;;;;;;iBAoBe,kBACf,sBACA,uBACE;UAac;EAChB;EACA;;;;;;;;iBAgDe,kBAAkB;;cAKrB,uBAAuB;WACd;EAArB,YAAqB;;UAaL;;;;;;;;EAQhB,UAAU;;;;;EAKV;;;;;;;cAQY;;cAGA,yBAAyB;WAE3B;WACA;EAFV,YACU,oBACA;;;;;;;cAYE,oCAAoC;WAEtC;WACA;EAFV,YACU,oBACA;;;;;;;;iBA0GW,WACrB,eACE,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuCW,sBACrB,cACA,UAAS,oBACP,QAAQ;iBAKW,oBACrB,cACA,UAAS,oBACP,QAAQ;;;;;;;;cAmEE,sCAAsC;WAC7B;EAArB,YAAqB;;UAWL;EAChB;EACA,KAAK;EACL,WAAW;EACX,WAAW;EACX;EACA;;;cAqCY,mBAAmB;WAErB;WACA,MAAM,SAAS;EAFzB,YACU,aACA,MAAM,SAAS;;;;;;;;;;;;;;;iBAoCJ,cACrB,eACE,QAAQ;;cAkBE,uBAAuB;WACd;EAArB,YAAqB;;UAQL;;EAEhB;EACA,KAAK;EACL,WAAW;EACX;;;;;;;;;iBAUqB,qBACrB,eACE,QAAQ"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Lt as Sandbox, Wt as GkmError, b as NormalizedAppConfig, r as GkmConfig, v as LoadedConfig, x as NormalizedWorkspace } from "./types-
|
|
2
|
-
import "./index-
|
|
1
|
+
import { Lt as Sandbox, Wt as GkmError, b as NormalizedAppConfig, r as GkmConfig, v as LoadedConfig, x as NormalizedWorkspace } from "./types-Bmjs4jZV.mjs";
|
|
2
|
+
import "./index-DrkV7N5w.mjs";
|
|
3
3
|
import { ConstructManifest } from "@geekmidas/manifest";
|
|
4
4
|
//#region src/dev/discovery.d.ts
|
|
5
5
|
/** Where an app is in its life. `stopped` is a server that exited on its own. */
|
|
@@ -265,4 +265,4 @@ interface WorkspaceAppInfo {
|
|
|
265
265
|
declare function loadWorkspaceAppInfo(cwd?: string): Promise<WorkspaceAppInfo>;
|
|
266
266
|
//#endregion
|
|
267
267
|
export { DiscoveredApp as C, DiscoveryResponse as D, DiscoveryEvent as E, DataApiKind as S, DiscoveredWorkspace as T, loadWorkspaceAppInfo as _, ConfigNotFound as a, parseModuleConfig as b, NotABackendApp as c, WorkspaceAppInfo as d, WorkspaceDeclaresNoConstructs as f, loadConfig as g, loadAppConfig as h, ConfigLoadFailed as i, NotInAnApp as l, findWorkspaceRoot as m, CONFIG_LOAD_TIMEOUT_MS as n, ConfigObjectNotSerializable as o, defineConfig as p, ConfigDiscoveryResult as r, LoadConfigOptions as s, AppConfigResult as t, ParsedModuleConfig as u, loadWorkspaceConfig as v, DiscoveredDataApi as w, AppStatus as x, loadWorkspaceSettings as y };
|
|
268
|
-
//# sourceMappingURL=config-
|
|
268
|
+
//# sourceMappingURL=config-_y1FGBWR.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-
|
|
1
|
+
{"version":3,"file":"config-_y1FGBWR.d.mts","names":[],"sources":["../src/dev/discovery.ts","../src/config.ts"],"mappings":";;;;;KAqFY;;KAGA;;;;;;UAyBK;;EAEhB;;EAEA;;UA8BgB;EAChB,MAAM;;EAEN;;EAEA;;EAEA;;UAGgB;EAChB;EACA;EACA;;EAEA;EACA;EACA,QAAQ;EACR;;EAEA;EACA,UAAU;;UAGM;;EAEhB;EACA;EACA;EACA;EACA,UAAU;;EAEV,WAAW;EACX,MAAM;;;UAIU;EAChB;;EAEA;IAAQ;IAAa;;;EAErB;EACA,YAAY;;;KAID;EACP;EAAkB,UAAU;;EAC5B;EAAiD;;EAEnD;EACA;EACA,KAAK;;;;;;;;;;;;;;;;;;;;;iBCpJQ,aAAa,QAAQ,YAAY;UAIhC;EAChB;EACA;;;;;;;;;;;;;;;;;;;iBAoBe,kBACf,sBACA,uBACE;UAac;EAChB;EACA;;;;;;;;iBAgDe,kBAAkB;;cAKrB,uBAAuB;WACd;EAArB,YAAqB;;UAaL;;;;;;;;EAQhB,UAAU;;;;;EAKV;;;;;;;cAQY;;cAGA,yBAAyB;WAE3B;WACA;EAFV,YACU,oBACA;;;;;;;cAYE,oCAAoC;WAEtC;WACA;EAFV,YACU,oBACA;;;;;;;;iBA0GW,WACrB,eACE,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuCW,sBACrB,cACA,UAAS,oBACP,QAAQ;iBAKW,oBACrB,cACA,UAAS,oBACP,QAAQ;;;;;;;;cAmEE,sCAAsC;WAC7B;EAArB,YAAqB;;UAWL;EAChB;EACA,KAAK;EACL,WAAW;EACX,WAAW;EACX;EACA;;;cAqCY,mBAAmB;WAErB;WACA,MAAM,SAAS;EAFzB,YACU,aACA,MAAM,SAAS;;;;;;;;;;;;;;;iBAoCJ,cACrB,eACE,QAAQ;;cAkBE,uBAAuB;WACd;EAArB,YAAqB;;UAQL;;EAEhB;EACA,KAAK;EACL,WAAW;EACX;;;;;;;;;iBAUqB,qBACrB,eACE,QAAQ"}
|
package/dist/config.cjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_errors = require("./errors-DMC4Umsb.cjs");
|
|
3
|
-
const require_workspace = require("./workspace-
|
|
3
|
+
const require_workspace = require("./workspace-Du4Afb03.cjs");
|
|
4
4
|
const require_schemas = require("./schemas-BQ_v0lEX.cjs");
|
|
5
5
|
const require_derive = require("./derive-DAbo49sm.cjs");
|
|
6
|
-
const require_discover = require("./discover-
|
|
6
|
+
const require_discover = require("./discover-DL6h-J97.cjs");
|
|
7
7
|
const require_sandbox = require("./sandbox-CHv3OYXg.cjs");
|
|
8
8
|
let node_path = require("node:path");
|
|
9
9
|
let node_fs = require("node:fs");
|
package/dist/config.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as WorkspaceConfig, m as DevConfig, r as GkmConfig, v as LoadedConfig } from "./types-
|
|
2
|
-
import { l as defineWorkspace } from "./index-
|
|
3
|
-
import { C as DiscoveredApp, D as DiscoveryResponse, E as DiscoveryEvent, S as DataApiKind, T as DiscoveredWorkspace, _ as loadWorkspaceAppInfo, a as ConfigNotFound, b as parseModuleConfig, c as NotABackendApp, d as WorkspaceAppInfo, f as WorkspaceDeclaresNoConstructs, g as loadConfig, h as loadAppConfig, i as ConfigLoadFailed, l as NotInAnApp, m as findWorkspaceRoot, n as CONFIG_LOAD_TIMEOUT_MS, o as ConfigObjectNotSerializable, p as defineConfig, r as ConfigDiscoveryResult, s as LoadConfigOptions, t as AppConfigResult, u as ParsedModuleConfig, v as loadWorkspaceConfig, w as DiscoveredDataApi, x as AppStatus, y as loadWorkspaceSettings } from "./config-
|
|
1
|
+
import { D as WorkspaceConfig, m as DevConfig, r as GkmConfig, v as LoadedConfig } from "./types-D0IsQxES.cjs";
|
|
2
|
+
import { l as defineWorkspace } from "./index-yaXZ9m-J.cjs";
|
|
3
|
+
import { C as DiscoveredApp, D as DiscoveryResponse, E as DiscoveryEvent, S as DataApiKind, T as DiscoveredWorkspace, _ as loadWorkspaceAppInfo, a as ConfigNotFound, b as parseModuleConfig, c as NotABackendApp, d as WorkspaceAppInfo, f as WorkspaceDeclaresNoConstructs, g as loadConfig, h as loadAppConfig, i as ConfigLoadFailed, l as NotInAnApp, m as findWorkspaceRoot, n as CONFIG_LOAD_TIMEOUT_MS, o as ConfigObjectNotSerializable, p as defineConfig, r as ConfigDiscoveryResult, s as LoadConfigOptions, t as AppConfigResult, u as ParsedModuleConfig, v as loadWorkspaceConfig, w as DiscoveredDataApi, x as AppStatus, y as loadWorkspaceSettings } from "./config-CdytFgSR.cjs";
|
|
4
4
|
export { AppConfigResult, type AppStatus, CONFIG_LOAD_TIMEOUT_MS, ConfigDiscoveryResult, ConfigLoadFailed, ConfigNotFound, ConfigObjectNotSerializable, type DataApiKind, type DevConfig, type DiscoveredApp, type DiscoveredDataApi, type DiscoveredWorkspace, type DiscoveryEvent, type DiscoveryResponse, type GkmConfig, LoadConfigOptions, type LoadedConfig, NotABackendApp, NotInAnApp, ParsedModuleConfig, WorkspaceAppInfo, type WorkspaceConfig, WorkspaceDeclaresNoConstructs, defineConfig, defineWorkspace, findWorkspaceRoot, loadAppConfig, loadConfig, loadWorkspaceAppInfo, loadWorkspaceConfig, loadWorkspaceSettings, parseModuleConfig };
|
package/dist/config.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as WorkspaceConfig, m as DevConfig, r as GkmConfig, v as LoadedConfig } from "./types-
|
|
2
|
-
import { l as defineWorkspace } from "./index-
|
|
3
|
-
import { C as DiscoveredApp, D as DiscoveryResponse, E as DiscoveryEvent, S as DataApiKind, T as DiscoveredWorkspace, _ as loadWorkspaceAppInfo, a as ConfigNotFound, b as parseModuleConfig, c as NotABackendApp, d as WorkspaceAppInfo, f as WorkspaceDeclaresNoConstructs, g as loadConfig, h as loadAppConfig, i as ConfigLoadFailed, l as NotInAnApp, m as findWorkspaceRoot, n as CONFIG_LOAD_TIMEOUT_MS, o as ConfigObjectNotSerializable, p as defineConfig, r as ConfigDiscoveryResult, s as LoadConfigOptions, t as AppConfigResult, u as ParsedModuleConfig, v as loadWorkspaceConfig, w as DiscoveredDataApi, x as AppStatus, y as loadWorkspaceSettings } from "./config-
|
|
1
|
+
import { D as WorkspaceConfig, m as DevConfig, r as GkmConfig, v as LoadedConfig } from "./types-Bmjs4jZV.mjs";
|
|
2
|
+
import { l as defineWorkspace } from "./index-DrkV7N5w.mjs";
|
|
3
|
+
import { C as DiscoveredApp, D as DiscoveryResponse, E as DiscoveryEvent, S as DataApiKind, T as DiscoveredWorkspace, _ as loadWorkspaceAppInfo, a as ConfigNotFound, b as parseModuleConfig, c as NotABackendApp, d as WorkspaceAppInfo, f as WorkspaceDeclaresNoConstructs, g as loadConfig, h as loadAppConfig, i as ConfigLoadFailed, l as NotInAnApp, m as findWorkspaceRoot, n as CONFIG_LOAD_TIMEOUT_MS, o as ConfigObjectNotSerializable, p as defineConfig, r as ConfigDiscoveryResult, s as LoadConfigOptions, t as AppConfigResult, u as ParsedModuleConfig, v as loadWorkspaceConfig, w as DiscoveredDataApi, x as AppStatus, y as loadWorkspaceSettings } from "./config-_y1FGBWR.mjs";
|
|
4
4
|
export { AppConfigResult, type AppStatus, CONFIG_LOAD_TIMEOUT_MS, ConfigDiscoveryResult, ConfigLoadFailed, ConfigNotFound, ConfigObjectNotSerializable, type DataApiKind, type DevConfig, type DiscoveredApp, type DiscoveredDataApi, type DiscoveredWorkspace, type DiscoveryEvent, type DiscoveryResponse, type GkmConfig, LoadConfigOptions, type LoadedConfig, NotABackendApp, NotInAnApp, ParsedModuleConfig, WorkspaceAppInfo, type WorkspaceConfig, WorkspaceDeclaresNoConstructs, defineConfig, defineWorkspace, findWorkspaceRoot, loadAppConfig, loadConfig, loadWorkspaceAppInfo, loadWorkspaceConfig, loadWorkspaceSettings, parseModuleConfig };
|
package/dist/config.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { t as GkmError } from "./errors-D8Gwp5kU.mjs";
|
|
2
|
-
import { a as allConstructGlobs, b as isWorkspaceConfig, d as getAppGkmConfig, l as defineWorkspace, m as processConfig } from "./workspace-
|
|
2
|
+
import { a as allConstructGlobs, b as isWorkspaceConfig, d as getAppGkmConfig, l as defineWorkspace, m as processConfig } from "./workspace-DBHF9Gba.mjs";
|
|
3
3
|
import { a as discriminatedUnion, c as literal, d as object, f as record, g as unknown, n as array, p as string } from "./schemas-BCwKKA42.mjs";
|
|
4
4
|
import { n as derivedApps } from "./derive-B4vDpzgP.mjs";
|
|
5
|
-
import { f as output, i as discover, l as runWorker } from "./discover-
|
|
5
|
+
import { f as output, i as discover, l as runWorker } from "./discover-CzGM5P3p.mjs";
|
|
6
6
|
import { i as activeSandbox } from "./sandbox-CbVB7uOD.mjs";
|
|
7
7
|
import { dirname, join, parse, resolve, sep } from "node:path";
|
|
8
8
|
import { existsSync, realpathSync } from "node:fs";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const require_errors = require("./errors-DMC4Umsb.cjs");
|
|
2
2
|
const require_schemas = require("./schemas-BQ_v0lEX.cjs");
|
|
3
|
-
const require_discover = require("./discover-
|
|
3
|
+
const require_discover = require("./discover-DL6h-J97.cjs");
|
|
4
4
|
const require_sandbox = require("./sandbox-CHv3OYXg.cjs");
|
|
5
5
|
let _geekmidas_manifest = require("@geekmidas/manifest");
|
|
6
6
|
let _geekmidas_constructs_credential = require("@geekmidas/constructs/credential");
|
|
@@ -269,4 +269,4 @@ Object.defineProperty(exports, "loadCredentialSchemas", {
|
|
|
269
269
|
}
|
|
270
270
|
});
|
|
271
271
|
|
|
272
|
-
//# sourceMappingURL=credentialSchemas-
|
|
272
|
+
//# sourceMappingURL=credentialSchemas-DFxvGEwa.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credentialSchemas-AhIBuQxQ.cjs","names":["provideKey","decodeCredentials","activeSandbox","runWorker","ConstructDiscoveryFailed","discover","GkmError"],"sources":["../src/secrets/credentialSchemas.ts"],"sourcesContent":["/**\n * A third party's credentials, checked against the schema of the construct\n * that reads them — before they are stored, and before a deploy builds\n * anything with them.\n *\n * The schema lives on the construct (`ExternalApi.credentialsSchema`,\n * `Credential.credentialsSchema`), which is the project's code. So the\n * constructs are loaded where a deploy loads them: in the run's sandbox when\n * there is one, here otherwise. What comes back is data only — each schema as\n * JSON Schema where it can say so, and `{ ok, issues }` for each value asked\n * about — because a live schema cannot cross an isolating sandbox. A value\n * asked about goes in as a secret file, never an argument, and no issue\n * carries it back: an issue is a path and a message.\n */\n\nimport { decodeCredentials } from '@geekmidas/constructs/credential';\nimport { type ConstructManifest, provideKey } from '@geekmidas/manifest';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { z } from 'zod';\nimport { GkmError } from '../errors';\nimport {\n\tConstructDiscoveryFailed,\n\ttype ConstructSource,\n\tdiscover,\n} from '../reconcile/discover';\nimport { activeSandbox } from '../sandbox/sandbox';\nimport { runWorker } from '../sandbox/worker';\n\n/** One thing a schema refused: where in the value, and why. */\nexport interface CredentialIssue {\n\t/** Dotted, from the value's root — `apiKey`, `keys.0`; empty for the root. */\n\tpath: string;\n\tmessage: string;\n}\n\n/** What a candidate value came to. */\nexport interface CredentialCheck {\n\tok: boolean;\n\tissues: CredentialIssue[];\n}\n\n/** A construct's credentials key, and its schema as data. */\nexport interface CredentialSchemaInfo {\n\tkey: string;\n\tid: string;\n\tkind: 'external-api' | 'credential';\n\t/**\n\t * The schema as JSON Schema, where the schema can say — zod's, or any\n\t * Standard JSON Schema. Absent otherwise: the value is asked for as JSON.\n\t */\n\tjsonSchema?: Record<string, unknown>;\n}\n\n/** What loading the constructs answers. */\nexport interface CredentialInspection {\n\tschemas: CredentialSchemaInfo[];\n\t/** Each value asked about, by key. */\n\tchecks: Record<string, CredentialCheck>;\n}\n\n/** A construct whose credentials have a schema. */\ninterface LiveCredential {\n\tkey: string;\n\tid: string;\n\tkind: 'external-api' | 'credential';\n\tschema: StandardSchemaV1;\n}\n\n/** The credentials keys a manifest declares, by the construct that reads each. */\nexport function credentialKeys(\n\tmanifest: ConstructManifest,\n): { key: string; id: string; kind: 'external-api' | 'credential' }[] {\n\treturn Object.entries(manifest).flatMap(([id, declaration]) =>\n\t\tdeclaration.kind === 'external-api' || declaration.kind === 'credential'\n\t\t\t? [{ key: provideKey(id, 'credentials'), id, kind: declaration.kind }]\n\t\t\t: [],\n\t);\n}\n\n/** The constructs that read a third party's credentials, with their schemas. */\nexport function liveCredentials(\n\tmanifest: ConstructManifest,\n\tsources: Readonly<Record<string, ConstructSource>>,\n): LiveCredential[] {\n\treturn credentialKeys(manifest).flatMap(({ key, id, kind }) => {\n\t\tconst schema = (sources[id]?.construct as { credentialsSchema?: unknown })\n\t\t\t?.credentialsSchema;\n\t\treturn isStandardSchema(schema) ? [{ key, id, kind, schema }] : [];\n\t});\n}\n\nfunction isStandardSchema(value: unknown): value is StandardSchemaV1 {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\ttypeof (value as StandardSchemaV1)['~standard']?.validate === 'function'\n\t);\n}\n\n/**\n * A schema as JSON Schema: through the Standard JSON Schema extension where\n * the schema has it, as zod 4's does, else zod's own converter — or nothing,\n * for a schema neither can describe.\n */\nexport function jsonSchemaOf(\n\tschema: StandardSchemaV1,\n): Record<string, unknown> | undefined {\n\tconst standard = schema['~standard'] as StandardSchemaV1['~standard'] & {\n\t\tjsonSchema?: {\n\t\t\tinput?: (options: { target: string }) => Record<string, unknown>;\n\t\t};\n\t};\n\ttry {\n\t\tconst described = standard.jsonSchema?.input?.({\n\t\t\ttarget: 'draft-2020-12',\n\t\t});\n\t\tif (described) return described;\n\t} catch {\n\t\t// A type JSON Schema cannot express: try zod's converter, then nothing.\n\t}\n\tif (typeof schema === 'object' && schema !== null && '_zod' in schema) {\n\t\ttry {\n\t\t\treturn z.toJSONSchema(schema as unknown as z.ZodType, {\n\t\t\t\tio: 'input',\n\t\t\t}) as Record<string, unknown>;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/** A stored value against its schema, read the way the construct reads it. */\nexport async function checkCredential(\n\tschema: StandardSchemaV1,\n\traw: string,\n): Promise<CredentialCheck> {\n\tconst result = await schema['~standard'].validate(decodeCredentials(raw));\n\tif (!result.issues) return { ok: true, issues: [] };\n\treturn {\n\t\tok: false,\n\t\tissues: result.issues.map((issue) => ({\n\t\t\tpath: (issue.path ?? [])\n\t\t\t\t.map((segment) =>\n\t\t\t\t\ttypeof segment === 'object' ? String(segment.key) : String(segment),\n\t\t\t\t)\n\t\t\t\t.join('.'),\n\t\t\tmessage: issue.message,\n\t\t})),\n\t};\n}\n\n/** What a set of live credentials says about some values: data only. */\nexport async function inspectLive(\n\tlive: readonly LiveCredential[],\n\tvalues: Readonly<Record<string, string>>,\n): Promise<CredentialInspection> {\n\tconst checks: Record<string, CredentialCheck> = {};\n\tfor (const credential of live) {\n\t\tconst value = values[credential.key];\n\t\tif (value === undefined) continue;\n\t\tchecks[credential.key] = await checkCredential(credential.schema, value);\n\t}\n\treturn {\n\t\tschemas: live.map(({ key, id, kind, schema }) => {\n\t\t\tconst jsonSchema = jsonSchemaOf(schema);\n\t\t\treturn { key, id, kind, ...(jsonSchema ? { jsonSchema } : {}) };\n\t\t}),\n\t\tchecks,\n\t};\n}\n\nexport interface InspectOptions {\n\t/** The workspace root. */\n\troot: string;\n\t/** Its construct globs. */\n\tpatterns: readonly string[];\n\t/** The values to check, by key. Only credentials keys are looked at. */\n\tvalues?: Readonly<Record<string, string>>;\n}\n\nconst Issue = z.object({ path: z.string(), message: z.string() });\n\n/** What the credentials worker answers. Checked: the worker ran project code. */\nconst CredentialsAnswer = z.discriminatedUnion('reason', [\n\tz.object({\n\t\treason: z.literal('inspected'),\n\t\tschemas: z.array(\n\t\t\tz.object({\n\t\t\t\tkey: z.string(),\n\t\t\t\tid: z.string(),\n\t\t\t\tkind: z.enum(['external-api', 'credential']),\n\t\t\t\tjsonSchema: z.record(z.string(), z.unknown()).optional(),\n\t\t\t}),\n\t\t),\n\t\tchecks: z.record(\n\t\t\tz.string(),\n\t\t\tz.object({ ok: z.boolean(), issues: z.array(Issue) }),\n\t\t),\n\t}),\n\tz.object({\n\t\treason: z.literal('failed'),\n\t\terror: z.object({ name: z.string(), message: z.string() }).loose(),\n\t}),\n]);\n\n/** How long loading the constructs to check credentials may take. */\nconst INSPECT_TIMEOUT_MS = 60_000;\n\n/**\n * The workspace's credential schemas, and what each of `values` comes to —\n * loaded in the run's sandbox when there is one, here otherwise.\n */\nexport async function inspectCredentials(\n\toptions: InspectOptions,\n): Promise<CredentialInspection> {\n\tconst sandbox = activeSandbox();\n\tif (!sandbox) {\n\t\treturn (await loadCredentialSchemasHere(options)).inspect(\n\t\t\toptions.values ?? {},\n\t\t);\n\t}\n\n\tconst secrets = Object.fromEntries(\n\t\tObject.entries(options.values ?? {}).filter(([key]) =>\n\t\t\tkey.endsWith('_CREDENTIALS'),\n\t\t),\n\t);\n\tconst { value } = await runWorker(sandbox, 'credentials check', {\n\t\tname: 'credentials-worker',\n\t\targs: [JSON.stringify({ patterns: options.patterns, cwd: options.root })],\n\t\tcwd: options.root,\n\t\ttimeoutMs: INSPECT_TIMEOUT_MS,\n\t\tschema: CredentialsAnswer,\n\t\t...(Object.keys(secrets).length > 0 ? { secrets } : {}),\n\t});\n\tif (value.reason === 'failed') {\n\t\tthrow new ConstructDiscoveryFailed(value.error.name, value.error.message);\n\t}\n\tconst { schemas, checks } = value;\n\treturn {\n\t\tschemas: schemas.map(({ jsonSchema, ...rest }) => ({\n\t\t\t...rest,\n\t\t\t...(jsonSchema ? { jsonSchema } : {}),\n\t\t})),\n\t\tchecks,\n\t};\n}\n\n/** The constructs loaded once, here, and asked about as often as needed. */\nasync function loadCredentialSchemasHere(options: InspectOptions): Promise<{\n\tinspect(\n\t\tvalues: Readonly<Record<string, string>>,\n\t): Promise<CredentialInspection>;\n}> {\n\tconst sources: Record<string, ConstructSource> = {};\n\tconst manifest = await discover({\n\t\tpatterns: [...options.patterns],\n\t\tcwd: options.root,\n\t\tsources,\n\t});\n\tconst live = liveCredentials(manifest, sources);\n\treturn { inspect: (values) => inspectLive(live, values) };\n}\n\n/** The schemas, and a check of one candidate value at a time. */\nexport interface CredentialSchemas {\n\tschemas: CredentialSchemaInfo[];\n\t/** `raw` against `key`'s schema; ok for a key no schema describes. */\n\tcheck(key: string, raw: string): Promise<CredentialCheck>;\n}\n\n/**\n * The workspace's credential schemas, for a command that checks values one\n * at a time as they are typed. In-process the constructs are loaded once;\n * in a sandbox each check is a run of the worker.\n */\nexport async function loadCredentialSchemas(\n\toptions: Omit<InspectOptions, 'values'>,\n): Promise<CredentialSchemas> {\n\tconst here = activeSandbox()\n\t\t? undefined\n\t\t: await loadCredentialSchemasHere(options);\n\tconst inspect = (values: Readonly<Record<string, string>>) =>\n\t\there ? here.inspect(values) : inspectCredentials({ ...options, values });\n\n\tconst { schemas } = await inspect({});\n\treturn {\n\t\tschemas,\n\t\tasync check(key, raw) {\n\t\t\tif (!schemas.some((s) => s.key === key)) return { ok: true, issues: [] };\n\t\t\tconst { checks } = await inspect({ [key]: raw });\n\t\t\treturn checks[key] ?? { ok: true, issues: [] };\n\t\t},\n\t};\n}\n\n/** One stored credential its schema refuses. */\nexport interface InvalidCredential {\n\tkey: string;\n\tissues: CredentialIssue[];\n}\n\n/** An issue as the line that names it: `SHIPPING_CREDENTIALS.apiKey: …`. */\nexport function issueLine(key: string, issue: CredentialIssue): string {\n\treturn `${key}${issue.path ? `.${issue.path}` : ''}: ${issue.message}`;\n}\n\n/**\n * Credentials their construct's schema refuses — on their way into the\n * stage's secrets, or already there when a deploy reads them. The values are\n * never in the message: only where each is wrong, and why.\n */\nexport class CredentialsInvalid extends GkmError {\n\tconstructor(\n\t\treadonly stage: string,\n\t\treadonly invalid: readonly InvalidCredential[],\n\t\t/** Whether a value was being set (and was not saved), or deployed. */\n\t\treadonly during: 'set' | 'deploy',\n\t) {\n\t\tconst lines = invalid.flatMap(({ key, issues }) =>\n\t\t\tissues.map((issue) => ` ${issueLine(key, issue)}`),\n\t\t);\n\t\tconst keys = invalid.map((i) => i.key);\n\t\tsuper(\n\t\t\tduring === 'set'\n\t\t\t\t? `${keys.join(', ')} is not what its construct's schema describes, ` +\n\t\t\t\t\t\t`so nothing was saved:\\n\\n${lines.join('\\n')}\\n\\n` +\n\t\t\t\t\t\t`Set a value that matches, or let gkm ask for each field: ` +\n\t\t\t\t\t\t`gkm secrets:add --stage ${stage}`\n\t\t\t\t: `The stage '${stage}' holds ${keys.length === 1 ? 'a credential' : 'credentials'} ` +\n\t\t\t\t\t\t`${keys.length === 1 ? \"its construct's schema refuses\" : \"their constructs' schemas refuse\"}, ` +\n\t\t\t\t\t\t`and every app reading ${keys.length === 1 ? 'it' : 'them'} would fail ` +\n\t\t\t\t\t\t`as it starts:\\n\\n${lines.join('\\n')}\\n\\n` +\n\t\t\t\t\t\t`Set ${keys.length === 1 ? 'it' : 'them'} again, field by field: ` +\n\t\t\t\t\t\t`gkm secrets:add --stage ${stage}`,\n\t\t);\n\t\tthis.name = 'CredentialsInvalid';\n\t}\n}\n\n/**\n * Every credential the stage holds for a construct, against its schema —\n * before a deploy builds anything with one the app would refuse as it\n * starts. Loads nothing when the stage holds none.\n *\n * @throws {CredentialsInvalid} naming each key and every issue\n */\nexport async function assertStageCredentials(options: {\n\troot: string;\n\tpatterns: readonly string[];\n\tmanifest: ConstructManifest;\n\tstage: string;\n\tsupplied: Readonly<Record<string, string>>;\n}): Promise<void> {\n\tconst values = Object.fromEntries(\n\t\tcredentialKeys(options.manifest)\n\t\t\t.map(({ key }) => [key, options.supplied[key]] as const)\n\t\t\t.filter((entry): entry is [string, string] => entry[1] !== undefined),\n\t);\n\tif (Object.keys(values).length === 0) return;\n\n\tconst { checks } = await inspectCredentials({\n\t\troot: options.root,\n\t\tpatterns: options.patterns,\n\t\tvalues,\n\t});\n\tconst invalid = Object.entries(checks)\n\t\t.filter(([, check]) => !check.ok)\n\t\t.map(([key, check]) => ({ key, issues: check.issues }))\n\t\t.sort((a, b) => a.key.localeCompare(b.key));\n\tif (invalid.length > 0) {\n\t\tthrow new CredentialsInvalid(options.stage, invalid, 'deploy');\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"credentialSchemas-DFxvGEwa.cjs","names":["provideKey","decodeCredentials","activeSandbox","runWorker","ConstructDiscoveryFailed","discover","GkmError"],"sources":["../src/secrets/credentialSchemas.ts"],"sourcesContent":["/**\n * A third party's credentials, checked against the schema of the construct\n * that reads them — before they are stored, and before a deploy builds\n * anything with them.\n *\n * The schema lives on the construct (`ExternalApi.credentialsSchema`,\n * `Credential.credentialsSchema`), which is the project's code. So the\n * constructs are loaded where a deploy loads them: in the run's sandbox when\n * there is one, here otherwise. What comes back is data only — each schema as\n * JSON Schema where it can say so, and `{ ok, issues }` for each value asked\n * about — because a live schema cannot cross an isolating sandbox. A value\n * asked about goes in as a secret file, never an argument, and no issue\n * carries it back: an issue is a path and a message.\n */\n\nimport { decodeCredentials } from '@geekmidas/constructs/credential';\nimport { type ConstructManifest, provideKey } from '@geekmidas/manifest';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { z } from 'zod';\nimport { GkmError } from '../errors';\nimport {\n\tConstructDiscoveryFailed,\n\ttype ConstructSource,\n\tdiscover,\n} from '../reconcile/discover';\nimport { activeSandbox } from '../sandbox/sandbox';\nimport { runWorker } from '../sandbox/worker';\n\n/** One thing a schema refused: where in the value, and why. */\nexport interface CredentialIssue {\n\t/** Dotted, from the value's root — `apiKey`, `keys.0`; empty for the root. */\n\tpath: string;\n\tmessage: string;\n}\n\n/** What a candidate value came to. */\nexport interface CredentialCheck {\n\tok: boolean;\n\tissues: CredentialIssue[];\n}\n\n/** A construct's credentials key, and its schema as data. */\nexport interface CredentialSchemaInfo {\n\tkey: string;\n\tid: string;\n\tkind: 'external-api' | 'credential';\n\t/**\n\t * The schema as JSON Schema, where the schema can say — zod's, or any\n\t * Standard JSON Schema. Absent otherwise: the value is asked for as JSON.\n\t */\n\tjsonSchema?: Record<string, unknown>;\n}\n\n/** What loading the constructs answers. */\nexport interface CredentialInspection {\n\tschemas: CredentialSchemaInfo[];\n\t/** Each value asked about, by key. */\n\tchecks: Record<string, CredentialCheck>;\n}\n\n/** A construct whose credentials have a schema. */\ninterface LiveCredential {\n\tkey: string;\n\tid: string;\n\tkind: 'external-api' | 'credential';\n\tschema: StandardSchemaV1;\n}\n\n/** The credentials keys a manifest declares, by the construct that reads each. */\nexport function credentialKeys(\n\tmanifest: ConstructManifest,\n): { key: string; id: string; kind: 'external-api' | 'credential' }[] {\n\treturn Object.entries(manifest).flatMap(([id, declaration]) =>\n\t\tdeclaration.kind === 'external-api' || declaration.kind === 'credential'\n\t\t\t? [{ key: provideKey(id, 'credentials'), id, kind: declaration.kind }]\n\t\t\t: [],\n\t);\n}\n\n/** The constructs that read a third party's credentials, with their schemas. */\nexport function liveCredentials(\n\tmanifest: ConstructManifest,\n\tsources: Readonly<Record<string, ConstructSource>>,\n): LiveCredential[] {\n\treturn credentialKeys(manifest).flatMap(({ key, id, kind }) => {\n\t\tconst schema = (sources[id]?.construct as { credentialsSchema?: unknown })\n\t\t\t?.credentialsSchema;\n\t\treturn isStandardSchema(schema) ? [{ key, id, kind, schema }] : [];\n\t});\n}\n\nfunction isStandardSchema(value: unknown): value is StandardSchemaV1 {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\ttypeof (value as StandardSchemaV1)['~standard']?.validate === 'function'\n\t);\n}\n\n/**\n * A schema as JSON Schema: through the Standard JSON Schema extension where\n * the schema has it, as zod 4's does, else zod's own converter — or nothing,\n * for a schema neither can describe.\n */\nexport function jsonSchemaOf(\n\tschema: StandardSchemaV1,\n): Record<string, unknown> | undefined {\n\tconst standard = schema['~standard'] as StandardSchemaV1['~standard'] & {\n\t\tjsonSchema?: {\n\t\t\tinput?: (options: { target: string }) => Record<string, unknown>;\n\t\t};\n\t};\n\ttry {\n\t\tconst described = standard.jsonSchema?.input?.({\n\t\t\ttarget: 'draft-2020-12',\n\t\t});\n\t\tif (described) return described;\n\t} catch {\n\t\t// A type JSON Schema cannot express: try zod's converter, then nothing.\n\t}\n\tif (typeof schema === 'object' && schema !== null && '_zod' in schema) {\n\t\ttry {\n\t\t\treturn z.toJSONSchema(schema as unknown as z.ZodType, {\n\t\t\t\tio: 'input',\n\t\t\t}) as Record<string, unknown>;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/** A stored value against its schema, read the way the construct reads it. */\nexport async function checkCredential(\n\tschema: StandardSchemaV1,\n\traw: string,\n): Promise<CredentialCheck> {\n\tconst result = await schema['~standard'].validate(decodeCredentials(raw));\n\tif (!result.issues) return { ok: true, issues: [] };\n\treturn {\n\t\tok: false,\n\t\tissues: result.issues.map((issue) => ({\n\t\t\tpath: (issue.path ?? [])\n\t\t\t\t.map((segment) =>\n\t\t\t\t\ttypeof segment === 'object' ? String(segment.key) : String(segment),\n\t\t\t\t)\n\t\t\t\t.join('.'),\n\t\t\tmessage: issue.message,\n\t\t})),\n\t};\n}\n\n/** What a set of live credentials says about some values: data only. */\nexport async function inspectLive(\n\tlive: readonly LiveCredential[],\n\tvalues: Readonly<Record<string, string>>,\n): Promise<CredentialInspection> {\n\tconst checks: Record<string, CredentialCheck> = {};\n\tfor (const credential of live) {\n\t\tconst value = values[credential.key];\n\t\tif (value === undefined) continue;\n\t\tchecks[credential.key] = await checkCredential(credential.schema, value);\n\t}\n\treturn {\n\t\tschemas: live.map(({ key, id, kind, schema }) => {\n\t\t\tconst jsonSchema = jsonSchemaOf(schema);\n\t\t\treturn { key, id, kind, ...(jsonSchema ? { jsonSchema } : {}) };\n\t\t}),\n\t\tchecks,\n\t};\n}\n\nexport interface InspectOptions {\n\t/** The workspace root. */\n\troot: string;\n\t/** Its construct globs. */\n\tpatterns: readonly string[];\n\t/** The values to check, by key. Only credentials keys are looked at. */\n\tvalues?: Readonly<Record<string, string>>;\n}\n\nconst Issue = z.object({ path: z.string(), message: z.string() });\n\n/** What the credentials worker answers. Checked: the worker ran project code. */\nconst CredentialsAnswer = z.discriminatedUnion('reason', [\n\tz.object({\n\t\treason: z.literal('inspected'),\n\t\tschemas: z.array(\n\t\t\tz.object({\n\t\t\t\tkey: z.string(),\n\t\t\t\tid: z.string(),\n\t\t\t\tkind: z.enum(['external-api', 'credential']),\n\t\t\t\tjsonSchema: z.record(z.string(), z.unknown()).optional(),\n\t\t\t}),\n\t\t),\n\t\tchecks: z.record(\n\t\t\tz.string(),\n\t\t\tz.object({ ok: z.boolean(), issues: z.array(Issue) }),\n\t\t),\n\t}),\n\tz.object({\n\t\treason: z.literal('failed'),\n\t\terror: z.object({ name: z.string(), message: z.string() }).loose(),\n\t}),\n]);\n\n/** How long loading the constructs to check credentials may take. */\nconst INSPECT_TIMEOUT_MS = 60_000;\n\n/**\n * The workspace's credential schemas, and what each of `values` comes to —\n * loaded in the run's sandbox when there is one, here otherwise.\n */\nexport async function inspectCredentials(\n\toptions: InspectOptions,\n): Promise<CredentialInspection> {\n\tconst sandbox = activeSandbox();\n\tif (!sandbox) {\n\t\treturn (await loadCredentialSchemasHere(options)).inspect(\n\t\t\toptions.values ?? {},\n\t\t);\n\t}\n\n\tconst secrets = Object.fromEntries(\n\t\tObject.entries(options.values ?? {}).filter(([key]) =>\n\t\t\tkey.endsWith('_CREDENTIALS'),\n\t\t),\n\t);\n\tconst { value } = await runWorker(sandbox, 'credentials check', {\n\t\tname: 'credentials-worker',\n\t\targs: [JSON.stringify({ patterns: options.patterns, cwd: options.root })],\n\t\tcwd: options.root,\n\t\ttimeoutMs: INSPECT_TIMEOUT_MS,\n\t\tschema: CredentialsAnswer,\n\t\t...(Object.keys(secrets).length > 0 ? { secrets } : {}),\n\t});\n\tif (value.reason === 'failed') {\n\t\tthrow new ConstructDiscoveryFailed(value.error.name, value.error.message);\n\t}\n\tconst { schemas, checks } = value;\n\treturn {\n\t\tschemas: schemas.map(({ jsonSchema, ...rest }) => ({\n\t\t\t...rest,\n\t\t\t...(jsonSchema ? { jsonSchema } : {}),\n\t\t})),\n\t\tchecks,\n\t};\n}\n\n/** The constructs loaded once, here, and asked about as often as needed. */\nasync function loadCredentialSchemasHere(options: InspectOptions): Promise<{\n\tinspect(\n\t\tvalues: Readonly<Record<string, string>>,\n\t): Promise<CredentialInspection>;\n}> {\n\tconst sources: Record<string, ConstructSource> = {};\n\tconst manifest = await discover({\n\t\tpatterns: [...options.patterns],\n\t\tcwd: options.root,\n\t\tsources,\n\t});\n\tconst live = liveCredentials(manifest, sources);\n\treturn { inspect: (values) => inspectLive(live, values) };\n}\n\n/** The schemas, and a check of one candidate value at a time. */\nexport interface CredentialSchemas {\n\tschemas: CredentialSchemaInfo[];\n\t/** `raw` against `key`'s schema; ok for a key no schema describes. */\n\tcheck(key: string, raw: string): Promise<CredentialCheck>;\n}\n\n/**\n * The workspace's credential schemas, for a command that checks values one\n * at a time as they are typed. In-process the constructs are loaded once;\n * in a sandbox each check is a run of the worker.\n */\nexport async function loadCredentialSchemas(\n\toptions: Omit<InspectOptions, 'values'>,\n): Promise<CredentialSchemas> {\n\tconst here = activeSandbox()\n\t\t? undefined\n\t\t: await loadCredentialSchemasHere(options);\n\tconst inspect = (values: Readonly<Record<string, string>>) =>\n\t\there ? here.inspect(values) : inspectCredentials({ ...options, values });\n\n\tconst { schemas } = await inspect({});\n\treturn {\n\t\tschemas,\n\t\tasync check(key, raw) {\n\t\t\tif (!schemas.some((s) => s.key === key)) return { ok: true, issues: [] };\n\t\t\tconst { checks } = await inspect({ [key]: raw });\n\t\t\treturn checks[key] ?? { ok: true, issues: [] };\n\t\t},\n\t};\n}\n\n/** One stored credential its schema refuses. */\nexport interface InvalidCredential {\n\tkey: string;\n\tissues: CredentialIssue[];\n}\n\n/** An issue as the line that names it: `SHIPPING_CREDENTIALS.apiKey: …`. */\nexport function issueLine(key: string, issue: CredentialIssue): string {\n\treturn `${key}${issue.path ? `.${issue.path}` : ''}: ${issue.message}`;\n}\n\n/**\n * Credentials their construct's schema refuses — on their way into the\n * stage's secrets, or already there when a deploy reads them. The values are\n * never in the message: only where each is wrong, and why.\n */\nexport class CredentialsInvalid extends GkmError {\n\tconstructor(\n\t\treadonly stage: string,\n\t\treadonly invalid: readonly InvalidCredential[],\n\t\t/** Whether a value was being set (and was not saved), or deployed. */\n\t\treadonly during: 'set' | 'deploy',\n\t) {\n\t\tconst lines = invalid.flatMap(({ key, issues }) =>\n\t\t\tissues.map((issue) => ` ${issueLine(key, issue)}`),\n\t\t);\n\t\tconst keys = invalid.map((i) => i.key);\n\t\tsuper(\n\t\t\tduring === 'set'\n\t\t\t\t? `${keys.join(', ')} is not what its construct's schema describes, ` +\n\t\t\t\t\t\t`so nothing was saved:\\n\\n${lines.join('\\n')}\\n\\n` +\n\t\t\t\t\t\t`Set a value that matches, or let gkm ask for each field: ` +\n\t\t\t\t\t\t`gkm secrets:add --stage ${stage}`\n\t\t\t\t: `The stage '${stage}' holds ${keys.length === 1 ? 'a credential' : 'credentials'} ` +\n\t\t\t\t\t\t`${keys.length === 1 ? \"its construct's schema refuses\" : \"their constructs' schemas refuse\"}, ` +\n\t\t\t\t\t\t`and every app reading ${keys.length === 1 ? 'it' : 'them'} would fail ` +\n\t\t\t\t\t\t`as it starts:\\n\\n${lines.join('\\n')}\\n\\n` +\n\t\t\t\t\t\t`Set ${keys.length === 1 ? 'it' : 'them'} again, field by field: ` +\n\t\t\t\t\t\t`gkm secrets:add --stage ${stage}`,\n\t\t);\n\t\tthis.name = 'CredentialsInvalid';\n\t}\n}\n\n/**\n * Every credential the stage holds for a construct, against its schema —\n * before a deploy builds anything with one the app would refuse as it\n * starts. Loads nothing when the stage holds none.\n *\n * @throws {CredentialsInvalid} naming each key and every issue\n */\nexport async function assertStageCredentials(options: {\n\troot: string;\n\tpatterns: readonly string[];\n\tmanifest: ConstructManifest;\n\tstage: string;\n\tsupplied: Readonly<Record<string, string>>;\n}): Promise<void> {\n\tconst values = Object.fromEntries(\n\t\tcredentialKeys(options.manifest)\n\t\t\t.map(({ key }) => [key, options.supplied[key]] as const)\n\t\t\t.filter((entry): entry is [string, string] => entry[1] !== undefined),\n\t);\n\tif (Object.keys(values).length === 0) return;\n\n\tconst { checks } = await inspectCredentials({\n\t\troot: options.root,\n\t\tpatterns: options.patterns,\n\t\tvalues,\n\t});\n\tconst invalid = Object.entries(checks)\n\t\t.filter(([, check]) => !check.ok)\n\t\t.map(([key, check]) => ({ key, issues: check.issues }))\n\t\t.sort((a, b) => a.key.localeCompare(b.key));\n\tif (invalid.length > 0) {\n\t\tthrow new CredentialsInvalid(options.stage, invalid, 'deploy');\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as GkmError } from "./errors-D8Gwp5kU.mjs";
|
|
2
2
|
import { a as discriminatedUnion, c as literal, d as object, f as record, g as unknown, n as array, p as string, r as boolean, t as _enum, v as toJSONSchema } from "./schemas-BCwKKA42.mjs";
|
|
3
|
-
import { i as discover, l as runWorker, t as ConstructDiscoveryFailed } from "./discover-
|
|
3
|
+
import { i as discover, l as runWorker, t as ConstructDiscoveryFailed } from "./discover-CzGM5P3p.mjs";
|
|
4
4
|
import { i as activeSandbox } from "./sandbox-CbVB7uOD.mjs";
|
|
5
5
|
import { provideKey } from "@geekmidas/manifest";
|
|
6
6
|
import { decodeCredentials } from "@geekmidas/constructs/credential";
|
|
@@ -234,4 +234,4 @@ async function assertStageCredentials(options) {
|
|
|
234
234
|
//#endregion
|
|
235
235
|
export { liveCredentials as a, issueLine as i, assertStageCredentials as n, loadCredentialSchemas as o, inspectLive as r, CredentialsInvalid as t };
|
|
236
236
|
|
|
237
|
-
//# sourceMappingURL=credentialSchemas-
|
|
237
|
+
//# sourceMappingURL=credentialSchemas-DaMpt-Dx.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credentialSchemas-DLKbxYBy.mjs","names":["z.toJSONSchema","z.object","z.string","z.discriminatedUnion","z.literal","z.array","z.enum","z.record","z.unknown","z.boolean"],"sources":["../src/secrets/credentialSchemas.ts"],"sourcesContent":["/**\n * A third party's credentials, checked against the schema of the construct\n * that reads them — before they are stored, and before a deploy builds\n * anything with them.\n *\n * The schema lives on the construct (`ExternalApi.credentialsSchema`,\n * `Credential.credentialsSchema`), which is the project's code. So the\n * constructs are loaded where a deploy loads them: in the run's sandbox when\n * there is one, here otherwise. What comes back is data only — each schema as\n * JSON Schema where it can say so, and `{ ok, issues }` for each value asked\n * about — because a live schema cannot cross an isolating sandbox. A value\n * asked about goes in as a secret file, never an argument, and no issue\n * carries it back: an issue is a path and a message.\n */\n\nimport { decodeCredentials } from '@geekmidas/constructs/credential';\nimport { type ConstructManifest, provideKey } from '@geekmidas/manifest';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { z } from 'zod';\nimport { GkmError } from '../errors';\nimport {\n\tConstructDiscoveryFailed,\n\ttype ConstructSource,\n\tdiscover,\n} from '../reconcile/discover';\nimport { activeSandbox } from '../sandbox/sandbox';\nimport { runWorker } from '../sandbox/worker';\n\n/** One thing a schema refused: where in the value, and why. */\nexport interface CredentialIssue {\n\t/** Dotted, from the value's root — `apiKey`, `keys.0`; empty for the root. */\n\tpath: string;\n\tmessage: string;\n}\n\n/** What a candidate value came to. */\nexport interface CredentialCheck {\n\tok: boolean;\n\tissues: CredentialIssue[];\n}\n\n/** A construct's credentials key, and its schema as data. */\nexport interface CredentialSchemaInfo {\n\tkey: string;\n\tid: string;\n\tkind: 'external-api' | 'credential';\n\t/**\n\t * The schema as JSON Schema, where the schema can say — zod's, or any\n\t * Standard JSON Schema. Absent otherwise: the value is asked for as JSON.\n\t */\n\tjsonSchema?: Record<string, unknown>;\n}\n\n/** What loading the constructs answers. */\nexport interface CredentialInspection {\n\tschemas: CredentialSchemaInfo[];\n\t/** Each value asked about, by key. */\n\tchecks: Record<string, CredentialCheck>;\n}\n\n/** A construct whose credentials have a schema. */\ninterface LiveCredential {\n\tkey: string;\n\tid: string;\n\tkind: 'external-api' | 'credential';\n\tschema: StandardSchemaV1;\n}\n\n/** The credentials keys a manifest declares, by the construct that reads each. */\nexport function credentialKeys(\n\tmanifest: ConstructManifest,\n): { key: string; id: string; kind: 'external-api' | 'credential' }[] {\n\treturn Object.entries(manifest).flatMap(([id, declaration]) =>\n\t\tdeclaration.kind === 'external-api' || declaration.kind === 'credential'\n\t\t\t? [{ key: provideKey(id, 'credentials'), id, kind: declaration.kind }]\n\t\t\t: [],\n\t);\n}\n\n/** The constructs that read a third party's credentials, with their schemas. */\nexport function liveCredentials(\n\tmanifest: ConstructManifest,\n\tsources: Readonly<Record<string, ConstructSource>>,\n): LiveCredential[] {\n\treturn credentialKeys(manifest).flatMap(({ key, id, kind }) => {\n\t\tconst schema = (sources[id]?.construct as { credentialsSchema?: unknown })\n\t\t\t?.credentialsSchema;\n\t\treturn isStandardSchema(schema) ? [{ key, id, kind, schema }] : [];\n\t});\n}\n\nfunction isStandardSchema(value: unknown): value is StandardSchemaV1 {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\ttypeof (value as StandardSchemaV1)['~standard']?.validate === 'function'\n\t);\n}\n\n/**\n * A schema as JSON Schema: through the Standard JSON Schema extension where\n * the schema has it, as zod 4's does, else zod's own converter — or nothing,\n * for a schema neither can describe.\n */\nexport function jsonSchemaOf(\n\tschema: StandardSchemaV1,\n): Record<string, unknown> | undefined {\n\tconst standard = schema['~standard'] as StandardSchemaV1['~standard'] & {\n\t\tjsonSchema?: {\n\t\t\tinput?: (options: { target: string }) => Record<string, unknown>;\n\t\t};\n\t};\n\ttry {\n\t\tconst described = standard.jsonSchema?.input?.({\n\t\t\ttarget: 'draft-2020-12',\n\t\t});\n\t\tif (described) return described;\n\t} catch {\n\t\t// A type JSON Schema cannot express: try zod's converter, then nothing.\n\t}\n\tif (typeof schema === 'object' && schema !== null && '_zod' in schema) {\n\t\ttry {\n\t\t\treturn z.toJSONSchema(schema as unknown as z.ZodType, {\n\t\t\t\tio: 'input',\n\t\t\t}) as Record<string, unknown>;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/** A stored value against its schema, read the way the construct reads it. */\nexport async function checkCredential(\n\tschema: StandardSchemaV1,\n\traw: string,\n): Promise<CredentialCheck> {\n\tconst result = await schema['~standard'].validate(decodeCredentials(raw));\n\tif (!result.issues) return { ok: true, issues: [] };\n\treturn {\n\t\tok: false,\n\t\tissues: result.issues.map((issue) => ({\n\t\t\tpath: (issue.path ?? [])\n\t\t\t\t.map((segment) =>\n\t\t\t\t\ttypeof segment === 'object' ? String(segment.key) : String(segment),\n\t\t\t\t)\n\t\t\t\t.join('.'),\n\t\t\tmessage: issue.message,\n\t\t})),\n\t};\n}\n\n/** What a set of live credentials says about some values: data only. */\nexport async function inspectLive(\n\tlive: readonly LiveCredential[],\n\tvalues: Readonly<Record<string, string>>,\n): Promise<CredentialInspection> {\n\tconst checks: Record<string, CredentialCheck> = {};\n\tfor (const credential of live) {\n\t\tconst value = values[credential.key];\n\t\tif (value === undefined) continue;\n\t\tchecks[credential.key] = await checkCredential(credential.schema, value);\n\t}\n\treturn {\n\t\tschemas: live.map(({ key, id, kind, schema }) => {\n\t\t\tconst jsonSchema = jsonSchemaOf(schema);\n\t\t\treturn { key, id, kind, ...(jsonSchema ? { jsonSchema } : {}) };\n\t\t}),\n\t\tchecks,\n\t};\n}\n\nexport interface InspectOptions {\n\t/** The workspace root. */\n\troot: string;\n\t/** Its construct globs. */\n\tpatterns: readonly string[];\n\t/** The values to check, by key. Only credentials keys are looked at. */\n\tvalues?: Readonly<Record<string, string>>;\n}\n\nconst Issue = z.object({ path: z.string(), message: z.string() });\n\n/** What the credentials worker answers. Checked: the worker ran project code. */\nconst CredentialsAnswer = z.discriminatedUnion('reason', [\n\tz.object({\n\t\treason: z.literal('inspected'),\n\t\tschemas: z.array(\n\t\t\tz.object({\n\t\t\t\tkey: z.string(),\n\t\t\t\tid: z.string(),\n\t\t\t\tkind: z.enum(['external-api', 'credential']),\n\t\t\t\tjsonSchema: z.record(z.string(), z.unknown()).optional(),\n\t\t\t}),\n\t\t),\n\t\tchecks: z.record(\n\t\t\tz.string(),\n\t\t\tz.object({ ok: z.boolean(), issues: z.array(Issue) }),\n\t\t),\n\t}),\n\tz.object({\n\t\treason: z.literal('failed'),\n\t\terror: z.object({ name: z.string(), message: z.string() }).loose(),\n\t}),\n]);\n\n/** How long loading the constructs to check credentials may take. */\nconst INSPECT_TIMEOUT_MS = 60_000;\n\n/**\n * The workspace's credential schemas, and what each of `values` comes to —\n * loaded in the run's sandbox when there is one, here otherwise.\n */\nexport async function inspectCredentials(\n\toptions: InspectOptions,\n): Promise<CredentialInspection> {\n\tconst sandbox = activeSandbox();\n\tif (!sandbox) {\n\t\treturn (await loadCredentialSchemasHere(options)).inspect(\n\t\t\toptions.values ?? {},\n\t\t);\n\t}\n\n\tconst secrets = Object.fromEntries(\n\t\tObject.entries(options.values ?? {}).filter(([key]) =>\n\t\t\tkey.endsWith('_CREDENTIALS'),\n\t\t),\n\t);\n\tconst { value } = await runWorker(sandbox, 'credentials check', {\n\t\tname: 'credentials-worker',\n\t\targs: [JSON.stringify({ patterns: options.patterns, cwd: options.root })],\n\t\tcwd: options.root,\n\t\ttimeoutMs: INSPECT_TIMEOUT_MS,\n\t\tschema: CredentialsAnswer,\n\t\t...(Object.keys(secrets).length > 0 ? { secrets } : {}),\n\t});\n\tif (value.reason === 'failed') {\n\t\tthrow new ConstructDiscoveryFailed(value.error.name, value.error.message);\n\t}\n\tconst { schemas, checks } = value;\n\treturn {\n\t\tschemas: schemas.map(({ jsonSchema, ...rest }) => ({\n\t\t\t...rest,\n\t\t\t...(jsonSchema ? { jsonSchema } : {}),\n\t\t})),\n\t\tchecks,\n\t};\n}\n\n/** The constructs loaded once, here, and asked about as often as needed. */\nasync function loadCredentialSchemasHere(options: InspectOptions): Promise<{\n\tinspect(\n\t\tvalues: Readonly<Record<string, string>>,\n\t): Promise<CredentialInspection>;\n}> {\n\tconst sources: Record<string, ConstructSource> = {};\n\tconst manifest = await discover({\n\t\tpatterns: [...options.patterns],\n\t\tcwd: options.root,\n\t\tsources,\n\t});\n\tconst live = liveCredentials(manifest, sources);\n\treturn { inspect: (values) => inspectLive(live, values) };\n}\n\n/** The schemas, and a check of one candidate value at a time. */\nexport interface CredentialSchemas {\n\tschemas: CredentialSchemaInfo[];\n\t/** `raw` against `key`'s schema; ok for a key no schema describes. */\n\tcheck(key: string, raw: string): Promise<CredentialCheck>;\n}\n\n/**\n * The workspace's credential schemas, for a command that checks values one\n * at a time as they are typed. In-process the constructs are loaded once;\n * in a sandbox each check is a run of the worker.\n */\nexport async function loadCredentialSchemas(\n\toptions: Omit<InspectOptions, 'values'>,\n): Promise<CredentialSchemas> {\n\tconst here = activeSandbox()\n\t\t? undefined\n\t\t: await loadCredentialSchemasHere(options);\n\tconst inspect = (values: Readonly<Record<string, string>>) =>\n\t\there ? here.inspect(values) : inspectCredentials({ ...options, values });\n\n\tconst { schemas } = await inspect({});\n\treturn {\n\t\tschemas,\n\t\tasync check(key, raw) {\n\t\t\tif (!schemas.some((s) => s.key === key)) return { ok: true, issues: [] };\n\t\t\tconst { checks } = await inspect({ [key]: raw });\n\t\t\treturn checks[key] ?? { ok: true, issues: [] };\n\t\t},\n\t};\n}\n\n/** One stored credential its schema refuses. */\nexport interface InvalidCredential {\n\tkey: string;\n\tissues: CredentialIssue[];\n}\n\n/** An issue as the line that names it: `SHIPPING_CREDENTIALS.apiKey: …`. */\nexport function issueLine(key: string, issue: CredentialIssue): string {\n\treturn `${key}${issue.path ? `.${issue.path}` : ''}: ${issue.message}`;\n}\n\n/**\n * Credentials their construct's schema refuses — on their way into the\n * stage's secrets, or already there when a deploy reads them. The values are\n * never in the message: only where each is wrong, and why.\n */\nexport class CredentialsInvalid extends GkmError {\n\tconstructor(\n\t\treadonly stage: string,\n\t\treadonly invalid: readonly InvalidCredential[],\n\t\t/** Whether a value was being set (and was not saved), or deployed. */\n\t\treadonly during: 'set' | 'deploy',\n\t) {\n\t\tconst lines = invalid.flatMap(({ key, issues }) =>\n\t\t\tissues.map((issue) => ` ${issueLine(key, issue)}`),\n\t\t);\n\t\tconst keys = invalid.map((i) => i.key);\n\t\tsuper(\n\t\t\tduring === 'set'\n\t\t\t\t? `${keys.join(', ')} is not what its construct's schema describes, ` +\n\t\t\t\t\t\t`so nothing was saved:\\n\\n${lines.join('\\n')}\\n\\n` +\n\t\t\t\t\t\t`Set a value that matches, or let gkm ask for each field: ` +\n\t\t\t\t\t\t`gkm secrets:add --stage ${stage}`\n\t\t\t\t: `The stage '${stage}' holds ${keys.length === 1 ? 'a credential' : 'credentials'} ` +\n\t\t\t\t\t\t`${keys.length === 1 ? \"its construct's schema refuses\" : \"their constructs' schemas refuse\"}, ` +\n\t\t\t\t\t\t`and every app reading ${keys.length === 1 ? 'it' : 'them'} would fail ` +\n\t\t\t\t\t\t`as it starts:\\n\\n${lines.join('\\n')}\\n\\n` +\n\t\t\t\t\t\t`Set ${keys.length === 1 ? 'it' : 'them'} again, field by field: ` +\n\t\t\t\t\t\t`gkm secrets:add --stage ${stage}`,\n\t\t);\n\t\tthis.name = 'CredentialsInvalid';\n\t}\n}\n\n/**\n * Every credential the stage holds for a construct, against its schema —\n * before a deploy builds anything with one the app would refuse as it\n * starts. Loads nothing when the stage holds none.\n *\n * @throws {CredentialsInvalid} naming each key and every issue\n */\nexport async function assertStageCredentials(options: {\n\troot: string;\n\tpatterns: readonly string[];\n\tmanifest: ConstructManifest;\n\tstage: string;\n\tsupplied: Readonly<Record<string, string>>;\n}): Promise<void> {\n\tconst values = Object.fromEntries(\n\t\tcredentialKeys(options.manifest)\n\t\t\t.map(({ key }) => [key, options.supplied[key]] as const)\n\t\t\t.filter((entry): entry is [string, string] => entry[1] !== undefined),\n\t);\n\tif (Object.keys(values).length === 0) return;\n\n\tconst { checks } = await inspectCredentials({\n\t\troot: options.root,\n\t\tpatterns: options.patterns,\n\t\tvalues,\n\t});\n\tconst invalid = Object.entries(checks)\n\t\t.filter(([, check]) => !check.ok)\n\t\t.map(([key, check]) => ({ key, issues: check.issues }))\n\t\t.sort((a, b) => a.key.localeCompare(b.key));\n\tif (invalid.length > 0) {\n\t\tthrow new CredentialsInvalid(options.stage, invalid, 'deploy');\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"credentialSchemas-DaMpt-Dx.mjs","names":["z.toJSONSchema","z.object","z.string","z.discriminatedUnion","z.literal","z.array","z.enum","z.record","z.unknown","z.boolean"],"sources":["../src/secrets/credentialSchemas.ts"],"sourcesContent":["/**\n * A third party's credentials, checked against the schema of the construct\n * that reads them — before they are stored, and before a deploy builds\n * anything with them.\n *\n * The schema lives on the construct (`ExternalApi.credentialsSchema`,\n * `Credential.credentialsSchema`), which is the project's code. So the\n * constructs are loaded where a deploy loads them: in the run's sandbox when\n * there is one, here otherwise. What comes back is data only — each schema as\n * JSON Schema where it can say so, and `{ ok, issues }` for each value asked\n * about — because a live schema cannot cross an isolating sandbox. A value\n * asked about goes in as a secret file, never an argument, and no issue\n * carries it back: an issue is a path and a message.\n */\n\nimport { decodeCredentials } from '@geekmidas/constructs/credential';\nimport { type ConstructManifest, provideKey } from '@geekmidas/manifest';\nimport type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { z } from 'zod';\nimport { GkmError } from '../errors';\nimport {\n\tConstructDiscoveryFailed,\n\ttype ConstructSource,\n\tdiscover,\n} from '../reconcile/discover';\nimport { activeSandbox } from '../sandbox/sandbox';\nimport { runWorker } from '../sandbox/worker';\n\n/** One thing a schema refused: where in the value, and why. */\nexport interface CredentialIssue {\n\t/** Dotted, from the value's root — `apiKey`, `keys.0`; empty for the root. */\n\tpath: string;\n\tmessage: string;\n}\n\n/** What a candidate value came to. */\nexport interface CredentialCheck {\n\tok: boolean;\n\tissues: CredentialIssue[];\n}\n\n/** A construct's credentials key, and its schema as data. */\nexport interface CredentialSchemaInfo {\n\tkey: string;\n\tid: string;\n\tkind: 'external-api' | 'credential';\n\t/**\n\t * The schema as JSON Schema, where the schema can say — zod's, or any\n\t * Standard JSON Schema. Absent otherwise: the value is asked for as JSON.\n\t */\n\tjsonSchema?: Record<string, unknown>;\n}\n\n/** What loading the constructs answers. */\nexport interface CredentialInspection {\n\tschemas: CredentialSchemaInfo[];\n\t/** Each value asked about, by key. */\n\tchecks: Record<string, CredentialCheck>;\n}\n\n/** A construct whose credentials have a schema. */\ninterface LiveCredential {\n\tkey: string;\n\tid: string;\n\tkind: 'external-api' | 'credential';\n\tschema: StandardSchemaV1;\n}\n\n/** The credentials keys a manifest declares, by the construct that reads each. */\nexport function credentialKeys(\n\tmanifest: ConstructManifest,\n): { key: string; id: string; kind: 'external-api' | 'credential' }[] {\n\treturn Object.entries(manifest).flatMap(([id, declaration]) =>\n\t\tdeclaration.kind === 'external-api' || declaration.kind === 'credential'\n\t\t\t? [{ key: provideKey(id, 'credentials'), id, kind: declaration.kind }]\n\t\t\t: [],\n\t);\n}\n\n/** The constructs that read a third party's credentials, with their schemas. */\nexport function liveCredentials(\n\tmanifest: ConstructManifest,\n\tsources: Readonly<Record<string, ConstructSource>>,\n): LiveCredential[] {\n\treturn credentialKeys(manifest).flatMap(({ key, id, kind }) => {\n\t\tconst schema = (sources[id]?.construct as { credentialsSchema?: unknown })\n\t\t\t?.credentialsSchema;\n\t\treturn isStandardSchema(schema) ? [{ key, id, kind, schema }] : [];\n\t});\n}\n\nfunction isStandardSchema(value: unknown): value is StandardSchemaV1 {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\ttypeof (value as StandardSchemaV1)['~standard']?.validate === 'function'\n\t);\n}\n\n/**\n * A schema as JSON Schema: through the Standard JSON Schema extension where\n * the schema has it, as zod 4's does, else zod's own converter — or nothing,\n * for a schema neither can describe.\n */\nexport function jsonSchemaOf(\n\tschema: StandardSchemaV1,\n): Record<string, unknown> | undefined {\n\tconst standard = schema['~standard'] as StandardSchemaV1['~standard'] & {\n\t\tjsonSchema?: {\n\t\t\tinput?: (options: { target: string }) => Record<string, unknown>;\n\t\t};\n\t};\n\ttry {\n\t\tconst described = standard.jsonSchema?.input?.({\n\t\t\ttarget: 'draft-2020-12',\n\t\t});\n\t\tif (described) return described;\n\t} catch {\n\t\t// A type JSON Schema cannot express: try zod's converter, then nothing.\n\t}\n\tif (typeof schema === 'object' && schema !== null && '_zod' in schema) {\n\t\ttry {\n\t\t\treturn z.toJSONSchema(schema as unknown as z.ZodType, {\n\t\t\t\tio: 'input',\n\t\t\t}) as Record<string, unknown>;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/** A stored value against its schema, read the way the construct reads it. */\nexport async function checkCredential(\n\tschema: StandardSchemaV1,\n\traw: string,\n): Promise<CredentialCheck> {\n\tconst result = await schema['~standard'].validate(decodeCredentials(raw));\n\tif (!result.issues) return { ok: true, issues: [] };\n\treturn {\n\t\tok: false,\n\t\tissues: result.issues.map((issue) => ({\n\t\t\tpath: (issue.path ?? [])\n\t\t\t\t.map((segment) =>\n\t\t\t\t\ttypeof segment === 'object' ? String(segment.key) : String(segment),\n\t\t\t\t)\n\t\t\t\t.join('.'),\n\t\t\tmessage: issue.message,\n\t\t})),\n\t};\n}\n\n/** What a set of live credentials says about some values: data only. */\nexport async function inspectLive(\n\tlive: readonly LiveCredential[],\n\tvalues: Readonly<Record<string, string>>,\n): Promise<CredentialInspection> {\n\tconst checks: Record<string, CredentialCheck> = {};\n\tfor (const credential of live) {\n\t\tconst value = values[credential.key];\n\t\tif (value === undefined) continue;\n\t\tchecks[credential.key] = await checkCredential(credential.schema, value);\n\t}\n\treturn {\n\t\tschemas: live.map(({ key, id, kind, schema }) => {\n\t\t\tconst jsonSchema = jsonSchemaOf(schema);\n\t\t\treturn { key, id, kind, ...(jsonSchema ? { jsonSchema } : {}) };\n\t\t}),\n\t\tchecks,\n\t};\n}\n\nexport interface InspectOptions {\n\t/** The workspace root. */\n\troot: string;\n\t/** Its construct globs. */\n\tpatterns: readonly string[];\n\t/** The values to check, by key. Only credentials keys are looked at. */\n\tvalues?: Readonly<Record<string, string>>;\n}\n\nconst Issue = z.object({ path: z.string(), message: z.string() });\n\n/** What the credentials worker answers. Checked: the worker ran project code. */\nconst CredentialsAnswer = z.discriminatedUnion('reason', [\n\tz.object({\n\t\treason: z.literal('inspected'),\n\t\tschemas: z.array(\n\t\t\tz.object({\n\t\t\t\tkey: z.string(),\n\t\t\t\tid: z.string(),\n\t\t\t\tkind: z.enum(['external-api', 'credential']),\n\t\t\t\tjsonSchema: z.record(z.string(), z.unknown()).optional(),\n\t\t\t}),\n\t\t),\n\t\tchecks: z.record(\n\t\t\tz.string(),\n\t\t\tz.object({ ok: z.boolean(), issues: z.array(Issue) }),\n\t\t),\n\t}),\n\tz.object({\n\t\treason: z.literal('failed'),\n\t\terror: z.object({ name: z.string(), message: z.string() }).loose(),\n\t}),\n]);\n\n/** How long loading the constructs to check credentials may take. */\nconst INSPECT_TIMEOUT_MS = 60_000;\n\n/**\n * The workspace's credential schemas, and what each of `values` comes to —\n * loaded in the run's sandbox when there is one, here otherwise.\n */\nexport async function inspectCredentials(\n\toptions: InspectOptions,\n): Promise<CredentialInspection> {\n\tconst sandbox = activeSandbox();\n\tif (!sandbox) {\n\t\treturn (await loadCredentialSchemasHere(options)).inspect(\n\t\t\toptions.values ?? {},\n\t\t);\n\t}\n\n\tconst secrets = Object.fromEntries(\n\t\tObject.entries(options.values ?? {}).filter(([key]) =>\n\t\t\tkey.endsWith('_CREDENTIALS'),\n\t\t),\n\t);\n\tconst { value } = await runWorker(sandbox, 'credentials check', {\n\t\tname: 'credentials-worker',\n\t\targs: [JSON.stringify({ patterns: options.patterns, cwd: options.root })],\n\t\tcwd: options.root,\n\t\ttimeoutMs: INSPECT_TIMEOUT_MS,\n\t\tschema: CredentialsAnswer,\n\t\t...(Object.keys(secrets).length > 0 ? { secrets } : {}),\n\t});\n\tif (value.reason === 'failed') {\n\t\tthrow new ConstructDiscoveryFailed(value.error.name, value.error.message);\n\t}\n\tconst { schemas, checks } = value;\n\treturn {\n\t\tschemas: schemas.map(({ jsonSchema, ...rest }) => ({\n\t\t\t...rest,\n\t\t\t...(jsonSchema ? { jsonSchema } : {}),\n\t\t})),\n\t\tchecks,\n\t};\n}\n\n/** The constructs loaded once, here, and asked about as often as needed. */\nasync function loadCredentialSchemasHere(options: InspectOptions): Promise<{\n\tinspect(\n\t\tvalues: Readonly<Record<string, string>>,\n\t): Promise<CredentialInspection>;\n}> {\n\tconst sources: Record<string, ConstructSource> = {};\n\tconst manifest = await discover({\n\t\tpatterns: [...options.patterns],\n\t\tcwd: options.root,\n\t\tsources,\n\t});\n\tconst live = liveCredentials(manifest, sources);\n\treturn { inspect: (values) => inspectLive(live, values) };\n}\n\n/** The schemas, and a check of one candidate value at a time. */\nexport interface CredentialSchemas {\n\tschemas: CredentialSchemaInfo[];\n\t/** `raw` against `key`'s schema; ok for a key no schema describes. */\n\tcheck(key: string, raw: string): Promise<CredentialCheck>;\n}\n\n/**\n * The workspace's credential schemas, for a command that checks values one\n * at a time as they are typed. In-process the constructs are loaded once;\n * in a sandbox each check is a run of the worker.\n */\nexport async function loadCredentialSchemas(\n\toptions: Omit<InspectOptions, 'values'>,\n): Promise<CredentialSchemas> {\n\tconst here = activeSandbox()\n\t\t? undefined\n\t\t: await loadCredentialSchemasHere(options);\n\tconst inspect = (values: Readonly<Record<string, string>>) =>\n\t\there ? here.inspect(values) : inspectCredentials({ ...options, values });\n\n\tconst { schemas } = await inspect({});\n\treturn {\n\t\tschemas,\n\t\tasync check(key, raw) {\n\t\t\tif (!schemas.some((s) => s.key === key)) return { ok: true, issues: [] };\n\t\t\tconst { checks } = await inspect({ [key]: raw });\n\t\t\treturn checks[key] ?? { ok: true, issues: [] };\n\t\t},\n\t};\n}\n\n/** One stored credential its schema refuses. */\nexport interface InvalidCredential {\n\tkey: string;\n\tissues: CredentialIssue[];\n}\n\n/** An issue as the line that names it: `SHIPPING_CREDENTIALS.apiKey: …`. */\nexport function issueLine(key: string, issue: CredentialIssue): string {\n\treturn `${key}${issue.path ? `.${issue.path}` : ''}: ${issue.message}`;\n}\n\n/**\n * Credentials their construct's schema refuses — on their way into the\n * stage's secrets, or already there when a deploy reads them. The values are\n * never in the message: only where each is wrong, and why.\n */\nexport class CredentialsInvalid extends GkmError {\n\tconstructor(\n\t\treadonly stage: string,\n\t\treadonly invalid: readonly InvalidCredential[],\n\t\t/** Whether a value was being set (and was not saved), or deployed. */\n\t\treadonly during: 'set' | 'deploy',\n\t) {\n\t\tconst lines = invalid.flatMap(({ key, issues }) =>\n\t\t\tissues.map((issue) => ` ${issueLine(key, issue)}`),\n\t\t);\n\t\tconst keys = invalid.map((i) => i.key);\n\t\tsuper(\n\t\t\tduring === 'set'\n\t\t\t\t? `${keys.join(', ')} is not what its construct's schema describes, ` +\n\t\t\t\t\t\t`so nothing was saved:\\n\\n${lines.join('\\n')}\\n\\n` +\n\t\t\t\t\t\t`Set a value that matches, or let gkm ask for each field: ` +\n\t\t\t\t\t\t`gkm secrets:add --stage ${stage}`\n\t\t\t\t: `The stage '${stage}' holds ${keys.length === 1 ? 'a credential' : 'credentials'} ` +\n\t\t\t\t\t\t`${keys.length === 1 ? \"its construct's schema refuses\" : \"their constructs' schemas refuse\"}, ` +\n\t\t\t\t\t\t`and every app reading ${keys.length === 1 ? 'it' : 'them'} would fail ` +\n\t\t\t\t\t\t`as it starts:\\n\\n${lines.join('\\n')}\\n\\n` +\n\t\t\t\t\t\t`Set ${keys.length === 1 ? 'it' : 'them'} again, field by field: ` +\n\t\t\t\t\t\t`gkm secrets:add --stage ${stage}`,\n\t\t);\n\t\tthis.name = 'CredentialsInvalid';\n\t}\n}\n\n/**\n * Every credential the stage holds for a construct, against its schema —\n * before a deploy builds anything with one the app would refuse as it\n * starts. Loads nothing when the stage holds none.\n *\n * @throws {CredentialsInvalid} naming each key and every issue\n */\nexport async function assertStageCredentials(options: {\n\troot: string;\n\tpatterns: readonly string[];\n\tmanifest: ConstructManifest;\n\tstage: string;\n\tsupplied: Readonly<Record<string, string>>;\n}): Promise<void> {\n\tconst values = Object.fromEntries(\n\t\tcredentialKeys(options.manifest)\n\t\t\t.map(({ key }) => [key, options.supplied[key]] as const)\n\t\t\t.filter((entry): entry is [string, string] => entry[1] !== undefined),\n\t);\n\tif (Object.keys(values).length === 0) return;\n\n\tconst { checks } = await inspectCredentials({\n\t\troot: options.root,\n\t\tpatterns: options.patterns,\n\t\tvalues,\n\t});\n\tconst invalid = Object.entries(checks)\n\t\t.filter(([, check]) => !check.ok)\n\t\t.map(([key, check]) => ({ key, issues: check.issues }))\n\t\t.sort((a, b) => a.key.localeCompare(b.key));\n\tif (invalid.length > 0) {\n\t\tthrow new CredentialsInvalid(options.stage, invalid, 'deploy');\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { t as GkmError } from "./errors-D8Gwp5kU.mjs";
|
|
2
|
+
import { n as driversFor, r as eventsBackendsIn, t as cacheBackendsIn } from "./drivers-CDjpjakg.mjs";
|
|
2
3
|
import { createRequire } from "node:module";
|
|
3
4
|
import { extname, join } from "node:path";
|
|
4
|
-
import { readFile, readdir, stat } from "node:fs/promises";
|
|
5
|
+
import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
5
7
|
import { DATABASE_FOLDERS, MIGRATIONS_ROOT, canonicalId, migrationTargets, provideKey } from "@geekmidas/manifest";
|
|
6
8
|
import { pathToFileURL } from "node:url";
|
|
7
9
|
import pg from "pg";
|
|
@@ -137,6 +139,58 @@ async function sqlMigration(file, raw) {
|
|
|
137
139
|
} };
|
|
138
140
|
}
|
|
139
141
|
//#endregion
|
|
142
|
+
//#region src/migrate/seedDrivers.ts
|
|
143
|
+
/**
|
|
144
|
+
* The drivers a seed run registers before any seed runs.
|
|
145
|
+
*
|
|
146
|
+
* The seed runner is an entry point gkm owns, like the generated server and
|
|
147
|
+
* the test harness, so it registers what they register — from the same
|
|
148
|
+
* {@link driversFor}, so the two cannot drift. A seed then reaches a bucket or
|
|
149
|
+
* a cache through the construct's service, exactly as a handler does, and no
|
|
150
|
+
* application code names a provider.
|
|
151
|
+
*
|
|
152
|
+
* The registrations are written to a module under `.gkm/` and imported from
|
|
153
|
+
* there, rather than imported by gkm itself: a registry is a module-level map,
|
|
154
|
+
* so it has to be the copy the app's constructs resolve — which is the one a
|
|
155
|
+
* bare specifier finds from the project root, not the one beside gkm.
|
|
156
|
+
*/
|
|
157
|
+
/** The drivers a seed run needs could not be loaded from the project. */
|
|
158
|
+
var SeedDriversUnresolved = class extends GkmError {
|
|
159
|
+
root;
|
|
160
|
+
cause;
|
|
161
|
+
constructor(root, cause) {
|
|
162
|
+
super(`Could not load the drivers seeds run with from ${root} — ${cause instanceof Error ? cause.message : String(cause)}. They are the ones the app's own entry registers; install the package it names where the project's constructs are declared.`);
|
|
163
|
+
this.root = root;
|
|
164
|
+
this.cause = cause;
|
|
165
|
+
this.name = "SeedDriversUnresolved";
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* Register the drivers a generated entry for this project would: storage when
|
|
170
|
+
* it installs `@geekmidas/storage`, the cache backend its caches resolve to,
|
|
171
|
+
* and the broker its topics and queues do. Nothing when it declares none.
|
|
172
|
+
*/
|
|
173
|
+
async function registerSeedDrivers(options) {
|
|
174
|
+
const drivers = driversFor({
|
|
175
|
+
appRoot: options.root,
|
|
176
|
+
cache: cacheBackendsIn(options.manifest, options.backends.cache),
|
|
177
|
+
events: eventsBackendsIn(options.manifest, options.backends.events)
|
|
178
|
+
});
|
|
179
|
+
if (!drivers.setup) return;
|
|
180
|
+
const content = `${drivers.imports}\n\n${drivers.setup}\n`;
|
|
181
|
+
const dir = join(options.root, ".gkm");
|
|
182
|
+
const file = join(dir, "seed-drivers.mjs");
|
|
183
|
+
await mkdir(dir, { recursive: true });
|
|
184
|
+
await writeFile(file, content);
|
|
185
|
+
const url = pathToFileURL(file);
|
|
186
|
+
url.searchParams.set("v", createHash("sha256").update(content).digest("hex").slice(0, 12));
|
|
187
|
+
try {
|
|
188
|
+
await import(url.href);
|
|
189
|
+
} catch (error) {
|
|
190
|
+
throw new SeedDriversUnresolved(options.root, error);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
//#endregion
|
|
140
194
|
//#region src/migrate/databases.ts
|
|
141
195
|
/**
|
|
142
196
|
* Bring each construct's schema up to its migrations folder.
|
|
@@ -279,9 +333,13 @@ async function migrateDatabases(options) {
|
|
|
279
333
|
* plugins included — on the owner's connection. One written against
|
|
280
334
|
* `Kysely<DB>` with a `CamelCasePlugin` writes `isEditable` here as it does in
|
|
281
335
|
* a handler or a test.
|
|
336
|
+
*
|
|
337
|
+
* And with the drivers the stage's entry registers, so a seed reaching a
|
|
338
|
+
* bucket or a cache through its construct gets the client a handler would.
|
|
282
339
|
*/
|
|
283
340
|
async function seedDatabases(options) {
|
|
284
341
|
const runs = [];
|
|
342
|
+
let registered = false;
|
|
285
343
|
for (const target of await targetsFor(options)) {
|
|
286
344
|
const folder = join(options.root, target.seeds);
|
|
287
345
|
if ((await migrationFiles(folder)).size === 0) {
|
|
@@ -291,6 +349,10 @@ async function seedDatabases(options) {
|
|
|
291
349
|
});
|
|
292
350
|
continue;
|
|
293
351
|
}
|
|
352
|
+
if (!registered) {
|
|
353
|
+
await registerSeedDrivers(options);
|
|
354
|
+
registered = true;
|
|
355
|
+
}
|
|
294
356
|
const seeded = await withOwner(options, target, clientConfigOf(options, target), async (db, kysely) => {
|
|
295
357
|
const names = [];
|
|
296
358
|
for (const seed of await loadSeeds(folder, kysely.sql)) {
|
|
@@ -517,6 +579,6 @@ async function kyselyFrom(from) {
|
|
|
517
579
|
}
|
|
518
580
|
}
|
|
519
581
|
//#endregion
|
|
520
|
-
export {
|
|
582
|
+
export { MigrationHasNoUp as _, NoSuchMigrationTarget as a, UnknownMigrationFolder as c, pendingMigrations as d, plannedSeeds as f, DuplicateMigration as g, registerSeedDrivers as h, NoOwnerCredential as i, migrateAndSeed as l, SeedDriversUnresolved as m, MigrationFailed as n, SeedFailed as o, seedDatabases as p, MigrationsOutsideFolder as r, UnknownDatabaseFolder as s, KyselyNotFound as t, migrateDatabases as u, SeedHasNoSeed as v, migrationFiles as y };
|
|
521
583
|
|
|
522
|
-
//# sourceMappingURL=databases-
|
|
584
|
+
//# sourceMappingURL=databases-6GD0tI2F.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"databases-6GD0tI2F.mjs","names":[],"sources":["../src/migrate/provider.ts","../src/migrate/seedDrivers.ts","../src/migrate/databases.ts"],"sourcesContent":["/**\n * One construct's migrations and seeds, read from its folders.\n *\n * Two kinds of file, told apart by extension rather than by configuration: a\n * script exports `up` (and may export `down`) — or `seed(db, { stage })`, in\n * `seeds/` — and a\n * `.sql` file is run whole. The second is what makes a folder independent of\n * the client the app uses — Better Auth's schema is SQL whatever the\n * application queries with.\n */\n\nimport { readdir, readFile, stat } from 'node:fs/promises';\nimport { extname, join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { SeedContext } from '@geekmidas/constructs';\nimport type { Kysely, sql } from 'kysely';\nimport type { Migration, MigrationProvider } from 'kysely/migration';\nimport { GkmError } from '../errors';\n\nconst SCRIPTS = new Set(['.ts', '.mts', '.js', '.mjs']);\n\n/** Two files in one folder that would be one migration. */\nexport class DuplicateMigration extends GkmError {\n\tconstructor(\n\t\treadonly folder: string,\n\t\treadonly migration: string,\n\t) {\n\t\tsuper(\n\t\t\t`${folder} has two migrations named '${migration}' — a script and a .sql file ` +\n\t\t\t\t`with the same name. A migration is recorded by name, so only one of ` +\n\t\t\t\t`them could ever run; rename or remove the other.`,\n\t\t);\n\t\tthis.name = 'DuplicateMigration';\n\t}\n}\n\n/** A script in a migrations folder that exports no `up`. */\nexport class MigrationHasNoUp extends GkmError {\n\tconstructor(readonly file: string) {\n\t\tsuper(\n\t\t\t`${file} is in a migrations folder but exports no \\`up\\` function. ` +\n\t\t\t\t`Export \\`async function up(db: Kysely<unknown>)\\`, or move the file ` +\n\t\t\t\t`out of the folder if it is not a migration.`,\n\t\t);\n\t\tthis.name = 'MigrationHasNoUp';\n\t}\n}\n\n/** A script in a seeds folder that exports no `seed`. */\nexport class SeedHasNoSeed extends GkmError {\n\tconstructor(readonly file: string) {\n\t\tsuper(\n\t\t\t`${file} is in a seeds folder but exports no \\`seed\\` function. ` +\n\t\t\t\t`Export \\`async function seed(db, { stage })\\`, or move the ` +\n\t\t\t\t`file out of the folder if it is not a seed.`,\n\t\t);\n\t\tthis.name = 'SeedHasNoSeed';\n\t}\n}\n\n/**\n * What a seed is handed beside its database — `@geekmidas/constructs`'\n * `SeedContext`, whose `stage` is the union of the declared stages once\n * `.gkm/stages.d.ts` is generated.\n */\nexport type { SeedContext };\n\n/** One seed: what it is called, and what it does. */\nexport interface Seed {\n\tname: string;\n\trun: (db: Kysely<unknown>, context: SeedContext) => Promise<void>;\n}\n\n/**\n * The migration files in a folder, by name, without reading them.\n *\n * Also what `gkm dev` compares against a construct's history to report what\n * is pending, which is why it is separate from loading them.\n */\nexport async function migrationFiles(\n\tfolder: string,\n): Promise<Map<string, string>> {\n\tconst entries = await readdir(folder, { withFileTypes: true }).catch(\n\t\t(error: NodeJS.ErrnoException) => {\n\t\t\tif (error.code === 'ENOENT') return [];\n\t\t\tthrow error;\n\t\t},\n\t);\n\n\tconst files = new Map<string, string>();\n\tfor (const entry of entries) {\n\t\tif (!entry.isFile() || !isMigration(entry.name)) continue;\n\n\t\tconst name = entry.name.slice(0, -extname(entry.name).length);\n\t\tif (files.has(name)) throw new DuplicateMigration(folder, name);\n\n\t\tfiles.set(name, join(folder, entry.name));\n\t}\n\n\treturn files;\n}\n\n/** A Kysely provider over one construct's folder. */\nexport function folderProvider(\n\tfolder: string,\n\traw: typeof sql,\n): MigrationProvider {\n\treturn {\n\t\tasync getMigrations() {\n\t\t\tconst migrations: Record<string, Migration> = {};\n\n\t\t\tfor (const [name, file] of await migrationFiles(folder)) {\n\t\t\t\tmigrations[name] =\n\t\t\t\t\textname(file) === '.sql'\n\t\t\t\t\t\t? await sqlMigration(file, raw)\n\t\t\t\t\t\t: await scriptMigration(file);\n\t\t\t}\n\n\t\t\treturn migrations;\n\t\t},\n\t};\n}\n\n/**\n * The seeds in a folder, loaded, in name order.\n *\n * Every one runs on every pass — there is no history to consult — so the order\n * is the only thing between two seeds where one reads what another writes.\n * Name them to sort that way.\n */\nexport async function loadSeeds(\n\tfolder: string,\n\traw: typeof sql,\n): Promise<Seed[]> {\n\tconst files = [...(await migrationFiles(folder))].sort(([a], [b]) =>\n\t\ta < b ? -1 : a > b ? 1 : 0,\n\t);\n\n\tconst seeds: Seed[] = [];\n\tfor (const [name, file] of files) {\n\t\tseeds.push({\n\t\t\tname,\n\t\t\trun:\n\t\t\t\textname(file) === '.sql'\n\t\t\t\t\t? (await sqlMigration(file, raw)).up\n\t\t\t\t\t: await scriptSeed(file),\n\t\t});\n\t}\n\n\treturn seeds;\n}\n\n/**\n * A seed script, imported as it is on disk now.\n *\n * Keyed by its modification time: a seed is run again after it is edited, and\n * a process that has imported it once would otherwise run the old one.\n */\nasync function scriptSeed(file: string): Promise<Seed['run']> {\n\tconst url = pathToFileURL(file);\n\turl.searchParams.set('mtime', String((await stat(file)).mtimeMs));\n\tconst module = (await import(url.href)) as { seed?: unknown };\n\tif (typeof module.seed !== 'function') throw new SeedHasNoSeed(file);\n\n\treturn module.seed as Seed['run'];\n}\n\nfunction isMigration(file: string): boolean {\n\tif (file.endsWith('.d.ts')) return false;\n\tif (/\\.(spec|test)\\.[cm]?[jt]s$/.test(file)) return false;\n\n\tconst extension = extname(file);\n\treturn extension === '.sql' || SCRIPTS.has(extension);\n}\n\nasync function scriptMigration(file: string): Promise<Migration> {\n\tconst module = (await import(pathToFileURL(file).href)) as Partial<Migration>;\n\tif (typeof module.up !== 'function') throw new MigrationHasNoUp(file);\n\n\treturn {\n\t\tup: module.up,\n\t\t...(typeof module.down === 'function' ? { down: module.down } : {}),\n\t};\n}\n\n/**\n * A `.sql` file, run whole.\n *\n * One query rather than split on `;`: with no parameters, Postgres takes\n * several statements in one message, and splitting by hand breaks on the first\n * `;` inside a string or a function body. There is no `down` — a generated\n * schema is rolled back by a migration that says how, not by guessing.\n */\nasync function sqlMigration(file: string, raw: typeof sql): Promise<Migration> {\n\tconst statements = await readFile(file, 'utf-8');\n\n\treturn {\n\t\tup: async (db: Kysely<unknown>) => {\n\t\t\tawait raw.raw(statements).execute(db);\n\t\t},\n\t};\n}\n","/**\n * The drivers a seed run registers before any seed runs.\n *\n * The seed runner is an entry point gkm owns, like the generated server and\n * the test harness, so it registers what they register — from the same\n * {@link driversFor}, so the two cannot drift. A seed then reaches a bucket or\n * a cache through the construct's service, exactly as a handler does, and no\n * application code names a provider.\n *\n * The registrations are written to a module under `.gkm/` and imported from\n * there, rather than imported by gkm itself: a registry is a module-level map,\n * so it has to be the copy the app's constructs resolve — which is the one a\n * bare specifier finds from the project root, not the one beside gkm.\n */\n\nimport { createHash } from 'node:crypto';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { ConstructManifest } from '@geekmidas/manifest';\nimport { GkmError } from '../errors';\nimport {\n\tcacheBackendsIn,\n\tdriversFor,\n\teventsBackendsIn,\n} from '../generators/drivers';\nimport type { CacheBackend, EventsBackend } from '../types';\n\n/** Which backends the stage being seeded resolves its declarations to. */\nexport interface SeedBackends {\n\tcache: CacheBackend;\n\tevents: EventsBackend;\n}\n\n/** The drivers a seed run needs could not be loaded from the project. */\nexport class SeedDriversUnresolved extends GkmError {\n\tconstructor(\n\t\treadonly root: string,\n\t\toverride readonly cause: unknown,\n\t) {\n\t\tsuper(\n\t\t\t`Could not load the drivers seeds run with from ${root} — ` +\n\t\t\t\t`${cause instanceof Error ? cause.message : String(cause)}. ` +\n\t\t\t\t`They are the ones the app's own entry registers; install the ` +\n\t\t\t\t`package it names where the project's constructs are declared.`,\n\t\t);\n\t\tthis.name = 'SeedDriversUnresolved';\n\t}\n}\n\n/**\n * Register the drivers a generated entry for this project would: storage when\n * it installs `@geekmidas/storage`, the cache backend its caches resolve to,\n * and the broker its topics and queues do. Nothing when it declares none.\n */\nexport async function registerSeedDrivers(options: {\n\troot: string;\n\tmanifest: ConstructManifest;\n\tbackends: SeedBackends;\n}): Promise<void> {\n\tconst drivers = driversFor({\n\t\tappRoot: options.root,\n\t\tcache: cacheBackendsIn(options.manifest, options.backends.cache),\n\t\tevents: eventsBackendsIn(options.manifest, options.backends.events),\n\t});\n\tif (!drivers.setup) return;\n\n\tconst content = `${drivers.imports}\\n\\n${drivers.setup}\\n`;\n\tconst dir = join(options.root, '.gkm');\n\tconst file = join(dir, 'seed-drivers.mjs');\n\tawait mkdir(dir, { recursive: true });\n\tawait writeFile(file, content);\n\n\t// Keyed by content: registration is idempotent, but a process seeding\n\t// twice after the declarations changed must load the new set.\n\tconst url = pathToFileURL(file);\n\turl.searchParams.set(\n\t\t'v',\n\t\tcreateHash('sha256').update(content).digest('hex').slice(0, 12),\n\t);\n\n\ttry {\n\t\tawait import(url.href);\n\t} catch (error) {\n\t\tthrow new SeedDriversUnresolved(options.root, error);\n\t}\n}\n","/**\n * Bring each construct's schema up to its migrations folder.\n *\n * Which constructs, in what order, from which folder, is `migrationTargets`'\n * answer and nobody else's. What is decided here is only how one target is\n * run: as its owner, in its own schema, with a history of its own.\n */\n\nimport { readdir } from 'node:fs/promises';\nimport { createRequire } from 'node:module';\nimport { join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport {\n\ttype ConstructManifest,\n\tcanonicalId,\n\tDATABASE_FOLDERS,\n\tMIGRATIONS_ROOT,\n\ttype MigrationTarget,\n\tmigrationTargets,\n\tprovideKey,\n} from '@geekmidas/manifest';\nimport type { Kysely, KyselyConfig } from 'kysely';\nimport type { Migrator } from 'kysely/migration';\nimport pg from 'pg';\nimport { GkmError } from '../errors';\nimport type { ConstructSource } from '../reconcile/discover';\nimport { folderProvider, loadSeeds, migrationFiles } from './provider';\nimport { registerSeedDrivers, type SeedBackends } from './seedDrivers';\n\nexport interface DatabasesOptions {\n\t/** The project root — where `db/` lives. */\n\troot: string;\n\tmanifest: ConstructManifest;\n\t/**\n\t * Where each construct was declared. A construct's migrations run with the\n\t * Kysely its own file resolves, which is the one its migrations import.\n\t */\n\tsources?: Readonly<Record<string, ConstructSource>>;\n\t/** The resolved environment: each construct's owner URL is read from it. */\n\tenv: Readonly<Record<string, string | undefined>>;\n\t/** One construct, by name. All of them when absent. */\n\tonly?: string;\n}\n\nexport interface MigrationRun {\n\ttarget: MigrationTarget;\n\t/** The migrations this run applied, in order. */\n\tapplied: string[];\n}\n\nexport interface SeedOptions extends DatabasesOptions {\n\t/** The stage being seeded, handed to every seed. */\n\tstage: string;\n\t/**\n\t * What the stage's caches and topics resolve to — which drivers a seed is\n\t * run with, as the stage's own entry would register them.\n\t */\n\tbackends: SeedBackends;\n}\n\nexport interface SeedRun {\n\ttarget: MigrationTarget;\n\t/** The seeds this run ran, in order — every one, every time. */\n\tseeded: string[];\n}\n\n/** The seeds a run would run for one construct, read without connecting. */\nexport interface PlannedSeeds {\n\ttarget: MigrationTarget;\n\t/** In the order they would run. */\n\tseeds: string[];\n}\n\nexport interface PendingMigrations {\n\ttarget: MigrationTarget;\n\tpending: string[];\n}\n\n/** A folder under `db/` that names no construct. */\nexport class UnknownMigrationFolder extends GkmError {\n\tconstructor(\n\t\treadonly folder: string,\n\t\treadonly known: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`${folder} names no database construct, so its migrations would never ` +\n\t\t\t\t`run. ${known.length > 0 ? `The folders that do: ${known.join(', ')}.` : 'This project declares no database.'} ` +\n\t\t\t\t`Rename the folder after the construct it belongs to.`,\n\t\t);\n\t\tthis.name = 'UnknownMigrationFolder';\n\t}\n}\n\n/** A construct was asked for by a name that takes no migrations. */\nexport class NoSuchMigrationTarget extends GkmError {\n\tconstructor(\n\t\treadonly construct: string,\n\t\treadonly known: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`'${construct}' is not a database construct. ` +\n\t\t\t\t(known.length > 0\n\t\t\t\t\t? `The ones with migrations: ${known.join(', ')}.`\n\t\t\t\t\t: 'This project declares no database.'),\n\t\t);\n\t\tthis.name = 'NoSuchMigrationTarget';\n\t}\n}\n\n/**\n * A migration left directly in a construct's folder, where nothing reads it.\n *\n * Migrations moved into `migrations/` so seeds could sit beside them. A file\n * still at the old level would otherwise never run, and nothing would say so.\n */\nexport class MigrationsOutsideFolder extends GkmError {\n\tconstructor(\n\t\treadonly folder: string,\n\t\treadonly files: readonly string[],\n\t) {\n\t\tsuper(\n\t\t\t`${folder} has ${files.join(', ')} directly inside it, where nothing ` +\n\t\t\t\t`runs them. Migrations live in ${folder}/migrations/ and seeds in ` +\n\t\t\t\t`${folder}/seeds/ — move ${files.length === 1 ? 'it' : 'them'} there.`,\n\t\t);\n\t\tthis.name = 'MigrationsOutsideFolder';\n\t}\n}\n\n/** A folder inside a construct's folder that is neither `migrations` nor `seeds`. */\nexport class UnknownDatabaseFolder extends GkmError {\n\tconstructor(readonly folder: string) {\n\t\tsuper(\n\t\t\t`${folder} is neither migrations/ nor seeds/, so nothing in it would ` +\n\t\t\t\t`ever run. A construct's folder holds those two; rename or remove it.`,\n\t\t);\n\t\tthis.name = 'UnknownDatabaseFolder';\n\t}\n}\n\n/** A seed failed; its own writes are rolled back, the ones before it stay. */\nexport class SeedFailed extends Error {\n\tconstructor(\n\t\treadonly construct: string,\n\t\treadonly seed: string,\n\t\toverride readonly cause: unknown,\n\t) {\n\t\tsuper(\n\t\t\t`${construct}: seed '${seed}' failed — ` +\n\t\t\t\t`${cause instanceof Error ? cause.message : String(cause)}. ` +\n\t\t\t\t`Its writes were rolled back; fix it and run it again.`,\n\t\t);\n\t\tthis.name = 'SeedFailed';\n\t}\n}\n\n/** A construct with roles has no owner URL to migrate with. */\nexport class NoOwnerCredential extends GkmError {\n\tconstructor(\n\t\treadonly construct: string,\n\t\treadonly key: string,\n\t) {\n\t\tsuper(\n\t\t\t`${construct} has no ${key} to migrate with. Migrations run as the owner ` +\n\t\t\t\t`role — the runtime one cannot create a table — and nothing ` +\n\t\t\t\t`resolved its URL. Is the stage reconciled?`,\n\t\t);\n\t\tthis.name = 'NoOwnerCredential';\n\t}\n}\n\n/** A migration failed; the ones before it in the run stay applied. */\nexport class MigrationFailed extends Error {\n\tconstructor(\n\t\treadonly construct: string,\n\t\treadonly migration: string | undefined,\n\t\toverride readonly cause: unknown,\n\t) {\n\t\tsuper(\n\t\t\t`${construct}: migration ${migration ? `'${migration}' ` : ''}failed — ` +\n\t\t\t\t`${cause instanceof Error ? cause.message : String(cause)}`,\n\t\t);\n\t\tthis.name = 'MigrationFailed';\n\t}\n}\n\n/** The project's Kysely could not be found from where a database is declared. */\nexport class KyselyNotFound extends GkmError {\n\tconstructor(readonly from: string) {\n\t\tsuper(\n\t\t\t`Could not resolve 'kysely' from ${from}. Migrations run with the ` +\n\t\t\t\t`project's own Kysely — install it where the database is declared.`,\n\t\t);\n\t\tthis.name = 'KyselyNotFound';\n\t}\n}\n\n/** Apply every pending migration, construct by construct, parents first. */\nexport async function migrateDatabases(\n\toptions: DatabasesOptions,\n): Promise<MigrationRun[]> {\n\tconst runs: MigrationRun[] = [];\n\n\tfor (const target of await targetsFor(options)) {\n\t\t// No folder, or an empty one, is nothing to do — and no reason to\n\t\t// connect, which a construct nobody has written a migration for yet\n\t\t// should not need.\n\t\tconst files = await migrationFiles(join(options.root, target.migrations));\n\t\tif (files.size === 0) {\n\t\t\truns.push({ target, applied: [] });\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst applied = await withMigrator(options, target, async (migrator) => {\n\t\t\tconst { error, results = [] } = await migrator.migrateToLatest();\n\t\t\tif (error) {\n\t\t\t\tconst failed = results.find((result) => result.status === 'Error');\n\t\t\t\tthrow new MigrationFailed(target.id, failed?.migrationName, error);\n\t\t\t}\n\n\t\t\treturn results\n\t\t\t\t.filter((result) => result.status === 'Success')\n\t\t\t\t.map((result) => result.migrationName);\n\t\t});\n\n\t\truns.push({ target, applied });\n\t}\n\n\treturn runs;\n}\n\n/**\n * Run every construct's seeds, parents first — each one, every time, on every\n * stage, production included. Each is handed the stage, so a seed decides\n * what belongs where.\n *\n * Seeds are reference data kept up to date by being run again, so there is no\n * history: a seed is an upsert, and a changed one is applied by the next run.\n * Each runs in its own transaction, as the construct's owner, so a failure\n * leaves nothing half-written. Assumes the schema is migrated —\n * {@link migrateAndSeed} is what makes that true.\n *\n * A seed is handed the client the app gets — the construct's `clientConfig`,\n * plugins included — on the owner's connection. One written against\n * `Kysely<DB>` with a `CamelCasePlugin` writes `isEditable` here as it does in\n * a handler or a test.\n *\n * And with the drivers the stage's entry registers, so a seed reaching a\n * bucket or a cache through its construct gets the client a handler would.\n */\nexport async function seedDatabases(options: SeedOptions): Promise<SeedRun[]> {\n\tconst runs: SeedRun[] = [];\n\tlet registered = false;\n\n\tfor (const target of await targetsFor(options)) {\n\t\tconst folder = join(options.root, target.seeds);\n\t\tif ((await migrationFiles(folder)).size === 0) {\n\t\t\truns.push({ target, seeded: [] });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!registered) {\n\t\t\tawait registerSeedDrivers(options);\n\t\t\tregistered = true;\n\t\t}\n\n\t\tconst config = clientConfigOf(options, target);\n\t\tconst seeded = await withOwner(\n\t\t\toptions,\n\t\t\ttarget,\n\t\t\tconfig,\n\t\t\tasync (db, kysely) => {\n\t\t\t\tconst names: string[] = [];\n\t\t\t\tfor (const seed of await loadSeeds(folder, kysely.sql)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait db\n\t\t\t\t\t\t\t.transaction()\n\t\t\t\t\t\t\t.execute((trx) => seed.run(trx, { stage: options.stage }));\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tthrow new SeedFailed(target.id, seed.name, error);\n\t\t\t\t\t}\n\t\t\t\t\tnames.push(seed.name);\n\t\t\t\t}\n\t\t\t\treturn names;\n\t\t\t},\n\t\t);\n\n\t\truns.push({ target, seeded });\n\t}\n\n\treturn runs;\n}\n\n/**\n * The seeds {@link seedDatabases} would run, construct by construct, parents\n * first, in the order it would run them — read from the folders alone, with\n * no connection. What a dry run lists. Constructs with none are left out.\n */\nexport async function plannedSeeds(\n\toptions: Pick<DatabasesOptions, 'root' | 'manifest' | 'only'>,\n): Promise<PlannedSeeds[]> {\n\tconst planned: PlannedSeeds[] = [];\n\tfor (const target of await targetsFor(options)) {\n\t\tconst files = await migrationFiles(join(options.root, target.seeds));\n\t\tif (files.size === 0) continue;\n\t\tplanned.push({ target, seeds: [...files.keys()].sort() });\n\t}\n\treturn planned;\n}\n\n/**\n * Migrate, then seed: a seed only ever runs against the schema it was written\n * for.\n *\n * With `only`, the constructs it lives in are migrated too — a tenant's seed\n * cannot run before the database that owns its schema exists — and only it is\n * seeded.\n */\nexport async function migrateAndSeed(options: SeedOptions): Promise<{\n\tmigrations: MigrationRun[];\n\tseeds: SeedRun[];\n}> {\n\tconst migrations: MigrationRun[] = [];\n\tfor (const target of await withParents(options)) {\n\t\tmigrations.push(\n\t\t\t...(await migrateDatabases({ ...options, only: target.id })),\n\t\t);\n\t}\n\n\treturn { migrations, seeds: await seedDatabases(options) };\n}\n\n/** The targets `only` names, after the ones it lives in; all without it. */\nasync function withParents(\n\toptions: DatabasesOptions,\n): Promise<MigrationTarget[]> {\n\tconst chosen = await targetsFor(options);\n\tif (!options.only) return chosen;\n\n\tconst all = migrationTargets(options.manifest);\n\tconst ids = new Set<string>();\n\tfor (const target of chosen) {\n\t\tlet current: MigrationTarget | undefined = target;\n\t\twhile (current) {\n\t\t\tids.add(current.id);\n\t\t\tconst parent: string | undefined = current.of;\n\t\t\tcurrent = parent ? all.find((t) => t.id === parent) : undefined;\n\t\t}\n\t}\n\n\treturn all.filter((target) => ids.has(target.id));\n}\n\n/**\n * What each construct's folder has that its history does not — without\n * applying any of it. What `gkm dev` reports.\n */\nexport async function pendingMigrations(\n\toptions: DatabasesOptions,\n): Promise<PendingMigrations[]> {\n\tconst found: PendingMigrations[] = [];\n\n\tfor (const target of await targetsFor(options)) {\n\t\tconst files = await migrationFiles(join(options.root, target.migrations));\n\t\tif (files.size === 0) continue;\n\n\t\tconst pending = await withMigrator(options, target, async (migrator) =>\n\t\t\t(await migrator.getMigrations())\n\t\t\t\t.filter((migration) => migration.executedAt === undefined)\n\t\t\t\t.map((migration) => migration.name),\n\t\t);\n\n\t\tif (pending.length > 0) found.push({ target, pending });\n\t}\n\n\treturn found;\n}\n\n/**\n * The targets this run covers, with every folder under `db/` accounted for.\n *\n * A folder that names no construct is an error rather than something to skip:\n * a typo in its name is otherwise a migration that silently never runs.\n */\nasync function targetsFor(\n\toptions: Pick<DatabasesOptions, 'root' | 'manifest' | 'only'>,\n): Promise<MigrationTarget[]> {\n\tconst targets = migrationTargets(options.manifest);\n\tconst folders = targets.map((target) => target.folder);\n\n\tfor (const folder of await foldersIn(join(options.root, MIGRATIONS_ROOT))) {\n\t\tconst relative = `${MIGRATIONS_ROOT}/${folder}`;\n\t\tif (!folders.includes(relative)) {\n\t\t\tthrow new UnknownMigrationFolder(relative, folders);\n\t\t}\n\t\tawait checkLayout(options.root, relative);\n\t}\n\n\tif (!options.only) return targets;\n\n\tconst id = canonicalId(options.only);\n\tconst chosen = targets.filter((target) => target.id === id);\n\tif (chosen.length === 0) {\n\t\tthrow new NoSuchMigrationTarget(\n\t\t\toptions.only,\n\t\t\ttargets.map((target) => target.id),\n\t\t);\n\t}\n\n\treturn chosen;\n}\n\n/**\n * A construct's folder holds `migrations/` and `seeds/`, and nothing else —\n * anything beside them is a file or folder nothing would ever run.\n */\nasync function checkLayout(root: string, folder: string): Promise<void> {\n\tconst entries = await readdir(join(root, folder), { withFileTypes: true });\n\n\tconst loose = entries\n\t\t.filter((entry) => entry.isFile() && !entry.name.startsWith('.'))\n\t\t.map((entry) => entry.name);\n\tif (loose.length > 0) throw new MigrationsOutsideFolder(folder, loose);\n\n\tfor (const entry of entries) {\n\t\tif (\n\t\t\tentry.isDirectory() &&\n\t\t\t!(DATABASE_FOLDERS as readonly string[]).includes(entry.name)\n\t\t) {\n\t\t\tthrow new UnknownDatabaseFolder(`${folder}/${entry.name}`);\n\t\t}\n\t}\n}\n\nasync function foldersIn(dir: string): Promise<string[]> {\n\tconst entries = await readdir(dir, { withFileTypes: true }).catch(\n\t\t(error: NodeJS.ErrnoException) => {\n\t\t\tif (error.code === 'ENOENT') return [];\n\t\t\tthrow error;\n\t\t},\n\t);\n\n\treturn entries\n\t\t.filter((entry) => entry.isDirectory())\n\t\t.map((entry) => entry.name);\n}\n\n/**\n * A migrator for one target, connected as its owner.\n *\n * No `migrationTableSchema`: the owner role's `search_path` is pinned to the\n * construct's schema, so the history lands there — `app.kysely_migration` for\n * the database, `auth_database.kysely_migration` for its tenant — and two\n * constructs in one Postgres never share one.\n *\n * Unordered migrations are allowed. Files are timestamped, so a branch merged\n * after another's migration ran carries an older one; refusing it would make\n * every such merge a manual repair.\n *\n * The client is bare — none of the construct's plugins. A casing plugin\n * rewrites identifiers in schema-builder DDL too, and a migration must do the\n * same thing forever after it has run, so it cannot depend on configuration\n * that may change.\n */\nasync function withMigrator<T>(\n\toptions: DatabasesOptions,\n\ttarget: MigrationTarget,\n\trun: (migrator: Migrator) => Promise<T>,\n): Promise<T> {\n\treturn withOwner(options, target, {}, (db, { Migrator, sql }) =>\n\t\trun(\n\t\t\tnew Migrator({\n\t\t\t\tdb,\n\t\t\t\tprovider: folderProvider(join(options.root, target.migrations), sql),\n\t\t\t\tallowUnorderedMigrations: true,\n\t\t\t}),\n\t\t),\n\t);\n}\n\n/**\n * One target's database, connected as its owner and closed afterwards — what\n * migrations and seeds both run as, each with the client config it needs.\n */\nasync function withOwner<T>(\n\toptions: DatabasesOptions,\n\ttarget: MigrationTarget,\n\tconfig: Omit<KyselyConfig, 'dialect'>,\n\trun: (\n\t\tdb: Kysely<unknown>,\n\t\tkysely: Awaited<ReturnType<typeof kyselyFrom>>,\n\t) => Promise<T>,\n): Promise<T> {\n\tconst from =\n\t\toptions.sources?.[target.id]?.file ??\n\t\t(target.of ? options.sources?.[target.of]?.file : undefined) ??\n\t\tjoin(options.root, 'package.json');\n\tconst kysely = await kyselyFrom(from);\n\n\tconst db: Kysely<unknown> = new kysely.Kysely<unknown>({\n\t\t...config,\n\t\tdialect: new kysely.PostgresDialect({\n\t\t\tpool: new pg.Pool(poolConfig(ownerUrl(options, target))),\n\t\t}),\n\t});\n\n\ttry {\n\t\treturn await run(db, kysely);\n\t} finally {\n\t\tawait db.destroy();\n\t}\n}\n\n/**\n * What the construct builds its clients with besides a dialect — its plugins\n * and logging — read from the construct discovery already imported.\n *\n * A tenant's is its own: `database.schema('Auth', { plugins })` declares the\n * client for its tables, not the parent's. With no construct to ask (a\n * manifest without sources), the client is bare.\n */\nfunction clientConfigOf(\n\toptions: DatabasesOptions,\n\ttarget: MigrationTarget,\n): Omit<KyselyConfig, 'dialect'> {\n\tconst construct = options.sources?.[target.id]?.construct;\n\tif (typeof construct !== 'object' || construct === null) return {};\n\tif (!('clientConfig' in construct)) return {};\n\treturn (construct.clientConfig as Omit<KyselyConfig, 'dialect'>) ?? {};\n}\n\n/**\n * The owner's URL, with no fallback to the runtime one.\n *\n * The runtime role can create nothing, so falling back would only move the\n * failure to the first `CREATE TABLE` and make it read like a permissions\n * bug. The one exception is a database declared `roles: false`, where there is\n * no owner — both URLs are the master credential by design.\n */\nfunction ownerUrl(options: DatabasesOptions, target: MigrationTarget): string {\n\tconst key = provideKey(target.id, 'ownerUrl');\n\tconst owner = options.env[key];\n\tif (owner) return owner;\n\n\tconst database = options.manifest[target.of ?? target.id];\n\tif (database?.kind === 'database' && database.roles === false) {\n\t\tconst url = options.env[provideKey(target.id, 'url')];\n\t\tif (url) return url;\n\t}\n\n\tthrow new NoOwnerCredential(target.id, key);\n}\n\n/**\n * Pool settings for a URL, with `?search_path=` as the startup option Postgres\n * reads. Only a `roles: false` URL carries it — a role pins its own.\n */\nfunction poolConfig(url: string): pg.PoolConfig {\n\tconst parsed = new URL(url);\n\tconst searchPath = parsed.searchParams.get('search_path');\n\tif (!searchPath) return { connectionString: url };\n\n\tparsed.searchParams.delete('search_path');\n\treturn {\n\t\tconnectionString: parsed.toString(),\n\t\toptions: `-c search_path=${searchPath}`,\n\t};\n}\n\n/** Kysely as the project resolves it from `from`. */\nasync function kyselyFrom(from: string) {\n\tconst require = createRequire(from);\n\n\ttry {\n\t\tconst [main, migration] = await Promise.all([\n\t\t\timport(pathToFileURL(require.resolve('kysely')).href),\n\t\t\timport(pathToFileURL(require.resolve('kysely/migration')).href),\n\t\t]);\n\n\t\treturn {\n\t\t\tKysely: main.Kysely as typeof import('kysely').Kysely,\n\t\t\tPostgresDialect:\n\t\t\t\tmain.PostgresDialect as typeof import('kysely').PostgresDialect,\n\t\t\tsql: main.sql as typeof import('kysely').sql,\n\t\t\tMigrator:\n\t\t\t\tmigration.Migrator as typeof import('kysely/migration').Migrator,\n\t\t};\n\t} catch {\n\t\tthrow new KyselyNotFound(from);\n\t}\n}\n"],"mappings":"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"}
|