@geekmidas/cli 10.0.0-alpha.85 → 10.0.0-alpha.87
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/{HostingerProvider-dxkwynSs.cjs → HostingerProvider-BCB1QJj1.cjs} +2 -2
- package/dist/{HostingerProvider-dxkwynSs.cjs.map → HostingerProvider-BCB1QJj1.cjs.map} +1 -1
- package/dist/{HostingerProvider-D85ayzTi.mjs → HostingerProvider-CVc3rLPB.mjs} +2 -2
- package/dist/{HostingerProvider-D85ayzTi.mjs.map → HostingerProvider-CVc3rLPB.mjs.map} +1 -1
- package/dist/{LegacyStateStore-CJ2o18nT.mjs → LegacyStateStore-B0R4LlX_.mjs} +2 -2
- package/dist/{LegacyStateStore-CJ2o18nT.mjs.map → LegacyStateStore-B0R4LlX_.mjs.map} +1 -1
- package/dist/{LegacyStateStore-xGxPwP-m.cjs → LegacyStateStore-CWG_HVC0.cjs} +7 -7
- package/dist/{LegacyStateStore-xGxPwP-m.cjs.map → LegacyStateStore-CWG_HVC0.cjs.map} +1 -1
- package/dist/{LocalStateStore-CkjFD-4b.cjs → LocalStateStore-CLwa2DpK.cjs} +8 -8
- package/dist/{LocalStateStore-CkjFD-4b.cjs.map → LocalStateStore-CLwa2DpK.cjs.map} +1 -1
- package/dist/{LocalStateStore-ByVjUIvS.mjs → LocalStateStore-Q4vXg2ua.mjs} +2 -2
- package/dist/{LocalStateStore-ByVjUIvS.mjs.map → LocalStateStore-Q4vXg2ua.mjs.map} +1 -1
- package/dist/{S3StateStore-iqMezbES.cjs → S3StateStore-Cea9_5gF.cjs} +5 -5
- package/dist/{S3StateStore-iqMezbES.cjs.map → S3StateStore-Cea9_5gF.cjs.map} +1 -1
- package/dist/{S3StateStore-kpFlGVLE.mjs → S3StateStore-CksKYKRa.mjs} +2 -2
- package/dist/{S3StateStore-kpFlGVLE.mjs.map → S3StateStore-CksKYKRa.mjs.map} +1 -1
- package/dist/{SSMStateStore-Bkz5ztfo.mjs → SSMStateStore-BszSCAS2.mjs} +2 -2
- package/dist/{SSMStateStore-Bkz5ztfo.mjs.map → SSMStateStore-BszSCAS2.mjs.map} +1 -1
- package/dist/{SSMStateStore-Z2OMVCtq.cjs → SSMStateStore-aBOTF018.cjs} +9 -9
- package/dist/{SSMStateStore-Z2OMVCtq.cjs.map → SSMStateStore-aBOTF018.cjs.map} +1 -1
- package/dist/{add-CM7RLj89.cjs → add-5MZAXybv.cjs} +8 -5
- package/dist/add-5MZAXybv.cjs.map +1 -0
- package/dist/{add-jpX7M8RB.mjs → add-D_jNqnfZ.mjs} +8 -5
- package/dist/add-D_jNqnfZ.mjs.map +1 -0
- package/dist/{bundler-lEBH8ENP.cjs → bundler-1REMhKps.cjs} +5 -5
- package/dist/{bundler-lEBH8ENP.cjs.map → bundler-1REMhKps.cjs.map} +1 -1
- package/dist/{bundler-CaAKsbcN.mjs → bundler-BMo-JP5s.mjs} +5 -5
- package/dist/{bundler-CaAKsbcN.mjs.map → bundler-BMo-JP5s.mjs.map} +1 -1
- package/dist/{cli-BV3jzbk0.mjs → cli-7edNFwGk.mjs} +5 -13
- package/dist/cli-7edNFwGk.mjs.map +1 -0
- package/dist/{cli-DQCBcNlN.cjs → cli-BL8ZHsLQ.cjs} +5 -13
- package/dist/cli-BL8ZHsLQ.cjs.map +1 -0
- package/dist/{compose-CQK6StuE.mjs → compose-DbJhRQlh.mjs} +24 -11
- package/dist/compose-DbJhRQlh.mjs.map +1 -0
- package/dist/{compose-CSR0yEJm.cjs → compose-xw86kVYi.cjs} +34 -21
- package/dist/compose-xw86kVYi.cjs.map +1 -0
- package/dist/{config-BzIfP8a-.d.cts → config-CpjsVxru.d.cts} +3 -3
- package/dist/{config-BzIfP8a-.d.cts.map → config-CpjsVxru.d.cts.map} +1 -1
- package/dist/{config-DhdzmndX.d.mts → config-DrCAyoH5.d.mts} +3 -3
- package/dist/{config-DhdzmndX.d.mts.map → config-DrCAyoH5.d.mts.map} +1 -1
- package/dist/config.cjs +1 -1
- package/dist/config.d.cts +3 -3
- package/dist/config.d.mts +3 -3
- package/dist/config.mjs +1 -1
- package/dist/{credentials-pAtB70k3.mjs → credentials-BgJ5mS_d.mjs} +91 -181
- package/dist/credentials-BgJ5mS_d.mjs.map +1 -0
- package/dist/{credentials-BVs7mrtw.cjs → credentials-tr26-KML.cjs} +122 -188
- package/dist/credentials-tr26-KML.cjs.map +1 -0
- package/dist/deploy/public.cjs +24 -20
- package/dist/deploy/public.cjs.map +1 -1
- package/dist/deploy/public.d.cts +95 -13
- package/dist/deploy/public.d.cts.map +1 -1
- package/dist/deploy/public.d.mts +95 -13
- package/dist/deploy/public.d.mts.map +1 -1
- package/dist/deploy/public.mjs +11 -10
- package/dist/deploy/public.mjs.map +1 -1
- package/dist/{deploy-BuU117CA.mjs → deploy-BTfmXd3g.mjs} +9 -9
- package/dist/deploy-BTfmXd3g.mjs.map +1 -0
- package/dist/{deploy-Bw2Mm3x3.cjs → deploy-CtbZj4zN.cjs} +13 -13
- package/dist/deploy-CtbZj4zN.cjs.map +1 -0
- package/dist/{dokploy-C81J1MVK.cjs → dokploy-TGk3oPwr.cjs} +2 -2
- package/dist/{dokploy-C81J1MVK.cjs.map → dokploy-TGk3oPwr.cjs.map} +1 -1
- package/dist/{dokploy-DWALWk7u.mjs → dokploy-r69yZaIt.mjs} +2 -2
- package/dist/{dokploy-DWALWk7u.mjs.map → dokploy-r69yZaIt.mjs.map} +1 -1
- package/dist/{encryption-DpAum8W7.mjs → encryption-C-8Tt5Hh.mjs} +3 -3
- package/dist/{encryption-DpAum8W7.mjs.map → encryption-C-8Tt5Hh.mjs.map} +1 -1
- package/dist/{encryption-B8h8Tna0.cjs → encryption-CDn7BH5O.cjs} +3 -3
- package/dist/{encryption-B8h8Tna0.cjs.map → encryption-CDn7BH5O.cjs.map} +1 -1
- package/dist/{engine-B01fjhLt.cjs → engine-Bt5k_UMq.cjs} +33 -23
- package/dist/engine-Bt5k_UMq.cjs.map +1 -0
- package/dist/{engine-BXCtEhSH.mjs → engine-jAINgiOB.mjs} +28 -18
- package/dist/engine-jAINgiOB.mjs.map +1 -0
- package/dist/{github-8B68qrLs.mjs → github-CZHAtwPT.mjs} +3 -3
- package/dist/{github-8B68qrLs.mjs.map → github-CZHAtwPT.mjs.map} +1 -1
- package/dist/{github-Cis9tYur.cjs → github-DFhuJQlp.cjs} +3 -3
- package/dist/{github-Cis9tYur.cjs.map → github-DFhuJQlp.cjs.map} +1 -1
- package/dist/{index-f77HdqN5.d.mts → index-MnUJuUlj.d.mts} +2 -2
- package/dist/{index-D1ODeM9s.d.cts.map → index-MnUJuUlj.d.mts.map} +1 -1
- package/dist/{index-D1ODeM9s.d.cts → index-elsLJTUv.d.cts} +2 -2
- package/dist/{index-f77HdqN5.d.mts.map → index-elsLJTUv.d.cts.map} +1 -1
- package/dist/index.cjs +106 -68
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +100 -62
- package/dist/index.mjs.map +1 -1
- package/dist/local-Ciq-bTPr.mjs +224 -0
- package/dist/local-Ciq-bTPr.mjs.map +1 -0
- package/dist/local-Cq8qdgNX.cjs +241 -0
- package/dist/local-Cq8qdgNX.cjs.map +1 -0
- package/dist/{migrate-CPWn7A51.cjs → migrate-B16qgYTn.cjs} +3 -3
- package/dist/{migrate-CPWn7A51.cjs.map → migrate-B16qgYTn.cjs.map} +1 -1
- package/dist/{migrate-BBCp5blp.cjs → migrate-B1rVlwj1.cjs} +3 -3
- package/dist/{migrate-BBCp5blp.cjs.map → migrate-B1rVlwj1.cjs.map} +1 -1
- package/dist/{migrate-sDq7NApJ.mjs → migrate-Dn7nK6sh.mjs} +3 -3
- package/dist/{migrate-sDq7NApJ.mjs.map → migrate-Dn7nK6sh.mjs.map} +1 -1
- package/dist/{migrate-BeTWLSeC.mjs → migrate-ggkPVJRC.mjs} +3 -3
- package/dist/{migrate-BeTWLSeC.mjs.map → migrate-ggkPVJRC.mjs.map} +1 -1
- package/dist/openapi.cjs +1 -1
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/openapi.mjs +1 -1
- package/dist/reconcile/public.d.cts +1 -1
- package/dist/reconcile/public.d.mts +1 -1
- package/dist/{resolve-CXbwJ_iu.mjs → resolve-BSke45k6.mjs} +4 -4
- package/dist/{resolve-CXbwJ_iu.mjs.map → resolve-BSke45k6.mjs.map} +1 -1
- package/dist/{resolve-CztIqBOI.cjs → resolve-BXeXzpmU.cjs} +4 -4
- package/dist/{resolve-CztIqBOI.cjs.map → resolve-BXeXzpmU.cjs.map} +1 -1
- package/dist/{rollback-ByyFE5lV.mjs → rollback-CEE6dse4.mjs} +6 -6
- package/dist/{rollback-ByyFE5lV.mjs.map → rollback-CEE6dse4.mjs.map} +1 -1
- package/dist/{rollback-CyIJ4xGJ.cjs → rollback-DFMiBWf0.cjs} +8 -8
- package/dist/{rollback-CyIJ4xGJ.cjs.map → rollback-DFMiBWf0.cjs.map} +1 -1
- package/dist/{runtime-CNu2C2hB.d.mts → runtime-D48ZKk8_.d.cts} +2 -2
- package/dist/{runtime-CNu2C2hB.d.mts.map → runtime-D48ZKk8_.d.cts.map} +1 -1
- package/dist/{runtime-DMLgL26v.d.cts → runtime-HabiNBtJ.d.mts} +2 -2
- package/dist/{runtime-DMLgL26v.d.cts.map → runtime-HabiNBtJ.d.mts.map} +1 -1
- package/dist/{seeds-9C5CkDon.mjs → seeds-BYdrtZsC.mjs} +1525 -53
- package/dist/seeds-BYdrtZsC.mjs.map +1 -0
- package/dist/{seeds-B_Beuv0o.cjs → seeds-CsI0A_Ef.cjs} +1628 -65
- package/dist/seeds-CsI0A_Ef.cjs.map +1 -0
- package/dist/{sniffer-DgBkaLAu.mjs → sniffer-B0EU73bj.mjs} +5 -360
- package/dist/sniffer-B0EU73bj.mjs.map +1 -0
- package/dist/{sniffer-3fA0iExx.cjs → sniffer-DJYupBeK.cjs} +4 -413
- package/dist/sniffer-DJYupBeK.cjs.map +1 -0
- package/dist/{sst-DRi3H5TB.mjs → sst-D1Qj4sIs.mjs} +3 -3
- package/dist/{sst-DRi3H5TB.mjs.map → sst-D1Qj4sIs.mjs.map} +1 -1
- package/dist/{sst-hBrKouBy.cjs → sst-DAqUoZKG.cjs} +5 -5
- package/dist/{sst-hBrKouBy.cjs.map → sst-DAqUoZKG.cjs.map} +1 -1
- package/dist/{stages-CS1sjcRb.cjs → stages-Brn3vcdy.cjs} +2 -2
- package/dist/{stages-CS1sjcRb.cjs.map → stages-Brn3vcdy.cjs.map} +1 -1
- package/dist/{stages-CSXt7N2b.mjs → stages-DoHHz6pS.mjs} +2 -2
- package/dist/{stages-CSXt7N2b.mjs.map → stages-DoHHz6pS.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-BdvrmkaC.mjs → terminal-BTbZlrFV.mjs} +2 -2
- package/dist/{terminal-BdvrmkaC.mjs.map → terminal-BTbZlrFV.mjs.map} +1 -1
- package/dist/{terminal-BL5E0xbR.cjs → terminal-COv23heb.cjs} +2 -2
- package/dist/{terminal-BL5E0xbR.cjs.map → terminal-COv23heb.cjs.map} +1 -1
- package/dist/{types-BZn-8ssD.d.mts → types-0oAyFOfR.d.cts} +48 -49
- package/dist/types-0oAyFOfR.d.cts.map +1 -0
- package/dist/{types-DiZj6hqp.d.cts → types-BZ01tZs-.d.mts} +47 -50
- package/dist/types-BZ01tZs-.d.mts.map +1 -0
- 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-Bic_R3tz.cjs → workspace-CT0JM3Y8.cjs} +333 -1
- package/dist/workspace-CT0JM3Y8.cjs.map +1 -0
- package/dist/{workspace-Drz4jsvy.mjs → workspace-D2CYLMCW.mjs} +250 -2
- package/dist/workspace-D2CYLMCW.mjs.map +1 -0
- package/package.json +15 -15
- package/dist/add-CM7RLj89.cjs.map +0 -1
- package/dist/add-jpX7M8RB.mjs.map +0 -1
- package/dist/cli-BV3jzbk0.mjs.map +0 -1
- package/dist/cli-DQCBcNlN.cjs.map +0 -1
- package/dist/compose-CQK6StuE.mjs.map +0 -1
- package/dist/compose-CSR0yEJm.cjs.map +0 -1
- package/dist/credentials-BVs7mrtw.cjs.map +0 -1
- package/dist/credentials-pAtB70k3.mjs.map +0 -1
- package/dist/deploy-BuU117CA.mjs.map +0 -1
- package/dist/deploy-Bw2Mm3x3.cjs.map +0 -1
- package/dist/engine-B01fjhLt.cjs.map +0 -1
- package/dist/engine-BXCtEhSH.mjs.map +0 -1
- package/dist/run-BJLIerMM.mjs +0 -133
- package/dist/run-BJLIerMM.mjs.map +0 -1
- package/dist/run-fVZ-rLnc.cjs +0 -174
- package/dist/run-fVZ-rLnc.cjs.map +0 -1
- package/dist/seeds-9C5CkDon.mjs.map +0 -1
- package/dist/seeds-B_Beuv0o.cjs.map +0 -1
- package/dist/sniffer-3fA0iExx.cjs.map +0 -1
- package/dist/sniffer-DgBkaLAu.mjs.map +0 -1
- package/dist/types-BZn-8ssD.d.mts.map +0 -1
- package/dist/types-DiZj6hqp.d.cts.map +0 -1
- package/dist/workspace-Bic_R3tz.cjs.map +0 -1
- package/dist/workspace-Drz4jsvy.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"S3StateStore-kpFlGVLE.mjs","names":[],"sources":["../src/deploy/S3StateStore.ts"],"sourcesContent":["/**\n * Amazon S3 state store.\n *\n * - `<prefix>/<workspace>/<stage>/state.json`: the state.\n * - `<prefix>/<workspace>/<stage>/lock.json`: the lock.\n * - `<prefix>/<workspace>/<stage>/state.v1.json`: the v1 state, kept on\n * migration.\n *\n * Every write is conditional on the server: `If-None-Match: *` to create,\n * `If-Match: <etag>` to replace. S3 answers a lost race with 412 (or 409 when\n * two conditional writes are in flight at once), so there is no window\n * between a check and a write for another run to slip into.\n */\n\nimport {\n\tDeleteObjectCommand,\n\tGetObjectCommand,\n\tPutObjectCommand,\n\tS3Client,\n\ttype S3ClientConfig,\n} from '@aws-sdk/client-s3';\nimport type { AwsRegion } from './StateProvider';\nimport {\n\tDocumentStateStore,\n\ttype LockHolder,\n\ttype RawState,\n\tStateLocked,\n\ttype StateVersion,\n\tStateVersionConflict,\n} from './StateStore';\n\nexport interface S3StateStoreOptions {\n\tworkspaceName: string;\n\tbucket: string;\n\t/** Key prefix inside the bucket; `gkm` by default. */\n\tprefix?: string;\n\tregion?: AwsRegion;\n\t/** Uses the default credential chain when omitted. */\n\tprofile?: string;\n\tcredentials?: S3ClientConfig['credentials'];\n\t/** For the local AWS emulator. */\n\tendpoint?: string;\n}\n\ninterface S3Failure {\n\tname?: string;\n\t$metadata?: { httpStatusCode?: number };\n}\n\n/** A conditional write that lost: the object is not what the write assumed. */\nfunction lostRace(error: unknown): boolean {\n\tconst { name, $metadata } = (error ?? {}) as S3Failure;\n\treturn (\n\t\tname === 'PreconditionFailed' ||\n\t\tname === 'ConditionalRequestConflict' ||\n\t\t$metadata?.httpStatusCode === 412 ||\n\t\t$metadata?.httpStatusCode === 409\n\t);\n}\n\nfunction notFound(error: unknown): boolean {\n\tconst { name, $metadata } = (error ?? {}) as S3Failure;\n\treturn (\n\t\tname === 'NoSuchKey' ||\n\t\tname === 'NotFound' ||\n\t\t$metadata?.httpStatusCode === 404\n\t);\n}\n\nexport class S3StateStore extends DocumentStateStore {\n\tprivate readonly prefix: string;\n\n\tconstructor(\n\t\treadonly workspaceName: string,\n\t\treadonly bucket: string,\n\t\tprivate readonly client: S3Client,\n\t\tprefix = 'gkm',\n\t) {\n\t\tsuper();\n\t\tthis.prefix = prefix.replace(/\\/+$/, '');\n\t}\n\n\tstatic create(options: S3StateStoreOptions): S3StateStore {\n\t\tconst config: S3ClientConfig = {\n\t\t\tregion: options.region,\n\t\t\tendpoint: options.endpoint,\n\t\t\t// The emulator serves buckets by path, not by subdomain.\n\t\t\tforcePathStyle: options.endpoint ? true : undefined,\n\t\t};\n\t\tif (options.profile) {\n\t\t\t// Required lazily: only a profile needs the credential providers.\n\t\t\tconst { fromIni } = require('@aws-sdk/credential-providers');\n\t\t\tconfig.credentials = fromIni({ profile: options.profile });\n\t\t} else if (options.credentials) {\n\t\t\tconfig.credentials = options.credentials;\n\t\t}\n\t\treturn new S3StateStore(\n\t\t\toptions.workspaceName,\n\t\t\toptions.bucket,\n\t\t\tnew S3Client(config),\n\t\t\toptions.prefix,\n\t\t);\n\t}\n\n\tprivate key(stage: string, leaf: string): string {\n\t\tconst path = `${this.workspaceName}/${stage}/${leaf}`;\n\t\treturn this.prefix ? `${this.prefix}/${path}` : path;\n\t}\n\n\tprotected location(stage: string): string {\n\t\treturn `s3://${this.bucket}/${this.key(stage, 'state.json')}`;\n\t}\n\n\tprotected async readRaw(stage: string): Promise<RawState | null> {\n\t\tconst object = await this.get(this.key(stage, 'state.json'));\n\t\tif (!object) return null;\n\t\treturn { body: object.body, version: object.etag };\n\t}\n\n\tprotected async writeRaw(\n\t\tstage: string,\n\t\tbody: string,\n\t\texpectedVersion: StateVersion | null,\n\t): Promise<StateVersion> {\n\t\tconst Key = this.key(stage, 'state.json');\n\t\ttry {\n\t\t\tconst { ETag } = await this.client.send(\n\t\t\t\tnew PutObjectCommand({\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tKey,\n\t\t\t\t\tBody: body,\n\t\t\t\t\tContentType: 'application/json',\n\t\t\t\t\t...(expectedVersion === null\n\t\t\t\t\t\t? { IfNoneMatch: '*' }\n\t\t\t\t\t\t: { IfMatch: expectedVersion }),\n\t\t\t\t}),\n\t\t\t);\n\t\t\tif (ETag) return ETag;\n\t\t\t// Some S3-compatible servers omit the ETag on a conditional put.\n\t\t\treturn (await this.get(Key))?.etag ?? '';\n\t\t} catch (error) {\n\t\t\tif (lostRace(error)) {\n\t\t\t\tconst current = await this.get(Key);\n\t\t\t\tthrow new StateVersionConflict(\n\t\t\t\t\tstage,\n\t\t\t\t\texpectedVersion,\n\t\t\t\t\tcurrent?.etag ?? null,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprotected async writeV1Backup(stage: string, body: string): Promise<void> {\n\t\ttry {\n\t\t\tawait this.client.send(\n\t\t\t\tnew PutObjectCommand({\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tKey: this.key(stage, 'state.v1.json'),\n\t\t\t\t\tBody: body,\n\t\t\t\t\tContentType: 'application/json',\n\t\t\t\t\tIfNoneMatch: '*',\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\t// The first migration's backup is the one worth keeping.\n\t\t\tif (!lostRace(error)) throw error;\n\t\t}\n\t}\n\n\tprotected async createLock(stage: string, holder: LockHolder): Promise<void> {\n\t\tconst Key = this.key(stage, 'lock.json');\n\t\ttry {\n\t\t\tawait this.client.send(\n\t\t\t\tnew PutObjectCommand({\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tKey,\n\t\t\t\t\tBody: JSON.stringify(holder),\n\t\t\t\t\tContentType: 'application/json',\n\t\t\t\t\tIfNoneMatch: '*',\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (lostRace(error)) {\n\t\t\t\tthrow new StateLocked(\n\t\t\t\t\tstage,\n\t\t\t\t\tawait this.readLock(stage),\n\t\t\t\t\t`s3://${this.bucket}/${Key}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprotected async readLock(stage: string): Promise<LockHolder | null> {\n\t\tconst object = await this.get(this.key(stage, 'lock.json'));\n\t\tif (!object) return null;\n\t\ttry {\n\t\t\treturn JSON.parse(object.body) as LockHolder;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprotected async removeLock(\n\t\tstage: string,\n\t\tholder: LockHolder | null,\n\t): Promise<void> {\n\t\tconst Key = this.key(stage, 'lock.json');\n\t\tconst object = await this.get(Key);\n\t\tif (!object) return;\n\t\tif (holder) {\n\t\t\ttry {\n\t\t\t\tif ((JSON.parse(object.body) as LockHolder).id !== holder.id) return;\n\t\t\t} catch {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\ttry {\n\t\t\t// Conditional on the lock read above, so a lock taken by another\n\t\t\t// run in the meantime survives.\n\t\t\tawait this.client.send(\n\t\t\t\tnew DeleteObjectCommand({\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tKey,\n\t\t\t\t\tIfMatch: object.etag,\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (!lostRace(error) && !notFound(error)) throw error;\n\t\t}\n\t}\n\n\tprivate async get(\n\t\tKey: string,\n\t): Promise<{ body: string; etag: string } | null> {\n\t\ttry {\n\t\t\tconst response = await this.client.send(\n\t\t\t\tnew GetObjectCommand({ Bucket: this.bucket, Key }),\n\t\t\t);\n\t\t\tconst body = (await response.Body?.transformToString('utf-8')) ?? '';\n\t\t\treturn { body, etag: response.ETag ?? '' };\n\t\t} catch (error) {\n\t\t\tif (notFound(error)) return null;\n\t\t\tthrow error;\n\t\t}\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"S3StateStore-CksKYKRa.mjs","names":[],"sources":["../src/deploy/S3StateStore.ts"],"sourcesContent":["/**\n * Amazon S3 state store.\n *\n * - `<prefix>/<workspace>/<stage>/state.json`: the state.\n * - `<prefix>/<workspace>/<stage>/lock.json`: the lock.\n * - `<prefix>/<workspace>/<stage>/state.v1.json`: the v1 state, kept on\n * migration.\n *\n * Every write is conditional on the server: `If-None-Match: *` to create,\n * `If-Match: <etag>` to replace. S3 answers a lost race with 412 (or 409 when\n * two conditional writes are in flight at once), so there is no window\n * between a check and a write for another run to slip into.\n */\n\nimport {\n\tDeleteObjectCommand,\n\tGetObjectCommand,\n\tPutObjectCommand,\n\tS3Client,\n\ttype S3ClientConfig,\n} from '@aws-sdk/client-s3';\nimport type { AwsRegion } from './StateProvider';\nimport {\n\tDocumentStateStore,\n\ttype LockHolder,\n\ttype RawState,\n\tStateLocked,\n\ttype StateVersion,\n\tStateVersionConflict,\n} from './StateStore';\n\nexport interface S3StateStoreOptions {\n\tworkspaceName: string;\n\tbucket: string;\n\t/** Key prefix inside the bucket; `gkm` by default. */\n\tprefix?: string;\n\tregion?: AwsRegion;\n\t/** Uses the default credential chain when omitted. */\n\tprofile?: string;\n\tcredentials?: S3ClientConfig['credentials'];\n\t/** For the local AWS emulator. */\n\tendpoint?: string;\n}\n\ninterface S3Failure {\n\tname?: string;\n\t$metadata?: { httpStatusCode?: number };\n}\n\n/** A conditional write that lost: the object is not what the write assumed. */\nfunction lostRace(error: unknown): boolean {\n\tconst { name, $metadata } = (error ?? {}) as S3Failure;\n\treturn (\n\t\tname === 'PreconditionFailed' ||\n\t\tname === 'ConditionalRequestConflict' ||\n\t\t$metadata?.httpStatusCode === 412 ||\n\t\t$metadata?.httpStatusCode === 409\n\t);\n}\n\nfunction notFound(error: unknown): boolean {\n\tconst { name, $metadata } = (error ?? {}) as S3Failure;\n\treturn (\n\t\tname === 'NoSuchKey' ||\n\t\tname === 'NotFound' ||\n\t\t$metadata?.httpStatusCode === 404\n\t);\n}\n\nexport class S3StateStore extends DocumentStateStore {\n\tprivate readonly prefix: string;\n\n\tconstructor(\n\t\treadonly workspaceName: string,\n\t\treadonly bucket: string,\n\t\tprivate readonly client: S3Client,\n\t\tprefix = 'gkm',\n\t) {\n\t\tsuper();\n\t\tthis.prefix = prefix.replace(/\\/+$/, '');\n\t}\n\n\tstatic create(options: S3StateStoreOptions): S3StateStore {\n\t\tconst config: S3ClientConfig = {\n\t\t\tregion: options.region,\n\t\t\tendpoint: options.endpoint,\n\t\t\t// The emulator serves buckets by path, not by subdomain.\n\t\t\tforcePathStyle: options.endpoint ? true : undefined,\n\t\t};\n\t\tif (options.profile) {\n\t\t\t// Required lazily: only a profile needs the credential providers.\n\t\t\tconst { fromIni } = require('@aws-sdk/credential-providers');\n\t\t\tconfig.credentials = fromIni({ profile: options.profile });\n\t\t} else if (options.credentials) {\n\t\t\tconfig.credentials = options.credentials;\n\t\t}\n\t\treturn new S3StateStore(\n\t\t\toptions.workspaceName,\n\t\t\toptions.bucket,\n\t\t\tnew S3Client(config),\n\t\t\toptions.prefix,\n\t\t);\n\t}\n\n\tprivate key(stage: string, leaf: string): string {\n\t\tconst path = `${this.workspaceName}/${stage}/${leaf}`;\n\t\treturn this.prefix ? `${this.prefix}/${path}` : path;\n\t}\n\n\tprotected location(stage: string): string {\n\t\treturn `s3://${this.bucket}/${this.key(stage, 'state.json')}`;\n\t}\n\n\tprotected async readRaw(stage: string): Promise<RawState | null> {\n\t\tconst object = await this.get(this.key(stage, 'state.json'));\n\t\tif (!object) return null;\n\t\treturn { body: object.body, version: object.etag };\n\t}\n\n\tprotected async writeRaw(\n\t\tstage: string,\n\t\tbody: string,\n\t\texpectedVersion: StateVersion | null,\n\t): Promise<StateVersion> {\n\t\tconst Key = this.key(stage, 'state.json');\n\t\ttry {\n\t\t\tconst { ETag } = await this.client.send(\n\t\t\t\tnew PutObjectCommand({\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tKey,\n\t\t\t\t\tBody: body,\n\t\t\t\t\tContentType: 'application/json',\n\t\t\t\t\t...(expectedVersion === null\n\t\t\t\t\t\t? { IfNoneMatch: '*' }\n\t\t\t\t\t\t: { IfMatch: expectedVersion }),\n\t\t\t\t}),\n\t\t\t);\n\t\t\tif (ETag) return ETag;\n\t\t\t// Some S3-compatible servers omit the ETag on a conditional put.\n\t\t\treturn (await this.get(Key))?.etag ?? '';\n\t\t} catch (error) {\n\t\t\tif (lostRace(error)) {\n\t\t\t\tconst current = await this.get(Key);\n\t\t\t\tthrow new StateVersionConflict(\n\t\t\t\t\tstage,\n\t\t\t\t\texpectedVersion,\n\t\t\t\t\tcurrent?.etag ?? null,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprotected async writeV1Backup(stage: string, body: string): Promise<void> {\n\t\ttry {\n\t\t\tawait this.client.send(\n\t\t\t\tnew PutObjectCommand({\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tKey: this.key(stage, 'state.v1.json'),\n\t\t\t\t\tBody: body,\n\t\t\t\t\tContentType: 'application/json',\n\t\t\t\t\tIfNoneMatch: '*',\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\t// The first migration's backup is the one worth keeping.\n\t\t\tif (!lostRace(error)) throw error;\n\t\t}\n\t}\n\n\tprotected async createLock(stage: string, holder: LockHolder): Promise<void> {\n\t\tconst Key = this.key(stage, 'lock.json');\n\t\ttry {\n\t\t\tawait this.client.send(\n\t\t\t\tnew PutObjectCommand({\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tKey,\n\t\t\t\t\tBody: JSON.stringify(holder),\n\t\t\t\t\tContentType: 'application/json',\n\t\t\t\t\tIfNoneMatch: '*',\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (lostRace(error)) {\n\t\t\t\tthrow new StateLocked(\n\t\t\t\t\tstage,\n\t\t\t\t\tawait this.readLock(stage),\n\t\t\t\t\t`s3://${this.bucket}/${Key}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprotected async readLock(stage: string): Promise<LockHolder | null> {\n\t\tconst object = await this.get(this.key(stage, 'lock.json'));\n\t\tif (!object) return null;\n\t\ttry {\n\t\t\treturn JSON.parse(object.body) as LockHolder;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprotected async removeLock(\n\t\tstage: string,\n\t\tholder: LockHolder | null,\n\t): Promise<void> {\n\t\tconst Key = this.key(stage, 'lock.json');\n\t\tconst object = await this.get(Key);\n\t\tif (!object) return;\n\t\tif (holder) {\n\t\t\ttry {\n\t\t\t\tif ((JSON.parse(object.body) as LockHolder).id !== holder.id) return;\n\t\t\t} catch {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\ttry {\n\t\t\t// Conditional on the lock read above, so a lock taken by another\n\t\t\t// run in the meantime survives.\n\t\t\tawait this.client.send(\n\t\t\t\tnew DeleteObjectCommand({\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tKey,\n\t\t\t\t\tIfMatch: object.etag,\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (!lostRace(error) && !notFound(error)) throw error;\n\t\t}\n\t}\n\n\tprivate async get(\n\t\tKey: string,\n\t): Promise<{ body: string; etag: string } | null> {\n\t\ttry {\n\t\t\tconst response = await this.client.send(\n\t\t\t\tnew GetObjectCommand({ Bucket: this.bucket, Key }),\n\t\t\t);\n\t\t\tconst body = (await response.Body?.transformToString('utf-8')) ?? '';\n\t\t\treturn { body, etag: response.ETag ?? '' };\n\t\t} catch (error) {\n\t\t\tif (notFound(error)) return null;\n\t\t\tthrow error;\n\t\t}\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as __require } from "./rolldown-runtime-BhDjJH2R.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { L as StateVersionConflict, M as DocumentStateStore, P as StateLocked } from "./seeds-BYdrtZsC.mjs";
|
|
3
3
|
import { DeleteParameterCommand, GetParameterCommand, ParameterAlreadyExists, ParameterNotFound, PutParameterCommand, SSMClient } from "@aws-sdk/client-ssm";
|
|
4
4
|
//#region src/deploy/SSMStateStore.ts
|
|
5
5
|
/**
|
|
@@ -151,4 +151,4 @@ function parseHolder(value) {
|
|
|
151
151
|
//#endregion
|
|
152
152
|
export { SSMStateStore };
|
|
153
153
|
|
|
154
|
-
//# sourceMappingURL=SSMStateStore-
|
|
154
|
+
//# sourceMappingURL=SSMStateStore-BszSCAS2.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SSMStateStore-Bkz5ztfo.mjs","names":[],"sources":["../src/deploy/SSMStateStore.ts"],"sourcesContent":["/**\n * AWS SSM Parameter Store state store.\n *\n * - `/gkm/<workspace>/<stage>/state`: the state, a SecureString.\n * - `/gkm/<workspace>/<stage>/lock`: the lock, created only if absent.\n * - `/gkm/<workspace>/<stage>/state.v1`: the v1 state, kept on migration.\n *\n * SSM has no conditional put, so a write checks the parameter's version\n * before it puts, and checks the version the put returns after: a put that\n * did not land exactly one version above the one it was based on raced\n * another writer, and raises `StateVersionConflict` rather than reporting\n * success. Both writes stay in the parameter's history.\n */\n\nimport {\n\tDeleteParameterCommand,\n\tGetParameterCommand,\n\tParameterAlreadyExists,\n\tParameterNotFound,\n\tPutParameterCommand,\n\tSSMClient,\n\ttype SSMClientConfig,\n} from '@aws-sdk/client-ssm';\nimport type { AwsRegion } from './StateProvider';\nimport {\n\tDocumentStateStore,\n\ttype LockHolder,\n\ttype RawState,\n\tStateLocked,\n\ttype StateVersion,\n\tStateVersionConflict,\n} from './StateStore';\n\nexport interface SSMStateStoreOptions {\n\tworkspaceName: string;\n\tregion?: AwsRegion;\n\t/** Uses the default credential chain when omitted. */\n\tprofile?: string;\n\tcredentials?: SSMClientConfig['credentials'];\n\t/** For the local AWS emulator. */\n\tendpoint?: string;\n}\n\nexport class SSMStateStore extends DocumentStateStore {\n\tconstructor(\n\t\treadonly workspaceName: string,\n\t\tprivate readonly client: SSMClient,\n\t) {\n\t\tsuper();\n\t}\n\n\tstatic create(options: SSMStateStoreOptions): SSMStateStore {\n\t\tconst config: SSMClientConfig = {\n\t\t\tregion: options.region,\n\t\t\tendpoint: options.endpoint,\n\t\t};\n\t\tif (options.profile) {\n\t\t\t// Required lazily: only a profile needs the credential providers.\n\t\t\tconst { fromIni } = require('@aws-sdk/credential-providers');\n\t\t\tconfig.credentials = fromIni({ profile: options.profile });\n\t\t} else if (options.credentials) {\n\t\t\tconfig.credentials = options.credentials;\n\t\t}\n\t\treturn new SSMStateStore(options.workspaceName, new SSMClient(config));\n\t}\n\n\tprivate name(stage: string, leaf: string): string {\n\t\treturn `/gkm/${this.workspaceName}/${stage}/${leaf}`;\n\t}\n\n\tprotected location(stage: string): string {\n\t\treturn `ssm:${this.name(stage, 'state')}`;\n\t}\n\n\tprotected async readRaw(stage: string): Promise<RawState | null> {\n\t\tconst parameter = await this.get(this.name(stage, 'state'));\n\t\tif (!parameter) return null;\n\t\treturn { body: parameter.value, version: String(parameter.version) };\n\t}\n\n\tprotected async writeRaw(\n\t\tstage: string,\n\t\tbody: string,\n\t\texpectedVersion: StateVersion | null,\n\t): Promise<StateVersion> {\n\t\tconst Name = this.name(stage, 'state');\n\t\tconst Description = `GKM deployment state for ${this.workspaceName}/${stage}`;\n\n\t\tif (expectedVersion === null) {\n\t\t\ttry {\n\t\t\t\tconst { Version } = await this.client.send(\n\t\t\t\t\tnew PutParameterCommand({\n\t\t\t\t\t\tName,\n\t\t\t\t\t\tValue: body,\n\t\t\t\t\t\tType: 'SecureString',\n\t\t\t\t\t\tDescription,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn String(Version);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof ParameterAlreadyExists) {\n\t\t\t\t\tconst current = await this.get(Name);\n\t\t\t\t\tthrow new StateVersionConflict(\n\t\t\t\t\t\tstage,\n\t\t\t\t\t\tnull,\n\t\t\t\t\t\tcurrent ? String(current.version) : null,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\tconst current = await this.get(Name);\n\t\tconst actual = current ? String(current.version) : null;\n\t\tif (actual !== expectedVersion) {\n\t\t\tthrow new StateVersionConflict(stage, expectedVersion, actual);\n\t\t}\n\n\t\tconst { Version } = await this.client.send(\n\t\t\tnew PutParameterCommand({\n\t\t\t\tName,\n\t\t\t\tValue: body,\n\t\t\t\tType: 'SecureString',\n\t\t\t\tOverwrite: true,\n\t\t\t\tDescription,\n\t\t\t}),\n\t\t);\n\t\tif (Version !== Number(expectedVersion) + 1) {\n\t\t\t// Another put landed between the check and this one. Ours is now\n\t\t\t// on top, but the caller that wrote the other believes its write\n\t\t\t// is current — its next write will conflict too, so neither is\n\t\t\t// lost silently.\n\t\t\tthrow new StateVersionConflict(\n\t\t\t\tstage,\n\t\t\t\texpectedVersion,\n\t\t\t\tString((Version ?? 1) - 1),\n\t\t\t);\n\t\t}\n\n\t\t// The version alone is not enough under an emulator, and need not be\n\t\t// on SSM either: two overwrites that raced can both be answered with\n\t\t// the same version, and both would report success. If the parameter is\n\t\t// still at the version this put returned, it has to hold this body —\n\t\t// otherwise the other put is the one that stuck.\n\t\tconst landed = await this.get(Name);\n\t\tif (landed && landed.version === Version && landed.value !== body) {\n\t\t\tthrow new StateVersionConflict(stage, expectedVersion, String(Version));\n\t\t}\n\t\treturn String(Version);\n\t}\n\n\tprotected async writeV1Backup(stage: string, body: string): Promise<void> {\n\t\ttry {\n\t\t\tawait this.client.send(\n\t\t\t\tnew PutParameterCommand({\n\t\t\t\t\tName: this.name(stage, 'state.v1'),\n\t\t\t\t\tValue: body,\n\t\t\t\t\tType: 'SecureString',\n\t\t\t\t\tDescription: `GKM v1 deployment state for ${this.workspaceName}/${stage}, kept on migration`,\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\t// The first migration's backup is the one worth keeping.\n\t\t\tif (!(error instanceof ParameterAlreadyExists)) throw error;\n\t\t}\n\t}\n\n\tprotected async createLock(stage: string, holder: LockHolder): Promise<void> {\n\t\tconst Name = this.name(stage, 'lock');\n\t\ttry {\n\t\t\tawait this.client.send(\n\t\t\t\tnew PutParameterCommand({\n\t\t\t\t\tName,\n\t\t\t\t\tValue: JSON.stringify(holder),\n\t\t\t\t\tType: 'String',\n\t\t\t\t\tDescription: `GKM deploy lock for ${this.workspaceName}/${stage}`,\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (error instanceof ParameterAlreadyExists) {\n\t\t\t\tthrow new StateLocked(stage, await this.readLock(stage), `ssm:${Name}`);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\n\t\t// A create-only put is atomic on SSM, so the lock is ours. Read it back\n\t\t// anyway: on a store where two racing creates can both succeed (the\n\t\t// local emulator does, a few times in a hundred) the later one has\n\t\t// overwritten the earlier — version 2, someone else's holder — and\n\t\t// taking the lock regardless would give the stage two deploys.\n\t\tconst created = await this.get(Name);\n\t\tconst recorded = created ? parseHolder(created.value) : null;\n\t\tif (created?.version !== 1 || recorded?.id !== holder.id) {\n\t\t\tthrow new StateLocked(stage, recorded, `ssm:${Name}`);\n\t\t}\n\t}\n\n\tprotected async readLock(stage: string): Promise<LockHolder | null> {\n\t\tconst parameter = await this.get(this.name(stage, 'lock'));\n\t\treturn parameter ? parseHolder(parameter.value) : null;\n\t}\n\n\tprotected async removeLock(\n\t\tstage: string,\n\t\tholder: LockHolder | null,\n\t): Promise<void> {\n\t\tif (holder) {\n\t\t\tconst current = await this.readLock(stage);\n\t\t\tif (current?.id !== holder.id) return;\n\t\t}\n\t\ttry {\n\t\t\tawait this.client.send(\n\t\t\t\tnew DeleteParameterCommand({ Name: this.name(stage, 'lock') }),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (!(error instanceof ParameterNotFound)) throw error;\n\t\t}\n\t}\n\n\tprivate async get(\n\t\tName: string,\n\t): Promise<{ value: string; version: number } | null> {\n\t\ttry {\n\t\t\tconst { Parameter } = await this.client.send(\n\t\t\t\tnew GetParameterCommand({ Name, WithDecryption: true }),\n\t\t\t);\n\t\t\tif (Parameter?.Value === undefined) return null;\n\t\t\treturn { value: Parameter.Value, version: Parameter.Version ?? 1 };\n\t\t} catch (error) {\n\t\t\tif (error instanceof ParameterNotFound) return null;\n\t\t\tthrow error;\n\t\t}\n\t}\n}\n\nfunction parseHolder(value: string): LockHolder | null {\n\ttry {\n\t\treturn JSON.parse(value) as LockHolder;\n\t} catch {\n\t\treturn null;\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SSMStateStore-BszSCAS2.mjs","names":[],"sources":["../src/deploy/SSMStateStore.ts"],"sourcesContent":["/**\n * AWS SSM Parameter Store state store.\n *\n * - `/gkm/<workspace>/<stage>/state`: the state, a SecureString.\n * - `/gkm/<workspace>/<stage>/lock`: the lock, created only if absent.\n * - `/gkm/<workspace>/<stage>/state.v1`: the v1 state, kept on migration.\n *\n * SSM has no conditional put, so a write checks the parameter's version\n * before it puts, and checks the version the put returns after: a put that\n * did not land exactly one version above the one it was based on raced\n * another writer, and raises `StateVersionConflict` rather than reporting\n * success. Both writes stay in the parameter's history.\n */\n\nimport {\n\tDeleteParameterCommand,\n\tGetParameterCommand,\n\tParameterAlreadyExists,\n\tParameterNotFound,\n\tPutParameterCommand,\n\tSSMClient,\n\ttype SSMClientConfig,\n} from '@aws-sdk/client-ssm';\nimport type { AwsRegion } from './StateProvider';\nimport {\n\tDocumentStateStore,\n\ttype LockHolder,\n\ttype RawState,\n\tStateLocked,\n\ttype StateVersion,\n\tStateVersionConflict,\n} from './StateStore';\n\nexport interface SSMStateStoreOptions {\n\tworkspaceName: string;\n\tregion?: AwsRegion;\n\t/** Uses the default credential chain when omitted. */\n\tprofile?: string;\n\tcredentials?: SSMClientConfig['credentials'];\n\t/** For the local AWS emulator. */\n\tendpoint?: string;\n}\n\nexport class SSMStateStore extends DocumentStateStore {\n\tconstructor(\n\t\treadonly workspaceName: string,\n\t\tprivate readonly client: SSMClient,\n\t) {\n\t\tsuper();\n\t}\n\n\tstatic create(options: SSMStateStoreOptions): SSMStateStore {\n\t\tconst config: SSMClientConfig = {\n\t\t\tregion: options.region,\n\t\t\tendpoint: options.endpoint,\n\t\t};\n\t\tif (options.profile) {\n\t\t\t// Required lazily: only a profile needs the credential providers.\n\t\t\tconst { fromIni } = require('@aws-sdk/credential-providers');\n\t\t\tconfig.credentials = fromIni({ profile: options.profile });\n\t\t} else if (options.credentials) {\n\t\t\tconfig.credentials = options.credentials;\n\t\t}\n\t\treturn new SSMStateStore(options.workspaceName, new SSMClient(config));\n\t}\n\n\tprivate name(stage: string, leaf: string): string {\n\t\treturn `/gkm/${this.workspaceName}/${stage}/${leaf}`;\n\t}\n\n\tprotected location(stage: string): string {\n\t\treturn `ssm:${this.name(stage, 'state')}`;\n\t}\n\n\tprotected async readRaw(stage: string): Promise<RawState | null> {\n\t\tconst parameter = await this.get(this.name(stage, 'state'));\n\t\tif (!parameter) return null;\n\t\treturn { body: parameter.value, version: String(parameter.version) };\n\t}\n\n\tprotected async writeRaw(\n\t\tstage: string,\n\t\tbody: string,\n\t\texpectedVersion: StateVersion | null,\n\t): Promise<StateVersion> {\n\t\tconst Name = this.name(stage, 'state');\n\t\tconst Description = `GKM deployment state for ${this.workspaceName}/${stage}`;\n\n\t\tif (expectedVersion === null) {\n\t\t\ttry {\n\t\t\t\tconst { Version } = await this.client.send(\n\t\t\t\t\tnew PutParameterCommand({\n\t\t\t\t\t\tName,\n\t\t\t\t\t\tValue: body,\n\t\t\t\t\t\tType: 'SecureString',\n\t\t\t\t\t\tDescription,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn String(Version);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof ParameterAlreadyExists) {\n\t\t\t\t\tconst current = await this.get(Name);\n\t\t\t\t\tthrow new StateVersionConflict(\n\t\t\t\t\t\tstage,\n\t\t\t\t\t\tnull,\n\t\t\t\t\t\tcurrent ? String(current.version) : null,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\tconst current = await this.get(Name);\n\t\tconst actual = current ? String(current.version) : null;\n\t\tif (actual !== expectedVersion) {\n\t\t\tthrow new StateVersionConflict(stage, expectedVersion, actual);\n\t\t}\n\n\t\tconst { Version } = await this.client.send(\n\t\t\tnew PutParameterCommand({\n\t\t\t\tName,\n\t\t\t\tValue: body,\n\t\t\t\tType: 'SecureString',\n\t\t\t\tOverwrite: true,\n\t\t\t\tDescription,\n\t\t\t}),\n\t\t);\n\t\tif (Version !== Number(expectedVersion) + 1) {\n\t\t\t// Another put landed between the check and this one. Ours is now\n\t\t\t// on top, but the caller that wrote the other believes its write\n\t\t\t// is current — its next write will conflict too, so neither is\n\t\t\t// lost silently.\n\t\t\tthrow new StateVersionConflict(\n\t\t\t\tstage,\n\t\t\t\texpectedVersion,\n\t\t\t\tString((Version ?? 1) - 1),\n\t\t\t);\n\t\t}\n\n\t\t// The version alone is not enough under an emulator, and need not be\n\t\t// on SSM either: two overwrites that raced can both be answered with\n\t\t// the same version, and both would report success. If the parameter is\n\t\t// still at the version this put returned, it has to hold this body —\n\t\t// otherwise the other put is the one that stuck.\n\t\tconst landed = await this.get(Name);\n\t\tif (landed && landed.version === Version && landed.value !== body) {\n\t\t\tthrow new StateVersionConflict(stage, expectedVersion, String(Version));\n\t\t}\n\t\treturn String(Version);\n\t}\n\n\tprotected async writeV1Backup(stage: string, body: string): Promise<void> {\n\t\ttry {\n\t\t\tawait this.client.send(\n\t\t\t\tnew PutParameterCommand({\n\t\t\t\t\tName: this.name(stage, 'state.v1'),\n\t\t\t\t\tValue: body,\n\t\t\t\t\tType: 'SecureString',\n\t\t\t\t\tDescription: `GKM v1 deployment state for ${this.workspaceName}/${stage}, kept on migration`,\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\t// The first migration's backup is the one worth keeping.\n\t\t\tif (!(error instanceof ParameterAlreadyExists)) throw error;\n\t\t}\n\t}\n\n\tprotected async createLock(stage: string, holder: LockHolder): Promise<void> {\n\t\tconst Name = this.name(stage, 'lock');\n\t\ttry {\n\t\t\tawait this.client.send(\n\t\t\t\tnew PutParameterCommand({\n\t\t\t\t\tName,\n\t\t\t\t\tValue: JSON.stringify(holder),\n\t\t\t\t\tType: 'String',\n\t\t\t\t\tDescription: `GKM deploy lock for ${this.workspaceName}/${stage}`,\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (error instanceof ParameterAlreadyExists) {\n\t\t\t\tthrow new StateLocked(stage, await this.readLock(stage), `ssm:${Name}`);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\n\t\t// A create-only put is atomic on SSM, so the lock is ours. Read it back\n\t\t// anyway: on a store where two racing creates can both succeed (the\n\t\t// local emulator does, a few times in a hundred) the later one has\n\t\t// overwritten the earlier — version 2, someone else's holder — and\n\t\t// taking the lock regardless would give the stage two deploys.\n\t\tconst created = await this.get(Name);\n\t\tconst recorded = created ? parseHolder(created.value) : null;\n\t\tif (created?.version !== 1 || recorded?.id !== holder.id) {\n\t\t\tthrow new StateLocked(stage, recorded, `ssm:${Name}`);\n\t\t}\n\t}\n\n\tprotected async readLock(stage: string): Promise<LockHolder | null> {\n\t\tconst parameter = await this.get(this.name(stage, 'lock'));\n\t\treturn parameter ? parseHolder(parameter.value) : null;\n\t}\n\n\tprotected async removeLock(\n\t\tstage: string,\n\t\tholder: LockHolder | null,\n\t): Promise<void> {\n\t\tif (holder) {\n\t\t\tconst current = await this.readLock(stage);\n\t\t\tif (current?.id !== holder.id) return;\n\t\t}\n\t\ttry {\n\t\t\tawait this.client.send(\n\t\t\t\tnew DeleteParameterCommand({ Name: this.name(stage, 'lock') }),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (!(error instanceof ParameterNotFound)) throw error;\n\t\t}\n\t}\n\n\tprivate async get(\n\t\tName: string,\n\t): Promise<{ value: string; version: number } | null> {\n\t\ttry {\n\t\t\tconst { Parameter } = await this.client.send(\n\t\t\t\tnew GetParameterCommand({ Name, WithDecryption: true }),\n\t\t\t);\n\t\t\tif (Parameter?.Value === undefined) return null;\n\t\t\treturn { value: Parameter.Value, version: Parameter.Version ?? 1 };\n\t\t} catch (error) {\n\t\t\tif (error instanceof ParameterNotFound) return null;\n\t\t\tthrow error;\n\t\t}\n\t}\n}\n\nfunction parseHolder(value: string): LockHolder | null {\n\ttry {\n\t\treturn JSON.parse(value) as LockHolder;\n\t} catch {\n\t\treturn null;\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const require_seeds = require("./seeds-CsI0A_Ef.cjs");
|
|
2
2
|
let _aws_sdk_client_ssm = require("@aws-sdk/client-ssm");
|
|
3
3
|
//#region src/deploy/SSMStateStore.ts
|
|
4
4
|
/**
|
|
@@ -14,7 +14,7 @@ let _aws_sdk_client_ssm = require("@aws-sdk/client-ssm");
|
|
|
14
14
|
* another writer, and raises `StateVersionConflict` rather than reporting
|
|
15
15
|
* success. Both writes stay in the parameter's history.
|
|
16
16
|
*/
|
|
17
|
-
var SSMStateStore = class SSMStateStore extends
|
|
17
|
+
var SSMStateStore = class SSMStateStore extends require_seeds.DocumentStateStore {
|
|
18
18
|
workspaceName;
|
|
19
19
|
client;
|
|
20
20
|
constructor(workspaceName, client) {
|
|
@@ -61,13 +61,13 @@ var SSMStateStore = class SSMStateStore extends require_sniffer.DocumentStateSto
|
|
|
61
61
|
} catch (error) {
|
|
62
62
|
if (error instanceof _aws_sdk_client_ssm.ParameterAlreadyExists) {
|
|
63
63
|
const current = await this.get(Name);
|
|
64
|
-
throw new
|
|
64
|
+
throw new require_seeds.StateVersionConflict(stage, null, current ? String(current.version) : null);
|
|
65
65
|
}
|
|
66
66
|
throw error;
|
|
67
67
|
}
|
|
68
68
|
const current = await this.get(Name);
|
|
69
69
|
const actual = current ? String(current.version) : null;
|
|
70
|
-
if (actual !== expectedVersion) throw new
|
|
70
|
+
if (actual !== expectedVersion) throw new require_seeds.StateVersionConflict(stage, expectedVersion, actual);
|
|
71
71
|
const { Version } = await this.client.send(new _aws_sdk_client_ssm.PutParameterCommand({
|
|
72
72
|
Name,
|
|
73
73
|
Value: body,
|
|
@@ -75,9 +75,9 @@ var SSMStateStore = class SSMStateStore extends require_sniffer.DocumentStateSto
|
|
|
75
75
|
Overwrite: true,
|
|
76
76
|
Description
|
|
77
77
|
}));
|
|
78
|
-
if (Version !== Number(expectedVersion) + 1) throw new
|
|
78
|
+
if (Version !== Number(expectedVersion) + 1) throw new require_seeds.StateVersionConflict(stage, expectedVersion, String((Version ?? 1) - 1));
|
|
79
79
|
const landed = await this.get(Name);
|
|
80
|
-
if (landed && landed.version === Version && landed.value !== body) throw new
|
|
80
|
+
if (landed && landed.version === Version && landed.value !== body) throw new require_seeds.StateVersionConflict(stage, expectedVersion, String(Version));
|
|
81
81
|
return String(Version);
|
|
82
82
|
}
|
|
83
83
|
async writeV1Backup(stage, body) {
|
|
@@ -102,12 +102,12 @@ var SSMStateStore = class SSMStateStore extends require_sniffer.DocumentStateSto
|
|
|
102
102
|
Description: `GKM deploy lock for ${this.workspaceName}/${stage}`
|
|
103
103
|
}));
|
|
104
104
|
} catch (error) {
|
|
105
|
-
if (error instanceof _aws_sdk_client_ssm.ParameterAlreadyExists) throw new
|
|
105
|
+
if (error instanceof _aws_sdk_client_ssm.ParameterAlreadyExists) throw new require_seeds.StateLocked(stage, await this.readLock(stage), `ssm:${Name}`);
|
|
106
106
|
throw error;
|
|
107
107
|
}
|
|
108
108
|
const created = await this.get(Name);
|
|
109
109
|
const recorded = created ? parseHolder(created.value) : null;
|
|
110
|
-
if (created?.version !== 1 || recorded?.id !== holder.id) throw new
|
|
110
|
+
if (created?.version !== 1 || recorded?.id !== holder.id) throw new require_seeds.StateLocked(stage, recorded, `ssm:${Name}`);
|
|
111
111
|
}
|
|
112
112
|
async readLock(stage) {
|
|
113
113
|
const parameter = await this.get(this.name(stage, "lock"));
|
|
@@ -150,4 +150,4 @@ function parseHolder(value) {
|
|
|
150
150
|
//#endregion
|
|
151
151
|
exports.SSMStateStore = SSMStateStore;
|
|
152
152
|
|
|
153
|
-
//# sourceMappingURL=SSMStateStore-
|
|
153
|
+
//# sourceMappingURL=SSMStateStore-aBOTF018.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SSMStateStore-Z2OMVCtq.cjs","names":["DocumentStateStore","SSMClient","PutParameterCommand","ParameterAlreadyExists","StateVersionConflict","StateLocked","DeleteParameterCommand","ParameterNotFound","GetParameterCommand"],"sources":["../src/deploy/SSMStateStore.ts"],"sourcesContent":["/**\n * AWS SSM Parameter Store state store.\n *\n * - `/gkm/<workspace>/<stage>/state`: the state, a SecureString.\n * - `/gkm/<workspace>/<stage>/lock`: the lock, created only if absent.\n * - `/gkm/<workspace>/<stage>/state.v1`: the v1 state, kept on migration.\n *\n * SSM has no conditional put, so a write checks the parameter's version\n * before it puts, and checks the version the put returns after: a put that\n * did not land exactly one version above the one it was based on raced\n * another writer, and raises `StateVersionConflict` rather than reporting\n * success. Both writes stay in the parameter's history.\n */\n\nimport {\n\tDeleteParameterCommand,\n\tGetParameterCommand,\n\tParameterAlreadyExists,\n\tParameterNotFound,\n\tPutParameterCommand,\n\tSSMClient,\n\ttype SSMClientConfig,\n} from '@aws-sdk/client-ssm';\nimport type { AwsRegion } from './StateProvider';\nimport {\n\tDocumentStateStore,\n\ttype LockHolder,\n\ttype RawState,\n\tStateLocked,\n\ttype StateVersion,\n\tStateVersionConflict,\n} from './StateStore';\n\nexport interface SSMStateStoreOptions {\n\tworkspaceName: string;\n\tregion?: AwsRegion;\n\t/** Uses the default credential chain when omitted. */\n\tprofile?: string;\n\tcredentials?: SSMClientConfig['credentials'];\n\t/** For the local AWS emulator. */\n\tendpoint?: string;\n}\n\nexport class SSMStateStore extends DocumentStateStore {\n\tconstructor(\n\t\treadonly workspaceName: string,\n\t\tprivate readonly client: SSMClient,\n\t) {\n\t\tsuper();\n\t}\n\n\tstatic create(options: SSMStateStoreOptions): SSMStateStore {\n\t\tconst config: SSMClientConfig = {\n\t\t\tregion: options.region,\n\t\t\tendpoint: options.endpoint,\n\t\t};\n\t\tif (options.profile) {\n\t\t\t// Required lazily: only a profile needs the credential providers.\n\t\t\tconst { fromIni } = require('@aws-sdk/credential-providers');\n\t\t\tconfig.credentials = fromIni({ profile: options.profile });\n\t\t} else if (options.credentials) {\n\t\t\tconfig.credentials = options.credentials;\n\t\t}\n\t\treturn new SSMStateStore(options.workspaceName, new SSMClient(config));\n\t}\n\n\tprivate name(stage: string, leaf: string): string {\n\t\treturn `/gkm/${this.workspaceName}/${stage}/${leaf}`;\n\t}\n\n\tprotected location(stage: string): string {\n\t\treturn `ssm:${this.name(stage, 'state')}`;\n\t}\n\n\tprotected async readRaw(stage: string): Promise<RawState | null> {\n\t\tconst parameter = await this.get(this.name(stage, 'state'));\n\t\tif (!parameter) return null;\n\t\treturn { body: parameter.value, version: String(parameter.version) };\n\t}\n\n\tprotected async writeRaw(\n\t\tstage: string,\n\t\tbody: string,\n\t\texpectedVersion: StateVersion | null,\n\t): Promise<StateVersion> {\n\t\tconst Name = this.name(stage, 'state');\n\t\tconst Description = `GKM deployment state for ${this.workspaceName}/${stage}`;\n\n\t\tif (expectedVersion === null) {\n\t\t\ttry {\n\t\t\t\tconst { Version } = await this.client.send(\n\t\t\t\t\tnew PutParameterCommand({\n\t\t\t\t\t\tName,\n\t\t\t\t\t\tValue: body,\n\t\t\t\t\t\tType: 'SecureString',\n\t\t\t\t\t\tDescription,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn String(Version);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof ParameterAlreadyExists) {\n\t\t\t\t\tconst current = await this.get(Name);\n\t\t\t\t\tthrow new StateVersionConflict(\n\t\t\t\t\t\tstage,\n\t\t\t\t\t\tnull,\n\t\t\t\t\t\tcurrent ? String(current.version) : null,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\tconst current = await this.get(Name);\n\t\tconst actual = current ? String(current.version) : null;\n\t\tif (actual !== expectedVersion) {\n\t\t\tthrow new StateVersionConflict(stage, expectedVersion, actual);\n\t\t}\n\n\t\tconst { Version } = await this.client.send(\n\t\t\tnew PutParameterCommand({\n\t\t\t\tName,\n\t\t\t\tValue: body,\n\t\t\t\tType: 'SecureString',\n\t\t\t\tOverwrite: true,\n\t\t\t\tDescription,\n\t\t\t}),\n\t\t);\n\t\tif (Version !== Number(expectedVersion) + 1) {\n\t\t\t// Another put landed between the check and this one. Ours is now\n\t\t\t// on top, but the caller that wrote the other believes its write\n\t\t\t// is current — its next write will conflict too, so neither is\n\t\t\t// lost silently.\n\t\t\tthrow new StateVersionConflict(\n\t\t\t\tstage,\n\t\t\t\texpectedVersion,\n\t\t\t\tString((Version ?? 1) - 1),\n\t\t\t);\n\t\t}\n\n\t\t// The version alone is not enough under an emulator, and need not be\n\t\t// on SSM either: two overwrites that raced can both be answered with\n\t\t// the same version, and both would report success. If the parameter is\n\t\t// still at the version this put returned, it has to hold this body —\n\t\t// otherwise the other put is the one that stuck.\n\t\tconst landed = await this.get(Name);\n\t\tif (landed && landed.version === Version && landed.value !== body) {\n\t\t\tthrow new StateVersionConflict(stage, expectedVersion, String(Version));\n\t\t}\n\t\treturn String(Version);\n\t}\n\n\tprotected async writeV1Backup(stage: string, body: string): Promise<void> {\n\t\ttry {\n\t\t\tawait this.client.send(\n\t\t\t\tnew PutParameterCommand({\n\t\t\t\t\tName: this.name(stage, 'state.v1'),\n\t\t\t\t\tValue: body,\n\t\t\t\t\tType: 'SecureString',\n\t\t\t\t\tDescription: `GKM v1 deployment state for ${this.workspaceName}/${stage}, kept on migration`,\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\t// The first migration's backup is the one worth keeping.\n\t\t\tif (!(error instanceof ParameterAlreadyExists)) throw error;\n\t\t}\n\t}\n\n\tprotected async createLock(stage: string, holder: LockHolder): Promise<void> {\n\t\tconst Name = this.name(stage, 'lock');\n\t\ttry {\n\t\t\tawait this.client.send(\n\t\t\t\tnew PutParameterCommand({\n\t\t\t\t\tName,\n\t\t\t\t\tValue: JSON.stringify(holder),\n\t\t\t\t\tType: 'String',\n\t\t\t\t\tDescription: `GKM deploy lock for ${this.workspaceName}/${stage}`,\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (error instanceof ParameterAlreadyExists) {\n\t\t\t\tthrow new StateLocked(stage, await this.readLock(stage), `ssm:${Name}`);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\n\t\t// A create-only put is atomic on SSM, so the lock is ours. Read it back\n\t\t// anyway: on a store where two racing creates can both succeed (the\n\t\t// local emulator does, a few times in a hundred) the later one has\n\t\t// overwritten the earlier — version 2, someone else's holder — and\n\t\t// taking the lock regardless would give the stage two deploys.\n\t\tconst created = await this.get(Name);\n\t\tconst recorded = created ? parseHolder(created.value) : null;\n\t\tif (created?.version !== 1 || recorded?.id !== holder.id) {\n\t\t\tthrow new StateLocked(stage, recorded, `ssm:${Name}`);\n\t\t}\n\t}\n\n\tprotected async readLock(stage: string): Promise<LockHolder | null> {\n\t\tconst parameter = await this.get(this.name(stage, 'lock'));\n\t\treturn parameter ? parseHolder(parameter.value) : null;\n\t}\n\n\tprotected async removeLock(\n\t\tstage: string,\n\t\tholder: LockHolder | null,\n\t): Promise<void> {\n\t\tif (holder) {\n\t\t\tconst current = await this.readLock(stage);\n\t\t\tif (current?.id !== holder.id) return;\n\t\t}\n\t\ttry {\n\t\t\tawait this.client.send(\n\t\t\t\tnew DeleteParameterCommand({ Name: this.name(stage, 'lock') }),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (!(error instanceof ParameterNotFound)) throw error;\n\t\t}\n\t}\n\n\tprivate async get(\n\t\tName: string,\n\t): Promise<{ value: string; version: number } | null> {\n\t\ttry {\n\t\t\tconst { Parameter } = await this.client.send(\n\t\t\t\tnew GetParameterCommand({ Name, WithDecryption: true }),\n\t\t\t);\n\t\t\tif (Parameter?.Value === undefined) return null;\n\t\t\treturn { value: Parameter.Value, version: Parameter.Version ?? 1 };\n\t\t} catch (error) {\n\t\t\tif (error instanceof ParameterNotFound) return null;\n\t\t\tthrow error;\n\t\t}\n\t}\n}\n\nfunction parseHolder(value: string): LockHolder | null {\n\ttry {\n\t\treturn JSON.parse(value) as LockHolder;\n\t} catch {\n\t\treturn null;\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SSMStateStore-aBOTF018.cjs","names":["DocumentStateStore","SSMClient","PutParameterCommand","ParameterAlreadyExists","StateVersionConflict","StateLocked","DeleteParameterCommand","ParameterNotFound","GetParameterCommand"],"sources":["../src/deploy/SSMStateStore.ts"],"sourcesContent":["/**\n * AWS SSM Parameter Store state store.\n *\n * - `/gkm/<workspace>/<stage>/state`: the state, a SecureString.\n * - `/gkm/<workspace>/<stage>/lock`: the lock, created only if absent.\n * - `/gkm/<workspace>/<stage>/state.v1`: the v1 state, kept on migration.\n *\n * SSM has no conditional put, so a write checks the parameter's version\n * before it puts, and checks the version the put returns after: a put that\n * did not land exactly one version above the one it was based on raced\n * another writer, and raises `StateVersionConflict` rather than reporting\n * success. Both writes stay in the parameter's history.\n */\n\nimport {\n\tDeleteParameterCommand,\n\tGetParameterCommand,\n\tParameterAlreadyExists,\n\tParameterNotFound,\n\tPutParameterCommand,\n\tSSMClient,\n\ttype SSMClientConfig,\n} from '@aws-sdk/client-ssm';\nimport type { AwsRegion } from './StateProvider';\nimport {\n\tDocumentStateStore,\n\ttype LockHolder,\n\ttype RawState,\n\tStateLocked,\n\ttype StateVersion,\n\tStateVersionConflict,\n} from './StateStore';\n\nexport interface SSMStateStoreOptions {\n\tworkspaceName: string;\n\tregion?: AwsRegion;\n\t/** Uses the default credential chain when omitted. */\n\tprofile?: string;\n\tcredentials?: SSMClientConfig['credentials'];\n\t/** For the local AWS emulator. */\n\tendpoint?: string;\n}\n\nexport class SSMStateStore extends DocumentStateStore {\n\tconstructor(\n\t\treadonly workspaceName: string,\n\t\tprivate readonly client: SSMClient,\n\t) {\n\t\tsuper();\n\t}\n\n\tstatic create(options: SSMStateStoreOptions): SSMStateStore {\n\t\tconst config: SSMClientConfig = {\n\t\t\tregion: options.region,\n\t\t\tendpoint: options.endpoint,\n\t\t};\n\t\tif (options.profile) {\n\t\t\t// Required lazily: only a profile needs the credential providers.\n\t\t\tconst { fromIni } = require('@aws-sdk/credential-providers');\n\t\t\tconfig.credentials = fromIni({ profile: options.profile });\n\t\t} else if (options.credentials) {\n\t\t\tconfig.credentials = options.credentials;\n\t\t}\n\t\treturn new SSMStateStore(options.workspaceName, new SSMClient(config));\n\t}\n\n\tprivate name(stage: string, leaf: string): string {\n\t\treturn `/gkm/${this.workspaceName}/${stage}/${leaf}`;\n\t}\n\n\tprotected location(stage: string): string {\n\t\treturn `ssm:${this.name(stage, 'state')}`;\n\t}\n\n\tprotected async readRaw(stage: string): Promise<RawState | null> {\n\t\tconst parameter = await this.get(this.name(stage, 'state'));\n\t\tif (!parameter) return null;\n\t\treturn { body: parameter.value, version: String(parameter.version) };\n\t}\n\n\tprotected async writeRaw(\n\t\tstage: string,\n\t\tbody: string,\n\t\texpectedVersion: StateVersion | null,\n\t): Promise<StateVersion> {\n\t\tconst Name = this.name(stage, 'state');\n\t\tconst Description = `GKM deployment state for ${this.workspaceName}/${stage}`;\n\n\t\tif (expectedVersion === null) {\n\t\t\ttry {\n\t\t\t\tconst { Version } = await this.client.send(\n\t\t\t\t\tnew PutParameterCommand({\n\t\t\t\t\t\tName,\n\t\t\t\t\t\tValue: body,\n\t\t\t\t\t\tType: 'SecureString',\n\t\t\t\t\t\tDescription,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn String(Version);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof ParameterAlreadyExists) {\n\t\t\t\t\tconst current = await this.get(Name);\n\t\t\t\t\tthrow new StateVersionConflict(\n\t\t\t\t\t\tstage,\n\t\t\t\t\t\tnull,\n\t\t\t\t\t\tcurrent ? String(current.version) : null,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\tconst current = await this.get(Name);\n\t\tconst actual = current ? String(current.version) : null;\n\t\tif (actual !== expectedVersion) {\n\t\t\tthrow new StateVersionConflict(stage, expectedVersion, actual);\n\t\t}\n\n\t\tconst { Version } = await this.client.send(\n\t\t\tnew PutParameterCommand({\n\t\t\t\tName,\n\t\t\t\tValue: body,\n\t\t\t\tType: 'SecureString',\n\t\t\t\tOverwrite: true,\n\t\t\t\tDescription,\n\t\t\t}),\n\t\t);\n\t\tif (Version !== Number(expectedVersion) + 1) {\n\t\t\t// Another put landed between the check and this one. Ours is now\n\t\t\t// on top, but the caller that wrote the other believes its write\n\t\t\t// is current — its next write will conflict too, so neither is\n\t\t\t// lost silently.\n\t\t\tthrow new StateVersionConflict(\n\t\t\t\tstage,\n\t\t\t\texpectedVersion,\n\t\t\t\tString((Version ?? 1) - 1),\n\t\t\t);\n\t\t}\n\n\t\t// The version alone is not enough under an emulator, and need not be\n\t\t// on SSM either: two overwrites that raced can both be answered with\n\t\t// the same version, and both would report success. If the parameter is\n\t\t// still at the version this put returned, it has to hold this body —\n\t\t// otherwise the other put is the one that stuck.\n\t\tconst landed = await this.get(Name);\n\t\tif (landed && landed.version === Version && landed.value !== body) {\n\t\t\tthrow new StateVersionConflict(stage, expectedVersion, String(Version));\n\t\t}\n\t\treturn String(Version);\n\t}\n\n\tprotected async writeV1Backup(stage: string, body: string): Promise<void> {\n\t\ttry {\n\t\t\tawait this.client.send(\n\t\t\t\tnew PutParameterCommand({\n\t\t\t\t\tName: this.name(stage, 'state.v1'),\n\t\t\t\t\tValue: body,\n\t\t\t\t\tType: 'SecureString',\n\t\t\t\t\tDescription: `GKM v1 deployment state for ${this.workspaceName}/${stage}, kept on migration`,\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\t// The first migration's backup is the one worth keeping.\n\t\t\tif (!(error instanceof ParameterAlreadyExists)) throw error;\n\t\t}\n\t}\n\n\tprotected async createLock(stage: string, holder: LockHolder): Promise<void> {\n\t\tconst Name = this.name(stage, 'lock');\n\t\ttry {\n\t\t\tawait this.client.send(\n\t\t\t\tnew PutParameterCommand({\n\t\t\t\t\tName,\n\t\t\t\t\tValue: JSON.stringify(holder),\n\t\t\t\t\tType: 'String',\n\t\t\t\t\tDescription: `GKM deploy lock for ${this.workspaceName}/${stage}`,\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (error instanceof ParameterAlreadyExists) {\n\t\t\t\tthrow new StateLocked(stage, await this.readLock(stage), `ssm:${Name}`);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\n\t\t// A create-only put is atomic on SSM, so the lock is ours. Read it back\n\t\t// anyway: on a store where two racing creates can both succeed (the\n\t\t// local emulator does, a few times in a hundred) the later one has\n\t\t// overwritten the earlier — version 2, someone else's holder — and\n\t\t// taking the lock regardless would give the stage two deploys.\n\t\tconst created = await this.get(Name);\n\t\tconst recorded = created ? parseHolder(created.value) : null;\n\t\tif (created?.version !== 1 || recorded?.id !== holder.id) {\n\t\t\tthrow new StateLocked(stage, recorded, `ssm:${Name}`);\n\t\t}\n\t}\n\n\tprotected async readLock(stage: string): Promise<LockHolder | null> {\n\t\tconst parameter = await this.get(this.name(stage, 'lock'));\n\t\treturn parameter ? parseHolder(parameter.value) : null;\n\t}\n\n\tprotected async removeLock(\n\t\tstage: string,\n\t\tholder: LockHolder | null,\n\t): Promise<void> {\n\t\tif (holder) {\n\t\t\tconst current = await this.readLock(stage);\n\t\t\tif (current?.id !== holder.id) return;\n\t\t}\n\t\ttry {\n\t\t\tawait this.client.send(\n\t\t\t\tnew DeleteParameterCommand({ Name: this.name(stage, 'lock') }),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (!(error instanceof ParameterNotFound)) throw error;\n\t\t}\n\t}\n\n\tprivate async get(\n\t\tName: string,\n\t): Promise<{ value: string; version: number } | null> {\n\t\ttry {\n\t\t\tconst { Parameter } = await this.client.send(\n\t\t\t\tnew GetParameterCommand({ Name, WithDecryption: true }),\n\t\t\t);\n\t\t\tif (Parameter?.Value === undefined) return null;\n\t\t\treturn { value: Parameter.Value, version: Parameter.Version ?? 1 };\n\t\t} catch (error) {\n\t\t\tif (error instanceof ParameterNotFound) return null;\n\t\t\tthrow error;\n\t\t}\n\t}\n}\n\nfunction parseHolder(value: string): LockHolder | null {\n\ttry {\n\t\treturn JSON.parse(value) as LockHolder;\n\t} catch {\n\t\treturn null;\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -2,9 +2,9 @@ const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
|
|
|
2
2
|
const require_schemas = require("./schemas-BObwxB_t.cjs");
|
|
3
3
|
const require_discover = require("./discover-D1It5r_h.cjs");
|
|
4
4
|
const require_derive = require("./derive-DAbo49sm.cjs");
|
|
5
|
-
const require_workspace = require("./workspace-
|
|
5
|
+
const require_workspace = require("./workspace-CT0JM3Y8.cjs");
|
|
6
6
|
const require_config = require("./config.cjs");
|
|
7
|
-
const require_seeds = require("./seeds-
|
|
7
|
+
const require_seeds = require("./seeds-CsI0A_Ef.cjs");
|
|
8
8
|
const require_credentialSchemas = require("./credentialSchemas-DCR4Wd1W.cjs");
|
|
9
9
|
let _geekmidas_manifest = require("@geekmidas/manifest");
|
|
10
10
|
let prompts = require("prompts");
|
|
@@ -89,7 +89,8 @@ function workspaceStageKeys(input) {
|
|
|
89
89
|
local: input.local,
|
|
90
90
|
services,
|
|
91
91
|
credentials,
|
|
92
|
-
...input.domain ? { domain: input.domain } : {}
|
|
92
|
+
...input.domain ? { domain: input.domain } : {},
|
|
93
|
+
...input.providers ? { providers: input.providers } : {}
|
|
93
94
|
}).map((key) => ({
|
|
94
95
|
...key,
|
|
95
96
|
set: input.supplied[key.key] !== void 0
|
|
@@ -158,7 +159,8 @@ async function secretsAddCommand(options, io = defaultIo()) {
|
|
|
158
159
|
runnables,
|
|
159
160
|
local,
|
|
160
161
|
supplied: stored?.custom ?? {},
|
|
161
|
-
...domain ? { domain } : {}
|
|
162
|
+
...domain ? { domain } : {},
|
|
163
|
+
providers: require_seeds.stageProviderNotes(workspace, stage)
|
|
162
164
|
});
|
|
163
165
|
const keys = options.missing ? all.filter((k) => !k.set) : all;
|
|
164
166
|
if (options.json) {
|
|
@@ -208,6 +210,7 @@ async function secretsAddCommand(options, io = defaultIo()) {
|
|
|
208
210
|
})) continue;
|
|
209
211
|
}
|
|
210
212
|
io.log(`\n${entry.key} — ${entry.what}`);
|
|
213
|
+
if (entry.hint) io.log(` ${entry.hint}`);
|
|
211
214
|
switch (entry.kind) {
|
|
212
215
|
case "bucket":
|
|
213
216
|
Object.assign(values, await buildBucket(ask, io, entry, has));
|
|
@@ -565,4 +568,4 @@ async function askFields(ask, io, shape) {
|
|
|
565
568
|
//#endregion
|
|
566
569
|
exports.secretsAddCommand = secretsAddCommand;
|
|
567
570
|
|
|
568
|
-
//# sourceMappingURL=add-
|
|
571
|
+
//# sourceMappingURL=add-5MZAXybv.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-5MZAXybv.cjs","names":["provideKey","appKey","appEnvKeys","requiredStageKeys","loadWorkspaceSettings","constructGlobs","discover","secretsStoreFor","stageProviderNotes","loadCredentialSchemas","initStageSecrets","s3Parse","s3Build","issueLine"],"sources":["../src/secrets/stageKeys.ts","../src/secrets/add.ts"],"sourcesContent":["/**\n * The keys a workspace's stage must be given — across every app, each once,\n * with who reads it and whether the stage holds it.\n *\n * The keys themselves are `requiredStageKeys`'s, the list a deploy refuses a\n * stage by. What this adds is the workspace: which constructs its apps read\n * (`appEnvKeys`, the keys each app's environment is built from) and which of\n * the keys the stage has set.\n */\n\nimport { type ConstructManifest, provideKey } from '@geekmidas/manifest';\nimport {\n\ttype CredentialDeclaration,\n\trequiredStageKeys,\n\ttype ServiceDeclaration,\n\ttype StageKey,\n\ttype StageProviderNotes,\n} from '../deploy/devServices';\nimport { appEnvKeys } from '../reconcile/apps';\nimport { appKey } from '../workspace/derive';\n\n/** A stage key, and whether the stage's secrets hold it. */\nexport interface WorkspaceStageKey extends StageKey {\n\tset: boolean;\n}\n\nexport interface WorkspaceStageKeysInput {\n\tmanifest: ConstructManifest;\n\t/** Each owner's runnables' edges, from discovery. */\n\trunnables?: Readonly<Record<string, readonly string[]>>;\n\t/** Whether the stage is the workspace's local one. */\n\tlocal: boolean;\n\t/** What the stage's secrets hold, by key. */\n\tsupplied: Readonly<Record<string, string>>;\n\t/** The stage's base domain, for the examples. */\n\tdomain?: string;\n\t/** What the stage's providers say — a missing key's hint. */\n\tproviders?: StageProviderNotes;\n}\n\n/** The keys of each kind of construct an app reads, that the stage supplies. */\nfunction keysOf(id: string, kind: string): string[] {\n\tswitch (kind) {\n\t\tcase 'email':\n\t\t\treturn [provideKey(id, 'url'), provideKey(id, 'from')];\n\t\tcase 'objects':\n\t\tcase 'file-server':\n\t\t\treturn [provideKey(id, 'url')];\n\t\tcase 'external-api':\n\t\tcase 'credential':\n\t\t\treturn [provideKey(id, 'credentials')];\n\t\tdefault:\n\t\t\treturn [];\n\t}\n}\n\n/**\n * Every key the stage must be given for the constructs its apps read — a\n * file server's whenever its bucket is read, since its client reads both —\n * and every file server's bucket, which serves it whether or not an app\n * reads it directly.\n */\nexport function workspaceStageKeys(\n\tinput: WorkspaceStageKeysInput,\n): WorkspaceStageKey[] {\n\tconst { manifest } = input;\n\n\t// What each app's environment holds.\n\tconst reads = new Map<string, Set<string>>();\n\tfor (const [id, declaration] of Object.entries(manifest)) {\n\t\tconst { kind } = declaration;\n\t\tif (kind !== 'rest-api' && kind !== 'site' && kind !== 'mobile-app') {\n\t\t\tcontinue;\n\t\t}\n\t\tconst name = appKey(id);\n\t\tconst keys = appEnvKeys(manifest, name, input.runnables);\n\t\tif (keys) reads.set(name, keys);\n\t}\n\n\tconst readers = (id: string, kind: string) => {\n\t\tconst keys = keysOf(id, kind);\n\t\treturn [...reads]\n\t\t\t.filter(([, env]) => keys.some((key) => env.has(key)))\n\t\t\t.map(([app]) => app)\n\t\t\t.sort();\n\t};\n\n\tconst services: ServiceDeclaration[] = [];\n\tconst credentials: CredentialDeclaration[] = [];\n\tconst buckets = new Set<string>();\n\tfor (const [id, declaration] of Object.entries(manifest)) {\n\t\tconst { kind } = declaration;\n\t\t// A file server's client reads its bucket's URL and its own, and an\n\t\t// app's edge is to the bucket: whoever reads the bucket reads both.\n\t\tconst apps =\n\t\t\tdeclaration.kind === 'file-server' && declaration.of\n\t\t\t\t? [\n\t\t\t\t\t\t...new Set([\n\t\t\t\t\t\t\t...readers(id, kind),\n\t\t\t\t\t\t\t...readers(declaration.of, 'objects'),\n\t\t\t\t\t\t]),\n\t\t\t\t\t].sort()\n\t\t\t\t: readers(id, kind);\n\t\tif (kind === 'external-api' || kind === 'credential') {\n\t\t\tif (apps.length > 0) credentials.push({ id, kind, apps });\n\t\t\tcontinue;\n\t\t}\n\t\tif (kind !== 'email' && kind !== 'objects' && kind !== 'file-server') {\n\t\t\tcontinue;\n\t\t}\n\t\tif (apps.length === 0) continue;\n\t\tconst of = declaration.kind === 'file-server' ? declaration.of : undefined;\n\t\tservices.push({ id, kind, ...(of ? { of } : {}), apps });\n\t\tif (of) buckets.add(of);\n\t}\n\tfor (const of of buckets) {\n\t\tif (services.some((s) => s.id === of)) continue;\n\t\tif (manifest[of]?.kind !== 'objects') continue;\n\t\tservices.push({ id: of, kind: 'objects', apps: readers(of, 'objects') });\n\t}\n\n\treturn requiredStageKeys({\n\t\tlocal: input.local,\n\t\tservices,\n\t\tcredentials,\n\t\t...(input.domain ? { domain: input.domain } : {}),\n\t\t...(input.providers ? { providers: input.providers } : {}),\n\t}).map((key) => ({ ...key, set: input.supplied[key.key] !== undefined }));\n}\n","/**\n * `gkm secrets:add --stage <stage>` — the secrets a stage must be given,\n * built key by key.\n *\n * It offers exactly the keys a deploy would refuse the stage without\n * (`requiredStageKeys`), across every app in the workspace, each once: the\n * stage's buckets, mail and file servers where it is deployed, and every\n * third party's credentials. A key is built by what it is — a bucket from its\n * provider, mail from its SMTP server, credentials field by field from their\n * construct's schema — checked, and saved through the stage's own store, the\n * one `gkm secrets:set` writes. No value is ever printed.\n *\n * `--json` asks nothing: it prints the keys, for a script or an agent to set\n * with `gkm secrets:set`.\n */\n\nimport {\n\ttype S3Address,\n\tbuild as s3Build,\n\tparse as s3Parse,\n} from '@geekmidas/storage/s3-url';\nimport prompts, { type PromptObject } from 'prompts';\nimport { z } from 'zod';\nimport { loadWorkspaceSettings } from '../config';\nimport { stageProviderNotes } from '../providers/notes.js';\nimport { discover } from '../reconcile/discover';\nimport { constructGlobs } from '../reconcile/workspace';\nimport { assertDeployedStage } from '../workspace/stages';\nimport {\n\ttype CredentialSchemaInfo,\n\ttype CredentialSchemas,\n\tissueLine,\n\tloadCredentialSchemas,\n} from './credentialSchemas';\nimport { type WorkspaceStageKey, workspaceStageKeys } from './stageKeys';\nimport { initStageSecrets } from './storage';\nimport { secretsStoreFor } from './store';\n\nexport interface SecretsAddOptions {\n\tstage: string;\n\t/** Only the keys the stage has not set. */\n\tmissing?: boolean;\n\t/** Print the keys as JSON and ask nothing. */\n\tjson?: boolean;\n\t/** The workspace — the current directory when absent. */\n\tcwd?: string;\n\t/** The CLI's home, for a file store's keys. Defaults to `GKM_HOME`. */\n\thome?: string;\n}\n\n/** Where the command writes, and whether there is anyone to ask. */\nexport interface SecretsAddIo {\n\t/** A line for the person at the terminal. */\n\tlog(line: string): void;\n\t/** `--json`'s output. */\n\twrite(chunk: string): void;\n\t/** Whether prompts can be answered. */\n\tinteractive: boolean;\n}\n\n/** What a run of the command came to. */\nexport interface SecretsAddResult {\n\t/** The keys offered. */\n\tkeys: WorkspaceStageKey[];\n\t/** The keys saved, in the order they were built. */\n\tsaved: string[];\n}\n\n/** One key as `--json` prints it. */\nexport interface StageKeyJson {\n\tkey: string;\n\tkind: WorkspaceStageKey['kind'];\n\tconstruct: string;\n\tapps: string[];\n\tset: boolean;\n}\n\n/** `gkm secrets:add` with nobody at a terminal to answer it. */\nexport class SecretsAddNeedsTerminal extends Error {\n\tconstructor(readonly stage: string) {\n\t\tsuper(\n\t\t\t`gkm secrets:add asks for each key, and there is no terminal to ask ` +\n\t\t\t\t`at. List what the stage needs with ` +\n\t\t\t\t`gkm secrets:add --stage ${stage} --missing --json, and set each ` +\n\t\t\t\t`with gkm secrets:set <KEY> <value> --stage ${stage}.`,\n\t\t);\n\t\tthis.name = 'SecretsAddNeedsTerminal';\n\t}\n}\n\n/** The person stopped the builder; nothing was saved. */\nexport class SecretsAddCancelled extends Error {\n\tconstructor(readonly stage: string) {\n\t\tsuper(`Stopped. Nothing was saved to the stage '${stage}'.`);\n\t\tthis.name = 'SecretsAddCancelled';\n\t}\n}\n\nconst defaultIo = (): SecretsAddIo => ({\n\tlog: (line) => console.log(line),\n\twrite: (chunk) => {\n\t\tprocess.stdout.write(chunk);\n\t},\n\tinteractive: process.stdin.isTTY === true && process.stdout.isTTY === true,\n});\n\n/** `gkm secrets:add`. */\nexport async function secretsAddCommand(\n\toptions: SecretsAddOptions,\n\tio: SecretsAddIo = defaultIo(),\n): Promise<SecretsAddResult> {\n\tconst { stage } = options;\n\tconst workspace = await loadWorkspaceSettings(options.cwd ?? process.cwd());\n\tconst local = stage === workspace.stages.local;\n\tif (!local) assertDeployedStage(workspace.stages, stage);\n\n\tconst patterns = constructGlobs(workspace);\n\tconst runnables: Record<string, string[]> = {};\n\tconst manifest = await discover({\n\t\tpatterns,\n\t\tcwd: workspace.root,\n\t\trunnables,\n\t});\n\n\tconst store = await secretsStoreFor(workspace, stage, {\n\t\t...(options.home ? { home: options.home } : {}),\n\t});\n\tconst stored = await store.read(stage);\n\tconst domain = workspace.deploy?.domains?.[stage];\n\n\tconst all = workspaceStageKeys({\n\t\tmanifest,\n\t\trunnables,\n\t\tlocal,\n\t\tsupplied: stored?.custom ?? {},\n\t\t...(domain ? { domain } : {}),\n\t\tproviders: stageProviderNotes(workspace, stage),\n\t});\n\tconst keys = options.missing ? all.filter((k) => !k.set) : all;\n\n\tif (options.json) {\n\t\tconst listed: StageKeyJson[] = keys.map((k) => ({\n\t\t\tkey: k.key,\n\t\t\tkind: k.kind,\n\t\t\tconstruct: k.id,\n\t\t\tapps: [...(k.apps ?? [])],\n\t\t\tset: k.set,\n\t\t}));\n\t\tio.write(`${JSON.stringify(listed, null, 2)}\\n`);\n\t\treturn { keys, saved: [] };\n\t}\n\n\tif (!io.interactive) throw new SecretsAddNeedsTerminal(stage);\n\n\tif (keys.length === 0) {\n\t\tio.log(\n\t\t\tall.length === 0\n\t\t\t\t? `Nothing to add: no construct on '${stage}' needs a key only the stage can supply.`\n\t\t\t\t: `Nothing to add: the stage '${stage}' has every key it needs.`,\n\t\t);\n\t\treturn { keys, saved: [] };\n\t}\n\n\tconst ask = asker(stage);\n\tconst chosen: string[] = await ask({\n\t\ttype: 'multiselect',\n\t\tmessage: `Which keys for '${stage}'? (${store.name} store)`,\n\t\tchoices: keys.map((k) => ({\n\t\t\ttitle: `${k.key} ${KIND_LABEL[k.kind]} '${k.id}'${k.apps?.length ? ` · ${k.apps.join(', ')}` : ''}${k.set ? ' · set' : ''}`,\n\t\t\tvalue: k.key,\n\t\t\tselected: !k.set,\n\t\t})),\n\t\tinstructions: false,\n\t\thint: 'space to toggle, enter to continue',\n\t});\n\tconst selected = keys.filter((k) => (chosen ?? []).includes(k.key));\n\n\tconst values: Record<string, string> = {};\n\tconst has = (key: string) =>\n\t\tvalues[key] !== undefined || stored?.custom?.[key] !== undefined;\n\tlet schemas: CredentialSchemas | undefined;\n\n\tfor (const entry of selected) {\n\t\tif (entry.set) {\n\t\t\tconst overwrite: boolean = await ask({\n\t\t\t\ttype: 'confirm',\n\t\t\t\tmessage: `${entry.key} is set. Replace it?`,\n\t\t\t\tinitial: false,\n\t\t\t});\n\t\t\tif (!overwrite) continue;\n\t\t}\n\t\tio.log(`\\n${entry.key} — ${entry.what}`);\n\t\tif (entry.hint) io.log(` ${entry.hint}`);\n\n\t\tswitch (entry.kind) {\n\t\t\tcase 'bucket':\n\t\t\t\tObject.assign(values, await buildBucket(ask, io, entry, has));\n\t\t\t\tbreak;\n\t\t\tcase 'email':\n\t\t\t\tvalues[entry.key] = entry.key.endsWith('_FROM')\n\t\t\t\t\t? await askFrom(ask, io)\n\t\t\t\t\t: await buildSmtpUrl(ask, io);\n\t\t\t\tbreak;\n\t\t\tcase 'file-server':\n\t\t\t\tvalues[entry.key] = await askHttpUrl(ask, io, 'Its public URL');\n\t\t\t\tbreak;\n\t\t\tcase 'external-api':\n\t\t\tcase 'credential':\n\t\t\t\tschemas ??= await loadCredentialSchemas({\n\t\t\t\t\troot: workspace.root,\n\t\t\t\t\tpatterns,\n\t\t\t\t});\n\t\t\t\tvalues[entry.key] = await buildCredentials(ask, io, entry, schemas);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tconst saved = Object.keys(values);\n\tif (saved.length === 0) {\n\t\tio.log('\\nNothing was saved.');\n\t\treturn { keys, saved };\n\t}\n\n\tconst base = stored ?? initStageSecrets(stage);\n\tawait store.write(stage, {\n\t\t...base,\n\t\tupdatedAt: new Date().toISOString(),\n\t\tcustom: { ...base.custom, ...values },\n\t});\n\tio.log(\n\t\t`\\n✓ Saved ${saved.join(', ')} to the stage '${stage}' (${store.name} store).`,\n\t);\n\treturn { keys, saved };\n}\n\nconst KIND_LABEL: Record<WorkspaceStageKey['kind'], string> = {\n\tbucket: 'bucket',\n\temail: 'email',\n\t'file-server': 'file server',\n\t'external-api': 'external API',\n\tcredential: 'credential',\n};\n\n/** One question, answered — or the run stopped. */\ntype Ask = <T = string>(question: Omit<PromptObject, 'name'>) => Promise<T>;\n\nfunction asker(stage: string): Ask {\n\treturn async <T>(question: Omit<PromptObject, 'name'>) => {\n\t\tconst answers = await prompts(\n\t\t\t{ ...question, name: 'value' } as PromptObject,\n\t\t\t{\n\t\t\t\tonCancel: () => {\n\t\t\t\t\tthrow new SecretsAddCancelled(stage);\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t\treturn answers.value as T;\n\t};\n}\n\n/** Ask until `accept` takes the answer; `accept` returns why it did not. */\nasync function askUntil<T>(\n\task: Ask,\n\tio: SecretsAddIo,\n\tquestion: Omit<PromptObject, 'name'>,\n\taccept: (value: T) => string | undefined,\n): Promise<T> {\n\tfor (;;) {\n\t\tconst value = await ask<T>(question);\n\t\tconst problem = accept(value);\n\t\tif (!problem) return value;\n\t\tio.log(` ✗ ${problem}`);\n\t}\n}\n\nconst required =\n\t(what: string) =>\n\t(value: string | undefined): string | undefined =>\n\t\tvalue?.trim() ? undefined : `${what} is required.`;\n\nconst text = (value: unknown) => String(value ?? '').trim();\n\n/** An `http(s)://` URL. */\nconst HttpUrl = z.url({ protocol: /^https?$/ });\n\nasync function askHttpUrl(\n\task: Ask,\n\tio: SecretsAddIo,\n\tmessage: string,\n): Promise<string> {\n\treturn text(\n\t\tawait askUntil<string>(ask, io, { type: 'text', message }, (value) =>\n\t\t\tHttpUrl.safeParse(text(value)).success\n\t\t\t\t? undefined\n\t\t\t\t: 'An http:// or https:// URL is required.',\n\t\t),\n\t);\n}\n\nasync function askFrom(ask: Ask, io: SecretsAddIo): Promise<string> {\n\treturn text(\n\t\tawait askUntil<string>(\n\t\t\task,\n\t\t\tio,\n\t\t\t{ type: 'text', message: 'The address it sends from' },\n\t\t\t(value) =>\n\t\t\t\tz.email().safeParse(text(value)).success\n\t\t\t\t\t? undefined\n\t\t\t\t\t: 'An email address is required, e.g. noreply@example.com.',\n\t\t),\n\t);\n}\n\n/**\n * An SMTP server as the URL `@geekmidas/emailkit` reads: `smtp://` for\n * STARTTLS, `smtps://` for TLS from the first byte, with the user and\n * password percent-encoded.\n */\nasync function buildSmtpUrl(ask: Ask, io: SecretsAddIo): Promise<string> {\n\tconst host = text(\n\t\tawait askUntil<string>(\n\t\t\task,\n\t\t\tio,\n\t\t\t{ type: 'text', message: 'SMTP host' },\n\t\t\trequired('The host'),\n\t\t),\n\t);\n\tconst port = await askUntil<string | number>(\n\t\task,\n\t\tio,\n\t\t{ type: 'text', message: 'Port', initial: '587' },\n\t\t(value) => {\n\t\t\tconst n = Number(value);\n\t\t\treturn Number.isInteger(n) && n > 0 && n < 65536\n\t\t\t\t? undefined\n\t\t\t\t: 'A port number is required.';\n\t\t},\n\t);\n\tconst user = text(\n\t\tawait ask<string>({ type: 'text', message: 'User (empty for none)' }),\n\t);\n\tconst password = user\n\t\t? await ask<string>({ type: 'password', message: 'Password' })\n\t\t: '';\n\tconst tls = await ask<'starttls' | 'tls'>({\n\t\ttype: 'select',\n\t\tmessage: 'TLS',\n\t\tchoices: [\n\t\t\t{ title: 'STARTTLS (smtp://, usually port 587)', value: 'starttls' },\n\t\t\t{ title: 'TLS on connect (smtps://, usually port 465)', value: 'tls' },\n\t\t],\n\t\tinitial: 0,\n\t});\n\n\tconst url = new URL(`${tls === 'tls' ? 'smtps' : 'smtp'}://${host}`);\n\turl.port = String(Number(port));\n\tif (user) {\n\t\turl.username = encodeURIComponent(user);\n\t\turl.password = encodeURIComponent(password ?? '');\n\t}\n\treturn url.toString().replace(/\\/$/, '');\n}\n\n/**\n * A bucket's URL, from its provider — and, optionally, a key for it alone in\n * the URL, or the stage's shared pair. Credentials are never required: without\n * them the SDK's own chain signs, a role included.\n */\nasync function buildBucket(\n\task: Ask,\n\tio: SecretsAddIo,\n\tentry: WorkspaceStageKey,\n\thas: (key: string) => boolean,\n): Promise<Record<string, string>> {\n\tconst provider = await ask<'s3' | 'r2' | 'compatible' | 'url'>({\n\t\ttype: 'select',\n\t\tmessage: 'Where is the bucket?',\n\t\tchoices: [\n\t\t\t{ title: 'AWS S3', value: 's3' },\n\t\t\t{ title: 'Cloudflare R2', value: 'r2' },\n\t\t\t{ title: 'MinIO, or another S3-compatible store', value: 'compatible' },\n\t\t\t{ title: 'Paste an s3:// URL', value: 'url' },\n\t\t],\n\t\tinitial: 0,\n\t});\n\n\tconst bucketName = async () =>\n\t\ttext(\n\t\t\tawait askUntil<string>(\n\t\t\t\task,\n\t\t\t\tio,\n\t\t\t\t{ type: 'text', message: 'Bucket name' },\n\t\t\t\trequired('The bucket name'),\n\t\t\t),\n\t\t);\n\n\tlet address: S3Address;\n\tswitch (provider) {\n\t\tcase 's3': {\n\t\t\tconst bucket = await bucketName();\n\t\t\tconst region = text(\n\t\t\t\tawait askUntil<string>(\n\t\t\t\t\task,\n\t\t\t\t\tio,\n\t\t\t\t\t{ type: 'text', message: 'Region', initial: 'eu-west-1' },\n\t\t\t\t\trequired('The region'),\n\t\t\t\t),\n\t\t\t);\n\t\t\taddress = { bucket, region };\n\t\t\tbreak;\n\t\t}\n\t\tcase 'r2': {\n\t\t\tconst account = text(\n\t\t\t\tawait askUntil<string>(\n\t\t\t\t\task,\n\t\t\t\t\tio,\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\tmessage: 'Cloudflare account id, or the R2 endpoint URL',\n\t\t\t\t\t},\n\t\t\t\t\trequired('The account id or endpoint'),\n\t\t\t\t),\n\t\t\t);\n\t\t\tconst bucket = await bucketName();\n\t\t\taddress = {\n\t\t\t\tbucket,\n\t\t\t\tregion: 'auto',\n\t\t\t\tendpoint: /^https?:\\/\\//.test(account)\n\t\t\t\t\t? account\n\t\t\t\t\t: `https://${account}.r2.cloudflarestorage.com`,\n\t\t\t};\n\t\t\tbreak;\n\t\t}\n\t\tcase 'compatible': {\n\t\t\tconst endpoint = await askHttpUrl(ask, io, 'Endpoint URL');\n\t\t\tconst bucket = await bucketName();\n\t\t\tconst region = text(\n\t\t\t\tawait ask<string>({\n\t\t\t\t\ttype: 'text',\n\t\t\t\t\tmessage: 'Region',\n\t\t\t\t\tinitial: 'us-east-1',\n\t\t\t\t}),\n\t\t\t);\n\t\t\tconst forcePathStyle = await ask<boolean>({\n\t\t\t\ttype: 'confirm',\n\t\t\t\tmessage: 'Path-style addressing? (MinIO needs it)',\n\t\t\t\tinitial: true,\n\t\t\t});\n\t\t\taddress = {\n\t\t\t\tbucket,\n\t\t\t\t...(region ? { region } : {}),\n\t\t\t\tendpoint,\n\t\t\t\t...(forcePathStyle ? { forcePathStyle } : {}),\n\t\t\t};\n\t\t\tbreak;\n\t\t}\n\t\tcase 'url': {\n\t\t\tconst pasted = await askUntil<string>(\n\t\t\t\task,\n\t\t\t\tio,\n\t\t\t\t{ type: 'password', message: 'The s3:// URL' },\n\t\t\t\t(value) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\ts3Parse(text(value));\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\treturn `Not an s3:// URL the storage client can read (${(error as Error).name}).`;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t);\n\t\t\taddress = s3Parse(text(pasted));\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (!address.accessKeyId) {\n\t\tconst own = await ask<boolean>({\n\t\t\ttype: 'confirm',\n\t\t\tmessage: `A key for '${entry.id}' alone, in its URL? (optional)`,\n\t\t\tinitial: false,\n\t\t});\n\t\tif (own) {\n\t\t\tconst accessKeyId = text(\n\t\t\t\tawait askUntil<string>(\n\t\t\t\t\task,\n\t\t\t\t\tio,\n\t\t\t\t\t{ type: 'text', message: 'Access key id' },\n\t\t\t\t\trequired('The access key id'),\n\t\t\t\t),\n\t\t\t);\n\t\t\tconst secretAccessKey = await askUntil<string>(\n\t\t\t\task,\n\t\t\t\tio,\n\t\t\t\t{ type: 'password', message: 'Secret access key' },\n\t\t\t\trequired('The secret access key'),\n\t\t\t);\n\t\t\taddress = { ...address, accessKeyId, secretAccessKey };\n\t\t}\n\t}\n\n\tconst values: Record<string, string> = { [entry.key]: s3Build(address) };\n\n\tif (!address.accessKeyId && !has('AWS_ACCESS_KEY_ID')) {\n\t\tconst shared = await ask<boolean>({\n\t\t\ttype: 'confirm',\n\t\t\tmessage:\n\t\t\t\t\"Set the stage's shared AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY? \" +\n\t\t\t\t'(optional: without them a role signs)',\n\t\t\tinitial: false,\n\t\t});\n\t\tif (shared) {\n\t\t\tvalues.AWS_ACCESS_KEY_ID = text(\n\t\t\t\tawait askUntil<string>(\n\t\t\t\t\task,\n\t\t\t\t\tio,\n\t\t\t\t\t{ type: 'text', message: 'AWS_ACCESS_KEY_ID' },\n\t\t\t\t\trequired('The access key id'),\n\t\t\t\t),\n\t\t\t);\n\t\t\tvalues.AWS_SECRET_ACCESS_KEY = await askUntil<string>(\n\t\t\t\task,\n\t\t\t\tio,\n\t\t\t\t{ type: 'password', message: 'AWS_SECRET_ACCESS_KEY' },\n\t\t\t\trequired('The secret access key'),\n\t\t\t);\n\t\t}\n\t}\n\n\treturn values;\n}\n\n/** A field whose name says it is a secret, asked for without echo. */\nconst SECRET_FIELD = /secret|key|token|password/i;\n\ninterface JsonSchemaProperty {\n\ttype?: string | string[];\n\tenum?: unknown[];\n\tdescription?: string;\n}\n\n/** The properties of an object schema, or nothing for any other shape. */\nfunction objectProperties(\n\tinfo: CredentialSchemaInfo | undefined,\n):\n\t| { properties: Record<string, JsonSchemaProperty>; required: string[] }\n\t| undefined {\n\tconst schema = info?.jsonSchema;\n\tif (!schema || schema.type !== 'object') return undefined;\n\tconst properties = schema.properties;\n\tif (!properties || typeof properties !== 'object') return undefined;\n\treturn {\n\t\tproperties: properties as Record<string, JsonSchemaProperty>,\n\t\trequired: Array.isArray(schema.required)\n\t\t\t? (schema.required as string[])\n\t\t\t: [],\n\t};\n}\n\nfunction typesOf(property: JsonSchemaProperty): string[] {\n\tif (Array.isArray(property.type)) return property.type;\n\treturn property.type ? [property.type] : [];\n}\n\n/**\n * Credentials, field by field where the construct's schema is an object it\n * can describe, and as JSON otherwise — checked against the schema itself\n * before anything is kept, and asked again, with each issue's path, until\n * the schema takes it.\n */\nasync function buildCredentials(\n\task: Ask,\n\tio: SecretsAddIo,\n\tentry: WorkspaceStageKey,\n\tschemas: CredentialSchemas,\n): Promise<string> {\n\tconst info = schemas.schemas.find((s) => s.key === entry.key);\n\tconst shape = objectProperties(info);\n\tif (!info) {\n\t\tio.log(\n\t\t\t` '${entry.id}' exposes no schema to check against; the value is stored as given.`,\n\t\t);\n\t}\n\n\tfor (;;) {\n\t\tconst raw = shape\n\t\t\t? JSON.stringify(await askFields(ask, io, shape))\n\t\t\t: text(\n\t\t\t\t\tawait ask<string>({\n\t\t\t\t\t\ttype: 'password',\n\t\t\t\t\t\tmessage: 'The value, as JSON (or one opaque string)',\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\tconst check = await schemas.check(entry.key, raw);\n\t\tif (check.ok) return raw;\n\t\tio.log(` ✗ The schema of '${entry.id}' refuses it:`);\n\t\tfor (const issue of check.issues) {\n\t\t\tio.log(` ${issueLine(entry.key, issue)}`);\n\t\t}\n\t\tio.log(' Again:');\n\t}\n}\n\nasync function askFields(\n\task: Ask,\n\tio: SecretsAddIo,\n\tshape: {\n\t\tproperties: Record<string, JsonSchemaProperty>;\n\t\trequired: string[];\n\t},\n): Promise<Record<string, unknown>> {\n\tconst value: Record<string, unknown> = {};\n\tfor (const [name, property] of Object.entries(shape.properties)) {\n\t\tconst optional = !shape.required.includes(name);\n\t\tconst label = `${name}${optional ? ' (optional)' : ''}${property.description ? ` — ${property.description}` : ''}`;\n\t\tconst types = typesOf(property);\n\n\t\tif (property.enum?.length) {\n\t\t\tconst choices = property.enum.map((option) => ({\n\t\t\t\ttitle: String(option),\n\t\t\t\tvalue: option,\n\t\t\t}));\n\t\t\tconst picked = await ask<unknown>({\n\t\t\t\ttype: 'select',\n\t\t\t\tmessage: label,\n\t\t\t\tchoices: optional\n\t\t\t\t\t? [{ title: '(none)', value: undefined }, ...choices]\n\t\t\t\t\t: choices,\n\t\t\t} as Omit<PromptObject, 'name'>);\n\t\t\tif (picked !== undefined) value[name] = picked;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (types.includes('boolean')) {\n\t\t\tvalue[name] = await ask<boolean>({\n\t\t\t\ttype: 'confirm',\n\t\t\t\tmessage: label,\n\t\t\t\tinitial: false,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst numeric = types.includes('number') || types.includes('integer');\n\t\tconst plain = types.length === 0 || types.includes('string');\n\t\tconst answer = await askUntil<string>(\n\t\t\task,\n\t\t\tio,\n\t\t\t{\n\t\t\t\ttype: SECRET_FIELD.test(name) ? 'password' : 'text',\n\t\t\t\tmessage: label,\n\t\t\t},\n\t\t\t(given) => {\n\t\t\t\tconst typed = text(given);\n\t\t\t\tif (!typed) return optional ? undefined : `${name} is required.`;\n\t\t\t\tif (numeric && !plain && Number.isNaN(Number(typed))) {\n\t\t\t\t\treturn `${name} is a number.`;\n\t\t\t\t}\n\t\t\t\tif (!numeric && !plain) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tJSON.parse(typed);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\treturn `${name} is JSON (${types.join(' or ')}).`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn undefined;\n\t\t\t},\n\t\t);\n\t\tconst typed = text(answer);\n\t\tif (!typed) continue;\n\t\tvalue[name] = plain ? typed : numeric ? Number(typed) : JSON.parse(typed);\n\t}\n\treturn value;\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { g as url, o as email } from "./schemas-D-xeKJDD.mjs";
|
|
2
2
|
import { r as discover } from "./discover-BPelzeGW.mjs";
|
|
3
3
|
import { t as appKey } from "./derive-B4vDpzgP.mjs";
|
|
4
|
-
import { j as assertDeployedStage } from "./workspace-
|
|
4
|
+
import { j as assertDeployedStage } from "./workspace-D2CYLMCW.mjs";
|
|
5
5
|
import { loadWorkspaceSettings } from "./config.mjs";
|
|
6
|
-
import {
|
|
6
|
+
import { C as stageProviderNotes, It as appEnvKeys, On as secretsStoreFor, Q as requiredStageKeys, Wn as initStageSecrets, ct as constructGlobs } from "./seeds-BYdrtZsC.mjs";
|
|
7
7
|
import { i as issueLine, o as loadCredentialSchemas } from "./credentialSchemas-BJqRJNK4.mjs";
|
|
8
8
|
import { provideKey } from "@geekmidas/manifest";
|
|
9
9
|
import prompts from "prompts";
|
|
@@ -87,7 +87,8 @@ function workspaceStageKeys(input) {
|
|
|
87
87
|
local: input.local,
|
|
88
88
|
services,
|
|
89
89
|
credentials,
|
|
90
|
-
...input.domain ? { domain: input.domain } : {}
|
|
90
|
+
...input.domain ? { domain: input.domain } : {},
|
|
91
|
+
...input.providers ? { providers: input.providers } : {}
|
|
91
92
|
}).map((key) => ({
|
|
92
93
|
...key,
|
|
93
94
|
set: input.supplied[key.key] !== void 0
|
|
@@ -156,7 +157,8 @@ async function secretsAddCommand(options, io = defaultIo()) {
|
|
|
156
157
|
runnables,
|
|
157
158
|
local,
|
|
158
159
|
supplied: stored?.custom ?? {},
|
|
159
|
-
...domain ? { domain } : {}
|
|
160
|
+
...domain ? { domain } : {},
|
|
161
|
+
providers: stageProviderNotes(workspace, stage)
|
|
160
162
|
});
|
|
161
163
|
const keys = options.missing ? all.filter((k) => !k.set) : all;
|
|
162
164
|
if (options.json) {
|
|
@@ -206,6 +208,7 @@ async function secretsAddCommand(options, io = defaultIo()) {
|
|
|
206
208
|
})) continue;
|
|
207
209
|
}
|
|
208
210
|
io.log(`\n${entry.key} — ${entry.what}`);
|
|
211
|
+
if (entry.hint) io.log(` ${entry.hint}`);
|
|
209
212
|
switch (entry.kind) {
|
|
210
213
|
case "bucket":
|
|
211
214
|
Object.assign(values, await buildBucket(ask, io, entry, has));
|
|
@@ -563,4 +566,4 @@ async function askFields(ask, io, shape) {
|
|
|
563
566
|
//#endregion
|
|
564
567
|
export { secretsAddCommand };
|
|
565
568
|
|
|
566
|
-
//# sourceMappingURL=add-
|
|
569
|
+
//# sourceMappingURL=add-D_jNqnfZ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-D_jNqnfZ.mjs","names":["z.url","z.email","s3Parse","s3Build"],"sources":["../src/secrets/stageKeys.ts","../src/secrets/add.ts"],"sourcesContent":["/**\n * The keys a workspace's stage must be given — across every app, each once,\n * with who reads it and whether the stage holds it.\n *\n * The keys themselves are `requiredStageKeys`'s, the list a deploy refuses a\n * stage by. What this adds is the workspace: which constructs its apps read\n * (`appEnvKeys`, the keys each app's environment is built from) and which of\n * the keys the stage has set.\n */\n\nimport { type ConstructManifest, provideKey } from '@geekmidas/manifest';\nimport {\n\ttype CredentialDeclaration,\n\trequiredStageKeys,\n\ttype ServiceDeclaration,\n\ttype StageKey,\n\ttype StageProviderNotes,\n} from '../deploy/devServices';\nimport { appEnvKeys } from '../reconcile/apps';\nimport { appKey } from '../workspace/derive';\n\n/** A stage key, and whether the stage's secrets hold it. */\nexport interface WorkspaceStageKey extends StageKey {\n\tset: boolean;\n}\n\nexport interface WorkspaceStageKeysInput {\n\tmanifest: ConstructManifest;\n\t/** Each owner's runnables' edges, from discovery. */\n\trunnables?: Readonly<Record<string, readonly string[]>>;\n\t/** Whether the stage is the workspace's local one. */\n\tlocal: boolean;\n\t/** What the stage's secrets hold, by key. */\n\tsupplied: Readonly<Record<string, string>>;\n\t/** The stage's base domain, for the examples. */\n\tdomain?: string;\n\t/** What the stage's providers say — a missing key's hint. */\n\tproviders?: StageProviderNotes;\n}\n\n/** The keys of each kind of construct an app reads, that the stage supplies. */\nfunction keysOf(id: string, kind: string): string[] {\n\tswitch (kind) {\n\t\tcase 'email':\n\t\t\treturn [provideKey(id, 'url'), provideKey(id, 'from')];\n\t\tcase 'objects':\n\t\tcase 'file-server':\n\t\t\treturn [provideKey(id, 'url')];\n\t\tcase 'external-api':\n\t\tcase 'credential':\n\t\t\treturn [provideKey(id, 'credentials')];\n\t\tdefault:\n\t\t\treturn [];\n\t}\n}\n\n/**\n * Every key the stage must be given for the constructs its apps read — a\n * file server's whenever its bucket is read, since its client reads both —\n * and every file server's bucket, which serves it whether or not an app\n * reads it directly.\n */\nexport function workspaceStageKeys(\n\tinput: WorkspaceStageKeysInput,\n): WorkspaceStageKey[] {\n\tconst { manifest } = input;\n\n\t// What each app's environment holds.\n\tconst reads = new Map<string, Set<string>>();\n\tfor (const [id, declaration] of Object.entries(manifest)) {\n\t\tconst { kind } = declaration;\n\t\tif (kind !== 'rest-api' && kind !== 'site' && kind !== 'mobile-app') {\n\t\t\tcontinue;\n\t\t}\n\t\tconst name = appKey(id);\n\t\tconst keys = appEnvKeys(manifest, name, input.runnables);\n\t\tif (keys) reads.set(name, keys);\n\t}\n\n\tconst readers = (id: string, kind: string) => {\n\t\tconst keys = keysOf(id, kind);\n\t\treturn [...reads]\n\t\t\t.filter(([, env]) => keys.some((key) => env.has(key)))\n\t\t\t.map(([app]) => app)\n\t\t\t.sort();\n\t};\n\n\tconst services: ServiceDeclaration[] = [];\n\tconst credentials: CredentialDeclaration[] = [];\n\tconst buckets = new Set<string>();\n\tfor (const [id, declaration] of Object.entries(manifest)) {\n\t\tconst { kind } = declaration;\n\t\t// A file server's client reads its bucket's URL and its own, and an\n\t\t// app's edge is to the bucket: whoever reads the bucket reads both.\n\t\tconst apps =\n\t\t\tdeclaration.kind === 'file-server' && declaration.of\n\t\t\t\t? [\n\t\t\t\t\t\t...new Set([\n\t\t\t\t\t\t\t...readers(id, kind),\n\t\t\t\t\t\t\t...readers(declaration.of, 'objects'),\n\t\t\t\t\t\t]),\n\t\t\t\t\t].sort()\n\t\t\t\t: readers(id, kind);\n\t\tif (kind === 'external-api' || kind === 'credential') {\n\t\t\tif (apps.length > 0) credentials.push({ id, kind, apps });\n\t\t\tcontinue;\n\t\t}\n\t\tif (kind !== 'email' && kind !== 'objects' && kind !== 'file-server') {\n\t\t\tcontinue;\n\t\t}\n\t\tif (apps.length === 0) continue;\n\t\tconst of = declaration.kind === 'file-server' ? declaration.of : undefined;\n\t\tservices.push({ id, kind, ...(of ? { of } : {}), apps });\n\t\tif (of) buckets.add(of);\n\t}\n\tfor (const of of buckets) {\n\t\tif (services.some((s) => s.id === of)) continue;\n\t\tif (manifest[of]?.kind !== 'objects') continue;\n\t\tservices.push({ id: of, kind: 'objects', apps: readers(of, 'objects') });\n\t}\n\n\treturn requiredStageKeys({\n\t\tlocal: input.local,\n\t\tservices,\n\t\tcredentials,\n\t\t...(input.domain ? { domain: input.domain } : {}),\n\t\t...(input.providers ? { providers: input.providers } : {}),\n\t}).map((key) => ({ ...key, set: input.supplied[key.key] !== undefined }));\n}\n","/**\n * `gkm secrets:add --stage <stage>` — the secrets a stage must be given,\n * built key by key.\n *\n * It offers exactly the keys a deploy would refuse the stage without\n * (`requiredStageKeys`), across every app in the workspace, each once: the\n * stage's buckets, mail and file servers where it is deployed, and every\n * third party's credentials. A key is built by what it is — a bucket from its\n * provider, mail from its SMTP server, credentials field by field from their\n * construct's schema — checked, and saved through the stage's own store, the\n * one `gkm secrets:set` writes. No value is ever printed.\n *\n * `--json` asks nothing: it prints the keys, for a script or an agent to set\n * with `gkm secrets:set`.\n */\n\nimport {\n\ttype S3Address,\n\tbuild as s3Build,\n\tparse as s3Parse,\n} from '@geekmidas/storage/s3-url';\nimport prompts, { type PromptObject } from 'prompts';\nimport { z } from 'zod';\nimport { loadWorkspaceSettings } from '../config';\nimport { stageProviderNotes } from '../providers/notes.js';\nimport { discover } from '../reconcile/discover';\nimport { constructGlobs } from '../reconcile/workspace';\nimport { assertDeployedStage } from '../workspace/stages';\nimport {\n\ttype CredentialSchemaInfo,\n\ttype CredentialSchemas,\n\tissueLine,\n\tloadCredentialSchemas,\n} from './credentialSchemas';\nimport { type WorkspaceStageKey, workspaceStageKeys } from './stageKeys';\nimport { initStageSecrets } from './storage';\nimport { secretsStoreFor } from './store';\n\nexport interface SecretsAddOptions {\n\tstage: string;\n\t/** Only the keys the stage has not set. */\n\tmissing?: boolean;\n\t/** Print the keys as JSON and ask nothing. */\n\tjson?: boolean;\n\t/** The workspace — the current directory when absent. */\n\tcwd?: string;\n\t/** The CLI's home, for a file store's keys. Defaults to `GKM_HOME`. */\n\thome?: string;\n}\n\n/** Where the command writes, and whether there is anyone to ask. */\nexport interface SecretsAddIo {\n\t/** A line for the person at the terminal. */\n\tlog(line: string): void;\n\t/** `--json`'s output. */\n\twrite(chunk: string): void;\n\t/** Whether prompts can be answered. */\n\tinteractive: boolean;\n}\n\n/** What a run of the command came to. */\nexport interface SecretsAddResult {\n\t/** The keys offered. */\n\tkeys: WorkspaceStageKey[];\n\t/** The keys saved, in the order they were built. */\n\tsaved: string[];\n}\n\n/** One key as `--json` prints it. */\nexport interface StageKeyJson {\n\tkey: string;\n\tkind: WorkspaceStageKey['kind'];\n\tconstruct: string;\n\tapps: string[];\n\tset: boolean;\n}\n\n/** `gkm secrets:add` with nobody at a terminal to answer it. */\nexport class SecretsAddNeedsTerminal extends Error {\n\tconstructor(readonly stage: string) {\n\t\tsuper(\n\t\t\t`gkm secrets:add asks for each key, and there is no terminal to ask ` +\n\t\t\t\t`at. List what the stage needs with ` +\n\t\t\t\t`gkm secrets:add --stage ${stage} --missing --json, and set each ` +\n\t\t\t\t`with gkm secrets:set <KEY> <value> --stage ${stage}.`,\n\t\t);\n\t\tthis.name = 'SecretsAddNeedsTerminal';\n\t}\n}\n\n/** The person stopped the builder; nothing was saved. */\nexport class SecretsAddCancelled extends Error {\n\tconstructor(readonly stage: string) {\n\t\tsuper(`Stopped. Nothing was saved to the stage '${stage}'.`);\n\t\tthis.name = 'SecretsAddCancelled';\n\t}\n}\n\nconst defaultIo = (): SecretsAddIo => ({\n\tlog: (line) => console.log(line),\n\twrite: (chunk) => {\n\t\tprocess.stdout.write(chunk);\n\t},\n\tinteractive: process.stdin.isTTY === true && process.stdout.isTTY === true,\n});\n\n/** `gkm secrets:add`. */\nexport async function secretsAddCommand(\n\toptions: SecretsAddOptions,\n\tio: SecretsAddIo = defaultIo(),\n): Promise<SecretsAddResult> {\n\tconst { stage } = options;\n\tconst workspace = await loadWorkspaceSettings(options.cwd ?? process.cwd());\n\tconst local = stage === workspace.stages.local;\n\tif (!local) assertDeployedStage(workspace.stages, stage);\n\n\tconst patterns = constructGlobs(workspace);\n\tconst runnables: Record<string, string[]> = {};\n\tconst manifest = await discover({\n\t\tpatterns,\n\t\tcwd: workspace.root,\n\t\trunnables,\n\t});\n\n\tconst store = await secretsStoreFor(workspace, stage, {\n\t\t...(options.home ? { home: options.home } : {}),\n\t});\n\tconst stored = await store.read(stage);\n\tconst domain = workspace.deploy?.domains?.[stage];\n\n\tconst all = workspaceStageKeys({\n\t\tmanifest,\n\t\trunnables,\n\t\tlocal,\n\t\tsupplied: stored?.custom ?? {},\n\t\t...(domain ? { domain } : {}),\n\t\tproviders: stageProviderNotes(workspace, stage),\n\t});\n\tconst keys = options.missing ? all.filter((k) => !k.set) : all;\n\n\tif (options.json) {\n\t\tconst listed: StageKeyJson[] = keys.map((k) => ({\n\t\t\tkey: k.key,\n\t\t\tkind: k.kind,\n\t\t\tconstruct: k.id,\n\t\t\tapps: [...(k.apps ?? [])],\n\t\t\tset: k.set,\n\t\t}));\n\t\tio.write(`${JSON.stringify(listed, null, 2)}\\n`);\n\t\treturn { keys, saved: [] };\n\t}\n\n\tif (!io.interactive) throw new SecretsAddNeedsTerminal(stage);\n\n\tif (keys.length === 0) {\n\t\tio.log(\n\t\t\tall.length === 0\n\t\t\t\t? `Nothing to add: no construct on '${stage}' needs a key only the stage can supply.`\n\t\t\t\t: `Nothing to add: the stage '${stage}' has every key it needs.`,\n\t\t);\n\t\treturn { keys, saved: [] };\n\t}\n\n\tconst ask = asker(stage);\n\tconst chosen: string[] = await ask({\n\t\ttype: 'multiselect',\n\t\tmessage: `Which keys for '${stage}'? (${store.name} store)`,\n\t\tchoices: keys.map((k) => ({\n\t\t\ttitle: `${k.key} ${KIND_LABEL[k.kind]} '${k.id}'${k.apps?.length ? ` · ${k.apps.join(', ')}` : ''}${k.set ? ' · set' : ''}`,\n\t\t\tvalue: k.key,\n\t\t\tselected: !k.set,\n\t\t})),\n\t\tinstructions: false,\n\t\thint: 'space to toggle, enter to continue',\n\t});\n\tconst selected = keys.filter((k) => (chosen ?? []).includes(k.key));\n\n\tconst values: Record<string, string> = {};\n\tconst has = (key: string) =>\n\t\tvalues[key] !== undefined || stored?.custom?.[key] !== undefined;\n\tlet schemas: CredentialSchemas | undefined;\n\n\tfor (const entry of selected) {\n\t\tif (entry.set) {\n\t\t\tconst overwrite: boolean = await ask({\n\t\t\t\ttype: 'confirm',\n\t\t\t\tmessage: `${entry.key} is set. Replace it?`,\n\t\t\t\tinitial: false,\n\t\t\t});\n\t\t\tif (!overwrite) continue;\n\t\t}\n\t\tio.log(`\\n${entry.key} — ${entry.what}`);\n\t\tif (entry.hint) io.log(` ${entry.hint}`);\n\n\t\tswitch (entry.kind) {\n\t\t\tcase 'bucket':\n\t\t\t\tObject.assign(values, await buildBucket(ask, io, entry, has));\n\t\t\t\tbreak;\n\t\t\tcase 'email':\n\t\t\t\tvalues[entry.key] = entry.key.endsWith('_FROM')\n\t\t\t\t\t? await askFrom(ask, io)\n\t\t\t\t\t: await buildSmtpUrl(ask, io);\n\t\t\t\tbreak;\n\t\t\tcase 'file-server':\n\t\t\t\tvalues[entry.key] = await askHttpUrl(ask, io, 'Its public URL');\n\t\t\t\tbreak;\n\t\t\tcase 'external-api':\n\t\t\tcase 'credential':\n\t\t\t\tschemas ??= await loadCredentialSchemas({\n\t\t\t\t\troot: workspace.root,\n\t\t\t\t\tpatterns,\n\t\t\t\t});\n\t\t\t\tvalues[entry.key] = await buildCredentials(ask, io, entry, schemas);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tconst saved = Object.keys(values);\n\tif (saved.length === 0) {\n\t\tio.log('\\nNothing was saved.');\n\t\treturn { keys, saved };\n\t}\n\n\tconst base = stored ?? initStageSecrets(stage);\n\tawait store.write(stage, {\n\t\t...base,\n\t\tupdatedAt: new Date().toISOString(),\n\t\tcustom: { ...base.custom, ...values },\n\t});\n\tio.log(\n\t\t`\\n✓ Saved ${saved.join(', ')} to the stage '${stage}' (${store.name} store).`,\n\t);\n\treturn { keys, saved };\n}\n\nconst KIND_LABEL: Record<WorkspaceStageKey['kind'], string> = {\n\tbucket: 'bucket',\n\temail: 'email',\n\t'file-server': 'file server',\n\t'external-api': 'external API',\n\tcredential: 'credential',\n};\n\n/** One question, answered — or the run stopped. */\ntype Ask = <T = string>(question: Omit<PromptObject, 'name'>) => Promise<T>;\n\nfunction asker(stage: string): Ask {\n\treturn async <T>(question: Omit<PromptObject, 'name'>) => {\n\t\tconst answers = await prompts(\n\t\t\t{ ...question, name: 'value' } as PromptObject,\n\t\t\t{\n\t\t\t\tonCancel: () => {\n\t\t\t\t\tthrow new SecretsAddCancelled(stage);\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t\treturn answers.value as T;\n\t};\n}\n\n/** Ask until `accept` takes the answer; `accept` returns why it did not. */\nasync function askUntil<T>(\n\task: Ask,\n\tio: SecretsAddIo,\n\tquestion: Omit<PromptObject, 'name'>,\n\taccept: (value: T) => string | undefined,\n): Promise<T> {\n\tfor (;;) {\n\t\tconst value = await ask<T>(question);\n\t\tconst problem = accept(value);\n\t\tif (!problem) return value;\n\t\tio.log(` ✗ ${problem}`);\n\t}\n}\n\nconst required =\n\t(what: string) =>\n\t(value: string | undefined): string | undefined =>\n\t\tvalue?.trim() ? undefined : `${what} is required.`;\n\nconst text = (value: unknown) => String(value ?? '').trim();\n\n/** An `http(s)://` URL. */\nconst HttpUrl = z.url({ protocol: /^https?$/ });\n\nasync function askHttpUrl(\n\task: Ask,\n\tio: SecretsAddIo,\n\tmessage: string,\n): Promise<string> {\n\treturn text(\n\t\tawait askUntil<string>(ask, io, { type: 'text', message }, (value) =>\n\t\t\tHttpUrl.safeParse(text(value)).success\n\t\t\t\t? undefined\n\t\t\t\t: 'An http:// or https:// URL is required.',\n\t\t),\n\t);\n}\n\nasync function askFrom(ask: Ask, io: SecretsAddIo): Promise<string> {\n\treturn text(\n\t\tawait askUntil<string>(\n\t\t\task,\n\t\t\tio,\n\t\t\t{ type: 'text', message: 'The address it sends from' },\n\t\t\t(value) =>\n\t\t\t\tz.email().safeParse(text(value)).success\n\t\t\t\t\t? undefined\n\t\t\t\t\t: 'An email address is required, e.g. noreply@example.com.',\n\t\t),\n\t);\n}\n\n/**\n * An SMTP server as the URL `@geekmidas/emailkit` reads: `smtp://` for\n * STARTTLS, `smtps://` for TLS from the first byte, with the user and\n * password percent-encoded.\n */\nasync function buildSmtpUrl(ask: Ask, io: SecretsAddIo): Promise<string> {\n\tconst host = text(\n\t\tawait askUntil<string>(\n\t\t\task,\n\t\t\tio,\n\t\t\t{ type: 'text', message: 'SMTP host' },\n\t\t\trequired('The host'),\n\t\t),\n\t);\n\tconst port = await askUntil<string | number>(\n\t\task,\n\t\tio,\n\t\t{ type: 'text', message: 'Port', initial: '587' },\n\t\t(value) => {\n\t\t\tconst n = Number(value);\n\t\t\treturn Number.isInteger(n) && n > 0 && n < 65536\n\t\t\t\t? undefined\n\t\t\t\t: 'A port number is required.';\n\t\t},\n\t);\n\tconst user = text(\n\t\tawait ask<string>({ type: 'text', message: 'User (empty for none)' }),\n\t);\n\tconst password = user\n\t\t? await ask<string>({ type: 'password', message: 'Password' })\n\t\t: '';\n\tconst tls = await ask<'starttls' | 'tls'>({\n\t\ttype: 'select',\n\t\tmessage: 'TLS',\n\t\tchoices: [\n\t\t\t{ title: 'STARTTLS (smtp://, usually port 587)', value: 'starttls' },\n\t\t\t{ title: 'TLS on connect (smtps://, usually port 465)', value: 'tls' },\n\t\t],\n\t\tinitial: 0,\n\t});\n\n\tconst url = new URL(`${tls === 'tls' ? 'smtps' : 'smtp'}://${host}`);\n\turl.port = String(Number(port));\n\tif (user) {\n\t\turl.username = encodeURIComponent(user);\n\t\turl.password = encodeURIComponent(password ?? '');\n\t}\n\treturn url.toString().replace(/\\/$/, '');\n}\n\n/**\n * A bucket's URL, from its provider — and, optionally, a key for it alone in\n * the URL, or the stage's shared pair. Credentials are never required: without\n * them the SDK's own chain signs, a role included.\n */\nasync function buildBucket(\n\task: Ask,\n\tio: SecretsAddIo,\n\tentry: WorkspaceStageKey,\n\thas: (key: string) => boolean,\n): Promise<Record<string, string>> {\n\tconst provider = await ask<'s3' | 'r2' | 'compatible' | 'url'>({\n\t\ttype: 'select',\n\t\tmessage: 'Where is the bucket?',\n\t\tchoices: [\n\t\t\t{ title: 'AWS S3', value: 's3' },\n\t\t\t{ title: 'Cloudflare R2', value: 'r2' },\n\t\t\t{ title: 'MinIO, or another S3-compatible store', value: 'compatible' },\n\t\t\t{ title: 'Paste an s3:// URL', value: 'url' },\n\t\t],\n\t\tinitial: 0,\n\t});\n\n\tconst bucketName = async () =>\n\t\ttext(\n\t\t\tawait askUntil<string>(\n\t\t\t\task,\n\t\t\t\tio,\n\t\t\t\t{ type: 'text', message: 'Bucket name' },\n\t\t\t\trequired('The bucket name'),\n\t\t\t),\n\t\t);\n\n\tlet address: S3Address;\n\tswitch (provider) {\n\t\tcase 's3': {\n\t\t\tconst bucket = await bucketName();\n\t\t\tconst region = text(\n\t\t\t\tawait askUntil<string>(\n\t\t\t\t\task,\n\t\t\t\t\tio,\n\t\t\t\t\t{ type: 'text', message: 'Region', initial: 'eu-west-1' },\n\t\t\t\t\trequired('The region'),\n\t\t\t\t),\n\t\t\t);\n\t\t\taddress = { bucket, region };\n\t\t\tbreak;\n\t\t}\n\t\tcase 'r2': {\n\t\t\tconst account = text(\n\t\t\t\tawait askUntil<string>(\n\t\t\t\t\task,\n\t\t\t\t\tio,\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\tmessage: 'Cloudflare account id, or the R2 endpoint URL',\n\t\t\t\t\t},\n\t\t\t\t\trequired('The account id or endpoint'),\n\t\t\t\t),\n\t\t\t);\n\t\t\tconst bucket = await bucketName();\n\t\t\taddress = {\n\t\t\t\tbucket,\n\t\t\t\tregion: 'auto',\n\t\t\t\tendpoint: /^https?:\\/\\//.test(account)\n\t\t\t\t\t? account\n\t\t\t\t\t: `https://${account}.r2.cloudflarestorage.com`,\n\t\t\t};\n\t\t\tbreak;\n\t\t}\n\t\tcase 'compatible': {\n\t\t\tconst endpoint = await askHttpUrl(ask, io, 'Endpoint URL');\n\t\t\tconst bucket = await bucketName();\n\t\t\tconst region = text(\n\t\t\t\tawait ask<string>({\n\t\t\t\t\ttype: 'text',\n\t\t\t\t\tmessage: 'Region',\n\t\t\t\t\tinitial: 'us-east-1',\n\t\t\t\t}),\n\t\t\t);\n\t\t\tconst forcePathStyle = await ask<boolean>({\n\t\t\t\ttype: 'confirm',\n\t\t\t\tmessage: 'Path-style addressing? (MinIO needs it)',\n\t\t\t\tinitial: true,\n\t\t\t});\n\t\t\taddress = {\n\t\t\t\tbucket,\n\t\t\t\t...(region ? { region } : {}),\n\t\t\t\tendpoint,\n\t\t\t\t...(forcePathStyle ? { forcePathStyle } : {}),\n\t\t\t};\n\t\t\tbreak;\n\t\t}\n\t\tcase 'url': {\n\t\t\tconst pasted = await askUntil<string>(\n\t\t\t\task,\n\t\t\t\tio,\n\t\t\t\t{ type: 'password', message: 'The s3:// URL' },\n\t\t\t\t(value) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\ts3Parse(text(value));\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\treturn `Not an s3:// URL the storage client can read (${(error as Error).name}).`;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t);\n\t\t\taddress = s3Parse(text(pasted));\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (!address.accessKeyId) {\n\t\tconst own = await ask<boolean>({\n\t\t\ttype: 'confirm',\n\t\t\tmessage: `A key for '${entry.id}' alone, in its URL? (optional)`,\n\t\t\tinitial: false,\n\t\t});\n\t\tif (own) {\n\t\t\tconst accessKeyId = text(\n\t\t\t\tawait askUntil<string>(\n\t\t\t\t\task,\n\t\t\t\t\tio,\n\t\t\t\t\t{ type: 'text', message: 'Access key id' },\n\t\t\t\t\trequired('The access key id'),\n\t\t\t\t),\n\t\t\t);\n\t\t\tconst secretAccessKey = await askUntil<string>(\n\t\t\t\task,\n\t\t\t\tio,\n\t\t\t\t{ type: 'password', message: 'Secret access key' },\n\t\t\t\trequired('The secret access key'),\n\t\t\t);\n\t\t\taddress = { ...address, accessKeyId, secretAccessKey };\n\t\t}\n\t}\n\n\tconst values: Record<string, string> = { [entry.key]: s3Build(address) };\n\n\tif (!address.accessKeyId && !has('AWS_ACCESS_KEY_ID')) {\n\t\tconst shared = await ask<boolean>({\n\t\t\ttype: 'confirm',\n\t\t\tmessage:\n\t\t\t\t\"Set the stage's shared AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY? \" +\n\t\t\t\t'(optional: without them a role signs)',\n\t\t\tinitial: false,\n\t\t});\n\t\tif (shared) {\n\t\t\tvalues.AWS_ACCESS_KEY_ID = text(\n\t\t\t\tawait askUntil<string>(\n\t\t\t\t\task,\n\t\t\t\t\tio,\n\t\t\t\t\t{ type: 'text', message: 'AWS_ACCESS_KEY_ID' },\n\t\t\t\t\trequired('The access key id'),\n\t\t\t\t),\n\t\t\t);\n\t\t\tvalues.AWS_SECRET_ACCESS_KEY = await askUntil<string>(\n\t\t\t\task,\n\t\t\t\tio,\n\t\t\t\t{ type: 'password', message: 'AWS_SECRET_ACCESS_KEY' },\n\t\t\t\trequired('The secret access key'),\n\t\t\t);\n\t\t}\n\t}\n\n\treturn values;\n}\n\n/** A field whose name says it is a secret, asked for without echo. */\nconst SECRET_FIELD = /secret|key|token|password/i;\n\ninterface JsonSchemaProperty {\n\ttype?: string | string[];\n\tenum?: unknown[];\n\tdescription?: string;\n}\n\n/** The properties of an object schema, or nothing for any other shape. */\nfunction objectProperties(\n\tinfo: CredentialSchemaInfo | undefined,\n):\n\t| { properties: Record<string, JsonSchemaProperty>; required: string[] }\n\t| undefined {\n\tconst schema = info?.jsonSchema;\n\tif (!schema || schema.type !== 'object') return undefined;\n\tconst properties = schema.properties;\n\tif (!properties || typeof properties !== 'object') return undefined;\n\treturn {\n\t\tproperties: properties as Record<string, JsonSchemaProperty>,\n\t\trequired: Array.isArray(schema.required)\n\t\t\t? (schema.required as string[])\n\t\t\t: [],\n\t};\n}\n\nfunction typesOf(property: JsonSchemaProperty): string[] {\n\tif (Array.isArray(property.type)) return property.type;\n\treturn property.type ? [property.type] : [];\n}\n\n/**\n * Credentials, field by field where the construct's schema is an object it\n * can describe, and as JSON otherwise — checked against the schema itself\n * before anything is kept, and asked again, with each issue's path, until\n * the schema takes it.\n */\nasync function buildCredentials(\n\task: Ask,\n\tio: SecretsAddIo,\n\tentry: WorkspaceStageKey,\n\tschemas: CredentialSchemas,\n): Promise<string> {\n\tconst info = schemas.schemas.find((s) => s.key === entry.key);\n\tconst shape = objectProperties(info);\n\tif (!info) {\n\t\tio.log(\n\t\t\t` '${entry.id}' exposes no schema to check against; the value is stored as given.`,\n\t\t);\n\t}\n\n\tfor (;;) {\n\t\tconst raw = shape\n\t\t\t? JSON.stringify(await askFields(ask, io, shape))\n\t\t\t: text(\n\t\t\t\t\tawait ask<string>({\n\t\t\t\t\t\ttype: 'password',\n\t\t\t\t\t\tmessage: 'The value, as JSON (or one opaque string)',\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\tconst check = await schemas.check(entry.key, raw);\n\t\tif (check.ok) return raw;\n\t\tio.log(` ✗ The schema of '${entry.id}' refuses it:`);\n\t\tfor (const issue of check.issues) {\n\t\t\tio.log(` ${issueLine(entry.key, issue)}`);\n\t\t}\n\t\tio.log(' Again:');\n\t}\n}\n\nasync function askFields(\n\task: Ask,\n\tio: SecretsAddIo,\n\tshape: {\n\t\tproperties: Record<string, JsonSchemaProperty>;\n\t\trequired: string[];\n\t},\n): Promise<Record<string, unknown>> {\n\tconst value: Record<string, unknown> = {};\n\tfor (const [name, property] of Object.entries(shape.properties)) {\n\t\tconst optional = !shape.required.includes(name);\n\t\tconst label = `${name}${optional ? ' (optional)' : ''}${property.description ? ` — ${property.description}` : ''}`;\n\t\tconst types = typesOf(property);\n\n\t\tif (property.enum?.length) {\n\t\t\tconst choices = property.enum.map((option) => ({\n\t\t\t\ttitle: String(option),\n\t\t\t\tvalue: option,\n\t\t\t}));\n\t\t\tconst picked = await ask<unknown>({\n\t\t\t\ttype: 'select',\n\t\t\t\tmessage: label,\n\t\t\t\tchoices: optional\n\t\t\t\t\t? [{ title: '(none)', value: undefined }, ...choices]\n\t\t\t\t\t: choices,\n\t\t\t} as Omit<PromptObject, 'name'>);\n\t\t\tif (picked !== undefined) value[name] = picked;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (types.includes('boolean')) {\n\t\t\tvalue[name] = await ask<boolean>({\n\t\t\t\ttype: 'confirm',\n\t\t\t\tmessage: label,\n\t\t\t\tinitial: false,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst numeric = types.includes('number') || types.includes('integer');\n\t\tconst plain = types.length === 0 || types.includes('string');\n\t\tconst answer = await askUntil<string>(\n\t\t\task,\n\t\t\tio,\n\t\t\t{\n\t\t\t\ttype: SECRET_FIELD.test(name) ? 'password' : 'text',\n\t\t\t\tmessage: label,\n\t\t\t},\n\t\t\t(given) => {\n\t\t\t\tconst typed = text(given);\n\t\t\t\tif (!typed) return optional ? undefined : `${name} is required.`;\n\t\t\t\tif (numeric && !plain && Number.isNaN(Number(typed))) {\n\t\t\t\t\treturn `${name} is a number.`;\n\t\t\t\t}\n\t\t\t\tif (!numeric && !plain) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tJSON.parse(typed);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\treturn `${name} is JSON (${types.join(' or ')}).`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn undefined;\n\t\t\t},\n\t\t);\n\t\tconst typed = text(answer);\n\t\tif (!typed) continue;\n\t\tvalue[name] = plain ? typed : numeric ? Number(typed) : JSON.parse(typed);\n\t}\n\treturn value;\n}\n"],"mappings":"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"}
|
|
@@ -82,10 +82,10 @@ async function bundleServer(options) {
|
|
|
82
82
|
for (const ext of external) args.push(`--external:${ext}`);
|
|
83
83
|
let masterKey;
|
|
84
84
|
if (stage) {
|
|
85
|
-
const { toEmbeddableSecrets, validateEnvironmentVariables, initStageSecrets } = await Promise.resolve().then(() => require("./seeds-
|
|
86
|
-
const { FileSecretsStore, secretsStoreFor } = await Promise.resolve().then(() => require("./seeds-
|
|
85
|
+
const { toEmbeddableSecrets, validateEnvironmentVariables, initStageSecrets } = await Promise.resolve().then(() => require("./seeds-CsI0A_Ef.cjs")).then((n) => n.storage_exports);
|
|
86
|
+
const { FileSecretsStore, secretsStoreFor } = await Promise.resolve().then(() => require("./seeds-CsI0A_Ef.cjs")).then((n) => n.store_exports);
|
|
87
87
|
const { ConfigNotFound, loadWorkspaceSettings } = await Promise.resolve().then(() => require("./config.cjs"));
|
|
88
|
-
const { encryptSecrets, generateDefineOptions } = await Promise.resolve().then(() => require("./sniffer-
|
|
88
|
+
const { encryptSecrets, generateDefineOptions } = await Promise.resolve().then(() => require("./sniffer-DJYupBeK.cjs")).then((n) => n.encryption_exports);
|
|
89
89
|
const store = await loadWorkspaceSettings().then((workspace) => secretsStoreFor(workspace, stage), (error) => {
|
|
90
90
|
if (error instanceof ConfigNotFound) return new FileSecretsStore(process.cwd());
|
|
91
91
|
throw error;
|
|
@@ -133,7 +133,7 @@ async function bundleServer(options) {
|
|
|
133
133
|
const encryptedPath = (0, node_path.join)(gkmDir, "credentials.enc");
|
|
134
134
|
const ivPath = (0, node_path.join)(gkmDir, "credentials.iv");
|
|
135
135
|
if ((0, node_fs.existsSync)(encryptedPath) && (0, node_fs.existsSync)(ivPath)) {
|
|
136
|
-
const { generateDefineOptions } = await Promise.resolve().then(() => require("./sniffer-
|
|
136
|
+
const { generateDefineOptions } = await Promise.resolve().then(() => require("./sniffer-DJYupBeK.cjs")).then((n) => n.encryption_exports);
|
|
137
137
|
const defines = generateDefineOptions({
|
|
138
138
|
encrypted: (0, node_fs.readFileSync)(encryptedPath, "utf-8").trim(),
|
|
139
139
|
iv: (0, node_fs.readFileSync)(ivPath, "utf-8").trim(),
|
|
@@ -166,4 +166,4 @@ async function bundleServer(options) {
|
|
|
166
166
|
//#endregion
|
|
167
167
|
exports.bundleServer = bundleServer;
|
|
168
168
|
|
|
169
|
-
//# sourceMappingURL=bundler-
|
|
169
|
+
//# sourceMappingURL=bundler-1REMhKps.cjs.map
|