@abloatai/cli 0.54.0 → 0.56.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 +137 -46
- package/package.json +3 -3
package/dist/cli.cjs
CHANGED
|
@@ -3970,7 +3970,7 @@ var init_observeCliError = __esm({
|
|
|
3970
3970
|
import_errorObservation = require("@abloatai/transaction/errorObservation");
|
|
3971
3971
|
import_errors5 = require("@abloatai/transaction/errors");
|
|
3972
3972
|
dsn = process.env.ABLO_CLI_SENTRY_DSN ?? "https://1ac154bff10b06836e1ea9de9e0d92f0@o4510928209772544.ingest.de.sentry.io/4511660691423312" ?? "";
|
|
3973
|
-
release = process.env.ABLO_CLI_RELEASE ?? "@abloatai/cli@0.
|
|
3973
|
+
release = process.env.ABLO_CLI_RELEASE ?? "@abloatai/cli@0.56.0";
|
|
3974
3974
|
initialized = false;
|
|
3975
3975
|
nativeProcessExit = process.exit.bind(process);
|
|
3976
3976
|
exitBoundaryInstalled = false;
|
|
@@ -4297,7 +4297,7 @@ var init_src2 = __esm({
|
|
|
4297
4297
|
|
|
4298
4298
|
// src/cliEnvironment.ts
|
|
4299
4299
|
function cliVersion() {
|
|
4300
|
-
return "0.
|
|
4300
|
+
return "0.56.0";
|
|
4301
4301
|
}
|
|
4302
4302
|
function cliOs() {
|
|
4303
4303
|
const value = (0, import_node_os.platform)();
|
|
@@ -5968,6 +5968,28 @@ async function fetchPushedSchema(apiUrl3, apiKey) {
|
|
|
5968
5968
|
clearTimeout(t);
|
|
5969
5969
|
}
|
|
5970
5970
|
}
|
|
5971
|
+
async function fetchDeliveryState(apiUrl3, apiKey, timeoutMs = 4e3) {
|
|
5972
|
+
if (!apiKey) return { kind: "unknown", detail: "no key" };
|
|
5973
|
+
const ctrl = new AbortController();
|
|
5974
|
+
const t = setTimeout(() => {
|
|
5975
|
+
ctrl.abort();
|
|
5976
|
+
}, timeoutMs);
|
|
5977
|
+
try {
|
|
5978
|
+
const res = await fetch(`${apiUrl3}/api/v1/logs/delivery`, {
|
|
5979
|
+
headers: { authorization: `Bearer ${apiKey}` },
|
|
5980
|
+
signal: ctrl.signal
|
|
5981
|
+
});
|
|
5982
|
+
if (!res.ok) return { kind: "unknown", detail: `HTTP ${res.status}` };
|
|
5983
|
+
const parsed = import_wire5.logDeliveryResponseSchema.safeParse(await res.json());
|
|
5984
|
+
if (!parsed.success) return { kind: "unknown", detail: "unrecognized response" };
|
|
5985
|
+
const { window_seconds, recorded, unroutable, sample } = parsed.data;
|
|
5986
|
+
return { kind: "known", window_seconds, recorded, unroutable, sample: sample ?? null };
|
|
5987
|
+
} catch {
|
|
5988
|
+
return { kind: "unknown", detail: "unreachable" };
|
|
5989
|
+
} finally {
|
|
5990
|
+
clearTimeout(t);
|
|
5991
|
+
}
|
|
5992
|
+
}
|
|
5971
5993
|
async function fetchDataSourceState(apiUrl3, apiKey, timeoutMs = 4e3) {
|
|
5972
5994
|
if (!apiKey) return { kind: "unknown", detail: "no key" };
|
|
5973
5995
|
const ctrl = new AbortController();
|
|
@@ -6069,7 +6091,7 @@ function blockers(input) {
|
|
|
6069
6091
|
}
|
|
6070
6092
|
return found;
|
|
6071
6093
|
}
|
|
6072
|
-
var import_wire5, import_schema4;
|
|
6094
|
+
var import_wire5, import_schema4, WRITE_READY_VERDICT;
|
|
6073
6095
|
var init_readiness = __esm({
|
|
6074
6096
|
"src/readiness.ts"() {
|
|
6075
6097
|
"use strict";
|
|
@@ -6079,6 +6101,7 @@ var init_readiness = __esm({
|
|
|
6079
6101
|
init_dbProvider();
|
|
6080
6102
|
init_remoteValidation();
|
|
6081
6103
|
import_schema4 = require("@abloatai/transaction/schema");
|
|
6104
|
+
WRITE_READY_VERDICT = "write infrastructure is ready. Your database constraints and row-level policies still apply.";
|
|
6082
6105
|
}
|
|
6083
6106
|
});
|
|
6084
6107
|
|
|
@@ -284769,21 +284792,14 @@ function classifyKey(apiKey) {
|
|
|
284769
284792
|
reason: `${import_picocolors16.default.bold("ABLO_API_KEY")} is not a secret Ablo key. Expected a branch-bound ${import_picocolors16.default.bold("sk_\u2026")} credential. Run ${import_picocolors16.default.bold("npx ablo dev")} to prepare a development branch.`
|
|
284770
284793
|
};
|
|
284771
284794
|
}
|
|
284772
|
-
function wireEnvLocal(apiKey, cwd = process.cwd()
|
|
284795
|
+
function wireEnvLocal(apiKey, cwd = process.cwd()) {
|
|
284773
284796
|
const envPath = (0, import_path5.resolve)(cwd, ".env.local");
|
|
284774
284797
|
const line = `ABLO_API_KEY=${apiKey}`;
|
|
284775
|
-
const projectLine = projectId ? `ABLO_PROJECT_ID=${projectId}` : null;
|
|
284776
|
-
const branchLine = branchId ? `ABLO_BRANCH_ID=${branchId}` : null;
|
|
284777
284798
|
let action;
|
|
284799
|
+
let removedPins = [];
|
|
284778
284800
|
if (!(0, import_fs7.existsSync)(envPath)) {
|
|
284779
|
-
(0, import_fs7.writeFileSync)(
|
|
284780
|
-
|
|
284781
|
-
`${line}
|
|
284782
|
-
${projectLine ? `${projectLine}
|
|
284783
|
-
` : ""}${branchLine ? `${branchLine}
|
|
284784
|
-
` : ""}`,
|
|
284785
|
-
{ mode: 384 }
|
|
284786
|
-
);
|
|
284801
|
+
(0, import_fs7.writeFileSync)(envPath, `${line}
|
|
284802
|
+
`, { mode: 384 });
|
|
284787
284803
|
action = `Created ${import_picocolors16.default.bold(".env.local")} with ${import_picocolors16.default.bold("ABLO_API_KEY")}`;
|
|
284788
284804
|
} else {
|
|
284789
284805
|
const content = (0, import_fs7.readFileSync)(envPath, "utf8");
|
|
@@ -284799,25 +284815,16 @@ ${projectLine ? `${projectLine}
|
|
|
284799
284815
|
(0, import_fs7.writeFileSync)(envPath, content.replace(/^ABLO_API_KEY=.*$/m, line));
|
|
284800
284816
|
action = `Updated ${import_picocolors16.default.bold("ABLO_API_KEY")} in ${import_picocolors16.default.bold(".env.local")} ${import_picocolors16.default.dim(`(was ${existing.slice(0, 12)}\u2026)`)}`;
|
|
284801
284817
|
}
|
|
284802
|
-
|
|
284803
|
-
|
|
284804
|
-
|
|
284805
|
-
|
|
284806
|
-
|
|
284807
|
-
|
|
284808
|
-
|
|
284809
|
-
}
|
|
284810
|
-
}
|
|
284811
|
-
if (branchLine) {
|
|
284812
|
-
const next = (0, import_fs7.readFileSync)(envPath, "utf8");
|
|
284813
|
-
if (/^ABLO_BRANCH_ID=.*$/m.test(next)) {
|
|
284814
|
-
(0, import_fs7.writeFileSync)(envPath, next.replace(/^ABLO_BRANCH_ID=.*$/m, branchLine));
|
|
284815
|
-
} else {
|
|
284816
|
-
(0, import_fs7.appendFileSync)(envPath, `${next.endsWith("\n") || next.length === 0 ? "" : "\n"}${branchLine}
|
|
284817
|
-
`);
|
|
284818
|
-
}
|
|
284818
|
+
const before = (0, import_fs7.readFileSync)(envPath, "utf8");
|
|
284819
|
+
const after = before.replace(/^ABLO_(?:PROJECT|BRANCH)_ID=.*\n?/gm, "");
|
|
284820
|
+
if (after !== before) {
|
|
284821
|
+
removedPins = ["ABLO_PROJECT_ID", "ABLO_BRANCH_ID"].filter(
|
|
284822
|
+
(key) => new RegExp(`^${key}=`, "m").test(before)
|
|
284823
|
+
);
|
|
284824
|
+
(0, import_fs7.writeFileSync)(envPath, after);
|
|
284819
284825
|
}
|
|
284820
284826
|
}
|
|
284827
|
+
const pinNote = removedPins.length ? ` Removed ${removedPins.map((key) => import_picocolors16.default.bold(key)).join(" and ")}; the key names its own project and branch.` : "";
|
|
284821
284828
|
const gitignorePath = (0, import_path5.resolve)(cwd, ".gitignore");
|
|
284822
284829
|
const gitignore = (0, import_fs7.existsSync)(gitignorePath) ? (0, import_fs7.readFileSync)(gitignorePath, "utf8") : "";
|
|
284823
284830
|
const ignored = /^(\.env\.local|\.env\*|\.env\.\*|\.env.*)$/m.test(gitignore);
|
|
@@ -284831,7 +284838,7 @@ ${projectLine ? `${projectLine}
|
|
|
284831
284838
|
);
|
|
284832
284839
|
gitignoreNote = ` Added ${import_picocolors16.default.bold(".env.local")} to ${import_picocolors16.default.bold(".gitignore")} so the key can't be committed.`;
|
|
284833
284840
|
}
|
|
284834
|
-
return `${action}.${gitignoreNote}`;
|
|
284841
|
+
return `${action}.${pinNote}${gitignoreNote}`;
|
|
284835
284842
|
}
|
|
284836
284843
|
async function runPush(schema, args) {
|
|
284837
284844
|
const { ok, status: status2, body, bodyText } = await pushSchema(schema, {
|
|
@@ -284992,7 +284999,7 @@ async function dev(argv, runtime = {}) {
|
|
|
284992
284999
|
if (runtime.branch) {
|
|
284993
285000
|
console.log(
|
|
284994
285001
|
`
|
|
284995
|
-
${import_picocolors16.default.green("\u2713")} ${wireEnvLocal(args.apiKey, process.cwd()
|
|
285002
|
+
${import_picocolors16.default.green("\u2713")} ${wireEnvLocal(args.apiKey, process.cwd())}`
|
|
284996
285003
|
);
|
|
284997
285004
|
console.log(
|
|
284998
285005
|
` ${import_picocolors16.default.dim(`Temporary branch credential expires ${runtime.branch.expiresAt}; rerun ablo dev to rotate it.`)}`
|
|
@@ -285423,6 +285430,10 @@ init_controlPlane();
|
|
|
285423
285430
|
init_config();
|
|
285424
285431
|
init_target();
|
|
285425
285432
|
init_readiness();
|
|
285433
|
+
function doctorVerdict(counts) {
|
|
285434
|
+
if (counts.blockers > 0 || counts.failed > 0) return "blocked";
|
|
285435
|
+
return counts.skipped > 0 ? "unverified" : "ready";
|
|
285436
|
+
}
|
|
285426
285437
|
function render(check2) {
|
|
285427
285438
|
const mark = check2.state === "ok" ? import_picocolors18.default.green("\u2713") : check2.state === "fail" ? import_picocolors18.default.red("\u2717") : import_picocolors18.default.dim("\u2013");
|
|
285428
285439
|
console.log(
|
|
@@ -285430,6 +285441,14 @@ function render(check2) {
|
|
|
285430
285441
|
);
|
|
285431
285442
|
if (check2.fix) console.log(` ${" ".repeat(11)}${import_picocolors18.default.dim(`\u2192 ${check2.fix}`)}`);
|
|
285432
285443
|
}
|
|
285444
|
+
function windowWords(seconds) {
|
|
285445
|
+
if (seconds % 3600 === 0) {
|
|
285446
|
+
const hours = seconds / 3600;
|
|
285447
|
+
return hours === 1 ? "the last hour" : `the last ${hours} hours`;
|
|
285448
|
+
}
|
|
285449
|
+
const minutes = Math.max(1, Math.round(seconds / 60));
|
|
285450
|
+
return minutes === 1 ? "the last minute" : `the last ${minutes} minutes`;
|
|
285451
|
+
}
|
|
285433
285452
|
async function ping(apiUrl3) {
|
|
285434
285453
|
const ctrl = new AbortController();
|
|
285435
285454
|
const t = setTimeout(() => {
|
|
@@ -285572,6 +285591,32 @@ async function inspectDoctor(options = {}) {
|
|
|
285572
285591
|
} else {
|
|
285573
285592
|
checks.push({ label: "database", state: "skip", detail: "nothing connected to check" });
|
|
285574
285593
|
}
|
|
285594
|
+
const delivery = reachable ? await fetchDeliveryState(apiUrl3, runtimeKey.key) : { kind: "unknown", detail: "unreachable" };
|
|
285595
|
+
if (delivery.kind === "known") {
|
|
285596
|
+
const when = windowWords(delivery.window_seconds);
|
|
285597
|
+
checks.push(
|
|
285598
|
+
delivery.unroutable > 0 ? delivery.unroutable === delivery.recorded ? {
|
|
285599
|
+
// Nothing at all was routable. One bad row does not look like
|
|
285600
|
+
// this, so the cause is the plane rather than the rows: reporting
|
|
285601
|
+
// it as "N of N" would send the reader hunting for the N.
|
|
285602
|
+
label: "delivery",
|
|
285603
|
+
state: "fail",
|
|
285604
|
+
detail: `no change reached anyone (${delivery.recorded} in ${when})`,
|
|
285605
|
+
fix: "run `ablo check`. When nothing routes, the tenancy value is usually missing for the whole plane rather than for particular rows."
|
|
285606
|
+
} : {
|
|
285607
|
+
label: "delivery",
|
|
285608
|
+
state: "fail",
|
|
285609
|
+
detail: `${delivery.unroutable} of ${delivery.recorded} change${delivery.recorded === 1 ? "" : "s"} in ${when} reached nobody` + (delivery.sample ? ` (e.g. ${delivery.sample.model}/${delivery.sample.id})` : ""),
|
|
285610
|
+
fix: "run `ablo check`. Rows written to Postgres outside Ablo carry no tenancy value, so nothing can route the change."
|
|
285611
|
+
} : {
|
|
285612
|
+
label: "delivery",
|
|
285613
|
+
state: "ok",
|
|
285614
|
+
detail: delivery.recorded === 0 ? `no changes in ${when}` : `${delivery.recorded} change${delivery.recorded === 1 ? "" : "s"} in ${when}, all deliverable`
|
|
285615
|
+
}
|
|
285616
|
+
);
|
|
285617
|
+
} else {
|
|
285618
|
+
checks.push({ label: "delivery", state: "skip", detail: `not determined (${delivery.detail})` });
|
|
285619
|
+
}
|
|
285575
285620
|
const blocking = blockers({
|
|
285576
285621
|
reachable,
|
|
285577
285622
|
hasKey: Boolean(runtimeKey.key),
|
|
@@ -285592,7 +285637,9 @@ async function inspectDoctor(options = {}) {
|
|
|
285592
285637
|
target,
|
|
285593
285638
|
dataSource,
|
|
285594
285639
|
pushedSchema: pushed,
|
|
285595
|
-
schemaDrift: drift
|
|
285640
|
+
schemaDrift: drift,
|
|
285641
|
+
delivery,
|
|
285642
|
+
verdict: doctorVerdict({ blockers: blocking.length, failed, skipped })
|
|
285596
285643
|
};
|
|
285597
285644
|
}
|
|
285598
285645
|
function renderDoctorReport(report) {
|
|
@@ -285610,19 +285657,35 @@ function renderDoctorReport(report) {
|
|
|
285610
285657
|
);
|
|
285611
285658
|
} else if (report.skipped > 0) {
|
|
285612
285659
|
console.log(
|
|
285613
|
-
` ${import_picocolors18.default.yellow("?")} ${import_picocolors18.default.dim(`nothing
|
|
285660
|
+
` ${import_picocolors18.default.yellow("?")} ${import_picocolors18.default.dim(`nothing found a problem, but ${report.skipped} check${report.skipped === 1 ? "" : "s"} could not be run. This is not a clean bill of health.`)}`
|
|
285614
285661
|
);
|
|
285615
285662
|
} else {
|
|
285616
285663
|
console.log(
|
|
285617
|
-
` ${import_picocolors18.default.green("\u2713")} ${import_picocolors18.default.dim(
|
|
285664
|
+
` ${import_picocolors18.default.green("\u2713")} ${import_picocolors18.default.dim(WRITE_READY_VERDICT)}`
|
|
285618
285665
|
);
|
|
285619
285666
|
}
|
|
285620
285667
|
console.log();
|
|
285621
285668
|
}
|
|
285622
|
-
|
|
285669
|
+
function doctorReportAsJson(report) {
|
|
285670
|
+
return JSON.stringify(
|
|
285671
|
+
{
|
|
285672
|
+
object: "doctor_report",
|
|
285673
|
+
verdict: report.verdict,
|
|
285674
|
+
checks: report.checks,
|
|
285675
|
+
blockers: report.blockers
|
|
285676
|
+
},
|
|
285677
|
+
null,
|
|
285678
|
+
2
|
|
285679
|
+
);
|
|
285680
|
+
}
|
|
285681
|
+
async function doctor(argv = []) {
|
|
285623
285682
|
const report = await inspectDoctor();
|
|
285624
|
-
|
|
285625
|
-
|
|
285683
|
+
if (argv.includes("--json") || process.env.ABLO_JSON === "1") {
|
|
285684
|
+
console.log(doctorReportAsJson(report));
|
|
285685
|
+
} else {
|
|
285686
|
+
renderDoctorReport(report);
|
|
285687
|
+
}
|
|
285688
|
+
if (report.verdict !== "ready") process.exitCode = 1;
|
|
285626
285689
|
}
|
|
285627
285690
|
|
|
285628
285691
|
// src/setup/contracts.ts
|
|
@@ -287458,7 +287521,10 @@ var COMMANDS = [
|
|
|
287458
287521
|
core: { group: "Every day", does: "Check the whole setup at once and list everything that would block a write" },
|
|
287459
287522
|
full: {
|
|
287460
287523
|
group: "See what's happening",
|
|
287461
|
-
rows: [
|
|
287524
|
+
rows: [
|
|
287525
|
+
{ run: "doctor", does: "Every setup check at once. Exits non-zero when a write would fail, or when a check could not be run" },
|
|
287526
|
+
{ run: "doctor --json", does: "The same verdict as data, for a script or an agent" }
|
|
287527
|
+
]
|
|
287462
287528
|
}
|
|
287463
287529
|
},
|
|
287464
287530
|
{
|
|
@@ -288136,7 +288202,7 @@ async function status(args = []) {
|
|
|
288136
288202
|
);
|
|
288137
288203
|
} else {
|
|
288138
288204
|
console.log(
|
|
288139
|
-
` ${import_picocolors22.default.green("\u2713")} ${import_picocolors22.default.dim(
|
|
288205
|
+
` ${import_picocolors22.default.green("\u2713")} ${import_picocolors22.default.dim(WRITE_READY_VERDICT)}`
|
|
288140
288206
|
);
|
|
288141
288207
|
}
|
|
288142
288208
|
console.log();
|
|
@@ -288623,6 +288689,24 @@ function parseCheckArgs(argv) {
|
|
|
288623
288689
|
}
|
|
288624
288690
|
return { schemaPath, exportName, appSchema };
|
|
288625
288691
|
}
|
|
288692
|
+
function quoteIdent2(raw) {
|
|
288693
|
+
return `"${raw.replace(/"/g, '""')}"`;
|
|
288694
|
+
}
|
|
288695
|
+
var UNSTAMPED_CAP = 500;
|
|
288696
|
+
async function countUnstamped(sql, appSchema, table, column) {
|
|
288697
|
+
try {
|
|
288698
|
+
const rows = await sql.unsafe(
|
|
288699
|
+
`SELECT count(*)::int AS n FROM (
|
|
288700
|
+
SELECT 1 FROM ${quoteIdent2(appSchema)}.${quoteIdent2(table)}
|
|
288701
|
+
WHERE ${quoteIdent2(column)} IS NULL
|
|
288702
|
+
LIMIT ${UNSTAMPED_CAP + 1}
|
|
288703
|
+
) s`
|
|
288704
|
+
);
|
|
288705
|
+
return rows[0]?.n ?? 0;
|
|
288706
|
+
} catch {
|
|
288707
|
+
return null;
|
|
288708
|
+
}
|
|
288709
|
+
}
|
|
288626
288710
|
function hostOf(connectionString) {
|
|
288627
288711
|
try {
|
|
288628
288712
|
return new URL(connectionString).hostname || null;
|
|
@@ -288700,7 +288784,6 @@ async function check(argv) {
|
|
|
288700
288784
|
await sql.end({ timeout: 2 });
|
|
288701
288785
|
process.exit(1);
|
|
288702
288786
|
}
|
|
288703
|
-
await sql.end({ timeout: 2 });
|
|
288704
288787
|
const colsByTable = /* @__PURE__ */ new Map();
|
|
288705
288788
|
for (const r2 of rows) {
|
|
288706
288789
|
let set = colsByTable.get(r2.table_name);
|
|
@@ -288739,6 +288822,15 @@ async function check(argv) {
|
|
|
288739
288822
|
if (BASE_COLUMNS.has(col) || col === orgCol) continue;
|
|
288740
288823
|
if (!present.has(col)) problems.push(`missing column "${col}" (field ${fieldName})`);
|
|
288741
288824
|
}
|
|
288825
|
+
if (orgCol && present.has(orgCol)) {
|
|
288826
|
+
const unstamped = await countUnstamped(sql, args.appSchema, table, orgCol);
|
|
288827
|
+
if (unstamped !== null && unstamped > 0) {
|
|
288828
|
+
const count = unstamped > UNSTAMPED_CAP ? `${UNSTAMPED_CAP}+ rows` : `${unstamped} row${unstamped === 1 ? "" : "s"}`;
|
|
288829
|
+
problems.push(
|
|
288830
|
+
`${count} have no "${orgCol}", so nothing can route them. Ablo stamps it on writes it makes; an insert straight into Postgres does not. Backfill the value, then run \`ablo connect resnapshot\`.`
|
|
288831
|
+
);
|
|
288832
|
+
}
|
|
288833
|
+
}
|
|
288742
288834
|
if (problems.length > 0) {
|
|
288743
288835
|
console.log(` ${import_picocolors25.default.red("\u2717")} ${import_picocolors25.default.bold(key)} ${import_picocolors25.default.dim("\u2192")} ${table}`);
|
|
288744
288836
|
for (const p2 of problems) console.log(` ${import_picocolors25.default.red("\u2022")} ${p2}`);
|
|
@@ -288752,6 +288844,7 @@ async function check(argv) {
|
|
|
288752
288844
|
console.log(` ${import_picocolors25.default.green("\u2713")} ${import_picocolors25.default.bold(key)} ${import_picocolors25.default.dim(`\u2192 ${table} (id, ${orgCol ?? "no org"} ok)`)}`);
|
|
288753
288845
|
}
|
|
288754
288846
|
}
|
|
288847
|
+
await sql.end({ timeout: 2 });
|
|
288755
288848
|
const modelCount = Object.keys(schemaJson.models).length;
|
|
288756
288849
|
const ignored = [...colsByTable.keys()].filter((t) => !declaredTables.has(t)).length;
|
|
288757
288850
|
console.log(
|
|
@@ -289736,8 +289829,6 @@ import { schema } from './schema';
|
|
|
289736
289829
|
// via the session route and never touches the key.
|
|
289737
289830
|
export const sync = Ablo({
|
|
289738
289831
|
apiKey: process.env.ABLO_API_KEY,${authLine}
|
|
289739
|
-
workspaceId: process.env.ABLO_PROJECT_ID,
|
|
289740
|
-
branchId: process.env.ABLO_BRANCH_ID,
|
|
289741
289832
|
schema,
|
|
289742
289833
|
});
|
|
289743
289834
|
|
|
@@ -289763,7 +289854,7 @@ function generateEnv(storage, opts = {}) {
|
|
|
289763
289854
|
const { includeApiKey = true } = opts;
|
|
289764
289855
|
const databaseBlock = storage === "replication" ? "# Used by `npx ablo connect` to set up + register logical replication \u2014 the\n# DIRECT (un-pooled) endpoint. Ablo TAILS your WAL from here; it never writes.\n# The client never sees it; the browser never sees it. Your DB stays yours.\nDATABASE_URL=postgres://user:password@host:5432/db\n" : "# Used by ablo/data-source.ts (your DB endpoint) + `ablo migrate` \u2014 NOT the client.\n# Ablo never sees it; the browser never sees it. Your DB stays in your app.\nDATABASE_URL=postgres://user:password@host:5432/db\n";
|
|
289765
289856
|
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" : "";
|
|
289766
|
-
const apiKeyBlock = includeApiKey ? "# Ablo: a branch-bound sk_ key (`npx ablo dev`
|
|
289857
|
+
const apiKeyBlock = includeApiKey ? "# Ablo: a branch-bound sk_ key (`npx ablo dev` writes it for you).\n# The key names its own project and branch, so nothing else is needed here.\nABLO_API_KEY=sk_your_key_here\n" : "";
|
|
289767
289858
|
return `${apiKeyBlock}${webhookBlock}${databaseBlock}`;
|
|
289768
289859
|
}
|
|
289769
289860
|
function generateDataSource(orm) {
|
|
@@ -290454,7 +290545,7 @@ var HANDLERS = {
|
|
|
290454
290545
|
branch: (argv) => branches([...argv]),
|
|
290455
290546
|
status: (argv) => status([...argv]),
|
|
290456
290547
|
whoami: (argv) => whoami([...argv]),
|
|
290457
|
-
doctor: () => doctor(),
|
|
290548
|
+
doctor: (argv) => doctor([...argv]),
|
|
290458
290549
|
logs: (argv) => logs([...argv]),
|
|
290459
290550
|
webhooks: (argv) => webhooks([...argv]),
|
|
290460
290551
|
check: (argv) => check([...argv]),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abloatai/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.56.0",
|
|
4
4
|
"description": "The ablo command line: set up Ablo, connect your database, and push your schema from the terminal.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -35,10 +35,10 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@sentry/node": "^10.18.0",
|
|
38
|
-
"@abloatai/transaction": "^0.
|
|
38
|
+
"@abloatai/transaction": "^0.56.0",
|
|
39
39
|
"jiti": "^2.7.0",
|
|
40
40
|
"zod": "^4.4.3",
|
|
41
|
-
"@abloatai/humans": "^0.
|
|
41
|
+
"@abloatai/humans": "^0.56.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@ablo/product-analytics": "file:../product-analytics",
|