@abloatai/cli 0.55.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 +57 -43
- 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)();
|
|
@@ -284792,21 +284792,14 @@ function classifyKey(apiKey) {
|
|
|
284792
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.`
|
|
284793
284793
|
};
|
|
284794
284794
|
}
|
|
284795
|
-
function wireEnvLocal(apiKey, cwd = process.cwd()
|
|
284795
|
+
function wireEnvLocal(apiKey, cwd = process.cwd()) {
|
|
284796
284796
|
const envPath = (0, import_path5.resolve)(cwd, ".env.local");
|
|
284797
284797
|
const line = `ABLO_API_KEY=${apiKey}`;
|
|
284798
|
-
const projectLine = projectId ? `ABLO_PROJECT_ID=${projectId}` : null;
|
|
284799
|
-
const branchLine = branchId ? `ABLO_BRANCH_ID=${branchId}` : null;
|
|
284800
284798
|
let action;
|
|
284799
|
+
let removedPins = [];
|
|
284801
284800
|
if (!(0, import_fs7.existsSync)(envPath)) {
|
|
284802
|
-
(0, import_fs7.writeFileSync)(
|
|
284803
|
-
|
|
284804
|
-
`${line}
|
|
284805
|
-
${projectLine ? `${projectLine}
|
|
284806
|
-
` : ""}${branchLine ? `${branchLine}
|
|
284807
|
-
` : ""}`,
|
|
284808
|
-
{ mode: 384 }
|
|
284809
|
-
);
|
|
284801
|
+
(0, import_fs7.writeFileSync)(envPath, `${line}
|
|
284802
|
+
`, { mode: 384 });
|
|
284810
284803
|
action = `Created ${import_picocolors16.default.bold(".env.local")} with ${import_picocolors16.default.bold("ABLO_API_KEY")}`;
|
|
284811
284804
|
} else {
|
|
284812
284805
|
const content = (0, import_fs7.readFileSync)(envPath, "utf8");
|
|
@@ -284822,25 +284815,16 @@ ${projectLine ? `${projectLine}
|
|
|
284822
284815
|
(0, import_fs7.writeFileSync)(envPath, content.replace(/^ABLO_API_KEY=.*$/m, line));
|
|
284823
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)`)}`;
|
|
284824
284817
|
}
|
|
284825
|
-
|
|
284826
|
-
|
|
284827
|
-
|
|
284828
|
-
|
|
284829
|
-
|
|
284830
|
-
|
|
284831
|
-
|
|
284832
|
-
}
|
|
284833
|
-
}
|
|
284834
|
-
if (branchLine) {
|
|
284835
|
-
const next = (0, import_fs7.readFileSync)(envPath, "utf8");
|
|
284836
|
-
if (/^ABLO_BRANCH_ID=.*$/m.test(next)) {
|
|
284837
|
-
(0, import_fs7.writeFileSync)(envPath, next.replace(/^ABLO_BRANCH_ID=.*$/m, branchLine));
|
|
284838
|
-
} else {
|
|
284839
|
-
(0, import_fs7.appendFileSync)(envPath, `${next.endsWith("\n") || next.length === 0 ? "" : "\n"}${branchLine}
|
|
284840
|
-
`);
|
|
284841
|
-
}
|
|
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);
|
|
284842
284825
|
}
|
|
284843
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.` : "";
|
|
284844
284828
|
const gitignorePath = (0, import_path5.resolve)(cwd, ".gitignore");
|
|
284845
284829
|
const gitignore = (0, import_fs7.existsSync)(gitignorePath) ? (0, import_fs7.readFileSync)(gitignorePath, "utf8") : "";
|
|
284846
284830
|
const ignored = /^(\.env\.local|\.env\*|\.env\.\*|\.env.*)$/m.test(gitignore);
|
|
@@ -284854,7 +284838,7 @@ ${projectLine ? `${projectLine}
|
|
|
284854
284838
|
);
|
|
284855
284839
|
gitignoreNote = ` Added ${import_picocolors16.default.bold(".env.local")} to ${import_picocolors16.default.bold(".gitignore")} so the key can't be committed.`;
|
|
284856
284840
|
}
|
|
284857
|
-
return `${action}.${gitignoreNote}`;
|
|
284841
|
+
return `${action}.${pinNote}${gitignoreNote}`;
|
|
284858
284842
|
}
|
|
284859
284843
|
async function runPush(schema, args) {
|
|
284860
284844
|
const { ok, status: status2, body, bodyText } = await pushSchema(schema, {
|
|
@@ -285015,7 +284999,7 @@ async function dev(argv, runtime = {}) {
|
|
|
285015
284999
|
if (runtime.branch) {
|
|
285016
285000
|
console.log(
|
|
285017
285001
|
`
|
|
285018
|
-
${import_picocolors16.default.green("\u2713")} ${wireEnvLocal(args.apiKey, process.cwd()
|
|
285002
|
+
${import_picocolors16.default.green("\u2713")} ${wireEnvLocal(args.apiKey, process.cwd())}`
|
|
285019
285003
|
);
|
|
285020
285004
|
console.log(
|
|
285021
285005
|
` ${import_picocolors16.default.dim(`Temporary branch credential expires ${runtime.branch.expiresAt}; rerun ablo dev to rotate it.`)}`
|
|
@@ -285446,6 +285430,10 @@ init_controlPlane();
|
|
|
285446
285430
|
init_config();
|
|
285447
285431
|
init_target();
|
|
285448
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
|
+
}
|
|
285449
285437
|
function render(check2) {
|
|
285450
285438
|
const mark = check2.state === "ok" ? import_picocolors18.default.green("\u2713") : check2.state === "fail" ? import_picocolors18.default.red("\u2717") : import_picocolors18.default.dim("\u2013");
|
|
285451
285439
|
console.log(
|
|
@@ -285607,7 +285595,15 @@ async function inspectDoctor(options = {}) {
|
|
|
285607
285595
|
if (delivery.kind === "known") {
|
|
285608
285596
|
const when = windowWords(delivery.window_seconds);
|
|
285609
285597
|
checks.push(
|
|
285610
|
-
delivery.unroutable > 0 ? {
|
|
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
|
+
} : {
|
|
285611
285607
|
label: "delivery",
|
|
285612
285608
|
state: "fail",
|
|
285613
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})` : ""),
|
|
@@ -285642,7 +285638,8 @@ async function inspectDoctor(options = {}) {
|
|
|
285642
285638
|
dataSource,
|
|
285643
285639
|
pushedSchema: pushed,
|
|
285644
285640
|
schemaDrift: drift,
|
|
285645
|
-
delivery
|
|
285641
|
+
delivery,
|
|
285642
|
+
verdict: doctorVerdict({ blockers: blocking.length, failed, skipped })
|
|
285646
285643
|
};
|
|
285647
285644
|
}
|
|
285648
285645
|
function renderDoctorReport(report) {
|
|
@@ -285660,7 +285657,7 @@ function renderDoctorReport(report) {
|
|
|
285660
285657
|
);
|
|
285661
285658
|
} else if (report.skipped > 0) {
|
|
285662
285659
|
console.log(
|
|
285663
|
-
` ${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.`)}`
|
|
285664
285661
|
);
|
|
285665
285662
|
} else {
|
|
285666
285663
|
console.log(
|
|
@@ -285669,10 +285666,26 @@ function renderDoctorReport(report) {
|
|
|
285669
285666
|
}
|
|
285670
285667
|
console.log();
|
|
285671
285668
|
}
|
|
285672
|
-
|
|
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 = []) {
|
|
285673
285682
|
const report = await inspectDoctor();
|
|
285674
|
-
|
|
285675
|
-
|
|
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;
|
|
285676
285689
|
}
|
|
285677
285690
|
|
|
285678
285691
|
// src/setup/contracts.ts
|
|
@@ -287508,7 +287521,10 @@ var COMMANDS = [
|
|
|
287508
287521
|
core: { group: "Every day", does: "Check the whole setup at once and list everything that would block a write" },
|
|
287509
287522
|
full: {
|
|
287510
287523
|
group: "See what's happening",
|
|
287511
|
-
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
|
+
]
|
|
287512
287528
|
}
|
|
287513
287529
|
},
|
|
287514
287530
|
{
|
|
@@ -289813,8 +289829,6 @@ import { schema } from './schema';
|
|
|
289813
289829
|
// via the session route and never touches the key.
|
|
289814
289830
|
export const sync = Ablo({
|
|
289815
289831
|
apiKey: process.env.ABLO_API_KEY,${authLine}
|
|
289816
|
-
workspaceId: process.env.ABLO_PROJECT_ID,
|
|
289817
|
-
branchId: process.env.ABLO_BRANCH_ID,
|
|
289818
289832
|
schema,
|
|
289819
289833
|
});
|
|
289820
289834
|
|
|
@@ -289840,7 +289854,7 @@ function generateEnv(storage, opts = {}) {
|
|
|
289840
289854
|
const { includeApiKey = true } = opts;
|
|
289841
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";
|
|
289842
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" : "";
|
|
289843
|
-
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" : "";
|
|
289844
289858
|
return `${apiKeyBlock}${webhookBlock}${databaseBlock}`;
|
|
289845
289859
|
}
|
|
289846
289860
|
function generateDataSource(orm) {
|
|
@@ -290531,7 +290545,7 @@ var HANDLERS = {
|
|
|
290531
290545
|
branch: (argv) => branches([...argv]),
|
|
290532
290546
|
status: (argv) => status([...argv]),
|
|
290533
290547
|
whoami: (argv) => whoami([...argv]),
|
|
290534
|
-
doctor: () => doctor(),
|
|
290548
|
+
doctor: (argv) => doctor([...argv]),
|
|
290535
290549
|
logs: (argv) => logs([...argv]),
|
|
290536
290550
|
webhooks: (argv) => webhooks([...argv]),
|
|
290537
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",
|