@mybase-dev/cli 1.0.5 → 1.0.6

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.
Files changed (2) hide show
  1. package/dist/mybase.js +63 -1
  2. package/package.json +1 -1
package/dist/mybase.js CHANGED
@@ -139,7 +139,7 @@ function parseDotenv(text) {
139
139
  // package.json
140
140
  var package_default = {
141
141
  name: "@mybase-dev/cli",
142
- version: "1.0.5",
142
+ version: "1.0.6",
143
143
  description: "The mybase CLI: projects, keys, cron, queues, cache, rate limits, analytics, docs, and agent setup for a self-hosted mybase.",
144
144
  type: "module",
145
145
  repository: {
@@ -3759,6 +3759,7 @@ var compose_default = `# Runs mybase: the control plane (API + dashboard), the s
3759
3759
  # MYBASE_S3_PUBLIC_URL=https://s3.<domain>
3760
3760
  # MYBASE_TRUST_PROXY=cloudflare
3761
3761
  # Optionally POSTGRES_BIND=127.0.0.1, GARAGE_S3_BIND=127.0.0.1, and VALKEY_BIND=127.0.0.1 to stop exposing those ports on the LAN.
3762
+ # Optionally CLOUDFLARED_REGION=us if the tunnel lands on far-away data centers (see \`mybase server status\`).
3762
3763
  # 5. docker compose up -d
3763
3764
  # Apps on serverless hosts reach Postgres at wss://mybase.<domain>/db with @neondatabase/serverless,
3764
3765
  # or, with a router port forward, at a normal postgres:// URL (public Postgres, below).
@@ -3922,6 +3923,11 @@ services:
3922
3923
  command: tunnel --no-autoupdate run
3923
3924
  environment:
3924
3925
  TUNNEL_TOKEN: \${CLOUDFLARE_TUNNEL_TOKEN:-}
3926
+ # Which Cloudflare data centers the tunnel connects to: empty = nearest by anycast, \`us\` = US only
3927
+ # (if \`mybase server status\` shows far-away colos, every request takes the detour).
3928
+ TUNNEL_REGION: \${CLOUDFLARED_REGION:-}
3929
+ # auto (QUIC, falls back to HTTP/2), quic, or http2 (if your network blocks or throttles UDP).
3930
+ TUNNEL_TRANSPORT_PROTOCOL: \${CLOUDFLARED_PROTOCOL:-auto}
3925
3931
  depends_on:
3926
3932
  - mybase
3927
3933
 
@@ -4253,6 +4259,25 @@ async function enableDockerOnBoot() {
4253
4259
  return false;
4254
4260
  }
4255
4261
  }
4262
+ function tunnelConnections(logs) {
4263
+ const conns = new Map;
4264
+ for (const line of logs.split(`
4265
+ `)) {
4266
+ if (/Starting tunnel/.test(line))
4267
+ conns.clear();
4268
+ const index = Number(/connIndex=(\d+)/.exec(line)?.[1]);
4269
+ if (Number.isNaN(index))
4270
+ continue;
4271
+ if (/Registered tunnel connection/.test(line)) {
4272
+ const location = /location=(\S+)/.exec(line)?.[1];
4273
+ if (location)
4274
+ conns.set(index, { index, location, protocol: /protocol=(\S+)/.exec(line)?.[1] ?? null });
4275
+ } else if (/Unregistered tunnel connection|Connection terminated|Retrying connection|Serve tunnel error/.test(line)) {
4276
+ conns.delete(index);
4277
+ }
4278
+ }
4279
+ return [...conns.values()].sort((a, b) => a.index - b.index);
4280
+ }
4256
4281
 
4257
4282
  // src/server-setup.ts
4258
4283
  import { chmod as chmod2, mkdir as mkdir3 } from "fs/promises";
@@ -5044,6 +5069,7 @@ var serverUsage = ` server setup [--dir <dir>] Install mybase on this machi
5044
5069
  [--admin-user <u> --admin-password-stdin] Without a terminal: defaults plus these flags
5045
5070
  server status [--dir <dir>] Containers, health, and whether mybase starts on boot
5046
5071
  server update [--dir <dir>] Download new images and restart (also refreshes compose.yml)
5072
+ server restart [--dir <dir>] Restart every container (API, Postgres, storage, cache, search, tunnel)
5047
5073
  server tunnel [--dir <dir>] Add or replace the Cloudflare Tunnel [--tunnel-token <t> --domain <d>] | --off
5048
5074
  server database-public [--dir <dir>] A normal postgres:// URL from anywhere: router port forward +
5049
5075
  Let's Encrypt TLS + DNS kept on your IP (Cloudflare)
@@ -5076,6 +5102,10 @@ async function status(args) {
5076
5102
  const health = await fetch(`${url}/health`, { signal: AbortSignal.timeout(3000) }).then(async (r) => r.ok ? (await r.json()).version ?? "unknown" : null).catch(() => null);
5077
5103
  const autostart = values.MYBASE_RESTART !== "no";
5078
5104
  const docker = dockerOnBoot();
5105
+ const tunnelOn = !!values.CLOUDFLARE_TUNNEL_TOKEN && containers.some((c) => c.Service === "cloudflared");
5106
+ const tunnelLogs = tunnelOn ? await compose(dir, ["logs", "--no-log-prefix", "--tail", "500", "cloudflared"]) : null;
5107
+ const tunnel = tunnelLogs?.ok ? tunnelConnections(`${tunnelLogs.stdout}
5108
+ ${tunnelLogs.stderr}`) : null;
5079
5109
  const data = {
5080
5110
  dir,
5081
5111
  url,
@@ -5084,6 +5114,7 @@ async function status(args) {
5084
5114
  autostart: autostart && docker !== "disabled",
5085
5115
  dockerOnBoot: docker,
5086
5116
  publicUrl: values.CLOUDFLARE_TUNNEL_TOKEN ? values.MYBASE_PUBLIC_URL ?? null : null,
5117
+ tunnel,
5087
5118
  containers: containers.map((c) => ({ service: c.Service, state: c.State, health: c.Health || null }))
5088
5119
  };
5089
5120
  print(data, () => {
@@ -5091,6 +5122,10 @@ async function status(args) {
5091
5122
  console.log(` ${health ? green("\u25CF") : red("\u25CF")} ${url} ${health ? `version ${health}` : "not answering"}`);
5092
5123
  if (data.publicUrl)
5093
5124
  console.log(` ${dim2("public")} ${data.publicUrl}`);
5125
+ if (tunnel) {
5126
+ const where = tunnel.map((c) => `${c.location}${c.protocol ? ` ${c.protocol}` : ""}`).join(", ");
5127
+ console.log(` ${tunnel.length > 0 ? green("\u25CF") : red("\u25CF")} ${dim2("tunnel")} ${tunnel.length > 0 ? `${tunnel.length} connection(s): ${where}` : "not connected to Cloudflare (public URL answers 530)"}`);
5128
+ }
5094
5129
  console.log(` ${dim2("starts on boot")} ${!autostart ? "no (mybase server autostart on)" : docker === "disabled" ? "no: Docker doesn't start at boot (sudo systemctl enable docker)" : "yes"}`);
5095
5130
  console.log("");
5096
5131
  if (containers.length === 0)
@@ -5121,6 +5156,31 @@ async function update(args) {
5121
5156
  return print({ dir, version, composeUpdated: replaced }, () => {});
5122
5157
  outro(`mybase ${version} is running at ${localUrl(values)}`);
5123
5158
  }
5159
+ async function restart(args) {
5160
+ const dir = await serverDir(args);
5161
+ const { values } = await loadEnv(dir);
5162
+ if (!await stackExists(dir))
5163
+ throw new CliError("no containers to restart. Start them: mybase server update", 4);
5164
+ const s = ui.spinner();
5165
+ s.start("Restarting containers");
5166
+ const res = await compose(dir, ["restart"]);
5167
+ if (!res.ok) {
5168
+ s.stop("Restart failed");
5169
+ throw new CliError(`docker compose restart failed:
5170
+ ${res.stderr}`);
5171
+ }
5172
+ s.message("Waiting for mybase to answer");
5173
+ const version = await waitHealthy(localUrl(values), 120000);
5174
+ s.stop(version ? "Restarted" : "Containers restarted");
5175
+ if (!version) {
5176
+ ui.warn("mybase didn't answer yet; check `mybase server status`.");
5177
+ process.exitCode = 1;
5178
+ }
5179
+ print({ dir, healthy: version !== null, version }, () => {
5180
+ if (version)
5181
+ console.log(`mybase ${version} is running at ${localUrl(values)}`);
5182
+ });
5183
+ }
5124
5184
  async function tunnel(args) {
5125
5185
  const dir = await serverDir(args);
5126
5186
  const { text, values } = await loadEnv(dir);
@@ -5277,6 +5337,8 @@ async function server(command, args) {
5277
5337
  await status(args);
5278
5338
  else if (command === "update")
5279
5339
  await update(args);
5340
+ else if (command === "restart")
5341
+ await restart(args);
5280
5342
  else if (command === "tunnel")
5281
5343
  await tunnel(args);
5282
5344
  else if (command === "database-public")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mybase-dev/cli",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "The mybase CLI: projects, keys, cron, queues, cache, rate limits, analytics, docs, and agent setup for a self-hosted mybase.",
5
5
  "type": "module",
6
6
  "repository": {