@geekmidas/cli 10.0.0-alpha.67 → 10.0.0-alpha.68
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/{bundler-Bq3HaLOZ.mjs → bundler-C-w7aGoZ.mjs} +5 -5
- package/dist/{bundler-Bq3HaLOZ.mjs.map → bundler-C-w7aGoZ.mjs.map} +1 -1
- package/dist/{bundler-pyLj-gS0.cjs → bundler-C1pnNrR0.cjs} +5 -5
- package/dist/{bundler-pyLj-gS0.cjs.map → bundler-C1pnNrR0.cjs.map} +1 -1
- package/dist/{cli-DR7B2_fX.cjs → cli-BLyD4c0O.cjs} +12 -3
- package/dist/cli-BLyD4c0O.cjs.map +1 -0
- package/dist/{cli-C2Tjbn27.mjs → cli-Ce4pLL5O.mjs} +12 -3
- package/dist/cli-Ce4pLL5O.mjs.map +1 -0
- package/dist/{compose-BjToENzG.mjs → compose-DFxuYhn6.mjs} +165 -51
- package/dist/compose-DFxuYhn6.mjs.map +1 -0
- package/dist/{compose-5oNHAKNT.cjs → compose-DvsgumY2.cjs} +165 -51
- package/dist/compose-DvsgumY2.cjs.map +1 -0
- package/dist/{config-4XFxX1al.d.cts → config-BnA0kPTY.d.cts} +3 -3
- package/dist/{config-4XFxX1al.d.cts.map → config-BnA0kPTY.d.cts.map} +1 -1
- package/dist/{config-UtKzhpFb.d.mts → config-CxEp_g7j.d.mts} +3 -3
- package/dist/{config-UtKzhpFb.d.mts.map → config-CxEp_g7j.d.mts.map} +1 -1
- package/dist/config.d.cts +3 -3
- package/dist/config.d.mts +3 -3
- package/dist/deploy/public.cjs +9 -5
- package/dist/deploy/public.d.cts +15 -4
- package/dist/deploy/public.d.cts.map +1 -1
- package/dist/deploy/public.d.mts +15 -4
- package/dist/deploy/public.d.mts.map +1 -1
- package/dist/deploy/public.mjs +6 -6
- package/dist/{deploy-BucRfbvX.cjs → deploy-C08GONYW.cjs} +8 -4
- package/dist/deploy-C08GONYW.cjs.map +1 -0
- package/dist/{deploy-DRAwTG72.mjs → deploy-D-EVOWvu.mjs} +8 -4
- package/dist/deploy-D-EVOWvu.mjs.map +1 -0
- package/dist/{dokploy-m345Zx02.cjs → dokploy-CZ6nfSV9.cjs} +2 -2
- package/dist/{dokploy-m345Zx02.cjs.map → dokploy-CZ6nfSV9.cjs.map} +1 -1
- package/dist/{dokploy-DIt1IZl1.mjs → dokploy-DU-XJsoT.mjs} +2 -2
- package/dist/{dokploy-DIt1IZl1.mjs.map → dokploy-DU-XJsoT.mjs.map} +1 -1
- package/dist/{encryption-rZ3BghXy.cjs → encryption-CCcBSLZs.cjs} +2 -2
- package/dist/{encryption-rZ3BghXy.cjs.map → encryption-CCcBSLZs.cjs.map} +1 -1
- package/dist/{encryption-Ccbahik7.mjs → encryption-DSiLau1-.mjs} +2 -2
- package/dist/{encryption-Ccbahik7.mjs.map → encryption-DSiLau1-.mjs.map} +1 -1
- package/dist/{engine-Cx_dvx9q.cjs → engine-BM9Dy_DT.cjs} +134 -24
- package/dist/engine-BM9Dy_DT.cjs.map +1 -0
- package/dist/{engine-Gs0abjuj.mjs → engine-llWnMZH5.mjs} +134 -24
- package/dist/engine-llWnMZH5.mjs.map +1 -0
- package/dist/{github-CrcGFkfD.cjs → github-ZoMam0OH.cjs} +2 -2
- package/dist/{github-CrcGFkfD.cjs.map → github-ZoMam0OH.cjs.map} +1 -1
- package/dist/{github-CJANTYqi.mjs → github-yy6WpHIl.mjs} +2 -2
- package/dist/{github-CJANTYqi.mjs.map → github-yy6WpHIl.mjs.map} +1 -1
- package/dist/{index-CyApaHVe.d.cts → index-CkX89m6S.d.mts} +2 -2
- package/dist/{index-CyApaHVe.d.cts.map → index-CkX89m6S.d.mts.map} +1 -1
- package/dist/{index-DD1FfUHh.d.mts → index-EvZBkycu.d.cts} +2 -2
- package/dist/{index-DD1FfUHh.d.mts.map → index-EvZBkycu.d.cts.map} +1 -1
- package/dist/index.cjs +46 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +46 -43
- package/dist/index.mjs.map +1 -1
- package/dist/{migrate-DCVo5gLS.mjs → migrate-BWPuwiXk.mjs} +2 -2
- package/dist/{migrate-DCVo5gLS.mjs.map → migrate-BWPuwiXk.mjs.map} +1 -1
- package/dist/{migrate-CQdSpttI.cjs → migrate-tOwxQBTI.cjs} +2 -2
- package/dist/{migrate-CQdSpttI.cjs.map → migrate-tOwxQBTI.cjs.map} +1 -1
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/reconcile/public.d.cts +1 -1
- package/dist/reconcile/public.d.mts +1 -1
- package/dist/{resolve-BexmDcsN.cjs → resolve-BymzGtuT.cjs} +3 -3
- package/dist/{resolve-BexmDcsN.cjs.map → resolve-BymzGtuT.cjs.map} +1 -1
- package/dist/{resolve-DhZgtvZe.mjs → resolve-pIvXlZ1h.mjs} +3 -3
- package/dist/{resolve-DhZgtvZe.mjs.map → resolve-pIvXlZ1h.mjs.map} +1 -1
- package/dist/{rollback-m4Yeym5x.mjs → rollback-ZlsbQOvj.mjs} +3 -3
- package/dist/{rollback-m4Yeym5x.mjs.map → rollback-ZlsbQOvj.mjs.map} +1 -1
- package/dist/{rollback-BnY7KuG_.cjs → rollback-zdfi6Reg.cjs} +3 -3
- package/dist/{rollback-BnY7KuG_.cjs.map → rollback-zdfi6Reg.cjs.map} +1 -1
- package/dist/{runtime-BRqFOvPM.d.cts → runtime-B3jNgeP-.d.mts} +2 -2
- package/dist/{runtime-BRqFOvPM.d.cts.map → runtime-B3jNgeP-.d.mts.map} +1 -1
- package/dist/{runtime-CEk5n4VH.d.mts → runtime-DWThEP-r.d.cts} +2 -2
- package/dist/{runtime-CEk5n4VH.d.mts.map → runtime-DWThEP-r.d.cts.map} +1 -1
- package/dist/sniffer-BdFeLSmA.mjs.map +1 -1
- package/dist/sniffer-D66HIvi9.cjs.map +1 -1
- package/dist/{state-DkUStoqJ.mjs → state-Bn5JDMFT.mjs} +247 -7
- package/dist/state-Bn5JDMFT.mjs.map +1 -0
- package/dist/{state-DgmM4EKq.cjs → state-CHZqCDRC.cjs} +342 -6
- package/dist/state-CHZqCDRC.cjs.map +1 -0
- package/dist/target/public.cjs +1 -1
- package/dist/target/public.d.cts +2 -2
- package/dist/target/public.d.mts +2 -2
- package/dist/target/public.mjs +1 -1
- package/dist/{types-CSw2w69a.d.mts → types-CZdCxUCK.d.cts} +64 -2
- package/dist/types-CZdCxUCK.d.cts.map +1 -0
- package/dist/{types-D5WIxRDP.d.cts → types-Da0E3Qv7.d.mts} +63 -3
- package/dist/types-Da0E3Qv7.d.mts.map +1 -0
- package/dist/workspace/index.d.cts +2 -2
- package/dist/workspace/index.d.mts +2 -2
- package/package.json +13 -13
- package/dist/cli-C2Tjbn27.mjs.map +0 -1
- package/dist/cli-DR7B2_fX.cjs.map +0 -1
- package/dist/compose-5oNHAKNT.cjs.map +0 -1
- package/dist/compose-BjToENzG.mjs.map +0 -1
- package/dist/deploy-BucRfbvX.cjs.map +0 -1
- package/dist/deploy-DRAwTG72.mjs.map +0 -1
- package/dist/engine-Cx_dvx9q.cjs.map +0 -1
- package/dist/engine-Gs0abjuj.mjs.map +0 -1
- package/dist/state-DgmM4EKq.cjs.map +0 -1
- package/dist/state-DkUStoqJ.mjs.map +0 -1
- package/dist/types-CSw2w69a.d.mts.map +0 -1
- package/dist/types-D5WIxRDP.d.cts.map +0 -1
|
@@ -3,7 +3,7 @@ import { a as runOutput, i as run } from "./run-BJLIerMM.mjs";
|
|
|
3
3
|
import { r as discover } from "./discover-BFoJWKGD.mjs";
|
|
4
4
|
import { t as appKey } from "./derive-B4vDpzgP.mjs";
|
|
5
5
|
import { t as defineTarget } from "./define-DR8xGYfL.mjs";
|
|
6
|
-
import {
|
|
6
|
+
import { A as assertExternalServices, C as isMainFrontendApp, Ct as primaryPortKey, F as reportDevServices, Ht as imageRef, I as encryptSecrets, J as applyPolicies, Q as postgresStatements, S as NoDomainForStage, St as portKeys, V as constructGlobs, X as bucketPolicies, Y as applyPostgres, a as recordRelease, at as envFor, b as ensureDockerignore, dt as imageLayout, et as composeFor, ft as TURBO_VERSION, g as credentialsFileContent, h as credentialsBuildArg, it as networkEnv, j as devServicesUsed, lt as hostFor, m as withGeneratedSecrets, mt as findBuildRoot, nt as pgClient, ot as localRolePassword, p as DeployJournal, q as applyBuckets, qt as initStageSecrets, rt as appEnvKeys, st as planFor, t as createEmptyState, tt as bucketClient, ut as composeBuildPaths, v as appDockerfile, w as resolveHost, x as validateImageRef, yt as DEFAULT_IMAGES } from "./state-Bn5JDMFT.mjs";
|
|
7
7
|
import { n as DEFAULT_CACHE, r as DEFAULT_EVENTS } from "./fakes-C9RiT6XG.mjs";
|
|
8
8
|
import { u as migrateDatabases } from "./databases-hUHTuwhx.mjs";
|
|
9
9
|
import { dirname, join } from "node:path";
|
|
@@ -261,22 +261,29 @@ function edgeCaddyfile(sites, options) {
|
|
|
261
261
|
}` : options.email ? `{
|
|
262
262
|
email ${options.email}
|
|
263
263
|
}` : "";
|
|
264
|
-
const blocks = sites.map(({ host, upstream }) => `https://${host} {${options.local ? `
|
|
264
|
+
const blocks = sites.map(({ host, upstream, rewrite }) => `https://${host} {${options.local ? `
|
|
265
265
|
tls internal
|
|
266
|
-
` : ""}
|
|
266
|
+
` : ""}${rewrite ? `
|
|
267
|
+
# A bucket, served at a host of its own: the bucket is a prefix on MinIO,
|
|
268
|
+
# which routes and signs on the Host header — so it is sent the upstream's.
|
|
269
|
+
reverse_proxy ${upstream} {
|
|
270
|
+
rewrite ${rewrite}
|
|
271
|
+
header_up Host {upstream_hostport}
|
|
272
|
+
}` : `
|
|
267
273
|
# Host and X-Forwarded-* are passed through as Caddy does by default, so
|
|
268
274
|
# an app builds redirects, cookies and links on the address a caller used.
|
|
269
275
|
reverse_proxy ${upstream} {
|
|
270
276
|
# Never buffer: a streamed response — server-sent events, a Next.js
|
|
271
277
|
# RSC payload — reaches the client as each chunk is written.
|
|
272
278
|
flush_interval -1
|
|
273
|
-
}
|
|
279
|
+
}`}
|
|
274
280
|
}`);
|
|
275
281
|
return `${HEADER}${global ? `${global}\n\n` : ""}${blocks.join("\n\n")}\n`;
|
|
276
282
|
}
|
|
277
283
|
const HEADER = `# Generated by gkm compose from the construct manifest — do not edit.
|
|
278
284
|
#
|
|
279
|
-
# One host per API and site, each in front of its own container
|
|
285
|
+
# One host per API and site, each in front of its own container, and one per
|
|
286
|
+
# file server in front of the stack's MinIO.
|
|
280
287
|
`;
|
|
281
288
|
//#endregion
|
|
282
289
|
//#region src/compose/stack.ts
|
|
@@ -317,42 +324,32 @@ const EDGE_PORT_ENV = {
|
|
|
317
324
|
/**
|
|
318
325
|
* Containers this target does not run.
|
|
319
326
|
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
327
|
+
* The AWS emulator never applies: a stack is a server target, whose events
|
|
328
|
+
* are pg-boss. Reconcile's Caddy fronts `gkm dev`'s host processes; the stack
|
|
329
|
+
* brings its own edge.
|
|
330
|
+
*
|
|
331
|
+
* MinIO and Mailpit run on the local stage always, and on a deployed stage
|
|
332
|
+
* only where `--allow-dev-services` allowed them and its secrets configure no
|
|
333
|
+
* real bucket or mail server — see `devServices.ts`.
|
|
324
334
|
*/
|
|
325
335
|
const NOT_RUN = {
|
|
326
|
-
minio: true,
|
|
327
336
|
localstack: true,
|
|
328
337
|
caddy: true
|
|
329
338
|
};
|
|
330
|
-
/**
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
"
|
|
339
|
+
/** The kinds a deployed stage takes from its secrets, or a dev service. */
|
|
340
|
+
const SERVICE_KINDS = {
|
|
341
|
+
email: "email",
|
|
342
|
+
objects: "objects",
|
|
343
|
+
"file-server": "file-server"
|
|
334
344
|
};
|
|
345
|
+
/** The region MinIO is addressed with. It has no regions; the SDK wants one. */
|
|
346
|
+
const MINIO_REGION = "us-east-1";
|
|
335
347
|
/** The S3 client's credentials, read beside a bucket's URL when it has them. */
|
|
336
348
|
const STORAGE_KEYS = [
|
|
337
349
|
"AWS_ACCESS_KEY_ID",
|
|
338
350
|
"AWS_SECRET_ACCESS_KEY",
|
|
339
351
|
"AWS_REGION"
|
|
340
352
|
];
|
|
341
|
-
/** A bucket the stack needs and the stage was not given. */
|
|
342
|
-
var BucketNotConfigured = class extends Error {
|
|
343
|
-
app;
|
|
344
|
-
id;
|
|
345
|
-
key;
|
|
346
|
-
stage;
|
|
347
|
-
constructor(app, id, key, stage) {
|
|
348
|
-
super(`'${app}' uses the bucket '${id}', and gkm compose runs no object storage: the stage needs an externally hosted bucket. Set its URL in the stage's secrets: gkm secrets:set ${key} 's3://…' --stage ${stage}`);
|
|
349
|
-
this.app = app;
|
|
350
|
-
this.id = id;
|
|
351
|
-
this.key = key;
|
|
352
|
-
this.stage = stage;
|
|
353
|
-
this.name = "BucketNotConfigured";
|
|
354
|
-
}
|
|
355
|
-
};
|
|
356
353
|
/** A value only the stage's secrets can hold, and they do not. */
|
|
357
354
|
var StageSecretMissing = class extends Error {
|
|
358
355
|
app;
|
|
@@ -370,7 +367,7 @@ var StageSecretMissing = class extends Error {
|
|
|
370
367
|
var StageSeedMissing = class extends Error {
|
|
371
368
|
stage;
|
|
372
369
|
constructor(stage) {
|
|
373
|
-
super(`The stage '${stage}' has no seed in its secrets, and a deployed stage's database passwords are derived from it. Run gkm compose without --dry-run once, or gkm deploy, to generate it.`);
|
|
370
|
+
super(`The stage '${stage}' has no seed in its secrets, and a deployed stage's database passwords are derived from it. Run gkm compose --stage ${stage} without --dry-run once, or gkm deploy, to generate it.`);
|
|
374
371
|
this.stage = stage;
|
|
375
372
|
this.name = "StageSeedMissing";
|
|
376
373
|
}
|
|
@@ -439,7 +436,6 @@ function composeStack(input) {
|
|
|
439
436
|
master: local ? "geekmidas" : localRolePassword(workspace.name, plan, "master", seed),
|
|
440
437
|
...seed ? { seed } : {}
|
|
441
438
|
};
|
|
442
|
-
const infra = plan.containers.filter((c) => !NOT_RUN[c]).filter((c) => local || c !== "mailpit").sort();
|
|
443
439
|
const apps = stackApps(workspace, manifest, plan, {
|
|
444
440
|
local,
|
|
445
441
|
stage,
|
|
@@ -448,10 +444,47 @@ function composeStack(input) {
|
|
|
448
444
|
images: input.images
|
|
449
445
|
});
|
|
450
446
|
if (apps.length === 0) throw new NothingToCompose(workspace.root);
|
|
447
|
+
const owners = /* @__PURE__ */ new Map();
|
|
448
|
+
for (const resource of plan.resources) {
|
|
449
|
+
owners.set(resource.envKey, resource);
|
|
450
|
+
if (resource.kind === "email") {
|
|
451
|
+
owners.set(provideKey(resource.id, "from"), resource);
|
|
452
|
+
owners.set(provideKey(resource.id, "inboxUrl"), resource);
|
|
453
|
+
}
|
|
454
|
+
if (resource.kind === "external-api") owners.set(provideKey(resource.id, "credentials"), resource);
|
|
455
|
+
}
|
|
456
|
+
const reads = /* @__PURE__ */ new Map();
|
|
457
|
+
for (const app of apps) {
|
|
458
|
+
const site = manifest[app.id];
|
|
459
|
+
reads.set(app.name, site?.kind === "site" ? Object.values(publicEnvFor(site, manifest)) : [...appEnvKeys(manifest, app.name, input.runnables) ?? []]);
|
|
460
|
+
}
|
|
461
|
+
const domain = workspace.deploy?.domains?.[stage];
|
|
462
|
+
const services = local ? {
|
|
463
|
+
missing: [],
|
|
464
|
+
minio: plan.resources.filter((r) => r.kind === "objects").map((r) => r.id),
|
|
465
|
+
mailpit: plan.resources.filter((r) => r.kind === "email").map((r) => r.id)
|
|
466
|
+
} : assertExternalServices({
|
|
467
|
+
stage,
|
|
468
|
+
declarations: serviceDeclarations(plan, reads, owners),
|
|
469
|
+
supplied: custom,
|
|
470
|
+
allow: input.allowDevServices ?? [],
|
|
471
|
+
...domain ? { domain } : {}
|
|
472
|
+
});
|
|
473
|
+
const infra = plan.containers.filter((c) => !NOT_RUN[c]).filter((c) => c !== "minio" || services.minio.length > 0).filter((c) => c !== "mailpit" || services.mailpit.length > 0).sort();
|
|
474
|
+
const storage = infra.includes("minio") ? (() => {
|
|
475
|
+
const buckets = services.minio.map((id) => byId.get(id)?.name).filter((name) => Boolean(name)).sort();
|
|
476
|
+
return {
|
|
477
|
+
user: custom.AWS_ACCESS_KEY_ID ?? (local ? "geekmidas" : `${workspace.name}-minio`),
|
|
478
|
+
password: custom.AWS_SECRET_ACCESS_KEY ?? (local ? "geekmidas" : localRolePassword(workspace.name, plan, "minio", seed)),
|
|
479
|
+
buckets,
|
|
480
|
+
policies: bucketPolicies(plan).filter((p) => buckets.includes(p.bucket))
|
|
481
|
+
};
|
|
482
|
+
})() : void 0;
|
|
451
483
|
const derivation = {
|
|
452
484
|
project: workspace.name,
|
|
453
485
|
master: credential.master,
|
|
454
|
-
...credential.seed ? { seed: credential.seed } : {}
|
|
486
|
+
...credential.seed ? { seed: credential.seed } : {},
|
|
487
|
+
...!local && domain ? { mailFrom: `noreply@${domain}` } : {}
|
|
455
488
|
};
|
|
456
489
|
const outside = networkEnv(plan, {
|
|
457
490
|
...derivation,
|
|
@@ -461,14 +494,27 @@ function composeStack(input) {
|
|
|
461
494
|
...derivation,
|
|
462
495
|
addresses: Object.fromEntries(apps.map((app) => [app.id, `http://${app.name}:${app.port}`]))
|
|
463
496
|
});
|
|
464
|
-
const
|
|
465
|
-
for (const resource of plan.resources) {
|
|
466
|
-
|
|
467
|
-
if (resource.
|
|
468
|
-
|
|
469
|
-
|
|
497
|
+
const fileServers = /* @__PURE__ */ new Map();
|
|
498
|
+
if (storage) for (const resource of plan.resources) {
|
|
499
|
+
if (resource.kind !== "file-server" || !resource.of) continue;
|
|
500
|
+
if (!services.minio.includes(resource.of)) continue;
|
|
501
|
+
if (custom[resource.envKey] !== void 0) continue;
|
|
502
|
+
const bucket = byId.get(resource.of);
|
|
503
|
+
if (!bucket) continue;
|
|
504
|
+
let host;
|
|
505
|
+
if (local) host = hostFor(resource, workspace.name);
|
|
506
|
+
else {
|
|
507
|
+
if (!domain) throw new NoDomainForStage(stage);
|
|
508
|
+
host = `${resource.subdomain ?? appKey(resource.id)}.${domain}`;
|
|
470
509
|
}
|
|
471
|
-
|
|
510
|
+
fileServers.set(resource.id, {
|
|
511
|
+
url: `https://${host}${local && https !== 443 ? `:${https}` : ""}`,
|
|
512
|
+
site: {
|
|
513
|
+
host,
|
|
514
|
+
upstream: "minio:9000",
|
|
515
|
+
rewrite: `/${bucket.name}{uri}`
|
|
516
|
+
}
|
|
517
|
+
});
|
|
472
518
|
}
|
|
473
519
|
const surfaceUrls = new Map(plan.resources.filter((r) => r.kind === "rest-api" || r.kind === "site").map((r) => [r.envKey, r.id]));
|
|
474
520
|
const appById = new Map(apps.map((app) => [app.id, app]));
|
|
@@ -477,10 +523,10 @@ function composeStack(input) {
|
|
|
477
523
|
* they can hold it, and the derivations otherwise.
|
|
478
524
|
*/
|
|
479
525
|
const valueFor = (app, key, owner) => {
|
|
480
|
-
if (owner &&
|
|
481
|
-
|
|
482
|
-
if (
|
|
483
|
-
return
|
|
526
|
+
if (owner && SERVICE_KINDS[owner.kind]) {
|
|
527
|
+
if (custom[key] !== void 0) return custom[key];
|
|
528
|
+
if (owner.kind === "file-server") return fileServers.get(owner.id)?.url;
|
|
529
|
+
return outside[key];
|
|
484
530
|
}
|
|
485
531
|
if (owner && suppliedBy(owner, key, local)) {
|
|
486
532
|
const value = custom[key];
|
|
@@ -510,7 +556,8 @@ function composeStack(input) {
|
|
|
510
556
|
const owner = owners.get(key) ?? storageOwner(key, plan);
|
|
511
557
|
if (!local && owner?.kind === "email" && key.endsWith("_INBOX_URL")) continue;
|
|
512
558
|
if (STORAGE_KEYS.includes(key)) {
|
|
513
|
-
|
|
559
|
+
const value = custom[key] ?? storageValue(key, storage);
|
|
560
|
+
if (value !== void 0) values[key] = value;
|
|
514
561
|
continue;
|
|
515
562
|
}
|
|
516
563
|
const value = valueFor(app, key, owner);
|
|
@@ -537,16 +584,17 @@ function composeStack(input) {
|
|
|
537
584
|
infra,
|
|
538
585
|
apps,
|
|
539
586
|
master: credential.master,
|
|
587
|
+
...storage ? { storage } : {},
|
|
540
588
|
https,
|
|
541
589
|
http,
|
|
542
590
|
composeDir: join(workspace.root, stackDir(stage)),
|
|
543
591
|
buildRoot: layout.buildRoot,
|
|
544
592
|
workspaceRoot: workspace.root
|
|
545
593
|
});
|
|
546
|
-
const caddyfile = edgeCaddyfile(apps.map((app) => ({
|
|
594
|
+
const caddyfile = edgeCaddyfile([...apps.map((app) => ({
|
|
547
595
|
host: app.host,
|
|
548
596
|
upstream: `${app.name}:${app.port}`
|
|
549
|
-
})), { local });
|
|
597
|
+
})), ...[...fileServers.values()].map(({ site }) => site)], { local });
|
|
550
598
|
const dockerfiles = {};
|
|
551
599
|
for (const app of apps) {
|
|
552
600
|
if (!app.build) continue;
|
|
@@ -566,16 +614,56 @@ function composeStack(input) {
|
|
|
566
614
|
caddyfile,
|
|
567
615
|
dockerfiles,
|
|
568
616
|
plan,
|
|
569
|
-
credential
|
|
617
|
+
credential,
|
|
618
|
+
...storage ? { storage } : {},
|
|
619
|
+
devServices: local ? [] : devServicesUsed(services)
|
|
570
620
|
};
|
|
571
621
|
/** Whether only the stage's secrets can supply `key` to `owner`. */
|
|
572
622
|
function suppliedBy(owner, key, isLocal) {
|
|
573
623
|
if (owner.kind === "credential") return true;
|
|
574
624
|
if (owner.kind === "external-api") return key === provideKey(owner.id, "credentials");
|
|
575
625
|
if (isLocal) return false;
|
|
576
|
-
|
|
577
|
-
|
|
626
|
+
return owner.kind === "secret" || owner.kind === "encryption";
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* The mail and storage constructs a deployed stage's apps read, with who
|
|
631
|
+
* reads each — and every file server's bucket, which serves it whether or
|
|
632
|
+
* not an app reads it directly.
|
|
633
|
+
*/
|
|
634
|
+
function serviceDeclarations(plan, reads, owners) {
|
|
635
|
+
const byId = new Map(plan.resources.map((r) => [r.id, r]));
|
|
636
|
+
const readers = /* @__PURE__ */ new Map();
|
|
637
|
+
const add = (id, app) => {
|
|
638
|
+
const set = readers.get(id) ?? /* @__PURE__ */ new Set();
|
|
639
|
+
if (app) set.add(app);
|
|
640
|
+
readers.set(id, set);
|
|
641
|
+
};
|
|
642
|
+
for (const [app, keys] of reads) for (const key of keys) {
|
|
643
|
+
const owner = owners.get(key);
|
|
644
|
+
if (!owner || !SERVICE_KINDS[owner.kind]) continue;
|
|
645
|
+
if (owner.kind === "email" && key.endsWith("_INBOX_URL")) continue;
|
|
646
|
+
add(owner.id, app);
|
|
647
|
+
if (owner.kind === "file-server" && owner.of) add(owner.of);
|
|
578
648
|
}
|
|
649
|
+
return [...readers].flatMap(([id, apps]) => {
|
|
650
|
+
const resource = byId.get(id);
|
|
651
|
+
const kind = resource && SERVICE_KINDS[resource.kind];
|
|
652
|
+
if (!resource || !kind) return [];
|
|
653
|
+
return [{
|
|
654
|
+
id,
|
|
655
|
+
kind,
|
|
656
|
+
...resource.of ? { of: resource.of } : {},
|
|
657
|
+
apps: [...apps].sort()
|
|
658
|
+
}];
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
/** The stack's MinIO's value for one of the S3 client's keys. */
|
|
662
|
+
function storageValue(key, storage) {
|
|
663
|
+
if (!storage) return void 0;
|
|
664
|
+
if (key === "AWS_ACCESS_KEY_ID") return storage.user;
|
|
665
|
+
if (key === "AWS_SECRET_ACCESS_KEY") return storage.password;
|
|
666
|
+
if (key === "AWS_REGION") return MINIO_REGION;
|
|
579
667
|
}
|
|
580
668
|
/** Which bucket an S3 credential key belongs to — the first one declared. */
|
|
581
669
|
function storageOwner(key, plan) {
|
|
@@ -651,6 +739,15 @@ function stackFile(options) {
|
|
|
651
739
|
};
|
|
652
740
|
postgres.ports = ["127.0.0.1::5432"];
|
|
653
741
|
}
|
|
742
|
+
const minio = services.minio;
|
|
743
|
+
if (minio && options.storage) {
|
|
744
|
+
minio.environment = {
|
|
745
|
+
...minio.environment,
|
|
746
|
+
MINIO_ROOT_USER: options.storage.user,
|
|
747
|
+
MINIO_ROOT_PASSWORD: options.storage.password
|
|
748
|
+
};
|
|
749
|
+
minio.ports = ["127.0.0.1::9000"];
|
|
750
|
+
}
|
|
654
751
|
for (const app of apps) services[app.name] = {
|
|
655
752
|
image: app.ref,
|
|
656
753
|
...app.build ? { build: {
|
|
@@ -925,6 +1022,7 @@ const defaultDeps = {
|
|
|
925
1022
|
docker: dockerCompose,
|
|
926
1023
|
revision: gitRevision,
|
|
927
1024
|
sql: pgClient,
|
|
1025
|
+
buckets: bucketClient,
|
|
928
1026
|
migrate: migrateDatabases,
|
|
929
1027
|
probe: httpsProbe,
|
|
930
1028
|
healthAttempts: 90,
|
|
@@ -961,9 +1059,11 @@ async function validateCompose(ctx, deps, forced) {
|
|
|
961
1059
|
...workspace.deploy?.registry ? { registry: workspace.deploy.registry } : {}
|
|
962
1060
|
},
|
|
963
1061
|
secrets,
|
|
1062
|
+
allowDevServices: ctx.allowDevServices,
|
|
964
1063
|
ports: edgePorts(deps.env),
|
|
965
1064
|
...layout ? { layout } : {}
|
|
966
1065
|
});
|
|
1066
|
+
reportDevServices(ctx, composed.devServices);
|
|
967
1067
|
const credentials = {};
|
|
968
1068
|
if (mode === "build") for (const app of composed.apps) {
|
|
969
1069
|
if (app.kind !== "rest-api" || !app.env || !app.build) continue;
|
|
@@ -1097,6 +1197,20 @@ async function provisionCompose(ctx, run, deps) {
|
|
|
1097
1197
|
});
|
|
1098
1198
|
}
|
|
1099
1199
|
if (stack.infra.includes("postgres")) await prepareDatabases(ctx, run, deps);
|
|
1200
|
+
if (stack.storage && stack.infra.includes("minio")) await prepareBuckets(ctx, run, deps);
|
|
1201
|
+
}
|
|
1202
|
+
/**
|
|
1203
|
+
* Create each bucket the stack's MinIO serves, and the open paths of each
|
|
1204
|
+
* one a file server fronts — from this machine, on MinIO's loopback port,
|
|
1205
|
+
* the way `gkm dev` creates them.
|
|
1206
|
+
*/
|
|
1207
|
+
async function prepareBuckets(ctx, run, deps) {
|
|
1208
|
+
const storage = run.stack.storage;
|
|
1209
|
+
if (storage.buckets.length === 0) return;
|
|
1210
|
+
const port = await deps.docker.port(run.ref, "minio", 9e3);
|
|
1211
|
+
const client = deps.buckets(port, storage);
|
|
1212
|
+
const created = [...await applyBuckets(client, storage.buckets), ...await applyPolicies(client, storage.policies)].filter((entry) => entry.created).length;
|
|
1213
|
+
ctx.logger.info(`🪣 Buckets: ${storage.buckets.join(", ")}${created ? ` (${created} change(s))` : ""}`);
|
|
1100
1214
|
}
|
|
1101
1215
|
/** Create what the plan names in the stack's Postgres, then migrate it. */
|
|
1102
1216
|
async function prepareDatabases(ctx, run, deps) {
|
|
@@ -1341,7 +1455,7 @@ async function writeStack(root, dir, stack, credentials = {}) {
|
|
|
1341
1455
|
return files;
|
|
1342
1456
|
}
|
|
1343
1457
|
function composeYaml(stack) {
|
|
1344
|
-
const stage =
|
|
1458
|
+
const stage = ` --stage ${stack.stage}`;
|
|
1345
1459
|
return `# Generated by gkm compose from the construct manifest — do not edit.
|
|
1346
1460
|
# The ${stack.stage} stage's APIs and sites behind one Caddy. Each backend
|
|
1347
1461
|
# reads exactly the keys in its own env file beside this one.
|
|
@@ -1420,4 +1534,4 @@ function composeTarget(options = {}) {
|
|
|
1420
1534
|
//#endregion
|
|
1421
1535
|
export { dockerCompose as a, stackDir as i, compose_exports as n, composeProject as r, composeTarget as t };
|
|
1422
1536
|
|
|
1423
|
-
//# sourceMappingURL=compose-
|
|
1537
|
+
//# sourceMappingURL=compose-DFxuYhn6.mjs.map
|