@abloatai/ablo 0.33.0 → 0.34.1

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 (45) hide show
  1. package/AGENTS.md +2 -0
  2. package/CHANGELOG.md +22 -0
  3. package/dist/cli.cjs +500 -383
  4. package/dist/client/Ablo.js +3 -2
  5. package/dist/client/createModelProxy.d.ts +53 -10
  6. package/dist/client/createModelProxy.js +24 -5
  7. package/dist/client/httpTransport.js +1 -0
  8. package/dist/client/resourceTypes.d.ts +10 -1
  9. package/dist/client/wsMutationExecutor.d.ts +2 -2
  10. package/dist/client/wsMutationExecutor.js +1 -1
  11. package/dist/coordination/index.d.ts +2 -2
  12. package/dist/coordination/index.js +1 -1
  13. package/dist/coordination/schema.d.ts +20 -0
  14. package/dist/coordination/schema.js +22 -0
  15. package/dist/errorCodes.d.ts +1 -1
  16. package/dist/errorCodes.js +1 -1
  17. package/dist/interfaces/index.d.ts +13 -1
  18. package/dist/react/AbloProvider.d.ts +8 -8
  19. package/dist/react/AbloProvider.js +6 -6
  20. package/dist/react/index.d.ts +2 -2
  21. package/dist/react/index.js +2 -2
  22. package/dist/server/commit.d.ts +8 -1
  23. package/dist/surface.d.ts +1 -1
  24. package/dist/surface.js +2 -1
  25. package/dist/sync/SyncWebSocket.d.ts +3 -3
  26. package/dist/sync/SyncWebSocket.js +4 -4
  27. package/dist/sync/commitFrames.d.ts +2 -2
  28. package/dist/sync/commitFrames.js +5 -1
  29. package/dist/transactions/TransactionQueue.d.ts +4 -1
  30. package/dist/transactions/TransactionQueue.js +18 -0
  31. package/dist/transactions/commitEnvelope.d.ts +8 -0
  32. package/dist/transactions/commitEnvelope.js +2 -1
  33. package/dist/transactions/durableWriteStore.d.ts +8 -0
  34. package/dist/wire/frames.d.ts +17 -1
  35. package/dist/wire/frames.js +2 -1
  36. package/docs/client-behavior.md +1 -1
  37. package/docs/coordination.md +5 -5
  38. package/docs/groups.md +50 -0
  39. package/docs/identity.md +2 -2
  40. package/docs/index.md +2 -0
  41. package/docs/migration.md +29 -5
  42. package/docs/operating-on-your-database.md +109 -0
  43. package/docs/react.md +9 -9
  44. package/llms.txt +1 -1
  45. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -787,8 +787,8 @@ ${import_picocolors2.default.gray(d2)} ${t}
787
787
  if (i) process.stdout.write(`${I2} ${l2}...`);
788
788
  else if (t === "timer") process.stdout.write(`${I2} ${l2} ${O2(g2)}`);
789
789
  else {
790
- const z8 = ".".repeat(Math.floor(w2)).slice(0, 3);
791
- process.stdout.write(`${I2} ${l2}${z8}`);
790
+ const z9 = ".".repeat(Math.floor(w2)).slice(0, 3);
791
+ process.stdout.write(`${I2} ${l2}${z9}`);
792
792
  }
793
793
  h2 = h2 + 1 < n.length ? h2 + 1 : 0, w2 = w2 < n.length ? w2 + 0.125 : 0;
794
794
  }, r2);
@@ -909,7 +909,7 @@ var init_errorCodes = __esm({
909
909
  model_claimed: wire("claim", 409, false, "Another participant holds a claim on this row. Read `claim.state` to see who holds it, or queue behind them with a claim of your own."),
910
910
  model_claimed_timeout: wire("claim", 409, false, "Another participant held a claim on this row and did not release it in time. Retry, or read `claim.state` to see who holds it."),
911
911
  model_claim_not_configured: client("claim", "Claiming requires the collaboration runtime, which the standard Ablo({ schema, apiKey }) client wires up for every model automatically \u2014 there is no per-model claim configuration to add. This appears only when a model proxy is constructed directly without that runtime (an internal/advanced path)."),
912
- model_watch_not_configured: client("claim", "watch() opens a presence/claim subscription and needs a live WebSocket, so it is unavailable on the HTTP transport and on model proxies built without a socket. Use the standard Ablo({ schema, apiKey }) client (default WebSocket transport)."),
912
+ model_join_not_configured: client("claim", "join() opens a presence/claim subscription and needs a live WebSocket, so it is unavailable on the HTTP transport and on model proxies built without a socket. Use the standard Ablo({ schema, apiKey }) client (default WebSocket transport)."),
913
913
  // ── stale context / idempotency (409) ──────────────────────────────
914
914
  // Not retryable at the transport: the rejected request carries its frozen
915
915
  // `readAt`, so resending the identical payload can never succeed. Recovery
@@ -1199,7 +1199,7 @@ var init_roles = __esm({
1199
1199
  });
1200
1200
 
1201
1201
  // src/coordination/schema.ts
1202
- var import_zod3, targetRangeSchema, participantKindSchema, wireParticipantKindSchema, targetRefSchema, onStaleModeSchema, writeGuardSchema, staleNotificationSchema, readDependencySchema, claimStatusSchema, grantStampFields, wireClaimBaseSchema, wireClaimSummarySchema, claimErrorSchema, wireClaimSchema, claimRejectionSchema, claimLostSchema, modelTargetSchema, modelClaimSchema, claimBeginPayloadSchema, claimAbandonPayloadSchema, claimReorderPayloadSchema, claimHeartbeatFieldsSchema, claimHeartbeatPayloadSchema, claimHeartbeatAckPayloadSchema, claimHeartbeatBatchPayloadSchema, claimHeartbeatBatchAckPayloadSchema, updateSubscriptionPayloadSchema, subscriptionAckPayloadSchema, commitOperationTypeSchema, commitOperationSchema, presenceKindSchema, presenceActivitySchema, presenceUpdateFrameSchema;
1202
+ var import_zod3, targetRangeSchema, participantKindSchema, wireParticipantKindSchema, targetRefSchema, onStaleModeSchema, writeGuardSchema, staleNotificationSchema, readDependencySchema, trackDependencySchema, claimStatusSchema, grantStampFields, wireClaimBaseSchema, wireClaimSummarySchema, claimErrorSchema, wireClaimSchema, claimRejectionSchema, claimLostSchema, modelTargetSchema, modelClaimSchema, claimBeginPayloadSchema, claimAbandonPayloadSchema, claimReorderPayloadSchema, claimHeartbeatFieldsSchema, claimHeartbeatPayloadSchema, claimHeartbeatAckPayloadSchema, claimHeartbeatBatchPayloadSchema, claimHeartbeatBatchAckPayloadSchema, updateSubscriptionPayloadSchema, subscriptionAckPayloadSchema, commitOperationTypeSchema, commitOperationSchema, presenceKindSchema, presenceActivitySchema, presenceUpdateFrameSchema;
1203
1203
  var init_schema = __esm({
1204
1204
  "src/coordination/schema.ts"() {
1205
1205
  "use strict";
@@ -1284,6 +1284,17 @@ var init_schema = __esm({
1284
1284
  onStale: onStaleModeSchema.optional()
1285
1285
  })
1286
1286
  ]);
1287
+ trackDependencySchema = import_zod3.z.union([
1288
+ import_zod3.z.object({
1289
+ model: import_zod3.z.string(),
1290
+ id: import_zod3.z.string(),
1291
+ readAt: import_zod3.z.number().optional()
1292
+ }),
1293
+ import_zod3.z.object({
1294
+ group: import_zod3.z.string(),
1295
+ readAt: import_zod3.z.number().optional()
1296
+ })
1297
+ ]);
1287
1298
  claimStatusSchema = import_zod3.z.enum([
1288
1299
  "active",
1289
1300
  "committed",
@@ -5594,7 +5605,8 @@ async function registerDirectDataSource(opts) {
5594
5605
  console.log(
5595
5606
  `
5596
5607
  ${import_picocolors6.default.green("\u2713")} Registered${body2.host ? ` ${import_picocolors6.default.dim(body2.host)}` : ""}${body2.id ? ` ${import_picocolors6.default.dim(`(${body2.id})`)}` : ""} as a direct DataSource (${statusNote}).
5597
- Customer COMMIT is durable acceptance; correlated WAL promotes queued writes to confirmed.
5608
+ Your database is connected. Reads follow its replication stream; writes go through Ablo
5609
+ and land in your own tables. Check the connection anytime with ${import_picocolors6.default.cyan("ablo connect check")}.
5598
5610
  `
5599
5611
  );
5600
5612
  return true;
@@ -5829,12 +5841,130 @@ var init_disconnect = __esm({
5829
5841
  }
5830
5842
  });
5831
5843
 
5844
+ // src/cli/connectOwnership.ts
5845
+ function ownershipBlockers(rows) {
5846
+ return rows.filter((row) => !row.can_manage && !row.is_superuser).map((row) => ({
5847
+ relation: row.relation,
5848
+ owner: row.owner,
5849
+ canGrantInherit: row.can_grant_inherit
5850
+ }));
5851
+ }
5852
+ function ownershipRemediation(blockers, admin) {
5853
+ const grantableByOwner = /* @__PURE__ */ new Map();
5854
+ for (const blocker of blockers) {
5855
+ grantableByOwner.set(
5856
+ blocker.owner,
5857
+ (grantableByOwner.get(blocker.owner) ?? false) || blocker.canGrantInherit
5858
+ );
5859
+ }
5860
+ const resolvedOwners = /* @__PURE__ */ new Set();
5861
+ const inheritGrants = [];
5862
+ for (const [owner, grantable] of grantableByOwner) {
5863
+ if (grantable) {
5864
+ inheritGrants.push(`GRANT ${quoteIdent(owner)} TO ${quoteIdent(admin)} WITH INHERIT TRUE;`);
5865
+ resolvedOwners.add(owner);
5866
+ }
5867
+ }
5868
+ const unresolved = blockers.filter((blocker) => !resolvedOwners.has(blocker.owner));
5869
+ return { inheritGrants, unresolved };
5870
+ }
5871
+ async function publishedTableBlockers(sql, tables) {
5872
+ const scoped = tables.length > 0;
5873
+ const raw = await sql.unsafe(
5874
+ `SELECT format('%I.%I', n.nspname, c.relname) AS relation, ${OWNERSHIP_COLUMNS}
5875
+ ${OWNERSHIP_FROM}
5876
+ WHERE c.relkind = 'r'
5877
+ AND n.nspname = 'public'
5878
+ AND c.relname <> 'ablo_idempotency'
5879
+ ${scoped ? "AND c.relname = ANY($1)" : ""}`,
5880
+ scoped ? [tables] : []
5881
+ );
5882
+ return ownershipBlockers(import_zod7.z.array(ownedRelationRowSchema).parse(raw));
5883
+ }
5884
+ async function ledgerBlocker(sql) {
5885
+ const raw = await sql.unsafe(
5886
+ `SELECT format('%I.%I', n.nspname, c.relname) AS relation, ${OWNERSHIP_COLUMNS}
5887
+ ${OWNERSHIP_FROM}
5888
+ WHERE c.relkind = 'r'
5889
+ AND n.nspname = 'public'
5890
+ AND c.relname = 'ablo_idempotency'`
5891
+ );
5892
+ const rows = import_zod7.z.array(ownedRelationRowSchema).parse(raw);
5893
+ const row = rows[0];
5894
+ if (!row) return null;
5895
+ return ownershipBlockers([row])[0] ?? null;
5896
+ }
5897
+ function formatUnresolvedOwnership(unresolved, admin, target) {
5898
+ const list = unresolved.map((b4) => `${b4.relation} (owned by ${b4.owner})`).join("\n ");
5899
+ const owners = [...new Set(unresolved.map((b4) => b4.owner))];
5900
+ const ownerNames = owners.map((o2) => import_picocolors8.default.bold(o2)).join(", ");
5901
+ const grants = owners.map((o2) => `GRANT ${quoteIdent(o2)} TO ${quoteIdent(admin)} WITH INHERIT TRUE;`).join(" ");
5902
+ const one = unresolved.length === 1;
5903
+ const hasLedger = unresolved.some((b4) => b4.relation.endsWith(".ablo_idempotency"));
5904
+ return import_picocolors8.default.red(
5905
+ `
5906
+ ${import_picocolors8.default.bold(String(unresolved.length))} relation${one ? "" : "s"} on ${target} ${one ? "is" : "are"} owned by a role ${import_picocolors8.default.bold(admin)} can't manage or take over:`
5907
+ ) + `
5908
+ ${list}
5909
+
5910
+ Apply grants your admin inheritance of an owning role for you when it may, but ${admin}
5911
+ isn't a member with admin option of ${ownerNames}, so it can't here. Re-run ${import_picocolors8.default.bold("--url")} as a
5912
+ role that owns ${one ? "it" : "them"}, or have a role with admin option on ${ownerNames} (or a
5913
+ superuser) run:
5914
+ ${import_picocolors8.default.cyan(grants)}
5915
+ ` + (hasLedger ? `
5916
+ For ${import_picocolors8.default.bold("ablo_idempotency")} you can instead drop it \u2014 it holds only idempotency replay
5917
+ records, safe to drop when no commit is in flight \u2014 and Ablo recreates it under this admin:
5918
+ ${import_picocolors8.default.cyan("DROP TABLE ablo_idempotency;")}
5919
+ ` : "");
5920
+ }
5921
+ var import_zod7, import_picocolors8, ownedRelationRowSchema, OWNERSHIP_COLUMNS, OWNERSHIP_FROM;
5922
+ var init_connectOwnership = __esm({
5923
+ "src/cli/connectOwnership.ts"() {
5924
+ "use strict";
5925
+ init_cjs_shims();
5926
+ import_zod7 = require("zod");
5927
+ import_picocolors8 = __toESM(require_picocolors(), 1);
5928
+ init_connectSetup();
5929
+ ownedRelationRowSchema = import_zod7.z.object({
5930
+ /** Schema-qualified relation, e.g. `public.documents`. */
5931
+ relation: import_zod7.z.string(),
5932
+ owner: import_zod7.z.string(),
5933
+ /**
5934
+ * The admin can act as the owner for grants — it owns the relation OR is an
5935
+ * INHERITing member of the owning role (`pg_has_role(current_user, owner,
5936
+ * 'USAGE')`). A plain NOINHERIT membership is false: the plan doesn't
5937
+ * `SET ROLE`, so the grant would fail.
5938
+ */
5939
+ can_manage: import_zod7.z.boolean(),
5940
+ is_superuser: import_zod7.z.boolean(),
5941
+ /**
5942
+ * The admin is a member of the owning role WITH admin option, so it can run
5943
+ * `GRANT <owner> TO <admin> WITH INHERIT TRUE` itself to gain the inheritance
5944
+ * the grants need — the runnable fix reassigning ownership can't be.
5945
+ */
5946
+ can_grant_inherit: import_zod7.z.boolean()
5947
+ });
5948
+ OWNERSHIP_COLUMNS = `
5949
+ pg_get_userbyid(c.relowner) AS owner,
5950
+ pg_has_role(current_user, c.relowner, 'USAGE') AS can_manage,
5951
+ r.rolsuper AS is_superuser,
5952
+ EXISTS (
5953
+ SELECT 1 FROM pg_auth_members m
5954
+ WHERE m.member = r.oid AND m.roleid = c.relowner AND m.admin_option
5955
+ ) AS can_grant_inherit`;
5956
+ OWNERSHIP_FROM = `
5957
+ FROM pg_class c
5958
+ JOIN pg_namespace n ON n.oid = c.relnamespace
5959
+ JOIN pg_roles r ON r.rolname = current_user`;
5960
+ }
5961
+ });
5962
+
5832
5963
  // src/cli/connectApply.ts
5833
5964
  var connectApply_exports = {};
5834
5965
  __export(connectApply_exports, {
5835
5966
  connectApplyPlan: () => connectApplyPlan,
5836
5967
  detectProvider: () => detectProvider,
5837
- ledgerBlockedBy: () => ledgerBlockedBy,
5838
5968
  logicalReplicationGuidance: () => logicalReplicationGuidance,
5839
5969
  passwordClause: () => passwordClause,
5840
5970
  postRegistrationOutcome: () => postRegistrationOutcome,
@@ -5890,7 +6020,16 @@ EXCEPTION WHEN duplicate_object THEN NULL;
5890
6020
  END $$;`
5891
6021
  ];
5892
6022
  const publicationDetail = reconcile2?.sql.length === 0 ? "already publishing exactly these tables \u2014 nothing to change" : tables.length > 0 ? `a read stream of the ${tables.length} table${tables.length === 1 ? "" : "s"} you chose` : "a read stream of your tables";
6023
+ const ownStep = input.inheritGrants && input.inheritGrants.length > 0 ? [
6024
+ {
6025
+ key: "own",
6026
+ title: "Let this admin manage tables owned by another role",
6027
+ detail: "your admin inherits the owning role so the steps below apply \u2014 reversible, no ownership change",
6028
+ sql: input.inheritGrants
6029
+ }
6030
+ ] : [];
5893
6031
  return [
6032
+ ...ownStep,
5894
6033
  ...walStep,
5895
6034
  {
5896
6035
  key: "publication",
@@ -5932,15 +6071,15 @@ function printPlan2(steps, showSql) {
5932
6071
  console.log(` This sets up your database for Ablo:
5933
6072
  `);
5934
6073
  for (const step of steps) {
5935
- console.log(` ${import_picocolors8.default.green("\u2022")} ${step.title}`);
6074
+ console.log(` ${import_picocolors9.default.green("\u2022")} ${step.title}`);
5936
6075
  if (showSql) {
5937
6076
  for (const statement of step.sql) {
5938
- for (const line of statement.split("\n")) console.log(` ${import_picocolors8.default.dim(line)}`);
6077
+ for (const line of statement.split("\n")) console.log(` ${import_picocolors9.default.dim(line)}`);
5939
6078
  }
5940
6079
  }
5941
6080
  }
5942
6081
  console.log(
5943
- import_picocolors8.default.dim(
6082
+ import_picocolors9.default.dim(
5944
6083
  `
5945
6084
  Your admin password stays on this machine.${showSql ? "" : " (--show-sql for the exact statements)"}
5946
6085
  `
@@ -5953,24 +6092,6 @@ async function adminCanCreateRoles(sql) {
5953
6092
  );
5954
6093
  return rows[0] ?? null;
5955
6094
  }
5956
- function ledgerBlockedBy(row) {
5957
- if (!row || row.is_owner || row.is_superuser) return null;
5958
- return row.owner;
5959
- }
5960
- async function unmanageableLedgerOwner(sql) {
5961
- const rows = await sql.unsafe(
5962
- `SELECT pg_get_userbyid(c.relowner) AS owner,
5963
- c.relowner = r.oid AS is_owner,
5964
- r.rolsuper AS is_superuser
5965
- FROM pg_class c
5966
- JOIN pg_namespace n ON n.oid = c.relnamespace
5967
- JOIN pg_roles r ON r.rolname = current_user
5968
- WHERE c.relkind = 'r'
5969
- AND c.relname = 'ablo_idempotency'
5970
- AND n.nspname = 'public'`
5971
- );
5972
- return ledgerBlockedBy(rows[0]);
5973
- }
5974
6095
  function detectProvider(hostOrTarget) {
5975
6096
  const host = hostOrTarget.toLowerCase();
5976
6097
  if (host.includes("neon.tech")) return "neon";
@@ -6029,8 +6150,8 @@ async function runConnectApply(args) {
6029
6150
  const adminUrl = args.url ?? readProjectAdminDatabaseUrl();
6030
6151
  if (!adminUrl) {
6031
6152
  console.error(
6032
- import_picocolors8.default.red(" No admin connection string.") + import_picocolors8.default.dim(
6033
- ` Pass ${import_picocolors8.default.bold("--url <admin-conn>")} (or set ${import_picocolors8.default.bold("DATABASE_URL")}) and re-run.`
6153
+ import_picocolors9.default.red(" No admin connection string.") + import_picocolors9.default.dim(
6154
+ ` Pass ${import_picocolors9.default.bold("--url <admin-conn>")} (or set ${import_picocolors9.default.bold("DATABASE_URL")}) and re-run.`
6034
6155
  )
6035
6156
  );
6036
6157
  process.exit(1);
@@ -6045,19 +6166,19 @@ async function runConnectApply(args) {
6045
6166
  const apiKey = resolveApiKey();
6046
6167
  if (!apiKey) {
6047
6168
  console.error(
6048
- import_picocolors8.default.red(" Not logged in.") + import_picocolors8.default.dim(
6049
- ` Run ${import_picocolors8.default.bold("ablo login")} (or set ${import_picocolors8.default.bold("ABLO_API_KEY")}) so Ablo knows which project to register this database for.`
6169
+ import_picocolors9.default.red(" Not logged in.") + import_picocolors9.default.dim(
6170
+ ` Run ${import_picocolors9.default.bold("ablo login")} (or set ${import_picocolors9.default.bold("ABLO_API_KEY")}) so Ablo knows which project to register this database for.`
6050
6171
  )
6051
6172
  );
6052
6173
  process.exit(1);
6053
6174
  }
6054
6175
  console.log(
6055
6176
  `
6056
- ${brand("ablo")} ${import_picocolors8.default.dim(verb)} ${import_picocolors8.default.dim(rotating ? "re-key the scoped roles" : "set up your database for Ablo")}
6177
+ ${brand("ablo")} ${import_picocolors9.default.dim(verb)} ${import_picocolors9.default.dim(rotating ? "re-key the scoped roles" : "set up your database for Ablo")}
6057
6178
  `
6058
6179
  );
6059
6180
  console.log(
6060
- ` ${import_picocolors8.default.dim("\u2192")} ${import_picocolors8.default.bold(target)}${adminSource === "DATABASE_URL" ? import_picocolors8.default.dim(" (admin via DATABASE_URL)") : ""}
6181
+ ` ${import_picocolors9.default.dim("\u2192")} ${import_picocolors9.default.bold(target)}${adminSource === "DATABASE_URL" ? import_picocolors9.default.dim(" (admin via DATABASE_URL)") : ""}
6061
6182
  `
6062
6183
  );
6063
6184
  const admin = src_default(adminUrl, {
@@ -6073,31 +6194,25 @@ async function runConnectApply(args) {
6073
6194
  } catch (err) {
6074
6195
  await admin.end({ timeout: 2 }).catch(() => void 0);
6075
6196
  const pg = err ?? {};
6076
- console.error(import_picocolors8.default.red(` Couldn't connect: ${pg.message ?? String(err)}`));
6197
+ console.error(import_picocolors9.default.red(` Couldn't connect: ${pg.message ?? String(err)}`));
6077
6198
  process.exit(1);
6078
6199
  }
6079
6200
  if (!capability || !(capability.rolsuper || capability.rolcreaterole)) {
6080
6201
  await admin.end({ timeout: 2 });
6081
6202
  console.error(
6082
- import_picocolors8.default.red(` ${capability?.rolname ?? "This role"} can't create roles.`) + import_picocolors8.default.dim(` Point ${import_picocolors8.default.bold("--url")} at your owner/admin connection and re-run.`)
6203
+ import_picocolors9.default.red(` ${capability?.rolname ?? "This role"} can't create roles.`) + import_picocolors9.default.dim(` Point ${import_picocolors9.default.bold("--url")} at your owner/admin connection and re-run.`)
6083
6204
  );
6084
6205
  process.exit(1);
6085
6206
  }
6086
- const blockingOwner = await unmanageableLedgerOwner(admin).catch(() => null);
6087
- if (blockingOwner) {
6207
+ const ledger = await ledgerBlocker(admin).catch(() => null);
6208
+ const foreignTables = await publishedTableBlockers(admin, args.tables).catch(() => []);
6209
+ const { inheritGrants, unresolved } = ownershipRemediation(
6210
+ [...ledger ? [ledger] : [], ...foreignTables],
6211
+ capability.rolname
6212
+ );
6213
+ if (unresolved.length > 0) {
6088
6214
  await admin.end({ timeout: 2 });
6089
- console.error(
6090
- import_picocolors8.default.red(
6091
- `
6092
- ${import_picocolors8.default.bold("ablo_idempotency")} already exists on ${target}, owned by ${import_picocolors8.default.bold(blockingOwner)}, but you connected as ${import_picocolors8.default.bold(capability.rolname)}.`
6093
- ) + `
6094
- Ablo's setup grants the writer role access to this ledger, and Postgres reserves that
6095
- for the table's owner. Either re-run pointing ${import_picocolors8.default.bold("--url")} at ${import_picocolors8.default.bold(blockingOwner)}'s connection,
6096
- or drop the existing ledger so Ablo recreates it under this admin \u2014 it holds only
6097
- idempotency replay records, safe to drop when no commit is in flight:
6098
- ${import_picocolors8.default.cyan("DROP TABLE ablo_idempotency;")}
6099
- `
6100
- );
6215
+ console.error(formatUnresolvedOwnership(unresolved, capability.rolname, target));
6101
6216
  process.exit(1);
6102
6217
  }
6103
6218
  const provider = detectProvider(target);
@@ -6118,18 +6233,19 @@ async function runConnectApply(args) {
6118
6233
  },
6119
6234
  walAlreadyLogical: walReady,
6120
6235
  provider,
6121
- existingPublication
6236
+ existingPublication,
6237
+ inheritGrants
6122
6238
  });
6123
6239
  const steps = buildPlan("scram-verifier");
6124
6240
  if (pubReconcile.removed.length > 0 || pubReconcile.recreated) {
6125
6241
  console.log(
6126
- ` ${import_picocolors8.default.yellow("!")} ${import_picocolors8.default.bold(ABLO_PUBLICATION)} already publishes a different set; reconciling to your ${import_picocolors8.default.bold("--tables")}:`
6242
+ ` ${import_picocolors9.default.yellow("!")} ${import_picocolors9.default.bold(ABLO_PUBLICATION)} already publishes a different set; reconciling to your ${import_picocolors9.default.bold("--tables")}:`
6127
6243
  );
6128
- for (const t of pubReconcile.added) console.log(` ${import_picocolors8.default.green("+")} ${t}`);
6244
+ for (const t of pubReconcile.added) console.log(` ${import_picocolors9.default.green("+")} ${t}`);
6129
6245
  for (const t of pubReconcile.removed)
6130
- console.log(` ${import_picocolors8.default.red("-")} ${t} ${import_picocolors8.default.dim("(stops replicating to Ablo)")}`);
6246
+ console.log(` ${import_picocolors9.default.red("-")} ${t} ${import_picocolors9.default.dim("(stops replicating to Ablo)")}`);
6131
6247
  if (pubReconcile.recreated && existingPublication.allTables)
6132
- console.log(` ${import_picocolors8.default.red("-")} ${import_picocolors8.default.dim("every other table (was FOR ALL TABLES)")}`);
6248
+ console.log(` ${import_picocolors9.default.red("-")} ${import_picocolors9.default.dim("every other table (was FOR ALL TABLES)")}`);
6133
6249
  console.log();
6134
6250
  }
6135
6251
  printPlan2(steps, args.showSql);
@@ -6137,7 +6253,7 @@ async function runConnectApply(args) {
6137
6253
  if (!process.stdout.isTTY) {
6138
6254
  await admin.end({ timeout: 2 });
6139
6255
  console.error(
6140
- import_picocolors8.default.dim(` Re-run with ${import_picocolors8.default.bold("--yes")} to apply this in a non-interactive session.
6256
+ import_picocolors9.default.dim(` Re-run with ${import_picocolors9.default.bold("--yes")} to apply this in a non-interactive session.
6141
6257
  `)
6142
6258
  );
6143
6259
  process.exit(1);
@@ -6149,7 +6265,7 @@ async function runConnectApply(args) {
6149
6265
  if (pD(proceed) || !proceed) {
6150
6266
  await admin.end({ timeout: 2 });
6151
6267
  console.log(
6152
- import_picocolors8.default.dim(` Nothing applied. Run ${import_picocolors8.default.bold("ablo connect")} to see the manual recipe.
6268
+ import_picocolors9.default.dim(` Nothing applied. Run ${import_picocolors9.default.bold("ablo connect")} to see the manual recipe.
6153
6269
  `)
6154
6270
  );
6155
6271
  process.exit(0);
@@ -6161,8 +6277,8 @@ async function runConnectApply(args) {
6161
6277
  await admin.end({ timeout: 2 }).catch(() => void 0);
6162
6278
  const pg = err ?? {};
6163
6279
  console.error(
6164
- import_picocolors8.default.red(`
6165
- Setup stopped: ${pg.message ?? String(err)}`) + import_picocolors8.default.dim(` Every step is safe to re-run.
6280
+ import_picocolors9.default.red(`
6281
+ Setup stopped: ${pg.message ?? String(err)}`) + import_picocolors9.default.dim(` Every step is safe to re-run.
6166
6282
  `)
6167
6283
  );
6168
6284
  process.exit(1);
@@ -6173,14 +6289,14 @@ async function runConnectApply(args) {
6173
6289
  const replicationUrl = rewriteDatabaseUrl(adminUrl, role, replicationPassword);
6174
6290
  const writeUrl = rewriteDatabaseUrl(adminUrl, writeRole, writePassword);
6175
6291
  console.log(`
6176
- ${import_picocolors8.default.green("\u2713")} Roles ${rotating ? "re-keyed" : "created"}.
6292
+ ${import_picocolors9.default.green("\u2713")} Roles ${rotating ? "re-keyed" : "created"}.
6177
6293
  `);
6178
6294
  if (!walReady) {
6179
6295
  console.error(
6180
- ` ${import_picocolors8.default.yellow("!")} One step left \u2014 logical replication isn't on yet.
6296
+ ` ${import_picocolors9.default.yellow("!")} One step left \u2014 logical replication isn't on yet.
6181
6297
  ${logicalReplicationGuidance(provider)}.
6182
6298
 
6183
- Then re-run: ${import_picocolors8.default.cyan(`npx ablo ${verb}`)}
6299
+ Then re-run: ${import_picocolors9.default.cyan(`npx ablo ${verb}`)}
6184
6300
  `
6185
6301
  );
6186
6302
  process.exit(1);
@@ -6197,15 +6313,15 @@ async function runConnectApply(args) {
6197
6313
  items = await probeReadiness(verifier);
6198
6314
  } catch {
6199
6315
  items = null;
6200
- console.log(import_picocolors8.default.dim(` Couldn't verify from here; Ablo will validate from its own network.
6316
+ console.log(import_picocolors9.default.dim(` Couldn't verify from here; Ablo will validate from its own network.
6201
6317
  `));
6202
6318
  }
6203
6319
  await verifier.end({ timeout: 2 }).catch(() => void 0);
6204
6320
  const failed = items?.filter((i) => !i.ok) ?? [];
6205
6321
  if (failed.length > 0) {
6206
- for (const item of failed) console.log(` ${import_picocolors8.default.yellow("!")} ${item.label}`);
6322
+ for (const item of failed) console.log(` ${import_picocolors9.default.yellow("!")} ${item.label}`);
6207
6323
  console.log(`
6208
- ${import_picocolors8.default.dim("Resolve, then re-run")} ${import_picocolors8.default.cyan(`npx ablo ${verb}`)}
6324
+ ${import_picocolors9.default.dim("Resolve, then re-run")} ${import_picocolors9.default.cyan(`npx ablo ${verb}`)}
6209
6325
  `);
6210
6326
  process.exit(1);
6211
6327
  }
@@ -6220,20 +6336,21 @@ async function runConnectApply(args) {
6220
6336
  const outcome = postRegistrationOutcome({ rotating, registered });
6221
6337
  if (outcome.notice) {
6222
6338
  console.error(`
6223
- ${import_picocolors8.default.red(outcome.notice.split("\n").join("\n "))}
6339
+ ${import_picocolors9.default.red(outcome.notice.split("\n").join("\n "))}
6224
6340
  `);
6225
6341
  }
6226
6342
  process.exit(outcome.exitCode);
6227
6343
  }
6228
- var import_picocolors8;
6344
+ var import_picocolors9;
6229
6345
  var init_connectApply = __esm({
6230
6346
  "src/cli/connectApply.ts"() {
6231
6347
  "use strict";
6232
6348
  init_cjs_shims();
6233
- import_picocolors8 = __toESM(require_picocolors(), 1);
6349
+ import_picocolors9 = __toESM(require_picocolors(), 1);
6234
6350
  init_src();
6235
6351
  init_dist2();
6236
6352
  init_connectSetup();
6353
+ init_connectOwnership();
6237
6354
  init_dbRole();
6238
6355
  init_config();
6239
6356
  init_push();
@@ -218258,11 +218375,11 @@ var require_commonjs2 = __commonJS({
218258
218375
  if (pad) {
218259
218376
  const need = width - c.length;
218260
218377
  if (need > 0) {
218261
- const z8 = new Array(need + 1).join("0");
218378
+ const z9 = new Array(need + 1).join("0");
218262
218379
  if (i < 0) {
218263
- c = "-" + z8 + c.slice(1);
218380
+ c = "-" + z9 + c.slice(1);
218264
218381
  } else {
218265
- c = z8 + c;
218382
+ c = z9 + c;
218266
218383
  }
218267
218384
  }
218268
218385
  }
@@ -282191,7 +282308,7 @@ Node text: ${this.#forgottenText}`;
282191
282308
  // src/cli/index.ts
282192
282309
  init_cjs_shims();
282193
282310
  init_dist2();
282194
- var import_picocolors23 = __toESM(require_picocolors(), 1);
282311
+ var import_picocolors24 = __toESM(require_picocolors(), 1);
282195
282312
  var import_fs12 = require("fs");
282196
282313
  var import_path7 = require("path");
282197
282314
  var import_child_process3 = require("child_process");
@@ -282382,7 +282499,7 @@ async function migrate(argv) {
282382
282499
  // src/cli/connect.ts
282383
282500
  init_cjs_shims();
282384
282501
  init_errors();
282385
- var import_picocolors9 = __toESM(require_picocolors(), 1);
282502
+ var import_picocolors10 = __toESM(require_picocolors(), 1);
282386
282503
  init_src();
282387
282504
  init_dbRole();
282388
282505
  init_config();
@@ -282614,7 +282731,7 @@ function printConnectRecipe(args) {
282614
282731
  });
282615
282732
  console.log(
282616
282733
  `
282617
- ${brand("ablo")} ${import_picocolors9.default.dim("connect")} ${import_picocolors9.default.dim("direct writes + WAL-settled sync")}
282734
+ ${brand("ablo")} ${import_picocolors10.default.dim("connect")} ${import_picocolors10.default.dim("direct writes + WAL-settled sync")}
282618
282735
  `
282619
282736
  );
282620
282737
  console.log(
@@ -282622,29 +282739,29 @@ function printConnectRecipe(args) {
282622
282739
  observes what committed, orders it with external writes, and confirms it in the sync log.
282623
282740
  Your database stays authoritative; Ablo never owns or migrates your application tables.
282624
282741
 
282625
- ${import_picocolors9.default.bold("ablo connect apply")} runs every step below for you from a one-time admin
282626
- connection and leaves your app holding only ${import_picocolors9.default.bold("ABLO_API_KEY")}. To do it by hand,
282627
- run this once against your Postgres ${import_picocolors9.default.dim("(as a superuser / DB owner)")}:
282742
+ ${import_picocolors10.default.bold("ablo connect apply")} runs every step below for you from a one-time admin
282743
+ connection and leaves your app holding only ${import_picocolors10.default.bold("ABLO_API_KEY")}. To do it by hand,
282744
+ run this once against your Postgres ${import_picocolors10.default.dim("(as a superuser / DB owner)")}:
282628
282745
  `
282629
282746
  );
282630
282747
  console.log(
282631
- ` ${import_picocolors9.default.bold("1.")} Enable logical decoding ${import_picocolors9.default.dim("(then RESTART Postgres \u2014 wal_level is not reloadable)")}`
282748
+ ` ${import_picocolors10.default.bold("1.")} Enable logical decoding ${import_picocolors10.default.dim("(then RESTART Postgres \u2014 wal_level is not reloadable)")}`
282632
282749
  );
282633
- console.log(` ${import_picocolors9.default.cyan(sql[0])}`);
282750
+ console.log(` ${import_picocolors10.default.cyan(sql[0])}`);
282634
282751
  console.log(
282635
- import_picocolors9.default.dim(
282636
- ` Managed hosts don't take ALTER SYSTEM: on Amazon RDS / Aurora set ${import_picocolors9.default.bold("rds.logical_replication = 1")}
282752
+ import_picocolors10.default.dim(
282753
+ ` Managed hosts don't take ALTER SYSTEM: on Amazon RDS / Aurora set ${import_picocolors10.default.bold("rds.logical_replication = 1")}
282637
282754
  in the parameter group and reboot; on Neon or Supabase enable logical replication in the
282638
- project settings. ${import_picocolors9.default.bold("ablo connect apply")} detects the host and does the right thing.`
282755
+ project settings. ${import_picocolors10.default.bold("ablo connect apply")} detects the host and does the right thing.`
282639
282756
  )
282640
282757
  );
282641
282758
  console.log(`
282642
- ${import_picocolors9.default.bold("2.")} Publish the tables Ablo should read`);
282643
- console.log(` ${import_picocolors9.default.cyan(sql[1])}`);
282759
+ ${import_picocolors10.default.bold("2.")} Publish the tables Ablo should read`);
282760
+ console.log(` ${import_picocolors10.default.cyan(sql[1])}`);
282644
282761
  if (args.tables.length === 0) {
282645
282762
  console.log(
282646
- import_picocolors9.default.dim(
282647
- ` (Scope it with ${import_picocolors9.default.bold("ablo connect --tables a,b,c")} to publish a subset.)`
282763
+ import_picocolors10.default.dim(
282764
+ ` (Scope it with ${import_picocolors10.default.bold("ablo connect --tables a,b,c")} to publish a subset.)`
282648
282765
  )
282649
282766
  );
282650
282767
  }
@@ -282653,52 +282770,52 @@ function printConnectRecipe(args) {
282653
282770
  const writerStatements = sql.slice(writerStart);
282654
282771
  console.log(
282655
282772
  `
282656
- ${import_picocolors9.default.bold("3.")} Create the scoped replication role ${import_picocolors9.default.dim("(pick your own replication password)")}`
282773
+ ${import_picocolors10.default.bold("3.")} Create the scoped replication role ${import_picocolors10.default.dim("(pick your own replication password)")}`
282657
282774
  );
282658
282775
  for (const statement of replicationStatements) {
282659
- for (const line of statement.split("\n")) console.log(` ${import_picocolors9.default.cyan(line)}`);
282776
+ for (const line of statement.split("\n")) console.log(` ${import_picocolors10.default.cyan(line)}`);
282660
282777
  }
282661
282778
  console.log(
282662
- import_picocolors9.default.dim(
282779
+ import_picocolors10.default.dim(
282663
282780
  ` On Amazon RDS, the REPLICATION attribute is granted, not set directly:
282664
- ${import_picocolors9.default.bold(`GRANT rds_replication TO ${quoteIdent(args.role)};`)}`
282781
+ ${import_picocolors10.default.bold(`GRANT rds_replication TO ${quoteIdent(args.role)};`)}`
282665
282782
  )
282666
282783
  );
282667
282784
  console.log(
282668
282785
  `
282669
- ${import_picocolors9.default.bold("4.")} Create the separate DML role and the idempotency ledger ` + import_picocolors9.default.dim("(pick your own write password)")
282786
+ ${import_picocolors10.default.bold("4.")} Create the separate DML role and the idempotency ledger ` + import_picocolors10.default.dim("(pick your own write password)")
282670
282787
  );
282671
282788
  for (const statement of writerStatements) {
282672
- for (const line of statement.split("\n")) console.log(` ${import_picocolors9.default.cyan(line)}`);
282789
+ for (const line of statement.split("\n")) console.log(` ${import_picocolors10.default.cyan(line)}`);
282673
282790
  }
282674
282791
  console.log(
282675
- import_picocolors9.default.dim(
282792
+ import_picocolors10.default.dim(
282676
282793
  ` The writer gets row DML + ledger access only. It has no REPLICATION, schema CREATE,
282677
282794
  role administration, database creation, ownership, or customer-table DDL. Direct uses
282678
- ${import_picocolors9.default.bold("ablo_idempotency")} but no outbox; WAL carries the committed row changes.
282679
- Each ledger row carries an ${import_picocolors9.default.bold("expires_at")}; the writer can't DELETE (tamper-
282795
+ ${import_picocolors10.default.bold("ablo_idempotency")} but no outbox; WAL carries the committed row changes.
282796
+ Each ledger row carries an ${import_picocolors10.default.bold("expires_at")}; the writer can't DELETE (tamper-
282680
282797
  resistance), so prune it from your own admin/cron when convenient:
282681
- ${import_picocolors9.default.bold("DELETE FROM ablo_idempotency WHERE expires_at < now();")}`
282798
+ ${import_picocolors10.default.bold("DELETE FROM ablo_idempotency WHERE expires_at < now();")}`
282682
282799
  )
282683
282800
  );
282684
282801
  console.log(
282685
282802
  `
282686
- ${import_picocolors9.default.bold("5.")} Register the two roles with Ablo. Set them just long enough to register \u2014
282687
- Ablo holds them from here, so your app keeps only ${import_picocolors9.default.bold("ABLO_API_KEY")}:
282688
- ${import_picocolors9.default.bold("ABLO_REPLICATION_DATABASE_URL")} ${import_picocolors9.default.dim(`\u2192 ${args.role} (replication only)`)}
282689
- ${import_picocolors9.default.bold("ABLO_WRITE_DATABASE_URL")} ${import_picocolors9.default.dim(`\u2192 ${args.writeRole} (DML only)`)}
282690
- ${import_picocolors9.default.cyan("npx ablo connect register")}
282803
+ ${import_picocolors10.default.bold("5.")} Register the two roles with Ablo. Set them just long enough to register \u2014
282804
+ Ablo holds them from here, so your app keeps only ${import_picocolors10.default.bold("ABLO_API_KEY")}:
282805
+ ${import_picocolors10.default.bold("ABLO_REPLICATION_DATABASE_URL")} ${import_picocolors10.default.dim(`\u2192 ${args.role} (replication only)`)}
282806
+ ${import_picocolors10.default.bold("ABLO_WRITE_DATABASE_URL")} ${import_picocolors10.default.dim(`\u2192 ${args.writeRole} (DML only)`)}
282807
+ ${import_picocolors10.default.cyan("npx ablo connect register")}
282691
282808
  `
282692
282809
  );
282693
282810
  console.log(
282694
- ` ${import_picocolors9.default.bold("6.")} Verify readiness ${import_picocolors9.default.dim("(checked from Ablo\u2019s side \u2014 needs only ABLO_API_KEY):")}
282695
- ${import_picocolors9.default.cyan("npx ablo connect check")}
282811
+ ` ${import_picocolors10.default.bold("6.")} Verify readiness ${import_picocolors10.default.dim("(checked from Ablo\u2019s side \u2014 needs only ABLO_API_KEY):")}
282812
+ ${import_picocolors10.default.cyan("npx ablo connect check")}
282696
282813
  `
282697
282814
  );
282698
282815
  console.log(
282699
- import_picocolors9.default.dim(
282816
+ import_picocolors10.default.dim(
282700
282817
  ` Reachable databases use this direct path. If no inbound route can be established, use the
282701
- signed ${import_picocolors9.default.bold("dataSource()")} endpoint fallback; its correlated events confirm writes
282818
+ signed ${import_picocolors10.default.bold("dataSource()")} endpoint fallback; its correlated events confirm writes
282702
282819
  without an Ablo-side customer database socket.`
282703
282820
  )
282704
282821
  );
@@ -282713,11 +282830,11 @@ var SYNC_INFRA_RELATIONS = [
282713
282830
  var SYNC_INFRA_TYPES = ["participant_kind", "backfill_provenance", "confirmation_state"];
282714
282831
  function printCheckItem(item) {
282715
282832
  if (item.ok) {
282716
- console.log(` ${import_picocolors9.default.green("\u2713")} ${item.label}`);
282833
+ console.log(` ${import_picocolors10.default.green("\u2713")} ${item.label}`);
282717
282834
  } else {
282718
- console.log(` ${import_picocolors9.default.red("\u2717")} ${item.label}`);
282835
+ console.log(` ${import_picocolors10.default.red("\u2717")} ${item.label}`);
282719
282836
  if (item.fix) {
282720
- for (const line of item.fix.split("\n")) console.log(` ${import_picocolors9.default.red("\u2022")} ${line}`);
282837
+ for (const line of item.fix.split("\n")) console.log(` ${import_picocolors10.default.red("\u2022")} ${line}`);
282721
282838
  }
282722
282839
  }
282723
282840
  }
@@ -282738,7 +282855,7 @@ async function probeDirectWriteReadiness(sql, opts = {}) {
282738
282855
  ok: false,
282739
282856
  label: `ABLO_WRITE_DATABASE_URL is not a scoped DML role`,
282740
282857
  fix: `Use ${ABLO_WRITE_ROLE} from the setup recipe: NOSUPERUSER, NOBYPASSRLS, NOCREATEDB, NOCREATEROLE, NOREPLICATION.`
282741
- } : { ok: true, label: `write role ${import_picocolors9.default.bold(role?.rolname ?? ABLO_WRITE_ROLE)} is DML-only` }
282858
+ } : { ok: true, label: `write role ${import_picocolors10.default.bold(role?.rolname ?? ABLO_WRITE_ROLE)} is DML-only` }
282742
282859
  );
282743
282860
  const schemaRows = await sql.unsafe(
282744
282861
  `SELECT
@@ -282765,10 +282882,10 @@ async function probeDirectWriteReadiness(sql, opts = {}) {
282765
282882
  );
282766
282883
  const ledger = ledgerRows[0];
282767
282884
  items.push(
282768
- ledger?.present && ledger.writes && !ledger.deletes ? { ok: true, label: `${import_picocolors9.default.bold("ablo_idempotency")} is durable and protected from DELETE` } : {
282885
+ ledger?.present && ledger.writes && !ledger.deletes ? { ok: true, label: `${import_picocolors10.default.bold("ablo_idempotency")} is durable and protected from DELETE` } : {
282769
282886
  ok: false,
282770
- label: `${import_picocolors9.default.bold("ablo_idempotency")} is missing or has unsafe grants`,
282771
- fix: `Apply the DML-role and idempotency-ledger statements printed by ${import_picocolors9.default.bold("ablo connect")}.`
282887
+ label: `${import_picocolors10.default.bold("ablo_idempotency")} is missing or has unsafe grants`,
282888
+ fix: `Apply the DML-role and idempotency-ledger statements printed by ${import_picocolors10.default.bold("ablo connect")}.`
282772
282889
  }
282773
282890
  );
282774
282891
  const tableRows = await sql.unsafe(
@@ -282857,8 +282974,8 @@ function requireScopedUrl(kind, verb) {
282857
282974
  const resolved = readProjectReplicationUrlWithSource();
282858
282975
  if (resolved) return resolved.url;
282859
282976
  console.error(
282860
- import_picocolors9.default.red(" No replication connection found (checked process env, .env.local, .env).") + import_picocolors9.default.dim(
282861
- ` Set ${import_picocolors9.default.bold("ABLO_REPLICATION_DATABASE_URL")} to the ${ABLO_REPLICATION_ROLE} connection printed by ${import_picocolors9.default.bold("ablo connect")}, then re-run ${import_picocolors9.default.bold(`ablo connect ${verb}`)}.`
282977
+ import_picocolors10.default.red(" No replication connection found (checked process env, .env.local, .env).") + import_picocolors10.default.dim(
282978
+ ` Set ${import_picocolors10.default.bold("ABLO_REPLICATION_DATABASE_URL")} to the ${ABLO_REPLICATION_ROLE} connection printed by ${import_picocolors10.default.bold("ablo connect")}, then re-run ${import_picocolors10.default.bold(`ablo connect ${verb}`)}.`
282862
282979
  )
282863
282980
  );
282864
282981
  process.exit(1);
@@ -282866,8 +282983,8 @@ function requireScopedUrl(kind, verb) {
282866
282983
  const dbUrl = readProjectWriteDatabaseUrl();
282867
282984
  if (dbUrl) return dbUrl;
282868
282985
  console.error(
282869
- import_picocolors9.default.red(" No ABLO_WRITE_DATABASE_URL found (checked process env, .env.local, .env).") + import_picocolors9.default.dim(
282870
- ` Set it to the ${ABLO_WRITE_ROLE} connection printed by ${import_picocolors9.default.bold("ablo connect")}, then re-run ${import_picocolors9.default.bold(`ablo connect ${verb}`)}. The replication credential is never reused for DML.`
282986
+ import_picocolors10.default.red(" No ABLO_WRITE_DATABASE_URL found (checked process env, .env.local, .env).") + import_picocolors10.default.dim(
282987
+ ` Set it to the ${ABLO_WRITE_ROLE} connection printed by ${import_picocolors10.default.bold("ablo connect")}, then re-run ${import_picocolors10.default.bold(`ablo connect ${verb}`)}. The replication credential is never reused for DML.`
282871
282988
  )
282872
282989
  );
282873
282990
  process.exit(1);
@@ -282883,7 +283000,7 @@ async function probeAndReport(dbUrl, kind = "replication") {
282883
283000
  const dial = dialFailureReason(err);
282884
283001
  if (dial) return { kind: "no-dial", reason: dial };
282885
283002
  const pg = err ?? {};
282886
- console.error(import_picocolors9.default.red(` Couldn't read the database: ${pg.message ?? String(err)}`));
283003
+ console.error(import_picocolors10.default.red(` Couldn't read the database: ${pg.message ?? String(err)}`));
282887
283004
  process.exit(1);
282888
283005
  }
282889
283006
  await sql.end({ timeout: 2 });
@@ -282893,14 +283010,14 @@ async function probeAndReport(dbUrl, kind = "replication") {
282893
283010
  async function runCheck() {
282894
283011
  console.log(
282895
283012
  `
282896
- ${brand("ablo")} ${import_picocolors9.default.dim("connect check")} ${import_picocolors9.default.dim("direct-write + WAL readiness")}
283013
+ ${brand("ablo")} ${import_picocolors10.default.dim("connect check")} ${import_picocolors10.default.dim("direct-write + WAL readiness")}
282897
283014
  `
282898
283015
  );
282899
283016
  const apiKey = resolveApiKey();
282900
283017
  if (!apiKey) {
282901
283018
  console.error(
282902
- import_picocolors9.default.red(" No API key found.") + import_picocolors9.default.dim(
282903
- ` Run ${import_picocolors9.default.bold("ablo login")} (or set ${import_picocolors9.default.bold("ABLO_API_KEY")}), then re-run ${import_picocolors9.default.bold("ablo connect check")}.`
283019
+ import_picocolors10.default.red(" No API key found.") + import_picocolors10.default.dim(
283020
+ ` Run ${import_picocolors10.default.bold("ablo login")} (or set ${import_picocolors10.default.bold("ABLO_API_KEY")}), then re-run ${import_picocolors10.default.bold("ablo connect check")}.`
282904
283021
  )
282905
283022
  );
282906
283023
  process.exit(1);
@@ -282910,19 +283027,19 @@ async function runCheck() {
282910
283027
  if (!result.ok) {
282911
283028
  if (result.code === "no_data_source_registered") {
282912
283029
  console.error(
282913
- ` ${import_picocolors9.default.yellow("\u2014")} No database is connected to this plane yet, so there's nothing to check.
282914
- ` + import_picocolors9.default.dim(
282915
- ` Connect one with ${import_picocolors9.default.bold("ablo connect apply")}, then re-run ${import_picocolors9.default.bold("ablo connect check")}.
283030
+ ` ${import_picocolors10.default.yellow("\u2014")} No database is connected to this plane yet, so there's nothing to check.
283031
+ ` + import_picocolors10.default.dim(
283032
+ ` Connect one with ${import_picocolors10.default.bold("ablo connect apply")}, then re-run ${import_picocolors10.default.bold("ablo connect check")}.
282916
283033
  `
282917
283034
  )
282918
283035
  );
282919
283036
  process.exit(1);
282920
283037
  }
282921
- console.error(import_picocolors9.default.red(` The check failed: ${result.message}`));
283038
+ console.error(import_picocolors10.default.red(` The check failed: ${result.message}`));
282922
283039
  if (result.code === "forbidden") {
282923
283040
  console.error(
282924
- import_picocolors9.default.dim(
282925
- ` Checking a connected database needs a ${import_picocolors9.default.bold("secret")} key (sk_\u2026). Run ${import_picocolors9.default.bold("ablo login")} for one.`
283041
+ import_picocolors10.default.dim(
283042
+ ` Checking a connected database needs a ${import_picocolors10.default.bold("secret")} key (sk_\u2026). Run ${import_picocolors10.default.bold("ablo login")} for one.`
282926
283043
  )
282927
283044
  );
282928
283045
  }
@@ -282931,12 +283048,12 @@ async function runCheck() {
282931
283048
  }
282932
283049
  if (!result.reachable) {
282933
283050
  console.error(
282934
- ` ${import_picocolors9.default.red("\u2717")} Ablo's infrastructure can't reach your database${result.reason ? ` ${import_picocolors9.default.dim(`(${result.reason})`)}` : ""}.`
283051
+ ` ${import_picocolors10.default.red("\u2717")} Ablo's infrastructure can't reach your database${result.reason ? ` ${import_picocolors10.default.dim(`(${result.reason})`)}` : ""}.`
282935
283052
  );
282936
283053
  console.error(
282937
- import_picocolors9.default.dim(
283054
+ import_picocolors10.default.dim(
282938
283055
  ` Direct needs a route Ablo's servers can dial \u2014 public allowlist, PrivateLink, peering,
282939
- or VPN. Only when no inbound route can exist, use the signed ${import_picocolors9.default.bold("dataSource()")} endpoint fallback.
283056
+ or VPN. Only when no inbound route can exist, use the signed ${import_picocolors10.default.bold("dataSource()")} endpoint fallback.
282940
283057
  `
282941
283058
  )
282942
283059
  );
@@ -282949,14 +283066,14 @@ async function runCheck() {
282949
283066
  console.log();
282950
283067
  if (result.ready) {
282951
283068
  console.log(
282952
- ` ${import_picocolors9.default.green("\u2713")} Ready \u2014 checked from Ablo's infrastructure. Ablo can apply scoped DML and settle it from WAL.
283069
+ ` ${import_picocolors10.default.green("\u2713")} Ready \u2014 checked from Ablo's infrastructure. Ablo can apply scoped DML and settle it from WAL.
282953
283070
  `
282954
283071
  );
282955
283072
  process.exit(0);
282956
283073
  }
282957
283074
  const count = result.failures.length;
282958
283075
  console.log(
282959
- ` ${import_picocolors9.default.red(`${count} item${count === 1 ? "" : "s"} to fix`)} ${import_picocolors9.default.dim(`\u2014 apply the fixes above, then re-run ${import_picocolors9.default.bold("ablo connect check")}.`)}
283076
+ ` ${import_picocolors10.default.red(`${count} item${count === 1 ? "" : "s"} to fix`)} ${import_picocolors10.default.dim(`\u2014 apply the fixes above, then re-run ${import_picocolors10.default.bold("ablo connect check")}.`)}
282960
283077
  `
282961
283078
  );
282962
283079
  process.exit(1);
@@ -282967,22 +283084,22 @@ async function runRegister(args) {
282967
283084
  const apiKey = resolveApiKey();
282968
283085
  if (!apiKey) {
282969
283086
  console.error(
282970
- import_picocolors9.default.red(" Not logged in.") + import_picocolors9.default.dim(
282971
- ` Run ${import_picocolors9.default.bold("ablo login")} (or set ${import_picocolors9.default.bold("ABLO_API_KEY")}) so Ablo knows which project to register this database for.`
283087
+ import_picocolors10.default.red(" Not logged in.") + import_picocolors10.default.dim(
283088
+ ` Run ${import_picocolors10.default.bold("ablo login")} (or set ${import_picocolors10.default.bold("ABLO_API_KEY")}) so Ablo knows which project to register this database for.`
282972
283089
  )
282973
283090
  );
282974
283091
  process.exit(1);
282975
283092
  }
282976
283093
  console.log(
282977
283094
  `
282978
- ${brand("ablo")} ${import_picocolors9.default.dim("connect register")} ${import_picocolors9.default.dim("register a direct DataSource")}
283095
+ ${brand("ablo")} ${import_picocolors10.default.dim("connect register")} ${import_picocolors10.default.dim("register a direct DataSource")}
282979
283096
  `
282980
283097
  );
282981
- console.log(` ${import_picocolors9.default.bold("Replication role")}
283098
+ console.log(` ${import_picocolors10.default.bold("Replication role")}
282982
283099
  `);
282983
283100
  const replication = await probeAndReport(dbUrl, "replication");
282984
283101
  console.log(`
282985
- ${import_picocolors9.default.bold("Direct-write role")}
283102
+ ${import_picocolors10.default.bold("Direct-write role")}
282986
283103
  `);
282987
283104
  const write = await probeAndReport(writeDbUrl, "write");
282988
283105
  const noDial = [
@@ -282992,7 +283109,7 @@ async function runRegister(args) {
282992
283109
  const failures = (replication.kind === "probed" ? replication.failures : 0) + (write.kind === "probed" ? write.failures : 0);
282993
283110
  if (noDial.length > 0) {
282994
283111
  console.log(
282995
- ` This machine can't reach one or both scoped connections (${import_picocolors9.default.dim(noDial.join("; "))}) \u2014 continuing anyway.
283112
+ ` This machine can't reach one or both scoped connections (${import_picocolors10.default.dim(noDial.join("; "))}) \u2014 continuing anyway.
282996
283113
  Ablo validates both credentials from the infrastructure that will use them and refuses
282997
283114
  registration unless replication and direct DML are both ready.
282998
283115
  `
@@ -283001,7 +283118,7 @@ async function runRegister(args) {
283001
283118
  if (failures > 0) {
283002
283119
  console.log(
283003
283120
  `
283004
- ${import_picocolors9.default.red(`${failures} item${failures === 1 ? "" : "s"} to fix`)} ${import_picocolors9.default.dim("\u2014 direct registration requires both scoped roles. Fix the above, then re-run.")}
283121
+ ${import_picocolors10.default.red(`${failures} item${failures === 1 ? "" : "s"} to fix`)} ${import_picocolors10.default.dim("\u2014 direct registration requires both scoped roles. Fix the above, then re-run.")}
283005
283122
  `
283006
283123
  );
283007
283124
  process.exit(1);
@@ -283025,31 +283142,31 @@ async function runScan() {
283025
283142
  artifacts = await auditTenantSyncInfra(sql);
283026
283143
  } catch (err) {
283027
283144
  const pg = err ?? {};
283028
- console.error(import_picocolors9.default.red(` Couldn't audit the database: ${pg.message ?? String(err)}`));
283145
+ console.error(import_picocolors10.default.red(` Couldn't audit the database: ${pg.message ?? String(err)}`));
283029
283146
  await sql.end({ timeout: 2 });
283030
283147
  process.exit(1);
283031
283148
  }
283032
283149
  await sql.end({ timeout: 2 });
283033
283150
  console.log(
283034
283151
  `
283035
- ${brand("ablo")} ${import_picocolors9.default.dim("connect scan")} ${import_picocolors9.default.dim("audit for leftover Ablo sync infrastructure")}
283152
+ ${brand("ablo")} ${import_picocolors10.default.dim("connect scan")} ${import_picocolors10.default.dim("audit for leftover Ablo sync infrastructure")}
283036
283153
  `
283037
283154
  );
283038
283155
  const present = artifacts.filter((a) => a.present);
283039
283156
  if (present.length === 0) {
283040
- console.log(` ${import_picocolors9.default.green("\u2713")} No deprecated Ablo sync infrastructure found in public.
283157
+ console.log(` ${import_picocolors10.default.green("\u2713")} No deprecated Ablo sync infrastructure found in public.
283041
283158
  `);
283042
283159
  process.exit(0);
283043
283160
  }
283044
283161
  for (const artifact of present) {
283045
283162
  const label = artifact.kind === "type" ? "type" : "relation";
283046
- console.log(` ${import_picocolors9.default.yellow("!")} ${label} ${import_picocolors9.default.bold(`public.${artifact.name}`)} exists`);
283163
+ console.log(` ${import_picocolors10.default.yellow("!")} ${label} ${import_picocolors10.default.bold(`public.${artifact.name}`)} exists`);
283047
283164
  }
283048
283165
  console.log(
283049
283166
  `
283050
- ${import_picocolors9.default.yellow(`${present.length} artifact${present.length === 1 ? "" : "s"} found`)} ` + import_picocolors9.default.dim(
283167
+ ${import_picocolors10.default.yellow(`${present.length} artifact${present.length === 1 ? "" : "s"} found`)} ` + import_picocolors10.default.dim(
283051
283168
  "\u2014 do not drop automatically. Confirm the org/environment is log-authoritative, then follow "
283052
- ) + import_picocolors9.default.bold("docs/runbooks/wal-stage5-customer-db-infra-cleanup.md") + import_picocolors9.default.dim(".\n")
283169
+ ) + import_picocolors10.default.bold("docs/runbooks/wal-stage5-customer-db-infra-cleanup.md") + import_picocolors10.default.dim(".\n")
283053
283170
  );
283054
283171
  process.exit(1);
283055
283172
  }
@@ -283063,7 +283180,7 @@ async function connect(argv) {
283063
283180
  try {
283064
283181
  args = parseConnectArgs(argv);
283065
283182
  } catch (err) {
283066
- console.error(import_picocolors9.default.red(` ${err instanceof Error ? err.message : String(err)}`));
283183
+ console.error(import_picocolors10.default.red(` ${err instanceof Error ? err.message : String(err)}`));
283067
283184
  process.exit(1);
283068
283185
  }
283069
283186
  if (args.apply || args.rotate) {
@@ -283119,7 +283236,7 @@ init_cjs_shims();
283119
283236
  init_errors();
283120
283237
  var import_fs6 = require("fs");
283121
283238
  var import_path4 = require("path");
283122
- var import_picocolors10 = __toESM(require_picocolors(), 1);
283239
+ var import_picocolors11 = __toESM(require_picocolors(), 1);
283123
283240
  var import_schema4 = require("@abloatai/ablo/schema");
283124
283241
  init_push();
283125
283242
  var DEFAULT_SCHEMA_PATH3 = "ablo/schema.ts";
@@ -283152,7 +283269,7 @@ async function generate(argv) {
283152
283269
  try {
283153
283270
  args = parseGenerateArgs(argv);
283154
283271
  } catch (err) {
283155
- console.error(import_picocolors10.default.red(` ${err instanceof Error ? err.message : String(err)}`));
283272
+ console.error(import_picocolors11.default.red(` ${err instanceof Error ? err.message : String(err)}`));
283156
283273
  process.exit(1);
283157
283274
  }
283158
283275
  let source;
@@ -283161,20 +283278,20 @@ async function generate(argv) {
283161
283278
  const schemaJson = JSON.parse((0, import_schema4.serializeSchema)(schema));
283162
283279
  source = (0, import_schema4.generateTypes)(schemaJson);
283163
283280
  } catch (err) {
283164
- console.error(import_picocolors10.default.red(` ${err instanceof Error ? err.message : String(err)}`));
283281
+ console.error(import_picocolors11.default.red(` ${err instanceof Error ? err.message : String(err)}`));
283165
283282
  process.exit(1);
283166
283283
  }
283167
283284
  const abs = (0, import_path4.resolve)(process.cwd(), args.out);
283168
283285
  (0, import_fs6.mkdirSync)((0, import_path4.dirname)(abs), { recursive: true });
283169
283286
  (0, import_fs6.writeFileSync)(abs, source);
283170
- console.log(` ${import_picocolors10.default.green("\u2713")} Generated types \u2192 ${import_picocolors10.default.bold(args.out)}`);
283287
+ console.log(` ${import_picocolors11.default.green("\u2713")} Generated types \u2192 ${import_picocolors11.default.bold(args.out)}`);
283171
283288
  }
283172
283289
 
283173
283290
  // src/cli/dev.ts
283174
283291
  init_cjs_shims();
283175
283292
  init_errors();
283176
283293
  init_credentialPolicy();
283177
- var import_picocolors11 = __toESM(require_picocolors(), 1);
283294
+ var import_picocolors12 = __toESM(require_picocolors(), 1);
283178
283295
  init_dist2();
283179
283296
  var import_fs7 = require("fs");
283180
283297
  var import_path5 = require("path");
@@ -283216,25 +283333,25 @@ function classifyKey(apiKey, activeMode) {
283216
283333
  if (!apiKey) {
283217
283334
  return {
283218
283335
  ok: false,
283219
- reason: `No API key. Run ${import_picocolors11.default.bold("npx ablo login")} for the sandbox dev loop \u2014 or set ${import_picocolors11.default.bold("ABLO_API_KEY")} (${import_picocolors11.default.bold("sk_test_")} = sandbox; ${import_picocolors11.default.bold("sk_live_")} = deliberate production deploy). ` + import_picocolors11.default.dim(`Mode is currently '${activeMode}'.`)
283336
+ reason: `No API key. Run ${import_picocolors12.default.bold("npx ablo login")} for the sandbox dev loop \u2014 or set ${import_picocolors12.default.bold("ABLO_API_KEY")} (${import_picocolors12.default.bold("sk_test_")} = sandbox; ${import_picocolors12.default.bold("sk_live_")} = deliberate production deploy). ` + import_picocolors12.default.dim(`Mode is currently '${activeMode}'.`)
283220
283337
  };
283221
283338
  }
283222
283339
  if (apiKey.startsWith("sk_test_")) return { ok: true };
283223
283340
  if (apiKey.startsWith("sk_live_")) {
283224
283341
  return {
283225
283342
  ok: false,
283226
- reason: `Production schema deploys run one-shot: ${import_picocolors11.default.bold("ABLO_API_KEY=sk_live_\u2026 npx ablo push")} (or ${import_picocolors11.default.bold("ablo mode production")}). ${import_picocolors11.default.bold("--watch")} is sandbox-only.`
283343
+ reason: `Production schema deploys run one-shot: ${import_picocolors12.default.bold("ABLO_API_KEY=sk_live_\u2026 npx ablo push")} (or ${import_picocolors12.default.bold("ablo mode production")}). ${import_picocolors12.default.bold("--watch")} is sandbox-only.`
283227
283344
  };
283228
283345
  }
283229
283346
  if (classifyCredentialKind(apiKey) === "restricted") {
283230
283347
  return {
283231
283348
  ok: false,
283232
- reason: `Restricted (${import_picocolors11.default.bold("rk_")}) keys can't push schema. Use a secret key: ${import_picocolors11.default.bold("sk_test_")} for the sandbox dev loop, or ${import_picocolors11.default.bold("sk_live_")} with ${import_picocolors11.default.bold("npx ablo push")} for a production deploy.`
283349
+ reason: `Restricted (${import_picocolors12.default.bold("rk_")}) keys can't push schema. Use a secret key: ${import_picocolors12.default.bold("sk_test_")} for the sandbox dev loop, or ${import_picocolors12.default.bold("sk_live_")} with ${import_picocolors12.default.bold("npx ablo push")} for a production deploy.`
283233
283350
  };
283234
283351
  }
283235
283352
  return {
283236
283353
  ok: false,
283237
- reason: `${import_picocolors11.default.bold("ABLO_API_KEY")} is not an Ablo key \u2014 expected ${import_picocolors11.default.bold("sk_test_\u2026")} (sandbox) or ${import_picocolors11.default.bold("sk_live_\u2026")} (production deploy via ${import_picocolors11.default.bold("npx ablo push")}).`
283354
+ reason: `${import_picocolors12.default.bold("ABLO_API_KEY")} is not an Ablo key \u2014 expected ${import_picocolors12.default.bold("sk_test_\u2026")} (sandbox) or ${import_picocolors12.default.bold("sk_live_\u2026")} (production deploy via ${import_picocolors12.default.bold("npx ablo push")}).`
283238
283355
  };
283239
283356
  }
283240
283357
  function wireEnvLocal(apiKey, cwd = process.cwd()) {
@@ -283244,7 +283361,7 @@ function wireEnvLocal(apiKey, cwd = process.cwd()) {
283244
283361
  if (!(0, import_fs7.existsSync)(envPath)) {
283245
283362
  (0, import_fs7.writeFileSync)(envPath, `${line}
283246
283363
  `, { mode: 384 });
283247
- action = `Created ${import_picocolors11.default.bold(".env.local")} with ${import_picocolors11.default.bold("ABLO_API_KEY")}`;
283364
+ action = `Created ${import_picocolors12.default.bold(".env.local")} with ${import_picocolors12.default.bold("ABLO_API_KEY")}`;
283248
283365
  } else {
283249
283366
  const content = (0, import_fs7.readFileSync)(envPath, "utf8");
283250
283367
  const match = /^ABLO_API_KEY=(.*)$/m.exec(content);
@@ -283252,12 +283369,12 @@ function wireEnvLocal(apiKey, cwd = process.cwd()) {
283252
283369
  if (!match) {
283253
283370
  (0, import_fs7.appendFileSync)(envPath, `${content.endsWith("\n") || content.length === 0 ? "" : "\n"}${line}
283254
283371
  `);
283255
- action = `Added ${import_picocolors11.default.bold("ABLO_API_KEY")} to ${import_picocolors11.default.bold(".env.local")}`;
283372
+ action = `Added ${import_picocolors12.default.bold("ABLO_API_KEY")} to ${import_picocolors12.default.bold(".env.local")}`;
283256
283373
  } else if (existing === apiKey) {
283257
- action = `${import_picocolors11.default.bold(".env.local")} already has this key`;
283374
+ action = `${import_picocolors12.default.bold(".env.local")} already has this key`;
283258
283375
  } else {
283259
283376
  (0, import_fs7.writeFileSync)(envPath, content.replace(/^ABLO_API_KEY=.*$/m, line));
283260
- action = `Updated ${import_picocolors11.default.bold("ABLO_API_KEY")} in ${import_picocolors11.default.bold(".env.local")} ${import_picocolors11.default.dim(`(was ${existing.slice(0, 12)}\u2026)`)}`;
283377
+ action = `Updated ${import_picocolors12.default.bold("ABLO_API_KEY")} in ${import_picocolors12.default.bold(".env.local")} ${import_picocolors12.default.dim(`(was ${existing.slice(0, 12)}\u2026)`)}`;
283261
283378
  }
283262
283379
  }
283263
283380
  const gitignorePath = (0, import_path5.resolve)(cwd, ".gitignore");
@@ -283271,7 +283388,7 @@ function wireEnvLocal(apiKey, cwd = process.cwd()) {
283271
283388
  `}.env.local
283272
283389
  `
283273
283390
  );
283274
- gitignoreNote = ` Added ${import_picocolors11.default.bold(".env.local")} to ${import_picocolors11.default.bold(".gitignore")} so the key can't be committed.`;
283391
+ gitignoreNote = ` Added ${import_picocolors12.default.bold(".env.local")} to ${import_picocolors12.default.bold(".gitignore")} so the key can't be committed.`;
283275
283392
  }
283276
283393
  return `${action}.${gitignoreNote}`;
283277
283394
  }
@@ -283286,7 +283403,7 @@ async function runPush(schema, args) {
283286
283403
  if (ok) {
283287
283404
  return {
283288
283405
  ok: true,
283289
- message: body.unchanged ? `schema unchanged ${import_picocolors11.default.dim(`(v${body.version})`)}` : `schema pushed (sandbox) ${import_picocolors11.default.dim(`(v${body.version}, hash ${body.hash})`)}`
283406
+ message: body.unchanged ? `schema unchanged ${import_picocolors12.default.dim(`(v${body.version})`)}` : `schema pushed (sandbox) ${import_picocolors12.default.dim(`(v${body.version}, hash ${body.hash})`)}`
283290
283407
  };
283291
283408
  }
283292
283409
  if (status2 === 409) {
@@ -283296,33 +283413,33 @@ async function runPush(schema, args) {
283296
283413
  (s) => s.shadowed != null
283297
283414
  );
283298
283415
  const lines = [
283299
- import_picocolors11.default.bold("Incompatible schema change \u2014 not safe to apply as-is."),
283416
+ import_picocolors12.default.bold("Incompatible schema change \u2014 not safe to apply as-is."),
283300
283417
  "",
283301
- ...unexecutable.map((u2) => import_picocolors11.default.red(fmtSignal(u2))),
283302
- ...warnings.map((w2) => import_picocolors11.default.yellow(fmtSignal(w2))),
283418
+ ...unexecutable.map((u2) => import_picocolors12.default.red(fmtSignal(u2))),
283419
+ ...warnings.map((w2) => import_picocolors12.default.yellow(fmtSignal(w2))),
283303
283420
  "",
283304
283421
  ...hasShadowed ? [
283305
- import_picocolors11.default.dim(
283422
+ import_picocolors12.default.dim(
283306
283423
  " These models exist in the baseline above but not in your push. Sandbox readers"
283307
283424
  ),
283308
- import_picocolors11.default.dim(
283425
+ import_picocolors12.default.dim(
283309
283426
  " fall back to the production schema until you push your own, so applying this drops them."
283310
283427
  ),
283311
283428
  ""
283312
283429
  ] : [],
283313
- import_picocolors11.default.dim(
283314
- ` Fix: ${import_picocolors11.default.bold("ablo push --force")} to apply anyway, or ${import_picocolors11.default.bold("--rename old:new")} if you renamed a model.`
283430
+ import_picocolors12.default.dim(
283431
+ ` Fix: ${import_picocolors12.default.bold("ablo push --force")} to apply anyway, or ${import_picocolors12.default.bold("--rename old:new")} if you renamed a model.`
283315
283432
  )
283316
283433
  ];
283317
283434
  return { ok: false, message: lines.join("\n") };
283318
283435
  }
283319
283436
  if (status2 === 403) {
283320
283437
  const serverSays = body.message ?? body.reason;
283321
- const hint = body.code === "database_role_cannot_enforce_rls" ? `Run ${import_picocolors11.default.bold("npx ablo migrate")} \u2014 it creates the scoped role for you (your DB credential never leaves this machine).` : `Schema authoring needs a ${import_picocolors11.default.bold("sandbox")} key with ${import_picocolors11.default.bold("schema:push")} \u2014 manage keys at ${import_picocolors11.default.cyan("https://abloatai.com")}.`;
283438
+ const hint = body.code === "database_role_cannot_enforce_rls" ? `Run ${import_picocolors12.default.bold("npx ablo migrate")} \u2014 it creates the scoped role for you (your DB credential never leaves this machine).` : `Schema authoring needs a ${import_picocolors12.default.bold("sandbox")} key with ${import_picocolors12.default.bold("schema:push")} \u2014 manage keys at ${import_picocolors12.default.cyan("https://abloatai.com")}.`;
283322
283439
  return {
283323
283440
  ok: false,
283324
283441
  message: `${serverSays ?? "This key can't author schema (missing schema:push scope)."}
283325
- ` + import_picocolors11.default.dim(hint)
283442
+ ` + import_picocolors12.default.dim(hint)
283326
283443
  };
283327
283444
  }
283328
283445
  return { ok: false, message: `Push failed (${status2}): ${body.message ?? body.reason ?? bodyText}` };
@@ -283332,25 +283449,25 @@ async function dev(argv) {
283332
283449
  try {
283333
283450
  args = parseDevArgs(argv);
283334
283451
  } catch (err) {
283335
- console.error(import_picocolors11.default.red(` ${err instanceof Error ? err.message : String(err)}`));
283452
+ console.error(import_picocolors12.default.red(` ${err instanceof Error ? err.message : String(err)}`));
283336
283453
  process.exit(1);
283337
283454
  }
283338
283455
  if (!args.apiKey) args.apiKey = resolveEffectiveApiKey("sandbox").key;
283339
283456
  const key = classifyKey(args.apiKey, getMode());
283340
283457
  if (!key.ok) {
283341
- console.error(import_picocolors11.default.red(` ${key.reason}`));
283458
+ console.error(import_picocolors12.default.red(` ${key.reason}`));
283342
283459
  process.exit(1);
283343
283460
  }
283344
283461
  console.log(`
283345
- ${brand("ablo")} ${import_picocolors11.default.dim("push")} ${import_picocolors11.default.dim("(sandbox)")}
283462
+ ${brand("ablo")} ${import_picocolors12.default.dim("push")} ${import_picocolors12.default.dim("(sandbox)")}
283346
283463
  `);
283347
283464
  const schema = await loadSchema(args.schemaPath, args.exportName);
283348
283465
  const modelCount = Object.keys(schema.models).length;
283349
283466
  console.log(
283350
- ` ${import_picocolors11.default.dim("schema")} ${import_picocolors11.default.bold(args.schemaPath)} ${import_picocolors11.default.dim(`(${modelCount} models, hash ${(0, import_schema5.schemaHash)(schema)})`)}`
283467
+ ` ${import_picocolors12.default.dim("schema")} ${import_picocolors12.default.bold(args.schemaPath)} ${import_picocolors12.default.dim(`(${modelCount} models, hash ${(0, import_schema5.schemaHash)(schema)})`)}`
283351
283468
  );
283352
- console.log(` ${import_picocolors11.default.dim("key")} ${args.apiKey.slice(0, 12)}\u2026`);
283353
- console.log(` ${import_picocolors11.default.dim("api")} ${args.url}
283469
+ console.log(` ${import_picocolors12.default.dim("key")} ${args.apiKey.slice(0, 12)}\u2026`);
283470
+ console.log(` ${import_picocolors12.default.dim("api")} ${args.url}
283354
283471
  `);
283355
283472
  const s = Y2();
283356
283473
  s.start("Pushing schema definition (sandbox)");
@@ -283359,16 +283476,16 @@ async function dev(argv) {
283359
283476
  if (!first.ok) process.exit(1);
283360
283477
  if (process.env.ABLO_API_KEY) {
283361
283478
  console.log(`
283362
- ${import_picocolors11.default.green("\u2713")} ${import_picocolors11.default.bold("ABLO_API_KEY")} is set in this shell \u2014 the SDK reads it directly.`);
283479
+ ${import_picocolors12.default.green("\u2713")} ${import_picocolors12.default.bold("ABLO_API_KEY")} is set in this shell \u2014 the SDK reads it directly.`);
283363
283480
  } else {
283364
283481
  console.log(`
283365
- ${import_picocolors11.default.green("\u2713")} ${wireEnvLocal(args.apiKey)}`);
283366
- console.log(` ${import_picocolors11.default.dim("Frameworks load it automatically; plain Node: node --env-file=.env.local app.ts")}`);
283482
+ ${import_picocolors12.default.green("\u2713")} ${wireEnvLocal(args.apiKey)}`);
283483
+ console.log(` ${import_picocolors12.default.dim("Frameworks load it automatically; plain Node: node --env-file=.env.local app.ts")}`);
283367
283484
  }
283368
283485
  console.log(` Your app is wired for the sandbox.`);
283369
283486
  if (!args.watch) return;
283370
283487
  const abs = (0, import_path5.resolve)(process.cwd(), args.schemaPath);
283371
- console.log(` ${import_picocolors11.default.dim(`watching ${args.schemaPath} \u2026 (Ctrl-C to stop)`)}
283488
+ console.log(` ${import_picocolors12.default.dim(`watching ${args.schemaPath} \u2026 (Ctrl-C to stop)`)}
283372
283489
  `);
283373
283490
  let timer2 = null;
283374
283491
  let pushing = false;
@@ -283388,7 +283505,7 @@ async function dev(argv) {
283388
283505
  const r2 = await runPush(next, args);
283389
283506
  s2.stop(r2.message, r2.ok ? 0 : 1);
283390
283507
  } catch (err) {
283391
- s2.stop(import_picocolors11.default.red(`schema reload failed: ${err instanceof Error ? err.message : String(err)}`), 1);
283508
+ s2.stop(import_picocolors12.default.red(`schema reload failed: ${err instanceof Error ? err.message : String(err)}`), 1);
283392
283509
  } finally {
283393
283510
  pushing = false;
283394
283511
  }
@@ -283396,7 +283513,7 @@ async function dev(argv) {
283396
283513
  const stop = () => {
283397
283514
  watcher.close();
283398
283515
  console.log(`
283399
- ${import_picocolors11.default.dim("stopped.")}`);
283516
+ ${import_picocolors12.default.dim("stopped.")}`);
283400
283517
  process.exit(0);
283401
283518
  };
283402
283519
  process.on("SIGINT", stop);
@@ -283408,7 +283525,7 @@ async function dev(argv) {
283408
283525
  // src/cli/login.ts
283409
283526
  init_cjs_shims();
283410
283527
  var import_child_process2 = require("child_process");
283411
- var import_picocolors12 = __toESM(require_picocolors(), 1);
283528
+ var import_picocolors13 = __toESM(require_picocolors(), 1);
283412
283529
  init_dist2();
283413
283530
  init_config();
283414
283531
  init_theme();
@@ -283469,9 +283586,9 @@ async function deviceLogin(argv, deps = {}) {
283469
283586
  const code = await codeRes.json();
283470
283587
  const approvePath = `/cli?user_code=${code.user_code}`;
283471
283588
  const url = account === "signup" ? `${DASHBOARD_URL}/signup?next=${encodeURIComponent(approvePath)}` : `${DASHBOARD_URL}${approvePath}`;
283472
- Me(`${import_picocolors12.default.bold(code.user_code)}
283589
+ Me(`${import_picocolors13.default.bold(code.user_code)}
283473
283590
 
283474
- ${import_picocolors12.default.dim(url)}`, "Approve in your browser");
283591
+ ${import_picocolors13.default.dim(url)}`, "Approve in your browser");
283475
283592
  openUrl(url);
283476
283593
  const s = Y2();
283477
283594
  s.start("Waiting for approval\u2026");
@@ -283538,7 +283655,7 @@ ${import_picocolors12.default.dim(url)}`, "Approve in your browser");
283538
283655
  if (reason) M2.error(reason);
283539
283656
  else if (provRes) M2.error(`Key provisioning returned ${provRes.status} from ${DASHBOARD_URL}/api/cli/provision-key.`);
283540
283657
  M2.error(
283541
- `The browser approval succeeded but the key handoff failed. Try again, or grab a ${import_picocolors12.default.bold("sk_test_")} key from the dashboard and set ${import_picocolors12.default.bold("ABLO_API_KEY")}.`
283658
+ `The browser approval succeeded but the key handoff failed. Try again, or grab a ${import_picocolors13.default.bold("sk_test_")} key from the dashboard and set ${import_picocolors13.default.bold("ABLO_API_KEY")}.`
283542
283659
  );
283543
283660
  process.exit(1);
283544
283661
  }
@@ -283558,9 +283675,9 @@ ${import_picocolors12.default.dim(url)}`, "Approve in your browser");
283558
283675
  { mode: "sandbox", activeProject: prov.project ?? void 0 }
283559
283676
  );
283560
283677
  s.stop(`Saved keys to ${path}`);
283561
- const where = prov.project ? ` ${import_picocolors12.default.dim(`(project ${prov.project.slug})`)}` : "";
283678
+ const where = prov.project ? ` ${import_picocolors13.default.dim(`(project ${prov.project.slug})`)}` : "";
283562
283679
  Se(
283563
- `${import_picocolors12.default.green("\u2713")} Logged in ${import_picocolors12.default.dim("(sandbox)")}${where}. Run ${import_picocolors12.default.bold("npx ablo push")} to push your schema.`
283680
+ `${import_picocolors13.default.green("\u2713")} Logged in ${import_picocolors13.default.dim("(sandbox)")}${where}. Run ${import_picocolors13.default.bold("npx ablo push")} to push your schema.`
283564
283681
  );
283565
283682
  }
283566
283683
  async function login(argv = [], deps = {}) {
@@ -283569,13 +283686,13 @@ async function login(argv = [], deps = {}) {
283569
283686
  function logout() {
283570
283687
  const removed = clearCredential();
283571
283688
  if (removed) {
283572
- console.log(` ${import_picocolors12.default.green("\u2713")} Logged out ${import_picocolors12.default.dim(`(credentials removed from ${configDir()})`)}`);
283689
+ console.log(` ${import_picocolors13.default.green("\u2713")} Logged out ${import_picocolors13.default.dim(`(credentials removed from ${configDir()})`)}`);
283573
283690
  } else {
283574
- console.log(` ${import_picocolors12.default.dim("\u25CB")} Not logged in \u2014 nothing to remove.`);
283691
+ console.log(` ${import_picocolors13.default.dim("\u25CB")} Not logged in \u2014 nothing to remove.`);
283575
283692
  }
283576
283693
  if (process.env.ABLO_API_KEY) {
283577
283694
  console.log(
283578
- import_picocolors12.default.dim(` Note: ${import_picocolors12.default.bold("ABLO_API_KEY")} is still set in this shell and takes precedence.`)
283695
+ import_picocolors13.default.dim(` Note: ${import_picocolors13.default.bold("ABLO_API_KEY")} is still set in this shell and takes precedence.`)
283579
283696
  );
283580
283697
  }
283581
283698
  }
@@ -283585,7 +283702,7 @@ init_config();
283585
283702
 
283586
283703
  // src/cli/mode.ts
283587
283704
  init_cjs_shims();
283588
- var import_picocolors13 = __toESM(require_picocolors(), 1);
283705
+ var import_picocolors14 = __toESM(require_picocolors(), 1);
283589
283706
  init_dist2();
283590
283707
  init_config();
283591
283708
  var PREFIX = { sandbox: "sk_test_", production: "rk_live_" };
@@ -283597,10 +283714,10 @@ function hintFor(m2, current) {
283597
283714
  }
283598
283715
  function apply(m2) {
283599
283716
  setMode(m2);
283600
- console.log(` ${import_picocolors13.default.green("\u2713")} now in ${import_picocolors13.default.bold(m2)}`);
283717
+ console.log(` ${import_picocolors14.default.green("\u2713")} now in ${import_picocolors14.default.bold(m2)}`);
283601
283718
  if (!getKeyEntry(m2)) {
283602
283719
  console.log(
283603
- import_picocolors13.default.dim(` No ${m2} key stored \u2014 run ${import_picocolors13.default.bold("ablo login")} or ${import_picocolors13.default.bold(`ablo login --api-key ${PREFIX[m2]}\u2026`)}.`)
283720
+ import_picocolors14.default.dim(` No ${m2} key stored \u2014 run ${import_picocolors14.default.bold("ablo login")} or ${import_picocolors14.default.bold(`ablo login --api-key ${PREFIX[m2]}\u2026`)}.`)
283604
283721
  );
283605
283722
  }
283606
283723
  }
@@ -283613,14 +283730,14 @@ async function mode(argv) {
283613
283730
  }
283614
283731
  if (arg) {
283615
283732
  console.error(
283616
- import_picocolors13.default.red(` unknown mode: ${arg}`) + import_picocolors13.default.dim(` (expected ${import_picocolors13.default.bold("sandbox")} or ${import_picocolors13.default.bold("production")})`)
283733
+ import_picocolors14.default.red(` unknown mode: ${arg}`) + import_picocolors14.default.dim(` (expected ${import_picocolors14.default.bold("sandbox")} or ${import_picocolors14.default.bold("production")})`)
283617
283734
  );
283618
283735
  process.exit(1);
283619
283736
  }
283620
283737
  const current = getMode();
283621
283738
  if (!process.stdin.isTTY || process.env.CI) {
283622
283739
  console.error(
283623
- import_picocolors13.default.red(" `ablo mode` needs an argument without a TTY: ") + import_picocolors13.default.bold("ablo mode sandbox") + import_picocolors13.default.dim(" | ") + import_picocolors13.default.bold("ablo mode production") + import_picocolors13.default.dim(` (current: ${current})`)
283740
+ import_picocolors14.default.red(" `ablo mode` needs an argument without a TTY: ") + import_picocolors14.default.bold("ablo mode sandbox") + import_picocolors14.default.dim(" | ") + import_picocolors14.default.bold("ablo mode production") + import_picocolors14.default.dim(` (current: ${current})`)
283624
283741
  );
283625
283742
  process.exit(1);
283626
283743
  }
@@ -283644,7 +283761,7 @@ init_projects();
283644
283761
 
283645
283762
  // src/cli/status.ts
283646
283763
  init_cjs_shims();
283647
- var import_picocolors14 = __toESM(require_picocolors(), 1);
283764
+ var import_picocolors15 = __toESM(require_picocolors(), 1);
283648
283765
  init_config();
283649
283766
  init_target();
283650
283767
  init_theme();
@@ -283652,9 +283769,9 @@ init_push();
283652
283769
  function expiryLabel(iso) {
283653
283770
  const ms = Date.parse(iso) - Date.now();
283654
283771
  if (Number.isNaN(ms)) return "";
283655
- if (ms <= 0) return import_picocolors14.default.red("expired");
283772
+ if (ms <= 0) return import_picocolors15.default.red("expired");
283656
283773
  const days = Math.floor(ms / (24 * 60 * 60 * 1e3));
283657
- return import_picocolors14.default.dim(days > 0 ? `expires in ${days}d` : "expires <1d");
283774
+ return import_picocolors15.default.dim(days > 0 ? `expires in ${days}d` : "expires <1d");
283658
283775
  }
283659
283776
  async function ping(apiUrl2) {
283660
283777
  const ctrl = new AbortController();
@@ -283738,27 +283855,27 @@ function formatConflict(conflict) {
283738
283855
  function printTargetLines(target, localProject) {
283739
283856
  const confirmed = target?.confirmed ?? null;
283740
283857
  if (confirmed?.organizationId) {
283741
- console.log(` ${import_picocolors14.default.dim("org")} ${import_picocolors14.default.dim(confirmed.organizationId)}`);
283858
+ console.log(` ${import_picocolors15.default.dim("org")} ${import_picocolors15.default.dim(confirmed.organizationId)}`);
283742
283859
  }
283743
283860
  let projectLine;
283744
283861
  if (confirmed?.project) {
283745
283862
  const p2 = confirmed.project;
283746
- projectLine = p2.isDefault ? `${import_picocolors14.default.bold("default")} ${import_picocolors14.default.dim("(org-default)")}` : `${import_picocolors14.default.bold(p2.slug)} ${import_picocolors14.default.dim(`(${p2.id})`)}`;
283863
+ projectLine = p2.isDefault ? `${import_picocolors15.default.bold("default")} ${import_picocolors15.default.dim("(org-default)")}` : `${import_picocolors15.default.bold(p2.slug)} ${import_picocolors15.default.dim(`(${p2.id})`)}`;
283747
283864
  } else if (confirmed) {
283748
- projectLine = `${import_picocolors14.default.bold("default")} ${import_picocolors14.default.dim("(org-default)")}`;
283865
+ projectLine = `${import_picocolors15.default.bold("default")} ${import_picocolors15.default.dim("(org-default)")}`;
283749
283866
  } else if (localProject) {
283750
- projectLine = `${import_picocolors14.default.bold(localProject.slug)} ${import_picocolors14.default.dim(`(${localProject.id})`)} ${import_picocolors14.default.yellow("(unconfirmed)")}`;
283867
+ projectLine = `${import_picocolors15.default.bold(localProject.slug)} ${import_picocolors15.default.dim(`(${localProject.id})`)} ${import_picocolors15.default.yellow("(unconfirmed)")}`;
283751
283868
  } else {
283752
- projectLine = `${import_picocolors14.default.bold("default")} ${target ? import_picocolors14.default.yellow("(unconfirmed)") : import_picocolors14.default.dim("(org-default)")}`;
283869
+ projectLine = `${import_picocolors15.default.bold("default")} ${target ? import_picocolors15.default.yellow("(unconfirmed)") : import_picocolors15.default.dim("(org-default)")}`;
283753
283870
  }
283754
- console.log(` ${import_picocolors14.default.dim("project")} ${projectLine}`);
283871
+ console.log(` ${import_picocolors15.default.dim("project")} ${projectLine}`);
283755
283872
  const env = confirmed?.environment ?? target?.keyEnv ?? null;
283756
283873
  if (env) {
283757
- const suffix = confirmed ? "" : ` ${import_picocolors14.default.yellow("(unconfirmed)")}`;
283758
- console.log(` ${import_picocolors14.default.dim("env")} ${import_picocolors14.default.bold(env)}${suffix}`);
283874
+ const suffix = confirmed ? "" : ` ${import_picocolors15.default.yellow("(unconfirmed)")}`;
283875
+ console.log(` ${import_picocolors15.default.dim("env")} ${import_picocolors15.default.bold(env)}${suffix}`);
283759
283876
  }
283760
283877
  for (const m2 of target?.mismatches ?? []) {
283761
- console.log(` ${import_picocolors14.default.yellow("\u26A0")} ${import_picocolors14.default.yellow(describeMismatch(m2))}`);
283878
+ console.log(` ${import_picocolors15.default.yellow("\u26A0")} ${import_picocolors15.default.yellow(describeMismatch(m2))}`);
283762
283879
  }
283763
283880
  }
283764
283881
  async function status(args = []) {
@@ -283829,80 +283946,80 @@ async function status(args = []) {
283829
283946
  return;
283830
283947
  }
283831
283948
  console.log(`
283832
- ${brand("ablo")} ${import_picocolors14.default.dim("status")}
283949
+ ${brand("ablo")} ${import_picocolors15.default.dim("status")}
283833
283950
  `);
283834
283951
  if (effective.key && effective.source && effective.source !== "stored") {
283835
283952
  const label = effective.source === "env" ? "ABLO_API_KEY env" : effective.source;
283836
283953
  console.log(
283837
- ` ${import_picocolors14.default.dim("key")} ${effective.key.slice(0, 12)}\u2026 ${import_picocolors14.default.dim(`(${label} \u2014 overrides stored)`)}`
283954
+ ` ${import_picocolors15.default.dim("key")} ${effective.key.slice(0, 12)}\u2026 ${import_picocolors15.default.dim(`(${label} \u2014 overrides stored)`)}`
283838
283955
  );
283839
283956
  } else if (!cfg) {
283840
- console.log(` ${import_picocolors14.default.yellow("!")} Not logged in \u2014 run ${import_picocolors14.default.bold("ablo login")}.`);
283957
+ console.log(` ${import_picocolors15.default.yellow("!")} Not logged in \u2014 run ${import_picocolors15.default.bold("ablo login")}.`);
283841
283958
  }
283842
- console.log(` ${import_picocolors14.default.dim("mode")} ${import_picocolors14.default.bold(mode2)}`);
283959
+ console.log(` ${import_picocolors15.default.dim("mode")} ${import_picocolors15.default.bold(mode2)}`);
283843
283960
  const activeEntry = getKeyEntry(mode2);
283844
283961
  const key = describeEffectiveKey(mode2, process.env.ABLO_API_KEY, activeEntry);
283845
283962
  if (key.keyMismatch) {
283846
- console.log(` ${import_picocolors14.default.yellow("!")} ${import_picocolors14.default.yellow(key.keyMismatch.message)}`);
283963
+ console.log(` ${import_picocolors15.default.yellow("!")} ${import_picocolors15.default.yellow(key.keyMismatch.message)}`);
283847
283964
  }
283848
283965
  const activeProject = getActiveProject();
283849
283966
  printTargetLines(target, activeProject);
283850
283967
  for (const m2 of ["sandbox", "production"]) {
283851
283968
  const entry = getKeyEntry(m2);
283852
- const marker = m2 === mode2 ? import_picocolors14.default.green("\u25CF") : import_picocolors14.default.dim("\u25CB");
283969
+ const marker = m2 === mode2 ? import_picocolors15.default.green("\u25CF") : import_picocolors15.default.dim("\u25CB");
283853
283970
  if (entry) {
283854
283971
  const exp = entry.expiresAt ? ` ${expiryLabel(entry.expiresAt)}` : "";
283855
- console.log(` ${marker} ${m2.padEnd(10)} ${import_picocolors14.default.dim(`${entry.apiKey.slice(0, 12)}\u2026`)}${exp}`);
283972
+ console.log(` ${marker} ${m2.padEnd(10)} ${import_picocolors15.default.dim(`${entry.apiKey.slice(0, 12)}\u2026`)}${exp}`);
283856
283973
  } else {
283857
- console.log(` ${marker} ${m2.padEnd(10)} ${import_picocolors14.default.dim("\u2014 no key")}`);
283974
+ console.log(` ${marker} ${m2.padEnd(10)} ${import_picocolors15.default.dim("\u2014 no key")}`);
283858
283975
  }
283859
283976
  }
283860
283977
  const org = target?.confirmed?.organizationId ?? activeEntry?.organizationId;
283861
283978
  const plan = resolvePushPlan();
283862
283979
  console.log(
283863
- ` ${import_picocolors14.default.dim("push")} ${plan.apiKey ? `${import_picocolors14.default.bold(plan.flow)} ${import_picocolors14.default.dim(`with ${plan.apiKey.slice(0, 12)}\u2026 (${plan.source})`)}` : `${import_picocolors14.default.bold(plan.flow)} ${import_picocolors14.default.yellow("\u2014 no credential")} ${import_picocolors14.default.dim(`(run ${import_picocolors14.default.bold("ablo login")} or set ${import_picocolors14.default.bold("ABLO_API_KEY")})`)}`}`
283980
+ ` ${import_picocolors15.default.dim("push")} ${plan.apiKey ? `${import_picocolors15.default.bold(plan.flow)} ${import_picocolors15.default.dim(`with ${plan.apiKey.slice(0, 12)}\u2026 (${plan.source})`)}` : `${import_picocolors15.default.bold(plan.flow)} ${import_picocolors15.default.yellow("\u2014 no credential")} ${import_picocolors15.default.dim(`(run ${import_picocolors15.default.bold("ablo login")} or set ${import_picocolors15.default.bold("ABLO_API_KEY")})`)}`}`
283864
283981
  );
283865
- process.stdout.write(` ${import_picocolors14.default.dim("api")} ${apiUrl2} `);
283982
+ process.stdout.write(` ${import_picocolors15.default.dim("api")} ${apiUrl2} `);
283866
283983
  const reachable = await ping(apiUrl2);
283867
- console.log(reachable ? import_picocolors14.default.green("reachable") : import_picocolors14.default.red("unreachable"));
283984
+ console.log(reachable ? import_picocolors15.default.green("reachable") : import_picocolors15.default.red("unreachable"));
283868
283985
  if (reachable) {
283869
283986
  const introspectKey = effective.key;
283870
283987
  const pushed = await fetchPushedSchema(apiUrl2, introspectKey);
283871
283988
  if (pushed?.active) {
283872
- const when = pushed.pushedAt ? ` ${import_picocolors14.default.dim(`@ ${pushed.pushedAt.slice(0, 10)}`)}` : "";
283873
- const ver = pushed.version != null ? ` ${import_picocolors14.default.dim(`(rev ${pushed.version})`)}` : "";
283874
- const hashLabel = pushed.hash ? ` ${import_picocolors14.default.dim(`hash ${pushed.hash}`)}` : "";
283875
- console.log(` ${import_picocolors14.default.dim("schema")} ${import_picocolors14.default.bold(`${pushed.models.length} models pushed`)}${ver}${hashLabel}${when}`);
283989
+ const when = pushed.pushedAt ? ` ${import_picocolors15.default.dim(`@ ${pushed.pushedAt.slice(0, 10)}`)}` : "";
283990
+ const ver = pushed.version != null ? ` ${import_picocolors15.default.dim(`(rev ${pushed.version})`)}` : "";
283991
+ const hashLabel = pushed.hash ? ` ${import_picocolors15.default.dim(`hash ${pushed.hash}`)}` : "";
283992
+ console.log(` ${import_picocolors15.default.dim("schema")} ${import_picocolors15.default.bold(`${pushed.models.length} models pushed`)}${ver}${hashLabel}${when}`);
283876
283993
  for (const m2 of pushed.models) {
283877
- const tn = m2.typename === m2.key ? import_picocolors14.default.dim(`typename=${m2.typename}`) : import_picocolors14.default.yellow(`typename=${m2.typename}`);
283994
+ const tn = m2.typename === m2.key ? import_picocolors15.default.dim(`typename=${m2.typename}`) : import_picocolors15.default.yellow(`typename=${m2.typename}`);
283878
283995
  const conflict = formatConflict(m2.conflict);
283879
- const conflictStr2 = conflict ? ` ${import_picocolors14.default.dim(`conflict=${conflict}`)}` : "";
283880
- console.log(` ${import_picocolors14.default.dim("\u2022")} ${m2.key.padEnd(14)} ${tn}${conflictStr2}`);
283996
+ const conflictStr2 = conflict ? ` ${import_picocolors15.default.dim(`conflict=${conflict}`)}` : "";
283997
+ console.log(` ${import_picocolors15.default.dim("\u2022")} ${m2.key.padEnd(14)} ${tn}${conflictStr2}`);
283881
283998
  }
283882
283999
  } else if (pushed && !pushed.active) {
283883
- console.log(` ${import_picocolors14.default.dim("schema")} ${import_picocolors14.default.yellow("none pushed")} ${import_picocolors14.default.dim(`(run ${import_picocolors14.default.bold("ablo push")} or ${import_picocolors14.default.bold("ablo dev")})`)}`);
284000
+ console.log(` ${import_picocolors15.default.dim("schema")} ${import_picocolors15.default.yellow("none pushed")} ${import_picocolors15.default.dim(`(run ${import_picocolors15.default.bold("ablo push")} or ${import_picocolors15.default.bold("ablo dev")})`)}`);
283884
284001
  }
283885
284002
  const firstPushedModel = pushed?.active ? pushed.models[0] : void 0;
283886
284003
  if (firstPushedModel !== void 0) {
283887
284004
  const probe = await probeDataPlane(apiUrl2, introspectKey, firstPushedModel.typename);
283888
284005
  if (probe.status === "no_database") {
283889
- console.log(` ${import_picocolors14.default.dim("data")} ${import_picocolors14.default.red("\u2717 no database registered")}${org ? import_picocolors14.default.dim(` for org ${org}`) : ""}`);
284006
+ console.log(` ${import_picocolors15.default.dim("data")} ${import_picocolors15.default.red("\u2717 no database registered")}${org ? import_picocolors15.default.dim(` for org ${org}`) : ""}`);
283890
284007
  console.log(
283891
- ` ${import_picocolors14.default.dim(
283892
- `reads/writes will fail with ${import_picocolors14.default.bold("tenant_routing_failed")}. Connect one with ${import_picocolors14.default.bold("ablo connect")}, or point ${import_picocolors14.default.bold("ABLO_API_KEY")} at an org that has a database.`
284008
+ ` ${import_picocolors15.default.dim(
284009
+ `reads/writes will fail with ${import_picocolors15.default.bold("tenant_routing_failed")}. Connect one with ${import_picocolors15.default.bold("ablo connect")}, or point ${import_picocolors15.default.bold("ABLO_API_KEY")} at an org that has a database.`
283893
284010
  )}`
283894
284011
  );
283895
284012
  } else if (probe.status === "intermittent") {
283896
- console.log(` ${import_picocolors14.default.dim("data")} ${import_picocolors14.default.red(`\u2717 database routing is intermittent`)} ${import_picocolors14.default.dim(`(${probe.ok} ok / ${probe.failed} failed of ${probe.ok + probe.failed})`)}${org ? import_picocolors14.default.dim(` for org ${org}`) : ""}`);
284013
+ console.log(` ${import_picocolors15.default.dim("data")} ${import_picocolors15.default.red(`\u2717 database routing is intermittent`)} ${import_picocolors15.default.dim(`(${probe.ok} ok / ${probe.failed} failed of ${probe.ok + probe.failed})`)}${org ? import_picocolors15.default.dim(` for org ${org}`) : ""}`);
283897
284014
  console.log(
283898
- ` ${import_picocolors14.default.dim(
283899
- `some reads/writes fail with ${import_picocolors14.default.bold("tenant_routing_failed")} \u2014 the registration is unstable. Re-establish it with ${import_picocolors14.default.bold("ablo connect")} (or check for a recent server redeploy).`
284015
+ ` ${import_picocolors15.default.dim(
284016
+ `some reads/writes fail with ${import_picocolors15.default.bold("tenant_routing_failed")} \u2014 the registration is unstable. Re-establish it with ${import_picocolors15.default.bold("ablo connect")} (or check for a recent server redeploy).`
283900
284017
  )}`
283901
284018
  );
283902
284019
  } else if (probe.status === "forbidden") {
283903
- console.log(` ${import_picocolors14.default.dim("data")} ${import_picocolors14.default.yellow("? key not authorized to read")}${probe.detail ? import_picocolors14.default.dim(` (${probe.detail})`) : ""}`);
284020
+ console.log(` ${import_picocolors15.default.dim("data")} ${import_picocolors15.default.yellow("? key not authorized to read")}${probe.detail ? import_picocolors15.default.dim(` (${probe.detail})`) : ""}`);
283904
284021
  } else if (probe.status === "unknown") {
283905
- console.log(` ${import_picocolors14.default.dim("data")} ${import_picocolors14.default.yellow(`? data-plane check inconclusive (${probe.detail})`)}`);
284022
+ console.log(` ${import_picocolors15.default.dim("data")} ${import_picocolors15.default.yellow(`? data-plane check inconclusive (${probe.detail})`)}`);
283906
284023
  }
283907
284024
  }
283908
284025
  }
@@ -283912,7 +284029,7 @@ async function status(args = []) {
283912
284029
  // src/cli/logs.ts
283913
284030
  init_cjs_shims();
283914
284031
  init_errors();
283915
- var import_picocolors15 = __toESM(require_picocolors(), 1);
284032
+ var import_picocolors16 = __toESM(require_picocolors(), 1);
283916
284033
  init_config();
283917
284034
  init_theme();
283918
284035
  init_push();
@@ -283979,10 +284096,10 @@ function resolveSince(since) {
283979
284096
  var sleep2 = (ms) => new Promise((r2) => setTimeout(r2, ms));
283980
284097
  function colorOp(op) {
283981
284098
  const label = op.padEnd(6);
283982
- if (op === "create") return import_picocolors15.default.green(label);
283983
- if (op === "update") return import_picocolors15.default.yellow(label);
283984
- if (op === "delete") return import_picocolors15.default.red(label);
283985
- return import_picocolors15.default.dim(label);
284099
+ if (op === "create") return import_picocolors16.default.green(label);
284100
+ if (op === "update") return import_picocolors16.default.yellow(label);
284101
+ if (op === "delete") return import_picocolors16.default.red(label);
284102
+ return import_picocolors16.default.dim(label);
283986
284103
  }
283987
284104
  function render(e2, json) {
283988
284105
  if (json) {
@@ -283991,21 +284108,21 @@ function render(e2, json) {
283991
284108
  return;
283992
284109
  }
283993
284110
  const t = new Date(e2.at).toLocaleTimeString();
283994
- const actor = e2.actor ? import_picocolors15.default.dim(` ${e2.actor}`) : "";
283995
- console.log(` ${import_picocolors15.default.dim(t)} ${colorOp(e2.op)} ${import_picocolors15.default.bold(e2.model)} ${import_picocolors15.default.dim(e2.recordId)}${actor}`);
284111
+ const actor = e2.actor ? import_picocolors16.default.dim(` ${e2.actor}`) : "";
284112
+ console.log(` ${import_picocolors16.default.dim(t)} ${colorOp(e2.op)} ${import_picocolors16.default.bold(e2.model)} ${import_picocolors16.default.dim(e2.recordId)}${actor}`);
283996
284113
  }
283997
284114
  async function logs(argv) {
283998
284115
  let args;
283999
284116
  try {
284000
284117
  args = parseLogsArgs(argv);
284001
284118
  } catch (err) {
284002
- console.error(import_picocolors15.default.red(` ${err instanceof Error ? err.message : String(err)}`));
284119
+ console.error(import_picocolors16.default.red(` ${err instanceof Error ? err.message : String(err)}`));
284003
284120
  process.exit(1);
284004
284121
  }
284005
284122
  const apiKey = resolveApiKey(args.mode);
284006
284123
  if (!apiKey) {
284007
284124
  console.error(
284008
- import_picocolors15.default.red(` No API key.`) + import_picocolors15.default.dim(` Run ${import_picocolors15.default.bold("ablo login")} or set ${import_picocolors15.default.bold("ABLO_API_KEY")}.`)
284125
+ import_picocolors16.default.red(` No API key.`) + import_picocolors16.default.dim(` Run ${import_picocolors16.default.bold("ablo login")} or set ${import_picocolors16.default.bold("ABLO_API_KEY")}.`)
284009
284126
  );
284010
284127
  process.exit(1);
284011
284128
  }
@@ -284019,7 +284136,7 @@ async function logs(argv) {
284019
284136
  if (!res) return null;
284020
284137
  if (!res.ok) {
284021
284138
  const body = await res.json().catch(() => ({}));
284022
- console.error(import_picocolors15.default.red(` logs failed (${res.status}): ${body.reason ?? body.message ?? ""}`));
284139
+ console.error(import_picocolors16.default.red(` logs failed (${res.status}): ${body.reason ?? body.message ?? ""}`));
284023
284140
  process.exit(1);
284024
284141
  }
284025
284142
  const json = await res.json();
@@ -284030,7 +284147,7 @@ async function logs(argv) {
284030
284147
  }
284031
284148
  if (!args.json) {
284032
284149
  console.log(`
284033
- ${brand("ablo")} ${import_picocolors15.default.dim("logs")} ${import_picocolors15.default.dim(`(${args.mode ?? "active"} mode)`)}
284150
+ ${brand("ablo")} ${import_picocolors16.default.dim("logs")} ${import_picocolors16.default.dim(`(${args.mode ?? "active"} mode)`)}
284034
284151
  `);
284035
284152
  }
284036
284153
  const initial = await fetchPage({
@@ -284040,13 +284157,13 @@ async function logs(argv) {
284040
284157
  ...args.op ? { op: args.op } : {}
284041
284158
  });
284042
284159
  if (!initial) {
284043
- console.error(import_picocolors15.default.red(` Couldn't reach ${baseUrl2}.`));
284160
+ console.error(import_picocolors16.default.red(` Couldn't reach ${baseUrl2}.`));
284044
284161
  process.exit(1);
284045
284162
  }
284046
284163
  for (const e2 of initial.events) render(e2, args.json);
284047
284164
  let cursor = initial.cursor;
284048
284165
  if (!args.follow) return;
284049
- if (!args.json) console.log(` ${import_picocolors15.default.dim("watching for new activity \u2026 (Ctrl-C to stop)")}
284166
+ if (!args.json) console.log(` ${import_picocolors16.default.dim("watching for new activity \u2026 (Ctrl-C to stop)")}
284050
284167
  `);
284051
284168
  for (; ; ) {
284052
284169
  await sleep2(1500);
@@ -284064,7 +284181,7 @@ async function logs(argv) {
284064
284181
  // src/cli/webhooks.ts
284065
284182
  init_cjs_shims();
284066
284183
  var import_fs8 = require("fs");
284067
- var import_picocolors16 = __toESM(require_picocolors(), 1);
284184
+ var import_picocolors17 = __toESM(require_picocolors(), 1);
284068
284185
  init_credentialPolicy();
284069
284186
  init_config();
284070
284187
  init_theme();
@@ -284097,12 +284214,12 @@ function requireKey2(mode2) {
284097
284214
  const apiKey = resolveApiKey(mode2);
284098
284215
  if (!apiKey) {
284099
284216
  console.error(
284100
- import_picocolors16.default.red(" No API key.") + import_picocolors16.default.dim(` Run ${import_picocolors16.default.bold("ablo login")} or set ${import_picocolors16.default.bold("ABLO_API_KEY")}.`)
284217
+ import_picocolors17.default.red(" No API key.") + import_picocolors17.default.dim(` Run ${import_picocolors17.default.bold("ablo login")} or set ${import_picocolors17.default.bold("ABLO_API_KEY")}.`)
284101
284218
  );
284102
284219
  process.exit(1);
284103
284220
  }
284104
284221
  if (classifyCredentialKind(apiKey) !== "secret") {
284105
- console.error(import_picocolors16.default.red(" Managing webhooks requires a secret key ") + import_picocolors16.default.dim("(sk_test_ / sk_live_)."));
284222
+ console.error(import_picocolors17.default.red(" Managing webhooks requires a secret key ") + import_picocolors17.default.dim("(sk_test_ / sk_live_)."));
284106
284223
  process.exit(1);
284107
284224
  }
284108
284225
  return apiKey;
@@ -284118,12 +284235,12 @@ async function api(apiKey, method, path, body) {
284118
284235
  ...body ? { body: JSON.stringify(body) } : {}
284119
284236
  }).catch(() => null);
284120
284237
  if (!res) {
284121
- console.error(import_picocolors16.default.red(` Couldn't reach ${baseUrl()}.`));
284238
+ console.error(import_picocolors17.default.red(` Couldn't reach ${baseUrl()}.`));
284122
284239
  process.exit(1);
284123
284240
  }
284124
284241
  if (!res.ok) {
284125
284242
  const err = await res.json().catch(() => ({}));
284126
- console.error(import_picocolors16.default.red(` Request failed (${res.status}): ${err.message ?? err.reason ?? ""}`));
284243
+ console.error(import_picocolors17.default.red(` Request failed (${res.status}): ${err.message ?? err.reason ?? ""}`));
284127
284244
  process.exit(1);
284128
284245
  }
284129
284246
  return await res.json();
@@ -284145,11 +284262,11 @@ ${line}
284145
284262
  return file;
284146
284263
  }
284147
284264
  function printEndpoint(e2) {
284148
- const dot = e2.status === "enabled" ? import_picocolors16.default.green("\u25CF") : import_picocolors16.default.red("\u25CF");
284149
- const health = e2.last_error ? import_picocolors16.default.red(` last error: ${e2.last_error}`) : "";
284150
- console.log(` ${dot} ${import_picocolors16.default.bold(e2.id)} ${e2.url}`);
284265
+ const dot = e2.status === "enabled" ? import_picocolors17.default.green("\u25CF") : import_picocolors17.default.red("\u25CF");
284266
+ const health = e2.last_error ? import_picocolors17.default.red(` last error: ${e2.last_error}`) : "";
284267
+ console.log(` ${dot} ${import_picocolors17.default.bold(e2.id)} ${e2.url}`);
284151
284268
  console.log(
284152
- import_picocolors16.default.dim(
284269
+ import_picocolors17.default.dim(
284153
284270
  ` ${e2.status} \xB7 ${e2.environment} \xB7 events ${e2.enabled_events.join(",")} \xB7 cursor ${e2.cursor ?? "\u2014"}${health}`
284154
284271
  )
284155
284272
  );
@@ -284161,7 +284278,7 @@ async function webhooks(argv) {
284161
284278
  if (sub === "create") {
284162
284279
  const url = positional(rest);
284163
284280
  if (!url) {
284164
- console.error(import_picocolors16.default.red(" Usage: ") + brand("ablo webhooks create <url>"));
284281
+ console.error(import_picocolors17.default.red(" Usage: ") + brand("ablo webhooks create <url>"));
284165
284282
  process.exit(1);
284166
284283
  }
284167
284284
  const apiKey = requireKey2(mode2);
@@ -284173,8 +284290,8 @@ async function webhooks(argv) {
284173
284290
  });
284174
284291
  const file = writeSecretToEnv(created.secret);
284175
284292
  console.log(`
284176
- ${import_picocolors16.default.green("\u2713")} Registered ${import_picocolors16.default.bold(created.id)} \u2192 ${created.url}`);
284177
- console.log(` ${import_picocolors16.default.green("\u2713")} Wrote ${import_picocolors16.default.bold(ENV_KEY)} to ${import_picocolors16.default.bold(file)} ${import_picocolors16.default.dim("(shown once)")}
284293
+ ${import_picocolors17.default.green("\u2713")} Registered ${import_picocolors17.default.bold(created.id)} \u2192 ${created.url}`);
284294
+ console.log(` ${import_picocolors17.default.green("\u2713")} Wrote ${import_picocolors17.default.bold(ENV_KEY)} to ${import_picocolors17.default.bold(file)} ${import_picocolors17.default.dim("(shown once)")}
284178
284295
  `);
284179
284296
  return;
284180
284297
  }
@@ -284182,7 +284299,7 @@ async function webhooks(argv) {
284182
284299
  const apiKey = requireKey2(mode2);
284183
284300
  const { data } = await api(apiKey, "GET", "");
284184
284301
  if (data.length === 0) {
284185
- console.log(import_picocolors16.default.dim(" No webhook endpoints. ") + brand("ablo webhooks create <url>"));
284302
+ console.log(import_picocolors17.default.dim(" No webhook endpoints. ") + brand("ablo webhooks create <url>"));
284186
284303
  return;
284187
284304
  }
284188
284305
  console.log();
@@ -284193,40 +284310,40 @@ async function webhooks(argv) {
284193
284310
  if (sub === "roll") {
284194
284311
  const id = positional(rest);
284195
284312
  if (!id) {
284196
- console.error(import_picocolors16.default.red(" Usage: ") + brand("ablo webhooks roll <id>"));
284313
+ console.error(import_picocolors17.default.red(" Usage: ") + brand("ablo webhooks roll <id>"));
284197
284314
  process.exit(1);
284198
284315
  }
284199
284316
  const apiKey = requireKey2(mode2);
284200
284317
  const rolled = await api(apiKey, "POST", `/${id}/roll_secret`);
284201
284318
  const file = writeSecretToEnv(rolled.secret);
284202
284319
  console.log(`
284203
- ${import_picocolors16.default.green("\u2713")} Rolled secret for ${import_picocolors16.default.bold(id)} \u2192 ${import_picocolors16.default.bold(file)} ${import_picocolors16.default.dim("(old secret now invalid)")}
284320
+ ${import_picocolors17.default.green("\u2713")} Rolled secret for ${import_picocolors17.default.bold(id)} \u2192 ${import_picocolors17.default.bold(file)} ${import_picocolors17.default.dim("(old secret now invalid)")}
284204
284321
  `);
284205
284322
  return;
284206
284323
  }
284207
284324
  if (sub === "enable") {
284208
284325
  const id = positional(rest);
284209
284326
  if (!id) {
284210
- console.error(import_picocolors16.default.red(" Usage: ") + brand("ablo webhooks enable <id>"));
284327
+ console.error(import_picocolors17.default.red(" Usage: ") + brand("ablo webhooks enable <id>"));
284211
284328
  process.exit(1);
284212
284329
  }
284213
284330
  const apiKey = requireKey2(mode2);
284214
284331
  const e2 = await api(apiKey, "POST", `/${id}/enable`);
284215
- console.log(` ${import_picocolors16.default.green("\u2713")} Re-enabled ${import_picocolors16.default.bold(e2.id)}`);
284332
+ console.log(` ${import_picocolors17.default.green("\u2713")} Re-enabled ${import_picocolors17.default.bold(e2.id)}`);
284216
284333
  return;
284217
284334
  }
284218
284335
  if (sub === "rm" || sub === "delete") {
284219
284336
  const id = positional(rest);
284220
284337
  if (!id) {
284221
- console.error(import_picocolors16.default.red(" Usage: ") + brand("ablo webhooks rm <id>"));
284338
+ console.error(import_picocolors17.default.red(" Usage: ") + brand("ablo webhooks rm <id>"));
284222
284339
  process.exit(1);
284223
284340
  }
284224
284341
  const apiKey = requireKey2(mode2);
284225
284342
  await api(apiKey, "DELETE", `/${id}`);
284226
- console.log(` ${import_picocolors16.default.green("\u2713")} Removed ${import_picocolors16.default.bold(id)}`);
284343
+ console.log(` ${import_picocolors17.default.green("\u2713")} Removed ${import_picocolors17.default.bold(id)}`);
284227
284344
  return;
284228
284345
  }
284229
- console.log(` ${import_picocolors16.default.bold("Usage:")}`);
284346
+ console.log(` ${import_picocolors17.default.bold("Usage:")}`);
284230
284347
  console.log(` ${brand("ablo webhooks create <url>")} Register an endpoint; writes ${ENV_KEY}`);
284231
284348
  console.log(` ${brand("ablo webhooks list")} List endpoints + delivery health`);
284232
284349
  console.log(` ${brand("ablo webhooks roll <id>")} Mint a fresh signing secret`);
@@ -284238,7 +284355,7 @@ async function webhooks(argv) {
284238
284355
  // src/cli/check.ts
284239
284356
  init_cjs_shims();
284240
284357
  init_errors();
284241
- var import_picocolors17 = __toESM(require_picocolors(), 1);
284358
+ var import_picocolors18 = __toESM(require_picocolors(), 1);
284242
284359
  init_src();
284243
284360
  var import_schema6 = require("@abloatai/ablo/schema");
284244
284361
  init_push();
@@ -284276,13 +284393,13 @@ async function check(argv) {
284276
284393
  try {
284277
284394
  args = parseCheckArgs(argv);
284278
284395
  } catch (err) {
284279
- console.error(import_picocolors17.default.red(` ${err instanceof Error ? err.message : String(err)}`));
284396
+ console.error(import_picocolors18.default.red(` ${err instanceof Error ? err.message : String(err)}`));
284280
284397
  process.exit(1);
284281
284398
  }
284282
284399
  const dbUrl = process.env.DATABASE_URL ?? process.env.ABLO_DATABASE_URL;
284283
284400
  if (!dbUrl) {
284284
284401
  console.error(
284285
- import_picocolors17.default.red(` No database.`) + import_picocolors17.default.dim(` Set ${import_picocolors17.default.bold("DATABASE_URL")} to the Postgres you want Ablo to adopt.`)
284402
+ import_picocolors18.default.red(` No database.`) + import_picocolors18.default.dim(` Set ${import_picocolors18.default.bold("DATABASE_URL")} to the Postgres you want Ablo to adopt.`)
284286
284403
  );
284287
284404
  process.exit(1);
284288
284405
  }
@@ -284297,7 +284414,7 @@ async function check(argv) {
284297
284414
  [args.appSchema]
284298
284415
  );
284299
284416
  } catch (err) {
284300
- console.error(import_picocolors17.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
284417
+ console.error(import_picocolors18.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
284301
284418
  await sql.end({ timeout: 2 });
284302
284419
  process.exit(1);
284303
284420
  }
@@ -284312,7 +284429,7 @@ async function check(argv) {
284312
284429
  set.add(r2.column_name);
284313
284430
  }
284314
284431
  console.log(`
284315
- ${brand("ablo")} ${import_picocolors17.default.dim("check")} ${import_picocolors17.default.dim(`schema "${args.appSchema}"`)}
284432
+ ${brand("ablo")} ${import_picocolors18.default.dim("check")} ${import_picocolors18.default.dim(`schema "${args.appSchema}"`)}
284316
284433
  `);
284317
284434
  const declaredTables = /* @__PURE__ */ new Set();
284318
284435
  let errors = 0;
@@ -284322,7 +284439,7 @@ async function check(argv) {
284322
284439
  declaredTables.add(table);
284323
284440
  const present = colsByTable.get(table);
284324
284441
  if (!present) {
284325
- console.log(` ${import_picocolors17.default.red("\u2717")} ${import_picocolors17.default.bold(key)} ${import_picocolors17.default.dim("\u2192")} table ${import_picocolors17.default.bold(table)} ${import_picocolors17.default.red("not found")}`);
284442
+ console.log(` ${import_picocolors18.default.red("\u2717")} ${import_picocolors18.default.bold(key)} ${import_picocolors18.default.dim("\u2192")} table ${import_picocolors18.default.bold(table)} ${import_picocolors18.default.red("not found")}`);
284326
284443
  errors++;
284327
284444
  continue;
284328
284445
  }
@@ -284344,26 +284461,26 @@ async function check(argv) {
284344
284461
  if (!present.has(col)) problems.push(`missing column "${col}" (field ${fieldName})`);
284345
284462
  }
284346
284463
  if (problems.length > 0) {
284347
- console.log(` ${import_picocolors17.default.red("\u2717")} ${import_picocolors17.default.bold(key)} ${import_picocolors17.default.dim("\u2192")} ${table}`);
284348
- for (const p2 of problems) console.log(` ${import_picocolors17.default.red("\u2022")} ${p2}`);
284349
- for (const w2 of warns) console.log(` ${import_picocolors17.default.yellow("\u2022")} ${w2}`);
284464
+ console.log(` ${import_picocolors18.default.red("\u2717")} ${import_picocolors18.default.bold(key)} ${import_picocolors18.default.dim("\u2192")} ${table}`);
284465
+ for (const p2 of problems) console.log(` ${import_picocolors18.default.red("\u2022")} ${p2}`);
284466
+ for (const w2 of warns) console.log(` ${import_picocolors18.default.yellow("\u2022")} ${w2}`);
284350
284467
  errors++;
284351
284468
  } else if (warns.length > 0) {
284352
- console.log(` ${import_picocolors17.default.yellow("!")} ${import_picocolors17.default.bold(key)} ${import_picocolors17.default.dim("\u2192")} ${table}`);
284353
- for (const w2 of warns) console.log(` ${import_picocolors17.default.yellow("\u2022")} ${w2}`);
284469
+ console.log(` ${import_picocolors18.default.yellow("!")} ${import_picocolors18.default.bold(key)} ${import_picocolors18.default.dim("\u2192")} ${table}`);
284470
+ for (const w2 of warns) console.log(` ${import_picocolors18.default.yellow("\u2022")} ${w2}`);
284354
284471
  warnings++;
284355
284472
  } else {
284356
- console.log(` ${import_picocolors17.default.green("\u2713")} ${import_picocolors17.default.bold(key)} ${import_picocolors17.default.dim(`\u2192 ${table} (id, ${orgCol ?? "no org"} ok)`)}`);
284473
+ console.log(` ${import_picocolors18.default.green("\u2713")} ${import_picocolors18.default.bold(key)} ${import_picocolors18.default.dim(`\u2192 ${table} (id, ${orgCol ?? "no org"} ok)`)}`);
284357
284474
  }
284358
284475
  }
284359
284476
  const modelCount = Object.keys(schemaJson.models).length;
284360
284477
  const ignored = [...colsByTable.keys()].filter((t) => !declaredTables.has(t)).length;
284361
284478
  console.log(
284362
284479
  `
284363
- ${modelCount} model${modelCount === 1 ? "" : "s"} \xB7 ${import_picocolors17.default.green(`${modelCount - errors - warnings} ok`)}` + (warnings ? ` \xB7 ${import_picocolors17.default.yellow(`${warnings} warning${warnings === 1 ? "" : "s"}`)}` : "") + (errors ? ` \xB7 ${import_picocolors17.default.red(`${errors} error${errors === 1 ? "" : "s"}`)}` : "")
284480
+ ${modelCount} model${modelCount === 1 ? "" : "s"} \xB7 ${import_picocolors18.default.green(`${modelCount - errors - warnings} ok`)}` + (warnings ? ` \xB7 ${import_picocolors18.default.yellow(`${warnings} warning${warnings === 1 ? "" : "s"}`)}` : "") + (errors ? ` \xB7 ${import_picocolors18.default.red(`${errors} error${errors === 1 ? "" : "s"}`)}` : "")
284364
284481
  );
284365
284482
  if (ignored > 0) {
284366
- console.log(` ${import_picocolors17.default.dim(`${ignored} other table${ignored === 1 ? "" : "s"} in your database \u2014 ignored by Ablo`)}`);
284483
+ console.log(` ${import_picocolors18.default.dim(`${ignored} other table${ignored === 1 ? "" : "s"} in your database \u2014 ignored by Ablo`)}`);
284367
284484
  }
284368
284485
  console.log();
284369
284486
  process.exit(errors > 0 ? 1 : 0);
@@ -284371,7 +284488,7 @@ async function check(argv) {
284371
284488
 
284372
284489
  // src/cli/upgrade.ts
284373
284490
  init_cjs_shims();
284374
- var import_picocolors18 = __toESM(require_picocolors(), 1);
284491
+ var import_picocolors19 = __toESM(require_picocolors(), 1);
284375
284492
  var import_ts_morph = __toESM(require_ts_morph(), 1);
284376
284493
  var DEFAULT_GLOBS = ["app/**/*.{ts,tsx}", "src/**/*.{ts,tsx}", "ablo/**/*.{ts,tsx}", "lib/**/*.{ts,tsx}"];
284377
284494
  var VERB_ARGS = {
@@ -284449,7 +284566,7 @@ async function upgrade(argv) {
284449
284566
  project.addSourceFilesAtPaths(globs.length > 0 ? globs : DEFAULT_GLOBS);
284450
284567
  const files = project.getSourceFiles();
284451
284568
  if (files.length === 0) {
284452
- console.log(import_picocolors18.default.yellow(' No .ts/.tsx files found. Pass a glob, e.g. `ablo upgrade "src/**/*.tsx"`.'));
284569
+ console.log(import_picocolors19.default.yellow(' No .ts/.tsx files found. Pass a glob, e.g. `ablo upgrade "src/**/*.tsx"`.'));
284453
284570
  return;
284454
284571
  }
284455
284572
  const edits = [];
@@ -284523,39 +284640,39 @@ async function upgrade(argv) {
284523
284640
  const rel = (f) => f.replace(cwd + "/", "");
284524
284641
  console.log();
284525
284642
  if (edits.length === 0 && manual.length === 0) {
284526
- console.log(import_picocolors18.default.green(" \u2713 Nothing to migrate \u2014 your code is already on the current API."));
284643
+ console.log(import_picocolors19.default.green(" \u2713 Nothing to migrate \u2014 your code is already on the current API."));
284527
284644
  return;
284528
284645
  }
284529
284646
  if (edits.length > 0) {
284530
- console.log(import_picocolors18.default.bold(` ${write ? "Applied" : "Would apply"} ${edits.length} change${edits.length === 1 ? "" : "s"}:`));
284647
+ console.log(import_picocolors19.default.bold(` ${write ? "Applied" : "Would apply"} ${edits.length} change${edits.length === 1 ? "" : "s"}:`));
284531
284648
  for (const e2 of edits) {
284532
- console.log(` ${import_picocolors18.default.dim(`${rel(e2.file)}:${e2.line}`)} ${import_picocolors18.default.cyan(e2.rule)}`);
284533
- console.log(` ${import_picocolors18.default.red("-")} ${e2.before}`);
284534
- console.log(` ${import_picocolors18.default.green("+")} ${e2.after}`);
284649
+ console.log(` ${import_picocolors19.default.dim(`${rel(e2.file)}:${e2.line}`)} ${import_picocolors19.default.cyan(e2.rule)}`);
284650
+ console.log(` ${import_picocolors19.default.red("-")} ${e2.before}`);
284651
+ console.log(` ${import_picocolors19.default.green("+")} ${e2.after}`);
284535
284652
  }
284536
284653
  }
284537
284654
  if (manual.length > 0) {
284538
284655
  console.log();
284539
- console.log(import_picocolors18.default.bold(import_picocolors18.default.yellow(` ${manual.length} spot${manual.length === 1 ? "" : "s"} need manual review (structural):`)));
284656
+ console.log(import_picocolors19.default.bold(import_picocolors19.default.yellow(` ${manual.length} spot${manual.length === 1 ? "" : "s"} need manual review (structural):`)));
284540
284657
  for (const m2 of manual) {
284541
- console.log(` ${import_picocolors18.default.dim(`${rel(m2.file)}:${m2.line}`)} ${import_picocolors18.default.yellow(m2.rule)}`);
284542
- console.log(` ${import_picocolors18.default.dim(m2.snippet)}`);
284658
+ console.log(` ${import_picocolors19.default.dim(`${rel(m2.file)}:${m2.line}`)} ${import_picocolors19.default.yellow(m2.rule)}`);
284659
+ console.log(` ${import_picocolors19.default.dim(m2.snippet)}`);
284543
284660
  console.log(` \u2192 ${m2.hint}`);
284544
284661
  }
284545
284662
  }
284546
284663
  console.log();
284547
284664
  if (write) {
284548
284665
  await project.save();
284549
- console.log(import_picocolors18.default.green(` \u2713 Wrote ${edits.length} change${edits.length === 1 ? "" : "s"}. Review the diff, run your typecheck.`));
284666
+ console.log(import_picocolors19.default.green(` \u2713 Wrote ${edits.length} change${edits.length === 1 ? "" : "s"}. Review the diff, run your typecheck.`));
284550
284667
  } else {
284551
- console.log(import_picocolors18.default.dim(" Dry run. Re-run with `--write` to apply the auto-fixes above (manual items are never auto-written)."));
284668
+ console.log(import_picocolors19.default.dim(" Dry run. Re-run with `--write` to apply the auto-fixes above (manual items are never auto-written)."));
284552
284669
  }
284553
284670
  }
284554
284671
 
284555
284672
  // src/cli/pull.ts
284556
284673
  init_cjs_shims();
284557
284674
  init_errors();
284558
- var import_picocolors19 = __toESM(require_picocolors(), 1);
284675
+ var import_picocolors20 = __toESM(require_picocolors(), 1);
284559
284676
  init_src();
284560
284677
  var import_fs9 = require("fs");
284561
284678
  init_theme();
@@ -284669,45 +284786,45 @@ async function pull(argv) {
284669
284786
  try {
284670
284787
  args = parsePullArgs(argv);
284671
284788
  } catch (err) {
284672
- console.error(import_picocolors19.default.red(` ${err instanceof Error ? err.message : String(err)}`));
284789
+ console.error(import_picocolors20.default.red(` ${err instanceof Error ? err.message : String(err)}`));
284673
284790
  process.exit(1);
284674
284791
  }
284675
284792
  const dbUrl = process.env.DATABASE_URL ?? process.env.ABLO_DATABASE_URL;
284676
284793
  if (!dbUrl) {
284677
- console.error(import_picocolors19.default.red(` No database.`) + import_picocolors19.default.dim(` Set ${import_picocolors19.default.bold("DATABASE_URL")} to the Postgres to pull from.`));
284794
+ console.error(import_picocolors20.default.red(` No database.`) + import_picocolors20.default.dim(` Set ${import_picocolors20.default.bold("DATABASE_URL")} to the Postgres to pull from.`));
284678
284795
  process.exit(1);
284679
284796
  }
284680
284797
  if ((0, import_fs9.existsSync)(args.out) && !args.force) {
284681
284798
  console.error(
284682
- import_picocolors19.default.red(` ${args.out} already exists.`) + import_picocolors19.default.dim(` Re-run with ${import_picocolors19.default.bold("--force")} to overwrite.`)
284799
+ import_picocolors20.default.red(` ${args.out} already exists.`) + import_picocolors20.default.dim(` Re-run with ${import_picocolors20.default.bold("--force")} to overwrite.`)
284683
284800
  );
284684
284801
  process.exit(1);
284685
284802
  }
284686
284803
  console.log(`
284687
- ${brand("ablo")} ${import_picocolors19.default.dim("pull")} ${import_picocolors19.default.dim(`schema "${args.appSchema}"`)}
284804
+ ${brand("ablo")} ${import_picocolors20.default.dim("pull")} ${import_picocolors20.default.dim(`schema "${args.appSchema}"`)}
284688
284805
  `);
284689
284806
  let result;
284690
284807
  try {
284691
284808
  result = await buildSchemaSourceFromDb({ dbUrl, appSchema: args.appSchema, importPath: args.importPath });
284692
284809
  } catch (err) {
284693
- console.error(import_picocolors19.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
284810
+ console.error(import_picocolors20.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
284694
284811
  process.exit(1);
284695
284812
  }
284696
284813
  if (result.models.length === 0) {
284697
284814
  console.error(
284698
- import_picocolors19.default.yellow(` No adoptable tables found`) + import_picocolors19.default.dim(` (a model needs an ${import_picocolors19.default.bold("id")} + ${import_picocolors19.default.bold("organization_id")} column).`)
284815
+ import_picocolors20.default.yellow(` No adoptable tables found`) + import_picocolors20.default.dim(` (a model needs an ${import_picocolors20.default.bold("id")} + ${import_picocolors20.default.bold("organization_id")} column).`)
284699
284816
  );
284700
284817
  process.exit(1);
284701
284818
  }
284702
284819
  (0, import_fs9.writeFileSync)(args.out, result.source);
284703
- console.log(` ${import_picocolors19.default.green("\u2713")} wrote ${import_picocolors19.default.bold(args.out)} ${import_picocolors19.default.dim(`(${result.models.length} models)`)}`);
284704
- console.log(` ${import_picocolors19.default.dim(`models: ${result.models.join(", ")}`)}`);
284820
+ console.log(` ${import_picocolors20.default.green("\u2713")} wrote ${import_picocolors20.default.bold(args.out)} ${import_picocolors20.default.dim(`(${result.models.length} models)`)}`);
284821
+ console.log(` ${import_picocolors20.default.dim(`models: ${result.models.join(", ")}`)}`);
284705
284822
  if (result.skipped > 0) {
284706
- console.log(` ${import_picocolors19.default.dim(`${result.skipped} table(s) skipped \u2014 no id/organization_id`)}`);
284823
+ console.log(` ${import_picocolors20.default.dim(`${result.skipped} table(s) skipped \u2014 no id/organization_id`)}`);
284707
284824
  }
284708
284825
  console.log(
284709
284826
  `
284710
- ${import_picocolors19.default.dim("Introspection is lossy (enums, JSON shape, relations). Review the file, then")} ${import_picocolors19.default.bold("ablo check")}.
284827
+ ${import_picocolors20.default.dim("Introspection is lossy (enums, JSON shape, relations). Review the file, then")} ${import_picocolors20.default.bold("ablo check")}.
284711
284828
  `
284712
284829
  );
284713
284830
  }
@@ -284715,7 +284832,7 @@ async function pull(argv) {
284715
284832
  // src/cli/prismaPull.ts
284716
284833
  init_cjs_shims();
284717
284834
  init_errors();
284718
- var import_picocolors20 = __toESM(require_picocolors(), 1);
284835
+ var import_picocolors21 = __toESM(require_picocolors(), 1);
284719
284836
  var import_fs10 = require("fs");
284720
284837
  init_theme();
284721
284838
 
@@ -285000,55 +285117,55 @@ async function prismaPull(argv) {
285000
285117
  try {
285001
285118
  args = parsePrismaPullArgs(argv);
285002
285119
  } catch (err) {
285003
- console.error(import_picocolors20.default.red(` ${err instanceof Error ? err.message : String(err)}`));
285120
+ console.error(import_picocolors21.default.red(` ${err instanceof Error ? err.message : String(err)}`));
285004
285121
  process.exit(1);
285005
285122
  }
285006
285123
  if (!(0, import_fs10.existsSync)(args.schema)) {
285007
285124
  console.error(
285008
- import_picocolors20.default.red(` No Prisma schema at ${import_picocolors20.default.bold(args.schema)}.`) + import_picocolors20.default.dim(` Pass a path: ${import_picocolors20.default.bold("ablo pull prisma <path>")}.`)
285125
+ import_picocolors21.default.red(` No Prisma schema at ${import_picocolors21.default.bold(args.schema)}.`) + import_picocolors21.default.dim(` Pass a path: ${import_picocolors21.default.bold("ablo pull prisma <path>")}.`)
285009
285126
  );
285010
285127
  process.exit(1);
285011
285128
  }
285012
285129
  if ((0, import_fs10.existsSync)(args.out) && !args.force) {
285013
285130
  console.error(
285014
- import_picocolors20.default.red(` ${args.out} already exists.`) + import_picocolors20.default.dim(` Re-run with ${import_picocolors20.default.bold("--force")} to overwrite.`)
285131
+ import_picocolors21.default.red(` ${args.out} already exists.`) + import_picocolors21.default.dim(` Re-run with ${import_picocolors21.default.bold("--force")} to overwrite.`)
285015
285132
  );
285016
285133
  process.exit(1);
285017
285134
  }
285018
285135
  console.log(`
285019
- ${brand("ablo")} ${import_picocolors20.default.dim("pull prisma")} ${import_picocolors20.default.dim(args.schema)}
285136
+ ${brand("ablo")} ${import_picocolors21.default.dim("pull prisma")} ${import_picocolors21.default.dim(args.schema)}
285020
285137
  `);
285021
285138
  let result;
285022
285139
  try {
285023
285140
  const src = (0, import_fs10.readFileSync)(args.schema, "utf8");
285024
285141
  result = buildSchemaSourceFromPrisma({ src, importPath: args.importPath });
285025
285142
  } catch (err) {
285026
- console.error(import_picocolors20.default.red(` Couldn't parse the schema: ${err instanceof Error ? err.message : String(err)}`));
285143
+ console.error(import_picocolors21.default.red(` Couldn't parse the schema: ${err instanceof Error ? err.message : String(err)}`));
285027
285144
  process.exit(1);
285028
285145
  }
285029
285146
  if (result.models.length === 0) {
285030
285147
  console.error(
285031
- import_picocolors20.default.yellow(` No adoptable models found`) + import_picocolors20.default.dim(` (a model needs an ${import_picocolors20.default.bold("id")} + ${import_picocolors20.default.bold("organizationId")} / ${import_picocolors20.default.bold("organization_id")}).`)
285148
+ import_picocolors21.default.yellow(` No adoptable models found`) + import_picocolors21.default.dim(` (a model needs an ${import_picocolors21.default.bold("id")} + ${import_picocolors21.default.bold("organizationId")} / ${import_picocolors21.default.bold("organization_id")}).`)
285032
285149
  );
285033
285150
  process.exit(1);
285034
285151
  }
285035
285152
  (0, import_fs10.writeFileSync)(args.out, result.source);
285036
- console.log(` ${import_picocolors20.default.green("\u2713")} wrote ${import_picocolors20.default.bold(args.out)} ${import_picocolors20.default.dim(`(${result.models.length} models)`)}`);
285037
- console.log(` ${import_picocolors20.default.dim(`models: ${result.models.join(", ")}`)}`);
285153
+ console.log(` ${import_picocolors21.default.green("\u2713")} wrote ${import_picocolors21.default.bold(args.out)} ${import_picocolors21.default.dim(`(${result.models.length} models)`)}`);
285154
+ console.log(` ${import_picocolors21.default.dim(`models: ${result.models.join(", ")}`)}`);
285038
285155
  if (result.skipped.length > 0) {
285039
- console.log(` ${import_picocolors20.default.dim(`${result.skipped.length} model(s) skipped:`)}`);
285040
- for (const s of result.skipped) console.log(` ${import_picocolors20.default.dim(`- ${s.name}: ${s.reason}`)}`);
285156
+ console.log(` ${import_picocolors21.default.dim(`${result.skipped.length} model(s) skipped:`)}`);
285157
+ for (const s of result.skipped) console.log(` ${import_picocolors21.default.dim(`- ${s.name}: ${s.reason}`)}`);
285041
285158
  }
285042
285159
  console.log(
285043
285160
  `
285044
- ${import_picocolors20.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors20.default.bold("ablo check")}.
285161
+ ${import_picocolors21.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors21.default.bold("ablo check")}.
285045
285162
  `
285046
285163
  );
285047
285164
  }
285048
285165
 
285049
285166
  // src/cli/drizzlePull.ts
285050
285167
  init_cjs_shims();
285051
- var import_picocolors21 = __toESM(require_picocolors(), 1);
285168
+ var import_picocolors22 = __toESM(require_picocolors(), 1);
285052
285169
  init_errors();
285053
285170
  var import_fs11 = require("fs");
285054
285171
  var import_path6 = require("path");
@@ -285187,27 +285304,27 @@ async function drizzlePull(argv) {
285187
285304
  try {
285188
285305
  args = parseDrizzlePullArgs(argv);
285189
285306
  } catch (err) {
285190
- console.error(import_picocolors21.default.red(` ${err instanceof Error ? err.message : String(err)}`));
285307
+ console.error(import_picocolors22.default.red(` ${err instanceof Error ? err.message : String(err)}`));
285191
285308
  process.exit(1);
285192
285309
  }
285193
285310
  if (!args.schema) {
285194
285311
  console.error(
285195
- import_picocolors21.default.red(` No Drizzle schema given.`) + import_picocolors21.default.dim(` Pass the module: ${import_picocolors21.default.bold("ablo pull drizzle src/db/schema.ts")}.`)
285312
+ import_picocolors22.default.red(` No Drizzle schema given.`) + import_picocolors22.default.dim(` Pass the module: ${import_picocolors22.default.bold("ablo pull drizzle src/db/schema.ts")}.`)
285196
285313
  );
285197
285314
  process.exit(1);
285198
285315
  }
285199
285316
  if (!(0, import_fs11.existsSync)(args.schema)) {
285200
- console.error(import_picocolors21.default.red(` No file at ${import_picocolors21.default.bold(args.schema)}.`));
285317
+ console.error(import_picocolors22.default.red(` No file at ${import_picocolors22.default.bold(args.schema)}.`));
285201
285318
  process.exit(1);
285202
285319
  }
285203
285320
  if ((0, import_fs11.existsSync)(args.out) && !args.force) {
285204
285321
  console.error(
285205
- import_picocolors21.default.red(` ${args.out} already exists.`) + import_picocolors21.default.dim(` Re-run with ${import_picocolors21.default.bold("--force")} to overwrite.`)
285322
+ import_picocolors22.default.red(` ${args.out} already exists.`) + import_picocolors22.default.dim(` Re-run with ${import_picocolors22.default.bold("--force")} to overwrite.`)
285206
285323
  );
285207
285324
  process.exit(1);
285208
285325
  }
285209
285326
  console.log(`
285210
- ${brand("ablo")} ${import_picocolors21.default.dim("pull drizzle")} ${import_picocolors21.default.dim(args.schema)}
285327
+ ${brand("ablo")} ${import_picocolors22.default.dim("pull drizzle")} ${import_picocolors22.default.dim(args.schema)}
285211
285328
  `);
285212
285329
  let result;
285213
285330
  try {
@@ -285215,26 +285332,26 @@ async function drizzlePull(argv) {
285215
285332
  result = await buildSchemaSourceFromDrizzle({ mod, importPath: args.importPath });
285216
285333
  } catch (err) {
285217
285334
  const msg = err instanceof Error ? err.message : String(err);
285218
- const hint = msg.includes("Cannot find package 'drizzle-orm'") ? import_picocolors21.default.dim(` (install ${import_picocolors21.default.bold("drizzle-orm")} in this project)`) : "";
285219
- console.error(import_picocolors21.default.red(` Couldn't load the schema: ${msg}`) + hint);
285335
+ const hint = msg.includes("Cannot find package 'drizzle-orm'") ? import_picocolors22.default.dim(` (install ${import_picocolors22.default.bold("drizzle-orm")} in this project)`) : "";
285336
+ console.error(import_picocolors22.default.red(` Couldn't load the schema: ${msg}`) + hint);
285220
285337
  process.exit(1);
285221
285338
  }
285222
285339
  if (result.models.length === 0) {
285223
285340
  console.error(
285224
- import_picocolors21.default.yellow(` No adoptable tables found`) + import_picocolors21.default.dim(` (a table needs an ${import_picocolors21.default.bold("id")} + ${import_picocolors21.default.bold("organization_id")} column).`)
285341
+ import_picocolors22.default.yellow(` No adoptable tables found`) + import_picocolors22.default.dim(` (a table needs an ${import_picocolors22.default.bold("id")} + ${import_picocolors22.default.bold("organization_id")} column).`)
285225
285342
  );
285226
285343
  process.exit(1);
285227
285344
  }
285228
285345
  (0, import_fs11.writeFileSync)(args.out, result.source);
285229
- console.log(` ${import_picocolors21.default.green("\u2713")} wrote ${import_picocolors21.default.bold(args.out)} ${import_picocolors21.default.dim(`(${result.models.length} models)`)}`);
285230
- console.log(` ${import_picocolors21.default.dim(`models: ${result.models.join(", ")}`)}`);
285346
+ console.log(` ${import_picocolors22.default.green("\u2713")} wrote ${import_picocolors22.default.bold(args.out)} ${import_picocolors22.default.dim(`(${result.models.length} models)`)}`);
285347
+ console.log(` ${import_picocolors22.default.dim(`models: ${result.models.join(", ")}`)}`);
285231
285348
  if (result.skipped.length > 0) {
285232
- console.log(` ${import_picocolors21.default.dim(`${result.skipped.length} table(s) skipped:`)}`);
285233
- for (const s of result.skipped) console.log(` ${import_picocolors21.default.dim(`- ${s.name}: ${s.reason}`)}`);
285349
+ console.log(` ${import_picocolors22.default.dim(`${result.skipped.length} table(s) skipped:`)}`);
285350
+ for (const s of result.skipped) console.log(` ${import_picocolors22.default.dim(`- ${s.name}: ${s.reason}`)}`);
285234
285351
  }
285235
285352
  console.log(
285236
285353
  `
285237
- ${import_picocolors21.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors21.default.bold("ablo check")}.
285354
+ ${import_picocolors22.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors22.default.bold("ablo check")}.
285238
285355
  `
285239
285356
  );
285240
285357
  }
@@ -285244,7 +285361,7 @@ init_theme();
285244
285361
 
285245
285362
  // src/cli/renderError.ts
285246
285363
  init_cjs_shims();
285247
- var import_picocolors22 = __toESM(require_picocolors(), 1);
285364
+ var import_picocolors23 = __toESM(require_picocolors(), 1);
285248
285365
  init_errors();
285249
285366
  init_theme();
285250
285367
  var RECOVERY_HINT = {
@@ -285266,15 +285383,15 @@ function isStringArray(v2) {
285266
285383
  function renderKnownDetails(details, line) {
285267
285384
  if (!details) return;
285268
285385
  const { retryAfterSeconds, missingIds, requiredCapability, unexecutable, errors } = details;
285269
- if (typeof retryAfterSeconds === "number") line(` ${import_picocolors22.default.dim("retry")} after ${retryAfterSeconds}s`);
285386
+ if (typeof retryAfterSeconds === "number") line(` ${import_picocolors23.default.dim("retry")} after ${retryAfterSeconds}s`);
285270
285387
  if (isStringArray(missingIds) && missingIds.length > 0) {
285271
285388
  const shown = missingIds.slice(0, 5).join(", ");
285272
285389
  const more = missingIds.length > 5 ? ` (+${missingIds.length - 5} more)` : "";
285273
- line(` ${import_picocolors22.default.dim("missing")} ${shown}${more}`);
285390
+ line(` ${import_picocolors23.default.dim("missing")} ${shown}${more}`);
285274
285391
  }
285275
- if (typeof requiredCapability === "string") line(` ${import_picocolors22.default.dim("needs")} ${requiredCapability}`);
285392
+ if (typeof requiredCapability === "string") line(` ${import_picocolors23.default.dim("needs")} ${requiredCapability}`);
285276
285393
  if (Array.isArray(unexecutable) && unexecutable.length > 0) {
285277
- line(` ${import_picocolors22.default.dim("blocked")} ${unexecutable.length} change(s) can't be applied \u2014 see \`unexecutable\` (--verbose)`);
285394
+ line(` ${import_picocolors23.default.dim("blocked")} ${unexecutable.length} change(s) can't be applied \u2014 see \`unexecutable\` (--verbose)`);
285278
285395
  }
285279
285396
  if (Array.isArray(errors)) {
285280
285397
  for (const e2 of errors.slice(0, 8)) {
@@ -285282,7 +285399,7 @@ function renderKnownDetails(details, line) {
285282
285399
  const rec = e2;
285283
285400
  const where = typeof rec.param === "string" ? `${rec.param}: ` : "";
285284
285401
  const msg = typeof rec.message === "string" ? rec.message : "";
285285
- if (msg) line(` ${import_picocolors22.default.dim("\xB7")} ${where}${msg}`);
285402
+ if (msg) line(` ${import_picocolors23.default.dim("\xB7")} ${where}${msg}`);
285286
285403
  }
285287
285404
  }
285288
285405
  }
@@ -285293,22 +285410,22 @@ function renderCliError(err, opts = {}) {
285293
285410
  });
285294
285411
  const verbose = opts.verbose ?? (process.argv.includes("--verbose") || process.env.ABLO_VERBOSE === "1");
285295
285412
  if (err instanceof AbloError) {
285296
- const codeTag = err.code ? ` ${import_picocolors22.default.dim(`[${err.code}]`)}` : "";
285413
+ const codeTag = err.code ? ` ${import_picocolors23.default.dim(`[${err.code}]`)}` : "";
285297
285414
  line("");
285298
- line(` ${brand("ablo")} ${import_picocolors22.default.red("\u2717")} ${import_picocolors22.default.bold(titleForType(err.type))}${codeTag}`);
285415
+ line(` ${brand("ablo")} ${import_picocolors23.default.red("\u2717")} ${import_picocolors23.default.bold(titleForType(err.type))}${codeTag}`);
285299
285416
  line("");
285300
285417
  line(` ${err.message}`);
285301
- if (err.param) line(` ${import_picocolors22.default.dim("field")} ${err.param}`);
285418
+ if (err.param) line(` ${import_picocolors23.default.dim("field")} ${err.param}`);
285302
285419
  renderKnownDetails(err.details, line);
285303
285420
  const hint = err.code ? RECOVERY_HINT[classifyRecovery(err.code)] : void 0;
285304
- if (hint) line(` ${import_picocolors22.default.dim(hint)}`);
285305
- if (err.docUrl) line(` ${import_picocolors22.default.dim("docs")} ${err.docUrl}`);
285306
- if (err.requestId) line(` ${import_picocolors22.default.dim("ref")} ${err.requestId}`);
285421
+ if (hint) line(` ${import_picocolors23.default.dim(hint)}`);
285422
+ if (err.docUrl) line(` ${import_picocolors23.default.dim("docs")} ${err.docUrl}`);
285423
+ if (err.requestId) line(` ${import_picocolors23.default.dim("ref")} ${err.requestId}`);
285307
285424
  if (verbose) {
285308
285425
  if (err.details && Object.keys(err.details).length > 0) {
285309
- line(` ${import_picocolors22.default.dim("details")} ${JSON.stringify(err.details)}`);
285426
+ line(` ${import_picocolors23.default.dim("details")} ${JSON.stringify(err.details)}`);
285310
285427
  }
285311
- if (err.stack) line(import_picocolors22.default.dim(err.stack));
285428
+ if (err.stack) line(import_picocolors23.default.dim(err.stack));
285312
285429
  }
285313
285430
  line("");
285314
285431
  process.exitCode = 1;
@@ -285316,16 +285433,16 @@ function renderCliError(err, opts = {}) {
285316
285433
  }
285317
285434
  const message = err instanceof Error ? err.message : String(err);
285318
285435
  line("");
285319
- line(` ${brand("ablo")} ${import_picocolors22.default.red("\u2717")} ${message}`);
285320
- if (verbose && err instanceof Error && err.stack) line(import_picocolors22.default.dim(err.stack));
285321
- else line(` ${import_picocolors22.default.dim("Run with --verbose for the full error.")}`);
285436
+ line(` ${brand("ablo")} ${import_picocolors23.default.red("\u2717")} ${message}`);
285437
+ if (verbose && err instanceof Error && err.stack) line(import_picocolors23.default.dim(err.stack));
285438
+ else line(` ${import_picocolors23.default.dim("Run with --verbose for the full error.")}`);
285322
285439
  line("");
285323
285440
  process.exitCode = 1;
285324
285441
  }
285325
285442
 
285326
285443
  // src/cli/index.ts
285327
285444
  var LOGO = `
285328
- ${brand("ablo")} ${import_picocolors23.default.dim("sync engine")}
285445
+ ${brand("ablo")} ${import_picocolors24.default.dim("sync engine")}
285329
285446
  `;
285330
285447
  var SUBCOMMAND_USAGE = {
285331
285448
  connect: CONNECT_USAGE,
@@ -285360,7 +285477,7 @@ async function main() {
285360
285477
  const devArgs = process.argv.slice(3);
285361
285478
  const oneShot = devArgs.includes("--no-watch");
285362
285479
  console.log(
285363
- import_picocolors23.default.dim(
285480
+ import_picocolors24.default.dim(
285364
285481
  oneShot ? " `ablo dev --no-watch` is `ablo push` (push once, no watcher) \u2014 running that." : " `ablo dev` is now `ablo push --watch` \u2014 running that."
285365
285482
  )
285366
285483
  );
@@ -285389,14 +285506,14 @@ async function main() {
285389
285506
  const guard = guardActiveProjectKey();
285390
285507
  if (!guard.ok && guard.available.length > 0 && !rest.includes("--url")) {
285391
285508
  console.error(
285392
- ` ${import_picocolors23.default.yellow("\u26A0")} active project ${import_picocolors23.default.bold(guard.activeProfile)} has no stored key ${import_picocolors23.default.dim(
285509
+ ` ${import_picocolors24.default.yellow("\u26A0")} active project ${import_picocolors24.default.bold(guard.activeProfile)} has no stored key ${import_picocolors24.default.dim(
285393
285510
  `(you have keys for: ${guard.available.join(", ")})`
285394
285511
  )}`
285395
285512
  );
285396
285513
  const loginCmd = guard.activeProfile === "default" ? "ablo login" : `ablo login --project ${guard.activeProfile}`;
285397
285514
  console.error(
285398
- import_picocolors23.default.dim(
285399
- ` Mint one with ${import_picocolors23.default.bold(loginCmd)}, or switch with ${import_picocolors23.default.bold("ablo projects use <slug>")}.`
285515
+ import_picocolors24.default.dim(
285516
+ ` Mint one with ${import_picocolors24.default.bold(loginCmd)}, or switch with ${import_picocolors24.default.bold("ablo projects use <slug>")}.`
285400
285517
  )
285401
285518
  );
285402
285519
  process.exitCode = 1;
@@ -285414,13 +285531,13 @@ async function main() {
285414
285531
  await generate(process.argv.slice(3));
285415
285532
  } else if (command === "schema") {
285416
285533
  console.error(
285417
- ` ${import_picocolors23.default.red("\u2717")} \`ablo schema push\` was renamed to \`${brand("ablo push")}\`.`
285534
+ ` ${import_picocolors24.default.red("\u2717")} \`ablo schema push\` was renamed to \`${brand("ablo push")}\`.`
285418
285535
  );
285419
285536
  console.error(` Run \`ablo push${process.argv.slice(4).join(" ") ? " " + process.argv.slice(4).join(" ") : ""}\` instead.`);
285420
285537
  process.exitCode = 1;
285421
285538
  } else {
285422
285539
  console.log(LOGO);
285423
- console.log(` ${import_picocolors23.default.bold("Usage:")}`);
285540
+ console.log(` ${import_picocolors24.default.bold("Usage:")}`);
285424
285541
  console.log(` npx ablo init Scaffold ablo/ directory + starter schema`);
285425
285542
  console.log(` npx ablo init --yes [--framework nextjs] Non-interactive (agents/CI): no prompts, flag-driven`);
285426
285543
  console.log(` [--auth apikey] [--storage replication|endpoint] [--project <slug>] [--no-project]`);
@@ -285457,10 +285574,10 @@ async function main() {
285457
285574
  console.log(` npx ablo generate Emit TypeScript types from your schema`);
285458
285575
  console.log(` npx ablo generate --out path.ts Write generated types to a path`);
285459
285576
  console.log();
285460
- console.log(` ${import_picocolors23.default.bold("Schema workflow:")}`);
285577
+ console.log(` ${import_picocolors24.default.bold("Schema workflow:")}`);
285461
285578
  console.log(` The server holds its own copy of your schema \u2014 edit ${brand("ablo/schema.ts")}, then`);
285462
285579
  console.log(` run ${brand("ablo push")} (or keep ${brand("ablo dev")} running) before the server will accept`);
285463
- console.log(` writes to new or changed models. Skip it and writes fail with ${import_picocolors23.default.yellow("server_execute_unknown_model")}.`);
285580
+ console.log(` writes to new or changed models. Skip it and writes fail with ${import_picocolors24.default.yellow("server_execute_unknown_model")}.`);
285464
285581
  console.log();
285465
285582
  }
285466
285583
  }
@@ -285511,7 +285628,7 @@ async function ensureInitProject(opts) {
285511
285628
  const ensured = await ensureProject(slug);
285512
285629
  if (ensured) {
285513
285630
  console.log(
285514
- ` ${import_picocolors23.default.green("\u2713")} ${ensured.created ? "Created" : "Using"} project ${import_picocolors23.default.bold(ensured.slug)} ${import_picocolors23.default.dim(`(${ensured.id})`)} \u2014 keys you mint for it are isolated from the org's other apps.`
285631
+ ` ${import_picocolors24.default.green("\u2713")} ${ensured.created ? "Created" : "Using"} project ${import_picocolors24.default.bold(ensured.slug)} ${import_picocolors24.default.dim(`(${ensured.id})`)} \u2014 keys you mint for it are isolated from the org's other apps.`
285515
285632
  );
285516
285633
  }
285517
285634
  }
@@ -285553,7 +285670,7 @@ async function chooseBool(flagValue, fallback, interactive, prompt) {
285553
285670
  async function init(args = []) {
285554
285671
  const opts = parseInitArgs(args);
285555
285672
  const interactive = Boolean(process.stdin.isTTY) && !opts.yes && !process.env.CI;
285556
- Ie(`${brand("ablo")} ${import_picocolors23.default.dim("sync engine")}`);
285673
+ Ie(`${brand("ablo")} ${import_picocolors24.default.dim("sync engine")}`);
285557
285674
  if (!(0, import_fs12.existsSync)("package.json")) {
285558
285675
  xe("No package.json found. Run this from your project root.");
285559
285676
  process.exit(1);
@@ -285631,7 +285748,7 @@ async function init(args = []) {
285631
285748
  if (pullExisting) {
285632
285749
  const dbUrl = process.env.DATABASE_URL ?? process.env.ABLO_DATABASE_URL;
285633
285750
  if (!dbUrl) {
285634
- schemaNote = import_picocolors23.default.dim(" (no DATABASE_URL \u2014 wrote starter; run `ablo pull` later)");
285751
+ schemaNote = import_picocolors24.default.dim(" (no DATABASE_URL \u2014 wrote starter; run `ablo pull` later)");
285635
285752
  } else {
285636
285753
  try {
285637
285754
  const pulled = await buildSchemaSourceFromDb({
@@ -285641,12 +285758,12 @@ async function init(args = []) {
285641
285758
  });
285642
285759
  if (pulled.models.length > 0) {
285643
285760
  schemaSource = pulled.source;
285644
- schemaNote = import_picocolors23.default.dim(` (pulled ${pulled.models.length} models)`);
285761
+ schemaNote = import_picocolors24.default.dim(` (pulled ${pulled.models.length} models)`);
285645
285762
  } else {
285646
- schemaNote = import_picocolors23.default.dim(" (no adoptable tables \u2014 wrote starter)");
285763
+ schemaNote = import_picocolors24.default.dim(" (no adoptable tables \u2014 wrote starter)");
285647
285764
  }
285648
285765
  } catch {
285649
- schemaNote = import_picocolors23.default.dim(" (pull failed \u2014 wrote starter)");
285766
+ schemaNote = import_picocolors24.default.dim(" (pull failed \u2014 wrote starter)");
285650
285767
  }
285651
285768
  }
285652
285769
  }
@@ -285672,14 +285789,14 @@ async function init(args = []) {
285672
285789
  const existing = (0, import_fs12.readFileSync)(envFile, "utf-8");
285673
285790
  if (!existing.includes("ABLO_")) {
285674
285791
  (0, import_fs12.writeFileSync)(envFile, existing + "\n" + envBody);
285675
- created.push(`${envFile} ${import_picocolors23.default.dim("(appended)")}`);
285792
+ created.push(`${envFile} ${import_picocolors24.default.dim("(appended)")}`);
285676
285793
  } else {
285677
- created.push(`${envFile} ${import_picocolors23.default.dim("(already configured)")}`);
285794
+ created.push(`${envFile} ${import_picocolors24.default.dim("(already configured)")}`);
285678
285795
  }
285679
285796
  }
285680
285797
  if (wireRealKey && resolvedKey) {
285681
285798
  wireEnvLocal(resolvedKey);
285682
- created.push(`.env.local ${import_picocolors23.default.dim("(ABLO_API_KEY set from your login)")}`);
285799
+ created.push(`.env.local ${import_picocolors24.default.dim("(ABLO_API_KEY set from your login)")}`);
285683
285800
  }
285684
285801
  if (agent) {
285685
285802
  (0, import_fs12.writeFileSync)((0, import_path7.join)(abloDir, "agent.ts"), generateAgent());
@@ -285694,17 +285811,17 @@ async function init(args = []) {
285694
285811
  }
285695
285812
  const providersPath = (0, import_path7.join)(layout.appBase, "providers.tsx");
285696
285813
  (0, import_fs12.writeFileSync)(providersPath, generateProviders());
285697
- created.push(`${providersPath} ${import_picocolors23.default.dim(`(wrap ${(0, import_path7.join)(layout.appBase, "layout.tsx")} in <Providers>)`)}`);
285814
+ created.push(`${providersPath} ${import_picocolors24.default.dim(`(wrap ${(0, import_path7.join)(layout.appBase, "layout.tsx")} in <Providers>)`)}`);
285698
285815
  const sessionDir = (0, import_path7.join)(layout.appBase, "api", "ablo-session");
285699
285816
  (0, import_fs12.mkdirSync)(sessionDir, { recursive: true });
285700
285817
  (0, import_fs12.writeFileSync)((0, import_path7.join)(sessionDir, "route.ts"), generateSessionRoute());
285701
- created.push(`${(0, import_path7.join)(sessionDir, "route.ts")} ${import_picocolors23.default.dim("(wire your auth)")}`);
285818
+ created.push(`${(0, import_path7.join)(sessionDir, "route.ts")} ${import_picocolors24.default.dim("(wire your auth)")}`);
285702
285819
  }
285703
285820
  if (framework !== "vanilla") {
285704
285821
  (0, import_fs12.writeFileSync)((0, import_path7.join)(abloDir, "TaskList.tsx"), generateComponent());
285705
285822
  created.push(`${abloDir}/TaskList.tsx`);
285706
285823
  }
285707
- Me(created.map((f) => `${import_picocolors23.default.green("\u2713")} ${f}`).join("\n"), "Created");
285824
+ Me(created.map((f) => `${import_picocolors24.default.green("\u2713")} ${f}`).join("\n"), "Created");
285708
285825
  const pm = detectPackageManager();
285709
285826
  if (opts.install) {
285710
285827
  const s = Y2();
@@ -285713,47 +285830,47 @@ async function init(args = []) {
285713
285830
  (0, import_child_process3.execSync)(`${pm} add @abloatai/ablo`, { stdio: "ignore" });
285714
285831
  s.stop("Installed @abloatai/ablo");
285715
285832
  } catch {
285716
- s.stop(`${import_picocolors23.default.yellow("!")} Couldn't auto-install \u2014 run ${import_picocolors23.default.bold(`${pm} install @abloatai/ablo`)}`);
285833
+ s.stop(`${import_picocolors24.default.yellow("!")} Couldn't auto-install \u2014 run ${import_picocolors24.default.bold(`${pm} install @abloatai/ablo`)}`);
285717
285834
  }
285718
285835
  }
285719
285836
  const steps = [
285720
- `Get a ${import_picocolors23.default.bold("sk_test_")} key at ${import_picocolors23.default.cyan("https://abloatai.com")}`,
285721
- `Run ${import_picocolors23.default.bold("npx ablo login")} (or add ${import_picocolors23.default.bold("ABLO_API_KEY")} to ${import_picocolors23.default.bold(envFile)})`,
285722
- `Set ${import_picocolors23.default.bold("DATABASE_URL")} in ${import_picocolors23.default.bold(envFile)} \u2014 your Postgres is the system of record; rows live there, never with Ablo`,
285723
- `Run ${import_picocolors23.default.bold("npx ablo dev")} \u2014 pushes your schema definition and watches for changes`,
285837
+ `Get a ${import_picocolors24.default.bold("sk_test_")} key at ${import_picocolors24.default.cyan("https://abloatai.com")}`,
285838
+ `Run ${import_picocolors24.default.bold("npx ablo login")} (or add ${import_picocolors24.default.bold("ABLO_API_KEY")} to ${import_picocolors24.default.bold(envFile)})`,
285839
+ `Set ${import_picocolors24.default.bold("DATABASE_URL")} in ${import_picocolors24.default.bold(envFile)} \u2014 your Postgres is the system of record; rows live there, never with Ablo`,
285840
+ `Run ${import_picocolors24.default.bold("npx ablo dev")} \u2014 pushes your schema definition and watches for changes`,
285724
285841
  ...storage === "replication" ? [
285725
- `Connect your database \u2014 ${import_picocolors23.default.bold("npx ablo connect")} prints the one-time logical-replication setup SQL to run on your Postgres`,
285726
- `Verify it \u2014 ${import_picocolors23.default.bold("npx ablo connect check")} walks wal_level, the publication, the role, and replica identity, with the exact fix for anything missing`,
285727
- `Register it \u2014 ${import_picocolors23.default.bold("npx ablo connect register")} tells Ablo to start replicating; your app keeps writing through your own backend while Ablo tails the WAL`
285842
+ `Connect your database \u2014 ${import_picocolors24.default.bold("npx ablo connect")} prints the one-time logical-replication setup SQL to run on your Postgres`,
285843
+ `Verify it \u2014 ${import_picocolors24.default.bold("npx ablo connect check")} walks wal_level, the publication, the role, and replica identity, with the exact fix for anything missing`,
285844
+ `Register it \u2014 ${import_picocolors24.default.bold("npx ablo connect register")} tells Ablo to start replicating; your app keeps writing through your own backend while Ablo tails the WAL`
285728
285845
  ] : [
285729
- `Provision your DB: ${import_picocolors23.default.bold("npx ablo migrate")} (creates your Ablo-model tables + the adapter tables; keep your own migrations for everything else), then mount ${import_picocolors23.default.bold(`${abloDir}/data-source.ts`)} at ${import_picocolors23.default.bold("/api/ablo/source")}`
285846
+ `Provision your DB: ${import_picocolors24.default.bold("npx ablo migrate")} (creates your Ablo-model tables + the adapter tables; keep your own migrations for everything else), then mount ${import_picocolors24.default.bold(`${abloDir}/data-source.ts`)} at ${import_picocolors24.default.bold("/api/ablo/source")}`
285730
285847
  ],
285731
285848
  ...framework === "nextjs" ? [
285732
- `Wrap ${import_picocolors23.default.bold((0, import_path7.join)(layout.appBase, "layout.tsx"))} in ${import_picocolors23.default.bold("<Providers>")} (${(0, import_path7.join)(layout.appBase, "providers.tsx")}) and add your auth to ${import_picocolors23.default.bold((0, import_path7.join)(layout.appBase, "api", "ablo-session", "route.ts"))}`
285849
+ `Wrap ${import_picocolors24.default.bold((0, import_path7.join)(layout.appBase, "layout.tsx"))} in ${import_picocolors24.default.bold("<Providers>")} (${(0, import_path7.join)(layout.appBase, "providers.tsx")}) and add your auth to ${import_picocolors24.default.bold((0, import_path7.join)(layout.appBase, "api", "ablo-session", "route.ts"))}`
285733
285850
  ] : [],
285734
- `Run ${import_picocolors23.default.bold(`${pm} run dev`)} and open two browser tabs \u2014 changes sync in real-time`,
285851
+ `Run ${import_picocolors24.default.bold(`${pm} run dev`)} and open two browser tabs \u2014 changes sync in real-time`,
285735
285852
  ...agent ? [
285736
- `Run ${import_picocolors23.default.bold(`npx tsx ${abloDir}/agent.ts`)} \u2014 an AI teammate edits the same tasks`,
285737
- `Run ${import_picocolors23.default.bold("npx ablo logs")} to watch human + agent commits stream by`
285853
+ `Run ${import_picocolors24.default.bold(`npx tsx ${abloDir}/agent.ts`)} \u2014 an AI teammate edits the same tasks`,
285854
+ `Run ${import_picocolors24.default.bold("npx ablo logs")} to watch human + agent commits stream by`
285738
285855
  ] : []
285739
285856
  ];
285740
285857
  Me(steps.map((s, i) => `${i + 1}. ${s}`).join("\n"), "Next steps");
285741
285858
  const existingKey = resolveApiKey("sandbox");
285742
285859
  if (existingKey) {
285743
285860
  await ensureInitProject(opts);
285744
- Se(`Already authorized ${import_picocolors23.default.dim(`(${existingKey.slice(0, 11)}\u2026)`)} \u2014 run ${import_picocolors23.default.bold("npx ablo push")} next. ${import_picocolors23.default.dim("Docs:")} https://abloatai.com/docs`);
285861
+ Se(`Already authorized ${import_picocolors24.default.dim(`(${existingKey.slice(0, 11)}\u2026)`)} \u2014 run ${import_picocolors24.default.bold("npx ablo push")} next. ${import_picocolors24.default.dim("Docs:")} https://abloatai.com/docs`);
285745
285862
  return;
285746
285863
  }
285747
285864
  if (interactive && opts.login) {
285748
285865
  const loginNow = await ye({ message: "Log in now? (opens your browser)", initialValue: true });
285749
285866
  if (!pD(loginNow) && loginNow) {
285750
- Se(`${import_picocolors23.default.dim("Docs:")} https://abloatai.com/docs`);
285867
+ Se(`${import_picocolors24.default.dim("Docs:")} https://abloatai.com/docs`);
285751
285868
  await login();
285752
285869
  await ensureInitProject(opts);
285753
285870
  return;
285754
285871
  }
285755
285872
  }
285756
- Se(`Run ${import_picocolors23.default.bold("npx ablo login")} when ready. ${import_picocolors23.default.dim("Docs:")} https://abloatai.com/docs`);
285873
+ Se(`Run ${import_picocolors24.default.bold("npx ablo login")} when ready. ${import_picocolors24.default.dim("Docs:")} https://abloatai.com/docs`);
285757
285874
  }
285758
285875
  function generateSchema() {
285759
285876
  return `import { defineSchema, model, relation, z } from '@abloatai/ablo/schema';