@abloatai/ablo 0.23.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -4850,8 +4850,8 @@ var require_typescript = __commonJS({
4850
4850
  let count = 0;
4851
4851
  if (array !== void 0) {
4852
4852
  for (let i = 0; i < array.length; i++) {
4853
- const v = array[i];
4854
- if (predicate(v, i)) {
4853
+ const v2 = array[i];
4854
+ if (predicate(v2, i)) {
4855
4855
  count++;
4856
4856
  }
4857
4857
  }
@@ -4926,12 +4926,12 @@ var require_typescript = __commonJS({
4926
4926
  function flatten(array) {
4927
4927
  const result = [];
4928
4928
  for (let i = 0; i < array.length; i++) {
4929
- const v = array[i];
4930
- if (v) {
4931
- if (isArray(v)) {
4932
- addRange(result, v);
4929
+ const v2 = array[i];
4930
+ if (v2) {
4931
+ if (isArray(v2)) {
4932
+ addRange(result, v2);
4933
4933
  } else {
4934
- result.push(v);
4934
+ result.push(v2);
4935
4935
  }
4936
4936
  }
4937
4937
  }
@@ -4941,12 +4941,12 @@ var require_typescript = __commonJS({
4941
4941
  let result;
4942
4942
  if (array !== void 0) {
4943
4943
  for (let i = 0; i < array.length; i++) {
4944
- const v = mapfn(array[i], i);
4945
- if (v) {
4946
- if (isArray(v)) {
4947
- result = addRange(result, v);
4944
+ const v2 = mapfn(array[i], i);
4945
+ if (v2) {
4946
+ if (isArray(v2)) {
4947
+ result = addRange(result, v2);
4948
4948
  } else {
4949
- result = append(result, v);
4949
+ result = append(result, v2);
4950
4950
  }
4951
4951
  }
4952
4952
  }
@@ -4957,12 +4957,12 @@ var require_typescript = __commonJS({
4957
4957
  const result = [];
4958
4958
  if (array !== void 0) {
4959
4959
  for (let i = 0; i < array.length; i++) {
4960
- const v = mapfn(array[i], i);
4961
- if (v) {
4962
- if (isArray(v)) {
4963
- addRange(result, v);
4960
+ const v2 = mapfn(array[i], i);
4961
+ if (v2) {
4962
+ if (isArray(v2)) {
4963
+ addRange(result, v2);
4964
4964
  } else {
4965
- result.push(v);
4965
+ result.push(v2);
4966
4966
  }
4967
4967
  }
4968
4968
  }
@@ -5066,9 +5066,9 @@ var require_typescript = __commonJS({
5066
5066
  pos++;
5067
5067
  }
5068
5068
  if (start < pos) {
5069
- const v = mapfn(array.slice(start, pos), previousKey, start, pos);
5070
- if (v) {
5071
- result.push(v);
5069
+ const v2 = mapfn(array.slice(start, pos), previousKey, start, pos);
5070
+ if (v2) {
5071
+ result.push(v2);
5072
5072
  }
5073
5073
  start = pos;
5074
5074
  }
@@ -5224,11 +5224,11 @@ var require_typescript = __commonJS({
5224
5224
  let result;
5225
5225
  if (array !== void 0) {
5226
5226
  for (let i = 0; i < array.length; i++) {
5227
- const v = array[i];
5228
- if (result ?? !v) {
5227
+ const v2 = array[i];
5228
+ if (result ?? !v2) {
5229
5229
  result ?? (result = array.slice(0, i));
5230
- if (v) {
5231
- result.push(v);
5230
+ if (v2) {
5231
+ result.push(v2);
5232
5232
  }
5233
5233
  }
5234
5234
  }
@@ -6055,11 +6055,11 @@ var require_typescript = __commonJS({
6055
6055
  let matchedValue;
6056
6056
  let longestMatchPrefixLength = -1;
6057
6057
  for (let i = 0; i < values2.length; i++) {
6058
- const v = values2[i];
6059
- const pattern = getPattern(v);
6058
+ const v2 = values2[i];
6059
+ const pattern = getPattern(v2);
6060
6060
  if (pattern.prefix.length > longestMatchPrefixLength && isPatternMatch(pattern, candidate)) {
6061
6061
  longestMatchPrefixLength = pattern.prefix.length;
6062
- matchedValue = v;
6062
+ matchedValue = v2;
6063
6063
  }
6064
6064
  }
6065
6065
  return matchedValue;
@@ -6323,8 +6323,8 @@ Node ${formatSyntaxKind(node.kind)} was unexpected.`,
6323
6323
  }
6324
6324
  Debug2.checkDefined = checkDefined;
6325
6325
  function assertEachIsDefined(value, message, stackCrawlMark) {
6326
- for (const v of value) {
6327
- assertIsDefined(v, message, stackCrawlMark || assertEachIsDefined);
6326
+ for (const v2 of value) {
6327
+ assertIsDefined(v2, message, stackCrawlMark || assertEachIsDefined);
6328
6328
  }
6329
6329
  }
6330
6330
  Debug2.assertEachIsDefined = assertEachIsDefined;
@@ -7695,7 +7695,7 @@ ${lanes.join("\n")}
7695
7695
  const meta = { cat: "__metadata", ph: "M", ts: 1e3 * timestamp(), pid: 1, tid: 1 };
7696
7696
  fs2.writeSync(
7697
7697
  traceFd,
7698
- "[\n" + [{ name: "process_name", args: { name: "tsc" }, ...meta }, { name: "thread_name", args: { name: "Main" }, ...meta }, { name: "TracingStartedInBrowser", ...meta, cat: "disabled-by-default-devtools.timeline" }].map((v) => JSON.stringify(v)).join(",\n")
7698
+ "[\n" + [{ name: "process_name", args: { name: "tsc" }, ...meta }, { name: "thread_name", args: { name: "Main" }, ...meta }, { name: "TracingStartedInBrowser", ...meta, cat: "disabled-by-default-devtools.timeline" }].map((v2) => JSON.stringify(v2)).join(",\n")
7699
7699
  );
7700
7700
  }
7701
7701
  tracingEnabled2.startTracing = startTracing2;
@@ -21820,8 +21820,8 @@ ${lanes.join("\n")}
21820
21820
  function getSingleInitializerOfVariableStatementOrPropertyDeclaration(node) {
21821
21821
  switch (node.kind) {
21822
21822
  case 243:
21823
- const v = getSingleVariableOfVariableStatement(node);
21824
- return v && v.initializer;
21823
+ const v2 = getSingleVariableOfVariableStatement(node);
21824
+ return v2 && v2.initializer;
21825
21825
  case 172:
21826
21826
  return node.initializer;
21827
21827
  case 303:
@@ -47572,14 +47572,14 @@ ${lanes.join("\n")}
47572
47572
  const values2 = value.split(",");
47573
47573
  switch (opt.element.type) {
47574
47574
  case "number":
47575
- return mapDefined(values2, (v) => validateJsonOptionValue(opt.element, parseInt(v), errors));
47575
+ return mapDefined(values2, (v2) => validateJsonOptionValue(opt.element, parseInt(v2), errors));
47576
47576
  case "string":
47577
- return mapDefined(values2, (v) => validateJsonOptionValue(opt.element, v || "", errors));
47577
+ return mapDefined(values2, (v2) => validateJsonOptionValue(opt.element, v2 || "", errors));
47578
47578
  case "boolean":
47579
47579
  case "object":
47580
47580
  return Debug.fail(`List of ${opt.element.type} is not yet supported.`);
47581
47581
  default:
47582
- return mapDefined(values2, (v) => parseCustomTypeOption(opt.element, v, errors));
47582
+ return mapDefined(values2, (v2) => parseCustomTypeOption(opt.element, v2, errors));
47583
47583
  }
47584
47584
  }
47585
47585
  function getOptionName(option) {
@@ -48060,7 +48060,7 @@ ${lanes.join("\n")}
48060
48060
  elements.forEach((element) => convertPropertyValueToJson(element, elementOption));
48061
48061
  return void 0;
48062
48062
  }
48063
- return filter(elements.map((element) => convertPropertyValueToJson(element, elementOption)), (v) => v !== void 0);
48063
+ return filter(elements.map((element) => convertPropertyValueToJson(element, elementOption)), (v2) => v2 !== void 0);
48064
48064
  }
48065
48065
  function convertPropertyValueToJson(valueExpression, option) {
48066
48066
  switch (valueExpression.kind) {
@@ -48255,7 +48255,7 @@ ${lanes.join("\n")}
48255
48255
  if (pathOptions && optionDefinition.isFilePath) {
48256
48256
  result.set(name, getRelativePathFromFile(pathOptions.configFilePath, getNormalizedAbsolutePath(value, getDirectoryPath(pathOptions.configFilePath)), getCanonicalFileName));
48257
48257
  } else if (pathOptions && optionDefinition.type === "list" && optionDefinition.element.isFilePath) {
48258
- result.set(name, value.map((v) => getRelativePathFromFile(pathOptions.configFilePath, getNormalizedAbsolutePath(v, getDirectoryPath(pathOptions.configFilePath)), getCanonicalFileName)));
48258
+ result.set(name, value.map((v2) => getRelativePathFromFile(pathOptions.configFilePath, getNormalizedAbsolutePath(v2, getDirectoryPath(pathOptions.configFilePath)), getCanonicalFileName)));
48259
48259
  } else {
48260
48260
  result.set(name, value);
48261
48261
  }
@@ -49063,7 +49063,7 @@ ${lanes.join("\n")}
49063
49063
  }
49064
49064
  }
49065
49065
  function convertJsonOptionOfListType(option, values2, basePath, errors, propertyAssignment, valueExpression, sourceFile) {
49066
- return filter(map(values2, (v, index) => convertJsonOption(option.element, v, basePath, errors, propertyAssignment, valueExpression == null ? void 0 : valueExpression.elements[index], sourceFile)), (v) => option.listPreserveFalsyValues ? true : !!v);
49066
+ return filter(map(values2, (v2, index) => convertJsonOption(option.element, v2, basePath, errors, propertyAssignment, valueExpression == null ? void 0 : valueExpression.elements[index], sourceFile)), (v2) => option.listPreserveFalsyValues ? true : !!v2);
49067
49067
  }
49068
49068
  var invalidTrailingRecursionPattern = /(?:^|\/)\*\*\/?$/;
49069
49069
  var wildcardDirectoryPattern = /^[^*?]*(?=\/[^/]*[*?])/;
@@ -49325,7 +49325,7 @@ ${lanes.join("\n")}
49325
49325
  // fall through to list
49326
49326
  case "list":
49327
49327
  const elementType = option.element;
49328
- return isArray(value) ? mapDefined(value, (v) => getOptionValueWithEmptyStrings(v, elementType)) : "";
49328
+ return isArray(value) ? mapDefined(value, (v2) => getOptionValueWithEmptyStrings(v2, elementType)) : "";
49329
49329
  default:
49330
49330
  return forEachEntry(option.type, (optionEnumValue, optionStringValue) => {
49331
49331
  if (optionEnumValue === value) {
@@ -69653,9 +69653,9 @@ ${lanes.join("\n")}
69653
69653
  return getBaseConstraint(getSubstitutionIntersection(t));
69654
69654
  }
69655
69655
  if (isGenericTupleType(t)) {
69656
- const newElements = map(getElementTypes(t), (v, i) => {
69657
- const constraint = v.flags & 262144 && t.target.elementFlags[i] & 8 && getBaseConstraint(v) || v;
69658
- return constraint !== v && everyType(constraint, (c) => isArrayOrTupleType(c) && !isGenericTupleType(c)) ? constraint : v;
69656
+ const newElements = map(getElementTypes(t), (v2, i) => {
69657
+ const constraint = v2.flags & 262144 && t.target.elementFlags[i] & 8 && getBaseConstraint(v2) || v2;
69658
+ return constraint !== v2 && everyType(constraint, (c) => isArrayOrTupleType(c) && !isGenericTupleType(c)) ? constraint : v2;
69659
69659
  });
69660
69660
  return createTupleType(newElements, t.target.elementFlags, t.target.readonly, t.target.labeledElementDeclarations);
69661
69661
  }
@@ -77429,7 +77429,7 @@ ${lanes.join("\n")}
77429
77429
  if (result2 = typeArgumentsRelatedTo(sourceTypeArguments, targetTypeArguments, variances, reportErrors2, intersectionState2)) {
77430
77430
  return result2;
77431
77431
  }
77432
- if (some(variances, (v) => !!(v & 24))) {
77432
+ if (some(variances, (v2) => !!(v2 & 24))) {
77433
77433
  originalErrorInfo = void 0;
77434
77434
  resetErrorInfo(saveErrorInfo);
77435
77435
  return void 0;
@@ -77439,7 +77439,7 @@ ${lanes.join("\n")}
77439
77439
  if (variances !== emptyArray && !allowStructuralFallback) {
77440
77440
  if (varianceCheckFailed && !(reportErrors2 && some(
77441
77441
  variances,
77442
- (v) => (v & 7) === 0
77442
+ (v2) => (v2 & 7) === 0
77443
77443
  /* Invariant */
77444
77444
  ))) {
77445
77445
  return 0;
@@ -140817,7 +140817,7 @@ ${lanes.join("\n")}
140817
140817
  function createManyToManyPathMap() {
140818
140818
  function create2(forward, reverse, deleted) {
140819
140819
  const map2 = {
140820
- getKeys: (v) => reverse.get(v),
140820
+ getKeys: (v2) => reverse.get(v2),
140821
140821
  getValues: (k3) => forward.get(k3),
140822
140822
  keys: () => forward.keys(),
140823
140823
  size: () => forward.size,
@@ -140827,7 +140827,7 @@ ${lanes.join("\n")}
140827
140827
  if (!set) {
140828
140828
  return false;
140829
140829
  }
140830
- set.forEach((v) => deleteFromMultimap(reverse, v, k3));
140830
+ set.forEach((v2) => deleteFromMultimap(reverse, v2, k3));
140831
140831
  forward.delete(k3);
140832
140832
  return true;
140833
140833
  },
@@ -140835,14 +140835,14 @@ ${lanes.join("\n")}
140835
140835
  deleted == null ? void 0 : deleted.delete(k3);
140836
140836
  const existingVSet = forward.get(k3);
140837
140837
  forward.set(k3, vSet);
140838
- existingVSet == null ? void 0 : existingVSet.forEach((v) => {
140839
- if (!vSet.has(v)) {
140840
- deleteFromMultimap(reverse, v, k3);
140838
+ existingVSet == null ? void 0 : existingVSet.forEach((v2) => {
140839
+ if (!vSet.has(v2)) {
140840
+ deleteFromMultimap(reverse, v2, k3);
140841
140841
  }
140842
140842
  });
140843
- vSet.forEach((v) => {
140844
- if (!(existingVSet == null ? void 0 : existingVSet.has(v))) {
140845
- addToMultimap(reverse, v, k3);
140843
+ vSet.forEach((v2) => {
140844
+ if (!(existingVSet == null ? void 0 : existingVSet.has(v2))) {
140845
+ addToMultimap(reverse, v2, k3);
140846
140846
  }
140847
140847
  });
140848
140848
  return map2;
@@ -140858,17 +140858,17 @@ ${lanes.join("\n")}
140858
140858
  );
140859
140859
  }
140860
140860
  BuilderState2.createManyToManyPathMap = createManyToManyPathMap;
140861
- function addToMultimap(map2, k3, v) {
140861
+ function addToMultimap(map2, k3, v2) {
140862
140862
  let set = map2.get(k3);
140863
140863
  if (!set) {
140864
140864
  set = /* @__PURE__ */ new Set();
140865
140865
  map2.set(k3, set);
140866
140866
  }
140867
- set.add(v);
140867
+ set.add(v2);
140868
140868
  }
140869
- function deleteFromMultimap(map2, k3, v) {
140869
+ function deleteFromMultimap(map2, k3, v2) {
140870
140870
  const set = map2.get(k3);
140871
- if (set == null ? void 0 : set.delete(v)) {
140871
+ if (set == null ? void 0 : set.delete(v2)) {
140872
140872
  if (!set.size) {
140873
140873
  map2.delete(k3);
140874
140874
  }
@@ -147186,7 +147186,7 @@ ${lanes.join("\n")}
147186
147186
  return options.pretty;
147187
147187
  }
147188
147188
  function getOptionsForHelp(commandLine) {
147189
- return !!commandLine.options.all ? toSorted(optionDeclarations.concat(tscBuildOption), (a, b4) => compareStringsCaseInsensitive(a.name, b4.name)) : filter(optionDeclarations.concat(tscBuildOption), (v) => !!v.showInSimplifiedHelpView);
147189
+ return !!commandLine.options.all ? toSorted(optionDeclarations.concat(tscBuildOption), (a, b4) => compareStringsCaseInsensitive(a.name, b4.name)) : filter(optionDeclarations.concat(tscBuildOption), (v2) => !!v2.showInSimplifiedHelpView);
147190
147190
  }
147191
147191
  function printVersion(sys2) {
147192
147192
  sys2.write(getDiagnosticText(Diagnostics.Version_0, version) + sys2.newLine);
@@ -150589,8 +150589,8 @@ ${lanes.join("\n")}
150589
150589
  default:
150590
150590
  return "";
150591
150591
  }
150592
- function getKindOfVariableDeclaration(v) {
150593
- return isVarConst(v) ? "const" : isLet(v) ? "let" : "var";
150592
+ function getKindOfVariableDeclaration(v2) {
150593
+ return isVarConst(v2) ? "const" : isLet(v2) ? "let" : "var";
150594
150594
  }
150595
150595
  }
150596
150596
  function isThis(node) {
@@ -156679,7 +156679,7 @@ interface Symbol {
156679
156679
  }
156680
156680
  var commandLineOptionsStringToEnum;
156681
156681
  function fixupCompilerOptions(options, diagnostics) {
156682
- commandLineOptionsStringToEnum = commandLineOptionsStringToEnum || filter(optionDeclarations, (o2) => typeof o2.type === "object" && !forEachEntry(o2.type, (v) => typeof v !== "number"));
156682
+ commandLineOptionsStringToEnum = commandLineOptionsStringToEnum || filter(optionDeclarations, (o2) => typeof o2.type === "object" && !forEachEntry(o2.type, (v2) => typeof v2 !== "number"));
156683
156683
  options = cloneCompilerOptions(options);
156684
156684
  for (const opt of commandLineOptionsStringToEnum) {
156685
156685
  if (!hasProperty(options, opt.name)) {
@@ -156689,7 +156689,7 @@ interface Symbol {
156689
156689
  if (isString(value)) {
156690
156690
  options[opt.name] = parseCustomTypeOption(opt, value, diagnostics);
156691
156691
  } else {
156692
- if (!forEachEntry(opt.type, (v) => v === value)) {
156692
+ if (!forEachEntry(opt.type, (v2) => v2 === value)) {
156693
156693
  diagnostics.push(createCompilerDiagnosticForInvalidCustomType(opt));
156694
156694
  }
156695
156695
  }
@@ -162506,12 +162506,12 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")}
162506
162506
  }
162507
162507
  }
162508
162508
  function getPropertyAssignmentsForWritesAndVariableDeclarations(exposedVariableDeclarations, writes) {
162509
- const variableAssignments = map(exposedVariableDeclarations, (v) => factory.createShorthandPropertyAssignment(v.symbol.name));
162509
+ const variableAssignments = map(exposedVariableDeclarations, (v2) => factory.createShorthandPropertyAssignment(v2.symbol.name));
162510
162510
  const writeAssignments = map(writes, (w2) => factory.createShorthandPropertyAssignment(w2.symbol.name));
162511
162511
  return variableAssignments === void 0 ? writeAssignments : writeAssignments === void 0 ? variableAssignments : variableAssignments.concat(writeAssignments);
162512
162512
  }
162513
- function isReadonlyArray(v) {
162514
- return isArray(v);
162513
+ function isReadonlyArray(v2) {
162514
+ return isArray(v2);
162515
162515
  }
162516
162516
  function getEnclosingTextRange(targetRange, sourceFile) {
162517
162517
  return isReadonlyArray(targetRange.range) ? { pos: first(targetRange.range).getStart(sourceFile), end: last(targetRange.range).getEnd() } : targetRange.range;
@@ -200579,19 +200579,19 @@ ${options.prefix}` : "\n" : options.prefix
200579
200579
  }
200580
200580
  const set = /* @__PURE__ */ new Map();
200581
200581
  let unique = 0;
200582
- for (const v of arr1) {
200583
- if (set.get(v) !== true) {
200584
- set.set(v, true);
200582
+ for (const v2 of arr1) {
200583
+ if (set.get(v2) !== true) {
200584
+ set.set(v2, true);
200585
200585
  unique++;
200586
200586
  }
200587
200587
  }
200588
- for (const v of arr2) {
200589
- const isSet = set.get(v);
200588
+ for (const v2 of arr2) {
200589
+ const isSet = set.get(v2);
200590
200590
  if (isSet === void 0) {
200591
200591
  return false;
200592
200592
  }
200593
200593
  if (isSet === true) {
200594
- set.set(v, false);
200594
+ set.set(v2, false);
200595
200595
  unique--;
200596
200596
  }
200597
200597
  }
@@ -211969,10 +211969,10 @@ Additional information: BADCLIENT: Bad error code, ${badCode} not found in range
211969
211969
  }
211970
211970
  })({ get exports() {
211971
211971
  return ts;
211972
- }, set exports(v) {
211973
- ts = v;
211972
+ }, set exports(v2) {
211973
+ ts = v2;
211974
211974
  if (typeof module2 !== "undefined" && module2.exports) {
211975
- module2.exports = v;
211975
+ module2.exports = v2;
211976
211976
  }
211977
211977
  } });
211978
211978
  }
@@ -212120,17 +212120,19 @@ var require_commonjs2 = __commonJS({
212120
212120
  }
212121
212121
  function expand_(str, max, isTop) {
212122
212122
  const expansions = [];
212123
- const m2 = (0, balanced_match_1.balanced)("{", "}", str);
212124
- if (!m2)
212125
- return [str];
212126
- const pre = m2.pre;
212127
- const post = m2.post.length ? expand_(m2.post, max, false) : [""];
212128
- if (/\$$/.test(m2.pre)) {
212129
- for (let k3 = 0; k3 < post.length && k3 < max; k3++) {
212130
- const expansion = pre + "{" + m2.body + "}" + post[k3];
212131
- expansions.push(expansion);
212123
+ for (; ; ) {
212124
+ const m2 = (0, balanced_match_1.balanced)("{", "}", str);
212125
+ if (!m2)
212126
+ return [str];
212127
+ const pre = m2.pre;
212128
+ if (/\$$/.test(m2.pre)) {
212129
+ const post2 = m2.post.length ? expand_(m2.post, max, false) : [""];
212130
+ for (let k3 = 0; k3 < post2.length && k3 < max; k3++) {
212131
+ const expansion = pre + "{" + m2.body + "}" + post2[k3];
212132
+ expansions.push(expansion);
212133
+ }
212134
+ return expansions;
212132
212135
  }
212133
- } else {
212134
212136
  const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m2.body);
212135
212137
  const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m2.body);
212136
212138
  const isSequence = isNumericSequence || isAlphaSequence;
@@ -212138,10 +212140,12 @@ var require_commonjs2 = __commonJS({
212138
212140
  if (!isSequence && !isOptions) {
212139
212141
  if (m2.post.match(/,(?!,).*\}/)) {
212140
212142
  str = m2.pre + "{" + m2.body + escClose + m2.post;
212141
- return expand_(str, max, true);
212143
+ isTop = true;
212144
+ continue;
212142
212145
  }
212143
212146
  return [str];
212144
212147
  }
212148
+ const post = m2.post.length ? expand_(m2.post, max, false) : [""];
212145
212149
  let n;
212146
212150
  if (isSequence) {
212147
212151
  n = m2.body.split(/\.\./);
@@ -212205,8 +212209,8 @@ var require_commonjs2 = __commonJS({
212205
212209
  }
212206
212210
  }
212207
212211
  }
212212
+ return expansions;
212208
212213
  }
212209
- return expansions;
212210
212214
  }
212211
212215
  }
212212
212216
  });
@@ -214992,10 +214996,10 @@ var require_fill_range = __commonJS({
214992
214996
  let negatives = "";
214993
214997
  let result;
214994
214998
  if (parts.positives.length) {
214995
- positives = parts.positives.map((v) => toMaxLen(String(v), maxLen)).join("|");
214999
+ positives = parts.positives.map((v2) => toMaxLen(String(v2), maxLen)).join("|");
214996
215000
  }
214997
215001
  if (parts.negatives.length) {
214998
- negatives = `-(${prefix2}${parts.negatives.map((v) => toMaxLen(String(v), maxLen)).join("|")})`;
215002
+ negatives = `-(${prefix2}${parts.negatives.map((v2) => toMaxLen(String(v2), maxLen)).join("|")})`;
214999
215003
  }
215000
215004
  if (positives && negatives) {
215001
215005
  result = `${positives}|${negatives}`;
@@ -216301,7 +216305,7 @@ var require_parse2 = __commonJS({
216301
216305
  try {
216302
216306
  new RegExp(value);
216303
216307
  } catch (ex) {
216304
- return args.map((v) => utils.escapeRegex(v)).join("..");
216308
+ return args.map((v2) => utils.escapeRegex(v2)).join("..");
216305
216309
  }
216306
216310
  return value;
216307
216311
  };
@@ -217441,10 +217445,10 @@ var require_micromatch = __commonJS({
217441
217445
  var braces = require_braces();
217442
217446
  var picomatch = require_picomatch2();
217443
217447
  var utils = require_utils2();
217444
- var isEmptyString = (v) => v === "" || v === "./";
217445
- var hasBraces = (v) => {
217446
- const index = v.indexOf("{");
217447
- return index > -1 && v.indexOf("}", index) > -1;
217448
+ var isEmptyString = (v2) => v2 === "" || v2 === "./";
217449
+ var hasBraces = (v2) => {
217450
+ const index = v2.indexOf("{");
217451
+ return index > -1 && v2.indexOf("}", index) > -1;
217448
217452
  };
217449
217453
  var micromatch = (list, patterns, options) => {
217450
217454
  patterns = [].concat(patterns);
@@ -217564,7 +217568,7 @@ var require_micromatch = __commonJS({
217564
217568
  let regex = picomatch.makeRe(String(glob), { ...options, capture: true });
217565
217569
  let match = regex.exec(posix ? utils.toPosixSlashes(input) : input);
217566
217570
  if (match) {
217567
- return match.slice(1).map((v) => v === void 0 ? "" : v);
217571
+ return match.slice(1).map((v2) => v2 === void 0 ? "" : v2);
217568
217572
  }
217569
217573
  };
217570
217574
  micromatch.makeRe = (...args) => picomatch.makeRe(...args);
@@ -256143,7 +256147,7 @@ var require_ts_morph = __commonJS({
256143
256147
  errors: result.errors.map((error) => new Diagnostic(void 0, error))
256144
256148
  };
256145
256149
  }
256146
- var [tsMajor, tsMinor, tsPatch] = common.ts.version.split(".").map((v) => parseInt(v, 10));
256150
+ var [tsMajor, tsMinor, tsPatch] = common.ts.version.split(".").map((v2) => parseInt(v2, 10));
256147
256151
  var WriterUtils = class {
256148
256152
  constructor() {
256149
256153
  }
@@ -276124,6 +276128,7 @@ var import_node_process = require("process");
276124
276128
  var g = __toESM(require("readline"), 1);
276125
276129
  var import_node_readline = __toESM(require("readline"), 1);
276126
276130
  var import_node_stream = require("stream");
276131
+ var import_picocolors = __toESM(require_picocolors(), 1);
276127
276132
  function DD({ onlyFirst: e2 = false } = {}) {
276128
276133
  const t = ["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?(?:\\u0007|\\u001B\\u005C|\\u009C))", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"].join("|");
276129
276134
  return new RegExp(t, e2 ? void 0 : "g");
@@ -276492,10 +276497,26 @@ var LD = class extends x {
276492
276497
  this.value = this._value.value;
276493
276498
  }
276494
276499
  };
276500
+ var RD = class extends x {
276501
+ get valueWithCursor() {
276502
+ if (this.state === "submit") return this.value;
276503
+ if (this.cursor >= this.value.length) return `${this.value}\u2588`;
276504
+ const u2 = this.value.slice(0, this.cursor), [t, ...F2] = this.value.slice(this.cursor);
276505
+ return `${u2}${import_picocolors.default.inverse(t)}${F2.join("")}`;
276506
+ }
276507
+ get cursor() {
276508
+ return this._cursor;
276509
+ }
276510
+ constructor(u2) {
276511
+ super(u2), this.on("finalize", () => {
276512
+ this.value || (this.value = u2.defaultValue);
276513
+ });
276514
+ }
276515
+ };
276495
276516
 
276496
276517
  // node_modules/@clack/prompts/dist/index.mjs
276497
276518
  var import_node_process2 = __toESM(require("process"), 1);
276498
- var import_picocolors = __toESM(require_picocolors(), 1);
276519
+ var import_picocolors2 = __toESM(require_picocolors(), 1);
276499
276520
  var import_sisteransi2 = __toESM(require_src(), 1);
276500
276521
  function ce() {
276501
276522
  return import_node_process2.default.platform !== "win32" ? import_node_process2.default.env.TERM !== "linux" : !!import_node_process2.default.env.CI || !!import_node_process2.default.env.WT_SESSION || !!import_node_process2.default.env.TERMINUS_SUBLIME || import_node_process2.default.env.ConEmuTask === "{cmd::Cmder}" || import_node_process2.default.env.TERM_PROGRAM === "Terminus-Sublime" || import_node_process2.default.env.TERM_PROGRAM === "vscode" || import_node_process2.default.env.TERM === "xterm-256color" || import_node_process2.default.env.TERM === "alacritty" || import_node_process2.default.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
@@ -276527,13 +276548,13 @@ var b2 = (t) => {
276527
276548
  switch (t) {
276528
276549
  case "initial":
276529
276550
  case "active":
276530
- return import_picocolors.default.cyan(le);
276551
+ return import_picocolors2.default.cyan(le);
276531
276552
  case "cancel":
276532
- return import_picocolors.default.red(L2);
276553
+ return import_picocolors2.default.red(L2);
276533
276554
  case "error":
276534
- return import_picocolors.default.yellow(W2);
276555
+ return import_picocolors2.default.yellow(W2);
276535
276556
  case "submit":
276536
- return import_picocolors.default.green(C);
276557
+ return import_picocolors2.default.green(C);
276537
276558
  }
276538
276559
  };
276539
276560
  var G2 = (t) => {
@@ -276541,26 +276562,47 @@ var G2 = (t) => {
276541
276562
  let l2 = 0;
276542
276563
  n >= l2 + a - 3 ? l2 = Math.max(Math.min(n - a + 3, r2.length - a), 0) : n < l2 + 2 && (l2 = Math.max(n - 2, 0));
276543
276564
  const $2 = a < r2.length && l2 > 0, g2 = a < r2.length && l2 + a < r2.length;
276544
- return r2.slice(l2, l2 + a).map((p2, v, f) => {
276545
- const j2 = v === 0 && $2, E = v === f.length - 1 && g2;
276546
- return j2 || E ? import_picocolors.default.dim("...") : i(p2, v + l2 === n);
276565
+ return r2.slice(l2, l2 + a).map((p2, v2, f) => {
276566
+ const j2 = v2 === 0 && $2, E = v2 === f.length - 1 && g2;
276567
+ return j2 || E ? import_picocolors2.default.dim("...") : i(p2, v2 + l2 === n);
276547
276568
  });
276548
276569
  };
276570
+ var he = (t) => new RD({ validate: t.validate, placeholder: t.placeholder, defaultValue: t.defaultValue, initialValue: t.initialValue, render() {
276571
+ const n = `${import_picocolors2.default.gray(o)}
276572
+ ${b2(this.state)} ${t.message}
276573
+ `, r2 = t.placeholder ? import_picocolors2.default.inverse(t.placeholder[0]) + import_picocolors2.default.dim(t.placeholder.slice(1)) : import_picocolors2.default.inverse(import_picocolors2.default.hidden("_")), i = this.value ? this.valueWithCursor : r2;
276574
+ switch (this.state) {
276575
+ case "error":
276576
+ return `${n.trim()}
276577
+ ${import_picocolors2.default.yellow(o)} ${i}
276578
+ ${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(this.error)}
276579
+ `;
276580
+ case "submit":
276581
+ return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(this.value || t.placeholder)}`;
276582
+ case "cancel":
276583
+ return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(this.value ?? ""))}${this.value?.trim() ? `
276584
+ ${import_picocolors2.default.gray(o)}` : ""}`;
276585
+ default:
276586
+ return `${n}${import_picocolors2.default.cyan(o)} ${i}
276587
+ ${import_picocolors2.default.cyan(d2)}
276588
+ `;
276589
+ }
276590
+ } }).prompt();
276549
276591
  var ye = (t) => {
276550
276592
  const n = t.active ?? "Yes", r2 = t.inactive ?? "No";
276551
276593
  return new dD({ active: n, inactive: r2, initialValue: t.initialValue ?? true, render() {
276552
- const i = `${import_picocolors.default.gray(o)}
276594
+ const i = `${import_picocolors2.default.gray(o)}
276553
276595
  ${b2(this.state)} ${t.message}
276554
276596
  `, s = this.value ? n : r2;
276555
276597
  switch (this.state) {
276556
276598
  case "submit":
276557
- return `${i}${import_picocolors.default.gray(o)} ${import_picocolors.default.dim(s)}`;
276599
+ return `${i}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(s)}`;
276558
276600
  case "cancel":
276559
- return `${i}${import_picocolors.default.gray(o)} ${import_picocolors.default.strikethrough(import_picocolors.default.dim(s))}
276560
- ${import_picocolors.default.gray(o)}`;
276601
+ return `${i}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}
276602
+ ${import_picocolors2.default.gray(o)}`;
276561
276603
  default:
276562
- return `${i}${import_picocolors.default.cyan(o)} ${this.value ? `${import_picocolors.default.green(k2)} ${n}` : `${import_picocolors.default.dim(P2)} ${import_picocolors.default.dim(n)}`} ${import_picocolors.default.dim("/")} ${this.value ? `${import_picocolors.default.dim(P2)} ${import_picocolors.default.dim(r2)}` : `${import_picocolors.default.green(k2)} ${r2}`}
276563
- ${import_picocolors.default.cyan(d2)}
276604
+ return `${i}${import_picocolors2.default.cyan(o)} ${this.value ? `${import_picocolors2.default.green(k2)} ${n}` : `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(n)}`} ${import_picocolors2.default.dim("/")} ${this.value ? `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(r2)}` : `${import_picocolors2.default.green(k2)} ${r2}`}
276605
+ ${import_picocolors2.default.cyan(d2)}
276564
276606
  `;
276565
276607
  }
276566
276608
  } }).prompt();
@@ -276570,29 +276612,29 @@ var ve = (t) => {
276570
276612
  const s = r2.label ?? String(r2.value);
276571
276613
  switch (i) {
276572
276614
  case "selected":
276573
- return `${import_picocolors.default.dim(s)}`;
276615
+ return `${import_picocolors2.default.dim(s)}`;
276574
276616
  case "active":
276575
- return `${import_picocolors.default.green(k2)} ${s} ${r2.hint ? import_picocolors.default.dim(`(${r2.hint})`) : ""}`;
276617
+ return `${import_picocolors2.default.green(k2)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}`;
276576
276618
  case "cancelled":
276577
- return `${import_picocolors.default.strikethrough(import_picocolors.default.dim(s))}`;
276619
+ return `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}`;
276578
276620
  default:
276579
- return `${import_picocolors.default.dim(P2)} ${import_picocolors.default.dim(s)}`;
276621
+ return `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(s)}`;
276580
276622
  }
276581
276623
  };
276582
276624
  return new LD({ options: t.options, initialValue: t.initialValue, render() {
276583
- const r2 = `${import_picocolors.default.gray(o)}
276625
+ const r2 = `${import_picocolors2.default.gray(o)}
276584
276626
  ${b2(this.state)} ${t.message}
276585
276627
  `;
276586
276628
  switch (this.state) {
276587
276629
  case "submit":
276588
- return `${r2}${import_picocolors.default.gray(o)} ${n(this.options[this.cursor], "selected")}`;
276630
+ return `${r2}${import_picocolors2.default.gray(o)} ${n(this.options[this.cursor], "selected")}`;
276589
276631
  case "cancel":
276590
- return `${r2}${import_picocolors.default.gray(o)} ${n(this.options[this.cursor], "cancelled")}
276591
- ${import_picocolors.default.gray(o)}`;
276632
+ return `${r2}${import_picocolors2.default.gray(o)} ${n(this.options[this.cursor], "cancelled")}
276633
+ ${import_picocolors2.default.gray(o)}`;
276592
276634
  default:
276593
- return `${r2}${import_picocolors.default.cyan(o)} ${G2({ cursor: this.cursor, options: this.options, maxItems: t.maxItems, style: (i, s) => n(i, s ? "active" : "inactive") }).join(`
276594
- ${import_picocolors.default.cyan(o)} `)}
276595
- ${import_picocolors.default.cyan(d2)}
276635
+ return `${r2}${import_picocolors2.default.cyan(o)} ${G2({ cursor: this.cursor, options: this.options, maxItems: t.maxItems, style: (i, s) => n(i, s ? "active" : "inactive") }).join(`
276636
+ ${import_picocolors2.default.cyan(o)} `)}
276637
+ ${import_picocolors2.default.cyan(d2)}
276596
276638
  `;
276597
276639
  }
276598
276640
  } }).prompt();
@@ -276604,63 +276646,63 @@ ${t}
276604
276646
  `), i = (0, import_node_util.stripVTControlCharacters)(n).length, s = Math.max(r2.reduce((a, l2) => {
276605
276647
  const $2 = (0, import_node_util.stripVTControlCharacters)(l2);
276606
276648
  return $2.length > a ? $2.length : a;
276607
- }, 0), i) + 2, c = r2.map((a) => `${import_picocolors.default.gray(o)} ${import_picocolors.default.dim(a)}${" ".repeat(s - (0, import_node_util.stripVTControlCharacters)(a).length)}${import_picocolors.default.gray(o)}`).join(`
276649
+ }, 0), i) + 2, c = r2.map((a) => `${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(a)}${" ".repeat(s - (0, import_node_util.stripVTControlCharacters)(a).length)}${import_picocolors2.default.gray(o)}`).join(`
276608
276650
  `);
276609
- process.stdout.write(`${import_picocolors.default.gray(o)}
276610
- ${import_picocolors.default.green(C)} ${import_picocolors.default.reset(n)} ${import_picocolors.default.gray(_2.repeat(Math.max(s - i - 1, 1)) + me)}
276651
+ process.stdout.write(`${import_picocolors2.default.gray(o)}
276652
+ ${import_picocolors2.default.green(C)} ${import_picocolors2.default.reset(n)} ${import_picocolors2.default.gray(_2.repeat(Math.max(s - i - 1, 1)) + me)}
276611
276653
  ${c}
276612
- ${import_picocolors.default.gray(de + _2.repeat(s + 2) + pe)}
276654
+ ${import_picocolors2.default.gray(de + _2.repeat(s + 2) + pe)}
276613
276655
  `);
276614
276656
  };
276615
276657
  var xe = (t = "") => {
276616
- process.stdout.write(`${import_picocolors.default.gray(d2)} ${import_picocolors.default.red(t)}
276658
+ process.stdout.write(`${import_picocolors2.default.gray(d2)} ${import_picocolors2.default.red(t)}
276617
276659
 
276618
276660
  `);
276619
276661
  };
276620
276662
  var Ie = (t = "") => {
276621
- process.stdout.write(`${import_picocolors.default.gray(ue)} ${t}
276663
+ process.stdout.write(`${import_picocolors2.default.gray(ue)} ${t}
276622
276664
  `);
276623
276665
  };
276624
276666
  var Se = (t = "") => {
276625
- process.stdout.write(`${import_picocolors.default.gray(o)}
276626
- ${import_picocolors.default.gray(d2)} ${t}
276667
+ process.stdout.write(`${import_picocolors2.default.gray(o)}
276668
+ ${import_picocolors2.default.gray(d2)} ${t}
276627
276669
 
276628
276670
  `);
276629
276671
  };
276630
- var M2 = { message: (t = "", { symbol: n = import_picocolors.default.gray(o) } = {}) => {
276631
- const r2 = [`${import_picocolors.default.gray(o)}`];
276672
+ var M2 = { message: (t = "", { symbol: n = import_picocolors2.default.gray(o) } = {}) => {
276673
+ const r2 = [`${import_picocolors2.default.gray(o)}`];
276632
276674
  if (t) {
276633
276675
  const [i, ...s] = t.split(`
276634
276676
  `);
276635
- r2.push(`${n} ${i}`, ...s.map((c) => `${import_picocolors.default.gray(o)} ${c}`));
276677
+ r2.push(`${n} ${i}`, ...s.map((c) => `${import_picocolors2.default.gray(o)} ${c}`));
276636
276678
  }
276637
276679
  process.stdout.write(`${r2.join(`
276638
276680
  `)}
276639
276681
  `);
276640
276682
  }, info: (t) => {
276641
- M2.message(t, { symbol: import_picocolors.default.blue(q) });
276683
+ M2.message(t, { symbol: import_picocolors2.default.blue(q) });
276642
276684
  }, success: (t) => {
276643
- M2.message(t, { symbol: import_picocolors.default.green(D) });
276685
+ M2.message(t, { symbol: import_picocolors2.default.green(D) });
276644
276686
  }, step: (t) => {
276645
- M2.message(t, { symbol: import_picocolors.default.green(C) });
276687
+ M2.message(t, { symbol: import_picocolors2.default.green(C) });
276646
276688
  }, warn: (t) => {
276647
- M2.message(t, { symbol: import_picocolors.default.yellow(U) });
276689
+ M2.message(t, { symbol: import_picocolors2.default.yellow(U) });
276648
276690
  }, warning: (t) => {
276649
276691
  M2.warn(t);
276650
276692
  }, error: (t) => {
276651
- M2.message(t, { symbol: import_picocolors.default.red(K2) });
276693
+ M2.message(t, { symbol: import_picocolors2.default.red(K2) });
276652
276694
  } };
276653
- var J2 = `${import_picocolors.default.gray(o)} `;
276695
+ var J2 = `${import_picocolors2.default.gray(o)} `;
276654
276696
  var Y2 = ({ indicator: t = "dots" } = {}) => {
276655
276697
  const n = V2 ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"], r2 = V2 ? 80 : 120, i = process.env.CI === "true";
276656
276698
  let s, c, a = false, l2 = "", $2, g2 = performance.now();
276657
276699
  const p2 = (m2) => {
276658
276700
  const h2 = m2 > 1 ? "Something went wrong" : "Canceled";
276659
276701
  a && N2(h2, m2);
276660
- }, v = () => p2(2), f = () => p2(1), j2 = () => {
276661
- process.on("uncaughtExceptionMonitor", v), process.on("unhandledRejection", v), process.on("SIGINT", f), process.on("SIGTERM", f), process.on("exit", p2);
276702
+ }, v2 = () => p2(2), f = () => p2(1), j2 = () => {
276703
+ process.on("uncaughtExceptionMonitor", v2), process.on("unhandledRejection", v2), process.on("SIGINT", f), process.on("SIGTERM", f), process.on("exit", p2);
276662
276704
  }, E = () => {
276663
- process.removeListener("uncaughtExceptionMonitor", v), process.removeListener("unhandledRejection", v), process.removeListener("SIGINT", f), process.removeListener("SIGTERM", f), process.removeListener("exit", p2);
276705
+ process.removeListener("uncaughtExceptionMonitor", v2), process.removeListener("unhandledRejection", v2), process.removeListener("SIGINT", f), process.removeListener("SIGTERM", f), process.removeListener("exit", p2);
276664
276706
  }, B2 = () => {
276665
276707
  if ($2 === void 0) return;
276666
276708
  i && process.stdout.write(`
@@ -276672,13 +276714,13 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
276672
276714
  const h2 = (performance.now() - m2) / 1e3, w2 = Math.floor(h2 / 60), I2 = Math.floor(h2 % 60);
276673
276715
  return w2 > 0 ? `[${w2}m ${I2}s]` : `[${I2}s]`;
276674
276716
  }, H = (m2 = "") => {
276675
- a = true, s = fD(), l2 = R2(m2), g2 = performance.now(), process.stdout.write(`${import_picocolors.default.gray(o)}
276717
+ a = true, s = fD(), l2 = R2(m2), g2 = performance.now(), process.stdout.write(`${import_picocolors2.default.gray(o)}
276676
276718
  `);
276677
276719
  let h2 = 0, w2 = 0;
276678
276720
  j2(), c = setInterval(() => {
276679
276721
  if (i && l2 === $2) return;
276680
276722
  B2(), $2 = l2;
276681
- const I2 = import_picocolors.default.magenta(n[h2]);
276723
+ const I2 = import_picocolors2.default.magenta(n[h2]);
276682
276724
  if (i) process.stdout.write(`${I2} ${l2}...`);
276683
276725
  else if (t === "timer") process.stdout.write(`${I2} ${l2} ${O2(g2)}`);
276684
276726
  else {
@@ -276689,7 +276731,7 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
276689
276731
  }, r2);
276690
276732
  }, N2 = (m2 = "", h2 = 0) => {
276691
276733
  a = false, clearInterval(c), B2();
276692
- const w2 = h2 === 0 ? import_picocolors.default.green(C) : h2 === 1 ? import_picocolors.default.red(L2) : import_picocolors.default.red(W2);
276734
+ const w2 = h2 === 0 ? import_picocolors2.default.green(C) : h2 === 1 ? import_picocolors2.default.red(L2) : import_picocolors2.default.red(W2);
276693
276735
  l2 = R2(m2 ?? l2), t === "timer" ? process.stdout.write(`${w2} ${l2} ${O2(g2)}
276694
276736
  `) : process.stdout.write(`${w2} ${l2}
276695
276737
  `), E(), s();
@@ -276700,10 +276742,10 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
276700
276742
  };
276701
276743
 
276702
276744
  // src/cli/index.ts
276703
- var import_picocolors19 = __toESM(require_picocolors(), 1);
276745
+ var import_picocolors20 = __toESM(require_picocolors(), 1);
276704
276746
  var import_fs12 = require("fs");
276705
276747
  var import_path7 = require("path");
276706
- var import_child_process2 = require("child_process");
276748
+ var import_child_process3 = require("child_process");
276707
276749
 
276708
276750
  // src/cli/migrate.ts
276709
276751
  init_cjs_shims();
@@ -277411,7 +277453,7 @@ var ErrorBodyShapeSchema = import_zod4.z.object({
277411
277453
  }).passthrough();
277412
277454
 
277413
277455
  // src/cli/migrate.ts
277414
- var import_picocolors3 = __toESM(require_picocolors(), 1);
277456
+ var import_picocolors4 = __toESM(require_picocolors(), 1);
277415
277457
  var import_fs5 = require("fs");
277416
277458
 
277417
277459
  // node_modules/postgres/src/index.js
@@ -277878,7 +277920,7 @@ var fromPascal = (x2) => (x2.slice(0, 1) + x2.slice(1).replace(/([A-Z])/g, "_$1"
277878
277920
  var fromKebab = (x2) => x2.replace(/-/g, "_");
277879
277921
  function createJsonTransform(fn) {
277880
277922
  return function jsonTransform(x2, column) {
277881
- return typeof x2 === "object" && x2 !== null && (column.type === 114 || column.type === 3802) ? Array.isArray(x2) ? x2.map((x3) => jsonTransform(x3, column)) : Object.entries(x2).reduce((acc, [k3, v]) => Object.assign(acc, { [fn(k3)]: jsonTransform(v, column) }), {}) : x2;
277923
+ return typeof x2 === "object" && x2 !== null && (column.type === 114 || column.type === 3802) ? Array.isArray(x2) ? x2.map((x3) => jsonTransform(x3, column)) : Object.entries(x2).reduce((acc, [k3, v2]) => Object.assign(acc, { [fn(k3)]: jsonTransform(v2, column) }), {}) : x2;
277882
277924
  };
277883
277925
  }
277884
277926
  toCamel.column = { from: toCamel };
@@ -277956,9 +277998,9 @@ init_cjs_shims();
277956
277998
  var size = 256;
277957
277999
  var buffer = Buffer.allocUnsafe(size);
277958
278000
  var messages = "BCcDdEFfHPpQSX".split("").reduce((acc, x2) => {
277959
- const v = x2.charCodeAt(0);
278001
+ const v2 = x2.charCodeAt(0);
277960
278002
  acc[x2] = () => {
277961
- buffer[0] = v;
278003
+ buffer[0] = v2;
277962
278004
  b3.i = 5;
277963
278005
  return b3;
277964
278006
  };
@@ -278453,11 +278495,11 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
278453
278495
  query.forEachFn ? query.forEachFn(transform.row.from ? transform.row.from(row) : row, result) : result[rows++] = transform.row.from ? transform.row.from(row) : row;
278454
278496
  }
278455
278497
  function ParameterStatus(x2) {
278456
- const [k3, v] = x2.toString("utf8", 5, x2.length - 1).split(bytes_default.N);
278457
- backendParameters[k3] = v;
278458
- if (options.parameters[k3] !== v) {
278459
- options.parameters[k3] = v;
278460
- onparameter && onparameter(k3, v);
278498
+ const [k3, v2] = x2.toString("utf8", 5, x2.length - 1).split(bytes_default.N);
278499
+ backendParameters[k3] = v2;
278500
+ if (options.parameters[k3] !== v2) {
278501
+ options.parameters[k3] = v2;
278502
+ onparameter && onparameter(k3, v2);
278461
278503
  }
278462
278504
  }
278463
278505
  function ReadyForQuery(x2) {
@@ -278814,7 +278856,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
278814
278856
  client_encoding: "UTF8"
278815
278857
  },
278816
278858
  options.connection
278817
- )).filter(([, v]) => v).map(([k3, v]) => k3 + bytes_default.N + v).join(bytes_default.N)
278859
+ )).filter(([, v2]) => v2).map(([k3, v2]) => k3 + bytes_default.N + v2).join(bytes_default.N)
278818
278860
  ).z(2).end(0);
278819
278861
  }
278820
278862
  }
@@ -278979,7 +279021,7 @@ function Time(x2) {
278979
279021
  return new Date(Date.UTC(2e3, 0, 1) + Number(x2 / BigInt(1e3)));
278980
279022
  }
278981
279023
  function parse(x2, state, parsers2, handle, transform) {
278982
- const char = (acc, [k3, v]) => (acc[k3.charCodeAt(0)] = v, acc);
279024
+ const char = (acc, [k3, v2]) => (acc[k3.charCodeAt(0)] = v2, acc);
278983
279025
  Object.entries({
278984
279026
  R: (x3) => {
278985
279027
  let i = 1;
@@ -279476,7 +279518,7 @@ function parseOptions(a, b4) {
279476
279518
  connection: {
279477
279519
  application_name: env.PGAPPNAME || "postgres.js",
279478
279520
  ...o2.connection,
279479
- ...Object.entries(query).reduce((acc, [k3, v]) => (k3 in defaults || (acc[k3] = v), acc), {})
279521
+ ...Object.entries(query).reduce((acc, [k3, v2]) => (k3 in defaults || (acc[k3] = v2), acc), {})
279480
279522
  },
279481
279523
  types: o2.types || {},
279482
279524
  target_session_attrs: tsa(o2, url, env),
@@ -279580,7 +279622,7 @@ var import_source = require("@abloatai/ablo/source");
279580
279622
 
279581
279623
  // src/cli/push.ts
279582
279624
  init_cjs_shims();
279583
- var import_picocolors2 = __toESM(require_picocolors(), 1);
279625
+ var import_picocolors3 = __toESM(require_picocolors(), 1);
279584
279626
 
279585
279627
  // src/auth/credentialPolicy.ts
279586
279628
  init_cjs_shims();
@@ -279600,6 +279642,7 @@ function classifyCredentialKind(value) {
279600
279642
  // src/cli/push.ts
279601
279643
  var import_fs4 = require("fs");
279602
279644
  var import_path3 = require("path");
279645
+ var import_child_process = require("child_process");
279603
279646
  var import_schema2 = require("@abloatai/ablo/schema");
279604
279647
 
279605
279648
  // src/cli/config.ts
@@ -279630,17 +279673,17 @@ function asKeyEntry(value) {
279630
279673
  }
279631
279674
  function asProfileKeys(value) {
279632
279675
  if (!value || typeof value !== "object") return void 0;
279633
- const v = value;
279634
- const sandbox = asKeyEntry(v.sandbox);
279635
- const production = asKeyEntry(v.production);
279676
+ const v2 = value;
279677
+ const sandbox = asKeyEntry(v2.sandbox);
279678
+ const production = asKeyEntry(v2.production);
279636
279679
  if (!sandbox && !production) return void 0;
279637
279680
  return { ...sandbox ? { sandbox } : {}, ...production ? { production } : {} };
279638
279681
  }
279639
279682
  function asProfileMap(value) {
279640
279683
  if (!value || typeof value !== "object") return {};
279641
279684
  const out = {};
279642
- for (const [name, v] of Object.entries(value)) {
279643
- const keys = asProfileKeys(v);
279685
+ for (const [name, v2] of Object.entries(value)) {
279686
+ const keys = asProfileKeys(v2);
279644
279687
  if (keys) out[name] = keys;
279645
279688
  }
279646
279689
  return out;
@@ -279656,8 +279699,8 @@ function readJson(path) {
279656
279699
  }
279657
279700
  function asActiveProject(value) {
279658
279701
  if (value && typeof value === "object" && typeof value.id === "string" && typeof value.slug === "string") {
279659
- const v = value;
279660
- return { id: v.id, slug: v.slug };
279702
+ const v2 = value;
279703
+ return { id: v2.id, slug: v2.slug };
279661
279704
  }
279662
279705
  return void 0;
279663
279706
  }
@@ -279841,6 +279884,19 @@ function resolvePushPlan() {
279841
279884
  return { flow: mode2, apiKey, source: apiKey ? "stored" : null };
279842
279885
  }
279843
279886
 
279887
+ // src/cli/theme.ts
279888
+ init_cjs_shims();
279889
+ var RESET = "\x1B[0m";
279890
+ var PAPER_BG = "\x1B[48;2;250;250;250m";
279891
+ var BLACK_FG = "\x1B[38;2;0;0;0m";
279892
+ function colorEnabled() {
279893
+ return Boolean(process.stdout.isTTY) && !process.env.NO_COLOR;
279894
+ }
279895
+ function brand(label = "ablo") {
279896
+ if (!colorEnabled()) return label;
279897
+ return `${PAPER_BG}${BLACK_FG} ${label} ${RESET}`;
279898
+ }
279899
+
279844
279900
  // src/cli/push.ts
279845
279901
  function coerceBackfill(raw) {
279846
279902
  if (raw === "true") return true;
@@ -279854,14 +279910,14 @@ var DEFAULT_URL = "https://api.abloatai.com";
279854
279910
  function fmtSignal(s) {
279855
279911
  const sig = s;
279856
279912
  const where = sig.field ? `${sig.model}.${sig.field}` : sig.model;
279857
- let line = ` \u2022 ${import_picocolors2.default.bold(where ?? "?")} \u2014 ${sig.detail ?? ""}`;
279913
+ let line = ` \u2022 ${import_picocolors3.default.bold(where ?? "?")} \u2014 ${sig.detail ?? ""}`;
279858
279914
  if (sig.shadowed) {
279859
279915
  const env = sig.shadowed.environment ?? "production";
279860
279916
  const ver = sig.shadowed.version != null ? `v${sig.shadowed.version}` : "active";
279861
279917
  const when = sig.shadowed.pushedAt ? new Date(sig.shadowed.pushedAt).toISOString().slice(0, 10) : "unknown date";
279862
279918
  const by = sig.shadowed.pushedBy ? ` by ${sig.shadowed.pushedBy}` : "";
279863
279919
  line += `
279864
- ${import_picocolors2.default.dim(`\u21B3 baseline: ${env} ${ver}, pushed ${when}${by}`)}`;
279920
+ ${import_picocolors3.default.dim(`\u21B3 baseline: ${env} ${ver}, pushed ${when}${by}`)}`;
279865
279921
  }
279866
279922
  return line;
279867
279923
  }
@@ -279893,6 +279949,9 @@ function parsePushArgs(argv) {
279893
279949
  let exportName = DEFAULT_EXPORT;
279894
279950
  let url = process.env.ABLO_API_URL ?? DEFAULT_URL;
279895
279951
  let force = false;
279952
+ let yes = false;
279953
+ let allowDirty = false;
279954
+ let dryRun = false;
279896
279955
  const renames = [];
279897
279956
  const backfills = [];
279898
279957
  for (let i = 0; i < argv.length; i++) {
@@ -279910,6 +279969,17 @@ function parsePushArgs(argv) {
279910
279969
  case "--force":
279911
279970
  force = true;
279912
279971
  break;
279972
+ case "--yes":
279973
+ case "-y":
279974
+ yes = true;
279975
+ break;
279976
+ case "--allow-dirty":
279977
+ allowDirty = true;
279978
+ break;
279979
+ case "--dry-run":
279980
+ case "--plan":
279981
+ dryRun = true;
279982
+ break;
279913
279983
  case "--rename": {
279914
279984
  const spec = argv[++i] ?? "";
279915
279985
  const [from, to] = spec.split(":");
@@ -279938,13 +280008,13 @@ function parsePushArgs(argv) {
279938
280008
  }
279939
280009
  }
279940
280010
  url = url.replace(/\/+$/, "");
279941
- return { schemaPath, exportName, url, apiKey: process.env.ABLO_API_KEY, force, renames, backfills };
280011
+ return { schemaPath, exportName, url, apiKey: process.env.ABLO_API_KEY, force, renames, backfills, yes, allowDirty, dryRun };
279942
280012
  }
279943
280013
  async function loadSchema(schemaPath, exportName) {
279944
280014
  const abs = (0, import_path3.resolve)(process.cwd(), schemaPath);
279945
280015
  if (!(0, import_fs4.existsSync)(abs)) {
279946
280016
  throw new AbloValidationError(
279947
- `schema not found at ${import_picocolors2.default.bold(schemaPath)}. Run ${import_picocolors2.default.bold("npx ablo init")} or pass ${import_picocolors2.default.bold("--schema <path>")}.`,
280017
+ `schema not found at ${import_picocolors3.default.bold(schemaPath)}. Run ${import_picocolors3.default.bold("npx ablo init")} or pass ${import_picocolors3.default.bold("--schema <path>")}.`,
279948
280018
  { code: "cli_invalid_arguments" }
279949
280019
  );
279950
280020
  }
@@ -279955,7 +280025,7 @@ async function loadSchema(schemaPath, exportName) {
279955
280025
  const schema = mod[exportName] ?? nested?.[exportName];
279956
280026
  if (!schema || typeof schema !== "object" || !("models" in schema)) {
279957
280027
  throw new AbloValidationError(
279958
- `${import_picocolors2.default.bold(schemaPath)} has no \`${exportName}\` export that looks like a Schema. Did you \`export const ${exportName} = defineSchema({ ... })\`?`,
280028
+ `${import_picocolors3.default.bold(schemaPath)} has no \`${exportName}\` export that looks like a Schema. Did you \`export const ${exportName} = defineSchema({ ... })\`?`,
279959
280029
  { code: "cli_invalid_arguments" }
279960
280030
  );
279961
280031
  }
@@ -279964,6 +280034,124 @@ async function loadSchema(schemaPath, exportName) {
279964
280034
  function maskKey(key) {
279965
280035
  return key ? `${key.slice(0, 12)}\u2026` : "(none)";
279966
280036
  }
280037
+ function schemaGitState(schemaPath) {
280038
+ try {
280039
+ const out = (0, import_child_process.execFileSync)("git", ["status", "--porcelain", "--", schemaPath], {
280040
+ cwd: process.cwd(),
280041
+ encoding: "utf8",
280042
+ stdio: ["ignore", "pipe", "ignore"]
280043
+ }).trim();
280044
+ if (out === "") return { dirty: false, untracked: false };
280045
+ return { dirty: true, untracked: out.startsWith("??") };
280046
+ } catch {
280047
+ return null;
280048
+ }
280049
+ }
280050
+ async function fetchActiveSchema(url, apiKey) {
280051
+ const ctrl = new AbortController();
280052
+ const t = setTimeout(() => ctrl.abort(), 3e3);
280053
+ try {
280054
+ const res = await fetch(`${url}/api/schema`, {
280055
+ headers: { authorization: `Bearer ${apiKey}` },
280056
+ signal: ctrl.signal
280057
+ });
280058
+ if (!res.ok) return null;
280059
+ return await res.json();
280060
+ } catch {
280061
+ return null;
280062
+ } finally {
280063
+ clearTimeout(t);
280064
+ }
280065
+ }
280066
+ function conflictStr(c) {
280067
+ if (!c) return "";
280068
+ const parts = ["user", "agent", "system"].flatMap((k3) => c[k3] ? [`${k3}:${c[k3]}`] : []);
280069
+ return parts.length ? `{${parts.join(",")}}` : "";
280070
+ }
280071
+ function localModels(schema) {
280072
+ const json = JSON.parse((0, import_schema2.serializeSchema)(schema));
280073
+ const out = /* @__PURE__ */ new Map();
280074
+ for (const [key, def] of Object.entries(json.models)) out.set(key, conflictStr(def.conflict));
280075
+ return out;
280076
+ }
280077
+ function printPlan(local, remote) {
280078
+ if (!remote?.models) {
280079
+ console.log(` ${import_picocolors3.default.dim("plan")} ${import_picocolors3.default.dim("(deployed schema unavailable \u2014 the server computes the diff on apply)")}
280080
+ `);
280081
+ return;
280082
+ }
280083
+ const remoteMap = /* @__PURE__ */ new Map();
280084
+ for (const m2 of remote.models) remoteMap.set(m2.key, conflictStr(m2.conflict));
280085
+ const added = [...local.keys()].filter((k3) => !remoteMap.has(k3));
280086
+ const removed = [...remoteMap.keys()].filter((k3) => !local.has(k3));
280087
+ const changed = [...local.keys()].filter((k3) => remoteMap.has(k3) && remoteMap.get(k3) !== local.get(k3));
280088
+ const verLabel = remote.version != null ? `v${remote.version}` : "active";
280089
+ if (added.length === 0 && removed.length === 0 && changed.length === 0) {
280090
+ console.log(` ${import_picocolors3.default.dim("plan")} ${import_picocolors3.default.dim(`no model-level changes vs deployed ${verLabel} (any field changes apply on push)`)}
280091
+ `);
280092
+ return;
280093
+ }
280094
+ console.log(` ${import_picocolors3.default.dim("plan")} ${import_picocolors3.default.dim(`vs deployed ${verLabel}:`)}`);
280095
+ for (const k3 of added) console.log(` ${import_picocolors3.default.green(`+ ${k3}`)} ${import_picocolors3.default.dim("(new model)")}`);
280096
+ for (const k3 of changed)
280097
+ console.log(` ${import_picocolors3.default.yellow(`~ ${k3}`)} ${import_picocolors3.default.dim(`conflict ${remoteMap.get(k3) || "(default)"} \u2192 ${local.get(k3) || "(default)"}`)}`);
280098
+ for (const k3 of removed) console.log(` ${import_picocolors3.default.red(`- ${k3}`)} ${import_picocolors3.default.dim("(removed \u2014 destructive, needs --force)")}`);
280099
+ console.log("");
280100
+ }
280101
+ async function confirmPush(args, env) {
280102
+ const isProd = env === "production";
280103
+ const tty = Boolean(process.stdout.isTTY && process.stdin.isTTY);
280104
+ if (isProd && !args.yes) {
280105
+ const git = schemaGitState(args.schemaPath);
280106
+ if (git?.dirty && !args.allowDirty) {
280107
+ console.error(` ${import_picocolors3.default.red("\u2717")} Refusing to deploy uncommitted schema to ${import_picocolors3.default.red(import_picocolors3.default.bold("production"))}.`);
280108
+ console.error(import_picocolors3.default.dim(` Commit ${import_picocolors3.default.bold(args.schemaPath)} first, or pass ${import_picocolors3.default.bold("--allow-dirty")} to override.`));
280109
+ process.exit(1);
280110
+ }
280111
+ if (!tty) {
280112
+ console.error(` ${import_picocolors3.default.red("\u2717")} Refusing to deploy to ${import_picocolors3.default.red(import_picocolors3.default.bold("production"))} non-interactively without confirmation.`);
280113
+ console.error(import_picocolors3.default.dim(` Re-run with ${import_picocolors3.default.bold("--yes")} to confirm in CI/scripts.`));
280114
+ process.exit(1);
280115
+ }
280116
+ const project = getActiveProject();
280117
+ const expected = project?.slug ?? "production";
280118
+ const typed = await he({
280119
+ message: `This deploys to ${import_picocolors3.default.red(import_picocolors3.default.bold("PRODUCTION"))}. Type ${import_picocolors3.default.bold(expected)} to confirm:`,
280120
+ placeholder: expected
280121
+ });
280122
+ if (pD(typed) || String(typed).trim() !== expected) {
280123
+ xe("Aborted \u2014 confirmation did not match.");
280124
+ process.exit(1);
280125
+ }
280126
+ return;
280127
+ }
280128
+ if (!isProd && !args.yes && tty) {
280129
+ const ok = await ye({ message: `Apply to ${import_picocolors3.default.green("sandbox")}?` });
280130
+ if (pD(ok) || !ok) {
280131
+ xe("Aborted.");
280132
+ process.exit(1);
280133
+ }
280134
+ }
280135
+ }
280136
+ function printPushTarget(opts) {
280137
+ const env = modeFromKey(opts.apiKey);
280138
+ const envLabel = env === "production" ? import_picocolors3.default.red(import_picocolors3.default.bold("production")) : env === "sandbox" ? import_picocolors3.default.green("sandbox") : import_picocolors3.default.yellow("unknown env");
280139
+ const project = getActiveProject();
280140
+ const projectLabel = project ? `${import_picocolors3.default.bold(project.slug)} ${import_picocolors3.default.dim(`(${project.id})`)}` : `${import_picocolors3.default.bold("default")} ${import_picocolors3.default.dim("(org-default \u2014 `ablo projects use <slug>` to scope)")}`;
280141
+ const cliMode = getMode();
280142
+ const modeNote = env && env !== cliMode ? ` ${import_picocolors3.default.yellow(`(CLI mode is ${cliMode} \u2014 this key targets ${env})`)}` : "";
280143
+ console.log(`
280144
+ ${brand("ablo")} ${import_picocolors3.default.dim("push")} ${import_picocolors3.default.dim("\u2192")} ${envLabel}${modeNote}`);
280145
+ console.log(` ${import_picocolors3.default.dim("project")} ${projectLabel}`);
280146
+ console.log(` ${import_picocolors3.default.dim("target")} ${import_picocolors3.default.dim(opts.url)}`);
280147
+ console.log(
280148
+ ` ${import_picocolors3.default.dim("key")} ${maskKey(opts.apiKey)} ${import_picocolors3.default.dim(`(${describeKeySource(opts.keySource)})`)}`
280149
+ );
280150
+ console.log(
280151
+ ` ${import_picocolors3.default.dim("schema")} ${import_picocolors3.default.bold(opts.schemaPath)} ${import_picocolors3.default.dim(`\xB7 ${opts.modelCount} models \xB7 hash ${opts.hash}`)}
280152
+ `
280153
+ );
280154
+ }
279967
280155
  function describeKeySource(source) {
279968
280156
  switch (source) {
279969
280157
  case "env":
@@ -279981,7 +280169,7 @@ async function push(argv) {
279981
280169
  try {
279982
280170
  args = parsePushArgs(argv);
279983
280171
  } catch (err) {
279984
- console.error(import_picocolors2.default.red(` ${err instanceof Error ? err.message : String(err)}`));
280172
+ console.error(import_picocolors3.default.red(` ${err instanceof Error ? err.message : String(err)}`));
279985
280173
  process.exit(1);
279986
280174
  }
279987
280175
  let keySource = "env";
@@ -279997,26 +280185,44 @@ async function push(argv) {
279997
280185
  }
279998
280186
  if (!args.apiKey) {
279999
280187
  console.error(
280000
- import_picocolors2.default.red(` No API key.`) + import_picocolors2.default.dim(
280001
- ` Run ${import_picocolors2.default.bold("npx ablo login")} for the sandbox dev loop \u2014 or set ${import_picocolors2.default.bold("ABLO_API_KEY")} (${import_picocolors2.default.bold("sk_test_")} = sandbox; ${import_picocolors2.default.bold("sk_live_")} = deliberate production deploy). Mode is currently '${getMode()}'.`
280188
+ import_picocolors3.default.red(` No API key.`) + import_picocolors3.default.dim(
280189
+ ` Run ${import_picocolors3.default.bold("npx ablo login")} for the sandbox dev loop \u2014 or set ${import_picocolors3.default.bold("ABLO_API_KEY")} (${import_picocolors3.default.bold("sk_test_")} = sandbox; ${import_picocolors3.default.bold("sk_live_")} = deliberate production deploy). Mode is currently '${getMode()}'.`
280002
280190
  )
280003
280191
  );
280004
280192
  process.exit(1);
280005
280193
  }
280006
280194
  const schema = await loadSchema(args.schemaPath, args.exportName);
280007
280195
  const hash = (0, import_schema2.schemaHash)(schema);
280008
- console.log(
280009
- ` Pushing ${import_picocolors2.default.bold(args.schemaPath)} ${import_picocolors2.default.dim(`(${Object.keys(schema.models).length} models, hash ${hash})`)} \u2192 ${import_picocolors2.default.dim(args.url)}`
280010
- );
280196
+ printPushTarget({
280197
+ schemaPath: args.schemaPath,
280198
+ url: args.url,
280199
+ apiKey: args.apiKey,
280200
+ keySource,
280201
+ modelCount: Object.keys(schema.models).length,
280202
+ hash
280203
+ });
280204
+ const remote = await fetchActiveSchema(args.url, args.apiKey);
280205
+ printPlan(localModels(schema), remote);
280206
+ const git = schemaGitState(args.schemaPath);
280207
+ if (git?.dirty) {
280208
+ const what = git.untracked ? "is untracked (not committed)" : "has uncommitted changes";
280209
+ console.log(` ${import_picocolors3.default.yellow("\u26A0")} ${import_picocolors3.default.bold(args.schemaPath)} ${what} \u2014 this deploy won't match a git commit.
280210
+ `);
280211
+ }
280212
+ if (args.dryRun) {
280213
+ console.log(` ${import_picocolors3.default.dim("\u25CB")} dry run \u2014 nothing applied. Re-run without ${import_picocolors3.default.bold("--dry-run")} to deploy.`);
280214
+ return;
280215
+ }
280216
+ await confirmPush(args, modeFromKey(args.apiKey));
280011
280217
  const { ok: resOk, status: status2, body, bodyText } = await pushSchema(schema, args);
280012
280218
  if (resOk) {
280013
280219
  if (body.unchanged) {
280014
- console.log(` ${import_picocolors2.default.dim("\u25CB")} No changes \u2014 schema already active (v${body.version}).`);
280220
+ console.log(` ${import_picocolors3.default.dim("\u25CB")} No changes \u2014 schema already active (v${body.version}).`);
280015
280221
  } else {
280016
- console.log(` ${import_picocolors2.default.green("\u2713")} Activated ${import_picocolors2.default.bold(`v${body.version}`)} ${import_picocolors2.default.dim(`(hash ${body.hash})`)}`);
280222
+ console.log(` ${import_picocolors3.default.green("\u2713")} Activated ${import_picocolors3.default.bold(`v${body.version}`)} ${import_picocolors3.default.dim(`(hash ${body.hash})`)}`);
280017
280223
  if (Array.isArray(body.warnings) && body.warnings.length > 0) {
280018
- console.log(import_picocolors2.default.yellow(` Applied ${body.warnings.length} destructive change(s):`));
280019
- for (const w2 of body.warnings) console.log(import_picocolors2.default.yellow(fmtSignal(w2)));
280224
+ console.log(import_picocolors3.default.yellow(` Applied ${body.warnings.length} destructive change(s):`));
280225
+ for (const w2 of body.warnings) console.log(import_picocolors3.default.yellow(fmtSignal(w2)));
280020
280226
  }
280021
280227
  }
280022
280228
  return;
@@ -280024,63 +280230,69 @@ async function push(argv) {
280024
280230
  if (status2 === 409) {
280025
280231
  const unexecutable = Array.isArray(body.unexecutable) ? body.unexecutable : [];
280026
280232
  const warnings = Array.isArray(body.warnings) ? body.warnings : [];
280027
- console.error(import_picocolors2.default.red(" Incompatible change \u2014 this push is not safe to apply as-is."));
280233
+ console.error(import_picocolors3.default.red(" Incompatible change \u2014 this push is not safe to apply as-is."));
280028
280234
  if (unexecutable.length > 0) {
280029
- console.error(import_picocolors2.default.red(` Unexecutable (would fail on existing rows):`));
280030
- for (const u2 of unexecutable) console.error(import_picocolors2.default.red(fmtSignal(u2)));
280235
+ console.error(import_picocolors3.default.red(` Unexecutable (would fail on existing rows):`));
280236
+ for (const u2 of unexecutable) console.error(import_picocolors3.default.red(fmtSignal(u2)));
280031
280237
  }
280032
280238
  if (warnings.length > 0) {
280033
- console.error(import_picocolors2.default.yellow(` Destructive (data loss):`));
280034
- for (const w2 of warnings) console.error(import_picocolors2.default.yellow(fmtSignal(w2)));
280239
+ console.error(import_picocolors3.default.yellow(` Destructive (data loss):`));
280240
+ for (const w2 of warnings) console.error(import_picocolors3.default.yellow(fmtSignal(w2)));
280035
280241
  }
280036
280242
  const hasShadowed = [...unexecutable, ...warnings].some(
280037
280243
  (s) => s.shadowed != null
280038
280244
  );
280039
280245
  if (hasShadowed) {
280040
280246
  console.error(
280041
- import_picocolors2.default.dim(
280247
+ import_picocolors3.default.dim(
280042
280248
  " These models exist in the baseline above but not in your push. Sandbox readers fall"
280043
280249
  )
280044
280250
  );
280045
280251
  console.error(
280046
- import_picocolors2.default.dim(
280252
+ import_picocolors3.default.dim(
280047
280253
  " back to the production schema until you push your own, so applying this drops them."
280048
280254
  )
280049
280255
  );
280050
280256
  }
280051
- console.error(import_picocolors2.default.dim(` Re-push with ${import_picocolors2.default.bold("--force")} to override, or use ${import_picocolors2.default.bold("--rename old:new")} if you renamed a model.`));
280257
+ console.error(import_picocolors3.default.dim(` Re-push with ${import_picocolors3.default.bold("--force")} to override, or use ${import_picocolors3.default.bold("--rename old:new")} if you renamed a model.`));
280052
280258
  } else if (status2 === 403) {
280053
280259
  const code = body.code ?? body.reason;
280054
280260
  const serverMsg = body.message ?? body.reason;
280055
- console.error(import_picocolors2.default.red(` Forbidden${code ? ` [${code}]` : ""}: ${serverMsg ?? "permission denied"}`));
280056
- console.error(import_picocolors2.default.dim(` Push used ${import_picocolors2.default.bold(maskKey(args.apiKey))} from ${describeKeySource(keySource)}.`));
280261
+ console.error(import_picocolors3.default.red(` Forbidden${code ? ` [${code}]` : ""}: ${serverMsg ?? "permission denied"}`));
280262
+ console.error(import_picocolors3.default.dim(` Push used ${import_picocolors3.default.bold(maskKey(args.apiKey))} from ${describeKeySource(keySource)}.`));
280057
280263
  if (code === "database_role_cannot_enforce_rls") {
280058
280264
  console.error(
280059
- import_picocolors2.default.dim(
280060
- ` Your database role bypasses row-level security. Run ${import_picocolors2.default.bold("npx ablo migrate")} to create a scoped (NOBYPASSRLS) role and repoint DATABASE_URL, then re-push.`
280265
+ import_picocolors3.default.dim(
280266
+ ` Your database role bypasses row-level security. Run ${import_picocolors3.default.bold("npx ablo migrate")} to create a scoped (NOBYPASSRLS) role and repoint DATABASE_URL, then re-push.`
280061
280267
  )
280062
280268
  );
280063
280269
  } else if (code === "database_tables_unforced_rls") {
280064
280270
  console.error(
280065
- import_picocolors2.default.dim(
280066
- ` One or more synced tables don't have FORCE ROW LEVEL SECURITY. Run ${import_picocolors2.default.bold("npx ablo migrate")} to (re)apply the tenant policies, then re-push.`
280271
+ import_picocolors3.default.dim(
280272
+ ` One or more synced tables don't have FORCE ROW LEVEL SECURITY. Run ${import_picocolors3.default.bold("npx ablo migrate")} to (re)apply the tenant policies, then re-push.`
280273
+ )
280274
+ );
280275
+ } else if (code === "capability_scope_denied" || code === "capability_invalid") {
280276
+ console.error(
280277
+ import_picocolors3.default.dim(
280278
+ ` This is a ${import_picocolors3.default.bold("database privilege")} error (Postgres 42501 / row-level security), not a key scope \u2014 a different API key won't help. The role behind this org's database can't write the target. Provision a writable, RLS-scoped role with ${import_picocolors3.default.bold("npx ablo migrate")}, or check the org's database registration. See docs/plans/read-path-logical-replication-vs-hosting.md.`
280067
280279
  )
280068
280280
  );
280069
280281
  } else if (args.apiKey != null && classifyCredentialKind(args.apiKey) === "restricted") {
280070
280282
  console.error(
280071
- import_picocolors2.default.dim(
280072
- ` Schema pushes need a SECRET key: ${import_picocolors2.default.bold("sk_test_")} (sandbox dev loop) or a dashboard ${import_picocolors2.default.bold("sk_live_")} (production deploy: ${import_picocolors2.default.bold("ABLO_API_KEY=sk_live_\u2026 npx ablo push")}).`
280283
+ import_picocolors3.default.dim(
280284
+ ` Schema pushes need a SECRET key: ${import_picocolors3.default.bold("sk_test_")} (sandbox dev loop) or a dashboard ${import_picocolors3.default.bold("sk_live_")} (production deploy: ${import_picocolors3.default.bold("ABLO_API_KEY=sk_live_\u2026 npx ablo push")}).`
280073
280285
  )
280074
280286
  );
280075
280287
  } else {
280076
280288
  console.error(
280077
- import_picocolors2.default.dim(
280078
- ` This key isn't authorized to push schema (needs ${import_picocolors2.default.bold("schema:push")}). ` + (keySource === "login" ? `It's your stored ${import_picocolors2.default.bold("ablo login")} sandbox key \u2014 a key in ${import_picocolors2.default.bold(".env.local")} or ${import_picocolors2.default.bold("ABLO_API_KEY")} takes precedence, so put a schema:push key there (sandbox ${import_picocolors2.default.bold("sk_test_")} or production ${import_picocolors2.default.bold("sk_live_")}) and re-push. ` : `Use a schema:push key \u2014 a sandbox ${import_picocolors2.default.bold("sk_test_")} or production ${import_picocolors2.default.bold("sk_live_")}. `) + `Manage keys at https://abloatai.com`
280289
+ import_picocolors3.default.dim(
280290
+ ` This key isn't authorized to push schema (needs ${import_picocolors3.default.bold("schema:push")}). ` + (keySource === "login" ? `It's your stored ${import_picocolors3.default.bold("ablo login")} sandbox key \u2014 a key in ${import_picocolors3.default.bold(".env.local")} or ${import_picocolors3.default.bold("ABLO_API_KEY")} takes precedence, so put a schema:push key there (sandbox ${import_picocolors3.default.bold("sk_test_")} or production ${import_picocolors3.default.bold("sk_live_")}) and re-push. ` : `Use a schema:push key \u2014 a sandbox ${import_picocolors3.default.bold("sk_test_")} or production ${import_picocolors3.default.bold("sk_live_")}. `) + `Manage keys at https://abloatai.com`
280079
280291
  )
280080
280292
  );
280081
280293
  }
280082
280294
  } else {
280083
- console.error(import_picocolors2.default.red(` Push failed (${status2}): ${body.message ?? body.reason ?? bodyText}`));
280295
+ console.error(import_picocolors3.default.red(` Push failed (${status2}): ${body.message ?? body.reason ?? bodyText}`));
280084
280296
  }
280085
280297
  process.exit(1);
280086
280298
  }
@@ -280140,8 +280352,8 @@ function planFor(schema, targetSchema = "public") {
280140
280352
  }
280141
280353
  var log = {
280142
280354
  info: (msg, fields) => console.log(`[migrate] ${msg}`, fields),
280143
- warn: (msg, fields) => console.warn(import_picocolors3.default.yellow(`[migrate] ${msg}`), fields),
280144
- error: (msg, fields) => console.error(import_picocolors3.default.red(`[migrate] ${msg}`), fields)
280355
+ warn: (msg, fields) => console.warn(import_picocolors4.default.yellow(`[migrate] ${msg}`), fields),
280356
+ error: (msg, fields) => console.error(import_picocolors4.default.red(`[migrate] ${msg}`), fields)
280145
280357
  };
280146
280358
  var PG_LOCK_NOT_AVAILABLE = "55P03";
280147
280359
  var LOCK_TIMEOUT = process.env.ABLO_SCHEMA_LOCK_TIMEOUT ?? process.env.ABLO_DDL_LOCK_TIMEOUT ?? "5s";
@@ -280216,7 +280428,7 @@ async function migrate(argv) {
280216
280428
  try {
280217
280429
  args = parseMigrateArgs(argv);
280218
280430
  } catch (err) {
280219
- console.error(import_picocolors3.default.red(` ${err instanceof Error ? err.message : String(err)}`));
280431
+ console.error(import_picocolors4.default.red(` ${err instanceof Error ? err.message : String(err)}`));
280220
280432
  process.exit(1);
280221
280433
  }
280222
280434
  const schema = await loadSchema(args.schemaPath, args.exportName);
@@ -280227,11 +280439,11 @@ async function migrate(argv) {
280227
280439
  ].join("\n");
280228
280440
  const totalStatements = plan.statements.length + plan.concurrent.length;
280229
280441
  console.log(
280230
- ` ${import_picocolors3.default.dim("Schema")} ${import_picocolors3.default.bold(args.schemaPath)} \u2192 ${import_picocolors3.default.dim(`${Object.keys(schema.models).length} models, ${totalStatements} statements`)}`
280442
+ ` ${import_picocolors4.default.dim("Schema")} ${import_picocolors4.default.bold(args.schemaPath)} \u2192 ${import_picocolors4.default.dim(`${Object.keys(schema.models).length} models, ${totalStatements} statements`)}`
280231
280443
  );
280232
280444
  if (args.outputFile) {
280233
280445
  (0, import_fs5.writeFileSync)(args.outputFile, sql + "\n");
280234
- console.log(` ${import_picocolors3.default.green("\u2713")} SQL written to ${import_picocolors3.default.bold(args.outputFile)}`);
280446
+ console.log(` ${import_picocolors4.default.green("\u2713")} SQL written to ${import_picocolors4.default.bold(args.outputFile)}`);
280235
280447
  return;
280236
280448
  }
280237
280449
  if (args.dryRun) {
@@ -280241,7 +280453,7 @@ async function migrate(argv) {
280241
280453
  const dbUrl = readProjectDatabaseUrl();
280242
280454
  if (!dbUrl) {
280243
280455
  console.error(
280244
- import_picocolors3.default.red(
280456
+ import_picocolors4.default.red(
280245
280457
  " No DATABASE_URL found (checked process env, .env.local, .env). Set it to apply, or use --dry-run to preview."
280246
280458
  )
280247
280459
  );
@@ -280249,7 +280461,7 @@ async function migrate(argv) {
280249
280461
  }
280250
280462
  try {
280251
280463
  await applyStatements(dbUrl, args.targetSchema, plan.statements, plan.concurrent);
280252
- console.log(` ${import_picocolors3.default.green("\u2713")} Migration complete`);
280464
+ console.log(` ${import_picocolors4.default.green("\u2713")} Migration complete`);
280253
280465
  } catch {
280254
280466
  process.exit(1);
280255
280467
  }
@@ -280257,26 +280469,13 @@ async function migrate(argv) {
280257
280469
 
280258
280470
  // src/cli/connect.ts
280259
280471
  init_cjs_shims();
280260
- var import_picocolors4 = __toESM(require_picocolors(), 1);
280261
-
280262
- // src/cli/theme.ts
280263
- init_cjs_shims();
280264
- var RESET = "\x1B[0m";
280265
- var PAPER_BG = "\x1B[48;2;250;250;250m";
280266
- var BLACK_FG = "\x1B[38;2;0;0;0m";
280267
- function colorEnabled() {
280268
- return Boolean(process.stdout.isTTY) && !process.env.NO_COLOR;
280269
- }
280270
- function brand(label = "ablo") {
280271
- if (!colorEnabled()) return label;
280272
- return `${PAPER_BG}${BLACK_FG} ${label} ${RESET}`;
280273
- }
280274
-
280275
- // src/cli/connect.ts
280472
+ var import_picocolors5 = __toESM(require_picocolors(), 1);
280276
280473
  var ABLO_PUBLICATION = "ablo_publication";
280277
280474
  var ABLO_REPLICATION_ROLE = "ablo_replicator";
280278
280475
  function parseConnectArgs(argv) {
280279
280476
  let check2 = false;
280477
+ let register = false;
280478
+ let auditInfra = false;
280280
280479
  let tables = [];
280281
280480
  let role = ABLO_REPLICATION_ROLE;
280282
280481
  for (let i = 0; i < argv.length; i++) {
@@ -280285,6 +280484,12 @@ function parseConnectArgs(argv) {
280285
280484
  case "--check":
280286
280485
  check2 = true;
280287
280486
  break;
280487
+ case "--register":
280488
+ register = true;
280489
+ break;
280490
+ case "--audit-infra":
280491
+ auditInfra = true;
280492
+ break;
280288
280493
  case "--tables": {
280289
280494
  const value = argv[++i] ?? "";
280290
280495
  tables = value.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
@@ -280297,7 +280502,7 @@ function parseConnectArgs(argv) {
280297
280502
  throw new AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
280298
280503
  }
280299
280504
  }
280300
- return { check: check2, tables, role };
280505
+ return { check: check2, register, auditInfra, tables, role };
280301
280506
  }
280302
280507
  function quoteIdent(id) {
280303
280508
  return `"${id.replace(/"/g, '""')}"`;
@@ -280321,74 +280526,89 @@ function connectSetupSql(input) {
280321
280526
  function printConnectRecipe(args) {
280322
280527
  const sql = connectSetupSql({ tables: args.tables, role: args.role });
280323
280528
  console.log(`
280324
- ${brand("ablo")} ${import_picocolors4.default.dim("connect")} ${import_picocolors4.default.dim("logical replication \u2014 the one way to connect a real database")}
280529
+ ${brand("ablo")} ${import_picocolors5.default.dim("connect")} ${import_picocolors5.default.dim("logical replication \u2014 the read path (your writes stay on your own backend)")}
280325
280530
  `);
280326
280531
  console.log(
280327
- ` Ablo READS your write-ahead log (WAL) and ${import_picocolors4.default.bold("never")} runs DDL, owns, or migrates your
280328
- schema. Your app keeps writing through your own backend \u2014 Ablo only tails the changes.
280329
- Run this once against your Postgres ${import_picocolors4.default.dim("(as a superuser / the DB owner)")}:
280532
+ ` Ablo consumes your write-ahead log (WAL) via logical replication and ${import_picocolors5.default.bold("never")} runs DDL,
280533
+ owns, hosts, or migrates your schema. Your app continues to own the write path \u2014 Ablo tails
280534
+ the changes and serves them as live shapes. Run this once against your Postgres ${import_picocolors5.default.dim("(as a superuser / DB owner)")}:
280330
280535
  `
280331
280536
  );
280332
- console.log(` ${import_picocolors4.default.bold("1.")} Enable logical decoding ${import_picocolors4.default.dim("(then RESTART Postgres \u2014 wal_level is not reloadable)")}`);
280333
- console.log(` ${import_picocolors4.default.cyan(sql[0])}`);
280537
+ console.log(` ${import_picocolors5.default.bold("1.")} Enable logical decoding ${import_picocolors5.default.dim("(then RESTART Postgres \u2014 wal_level is not reloadable)")}`);
280538
+ console.log(` ${import_picocolors5.default.cyan(sql[0])}`);
280334
280539
  console.log(
280335
- import_picocolors4.default.dim(
280336
- ` On Amazon RDS / Aurora you can't ALTER SYSTEM: set ${import_picocolors4.default.bold("rds.logical_replication = 1")} in the
280540
+ import_picocolors5.default.dim(
280541
+ ` On Amazon RDS / Aurora you can't ALTER SYSTEM: set ${import_picocolors5.default.bold("rds.logical_replication = 1")} in the
280337
280542
  instance's parameter group instead, then reboot.`
280338
280543
  )
280339
280544
  );
280340
280545
  console.log(`
280341
- ${import_picocolors4.default.bold("2.")} Publish the tables Ablo should read`);
280342
- console.log(` ${import_picocolors4.default.cyan(sql[1])}`);
280546
+ ${import_picocolors5.default.bold("2.")} Publish the tables Ablo should read`);
280547
+ console.log(` ${import_picocolors5.default.cyan(sql[1])}`);
280343
280548
  if (args.tables.length === 0) {
280344
- console.log(import_picocolors4.default.dim(` (Scope it with ${import_picocolors4.default.bold("ablo connect --tables a,b,c")} to publish a subset.)`));
280549
+ console.log(import_picocolors5.default.dim(` (Scope it with ${import_picocolors5.default.bold("ablo connect --tables a,b,c")} to publish a subset.)`));
280345
280550
  }
280346
280551
  console.log(`
280347
- ${import_picocolors4.default.bold("3.")} Create a least-privilege replication role ${import_picocolors4.default.dim("(pick your own password)")}`);
280348
- console.log(` ${import_picocolors4.default.cyan(sql[2])}`);
280349
- console.log(` ${import_picocolors4.default.cyan(sql[3])}`);
280350
- console.log(` ${import_picocolors4.default.cyan(sql[4])}`);
280552
+ ${import_picocolors5.default.bold("3.")} Create a least-privilege replication role ${import_picocolors5.default.dim("(pick your own password)")}`);
280553
+ console.log(` ${import_picocolors5.default.cyan(sql[2])}`);
280554
+ console.log(` ${import_picocolors5.default.cyan(sql[3])}`);
280555
+ console.log(` ${import_picocolors5.default.cyan(sql[4])}`);
280351
280556
  console.log(
280352
- import_picocolors4.default.dim(
280557
+ import_picocolors5.default.dim(
280353
280558
  ` On Amazon RDS, the REPLICATION attribute is granted, not set directly:
280354
- ${import_picocolors4.default.bold(`GRANT rds_replication TO ${quoteIdent(args.role)};`)}`
280559
+ ${import_picocolors5.default.bold(`GRANT rds_replication TO ${quoteIdent(args.role)};`)}`
280355
280560
  )
280356
280561
  );
280357
280562
  console.log(
280358
280563
  `
280359
- ${import_picocolors4.default.bold("4.")} Put the role's connection string in ${import_picocolors4.default.bold("DATABASE_URL")}, then verify:
280360
- ${import_picocolors4.default.cyan("npx ablo connect --check")}
280564
+ ${import_picocolors5.default.bold("4.")} Put the role's connection string in ${import_picocolors5.default.bold("DATABASE_URL")}, then verify:
280565
+ ${import_picocolors5.default.cyan("npx ablo connect --check")}
280361
280566
  `
280362
280567
  );
280363
280568
  console.log(
280364
- import_picocolors4.default.dim(
280365
- ` Reminder: Ablo never writes to your database on this path. Provisioning tables with
280366
- ${import_picocolors4.default.bold("ablo migrate")} is a separate, optional escape hatch \u2014 connecting a real database is this.`
280569
+ import_picocolors5.default.dim(
280570
+ ` Reminder: this is the READ path \u2014 Ablo tails your WAL and never writes to your database.
280571
+ Your writes keep going through your own backend. (Ablo HOSTING your rows, or dialing in via
280572
+ ${import_picocolors5.default.bold("databaseUrl")}, is the deprecated posture \u2014 see the read-path decision doc.)`
280367
280573
  )
280368
280574
  );
280369
280575
  console.log();
280370
280576
  }
280577
+ var SYNC_INFRA_RELATIONS = [
280578
+ "sync_deltas",
280579
+ "sync_id_seq",
280580
+ "sync_metadata",
280581
+ "mutation_log"
280582
+ ];
280583
+ var SYNC_INFRA_TYPES = [
280584
+ "participant_kind",
280585
+ "backfill_provenance",
280586
+ "confirmation_state"
280587
+ ];
280371
280588
  function printCheckItem(item) {
280372
280589
  if (item.ok) {
280373
- console.log(` ${import_picocolors4.default.green("\u2713")} ${item.label}`);
280590
+ console.log(` ${import_picocolors5.default.green("\u2713")} ${item.label}`);
280374
280591
  } else {
280375
- console.log(` ${import_picocolors4.default.red("\u2717")} ${item.label}`);
280592
+ console.log(` ${import_picocolors5.default.red("\u2717")} ${item.label}`);
280376
280593
  if (item.fix) {
280377
- for (const line of item.fix.split("\n")) console.log(` ${import_picocolors4.default.red("\u2022")} ${line}`);
280594
+ for (const line of item.fix.split("\n")) console.log(` ${import_picocolors5.default.red("\u2022")} ${line}`);
280378
280595
  }
280379
280596
  }
280380
280597
  }
280381
280598
  async function probeReadiness(sql, opts = {}) {
280382
280599
  const publication = opts.publication ?? ABLO_PUBLICATION;
280383
280600
  const items = [];
280384
- const walRows = await sql.unsafe(`SHOW wal_level`);
280601
+ const walRows = await sql.unsafe(
280602
+ `SELECT setting FROM pg_settings WHERE name = 'wal_level'`
280603
+ );
280385
280604
  const walLevel = walRows[0]?.setting ?? "unknown";
280386
280605
  items.push(
280387
- walLevel === "logical" ? { ok: true, label: `wal_level is ${import_picocolors4.default.bold("logical")}` } : {
280606
+ walLevel === "logical" ? { ok: true, label: `wal_level is ${import_picocolors5.default.bold("logical")}` } : {
280388
280607
  ok: false,
280389
- label: `wal_level is ${import_picocolors4.default.bold(walLevel)} (need ${import_picocolors4.default.bold("logical")})`,
280608
+ label: `wal_level is ${import_picocolors5.default.bold(walLevel)} (need ${import_picocolors5.default.bold("logical")})`,
280390
280609
  fix: `ALTER SYSTEM SET wal_level = 'logical'; then RESTART Postgres.
280391
- On RDS/Aurora set rds.logical_replication = 1 in the parameter group, then reboot.`
280610
+ On RDS/Aurora set rds.logical_replication = 1 in the parameter group, then reboot.
280611
+ On Neon enable Logical Replication in the project (Console \u2192 Settings \u2192 Logical Replication, or the API) \u2014 Neon forbids ALTER SYSTEM; the toggle sets wal_level=logical.`
280392
280612
  }
280393
280613
  );
280394
280614
  const pubRows = await sql.unsafe(
@@ -280398,10 +280618,10 @@ On RDS/Aurora set rds.logical_replication = 1 in the parameter group, then reboo
280398
280618
  items.push(
280399
280619
  pubRows.length > 0 ? {
280400
280620
  ok: true,
280401
- label: `publication ${import_picocolors4.default.bold(publication)} exists ${import_picocolors4.default.dim(pubRows[0].puballtables ? "(all tables)" : "(table subset)")}`
280621
+ label: `publication ${import_picocolors5.default.bold(publication)} exists ${import_picocolors5.default.dim(pubRows[0].puballtables ? "(all tables)" : "(table subset)")}`
280402
280622
  } : {
280403
280623
  ok: false,
280404
- label: `publication ${import_picocolors4.default.bold(publication)} not found`,
280624
+ label: `publication ${import_picocolors5.default.bold(publication)} not found`,
280405
280625
  fix: `CREATE PUBLICATION ${quoteIdent(publication)} FOR ALL TABLES;`
280406
280626
  }
280407
280627
  );
@@ -280411,9 +280631,9 @@ On RDS/Aurora set rds.logical_replication = 1 in the parameter group, then reboo
280411
280631
  const role = roleRows[0];
280412
280632
  const hasReplication = Boolean(role && (role.rolreplication || role.rolsuper));
280413
280633
  items.push(
280414
- hasReplication ? { ok: true, label: `DATABASE_URL role can stream replication ${import_picocolors4.default.dim("(REPLICATION)")}` } : {
280634
+ hasReplication ? { ok: true, label: `DATABASE_URL role can stream replication ${import_picocolors5.default.dim("(REPLICATION)")}` } : {
280415
280635
  ok: false,
280416
- label: `DATABASE_URL role lacks the ${import_picocolors4.default.bold("REPLICATION")} attribute`,
280636
+ label: `DATABASE_URL role lacks the ${import_picocolors5.default.bold("REPLICATION")} attribute`,
280417
280637
  fix: `ALTER ROLE current_user WITH REPLICATION;
280418
280638
  On RDS: GRANT rds_replication TO <your_role>;`
280419
280639
  }
@@ -280449,17 +280669,35 @@ On RDS: GRANT rds_replication TO <your_role>;`
280449
280669
  }
280450
280670
  return items;
280451
280671
  }
280452
- async function runCheck() {
280672
+ async function auditTenantSyncInfra(sql) {
280673
+ const artifacts = [];
280674
+ for (const name of SYNC_INFRA_RELATIONS) {
280675
+ const rows = await sql.unsafe(
280676
+ `SELECT to_regclass($1)::text AS reg`,
280677
+ [`public.${name}`]
280678
+ );
280679
+ artifacts.push({ kind: "relation", name, present: rows[0]?.reg != null });
280680
+ }
280681
+ for (const name of SYNC_INFRA_TYPES) {
280682
+ const rows = await sql.unsafe(
280683
+ `SELECT to_regtype($1)::text AS reg`,
280684
+ [`public.${name}`]
280685
+ );
280686
+ artifacts.push({ kind: "type", name, present: rows[0]?.reg != null });
280687
+ }
280688
+ return artifacts;
280689
+ }
280690
+ function requireDatabaseUrl(verb) {
280453
280691
  const dbUrl = readProjectDatabaseUrl();
280454
280692
  if (!dbUrl) {
280455
280693
  console.error(
280456
- import_picocolors4.default.red(" No DATABASE_URL found (checked process env, .env.local, .env).") + import_picocolors4.default.dim(` Set it to the Postgres you want Ablo to read, then re-run ${import_picocolors4.default.bold("ablo connect --check")}.`)
280694
+ import_picocolors5.default.red(" No DATABASE_URL found (checked process env, .env.local, .env).") + import_picocolors5.default.dim(` Set it to the Postgres you want Ablo to read, then re-run ${import_picocolors5.default.bold(`ablo connect ${verb}`)}.`)
280457
280695
  );
280458
280696
  process.exit(1);
280459
280697
  }
280460
- console.log(`
280461
- ${brand("ablo")} ${import_picocolors4.default.dim("connect --check")} ${import_picocolors4.default.dim("logical-replication readiness")}
280462
- `);
280698
+ return dbUrl;
280699
+ }
280700
+ async function probeAndReport(dbUrl) {
280463
280701
  const sql = src_default(dbUrl, { max: 1, prepare: false, onnotice: () => {
280464
280702
  } });
280465
280703
  let items;
@@ -280467,55 +280705,170 @@ async function runCheck() {
280467
280705
  items = await probeReadiness(sql);
280468
280706
  } catch (err) {
280469
280707
  const pg = err ?? {};
280470
- console.error(import_picocolors4.default.red(` Couldn't read the database: ${pg.message ?? String(err)}`));
280708
+ console.error(import_picocolors5.default.red(` Couldn't read the database: ${pg.message ?? String(err)}`));
280471
280709
  await sql.end({ timeout: 2 });
280472
280710
  process.exit(1);
280473
280711
  }
280474
280712
  await sql.end({ timeout: 2 });
280475
280713
  for (const item of items) printCheckItem(item);
280476
- const failures = items.filter((i) => !i.ok).length;
280714
+ return items.filter((i) => !i.ok).length;
280715
+ }
280716
+ async function runCheck() {
280717
+ const dbUrl = requireDatabaseUrl("--check");
280718
+ console.log(`
280719
+ ${brand("ablo")} ${import_picocolors5.default.dim("connect --check")} ${import_picocolors5.default.dim("logical-replication readiness")}
280720
+ `);
280721
+ const failures = await probeAndReport(dbUrl);
280477
280722
  console.log();
280478
280723
  if (failures === 0) {
280479
- console.log(` ${import_picocolors4.default.green("\u2713")} Ready \u2014 Ablo can connect and tail this database's WAL.
280724
+ console.log(` ${import_picocolors5.default.green("\u2713")} Ready \u2014 Ablo can connect and tail this database's WAL.
280480
280725
  `);
280481
280726
  process.exit(0);
280482
280727
  }
280483
280728
  console.log(
280484
- ` ${import_picocolors4.default.red(`${failures} item${failures === 1 ? "" : "s"} to fix`)} ${import_picocolors4.default.dim(`\u2014 apply the fixes above, then re-run ${import_picocolors4.default.bold("ablo connect --check")}.`)}
280729
+ ` ${import_picocolors5.default.red(`${failures} item${failures === 1 ? "" : "s"} to fix`)} ${import_picocolors5.default.dim(`\u2014 apply the fixes above, then re-run ${import_picocolors5.default.bold("ablo connect --check")}.`)}
280485
280730
  `
280486
280731
  );
280487
280732
  process.exit(1);
280488
280733
  }
280734
+ async function runRegister() {
280735
+ const dbUrl = requireDatabaseUrl("--register");
280736
+ const apiKey = resolveApiKey();
280737
+ if (!apiKey) {
280738
+ console.error(
280739
+ import_picocolors5.default.red(" Not logged in.") + import_picocolors5.default.dim(` Run ${import_picocolors5.default.bold("ablo login")} (or set ${import_picocolors5.default.bold("ABLO_API_KEY")}) so Ablo knows which project to register this database for.`)
280740
+ );
280741
+ process.exit(1);
280742
+ }
280743
+ console.log(`
280744
+ ${brand("ablo")} ${import_picocolors5.default.dim("connect --register")} ${import_picocolors5.default.dim("register this database for replication")}
280745
+ `);
280746
+ const failures = await probeAndReport(dbUrl);
280747
+ if (failures > 0) {
280748
+ console.log(
280749
+ `
280750
+ ${import_picocolors5.default.red(`${failures} item${failures === 1 ? "" : "s"} to fix`)} ${import_picocolors5.default.dim("\u2014 a database that isn\u2019t replication-ready can\u2019t stream. Fix the above, then re-run.")}
280751
+ `
280752
+ );
280753
+ process.exit(1);
280754
+ }
280755
+ const apiUrl2 = (process.env.ABLO_API_URL ?? DEFAULT_URL).replace(/\/+$/, "");
280756
+ let res;
280757
+ try {
280758
+ res = await fetch(`${apiUrl2}/v1/datasources`, {
280759
+ method: "POST",
280760
+ headers: { "content-type": "application/json", authorization: `Bearer ${apiKey}` },
280761
+ body: JSON.stringify({ connectionString: dbUrl })
280762
+ });
280763
+ } catch (err) {
280764
+ console.error(import_picocolors5.default.red(`
280765
+ Couldn't reach ${apiUrl2}: ${err instanceof Error ? err.message : String(err)}
280766
+ `));
280767
+ process.exit(1);
280768
+ }
280769
+ if (res.ok) {
280770
+ const body2 = await res.json().catch(() => ({}));
280771
+ console.log(
280772
+ `
280773
+ ${import_picocolors5.default.green("\u2713")} Registered${body2.host ? ` ${import_picocolors5.default.dim(body2.host)}` : ""}${body2.id ? ` ${import_picocolors5.default.dim(`(${body2.id})`)}` : ""} \u2014 Ablo will replicate this database on the next sync.
280774
+ `
280775
+ );
280776
+ process.exit(0);
280777
+ }
280778
+ const body = await res.json().catch(() => ({}));
280779
+ const code = body.error?.code;
280780
+ const message = body.error?.message ?? `HTTP ${res.status}`;
280781
+ console.error(import_picocolors5.default.red(`
280782
+ Registration failed: ${message}`));
280783
+ if (code === "forbidden") {
280784
+ console.error(import_picocolors5.default.dim(` Registering a database needs a ${import_picocolors5.default.bold("secret")} key (sk_\u2026). Run ${import_picocolors5.default.bold("ablo login")} for one.`));
280785
+ } else if (code === "datasource_direct_deprecated") {
280786
+ console.error(
280787
+ import_picocolors5.default.dim(
280788
+ ` This deployment doesn\u2019t accept new connection-string registrations yet. The operator must enable it (${import_picocolors5.default.bold("ABLO_ALLOW_DIRECT_DATASOURCE=true")}) \u2014 see ${import_picocolors5.default.bold("docs/runbooks/connect-customer-database-byo-replication.md")}.`
280789
+ )
280790
+ );
280791
+ } else if (code === "datasource_connection_unsupported") {
280792
+ console.error(
280793
+ import_picocolors5.default.dim(` This deployment can\u2019t accept connection strings \u2014 use a self-hosted/hosted engine, or the signed endpoint fallback.`)
280794
+ );
280795
+ }
280796
+ console.error();
280797
+ process.exit(1);
280798
+ }
280799
+ async function runAuditInfra() {
280800
+ const dbUrl = requireDatabaseUrl("--audit-infra");
280801
+ const sql = src_default(dbUrl, { max: 1, prepare: false, onnotice: () => {
280802
+ } });
280803
+ let artifacts;
280804
+ try {
280805
+ artifacts = await auditTenantSyncInfra(sql);
280806
+ } catch (err) {
280807
+ const pg = err ?? {};
280808
+ console.error(import_picocolors5.default.red(` Couldn't audit the database: ${pg.message ?? String(err)}`));
280809
+ await sql.end({ timeout: 2 });
280810
+ process.exit(1);
280811
+ }
280812
+ await sql.end({ timeout: 2 });
280813
+ console.log(`
280814
+ ${brand("ablo")} ${import_picocolors5.default.dim("connect --audit-infra")} ${import_picocolors5.default.dim("Stage 5 tenant DB sync-infra audit")}
280815
+ `);
280816
+ const present = artifacts.filter((a) => a.present);
280817
+ if (present.length === 0) {
280818
+ console.log(` ${import_picocolors5.default.green("\u2713")} No deprecated Ablo sync infrastructure found in public.
280819
+ `);
280820
+ process.exit(0);
280821
+ }
280822
+ for (const artifact of present) {
280823
+ const label = artifact.kind === "type" ? "type" : "relation";
280824
+ console.log(` ${import_picocolors5.default.yellow("!")} ${label} ${import_picocolors5.default.bold(`public.${artifact.name}`)} exists`);
280825
+ }
280826
+ console.log(
280827
+ `
280828
+ ${import_picocolors5.default.yellow(`${present.length} artifact${present.length === 1 ? "" : "s"} found`)} ` + import_picocolors5.default.dim("\u2014 do not drop automatically. Confirm the org/environment is log-authoritative, then follow ") + import_picocolors5.default.bold("docs/runbooks/wal-stage5-customer-db-infra-cleanup.md") + import_picocolors5.default.dim(".\n")
280829
+ );
280830
+ process.exit(1);
280831
+ }
280489
280832
  async function connect(argv) {
280490
280833
  let args;
280491
280834
  try {
280492
280835
  args = parseConnectArgs(argv);
280493
280836
  } catch (err) {
280494
- console.error(import_picocolors4.default.red(` ${err instanceof Error ? err.message : String(err)}`));
280837
+ console.error(import_picocolors5.default.red(` ${err instanceof Error ? err.message : String(err)}`));
280495
280838
  process.exit(1);
280496
280839
  }
280497
280840
  if (args.check) {
280498
280841
  await runCheck();
280499
280842
  return;
280500
280843
  }
280844
+ if (args.register) {
280845
+ await runRegister();
280846
+ return;
280847
+ }
280848
+ if (args.auditInfra) {
280849
+ await runAuditInfra();
280850
+ return;
280851
+ }
280501
280852
  printConnectRecipe(args);
280502
280853
  }
280503
- var CONNECT_USAGE = ` ablo connect \u2014 connect a real database to Ablo via logical replication (the one way)
280854
+ var CONNECT_USAGE = ` ablo connect \u2014 connect your database for the read path, via logical replication
280504
280855
 
280505
- Ablo READS your WAL and never runs DDL, owns, or migrates your schema. Your app
280506
- keeps writing through your own backend.
280856
+ The Electric/PowerSync/Zero model: Ablo consumes your WAL via logical replication and
280857
+ never runs DDL, owns, hosts, or migrates your schema. Your app continues to own the write path.
280507
280858
 
280508
280859
  Usage:
280509
280860
  npx ablo connect Print the exact setup SQL for your Postgres
280510
280861
  npx ablo connect --tables a,b,c Publish only these tables (default: all tables)
280511
280862
  npx ablo connect --role <name> Name the replication role (default: ablo_replicator)
280512
- npx ablo connect --check Validate DATABASE_URL is replication-ready`;
280863
+ npx ablo connect --check Validate DATABASE_URL is replication-ready
280864
+ npx ablo connect --register Register DATABASE_URL so Ablo replicates it (one self-service step)
280865
+ npx ablo connect --audit-infra Read-only Stage 5 audit for deprecated Ablo sync tables/types`;
280513
280866
 
280514
280867
  // src/cli/generate.ts
280515
280868
  init_cjs_shims();
280516
280869
  var import_fs6 = require("fs");
280517
280870
  var import_path4 = require("path");
280518
- var import_picocolors5 = __toESM(require_picocolors(), 1);
280871
+ var import_picocolors6 = __toESM(require_picocolors(), 1);
280519
280872
  var import_schema4 = require("@abloatai/ablo/schema");
280520
280873
  var DEFAULT_SCHEMA_PATH3 = "ablo/schema.ts";
280521
280874
  var DEFAULT_EXPORT3 = "schema";
@@ -280547,7 +280900,7 @@ async function generate(argv) {
280547
280900
  try {
280548
280901
  args = parseGenerateArgs(argv);
280549
280902
  } catch (err) {
280550
- console.error(import_picocolors5.default.red(` ${err instanceof Error ? err.message : String(err)}`));
280903
+ console.error(import_picocolors6.default.red(` ${err instanceof Error ? err.message : String(err)}`));
280551
280904
  process.exit(1);
280552
280905
  }
280553
280906
  let source;
@@ -280556,18 +280909,18 @@ async function generate(argv) {
280556
280909
  const schemaJson = JSON.parse((0, import_schema4.serializeSchema)(schema));
280557
280910
  source = (0, import_schema4.generateTypes)(schemaJson);
280558
280911
  } catch (err) {
280559
- console.error(import_picocolors5.default.red(` ${err instanceof Error ? err.message : String(err)}`));
280912
+ console.error(import_picocolors6.default.red(` ${err instanceof Error ? err.message : String(err)}`));
280560
280913
  process.exit(1);
280561
280914
  }
280562
280915
  const abs = (0, import_path4.resolve)(process.cwd(), args.out);
280563
280916
  (0, import_fs6.mkdirSync)((0, import_path4.dirname)(abs), { recursive: true });
280564
280917
  (0, import_fs6.writeFileSync)(abs, source);
280565
- console.log(` ${import_picocolors5.default.green("\u2713")} Generated types \u2192 ${import_picocolors5.default.bold(args.out)}`);
280918
+ console.log(` ${import_picocolors6.default.green("\u2713")} Generated types \u2192 ${import_picocolors6.default.bold(args.out)}`);
280566
280919
  }
280567
280920
 
280568
280921
  // src/cli/dev.ts
280569
280922
  init_cjs_shims();
280570
- var import_picocolors6 = __toESM(require_picocolors(), 1);
280923
+ var import_picocolors7 = __toESM(require_picocolors(), 1);
280571
280924
  var import_fs7 = require("fs");
280572
280925
  var import_path5 = require("path");
280573
280926
  var import_schema5 = require("@abloatai/ablo/schema");
@@ -280605,25 +280958,25 @@ function classifyKey(apiKey, activeMode) {
280605
280958
  if (!apiKey) {
280606
280959
  return {
280607
280960
  ok: false,
280608
- reason: `No API key. Run ${import_picocolors6.default.bold("npx ablo login")} for the sandbox dev loop \u2014 or set ${import_picocolors6.default.bold("ABLO_API_KEY")} (${import_picocolors6.default.bold("sk_test_")} = sandbox; ${import_picocolors6.default.bold("sk_live_")} = deliberate production deploy). ` + import_picocolors6.default.dim(`Mode is currently '${activeMode}'.`)
280961
+ reason: `No API key. Run ${import_picocolors7.default.bold("npx ablo login")} for the sandbox dev loop \u2014 or set ${import_picocolors7.default.bold("ABLO_API_KEY")} (${import_picocolors7.default.bold("sk_test_")} = sandbox; ${import_picocolors7.default.bold("sk_live_")} = deliberate production deploy). ` + import_picocolors7.default.dim(`Mode is currently '${activeMode}'.`)
280609
280962
  };
280610
280963
  }
280611
280964
  if (apiKey.startsWith("sk_test_")) return { ok: true };
280612
280965
  if (apiKey.startsWith("sk_live_")) {
280613
280966
  return {
280614
280967
  ok: false,
280615
- reason: `Production schema deploys run one-shot: ${import_picocolors6.default.bold("ABLO_API_KEY=sk_live_\u2026 npx ablo push")} (or ${import_picocolors6.default.bold("ablo mode production")}). ${import_picocolors6.default.bold("--watch")} is sandbox-only.`
280968
+ reason: `Production schema deploys run one-shot: ${import_picocolors7.default.bold("ABLO_API_KEY=sk_live_\u2026 npx ablo push")} (or ${import_picocolors7.default.bold("ablo mode production")}). ${import_picocolors7.default.bold("--watch")} is sandbox-only.`
280616
280969
  };
280617
280970
  }
280618
280971
  if (classifyCredentialKind(apiKey) === "restricted") {
280619
280972
  return {
280620
280973
  ok: false,
280621
- reason: `Restricted (${import_picocolors6.default.bold("rk_")}) keys can't push schema. Use a secret key: ${import_picocolors6.default.bold("sk_test_")} for the sandbox dev loop, or ${import_picocolors6.default.bold("sk_live_")} with ${import_picocolors6.default.bold("npx ablo push")} for a production deploy.`
280974
+ reason: `Restricted (${import_picocolors7.default.bold("rk_")}) keys can't push schema. Use a secret key: ${import_picocolors7.default.bold("sk_test_")} for the sandbox dev loop, or ${import_picocolors7.default.bold("sk_live_")} with ${import_picocolors7.default.bold("npx ablo push")} for a production deploy.`
280622
280975
  };
280623
280976
  }
280624
280977
  return {
280625
280978
  ok: false,
280626
- reason: `${import_picocolors6.default.bold("ABLO_API_KEY")} is not an Ablo key \u2014 expected ${import_picocolors6.default.bold("sk_test_\u2026")} (sandbox) or ${import_picocolors6.default.bold("sk_live_\u2026")} (production deploy via ${import_picocolors6.default.bold("npx ablo push")}).`
280979
+ reason: `${import_picocolors7.default.bold("ABLO_API_KEY")} is not an Ablo key \u2014 expected ${import_picocolors7.default.bold("sk_test_\u2026")} (sandbox) or ${import_picocolors7.default.bold("sk_live_\u2026")} (production deploy via ${import_picocolors7.default.bold("npx ablo push")}).`
280627
280980
  };
280628
280981
  }
280629
280982
  function wireEnvLocal(apiKey, cwd = process.cwd()) {
@@ -280633,19 +280986,19 @@ function wireEnvLocal(apiKey, cwd = process.cwd()) {
280633
280986
  if (!(0, import_fs7.existsSync)(envPath)) {
280634
280987
  (0, import_fs7.writeFileSync)(envPath, `${line}
280635
280988
  `, { mode: 384 });
280636
- action = `Created ${import_picocolors6.default.bold(".env.local")} with ${import_picocolors6.default.bold("ABLO_API_KEY")}`;
280989
+ action = `Created ${import_picocolors7.default.bold(".env.local")} with ${import_picocolors7.default.bold("ABLO_API_KEY")}`;
280637
280990
  } else {
280638
280991
  const content = (0, import_fs7.readFileSync)(envPath, "utf8");
280639
280992
  const match = content.match(/^ABLO_API_KEY=(.*)$/m);
280640
280993
  if (!match) {
280641
280994
  (0, import_fs7.appendFileSync)(envPath, `${content.endsWith("\n") || content.length === 0 ? "" : "\n"}${line}
280642
280995
  `);
280643
- action = `Added ${import_picocolors6.default.bold("ABLO_API_KEY")} to ${import_picocolors6.default.bold(".env.local")}`;
280996
+ action = `Added ${import_picocolors7.default.bold("ABLO_API_KEY")} to ${import_picocolors7.default.bold(".env.local")}`;
280644
280997
  } else if (match[1] === apiKey) {
280645
- action = `${import_picocolors6.default.bold(".env.local")} already has this key`;
280998
+ action = `${import_picocolors7.default.bold(".env.local")} already has this key`;
280646
280999
  } else {
280647
281000
  (0, import_fs7.writeFileSync)(envPath, content.replace(/^ABLO_API_KEY=.*$/m, line));
280648
- action = `Updated ${import_picocolors6.default.bold("ABLO_API_KEY")} in ${import_picocolors6.default.bold(".env.local")} ${import_picocolors6.default.dim(`(was ${match[1].slice(0, 12)}\u2026)`)}`;
281001
+ action = `Updated ${import_picocolors7.default.bold("ABLO_API_KEY")} in ${import_picocolors7.default.bold(".env.local")} ${import_picocolors7.default.dim(`(was ${match[1].slice(0, 12)}\u2026)`)}`;
280649
281002
  }
280650
281003
  }
280651
281004
  const gitignorePath = (0, import_path5.resolve)(cwd, ".gitignore");
@@ -280659,7 +281012,7 @@ function wireEnvLocal(apiKey, cwd = process.cwd()) {
280659
281012
  `}.env.local
280660
281013
  `
280661
281014
  );
280662
- gitignoreNote = ` Added ${import_picocolors6.default.bold(".env.local")} to ${import_picocolors6.default.bold(".gitignore")} so the key can't be committed.`;
281015
+ gitignoreNote = ` Added ${import_picocolors7.default.bold(".env.local")} to ${import_picocolors7.default.bold(".gitignore")} so the key can't be committed.`;
280663
281016
  }
280664
281017
  return `${action}.${gitignoreNote}`;
280665
281018
  }
@@ -280674,7 +281027,7 @@ async function runPush(schema, args) {
280674
281027
  if (ok) {
280675
281028
  return {
280676
281029
  ok: true,
280677
- message: body.unchanged ? `schema unchanged ${import_picocolors6.default.dim(`(v${body.version})`)}` : `schema pushed (sandbox) ${import_picocolors6.default.dim(`(v${body.version}, hash ${body.hash})`)}`
281030
+ message: body.unchanged ? `schema unchanged ${import_picocolors7.default.dim(`(v${body.version})`)}` : `schema pushed (sandbox) ${import_picocolors7.default.dim(`(v${body.version}, hash ${body.hash})`)}`
280678
281031
  };
280679
281032
  }
280680
281033
  if (status2 === 409) {
@@ -280684,33 +281037,33 @@ async function runPush(schema, args) {
280684
281037
  (s) => s.shadowed != null
280685
281038
  );
280686
281039
  const lines = [
280687
- import_picocolors6.default.bold("Incompatible schema change \u2014 not safe to apply as-is."),
281040
+ import_picocolors7.default.bold("Incompatible schema change \u2014 not safe to apply as-is."),
280688
281041
  "",
280689
- ...unexecutable.map((u2) => import_picocolors6.default.red(fmtSignal(u2))),
280690
- ...warnings.map((w2) => import_picocolors6.default.yellow(fmtSignal(w2))),
281042
+ ...unexecutable.map((u2) => import_picocolors7.default.red(fmtSignal(u2))),
281043
+ ...warnings.map((w2) => import_picocolors7.default.yellow(fmtSignal(w2))),
280691
281044
  "",
280692
281045
  ...hasShadowed ? [
280693
- import_picocolors6.default.dim(
281046
+ import_picocolors7.default.dim(
280694
281047
  " These models exist in the baseline above but not in your push. Sandbox readers"
280695
281048
  ),
280696
- import_picocolors6.default.dim(
281049
+ import_picocolors7.default.dim(
280697
281050
  " fall back to the production schema until you push your own, so applying this drops them."
280698
281051
  ),
280699
281052
  ""
280700
281053
  ] : [],
280701
- import_picocolors6.default.dim(
280702
- ` Fix: ${import_picocolors6.default.bold("ablo push --force")} to apply anyway, or ${import_picocolors6.default.bold("--rename old:new")} if you renamed a model.`
281054
+ import_picocolors7.default.dim(
281055
+ ` Fix: ${import_picocolors7.default.bold("ablo push --force")} to apply anyway, or ${import_picocolors7.default.bold("--rename old:new")} if you renamed a model.`
280703
281056
  )
280704
281057
  ];
280705
281058
  return { ok: false, message: lines.join("\n") };
280706
281059
  }
280707
281060
  if (status2 === 403) {
280708
281061
  const serverSays = body.message ?? body.reason;
280709
- const hint = body.code === "database_role_cannot_enforce_rls" ? `Run ${import_picocolors6.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_picocolors6.default.bold("sandbox")} key with ${import_picocolors6.default.bold("schema:push")} \u2014 manage keys at ${import_picocolors6.default.cyan("https://abloatai.com")}.`;
281062
+ const hint = body.code === "database_role_cannot_enforce_rls" ? `Run ${import_picocolors7.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_picocolors7.default.bold("sandbox")} key with ${import_picocolors7.default.bold("schema:push")} \u2014 manage keys at ${import_picocolors7.default.cyan("https://abloatai.com")}.`;
280710
281063
  return {
280711
281064
  ok: false,
280712
281065
  message: `${serverSays ?? "This key can't author schema (missing schema:push scope)."}
280713
- ` + import_picocolors6.default.dim(hint)
281066
+ ` + import_picocolors7.default.dim(hint)
280714
281067
  };
280715
281068
  }
280716
281069
  return { ok: false, message: `Push failed (${status2}): ${body.message ?? body.reason ?? bodyText}` };
@@ -280720,25 +281073,25 @@ async function dev(argv) {
280720
281073
  try {
280721
281074
  args = parseDevArgs(argv);
280722
281075
  } catch (err) {
280723
- console.error(import_picocolors6.default.red(` ${err instanceof Error ? err.message : String(err)}`));
281076
+ console.error(import_picocolors7.default.red(` ${err instanceof Error ? err.message : String(err)}`));
280724
281077
  process.exit(1);
280725
281078
  }
280726
281079
  if (!args.apiKey) args.apiKey = resolveApiKey("sandbox");
280727
281080
  const key = classifyKey(args.apiKey, getMode());
280728
281081
  if (!key.ok) {
280729
- console.error(import_picocolors6.default.red(` ${key.reason}`));
281082
+ console.error(import_picocolors7.default.red(` ${key.reason}`));
280730
281083
  process.exit(1);
280731
281084
  }
280732
281085
  console.log(`
280733
- ${brand("ablo")} ${import_picocolors6.default.dim("push")} ${import_picocolors6.default.dim("(sandbox)")}
281086
+ ${brand("ablo")} ${import_picocolors7.default.dim("push")} ${import_picocolors7.default.dim("(sandbox)")}
280734
281087
  `);
280735
281088
  const schema = await loadSchema(args.schemaPath, args.exportName);
280736
281089
  const modelCount = Object.keys(schema.models).length;
280737
281090
  console.log(
280738
- ` ${import_picocolors6.default.dim("schema")} ${import_picocolors6.default.bold(args.schemaPath)} ${import_picocolors6.default.dim(`(${modelCount} models, hash ${(0, import_schema5.schemaHash)(schema)})`)}`
281091
+ ` ${import_picocolors7.default.dim("schema")} ${import_picocolors7.default.bold(args.schemaPath)} ${import_picocolors7.default.dim(`(${modelCount} models, hash ${(0, import_schema5.schemaHash)(schema)})`)}`
280739
281092
  );
280740
- console.log(` ${import_picocolors6.default.dim("key")} ${args.apiKey.slice(0, 12)}\u2026`);
280741
- console.log(` ${import_picocolors6.default.dim("api")} ${args.url}
281093
+ console.log(` ${import_picocolors7.default.dim("key")} ${args.apiKey.slice(0, 12)}\u2026`);
281094
+ console.log(` ${import_picocolors7.default.dim("api")} ${args.url}
280742
281095
  `);
280743
281096
  const s = Y2();
280744
281097
  s.start("Pushing schema definition (sandbox)");
@@ -280747,16 +281100,16 @@ async function dev(argv) {
280747
281100
  if (!first.ok) process.exit(1);
280748
281101
  if (process.env.ABLO_API_KEY) {
280749
281102
  console.log(`
280750
- ${import_picocolors6.default.green("\u2713")} ${import_picocolors6.default.bold("ABLO_API_KEY")} is set in this shell \u2014 the SDK reads it directly.`);
281103
+ ${import_picocolors7.default.green("\u2713")} ${import_picocolors7.default.bold("ABLO_API_KEY")} is set in this shell \u2014 the SDK reads it directly.`);
280751
281104
  } else {
280752
281105
  console.log(`
280753
- ${import_picocolors6.default.green("\u2713")} ${wireEnvLocal(args.apiKey)}`);
280754
- console.log(` ${import_picocolors6.default.dim("Frameworks load it automatically; plain Node: node --env-file=.env.local app.ts")}`);
281106
+ ${import_picocolors7.default.green("\u2713")} ${wireEnvLocal(args.apiKey)}`);
281107
+ console.log(` ${import_picocolors7.default.dim("Frameworks load it automatically; plain Node: node --env-file=.env.local app.ts")}`);
280755
281108
  }
280756
281109
  console.log(` Your app is wired for the sandbox.`);
280757
281110
  if (!args.watch) return;
280758
281111
  const abs = (0, import_path5.resolve)(process.cwd(), args.schemaPath);
280759
- console.log(` ${import_picocolors6.default.dim(`watching ${args.schemaPath} \u2026 (Ctrl-C to stop)`)}
281112
+ console.log(` ${import_picocolors7.default.dim(`watching ${args.schemaPath} \u2026 (Ctrl-C to stop)`)}
280760
281113
  `);
280761
281114
  let timer2 = null;
280762
281115
  let pushing = false;
@@ -280776,7 +281129,7 @@ async function dev(argv) {
280776
281129
  const r2 = await runPush(next, args);
280777
281130
  s2.stop(r2.message, r2.ok ? 0 : 1);
280778
281131
  } catch (err) {
280779
- s2.stop(import_picocolors6.default.red(`schema reload failed: ${err instanceof Error ? err.message : String(err)}`), 1);
281132
+ s2.stop(import_picocolors7.default.red(`schema reload failed: ${err instanceof Error ? err.message : String(err)}`), 1);
280780
281133
  } finally {
280781
281134
  pushing = false;
280782
281135
  }
@@ -280784,7 +281137,7 @@ async function dev(argv) {
280784
281137
  const stop = () => {
280785
281138
  watcher.close();
280786
281139
  console.log(`
280787
- ${import_picocolors6.default.dim("stopped.")}`);
281140
+ ${import_picocolors7.default.dim("stopped.")}`);
280788
281141
  process.exit(0);
280789
281142
  };
280790
281143
  process.on("SIGINT", stop);
@@ -280795,8 +281148,8 @@ async function dev(argv) {
280795
281148
 
280796
281149
  // src/cli/login.ts
280797
281150
  init_cjs_shims();
280798
- var import_child_process = require("child_process");
280799
- var import_picocolors7 = __toESM(require_picocolors(), 1);
281151
+ var import_child_process2 = require("child_process");
281152
+ var import_picocolors8 = __toESM(require_picocolors(), 1);
280800
281153
  var CLIENT_ID = "ablo-cli";
280801
281154
  var stripSlash = (u2) => u2.replace(/\/+$/, "");
280802
281155
  var AUTH_URL = stripSlash(process.env.ABLO_AUTH_URL ?? "https://auth.abloatai.com");
@@ -280805,7 +281158,7 @@ var sleep = (ms) => new Promise((r2) => setTimeout(r2, ms));
280805
281158
  function openBrowser(url) {
280806
281159
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
280807
281160
  try {
280808
- const child = (0, import_child_process.spawn)(cmd, [url], { stdio: "ignore", detached: true, shell: process.platform === "win32" });
281161
+ const child = (0, import_child_process2.spawn)(cmd, [url], { stdio: "ignore", detached: true, shell: process.platform === "win32" });
280809
281162
  child.on("error", () => {
280810
281163
  });
280811
281164
  child.unref();
@@ -280854,9 +281207,9 @@ async function deviceLogin(argv, deps = {}) {
280854
281207
  const code = await codeRes.json();
280855
281208
  const approvePath = `/cli?user_code=${code.user_code}`;
280856
281209
  const url = account === "signup" ? `${DASHBOARD_URL}/signup?next=${encodeURIComponent(approvePath)}` : `${DASHBOARD_URL}${approvePath}`;
280857
- Me(`${import_picocolors7.default.bold(code.user_code)}
281210
+ Me(`${import_picocolors8.default.bold(code.user_code)}
280858
281211
 
280859
- ${import_picocolors7.default.dim(url)}`, "Approve in your browser");
281212
+ ${import_picocolors8.default.dim(url)}`, "Approve in your browser");
280860
281213
  openUrl(url);
280861
281214
  const s = Y2();
280862
281215
  s.start("Waiting for approval\u2026");
@@ -280923,7 +281276,7 @@ ${import_picocolors7.default.dim(url)}`, "Approve in your browser");
280923
281276
  if (reason) M2.error(reason);
280924
281277
  else if (provRes) M2.error(`Key provisioning returned ${provRes.status} from ${DASHBOARD_URL}/api/cli/provision-key.`);
280925
281278
  M2.error(
280926
- `The browser approval succeeded but the key handoff failed. Try again, or grab a ${import_picocolors7.default.bold("sk_test_")} key from the dashboard and set ${import_picocolors7.default.bold("ABLO_API_KEY")}.`
281279
+ `The browser approval succeeded but the key handoff failed. Try again, or grab a ${import_picocolors8.default.bold("sk_test_")} key from the dashboard and set ${import_picocolors8.default.bold("ABLO_API_KEY")}.`
280927
281280
  );
280928
281281
  process.exit(1);
280929
281282
  }
@@ -280943,9 +281296,9 @@ ${import_picocolors7.default.dim(url)}`, "Approve in your browser");
280943
281296
  { mode: "sandbox", activeProject: prov.project ?? void 0 }
280944
281297
  );
280945
281298
  s.stop(`Saved keys to ${path}`);
280946
- const where = prov.project ? ` ${import_picocolors7.default.dim(`(project ${prov.project.slug})`)}` : "";
281299
+ const where = prov.project ? ` ${import_picocolors8.default.dim(`(project ${prov.project.slug})`)}` : "";
280947
281300
  Se(
280948
- `${import_picocolors7.default.green("\u2713")} Logged in ${import_picocolors7.default.dim("(sandbox)")}${where}. Run ${import_picocolors7.default.bold("npx ablo push")} to push your schema.`
281301
+ `${import_picocolors8.default.green("\u2713")} Logged in ${import_picocolors8.default.dim("(sandbox)")}${where}. Run ${import_picocolors8.default.bold("npx ablo push")} to push your schema.`
280949
281302
  );
280950
281303
  }
280951
281304
  async function login(argv = [], deps = {}) {
@@ -280954,20 +281307,20 @@ async function login(argv = [], deps = {}) {
280954
281307
  function logout() {
280955
281308
  const removed = clearCredential();
280956
281309
  if (removed) {
280957
- console.log(` ${import_picocolors7.default.green("\u2713")} Logged out ${import_picocolors7.default.dim(`(credentials removed from ${configDir()})`)}`);
281310
+ console.log(` ${import_picocolors8.default.green("\u2713")} Logged out ${import_picocolors8.default.dim(`(credentials removed from ${configDir()})`)}`);
280958
281311
  } else {
280959
- console.log(` ${import_picocolors7.default.dim("\u25CB")} Not logged in \u2014 nothing to remove.`);
281312
+ console.log(` ${import_picocolors8.default.dim("\u25CB")} Not logged in \u2014 nothing to remove.`);
280960
281313
  }
280961
281314
  if (process.env.ABLO_API_KEY) {
280962
281315
  console.log(
280963
- import_picocolors7.default.dim(` Note: ${import_picocolors7.default.bold("ABLO_API_KEY")} is still set in this shell and takes precedence.`)
281316
+ import_picocolors8.default.dim(` Note: ${import_picocolors8.default.bold("ABLO_API_KEY")} is still set in this shell and takes precedence.`)
280964
281317
  );
280965
281318
  }
280966
281319
  }
280967
281320
 
280968
281321
  // src/cli/mode.ts
280969
281322
  init_cjs_shims();
280970
- var import_picocolors8 = __toESM(require_picocolors(), 1);
281323
+ var import_picocolors9 = __toESM(require_picocolors(), 1);
280971
281324
  var PREFIX = { sandbox: "sk_test_", production: "rk_live_" };
280972
281325
  function hintFor(m2, current) {
280973
281326
  const parts = [];
@@ -280977,10 +281330,10 @@ function hintFor(m2, current) {
280977
281330
  }
280978
281331
  function apply(m2) {
280979
281332
  setMode(m2);
280980
- console.log(` ${import_picocolors8.default.green("\u2713")} now in ${import_picocolors8.default.bold(m2)}`);
281333
+ console.log(` ${import_picocolors9.default.green("\u2713")} now in ${import_picocolors9.default.bold(m2)}`);
280981
281334
  if (!getKeyEntry(m2)) {
280982
281335
  console.log(
280983
- import_picocolors8.default.dim(` No ${m2} key stored \u2014 run ${import_picocolors8.default.bold("ablo login")} or ${import_picocolors8.default.bold(`ablo login --api-key ${PREFIX[m2]}\u2026`)}.`)
281336
+ import_picocolors9.default.dim(` No ${m2} key stored \u2014 run ${import_picocolors9.default.bold("ablo login")} or ${import_picocolors9.default.bold(`ablo login --api-key ${PREFIX[m2]}\u2026`)}.`)
280984
281337
  );
280985
281338
  }
280986
281339
  }
@@ -280993,14 +281346,14 @@ async function mode(argv) {
280993
281346
  }
280994
281347
  if (arg) {
280995
281348
  console.error(
280996
- import_picocolors8.default.red(` unknown mode: ${arg}`) + import_picocolors8.default.dim(` (expected ${import_picocolors8.default.bold("sandbox")} or ${import_picocolors8.default.bold("production")})`)
281349
+ import_picocolors9.default.red(` unknown mode: ${arg}`) + import_picocolors9.default.dim(` (expected ${import_picocolors9.default.bold("sandbox")} or ${import_picocolors9.default.bold("production")})`)
280997
281350
  );
280998
281351
  process.exit(1);
280999
281352
  }
281000
281353
  const current = getMode();
281001
281354
  if (!process.stdin.isTTY || process.env.CI) {
281002
281355
  console.error(
281003
- import_picocolors8.default.red(" `ablo mode` needs an argument without a TTY: ") + import_picocolors8.default.bold("ablo mode sandbox") + import_picocolors8.default.dim(" | ") + import_picocolors8.default.bold("ablo mode production") + import_picocolors8.default.dim(` (current: ${current})`)
281356
+ import_picocolors9.default.red(" `ablo mode` needs an argument without a TTY: ") + import_picocolors9.default.bold("ablo mode sandbox") + import_picocolors9.default.dim(" | ") + import_picocolors9.default.bold("ablo mode production") + import_picocolors9.default.dim(` (current: ${current})`)
281004
281357
  );
281005
281358
  process.exit(1);
281006
281359
  }
@@ -281021,7 +281374,7 @@ async function mode(argv) {
281021
281374
 
281022
281375
  // src/cli/projects.ts
281023
281376
  init_cjs_shims();
281024
- var import_picocolors9 = __toESM(require_picocolors(), 1);
281377
+ var import_picocolors10 = __toESM(require_picocolors(), 1);
281025
281378
  function apiUrl() {
281026
281379
  return (process.env.ABLO_API_URL ?? DEFAULT_URL).replace(/\/+$/, "");
281027
281380
  }
@@ -281029,8 +281382,8 @@ function requireKey() {
281029
281382
  const apiKey = resolveApiKey();
281030
281383
  if (!apiKey) {
281031
281384
  console.error(
281032
- import_picocolors9.default.red(" No API key.") + import_picocolors9.default.dim(
281033
- ` Run ${import_picocolors9.default.bold("npx ablo login")} \u2014 or set ${import_picocolors9.default.bold("ABLO_API_KEY")} (${import_picocolors9.default.bold("sk_test_")} = sandbox; ${import_picocolors9.default.bold("sk_live_")} = production).`
281385
+ import_picocolors10.default.red(" No API key.") + import_picocolors10.default.dim(
281386
+ ` Run ${import_picocolors10.default.bold("npx ablo login")} \u2014 or set ${import_picocolors10.default.bold("ABLO_API_KEY")} (${import_picocolors10.default.bold("sk_test_")} = sandbox; ${import_picocolors10.default.bold("sk_live_")} = production).`
281034
281387
  )
281035
281388
  );
281036
281389
  process.exit(1);
@@ -281065,7 +281418,7 @@ async function listProjects(apiKey) {
281065
281418
  async function fetchProjects() {
281066
281419
  const all = await listProjects(requireKey());
281067
281420
  if (!all) {
281068
- console.error(import_picocolors9.default.red(" Could not list projects \u2014 is the API reachable and the key valid?"));
281421
+ console.error(import_picocolors10.default.red(" Could not list projects \u2014 is the API reachable and the key valid?"));
281069
281422
  process.exit(1);
281070
281423
  }
281071
281424
  return all;
@@ -281105,10 +281458,10 @@ function printList(projects2) {
281105
281458
  const active = getActiveProject();
281106
281459
  for (const p2 of projects2) {
281107
281460
  const isActive = active ? active.id === p2.id : p2.default;
281108
- const marker = isActive ? import_picocolors9.default.green("\u25CF") : import_picocolors9.default.dim("\u25CB");
281109
- const tags = [p2.default ? import_picocolors9.default.dim("default") : "", isActive ? import_picocolors9.default.green("active") : ""].filter(Boolean).join(import_picocolors9.default.dim(", "));
281461
+ const marker = isActive ? import_picocolors10.default.green("\u25CF") : import_picocolors10.default.dim("\u25CB");
281462
+ const tags = [p2.default ? import_picocolors10.default.dim("default") : "", isActive ? import_picocolors10.default.green("active") : ""].filter(Boolean).join(import_picocolors10.default.dim(", "));
281110
281463
  console.log(
281111
- ` ${marker} ${p2.slug.padEnd(20)} ${import_picocolors9.default.dim(p2.id)}${tags ? ` ${tags}` : ""}`
281464
+ ` ${marker} ${p2.slug.padEnd(20)} ${import_picocolors10.default.dim(p2.id)}${tags ? ` ${tags}` : ""}`
281112
281465
  );
281113
281466
  }
281114
281467
  }
@@ -281116,7 +281469,7 @@ async function projects(argv) {
281116
281469
  const sub = argv[0];
281117
281470
  if (sub === "list" || sub === void 0) {
281118
281471
  console.log(`
281119
- ${brand("ablo")} ${import_picocolors9.default.dim("projects")}
281472
+ ${brand("ablo")} ${import_picocolors10.default.dim("projects")}
281120
281473
  `);
281121
281474
  printList(await fetchProjects());
281122
281475
  console.log();
@@ -281125,7 +281478,7 @@ async function projects(argv) {
281125
281478
  if (sub === "create") {
281126
281479
  const slug = argv[1];
281127
281480
  if (!slug || slug.startsWith("-")) {
281128
- console.error(import_picocolors9.default.red(' usage: ablo projects create <slug> [--name "Display Name"]'));
281481
+ console.error(import_picocolors10.default.red(' usage: ablo projects create <slug> [--name "Display Name"]'));
281129
281482
  process.exit(1);
281130
281483
  }
281131
281484
  const nameIdx = argv.indexOf("--name");
@@ -281136,17 +281489,17 @@ async function projects(argv) {
281136
281489
  });
281137
281490
  if (status2 !== 201) {
281138
281491
  console.error(
281139
- import_picocolors9.default.red(` Create failed (${status2}): ${String(body.message ?? body.code ?? "")}`)
281492
+ import_picocolors10.default.red(` Create failed (${status2}): ${String(body.message ?? body.code ?? "")}`)
281140
281493
  );
281141
281494
  if (body.code === "project_slug_taken") {
281142
- console.error(import_picocolors9.default.dim(` Pick another slug, or switch to it: ${import_picocolors9.default.bold(`ablo projects use ${slug}`)}`));
281495
+ console.error(import_picocolors10.default.dim(` Pick another slug, or switch to it: ${import_picocolors10.default.bold(`ablo projects use ${slug}`)}`));
281143
281496
  }
281144
281497
  process.exit(1);
281145
281498
  }
281146
281499
  const created = body;
281147
- console.log(` ${import_picocolors9.default.green("\u2713")} Created project ${import_picocolors9.default.bold(created.slug)} ${import_picocolors9.default.dim(`(${created.id})`)}`);
281500
+ console.log(` ${import_picocolors10.default.green("\u2713")} Created project ${import_picocolors10.default.bold(created.slug)} ${import_picocolors10.default.dim(`(${created.id})`)}`);
281148
281501
  console.log(
281149
- import_picocolors9.default.dim(` Make it active with ${import_picocolors9.default.bold(`ablo projects use ${created.slug}`)}; mint its keys in the dashboard.`)
281502
+ import_picocolors10.default.dim(` Make it active with ${import_picocolors10.default.bold(`ablo projects use ${created.slug}`)}; mint its keys in the dashboard.`)
281150
281503
  );
281151
281504
  return;
281152
281505
  }
@@ -281154,17 +281507,17 @@ async function projects(argv) {
281154
281507
  const ref = argv[1];
281155
281508
  const name = argv.slice(2).join(" ").trim();
281156
281509
  if (!ref || ref.startsWith("-") || !name) {
281157
- console.error(import_picocolors9.default.red(" usage: ablo projects rename <slug|id> <new name>"));
281510
+ console.error(import_picocolors10.default.red(" usage: ablo projects rename <slug|id> <new name>"));
281158
281511
  process.exit(1);
281159
281512
  }
281160
281513
  const all = await fetchProjects();
281161
281514
  const target = all.find((p2) => p2.slug === ref || p2.id === ref);
281162
281515
  if (!target) {
281163
- console.error(import_picocolors9.default.red(` No project "${ref}".`) + import_picocolors9.default.dim(" Run ablo projects list."));
281516
+ console.error(import_picocolors10.default.red(` No project "${ref}".`) + import_picocolors10.default.dim(" Run ablo projects list."));
281164
281517
  process.exit(1);
281165
281518
  }
281166
281519
  if (target.default) {
281167
- console.error(import_picocolors9.default.red(" The default project cannot be renamed."));
281520
+ console.error(import_picocolors10.default.red(" The default project cannot be renamed."));
281168
281521
  process.exit(1);
281169
281522
  }
281170
281523
  const { status: status2, body } = await request(`/api/v1/projects/${target.id}`, requireKey(), {
@@ -281173,47 +281526,47 @@ async function projects(argv) {
281173
281526
  });
281174
281527
  if (status2 !== 200) {
281175
281528
  console.error(
281176
- import_picocolors9.default.red(` Rename failed (${status2}): ${String(body.message ?? body.code ?? "")}`)
281529
+ import_picocolors10.default.red(` Rename failed (${status2}): ${String(body.message ?? body.code ?? "")}`)
281177
281530
  );
281178
281531
  process.exit(1);
281179
281532
  }
281180
281533
  const updated = body;
281181
281534
  console.log(
281182
- ` ${import_picocolors9.default.green("\u2713")} Renamed ${import_picocolors9.default.bold(updated.slug)} \u2192 ${import_picocolors9.default.bold(updated.name ?? updated.slug)} ${import_picocolors9.default.dim(`(${updated.id})`)}`
281535
+ ` ${import_picocolors10.default.green("\u2713")} Renamed ${import_picocolors10.default.bold(updated.slug)} \u2192 ${import_picocolors10.default.bold(updated.name ?? updated.slug)} ${import_picocolors10.default.dim(`(${updated.id})`)}`
281183
281536
  );
281184
281537
  return;
281185
281538
  }
281186
281539
  if (sub === "use") {
281187
281540
  const ref = argv[1];
281188
281541
  if (!ref) {
281189
- console.error(import_picocolors9.default.red(" usage: ablo projects use <slug|id|default>"));
281542
+ console.error(import_picocolors10.default.red(" usage: ablo projects use <slug|id|default>"));
281190
281543
  process.exit(1);
281191
281544
  }
281192
281545
  const all = await fetchProjects();
281193
281546
  const target = all.find((p2) => p2.slug === ref || p2.id === ref);
281194
281547
  if (!target) {
281195
- console.error(import_picocolors9.default.red(` No project "${ref}".`) + import_picocolors9.default.dim(" Run ablo projects list."));
281548
+ console.error(import_picocolors10.default.red(` No project "${ref}".`) + import_picocolors10.default.dim(" Run ablo projects list."));
281196
281549
  process.exit(1);
281197
281550
  }
281198
281551
  if (target.default) {
281199
281552
  setActiveProject(void 0);
281200
- console.log(` ${import_picocolors9.default.green("\u2713")} now targeting the ${import_picocolors9.default.bold("default")} project`);
281553
+ console.log(` ${import_picocolors10.default.green("\u2713")} now targeting the ${import_picocolors10.default.bold("default")} project`);
281201
281554
  } else {
281202
281555
  setActiveProject({ id: target.id, slug: target.slug });
281203
- console.log(` ${import_picocolors9.default.green("\u2713")} now targeting project ${import_picocolors9.default.bold(target.slug)} ${import_picocolors9.default.dim(`(${target.id})`)}`);
281556
+ console.log(` ${import_picocolors10.default.green("\u2713")} now targeting project ${import_picocolors10.default.bold(target.slug)} ${import_picocolors10.default.dim(`(${target.id})`)}`);
281204
281557
  }
281205
281558
  const guard = guardActiveProjectKey();
281206
281559
  if (!guard.ok) {
281207
281560
  const loginCmd = guard.activeProfile === DEFAULT_PROFILE ? "ablo login" : `ablo login --project ${guard.activeProfile}`;
281208
281561
  console.log(
281209
- import_picocolors9.default.dim(` No key stored for this project yet \u2014 run ${import_picocolors9.default.bold(loginCmd)} to mint one.`)
281562
+ import_picocolors10.default.dim(` No key stored for this project yet \u2014 run ${import_picocolors10.default.bold(loginCmd)} to mint one.`)
281210
281563
  );
281211
281564
  }
281212
281565
  return;
281213
281566
  }
281214
281567
  console.error(
281215
- import_picocolors9.default.red(` unknown subcommand: ${sub}`) + import_picocolors9.default.dim(
281216
- ` (expected ${import_picocolors9.default.bold("list")}, ${import_picocolors9.default.bold("create")}, ${import_picocolors9.default.bold("rename")}, or ${import_picocolors9.default.bold("use")})`
281568
+ import_picocolors10.default.red(` unknown subcommand: ${sub}`) + import_picocolors10.default.dim(
281569
+ ` (expected ${import_picocolors10.default.bold("list")}, ${import_picocolors10.default.bold("create")}, ${import_picocolors10.default.bold("rename")}, or ${import_picocolors10.default.bold("use")})`
281217
281570
  )
281218
281571
  );
281219
281572
  process.exit(1);
@@ -281221,13 +281574,13 @@ async function projects(argv) {
281221
281574
 
281222
281575
  // src/cli/status.ts
281223
281576
  init_cjs_shims();
281224
- var import_picocolors10 = __toESM(require_picocolors(), 1);
281577
+ var import_picocolors11 = __toESM(require_picocolors(), 1);
281225
281578
  function expiryLabel(iso) {
281226
281579
  const ms = Date.parse(iso) - Date.now();
281227
281580
  if (Number.isNaN(ms)) return "";
281228
- if (ms <= 0) return import_picocolors10.default.red("expired");
281581
+ if (ms <= 0) return import_picocolors11.default.red("expired");
281229
281582
  const days = Math.floor(ms / (24 * 60 * 60 * 1e3));
281230
- return import_picocolors10.default.dim(days > 0 ? `expires in ${days}d` : "expires <1d");
281583
+ return import_picocolors11.default.dim(days > 0 ? `expires in ${days}d` : "expires <1d");
281231
281584
  }
281232
281585
  async function ping(apiUrl2) {
281233
281586
  const ctrl = new AbortController();
@@ -281258,6 +281611,45 @@ async function fetchPushedSchema(apiUrl2, apiKey) {
281258
281611
  clearTimeout(t);
281259
281612
  }
281260
281613
  }
281614
+ async function sampleRead(apiUrl2, apiKey, modelTypename, n) {
281615
+ const ctrl = new AbortController();
281616
+ const t = setTimeout(() => ctrl.abort(), 4e3);
281617
+ try {
281618
+ const res = await fetch(
281619
+ `${apiUrl2}/v1/models/${encodeURIComponent(modelTypename)}/__ablo_health_probe_${n}__`,
281620
+ { headers: { authorization: `Bearer ${apiKey}` }, signal: ctrl.signal }
281621
+ );
281622
+ if (res.ok) return "routed";
281623
+ let code;
281624
+ try {
281625
+ const body = await res.json();
281626
+ code = body.code ?? body.error?.code;
281627
+ } catch {
281628
+ }
281629
+ if (code === "entity_not_found") return "routed";
281630
+ if (code === "tenant_routing_failed") return "no_route";
281631
+ if (res.status === 401 || res.status === 403) return { forbidden: code };
281632
+ return { other: `${res.status}${code ? ` ${code}` : ""}` };
281633
+ } catch {
281634
+ return { other: "unreachable" };
281635
+ } finally {
281636
+ clearTimeout(t);
281637
+ }
281638
+ }
281639
+ async function probeDataPlane(apiUrl2, apiKey, modelTypename) {
281640
+ if (!apiKey) return { status: "skipped" };
281641
+ const samples = [];
281642
+ for (let i = 0; i < 3; i++) samples.push(await sampleRead(apiUrl2, apiKey, modelTypename, i));
281643
+ const forbidden = samples.find((s) => typeof s === "object" && "forbidden" in s);
281644
+ if (forbidden) return { status: "forbidden", detail: forbidden.forbidden };
281645
+ const routed = samples.filter((s) => s === "routed").length;
281646
+ const noRoute = samples.filter((s) => s === "no_route").length;
281647
+ if (routed === samples.length) return { status: "ok" };
281648
+ if (noRoute === samples.length) return { status: "no_database" };
281649
+ if (routed > 0 && noRoute > 0) return { status: "intermittent", ok: routed, failed: noRoute };
281650
+ const other = samples.find((s) => typeof s === "object" && "other" in s);
281651
+ return { status: "unknown", detail: other?.other ?? "inconclusive" };
281652
+ }
281261
281653
  function formatConflict(conflict) {
281262
281654
  if (!conflict) return "";
281263
281655
  const parts = ["user", "agent", "system"].flatMap((k3) => conflict[k3] ? [`${k3}:${conflict[k3]}`] : []);
@@ -281309,59 +281701,81 @@ async function status(args = []) {
281309
281701
  return;
281310
281702
  }
281311
281703
  console.log(`
281312
- ${brand("ablo")} ${import_picocolors10.default.dim("status")}
281704
+ ${brand("ablo")} ${import_picocolors11.default.dim("status")}
281313
281705
  `);
281314
281706
  if (process.env.ABLO_API_KEY) {
281315
281707
  console.log(
281316
- ` ${import_picocolors10.default.dim("key")} ${process.env.ABLO_API_KEY.slice(0, 12)}\u2026 ${import_picocolors10.default.dim("(ABLO_API_KEY env \u2014 overrides stored)")}`
281708
+ ` ${import_picocolors11.default.dim("key")} ${process.env.ABLO_API_KEY.slice(0, 12)}\u2026 ${import_picocolors11.default.dim("(ABLO_API_KEY env \u2014 overrides stored)")}`
281317
281709
  );
281318
281710
  } else if (!cfg) {
281319
- console.log(` ${import_picocolors10.default.yellow("!")} Not logged in \u2014 run ${import_picocolors10.default.bold("ablo login")}.`);
281711
+ console.log(` ${import_picocolors11.default.yellow("!")} Not logged in \u2014 run ${import_picocolors11.default.bold("ablo login")}.`);
281320
281712
  }
281321
- console.log(` ${import_picocolors10.default.dim("mode")} ${import_picocolors10.default.bold(mode2)}`);
281713
+ console.log(` ${import_picocolors11.default.dim("mode")} ${import_picocolors11.default.bold(mode2)}`);
281322
281714
  const activeEntry = getKeyEntry(mode2);
281323
281715
  const key = describeEffectiveKey(mode2, process.env.ABLO_API_KEY, activeEntry);
281324
281716
  if (key.keyMismatch) {
281325
- console.log(` ${import_picocolors10.default.yellow("!")} ${import_picocolors10.default.yellow(key.keyMismatch.message)}`);
281717
+ console.log(` ${import_picocolors11.default.yellow("!")} ${import_picocolors11.default.yellow(key.keyMismatch.message)}`);
281326
281718
  }
281327
281719
  const activeProject = getActiveProject();
281328
281720
  console.log(
281329
- ` ${import_picocolors10.default.dim("project")} ${activeProject ? `${import_picocolors10.default.bold(activeProject.slug)} ${import_picocolors10.default.dim(`(${activeProject.id})`)}` : import_picocolors10.default.bold("default")}`
281721
+ ` ${import_picocolors11.default.dim("project")} ${activeProject ? `${import_picocolors11.default.bold(activeProject.slug)} ${import_picocolors11.default.dim(`(${activeProject.id})`)}` : import_picocolors11.default.bold("default")}`
281330
281722
  );
281331
281723
  for (const m2 of ["sandbox", "production"]) {
281332
281724
  const entry = getKeyEntry(m2);
281333
- const marker = m2 === mode2 ? import_picocolors10.default.green("\u25CF") : import_picocolors10.default.dim("\u25CB");
281725
+ const marker = m2 === mode2 ? import_picocolors11.default.green("\u25CF") : import_picocolors11.default.dim("\u25CB");
281334
281726
  if (entry) {
281335
281727
  const exp = entry.expiresAt ? ` ${expiryLabel(entry.expiresAt)}` : "";
281336
- console.log(` ${marker} ${m2.padEnd(10)} ${import_picocolors10.default.dim(`${entry.apiKey.slice(0, 12)}\u2026`)}${exp}`);
281728
+ console.log(` ${marker} ${m2.padEnd(10)} ${import_picocolors11.default.dim(`${entry.apiKey.slice(0, 12)}\u2026`)}${exp}`);
281337
281729
  } else {
281338
- console.log(` ${marker} ${m2.padEnd(10)} ${import_picocolors10.default.dim("\u2014 no key")}`);
281730
+ console.log(` ${marker} ${m2.padEnd(10)} ${import_picocolors11.default.dim("\u2014 no key")}`);
281339
281731
  }
281340
281732
  }
281341
281733
  const org = activeEntry?.organizationId;
281342
- if (org) console.log(` ${import_picocolors10.default.dim("org")} ${org}`);
281734
+ if (org) console.log(` ${import_picocolors11.default.dim("org")} ${org}`);
281343
281735
  const plan = resolvePushPlan();
281344
281736
  console.log(
281345
- ` ${import_picocolors10.default.dim("push")} ${plan.apiKey ? `${import_picocolors10.default.bold(plan.flow)} ${import_picocolors10.default.dim(`with ${plan.apiKey.slice(0, 12)}\u2026 (${plan.source})`)}` : `${import_picocolors10.default.bold(plan.flow)} ${import_picocolors10.default.yellow("\u2014 no credential")} ${import_picocolors10.default.dim(`(run ${import_picocolors10.default.bold("ablo login")} or set ${import_picocolors10.default.bold("ABLO_API_KEY")})`)}`}`
281737
+ ` ${import_picocolors11.default.dim("push")} ${plan.apiKey ? `${import_picocolors11.default.bold(plan.flow)} ${import_picocolors11.default.dim(`with ${plan.apiKey.slice(0, 12)}\u2026 (${plan.source})`)}` : `${import_picocolors11.default.bold(plan.flow)} ${import_picocolors11.default.yellow("\u2014 no credential")} ${import_picocolors11.default.dim(`(run ${import_picocolors11.default.bold("ablo login")} or set ${import_picocolors11.default.bold("ABLO_API_KEY")})`)}`}`
281346
281738
  );
281347
- process.stdout.write(` ${import_picocolors10.default.dim("api")} ${apiUrl2} `);
281739
+ process.stdout.write(` ${import_picocolors11.default.dim("api")} ${apiUrl2} `);
281348
281740
  const reachable = await ping(apiUrl2);
281349
- console.log(reachable ? import_picocolors10.default.green("reachable") : import_picocolors10.default.red("unreachable"));
281741
+ console.log(reachable ? import_picocolors11.default.green("reachable") : import_picocolors11.default.red("unreachable"));
281350
281742
  if (reachable) {
281351
281743
  const introspectKey = process.env.ABLO_API_KEY ?? activeEntry?.apiKey;
281352
281744
  const pushed = await fetchPushedSchema(apiUrl2, introspectKey);
281353
281745
  if (pushed && pushed.active) {
281354
- const when = pushed.pushedAt ? ` ${import_picocolors10.default.dim(`@ ${pushed.pushedAt.slice(0, 10)}`)}` : "";
281355
- const ver = pushed.version != null ? ` ${import_picocolors10.default.dim(`(rev ${pushed.version})`)}` : "";
281356
- console.log(` ${import_picocolors10.default.dim("schema")} ${import_picocolors10.default.bold(`${pushed.models.length} models pushed`)}${ver}${when}`);
281746
+ const when = pushed.pushedAt ? ` ${import_picocolors11.default.dim(`@ ${pushed.pushedAt.slice(0, 10)}`)}` : "";
281747
+ const ver = pushed.version != null ? ` ${import_picocolors11.default.dim(`(rev ${pushed.version})`)}` : "";
281748
+ console.log(` ${import_picocolors11.default.dim("schema")} ${import_picocolors11.default.bold(`${pushed.models.length} models pushed`)}${ver}${when}`);
281357
281749
  for (const m2 of pushed.models) {
281358
- const tn = m2.typename === m2.key ? import_picocolors10.default.dim(`typename=${m2.typename}`) : import_picocolors10.default.yellow(`typename=${m2.typename}`);
281750
+ const tn = m2.typename === m2.key ? import_picocolors11.default.dim(`typename=${m2.typename}`) : import_picocolors11.default.yellow(`typename=${m2.typename}`);
281359
281751
  const conflict = formatConflict(m2.conflict);
281360
- const conflictStr = conflict ? ` ${import_picocolors10.default.dim(`conflict=${conflict}`)}` : "";
281361
- console.log(` ${import_picocolors10.default.dim("\u2022")} ${m2.key.padEnd(14)} ${tn}${conflictStr}`);
281752
+ const conflictStr2 = conflict ? ` ${import_picocolors11.default.dim(`conflict=${conflict}`)}` : "";
281753
+ console.log(` ${import_picocolors11.default.dim("\u2022")} ${m2.key.padEnd(14)} ${tn}${conflictStr2}`);
281362
281754
  }
281363
281755
  } else if (pushed && !pushed.active) {
281364
- console.log(` ${import_picocolors10.default.dim("schema")} ${import_picocolors10.default.yellow("none pushed")} ${import_picocolors10.default.dim(`(run ${import_picocolors10.default.bold("ablo push")} or ${import_picocolors10.default.bold("ablo dev")})`)}`);
281756
+ console.log(` ${import_picocolors11.default.dim("schema")} ${import_picocolors11.default.yellow("none pushed")} ${import_picocolors11.default.dim(`(run ${import_picocolors11.default.bold("ablo push")} or ${import_picocolors11.default.bold("ablo dev")})`)}`);
281757
+ }
281758
+ if (pushed && pushed.active && pushed.models.length > 0) {
281759
+ const probe = await probeDataPlane(apiUrl2, introspectKey, pushed.models[0].typename);
281760
+ if (probe.status === "no_database") {
281761
+ console.log(` ${import_picocolors11.default.dim("data")} ${import_picocolors11.default.red("\u2717 no database registered")}${org ? import_picocolors11.default.dim(` for org ${org}`) : ""}`);
281762
+ console.log(
281763
+ ` ${import_picocolors11.default.dim(
281764
+ `reads/writes will fail with ${import_picocolors11.default.bold("tenant_routing_failed")}. Connect one with ${import_picocolors11.default.bold("ablo connect")}, or point ${import_picocolors11.default.bold("ABLO_API_KEY")} at an org that has a database.`
281765
+ )}`
281766
+ );
281767
+ } else if (probe.status === "intermittent") {
281768
+ console.log(` ${import_picocolors11.default.dim("data")} ${import_picocolors11.default.red(`\u2717 database routing is intermittent`)} ${import_picocolors11.default.dim(`(${probe.ok} ok / ${probe.failed} failed of ${probe.ok + probe.failed})`)}${org ? import_picocolors11.default.dim(` for org ${org}`) : ""}`);
281769
+ console.log(
281770
+ ` ${import_picocolors11.default.dim(
281771
+ `some reads/writes fail with ${import_picocolors11.default.bold("tenant_routing_failed")} \u2014 the registration is unstable. Re-establish it with ${import_picocolors11.default.bold("ablo connect")} (or check for a recent server redeploy).`
281772
+ )}`
281773
+ );
281774
+ } else if (probe.status === "forbidden") {
281775
+ console.log(` ${import_picocolors11.default.dim("data")} ${import_picocolors11.default.yellow("? key not authorized to read")}${probe.detail ? import_picocolors11.default.dim(` (${probe.detail})`) : ""}`);
281776
+ } else if (probe.status === "unknown") {
281777
+ console.log(` ${import_picocolors11.default.dim("data")} ${import_picocolors11.default.yellow(`? data-plane check inconclusive (${probe.detail})`)}`);
281778
+ }
281365
281779
  }
281366
281780
  }
281367
281781
  console.log();
@@ -281369,7 +281783,7 @@ async function status(args = []) {
281369
281783
 
281370
281784
  // src/cli/logs.ts
281371
281785
  init_cjs_shims();
281372
- var import_picocolors11 = __toESM(require_picocolors(), 1);
281786
+ var import_picocolors12 = __toESM(require_picocolors(), 1);
281373
281787
  function parseLogsArgs(argv) {
281374
281788
  const args = {
281375
281789
  follow: true,
@@ -281433,10 +281847,10 @@ function resolveSince(since) {
281433
281847
  var sleep2 = (ms) => new Promise((r2) => setTimeout(r2, ms));
281434
281848
  function colorOp(op) {
281435
281849
  const label = op.padEnd(6);
281436
- if (op === "create") return import_picocolors11.default.green(label);
281437
- if (op === "update") return import_picocolors11.default.yellow(label);
281438
- if (op === "delete") return import_picocolors11.default.red(label);
281439
- return import_picocolors11.default.dim(label);
281850
+ if (op === "create") return import_picocolors12.default.green(label);
281851
+ if (op === "update") return import_picocolors12.default.yellow(label);
281852
+ if (op === "delete") return import_picocolors12.default.red(label);
281853
+ return import_picocolors12.default.dim(label);
281440
281854
  }
281441
281855
  function render(e2, json) {
281442
281856
  if (json) {
@@ -281445,21 +281859,21 @@ function render(e2, json) {
281445
281859
  return;
281446
281860
  }
281447
281861
  const t = new Date(e2.at).toLocaleTimeString();
281448
- const actor = e2.actor ? import_picocolors11.default.dim(` ${e2.actor}`) : "";
281449
- console.log(` ${import_picocolors11.default.dim(t)} ${colorOp(e2.op)} ${import_picocolors11.default.bold(e2.model)} ${import_picocolors11.default.dim(e2.recordId)}${actor}`);
281862
+ const actor = e2.actor ? import_picocolors12.default.dim(` ${e2.actor}`) : "";
281863
+ console.log(` ${import_picocolors12.default.dim(t)} ${colorOp(e2.op)} ${import_picocolors12.default.bold(e2.model)} ${import_picocolors12.default.dim(e2.recordId)}${actor}`);
281450
281864
  }
281451
281865
  async function logs(argv) {
281452
281866
  let args;
281453
281867
  try {
281454
281868
  args = parseLogsArgs(argv);
281455
281869
  } catch (err) {
281456
- console.error(import_picocolors11.default.red(` ${err instanceof Error ? err.message : String(err)}`));
281870
+ console.error(import_picocolors12.default.red(` ${err instanceof Error ? err.message : String(err)}`));
281457
281871
  process.exit(1);
281458
281872
  }
281459
281873
  const apiKey = resolveApiKey(args.mode);
281460
281874
  if (!apiKey) {
281461
281875
  console.error(
281462
- import_picocolors11.default.red(` No API key.`) + import_picocolors11.default.dim(` Run ${import_picocolors11.default.bold("ablo login")} or set ${import_picocolors11.default.bold("ABLO_API_KEY")}.`)
281876
+ import_picocolors12.default.red(` No API key.`) + import_picocolors12.default.dim(` Run ${import_picocolors12.default.bold("ablo login")} or set ${import_picocolors12.default.bold("ABLO_API_KEY")}.`)
281463
281877
  );
281464
281878
  process.exit(1);
281465
281879
  }
@@ -281473,7 +281887,7 @@ async function logs(argv) {
281473
281887
  if (!res) return null;
281474
281888
  if (!res.ok) {
281475
281889
  const body = await res.json().catch(() => ({}));
281476
- console.error(import_picocolors11.default.red(` logs failed (${res.status}): ${body.reason ?? body.message ?? ""}`));
281890
+ console.error(import_picocolors12.default.red(` logs failed (${res.status}): ${body.reason ?? body.message ?? ""}`));
281477
281891
  process.exit(1);
281478
281892
  }
281479
281893
  const json = await res.json();
@@ -281484,7 +281898,7 @@ async function logs(argv) {
281484
281898
  }
281485
281899
  if (!args.json) {
281486
281900
  console.log(`
281487
- ${brand("ablo")} ${import_picocolors11.default.dim("logs")} ${import_picocolors11.default.dim(`(${args.mode ?? "active"} mode)`)}
281901
+ ${brand("ablo")} ${import_picocolors12.default.dim("logs")} ${import_picocolors12.default.dim(`(${args.mode ?? "active"} mode)`)}
281488
281902
  `);
281489
281903
  }
281490
281904
  const initial = await fetchPage({
@@ -281494,13 +281908,13 @@ async function logs(argv) {
281494
281908
  ...args.op ? { op: args.op } : {}
281495
281909
  });
281496
281910
  if (!initial) {
281497
- console.error(import_picocolors11.default.red(` Couldn't reach ${baseUrl2}.`));
281911
+ console.error(import_picocolors12.default.red(` Couldn't reach ${baseUrl2}.`));
281498
281912
  process.exit(1);
281499
281913
  }
281500
281914
  for (const e2 of initial.events) render(e2, args.json);
281501
281915
  let cursor = initial.cursor;
281502
281916
  if (!args.follow) return;
281503
- if (!args.json) console.log(` ${import_picocolors11.default.dim("watching for new activity \u2026 (Ctrl-C to stop)")}
281917
+ if (!args.json) console.log(` ${import_picocolors12.default.dim("watching for new activity \u2026 (Ctrl-C to stop)")}
281504
281918
  `);
281505
281919
  for (; ; ) {
281506
281920
  await sleep2(1500);
@@ -281518,7 +281932,7 @@ async function logs(argv) {
281518
281932
  // src/cli/webhooks.ts
281519
281933
  init_cjs_shims();
281520
281934
  var import_fs8 = require("fs");
281521
- var import_picocolors12 = __toESM(require_picocolors(), 1);
281935
+ var import_picocolors13 = __toESM(require_picocolors(), 1);
281522
281936
  var ENV_KEY = "ABLO_WEBHOOK_SECRET";
281523
281937
  function flag(args, name) {
281524
281938
  const inline = args.find((a) => a.startsWith(`${name}=`));
@@ -281545,12 +281959,12 @@ function requireKey2(mode2) {
281545
281959
  const apiKey = resolveApiKey(mode2);
281546
281960
  if (!apiKey) {
281547
281961
  console.error(
281548
- import_picocolors12.default.red(" No API key.") + import_picocolors12.default.dim(` Run ${import_picocolors12.default.bold("ablo login")} or set ${import_picocolors12.default.bold("ABLO_API_KEY")}.`)
281962
+ import_picocolors13.default.red(" No API key.") + import_picocolors13.default.dim(` Run ${import_picocolors13.default.bold("ablo login")} or set ${import_picocolors13.default.bold("ABLO_API_KEY")}.`)
281549
281963
  );
281550
281964
  process.exit(1);
281551
281965
  }
281552
281966
  if (classifyCredentialKind(apiKey) !== "secret") {
281553
- console.error(import_picocolors12.default.red(" Managing webhooks requires a secret key ") + import_picocolors12.default.dim("(sk_test_ / sk_live_)."));
281967
+ console.error(import_picocolors13.default.red(" Managing webhooks requires a secret key ") + import_picocolors13.default.dim("(sk_test_ / sk_live_)."));
281554
281968
  process.exit(1);
281555
281969
  }
281556
281970
  return apiKey;
@@ -281566,12 +281980,12 @@ async function api(apiKey, method, path, body) {
281566
281980
  ...body ? { body: JSON.stringify(body) } : {}
281567
281981
  }).catch(() => null);
281568
281982
  if (!res) {
281569
- console.error(import_picocolors12.default.red(` Couldn't reach ${baseUrl()}.`));
281983
+ console.error(import_picocolors13.default.red(` Couldn't reach ${baseUrl()}.`));
281570
281984
  process.exit(1);
281571
281985
  }
281572
281986
  if (!res.ok) {
281573
281987
  const err = await res.json().catch(() => ({}));
281574
- console.error(import_picocolors12.default.red(` Request failed (${res.status}): ${err.message ?? err.reason ?? ""}`));
281988
+ console.error(import_picocolors13.default.red(` Request failed (${res.status}): ${err.message ?? err.reason ?? ""}`));
281575
281989
  process.exit(1);
281576
281990
  }
281577
281991
  return await res.json();
@@ -281593,11 +282007,11 @@ ${line}
281593
282007
  return file;
281594
282008
  }
281595
282009
  function printEndpoint(e2) {
281596
- const dot = e2.status === "enabled" ? import_picocolors12.default.green("\u25CF") : import_picocolors12.default.red("\u25CF");
281597
- const health = e2.last_error ? import_picocolors12.default.red(` last error: ${e2.last_error}`) : "";
281598
- console.log(` ${dot} ${import_picocolors12.default.bold(e2.id)} ${e2.url}`);
282010
+ const dot = e2.status === "enabled" ? import_picocolors13.default.green("\u25CF") : import_picocolors13.default.red("\u25CF");
282011
+ const health = e2.last_error ? import_picocolors13.default.red(` last error: ${e2.last_error}`) : "";
282012
+ console.log(` ${dot} ${import_picocolors13.default.bold(e2.id)} ${e2.url}`);
281599
282013
  console.log(
281600
- import_picocolors12.default.dim(
282014
+ import_picocolors13.default.dim(
281601
282015
  ` ${e2.status} \xB7 ${e2.environment} \xB7 events ${e2.enabled_events.join(",")} \xB7 cursor ${e2.cursor ?? "\u2014"}${health}`
281602
282016
  )
281603
282017
  );
@@ -281609,7 +282023,7 @@ async function webhooks(argv) {
281609
282023
  if (sub === "create") {
281610
282024
  const url = positional(rest);
281611
282025
  if (!url) {
281612
- console.error(import_picocolors12.default.red(" Usage: ") + brand("ablo webhooks create <url>"));
282026
+ console.error(import_picocolors13.default.red(" Usage: ") + brand("ablo webhooks create <url>"));
281613
282027
  process.exit(1);
281614
282028
  }
281615
282029
  const apiKey = requireKey2(mode2);
@@ -281621,8 +282035,8 @@ async function webhooks(argv) {
281621
282035
  });
281622
282036
  const file = writeSecretToEnv(created.secret);
281623
282037
  console.log(`
281624
- ${import_picocolors12.default.green("\u2713")} Registered ${import_picocolors12.default.bold(created.id)} \u2192 ${created.url}`);
281625
- console.log(` ${import_picocolors12.default.green("\u2713")} Wrote ${import_picocolors12.default.bold(ENV_KEY)} to ${import_picocolors12.default.bold(file)} ${import_picocolors12.default.dim("(shown once)")}
282038
+ ${import_picocolors13.default.green("\u2713")} Registered ${import_picocolors13.default.bold(created.id)} \u2192 ${created.url}`);
282039
+ console.log(` ${import_picocolors13.default.green("\u2713")} Wrote ${import_picocolors13.default.bold(ENV_KEY)} to ${import_picocolors13.default.bold(file)} ${import_picocolors13.default.dim("(shown once)")}
281626
282040
  `);
281627
282041
  return;
281628
282042
  }
@@ -281630,7 +282044,7 @@ async function webhooks(argv) {
281630
282044
  const apiKey = requireKey2(mode2);
281631
282045
  const { data } = await api(apiKey, "GET", "");
281632
282046
  if (data.length === 0) {
281633
- console.log(import_picocolors12.default.dim(" No webhook endpoints. ") + brand("ablo webhooks create <url>"));
282047
+ console.log(import_picocolors13.default.dim(" No webhook endpoints. ") + brand("ablo webhooks create <url>"));
281634
282048
  return;
281635
282049
  }
281636
282050
  console.log();
@@ -281641,40 +282055,40 @@ async function webhooks(argv) {
281641
282055
  if (sub === "roll") {
281642
282056
  const id = positional(rest);
281643
282057
  if (!id) {
281644
- console.error(import_picocolors12.default.red(" Usage: ") + brand("ablo webhooks roll <id>"));
282058
+ console.error(import_picocolors13.default.red(" Usage: ") + brand("ablo webhooks roll <id>"));
281645
282059
  process.exit(1);
281646
282060
  }
281647
282061
  const apiKey = requireKey2(mode2);
281648
282062
  const rolled = await api(apiKey, "POST", `/${id}/roll_secret`);
281649
282063
  const file = writeSecretToEnv(rolled.secret);
281650
282064
  console.log(`
281651
- ${import_picocolors12.default.green("\u2713")} Rolled secret for ${import_picocolors12.default.bold(id)} \u2192 ${import_picocolors12.default.bold(file)} ${import_picocolors12.default.dim("(old secret now invalid)")}
282065
+ ${import_picocolors13.default.green("\u2713")} Rolled secret for ${import_picocolors13.default.bold(id)} \u2192 ${import_picocolors13.default.bold(file)} ${import_picocolors13.default.dim("(old secret now invalid)")}
281652
282066
  `);
281653
282067
  return;
281654
282068
  }
281655
282069
  if (sub === "enable") {
281656
282070
  const id = positional(rest);
281657
282071
  if (!id) {
281658
- console.error(import_picocolors12.default.red(" Usage: ") + brand("ablo webhooks enable <id>"));
282072
+ console.error(import_picocolors13.default.red(" Usage: ") + brand("ablo webhooks enable <id>"));
281659
282073
  process.exit(1);
281660
282074
  }
281661
282075
  const apiKey = requireKey2(mode2);
281662
282076
  const e2 = await api(apiKey, "POST", `/${id}/enable`);
281663
- console.log(` ${import_picocolors12.default.green("\u2713")} Re-enabled ${import_picocolors12.default.bold(e2.id)}`);
282077
+ console.log(` ${import_picocolors13.default.green("\u2713")} Re-enabled ${import_picocolors13.default.bold(e2.id)}`);
281664
282078
  return;
281665
282079
  }
281666
282080
  if (sub === "rm" || sub === "delete") {
281667
282081
  const id = positional(rest);
281668
282082
  if (!id) {
281669
- console.error(import_picocolors12.default.red(" Usage: ") + brand("ablo webhooks rm <id>"));
282083
+ console.error(import_picocolors13.default.red(" Usage: ") + brand("ablo webhooks rm <id>"));
281670
282084
  process.exit(1);
281671
282085
  }
281672
282086
  const apiKey = requireKey2(mode2);
281673
282087
  await api(apiKey, "DELETE", `/${id}`);
281674
- console.log(` ${import_picocolors12.default.green("\u2713")} Removed ${import_picocolors12.default.bold(id)}`);
282088
+ console.log(` ${import_picocolors13.default.green("\u2713")} Removed ${import_picocolors13.default.bold(id)}`);
281675
282089
  return;
281676
282090
  }
281677
- console.log(` ${import_picocolors12.default.bold("Usage:")}`);
282091
+ console.log(` ${import_picocolors13.default.bold("Usage:")}`);
281678
282092
  console.log(` ${brand("ablo webhooks create <url>")} Register an endpoint; writes ${ENV_KEY}`);
281679
282093
  console.log(` ${brand("ablo webhooks list")} List endpoints + delivery health`);
281680
282094
  console.log(` ${brand("ablo webhooks roll <id>")} Mint a fresh signing secret`);
@@ -281685,7 +282099,7 @@ async function webhooks(argv) {
281685
282099
 
281686
282100
  // src/cli/check.ts
281687
282101
  init_cjs_shims();
281688
- var import_picocolors13 = __toESM(require_picocolors(), 1);
282102
+ var import_picocolors14 = __toESM(require_picocolors(), 1);
281689
282103
  var import_schema6 = require("@abloatai/ablo/schema");
281690
282104
  var DEFAULT_SCHEMA_PATH4 = "ablo/schema.ts";
281691
282105
  var DEFAULT_EXPORT4 = "schema";
@@ -281720,13 +282134,13 @@ async function check(argv) {
281720
282134
  try {
281721
282135
  args = parseCheckArgs(argv);
281722
282136
  } catch (err) {
281723
- console.error(import_picocolors13.default.red(` ${err instanceof Error ? err.message : String(err)}`));
282137
+ console.error(import_picocolors14.default.red(` ${err instanceof Error ? err.message : String(err)}`));
281724
282138
  process.exit(1);
281725
282139
  }
281726
282140
  const dbUrl = process.env.DATABASE_URL ?? process.env.ABLO_DATABASE_URL;
281727
282141
  if (!dbUrl) {
281728
282142
  console.error(
281729
- import_picocolors13.default.red(` No database.`) + import_picocolors13.default.dim(` Set ${import_picocolors13.default.bold("DATABASE_URL")} to the Postgres you want Ablo to adopt.`)
282143
+ import_picocolors14.default.red(` No database.`) + import_picocolors14.default.dim(` Set ${import_picocolors14.default.bold("DATABASE_URL")} to the Postgres you want Ablo to adopt.`)
281730
282144
  );
281731
282145
  process.exit(1);
281732
282146
  }
@@ -281741,7 +282155,7 @@ async function check(argv) {
281741
282155
  [args.appSchema]
281742
282156
  );
281743
282157
  } catch (err) {
281744
- console.error(import_picocolors13.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
282158
+ console.error(import_picocolors14.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
281745
282159
  await sql.end({ timeout: 2 });
281746
282160
  process.exit(1);
281747
282161
  }
@@ -281756,7 +282170,7 @@ async function check(argv) {
281756
282170
  set.add(r2.column_name);
281757
282171
  }
281758
282172
  console.log(`
281759
- ${brand("ablo")} ${import_picocolors13.default.dim("check")} ${import_picocolors13.default.dim(`schema "${args.appSchema}"`)}
282173
+ ${brand("ablo")} ${import_picocolors14.default.dim("check")} ${import_picocolors14.default.dim(`schema "${args.appSchema}"`)}
281760
282174
  `);
281761
282175
  const declaredTables = /* @__PURE__ */ new Set();
281762
282176
  let errors = 0;
@@ -281766,7 +282180,7 @@ async function check(argv) {
281766
282180
  declaredTables.add(table);
281767
282181
  const present = colsByTable.get(table);
281768
282182
  if (!present) {
281769
- console.log(` ${import_picocolors13.default.red("\u2717")} ${import_picocolors13.default.bold(key)} ${import_picocolors13.default.dim("\u2192")} table ${import_picocolors13.default.bold(table)} ${import_picocolors13.default.red("not found")}`);
282183
+ console.log(` ${import_picocolors14.default.red("\u2717")} ${import_picocolors14.default.bold(key)} ${import_picocolors14.default.dim("\u2192")} table ${import_picocolors14.default.bold(table)} ${import_picocolors14.default.red("not found")}`);
281770
282184
  errors++;
281771
282185
  continue;
281772
282186
  }
@@ -281788,26 +282202,26 @@ async function check(argv) {
281788
282202
  if (!present.has(col)) problems.push(`missing column "${col}" (field ${fieldName})`);
281789
282203
  }
281790
282204
  if (problems.length > 0) {
281791
- console.log(` ${import_picocolors13.default.red("\u2717")} ${import_picocolors13.default.bold(key)} ${import_picocolors13.default.dim("\u2192")} ${table}`);
281792
- for (const p2 of problems) console.log(` ${import_picocolors13.default.red("\u2022")} ${p2}`);
281793
- for (const w2 of warns) console.log(` ${import_picocolors13.default.yellow("\u2022")} ${w2}`);
282205
+ console.log(` ${import_picocolors14.default.red("\u2717")} ${import_picocolors14.default.bold(key)} ${import_picocolors14.default.dim("\u2192")} ${table}`);
282206
+ for (const p2 of problems) console.log(` ${import_picocolors14.default.red("\u2022")} ${p2}`);
282207
+ for (const w2 of warns) console.log(` ${import_picocolors14.default.yellow("\u2022")} ${w2}`);
281794
282208
  errors++;
281795
282209
  } else if (warns.length > 0) {
281796
- console.log(` ${import_picocolors13.default.yellow("!")} ${import_picocolors13.default.bold(key)} ${import_picocolors13.default.dim("\u2192")} ${table}`);
281797
- for (const w2 of warns) console.log(` ${import_picocolors13.default.yellow("\u2022")} ${w2}`);
282210
+ console.log(` ${import_picocolors14.default.yellow("!")} ${import_picocolors14.default.bold(key)} ${import_picocolors14.default.dim("\u2192")} ${table}`);
282211
+ for (const w2 of warns) console.log(` ${import_picocolors14.default.yellow("\u2022")} ${w2}`);
281798
282212
  warnings++;
281799
282213
  } else {
281800
- console.log(` ${import_picocolors13.default.green("\u2713")} ${import_picocolors13.default.bold(key)} ${import_picocolors13.default.dim(`\u2192 ${table} (id, ${orgCol ?? "no org"} ok)`)}`);
282214
+ console.log(` ${import_picocolors14.default.green("\u2713")} ${import_picocolors14.default.bold(key)} ${import_picocolors14.default.dim(`\u2192 ${table} (id, ${orgCol ?? "no org"} ok)`)}`);
281801
282215
  }
281802
282216
  }
281803
282217
  const modelCount = Object.keys(schemaJson.models).length;
281804
282218
  const ignored = [...colsByTable.keys()].filter((t) => !declaredTables.has(t)).length;
281805
282219
  console.log(
281806
282220
  `
281807
- ${modelCount} model${modelCount === 1 ? "" : "s"} \xB7 ${import_picocolors13.default.green(`${modelCount - errors - warnings} ok`)}` + (warnings ? ` \xB7 ${import_picocolors13.default.yellow(`${warnings} warning${warnings === 1 ? "" : "s"}`)}` : "") + (errors ? ` \xB7 ${import_picocolors13.default.red(`${errors} error${errors === 1 ? "" : "s"}`)}` : "")
282221
+ ${modelCount} model${modelCount === 1 ? "" : "s"} \xB7 ${import_picocolors14.default.green(`${modelCount - errors - warnings} ok`)}` + (warnings ? ` \xB7 ${import_picocolors14.default.yellow(`${warnings} warning${warnings === 1 ? "" : "s"}`)}` : "") + (errors ? ` \xB7 ${import_picocolors14.default.red(`${errors} error${errors === 1 ? "" : "s"}`)}` : "")
281808
282222
  );
281809
282223
  if (ignored > 0) {
281810
- console.log(` ${import_picocolors13.default.dim(`${ignored} other table${ignored === 1 ? "" : "s"} in your database \u2014 ignored by Ablo`)}`);
282224
+ console.log(` ${import_picocolors14.default.dim(`${ignored} other table${ignored === 1 ? "" : "s"} in your database \u2014 ignored by Ablo`)}`);
281811
282225
  }
281812
282226
  console.log();
281813
282227
  process.exit(errors > 0 ? 1 : 0);
@@ -281815,7 +282229,7 @@ async function check(argv) {
281815
282229
 
281816
282230
  // src/cli/upgrade.ts
281817
282231
  init_cjs_shims();
281818
- var import_picocolors14 = __toESM(require_picocolors(), 1);
282232
+ var import_picocolors15 = __toESM(require_picocolors(), 1);
281819
282233
  var import_ts_morph = __toESM(require_ts_morph(), 1);
281820
282234
  var DEFAULT_GLOBS = ["app/**/*.{ts,tsx}", "src/**/*.{ts,tsx}", "ablo/**/*.{ts,tsx}", "lib/**/*.{ts,tsx}"];
281821
282235
  var VERB_ARGS = {
@@ -281893,7 +282307,7 @@ async function upgrade(argv) {
281893
282307
  project.addSourceFilesAtPaths(globs.length > 0 ? globs : DEFAULT_GLOBS);
281894
282308
  const files = project.getSourceFiles();
281895
282309
  if (files.length === 0) {
281896
- console.log(import_picocolors14.default.yellow(' No .ts/.tsx files found. Pass a glob, e.g. `ablo upgrade "src/**/*.tsx"`.'));
282310
+ console.log(import_picocolors15.default.yellow(' No .ts/.tsx files found. Pass a glob, e.g. `ablo upgrade "src/**/*.tsx"`.'));
281897
282311
  return;
281898
282312
  }
281899
282313
  const edits = [];
@@ -281967,38 +282381,38 @@ async function upgrade(argv) {
281967
282381
  const rel = (f) => f.replace(cwd + "/", "");
281968
282382
  console.log();
281969
282383
  if (edits.length === 0 && manual.length === 0) {
281970
- console.log(import_picocolors14.default.green(" \u2713 Nothing to migrate \u2014 your code is already on the current API."));
282384
+ console.log(import_picocolors15.default.green(" \u2713 Nothing to migrate \u2014 your code is already on the current API."));
281971
282385
  return;
281972
282386
  }
281973
282387
  if (edits.length > 0) {
281974
- console.log(import_picocolors14.default.bold(` ${write ? "Applied" : "Would apply"} ${edits.length} change${edits.length === 1 ? "" : "s"}:`));
282388
+ console.log(import_picocolors15.default.bold(` ${write ? "Applied" : "Would apply"} ${edits.length} change${edits.length === 1 ? "" : "s"}:`));
281975
282389
  for (const e2 of edits) {
281976
- console.log(` ${import_picocolors14.default.dim(`${rel(e2.file)}:${e2.line}`)} ${import_picocolors14.default.cyan(e2.rule)}`);
281977
- console.log(` ${import_picocolors14.default.red("-")} ${e2.before}`);
281978
- console.log(` ${import_picocolors14.default.green("+")} ${e2.after}`);
282390
+ console.log(` ${import_picocolors15.default.dim(`${rel(e2.file)}:${e2.line}`)} ${import_picocolors15.default.cyan(e2.rule)}`);
282391
+ console.log(` ${import_picocolors15.default.red("-")} ${e2.before}`);
282392
+ console.log(` ${import_picocolors15.default.green("+")} ${e2.after}`);
281979
282393
  }
281980
282394
  }
281981
282395
  if (manual.length > 0) {
281982
282396
  console.log();
281983
- console.log(import_picocolors14.default.bold(import_picocolors14.default.yellow(` ${manual.length} spot${manual.length === 1 ? "" : "s"} need manual review (structural):`)));
282397
+ console.log(import_picocolors15.default.bold(import_picocolors15.default.yellow(` ${manual.length} spot${manual.length === 1 ? "" : "s"} need manual review (structural):`)));
281984
282398
  for (const m2 of manual) {
281985
- console.log(` ${import_picocolors14.default.dim(`${rel(m2.file)}:${m2.line}`)} ${import_picocolors14.default.yellow(m2.rule)}`);
281986
- console.log(` ${import_picocolors14.default.dim(m2.snippet)}`);
282399
+ console.log(` ${import_picocolors15.default.dim(`${rel(m2.file)}:${m2.line}`)} ${import_picocolors15.default.yellow(m2.rule)}`);
282400
+ console.log(` ${import_picocolors15.default.dim(m2.snippet)}`);
281987
282401
  console.log(` \u2192 ${m2.hint}`);
281988
282402
  }
281989
282403
  }
281990
282404
  console.log();
281991
282405
  if (write) {
281992
282406
  await project.save();
281993
- console.log(import_picocolors14.default.green(` \u2713 Wrote ${edits.length} change${edits.length === 1 ? "" : "s"}. Review the diff, run your typecheck.`));
282407
+ console.log(import_picocolors15.default.green(` \u2713 Wrote ${edits.length} change${edits.length === 1 ? "" : "s"}. Review the diff, run your typecheck.`));
281994
282408
  } else {
281995
- console.log(import_picocolors14.default.dim(" Dry run. Re-run with `--write` to apply the auto-fixes above (manual items are never auto-written)."));
282409
+ console.log(import_picocolors15.default.dim(" Dry run. Re-run with `--write` to apply the auto-fixes above (manual items are never auto-written)."));
281996
282410
  }
281997
282411
  }
281998
282412
 
281999
282413
  // src/cli/pull.ts
282000
282414
  init_cjs_shims();
282001
- var import_picocolors15 = __toESM(require_picocolors(), 1);
282415
+ var import_picocolors16 = __toESM(require_picocolors(), 1);
282002
282416
  var import_fs9 = require("fs");
282003
282417
  var DEFAULT_OUT2 = "ablo/schema.ts";
282004
282418
  var DEFAULT_IMPORT = "@abloatai/ablo/schema";
@@ -282110,52 +282524,52 @@ async function pull(argv) {
282110
282524
  try {
282111
282525
  args = parsePullArgs(argv);
282112
282526
  } catch (err) {
282113
- console.error(import_picocolors15.default.red(` ${err instanceof Error ? err.message : String(err)}`));
282527
+ console.error(import_picocolors16.default.red(` ${err instanceof Error ? err.message : String(err)}`));
282114
282528
  process.exit(1);
282115
282529
  }
282116
282530
  const dbUrl = process.env.DATABASE_URL ?? process.env.ABLO_DATABASE_URL;
282117
282531
  if (!dbUrl) {
282118
- console.error(import_picocolors15.default.red(` No database.`) + import_picocolors15.default.dim(` Set ${import_picocolors15.default.bold("DATABASE_URL")} to the Postgres to pull from.`));
282532
+ console.error(import_picocolors16.default.red(` No database.`) + import_picocolors16.default.dim(` Set ${import_picocolors16.default.bold("DATABASE_URL")} to the Postgres to pull from.`));
282119
282533
  process.exit(1);
282120
282534
  }
282121
282535
  if ((0, import_fs9.existsSync)(args.out) && !args.force) {
282122
282536
  console.error(
282123
- import_picocolors15.default.red(` ${args.out} already exists.`) + import_picocolors15.default.dim(` Re-run with ${import_picocolors15.default.bold("--force")} to overwrite.`)
282537
+ import_picocolors16.default.red(` ${args.out} already exists.`) + import_picocolors16.default.dim(` Re-run with ${import_picocolors16.default.bold("--force")} to overwrite.`)
282124
282538
  );
282125
282539
  process.exit(1);
282126
282540
  }
282127
282541
  console.log(`
282128
- ${brand("ablo")} ${import_picocolors15.default.dim("pull")} ${import_picocolors15.default.dim(`schema "${args.appSchema}"`)}
282542
+ ${brand("ablo")} ${import_picocolors16.default.dim("pull")} ${import_picocolors16.default.dim(`schema "${args.appSchema}"`)}
282129
282543
  `);
282130
282544
  let result;
282131
282545
  try {
282132
282546
  result = await buildSchemaSourceFromDb({ dbUrl, appSchema: args.appSchema, importPath: args.importPath });
282133
282547
  } catch (err) {
282134
- console.error(import_picocolors15.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
282548
+ console.error(import_picocolors16.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
282135
282549
  process.exit(1);
282136
282550
  }
282137
282551
  if (result.models.length === 0) {
282138
282552
  console.error(
282139
- import_picocolors15.default.yellow(` No adoptable tables found`) + import_picocolors15.default.dim(` (a model needs an ${import_picocolors15.default.bold("id")} + ${import_picocolors15.default.bold("organization_id")} column).`)
282553
+ import_picocolors16.default.yellow(` No adoptable tables found`) + import_picocolors16.default.dim(` (a model needs an ${import_picocolors16.default.bold("id")} + ${import_picocolors16.default.bold("organization_id")} column).`)
282140
282554
  );
282141
282555
  process.exit(1);
282142
282556
  }
282143
282557
  (0, import_fs9.writeFileSync)(args.out, result.source);
282144
- console.log(` ${import_picocolors15.default.green("\u2713")} wrote ${import_picocolors15.default.bold(args.out)} ${import_picocolors15.default.dim(`(${result.models.length} models)`)}`);
282145
- console.log(` ${import_picocolors15.default.dim(`models: ${result.models.join(", ")}`)}`);
282558
+ console.log(` ${import_picocolors16.default.green("\u2713")} wrote ${import_picocolors16.default.bold(args.out)} ${import_picocolors16.default.dim(`(${result.models.length} models)`)}`);
282559
+ console.log(` ${import_picocolors16.default.dim(`models: ${result.models.join(", ")}`)}`);
282146
282560
  if (result.skipped > 0) {
282147
- console.log(` ${import_picocolors15.default.dim(`${result.skipped} table(s) skipped \u2014 no id/organization_id`)}`);
282561
+ console.log(` ${import_picocolors16.default.dim(`${result.skipped} table(s) skipped \u2014 no id/organization_id`)}`);
282148
282562
  }
282149
282563
  console.log(
282150
282564
  `
282151
- ${import_picocolors15.default.dim("Introspection is lossy (enums, JSON shape, relations). Review the file, then")} ${import_picocolors15.default.bold("ablo check")}.
282565
+ ${import_picocolors16.default.dim("Introspection is lossy (enums, JSON shape, relations). Review the file, then")} ${import_picocolors16.default.bold("ablo check")}.
282152
282566
  `
282153
282567
  );
282154
282568
  }
282155
282569
 
282156
282570
  // src/cli/prisma-pull.ts
282157
282571
  init_cjs_shims();
282158
- var import_picocolors16 = __toESM(require_picocolors(), 1);
282572
+ var import_picocolors17 = __toESM(require_picocolors(), 1);
282159
282573
  var import_fs10 = require("fs");
282160
282574
 
282161
282575
  // src/cli/schema-ir.ts
@@ -282433,55 +282847,55 @@ async function prismaPull(argv) {
282433
282847
  try {
282434
282848
  args = parsePrismaPullArgs(argv);
282435
282849
  } catch (err) {
282436
- console.error(import_picocolors16.default.red(` ${err instanceof Error ? err.message : String(err)}`));
282850
+ console.error(import_picocolors17.default.red(` ${err instanceof Error ? err.message : String(err)}`));
282437
282851
  process.exit(1);
282438
282852
  }
282439
282853
  if (!(0, import_fs10.existsSync)(args.schema)) {
282440
282854
  console.error(
282441
- import_picocolors16.default.red(` No Prisma schema at ${import_picocolors16.default.bold(args.schema)}.`) + import_picocolors16.default.dim(` Pass a path: ${import_picocolors16.default.bold("ablo pull prisma <path>")}.`)
282855
+ import_picocolors17.default.red(` No Prisma schema at ${import_picocolors17.default.bold(args.schema)}.`) + import_picocolors17.default.dim(` Pass a path: ${import_picocolors17.default.bold("ablo pull prisma <path>")}.`)
282442
282856
  );
282443
282857
  process.exit(1);
282444
282858
  }
282445
282859
  if ((0, import_fs10.existsSync)(args.out) && !args.force) {
282446
282860
  console.error(
282447
- import_picocolors16.default.red(` ${args.out} already exists.`) + import_picocolors16.default.dim(` Re-run with ${import_picocolors16.default.bold("--force")} to overwrite.`)
282861
+ import_picocolors17.default.red(` ${args.out} already exists.`) + import_picocolors17.default.dim(` Re-run with ${import_picocolors17.default.bold("--force")} to overwrite.`)
282448
282862
  );
282449
282863
  process.exit(1);
282450
282864
  }
282451
282865
  console.log(`
282452
- ${brand("ablo")} ${import_picocolors16.default.dim("pull prisma")} ${import_picocolors16.default.dim(args.schema)}
282866
+ ${brand("ablo")} ${import_picocolors17.default.dim("pull prisma")} ${import_picocolors17.default.dim(args.schema)}
282453
282867
  `);
282454
282868
  let result;
282455
282869
  try {
282456
282870
  const src = (0, import_fs10.readFileSync)(args.schema, "utf8");
282457
282871
  result = buildSchemaSourceFromPrisma({ src, importPath: args.importPath });
282458
282872
  } catch (err) {
282459
- console.error(import_picocolors16.default.red(` Couldn't parse the schema: ${err instanceof Error ? err.message : String(err)}`));
282873
+ console.error(import_picocolors17.default.red(` Couldn't parse the schema: ${err instanceof Error ? err.message : String(err)}`));
282460
282874
  process.exit(1);
282461
282875
  }
282462
282876
  if (result.models.length === 0) {
282463
282877
  console.error(
282464
- import_picocolors16.default.yellow(` No adoptable models found`) + import_picocolors16.default.dim(` (a model needs an ${import_picocolors16.default.bold("id")} + ${import_picocolors16.default.bold("organizationId")} / ${import_picocolors16.default.bold("organization_id")}).`)
282878
+ import_picocolors17.default.yellow(` No adoptable models found`) + import_picocolors17.default.dim(` (a model needs an ${import_picocolors17.default.bold("id")} + ${import_picocolors17.default.bold("organizationId")} / ${import_picocolors17.default.bold("organization_id")}).`)
282465
282879
  );
282466
282880
  process.exit(1);
282467
282881
  }
282468
282882
  (0, import_fs10.writeFileSync)(args.out, result.source);
282469
- console.log(` ${import_picocolors16.default.green("\u2713")} wrote ${import_picocolors16.default.bold(args.out)} ${import_picocolors16.default.dim(`(${result.models.length} models)`)}`);
282470
- console.log(` ${import_picocolors16.default.dim(`models: ${result.models.join(", ")}`)}`);
282883
+ console.log(` ${import_picocolors17.default.green("\u2713")} wrote ${import_picocolors17.default.bold(args.out)} ${import_picocolors17.default.dim(`(${result.models.length} models)`)}`);
282884
+ console.log(` ${import_picocolors17.default.dim(`models: ${result.models.join(", ")}`)}`);
282471
282885
  if (result.skipped.length > 0) {
282472
- console.log(` ${import_picocolors16.default.dim(`${result.skipped.length} model(s) skipped:`)}`);
282473
- for (const s of result.skipped) console.log(` ${import_picocolors16.default.dim(`- ${s.name}: ${s.reason}`)}`);
282886
+ console.log(` ${import_picocolors17.default.dim(`${result.skipped.length} model(s) skipped:`)}`);
282887
+ for (const s of result.skipped) console.log(` ${import_picocolors17.default.dim(`- ${s.name}: ${s.reason}`)}`);
282474
282888
  }
282475
282889
  console.log(
282476
282890
  `
282477
- ${import_picocolors16.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors16.default.bold("ablo check")}.
282891
+ ${import_picocolors17.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors17.default.bold("ablo check")}.
282478
282892
  `
282479
282893
  );
282480
282894
  }
282481
282895
 
282482
282896
  // src/cli/drizzle-pull.ts
282483
282897
  init_cjs_shims();
282484
- var import_picocolors17 = __toESM(require_picocolors(), 1);
282898
+ var import_picocolors18 = __toESM(require_picocolors(), 1);
282485
282899
  var import_fs11 = require("fs");
282486
282900
  var import_path6 = require("path");
282487
282901
  var DEFAULT_OUT4 = "ablo/schema.ts";
@@ -282530,7 +282944,7 @@ async function loadDrizzle() {
282530
282944
  }
282531
282945
  async function lowerDrizzleModule(mod) {
282532
282946
  const { is, getTableName, getTableColumns, PgTable, getTableConfig } = await loadDrizzle();
282533
- const tables = Object.values(mod).filter((v) => is(v, PgTable));
282947
+ const tables = Object.values(mod).filter((v2) => is(v2, PgTable));
282534
282948
  const models = [];
282535
282949
  const skipped = [];
282536
282950
  for (const table of tables) {
@@ -282617,27 +283031,27 @@ async function drizzlePull(argv) {
282617
283031
  try {
282618
283032
  args = parseDrizzlePullArgs(argv);
282619
283033
  } catch (err) {
282620
- console.error(import_picocolors17.default.red(` ${err instanceof Error ? err.message : String(err)}`));
283034
+ console.error(import_picocolors18.default.red(` ${err instanceof Error ? err.message : String(err)}`));
282621
283035
  process.exit(1);
282622
283036
  }
282623
283037
  if (!args.schema) {
282624
283038
  console.error(
282625
- import_picocolors17.default.red(` No Drizzle schema given.`) + import_picocolors17.default.dim(` Pass the module: ${import_picocolors17.default.bold("ablo pull drizzle src/db/schema.ts")}.`)
283039
+ import_picocolors18.default.red(` No Drizzle schema given.`) + import_picocolors18.default.dim(` Pass the module: ${import_picocolors18.default.bold("ablo pull drizzle src/db/schema.ts")}.`)
282626
283040
  );
282627
283041
  process.exit(1);
282628
283042
  }
282629
283043
  if (!(0, import_fs11.existsSync)(args.schema)) {
282630
- console.error(import_picocolors17.default.red(` No file at ${import_picocolors17.default.bold(args.schema)}.`));
283044
+ console.error(import_picocolors18.default.red(` No file at ${import_picocolors18.default.bold(args.schema)}.`));
282631
283045
  process.exit(1);
282632
283046
  }
282633
283047
  if ((0, import_fs11.existsSync)(args.out) && !args.force) {
282634
283048
  console.error(
282635
- import_picocolors17.default.red(` ${args.out} already exists.`) + import_picocolors17.default.dim(` Re-run with ${import_picocolors17.default.bold("--force")} to overwrite.`)
283049
+ import_picocolors18.default.red(` ${args.out} already exists.`) + import_picocolors18.default.dim(` Re-run with ${import_picocolors18.default.bold("--force")} to overwrite.`)
282636
283050
  );
282637
283051
  process.exit(1);
282638
283052
  }
282639
283053
  console.log(`
282640
- ${brand("ablo")} ${import_picocolors17.default.dim("pull drizzle")} ${import_picocolors17.default.dim(args.schema)}
283054
+ ${brand("ablo")} ${import_picocolors18.default.dim("pull drizzle")} ${import_picocolors18.default.dim(args.schema)}
282641
283055
  `);
282642
283056
  let result;
282643
283057
  try {
@@ -282645,33 +283059,33 @@ async function drizzlePull(argv) {
282645
283059
  result = await buildSchemaSourceFromDrizzle({ mod, importPath: args.importPath });
282646
283060
  } catch (err) {
282647
283061
  const msg = err instanceof Error ? err.message : String(err);
282648
- const hint = /Cannot find package 'drizzle-orm'/.test(msg) ? import_picocolors17.default.dim(` (install ${import_picocolors17.default.bold("drizzle-orm")} in this project)`) : "";
282649
- console.error(import_picocolors17.default.red(` Couldn't load the schema: ${msg}`) + hint);
283062
+ const hint = /Cannot find package 'drizzle-orm'/.test(msg) ? import_picocolors18.default.dim(` (install ${import_picocolors18.default.bold("drizzle-orm")} in this project)`) : "";
283063
+ console.error(import_picocolors18.default.red(` Couldn't load the schema: ${msg}`) + hint);
282650
283064
  process.exit(1);
282651
283065
  }
282652
283066
  if (result.models.length === 0) {
282653
283067
  console.error(
282654
- import_picocolors17.default.yellow(` No adoptable tables found`) + import_picocolors17.default.dim(` (a table needs an ${import_picocolors17.default.bold("id")} + ${import_picocolors17.default.bold("organization_id")} column).`)
283068
+ import_picocolors18.default.yellow(` No adoptable tables found`) + import_picocolors18.default.dim(` (a table needs an ${import_picocolors18.default.bold("id")} + ${import_picocolors18.default.bold("organization_id")} column).`)
282655
283069
  );
282656
283070
  process.exit(1);
282657
283071
  }
282658
283072
  (0, import_fs11.writeFileSync)(args.out, result.source);
282659
- console.log(` ${import_picocolors17.default.green("\u2713")} wrote ${import_picocolors17.default.bold(args.out)} ${import_picocolors17.default.dim(`(${result.models.length} models)`)}`);
282660
- console.log(` ${import_picocolors17.default.dim(`models: ${result.models.join(", ")}`)}`);
283073
+ console.log(` ${import_picocolors18.default.green("\u2713")} wrote ${import_picocolors18.default.bold(args.out)} ${import_picocolors18.default.dim(`(${result.models.length} models)`)}`);
283074
+ console.log(` ${import_picocolors18.default.dim(`models: ${result.models.join(", ")}`)}`);
282661
283075
  if (result.skipped.length > 0) {
282662
- console.log(` ${import_picocolors17.default.dim(`${result.skipped.length} table(s) skipped:`)}`);
282663
- for (const s of result.skipped) console.log(` ${import_picocolors17.default.dim(`- ${s.name}: ${s.reason}`)}`);
283076
+ console.log(` ${import_picocolors18.default.dim(`${result.skipped.length} table(s) skipped:`)}`);
283077
+ for (const s of result.skipped) console.log(` ${import_picocolors18.default.dim(`- ${s.name}: ${s.reason}`)}`);
282664
283078
  }
282665
283079
  console.log(
282666
283080
  `
282667
- ${import_picocolors17.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors17.default.bold("ablo check")}.
283081
+ ${import_picocolors18.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors18.default.bold("ablo check")}.
282668
283082
  `
282669
283083
  );
282670
283084
  }
282671
283085
 
282672
283086
  // src/cli/renderError.ts
282673
283087
  init_cjs_shims();
282674
- var import_picocolors18 = __toESM(require_picocolors(), 1);
283088
+ var import_picocolors19 = __toESM(require_picocolors(), 1);
282675
283089
  var RECOVERY_HINT = {
282676
283090
  transient: "This looks transient \u2014 retry in a moment.",
282677
283091
  permission: "Your key isn't allowed to do this \u2014 check its scopes or role.",
@@ -282685,21 +283099,21 @@ function titleForType(type) {
282685
283099
  if (!spaced) return "Error";
282686
283100
  return /error$/i.test(spaced) ? spaced : `${spaced} error`;
282687
283101
  }
282688
- function isStringArray(v) {
282689
- return Array.isArray(v) && v.every((x2) => typeof x2 === "string");
283102
+ function isStringArray(v2) {
283103
+ return Array.isArray(v2) && v2.every((x2) => typeof x2 === "string");
282690
283104
  }
282691
283105
  function renderKnownDetails(details, line) {
282692
283106
  if (!details) return;
282693
283107
  const { retryAfterSeconds, missingIds, requiredCapability, unexecutable, errors } = details;
282694
- if (typeof retryAfterSeconds === "number") line(` ${import_picocolors18.default.dim("retry")} after ${retryAfterSeconds}s`);
283108
+ if (typeof retryAfterSeconds === "number") line(` ${import_picocolors19.default.dim("retry")} after ${retryAfterSeconds}s`);
282695
283109
  if (isStringArray(missingIds) && missingIds.length > 0) {
282696
283110
  const shown = missingIds.slice(0, 5).join(", ");
282697
283111
  const more = missingIds.length > 5 ? ` (+${missingIds.length - 5} more)` : "";
282698
- line(` ${import_picocolors18.default.dim("missing")} ${shown}${more}`);
283112
+ line(` ${import_picocolors19.default.dim("missing")} ${shown}${more}`);
282699
283113
  }
282700
- if (typeof requiredCapability === "string") line(` ${import_picocolors18.default.dim("needs")} ${requiredCapability}`);
283114
+ if (typeof requiredCapability === "string") line(` ${import_picocolors19.default.dim("needs")} ${requiredCapability}`);
282701
283115
  if (Array.isArray(unexecutable) && unexecutable.length > 0) {
282702
- line(` ${import_picocolors18.default.dim("blocked")} ${unexecutable.length} change(s) can't be applied \u2014 see \`unexecutable\` (--verbose)`);
283116
+ line(` ${import_picocolors19.default.dim("blocked")} ${unexecutable.length} change(s) can't be applied \u2014 see \`unexecutable\` (--verbose)`);
282703
283117
  }
282704
283118
  if (Array.isArray(errors)) {
282705
283119
  for (const e2 of errors.slice(0, 8)) {
@@ -282707,7 +283121,7 @@ function renderKnownDetails(details, line) {
282707
283121
  const rec = e2;
282708
283122
  const where = typeof rec.param === "string" ? `${rec.param}: ` : "";
282709
283123
  const msg = typeof rec.message === "string" ? rec.message : "";
282710
- if (msg) line(` ${import_picocolors18.default.dim("\xB7")} ${where}${msg}`);
283124
+ if (msg) line(` ${import_picocolors19.default.dim("\xB7")} ${where}${msg}`);
282711
283125
  }
282712
283126
  }
282713
283127
  }
@@ -282716,22 +283130,22 @@ function renderCliError(err, opts = {}) {
282716
283130
  const line = opts.write ?? ((l2) => console.error(l2));
282717
283131
  const verbose = opts.verbose ?? (process.argv.includes("--verbose") || process.env.ABLO_VERBOSE === "1");
282718
283132
  if (err instanceof AbloError) {
282719
- const codeTag = err.code ? ` ${import_picocolors18.default.dim(`[${err.code}]`)}` : "";
283133
+ const codeTag = err.code ? ` ${import_picocolors19.default.dim(`[${err.code}]`)}` : "";
282720
283134
  line("");
282721
- line(` ${brand("ablo")} ${import_picocolors18.default.red("\u2717")} ${import_picocolors18.default.bold(titleForType(err.type))}${codeTag}`);
283135
+ line(` ${brand("ablo")} ${import_picocolors19.default.red("\u2717")} ${import_picocolors19.default.bold(titleForType(err.type))}${codeTag}`);
282722
283136
  line("");
282723
283137
  line(` ${err.message}`);
282724
- if (err.param) line(` ${import_picocolors18.default.dim("field")} ${err.param}`);
283138
+ if (err.param) line(` ${import_picocolors19.default.dim("field")} ${err.param}`);
282725
283139
  renderKnownDetails(err.details, line);
282726
283140
  const hint = err.code ? RECOVERY_HINT[classifyRecovery(err.code)] : void 0;
282727
- if (hint) line(` ${import_picocolors18.default.dim(hint)}`);
282728
- if (err.docUrl) line(` ${import_picocolors18.default.dim("docs")} ${err.docUrl}`);
282729
- if (err.requestId) line(` ${import_picocolors18.default.dim("ref")} ${err.requestId}`);
283141
+ if (hint) line(` ${import_picocolors19.default.dim(hint)}`);
283142
+ if (err.docUrl) line(` ${import_picocolors19.default.dim("docs")} ${err.docUrl}`);
283143
+ if (err.requestId) line(` ${import_picocolors19.default.dim("ref")} ${err.requestId}`);
282730
283144
  if (verbose) {
282731
283145
  if (err.details && Object.keys(err.details).length > 0) {
282732
- line(` ${import_picocolors18.default.dim("details")} ${JSON.stringify(err.details)}`);
283146
+ line(` ${import_picocolors19.default.dim("details")} ${JSON.stringify(err.details)}`);
282733
283147
  }
282734
- if (err.stack) line(import_picocolors18.default.dim(err.stack));
283148
+ if (err.stack) line(import_picocolors19.default.dim(err.stack));
282735
283149
  }
282736
283150
  line("");
282737
283151
  process.exitCode = 1;
@@ -282739,16 +283153,16 @@ function renderCliError(err, opts = {}) {
282739
283153
  }
282740
283154
  const message = err instanceof Error ? err.message : String(err);
282741
283155
  line("");
282742
- line(` ${brand("ablo")} ${import_picocolors18.default.red("\u2717")} ${message}`);
282743
- if (verbose && err instanceof Error && err.stack) line(import_picocolors18.default.dim(err.stack));
282744
- else line(` ${import_picocolors18.default.dim("Run with --verbose for the full error.")}`);
283156
+ line(` ${brand("ablo")} ${import_picocolors19.default.red("\u2717")} ${message}`);
283157
+ if (verbose && err instanceof Error && err.stack) line(import_picocolors19.default.dim(err.stack));
283158
+ else line(` ${import_picocolors19.default.dim("Run with --verbose for the full error.")}`);
282745
283159
  line("");
282746
283160
  process.exitCode = 1;
282747
283161
  }
282748
283162
 
282749
283163
  // src/cli/index.ts
282750
283164
  var LOGO = `
282751
- ${brand("ablo")} ${import_picocolors19.default.dim("sync engine")}
283165
+ ${brand("ablo")} ${import_picocolors20.default.dim("sync engine")}
282752
283166
  `;
282753
283167
  var SUBCOMMAND_USAGE = {
282754
283168
  connect: CONNECT_USAGE,
@@ -282783,7 +283197,7 @@ async function main() {
282783
283197
  const devArgs = process.argv.slice(3);
282784
283198
  const oneShot = devArgs.includes("--no-watch");
282785
283199
  console.log(
282786
- import_picocolors19.default.dim(
283200
+ import_picocolors20.default.dim(
282787
283201
  oneShot ? " `ablo dev --no-watch` is `ablo push` (push once, no watcher) \u2014 running that." : " `ablo dev` is now `ablo push --watch` \u2014 running that."
282788
283202
  )
282789
283203
  );
@@ -282805,19 +283219,21 @@ async function main() {
282805
283219
  await migrate(process.argv.slice(3));
282806
283220
  } else if (command === "push") {
282807
283221
  const rest = process.argv.slice(3);
282808
- const advanced = rest.some((a) => ["--force", "--rename", "--backfill", "--url"].includes(a));
283222
+ const advanced = rest.some(
283223
+ (a) => ["--force", "--rename", "--backfill", "--url", "--dry-run", "--plan", "--yes", "-y", "--allow-dirty"].includes(a)
283224
+ );
282809
283225
  const watching = rest.includes("--watch");
282810
283226
  const guard = guardActiveProjectKey();
282811
283227
  if (!guard.ok && guard.available.length > 0 && !rest.includes("--url")) {
282812
283228
  console.error(
282813
- ` ${import_picocolors19.default.yellow("\u26A0")} active project ${import_picocolors19.default.bold(guard.activeProfile)} has no stored key ${import_picocolors19.default.dim(
283229
+ ` ${import_picocolors20.default.yellow("\u26A0")} active project ${import_picocolors20.default.bold(guard.activeProfile)} has no stored key ${import_picocolors20.default.dim(
282814
283230
  `(you have keys for: ${guard.available.join(", ")})`
282815
283231
  )}`
282816
283232
  );
282817
283233
  const loginCmd = guard.activeProfile === "default" ? "ablo login" : `ablo login --project ${guard.activeProfile}`;
282818
283234
  console.error(
282819
- import_picocolors19.default.dim(
282820
- ` Mint one with ${import_picocolors19.default.bold(loginCmd)}, or switch with ${import_picocolors19.default.bold("ablo projects use <slug>")}.`
283235
+ import_picocolors20.default.dim(
283236
+ ` Mint one with ${import_picocolors20.default.bold(loginCmd)}, or switch with ${import_picocolors20.default.bold("ablo projects use <slug>")}.`
282821
283237
  )
282822
283238
  );
282823
283239
  process.exitCode = 1;
@@ -282835,13 +283251,13 @@ async function main() {
282835
283251
  await generate(process.argv.slice(3));
282836
283252
  } else if (command === "schema") {
282837
283253
  console.error(
282838
- ` ${import_picocolors19.default.red("\u2717")} \`ablo schema push\` was renamed to \`${brand("ablo push")}\`.`
283254
+ ` ${import_picocolors20.default.red("\u2717")} \`ablo schema push\` was renamed to \`${brand("ablo push")}\`.`
282839
283255
  );
282840
283256
  console.error(` Run \`ablo push${process.argv.slice(4).join(" ") ? " " + process.argv.slice(4).join(" ") : ""}\` instead.`);
282841
283257
  process.exitCode = 1;
282842
283258
  } else {
282843
283259
  console.log(LOGO);
282844
- console.log(` ${import_picocolors19.default.bold("Usage:")}`);
283260
+ console.log(` ${import_picocolors20.default.bold("Usage:")}`);
282845
283261
  console.log(` npx ablo init Scaffold ablo/ directory + starter schema`);
282846
283262
  console.log(` npx ablo init --yes [--framework nextjs] Non-interactive (agents/CI): no prompts, flag-driven`);
282847
283263
  console.log(` [--auth apikey] [--storage direct|endpoint] [--project <slug>] [--no-project]`);
@@ -282866,6 +283282,7 @@ async function main() {
282866
283282
  console.log(` npx ablo check Check your existing database fits the schema (read-only, creates no tables)`);
282867
283283
  console.log(` npx ablo connect Connect a real database \u2014 prints the logical-replication setup SQL (the one way)`);
282868
283284
  console.log(` npx ablo connect --check Validate DATABASE_URL is replication-ready (wal_level, publication, role, replica identity)`);
283285
+ console.log(` npx ablo connect --audit-infra Read-only audit for deprecated Ablo sync infra in a customer DB`);
282869
283286
  console.log(` npx ablo migrate Provision your synced-model tables in your own Postgres (optional escape hatch \u2014 \`connect\` is the way)`);
282870
283287
  console.log(` npx ablo migrate --dry-run Print the SQL without executing (preview)`);
282871
283288
  console.log(` npx ablo push Upload your schema definition to Ablo (metadata only \u2014 rows stay in your DB)`);
@@ -282876,10 +283293,10 @@ async function main() {
282876
283293
  console.log(` npx ablo generate Emit TypeScript types from your schema`);
282877
283294
  console.log(` npx ablo generate --out path.ts Write generated types to a path`);
282878
283295
  console.log();
282879
- console.log(` ${import_picocolors19.default.bold("Schema workflow:")}`);
283296
+ console.log(` ${import_picocolors20.default.bold("Schema workflow:")}`);
282880
283297
  console.log(` The server holds its own copy of your schema \u2014 edit ${brand("ablo/schema.ts")}, then`);
282881
283298
  console.log(` run ${brand("ablo push")} (or keep ${brand("ablo dev")} running) before the server will accept`);
282882
- console.log(` writes to new or changed models. Skip it and writes fail with ${import_picocolors19.default.yellow("server_execute_unknown_model")}.`);
283299
+ console.log(` writes to new or changed models. Skip it and writes fail with ${import_picocolors20.default.yellow("server_execute_unknown_model")}.`);
282883
283300
  console.log();
282884
283301
  }
282885
283302
  }
@@ -282891,7 +283308,7 @@ function bailIfCancelled(value) {
282891
283308
  }
282892
283309
  var INIT_FRAMEWORKS = ["nextjs", "vite", "remix", "vanilla"];
282893
283310
  var INIT_AUTHS = ["apikey", "firebase", "auth0", "clerk", "supabase", "betterauth", "jwt"];
282894
- var INIT_STORAGES = ["endpoint", "direct", "datasource"];
283311
+ var INIT_STORAGES = ["replication", "endpoint", "direct", "datasource"];
282895
283312
  function parseInitArgs(args) {
282896
283313
  const has = (flag2) => args.includes(flag2);
282897
283314
  const val = (flag2) => {
@@ -282930,7 +283347,7 @@ async function ensureInitProject(opts) {
282930
283347
  const ensured = await ensureProject(slug);
282931
283348
  if (ensured) {
282932
283349
  console.log(
282933
- ` ${import_picocolors19.default.green("\u2713")} ${ensured.created ? "Created" : "Using"} project ${import_picocolors19.default.bold(ensured.slug)} ${import_picocolors19.default.dim(`(${ensured.id})`)} \u2014 keys you mint for it are isolated from the org's other apps.`
283350
+ ` ${import_picocolors20.default.green("\u2713")} ${ensured.created ? "Created" : "Using"} project ${import_picocolors20.default.bold(ensured.slug)} ${import_picocolors20.default.dim(`(${ensured.id})`)} \u2014 keys you mint for it are isolated from the org's other apps.`
282934
283351
  );
282935
283352
  }
282936
283353
  }
@@ -282972,7 +283389,7 @@ async function chooseBool(flagValue, fallback, interactive, prompt) {
282972
283389
  async function init(args = []) {
282973
283390
  const opts = parseInitArgs(args);
282974
283391
  const interactive = Boolean(process.stdin.isTTY) && !opts.yes && !process.env.CI;
282975
- Ie(`${brand("ablo")} ${import_picocolors19.default.dim("sync engine")}`);
283392
+ Ie(`${brand("ablo")} ${import_picocolors20.default.dim("sync engine")}`);
282976
283393
  if (!(0, import_fs12.existsSync)("package.json")) {
282977
283394
  xe("No package.json found. Run this from your project root.");
282978
283395
  process.exit(1);
@@ -283017,16 +283434,16 @@ async function init(args = []) {
283017
283434
  const storageChoice = await chooseOption(
283018
283435
  "storage",
283019
283436
  opts.storage,
283020
- "endpoint",
283437
+ "replication",
283021
283438
  INIT_STORAGES,
283022
283439
  false,
283023
- () => Promise.resolve("endpoint")
283440
+ () => Promise.resolve("replication")
283024
283441
  );
283025
283442
  const storage = storageChoice === "datasource" ? "endpoint" : storageChoice;
283026
283443
  if (storage === "direct") {
283027
283444
  Me(
283028
- "`--storage direct` uses the deprecated databaseUrl connector. The signed Data\nSource endpoint is the supported path.",
283029
- import_picocolors19.default.yellow("Deprecated")
283445
+ "`--storage direct` uses the deprecated databaseUrl connector. Logical replication\n(`npx ablo connect`) is the supported path; a signed Data Source endpoint is the fallback.",
283446
+ import_picocolors20.default.yellow("Deprecated")
283030
283447
  );
283031
283448
  }
283032
283449
  const agent = await chooseBool(
@@ -283056,7 +283473,7 @@ async function init(args = []) {
283056
283473
  if (pullExisting) {
283057
283474
  const dbUrl = process.env.DATABASE_URL ?? process.env.ABLO_DATABASE_URL;
283058
283475
  if (!dbUrl) {
283059
- schemaNote = import_picocolors19.default.dim(" (no DATABASE_URL \u2014 wrote starter; run `ablo pull` later)");
283476
+ schemaNote = import_picocolors20.default.dim(" (no DATABASE_URL \u2014 wrote starter; run `ablo pull` later)");
283060
283477
  } else {
283061
283478
  try {
283062
283479
  const pulled = await buildSchemaSourceFromDb({
@@ -283066,12 +283483,12 @@ async function init(args = []) {
283066
283483
  });
283067
283484
  if (pulled.models.length > 0) {
283068
283485
  schemaSource = pulled.source;
283069
- schemaNote = import_picocolors19.default.dim(` (pulled ${pulled.models.length} models)`);
283486
+ schemaNote = import_picocolors20.default.dim(` (pulled ${pulled.models.length} models)`);
283070
283487
  } else {
283071
- schemaNote = import_picocolors19.default.dim(" (no adoptable tables \u2014 wrote starter)");
283488
+ schemaNote = import_picocolors20.default.dim(" (no adoptable tables \u2014 wrote starter)");
283072
283489
  }
283073
283490
  } catch {
283074
- schemaNote = import_picocolors19.default.dim(" (pull failed \u2014 wrote starter)");
283491
+ schemaNote = import_picocolors20.default.dim(" (pull failed \u2014 wrote starter)");
283075
283492
  }
283076
283493
  }
283077
283494
  }
@@ -283097,14 +283514,14 @@ async function init(args = []) {
283097
283514
  const existing = (0, import_fs12.readFileSync)(envFile, "utf-8");
283098
283515
  if (!existing.includes("ABLO_")) {
283099
283516
  (0, import_fs12.writeFileSync)(envFile, existing + "\n" + envBody);
283100
- created.push(`${envFile} ${import_picocolors19.default.dim("(appended)")}`);
283517
+ created.push(`${envFile} ${import_picocolors20.default.dim("(appended)")}`);
283101
283518
  } else {
283102
- created.push(`${envFile} ${import_picocolors19.default.dim("(already configured)")}`);
283519
+ created.push(`${envFile} ${import_picocolors20.default.dim("(already configured)")}`);
283103
283520
  }
283104
283521
  }
283105
283522
  if (wireRealKey && resolvedKey) {
283106
283523
  wireEnvLocal(resolvedKey);
283107
- created.push(`.env.local ${import_picocolors19.default.dim("(ABLO_API_KEY set from your login)")}`);
283524
+ created.push(`.env.local ${import_picocolors20.default.dim("(ABLO_API_KEY set from your login)")}`);
283108
283525
  }
283109
283526
  if (agent) {
283110
283527
  (0, import_fs12.writeFileSync)((0, import_path7.join)(abloDir, "agent.ts"), generateAgent());
@@ -283119,64 +283536,66 @@ async function init(args = []) {
283119
283536
  }
283120
283537
  const providersPath = (0, import_path7.join)(layout.appBase, "providers.tsx");
283121
283538
  (0, import_fs12.writeFileSync)(providersPath, generateProviders());
283122
- created.push(`${providersPath} ${import_picocolors19.default.dim(`(wrap ${(0, import_path7.join)(layout.appBase, "layout.tsx")} in <Providers>)`)}`);
283539
+ created.push(`${providersPath} ${import_picocolors20.default.dim(`(wrap ${(0, import_path7.join)(layout.appBase, "layout.tsx")} in <Providers>)`)}`);
283123
283540
  const sessionDir = (0, import_path7.join)(layout.appBase, "api", "ablo-session");
283124
283541
  (0, import_fs12.mkdirSync)(sessionDir, { recursive: true });
283125
283542
  (0, import_fs12.writeFileSync)((0, import_path7.join)(sessionDir, "route.ts"), generateSessionRoute());
283126
- created.push(`${(0, import_path7.join)(sessionDir, "route.ts")} ${import_picocolors19.default.dim("(wire your auth)")}`);
283543
+ created.push(`${(0, import_path7.join)(sessionDir, "route.ts")} ${import_picocolors20.default.dim("(wire your auth)")}`);
283127
283544
  }
283128
283545
  if (framework !== "vanilla") {
283129
283546
  (0, import_fs12.writeFileSync)((0, import_path7.join)(abloDir, "TaskList.tsx"), generateComponent());
283130
283547
  created.push(`${abloDir}/TaskList.tsx`);
283131
283548
  }
283132
- Me(created.map((f) => `${import_picocolors19.default.green("\u2713")} ${f}`).join("\n"), "Created");
283549
+ Me(created.map((f) => `${import_picocolors20.default.green("\u2713")} ${f}`).join("\n"), "Created");
283133
283550
  const pm = detectPackageManager();
283134
283551
  if (opts.install) {
283135
283552
  const s = Y2();
283136
283553
  s.start("Installing @abloatai/ablo");
283137
283554
  try {
283138
- (0, import_child_process2.execSync)(`${pm} add @abloatai/ablo`, { stdio: "ignore" });
283555
+ (0, import_child_process3.execSync)(`${pm} add @abloatai/ablo`, { stdio: "ignore" });
283139
283556
  s.stop("Installed @abloatai/ablo");
283140
283557
  } catch {
283141
- s.stop(`${import_picocolors19.default.yellow("!")} Couldn't auto-install \u2014 run ${import_picocolors19.default.bold(`${pm} install @abloatai/ablo`)}`);
283558
+ s.stop(`${import_picocolors20.default.yellow("!")} Couldn't auto-install \u2014 run ${import_picocolors20.default.bold(`${pm} install @abloatai/ablo`)}`);
283142
283559
  }
283143
283560
  }
283144
283561
  const steps = [
283145
- `Get a ${import_picocolors19.default.bold("sk_test_")} key at ${import_picocolors19.default.cyan("https://abloatai.com")}`,
283146
- `Run ${import_picocolors19.default.bold("npx ablo login")} (or add ${import_picocolors19.default.bold("ABLO_API_KEY")} to ${import_picocolors19.default.bold(envFile)})`,
283147
- `Set ${import_picocolors19.default.bold("DATABASE_URL")} in ${import_picocolors19.default.bold(envFile)} \u2014 your Postgres is the system of record; rows live there, never with Ablo`,
283148
- `Run ${import_picocolors19.default.bold("npx ablo dev")} \u2014 pushes your schema definition and watches for changes`,
283149
- ...storage === "direct" ? [
283150
- `Provision your DB: ${import_picocolors19.default.bold("npx ablo migrate")} (creates your synced-model tables with row-level security; keep your own migrations for everything else)`
283562
+ `Get a ${import_picocolors20.default.bold("sk_test_")} key at ${import_picocolors20.default.cyan("https://abloatai.com")}`,
283563
+ `Run ${import_picocolors20.default.bold("npx ablo login")} (or add ${import_picocolors20.default.bold("ABLO_API_KEY")} to ${import_picocolors20.default.bold(envFile)})`,
283564
+ `Set ${import_picocolors20.default.bold("DATABASE_URL")} in ${import_picocolors20.default.bold(envFile)} \u2014 your Postgres is the system of record; rows live there, never with Ablo`,
283565
+ `Run ${import_picocolors20.default.bold("npx ablo dev")} \u2014 pushes your schema definition and watches for changes`,
283566
+ ...storage === "replication" ? [
283567
+ `Connect your database: ${import_picocolors20.default.bold("npx ablo connect")} prints the logical-replication setup SQL (run it once on your Postgres), then ${import_picocolors20.default.bold("npx ablo connect --register")} tells Ablo to replicate it \u2014 your app keeps writing through your own backend, Ablo tails the WAL`
283568
+ ] : storage === "direct" ? [
283569
+ `Provision your DB: ${import_picocolors20.default.bold("npx ablo migrate")} (creates your synced-model tables with row-level security; keep your own migrations for everything else)`
283151
283570
  ] : [
283152
- `Provision your DB: ${import_picocolors19.default.bold("npx ablo migrate")} (creates your Ablo-model tables + the adapter tables; keep your own migrations for everything else), then mount ${import_picocolors19.default.bold(`${abloDir}/data-source.ts`)} at ${import_picocolors19.default.bold("/api/ablo/source")}`
283571
+ `Provision your DB: ${import_picocolors20.default.bold("npx ablo migrate")} (creates your Ablo-model tables + the adapter tables; keep your own migrations for everything else), then mount ${import_picocolors20.default.bold(`${abloDir}/data-source.ts`)} at ${import_picocolors20.default.bold("/api/ablo/source")}`
283153
283572
  ],
283154
283573
  ...framework === "nextjs" ? [
283155
- `Wrap ${import_picocolors19.default.bold((0, import_path7.join)(layout.appBase, "layout.tsx"))} in ${import_picocolors19.default.bold("<Providers>")} (${(0, import_path7.join)(layout.appBase, "providers.tsx")}) and add your auth to ${import_picocolors19.default.bold((0, import_path7.join)(layout.appBase, "api", "ablo-session", "route.ts"))}`
283574
+ `Wrap ${import_picocolors20.default.bold((0, import_path7.join)(layout.appBase, "layout.tsx"))} in ${import_picocolors20.default.bold("<Providers>")} (${(0, import_path7.join)(layout.appBase, "providers.tsx")}) and add your auth to ${import_picocolors20.default.bold((0, import_path7.join)(layout.appBase, "api", "ablo-session", "route.ts"))}`
283156
283575
  ] : [],
283157
- `Run ${import_picocolors19.default.bold(`${pm} run dev`)} and open two browser tabs \u2014 changes sync in real-time`,
283576
+ `Run ${import_picocolors20.default.bold(`${pm} run dev`)} and open two browser tabs \u2014 changes sync in real-time`,
283158
283577
  ...agent ? [
283159
- `Run ${import_picocolors19.default.bold(`npx tsx ${abloDir}/agent.ts`)} \u2014 an AI teammate edits the same tasks`,
283160
- `Run ${import_picocolors19.default.bold("npx ablo logs")} to watch human + agent commits stream by`
283578
+ `Run ${import_picocolors20.default.bold(`npx tsx ${abloDir}/agent.ts`)} \u2014 an AI teammate edits the same tasks`,
283579
+ `Run ${import_picocolors20.default.bold("npx ablo logs")} to watch human + agent commits stream by`
283161
283580
  ] : []
283162
283581
  ];
283163
283582
  Me(steps.map((s, i) => `${i + 1}. ${s}`).join("\n"), "Next steps");
283164
283583
  const existingKey = resolveApiKey("sandbox");
283165
283584
  if (existingKey) {
283166
283585
  await ensureInitProject(opts);
283167
- Se(`Already authorized ${import_picocolors19.default.dim(`(${existingKey.slice(0, 11)}\u2026)`)} \u2014 run ${import_picocolors19.default.bold("npx ablo push")} next. ${import_picocolors19.default.dim("Docs:")} https://abloatai.com/docs`);
283586
+ Se(`Already authorized ${import_picocolors20.default.dim(`(${existingKey.slice(0, 11)}\u2026)`)} \u2014 run ${import_picocolors20.default.bold("npx ablo push")} next. ${import_picocolors20.default.dim("Docs:")} https://abloatai.com/docs`);
283168
283587
  return;
283169
283588
  }
283170
283589
  if (interactive && opts.login) {
283171
283590
  const loginNow = await ye({ message: "Log in now? (opens your browser)", initialValue: true });
283172
283591
  if (!pD(loginNow) && loginNow) {
283173
- Se(`${import_picocolors19.default.dim("Docs:")} https://abloatai.com/docs`);
283592
+ Se(`${import_picocolors20.default.dim("Docs:")} https://abloatai.com/docs`);
283174
283593
  await login();
283175
283594
  await ensureInitProject(opts);
283176
283595
  return;
283177
283596
  }
283178
283597
  }
283179
- Se(`Run ${import_picocolors19.default.bold("npx ablo login")} when ready. ${import_picocolors19.default.dim("Docs:")} https://abloatai.com/docs`);
283598
+ Se(`Run ${import_picocolors20.default.bold("npx ablo login")} when ready. ${import_picocolors20.default.dim("Docs:")} https://abloatai.com/docs`);
283180
283599
  }
283181
283600
  function generateSchema() {
283182
283601
  return `import { defineSchema, model, relation, z } from '@abloatai/ablo/schema';
@@ -283251,7 +283670,7 @@ export {};
283251
283670
  }
283252
283671
  function generateEnv(storage, opts = {}) {
283253
283672
  const { includeApiKey = true } = opts;
283254
- const databaseBlock = storage === "direct" ? "# DEPRECATED direct connector. The client registers this connection (sent once\n# over TLS, stored sealed) so Ablo dials into your Postgres. Prefer a signed Data\n# Source endpoint; to keep the transaction log in your infra too, self-host the engine.\n# Use a dedicated non-superuser role; the browser never sees this value.\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";
283673
+ const databaseBlock = storage === "direct" ? "# DEPRECATED direct connector. The client registers this connection (sent once\n# over TLS, stored sealed) so Ablo dials into your Postgres. Prefer logical\n# replication (`npx ablo connect`); to keep the transaction log in your infra too,\n# self-host the engine. Use a dedicated non-superuser role; the browser never sees this.\nDATABASE_URL=postgres://user:password@host:5432/db\n" : 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";
283255
283674
  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" : "";
283256
283675
  const apiKeyBlock = includeApiKey ? "# Ablo Sync Engine \u2014 use a sk_test_ key for local dev (`npx ablo push`)\nABLO_API_KEY=sk_test_your_key_here\n" : "";
283257
283676
  return `${apiKeyBlock}${webhookBlock}${databaseBlock}`;