@sealant/mend 0.36.0-next.684 → 0.36.0-next.708
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/main.js +253 -20
- package/man/mend-accounts.1 +1 -1
- package/man/mend-adopt.1 +1 -1
- package/man/mend-attach.1 +1 -1
- package/man/mend-codex.1 +1 -1
- package/man/mend-completions.1 +1 -1
- package/man/mend-connect-pi.1 +1 -1
- package/man/mend-connect.1 +1 -1
- package/man/mend-continue.1 +1 -1
- package/man/mend-doctor.1 +1 -1
- package/man/mend-dotfiles-repo.1 +1 -1
- package/man/mend-dotfiles-sync.1 +1 -1
- package/man/mend-dotfiles.1 +1 -1
- package/man/mend-env-cluster.1 +1 -1
- package/man/mend-env-load.1 +1 -1
- package/man/mend-env-show.1 +1 -1
- package/man/mend-folder-create.1 +1 -1
- package/man/mend-folder-list.1 +1 -1
- package/man/mend-folder-push.1 +1 -1
- package/man/mend-folder-rm.1 +1 -1
- package/man/mend-git-author.1 +1 -1
- package/man/mend-help.1 +1 -1
- package/man/mend-invite.1 +1 -1
- package/man/mend-keys-init.1 +1 -1
- package/man/mend-keys-mode.1 +1 -1
- package/man/mend-keys-share.1 +1 -1
- package/man/mend-keys-show.1 +1 -1
- package/man/mend-land.1 +1 -1
- package/man/mend-login.1 +1 -1
- package/man/mend-logout.1 +1 -1
- package/man/mend-logs.1 +1 -1
- package/man/mend-man.1 +1 -1
- package/man/mend-members.1 +1 -1
- package/man/mend-memory-import.1 +1 -1
- package/man/mend-memory-rm.1 +1 -1
- package/man/mend-memory-show.1 +1 -1
- package/man/mend-memory.1 +1 -1
- package/man/mend-models.1 +1 -1
- package/man/mend-operator-exposure.1 +2 -2
- package/man/mend-operator-gate.1 +1 -1
- package/man/mend-operator-grant-owner.1 +1 -1
- package/man/mend-operator-org-create.1 +1 -1
- package/man/mend-operator-org-invite-owner.1 +1 -1
- package/man/mend-operator-org-list.1 +1 -1
- package/man/mend-operator-org-rename.1 +1 -1
- package/man/mend-operator-reset-link.1 +1 -1
- package/man/mend-pair.1 +1 -1
- package/man/mend-projects.1 +1 -1
- package/man/mend-pull.1 +1 -1
- package/man/mend-refresh.1 +1 -1
- package/man/mend-rejoin.1 +1 -1
- package/man/mend-resume.1 +1 -1
- package/man/mend-run.1 +1 -1
- package/man/mend-secrets-add.1 +1 -1
- package/man/mend-secrets-rm.1 +1 -1
- package/man/mend-secrets.1 +1 -1
- package/man/mend-server-logs.1 +1 -1
- package/man/mend-server-restart.1 +1 -1
- package/man/mend-server-setup.1 +13 -2
- package/man/mend-server-start.1 +1 -1
- package/man/mend-server-status.1 +1 -1
- package/man/mend-server-stop.1 +1 -1
- package/man/mend-server-upgrade.1 +1 -1
- package/man/mend-server.1 +1 -1
- package/man/mend-service-add.1 +1 -1
- package/man/mend-service-connect.1 +1 -1
- package/man/mend-service-init.1 +1 -1
- package/man/mend-service-list.1 +1 -1
- package/man/mend-service-logs.1 +1 -1
- package/man/mend-service-restart.1 +1 -1
- package/man/mend-service-run.1 +1 -1
- package/man/mend-service-stop.1 +1 -1
- package/man/mend-session-share.1 +1 -1
- package/man/mend-sessions.1 +1 -1
- package/man/mend-shell.1 +1 -1
- package/man/mend-skills-push.1 +1 -1
- package/man/mend-skills.1 +1 -1
- package/man/mend-snake.1 +1 -1
- package/man/mend-ssh-keys-remove.1 +1 -1
- package/man/mend-ssh-keys.1 +1 -1
- package/man/mend-ssh-setup.1 +1 -1
- package/man/mend-ssh.1 +1 -1
- package/man/mend-stop.1 +1 -1
- package/man/mend-ui.1 +1 -1
- package/man/mend-uninstall.1 +1 -1
- package/man/mend-version.1 +1 -1
- package/man/mend-wait.1 +1 -1
- package/man/mend-workspace-replace.1 +1 -1
- package/man/mend-worktrees-rm.1 +1 -1
- package/man/mend-worktrees.1 +1 -1
- package/man/mend.1 +1 -1
- package/package.json +2 -2
package/dist/main.js
CHANGED
|
@@ -1280,7 +1280,15 @@ var isTenancy = (value) => TENANCIES.some((tenancy) => tenancy === value);
|
|
|
1280
1280
|
var EDGE_IMAGE = "caddy:2.10-alpine";
|
|
1281
1281
|
var EDGE_COMPOSE_FILE = "compose.edge.yaml";
|
|
1282
1282
|
var POSTURE_COMPOSE_FILE = "compose.posture.yaml";
|
|
1283
|
-
var
|
|
1283
|
+
var T3_GATEWAY_COMPOSE_FILE = "compose.t3.yaml";
|
|
1284
|
+
var T3_GATEWAY_CONTAINER_PORT = 3120;
|
|
1285
|
+
var DEFAULT_T3_GATEWAY_PORT = 3120;
|
|
1286
|
+
var DECLARABLE_ITEMS = [
|
|
1287
|
+
"core-private",
|
|
1288
|
+
"edge-tls",
|
|
1289
|
+
"workspace-ssh",
|
|
1290
|
+
"t3code-gateway"
|
|
1291
|
+
];
|
|
1284
1292
|
var isDeclarableItem = (value) => DECLARABLE_ITEMS.some((item) => item === value);
|
|
1285
1293
|
var publishedAddress = (address, port) => `${net2.isIP(address) === 6 ? `[${address}]` : address}:${port}`;
|
|
1286
1294
|
var parseEdgeHost = (value) => {
|
|
@@ -1307,6 +1315,7 @@ var postureEnvironment = (posture) => {
|
|
|
1307
1315
|
};
|
|
1308
1316
|
var postureEnvLines = (posture) => [
|
|
1309
1317
|
...posture.edgeHost === void 0 ? [] : [`MEND_EDGE_HOST=${posture.edgeHost}`],
|
|
1318
|
+
...posture.t3GatewayPort === void 0 ? [] : [`MEND_T3_GATEWAY_PORT=${posture.t3GatewayPort}`],
|
|
1310
1319
|
...postureEnvironment(posture).map(([key, value]) => `${key}=${value}`)
|
|
1311
1320
|
];
|
|
1312
1321
|
var renderPostureOverlay = (posture) => {
|
|
@@ -1326,10 +1335,33 @@ var renderPostureOverlay = (posture) => {
|
|
|
1326
1335
|
""
|
|
1327
1336
|
].join("\n");
|
|
1328
1337
|
};
|
|
1338
|
+
var T3_GATEWAY_VOLUME = "mend-t3-gateway";
|
|
1339
|
+
var T3_GATEWAY_IMAGE_LABEL = "dev.sealant.mend.t3-gateway";
|
|
1340
|
+
var T3_GATEWAY_STATE_DIR = "/opt/mend-t3-gateway/state";
|
|
1341
|
+
var renderT3GatewayOverlay = (posture) => {
|
|
1342
|
+
if (posture.t3GatewayPort === void 0) return void 0;
|
|
1343
|
+
return [
|
|
1344
|
+
"# Written by mend server setup --t3-gateway: the t3code gateway (docs/adr/0012), its own",
|
|
1345
|
+
"# listener beside Mend's, published on loopback only. Reaching it from elsewhere is an",
|
|
1346
|
+
"# exposure the operator declares (docs/adr/0004). mend server setup --no-t3-gateway removes it.",
|
|
1347
|
+
"services:",
|
|
1348
|
+
" mend:",
|
|
1349
|
+
" environment:",
|
|
1350
|
+
' MEND_T3_GATEWAY_ENABLED: "true"',
|
|
1351
|
+
" ports:",
|
|
1352
|
+
` - "127.0.0.1:\${MEND_T3_GATEWAY_PORT:?set MEND_T3_GATEWAY_PORT in server.env}:${T3_GATEWAY_CONTAINER_PORT}"`,
|
|
1353
|
+
" volumes:",
|
|
1354
|
+
` - ${T3_GATEWAY_VOLUME}:${T3_GATEWAY_STATE_DIR}`,
|
|
1355
|
+
"volumes:",
|
|
1356
|
+
` ${T3_GATEWAY_VOLUME}:`,
|
|
1357
|
+
""
|
|
1358
|
+
].join("\n");
|
|
1359
|
+
};
|
|
1329
1360
|
var composeOverlays = (posture) => [
|
|
1330
1361
|
...posture.edgeHost === void 0 ? [] : [EDGE_COMPOSE_FILE],
|
|
1331
1362
|
...renderPostureOverlay(posture) === void 0 ? [] : [POSTURE_COMPOSE_FILE],
|
|
1332
|
-
...runsMirrors(posture.mirrors) ? [MIRRORS_COMPOSE_FILE] : []
|
|
1363
|
+
...runsMirrors(posture.mirrors) ? [MIRRORS_COMPOSE_FILE] : [],
|
|
1364
|
+
...posture.t3GatewayPort === void 0 ? [] : [T3_GATEWAY_COMPOSE_FILE]
|
|
1333
1365
|
];
|
|
1334
1366
|
var record = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? new Map(Object.entries(value)) : null;
|
|
1335
1367
|
var healthPosture = (body) => {
|
|
@@ -1353,6 +1385,9 @@ var healthPosture = (body) => {
|
|
|
1353
1385
|
};
|
|
1354
1386
|
var declaredPostureLines = (posture) => [
|
|
1355
1387
|
...posture.edgeHost === void 0 ? [] : [`edge \xB7 ${posture.edgeHost} \xB7 ${EDGE_IMAGE} on 80 and 443 \xB7 Mend's own port on loopback`],
|
|
1388
|
+
...posture.t3GatewayPort === void 0 ? [] : [
|
|
1389
|
+
`t3code gateway \xB7 on \xB7 127.0.0.1:${posture.t3GatewayPort} \xB7 loopback only \xB7 reaching it from elsewhere is an exposure you declare`
|
|
1390
|
+
],
|
|
1356
1391
|
`exposure \xB7 declared ${posture.exposure ?? "private"}${posture.exposure === void 0 ? " \xB7 the default, not set on this install" : ""}`,
|
|
1357
1392
|
`tenancy \xB7 declared ${posture.tenancy ?? "single"}${posture.tenancy === void 0 ? " \xB7 the default, not set on this install" : ""}`,
|
|
1358
1393
|
...posture.sshBind === void 0 || posture.sshPort === void 0 ? [] : [
|
|
@@ -3161,7 +3196,7 @@ var COMMANDS = [
|
|
|
3161
3196
|
summary: "how this instance is exposed, as declared and as observed",
|
|
3162
3197
|
synopsis: [],
|
|
3163
3198
|
description: [
|
|
3164
|
-
"Operator only. States MEND_EXPOSURE as declared (loopback, private or public) and one line per item of the public exposure gate, with how it was established: observed (this server read it), carried (this build contains it, and the server cannot see it in effect), declared (you stated it and the server cannot check it), or open. MEND_EXPOSURE=public refuses to start while an item that blocks a start is open: every item the server can observe, and workspace-ssh until you declare it. Items it cannot observe say what would verify them; once you have verified core-private, edge-tls
|
|
3199
|
+
"Operator only. States MEND_EXPOSURE as declared (loopback, private or public) and one line per item of the public exposure gate, with how it was established: observed (this server read it), carried (this build contains it, and the server cannot see it in effect), declared (you stated it and the server cannot check it), or open. MEND_EXPOSURE=public refuses to start while an item that blocks a start is open: every item the server can observe, and workspace-ssh until you declare it. Items it cannot observe say what would verify them; once you have verified core-private, edge-tls, workspace-ssh (SSH published apart from the web port) or (while it is enabled) t3code-gateway from outside, name it in MEND_EXPOSURE_DECLARED, or with mend server setup --declare. The report is what was observed; it is not a statement that the instance is fit to expose."
|
|
3165
3200
|
],
|
|
3166
3201
|
see: ["operator gate", "doctor"]
|
|
3167
3202
|
},
|
|
@@ -3247,12 +3282,13 @@ var COMMANDS = [
|
|
|
3247
3282
|
section: "this machine",
|
|
3248
3283
|
summary: "install or repair the local Mend server",
|
|
3249
3284
|
synopsis: [
|
|
3250
|
-
"[--context <name>] [--version <version|latest>] [--bind <ip>] [--ssh-bind <ip>] [--url <origin>] [--origin <origin>...] [--port <n>] [--ssh-port <n>] [--edge <host> | --no-edge] [--exposure <loopback|private|public>] [--tenancy <single|multi>] [--declare <item>...] [--npm-mirror | --no-npm-mirror] [--npm-mirror-max-size <size>] [--docker-mirror | --no-docker-mirror] [--docker-mirror-max-size <size>] [--docker-hub-username <name> --docker-hub-token-stdin --docker-hub-public-only | --no-docker-hub-login] [--docker-socket <path>] [--assets-dir <dir>] [--offline]"
|
|
3285
|
+
"[--context <name>] [--version <version|latest>] [--bind <ip>] [--ssh-bind <ip>] [--url <origin>] [--origin <origin>...] [--port <n>] [--ssh-port <n>] [--edge <host> | --no-edge] [--exposure <loopback|private|public>] [--tenancy <single|multi>] [--declare <item>...] [--t3-gateway [--t3-gateway-port <n>] | --no-t3-gateway] [--npm-mirror | --no-npm-mirror] [--npm-mirror-max-size <size>] [--docker-mirror | --no-docker-mirror] [--docker-mirror-max-size <size>] [--docker-hub-username <name> --docker-hub-token-stdin --docker-hub-public-only | --no-docker-hub-login] [--docker-socket <path>] [--assets-dir <dir>] [--offline]"
|
|
3251
3286
|
],
|
|
3252
3287
|
description: [
|
|
3253
3288
|
"Checks a local Unix-socket Docker context and the Compose plugin, downloads the compose and Postgres initialization assets for one Mend release, preserves existing data and secrets, and starts the server. Re-running repairs the same pinned version. A changed --version is refused; use mend server upgrade. Updating this CLI never updates an existing server pin.",
|
|
3254
3289
|
"The default listens only on localhost at http://localhost:3105. Non-local access requires both --bind and --url. Every extra browser origin must be named with --origin; setup never guesses from the request Host header or network interfaces.",
|
|
3255
3290
|
"--edge <host> runs a TLS edge in front of Mend: Caddy on ports 80 and 443 of every interface, which obtains and renews a certificate for the host and proxies to Mend's web tier. Mend's own port stays on loopback and the browser origin is https://<host>. The edge's compose overlay and Caddyfile are written into the generation beside compose.yaml, so start, restart and upgrade run them every time. --no-edge takes it away again, and the edge's container with it. A fresh install cannot start with the edge: until the first account exists, registration is open to whoever reaches the origin first, so set up on localhost, create the account, then add the edge.",
|
|
3291
|
+
"--t3-gateway turns on the t3code gateway (docs/adr/0012): t3code's desktop, mobile and web clients add it as an environment, pair with a code from mend pair, and see this Mend's projects and sessions. It runs in the Mend container, confined to a root and a uid of its own, on a listener of its own published on 127.0.0.1 only (port 3120, or --t3-gateway-port): reaching it from another machine is an exposure you put in front of it and declare. Setup refuses it on a Mend image that has no gateway, and says whether it answered. It is kept across reruns and upgrades; --no-t3-gateway turns it off, and its state stays in its own volume, mend-t3-gateway. Off, nothing of it runs.",
|
|
3256
3292
|
"--exposure declares how the instance is reached, and --tenancy whether one organization or many use it. Both are written into the generation and kept across reruns and upgrades. public needs the edge and an existing first account. With multi, or with public, the multi mode gate's settings follow: MEND_SOURCE_POLICY=tenant and MEND_CAPTURE_REQUIRE_SIZES=true, and public sets MEND_URL_BEARERS=refuse. The server still decides whether it starts, and mend server status shows what it reports.",
|
|
3257
3293
|
"Two mirrors run beside Mend unless turned off: an npm mirror (nginx caching npmjs.org, capped at 10g by default, least recently used out) and a Docker mirror (a pull-through cache of Docker Hub, capped at 20g by default: over the cap its cache is cleared). Both leave 5g free on their disk: below that, nginx evicts and the Docker mirror pauses, and sessions pull from Docker Hub directly. Neither publishes a host port. Sessions install npm packages and pull Docker Hub images through them; a project's own npm settings win, and a mirror that is down sends sessions upstream instead. Both are kept across reruns and upgrades, and an upgrade adds them to an install from before them. The Docker mirror pulls anonymously unless given a Docker Hub login: --docker-hub-username with the access token piped on standard input, kept in server.env only. The mirror has no login of its own, so every session that reaches it can pull whatever that token can read: setup takes a login only with --docker-hub-public-only, your statement that the token's access permission is Public Repo Read-only. Mend cannot check a token's scope.",
|
|
3258
3294
|
"Docker Desktop on Linux and macOS, and OrbStack on macOS, expose client-side proxy sockets. Containers use the daemon-side /var/run/docker.sock. --docker-socket overrides detection and is retained on reruns.",
|
|
@@ -3287,6 +3323,15 @@ var COMMANDS = [
|
|
|
3287
3323
|
text: "run the Caddy TLS edge for this DNS name on 80 and 443; the origin becomes https://<host>, --bind stays on loopback, and the first account must already exist"
|
|
3288
3324
|
},
|
|
3289
3325
|
{ flag: "--no-edge", text: "take a saved edge away; the origin returns to http://localhost" },
|
|
3326
|
+
{
|
|
3327
|
+
flag: "--t3-gateway",
|
|
3328
|
+
text: "run the t3code gateway, published on 127.0.0.1:3120 only; kept across reruns and upgrades"
|
|
3329
|
+
},
|
|
3330
|
+
{
|
|
3331
|
+
flag: "--t3-gateway-port <n>",
|
|
3332
|
+
text: "the gateway's port on 127.0.0.1; implies --t3-gateway"
|
|
3333
|
+
},
|
|
3334
|
+
{ flag: "--no-t3-gateway", text: "turn the t3code gateway off; its state stays" },
|
|
3290
3335
|
{
|
|
3291
3336
|
flag: "--exposure <v>",
|
|
3292
3337
|
text: "declare loopback, private or public; kept across reruns and upgrades. public needs --edge and an existing first account"
|
|
@@ -6835,7 +6880,8 @@ var optionalFileKeys = [
|
|
|
6835
6880
|
"caddyfile",
|
|
6836
6881
|
"mirrors",
|
|
6837
6882
|
"npmMirrorConf",
|
|
6838
|
-
"dockerMirrorGuard"
|
|
6883
|
+
"dockerMirrorGuard",
|
|
6884
|
+
"t3Gateway"
|
|
6839
6885
|
];
|
|
6840
6886
|
var fileNames = {
|
|
6841
6887
|
identity: "identity.env",
|
|
@@ -6848,7 +6894,8 @@ var fileNames = {
|
|
|
6848
6894
|
caddyfile: "Caddyfile",
|
|
6849
6895
|
mirrors: "compose.mirrors.yaml",
|
|
6850
6896
|
npmMirrorConf: "npm-mirror.conf",
|
|
6851
|
-
dockerMirrorGuard: "docker-mirror-guard.sh"
|
|
6897
|
+
dockerMirrorGuard: "docker-mirror-guard.sh",
|
|
6898
|
+
t3Gateway: "compose.t3.yaml"
|
|
6852
6899
|
};
|
|
6853
6900
|
var fileModes = {
|
|
6854
6901
|
identity: 384,
|
|
@@ -6861,7 +6908,8 @@ var fileModes = {
|
|
|
6861
6908
|
caddyfile: 420,
|
|
6862
6909
|
mirrors: 384,
|
|
6863
6910
|
npmMirrorConf: 420,
|
|
6864
|
-
dockerMirrorGuard: 420
|
|
6911
|
+
dockerMirrorGuard: 420,
|
|
6912
|
+
t3Gateway: 384
|
|
6865
6913
|
};
|
|
6866
6914
|
var allFiles = (files) => [...fileKeys, ...optionalFileKeys].map((key) => [key, files[key]]);
|
|
6867
6915
|
var parseLockOwner = (raw) => {
|
|
@@ -6968,6 +7016,7 @@ var readActive = (paths) => {
|
|
|
6968
7016
|
const mirrors = optional("mirrors");
|
|
6969
7017
|
const npmMirrorConf = optional("npmMirrorConf");
|
|
6970
7018
|
const dockerMirrorGuard = optional("dockerMirrorGuard");
|
|
7019
|
+
const t3Gateway = optional("t3Gateway");
|
|
6971
7020
|
const files = {
|
|
6972
7021
|
identity: fs14.readFileSync(path15.join(directory, fileNames.identity), "utf8"),
|
|
6973
7022
|
config: fs14.readFileSync(path15.join(directory, fileNames.config), "utf8"),
|
|
@@ -6979,7 +7028,8 @@ var readActive = (paths) => {
|
|
|
6979
7028
|
...caddyfile === void 0 ? {} : { caddyfile },
|
|
6980
7029
|
...mirrors === void 0 ? {} : { mirrors },
|
|
6981
7030
|
...npmMirrorConf === void 0 ? {} : { npmMirrorConf },
|
|
6982
|
-
...dockerMirrorGuard === void 0 ? {} : { dockerMirrorGuard }
|
|
7031
|
+
...dockerMirrorGuard === void 0 ? {} : { dockerMirrorGuard },
|
|
7032
|
+
...t3Gateway === void 0 ? {} : { t3Gateway }
|
|
6983
7033
|
};
|
|
6984
7034
|
if (readIdentity(paths) !== files.identity) {
|
|
6985
7035
|
throw new ServerStoreError(
|
|
@@ -7539,7 +7589,10 @@ var SETUP_FLAGS = /* @__PURE__ */ new Set([
|
|
|
7539
7589
|
"--docker-hub-username",
|
|
7540
7590
|
"--docker-hub-token-stdin",
|
|
7541
7591
|
"--docker-hub-public-only",
|
|
7542
|
-
"--no-docker-hub-login"
|
|
7592
|
+
"--no-docker-hub-login",
|
|
7593
|
+
"--t3-gateway",
|
|
7594
|
+
"--t3-gateway-port",
|
|
7595
|
+
"--no-t3-gateway"
|
|
7543
7596
|
]);
|
|
7544
7597
|
var SWITCHES = /* @__PURE__ */ new Set([
|
|
7545
7598
|
"--offline",
|
|
@@ -7550,7 +7603,9 @@ var SWITCHES = /* @__PURE__ */ new Set([
|
|
|
7550
7603
|
"--no-docker-mirror",
|
|
7551
7604
|
"--docker-hub-token-stdin",
|
|
7552
7605
|
"--docker-hub-public-only",
|
|
7553
|
-
"--no-docker-hub-login"
|
|
7606
|
+
"--no-docker-hub-login",
|
|
7607
|
+
"--t3-gateway",
|
|
7608
|
+
"--no-t3-gateway"
|
|
7554
7609
|
]);
|
|
7555
7610
|
var parseExposure = (value) => {
|
|
7556
7611
|
if (!isExposure(value))
|
|
@@ -7663,6 +7718,10 @@ var parseSetupOptions = (args) => {
|
|
|
7663
7718
|
throw setupError(
|
|
7664
7719
|
`--docker-hub-username and ${noDockerHubLogin ? "--no-docker-hub-login" : "--no-docker-mirror"} contradict each other.`
|
|
7665
7720
|
);
|
|
7721
|
+
const t3GatewayPort = flagValue3("--t3-gateway-port");
|
|
7722
|
+
if (values.has("--no-t3-gateway") && (values.has("--t3-gateway") || t3GatewayPort !== void 0)) {
|
|
7723
|
+
throw setupError("--no-t3-gateway contradicts --t3-gateway and --t3-gateway-port.");
|
|
7724
|
+
}
|
|
7666
7725
|
return {
|
|
7667
7726
|
context: flagValue3("--context"),
|
|
7668
7727
|
version: version === void 0 ? void 0 : parseVersion(version),
|
|
@@ -7686,7 +7745,10 @@ var parseSetupOptions = (args) => {
|
|
|
7686
7745
|
dockerMirrorMaxSize,
|
|
7687
7746
|
dockerHubUsername,
|
|
7688
7747
|
dockerHubTokenStdin,
|
|
7689
|
-
noDockerHubLogin
|
|
7748
|
+
noDockerHubLogin,
|
|
7749
|
+
t3Gateway: values.has("--t3-gateway"),
|
|
7750
|
+
t3GatewayPort: t3GatewayPort === void 0 ? void 0 : parsePort(t3GatewayPort, "--t3-gateway-port"),
|
|
7751
|
+
noT3Gateway: values.has("--no-t3-gateway")
|
|
7690
7752
|
};
|
|
7691
7753
|
};
|
|
7692
7754
|
var resolveMirrors = (saved, options) => {
|
|
@@ -7844,6 +7906,15 @@ var validateExposure = (existing, options) => {
|
|
|
7844
7906
|
const edgeHost = options.noEdge ? void 0 : options.edge ?? existing?.edgeHost;
|
|
7845
7907
|
const exposure = options.exposure ?? existing?.exposure;
|
|
7846
7908
|
const tenancy = options.tenancy ?? existing?.tenancy;
|
|
7909
|
+
const t3GatewayPort = options.noT3Gateway ? void 0 : options.t3GatewayPort ?? existing?.t3GatewayPort ?? (options.t3Gateway ? DEFAULT_T3_GATEWAY_PORT : void 0);
|
|
7910
|
+
if (t3GatewayPort !== void 0 && [appPort, sshPort].includes(t3GatewayPort)) {
|
|
7911
|
+
throw setupError(
|
|
7912
|
+
`--t3-gateway-port ${t3GatewayPort} is Mend's own --port or --ssh-port: the gateway needs a port of its own.`
|
|
7913
|
+
);
|
|
7914
|
+
}
|
|
7915
|
+
if (t3GatewayPort !== void 0 && edgeHost !== void 0 && [80, 443].includes(t3GatewayPort)) {
|
|
7916
|
+
throw setupError("With an edge, --t3-gateway-port must not be 80 or 443: the edge has them.");
|
|
7917
|
+
}
|
|
7847
7918
|
const declared = options.declared ?? existing?.declared ?? [];
|
|
7848
7919
|
checkPosture(bind, sshBind ?? bind, { appPort, sshPort }, edgeHost, exposure, declared);
|
|
7849
7920
|
const appUrl = resolveAppUrl(existing, options, appPort, edgeHost);
|
|
@@ -7864,7 +7935,8 @@ var validateExposure = (existing, options) => {
|
|
|
7864
7935
|
...edgeHost === void 0 ? {} : { edgeHost },
|
|
7865
7936
|
...exposure === void 0 ? {} : { exposure },
|
|
7866
7937
|
...tenancy === void 0 ? {} : { tenancy },
|
|
7867
|
-
...declared.length === 0 ? {} : { declared }
|
|
7938
|
+
...declared.length === 0 ? {} : { declared },
|
|
7939
|
+
...t3GatewayPort === void 0 ? {} : { t3GatewayPort }
|
|
7868
7940
|
};
|
|
7869
7941
|
};
|
|
7870
7942
|
var parseServerConfig = (raw) => {
|
|
@@ -7910,6 +7982,7 @@ var parseServerConfig = (raw) => {
|
|
|
7910
7982
|
);
|
|
7911
7983
|
}
|
|
7912
7984
|
const declared = Array.isArray(declaredField) ? declaredField.filter((item) => isDeclarableItem(String(item))) : [];
|
|
7985
|
+
const t3GatewayPort = fields.has("t3GatewayPort") ? requiredInteger(fields, "t3GatewayPort") : void 0;
|
|
7913
7986
|
const config = {
|
|
7914
7987
|
schemaVersion: requiredInteger(fields, "schemaVersion"),
|
|
7915
7988
|
assetContract: requiredString(fields, "assetContract"),
|
|
@@ -7932,7 +8005,8 @@ var parseServerConfig = (raw) => {
|
|
|
7932
8005
|
...exposure === void 0 ? {} : { exposure },
|
|
7933
8006
|
...tenancy === void 0 ? {} : { tenancy },
|
|
7934
8007
|
...declared.length === 0 ? {} : { declared },
|
|
7935
|
-
...fields.has("mirrors") ? { mirrors: parseMirrorsField(fields.get("mirrors")) } : {}
|
|
8008
|
+
...fields.has("mirrors") ? { mirrors: parseMirrorsField(fields.get("mirrors")) } : {},
|
|
8009
|
+
...t3GatewayPort === void 0 ? {} : { t3GatewayPort }
|
|
7936
8010
|
};
|
|
7937
8011
|
if (config.schemaVersion !== CONFIG_SCHEMA_VERSION || config.assetContract !== ASSET_CONTRACT && !LEGACY_ASSET_CONTRACTS.has(config.assetContract)) {
|
|
7938
8012
|
throw setupError(
|
|
@@ -7943,6 +8017,8 @@ var parseServerConfig = (raw) => {
|
|
|
7943
8017
|
parsePort(String(config.sshPort), "Server config sshPort");
|
|
7944
8018
|
if (config.registryPort !== void 0)
|
|
7945
8019
|
parsePort(String(config.registryPort), "Server config registryPort");
|
|
8020
|
+
if (config.t3GatewayPort !== void 0)
|
|
8021
|
+
parsePort(String(config.t3GatewayPort), "Server config t3GatewayPort");
|
|
7946
8022
|
validateExposure(null, {
|
|
7947
8023
|
context: void 0,
|
|
7948
8024
|
version: void 0,
|
|
@@ -7966,7 +8042,10 @@ var parseServerConfig = (raw) => {
|
|
|
7966
8042
|
dockerMirrorMaxSize: void 0,
|
|
7967
8043
|
dockerHubUsername: void 0,
|
|
7968
8044
|
dockerHubTokenStdin: false,
|
|
7969
|
-
noDockerHubLogin: false
|
|
8045
|
+
noDockerHubLogin: false,
|
|
8046
|
+
t3Gateway: false,
|
|
8047
|
+
t3GatewayPort: config.t3GatewayPort,
|
|
8048
|
+
noT3Gateway: false
|
|
7970
8049
|
});
|
|
7971
8050
|
return config;
|
|
7972
8051
|
};
|
|
@@ -8360,12 +8439,22 @@ var validateOverlays = (config, files) => {
|
|
|
8360
8439
|
}
|
|
8361
8440
|
for (const line of postureEnvLines(config)) {
|
|
8362
8441
|
const key = line.slice(0, line.indexOf("="));
|
|
8363
|
-
if (key !== "MEND_EDGE_HOST" && !(files.posture ?? "").includes(` ${key}: \${${key}`)) {
|
|
8442
|
+
if (key !== "MEND_EDGE_HOST" && key !== "MEND_T3_GATEWAY_PORT" && !(files.posture ?? "").includes(` ${key}: \${${key}`)) {
|
|
8364
8443
|
throw setupError(
|
|
8365
8444
|
`Server generation is corrupt: compose.posture.yaml does not hand ${key} to Mend.`
|
|
8366
8445
|
);
|
|
8367
8446
|
}
|
|
8368
8447
|
}
|
|
8448
|
+
if (config.t3GatewayPort === void 0 !== (files.t3Gateway === void 0)) {
|
|
8449
|
+
throw setupError(
|
|
8450
|
+
"Server generation is corrupt: compose.t3.yaml does not match the persisted server config."
|
|
8451
|
+
);
|
|
8452
|
+
}
|
|
8453
|
+
if (files.t3Gateway !== void 0 && (!files.t3Gateway.includes('MEND_T3_GATEWAY_ENABLED: "true"') || !files.t3Gateway.includes('"127.0.0.1:${MEND_T3_GATEWAY_PORT'))) {
|
|
8454
|
+
throw setupError(
|
|
8455
|
+
"Server generation is corrupt: compose.t3.yaml is not the gateway overlay on loopback."
|
|
8456
|
+
);
|
|
8457
|
+
}
|
|
8369
8458
|
if (config.edgeHost === void 0 !== (files.edge === void 0) || config.edgeHost === void 0 !== (files.caddyfile === void 0)) {
|
|
8370
8459
|
throw setupError(
|
|
8371
8460
|
"Server generation is corrupt: compose.edge.yaml and Caddyfile do not match the persisted server config."
|
|
@@ -8478,7 +8567,8 @@ var readServerInstallationFacts = async (configDir) => {
|
|
|
8478
8567
|
...generation.files.posture === void 0 ? [] : [{ name: "compose.posture.yaml", content: generation.files.posture }],
|
|
8479
8568
|
...generation.files.mirrors === void 0 ? [] : [{ name: MIRRORS_COMPOSE_FILE, content: generation.files.mirrors }],
|
|
8480
8569
|
...generation.files.npmMirrorConf === void 0 ? [] : [{ name: NPM_MIRROR_CONF_NAME, content: generation.files.npmMirrorConf }],
|
|
8481
|
-
...generation.files.dockerMirrorGuard === void 0 ? [] : [{ name: DOCKER_MIRROR_GUARD_NAME, content: generation.files.dockerMirrorGuard }]
|
|
8570
|
+
...generation.files.dockerMirrorGuard === void 0 ? [] : [{ name: DOCKER_MIRROR_GUARD_NAME, content: generation.files.dockerMirrorGuard }],
|
|
8571
|
+
...generation.files.t3Gateway === void 0 ? [] : [{ name: "compose.t3.yaml", content: generation.files.t3Gateway }]
|
|
8482
8572
|
],
|
|
8483
8573
|
envKeys: envKeyNames(generation.files.env)
|
|
8484
8574
|
};
|
|
@@ -8491,6 +8581,7 @@ var readServerInstallationFacts = async (configDir) => {
|
|
|
8491
8581
|
var generationFiles = (config, secrets, assets, identity = renderIdentity(secrets)) => {
|
|
8492
8582
|
const posture = renderPostureOverlay(config);
|
|
8493
8583
|
const mirrors = renderMirrorsOverlay(config.mirrors);
|
|
8584
|
+
const t3Gateway = renderT3GatewayOverlay(config);
|
|
8494
8585
|
return {
|
|
8495
8586
|
identity,
|
|
8496
8587
|
config: `${JSON.stringify(config, null, 2)}
|
|
@@ -8498,6 +8589,7 @@ var generationFiles = (config, secrets, assets, identity = renderIdentity(secret
|
|
|
8498
8589
|
env: renderSecrets(secrets, config),
|
|
8499
8590
|
...assets,
|
|
8500
8591
|
...posture === void 0 ? {} : { posture },
|
|
8592
|
+
...t3Gateway === void 0 ? {} : { t3Gateway },
|
|
8501
8593
|
...config.edgeHost === void 0 ? {} : { edge: EDGE_COMPOSE_OVERLAY, caddyfile: EDGE_CADDYFILE },
|
|
8502
8594
|
...mirrors === void 0 ? {} : { mirrors },
|
|
8503
8595
|
...config.mirrors === void 0 || config.mirrors.npm === null ? {} : { npmMirrorConf: NPM_MIRROR_CONF },
|
|
@@ -8511,6 +8603,18 @@ var healthOrigin = (config) => {
|
|
|
8511
8603
|
return `http://${host}:${config.appPort}`;
|
|
8512
8604
|
};
|
|
8513
8605
|
var reachableLine = (config) => config.edgeHost === void 0 ? `Mend ${config.serverVersion} is reachable at ${config.appUrl}` : `Mend ${config.serverVersion} answers at ${healthOrigin(config)} on this machine \xB7 the edge is set up for ${config.appUrl}`;
|
|
8606
|
+
var T3_GATEWAY_OBSERVE_ATTEMPTS = 15;
|
|
8607
|
+
var observeT3Gateway = async (runtime, port) => {
|
|
8608
|
+
const url = `http://127.0.0.1:${port}/.well-known/t3/environment`;
|
|
8609
|
+
for (let attempt2 = 0; attempt2 < T3_GATEWAY_OBSERVE_ATTEMPTS; attempt2 += 1) {
|
|
8610
|
+
const response = await runtime.fetchText(url, 2e3);
|
|
8611
|
+
if (response.error === void 0 && response.status === 200) {
|
|
8612
|
+
return `The t3code gateway answered at 127.0.0.1:${port}, observed from this machine; it is published there only. In t3code, add it as an environment at http://127.0.0.1:${port} and pair with a code from mend pair; reaching it from elsewhere is an exposure you put in front of it and declare (docs/adr/0004).`;
|
|
8613
|
+
}
|
|
8614
|
+
if (attempt2 < T3_GATEWAY_OBSERVE_ATTEMPTS - 1) await runtime.sleep(2e3);
|
|
8615
|
+
}
|
|
8616
|
+
return `The t3code gateway did not answer at 127.0.0.1:${port} from this machine within about a minute. Mend runs without it; mend server logs shows what it said, and mend server status looks again.`;
|
|
8617
|
+
};
|
|
8514
8618
|
var probeHealth = async (runtime, appUrl, expectedVersion) => {
|
|
8515
8619
|
const healthUrl = `${appUrl}/api/health`;
|
|
8516
8620
|
let lastFailure = "request did not complete";
|
|
@@ -8639,6 +8743,22 @@ var checkLocalImages = async (runtime, installation, policy = "local") => {
|
|
|
8639
8743
|
`Image ${image} must carry org.opencontainers.image.version=${config.serverVersion}.`
|
|
8640
8744
|
);
|
|
8641
8745
|
}
|
|
8746
|
+
if (config.t3GatewayPort !== void 0) {
|
|
8747
|
+
const gateway = await runtime.run("docker", [
|
|
8748
|
+
"--context",
|
|
8749
|
+
config.dockerContext,
|
|
8750
|
+
"image",
|
|
8751
|
+
"inspect",
|
|
8752
|
+
image,
|
|
8753
|
+
"--format",
|
|
8754
|
+
`{{index .Config.Labels "${T3_GATEWAY_IMAGE_LABEL}"}}`
|
|
8755
|
+
]);
|
|
8756
|
+
if (gateway.status !== 0 || gateway.stdout.trim() !== "1") {
|
|
8757
|
+
throw setupError(
|
|
8758
|
+
`Mend ${config.serverVersion} has no t3code gateway (its image carries no ${T3_GATEWAY_IMAGE_LABEL} label). Upgrade to a version that has one with mend server upgrade --version <version>, then turn it on; or run mend server setup --no-t3-gateway`
|
|
8759
|
+
);
|
|
8760
|
+
}
|
|
8761
|
+
}
|
|
8642
8762
|
const postgres = await inspectImage(
|
|
8643
8763
|
runtime,
|
|
8644
8764
|
config.dockerContext,
|
|
@@ -8965,6 +9085,11 @@ var setupServer = async (args, runtime, store) => {
|
|
|
8965
9085
|
...savedSecrets ?? createSecrets(runtime),
|
|
8966
9086
|
...dockerHubToken === void 0 ? {} : { dockerHubToken }
|
|
8967
9087
|
};
|
|
9088
|
+
if (config.t3GatewayPort !== void 0 && config.t3GatewayPort !== existing?.config.t3GatewayPort && config.dockerEndpoint.startsWith("unix://") && runtime.portTaken !== void 0 && await runtime.portTaken(config.t3GatewayPort)) {
|
|
9089
|
+
throw setupError(
|
|
9090
|
+
`127.0.0.1:${config.t3GatewayPort} is already in use on this machine, so the t3code gateway cannot be published there and Mend would not start. Free it, or pick another with --t3-gateway-port <n>`
|
|
9091
|
+
);
|
|
9092
|
+
}
|
|
8968
9093
|
const generation = persistSetup(store, config, secrets, assets);
|
|
8969
9094
|
const installation = {
|
|
8970
9095
|
directory: generation.directory,
|
|
@@ -8994,6 +9119,14 @@ var setupServer = async (args, runtime, store) => {
|
|
|
8994
9119
|
if (edgeStarted !== null) runtime.writeLine(edgeStarted);
|
|
8995
9120
|
const sshPublication = await sshPublicationLine(runtime, config);
|
|
8996
9121
|
if (sshPublication !== null) runtime.writeLine(sshPublication);
|
|
9122
|
+
if (config.t3GatewayPort !== void 0) {
|
|
9123
|
+
runtime.writeLine(await observeT3Gateway(runtime, config.t3GatewayPort));
|
|
9124
|
+
}
|
|
9125
|
+
if (existing?.config.t3GatewayPort !== void 0 && config.t3GatewayPort === void 0) {
|
|
9126
|
+
runtime.writeLine(
|
|
9127
|
+
`The t3code gateway is off. Its state (pairings and the device tokens they hold, queued messages) stays in its volume and comes back if you turn it on again; to remove it: docker --context ${config.dockerContext} volume rm mend_${T3_GATEWAY_VOLUME}`
|
|
9128
|
+
);
|
|
9129
|
+
}
|
|
8997
9130
|
if (existing?.config.edgeHost !== void 0 && config.edgeHost === void 0) {
|
|
8998
9131
|
runtime.writeLine(
|
|
8999
9132
|
`The edge for ${existing.config.edgeHost} is gone. Its certificate volumes stay until you remove them: docker --context ${config.dockerContext} volume rm mend_mend-edge-data mend_mend-edge-config`
|
|
@@ -9627,6 +9760,15 @@ var serverStatus = async (runtime, installation) => {
|
|
|
9627
9760
|
}
|
|
9628
9761
|
for (const line of await mirrorStatusLines(runtime, installation, runningServices))
|
|
9629
9762
|
runtime.writeLine(line);
|
|
9763
|
+
if (config.t3GatewayPort !== void 0 && runningServices.includes("mend")) {
|
|
9764
|
+
const gateway = await runtime.fetchText(
|
|
9765
|
+
`http://127.0.0.1:${config.t3GatewayPort}/.well-known/t3/environment`,
|
|
9766
|
+
2e3
|
|
9767
|
+
);
|
|
9768
|
+
runtime.writeLine(
|
|
9769
|
+
gateway.error === void 0 && gateway.status === 200 ? `t3code gateway \xB7 observed answering at 127.0.0.1:${config.t3GatewayPort} from this machine` : `t3code gateway \xB7 not observed at 127.0.0.1:${config.t3GatewayPort} from this machine \xB7 mend server logs shows what it said`
|
|
9770
|
+
);
|
|
9771
|
+
}
|
|
9630
9772
|
if (!runningServices.includes("mend")) {
|
|
9631
9773
|
runtime.writeLine("Mend is stopped. No health claim was made.");
|
|
9632
9774
|
return;
|
|
@@ -9743,6 +9885,7 @@ var nodeServerRuntime = () => {
|
|
|
9743
9885
|
dockerDaemonFacts: hostDockerDaemonFacts,
|
|
9744
9886
|
readLogin: (configDir) => savedLogin(configDir, environment),
|
|
9745
9887
|
probeSsh: probeSshFromHere,
|
|
9888
|
+
portTaken: portTakenHere,
|
|
9746
9889
|
readStdin: async () => {
|
|
9747
9890
|
const chunks = [];
|
|
9748
9891
|
for await (const chunk of process.stdin)
|
|
@@ -9774,6 +9917,11 @@ var sshBannerAt = async (host, port, timeoutMs) => {
|
|
|
9774
9917
|
socket.destroy();
|
|
9775
9918
|
}
|
|
9776
9919
|
};
|
|
9920
|
+
var portTakenHere = (port) => new Promise((resolve8) => {
|
|
9921
|
+
const server = net3.createServer();
|
|
9922
|
+
server.once("error", (error) => resolve8(error.code === "EADDRINUSE"));
|
|
9923
|
+
server.listen(port, "127.0.0.1", () => server.close(() => resolve8(false)));
|
|
9924
|
+
});
|
|
9777
9925
|
var probeSshFromHere = async (bind, port) => {
|
|
9778
9926
|
const unspecified = bind === "0.0.0.0" || bind === "::";
|
|
9779
9927
|
const addresses = unspecified ? Object.values(os10.networkInterfaces()).flatMap((entries) => entries ?? []).filter(
|
|
@@ -10748,11 +10896,65 @@ var writeWorkspaceSshConfig = (configFile, target, identityFile) => {
|
|
|
10748
10896
|
try {
|
|
10749
10897
|
fs18.mkdirSync(path18.dirname(configFile), { recursive: true, mode: 448 });
|
|
10750
10898
|
fs18.chmodSync(path18.dirname(configFile), 448);
|
|
10751
|
-
|
|
10752
|
-
fs18.chmodSync(configFile, 384);
|
|
10899
|
+
replaceFileAtomically(configFile, reconciled.value, 384);
|
|
10753
10900
|
return success(void 0);
|
|
10754
10901
|
} catch (cause) {
|
|
10755
|
-
return failure(
|
|
10902
|
+
return failure(
|
|
10903
|
+
new WorkspaceSshError(
|
|
10904
|
+
"config",
|
|
10905
|
+
`Could not write ${configFile}${cause instanceof Error ? `: ${cause.message}` : "."}`,
|
|
10906
|
+
cause
|
|
10907
|
+
)
|
|
10908
|
+
);
|
|
10909
|
+
}
|
|
10910
|
+
};
|
|
10911
|
+
var linkTarget = (file) => {
|
|
10912
|
+
let current = file;
|
|
10913
|
+
for (let hops = 0; hops < 40; hops += 1) {
|
|
10914
|
+
let stat;
|
|
10915
|
+
try {
|
|
10916
|
+
stat = fs18.lstatSync(current);
|
|
10917
|
+
} catch {
|
|
10918
|
+
if (current !== file && !fs18.existsSync(path18.dirname(current))) {
|
|
10919
|
+
throw new Error(
|
|
10920
|
+
`${file} is a symlink to ${current}, whose directory does not exist. Create it, or replace the link with a file; Mend left the link as it is.`
|
|
10921
|
+
);
|
|
10922
|
+
}
|
|
10923
|
+
return current;
|
|
10924
|
+
}
|
|
10925
|
+
if (!stat.isSymbolicLink()) return current;
|
|
10926
|
+
current = path18.resolve(path18.dirname(current), fs18.readlinkSync(current));
|
|
10927
|
+
}
|
|
10928
|
+
throw new Error(`${file} is a chain of symlinks too long to follow; Mend left it as it is.`);
|
|
10929
|
+
};
|
|
10930
|
+
var replaceFileAtomically = (file, contents, mode) => {
|
|
10931
|
+
const destination = linkTarget(file);
|
|
10932
|
+
const temporary = path18.join(
|
|
10933
|
+
path18.dirname(destination),
|
|
10934
|
+
`.${path18.basename(destination)}.mend-${process.pid}-${createHash3("sha256").update(`${Date.now()}:${Math.random()}`).digest("hex").slice(0, 12)}`
|
|
10935
|
+
);
|
|
10936
|
+
let descriptor = null;
|
|
10937
|
+
try {
|
|
10938
|
+
descriptor = fs18.openSync(temporary, "wx", mode);
|
|
10939
|
+
fs18.writeFileSync(descriptor, contents);
|
|
10940
|
+
fs18.fsyncSync(descriptor);
|
|
10941
|
+
fs18.closeSync(descriptor);
|
|
10942
|
+
descriptor = null;
|
|
10943
|
+
fs18.chmodSync(temporary, mode);
|
|
10944
|
+
fs18.renameSync(temporary, destination);
|
|
10945
|
+
} catch (cause) {
|
|
10946
|
+
if (descriptor !== null) fs18.closeSync(descriptor);
|
|
10947
|
+
fs18.rmSync(temporary, { force: true });
|
|
10948
|
+
throw cause;
|
|
10949
|
+
}
|
|
10950
|
+
try {
|
|
10951
|
+
const directory = fs18.openSync(path18.dirname(destination), "r");
|
|
10952
|
+
try {
|
|
10953
|
+
fs18.fsyncSync(directory);
|
|
10954
|
+
} finally {
|
|
10955
|
+
fs18.closeSync(directory);
|
|
10956
|
+
}
|
|
10957
|
+
} catch {
|
|
10756
10958
|
}
|
|
10757
10959
|
};
|
|
10758
10960
|
|
|
@@ -11112,6 +11314,17 @@ var describeUninstall = async (runtime, scope) => {
|
|
|
11112
11314
|
dockerContext: read.value.config.dockerContext,
|
|
11113
11315
|
edgeHost: read.value.config.edgeHost ?? null,
|
|
11114
11316
|
mirrors: mirrorServices(read.value.config.mirrors),
|
|
11317
|
+
t3GatewayVolume: read.value.config.t3GatewayPort !== void 0 || (await runtime.server.run(
|
|
11318
|
+
"docker",
|
|
11319
|
+
dockerArgs(
|
|
11320
|
+
read.value.config.dockerContext,
|
|
11321
|
+
"volume",
|
|
11322
|
+
"inspect",
|
|
11323
|
+
`mend_${T3_GATEWAY_VOLUME}`,
|
|
11324
|
+
"--format",
|
|
11325
|
+
"{{json .}}"
|
|
11326
|
+
)
|
|
11327
|
+
)).status === 0,
|
|
11115
11328
|
generations: countEntries(path20.join(configDir, "generations")),
|
|
11116
11329
|
backups: countEntries(path20.join(configDir, "backups"))
|
|
11117
11330
|
};
|
|
@@ -11145,7 +11358,9 @@ var planLines = (plan, configDir) => {
|
|
|
11145
11358
|
const edge = [...edgeHost === null ? [] : ["edge"], ...mirrors];
|
|
11146
11359
|
const edgeVolumes = [
|
|
11147
11360
|
...edgeHost === null ? [] : ["mend-edge-data", "mend-edge-config"],
|
|
11148
|
-
...mirrors.map((service) => `mend-${service}`)
|
|
11361
|
+
...mirrors.map((service) => `mend-${service}`),
|
|
11362
|
+
// The t3code gateway's state, with paired people's device tokens, when it is there.
|
|
11363
|
+
...plan.server.t3GatewayVolume === true ? [T3_GATEWAY_VOLUME] : []
|
|
11149
11364
|
];
|
|
11150
11365
|
lines.push(
|
|
11151
11366
|
` containers ${["mend", "postgres", "garage", ...edge].join(", ")} \xB7 volumes ${[MEND_DOCKER_NAMESPACE_WITH_GARAGE.store, ...secondaryVolumesOf(MEND_DOCKER_NAMESPACE_WITH_GARAGE), "mend-config", "mend-ssh", "mend-postgres", ...edgeVolumes].join(", ")} \xB7 image ghcr.io/sealant-sh/mend:${version}${edgeHost === null ? "" : ` \xB7 the edge for ${edgeHost}`}`
|
|
@@ -11211,6 +11426,24 @@ var removeServer = async (runtime, failures, leftovers) => {
|
|
|
11211
11426
|
server.writeLine(
|
|
11212
11427
|
`removed containers ${["mend", "postgres", "garage", ...mirrorServices(installation.config.mirrors)].join(", ")} and the Compose-owned volumes`
|
|
11213
11428
|
);
|
|
11429
|
+
const gatewayVolume = `mend_${T3_GATEWAY_VOLUME}`;
|
|
11430
|
+
const gatewayLeft = await server.run(
|
|
11431
|
+
"docker",
|
|
11432
|
+
dockerArgs(context, "volume", "inspect", gatewayVolume, "--format", "{{json .}}")
|
|
11433
|
+
);
|
|
11434
|
+
if (gatewayLeft.status === 0) {
|
|
11435
|
+
const gone = await server.run(
|
|
11436
|
+
"docker",
|
|
11437
|
+
dockerArgs(context, "volume", "rm", gatewayVolume)
|
|
11438
|
+
);
|
|
11439
|
+
if (gone.status === 0) {
|
|
11440
|
+
server.writeLine(`removed volume ${gatewayVolume}, the t3code gateway's state`);
|
|
11441
|
+
} else {
|
|
11442
|
+
failures.push(
|
|
11443
|
+
`could not remove volume ${gatewayVolume} (the t3code gateway's state, with paired device tokens): ${(gone.error ?? gone.stderr.trim()) || "no output"}`
|
|
11444
|
+
);
|
|
11445
|
+
}
|
|
11446
|
+
}
|
|
11214
11447
|
const namespace = installation.config.bucket === "garage" ? MEND_DOCKER_NAMESPACE_WITH_GARAGE : MEND_DOCKER_NAMESPACE;
|
|
11215
11448
|
const dataVolumes = [namespace.store, ...secondaryVolumesOf(namespace)];
|
|
11216
11449
|
const identity = store.readIdentity();
|
package/man/mend-accounts.1
CHANGED
package/man/mend-adopt.1
CHANGED
package/man/mend-attach.1
CHANGED
package/man/mend-codex.1
CHANGED
package/man/mend-completions.1
CHANGED
package/man/mend-connect-pi.1
CHANGED
package/man/mend-connect.1
CHANGED
package/man/mend-continue.1
CHANGED
package/man/mend-doctor.1
CHANGED
package/man/mend-dotfiles-repo.1
CHANGED
package/man/mend-dotfiles-sync.1
CHANGED
package/man/mend-dotfiles.1
CHANGED
package/man/mend-env-cluster.1
CHANGED
package/man/mend-env-load.1
CHANGED
package/man/mend-env-show.1
CHANGED