@geekmidas/cli 10.0.0-alpha.10 → 10.0.0-alpha.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -40
- package/dist/{CachedStateProvider-CqPdW7CB.cjs → CachedStateProvider-BEBl2wQT.cjs} +1 -1
- package/dist/{CachedStateProvider-CqPdW7CB.cjs.map → CachedStateProvider-BEBl2wQT.cjs.map} +1 -1
- package/dist/CachedStateProvider-C-8wtlto.mjs +3 -0
- package/dist/{CachedStateProvider-DTniehMP.mjs → CachedStateProvider-Co4n5Wvs.mjs} +1 -1
- package/dist/{CachedStateProvider-DTniehMP.mjs.map → CachedStateProvider-Co4n5Wvs.mjs.map} +1 -1
- package/dist/{CachedStateProvider-BLo7zv7S.cjs → CachedStateProvider-DqhGpzsm.cjs} +1 -1
- package/dist/{HostingerProvider-h3EbEp-Z.cjs → HostingerProvider-BOvsgATO.cjs} +1 -1
- package/dist/{HostingerProvider-h3EbEp-Z.cjs.map → HostingerProvider-BOvsgATO.cjs.map} +1 -1
- package/dist/{HostingerProvider-Cft7lEYr.mjs → HostingerProvider-BcyFRbqV.mjs} +1 -1
- package/dist/{HostingerProvider-Cft7lEYr.mjs.map → HostingerProvider-BcyFRbqV.mjs.map} +1 -1
- package/dist/{LocalStateProvider-Bn6tS-oL.mjs → LocalStateProvider-Bq-0C0sg.mjs} +1 -1
- package/dist/{LocalStateProvider-Bn6tS-oL.mjs.map → LocalStateProvider-Bq-0C0sg.mjs.map} +1 -1
- package/dist/{LocalStateProvider-Db9SEjyH.cjs → LocalStateProvider-yjXZXZDM.cjs} +1 -1
- package/dist/{LocalStateProvider-Db9SEjyH.cjs.map → LocalStateProvider-yjXZXZDM.cjs.map} +1 -1
- package/dist/{Route53Provider-RdpUDJQk.mjs → Route53Provider-C0xmer8U.mjs} +1 -1
- package/dist/{Route53Provider-RdpUDJQk.mjs.map → Route53Provider-C0xmer8U.mjs.map} +1 -1
- package/dist/{Route53Provider-di2fMM5N.cjs → Route53Provider-CH9XH7bz.cjs} +1 -1
- package/dist/{Route53Provider-di2fMM5N.cjs.map → Route53Provider-CH9XH7bz.cjs.map} +1 -1
- package/dist/{SSMStateProvider-DyX8s9HI.cjs → SSMStateProvider-CXtNgPfy.cjs} +1 -1
- package/dist/{SSMStateProvider-DyX8s9HI.cjs.map → SSMStateProvider-CXtNgPfy.cjs.map} +1 -1
- package/dist/{SSMStateProvider-BRt2py-A.mjs → SSMStateProvider-DOZifZfE.mjs} +1 -1
- package/dist/{SSMStateProvider-BRt2py-A.mjs.map → SSMStateProvider-DOZifZfE.mjs.map} +1 -1
- package/dist/{backup-provisioner-Bgj5Vi_L.mjs → backup-provisioner-DXXg6FIL.mjs} +1 -1
- package/dist/{backup-provisioner-Bgj5Vi_L.mjs.map → backup-provisioner-DXXg6FIL.mjs.map} +1 -1
- package/dist/{backup-provisioner-BrsHwYG0.cjs → backup-provisioner-cE2PuCTb.cjs} +1 -1
- package/dist/{backup-provisioner-BrsHwYG0.cjs.map → backup-provisioner-cE2PuCTb.cjs.map} +1 -1
- package/dist/{bundler-BY1OmV1e.cjs → bundler-BMekgx7a.cjs} +4 -19
- package/dist/bundler-BMekgx7a.cjs.map +1 -0
- package/dist/{bundler-Be8Zg4Wd.mjs → bundler-Bux2iF-v.mjs} +4 -19
- package/dist/bundler-Bux2iF-v.mjs.map +1 -0
- package/dist/{config-DVVph9yz.mjs → config-DTsVjKZD.mjs} +3 -3
- package/dist/{config-DVVph9yz.mjs.map → config-DTsVjKZD.mjs.map} +1 -1
- package/dist/{config-BZ1F0WuA.cjs → config-RYR9j6EF.cjs} +3 -3
- package/dist/{config-BZ1F0WuA.cjs.map → config-RYR9j6EF.cjs.map} +1 -1
- package/dist/config.cjs +3 -3
- package/dist/config.d.cts +2 -2
- package/dist/config.d.mts +2 -2
- package/dist/config.mjs +3 -3
- package/dist/{credentials-Xamqe_NJ.cjs → credentials-DQRvPz2S.cjs} +1166 -1078
- package/dist/credentials-DQRvPz2S.cjs.map +1 -0
- package/dist/{credentials-dP8vRVRv.mjs → credentials-jMJC63qs.mjs} +1145 -1069
- package/dist/credentials-jMJC63qs.mjs.map +1 -0
- package/dist/{discover-CAlFgYec.mjs → discover-BYHQwQqu.mjs} +15 -2
- package/dist/discover-BYHQwQqu.mjs.map +1 -0
- package/dist/{discover-DTmFeloL.cjs → discover-DmW9Bscc.cjs} +20 -1
- package/dist/discover-DmW9Bscc.cjs.map +1 -0
- package/dist/dokploy-api-5cK2InBm.cjs +3 -0
- package/dist/dokploy-api-D2Ny4Jrc.mjs +3 -0
- package/dist/{dokploy-api-aTFPz7_4.mjs → dokploy-api-pdaBryoY.mjs} +1 -1
- package/dist/{dokploy-api-aTFPz7_4.mjs.map → dokploy-api-pdaBryoY.mjs.map} +1 -1
- package/dist/{dokploy-api-BsVH0y_s.cjs → dokploy-api-zqKe9lHH.cjs} +1 -1
- package/dist/{dokploy-api-BsVH0y_s.cjs.map → dokploy-api-zqKe9lHH.cjs.map} +1 -1
- package/dist/{emit-CiZS_5Ub.mjs → emit-CIlvnDvV.mjs} +1 -1
- package/dist/{emit-CiZS_5Ub.mjs.map → emit-CIlvnDvV.mjs.map} +1 -1
- package/dist/{emit-CbcRolsa.cjs → emit-CUD1BWls.cjs} +1 -1
- package/dist/{emit-CbcRolsa.cjs.map → emit-CUD1BWls.cjs.map} +1 -1
- package/dist/{encryption-C6jaU0hE.cjs → encryption-D2pL3tHH.cjs} +1 -1
- package/dist/{encryption-C6jaU0hE.cjs.map → encryption-D2pL3tHH.cjs.map} +1 -1
- package/dist/encryption-YDsXXi6w.mjs +3 -0
- package/dist/{encryption-D-abyhZx.mjs → encryption-_4zwjOAR.mjs} +1 -1
- package/dist/{encryption-D-abyhZx.mjs.map → encryption-_4zwjOAR.mjs.map} +1 -1
- package/dist/{encryption-CHzzeR8a.cjs → encryption-sQ2Oxx0d.cjs} +1 -1
- package/dist/{fullstack-secrets-D1o9-G5l.mjs → fullstack-secrets-B6KBHf-g.mjs} +2 -2
- package/dist/{fullstack-secrets-D1o9-G5l.mjs.map → fullstack-secrets-B6KBHf-g.mjs.map} +1 -1
- package/dist/{fullstack-secrets-C-GGohke.cjs → fullstack-secrets-DL8v0y4D.cjs} +1 -13
- package/dist/{fullstack-secrets-C-GGohke.cjs.map → fullstack-secrets-DL8v0y4D.cjs.map} +1 -1
- package/dist/github-BThvbf2W.cjs +197 -0
- package/dist/github-BThvbf2W.cjs.map +1 -0
- package/dist/github-DpMZurEK.mjs +196 -0
- package/dist/github-DpMZurEK.mjs.map +1 -0
- package/dist/{index-CR5urhWX.d.cts → index-BzJ7QJ9c.d.mts} +2 -6
- package/dist/index-BzJ7QJ9c.d.mts.map +1 -0
- package/dist/{index-C6e-ULLx.d.mts → index-CfMjtdVC.d.cts} +2 -6
- package/dist/index-CfMjtdVC.d.cts.map +1 -0
- package/dist/index.cjs +474 -1381
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +474 -1381
- package/dist/index.mjs.map +1 -1
- package/dist/keystore-C9rint2E.cjs +101 -0
- package/dist/keystore-C9rint2E.cjs.map +1 -0
- package/dist/keystore-TxeYM7an.mjs +83 -0
- package/dist/keystore-TxeYM7an.mjs.map +1 -0
- package/dist/{openapi-Xx0A7Wg0.mjs → openapi-Bs3-5q_r.mjs} +3 -3
- package/dist/{openapi-Xx0A7Wg0.mjs.map → openapi-Bs3-5q_r.mjs.map} +1 -1
- package/dist/{openapi-SjsgARie.cjs → openapi-DWLTsYLL.cjs} +3 -3
- package/dist/{openapi-SjsgARie.cjs.map → openapi-DWLTsYLL.cjs.map} +1 -1
- package/dist/openapi.cjs +4 -4
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/openapi.mjs +4 -4
- package/dist/reconcile/public.cjs +2 -2
- package/dist/reconcile/public.d.cts +1 -1
- package/dist/reconcile/public.d.mts +1 -1
- package/dist/reconcile/public.mjs +2 -2
- package/dist/{reconcile-CFs8C_1a.mjs → reconcile-BI0tWkwz.mjs} +2 -2
- package/dist/{reconcile-CFs8C_1a.mjs.map → reconcile-BI0tWkwz.mjs.map} +1 -1
- package/dist/{reconcile-D0pimNiy.cjs → reconcile-Bhw5fmKu.cjs} +2 -2
- package/dist/{reconcile-D0pimNiy.cjs.map → reconcile-Bhw5fmKu.cjs.map} +1 -1
- package/dist/setup-BmLoNrDX.mjs +12 -0
- package/dist/setup-BrR1_xGy.cjs +12 -0
- package/dist/{setup-hC6hI86f.cjs → setup-BsNR2LBG.cjs} +16 -22
- package/dist/setup-BsNR2LBG.cjs.map +1 -0
- package/dist/{setup-C8KOx8_8.mjs → setup-D5-JMknk.mjs} +16 -22
- package/dist/setup-D5-JMknk.mjs.map +1 -0
- package/dist/{storage-Bi24WfoW.mjs → storage-B020InPW.mjs} +4 -79
- package/dist/storage-B020InPW.mjs.map +1 -0
- package/dist/{storage-BJmzYxt8.cjs → storage-CSNplaJn.cjs} +4 -85
- package/dist/storage-CSNplaJn.cjs.map +1 -0
- package/dist/{storage-CYlGwWTj.mjs → storage-DGBzMLZa.mjs} +2 -1
- package/dist/{storage-BM9hGpgv.cjs → storage-DlVol_oj.cjs} +2 -1
- package/dist/{sync-SizaChmC.cjs → sync-0ILCb-1S.cjs} +2 -2
- package/dist/{sync-SizaChmC.cjs.map → sync-0ILCb-1S.cjs.map} +1 -1
- package/dist/{sync-CmEuNZsB.mjs → sync-CzHXiR9c.mjs} +2 -2
- package/dist/{sync-CmEuNZsB.mjs.map → sync-CzHXiR9c.mjs.map} +1 -1
- package/dist/sync-DYENfOt4.cjs +4 -0
- package/dist/{sync-hOqAWHR6.mjs → sync-HAau6h_R.mjs} +1 -1
- package/dist/{types-6pkp2RRj.d.mts → types-DVIx8I1N.d.mts} +4 -274
- package/dist/types-DVIx8I1N.d.mts.map +1 -0
- package/dist/{types-Y3fKQSAK.d.cts → types-PMP_qXRY.d.cts} +4 -274
- package/dist/types-PMP_qXRY.d.cts.map +1 -0
- package/dist/workspace/index.cjs +1 -1
- package/dist/workspace/index.d.cts +3 -3
- package/dist/workspace/index.d.mts +3 -3
- package/dist/workspace/index.mjs +1 -1
- package/dist/workspace-Cji6lE8E.cjs +10 -0
- package/dist/workspace-CkJAtRIX.mjs +9 -0
- package/dist/{workspace-zoqRbihZ.mjs → workspace-CtnZnWsa.mjs} +40 -72
- package/dist/workspace-CtnZnWsa.mjs.map +1 -0
- package/dist/{workspace-C6VJQVtG.cjs → workspace-DPV7FtAv.cjs} +45 -71
- package/dist/workspace-DPV7FtAv.cjs.map +1 -0
- package/package.json +11 -11
- package/dist/CachedStateProvider-BxoAm-B2.mjs +0 -3
- package/dist/bundler-BY1OmV1e.cjs.map +0 -1
- package/dist/bundler-Be8Zg4Wd.mjs.map +0 -1
- package/dist/credentials-Xamqe_NJ.cjs.map +0 -1
- package/dist/credentials-dP8vRVRv.mjs.map +0 -1
- package/dist/discover-CAlFgYec.mjs.map +0 -1
- package/dist/discover-DTmFeloL.cjs.map +0 -1
- package/dist/dokploy-api-BS2xnJLZ.mjs +0 -3
- package/dist/dokploy-api-BuxDRo3l.cjs +0 -3
- package/dist/encryption-CQUncu7v.mjs +0 -3
- package/dist/index-C6e-ULLx.d.mts.map +0 -1
- package/dist/index-CR5urhWX.d.cts.map +0 -1
- package/dist/setup-BA8ciTPU.mjs +0 -11
- package/dist/setup-BsZvZP6f.cjs +0 -11
- package/dist/setup-C8KOx8_8.mjs.map +0 -1
- package/dist/setup-hC6hI86f.cjs.map +0 -1
- package/dist/storage-BJmzYxt8.cjs.map +0 -1
- package/dist/storage-Bi24WfoW.mjs.map +0 -1
- package/dist/sync-D306yOWu.cjs +0 -4
- package/dist/types-6pkp2RRj.d.mts.map +0 -1
- package/dist/types-Y3fKQSAK.d.cts.map +0 -1
- package/dist/workspace-BzrG_2SI.mjs +0 -8
- package/dist/workspace-C6VJQVtG.cjs.map +0 -1
- package/dist/workspace-XXtNhqJl.cjs +0 -9
- package/dist/workspace-zoqRbihZ.mjs.map +0 -1
|
@@ -1,85 +1,10 @@
|
|
|
1
1
|
const require_chunk = require('./chunk-CUT6urMc.cjs');
|
|
2
|
+
const require_keystore = require('./keystore-C9rint2E.cjs');
|
|
2
3
|
const node_fs = require_chunk.__toESM(require("node:fs"));
|
|
3
4
|
const node_path = require_chunk.__toESM(require("node:path"));
|
|
4
5
|
const node_fs_promises = require_chunk.__toESM(require("node:fs/promises"));
|
|
5
|
-
const node_os = require_chunk.__toESM(require("node:os"));
|
|
6
6
|
const node_crypto = require_chunk.__toESM(require("node:crypto"));
|
|
7
7
|
|
|
8
|
-
//#region src/secrets/keystore.ts
|
|
9
|
-
/** Key length for AES-256 encryption */
|
|
10
|
-
const KEY_LENGTH = 32;
|
|
11
|
-
/**
|
|
12
|
-
* Get the keystore directory for a project.
|
|
13
|
-
* Keys are stored at ~/.gkm/{project-name}/
|
|
14
|
-
*
|
|
15
|
-
* @param projectName - Name of the project (defaults to current directory name)
|
|
16
|
-
* @returns Path to the keystore directory
|
|
17
|
-
*/
|
|
18
|
-
function getKeystoreDir(projectName) {
|
|
19
|
-
const name = projectName ?? (0, node_path.basename)(process.cwd());
|
|
20
|
-
return (0, node_path.join)((0, node_os.homedir)(), ".gkm", name);
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Get the path to a stage's encryption key.
|
|
24
|
-
*
|
|
25
|
-
* @param stage - Stage name (e.g., 'development', 'production')
|
|
26
|
-
* @param projectName - Name of the project (defaults to current directory name)
|
|
27
|
-
* @returns Path to the key file
|
|
28
|
-
*/
|
|
29
|
-
function getKeyPath(stage, projectName) {
|
|
30
|
-
return (0, node_path.join)(getKeystoreDir(projectName), `${stage}.key`);
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Generate a new encryption key for a stage.
|
|
34
|
-
* The key is stored at ~/.gkm/{project-name}/{stage}.key with restricted permissions.
|
|
35
|
-
*
|
|
36
|
-
* @param stage - Stage name
|
|
37
|
-
* @param projectName - Project name (defaults to current directory name)
|
|
38
|
-
* @returns The generated key as a hex string
|
|
39
|
-
*/
|
|
40
|
-
async function generateKey(stage, projectName) {
|
|
41
|
-
const keyDir = getKeystoreDir(projectName);
|
|
42
|
-
const keyPath = getKeyPath(stage, projectName);
|
|
43
|
-
await (0, node_fs_promises.mkdir)(keyDir, {
|
|
44
|
-
recursive: true,
|
|
45
|
-
mode: 448
|
|
46
|
-
});
|
|
47
|
-
const key = (0, node_crypto.randomBytes)(KEY_LENGTH).toString("hex");
|
|
48
|
-
await (0, node_fs_promises.writeFile)(keyPath, key, {
|
|
49
|
-
mode: 384,
|
|
50
|
-
encoding: "utf-8"
|
|
51
|
-
});
|
|
52
|
-
await (0, node_fs_promises.chmod)(keyPath, 384);
|
|
53
|
-
return key;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Read an encryption key for a stage.
|
|
57
|
-
*
|
|
58
|
-
* @param stage - Stage name
|
|
59
|
-
* @param projectName - Project name (defaults to current directory name)
|
|
60
|
-
* @returns The key as a hex string, or null if not found
|
|
61
|
-
*/
|
|
62
|
-
async function readKey(stage, projectName) {
|
|
63
|
-
const keyPath = getKeyPath(stage, projectName);
|
|
64
|
-
if (!(0, node_fs.existsSync)(keyPath)) return null;
|
|
65
|
-
const key = await (0, node_fs_promises.readFile)(keyPath, "utf-8");
|
|
66
|
-
return key.trim();
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Get or create a key for a stage.
|
|
70
|
-
* If the key already exists, it is returned. Otherwise, a new key is generated.
|
|
71
|
-
*
|
|
72
|
-
* @param stage - Stage name
|
|
73
|
-
* @param projectName - Project name (defaults to current directory name)
|
|
74
|
-
* @returns The key as a hex string
|
|
75
|
-
*/
|
|
76
|
-
async function getOrCreateKey(stage, projectName) {
|
|
77
|
-
const existingKey = await readKey(stage, projectName);
|
|
78
|
-
if (existingKey) return existingKey;
|
|
79
|
-
return generateKey(stage, projectName);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
//#endregion
|
|
83
8
|
//#region src/secrets/storage.ts
|
|
84
9
|
/** Default secrets directory relative to project root */
|
|
85
10
|
const SECRETS_DIR = ".gkm/secrets";
|
|
@@ -163,7 +88,7 @@ async function readStageSecrets(stage, cwd = process.cwd()) {
|
|
|
163
88
|
const data = JSON.parse(content);
|
|
164
89
|
if (data.version === 1 && data.encrypted && data.iv) {
|
|
165
90
|
const projectName = (0, node_path.basename)(cwd);
|
|
166
|
-
const key = await readKey(stage, projectName);
|
|
91
|
+
const key = await require_keystore.readKey(stage, projectName);
|
|
167
92
|
if (!key) throw new Error(`Decryption key not found for stage "${stage}". Expected key at: ~/.gkm/${projectName}/${stage}.key`);
|
|
168
93
|
return decryptSecretsData(data, key);
|
|
169
94
|
}
|
|
@@ -178,7 +103,7 @@ async function writeStageSecrets(secrets, cwd = process.cwd()) {
|
|
|
178
103
|
const path = getSecretsPath(secrets.stage, cwd);
|
|
179
104
|
const projectName = (0, node_path.basename)(cwd);
|
|
180
105
|
await (0, node_fs_promises.mkdir)(dir, { recursive: true });
|
|
181
|
-
const key = await getOrCreateKey(secrets.stage, projectName);
|
|
106
|
+
const key = await require_keystore.getOrCreateKey(secrets.stage, projectName);
|
|
182
107
|
const encrypted = encryptSecretsData(secrets, key);
|
|
183
108
|
await (0, node_fs_promises.writeFile)(path, JSON.stringify(encrypted, null, 2), "utf-8");
|
|
184
109
|
}
|
|
@@ -294,12 +219,6 @@ function validateEnvironmentVariables(requiredVars, secrets) {
|
|
|
294
219
|
}
|
|
295
220
|
|
|
296
221
|
//#endregion
|
|
297
|
-
Object.defineProperty(exports, 'getKeyPath', {
|
|
298
|
-
enumerable: true,
|
|
299
|
-
get: function () {
|
|
300
|
-
return getKeyPath;
|
|
301
|
-
}
|
|
302
|
-
});
|
|
303
222
|
Object.defineProperty(exports, 'getSecretsDir', {
|
|
304
223
|
enumerable: true,
|
|
305
224
|
get: function () {
|
|
@@ -360,4 +279,4 @@ Object.defineProperty(exports, 'writeStageSecrets', {
|
|
|
360
279
|
return writeStageSecrets;
|
|
361
280
|
}
|
|
362
281
|
});
|
|
363
|
-
//# sourceMappingURL=storage-
|
|
282
|
+
//# sourceMappingURL=storage-CSNplaJn.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-CSNplaJn.cjs","names":["stage: string","secrets: StageSecrets","keyHex: string","data: EncryptedSecretsFile","key: string","value: string","updated: StageSecrets","password: string","requiredVars: string[]","missing: string[]","provided: string[]"],"sources":["../src/secrets/storage.ts"],"sourcesContent":["import { createCipheriv, createDecipheriv, randomBytes } from 'node:crypto';\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { basename, join } from 'node:path';\nimport { getOrCreateKey, readKey } from './keystore';\nimport type { EmbeddableSecrets, StageSecrets } from './types';\n\n/** Default secrets directory relative to project root */\nconst SECRETS_DIR = '.gkm/secrets';\n\n/** AES-256-GCM configuration */\nconst ALGORITHM = 'aes-256-gcm';\nconst IV_LENGTH = 12; // 96 bits for GCM\nconst AUTH_TAG_LENGTH = 16; // 128 bits\n\n/** Encrypted secrets file structure */\ninterface EncryptedSecretsFile {\n\t/** Version for future format changes */\n\tversion: 1;\n\t/** Base64 encoded encrypted data (ciphertext + auth tag) */\n\tencrypted: string;\n\t/** Hex encoded IV */\n\tiv: string;\n}\n\n/**\n * Get the secrets directory path.\n */\nexport function getSecretsDir(cwd = process.cwd()): string {\n\treturn join(cwd, SECRETS_DIR);\n}\n\n/**\n * Get the secrets file path for a stage.\n */\nexport function getSecretsPath(stage: string, cwd = process.cwd()): string {\n\treturn join(getSecretsDir(cwd), `${stage}.json`);\n}\n\n/**\n * Check if secrets exist for a stage.\n */\nexport function secretsExist(stage: string, cwd = process.cwd()): boolean {\n\treturn existsSync(getSecretsPath(stage, cwd));\n}\n\n/**\n * Initialize an empty StageSecrets object for a stage.\n */\nexport function initStageSecrets(stage: string): StageSecrets {\n\tconst now = new Date().toISOString();\n\treturn {\n\t\tstage,\n\t\tcreatedAt: now,\n\t\tupdatedAt: now,\n\t\tservices: {},\n\t\turls: {},\n\t\tcustom: {},\n\t};\n}\n\n/**\n * Encrypt secrets using a key.\n */\nfunction encryptSecretsData(\n\tsecrets: StageSecrets,\n\tkeyHex: string,\n): EncryptedSecretsFile {\n\tconst key = Buffer.from(keyHex, 'hex');\n\tconst iv = randomBytes(IV_LENGTH);\n\n\t// Serialize secrets to JSON\n\tconst plaintext = JSON.stringify(secrets);\n\n\t// Encrypt\n\tconst cipher = createCipheriv(ALGORITHM, key, iv);\n\tconst ciphertext = Buffer.concat([\n\t\tcipher.update(plaintext, 'utf-8'),\n\t\tcipher.final(),\n\t]);\n\n\t// Get auth tag\n\tconst authTag = cipher.getAuthTag();\n\n\t// Combine ciphertext + auth tag\n\tconst combined = Buffer.concat([ciphertext, authTag]);\n\n\treturn {\n\t\tversion: 1,\n\t\tencrypted: combined.toString('base64'),\n\t\tiv: iv.toString('hex'),\n\t};\n}\n\n/**\n * Decrypt secrets using a key.\n */\nfunction decryptSecretsData(\n\tdata: EncryptedSecretsFile,\n\tkeyHex: string,\n): StageSecrets {\n\tconst key = Buffer.from(keyHex, 'hex');\n\tconst ivBuffer = Buffer.from(data.iv, 'hex');\n\tconst combined = Buffer.from(data.encrypted, 'base64');\n\n\t// Split ciphertext and auth tag\n\tconst ciphertext = combined.subarray(0, -AUTH_TAG_LENGTH);\n\tconst authTag = combined.subarray(-AUTH_TAG_LENGTH);\n\n\t// Decrypt\n\tconst decipher = createDecipheriv(ALGORITHM, key, ivBuffer);\n\tdecipher.setAuthTag(authTag);\n\n\tconst plaintext = Buffer.concat([\n\t\tdecipher.update(ciphertext),\n\t\tdecipher.final(),\n\t]);\n\n\treturn JSON.parse(plaintext.toString('utf-8')) as StageSecrets;\n}\n\n/**\n * Read secrets for a stage (encrypted).\n * Requires the decryption key to be present at ~/.gkm/{project}/{stage}.key\n *\n * @returns StageSecrets or null if not found\n */\nexport async function readStageSecrets(\n\tstage: string,\n\tcwd = process.cwd(),\n): Promise<StageSecrets | null> {\n\tconst path = getSecretsPath(stage, cwd);\n\n\tif (!existsSync(path)) {\n\t\treturn null;\n\t}\n\n\tconst content = await readFile(path, 'utf-8');\n\tconst data = JSON.parse(content);\n\n\t// Check if this is an encrypted file (has version field)\n\tif (data.version === 1 && data.encrypted && data.iv) {\n\t\tconst projectName = basename(cwd);\n\t\tconst key = await readKey(stage, projectName);\n\n\t\tif (!key) {\n\t\t\tthrow new Error(\n\t\t\t\t`Decryption key not found for stage \"${stage}\". ` +\n\t\t\t\t\t`Expected key at: ~/.gkm/${projectName}/${stage}.key`,\n\t\t\t);\n\t\t}\n\n\t\treturn decryptSecretsData(data as EncryptedSecretsFile, key);\n\t}\n\n\t// Legacy: unencrypted format (for backwards compatibility)\n\treturn data as StageSecrets;\n}\n\n/**\n * Write secrets for a stage (encrypted).\n * Creates or uses existing encryption key at ~/.gkm/{project}/{stage}.key\n */\nexport async function writeStageSecrets(\n\tsecrets: StageSecrets,\n\tcwd = process.cwd(),\n): Promise<void> {\n\tconst dir = getSecretsDir(cwd);\n\tconst path = getSecretsPath(secrets.stage, cwd);\n\tconst projectName = basename(cwd);\n\n\t// Ensure directory exists\n\tawait mkdir(dir, { recursive: true });\n\n\t// Get or create encryption key\n\tconst key = await getOrCreateKey(secrets.stage, projectName);\n\n\t// Encrypt and write\n\tconst encrypted = encryptSecretsData(secrets, key);\n\tawait writeFile(path, JSON.stringify(encrypted, null, 2), 'utf-8');\n}\n\n/**\n * Convert StageSecrets to embeddable format (flat key-value pairs).\n * This is what gets encrypted and embedded in the bundle.\n */\nexport function toEmbeddableSecrets(secrets: StageSecrets): EmbeddableSecrets {\n\treturn {\n\t\t...secrets.urls,\n\t\t...secrets.custom,\n\t\t// Also include individual service credentials if needed\n\t\t...(secrets.services.postgres && {\n\t\t\tPOSTGRES_USER: secrets.services.postgres.username,\n\t\t\tPOSTGRES_PASSWORD: secrets.services.postgres.password,\n\t\t\tPOSTGRES_DB: secrets.services.postgres.database ?? 'app',\n\t\t\tPOSTGRES_HOST: secrets.services.postgres.host,\n\t\t\tPOSTGRES_PORT: String(secrets.services.postgres.port),\n\t\t}),\n\t\t...(secrets.services.redis && {\n\t\t\tREDIS_PASSWORD: secrets.services.redis.password,\n\t\t\tREDIS_HOST: secrets.services.redis.host,\n\t\t\tREDIS_PORT: String(secrets.services.redis.port),\n\t\t}),\n\t\t...(secrets.services.rabbitmq && {\n\t\t\tRABBITMQ_USER: secrets.services.rabbitmq.username,\n\t\t\tRABBITMQ_PASSWORD: secrets.services.rabbitmq.password,\n\t\t\tRABBITMQ_HOST: secrets.services.rabbitmq.host,\n\t\t\tRABBITMQ_PORT: String(secrets.services.rabbitmq.port),\n\t\t\tRABBITMQ_VHOST: secrets.services.rabbitmq.vhost ?? '/',\n\t\t}),\n\t\t...(secrets.services.minio && {\n\t\t\tSTORAGE_ACCESS_KEY_ID: secrets.services.minio.username,\n\t\t\tSTORAGE_SECRET_ACCESS_KEY: secrets.services.minio.password,\n\t\t\tSTORAGE_BUCKET: secrets.services.minio.bucket ?? 'app',\n\t\t\tSTORAGE_REGION: 'eu-west-1',\n\t\t\tSTORAGE_FORCE_PATH_STYLE: 'true',\n\t\t}),\n\t\t...(secrets.services.mailpit && {\n\t\t\tSMTP_HOST: secrets.services.mailpit.host,\n\t\t\tSMTP_PORT: String(secrets.services.mailpit.port),\n\t\t\tSMTP_USER: secrets.services.mailpit.username,\n\t\t\tSMTP_PASS: secrets.services.mailpit.password,\n\t\t\tSMTP_SECURE: 'false',\n\t\t\tMAIL_FROM: 'noreply@localhost',\n\t\t}),\n\t\t...(secrets.services.localstack && {\n\t\t\tAWS_ACCESS_KEY_ID:\n\t\t\t\tsecrets.services.localstack.accessKeyId ??\n\t\t\t\tsecrets.services.localstack.username,\n\t\t\tAWS_SECRET_ACCESS_KEY: secrets.services.localstack.password,\n\t\t\tAWS_REGION: secrets.services.localstack.region ?? 'us-east-1',\n\t\t\tAWS_ENDPOINT_URL: `http://${secrets.services.localstack.host}:${secrets.services.localstack.port}`,\n\t\t}),\n\t\t...(secrets.services.pgboss && {\n\t\t\tPGBOSS_DB_USER: secrets.services.pgboss.username,\n\t\t\tPGBOSS_DB_PASSWORD: secrets.services.pgboss.password,\n\t\t}),\n\t};\n}\n\n/**\n * Update a custom secret in the secrets file.\n */\nexport async function setCustomSecret(\n\tstage: string,\n\tkey: string,\n\tvalue: string,\n\tcwd = process.cwd(),\n): Promise<StageSecrets> {\n\tconst secrets = await readStageSecrets(stage, cwd);\n\n\tif (!secrets) {\n\t\tthrow new Error(\n\t\t\t`Secrets not found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t);\n\t}\n\n\tconst updated: StageSecrets = {\n\t\t...secrets,\n\t\tupdatedAt: new Date().toISOString(),\n\t\tcustom: {\n\t\t\t...secrets.custom,\n\t\t\t[key]: value,\n\t\t},\n\t};\n\n\tawait writeStageSecrets(updated, cwd);\n\treturn updated;\n}\n\n/**\n * Mask a password for display (show first 4 and last 2 chars).\n */\nexport function maskPassword(password: string): string {\n\tif (password.length <= 8) {\n\t\treturn '********';\n\t}\n\treturn `${password.slice(0, 4)}${'*'.repeat(password.length - 6)}${password.slice(-2)}`;\n}\n\n/**\n * Result of environment variable validation.\n */\nexport interface EnvValidationResult {\n\t/** Whether all required environment variables are present */\n\tvalid: boolean;\n\t/** List of missing environment variable names */\n\tmissing: string[];\n\t/** List of environment variables that are provided */\n\tprovided: string[];\n\t/** List of environment variables that were required */\n\trequired: string[];\n}\n\n/**\n * Validate that all required environment variables are present in secrets.\n *\n * @param requiredVars - Array of environment variable names required by the application\n * @param secrets - Stage secrets to validate against\n * @returns Validation result with missing and provided variables\n *\n * @example\n * ```typescript\n * const required = ['DATABASE_URL', 'API_KEY', 'JWT_SECRET'];\n * const secrets = await readStageSecrets('production');\n * const result = validateEnvironmentVariables(required, secrets);\n *\n * if (!result.valid) {\n * console.error(`Missing environment variables: ${result.missing.join(', ')}`);\n * }\n * ```\n */\nexport function validateEnvironmentVariables(\n\trequiredVars: string[],\n\tsecrets: StageSecrets,\n): EnvValidationResult {\n\tconst embeddable = toEmbeddableSecrets(secrets);\n\tconst availableVars = new Set(Object.keys(embeddable));\n\n\tconst missing: string[] = [];\n\tconst provided: string[] = [];\n\n\tfor (const varName of requiredVars) {\n\t\tif (availableVars.has(varName)) {\n\t\t\tprovided.push(varName);\n\t\t} else {\n\t\t\tmissing.push(varName);\n\t\t}\n\t}\n\n\treturn {\n\t\tvalid: missing.length === 0,\n\t\tmissing: missing.sort(),\n\t\tprovided: provided.sort(),\n\t\trequired: [...requiredVars].sort(),\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "./keystore-TxeYM7an.mjs";
|
|
2
|
+
import { getSecretsDir, getSecretsPath, initStageSecrets, maskPassword, readStageSecrets, secretsExist, setCustomSecret, toEmbeddableSecrets, validateEnvironmentVariables, writeStageSecrets } from "./storage-B020InPW.mjs";
|
|
2
3
|
|
|
3
4
|
export { initStageSecrets, readStageSecrets, toEmbeddableSecrets, validateEnvironmentVariables, writeStageSecrets };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
require('./keystore-C9rint2E.cjs');
|
|
2
|
+
const require_storage = require('./storage-CSNplaJn.cjs');
|
|
2
3
|
|
|
3
4
|
exports.initStageSecrets = require_storage.initStageSecrets;
|
|
4
5
|
exports.readStageSecrets = require_storage.readStageSecrets;
|
|
@@ -30,7 +30,7 @@ async function pushSecrets(stage, workspace) {
|
|
|
30
30
|
if (!workspace.name) throw new Error("Workspace name is required for SSM secrets sync. Set \"name\" in gkm.config.ts.");
|
|
31
31
|
const client = createSSMClient(config);
|
|
32
32
|
const parameterName = getSecretsParameterName(workspace.name, stage);
|
|
33
|
-
const { readStageSecrets } = await Promise.resolve().then(() => require("./storage-
|
|
33
|
+
const { readStageSecrets } = await Promise.resolve().then(() => require("./storage-DlVol_oj.cjs"));
|
|
34
34
|
const secrets = await readStageSecrets(stage, workspace.root);
|
|
35
35
|
if (!secrets) throw new Error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
|
|
36
36
|
await client.send(new __aws_sdk_client_ssm.PutParameterCommand({
|
|
@@ -90,4 +90,4 @@ Object.defineProperty(exports, 'pushSecrets', {
|
|
|
90
90
|
return pushSecrets;
|
|
91
91
|
}
|
|
92
92
|
});
|
|
93
|
-
//# sourceMappingURL=sync-
|
|
93
|
+
//# sourceMappingURL=sync-0ILCb-1S.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-
|
|
1
|
+
{"version":3,"file":"sync-0ILCb-1S.cjs","names":["workspaceName: string","stage: string","config: SSMStateConfig","clientConfig: SSMClientConfig","SSMClient","workspace: NormalizedWorkspace","PutParameterCommand","GetParameterCommand","ParameterNotFound"],"sources":["../src/secrets/sync.ts"],"sourcesContent":["/**\n * Secrets Sync via AWS SSM Parameter Store\n *\n * Stores and retrieves encrypted StageSecrets as SecureString parameters.\n * Reuses the SSM infrastructure from the state provider.\n *\n * Parameter naming: /gkm/{workspaceName}/{stage}/secrets\n */\n\nimport {\n\tGetParameterCommand,\n\tParameterNotFound,\n\tPutParameterCommand,\n\tSSMClient,\n\ttype SSMClientConfig,\n} from '@aws-sdk/client-ssm';\nimport type { SSMStateConfig } from '../deploy/StateProvider.js';\nimport type { NormalizedWorkspace } from '../workspace/types.js';\nimport type { StageSecrets } from './types.js';\n\n/**\n * Get the SSM parameter name for secrets.\n */\nfunction getSecretsParameterName(workspaceName: string, stage: string): string {\n\treturn `/gkm/${workspaceName}/${stage}/secrets`;\n}\n\n/**\n * Create an SSM client from workspace state config.\n */\nfunction createSSMClient(config: SSMStateConfig): SSMClient {\n\tconst clientConfig: SSMClientConfig = {\n\t\tregion: config.region,\n\t};\n\n\tif (config.profile) {\n\t\tconst { fromIni } = require('@aws-sdk/credential-providers');\n\t\tclientConfig.credentials = fromIni({ profile: config.profile });\n\t}\n\n\treturn new SSMClient(clientConfig);\n}\n\n/**\n * Push secrets to SSM Parameter Store.\n *\n * Stores the full StageSecrets object as a SecureString parameter.\n */\nexport async function pushSecrets(\n\tstage: string,\n\tworkspace: NormalizedWorkspace,\n): Promise<void> {\n\tconst config = workspace.state;\n\tif (!config || config.provider !== 'ssm') {\n\t\tthrow new Error(\n\t\t\t'SSM state provider not configured. Add state: { provider: \"ssm\", region: \"...\" } to gkm.config.ts.',\n\t\t);\n\t}\n\n\tif (!workspace.name) {\n\t\tthrow new Error(\n\t\t\t'Workspace name is required for SSM secrets sync. Set \"name\" in gkm.config.ts.',\n\t\t);\n\t}\n\n\tconst client = createSSMClient(config as SSMStateConfig);\n\tconst parameterName = getSecretsParameterName(workspace.name, stage);\n\n\tconst { readStageSecrets } = await import('./storage.js');\n\tconst secrets = await readStageSecrets(stage, workspace.root);\n\n\tif (!secrets) {\n\t\tthrow new Error(\n\t\t\t`No secrets found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t);\n\t}\n\n\tawait client.send(\n\t\tnew PutParameterCommand({\n\t\t\tName: parameterName,\n\t\t\tValue: JSON.stringify(secrets),\n\t\t\tType: 'SecureString',\n\t\t\tOverwrite: true,\n\t\t\tDescription: `GKM secrets for ${workspace.name}/${stage}`,\n\t\t}),\n\t);\n}\n\n/**\n * Pull secrets from SSM Parameter Store.\n *\n * @returns StageSecrets or null if no secrets are stored remotely\n */\nexport async function pullSecrets(\n\tstage: string,\n\tworkspace: NormalizedWorkspace,\n): Promise<StageSecrets | null> {\n\tconst config = workspace.state;\n\tif (!config || config.provider !== 'ssm') {\n\t\treturn null;\n\t}\n\n\tif (!workspace.name) {\n\t\treturn null;\n\t}\n\n\tconst client = createSSMClient(config as SSMStateConfig);\n\tconst parameterName = getSecretsParameterName(workspace.name, stage);\n\n\ttry {\n\t\tconst response = await client.send(\n\t\t\tnew GetParameterCommand({\n\t\t\t\tName: parameterName,\n\t\t\t\tWithDecryption: true,\n\t\t\t}),\n\t\t);\n\n\t\tif (!response.Parameter?.Value) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn JSON.parse(response.Parameter.Value) as StageSecrets;\n\t} catch (error) {\n\t\tif (error instanceof ParameterNotFound) {\n\t\t\treturn null;\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/**\n * Check if SSM is configured for the workspace.\n */\nexport function isSSMConfigured(workspace: NormalizedWorkspace): boolean {\n\treturn !!workspace.state && workspace.state.provider === 'ssm';\n}\n"],"mappings":";;;;;;;AAuBA,SAAS,wBAAwBA,eAAuBC,OAAuB;AAC9E,SAAQ,OAAO,cAAc,GAAG,MAAM;AACtC;;;;AAKD,SAAS,gBAAgBC,QAAmC;CAC3D,MAAMC,eAAgC,EACrC,QAAQ,OAAO,OACf;AAED,KAAI,OAAO,SAAS;EACnB,MAAM,EAAE,SAAS,GAAG,QAAQ,gCAAgC;AAC5D,eAAa,cAAc,QAAQ,EAAE,SAAS,OAAO,QAAS,EAAC;CAC/D;AAED,QAAO,IAAIC,+BAAU;AACrB;;;;;;AAOD,eAAsB,YACrBH,OACAI,WACgB;CAChB,MAAM,SAAS,UAAU;AACzB,MAAK,UAAU,OAAO,aAAa,MAClC,OAAM,IAAI,MACT;AAIF,MAAK,UAAU,KACd,OAAM,IAAI,MACT;CAIF,MAAM,SAAS,gBAAgB,OAAyB;CACxD,MAAM,gBAAgB,wBAAwB,UAAU,MAAM,MAAM;CAEpE,MAAM,EAAE,kBAAkB,GAAG,2CAAM;CACnC,MAAM,UAAU,MAAM,iBAAiB,OAAO,UAAU,KAAK;AAE7D,MAAK,QACJ,OAAM,IAAI,OACR,8BAA8B,MAAM,mCAAmC,MAAM;AAIhF,OAAM,OAAO,KACZ,IAAIC,yCAAoB;EACvB,MAAM;EACN,OAAO,KAAK,UAAU,QAAQ;EAC9B,MAAM;EACN,WAAW;EACX,cAAc,kBAAkB,UAAU,KAAK,GAAG,MAAM;CACxD,GACD;AACD;;;;;;AAOD,eAAsB,YACrBL,OACAI,WAC+B;CAC/B,MAAM,SAAS,UAAU;AACzB,MAAK,UAAU,OAAO,aAAa,MAClC,QAAO;AAGR,MAAK,UAAU,KACd,QAAO;CAGR,MAAM,SAAS,gBAAgB,OAAyB;CACxD,MAAM,gBAAgB,wBAAwB,UAAU,MAAM,MAAM;AAEpE,KAAI;EACH,MAAM,WAAW,MAAM,OAAO,KAC7B,IAAIE,yCAAoB;GACvB,MAAM;GACN,gBAAgB;EAChB,GACD;AAED,OAAK,SAAS,WAAW,MACxB,QAAO;AAGR,SAAO,KAAK,MAAM,SAAS,UAAU,MAAM;CAC3C,SAAQ,OAAO;AACf,MAAI,iBAAiBC,uCACpB,QAAO;AAER,QAAM;CACN;AACD;;;;AAKD,SAAgB,gBAAgBH,WAAyC;AACxE,UAAS,UAAU,SAAS,UAAU,MAAM,aAAa;AACzD"}
|
|
@@ -30,7 +30,7 @@ async function pushSecrets(stage, workspace) {
|
|
|
30
30
|
if (!workspace.name) throw new Error("Workspace name is required for SSM secrets sync. Set \"name\" in gkm.config.ts.");
|
|
31
31
|
const client = createSSMClient(config);
|
|
32
32
|
const parameterName = getSecretsParameterName(workspace.name, stage);
|
|
33
|
-
const { readStageSecrets } = await import("./storage-
|
|
33
|
+
const { readStageSecrets } = await import("./storage-DGBzMLZa.mjs");
|
|
34
34
|
const secrets = await readStageSecrets(stage, workspace.root);
|
|
35
35
|
if (!secrets) throw new Error(`No secrets found for stage "${stage}". Run "gkm secrets:init --stage ${stage}" first.`);
|
|
36
36
|
await client.send(new PutParameterCommand({
|
|
@@ -73,4 +73,4 @@ function isSSMConfigured(workspace) {
|
|
|
73
73
|
|
|
74
74
|
//#endregion
|
|
75
75
|
export { isSSMConfigured, pullSecrets, pushSecrets };
|
|
76
|
-
//# sourceMappingURL=sync-
|
|
76
|
+
//# sourceMappingURL=sync-CzHXiR9c.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-
|
|
1
|
+
{"version":3,"file":"sync-CzHXiR9c.mjs","names":["workspaceName: string","stage: string","config: SSMStateConfig","clientConfig: SSMClientConfig","workspace: NormalizedWorkspace"],"sources":["../src/secrets/sync.ts"],"sourcesContent":["/**\n * Secrets Sync via AWS SSM Parameter Store\n *\n * Stores and retrieves encrypted StageSecrets as SecureString parameters.\n * Reuses the SSM infrastructure from the state provider.\n *\n * Parameter naming: /gkm/{workspaceName}/{stage}/secrets\n */\n\nimport {\n\tGetParameterCommand,\n\tParameterNotFound,\n\tPutParameterCommand,\n\tSSMClient,\n\ttype SSMClientConfig,\n} from '@aws-sdk/client-ssm';\nimport type { SSMStateConfig } from '../deploy/StateProvider.js';\nimport type { NormalizedWorkspace } from '../workspace/types.js';\nimport type { StageSecrets } from './types.js';\n\n/**\n * Get the SSM parameter name for secrets.\n */\nfunction getSecretsParameterName(workspaceName: string, stage: string): string {\n\treturn `/gkm/${workspaceName}/${stage}/secrets`;\n}\n\n/**\n * Create an SSM client from workspace state config.\n */\nfunction createSSMClient(config: SSMStateConfig): SSMClient {\n\tconst clientConfig: SSMClientConfig = {\n\t\tregion: config.region,\n\t};\n\n\tif (config.profile) {\n\t\tconst { fromIni } = require('@aws-sdk/credential-providers');\n\t\tclientConfig.credentials = fromIni({ profile: config.profile });\n\t}\n\n\treturn new SSMClient(clientConfig);\n}\n\n/**\n * Push secrets to SSM Parameter Store.\n *\n * Stores the full StageSecrets object as a SecureString parameter.\n */\nexport async function pushSecrets(\n\tstage: string,\n\tworkspace: NormalizedWorkspace,\n): Promise<void> {\n\tconst config = workspace.state;\n\tif (!config || config.provider !== 'ssm') {\n\t\tthrow new Error(\n\t\t\t'SSM state provider not configured. Add state: { provider: \"ssm\", region: \"...\" } to gkm.config.ts.',\n\t\t);\n\t}\n\n\tif (!workspace.name) {\n\t\tthrow new Error(\n\t\t\t'Workspace name is required for SSM secrets sync. Set \"name\" in gkm.config.ts.',\n\t\t);\n\t}\n\n\tconst client = createSSMClient(config as SSMStateConfig);\n\tconst parameterName = getSecretsParameterName(workspace.name, stage);\n\n\tconst { readStageSecrets } = await import('./storage.js');\n\tconst secrets = await readStageSecrets(stage, workspace.root);\n\n\tif (!secrets) {\n\t\tthrow new Error(\n\t\t\t`No secrets found for stage \"${stage}\". Run \"gkm secrets:init --stage ${stage}\" first.`,\n\t\t);\n\t}\n\n\tawait client.send(\n\t\tnew PutParameterCommand({\n\t\t\tName: parameterName,\n\t\t\tValue: JSON.stringify(secrets),\n\t\t\tType: 'SecureString',\n\t\t\tOverwrite: true,\n\t\t\tDescription: `GKM secrets for ${workspace.name}/${stage}`,\n\t\t}),\n\t);\n}\n\n/**\n * Pull secrets from SSM Parameter Store.\n *\n * @returns StageSecrets or null if no secrets are stored remotely\n */\nexport async function pullSecrets(\n\tstage: string,\n\tworkspace: NormalizedWorkspace,\n): Promise<StageSecrets | null> {\n\tconst config = workspace.state;\n\tif (!config || config.provider !== 'ssm') {\n\t\treturn null;\n\t}\n\n\tif (!workspace.name) {\n\t\treturn null;\n\t}\n\n\tconst client = createSSMClient(config as SSMStateConfig);\n\tconst parameterName = getSecretsParameterName(workspace.name, stage);\n\n\ttry {\n\t\tconst response = await client.send(\n\t\t\tnew GetParameterCommand({\n\t\t\t\tName: parameterName,\n\t\t\t\tWithDecryption: true,\n\t\t\t}),\n\t\t);\n\n\t\tif (!response.Parameter?.Value) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn JSON.parse(response.Parameter.Value) as StageSecrets;\n\t} catch (error) {\n\t\tif (error instanceof ParameterNotFound) {\n\t\t\treturn null;\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/**\n * Check if SSM is configured for the workspace.\n */\nexport function isSSMConfigured(workspace: NormalizedWorkspace): boolean {\n\treturn !!workspace.state && workspace.state.provider === 'ssm';\n}\n"],"mappings":";;;;;;;AAuBA,SAAS,wBAAwBA,eAAuBC,OAAuB;AAC9E,SAAQ,OAAO,cAAc,GAAG,MAAM;AACtC;;;;AAKD,SAAS,gBAAgBC,QAAmC;CAC3D,MAAMC,eAAgC,EACrC,QAAQ,OAAO,OACf;AAED,KAAI,OAAO,SAAS;EACnB,MAAM,EAAE,SAAS,GAAG,UAAQ,gCAAgC;AAC5D,eAAa,cAAc,QAAQ,EAAE,SAAS,OAAO,QAAS,EAAC;CAC/D;AAED,QAAO,IAAI,UAAU;AACrB;;;;;;AAOD,eAAsB,YACrBF,OACAG,WACgB;CAChB,MAAM,SAAS,UAAU;AACzB,MAAK,UAAU,OAAO,aAAa,MAClC,OAAM,IAAI,MACT;AAIF,MAAK,UAAU,KACd,OAAM,IAAI,MACT;CAIF,MAAM,SAAS,gBAAgB,OAAyB;CACxD,MAAM,gBAAgB,wBAAwB,UAAU,MAAM,MAAM;CAEpE,MAAM,EAAE,kBAAkB,GAAG,MAAM,OAAO;CAC1C,MAAM,UAAU,MAAM,iBAAiB,OAAO,UAAU,KAAK;AAE7D,MAAK,QACJ,OAAM,IAAI,OACR,8BAA8B,MAAM,mCAAmC,MAAM;AAIhF,OAAM,OAAO,KACZ,IAAI,oBAAoB;EACvB,MAAM;EACN,OAAO,KAAK,UAAU,QAAQ;EAC9B,MAAM;EACN,WAAW;EACX,cAAc,kBAAkB,UAAU,KAAK,GAAG,MAAM;CACxD,GACD;AACD;;;;;;AAOD,eAAsB,YACrBH,OACAG,WAC+B;CAC/B,MAAM,SAAS,UAAU;AACzB,MAAK,UAAU,OAAO,aAAa,MAClC,QAAO;AAGR,MAAK,UAAU,KACd,QAAO;CAGR,MAAM,SAAS,gBAAgB,OAAyB;CACxD,MAAM,gBAAgB,wBAAwB,UAAU,MAAM,MAAM;AAEpE,KAAI;EACH,MAAM,WAAW,MAAM,OAAO,KAC7B,IAAI,oBAAoB;GACvB,MAAM;GACN,gBAAgB;EAChB,GACD;AAED,OAAK,SAAS,WAAW,MACxB,QAAO;AAGR,SAAO,KAAK,MAAM,SAAS,UAAU,MAAM;CAC3C,SAAQ,OAAO;AACf,MAAI,iBAAiB,kBACpB,QAAO;AAER,QAAM;CACN;AACD;;;;AAKD,SAAgB,gBAAgBA,WAAyC;AACxE,UAAS,UAAU,SAAS,UAAU,MAAM,aAAa;AACzD"}
|
|
@@ -722,48 +722,6 @@ declare const WorkspaceConfigSchema: z.ZodObject<{
|
|
|
722
722
|
retention: z.ZodOptional<z.ZodNumber>;
|
|
723
723
|
}, z.core.$strip>>;
|
|
724
724
|
}, z.core.$strip>>;
|
|
725
|
-
services: z.ZodOptional<z.ZodObject<{
|
|
726
|
-
db: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
|
|
727
|
-
version: z.ZodOptional<z.ZodString>;
|
|
728
|
-
image: z.ZodOptional<z.ZodString>;
|
|
729
|
-
}, z.core.$strip>]>>;
|
|
730
|
-
cache: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
|
|
731
|
-
version: z.ZodOptional<z.ZodString>;
|
|
732
|
-
image: z.ZodOptional<z.ZodString>;
|
|
733
|
-
}, z.core.$strip>, z.ZodEnum<{
|
|
734
|
-
upstash: "upstash";
|
|
735
|
-
elasticache: "elasticache";
|
|
736
|
-
db: "db";
|
|
737
|
-
}>]>>;
|
|
738
|
-
mail: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
|
|
739
|
-
version: z.ZodOptional<z.ZodString>;
|
|
740
|
-
image: z.ZodOptional<z.ZodString>;
|
|
741
|
-
smtp: z.ZodOptional<z.ZodObject<{
|
|
742
|
-
host: z.ZodString;
|
|
743
|
-
port: z.ZodNumber;
|
|
744
|
-
user: z.ZodOptional<z.ZodString>;
|
|
745
|
-
pass: z.ZodOptional<z.ZodString>;
|
|
746
|
-
}, z.core.$strip>>;
|
|
747
|
-
}, z.core.$strip>, z.ZodEnum<{
|
|
748
|
-
resend: "resend";
|
|
749
|
-
ses: "ses";
|
|
750
|
-
smtp: "smtp";
|
|
751
|
-
}>]>>;
|
|
752
|
-
storage: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
|
|
753
|
-
version: z.ZodOptional<z.ZodString>;
|
|
754
|
-
image: z.ZodOptional<z.ZodString>;
|
|
755
|
-
}, z.core.$strip>, z.ZodEnum<{
|
|
756
|
-
minio: "minio";
|
|
757
|
-
s3: "s3";
|
|
758
|
-
r2: "r2";
|
|
759
|
-
}>]>>;
|
|
760
|
-
events: z.ZodOptional<z.ZodEnum<{
|
|
761
|
-
pgboss: "pgboss";
|
|
762
|
-
sns: "sns";
|
|
763
|
-
rabbitmq: "rabbitmq";
|
|
764
|
-
}>>;
|
|
765
|
-
trustLocalCa: z.ZodOptional<z.ZodBoolean>;
|
|
766
|
-
}, z.core.$strip>>;
|
|
767
725
|
stages: z.ZodObject<{
|
|
768
726
|
local: z.ZodString;
|
|
769
727
|
deployed: z.ZodArray<z.ZodString>;
|
|
@@ -820,7 +778,7 @@ declare const WorkspaceConfigSchema: z.ZodObject<{
|
|
|
820
778
|
write: Function;
|
|
821
779
|
}>;
|
|
822
780
|
}, z.core.$strip>]>>;
|
|
823
|
-
}, z.core.$
|
|
781
|
+
}, z.core.$strict>;
|
|
824
782
|
/**
|
|
825
783
|
* Validate workspace configuration.
|
|
826
784
|
* Throws ZodError with detailed messages on validation failure.
|
|
@@ -856,153 +814,6 @@ declare function formatValidationErrors(error: z.ZodError): string;
|
|
|
856
814
|
* ```
|
|
857
815
|
*/
|
|
858
816
|
type DeployTarget = 'dokploy' | 'vercel' | 'cloudflare';
|
|
859
|
-
/**
|
|
860
|
-
* Service image configuration for custom Docker images.
|
|
861
|
-
*
|
|
862
|
-
* @example
|
|
863
|
-
* ```ts
|
|
864
|
-
* // Use specific version
|
|
865
|
-
* db: { version: '18-alpine' }
|
|
866
|
-
*
|
|
867
|
-
* // Use custom image
|
|
868
|
-
* db: { image: 'timescale/timescaledb:latest-pg16' }
|
|
869
|
-
* ```
|
|
870
|
-
*/
|
|
871
|
-
interface ServiceImageConfig {
|
|
872
|
-
/** Docker image version/tag (e.g., '18-alpine') */
|
|
873
|
-
version?: string;
|
|
874
|
-
/** Full Docker image reference (overrides version) */
|
|
875
|
-
image?: string;
|
|
876
|
-
}
|
|
877
|
-
/**
|
|
878
|
-
* Mail service configuration.
|
|
879
|
-
*
|
|
880
|
-
* In development, uses Mailpit for email testing.
|
|
881
|
-
* In production, uses SMTP configuration.
|
|
882
|
-
*
|
|
883
|
-
* @example
|
|
884
|
-
* ```ts
|
|
885
|
-
* services: {
|
|
886
|
-
* mail: {
|
|
887
|
-
* smtp: {
|
|
888
|
-
* host: 'smtp.sendgrid.net',
|
|
889
|
-
* port: 587,
|
|
890
|
-
* user: 'apikey',
|
|
891
|
-
* pass: process.env.SENDGRID_API_KEY,
|
|
892
|
-
* }
|
|
893
|
-
* }
|
|
894
|
-
* }
|
|
895
|
-
* ```
|
|
896
|
-
*/
|
|
897
|
-
interface MailServiceConfig extends ServiceImageConfig {
|
|
898
|
-
/** SMTP configuration for production */
|
|
899
|
-
smtp?: {
|
|
900
|
-
host: string;
|
|
901
|
-
port: number;
|
|
902
|
-
user?: string;
|
|
903
|
-
pass?: string;
|
|
904
|
-
};
|
|
905
|
-
}
|
|
906
|
-
/**
|
|
907
|
-
* Development services configuration.
|
|
908
|
-
*
|
|
909
|
-
* Configures shared infrastructure services like databases and caches.
|
|
910
|
-
* These are automatically provisioned in Dokploy during deployment.
|
|
911
|
-
*
|
|
912
|
-
* @example
|
|
913
|
-
* ```ts
|
|
914
|
-
* // Enable with defaults
|
|
915
|
-
* services: {
|
|
916
|
-
* db: true, // postgres:18-alpine
|
|
917
|
-
* cache: true, // redis:8-alpine
|
|
918
|
-
* }
|
|
919
|
-
*
|
|
920
|
-
* // Custom versions
|
|
921
|
-
* services: {
|
|
922
|
-
* db: { version: '18-alpine' },
|
|
923
|
-
* cache: { version: '7-alpine' },
|
|
924
|
-
* }
|
|
925
|
-
*
|
|
926
|
-
* // Custom images
|
|
927
|
-
* services: {
|
|
928
|
-
* db: { image: 'timescale/timescaledb:latest-pg16' },
|
|
929
|
-
* }
|
|
930
|
-
*
|
|
931
|
-
* // With mail service
|
|
932
|
-
* services: {
|
|
933
|
-
* db: true,
|
|
934
|
-
* cache: true,
|
|
935
|
-
* mail: true, // Mailpit in dev
|
|
936
|
-
* }
|
|
937
|
-
*
|
|
938
|
-
* // With event backend
|
|
939
|
-
* services: {
|
|
940
|
-
* db: true,
|
|
941
|
-
* cache: true,
|
|
942
|
-
* events: 'pgboss', // reuses postgres (auto-enables db)
|
|
943
|
-
* // events: 'sns', // adds LocalStack container
|
|
944
|
-
* // events: 'rabbitmq', // adds RabbitMQ container
|
|
945
|
-
* }
|
|
946
|
-
* ```
|
|
947
|
-
*/
|
|
948
|
-
interface ServicesConfig {
|
|
949
|
-
/**
|
|
950
|
-
* Whether to install the local edge's certificate authority automatically.
|
|
951
|
-
*
|
|
952
|
-
* A declared `file-server` answers on `https://` locally, which needs a
|
|
953
|
-
* certificate, which needs an authority this machine trusts. Everything gkm
|
|
954
|
-
* starts trusts it already — reconcile injects `NODE_EXTRA_CA_CERTS` — but a
|
|
955
|
-
* *browser* asks the operating system, and until the root is in its store a
|
|
956
|
-
* local address reads as "not secure".
|
|
957
|
-
*
|
|
958
|
-
* Installing it needs `sudo`, so it is never silent by default:
|
|
959
|
-
*
|
|
960
|
-
* - unset — `gkm setup` asks once, on a machine that does not trust it yet,
|
|
961
|
-
* and remembers a "no" so it stops asking.
|
|
962
|
-
* - `true` — install without asking. For a team that has decided, and for
|
|
963
|
-
* any machine where a prompt has nobody to answer it.
|
|
964
|
-
* - `false` — never. Correct for CI, and for anyone who only ever reaches
|
|
965
|
-
* these addresses from code, which trusts the root without any of this.
|
|
966
|
-
*/
|
|
967
|
-
trustLocalCa?: boolean;
|
|
968
|
-
/**
|
|
969
|
-
* Where a declared cache lives — `'upstash'`, `'elasticache'` or `'db'`.
|
|
970
|
-
*
|
|
971
|
-
* A backend name and nothing else. Whether there *is* a cache comes from the
|
|
972
|
-
* manifest: declaring one implies its container the way declaring a database
|
|
973
|
-
* implies Postgres, so this only ever answers the second question.
|
|
974
|
-
*
|
|
975
|
-
* Defaults by target — see `DEFAULT_CACHE`.
|
|
976
|
-
*/
|
|
977
|
-
cache?: CacheBackend;
|
|
978
|
-
/**
|
|
979
|
-
* Who delivers a declared app's mail — `'ses'`, `'resend'` or `'smtp'`.
|
|
980
|
-
*
|
|
981
|
-
* Locally every one of them is Mailpit, because every one speaks SMTP.
|
|
982
|
-
*/
|
|
983
|
-
mail?: EmailBackend;
|
|
984
|
-
/** Where a declared bucket lives — `'minio'`, `'s3'` or `'r2'`. */
|
|
985
|
-
storage?: StorageBackend;
|
|
986
|
-
/** What carries a declared queue or topic — pgboss, sns or rabbitmq. */
|
|
987
|
-
events?: EventsBackend;
|
|
988
|
-
/**
|
|
989
|
-
* Image pins for the containers the manifest derives.
|
|
990
|
-
*
|
|
991
|
-
* Separate from the backend names above, because they answer unrelated
|
|
992
|
-
* questions: a backend says where a thing lives, a pin says which image runs
|
|
993
|
-
* locally. They shared one key until `cache: true` meant "start a Redis" —
|
|
994
|
-
* which was the last way a container could exist because config asked for
|
|
995
|
-
* it rather than because something declared it.
|
|
996
|
-
*
|
|
997
|
-
* ```ts
|
|
998
|
-
* services: { cache: 'elasticache', images: { redis: 'redis:6-alpine' } }
|
|
999
|
-
* ```
|
|
1000
|
-
*
|
|
1001
|
-
* Pinning an image for a container nothing declares is a no-op, not an
|
|
1002
|
-
* error: it says which image *would* run, and nothing runs.
|
|
1003
|
-
*/
|
|
1004
|
-
images?: Partial<Record<ComposeServiceName, string>>;
|
|
1005
|
-
}
|
|
1006
817
|
/**
|
|
1007
818
|
* Stage-based domain configuration.
|
|
1008
819
|
*
|
|
@@ -1537,10 +1348,6 @@ type ConstrainedApps<TApps extends AppsRecord> = { [K in keyof TApps]: Omit<TApp
|
|
|
1537
1348
|
* dependencies: ['api'],
|
|
1538
1349
|
* },
|
|
1539
1350
|
* },
|
|
1540
|
-
* services: {
|
|
1541
|
-
* db: true,
|
|
1542
|
-
* cache: true,
|
|
1543
|
-
* },
|
|
1544
1351
|
* deploy: {
|
|
1545
1352
|
* default: 'dokploy',
|
|
1546
1353
|
* },
|
|
@@ -1569,8 +1376,6 @@ type WorkspaceInput<TApps extends AppsRecord> = {
|
|
|
1569
1376
|
shared?: SharedConfig;
|
|
1570
1377
|
/** Deployment configuration */
|
|
1571
1378
|
deploy?: DeployConfig;
|
|
1572
|
-
/** Development services (db, cache, mail, storage, events) */
|
|
1573
|
-
services?: ServicesConfig;
|
|
1574
1379
|
/** The project's stages: which one is local, which deploy */
|
|
1575
1380
|
stages: StagesConfig;
|
|
1576
1381
|
/** Encrypted secrets configuration */
|
|
@@ -1599,7 +1404,6 @@ type InferredWorkspaceConfig<TApps extends AppsRecord> = {
|
|
|
1599
1404
|
} };
|
|
1600
1405
|
shared?: SharedConfig;
|
|
1601
1406
|
deploy?: DeployConfig;
|
|
1602
|
-
services?: ServicesConfig;
|
|
1603
1407
|
stages: StagesConfig;
|
|
1604
1408
|
secrets?: SecretsConfig;
|
|
1605
1409
|
state?: StateConfig;
|
|
@@ -1651,12 +1455,6 @@ type InferredWorkspaceConfig<TApps extends AppsRecord> = {
|
|
|
1651
1455
|
* },
|
|
1652
1456
|
* },
|
|
1653
1457
|
*
|
|
1654
|
-
* // Infrastructure services
|
|
1655
|
-
* services: {
|
|
1656
|
-
* db: true, // PostgreSQL
|
|
1657
|
-
* cache: true, // Redis
|
|
1658
|
-
* },
|
|
1659
|
-
*
|
|
1660
1458
|
* // Deployment configuration
|
|
1661
1459
|
* deploy: {
|
|
1662
1460
|
* default: 'dokploy',
|
|
@@ -1697,8 +1495,6 @@ interface WorkspaceConfig {
|
|
|
1697
1495
|
shared?: SharedConfig;
|
|
1698
1496
|
/** Default deployment configuration */
|
|
1699
1497
|
deploy?: DeployConfig;
|
|
1700
|
-
/** Development services (db, cache, mail, storage, events) */
|
|
1701
|
-
services?: ServicesConfig;
|
|
1702
1498
|
/** The project's stages: which one is local, which deploy */
|
|
1703
1499
|
stages: StagesConfig;
|
|
1704
1500
|
/** Encrypted secrets configuration */
|
|
@@ -1760,8 +1556,6 @@ interface NormalizedWorkspace {
|
|
|
1760
1556
|
constructs?: Routes;
|
|
1761
1557
|
/** Normalized app configurations */
|
|
1762
1558
|
apps: Record<string, NormalizedAppConfig>;
|
|
1763
|
-
/** Services configuration (empty object if not specified) */
|
|
1764
|
-
services: ServicesConfig;
|
|
1765
1559
|
/** Deploy configuration (empty object if not specified) */
|
|
1766
1560
|
deploy: DeployConfig;
|
|
1767
1561
|
/** Shared packages configuration (empty object if not specified) */
|
|
@@ -1845,19 +1639,6 @@ interface ProductionConfig {
|
|
|
1845
1639
|
*/
|
|
1846
1640
|
optimizedHandlers?: boolean;
|
|
1847
1641
|
}
|
|
1848
|
-
/** Service-specific configuration for docker-compose */
|
|
1849
|
-
interface ServiceConfig {
|
|
1850
|
-
/**
|
|
1851
|
-
* Full Docker image reference (e.g., 'postgis/postgis:16-3.4-alpine').
|
|
1852
|
-
* When specified, overrides the default image entirely.
|
|
1853
|
-
*/
|
|
1854
|
-
image?: string;
|
|
1855
|
-
/**
|
|
1856
|
-
* Docker image version/tag (e.g., '15-alpine' for postgres).
|
|
1857
|
-
* Only used when `image` is not specified.
|
|
1858
|
-
*/
|
|
1859
|
-
version?: string;
|
|
1860
|
-
}
|
|
1861
1642
|
/**
|
|
1862
1643
|
* Supported event backend types.
|
|
1863
1644
|
*
|
|
@@ -1867,7 +1648,7 @@ interface ServiceConfig {
|
|
|
1867
1648
|
*
|
|
1868
1649
|
* All backends generate EVENT_PUBLISHER_CONNECTION_STRING and EVENT_SUBSCRIBER_CONNECTION_STRING.
|
|
1869
1650
|
*/
|
|
1870
|
-
|
|
1651
|
+
|
|
1871
1652
|
/**
|
|
1872
1653
|
* Where a declared cache actually lives.
|
|
1873
1654
|
*
|
|
@@ -1903,25 +1684,6 @@ type CacheBackend = 'upstash' | 'elasticache' | 'db';
|
|
|
1903
1684
|
* is what makes a single-host deploy self-contained, and what makes it a
|
|
1904
1685
|
* single disk with no replication. Locally this is what every backend is.
|
|
1905
1686
|
*/
|
|
1906
|
-
type StorageBackend = 'minio' | 's3' | 'r2';
|
|
1907
|
-
/**
|
|
1908
|
-
* The backend a project gets when it says nothing, by where it deploys.
|
|
1909
|
-
*
|
|
1910
|
-
* Flat defaults could not be right for both: `upstash` on a single box means a
|
|
1911
|
-
* SaaS round-trip for a cache the database could have held, and `minio` on AWS
|
|
1912
|
-
* means running a bucket beside S3. So the default is a function of the target,
|
|
1913
|
-
* and an app that says nothing gets the obvious answer in both places — which
|
|
1914
|
-
* is the whole of what "zero config" can mean once there is more than one
|
|
1915
|
-
* target.
|
|
1916
|
-
*
|
|
1917
|
-
* `server` covers Dokploy and a bare host alike: the question these answer is
|
|
1918
|
-
* whether the app is next to a managed cloud or next to its own containers, and
|
|
1919
|
-
* on that question the two are the same.
|
|
1920
|
-
*
|
|
1921
|
-
* A per-construct, per-stage override is the layer above this — see
|
|
1922
|
-
* `constructs-outstanding.md` — so two buckets in one app can differ. This is
|
|
1923
|
-
* only what happens when nobody has said anything at all.
|
|
1924
|
-
*/
|
|
1925
1687
|
|
|
1926
1688
|
/**
|
|
1927
1689
|
* Who delivers a declared app's mail.
|
|
@@ -1953,10 +1715,6 @@ type EmailBackend = 'resend' | 'ses' | 'smtp';
|
|
|
1953
1715
|
* give and would only be `ses` written twice.
|
|
1954
1716
|
*/
|
|
1955
1717
|
|
|
1956
|
-
/** Supported docker-compose service names */
|
|
1957
|
-
type ComposeServiceName = 'postgres' | 'redis' | 'rabbitmq' | 'minio' | 'mailpit' | 'localstack';
|
|
1958
|
-
/** Services configuration - can be boolean (use defaults) or object with version */
|
|
1959
|
-
type ComposeServicesConfig = { [K in ComposeServiceName]?: boolean | ServiceConfig };
|
|
1960
1718
|
interface DockerConfig {
|
|
1961
1719
|
/** Container registry URL (e.g., 'ghcr.io/myorg') */
|
|
1962
1720
|
registry?: string;
|
|
@@ -1966,23 +1724,6 @@ interface DockerConfig {
|
|
|
1966
1724
|
baseImage?: string;
|
|
1967
1725
|
/** Container port (default: 3000) */
|
|
1968
1726
|
port?: number;
|
|
1969
|
-
/** docker-compose services to include */
|
|
1970
|
-
compose?: {
|
|
1971
|
-
/**
|
|
1972
|
-
* Services to include in docker-compose.
|
|
1973
|
-
* Can be an object with service configs or an array of service names (legacy).
|
|
1974
|
-
*
|
|
1975
|
-
* @example Object format (recommended)
|
|
1976
|
-
* services: {
|
|
1977
|
-
* postgres: { version: '15-alpine' },
|
|
1978
|
-
* redis: true, // use default version
|
|
1979
|
-
* }
|
|
1980
|
-
*
|
|
1981
|
-
* @example Array format (legacy, uses default versions)
|
|
1982
|
-
* services: ['postgres', 'redis']
|
|
1983
|
-
*/
|
|
1984
|
-
services?: ComposeServicesConfig | ComposeServiceName[];
|
|
1985
|
-
};
|
|
1986
1727
|
}
|
|
1987
1728
|
interface ServerConfig extends ProviderConfig {
|
|
1988
1729
|
enableOpenApi?: boolean;
|
|
@@ -2101,17 +1842,6 @@ interface GkmConfig {
|
|
|
2101
1842
|
name?: string;
|
|
2102
1843
|
/** The project's stages: which one is local, which deploy */
|
|
2103
1844
|
stages: StagesConfig;
|
|
2104
|
-
/**
|
|
2105
|
-
* Where the things no construct implies live.
|
|
2106
|
-
*
|
|
2107
|
-
* The same block a workspace config carries, and the same split: `db` and
|
|
2108
|
-
* `storage` are derived from the declared `KyselyDatabase` and
|
|
2109
|
-
* `ObjectStorage` and are ignored here, while `cache`, `mail`, and `events`
|
|
2110
|
-
* name a *backend* — where the cache lives, who delivers the mail, which
|
|
2111
|
-
* broker carries events. A single-app project had no way to say any of that
|
|
2112
|
-
* before, so its event backend could only be guessed.
|
|
2113
|
-
*/
|
|
2114
|
-
services?: ServicesConfig;
|
|
2115
1845
|
/**
|
|
2116
1846
|
* Constructs glob pattern — one glob, every kind.
|
|
2117
1847
|
*
|
|
@@ -2216,5 +1946,5 @@ interface GkmConfig {
|
|
|
2216
1946
|
deploy?: DeployConfig;
|
|
2217
1947
|
}
|
|
2218
1948
|
//#endregion
|
|
2219
|
-
export { AppConfig, AppConfigInput, AppInput, AppsRecord, BackendFramework, CacheBackend, ConstrainedApps, DeployConfig, DeployTarget, DokployWorkspaceConfig, EmailBackend, Framework, FrontendFramework, GkmConfig, InferAppNames, InferredWorkspaceConfig, LoadedConfig,
|
|
2220
|
-
//# sourceMappingURL=types-
|
|
1949
|
+
export { AppConfig, AppConfigInput, AppInput, AppsRecord, BackendFramework, CacheBackend, ConstrainedApps, DeployConfig, DeployTarget, DokployWorkspaceConfig, EmailBackend, Framework, FrontendFramework, GkmConfig, InferAppNames, InferredWorkspaceConfig, LoadedConfig, MobileFramework, ModelsConfig, NormalizedAppConfig, NormalizedWorkspace, OpenApiConfig, PHASE_2_DEPLOY_TARGETS, Routes, SUPPORTED_DEPLOY_TARGETS, SecretsConfig, SharedConfig, WorkspaceConfig, WorkspaceConfigSchema, WorkspaceInput, formatValidationErrors, getDeployTargetError, isDeployTargetSupported, isPhase2DeployTarget, isWorkspaceConfig, safeValidateWorkspaceConfig, validateWorkspaceConfig };
|
|
1950
|
+
//# sourceMappingURL=types-DVIx8I1N.d.mts.map
|