@geekmidas/cli 10.0.0-alpha.74 → 10.0.0-alpha.75
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/{LegacyStateStore-D_78eaHM.cjs → LegacyStateStore-BFnXUFlx.cjs} +2 -2
- package/dist/{LegacyStateStore-D_78eaHM.cjs.map → LegacyStateStore-BFnXUFlx.cjs.map} +1 -1
- package/dist/{LegacyStateStore-DTo7z924.mjs → LegacyStateStore-cpt3K1vx.mjs} +2 -2
- package/dist/{LegacyStateStore-DTo7z924.mjs.map → LegacyStateStore-cpt3K1vx.mjs.map} +1 -1
- package/dist/{LocalStateStore-CNjgkRk4.mjs → LocalStateStore-RH9F2ZEy.mjs} +2 -2
- package/dist/{LocalStateStore-CNjgkRk4.mjs.map → LocalStateStore-RH9F2ZEy.mjs.map} +1 -1
- package/dist/{LocalStateStore-BhrlQIXD.cjs → LocalStateStore-zQGZ9b4J.cjs} +2 -2
- package/dist/{LocalStateStore-BhrlQIXD.cjs.map → LocalStateStore-zQGZ9b4J.cjs.map} +1 -1
- package/dist/{S3StateStore-oCxRs6HM.cjs → S3StateStore-CT-ZMlQY.cjs} +2 -2
- package/dist/{S3StateStore-oCxRs6HM.cjs.map → S3StateStore-CT-ZMlQY.cjs.map} +1 -1
- package/dist/{S3StateStore-g2P7T_Mo.mjs → S3StateStore-DBeBc0c0.mjs} +2 -2
- package/dist/{S3StateStore-g2P7T_Mo.mjs.map → S3StateStore-DBeBc0c0.mjs.map} +1 -1
- package/dist/{SSMStateStore-DXp0m7XI.cjs → SSMStateStore-HmsH3c4v.cjs} +2 -2
- package/dist/{SSMStateStore-DXp0m7XI.cjs.map → SSMStateStore-HmsH3c4v.cjs.map} +1 -1
- package/dist/{SSMStateStore-CYenunmK.mjs → SSMStateStore-rnzNfOaV.mjs} +2 -2
- package/dist/{SSMStateStore-CYenunmK.mjs.map → SSMStateStore-rnzNfOaV.mjs.map} +1 -1
- package/dist/{add-Djrr12Xc.cjs → add-CHBin8TF.cjs} +2 -2
- package/dist/{add-Djrr12Xc.cjs.map → add-CHBin8TF.cjs.map} +1 -1
- package/dist/{add-BTH7WaH3.mjs → add-Cvzdw8cf.mjs} +2 -2
- package/dist/{add-BTH7WaH3.mjs.map → add-Cvzdw8cf.mjs.map} +1 -1
- package/dist/{bundler-utHuESvL.cjs → bundler-_8AEZhrs.cjs} +5 -5
- package/dist/{bundler-utHuESvL.cjs.map → bundler-_8AEZhrs.cjs.map} +1 -1
- package/dist/{bundler-BUojOkof.mjs → bundler-xjp5RwRS.mjs} +5 -5
- package/dist/{bundler-BUojOkof.mjs.map → bundler-xjp5RwRS.mjs.map} +1 -1
- package/dist/{cli-Bx0sUzxH.cjs → cli-B4ktxAsM.cjs} +3 -3
- package/dist/{cli-Bx0sUzxH.cjs.map → cli-B4ktxAsM.cjs.map} +1 -1
- package/dist/{cli-CyYceKTS.mjs → cli-BTGfA0B7.mjs} +3 -3
- package/dist/{cli-CyYceKTS.mjs.map → cli-BTGfA0B7.mjs.map} +1 -1
- package/dist/{compose-DZp8DJ0A.mjs → compose-DdH2JQJD.mjs} +219 -152
- package/dist/compose-DdH2JQJD.mjs.map +1 -0
- package/dist/{compose-iuw8wfHk.cjs → compose-UKyv_1yU.cjs} +241 -150
- package/dist/compose-UKyv_1yU.cjs.map +1 -0
- package/dist/deploy/public.cjs +7 -6
- package/dist/deploy/public.d.cts +11 -0
- package/dist/deploy/public.d.cts.map +1 -1
- package/dist/deploy/public.d.mts +11 -0
- package/dist/deploy/public.d.mts.map +1 -1
- package/dist/deploy/public.mjs +7 -7
- package/dist/{deploy-C17K7Imy.mjs → deploy-CuSsiFIc.mjs} +21 -5
- package/dist/deploy-CuSsiFIc.mjs.map +1 -0
- package/dist/{deploy-eWorhvQp.cjs → deploy-XUZoA1us.cjs} +26 -4
- package/dist/deploy-XUZoA1us.cjs.map +1 -0
- package/dist/{dokploy-DKzcI-RL.cjs → dokploy-Cvgg_pID.cjs} +2 -2
- package/dist/{dokploy-DKzcI-RL.cjs.map → dokploy-Cvgg_pID.cjs.map} +1 -1
- package/dist/{dokploy-DKa49Nqm.mjs → dokploy-DZXTQX10.mjs} +2 -2
- package/dist/{dokploy-DKa49Nqm.mjs.map → dokploy-DZXTQX10.mjs.map} +1 -1
- package/dist/{encryption-sTMz3aWi.mjs → encryption-JkeMPugf.mjs} +2 -2
- package/dist/{encryption-sTMz3aWi.mjs.map → encryption-JkeMPugf.mjs.map} +1 -1
- package/dist/{encryption-DSkJdoyk.cjs → encryption-w-Ehh9DW.cjs} +2 -2
- package/dist/{encryption-DSkJdoyk.cjs.map → encryption-w-Ehh9DW.cjs.map} +1 -1
- package/dist/{engine-B1b4I34Z.mjs → engine-CmozkHxq.mjs} +192 -4
- package/dist/engine-CmozkHxq.mjs.map +1 -0
- package/dist/{engine-Bh76sAHy.cjs → engine-zpWBMsQq.cjs} +195 -7
- package/dist/engine-zpWBMsQq.cjs.map +1 -0
- package/dist/{github-BvN3CfxM.cjs → github-BGdJ-Lnm.cjs} +2 -2
- package/dist/{github-BvN3CfxM.cjs.map → github-BGdJ-Lnm.cjs.map} +1 -1
- package/dist/{github-C9ODoyZU.mjs → github-BNngHoId.mjs} +2 -2
- package/dist/{github-C9ODoyZU.mjs.map → github-BNngHoId.mjs.map} +1 -1
- package/dist/index.cjs +70 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +69 -44
- package/dist/index.mjs.map +1 -1
- package/dist/{migrate-CTtJhGV9.mjs → migrate-BLL1RTAj.mjs} +2 -2
- package/dist/{migrate-CTtJhGV9.mjs.map → migrate-BLL1RTAj.mjs.map} +1 -1
- package/dist/{migrate-B0FCZNkp.cjs → migrate-CgjlYeun.cjs} +2 -2
- package/dist/{migrate-B0FCZNkp.cjs.map → migrate-CgjlYeun.cjs.map} +1 -1
- package/dist/{resolve-DSAXj_47.mjs → resolve-DZNx7rLy.mjs} +3 -3
- package/dist/{resolve-DSAXj_47.mjs.map → resolve-DZNx7rLy.mjs.map} +1 -1
- package/dist/{resolve-D_BU-wKA.cjs → resolve-fevXn-wZ.cjs} +3 -3
- package/dist/{resolve-D_BU-wKA.cjs.map → resolve-fevXn-wZ.cjs.map} +1 -1
- package/dist/{rollback-CWYTUhfW.mjs → rollback-CLi5Pln_.mjs} +4 -4
- package/dist/{rollback-CWYTUhfW.mjs.map → rollback-CLi5Pln_.mjs.map} +1 -1
- package/dist/{rollback-DJy3t696.cjs → rollback-Dw-FW3X2.cjs} +4 -4
- package/dist/{rollback-DJy3t696.cjs.map → rollback-Dw-FW3X2.cjs.map} +1 -1
- package/dist/{sniffer-BFmdZpZ2.mjs → sniffer-BmCvVyhq.mjs} +59 -7
- package/dist/sniffer-BmCvVyhq.mjs.map +1 -0
- package/dist/{sniffer-C-T7dSMN.cjs → sniffer-bMzrX4cO.cjs} +75 -5
- package/dist/{sniffer-C-T7dSMN.cjs.map → sniffer-bMzrX4cO.cjs.map} +1 -1
- package/dist/{state-DpkxSwzI.mjs → state-BrWIOce_.mjs} +46 -284
- package/dist/state-BrWIOce_.mjs.map +1 -0
- package/dist/{state-DCwRWyh-.cjs → state-kA4Fkufx.cjs} +56 -312
- package/dist/state-kA4Fkufx.cjs.map +1 -0
- package/dist/target/public.cjs +1 -1
- package/dist/target/public.mjs +1 -1
- package/package.json +17 -17
- package/dist/compose-DZp8DJ0A.mjs.map +0 -1
- package/dist/compose-iuw8wfHk.cjs.map +0 -1
- package/dist/deploy-C17K7Imy.mjs.map +0 -1
- package/dist/deploy-eWorhvQp.cjs.map +0 -1
- package/dist/engine-B1b4I34Z.mjs.map +0 -1
- package/dist/engine-Bh76sAHy.cjs.map +0 -1
- package/dist/sniffer-BFmdZpZ2.mjs.map +0 -1
- package/dist/state-DCwRWyh-.cjs.map +0 -1
- package/dist/state-DpkxSwzI.mjs.map +0 -1
|
@@ -5,7 +5,7 @@ const require_derive = require("./derive-DAbo49sm.cjs");
|
|
|
5
5
|
const require_workspace = require("./workspace-vdrcRI-m.cjs");
|
|
6
6
|
const require_config = require("./config.cjs");
|
|
7
7
|
const require_EndpointGenerator = require("./EndpointGenerator-CP6sBvQV.cjs");
|
|
8
|
-
const require_resolve = require("./resolve-
|
|
8
|
+
const require_resolve = require("./resolve-fevXn-wZ.cjs");
|
|
9
9
|
const require_SubscriberGenerator = require("./SubscriberGenerator-CajwOa5W.cjs");
|
|
10
10
|
let node_path = require("node:path");
|
|
11
11
|
let node_fs = require("node:fs");
|
|
@@ -276,7 +276,7 @@ function applicationName(identity, app) {
|
|
|
276
276
|
* old file stays, so an older CLI on the same machine keeps working.
|
|
277
277
|
*/
|
|
278
278
|
/** Key length for AES-256 encryption */
|
|
279
|
-
const KEY_LENGTH
|
|
279
|
+
const KEY_LENGTH = 32;
|
|
280
280
|
/** A keystore project key that is not `<namespace>/<project>`. */
|
|
281
281
|
var KeystoreProjectInvalid = class extends Error {
|
|
282
282
|
key;
|
|
@@ -369,7 +369,7 @@ async function generateKey(stage, project, flag = "w") {
|
|
|
369
369
|
recursive: true,
|
|
370
370
|
mode: 448
|
|
371
371
|
});
|
|
372
|
-
const key = (0, node_crypto.randomBytes)(KEY_LENGTH
|
|
372
|
+
const key = (0, node_crypto.randomBytes)(KEY_LENGTH).toString("hex");
|
|
373
373
|
await (0, node_fs_promises.writeFile)(keyPath, key, {
|
|
374
374
|
mode: 384,
|
|
375
375
|
encoding: "utf-8",
|
|
@@ -438,8 +438,8 @@ async function getOrCreateKey(stage, project) {
|
|
|
438
438
|
/** Where the files live, relative to the project root. */
|
|
439
439
|
const SECRETS_DIR = ".gkm/secrets";
|
|
440
440
|
/** AES-256-GCM configuration */
|
|
441
|
-
const ALGORITHM
|
|
442
|
-
const IV_LENGTH
|
|
441
|
+
const ALGORITHM = "aes-256-gcm";
|
|
442
|
+
const IV_LENGTH = 12;
|
|
443
443
|
/**
|
|
444
444
|
* A stage's secrets as an encrypted file on this machine:
|
|
445
445
|
* `.gkm/secrets/<stage>.json`, with its key in the CLI's home at
|
|
@@ -507,8 +507,8 @@ function packageName$1(root) {
|
|
|
507
507
|
}
|
|
508
508
|
function encrypt(secrets, keyHex) {
|
|
509
509
|
const key = Buffer.from(keyHex, "hex");
|
|
510
|
-
const iv = (0, node_crypto.randomBytes)(IV_LENGTH
|
|
511
|
-
const cipher = (0, node_crypto.createCipheriv)(ALGORITHM
|
|
510
|
+
const iv = (0, node_crypto.randomBytes)(IV_LENGTH);
|
|
511
|
+
const cipher = (0, node_crypto.createCipheriv)(ALGORITHM, key, iv);
|
|
512
512
|
const ciphertext = Buffer.concat([cipher.update(JSON.stringify(secrets), "utf-8"), cipher.final()]);
|
|
513
513
|
return {
|
|
514
514
|
version: 1,
|
|
@@ -519,7 +519,7 @@ function encrypt(secrets, keyHex) {
|
|
|
519
519
|
function decrypt(data, keyHex) {
|
|
520
520
|
const key = Buffer.from(keyHex, "hex");
|
|
521
521
|
const combined = Buffer.from(data.encrypted, "base64");
|
|
522
|
-
const decipher = (0, node_crypto.createDecipheriv)(ALGORITHM
|
|
522
|
+
const decipher = (0, node_crypto.createDecipheriv)(ALGORITHM, key, Buffer.from(data.iv, "hex"));
|
|
523
523
|
decipher.setAuthTag(combined.subarray(-16));
|
|
524
524
|
const plaintext = Buffer.concat([decipher.update(combined.subarray(0, -16)), decipher.final()]);
|
|
525
525
|
return JSON.parse(plaintext.toString("utf-8"));
|
|
@@ -556,7 +556,7 @@ function isRemoteStore(workspace, stage) {
|
|
|
556
556
|
}
|
|
557
557
|
//#endregion
|
|
558
558
|
//#region src/credentials/index.ts
|
|
559
|
-
const logger$
|
|
559
|
+
const logger$1 = console;
|
|
560
560
|
/**
|
|
561
561
|
* Load environment files
|
|
562
562
|
* @internal Exported for testing
|
|
@@ -607,7 +607,7 @@ async function findAvailablePort(preferredPort, maxAttempts = 10) {
|
|
|
607
607
|
for (let i = 0; i < maxAttempts; i++) {
|
|
608
608
|
const port = preferredPort + i;
|
|
609
609
|
if (await isPortAvailable(port)) return port;
|
|
610
|
-
logger$
|
|
610
|
+
logger$1.log(`⚠️ Port ${port} is in use, trying ${port + 1}...`);
|
|
611
611
|
}
|
|
612
612
|
throw new Error(`Could not find an available port after trying ${maxAttempts} ports starting from ${preferredPort}`);
|
|
613
613
|
}
|
|
@@ -642,7 +642,7 @@ async function loadSecretsForApp(store, stage, appName) {
|
|
|
642
642
|
let secrets = {};
|
|
643
643
|
const stageSecrets = await store.read(stage);
|
|
644
644
|
if (stageSecrets) {
|
|
645
|
-
logger$
|
|
645
|
+
logger$1.log(`🔐 Loading secrets from stage: ${stage}`);
|
|
646
646
|
secrets = toEmbeddableSecrets(stageSecrets);
|
|
647
647
|
}
|
|
648
648
|
if (Object.keys(secrets).length === 0) return {};
|
|
@@ -748,7 +748,7 @@ async function prepareEntryCredentials(options) {
|
|
|
748
748
|
free: isPortAvailable,
|
|
749
749
|
holder: holderOf
|
|
750
750
|
});
|
|
751
|
-
for (const { app, from, to, holder } of assigned.moved) logger$
|
|
751
|
+
for (const { app, from, to, holder } of assigned.moved) logger$1.log(`↪️ ${app}: ${from} is held by ${describeHolder(holder)}, which is not this workspace's — using ${to}`);
|
|
752
752
|
workspace = withAppPorts(workspace, assigned.ports);
|
|
753
753
|
workspaceAppPort = assigned.ports[appName] ?? workspaceAppPort;
|
|
754
754
|
}
|
|
@@ -772,7 +772,7 @@ async function prepareEntryCredentials(options) {
|
|
|
772
772
|
});
|
|
773
773
|
Object.assign(credentials, reconciled.env);
|
|
774
774
|
declaredKeys.push(...Object.keys(reconciled.env));
|
|
775
|
-
if (Object.keys(reconciled.env).length > 0) logger$
|
|
775
|
+
if (Object.keys(reconciled.env).length > 0) logger$1.log(`🔌 Resolved ${Object.keys(reconciled.env).length} declared URL(s)`);
|
|
776
776
|
}
|
|
777
777
|
const secretsDir = (0, node_path.join)(secretsRoot, ".gkm");
|
|
778
778
|
await (0, node_fs_promises.mkdir)(secretsDir, { recursive: true });
|
|
@@ -1281,23 +1281,22 @@ RUN --mount=type=cache,id=${pm.cacheId},target=${pm.cacheTarget} \\
|
|
|
1281
1281
|
*
|
|
1282
1282
|
* Nothing built on the host reaches the image — `.dockerignore` keeps every
|
|
1283
1283
|
* `dist` out — so a workspace package (a CLI that is a sibling package) is
|
|
1284
|
-
* built here:
|
|
1285
|
-
*
|
|
1284
|
+
* built here: turbo's build of the app's dependencies (`^build`) and nothing
|
|
1285
|
+
* else. The root's own `build` script is never run: the slice holds one app,
|
|
1286
|
+
* and a root `build` that is `gkm build` (what `gkm init` scaffolds) builds
|
|
1287
|
+
* every app the workspace declares, most of which are not in it. The app
|
|
1288
|
+
* itself is built after this, by `gkm build` or its framework.
|
|
1286
1289
|
*/
|
|
1287
1290
|
function builderStage(options, extra = {}) {
|
|
1288
|
-
const {
|
|
1291
|
+
const { turbo, monorepo } = layout(options);
|
|
1289
1292
|
const args = extra.args ?? [];
|
|
1290
1293
|
const argLines = args.length ? `\n# Build-time args: public values the bundler inlines\n${args.map((a) => `ARG ${a}=""`).join("\n")}\n${args.map((a) => `ENV ${a}=$${a}`).join("\n")}\n` : "";
|
|
1291
1294
|
const scopes = [options.turboPackage, ...options.prunePackages ?? []];
|
|
1292
|
-
const dependencies = monorepo ? `\nRUN ${turbo} run build ${scopes.map((s) => `--filter='${s}^...'`).join(" ")}` : "";
|
|
1293
1295
|
return `# Stage 3: Build
|
|
1294
1296
|
FROM deps AS builder
|
|
1295
1297
|
WORKDIR /app
|
|
1296
1298
|
${argLines}
|
|
1297
|
-
COPY --from=pruner /app/out/full/
|
|
1298
|
-
|
|
1299
|
-
# The workspace packages the app depends on, built from source.
|
|
1300
|
-
RUN ${pm.run} --if-present build${dependencies}`;
|
|
1299
|
+
COPY --from=pruner /app/out/full/ ./${monorepo ? `\n# The workspace packages the app depends on, built from source.\nRUN ${turbo} run build ${scopes.map((s) => `--filter='${s}^...'`).join(" ")}` : ""}`;
|
|
1301
1300
|
}
|
|
1302
1301
|
/**
|
|
1303
1302
|
* The PATH a command in the app's directory runs with: the app's binaries,
|
|
@@ -5293,58 +5292,6 @@ logger.info({ port }, 'Worker started');
|
|
|
5293
5292
|
`;
|
|
5294
5293
|
}
|
|
5295
5294
|
//#endregion
|
|
5296
|
-
//#region src/secrets/encryption.ts
|
|
5297
|
-
var encryption_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
|
|
5298
|
-
encryptSecrets: () => encryptSecrets,
|
|
5299
|
-
generateDefineOptions: () => generateDefineOptions,
|
|
5300
|
-
keyFingerprint: () => keyFingerprint
|
|
5301
|
-
});
|
|
5302
|
-
/** AES-256-GCM configuration */
|
|
5303
|
-
const ALGORITHM = "aes-256-gcm";
|
|
5304
|
-
const KEY_LENGTH = 32;
|
|
5305
|
-
const IV_LENGTH = 12;
|
|
5306
|
-
/**
|
|
5307
|
-
* Encrypt secrets for embedding in a bundle.
|
|
5308
|
-
* Uses AES-256-GCM with a randomly generated ephemeral key.
|
|
5309
|
-
*
|
|
5310
|
-
* @param secrets - Key-value pairs to encrypt
|
|
5311
|
-
* @returns Encrypted payload with ephemeral master key
|
|
5312
|
-
*/
|
|
5313
|
-
function encryptSecrets(secrets) {
|
|
5314
|
-
const masterKey = (0, node_crypto.randomBytes)(KEY_LENGTH);
|
|
5315
|
-
const iv = (0, node_crypto.randomBytes)(IV_LENGTH);
|
|
5316
|
-
const plaintext = JSON.stringify(secrets);
|
|
5317
|
-
const cipher = (0, node_crypto.createCipheriv)(ALGORITHM, masterKey, iv);
|
|
5318
|
-
const ciphertext = Buffer.concat([cipher.update(plaintext, "utf-8"), cipher.final()]);
|
|
5319
|
-
const authTag = cipher.getAuthTag();
|
|
5320
|
-
return {
|
|
5321
|
-
encrypted: Buffer.concat([ciphertext, authTag]).toString("base64"),
|
|
5322
|
-
iv: iv.toString("hex"),
|
|
5323
|
-
masterKey: masterKey.toString("hex")
|
|
5324
|
-
};
|
|
5325
|
-
}
|
|
5326
|
-
/**
|
|
5327
|
-
* Generate the define options for tsdown/esbuild.
|
|
5328
|
-
* These will be injected at build time.
|
|
5329
|
-
*/
|
|
5330
|
-
function generateDefineOptions(payload) {
|
|
5331
|
-
return {
|
|
5332
|
-
__GKM_ENCRYPTED_CREDENTIALS__: JSON.stringify(payload.encrypted),
|
|
5333
|
-
__GKM_CREDENTIALS_IV__: JSON.stringify(payload.iv)
|
|
5334
|
-
};
|
|
5335
|
-
}
|
|
5336
|
-
/**
|
|
5337
|
-
* A short, one-way name for a master key: the first 8 hex characters of its
|
|
5338
|
-
* SHA-256.
|
|
5339
|
-
*
|
|
5340
|
-
* Printed where the key itself used to be, so a person can tell which key a
|
|
5341
|
-
* build used — and match it against the one they hold — without the output
|
|
5342
|
-
* carrying a value that decrypts every secret of the stage.
|
|
5343
|
-
*/
|
|
5344
|
-
function keyFingerprint(masterKey) {
|
|
5345
|
-
return (0, node_crypto.createHash)("sha256").update(masterKey).digest("hex").slice(0, 8);
|
|
5346
|
-
}
|
|
5347
|
-
//#endregion
|
|
5348
5295
|
//#region src/build/workers.ts
|
|
5349
5296
|
/** A worker with background work and no backend app to build it from. */
|
|
5350
5297
|
var WorkerHasNoApp = class extends Error {
|
|
@@ -5832,7 +5779,7 @@ function validateImageRef(ref) {
|
|
|
5832
5779
|
}
|
|
5833
5780
|
//#endregion
|
|
5834
5781
|
//#region src/docker/index.ts
|
|
5835
|
-
const logger
|
|
5782
|
+
const logger = require_discover.output;
|
|
5836
5783
|
/** `docker build` failed; what docker printed above says why. */
|
|
5837
5784
|
var DockerBuildFailed = class extends Error {
|
|
5838
5785
|
imageRef;
|
|
@@ -5883,7 +5830,7 @@ async function buildDockerImage(app, buildRoot, options) {
|
|
|
5883
5830
|
const tag = options.tag ?? "latest";
|
|
5884
5831
|
const registry = options.registry;
|
|
5885
5832
|
const fullImageName = validateImageRef(registry ? `${registry}/${app.imageName}:${tag}` : `${app.imageName}:${tag}`);
|
|
5886
|
-
logger
|
|
5833
|
+
logger.log(`\n🐳 Building Docker image: ${fullImageName}`);
|
|
5887
5834
|
try {
|
|
5888
5835
|
await require_run.run("docker", [
|
|
5889
5836
|
"build",
|
|
@@ -5897,7 +5844,7 @@ async function buildDockerImage(app, buildRoot, options) {
|
|
|
5897
5844
|
DOCKER_BUILDKIT: "1"
|
|
5898
5845
|
}
|
|
5899
5846
|
});
|
|
5900
|
-
logger
|
|
5847
|
+
logger.log(`✅ Docker image built: ${fullImageName}`);
|
|
5901
5848
|
} catch (error) {
|
|
5902
5849
|
throw new DockerBuildFailed(fullImageName, error);
|
|
5903
5850
|
}
|
|
@@ -5910,10 +5857,10 @@ async function pushDockerImage(imageName, options, cwd) {
|
|
|
5910
5857
|
const registry = options.registry;
|
|
5911
5858
|
if (!registry) throw new PushNeedsRegistry(imageName);
|
|
5912
5859
|
const fullImageName = validateImageRef(`${registry}/${imageName}:${tag}`);
|
|
5913
|
-
logger
|
|
5860
|
+
logger.log(`\n🚀 Pushing Docker image: ${fullImageName}`);
|
|
5914
5861
|
try {
|
|
5915
5862
|
await require_run.run("docker", ["push", fullImageName], { cwd });
|
|
5916
|
-
logger
|
|
5863
|
+
logger.log(`✅ Docker image pushed: ${fullImageName}`);
|
|
5917
5864
|
} catch (error) {
|
|
5918
5865
|
throw new DockerPushFailed(fullImageName, error);
|
|
5919
5866
|
}
|
|
@@ -5925,16 +5872,16 @@ async function pushDockerImage(imageName, options, cwd) {
|
|
|
5925
5872
|
async function workspaceDockerCommand(workspace, manifest, imageNames = {}, background = {}) {
|
|
5926
5873
|
const results = [];
|
|
5927
5874
|
const layout = imageLayout(workspace);
|
|
5928
|
-
logger
|
|
5929
|
-
logger
|
|
5930
|
-
logger
|
|
5875
|
+
logger.log(`\n🐳 Generating Dockerfiles for workspace: ${workspace.name}`);
|
|
5876
|
+
logger.log(` Build root: ${layout.buildRoot}`);
|
|
5877
|
+
logger.log(` Package manager: ${layout.tools.packageManager}${layout.tools.packageManagerVersion ? `@${layout.tools.packageManagerVersion}` : ""}, turbo@${layout.tools.turboVersion}`);
|
|
5931
5878
|
for (const [appName, app] of Object.entries(workspace.apps)) {
|
|
5932
5879
|
if (app.type === "mobile") {
|
|
5933
|
-
logger
|
|
5880
|
+
logger.log(`\n 📱 Skipping Docker for ${appName} (mobile app — deploy via framework toolchain)`);
|
|
5934
5881
|
continue;
|
|
5935
5882
|
}
|
|
5936
5883
|
const buildType = app.entry ? "entry" : app.type;
|
|
5937
|
-
logger
|
|
5884
|
+
logger.log(`\n 📄 Generating Dockerfile for ${appName} (${buildType})`);
|
|
5938
5885
|
const dockerfile = appDockerfile(appName, app, {
|
|
5939
5886
|
layout,
|
|
5940
5887
|
workspaceRoot: workspace.root,
|
|
@@ -5944,7 +5891,7 @@ async function workspaceDockerCommand(workspace, manifest, imageNames = {}, back
|
|
|
5944
5891
|
const dockerfilePath = (0, node_path.join)(workspace.root, path);
|
|
5945
5892
|
await (0, node_fs_promises.mkdir)((0, node_path.dirname)(dockerfilePath), { recursive: true });
|
|
5946
5893
|
await (0, node_fs_promises.writeFile)(dockerfilePath, dockerfile);
|
|
5947
|
-
logger
|
|
5894
|
+
logger.log(` Generated: ${path}`);
|
|
5948
5895
|
results.push({
|
|
5949
5896
|
appName,
|
|
5950
5897
|
type: app.type,
|
|
@@ -5953,7 +5900,7 @@ async function workspaceDockerCommand(workspace, manifest, imageNames = {}, back
|
|
|
5953
5900
|
});
|
|
5954
5901
|
}
|
|
5955
5902
|
for (const worker of manifest ? workerUnits(workspace, manifest, background) : []) {
|
|
5956
|
-
logger
|
|
5903
|
+
logger.log(`\n 📄 Generating Dockerfile for ${worker.name} (worker ${worker.id}, built from ${worker.app})`);
|
|
5957
5904
|
const dockerfile = workerDockerfile(worker, workspace.apps[worker.app], {
|
|
5958
5905
|
layout,
|
|
5959
5906
|
workspaceRoot: workspace.root
|
|
@@ -5962,7 +5909,7 @@ async function workspaceDockerCommand(workspace, manifest, imageNames = {}, back
|
|
|
5962
5909
|
const dockerfilePath = (0, node_path.join)(workspace.root, path);
|
|
5963
5910
|
await (0, node_fs_promises.mkdir)((0, node_path.dirname)(dockerfilePath), { recursive: true });
|
|
5964
5911
|
await (0, node_fs_promises.writeFile)(dockerfilePath, dockerfile);
|
|
5965
|
-
logger
|
|
5912
|
+
logger.log(` Generated: ${path}`);
|
|
5966
5913
|
results.push({
|
|
5967
5914
|
appName: worker.name,
|
|
5968
5915
|
type: "backend",
|
|
@@ -5971,13 +5918,13 @@ async function workspaceDockerCommand(workspace, manifest, imageNames = {}, back
|
|
|
5971
5918
|
});
|
|
5972
5919
|
}
|
|
5973
5920
|
const dockerignorePath = await ensureDockerignore(layout.buildRoot);
|
|
5974
|
-
logger
|
|
5921
|
+
logger.log(`\n Ensured: ${dockerignorePath}`);
|
|
5975
5922
|
const composePath = await writeConstructsCompose(workspace);
|
|
5976
|
-
logger
|
|
5977
|
-
logger
|
|
5923
|
+
logger.log(`\n✅ Generated ${results.length} Dockerfile(s) + ${COMPOSE_PATH}`);
|
|
5924
|
+
logger.log(`\n📋 Build commands (from ${layout.buildRoot}):`);
|
|
5978
5925
|
for (const result of results) {
|
|
5979
5926
|
const icon = result.type === "backend" ? "⚙️" : result.type === "mobile" ? "📱" : "🌐";
|
|
5980
|
-
logger
|
|
5927
|
+
logger.log(` ${icon} docker build -f ${(0, node_path.relative)(layout.buildRoot, result.dockerfile)} -t ${result.imageName} .`);
|
|
5981
5928
|
}
|
|
5982
5929
|
printRunInstructions(workspace);
|
|
5983
5930
|
return {
|
|
@@ -6096,199 +6043,14 @@ async function writeConstructsCompose(workspace) {
|
|
|
6096
6043
|
stage: workspace.stages.local,
|
|
6097
6044
|
start: false
|
|
6098
6045
|
});
|
|
6099
|
-
logger
|
|
6046
|
+
logger.log(` Generated: ${COMPOSE_PATH} (project root)`);
|
|
6100
6047
|
return (0, node_path.join)(workspace.root, COMPOSE_PATH);
|
|
6101
6048
|
}
|
|
6102
6049
|
function printRunInstructions(workspace) {
|
|
6103
6050
|
const project = (0, node_fs.existsSync)((0, node_path.join)(workspace.root, "docker-compose.yml")) ? " -f docker-compose.yml" : "";
|
|
6104
|
-
logger
|
|
6105
|
-
logger
|
|
6106
|
-
logger
|
|
6107
|
-
}
|
|
6108
|
-
//#endregion
|
|
6109
|
-
//#region src/deploy/docker.ts
|
|
6110
|
-
const logger = require_discover.output;
|
|
6111
|
-
/**
|
|
6112
|
-
* The id the Dockerfile templates mount the encrypted credentials under:
|
|
6113
|
-
* `RUN --mount=type=secret,id=gkm_credentials`.
|
|
6114
|
-
*/
|
|
6115
|
-
const CREDENTIALS_SECRET_ID = "gkm_credentials";
|
|
6116
|
-
/**
|
|
6117
|
-
* Get the full image reference
|
|
6118
|
-
*/
|
|
6119
|
-
function getImageRef(registry, imageName, tag) {
|
|
6120
|
-
if (registry) return `${registry}/${imageName}:${tag}`;
|
|
6121
|
-
return `${imageName}:${tag}`;
|
|
6122
|
-
}
|
|
6123
|
-
/**
|
|
6124
|
-
* The `docker build` argv for an image.
|
|
6125
|
-
*
|
|
6126
|
-
* One element per value, so nothing in a ref or a build arg is read by a
|
|
6127
|
-
* shell, and `--opt=value` rather than `--opt value`, so a value that starts
|
|
6128
|
-
* with `-` cannot be taken for one of docker's own flags.
|
|
6129
|
-
*
|
|
6130
|
-
* @internal Exported for testing
|
|
6131
|
-
*/
|
|
6132
|
-
function dockerBuildArgs(options) {
|
|
6133
|
-
const { dockerfilePath, imageRef, buildArgs = [], credentialsFile } = options;
|
|
6134
|
-
return [
|
|
6135
|
-
"build",
|
|
6136
|
-
"--platform=linux/amd64",
|
|
6137
|
-
`--file=${dockerfilePath}`,
|
|
6138
|
-
`--tag=${imageRef}`,
|
|
6139
|
-
...buildArgs.map((arg) => `--build-arg=${arg}`),
|
|
6140
|
-
...credentialsFile ? [`--secret=id=${CREDENTIALS_SECRET_ID},src=${credentialsFile}`] : [],
|
|
6141
|
-
"."
|
|
6142
|
-
];
|
|
6143
|
-
}
|
|
6144
|
-
/**
|
|
6145
|
-
* The build arg that names which credentials an image embeds: a hash of the
|
|
6146
|
-
* ciphertext, which is not a secret. A BuildKit secret is no part of the
|
|
6147
|
-
* build cache's key, so without it a rebuild with credentials encrypted under
|
|
6148
|
-
* a new key would reuse the layer that embedded the old ones.
|
|
6149
|
-
*/
|
|
6150
|
-
function credentialsBuildArg(credentials) {
|
|
6151
|
-
return `GKM_CIPHERTEXT_HASH=${(0, node_crypto.createHash)("sha256").update(`${credentials.encrypted}\n${credentials.iv}`).digest("hex").slice(0, 16)}`;
|
|
6152
|
-
}
|
|
6153
|
-
/** The secret file's content: ciphertext, then IV, one per line. */
|
|
6154
|
-
function credentialsFileContent(credentials) {
|
|
6155
|
-
return `${credentials.encrypted}\n${credentials.iv}\n`;
|
|
6156
|
-
}
|
|
6157
|
-
/**
|
|
6158
|
-
* Write the encrypted credentials where `docker build --secret` reads them.
|
|
6159
|
-
*
|
|
6160
|
-
* Two lines — ciphertext, then IV — so a template can split them with `sed`
|
|
6161
|
-
* in any base image. Owner-only, in a directory of its own, and the returned
|
|
6162
|
-
* cleanup removes both whatever the build did.
|
|
6163
|
-
*
|
|
6164
|
-
* @internal Exported for testing
|
|
6165
|
-
*/
|
|
6166
|
-
async function writeCredentialsFile(credentials) {
|
|
6167
|
-
const dir = await (0, node_fs_promises.mkdtemp)((0, node_path.join)((0, node_os.tmpdir)(), "gkm-credentials-"));
|
|
6168
|
-
const path = (0, node_path.join)(dir, CREDENTIALS_SECRET_ID);
|
|
6169
|
-
await (0, node_fs_promises.writeFile)(path, credentialsFileContent(credentials), { mode: 384 });
|
|
6170
|
-
await (0, node_fs_promises.chmod)(path, 384);
|
|
6171
|
-
return {
|
|
6172
|
-
path,
|
|
6173
|
-
cleanup: () => (0, node_fs_promises.rm)(dir, {
|
|
6174
|
-
recursive: true,
|
|
6175
|
-
force: true
|
|
6176
|
-
})
|
|
6177
|
-
};
|
|
6178
|
-
}
|
|
6179
|
-
/**
|
|
6180
|
-
* Build Docker image
|
|
6181
|
-
* @param imageRef - Full image reference (registry/name:tag)
|
|
6182
|
-
* @param buildArgs - Build arguments to pass to docker build
|
|
6183
|
-
* @param credentials - Encrypted credentials, passed as a build secret
|
|
6184
|
-
*/
|
|
6185
|
-
async function buildImage(imageRef, buildArgs, credentials, { cwd, dockerfile, signal, stdio }) {
|
|
6186
|
-
logger.log(`\n🔨 Building Docker image: ${imageRef}`);
|
|
6187
|
-
logger.log(" Generating Dockerfile...");
|
|
6188
|
-
const { buildRoot } = await dockerCommand({ cwd });
|
|
6189
|
-
const dockerfilePath = (0, node_path.relative)(buildRoot, dockerfile);
|
|
6190
|
-
const secret = credentials ? await writeCredentialsFile(credentials) : void 0;
|
|
6191
|
-
try {
|
|
6192
|
-
await require_run.run("docker", dockerBuildArgs({
|
|
6193
|
-
dockerfilePath,
|
|
6194
|
-
imageRef,
|
|
6195
|
-
buildArgs: [...buildArgs ?? [], ...credentials ? [credentialsBuildArg(credentials)] : []],
|
|
6196
|
-
credentialsFile: secret?.path
|
|
6197
|
-
}), {
|
|
6198
|
-
cwd: buildRoot,
|
|
6199
|
-
env: {
|
|
6200
|
-
...process.env,
|
|
6201
|
-
DOCKER_BUILDKIT: "1"
|
|
6202
|
-
},
|
|
6203
|
-
...signal ? { signal } : {},
|
|
6204
|
-
...stdio ? { stdio } : {}
|
|
6205
|
-
});
|
|
6206
|
-
logger.log(`✅ Image built: ${imageRef}`);
|
|
6207
|
-
} catch (error) {
|
|
6208
|
-
throw new DockerBuildFailed(imageRef, error);
|
|
6209
|
-
} finally {
|
|
6210
|
-
await secret?.cleanup();
|
|
6211
|
-
}
|
|
6212
|
-
}
|
|
6213
|
-
/**
|
|
6214
|
-
* Push Docker image to registry
|
|
6215
|
-
*/
|
|
6216
|
-
async function pushImage(imageRef, { cwd, signal, stdio }) {
|
|
6217
|
-
logger.log(`\n☁️ Pushing image: ${imageRef}`);
|
|
6218
|
-
try {
|
|
6219
|
-
await require_run.run("docker", ["push", imageRef], {
|
|
6220
|
-
cwd,
|
|
6221
|
-
...signal ? { signal } : {},
|
|
6222
|
-
...stdio ? { stdio } : {}
|
|
6223
|
-
});
|
|
6224
|
-
logger.log(`✅ Image pushed: ${imageRef}`);
|
|
6225
|
-
} catch (error) {
|
|
6226
|
-
throw new DockerPushFailed(imageRef, error);
|
|
6227
|
-
}
|
|
6228
|
-
}
|
|
6229
|
-
/**
|
|
6230
|
-
* The digest the registry gave a pushed image, `sha256:…`.
|
|
6231
|
-
*
|
|
6232
|
-
* A tag can be pushed over — by the next deploy, or by anything else that
|
|
6233
|
-
* shares the repository — and the digest is what says which image a stage
|
|
6234
|
-
* actually ran. `RepoDigests` has one entry per repository the image was
|
|
6235
|
-
* pushed to, so the one for this ref's repository is picked by name.
|
|
6236
|
-
*
|
|
6237
|
-
* @internal Exported for testing
|
|
6238
|
-
*/
|
|
6239
|
-
async function pushedDigest(imageRef, { cwd, signal } = { cwd: process.cwd() }) {
|
|
6240
|
-
const repository = imageRef.split("@")[0].replace(/:[\w][\w.-]*$/, "");
|
|
6241
|
-
const output = await require_run.runOutput("docker", [
|
|
6242
|
-
"image",
|
|
6243
|
-
"inspect",
|
|
6244
|
-
"--format={{json .RepoDigests}}",
|
|
6245
|
-
imageRef
|
|
6246
|
-
], {
|
|
6247
|
-
cwd,
|
|
6248
|
-
...signal ? { signal } : {}
|
|
6249
|
-
});
|
|
6250
|
-
let digests;
|
|
6251
|
-
try {
|
|
6252
|
-
digests = JSON.parse(output.trim() || "[]");
|
|
6253
|
-
} catch {
|
|
6254
|
-
return;
|
|
6255
|
-
}
|
|
6256
|
-
if (!Array.isArray(digests)) return void 0;
|
|
6257
|
-
return digests.find((entry) => typeof entry === "string" && entry.startsWith(`${repository}@`))?.slice(repository.length + 1);
|
|
6258
|
-
}
|
|
6259
|
-
/**
|
|
6260
|
-
* Deploy using Docker (build and optionally push image)
|
|
6261
|
-
*/
|
|
6262
|
-
async function deployDocker(options) {
|
|
6263
|
-
const { stage, tag, skipPush, masterKey, config, buildArgs, credentials } = options;
|
|
6264
|
-
const imageName = config.imageName;
|
|
6265
|
-
const imageRef = validateImageRef(getImageRef(config.registry, imageName, tag));
|
|
6266
|
-
const cwd = options.cwd ?? process.cwd();
|
|
6267
|
-
const docker = {
|
|
6268
|
-
cwd,
|
|
6269
|
-
dockerfile: (0, node_path.join)(cwd, options.dockerfile ?? dockerfileOf(config.appName ?? imageName, options.appPath ?? ".")),
|
|
6270
|
-
...options.signal ? { signal: options.signal } : {},
|
|
6271
|
-
...options.stdio ? { stdio: options.stdio } : {}
|
|
6272
|
-
};
|
|
6273
|
-
await buildImage(imageRef, buildArgs, credentials, docker);
|
|
6274
|
-
let digest;
|
|
6275
|
-
if (!skipPush) {
|
|
6276
|
-
if (!config.registry) logger.warn("\n⚠️ No registry configured. Use --skip-push or configure docker.registry in gkm.config.ts");
|
|
6277
|
-
else {
|
|
6278
|
-
await pushImage(imageRef, docker);
|
|
6279
|
-
digest = await pushedDigest(imageRef, docker);
|
|
6280
|
-
}
|
|
6281
|
-
}
|
|
6282
|
-
logger.log("\n✅ Docker deployment ready!");
|
|
6283
|
-
logger.log(`\n📋 Deployment details:`);
|
|
6284
|
-
logger.log(` Image: ${imageRef}`);
|
|
6285
|
-
logger.log(` Stage: ${stage}`);
|
|
6286
|
-
if (masterKey) logger.log(`\n🔐 Run the container with GKM_MASTER_KEY set to the key with fingerprint ${keyFingerprint(masterKey)}.`);
|
|
6287
|
-
return {
|
|
6288
|
-
imageRef,
|
|
6289
|
-
...digest ? { digest } : {},
|
|
6290
|
-
masterKey
|
|
6291
|
-
};
|
|
6051
|
+
logger.log("\n📋 Run everything (the apps sit behind the \"apps\" profile):");
|
|
6052
|
+
logger.log(" gkm setup # starts the containers and creates what they hold");
|
|
6053
|
+
logger.log(` docker compose -f ${COMPOSE_PATH}${project} --profile apps up --build`);
|
|
6292
6054
|
}
|
|
6293
6055
|
//#endregion
|
|
6294
6056
|
//#region src/deploy/generated.ts
|
|
@@ -6628,6 +6390,18 @@ Object.defineProperty(exports, "DevServicesNeedServerTarget", {
|
|
|
6628
6390
|
return DevServicesNeedServerTarget;
|
|
6629
6391
|
}
|
|
6630
6392
|
});
|
|
6393
|
+
Object.defineProperty(exports, "DockerBuildFailed", {
|
|
6394
|
+
enumerable: true,
|
|
6395
|
+
get: function() {
|
|
6396
|
+
return DockerBuildFailed;
|
|
6397
|
+
}
|
|
6398
|
+
});
|
|
6399
|
+
Object.defineProperty(exports, "DockerPushFailed", {
|
|
6400
|
+
enumerable: true,
|
|
6401
|
+
get: function() {
|
|
6402
|
+
return DockerPushFailed;
|
|
6403
|
+
}
|
|
6404
|
+
});
|
|
6631
6405
|
Object.defineProperty(exports, "ExternalServicesNotConfigured", {
|
|
6632
6406
|
enumerable: true,
|
|
6633
6407
|
get: function() {
|
|
@@ -6796,24 +6570,6 @@ Object.defineProperty(exports, "createEntryWrapper", {
|
|
|
6796
6570
|
return createEntryWrapper;
|
|
6797
6571
|
}
|
|
6798
6572
|
});
|
|
6799
|
-
Object.defineProperty(exports, "credentialsBuildArg", {
|
|
6800
|
-
enumerable: true,
|
|
6801
|
-
get: function() {
|
|
6802
|
-
return credentialsBuildArg;
|
|
6803
|
-
}
|
|
6804
|
-
});
|
|
6805
|
-
Object.defineProperty(exports, "credentialsFileContent", {
|
|
6806
|
-
enumerable: true,
|
|
6807
|
-
get: function() {
|
|
6808
|
-
return credentialsFileContent;
|
|
6809
|
-
}
|
|
6810
|
-
});
|
|
6811
|
-
Object.defineProperty(exports, "deployDocker", {
|
|
6812
|
-
enumerable: true,
|
|
6813
|
-
get: function() {
|
|
6814
|
-
return deployDocker;
|
|
6815
|
-
}
|
|
6816
|
-
});
|
|
6817
6573
|
Object.defineProperty(exports, "deployIdentity", {
|
|
6818
6574
|
enumerable: true,
|
|
6819
6575
|
get: function() {
|
|
@@ -6850,16 +6606,10 @@ Object.defineProperty(exports, "dockerCommand", {
|
|
|
6850
6606
|
return dockerCommand;
|
|
6851
6607
|
}
|
|
6852
6608
|
});
|
|
6853
|
-
Object.defineProperty(exports, "
|
|
6609
|
+
Object.defineProperty(exports, "dockerfileOf", {
|
|
6854
6610
|
enumerable: true,
|
|
6855
6611
|
get: function() {
|
|
6856
|
-
return
|
|
6857
|
-
}
|
|
6858
|
-
});
|
|
6859
|
-
Object.defineProperty(exports, "encryption_exports", {
|
|
6860
|
-
enumerable: true,
|
|
6861
|
-
get: function() {
|
|
6862
|
-
return encryption_exports;
|
|
6612
|
+
return dockerfileOf;
|
|
6863
6613
|
}
|
|
6864
6614
|
});
|
|
6865
6615
|
Object.defineProperty(exports, "ensureDockerignore", {
|
|
@@ -6994,12 +6744,6 @@ Object.defineProperty(exports, "isRemoteStore", {
|
|
|
6994
6744
|
return isRemoteStore;
|
|
6995
6745
|
}
|
|
6996
6746
|
});
|
|
6997
|
-
Object.defineProperty(exports, "keyFingerprint", {
|
|
6998
|
-
enumerable: true,
|
|
6999
|
-
get: function() {
|
|
7000
|
-
return keyFingerprint;
|
|
7001
|
-
}
|
|
7002
|
-
});
|
|
7003
6747
|
Object.defineProperty(exports, "keystoreProject", {
|
|
7004
6748
|
enumerable: true,
|
|
7005
6749
|
get: function() {
|
|
@@ -7313,4 +7057,4 @@ Object.defineProperty(exports, "workspace_exports", {
|
|
|
7313
7057
|
}
|
|
7314
7058
|
});
|
|
7315
7059
|
|
|
7316
|
-
//# sourceMappingURL=state-
|
|
7060
|
+
//# sourceMappingURL=state-kA4Fkufx.cjs.map
|