@abloatai/cli 0.41.0 → 0.42.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 +650 -323
- package/package.json +3 -3
package/dist/cli.cjs
CHANGED
|
@@ -3047,23 +3047,28 @@ function readProjectWriteDatabaseUrl(cwd = process.cwd()) {
|
|
|
3047
3047
|
return readProjectEnvValue("ABLO_WRITE_DATABASE_URL", cwd);
|
|
3048
3048
|
}
|
|
3049
3049
|
function readProjectEnvValue(variable, cwd) {
|
|
3050
|
+
return readProjectEnvVariable(variable, cwd, false)?.value ?? null;
|
|
3051
|
+
}
|
|
3052
|
+
function readProjectEnvVariable(variable, cwd = process.cwd(), includeProcess = true) {
|
|
3053
|
+
if (includeProcess && process.env[variable]) {
|
|
3054
|
+
return { value: process.env[variable], source: "env" };
|
|
3055
|
+
}
|
|
3050
3056
|
for (const filename of [".env.local", ".env"]) {
|
|
3051
3057
|
const path = (0, import_path.resolve)(cwd, filename);
|
|
3052
3058
|
if (!(0, import_fs2.existsSync)(path)) continue;
|
|
3053
3059
|
const match = new RegExp(`^${variable}=(.+)$`, "m").exec((0, import_fs2.readFileSync)(path, "utf8"));
|
|
3054
|
-
if (match?.[1])
|
|
3060
|
+
if (match?.[1]) {
|
|
3061
|
+
return {
|
|
3062
|
+
value: match[1].trim().replace(/^["']|["']$/g, ""),
|
|
3063
|
+
source: filename
|
|
3064
|
+
};
|
|
3065
|
+
}
|
|
3055
3066
|
}
|
|
3056
3067
|
return null;
|
|
3057
3068
|
}
|
|
3058
3069
|
function readProjectApiKey(cwd = process.cwd()) {
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
const path = (0, import_path.resolve)(cwd, name);
|
|
3062
|
-
if (!(0, import_fs2.existsSync)(path)) continue;
|
|
3063
|
-
const match = /^ABLO_API_KEY=(.+)$/m.exec((0, import_fs2.readFileSync)(path, "utf8"));
|
|
3064
|
-
if (match?.[1]) return { key: match[1].trim().replace(/^["']|["']$/g, ""), source: name };
|
|
3065
|
-
}
|
|
3066
|
-
return null;
|
|
3070
|
+
const found = readProjectEnvVariable("ABLO_API_KEY", cwd);
|
|
3071
|
+
return found ? { key: found.value, source: found.source } : null;
|
|
3067
3072
|
}
|
|
3068
3073
|
var import_crypto2, import_fs2, import_path, REPLICATION_URL_VARS, ADMIN_URL_VAR;
|
|
3069
3074
|
var init_dbRole = __esm({
|
|
@@ -3361,6 +3366,11 @@ function clearCredential() {
|
|
|
3361
3366
|
function resolveApiKey(modeOverride) {
|
|
3362
3367
|
return resolveKey({ purpose: "data", mode: modeOverride }).key;
|
|
3363
3368
|
}
|
|
3369
|
+
function ambientEnvKeyNote(cwd) {
|
|
3370
|
+
const ambient = readProjectApiKey(cwd);
|
|
3371
|
+
if (!ambient || ambient.source === "env") return null;
|
|
3372
|
+
return `Note: ${ambient.source} in this directory holds an ABLO_API_KEY, which this command does not load \u2014 it reads only the process environment and your stored login, so a file cannot silently choose the plane. Export the variable (or prefix the command with it) to use that key.`;
|
|
3373
|
+
}
|
|
3364
3374
|
function resolveManagementKey() {
|
|
3365
3375
|
if (process.env.ABLO_MANAGEMENT_KEY) return process.env.ABLO_MANAGEMENT_KEY;
|
|
3366
3376
|
const cfg = readConfig();
|
|
@@ -3773,7 +3783,8 @@ async function confirmFromServer(opts) {
|
|
|
3773
3783
|
branchId: identity.branchId ?? null,
|
|
3774
3784
|
branchRoot: identity.branchRoot
|
|
3775
3785
|
};
|
|
3776
|
-
} catch {
|
|
3786
|
+
} catch (error) {
|
|
3787
|
+
if (opts.strict) throw error;
|
|
3777
3788
|
return null;
|
|
3778
3789
|
}
|
|
3779
3790
|
}
|
|
@@ -5600,7 +5611,8 @@ function rotateWithoutConnection(input) {
|
|
|
5600
5611
|
return "Ablo did not accept this API key, so it cannot be told about a new password. Rotate changes the password in your database first, so running it with a key Ablo refuses would leave the database on a password nobody holds.";
|
|
5601
5612
|
}
|
|
5602
5613
|
if (!input.known || input.planeHasConnection) return null;
|
|
5603
|
-
|
|
5614
|
+
if (input.existingRoles.length > 0) return null;
|
|
5615
|
+
return "This plane has no connected database and Ablo's roles are not in this database, so there is no credential to re-key. Connecting for the first time is `ablo connect apply`, which creates the roles and registers them in one run.";
|
|
5604
5616
|
}
|
|
5605
5617
|
async function locateExistingConnection(input) {
|
|
5606
5618
|
const result = await tryControlPlane({
|
|
@@ -5678,7 +5690,7 @@ async function executePlan(sql, steps, rebuildPlaintext) {
|
|
|
5678
5690
|
async function runConnectApply(args) {
|
|
5679
5691
|
const rotating = args.rotate;
|
|
5680
5692
|
const verb = rotating ? "connect rotate" : "connect apply";
|
|
5681
|
-
|
|
5693
|
+
let adminUrl = args.url ?? readProjectAdminDatabaseUrl();
|
|
5682
5694
|
if (!adminUrl) {
|
|
5683
5695
|
throw new import_errors9.AbloValidationError(
|
|
5684
5696
|
"No admin connection string. Pass --url <admin-conn> (or set DATABASE_URL) and re-run.",
|
|
@@ -5695,12 +5707,17 @@ async function runConnectApply(args) {
|
|
|
5695
5707
|
const apiKey = resolveApiKey();
|
|
5696
5708
|
if (!apiKey) {
|
|
5697
5709
|
const loggedIn = resolveManagementKey() !== void 0;
|
|
5710
|
+
const ambient = ambientEnvKeyNote();
|
|
5698
5711
|
throw new import_errors9.AbloAuthenticationError(
|
|
5699
5712
|
loggedIn ? `You are logged in, but this project has no ${getMode()} data key.
|
|
5700
5713
|
|
|
5701
5714
|
The key is looked for in ABLO_API_KEY, then in the credential stored for the active project in the active mode (${getMode()}). Logging in stores a management credential, which administers the project but cannot register a database \u2014 and a key for another mode is never used implicitly, so registering against production takes an explicit production key.
|
|
5702
5715
|
|
|
5703
|
-
Mint a sandbox key with \`npx ablo dev\`, or set ABLO_API_KEY to the key of the plane this database should join (its sk_live_ key for production)
|
|
5716
|
+
Mint a sandbox key with \`npx ablo dev\`, or set ABLO_API_KEY to the key of the plane this database should join (its sk_live_ key for production).${ambient ? `
|
|
5717
|
+
|
|
5718
|
+
${ambient}` : ""}` : `Not logged in, and no ABLO_API_KEY is set. Run \`ablo login\` (or set ABLO_API_KEY) so Ablo knows which project to register this database for.${ambient ? `
|
|
5719
|
+
|
|
5720
|
+
${ambient}` : ""}`,
|
|
5704
5721
|
{ code: "cli_api_key_missing" }
|
|
5705
5722
|
);
|
|
5706
5723
|
}
|
|
@@ -5715,23 +5732,39 @@ Mint a sandbox key with \`npx ablo dev\`, or set ABLO_API_KEY to the key of the
|
|
|
5715
5732
|
);
|
|
5716
5733
|
const pooledAdmin = detectPooler(adminUrl);
|
|
5717
5734
|
if (pooledAdmin?.confidence === "host") {
|
|
5718
|
-
|
|
5719
|
-
|
|
5735
|
+
if (pooledAdmin.direct) {
|
|
5736
|
+
adminUrl = pooledAdmin.direct;
|
|
5737
|
+
const pooledLabel = target;
|
|
5738
|
+
try {
|
|
5739
|
+
const parsed = new URL(adminUrl);
|
|
5740
|
+
target = `${parsed.host}${parsed.pathname === "/" ? "" : parsed.pathname}`;
|
|
5741
|
+
} catch {
|
|
5742
|
+
}
|
|
5743
|
+
console.log(
|
|
5744
|
+
` ${import_picocolors11.default.yellow("!")} ${import_picocolors11.default.bold(pooledLabel)} is a connection pooler, so this run uses the direct host:
|
|
5745
|
+
${import_picocolors11.default.bold(target)}
|
|
5746
|
+
` + import_picocolors11.default.dim(
|
|
5747
|
+
` A pooler terminates the session, so replication cannot run over it. Your app
|
|
5748
|
+
keeps the pooled URL; the setup needs the database itself.
|
|
5720
5749
|
`
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5750
|
+
)
|
|
5751
|
+
);
|
|
5752
|
+
} else {
|
|
5753
|
+
console.error(
|
|
5754
|
+
` ${import_picocolors11.default.yellow("!")} ${import_picocolors11.default.bold(target)} is a connection pooler, not the database.
|
|
5726
5755
|
`
|
|
5727
|
-
)
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5756
|
+
);
|
|
5757
|
+
console.error(
|
|
5758
|
+
import_picocolors11.default.dim(
|
|
5759
|
+
` A pooler terminates the session, so replication cannot run over it. Setting up
|
|
5760
|
+
through it creates roles that Ablo then cannot use to stream.
|
|
5732
5761
|
`
|
|
5733
|
-
|
|
5734
|
-
|
|
5762
|
+
)
|
|
5763
|
+
);
|
|
5764
|
+
console.error(` Re-run against the direct database host, not the pooled one.
|
|
5765
|
+
`);
|
|
5766
|
+
process.exit(1);
|
|
5767
|
+
}
|
|
5735
5768
|
}
|
|
5736
5769
|
if (pooledAdmin?.confidence === "port") {
|
|
5737
5770
|
console.log(
|
|
@@ -5771,31 +5804,31 @@ Mint a sandbox key with \`npx ablo dev\`, or set ABLO_API_KEY to the key of the
|
|
|
5771
5804
|
`);
|
|
5772
5805
|
console.error(
|
|
5773
5806
|
import_picocolors11.default.dim(` Your database is untouched.
|
|
5774
|
-
`) + ` To move it here, disconnect it there first with ${import_picocolors11.default.cyan("ablo connect deregister")}
|
|
5775
|
-
`
|
|
5807
|
+
`) + ` To move it here, disconnect it there first with ${import_picocolors11.default.cyan("ablo connect deregister")}
|
|
5808
|
+
` + import_picocolors11.default.dim(` (run with a key for that plane). Match the project id to a name with `) + import_picocolors11.default.bold("ablo projects list --json") + import_picocolors11.default.dim(".") + "\n"
|
|
5776
5809
|
);
|
|
5777
5810
|
process.exit(1);
|
|
5778
5811
|
}
|
|
5812
|
+
let rotatePlane = null;
|
|
5779
5813
|
if (rotating) {
|
|
5780
5814
|
const state = await fetchDataSourceState(apiBaseUrl(), apiKey).catch(
|
|
5781
5815
|
() => ({ kind: "unknown", detail: "unreachable" })
|
|
5782
5816
|
);
|
|
5783
|
-
|
|
5784
|
-
rotating,
|
|
5817
|
+
rotatePlane = {
|
|
5785
5818
|
planeHasConnection: state.kind === "connected",
|
|
5786
5819
|
known: state.kind !== "unknown",
|
|
5787
5820
|
// 401/403 is Ablo answering and declining the key, not a network failure.
|
|
5788
5821
|
keyRejected: state.kind === "unknown" && /HTTP 40[13]/.test(state.detail)
|
|
5789
|
-
}
|
|
5790
|
-
if (
|
|
5791
|
-
|
|
5822
|
+
};
|
|
5823
|
+
if (rotatePlane.keyRejected) {
|
|
5824
|
+
const refusal = rotateWithoutConnection({ rotating, ...rotatePlane, existingRoles: [] });
|
|
5825
|
+
if (refusal) {
|
|
5826
|
+
console.error(` ${import_picocolors11.default.yellow("!")} ${refusal}
|
|
5792
5827
|
`);
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
);
|
|
5798
|
-
process.exit(1);
|
|
5828
|
+
console.error(import_picocolors11.default.dim(` Your database is untouched.
|
|
5829
|
+
`));
|
|
5830
|
+
process.exit(1);
|
|
5831
|
+
}
|
|
5799
5832
|
}
|
|
5800
5833
|
}
|
|
5801
5834
|
const admin = src_default(adminUrl, {
|
|
@@ -5855,9 +5888,21 @@ Mint a sandbox key with \`npx ablo dev\`, or set ABLO_API_KEY to the key of the
|
|
|
5855
5888
|
const pubReconcile = reconcilePublicationPlan(existingPublication, tables);
|
|
5856
5889
|
const role = args.role && args.role.length > 0 ? args.role : import_footprint.ABLO_REPLICATION_ROLE;
|
|
5857
5890
|
const writeRole = args.writeRole && args.writeRole.length > 0 ? args.writeRole : import_footprint.ABLO_WRITE_ROLE;
|
|
5891
|
+
const existingRoles = await presentRoles(admin, [role, writeRole]).catch(() => []);
|
|
5892
|
+
if (rotatePlane) {
|
|
5893
|
+
const refusal = rotateWithoutConnection({ rotating, ...rotatePlane, existingRoles });
|
|
5894
|
+
if (refusal) {
|
|
5895
|
+
await admin.end({ timeout: 2 });
|
|
5896
|
+
console.error(` ${import_picocolors11.default.yellow("!")} ${refusal}
|
|
5897
|
+
`);
|
|
5898
|
+
console.error(import_picocolors11.default.dim(` Your database is untouched.
|
|
5899
|
+
`));
|
|
5900
|
+
process.exit(1);
|
|
5901
|
+
}
|
|
5902
|
+
}
|
|
5858
5903
|
const blocker = reapplyBlocker({
|
|
5859
5904
|
rotating,
|
|
5860
|
-
existingRoles
|
|
5905
|
+
existingRoles
|
|
5861
5906
|
});
|
|
5862
5907
|
if (blocker) {
|
|
5863
5908
|
await admin.end({ timeout: 2 });
|
|
@@ -6080,6 +6125,7 @@ function parseConnectArgs(argv) {
|
|
|
6080
6125
|
let yes = false;
|
|
6081
6126
|
let showSql = false;
|
|
6082
6127
|
let scan = false;
|
|
6128
|
+
let locate = false;
|
|
6083
6129
|
let manual = false;
|
|
6084
6130
|
let tables = [];
|
|
6085
6131
|
let role = import_footprint.ABLO_REPLICATION_ROLE;
|
|
@@ -6104,9 +6150,12 @@ function parseConnectArgs(argv) {
|
|
|
6104
6150
|
case "scan":
|
|
6105
6151
|
scan = true;
|
|
6106
6152
|
break;
|
|
6153
|
+
case "locate":
|
|
6154
|
+
locate = true;
|
|
6155
|
+
break;
|
|
6107
6156
|
default:
|
|
6108
6157
|
throw new import_errors10.AbloValidationError(
|
|
6109
|
-
`unknown connect subcommand: ${lead} (expected register, deregister, check, apply, rotate, scan)`,
|
|
6158
|
+
`unknown connect subcommand: ${lead} (expected register, deregister, check, apply, rotate, scan, locate)`,
|
|
6110
6159
|
{ code: "cli_invalid_arguments" }
|
|
6111
6160
|
);
|
|
6112
6161
|
}
|
|
@@ -6168,6 +6217,7 @@ function parseConnectArgs(argv) {
|
|
|
6168
6217
|
yes,
|
|
6169
6218
|
showSql,
|
|
6170
6219
|
scan,
|
|
6220
|
+
locate,
|
|
6171
6221
|
tables,
|
|
6172
6222
|
role,
|
|
6173
6223
|
writeRole,
|
|
@@ -6465,8 +6515,11 @@ async function runCheck() {
|
|
|
6465
6515
|
);
|
|
6466
6516
|
const apiKey = resolveApiKey();
|
|
6467
6517
|
if (!apiKey) {
|
|
6518
|
+
const ambient = ambientEnvKeyNote();
|
|
6468
6519
|
throw new import_errors10.AbloAuthenticationError(
|
|
6469
|
-
|
|
6520
|
+
`No API key found. Run \`ablo login\` (or set ABLO_API_KEY), then re-run \`ablo connect check\`.${ambient ? `
|
|
6521
|
+
|
|
6522
|
+
${ambient}` : ""}`,
|
|
6470
6523
|
{ code: "cli_api_key_missing" }
|
|
6471
6524
|
);
|
|
6472
6525
|
}
|
|
@@ -6531,8 +6584,11 @@ async function runRegister(args) {
|
|
|
6531
6584
|
const writeDbUrl = requireScopedUrl("write", "register");
|
|
6532
6585
|
const apiKey = resolveApiKey();
|
|
6533
6586
|
if (!apiKey) {
|
|
6587
|
+
const ambient = ambientEnvKeyNote();
|
|
6534
6588
|
throw new import_errors10.AbloAuthenticationError(
|
|
6535
|
-
|
|
6589
|
+
`Not logged in. Run \`ablo login\` (or set ABLO_API_KEY) so Ablo knows which project to register this database for.${ambient ? `
|
|
6590
|
+
|
|
6591
|
+
${ambient}` : ""}`,
|
|
6536
6592
|
{ code: "cli_api_key_missing" }
|
|
6537
6593
|
);
|
|
6538
6594
|
}
|
|
@@ -6633,6 +6689,62 @@ async function runScan() {
|
|
|
6633
6689
|
}
|
|
6634
6690
|
process.exit(retired.length > 0 ? 1 : 0);
|
|
6635
6691
|
}
|
|
6692
|
+
async function runLocate(args) {
|
|
6693
|
+
console.log(
|
|
6694
|
+
`
|
|
6695
|
+
${brand("ablo")} ${import_picocolors12.default.dim("connect locate")} ${import_picocolors12.default.dim("which plane holds this database")}
|
|
6696
|
+
`
|
|
6697
|
+
);
|
|
6698
|
+
const url = args.url ?? readProjectAdminDatabaseUrl();
|
|
6699
|
+
if (!url) {
|
|
6700
|
+
throw new import_errors10.AbloValidationError(
|
|
6701
|
+
"Locating needs a connection string to identify the database. Pass --url <conn> (or set DATABASE_URL) and re-run.",
|
|
6702
|
+
{ code: "cli_database_url_missing" }
|
|
6703
|
+
);
|
|
6704
|
+
}
|
|
6705
|
+
const apiKey = resolveApiKey();
|
|
6706
|
+
if (!apiKey) {
|
|
6707
|
+
const ambient = ambientEnvKeyNote();
|
|
6708
|
+
throw new import_errors10.AbloAuthenticationError(
|
|
6709
|
+
`No API key found. Run \`ablo login\` (or set ABLO_API_KEY), then re-run \`ablo connect locate\`.${ambient ? `
|
|
6710
|
+
|
|
6711
|
+
${ambient}` : ""}`,
|
|
6712
|
+
{ code: "cli_api_key_missing" }
|
|
6713
|
+
);
|
|
6714
|
+
}
|
|
6715
|
+
let label = "this database";
|
|
6716
|
+
try {
|
|
6717
|
+
const parsed = new URL(url);
|
|
6718
|
+
label = `${parsed.host}${parsed.pathname === "/" ? "" : parsed.pathname}`;
|
|
6719
|
+
} catch {
|
|
6720
|
+
}
|
|
6721
|
+
const answer = await requestControlPlane({
|
|
6722
|
+
path: "/v1/datasources/locate",
|
|
6723
|
+
method: "POST",
|
|
6724
|
+
apiKey,
|
|
6725
|
+
body: { connectionString: url },
|
|
6726
|
+
responseSchema: import_wire7.datasourceLocationResponseSchema
|
|
6727
|
+
});
|
|
6728
|
+
if (!answer.held) {
|
|
6729
|
+
console.log(
|
|
6730
|
+
` ${import_picocolors12.default.green("\u2713")} No plane holds ${import_picocolors12.default.bold(label)} \u2014 ${import_picocolors12.default.bold("ablo connect apply")} can register it here.
|
|
6731
|
+
`
|
|
6732
|
+
);
|
|
6733
|
+
return;
|
|
6734
|
+
}
|
|
6735
|
+
console.log(
|
|
6736
|
+
` ${import_picocolors12.default.yellow("!")} ${import_picocolors12.default.bold(label)} is connected to ${answer.held.project ? `project ${import_picocolors12.default.bold(answer.held.project)}, ` : ""}branch ${import_picocolors12.default.bold(answer.held.branch)}.
|
|
6737
|
+
`
|
|
6738
|
+
);
|
|
6739
|
+
console.log(
|
|
6740
|
+
import_picocolors12.default.dim(
|
|
6741
|
+
` Ablo streams a database from one plane at a time. To move it, disconnect it there
|
|
6742
|
+
first \u2014 run `
|
|
6743
|
+
) + import_picocolors12.default.cyan("ablo connect deregister") + import_picocolors12.default.dim(` with a key for that plane, then connect here.
|
|
6744
|
+
`) + import_picocolors12.default.dim(` Confirm a candidate key first with `) + import_picocolors12.default.bold("ablo whoami --key-env <NAME>") + import_picocolors12.default.dim(`.
|
|
6745
|
+
`) + import_picocolors12.default.dim(` Match the project id to a name with `) + import_picocolors12.default.bold("ablo projects list --json") + import_picocolors12.default.dim(".") + "\n"
|
|
6746
|
+
);
|
|
6747
|
+
}
|
|
6636
6748
|
async function connect(argv) {
|
|
6637
6749
|
if (argv[0] === "deregister") {
|
|
6638
6750
|
const { disconnect: disconnect2 } = await Promise.resolve().then(() => (init_disconnect(), disconnect_exports));
|
|
@@ -6657,6 +6769,10 @@ async function connect(argv) {
|
|
|
6657
6769
|
await runScan();
|
|
6658
6770
|
return;
|
|
6659
6771
|
}
|
|
6772
|
+
if (args.locate) {
|
|
6773
|
+
await runLocate(args);
|
|
6774
|
+
return;
|
|
6775
|
+
}
|
|
6660
6776
|
const credentialReachable = (args.url ?? readProjectAdminDatabaseUrl()) != null;
|
|
6661
6777
|
const canConfirm = process.stdout.isTTY || args.yes;
|
|
6662
6778
|
if (!args.manual && credentialReachable && canConfirm) {
|
|
@@ -6666,7 +6782,7 @@ async function connect(argv) {
|
|
|
6666
6782
|
}
|
|
6667
6783
|
printConnectRecipe(args);
|
|
6668
6784
|
}
|
|
6669
|
-
var import_errors10, import_picocolors12, import_footprint2, FOOTPRINT_LOOKUP, CONNECT_USAGE;
|
|
6785
|
+
var import_errors10, import_picocolors12, import_footprint2, import_wire7, FOOTPRINT_LOOKUP, CONNECT_USAGE;
|
|
6670
6786
|
var init_connect = __esm({
|
|
6671
6787
|
"src/connect.ts"() {
|
|
6672
6788
|
"use strict";
|
|
@@ -6678,6 +6794,7 @@ var init_connect = __esm({
|
|
|
6678
6794
|
init_dbRole();
|
|
6679
6795
|
init_config();
|
|
6680
6796
|
init_controlPlane();
|
|
6797
|
+
import_wire7 = require("@abloatai/transaction/wire");
|
|
6681
6798
|
init_theme();
|
|
6682
6799
|
init_remoteValidation();
|
|
6683
6800
|
init_connectSetup();
|
|
@@ -6701,6 +6818,7 @@ var init_connect = __esm({
|
|
|
6701
6818
|
npx ablo connect check Confirm the connected database is ready, from Ablo's side (needs only ABLO_API_KEY)
|
|
6702
6819
|
npx ablo connect rotate New passwords for both logins, then re-register
|
|
6703
6820
|
npx ablo connect scan List anything Ablo ever set up in your database (read-only, never drops)
|
|
6821
|
+
npx ablo connect locate See which plane holds this database (read-only; nothing is changed)
|
|
6704
6822
|
|
|
6705
6823
|
Running it: bare \`ablo connect\` sets everything up for you \u2014 creating the two
|
|
6706
6824
|
scoped logins, sharing your tables, and registering \u2014 whenever it finds a
|
|
@@ -282702,7 +282820,7 @@ Node text: ${this.#forgottenText}`;
|
|
|
282702
282820
|
// src/index.ts
|
|
282703
282821
|
init_cjs_shims();
|
|
282704
282822
|
init_dist2();
|
|
282705
|
-
var
|
|
282823
|
+
var import_picocolors28 = __toESM(require_picocolors(), 1);
|
|
282706
282824
|
var import_fs13 = require("fs");
|
|
282707
282825
|
var import_path8 = require("path");
|
|
282708
282826
|
var import_child_process3 = require("child_process");
|
|
@@ -283736,6 +283854,223 @@ async function runBranchDev(argv, dependencies = {}) {
|
|
|
283736
283854
|
});
|
|
283737
283855
|
}
|
|
283738
283856
|
|
|
283857
|
+
// src/whoami.ts
|
|
283858
|
+
init_cjs_shims();
|
|
283859
|
+
var import_picocolors16 = __toESM(require_picocolors(), 1);
|
|
283860
|
+
var import_errors13 = require("@abloatai/transaction/errors");
|
|
283861
|
+
init_config();
|
|
283862
|
+
init_controlPlane();
|
|
283863
|
+
|
|
283864
|
+
// src/credentialCapability.ts
|
|
283865
|
+
init_cjs_shims();
|
|
283866
|
+
var import_credentialPolicy3 = require("@abloatai/transaction/auth/credentialPolicy");
|
|
283867
|
+
init_config();
|
|
283868
|
+
function secretCounterpart(key) {
|
|
283869
|
+
return modeFromKey(key) === "production" ? "sk_live_" : "sk_test_";
|
|
283870
|
+
}
|
|
283871
|
+
function credentialCapability(key) {
|
|
283872
|
+
const kind = key ? (0, import_credentialPolicy3.classifyCredentialKind)(key) : null;
|
|
283873
|
+
if (!key || kind === null) return { kind, label: "", note: null };
|
|
283874
|
+
const secret = `${secretCounterpart(key)}\u2026`;
|
|
283875
|
+
switch (kind) {
|
|
283876
|
+
case "secret":
|
|
283877
|
+
return { kind, label: "", note: null };
|
|
283878
|
+
case "restricted":
|
|
283879
|
+
return {
|
|
283880
|
+
kind,
|
|
283881
|
+
label: "scoped",
|
|
283882
|
+
note: `A scoped key does exactly what it was minted for. The production key \`ablo login\` stores is for observing your live plane with \`ablo status\` and \`ablo logs\`; authoring schema there takes a secret ${secret} key from the dashboard.`
|
|
283883
|
+
};
|
|
283884
|
+
case "publishable":
|
|
283885
|
+
return {
|
|
283886
|
+
kind,
|
|
283887
|
+
label: "read-only",
|
|
283888
|
+
note: `This is the key that is safe to ship in a browser bundle, and it reads. Work from a terminal wants a secret ${secret} key.`
|
|
283889
|
+
};
|
|
283890
|
+
case "ephemeral":
|
|
283891
|
+
return {
|
|
283892
|
+
kind,
|
|
283893
|
+
label: "session key",
|
|
283894
|
+
note: `This is a short-lived credential minted for one signed-in person, and it expires. Pushing a schema needs a secret ${secret} key.`
|
|
283895
|
+
};
|
|
283896
|
+
}
|
|
283897
|
+
}
|
|
283898
|
+
|
|
283899
|
+
// src/whoami.ts
|
|
283900
|
+
init_dbRole();
|
|
283901
|
+
init_theme();
|
|
283902
|
+
init_target();
|
|
283903
|
+
var WHOAMI_USAGE = ` ablo whoami \u2014 show the plane a credential acts on
|
|
283904
|
+
|
|
283905
|
+
Usage
|
|
283906
|
+
npx ablo whoami
|
|
283907
|
+
npx ablo whoami --key-env <NAME>
|
|
283908
|
+
npx ablo whoami --key <VALUE>
|
|
283909
|
+
npx ablo whoami --json
|
|
283910
|
+
|
|
283911
|
+
Credential choice
|
|
283912
|
+
With no flag, uses ABLO_API_KEY, then the active project's stored data key,
|
|
283913
|
+
then the stored login. This command does not load .env files implicitly.
|
|
283914
|
+
|
|
283915
|
+
--key-env reads a named variable from the process, .env.local, or .env
|
|
283916
|
+
without putting its value in shell history or the process list. Prefer it
|
|
283917
|
+
for comparing several keys.
|
|
283918
|
+
--key accepts a value directly for one-off use.
|
|
283919
|
+
|
|
283920
|
+
Output never prints the full credential. Identity is confirmed by the server;
|
|
283921
|
+
an invalid key, unreachable server, or unsupported server fails non-zero.`;
|
|
283922
|
+
function parseWhoamiArgs(argv) {
|
|
283923
|
+
let json = false;
|
|
283924
|
+
let key;
|
|
283925
|
+
let keyEnv;
|
|
283926
|
+
for (let i = 0; i < argv.length; i++) {
|
|
283927
|
+
const arg = argv[i];
|
|
283928
|
+
switch (arg) {
|
|
283929
|
+
case "--json":
|
|
283930
|
+
json = true;
|
|
283931
|
+
break;
|
|
283932
|
+
case "--key": {
|
|
283933
|
+
const value = argv[++i];
|
|
283934
|
+
if (!value || value.startsWith("--")) {
|
|
283935
|
+
throw new import_errors13.AbloValidationError("`--key` needs a credential value.", {
|
|
283936
|
+
code: "cli_invalid_arguments"
|
|
283937
|
+
});
|
|
283938
|
+
}
|
|
283939
|
+
key = value;
|
|
283940
|
+
break;
|
|
283941
|
+
}
|
|
283942
|
+
case "--key-env": {
|
|
283943
|
+
const value = argv[++i];
|
|
283944
|
+
if (!value || value.startsWith("--")) {
|
|
283945
|
+
throw new import_errors13.AbloValidationError("`--key-env` needs an environment variable name.", {
|
|
283946
|
+
code: "cli_invalid_arguments"
|
|
283947
|
+
});
|
|
283948
|
+
}
|
|
283949
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {
|
|
283950
|
+
throw new import_errors13.AbloValidationError(
|
|
283951
|
+
`\`${value}\` is not a valid environment variable name.`,
|
|
283952
|
+
{ code: "cli_invalid_arguments" }
|
|
283953
|
+
);
|
|
283954
|
+
}
|
|
283955
|
+
keyEnv = value;
|
|
283956
|
+
break;
|
|
283957
|
+
}
|
|
283958
|
+
default:
|
|
283959
|
+
throw new import_errors13.AbloValidationError(`unknown whoami flag: ${arg}`, {
|
|
283960
|
+
code: "cli_invalid_arguments"
|
|
283961
|
+
});
|
|
283962
|
+
}
|
|
283963
|
+
}
|
|
283964
|
+
if (key && keyEnv) {
|
|
283965
|
+
throw new import_errors13.AbloValidationError("Choose one credential source: `--key` or `--key-env`.", {
|
|
283966
|
+
code: "cli_invalid_arguments"
|
|
283967
|
+
});
|
|
283968
|
+
}
|
|
283969
|
+
return { json, ...key ? { key } : {}, ...keyEnv ? { keyEnv } : {} };
|
|
283970
|
+
}
|
|
283971
|
+
function selectWhoamiCredential(args, cwd = process.cwd()) {
|
|
283972
|
+
if (args.key) return { key: args.key, source: "--key", targetSource: "env" };
|
|
283973
|
+
if (args.keyEnv) {
|
|
283974
|
+
const found = readProjectEnvVariable(args.keyEnv, cwd);
|
|
283975
|
+
if (!found) {
|
|
283976
|
+
throw new import_errors13.AbloAuthenticationError(
|
|
283977
|
+
`${args.keyEnv} is not set in the process environment, .env.local, or .env.`,
|
|
283978
|
+
{ code: "cli_api_key_missing" }
|
|
283979
|
+
);
|
|
283980
|
+
}
|
|
283981
|
+
return {
|
|
283982
|
+
key: found.value,
|
|
283983
|
+
source: `${found.source}:${args.keyEnv}`,
|
|
283984
|
+
targetSource: "env"
|
|
283985
|
+
};
|
|
283986
|
+
}
|
|
283987
|
+
const dataKey = resolveApiKey();
|
|
283988
|
+
if (dataKey) {
|
|
283989
|
+
return {
|
|
283990
|
+
key: dataKey,
|
|
283991
|
+
source: process.env.ABLO_API_KEY ? "env:ABLO_API_KEY" : "stored data key",
|
|
283992
|
+
targetSource: process.env.ABLO_API_KEY ? "env" : "stored"
|
|
283993
|
+
};
|
|
283994
|
+
}
|
|
283995
|
+
const managementKey = resolveManagementKey();
|
|
283996
|
+
if (managementKey) {
|
|
283997
|
+
return {
|
|
283998
|
+
key: managementKey,
|
|
283999
|
+
source: process.env.ABLO_MANAGEMENT_KEY ? "env:ABLO_MANAGEMENT_KEY" : "stored login",
|
|
284000
|
+
targetSource: process.env.ABLO_MANAGEMENT_KEY ? "env" : "stored"
|
|
284001
|
+
};
|
|
284002
|
+
}
|
|
284003
|
+
const ambient = ambientEnvKeyNote();
|
|
284004
|
+
throw new import_errors13.AbloAuthenticationError(
|
|
284005
|
+
`No credential found. Run \`ablo login\`, set ABLO_API_KEY, or pass \`--key-env <NAME>\`.${ambient ? `
|
|
284006
|
+
|
|
284007
|
+
${ambient}` : ""}`,
|
|
284008
|
+
{ code: "cli_api_key_missing" }
|
|
284009
|
+
);
|
|
284010
|
+
}
|
|
284011
|
+
async function whoami(argv) {
|
|
284012
|
+
const args = parseWhoamiArgs(argv);
|
|
284013
|
+
const selected = selectWhoamiCredential(args);
|
|
284014
|
+
const target = await resolveTarget({
|
|
284015
|
+
url: apiBaseUrl(),
|
|
284016
|
+
apiKey: selected.key,
|
|
284017
|
+
keySource: selected.targetSource,
|
|
284018
|
+
strict: true
|
|
284019
|
+
});
|
|
284020
|
+
const confirmed = target.confirmed;
|
|
284021
|
+
if (!confirmed) {
|
|
284022
|
+
throw new import_errors13.AbloAuthenticationError(
|
|
284023
|
+
"The server did not confirm an identity for this credential.",
|
|
284024
|
+
{ code: "identity_resolve_failed" }
|
|
284025
|
+
);
|
|
284026
|
+
}
|
|
284027
|
+
const project = confirmed.project;
|
|
284028
|
+
const projectLabel = project ? project.isDefault ? "default" : project.slug : "default";
|
|
284029
|
+
const actsOn = confirmed.branchId ? confirmed.branchRoot ? "production root" : `branch ${confirmed.branchId}` : confirmed.environment ?? "unknown";
|
|
284030
|
+
const capability = credentialCapability(selected.key);
|
|
284031
|
+
if (args.json) {
|
|
284032
|
+
console.log(
|
|
284033
|
+
JSON.stringify(
|
|
284034
|
+
{
|
|
284035
|
+
authenticated: true,
|
|
284036
|
+
key: {
|
|
284037
|
+
prefix: `${selected.key.slice(0, 12)}\u2026`,
|
|
284038
|
+
source: selected.source,
|
|
284039
|
+
kind: capability.kind
|
|
284040
|
+
},
|
|
284041
|
+
organizationId: confirmed.organizationId,
|
|
284042
|
+
project: project ? {
|
|
284043
|
+
id: project.id,
|
|
284044
|
+
slug: projectLabel,
|
|
284045
|
+
name: project.name,
|
|
284046
|
+
default: project.isDefault
|
|
284047
|
+
} : null,
|
|
284048
|
+
environment: confirmed.environment,
|
|
284049
|
+
branchId: confirmed.branchId ?? null,
|
|
284050
|
+
branchRoot: confirmed.branchRoot ?? false
|
|
284051
|
+
},
|
|
284052
|
+
null,
|
|
284053
|
+
2
|
|
284054
|
+
)
|
|
284055
|
+
);
|
|
284056
|
+
return;
|
|
284057
|
+
}
|
|
284058
|
+
console.log(`
|
|
284059
|
+
${brand("ablo")} ${import_picocolors16.default.dim("whoami")}
|
|
284060
|
+
`);
|
|
284061
|
+
console.log(
|
|
284062
|
+
` ${import_picocolors16.default.dim("key")} ${selected.key.slice(0, 12)}\u2026 ${import_picocolors16.default.dim(`(${selected.source} \xB7 ${capability.label})`)}`
|
|
284063
|
+
);
|
|
284064
|
+
console.log(` ${import_picocolors16.default.dim("org")} ${import_picocolors16.default.dim(confirmed.organizationId)}`);
|
|
284065
|
+
console.log(
|
|
284066
|
+
` ${import_picocolors16.default.dim("project")} ${import_picocolors16.default.bold(projectLabel)}${project ? ` ${import_picocolors16.default.dim(`(${project.id})`)}` : ""}`
|
|
284067
|
+
);
|
|
284068
|
+
console.log(` ${import_picocolors16.default.dim("acts on")} ${import_picocolors16.default.bold(actsOn)}`);
|
|
284069
|
+
console.log(`
|
|
284070
|
+
${import_picocolors16.default.green("\u2713")} ${import_picocolors16.default.dim("credential accepted; target confirmed by the server")}
|
|
284071
|
+
`);
|
|
284072
|
+
}
|
|
284073
|
+
|
|
283739
284074
|
// src/commands.ts
|
|
283740
284075
|
var CORE_GROUPS = ["Start", "Every day", "More"];
|
|
283741
284076
|
var FULL_GROUPS = [
|
|
@@ -283786,6 +284121,7 @@ var COMMANDS = [
|
|
|
283786
284121
|
{ run: "connect apply", does: "Run that setup for you, from a one-time admin URL" },
|
|
283787
284122
|
{ run: "connect check", does: "Confirm your database is ready to share changes with Ablo" },
|
|
283788
284123
|
{ run: "connect scan", does: "List anything Ablo ever set up in your database (read-only)" },
|
|
284124
|
+
{ run: "connect locate", does: "See which plane holds a database before connecting it" },
|
|
283789
284125
|
{ run: "connect deregister", does: "Disconnect this project's database \u2014 Ablo stops reading and writing it" }
|
|
283790
284126
|
]
|
|
283791
284127
|
}
|
|
@@ -283875,6 +284211,18 @@ var COMMANDS = [
|
|
|
283875
284211
|
]
|
|
283876
284212
|
}
|
|
283877
284213
|
},
|
|
284214
|
+
{
|
|
284215
|
+
name: "whoami",
|
|
284216
|
+
usage: WHOAMI_USAGE,
|
|
284217
|
+
full: {
|
|
284218
|
+
group: "See what's happening",
|
|
284219
|
+
rows: [
|
|
284220
|
+
{ run: "whoami", does: "Show the server-confirmed plane the active credential acts on" },
|
|
284221
|
+
{ run: "whoami --key-env <NAME>", does: "Inspect another key without exposing it in argv" },
|
|
284222
|
+
{ run: "whoami --json", does: "Same, machine-readable" }
|
|
284223
|
+
]
|
|
284224
|
+
}
|
|
284225
|
+
},
|
|
283878
284226
|
{
|
|
283879
284227
|
name: "status",
|
|
283880
284228
|
core: { group: "Every day", does: "See what this key acts on, your pushed schema, and whether writes will work" },
|
|
@@ -284003,15 +284351,15 @@ function fullRows(group) {
|
|
|
284003
284351
|
}
|
|
284004
284352
|
|
|
284005
284353
|
// src/index.ts
|
|
284006
|
-
var
|
|
284354
|
+
var import_errors21 = require("@abloatai/transaction/errors");
|
|
284007
284355
|
init_push();
|
|
284008
284356
|
|
|
284009
284357
|
// src/generate.ts
|
|
284010
284358
|
init_cjs_shims();
|
|
284011
|
-
var
|
|
284359
|
+
var import_errors14 = require("@abloatai/transaction/errors");
|
|
284012
284360
|
var import_fs8 = require("fs");
|
|
284013
284361
|
var import_path6 = require("path");
|
|
284014
|
-
var
|
|
284362
|
+
var import_picocolors17 = __toESM(require_picocolors(), 1);
|
|
284015
284363
|
var import_schema7 = require("@abloatai/transaction/schema");
|
|
284016
284364
|
init_push();
|
|
284017
284365
|
var DEFAULT_SCHEMA_PATH4 = "ablo/schema.ts";
|
|
@@ -284034,7 +284382,7 @@ function parseGenerateArgs(argv) {
|
|
|
284034
284382
|
out = argv[++i] ?? out;
|
|
284035
284383
|
break;
|
|
284036
284384
|
default:
|
|
284037
|
-
throw new
|
|
284385
|
+
throw new import_errors14.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
|
|
284038
284386
|
}
|
|
284039
284387
|
}
|
|
284040
284388
|
return { schemaPath, exportName, out };
|
|
@@ -284044,7 +284392,7 @@ async function generate(argv) {
|
|
|
284044
284392
|
try {
|
|
284045
284393
|
args = parseGenerateArgs(argv);
|
|
284046
284394
|
} catch (err) {
|
|
284047
|
-
console.error(
|
|
284395
|
+
console.error(import_picocolors17.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
284048
284396
|
process.exit(1);
|
|
284049
284397
|
}
|
|
284050
284398
|
let source;
|
|
@@ -284053,22 +284401,22 @@ async function generate(argv) {
|
|
|
284053
284401
|
const schemaJson = JSON.parse((0, import_schema7.serializeSchema)(schema));
|
|
284054
284402
|
source = (0, import_schema7.generateTypes)(schemaJson);
|
|
284055
284403
|
} catch (err) {
|
|
284056
|
-
console.error(
|
|
284404
|
+
console.error(import_picocolors17.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
284057
284405
|
process.exit(1);
|
|
284058
284406
|
}
|
|
284059
284407
|
const abs = (0, import_path6.resolve)(process.cwd(), args.out);
|
|
284060
284408
|
(0, import_fs8.mkdirSync)((0, import_path6.dirname)(abs), { recursive: true });
|
|
284061
284409
|
(0, import_fs8.writeFileSync)(abs, source);
|
|
284062
|
-
console.log(` ${
|
|
284410
|
+
console.log(` ${import_picocolors17.default.green("\u2713")} Generated types \u2192 ${import_picocolors17.default.bold(args.out)}`);
|
|
284063
284411
|
}
|
|
284064
284412
|
|
|
284065
284413
|
// src/login.ts
|
|
284066
284414
|
init_cjs_shims();
|
|
284067
284415
|
var import_child_process2 = require("child_process");
|
|
284068
|
-
var
|
|
284416
|
+
var import_picocolors18 = __toESM(require_picocolors(), 1);
|
|
284069
284417
|
init_dist2();
|
|
284070
|
-
var
|
|
284071
|
-
var
|
|
284418
|
+
var import_errors15 = require("@abloatai/transaction/errors");
|
|
284419
|
+
var import_wire8 = require("@abloatai/transaction/wire");
|
|
284072
284420
|
init_config();
|
|
284073
284421
|
init_theme();
|
|
284074
284422
|
var CLIENT_ID = "ablo-cli";
|
|
@@ -284086,20 +284434,21 @@ function openBrowser(url) {
|
|
|
284086
284434
|
} catch {
|
|
284087
284435
|
}
|
|
284088
284436
|
}
|
|
284089
|
-
function
|
|
284090
|
-
const i = argv.indexOf(
|
|
284437
|
+
function parseSlugFlag(argv, flag2) {
|
|
284438
|
+
const i = argv.indexOf(flag2);
|
|
284091
284439
|
if (i >= 0) {
|
|
284092
284440
|
const slug = argv[i + 1];
|
|
284093
284441
|
if (slug && !slug.startsWith("-")) return slug;
|
|
284094
284442
|
}
|
|
284095
|
-
const eq = argv.find((a) => a.startsWith(
|
|
284096
|
-
return eq ? eq.slice(
|
|
284443
|
+
const eq = argv.find((a) => a.startsWith(`${flag2}=`));
|
|
284444
|
+
return eq ? eq.slice(flag2.length + 1) || void 0 : void 0;
|
|
284097
284445
|
}
|
|
284098
284446
|
async function deviceLogin(argv, deps = {}) {
|
|
284099
284447
|
const openUrl = deps.openUrl ?? openBrowser;
|
|
284100
284448
|
Ie(`${brand("ablo")} login`);
|
|
284101
|
-
const requested =
|
|
284449
|
+
const requested = parseSlugFlag(argv, "--project") ?? getActiveProject()?.slug;
|
|
284102
284450
|
const targetProject = requested === DEFAULT_PROFILE ? void 0 : requested;
|
|
284451
|
+
const targetOrg = parseSlugFlag(argv, "--org");
|
|
284103
284452
|
const interactive = Boolean(process.stdout.isTTY && process.stdin.isTTY);
|
|
284104
284453
|
let account = "login";
|
|
284105
284454
|
if (interactive) {
|
|
@@ -284126,11 +284475,11 @@ async function deviceLogin(argv, deps = {}) {
|
|
|
284126
284475
|
process.exit(1);
|
|
284127
284476
|
}
|
|
284128
284477
|
const code = await codeRes.json();
|
|
284129
|
-
const approvePath = `/cli?user_code=${code.user_code}`;
|
|
284478
|
+
const approvePath = `/cli?user_code=${code.user_code}${targetOrg ? `&org=${encodeURIComponent(targetOrg)}` : ""}`;
|
|
284130
284479
|
const url = account === "signup" ? `${DASHBOARD_URL}/signup?next=${encodeURIComponent(approvePath)}` : `${DASHBOARD_URL}${approvePath}`;
|
|
284131
|
-
Me(`${
|
|
284480
|
+
Me(`${import_picocolors18.default.bold(code.user_code)}
|
|
284132
284481
|
|
|
284133
|
-
${
|
|
284482
|
+
${import_picocolors18.default.dim(url)}`, "Approve in your browser");
|
|
284134
284483
|
openUrl(url);
|
|
284135
284484
|
const s = Y2();
|
|
284136
284485
|
s.start("Waiting for approval\u2026");
|
|
@@ -284200,7 +284549,7 @@ ${import_picocolors17.default.dim(url)}`, "Approve in your browser");
|
|
|
284200
284549
|
}
|
|
284201
284550
|
if (!provRes.ok) {
|
|
284202
284551
|
s.stop("Could not provision a key.");
|
|
284203
|
-
const err = (0,
|
|
284552
|
+
const err = (0, import_errors15.translateHttpError)(
|
|
284204
284553
|
provRes.status,
|
|
284205
284554
|
await provRes.json().catch(() => null),
|
|
284206
284555
|
provRes.headers.get("x-request-id") ?? void 0
|
|
@@ -284208,30 +284557,36 @@ ${import_picocolors17.default.dim(url)}`, "Approve in your browser");
|
|
|
284208
284557
|
M2.error(err.message);
|
|
284209
284558
|
if (err.code === "entity_not_found" && targetProject) {
|
|
284210
284559
|
M2.error(
|
|
284211
|
-
`If that isn't the account you meant, run ${
|
|
284560
|
+
`If that isn't the account you meant, run ${import_picocolors18.default.bold("npx ablo logout")} and sign in again. Otherwise create it with ${import_picocolors18.default.bold(`npx ablo projects create ${targetProject}`)}.`
|
|
284212
284561
|
);
|
|
284213
284562
|
} else {
|
|
284214
284563
|
M2.error(
|
|
284215
|
-
`The browser approval succeeded but the credential handoff failed. Try ${
|
|
284564
|
+
`The browser approval succeeded but the credential handoff failed. Try ${import_picocolors18.default.bold("npx ablo login")} again.`
|
|
284216
284565
|
);
|
|
284217
284566
|
}
|
|
284218
284567
|
process.exit(1);
|
|
284219
284568
|
}
|
|
284220
|
-
const parsedProv =
|
|
284569
|
+
const parsedProv = import_wire8.provisionKeyResponseSchema.safeParse(
|
|
284221
284570
|
await provRes.json().catch(() => null)
|
|
284222
284571
|
);
|
|
284223
284572
|
if (!parsedProv.success) {
|
|
284224
284573
|
s.stop("Could not provision a key.");
|
|
284225
284574
|
M2.error("The key handoff returned something this version does not recognize.");
|
|
284226
|
-
M2.error(`Try again, or upgrade with ${
|
|
284575
|
+
M2.error(`Try again, or upgrade with ${import_picocolors18.default.bold("npm i -g @abloatai/ablo")}.`);
|
|
284227
284576
|
process.exit(1);
|
|
284228
284577
|
}
|
|
284229
284578
|
const prov = parsedProv.data;
|
|
284230
284579
|
const entry = (k3) => ({
|
|
284231
284580
|
apiKey: k3.apiKey,
|
|
284232
284581
|
...prov.organizationId ? { organizationId: prov.organizationId } : {},
|
|
284582
|
+
...prov.organizationSlug ? { organizationSlug: prov.organizationSlug } : {},
|
|
284233
284583
|
...k3.expiresAt ? { expiresAt: k3.expiresAt } : {}
|
|
284234
284584
|
});
|
|
284585
|
+
if (targetOrg && prov.organizationSlug && prov.organizationSlug !== targetOrg) {
|
|
284586
|
+
M2.warn(
|
|
284587
|
+
`The approval chose ${import_picocolors18.default.bold(prov.organizationSlug)}, not ${import_picocolors18.default.bold(targetOrg)}. The credential is scoped to ${import_picocolors18.default.bold(prov.organizationSlug)}.`
|
|
284588
|
+
);
|
|
284589
|
+
}
|
|
284235
284590
|
const profileName = prov.project?.slug ?? DEFAULT_PROFILE;
|
|
284236
284591
|
const path = setProfileKeys(
|
|
284237
284592
|
profileName,
|
|
@@ -284241,9 +284596,10 @@ ${import_picocolors17.default.dim(url)}`, "Approve in your browser");
|
|
|
284241
284596
|
{ mode: "sandbox", activeProject: prov.project ?? void 0 }
|
|
284242
284597
|
);
|
|
284243
284598
|
s.stop(`Saved project credential to ${path}`);
|
|
284244
|
-
const
|
|
284599
|
+
const orgLabel = prov.organizationSlug ? ` to ${import_picocolors18.default.bold(prov.organizationSlug)}` : "";
|
|
284600
|
+
const where = prov.project ? ` ${import_picocolors18.default.dim(`(project ${prov.project.slug})`)}` : "";
|
|
284245
284601
|
Se(
|
|
284246
|
-
`${
|
|
284602
|
+
`${import_picocolors18.default.green("\u2713")} Logged in${orgLabel}${where}. Run ${import_picocolors18.default.bold("npx ablo dev")} to create or resume your Git branch and start with an expiring runtime key.`
|
|
284247
284603
|
);
|
|
284248
284604
|
}
|
|
284249
284605
|
async function login(argv = [], deps = {}) {
|
|
@@ -284252,14 +284608,14 @@ async function login(argv = [], deps = {}) {
|
|
|
284252
284608
|
function logout() {
|
|
284253
284609
|
const removed = clearCredential();
|
|
284254
284610
|
if (removed) {
|
|
284255
|
-
console.log(` ${
|
|
284611
|
+
console.log(` ${import_picocolors18.default.green("\u2713")} Logged out ${import_picocolors18.default.dim(`(credentials removed from ${configDir()})`)}`);
|
|
284256
284612
|
} else {
|
|
284257
|
-
console.log(` ${
|
|
284613
|
+
console.log(` ${import_picocolors18.default.dim("\u25CB")} Not logged in \u2014 nothing to remove.`);
|
|
284258
284614
|
}
|
|
284259
284615
|
if (process.env.ABLO_MANAGEMENT_KEY) {
|
|
284260
284616
|
console.log(
|
|
284261
|
-
|
|
284262
|
-
` Note: ${
|
|
284617
|
+
import_picocolors18.default.dim(
|
|
284618
|
+
` Note: ${import_picocolors18.default.bold("ABLO_MANAGEMENT_KEY")} is still set in this shell and takes precedence.`
|
|
284263
284619
|
)
|
|
284264
284620
|
);
|
|
284265
284621
|
}
|
|
@@ -284271,46 +284627,9 @@ init_projects();
|
|
|
284271
284627
|
|
|
284272
284628
|
// src/status.ts
|
|
284273
284629
|
init_cjs_shims();
|
|
284274
|
-
var
|
|
284630
|
+
var import_picocolors19 = __toESM(require_picocolors(), 1);
|
|
284275
284631
|
init_config();
|
|
284276
284632
|
init_target();
|
|
284277
|
-
|
|
284278
|
-
// src/credentialCapability.ts
|
|
284279
|
-
init_cjs_shims();
|
|
284280
|
-
var import_credentialPolicy3 = require("@abloatai/transaction/auth/credentialPolicy");
|
|
284281
|
-
init_config();
|
|
284282
|
-
function secretCounterpart(key) {
|
|
284283
|
-
return modeFromKey(key) === "production" ? "sk_live_" : "sk_test_";
|
|
284284
|
-
}
|
|
284285
|
-
function credentialCapability(key) {
|
|
284286
|
-
const kind = key ? (0, import_credentialPolicy3.classifyCredentialKind)(key) : null;
|
|
284287
|
-
if (!key || kind === null) return { kind, label: "", note: null };
|
|
284288
|
-
const secret = `${secretCounterpart(key)}\u2026`;
|
|
284289
|
-
switch (kind) {
|
|
284290
|
-
case "secret":
|
|
284291
|
-
return { kind, label: "", note: null };
|
|
284292
|
-
case "restricted":
|
|
284293
|
-
return {
|
|
284294
|
-
kind,
|
|
284295
|
-
label: "scoped",
|
|
284296
|
-
note: `A scoped key does exactly what it was minted for. The production key \`ablo login\` stores is for observing your live plane with \`ablo status\` and \`ablo logs\`; authoring schema there takes a secret ${secret} key from the dashboard.`
|
|
284297
|
-
};
|
|
284298
|
-
case "publishable":
|
|
284299
|
-
return {
|
|
284300
|
-
kind,
|
|
284301
|
-
label: "read-only",
|
|
284302
|
-
note: `This is the key that is safe to ship in a browser bundle, and it reads. Work from a terminal wants a secret ${secret} key.`
|
|
284303
|
-
};
|
|
284304
|
-
case "ephemeral":
|
|
284305
|
-
return {
|
|
284306
|
-
kind,
|
|
284307
|
-
label: "session key",
|
|
284308
|
-
note: `This is a short-lived credential minted for one signed-in person, and it expires. Pushing a schema needs a secret ${secret} key.`
|
|
284309
|
-
};
|
|
284310
|
-
}
|
|
284311
|
-
}
|
|
284312
|
-
|
|
284313
|
-
// src/status.ts
|
|
284314
284633
|
init_theme();
|
|
284315
284634
|
init_controlPlane();
|
|
284316
284635
|
var import_schema8 = require("@abloatai/transaction/coordination/schema");
|
|
@@ -284318,9 +284637,9 @@ init_readiness();
|
|
|
284318
284637
|
function expiryLabel(iso) {
|
|
284319
284638
|
const ms = Date.parse(iso) - Date.now();
|
|
284320
284639
|
if (Number.isNaN(ms)) return "";
|
|
284321
|
-
if (ms <= 0) return
|
|
284640
|
+
if (ms <= 0) return import_picocolors19.default.red("expired");
|
|
284322
284641
|
const days = Math.floor(ms / (24 * 60 * 60 * 1e3));
|
|
284323
|
-
return
|
|
284642
|
+
return import_picocolors19.default.dim(days > 0 ? `expires in ${days}d` : "expires <1d");
|
|
284324
284643
|
}
|
|
284325
284644
|
async function ping(apiUrl3) {
|
|
284326
284645
|
const ctrl = new AbortController();
|
|
@@ -284341,40 +284660,42 @@ function formatConflict(conflict) {
|
|
|
284341
284660
|
const parts = import_schema8.participantKindSchema.options.flatMap((k3) => conflict[k3] ? [`${k3}:${conflict[k3]}`] : []);
|
|
284342
284661
|
return parts.length ? `{${parts.join(",")}}` : "";
|
|
284343
284662
|
}
|
|
284344
|
-
function printTargetLines(target, localProject, storedOrganizationId) {
|
|
284663
|
+
function printTargetLines(target, localProject, storedOrganizationId, storedOrganizationSlug) {
|
|
284345
284664
|
const confirmed = target?.confirmed ?? null;
|
|
284346
284665
|
const org = confirmed?.organizationId ?? storedOrganizationId;
|
|
284347
284666
|
if (org) {
|
|
284348
|
-
const suffix = confirmed?.organizationId ? "" : ` ${
|
|
284349
|
-
|
|
284667
|
+
const suffix = confirmed?.organizationId ? "" : ` ${import_picocolors19.default.yellow("(unconfirmed)")}`;
|
|
284668
|
+
const slug = org === storedOrganizationId ? storedOrganizationSlug : void 0;
|
|
284669
|
+
const label = slug ? `${import_picocolors19.default.bold(slug)} ${import_picocolors19.default.dim(`(${org})`)}` : import_picocolors19.default.dim(org);
|
|
284670
|
+
console.log(` ${import_picocolors19.default.dim("org")} ${label}${suffix}`);
|
|
284350
284671
|
} else {
|
|
284351
284672
|
console.log(
|
|
284352
|
-
` ${
|
|
284673
|
+
` ${import_picocolors19.default.dim("org")} ${import_picocolors19.default.yellow("unknown")} ${import_picocolors19.default.dim("(the server did not confirm one for this key)")}`
|
|
284353
284674
|
);
|
|
284354
284675
|
}
|
|
284355
284676
|
let projectLine;
|
|
284356
284677
|
if (confirmed?.project) {
|
|
284357
284678
|
const p2 = confirmed.project;
|
|
284358
|
-
projectLine = p2.isDefault ? `${
|
|
284679
|
+
projectLine = p2.isDefault ? `${import_picocolors19.default.bold("default")} ${import_picocolors19.default.dim("(org-default)")}` : `${import_picocolors19.default.bold(p2.slug)} ${import_picocolors19.default.dim(`(${p2.id})`)}`;
|
|
284359
284680
|
} else if (confirmed) {
|
|
284360
|
-
projectLine = `${
|
|
284681
|
+
projectLine = `${import_picocolors19.default.bold("default")} ${import_picocolors19.default.dim("(org-default)")}`;
|
|
284361
284682
|
} else if (localProject) {
|
|
284362
|
-
projectLine = `${
|
|
284683
|
+
projectLine = `${import_picocolors19.default.bold(localProject.slug)} ${import_picocolors19.default.dim(`(${localProject.id})`)} ${import_picocolors19.default.yellow("(unconfirmed)")}`;
|
|
284363
284684
|
} else {
|
|
284364
|
-
projectLine = `${
|
|
284685
|
+
projectLine = `${import_picocolors19.default.bold("default")} ${target ? import_picocolors19.default.yellow("(unconfirmed)") : import_picocolors19.default.dim("(org-default)")}`;
|
|
284365
284686
|
}
|
|
284366
|
-
console.log(` ${
|
|
284687
|
+
console.log(` ${import_picocolors19.default.dim("project")} ${projectLine}`);
|
|
284367
284688
|
const branch = confirmed?.branchId ?? null;
|
|
284368
284689
|
const env = confirmed?.environment ?? target?.keyEnv ?? null;
|
|
284369
284690
|
if (branch) {
|
|
284370
284691
|
const label = confirmed?.branchRoot ? "production root" : `branch ${branch}`;
|
|
284371
|
-
console.log(` ${
|
|
284692
|
+
console.log(` ${import_picocolors19.default.dim("acts on")} ${import_picocolors19.default.bold(label)}`);
|
|
284372
284693
|
} else if (env) {
|
|
284373
|
-
const suffix = confirmed ? "" : ` ${
|
|
284374
|
-
console.log(` ${
|
|
284694
|
+
const suffix = confirmed ? "" : ` ${import_picocolors19.default.yellow("(unconfirmed)")}`;
|
|
284695
|
+
console.log(` ${import_picocolors19.default.dim("acts on")} ${import_picocolors19.default.bold(env)}${suffix}`);
|
|
284375
284696
|
}
|
|
284376
284697
|
const divergence = describeMismatches(target?.mismatches ?? []);
|
|
284377
|
-
if (divergence) console.log(` ${
|
|
284698
|
+
if (divergence) console.log(` ${import_picocolors19.default.yellow(`\u26A0 ${divergence}`)}`);
|
|
284378
284699
|
}
|
|
284379
284700
|
async function status(args = []) {
|
|
284380
284701
|
const apiUrl3 = apiBaseUrl();
|
|
@@ -284463,23 +284784,28 @@ async function status(args = []) {
|
|
|
284463
284784
|
return;
|
|
284464
284785
|
}
|
|
284465
284786
|
console.log(`
|
|
284466
|
-
${brand("ablo")} ${
|
|
284787
|
+
${brand("ablo")} ${import_picocolors19.default.dim("status")}
|
|
284467
284788
|
`);
|
|
284468
284789
|
if (effective.key && effective.source && effective.source !== "stored") {
|
|
284469
284790
|
const label = effective.source === "env" ? "ABLO_API_KEY env" : effective.source;
|
|
284470
284791
|
console.log(
|
|
284471
|
-
` ${
|
|
284792
|
+
` ${import_picocolors19.default.dim("key")} ${effective.key.slice(0, 12)}\u2026 ${import_picocolors19.default.dim(`(${label} \u2014 overrides stored)`)}`
|
|
284472
284793
|
);
|
|
284473
284794
|
} else if (!cfg) {
|
|
284474
|
-
console.log(` ${
|
|
284795
|
+
console.log(` ${import_picocolors19.default.yellow("!")} Not logged in \u2014 run ${import_picocolors19.default.bold("ablo login")}.`);
|
|
284475
284796
|
}
|
|
284476
284797
|
const activeEntry = getKeyEntry(mode);
|
|
284477
284798
|
const key = describeEffectiveKey(mode, process.env.ABLO_API_KEY, activeEntry);
|
|
284478
284799
|
if (key.keyMismatch) {
|
|
284479
|
-
console.log(` ${
|
|
284800
|
+
console.log(` ${import_picocolors19.default.yellow(`! ${key.keyMismatch.message}`)}`);
|
|
284480
284801
|
}
|
|
284481
284802
|
const activeProject = getActiveProject();
|
|
284482
|
-
printTargetLines(
|
|
284803
|
+
printTargetLines(
|
|
284804
|
+
target,
|
|
284805
|
+
activeProject,
|
|
284806
|
+
activeEntry?.organizationId,
|
|
284807
|
+
activeEntry?.organizationSlug
|
|
284808
|
+
);
|
|
284483
284809
|
for (const { key: m2, label } of [
|
|
284484
284810
|
{ key: "sandbox", label: "management" },
|
|
284485
284811
|
{ key: "production", label: "observer" }
|
|
@@ -284490,68 +284816,68 @@ async function status(args = []) {
|
|
|
284490
284816
|
credentialCapability(entry.apiKey).label,
|
|
284491
284817
|
entry.expiresAt ? expiryLabel(entry.expiresAt) : ""
|
|
284492
284818
|
].filter(Boolean);
|
|
284493
|
-
const trail = facts.length ? ` ${
|
|
284819
|
+
const trail = facts.length ? ` ${import_picocolors19.default.dim("\xB7")} ${facts.join(import_picocolors19.default.dim(" \xB7 "))}` : "";
|
|
284494
284820
|
console.log(
|
|
284495
|
-
` ${
|
|
284821
|
+
` ${import_picocolors19.default.dim("\u25CB")} ${label.padEnd(10)} ${import_picocolors19.default.dim(`${entry.apiKey.slice(0, 12)}\u2026`)}${trail}`
|
|
284496
284822
|
);
|
|
284497
284823
|
} else {
|
|
284498
|
-
console.log(` ${
|
|
284824
|
+
console.log(` ${import_picocolors19.default.dim("\u25CB")} ${label.padEnd(10)} ${import_picocolors19.default.dim("\u2014 no key")}`);
|
|
284499
284825
|
}
|
|
284500
284826
|
}
|
|
284501
284827
|
const plan = resolvePushPlan();
|
|
284502
284828
|
console.log(
|
|
284503
|
-
` ${
|
|
284829
|
+
` ${import_picocolors19.default.dim("push")} ${plan.apiKey ? `${import_picocolors19.default.bold(plan.flow)} ${import_picocolors19.default.dim(`with ${plan.apiKey.slice(0, 12)}\u2026 (${plan.source})`)}` : `${import_picocolors19.default.bold(plan.flow)} ${import_picocolors19.default.yellow("\u2014 no credential")} ${import_picocolors19.default.dim(`(run ${import_picocolors19.default.bold("ablo login")} or set ${import_picocolors19.default.bold("ABLO_API_KEY")})`)}`}`
|
|
284504
284830
|
);
|
|
284505
284831
|
const capability = credentialCapability(effective.key);
|
|
284506
|
-
if (capability.note) console.log(` ${
|
|
284507
|
-
process.stdout.write(` ${
|
|
284832
|
+
if (capability.note) console.log(` ${import_picocolors19.default.dim(capability.note)}`);
|
|
284833
|
+
process.stdout.write(` ${import_picocolors19.default.dim("api")} ${apiUrl3} `);
|
|
284508
284834
|
const reachable = await ping(apiUrl3);
|
|
284509
|
-
console.log(reachable ?
|
|
284835
|
+
console.log(reachable ? import_picocolors19.default.green("reachable") : import_picocolors19.default.red("unreachable"));
|
|
284510
284836
|
const introspectKey = effective.key;
|
|
284511
284837
|
const { source: dataSource, validation } = reachable ? await fetchRoutingState(apiUrl3, introspectKey) : { source: { kind: "unknown", detail: "unreachable" }, validation: null };
|
|
284512
284838
|
if (dataSource.kind === "connected") {
|
|
284513
284839
|
const how = [...new Set(dataSource.connections)].join(" + ");
|
|
284514
284840
|
const pooled = detectPoolerIn(dataSource.hosts);
|
|
284515
284841
|
const unreachable = validation && !validation.ok ? validation.message : void 0;
|
|
284516
|
-
console.log(` ${
|
|
284842
|
+
console.log(` ${import_picocolors19.default.dim("data")} ${import_picocolors19.default.green("\u2713")} ${import_picocolors19.default.dim(`database connected to this plane (${how})`)}`);
|
|
284517
284843
|
if (pooled) {
|
|
284518
284844
|
console.log(
|
|
284519
|
-
` ${
|
|
284845
|
+
` ${import_picocolors19.default.yellow("\u26A0")} ${import_picocolors19.default.dim(
|
|
284520
284846
|
`${pooled.host} is a connection pooler` + (pooled.direct ? `; register the direct host instead: ${pooled.direct}` : "; register the direct host instead")
|
|
284521
284847
|
)}`
|
|
284522
284848
|
);
|
|
284523
284849
|
}
|
|
284524
284850
|
if (unreachable) {
|
|
284525
|
-
console.log(` ${
|
|
284851
|
+
console.log(` ${import_picocolors19.default.red("\u2717")} ${import_picocolors19.default.dim(`Ablo could not reach it \u2014 ${unreachable}`)}`);
|
|
284526
284852
|
}
|
|
284527
284853
|
} else if (dataSource.kind === "none") {
|
|
284528
284854
|
console.log(
|
|
284529
|
-
` ${
|
|
284855
|
+
` ${import_picocolors19.default.dim("data")} ${import_picocolors19.default.red("\u2717 no database connected to this plane")} ${import_picocolors19.default.dim("\u2014 writes are held")}`
|
|
284530
284856
|
);
|
|
284531
284857
|
} else if (reachable) {
|
|
284532
|
-
console.log(` ${
|
|
284858
|
+
console.log(` ${import_picocolors19.default.dim("data")} ${import_picocolors19.default.yellow("?")} ${import_picocolors19.default.dim(`could not read the plane's databases (${dataSource.detail})`)}`);
|
|
284533
284859
|
}
|
|
284534
284860
|
const pushed = reachable ? await fetchPushedSchema(apiUrl3, introspectKey) : null;
|
|
284535
284861
|
if (reachable) {
|
|
284536
284862
|
if (pushed?.active) {
|
|
284537
|
-
const when = pushed.pushedAt ? ` ${
|
|
284538
|
-
const ver = pushed.version != null ? ` ${
|
|
284539
|
-
const hashLabel = pushed.hash ? ` ${
|
|
284540
|
-
console.log(` ${
|
|
284863
|
+
const when = pushed.pushedAt ? ` ${import_picocolors19.default.dim(`@ ${pushed.pushedAt.slice(0, 10)}`)}` : "";
|
|
284864
|
+
const ver = pushed.version != null ? ` ${import_picocolors19.default.dim(`(rev ${pushed.version})`)}` : "";
|
|
284865
|
+
const hashLabel = pushed.hash ? ` ${import_picocolors19.default.dim(`hash ${pushed.hash}`)}` : "";
|
|
284866
|
+
console.log(` ${import_picocolors19.default.dim("schema")} ${import_picocolors19.default.bold(`${pushed.models.length} models pushed`)}${ver}${hashLabel}${when}`);
|
|
284541
284867
|
for (const m2 of pushed.models) {
|
|
284542
|
-
const tn = m2.typename === m2.key ?
|
|
284868
|
+
const tn = m2.typename === m2.key ? import_picocolors19.default.dim(`typename=${m2.typename}`) : import_picocolors19.default.yellow(`typename=${m2.typename}`);
|
|
284543
284869
|
const conflict = formatConflict(m2.conflict);
|
|
284544
|
-
const conflictStr2 = conflict ? ` ${
|
|
284545
|
-
console.log(` ${
|
|
284870
|
+
const conflictStr2 = conflict ? ` ${import_picocolors19.default.dim(`conflict=${conflict}`)}` : "";
|
|
284871
|
+
console.log(` ${import_picocolors19.default.dim("\u2022")} ${m2.key.padEnd(14)} ${tn}${conflictStr2}`);
|
|
284546
284872
|
}
|
|
284547
284873
|
} else if (pushed && !pushed.active) {
|
|
284548
|
-
console.log(` ${
|
|
284874
|
+
console.log(` ${import_picocolors19.default.dim("schema")} ${import_picocolors19.default.yellow("none pushed")} ${import_picocolors19.default.dim(`(run ${import_picocolors19.default.bold("ablo push")} or ${import_picocolors19.default.bold("ablo dev")})`)}`);
|
|
284549
284875
|
}
|
|
284550
284876
|
}
|
|
284551
284877
|
const drift = schemaDrift(await readLocalSchemaHash(), pushed?.hash);
|
|
284552
284878
|
if (drift) {
|
|
284553
284879
|
console.log(
|
|
284554
|
-
` ${
|
|
284880
|
+
` ${import_picocolors19.default.dim("drift")} ${import_picocolors19.default.red("\u2717 local schema differs from the server")} ` + import_picocolors19.default.dim(`(local ${drift.local}, server ${drift.server})`)
|
|
284555
284881
|
);
|
|
284556
284882
|
}
|
|
284557
284883
|
const found = blockers({
|
|
@@ -284563,33 +284889,33 @@ async function status(args = []) {
|
|
|
284563
284889
|
});
|
|
284564
284890
|
console.log();
|
|
284565
284891
|
if (found.length > 0) {
|
|
284566
|
-
console.log(` ${
|
|
284892
|
+
console.log(` ${import_picocolors19.default.red("\u2717")} ${import_picocolors19.default.bold("writes would fail right now")}`);
|
|
284567
284893
|
for (const b4 of found) {
|
|
284568
|
-
console.log(` ${
|
|
284569
|
-
console.log(` ${
|
|
284894
|
+
console.log(` ${import_picocolors19.default.dim("\xB7")} ${b4.problem}`);
|
|
284895
|
+
console.log(` ${import_picocolors19.default.dim(b4.fix)}`);
|
|
284570
284896
|
}
|
|
284571
284897
|
} else if (dataSource.kind === "unknown") {
|
|
284572
284898
|
console.log(
|
|
284573
|
-
` ${
|
|
284899
|
+
` ${import_picocolors19.default.yellow("?")} ${import_picocolors19.default.dim("nothing is blocking a write, but this key could not read the plane's databases \u2014 some checks were skipped")}`
|
|
284574
284900
|
);
|
|
284575
284901
|
} else {
|
|
284576
|
-
console.log(` ${
|
|
284902
|
+
console.log(` ${import_picocolors19.default.green("\u2713")} ${import_picocolors19.default.dim("ready \u2014 a write should succeed")}`);
|
|
284577
284903
|
}
|
|
284578
284904
|
console.log();
|
|
284579
284905
|
}
|
|
284580
284906
|
|
|
284581
284907
|
// src/doctor.ts
|
|
284582
284908
|
init_cjs_shims();
|
|
284583
|
-
var
|
|
284909
|
+
var import_picocolors20 = __toESM(require_picocolors(), 1);
|
|
284584
284910
|
init_theme();
|
|
284585
284911
|
init_controlPlane();
|
|
284586
284912
|
init_config();
|
|
284587
284913
|
init_target();
|
|
284588
284914
|
init_readiness();
|
|
284589
284915
|
function render(check2) {
|
|
284590
|
-
const mark = check2.state === "ok" ?
|
|
284591
|
-
console.log(` ${mark} ${check2.label.padEnd(10)} ${check2.state === "fail" ? check2.detail :
|
|
284592
|
-
if (check2.fix) console.log(` ${" ".repeat(11)}${
|
|
284916
|
+
const mark = check2.state === "ok" ? import_picocolors20.default.green("\u2713") : check2.state === "fail" ? import_picocolors20.default.red("\u2717") : import_picocolors20.default.dim("\u2013");
|
|
284917
|
+
console.log(` ${mark} ${check2.label.padEnd(10)} ${check2.state === "fail" ? check2.detail : import_picocolors20.default.dim(check2.detail)}`);
|
|
284918
|
+
if (check2.fix) console.log(` ${" ".repeat(11)}${import_picocolors20.default.dim(`\u2192 ${check2.fix}`)}`);
|
|
284593
284919
|
}
|
|
284594
284920
|
async function ping2(apiUrl3) {
|
|
284595
284921
|
const ctrl = new AbortController();
|
|
@@ -284607,7 +284933,7 @@ async function ping2(apiUrl3) {
|
|
|
284607
284933
|
}
|
|
284608
284934
|
async function doctor() {
|
|
284609
284935
|
console.log(`
|
|
284610
|
-
${brand("ablo")} ${
|
|
284936
|
+
${brand("ablo")} ${import_picocolors20.default.dim("doctor")}
|
|
284611
284937
|
`);
|
|
284612
284938
|
const apiUrl3 = apiBaseUrl();
|
|
284613
284939
|
const effective = resolveEffectiveApiKey();
|
|
@@ -284722,15 +285048,15 @@ async function doctor() {
|
|
|
284722
285048
|
console.log();
|
|
284723
285049
|
if (failed > 0) {
|
|
284724
285050
|
console.log(
|
|
284725
|
-
` ${
|
|
285051
|
+
` ${import_picocolors20.default.red("\u2717")} ${import_picocolors20.default.bold(`${failed} problem${failed === 1 ? "" : "s"}`)}` + import_picocolors20.default.dim(skipped > 0 ? `, ${skipped} check${skipped === 1 ? "" : "s"} skipped` : "")
|
|
284726
285052
|
);
|
|
284727
|
-
console.log(
|
|
285053
|
+
console.log(import_picocolors20.default.dim(" Fix them in the order above \u2014 an earlier one often explains a later one."));
|
|
284728
285054
|
} else if (skipped > 0) {
|
|
284729
285055
|
console.log(
|
|
284730
|
-
` ${
|
|
285056
|
+
` ${import_picocolors20.default.yellow("?")} ${import_picocolors20.default.dim(`nothing is blocking a write, but ${skipped} check${skipped === 1 ? "" : "s"} could not be run`)}`
|
|
284731
285057
|
);
|
|
284732
285058
|
} else {
|
|
284733
|
-
console.log(` ${
|
|
285059
|
+
console.log(` ${import_picocolors20.default.green("\u2713")} ${import_picocolors20.default.dim("everything checks out \u2014 a write should succeed")}`);
|
|
284734
285060
|
}
|
|
284735
285061
|
console.log();
|
|
284736
285062
|
if (blocking.length > 0 || failed > 0) process.exitCode = 1;
|
|
@@ -284738,9 +285064,9 @@ async function doctor() {
|
|
|
284738
285064
|
|
|
284739
285065
|
// src/logs.ts
|
|
284740
285066
|
init_cjs_shims();
|
|
284741
|
-
var
|
|
284742
|
-
var
|
|
284743
|
-
var
|
|
285067
|
+
var import_errors16 = require("@abloatai/transaction/errors");
|
|
285068
|
+
var import_wire9 = require("@abloatai/transaction/wire");
|
|
285069
|
+
var import_picocolors21 = __toESM(require_picocolors(), 1);
|
|
284744
285070
|
init_config();
|
|
284745
285071
|
init_theme();
|
|
284746
285072
|
init_controlPlane();
|
|
@@ -284783,12 +285109,12 @@ function parseLogsArgs(argv) {
|
|
|
284783
285109
|
case "--mode": {
|
|
284784
285110
|
const raw = argv[++i];
|
|
284785
285111
|
const m2 = normalizeMode(raw);
|
|
284786
|
-
if (!m2) throw new
|
|
285112
|
+
if (!m2) throw new import_errors16.AbloValidationError(`--mode expects "sandbox" or "production", got "${raw}"`, { code: "cli_invalid_arguments" });
|
|
284787
285113
|
args.mode = m2;
|
|
284788
285114
|
break;
|
|
284789
285115
|
}
|
|
284790
285116
|
default:
|
|
284791
|
-
throw new
|
|
285117
|
+
throw new import_errors16.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
|
|
284792
285118
|
}
|
|
284793
285119
|
}
|
|
284794
285120
|
return args;
|
|
@@ -284807,10 +285133,10 @@ function resolveSince(since) {
|
|
|
284807
285133
|
var sleep2 = (ms) => new Promise((r2) => setTimeout(r2, ms));
|
|
284808
285134
|
function colorOp(op) {
|
|
284809
285135
|
const label = op.padEnd(6);
|
|
284810
|
-
if (op === "create") return
|
|
284811
|
-
if (op === "update") return
|
|
284812
|
-
if (op === "delete") return
|
|
284813
|
-
return
|
|
285136
|
+
if (op === "create") return import_picocolors21.default.green(label);
|
|
285137
|
+
if (op === "update") return import_picocolors21.default.yellow(label);
|
|
285138
|
+
if (op === "delete") return import_picocolors21.default.red(label);
|
|
285139
|
+
return import_picocolors21.default.dim(label);
|
|
284814
285140
|
}
|
|
284815
285141
|
function render2(e2, json) {
|
|
284816
285142
|
if (json) {
|
|
@@ -284819,21 +285145,21 @@ function render2(e2, json) {
|
|
|
284819
285145
|
return;
|
|
284820
285146
|
}
|
|
284821
285147
|
const t = new Date(e2.at).toLocaleTimeString();
|
|
284822
|
-
const actor = e2.actor ?
|
|
284823
|
-
console.log(` ${
|
|
285148
|
+
const actor = e2.actor ? import_picocolors21.default.dim(` ${e2.actor}`) : "";
|
|
285149
|
+
console.log(` ${import_picocolors21.default.dim(t)} ${colorOp(e2.op)} ${import_picocolors21.default.bold(e2.model)} ${import_picocolors21.default.dim(e2.recordId)}${actor}`);
|
|
284824
285150
|
}
|
|
284825
285151
|
async function logs(argv) {
|
|
284826
285152
|
let args;
|
|
284827
285153
|
try {
|
|
284828
285154
|
args = parseLogsArgs(argv);
|
|
284829
285155
|
} catch (err) {
|
|
284830
|
-
console.error(
|
|
285156
|
+
console.error(import_picocolors21.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
284831
285157
|
process.exit(1);
|
|
284832
285158
|
}
|
|
284833
285159
|
const apiKey = resolveApiKey(args.mode);
|
|
284834
285160
|
if (!apiKey) {
|
|
284835
285161
|
console.error(
|
|
284836
|
-
|
|
285162
|
+
import_picocolors21.default.red(` No API key.`) + import_picocolors21.default.dim(` Run ${import_picocolors21.default.bold("ablo login")} or set ${import_picocolors21.default.bold("ABLO_API_KEY")}.`)
|
|
284837
285163
|
);
|
|
284838
285164
|
process.exit(1);
|
|
284839
285165
|
}
|
|
@@ -284847,18 +285173,18 @@ async function logs(argv) {
|
|
|
284847
285173
|
if (!res) return null;
|
|
284848
285174
|
if (!res.ok) {
|
|
284849
285175
|
const body = await res.json().catch(() => ({}));
|
|
284850
|
-
console.error(
|
|
285176
|
+
console.error(import_picocolors21.default.red(` logs failed (${res.status}): ${body.reason ?? body.message ?? ""}`));
|
|
284851
285177
|
process.exit(1);
|
|
284852
285178
|
}
|
|
284853
285179
|
const json = await res.json();
|
|
284854
285180
|
return {
|
|
284855
285181
|
events: json.data ?? json.events ?? [],
|
|
284856
|
-
cursor: json.next_cursor ?? (json.cursor != null ? (0,
|
|
285182
|
+
cursor: json.next_cursor ?? (json.cursor != null ? (0, import_wire9.formatFeedCursor)({ log: json.cursor, claims: 0 }) : (0, import_wire9.formatFeedCursor)(import_wire9.FEED_CURSOR_START))
|
|
284857
285183
|
};
|
|
284858
285184
|
}
|
|
284859
285185
|
if (!args.json) {
|
|
284860
285186
|
console.log(`
|
|
284861
|
-
${brand("ablo")} ${
|
|
285187
|
+
${brand("ablo")} ${import_picocolors21.default.dim("logs")} ${import_picocolors21.default.dim(`(${args.mode ?? "active"} mode)`)}
|
|
284862
285188
|
`);
|
|
284863
285189
|
}
|
|
284864
285190
|
const initial = await fetchPage({
|
|
@@ -284868,13 +285194,13 @@ async function logs(argv) {
|
|
|
284868
285194
|
...args.op ? { op: args.op } : {}
|
|
284869
285195
|
});
|
|
284870
285196
|
if (!initial) {
|
|
284871
|
-
console.error(
|
|
285197
|
+
console.error(import_picocolors21.default.red(` Couldn't reach ${baseUrl2}.`));
|
|
284872
285198
|
process.exit(1);
|
|
284873
285199
|
}
|
|
284874
285200
|
for (const e2 of initial.events) render2(e2, args.json);
|
|
284875
285201
|
let cursor = initial.cursor;
|
|
284876
285202
|
if (!args.follow) return;
|
|
284877
|
-
if (!args.json) console.log(` ${
|
|
285203
|
+
if (!args.json) console.log(` ${import_picocolors21.default.dim("watching for new activity \u2026 (Ctrl-C to stop)")}
|
|
284878
285204
|
`);
|
|
284879
285205
|
for (; ; ) {
|
|
284880
285206
|
await sleep2(1500);
|
|
@@ -284885,16 +285211,16 @@ async function logs(argv) {
|
|
|
284885
285211
|
});
|
|
284886
285212
|
if (!page) continue;
|
|
284887
285213
|
for (const e2 of page.events) render2(e2, args.json);
|
|
284888
|
-
const prev = (0,
|
|
284889
|
-
const next = (0,
|
|
284890
|
-
if (prev && next && (0,
|
|
285214
|
+
const prev = (0, import_wire9.parseFeedCursor)(cursor);
|
|
285215
|
+
const next = (0, import_wire9.parseFeedCursor)(page.cursor);
|
|
285216
|
+
if (prev && next && (0, import_wire9.feedCursorAdvanced)(prev, next)) cursor = page.cursor;
|
|
284891
285217
|
}
|
|
284892
285218
|
}
|
|
284893
285219
|
|
|
284894
285220
|
// src/webhooks.ts
|
|
284895
285221
|
init_cjs_shims();
|
|
284896
285222
|
var import_fs9 = require("fs");
|
|
284897
|
-
var
|
|
285223
|
+
var import_picocolors22 = __toESM(require_picocolors(), 1);
|
|
284898
285224
|
var import_credentialPolicy4 = require("@abloatai/transaction/auth/credentialPolicy");
|
|
284899
285225
|
init_config();
|
|
284900
285226
|
init_theme();
|
|
@@ -284927,12 +285253,12 @@ function requireKey3(mode) {
|
|
|
284927
285253
|
const apiKey = resolveApiKey(mode);
|
|
284928
285254
|
if (!apiKey) {
|
|
284929
285255
|
console.error(
|
|
284930
|
-
|
|
285256
|
+
import_picocolors22.default.red(" No API key.") + import_picocolors22.default.dim(` Run ${import_picocolors22.default.bold("ablo login")} or set ${import_picocolors22.default.bold("ABLO_API_KEY")}.`)
|
|
284931
285257
|
);
|
|
284932
285258
|
process.exit(1);
|
|
284933
285259
|
}
|
|
284934
285260
|
if ((0, import_credentialPolicy4.classifyCredentialKind)(apiKey) !== "secret") {
|
|
284935
|
-
console.error(
|
|
285261
|
+
console.error(import_picocolors22.default.red(" Managing webhooks requires a secret key ") + import_picocolors22.default.dim("(sk_test_ / sk_live_)."));
|
|
284936
285262
|
process.exit(1);
|
|
284937
285263
|
}
|
|
284938
285264
|
return apiKey;
|
|
@@ -284948,12 +285274,12 @@ async function api(apiKey, method, path, body) {
|
|
|
284948
285274
|
...body ? { body: JSON.stringify(body) } : {}
|
|
284949
285275
|
}).catch(() => null);
|
|
284950
285276
|
if (!res) {
|
|
284951
|
-
console.error(
|
|
285277
|
+
console.error(import_picocolors22.default.red(` Couldn't reach ${baseUrl()}.`));
|
|
284952
285278
|
process.exit(1);
|
|
284953
285279
|
}
|
|
284954
285280
|
if (!res.ok) {
|
|
284955
285281
|
const err = await res.json().catch(() => ({}));
|
|
284956
|
-
console.error(
|
|
285282
|
+
console.error(import_picocolors22.default.red(` Request failed (${res.status}): ${err.message ?? err.reason ?? ""}`));
|
|
284957
285283
|
process.exit(1);
|
|
284958
285284
|
}
|
|
284959
285285
|
return await res.json();
|
|
@@ -284975,11 +285301,11 @@ ${line}
|
|
|
284975
285301
|
return file;
|
|
284976
285302
|
}
|
|
284977
285303
|
function printEndpoint(e2) {
|
|
284978
|
-
const dot = e2.status === "enabled" ?
|
|
284979
|
-
const health = e2.last_error ?
|
|
284980
|
-
console.log(` ${dot} ${
|
|
285304
|
+
const dot = e2.status === "enabled" ? import_picocolors22.default.green("\u25CF") : import_picocolors22.default.red("\u25CF");
|
|
285305
|
+
const health = e2.last_error ? import_picocolors22.default.red(` last error: ${e2.last_error}`) : "";
|
|
285306
|
+
console.log(` ${dot} ${import_picocolors22.default.bold(e2.id)} ${e2.url}`);
|
|
284981
285307
|
console.log(
|
|
284982
|
-
|
|
285308
|
+
import_picocolors22.default.dim(
|
|
284983
285309
|
` ${e2.status} \xB7 ${e2.environment} \xB7 events ${e2.enabled_events.join(",")} \xB7 cursor ${e2.cursor ?? "\u2014"}${health}`
|
|
284984
285310
|
)
|
|
284985
285311
|
);
|
|
@@ -284991,7 +285317,7 @@ async function webhooks(argv) {
|
|
|
284991
285317
|
if (sub === "create") {
|
|
284992
285318
|
const url = positional(rest);
|
|
284993
285319
|
if (!url) {
|
|
284994
|
-
console.error(
|
|
285320
|
+
console.error(import_picocolors22.default.red(" Usage: ") + brand("ablo webhooks create <url>"));
|
|
284995
285321
|
process.exit(1);
|
|
284996
285322
|
}
|
|
284997
285323
|
const apiKey = requireKey3(mode);
|
|
@@ -285003,8 +285329,8 @@ async function webhooks(argv) {
|
|
|
285003
285329
|
});
|
|
285004
285330
|
const file = writeSecretToEnv(created.secret);
|
|
285005
285331
|
console.log(`
|
|
285006
|
-
${
|
|
285007
|
-
console.log(` ${
|
|
285332
|
+
${import_picocolors22.default.green("\u2713")} Registered ${import_picocolors22.default.bold(created.id)} \u2192 ${created.url}`);
|
|
285333
|
+
console.log(` ${import_picocolors22.default.green("\u2713")} Wrote ${import_picocolors22.default.bold(ENV_KEY)} to ${import_picocolors22.default.bold(file)} ${import_picocolors22.default.dim("(shown once)")}
|
|
285008
285334
|
`);
|
|
285009
285335
|
return;
|
|
285010
285336
|
}
|
|
@@ -285012,7 +285338,7 @@ async function webhooks(argv) {
|
|
|
285012
285338
|
const apiKey = requireKey3(mode);
|
|
285013
285339
|
const { data } = await api(apiKey, "GET", "");
|
|
285014
285340
|
if (data.length === 0) {
|
|
285015
|
-
console.log(
|
|
285341
|
+
console.log(import_picocolors22.default.dim(" No webhook endpoints. ") + brand("ablo webhooks create <url>"));
|
|
285016
285342
|
return;
|
|
285017
285343
|
}
|
|
285018
285344
|
console.log();
|
|
@@ -285023,40 +285349,40 @@ async function webhooks(argv) {
|
|
|
285023
285349
|
if (sub === "roll") {
|
|
285024
285350
|
const id = positional(rest);
|
|
285025
285351
|
if (!id) {
|
|
285026
|
-
console.error(
|
|
285352
|
+
console.error(import_picocolors22.default.red(" Usage: ") + brand("ablo webhooks roll <id>"));
|
|
285027
285353
|
process.exit(1);
|
|
285028
285354
|
}
|
|
285029
285355
|
const apiKey = requireKey3(mode);
|
|
285030
285356
|
const rolled = await api(apiKey, "POST", `/${id}/roll_secret`);
|
|
285031
285357
|
const file = writeSecretToEnv(rolled.secret);
|
|
285032
285358
|
console.log(`
|
|
285033
|
-
${
|
|
285359
|
+
${import_picocolors22.default.green("\u2713")} Rolled secret for ${import_picocolors22.default.bold(id)} \u2192 ${import_picocolors22.default.bold(file)} ${import_picocolors22.default.dim("(old secret now invalid)")}
|
|
285034
285360
|
`);
|
|
285035
285361
|
return;
|
|
285036
285362
|
}
|
|
285037
285363
|
if (sub === "enable") {
|
|
285038
285364
|
const id = positional(rest);
|
|
285039
285365
|
if (!id) {
|
|
285040
|
-
console.error(
|
|
285366
|
+
console.error(import_picocolors22.default.red(" Usage: ") + brand("ablo webhooks enable <id>"));
|
|
285041
285367
|
process.exit(1);
|
|
285042
285368
|
}
|
|
285043
285369
|
const apiKey = requireKey3(mode);
|
|
285044
285370
|
const e2 = await api(apiKey, "POST", `/${id}/enable`);
|
|
285045
|
-
console.log(` ${
|
|
285371
|
+
console.log(` ${import_picocolors22.default.green("\u2713")} Re-enabled ${import_picocolors22.default.bold(e2.id)}`);
|
|
285046
285372
|
return;
|
|
285047
285373
|
}
|
|
285048
285374
|
if (sub === "rm" || sub === "delete") {
|
|
285049
285375
|
const id = positional(rest);
|
|
285050
285376
|
if (!id) {
|
|
285051
|
-
console.error(
|
|
285377
|
+
console.error(import_picocolors22.default.red(" Usage: ") + brand("ablo webhooks rm <id>"));
|
|
285052
285378
|
process.exit(1);
|
|
285053
285379
|
}
|
|
285054
285380
|
const apiKey = requireKey3(mode);
|
|
285055
285381
|
await api(apiKey, "DELETE", `/${id}`);
|
|
285056
|
-
console.log(` ${
|
|
285382
|
+
console.log(` ${import_picocolors22.default.green("\u2713")} Removed ${import_picocolors22.default.bold(id)}`);
|
|
285057
285383
|
return;
|
|
285058
285384
|
}
|
|
285059
|
-
console.log(` ${
|
|
285385
|
+
console.log(` ${import_picocolors22.default.bold("Usage:")}`);
|
|
285060
285386
|
console.log(` ${brand("ablo webhooks create <url>")} Register an endpoint; writes ${ENV_KEY}`);
|
|
285061
285387
|
console.log(` ${brand("ablo webhooks list")} List endpoints + delivery health`);
|
|
285062
285388
|
console.log(` ${brand("ablo webhooks roll <id>")} Mint a fresh signing secret`);
|
|
@@ -285067,8 +285393,8 @@ async function webhooks(argv) {
|
|
|
285067
285393
|
|
|
285068
285394
|
// src/check.ts
|
|
285069
285395
|
init_cjs_shims();
|
|
285070
|
-
var
|
|
285071
|
-
var
|
|
285396
|
+
var import_errors17 = require("@abloatai/transaction/errors");
|
|
285397
|
+
var import_picocolors23 = __toESM(require_picocolors(), 1);
|
|
285072
285398
|
init_src();
|
|
285073
285399
|
var import_schema9 = require("@abloatai/transaction/schema");
|
|
285074
285400
|
init_push();
|
|
@@ -285215,7 +285541,7 @@ function parseCheckArgs(argv) {
|
|
|
285215
285541
|
appSchema = argv[++i] ?? appSchema;
|
|
285216
285542
|
break;
|
|
285217
285543
|
default:
|
|
285218
|
-
throw new
|
|
285544
|
+
throw new import_errors17.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
|
|
285219
285545
|
}
|
|
285220
285546
|
}
|
|
285221
285547
|
return { schemaPath, exportName, appSchema };
|
|
@@ -285229,22 +285555,22 @@ function hostOf(connectionString) {
|
|
|
285229
285555
|
}
|
|
285230
285556
|
async function reportReadSubject(dbUrl) {
|
|
285231
285557
|
const host = hostOf(dbUrl);
|
|
285232
|
-
console.log(` ${
|
|
285558
|
+
console.log(` ${import_picocolors23.default.dim("reading")} ${import_picocolors23.default.bold(host ?? "your database")}`);
|
|
285233
285559
|
const effective = resolveEffectiveApiKey();
|
|
285234
285560
|
const state = await fetchDataSourceState(apiBaseUrl(), effective.key);
|
|
285235
285561
|
if (state.kind === "unknown") {
|
|
285236
285562
|
console.log(
|
|
285237
|
-
` ${
|
|
285563
|
+
` ${import_picocolors23.default.dim("ablo")} ${import_picocolors23.default.yellow("?")} ${import_picocolors23.default.dim(`couldn't ask which database Ablo reads (${state.detail})`)}
|
|
285238
285564
|
`
|
|
285239
285565
|
);
|
|
285240
285566
|
return;
|
|
285241
285567
|
}
|
|
285242
285568
|
if (state.kind === "none") {
|
|
285243
285569
|
console.log(
|
|
285244
|
-
` ${
|
|
285570
|
+
` ${import_picocolors23.default.dim("ablo")} ${import_picocolors23.default.yellow("!")} no database is registered for this plane, so Ablo does not read this one`
|
|
285245
285571
|
);
|
|
285246
285572
|
console.log(
|
|
285247
|
-
` ${
|
|
285573
|
+
` ${import_picocolors23.default.dim(`Connect it with ${import_picocolors23.default.bold("ablo connect apply")}. Until then a table here is invisible to the engine.`)}
|
|
285248
285574
|
`
|
|
285249
285575
|
);
|
|
285250
285576
|
return;
|
|
@@ -285252,15 +285578,15 @@ async function reportReadSubject(dbUrl) {
|
|
|
285252
285578
|
const registered = [...new Set(state.hosts)];
|
|
285253
285579
|
if (host && registered.length > 0 && !registered.includes(host)) {
|
|
285254
285580
|
console.log(
|
|
285255
|
-
` ${
|
|
285581
|
+
` ${import_picocolors23.default.dim("ablo")} ${import_picocolors23.default.yellow("!")} Ablo reads ${import_picocolors23.default.bold(registered.join(", "))}`
|
|
285256
285582
|
);
|
|
285257
285583
|
console.log(
|
|
285258
|
-
` ${
|
|
285584
|
+
` ${import_picocolors23.default.dim("If that is this database under a pooled hostname, this is fine \u2014 otherwise the report below describes a database Ablo never reads.")}
|
|
285259
285585
|
`
|
|
285260
285586
|
);
|
|
285261
285587
|
return;
|
|
285262
285588
|
}
|
|
285263
|
-
console.log(` ${
|
|
285589
|
+
console.log(` ${import_picocolors23.default.dim("ablo")} ${import_picocolors23.default.green("\u2713")} ${import_picocolors23.default.dim("reads this database")}
|
|
285264
285590
|
`);
|
|
285265
285591
|
}
|
|
285266
285592
|
async function check(argv) {
|
|
@@ -285268,20 +285594,20 @@ async function check(argv) {
|
|
|
285268
285594
|
try {
|
|
285269
285595
|
args = parseCheckArgs(argv);
|
|
285270
285596
|
} catch (err) {
|
|
285271
|
-
console.error(
|
|
285597
|
+
console.error(import_picocolors23.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
285272
285598
|
process.exit(1);
|
|
285273
285599
|
}
|
|
285274
285600
|
const dbUrl = readProjectAdminDatabaseUrl();
|
|
285275
285601
|
if (!dbUrl) {
|
|
285276
285602
|
console.error(
|
|
285277
|
-
|
|
285603
|
+
import_picocolors23.default.red(` No database.`) + import_picocolors23.default.dim(` Set ${import_picocolors23.default.bold(ADMIN_URL_VAR)} to the Postgres you want Ablo to adopt.`)
|
|
285278
285604
|
);
|
|
285279
285605
|
process.exit(1);
|
|
285280
285606
|
}
|
|
285281
285607
|
const schema = await loadSchema(args.schemaPath, args.exportName);
|
|
285282
285608
|
const schemaJson = JSON.parse((0, import_schema9.serializeSchema)(schema));
|
|
285283
285609
|
console.log(`
|
|
285284
|
-
${brand("ablo")} ${
|
|
285610
|
+
${brand("ablo")} ${import_picocolors23.default.dim("check")} ${import_picocolors23.default.dim(`schema "${args.appSchema}"`)}
|
|
285285
285611
|
`);
|
|
285286
285612
|
await reportReadSubject(dbUrl);
|
|
285287
285613
|
const sql = src_default(dbUrl, { max: 1, prepare: false, onnotice: () => {
|
|
@@ -285293,7 +285619,7 @@ async function check(argv) {
|
|
|
285293
285619
|
[args.appSchema]
|
|
285294
285620
|
);
|
|
285295
285621
|
} catch (err) {
|
|
285296
|
-
console.error(
|
|
285622
|
+
console.error(import_picocolors23.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
|
|
285297
285623
|
await sql.end({ timeout: 2 });
|
|
285298
285624
|
process.exit(1);
|
|
285299
285625
|
}
|
|
@@ -285315,7 +285641,7 @@ async function check(argv) {
|
|
|
285315
285641
|
declaredTables.add(table);
|
|
285316
285642
|
const present = colsByTable.get(table);
|
|
285317
285643
|
if (!present) {
|
|
285318
|
-
console.log(` ${
|
|
285644
|
+
console.log(` ${import_picocolors23.default.red("\u2717")} ${import_picocolors23.default.bold(key)} ${import_picocolors23.default.dim("\u2192")} table ${import_picocolors23.default.bold(table)} ${import_picocolors23.default.red("not found")}`);
|
|
285319
285645
|
errors++;
|
|
285320
285646
|
continue;
|
|
285321
285647
|
}
|
|
@@ -285337,26 +285663,26 @@ async function check(argv) {
|
|
|
285337
285663
|
if (!present.has(col)) problems.push(`missing column "${col}" (field ${fieldName})`);
|
|
285338
285664
|
}
|
|
285339
285665
|
if (problems.length > 0) {
|
|
285340
|
-
console.log(` ${
|
|
285341
|
-
for (const p2 of problems) console.log(` ${
|
|
285342
|
-
for (const w2 of warns) console.log(` ${
|
|
285666
|
+
console.log(` ${import_picocolors23.default.red("\u2717")} ${import_picocolors23.default.bold(key)} ${import_picocolors23.default.dim("\u2192")} ${table}`);
|
|
285667
|
+
for (const p2 of problems) console.log(` ${import_picocolors23.default.red("\u2022")} ${p2}`);
|
|
285668
|
+
for (const w2 of warns) console.log(` ${import_picocolors23.default.yellow("\u2022")} ${w2}`);
|
|
285343
285669
|
errors++;
|
|
285344
285670
|
} else if (warns.length > 0) {
|
|
285345
|
-
console.log(` ${
|
|
285346
|
-
for (const w2 of warns) console.log(` ${
|
|
285671
|
+
console.log(` ${import_picocolors23.default.yellow("!")} ${import_picocolors23.default.bold(key)} ${import_picocolors23.default.dim("\u2192")} ${table}`);
|
|
285672
|
+
for (const w2 of warns) console.log(` ${import_picocolors23.default.yellow("\u2022")} ${w2}`);
|
|
285347
285673
|
warnings++;
|
|
285348
285674
|
} else {
|
|
285349
|
-
console.log(` ${
|
|
285675
|
+
console.log(` ${import_picocolors23.default.green("\u2713")} ${import_picocolors23.default.bold(key)} ${import_picocolors23.default.dim(`\u2192 ${table} (id, ${orgCol ?? "no org"} ok)`)}`);
|
|
285350
285676
|
}
|
|
285351
285677
|
}
|
|
285352
285678
|
const modelCount = Object.keys(schemaJson.models).length;
|
|
285353
285679
|
const ignored = [...colsByTable.keys()].filter((t) => !declaredTables.has(t)).length;
|
|
285354
285680
|
console.log(
|
|
285355
285681
|
`
|
|
285356
|
-
${modelCount} model${modelCount === 1 ? "" : "s"} \xB7 ${
|
|
285682
|
+
${modelCount} model${modelCount === 1 ? "" : "s"} \xB7 ${import_picocolors23.default.green(`${modelCount - errors - warnings} ok`)}` + (warnings ? ` \xB7 ${import_picocolors23.default.yellow(`${warnings} warning${warnings === 1 ? "" : "s"}`)}` : "") + (errors ? ` \xB7 ${import_picocolors23.default.red(`${errors} error${errors === 1 ? "" : "s"}`)}` : "")
|
|
285357
285683
|
);
|
|
285358
285684
|
if (ignored > 0) {
|
|
285359
|
-
console.log(` ${
|
|
285685
|
+
console.log(` ${import_picocolors23.default.dim(`${ignored} other table${ignored === 1 ? "" : "s"} in your database \u2014 ignored by Ablo`)}`);
|
|
285360
285686
|
}
|
|
285361
285687
|
console.log();
|
|
285362
285688
|
process.exit(errors > 0 ? 1 : 0);
|
|
@@ -285367,7 +285693,7 @@ init_dbRole();
|
|
|
285367
285693
|
|
|
285368
285694
|
// src/upgrade.ts
|
|
285369
285695
|
init_cjs_shims();
|
|
285370
|
-
var
|
|
285696
|
+
var import_picocolors24 = __toESM(require_picocolors(), 1);
|
|
285371
285697
|
var import_ts_morph = __toESM(require_ts_morph(), 1);
|
|
285372
285698
|
var DEFAULT_GLOBS = ["app/**/*.{ts,tsx}", "src/**/*.{ts,tsx}", "ablo/**/*.{ts,tsx}", "lib/**/*.{ts,tsx}"];
|
|
285373
285699
|
var VERB_ARGS = {
|
|
@@ -285445,7 +285771,7 @@ async function upgrade(argv) {
|
|
|
285445
285771
|
project.addSourceFilesAtPaths(globs.length > 0 ? globs : DEFAULT_GLOBS);
|
|
285446
285772
|
const files = project.getSourceFiles();
|
|
285447
285773
|
if (files.length === 0) {
|
|
285448
|
-
console.log(
|
|
285774
|
+
console.log(import_picocolors24.default.yellow(' No .ts/.tsx files found. Pass a glob, e.g. `ablo upgrade "src/**/*.tsx"`.'));
|
|
285449
285775
|
return;
|
|
285450
285776
|
}
|
|
285451
285777
|
const edits = [];
|
|
@@ -285519,39 +285845,39 @@ async function upgrade(argv) {
|
|
|
285519
285845
|
const rel = (f) => f.replace(cwd + "/", "");
|
|
285520
285846
|
console.log();
|
|
285521
285847
|
if (edits.length === 0 && manual.length === 0) {
|
|
285522
|
-
console.log(
|
|
285848
|
+
console.log(import_picocolors24.default.green(" \u2713 Nothing to migrate \u2014 your code is already on the current API."));
|
|
285523
285849
|
return;
|
|
285524
285850
|
}
|
|
285525
285851
|
if (edits.length > 0) {
|
|
285526
|
-
console.log(
|
|
285852
|
+
console.log(import_picocolors24.default.bold(` ${write ? "Applied" : "Would apply"} ${edits.length} change${edits.length === 1 ? "" : "s"}:`));
|
|
285527
285853
|
for (const e2 of edits) {
|
|
285528
|
-
console.log(` ${
|
|
285529
|
-
console.log(` ${
|
|
285530
|
-
console.log(` ${
|
|
285854
|
+
console.log(` ${import_picocolors24.default.dim(`${rel(e2.file)}:${e2.line}`)} ${import_picocolors24.default.cyan(e2.rule)}`);
|
|
285855
|
+
console.log(` ${import_picocolors24.default.red("-")} ${e2.before}`);
|
|
285856
|
+
console.log(` ${import_picocolors24.default.green("+")} ${e2.after}`);
|
|
285531
285857
|
}
|
|
285532
285858
|
}
|
|
285533
285859
|
if (manual.length > 0) {
|
|
285534
285860
|
console.log();
|
|
285535
|
-
console.log(
|
|
285861
|
+
console.log(import_picocolors24.default.bold(import_picocolors24.default.yellow(` ${manual.length} spot${manual.length === 1 ? "" : "s"} need manual review (structural):`)));
|
|
285536
285862
|
for (const m2 of manual) {
|
|
285537
|
-
console.log(` ${
|
|
285538
|
-
console.log(` ${
|
|
285863
|
+
console.log(` ${import_picocolors24.default.dim(`${rel(m2.file)}:${m2.line}`)} ${import_picocolors24.default.yellow(m2.rule)}`);
|
|
285864
|
+
console.log(` ${import_picocolors24.default.dim(m2.snippet)}`);
|
|
285539
285865
|
console.log(` \u2192 ${m2.hint}`);
|
|
285540
285866
|
}
|
|
285541
285867
|
}
|
|
285542
285868
|
console.log();
|
|
285543
285869
|
if (write) {
|
|
285544
285870
|
await project.save();
|
|
285545
|
-
console.log(
|
|
285871
|
+
console.log(import_picocolors24.default.green(` \u2713 Wrote ${edits.length} change${edits.length === 1 ? "" : "s"}. Review the diff, run your typecheck.`));
|
|
285546
285872
|
} else {
|
|
285547
|
-
console.log(
|
|
285873
|
+
console.log(import_picocolors24.default.dim(" Dry run. Re-run with `--write` to apply the auto-fixes above (manual items are never auto-written)."));
|
|
285548
285874
|
}
|
|
285549
285875
|
}
|
|
285550
285876
|
|
|
285551
285877
|
// src/pull.ts
|
|
285552
285878
|
init_cjs_shims();
|
|
285553
|
-
var
|
|
285554
|
-
var
|
|
285879
|
+
var import_errors18 = require("@abloatai/transaction/errors");
|
|
285880
|
+
var import_picocolors25 = __toESM(require_picocolors(), 1);
|
|
285555
285881
|
init_src();
|
|
285556
285882
|
var import_fs10 = require("fs");
|
|
285557
285883
|
init_theme();
|
|
@@ -285579,7 +285905,7 @@ function parsePullArgs(argv) {
|
|
|
285579
285905
|
force = true;
|
|
285580
285906
|
break;
|
|
285581
285907
|
default:
|
|
285582
|
-
throw new
|
|
285908
|
+
throw new import_errors18.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
|
|
285583
285909
|
}
|
|
285584
285910
|
}
|
|
285585
285911
|
return { out, appSchema, importPath, force };
|
|
@@ -285649,56 +285975,56 @@ async function pull(argv) {
|
|
|
285649
285975
|
try {
|
|
285650
285976
|
args = parsePullArgs(argv);
|
|
285651
285977
|
} catch (err) {
|
|
285652
|
-
console.error(
|
|
285978
|
+
console.error(import_picocolors25.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
285653
285979
|
process.exit(1);
|
|
285654
285980
|
}
|
|
285655
285981
|
const dbUrl = readProjectAdminDatabaseUrl();
|
|
285656
285982
|
if (!dbUrl) {
|
|
285657
285983
|
console.error(
|
|
285658
|
-
|
|
285984
|
+
import_picocolors25.default.red(` No database.`) + import_picocolors25.default.dim(` Set ${import_picocolors25.default.bold(ADMIN_URL_VAR)} to the Postgres to pull from.`)
|
|
285659
285985
|
);
|
|
285660
285986
|
process.exit(1);
|
|
285661
285987
|
}
|
|
285662
285988
|
if ((0, import_fs10.existsSync)(args.out) && !args.force) {
|
|
285663
285989
|
console.error(
|
|
285664
|
-
|
|
285990
|
+
import_picocolors25.default.red(` ${args.out} already exists.`) + import_picocolors25.default.dim(` Re-run with ${import_picocolors25.default.bold("--force")} to overwrite.`)
|
|
285665
285991
|
);
|
|
285666
285992
|
process.exit(1);
|
|
285667
285993
|
}
|
|
285668
285994
|
console.log(`
|
|
285669
|
-
${brand("ablo")} ${
|
|
285995
|
+
${brand("ablo")} ${import_picocolors25.default.dim("pull")} ${import_picocolors25.default.dim(`schema "${args.appSchema}"`)}
|
|
285670
285996
|
`);
|
|
285671
285997
|
let result;
|
|
285672
285998
|
try {
|
|
285673
285999
|
result = await buildSchemaSourceFromDb({ dbUrl, appSchema: args.appSchema, importPath: args.importPath });
|
|
285674
286000
|
} catch (err) {
|
|
285675
|
-
console.error(
|
|
286001
|
+
console.error(import_picocolors25.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
|
|
285676
286002
|
process.exit(1);
|
|
285677
286003
|
}
|
|
285678
286004
|
if (result.models.length === 0) {
|
|
285679
286005
|
console.error(
|
|
285680
|
-
|
|
286006
|
+
import_picocolors25.default.yellow(` No adoptable tables found`) + import_picocolors25.default.dim(` (a model needs an ${import_picocolors25.default.bold("id")} + ${import_picocolors25.default.bold("organization_id")} column).`)
|
|
285681
286007
|
);
|
|
285682
286008
|
process.exit(1);
|
|
285683
286009
|
}
|
|
285684
286010
|
(0, import_fs10.writeFileSync)(args.out, result.source);
|
|
285685
|
-
console.log(` ${
|
|
285686
|
-
console.log(` ${
|
|
286011
|
+
console.log(` ${import_picocolors25.default.green("\u2713")} wrote ${import_picocolors25.default.bold(args.out)} ${import_picocolors25.default.dim(`(${result.models.length} models)`)}`);
|
|
286012
|
+
console.log(` ${import_picocolors25.default.dim(`models: ${result.models.join(", ")}`)}`);
|
|
285687
286013
|
if (result.skipped.length > 0) {
|
|
285688
|
-
console.log(` ${
|
|
285689
|
-
for (const s of result.skipped) console.log(` ${
|
|
286014
|
+
console.log(` ${import_picocolors25.default.dim(`${result.skipped.length} table(s) skipped:`)}`);
|
|
286015
|
+
for (const s of result.skipped) console.log(` ${import_picocolors25.default.dim(`- ${s.name}: ${s.reason}`)}`);
|
|
285690
286016
|
}
|
|
285691
286017
|
console.log(
|
|
285692
286018
|
`
|
|
285693
|
-
${
|
|
286019
|
+
${import_picocolors25.default.dim("Introspection is lossy (enums, JSON shape, relations). Review the file, then")} ${import_picocolors25.default.bold("ablo check")}.
|
|
285694
286020
|
`
|
|
285695
286021
|
);
|
|
285696
286022
|
}
|
|
285697
286023
|
|
|
285698
286024
|
// src/prismaPull.ts
|
|
285699
286025
|
init_cjs_shims();
|
|
285700
|
-
var
|
|
285701
|
-
var
|
|
286026
|
+
var import_errors19 = require("@abloatai/transaction/errors");
|
|
286027
|
+
var import_picocolors26 = __toESM(require_picocolors(), 1);
|
|
285702
286028
|
var import_fs11 = require("fs");
|
|
285703
286029
|
init_theme();
|
|
285704
286030
|
var DEFAULT_SCHEMA = "prisma/schema.prisma";
|
|
@@ -285895,7 +286221,7 @@ function parsePrismaPullArgs(argv) {
|
|
|
285895
286221
|
force = true;
|
|
285896
286222
|
break;
|
|
285897
286223
|
default:
|
|
285898
|
-
if (arg.startsWith("--")) throw new
|
|
286224
|
+
if (arg.startsWith("--")) throw new import_errors19.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
|
|
285899
286225
|
schema = arg;
|
|
285900
286226
|
}
|
|
285901
286227
|
}
|
|
@@ -285906,56 +286232,56 @@ async function prismaPull(argv) {
|
|
|
285906
286232
|
try {
|
|
285907
286233
|
args = parsePrismaPullArgs(argv);
|
|
285908
286234
|
} catch (err) {
|
|
285909
|
-
console.error(
|
|
286235
|
+
console.error(import_picocolors26.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
285910
286236
|
process.exit(1);
|
|
285911
286237
|
}
|
|
285912
286238
|
if (!(0, import_fs11.existsSync)(args.schema)) {
|
|
285913
286239
|
console.error(
|
|
285914
|
-
|
|
286240
|
+
import_picocolors26.default.red(` No Prisma schema at ${import_picocolors26.default.bold(args.schema)}.`) + import_picocolors26.default.dim(` Pass a path: ${import_picocolors26.default.bold("ablo pull prisma <path>")}.`)
|
|
285915
286241
|
);
|
|
285916
286242
|
process.exit(1);
|
|
285917
286243
|
}
|
|
285918
286244
|
if ((0, import_fs11.existsSync)(args.out) && !args.force) {
|
|
285919
286245
|
console.error(
|
|
285920
|
-
|
|
286246
|
+
import_picocolors26.default.red(` ${args.out} already exists.`) + import_picocolors26.default.dim(` Re-run with ${import_picocolors26.default.bold("--force")} to overwrite.`)
|
|
285921
286247
|
);
|
|
285922
286248
|
process.exit(1);
|
|
285923
286249
|
}
|
|
285924
286250
|
console.log(`
|
|
285925
|
-
${brand("ablo")} ${
|
|
286251
|
+
${brand("ablo")} ${import_picocolors26.default.dim("pull prisma")} ${import_picocolors26.default.dim(args.schema)}
|
|
285926
286252
|
`);
|
|
285927
286253
|
let result;
|
|
285928
286254
|
try {
|
|
285929
286255
|
const src = (0, import_fs11.readFileSync)(args.schema, "utf8");
|
|
285930
286256
|
result = buildSchemaSourceFromPrisma({ src, importPath: args.importPath });
|
|
285931
286257
|
} catch (err) {
|
|
285932
|
-
console.error(
|
|
286258
|
+
console.error(import_picocolors26.default.red(` Couldn't parse the schema: ${err instanceof Error ? err.message : String(err)}`));
|
|
285933
286259
|
process.exit(1);
|
|
285934
286260
|
}
|
|
285935
286261
|
if (result.models.length === 0) {
|
|
285936
286262
|
console.error(
|
|
285937
|
-
|
|
286263
|
+
import_picocolors26.default.yellow(` No adoptable models found`) + import_picocolors26.default.dim(` (a model needs an ${import_picocolors26.default.bold("id")} + ${import_picocolors26.default.bold("organizationId")} / ${import_picocolors26.default.bold("organization_id")}).`)
|
|
285938
286264
|
);
|
|
285939
286265
|
process.exit(1);
|
|
285940
286266
|
}
|
|
285941
286267
|
(0, import_fs11.writeFileSync)(args.out, result.source);
|
|
285942
|
-
console.log(` ${
|
|
285943
|
-
console.log(` ${
|
|
286268
|
+
console.log(` ${import_picocolors26.default.green("\u2713")} wrote ${import_picocolors26.default.bold(args.out)} ${import_picocolors26.default.dim(`(${result.models.length} models)`)}`);
|
|
286269
|
+
console.log(` ${import_picocolors26.default.dim(`models: ${result.models.join(", ")}`)}`);
|
|
285944
286270
|
if (result.skipped.length > 0) {
|
|
285945
|
-
console.log(` ${
|
|
285946
|
-
for (const s of result.skipped) console.log(` ${
|
|
286271
|
+
console.log(` ${import_picocolors26.default.dim(`${result.skipped.length} model(s) skipped:`)}`);
|
|
286272
|
+
for (const s of result.skipped) console.log(` ${import_picocolors26.default.dim(`- ${s.name}: ${s.reason}`)}`);
|
|
285947
286273
|
}
|
|
285948
286274
|
console.log(
|
|
285949
286275
|
`
|
|
285950
|
-
${
|
|
286276
|
+
${import_picocolors26.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors26.default.bold("ablo check")}.
|
|
285951
286277
|
`
|
|
285952
286278
|
);
|
|
285953
286279
|
}
|
|
285954
286280
|
|
|
285955
286281
|
// src/drizzlePull.ts
|
|
285956
286282
|
init_cjs_shims();
|
|
285957
|
-
var
|
|
285958
|
-
var
|
|
286283
|
+
var import_picocolors27 = __toESM(require_picocolors(), 1);
|
|
286284
|
+
var import_errors20 = require("@abloatai/transaction/errors");
|
|
285959
286285
|
var import_fs12 = require("fs");
|
|
285960
286286
|
var import_path7 = require("path");
|
|
285961
286287
|
init_theme();
|
|
@@ -286062,7 +286388,7 @@ function parseDrizzlePullArgs(argv) {
|
|
|
286062
286388
|
force = true;
|
|
286063
286389
|
break;
|
|
286064
286390
|
default:
|
|
286065
|
-
if (arg.startsWith("--")) throw new
|
|
286391
|
+
if (arg.startsWith("--")) throw new import_errors20.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
|
|
286066
286392
|
schema = arg;
|
|
286067
286393
|
}
|
|
286068
286394
|
}
|
|
@@ -286079,27 +286405,27 @@ async function drizzlePull(argv) {
|
|
|
286079
286405
|
try {
|
|
286080
286406
|
args = parseDrizzlePullArgs(argv);
|
|
286081
286407
|
} catch (err) {
|
|
286082
|
-
console.error(
|
|
286408
|
+
console.error(import_picocolors27.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
286083
286409
|
process.exit(1);
|
|
286084
286410
|
}
|
|
286085
286411
|
if (!args.schema) {
|
|
286086
286412
|
console.error(
|
|
286087
|
-
|
|
286413
|
+
import_picocolors27.default.red(` No Drizzle schema given.`) + import_picocolors27.default.dim(` Pass the module: ${import_picocolors27.default.bold("ablo pull drizzle src/db/schema.ts")}.`)
|
|
286088
286414
|
);
|
|
286089
286415
|
process.exit(1);
|
|
286090
286416
|
}
|
|
286091
286417
|
if (!(0, import_fs12.existsSync)(args.schema)) {
|
|
286092
|
-
console.error(
|
|
286418
|
+
console.error(import_picocolors27.default.red(` No file at ${import_picocolors27.default.bold(args.schema)}.`));
|
|
286093
286419
|
process.exit(1);
|
|
286094
286420
|
}
|
|
286095
286421
|
if ((0, import_fs12.existsSync)(args.out) && !args.force) {
|
|
286096
286422
|
console.error(
|
|
286097
|
-
|
|
286423
|
+
import_picocolors27.default.red(` ${args.out} already exists.`) + import_picocolors27.default.dim(` Re-run with ${import_picocolors27.default.bold("--force")} to overwrite.`)
|
|
286098
286424
|
);
|
|
286099
286425
|
process.exit(1);
|
|
286100
286426
|
}
|
|
286101
286427
|
console.log(`
|
|
286102
|
-
${brand("ablo")} ${
|
|
286428
|
+
${brand("ablo")} ${import_picocolors27.default.dim("pull drizzle")} ${import_picocolors27.default.dim(args.schema)}
|
|
286103
286429
|
`);
|
|
286104
286430
|
let result;
|
|
286105
286431
|
try {
|
|
@@ -286107,26 +286433,26 @@ async function drizzlePull(argv) {
|
|
|
286107
286433
|
result = await buildSchemaSourceFromDrizzle({ mod, importPath: args.importPath });
|
|
286108
286434
|
} catch (err) {
|
|
286109
286435
|
const msg = err instanceof Error ? err.message : String(err);
|
|
286110
|
-
const hint = msg.includes("Cannot find package 'drizzle-orm'") ?
|
|
286111
|
-
console.error(
|
|
286436
|
+
const hint = msg.includes("Cannot find package 'drizzle-orm'") ? import_picocolors27.default.dim(` (install ${import_picocolors27.default.bold("drizzle-orm")} in this project)`) : "";
|
|
286437
|
+
console.error(import_picocolors27.default.red(` Couldn't load the schema: ${msg}`) + hint);
|
|
286112
286438
|
process.exit(1);
|
|
286113
286439
|
}
|
|
286114
286440
|
if (result.models.length === 0) {
|
|
286115
286441
|
console.error(
|
|
286116
|
-
|
|
286442
|
+
import_picocolors27.default.yellow(` No adoptable tables found`) + import_picocolors27.default.dim(` (a table needs an ${import_picocolors27.default.bold("id")} + ${import_picocolors27.default.bold("organization_id")} column).`)
|
|
286117
286443
|
);
|
|
286118
286444
|
process.exit(1);
|
|
286119
286445
|
}
|
|
286120
286446
|
(0, import_fs12.writeFileSync)(args.out, result.source);
|
|
286121
|
-
console.log(` ${
|
|
286122
|
-
console.log(` ${
|
|
286447
|
+
console.log(` ${import_picocolors27.default.green("\u2713")} wrote ${import_picocolors27.default.bold(args.out)} ${import_picocolors27.default.dim(`(${result.models.length} models)`)}`);
|
|
286448
|
+
console.log(` ${import_picocolors27.default.dim(`models: ${result.models.join(", ")}`)}`);
|
|
286123
286449
|
if (result.skipped.length > 0) {
|
|
286124
|
-
console.log(` ${
|
|
286125
|
-
for (const s of result.skipped) console.log(` ${
|
|
286450
|
+
console.log(` ${import_picocolors27.default.dim(`${result.skipped.length} table(s) skipped:`)}`);
|
|
286451
|
+
for (const s of result.skipped) console.log(` ${import_picocolors27.default.dim(`- ${s.name}: ${s.reason}`)}`);
|
|
286126
286452
|
}
|
|
286127
286453
|
console.log(
|
|
286128
286454
|
`
|
|
286129
|
-
${
|
|
286455
|
+
${import_picocolors27.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors27.default.bold("ablo check")}.
|
|
286130
286456
|
`
|
|
286131
286457
|
);
|
|
286132
286458
|
}
|
|
@@ -286212,7 +286538,7 @@ async function getCurrentUser(): Promise<{ id: string } | null> {
|
|
|
286212
286538
|
|
|
286213
286539
|
// src/index.ts
|
|
286214
286540
|
var LOGO = `
|
|
286215
|
-
${brand("ablo")} ${
|
|
286541
|
+
${brand("ablo")} ${import_picocolors28.default.dim("sync engine")}
|
|
286216
286542
|
`;
|
|
286217
286543
|
var HANDLERS = {
|
|
286218
286544
|
init: (argv) => init([...argv]),
|
|
@@ -286221,6 +286547,7 @@ var HANDLERS = {
|
|
|
286221
286547
|
projects: (argv) => projects([...argv]),
|
|
286222
286548
|
branch: (argv) => branches([...argv]),
|
|
286223
286549
|
status: (argv) => status([...argv]),
|
|
286550
|
+
whoami: (argv) => whoami([...argv]),
|
|
286224
286551
|
doctor: () => doctor(),
|
|
286225
286552
|
logs: (argv) => logs([...argv]),
|
|
286226
286553
|
webhooks: (argv) => webhooks([...argv]),
|
|
@@ -286239,7 +286566,7 @@ async function runDev(argv) {
|
|
|
286239
286566
|
const devArgs = [...argv];
|
|
286240
286567
|
const oneShot = devArgs.includes("--no-watch");
|
|
286241
286568
|
console.log(
|
|
286242
|
-
|
|
286569
|
+
import_picocolors28.default.dim(
|
|
286243
286570
|
oneShot ? " `ablo dev --no-watch` prepares this Git branch and pushes once." : " `ablo dev` prepares this Git branch and watches the schema."
|
|
286244
286571
|
)
|
|
286245
286572
|
);
|
|
@@ -286260,13 +286587,13 @@ async function runPush2(argv) {
|
|
|
286260
286587
|
const guard = guardActiveProjectKey();
|
|
286261
286588
|
if (!guard.ok && guard.available.length > 0 && !rest.includes("--url")) {
|
|
286262
286589
|
console.error(
|
|
286263
|
-
` ${
|
|
286590
|
+
` ${import_picocolors28.default.yellow("\u26A0")} active project ${import_picocolors28.default.bold(guard.activeProfile)} has no stored key ${import_picocolors28.default.dim(
|
|
286264
286591
|
`(you have keys for: ${guard.available.join(", ")})`
|
|
286265
286592
|
)}`
|
|
286266
286593
|
);
|
|
286267
286594
|
const loginCmd = guard.activeProfile === "default" ? "ablo login" : `ablo login --project ${guard.activeProfile}`;
|
|
286268
286595
|
console.error(
|
|
286269
|
-
|
|
286596
|
+
import_picocolors28.default.dim(` Mint one with ${import_picocolors28.default.bold(loginCmd)}, or switch with ${import_picocolors28.default.bold("ablo projects use <slug>")}.`)
|
|
286270
286597
|
);
|
|
286271
286598
|
process.exitCode = 1;
|
|
286272
286599
|
return;
|
|
@@ -286277,7 +286604,7 @@ async function runPush2(argv) {
|
|
|
286277
286604
|
}
|
|
286278
286605
|
function runRenamedSchema(argv) {
|
|
286279
286606
|
const forwarded = argv.slice(1).join(" ");
|
|
286280
|
-
console.error(` ${
|
|
286607
|
+
console.error(` ${import_picocolors28.default.red("\u2717")} \`ablo schema push\` was renamed to \`${brand("ablo push")}\`.`);
|
|
286281
286608
|
console.error(` Run \`ablo push${forwarded ? " " + forwarded : ""}\` instead.`);
|
|
286282
286609
|
process.exitCode = 1;
|
|
286283
286610
|
}
|
|
@@ -286287,7 +286614,7 @@ async function main() {
|
|
|
286287
286614
|
const argv = process.argv.slice(3);
|
|
286288
286615
|
if (!command && raw !== void 0 && raw !== "help" && !raw.startsWith("-")) {
|
|
286289
286616
|
const suggestion = suggestCommand(raw);
|
|
286290
|
-
throw new
|
|
286617
|
+
throw new import_errors21.AbloValidationError(
|
|
286291
286618
|
`\`${raw}\` isn't an ablo command.` + (suggestion ? ` Did you mean \`ablo ${suggestion}\`?` : " Run `ablo help --all` to see every command."),
|
|
286292
286619
|
{ code: "cli_invalid_arguments" }
|
|
286293
286620
|
);
|
|
@@ -286318,7 +286645,7 @@ function printCoreHelp() {
|
|
|
286318
286645
|
const width = Math.max(...rows.map((r2) => r2.run.length)) + 4;
|
|
286319
286646
|
console.log(LOGO);
|
|
286320
286647
|
for (const group of CORE_GROUPS) {
|
|
286321
|
-
console.log(` ${
|
|
286648
|
+
console.log(` ${import_picocolors28.default.bold(group)}`);
|
|
286322
286649
|
const printed = group === "More" ? [...coreRows(group), ...extra] : coreRows(group);
|
|
286323
286650
|
for (const row of printed) console.log(` npx ablo ${row.run.padEnd(width)}${row.does}`);
|
|
286324
286651
|
console.log();
|
|
@@ -286327,7 +286654,7 @@ function printCoreHelp() {
|
|
|
286327
286654
|
}
|
|
286328
286655
|
function printSchemaReminder() {
|
|
286329
286656
|
console.log(
|
|
286330
|
-
|
|
286657
|
+
import_picocolors28.default.dim(` Edit ${import_picocolors28.default.bold("ablo/schema.ts")}, then push \u2014 writes to models you haven't pushed fail with `) + import_picocolors28.default.yellow("server_execute_unknown_model") + import_picocolors28.default.dim(".")
|
|
286331
286658
|
);
|
|
286332
286659
|
console.log();
|
|
286333
286660
|
}
|
|
@@ -286337,7 +286664,7 @@ function printFullHelp() {
|
|
|
286337
286664
|
) + 2;
|
|
286338
286665
|
console.log(LOGO);
|
|
286339
286666
|
for (const group of FULL_GROUPS) {
|
|
286340
|
-
console.log(` ${
|
|
286667
|
+
console.log(` ${import_picocolors28.default.bold(group)}`);
|
|
286341
286668
|
for (const row of fullRows(group)) {
|
|
286342
286669
|
console.log(row.does === void 0 ? ` ${" ".repeat(9)}${row.run}` : ` npx ablo ${row.run.padEnd(width)}${row.does}`);
|
|
286343
286670
|
}
|
|
@@ -286392,7 +286719,7 @@ async function ensureInitProject(opts) {
|
|
|
286392
286719
|
const ensured = await ensureProject(slug);
|
|
286393
286720
|
if (ensured) {
|
|
286394
286721
|
console.log(
|
|
286395
|
-
` ${
|
|
286722
|
+
` ${import_picocolors28.default.green("\u2713")} ${ensured.created ? "Created" : "Using"} project ${import_picocolors28.default.bold(ensured.slug)} ${import_picocolors28.default.dim(`(${ensured.id})`)} \u2014 keys you mint for it are isolated from the org's other apps.`
|
|
286396
286723
|
);
|
|
286397
286724
|
}
|
|
286398
286725
|
}
|
|
@@ -286434,7 +286761,7 @@ async function chooseBool(flagValue, fallback, interactive, prompt) {
|
|
|
286434
286761
|
async function init(args = []) {
|
|
286435
286762
|
const opts = parseInitArgs(args);
|
|
286436
286763
|
const interactive = Boolean(process.stdin.isTTY) && !opts.yes && !process.env.CI;
|
|
286437
|
-
Ie(`${brand("ablo")} ${
|
|
286764
|
+
Ie(`${brand("ablo")} ${import_picocolors28.default.dim("sync engine")}`);
|
|
286438
286765
|
if (!(0, import_fs13.existsSync)("package.json")) {
|
|
286439
286766
|
xe("No package.json found. Run this from your project root.");
|
|
286440
286767
|
process.exit(1);
|
|
@@ -286512,7 +286839,7 @@ async function init(args = []) {
|
|
|
286512
286839
|
if (pullExisting) {
|
|
286513
286840
|
const dbUrl = readProjectAdminDatabaseUrl();
|
|
286514
286841
|
if (!dbUrl) {
|
|
286515
|
-
schemaNote =
|
|
286842
|
+
schemaNote = import_picocolors28.default.dim(` (no ${ADMIN_URL_VAR} \u2014 wrote starter; run \`ablo pull\` later)`);
|
|
286516
286843
|
} else {
|
|
286517
286844
|
try {
|
|
286518
286845
|
const pulled = await buildSchemaSourceFromDb({
|
|
@@ -286522,12 +286849,12 @@ async function init(args = []) {
|
|
|
286522
286849
|
});
|
|
286523
286850
|
if (pulled.models.length > 0) {
|
|
286524
286851
|
schemaSource = pulled.source;
|
|
286525
|
-
schemaNote =
|
|
286852
|
+
schemaNote = import_picocolors28.default.dim(` (pulled ${pulled.models.length} models)`);
|
|
286526
286853
|
} else {
|
|
286527
|
-
schemaNote =
|
|
286854
|
+
schemaNote = import_picocolors28.default.dim(" (no adoptable tables \u2014 wrote starter)");
|
|
286528
286855
|
}
|
|
286529
286856
|
} catch {
|
|
286530
|
-
schemaNote =
|
|
286857
|
+
schemaNote = import_picocolors28.default.dim(" (pull failed \u2014 wrote starter)");
|
|
286531
286858
|
}
|
|
286532
286859
|
}
|
|
286533
286860
|
}
|
|
@@ -286551,9 +286878,9 @@ async function init(args = []) {
|
|
|
286551
286878
|
const existing = (0, import_fs13.readFileSync)(envFile, "utf-8");
|
|
286552
286879
|
if (!existing.includes("ABLO_")) {
|
|
286553
286880
|
(0, import_fs13.writeFileSync)(envFile, existing + "\n" + envBody);
|
|
286554
|
-
created.push(`${envFile} ${
|
|
286881
|
+
created.push(`${envFile} ${import_picocolors28.default.dim("(appended)")}`);
|
|
286555
286882
|
} else {
|
|
286556
|
-
created.push(`${envFile} ${
|
|
286883
|
+
created.push(`${envFile} ${import_picocolors28.default.dim("(already configured)")}`);
|
|
286557
286884
|
}
|
|
286558
286885
|
}
|
|
286559
286886
|
if (agent) {
|
|
@@ -286569,17 +286896,17 @@ async function init(args = []) {
|
|
|
286569
286896
|
}
|
|
286570
286897
|
const providersPath = (0, import_path8.join)(layout.appBase, "providers.tsx");
|
|
286571
286898
|
(0, import_fs13.writeFileSync)(providersPath, generateProviders());
|
|
286572
|
-
created.push(`${providersPath} ${
|
|
286899
|
+
created.push(`${providersPath} ${import_picocolors28.default.dim(`(wrap ${(0, import_path8.join)(layout.appBase, "layout.tsx")} in <Providers>)`)}`);
|
|
286573
286900
|
const sessionDir = (0, import_path8.join)(layout.appBase, "api", "ablo-session");
|
|
286574
286901
|
(0, import_fs13.mkdirSync)(sessionDir, { recursive: true });
|
|
286575
286902
|
(0, import_fs13.writeFileSync)((0, import_path8.join)(sessionDir, "route.ts"), generateSessionRoute());
|
|
286576
|
-
created.push(`${(0, import_path8.join)(sessionDir, "route.ts")} ${
|
|
286903
|
+
created.push(`${(0, import_path8.join)(sessionDir, "route.ts")} ${import_picocolors28.default.dim("(wire your auth)")}`);
|
|
286577
286904
|
}
|
|
286578
286905
|
if (framework !== "vanilla") {
|
|
286579
286906
|
(0, import_fs13.writeFileSync)((0, import_path8.join)(abloDir, "TaskList.tsx"), generateComponent());
|
|
286580
286907
|
created.push(`${abloDir}/TaskList.tsx`);
|
|
286581
286908
|
}
|
|
286582
|
-
Me(created.map((f) => `${
|
|
286909
|
+
Me(created.map((f) => `${import_picocolors28.default.green("\u2713")} ${f}`).join("\n"), "Created");
|
|
286583
286910
|
const pm = detectPackageManager();
|
|
286584
286911
|
if (opts.install) {
|
|
286585
286912
|
const s = Y2();
|
|
@@ -286588,46 +286915,46 @@ async function init(args = []) {
|
|
|
286588
286915
|
(0, import_child_process3.execSync)(`${pm} add @abloatai/ablo`, { stdio: "ignore" });
|
|
286589
286916
|
s.stop("Installed @abloatai/ablo");
|
|
286590
286917
|
} catch {
|
|
286591
|
-
s.stop(`${
|
|
286918
|
+
s.stop(`${import_picocolors28.default.yellow("!")} Couldn't auto-install \u2014 run ${import_picocolors28.default.bold(`${pm} install @abloatai/ablo`)}`);
|
|
286592
286919
|
}
|
|
286593
286920
|
}
|
|
286594
286921
|
const steps = [
|
|
286595
|
-
`Run ${
|
|
286596
|
-
`Set ${
|
|
286597
|
-
`Run ${
|
|
286922
|
+
`Run ${import_picocolors28.default.bold("npx ablo login")} to authorize branch management`,
|
|
286923
|
+
`Set ${import_picocolors28.default.bold("DATABASE_URL")} in ${import_picocolors28.default.bold(envFile)} \u2014 your Postgres is the system of record; rows live there, never with Ablo`,
|
|
286924
|
+
`Run ${import_picocolors28.default.bold("npx ablo dev")} \u2014 pushes your schema definition and watches for changes`,
|
|
286598
286925
|
...storage === "replication" ? [
|
|
286599
|
-
`Connect your database \u2014 ${
|
|
286600
|
-
`Verify it \u2014 ${
|
|
286601
|
-
`Register it \u2014 ${
|
|
286926
|
+
`Connect your database \u2014 ${import_picocolors28.default.bold("npx ablo connect")} prints the one-time logical-replication setup SQL to run on your Postgres`,
|
|
286927
|
+
`Verify it \u2014 ${import_picocolors28.default.bold("npx ablo connect check")} walks wal_level, the publication, the role, and replica identity, with the exact fix for anything missing`,
|
|
286928
|
+
`Register it \u2014 ${import_picocolors28.default.bold("npx ablo connect register")} tells Ablo to start replicating; your app keeps writing through your own backend while Ablo tails the WAL`
|
|
286602
286929
|
] : [
|
|
286603
|
-
`Provision your DB: ${
|
|
286930
|
+
`Provision your DB: ${import_picocolors28.default.bold("npx ablo migrate")} (creates your Ablo-model tables + the adapter tables; keep your own migrations for everything else), then mount ${import_picocolors28.default.bold(`${abloDir}/data-source.ts`)} at ${import_picocolors28.default.bold("/api/ablo/source")}`
|
|
286604
286931
|
],
|
|
286605
286932
|
...framework === "nextjs" ? [
|
|
286606
|
-
`Wrap ${
|
|
286933
|
+
`Wrap ${import_picocolors28.default.bold((0, import_path8.join)(layout.appBase, "layout.tsx"))} in ${import_picocolors28.default.bold("<Providers>")} (${(0, import_path8.join)(layout.appBase, "providers.tsx")}) and add your auth to ${import_picocolors28.default.bold((0, import_path8.join)(layout.appBase, "api", "ablo-session", "route.ts"))}`
|
|
286607
286934
|
] : [],
|
|
286608
|
-
`Run ${
|
|
286935
|
+
`Run ${import_picocolors28.default.bold(`${pm} run dev`)} and open two browser tabs \u2014 changes sync in real-time`,
|
|
286609
286936
|
...agent ? [
|
|
286610
|
-
`Run ${
|
|
286611
|
-
`Run ${
|
|
286937
|
+
`Run ${import_picocolors28.default.bold(`npx tsx ${abloDir}/agent.ts`)} \u2014 an AI teammate edits the same tasks`,
|
|
286938
|
+
`Run ${import_picocolors28.default.bold("npx ablo logs")} to watch human + agent commits stream by`
|
|
286612
286939
|
] : []
|
|
286613
286940
|
];
|
|
286614
286941
|
Me(steps.map((s, i) => `${i + 1}. ${s}`).join("\n"), "Next steps");
|
|
286615
286942
|
const existingKey = resolveManagementKey();
|
|
286616
286943
|
if (existingKey) {
|
|
286617
286944
|
await ensureInitProject(opts);
|
|
286618
|
-
Se(`Already authorized ${
|
|
286945
|
+
Se(`Already authorized ${import_picocolors28.default.dim(`(${existingKey.slice(0, 11)}\u2026)`)}. Run ${import_picocolors28.default.bold("npx ablo dev")} next. ${import_picocolors28.default.dim("Docs:")} https://abloatai.com/docs`);
|
|
286619
286946
|
return;
|
|
286620
286947
|
}
|
|
286621
286948
|
if (interactive && opts.login) {
|
|
286622
286949
|
const loginNow = await ye({ message: "Log in now? (opens your browser)", initialValue: true });
|
|
286623
286950
|
if (!pD(loginNow) && loginNow) {
|
|
286624
|
-
Se(`${
|
|
286951
|
+
Se(`${import_picocolors28.default.dim("Docs:")} https://abloatai.com/docs`);
|
|
286625
286952
|
await login();
|
|
286626
286953
|
await ensureInitProject(opts);
|
|
286627
286954
|
return;
|
|
286628
286955
|
}
|
|
286629
286956
|
}
|
|
286630
|
-
Se(`Run ${
|
|
286957
|
+
Se(`Run ${import_picocolors28.default.bold("npx ablo login")} when ready. ${import_picocolors28.default.dim("Docs:")} https://abloatai.com/docs`);
|
|
286631
286958
|
}
|
|
286632
286959
|
function generateSchema() {
|
|
286633
286960
|
return `import { defineSchema, model, relation, z } from '@abloatai/ablo/schema';
|