@abloatai/cli 0.40.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 +704 -326
- 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
|
}
|
|
@@ -5102,8 +5113,8 @@ var init_disconnect = __esm({
|
|
|
5102
5113
|
npx ablo connect deregister Remove the active project's data source (confirms first)
|
|
5103
5114
|
npx ablo connect deregister --yes Skip the confirmation
|
|
5104
5115
|
|
|
5105
|
-
Acts on one plane \u2014 the active project (${import_picocolors8.default.bold("ablo projects use")}) in the
|
|
5106
|
-
environment (${import_picocolors8.default.bold("
|
|
5116
|
+
Acts on one plane \u2014 the active project (${import_picocolors8.default.bold("ablo projects use")}) in the key's
|
|
5117
|
+
environment (its ${import_picocolors8.default.bold("sk_test_")}/${import_picocolors8.default.bold("sk_live_")} prefix), shown before it runs. Removes the registration and
|
|
5107
5118
|
Ablo's replication state for that plane, so Ablo stops reading and writing the
|
|
5108
5119
|
database. Reconnect with ${import_picocolors8.default.bold("ablo connect")}.`;
|
|
5109
5120
|
}
|
|
@@ -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,10 +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
|
-
loggedIn ? `You are logged in, but this project has no
|
|
5700
|
-
|
|
5701
|
-
|
|
5712
|
+
loggedIn ? `You are logged in, but this project has no ${getMode()} data key.
|
|
5713
|
+
|
|
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.
|
|
5715
|
+
|
|
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}` : ""}`,
|
|
5702
5721
|
{ code: "cli_api_key_missing" }
|
|
5703
5722
|
);
|
|
5704
5723
|
}
|
|
@@ -5713,23 +5732,39 @@ Start one with \`npx ablo dev\`, or set ABLO_API_KEY to that plane's key.` : "No
|
|
|
5713
5732
|
);
|
|
5714
5733
|
const pooledAdmin = detectPooler(adminUrl);
|
|
5715
5734
|
if (pooledAdmin?.confidence === "host") {
|
|
5716
|
-
|
|
5717
|
-
|
|
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.
|
|
5718
5749
|
`
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5750
|
+
)
|
|
5751
|
+
);
|
|
5752
|
+
} else {
|
|
5753
|
+
console.error(
|
|
5754
|
+
` ${import_picocolors11.default.yellow("!")} ${import_picocolors11.default.bold(target)} is a connection pooler, not the database.
|
|
5724
5755
|
`
|
|
5725
|
-
)
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
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.
|
|
5730
5761
|
`
|
|
5731
|
-
|
|
5732
|
-
|
|
5762
|
+
)
|
|
5763
|
+
);
|
|
5764
|
+
console.error(` Re-run against the direct database host, not the pooled one.
|
|
5765
|
+
`);
|
|
5766
|
+
process.exit(1);
|
|
5767
|
+
}
|
|
5733
5768
|
}
|
|
5734
5769
|
if (pooledAdmin?.confidence === "port") {
|
|
5735
5770
|
console.log(
|
|
@@ -5769,31 +5804,31 @@ Start one with \`npx ablo dev\`, or set ABLO_API_KEY to that plane's key.` : "No
|
|
|
5769
5804
|
`);
|
|
5770
5805
|
console.error(
|
|
5771
5806
|
import_picocolors11.default.dim(` Your database is untouched.
|
|
5772
|
-
`) + ` To move it here, disconnect it there first with ${import_picocolors11.default.cyan("ablo connect deregister")}
|
|
5773
|
-
`
|
|
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"
|
|
5774
5809
|
);
|
|
5775
5810
|
process.exit(1);
|
|
5776
5811
|
}
|
|
5812
|
+
let rotatePlane = null;
|
|
5777
5813
|
if (rotating) {
|
|
5778
5814
|
const state = await fetchDataSourceState(apiBaseUrl(), apiKey).catch(
|
|
5779
5815
|
() => ({ kind: "unknown", detail: "unreachable" })
|
|
5780
5816
|
);
|
|
5781
|
-
|
|
5782
|
-
rotating,
|
|
5817
|
+
rotatePlane = {
|
|
5783
5818
|
planeHasConnection: state.kind === "connected",
|
|
5784
5819
|
known: state.kind !== "unknown",
|
|
5785
5820
|
// 401/403 is Ablo answering and declining the key, not a network failure.
|
|
5786
5821
|
keyRejected: state.kind === "unknown" && /HTTP 40[13]/.test(state.detail)
|
|
5787
|
-
}
|
|
5788
|
-
if (
|
|
5789
|
-
|
|
5822
|
+
};
|
|
5823
|
+
if (rotatePlane.keyRejected) {
|
|
5824
|
+
const refusal = rotateWithoutConnection({ rotating, ...rotatePlane, existingRoles: [] });
|
|
5825
|
+
if (refusal) {
|
|
5826
|
+
console.error(` ${import_picocolors11.default.yellow("!")} ${refusal}
|
|
5790
5827
|
`);
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
);
|
|
5796
|
-
process.exit(1);
|
|
5828
|
+
console.error(import_picocolors11.default.dim(` Your database is untouched.
|
|
5829
|
+
`));
|
|
5830
|
+
process.exit(1);
|
|
5831
|
+
}
|
|
5797
5832
|
}
|
|
5798
5833
|
}
|
|
5799
5834
|
const admin = src_default(adminUrl, {
|
|
@@ -5853,9 +5888,21 @@ Start one with \`npx ablo dev\`, or set ABLO_API_KEY to that plane's key.` : "No
|
|
|
5853
5888
|
const pubReconcile = reconcilePublicationPlan(existingPublication, tables);
|
|
5854
5889
|
const role = args.role && args.role.length > 0 ? args.role : import_footprint.ABLO_REPLICATION_ROLE;
|
|
5855
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
|
+
}
|
|
5856
5903
|
const blocker = reapplyBlocker({
|
|
5857
5904
|
rotating,
|
|
5858
|
-
existingRoles
|
|
5905
|
+
existingRoles
|
|
5859
5906
|
});
|
|
5860
5907
|
if (blocker) {
|
|
5861
5908
|
await admin.end({ timeout: 2 });
|
|
@@ -6078,6 +6125,7 @@ function parseConnectArgs(argv) {
|
|
|
6078
6125
|
let yes = false;
|
|
6079
6126
|
let showSql = false;
|
|
6080
6127
|
let scan = false;
|
|
6128
|
+
let locate = false;
|
|
6081
6129
|
let manual = false;
|
|
6082
6130
|
let tables = [];
|
|
6083
6131
|
let role = import_footprint.ABLO_REPLICATION_ROLE;
|
|
@@ -6102,9 +6150,12 @@ function parseConnectArgs(argv) {
|
|
|
6102
6150
|
case "scan":
|
|
6103
6151
|
scan = true;
|
|
6104
6152
|
break;
|
|
6153
|
+
case "locate":
|
|
6154
|
+
locate = true;
|
|
6155
|
+
break;
|
|
6105
6156
|
default:
|
|
6106
6157
|
throw new import_errors10.AbloValidationError(
|
|
6107
|
-
`unknown connect subcommand: ${lead} (expected register, deregister, check, apply, rotate, scan)`,
|
|
6158
|
+
`unknown connect subcommand: ${lead} (expected register, deregister, check, apply, rotate, scan, locate)`,
|
|
6108
6159
|
{ code: "cli_invalid_arguments" }
|
|
6109
6160
|
);
|
|
6110
6161
|
}
|
|
@@ -6166,6 +6217,7 @@ function parseConnectArgs(argv) {
|
|
|
6166
6217
|
yes,
|
|
6167
6218
|
showSql,
|
|
6168
6219
|
scan,
|
|
6220
|
+
locate,
|
|
6169
6221
|
tables,
|
|
6170
6222
|
role,
|
|
6171
6223
|
writeRole,
|
|
@@ -6463,8 +6515,11 @@ async function runCheck() {
|
|
|
6463
6515
|
);
|
|
6464
6516
|
const apiKey = resolveApiKey();
|
|
6465
6517
|
if (!apiKey) {
|
|
6518
|
+
const ambient = ambientEnvKeyNote();
|
|
6466
6519
|
throw new import_errors10.AbloAuthenticationError(
|
|
6467
|
-
|
|
6520
|
+
`No API key found. Run \`ablo login\` (or set ABLO_API_KEY), then re-run \`ablo connect check\`.${ambient ? `
|
|
6521
|
+
|
|
6522
|
+
${ambient}` : ""}`,
|
|
6468
6523
|
{ code: "cli_api_key_missing" }
|
|
6469
6524
|
);
|
|
6470
6525
|
}
|
|
@@ -6529,8 +6584,11 @@ async function runRegister(args) {
|
|
|
6529
6584
|
const writeDbUrl = requireScopedUrl("write", "register");
|
|
6530
6585
|
const apiKey = resolveApiKey();
|
|
6531
6586
|
if (!apiKey) {
|
|
6587
|
+
const ambient = ambientEnvKeyNote();
|
|
6532
6588
|
throw new import_errors10.AbloAuthenticationError(
|
|
6533
|
-
|
|
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}` : ""}`,
|
|
6534
6592
|
{ code: "cli_api_key_missing" }
|
|
6535
6593
|
);
|
|
6536
6594
|
}
|
|
@@ -6631,6 +6689,62 @@ async function runScan() {
|
|
|
6631
6689
|
}
|
|
6632
6690
|
process.exit(retired.length > 0 ? 1 : 0);
|
|
6633
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
|
+
}
|
|
6634
6748
|
async function connect(argv) {
|
|
6635
6749
|
if (argv[0] === "deregister") {
|
|
6636
6750
|
const { disconnect: disconnect2 } = await Promise.resolve().then(() => (init_disconnect(), disconnect_exports));
|
|
@@ -6655,6 +6769,10 @@ async function connect(argv) {
|
|
|
6655
6769
|
await runScan();
|
|
6656
6770
|
return;
|
|
6657
6771
|
}
|
|
6772
|
+
if (args.locate) {
|
|
6773
|
+
await runLocate(args);
|
|
6774
|
+
return;
|
|
6775
|
+
}
|
|
6658
6776
|
const credentialReachable = (args.url ?? readProjectAdminDatabaseUrl()) != null;
|
|
6659
6777
|
const canConfirm = process.stdout.isTTY || args.yes;
|
|
6660
6778
|
if (!args.manual && credentialReachable && canConfirm) {
|
|
@@ -6664,7 +6782,7 @@ async function connect(argv) {
|
|
|
6664
6782
|
}
|
|
6665
6783
|
printConnectRecipe(args);
|
|
6666
6784
|
}
|
|
6667
|
-
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;
|
|
6668
6786
|
var init_connect = __esm({
|
|
6669
6787
|
"src/connect.ts"() {
|
|
6670
6788
|
"use strict";
|
|
@@ -6676,6 +6794,7 @@ var init_connect = __esm({
|
|
|
6676
6794
|
init_dbRole();
|
|
6677
6795
|
init_config();
|
|
6678
6796
|
init_controlPlane();
|
|
6797
|
+
import_wire7 = require("@abloatai/transaction/wire");
|
|
6679
6798
|
init_theme();
|
|
6680
6799
|
init_remoteValidation();
|
|
6681
6800
|
init_connectSetup();
|
|
@@ -6699,6 +6818,7 @@ var init_connect = __esm({
|
|
|
6699
6818
|
npx ablo connect check Confirm the connected database is ready, from Ablo's side (needs only ABLO_API_KEY)
|
|
6700
6819
|
npx ablo connect rotate New passwords for both logins, then re-register
|
|
6701
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)
|
|
6702
6822
|
|
|
6703
6823
|
Running it: bare \`ablo connect\` sets everything up for you \u2014 creating the two
|
|
6704
6824
|
scoped logins, sharing your tables, and registering \u2014 whenever it finds a
|
|
@@ -282700,7 +282820,7 @@ Node text: ${this.#forgottenText}`;
|
|
|
282700
282820
|
// src/index.ts
|
|
282701
282821
|
init_cjs_shims();
|
|
282702
282822
|
init_dist2();
|
|
282703
|
-
var
|
|
282823
|
+
var import_picocolors28 = __toESM(require_picocolors(), 1);
|
|
282704
282824
|
var import_fs13 = require("fs");
|
|
282705
282825
|
var import_path8 = require("path");
|
|
282706
282826
|
var import_child_process3 = require("child_process");
|
|
@@ -283734,6 +283854,223 @@ async function runBranchDev(argv, dependencies = {}) {
|
|
|
283734
283854
|
});
|
|
283735
283855
|
}
|
|
283736
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
|
+
|
|
283737
284074
|
// src/commands.ts
|
|
283738
284075
|
var CORE_GROUPS = ["Start", "Every day", "More"];
|
|
283739
284076
|
var FULL_GROUPS = [
|
|
@@ -283784,6 +284121,7 @@ var COMMANDS = [
|
|
|
283784
284121
|
{ run: "connect apply", does: "Run that setup for you, from a one-time admin URL" },
|
|
283785
284122
|
{ run: "connect check", does: "Confirm your database is ready to share changes with Ablo" },
|
|
283786
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" },
|
|
283787
284125
|
{ run: "connect deregister", does: "Disconnect this project's database \u2014 Ablo stops reading and writing it" }
|
|
283788
284126
|
]
|
|
283789
284127
|
}
|
|
@@ -283873,6 +284211,18 @@ var COMMANDS = [
|
|
|
283873
284211
|
]
|
|
283874
284212
|
}
|
|
283875
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
|
+
},
|
|
283876
284226
|
{
|
|
283877
284227
|
name: "status",
|
|
283878
284228
|
core: { group: "Every day", does: "See what this key acts on, your pushed schema, and whether writes will work" },
|
|
@@ -283947,6 +284297,46 @@ var BY_NAME = new Map(ALL.map((c) => [c.name, c]));
|
|
|
283947
284297
|
function parseCommandName(raw) {
|
|
283948
284298
|
return raw !== void 0 && BY_NAME.has(raw) ? raw : null;
|
|
283949
284299
|
}
|
|
284300
|
+
var REDIRECTS = /* @__PURE__ */ new Map([
|
|
284301
|
+
["disconnect", "connect deregister"],
|
|
284302
|
+
["deregister", "connect deregister"],
|
|
284303
|
+
["register", "connect register"],
|
|
284304
|
+
["rotate", "connect rotate"]
|
|
284305
|
+
]);
|
|
284306
|
+
function editDistance(a, b4) {
|
|
284307
|
+
const cols = b4.length + 1;
|
|
284308
|
+
let prevPrev = new Int32Array(cols);
|
|
284309
|
+
let prev = new Int32Array(cols);
|
|
284310
|
+
let curr = new Int32Array(cols);
|
|
284311
|
+
const at = (row, index) => row[index] ?? 0;
|
|
284312
|
+
for (let j2 = 0; j2 < cols; j2++) prev[j2] = j2;
|
|
284313
|
+
for (let i = 1; i <= a.length; i++) {
|
|
284314
|
+
curr[0] = i;
|
|
284315
|
+
for (let j2 = 1; j2 < cols; j2++) {
|
|
284316
|
+
const cost = a.charCodeAt(i - 1) === b4.charCodeAt(j2 - 1) ? 0 : 1;
|
|
284317
|
+
let best = Math.min(at(prev, j2) + 1, at(curr, j2 - 1) + 1, at(prev, j2 - 1) + cost);
|
|
284318
|
+
if (i > 1 && j2 > 1 && a.charCodeAt(i - 1) === b4.charCodeAt(j2 - 2) && a.charCodeAt(i - 2) === b4.charCodeAt(j2 - 1)) {
|
|
284319
|
+
best = Math.min(best, at(prevPrev, j2 - 2) + 1);
|
|
284320
|
+
}
|
|
284321
|
+
curr[j2] = best;
|
|
284322
|
+
}
|
|
284323
|
+
[prevPrev, prev, curr] = [prev, curr, prevPrev];
|
|
284324
|
+
}
|
|
284325
|
+
return at(prev, b4.length);
|
|
284326
|
+
}
|
|
284327
|
+
function suggestCommand(raw) {
|
|
284328
|
+
const exact = REDIRECTS.get(raw);
|
|
284329
|
+
if (exact) return exact;
|
|
284330
|
+
let best = null;
|
|
284331
|
+
for (const name of [...BY_NAME.keys(), ...REDIRECTS.keys()]) {
|
|
284332
|
+
const distance = editDistance(raw.toLowerCase(), name);
|
|
284333
|
+
if (distance <= 2 && (best === null || distance < best.distance)) {
|
|
284334
|
+
best = { name, distance };
|
|
284335
|
+
}
|
|
284336
|
+
}
|
|
284337
|
+
if (best === null) return null;
|
|
284338
|
+
return REDIRECTS.get(best.name) ?? best.name;
|
|
284339
|
+
}
|
|
283950
284340
|
function usageFor(name) {
|
|
283951
284341
|
return BY_NAME.get(name)?.usage;
|
|
283952
284342
|
}
|
|
@@ -283961,14 +284351,15 @@ function fullRows(group) {
|
|
|
283961
284351
|
}
|
|
283962
284352
|
|
|
283963
284353
|
// src/index.ts
|
|
284354
|
+
var import_errors21 = require("@abloatai/transaction/errors");
|
|
283964
284355
|
init_push();
|
|
283965
284356
|
|
|
283966
284357
|
// src/generate.ts
|
|
283967
284358
|
init_cjs_shims();
|
|
283968
|
-
var
|
|
284359
|
+
var import_errors14 = require("@abloatai/transaction/errors");
|
|
283969
284360
|
var import_fs8 = require("fs");
|
|
283970
284361
|
var import_path6 = require("path");
|
|
283971
|
-
var
|
|
284362
|
+
var import_picocolors17 = __toESM(require_picocolors(), 1);
|
|
283972
284363
|
var import_schema7 = require("@abloatai/transaction/schema");
|
|
283973
284364
|
init_push();
|
|
283974
284365
|
var DEFAULT_SCHEMA_PATH4 = "ablo/schema.ts";
|
|
@@ -283991,7 +284382,7 @@ function parseGenerateArgs(argv) {
|
|
|
283991
284382
|
out = argv[++i] ?? out;
|
|
283992
284383
|
break;
|
|
283993
284384
|
default:
|
|
283994
|
-
throw new
|
|
284385
|
+
throw new import_errors14.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
|
|
283995
284386
|
}
|
|
283996
284387
|
}
|
|
283997
284388
|
return { schemaPath, exportName, out };
|
|
@@ -284001,7 +284392,7 @@ async function generate(argv) {
|
|
|
284001
284392
|
try {
|
|
284002
284393
|
args = parseGenerateArgs(argv);
|
|
284003
284394
|
} catch (err) {
|
|
284004
|
-
console.error(
|
|
284395
|
+
console.error(import_picocolors17.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
284005
284396
|
process.exit(1);
|
|
284006
284397
|
}
|
|
284007
284398
|
let source;
|
|
@@ -284010,22 +284401,22 @@ async function generate(argv) {
|
|
|
284010
284401
|
const schemaJson = JSON.parse((0, import_schema7.serializeSchema)(schema));
|
|
284011
284402
|
source = (0, import_schema7.generateTypes)(schemaJson);
|
|
284012
284403
|
} catch (err) {
|
|
284013
|
-
console.error(
|
|
284404
|
+
console.error(import_picocolors17.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
284014
284405
|
process.exit(1);
|
|
284015
284406
|
}
|
|
284016
284407
|
const abs = (0, import_path6.resolve)(process.cwd(), args.out);
|
|
284017
284408
|
(0, import_fs8.mkdirSync)((0, import_path6.dirname)(abs), { recursive: true });
|
|
284018
284409
|
(0, import_fs8.writeFileSync)(abs, source);
|
|
284019
|
-
console.log(` ${
|
|
284410
|
+
console.log(` ${import_picocolors17.default.green("\u2713")} Generated types \u2192 ${import_picocolors17.default.bold(args.out)}`);
|
|
284020
284411
|
}
|
|
284021
284412
|
|
|
284022
284413
|
// src/login.ts
|
|
284023
284414
|
init_cjs_shims();
|
|
284024
284415
|
var import_child_process2 = require("child_process");
|
|
284025
|
-
var
|
|
284416
|
+
var import_picocolors18 = __toESM(require_picocolors(), 1);
|
|
284026
284417
|
init_dist2();
|
|
284027
|
-
var
|
|
284028
|
-
var
|
|
284418
|
+
var import_errors15 = require("@abloatai/transaction/errors");
|
|
284419
|
+
var import_wire8 = require("@abloatai/transaction/wire");
|
|
284029
284420
|
init_config();
|
|
284030
284421
|
init_theme();
|
|
284031
284422
|
var CLIENT_ID = "ablo-cli";
|
|
@@ -284043,20 +284434,21 @@ function openBrowser(url) {
|
|
|
284043
284434
|
} catch {
|
|
284044
284435
|
}
|
|
284045
284436
|
}
|
|
284046
|
-
function
|
|
284047
|
-
const i = argv.indexOf(
|
|
284437
|
+
function parseSlugFlag(argv, flag2) {
|
|
284438
|
+
const i = argv.indexOf(flag2);
|
|
284048
284439
|
if (i >= 0) {
|
|
284049
284440
|
const slug = argv[i + 1];
|
|
284050
284441
|
if (slug && !slug.startsWith("-")) return slug;
|
|
284051
284442
|
}
|
|
284052
|
-
const eq = argv.find((a) => a.startsWith(
|
|
284053
|
-
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;
|
|
284054
284445
|
}
|
|
284055
284446
|
async function deviceLogin(argv, deps = {}) {
|
|
284056
284447
|
const openUrl = deps.openUrl ?? openBrowser;
|
|
284057
284448
|
Ie(`${brand("ablo")} login`);
|
|
284058
|
-
const requested =
|
|
284449
|
+
const requested = parseSlugFlag(argv, "--project") ?? getActiveProject()?.slug;
|
|
284059
284450
|
const targetProject = requested === DEFAULT_PROFILE ? void 0 : requested;
|
|
284451
|
+
const targetOrg = parseSlugFlag(argv, "--org");
|
|
284060
284452
|
const interactive = Boolean(process.stdout.isTTY && process.stdin.isTTY);
|
|
284061
284453
|
let account = "login";
|
|
284062
284454
|
if (interactive) {
|
|
@@ -284083,11 +284475,11 @@ async function deviceLogin(argv, deps = {}) {
|
|
|
284083
284475
|
process.exit(1);
|
|
284084
284476
|
}
|
|
284085
284477
|
const code = await codeRes.json();
|
|
284086
|
-
const approvePath = `/cli?user_code=${code.user_code}`;
|
|
284478
|
+
const approvePath = `/cli?user_code=${code.user_code}${targetOrg ? `&org=${encodeURIComponent(targetOrg)}` : ""}`;
|
|
284087
284479
|
const url = account === "signup" ? `${DASHBOARD_URL}/signup?next=${encodeURIComponent(approvePath)}` : `${DASHBOARD_URL}${approvePath}`;
|
|
284088
|
-
Me(`${
|
|
284480
|
+
Me(`${import_picocolors18.default.bold(code.user_code)}
|
|
284089
284481
|
|
|
284090
|
-
${
|
|
284482
|
+
${import_picocolors18.default.dim(url)}`, "Approve in your browser");
|
|
284091
284483
|
openUrl(url);
|
|
284092
284484
|
const s = Y2();
|
|
284093
284485
|
s.start("Waiting for approval\u2026");
|
|
@@ -284157,7 +284549,7 @@ ${import_picocolors17.default.dim(url)}`, "Approve in your browser");
|
|
|
284157
284549
|
}
|
|
284158
284550
|
if (!provRes.ok) {
|
|
284159
284551
|
s.stop("Could not provision a key.");
|
|
284160
|
-
const err = (0,
|
|
284552
|
+
const err = (0, import_errors15.translateHttpError)(
|
|
284161
284553
|
provRes.status,
|
|
284162
284554
|
await provRes.json().catch(() => null),
|
|
284163
284555
|
provRes.headers.get("x-request-id") ?? void 0
|
|
@@ -284165,30 +284557,36 @@ ${import_picocolors17.default.dim(url)}`, "Approve in your browser");
|
|
|
284165
284557
|
M2.error(err.message);
|
|
284166
284558
|
if (err.code === "entity_not_found" && targetProject) {
|
|
284167
284559
|
M2.error(
|
|
284168
|
-
`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}`)}.`
|
|
284169
284561
|
);
|
|
284170
284562
|
} else {
|
|
284171
284563
|
M2.error(
|
|
284172
|
-
`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.`
|
|
284173
284565
|
);
|
|
284174
284566
|
}
|
|
284175
284567
|
process.exit(1);
|
|
284176
284568
|
}
|
|
284177
|
-
const parsedProv =
|
|
284569
|
+
const parsedProv = import_wire8.provisionKeyResponseSchema.safeParse(
|
|
284178
284570
|
await provRes.json().catch(() => null)
|
|
284179
284571
|
);
|
|
284180
284572
|
if (!parsedProv.success) {
|
|
284181
284573
|
s.stop("Could not provision a key.");
|
|
284182
284574
|
M2.error("The key handoff returned something this version does not recognize.");
|
|
284183
|
-
M2.error(`Try again, or upgrade with ${
|
|
284575
|
+
M2.error(`Try again, or upgrade with ${import_picocolors18.default.bold("npm i -g @abloatai/ablo")}.`);
|
|
284184
284576
|
process.exit(1);
|
|
284185
284577
|
}
|
|
284186
284578
|
const prov = parsedProv.data;
|
|
284187
284579
|
const entry = (k3) => ({
|
|
284188
284580
|
apiKey: k3.apiKey,
|
|
284189
284581
|
...prov.organizationId ? { organizationId: prov.organizationId } : {},
|
|
284582
|
+
...prov.organizationSlug ? { organizationSlug: prov.organizationSlug } : {},
|
|
284190
284583
|
...k3.expiresAt ? { expiresAt: k3.expiresAt } : {}
|
|
284191
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
|
+
}
|
|
284192
284590
|
const profileName = prov.project?.slug ?? DEFAULT_PROFILE;
|
|
284193
284591
|
const path = setProfileKeys(
|
|
284194
284592
|
profileName,
|
|
@@ -284198,9 +284596,10 @@ ${import_picocolors17.default.dim(url)}`, "Approve in your browser");
|
|
|
284198
284596
|
{ mode: "sandbox", activeProject: prov.project ?? void 0 }
|
|
284199
284597
|
);
|
|
284200
284598
|
s.stop(`Saved project credential to ${path}`);
|
|
284201
|
-
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})`)}` : "";
|
|
284202
284601
|
Se(
|
|
284203
|
-
`${
|
|
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.`
|
|
284204
284603
|
);
|
|
284205
284604
|
}
|
|
284206
284605
|
async function login(argv = [], deps = {}) {
|
|
@@ -284209,14 +284608,14 @@ async function login(argv = [], deps = {}) {
|
|
|
284209
284608
|
function logout() {
|
|
284210
284609
|
const removed = clearCredential();
|
|
284211
284610
|
if (removed) {
|
|
284212
|
-
console.log(` ${
|
|
284611
|
+
console.log(` ${import_picocolors18.default.green("\u2713")} Logged out ${import_picocolors18.default.dim(`(credentials removed from ${configDir()})`)}`);
|
|
284213
284612
|
} else {
|
|
284214
|
-
console.log(` ${
|
|
284613
|
+
console.log(` ${import_picocolors18.default.dim("\u25CB")} Not logged in \u2014 nothing to remove.`);
|
|
284215
284614
|
}
|
|
284216
284615
|
if (process.env.ABLO_MANAGEMENT_KEY) {
|
|
284217
284616
|
console.log(
|
|
284218
|
-
|
|
284219
|
-
` Note: ${
|
|
284617
|
+
import_picocolors18.default.dim(
|
|
284618
|
+
` Note: ${import_picocolors18.default.bold("ABLO_MANAGEMENT_KEY")} is still set in this shell and takes precedence.`
|
|
284220
284619
|
)
|
|
284221
284620
|
);
|
|
284222
284621
|
}
|
|
@@ -284228,46 +284627,9 @@ init_projects();
|
|
|
284228
284627
|
|
|
284229
284628
|
// src/status.ts
|
|
284230
284629
|
init_cjs_shims();
|
|
284231
|
-
var
|
|
284630
|
+
var import_picocolors19 = __toESM(require_picocolors(), 1);
|
|
284232
284631
|
init_config();
|
|
284233
284632
|
init_target();
|
|
284234
|
-
|
|
284235
|
-
// src/credentialCapability.ts
|
|
284236
|
-
init_cjs_shims();
|
|
284237
|
-
var import_credentialPolicy3 = require("@abloatai/transaction/auth/credentialPolicy");
|
|
284238
|
-
init_config();
|
|
284239
|
-
function secretCounterpart(key) {
|
|
284240
|
-
return modeFromKey(key) === "production" ? "sk_live_" : "sk_test_";
|
|
284241
|
-
}
|
|
284242
|
-
function credentialCapability(key) {
|
|
284243
|
-
const kind = key ? (0, import_credentialPolicy3.classifyCredentialKind)(key) : null;
|
|
284244
|
-
if (!key || kind === null) return { kind, label: "", note: null };
|
|
284245
|
-
const secret = `${secretCounterpart(key)}\u2026`;
|
|
284246
|
-
switch (kind) {
|
|
284247
|
-
case "secret":
|
|
284248
|
-
return { kind, label: "", note: null };
|
|
284249
|
-
case "restricted":
|
|
284250
|
-
return {
|
|
284251
|
-
kind,
|
|
284252
|
-
label: "scoped",
|
|
284253
|
-
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.`
|
|
284254
|
-
};
|
|
284255
|
-
case "publishable":
|
|
284256
|
-
return {
|
|
284257
|
-
kind,
|
|
284258
|
-
label: "read-only",
|
|
284259
|
-
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.`
|
|
284260
|
-
};
|
|
284261
|
-
case "ephemeral":
|
|
284262
|
-
return {
|
|
284263
|
-
kind,
|
|
284264
|
-
label: "session key",
|
|
284265
|
-
note: `This is a short-lived credential minted for one signed-in person, and it expires. Pushing a schema needs a secret ${secret} key.`
|
|
284266
|
-
};
|
|
284267
|
-
}
|
|
284268
|
-
}
|
|
284269
|
-
|
|
284270
|
-
// src/status.ts
|
|
284271
284633
|
init_theme();
|
|
284272
284634
|
init_controlPlane();
|
|
284273
284635
|
var import_schema8 = require("@abloatai/transaction/coordination/schema");
|
|
@@ -284275,9 +284637,9 @@ init_readiness();
|
|
|
284275
284637
|
function expiryLabel(iso) {
|
|
284276
284638
|
const ms = Date.parse(iso) - Date.now();
|
|
284277
284639
|
if (Number.isNaN(ms)) return "";
|
|
284278
|
-
if (ms <= 0) return
|
|
284640
|
+
if (ms <= 0) return import_picocolors19.default.red("expired");
|
|
284279
284641
|
const days = Math.floor(ms / (24 * 60 * 60 * 1e3));
|
|
284280
|
-
return
|
|
284642
|
+
return import_picocolors19.default.dim(days > 0 ? `expires in ${days}d` : "expires <1d");
|
|
284281
284643
|
}
|
|
284282
284644
|
async function ping(apiUrl3) {
|
|
284283
284645
|
const ctrl = new AbortController();
|
|
@@ -284298,40 +284660,42 @@ function formatConflict(conflict) {
|
|
|
284298
284660
|
const parts = import_schema8.participantKindSchema.options.flatMap((k3) => conflict[k3] ? [`${k3}:${conflict[k3]}`] : []);
|
|
284299
284661
|
return parts.length ? `{${parts.join(",")}}` : "";
|
|
284300
284662
|
}
|
|
284301
|
-
function printTargetLines(target, localProject, storedOrganizationId) {
|
|
284663
|
+
function printTargetLines(target, localProject, storedOrganizationId, storedOrganizationSlug) {
|
|
284302
284664
|
const confirmed = target?.confirmed ?? null;
|
|
284303
284665
|
const org = confirmed?.organizationId ?? storedOrganizationId;
|
|
284304
284666
|
if (org) {
|
|
284305
|
-
const suffix = confirmed?.organizationId ? "" : ` ${
|
|
284306
|
-
|
|
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}`);
|
|
284307
284671
|
} else {
|
|
284308
284672
|
console.log(
|
|
284309
|
-
` ${
|
|
284673
|
+
` ${import_picocolors19.default.dim("org")} ${import_picocolors19.default.yellow("unknown")} ${import_picocolors19.default.dim("(the server did not confirm one for this key)")}`
|
|
284310
284674
|
);
|
|
284311
284675
|
}
|
|
284312
284676
|
let projectLine;
|
|
284313
284677
|
if (confirmed?.project) {
|
|
284314
284678
|
const p2 = confirmed.project;
|
|
284315
|
-
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})`)}`;
|
|
284316
284680
|
} else if (confirmed) {
|
|
284317
|
-
projectLine = `${
|
|
284681
|
+
projectLine = `${import_picocolors19.default.bold("default")} ${import_picocolors19.default.dim("(org-default)")}`;
|
|
284318
284682
|
} else if (localProject) {
|
|
284319
|
-
projectLine = `${
|
|
284683
|
+
projectLine = `${import_picocolors19.default.bold(localProject.slug)} ${import_picocolors19.default.dim(`(${localProject.id})`)} ${import_picocolors19.default.yellow("(unconfirmed)")}`;
|
|
284320
284684
|
} else {
|
|
284321
|
-
projectLine = `${
|
|
284685
|
+
projectLine = `${import_picocolors19.default.bold("default")} ${target ? import_picocolors19.default.yellow("(unconfirmed)") : import_picocolors19.default.dim("(org-default)")}`;
|
|
284322
284686
|
}
|
|
284323
|
-
console.log(` ${
|
|
284687
|
+
console.log(` ${import_picocolors19.default.dim("project")} ${projectLine}`);
|
|
284324
284688
|
const branch = confirmed?.branchId ?? null;
|
|
284325
284689
|
const env = confirmed?.environment ?? target?.keyEnv ?? null;
|
|
284326
284690
|
if (branch) {
|
|
284327
284691
|
const label = confirmed?.branchRoot ? "production root" : `branch ${branch}`;
|
|
284328
|
-
console.log(` ${
|
|
284692
|
+
console.log(` ${import_picocolors19.default.dim("acts on")} ${import_picocolors19.default.bold(label)}`);
|
|
284329
284693
|
} else if (env) {
|
|
284330
|
-
const suffix = confirmed ? "" : ` ${
|
|
284331
|
-
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}`);
|
|
284332
284696
|
}
|
|
284333
284697
|
const divergence = describeMismatches(target?.mismatches ?? []);
|
|
284334
|
-
if (divergence) console.log(` ${
|
|
284698
|
+
if (divergence) console.log(` ${import_picocolors19.default.yellow(`\u26A0 ${divergence}`)}`);
|
|
284335
284699
|
}
|
|
284336
284700
|
async function status(args = []) {
|
|
284337
284701
|
const apiUrl3 = apiBaseUrl();
|
|
@@ -284420,23 +284784,28 @@ async function status(args = []) {
|
|
|
284420
284784
|
return;
|
|
284421
284785
|
}
|
|
284422
284786
|
console.log(`
|
|
284423
|
-
${brand("ablo")} ${
|
|
284787
|
+
${brand("ablo")} ${import_picocolors19.default.dim("status")}
|
|
284424
284788
|
`);
|
|
284425
284789
|
if (effective.key && effective.source && effective.source !== "stored") {
|
|
284426
284790
|
const label = effective.source === "env" ? "ABLO_API_KEY env" : effective.source;
|
|
284427
284791
|
console.log(
|
|
284428
|
-
` ${
|
|
284792
|
+
` ${import_picocolors19.default.dim("key")} ${effective.key.slice(0, 12)}\u2026 ${import_picocolors19.default.dim(`(${label} \u2014 overrides stored)`)}`
|
|
284429
284793
|
);
|
|
284430
284794
|
} else if (!cfg) {
|
|
284431
|
-
console.log(` ${
|
|
284795
|
+
console.log(` ${import_picocolors19.default.yellow("!")} Not logged in \u2014 run ${import_picocolors19.default.bold("ablo login")}.`);
|
|
284432
284796
|
}
|
|
284433
284797
|
const activeEntry = getKeyEntry(mode);
|
|
284434
284798
|
const key = describeEffectiveKey(mode, process.env.ABLO_API_KEY, activeEntry);
|
|
284435
284799
|
if (key.keyMismatch) {
|
|
284436
|
-
console.log(` ${
|
|
284800
|
+
console.log(` ${import_picocolors19.default.yellow(`! ${key.keyMismatch.message}`)}`);
|
|
284437
284801
|
}
|
|
284438
284802
|
const activeProject = getActiveProject();
|
|
284439
|
-
printTargetLines(
|
|
284803
|
+
printTargetLines(
|
|
284804
|
+
target,
|
|
284805
|
+
activeProject,
|
|
284806
|
+
activeEntry?.organizationId,
|
|
284807
|
+
activeEntry?.organizationSlug
|
|
284808
|
+
);
|
|
284440
284809
|
for (const { key: m2, label } of [
|
|
284441
284810
|
{ key: "sandbox", label: "management" },
|
|
284442
284811
|
{ key: "production", label: "observer" }
|
|
@@ -284447,68 +284816,68 @@ async function status(args = []) {
|
|
|
284447
284816
|
credentialCapability(entry.apiKey).label,
|
|
284448
284817
|
entry.expiresAt ? expiryLabel(entry.expiresAt) : ""
|
|
284449
284818
|
].filter(Boolean);
|
|
284450
|
-
const trail = facts.length ? ` ${
|
|
284819
|
+
const trail = facts.length ? ` ${import_picocolors19.default.dim("\xB7")} ${facts.join(import_picocolors19.default.dim(" \xB7 "))}` : "";
|
|
284451
284820
|
console.log(
|
|
284452
|
-
` ${
|
|
284821
|
+
` ${import_picocolors19.default.dim("\u25CB")} ${label.padEnd(10)} ${import_picocolors19.default.dim(`${entry.apiKey.slice(0, 12)}\u2026`)}${trail}`
|
|
284453
284822
|
);
|
|
284454
284823
|
} else {
|
|
284455
|
-
console.log(` ${
|
|
284824
|
+
console.log(` ${import_picocolors19.default.dim("\u25CB")} ${label.padEnd(10)} ${import_picocolors19.default.dim("\u2014 no key")}`);
|
|
284456
284825
|
}
|
|
284457
284826
|
}
|
|
284458
284827
|
const plan = resolvePushPlan();
|
|
284459
284828
|
console.log(
|
|
284460
|
-
` ${
|
|
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")})`)}`}`
|
|
284461
284830
|
);
|
|
284462
284831
|
const capability = credentialCapability(effective.key);
|
|
284463
|
-
if (capability.note) console.log(` ${
|
|
284464
|
-
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} `);
|
|
284465
284834
|
const reachable = await ping(apiUrl3);
|
|
284466
|
-
console.log(reachable ?
|
|
284835
|
+
console.log(reachable ? import_picocolors19.default.green("reachable") : import_picocolors19.default.red("unreachable"));
|
|
284467
284836
|
const introspectKey = effective.key;
|
|
284468
284837
|
const { source: dataSource, validation } = reachable ? await fetchRoutingState(apiUrl3, introspectKey) : { source: { kind: "unknown", detail: "unreachable" }, validation: null };
|
|
284469
284838
|
if (dataSource.kind === "connected") {
|
|
284470
284839
|
const how = [...new Set(dataSource.connections)].join(" + ");
|
|
284471
284840
|
const pooled = detectPoolerIn(dataSource.hosts);
|
|
284472
284841
|
const unreachable = validation && !validation.ok ? validation.message : void 0;
|
|
284473
|
-
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})`)}`);
|
|
284474
284843
|
if (pooled) {
|
|
284475
284844
|
console.log(
|
|
284476
|
-
` ${
|
|
284845
|
+
` ${import_picocolors19.default.yellow("\u26A0")} ${import_picocolors19.default.dim(
|
|
284477
284846
|
`${pooled.host} is a connection pooler` + (pooled.direct ? `; register the direct host instead: ${pooled.direct}` : "; register the direct host instead")
|
|
284478
284847
|
)}`
|
|
284479
284848
|
);
|
|
284480
284849
|
}
|
|
284481
284850
|
if (unreachable) {
|
|
284482
|
-
console.log(` ${
|
|
284851
|
+
console.log(` ${import_picocolors19.default.red("\u2717")} ${import_picocolors19.default.dim(`Ablo could not reach it \u2014 ${unreachable}`)}`);
|
|
284483
284852
|
}
|
|
284484
284853
|
} else if (dataSource.kind === "none") {
|
|
284485
284854
|
console.log(
|
|
284486
|
-
` ${
|
|
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")}`
|
|
284487
284856
|
);
|
|
284488
284857
|
} else if (reachable) {
|
|
284489
|
-
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})`)}`);
|
|
284490
284859
|
}
|
|
284491
284860
|
const pushed = reachable ? await fetchPushedSchema(apiUrl3, introspectKey) : null;
|
|
284492
284861
|
if (reachable) {
|
|
284493
284862
|
if (pushed?.active) {
|
|
284494
|
-
const when = pushed.pushedAt ? ` ${
|
|
284495
|
-
const ver = pushed.version != null ? ` ${
|
|
284496
|
-
const hashLabel = pushed.hash ? ` ${
|
|
284497
|
-
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}`);
|
|
284498
284867
|
for (const m2 of pushed.models) {
|
|
284499
|
-
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}`);
|
|
284500
284869
|
const conflict = formatConflict(m2.conflict);
|
|
284501
|
-
const conflictStr2 = conflict ? ` ${
|
|
284502
|
-
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}`);
|
|
284503
284872
|
}
|
|
284504
284873
|
} else if (pushed && !pushed.active) {
|
|
284505
|
-
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")})`)}`);
|
|
284506
284875
|
}
|
|
284507
284876
|
}
|
|
284508
284877
|
const drift = schemaDrift(await readLocalSchemaHash(), pushed?.hash);
|
|
284509
284878
|
if (drift) {
|
|
284510
284879
|
console.log(
|
|
284511
|
-
` ${
|
|
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})`)
|
|
284512
284881
|
);
|
|
284513
284882
|
}
|
|
284514
284883
|
const found = blockers({
|
|
@@ -284520,33 +284889,33 @@ async function status(args = []) {
|
|
|
284520
284889
|
});
|
|
284521
284890
|
console.log();
|
|
284522
284891
|
if (found.length > 0) {
|
|
284523
|
-
console.log(` ${
|
|
284892
|
+
console.log(` ${import_picocolors19.default.red("\u2717")} ${import_picocolors19.default.bold("writes would fail right now")}`);
|
|
284524
284893
|
for (const b4 of found) {
|
|
284525
|
-
console.log(` ${
|
|
284526
|
-
console.log(` ${
|
|
284894
|
+
console.log(` ${import_picocolors19.default.dim("\xB7")} ${b4.problem}`);
|
|
284895
|
+
console.log(` ${import_picocolors19.default.dim(b4.fix)}`);
|
|
284527
284896
|
}
|
|
284528
284897
|
} else if (dataSource.kind === "unknown") {
|
|
284529
284898
|
console.log(
|
|
284530
|
-
` ${
|
|
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")}`
|
|
284531
284900
|
);
|
|
284532
284901
|
} else {
|
|
284533
|
-
console.log(` ${
|
|
284902
|
+
console.log(` ${import_picocolors19.default.green("\u2713")} ${import_picocolors19.default.dim("ready \u2014 a write should succeed")}`);
|
|
284534
284903
|
}
|
|
284535
284904
|
console.log();
|
|
284536
284905
|
}
|
|
284537
284906
|
|
|
284538
284907
|
// src/doctor.ts
|
|
284539
284908
|
init_cjs_shims();
|
|
284540
|
-
var
|
|
284909
|
+
var import_picocolors20 = __toESM(require_picocolors(), 1);
|
|
284541
284910
|
init_theme();
|
|
284542
284911
|
init_controlPlane();
|
|
284543
284912
|
init_config();
|
|
284544
284913
|
init_target();
|
|
284545
284914
|
init_readiness();
|
|
284546
284915
|
function render(check2) {
|
|
284547
|
-
const mark = check2.state === "ok" ?
|
|
284548
|
-
console.log(` ${mark} ${check2.label.padEnd(10)} ${check2.state === "fail" ? check2.detail :
|
|
284549
|
-
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}`)}`);
|
|
284550
284919
|
}
|
|
284551
284920
|
async function ping2(apiUrl3) {
|
|
284552
284921
|
const ctrl = new AbortController();
|
|
@@ -284564,7 +284933,7 @@ async function ping2(apiUrl3) {
|
|
|
284564
284933
|
}
|
|
284565
284934
|
async function doctor() {
|
|
284566
284935
|
console.log(`
|
|
284567
|
-
${brand("ablo")} ${
|
|
284936
|
+
${brand("ablo")} ${import_picocolors20.default.dim("doctor")}
|
|
284568
284937
|
`);
|
|
284569
284938
|
const apiUrl3 = apiBaseUrl();
|
|
284570
284939
|
const effective = resolveEffectiveApiKey();
|
|
@@ -284679,15 +285048,15 @@ async function doctor() {
|
|
|
284679
285048
|
console.log();
|
|
284680
285049
|
if (failed > 0) {
|
|
284681
285050
|
console.log(
|
|
284682
|
-
` ${
|
|
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` : "")
|
|
284683
285052
|
);
|
|
284684
|
-
console.log(
|
|
285053
|
+
console.log(import_picocolors20.default.dim(" Fix them in the order above \u2014 an earlier one often explains a later one."));
|
|
284685
285054
|
} else if (skipped > 0) {
|
|
284686
285055
|
console.log(
|
|
284687
|
-
` ${
|
|
285056
|
+
` ${import_picocolors20.default.yellow("?")} ${import_picocolors20.default.dim(`nothing is blocking a write, but ${skipped} check${skipped === 1 ? "" : "s"} could not be run`)}`
|
|
284688
285057
|
);
|
|
284689
285058
|
} else {
|
|
284690
|
-
console.log(` ${
|
|
285059
|
+
console.log(` ${import_picocolors20.default.green("\u2713")} ${import_picocolors20.default.dim("everything checks out \u2014 a write should succeed")}`);
|
|
284691
285060
|
}
|
|
284692
285061
|
console.log();
|
|
284693
285062
|
if (blocking.length > 0 || failed > 0) process.exitCode = 1;
|
|
@@ -284695,9 +285064,9 @@ async function doctor() {
|
|
|
284695
285064
|
|
|
284696
285065
|
// src/logs.ts
|
|
284697
285066
|
init_cjs_shims();
|
|
284698
|
-
var
|
|
284699
|
-
var
|
|
284700
|
-
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);
|
|
284701
285070
|
init_config();
|
|
284702
285071
|
init_theme();
|
|
284703
285072
|
init_controlPlane();
|
|
@@ -284740,12 +285109,12 @@ function parseLogsArgs(argv) {
|
|
|
284740
285109
|
case "--mode": {
|
|
284741
285110
|
const raw = argv[++i];
|
|
284742
285111
|
const m2 = normalizeMode(raw);
|
|
284743
|
-
if (!m2) throw new
|
|
285112
|
+
if (!m2) throw new import_errors16.AbloValidationError(`--mode expects "sandbox" or "production", got "${raw}"`, { code: "cli_invalid_arguments" });
|
|
284744
285113
|
args.mode = m2;
|
|
284745
285114
|
break;
|
|
284746
285115
|
}
|
|
284747
285116
|
default:
|
|
284748
|
-
throw new
|
|
285117
|
+
throw new import_errors16.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
|
|
284749
285118
|
}
|
|
284750
285119
|
}
|
|
284751
285120
|
return args;
|
|
@@ -284764,10 +285133,10 @@ function resolveSince(since) {
|
|
|
284764
285133
|
var sleep2 = (ms) => new Promise((r2) => setTimeout(r2, ms));
|
|
284765
285134
|
function colorOp(op) {
|
|
284766
285135
|
const label = op.padEnd(6);
|
|
284767
|
-
if (op === "create") return
|
|
284768
|
-
if (op === "update") return
|
|
284769
|
-
if (op === "delete") return
|
|
284770
|
-
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);
|
|
284771
285140
|
}
|
|
284772
285141
|
function render2(e2, json) {
|
|
284773
285142
|
if (json) {
|
|
@@ -284776,21 +285145,21 @@ function render2(e2, json) {
|
|
|
284776
285145
|
return;
|
|
284777
285146
|
}
|
|
284778
285147
|
const t = new Date(e2.at).toLocaleTimeString();
|
|
284779
|
-
const actor = e2.actor ?
|
|
284780
|
-
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}`);
|
|
284781
285150
|
}
|
|
284782
285151
|
async function logs(argv) {
|
|
284783
285152
|
let args;
|
|
284784
285153
|
try {
|
|
284785
285154
|
args = parseLogsArgs(argv);
|
|
284786
285155
|
} catch (err) {
|
|
284787
|
-
console.error(
|
|
285156
|
+
console.error(import_picocolors21.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
284788
285157
|
process.exit(1);
|
|
284789
285158
|
}
|
|
284790
285159
|
const apiKey = resolveApiKey(args.mode);
|
|
284791
285160
|
if (!apiKey) {
|
|
284792
285161
|
console.error(
|
|
284793
|
-
|
|
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")}.`)
|
|
284794
285163
|
);
|
|
284795
285164
|
process.exit(1);
|
|
284796
285165
|
}
|
|
@@ -284804,18 +285173,18 @@ async function logs(argv) {
|
|
|
284804
285173
|
if (!res) return null;
|
|
284805
285174
|
if (!res.ok) {
|
|
284806
285175
|
const body = await res.json().catch(() => ({}));
|
|
284807
|
-
console.error(
|
|
285176
|
+
console.error(import_picocolors21.default.red(` logs failed (${res.status}): ${body.reason ?? body.message ?? ""}`));
|
|
284808
285177
|
process.exit(1);
|
|
284809
285178
|
}
|
|
284810
285179
|
const json = await res.json();
|
|
284811
285180
|
return {
|
|
284812
285181
|
events: json.data ?? json.events ?? [],
|
|
284813
|
-
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))
|
|
284814
285183
|
};
|
|
284815
285184
|
}
|
|
284816
285185
|
if (!args.json) {
|
|
284817
285186
|
console.log(`
|
|
284818
|
-
${brand("ablo")} ${
|
|
285187
|
+
${brand("ablo")} ${import_picocolors21.default.dim("logs")} ${import_picocolors21.default.dim(`(${args.mode ?? "active"} mode)`)}
|
|
284819
285188
|
`);
|
|
284820
285189
|
}
|
|
284821
285190
|
const initial = await fetchPage({
|
|
@@ -284825,13 +285194,13 @@ async function logs(argv) {
|
|
|
284825
285194
|
...args.op ? { op: args.op } : {}
|
|
284826
285195
|
});
|
|
284827
285196
|
if (!initial) {
|
|
284828
|
-
console.error(
|
|
285197
|
+
console.error(import_picocolors21.default.red(` Couldn't reach ${baseUrl2}.`));
|
|
284829
285198
|
process.exit(1);
|
|
284830
285199
|
}
|
|
284831
285200
|
for (const e2 of initial.events) render2(e2, args.json);
|
|
284832
285201
|
let cursor = initial.cursor;
|
|
284833
285202
|
if (!args.follow) return;
|
|
284834
|
-
if (!args.json) console.log(` ${
|
|
285203
|
+
if (!args.json) console.log(` ${import_picocolors21.default.dim("watching for new activity \u2026 (Ctrl-C to stop)")}
|
|
284835
285204
|
`);
|
|
284836
285205
|
for (; ; ) {
|
|
284837
285206
|
await sleep2(1500);
|
|
@@ -284842,16 +285211,16 @@ async function logs(argv) {
|
|
|
284842
285211
|
});
|
|
284843
285212
|
if (!page) continue;
|
|
284844
285213
|
for (const e2 of page.events) render2(e2, args.json);
|
|
284845
|
-
const prev = (0,
|
|
284846
|
-
const next = (0,
|
|
284847
|
-
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;
|
|
284848
285217
|
}
|
|
284849
285218
|
}
|
|
284850
285219
|
|
|
284851
285220
|
// src/webhooks.ts
|
|
284852
285221
|
init_cjs_shims();
|
|
284853
285222
|
var import_fs9 = require("fs");
|
|
284854
|
-
var
|
|
285223
|
+
var import_picocolors22 = __toESM(require_picocolors(), 1);
|
|
284855
285224
|
var import_credentialPolicy4 = require("@abloatai/transaction/auth/credentialPolicy");
|
|
284856
285225
|
init_config();
|
|
284857
285226
|
init_theme();
|
|
@@ -284884,12 +285253,12 @@ function requireKey3(mode) {
|
|
|
284884
285253
|
const apiKey = resolveApiKey(mode);
|
|
284885
285254
|
if (!apiKey) {
|
|
284886
285255
|
console.error(
|
|
284887
|
-
|
|
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")}.`)
|
|
284888
285257
|
);
|
|
284889
285258
|
process.exit(1);
|
|
284890
285259
|
}
|
|
284891
285260
|
if ((0, import_credentialPolicy4.classifyCredentialKind)(apiKey) !== "secret") {
|
|
284892
|
-
console.error(
|
|
285261
|
+
console.error(import_picocolors22.default.red(" Managing webhooks requires a secret key ") + import_picocolors22.default.dim("(sk_test_ / sk_live_)."));
|
|
284893
285262
|
process.exit(1);
|
|
284894
285263
|
}
|
|
284895
285264
|
return apiKey;
|
|
@@ -284905,12 +285274,12 @@ async function api(apiKey, method, path, body) {
|
|
|
284905
285274
|
...body ? { body: JSON.stringify(body) } : {}
|
|
284906
285275
|
}).catch(() => null);
|
|
284907
285276
|
if (!res) {
|
|
284908
|
-
console.error(
|
|
285277
|
+
console.error(import_picocolors22.default.red(` Couldn't reach ${baseUrl()}.`));
|
|
284909
285278
|
process.exit(1);
|
|
284910
285279
|
}
|
|
284911
285280
|
if (!res.ok) {
|
|
284912
285281
|
const err = await res.json().catch(() => ({}));
|
|
284913
|
-
console.error(
|
|
285282
|
+
console.error(import_picocolors22.default.red(` Request failed (${res.status}): ${err.message ?? err.reason ?? ""}`));
|
|
284914
285283
|
process.exit(1);
|
|
284915
285284
|
}
|
|
284916
285285
|
return await res.json();
|
|
@@ -284932,11 +285301,11 @@ ${line}
|
|
|
284932
285301
|
return file;
|
|
284933
285302
|
}
|
|
284934
285303
|
function printEndpoint(e2) {
|
|
284935
|
-
const dot = e2.status === "enabled" ?
|
|
284936
|
-
const health = e2.last_error ?
|
|
284937
|
-
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}`);
|
|
284938
285307
|
console.log(
|
|
284939
|
-
|
|
285308
|
+
import_picocolors22.default.dim(
|
|
284940
285309
|
` ${e2.status} \xB7 ${e2.environment} \xB7 events ${e2.enabled_events.join(",")} \xB7 cursor ${e2.cursor ?? "\u2014"}${health}`
|
|
284941
285310
|
)
|
|
284942
285311
|
);
|
|
@@ -284948,7 +285317,7 @@ async function webhooks(argv) {
|
|
|
284948
285317
|
if (sub === "create") {
|
|
284949
285318
|
const url = positional(rest);
|
|
284950
285319
|
if (!url) {
|
|
284951
|
-
console.error(
|
|
285320
|
+
console.error(import_picocolors22.default.red(" Usage: ") + brand("ablo webhooks create <url>"));
|
|
284952
285321
|
process.exit(1);
|
|
284953
285322
|
}
|
|
284954
285323
|
const apiKey = requireKey3(mode);
|
|
@@ -284960,8 +285329,8 @@ async function webhooks(argv) {
|
|
|
284960
285329
|
});
|
|
284961
285330
|
const file = writeSecretToEnv(created.secret);
|
|
284962
285331
|
console.log(`
|
|
284963
|
-
${
|
|
284964
|
-
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)")}
|
|
284965
285334
|
`);
|
|
284966
285335
|
return;
|
|
284967
285336
|
}
|
|
@@ -284969,7 +285338,7 @@ async function webhooks(argv) {
|
|
|
284969
285338
|
const apiKey = requireKey3(mode);
|
|
284970
285339
|
const { data } = await api(apiKey, "GET", "");
|
|
284971
285340
|
if (data.length === 0) {
|
|
284972
|
-
console.log(
|
|
285341
|
+
console.log(import_picocolors22.default.dim(" No webhook endpoints. ") + brand("ablo webhooks create <url>"));
|
|
284973
285342
|
return;
|
|
284974
285343
|
}
|
|
284975
285344
|
console.log();
|
|
@@ -284980,40 +285349,40 @@ async function webhooks(argv) {
|
|
|
284980
285349
|
if (sub === "roll") {
|
|
284981
285350
|
const id = positional(rest);
|
|
284982
285351
|
if (!id) {
|
|
284983
|
-
console.error(
|
|
285352
|
+
console.error(import_picocolors22.default.red(" Usage: ") + brand("ablo webhooks roll <id>"));
|
|
284984
285353
|
process.exit(1);
|
|
284985
285354
|
}
|
|
284986
285355
|
const apiKey = requireKey3(mode);
|
|
284987
285356
|
const rolled = await api(apiKey, "POST", `/${id}/roll_secret`);
|
|
284988
285357
|
const file = writeSecretToEnv(rolled.secret);
|
|
284989
285358
|
console.log(`
|
|
284990
|
-
${
|
|
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)")}
|
|
284991
285360
|
`);
|
|
284992
285361
|
return;
|
|
284993
285362
|
}
|
|
284994
285363
|
if (sub === "enable") {
|
|
284995
285364
|
const id = positional(rest);
|
|
284996
285365
|
if (!id) {
|
|
284997
|
-
console.error(
|
|
285366
|
+
console.error(import_picocolors22.default.red(" Usage: ") + brand("ablo webhooks enable <id>"));
|
|
284998
285367
|
process.exit(1);
|
|
284999
285368
|
}
|
|
285000
285369
|
const apiKey = requireKey3(mode);
|
|
285001
285370
|
const e2 = await api(apiKey, "POST", `/${id}/enable`);
|
|
285002
|
-
console.log(` ${
|
|
285371
|
+
console.log(` ${import_picocolors22.default.green("\u2713")} Re-enabled ${import_picocolors22.default.bold(e2.id)}`);
|
|
285003
285372
|
return;
|
|
285004
285373
|
}
|
|
285005
285374
|
if (sub === "rm" || sub === "delete") {
|
|
285006
285375
|
const id = positional(rest);
|
|
285007
285376
|
if (!id) {
|
|
285008
|
-
console.error(
|
|
285377
|
+
console.error(import_picocolors22.default.red(" Usage: ") + brand("ablo webhooks rm <id>"));
|
|
285009
285378
|
process.exit(1);
|
|
285010
285379
|
}
|
|
285011
285380
|
const apiKey = requireKey3(mode);
|
|
285012
285381
|
await api(apiKey, "DELETE", `/${id}`);
|
|
285013
|
-
console.log(` ${
|
|
285382
|
+
console.log(` ${import_picocolors22.default.green("\u2713")} Removed ${import_picocolors22.default.bold(id)}`);
|
|
285014
285383
|
return;
|
|
285015
285384
|
}
|
|
285016
|
-
console.log(` ${
|
|
285385
|
+
console.log(` ${import_picocolors22.default.bold("Usage:")}`);
|
|
285017
285386
|
console.log(` ${brand("ablo webhooks create <url>")} Register an endpoint; writes ${ENV_KEY}`);
|
|
285018
285387
|
console.log(` ${brand("ablo webhooks list")} List endpoints + delivery health`);
|
|
285019
285388
|
console.log(` ${brand("ablo webhooks roll <id>")} Mint a fresh signing secret`);
|
|
@@ -285024,8 +285393,8 @@ async function webhooks(argv) {
|
|
|
285024
285393
|
|
|
285025
285394
|
// src/check.ts
|
|
285026
285395
|
init_cjs_shims();
|
|
285027
|
-
var
|
|
285028
|
-
var
|
|
285396
|
+
var import_errors17 = require("@abloatai/transaction/errors");
|
|
285397
|
+
var import_picocolors23 = __toESM(require_picocolors(), 1);
|
|
285029
285398
|
init_src();
|
|
285030
285399
|
var import_schema9 = require("@abloatai/transaction/schema");
|
|
285031
285400
|
init_push();
|
|
@@ -285172,7 +285541,7 @@ function parseCheckArgs(argv) {
|
|
|
285172
285541
|
appSchema = argv[++i] ?? appSchema;
|
|
285173
285542
|
break;
|
|
285174
285543
|
default:
|
|
285175
|
-
throw new
|
|
285544
|
+
throw new import_errors17.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
|
|
285176
285545
|
}
|
|
285177
285546
|
}
|
|
285178
285547
|
return { schemaPath, exportName, appSchema };
|
|
@@ -285186,22 +285555,22 @@ function hostOf(connectionString) {
|
|
|
285186
285555
|
}
|
|
285187
285556
|
async function reportReadSubject(dbUrl) {
|
|
285188
285557
|
const host = hostOf(dbUrl);
|
|
285189
|
-
console.log(` ${
|
|
285558
|
+
console.log(` ${import_picocolors23.default.dim("reading")} ${import_picocolors23.default.bold(host ?? "your database")}`);
|
|
285190
285559
|
const effective = resolveEffectiveApiKey();
|
|
285191
285560
|
const state = await fetchDataSourceState(apiBaseUrl(), effective.key);
|
|
285192
285561
|
if (state.kind === "unknown") {
|
|
285193
285562
|
console.log(
|
|
285194
|
-
` ${
|
|
285563
|
+
` ${import_picocolors23.default.dim("ablo")} ${import_picocolors23.default.yellow("?")} ${import_picocolors23.default.dim(`couldn't ask which database Ablo reads (${state.detail})`)}
|
|
285195
285564
|
`
|
|
285196
285565
|
);
|
|
285197
285566
|
return;
|
|
285198
285567
|
}
|
|
285199
285568
|
if (state.kind === "none") {
|
|
285200
285569
|
console.log(
|
|
285201
|
-
` ${
|
|
285570
|
+
` ${import_picocolors23.default.dim("ablo")} ${import_picocolors23.default.yellow("!")} no database is registered for this plane, so Ablo does not read this one`
|
|
285202
285571
|
);
|
|
285203
285572
|
console.log(
|
|
285204
|
-
` ${
|
|
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.`)}
|
|
285205
285574
|
`
|
|
285206
285575
|
);
|
|
285207
285576
|
return;
|
|
@@ -285209,15 +285578,15 @@ async function reportReadSubject(dbUrl) {
|
|
|
285209
285578
|
const registered = [...new Set(state.hosts)];
|
|
285210
285579
|
if (host && registered.length > 0 && !registered.includes(host)) {
|
|
285211
285580
|
console.log(
|
|
285212
|
-
` ${
|
|
285581
|
+
` ${import_picocolors23.default.dim("ablo")} ${import_picocolors23.default.yellow("!")} Ablo reads ${import_picocolors23.default.bold(registered.join(", "))}`
|
|
285213
285582
|
);
|
|
285214
285583
|
console.log(
|
|
285215
|
-
` ${
|
|
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.")}
|
|
285216
285585
|
`
|
|
285217
285586
|
);
|
|
285218
285587
|
return;
|
|
285219
285588
|
}
|
|
285220
|
-
console.log(` ${
|
|
285589
|
+
console.log(` ${import_picocolors23.default.dim("ablo")} ${import_picocolors23.default.green("\u2713")} ${import_picocolors23.default.dim("reads this database")}
|
|
285221
285590
|
`);
|
|
285222
285591
|
}
|
|
285223
285592
|
async function check(argv) {
|
|
@@ -285225,20 +285594,20 @@ async function check(argv) {
|
|
|
285225
285594
|
try {
|
|
285226
285595
|
args = parseCheckArgs(argv);
|
|
285227
285596
|
} catch (err) {
|
|
285228
|
-
console.error(
|
|
285597
|
+
console.error(import_picocolors23.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
285229
285598
|
process.exit(1);
|
|
285230
285599
|
}
|
|
285231
285600
|
const dbUrl = readProjectAdminDatabaseUrl();
|
|
285232
285601
|
if (!dbUrl) {
|
|
285233
285602
|
console.error(
|
|
285234
|
-
|
|
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.`)
|
|
285235
285604
|
);
|
|
285236
285605
|
process.exit(1);
|
|
285237
285606
|
}
|
|
285238
285607
|
const schema = await loadSchema(args.schemaPath, args.exportName);
|
|
285239
285608
|
const schemaJson = JSON.parse((0, import_schema9.serializeSchema)(schema));
|
|
285240
285609
|
console.log(`
|
|
285241
|
-
${brand("ablo")} ${
|
|
285610
|
+
${brand("ablo")} ${import_picocolors23.default.dim("check")} ${import_picocolors23.default.dim(`schema "${args.appSchema}"`)}
|
|
285242
285611
|
`);
|
|
285243
285612
|
await reportReadSubject(dbUrl);
|
|
285244
285613
|
const sql = src_default(dbUrl, { max: 1, prepare: false, onnotice: () => {
|
|
@@ -285250,7 +285619,7 @@ async function check(argv) {
|
|
|
285250
285619
|
[args.appSchema]
|
|
285251
285620
|
);
|
|
285252
285621
|
} catch (err) {
|
|
285253
|
-
console.error(
|
|
285622
|
+
console.error(import_picocolors23.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
|
|
285254
285623
|
await sql.end({ timeout: 2 });
|
|
285255
285624
|
process.exit(1);
|
|
285256
285625
|
}
|
|
@@ -285272,7 +285641,7 @@ async function check(argv) {
|
|
|
285272
285641
|
declaredTables.add(table);
|
|
285273
285642
|
const present = colsByTable.get(table);
|
|
285274
285643
|
if (!present) {
|
|
285275
|
-
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")}`);
|
|
285276
285645
|
errors++;
|
|
285277
285646
|
continue;
|
|
285278
285647
|
}
|
|
@@ -285294,26 +285663,26 @@ async function check(argv) {
|
|
|
285294
285663
|
if (!present.has(col)) problems.push(`missing column "${col}" (field ${fieldName})`);
|
|
285295
285664
|
}
|
|
285296
285665
|
if (problems.length > 0) {
|
|
285297
|
-
console.log(` ${
|
|
285298
|
-
for (const p2 of problems) console.log(` ${
|
|
285299
|
-
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}`);
|
|
285300
285669
|
errors++;
|
|
285301
285670
|
} else if (warns.length > 0) {
|
|
285302
|
-
console.log(` ${
|
|
285303
|
-
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}`);
|
|
285304
285673
|
warnings++;
|
|
285305
285674
|
} else {
|
|
285306
|
-
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)`)}`);
|
|
285307
285676
|
}
|
|
285308
285677
|
}
|
|
285309
285678
|
const modelCount = Object.keys(schemaJson.models).length;
|
|
285310
285679
|
const ignored = [...colsByTable.keys()].filter((t) => !declaredTables.has(t)).length;
|
|
285311
285680
|
console.log(
|
|
285312
285681
|
`
|
|
285313
|
-
${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"}`)}` : "")
|
|
285314
285683
|
);
|
|
285315
285684
|
if (ignored > 0) {
|
|
285316
|
-
console.log(` ${
|
|
285685
|
+
console.log(` ${import_picocolors23.default.dim(`${ignored} other table${ignored === 1 ? "" : "s"} in your database \u2014 ignored by Ablo`)}`);
|
|
285317
285686
|
}
|
|
285318
285687
|
console.log();
|
|
285319
285688
|
process.exit(errors > 0 ? 1 : 0);
|
|
@@ -285324,7 +285693,7 @@ init_dbRole();
|
|
|
285324
285693
|
|
|
285325
285694
|
// src/upgrade.ts
|
|
285326
285695
|
init_cjs_shims();
|
|
285327
|
-
var
|
|
285696
|
+
var import_picocolors24 = __toESM(require_picocolors(), 1);
|
|
285328
285697
|
var import_ts_morph = __toESM(require_ts_morph(), 1);
|
|
285329
285698
|
var DEFAULT_GLOBS = ["app/**/*.{ts,tsx}", "src/**/*.{ts,tsx}", "ablo/**/*.{ts,tsx}", "lib/**/*.{ts,tsx}"];
|
|
285330
285699
|
var VERB_ARGS = {
|
|
@@ -285402,7 +285771,7 @@ async function upgrade(argv) {
|
|
|
285402
285771
|
project.addSourceFilesAtPaths(globs.length > 0 ? globs : DEFAULT_GLOBS);
|
|
285403
285772
|
const files = project.getSourceFiles();
|
|
285404
285773
|
if (files.length === 0) {
|
|
285405
|
-
console.log(
|
|
285774
|
+
console.log(import_picocolors24.default.yellow(' No .ts/.tsx files found. Pass a glob, e.g. `ablo upgrade "src/**/*.tsx"`.'));
|
|
285406
285775
|
return;
|
|
285407
285776
|
}
|
|
285408
285777
|
const edits = [];
|
|
@@ -285476,39 +285845,39 @@ async function upgrade(argv) {
|
|
|
285476
285845
|
const rel = (f) => f.replace(cwd + "/", "");
|
|
285477
285846
|
console.log();
|
|
285478
285847
|
if (edits.length === 0 && manual.length === 0) {
|
|
285479
|
-
console.log(
|
|
285848
|
+
console.log(import_picocolors24.default.green(" \u2713 Nothing to migrate \u2014 your code is already on the current API."));
|
|
285480
285849
|
return;
|
|
285481
285850
|
}
|
|
285482
285851
|
if (edits.length > 0) {
|
|
285483
|
-
console.log(
|
|
285852
|
+
console.log(import_picocolors24.default.bold(` ${write ? "Applied" : "Would apply"} ${edits.length} change${edits.length === 1 ? "" : "s"}:`));
|
|
285484
285853
|
for (const e2 of edits) {
|
|
285485
|
-
console.log(` ${
|
|
285486
|
-
console.log(` ${
|
|
285487
|
-
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}`);
|
|
285488
285857
|
}
|
|
285489
285858
|
}
|
|
285490
285859
|
if (manual.length > 0) {
|
|
285491
285860
|
console.log();
|
|
285492
|
-
console.log(
|
|
285861
|
+
console.log(import_picocolors24.default.bold(import_picocolors24.default.yellow(` ${manual.length} spot${manual.length === 1 ? "" : "s"} need manual review (structural):`)));
|
|
285493
285862
|
for (const m2 of manual) {
|
|
285494
|
-
console.log(` ${
|
|
285495
|
-
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)}`);
|
|
285496
285865
|
console.log(` \u2192 ${m2.hint}`);
|
|
285497
285866
|
}
|
|
285498
285867
|
}
|
|
285499
285868
|
console.log();
|
|
285500
285869
|
if (write) {
|
|
285501
285870
|
await project.save();
|
|
285502
|
-
console.log(
|
|
285871
|
+
console.log(import_picocolors24.default.green(` \u2713 Wrote ${edits.length} change${edits.length === 1 ? "" : "s"}. Review the diff, run your typecheck.`));
|
|
285503
285872
|
} else {
|
|
285504
|
-
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)."));
|
|
285505
285874
|
}
|
|
285506
285875
|
}
|
|
285507
285876
|
|
|
285508
285877
|
// src/pull.ts
|
|
285509
285878
|
init_cjs_shims();
|
|
285510
|
-
var
|
|
285511
|
-
var
|
|
285879
|
+
var import_errors18 = require("@abloatai/transaction/errors");
|
|
285880
|
+
var import_picocolors25 = __toESM(require_picocolors(), 1);
|
|
285512
285881
|
init_src();
|
|
285513
285882
|
var import_fs10 = require("fs");
|
|
285514
285883
|
init_theme();
|
|
@@ -285536,7 +285905,7 @@ function parsePullArgs(argv) {
|
|
|
285536
285905
|
force = true;
|
|
285537
285906
|
break;
|
|
285538
285907
|
default:
|
|
285539
|
-
throw new
|
|
285908
|
+
throw new import_errors18.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
|
|
285540
285909
|
}
|
|
285541
285910
|
}
|
|
285542
285911
|
return { out, appSchema, importPath, force };
|
|
@@ -285606,56 +285975,56 @@ async function pull(argv) {
|
|
|
285606
285975
|
try {
|
|
285607
285976
|
args = parsePullArgs(argv);
|
|
285608
285977
|
} catch (err) {
|
|
285609
|
-
console.error(
|
|
285978
|
+
console.error(import_picocolors25.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
285610
285979
|
process.exit(1);
|
|
285611
285980
|
}
|
|
285612
285981
|
const dbUrl = readProjectAdminDatabaseUrl();
|
|
285613
285982
|
if (!dbUrl) {
|
|
285614
285983
|
console.error(
|
|
285615
|
-
|
|
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.`)
|
|
285616
285985
|
);
|
|
285617
285986
|
process.exit(1);
|
|
285618
285987
|
}
|
|
285619
285988
|
if ((0, import_fs10.existsSync)(args.out) && !args.force) {
|
|
285620
285989
|
console.error(
|
|
285621
|
-
|
|
285990
|
+
import_picocolors25.default.red(` ${args.out} already exists.`) + import_picocolors25.default.dim(` Re-run with ${import_picocolors25.default.bold("--force")} to overwrite.`)
|
|
285622
285991
|
);
|
|
285623
285992
|
process.exit(1);
|
|
285624
285993
|
}
|
|
285625
285994
|
console.log(`
|
|
285626
|
-
${brand("ablo")} ${
|
|
285995
|
+
${brand("ablo")} ${import_picocolors25.default.dim("pull")} ${import_picocolors25.default.dim(`schema "${args.appSchema}"`)}
|
|
285627
285996
|
`);
|
|
285628
285997
|
let result;
|
|
285629
285998
|
try {
|
|
285630
285999
|
result = await buildSchemaSourceFromDb({ dbUrl, appSchema: args.appSchema, importPath: args.importPath });
|
|
285631
286000
|
} catch (err) {
|
|
285632
|
-
console.error(
|
|
286001
|
+
console.error(import_picocolors25.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
|
|
285633
286002
|
process.exit(1);
|
|
285634
286003
|
}
|
|
285635
286004
|
if (result.models.length === 0) {
|
|
285636
286005
|
console.error(
|
|
285637
|
-
|
|
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).`)
|
|
285638
286007
|
);
|
|
285639
286008
|
process.exit(1);
|
|
285640
286009
|
}
|
|
285641
286010
|
(0, import_fs10.writeFileSync)(args.out, result.source);
|
|
285642
|
-
console.log(` ${
|
|
285643
|
-
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(", ")}`)}`);
|
|
285644
286013
|
if (result.skipped.length > 0) {
|
|
285645
|
-
console.log(` ${
|
|
285646
|
-
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}`)}`);
|
|
285647
286016
|
}
|
|
285648
286017
|
console.log(
|
|
285649
286018
|
`
|
|
285650
|
-
${
|
|
286019
|
+
${import_picocolors25.default.dim("Introspection is lossy (enums, JSON shape, relations). Review the file, then")} ${import_picocolors25.default.bold("ablo check")}.
|
|
285651
286020
|
`
|
|
285652
286021
|
);
|
|
285653
286022
|
}
|
|
285654
286023
|
|
|
285655
286024
|
// src/prismaPull.ts
|
|
285656
286025
|
init_cjs_shims();
|
|
285657
|
-
var
|
|
285658
|
-
var
|
|
286026
|
+
var import_errors19 = require("@abloatai/transaction/errors");
|
|
286027
|
+
var import_picocolors26 = __toESM(require_picocolors(), 1);
|
|
285659
286028
|
var import_fs11 = require("fs");
|
|
285660
286029
|
init_theme();
|
|
285661
286030
|
var DEFAULT_SCHEMA = "prisma/schema.prisma";
|
|
@@ -285852,7 +286221,7 @@ function parsePrismaPullArgs(argv) {
|
|
|
285852
286221
|
force = true;
|
|
285853
286222
|
break;
|
|
285854
286223
|
default:
|
|
285855
|
-
if (arg.startsWith("--")) throw new
|
|
286224
|
+
if (arg.startsWith("--")) throw new import_errors19.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
|
|
285856
286225
|
schema = arg;
|
|
285857
286226
|
}
|
|
285858
286227
|
}
|
|
@@ -285863,56 +286232,56 @@ async function prismaPull(argv) {
|
|
|
285863
286232
|
try {
|
|
285864
286233
|
args = parsePrismaPullArgs(argv);
|
|
285865
286234
|
} catch (err) {
|
|
285866
|
-
console.error(
|
|
286235
|
+
console.error(import_picocolors26.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
285867
286236
|
process.exit(1);
|
|
285868
286237
|
}
|
|
285869
286238
|
if (!(0, import_fs11.existsSync)(args.schema)) {
|
|
285870
286239
|
console.error(
|
|
285871
|
-
|
|
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>")}.`)
|
|
285872
286241
|
);
|
|
285873
286242
|
process.exit(1);
|
|
285874
286243
|
}
|
|
285875
286244
|
if ((0, import_fs11.existsSync)(args.out) && !args.force) {
|
|
285876
286245
|
console.error(
|
|
285877
|
-
|
|
286246
|
+
import_picocolors26.default.red(` ${args.out} already exists.`) + import_picocolors26.default.dim(` Re-run with ${import_picocolors26.default.bold("--force")} to overwrite.`)
|
|
285878
286247
|
);
|
|
285879
286248
|
process.exit(1);
|
|
285880
286249
|
}
|
|
285881
286250
|
console.log(`
|
|
285882
|
-
${brand("ablo")} ${
|
|
286251
|
+
${brand("ablo")} ${import_picocolors26.default.dim("pull prisma")} ${import_picocolors26.default.dim(args.schema)}
|
|
285883
286252
|
`);
|
|
285884
286253
|
let result;
|
|
285885
286254
|
try {
|
|
285886
286255
|
const src = (0, import_fs11.readFileSync)(args.schema, "utf8");
|
|
285887
286256
|
result = buildSchemaSourceFromPrisma({ src, importPath: args.importPath });
|
|
285888
286257
|
} catch (err) {
|
|
285889
|
-
console.error(
|
|
286258
|
+
console.error(import_picocolors26.default.red(` Couldn't parse the schema: ${err instanceof Error ? err.message : String(err)}`));
|
|
285890
286259
|
process.exit(1);
|
|
285891
286260
|
}
|
|
285892
286261
|
if (result.models.length === 0) {
|
|
285893
286262
|
console.error(
|
|
285894
|
-
|
|
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")}).`)
|
|
285895
286264
|
);
|
|
285896
286265
|
process.exit(1);
|
|
285897
286266
|
}
|
|
285898
286267
|
(0, import_fs11.writeFileSync)(args.out, result.source);
|
|
285899
|
-
console.log(` ${
|
|
285900
|
-
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(", ")}`)}`);
|
|
285901
286270
|
if (result.skipped.length > 0) {
|
|
285902
|
-
console.log(` ${
|
|
285903
|
-
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}`)}`);
|
|
285904
286273
|
}
|
|
285905
286274
|
console.log(
|
|
285906
286275
|
`
|
|
285907
|
-
${
|
|
286276
|
+
${import_picocolors26.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors26.default.bold("ablo check")}.
|
|
285908
286277
|
`
|
|
285909
286278
|
);
|
|
285910
286279
|
}
|
|
285911
286280
|
|
|
285912
286281
|
// src/drizzlePull.ts
|
|
285913
286282
|
init_cjs_shims();
|
|
285914
|
-
var
|
|
285915
|
-
var
|
|
286283
|
+
var import_picocolors27 = __toESM(require_picocolors(), 1);
|
|
286284
|
+
var import_errors20 = require("@abloatai/transaction/errors");
|
|
285916
286285
|
var import_fs12 = require("fs");
|
|
285917
286286
|
var import_path7 = require("path");
|
|
285918
286287
|
init_theme();
|
|
@@ -286019,7 +286388,7 @@ function parseDrizzlePullArgs(argv) {
|
|
|
286019
286388
|
force = true;
|
|
286020
286389
|
break;
|
|
286021
286390
|
default:
|
|
286022
|
-
if (arg.startsWith("--")) throw new
|
|
286391
|
+
if (arg.startsWith("--")) throw new import_errors20.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
|
|
286023
286392
|
schema = arg;
|
|
286024
286393
|
}
|
|
286025
286394
|
}
|
|
@@ -286036,27 +286405,27 @@ async function drizzlePull(argv) {
|
|
|
286036
286405
|
try {
|
|
286037
286406
|
args = parseDrizzlePullArgs(argv);
|
|
286038
286407
|
} catch (err) {
|
|
286039
|
-
console.error(
|
|
286408
|
+
console.error(import_picocolors27.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
286040
286409
|
process.exit(1);
|
|
286041
286410
|
}
|
|
286042
286411
|
if (!args.schema) {
|
|
286043
286412
|
console.error(
|
|
286044
|
-
|
|
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")}.`)
|
|
286045
286414
|
);
|
|
286046
286415
|
process.exit(1);
|
|
286047
286416
|
}
|
|
286048
286417
|
if (!(0, import_fs12.existsSync)(args.schema)) {
|
|
286049
|
-
console.error(
|
|
286418
|
+
console.error(import_picocolors27.default.red(` No file at ${import_picocolors27.default.bold(args.schema)}.`));
|
|
286050
286419
|
process.exit(1);
|
|
286051
286420
|
}
|
|
286052
286421
|
if ((0, import_fs12.existsSync)(args.out) && !args.force) {
|
|
286053
286422
|
console.error(
|
|
286054
|
-
|
|
286423
|
+
import_picocolors27.default.red(` ${args.out} already exists.`) + import_picocolors27.default.dim(` Re-run with ${import_picocolors27.default.bold("--force")} to overwrite.`)
|
|
286055
286424
|
);
|
|
286056
286425
|
process.exit(1);
|
|
286057
286426
|
}
|
|
286058
286427
|
console.log(`
|
|
286059
|
-
${brand("ablo")} ${
|
|
286428
|
+
${brand("ablo")} ${import_picocolors27.default.dim("pull drizzle")} ${import_picocolors27.default.dim(args.schema)}
|
|
286060
286429
|
`);
|
|
286061
286430
|
let result;
|
|
286062
286431
|
try {
|
|
@@ -286064,26 +286433,26 @@ async function drizzlePull(argv) {
|
|
|
286064
286433
|
result = await buildSchemaSourceFromDrizzle({ mod, importPath: args.importPath });
|
|
286065
286434
|
} catch (err) {
|
|
286066
286435
|
const msg = err instanceof Error ? err.message : String(err);
|
|
286067
|
-
const hint = msg.includes("Cannot find package 'drizzle-orm'") ?
|
|
286068
|
-
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);
|
|
286069
286438
|
process.exit(1);
|
|
286070
286439
|
}
|
|
286071
286440
|
if (result.models.length === 0) {
|
|
286072
286441
|
console.error(
|
|
286073
|
-
|
|
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).`)
|
|
286074
286443
|
);
|
|
286075
286444
|
process.exit(1);
|
|
286076
286445
|
}
|
|
286077
286446
|
(0, import_fs12.writeFileSync)(args.out, result.source);
|
|
286078
|
-
console.log(` ${
|
|
286079
|
-
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(", ")}`)}`);
|
|
286080
286449
|
if (result.skipped.length > 0) {
|
|
286081
|
-
console.log(` ${
|
|
286082
|
-
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}`)}`);
|
|
286083
286452
|
}
|
|
286084
286453
|
console.log(
|
|
286085
286454
|
`
|
|
286086
|
-
${
|
|
286455
|
+
${import_picocolors27.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors27.default.bold("ablo check")}.
|
|
286087
286456
|
`
|
|
286088
286457
|
);
|
|
286089
286458
|
}
|
|
@@ -286169,7 +286538,7 @@ async function getCurrentUser(): Promise<{ id: string } | null> {
|
|
|
286169
286538
|
|
|
286170
286539
|
// src/index.ts
|
|
286171
286540
|
var LOGO = `
|
|
286172
|
-
${brand("ablo")} ${
|
|
286541
|
+
${brand("ablo")} ${import_picocolors28.default.dim("sync engine")}
|
|
286173
286542
|
`;
|
|
286174
286543
|
var HANDLERS = {
|
|
286175
286544
|
init: (argv) => init([...argv]),
|
|
@@ -286178,6 +286547,7 @@ var HANDLERS = {
|
|
|
286178
286547
|
projects: (argv) => projects([...argv]),
|
|
286179
286548
|
branch: (argv) => branches([...argv]),
|
|
286180
286549
|
status: (argv) => status([...argv]),
|
|
286550
|
+
whoami: (argv) => whoami([...argv]),
|
|
286181
286551
|
doctor: () => doctor(),
|
|
286182
286552
|
logs: (argv) => logs([...argv]),
|
|
286183
286553
|
webhooks: (argv) => webhooks([...argv]),
|
|
@@ -286196,7 +286566,7 @@ async function runDev(argv) {
|
|
|
286196
286566
|
const devArgs = [...argv];
|
|
286197
286567
|
const oneShot = devArgs.includes("--no-watch");
|
|
286198
286568
|
console.log(
|
|
286199
|
-
|
|
286569
|
+
import_picocolors28.default.dim(
|
|
286200
286570
|
oneShot ? " `ablo dev --no-watch` prepares this Git branch and pushes once." : " `ablo dev` prepares this Git branch and watches the schema."
|
|
286201
286571
|
)
|
|
286202
286572
|
);
|
|
@@ -286217,13 +286587,13 @@ async function runPush2(argv) {
|
|
|
286217
286587
|
const guard = guardActiveProjectKey();
|
|
286218
286588
|
if (!guard.ok && guard.available.length > 0 && !rest.includes("--url")) {
|
|
286219
286589
|
console.error(
|
|
286220
|
-
` ${
|
|
286590
|
+
` ${import_picocolors28.default.yellow("\u26A0")} active project ${import_picocolors28.default.bold(guard.activeProfile)} has no stored key ${import_picocolors28.default.dim(
|
|
286221
286591
|
`(you have keys for: ${guard.available.join(", ")})`
|
|
286222
286592
|
)}`
|
|
286223
286593
|
);
|
|
286224
286594
|
const loginCmd = guard.activeProfile === "default" ? "ablo login" : `ablo login --project ${guard.activeProfile}`;
|
|
286225
286595
|
console.error(
|
|
286226
|
-
|
|
286596
|
+
import_picocolors28.default.dim(` Mint one with ${import_picocolors28.default.bold(loginCmd)}, or switch with ${import_picocolors28.default.bold("ablo projects use <slug>")}.`)
|
|
286227
286597
|
);
|
|
286228
286598
|
process.exitCode = 1;
|
|
286229
286599
|
return;
|
|
@@ -286234,13 +286604,21 @@ async function runPush2(argv) {
|
|
|
286234
286604
|
}
|
|
286235
286605
|
function runRenamedSchema(argv) {
|
|
286236
286606
|
const forwarded = argv.slice(1).join(" ");
|
|
286237
|
-
console.error(` ${
|
|
286607
|
+
console.error(` ${import_picocolors28.default.red("\u2717")} \`ablo schema push\` was renamed to \`${brand("ablo push")}\`.`);
|
|
286238
286608
|
console.error(` Run \`ablo push${forwarded ? " " + forwarded : ""}\` instead.`);
|
|
286239
286609
|
process.exitCode = 1;
|
|
286240
286610
|
}
|
|
286241
286611
|
async function main() {
|
|
286242
|
-
const
|
|
286612
|
+
const raw = process.argv[2];
|
|
286613
|
+
const command = parseCommandName(raw);
|
|
286243
286614
|
const argv = process.argv.slice(3);
|
|
286615
|
+
if (!command && raw !== void 0 && raw !== "help" && !raw.startsWith("-")) {
|
|
286616
|
+
const suggestion = suggestCommand(raw);
|
|
286617
|
+
throw new import_errors21.AbloValidationError(
|
|
286618
|
+
`\`${raw}\` isn't an ablo command.` + (suggestion ? ` Did you mean \`ablo ${suggestion}\`?` : " Run `ablo help --all` to see every command."),
|
|
286619
|
+
{ code: "cli_invalid_arguments" }
|
|
286620
|
+
);
|
|
286621
|
+
}
|
|
286244
286622
|
if (command && argv.some((a) => a === "--help" || a === "-h")) {
|
|
286245
286623
|
const usage = usageFor(command);
|
|
286246
286624
|
if (usage) {
|
|
@@ -286267,7 +286645,7 @@ function printCoreHelp() {
|
|
|
286267
286645
|
const width = Math.max(...rows.map((r2) => r2.run.length)) + 4;
|
|
286268
286646
|
console.log(LOGO);
|
|
286269
286647
|
for (const group of CORE_GROUPS) {
|
|
286270
|
-
console.log(` ${
|
|
286648
|
+
console.log(` ${import_picocolors28.default.bold(group)}`);
|
|
286271
286649
|
const printed = group === "More" ? [...coreRows(group), ...extra] : coreRows(group);
|
|
286272
286650
|
for (const row of printed) console.log(` npx ablo ${row.run.padEnd(width)}${row.does}`);
|
|
286273
286651
|
console.log();
|
|
@@ -286276,7 +286654,7 @@ function printCoreHelp() {
|
|
|
286276
286654
|
}
|
|
286277
286655
|
function printSchemaReminder() {
|
|
286278
286656
|
console.log(
|
|
286279
|
-
|
|
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(".")
|
|
286280
286658
|
);
|
|
286281
286659
|
console.log();
|
|
286282
286660
|
}
|
|
@@ -286286,7 +286664,7 @@ function printFullHelp() {
|
|
|
286286
286664
|
) + 2;
|
|
286287
286665
|
console.log(LOGO);
|
|
286288
286666
|
for (const group of FULL_GROUPS) {
|
|
286289
|
-
console.log(` ${
|
|
286667
|
+
console.log(` ${import_picocolors28.default.bold(group)}`);
|
|
286290
286668
|
for (const row of fullRows(group)) {
|
|
286291
286669
|
console.log(row.does === void 0 ? ` ${" ".repeat(9)}${row.run}` : ` npx ablo ${row.run.padEnd(width)}${row.does}`);
|
|
286292
286670
|
}
|
|
@@ -286341,7 +286719,7 @@ async function ensureInitProject(opts) {
|
|
|
286341
286719
|
const ensured = await ensureProject(slug);
|
|
286342
286720
|
if (ensured) {
|
|
286343
286721
|
console.log(
|
|
286344
|
-
` ${
|
|
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.`
|
|
286345
286723
|
);
|
|
286346
286724
|
}
|
|
286347
286725
|
}
|
|
@@ -286383,7 +286761,7 @@ async function chooseBool(flagValue, fallback, interactive, prompt) {
|
|
|
286383
286761
|
async function init(args = []) {
|
|
286384
286762
|
const opts = parseInitArgs(args);
|
|
286385
286763
|
const interactive = Boolean(process.stdin.isTTY) && !opts.yes && !process.env.CI;
|
|
286386
|
-
Ie(`${brand("ablo")} ${
|
|
286764
|
+
Ie(`${brand("ablo")} ${import_picocolors28.default.dim("sync engine")}`);
|
|
286387
286765
|
if (!(0, import_fs13.existsSync)("package.json")) {
|
|
286388
286766
|
xe("No package.json found. Run this from your project root.");
|
|
286389
286767
|
process.exit(1);
|
|
@@ -286461,7 +286839,7 @@ async function init(args = []) {
|
|
|
286461
286839
|
if (pullExisting) {
|
|
286462
286840
|
const dbUrl = readProjectAdminDatabaseUrl();
|
|
286463
286841
|
if (!dbUrl) {
|
|
286464
|
-
schemaNote =
|
|
286842
|
+
schemaNote = import_picocolors28.default.dim(` (no ${ADMIN_URL_VAR} \u2014 wrote starter; run \`ablo pull\` later)`);
|
|
286465
286843
|
} else {
|
|
286466
286844
|
try {
|
|
286467
286845
|
const pulled = await buildSchemaSourceFromDb({
|
|
@@ -286471,12 +286849,12 @@ async function init(args = []) {
|
|
|
286471
286849
|
});
|
|
286472
286850
|
if (pulled.models.length > 0) {
|
|
286473
286851
|
schemaSource = pulled.source;
|
|
286474
|
-
schemaNote =
|
|
286852
|
+
schemaNote = import_picocolors28.default.dim(` (pulled ${pulled.models.length} models)`);
|
|
286475
286853
|
} else {
|
|
286476
|
-
schemaNote =
|
|
286854
|
+
schemaNote = import_picocolors28.default.dim(" (no adoptable tables \u2014 wrote starter)");
|
|
286477
286855
|
}
|
|
286478
286856
|
} catch {
|
|
286479
|
-
schemaNote =
|
|
286857
|
+
schemaNote = import_picocolors28.default.dim(" (pull failed \u2014 wrote starter)");
|
|
286480
286858
|
}
|
|
286481
286859
|
}
|
|
286482
286860
|
}
|
|
@@ -286500,9 +286878,9 @@ async function init(args = []) {
|
|
|
286500
286878
|
const existing = (0, import_fs13.readFileSync)(envFile, "utf-8");
|
|
286501
286879
|
if (!existing.includes("ABLO_")) {
|
|
286502
286880
|
(0, import_fs13.writeFileSync)(envFile, existing + "\n" + envBody);
|
|
286503
|
-
created.push(`${envFile} ${
|
|
286881
|
+
created.push(`${envFile} ${import_picocolors28.default.dim("(appended)")}`);
|
|
286504
286882
|
} else {
|
|
286505
|
-
created.push(`${envFile} ${
|
|
286883
|
+
created.push(`${envFile} ${import_picocolors28.default.dim("(already configured)")}`);
|
|
286506
286884
|
}
|
|
286507
286885
|
}
|
|
286508
286886
|
if (agent) {
|
|
@@ -286518,17 +286896,17 @@ async function init(args = []) {
|
|
|
286518
286896
|
}
|
|
286519
286897
|
const providersPath = (0, import_path8.join)(layout.appBase, "providers.tsx");
|
|
286520
286898
|
(0, import_fs13.writeFileSync)(providersPath, generateProviders());
|
|
286521
|
-
created.push(`${providersPath} ${
|
|
286899
|
+
created.push(`${providersPath} ${import_picocolors28.default.dim(`(wrap ${(0, import_path8.join)(layout.appBase, "layout.tsx")} in <Providers>)`)}`);
|
|
286522
286900
|
const sessionDir = (0, import_path8.join)(layout.appBase, "api", "ablo-session");
|
|
286523
286901
|
(0, import_fs13.mkdirSync)(sessionDir, { recursive: true });
|
|
286524
286902
|
(0, import_fs13.writeFileSync)((0, import_path8.join)(sessionDir, "route.ts"), generateSessionRoute());
|
|
286525
|
-
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)")}`);
|
|
286526
286904
|
}
|
|
286527
286905
|
if (framework !== "vanilla") {
|
|
286528
286906
|
(0, import_fs13.writeFileSync)((0, import_path8.join)(abloDir, "TaskList.tsx"), generateComponent());
|
|
286529
286907
|
created.push(`${abloDir}/TaskList.tsx`);
|
|
286530
286908
|
}
|
|
286531
|
-
Me(created.map((f) => `${
|
|
286909
|
+
Me(created.map((f) => `${import_picocolors28.default.green("\u2713")} ${f}`).join("\n"), "Created");
|
|
286532
286910
|
const pm = detectPackageManager();
|
|
286533
286911
|
if (opts.install) {
|
|
286534
286912
|
const s = Y2();
|
|
@@ -286537,46 +286915,46 @@ async function init(args = []) {
|
|
|
286537
286915
|
(0, import_child_process3.execSync)(`${pm} add @abloatai/ablo`, { stdio: "ignore" });
|
|
286538
286916
|
s.stop("Installed @abloatai/ablo");
|
|
286539
286917
|
} catch {
|
|
286540
|
-
s.stop(`${
|
|
286918
|
+
s.stop(`${import_picocolors28.default.yellow("!")} Couldn't auto-install \u2014 run ${import_picocolors28.default.bold(`${pm} install @abloatai/ablo`)}`);
|
|
286541
286919
|
}
|
|
286542
286920
|
}
|
|
286543
286921
|
const steps = [
|
|
286544
|
-
`Run ${
|
|
286545
|
-
`Set ${
|
|
286546
|
-
`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`,
|
|
286547
286925
|
...storage === "replication" ? [
|
|
286548
|
-
`Connect your database \u2014 ${
|
|
286549
|
-
`Verify it \u2014 ${
|
|
286550
|
-
`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`
|
|
286551
286929
|
] : [
|
|
286552
|
-
`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")}`
|
|
286553
286931
|
],
|
|
286554
286932
|
...framework === "nextjs" ? [
|
|
286555
|
-
`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"))}`
|
|
286556
286934
|
] : [],
|
|
286557
|
-
`Run ${
|
|
286935
|
+
`Run ${import_picocolors28.default.bold(`${pm} run dev`)} and open two browser tabs \u2014 changes sync in real-time`,
|
|
286558
286936
|
...agent ? [
|
|
286559
|
-
`Run ${
|
|
286560
|
-
`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`
|
|
286561
286939
|
] : []
|
|
286562
286940
|
];
|
|
286563
286941
|
Me(steps.map((s, i) => `${i + 1}. ${s}`).join("\n"), "Next steps");
|
|
286564
286942
|
const existingKey = resolveManagementKey();
|
|
286565
286943
|
if (existingKey) {
|
|
286566
286944
|
await ensureInitProject(opts);
|
|
286567
|
-
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`);
|
|
286568
286946
|
return;
|
|
286569
286947
|
}
|
|
286570
286948
|
if (interactive && opts.login) {
|
|
286571
286949
|
const loginNow = await ye({ message: "Log in now? (opens your browser)", initialValue: true });
|
|
286572
286950
|
if (!pD(loginNow) && loginNow) {
|
|
286573
|
-
Se(`${
|
|
286951
|
+
Se(`${import_picocolors28.default.dim("Docs:")} https://abloatai.com/docs`);
|
|
286574
286952
|
await login();
|
|
286575
286953
|
await ensureInitProject(opts);
|
|
286576
286954
|
return;
|
|
286577
286955
|
}
|
|
286578
286956
|
}
|
|
286579
|
-
Se(`Run ${
|
|
286957
|
+
Se(`Run ${import_picocolors28.default.bold("npx ablo login")} when ready. ${import_picocolors28.default.dim("Docs:")} https://abloatai.com/docs`);
|
|
286580
286958
|
}
|
|
286581
286959
|
function generateSchema() {
|
|
286582
286960
|
return `import { defineSchema, model, relation, z } from '@abloatai/ablo/schema';
|