@abloatai/cli 0.56.0 → 0.58.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.
Files changed (2) hide show
  1. package/dist/cli.cjs +1145 -568
  2. package/package.json +4 -3
package/dist/cli.cjs CHANGED
@@ -827,9 +827,9 @@ var init_query = __esm({
827
827
  CLOSE = {};
828
828
  Query = class extends Promise {
829
829
  constructor(strings, args, handler, canceller, options = {}) {
830
- let resolve10, reject;
830
+ let resolve11, reject;
831
831
  super((a, b4) => {
832
- resolve10 = a;
832
+ resolve11 = a;
833
833
  reject = b4;
834
834
  });
835
835
  this.tagged = Array.isArray(strings.raw);
@@ -840,7 +840,7 @@ var init_query = __esm({
840
840
  this.options = options;
841
841
  this.state = null;
842
842
  this.statement = null;
843
- this.resolve = (x2) => (this.active = false, resolve10(x2));
843
+ this.resolve = (x2) => (this.active = false, resolve11(x2));
844
844
  this.reject = (x2) => (this.active = false, reject(x2));
845
845
  this.active = false;
846
846
  this.cancelled = null;
@@ -888,12 +888,12 @@ var init_query = __esm({
888
888
  if (this.executed && !this.active)
889
889
  return { done: true };
890
890
  prev && prev();
891
- const promise = new Promise((resolve10, reject) => {
891
+ const promise = new Promise((resolve11, reject) => {
892
892
  this.cursorFn = (value) => {
893
- resolve10({ value, done: false });
893
+ resolve11({ value, done: false });
894
894
  return new Promise((r2) => prev = r2);
895
895
  };
896
- this.resolve = () => (this.active = false, resolve10({ done: true }));
896
+ this.resolve = () => (this.active = false, resolve11({ done: true }));
897
897
  this.reject = (x2) => (this.active = false, reject(x2));
898
898
  });
899
899
  this.execute();
@@ -1491,12 +1491,12 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
1491
1491
  x2.on("drain", drain);
1492
1492
  return x2;
1493
1493
  }
1494
- async function cancel({ pid, secret }, resolve10, reject) {
1494
+ async function cancel({ pid, secret }, resolve11, reject) {
1495
1495
  try {
1496
1496
  cancelMessage = bytes_default().i32(16).i32(80877102).i32(pid).i32(secret).end(16);
1497
1497
  await connect2();
1498
1498
  socket.once("error", reject);
1499
- socket.once("close", resolve10);
1499
+ socket.once("close", resolve11);
1500
1500
  } catch (error2) {
1501
1501
  reject(error2);
1502
1502
  }
@@ -2519,7 +2519,7 @@ var init_subscribe = __esm({
2519
2519
 
2520
2520
  // ../../node_modules/postgres/src/large.js
2521
2521
  function largeObject(sql, oid, mode = 131072 | 262144) {
2522
- return new Promise(async (resolve10, reject) => {
2522
+ return new Promise(async (resolve11, reject) => {
2523
2523
  await sql.begin(async (sql2) => {
2524
2524
  let finish;
2525
2525
  !oid && ([{ oid }] = await sql2`select lo_creat(-1) as oid`);
@@ -2545,7 +2545,7 @@ function largeObject(sql, oid, mode = 131072 | 262144) {
2545
2545
  ) seek
2546
2546
  `
2547
2547
  };
2548
- resolve10(lo);
2548
+ resolve11(lo);
2549
2549
  return new Promise(async (r2) => finish = r2);
2550
2550
  async function readable({
2551
2551
  highWaterMark = 2048 * 8,
@@ -2707,8 +2707,8 @@ function Postgres(a, b4) {
2707
2707
  }
2708
2708
  async function reserve() {
2709
2709
  const queue = queue_default();
2710
- const c = open.length ? open.shift() : await new Promise((resolve10, reject) => {
2711
- const query = { reserve: resolve10, reject };
2710
+ const c = open.length ? open.shift() : await new Promise((resolve11, reject) => {
2711
+ const query = { reserve: resolve11, reject };
2712
2712
  queries.push(query);
2713
2713
  closed.length && connect2(closed.shift(), query);
2714
2714
  });
@@ -2745,9 +2745,9 @@ function Postgres(a, b4) {
2745
2745
  let uncaughtError, result;
2746
2746
  name && await sql2`savepoint ${sql2(name)}`;
2747
2747
  try {
2748
- result = await new Promise((resolve10, reject) => {
2748
+ result = await new Promise((resolve11, reject) => {
2749
2749
  const x2 = fn2(sql2);
2750
- Promise.resolve(Array.isArray(x2) ? Promise.all(x2) : x2).then(resolve10, reject);
2750
+ Promise.resolve(Array.isArray(x2) ? Promise.all(x2) : x2).then(resolve11, reject);
2751
2751
  });
2752
2752
  if (uncaughtError)
2753
2753
  throw uncaughtError;
@@ -2804,8 +2804,8 @@ function Postgres(a, b4) {
2804
2804
  return c.execute(query) ? move(c, busy) : move(c, full);
2805
2805
  }
2806
2806
  function cancel(query) {
2807
- return new Promise((resolve10, reject) => {
2808
- query.state ? query.active ? connection_default(options).cancel(query.state, resolve10, reject) : query.cancelled = { resolve: resolve10, reject } : (queries.remove(query), query.cancelled = true, query.reject(Errors.generic("57014", "canceling statement due to user request")), resolve10());
2807
+ return new Promise((resolve11, reject) => {
2808
+ query.state ? query.active ? connection_default(options).cancel(query.state, resolve11, reject) : query.cancelled = { resolve: resolve11, reject } : (queries.remove(query), query.cancelled = true, query.reject(Errors.generic("57014", "canceling statement due to user request")), resolve11());
2809
2809
  });
2810
2810
  }
2811
2811
  async function end({ timeout = null } = {}) {
@@ -2824,11 +2824,11 @@ function Postgres(a, b4) {
2824
2824
  async function close() {
2825
2825
  await Promise.all(connections.map((c) => c.end()));
2826
2826
  }
2827
- async function destroy(resolve10) {
2827
+ async function destroy(resolve11) {
2828
2828
  await Promise.all(connections.map((c) => c.terminate()));
2829
2829
  while (queries.length)
2830
2830
  queries.shift().reject(Errors.connection("CONNECTION_DESTROYED", options));
2831
- resolve10();
2831
+ resolve11();
2832
2832
  }
2833
2833
  function connect2(c, query) {
2834
2834
  move(c, connecting);
@@ -3349,7 +3349,7 @@ function ambientEnvKeyNote(cwd) {
3349
3349
  return `Note: ${ambient.source} in this directory holds an ABLO_API_KEY, which this command does not load \u2014 it reads only the process environment and your stored login, so a file cannot silently choose a branch. Export the variable, or pass \`--env-file ` + ambient.source + "` to a connect command, to choose it explicitly.";
3350
3350
  }
3351
3351
  function resolveManagementKey() {
3352
- if (process.env.ABLO_MANAGEMENT_KEY) return process.env.ABLO_MANAGEMENT_KEY;
3352
+ if (process.env.ABLO_API_KEY?.startsWith("mk_")) return process.env.ABLO_API_KEY;
3353
3353
  const cfg = readConfig();
3354
3354
  if (!cfg) return void 0;
3355
3355
  const entry = cfg.profiles[activeProfileName(cfg)]?.management;
@@ -3358,7 +3358,7 @@ function resolveManagementKey() {
3358
3358
  return entry.apiKey;
3359
3359
  }
3360
3360
  function resolveOrgManagementKey(options = {}) {
3361
- if (process.env.ABLO_MANAGEMENT_KEY) return process.env.ABLO_MANAGEMENT_KEY;
3361
+ if (process.env.ABLO_API_KEY?.startsWith("mk_")) return process.env.ABLO_API_KEY;
3362
3362
  const cfg = readConfig({ persistMigrations: options.persistConfigMigrations });
3363
3363
  if (!cfg) return void 0;
3364
3364
  const profiles = [.../* @__PURE__ */ new Set([
@@ -3458,7 +3458,7 @@ function requireKey() {
3458
3458
  if (!apiKey) {
3459
3459
  console.error(
3460
3460
  import_picocolors3.default.red(" No project management credential.") + import_picocolors3.default.dim(
3461
- ` Run ${import_picocolors3.default.bold("npx ablo login")} \u2014 or set ${import_picocolors3.default.bold("ABLO_MANAGEMENT_KEY")} to an ${import_picocolors3.default.bold("mk_")} credential.`
3461
+ ` Run ${import_picocolors3.default.bold("npx ablo login")} \u2014 or set ${import_picocolors3.default.bold("ABLO_API_KEY")} to an ${import_picocolors3.default.bold("mk_")} credential.`
3462
3462
  )
3463
3463
  );
3464
3464
  process.exit(1);
@@ -3481,15 +3481,18 @@ async function request(path, apiKey, init3 = {}, baseUrl2) {
3481
3481
  }
3482
3482
  return { status: res.status, body };
3483
3483
  }
3484
+ function projectListResult(status2, body) {
3485
+ if (status2 !== 200) {
3486
+ const code = typeof body === "object" && body !== null && "code" in body ? body.code : void 0;
3487
+ return { ok: false, reason: typeof code === "string" ? code : `HTTP ${status2}` };
3488
+ }
3489
+ const parsed = import_wire.projectListResponseSchema.safeParse(body);
3490
+ return parsed.success ? { ok: true, projects: parsed.data.data } : { ok: false, reason: "the response did not match the project list" };
3491
+ }
3484
3492
  async function listProjects(apiKey, baseUrl2) {
3485
3493
  try {
3486
3494
  const { status: status2, body } = await request("/api/v1/projects", apiKey, {}, baseUrl2);
3487
- if (status2 !== 200) {
3488
- const code = body?.code;
3489
- return { ok: false, reason: typeof code === "string" ? code : `HTTP ${status2}` };
3490
- }
3491
- const parsed = import_wire.projectListResponseSchema.safeParse(body);
3492
- return parsed.success ? { ok: true, projects: parsed.data.data } : { ok: false, reason: "the response did not match the project list" };
3495
+ return projectListResult(status2, body);
3493
3496
  } catch (err) {
3494
3497
  return { ok: false, reason: err instanceof Error ? err.message : "the request failed" };
3495
3498
  }
@@ -3538,6 +3541,10 @@ async function ensureProject(slug, name) {
3538
3541
  return null;
3539
3542
  }
3540
3543
  }
3544
+ function projectDisplayName(p2) {
3545
+ const spelling = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
3546
+ return p2.name && spelling(p2.name) !== spelling(p2.slug) ? p2.name : void 0;
3547
+ }
3541
3548
  function describeKeys(profile) {
3542
3549
  const now = Date.now();
3543
3550
  let usable = 0;
@@ -3566,8 +3573,7 @@ function describeAge(createdAt) {
3566
3573
  function printList(projects2) {
3567
3574
  const active = getActiveProject();
3568
3575
  const profiles = readConfig()?.profiles ?? {};
3569
- const spelling = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
3570
- const nameOf = (p2) => p2.name && spelling(p2.name) !== spelling(p2.slug) ? p2.name : "";
3576
+ const nameOf = (p2) => projectDisplayName(p2) ?? "";
3571
3577
  const showNames = projects2.some((p2) => nameOf(p2) !== "");
3572
3578
  const slugWidth = Math.max(...projects2.map((p2) => p2.slug.length));
3573
3579
  const nameWidth = showNames ? Math.max(...projects2.map((p2) => nameOf(p2).length)) : 0;
@@ -3970,7 +3976,7 @@ var init_observeCliError = __esm({
3970
3976
  import_errorObservation = require("@abloatai/transaction/errorObservation");
3971
3977
  import_errors5 = require("@abloatai/transaction/errors");
3972
3978
  dsn = process.env.ABLO_CLI_SENTRY_DSN ?? "https://1ac154bff10b06836e1ea9de9e0d92f0@o4510928209772544.ingest.de.sentry.io/4511660691423312" ?? "";
3973
- release = process.env.ABLO_CLI_RELEASE ?? "@abloatai/cli@0.56.0";
3979
+ release = process.env.ABLO_CLI_RELEASE ?? "@abloatai/cli@0.58.0";
3974
3980
  initialized = false;
3975
3981
  nativeProcessExit = process.exit.bind(process);
3976
3982
  exitBoundaryInstalled = false;
@@ -4297,7 +4303,7 @@ var init_src2 = __esm({
4297
4303
 
4298
4304
  // src/cliEnvironment.ts
4299
4305
  function cliVersion() {
4300
- return "0.56.0";
4306
+ return "0.58.0";
4301
4307
  }
4302
4308
  function cliOs() {
4303
4309
  const value = (0, import_node_os.platform)();
@@ -4372,7 +4378,9 @@ function trackCliSchemaPushAttempted() {
4372
4378
  }
4373
4379
  function flushProductAnalytics(options = {}) {
4374
4380
  if (flushInFlight) return flushInFlight;
4375
- flushInFlight = flushOnce(options).catch(() => void 0).finally(() => {
4381
+ flushInFlight = flushOnce(options).catch((error) => {
4382
+ void error;
4383
+ }).finally(() => {
4376
4384
  flushInFlight = null;
4377
4385
  });
4378
4386
  return flushInFlight;
@@ -4395,8 +4403,8 @@ function queueEvent(eventName, properties) {
4395
4403
  state.queue = [...state.queue, parsed].slice(-MAX_QUEUED_EVENTS);
4396
4404
  writeState(state);
4397
4405
  if (disclose) {
4398
- console.error(
4399
- "Ablo collects limited usage analytics. Run `ablo telemetry disable` to opt out or `ablo telemetry status` for details."
4406
+ process.stderr.write(
4407
+ "Ablo collects limited usage analytics. Run `ablo telemetry disable` to opt out or `ablo telemetry status` for details.\n"
4400
4408
  );
4401
4409
  }
4402
4410
  } catch {
@@ -4473,8 +4481,9 @@ function writeState(state) {
4473
4481
  function environmentBlocker() {
4474
4482
  if (process.env.ABLO_TELEMETRY_DISABLED === "1") return "ABLO_TELEMETRY_DISABLED";
4475
4483
  if (process.env.DO_NOT_TRACK === "1") return "DO_NOT_TRACK";
4476
- const ciVariables = ["CI", "GITHUB_ACTIONS", "GITLAB_CI", "BUILDKITE", "CIRCLECI", "TF_BUILD"];
4477
- return ciVariables.find((name) => truthyEnvironmentValue(process.env[name])) ?? null;
4484
+ return TELEMETRY_BLOCKING_ENV.slice(2).find(
4485
+ (name) => truthyEnvironmentValue(process.env[name])
4486
+ ) ?? null;
4478
4487
  }
4479
4488
  function truthyEnvironmentValue(value) {
4480
4489
  return value !== void 0 && value !== "" && value !== "0" && value.toLowerCase() !== "false";
@@ -4502,7 +4511,7 @@ function runTelemetryCommand(argv) {
4502
4511
  if (status2.blockedBy) console.log(`Environment override: ${status2.blockedBy}`);
4503
4512
  console.log(`Queued events: ${status2.queuedEvents}`);
4504
4513
  }
4505
- var import_node_crypto2, import_node_fs, import_node_path, TELEMETRY_FILE_VERSION, MAX_QUEUED_EVENTS, MAX_FLUSH_EVENTS, DEFAULT_FLUSH_TIMEOUT_MS, flushInFlight;
4514
+ var import_node_crypto2, import_node_fs, import_node_path, TELEMETRY_FILE_VERSION, MAX_QUEUED_EVENTS, MAX_FLUSH_EVENTS, DEFAULT_FLUSH_TIMEOUT_MS, flushInFlight, TELEMETRY_BLOCKING_ENV;
4506
4515
  var init_telemetry = __esm({
4507
4516
  "src/telemetry.ts"() {
4508
4517
  "use strict";
@@ -4519,6 +4528,16 @@ var init_telemetry = __esm({
4519
4528
  MAX_FLUSH_EVENTS = 20;
4520
4529
  DEFAULT_FLUSH_TIMEOUT_MS = 800;
4521
4530
  flushInFlight = null;
4531
+ TELEMETRY_BLOCKING_ENV = [
4532
+ "ABLO_TELEMETRY_DISABLED",
4533
+ "DO_NOT_TRACK",
4534
+ "CI",
4535
+ "GITHUB_ACTIONS",
4536
+ "GITLAB_CI",
4537
+ "BUILDKITE",
4538
+ "CIRCLECI",
4539
+ "TF_BUILD"
4540
+ ];
4522
4541
  }
4523
4542
  });
4524
4543
 
@@ -4716,16 +4735,9 @@ async function fetchActiveSchema(url, apiKey) {
4716
4735
  clearTimeout(t);
4717
4736
  }
4718
4737
  }
4719
- function conflictStr(c) {
4720
- if (!c) return "";
4721
- const parts = import_schema2.participantKindSchema.options.flatMap((k3) => c[k3] ? [`${k3}:${c[k3]}`] : []);
4722
- return parts.length ? `{${parts.join(",")}}` : "";
4723
- }
4724
4738
  function localModels(schema) {
4725
4739
  const json = JSON.parse((0, import_schema.serializeSchema)(schema));
4726
- const out = /* @__PURE__ */ new Map();
4727
- for (const [key, def] of Object.entries(json.models)) out.set(key, conflictStr(def.conflict));
4728
- return out;
4740
+ return new Set(Object.keys(json.models));
4729
4741
  }
4730
4742
  function printPlan(local, remote) {
4731
4743
  if (!remote?.models) {
@@ -4733,21 +4745,17 @@ function printPlan(local, remote) {
4733
4745
  `);
4734
4746
  return;
4735
4747
  }
4736
- const remoteMap = /* @__PURE__ */ new Map();
4737
- for (const m2 of remote.models) remoteMap.set(m2.key, conflictStr(m2.conflict));
4738
- const added = [...local.keys()].filter((k3) => !remoteMap.has(k3));
4739
- const removed = [...remoteMap.keys()].filter((k3) => !local.has(k3));
4740
- const changed = [...local.keys()].filter((k3) => remoteMap.has(k3) && remoteMap.get(k3) !== local.get(k3));
4748
+ const remoteKeys = new Set(remote.models.map((model) => model.key));
4749
+ const added = [...local].filter((key) => !remoteKeys.has(key));
4750
+ const removed = [...remoteKeys].filter((key) => !local.has(key));
4741
4751
  const verLabel = remote.version != null ? `v${remote.version}` : "active";
4742
- if (added.length === 0 && removed.length === 0 && changed.length === 0) {
4752
+ if (added.length === 0 && removed.length === 0) {
4743
4753
  console.log(` ${import_picocolors5.default.dim("plan")} ${import_picocolors5.default.dim(`no model-level changes vs deployed ${verLabel} (any field changes apply on push)`)}
4744
4754
  `);
4745
4755
  return;
4746
4756
  }
4747
4757
  console.log(` ${import_picocolors5.default.dim("plan")} ${import_picocolors5.default.dim(`vs deployed ${verLabel}:`)}`);
4748
4758
  for (const k3 of added) console.log(` ${import_picocolors5.default.green(`+ ${k3}`)} ${import_picocolors5.default.dim("(new model)")}`);
4749
- for (const k3 of changed)
4750
- console.log(` ${import_picocolors5.default.yellow(`~ ${k3}`)} ${import_picocolors5.default.dim(`conflict ${remoteMap.get(k3) || "(default)"} \u2192 ${local.get(k3) || "(default)"}`)}`);
4751
4759
  for (const k3 of removed) console.log(` ${import_picocolors5.default.red(`- ${k3}`)} ${import_picocolors5.default.dim("(removed \u2014 destructive, needs --force)")}`);
4752
4760
  console.log("");
4753
4761
  }
@@ -5038,7 +5046,7 @@ async function push(argv) {
5038
5046
  }
5039
5047
  process.exit(1);
5040
5048
  }
5041
- var import_picocolors5, import_errors7, import_credentialPolicy, import_fs4, import_path3, import_child_process, import_schema, import_schema2, DEFAULT_SCHEMA_PATH, DEFAULT_EXPORT, PUSH_USAGE;
5049
+ var import_picocolors5, import_errors7, import_credentialPolicy, import_fs4, import_path3, import_child_process, import_schema, DEFAULT_SCHEMA_PATH, DEFAULT_EXPORT, PUSH_USAGE;
5042
5050
  var init_push = __esm({
5043
5051
  "src/push.ts"() {
5044
5052
  "use strict";
@@ -5056,7 +5064,6 @@ var init_push = __esm({
5056
5064
  init_target();
5057
5065
  init_theme();
5058
5066
  init_renderError();
5059
- import_schema2 = require("@abloatai/transaction/coordination/schema");
5060
5067
  init_telemetry();
5061
5068
  DEFAULT_SCHEMA_PATH = "ablo/schema.ts";
5062
5069
  DEFAULT_EXPORT = "schema";
@@ -5083,6 +5090,84 @@ var init_push = __esm({
5083
5090
  }
5084
5091
  });
5085
5092
 
5093
+ // src/dbProvider.ts
5094
+ function hostAndPort(hostOrTarget) {
5095
+ const withoutScheme = hostOrTarget.trim().replace(/^[a-z0-9+.-]+:\/\//i, "");
5096
+ const at = withoutScheme.lastIndexOf("@");
5097
+ const withoutUserinfo = at === -1 ? withoutScheme : withoutScheme.slice(at + 1);
5098
+ const authority = withoutUserinfo.split("/")[0] ?? "";
5099
+ const parts = /^(\[[^\]]*\]|[^:]*)(?::(\d+))?$/.exec(authority);
5100
+ return { hostname: (parts?.[1] ?? authority).toLowerCase(), port: parts?.[2] ?? "" };
5101
+ }
5102
+ function inDomain(hostname, domain) {
5103
+ return hostname === domain || hostname.endsWith(`.${domain}`);
5104
+ }
5105
+ function detectProvider(hostOrTarget) {
5106
+ const { hostname } = hostAndPort(hostOrTarget);
5107
+ const spec = PROVIDERS.find((p2) => p2.domains.some((domain) => inDomain(hostname, domain)));
5108
+ return spec?.id ?? "generic";
5109
+ }
5110
+ function detectPooler(hostOrTarget) {
5111
+ const { hostname, port } = hostAndPort(hostOrTarget);
5112
+ const provider = detectProvider(hostOrTarget);
5113
+ const spec = PROVIDERS.find((p2) => p2.id === provider);
5114
+ if (spec?.isPooledHost?.(hostname)) {
5115
+ const direct = spec.directTarget?.(hostOrTarget);
5116
+ return direct === void 0 ? { provider, confidence: "host" } : { provider, direct, confidence: "host" };
5117
+ }
5118
+ if (POOLER_PORTS.has(port)) return { provider, confidence: "port" };
5119
+ return null;
5120
+ }
5121
+ function replicationGrantRole(provider) {
5122
+ const specs = PROVIDERS;
5123
+ const spec = specs.find((candidate) => candidate.id === provider);
5124
+ return spec?.replicationGrantRole ?? null;
5125
+ }
5126
+ function logicalReplicationGuidance(provider) {
5127
+ const spec = PROVIDERS.find((p2) => p2.id === provider);
5128
+ if (spec) return spec.logicalReplication;
5129
+ return `run the ALTER SYSTEM above, then restart Postgres (wal_level is not reloadable). On a managed host that refuses ALTER SYSTEM, set wal_level to logical in its dashboard instead`;
5130
+ }
5131
+ var PROVIDERS, POOLER_PORTS;
5132
+ var init_dbProvider = __esm({
5133
+ "src/dbProvider.ts"() {
5134
+ "use strict";
5135
+ init_cjs_shims();
5136
+ PROVIDERS = [
5137
+ {
5138
+ id: "neon",
5139
+ domains: ["neon.tech"],
5140
+ logicalReplication: `enable logical replication in your Neon project settings \u2014 it can't be set over SQL`,
5141
+ // Neon encodes pooling in the endpoint id, so the direct host is the same
5142
+ // name with the marker removed: a fix the reader applies without a lookup.
5143
+ isPooledHost: (hostname) => hostname.includes("-pooler"),
5144
+ directTarget: (hostOrTarget) => hostOrTarget.replace(/-pooler/i, "")
5145
+ },
5146
+ {
5147
+ id: "supabase",
5148
+ domains: ["supabase.co", "supabase.com"],
5149
+ logicalReplication: `raise wal_level to logical in your Supabase project's database settings`,
5150
+ // Supavisor is a separate host entirely (`aws-0-<region>.pooler.supabase.com`),
5151
+ // so there is no direct host to derive from it.
5152
+ isPooledHost: (hostname) => hostname.endsWith(".pooler.supabase.com")
5153
+ },
5154
+ {
5155
+ id: "rds",
5156
+ // Anchored to the real RDS domains, including the China partition, rather
5157
+ // than a bare `.rds.` anywhere in the name.
5158
+ domains: ["rds.amazonaws.com", "rds.amazonaws.com.cn"],
5159
+ logicalReplication: `set rds.logical_replication = 1 in the instance's parameter group, then reboot`,
5160
+ // RDS Proxy fronts the instance under a `.proxy-` subdomain.
5161
+ isPooledHost: (hostname) => hostname.includes(".proxy-"),
5162
+ // Neither the master user nor rds_superuser carries REPLICATION; AWS keeps
5163
+ // it on rdsadmin and exposes it through this role.
5164
+ replicationGrantRole: "rds_replication"
5165
+ }
5166
+ ];
5167
+ POOLER_PORTS = /* @__PURE__ */ new Set(["6432", "6543"]);
5168
+ }
5169
+ });
5170
+
5086
5171
  // src/remoteValidation.ts
5087
5172
  function dialFailureReason(err) {
5088
5173
  if (err === null || typeof err !== "object") return null;
@@ -5179,76 +5264,6 @@ var init_remoteValidation = __esm({
5179
5264
  }
5180
5265
  });
5181
5266
 
5182
- // src/dbProvider.ts
5183
- function hostAndPort(hostOrTarget) {
5184
- const withoutScheme = hostOrTarget.trim().replace(/^[a-z0-9+.-]+:\/\//i, "");
5185
- const at = withoutScheme.lastIndexOf("@");
5186
- const withoutUserinfo = at === -1 ? withoutScheme : withoutScheme.slice(at + 1);
5187
- const authority = withoutUserinfo.split("/")[0] ?? "";
5188
- const parts = /^(\[[^\]]*\]|[^:]*)(?::(\d+))?$/.exec(authority);
5189
- return { hostname: (parts?.[1] ?? authority).toLowerCase(), port: parts?.[2] ?? "" };
5190
- }
5191
- function inDomain(hostname, domain) {
5192
- return hostname === domain || hostname.endsWith(`.${domain}`);
5193
- }
5194
- function detectProvider(hostOrTarget) {
5195
- const { hostname } = hostAndPort(hostOrTarget);
5196
- const spec = PROVIDERS.find((p2) => p2.domains.some((domain) => inDomain(hostname, domain)));
5197
- return spec?.id ?? "generic";
5198
- }
5199
- function detectPooler(hostOrTarget) {
5200
- const { hostname, port } = hostAndPort(hostOrTarget);
5201
- const provider = detectProvider(hostOrTarget);
5202
- const spec = PROVIDERS.find((p2) => p2.id === provider);
5203
- if (spec?.isPooledHost?.(hostname)) {
5204
- const direct = spec.directTarget?.(hostOrTarget);
5205
- return direct === void 0 ? { provider, confidence: "host" } : { provider, direct, confidence: "host" };
5206
- }
5207
- if (POOLER_PORTS.has(port)) return { provider, confidence: "port" };
5208
- return null;
5209
- }
5210
- function logicalReplicationGuidance(provider) {
5211
- const spec = PROVIDERS.find((p2) => p2.id === provider);
5212
- if (spec) return spec.logicalReplication;
5213
- return `run the ALTER SYSTEM above, then restart Postgres (wal_level is not reloadable). On a managed host that refuses ALTER SYSTEM, set wal_level to logical in its dashboard instead`;
5214
- }
5215
- var PROVIDERS, POOLER_PORTS;
5216
- var init_dbProvider = __esm({
5217
- "src/dbProvider.ts"() {
5218
- "use strict";
5219
- init_cjs_shims();
5220
- PROVIDERS = [
5221
- {
5222
- id: "neon",
5223
- domains: ["neon.tech"],
5224
- logicalReplication: `enable logical replication in your Neon project settings \u2014 it can't be set over SQL`,
5225
- // Neon encodes pooling in the endpoint id, so the direct host is the same
5226
- // name with the marker removed: a fix the reader applies without a lookup.
5227
- isPooledHost: (hostname) => hostname.includes("-pooler"),
5228
- directTarget: (hostOrTarget) => hostOrTarget.replace(/-pooler/i, "")
5229
- },
5230
- {
5231
- id: "supabase",
5232
- domains: ["supabase.co", "supabase.com"],
5233
- logicalReplication: `raise wal_level to logical in your Supabase project's database settings`,
5234
- // Supavisor is a separate host entirely (`aws-0-<region>.pooler.supabase.com`),
5235
- // so there is no direct host to derive from it.
5236
- isPooledHost: (hostname) => hostname.endsWith(".pooler.supabase.com")
5237
- },
5238
- {
5239
- id: "rds",
5240
- // Anchored to the real RDS domains, including the China partition, rather
5241
- // than a bare `.rds.` anywhere in the name.
5242
- domains: ["rds.amazonaws.com", "rds.amazonaws.com.cn"],
5243
- logicalReplication: `set rds.logical_replication = 1 in the instance's parameter group, then reboot`,
5244
- // RDS Proxy fronts the instance under a `.proxy-` subdomain.
5245
- isPooledHost: (hostname) => hostname.includes(".proxy-")
5246
- }
5247
- ];
5248
- POOLER_PORTS = /* @__PURE__ */ new Set(["6432", "6543"]);
5249
- }
5250
- });
5251
-
5252
5267
  // src/connectSetup.ts
5253
5268
  function hostLabel(connectionString) {
5254
5269
  try {
@@ -5280,12 +5295,26 @@ BEGIN
5280
5295
  END LOOP;
5281
5296
  END $$;`;
5282
5297
  }
5298
+ function replicationBypassSql(input) {
5299
+ if (input.canGrantBypassRls) return [];
5300
+ return input.tables.flatMap((table) => {
5301
+ const qualified = `${quoteIdent(input.schema)}.${quoteIdent(table)}`;
5302
+ const policy = quoteIdent(`${input.role}_snapshot`);
5303
+ return [
5304
+ // CREATE POLICY has no IF NOT EXISTS, and every step here is safe to
5305
+ // re-run, so the drop carries the idempotency.
5306
+ `DROP POLICY IF EXISTS ${policy} ON ${qualified};`,
5307
+ `CREATE POLICY ${policy} ON ${qualified} FOR SELECT TO ${quoteIdent(input.role)} USING (true);`
5308
+ ];
5309
+ });
5310
+ }
5283
5311
  function connectSetupSql(input) {
5284
5312
  const role = input.role && input.role.length > 0 ? input.role : import_footprint.ABLO_REPLICATION_ROLE;
5285
5313
  const writeRole = input.writeRole && input.writeRole.length > 0 ? input.writeRole : import_footprint.ABLO_WRITE_ROLE;
5286
5314
  const tables = input.tables ?? [];
5287
5315
  const schema = input.schema ?? "public";
5288
5316
  const publication = input.publication;
5317
+ const canGrantBypassRls = input.canGrantBypassRls !== false;
5289
5318
  const qualifiedTables = tables.map((table) => `${quoteIdent(schema)}.${quoteIdent(table)}`);
5290
5319
  const publicationTarget = tables.length > 0 ? `FOR TABLE ${qualifiedTables.join(", ")}` : "FOR ALL TABLES";
5291
5320
  const tableList = qualifiedTables.join(", ");
@@ -5305,9 +5334,11 @@ function connectSetupSql(input) {
5305
5334
  // 3. A least-privilege role: it can stream replication and SELECT the
5306
5335
  // published tables, including the initial snapshot of RLS-protected tables.
5307
5336
  // Logical decoding already exposes every published row independently of
5308
- // RLS; BYPASSRLS makes the ordinary SELECT snapshot match that same scope.
5309
- `CREATE ROLE ${quoteIdent(role)} WITH NOSUPERUSER BYPASSRLS NOCREATEDB NOCREATEROLE REPLICATION NOINHERIT LOGIN PASSWORD '<password>';`,
5337
+ // RLS, so the reader needs the ordinary SELECT snapshot to match that same
5338
+ // scope. How it gets there depends on what this admin may grant.
5339
+ `CREATE ROLE ${quoteIdent(role)} WITH NOSUPERUSER ${canGrantBypassRls ? "BYPASSRLS " : ""}NOCREATEDB NOCREATEROLE ${canGrantBypassRls ? "REPLICATION NOINHERIT" : "NOREPLICATION INHERIT"} LOGIN PASSWORD '<password>';`,
5310
5340
  ...replicationReadGrants,
5341
+ ...replicationBypassSql({ role, tables, schema, canGrantBypassRls }),
5311
5342
  // 4. A distinct DML role: no replication, role administration, ownership,
5312
5343
  // schema creation, or DDL. It runs NOBYPASSRLS with row_security on, so on a
5313
5344
  // table that HAS row-level-security policies they govern its writes and it
@@ -5453,7 +5484,15 @@ On Neon enable Logical Replication in the project (Console \u2192 Settings \u219
5453
5484
  `SELECT rolreplication, rolsuper, rolbypassrls FROM pg_roles WHERE rolname = current_user`
5454
5485
  );
5455
5486
  const role = roleRows[0];
5456
- const hasReplication = Boolean(role && (role.rolreplication || role.rolsuper));
5487
+ const grantRole = opts.replicationGrantRole ?? null;
5488
+ const viaGrant = grantRole ? (await sql.unsafe(
5489
+ `SELECT EXISTS (
5490
+ SELECT 1 FROM pg_roles r
5491
+ WHERE r.rolname = $1 AND pg_has_role(current_user, r.oid, 'MEMBER')
5492
+ ) AS member`,
5493
+ [grantRole]
5494
+ ))[0]?.member === true : false;
5495
+ const hasReplication = Boolean(role && (role.rolreplication || role.rolsuper)) || viaGrant;
5457
5496
  items.push(
5458
5497
  hasReplication ? {
5459
5498
  ok: true,
@@ -5473,6 +5512,20 @@ On RDS: GRANT rds_replication TO <your_role>;`
5473
5512
  JOIN pg_class c ON c.relnamespace = n.oid AND c.relname = pt.tablename
5474
5513
  WHERE pt.pubname = $1 AND pt.schemaname = $2
5475
5514
  AND row_security_active(c.oid)
5515
+ AND NOT EXISTS (
5516
+ SELECT 1 FROM pg_policies p
5517
+ WHERE p.schemaname = pt.schemaname
5518
+ AND p.tablename = pt.tablename
5519
+ AND p.permissive = 'PERMISSIVE'
5520
+ AND p.cmd IN ('ALL', 'SELECT')
5521
+ AND p.qual = 'true'
5522
+ -- Membership, not containment: pg_policies.roles is name[], while
5523
+ -- ARRAY['public'] is text[]. Postgres has no name[] @> text[] operator, so
5524
+ -- the containment spelling fails at execution rather than at parse time:
5525
+ -- the probe threw instead of reporting, which reads as an unreachable
5526
+ -- database rather than a readable one.
5527
+ AND ('public' = ANY(p.roles) OR current_user = ANY(p.roles))
5528
+ )
5476
5529
  ORDER BY table_name`,
5477
5530
  [publication, schema]
5478
5531
  );
@@ -5482,7 +5535,9 @@ On RDS: GRANT rds_replication TO <your_role>;`
5482
5535
  ok: false,
5483
5536
  label: `${rlsRelevant.length} published table${rlsRelevant.length === 1 ? "" : "s"} hide historical rows behind RLS`,
5484
5537
  fix: `ALTER ROLE current_user WITH BYPASSRLS;
5485
- Logical replication already exposes every published row; this lets the ordinary initial SELECT read that same scope.`
5538
+ Where the provider reserves that attribute (Amazon RDS, Aurora), give the reader a policy instead:
5539
+ CREATE POLICY <reader>_snapshot ON <table> FOR SELECT TO <reader> USING (true);
5540
+ Logical replication already exposes every published row; either lets the ordinary initial SELECT read that same scope.`
5486
5541
  }
5487
5542
  );
5488
5543
  const badRows = await sql.unsafe(
@@ -6020,7 +6075,7 @@ async function fetchDataSourceState(apiUrl3, apiKey, timeoutMs = 4e3) {
6020
6075
  async function readLocalSchemaHash(schemaPath = DEFAULT_SCHEMA_PATH) {
6021
6076
  try {
6022
6077
  const schema = await loadSchema(schemaPath, DEFAULT_EXPORT);
6023
- return (0, import_schema4.schemaHash)(schema);
6078
+ return (0, import_schema3.schemaHash)(schema);
6024
6079
  } catch {
6025
6080
  return null;
6026
6081
  }
@@ -6091,7 +6146,7 @@ function blockers(input) {
6091
6146
  }
6092
6147
  return found;
6093
6148
  }
6094
- var import_wire5, import_schema4, WRITE_READY_VERDICT;
6149
+ var import_wire5, import_schema3, WRITE_READY_VERDICT;
6095
6150
  var init_readiness = __esm({
6096
6151
  "src/readiness.ts"() {
6097
6152
  "use strict";
@@ -6100,7 +6155,7 @@ var init_readiness = __esm({
6100
6155
  init_push();
6101
6156
  init_dbProvider();
6102
6157
  init_remoteValidation();
6103
- import_schema4 = require("@abloatai/transaction/schema");
6158
+ import_schema3 = require("@abloatai/transaction/schema");
6104
6159
  WRITE_READY_VERDICT = "write infrastructure is ready. Your database constraints and row-level policies still apply.";
6105
6160
  }
6106
6161
  });
@@ -6128,7 +6183,17 @@ function connectApplyPlan(input) {
6128
6183
  const schema = input.schema ?? "public";
6129
6184
  const publication = input.publication;
6130
6185
  const provider = input.provider ?? "generic";
6131
- const recipe = connectSetupSql({ tables, role, writeRole, schema, publication });
6186
+ const canGrantBypassRls = input.canGrantBypassRls !== false;
6187
+ const canGrantReplication = input.canGrantReplication !== false;
6188
+ const grantedReplicationRole = canGrantReplication ? null : replicationGrantRole(provider);
6189
+ const recipe = connectSetupSql({
6190
+ tables,
6191
+ role,
6192
+ writeRole,
6193
+ schema,
6194
+ publication,
6195
+ canGrantBypassRls
6196
+ });
6132
6197
  const isWal = (s) => s.startsWith("ALTER SYSTEM SET wal_level");
6133
6198
  const isPublication = (s) => s.startsWith("CREATE PUBLICATION");
6134
6199
  const isRoleCreate = (s) => s.startsWith("CREATE ROLE ");
@@ -6176,19 +6241,46 @@ END $$;`
6176
6241
  {
6177
6242
  key: "replication-role",
6178
6243
  title: "Create the read-only login Ablo reads with",
6179
- detail: `${role} \u2014 it can follow your changes and snapshot the same published rows, including through RLS`,
6244
+ detail: canGrantBypassRls ? `${role} \u2014 it can follow your changes and snapshot the same published rows, including through RLS` : `${role} \u2014 it can follow your changes, and reads the published rows through a SELECT policy of its own, because this provider reserves BYPASSRLS`,
6180
6245
  sql: [
6181
6246
  idempotentRole(
6182
6247
  role,
6183
- "NOSUPERUSER BYPASSRLS NOCREATEDB NOCREATEROLE REPLICATION NOINHERIT",
6248
+ // NOINHERIT everywhere the capability is an attribute: the reader
6249
+ // should hold what it was given and nothing that arrives later.
6250
+ // Where the provider lends REPLICATION as a role instead, the
6251
+ // membership only confers it by inheriting — a NOINHERIT member holds
6252
+ // it in name, `pg_has_role(..., 'USAGE')` is false, and replication
6253
+ // fails while every "was it granted" check says yes. So the grant
6254
+ // path inherits, and its only membership is the one granted below.
6255
+ `NOSUPERUSER ${canGrantBypassRls ? "BYPASSRLS " : ""}NOCREATEDB NOCREATEROLE ${canGrantReplication ? "REPLICATION" : "NOREPLICATION"} ${grantedReplicationRole ? "INHERIT" : "NOINHERIT"}`,
6184
6256
  input.credentials.replicationClause,
6185
6257
  input.rotate === true
6186
6258
  ),
6187
6259
  // Unlike a password, this is a required invariant rather than secret
6188
6260
  // material owned by one plane. Re-assert it for an existing pre-snapshot
6189
6261
  // role so `connect apply` repairs the exact upgrade gap that otherwise
6190
- // certifies an RLS-filtered empty snapshot as complete.
6191
- `ALTER ROLE ${quoteIdent(role)} WITH BYPASSRLS;`
6262
+ // certifies an RLS-filtered empty snapshot as complete. Where the
6263
+ // attribute cannot be granted at all, the policies in the grants step
6264
+ // carry the same invariant.
6265
+ ...canGrantBypassRls ? [`ALTER ROLE ${quoteIdent(role)} WITH BYPASSRLS;`] : [],
6266
+ // The provider keeps REPLICATION on an internal superuser and lends it
6267
+ // through a role. Without this the reader authenticates and then cannot
6268
+ // open a replication slot, which surfaces far from its cause.
6269
+ ...grantedReplicationRole ? [
6270
+ // WITH INHERIT TRUE, because Postgres 16 records inheritance on
6271
+ // the MEMBERSHIP rather than only on the role. A member that does
6272
+ // not inherit holds the grant without holding what it carries:
6273
+ // `pg_has_role(..., 'MEMBER')` is true, `USAGE` is false, and
6274
+ // replication does not work while every "was it granted" check
6275
+ // says yes.
6276
+ //
6277
+ // Stated on the grant rather than left to the role's default so
6278
+ // it also repairs a reader created before this path existed.
6279
+ // `ALTER ROLE ... INHERIT` does not: it changes the default for
6280
+ // FUTURE memberships and leaves the recorded one untouched, which
6281
+ // is a fix that reports success and changes nothing.
6282
+ `GRANT ${quoteIdent(grantedReplicationRole)} TO ${quoteIdent(role)} WITH INHERIT TRUE;`
6283
+ ] : []
6192
6284
  ]
6193
6285
  },
6194
6286
  {
@@ -6288,14 +6380,14 @@ function reapplyBlocker(input) {
6288
6380
  }
6289
6381
  async function adminCanCreateRoles(sql) {
6290
6382
  const rows = await sql.unsafe(
6291
- `SELECT rolname, rolsuper, rolcreaterole FROM pg_roles WHERE rolname = current_user`
6383
+ `SELECT rolname, rolsuper, rolcreaterole, rolbypassrls, rolreplication FROM pg_roles WHERE rolname = current_user`
6292
6384
  );
6293
6385
  return rows[0] ?? null;
6294
6386
  }
6295
6387
  async function schemaDeclaredTables() {
6296
6388
  try {
6297
6389
  const schema = await loadSchema(DEFAULT_SCHEMA_PATH, DEFAULT_EXPORT);
6298
- const json = JSON.parse((0, import_schema5.serializeSchema)(schema));
6390
+ const json = JSON.parse((0, import_schema4.serializeSchema)(schema));
6299
6391
  const tables = Object.entries(json.models).map(([key, model]) => model.tableName ?? key);
6300
6392
  return tables.length > 0 ? tables : null;
6301
6393
  } catch {
@@ -6368,7 +6460,7 @@ function alreadyConnectedElsewhere(held) {
6368
6460
  const where = held.project ? `project ${held.project}, branch ${held.branch}` : `branch ${held.branch}`;
6369
6461
  return `This database schema is already connected to ${where}. A (database, schema) binding belongs to one plane at a time.`;
6370
6462
  }
6371
- var import_wire6, import_schema5;
6463
+ var import_wire6, import_schema4;
6372
6464
  var init_connectPreflight = __esm({
6373
6465
  "src/connectPreflight.ts"() {
6374
6466
  "use strict";
@@ -6377,7 +6469,7 @@ var init_connectPreflight = __esm({
6377
6469
  import_wire6 = require("@abloatai/transaction/wire");
6378
6470
  init_controlPlane();
6379
6471
  init_push();
6380
- import_schema5 = require("@abloatai/transaction/schema");
6472
+ import_schema4 = require("@abloatai/transaction/schema");
6381
6473
  init_readiness();
6382
6474
  }
6383
6475
  });
@@ -6709,7 +6801,16 @@ ${ambient}` : ""}`,
6709
6801
  walAlreadyLogical: walReady,
6710
6802
  provider,
6711
6803
  existingPublication,
6712
- inheritGrants
6804
+ inheritGrants,
6805
+ // Read off the connected admin rather than guessed from the hostname. A
6806
+ // role can only hand out an attribute it holds, and on RDS and Aurora
6807
+ // BYPASSRLS is reserved to `rdsadmin`, so the recipe substitutes explicit
6808
+ // SELECT policies for the reader.
6809
+ canGrantBypassRls: capability?.rolbypassrls === true,
6810
+ // Same rule, second attribute: RDS and Aurora keep REPLICATION on
6811
+ // rdsadmin and lend it as `rds_replication`, so the recipe grants that
6812
+ // role rather than setting an attribute this admin cannot pass on.
6813
+ canGrantReplication: capability?.rolreplication === true
6713
6814
  });
6714
6815
  const steps = buildPlan("scram-verifier");
6715
6816
  if (pubReconcile.removed.length > 0 || pubReconcile.recreated) {
@@ -6791,7 +6892,14 @@ ${ambient}` : ""}`,
6791
6892
  }
6792
6893
  const replicationProbe = await probeAsRole(
6793
6894
  replicationUrl,
6794
- (sql) => probeReadiness(sql, { coordinatedTables, schema: args.schema, publication })
6895
+ (sql) => probeReadiness(sql, {
6896
+ coordinatedTables,
6897
+ schema: args.schema,
6898
+ publication,
6899
+ // The reader may hold REPLICATION through the provider's role rather than
6900
+ // the attribute, which is the only shape available on RDS and Aurora.
6901
+ replicationGrantRole: replicationGrantRole(provider)
6902
+ })
6795
6903
  );
6796
6904
  const writeProbe = await probeAsRole(
6797
6905
  writeUrl,
@@ -7441,7 +7549,11 @@ ${ambient}` : ""}`,
7441
7549
  `);
7442
7550
  const replication = await probeAndReport(dbUrl, "replication", {
7443
7551
  schema: args.schema,
7444
- publication
7552
+ publication,
7553
+ // Derived from the host being dialled: where the provider lends REPLICATION
7554
+ // as a role rather than granting the attribute, membership is what the
7555
+ // reader actually holds.
7556
+ replicationGrantRole: replicationGrantRole(detectProvider(dbUrl))
7445
7557
  });
7446
7558
  console.log(`
7447
7559
  ${import_picocolors12.default.bold("Direct-write role")}
@@ -7734,6 +7846,7 @@ var init_connect = __esm({
7734
7846
  init_cjs_shims();
7735
7847
  import_errors11 = require("@abloatai/transaction/errors");
7736
7848
  import_picocolors12 = __toESM(require_picocolors(), 1);
7849
+ init_dbProvider();
7737
7850
  init_src();
7738
7851
  import_footprint3 = require("@abloatai/transaction/footprint");
7739
7852
  init_dbRole();
@@ -7980,7 +8093,7 @@ var require_util = __commonJS({
7980
8093
  return path;
7981
8094
  }
7982
8095
  exports2.normalize = normalize;
7983
- function join8(aRoot, aPath) {
8096
+ function join9(aRoot, aPath) {
7984
8097
  if (aRoot === "") {
7985
8098
  aRoot = ".";
7986
8099
  }
@@ -8012,7 +8125,7 @@ var require_util = __commonJS({
8012
8125
  }
8013
8126
  return joined;
8014
8127
  }
8015
- exports2.join = join8;
8128
+ exports2.join = join9;
8016
8129
  exports2.isAbsolute = function(aPath) {
8017
8130
  return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
8018
8131
  };
@@ -8185,7 +8298,7 @@ var require_util = __commonJS({
8185
8298
  parsed.path = parsed.path.substring(0, index + 1);
8186
8299
  }
8187
8300
  }
8188
- sourceURL = join8(urlGenerate(parsed), sourceURL);
8301
+ sourceURL = join9(urlGenerate(parsed), sourceURL);
8189
8302
  }
8190
8303
  return normalize(sourceURL);
8191
8304
  }
@@ -28205,9 +28318,9 @@ ${lanes.join("\n")}
28205
28318
  return getSpanOfTokenAtPosition(sourceFile, node.pos);
28206
28319
  }
28207
28320
  Debug.assert(!isJSDoc(errorNode));
28208
- const isMissing = nodeIsMissing(errorNode);
28209
- const pos = isMissing || isJsxText(node) ? errorNode.pos : skipTrivia(sourceFile.text, errorNode.pos);
28210
- if (isMissing) {
28321
+ const isMissing2 = nodeIsMissing(errorNode);
28322
+ const pos = isMissing2 || isJsxText(node) ? errorNode.pos : skipTrivia(sourceFile.text, errorNode.pos);
28323
+ if (isMissing2) {
28211
28324
  Debug.assert(pos === errorNode.pos, "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809");
28212
28325
  Debug.assert(pos === errorNode.end, "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809");
28213
28326
  } else {
@@ -132684,7 +132797,7 @@ ${lanes.join("\n")}
132684
132797
  }
132685
132798
  }
132686
132799
  function createImportCallExpressionAMD(arg, containsLexicalThis) {
132687
- const resolve10 = factory2.createUniqueName("resolve");
132800
+ const resolve11 = factory2.createUniqueName("resolve");
132688
132801
  const reject = factory2.createUniqueName("reject");
132689
132802
  const parameters = [
132690
132803
  factory2.createParameterDeclaration(
@@ -132693,7 +132806,7 @@ ${lanes.join("\n")}
132693
132806
  /*dotDotDotToken*/
132694
132807
  void 0,
132695
132808
  /*name*/
132696
- resolve10
132809
+ resolve11
132697
132810
  ),
132698
132811
  factory2.createParameterDeclaration(
132699
132812
  /*modifiers*/
@@ -132710,7 +132823,7 @@ ${lanes.join("\n")}
132710
132823
  factory2.createIdentifier("require"),
132711
132824
  /*typeArguments*/
132712
132825
  void 0,
132713
- [factory2.createArrayLiteralExpression([arg || factory2.createOmittedExpression()]), resolve10, reject]
132826
+ [factory2.createArrayLiteralExpression([arg || factory2.createOmittedExpression()]), resolve11, reject]
132714
132827
  )
132715
132828
  )
132716
132829
  ]);
@@ -172633,9 +172746,9 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
172633
172746
  const sourceFile = getValidSourceFile(fileName);
172634
172747
  const span = createTextSpanFromBounds(start, end);
172635
172748
  const formatContext = ts_formatting_exports.getFormatContext(formatOptions, host);
172636
- return flatMap(deduplicate(errorCodes68, equateValues, compareValues), (errorCode) => {
172749
+ return flatMap(deduplicate(errorCodes68, equateValues, compareValues), (errorCode2) => {
172637
172750
  cancellationToken.throwIfCancellationRequested();
172638
- return ts_codefix_exports.getFixes({ errorCode, sourceFile, span, program, host, cancellationToken, formatContext, preferences });
172751
+ return ts_codefix_exports.getFixes({ errorCode: errorCode2, sourceFile, span, program, host, cancellationToken, formatContext, preferences });
172639
172752
  });
172640
172753
  }
172641
172754
  function getCombinedCodeFix(scope, fixId56, formatOptions, preferences = emptyOptions) {
@@ -174473,8 +174586,8 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
174473
174586
  fixIds: [fixId2],
174474
174587
  errorCodes: errorCodes2,
174475
174588
  getCodeActions: function getCodeActionsToAddMissingAsync(context) {
174476
- const { sourceFile, errorCode, cancellationToken, program, span } = context;
174477
- const diagnostic = find(program.getTypeChecker().getDiagnostics(sourceFile, cancellationToken), getIsMatchingAsyncError(span, errorCode));
174589
+ const { sourceFile, errorCode: errorCode2, cancellationToken, program, span } = context;
174590
+ const diagnostic = find(program.getTypeChecker().getDiagnostics(sourceFile, cancellationToken), getIsMatchingAsyncError(span, errorCode2));
174478
174591
  const directSpan = diagnostic && diagnostic.relatedInformation && find(diagnostic.relatedInformation, (r2) => r2.code === Diagnostics.Did_you_mean_to_mark_this_function_as_async.code);
174479
174592
  const decl = getFixableErrorSpanDeclaration(sourceFile, directSpan);
174480
174593
  if (!decl) {
@@ -174536,8 +174649,8 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
174536
174649
  });
174537
174650
  return decl;
174538
174651
  }
174539
- function getIsMatchingAsyncError(span, errorCode) {
174540
- return ({ start, length: length2, relatedInformation, code }) => isNumber(start) && isNumber(length2) && textSpansEqual({ start, length: length2 }, span) && code === errorCode && !!relatedInformation && some(relatedInformation, (related) => related.code === Diagnostics.Did_you_mean_to_mark_this_function_as_async.code);
174652
+ function getIsMatchingAsyncError(span, errorCode2) {
174653
+ return ({ start, length: length2, relatedInformation, code }) => isNumber(start) && isNumber(length2) && textSpansEqual({ start, length: length2 }, span) && code === errorCode2 && !!relatedInformation && some(relatedInformation, (related) => related.code === Diagnostics.Did_you_mean_to_mark_this_function_as_async.code);
174541
174654
  }
174542
174655
  var fixId3 = "addMissingAwait";
174543
174656
  var propertyAccessCode = Diagnostics.Property_0_does_not_exist_on_type_1.code;
@@ -174568,16 +174681,16 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
174568
174681
  fixIds: [fixId3],
174569
174682
  errorCodes: errorCodes3,
174570
174683
  getCodeActions: function getCodeActionsToAddMissingAwait(context) {
174571
- const { sourceFile, errorCode, span, cancellationToken, program } = context;
174572
- const expression = getAwaitErrorSpanExpression(sourceFile, errorCode, span, cancellationToken, program);
174684
+ const { sourceFile, errorCode: errorCode2, span, cancellationToken, program } = context;
174685
+ const expression = getAwaitErrorSpanExpression(sourceFile, errorCode2, span, cancellationToken, program);
174573
174686
  if (!expression) {
174574
174687
  return;
174575
174688
  }
174576
174689
  const checker = context.program.getTypeChecker();
174577
174690
  const trackChanges = (cb) => ts_textChanges_exports.ChangeTracker.with(context, cb);
174578
174691
  return compact([
174579
- getDeclarationSiteFix(context, expression, errorCode, checker, trackChanges),
174580
- getUseSiteFix(context, expression, errorCode, checker, trackChanges)
174692
+ getDeclarationSiteFix(context, expression, errorCode2, checker, trackChanges),
174693
+ getUseSiteFix(context, expression, errorCode2, checker, trackChanges)
174581
174694
  ]);
174582
174695
  },
174583
174696
  getAllCodeActions: (context) => {
@@ -174594,18 +174707,18 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
174594
174707
  });
174595
174708
  }
174596
174709
  });
174597
- function getAwaitErrorSpanExpression(sourceFile, errorCode, span, cancellationToken, program) {
174710
+ function getAwaitErrorSpanExpression(sourceFile, errorCode2, span, cancellationToken, program) {
174598
174711
  const expression = getFixableErrorSpanExpression(sourceFile, span);
174599
- return expression && isMissingAwaitError(sourceFile, errorCode, span, cancellationToken, program) && isInsideAwaitableBody(expression) ? expression : void 0;
174712
+ return expression && isMissingAwaitError(sourceFile, errorCode2, span, cancellationToken, program) && isInsideAwaitableBody(expression) ? expression : void 0;
174600
174713
  }
174601
- function getDeclarationSiteFix(context, expression, errorCode, checker, trackChanges, fixedDeclarations) {
174714
+ function getDeclarationSiteFix(context, expression, errorCode2, checker, trackChanges, fixedDeclarations) {
174602
174715
  const { sourceFile, program, cancellationToken } = context;
174603
174716
  const awaitableInitializers = findAwaitableInitializers(expression, sourceFile, cancellationToken, program, checker);
174604
174717
  if (awaitableInitializers) {
174605
174718
  const initializerChanges = trackChanges((t) => {
174606
- forEach(awaitableInitializers.initializers, ({ expression: expression2 }) => makeChange3(t, errorCode, sourceFile, checker, expression2, fixedDeclarations));
174719
+ forEach(awaitableInitializers.initializers, ({ expression: expression2 }) => makeChange3(t, errorCode2, sourceFile, checker, expression2, fixedDeclarations));
174607
174720
  if (fixedDeclarations && awaitableInitializers.needsSecondPassForFixAll) {
174608
- makeChange3(t, errorCode, sourceFile, checker, expression, fixedDeclarations);
174721
+ makeChange3(t, errorCode2, sourceFile, checker, expression, fixedDeclarations);
174609
174722
  }
174610
174723
  });
174611
174724
  return createCodeFixActionWithoutFixAll(
@@ -174615,14 +174728,14 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
174615
174728
  );
174616
174729
  }
174617
174730
  }
174618
- function getUseSiteFix(context, expression, errorCode, checker, trackChanges, fixedDeclarations) {
174619
- const changes = trackChanges((t) => makeChange3(t, errorCode, context.sourceFile, checker, expression, fixedDeclarations));
174731
+ function getUseSiteFix(context, expression, errorCode2, checker, trackChanges, fixedDeclarations) {
174732
+ const changes = trackChanges((t) => makeChange3(t, errorCode2, context.sourceFile, checker, expression, fixedDeclarations));
174620
174733
  return createCodeFixAction(fixId3, changes, Diagnostics.Add_await, fixId3, Diagnostics.Fix_all_expressions_possibly_missing_await);
174621
174734
  }
174622
- function isMissingAwaitError(sourceFile, errorCode, span, cancellationToken, program) {
174735
+ function isMissingAwaitError(sourceFile, errorCode2, span, cancellationToken, program) {
174623
174736
  const checker = program.getTypeChecker();
174624
174737
  const diagnostics = checker.getDiagnostics(sourceFile, cancellationToken);
174625
- return some(diagnostics, ({ start, length: length2, relatedInformation, code }) => isNumber(start) && isNumber(length2) && textSpansEqual({ start, length: length2 }, span) && code === errorCode && !!relatedInformation && some(relatedInformation, (related) => related.code === Diagnostics.Did_you_forget_to_use_await.code));
174738
+ return some(diagnostics, ({ start, length: length2, relatedInformation, code }) => isNumber(start) && isNumber(length2) && textSpansEqual({ start, length: length2 }, span) && code === errorCode2 && !!relatedInformation && some(relatedInformation, (related) => related.code === Diagnostics.Did_you_forget_to_use_await.code));
174626
174739
  }
174627
174740
  function findAwaitableInitializers(expression, sourceFile, cancellationToken, program, checker) {
174628
174741
  const identifiers = getIdentifiersFromErrorSpanExpression(expression, checker);
@@ -174707,7 +174820,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
174707
174820
  function isInsideAwaitableBody(node) {
174708
174821
  return node.flags & 65536 || !!findAncestor(node, (ancestor) => ancestor.parent && isArrowFunction(ancestor.parent) && ancestor.parent.body === ancestor || isBlock(ancestor) && (ancestor.parent.kind === 262 || ancestor.parent.kind === 218 || ancestor.parent.kind === 219 || ancestor.parent.kind === 174));
174709
174822
  }
174710
- function makeChange3(changeTracker, errorCode, sourceFile, checker, insertionSite, fixedDeclarations) {
174823
+ function makeChange3(changeTracker, errorCode2, sourceFile, checker, insertionSite, fixedDeclarations) {
174711
174824
  if (isForOfStatement(insertionSite.parent) && !insertionSite.parent.awaitModifier) {
174712
174825
  const exprType = checker.getTypeAtLocation(insertionSite);
174713
174826
  const asyncIter = checker.getAnyAsyncIterableType();
@@ -174732,7 +174845,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
174732
174845
  const newNode = checker.getPromisedTypeOfPromise(type) ? factory.createAwaitExpression(side) : side;
174733
174846
  changeTracker.replaceNode(sourceFile, side, newNode);
174734
174847
  }
174735
- } else if (errorCode === propertyAccessCode && isPropertyAccessExpression(insertionSite.parent)) {
174848
+ } else if (errorCode2 === propertyAccessCode && isPropertyAccessExpression(insertionSite.parent)) {
174736
174849
  if (fixedDeclarations && isIdentifier2(insertionSite.parent.expression)) {
174737
174850
  const symbol = checker.getSymbolAtLocation(insertionSite.parent.expression);
174738
174851
  if (symbol && fixedDeclarations.has(getSymbolId(symbol))) {
@@ -174745,7 +174858,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
174745
174858
  factory.createParenthesizedExpression(factory.createAwaitExpression(insertionSite.parent.expression))
174746
174859
  );
174747
174860
  insertLeadingSemicolonIfNeeded(changeTracker, insertionSite.parent.expression, sourceFile);
174748
- } else if (contains(callableConstructableErrorCodes, errorCode) && isCallOrNewExpression(insertionSite.parent)) {
174861
+ } else if (contains(callableConstructableErrorCodes, errorCode2) && isCallOrNewExpression(insertionSite.parent)) {
174749
174862
  if (fixedDeclarations && isIdentifier2(insertionSite)) {
174750
174863
  const symbol = checker.getSymbolAtLocation(insertionSite);
174751
174864
  if (symbol && fixedDeclarations.has(getSymbolId(symbol))) {
@@ -177518,10 +177631,10 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
177518
177631
  registerCodeFix({
177519
177632
  errorCodes: errorCodes19,
177520
177633
  getCodeActions(context) {
177521
- const { errorCode, preferences, sourceFile, span, program } = context;
177634
+ const { errorCode: errorCode2, preferences, sourceFile, span, program } = context;
177522
177635
  const info = getFixInfos(
177523
177636
  context,
177524
- errorCode,
177637
+ errorCode2,
177525
177638
  span.start,
177526
177639
  /*useAutoImportProvider*/
177527
177640
  true
@@ -178459,14 +178572,14 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
178459
178572
  return { kind: 3, moduleSpecifierKind: void 0, moduleSpecifier, importKind, addAsTypeOnly, useRequire };
178460
178573
  }
178461
178574
  }
178462
- function getFixInfos(context, errorCode, pos, useAutoImportProvider) {
178575
+ function getFixInfos(context, errorCode2, pos, useAutoImportProvider) {
178463
178576
  const symbolToken = getTokenAtPosition(context.sourceFile, pos);
178464
178577
  let info;
178465
- if (errorCode === Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead.code) {
178578
+ if (errorCode2 === Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead.code) {
178466
178579
  info = getFixesInfoForUMDImport(context, symbolToken);
178467
178580
  } else if (!isIdentifier2(symbolToken)) {
178468
178581
  return void 0;
178469
- } else if (errorCode === Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type.code) {
178582
+ } else if (errorCode2 === Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type.code) {
178470
178583
  const symbolName2 = single(getSymbolNamesToImport(context.sourceFile, context.program.getTypeChecker(), symbolToken, context.program.getCompilerOptions()));
178471
178584
  const fix = getTypeOnlyPromotionFix(context.sourceFile, symbolToken, symbolName2, context.program);
178472
178585
  return fix && [{ fix, symbolName: symbolName2, errorIdentifierText: symbolToken.text }];
@@ -179296,11 +179409,11 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
179296
179409
  registerCodeFix({
179297
179410
  errorCodes: errorCodes21,
179298
179411
  getCodeActions: function getCodeActionsToFixOverrideModifierIssues(context) {
179299
- const { errorCode, span } = context;
179300
- const info = errorCodeFixIdMap[errorCode];
179412
+ const { errorCode: errorCode2, span } = context;
179413
+ const info = errorCodeFixIdMap[errorCode2];
179301
179414
  if (!info) return emptyArray;
179302
179415
  const { descriptions, fixId: fixId56, fixAllDescriptions } = info;
179303
- const changes = ts_textChanges_exports.ChangeTracker.with(context, (changes2) => dispatchChanges(changes2, context, errorCode, span.start));
179416
+ const changes = ts_textChanges_exports.ChangeTracker.with(context, (changes2) => dispatchChanges(changes2, context, errorCode2, span.start));
179304
179417
  return [
179305
179418
  createCodeFixActionMaybeFixAll(fixName, changes, descriptions, fixId56, fixAllDescriptions)
179306
179419
  ];
@@ -179315,8 +179428,8 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
179315
179428
  dispatchChanges(changes, context, code, start);
179316
179429
  })
179317
179430
  });
179318
- function dispatchChanges(changeTracker, context, errorCode, pos) {
179319
- switch (errorCode) {
179431
+ function dispatchChanges(changeTracker, context, errorCode2, pos) {
179432
+ switch (errorCode2) {
179320
179433
  case Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_a_member_in_the_base_class_0.code:
179321
179434
  case Diagnostics.This_member_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0.code:
179322
179435
  case Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_an_abstract_method_that_is_declared_in_the_base_class_0.code:
@@ -179329,7 +179442,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
179329
179442
  case Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_its_containing_class_0_does_not_extend_another_class.code:
179330
179443
  return doRemoveOverrideModifierChange(changeTracker, context.sourceFile, pos);
179331
179444
  default:
179332
- Debug.fail("Unexpected error code: " + errorCode);
179445
+ Debug.fail("Unexpected error code: " + errorCode2);
179333
179446
  }
179334
179447
  }
179335
179448
  function doAddOverrideModifierChange(changeTracker, sourceFile, pos) {
@@ -179702,8 +179815,8 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
179702
179815
  registerCodeFix({
179703
179816
  errorCodes: errorCodes26,
179704
179817
  getCodeActions(context) {
179705
- const { sourceFile, errorCode } = context;
179706
- const info = getInfo8(sourceFile, context.span.start, context, errorCode);
179818
+ const { sourceFile, errorCode: errorCode2 } = context;
179819
+ const info = getInfo8(sourceFile, context.span.start, context, errorCode2);
179707
179820
  if (!info) return void 0;
179708
179821
  const { node, suggestedSymbol } = info;
179709
179822
  const target = getEmitScriptTarget(context.host.getCompilationSettings());
@@ -179717,10 +179830,10 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
179717
179830
  if (info) doChange18(changes, context.sourceFile, info.node, info.suggestedSymbol, target);
179718
179831
  })
179719
179832
  });
179720
- function getInfo8(sourceFile, pos, context, errorCode) {
179833
+ function getInfo8(sourceFile, pos, context, errorCode2) {
179721
179834
  const node = getTokenAtPosition(sourceFile, pos);
179722
179835
  const parent2 = node.parent;
179723
- if ((errorCode === Diagnostics.No_overload_matches_this_call.code || errorCode === Diagnostics.Type_0_is_not_assignable_to_type_1.code) && !isJsxAttribute(parent2)) return void 0;
179836
+ if ((errorCode2 === Diagnostics.No_overload_matches_this_call.code || errorCode2 === Diagnostics.Type_0_is_not_assignable_to_type_1.code) && !isJsxAttribute(parent2)) return void 0;
179724
179837
  const checker = context.program.getTypeChecker();
179725
179838
  let suggestedSymbol;
179726
179839
  if (isPropertyAccessExpression(parent2) && parent2.name === node) {
@@ -179811,8 +179924,8 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
179811
179924
  errorCodes: errorCodes27,
179812
179925
  fixIds: [fixIdAddReturnStatement, fixRemoveBracesFromArrowFunctionBody, fixIdWrapTheBlockWithParen],
179813
179926
  getCodeActions: function getCodeActionsToCorrectReturnValue(context) {
179814
- const { program, sourceFile, span: { start }, errorCode } = context;
179815
- const info = getInfo9(program.getTypeChecker(), sourceFile, start, errorCode);
179927
+ const { program, sourceFile, span: { start }, errorCode: errorCode2 } = context;
179928
+ const info = getInfo9(program.getTypeChecker(), sourceFile, start, errorCode2);
179816
179929
  if (!info) return void 0;
179817
179930
  if (info.kind === 0) {
179818
179931
  return append(
@@ -179947,11 +180060,11 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
179947
180060
  }
179948
180061
  return checker.isTypeAssignableTo(exprType, type);
179949
180062
  }
179950
- function getInfo9(checker, sourceFile, position, errorCode) {
180063
+ function getInfo9(checker, sourceFile, position, errorCode2) {
179951
180064
  const node = getTokenAtPosition(sourceFile, position);
179952
180065
  if (!node.parent) return void 0;
179953
180066
  const declaration = findAncestor(node.parent, isFunctionLikeDeclaration);
179954
- switch (errorCode) {
180067
+ switch (errorCode2) {
179955
180068
  case Diagnostics.A_function_whose_declared_type_is_neither_undefined_void_nor_any_must_return_a_value.code:
179956
180069
  if (!declaration || !declaration.body || !declaration.type || !rangeContainsRange(declaration.type, node)) return void 0;
179957
180070
  return getFixInfo(
@@ -180146,11 +180259,11 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
180146
180259
  }));
180147
180260
  }
180148
180261
  });
180149
- function getInfo10(sourceFile, tokenPos, errorCode, checker, program) {
180262
+ function getInfo10(sourceFile, tokenPos, errorCode2, checker, program) {
180150
180263
  var _a, _b;
180151
180264
  const token = getTokenAtPosition(sourceFile, tokenPos);
180152
180265
  const parent2 = token.parent;
180153
- if (errorCode === Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code) {
180266
+ if (errorCode2 === Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code) {
180154
180267
  if (!(token.kind === 19 && isObjectLiteralExpression(parent2) && isCallExpression(parent2.parent))) return void 0;
180155
180268
  const argIndex = findIndex(parent2.parent.arguments, (arg) => arg === parent2);
180156
180269
  if (argIndex < 0) return void 0;
@@ -181007,10 +181120,10 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
181007
181120
  registerCodeFix({
181008
181121
  errorCodes: errorCodes31,
181009
181122
  getCodeActions: function getCodeActionsToFixNotFoundModule(context) {
181010
- const { host, sourceFile, span: { start }, errorCode } = context;
181011
- const packageName = errorCode === errorCannotFindImplicitJsxImport ? getJSXImplicitImportBase(context.program.getCompilerOptions(), sourceFile) : tryGetImportedPackageName(sourceFile, start);
181123
+ const { host, sourceFile, span: { start }, errorCode: errorCode2 } = context;
181124
+ const packageName = errorCode2 === errorCannotFindImplicitJsxImport ? getJSXImplicitImportBase(context.program.getCompilerOptions(), sourceFile) : tryGetImportedPackageName(sourceFile, start);
181012
181125
  if (packageName === void 0) return void 0;
181013
- const typesPackageName = getTypesPackageNameToInstall(packageName, host, errorCode);
181126
+ const typesPackageName = getTypesPackageNameToInstall(packageName, host, errorCode2);
181014
181127
  return typesPackageName === void 0 ? [] : [createCodeFixAction(
181015
181128
  fixName2,
181016
181129
  /*changes*/
@@ -181582,7 +181695,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
181582
181695
  registerCodeFix({
181583
181696
  errorCodes: errorCodes43,
181584
181697
  getCodeActions(context) {
181585
- const { errorCode, sourceFile, program, cancellationToken } = context;
181698
+ const { errorCode: errorCode2, sourceFile, program, cancellationToken } = context;
181586
181699
  const checker = program.getTypeChecker();
181587
181700
  const sourceFiles = program.getSourceFiles();
181588
181701
  const token = getTokenAtPosition(sourceFile, context.span.start);
@@ -181658,7 +181771,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
181658
181771
  result.push(createDeleteFix(deletion, [Diagnostics.Remove_unused_declaration_for_Colon_0, name.getText(sourceFile)]));
181659
181772
  }
181660
181773
  }
181661
- const prefix = ts_textChanges_exports.ChangeTracker.with(context, (t) => tryPrefixDeclaration(t, errorCode, sourceFile, token));
181774
+ const prefix = ts_textChanges_exports.ChangeTracker.with(context, (t) => tryPrefixDeclaration(t, errorCode2, sourceFile, token));
181662
181775
  if (prefix.length) {
181663
181776
  result.push(createCodeFixAction(fixName3, prefix, [Diagnostics.Prefix_0_with_an_underscore, token.getText(sourceFile)], fixIdPrefix, Diagnostics.Prefix_all_unused_declarations_with_where_possible));
181664
181777
  }
@@ -181784,8 +181897,8 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
181784
181897
  changes.delete(sourceFile, parent2);
181785
181898
  }
181786
181899
  }
181787
- function tryPrefixDeclaration(changes, errorCode, sourceFile, token) {
181788
- if (errorCode === Diagnostics.Property_0_is_declared_but_its_value_is_never_read.code) return;
181900
+ function tryPrefixDeclaration(changes, errorCode2, sourceFile, token) {
181901
+ if (errorCode2 === Diagnostics.Property_0_is_declared_but_its_value_is_never_read.code) return;
181789
181902
  if (token.kind === 140) {
181790
181903
  token = cast(token.parent, isInferTypeNode).typeParameter.name;
181791
181904
  }
@@ -181925,14 +182038,14 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
181925
182038
  fixIds: [fixId34],
181926
182039
  getAllCodeActions: (context) => codeFixAll(context, errorCodes44, (changes, diag2) => doChange27(changes, diag2.file, diag2.start, diag2.length, diag2.code))
181927
182040
  });
181928
- function doChange27(changes, sourceFile, start, length2, errorCode) {
182041
+ function doChange27(changes, sourceFile, start, length2, errorCode2) {
181929
182042
  const token = getTokenAtPosition(sourceFile, start);
181930
182043
  const statement = findAncestor(token, isStatement);
181931
182044
  if (statement.getStart(sourceFile) !== token.getStart(sourceFile)) {
181932
182045
  const logData = JSON.stringify({
181933
182046
  statementKind: Debug.formatSyntaxKind(statement.kind),
181934
182047
  tokenKind: Debug.formatSyntaxKind(token.kind),
181935
- errorCode,
182048
+ errorCode: errorCode2,
181936
182049
  start,
181937
182050
  length: length2
181938
182051
  });
@@ -183255,7 +183368,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
183255
183368
  registerCodeFix({
183256
183369
  errorCodes: errorCodes51,
183257
183370
  getCodeActions(context) {
183258
- const { sourceFile, program, span: { start }, errorCode, cancellationToken, host, preferences } = context;
183371
+ const { sourceFile, program, span: { start }, errorCode: errorCode2, cancellationToken, host, preferences } = context;
183259
183372
  const token = getTokenAtPosition(sourceFile, start);
183260
183373
  let declaration;
183261
183374
  const changes = ts_textChanges_exports.ChangeTracker.with(context, (changes2) => {
@@ -183263,7 +183376,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
183263
183376
  changes2,
183264
183377
  sourceFile,
183265
183378
  token,
183266
- errorCode,
183379
+ errorCode2,
183267
183380
  program,
183268
183381
  cancellationToken,
183269
183382
  /*markSeen*/
@@ -183273,7 +183386,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
183273
183386
  );
183274
183387
  });
183275
183388
  const name = declaration && getNameOfDeclaration(declaration);
183276
- return !name || changes.length === 0 ? void 0 : [createCodeFixAction(fixId40, changes, [getDiagnostic(errorCode, token), getTextOfNode(name)], fixId40, Diagnostics.Infer_all_types_from_usage)];
183389
+ return !name || changes.length === 0 ? void 0 : [createCodeFixAction(fixId40, changes, [getDiagnostic(errorCode2, token), getTextOfNode(name)], fixId40, Diagnostics.Infer_all_types_from_usage)];
183277
183390
  },
183278
183391
  fixIds: [fixId40],
183279
183392
  getAllCodeActions(context) {
@@ -183284,8 +183397,8 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
183284
183397
  });
183285
183398
  }
183286
183399
  });
183287
- function getDiagnostic(errorCode, token) {
183288
- switch (errorCode) {
183400
+ function getDiagnostic(errorCode2, token) {
183401
+ switch (errorCode2) {
183289
183402
  case Diagnostics.Parameter_0_implicitly_has_an_1_type.code:
183290
183403
  case Diagnostics.Parameter_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code:
183291
183404
  return isSetAccessorDeclaration(getContainingFunction(token)) ? Diagnostics.Infer_type_of_0_from_usage : Diagnostics.Infer_parameter_types_from_usage;
@@ -183299,8 +183412,8 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
183299
183412
  return Diagnostics.Infer_type_of_0_from_usage;
183300
183413
  }
183301
183414
  }
183302
- function mapSuggestionDiagnostic(errorCode) {
183303
- switch (errorCode) {
183415
+ function mapSuggestionDiagnostic(errorCode2) {
183416
+ switch (errorCode2) {
183304
183417
  case Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_but_a_better_type_may_be_inferred_from_usage.code:
183305
183418
  return Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined.code;
183306
183419
  case Diagnostics.Variable_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code:
@@ -183318,16 +183431,16 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
183318
183431
  case Diagnostics.Member_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code:
183319
183432
  return Diagnostics.Member_0_implicitly_has_an_1_type.code;
183320
183433
  }
183321
- return errorCode;
183434
+ return errorCode2;
183322
183435
  }
183323
- function doChange33(changes, sourceFile, token, errorCode, program, cancellationToken, markSeen, host, preferences) {
183436
+ function doChange33(changes, sourceFile, token, errorCode2, program, cancellationToken, markSeen, host, preferences) {
183324
183437
  if (!isParameterPropertyModifier(token.kind) && token.kind !== 80 && token.kind !== 26 && token.kind !== 110) {
183325
183438
  return void 0;
183326
183439
  }
183327
183440
  const { parent: parent2 } = token;
183328
183441
  const importAdder = createImportAdder(sourceFile, program, preferences, host);
183329
- errorCode = mapSuggestionDiagnostic(errorCode);
183330
- switch (errorCode) {
183442
+ errorCode2 = mapSuggestionDiagnostic(errorCode2);
183443
+ switch (errorCode2) {
183331
183444
  // Variable and Property declarations
183332
183445
  case Diagnostics.Member_0_implicitly_has_an_1_type.code:
183333
183446
  case Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined.code:
@@ -183368,7 +183481,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
183368
183481
  return void 0;
183369
183482
  }
183370
183483
  let declaration;
183371
- switch (errorCode) {
183484
+ switch (errorCode2) {
183372
183485
  // Parameter declarations
183373
183486
  case Diagnostics.Parameter_0_implicitly_has_an_1_type.code:
183374
183487
  if (isSetAccessorDeclaration(containingFunction)) {
@@ -183407,7 +183520,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
183407
183520
  }
183408
183521
  break;
183409
183522
  default:
183410
- return Debug.fail(String(errorCode));
183523
+ return Debug.fail(String(errorCode2));
183411
183524
  }
183412
183525
  importAdder.writeFixes(changes);
183413
183526
  return declaration;
@@ -219319,8 +219432,8 @@ Additional information: BADCLIENT: Bad error code, ${badCode} not found in range
219319
219432
  installPackage(options) {
219320
219433
  this.packageInstallId++;
219321
219434
  const request3 = { kind: "installPackage", ...options, id: this.packageInstallId };
219322
- const promise = new Promise((resolve10, reject) => {
219323
- (this.packageInstalledPromise ?? (this.packageInstalledPromise = /* @__PURE__ */ new Map())).set(this.packageInstallId, { resolve: resolve10, reject });
219435
+ const promise = new Promise((resolve11, reject) => {
219436
+ (this.packageInstalledPromise ?? (this.packageInstalledPromise = /* @__PURE__ */ new Map())).set(this.packageInstallId, { resolve: resolve11, reject });
219324
219437
  });
219325
219438
  this.installer.send(request3);
219326
219439
  return promise;
@@ -221621,7 +221734,7 @@ var require_path_browserify = __commonJS({
221621
221734
  }
221622
221735
  var posix = {
221623
221736
  // path.resolve([from ...], to)
221624
- resolve: function resolve10() {
221737
+ resolve: function resolve11() {
221625
221738
  var resolvedPath = "";
221626
221739
  var resolvedAbsolute = false;
221627
221740
  var cwd;
@@ -221668,7 +221781,7 @@ var require_path_browserify = __commonJS({
221668
221781
  assertPath(path);
221669
221782
  return path.length > 0 && path.charCodeAt(0) === 47;
221670
221783
  },
221671
- join: function join8() {
221784
+ join: function join9() {
221672
221785
  if (arguments.length === 0)
221673
221786
  return ".";
221674
221787
  var joined;
@@ -226521,41 +226634,41 @@ var require_queue = __commonJS({
226521
226634
  queue.drained = drained;
226522
226635
  return queue;
226523
226636
  function push2(value) {
226524
- var p2 = new Promise(function(resolve10, reject) {
226637
+ var p2 = new Promise(function(resolve11, reject) {
226525
226638
  pushCb(value, function(err, result) {
226526
226639
  if (err) {
226527
226640
  reject(err);
226528
226641
  return;
226529
226642
  }
226530
- resolve10(result);
226643
+ resolve11(result);
226531
226644
  });
226532
226645
  });
226533
226646
  p2.catch(noop3);
226534
226647
  return p2;
226535
226648
  }
226536
226649
  function unshift(value) {
226537
- var p2 = new Promise(function(resolve10, reject) {
226650
+ var p2 = new Promise(function(resolve11, reject) {
226538
226651
  unshiftCb(value, function(err, result) {
226539
226652
  if (err) {
226540
226653
  reject(err);
226541
226654
  return;
226542
226655
  }
226543
- resolve10(result);
226656
+ resolve11(result);
226544
226657
  });
226545
226658
  });
226546
226659
  p2.catch(noop3);
226547
226660
  return p2;
226548
226661
  }
226549
226662
  function drained() {
226550
- var p2 = new Promise(function(resolve10) {
226663
+ var p2 = new Promise(function(resolve11) {
226551
226664
  process.nextTick(function() {
226552
226665
  if (queue.idle()) {
226553
- resolve10();
226666
+ resolve11();
226554
226667
  } else {
226555
226668
  var previousDrain = queue.drain;
226556
226669
  queue.drain = function() {
226557
226670
  if (typeof previousDrain === "function") previousDrain();
226558
- resolve10();
226671
+ resolve11();
226559
226672
  queue.drain = previousDrain;
226560
226673
  };
226561
226674
  }
@@ -227052,9 +227165,9 @@ var require_stream3 = __commonJS({
227052
227165
  });
227053
227166
  }
227054
227167
  _getStat(filepath) {
227055
- return new Promise((resolve10, reject) => {
227168
+ return new Promise((resolve11, reject) => {
227056
227169
  this._stat(filepath, this._fsStatSettings, (error, stats) => {
227057
- return error === null ? resolve10(stats) : reject(error);
227170
+ return error === null ? resolve11(stats) : reject(error);
227058
227171
  });
227059
227172
  });
227060
227173
  }
@@ -227079,10 +227192,10 @@ var require_async5 = __commonJS({
227079
227192
  this._readerStream = new stream_1.default(this._settings);
227080
227193
  }
227081
227194
  dynamic(root, options) {
227082
- return new Promise((resolve10, reject) => {
227195
+ return new Promise((resolve11, reject) => {
227083
227196
  this._walkAsync(root, options, (error, entries) => {
227084
227197
  if (error === null) {
227085
- resolve10(entries);
227198
+ resolve11(entries);
227086
227199
  } else {
227087
227200
  reject(error);
227088
227201
  }
@@ -227092,10 +227205,10 @@ var require_async5 = __commonJS({
227092
227205
  async static(patterns, options) {
227093
227206
  const entries = [];
227094
227207
  const stream = this._readerStream.static(patterns, options);
227095
- return new Promise((resolve10, reject) => {
227208
+ return new Promise((resolve11, reject) => {
227096
227209
  stream.once("error", reject);
227097
227210
  stream.on("data", (entry) => entries.push(entry));
227098
- stream.once("end", () => resolve10(entries));
227211
+ stream.once("end", () => resolve11(entries));
227099
227212
  });
227100
227213
  }
227101
227214
  };
@@ -260001,12 +260114,12 @@ type XMLHttpRequestResponseType = "" | "arraybuffer" | "blob" | "document" | "js
260001
260114
  };
260002
260115
  var NodeRuntimeFileSystem = class {
260003
260116
  delete(path2) {
260004
- return new Promise((resolve10, reject) => {
260117
+ return new Promise((resolve11, reject) => {
260005
260118
  fs__namespace.rm(path2, { recursive: true }, (err) => {
260006
260119
  if (err)
260007
260120
  reject(err);
260008
260121
  else
260009
- resolve10();
260122
+ resolve11();
260010
260123
  });
260011
260124
  });
260012
260125
  }
@@ -260025,12 +260138,12 @@ type XMLHttpRequestResponseType = "" | "arraybuffer" | "blob" | "document" | "js
260025
260138
  }));
260026
260139
  }
260027
260140
  readFile(filePath, encoding = "utf-8") {
260028
- return new Promise((resolve10, reject) => {
260141
+ return new Promise((resolve11, reject) => {
260029
260142
  fs__namespace.readFile(filePath, encoding, (err, data) => {
260030
260143
  if (err)
260031
260144
  reject(err);
260032
260145
  else
260033
- resolve10(data);
260146
+ resolve11(data);
260034
260147
  });
260035
260148
  });
260036
260149
  }
@@ -260038,12 +260151,12 @@ type XMLHttpRequestResponseType = "" | "arraybuffer" | "blob" | "document" | "js
260038
260151
  return fs__namespace.readFileSync(filePath, encoding);
260039
260152
  }
260040
260153
  async writeFile(filePath, fileText) {
260041
- await new Promise((resolve10, reject) => {
260154
+ await new Promise((resolve11, reject) => {
260042
260155
  fs__namespace.writeFile(filePath, fileText, (err) => {
260043
260156
  if (err)
260044
260157
  reject(err);
260045
260158
  else
260046
- resolve10();
260159
+ resolve11();
260047
260160
  });
260048
260161
  });
260049
260162
  }
@@ -260057,12 +260170,12 @@ type XMLHttpRequestResponseType = "" | "arraybuffer" | "blob" | "document" | "js
260057
260170
  fs__namespace.mkdirSync(dirPath, { recursive: true });
260058
260171
  }
260059
260172
  move(srcPath, destPath) {
260060
- return new Promise((resolve10, reject) => {
260173
+ return new Promise((resolve11, reject) => {
260061
260174
  fs__namespace.rename(srcPath, destPath, (err) => {
260062
260175
  if (err)
260063
260176
  reject(err);
260064
260177
  else
260065
- resolve10();
260178
+ resolve11();
260066
260179
  });
260067
260180
  });
260068
260181
  }
@@ -260070,12 +260183,12 @@ type XMLHttpRequestResponseType = "" | "arraybuffer" | "blob" | "document" | "js
260070
260183
  fs__namespace.renameSync(srcPath, destPath);
260071
260184
  }
260072
260185
  copy(srcPath, destPath) {
260073
- return new Promise((resolve10, reject) => {
260186
+ return new Promise((resolve11, reject) => {
260074
260187
  fs__namespace.copyFile(srcPath, destPath, (err) => {
260075
260188
  if (err)
260076
260189
  reject(err);
260077
260190
  else
260078
- resolve10();
260191
+ resolve11();
260079
260192
  });
260080
260193
  });
260081
260194
  }
@@ -260083,15 +260196,15 @@ type XMLHttpRequestResponseType = "" | "arraybuffer" | "blob" | "document" | "js
260083
260196
  fs__namespace.copyFileSync(srcPath, destPath);
260084
260197
  }
260085
260198
  stat(path2) {
260086
- return new Promise((resolve10, reject) => {
260199
+ return new Promise((resolve11, reject) => {
260087
260200
  fs__namespace.stat(path2, (err, stat) => {
260088
260201
  if (err) {
260089
260202
  if (err.code === "ENOENT" || err.code === "ENOTDIR")
260090
- resolve10(void 0);
260203
+ resolve11(void 0);
260091
260204
  else
260092
260205
  reject(err);
260093
260206
  } else {
260094
- resolve10(stat);
260207
+ resolve11(stat);
260095
260208
  }
260096
260209
  });
260097
260210
  });
@@ -283768,7 +283881,7 @@ Node text: ${this.#forgottenText}`;
283768
283881
 
283769
283882
  // src/index.ts
283770
283883
  init_cjs_shims();
283771
- var import_picocolors31 = __toESM(require_picocolors(), 1);
283884
+ var import_picocolors32 = __toESM(require_picocolors(), 1);
283772
283885
 
283773
283886
  // src/migrate.ts
283774
283887
  init_cjs_shims();
@@ -283778,7 +283891,7 @@ var import_picocolors6 = __toESM(require_picocolors(), 1);
283778
283891
  var import_fs5 = require("fs");
283779
283892
  init_src();
283780
283893
  init_dbRole();
283781
- var import_schema3 = require("@abloatai/transaction/schema");
283894
+ var import_schema2 = require("@abloatai/transaction/schema");
283782
283895
  var import_source = require("@abloatai/transaction/source");
283783
283896
  init_push();
283784
283897
  var MIGRATE_USAGE = ` ablo migrate \u2014 create the tables your schema needs in your own database (DATABASE_URL)
@@ -283825,8 +283938,8 @@ function parseMigrateArgs(argv) {
283825
283938
  return { schemaPath, exportName, targetSchema, dryRun, outputFile };
283826
283939
  }
283827
283940
  function planFor(schema, targetSchema = "public") {
283828
- const schemaJson = JSON.parse((0, import_schema3.serializeSchema)(schema));
283829
- const plan = (0, import_schema3.generateProvisionPlan)(schemaJson, targetSchema, {
283941
+ const schemaJson = JSON.parse((0, import_schema2.serializeSchema)(schema));
283942
+ const plan = (0, import_schema2.generateProvisionPlan)(schemaJson, targetSchema, {
283830
283943
  foreignKeys: targetSchema === "public"
283831
283944
  });
283832
283945
  const adapterTables = (0, import_source.adapterTableMigrations)().map((m2) => m2.up);
@@ -283848,8 +283961,8 @@ async function applyStatements(dbUrl, targetSchema, statements, concurrent = [],
283848
283961
  } });
283849
283962
  const total = statements.length;
283850
283963
  const startedAt = Date.now();
283851
- const lockTimeout = (0, import_schema3.resolveDdlLockTimeout)();
283852
- const maxLockAttempts = (0, import_schema3.resolveDdlMaxLockAttempts)();
283964
+ const lockTimeout = (0, import_schema2.resolveDdlLockTimeout)();
283965
+ const maxLockAttempts = (0, import_schema2.resolveDdlMaxLockAttempts)();
283853
283966
  if (!observer.quiet) log.info("applying migration plan", { targetSchema, statements: total });
283854
283967
  try {
283855
283968
  for (let attempt = 1; ; attempt++) {
@@ -283863,7 +283976,7 @@ async function applyStatements(dbUrl, targetSchema, statements, concurrent = [],
283863
283976
  observer.onStatement?.(index + 1, total);
283864
283977
  } catch (err) {
283865
283978
  const pg = err ?? {};
283866
- if (pg.code === import_schema3.PG_LOCK_NOT_AVAILABLE) throw err;
283979
+ if (pg.code === import_schema2.PG_LOCK_NOT_AVAILABLE) throw err;
283867
283980
  log.error("migration plan failed", {
283868
283981
  code: "migration_failed",
283869
283982
  durationMs: Date.now() - startedAt,
@@ -283881,10 +283994,10 @@ async function applyStatements(dbUrl, targetSchema, statements, concurrent = [],
283881
283994
  break;
283882
283995
  } catch (err) {
283883
283996
  const pg = err ?? {};
283884
- if (pg.code === import_schema3.PG_LOCK_NOT_AVAILABLE && attempt < maxLockAttempts) {
283885
- const backoffMs = (0, import_schema3.ddlLockRetryBackoffMs)(attempt);
283997
+ if (pg.code === import_schema2.PG_LOCK_NOT_AVAILABLE && attempt < maxLockAttempts) {
283998
+ const backoffMs = (0, import_schema2.ddlLockRetryBackoffMs)(attempt);
283886
283999
  log.warn("schema change blocked by a lock; backing off and retrying", { targetSchema, attempt, backoffMs });
283887
- await new Promise((resolve10) => setTimeout(resolve10, backoffMs));
284000
+ await new Promise((resolve11) => setTimeout(resolve11, backoffMs));
283888
284001
  continue;
283889
284002
  }
283890
284003
  throw err;
@@ -284226,11 +284339,11 @@ function parseFeedbackArgs(argv) {
284226
284339
  const positional2 = [];
284227
284340
  let detail;
284228
284341
  let command;
284229
- let errorCode;
284342
+ let errorCode2;
284230
284343
  let from;
284231
284344
  let yes = false;
284232
284345
  let json = false;
284233
- const flagValue = (flag2, value) => {
284346
+ const flagValue2 = (flag2, value) => {
284234
284347
  if (value === void 0 || value.startsWith("--")) {
284235
284348
  throw new import_errors12.AbloValidationError(`\`${flag2}\` needs a value.`, {
284236
284349
  code: "cli_invalid_arguments"
@@ -284242,16 +284355,16 @@ function parseFeedbackArgs(argv) {
284242
284355
  const arg = argv[i];
284243
284356
  switch (arg) {
284244
284357
  case "--detail":
284245
- detail = flagValue("--detail", argv[++i]);
284358
+ detail = flagValue2("--detail", argv[++i]);
284246
284359
  break;
284247
284360
  case "--command":
284248
- command = flagValue("--command", argv[++i]);
284361
+ command = flagValue2("--command", argv[++i]);
284249
284362
  break;
284250
284363
  case "--error-code":
284251
- errorCode = flagValue("--error-code", argv[++i]);
284364
+ errorCode2 = flagValue2("--error-code", argv[++i]);
284252
284365
  break;
284253
284366
  case "--from":
284254
- from = flagValue("--from", argv[++i]);
284367
+ from = flagValue2("--from", argv[++i]);
284255
284368
  break;
284256
284369
  case "--yes":
284257
284370
  yes = true;
@@ -284286,7 +284399,7 @@ function parseFeedbackArgs(argv) {
284286
284399
  summary,
284287
284400
  ...detail !== void 0 ? { detail } : {},
284288
284401
  ...command !== void 0 ? { command } : {},
284289
- ...errorCode !== void 0 ? { errorCode } : {},
284402
+ ...errorCode2 !== void 0 ? { errorCode: errorCode2 } : {},
284290
284403
  ...from !== void 0 ? { from } : {},
284291
284404
  yes,
284292
284405
  json
@@ -284407,8 +284520,8 @@ init_controlPlane();
284407
284520
  init_config();
284408
284521
  var BRANCH_USAGE = `Usage:
284409
284522
  ablo branch list [--json]
284410
- ablo branch create <slug> [--from <id|slug>] [--kind dev|preview|test|long_lived] [--credential]
284411
- ablo branch ensure <slug> [--from <id|slug>] [--kind dev|preview|test|long_lived] [--credential]
284523
+ ablo branch create <slug> [--from <id|slug>] [--kind dev|preview|test|long_lived] [--hosted] [--credential]
284524
+ ablo branch ensure <slug> [--from <id|slug>] [--kind dev|preview|test|long_lived] [--hosted] [--credential]
284412
284525
  ablo branch credential <id|slug> [--ttl-hours <1-168>] [--json]
284413
284526
  ablo branch status <branch-id|slug> [--json]
284414
284527
  ablo branch check <branch-id|slug> [--json]
@@ -284421,7 +284534,7 @@ function requireKey2(explicit) {
284421
284534
  const key = explicit ?? resolveManagementKey();
284422
284535
  if (!key) {
284423
284536
  throw new Error(
284424
- "No project management credential. Run `npx ablo login` or set ABLO_MANAGEMENT_KEY."
284537
+ "No project management credential. Run `npx ablo login` or set ABLO_API_KEY to an mk_ credential."
284425
284538
  );
284426
284539
  }
284427
284540
  return key;
@@ -284561,7 +284674,8 @@ async function create(slug, argv, idempotent, context = {}) {
284561
284674
  slug: parsedSlug.data,
284562
284675
  ...parentId ? { parent_branch_id: parentId } : {},
284563
284676
  ...valueAfter(argv, "--kind") ? { kind: valueAfter(argv, "--kind") } : {},
284564
- ...valueAfter(argv, "--expires-at") ? { expires_at: valueAfter(argv, "--expires-at") } : {}
284677
+ ...valueAfter(argv, "--expires-at") ? { expires_at: valueAfter(argv, "--expires-at") } : {},
284678
+ ...argv.includes("--hosted") ? { storage: "hosted" } : {}
284565
284679
  }
284566
284680
  }, context);
284567
284681
  if (response.status !== 201) {
@@ -284659,29 +284773,118 @@ async function branches(argv) {
284659
284773
 
284660
284774
  // src/branchDev.ts
284661
284775
  init_cjs_shims();
284662
- var import_node_crypto5 = require("crypto");
284776
+ var import_node_crypto6 = require("crypto");
284663
284777
  var import_node_child_process = require("child_process");
284664
284778
  var import_branches2 = require("@abloatai/transaction/branches");
284665
- var import_errors14 = require("@abloatai/transaction/errors");
284779
+ var import_errors15 = require("@abloatai/transaction/errors");
284666
284780
  init_config();
284667
284781
  init_telemetry();
284668
284782
 
284669
284783
  // src/dev.ts
284670
284784
  init_cjs_shims();
284671
- var import_errors13 = require("@abloatai/transaction/errors");
284785
+ var import_errors14 = require("@abloatai/transaction/errors");
284672
284786
  var import_credentialPolicy2 = require("@abloatai/transaction/auth/credentialPolicy");
284673
284787
  var import_picocolors16 = __toESM(require_picocolors(), 1);
284674
284788
  init_dist2();
284675
284789
  var import_fs7 = require("fs");
284676
284790
  var import_path5 = require("path");
284677
- var import_schema6 = require("@abloatai/transaction/schema");
284791
+ var import_schema5 = require("@abloatai/transaction/schema");
284678
284792
  init_push();
284679
284793
  init_controlPlane();
284794
+ var import_wire8 = require("@abloatai/transaction/wire");
284680
284795
  init_config();
284681
284796
  init_readiness();
284682
284797
  init_theme();
284683
284798
  init_dbRole();
284684
284799
  var import_source3 = require("@abloatai/transaction/source");
284800
+
284801
+ // src/localConnectorLease.ts
284802
+ init_cjs_shims();
284803
+ var import_node_crypto5 = require("crypto");
284804
+ var import_node_fs3 = require("fs");
284805
+ var import_node_os2 = require("os");
284806
+ var import_node_path2 = require("path");
284807
+ var import_errors13 = require("@abloatai/transaction/errors");
284808
+ function acquireLocalConnectorLease(identity, options = {}) {
284809
+ const directory = options.directory ?? (0, import_node_path2.join)((0, import_node_os2.tmpdir)(), "ablo-source-connectors");
284810
+ const pid = options.pid ?? process.pid;
284811
+ const isProcessAlive = options.isProcessAlive ?? processIsAlive;
284812
+ const key = (0, import_node_crypto5.createHash)("sha256").update(`${(0, import_node_path2.resolve)(identity.cwd)}\0${identity.baseUrl}\0${identity.branch}`).digest("hex").slice(0, 24);
284813
+ const path = (0, import_node_path2.join)(directory, `${key}.lock`);
284814
+ const token = (0, import_node_crypto5.randomUUID)();
284815
+ const record = { pid, token };
284816
+ (0, import_node_fs3.mkdirSync)(directory, { recursive: true, mode: 448 });
284817
+ for (let attempt = 0; attempt < 2; attempt += 1) {
284818
+ try {
284819
+ const fd = (0, import_node_fs3.openSync)(path, "wx", 384);
284820
+ try {
284821
+ (0, import_node_fs3.writeFileSync)(fd, JSON.stringify(record));
284822
+ } finally {
284823
+ (0, import_node_fs3.closeSync)(fd);
284824
+ }
284825
+ let released = false;
284826
+ return {
284827
+ release() {
284828
+ if (released) return;
284829
+ released = true;
284830
+ try {
284831
+ const current = readLease(path);
284832
+ if (current?.token === token) (0, import_node_fs3.unlinkSync)(path);
284833
+ } catch {
284834
+ }
284835
+ }
284836
+ };
284837
+ } catch (error) {
284838
+ if (!isAlreadyExists(error)) throw error;
284839
+ const owner = readLease(path);
284840
+ if (owner && isProcessAlive(owner.pid)) {
284841
+ throw new import_errors13.AbloValidationError(
284842
+ `Another ablo dev --local process (PID ${owner.pid}) already owns this branch's local Data Source. Stop it before starting another connector.`,
284843
+ { code: "cli_invalid_arguments" }
284844
+ );
284845
+ }
284846
+ try {
284847
+ (0, import_node_fs3.unlinkSync)(path);
284848
+ } catch (unlinkError) {
284849
+ if (!isMissing(unlinkError)) throw unlinkError;
284850
+ }
284851
+ }
284852
+ }
284853
+ throw new import_errors13.AbloValidationError(
284854
+ "Could not acquire this branch's local Data Source connector lease. Retry after the other connector exits.",
284855
+ { code: "cli_invalid_arguments" }
284856
+ );
284857
+ }
284858
+ function readLease(path) {
284859
+ try {
284860
+ const parsed = JSON.parse((0, import_node_fs3.readFileSync)(path, "utf8"));
284861
+ return typeof parsed.pid === "number" && typeof parsed.token === "string" ? { pid: parsed.pid, token: parsed.token } : void 0;
284862
+ } catch {
284863
+ return void 0;
284864
+ }
284865
+ }
284866
+ function processIsAlive(pid) {
284867
+ try {
284868
+ process.kill(pid, 0);
284869
+ return true;
284870
+ } catch (error) {
284871
+ return !isNoSuchProcess(error);
284872
+ }
284873
+ }
284874
+ function errorCode(error) {
284875
+ return error && typeof error === "object" && "code" in error ? String(error.code) : void 0;
284876
+ }
284877
+ function isAlreadyExists(error) {
284878
+ return errorCode(error) === "EEXIST";
284879
+ }
284880
+ function isMissing(error) {
284881
+ return errorCode(error) === "ENOENT";
284882
+ }
284883
+ function isNoSuchProcess(error) {
284884
+ return errorCode(error) === "ESRCH";
284885
+ }
284886
+
284887
+ // src/dev.ts
284685
284888
  function parseDevArgs(argv) {
284686
284889
  let schemaPath = DEFAULT_SCHEMA_PATH;
284687
284890
  let exportName = DEFAULT_EXPORT;
@@ -284714,7 +284917,7 @@ function parseDevArgs(argv) {
284714
284917
  sourcePath = argv[++i] ?? sourcePath;
284715
284918
  break;
284716
284919
  default:
284717
- throw new import_errors13.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
284920
+ throw new import_errors14.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
284718
284921
  }
284719
284922
  }
284720
284923
  url = apiBaseUrl(url);
@@ -284732,7 +284935,7 @@ function parseDevArgs(argv) {
284732
284935
  async function loadLocalSourceHandler(sourcePath) {
284733
284936
  const abs = (0, import_path5.resolve)(process.cwd(), sourcePath);
284734
284937
  if (!(0, import_fs7.existsSync)(abs)) {
284735
- throw new import_errors13.AbloValidationError(
284938
+ throw new import_errors14.AbloValidationError(
284736
284939
  `local Data Source not found at ${import_picocolors16.default.bold(sourcePath)}. Add the signed Data Source handler described by ${import_picocolors16.default.bold("npx ablo docs data-sources")}, or pass ${import_picocolors16.default.bold("--source <path>")}.`,
284737
284940
  { code: "cli_invalid_arguments" }
284738
284941
  );
@@ -284743,7 +284946,7 @@ async function loadLocalSourceHandler(sourcePath) {
284743
284946
  const nested = mod.default && typeof mod.default === "object" ? mod.default : void 0;
284744
284947
  const handler = mod.POST ?? nested?.POST;
284745
284948
  if (typeof handler !== "function") {
284746
- throw new import_errors13.AbloValidationError(
284949
+ throw new import_errors14.AbloValidationError(
284747
284950
  `${import_picocolors16.default.bold(sourcePath)} must export a ${import_picocolors16.default.bold("POST(request)")} Data Source handler.`,
284748
284951
  { code: "cli_invalid_arguments" }
284749
284952
  );
@@ -284751,27 +284954,20 @@ async function loadLocalSourceHandler(sourcePath) {
284751
284954
  return handler;
284752
284955
  }
284753
284956
  async function registerLocalSource(args) {
284754
- const response = await fetch(`${args.url}/v1/datasources`, {
284957
+ await requestControlPlane({
284958
+ path: "/v1/datasources",
284755
284959
  method: "POST",
284756
- headers: {
284757
- authorization: `Bearer ${args.apiKey}`,
284758
- "content-type": "application/json"
284759
- },
284760
- body: JSON.stringify({
284960
+ ...args.apiKey ? { apiKey: args.apiKey } : {},
284961
+ baseUrl: args.url,
284962
+ body: {
284761
284963
  connection: "endpoint",
284762
284964
  endpoint: "http://localhost/ablo-dev/reverse-channel",
284763
284965
  signingKey: args.apiKey,
284764
284966
  reverseChannel: true,
284765
284967
  metadata: { managed_by: "ablo dev --local" }
284766
- })
284968
+ },
284969
+ responseSchema: import_wire8.datasourceSummarySchema
284767
284970
  });
284768
- if (!response.ok) {
284769
- const body = await response.text();
284770
- throw new import_errors13.AbloValidationError(
284771
- `Could not register the local Data Source (${response.status}): ${body}`,
284772
- { code: "cli_invalid_arguments" }
284773
- );
284774
- }
284775
284971
  }
284776
284972
  function classifyKey(apiKey) {
284777
284973
  if (!apiKey) {
@@ -284928,7 +285124,7 @@ async function dev(argv, runtime = {}) {
284928
285124
  else if (!args.apiKey) args.apiKey = resolveRuntimeApiKey("sandbox").key;
284929
285125
  if (runtime.branch) args.planeLabel = runtime.branch.slug;
284930
285126
  if (args.local && !args.watch) {
284931
- throw new import_errors13.AbloValidationError(
285127
+ throw new import_errors14.AbloValidationError(
284932
285128
  `${import_picocolors16.default.bold("--local")} opens a long-lived secure connector and cannot be combined with ${import_picocolors16.default.bold("--no-watch")}.`,
284933
285129
  { code: "cli_invalid_arguments" }
284934
285130
  );
@@ -284950,6 +285146,7 @@ async function dev(argv, runtime = {}) {
284950
285146
  );
284951
285147
  }
284952
285148
  let localAbort = null;
285149
+ let localLease = null;
284953
285150
  if (args.local) {
284954
285151
  process.env.ABLO_API_KEY = args.apiKey;
284955
285152
  if (!process.env.DATABASE_URL) {
@@ -284957,7 +285154,18 @@ async function dev(argv, runtime = {}) {
284957
285154
  if (databaseUrl) process.env.DATABASE_URL = databaseUrl.value;
284958
285155
  }
284959
285156
  const handler = await loadLocalSourceHandler(args.sourcePath);
284960
- await registerLocalSource(args);
285157
+ localLease = acquireLocalConnectorLease({
285158
+ cwd: process.cwd(),
285159
+ baseUrl: args.url,
285160
+ branch: args.planeLabel
285161
+ });
285162
+ try {
285163
+ await registerLocalSource(args);
285164
+ } catch (error) {
285165
+ localLease.release();
285166
+ localLease = null;
285167
+ throw error;
285168
+ }
284961
285169
  localAbort = new AbortController();
284962
285170
  const connector = (0, import_source3.createSourceConnector)({
284963
285171
  apiKey: args.apiKey,
@@ -284975,13 +285183,16 @@ async function dev(argv, runtime = {}) {
284975
285183
  });
284976
285184
  void connector.run(localAbort.signal).catch((error) => {
284977
285185
  console.error(import_picocolors16.default.red(` local connector stopped: ${error instanceof Error ? error.message : String(error)}`));
285186
+ }).finally(() => {
285187
+ localLease?.release();
285188
+ localLease = null;
284978
285189
  });
284979
285190
  console.log(` ${import_picocolors16.default.dim("source")} ${args.sourcePath} ${import_picocolors16.default.dim("(outbound connector; no public URL)")}`);
284980
285191
  }
284981
285192
  const schema = await loadSchema(args.schemaPath, args.exportName);
284982
285193
  const modelCount = Object.keys(schema.models).length;
284983
285194
  console.log(
284984
- ` ${import_picocolors16.default.dim("schema")} ${import_picocolors16.default.bold(args.schemaPath)} ${import_picocolors16.default.dim(`(${modelCount} models, hash ${(0, import_schema6.schemaHash)(schema)})`)}`
285195
+ ` ${import_picocolors16.default.dim("schema")} ${import_picocolors16.default.bold(args.schemaPath)} ${import_picocolors16.default.dim(`(${modelCount} models, hash ${(0, import_schema5.schemaHash)(schema)})`)}`
284985
285196
  );
284986
285197
  if (!runtime.branch) {
284987
285198
  console.log(` ${import_picocolors16.default.dim("key")} ${args.apiKey.slice(0, 12)}\u2026`);
@@ -284994,6 +285205,7 @@ async function dev(argv, runtime = {}) {
284994
285205
  s.stop(first.message, first.ok ? 0 : 1);
284995
285206
  if (!first.ok) {
284996
285207
  localAbort?.abort();
285208
+ localLease?.release();
284997
285209
  process.exit(1);
284998
285210
  }
284999
285211
  if (runtime.branch) {
@@ -285050,6 +285262,7 @@ async function dev(argv, runtime = {}) {
285050
285262
  const stop = () => {
285051
285263
  watcher.close();
285052
285264
  localAbort?.abort();
285265
+ localLease?.release();
285053
285266
  console.log(`
285054
285267
  ${import_picocolors16.default.dim("stopped.")}`);
285055
285268
  process.exit(0);
@@ -285079,7 +285292,7 @@ function parseBranchDevArgs(argv) {
285079
285292
  const arg = argv[index];
285080
285293
  if (!arg) continue;
285081
285294
  if (arg === "--no-branch") {
285082
- throw new import_errors14.AbloValidationError(
285295
+ throw new import_errors15.AbloValidationError(
285083
285296
  "--no-branch was removed: development is branch-isolated. Use --branch <slug> to select explicitly.",
285084
285297
  { code: "cli_invalid_arguments" }
285085
285298
  );
@@ -285087,7 +285300,7 @@ function parseBranchDevArgs(argv) {
285087
285300
  if (arg === "--branch") {
285088
285301
  branchSlug = argv[++index];
285089
285302
  if (!branchSlug) {
285090
- throw new import_errors14.AbloValidationError("--branch requires a slug", {
285303
+ throw new import_errors15.AbloValidationError("--branch requires a slug", {
285091
285304
  code: "cli_invalid_arguments"
285092
285305
  });
285093
285306
  }
@@ -285096,7 +285309,7 @@ function parseBranchDevArgs(argv) {
285096
285309
  if (arg === "--branch-ttl-hours") {
285097
285310
  const value = Number(argv[++index]);
285098
285311
  if (!Number.isInteger(value) || value < 1 || value > 168) {
285099
- throw new import_errors14.AbloValidationError("--branch-ttl-hours must be between 1 and 168", {
285312
+ throw new import_errors15.AbloValidationError("--branch-ttl-hours must be between 1 and 168", {
285100
285313
  code: "cli_invalid_arguments"
285101
285314
  });
285102
285315
  }
@@ -285114,12 +285327,12 @@ function parseBranchDevArgs(argv) {
285114
285327
  function branchSlugFromRef(ref) {
285115
285328
  const base = ref.normalize("NFKD").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
285116
285329
  if (!base) {
285117
- throw new import_errors14.AbloValidationError(`cannot derive an Ablo branch slug from "${ref}"`, {
285330
+ throw new import_errors15.AbloValidationError(`cannot derive an Ablo branch slug from "${ref}"`, {
285118
285331
  code: "cli_invalid_arguments"
285119
285332
  });
285120
285333
  }
285121
285334
  const nonRoot = base === "production" ? "production-dev" : base;
285122
- const shortened = nonRoot.length <= 40 ? nonRoot : `${nonRoot.slice(0, 31).replace(/-+$/g, "")}-${(0, import_node_crypto5.createHash)("sha256").update(nonRoot).digest("hex").slice(0, 8)}`;
285335
+ const shortened = nonRoot.length <= 40 ? nonRoot : `${nonRoot.slice(0, 31).replace(/-+$/g, "")}-${(0, import_node_crypto6.createHash)("sha256").update(nonRoot).digest("hex").slice(0, 8)}`;
285123
285336
  return import_branches2.branchSlugSchema.parse(shortened);
285124
285337
  }
285125
285338
  function gitBranch() {
@@ -285136,7 +285349,7 @@ function gitBranch() {
285136
285349
  function discoverBranchRef(explicit, env = process.env, readGitBranch = gitBranch) {
285137
285350
  const value = explicit ?? env.ABLO_BRANCH ?? env.GITHUB_HEAD_REF ?? env.GITHUB_REF_NAME ?? env.VERCEL_GIT_COMMIT_REF ?? env.CI_COMMIT_REF_NAME ?? readGitBranch();
285138
285351
  if (!value) {
285139
- throw new import_errors14.AbloValidationError(
285352
+ throw new import_errors15.AbloValidationError(
285140
285353
  "Could not determine the Git branch. Pass --branch <slug> or set ABLO_BRANCH.",
285141
285354
  { code: "cli_invalid_arguments" }
285142
285355
  );
@@ -285154,13 +285367,13 @@ async function runBranchDev(argv, dependencies = {}) {
285154
285367
  const slug = branchSlugFromRef(ref);
285155
285368
  const managementKey = dependencies.resolveManagementKey?.() ?? resolveManagementKey();
285156
285369
  if (!managementKey) {
285157
- throw new import_errors14.AbloValidationError(
285158
- "Creating a development branch needs a project management credential. Run `npx ablo login` or set ABLO_MANAGEMENT_KEY.",
285370
+ throw new import_errors15.AbloValidationError(
285371
+ "Creating a development branch needs a project management credential. Run `npx ablo login` or set ABLO_API_KEY to an mk_ credential.",
285159
285372
  { code: "cli_invalid_arguments" }
285160
285373
  );
285161
285374
  }
285162
285375
  if (!managementKey.startsWith("mk_")) {
285163
- throw new import_errors14.AbloValidationError(
285376
+ throw new import_errors15.AbloValidationError(
285164
285377
  "Branch creation needs the active project management credential (mk_\u2026). Run `npx ablo login` to refresh it.",
285165
285378
  { code: "cli_invalid_arguments" }
285166
285379
  );
@@ -285189,7 +285402,7 @@ async function runBranchDev(argv, dependencies = {}) {
285189
285402
  // src/whoami.ts
285190
285403
  init_cjs_shims();
285191
285404
  var import_picocolors17 = __toESM(require_picocolors(), 1);
285192
- var import_errors15 = require("@abloatai/transaction/errors");
285405
+ var import_errors16 = require("@abloatai/transaction/errors");
285193
285406
  init_config();
285194
285407
  init_controlPlane();
285195
285408
 
@@ -285264,7 +285477,7 @@ function parseWhoamiArgs(argv) {
285264
285477
  case "--key": {
285265
285478
  const value = argv[++i];
285266
285479
  if (!value || value.startsWith("--")) {
285267
- throw new import_errors15.AbloValidationError("`--key` needs a credential value.", {
285480
+ throw new import_errors16.AbloValidationError("`--key` needs a credential value.", {
285268
285481
  code: "cli_invalid_arguments"
285269
285482
  });
285270
285483
  }
@@ -285274,12 +285487,12 @@ function parseWhoamiArgs(argv) {
285274
285487
  case "--key-env": {
285275
285488
  const value = argv[++i];
285276
285489
  if (!value || value.startsWith("--")) {
285277
- throw new import_errors15.AbloValidationError("`--key-env` needs an environment variable name.", {
285490
+ throw new import_errors16.AbloValidationError("`--key-env` needs an environment variable name.", {
285278
285491
  code: "cli_invalid_arguments"
285279
285492
  });
285280
285493
  }
285281
285494
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {
285282
- throw new import_errors15.AbloValidationError(
285495
+ throw new import_errors16.AbloValidationError(
285283
285496
  `\`${value}\` is not a valid environment variable name.`,
285284
285497
  { code: "cli_invalid_arguments" }
285285
285498
  );
@@ -285288,13 +285501,13 @@ function parseWhoamiArgs(argv) {
285288
285501
  break;
285289
285502
  }
285290
285503
  default:
285291
- throw new import_errors15.AbloValidationError(`unknown whoami flag: ${arg}`, {
285504
+ throw new import_errors16.AbloValidationError(`unknown whoami flag: ${arg}`, {
285292
285505
  code: "cli_invalid_arguments"
285293
285506
  });
285294
285507
  }
285295
285508
  }
285296
285509
  if (key && keyEnv) {
285297
- throw new import_errors15.AbloValidationError("Choose one credential source: `--key` or `--key-env`.", {
285510
+ throw new import_errors16.AbloValidationError("Choose one credential source: `--key` or `--key-env`.", {
285298
285511
  code: "cli_invalid_arguments"
285299
285512
  });
285300
285513
  }
@@ -285305,7 +285518,7 @@ function selectWhoamiCredential(args, cwd = process.cwd()) {
285305
285518
  if (args.keyEnv) {
285306
285519
  const found = readProjectEnvVariable(args.keyEnv, cwd);
285307
285520
  if (!found) {
285308
- throw new import_errors15.AbloAuthenticationError(
285521
+ throw new import_errors16.AbloAuthenticationError(
285309
285522
  `${args.keyEnv} is not set in the process environment, .env.local, or .env.`,
285310
285523
  { code: "cli_api_key_missing" }
285311
285524
  );
@@ -285329,12 +285542,12 @@ function selectWhoamiCredential(args, cwd = process.cwd()) {
285329
285542
  if (managementKey) {
285330
285543
  return {
285331
285544
  key: managementKey,
285332
- source: process.env.ABLO_MANAGEMENT_KEY ? "env:ABLO_MANAGEMENT_KEY" : "stored login",
285333
- targetSource: process.env.ABLO_MANAGEMENT_KEY ? "env" : "stored"
285545
+ source: "stored login",
285546
+ targetSource: "stored"
285334
285547
  };
285335
285548
  }
285336
285549
  const ambient = ambientEnvKeyNote();
285337
- throw new import_errors15.AbloAuthenticationError(
285550
+ throw new import_errors16.AbloAuthenticationError(
285338
285551
  `No credential found. Run \`ablo login\`, set ABLO_API_KEY, or pass \`--key-env <NAME>\`.${ambient ? `
285339
285552
 
285340
285553
  ${ambient}` : ""}`,
@@ -285352,7 +285565,7 @@ async function whoami(argv) {
285352
285565
  });
285353
285566
  const confirmed = target.confirmed;
285354
285567
  if (!confirmed) {
285355
- throw new import_errors15.AbloAuthenticationError(
285568
+ throw new import_errors16.AbloAuthenticationError(
285356
285569
  "The server did not confirm an identity for this credential.",
285357
285570
  { code: "identity_resolve_failed" }
285358
285571
  );
@@ -285410,15 +285623,15 @@ init_push();
285410
285623
  // src/setup/run.ts
285411
285624
  init_cjs_shims();
285412
285625
  var import_picocolors19 = __toESM(require_picocolors(), 1);
285413
- var import_errors16 = require("@abloatai/transaction/errors");
285626
+ var import_errors17 = require("@abloatai/transaction/errors");
285414
285627
  init_theme();
285415
285628
 
285416
285629
  // src/setup/discover.ts
285417
285630
  init_cjs_shims();
285418
- var import_node_fs3 = require("fs");
285419
- var import_node_crypto6 = require("crypto");
285631
+ var import_node_fs4 = require("fs");
285632
+ var import_node_crypto7 = require("crypto");
285420
285633
  var import_node_child_process2 = require("child_process");
285421
- var import_node_path2 = require("path");
285634
+ var import_node_path3 = require("path");
285422
285635
  init_controlPlane();
285423
285636
  init_config();
285424
285637
 
@@ -286477,7 +286690,7 @@ function tryGit(cwd, args) {
286477
286690
  }
286478
286691
  }
286479
286692
  function resolveRepositoryRoot(cwd = process.cwd()) {
286480
- return (0, import_node_path2.resolve)(tryGit(cwd, ["rev-parse", "--show-toplevel"]) || cwd);
286693
+ return (0, import_node_path3.resolve)(tryGit(cwd, ["rev-parse", "--show-toplevel"]) || cwd);
286481
286694
  }
286482
286695
  function walkFiles(root, maxDepth = 5) {
286483
286696
  const files = [];
@@ -286486,13 +286699,13 @@ function walkFiles(root, maxDepth = 5) {
286486
286699
  const current = stack.pop();
286487
286700
  let entries;
286488
286701
  try {
286489
- entries = (0, import_node_fs3.readdirSync)(current.path, { withFileTypes: true });
286702
+ entries = (0, import_node_fs4.readdirSync)(current.path, { withFileTypes: true });
286490
286703
  } catch {
286491
286704
  continue;
286492
286705
  }
286493
286706
  for (const entry of entries.slice(0, 1e4)) {
286494
286707
  if (files.length >= MAX_DISCOVERY_FILES) break;
286495
- const path = (0, import_node_path2.join)(current.path, entry.name);
286708
+ const path = (0, import_node_path3.join)(current.path, entry.name);
286496
286709
  if (entry.isDirectory()) {
286497
286710
  if (current.depth < maxDepth && !IGNORED_DIRECTORIES.has(entry.name)) {
286498
286711
  stack.push({ path, depth: current.depth + 1 });
@@ -286506,9 +286719,9 @@ function walkFiles(root, maxDepth = 5) {
286506
286719
  }
286507
286720
  function readManifest(path) {
286508
286721
  try {
286509
- const parsed = JSON.parse((0, import_node_fs3.readFileSync)(path, "utf8"));
286722
+ const parsed = JSON.parse((0, import_node_fs4.readFileSync)(path, "utf8"));
286510
286723
  return {
286511
- root: (0, import_node_path2.resolve)(path, ".."),
286724
+ root: (0, import_node_path3.resolve)(path, ".."),
286512
286725
  name: typeof parsed.name === "string" ? parsed.name : null,
286513
286726
  dependencies: { ...parsed.dependencies, ...parsed.devDependencies },
286514
286727
  scripts: { ...parsed.scripts }
@@ -286518,14 +286731,14 @@ function readManifest(path) {
286518
286731
  }
286519
286732
  }
286520
286733
  function packageManifests(root, files) {
286521
- return files.filter((path) => (0, import_node_path2.basename)(path) === "package.json").flatMap((path) => {
286734
+ return files.filter((path) => (0, import_node_path3.basename)(path) === "package.json").flatMap((path) => {
286522
286735
  const manifest = readManifest(path);
286523
286736
  return manifest ? [manifest] : [];
286524
286737
  }).sort((a, b4) => a.root.localeCompare(b4.root));
286525
286738
  }
286526
286739
  function pathInside(root, target) {
286527
- const fromRoot = (0, import_node_path2.relative)(root, target);
286528
- return fromRoot === "" || fromRoot !== ".." && !fromRoot.startsWith(`..${import_node_path2.sep}`);
286740
+ const fromRoot = (0, import_node_path3.relative)(root, target);
286741
+ return fromRoot === "" || fromRoot !== ".." && !fromRoot.startsWith(`..${import_node_path3.sep}`);
286529
286742
  }
286530
286743
  function packageOwnedFiles(manifest, manifests, files) {
286531
286744
  const nestedPackageRoots = manifests.filter(({ root }) => root !== manifest.root && pathInside(manifest.root, root));
@@ -286583,8 +286796,8 @@ function detectedPersistence(manifest, files) {
286583
286796
  if (!SOURCE_EXTENSIONS.has(sourceExtension(path))) continue;
286584
286797
  let source;
286585
286798
  try {
286586
- if ((0, import_node_fs3.lstatSync)(path).size > MAX_SOURCE_BYTES) continue;
286587
- source = (0, import_node_fs3.readFileSync)(path, "utf8");
286799
+ if ((0, import_node_fs4.lstatSync)(path).size > MAX_SOURCE_BYTES) continue;
286800
+ source = (0, import_node_fs4.readFileSync)(path, "utf8");
286588
286801
  } catch {
286589
286802
  continue;
286590
286803
  }
@@ -286612,17 +286825,17 @@ function coordinationAdoptionReason(disposition, persistence) {
286612
286825
  }
286613
286826
  }
286614
286827
  function packageManager(root) {
286615
- if ((0, import_node_fs3.existsSync)((0, import_node_path2.join)(root, "pnpm-lock.yaml"))) return "pnpm";
286616
- if ((0, import_node_fs3.existsSync)((0, import_node_path2.join)(root, "yarn.lock"))) return "yarn";
286617
- if ((0, import_node_fs3.existsSync)((0, import_node_path2.join)(root, "bun.lockb")) || (0, import_node_fs3.existsSync)((0, import_node_path2.join)(root, "bun.lock"))) return "bun";
286828
+ if ((0, import_node_fs4.existsSync)((0, import_node_path3.join)(root, "pnpm-lock.yaml"))) return "pnpm";
286829
+ if ((0, import_node_fs4.existsSync)((0, import_node_path3.join)(root, "yarn.lock"))) return "yarn";
286830
+ if ((0, import_node_fs4.existsSync)((0, import_node_path3.join)(root, "bun.lockb")) || (0, import_node_fs4.existsSync)((0, import_node_path3.join)(root, "bun.lock"))) return "bun";
286618
286831
  return "npm";
286619
286832
  }
286620
286833
  function environmentKeyNames(root) {
286621
286834
  const names = [".env.local", ".env.development.local", ".env.development", ".env"];
286622
286835
  return names.flatMap((name) => {
286623
- const path = (0, import_node_path2.join)(root, name);
286624
- if (!(0, import_node_fs3.existsSync)(path)) return [];
286625
- const keys = (0, import_node_fs3.readFileSync)(path, "utf8").split(/\r?\n/).flatMap((line) => {
286836
+ const path = (0, import_node_path3.join)(root, name);
286837
+ if (!(0, import_node_fs4.existsSync)(path)) return [];
286838
+ const keys = (0, import_node_fs4.readFileSync)(path, "utf8").split(/\r?\n/).flatMap((line) => {
286626
286839
  const match = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/.exec(line);
286627
286840
  return match ? [match[1]] : [];
286628
286841
  });
@@ -286637,8 +286850,8 @@ function abloSourceFiles(root, files) {
286637
286850
  return files.flatMap((path) => {
286638
286851
  if (!SOURCE_EXTENSIONS.has(sourceExtension(path))) return [];
286639
286852
  try {
286640
- if ((0, import_node_fs3.lstatSync)(path).size > MAX_SOURCE_BYTES) return [];
286641
- return (0, import_node_fs3.readFileSync)(path, "utf8").includes("@abloatai/") ? [(0, import_node_path2.relative)(root, path) || "."] : [];
286853
+ if ((0, import_node_fs4.lstatSync)(path).size > MAX_SOURCE_BYTES) return [];
286854
+ return (0, import_node_fs4.readFileSync)(path, "utf8").includes("@abloatai/") ? [(0, import_node_path3.relative)(root, path) || "."] : [];
286642
286855
  } catch {
286643
286856
  return [];
286644
286857
  }
@@ -286665,12 +286878,12 @@ function discoverMutationSites(root, files) {
286665
286878
  if (!SOURCE_EXTENSIONS.has(sourceExtension(path))) continue;
286666
286879
  let source;
286667
286880
  try {
286668
- if ((0, import_node_fs3.lstatSync)(path).size > MAX_SOURCE_BYTES) continue;
286669
- source = (0, import_node_fs3.readFileSync)(path, "utf8");
286881
+ if ((0, import_node_fs4.lstatSync)(path).size > MAX_SOURCE_BYTES) continue;
286882
+ source = (0, import_node_fs4.readFileSync)(path, "utf8");
286670
286883
  } catch {
286671
286884
  continue;
286672
286885
  }
286673
- const locator = (0, import_node_path2.relative)(root, path) || ".";
286886
+ const locator = (0, import_node_path3.relative)(root, path) || ".";
286674
286887
  for (const match of source.matchAll(/\b(?:(?:[A-Za-z_$][\w$]*)\.query|query|q)\s*\(\s*(?:`|['"])\s*(INSERT\s+INTO|UPDATE|DELETE\s+FROM)\s+([A-Za-z_$][\w$.[\]"`]*|"[^"]+"|`[^`]+`)/gi)) {
286675
286888
  const rawTable = match[2] ?? "";
286676
286889
  const modelHint = rawTable.replace(/["`\[\]]/g, "").split(".").at(-1)?.toLowerCase() || null;
@@ -286702,13 +286915,13 @@ function discoverMutationSites(root, files) {
286702
286915
  return sites.sort((a, b4) => a.path.localeCompare(b4.path) || a.line - b4.line);
286703
286916
  }
286704
286917
  function isProductionMutationFile(root, path) {
286705
- const locator = (0, import_node_path2.relative)(root, path).replaceAll("\\", "/");
286918
+ const locator = (0, import_node_path3.relative)(root, path).replaceAll("\\", "/");
286706
286919
  return !/(?:^|\/)(?:test|tests|__tests__|scripts)(?:\/|$)/.test(locator) && !/\.(?:test|spec)\.[cm]?[jt]sx?$/.test(locator);
286707
286920
  }
286708
286921
  function digestFile(path) {
286709
- if (!(0, import_node_fs3.existsSync)(path)) return null;
286922
+ if (!(0, import_node_fs4.existsSync)(path)) return null;
286710
286923
  try {
286711
- return (0, import_node_crypto6.createHash)("sha256").update((0, import_node_fs3.readFileSync)(path)).digest("hex");
286924
+ return (0, import_node_crypto7.createHash)("sha256").update((0, import_node_fs4.readFileSync)(path)).digest("hex");
286712
286925
  } catch {
286713
286926
  return null;
286714
286927
  }
@@ -286739,7 +286952,7 @@ function localDiscoveryStep(state) {
286739
286952
  const appFiles = selected ? packageOwnedFiles(selected, state.packageManifests, files) : files.filter((path) => pathInside(envRoot, path));
286740
286953
  const persistence = selected ? detectedPersistence(selected, appFiles) : [];
286741
286954
  const coordinationAdoption = coordinationAdoptionDisposition(persistence);
286742
- const excludedNestedPackages = selected ? state.packageManifests.filter(({ root: packageRoot2 }) => packageRoot2 !== selected.root && pathInside(selected.root, packageRoot2)).map(({ root: packageRoot2, name }) => ({ root: (0, import_node_path2.relative)(root, packageRoot2), name })) : [];
286955
+ const excludedNestedPackages = selected ? state.packageManifests.filter(({ root: packageRoot2 }) => packageRoot2 !== selected.root && pathInside(selected.root, packageRoot2)).map(({ root: packageRoot2, name }) => ({ root: (0, import_node_path3.relative)(root, packageRoot2), name })) : [];
286743
286956
  const mutationSites = discoverMutationSites(
286744
286957
  envRoot,
286745
286958
  appFiles.filter((path) => isProductionMutationFile(envRoot, path))
@@ -286752,17 +286965,17 @@ function localDiscoveryStep(state) {
286752
286965
  if (!SOURCE_EXTENSIONS.has(sourceExtension(path))) continue;
286753
286966
  let source;
286754
286967
  try {
286755
- if ((0, import_node_fs3.lstatSync)(path).size > MAX_SOURCE_BYTES) continue;
286756
- source = (0, import_node_fs3.readFileSync)(path, "utf8");
286968
+ if ((0, import_node_fs4.lstatSync)(path).size > MAX_SOURCE_BYTES) continue;
286969
+ source = (0, import_node_fs4.readFileSync)(path, "utf8");
286757
286970
  } catch {
286758
286971
  continue;
286759
286972
  }
286760
286973
  databaseColumns.push(...discoverDatabaseColumnsFromSqlSource({
286761
- path: (0, import_node_path2.relative)(envRoot, path),
286974
+ path: (0, import_node_path3.relative)(envRoot, path),
286762
286975
  source
286763
286976
  }));
286764
286977
  transactionalRequirements.push(...discoverTransactionalRequirementsFromSqlSource({
286765
- path: (0, import_node_path2.relative)(envRoot, path),
286978
+ path: (0, import_node_path3.relative)(envRoot, path),
286766
286979
  source
286767
286980
  }));
286768
286981
  }
@@ -286794,8 +287007,8 @@ function localDiscoveryStep(state) {
286794
287007
  "src/app/providers.tsx",
286795
287008
  "app/api/ablo-session/route.ts",
286796
287009
  "src/app/api/ablo-session/route.ts"
286797
- ].filter((path) => (0, import_node_fs3.existsSync)((0, import_node_path2.join)(envRoot, path)));
286798
- const localSchemaPath = [(0, import_node_path2.join)(envRoot, "ablo", "schema.ts"), (0, import_node_path2.join)(envRoot, "src", "ablo", "schema.ts")].find((path) => (0, import_node_fs3.existsSync)(path)) ?? (0, import_node_path2.join)(envRoot, "ablo", "schema.ts");
287010
+ ].filter((path) => (0, import_node_fs4.existsSync)((0, import_node_path3.join)(envRoot, path)));
287011
+ const localSchemaPath = [(0, import_node_path3.join)(envRoot, "ablo", "schema.ts"), (0, import_node_path3.join)(envRoot, "src", "ablo", "schema.ts")].find((path) => (0, import_node_fs4.existsSync)(path)) ?? (0, import_node_path3.join)(envRoot, "ablo", "schema.ts");
286799
287012
  state.localSchemaDigest = digestFile(localSchemaPath);
286800
287013
  const facts = [
286801
287014
  fact("repository.root", root, "git", tryGit(root, ["rev-parse", "--show-toplevel"]) ? "Resolved from Git." : "No Git root was available; using the requested directory.", root),
@@ -286804,9 +287017,9 @@ function localDiscoveryStep(state) {
286804
287017
  fact("repository.dirtyPathCount", dirtyEntries.length, "git", "Count from porcelain status; path names are intentionally omitted.", root),
286805
287018
  fact("repository.scanTruncated", files.length >= MAX_DISCOVERY_FILES, "filesystem", `Scanned at most ${MAX_DISCOVERY_FILES} files to depth 5.`, root),
286806
287019
  fact("package.manager", packageManager(root), "filesystem", "Detected from the repository lockfile.", root),
286807
- fact("application.candidates", candidates.map(({ manifest, frameworks, dataAccess, runtimeEntrypoint }) => ({ root: (0, import_node_path2.relative)(root, manifest.root) || ".", name: manifest.name, frameworks, dataAccess, runtimeEntrypoint })), "package_manifest", `${candidates.length} runnable application candidate(s) found.`, root),
286808
- fact("application.selectedRoot", state.applicationRoot ? (0, import_node_path2.relative)(root, state.applicationRoot) || "." : null, "inference", state.applicationRoot ? "Exactly one usable application root was selected." : "Application selection is ambiguous.", root, state.applicationRoot ? "high" : "low"),
286809
- fact("application.packageName", state.packageName, "package_manifest", "Read from the selected package manifest.", state.applicationRoot ? (0, import_node_path2.join)((0, import_node_path2.relative)(root, state.applicationRoot), "package.json") : "package.json"),
287020
+ fact("application.candidates", candidates.map(({ manifest, frameworks, dataAccess, runtimeEntrypoint }) => ({ root: (0, import_node_path3.relative)(root, manifest.root) || ".", name: manifest.name, frameworks, dataAccess, runtimeEntrypoint })), "package_manifest", `${candidates.length} runnable application candidate(s) found.`, root),
287021
+ fact("application.selectedRoot", state.applicationRoot ? (0, import_node_path3.relative)(root, state.applicationRoot) || "." : null, "inference", state.applicationRoot ? "Exactly one usable application root was selected." : "Application selection is ambiguous.", root, state.applicationRoot ? "high" : "low"),
287022
+ fact("application.packageName", state.packageName, "package_manifest", "Read from the selected package manifest.", state.applicationRoot ? (0, import_node_path3.join)((0, import_node_path3.relative)(root, state.applicationRoot), "package.json") : "package.json"),
286810
287023
  fact("application.frameworks", selected ? selectedFrameworks : candidates.flatMap(({ frameworks }) => frameworks), "package_manifest", "Detected only from declared package dependencies.", root),
286811
287024
  fact("application.kinds", selectedApplicationKinds, "package_manifest", "Detected from runtime scripts and declared framework or database dependencies.", root),
286812
287025
  fact("application.excludedNestedPackages", excludedNestedPackages, "package_manifest", "Independently manifested nested packages are excluded from the selected package's lexical mutation inventory; an agent may still follow application imports across that boundary.", root),
@@ -286827,16 +287040,16 @@ function localDiscoveryStep(state) {
286827
287040
  fact("application.databaseSchemaEvidence", uniqueDatabaseColumns, "filesystem", "Conservative database-column evidence derived from application-owned CREATE TABLE statements. Database catalogs remain authoritative.", envRoot, "medium"),
286828
287041
  fact("application.transactionalRequirements", uniqueRequirements, "filesystem", "Transaction shapes whose atomic predicates or exact RETURNING rows must be preserved.", envRoot, "medium"),
286829
287042
  fact("application.compatibilityDisposition", state.compatibility, "inference", "Compared database and transaction evidence with the current canonical Ablo contracts.", envRoot, uniqueDatabaseColumns.length > 0 ? "medium" : "low"),
286830
- fact("application.localSchemaDigest", state.localSchemaDigest, "filesystem", state.localSchemaDigest ? "SHA-256 of the local schema source file." : "No local ablo/schema.ts was found.", (0, import_node_path2.relative)(root, localSchemaPath))
287043
+ fact("application.localSchemaDigest", state.localSchemaDigest, "filesystem", state.localSchemaDigest ? "SHA-256 of the local schema source file." : "No local ablo/schema.ts was found.", (0, import_node_path3.relative)(root, localSchemaPath))
286831
287044
  ];
286832
287045
  const applicationChoices = candidates.map(({ manifest, frameworks, dataAccess }) => ({
286833
- value: (0, import_node_path2.relative)(root, manifest.root) || ".",
286834
- label: manifest.name ?? ((0, import_node_path2.relative)(root, manifest.root) || "."),
287046
+ value: (0, import_node_path3.relative)(root, manifest.root) || ".",
287047
+ label: manifest.name ?? ((0, import_node_path3.relative)(root, manifest.root) || "."),
286835
287048
  consequence: `Setup will modify only this ${[...frameworks, ...dataAccess].join("/")} application.`
286836
287049
  }));
286837
- if (state.applicationRoot && !applicationChoices.some(({ value }) => value === ((0, import_node_path2.relative)(root, state.applicationRoot) || "."))) {
287050
+ if (state.applicationRoot && !applicationChoices.some(({ value }) => value === ((0, import_node_path3.relative)(root, state.applicationRoot) || "."))) {
286838
287051
  applicationChoices.push({
286839
- value: (0, import_node_path2.relative)(root, state.applicationRoot) || ".",
287052
+ value: (0, import_node_path3.relative)(root, state.applicationRoot) || ".",
286840
287053
  label: state.packageName ?? ".",
286841
287054
  consequence: "Setup will treat this package as the application root; framework support remains unconfirmed."
286842
287055
  });
@@ -286847,7 +287060,7 @@ function localDiscoveryStep(state) {
286847
287060
  question: "Which application should Ablo set up?",
286848
287061
  status: state.applicationRoot ? "resolved" : "unresolved",
286849
287062
  choices: applicationChoices,
286850
- ...state.applicationRoot ? { selected: (0, import_node_path2.relative)(root, state.applicationRoot) || "." } : {},
287063
+ ...state.applicationRoot ? { selected: (0, import_node_path3.relative)(root, state.applicationRoot) || "." } : {},
286851
287064
  reason: state.applicationRoot ? dataApplications.length === 1 ? "Exactly one runnable package owns database access, so it is the coordination boundary." : runtimeOwners.length === 1 ? "Exactly one package owns a concrete runtime entrypoint, so it is the application boundary." : "The repository has one unambiguous application target." : "More than one or no runnable application was identified."
286852
287065
  },
286853
287066
  {
@@ -287197,7 +287410,7 @@ function parseSetupArgs(args) {
287197
287410
  if (arg === "--root") {
287198
287411
  const next = args[index + 1];
287199
287412
  if (!next || next.startsWith("-")) {
287200
- throw new import_errors16.AbloValidationError("`--root` requires a directory.", {
287413
+ throw new import_errors17.AbloValidationError("`--root` requires a directory.", {
287201
287414
  code: "cli_invalid_arguments"
287202
287415
  });
287203
287416
  }
@@ -287206,7 +287419,7 @@ function parseSetupArgs(args) {
287206
287419
  continue;
287207
287420
  }
287208
287421
  if (!allowedFlags.has(arg)) {
287209
- throw new import_errors16.AbloValidationError(`Unknown setup option: ${arg}`, {
287422
+ throw new import_errors17.AbloValidationError(`Unknown setup option: ${arg}`, {
287210
287423
  code: "cli_invalid_arguments"
287211
287424
  });
287212
287425
  }
@@ -287292,7 +287505,7 @@ function renderHumanPlan(plan) {
287292
287505
  async function runSetup(args) {
287293
287506
  const options = parseSetupArgs(args);
287294
287507
  if (options.json && !options.plan) {
287295
- throw new import_errors16.AbloValidationError(
287508
+ throw new import_errors17.AbloValidationError(
287296
287509
  "`--json` is a plan renderer. Use `ablo setup --plan --json`.",
287297
287510
  { code: "cli_invalid_arguments" }
287298
287511
  );
@@ -287306,11 +287519,13 @@ async function runSetup(args) {
287306
287519
  }
287307
287520
 
287308
287521
  // src/commands.ts
287522
+ init_theme();
287309
287523
  var CORE_GROUPS = ["Start", "Every day", "More"];
287310
287524
  var FULL_GROUPS = [
287311
287525
  "Set up",
287312
287526
  "Your database",
287313
287527
  "Your schema",
287528
+ "Your writes",
287314
287529
  "Read the docs",
287315
287530
  "See what's happening",
287316
287531
  "Workspace"
@@ -287349,8 +287564,8 @@ var COMMANDS = [
287349
287564
  full: {
287350
287565
  group: "Set up",
287351
287566
  rows: [
287352
- { run: "login", does: "Authorize in your browser \u2014 stores one mk_ management credential" },
287353
- { run: "login --project <slug>", does: "Same, for one project \u2014 it becomes active" }
287567
+ { run: "login", does: "Authorize in your browser, pick a project \u2014 stores its mk_ management credential" },
287568
+ { run: "login --project <slug>", does: "Same, without the picker \u2014 the named project becomes active" }
287354
287569
  ]
287355
287570
  }
287356
287571
  },
@@ -287441,6 +287656,28 @@ var COMMANDS = [
287441
287656
  ]
287442
287657
  }
287443
287658
  },
287659
+ {
287660
+ name: "claims",
287661
+ core: {
287662
+ group: "Every day",
287663
+ does: "Say what you are editing, so another writer waits instead of clobbering it"
287664
+ },
287665
+ full: {
287666
+ group: "Your writes",
287667
+ rows: [
287668
+ { run: "claims acquire <model> <id>", does: "Take the lease on one row" },
287669
+ { run: "claims acquire <model> <id> -- <cmd>", does: "Hold it only while <cmd> runs, then release" },
287670
+ { run: "claims acquire <model> <id> --queue", does: "Wait in line when it is held, instead of failing" },
287671
+ { run: "claims acquire <model> <id> --ttl 5m", does: "Lease length: 30s, 5m, 2h (default 60s)" },
287672
+ { run: "claims acquire <model> <id> --description <t>", does: "What you are doing, shown to whoever waits" },
287673
+ { run: "claims release <model> <id>", does: "Give the lease back" },
287674
+ { run: "claims heartbeat <model> <id>", does: "Extend a lease you already hold" },
287675
+ { run: "claims list [<model> [<id>]]", does: "Who holds what, and who waits" },
287676
+ { run: "claims list --actor <id>", does: "Narrow a listing to one holder" },
287677
+ { run: "claims list --json", does: "Same, machine-readable" }
287678
+ ]
287679
+ }
287680
+ },
287444
287681
  {
287445
287682
  name: "generate",
287446
287683
  full: {
@@ -287586,7 +287823,9 @@ var REDIRECTS = /* @__PURE__ */ new Map([
287586
287823
  ["disconnect", "connect deregister"],
287587
287824
  ["deregister", "connect deregister"],
287588
287825
  ["register", "connect register"],
287589
- ["rotate", "connect rotate"]
287826
+ ["rotate", "connect rotate"],
287827
+ ["claim", "claims acquire"],
287828
+ ["release", "claims release"]
287590
287829
  ]);
287591
287830
  function editDistance(a, b4) {
287592
287831
  const cols = b4.length + 1;
@@ -287623,7 +287862,22 @@ function suggestCommand(raw) {
287623
287862
  return REDIRECTS.get(best.name) ?? best.name;
287624
287863
  }
287625
287864
  function usageFor(name) {
287626
- return BY_NAME.get(name)?.usage;
287865
+ const command = BY_NAME.get(name);
287866
+ if (command === void 0) return void 0;
287867
+ if (command.usage !== void 0) return command.usage;
287868
+ const rows = command.full?.rows ?? [];
287869
+ const described = rows.filter((row) => row.does !== void 0);
287870
+ if (described.length === 0) return void 0;
287871
+ const width = Math.max(...described.map((row) => row.run.length)) + 2;
287872
+ const headline = command.core?.does;
287873
+ return [
287874
+ ` ${brand(`ablo ${name}`)}${headline !== void 0 ? ` \u2014 ${headline}` : ""}`,
287875
+ "",
287876
+ ...rows.map(
287877
+ (row) => row.does === void 0 ? ` ${row.run}` : ` ablo ${row.run.padEnd(width)}${row.does}`
287878
+ ),
287879
+ ""
287880
+ ].join("\n");
287627
287881
  }
287628
287882
  function coreRows(group) {
287629
287883
  return ALL.filter((c) => c.core?.group === group).map((c) => ({
@@ -287636,16 +287890,16 @@ function fullRows(group) {
287636
287890
  }
287637
287891
 
287638
287892
  // src/index.ts
287639
- var import_errors25 = require("@abloatai/transaction/errors");
287893
+ var import_errors26 = require("@abloatai/transaction/errors");
287640
287894
  init_push();
287641
287895
 
287642
287896
  // src/generate.ts
287643
287897
  init_cjs_shims();
287644
- var import_errors17 = require("@abloatai/transaction/errors");
287898
+ var import_errors18 = require("@abloatai/transaction/errors");
287645
287899
  var import_fs8 = require("fs");
287646
287900
  var import_path6 = require("path");
287647
287901
  var import_picocolors20 = __toESM(require_picocolors(), 1);
287648
- var import_schema7 = require("@abloatai/transaction/schema");
287902
+ var import_schema6 = require("@abloatai/transaction/schema");
287649
287903
  init_push();
287650
287904
  var DEFAULT_SCHEMA_PATH4 = "ablo/schema.ts";
287651
287905
  var DEFAULT_EXPORT3 = "schema";
@@ -287667,7 +287921,7 @@ function parseGenerateArgs(argv) {
287667
287921
  out = argv[++i] ?? out;
287668
287922
  break;
287669
287923
  default:
287670
- throw new import_errors17.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
287924
+ throw new import_errors18.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
287671
287925
  }
287672
287926
  }
287673
287927
  return { schemaPath, exportName, out };
@@ -287683,8 +287937,8 @@ async function generate(argv) {
287683
287937
  let source;
287684
287938
  try {
287685
287939
  const schema = await loadSchema(args.schemaPath, args.exportName);
287686
- const schemaJson = JSON.parse((0, import_schema7.serializeSchema)(schema));
287687
- source = (0, import_schema7.generateTypes)(schemaJson);
287940
+ const schemaJson = JSON.parse((0, import_schema6.serializeSchema)(schema));
287941
+ source = (0, import_schema6.generateTypes)(schemaJson);
287688
287942
  } catch (err) {
287689
287943
  console.error(import_picocolors20.default.red(` ${err instanceof Error ? err.message : String(err)}`));
287690
287944
  process.exit(1);
@@ -287700,9 +287954,10 @@ init_cjs_shims();
287700
287954
  var import_child_process2 = require("child_process");
287701
287955
  var import_picocolors21 = __toESM(require_picocolors(), 1);
287702
287956
  init_dist2();
287703
- var import_errors18 = require("@abloatai/transaction/errors");
287704
- var import_wire8 = require("@abloatai/transaction/wire");
287957
+ var import_errors19 = require("@abloatai/transaction/errors");
287958
+ var import_wire9 = require("@abloatai/transaction/wire");
287705
287959
  init_config();
287960
+ init_projects();
287706
287961
  init_theme();
287707
287962
  var CLIENT_ID = "ablo-cli";
287708
287963
  var stripSlash = (u2) => u2.replace(/\/+$/, "");
@@ -287728,11 +287983,52 @@ function parseSlugFlag(argv, flag2) {
287728
287983
  const eq = argv.find((a) => a.startsWith(`${flag2}=`));
287729
287984
  return eq ? eq.slice(flag2.length + 1) || void 0 : void 0;
287730
287985
  }
287986
+ function projectSlugOrDefault(slug) {
287987
+ return slug === DEFAULT_PROFILE ? void 0 : slug;
287988
+ }
287989
+ async function listProjectsForSession(accessToken) {
287990
+ const res = await fetch(`${DASHBOARD_URL}/api/cli/projects`, {
287991
+ headers: { authorization: `Bearer ${accessToken}`, accept: "application/json" }
287992
+ }).catch(() => null);
287993
+ if (!res) return { ok: false, reason: `${DASHBOARD_URL} could not be reached` };
287994
+ return projectListResult(res.status, await res.json().catch(() => null));
287995
+ }
287996
+ async function pickProject(accessToken) {
287997
+ const active = getActiveProject();
287998
+ const s = Y2();
287999
+ s.start("Listing projects\u2026");
288000
+ const listed = await listProjectsForSession(accessToken);
288001
+ if (!listed.ok) {
288002
+ const fallback = projectSlugOrDefault(active?.slug);
288003
+ s.stop(
288004
+ `Couldn't list projects (${listed.reason}); continuing with ${fallback ? `project ${import_picocolors21.default.bold(fallback)}` : "the organization default"}.`
288005
+ );
288006
+ return fallback;
288007
+ }
288008
+ if (listed.projects.every((p2) => p2.default)) {
288009
+ s.stop("One project, the organization default.");
288010
+ return void 0;
288011
+ }
288012
+ s.stop(`${listed.projects.length} projects`);
288013
+ const current = active ? listed.projects.find((p2) => p2.id === active.id) : void 0;
288014
+ const choice = await ve({
288015
+ message: "Project",
288016
+ options: listed.projects.map((p2) => {
288017
+ const hint = projectDisplayName(p2) ?? (p2.default ? "organization default" : void 0);
288018
+ return { value: p2, label: p2.slug, ...hint ? { hint } : {} };
288019
+ }),
288020
+ ...current ? { initialValue: current } : {}
288021
+ });
288022
+ if (pD(choice)) {
288023
+ xe("Cancelled.");
288024
+ process.exit(0);
288025
+ }
288026
+ return choice.default ? void 0 : choice.slug;
288027
+ }
287731
288028
  async function deviceLogin(argv, deps = {}) {
287732
288029
  const openUrl = deps.openUrl ?? openBrowser;
287733
288030
  Ie(`${brand("ablo")} login`);
287734
- const requested = parseSlugFlag(argv, "--project") ?? getActiveProject()?.slug;
287735
- const targetProject = requested === DEFAULT_PROFILE ? void 0 : requested;
288031
+ const flagged = parseSlugFlag(argv, "--project");
287736
288032
  const targetOrg = parseSlugFlag(argv, "--org");
287737
288033
  const interactive = Boolean(process.stdout.isTTY && process.stdin.isTTY);
287738
288034
  let account = "login";
@@ -287811,30 +288107,33 @@ ${import_picocolors21.default.dim(url)}`, "Approve in your browser");
287811
288107
  s.stop("Timed out waiting for approval.");
287812
288108
  process.exit(1);
287813
288109
  }
287814
- s.message(
288110
+ s.stop("Approved.");
288111
+ const targetProject = flagged !== void 0 ? projectSlugOrDefault(flagged) : interactive ? await pickProject(accessToken) : projectSlugOrDefault(getActiveProject()?.slug);
288112
+ const mint = Y2();
288113
+ mint.start(
287815
288114
  targetProject ? `Provisioning project access for ${targetProject}\u2026` : "Provisioning project access\u2026"
287816
288115
  );
287817
288116
  const provRes = await fetch(`${DASHBOARD_URL}/api/cli/provision-key`, {
287818
288117
  method: "POST",
287819
288118
  headers: { authorization: `Bearer ${accessToken}`, "content-type": "application/json" },
287820
- // Scope the minted keys to the chosen project (`--project`/active), with
287821
- // the device_code as a legacy fallback for the /cli picker. Both harmless
287822
- // if absent → org-default keys.
288119
+ // Scope the minted keys to the chosen project, with the device_code as a
288120
+ // legacy fallback for the /cli picker. Both harmless if absent →
288121
+ // org-default keys.
287823
288122
  body: JSON.stringify({
287824
288123
  device_code: code.device_code,
287825
288124
  ...targetProject ? { project_slug: targetProject } : {}
287826
288125
  })
287827
288126
  }).catch(() => null);
287828
288127
  if (!provRes) {
287829
- s.stop("Could not provision a key.");
288128
+ mint.stop("Could not provision a key.");
287830
288129
  M2.error(
287831
288130
  `Could not reach ${DASHBOARD_URL} to finish the handoff. Check your connection and run \`ablo login\` again.`
287832
288131
  );
287833
288132
  process.exit(1);
287834
288133
  }
287835
288134
  if (!provRes.ok) {
287836
- s.stop("Could not provision a key.");
287837
- const err = (0, import_errors18.translateHttpError)(
288135
+ mint.stop("Could not provision a key.");
288136
+ const err = (0, import_errors19.translateHttpError)(
287838
288137
  provRes.status,
287839
288138
  await provRes.json().catch(() => null),
287840
288139
  provRes.headers.get("x-request-id") ?? void 0
@@ -287851,11 +288150,11 @@ ${import_picocolors21.default.dim(url)}`, "Approve in your browser");
287851
288150
  }
287852
288151
  process.exit(1);
287853
288152
  }
287854
- const parsedProv = import_wire8.provisionKeyResponseSchema.safeParse(
288153
+ const parsedProv = import_wire9.provisionKeyResponseSchema.safeParse(
287855
288154
  await provRes.json().catch(() => null)
287856
288155
  );
287857
288156
  if (!parsedProv.success) {
287858
- s.stop("Could not provision a key.");
288157
+ mint.stop("Could not provision a key.");
287859
288158
  M2.error("The key handoff returned something this version does not recognize.");
287860
288159
  M2.error(`Try again, or upgrade with ${import_picocolors21.default.bold("npm i -g @abloatai/ablo")}.`);
287861
288160
  process.exit(1);
@@ -287880,7 +288179,7 @@ ${import_picocolors21.default.dim(url)}`, "Approve in your browser");
287880
288179
  },
287881
288180
  { mode: "sandbox", activeProject: prov.project ?? void 0 }
287882
288181
  );
287883
- s.stop(`Saved project credential to ${path}`);
288182
+ mint.stop(`Saved project credential to ${path}`);
287884
288183
  const orgLabel = prov.organizationSlug ? ` to ${import_picocolors21.default.bold(prov.organizationSlug)}` : "";
287885
288184
  const where = prov.project ? ` ${import_picocolors21.default.dim(`(project ${prov.project.slug})`)}` : "";
287886
288185
  Se(
@@ -287897,10 +288196,10 @@ function logout() {
287897
288196
  } else {
287898
288197
  console.log(` ${import_picocolors21.default.dim("\u25CB")} Not logged in \u2014 nothing to remove.`);
287899
288198
  }
287900
- if (process.env.ABLO_MANAGEMENT_KEY) {
288199
+ if (process.env.ABLO_API_KEY?.startsWith("mk_")) {
287901
288200
  console.log(
287902
288201
  import_picocolors21.default.dim(
287903
- ` Note: ${import_picocolors21.default.bold("ABLO_MANAGEMENT_KEY")} is still set in this shell and takes precedence.`
288202
+ ` Note: ${import_picocolors21.default.bold("ABLO_API_KEY")} still contains an ${import_picocolors21.default.bold("mk_")} credential in this shell and takes precedence.`
287904
288203
  )
287905
288204
  );
287906
288205
  }
@@ -287916,7 +288215,6 @@ init_config();
287916
288215
  init_target();
287917
288216
  init_theme();
287918
288217
  init_controlPlane();
287919
- var import_schema8 = require("@abloatai/transaction/coordination/schema");
287920
288218
  init_readiness();
287921
288219
  function expiryLabel(iso) {
287922
288220
  const ms = Date.parse(iso) - Date.now();
@@ -287939,13 +288237,6 @@ async function ping2(apiUrl3) {
287939
288237
  clearTimeout(t);
287940
288238
  }
287941
288239
  }
287942
- function formatConflict(conflict) {
287943
- if (!conflict) return "";
287944
- const parts = import_schema8.participantKindSchema.options.flatMap(
287945
- (k3) => conflict[k3] ? [`${k3}:${conflict[k3]}`] : []
287946
- );
287947
- return parts.length ? `{${parts.join(",")}}` : "";
287948
- }
287949
288240
  function printTargetLines(target, localProject, storedOrganizationId, storedOrganizationSlug) {
287950
288241
  const confirmed = target?.confirmed ?? null;
287951
288242
  const org = confirmed?.organizationId ?? storedOrganizationId;
@@ -288166,9 +288457,7 @@ async function status(args = []) {
288166
288457
  );
288167
288458
  for (const m2 of pushed.models) {
288168
288459
  const tn = m2.typename === m2.key ? import_picocolors22.default.dim(`typename=${m2.typename}`) : import_picocolors22.default.yellow(`typename=${m2.typename}`);
288169
- const conflict = formatConflict(m2.conflict);
288170
- const conflictStr2 = conflict ? ` ${import_picocolors22.default.dim(`conflict=${conflict}`)}` : "";
288171
- console.log(` ${import_picocolors22.default.dim("\u2022")} ${m2.key.padEnd(14)} ${tn}${conflictStr2}`);
288460
+ console.log(` ${import_picocolors22.default.dim("\u2022")} ${m2.key.padEnd(14)} ${tn}`);
288172
288461
  }
288173
288462
  } else if (pushed && !pushed.active) {
288174
288463
  console.log(
@@ -288210,8 +288499,8 @@ async function status(args = []) {
288210
288499
 
288211
288500
  // src/logs.ts
288212
288501
  init_cjs_shims();
288213
- var import_errors19 = require("@abloatai/transaction/errors");
288214
- var import_wire9 = require("@abloatai/transaction/wire");
288502
+ var import_errors20 = require("@abloatai/transaction/errors");
288503
+ var import_wire10 = require("@abloatai/transaction/wire");
288215
288504
  var import_picocolors23 = __toESM(require_picocolors(), 1);
288216
288505
  init_config();
288217
288506
  init_theme();
@@ -288252,12 +288541,12 @@ function parseLogsArgs(argv) {
288252
288541
  args.json = true;
288253
288542
  break;
288254
288543
  case "--mode":
288255
- throw new import_errors19.AbloValidationError(
288544
+ throw new import_errors20.AbloValidationError(
288256
288545
  "--mode was removed. Logs follow the branch bound to ABLO_API_KEY; select a different branch by supplying its key.",
288257
288546
  { code: "cli_invalid_arguments" }
288258
288547
  );
288259
288548
  default:
288260
- throw new import_errors19.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
288549
+ throw new import_errors20.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
288261
288550
  }
288262
288551
  }
288263
288552
  return args;
@@ -288322,7 +288611,7 @@ async function logs(argv) {
288322
288611
  const json = await res.json();
288323
288612
  return {
288324
288613
  events: json.data ?? json.events ?? [],
288325
- cursor: json.next_cursor ?? (json.cursor != null ? (0, import_wire9.formatFeedCursor)({ log: json.cursor, claims: 0 }) : (0, import_wire9.formatFeedCursor)(import_wire9.FEED_CURSOR_START))
288614
+ cursor: json.next_cursor ?? (json.cursor != null ? (0, import_wire10.formatFeedCursor)({ log: json.cursor, claims: 0 }) : (0, import_wire10.formatFeedCursor)(import_wire10.FEED_CURSOR_START))
288326
288615
  };
288327
288616
  }
288328
288617
  if (!args.json) {
@@ -288354,9 +288643,9 @@ async function logs(argv) {
288354
288643
  });
288355
288644
  if (!page) continue;
288356
288645
  for (const e2 of page.events) render2(e2, args.json);
288357
- const prev = (0, import_wire9.parseFeedCursor)(cursor);
288358
- const next = (0, import_wire9.parseFeedCursor)(page.cursor);
288359
- if (prev && next && (0, import_wire9.feedCursorAdvanced)(prev, next)) cursor = page.cursor;
288646
+ const prev = (0, import_wire10.parseFeedCursor)(cursor);
288647
+ const next = (0, import_wire10.parseFeedCursor)(page.cursor);
288648
+ if (prev && next && (0, import_wire10.feedCursorAdvanced)(prev, next)) cursor = page.cursor;
288360
288649
  }
288361
288650
  }
288362
288651
 
@@ -288536,10 +288825,10 @@ async function webhooks(argv) {
288536
288825
 
288537
288826
  // src/check.ts
288538
288827
  init_cjs_shims();
288539
- var import_errors20 = require("@abloatai/transaction/errors");
288828
+ var import_errors21 = require("@abloatai/transaction/errors");
288540
288829
  var import_picocolors25 = __toESM(require_picocolors(), 1);
288541
288830
  init_src();
288542
- var import_schema9 = require("@abloatai/transaction/schema");
288831
+ var import_schema8 = require("@abloatai/transaction/schema");
288543
288832
  init_push();
288544
288833
 
288545
288834
  // src/schemaIr.ts
@@ -288614,14 +288903,15 @@ function emitSchemaSource(schema, importPath) {
288614
288903
 
288615
288904
  // src/schemaSource.ts
288616
288905
  init_cjs_shims();
288906
+ var import_schema7 = require("@abloatai/transaction/schema");
288617
288907
  var TENANCY_COLUMN = "organization_id";
288618
- var BASE_FIELDS = /* @__PURE__ */ new Set(["id", "organizationId", "createdBy", "createdAt", "updatedAt"]);
288908
+ var BASE_FIELDS = /* @__PURE__ */ new Set([
288909
+ ...import_schema7.BASE_FIELDS,
288910
+ "organizationId"
288911
+ ]);
288619
288912
  var BASE_COLUMNS = /* @__PURE__ */ new Set([
288620
- "id",
288621
- "organization_id",
288622
- "created_by",
288623
- "created_at",
288624
- "updated_at"
288913
+ ...import_schema7.BASE_FIELDS.map(camelToSnake),
288914
+ TENANCY_COLUMN
288625
288915
  ]);
288626
288916
  function fieldNameForColumn(column) {
288627
288917
  const camel2 = column.replace(/_([a-z0-9])/g, (_3, c) => c.toUpperCase());
@@ -288684,7 +288974,7 @@ function parseCheckArgs(argv) {
288684
288974
  appSchema = argv[++i] ?? appSchema;
288685
288975
  break;
288686
288976
  default:
288687
- throw new import_errors20.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
288977
+ throw new import_errors21.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
288688
288978
  }
288689
288979
  }
288690
288980
  return { schemaPath, exportName, appSchema };
@@ -288766,7 +289056,10 @@ async function check(argv) {
288766
289056
  process.exit(1);
288767
289057
  }
288768
289058
  const schema = await loadSchema(args.schemaPath, args.exportName);
288769
- const schemaJson = JSON.parse((0, import_schema9.serializeSchema)(schema));
289059
+ const schemaJson = JSON.parse((0, import_schema8.serializeSchema)(schema));
289060
+ const accessFindings = new Map(
289061
+ (0, import_schema8.auditSchemaAccessPolicies)(schemaJson).map((finding) => [finding.model, finding])
289062
+ );
288770
289063
  console.log(`
288771
289064
  ${brand("ablo")} ${import_picocolors25.default.dim("check")} ${import_picocolors25.default.dim(`schema "${args.appSchema}"`)}
288772
289065
  `);
@@ -288807,8 +289100,14 @@ async function check(argv) {
288807
289100
  }
288808
289101
  const problems = [];
288809
289102
  const warns = [];
289103
+ const accessFinding = accessFindings.get(key);
289104
+ if (accessFinding) {
289105
+ problems.push(
289106
+ `[${accessFinding.code}] ${accessFinding.message} Fix: ${accessFinding.fix}`
289107
+ );
289108
+ }
288810
289109
  if (!present.has("id")) problems.push('missing primary key "id"');
288811
- const orgCol = (0, import_schema9.tenancyColumn)((0, import_schema9.resolveTenancy)(model));
289110
+ const orgCol = (0, import_schema8.tenancyColumn)((0, import_schema8.resolveTenancy)(model));
288812
289111
  if (orgCol && !present.has(orgCol)) {
288813
289112
  problems.push(
288814
289113
  `missing "${orgCol}" \u2014 Ablo isolates tenants (RLS) and routes realtime by it, so a table without it has no safe boundary. Add the column, or use a Data Source endpoint.`
@@ -288858,9 +289157,244 @@ async function check(argv) {
288858
289157
  process.exit(errors > 0 ? 1 : 0);
288859
289158
  }
288860
289159
 
288861
- // src/upgrade.ts
289160
+ // src/claims.ts
288862
289161
  init_cjs_shims();
289162
+ var import_node_child_process3 = require("child_process");
288863
289163
  var import_picocolors26 = __toESM(require_picocolors(), 1);
289164
+ var import_contract = require("@abloatai/transaction/claims/contract");
289165
+ var import_routes = require("@abloatai/transaction/claims/routes");
289166
+ init_controlPlane();
289167
+ init_config();
289168
+ function requireRuntimeKey() {
289169
+ const { key } = resolveRuntimeApiKey();
289170
+ if (!key) {
289171
+ console.error(
289172
+ import_picocolors26.default.red(" No runtime credential.") + import_picocolors26.default.dim(
289173
+ ` Run ${import_picocolors26.default.bold("npx ablo login")}, or set ${import_picocolors26.default.bold("ABLO_API_KEY")} to a runtime key.`
289174
+ )
289175
+ );
289176
+ process.exit(1);
289177
+ }
289178
+ return key;
289179
+ }
289180
+ var VALUE_FLAGS = /* @__PURE__ */ new Set(["--ttl", "--description", "--actor"]);
289181
+ function flagValue(argv, name) {
289182
+ const at = argv.indexOf(`--${name}`);
289183
+ return at === -1 ? void 0 : argv[at + 1];
289184
+ }
289185
+ function parseFlags(argv) {
289186
+ return {
289187
+ json: argv.includes("--json") || process.env.ABLO_JSON === "1",
289188
+ queue: argv.includes("--queue"),
289189
+ ttl: flagValue(argv, "ttl"),
289190
+ description: flagValue(argv, "description"),
289191
+ actor: flagValue(argv, "actor")
289192
+ };
289193
+ }
289194
+ function splitAtCommand(argv) {
289195
+ const at = argv.indexOf("--");
289196
+ return at === -1 ? { args: argv, command: [] } : { args: argv.slice(0, at), command: argv.slice(at + 1) };
289197
+ }
289198
+ function positionals(args) {
289199
+ const out = [];
289200
+ for (let i = 0; i < args.length; i += 1) {
289201
+ const arg = args[i];
289202
+ if (arg === void 0) continue;
289203
+ if (VALUE_FLAGS.has(arg)) {
289204
+ i += 1;
289205
+ continue;
289206
+ }
289207
+ if (arg.startsWith("-")) continue;
289208
+ out.push(arg);
289209
+ }
289210
+ return out;
289211
+ }
289212
+ async function acquireClaim(model, id, flags, apiKey) {
289213
+ return requestControlPlane({
289214
+ path: (0, import_routes.claimOnModelPath)({ model, id }),
289215
+ method: "POST",
289216
+ apiKey,
289217
+ body: {
289218
+ ...flags.ttl !== void 0 ? { ttl: flags.ttl } : {},
289219
+ ...flags.description !== void 0 ? { description: flags.description } : {},
289220
+ ...flags.queue ? { queue: true } : {}
289221
+ },
289222
+ responseSchema: import_contract.claimAcquireResponseSchema
289223
+ });
289224
+ }
289225
+ async function releaseClaim(model, id, apiKey) {
289226
+ const reply = await requestControlPlane({
289227
+ path: (0, import_routes.claimOnModelPath)({ model, id }),
289228
+ method: "DELETE",
289229
+ apiKey,
289230
+ responseSchema: import_contract.claimReleaseReplySchema
289231
+ });
289232
+ return reply.released;
289233
+ }
289234
+ async function beat(model, id, ttl, apiKey) {
289235
+ await requestControlPlane({
289236
+ path: (0, import_routes.claimHeartbeatOnModelPath)({ model, id }),
289237
+ method: "POST",
289238
+ apiKey,
289239
+ body: ttl !== void 0 ? { ttl } : {},
289240
+ responseSchema: import_contract.claimHeartbeatReplySchema
289241
+ });
289242
+ }
289243
+ async function pollClaim(claimId, apiKey) {
289244
+ return requestControlPlane({
289245
+ path: (0, import_routes.claimByIdPath)(claimId),
289246
+ apiKey,
289247
+ responseSchema: import_contract.claimStateSchema
289248
+ });
289249
+ }
289250
+ async function waitForGrant(claimId, ttl, apiKey) {
289251
+ const everyMs = Math.max(1e3, Math.floor((0, import_contract.claimTtlMs)(ttl) / 4));
289252
+ for (; ; ) {
289253
+ await new Promise((resolve11) => setTimeout(resolve11, everyMs));
289254
+ const state = await pollClaim(claimId, apiKey);
289255
+ if (state.status === "active") return;
289256
+ if (state.status !== "queued") {
289257
+ throw new Error(`the wait ended without the lease (${state.status})`);
289258
+ }
289259
+ }
289260
+ }
289261
+ function describeAcquired(model, id, granted) {
289262
+ if (granted.status === "queued") {
289263
+ const ahead = granted.position;
289264
+ return ` ${import_picocolors26.default.yellow("\xB7")} Waiting for ${import_picocolors26.default.bold(`${model} ${id}`)}. ` + import_picocolors26.default.dim(ahead === 0 ? "Next in line." : `${ahead} ahead of you.`);
289265
+ }
289266
+ return ` ${import_picocolors26.default.green("\u2713")} Holding ${import_picocolors26.default.bold(`${model} ${id}`)}.`;
289267
+ }
289268
+ async function holdWhile(model, id, flags, apiKey, command) {
289269
+ const granted = await acquireClaim(model, id, flags, apiKey);
289270
+ if (granted.status === "queued") {
289271
+ if (!flags.json) console.error(describeAcquired(model, id, granted));
289272
+ await waitForGrant(granted.id, flags.ttl, apiKey);
289273
+ }
289274
+ if (!flags.json) console.error(` ${import_picocolors26.default.green("\u2713")} Holding ${import_picocolors26.default.bold(`${model} ${id}`)}.`);
289275
+ const everyMs = Math.max(1e3, Math.floor((0, import_contract.claimTtlMs)(flags.ttl) / 3));
289276
+ const timer2 = setInterval(() => {
289277
+ void beat(model, id, flags.ttl, apiKey).catch(() => {
289278
+ });
289279
+ }, everyMs);
289280
+ let released = false;
289281
+ const giveBack = async () => {
289282
+ if (released) return;
289283
+ released = true;
289284
+ clearInterval(timer2);
289285
+ try {
289286
+ await releaseClaim(model, id, apiKey);
289287
+ } catch {
289288
+ }
289289
+ };
289290
+ const [head, ...rest] = command;
289291
+ if (head === void 0) {
289292
+ await giveBack();
289293
+ throw new Error("no command was given after `--`");
289294
+ }
289295
+ const code = await new Promise((resolve11) => {
289296
+ const child = (0, import_node_child_process3.spawn)(head, rest, { stdio: "inherit" });
289297
+ const forward = (signal) => {
289298
+ child.kill(signal);
289299
+ };
289300
+ process.on("SIGINT", forward);
289301
+ process.on("SIGTERM", forward);
289302
+ child.on("error", () => {
289303
+ process.off("SIGINT", forward);
289304
+ process.off("SIGTERM", forward);
289305
+ resolve11(127);
289306
+ });
289307
+ child.on("close", (status2) => {
289308
+ process.off("SIGINT", forward);
289309
+ process.off("SIGTERM", forward);
289310
+ resolve11(status2 ?? 1);
289311
+ });
289312
+ });
289313
+ await giveBack();
289314
+ if (!flags.json) console.error(` ${import_picocolors26.default.dim("\xB7")} ${import_picocolors26.default.dim(`Released ${model} ${id}.`)}`);
289315
+ return code;
289316
+ }
289317
+ function renderList(rows) {
289318
+ if (rows.length === 0) {
289319
+ console.log(` ${import_picocolors26.default.dim("Nothing is held right now.")}`);
289320
+ return;
289321
+ }
289322
+ const held = rows.filter((row) => row.status !== "queued").length;
289323
+ const waiting = rows.length - held;
289324
+ console.log();
289325
+ for (const row of rows) {
289326
+ const where = `${row.target.model} ${row.target.id}`;
289327
+ const state = row.status === "queued" ? import_picocolors26.default.yellow(row.position === void 0 ? "waiting" : `waiting (${row.position} ahead)`) : import_picocolors26.default.green("held");
289328
+ console.log(
289329
+ ` ${import_picocolors26.default.bold(where.padEnd(28))} ${state.padEnd(28)} ${import_picocolors26.default.dim(row.description ?? row.actor)}`
289330
+ );
289331
+ }
289332
+ console.log();
289333
+ console.log(import_picocolors26.default.dim(` ${held} held, ${waiting} waiting.`));
289334
+ console.log();
289335
+ }
289336
+ async function claims(argv = []) {
289337
+ const { args, command } = splitAtCommand(argv);
289338
+ const flags = parseFlags(args);
289339
+ const [verb, ...rest] = positionals(args);
289340
+ if (verb === void 0 || verb === "help" || args.includes("--help")) {
289341
+ console.log(usageFor("claims"));
289342
+ return;
289343
+ }
289344
+ const apiKey = requireRuntimeKey();
289345
+ if (verb === "list") {
289346
+ const [model2, id2] = rest;
289347
+ const query = new URLSearchParams();
289348
+ if (model2 !== void 0) query.set("model", model2);
289349
+ if (id2 !== void 0) query.set("id", id2);
289350
+ if (flags.actor !== void 0) query.set("actorId", flags.actor);
289351
+ const suffix = query.toString();
289352
+ const page = await requestControlPlane({
289353
+ path: `${import_routes.CLAIM_ROUTES.collection}${suffix ? `?${suffix}` : ""}`,
289354
+ apiKey,
289355
+ responseSchema: import_contract.claimListResponseSchema
289356
+ });
289357
+ if (flags.json) console.log(JSON.stringify(page, null, 2));
289358
+ else renderList(page.data);
289359
+ return;
289360
+ }
289361
+ const [model, id] = rest;
289362
+ if (model === void 0 || id === void 0) {
289363
+ console.error(` ${import_picocolors26.default.red("\u2717")} Name the row: ${import_picocolors26.default.bold(`ablo claims ${verb} <model> <id>`)}.`);
289364
+ process.exitCode = 1;
289365
+ return;
289366
+ }
289367
+ if (verb === "acquire") {
289368
+ if (command.length > 0) {
289369
+ process.exitCode = await holdWhile(model, id, flags, apiKey, command);
289370
+ return;
289371
+ }
289372
+ const granted = await acquireClaim(model, id, flags, apiKey);
289373
+ if (flags.json) console.log(JSON.stringify(granted, null, 2));
289374
+ else console.log(describeAcquired(model, id, granted));
289375
+ return;
289376
+ }
289377
+ if (verb === "release") {
289378
+ const released = await releaseClaim(model, id, apiKey);
289379
+ if (flags.json) console.log(JSON.stringify({ object: "claim_release", released }, null, 2));
289380
+ else if (released) console.log(` ${import_picocolors26.default.green("\u2713")} Released ${import_picocolors26.default.bold(`${model} ${id}`)}.`);
289381
+ else console.log(` ${import_picocolors26.default.dim("\xB7")} ${import_picocolors26.default.dim(`You were not holding ${model} ${id}.`)}`);
289382
+ return;
289383
+ }
289384
+ if (verb === "heartbeat") {
289385
+ await beat(model, id, flags.ttl, apiKey);
289386
+ if (flags.json) console.log(JSON.stringify({ object: "claim_heartbeat", ok: true }, null, 2));
289387
+ else console.log(` ${import_picocolors26.default.green("\u2713")} Still holding ${import_picocolors26.default.bold(`${model} ${id}`)}.`);
289388
+ return;
289389
+ }
289390
+ console.error(` ${import_picocolors26.default.red("\u2717")} Unknown: ${import_picocolors26.default.bold(`ablo claims ${verb}`)}.`);
289391
+ console.error(usageFor("claims"));
289392
+ process.exitCode = 1;
289393
+ }
289394
+
289395
+ // src/upgrade.ts
289396
+ init_cjs_shims();
289397
+ var import_picocolors27 = __toESM(require_picocolors(), 1);
288864
289398
  var import_ts_morph = __toESM(require_ts_morph(), 1);
288865
289399
  var DEFAULT_GLOBS = ["app/**/*.{ts,tsx}", "src/**/*.{ts,tsx}", "ablo/**/*.{ts,tsx}", "lib/**/*.{ts,tsx}"];
288866
289400
  var VERB_ARGS = {
@@ -288902,12 +289436,14 @@ function verbRewrite(call, verb) {
288902
289436
  const args = call.getArguments();
288903
289437
  const first = args[0];
288904
289438
  if (first === void 0) return null;
288905
- const calleeText = call.getExpression().getText();
289439
+ const calleeText = verb === "retrieve" ? `${call.getExpression().getText().slice(0, -"retrieve".length)}get` : call.getExpression().getText();
288906
289440
  if (verb === "create") {
288907
289441
  if (import_ts_morph.Node.isObjectLiteralExpression(first) && hasKey2(first, "data")) return null;
288908
289442
  return `${calleeText}({ data: ${first.getText()}${spreadOpts(args[1])} })`;
288909
289443
  }
288910
- if (import_ts_morph.Node.isObjectLiteralExpression(first)) return null;
289444
+ if (import_ts_morph.Node.isObjectLiteralExpression(first)) {
289445
+ return verb === "retrieve" ? `${calleeText}(${first.getText()})` : null;
289446
+ }
288911
289447
  const keyed = params.map((key, i) => args[i] ? `${key}: ${args[i].getText()}` : null).filter(Boolean);
288912
289448
  return `${calleeText}({ ${keyed.join(", ")}${spreadOpts(args[params.length])} })`;
288913
289449
  }
@@ -288923,7 +289459,7 @@ function loadRewrite(call) {
288923
289459
  if (import_ts_morph.Node.isObjectLiteralExpression(whereVal)) {
288924
289460
  const idProp = whereVal.getProperty("id");
288925
289461
  if (idProp && whereVal.getProperties().length === 1 && import_ts_morph.Node.isPropertyAssignment(idProp)) {
288926
- return `${base}.retrieve({ id: ${idProp.getInitializerOrThrow().getText()} })`;
289462
+ return `${base}.get({ id: ${idProp.getInitializerOrThrow().getText()} })`;
288927
289463
  }
288928
289464
  }
288929
289465
  return `${base}.list({ where: ${whereVal.getText()} })`;
@@ -288938,7 +289474,7 @@ async function upgrade(argv) {
288938
289474
  project.addSourceFilesAtPaths(globs.length > 0 ? globs : DEFAULT_GLOBS);
288939
289475
  const files = project.getSourceFiles();
288940
289476
  if (files.length === 0) {
288941
- console.log(import_picocolors26.default.yellow(' No .ts/.tsx files found. Pass a glob, e.g. `ablo upgrade "src/**/*.tsx"`.'));
289477
+ console.log(import_picocolors27.default.yellow(' No .ts/.tsx files found. Pass a glob, e.g. `ablo upgrade "src/**/*.tsx"`.'));
288942
289478
  return;
288943
289479
  }
288944
289480
  const edits = [];
@@ -288986,7 +289522,7 @@ async function upgrade(argv) {
288986
289522
  } else if (method === "load") {
288987
289523
  const next = loadRewrite(call);
288988
289524
  if (next) {
288989
- record(call, "load\u2192retrieve/list", (call.getText().split("\n")[0] ?? "").slice(0, 80), next.slice(0, 80));
289525
+ record(call, "load\u2192get/list", (call.getText().split("\n")[0] ?? "").slice(0, 80), next.slice(0, 80));
288990
289526
  call.replaceWithText(next);
288991
289527
  }
288992
289528
  }
@@ -289012,39 +289548,39 @@ async function upgrade(argv) {
289012
289548
  const rel = (f) => f.replace(cwd + "/", "");
289013
289549
  console.log();
289014
289550
  if (edits.length === 0 && manual.length === 0) {
289015
- console.log(import_picocolors26.default.green(" \u2713 Nothing to migrate \u2014 your code is already on the current API."));
289551
+ console.log(import_picocolors27.default.green(" \u2713 Nothing to migrate \u2014 your code is already on the current API."));
289016
289552
  return;
289017
289553
  }
289018
289554
  if (edits.length > 0) {
289019
- console.log(import_picocolors26.default.bold(` ${write ? "Applied" : "Would apply"} ${edits.length} change${edits.length === 1 ? "" : "s"}:`));
289555
+ console.log(import_picocolors27.default.bold(` ${write ? "Applied" : "Would apply"} ${edits.length} change${edits.length === 1 ? "" : "s"}:`));
289020
289556
  for (const e2 of edits) {
289021
- console.log(` ${import_picocolors26.default.dim(`${rel(e2.file)}:${e2.line}`)} ${import_picocolors26.default.cyan(e2.rule)}`);
289022
- console.log(` ${import_picocolors26.default.red("-")} ${e2.before}`);
289023
- console.log(` ${import_picocolors26.default.green("+")} ${e2.after}`);
289557
+ console.log(` ${import_picocolors27.default.dim(`${rel(e2.file)}:${e2.line}`)} ${import_picocolors27.default.cyan(e2.rule)}`);
289558
+ console.log(` ${import_picocolors27.default.red("-")} ${e2.before}`);
289559
+ console.log(` ${import_picocolors27.default.green("+")} ${e2.after}`);
289024
289560
  }
289025
289561
  }
289026
289562
  if (manual.length > 0) {
289027
289563
  console.log();
289028
- console.log(import_picocolors26.default.bold(import_picocolors26.default.yellow(` ${manual.length} spot${manual.length === 1 ? "" : "s"} need manual review (structural):`)));
289564
+ console.log(import_picocolors27.default.bold(import_picocolors27.default.yellow(` ${manual.length} spot${manual.length === 1 ? "" : "s"} need manual review (structural):`)));
289029
289565
  for (const m2 of manual) {
289030
- console.log(` ${import_picocolors26.default.dim(`${rel(m2.file)}:${m2.line}`)} ${import_picocolors26.default.yellow(m2.rule)}`);
289031
- console.log(` ${import_picocolors26.default.dim(m2.snippet)}`);
289566
+ console.log(` ${import_picocolors27.default.dim(`${rel(m2.file)}:${m2.line}`)} ${import_picocolors27.default.yellow(m2.rule)}`);
289567
+ console.log(` ${import_picocolors27.default.dim(m2.snippet)}`);
289032
289568
  console.log(` \u2192 ${m2.hint}`);
289033
289569
  }
289034
289570
  }
289035
289571
  console.log();
289036
289572
  if (write) {
289037
289573
  await project.save();
289038
- console.log(import_picocolors26.default.green(` \u2713 Wrote ${edits.length} change${edits.length === 1 ? "" : "s"}. Review the diff, run your typecheck.`));
289574
+ console.log(import_picocolors27.default.green(` \u2713 Wrote ${edits.length} change${edits.length === 1 ? "" : "s"}. Review the diff, run your typecheck.`));
289039
289575
  } else {
289040
- console.log(import_picocolors26.default.dim(" Dry run. Re-run with `--write` to apply the auto-fixes above (manual items are never auto-written)."));
289576
+ console.log(import_picocolors27.default.dim(" Dry run. Re-run with `--write` to apply the auto-fixes above (manual items are never auto-written)."));
289041
289577
  }
289042
289578
  }
289043
289579
 
289044
289580
  // src/pull.ts
289045
289581
  init_cjs_shims();
289046
- var import_errors21 = require("@abloatai/transaction/errors");
289047
- var import_picocolors27 = __toESM(require_picocolors(), 1);
289582
+ var import_errors22 = require("@abloatai/transaction/errors");
289583
+ var import_picocolors28 = __toESM(require_picocolors(), 1);
289048
289584
  init_src();
289049
289585
  var import_fs10 = require("fs");
289050
289586
  init_theme();
@@ -289072,7 +289608,7 @@ function parsePullArgs(argv) {
289072
289608
  force = true;
289073
289609
  break;
289074
289610
  default:
289075
- throw new import_errors21.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
289611
+ throw new import_errors22.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
289076
289612
  }
289077
289613
  }
289078
289614
  return { out, appSchema, importPath, force };
@@ -289142,56 +289678,56 @@ async function pull(argv) {
289142
289678
  try {
289143
289679
  args = parsePullArgs(argv);
289144
289680
  } catch (err) {
289145
- console.error(import_picocolors27.default.red(` ${err instanceof Error ? err.message : String(err)}`));
289681
+ console.error(import_picocolors28.default.red(` ${err instanceof Error ? err.message : String(err)}`));
289146
289682
  process.exit(1);
289147
289683
  }
289148
289684
  const dbUrl = readProjectAdminDatabaseUrl();
289149
289685
  if (!dbUrl) {
289150
289686
  console.error(
289151
- import_picocolors27.default.red(` No database.`) + import_picocolors27.default.dim(` Set ${import_picocolors27.default.bold(ADMIN_URL_VAR)} to the Postgres to pull from.`)
289687
+ import_picocolors28.default.red(` No database.`) + import_picocolors28.default.dim(` Set ${import_picocolors28.default.bold(ADMIN_URL_VAR)} to the Postgres to pull from.`)
289152
289688
  );
289153
289689
  process.exit(1);
289154
289690
  }
289155
289691
  if ((0, import_fs10.existsSync)(args.out) && !args.force) {
289156
289692
  console.error(
289157
- import_picocolors27.default.red(` ${args.out} already exists.`) + import_picocolors27.default.dim(` Re-run with ${import_picocolors27.default.bold("--force")} to overwrite.`)
289693
+ import_picocolors28.default.red(` ${args.out} already exists.`) + import_picocolors28.default.dim(` Re-run with ${import_picocolors28.default.bold("--force")} to overwrite.`)
289158
289694
  );
289159
289695
  process.exit(1);
289160
289696
  }
289161
289697
  console.log(`
289162
- ${brand("ablo")} ${import_picocolors27.default.dim("pull")} ${import_picocolors27.default.dim(`schema "${args.appSchema}"`)}
289698
+ ${brand("ablo")} ${import_picocolors28.default.dim("pull")} ${import_picocolors28.default.dim(`schema "${args.appSchema}"`)}
289163
289699
  `);
289164
289700
  let result;
289165
289701
  try {
289166
289702
  result = await buildSchemaSourceFromDb({ dbUrl, appSchema: args.appSchema, importPath: args.importPath });
289167
289703
  } catch (err) {
289168
- console.error(import_picocolors27.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
289704
+ console.error(import_picocolors28.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
289169
289705
  process.exit(1);
289170
289706
  }
289171
289707
  if (result.models.length === 0) {
289172
289708
  console.error(
289173
- import_picocolors27.default.yellow(` No adoptable tables found`) + import_picocolors27.default.dim(` (a model needs an ${import_picocolors27.default.bold("id")} + ${import_picocolors27.default.bold("organization_id")} column).`)
289709
+ import_picocolors28.default.yellow(` No adoptable tables found`) + import_picocolors28.default.dim(` (a model needs an ${import_picocolors28.default.bold("id")} + ${import_picocolors28.default.bold("organization_id")} column).`)
289174
289710
  );
289175
289711
  process.exit(1);
289176
289712
  }
289177
289713
  (0, import_fs10.writeFileSync)(args.out, result.source);
289178
- console.log(` ${import_picocolors27.default.green("\u2713")} wrote ${import_picocolors27.default.bold(args.out)} ${import_picocolors27.default.dim(`(${result.models.length} models)`)}`);
289179
- console.log(` ${import_picocolors27.default.dim(`models: ${result.models.join(", ")}`)}`);
289714
+ console.log(` ${import_picocolors28.default.green("\u2713")} wrote ${import_picocolors28.default.bold(args.out)} ${import_picocolors28.default.dim(`(${result.models.length} models)`)}`);
289715
+ console.log(` ${import_picocolors28.default.dim(`models: ${result.models.join(", ")}`)}`);
289180
289716
  if (result.skipped.length > 0) {
289181
- console.log(` ${import_picocolors27.default.dim(`${result.skipped.length} table(s) skipped:`)}`);
289182
- for (const s of result.skipped) console.log(` ${import_picocolors27.default.dim(`- ${s.name}: ${s.reason}`)}`);
289717
+ console.log(` ${import_picocolors28.default.dim(`${result.skipped.length} table(s) skipped:`)}`);
289718
+ for (const s of result.skipped) console.log(` ${import_picocolors28.default.dim(`- ${s.name}: ${s.reason}`)}`);
289183
289719
  }
289184
289720
  console.log(
289185
289721
  `
289186
- ${import_picocolors27.default.dim("Introspection is lossy (enums, JSON shape, relations). Review the file, then")} ${import_picocolors27.default.bold("ablo check")}.
289722
+ ${import_picocolors28.default.dim("Introspection is lossy (enums, JSON shape, relations). Review the file, then")} ${import_picocolors28.default.bold("ablo check")}.
289187
289723
  `
289188
289724
  );
289189
289725
  }
289190
289726
 
289191
289727
  // src/prismaPull.ts
289192
289728
  init_cjs_shims();
289193
- var import_errors22 = require("@abloatai/transaction/errors");
289194
- var import_picocolors28 = __toESM(require_picocolors(), 1);
289729
+ var import_errors23 = require("@abloatai/transaction/errors");
289730
+ var import_picocolors29 = __toESM(require_picocolors(), 1);
289195
289731
  var import_fs11 = require("fs");
289196
289732
  init_theme();
289197
289733
  var DEFAULT_SCHEMA = "prisma/schema.prisma";
@@ -289388,7 +289924,7 @@ function parsePrismaPullArgs(argv) {
289388
289924
  force = true;
289389
289925
  break;
289390
289926
  default:
289391
- if (arg.startsWith("--")) throw new import_errors22.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
289927
+ if (arg.startsWith("--")) throw new import_errors23.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
289392
289928
  schema = arg;
289393
289929
  }
289394
289930
  }
@@ -289399,56 +289935,56 @@ async function prismaPull(argv) {
289399
289935
  try {
289400
289936
  args = parsePrismaPullArgs(argv);
289401
289937
  } catch (err) {
289402
- console.error(import_picocolors28.default.red(` ${err instanceof Error ? err.message : String(err)}`));
289938
+ console.error(import_picocolors29.default.red(` ${err instanceof Error ? err.message : String(err)}`));
289403
289939
  process.exit(1);
289404
289940
  }
289405
289941
  if (!(0, import_fs11.existsSync)(args.schema)) {
289406
289942
  console.error(
289407
- import_picocolors28.default.red(` No Prisma schema at ${import_picocolors28.default.bold(args.schema)}.`) + import_picocolors28.default.dim(` Pass a path: ${import_picocolors28.default.bold("ablo pull prisma <path>")}.`)
289943
+ import_picocolors29.default.red(` No Prisma schema at ${import_picocolors29.default.bold(args.schema)}.`) + import_picocolors29.default.dim(` Pass a path: ${import_picocolors29.default.bold("ablo pull prisma <path>")}.`)
289408
289944
  );
289409
289945
  process.exit(1);
289410
289946
  }
289411
289947
  if ((0, import_fs11.existsSync)(args.out) && !args.force) {
289412
289948
  console.error(
289413
- import_picocolors28.default.red(` ${args.out} already exists.`) + import_picocolors28.default.dim(` Re-run with ${import_picocolors28.default.bold("--force")} to overwrite.`)
289949
+ import_picocolors29.default.red(` ${args.out} already exists.`) + import_picocolors29.default.dim(` Re-run with ${import_picocolors29.default.bold("--force")} to overwrite.`)
289414
289950
  );
289415
289951
  process.exit(1);
289416
289952
  }
289417
289953
  console.log(`
289418
- ${brand("ablo")} ${import_picocolors28.default.dim("pull prisma")} ${import_picocolors28.default.dim(args.schema)}
289954
+ ${brand("ablo")} ${import_picocolors29.default.dim("pull prisma")} ${import_picocolors29.default.dim(args.schema)}
289419
289955
  `);
289420
289956
  let result;
289421
289957
  try {
289422
289958
  const src = (0, import_fs11.readFileSync)(args.schema, "utf8");
289423
289959
  result = buildSchemaSourceFromPrisma({ src, importPath: args.importPath });
289424
289960
  } catch (err) {
289425
- console.error(import_picocolors28.default.red(` Couldn't parse the schema: ${err instanceof Error ? err.message : String(err)}`));
289961
+ console.error(import_picocolors29.default.red(` Couldn't parse the schema: ${err instanceof Error ? err.message : String(err)}`));
289426
289962
  process.exit(1);
289427
289963
  }
289428
289964
  if (result.models.length === 0) {
289429
289965
  console.error(
289430
- import_picocolors28.default.yellow(` No adoptable models found`) + import_picocolors28.default.dim(` (a model needs an ${import_picocolors28.default.bold("id")} + ${import_picocolors28.default.bold("organizationId")} / ${import_picocolors28.default.bold("organization_id")}).`)
289966
+ import_picocolors29.default.yellow(` No adoptable models found`) + import_picocolors29.default.dim(` (a model needs an ${import_picocolors29.default.bold("id")} + ${import_picocolors29.default.bold("organizationId")} / ${import_picocolors29.default.bold("organization_id")}).`)
289431
289967
  );
289432
289968
  process.exit(1);
289433
289969
  }
289434
289970
  (0, import_fs11.writeFileSync)(args.out, result.source);
289435
- console.log(` ${import_picocolors28.default.green("\u2713")} wrote ${import_picocolors28.default.bold(args.out)} ${import_picocolors28.default.dim(`(${result.models.length} models)`)}`);
289436
- console.log(` ${import_picocolors28.default.dim(`models: ${result.models.join(", ")}`)}`);
289971
+ console.log(` ${import_picocolors29.default.green("\u2713")} wrote ${import_picocolors29.default.bold(args.out)} ${import_picocolors29.default.dim(`(${result.models.length} models)`)}`);
289972
+ console.log(` ${import_picocolors29.default.dim(`models: ${result.models.join(", ")}`)}`);
289437
289973
  if (result.skipped.length > 0) {
289438
- console.log(` ${import_picocolors28.default.dim(`${result.skipped.length} model(s) skipped:`)}`);
289439
- for (const s of result.skipped) console.log(` ${import_picocolors28.default.dim(`- ${s.name}: ${s.reason}`)}`);
289974
+ console.log(` ${import_picocolors29.default.dim(`${result.skipped.length} model(s) skipped:`)}`);
289975
+ for (const s of result.skipped) console.log(` ${import_picocolors29.default.dim(`- ${s.name}: ${s.reason}`)}`);
289440
289976
  }
289441
289977
  console.log(
289442
289978
  `
289443
- ${import_picocolors28.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors28.default.bold("ablo check")}.
289979
+ ${import_picocolors29.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors29.default.bold("ablo check")}.
289444
289980
  `
289445
289981
  );
289446
289982
  }
289447
289983
 
289448
289984
  // src/drizzlePull.ts
289449
289985
  init_cjs_shims();
289450
- var import_picocolors29 = __toESM(require_picocolors(), 1);
289451
- var import_errors23 = require("@abloatai/transaction/errors");
289986
+ var import_picocolors30 = __toESM(require_picocolors(), 1);
289987
+ var import_errors24 = require("@abloatai/transaction/errors");
289452
289988
  var import_fs12 = require("fs");
289453
289989
  var import_path7 = require("path");
289454
289990
  init_theme();
@@ -289555,7 +290091,7 @@ function parseDrizzlePullArgs(argv) {
289555
290091
  force = true;
289556
290092
  break;
289557
290093
  default:
289558
- if (arg.startsWith("--")) throw new import_errors23.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
290094
+ if (arg.startsWith("--")) throw new import_errors24.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
289559
290095
  schema = arg;
289560
290096
  }
289561
290097
  }
@@ -289572,27 +290108,27 @@ async function drizzlePull(argv) {
289572
290108
  try {
289573
290109
  args = parseDrizzlePullArgs(argv);
289574
290110
  } catch (err) {
289575
- console.error(import_picocolors29.default.red(` ${err instanceof Error ? err.message : String(err)}`));
290111
+ console.error(import_picocolors30.default.red(` ${err instanceof Error ? err.message : String(err)}`));
289576
290112
  process.exit(1);
289577
290113
  }
289578
290114
  if (!args.schema) {
289579
290115
  console.error(
289580
- import_picocolors29.default.red(` No Drizzle schema given.`) + import_picocolors29.default.dim(` Pass the module: ${import_picocolors29.default.bold("ablo pull drizzle src/db/schema.ts")}.`)
290116
+ import_picocolors30.default.red(` No Drizzle schema given.`) + import_picocolors30.default.dim(` Pass the module: ${import_picocolors30.default.bold("ablo pull drizzle src/db/schema.ts")}.`)
289581
290117
  );
289582
290118
  process.exit(1);
289583
290119
  }
289584
290120
  if (!(0, import_fs12.existsSync)(args.schema)) {
289585
- console.error(import_picocolors29.default.red(` No file at ${import_picocolors29.default.bold(args.schema)}.`));
290121
+ console.error(import_picocolors30.default.red(` No file at ${import_picocolors30.default.bold(args.schema)}.`));
289586
290122
  process.exit(1);
289587
290123
  }
289588
290124
  if ((0, import_fs12.existsSync)(args.out) && !args.force) {
289589
290125
  console.error(
289590
- import_picocolors29.default.red(` ${args.out} already exists.`) + import_picocolors29.default.dim(` Re-run with ${import_picocolors29.default.bold("--force")} to overwrite.`)
290126
+ import_picocolors30.default.red(` ${args.out} already exists.`) + import_picocolors30.default.dim(` Re-run with ${import_picocolors30.default.bold("--force")} to overwrite.`)
289591
290127
  );
289592
290128
  process.exit(1);
289593
290129
  }
289594
290130
  console.log(`
289595
- ${brand("ablo")} ${import_picocolors29.default.dim("pull drizzle")} ${import_picocolors29.default.dim(args.schema)}
290131
+ ${brand("ablo")} ${import_picocolors30.default.dim("pull drizzle")} ${import_picocolors30.default.dim(args.schema)}
289596
290132
  `);
289597
290133
  let result;
289598
290134
  try {
@@ -289600,26 +290136,26 @@ async function drizzlePull(argv) {
289600
290136
  result = await buildSchemaSourceFromDrizzle({ mod, importPath: args.importPath });
289601
290137
  } catch (err) {
289602
290138
  const msg = err instanceof Error ? err.message : String(err);
289603
- const hint = msg.includes("Cannot find package 'drizzle-orm'") ? import_picocolors29.default.dim(` (install ${import_picocolors29.default.bold("drizzle-orm")} in this project)`) : "";
289604
- console.error(import_picocolors29.default.red(` Couldn't load the schema: ${msg}`) + hint);
290139
+ const hint = msg.includes("Cannot find package 'drizzle-orm'") ? import_picocolors30.default.dim(` (install ${import_picocolors30.default.bold("drizzle-orm")} in this project)`) : "";
290140
+ console.error(import_picocolors30.default.red(` Couldn't load the schema: ${msg}`) + hint);
289605
290141
  process.exit(1);
289606
290142
  }
289607
290143
  if (result.models.length === 0) {
289608
290144
  console.error(
289609
- import_picocolors29.default.yellow(` No adoptable tables found`) + import_picocolors29.default.dim(` (a table needs an ${import_picocolors29.default.bold("id")} + ${import_picocolors29.default.bold("organization_id")} column).`)
290145
+ import_picocolors30.default.yellow(` No adoptable tables found`) + import_picocolors30.default.dim(` (a table needs an ${import_picocolors30.default.bold("id")} + ${import_picocolors30.default.bold("organization_id")} column).`)
289610
290146
  );
289611
290147
  process.exit(1);
289612
290148
  }
289613
290149
  (0, import_fs12.writeFileSync)(args.out, result.source);
289614
- console.log(` ${import_picocolors29.default.green("\u2713")} wrote ${import_picocolors29.default.bold(args.out)} ${import_picocolors29.default.dim(`(${result.models.length} models)`)}`);
289615
- console.log(` ${import_picocolors29.default.dim(`models: ${result.models.join(", ")}`)}`);
290150
+ console.log(` ${import_picocolors30.default.green("\u2713")} wrote ${import_picocolors30.default.bold(args.out)} ${import_picocolors30.default.dim(`(${result.models.length} models)`)}`);
290151
+ console.log(` ${import_picocolors30.default.dim(`models: ${result.models.join(", ")}`)}`);
289616
290152
  if (result.skipped.length > 0) {
289617
- console.log(` ${import_picocolors29.default.dim(`${result.skipped.length} table(s) skipped:`)}`);
289618
- for (const s of result.skipped) console.log(` ${import_picocolors29.default.dim(`- ${s.name}: ${s.reason}`)}`);
290153
+ console.log(` ${import_picocolors30.default.dim(`${result.skipped.length} table(s) skipped:`)}`);
290154
+ for (const s of result.skipped) console.log(` ${import_picocolors30.default.dim(`- ${s.name}: ${s.reason}`)}`);
289619
290155
  }
289620
290156
  console.log(
289621
290157
  `
289622
- ${import_picocolors29.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors29.default.bold("ablo check")}.
290158
+ ${import_picocolors30.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors30.default.bold("ablo check")}.
289623
290159
  `
289624
290160
  );
289625
290161
  }
@@ -289632,8 +290168,8 @@ init_telemetry();
289632
290168
 
289633
290169
  // src/init/options.ts
289634
290170
  init_cjs_shims();
289635
- var import_node_fs4 = require("fs");
289636
- var import_node_path3 = require("path");
290171
+ var import_node_fs5 = require("fs");
290172
+ var import_node_path4 = require("path");
289637
290173
  var INIT_FRAMEWORKS = ["nextjs", "vite", "remix", "vanilla"];
289638
290174
  var INIT_AUTHS = [
289639
290175
  "apikey",
@@ -289672,7 +290208,7 @@ function parseInitArgs(args) {
289672
290208
  function detectOrm(override, root = process.cwd()) {
289673
290209
  if (override === "prisma" || override === "drizzle" || override === "none") return override;
289674
290210
  try {
289675
- const pkg = JSON.parse((0, import_node_fs4.readFileSync)((0, import_node_path3.resolve)(root, "package.json"), "utf8"));
290211
+ const pkg = JSON.parse((0, import_node_fs5.readFileSync)((0, import_node_path4.resolve)(root, "package.json"), "utf8"));
289676
290212
  const dependencies = { ...pkg.dependencies, ...pkg.devDependencies };
289677
290213
  if (dependencies["@prisma/client"] || dependencies.prisma) return "prisma";
289678
290214
  if (dependencies["drizzle-orm"]) return "drizzle";
@@ -289681,24 +290217,24 @@ function detectOrm(override, root = process.cwd()) {
289681
290217
  return "none";
289682
290218
  }
289683
290219
  function detectNextLayout(root = process.cwd()) {
289684
- const useSrc = (0, import_node_fs4.existsSync)((0, import_node_path3.resolve)(root, "src", "app")) || !(0, import_node_fs4.existsSync)((0, import_node_path3.resolve)(root, "app")) && (0, import_node_fs4.existsSync)((0, import_node_path3.resolve)(root, "src"));
289685
- return useSrc ? { appBase: (0, import_node_path3.join)("src", "app"), aliasBase: "src" } : { appBase: "app", aliasBase: "." };
290220
+ const useSrc = (0, import_node_fs5.existsSync)((0, import_node_path4.resolve)(root, "src", "app")) || !(0, import_node_fs5.existsSync)((0, import_node_path4.resolve)(root, "app")) && (0, import_node_fs5.existsSync)((0, import_node_path4.resolve)(root, "src"));
290221
+ return useSrc ? { appBase: (0, import_node_path4.join)("src", "app"), aliasBase: "src" } : { appBase: "app", aliasBase: "." };
289686
290222
  }
289687
290223
  function detectPackageManager(root = process.cwd()) {
289688
- if ((0, import_node_fs4.existsSync)((0, import_node_path3.resolve)(root, "pnpm-lock.yaml"))) return "pnpm";
289689
- if ((0, import_node_fs4.existsSync)((0, import_node_path3.resolve)(root, "yarn.lock"))) return "yarn";
289690
- if ((0, import_node_fs4.existsSync)((0, import_node_path3.resolve)(root, "bun.lockb"))) return "bun";
290224
+ if ((0, import_node_fs5.existsSync)((0, import_node_path4.resolve)(root, "pnpm-lock.yaml"))) return "pnpm";
290225
+ if ((0, import_node_fs5.existsSync)((0, import_node_path4.resolve)(root, "yarn.lock"))) return "yarn";
290226
+ if ((0, import_node_fs5.existsSync)((0, import_node_path4.resolve)(root, "bun.lockb"))) return "bun";
289691
290227
  return "npm";
289692
290228
  }
289693
290229
 
289694
290230
  // src/init/run.ts
289695
290231
  init_cjs_shims();
289696
- var import_node_child_process3 = require("child_process");
289697
- var import_node_fs6 = require("fs");
289698
- var import_node_path5 = require("path");
290232
+ var import_node_child_process4 = require("child_process");
290233
+ var import_node_fs7 = require("fs");
290234
+ var import_node_path6 = require("path");
289699
290235
  init_dist2();
289700
- var import_picocolors30 = __toESM(require_picocolors(), 1);
289701
- var import_errors24 = require("@abloatai/transaction/errors");
290236
+ var import_picocolors31 = __toESM(require_picocolors(), 1);
290237
+ var import_errors25 = require("@abloatai/transaction/errors");
289702
290238
  init_dbRole();
289703
290239
  init_config();
289704
290240
  init_projects();
@@ -289751,8 +290287,21 @@ export async function POST(request: Request): Promise<Response> {
289751
290287
  );
289752
290288
  }
289753
290289
 
290290
+ const authorizedScope = await authorizeActiveWorkspace(user.id);
290291
+ if (!authorizedScope) {
290292
+ return Response.json(
290293
+ credentialEndpointErrorSchema.parse({
290294
+ error: { code: 'policy_denied', message: 'Workspace membership is stale or revoked' },
290295
+ }),
290296
+ { status: 403, headers: noStore },
290297
+ );
290298
+ }
290299
+
289754
290300
  const { token, expiresAt } = await sync.sessions.create({
289755
290301
  user: { id: user.id },
290302
+ // These ids came from the server-side membership lookup below. Never take
290303
+ // organization, workspace, team, or group ids from the request body.
290304
+ syncGroups: authorizedScope.syncGroups,
289756
290305
  can: { records: ['read', 'create', 'update'] },
289757
290306
  });
289758
290307
  return Response.json(
@@ -289776,6 +290325,27 @@ async function getCurrentUser(): Promise<{ id: string } | null> {
289776
290325
  const session = await auth.api.getSession({ headers: await headers() });
289777
290326
  return session?.user ? { id: session.user.id } : null;
289778
290327
  }
290328
+
290329
+ type AuthorizedWorkspace = {
290330
+ workspaceId: string;
290331
+ syncGroups: readonly [\`workspace:\${string}\`, ...\`\${string}:\${string}\`[]];
290332
+ };
290333
+
290334
+ async function authorizeActiveWorkspace(userId: string): Promise<AuthorizedWorkspace | null> {
290335
+ void userId;
290336
+ // REQUIRED: query your membership table here, immediately before minting.
290337
+ // Read the active workspace from the server-side session, verify this user has
290338
+ // an active membership, and derive every team/group id on the server. Return
290339
+ // null for a stale or revoked membership. This refusal keeps a newly generated
290340
+ // route from turning "signed in" into workspace authorization by accident.
290341
+ //
290342
+ // Example after your membership query:
290343
+ // return {
290344
+ // workspaceId: membership.workspaceId,
290345
+ // syncGroups: [\`workspace:\${membership.workspaceId}\`],
290346
+ // };
290347
+ return null;
290348
+ }
289779
290349
  `;
289780
290350
  }
289781
290351
 
@@ -289808,7 +290378,7 @@ export const schema = defineSchema({
289808
290378
  });
289809
290379
  `;
289810
290380
  }
289811
- function generateSyncConfig(auth) {
290381
+ function generateSyncConfig(auth, options = {}) {
289812
290382
  const authLine = auth === "apikey" ? "" : auth === "firebase" ? `
289813
290383
  auth: async () => {
289814
290384
  const { getAuth } = await import('firebase/auth');
@@ -289820,7 +290390,7 @@ function generateSyncConfig(auth) {
289820
290390
  // auth: async () => { const { data } = await supabase.auth.getSession(); return data.session?.access_token ?? ''; },` : auth === "betterauth" ? `
289821
290391
  // auth: async () => { const session = await authClient.getSession(); return session?.token ?? ''; },` : `
289822
290392
  // auth: () => 'your-jwt-token', // replace with your auth provider`;
289823
- return `import Ablo from '@abloatai/ablo';
290393
+ return `${options.serverOnly ? "import 'server-only';\n\n" : ""}import Ablo from '@abloatai/ablo';
289824
290394
  import { schema } from './schema';
289825
290395
 
289826
290396
  // SERVER-ONLY client \u2014 it holds your \`sk_\` key. Use it from server code: the
@@ -289982,7 +290552,10 @@ export async function POST(req: Request): Promise<Response> {
289982
290552
  const model: unknown = Reflect.get(prisma, event.model); // prisma.record, prisma.task, \u2026
289983
290553
  if (!isModelDelegate(model)) continue; // a model you don't mirror locally \u2014 skip it
289984
290554
  if (event.data === null) {
289985
- await model.delete({ where: { id: event.objectId } }).catch(() => {}); // already gone
290555
+ await model.delete({ where: { id: event.objectId } }).catch((error) => {
290556
+ // Idempotent replay: a missing local row is already the desired state.
290557
+ void error;
290558
+ });
289986
290559
  } else {
289987
290560
  await model.upsert({ where: { id: event.objectId }, create: event.data, update: event.data });
289988
290561
  }
@@ -290046,12 +290619,12 @@ async function main() {
290046
290619
  // Triage the urgent one to the top. We write based on the version we just
290047
290620
  // read (\`readAt\`), so if a human edits the same row at the same moment the
290048
290621
  // write is rejected instead of silently clobbering them.
290049
- const snap = ablo.snapshot({ records: urgent.id });
290622
+ const current = await ablo.records.read({ id: urgent.id });
290623
+ if (!current) throw new Error('urgent record was not found');
290050
290624
  await ablo.records.update({
290051
290625
  id: urgent.id,
290052
290626
  data: { priority: 10 },
290053
- readAt: snap.stamp,
290054
- onStale: 'reject',
290627
+ reads: [current],
290055
290628
  });
290056
290629
  console.log('prioritized:', urgent.title);
290057
290630
 
@@ -290062,7 +290635,7 @@ async function main() {
290062
290635
  main().catch((err) => {
290063
290636
  // Ablo errors stringify to one clean line (code + message + docs link),
290064
290637
  // never a stack/object dump \u2014 see AbloError.toString().
290065
- console.error(String(err));
290638
+ process.stderr.write(String(err) + '\\n');
290066
290639
  process.exit(1);
290067
290640
  });
290068
290641
  `;
@@ -290121,9 +290694,9 @@ export function RecordList() {
290121
290694
 
290122
290695
  // src/init/writer.ts
290123
290696
  init_cjs_shims();
290124
- var import_node_fs5 = require("fs");
290125
- var import_node_path4 = require("path");
290126
- var import_node_crypto7 = require("crypto");
290697
+ var import_node_fs6 = require("fs");
290698
+ var import_node_path5 = require("path");
290699
+ var import_node_crypto8 = require("crypto");
290127
290700
  function projectInitWritePlan(plan) {
290128
290701
  return setupInitPlanProjectionSchema.parse({
290129
290702
  root: plan.root,
@@ -290137,18 +290710,18 @@ function projectInitWritePlan(plan) {
290137
290710
  });
290138
290711
  }
290139
290712
  function absolute(root, path) {
290140
- const target = (0, import_node_path4.resolve)(root, path);
290141
- const fromRoot = (0, import_node_path4.relative)(root, target);
290142
- if (fromRoot === "" || fromRoot === ".." || fromRoot.startsWith(`..${import_node_path4.sep}`) || (0, import_node_path4.isAbsolute)(fromRoot)) {
290713
+ const target = (0, import_node_path5.resolve)(root, path);
290714
+ const fromRoot = (0, import_node_path5.relative)(root, target);
290715
+ if (fromRoot === "" || fromRoot === ".." || fromRoot.startsWith(`..${import_node_path5.sep}`) || (0, import_node_path5.isAbsolute)(fromRoot)) {
290143
290716
  throw new Error(`Init target must stay inside the project root: ${path}`);
290144
290717
  }
290145
290718
  return target;
290146
290719
  }
290147
290720
  function sha2562(content) {
290148
- return (0, import_node_crypto7.createHash)("sha256").update(content).digest("hex");
290721
+ return (0, import_node_crypto8.createHash)("sha256").update(content).digest("hex");
290149
290722
  }
290150
290723
  function readIfPresent(path) {
290151
- return (0, import_node_fs5.existsSync)(path) ? (0, import_node_fs5.readFileSync)(path, "utf8") : void 0;
290724
+ return (0, import_node_fs6.existsSync)(path) ? (0, import_node_fs6.readFileSync)(path, "utf8") : void 0;
290152
290725
  }
290153
290726
  function mergeEnvironmentTemplate(existing, template) {
290154
290727
  const assignments = template.split(/\r?\n/).map((line) => {
@@ -290172,7 +290745,7 @@ function mergeEnvironmentTemplate(existing, template) {
290172
290745
  };
290173
290746
  }
290174
290747
  function planInitWrites(input) {
290175
- const root = (0, import_node_path4.resolve)(input.root ?? process.cwd());
290748
+ const root = (0, import_node_path5.resolve)(input.root ?? process.cwd());
290176
290749
  const actions = [];
290177
290750
  const conflicts = [];
290178
290751
  for (const file of input.files) {
@@ -290217,18 +290790,18 @@ function planInitWrites(input) {
290217
290790
  return { root, actions, conflicts };
290218
290791
  }
290219
290792
  function writeAtomic(path, content, kind) {
290220
- (0, import_node_fs5.mkdirSync)((0, import_node_path4.dirname)(path), { recursive: true });
290221
- const temporary = (0, import_node_path4.join)((0, import_node_path4.dirname)(path), `.${(0, import_node_crypto7.randomUUID)()}.ablo-init.tmp`);
290222
- (0, import_node_fs5.writeFileSync)(temporary, content, { flag: "wx" });
290793
+ (0, import_node_fs6.mkdirSync)((0, import_node_path5.dirname)(path), { recursive: true });
290794
+ const temporary = (0, import_node_path5.join)((0, import_node_path5.dirname)(path), `.${(0, import_node_crypto8.randomUUID)()}.ablo-init.tmp`);
290795
+ (0, import_node_fs6.writeFileSync)(temporary, content, { flag: "wx" });
290223
290796
  try {
290224
290797
  if (kind === "create") {
290225
- (0, import_node_fs5.linkSync)(temporary, path);
290226
- (0, import_node_fs5.unlinkSync)(temporary);
290798
+ (0, import_node_fs6.linkSync)(temporary, path);
290799
+ (0, import_node_fs6.unlinkSync)(temporary);
290227
290800
  } else {
290228
- (0, import_node_fs5.renameSync)(temporary, path);
290801
+ (0, import_node_fs6.renameSync)(temporary, path);
290229
290802
  }
290230
290803
  } catch (error) {
290231
- if ((0, import_node_fs5.existsSync)(temporary)) (0, import_node_fs5.unlinkSync)(temporary);
290804
+ if ((0, import_node_fs6.existsSync)(temporary)) (0, import_node_fs6.unlinkSync)(temporary);
290232
290805
  throw error;
290233
290806
  }
290234
290807
  }
@@ -290259,23 +290832,23 @@ function bailIfCancelled(value) {
290259
290832
  process.exit(0);
290260
290833
  }
290261
290834
  }
290262
- async function chooseOption(name, flagValue, fallback, allowed, interactive, prompt) {
290263
- if (flagValue !== void 0) {
290264
- if (!allowed.includes(flagValue)) {
290265
- throw new import_errors24.AbloValidationError(
290266
- `Invalid --${name} "${flagValue}". Allowed: ${allowed.join(", ")}`,
290835
+ async function chooseOption(name, flagValue2, fallback, allowed, interactive, prompt) {
290836
+ if (flagValue2 !== void 0) {
290837
+ if (!allowed.includes(flagValue2)) {
290838
+ throw new import_errors25.AbloValidationError(
290839
+ `Invalid --${name} "${flagValue2}". Allowed: ${allowed.join(", ")}`,
290267
290840
  { code: "cli_invalid_arguments" }
290268
290841
  );
290269
290842
  }
290270
- return flagValue;
290843
+ return flagValue2;
290271
290844
  }
290272
290845
  if (!interactive) return fallback;
290273
290846
  const value = await prompt();
290274
290847
  bailIfCancelled(value);
290275
290848
  return value;
290276
290849
  }
290277
- async function chooseBool(flagValue, fallback, interactive, prompt) {
290278
- if (flagValue !== void 0) return flagValue;
290850
+ async function chooseBool(flagValue2, fallback, interactive, prompt) {
290851
+ if (flagValue2 !== void 0) return flagValue2;
290279
290852
  if (!interactive) return fallback;
290280
290853
  const value = await prompt();
290281
290854
  bailIfCancelled(value);
@@ -290286,7 +290859,7 @@ async function ensureInitProject(opts) {
290286
290859
  const slug = opts.project ?? projectSlugFromPackageName(
290287
290860
  (() => {
290288
290861
  try {
290289
- return JSON.parse((0, import_node_fs6.readFileSync)("package.json", "utf8")).name;
290862
+ return JSON.parse((0, import_node_fs7.readFileSync)("package.json", "utf8")).name;
290290
290863
  } catch {
290291
290864
  return void 0;
290292
290865
  }
@@ -290296,7 +290869,7 @@ async function ensureInitProject(opts) {
290296
290869
  const ensured = await ensureProject(slug);
290297
290870
  if (ensured) {
290298
290871
  console.log(
290299
- ` ${import_picocolors30.default.green("\u2713")} ${ensured.created ? "Created" : "Using"} project ${import_picocolors30.default.bold(ensured.slug)} ${import_picocolors30.default.dim(`(${ensured.id})`)} \u2014 keys you mint for it are isolated from the org's other apps.`
290872
+ ` ${import_picocolors31.default.green("\u2713")} ${ensured.created ? "Created" : "Using"} project ${import_picocolors31.default.bold(ensured.slug)} ${import_picocolors31.default.dim(`(${ensured.id})`)} \u2014 keys you mint for it are isolated from the org's other apps.`
290300
290873
  );
290301
290874
  }
290302
290875
  }
@@ -290308,16 +290881,16 @@ function renderWritePlan(actions) {
290308
290881
  }
290309
290882
  function renderAppliedWrites(actions) {
290310
290883
  return actions.map((action) => {
290311
- const status2 = action.kind === "create" ? import_picocolors30.default.green("created") : action.kind === "update" ? import_picocolors30.default.yellow("updated") : import_picocolors30.default.dim("unchanged");
290312
- return `${import_picocolors30.default.green("\u2713")} ${action.path}${action.note ?? ""} ${import_picocolors30.default.dim(`(${status2})`)}`;
290884
+ const status2 = action.kind === "create" ? import_picocolors31.default.green("created") : action.kind === "update" ? import_picocolors31.default.yellow("updated") : import_picocolors31.default.dim("unchanged");
290885
+ return `${import_picocolors31.default.green("\u2713")} ${action.path}${action.note ?? ""} ${import_picocolors31.default.dim(`(${status2})`)}`;
290313
290886
  }).join("\n");
290314
290887
  }
290315
290888
  async function runInit(args = []) {
290316
290889
  const opts = parseInitArgs(args);
290317
290890
  const interactive = Boolean(process.stdin.isTTY) && !opts.yes && !process.env.CI;
290318
- Ie(`${brand("ablo")} ${import_picocolors30.default.dim("sync engine")}`);
290319
- if (!(0, import_node_fs6.existsSync)("package.json")) {
290320
- throw new import_errors24.AbloValidationError("No package.json found. Run this from your project root.", {
290891
+ Ie(`${brand("ablo")} ${import_picocolors31.default.dim("sync engine")}`);
290892
+ if (!(0, import_node_fs7.existsSync)("package.json")) {
290893
+ throw new import_errors25.AbloValidationError("No package.json found. Run this from your project root.", {
290321
290894
  code: "cli_invalid_arguments"
290322
290895
  });
290323
290896
  }
@@ -290386,14 +290959,14 @@ async function runInit(args = []) {
290386
290959
  );
290387
290960
  }
290388
290961
  const layout = framework === "nextjs" ? detectNextLayout() : { appBase: "app", aliasBase: "." };
290389
- const abloDir = (0, import_node_path5.join)(layout.aliasBase, "ablo");
290962
+ const abloDir = (0, import_node_path6.join)(layout.aliasBase, "ablo");
290390
290963
  const files = [];
290391
290964
  let schemaSource = generateSchema();
290392
290965
  let schemaNote = "";
290393
290966
  if (pullExisting) {
290394
290967
  const dbUrl = readProjectAdminDatabaseUrl();
290395
290968
  if (!dbUrl) {
290396
- schemaNote = import_picocolors30.default.dim(` (no ${ADMIN_URL_VAR} \u2014 wrote starter; run \`ablo pull\` later)`);
290969
+ schemaNote = import_picocolors31.default.dim(` (no ${ADMIN_URL_VAR} \u2014 wrote starter; run \`ablo pull\` later)`);
290397
290970
  } else {
290398
290971
  try {
290399
290972
  const pulled = await buildSchemaSourceFromDb({
@@ -290403,56 +290976,59 @@ async function runInit(args = []) {
290403
290976
  });
290404
290977
  if (pulled.models.length > 0) {
290405
290978
  schemaSource = pulled.source;
290406
- schemaNote = import_picocolors30.default.dim(` (pulled ${pulled.models.length} models)`);
290979
+ schemaNote = import_picocolors31.default.dim(` (pulled ${pulled.models.length} models)`);
290407
290980
  } else {
290408
- schemaNote = import_picocolors30.default.dim(" (no adoptable tables \u2014 wrote starter)");
290981
+ schemaNote = import_picocolors31.default.dim(" (no adoptable tables \u2014 wrote starter)");
290409
290982
  }
290410
290983
  } catch {
290411
- schemaNote = import_picocolors30.default.dim(" (pull failed \u2014 wrote starter)");
290984
+ schemaNote = import_picocolors31.default.dim(" (pull failed \u2014 wrote starter)");
290412
290985
  }
290413
290986
  }
290414
290987
  }
290415
- files.push({ path: (0, import_node_path5.join)(abloDir, "schema.ts"), content: schemaSource, note: schemaNote });
290416
- files.push({ path: (0, import_node_path5.join)(abloDir, "index.ts"), content: generateSyncConfig(auth) });
290417
- files.push({ path: (0, import_node_path5.join)(abloDir, "register.ts"), content: generateRegister() });
290988
+ files.push({ path: (0, import_node_path6.join)(abloDir, "schema.ts"), content: schemaSource, note: schemaNote });
290989
+ files.push({
290990
+ path: (0, import_node_path6.join)(abloDir, "index.ts"),
290991
+ content: generateSyncConfig(auth, { serverOnly: framework === "nextjs" })
290992
+ });
290993
+ files.push({ path: (0, import_node_path6.join)(abloDir, "register.ts"), content: generateRegister() });
290418
290994
  const orm = detectOrm(opts.orm);
290419
290995
  if (storage === "endpoint") {
290420
290996
  files.push({
290421
- path: (0, import_node_path5.join)(abloDir, "data-source.ts"),
290997
+ path: (0, import_node_path6.join)(abloDir, "data-source.ts"),
290422
290998
  content: generateDataSource(orm),
290423
290999
  note: orm === "drizzle" ? " (Drizzle)" : " (Prisma)"
290424
291000
  });
290425
291001
  }
290426
291002
  const envFile = framework === "nextjs" ? ".env.local" : ".env";
290427
291003
  const envBody = generateEnv(storage);
290428
- if (agent) files.push({ path: (0, import_node_path5.join)(abloDir, "agent.ts"), content: generateAgent() });
291004
+ if (agent) files.push({ path: (0, import_node_path6.join)(abloDir, "agent.ts"), content: generateAgent() });
290429
291005
  if (framework === "nextjs") {
290430
291006
  if (storage === "endpoint") {
290431
- const webhookDir = (0, import_node_path5.join)(layout.appBase, "api", "ablo", "webhooks");
291007
+ const webhookDir = (0, import_node_path6.join)(layout.appBase, "api", "ablo", "webhooks");
290432
291008
  files.push({
290433
- path: (0, import_node_path5.join)(webhookDir, "route.ts"),
291009
+ path: (0, import_node_path6.join)(webhookDir, "route.ts"),
290434
291010
  content: generateWebhookRoute(orm),
290435
291011
  note: orm === "prisma" ? " (Prisma mirror)" : " (add your database write)"
290436
291012
  });
290437
291013
  }
290438
291014
  files.push({
290439
- path: (0, import_node_path5.join)(layout.appBase, "providers.tsx"),
291015
+ path: (0, import_node_path6.join)(layout.appBase, "providers.tsx"),
290440
291016
  content: generateProviders(),
290441
- note: ` (wrap ${(0, import_node_path5.join)(layout.appBase, "layout.tsx")} in <Providers>)`
291017
+ note: ` (wrap ${(0, import_node_path6.join)(layout.appBase, "layout.tsx")} in <Providers>)`
290442
291018
  });
290443
291019
  files.push({
290444
- path: (0, import_node_path5.join)(layout.appBase, "api", "ablo-session", "route.ts"),
291020
+ path: (0, import_node_path6.join)(layout.appBase, "api", "ablo-session", "route.ts"),
290445
291021
  content: generateSessionRoute(),
290446
291022
  note: " (wire your auth)"
290447
291023
  });
290448
291024
  }
290449
291025
  if (framework !== "vanilla") {
290450
- files.push({ path: (0, import_node_path5.join)(abloDir, "RecordList.tsx"), content: generateComponent() });
291026
+ files.push({ path: (0, import_node_path6.join)(abloDir, "RecordList.tsx"), content: generateComponent() });
290451
291027
  }
290452
291028
  const writePlan = planInitWrites({ files, environment: { path: envFile, template: envBody } });
290453
291029
  if (writePlan.conflicts.length > 0) {
290454
291030
  const occupied = writePlan.conflicts.map(({ path }) => ` - ${path}`).join("\n");
290455
- throw new import_errors24.AbloValidationError(
291031
+ throw new import_errors25.AbloValidationError(
290456
291032
  `Ablo init did not change any files because these application-owned paths already contain different contents:
290457
291033
  ${occupied}
290458
291034
 
@@ -290462,7 +291038,7 @@ Move them, reconcile Ablo manually, or rerun after they match the generated scaf
290462
291038
  }
290463
291039
  if (opts.plan) {
290464
291040
  Me(renderWritePlan(writePlan.actions), "Plan (no files changed)");
290465
- Se(`Dry run complete. Re-run without ${import_picocolors30.default.bold("--plan")} to apply it.`);
291041
+ Se(`Dry run complete. Re-run without ${import_picocolors31.default.bold("--plan")} to apply it.`);
290466
291042
  return setupInitResultSchema.parse({
290467
291043
  status: "planned",
290468
291044
  plan: projectInitWritePlan(writePlan)
@@ -290479,32 +291055,32 @@ Move them, reconcile Ablo manually, or rerun after they match the generated scaf
290479
291055
  const progress = Y2();
290480
291056
  progress.start("Installing @abloatai/ablo");
290481
291057
  try {
290482
- (0, import_node_child_process3.execFileSync)(packageManager2, ["add", "@abloatai/ablo"], { stdio: "ignore" });
291058
+ (0, import_node_child_process4.execFileSync)(packageManager2, ["add", "@abloatai/ablo"], { stdio: "ignore" });
290483
291059
  progress.stop("Installed @abloatai/ablo");
290484
291060
  } catch {
290485
291061
  progress.stop(
290486
- `${import_picocolors30.default.yellow("!")} Couldn't auto-install \u2014 run ${import_picocolors30.default.bold(`${packageManager2} install @abloatai/ablo`)}`
291062
+ `${import_picocolors31.default.yellow("!")} Couldn't auto-install \u2014 run ${import_picocolors31.default.bold(`${packageManager2} install @abloatai/ablo`)}`
290487
291063
  );
290488
291064
  }
290489
291065
  }
290490
291066
  const steps = [
290491
- `Run ${import_picocolors30.default.bold("npx ablo login")} to authorize branch management`,
290492
- `Set ${import_picocolors30.default.bold("DATABASE_URL")} in ${import_picocolors30.default.bold(envFile)} \u2014 your Postgres is the system of record; rows live there, never with Ablo`,
290493
- `Run ${import_picocolors30.default.bold("npx ablo dev")} \u2014 pushes your schema definition and watches for changes`,
291067
+ `Run ${import_picocolors31.default.bold("npx ablo login")} to authorize branch management`,
291068
+ `Set ${import_picocolors31.default.bold("DATABASE_URL")} in ${import_picocolors31.default.bold(envFile)} \u2014 your Postgres is the system of record; rows live there, never with Ablo`,
291069
+ `Run ${import_picocolors31.default.bold("npx ablo dev")} \u2014 pushes your schema definition and watches for changes`,
290494
291070
  ...storage === "replication" ? [
290495
- `Connect your database \u2014 ${import_picocolors30.default.bold("npx ablo connect")} prints the one-time logical-replication setup SQL to run on your Postgres`,
290496
- `Verify it \u2014 ${import_picocolors30.default.bold("npx ablo connect check")} walks wal_level, the publication, the role, and replica identity, with the exact fix for anything missing`,
290497
- `Register it \u2014 ${import_picocolors30.default.bold("npx ablo connect register")} tells Ablo to start replicating; your app keeps writing through your own backend while Ablo tails the WAL`
291071
+ `Connect your database \u2014 ${import_picocolors31.default.bold("npx ablo connect")} prints the one-time logical-replication setup SQL to run on your Postgres`,
291072
+ `Verify it \u2014 ${import_picocolors31.default.bold("npx ablo connect check")} walks wal_level, the publication, the role, and replica identity, with the exact fix for anything missing`,
291073
+ `Register it \u2014 ${import_picocolors31.default.bold("npx ablo connect register")} tells Ablo to start replicating; your app keeps writing through your own backend while Ablo tails the WAL`
290498
291074
  ] : [
290499
- `Provision your DB: ${import_picocolors30.default.bold("npx ablo migrate")} (creates your Ablo-model tables + the adapter tables; keep your own migrations for everything else), then mount ${import_picocolors30.default.bold(`${abloDir}/data-source.ts`)} at ${import_picocolors30.default.bold("/api/ablo/source")}`
291075
+ `Provision your DB: ${import_picocolors31.default.bold("npx ablo migrate")} (creates your Ablo-model tables + the adapter tables; keep your own migrations for everything else), then mount ${import_picocolors31.default.bold(`${abloDir}/data-source.ts`)} at ${import_picocolors31.default.bold("/api/ablo/source")}`
290500
291076
  ],
290501
291077
  ...framework === "nextjs" ? [
290502
- `Wrap ${import_picocolors30.default.bold((0, import_node_path5.join)(layout.appBase, "layout.tsx"))} in ${import_picocolors30.default.bold("<Providers>")} (${(0, import_node_path5.join)(layout.appBase, "providers.tsx")}) and add your auth to ${import_picocolors30.default.bold((0, import_node_path5.join)(layout.appBase, "api", "ablo-session", "route.ts"))}`
291078
+ `Wrap ${import_picocolors31.default.bold((0, import_node_path6.join)(layout.appBase, "layout.tsx"))} in ${import_picocolors31.default.bold("<Providers>")} (${(0, import_node_path6.join)(layout.appBase, "providers.tsx")}) and add your auth to ${import_picocolors31.default.bold((0, import_node_path6.join)(layout.appBase, "api", "ablo-session", "route.ts"))}`
290503
291079
  ] : [],
290504
- `Run ${import_picocolors30.default.bold(`${packageManager2} run dev`)} and open two browser tabs \u2014 changes sync in real-time`,
291080
+ `Run ${import_picocolors31.default.bold(`${packageManager2} run dev`)} and open two browser tabs \u2014 changes sync in real-time`,
290505
291081
  ...agent ? [
290506
- `Run ${import_picocolors30.default.bold(`npx tsx ${abloDir}/agent.ts`)} \u2014 an AI teammate edits the same records`,
290507
- `Run ${import_picocolors30.default.bold("npx ablo logs")} to watch human + agent commits stream by`
291082
+ `Run ${import_picocolors31.default.bold(`npx tsx ${abloDir}/agent.ts`)} \u2014 an AI teammate edits the same records`,
291083
+ `Run ${import_picocolors31.default.bold("npx ablo logs")} to watch human + agent commits stream by`
290508
291084
  ] : []
290509
291085
  ];
290510
291086
  Me(steps.map((step, index) => `${index + 1}. ${step}`).join("\n"), "Next steps");
@@ -290512,26 +291088,26 @@ Move them, reconcile Ablo manually, or rerun after they match the generated scaf
290512
291088
  if (existingKey) {
290513
291089
  await ensureInitProject(opts);
290514
291090
  Se(
290515
- `Already authorized ${import_picocolors30.default.dim(`(${existingKey.slice(0, 11)}\u2026)`)}. Run ${import_picocolors30.default.bold("npx ablo dev")} next. ${import_picocolors30.default.dim("Docs:")} https://abloatai.com/docs`
291091
+ `Already authorized ${import_picocolors31.default.dim(`(${existingKey.slice(0, 11)}\u2026)`)}. Run ${import_picocolors31.default.bold("npx ablo dev")} next. ${import_picocolors31.default.dim("Docs:")} https://abloatai.com/docs`
290516
291092
  );
290517
291093
  return initResult;
290518
291094
  }
290519
291095
  if (interactive && opts.login) {
290520
291096
  const loginNow = await ye({ message: "Log in now? (opens your browser)", initialValue: true });
290521
291097
  if (!pD(loginNow) && loginNow) {
290522
- Se(`${import_picocolors30.default.dim("Docs:")} https://abloatai.com/docs`);
291098
+ Se(`${import_picocolors31.default.dim("Docs:")} https://abloatai.com/docs`);
290523
291099
  await login();
290524
291100
  await ensureInitProject(opts);
290525
291101
  return initResult;
290526
291102
  }
290527
291103
  }
290528
- Se(`Run ${import_picocolors30.default.bold("npx ablo login")} when ready. ${import_picocolors30.default.dim("Docs:")} https://abloatai.com/docs`);
291104
+ Se(`Run ${import_picocolors31.default.bold("npx ablo login")} when ready. ${import_picocolors31.default.dim("Docs:")} https://abloatai.com/docs`);
290529
291105
  return initResult;
290530
291106
  }
290531
291107
 
290532
291108
  // src/index.ts
290533
291109
  var LOGO = `
290534
- ${brand("ablo")} ${import_picocolors31.default.dim("sync engine")}
291110
+ ${brand("ablo")} ${import_picocolors32.default.dim("sync engine")}
290535
291111
  `;
290536
291112
  var HANDLERS = {
290537
291113
  setup: (argv) => runSetup(argv),
@@ -290547,6 +291123,7 @@ var HANDLERS = {
290547
291123
  whoami: (argv) => whoami([...argv]),
290548
291124
  doctor: (argv) => doctor([...argv]),
290549
291125
  logs: (argv) => logs([...argv]),
291126
+ claims: (argv) => claims([...argv]),
290550
291127
  webhooks: (argv) => webhooks([...argv]),
290551
291128
  check: (argv) => check([...argv]),
290552
291129
  docs: (argv) => docs([...argv]),
@@ -290564,7 +291141,7 @@ async function runDev(argv) {
290564
291141
  const devArgs = [...argv];
290565
291142
  const oneShot = devArgs.includes("--no-watch");
290566
291143
  console.log(
290567
- import_picocolors31.default.dim(
291144
+ import_picocolors32.default.dim(
290568
291145
  oneShot ? " `ablo dev --no-watch` prepares this Git branch and pushes once." : " `ablo dev` prepares this Git branch and watches the schema."
290569
291146
  )
290570
291147
  );
@@ -290582,7 +291159,7 @@ async function runPush2(argv) {
290582
291159
  }
290583
291160
  function runRenamedSchema(argv) {
290584
291161
  const forwarded = argv.slice(1).join(" ");
290585
- console.error(` ${import_picocolors31.default.red("\u2717")} \`ablo schema push\` was renamed to \`${brand("ablo push")}\`.`);
291162
+ console.error(` ${import_picocolors32.default.red("\u2717")} \`ablo schema push\` was renamed to \`${brand("ablo push")}\`.`);
290586
291163
  console.error(` Run \`ablo push${forwarded ? " " + forwarded : ""}\` instead.`);
290587
291164
  process.exitCode = 1;
290588
291165
  }
@@ -290592,7 +291169,7 @@ async function main() {
290592
291169
  const argv = process.argv.slice(3);
290593
291170
  if (!command && raw !== void 0 && raw !== "help" && !raw.startsWith("-")) {
290594
291171
  const suggestion = suggestCommand(raw);
290595
- throw new import_errors25.AbloValidationError(
291172
+ throw new import_errors26.AbloValidationError(
290596
291173
  `\`${raw}\` isn't an ablo command.` + (suggestion ? ` Did you mean \`ablo ${suggestion}\`?` : " Run `ablo help --all` to see every command."),
290597
291174
  { code: "cli_invalid_arguments" }
290598
291175
  );
@@ -290633,7 +291210,7 @@ function printCoreHelp() {
290633
291210
  const width = Math.max(...rows.map((r2) => r2.run.length)) + 4;
290634
291211
  console.log(LOGO);
290635
291212
  for (const group of CORE_GROUPS) {
290636
- console.log(` ${import_picocolors31.default.bold(group)}`);
291213
+ console.log(` ${import_picocolors32.default.bold(group)}`);
290637
291214
  const printed = group === "More" ? [...coreRows(group), ...extra] : coreRows(group);
290638
291215
  for (const row of printed) console.log(` npx ablo ${row.run.padEnd(width)}${row.does}`);
290639
291216
  console.log();
@@ -290642,7 +291219,7 @@ function printCoreHelp() {
290642
291219
  }
290643
291220
  function printSchemaReminder() {
290644
291221
  console.log(
290645
- import_picocolors31.default.dim(` Edit ${import_picocolors31.default.bold("ablo/schema.ts")}, then push \u2014 writes to models you haven't pushed fail with `) + import_picocolors31.default.yellow("server_execute_unknown_model") + import_picocolors31.default.dim(".")
291222
+ import_picocolors32.default.dim(` Edit ${import_picocolors32.default.bold("ablo/schema.ts")}, then push \u2014 writes to models you haven't pushed fail with `) + import_picocolors32.default.yellow("server_execute_unknown_model") + import_picocolors32.default.dim(".")
290646
291223
  );
290647
291224
  console.log();
290648
291225
  }
@@ -290652,7 +291229,7 @@ function printFullHelp() {
290652
291229
  ) + 2;
290653
291230
  console.log(LOGO);
290654
291231
  for (const group of FULL_GROUPS) {
290655
- console.log(` ${import_picocolors31.default.bold(group)}`);
291232
+ console.log(` ${import_picocolors32.default.bold(group)}`);
290656
291233
  for (const row of fullRows(group)) {
290657
291234
  console.log(row.does === void 0 ? ` ${" ".repeat(9)}${row.run}` : ` npx ablo ${row.run.padEnd(width)}${row.does}`);
290658
291235
  }