@crvouga/mockingbird-service-postgres 3.12.8 → 3.14.0

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/index.js CHANGED
@@ -32501,7 +32501,7 @@ function analyzeSchema(sql, options = {}) {
32501
32501
  const diagnosticLimit = bounded(options.maxDiagnostics, 100, 1e3);
32502
32502
  const report = {
32503
32503
  engine: "mockingbird-postgres",
32504
- version: true ? "3.12.8" : "source-tree",
32504
+ version: true ? "3.14.0" : "source-tree",
32505
32505
  statements: 0,
32506
32506
  accepted: 0,
32507
32507
  compatible: null,
package/dist/wire/cli.js CHANGED
@@ -2649,9 +2649,7 @@ data: ${JSON.stringify(data)}
2649
2649
  async handle(request, path, namespace, body, admin) {
2650
2650
  const route = path.slice("/fleet".length), method = request.method;
2651
2651
  if (path === "/ui")
2652
- return new Response(fleetConsole(this.ctx.config.adminPrefix ?? "/__admin"), {
2653
- headers: { "content-type": "text/html; charset=utf-8" }
2654
- });
2652
+ return new Response(fleetConsole(this.ctx.config.adminPrefix ?? "/__admin", this.ctx.dashboard?.()), { headers: { "content-type": "text/html; charset=utf-8" } });
2655
2653
  if (route === "" && method === "GET")
2656
2654
  return Response.json({
2657
2655
  ...this.capability(),
@@ -3621,7 +3619,8 @@ data: ${JSON.stringify(data)}
3621
3619
  clearInterval(this.expiryTimer);
3622
3620
  }
3623
3621
  };
3624
- var fleetConsole = (prefix) => `<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>Mockingbird Fleet</title><style>body{font:16px system-ui;max-width:1000px;margin:3rem auto;padding:1rem;background:#10151b;color:#e0e9f2}input,select,button{padding:.7rem;margin:.3rem;background:#233142;color:inherit;border:1px solid #60768b;border-radius:5px}pre{white-space:pre-wrap;overflow-wrap:anywhere}a{color:#9fdbff}</style><h1>Mockingbird Fleet</h1><label>Admin key <input id="key" type="password" autocomplete="off"></label><label>Namespace <input id="ns" value="default"></label><button id="refresh">Refresh</button><section id="children"></section><label>Action <select id="action"><option value="snapshots">Capture checkpoint</option><option value="reset">Reset namespace</option></select></label><button id="run">Run</button><h2>Lifecycle and operations</h2><pre id="result"></pre><script type="module">const base=${JSON.stringify(`${prefix}/fleet`)};const key=document.querySelector('#key'),ns=document.querySelector('#ns'),result=document.querySelector('#result');async function api(path,method='GET',body){const r=await fetch(base+path,{method,headers:{'content-type':'application/json','x-mockingbird-admin-key':key.value},...(body?{body:JSON.stringify(body)}:{})});const data=await r.json();result.textContent=JSON.stringify(data,null,2);return data}document.querySelector('#refresh').onclick=async()=>{const data=await api('');const host=document.querySelector('#children');host.replaceChildren();for(const [name,child]of Object.entries(data.manifest?.services??{})){const link=document.createElement('a');link.href=child.adminUrl;link.textContent=name+' ('+child.protocol+') ';host.append(link)}await api('/operations?namespace='+encodeURIComponent(ns.value))};document.querySelector('#run').onclick=()=>api('/namespaces/'+encodeURIComponent(ns.value)+'/'+document.querySelector('#action').value,'POST',{});</script></html>`;
3622
+ var escapeAttribute = (value) => value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;");
3623
+ var fleetConsole = (prefix, dashboard) => `<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>Mockingbird Fleet</title><style>body{font:16px system-ui;max-width:1000px;margin:3rem auto;padding:1rem;background:#10151b;color:#e0e9f2}input,select,button{padding:.7rem;margin:.3rem;background:#233142;color:inherit;border:1px solid #60768b;border-radius:5px}pre{white-space:pre-wrap;overflow-wrap:anywhere}a{color:#9fdbff}</style><h1>Mockingbird Fleet</h1>${dashboard ? `<p id="dashboard">Every emulator's admin UI and the notifications UI are on the <a href="${escapeAttribute(dashboard)}">dashboard</a>.</p>` : ""}<label>Admin key <input id="key" type="password" autocomplete="off"></label><label>Namespace <input id="ns" value="default"></label><button id="refresh">Refresh</button><section id="children"></section><label>Action <select id="action"><option value="snapshots">Capture checkpoint</option><option value="reset">Reset namespace</option></select></label><button id="run">Run</button><h2>Lifecycle and operations</h2><pre id="result"></pre><script type="module">const base=${JSON.stringify(`${prefix}/fleet`)};const key=document.querySelector('#key'),ns=document.querySelector('#ns'),result=document.querySelector('#result');async function api(path,method='GET',body){const r=await fetch(base+path,{method,headers:{'content-type':'application/json','x-mockingbird-admin-key':key.value},...(body?{body:JSON.stringify(body)}:{})});const data=await r.json();result.textContent=JSON.stringify(data,null,2);return data}document.querySelector('#refresh').onclick=async()=>{const data=await api('');const host=document.querySelector('#children');host.replaceChildren();for(const [name,child]of Object.entries(data.manifest?.services??{})){const link=document.createElement('a');link.href=child.adminUrl;link.textContent=name+' ('+child.protocol+') ';host.append(link)}await api('/operations?namespace='+encodeURIComponent(ns.value))};document.querySelector('#run').onclick=()=>api('/namespaces/'+encodeURIComponent(ns.value)+'/'+document.querySelector('#action').value,'POST',{});</script></html>`;
3625
3624
 
3626
3625
  // ../../adapters/node/dist/fleet-preflight.js
3627
3626
  import { readFile, realpath } from "node:fs/promises";
@@ -3685,6 +3684,28 @@ var fleet_config_schema_default = {
3685
3684
  }
3686
3685
  }
3687
3686
  },
3687
+ dashboard: {
3688
+ description: "Serve the dashboard (every emulator's admin UI and the notifications UI) next to the fleet. Honored by mockingbird-fleet serve.",
3689
+ anyOf: [
3690
+ {
3691
+ type: "boolean"
3692
+ },
3693
+ {
3694
+ type: "object",
3695
+ additionalProperties: false,
3696
+ properties: {
3697
+ port: {
3698
+ type: "integer",
3699
+ minimum: 0,
3700
+ maximum: 65535
3701
+ },
3702
+ host: {
3703
+ type: "string"
3704
+ }
3705
+ }
3706
+ }
3707
+ ]
3708
+ },
3688
3709
  cors: {
3689
3710
  type: "object",
3690
3711
  required: ["origins"],
@@ -3969,6 +3990,7 @@ async function preflightFleet(config, options2) {
3969
3990
  throw new Error("protected archive policy requires a protected repository; configure its protector before startup");
3970
3991
  resolveAdminPrefix(config.adminPrefix);
3971
3992
  normalizeBootControls(config.adminControls);
3993
+ validateDashboard(config.dashboard);
3972
3994
  if (config.idBase !== void 0)
3973
3995
  normalizeIdBase(config.idBase, "idBase");
3974
3996
  const targets = /* @__PURE__ */ new Map();
@@ -4044,7 +4066,7 @@ async function preflightFleet(config, options2) {
4044
4066
  break;
4045
4067
  }
4046
4068
  }
4047
- targets.set(name2, { ...target, packageVersion: packageVersion ?? "3.12.8" });
4069
+ targets.set(name2, { ...target, packageVersion: packageVersion ?? "3.14.0" });
4048
4070
  } catch (error) {
4049
4071
  throw new Error(`service ${name2}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
4050
4072
  }
@@ -4129,6 +4151,22 @@ function validateFleetPolicies(options2) {
4129
4151
  if (duration !== void 0 && (!Number.isSafeInteger(duration) || duration < 1))
4130
4152
  throw new Error("hook deadlines must be positive integer milliseconds");
4131
4153
  }
4154
+ function validateDashboard(value) {
4155
+ if (value === void 0 || typeof value === "boolean")
4156
+ return;
4157
+ if (!value || typeof value !== "object" || Array.isArray(value))
4158
+ throw new Error("dashboard: expected true, false or { port, host }");
4159
+ for (const [key, entry] of Object.entries(value)) {
4160
+ if (key === "port") {
4161
+ if (!Number.isInteger(entry) || entry < 0 || entry > 65535)
4162
+ throw new Error("dashboard.port: expected an integer from 0 to 65535");
4163
+ } else if (key === "host") {
4164
+ if (typeof entry !== "string" || !entry)
4165
+ throw new Error("dashboard.host: expected a host");
4166
+ } else
4167
+ throw new Error(`dashboard.${key}: unknown key; expected port or host`);
4168
+ }
4169
+ }
4132
4170
 
4133
4171
  // ../../adapters/node/dist/serve.js
4134
4172
  import { createServer } from "node:http";
@@ -4584,6 +4622,7 @@ async function startFleet(config, options2) {
4584
4622
  const checkpoints = /* @__PURE__ */ new Map();
4585
4623
  let supervisor;
4586
4624
  let management;
4625
+ let dashboard;
4587
4626
  let manifest;
4588
4627
  const privateConnections = () => Object.fromEntries([...children].map(([name2, child]) => [
4589
4628
  name2,
@@ -4651,6 +4690,7 @@ async function startFleet(config, options2) {
4651
4690
  }
4652
4691
  }
4653
4692
  const cleanup = await Promise.allSettled([
4693
+ dashboard?.close(),
4654
4694
  supervisor?.close(),
4655
4695
  removeOwned(options2.readyFile, id),
4656
4696
  removeOwned(options2.connectionsFile, id)
@@ -5017,6 +5057,7 @@ async function startFleet(config, options2) {
5017
5057
  clock,
5018
5058
  transaction,
5019
5059
  manifest: () => manifest,
5060
+ dashboard: () => dashboard?.url,
5020
5061
  publish,
5021
5062
  recovery,
5022
5063
  controlling
@@ -5080,6 +5121,10 @@ async function startFleet(config, options2) {
5080
5121
  }
5081
5122
  }
5082
5123
  await management.startPolicies();
5124
+ if (options2.dashboard) {
5125
+ dashboard = await options2.dashboard({ manifest, config });
5126
+ manifest.dashboard = dashboard.url;
5127
+ }
5083
5128
  await publish();
5084
5129
  if (manifest.state === "ready")
5085
5130
  options2.onReady?.(manifest);
@@ -5911,6 +5956,8 @@ var serveCommand = (target) => ({
5911
5956
  const adminKey2 = config.adminKey ?? asString(values["admin-key"]) ?? process.env.MOCKINGBIRD_ADMIN_KEY;
5912
5957
  if (adminKey2 !== void 0)
5913
5958
  config.adminKey = adminKey2;
5959
+ if (config.dashboard)
5960
+ console.error(`${configPath}: "dashboard" is served by mockingbird-fleet (npx @crvouga/mockingbird-fleet serve --config ${configPath}); a service's own serve command starts the fleet without it`);
5914
5961
  const adminControls = await resolveServeControls(values, process.env, config.adminControls);
5915
5962
  if (adminControls !== void 0)
5916
5963
  config.adminControls = adminControls;