@geekmidas/cli 10.0.0-alpha.124 → 10.0.0-alpha.125
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-BN1dODm9.mjs} +2 -2
- package/dist/{GoDaddyProvider-55x4o-4z.mjs.map → GoDaddyProvider-BN1dODm9.mjs.map} +1 -1
- package/dist/{GoDaddyProvider-0z5RAN1k.cjs → GoDaddyProvider-BTdtqhI_.cjs} +2 -2
- package/dist/{GoDaddyProvider-0z5RAN1k.cjs.map → GoDaddyProvider-BTdtqhI_.cjs.map} +1 -1
- package/dist/{LegacyStateStore-DRpB-yC5.cjs → LegacyStateStore-C2S8TGwx.cjs} +3 -3
- package/dist/{LegacyStateStore-DRpB-yC5.cjs.map → LegacyStateStore-C2S8TGwx.cjs.map} +1 -1
- package/dist/{LegacyStateStore-C-vumKSN.mjs → LegacyStateStore-DgXmuG87.mjs} +3 -3
- package/dist/{LegacyStateStore-C-vumKSN.mjs.map → LegacyStateStore-DgXmuG87.mjs.map} +1 -1
- package/dist/{LocalStateStore-C3ummuDT.cjs → LocalStateStore-CaJw9H-3.cjs} +2 -2
- package/dist/{LocalStateStore-C3ummuDT.cjs.map → LocalStateStore-CaJw9H-3.cjs.map} +1 -1
- package/dist/{LocalStateStore-CtOjpV1w.mjs → LocalStateStore-ojY_BiMK.mjs} +2 -2
- package/dist/{LocalStateStore-CtOjpV1w.mjs.map → LocalStateStore-ojY_BiMK.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-BSPkxhrx.mjs} +2 -2
- package/dist/{S3StateStore-BC4Jm3Tw.mjs.map → S3StateStore-BSPkxhrx.mjs.map} +1 -1
- package/dist/{S3StateStore-BeArp0aF.cjs → S3StateStore-BqugXIcb.cjs} +2 -2
- package/dist/{S3StateStore-BeArp0aF.cjs.map → S3StateStore-BqugXIcb.cjs.map} +1 -1
- package/dist/{SSMStateStore-DcstR6cW.cjs → SSMStateStore-B0OsuT_k.cjs} +2 -2
- package/dist/{SSMStateStore-DcstR6cW.cjs.map → SSMStateStore-B0OsuT_k.cjs.map} +1 -1
- package/dist/{SSMStateStore-Crl76aYZ.mjs → SSMStateStore-DM85OiH0.mjs} +2 -2
- package/dist/{SSMStateStore-Crl76aYZ.mjs.map → SSMStateStore-DM85OiH0.mjs.map} +1 -1
- package/dist/{SubscriberGenerator-C3QTae-R.cjs → SubscriberGenerator-BDUp7OeY.cjs} +3 -3
- package/dist/SubscriberGenerator-BDUp7OeY.cjs.map +1 -0
- package/dist/{SubscriberGenerator-COAVPgM-.mjs → SubscriberGenerator-ocQ2yj0K.mjs} +3 -3
- package/dist/{SubscriberGenerator-C3QTae-R.cjs.map → SubscriberGenerator-ocQ2yj0K.mjs.map} +1 -1
- package/dist/{add-CIjmgzkb.mjs → add-C7ZBXIzM.mjs} +6 -6
- package/dist/{add-CIjmgzkb.mjs.map → add-C7ZBXIzM.mjs.map} +1 -1
- package/dist/{add-BFjb6mMq.cjs → add-CrxvmSpq.cjs} +6 -6
- package/dist/{add-BFjb6mMq.cjs.map → add-CrxvmSpq.cjs.map} +1 -1
- package/dist/{bundler-CiUoIsku.cjs → bundler-DVUXW95p.cjs} +5 -5
- package/dist/{bundler-CiUoIsku.cjs.map → bundler-DVUXW95p.cjs.map} +1 -1
- package/dist/{bundler-D6KFNpQk.mjs → bundler-DpZ9uBGN.mjs} +5 -5
- package/dist/{bundler-D6KFNpQk.mjs.map → bundler-DpZ9uBGN.mjs.map} +1 -1
- package/dist/{cli-r4eUr98C.cjs → cli-BMRhE6cZ.cjs} +3 -3
- package/dist/{cli-r4eUr98C.cjs.map → cli-BMRhE6cZ.cjs.map} +1 -1
- package/dist/{cli-DNtSTtMc.mjs → cli-BWfYyy1k.mjs} +3 -3
- package/dist/{cli-DNtSTtMc.mjs.map → cli-BWfYyy1k.mjs.map} +1 -1
- package/dist/{compose-DJvvmF3X.mjs → compose-BFmdLig3.mjs} +232 -36
- package/dist/compose-BFmdLig3.mjs.map +1 -0
- package/dist/{compose-BfXXWJSp.cjs → compose-Bqcy0lqo.cjs} +232 -36
- package/dist/compose-Bqcy0lqo.cjs.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/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-D8pUA9Y0.mjs} +797 -25
- package/dist/deploy-D8pUA9Y0.mjs.map +1 -0
- package/dist/{deploy-BbI1UMh3.cjs → deploy-DVrNjX1X.cjs} +796 -24
- package/dist/deploy-DVrNjX1X.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-MM7c3IE0.mjs → dokploy-CzDGNB6A.mjs} +2 -2
- package/dist/{dokploy-MM7c3IE0.mjs.map → dokploy-CzDGNB6A.mjs.map} +1 -1
- package/dist/{dokploy-C0aQrCgs.cjs → dokploy-TtK6Zyl3.cjs} +2 -2
- package/dist/{dokploy-C0aQrCgs.cjs.map → dokploy-TtK6Zyl3.cjs.map} +1 -1
- package/dist/{drivers-Chb5Akov.mjs → drivers-C-VqMtld.mjs} +2 -2
- package/dist/{drivers-Chb5Akov.mjs.map → drivers-C-VqMtld.mjs.map} +1 -1
- package/dist/{drivers-CQ32PB5w.cjs → drivers-L29WvE95.cjs} +2 -2
- package/dist/{drivers-CQ32PB5w.cjs.map → drivers-L29WvE95.cjs.map} +1 -1
- package/dist/{eas-CJoys9yh.cjs → eas-D3clzkni.cjs} +2 -2
- package/dist/{eas-CJoys9yh.cjs.map → eas-D3clzkni.cjs.map} +1 -1
- package/dist/{eas-1Ee6kql0.mjs → eas-DaobzDks.mjs} +2 -2
- package/dist/{eas-1Ee6kql0.mjs.map → eas-DaobzDks.mjs.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-Bo9VlRnl.cjs → encryption-DBkIFiR2.cjs} +3 -3
- package/dist/{encryption-Bo9VlRnl.cjs.map → encryption-DBkIFiR2.cjs.map} +1 -1
- package/dist/{encryption-B8Bk1Mvu.mjs → encryption-DV31gEY8.mjs} +3 -3
- package/dist/{encryption-B8Bk1Mvu.mjs.map → encryption-DV31gEY8.mjs.map} +1 -1
- package/dist/{engine-BuinpJfS.mjs → engine-CFOR9h6X.mjs} +138 -13
- package/dist/engine-CFOR9h6X.mjs.map +1 -0
- package/dist/{engine-esxTxcIx.cjs → engine-CuZUGbEh.cjs} +138 -13
- package/dist/engine-CuZUGbEh.cjs.map +1 -0
- package/dist/{github-BEA4K3_X.cjs → github-CsvtWSBW.cjs} +41 -6
- package/dist/github-CsvtWSBW.cjs.map +1 -0
- package/dist/{github-BUlKJfOV.mjs → github-Nep8pI4_.mjs} +41 -6
- package/dist/github-Nep8pI4_.mjs.map +1 -0
- package/dist/{googlePlay-CiqAS2ma.cjs → googlePlay-C-UfBXJU.cjs} +3 -3
- package/dist/{googlePlay-CiqAS2ma.cjs.map → googlePlay-C-UfBXJU.cjs.map} +1 -1
- package/dist/{googlePlay-CK05QiTq.mjs → googlePlay-lF7Atm_N.mjs} +3 -3
- package/dist/{googlePlay-CK05QiTq.mjs.map → googlePlay-lF7Atm_N.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 +147 -65
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +147 -65
- package/dist/index.mjs.map +1 -1
- package/dist/{migrate-DeQJBexh.cjs → migrate-Dp3GhFnf.cjs} +4 -4
- package/dist/{migrate-DeQJBexh.cjs.map → migrate-Dp3GhFnf.cjs.map} +1 -1
- package/dist/{migrate-CnbvrVag.mjs → migrate-NfbPVhi9.mjs} +4 -4
- package/dist/{migrate-CnbvrVag.mjs.map → migrate-NfbPVhi9.mjs.map} +1 -1
- package/dist/{migrate-BzCHT9qs.mjs → migrate-_sBX0pve.mjs} +3 -3
- package/dist/{migrate-BzCHT9qs.mjs.map → migrate-_sBX0pve.mjs.map} +1 -1
- package/dist/{migrate-C-hmbjpG.cjs → migrate-hlNKNWmg.cjs} +3 -3
- package/dist/{migrate-C-hmbjpG.cjs.map → migrate-hlNKNWmg.cjs.map} +1 -1
- 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-BuUVaZVy.mjs} +2 -2
- package/dist/{publish-BISBrrqR.mjs.map → publish-BuUVaZVy.mjs.map} +1 -1
- package/dist/{publish-DtSIB-hZ.cjs → publish-ZOo4xEuZ.cjs} +2 -2
- package/dist/{publish-DtSIB-hZ.cjs.map → publish-ZOo4xEuZ.cjs.map} +1 -1
- package/dist/{ready-DqsyadOs.mjs → ready-Ca883OvY.mjs} +6 -6
- package/dist/{ready-DqsyadOs.mjs.map → ready-Ca883OvY.mjs.map} +1 -1
- package/dist/{ready-IVGu-q18.cjs → ready-qnqp6JAY.cjs} +6 -6
- package/dist/{ready-IVGu-q18.cjs.map → ready-qnqp6JAY.cjs.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-BCU9pYDx.mjs} +3 -3
- package/dist/{resolve-BT7fkPN5.mjs.map → resolve-BCU9pYDx.mjs.map} +1 -1
- package/dist/{resolve-C7GKQcE4.cjs → resolve-C9QqOl5t.cjs} +3 -3
- package/dist/{resolve-C7GKQcE4.cjs.map → resolve-C9QqOl5t.cjs.map} +1 -1
- package/dist/{rollback-BEiB-Pje.cjs → rollback-CTWdDBgB.cjs} +5 -5
- package/dist/{rollback-BEiB-Pje.cjs.map → rollback-CTWdDBgB.cjs.map} +1 -1
- package/dist/{rollback-DbP0KuDw.mjs → rollback-CWyyTQ0B.mjs} +5 -5
- package/dist/{rollback-DbP0KuDw.mjs.map → rollback-CWyyTQ0B.mjs.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 +1 -1
- package/dist/sandbox/migrate-worker.mjs +1 -1
- package/dist/{seeds-rG-Evfz9.mjs → seeds-CK7w79VC.mjs} +516 -39
- package/dist/seeds-CK7w79VC.mjs.map +1 -0
- package/dist/{seeds-DOfxmDRO.cjs → seeds-CPEcmoPn.cjs} +599 -38
- package/dist/seeds-CPEcmoPn.cjs.map +1 -0
- package/dist/{serverSetup-xGw1fxuZ.mjs → serverSetup-BAPNuNEX.mjs} +6 -6
- package/dist/{serverSetup-xGw1fxuZ.mjs.map → serverSetup-BAPNuNEX.mjs.map} +1 -1
- package/dist/{serverSetup-CWWVcU6Y.cjs → serverSetup-C6t6Vtt7.cjs} +6 -6
- package/dist/{serverSetup-CWWVcU6Y.cjs.map → serverSetup-C6t6Vtt7.cjs.map} +1 -1
- package/dist/{sniffer-C7O9Pna_.cjs → sniffer-DdX_WN_-.cjs} +8 -8
- package/dist/{sniffer-C7O9Pna_.cjs.map → sniffer-DdX_WN_-.cjs.map} +1 -1
- package/dist/{sniffer-DVPgfyHr.mjs → sniffer-g9v7cqDN.mjs} +8 -8
- package/dist/{sniffer-DVPgfyHr.mjs.map → sniffer-g9v7cqDN.mjs.map} +1 -1
- package/dist/{snsSubscriptions-CSkteK2J.cjs → snsSubscriptions-5Cqww8S7.cjs} +15 -3
- package/dist/snsSubscriptions-5Cqww8S7.cjs.map +1 -0
- package/dist/{snsSubscriptions-CvBIGGp0.mjs → snsSubscriptions-BmYeeTH8.mjs} +4 -4
- package/dist/snsSubscriptions-BmYeeTH8.mjs.map +1 -0
- package/dist/{stage-2EKpzPQ1.mjs → stage-C-I2dVw1.mjs} +6 -6
- package/dist/{stage-2EKpzPQ1.mjs.map → stage-C-I2dVw1.mjs.map} +1 -1
- package/dist/{stage-fRfFtLwj.cjs → stage-CUE5pMmw.cjs} +6 -6
- package/dist/{stage-fRfFtLwj.cjs.map → stage-CUE5pMmw.cjs.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-COAVPgM-.mjs.map +0 -1
- package/dist/compose-BfXXWJSp.cjs.map +0 -1
- package/dist/compose-DJvvmF3X.mjs.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/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/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,21 +1,21 @@
|
|
|
1
1
|
const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
|
|
2
2
|
const require_errors = require("./errors-DMC4Umsb.cjs");
|
|
3
3
|
const require_credentials = require("./credentials-D7XJypNd.cjs");
|
|
4
|
-
const require_workspace = require("./workspace-
|
|
5
|
-
const require_snsSubscriptions = require("./snsSubscriptions-
|
|
4
|
+
const require_workspace = require("./workspace-Du4Afb03.cjs");
|
|
5
|
+
const require_snsSubscriptions = require("./snsSubscriptions-5Cqww8S7.cjs");
|
|
6
6
|
const require_define = require("./define-crmMcXFS.cjs");
|
|
7
|
-
const require_seeds = require("./seeds-
|
|
7
|
+
const require_seeds = require("./seeds-CPEcmoPn.cjs");
|
|
8
8
|
const require_derive = require("./derive-DAbo49sm.cjs");
|
|
9
|
-
const require_SubscriberGenerator = require("./SubscriberGenerator-
|
|
9
|
+
const require_SubscriberGenerator = require("./SubscriberGenerator-BDUp7OeY.cjs");
|
|
10
10
|
const require_identity = require("./identity-CbLfgQNT.cjs");
|
|
11
|
-
const require_discover = require("./discover-
|
|
11
|
+
const require_discover = require("./discover-DL6h-J97.cjs");
|
|
12
12
|
const require_sandbox = require("./sandbox-CHv3OYXg.cjs");
|
|
13
13
|
const require_config = require("./config.cjs");
|
|
14
|
-
const require_resolve = require("./resolve-
|
|
14
|
+
const require_resolve = require("./resolve-C9QqOl5t.cjs");
|
|
15
15
|
const require_local = require("./local-OPC9BCZt.cjs");
|
|
16
|
-
const require_sniffer = require("./sniffer-
|
|
16
|
+
const require_sniffer = require("./sniffer-DdX_WN_-.cjs");
|
|
17
17
|
const require_projectBucket = require("./projectBucket-BBbQ1lHF.cjs");
|
|
18
|
-
const require_credentialSchemas = require("./credentialSchemas-
|
|
18
|
+
const require_credentialSchemas = require("./credentialSchemas-DFxvGEwa.cjs");
|
|
19
19
|
let node_path = require("node:path");
|
|
20
20
|
let node_crypto = require("node:crypto");
|
|
21
21
|
let _geekmidas_manifest = require("@geekmidas/manifest");
|
|
@@ -221,10 +221,13 @@ function openResource(bucket, pattern) {
|
|
|
221
221
|
}
|
|
222
222
|
/**
|
|
223
223
|
* The bucket's own policy: every request refused unless it came over TLS,
|
|
224
|
-
* and — only when a file server opens paths on it —
|
|
225
|
-
*
|
|
224
|
+
* and — only when a file server opens paths on it — `s3:GetObject` on
|
|
225
|
+
* exactly those prefixes: to anyone, or, when a CDN serves them, to
|
|
226
|
+
* CloudFront alone, for exactly the stage's distributions. Behind a CDN the
|
|
227
|
+
* bucket is never public: a key outside the open prefixes is refused to
|
|
228
|
+
* CloudFront too, so the edge answers it 403.
|
|
226
229
|
*/
|
|
227
|
-
function bucketPolicy(bucket, open = []) {
|
|
230
|
+
function bucketPolicy(bucket, open = [], options = {}) {
|
|
228
231
|
const statements = [{
|
|
229
232
|
Sid: "GkmDenyInsecureTransport",
|
|
230
233
|
Effect: "Deny",
|
|
@@ -233,12 +236,21 @@ function bucketPolicy(bucket, open = []) {
|
|
|
233
236
|
Resource: [bucketArn(bucket), `${bucketArn(bucket)}/*`],
|
|
234
237
|
Condition: { Bool: { "aws:SecureTransport": "false" } }
|
|
235
238
|
}];
|
|
236
|
-
|
|
239
|
+
const resources = [...new Set(open.map((p) => openResource(bucket, p)))].sort();
|
|
240
|
+
if (open.length > 0 && options.cdn) statements.push({
|
|
241
|
+
Sid: "GkmCdnRead",
|
|
242
|
+
Effect: "Allow",
|
|
243
|
+
Principal: { Service: "cloudfront.amazonaws.com" },
|
|
244
|
+
Action: "s3:GetObject",
|
|
245
|
+
Resource: resources,
|
|
246
|
+
Condition: { StringEquals: { "AWS:SourceArn": [...new Set(options.cdn.distributionArns)].sort() } }
|
|
247
|
+
});
|
|
248
|
+
else if (open.length > 0) statements.push({
|
|
237
249
|
Sid: "GkmOpenPaths",
|
|
238
250
|
Effect: "Allow",
|
|
239
251
|
Principal: "*",
|
|
240
252
|
Action: "s3:GetObject",
|
|
241
|
-
Resource:
|
|
253
|
+
Resource: resources
|
|
242
254
|
});
|
|
243
255
|
return {
|
|
244
256
|
Version: "2012-10-17",
|
|
@@ -287,7 +299,7 @@ function canonical(value, key) {
|
|
|
287
299
|
}
|
|
288
300
|
if (value && typeof value === "object") return Object.fromEntries(Object.keys(value).sort().map((k) => {
|
|
289
301
|
const v = value[k];
|
|
290
|
-
return [k, canonical(k === "Action" || k === "Resource" || k === "AWS" ? Array.isArray(v) ? v : [v] : v, k)];
|
|
302
|
+
return [k, canonical(k === "Action" || k === "Resource" || k === "AWS" || k === "AWS:SourceArn" ? Array.isArray(v) ? v : [v] : v, k)];
|
|
291
303
|
}));
|
|
292
304
|
return value;
|
|
293
305
|
}
|
|
@@ -333,7 +345,7 @@ function identityTags(ctx, id) {
|
|
|
333
345
|
];
|
|
334
346
|
}
|
|
335
347
|
/** A read whose "there is none" answer is one of `missing`. */
|
|
336
|
-
async function readOr$
|
|
348
|
+
async function readOr$3(read, missing) {
|
|
337
349
|
try {
|
|
338
350
|
return await read();
|
|
339
351
|
} catch (error) {
|
|
@@ -363,7 +375,7 @@ async function ensureIamUser(ctx, clients, input) {
|
|
|
363
375
|
key: `iam-user:${id}`,
|
|
364
376
|
type: "iam-user"
|
|
365
377
|
};
|
|
366
|
-
const found = await readOr$
|
|
378
|
+
const found = await readOr$3(() => iam.send(new IAM.GetUserCommand({ UserName: user })), ["NoSuchEntity", "NoSuchEntityException"]);
|
|
367
379
|
if (found?.User) {
|
|
368
380
|
const tags = await iam.send(new IAM.ListUserTagsCommand({ UserName: user }));
|
|
369
381
|
const tag = (key) => tags.Tags?.find((t) => t.Key === key)?.Value;
|
|
@@ -383,7 +395,7 @@ async function ensureIamUser(ctx, clients, input) {
|
|
|
383
395
|
await ctx.state.ready(entry, user);
|
|
384
396
|
});
|
|
385
397
|
const exists = Boolean(found?.User) || !ctx.dryRun;
|
|
386
|
-
const current = exists ? await readOr$
|
|
398
|
+
const current = exists ? await readOr$3(() => iam.send(new IAM.GetUserPolicyCommand({
|
|
387
399
|
UserName: user,
|
|
388
400
|
PolicyName: input.policyName
|
|
389
401
|
})), ["NoSuchEntity", "NoSuchEntityException"]) : void 0;
|
|
@@ -797,6 +809,738 @@ async function verifyStageBackups(input) {
|
|
|
797
809
|
}
|
|
798
810
|
}
|
|
799
811
|
//#endregion
|
|
812
|
+
//#region src/providers/dnsWriter.ts
|
|
813
|
+
/**
|
|
814
|
+
* The DNS records a provider asks for — a certificate's validation record, a
|
|
815
|
+
* CDN's name — written through the stage's own DNS providers.
|
|
816
|
+
*
|
|
817
|
+
* The same machinery the deploy's DNS step uses for the stack's hosts
|
|
818
|
+
* (`settleStackDns`), handed a plan of CNAMEs instead of the server's
|
|
819
|
+
* addresses: a record holding its value is left alone, one with another value
|
|
820
|
+
* is replaced and printed, and what is written is read back. A host under no
|
|
821
|
+
* domain in `dns`, or under a `manual` one, is printed for the person to
|
|
822
|
+
* create and reported back, so the provider can say what it is waiting on.
|
|
823
|
+
*/
|
|
824
|
+
async function writeProviderDns(records, options) {
|
|
825
|
+
const { log } = options;
|
|
826
|
+
const dns = options.workspace.dns ? require_seeds.normalizeDnsConfig(options.workspace.dns) : {};
|
|
827
|
+
const manual = [];
|
|
828
|
+
const domains = /* @__PURE__ */ new Map();
|
|
829
|
+
for (const record of records) {
|
|
830
|
+
const host = record.host.toLowerCase().replace(/\.$/, "");
|
|
831
|
+
const value = record.value.replace(/\.$/, "");
|
|
832
|
+
const domain = require_seeds.findRootDomain(host, dns);
|
|
833
|
+
if (!domain) {
|
|
834
|
+
log(` create at its DNS host: ${host} CNAME ${value}`);
|
|
835
|
+
manual.push(host);
|
|
836
|
+
continue;
|
|
837
|
+
}
|
|
838
|
+
const config = dns[domain];
|
|
839
|
+
const plan = domains.get(domain) ?? {
|
|
840
|
+
domain,
|
|
841
|
+
provider: typeof config.provider === "string" ? config.provider : "custom",
|
|
842
|
+
config,
|
|
843
|
+
records: []
|
|
844
|
+
};
|
|
845
|
+
const planned = {
|
|
846
|
+
host,
|
|
847
|
+
domain,
|
|
848
|
+
name: require_seeds.extractSubdomain(host, domain),
|
|
849
|
+
type: record.type,
|
|
850
|
+
value,
|
|
851
|
+
ttl: require_snsSubscriptions.recordTtl(config)
|
|
852
|
+
};
|
|
853
|
+
plan.records.push(planned);
|
|
854
|
+
domains.set(domain, plan);
|
|
855
|
+
}
|
|
856
|
+
if (domains.size === 0) return { manual };
|
|
857
|
+
const plans = [...domains.values()];
|
|
858
|
+
const tokens = await require_snsSubscriptions.dnsCredentials(options.stage, plans.map(({ domain, config }) => ({
|
|
859
|
+
domain,
|
|
860
|
+
config
|
|
861
|
+
})), options.credentials);
|
|
862
|
+
const applied = await require_snsSubscriptions.settleStackDns({
|
|
863
|
+
stage: options.stage,
|
|
864
|
+
server: { ipv4: "" },
|
|
865
|
+
domains: plans,
|
|
866
|
+
uncovered: []
|
|
867
|
+
}, {
|
|
868
|
+
...options.dryRun ? { dryRun: true } : { confirm: true },
|
|
869
|
+
log,
|
|
870
|
+
credentials: {
|
|
871
|
+
...tokens.godaddy ? { credential: tokens.godaddy } : {},
|
|
872
|
+
log
|
|
873
|
+
},
|
|
874
|
+
...tokens.hostinger ? { hostinger: tokens.hostinger } : {},
|
|
875
|
+
...options.providerFor ? { providerFor: options.providerFor } : {}
|
|
876
|
+
});
|
|
877
|
+
for (const change of applied.changes) {
|
|
878
|
+
if (change.action !== "manual") continue;
|
|
879
|
+
const host = plans.find((p) => p.domain === change.domain)?.records.find((r) => r.name === change.name)?.host;
|
|
880
|
+
if (host) manual.push(host);
|
|
881
|
+
}
|
|
882
|
+
return { manual: [...new Set(manual)].sort() };
|
|
883
|
+
}
|
|
884
|
+
//#endregion
|
|
885
|
+
//#region src/providers/s3/cdn.ts
|
|
886
|
+
/** AWS's managed `CachingOptimized` cache policy: path-keyed, gzip and brotli. */
|
|
887
|
+
const CACHING_OPTIMIZED = "658327ea-f89d-4fab-a63d-7e88639e58f6";
|
|
888
|
+
/** What an immutable path is served with. */
|
|
889
|
+
const IMMUTABLE_CACHE_CONTROL = "public, max-age=31536000, immutable";
|
|
890
|
+
/** The only region CloudFront reads a certificate from. */
|
|
891
|
+
const CDN_REGION = "us-east-1";
|
|
892
|
+
/** The distribution's bucket origin. */
|
|
893
|
+
const ORIGIN_ID = "bucket";
|
|
894
|
+
/** Its processors' origin: the stack's processor unit, at a host of its own. */
|
|
895
|
+
const PROCESSORS_ORIGIN_ID = "processors";
|
|
896
|
+
/**
|
|
897
|
+
* AWS's managed `CachingOptimizedForUncompressedObjects`: keyed on the path
|
|
898
|
+
* alone, and nothing re-compressed — a derivative is an image, already
|
|
899
|
+
* compressed, and its width is in the path, so nothing else may fragment it.
|
|
900
|
+
*/
|
|
901
|
+
const CACHING_OPTIMIZED_UNCOMPRESSED = "b2884449-e4de-46a7-ac36-70bc7f1ddd6d";
|
|
902
|
+
/** A CDN is a name on the stage's domain, and the stage has none. */
|
|
903
|
+
var FileServerCdnNeedsDomain = class extends require_errors.GkmError {
|
|
904
|
+
server;
|
|
905
|
+
stage;
|
|
906
|
+
constructor(server, stage) {
|
|
907
|
+
super(`'${server}' is served through a CDN on '${stage}', which answers on <fileserver>.<domain> — and '${stage}' has no domain. Set domains.${stage} in gkm.config.ts, or set deploy.objects.${stage}.cdn to false to serve it from the bucket's own endpoint.`);
|
|
908
|
+
this.server = server;
|
|
909
|
+
this.stage = stage;
|
|
910
|
+
this.name = "FileServerCdnNeedsDomain";
|
|
911
|
+
}
|
|
912
|
+
};
|
|
913
|
+
/**
|
|
914
|
+
* The certificate is waiting on its validation record: one the person has to
|
|
915
|
+
* create, or one that has not propagated yet. Everything up to it is
|
|
916
|
+
* recorded, so the next deploy carries on from here.
|
|
917
|
+
*/
|
|
918
|
+
var CdnCertificatePending = class extends require_errors.GkmError {
|
|
919
|
+
server;
|
|
920
|
+
host;
|
|
921
|
+
record;
|
|
922
|
+
reason;
|
|
923
|
+
constructor(server, host, record, reason) {
|
|
924
|
+
super((reason === "manual" ? `The certificate for ${host} ('${server}') is validated by a DNS record no DNS provider in gkm.config.ts can write. Create it at the domain's DNS host:
|
|
925
|
+
` : `The certificate for ${host} ('${server}') is not issued yet: ACM has not seen its validation record. It is written; DNS can take a while to answer with it. Check it resolves:
|
|
926
|
+
`) + ` ${record.name} CNAME ${record.value}\nthen deploy again — the certificate and everything before it are recorded, and the deploy carries on from there.`);
|
|
927
|
+
this.server = server;
|
|
928
|
+
this.host = host;
|
|
929
|
+
this.record = record;
|
|
930
|
+
this.reason = reason;
|
|
931
|
+
this.name = "CdnCertificatePending";
|
|
932
|
+
}
|
|
933
|
+
};
|
|
934
|
+
/** ACM gave up on the certificate. */
|
|
935
|
+
var CdnCertificateFailed = class extends require_errors.GkmError {
|
|
936
|
+
server;
|
|
937
|
+
host;
|
|
938
|
+
status;
|
|
939
|
+
reason;
|
|
940
|
+
constructor(server, host, status, reason) {
|
|
941
|
+
super(`ACM did not issue the certificate for ${host} ('${server}'): ${status}` + (reason ? ` (${reason})` : "") + ". A CAA record on the domain that does not allow amazon.com, or a validation record removed before it was checked, are the usual causes. Fix it and deploy again: a new certificate is requested.");
|
|
942
|
+
this.server = server;
|
|
943
|
+
this.host = host;
|
|
944
|
+
this.status = status;
|
|
945
|
+
this.reason = reason;
|
|
946
|
+
this.name = "CdnCertificateFailed";
|
|
947
|
+
}
|
|
948
|
+
};
|
|
949
|
+
/** Where a file server answers: `<fileserver>.<domain>`. */
|
|
950
|
+
function cdnHost(serverId, domain) {
|
|
951
|
+
return `${require_derive.appKey(serverId)}.${domain}`.toLowerCase();
|
|
952
|
+
}
|
|
953
|
+
/**
|
|
954
|
+
* The name the stage's CDN resources go by, within CloudFront's limits:
|
|
955
|
+
* letters, digits, `-` and `_`, and at most 64 characters (an origin access
|
|
956
|
+
* control's). Kept whole where it fits; otherwise shortened with a hash of
|
|
957
|
+
* the whole, so two long names never meet.
|
|
958
|
+
*/
|
|
959
|
+
function cdnName(scope, stage, serverId) {
|
|
960
|
+
const whole = `gkm-${scope}-${stage}-${require_derive.appKey(serverId)}`.replace(/[^A-Za-z0-9_-]/g, "-");
|
|
961
|
+
if (whole.length <= 56) return whole;
|
|
962
|
+
return `${whole.slice(0, 47)}-${hash(whole)}`;
|
|
963
|
+
}
|
|
964
|
+
function hash(value) {
|
|
965
|
+
let h = 2166136261;
|
|
966
|
+
for (let i = 0; i < value.length; i++) {
|
|
967
|
+
h ^= value.charCodeAt(i);
|
|
968
|
+
h = Math.imul(h, 16777619);
|
|
969
|
+
}
|
|
970
|
+
return (h >>> 0).toString(36).padStart(8, "0").slice(0, 8);
|
|
971
|
+
}
|
|
972
|
+
/**
|
|
973
|
+
* An open or immutable glob as a CloudFront path pattern. CloudFront's `*`
|
|
974
|
+
* crosses `/`, so a single star is as wide as a double one — the bucket
|
|
975
|
+
* policy reads it the same way, and the construct's own check is the
|
|
976
|
+
* stricter of the three.
|
|
977
|
+
*/
|
|
978
|
+
function pathPattern(glob) {
|
|
979
|
+
return glob.replace(/^\/+/, "").replace(/\*\*/g, "*");
|
|
980
|
+
}
|
|
981
|
+
/** A CloudFront list: its `Quantity` and, when it has some, its `Items`. */
|
|
982
|
+
function list(items) {
|
|
983
|
+
return items.length > 0 ? {
|
|
984
|
+
Quantity: items.length,
|
|
985
|
+
Items: [...items]
|
|
986
|
+
} : { Quantity: 0 };
|
|
987
|
+
}
|
|
988
|
+
/** One of the stage's response headers policies. */
|
|
989
|
+
function headersPolicyConfig(input) {
|
|
990
|
+
return {
|
|
991
|
+
Name: input.name,
|
|
992
|
+
Comment: input.comment,
|
|
993
|
+
...input.origins.length > 0 ? { CorsConfig: {
|
|
994
|
+
AccessControlAllowOrigins: list([...input.origins].sort()),
|
|
995
|
+
AccessControlAllowHeaders: {
|
|
996
|
+
Quantity: 1,
|
|
997
|
+
Items: ["*"]
|
|
998
|
+
},
|
|
999
|
+
AccessControlAllowMethods: {
|
|
1000
|
+
Quantity: 3,
|
|
1001
|
+
Items: [
|
|
1002
|
+
"GET",
|
|
1003
|
+
"HEAD",
|
|
1004
|
+
"OPTIONS"
|
|
1005
|
+
]
|
|
1006
|
+
},
|
|
1007
|
+
AccessControlAllowCredentials: false,
|
|
1008
|
+
AccessControlMaxAgeSec: 86400,
|
|
1009
|
+
OriginOverride: false
|
|
1010
|
+
} } : {},
|
|
1011
|
+
...input.immutable ? { CustomHeadersConfig: {
|
|
1012
|
+
Quantity: 1,
|
|
1013
|
+
Items: [{
|
|
1014
|
+
Header: "Cache-Control",
|
|
1015
|
+
Value: IMMUTABLE_CACHE_CONTROL,
|
|
1016
|
+
Override: true
|
|
1017
|
+
}]
|
|
1018
|
+
} } : {}
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
1021
|
+
/** The parts of a distribution's config this provider owns. */
|
|
1022
|
+
function distributionConfig(input) {
|
|
1023
|
+
const behaviour = (policy) => ({
|
|
1024
|
+
TargetOriginId: ORIGIN_ID,
|
|
1025
|
+
ViewerProtocolPolicy: "redirect-to-https",
|
|
1026
|
+
AllowedMethods: {
|
|
1027
|
+
Quantity: 3,
|
|
1028
|
+
Items: [
|
|
1029
|
+
"GET",
|
|
1030
|
+
"HEAD",
|
|
1031
|
+
"OPTIONS"
|
|
1032
|
+
],
|
|
1033
|
+
CachedMethods: {
|
|
1034
|
+
Quantity: 2,
|
|
1035
|
+
Items: ["GET", "HEAD"]
|
|
1036
|
+
}
|
|
1037
|
+
},
|
|
1038
|
+
Compress: true,
|
|
1039
|
+
CachePolicyId: CACHING_OPTIMIZED,
|
|
1040
|
+
...policy ? { ResponseHeadersPolicyId: policy } : {}
|
|
1041
|
+
});
|
|
1042
|
+
const patterns = [...new Set(input.immutable.map(pathPattern))].sort();
|
|
1043
|
+
const processors = input.processors;
|
|
1044
|
+
const processorPatterns = processors ? [...new Set(processors.prefixes.map((p) => `${pathPattern(p)}*`))].sort() : [];
|
|
1045
|
+
return {
|
|
1046
|
+
CallerReference: input.callerReference,
|
|
1047
|
+
Comment: input.comment,
|
|
1048
|
+
Enabled: true,
|
|
1049
|
+
Aliases: {
|
|
1050
|
+
Quantity: 1,
|
|
1051
|
+
Items: [input.host]
|
|
1052
|
+
},
|
|
1053
|
+
Origins: list([{
|
|
1054
|
+
Id: ORIGIN_ID,
|
|
1055
|
+
DomainName: input.bucketDomain,
|
|
1056
|
+
OriginPath: "",
|
|
1057
|
+
S3OriginConfig: { OriginAccessIdentity: "" },
|
|
1058
|
+
OriginAccessControlId: input.originAccessControlId
|
|
1059
|
+
}, ...processors ? [{
|
|
1060
|
+
Id: PROCESSORS_ORIGIN_ID,
|
|
1061
|
+
DomainName: processors.host,
|
|
1062
|
+
OriginPath: "",
|
|
1063
|
+
CustomOriginConfig: {
|
|
1064
|
+
HTTPPort: 80,
|
|
1065
|
+
HTTPSPort: 443,
|
|
1066
|
+
OriginProtocolPolicy: "https-only",
|
|
1067
|
+
OriginSslProtocols: {
|
|
1068
|
+
Quantity: 1,
|
|
1069
|
+
Items: ["TLSv1.2"]
|
|
1070
|
+
},
|
|
1071
|
+
OriginReadTimeout: 30,
|
|
1072
|
+
OriginKeepaliveTimeout: 5
|
|
1073
|
+
},
|
|
1074
|
+
CustomHeaders: {
|
|
1075
|
+
Quantity: 1,
|
|
1076
|
+
Items: [{
|
|
1077
|
+
HeaderName: require_seeds.ORIGIN_VERIFY_HEADER,
|
|
1078
|
+
HeaderValue: processors.secret
|
|
1079
|
+
}]
|
|
1080
|
+
}
|
|
1081
|
+
}] : []]),
|
|
1082
|
+
DefaultCacheBehavior: behaviour(input.corsPolicyId),
|
|
1083
|
+
CacheBehaviors: list([...processorPatterns.map((PathPattern) => ({
|
|
1084
|
+
...behaviour(input.corsPolicyId),
|
|
1085
|
+
TargetOriginId: PROCESSORS_ORIGIN_ID,
|
|
1086
|
+
Compress: false,
|
|
1087
|
+
CachePolicyId: CACHING_OPTIMIZED_UNCOMPRESSED,
|
|
1088
|
+
PathPattern
|
|
1089
|
+
})), ...patterns.map((PathPattern) => ({
|
|
1090
|
+
...behaviour(input.immutablePolicyId),
|
|
1091
|
+
PathPattern
|
|
1092
|
+
}))]),
|
|
1093
|
+
ViewerCertificate: {
|
|
1094
|
+
ACMCertificateArn: input.certificateArn,
|
|
1095
|
+
SSLSupportMethod: "sni-only",
|
|
1096
|
+
MinimumProtocolVersion: "TLSv1.2_2021",
|
|
1097
|
+
CloudFrontDefaultCertificate: false
|
|
1098
|
+
},
|
|
1099
|
+
HttpVersion: "http2and3",
|
|
1100
|
+
IsIPV6Enabled: true,
|
|
1101
|
+
DefaultRootObject: ""
|
|
1102
|
+
};
|
|
1103
|
+
}
|
|
1104
|
+
/**
|
|
1105
|
+
* Whether `current` already holds everything in `wanted`: each key `wanted`
|
|
1106
|
+
* names, recursively, with lists compared as sets. What else `current` holds
|
|
1107
|
+
* — logging, a WAF, geo restrictions set by hand — is left alone, and a
|
|
1108
|
+
* `CallerReference`, fixed at creation, is never compared.
|
|
1109
|
+
*/
|
|
1110
|
+
function holds(current, wanted, key) {
|
|
1111
|
+
if (key === "CallerReference") return true;
|
|
1112
|
+
if (Array.isArray(wanted)) return Array.isArray(current) && current.length === wanted.length && wanted.every((w) => current.some((c) => holds(c, w)));
|
|
1113
|
+
if (wanted && typeof wanted === "object") {
|
|
1114
|
+
if (!current || typeof current !== "object") return false;
|
|
1115
|
+
return Object.entries(wanted).every(([k, v]) => holds(current[k], v, k));
|
|
1116
|
+
}
|
|
1117
|
+
return current === wanted;
|
|
1118
|
+
}
|
|
1119
|
+
/** Header configs a policy may hold that this provider never sets. */
|
|
1120
|
+
const FOREIGN_HEADER_CONFIGS = [
|
|
1121
|
+
"CorsConfig",
|
|
1122
|
+
"CustomHeadersConfig",
|
|
1123
|
+
"SecurityHeadersConfig",
|
|
1124
|
+
"RemoveHeadersConfig",
|
|
1125
|
+
"ServerTimingHeadersConfig"
|
|
1126
|
+
];
|
|
1127
|
+
/** Whether a policy is exactly what is wanted: nothing missing, nothing more. */
|
|
1128
|
+
function sameHeadersPolicy(current, wanted) {
|
|
1129
|
+
if (!current || !holds(current, wanted)) return false;
|
|
1130
|
+
return FOREIGN_HEADER_CONFIGS.every((k) => {
|
|
1131
|
+
if (k in wanted) return true;
|
|
1132
|
+
const extra = current[k];
|
|
1133
|
+
return !extra || extra.Quantity === 0;
|
|
1134
|
+
});
|
|
1135
|
+
}
|
|
1136
|
+
const defaultCdnClients = async (credential) => {
|
|
1137
|
+
const CF = await import("@aws-sdk/client-cloudfront");
|
|
1138
|
+
const ACM = await import("@aws-sdk/client-acm");
|
|
1139
|
+
const config = await require_snsSubscriptions.awsClientConfig(credential, CDN_REGION);
|
|
1140
|
+
const cloudfront = require_snsSubscriptions.awsEndpoint(process.env, "CLOUDFRONT");
|
|
1141
|
+
const acm = require_snsSubscriptions.awsEndpoint(process.env, "ACM");
|
|
1142
|
+
return {
|
|
1143
|
+
CF,
|
|
1144
|
+
ACM,
|
|
1145
|
+
cloudfront: new CF.CloudFrontClient({
|
|
1146
|
+
...config,
|
|
1147
|
+
...cloudfront ? { endpoint: cloudfront } : {}
|
|
1148
|
+
}),
|
|
1149
|
+
acm: new ACM.ACMClient({
|
|
1150
|
+
...config,
|
|
1151
|
+
...acm ? { endpoint: acm } : {}
|
|
1152
|
+
}),
|
|
1153
|
+
wait: {
|
|
1154
|
+
timeoutMs: 9e5,
|
|
1155
|
+
intervalMs: 1e4
|
|
1156
|
+
}
|
|
1157
|
+
};
|
|
1158
|
+
};
|
|
1159
|
+
let makeCdnClients = defaultCdnClients;
|
|
1160
|
+
/** What an AWS SDK error is called, whichever field carries it. */
|
|
1161
|
+
function errorName$2(error) {
|
|
1162
|
+
const e = error;
|
|
1163
|
+
return e?.Code ?? e?.name ?? "";
|
|
1164
|
+
}
|
|
1165
|
+
async function readOr$2(read, missing) {
|
|
1166
|
+
try {
|
|
1167
|
+
return await read();
|
|
1168
|
+
} catch (error) {
|
|
1169
|
+
if (missing.includes(errorName$2(error))) return void 0;
|
|
1170
|
+
throw error;
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
1174
|
+
/** What stands in for an id a dry run would create. */
|
|
1175
|
+
const PLANNED = "(created by this deploy)";
|
|
1176
|
+
/** Each file server over a bucket, behind its own distribution. */
|
|
1177
|
+
async function ensureBucketCdn(ctx, input) {
|
|
1178
|
+
const domain = ctx.workspace.domains?.[ctx.stage];
|
|
1179
|
+
if (!domain) throw new FileServerCdnNeedsDomain(input.servers[0].id, ctx.stage);
|
|
1180
|
+
const clients = await makeCdnClients(ctx.credential);
|
|
1181
|
+
const out = {
|
|
1182
|
+
distributionArns: [],
|
|
1183
|
+
urls: {}
|
|
1184
|
+
};
|
|
1185
|
+
for (const server of input.servers) {
|
|
1186
|
+
const { arn, url } = await ensureServerCdn(ctx, clients, {
|
|
1187
|
+
...input,
|
|
1188
|
+
server,
|
|
1189
|
+
host: cdnHost(server.id, domain),
|
|
1190
|
+
processorHost: require_seeds.processorOriginHost(server.id, domain)
|
|
1191
|
+
});
|
|
1192
|
+
out.distributionArns.push(arn);
|
|
1193
|
+
out.urls[server.id] = url;
|
|
1194
|
+
}
|
|
1195
|
+
return out;
|
|
1196
|
+
}
|
|
1197
|
+
async function ensureServerCdn(ctx, clients, input) {
|
|
1198
|
+
const { server, host } = input;
|
|
1199
|
+
const name = cdnName(ctx.identity.scope, ctx.stage, server.id);
|
|
1200
|
+
const comment = `gkm ${ctx.identity.key} ${ctx.stage} ${server.id}`.slice(0, 128);
|
|
1201
|
+
const certificateArn = await ensureCertificate(ctx, clients, {
|
|
1202
|
+
id: server.id,
|
|
1203
|
+
host,
|
|
1204
|
+
name
|
|
1205
|
+
});
|
|
1206
|
+
const originAccessControlId = await ensureOriginAccessControl(ctx, clients, {
|
|
1207
|
+
id: server.id,
|
|
1208
|
+
name,
|
|
1209
|
+
bucket: input.bucket
|
|
1210
|
+
});
|
|
1211
|
+
const corsPolicyId = input.origins.length > 0 ? await ensureHeadersPolicy(ctx, clients, {
|
|
1212
|
+
id: server.id,
|
|
1213
|
+
kind: "cors",
|
|
1214
|
+
config: headersPolicyConfig({
|
|
1215
|
+
name: `${name}-cors`,
|
|
1216
|
+
comment: `${comment}: CORS`,
|
|
1217
|
+
origins: input.origins,
|
|
1218
|
+
immutable: false
|
|
1219
|
+
})
|
|
1220
|
+
}) : void 0;
|
|
1221
|
+
const immutablePolicyId = server.immutable.length > 0 ? await ensureHeadersPolicy(ctx, clients, {
|
|
1222
|
+
id: server.id,
|
|
1223
|
+
kind: "immutable",
|
|
1224
|
+
config: headersPolicyConfig({
|
|
1225
|
+
name: `${name}-immutable`,
|
|
1226
|
+
comment: `${comment}: CORS and Cache-Control immutable`,
|
|
1227
|
+
origins: input.origins,
|
|
1228
|
+
immutable: true
|
|
1229
|
+
})
|
|
1230
|
+
}) : void 0;
|
|
1231
|
+
const processors = server.processors?.length ? {
|
|
1232
|
+
prefixes: server.processors,
|
|
1233
|
+
host: input.processorHost,
|
|
1234
|
+
secret: await ensureOriginSecret(ctx, server.id)
|
|
1235
|
+
} : void 0;
|
|
1236
|
+
const distribution = await ensureDistribution(ctx, clients, {
|
|
1237
|
+
id: server.id,
|
|
1238
|
+
comment,
|
|
1239
|
+
config: distributionConfig({
|
|
1240
|
+
comment,
|
|
1241
|
+
callerReference: name,
|
|
1242
|
+
host,
|
|
1243
|
+
certificateArn,
|
|
1244
|
+
bucketDomain: `${input.bucket}.s3.${input.region}.amazonaws.com`,
|
|
1245
|
+
originAccessControlId,
|
|
1246
|
+
...corsPolicyId ? { corsPolicyId } : {},
|
|
1247
|
+
...immutablePolicyId ? { immutablePolicyId } : {},
|
|
1248
|
+
immutable: server.immutable,
|
|
1249
|
+
...processors ? { processors } : {}
|
|
1250
|
+
})
|
|
1251
|
+
});
|
|
1252
|
+
if (distribution.domainName !== PLANNED) {
|
|
1253
|
+
if ((await ctx.writeDns([{
|
|
1254
|
+
host,
|
|
1255
|
+
type: "CNAME",
|
|
1256
|
+
value: distribution.domainName
|
|
1257
|
+
}])).manual.includes(host)) ctx.log(` ${host} answers once that record exists — ${server.id}'s URL is https://${host}`);
|
|
1258
|
+
}
|
|
1259
|
+
return {
|
|
1260
|
+
arn: distribution.arn,
|
|
1261
|
+
url: `https://${host}`
|
|
1262
|
+
};
|
|
1263
|
+
}
|
|
1264
|
+
/**
|
|
1265
|
+
* The secret the CDN sends a file server's processors: the one in the stage's
|
|
1266
|
+
* secrets, or a new one written there — read by the stack, whose edge checks
|
|
1267
|
+
* it, when it composes.
|
|
1268
|
+
*/
|
|
1269
|
+
async function ensureOriginSecret(ctx, serverId) {
|
|
1270
|
+
const key = require_seeds.originSecretKey(serverId);
|
|
1271
|
+
const kept = ctx.secrets[key];
|
|
1272
|
+
if (kept) return kept;
|
|
1273
|
+
const secret = require_seeds.newOriginSecret();
|
|
1274
|
+
ctx.log(` ${serverId}: a new processor origin secret, kept as ${key}`);
|
|
1275
|
+
await ctx.writeSecrets({ [key]: secret });
|
|
1276
|
+
return secret;
|
|
1277
|
+
}
|
|
1278
|
+
/** The certificate for `host`: recorded, adopted, or requested — then issued. */
|
|
1279
|
+
async function ensureCertificate(ctx, clients, input) {
|
|
1280
|
+
const { ACM, acm } = clients;
|
|
1281
|
+
const { id, host } = input;
|
|
1282
|
+
const entry = {
|
|
1283
|
+
key: `acm-certificate:${id}`,
|
|
1284
|
+
type: "acm-certificate",
|
|
1285
|
+
data: { host }
|
|
1286
|
+
};
|
|
1287
|
+
const describe = (arn) => readOr$2(() => acm.send(new ACM.DescribeCertificateCommand({ CertificateArn: arn })), ["ResourceNotFoundException"]).then((out) => out?.Certificate);
|
|
1288
|
+
let arn;
|
|
1289
|
+
const recorded = ctx.state.record(entry.key);
|
|
1290
|
+
if (recorded?.id && recorded.data?.host === host) {
|
|
1291
|
+
const found = await describe(recorded.id);
|
|
1292
|
+
if (found && found.Status !== "FAILED" && found.Status !== "VALIDATION_TIMED_OUT" && found.Status !== "REVOKED" && found.Status !== "EXPIRED") arn = recorded.id;
|
|
1293
|
+
}
|
|
1294
|
+
if (!arn) {
|
|
1295
|
+
arn = await findCertificate(clients, host);
|
|
1296
|
+
if (arn) ctx.log(` adopting the certificate for ${host} — ${arn}`);
|
|
1297
|
+
}
|
|
1298
|
+
if (!arn) {
|
|
1299
|
+
if (ctx.dryRun) {
|
|
1300
|
+
await ctx.change({
|
|
1301
|
+
construct: id,
|
|
1302
|
+
resource: `certificate ${host}`,
|
|
1303
|
+
change: "request (ACM, us-east-1, DNS-validated)"
|
|
1304
|
+
}, async () => {});
|
|
1305
|
+
return PLANNED;
|
|
1306
|
+
}
|
|
1307
|
+
await ctx.state.pending(entry);
|
|
1308
|
+
arn = (await acm.send(new ACM.RequestCertificateCommand({
|
|
1309
|
+
DomainName: host,
|
|
1310
|
+
ValidationMethod: "DNS",
|
|
1311
|
+
IdempotencyToken: input.name.replace(/[^A-Za-z0-9]/g, "").slice(0, 32),
|
|
1312
|
+
Tags: identityTags(ctx, id).map((t) => ({
|
|
1313
|
+
Key: t.Key,
|
|
1314
|
+
Value: t.Value
|
|
1315
|
+
}))
|
|
1316
|
+
}))).CertificateArn;
|
|
1317
|
+
await ctx.change({
|
|
1318
|
+
construct: id,
|
|
1319
|
+
resource: `certificate ${host}`,
|
|
1320
|
+
change: "request (ACM, us-east-1, DNS-validated)"
|
|
1321
|
+
}, async () => {});
|
|
1322
|
+
}
|
|
1323
|
+
if (!ctx.dryRun) await ctx.state.ready(entry, arn);
|
|
1324
|
+
let certificate = await describe(arn);
|
|
1325
|
+
let record = certificate?.DomainValidationOptions?.[0]?.ResourceRecord;
|
|
1326
|
+
for (let i = 0; !record && i < 15; i++) {
|
|
1327
|
+
await sleep(Math.min(clients.wait.intervalMs, 2e3));
|
|
1328
|
+
certificate = await describe(arn);
|
|
1329
|
+
record = certificate?.DomainValidationOptions?.[0]?.ResourceRecord;
|
|
1330
|
+
}
|
|
1331
|
+
const validation = record ? {
|
|
1332
|
+
name: record.Name.replace(/\.$/, ""),
|
|
1333
|
+
value: record.Value.replace(/\.$/, "")
|
|
1334
|
+
} : void 0;
|
|
1335
|
+
const written = validation ? await ctx.writeDns([{
|
|
1336
|
+
host: validation.name,
|
|
1337
|
+
type: "CNAME",
|
|
1338
|
+
value: validation.value
|
|
1339
|
+
}]) : { manual: [] };
|
|
1340
|
+
if (certificate?.Status === "ISSUED" || ctx.dryRun) return arn;
|
|
1341
|
+
if (validation && written.manual.includes(validation.name.toLowerCase())) throw new CdnCertificatePending(id, host, validation, "manual");
|
|
1342
|
+
ctx.log(` waiting for ACM to issue the certificate for ${host}…`);
|
|
1343
|
+
const deadline = Date.now() + clients.wait.timeoutMs;
|
|
1344
|
+
while (certificate?.Status === "PENDING_VALIDATION" && Date.now() < deadline) {
|
|
1345
|
+
await sleep(clients.wait.intervalMs);
|
|
1346
|
+
certificate = await describe(arn);
|
|
1347
|
+
}
|
|
1348
|
+
if (certificate?.Status === "ISSUED") return arn;
|
|
1349
|
+
if (certificate?.Status === "PENDING_VALIDATION" || !certificate) throw new CdnCertificatePending(id, host, validation ?? {
|
|
1350
|
+
name: `(not published yet) ${host}`,
|
|
1351
|
+
value: ""
|
|
1352
|
+
}, "timeout");
|
|
1353
|
+
throw new CdnCertificateFailed(id, host, certificate.Status ?? "unknown", certificate.FailureReason);
|
|
1354
|
+
}
|
|
1355
|
+
/** An issued or pending certificate for exactly `host`, if the account has one. */
|
|
1356
|
+
async function findCertificate(clients, host) {
|
|
1357
|
+
const { ACM, acm } = clients;
|
|
1358
|
+
let NextToken;
|
|
1359
|
+
do {
|
|
1360
|
+
const page = await acm.send(new ACM.ListCertificatesCommand({
|
|
1361
|
+
CertificateStatuses: ["ISSUED", "PENDING_VALIDATION"],
|
|
1362
|
+
...NextToken ? { NextToken } : {}
|
|
1363
|
+
}));
|
|
1364
|
+
const match = page.CertificateSummaryList?.find((c) => c.DomainName?.toLowerCase() === host);
|
|
1365
|
+
if (match?.CertificateArn) return match.CertificateArn;
|
|
1366
|
+
NextToken = page.NextToken;
|
|
1367
|
+
} while (NextToken);
|
|
1368
|
+
}
|
|
1369
|
+
/** The origin access control CloudFront signs its bucket requests with. */
|
|
1370
|
+
async function ensureOriginAccessControl(ctx, clients, input) {
|
|
1371
|
+
const { CF, cloudfront } = clients;
|
|
1372
|
+
const entry = {
|
|
1373
|
+
key: `cloudfront-oac:${input.id}`,
|
|
1374
|
+
type: "cloudfront-oac",
|
|
1375
|
+
data: { name: input.name }
|
|
1376
|
+
};
|
|
1377
|
+
const recorded = ctx.state.record(entry.key)?.id;
|
|
1378
|
+
if (recorded) {
|
|
1379
|
+
if (await readOr$2(() => cloudfront.send(new CF.GetOriginAccessControlCommand({ Id: recorded })), ["NoSuchOriginAccessControl"])) return recorded;
|
|
1380
|
+
}
|
|
1381
|
+
let Marker;
|
|
1382
|
+
do {
|
|
1383
|
+
const page = await cloudfront.send(new CF.ListOriginAccessControlsCommand({ ...Marker ? { Marker } : {} }));
|
|
1384
|
+
const match = page.OriginAccessControlList?.Items?.find((o) => o.Name === input.name);
|
|
1385
|
+
if (match?.Id) {
|
|
1386
|
+
if (!ctx.dryRun) await ctx.state.ready(entry, match.Id);
|
|
1387
|
+
return match.Id;
|
|
1388
|
+
}
|
|
1389
|
+
Marker = page.OriginAccessControlList?.NextMarker;
|
|
1390
|
+
} while (Marker);
|
|
1391
|
+
let id = PLANNED;
|
|
1392
|
+
await ctx.change({
|
|
1393
|
+
construct: input.id,
|
|
1394
|
+
resource: `origin access control ${input.name}`,
|
|
1395
|
+
change: `create (CloudFront signs its reads of ${input.bucket})`
|
|
1396
|
+
}, async () => {
|
|
1397
|
+
await ctx.state.pending(entry);
|
|
1398
|
+
id = (await cloudfront.send(new CF.CreateOriginAccessControlCommand({ OriginAccessControlConfig: {
|
|
1399
|
+
Name: input.name,
|
|
1400
|
+
Description: `gkm: CloudFront's reads of ${input.bucket}`,
|
|
1401
|
+
OriginAccessControlOriginType: "s3",
|
|
1402
|
+
SigningBehavior: "always",
|
|
1403
|
+
SigningProtocol: "sigv4"
|
|
1404
|
+
} }))).OriginAccessControl.Id;
|
|
1405
|
+
await ctx.state.ready(entry, id);
|
|
1406
|
+
});
|
|
1407
|
+
return id;
|
|
1408
|
+
}
|
|
1409
|
+
/** One response headers policy, as wanted. */
|
|
1410
|
+
async function ensureHeadersPolicy(ctx, clients, input) {
|
|
1411
|
+
const { CF, cloudfront } = clients;
|
|
1412
|
+
const { config } = input;
|
|
1413
|
+
const entry = {
|
|
1414
|
+
key: `cloudfront-headers:${input.id}:${input.kind}`,
|
|
1415
|
+
type: "cloudfront-headers",
|
|
1416
|
+
data: { name: config.Name }
|
|
1417
|
+
};
|
|
1418
|
+
const read = (Id) => readOr$2(() => cloudfront.send(new CF.GetResponseHeadersPolicyConfigCommand({ Id })), ["NoSuchResponseHeadersPolicy"]);
|
|
1419
|
+
let id = ctx.state.record(entry.key)?.id;
|
|
1420
|
+
let current = id ? await read(id) : void 0;
|
|
1421
|
+
if (!current) {
|
|
1422
|
+
id = void 0;
|
|
1423
|
+
let Marker;
|
|
1424
|
+
do {
|
|
1425
|
+
const page = await cloudfront.send(new CF.ListResponseHeadersPoliciesCommand({
|
|
1426
|
+
Type: "custom",
|
|
1427
|
+
...Marker ? { Marker } : {}
|
|
1428
|
+
}));
|
|
1429
|
+
const match = page.ResponseHeadersPolicyList?.Items?.find((p) => p.ResponseHeadersPolicy?.ResponseHeadersPolicyConfig?.Name === config.Name);
|
|
1430
|
+
if (match?.ResponseHeadersPolicy?.Id) {
|
|
1431
|
+
id = match.ResponseHeadersPolicy.Id;
|
|
1432
|
+
current = await read(id);
|
|
1433
|
+
}
|
|
1434
|
+
Marker = page.ResponseHeadersPolicyList?.NextMarker;
|
|
1435
|
+
} while (!id && Marker);
|
|
1436
|
+
}
|
|
1437
|
+
if (id && current) {
|
|
1438
|
+
if (!ctx.dryRun) await ctx.state.ready(entry, id);
|
|
1439
|
+
if (sameHeadersPolicy(current.ResponseHeadersPolicyConfig, config)) return id;
|
|
1440
|
+
const existing = id;
|
|
1441
|
+
await ctx.change({
|
|
1442
|
+
construct: input.id,
|
|
1443
|
+
resource: `response headers policy ${config.Name}`,
|
|
1444
|
+
change: "put back what drifted"
|
|
1445
|
+
}, async () => {
|
|
1446
|
+
await cloudfront.send(new CF.UpdateResponseHeadersPolicyCommand({
|
|
1447
|
+
Id: existing,
|
|
1448
|
+
IfMatch: current.ETag,
|
|
1449
|
+
ResponseHeadersPolicyConfig: config
|
|
1450
|
+
}));
|
|
1451
|
+
});
|
|
1452
|
+
return existing;
|
|
1453
|
+
}
|
|
1454
|
+
let created = PLANNED;
|
|
1455
|
+
await ctx.change({
|
|
1456
|
+
construct: input.id,
|
|
1457
|
+
resource: `response headers policy ${config.Name}`,
|
|
1458
|
+
change: "create"
|
|
1459
|
+
}, async () => {
|
|
1460
|
+
await ctx.state.pending(entry);
|
|
1461
|
+
created = (await cloudfront.send(new CF.CreateResponseHeadersPolicyCommand({ ResponseHeadersPolicyConfig: config }))).ResponseHeadersPolicy.Id;
|
|
1462
|
+
await ctx.state.ready(entry, created);
|
|
1463
|
+
});
|
|
1464
|
+
return created;
|
|
1465
|
+
}
|
|
1466
|
+
/** The distribution: recorded, found by its comment, or created — as wanted. */
|
|
1467
|
+
async function ensureDistribution(ctx, clients, input) {
|
|
1468
|
+
const { CF, cloudfront } = clients;
|
|
1469
|
+
const entry = {
|
|
1470
|
+
key: `cloudfront-distribution:${input.id}`,
|
|
1471
|
+
type: "cloudfront-distribution"
|
|
1472
|
+
};
|
|
1473
|
+
const get = (Id) => readOr$2(() => cloudfront.send(new CF.GetDistributionCommand({ Id })), ["NoSuchDistribution"]);
|
|
1474
|
+
let found = ctx.state.record(entry.key)?.id ? await get(ctx.state.record(entry.key).id) : void 0;
|
|
1475
|
+
if (!found) {
|
|
1476
|
+
let Marker;
|
|
1477
|
+
do {
|
|
1478
|
+
const page = await cloudfront.send(new CF.ListDistributionsCommand({ ...Marker ? { Marker } : {} }));
|
|
1479
|
+
const match = page.DistributionList?.Items?.find((d) => d.Comment === input.comment);
|
|
1480
|
+
if (match?.Id) found = await get(match.Id);
|
|
1481
|
+
Marker = page.DistributionList?.NextMarker;
|
|
1482
|
+
} while (!found && Marker);
|
|
1483
|
+
}
|
|
1484
|
+
if (found?.Distribution) {
|
|
1485
|
+
const distribution = found.Distribution;
|
|
1486
|
+
const id = distribution.Id;
|
|
1487
|
+
const located = {
|
|
1488
|
+
arn: distribution.ARN,
|
|
1489
|
+
domainName: distribution.DomainName
|
|
1490
|
+
};
|
|
1491
|
+
if (!ctx.dryRun) await ctx.state.ready({
|
|
1492
|
+
...entry,
|
|
1493
|
+
data: located
|
|
1494
|
+
}, id);
|
|
1495
|
+
const current = await cloudfront.send(new CF.GetDistributionConfigCommand({ Id: id }));
|
|
1496
|
+
if (holds(current.DistributionConfig, input.config)) return located;
|
|
1497
|
+
await ctx.change({
|
|
1498
|
+
construct: input.id,
|
|
1499
|
+
resource: `distribution ${id}`,
|
|
1500
|
+
change: "put back what drifted"
|
|
1501
|
+
}, async () => {
|
|
1502
|
+
await cloudfront.send(new CF.UpdateDistributionCommand({
|
|
1503
|
+
Id: id,
|
|
1504
|
+
IfMatch: current.ETag,
|
|
1505
|
+
DistributionConfig: {
|
|
1506
|
+
...current.DistributionConfig,
|
|
1507
|
+
...input.config,
|
|
1508
|
+
CallerReference: current.DistributionConfig.CallerReference
|
|
1509
|
+
}
|
|
1510
|
+
}));
|
|
1511
|
+
});
|
|
1512
|
+
return located;
|
|
1513
|
+
}
|
|
1514
|
+
let created = {
|
|
1515
|
+
arn: `arn:aws:cloudfront::${PLANNED}`,
|
|
1516
|
+
domainName: PLANNED
|
|
1517
|
+
};
|
|
1518
|
+
const host = input.config.Aliases?.Items?.[0] ?? input.id;
|
|
1519
|
+
await ctx.change({
|
|
1520
|
+
construct: input.id,
|
|
1521
|
+
resource: `distribution ${host}`,
|
|
1522
|
+
change: "create (CloudFront, takes minutes to reach every edge)"
|
|
1523
|
+
}, async () => {
|
|
1524
|
+
await ctx.state.pending(entry);
|
|
1525
|
+
const out = await cloudfront.send(new CF.CreateDistributionWithTagsCommand({ DistributionConfigWithTags: {
|
|
1526
|
+
DistributionConfig: input.config,
|
|
1527
|
+
Tags: { Items: identityTags(ctx, input.id).map((t) => ({
|
|
1528
|
+
Key: t.Key,
|
|
1529
|
+
Value: t.Value
|
|
1530
|
+
})) }
|
|
1531
|
+
} }));
|
|
1532
|
+
created = {
|
|
1533
|
+
arn: out.Distribution.ARN,
|
|
1534
|
+
domainName: out.Distribution.DomainName
|
|
1535
|
+
};
|
|
1536
|
+
await ctx.state.ready({
|
|
1537
|
+
...entry,
|
|
1538
|
+
data: created
|
|
1539
|
+
}, out.Distribution.Id);
|
|
1540
|
+
});
|
|
1541
|
+
return created;
|
|
1542
|
+
}
|
|
1543
|
+
//#endregion
|
|
800
1544
|
//#region src/providers/s3/events.ts
|
|
801
1545
|
/** What S3 tells the topic about: every object written, and every removed. */
|
|
802
1546
|
const BUCKET_EVENTS = ["s3:ObjectCreated:*", "s3:ObjectRemoved:*"];
|
|
@@ -1225,10 +1969,12 @@ function bucketConstructs(manifest) {
|
|
|
1225
1969
|
return Object.entries(manifest).filter(([, d]) => d.kind === "objects").map(([id, d]) => ({
|
|
1226
1970
|
id,
|
|
1227
1971
|
versioned: d.versioned === true,
|
|
1228
|
-
...
|
|
1972
|
+
...(0, _geekmidas_manifest.bucketExpiry)(manifest, id) ? { expire: (0, _geekmidas_manifest.bucketExpiry)(manifest, id) } : {},
|
|
1229
1973
|
servers: Object.entries(manifest).filter(([, s]) => s.kind === "file-server" && s.of === id).map(([sid, s]) => ({
|
|
1230
1974
|
id: sid,
|
|
1231
|
-
open: s.open ?? []
|
|
1975
|
+
open: s.open ?? [],
|
|
1976
|
+
immutable: s.immutable ?? [],
|
|
1977
|
+
...s.processors?.length ? { processors: [...new Set(s.processors.map((p) => p.prefix))].sort() } : {}
|
|
1232
1978
|
})).sort((a, b) => a.id.localeCompare(b.id))
|
|
1233
1979
|
})).sort((a, b) => a.id.localeCompare(b.id));
|
|
1234
1980
|
}
|
|
@@ -1379,12 +2125,25 @@ async function ensureBucket(ctx, stageClients, construct, watchers) {
|
|
|
1379
2125
|
clients = await makeClients(ctx.credential, located.region);
|
|
1380
2126
|
ctx.log(` '${bucket}' is in ${located.region}, not ${stageClients.region}: '${id}' is reached and addressed there`);
|
|
1381
2127
|
}
|
|
2128
|
+
const cdn = ctx.config.cdn !== false && construct.servers.length > 0 ? await ensureBucketCdn(ctx, {
|
|
2129
|
+
bucket,
|
|
2130
|
+
region: clients.region,
|
|
2131
|
+
servers: construct.servers,
|
|
2132
|
+
origins: bucketOrigins({
|
|
2133
|
+
workspace: ctx.workspace,
|
|
2134
|
+
manifest: ctx.manifest,
|
|
2135
|
+
runnables: ctx.runnables,
|
|
2136
|
+
stage: ctx.stage,
|
|
2137
|
+
bucket: id
|
|
2138
|
+
}).origins
|
|
2139
|
+
}) : void 0;
|
|
1382
2140
|
await ensureBucketSettings(ctx, clients, {
|
|
1383
2141
|
id,
|
|
1384
2142
|
bucket,
|
|
1385
2143
|
exists,
|
|
1386
2144
|
versioning,
|
|
1387
2145
|
open,
|
|
2146
|
+
...cdn ? { cdn } : {},
|
|
1388
2147
|
...construct.expire ? { expire: construct.expire } : {}
|
|
1389
2148
|
});
|
|
1390
2149
|
const events = watchers ? await ensureBucketEvents(ctx, clients, {
|
|
@@ -1421,8 +2180,9 @@ async function ensureBucket(ctx, stageClients, construct, watchers) {
|
|
|
1421
2180
|
watchers
|
|
1422
2181
|
});
|
|
1423
2182
|
}
|
|
1424
|
-
const
|
|
2183
|
+
const bucketUrl = bucketPublicUrl(bucket, clients.region, clients.endpoint);
|
|
1425
2184
|
for (const server of construct.servers) {
|
|
2185
|
+
const publicUrl = cdn?.urls[server.id] ?? bucketUrl;
|
|
1426
2186
|
const key = (0, _geekmidas_manifest.provideKey)(server.id, "url");
|
|
1427
2187
|
const entry = {
|
|
1428
2188
|
key: `file-server:${server.id}`,
|
|
@@ -1580,7 +2340,7 @@ async function ensureBucketSettings(ctx, clients, input) {
|
|
|
1580
2340
|
Value: t.Value
|
|
1581
2341
|
})) }
|
|
1582
2342
|
})));
|
|
1583
|
-
const isOpen = input.open.length > 0;
|
|
2343
|
+
const isOpen = input.open.length > 0 && !input.cdn;
|
|
1584
2344
|
const block = publicAccessBlock(isOpen);
|
|
1585
2345
|
const ensureBlock = async () => {
|
|
1586
2346
|
const now = (await read(() => s3.send(new S3.GetPublicAccessBlockCommand({ Bucket })), ["NoSuchPublicAccessBlockConfiguration"]))?.PublicAccessBlockConfiguration;
|
|
@@ -1589,10 +2349,10 @@ async function ensureBucketSettings(ctx, clients, input) {
|
|
|
1589
2349
|
PublicAccessBlockConfiguration: block
|
|
1590
2350
|
})));
|
|
1591
2351
|
};
|
|
1592
|
-
const policy = bucketPolicy(bucket, input.open);
|
|
2352
|
+
const policy = bucketPolicy(bucket, input.open, input.cdn ? { cdn: input.cdn } : {});
|
|
1593
2353
|
const ensurePolicy = async () => {
|
|
1594
2354
|
const current = await read(() => s3.send(new S3.GetBucketPolicyCommand({ Bucket })), ["NoSuchBucketPolicy"]);
|
|
1595
|
-
if (!(current?.Policy !== void 0 && canonicalPolicy(JSON.parse(current.Policy)) === canonicalPolicy(policy))) await set(isOpen ? `policy: TLS only, public read on ${input.open.join(", ")}` : "policy: TLS only", () => s3.send(new S3.PutBucketPolicyCommand({
|
|
2355
|
+
if (!(current?.Policy !== void 0 && canonicalPolicy(JSON.parse(current.Policy)) === canonicalPolicy(policy))) await set(isOpen ? `policy: TLS only, public read on ${input.open.join(", ")}` : input.cdn && input.open.length > 0 ? `policy: TLS only, CloudFront reads ${input.open.join(", ")}` : "policy: TLS only", () => s3.send(new S3.PutBucketPolicyCommand({
|
|
1596
2356
|
Bucket,
|
|
1597
2357
|
Policy: JSON.stringify(policy)
|
|
1598
2358
|
})));
|
|
@@ -1894,6 +2654,17 @@ async function provisionStage(options) {
|
|
|
1894
2654
|
log(` ${dryRun ? "would " : ""}${action.change} — ${action.resource}`);
|
|
1895
2655
|
},
|
|
1896
2656
|
writeSecrets,
|
|
2657
|
+
writeDns: (records) => writeProviderDns(records, {
|
|
2658
|
+
workspace,
|
|
2659
|
+
stage,
|
|
2660
|
+
dryRun,
|
|
2661
|
+
credentials: options.credentials ?? require_credentials.storedCredentials({
|
|
2662
|
+
env,
|
|
2663
|
+
...options.home ? { home: options.home } : {}
|
|
2664
|
+
}),
|
|
2665
|
+
...options.dnsProviderFor ? { providerFor: options.dnsProviderFor } : {},
|
|
2666
|
+
log
|
|
2667
|
+
}),
|
|
1897
2668
|
log
|
|
1898
2669
|
});
|
|
1899
2670
|
if (entry.report.actions.length === 0) log(" up to date");
|
|
@@ -2336,6 +3107,7 @@ async function provisionResources(phaseCtx, request, ctx, store, emit) {
|
|
|
2336
3107
|
...request.rotateKeys ? { rotateKeys: true } : {},
|
|
2337
3108
|
...request.retireOldKeys ? { retireOldKeys: true } : {},
|
|
2338
3109
|
...ctx.home ? { home: ctx.home } : {},
|
|
3110
|
+
credentials: ctx.credentials,
|
|
2339
3111
|
log: (line) => phaseCtx.logger.info(line)
|
|
2340
3112
|
});
|
|
2341
3113
|
if (!ctx.dryRun) return;
|
|
@@ -2719,4 +3491,4 @@ Object.defineProperty(exports, "iamUserName", {
|
|
|
2719
3491
|
}
|
|
2720
3492
|
});
|
|
2721
3493
|
|
|
2722
|
-
//# sourceMappingURL=deploy-
|
|
3494
|
+
//# sourceMappingURL=deploy-DVrNjX1X.cjs.map
|