@geekmidas/cli 10.0.0-alpha.73 → 10.0.0-alpha.74
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/{SubscriberGenerator-DZk_pKDh.mjs → SubscriberGenerator-5looQ3gB.mjs} +18 -2
- package/dist/SubscriberGenerator-5looQ3gB.mjs.map +1 -0
- package/dist/{SubscriberGenerator-Bixm28fN.cjs → SubscriberGenerator-CajwOa5W.cjs} +29 -1
- package/dist/SubscriberGenerator-CajwOa5W.cjs.map +1 -0
- package/dist/{add-BiPlBUq3.mjs → add-BTH7WaH3.mjs} +2 -2
- package/dist/{add-BiPlBUq3.mjs.map → add-BTH7WaH3.mjs.map} +1 -1
- package/dist/{add-C1ojB2Yy.cjs → add-Djrr12Xc.cjs} +2 -2
- package/dist/{add-C1ojB2Yy.cjs.map → add-Djrr12Xc.cjs.map} +1 -1
- package/dist/{bundler-C2LZoLdP.mjs → bundler-BUojOkof.mjs} +5 -5
- package/dist/{bundler-C2LZoLdP.mjs.map → bundler-BUojOkof.mjs.map} +1 -1
- package/dist/{bundler-C35h0WKt.cjs → bundler-utHuESvL.cjs} +5 -5
- package/dist/{bundler-C35h0WKt.cjs.map → bundler-utHuESvL.cjs.map} +1 -1
- package/dist/{cli-DJVL2sL9.cjs → cli-Bx0sUzxH.cjs} +3 -3
- package/dist/{cli-DJVL2sL9.cjs.map → cli-Bx0sUzxH.cjs.map} +1 -1
- package/dist/{cli-BfdfyTF6.mjs → cli-CyYceKTS.mjs} +3 -3
- package/dist/{cli-BfdfyTF6.mjs.map → cli-CyYceKTS.mjs.map} +1 -1
- package/dist/{compose-9II-0IsK.mjs → compose-DZp8DJ0A.mjs} +202 -10
- package/dist/compose-DZp8DJ0A.mjs.map +1 -0
- package/dist/{compose-CNnw8meq.cjs → compose-iuw8wfHk.cjs} +202 -10
- package/dist/compose-iuw8wfHk.cjs.map +1 -0
- package/dist/{config-RLuR2o9A.d.cts → config-B38YWicj.d.cts} +3 -3
- package/dist/{config-B8OR_TrO.d.mts.map → config-B38YWicj.d.cts.map} +1 -1
- package/dist/{config-B8OR_TrO.d.mts → config-DA0kRTQe.d.mts} +3 -3
- package/dist/{config-RLuR2o9A.d.cts.map → config-DA0kRTQe.d.mts.map} +1 -1
- package/dist/config.d.cts +3 -3
- package/dist/config.d.mts +3 -3
- package/dist/deploy/public.cjs +5 -5
- package/dist/deploy/public.d.cts +3 -3
- package/dist/deploy/public.d.mts +3 -3
- package/dist/deploy/public.mjs +5 -5
- package/dist/{deploy-nmov4j0B.mjs → deploy-C17K7Imy.mjs} +3 -3
- package/dist/{deploy-nmov4j0B.mjs.map → deploy-C17K7Imy.mjs.map} +1 -1
- package/dist/{deploy-BitZLdnY.cjs → deploy-eWorhvQp.cjs} +3 -3
- package/dist/{deploy-BitZLdnY.cjs.map → deploy-eWorhvQp.cjs.map} +1 -1
- package/dist/{dokploy-CZ1vZt21.mjs → dokploy-DKa49Nqm.mjs} +2 -2
- package/dist/{dokploy-CZ1vZt21.mjs.map → dokploy-DKa49Nqm.mjs.map} +1 -1
- package/dist/{dokploy-Ce_VTytN.cjs → dokploy-DKzcI-RL.cjs} +2 -2
- package/dist/{dokploy-Ce_VTytN.cjs.map → dokploy-DKzcI-RL.cjs.map} +1 -1
- package/dist/drivers-BdvtCKc7.cjs +200 -0
- package/dist/drivers-BdvtCKc7.cjs.map +1 -0
- package/dist/drivers-Ch1rJitn.mjs +177 -0
- package/dist/drivers-Ch1rJitn.mjs.map +1 -0
- package/dist/{encryption-CDGRdcMr.cjs → encryption-DSkJdoyk.cjs} +2 -2
- package/dist/{encryption-CDGRdcMr.cjs.map → encryption-DSkJdoyk.cjs.map} +1 -1
- package/dist/{encryption-CmfPICSN.mjs → encryption-sTMz3aWi.mjs} +2 -2
- package/dist/{encryption-CmfPICSN.mjs.map → encryption-sTMz3aWi.mjs.map} +1 -1
- package/dist/{engine-B37qBO5W.mjs → engine-B1b4I34Z.mjs} +2 -2
- package/dist/{engine-B37qBO5W.mjs.map → engine-B1b4I34Z.mjs.map} +1 -1
- package/dist/{engine-DL2-PW6m.cjs → engine-Bh76sAHy.cjs} +2 -2
- package/dist/{engine-DL2-PW6m.cjs.map → engine-Bh76sAHy.cjs.map} +1 -1
- package/dist/{github-C6qF8kHg.cjs → github-BvN3CfxM.cjs} +2 -2
- package/dist/{github-C6qF8kHg.cjs.map → github-BvN3CfxM.cjs.map} +1 -1
- package/dist/{github-hjHHm7jM.mjs → github-C9ODoyZU.mjs} +2 -2
- package/dist/{github-hjHHm7jM.mjs.map → github-C9ODoyZU.mjs.map} +1 -1
- package/dist/{index-DHyTqGG3.d.mts → index-B-1lLGzy.d.mts} +2 -2
- package/dist/{index-DHyTqGG3.d.mts.map → index-B-1lLGzy.d.mts.map} +1 -1
- package/dist/{index-Dg-UZ4Hm.d.cts → index-vMidfqhU.d.cts} +2 -2
- package/dist/{index-Dg-UZ4Hm.d.cts.map → index-vMidfqhU.d.cts.map} +1 -1
- package/dist/index.cjs +59 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +57 -45
- package/dist/index.mjs.map +1 -1
- package/dist/{migrate-kA_j1TPK.cjs → migrate-B0FCZNkp.cjs} +2 -2
- package/dist/{migrate-kA_j1TPK.cjs.map → migrate-B0FCZNkp.cjs.map} +1 -1
- package/dist/{migrate-CFFC3esE.mjs → migrate-CTtJhGV9.mjs} +2 -2
- package/dist/{migrate-CFFC3esE.mjs.map → migrate-CTtJhGV9.mjs.map} +1 -1
- package/dist/openapi.d.cts +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/{ready-BIuMw6wH.cjs → ready-BB9xS4S9.cjs} +6 -188
- package/dist/ready-BB9xS4S9.cjs.map +1 -0
- package/dist/{ready-C0U0NYfB.mjs → ready-ZZoNskrr.mjs} +5 -169
- package/dist/ready-ZZoNskrr.mjs.map +1 -0
- package/dist/reconcile/public.d.cts +1 -1
- package/dist/reconcile/public.d.mts +1 -1
- package/dist/{resolve-CV4eQkDa.mjs → resolve-DSAXj_47.mjs} +3 -3
- package/dist/{resolve-CV4eQkDa.mjs.map → resolve-DSAXj_47.mjs.map} +1 -1
- package/dist/{resolve-E5RfY0bm.cjs → resolve-D_BU-wKA.cjs} +3 -3
- package/dist/{resolve-E5RfY0bm.cjs.map → resolve-D_BU-wKA.cjs.map} +1 -1
- package/dist/{rollback-C-V-Rf4a.mjs → rollback-CWYTUhfW.mjs} +3 -3
- package/dist/{rollback-C-V-Rf4a.mjs.map → rollback-CWYTUhfW.mjs.map} +1 -1
- package/dist/{rollback-QGwomD64.cjs → rollback-DJy3t696.cjs} +3 -3
- package/dist/{rollback-QGwomD64.cjs.map → rollback-DJy3t696.cjs.map} +1 -1
- package/dist/{runtime-CWYLIeCU.d.mts → runtime-BzZD5HHi.d.cts} +2 -2
- package/dist/{runtime-CWYLIeCU.d.mts.map → runtime-BzZD5HHi.d.cts.map} +1 -1
- package/dist/{runtime-CmuQOT6A.d.cts → runtime-Cm6J6L7n.d.mts} +2 -2
- package/dist/{runtime-CmuQOT6A.d.cts.map → runtime-Cm6J6L7n.d.mts.map} +1 -1
- package/dist/{state-DMjFPOhf.cjs → state-DCwRWyh-.cjs} +16 -11
- package/dist/state-DCwRWyh-.cjs.map +1 -0
- package/dist/{state-DtS2HEfi.mjs → state-DpkxSwzI.mjs} +16 -11
- package/dist/state-DpkxSwzI.mjs.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-BLdCL4fB.d.mts → types-Dp9lgx_S.d.mts} +6 -2
- package/dist/{types-BLdCL4fB.d.mts.map → types-Dp9lgx_S.d.mts.map} +1 -1
- package/dist/{types-DwCQCkC-.d.cts → types-TzCChNrA.d.cts} +6 -2
- package/dist/{types-DwCQCkC-.d.cts.map → types-TzCChNrA.d.cts.map} +1 -1
- package/dist/vitest.cjs +1 -1
- package/dist/vitest.mjs +1 -1
- package/dist/workspace/index.d.cts +2 -2
- package/dist/workspace/index.d.mts +2 -2
- package/package.json +15 -15
- package/dist/SubscriberGenerator-Bixm28fN.cjs.map +0 -1
- package/dist/SubscriberGenerator-DZk_pKDh.mjs.map +0 -1
- package/dist/compose-9II-0IsK.mjs.map +0 -1
- package/dist/compose-CNnw8meq.cjs.map +0 -1
- package/dist/ready-BIuMw6wH.cjs.map +0 -1
- package/dist/ready-C0U0NYfB.mjs.map +0 -1
- package/dist/state-DMjFPOhf.cjs.map +0 -1
- package/dist/state-DtS2HEfi.mjs.map +0 -1
|
@@ -4,8 +4,9 @@ import { r as discover } from "./discover-BPelzeGW.mjs";
|
|
|
4
4
|
import { t as appKey } from "./derive-B4vDpzgP.mjs";
|
|
5
5
|
import { M as LOGS_PORT, N as resolveLogs } from "./workspace-C7NqCsQF.mjs";
|
|
6
6
|
import { t as defineTarget } from "./define-DR8xGYfL.mjs";
|
|
7
|
-
import { $ as constructGlobs, C as validateImageRef, Ct as composeBuildPaths, D as isOtlpDestination, E as resolveHost, Et as WORKER_PORT, F as devServicesUsed, H as workerUnits, It as portKeys, Lt as primaryPortKey, Nt as DEFAULT_IMAGES, O as otelEnv, Ot as findBuildRoot, P as assertExternalServices, St as hostFor, T as isMainFrontendApp, Tt as TURBO_VERSION, U as encryptSecrets, V as suppliedOnly, _t as workerEnvKeys, a as recordRelease, at as applyBuckets, b as ensureDockerignore, bt as planFor, ct as bucketPolicies, ft as composeFor, g as credentialsFileContent, gt as networkEnv, h as credentialsBuildArg, ht as appEnvKeys, m as withGeneratedSecrets, mt as pgClient, nn as imageRef, ot as applyPolicies, p as DeployJournal, pt as bucketClient, sn as initStageSecrets, st as applyPostgres, t as createEmptyState, ut as postgresStatements, v as appDockerfile, vt as envFor, w as NoDomainForStage, wt as imageLayout, x as workerDockerfile, yt as localRolePassword, z as reportDevServices } from "./state-
|
|
8
|
-
import { i as DEFAULT_EVENTS
|
|
7
|
+
import { $ as constructGlobs, C as validateImageRef, Ct as composeBuildPaths, D as isOtlpDestination, E as resolveHost, Et as WORKER_PORT, F as devServicesUsed, H as workerUnits, It as portKeys, Lt as primaryPortKey, Nt as DEFAULT_IMAGES, O as otelEnv, Ot as findBuildRoot, P as assertExternalServices, St as hostFor, T as isMainFrontendApp, Tt as TURBO_VERSION, U as encryptSecrets, V as suppliedOnly, _t as workerEnvKeys, a as recordRelease, at as applyBuckets, b as ensureDockerignore, bt as planFor, ct as bucketPolicies, ft as composeFor, g as credentialsFileContent, gt as networkEnv, h as credentialsBuildArg, ht as appEnvKeys, m as withGeneratedSecrets, mt as pgClient, nn as imageRef, ot as applyPolicies, p as DeployJournal, pt as bucketClient, sn as initStageSecrets, st as applyPostgres, t as createEmptyState, ut as postgresStatements, v as appDockerfile, vt as envFor, w as NoDomainForStage, wt as imageLayout, x as workerDockerfile, yt as localRolePassword, z as reportDevServices } from "./state-DpkxSwzI.mjs";
|
|
8
|
+
import { i as DEFAULT_EVENTS } from "./SubscriberGenerator-5looQ3gB.mjs";
|
|
9
|
+
import { i as installedFrom } from "./drivers-Ch1rJitn.mjs";
|
|
9
10
|
import { u as migrateDatabases } from "./databases-hUHTuwhx.mjs";
|
|
10
11
|
import { n as assertStageCredentials } from "./credentialSchemas-BJqRJNK4.mjs";
|
|
11
12
|
import { dirname, join } from "node:path";
|
|
@@ -444,6 +445,152 @@ function logsAccess(logs, ctx) {
|
|
|
444
445
|
];
|
|
445
446
|
}
|
|
446
447
|
//#endregion
|
|
448
|
+
//#region src/compose/redis.ts
|
|
449
|
+
/**
|
|
450
|
+
* The stack's Redis: what every declared cache lives in when a workspace runs
|
|
451
|
+
* as a `gkm compose` stack, on the local stage and on a deployed one alike.
|
|
452
|
+
*
|
|
453
|
+
* A cache is the one store whose contents can always be rebuilt, so unlike
|
|
454
|
+
* Mailpit and MinIO it is a production service, not a dev stand-in: it runs
|
|
455
|
+
* for every stage, on the compose network only, with nothing published. It
|
|
456
|
+
* is bounded (`maxmemory`, evicting the least recently used key), persisted
|
|
457
|
+
* (an append-only file on a named volume, kept by `--down`) and password
|
|
458
|
+
* protected — the stage's own password, generated once like its seed.
|
|
459
|
+
*
|
|
460
|
+
* A stage that sets a cache's URL in its secrets — a managed Redis — keeps
|
|
461
|
+
* it, and a stack whose every cache is set that way runs no Redis at all.
|
|
462
|
+
*
|
|
463
|
+
* Pure: the stack decides it, and the phases keep the password.
|
|
464
|
+
*/
|
|
465
|
+
/**
|
|
466
|
+
* Where a stack's caches live: its own Redis, whatever the deploy target's
|
|
467
|
+
* default is. A stack is one machine running containers, and a Redis beside
|
|
468
|
+
* the apps is cheaper for a cache than a table in the database they share.
|
|
469
|
+
*/
|
|
470
|
+
const STACK_CACHE = "redis";
|
|
471
|
+
/** Its compose service name — the host every cache URL points at. */
|
|
472
|
+
const REDIS_SERVICE = "redis";
|
|
473
|
+
/** The port it answers on, inside the network. */
|
|
474
|
+
const REDIS_PORT = 6379;
|
|
475
|
+
/** Reconcile's pin, so `gkm dev` and the stack run one Redis. */
|
|
476
|
+
const REDIS_IMAGE = DEFAULT_IMAGES.redis;
|
|
477
|
+
/**
|
|
478
|
+
* How much it may hold before it evicts. A cache that grows until the box
|
|
479
|
+
* runs out of memory takes the apps with it; 256 MB is a lot of sessions and
|
|
480
|
+
* little of a small server. A project's `docker-compose.<stage>.yml` can
|
|
481
|
+
* replace the command to change it.
|
|
482
|
+
*/
|
|
483
|
+
const REDIS_MAXMEMORY = "256mb";
|
|
484
|
+
/** The stage secret holding its password. */
|
|
485
|
+
const REDIS_PASSWORD_KEY = "REDIS_PASSWORD";
|
|
486
|
+
/** Redis's own count of logical databases, before `--databases` raises it. */
|
|
487
|
+
const REDIS_DATABASES = 16;
|
|
488
|
+
/** A deployed stage that runs the stack's Redis and has no password yet. */
|
|
489
|
+
var RedisPasswordMissing = class extends Error {
|
|
490
|
+
stage;
|
|
491
|
+
constructor(stage) {
|
|
492
|
+
super(`The stage '${stage}' runs the stack's Redis and has no ${REDIS_PASSWORD_KEY} in its secrets. Run gkm compose --stage ${stage} without --dry-run once to generate it, or set one: gkm secrets:set ${REDIS_PASSWORD_KEY} '…' --stage ${stage}`);
|
|
493
|
+
this.stage = stage;
|
|
494
|
+
this.name = "RedisPasswordMissing";
|
|
495
|
+
}
|
|
496
|
+
};
|
|
497
|
+
/**
|
|
498
|
+
* Whether a stage's stack runs Redis: a cache is declared and the stage's
|
|
499
|
+
* secrets do not set the URL of every one.
|
|
500
|
+
*/
|
|
501
|
+
function runsRedis(manifest, custom) {
|
|
502
|
+
return Object.values(manifest).some((declaration) => declaration?.kind === "cache" && (declaration.provides ?? []).some((key) => custom[key] === void 0));
|
|
503
|
+
}
|
|
504
|
+
/** A password: 256 random bits, URL-safe, so it sits in a URL unescaped. */
|
|
505
|
+
function generateRedisPassword() {
|
|
506
|
+
return randomBytes(32).toString("base64url");
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* The stage's secrets with a generated Redis password, where it has none.
|
|
510
|
+
* Pure, like `withGeneratedSecrets`: the caller keeps the result once the run
|
|
511
|
+
* goes ahead.
|
|
512
|
+
*/
|
|
513
|
+
function withRedisPassword(secrets) {
|
|
514
|
+
if (secrets.custom?.["REDIS_PASSWORD"]) return {
|
|
515
|
+
secrets,
|
|
516
|
+
generated: []
|
|
517
|
+
};
|
|
518
|
+
return {
|
|
519
|
+
secrets: {
|
|
520
|
+
...secrets,
|
|
521
|
+
custom: {
|
|
522
|
+
...secrets.custom,
|
|
523
|
+
[REDIS_PASSWORD_KEY]: generateRedisPassword()
|
|
524
|
+
},
|
|
525
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
526
|
+
},
|
|
527
|
+
generated: [REDIS_PASSWORD_KEY]
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* The stack's Redis for one stage, or nothing where no cache needs it.
|
|
532
|
+
*
|
|
533
|
+
* Each cache it holds gets a logical database of its own, by the order of
|
|
534
|
+
* their ids, so two caches never read each other's keys.
|
|
535
|
+
*/
|
|
536
|
+
function stackRedis(options) {
|
|
537
|
+
const { plan, stage, local, custom } = options;
|
|
538
|
+
const caches = plan.resources.filter((r) => r.kind === "cache" && custom[r.envKey] === void 0).sort((a, b) => a.id.localeCompare(b.id));
|
|
539
|
+
if (caches.length === 0) return void 0;
|
|
540
|
+
const set = custom[REDIS_PASSWORD_KEY];
|
|
541
|
+
if (!set && !local) throw new RedisPasswordMissing(stage);
|
|
542
|
+
const password = set ?? "geekmidas";
|
|
543
|
+
const auth = encodeURIComponent(password);
|
|
544
|
+
return {
|
|
545
|
+
password,
|
|
546
|
+
passwordFromSecrets: Boolean(set),
|
|
547
|
+
urls: Object.fromEntries(caches.map((cache, index) => [cache.envKey, `redis://:${auth}@${REDIS_SERVICE}:${REDIS_PORT}/${index}`])),
|
|
548
|
+
env: {
|
|
549
|
+
[REDIS_PASSWORD_KEY]: password,
|
|
550
|
+
REDISCLI_AUTH: password
|
|
551
|
+
},
|
|
552
|
+
databases: Math.max(REDIS_DATABASES, caches.length)
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* Redis's service: bounded, persisted and password protected, on the
|
|
557
|
+
* network alone.
|
|
558
|
+
*
|
|
559
|
+
* The command runs the image's own entrypoint with `redis-server` first, so
|
|
560
|
+
* it still drops to the `redis` user and owns `/data`; the password is read
|
|
561
|
+
* from the env file by the shell (`$$` is compose's escape for `$`), so
|
|
562
|
+
* neither the compose file nor the container's command holds it.
|
|
563
|
+
*/
|
|
564
|
+
function redisService(redis) {
|
|
565
|
+
const flags = [
|
|
566
|
+
`--requirepass "$$${REDIS_PASSWORD_KEY}"`,
|
|
567
|
+
`--maxmemory ${REDIS_MAXMEMORY}`,
|
|
568
|
+
"--maxmemory-policy allkeys-lru",
|
|
569
|
+
"--appendonly yes",
|
|
570
|
+
...redis.databases > REDIS_DATABASES ? [`--databases ${redis.databases}`] : []
|
|
571
|
+
];
|
|
572
|
+
return {
|
|
573
|
+
image: REDIS_IMAGE,
|
|
574
|
+
restart: "unless-stopped",
|
|
575
|
+
command: [
|
|
576
|
+
"sh",
|
|
577
|
+
"-c",
|
|
578
|
+
`exec docker-entrypoint.sh redis-server ${flags.join(" ")}`
|
|
579
|
+
],
|
|
580
|
+
env_file: [{
|
|
581
|
+
path: `./${REDIS_SERVICE}.env`,
|
|
582
|
+
format: "raw"
|
|
583
|
+
}],
|
|
584
|
+
volumes: ["redis-data:/data"],
|
|
585
|
+
healthcheck: {
|
|
586
|
+
test: ["CMD-SHELL", "redis-cli ping | grep -q PONG"],
|
|
587
|
+
interval: "5s",
|
|
588
|
+
timeout: "3s",
|
|
589
|
+
retries: 10
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
//#endregion
|
|
447
594
|
//#region src/compose/caddyfile.ts
|
|
448
595
|
/** The Caddyfile for a stack's edge. */
|
|
449
596
|
function edgeCaddyfile(sites, options) {
|
|
@@ -640,7 +787,7 @@ function composeStack(input) {
|
|
|
640
787
|
const plan = planFor(manifest, stage, provisionOrder(manifest), {
|
|
641
788
|
localStage: workspace.stages.local,
|
|
642
789
|
events: DEFAULT_EVENTS.server,
|
|
643
|
-
cache:
|
|
790
|
+
cache: STACK_CACHE,
|
|
644
791
|
edge: false
|
|
645
792
|
});
|
|
646
793
|
const byId = new Map(plan.resources.map((r) => [r.id, r]));
|
|
@@ -700,7 +847,13 @@ function composeStack(input) {
|
|
|
700
847
|
allow: input.allowDevServices ?? [],
|
|
701
848
|
...domain ? { domain } : {}
|
|
702
849
|
});
|
|
703
|
-
const
|
|
850
|
+
const redis = stackRedis({
|
|
851
|
+
plan,
|
|
852
|
+
stage,
|
|
853
|
+
local,
|
|
854
|
+
custom
|
|
855
|
+
});
|
|
856
|
+
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).filter((c) => c !== "redis" || redis !== void 0), ...logs ? [LOGS_SERVICE] : []].sort();
|
|
704
857
|
const storage = infra.includes("minio") ? (() => {
|
|
705
858
|
const buckets = services.minio.map((id) => byId.get(id)?.name).filter((name) => Boolean(name)).sort();
|
|
706
859
|
return {
|
|
@@ -764,6 +917,7 @@ function composeStack(input) {
|
|
|
764
917
|
return value;
|
|
765
918
|
}
|
|
766
919
|
if (custom[key] !== void 0) return custom[key];
|
|
920
|
+
if (owner?.kind === "cache") return redis?.urls[key];
|
|
767
921
|
const surface = surfaceUrls.get(key);
|
|
768
922
|
if (app.kind === "rest-api" && surface && surface !== app.id) return inside[key];
|
|
769
923
|
return outside[key];
|
|
@@ -844,6 +998,7 @@ function composeStack(input) {
|
|
|
844
998
|
master: credential.master,
|
|
845
999
|
...storage ? { storage } : {},
|
|
846
1000
|
...logs ? { logs } : {},
|
|
1001
|
+
...redis ? { redis } : {},
|
|
847
1002
|
https,
|
|
848
1003
|
http,
|
|
849
1004
|
composeDir: join(workspace.root, stackDir(stage)),
|
|
@@ -868,7 +1023,8 @@ function composeStack(input) {
|
|
|
868
1023
|
dockerfiles[app.build.dockerfile] = appDockerfile(app.name, workspace.apps[app.name], {
|
|
869
1024
|
layout,
|
|
870
1025
|
workspaceRoot: workspace.root,
|
|
871
|
-
manifest
|
|
1026
|
+
manifest,
|
|
1027
|
+
cache: STACK_CACHE
|
|
872
1028
|
});
|
|
873
1029
|
}
|
|
874
1030
|
for (const worker of workers) {
|
|
@@ -879,7 +1035,8 @@ function composeStack(input) {
|
|
|
879
1035
|
app: worker.host
|
|
880
1036
|
}, workspace.apps[worker.host], {
|
|
881
1037
|
layout,
|
|
882
|
-
workspaceRoot: workspace.root
|
|
1038
|
+
workspaceRoot: workspace.root,
|
|
1039
|
+
cache: STACK_CACHE
|
|
883
1040
|
});
|
|
884
1041
|
}
|
|
885
1042
|
return {
|
|
@@ -896,7 +1053,8 @@ function composeStack(input) {
|
|
|
896
1053
|
credential,
|
|
897
1054
|
...storage ? { storage } : {},
|
|
898
1055
|
devServices: local ? [] : devServicesUsed(services),
|
|
899
|
-
...logs ? { logs } : {}
|
|
1056
|
+
...logs ? { logs } : {},
|
|
1057
|
+
...redis ? { redis } : {}
|
|
900
1058
|
};
|
|
901
1059
|
}
|
|
902
1060
|
/**
|
|
@@ -1036,6 +1194,7 @@ function stackFile(options) {
|
|
|
1036
1194
|
};
|
|
1037
1195
|
minio.ports = ["127.0.0.1::9000"];
|
|
1038
1196
|
}
|
|
1197
|
+
if (services["redis"] && options.redis) services[REDIS_SERVICE] = redisService(options.redis);
|
|
1039
1198
|
if (options.logs) services[LOGS_SERVICE] = logsService(options.logs);
|
|
1040
1199
|
for (const app of apps) services[app.name] = {
|
|
1041
1200
|
image: app.ref,
|
|
@@ -1421,6 +1580,7 @@ async function validateCompose(ctx, deps, forced) {
|
|
|
1421
1580
|
...layout ? { layout } : {}
|
|
1422
1581
|
});
|
|
1423
1582
|
reportDevServices(ctx, composed.devServices);
|
|
1583
|
+
if (mode === "build") assertRedisClient(workspace, composed);
|
|
1424
1584
|
const credentials = {};
|
|
1425
1585
|
if (mode === "build") {
|
|
1426
1586
|
for (const app of composed.apps) {
|
|
@@ -1458,6 +1618,7 @@ async function validateCompose(ctx, deps, forced) {
|
|
|
1458
1618
|
}
|
|
1459
1619
|
const stack = withBuildCredentials(composed, masterKeys);
|
|
1460
1620
|
if (mode === "pull" && !ctx.dryRun) await assertImagesExist(deps.docker, tag, [...stack.apps, ...stack.workers]);
|
|
1621
|
+
if (stack.redis && !stack.local) ctx.secrets.mask(stack.redis.password);
|
|
1461
1622
|
if (stack.logs && (!stack.local || stack.logs.passwordFromSecrets)) {
|
|
1462
1623
|
ctx.secrets.mask(stack.logs.password);
|
|
1463
1624
|
ctx.secrets.mask(stack.logs.appEnv.OTEL_EXPORTER_OTLP_HEADERS);
|
|
@@ -1495,6 +1656,28 @@ async function validateCompose(ctx, deps, forced) {
|
|
|
1495
1656
|
changes: []
|
|
1496
1657
|
};
|
|
1497
1658
|
}
|
|
1659
|
+
/** A stack whose caches are in Redis, built for an app that has no client. */
|
|
1660
|
+
var RedisClientMissing = class extends Error {
|
|
1661
|
+
apps;
|
|
1662
|
+
constructor(apps) {
|
|
1663
|
+
super(`The stack keeps every cache in Redis, and ${apps.join(", ")} ${apps.length === 1 ? "does" : "do"} not depend on ioredis, the client the generated server reaches it with. Add it to the workspace: pnpm add ioredis`);
|
|
1664
|
+
this.apps = apps;
|
|
1665
|
+
this.name = "RedisClientMissing";
|
|
1666
|
+
}
|
|
1667
|
+
};
|
|
1668
|
+
/**
|
|
1669
|
+
* Every backend and worker image built for a stack with a cache can resolve
|
|
1670
|
+
* `ioredis` — listed by its app or a directory above it, the way Node and
|
|
1671
|
+
* the image's install find it.
|
|
1672
|
+
*/
|
|
1673
|
+
function assertRedisClient(workspace, stack) {
|
|
1674
|
+
if (!stack.plan.resources.some((r) => r.kind === "cache")) return;
|
|
1675
|
+
const missing = [.../* @__PURE__ */ new Set([...stack.apps.filter((app) => app.kind === "rest-api").map((a) => a.name), ...stack.workers.map((worker) => worker.host)])].filter((name) => {
|
|
1676
|
+
const app = workspace.apps[name];
|
|
1677
|
+
return app && !installedFrom(join(workspace.root, app.path), "ioredis");
|
|
1678
|
+
}).sort();
|
|
1679
|
+
if (missing.length > 0) throw new RedisClientMissing(missing);
|
|
1680
|
+
}
|
|
1498
1681
|
/**
|
|
1499
1682
|
* The stage's secrets — and, for a deployed stage, everything it generates
|
|
1500
1683
|
* once: its seed, and each declared secret and keyring. Kept only once the
|
|
@@ -1512,8 +1695,16 @@ async function stageSecrets(ctx, manifest) {
|
|
|
1512
1695
|
secrets: withSeed.secrets,
|
|
1513
1696
|
generated: []
|
|
1514
1697
|
};
|
|
1515
|
-
const
|
|
1516
|
-
|
|
1698
|
+
const withRedis = runsRedis(manifest, withLogs.secrets.custom ?? {}) ? withRedisPassword(withLogs.secrets) : {
|
|
1699
|
+
secrets: withLogs.secrets,
|
|
1700
|
+
generated: []
|
|
1701
|
+
};
|
|
1702
|
+
const secrets = withRedis.secrets;
|
|
1703
|
+
const generated = [
|
|
1704
|
+
...withSeed.generated,
|
|
1705
|
+
...withLogs.generated,
|
|
1706
|
+
...withRedis.generated
|
|
1707
|
+
];
|
|
1517
1708
|
if (secrets.seed) ctx.secrets.mask(secrets.seed);
|
|
1518
1709
|
for (const value of Object.values(secrets.custom ?? {})) ctx.secrets.mask(value);
|
|
1519
1710
|
return {
|
|
@@ -1941,6 +2132,7 @@ async function writeStack(root, dir, stack, credentials = {}) {
|
|
|
1941
2132
|
await write(join(dir, "Caddyfile"), stack.caddyfile);
|
|
1942
2133
|
for (const app of [...stack.apps, ...stack.workers]) if (app.env) await write(join(dir, `${app.name}.env`), envFile(app.env), 384);
|
|
1943
2134
|
if (stack.logs) await write(join(dir, `${LOGS_SERVICE}.env`), envFile(stack.logs.env), 384);
|
|
2135
|
+
if (stack.redis) await write(join(dir, `${REDIS_SERVICE}.env`), envFile(stack.redis.env), 384);
|
|
1944
2136
|
for (const [name, payload] of Object.entries(credentials)) await write(join(dir, credentialsFile(name)), credentialsFileContent(payload), 384);
|
|
1945
2137
|
for (const [path, content] of Object.entries(stack.dockerfiles)) await write(join(root, path), content);
|
|
1946
2138
|
await ensureDockerignore(findBuildRoot(root));
|
|
@@ -2028,4 +2220,4 @@ function composeTarget(options = {}) {
|
|
|
2028
2220
|
//#endregion
|
|
2029
2221
|
export { stackDir as a, composeProject as i, compose_exports as n, dockerCompose as o, stackOverrideFile as r, composeTarget as t };
|
|
2030
2222
|
|
|
2031
|
-
//# sourceMappingURL=compose-
|
|
2223
|
+
//# sourceMappingURL=compose-DZp8DJ0A.mjs.map
|