@abloatai/cli 0.42.0 → 0.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.cjs +371 -332
  2. package/package.json +3 -3
package/dist/cli.cjs CHANGED
@@ -3313,43 +3313,16 @@ function getKeyEntry(mode) {
3313
3313
  if (!cfg) return void 0;
3314
3314
  return cfg.profiles[activeProfileName(cfg)]?.[mode];
3315
3315
  }
3316
+ function getManagementKeyEntry() {
3317
+ const cfg = readConfig();
3318
+ if (!cfg) return void 0;
3319
+ return cfg.profiles[activeProfileName(cfg)]?.management;
3320
+ }
3316
3321
  function modeFromKey(key) {
3317
3322
  if (/^(sk|rk)_test_/.test(key)) return "sandbox";
3318
3323
  if (/^(sk|rk)_live_/.test(key)) return "production";
3319
3324
  return void 0;
3320
3325
  }
3321
- function prefix(key) {
3322
- return key ? key.slice(0, 12) : null;
3323
- }
3324
- function describeEffectiveKey(activeMode, envKey, storedEntry) {
3325
- const effectiveKey = envKey ?? storedEntry?.apiKey;
3326
- const keySource = envKey ? "env" : storedEntry ? "stored" : null;
3327
- const keyMode = effectiveKey ? modeFromKey(effectiveKey) ?? null : null;
3328
- const keyMatchesActiveMode = keyMode ? keyMode === activeMode : null;
3329
- const keyMatchesStoredActiveKey = envKey && storedEntry?.apiKey ? envKey === storedEntry.apiKey : null;
3330
- let keyMismatch = null;
3331
- if (keyMode && keyMode !== activeMode) {
3332
- const sourceLabel = envKey ? "ABLO_API_KEY" : "stored active key";
3333
- keyMismatch = {
3334
- code: "key_mode_mismatch",
3335
- message: `${sourceLabel} is a ${keyMode} key but the CLI mode is ${activeMode}. Requests use ${sourceLabel} (${prefix(effectiveKey)}...), not the active CLI mode.`
3336
- };
3337
- } else if (envKey && storedEntry?.apiKey && envKey !== storedEntry.apiKey) {
3338
- keyMismatch = {
3339
- code: "env_key_overrides_stored",
3340
- message: `ABLO_API_KEY (${prefix(envKey)}...) overrides the stored ${activeMode} key (${prefix(storedEntry.apiKey)}...).`
3341
- };
3342
- }
3343
- return {
3344
- keyPrefix: prefix(effectiveKey),
3345
- keySource,
3346
- keyMode,
3347
- storedKeyPrefix: prefix(storedEntry?.apiKey),
3348
- keyMatchesActiveMode,
3349
- keyMatchesStoredActiveKey,
3350
- keyMismatch
3351
- };
3352
- }
3353
3326
  function normalizeMode(value) {
3354
3327
  return normalizeStoredMode(value);
3355
3328
  }
@@ -3363,13 +3336,13 @@ function clearCredential() {
3363
3336
  }
3364
3337
  return removed;
3365
3338
  }
3366
- function resolveApiKey(modeOverride) {
3339
+ function resolveMutationApiKey(modeOverride) {
3367
3340
  return resolveKey({ purpose: "data", mode: modeOverride }).key;
3368
3341
  }
3369
3342
  function ambientEnvKeyNote(cwd) {
3370
3343
  const ambient = readProjectApiKey(cwd);
3371
3344
  if (!ambient || ambient.source === "env") return null;
3372
- return `Note: ${ambient.source} in this directory holds an ABLO_API_KEY, which this command does not load \u2014 it reads only the process environment and your stored login, so a file cannot silently choose the plane. Export the variable (or prefix the command with it) to use that key.`;
3345
+ return `Note: ${ambient.source} in this directory holds an ABLO_API_KEY, which this command does not load \u2014 it reads only the process environment and your stored login, so a file cannot silently choose a branch. Export the variable, or pass \`--env-file ` + ambient.source + "` to a connect command, to choose it explicitly.";
3373
3346
  }
3374
3347
  function resolveManagementKey() {
3375
3348
  if (process.env.ABLO_MANAGEMENT_KEY) return process.env.ABLO_MANAGEMENT_KEY;
@@ -3398,7 +3371,7 @@ function resolveOrgManagementKey() {
3398
3371
  return void 0;
3399
3372
  }
3400
3373
  function guardActiveProjectKey() {
3401
- const { key, source } = resolveEffectiveApiKey();
3374
+ const { key, source } = resolveRuntimeApiKey();
3402
3375
  if (key != null && source != null && source !== "stored") {
3403
3376
  return { ok: true, activeProfile: DEFAULT_PROFILE, available: [] };
3404
3377
  }
@@ -3431,16 +3404,9 @@ function resolveKey(policy) {
3431
3404
  }
3432
3405
  return { key: void 0, source: null };
3433
3406
  }
3434
- function resolveEffectiveApiKey(modeOverride, cwd) {
3407
+ function resolveRuntimeApiKey(modeOverride, cwd) {
3435
3408
  return resolveKey({ purpose: "data", mode: modeOverride, scanEnvFiles: true, cwd });
3436
3409
  }
3437
- function resolvePushPlan() {
3438
- const { key, source } = resolveEffectiveApiKey();
3439
- if (key != null && source != null && source !== "stored") {
3440
- return { flow: modeFromKey(key) ?? getMode(), apiKey: key, source };
3441
- }
3442
- return { flow: getMode(), apiKey: key, source };
3443
- }
3444
3410
  var import_os2, import_path2, import_fs3, DEFAULT_PROFILE;
3445
3411
  var init_config = __esm({
3446
3412
  "src/config.ts"() {
@@ -3777,7 +3743,7 @@ async function confirmFromServer(opts) {
3777
3743
  const project = projectId ? await nameProject(projectId, identity.accountScope, opts) : null;
3778
3744
  return {
3779
3745
  organizationId: identity.accountScope,
3780
- environment: keyEnv,
3746
+ environment: identity.branchRoot === void 0 ? keyEnv : identity.branchRoot ? "production" : "sandbox",
3781
3747
  project,
3782
3748
  projectId,
3783
3749
  branchId: identity.branchId ?? null,
@@ -4028,6 +3994,7 @@ function parsePushArgs(argv) {
4028
3994
  let force = false;
4029
3995
  let yes = false;
4030
3996
  let dryRun = false;
3997
+ let envFile;
4031
3998
  const renames = [];
4032
3999
  const backfills = [];
4033
4000
  for (let i = 0; i < argv.length; i++) {
@@ -4042,6 +4009,9 @@ function parsePushArgs(argv) {
4042
4009
  case "--url":
4043
4010
  url = argv[++i] ?? url;
4044
4011
  break;
4012
+ case "--env-file":
4013
+ envFile = argv[++i] ?? envFile;
4014
+ break;
4045
4015
  case "--force":
4046
4016
  force = true;
4047
4017
  break;
@@ -4083,7 +4053,18 @@ function parsePushArgs(argv) {
4083
4053
  }
4084
4054
  }
4085
4055
  url = url.replace(/\/+$/, "");
4086
- return { schemaPath, exportName, url, apiKey: process.env.ABLO_API_KEY, force, renames, backfills, yes, dryRun };
4056
+ return {
4057
+ schemaPath,
4058
+ exportName,
4059
+ url,
4060
+ apiKey: process.env.ABLO_API_KEY,
4061
+ ...envFile ? { envFile } : {},
4062
+ force,
4063
+ renames,
4064
+ backfills,
4065
+ yes,
4066
+ dryRun
4067
+ };
4087
4068
  }
4088
4069
  function publicationGap(value) {
4089
4070
  if (typeof value !== "object" || value === null) return null;
@@ -4184,8 +4165,21 @@ function printPlan(local, remote) {
4184
4165
  console.log("");
4185
4166
  }
4186
4167
  async function confirmPush(args, target) {
4187
- const env = target.confirmed?.environment ?? target.keyEnv;
4188
- const isProd = env === "production";
4168
+ const confirmedRoot = target.confirmed?.branchRoot;
4169
+ const legacyEnv = target.keyEnv;
4170
+ if (confirmedRoot === void 0 && legacyEnv === null) {
4171
+ console.error(
4172
+ ` ${import_picocolors5.default.red("\u2717")} Refusing to deploy because the server did not confirm which branch this key targets.`
4173
+ );
4174
+ console.error(
4175
+ import_picocolors5.default.dim(
4176
+ ` Current ${import_picocolors5.default.bold("sk_")} keys do not encode live/test state. Check connectivity with ${import_picocolors5.default.bold("ablo whoami")} and retry; the CLI will not guess for a write.`
4177
+ )
4178
+ );
4179
+ process.exit(1);
4180
+ return;
4181
+ }
4182
+ const isProd = confirmedRoot ?? legacyEnv === "production";
4189
4183
  const tty = Boolean(process.stdout.isTTY && process.stdin.isTTY);
4190
4184
  if (isProd && !args.yes) {
4191
4185
  if (!tty) {
@@ -4208,7 +4202,10 @@ async function confirmPush(args, target) {
4208
4202
  return;
4209
4203
  }
4210
4204
  if (!isProd && !args.yes && tty) {
4211
- const ok = await ye({ message: `Apply to ${import_picocolors5.default.bold("sandbox")}?` });
4205
+ const branch = target.confirmed?.branchId;
4206
+ const ok = await ye({
4207
+ message: `Apply to development branch${branch ? ` ${import_picocolors5.default.bold(branch)}` : ""}?`
4208
+ });
4212
4209
  if (pD(ok) || !ok) {
4213
4210
  xe("Aborted.");
4214
4211
  process.exit(1);
@@ -4217,8 +4214,7 @@ async function confirmPush(args, target) {
4217
4214
  }
4218
4215
  function printPushTarget(target, schema) {
4219
4216
  const confirmed = target.confirmed;
4220
- const env = confirmed?.environment ?? target.keyEnv;
4221
- const envLabel = env === "production" ? import_picocolors5.default.bold("production") : env === "sandbox" ? import_picocolors5.default.bold("sandbox") : import_picocolors5.default.yellow("unknown env");
4217
+ const branchLabel = confirmed?.branchRoot === true ? import_picocolors5.default.bold("production root") : confirmed?.branchId ? `${import_picocolors5.default.bold("branch")} ${import_picocolors5.default.bold(confirmed.branchId)}` : target.keyEnv === "production" ? `${import_picocolors5.default.bold("production root")} ${import_picocolors5.default.yellow("(legacy key; unconfirmed)")}` : target.keyEnv === "sandbox" ? `${import_picocolors5.default.bold("development branch")} ${import_picocolors5.default.yellow("(legacy key; unconfirmed)")}` : import_picocolors5.default.red("unknown branch");
4222
4218
  let projectLabel;
4223
4219
  if (confirmed?.project) {
4224
4220
  const p2 = confirmed.project;
@@ -4231,7 +4227,7 @@ function printPushTarget(target, schema) {
4231
4227
  projectLabel = `${shown} ${import_picocolors5.default.yellow("(unconfirmed \u2014 server did not answer)")}`;
4232
4228
  }
4233
4229
  console.log(`
4234
- ${brand("ablo")} ${import_picocolors5.default.dim("push")} ${import_picocolors5.default.dim("\u2192")} ${envLabel}`);
4230
+ ${brand("ablo")} ${import_picocolors5.default.dim("push")} ${import_picocolors5.default.dim("\u2192")} ${branchLabel}`);
4235
4231
  if (confirmed?.organizationId) console.log(` ${import_picocolors5.default.dim("org")} ${import_picocolors5.default.dim(confirmed.organizationId)}`);
4236
4232
  console.log(` ${import_picocolors5.default.dim("project")} ${projectLabel}`);
4237
4233
  console.log(` ${import_picocolors5.default.dim("target")} ${import_picocolors5.default.dim(target.url)}`);
@@ -4260,6 +4256,8 @@ function describeKeySource(source) {
4260
4256
  return ".env";
4261
4257
  case "stored":
4262
4258
  return "ablo login";
4259
+ case "explicit-file":
4260
+ return "--env-file";
4263
4261
  }
4264
4262
  }
4265
4263
  async function push(argv) {
@@ -4270,16 +4268,29 @@ async function push(argv) {
4270
4268
  console.error(import_picocolors5.default.red(` ${err instanceof Error ? err.message : String(err)}`));
4271
4269
  process.exit(1);
4272
4270
  }
4271
+ if (args.envFile) {
4272
+ try {
4273
+ process.loadEnvFile(args.envFile);
4274
+ } catch (error) {
4275
+ throw new import_errors6.AbloValidationError(
4276
+ `could not load --env-file ${args.envFile}: ${error instanceof Error ? error.message : String(error)}`,
4277
+ { code: "cli_invalid_arguments" }
4278
+ );
4279
+ }
4280
+ args.apiKey = process.env.ABLO_API_KEY;
4281
+ }
4273
4282
  let keySource = "env";
4274
4283
  if (!args.apiKey) {
4275
- const resolved = resolveEffectiveApiKey();
4276
- args.apiKey = resolved.key;
4277
- keySource = resolved.source ?? "stored";
4284
+ args.apiKey = resolveMutationApiKey();
4285
+ keySource = args.apiKey ? "stored" : "env";
4286
+ } else if (args.envFile) {
4287
+ keySource = "explicit-file";
4278
4288
  }
4279
4289
  if (!args.apiKey) {
4290
+ const ambient = ambientEnvKeyNote();
4280
4291
  console.error(
4281
4292
  import_picocolors5.default.red(` No API key.`) + import_picocolors5.default.dim(
4282
- ` Run ${import_picocolors5.default.bold("npx ablo login")} \u2014 or set ${import_picocolors5.default.bold("ABLO_API_KEY")} (${import_picocolors5.default.bold("sk_test_")} = sandbox; ${import_picocolors5.default.bold("sk_live_")} = production).`
4293
+ ` Run ${import_picocolors5.default.bold("ablo login")}, or set ${import_picocolors5.default.bold("ABLO_API_KEY")} to a branch-bound ${import_picocolors5.default.bold("sk_")} credential.` + (ambient ? ` A project env file contains one; select it explicitly with ${import_picocolors5.default.bold("npx ablo push --env-file .env.local")}.` : "")
4283
4294
  )
4284
4295
  );
4285
4296
  process.exit(1);
@@ -4416,19 +4427,19 @@ async function push(argv) {
4416
4427
  } else if (code === "schema_provisioning_forbidden") {
4417
4428
  console.error(
4418
4429
  import_picocolors5.default.dim(
4419
- ` This is not a key problem \u2014 the push was authorized, but the target database refused to let the engine create tables (Postgres 42501). On the replication read path Ablo never runs DDL: register your database as a data source with ${import_picocolors5.default.bold("npx ablo connect register")}, and pushes to that environment record the schema as metadata only \u2014 no tables are created anywhere.`
4430
+ ` This is not a key problem \u2014 the push was authorized, but the target database refused to let the engine create tables (Postgres 42501). On the replication read path Ablo never runs DDL: register your database as a data source with ${import_picocolors5.default.bold("npx ablo connect register")}, and pushes to that branch record the schema as metadata only \u2014 no tables are created anywhere.`
4420
4431
  )
4421
4432
  );
4422
4433
  } else if (args.apiKey != null && (0, import_credentialPolicy.classifyCredentialKind)(args.apiKey) === "restricted") {
4423
4434
  console.error(
4424
4435
  import_picocolors5.default.dim(
4425
- ` Schema pushes need a SECRET key: ${import_picocolors5.default.bold("sk_test_")} (sandbox dev loop) or a dashboard ${import_picocolors5.default.bold("sk_live_")} (production deploy: ${import_picocolors5.default.bold("ABLO_API_KEY=sk_live_\u2026 npx ablo push")}).`
4436
+ ` Schema pushes need a branch-bound SECRET ${import_picocolors5.default.bold("sk_")} key. Use ${import_picocolors5.default.bold("ablo dev")} for a development child or ${import_picocolors5.default.bold("ablo push")} with a root-bound key for production.`
4426
4437
  )
4427
4438
  );
4428
4439
  } else {
4429
4440
  console.error(
4430
4441
  import_picocolors5.default.dim(
4431
- ` This key isn't authorized to push schema (needs ${import_picocolors5.default.bold("schema:push")}). ` + (keySource === "stored" ? `It's your stored ${import_picocolors5.default.bold("ablo login")} sandbox key \u2014 a key in ${import_picocolors5.default.bold(".env.local")} or ${import_picocolors5.default.bold("ABLO_API_KEY")} takes precedence, so put a schema:push key there (sandbox ${import_picocolors5.default.bold("sk_test_")} or production ${import_picocolors5.default.bold("sk_live_")}) and re-push. ` : `Use a schema:push key \u2014 a sandbox ${import_picocolors5.default.bold("sk_test_")} or production ${import_picocolors5.default.bold("sk_live_")}. `) + `Manage keys at https://abloatai.com`
4442
+ ` This key isn't authorized to push schema (needs ${import_picocolors5.default.bold("schema:push")}). ` + (keySource === "stored" ? `The stored login is management-only. Put a branch-bound ${import_picocolors5.default.bold("sk_")} key with ${import_picocolors5.default.bold("schema:push")} in ${import_picocolors5.default.bold(".env.local")} or ${import_picocolors5.default.bold("ABLO_API_KEY")} and retry. ` : `Use a branch-bound ${import_picocolors5.default.bold("sk_")} key with ${import_picocolors5.default.bold("schema:push")}. `) + `Manage keys at https://abloatai.com`
4432
4443
  )
4433
4444
  );
4434
4445
  }
@@ -4437,7 +4448,7 @@ async function push(argv) {
4437
4448
  }
4438
4449
  process.exit(1);
4439
4450
  }
4440
- var import_picocolors5, import_errors6, import_credentialPolicy, import_fs4, import_path3, import_child_process, import_schema, import_schema2, DEFAULT_SCHEMA_PATH, DEFAULT_EXPORT;
4451
+ var import_picocolors5, import_errors6, import_credentialPolicy, import_fs4, import_path3, import_child_process, import_schema, import_schema2, DEFAULT_SCHEMA_PATH, DEFAULT_EXPORT, PUSH_USAGE;
4441
4452
  var init_push = __esm({
4442
4453
  "src/push.ts"() {
4443
4454
  "use strict";
@@ -4458,6 +4469,26 @@ var init_push = __esm({
4458
4469
  import_schema2 = require("@abloatai/transaction/coordination/schema");
4459
4470
  DEFAULT_SCHEMA_PATH = "ablo/schema.ts";
4460
4471
  DEFAULT_EXPORT = "schema";
4472
+ PUSH_USAGE = ` ablo push \u2014 upload a schema to one confirmed branch
4473
+
4474
+ Usage:
4475
+ npx ablo push
4476
+ npx ablo push --env-file .env.production --yes
4477
+ npx ablo push --dry-run
4478
+
4479
+ Credential:
4480
+ ABLO_API_KEY Branch-bound sk_ key from the process environment
4481
+ --env-file <path> Explicitly load ABLO_API_KEY from a dotenv file
4482
+
4483
+ Safety:
4484
+ --yes, -y Confirm non-interactively (required for the production root)
4485
+ --dry-run, --plan Show target and schema diff without applying
4486
+ --force Allow destructive schema changes
4487
+ --rename old:new Record a model rename
4488
+ --backfill m.f=value Seed existing rows for a new required field
4489
+
4490
+ The server confirms the key's project and branch. Current keys do not encode
4491
+ live/test state, and push never guesses a branch from their spelling.`;
4461
4492
  }
4462
4493
  });
4463
4494
 
@@ -4982,8 +5013,8 @@ __export(disconnect_exports, {
4982
5013
  function planeLabel(target) {
4983
5014
  const confirmed = target.confirmed;
4984
5015
  const project = confirmed?.project?.name ?? confirmed?.project?.slug ?? confirmed?.projectId ?? "the default project";
4985
- const env = confirmed?.environment ?? target.keyEnv ?? "unknown environment";
4986
- return { project, env };
5016
+ const branch = confirmed?.branchRoot === true ? "production root" : confirmed?.branchId ? `branch ${confirmed.branchId}` : target.keyEnv === "production" ? "production root (legacy key; unconfirmed)" : target.keyEnv === "sandbox" ? "development branch (legacy key; unconfirmed)" : "unknown branch";
5017
+ return { project, branch };
4987
5018
  }
4988
5019
  async function deregisterDataSource(opts) {
4989
5020
  try {
@@ -5000,7 +5031,7 @@ async function deregisterDataSource(opts) {
5000
5031
  if (err instanceof import_errors8.AbloError && err.code === "entity_not_found") return { removed: false };
5001
5032
  if (err instanceof import_errors8.AbloError && err.code === "forbidden") {
5002
5033
  throw new import_errors8.AbloPermissionError(
5003
- `${err.message}. Disconnecting needs a secret key (sk_\u2026) \u2014 run \`ablo login\` to store one.`,
5034
+ `${err.message}. Disconnecting needs a branch-bound secret key (sk_\u2026).`,
5004
5035
  {
5005
5036
  code: "forbidden",
5006
5037
  ...err.requestId !== void 0 ? { requestId: err.requestId } : {}
@@ -5010,7 +5041,7 @@ async function deregisterDataSource(opts) {
5010
5041
  throw err;
5011
5042
  }
5012
5043
  }
5013
- function renderDisconnected(response, project, envLabel) {
5044
+ function renderDisconnected(response, project, branchLabel) {
5014
5045
  const parts = [];
5015
5046
  if (response.cleared.direct) parts.push("the direct database registration");
5016
5047
  if (response.cleared.endpoints > 0) {
@@ -5021,7 +5052,7 @@ function renderDisconnected(response, project, envLabel) {
5021
5052
  const what = parts.length > 0 ? parts.join(" and ") : "the data source";
5022
5053
  console.log(
5023
5054
  `
5024
- ${import_picocolors8.default.green("\u2713")} Disconnected ${what} for ${import_picocolors8.default.bold(project)} in ${envLabel}. Reconnect with ${import_picocolors8.default.bold("ablo connect")}.
5055
+ ${import_picocolors8.default.green("\u2713")} Disconnected ${what} for ${import_picocolors8.default.bold(project)} on ${branchLabel}. Reconnect with ${import_picocolors8.default.bold("ablo connect")}.
5025
5056
  `
5026
5057
  );
5027
5058
  const slot = response.replication_slot;
@@ -5030,14 +5061,27 @@ function renderDisconnected(response, project, envLabel) {
5030
5061
  ` ${import_picocolors8.default.yellow("!")} ${slot.warning ?? `The replication slot ${import_picocolors8.default.bold(slot.slot)} is still on your database and still holding your write-ahead log. Remove it yourself \u2014 nothing will release it now.`}`
5031
5062
  );
5032
5063
  if (slot.detail) console.log(import_picocolors8.default.dim(` ${slot.detail}`));
5033
- if (slot.remove_with) console.log(` ${import_picocolors8.default.bold(slot.remove_with)}`);
5064
+ console.log(
5065
+ import_picocolors8.default.dim(
5066
+ ` Moving this database to another branch? Keep the roles and slot; run ${import_picocolors8.default.bold("ablo connect rotate --env-file .env.local --yes")} to re-key and reuse them.`
5067
+ )
5068
+ );
5069
+ if (slot.remove_with) {
5070
+ console.log(import_picocolors8.default.dim(" Not reconnecting this database? Remove the unused slot in your SQL editor:"));
5071
+ console.log(` ${import_picocolors8.default.bold(slot.remove_with)}`);
5072
+ }
5034
5073
  console.log();
5035
5074
  }
5036
5075
  }
5037
5076
  async function disconnect(argv) {
5038
5077
  let skipConfirm = false;
5039
- for (const arg of argv) {
5078
+ let envFile;
5079
+ let keyEnv;
5080
+ for (let i = 0; i < argv.length; i++) {
5081
+ const arg = argv[i];
5040
5082
  if (arg === "--yes" || arg === "-y") skipConfirm = true;
5083
+ else if (arg === "--env-file") envFile = argv[++i];
5084
+ else if (arg === "--key-env") keyEnv = argv[++i];
5041
5085
  else if (arg === "--help" || arg === "-h") {
5042
5086
  console.log(DISCONNECT_USAGE);
5043
5087
  return;
@@ -5053,19 +5097,39 @@ async function disconnect(argv) {
5053
5097
  ${brand("ablo")} ${import_picocolors8.default.dim("connect deregister")} ${import_picocolors8.default.dim("remove this project's data source")}
5054
5098
  `
5055
5099
  );
5056
- const resolved = resolveEffectiveApiKey();
5100
+ if (envFile) {
5101
+ try {
5102
+ process.loadEnvFile(envFile);
5103
+ } catch (error) {
5104
+ throw new import_errors8.AbloValidationError(
5105
+ `could not load --env-file ${envFile}: ${error instanceof Error ? error.message : String(error)}`,
5106
+ { code: "cli_invalid_arguments" }
5107
+ );
5108
+ }
5109
+ }
5110
+ const selected = keyEnv ? readProjectEnvVariable(keyEnv) : null;
5111
+ if (keyEnv && !selected) {
5112
+ throw new import_errors8.AbloAuthenticationError(
5113
+ `No value named ${keyEnv} was found in the process environment, .env.local, or .env.`,
5114
+ { code: "cli_api_key_missing" }
5115
+ );
5116
+ }
5117
+ const resolved = selected ? { key: selected.value, source: selected.source } : {
5118
+ key: resolveMutationApiKey(),
5119
+ source: envFile ? "explicit-file" : process.env.ABLO_API_KEY ? "env" : "stored"
5120
+ };
5057
5121
  const apiKey = resolved.key;
5058
5122
  const keySource = resolved.source ?? "stored";
5059
5123
  if (!apiKey) {
5060
5124
  throw new import_errors8.AbloAuthenticationError(
5061
- "Disconnecting needs an API key, and none was found. Run `ablo login` (or set ABLO_API_KEY), then re-run `ablo connect deregister`.",
5125
+ "Disconnecting needs a branch-bound sk_ key. Set ABLO_API_KEY, pass `--env-file .env.local`, or select a named recovery key with `--key-env <NAME>`.",
5062
5126
  { code: "cli_api_key_missing" }
5063
5127
  );
5064
5128
  }
5065
5129
  const apiUrl3 = apiBaseUrl();
5066
5130
  const target = await resolveTarget({ url: apiUrl3, apiKey, keySource });
5067
- const { project, env } = planeLabel(target);
5068
- const envLabel = env === "production" ? import_picocolors8.default.yellow(env) : import_picocolors8.default.dim(env);
5131
+ const { project, branch } = planeLabel(target);
5132
+ const branchLabel = target.confirmed?.branchRoot ? import_picocolors8.default.yellow(branch) : import_picocolors8.default.dim(branch);
5069
5133
  const divergence = describeMismatches(target.mismatches);
5070
5134
  if (divergence) console.log(` ${import_picocolors8.default.yellow("\u26A0")} ${divergence}
5071
5135
  `);
@@ -5077,7 +5141,7 @@ async function disconnect(argv) {
5077
5141
  );
5078
5142
  }
5079
5143
  const proceed = await ye({
5080
- message: `Disconnect the data source for ${import_picocolors8.default.bold(project)} in ${envLabel}?`,
5144
+ message: `Disconnect the data source for ${import_picocolors8.default.bold(project)} on ${branchLabel}?`,
5081
5145
  initialValue: true
5082
5146
  });
5083
5147
  if (pD(proceed) || !proceed) {
@@ -5088,11 +5152,11 @@ async function disconnect(argv) {
5088
5152
  }
5089
5153
  const outcome = await deregisterDataSource({ apiKey });
5090
5154
  if (!outcome.removed) {
5091
- console.log(import_picocolors8.default.dim(` No data source registered for ${project} in ${env}.
5155
+ console.log(import_picocolors8.default.dim(` No data source registered for ${project} on ${branch}.
5092
5156
  `));
5093
5157
  return;
5094
5158
  }
5095
- renderDisconnected(outcome.response, project, envLabel);
5159
+ renderDisconnected(outcome.response, project, branchLabel);
5096
5160
  }
5097
5161
  var import_picocolors8, import_errors8, import_wire4, DISCONNECT_USAGE;
5098
5162
  var init_disconnect = __esm({
@@ -5104,6 +5168,7 @@ var init_disconnect = __esm({
5104
5168
  import_errors8 = require("@abloatai/transaction/errors");
5105
5169
  import_wire4 = require("@abloatai/transaction/wire");
5106
5170
  init_config();
5171
+ init_dbRole();
5107
5172
  init_controlPlane();
5108
5173
  init_theme();
5109
5174
  init_target();
@@ -5112,9 +5177,10 @@ var init_disconnect = __esm({
5112
5177
  Usage
5113
5178
  npx ablo connect deregister Remove the active project's data source (confirms first)
5114
5179
  npx ablo connect deregister --yes Skip the confirmation
5180
+ npx ablo connect deregister --key-env OLD_KEY_NAME --yes
5115
5181
 
5116
- Acts on one plane \u2014 the active project (${import_picocolors8.default.bold("ablo projects use")}) in the key's
5117
- environment (its ${import_picocolors8.default.bold("sk_test_")}/${import_picocolors8.default.bold("sk_live_")} prefix), shown before it runs. Removes the registration and
5182
+ Acts on exactly the server-confirmed project and branch bound to the key, shown
5183
+ before it runs. Removes the registration and
5118
5184
  Ablo's replication state for that plane, so Ablo stops reading and writing the
5119
5185
  database. Reconnect with ${import_picocolors8.default.bold("ablo connect")}.`;
5120
5186
  }
@@ -5704,18 +5770,20 @@ async function runConnectApply(args) {
5704
5770
  target = `${parsed.host}${parsed.pathname === "/" ? "" : parsed.pathname}`;
5705
5771
  } catch {
5706
5772
  }
5707
- const apiKey = resolveApiKey();
5773
+ const apiKey = resolveMutationApiKey();
5708
5774
  if (!apiKey) {
5709
5775
  const loggedIn = resolveManagementKey() !== void 0;
5710
5776
  const ambient = ambientEnvKeyNote();
5777
+ const retry = `npx ablo connect ${rotating ? "rotate" : "apply"} --env-file .env.local --yes`;
5711
5778
  throw new import_errors9.AbloAuthenticationError(
5712
- loggedIn ? `You are logged in, but this project has no ${getMode()} data key.
5779
+ loggedIn ? `You are logged in, but connect needs a branch-bound runtime key.
5713
5780
 
5714
- The key is looked for in ABLO_API_KEY, then in the credential stored for the active project in the active mode (${getMode()}). Logging in stores a management credential, which administers the project but cannot register a database \u2014 and a key for another mode is never used implicitly, so registering against production takes an explicit production key.
5781
+ Logging in stores an mk_ management credential; it can manage branches but cannot read, write, or register a database. Set ABLO_API_KEY to the sk_ key for the exact branch this database should join. The server confirms whether that branch is the production root or a development child; the CLI does not infer it from the key spelling.${ambient ? `
5715
5782
 
5716
- Mint a sandbox key with \`npx ablo dev\`, or set ABLO_API_KEY to the key of the plane this database should join (its sk_live_ key for production).${ambient ? `
5783
+ ${ambient}
5717
5784
 
5718
- ${ambient}` : ""}` : `Not logged in, and no ABLO_API_KEY is set. Run \`ablo login\` (or set ABLO_API_KEY) so Ablo knows which project to register this database for.${ambient ? `
5785
+ Use it explicitly with:
5786
+ ${retry}` : ""}` : `Not logged in, and no ABLO_API_KEY is set. Run \`ablo login\` (or set ABLO_API_KEY) so Ablo knows which project to register this database for.${ambient ? `
5719
5787
 
5720
5788
  ${ambient}` : ""}`,
5721
5789
  { code: "cli_api_key_missing" }
@@ -6122,6 +6190,7 @@ function parseConnectArgs(argv) {
6122
6190
  let apply = false;
6123
6191
  let rotate = false;
6124
6192
  let url;
6193
+ let envFile;
6125
6194
  let yes = false;
6126
6195
  let showSql = false;
6127
6196
  let scan = false;
@@ -6167,6 +6236,9 @@ function parseConnectArgs(argv) {
6167
6236
  case "--url":
6168
6237
  url = argv[++i] ?? url;
6169
6238
  break;
6239
+ case "--env-file":
6240
+ envFile = argv[++i] ?? envFile;
6241
+ break;
6170
6242
  case "--yes":
6171
6243
  case "-y":
6172
6244
  yes = true;
@@ -6214,6 +6286,7 @@ function parseConnectArgs(argv) {
6214
6286
  apply,
6215
6287
  rotate,
6216
6288
  url,
6289
+ envFile,
6217
6290
  yes,
6218
6291
  showSql,
6219
6292
  scan,
@@ -6513,11 +6586,11 @@ async function runCheck() {
6513
6586
  ${brand("ablo")} ${import_picocolors12.default.dim("connect check")} ${import_picocolors12.default.dim("direct-write + WAL readiness")}
6514
6587
  `
6515
6588
  );
6516
- const apiKey = resolveApiKey();
6589
+ const apiKey = resolveRuntimeApiKey().key;
6517
6590
  if (!apiKey) {
6518
6591
  const ambient = ambientEnvKeyNote();
6519
6592
  throw new import_errors10.AbloAuthenticationError(
6520
- `No API key found. Run \`ablo login\` (or set ABLO_API_KEY), then re-run \`ablo connect check\`.${ambient ? `
6593
+ `No branch-bound runtime key found. Set ABLO_API_KEY to the sk_ key for the branch to check, or pass \`--env-file .env.local\` explicitly.${ambient ? `
6521
6594
 
6522
6595
  ${ambient}` : ""}`,
6523
6596
  { code: "cli_api_key_missing" }
@@ -6582,11 +6655,11 @@ ${ambient}` : ""}`,
6582
6655
  async function runRegister(args) {
6583
6656
  const dbUrl = requireScopedUrl("replication", "register");
6584
6657
  const writeDbUrl = requireScopedUrl("write", "register");
6585
- const apiKey = resolveApiKey();
6658
+ const apiKey = resolveMutationApiKey();
6586
6659
  if (!apiKey) {
6587
6660
  const ambient = ambientEnvKeyNote();
6588
6661
  throw new import_errors10.AbloAuthenticationError(
6589
- `Not logged in. Run \`ablo login\` (or set ABLO_API_KEY) so Ablo knows which project to register this database for.${ambient ? `
6662
+ `No branch-bound runtime key found. Set ABLO_API_KEY to the sk_ key for the branch to register, or pass \`--env-file .env.local\` explicitly.${ambient ? `
6590
6663
 
6591
6664
  ${ambient}` : ""}`,
6592
6665
  { code: "cli_api_key_missing" }
@@ -6702,11 +6775,11 @@ async function runLocate(args) {
6702
6775
  { code: "cli_database_url_missing" }
6703
6776
  );
6704
6777
  }
6705
- const apiKey = resolveApiKey();
6778
+ const apiKey = resolveRuntimeApiKey().key;
6706
6779
  if (!apiKey) {
6707
6780
  const ambient = ambientEnvKeyNote();
6708
6781
  throw new import_errors10.AbloAuthenticationError(
6709
- `No API key found. Run \`ablo login\` (or set ABLO_API_KEY), then re-run \`ablo connect locate\`.${ambient ? `
6782
+ `No branch-bound runtime key found. Set ABLO_API_KEY to a key that can inspect this project, or pass \`--env-file .env.local\` explicitly.${ambient ? `
6710
6783
 
6711
6784
  ${ambient}` : ""}`,
6712
6785
  { code: "cli_api_key_missing" }
@@ -6752,6 +6825,16 @@ async function connect(argv) {
6752
6825
  return;
6753
6826
  }
6754
6827
  const args = parseConnectArgs(argv);
6828
+ if (args.envFile) {
6829
+ try {
6830
+ process.loadEnvFile(args.envFile);
6831
+ } catch (error) {
6832
+ throw new import_errors10.AbloValidationError(
6833
+ `could not load --env-file ${args.envFile}: ${error instanceof Error ? error.message : String(error)}`,
6834
+ { code: "cli_invalid_arguments" }
6835
+ );
6836
+ }
6837
+ }
6755
6838
  if (args.apply || args.rotate) {
6756
6839
  const { runConnectApply: runConnectApply2 } = await Promise.resolve().then(() => (init_connectApply(), connectApply_exports));
6757
6840
  await runConnectApply2(args);
@@ -6829,6 +6912,7 @@ var init_connect = __esm({
6829
6912
 
6830
6913
  Modifiers:
6831
6914
  --url <admin-conn> Admin connection used once to set up (else DATABASE_URL); never stored
6915
+ --env-file <path> Explicitly load DATABASE_URL and ABLO_API_KEY from this file
6832
6916
  --tables a,b,c Publish only these tables (default: all tables)
6833
6917
  --role <name> Name the replication role (default: ablo_replicator)
6834
6918
  --write-role <name> Name the DML role (default: ablo_writer)
@@ -12719,8 +12803,8 @@ var require_typescript = __commonJS({
12719
12803
  function createGetCanonicalFileName(useCaseSensitiveFileNames2) {
12720
12804
  return useCaseSensitiveFileNames2 ? identity : toFileNameLowerCase;
12721
12805
  }
12722
- function patternText({ prefix: prefix2, suffix }) {
12723
- return `${prefix2}*${suffix}`;
12806
+ function patternText({ prefix, suffix }) {
12807
+ return `${prefix}*${suffix}`;
12724
12808
  }
12725
12809
  function matchedText(pattern, candidate) {
12726
12810
  Debug.assert(isPatternMatch(pattern, candidate));
@@ -12739,17 +12823,17 @@ var require_typescript = __commonJS({
12739
12823
  }
12740
12824
  return matchedValue;
12741
12825
  }
12742
- function startsWith(str, prefix2, ignoreCase) {
12743
- return ignoreCase ? equateStringsCaseInsensitive(str.slice(0, prefix2.length), prefix2) : str.lastIndexOf(prefix2, 0) === 0;
12826
+ function startsWith(str, prefix, ignoreCase) {
12827
+ return ignoreCase ? equateStringsCaseInsensitive(str.slice(0, prefix.length), prefix) : str.lastIndexOf(prefix, 0) === 0;
12744
12828
  }
12745
- function removePrefix(str, prefix2) {
12746
- return startsWith(str, prefix2) ? str.substr(prefix2.length) : str;
12829
+ function removePrefix(str, prefix) {
12830
+ return startsWith(str, prefix) ? str.substr(prefix.length) : str;
12747
12831
  }
12748
- function tryRemovePrefix(str, prefix2, getCanonicalFileName = identity) {
12749
- return startsWith(getCanonicalFileName(str), getCanonicalFileName(prefix2)) ? str.substring(prefix2.length) : void 0;
12832
+ function tryRemovePrefix(str, prefix, getCanonicalFileName = identity) {
12833
+ return startsWith(getCanonicalFileName(str), getCanonicalFileName(prefix)) ? str.substring(prefix.length) : void 0;
12750
12834
  }
12751
- function isPatternMatch({ prefix: prefix2, suffix }, candidate) {
12752
- return candidate.length >= prefix2.length + suffix.length && startsWith(candidate, prefix2) && endsWith(candidate, suffix);
12835
+ function isPatternMatch({ prefix, suffix }, candidate) {
12836
+ return candidate.length >= prefix.length + suffix.length && startsWith(candidate, prefix) && endsWith(candidate, suffix);
12753
12837
  }
12754
12838
  function and(f, g2) {
12755
12839
  return (arg) => f(arg) && g2(arg);
@@ -18523,8 +18607,8 @@ ${lanes.join("\n")}
18523
18607
  );
18524
18608
  const firstComponent = pathComponents2[0];
18525
18609
  if (isAbsolutePathAnUrl && isRootedDiskPath(firstComponent)) {
18526
- const prefix2 = firstComponent.charAt(0) === directorySeparator ? "file://" : "file:///";
18527
- pathComponents2[0] = prefix2 + firstComponent;
18610
+ const prefix = firstComponent.charAt(0) === directorySeparator ? "file://" : "file:///";
18611
+ pathComponents2[0] = prefix + firstComponent;
18528
18612
  }
18529
18613
  return getPathFromPathComponents(pathComponents2);
18530
18614
  }
@@ -35540,12 +35624,12 @@ ${lanes.join("\n")}
35540
35624
  node.symbol = void 0;
35541
35625
  return node;
35542
35626
  }
35543
- function createBaseGeneratedIdentifier(text, autoGenerateFlags, prefix2, suffix) {
35627
+ function createBaseGeneratedIdentifier(text, autoGenerateFlags, prefix, suffix) {
35544
35628
  const node = createBaseIdentifier(escapeLeadingUnderscores(text));
35545
35629
  setIdentifierAutoGenerate(node, {
35546
35630
  flags: autoGenerateFlags,
35547
35631
  id: nextAutoGenerateId,
35548
- prefix: prefix2,
35632
+ prefix,
35549
35633
  suffix
35550
35634
  });
35551
35635
  nextAutoGenerateId++;
@@ -35568,10 +35652,10 @@ ${lanes.join("\n")}
35568
35652
  }
35569
35653
  return node;
35570
35654
  }
35571
- function createTempVariable(recordTempVariable, reservedInNestedScopes, prefix2, suffix) {
35655
+ function createTempVariable(recordTempVariable, reservedInNestedScopes, prefix, suffix) {
35572
35656
  let flags2 = 1;
35573
35657
  if (reservedInNestedScopes) flags2 |= 8;
35574
- const name = createBaseGeneratedIdentifier("", flags2, prefix2, suffix);
35658
+ const name = createBaseGeneratedIdentifier("", flags2, prefix, suffix);
35575
35659
  if (recordTempVariable) {
35576
35660
  recordTempVariable(name);
35577
35661
  }
@@ -35589,23 +35673,23 @@ ${lanes.join("\n")}
35589
35673
  void 0
35590
35674
  );
35591
35675
  }
35592
- function createUniqueName(text, flags2 = 0, prefix2, suffix) {
35676
+ function createUniqueName(text, flags2 = 0, prefix, suffix) {
35593
35677
  Debug.assert(!(flags2 & 7), "Argument out of range: flags");
35594
35678
  Debug.assert((flags2 & (16 | 32)) !== 32, "GeneratedIdentifierFlags.FileLevel cannot be set without also setting GeneratedIdentifierFlags.Optimistic");
35595
- return createBaseGeneratedIdentifier(text, 3 | flags2, prefix2, suffix);
35679
+ return createBaseGeneratedIdentifier(text, 3 | flags2, prefix, suffix);
35596
35680
  }
35597
- function getGeneratedNameForNode(node, flags2 = 0, prefix2, suffix) {
35681
+ function getGeneratedNameForNode(node, flags2 = 0, prefix, suffix) {
35598
35682
  Debug.assert(!(flags2 & 7), "Argument out of range: flags");
35599
35683
  const text = !node ? "" : isMemberName(node) ? formatGeneratedName(
35600
35684
  /*privateName*/
35601
35685
  false,
35602
- prefix2,
35686
+ prefix,
35603
35687
  node,
35604
35688
  suffix,
35605
35689
  idText
35606
35690
  ) : `generated@${getNodeId(node)}`;
35607
- if (prefix2 || suffix) flags2 |= 16;
35608
- const name = createBaseGeneratedIdentifier(text, 4 | flags2, prefix2, suffix);
35691
+ if (prefix || suffix) flags2 |= 16;
35692
+ const name = createBaseGeneratedIdentifier(text, 4 | flags2, prefix, suffix);
35609
35693
  name.original = node;
35610
35694
  return name;
35611
35695
  }
@@ -35622,33 +35706,33 @@ ${lanes.join("\n")}
35622
35706
  if (!startsWith(text, "#")) Debug.fail("First character of private identifier must be #: " + text);
35623
35707
  return createBasePrivateIdentifier(escapeLeadingUnderscores(text));
35624
35708
  }
35625
- function createBaseGeneratedPrivateIdentifier(text, autoGenerateFlags, prefix2, suffix) {
35709
+ function createBaseGeneratedPrivateIdentifier(text, autoGenerateFlags, prefix, suffix) {
35626
35710
  const node = createBasePrivateIdentifier(escapeLeadingUnderscores(text));
35627
35711
  setIdentifierAutoGenerate(node, {
35628
35712
  flags: autoGenerateFlags,
35629
35713
  id: nextAutoGenerateId,
35630
- prefix: prefix2,
35714
+ prefix,
35631
35715
  suffix
35632
35716
  });
35633
35717
  nextAutoGenerateId++;
35634
35718
  return node;
35635
35719
  }
35636
- function createUniquePrivateName(text, prefix2, suffix) {
35720
+ function createUniquePrivateName(text, prefix, suffix) {
35637
35721
  if (text && !startsWith(text, "#")) Debug.fail("First character of private identifier must be #: " + text);
35638
35722
  const autoGenerateFlags = 8 | (text ? 3 : 1);
35639
- return createBaseGeneratedPrivateIdentifier(text ?? "", autoGenerateFlags, prefix2, suffix);
35723
+ return createBaseGeneratedPrivateIdentifier(text ?? "", autoGenerateFlags, prefix, suffix);
35640
35724
  }
35641
- function getGeneratedPrivateNameForNode(node, prefix2, suffix) {
35725
+ function getGeneratedPrivateNameForNode(node, prefix, suffix) {
35642
35726
  const text = isMemberName(node) ? formatGeneratedName(
35643
35727
  /*privateName*/
35644
35728
  true,
35645
- prefix2,
35729
+ prefix,
35646
35730
  node,
35647
35731
  suffix,
35648
35732
  idText
35649
35733
  ) : `#generated@${getNodeId(node)}`;
35650
- const flags2 = prefix2 || suffix ? 16 : 0;
35651
- const name = createBaseGeneratedPrivateIdentifier(text, 4 | flags2, prefix2, suffix);
35734
+ const flags2 = prefix || suffix ? 16 : 0;
35735
+ const name = createBaseGeneratedPrivateIdentifier(text, 4 | flags2, prefix, suffix);
35652
35736
  name.original = node;
35653
35737
  return name;
35654
35738
  }
@@ -40450,13 +40534,13 @@ ${lanes.join("\n")}
40450
40534
  [expr]
40451
40535
  );
40452
40536
  }
40453
- function createSetFunctionNameHelper(f, name, prefix2) {
40537
+ function createSetFunctionNameHelper(f, name, prefix) {
40454
40538
  context.requestEmitHelper(setFunctionNameHelper);
40455
40539
  return context.factory.createCallExpression(
40456
40540
  getUnscopedHelperName("__setFunctionName"),
40457
40541
  /*typeArguments*/
40458
40542
  void 0,
40459
- prefix2 ? [f, name, context.factory.createStringLiteral(prefix2)] : [f, name]
40543
+ prefix ? [f, name, context.factory.createStringLiteral(prefix)] : [f, name]
40460
40544
  );
40461
40545
  }
40462
40546
  function createValuesHelper(expression) {
@@ -42793,11 +42877,11 @@ ${lanes.join("\n")}
42793
42877
  function formatIdentifierWorker(node, generateName) {
42794
42878
  return isGeneratedPrivateIdentifier(node) ? generateName(node).slice(1) : isGeneratedIdentifier(node) ? generateName(node) : isPrivateIdentifier(node) ? node.escapedText.slice(1) : idText(node);
42795
42879
  }
42796
- function formatGeneratedName(privateName, prefix2, baseName, suffix, generateName) {
42797
- prefix2 = formatGeneratedNamePart(prefix2, generateName);
42880
+ function formatGeneratedName(privateName, prefix, baseName, suffix, generateName) {
42881
+ prefix = formatGeneratedNamePart(prefix, generateName);
42798
42882
  suffix = formatGeneratedNamePart(suffix, generateName);
42799
42883
  baseName = formatIdentifier(baseName, generateName);
42800
- return `${privateName ? "#" : ""}${prefix2}${baseName}${suffix}`;
42884
+ return `${privateName ? "#" : ""}${prefix}${baseName}${suffix}`;
42801
42885
  }
42802
42886
  function createAccessorPropertyBackingField(factory2, node, modifiers, initializer) {
42803
42887
  return factory2.updatePropertyDeclaration(
@@ -62872,11 +62956,11 @@ ${lanes.join("\n")}
62872
62956
  candidates.push({ ending: void 0, value: relativeToBaseUrl });
62873
62957
  }
62874
62958
  if (indexOfStar !== -1) {
62875
- const prefix2 = pattern.substring(0, indexOfStar);
62959
+ const prefix = pattern.substring(0, indexOfStar);
62876
62960
  const suffix = pattern.substring(indexOfStar + 1);
62877
62961
  for (const { ending, value } of candidates) {
62878
- if (value.length >= prefix2.length + suffix.length && startsWith(value, prefix2) && endsWith(value, suffix) && validateEnding({ ending, value })) {
62879
- const matchedStar = value.substring(prefix2.length, value.length - suffix.length);
62962
+ if (value.length >= prefix.length + suffix.length && startsWith(value, prefix) && endsWith(value, suffix) && validateEnding({ ending, value })) {
62963
+ const matchedStar = value.substring(prefix.length, value.length - suffix.length);
62880
62964
  if (!pathIsRelative(matchedStar)) {
62881
62965
  return replaceFirstStar(key, matchedStar);
62882
62966
  }
@@ -82575,9 +82659,9 @@ ${lanes.join("\n")}
82575
82659
  }
82576
82660
  secondaryRootErrors.unshift([mappedMsg, args[0], args[1]]);
82577
82661
  } else {
82578
- const prefix2 = msg.code === Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible.code || msg.code === Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code ? "new " : "";
82662
+ const prefix = msg.code === Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible.code || msg.code === Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code ? "new " : "";
82579
82663
  const params = msg.code === Diagnostics.Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code || msg.code === Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code ? "" : "...";
82580
- path = `${prefix2}${path}(${params})`;
82664
+ path = `${prefix}${path}(${params})`;
82581
82665
  }
82582
82666
  break;
82583
82667
  }
@@ -117419,13 +117503,13 @@ ${lanes.join("\n")}
117419
117503
  }
117420
117504
  function createHoistedVariableForClass(name, node, suffix) {
117421
117505
  const { className } = getPrivateIdentifierEnvironment().data;
117422
- const prefix2 = className ? { prefix: "_", node: className, suffix: "_" } : "_";
117423
- const identifier = typeof name === "object" ? factory2.getGeneratedNameForNode(name, 16 | 8, prefix2, suffix) : typeof name === "string" ? factory2.createUniqueName(name, 16, prefix2, suffix) : factory2.createTempVariable(
117506
+ const prefix = className ? { prefix: "_", node: className, suffix: "_" } : "_";
117507
+ const identifier = typeof name === "object" ? factory2.getGeneratedNameForNode(name, 16 | 8, prefix, suffix) : typeof name === "string" ? factory2.createUniqueName(name, 16, prefix, suffix) : factory2.createTempVariable(
117424
117508
  /*recordTempVariable*/
117425
117509
  void 0,
117426
117510
  /*reservedInNestedScopes*/
117427
117511
  true,
117428
- prefix2,
117512
+ prefix,
117429
117513
  suffix
117430
117514
  );
117431
117515
  if (resolver.hasNodeCheckFlag(
@@ -118498,7 +118582,7 @@ ${lanes.join("\n")}
118498
118582
  if (!decoratorExpressions) {
118499
118583
  return void 0;
118500
118584
  }
118501
- const prefix2 = getClassMemberPrefix(node, member);
118585
+ const prefix = getClassMemberPrefix(node, member);
118502
118586
  const memberName = getExpressionForPropertyName(
118503
118587
  member,
118504
118588
  /*generateNameForComputedPropertyName*/
@@ -118511,7 +118595,7 @@ ${lanes.join("\n")}
118511
118595
  const descriptor = isPropertyDeclaration(member) && !hasAccessorModifier(member) ? factory2.createVoidZero() : factory2.createNull();
118512
118596
  const helper = emitHelpers().createDecorateHelper(
118513
118597
  decoratorExpressions,
118514
- prefix2,
118598
+ prefix,
118515
118599
  memberName,
118516
118600
  descriptor
118517
118601
  );
@@ -120414,13 +120498,13 @@ ${lanes.join("\n")}
120414
120498
  3072
120415
120499
  /* NoComments */
120416
120500
  );
120417
- const prefix2 = kind === "get" || kind === "set" ? kind : void 0;
120501
+ const prefix = kind === "get" || kind === "set" ? kind : void 0;
120418
120502
  const functionName = factory2.createStringLiteralFromNode(
120419
120503
  name,
120420
120504
  /*isSingleQuote*/
120421
120505
  void 0
120422
120506
  );
120423
- const namedFunction = emitHelpers().createSetFunctionNameHelper(func, functionName, prefix2);
120507
+ const namedFunction = emitHelpers().createSetFunctionNameHelper(func, functionName, prefix);
120424
120508
  const method = factory2.createPropertyAssignment(factory2.createIdentifier(kind), namedFunction);
120425
120509
  setOriginalNode(method, original);
120426
120510
  setSourceMapRange(method, moveRangePastDecorators(original));
@@ -141200,9 +141284,9 @@ ${lanes.join("\n")}
141200
141284
  emitExpression(node, parenthesizerRule);
141201
141285
  }
141202
141286
  }
141203
- function emitNodeWithPrefix(prefix2, prefixWriter, node, emit2) {
141287
+ function emitNodeWithPrefix(prefix, prefixWriter, node, emit2) {
141204
141288
  if (node) {
141205
- prefixWriter(prefix2);
141289
+ prefixWriter(prefix);
141206
141290
  emit2(node);
141207
141291
  }
141208
141292
  }
@@ -141940,10 +142024,10 @@ ${lanes.join("\n")}
141940
142024
  return autoGeneratedIdToGeneratedName[autoGenerateId] || (autoGeneratedIdToGeneratedName[autoGenerateId] = makeName(name));
141941
142025
  }
141942
142026
  }
141943
- function generateNameCached(node, privateName, flags, prefix2, suffix) {
142027
+ function generateNameCached(node, privateName, flags, prefix, suffix) {
141944
142028
  const nodeId = getNodeId(node);
141945
142029
  const cache = privateName ? nodeIdToGeneratedPrivateName : nodeIdToGeneratedName;
141946
- return cache[nodeId] || (cache[nodeId] = generateNameForNode(node, privateName, flags ?? 0, formatGeneratedNamePart(prefix2, generateName), formatGeneratedNamePart(suffix)));
142030
+ return cache[nodeId] || (cache[nodeId] = generateNameForNode(node, privateName, flags ?? 0, formatGeneratedNamePart(prefix, generateName), formatGeneratedNamePart(suffix)));
141947
142031
  }
141948
142032
  function isUniqueName(name, privateName) {
141949
142033
  return isFileLevelUniqueNameInCurrentFile(name, privateName) && !isReservedName(name, privateName) && !generatedNames.has(name);
@@ -142010,15 +142094,15 @@ ${lanes.join("\n")}
142010
142094
  break;
142011
142095
  }
142012
142096
  }
142013
- function makeTempVariableName(flags, reservedInNestedScopes, privateName, prefix2, suffix) {
142014
- if (prefix2.length > 0 && prefix2.charCodeAt(0) === 35) {
142015
- prefix2 = prefix2.slice(1);
142097
+ function makeTempVariableName(flags, reservedInNestedScopes, privateName, prefix, suffix) {
142098
+ if (prefix.length > 0 && prefix.charCodeAt(0) === 35) {
142099
+ prefix = prefix.slice(1);
142016
142100
  }
142017
- const key = formatGeneratedName(privateName, prefix2, "", suffix);
142101
+ const key = formatGeneratedName(privateName, prefix, "", suffix);
142018
142102
  let tempFlags2 = getTempFlags(key);
142019
142103
  if (flags && !(tempFlags2 & flags)) {
142020
142104
  const name = flags === 268435456 ? "_i" : "_n";
142021
- const fullName = formatGeneratedName(privateName, prefix2, name, suffix);
142105
+ const fullName = formatGeneratedName(privateName, prefix, name, suffix);
142022
142106
  if (isUniqueName(fullName, privateName)) {
142023
142107
  tempFlags2 |= flags;
142024
142108
  if (privateName) {
@@ -142035,7 +142119,7 @@ ${lanes.join("\n")}
142035
142119
  tempFlags2++;
142036
142120
  if (count !== 8 && count !== 13) {
142037
142121
  const name = count < 26 ? "_" + String.fromCharCode(97 + count) : "_" + (count - 26);
142038
- const fullName = formatGeneratedName(privateName, prefix2, name, suffix);
142122
+ const fullName = formatGeneratedName(privateName, prefix, name, suffix);
142039
142123
  if (isUniqueName(fullName, privateName)) {
142040
142124
  if (privateName) {
142041
142125
  reservePrivateNameInNestedScopes(fullName);
@@ -142048,15 +142132,15 @@ ${lanes.join("\n")}
142048
142132
  }
142049
142133
  }
142050
142134
  }
142051
- function makeUniqueName2(baseName, checkFn = isUniqueName, optimistic, scoped, privateName, prefix2, suffix) {
142135
+ function makeUniqueName2(baseName, checkFn = isUniqueName, optimistic, scoped, privateName, prefix, suffix) {
142052
142136
  if (baseName.length > 0 && baseName.charCodeAt(0) === 35) {
142053
142137
  baseName = baseName.slice(1);
142054
142138
  }
142055
- if (prefix2.length > 0 && prefix2.charCodeAt(0) === 35) {
142056
- prefix2 = prefix2.slice(1);
142139
+ if (prefix.length > 0 && prefix.charCodeAt(0) === 35) {
142140
+ prefix = prefix.slice(1);
142057
142141
  }
142058
142142
  if (optimistic) {
142059
- const fullName = formatGeneratedName(privateName, prefix2, baseName, suffix);
142143
+ const fullName = formatGeneratedName(privateName, prefix, baseName, suffix);
142060
142144
  if (checkFn(fullName, privateName)) {
142061
142145
  if (privateName) {
142062
142146
  reservePrivateNameInNestedScopes(fullName);
@@ -142073,7 +142157,7 @@ ${lanes.join("\n")}
142073
142157
  }
142074
142158
  let i = 1;
142075
142159
  while (true) {
142076
- const fullName = formatGeneratedName(privateName, prefix2, baseName + i, suffix);
142160
+ const fullName = formatGeneratedName(privateName, prefix, baseName + i, suffix);
142077
142161
  if (checkFn(fullName, privateName)) {
142078
142162
  if (privateName) {
142079
142163
  reservePrivateNameInNestedScopes(fullName);
@@ -142170,7 +142254,7 @@ ${lanes.join("\n")}
142170
142254
  ""
142171
142255
  );
142172
142256
  }
142173
- function generateNameForMethodOrAccessor(node, privateName, prefix2, suffix) {
142257
+ function generateNameForMethodOrAccessor(node, privateName, prefix, suffix) {
142174
142258
  if (isIdentifier2(node.name)) {
142175
142259
  return generateNameCached(node.name, privateName);
142176
142260
  }
@@ -142179,11 +142263,11 @@ ${lanes.join("\n")}
142179
142263
  /*reservedInNestedScopes*/
142180
142264
  false,
142181
142265
  privateName,
142182
- prefix2,
142266
+ prefix,
142183
142267
  suffix
142184
142268
  );
142185
142269
  }
142186
- function generateNameForNode(node, privateName, flags, prefix2, suffix) {
142270
+ function generateNameForNode(node, privateName, flags, prefix, suffix) {
142187
142271
  switch (node.kind) {
142188
142272
  case 80:
142189
142273
  case 81:
@@ -142193,20 +142277,20 @@ ${lanes.join("\n")}
142193
142277
  !!(flags & 16),
142194
142278
  !!(flags & 8),
142195
142279
  privateName,
142196
- prefix2,
142280
+ prefix,
142197
142281
  suffix
142198
142282
  );
142199
142283
  case 267:
142200
142284
  case 266:
142201
- Debug.assert(!prefix2 && !suffix && !privateName);
142285
+ Debug.assert(!prefix && !suffix && !privateName);
142202
142286
  return generateNameForModuleOrEnum(node);
142203
142287
  case 272:
142204
142288
  case 278:
142205
- Debug.assert(!prefix2 && !suffix && !privateName);
142289
+ Debug.assert(!prefix && !suffix && !privateName);
142206
142290
  return generateNameForImportOrExportDeclaration(node);
142207
142291
  case 262:
142208
142292
  case 263: {
142209
- Debug.assert(!prefix2 && !suffix && !privateName);
142293
+ Debug.assert(!prefix && !suffix && !privateName);
142210
142294
  const name = node.name;
142211
142295
  if (name && !isGeneratedIdentifier(name)) {
142212
142296
  return generateNameForNode(
@@ -142214,29 +142298,29 @@ ${lanes.join("\n")}
142214
142298
  /*privateName*/
142215
142299
  false,
142216
142300
  flags,
142217
- prefix2,
142301
+ prefix,
142218
142302
  suffix
142219
142303
  );
142220
142304
  }
142221
142305
  return generateNameForExportDefault();
142222
142306
  }
142223
142307
  case 277:
142224
- Debug.assert(!prefix2 && !suffix && !privateName);
142308
+ Debug.assert(!prefix && !suffix && !privateName);
142225
142309
  return generateNameForExportDefault();
142226
142310
  case 231:
142227
- Debug.assert(!prefix2 && !suffix && !privateName);
142311
+ Debug.assert(!prefix && !suffix && !privateName);
142228
142312
  return generateNameForClassExpression();
142229
142313
  case 174:
142230
142314
  case 177:
142231
142315
  case 178:
142232
- return generateNameForMethodOrAccessor(node, privateName, prefix2, suffix);
142316
+ return generateNameForMethodOrAccessor(node, privateName, prefix, suffix);
142233
142317
  case 167:
142234
142318
  return makeTempVariableName(
142235
142319
  0,
142236
142320
  /*reservedInNestedScopes*/
142237
142321
  true,
142238
142322
  privateName,
142239
- prefix2,
142323
+ prefix,
142240
142324
  suffix
142241
142325
  );
142242
142326
  default:
@@ -142245,18 +142329,18 @@ ${lanes.join("\n")}
142245
142329
  /*reservedInNestedScopes*/
142246
142330
  false,
142247
142331
  privateName,
142248
- prefix2,
142332
+ prefix,
142249
142333
  suffix
142250
142334
  );
142251
142335
  }
142252
142336
  }
142253
142337
  function makeName(name) {
142254
142338
  const autoGenerate = name.emitNode.autoGenerate;
142255
- const prefix2 = formatGeneratedNamePart(autoGenerate.prefix, generateName);
142339
+ const prefix = formatGeneratedNamePart(autoGenerate.prefix, generateName);
142256
142340
  const suffix = formatGeneratedNamePart(autoGenerate.suffix);
142257
142341
  switch (autoGenerate.flags & 7) {
142258
142342
  case 1:
142259
- return makeTempVariableName(0, !!(autoGenerate.flags & 8), isPrivateIdentifier(name), prefix2, suffix);
142343
+ return makeTempVariableName(0, !!(autoGenerate.flags & 8), isPrivateIdentifier(name), prefix, suffix);
142260
142344
  case 2:
142261
142345
  Debug.assertNode(name, isIdentifier2);
142262
142346
  return makeTempVariableName(
@@ -142264,7 +142348,7 @@ ${lanes.join("\n")}
142264
142348
  !!(autoGenerate.flags & 8),
142265
142349
  /*privateName*/
142266
142350
  false,
142267
- prefix2,
142351
+ prefix,
142268
142352
  suffix
142269
142353
  );
142270
142354
  case 3:
@@ -142274,7 +142358,7 @@ ${lanes.join("\n")}
142274
142358
  !!(autoGenerate.flags & 16),
142275
142359
  !!(autoGenerate.flags & 8),
142276
142360
  isPrivateIdentifier(name),
142277
- prefix2,
142361
+ prefix,
142278
142362
  suffix
142279
142363
  );
142280
142364
  }
@@ -158830,8 +158914,8 @@ ${lanes.join("\n")}
158830
158914
  }
158831
158915
  function buildLinkParts(link, checker) {
158832
158916
  var _a;
158833
- const prefix2 = isJSDocLink(link) ? "link" : isJSDocLinkCode(link) ? "linkcode" : "linkplain";
158834
- const parts = [linkPart(`{@${prefix2} `)];
158917
+ const prefix = isJSDocLink(link) ? "link" : isJSDocLinkCode(link) ? "linkcode" : "linkplain";
158918
+ const parts = [linkPart(`{@${prefix} `)];
158835
158919
  if (!link.name) {
158836
158920
  if (link.text) {
158837
158921
  parts.push(linkTextPart(link.text));
@@ -160304,9 +160388,9 @@ ${lanes.join("\n")}
160304
160388
  let token = 0;
160305
160389
  let lastNonTriviaToken = 0;
160306
160390
  const templateStack = [];
160307
- const { prefix: prefix2, pushTemplate } = getPrefixFromLexState(lexState);
160308
- text = prefix2 + text;
160309
- const offset = prefix2.length;
160391
+ const { prefix, pushTemplate } = getPrefixFromLexState(lexState);
160392
+ text = prefix + text;
160393
+ const offset = prefix.length;
160310
160394
  if (pushTemplate) {
160311
160395
  templateStack.push(
160312
160396
  16
@@ -169464,11 +169548,11 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
169464
169548
  if (decls && decls.some((d3) => d3.parent === scopeDecl)) {
169465
169549
  return factory.createIdentifier(symbol.name);
169466
169550
  }
169467
- const prefix2 = tryReplaceWithQualifiedNameOrPropertyAccess(symbol.parent, scopeDecl, isTypeNode2);
169468
- if (prefix2 === void 0) {
169551
+ const prefix = tryReplaceWithQualifiedNameOrPropertyAccess(symbol.parent, scopeDecl, isTypeNode2);
169552
+ if (prefix === void 0) {
169469
169553
  return void 0;
169470
169554
  }
169471
- return isTypeNode2 ? factory.createQualifiedName(prefix2, factory.createIdentifier(symbol.name)) : factory.createPropertyAccessExpression(prefix2, symbol.name);
169555
+ return isTypeNode2 ? factory.createQualifiedName(prefix, factory.createIdentifier(symbol.name)) : factory.createPropertyAccessExpression(prefix, symbol.name);
169472
169556
  }
169473
169557
  }
169474
169558
  function getExtractableParent(node) {
@@ -170783,13 +170867,13 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
170783
170867
  if (textChangeRange) {
170784
170868
  if (version2 !== sourceFile.version) {
170785
170869
  let newText;
170786
- const prefix2 = textChangeRange.span.start !== 0 ? sourceFile.text.substr(0, textChangeRange.span.start) : "";
170870
+ const prefix = textChangeRange.span.start !== 0 ? sourceFile.text.substr(0, textChangeRange.span.start) : "";
170787
170871
  const suffix = textSpanEnd(textChangeRange.span) !== sourceFile.text.length ? sourceFile.text.substr(textSpanEnd(textChangeRange.span)) : "";
170788
170872
  if (textChangeRange.newLength === 0) {
170789
- newText = prefix2 && suffix ? prefix2 + suffix : prefix2 || suffix;
170873
+ newText = prefix && suffix ? prefix + suffix : prefix || suffix;
170790
170874
  } else {
170791
170875
  const changedText = scriptSnapshot.getText(textChangeRange.span.start, textChangeRange.span.start + textChangeRange.newLength);
170792
- newText = prefix2 && suffix ? prefix2 + changedText + suffix : prefix2 ? prefix2 + changedText : changedText + suffix;
170876
+ newText = prefix && suffix ? prefix + changedText + suffix : prefix ? prefix + changedText : changedText + suffix;
170793
170877
  }
170794
170878
  const newSourceFile = updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks);
170795
170879
  setSourceFileFields(newSourceFile, scriptSnapshot, version2);
@@ -172919,8 +173003,8 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
172919
173003
  const end = pos + 6;
172920
173004
  const typeChecker = program.getTypeChecker();
172921
173005
  const symbol = typeChecker.getSymbolAtLocation(node.parent);
172922
- const prefix2 = symbol ? `${typeChecker.symbolToString(symbol, node.parent)} ` : "";
172923
- return { text: `${prefix2}static {}`, pos, end };
173006
+ const prefix = symbol ? `${typeChecker.symbolToString(symbol, node.parent)} ` : "";
173007
+ return { text: `${prefix}static {}`, pos, end };
172924
173008
  }
172925
173009
  const declName = isAssignedExpression(node) ? node.parent.name : Debug.checkDefined(getNameOfDeclaration(node), "Expected call hierarchy item to have a name");
172926
173010
  let text = isIdentifier2(declName) ? idText(declName) : isStringOrNumericLiteralLike(declName) ? declName.text : isComputedPropertyName(declName) ? isStringOrNumericLiteralLike(declName.expression) ? declName.expression.text : void 0 : void 0;
@@ -176266,18 +176350,18 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
176266
176350
  const commentNode = node.parent;
176267
176351
  const { leftSibling, rightSibling } = getLeftAndRightSiblings(node);
176268
176352
  let pos = commentNode.getStart();
176269
- let prefix2 = "";
176353
+ let prefix = "";
176270
176354
  if (!leftSibling && commentNode.comment) {
176271
176355
  pos = findEndOfTextBetween(commentNode, commentNode.getStart(), node.getStart());
176272
- prefix2 = `${newLine} */${newLine}`;
176356
+ prefix = `${newLine} */${newLine}`;
176273
176357
  }
176274
176358
  if (leftSibling) {
176275
176359
  if (fixAll && isJSDocTypedefTag(leftSibling)) {
176276
176360
  pos = node.getStart();
176277
- prefix2 = "";
176361
+ prefix = "";
176278
176362
  } else {
176279
176363
  pos = findEndOfTextBetween(commentNode, leftSibling.getStart(), node.getStart());
176280
- prefix2 = `${newLine} */${newLine}`;
176364
+ prefix = `${newLine} */${newLine}`;
176281
176365
  }
176282
176366
  }
176283
176367
  let end = commentNode.getEnd();
@@ -176291,7 +176375,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
176291
176375
  suffix = `${newLine}/**${newLine} * `;
176292
176376
  }
176293
176377
  }
176294
- changes.replaceRange(sourceFile, { pos, end }, declaration, { prefix: prefix2, suffix });
176378
+ changes.replaceRange(sourceFile, { pos, end }, declaration, { prefix, suffix });
176295
176379
  }
176296
176380
  function getLeftAndRightSiblings(typedefNode) {
176297
176381
  const commentNode = typedefNode.parent;
@@ -180709,9 +180793,9 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
180709
180793
  result.push(createDeleteFix(deletion, [Diagnostics.Remove_unused_declaration_for_Colon_0, name.getText(sourceFile)]));
180710
180794
  }
180711
180795
  }
180712
- const prefix2 = ts_textChanges_exports.ChangeTracker.with(context, (t) => tryPrefixDeclaration(t, errorCode, sourceFile, token));
180713
- if (prefix2.length) {
180714
- result.push(createCodeFixAction(fixName3, prefix2, [Diagnostics.Prefix_0_with_an_underscore, token.getText(sourceFile)], fixIdPrefix, Diagnostics.Prefix_all_unused_declarations_with_where_possible));
180796
+ const prefix = ts_textChanges_exports.ChangeTracker.with(context, (t) => tryPrefixDeclaration(t, errorCode, sourceFile, token));
180797
+ if (prefix.length) {
180798
+ result.push(createCodeFixAction(fixName3, prefix, [Diagnostics.Prefix_0_with_an_underscore, token.getText(sourceFile)], fixIdPrefix, Diagnostics.Prefix_all_unused_declarations_with_where_possible));
180715
180799
  }
180716
180800
  return result;
180717
180801
  },
@@ -190412,9 +190496,9 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
190412
190496
  function getDirectoryMatches(directoryName) {
190413
190497
  return mapDefined(tryGetDirectories(host, directoryName), (dir) => dir === "node_modules" ? void 0 : directoryResult(dir));
190414
190498
  }
190415
- function trimPrefixAndSuffix(path, prefix2) {
190499
+ function trimPrefixAndSuffix(path, prefix) {
190416
190500
  return firstDefined(matchingSuffixes, (suffix) => {
190417
- const inner = withoutStartAndEnd(normalizePath(path), prefix2, suffix);
190501
+ const inner = withoutStartAndEnd(normalizePath(path), prefix, suffix);
190418
190502
  return inner === void 0 ? void 0 : removeLeadingDirectorySeparator(inner);
190419
190503
  });
190420
190504
  }
@@ -190447,7 +190531,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
190447
190531
  if (!match) {
190448
190532
  return void 0;
190449
190533
  }
190450
- const [, prefix2, kind, toComplete] = match;
190534
+ const [, prefix, kind, toComplete] = match;
190451
190535
  const scriptPath = getDirectoryPath(sourceFile.path);
190452
190536
  const names = kind === "path" ? getCompletionEntriesForDirectoryFragment(
190453
190537
  toComplete,
@@ -190460,7 +190544,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
190460
190544
  true,
190461
190545
  sourceFile.path
190462
190546
  ) : kind === "types" ? getCompletionEntriesFromTypings(program, host, moduleSpecifierResolutionHost, scriptPath, getFragmentDirectory(toComplete), getExtensionOptions(compilerOptions, 1, sourceFile)) : Debug.fail();
190463
- return addReplacementSpans(toComplete, range.pos + prefix2.length, arrayFrom(names.values()));
190547
+ return addReplacementSpans(toComplete, range.pos + prefix.length, arrayFrom(names.values()));
190464
190548
  }
190465
190549
  function getCompletionEntriesFromTypings(program, host, moduleSpecifierResolutionHost, scriptPath, fragmentDirectory, extensionOptions, result = createNameAndKindSet()) {
190466
190550
  const options = program.getCompilerOptions();
@@ -196811,8 +196895,8 @@ ${content}
196811
196895
  ), spacePart()];
196812
196896
  function getSignatureHelpItem(candidateSignature, callTargetDisplayParts, isTypeParameterList, checker, enclosingDeclaration, sourceFile) {
196813
196897
  const infos = (isTypeParameterList ? itemInfoForTypeParameters : itemInfoForParameters)(candidateSignature, checker, enclosingDeclaration, sourceFile);
196814
- return map(infos, ({ isVariadic, parameters, prefix: prefix2, suffix }) => {
196815
- const prefixDisplayParts = [...callTargetDisplayParts, ...prefix2];
196898
+ return map(infos, ({ isVariadic, parameters, prefix, suffix }) => {
196899
+ const prefixDisplayParts = [...callTargetDisplayParts, ...prefix];
196816
196900
  const suffixDisplayParts = [...suffix, ...returnTypeToDisplayParts(candidateSignature, enclosingDeclaration, checker)];
196817
196901
  const documentation = candidateSignature.getDocumentationComment(checker);
196818
196902
  const tags = candidateSignature.getJsDocTags();
@@ -198899,11 +198983,11 @@ ${options.prefix}` : "\n" : options.prefix
198899
198983
  const noIndent = options.indentation !== void 0 || getLineStartPositionForPosition(pos, targetSourceFile) === pos ? text : text.replace(/^\s+/, "");
198900
198984
  return (options.prefix || "") + noIndent + (!options.suffix || endsWith(noIndent, options.suffix) ? "" : options.suffix);
198901
198985
  }
198902
- function getFormattedTextOfNode(nodeIn, targetSourceFile, sourceFile, pos, { indentation, prefix: prefix2, delta }, newLineCharacter, formatContext, validate) {
198986
+ function getFormattedTextOfNode(nodeIn, targetSourceFile, sourceFile, pos, { indentation, prefix, delta }, newLineCharacter, formatContext, validate) {
198903
198987
  const { node, text } = getNonformattedText(nodeIn, targetSourceFile, newLineCharacter);
198904
198988
  if (validate) validate(node, text);
198905
198989
  const formatOptions = getFormatCodeSettingsForWriting(formatContext, targetSourceFile);
198906
- const initialIndentation = indentation !== void 0 ? indentation : ts_formatting_exports.SmartIndenter.getIndentation(pos, sourceFile, formatOptions, prefix2 === newLineCharacter || getLineStartPositionForPosition(pos, targetSourceFile) === pos);
198990
+ const initialIndentation = indentation !== void 0 ? indentation : ts_formatting_exports.SmartIndenter.getIndentation(pos, sourceFile, formatOptions, prefix === newLineCharacter || getLineStartPositionForPosition(pos, targetSourceFile) === pos);
198907
198991
  if (delta === void 0) {
198908
198992
  delta = ts_formatting_exports.SmartIndenter.shouldIndentChildNode(formatOptions, nodeIn) ? formatOptions.indentSize || 0 : 0;
198909
198993
  }
@@ -216628,9 +216712,9 @@ Project '${project.projectName}' (${ProjectKind[project.projectKind]}) ${counter
216628
216712
  );
216629
216713
  if (completions === void 0) return void 0;
216630
216714
  if (kind === "completions-full") return completions;
216631
- const prefix2 = args.prefix || "";
216715
+ const prefix = args.prefix || "";
216632
216716
  const entries = mapDefined(completions.entries, (entry) => {
216633
- if (completions.isMemberCompletion || startsWith(entry.name.toLowerCase(), prefix2.toLowerCase())) {
216717
+ if (completions.isMemberCompletion || startsWith(entry.name.toLowerCase(), prefix.toLowerCase())) {
216634
216718
  const convertedSpan = entry.replacementSpan ? toProtocolTextSpan(entry.replacementSpan, scriptInfo) : void 0;
216635
216719
  return {
216636
216720
  ...entry,
@@ -221575,15 +221659,15 @@ var require_to_regex_range = __commonJS({
221575
221659
  }
221576
221660
  return tokens;
221577
221661
  }
221578
- function filterPatterns(arr, comparison, prefix2, intersection, options) {
221662
+ function filterPatterns(arr, comparison, prefix, intersection, options) {
221579
221663
  let result = [];
221580
221664
  for (let ele of arr) {
221581
221665
  let { string } = ele;
221582
221666
  if (!intersection && !contains(comparison, "string", string)) {
221583
- result.push(prefix2 + string);
221667
+ result.push(prefix + string);
221584
221668
  }
221585
221669
  if (intersection && contains(comparison, "string", string)) {
221586
- result.push(prefix2 + string);
221670
+ result.push(prefix + string);
221587
221671
  }
221588
221672
  }
221589
221673
  return result;
@@ -221694,7 +221778,7 @@ var require_fill_range = __commonJS({
221694
221778
  var toSequence = (parts, options, maxLen) => {
221695
221779
  parts.negatives.sort((a, b4) => a < b4 ? -1 : a > b4 ? 1 : 0);
221696
221780
  parts.positives.sort((a, b4) => a < b4 ? -1 : a > b4 ? 1 : 0);
221697
- let prefix2 = options.capture ? "" : "?:";
221781
+ let prefix = options.capture ? "" : "?:";
221698
221782
  let positives = "";
221699
221783
  let negatives = "";
221700
221784
  let result;
@@ -221702,7 +221786,7 @@ var require_fill_range = __commonJS({
221702
221786
  positives = parts.positives.map((v2) => toMaxLen(String(v2), maxLen)).join("|");
221703
221787
  }
221704
221788
  if (parts.negatives.length) {
221705
- negatives = `-(${prefix2}${parts.negatives.map((v2) => toMaxLen(String(v2), maxLen)).join("|")})`;
221789
+ negatives = `-(${prefix}${parts.negatives.map((v2) => toMaxLen(String(v2), maxLen)).join("|")})`;
221706
221790
  }
221707
221791
  if (positives && negatives) {
221708
221792
  result = `${positives}|${negatives}`;
@@ -221710,7 +221794,7 @@ var require_fill_range = __commonJS({
221710
221794
  result = positives || negatives;
221711
221795
  }
221712
221796
  if (options.wrap) {
221713
- return `(${prefix2}${result})`;
221797
+ return `(${prefix}${result})`;
221714
221798
  }
221715
221799
  return result;
221716
221800
  };
@@ -221726,8 +221810,8 @@ var require_fill_range = __commonJS({
221726
221810
  var toRegex = (start, end, options) => {
221727
221811
  if (Array.isArray(start)) {
221728
221812
  let wrap = options.wrap === true;
221729
- let prefix2 = options.capture ? "" : "?:";
221730
- return wrap ? `(${prefix2}${start.join("|")})` : start.join("|");
221813
+ let prefix = options.capture ? "" : "?:";
221814
+ return wrap ? `(${prefix}${start.join("|")})` : start.join("|");
221731
221815
  }
221732
221816
  return toRegexRange(start, end, options);
221733
221817
  };
@@ -221849,20 +221933,20 @@ var require_compile = __commonJS({
221849
221933
  const invalidBlock = utils.isInvalidBrace(parent);
221850
221934
  const invalidNode = node.invalid === true && options.escapeInvalid === true;
221851
221935
  const invalid = invalidBlock === true || invalidNode === true;
221852
- const prefix2 = options.escapeInvalid === true ? "\\" : "";
221936
+ const prefix = options.escapeInvalid === true ? "\\" : "";
221853
221937
  let output = "";
221854
221938
  if (node.isOpen === true) {
221855
- return prefix2 + node.value;
221939
+ return prefix + node.value;
221856
221940
  }
221857
221941
  if (node.isClose === true) {
221858
- console.log("node.isClose", prefix2, node.value);
221859
- return prefix2 + node.value;
221942
+ console.log("node.isClose", prefix, node.value);
221943
+ return prefix + node.value;
221860
221944
  }
221861
221945
  if (node.type === "open") {
221862
- return invalid ? prefix2 + node.value : "(";
221946
+ return invalid ? prefix + node.value : "(";
221863
221947
  }
221864
221948
  if (node.type === "close") {
221865
- return invalid ? prefix2 + node.value : ")";
221949
+ return invalid ? prefix + node.value : ")";
221866
221950
  }
221867
221951
  if (node.type === "comma") {
221868
221952
  return node.prev.type === "comma" ? "" : invalid ? node.value : "|";
@@ -222898,10 +222982,10 @@ var require_scan = __commonJS({
222898
222982
  isGlob = false;
222899
222983
  }
222900
222984
  let base = str;
222901
- let prefix2 = "";
222985
+ let prefix = "";
222902
222986
  let glob = "";
222903
222987
  if (start > 0) {
222904
- prefix2 = str.slice(0, start);
222988
+ prefix = str.slice(0, start);
222905
222989
  str = str.slice(start);
222906
222990
  lastIndex -= start;
222907
222991
  }
@@ -222926,7 +223010,7 @@ var require_scan = __commonJS({
222926
223010
  }
222927
223011
  }
222928
223012
  const state = {
222929
- prefix: prefix2,
223013
+ prefix,
222930
223014
  input,
222931
223015
  start,
222932
223016
  base,
@@ -222955,7 +223039,7 @@ var require_scan = __commonJS({
222955
223039
  if (opts.tokens) {
222956
223040
  if (idx === 0 && start !== 0) {
222957
223041
  tokens[idx].isPrefix = true;
222958
- tokens[idx].value = prefix2;
223042
+ tokens[idx].value = prefix;
222959
223043
  } else {
222960
223044
  tokens[idx].value = value;
222961
223045
  }
@@ -227173,8 +227257,8 @@ ${nodeLocation}` : message2;
227173
227257
  errors.ArgumentTypeError = ArgumentTypeError;
227174
227258
  class PathNotFoundError extends BaseError {
227175
227259
  path;
227176
- constructor(path2, prefix2 = "Path") {
227177
- super(`${prefix2} not found: ${path2}`);
227260
+ constructor(path2, prefix = "Path") {
227261
+ super(`${prefix} not found: ${path2}`);
227178
227262
  this.path = path2;
227179
227263
  }
227180
227264
  code = "ENOENT";
@@ -283492,32 +283576,26 @@ function parseDevArgs(argv) {
283492
283576
  url,
283493
283577
  apiKey: process.env.ABLO_API_KEY,
283494
283578
  watch: watchEnabled,
283495
- planeLabel: "sandbox"
283579
+ planeLabel: "branch"
283496
283580
  };
283497
283581
  }
283498
283582
  function classifyKey(apiKey) {
283499
283583
  if (!apiKey) {
283500
283584
  return {
283501
283585
  ok: false,
283502
- reason: `No API key. Run ${import_picocolors15.default.bold("npx ablo login")}, or set ${import_picocolors15.default.bold("ABLO_API_KEY")}: ${import_picocolors15.default.bold("sk_test_")} runs the ${import_picocolors15.default.bold("npx ablo dev")} watch loop, ${import_picocolors15.default.bold("sk_live_")} deploys production with ${import_picocolors15.default.bold("npx ablo push")}.`
283503
- };
283504
- }
283505
- if (apiKey.startsWith("sk_test_")) return { ok: true };
283506
- if (apiKey.startsWith("sk_live_")) {
283507
- return {
283508
- ok: false,
283509
- reason: `A ${import_picocolors15.default.bold("sk_live_")} key deploys production schema in one reviewed step: ${import_picocolors15.default.bold("npx ablo push")}. The ${import_picocolors15.default.bold("--watch")} loop runs on a ${import_picocolors15.default.bold("sk_test_")} key, which reaches the same API and the same schema over its own rows.`
283586
+ reason: `No API key. Run ${import_picocolors15.default.bold("npx ablo login")}, or set a branch-bound ${import_picocolors15.default.bold("ABLO_API_KEY")}. ${import_picocolors15.default.bold("npx ablo dev")} prepares a development branch.`
283510
283587
  };
283511
283588
  }
283589
+ if ((0, import_credentialPolicy2.classifyCredentialKind)(apiKey) === "secret") return { ok: true };
283512
283590
  if ((0, import_credentialPolicy2.classifyCredentialKind)(apiKey) === "restricted") {
283513
283591
  return {
283514
283592
  ok: false,
283515
- reason: `Authoring schema needs a secret key. ${import_picocolors15.default.bold("sk_test_")} runs the ${import_picocolors15.default.bold("npx ablo dev")} watch loop, ${import_picocolors15.default.bold("sk_live_")} deploys production with ${import_picocolors15.default.bold("npx ablo push")}. A restricted ${import_picocolors15.default.bold("rk_")} key carries only the scopes it was minted with.`
283593
+ reason: `Authoring schema needs a branch-bound secret ${import_picocolors15.default.bold("sk_")} key. ${import_picocolors15.default.bold("npx ablo dev")} prepares a development branch. A restricted ${import_picocolors15.default.bold("rk_")} key carries only the scopes it was minted with.`
283516
283594
  };
283517
283595
  }
283518
283596
  return {
283519
283597
  ok: false,
283520
- reason: `${import_picocolors15.default.bold("ABLO_API_KEY")} is not an Ablo key. Expected ${import_picocolors15.default.bold("sk_test_\u2026")} for the ${import_picocolors15.default.bold("npx ablo dev")} watch loop, or ${import_picocolors15.default.bold("sk_live_\u2026")} for a production deploy with ${import_picocolors15.default.bold("npx ablo push")}.`
283598
+ reason: `${import_picocolors15.default.bold("ABLO_API_KEY")} is not a secret Ablo key. Expected a branch-bound ${import_picocolors15.default.bold("sk_\u2026")} credential. Run ${import_picocolors15.default.bold("npx ablo dev")} to prepare a development branch.`
283521
283599
  };
283522
283600
  }
283523
283601
  function wireEnvLocal(apiKey, cwd = process.cwd()) {
@@ -283612,7 +283690,7 @@ async function runPush(schema, args) {
283612
283690
  }
283613
283691
  if (status2 === 403) {
283614
283692
  const serverSays = body.message ?? body.reason;
283615
- const hint = body.code === "database_role_cannot_enforce_rls" ? `Run ${import_picocolors15.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_picocolors15.default.bold("sandbox")} key with ${import_picocolors15.default.bold("schema:push")} \u2014 manage keys at ${import_picocolors15.default.cyan("https://abloatai.com")}.`;
283693
+ const hint = body.code === "database_role_cannot_enforce_rls" ? `Run ${import_picocolors15.default.bold("npx ablo migrate")} \u2014 it creates the scoped role for you (your DB credential never leaves this machine).` : `Schema authoring needs a branch-bound ${import_picocolors15.default.bold("sk_")} key with ${import_picocolors15.default.bold("schema:push")} \u2014 manage keys at ${import_picocolors15.default.cyan("https://abloatai.com")}.`;
283616
283694
  return {
283617
283695
  ok: false,
283618
283696
  message: `${serverSays ?? "This key can't author schema (missing schema:push scope)."}
@@ -283638,7 +283716,7 @@ async function dev(argv, runtime = {}) {
283638
283716
  process.exit(1);
283639
283717
  }
283640
283718
  if (runtime.apiKey) args.apiKey = runtime.apiKey;
283641
- else if (!args.apiKey) args.apiKey = resolveEffectiveApiKey("sandbox").key;
283719
+ else if (!args.apiKey) args.apiKey = resolveRuntimeApiKey("sandbox").key;
283642
283720
  if (runtime.branch) args.planeLabel = runtime.branch.slug;
283643
283721
  const key = classifyKey(args.apiKey);
283644
283722
  if (!key.ok) {
@@ -283667,7 +283745,7 @@ async function dev(argv, runtime = {}) {
283667
283745
  console.log(` ${import_picocolors15.default.dim("api")} ${args.url}
283668
283746
  `);
283669
283747
  const s = Y2();
283670
- s.start("Pushing schema definition (sandbox)");
283748
+ s.start("Pushing schema definition (development branch)");
283671
283749
  const first = await runPush(schema, args);
283672
283750
  s.stop(first.message, first.ok ? 0 : 1);
283673
283751
  if (!first.ok) process.exit(1);
@@ -283692,7 +283770,7 @@ async function dev(argv, runtime = {}) {
283692
283770
  ${import_picocolors15.default.green("\u2713")} ${wireEnvLocal(args.apiKey)}`);
283693
283771
  console.log(` ${import_picocolors15.default.dim("Frameworks load it automatically; plain Node: node --env-file=.env.local app.ts")}`);
283694
283772
  }
283695
- console.log(` Your app is wired for ${runtime.branch ? `branch ${runtime.branch.slug}` : "the sandbox"}.`);
283773
+ console.log(` Your app is wired for ${runtime.branch ? `branch ${runtime.branch.slug}` : "this branch"}.`);
283696
283774
  if (!args.watch) return;
283697
283775
  const abs = (0, import_path5.resolve)(process.cwd(), args.schemaPath);
283698
283776
  console.log(` ${import_picocolors15.default.dim(`watching ${args.schemaPath} \u2026 (Ctrl-C to stop)`)}
@@ -283864,9 +283942,9 @@ init_controlPlane();
283864
283942
  // src/credentialCapability.ts
283865
283943
  init_cjs_shims();
283866
283944
  var import_credentialPolicy3 = require("@abloatai/transaction/auth/credentialPolicy");
283867
- init_config();
283868
283945
  function secretCounterpart(key) {
283869
- return modeFromKey(key) === "production" ? "sk_live_" : "sk_test_";
283946
+ void key;
283947
+ return "sk_";
283870
283948
  }
283871
283949
  function credentialCapability(key) {
283872
283950
  const kind = key ? (0, import_credentialPolicy3.classifyCredentialKind)(key) : null;
@@ -283879,7 +283957,7 @@ function credentialCapability(key) {
283879
283957
  return {
283880
283958
  kind,
283881
283959
  label: "scoped",
283882
- note: `A scoped key does exactly what it was minted for. The production key \`ablo login\` stores is for observing your live plane with \`ablo status\` and \`ablo logs\`; authoring schema there takes a secret ${secret} key from the dashboard.`
283960
+ note: `A scoped key does exactly what it was minted for. Authoring schema requires a branch-bound secret ${secret} key with schema:push.`
283883
283961
  };
283884
283962
  case "publishable":
283885
283963
  return {
@@ -283984,12 +284062,13 @@ function selectWhoamiCredential(args, cwd = process.cwd()) {
283984
284062
  targetSource: "env"
283985
284063
  };
283986
284064
  }
283987
- const dataKey = resolveApiKey();
284065
+ const runtimeKey = resolveRuntimeApiKey();
284066
+ const dataKey = runtimeKey.key;
283988
284067
  if (dataKey) {
283989
284068
  return {
283990
284069
  key: dataKey,
283991
- source: process.env.ABLO_API_KEY ? "env:ABLO_API_KEY" : "stored data key",
283992
- targetSource: process.env.ABLO_API_KEY ? "env" : "stored"
284070
+ source: runtimeKey.source === "stored" ? "stored data key" : `${runtimeKey.source ?? "env"}:ABLO_API_KEY`,
284071
+ targetSource: runtimeKey.source ?? "stored"
283993
284072
  };
283994
284073
  }
283995
284074
  const managementKey = resolveManagementKey();
@@ -284072,6 +284151,7 @@ async function whoami(argv) {
284072
284151
  }
284073
284152
 
284074
284153
  // src/commands.ts
284154
+ init_push();
284075
284155
  var CORE_GROUPS = ["Start", "Every day", "More"];
284076
284156
  var FULL_GROUPS = [
284077
284157
  "Set up",
@@ -284170,6 +284250,7 @@ var COMMANDS = [
284170
284250
  },
284171
284251
  {
284172
284252
  name: "push",
284253
+ usage: PUSH_USAGE,
284173
284254
  core: { group: "Every day", does: "Upload your schema \u2014 schema only; your rows stay in your database" },
284174
284255
  full: {
284175
284256
  group: "Your schema",
@@ -284261,7 +284342,7 @@ var COMMANDS = [
284261
284342
  { run: "branch check [id|slug]", does: "CI alias for branch status" },
284262
284343
  { run: "branch create <slug>", does: "Create a child of the production root" },
284263
284344
  { run: "branch ensure <slug> --credential", does: "Resolve a branch and mint its expiring CI key" },
284264
- { run: "branch credential <id>", does: "Mint an expiring branch-bound test key" },
284345
+ { run: "branch credential <id>", does: "Mint an expiring branch-bound runtime key" },
284265
284346
  { run: "branch delete <id>", does: "Delete a non-root branch" }
284266
284347
  ]
284267
284348
  }
@@ -284701,16 +284782,14 @@ async function status(args = []) {
284701
284782
  const apiUrl3 = apiBaseUrl();
284702
284783
  const cfg = readConfig();
284703
284784
  const mode = getMode();
284704
- const effective = resolveEffectiveApiKey();
284705
- const target = effective.key ? await resolveTarget({ url: apiUrl3, apiKey: effective.key, keySource: effective.source ?? "stored" }) : null;
284785
+ const runtimeKey = resolveRuntimeApiKey();
284786
+ const target = runtimeKey.key ? await resolveTarget({ url: apiUrl3, apiKey: runtimeKey.key, keySource: runtimeKey.source ?? "stored" }) : null;
284706
284787
  if (args.includes("--json")) {
284707
284788
  const entry = getKeyEntry(mode);
284708
- const key2 = describeEffectiveKey(mode, process.env.ABLO_API_KEY, entry);
284709
- const plan2 = resolvePushPlan();
284710
284789
  const activeProject2 = getActiveProject();
284711
- const pushed2 = await fetchPushedSchema(apiUrl3, effective.key);
284790
+ const pushed2 = await fetchPushedSchema(apiUrl3, runtimeKey.key);
284712
284791
  const reachableForJson = await ping(apiUrl3);
284713
- const dataSource2 = reachableForJson ? (await fetchRoutingState(apiUrl3, effective.key)).source : { kind: "unknown", detail: "unreachable" };
284792
+ const dataSource2 = reachableForJson ? (await fetchRoutingState(apiUrl3, runtimeKey.key)).source : { kind: "unknown", detail: "unreachable" };
284714
284793
  const driftForJson = schemaDrift(await readLocalSchemaHash(), pushed2?.hash);
284715
284794
  const out = {
284716
284795
  // The locally-active project (`ablo projects use`); null = org-default.
@@ -284718,28 +284797,20 @@ async function status(args = []) {
284718
284797
  // The credential the CLI resolves for requests, with its source —
284719
284798
  // 'env' | '.env.local' | '.env' | 'stored'. Key confusion is a common
284720
284799
  // source of trouble, and the source is usually the answer.
284721
- effectiveKey: {
284722
- prefix: effective.key ? effective.key.slice(0, 12) : null,
284723
- source: effective.source,
284800
+ runtimeKey: {
284801
+ prefix: runtimeKey.key ? runtimeKey.key.slice(0, 12) : null,
284802
+ source: runtimeKey.source,
284724
284803
  // What this credential can do. A pipeline that pushes can read it before
284725
284804
  // running the push, rather than learning from the 403 — the same fact
284726
284805
  // the human output prints, from the same place.
284727
- kind: credentialCapability(effective.key).kind
284806
+ kind: credentialCapability(runtimeKey.key).kind
284728
284807
  },
284729
- keyPrefix: key2.keyPrefix,
284730
- keySource: key2.keySource,
284731
- keyMode: key2.keyMode,
284732
- storedKeyPrefix: key2.storedKeyPrefix,
284733
- keyMatchesActiveMode: key2.keyMatchesActiveMode,
284734
- keyMatchesStoredActiveKey: key2.keyMatchesStoredActiveKey,
284735
- keyMismatch: key2.keyMismatch,
284736
284808
  organizationId: entry?.organizationId ?? null,
284737
284809
  // The SERVER-CONFIRMED plane this key resolves to — the authoritative
284738
284810
  // answer to "where does a push land", independent of the local
284739
284811
  // project preference above. Null when the server didn't answer.
284740
284812
  confirmedTarget: target?.confirmed ? {
284741
284813
  organizationId: target.confirmed.organizationId,
284742
- environment: target.confirmed.environment,
284743
284814
  project: target.confirmed.project,
284744
284815
  projectId: target.confirmed.projectId,
284745
284816
  branchId: target.confirmed.branchId,
@@ -284747,14 +284818,7 @@ async function status(args = []) {
284747
284818
  } : null,
284748
284819
  // Divergence between local project intent and the confirmed target.
284749
284820
  mismatches: target?.mismatches ?? [],
284750
- // What `ablo push` would do right now — the answer to "why did push
284751
- // demand a different key".
284752
- push: {
284753
- flow: plan2.flow,
284754
- keyPrefix: plan2.apiKey?.slice(0, 12) ?? null,
284755
- keySource: plan2.source
284756
- },
284757
- // The schema active for this key's environment — the typename and conflict
284821
+ // The schema active for this key's branch — the typename and conflict
284758
284822
  // rules the engine enforces, which may differ from your local `schema.ts`.
284759
284823
  // null means the server did not answer (unreachable, too old, or no key).
284760
284824
  schema: pushed2 ? {
@@ -284774,7 +284838,7 @@ async function status(args = []) {
284774
284838
  drift: driftForJson,
284775
284839
  blockers: blockers({
284776
284840
  reachable: reachableForJson,
284777
- hasKey: Boolean(effective.key),
284841
+ hasKey: Boolean(runtimeKey.key),
284778
284842
  dataSource: dataSource2,
284779
284843
  schemaPushed: Boolean(pushed2?.active),
284780
284844
  drift: driftForJson
@@ -284786,19 +284850,15 @@ async function status(args = []) {
284786
284850
  console.log(`
284787
284851
  ${brand("ablo")} ${import_picocolors19.default.dim("status")}
284788
284852
  `);
284789
- if (effective.key && effective.source && effective.source !== "stored") {
284790
- const label = effective.source === "env" ? "ABLO_API_KEY env" : effective.source;
284853
+ if (runtimeKey.key && runtimeKey.source && runtimeKey.source !== "stored") {
284854
+ const label = runtimeKey.source === "env" ? "ABLO_API_KEY env" : runtimeKey.source;
284791
284855
  console.log(
284792
- ` ${import_picocolors19.default.dim("key")} ${effective.key.slice(0, 12)}\u2026 ${import_picocolors19.default.dim(`(${label} \u2014 overrides stored)`)}`
284856
+ ` ${import_picocolors19.default.dim("key")} ${runtimeKey.key.slice(0, 12)}\u2026 ${import_picocolors19.default.dim(`(${label} \u2014 overrides stored)`)}`
284793
284857
  );
284794
284858
  } else if (!cfg) {
284795
284859
  console.log(` ${import_picocolors19.default.yellow("!")} Not logged in \u2014 run ${import_picocolors19.default.bold("ablo login")}.`);
284796
284860
  }
284797
284861
  const activeEntry = getKeyEntry(mode);
284798
- const key = describeEffectiveKey(mode, process.env.ABLO_API_KEY, activeEntry);
284799
- if (key.keyMismatch) {
284800
- console.log(` ${import_picocolors19.default.yellow(`! ${key.keyMismatch.message}`)}`);
284801
- }
284802
284862
  const activeProject = getActiveProject();
284803
284863
  printTargetLines(
284804
284864
  target,
@@ -284806,9 +284866,13 @@ async function status(args = []) {
284806
284866
  activeEntry?.organizationId,
284807
284867
  activeEntry?.organizationSlug
284808
284868
  );
284869
+ const management = getManagementKeyEntry();
284870
+ console.log(
284871
+ ` ${import_picocolors19.default.dim("\u25CB")} ${"management".padEnd(12)} ${management ? import_picocolors19.default.dim(`${management.apiKey.slice(0, 12)}\u2026${management.expiresAt ? ` \xB7 ${expiryLabel(management.expiresAt)}` : ""}`) : import_picocolors19.default.dim("\u2014 no key")}`
284872
+ );
284809
284873
  for (const { key: m2, label } of [
284810
- { key: "sandbox", label: "management" },
284811
- { key: "production", label: "observer" }
284874
+ { key: "sandbox", label: "legacy child" },
284875
+ { key: "production", label: "legacy root" }
284812
284876
  ]) {
284813
284877
  const entry = getKeyEntry(m2);
284814
284878
  if (entry) {
@@ -284818,22 +284882,20 @@ async function status(args = []) {
284818
284882
  ].filter(Boolean);
284819
284883
  const trail = facts.length ? ` ${import_picocolors19.default.dim("\xB7")} ${facts.join(import_picocolors19.default.dim(" \xB7 "))}` : "";
284820
284884
  console.log(
284821
- ` ${import_picocolors19.default.dim("\u25CB")} ${label.padEnd(10)} ${import_picocolors19.default.dim(`${entry.apiKey.slice(0, 12)}\u2026`)}${trail}`
284885
+ ` ${import_picocolors19.default.dim("\u25CB")} ${label.padEnd(12)} ${import_picocolors19.default.dim(`${entry.apiKey.slice(0, 12)}\u2026`)}${trail}`
284822
284886
  );
284823
- } else {
284824
- console.log(` ${import_picocolors19.default.dim("\u25CB")} ${label.padEnd(10)} ${import_picocolors19.default.dim("\u2014 no key")}`);
284825
284887
  }
284826
284888
  }
284827
- const plan = resolvePushPlan();
284889
+ const pushBranch = target?.confirmed?.branchRoot === true ? "production root" : target?.confirmed?.branchId ? `branch ${target.confirmed.branchId}` : runtimeKey.key ? "unknown branch" : "no branch";
284828
284890
  console.log(
284829
- ` ${import_picocolors19.default.dim("push")} ${plan.apiKey ? `${import_picocolors19.default.bold(plan.flow)} ${import_picocolors19.default.dim(`with ${plan.apiKey.slice(0, 12)}\u2026 (${plan.source})`)}` : `${import_picocolors19.default.bold(plan.flow)} ${import_picocolors19.default.yellow("\u2014 no credential")} ${import_picocolors19.default.dim(`(run ${import_picocolors19.default.bold("ablo login")} or set ${import_picocolors19.default.bold("ABLO_API_KEY")})`)}`}`
284891
+ ` ${import_picocolors19.default.dim("push")} ${runtimeKey.key ? `${import_picocolors19.default.bold(pushBranch)} ${import_picocolors19.default.dim(`with ${runtimeKey.key.slice(0, 12)}\u2026 (${runtimeKey.source})`)}` : `${import_picocolors19.default.bold(pushBranch)} ${import_picocolors19.default.yellow("\u2014 no runtime key")} ${import_picocolors19.default.dim(`(set ${import_picocolors19.default.bold("ABLO_API_KEY")} or run ${import_picocolors19.default.bold("ablo dev")})`)}`}`
284830
284892
  );
284831
- const capability = credentialCapability(effective.key);
284893
+ const capability = credentialCapability(runtimeKey.key);
284832
284894
  if (capability.note) console.log(` ${import_picocolors19.default.dim(capability.note)}`);
284833
284895
  process.stdout.write(` ${import_picocolors19.default.dim("api")} ${apiUrl3} `);
284834
284896
  const reachable = await ping(apiUrl3);
284835
284897
  console.log(reachable ? import_picocolors19.default.green("reachable") : import_picocolors19.default.red("unreachable"));
284836
- const introspectKey = effective.key;
284898
+ const introspectKey = runtimeKey.key;
284837
284899
  const { source: dataSource, validation } = reachable ? await fetchRoutingState(apiUrl3, introspectKey) : { source: { kind: "unknown", detail: "unreachable" }, validation: null };
284838
284900
  if (dataSource.kind === "connected") {
284839
284901
  const how = [...new Set(dataSource.connections)].join(" + ");
@@ -284882,7 +284944,7 @@ async function status(args = []) {
284882
284944
  }
284883
284945
  const found = blockers({
284884
284946
  reachable,
284885
- hasKey: Boolean(effective.key),
284947
+ hasKey: Boolean(runtimeKey.key),
284886
284948
  dataSource,
284887
284949
  schemaPushed: Boolean(pushed?.active),
284888
284950
  drift
@@ -284936,13 +284998,13 @@ async function doctor() {
284936
284998
  ${brand("ablo")} ${import_picocolors20.default.dim("doctor")}
284937
284999
  `);
284938
285000
  const apiUrl3 = apiBaseUrl();
284939
- const effective = resolveEffectiveApiKey();
285001
+ const runtimeKey = resolveRuntimeApiKey();
284940
285002
  const checks = [];
284941
- if (effective.key) {
285003
+ if (runtimeKey.key) {
284942
285004
  checks.push({
284943
285005
  label: "key",
284944
285006
  state: "ok",
284945
- detail: `${effective.key.slice(0, 12)}\u2026 from ${effective.source}`
285007
+ detail: `${runtimeKey.key.slice(0, 12)}\u2026 from ${runtimeKey.source}`
284946
285008
  });
284947
285009
  } else {
284948
285010
  checks.push({
@@ -284961,7 +285023,7 @@ async function doctor() {
284961
285023
  fix: "check your connection, then re-run `ablo doctor`"
284962
285024
  }
284963
285025
  );
284964
- const target = effective.key ? await resolveTarget({ url: apiUrl3, apiKey: effective.key, keySource: effective.source ?? "stored" }) : null;
285026
+ const target = runtimeKey.key ? await resolveTarget({ url: apiUrl3, apiKey: runtimeKey.key, keySource: runtimeKey.source ?? "stored" }) : null;
284965
285027
  const confirmed = target?.confirmed ?? null;
284966
285028
  if (confirmed) {
284967
285029
  const project = confirmed.project ? confirmed.project.isDefault ? "default" : confirmed.project.name === null ? `${confirmed.project.id} (unnamed \u2014 ${confirmed.project.unnamedReason ?? "the project list did not answer"})` : `${confirmed.project.slug} (${confirmed.project.id})` : "default";
@@ -284974,12 +285036,12 @@ async function doctor() {
284974
285036
  const local = getActiveProject();
284975
285037
  checks.push({
284976
285038
  label: "identity",
284977
- state: effective.key && reachable ? "fail" : "skip",
284978
- detail: effective.key ? `the server did not resolve this key${local ? ` (locally selected: ${local.slug})` : ""}` : "no key to resolve",
284979
- fix: effective.key ? "check the key is valid and not expired \u2014 `ablo login` mints a fresh pair" : void 0
285039
+ state: runtimeKey.key && reachable ? "fail" : "skip",
285040
+ detail: runtimeKey.key ? `the server did not resolve this key${local ? ` (locally selected: ${local.slug})` : ""}` : "no key to resolve",
285041
+ fix: runtimeKey.key ? "check the key is valid and not expired \u2014 `ablo login` mints a fresh pair" : void 0
284980
285042
  });
284981
285043
  }
284982
- const { source: dataSource, validation } = reachable ? await fetchRoutingState(apiUrl3, effective.key) : { source: { kind: "unknown", detail: "unreachable" }, validation: null };
285044
+ const { source: dataSource, validation } = reachable ? await fetchRoutingState(apiUrl3, runtimeKey.key) : { source: { kind: "unknown", detail: "unreachable" }, validation: null };
284983
285045
  if (dataSource.kind === "connected") {
284984
285046
  const how = [...new Set(dataSource.connections)].join(" + ");
284985
285047
  const pooled = detectPoolerIn(dataSource.hosts);
@@ -285001,13 +285063,13 @@ async function doctor() {
285001
285063
  } else {
285002
285064
  checks.push({ label: "data", state: "skip", detail: `not determined (${dataSource.detail})` });
285003
285065
  }
285004
- const pushed = reachable ? await fetchPushedSchema(apiUrl3, effective.key) : null;
285066
+ const pushed = reachable ? await fetchPushedSchema(apiUrl3, runtimeKey.key) : null;
285005
285067
  checks.push(
285006
285068
  pushed?.active ? {
285007
285069
  label: "schema",
285008
285070
  state: "ok",
285009
285071
  detail: `${pushed.models.length} models active${pushed.hash ? `, hash ${pushed.hash}` : ""}`
285010
- } : reachable && effective.key ? { label: "schema", state: "fail", detail: "none active for this key", fix: "run `ablo push`" } : { label: "schema", state: "skip", detail: "not determined" }
285072
+ } : reachable && runtimeKey.key ? { label: "schema", state: "fail", detail: "none active for this key", fix: "run `ablo push`" } : { label: "schema", state: "skip", detail: "not determined" }
285011
285073
  );
285012
285074
  const drift = schemaDrift(await readLocalSchemaHash(), pushed?.hash);
285013
285075
  if (drift) {
@@ -285038,7 +285100,7 @@ async function doctor() {
285038
285100
  for (const check2 of checks) render(check2);
285039
285101
  const blocking = blockers({
285040
285102
  reachable,
285041
- hasKey: Boolean(effective.key),
285103
+ hasKey: Boolean(runtimeKey.key),
285042
285104
  dataSource,
285043
285105
  schemaPushed: Boolean(pushed?.active),
285044
285106
  drift
@@ -285077,8 +285139,7 @@ function parseLogsArgs(argv) {
285077
285139
  since: void 0,
285078
285140
  model: void 0,
285079
285141
  op: void 0,
285080
- json: false,
285081
- mode: void 0
285142
+ json: false
285082
285143
  };
285083
285144
  for (let i = 0; i < argv.length; i++) {
285084
285145
  const arg = argv[i];
@@ -285106,13 +285167,11 @@ function parseLogsArgs(argv) {
285106
285167
  case "--json":
285107
285168
  args.json = true;
285108
285169
  break;
285109
- case "--mode": {
285110
- const raw = argv[++i];
285111
- const m2 = normalizeMode(raw);
285112
- if (!m2) throw new import_errors16.AbloValidationError(`--mode expects "sandbox" or "production", got "${raw}"`, { code: "cli_invalid_arguments" });
285113
- args.mode = m2;
285114
- break;
285115
- }
285170
+ case "--mode":
285171
+ throw new import_errors16.AbloValidationError(
285172
+ "--mode was removed. Logs follow the branch bound to ABLO_API_KEY; select a different branch by supplying its key.",
285173
+ { code: "cli_invalid_arguments" }
285174
+ );
285116
285175
  default:
285117
285176
  throw new import_errors16.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
285118
285177
  }
@@ -285156,7 +285215,7 @@ async function logs(argv) {
285156
285215
  console.error(import_picocolors21.default.red(` ${err instanceof Error ? err.message : String(err)}`));
285157
285216
  process.exit(1);
285158
285217
  }
285159
- const apiKey = resolveApiKey(args.mode);
285218
+ const apiKey = resolveRuntimeApiKey().key;
285160
285219
  if (!apiKey) {
285161
285220
  console.error(
285162
285221
  import_picocolors21.default.red(` No API key.`) + import_picocolors21.default.dim(` Run ${import_picocolors21.default.bold("ablo login")} or set ${import_picocolors21.default.bold("ABLO_API_KEY")}.`)
@@ -285184,7 +285243,7 @@ async function logs(argv) {
285184
285243
  }
285185
285244
  if (!args.json) {
285186
285245
  console.log(`
285187
- ${brand("ablo")} ${import_picocolors21.default.dim("logs")} ${import_picocolors21.default.dim(`(${args.mode ?? "active"} mode)`)}
285246
+ ${brand("ablo")} ${import_picocolors21.default.dim("logs")}
285188
285247
  `);
285189
285248
  }
285190
285249
  const initial = await fetchPage({
@@ -285250,7 +285309,7 @@ function positional(args) {
285250
285309
  return void 0;
285251
285310
  }
285252
285311
  function requireKey3(mode) {
285253
- const apiKey = resolveApiKey(mode);
285312
+ const apiKey = resolveMutationApiKey(mode);
285254
285313
  if (!apiKey) {
285255
285314
  console.error(
285256
285315
  import_picocolors22.default.red(" No API key.") + import_picocolors22.default.dim(` Run ${import_picocolors22.default.bold("ablo login")} or set ${import_picocolors22.default.bold("ABLO_API_KEY")}.`)
@@ -285258,7 +285317,7 @@ function requireKey3(mode) {
285258
285317
  process.exit(1);
285259
285318
  }
285260
285319
  if ((0, import_credentialPolicy4.classifyCredentialKind)(apiKey) !== "secret") {
285261
- console.error(import_picocolors22.default.red(" Managing webhooks requires a secret key ") + import_picocolors22.default.dim("(sk_test_ / sk_live_)."));
285320
+ console.error(import_picocolors22.default.red(" Managing webhooks requires a branch-bound secret key ") + import_picocolors22.default.dim("(sk_)."));
285262
285321
  process.exit(1);
285263
285322
  }
285264
285323
  return apiKey;
@@ -285556,8 +285615,8 @@ function hostOf(connectionString) {
285556
285615
  async function reportReadSubject(dbUrl) {
285557
285616
  const host = hostOf(dbUrl);
285558
285617
  console.log(` ${import_picocolors23.default.dim("reading")} ${import_picocolors23.default.bold(host ?? "your database")}`);
285559
- const effective = resolveEffectiveApiKey();
285560
- const state = await fetchDataSourceState(apiBaseUrl(), effective.key);
285618
+ const runtimeKey = resolveRuntimeApiKey();
285619
+ const state = await fetchDataSourceState(apiBaseUrl(), runtimeKey.key);
285561
285620
  if (state.kind === "unknown") {
285562
285621
  console.log(
285563
285622
  ` ${import_picocolors23.default.dim("ablo")} ${import_picocolors23.default.yellow("?")} ${import_picocolors23.default.dim(`couldn't ask which database Ablo reads (${state.detail})`)}
@@ -286580,27 +286639,7 @@ async function runPull(argv) {
286580
286639
  }
286581
286640
  async function runPush2(argv) {
286582
286641
  const rest = [...argv];
286583
- const advanced = rest.some(
286584
- (a) => ["--force", "--rename", "--backfill", "--url", "--dry-run", "--plan", "--yes", "-y", "--allow-dirty"].includes(a)
286585
- );
286586
- const watching = rest.includes("--watch");
286587
- const guard = guardActiveProjectKey();
286588
- if (!guard.ok && guard.available.length > 0 && !rest.includes("--url")) {
286589
- console.error(
286590
- ` ${import_picocolors28.default.yellow("\u26A0")} active project ${import_picocolors28.default.bold(guard.activeProfile)} has no stored key ${import_picocolors28.default.dim(
286591
- `(you have keys for: ${guard.available.join(", ")})`
286592
- )}`
286593
- );
286594
- const loginCmd = guard.activeProfile === "default" ? "ablo login" : `ablo login --project ${guard.activeProfile}`;
286595
- console.error(
286596
- import_picocolors28.default.dim(` Mint one with ${import_picocolors28.default.bold(loginCmd)}, or switch with ${import_picocolors28.default.bold("ablo projects use <slug>")}.`)
286597
- );
286598
- process.exitCode = 1;
286599
- return;
286600
- }
286601
- const plan = resolvePushPlan();
286602
- if (advanced || plan.flow === "production" && !watching) await push(rest);
286603
- else await dev(rest);
286642
+ await push(rest);
286604
286643
  }
286605
286644
  function runRenamedSchema(argv) {
286606
286645
  const forwarded = argv.slice(1).join(" ");
@@ -287029,7 +287068,7 @@ function generateEnv(storage, opts = {}) {
287029
287068
  const { includeApiKey = true } = opts;
287030
287069
  const databaseBlock = storage === "replication" ? "# Used by `npx ablo connect` to set up + register logical replication \u2014 the\n# DIRECT (un-pooled) endpoint. Ablo TAILS your WAL from here; it never writes.\n# The client never sees it; the browser never sees it. Your DB stays yours.\nDATABASE_URL=postgres://user:password@host:5432/db\n" : "# Used by ablo/data-source.ts (your DB endpoint) + `ablo migrate` \u2014 NOT the client.\n# Ablo never sees it; the browser never sees it. Your DB stays in your app.\nDATABASE_URL=postgres://user:password@host:5432/db\n";
287031
287070
  const webhookBlock = storage === "endpoint" ? "# Signing secret for the webhook receiver (app/api/ablo/webhooks/route.ts).\n# Ablo mints this when you register the endpoint's URL (POST /v1/webhook_endpoints\n# or the dashboard) and returns it once \u2014 paste it here.\nABLO_WEBHOOK_SECRET=whsec_your_endpoint_secret_here\n" : "";
287032
- const apiKeyBlock = includeApiKey ? "# Ablo: a sk_test_ key for local development (`npx ablo dev` wires this for you)\nABLO_API_KEY=sk_test_your_key_here\n" : "";
287071
+ const apiKeyBlock = includeApiKey ? "# Ablo: a branch-bound sk_ key (`npx ablo dev` wires a development branch for you)\nABLO_API_KEY=sk_your_key_here\n" : "";
287033
287072
  return `${apiKeyBlock}${webhookBlock}${databaseBlock}`;
287034
287073
  }
287035
287074
  function generateDataSource(orm) {
@@ -287105,8 +287144,8 @@ var WEBHOOK_DOC = `/**
287105
287144
  * signature, then write each change into YOUR database. The other half \u2014 your app
287106
287145
  * MAKING changes + live sync \u2014 is the Ablo client in \`ablo/index.ts\`.
287107
287146
  *
287108
- * Just like Stripe: you call Ablo to make changes (client) and Ablo calls you to
287109
- * persist them (this route). Reliability is built in \u2014 Ablo retries on any
287147
+ * Your app calls Ablo to make changes, and Ablo calls this route to persist
287148
+ * them. Reliability is built in \u2014 Ablo retries on any
287110
287149
  * non-2xx, and \`event.syncId\` is a monotonic log position, so apply in order and
287111
287150
  * dedupe (skip a \`syncId\` you've already stored).
287112
287151
  */`;