@abloatai/ablo 0.9.5 → 0.9.7
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/CHANGELOG.md +12 -0
- package/README.md +3 -3
- package/dist/cli.cjs +421 -376
- package/dist/client/Ablo.d.ts +9 -0
- package/dist/client/Ablo.js +6 -4
- package/dist/client/createModelProxy.d.ts +8 -0
- package/dist/client/createModelProxy.js +31 -11
- package/dist/errorCodes.js +15 -6
- package/dist/sync/SyncWebSocket.d.ts +13 -0
- package/dist/sync/SyncWebSocket.js +28 -4
- package/dist/sync/awaitIntentGrant.d.ts +15 -1
- package/dist/sync/awaitIntentGrant.js +9 -7
- package/dist/transactions/TransactionQueue.js +39 -12
- package/docs/quickstart.md +29 -17
- package/llms-full.txt +1 -1
- package/llms.txt +3 -3
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -276700,8 +276700,8 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
|
|
|
276700
276700
|
};
|
|
276701
276701
|
|
|
276702
276702
|
// src/cli/index.ts
|
|
276703
|
-
var
|
|
276704
|
-
var
|
|
276703
|
+
var import_picocolors17 = __toESM(require_picocolors(), 1);
|
|
276704
|
+
var import_fs12 = require("fs");
|
|
276705
276705
|
var import_path7 = require("path");
|
|
276706
276706
|
var import_child_process2 = require("child_process");
|
|
276707
276707
|
|
|
@@ -276787,13 +276787,22 @@ var ERROR_CODES = {
|
|
|
276787
276787
|
byo_tenant_tables_unforced_rls: wire("permission", 403, false, "Tenant tables do not have RLS forced under the direct Postgres connector role."),
|
|
276788
276788
|
byo_host_not_allowed: wire("permission", 403, false, "The direct Postgres connector host resolves to a private, loopback, or link-local address and cannot be used."),
|
|
276789
276789
|
// ── claim / intent conflict (409) ──────────────────────────────────
|
|
276790
|
-
|
|
276791
|
-
|
|
276792
|
-
|
|
276793
|
-
|
|
276790
|
+
// Held-claim rejections are NOT queue-retryable (gRPC FAILED_PRECONDITION /
|
|
276791
|
+
// ABORTED semantics; Replicache/Zero SETTLE a rejected mutation — reject the
|
|
276792
|
+
// caller, roll back the optimistic effect — instead of resending it).
|
|
276793
|
+
// Blindly re-sending the same payload cannot succeed while the lease is
|
|
276794
|
+
// held, and a lease can outlive any sane retry budget. The correct recovery
|
|
276795
|
+
// lives at the CALLER: take a claim (`ablo.<model>.claim` queues fairly
|
|
276796
|
+
// behind the holder) or re-read and rebase. `retryable: true` here turned
|
|
276797
|
+
// every cross-client claim conflict into an infinite client resend loop
|
|
276798
|
+
// (~150ms storm — found by the claims journey, 2026-06-10).
|
|
276799
|
+
claim_conflict: wire("claim", 409, false, "The target entity is claimed by another participant."),
|
|
276800
|
+
claim_lost: wire("claim", 409, false, "A previously held claim was lost before the write applied."),
|
|
276801
|
+
entity_claimed: wire("claim", 409, false, "The target entity is currently claimed; write was blocked."),
|
|
276802
|
+
intent_conflict: wire("claim", 409, false, "An intent on the target conflicts with an active intent (server-internal alias of claim_conflict)."),
|
|
276794
276803
|
malformed_claim: wire("claim", 400, false, "The claim payload was malformed."),
|
|
276795
|
-
model_claimed: wire("claim", 409,
|
|
276796
|
-
model_claimed_timeout: wire("claim", 409,
|
|
276804
|
+
model_claimed: wire("claim", 409, false, "The model instance is claimed by another participant."),
|
|
276805
|
+
model_claimed_timeout: wire("claim", 409, false, "Timed out waiting for a model claim to clear."),
|
|
276797
276806
|
model_claim_not_configured: client("claim", "Claiming was requested on a model that has no claim configuration."),
|
|
276798
276807
|
// ── stale context / idempotency (409) ──────────────────────────────
|
|
276799
276808
|
stale_context: wire("conflict", 409, true, "The write carried a readAt watermark that is now stale; re-read and retry."),
|
|
@@ -277088,9 +277097,8 @@ var ErrorBodyShapeSchema = import_zod2.z.object({
|
|
|
277088
277097
|
}).passthrough();
|
|
277089
277098
|
|
|
277090
277099
|
// src/cli/migrate.ts
|
|
277091
|
-
var
|
|
277092
|
-
var
|
|
277093
|
-
var import_path3 = require("path");
|
|
277100
|
+
var import_picocolors4 = __toESM(require_picocolors(), 1);
|
|
277101
|
+
var import_fs5 = require("fs");
|
|
277094
277102
|
|
|
277095
277103
|
// node_modules/postgres/src/index.js
|
|
277096
277104
|
init_cjs_shims();
|
|
@@ -279229,6 +279237,9 @@ function osUsername() {
|
|
|
279229
279237
|
// src/cli/dbRole.ts
|
|
279230
279238
|
init_cjs_shims();
|
|
279231
279239
|
var import_crypto2 = require("crypto");
|
|
279240
|
+
var import_picocolors2 = __toESM(require_picocolors(), 1);
|
|
279241
|
+
var import_fs2 = require("fs");
|
|
279242
|
+
var import_path = require("path");
|
|
279232
279243
|
var DEFAULT_SCOPED_ROLE = "ablo_app";
|
|
279233
279244
|
async function detectRoleSafety(sql) {
|
|
279234
279245
|
const rows = await sql`SELECT rolname, rolsuper, rolbypassrls FROM pg_roles WHERE rolname = current_user`;
|
|
@@ -279300,6 +279311,94 @@ async function createScopedRole(ownerUrl, options) {
|
|
|
279300
279311
|
}
|
|
279301
279312
|
return { role, databaseUrl: rewriteDatabaseUrl(ownerUrl, role, password) };
|
|
279302
279313
|
}
|
|
279314
|
+
async function ensureScopedRoleInteractive(dbUrl) {
|
|
279315
|
+
let safety;
|
|
279316
|
+
try {
|
|
279317
|
+
const sql = src_default(dbUrl, { max: 1, prepare: false, onnotice: () => {
|
|
279318
|
+
} });
|
|
279319
|
+
try {
|
|
279320
|
+
safety = await detectRoleSafety(sql);
|
|
279321
|
+
} finally {
|
|
279322
|
+
await sql.end({ timeout: 5 });
|
|
279323
|
+
}
|
|
279324
|
+
} catch {
|
|
279325
|
+
return dbUrl;
|
|
279326
|
+
}
|
|
279327
|
+
if (!safety.unsafe) return dbUrl;
|
|
279328
|
+
const why = safety.superuser ? "a superuser" : "BYPASSRLS";
|
|
279329
|
+
console.log(
|
|
279330
|
+
`
|
|
279331
|
+
${import_picocolors2.default.yellow("!")} DATABASE_URL connects as ${import_picocolors2.default.bold(safety.role)} \u2014 ${why}, so row-level security can't be enforced.
|
|
279332
|
+
Ablo's server will refuse this connection (${import_picocolors2.default.bold("database_role_cannot_enforce_rls")}).`
|
|
279333
|
+
);
|
|
279334
|
+
if (!process.stdout.isTTY) {
|
|
279335
|
+
console.log(
|
|
279336
|
+
import_picocolors2.default.dim(
|
|
279337
|
+
` Create a scoped role and update DATABASE_URL \u2014 run \`npx ablo migrate\` interactively
|
|
279338
|
+
to do it automatically, or see https://docs.abloatai.com/quickstart#scoped-role`
|
|
279339
|
+
)
|
|
279340
|
+
);
|
|
279341
|
+
return dbUrl;
|
|
279342
|
+
}
|
|
279343
|
+
const proceed = await ye({
|
|
279344
|
+
message: `Create a scoped role ${DEFAULT_SCOPED_ROLE} (NOSUPERUSER, NOBYPASSRLS) and update DATABASE_URL?`,
|
|
279345
|
+
initialValue: true
|
|
279346
|
+
});
|
|
279347
|
+
if (pD(proceed) || !proceed) {
|
|
279348
|
+
console.log(import_picocolors2.default.dim(" Skipped \u2014 see https://docs.abloatai.com/quickstart#scoped-role for the manual recipe."));
|
|
279349
|
+
return dbUrl;
|
|
279350
|
+
}
|
|
279351
|
+
const { role, databaseUrl } = await createScopedRole(dbUrl);
|
|
279352
|
+
const where = persistDatabaseUrl(databaseUrl);
|
|
279353
|
+
console.log(
|
|
279354
|
+
` ${import_picocolors2.default.green("\u2713")} Created role ${import_picocolors2.default.bold(role)} and updated ${import_picocolors2.default.bold("DATABASE_URL")} in ${import_picocolors2.default.bold(where)}.
|
|
279355
|
+
` + import_picocolors2.default.dim(` The owner credential never left this machine; the new password was written, not printed.`)
|
|
279356
|
+
);
|
|
279357
|
+
return databaseUrl;
|
|
279358
|
+
}
|
|
279359
|
+
function persistDatabaseUrl(databaseUrl, cwd = process.cwd()) {
|
|
279360
|
+
const line = `DATABASE_URL=${databaseUrl}`;
|
|
279361
|
+
for (const name of [".env.local", ".env"]) {
|
|
279362
|
+
const path = (0, import_path.resolve)(cwd, name);
|
|
279363
|
+
if (!(0, import_fs2.existsSync)(path)) continue;
|
|
279364
|
+
const content = (0, import_fs2.readFileSync)(path, "utf8");
|
|
279365
|
+
if (/^DATABASE_URL=/m.test(content)) {
|
|
279366
|
+
(0, import_fs2.writeFileSync)(path, content.replace(/^DATABASE_URL=.*$/m, line));
|
|
279367
|
+
return name;
|
|
279368
|
+
}
|
|
279369
|
+
}
|
|
279370
|
+
const envLocal = (0, import_path.resolve)(cwd, ".env.local");
|
|
279371
|
+
if ((0, import_fs2.existsSync)(envLocal)) {
|
|
279372
|
+
const content = (0, import_fs2.readFileSync)(envLocal, "utf8");
|
|
279373
|
+
(0, import_fs2.appendFileSync)(envLocal, `${content.endsWith("\n") || content.length === 0 ? "" : "\n"}${line}
|
|
279374
|
+
`);
|
|
279375
|
+
} else {
|
|
279376
|
+
(0, import_fs2.writeFileSync)(envLocal, `${line}
|
|
279377
|
+
`, { mode: 384 });
|
|
279378
|
+
}
|
|
279379
|
+
const gitignorePath = (0, import_path.resolve)(cwd, ".gitignore");
|
|
279380
|
+
const gitignore = (0, import_fs2.existsSync)(gitignorePath) ? (0, import_fs2.readFileSync)(gitignorePath, "utf8") : "";
|
|
279381
|
+
if (!/^(\.env\.local|\.env\*|\.env\.\*|\.env.*)$/m.test(gitignore)) {
|
|
279382
|
+
(0, import_fs2.writeFileSync)(
|
|
279383
|
+
gitignorePath,
|
|
279384
|
+
`${gitignore.endsWith("\n") || gitignore.length === 0 ? gitignore : `${gitignore}
|
|
279385
|
+
`}.env.local
|
|
279386
|
+
`
|
|
279387
|
+
);
|
|
279388
|
+
}
|
|
279389
|
+
return ".env.local";
|
|
279390
|
+
}
|
|
279391
|
+
function readProjectDatabaseUrl(cwd = process.cwd()) {
|
|
279392
|
+
const fromEnv = process.env.DATABASE_URL ?? process.env.ABLO_DATABASE_URL;
|
|
279393
|
+
if (fromEnv) return fromEnv;
|
|
279394
|
+
for (const name of [".env.local", ".env"]) {
|
|
279395
|
+
const path = (0, import_path.resolve)(cwd, name);
|
|
279396
|
+
if (!(0, import_fs2.existsSync)(path)) continue;
|
|
279397
|
+
const match = (0, import_fs2.readFileSync)(path, "utf8").match(/^DATABASE_URL=(.+)$/m);
|
|
279398
|
+
if (match?.[1]) return match[1].trim().replace(/^["']|["']$/g, "");
|
|
279399
|
+
}
|
|
279400
|
+
return null;
|
|
279401
|
+
}
|
|
279303
279402
|
|
|
279304
279403
|
// src/cli/migrate.ts
|
|
279305
279404
|
var import_schema2 = require("@abloatai/ablo/schema");
|
|
@@ -279307,26 +279406,26 @@ var import_source = require("@abloatai/ablo/source");
|
|
|
279307
279406
|
|
|
279308
279407
|
// src/cli/push.ts
|
|
279309
279408
|
init_cjs_shims();
|
|
279310
|
-
var
|
|
279311
|
-
var
|
|
279312
|
-
var
|
|
279409
|
+
var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
279410
|
+
var import_fs4 = require("fs");
|
|
279411
|
+
var import_path3 = require("path");
|
|
279313
279412
|
var import_schema = require("@abloatai/ablo/schema");
|
|
279314
279413
|
|
|
279315
279414
|
// src/cli/config.ts
|
|
279316
279415
|
init_cjs_shims();
|
|
279317
279416
|
var import_os2 = require("os");
|
|
279318
|
-
var
|
|
279319
|
-
var
|
|
279417
|
+
var import_path2 = require("path");
|
|
279418
|
+
var import_fs3 = require("fs");
|
|
279320
279419
|
function configDir() {
|
|
279321
279420
|
if (process.env.ABLO_CONFIG_DIR) return process.env.ABLO_CONFIG_DIR;
|
|
279322
279421
|
const xdg = process.env.XDG_CONFIG_HOME;
|
|
279323
|
-
return xdg ? (0,
|
|
279422
|
+
return xdg ? (0, import_path2.join)(xdg, "ablo") : (0, import_path2.join)((0, import_os2.homedir)(), ".config", "ablo");
|
|
279324
279423
|
}
|
|
279325
279424
|
function configPath() {
|
|
279326
|
-
return (0,
|
|
279425
|
+
return (0, import_path2.join)(configDir(), "config.json");
|
|
279327
279426
|
}
|
|
279328
279427
|
function credentialsPath() {
|
|
279329
|
-
return (0,
|
|
279428
|
+
return (0, import_path2.join)(configDir(), "credentials.json");
|
|
279330
279429
|
}
|
|
279331
279430
|
function asKeyEntry(value) {
|
|
279332
279431
|
if (value && typeof value === "object" && typeof value.apiKey === "string") {
|
|
@@ -279335,9 +279434,9 @@ function asKeyEntry(value) {
|
|
|
279335
279434
|
return void 0;
|
|
279336
279435
|
}
|
|
279337
279436
|
function readJson(path) {
|
|
279338
|
-
if (!(0,
|
|
279437
|
+
if (!(0, import_fs3.existsSync)(path)) return null;
|
|
279339
279438
|
try {
|
|
279340
|
-
const parsed = JSON.parse((0,
|
|
279439
|
+
const parsed = JSON.parse((0, import_fs3.readFileSync)(path, "utf-8"));
|
|
279341
279440
|
return parsed && typeof parsed === "object" ? parsed : null;
|
|
279342
279441
|
} catch {
|
|
279343
279442
|
return null;
|
|
@@ -279374,14 +279473,14 @@ function readConfig() {
|
|
|
279374
279473
|
}
|
|
279375
279474
|
function writeConfig(cfg) {
|
|
279376
279475
|
const dir = configDir();
|
|
279377
|
-
(0,
|
|
279378
|
-
(0,
|
|
279476
|
+
(0, import_fs3.mkdirSync)(dir, { recursive: true, mode: 448 });
|
|
279477
|
+
(0, import_fs3.writeFileSync)(configPath(), `${JSON.stringify({ mode: cfg.mode }, null, 2)}
|
|
279379
279478
|
`, { mode: 384 });
|
|
279380
279479
|
const credentials = {
|
|
279381
279480
|
...cfg.sandbox ? { sandbox: cfg.sandbox } : {},
|
|
279382
279481
|
...cfg.production ? { production: cfg.production } : {}
|
|
279383
279482
|
};
|
|
279384
|
-
(0,
|
|
279483
|
+
(0, import_fs3.writeFileSync)(credentialsPath(), `${JSON.stringify(credentials, null, 2)}
|
|
279385
279484
|
`, { mode: 384 });
|
|
279386
279485
|
return credentialsPath();
|
|
279387
279486
|
}
|
|
@@ -279402,8 +279501,8 @@ function normalizeMode(value) {
|
|
|
279402
279501
|
function clearCredential() {
|
|
279403
279502
|
let removed = false;
|
|
279404
279503
|
for (const path of [configPath(), credentialsPath()]) {
|
|
279405
|
-
if ((0,
|
|
279406
|
-
(0,
|
|
279504
|
+
if ((0, import_fs3.existsSync)(path)) {
|
|
279505
|
+
(0, import_fs3.rmSync)(path);
|
|
279407
279506
|
removed = true;
|
|
279408
279507
|
}
|
|
279409
279508
|
}
|
|
@@ -279432,7 +279531,7 @@ var DEFAULT_URL = "https://api.abloatai.com";
|
|
|
279432
279531
|
function fmtSignal(s) {
|
|
279433
279532
|
const sig = s;
|
|
279434
279533
|
const where = sig.field ? `${sig.model}.${sig.field}` : sig.model;
|
|
279435
|
-
return ` \u2022 ${
|
|
279534
|
+
return ` \u2022 ${import_picocolors3.default.bold(where ?? "?")} \u2014 ${sig.detail ?? ""}`;
|
|
279436
279535
|
}
|
|
279437
279536
|
async function pushSchema(schema, args) {
|
|
279438
279537
|
const schemaJson = JSON.parse((0, import_schema.serializeSchema)(schema));
|
|
@@ -279510,10 +279609,10 @@ function parsePushArgs(argv) {
|
|
|
279510
279609
|
return { schemaPath, exportName, url, apiKey: process.env.ABLO_API_KEY, force, renames, backfills };
|
|
279511
279610
|
}
|
|
279512
279611
|
async function loadSchema(schemaPath, exportName) {
|
|
279513
|
-
const abs = (0,
|
|
279514
|
-
if (!(0,
|
|
279612
|
+
const abs = (0, import_path3.resolve)(process.cwd(), schemaPath);
|
|
279613
|
+
if (!(0, import_fs4.existsSync)(abs)) {
|
|
279515
279614
|
throw new AbloValidationError(
|
|
279516
|
-
`schema not found at ${
|
|
279615
|
+
`schema not found at ${import_picocolors3.default.bold(schemaPath)}. Run ${import_picocolors3.default.bold("npx ablo init")} or pass ${import_picocolors3.default.bold("--schema <path>")}.`,
|
|
279517
279616
|
{ code: "cli_invalid_arguments" }
|
|
279518
279617
|
);
|
|
279519
279618
|
}
|
|
@@ -279524,7 +279623,7 @@ async function loadSchema(schemaPath, exportName) {
|
|
|
279524
279623
|
const schema = mod[exportName] ?? nested?.[exportName];
|
|
279525
279624
|
if (!schema || typeof schema !== "object" || !("models" in schema)) {
|
|
279526
279625
|
throw new AbloValidationError(
|
|
279527
|
-
`${
|
|
279626
|
+
`${import_picocolors3.default.bold(schemaPath)} has no \`${exportName}\` export that looks like a Schema. Did you \`export const ${exportName} = defineSchema({ ... })\`?`,
|
|
279528
279627
|
{ code: "cli_invalid_arguments" }
|
|
279529
279628
|
);
|
|
279530
279629
|
}
|
|
@@ -279535,30 +279634,30 @@ async function push(argv) {
|
|
|
279535
279634
|
try {
|
|
279536
279635
|
args = parsePushArgs(argv);
|
|
279537
279636
|
} catch (err) {
|
|
279538
|
-
console.error(
|
|
279637
|
+
console.error(import_picocolors3.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
279539
279638
|
process.exit(1);
|
|
279540
279639
|
}
|
|
279541
279640
|
if (!args.apiKey) args.apiKey = resolveApiKey();
|
|
279542
279641
|
if (!args.apiKey) {
|
|
279543
279642
|
console.error(
|
|
279544
|
-
|
|
279643
|
+
import_picocolors3.default.red(` No API key.`) + import_picocolors3.default.dim(` Run ${import_picocolors3.default.bold("ablo login")} or set ${import_picocolors3.default.bold("ABLO_API_KEY")} (a secret sk_ key with schema:push).`)
|
|
279545
279644
|
);
|
|
279546
279645
|
process.exit(1);
|
|
279547
279646
|
}
|
|
279548
279647
|
const schema = await loadSchema(args.schemaPath, args.exportName);
|
|
279549
279648
|
const hash = (0, import_schema.schemaHash)(schema);
|
|
279550
279649
|
console.log(
|
|
279551
|
-
` Pushing ${
|
|
279650
|
+
` Pushing ${import_picocolors3.default.bold(args.schemaPath)} ${import_picocolors3.default.dim(`(${Object.keys(schema.models).length} models, hash ${hash})`)} \u2192 ${import_picocolors3.default.dim(args.url)}`
|
|
279552
279651
|
);
|
|
279553
279652
|
const { ok: resOk, status: status2, body, bodyText } = await pushSchema(schema, args);
|
|
279554
279653
|
if (resOk) {
|
|
279555
279654
|
if (body.unchanged) {
|
|
279556
|
-
console.log(` ${
|
|
279655
|
+
console.log(` ${import_picocolors3.default.dim("\u25CB")} No changes \u2014 schema already active (v${body.version}).`);
|
|
279557
279656
|
} else {
|
|
279558
|
-
console.log(` ${
|
|
279657
|
+
console.log(` ${import_picocolors3.default.green("\u2713")} Activated ${import_picocolors3.default.bold(`v${body.version}`)} ${import_picocolors3.default.dim(`(hash ${body.hash})`)}`);
|
|
279559
279658
|
if (Array.isArray(body.warnings) && body.warnings.length > 0) {
|
|
279560
|
-
console.log(
|
|
279561
|
-
for (const w2 of body.warnings) console.log(
|
|
279659
|
+
console.log(import_picocolors3.default.yellow(` Applied ${body.warnings.length} destructive change(s):`));
|
|
279660
|
+
for (const w2 of body.warnings) console.log(import_picocolors3.default.yellow(fmtSignal(w2)));
|
|
279562
279661
|
}
|
|
279563
279662
|
}
|
|
279564
279663
|
return;
|
|
@@ -279566,20 +279665,20 @@ async function push(argv) {
|
|
|
279566
279665
|
if (status2 === 409) {
|
|
279567
279666
|
const unexecutable = Array.isArray(body.unexecutable) ? body.unexecutable : [];
|
|
279568
279667
|
const warnings = Array.isArray(body.warnings) ? body.warnings : [];
|
|
279569
|
-
console.error(
|
|
279668
|
+
console.error(import_picocolors3.default.red(" Incompatible change \u2014 this push is not safe to apply as-is."));
|
|
279570
279669
|
if (unexecutable.length > 0) {
|
|
279571
|
-
console.error(
|
|
279572
|
-
for (const u2 of unexecutable) console.error(
|
|
279670
|
+
console.error(import_picocolors3.default.red(` Unexecutable (would fail on existing rows):`));
|
|
279671
|
+
for (const u2 of unexecutable) console.error(import_picocolors3.default.red(fmtSignal(u2)));
|
|
279573
279672
|
}
|
|
279574
279673
|
if (warnings.length > 0) {
|
|
279575
|
-
console.error(
|
|
279576
|
-
for (const w2 of warnings) console.error(
|
|
279674
|
+
console.error(import_picocolors3.default.yellow(` Destructive (data loss):`));
|
|
279675
|
+
for (const w2 of warnings) console.error(import_picocolors3.default.yellow(fmtSignal(w2)));
|
|
279577
279676
|
}
|
|
279578
|
-
console.error(
|
|
279677
|
+
console.error(import_picocolors3.default.dim(` Re-push with ${import_picocolors3.default.bold("--force")} to override, or use ${import_picocolors3.default.bold("--rename old:new")} if you renamed a model.`));
|
|
279579
279678
|
} else if (status2 === 403) {
|
|
279580
|
-
console.error(
|
|
279679
|
+
console.error(import_picocolors3.default.red(` Forbidden: ${body.message ?? body.reason ?? "key lacks schema:push scope"}`));
|
|
279581
279680
|
} else {
|
|
279582
|
-
console.error(
|
|
279681
|
+
console.error(import_picocolors3.default.red(` Push failed (${status2}): ${body.message ?? body.reason ?? bodyText}`));
|
|
279583
279682
|
}
|
|
279584
279683
|
process.exit(1);
|
|
279585
279684
|
}
|
|
@@ -279627,8 +279726,8 @@ function planFor(schema, targetSchema = "public") {
|
|
|
279627
279726
|
}
|
|
279628
279727
|
var log = {
|
|
279629
279728
|
info: (msg, fields) => console.log(`[migrate] ${msg}`, fields),
|
|
279630
|
-
warn: (msg, fields) => console.warn(
|
|
279631
|
-
error: (msg, fields) => console.error(
|
|
279729
|
+
warn: (msg, fields) => console.warn(import_picocolors4.default.yellow(`[migrate] ${msg}`), fields),
|
|
279730
|
+
error: (msg, fields) => console.error(import_picocolors4.default.red(`[migrate] ${msg}`), fields)
|
|
279632
279731
|
};
|
|
279633
279732
|
var PG_LOCK_NOT_AVAILABLE = "55P03";
|
|
279634
279733
|
var LOCK_TIMEOUT = process.env.ABLO_SCHEMA_LOCK_TIMEOUT ?? process.env.ABLO_DDL_LOCK_TIMEOUT ?? "5s";
|
|
@@ -279703,7 +279802,7 @@ async function migrate(argv) {
|
|
|
279703
279802
|
try {
|
|
279704
279803
|
args = parseMigrateArgs(argv);
|
|
279705
279804
|
} catch (err) {
|
|
279706
|
-
console.error(
|
|
279805
|
+
console.error(import_picocolors4.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
279707
279806
|
process.exit(1);
|
|
279708
279807
|
}
|
|
279709
279808
|
const schema = await loadSchema(args.schemaPath, args.exportName);
|
|
@@ -279714,11 +279813,11 @@ async function migrate(argv) {
|
|
|
279714
279813
|
].join("\n");
|
|
279715
279814
|
const totalStatements = plan.statements.length + plan.concurrent.length;
|
|
279716
279815
|
console.log(
|
|
279717
|
-
` ${
|
|
279816
|
+
` ${import_picocolors4.default.dim("Schema")} ${import_picocolors4.default.bold(args.schemaPath)} \u2192 ${import_picocolors4.default.dim(`${Object.keys(schema.models).length} models, ${totalStatements} statements`)}`
|
|
279718
279817
|
);
|
|
279719
279818
|
if (args.outputFile) {
|
|
279720
|
-
(0,
|
|
279721
|
-
console.log(` ${
|
|
279819
|
+
(0, import_fs5.writeFileSync)(args.outputFile, sql + "\n");
|
|
279820
|
+
console.log(` ${import_picocolors4.default.green("\u2713")} SQL written to ${import_picocolors4.default.bold(args.outputFile)}`);
|
|
279722
279821
|
return;
|
|
279723
279822
|
}
|
|
279724
279823
|
if (args.dryRun) {
|
|
@@ -279727,100 +279826,23 @@ async function migrate(argv) {
|
|
|
279727
279826
|
}
|
|
279728
279827
|
const dbUrl = process.env.DATABASE_URL ?? process.env.ABLO_DATABASE_URL;
|
|
279729
279828
|
if (!dbUrl) {
|
|
279730
|
-
console.error(
|
|
279829
|
+
console.error(import_picocolors4.default.red(" Set DATABASE_URL (or ABLO_DATABASE_URL) to apply, or use --dry-run to preview."));
|
|
279731
279830
|
process.exit(1);
|
|
279732
279831
|
}
|
|
279733
|
-
const effectiveUrl = await
|
|
279832
|
+
const effectiveUrl = await ensureScopedRoleInteractive(dbUrl);
|
|
279734
279833
|
try {
|
|
279735
279834
|
await applyStatements(effectiveUrl, args.targetSchema, plan.statements, plan.concurrent);
|
|
279736
|
-
console.log(` ${
|
|
279835
|
+
console.log(` ${import_picocolors4.default.green("\u2713")} Migration complete`);
|
|
279737
279836
|
} catch {
|
|
279738
279837
|
process.exit(1);
|
|
279739
279838
|
}
|
|
279740
279839
|
}
|
|
279741
|
-
async function ensureScopedRole(dbUrl) {
|
|
279742
|
-
let safety;
|
|
279743
|
-
try {
|
|
279744
|
-
const sql = src_default(dbUrl, { max: 1, prepare: false, onnotice: () => {
|
|
279745
|
-
} });
|
|
279746
|
-
try {
|
|
279747
|
-
safety = await detectRoleSafety(sql);
|
|
279748
|
-
} finally {
|
|
279749
|
-
await sql.end({ timeout: 5 });
|
|
279750
|
-
}
|
|
279751
|
-
} catch {
|
|
279752
|
-
return dbUrl;
|
|
279753
|
-
}
|
|
279754
|
-
if (!safety.unsafe) return dbUrl;
|
|
279755
|
-
const why = safety.superuser ? "a superuser" : "BYPASSRLS";
|
|
279756
|
-
console.log(
|
|
279757
|
-
`
|
|
279758
|
-
${import_picocolors3.default.yellow("!")} DATABASE_URL connects as ${import_picocolors3.default.bold(safety.role)} \u2014 ${why}, so row-level security can't be enforced.
|
|
279759
|
-
Ablo's server will refuse this connection (${import_picocolors3.default.bold("database_role_cannot_enforce_rls")}).`
|
|
279760
|
-
);
|
|
279761
|
-
if (!process.stdout.isTTY) {
|
|
279762
|
-
console.log(
|
|
279763
|
-
import_picocolors3.default.dim(
|
|
279764
|
-
` Create a scoped role and update DATABASE_URL \u2014 run \`npx ablo migrate\` interactively
|
|
279765
|
-
to do it automatically, or see https://docs.abloatai.com/quickstart#scoped-role`
|
|
279766
|
-
)
|
|
279767
|
-
);
|
|
279768
|
-
return dbUrl;
|
|
279769
|
-
}
|
|
279770
|
-
const proceed = await ye({
|
|
279771
|
-
message: `Create a scoped role ${DEFAULT_SCOPED_ROLE} (NOSUPERUSER, NOBYPASSRLS) and update DATABASE_URL?`,
|
|
279772
|
-
initialValue: true
|
|
279773
|
-
});
|
|
279774
|
-
if (pD(proceed) || !proceed) {
|
|
279775
|
-
console.log(import_picocolors3.default.dim(" Skipped \u2014 see https://docs.abloatai.com/quickstart#scoped-role for the manual recipe."));
|
|
279776
|
-
return dbUrl;
|
|
279777
|
-
}
|
|
279778
|
-
const { role, databaseUrl } = await createScopedRole(dbUrl);
|
|
279779
|
-
const where = persistDatabaseUrl(databaseUrl);
|
|
279780
|
-
console.log(
|
|
279781
|
-
` ${import_picocolors3.default.green("\u2713")} Created role ${import_picocolors3.default.bold(role)} and updated ${import_picocolors3.default.bold("DATABASE_URL")} in ${import_picocolors3.default.bold(where)}.
|
|
279782
|
-
` + import_picocolors3.default.dim(` The owner credential never left this machine; the new password was written, not printed.`)
|
|
279783
|
-
);
|
|
279784
|
-
return databaseUrl;
|
|
279785
|
-
}
|
|
279786
|
-
function persistDatabaseUrl(databaseUrl, cwd = process.cwd()) {
|
|
279787
|
-
const line = `DATABASE_URL=${databaseUrl}`;
|
|
279788
|
-
for (const name of [".env.local", ".env"]) {
|
|
279789
|
-
const path = (0, import_path3.resolve)(cwd, name);
|
|
279790
|
-
if (!(0, import_fs4.existsSync)(path)) continue;
|
|
279791
|
-
const content = (0, import_fs4.readFileSync)(path, "utf8");
|
|
279792
|
-
if (/^DATABASE_URL=/m.test(content)) {
|
|
279793
|
-
(0, import_fs4.writeFileSync)(path, content.replace(/^DATABASE_URL=.*$/m, line));
|
|
279794
|
-
return name;
|
|
279795
|
-
}
|
|
279796
|
-
}
|
|
279797
|
-
const envLocal = (0, import_path3.resolve)(cwd, ".env.local");
|
|
279798
|
-
if ((0, import_fs4.existsSync)(envLocal)) {
|
|
279799
|
-
const content = (0, import_fs4.readFileSync)(envLocal, "utf8");
|
|
279800
|
-
(0, import_fs4.appendFileSync)(envLocal, `${content.endsWith("\n") || content.length === 0 ? "" : "\n"}${line}
|
|
279801
|
-
`);
|
|
279802
|
-
} else {
|
|
279803
|
-
(0, import_fs4.writeFileSync)(envLocal, `${line}
|
|
279804
|
-
`, { mode: 384 });
|
|
279805
|
-
}
|
|
279806
|
-
const gitignorePath = (0, import_path3.resolve)(cwd, ".gitignore");
|
|
279807
|
-
const gitignore = (0, import_fs4.existsSync)(gitignorePath) ? (0, import_fs4.readFileSync)(gitignorePath, "utf8") : "";
|
|
279808
|
-
if (!/^(\.env\.local|\.env\*|\.env\.\*|\.env.*)$/m.test(gitignore)) {
|
|
279809
|
-
(0, import_fs4.writeFileSync)(
|
|
279810
|
-
gitignorePath,
|
|
279811
|
-
`${gitignore.endsWith("\n") || gitignore.length === 0 ? gitignore : `${gitignore}
|
|
279812
|
-
`}.env.local
|
|
279813
|
-
`
|
|
279814
|
-
);
|
|
279815
|
-
}
|
|
279816
|
-
return ".env.local";
|
|
279817
|
-
}
|
|
279818
279840
|
|
|
279819
279841
|
// src/cli/generate.ts
|
|
279820
279842
|
init_cjs_shims();
|
|
279821
|
-
var
|
|
279843
|
+
var import_fs6 = require("fs");
|
|
279822
279844
|
var import_path4 = require("path");
|
|
279823
|
-
var
|
|
279845
|
+
var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
279824
279846
|
var import_schema3 = require("@abloatai/ablo/schema");
|
|
279825
279847
|
var DEFAULT_SCHEMA_PATH3 = "ablo/schema.ts";
|
|
279826
279848
|
var DEFAULT_EXPORT3 = "schema";
|
|
@@ -279852,7 +279874,7 @@ async function generate(argv) {
|
|
|
279852
279874
|
try {
|
|
279853
279875
|
args = parseGenerateArgs(argv);
|
|
279854
279876
|
} catch (err) {
|
|
279855
|
-
console.error(
|
|
279877
|
+
console.error(import_picocolors5.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
279856
279878
|
process.exit(1);
|
|
279857
279879
|
}
|
|
279858
279880
|
let source;
|
|
@@ -279861,19 +279883,19 @@ async function generate(argv) {
|
|
|
279861
279883
|
const schemaJson = JSON.parse((0, import_schema3.serializeSchema)(schema));
|
|
279862
279884
|
source = (0, import_schema3.generateTypes)(schemaJson);
|
|
279863
279885
|
} catch (err) {
|
|
279864
|
-
console.error(
|
|
279886
|
+
console.error(import_picocolors5.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
279865
279887
|
process.exit(1);
|
|
279866
279888
|
}
|
|
279867
279889
|
const abs = (0, import_path4.resolve)(process.cwd(), args.out);
|
|
279868
|
-
(0,
|
|
279869
|
-
(0,
|
|
279870
|
-
console.log(` ${
|
|
279890
|
+
(0, import_fs6.mkdirSync)((0, import_path4.dirname)(abs), { recursive: true });
|
|
279891
|
+
(0, import_fs6.writeFileSync)(abs, source);
|
|
279892
|
+
console.log(` ${import_picocolors5.default.green("\u2713")} Generated types \u2192 ${import_picocolors5.default.bold(args.out)}`);
|
|
279871
279893
|
}
|
|
279872
279894
|
|
|
279873
279895
|
// src/cli/dev.ts
|
|
279874
279896
|
init_cjs_shims();
|
|
279875
|
-
var
|
|
279876
|
-
var
|
|
279897
|
+
var import_picocolors6 = __toESM(require_picocolors(), 1);
|
|
279898
|
+
var import_fs7 = require("fs");
|
|
279877
279899
|
var import_path5 = require("path");
|
|
279878
279900
|
var import_schema4 = require("@abloatai/ablo/schema");
|
|
279879
279901
|
|
|
@@ -279895,7 +279917,7 @@ function parseDevArgs(argv) {
|
|
|
279895
279917
|
let schemaPath = DEFAULT_SCHEMA_PATH;
|
|
279896
279918
|
let exportName = DEFAULT_EXPORT;
|
|
279897
279919
|
let url = process.env.ABLO_API_URL ?? DEFAULT_URL;
|
|
279898
|
-
let watchEnabled =
|
|
279920
|
+
let watchEnabled = false;
|
|
279899
279921
|
for (let i = 0; i < argv.length; i++) {
|
|
279900
279922
|
const arg = argv[i];
|
|
279901
279923
|
switch (arg) {
|
|
@@ -279908,6 +279930,9 @@ function parseDevArgs(argv) {
|
|
|
279908
279930
|
case "--url":
|
|
279909
279931
|
url = argv[++i] ?? url;
|
|
279910
279932
|
break;
|
|
279933
|
+
case "--watch":
|
|
279934
|
+
watchEnabled = true;
|
|
279935
|
+
break;
|
|
279911
279936
|
case "--no-watch":
|
|
279912
279937
|
watchEnabled = false;
|
|
279913
279938
|
break;
|
|
@@ -279922,58 +279947,58 @@ function classifyKey(apiKey) {
|
|
|
279922
279947
|
if (!apiKey) {
|
|
279923
279948
|
return {
|
|
279924
279949
|
ok: false,
|
|
279925
|
-
reason: `No API key. Run ${
|
|
279950
|
+
reason: `No API key. Run ${import_picocolors6.default.bold("ablo login")} (or set ${import_picocolors6.default.bold("ABLO_API_KEY")}) with a ${import_picocolors6.default.bold("sk_test_")} key from ${import_picocolors6.default.cyan("https://abloatai.com")}.`
|
|
279926
279951
|
};
|
|
279927
279952
|
}
|
|
279928
279953
|
if (apiKey.startsWith("sk_test_")) return { ok: true };
|
|
279929
279954
|
if (apiKey.startsWith("sk_live_")) {
|
|
279930
279955
|
return {
|
|
279931
279956
|
ok: false,
|
|
279932
|
-
reason: `${
|
|
279957
|
+
reason: `${import_picocolors6.default.bold("ablo dev")} refuses production keys. Use a ${import_picocolors6.default.bold("sk_test_")} key so the watch loop can't churn production data.`
|
|
279933
279958
|
};
|
|
279934
279959
|
}
|
|
279935
279960
|
if (apiKey.startsWith("rk_")) {
|
|
279936
279961
|
return {
|
|
279937
279962
|
ok: false,
|
|
279938
|
-
reason: `Restricted (${
|
|
279963
|
+
reason: `Restricted (${import_picocolors6.default.bold("rk_")}) keys can't push schema. Use a secret ${import_picocolors6.default.bold("sk_test_")} key.`
|
|
279939
279964
|
};
|
|
279940
279965
|
}
|
|
279941
|
-
return { ok: false, reason: `${
|
|
279966
|
+
return { ok: false, reason: `${import_picocolors6.default.bold("ABLO_API_KEY")} is not an Ablo key (expected ${import_picocolors6.default.bold("sk_test_\u2026")}).` };
|
|
279942
279967
|
}
|
|
279943
279968
|
function wireEnvLocal(apiKey, cwd = process.cwd()) {
|
|
279944
279969
|
const envPath = (0, import_path5.resolve)(cwd, ".env.local");
|
|
279945
279970
|
const line = `ABLO_API_KEY=${apiKey}`;
|
|
279946
279971
|
let action;
|
|
279947
|
-
if (!(0,
|
|
279948
|
-
(0,
|
|
279972
|
+
if (!(0, import_fs7.existsSync)(envPath)) {
|
|
279973
|
+
(0, import_fs7.writeFileSync)(envPath, `${line}
|
|
279949
279974
|
`, { mode: 384 });
|
|
279950
|
-
action = `Created ${
|
|
279975
|
+
action = `Created ${import_picocolors6.default.bold(".env.local")} with ${import_picocolors6.default.bold("ABLO_API_KEY")}`;
|
|
279951
279976
|
} else {
|
|
279952
|
-
const content = (0,
|
|
279977
|
+
const content = (0, import_fs7.readFileSync)(envPath, "utf8");
|
|
279953
279978
|
const match = content.match(/^ABLO_API_KEY=(.*)$/m);
|
|
279954
279979
|
if (!match) {
|
|
279955
|
-
(0,
|
|
279980
|
+
(0, import_fs7.appendFileSync)(envPath, `${content.endsWith("\n") || content.length === 0 ? "" : "\n"}${line}
|
|
279956
279981
|
`);
|
|
279957
|
-
action = `Added ${
|
|
279982
|
+
action = `Added ${import_picocolors6.default.bold("ABLO_API_KEY")} to ${import_picocolors6.default.bold(".env.local")}`;
|
|
279958
279983
|
} else if (match[1] === apiKey) {
|
|
279959
|
-
action = `${
|
|
279984
|
+
action = `${import_picocolors6.default.bold(".env.local")} already has this key`;
|
|
279960
279985
|
} else {
|
|
279961
|
-
(0,
|
|
279962
|
-
action = `Updated ${
|
|
279986
|
+
(0, import_fs7.writeFileSync)(envPath, content.replace(/^ABLO_API_KEY=.*$/m, line));
|
|
279987
|
+
action = `Updated ${import_picocolors6.default.bold("ABLO_API_KEY")} in ${import_picocolors6.default.bold(".env.local")} ${import_picocolors6.default.dim(`(was ${match[1].slice(0, 12)}\u2026)`)}`;
|
|
279963
279988
|
}
|
|
279964
279989
|
}
|
|
279965
279990
|
const gitignorePath = (0, import_path5.resolve)(cwd, ".gitignore");
|
|
279966
|
-
const gitignore = (0,
|
|
279991
|
+
const gitignore = (0, import_fs7.existsSync)(gitignorePath) ? (0, import_fs7.readFileSync)(gitignorePath, "utf8") : "";
|
|
279967
279992
|
const ignored = /^(\.env\.local|\.env\*|\.env\.\*|\.env.*)$/m.test(gitignore);
|
|
279968
279993
|
let gitignoreNote = "";
|
|
279969
279994
|
if (!ignored) {
|
|
279970
|
-
(0,
|
|
279995
|
+
(0, import_fs7.writeFileSync)(
|
|
279971
279996
|
gitignorePath,
|
|
279972
279997
|
`${gitignore.endsWith("\n") || gitignore.length === 0 ? gitignore : `${gitignore}
|
|
279973
279998
|
`}.env.local
|
|
279974
279999
|
`
|
|
279975
280000
|
);
|
|
279976
|
-
gitignoreNote = ` Added ${
|
|
280001
|
+
gitignoreNote = ` Added ${import_picocolors6.default.bold(".env.local")} to ${import_picocolors6.default.bold(".gitignore")} so the key can't be committed.`;
|
|
279977
280002
|
}
|
|
279978
280003
|
return `${action}.${gitignoreNote}`;
|
|
279979
280004
|
}
|
|
@@ -279988,7 +280013,7 @@ async function runPush(schema, args) {
|
|
|
279988
280013
|
if (ok) {
|
|
279989
280014
|
return {
|
|
279990
280015
|
ok: true,
|
|
279991
|
-
message: body.unchanged ? `schema unchanged ${
|
|
280016
|
+
message: body.unchanged ? `schema unchanged ${import_picocolors6.default.dim(`(v${body.version})`)}` : `schema pushed (sandbox) ${import_picocolors6.default.dim(`(v${body.version}, hash ${body.hash})`)}`
|
|
279992
280017
|
};
|
|
279993
280018
|
}
|
|
279994
280019
|
if (status2 === 409) {
|
|
@@ -279996,19 +280021,19 @@ async function runPush(schema, args) {
|
|
|
279996
280021
|
const warnings = Array.isArray(body.warnings) ? body.warnings : [];
|
|
279997
280022
|
const lines = [
|
|
279998
280023
|
"Incompatible schema change \u2014 not safe to apply as-is.",
|
|
279999
|
-
...unexecutable.map((u2) =>
|
|
280000
|
-
...warnings.map((w2) =>
|
|
280001
|
-
|
|
280024
|
+
...unexecutable.map((u2) => import_picocolors6.default.red(fmtSignal(u2))),
|
|
280025
|
+
...warnings.map((w2) => import_picocolors6.default.yellow(fmtSignal(w2))),
|
|
280026
|
+
import_picocolors6.default.dim(`Run ${import_picocolors6.default.bold("ablo push --force")} (or ${import_picocolors6.default.bold("--rename old:new")}) to resolve.`)
|
|
280002
280027
|
];
|
|
280003
280028
|
return { ok: false, message: lines.join("\n") };
|
|
280004
280029
|
}
|
|
280005
280030
|
if (status2 === 403) {
|
|
280006
280031
|
const serverSays = body.message ?? body.reason;
|
|
280007
|
-
const hint = body.code === "database_role_cannot_enforce_rls" ? `Run ${
|
|
280032
|
+
const hint = body.code === "database_role_cannot_enforce_rls" ? `Run ${import_picocolors6.default.bold("npx ablo migrate")} \u2014 it creates the scoped role for you (your DB credential never leaves this machine).` : `Schema authoring needs a ${import_picocolors6.default.bold("sandbox")} key with ${import_picocolors6.default.bold("schema:push")} \u2014 manage keys at ${import_picocolors6.default.cyan("https://abloatai.com")}.`;
|
|
280008
280033
|
return {
|
|
280009
280034
|
ok: false,
|
|
280010
280035
|
message: `${serverSays ?? "This key can't author schema (missing schema:push scope)."}
|
|
280011
|
-
` +
|
|
280036
|
+
` + import_picocolors6.default.dim(hint)
|
|
280012
280037
|
};
|
|
280013
280038
|
}
|
|
280014
280039
|
return { ok: false, message: `Push failed (${status2}): ${body.message ?? body.reason ?? bodyText}` };
|
|
@@ -280018,25 +280043,27 @@ async function dev(argv) {
|
|
|
280018
280043
|
try {
|
|
280019
280044
|
args = parseDevArgs(argv);
|
|
280020
280045
|
} catch (err) {
|
|
280021
|
-
console.error(
|
|
280046
|
+
console.error(import_picocolors6.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
280022
280047
|
process.exit(1);
|
|
280023
280048
|
}
|
|
280024
280049
|
if (!args.apiKey) args.apiKey = resolveApiKey("sandbox");
|
|
280025
280050
|
const key = classifyKey(args.apiKey);
|
|
280026
280051
|
if (!key.ok) {
|
|
280027
|
-
console.error(
|
|
280052
|
+
console.error(import_picocolors6.default.red(` ${key.reason}`));
|
|
280028
280053
|
process.exit(1);
|
|
280029
280054
|
}
|
|
280030
280055
|
console.log(`
|
|
280031
|
-
${brand("ablo")} ${
|
|
280056
|
+
${brand("ablo")} ${import_picocolors6.default.dim("sync engine \u2014 dev")} ${import_picocolors6.default.dim("(sandbox)")}
|
|
280032
280057
|
`);
|
|
280058
|
+
const projectDbUrl = readProjectDatabaseUrl();
|
|
280059
|
+
if (projectDbUrl) await ensureScopedRoleInteractive(projectDbUrl);
|
|
280033
280060
|
const schema = await loadSchema(args.schemaPath, args.exportName);
|
|
280034
280061
|
const modelCount = Object.keys(schema.models).length;
|
|
280035
280062
|
console.log(
|
|
280036
|
-
` ${
|
|
280063
|
+
` ${import_picocolors6.default.dim("schema")} ${import_picocolors6.default.bold(args.schemaPath)} ${import_picocolors6.default.dim(`(${modelCount} models, hash ${(0, import_schema4.schemaHash)(schema)})`)}`
|
|
280037
280064
|
);
|
|
280038
|
-
console.log(` ${
|
|
280039
|
-
console.log(` ${
|
|
280065
|
+
console.log(` ${import_picocolors6.default.dim("key")} ${args.apiKey.slice(0, 12)}\u2026`);
|
|
280066
|
+
console.log(` ${import_picocolors6.default.dim("api")} ${args.url}
|
|
280040
280067
|
`);
|
|
280041
280068
|
const s = Y2();
|
|
280042
280069
|
s.start("Pushing schema definition (sandbox)");
|
|
@@ -280045,20 +280072,20 @@ async function dev(argv) {
|
|
|
280045
280072
|
if (!first.ok) process.exit(1);
|
|
280046
280073
|
if (process.env.ABLO_API_KEY) {
|
|
280047
280074
|
console.log(`
|
|
280048
|
-
${
|
|
280075
|
+
${import_picocolors6.default.green("\u2713")} ${import_picocolors6.default.bold("ABLO_API_KEY")} is set in this shell \u2014 the SDK reads it directly.`);
|
|
280049
280076
|
} else {
|
|
280050
280077
|
console.log(`
|
|
280051
|
-
${
|
|
280052
|
-
console.log(` ${
|
|
280078
|
+
${import_picocolors6.default.green("\u2713")} ${wireEnvLocal(args.apiKey)}`);
|
|
280079
|
+
console.log(` ${import_picocolors6.default.dim("Frameworks load it automatically; plain Node: node --env-file=.env.local app.ts")}`);
|
|
280053
280080
|
}
|
|
280054
280081
|
console.log(` Your app is wired for the sandbox.`);
|
|
280055
280082
|
if (!args.watch) return;
|
|
280056
280083
|
const abs = (0, import_path5.resolve)(process.cwd(), args.schemaPath);
|
|
280057
|
-
console.log(` ${
|
|
280084
|
+
console.log(` ${import_picocolors6.default.dim(`watching ${args.schemaPath} \u2026 (Ctrl-C to stop)`)}
|
|
280058
280085
|
`);
|
|
280059
280086
|
let timer2 = null;
|
|
280060
280087
|
let pushing = false;
|
|
280061
|
-
const watcher = (0,
|
|
280088
|
+
const watcher = (0, import_fs7.watch)(abs, () => {
|
|
280062
280089
|
if (timer2) clearTimeout(timer2);
|
|
280063
280090
|
timer2 = setTimeout(() => {
|
|
280064
280091
|
void rePush();
|
|
@@ -280074,7 +280101,7 @@ async function dev(argv) {
|
|
|
280074
280101
|
const r2 = await runPush(next, args);
|
|
280075
280102
|
s2.stop(r2.message, r2.ok ? 0 : 1);
|
|
280076
280103
|
} catch (err) {
|
|
280077
|
-
s2.stop(
|
|
280104
|
+
s2.stop(import_picocolors6.default.red(`schema reload failed: ${err instanceof Error ? err.message : String(err)}`), 1);
|
|
280078
280105
|
} finally {
|
|
280079
280106
|
pushing = false;
|
|
280080
280107
|
}
|
|
@@ -280082,7 +280109,7 @@ async function dev(argv) {
|
|
|
280082
280109
|
const stop = () => {
|
|
280083
280110
|
watcher.close();
|
|
280084
280111
|
console.log(`
|
|
280085
|
-
${
|
|
280112
|
+
${import_picocolors6.default.dim("stopped.")}`);
|
|
280086
280113
|
process.exit(0);
|
|
280087
280114
|
};
|
|
280088
280115
|
process.on("SIGINT", stop);
|
|
@@ -280094,7 +280121,7 @@ async function dev(argv) {
|
|
|
280094
280121
|
// src/cli/login.ts
|
|
280095
280122
|
init_cjs_shims();
|
|
280096
280123
|
var import_child_process = require("child_process");
|
|
280097
|
-
var
|
|
280124
|
+
var import_picocolors7 = __toESM(require_picocolors(), 1);
|
|
280098
280125
|
var CLIENT_ID = "ablo-cli";
|
|
280099
280126
|
var AUTH_URL = (process.env.ABLO_AUTH_URL ?? "https://www.abloatai.com").replace(/\/+$/, "");
|
|
280100
280127
|
var sleep = (ms) => new Promise((r2) => setTimeout(r2, ms));
|
|
@@ -280110,16 +280137,21 @@ function openBrowser(url) {
|
|
|
280110
280137
|
}
|
|
280111
280138
|
async function deviceLogin() {
|
|
280112
280139
|
Ie(`${brand("ablo")} login`);
|
|
280113
|
-
const
|
|
280114
|
-
|
|
280115
|
-
|
|
280116
|
-
|
|
280117
|
-
|
|
280118
|
-
|
|
280119
|
-
|
|
280120
|
-
|
|
280121
|
-
|
|
280122
|
-
|
|
280140
|
+
const interactive = Boolean(process.stdout.isTTY && process.stdin.isTTY);
|
|
280141
|
+
let account = "login";
|
|
280142
|
+
if (interactive) {
|
|
280143
|
+
const choice = await ve({
|
|
280144
|
+
message: "Ablo account",
|
|
280145
|
+
options: [
|
|
280146
|
+
{ value: "login", label: "Log in to an existing account" },
|
|
280147
|
+
{ value: "signup", label: "Create a new account" }
|
|
280148
|
+
]
|
|
280149
|
+
});
|
|
280150
|
+
if (pD(choice)) {
|
|
280151
|
+
xe("Cancelled.");
|
|
280152
|
+
process.exit(0);
|
|
280153
|
+
}
|
|
280154
|
+
account = choice;
|
|
280123
280155
|
}
|
|
280124
280156
|
const codeRes = await fetch(`${AUTH_URL}/api/auth/device/code`, {
|
|
280125
280157
|
method: "POST",
|
|
@@ -280133,9 +280165,9 @@ async function deviceLogin() {
|
|
|
280133
280165
|
const code = await codeRes.json();
|
|
280134
280166
|
const approvePath = `/cli?user_code=${code.user_code}`;
|
|
280135
280167
|
const url = account === "signup" ? `${AUTH_URL}/signup?next=${encodeURIComponent(approvePath)}` : code.verification_uri_complete ?? code.verification_uri;
|
|
280136
|
-
Me(`${
|
|
280168
|
+
Me(`${import_picocolors7.default.bold(code.user_code)}
|
|
280137
280169
|
|
|
280138
|
-
${
|
|
280170
|
+
${import_picocolors7.default.dim(url)}`, "Approve in your browser");
|
|
280139
280171
|
openBrowser(url);
|
|
280140
280172
|
const s = Y2();
|
|
280141
280173
|
s.start("Waiting for approval\u2026");
|
|
@@ -280193,7 +280225,7 @@ ${import_picocolors6.default.dim(url)}`, "Approve in your browser");
|
|
|
280193
280225
|
if (reason) M2.error(reason);
|
|
280194
280226
|
else if (provRes) M2.error(`Key provisioning returned ${provRes.status} from ${AUTH_URL}/api/cli/provision-key.`);
|
|
280195
280227
|
M2.error(
|
|
280196
|
-
`The browser approval succeeded but the key handoff failed. Try again, or grab a ${
|
|
280228
|
+
`The browser approval succeeded but the key handoff failed. Try again, or grab a ${import_picocolors7.default.bold("sk_test_")} key from the dashboard and set ${import_picocolors7.default.bold("ABLO_API_KEY")}.`
|
|
280197
280229
|
);
|
|
280198
280230
|
process.exit(1);
|
|
280199
280231
|
}
|
|
@@ -280209,7 +280241,7 @@ ${import_picocolors6.default.dim(url)}`, "Approve in your browser");
|
|
|
280209
280241
|
...prov.live ? { production: entry(prov.live) } : {}
|
|
280210
280242
|
});
|
|
280211
280243
|
s.stop(`Saved keys to ${path}`);
|
|
280212
|
-
Se(`${
|
|
280244
|
+
Se(`${import_picocolors7.default.green("\u2713")} Logged in ${import_picocolors7.default.dim("(sandbox)")}. Run ${import_picocolors7.default.bold("ablo dev")}, or ${import_picocolors7.default.bold("ablo mode production")} to switch.`);
|
|
280213
280245
|
}
|
|
280214
280246
|
async function login() {
|
|
280215
280247
|
await deviceLogin();
|
|
@@ -280217,20 +280249,20 @@ async function login() {
|
|
|
280217
280249
|
function logout() {
|
|
280218
280250
|
const removed = clearCredential();
|
|
280219
280251
|
if (removed) {
|
|
280220
|
-
console.log(` ${
|
|
280252
|
+
console.log(` ${import_picocolors7.default.green("\u2713")} Logged out ${import_picocolors7.default.dim(`(credentials removed from ${configDir()})`)}`);
|
|
280221
280253
|
} else {
|
|
280222
|
-
console.log(` ${
|
|
280254
|
+
console.log(` ${import_picocolors7.default.dim("\u25CB")} Not logged in \u2014 nothing to remove.`);
|
|
280223
280255
|
}
|
|
280224
280256
|
if (process.env.ABLO_API_KEY) {
|
|
280225
280257
|
console.log(
|
|
280226
|
-
|
|
280258
|
+
import_picocolors7.default.dim(` Note: ${import_picocolors7.default.bold("ABLO_API_KEY")} is still set in this shell and takes precedence.`)
|
|
280227
280259
|
);
|
|
280228
280260
|
}
|
|
280229
280261
|
}
|
|
280230
280262
|
|
|
280231
280263
|
// src/cli/mode.ts
|
|
280232
280264
|
init_cjs_shims();
|
|
280233
|
-
var
|
|
280265
|
+
var import_picocolors8 = __toESM(require_picocolors(), 1);
|
|
280234
280266
|
var PREFIX = { sandbox: "sk_test_", production: "rk_live_" };
|
|
280235
280267
|
function hintFor(m2, current) {
|
|
280236
280268
|
const parts = [];
|
|
@@ -280240,10 +280272,10 @@ function hintFor(m2, current) {
|
|
|
280240
280272
|
}
|
|
280241
280273
|
function apply(m2) {
|
|
280242
280274
|
setMode(m2);
|
|
280243
|
-
console.log(` ${
|
|
280275
|
+
console.log(` ${import_picocolors8.default.green("\u2713")} now in ${import_picocolors8.default.bold(m2)}`);
|
|
280244
280276
|
if (!getKeyEntry(m2)) {
|
|
280245
280277
|
console.log(
|
|
280246
|
-
|
|
280278
|
+
import_picocolors8.default.dim(` No ${m2} key stored \u2014 run ${import_picocolors8.default.bold("ablo login")} or ${import_picocolors8.default.bold(`ablo login --api-key ${PREFIX[m2]}\u2026`)}.`)
|
|
280247
280279
|
);
|
|
280248
280280
|
}
|
|
280249
280281
|
}
|
|
@@ -280256,14 +280288,14 @@ async function mode(argv) {
|
|
|
280256
280288
|
}
|
|
280257
280289
|
if (arg) {
|
|
280258
280290
|
console.error(
|
|
280259
|
-
|
|
280291
|
+
import_picocolors8.default.red(` unknown mode: ${arg}`) + import_picocolors8.default.dim(` (expected ${import_picocolors8.default.bold("sandbox")} or ${import_picocolors8.default.bold("production")})`)
|
|
280260
280292
|
);
|
|
280261
280293
|
process.exit(1);
|
|
280262
280294
|
}
|
|
280263
280295
|
const current = getMode();
|
|
280264
280296
|
if (!process.stdin.isTTY || process.env.CI) {
|
|
280265
280297
|
console.error(
|
|
280266
|
-
|
|
280298
|
+
import_picocolors8.default.red(" `ablo mode` needs an argument without a TTY: ") + import_picocolors8.default.bold("ablo mode sandbox") + import_picocolors8.default.dim(" | ") + import_picocolors8.default.bold("ablo mode production") + import_picocolors8.default.dim(` (current: ${current})`)
|
|
280267
280299
|
);
|
|
280268
280300
|
process.exit(1);
|
|
280269
280301
|
}
|
|
@@ -280284,13 +280316,13 @@ async function mode(argv) {
|
|
|
280284
280316
|
|
|
280285
280317
|
// src/cli/status.ts
|
|
280286
280318
|
init_cjs_shims();
|
|
280287
|
-
var
|
|
280319
|
+
var import_picocolors9 = __toESM(require_picocolors(), 1);
|
|
280288
280320
|
function expiryLabel(iso) {
|
|
280289
280321
|
const ms = Date.parse(iso) - Date.now();
|
|
280290
280322
|
if (Number.isNaN(ms)) return "";
|
|
280291
|
-
if (ms <= 0) return
|
|
280323
|
+
if (ms <= 0) return import_picocolors9.default.red("expired");
|
|
280292
280324
|
const days = Math.floor(ms / (24 * 60 * 60 * 1e3));
|
|
280293
|
-
return
|
|
280325
|
+
return import_picocolors9.default.dim(days > 0 ? `expires in ${days}d` : "expires <1d");
|
|
280294
280326
|
}
|
|
280295
280327
|
async function ping(apiUrl) {
|
|
280296
280328
|
const ctrl = new AbortController();
|
|
@@ -280309,36 +280341,36 @@ async function status() {
|
|
|
280309
280341
|
const cfg = readConfig();
|
|
280310
280342
|
const mode2 = getMode();
|
|
280311
280343
|
console.log(`
|
|
280312
|
-
${brand("ablo")} ${
|
|
280344
|
+
${brand("ablo")} ${import_picocolors9.default.dim("status")}
|
|
280313
280345
|
`);
|
|
280314
280346
|
if (process.env.ABLO_API_KEY) {
|
|
280315
280347
|
console.log(
|
|
280316
|
-
` ${
|
|
280348
|
+
` ${import_picocolors9.default.dim("key")} ${process.env.ABLO_API_KEY.slice(0, 12)}\u2026 ${import_picocolors9.default.dim("(ABLO_API_KEY env \u2014 overrides stored)")}`
|
|
280317
280349
|
);
|
|
280318
280350
|
} else if (!cfg) {
|
|
280319
|
-
console.log(` ${
|
|
280351
|
+
console.log(` ${import_picocolors9.default.yellow("!")} Not logged in \u2014 run ${import_picocolors9.default.bold("ablo login")}.`);
|
|
280320
280352
|
}
|
|
280321
|
-
console.log(` ${
|
|
280353
|
+
console.log(` ${import_picocolors9.default.dim("mode")} ${import_picocolors9.default.bold(mode2)}`);
|
|
280322
280354
|
for (const m2 of ["sandbox", "production"]) {
|
|
280323
280355
|
const entry = getKeyEntry(m2);
|
|
280324
|
-
const marker = m2 === mode2 ?
|
|
280356
|
+
const marker = m2 === mode2 ? import_picocolors9.default.green("\u25CF") : import_picocolors9.default.dim("\u25CB");
|
|
280325
280357
|
if (entry) {
|
|
280326
280358
|
const exp = entry.expiresAt ? ` ${expiryLabel(entry.expiresAt)}` : "";
|
|
280327
|
-
console.log(` ${marker} ${m2.padEnd(10)} ${
|
|
280359
|
+
console.log(` ${marker} ${m2.padEnd(10)} ${import_picocolors9.default.dim(`${entry.apiKey.slice(0, 12)}\u2026`)}${exp}`);
|
|
280328
280360
|
} else {
|
|
280329
|
-
console.log(` ${marker} ${m2.padEnd(10)} ${
|
|
280361
|
+
console.log(` ${marker} ${m2.padEnd(10)} ${import_picocolors9.default.dim("\u2014 no key")}`);
|
|
280330
280362
|
}
|
|
280331
280363
|
}
|
|
280332
280364
|
const org = getKeyEntry(mode2)?.organizationId;
|
|
280333
|
-
if (org) console.log(` ${
|
|
280334
|
-
process.stdout.write(` ${
|
|
280335
|
-
console.log(await ping(apiUrl) ?
|
|
280365
|
+
if (org) console.log(` ${import_picocolors9.default.dim("org")} ${org}`);
|
|
280366
|
+
process.stdout.write(` ${import_picocolors9.default.dim("api")} ${apiUrl} `);
|
|
280367
|
+
console.log(await ping(apiUrl) ? import_picocolors9.default.green("reachable") : import_picocolors9.default.red("unreachable"));
|
|
280336
280368
|
console.log();
|
|
280337
280369
|
}
|
|
280338
280370
|
|
|
280339
280371
|
// src/cli/logs.ts
|
|
280340
280372
|
init_cjs_shims();
|
|
280341
|
-
var
|
|
280373
|
+
var import_picocolors10 = __toESM(require_picocolors(), 1);
|
|
280342
280374
|
function parseLogsArgs(argv) {
|
|
280343
280375
|
const args = {
|
|
280344
280376
|
follow: true,
|
|
@@ -280402,10 +280434,10 @@ function resolveSince(since) {
|
|
|
280402
280434
|
var sleep2 = (ms) => new Promise((r2) => setTimeout(r2, ms));
|
|
280403
280435
|
function colorOp(op) {
|
|
280404
280436
|
const label = op.padEnd(6);
|
|
280405
|
-
if (op === "create") return
|
|
280406
|
-
if (op === "update") return
|
|
280407
|
-
if (op === "delete") return
|
|
280408
|
-
return
|
|
280437
|
+
if (op === "create") return import_picocolors10.default.green(label);
|
|
280438
|
+
if (op === "update") return import_picocolors10.default.yellow(label);
|
|
280439
|
+
if (op === "delete") return import_picocolors10.default.red(label);
|
|
280440
|
+
return import_picocolors10.default.dim(label);
|
|
280409
280441
|
}
|
|
280410
280442
|
function render(e2, json) {
|
|
280411
280443
|
if (json) {
|
|
@@ -280414,21 +280446,21 @@ function render(e2, json) {
|
|
|
280414
280446
|
return;
|
|
280415
280447
|
}
|
|
280416
280448
|
const t = new Date(e2.at).toLocaleTimeString();
|
|
280417
|
-
const actor = e2.actor ?
|
|
280418
|
-
console.log(` ${
|
|
280449
|
+
const actor = e2.actor ? import_picocolors10.default.dim(` ${e2.actor}`) : "";
|
|
280450
|
+
console.log(` ${import_picocolors10.default.dim(t)} ${colorOp(e2.op)} ${import_picocolors10.default.bold(e2.model)} ${import_picocolors10.default.dim(e2.recordId)}${actor}`);
|
|
280419
280451
|
}
|
|
280420
280452
|
async function logs(argv) {
|
|
280421
280453
|
let args;
|
|
280422
280454
|
try {
|
|
280423
280455
|
args = parseLogsArgs(argv);
|
|
280424
280456
|
} catch (err) {
|
|
280425
|
-
console.error(
|
|
280457
|
+
console.error(import_picocolors10.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
280426
280458
|
process.exit(1);
|
|
280427
280459
|
}
|
|
280428
280460
|
const apiKey = resolveApiKey(args.mode);
|
|
280429
280461
|
if (!apiKey) {
|
|
280430
280462
|
console.error(
|
|
280431
|
-
|
|
280463
|
+
import_picocolors10.default.red(` No API key.`) + import_picocolors10.default.dim(` Run ${import_picocolors10.default.bold("ablo login")} or set ${import_picocolors10.default.bold("ABLO_API_KEY")}.`)
|
|
280432
280464
|
);
|
|
280433
280465
|
process.exit(1);
|
|
280434
280466
|
}
|
|
@@ -280442,7 +280474,7 @@ async function logs(argv) {
|
|
|
280442
280474
|
if (!res) return null;
|
|
280443
280475
|
if (!res.ok) {
|
|
280444
280476
|
const body = await res.json().catch(() => ({}));
|
|
280445
|
-
console.error(
|
|
280477
|
+
console.error(import_picocolors10.default.red(` logs failed (${res.status}): ${body.reason ?? body.message ?? ""}`));
|
|
280446
280478
|
process.exit(1);
|
|
280447
280479
|
}
|
|
280448
280480
|
const json = await res.json();
|
|
@@ -280453,7 +280485,7 @@ async function logs(argv) {
|
|
|
280453
280485
|
}
|
|
280454
280486
|
if (!args.json) {
|
|
280455
280487
|
console.log(`
|
|
280456
|
-
${brand("ablo")} ${
|
|
280488
|
+
${brand("ablo")} ${import_picocolors10.default.dim("logs")} ${import_picocolors10.default.dim(`(${args.mode ?? "active"} mode)`)}
|
|
280457
280489
|
`);
|
|
280458
280490
|
}
|
|
280459
280491
|
const initial = await fetchPage({
|
|
@@ -280463,13 +280495,13 @@ async function logs(argv) {
|
|
|
280463
280495
|
...args.op ? { op: args.op } : {}
|
|
280464
280496
|
});
|
|
280465
280497
|
if (!initial) {
|
|
280466
|
-
console.error(
|
|
280498
|
+
console.error(import_picocolors10.default.red(` Couldn't reach ${baseUrl2}.`));
|
|
280467
280499
|
process.exit(1);
|
|
280468
280500
|
}
|
|
280469
280501
|
for (const e2 of initial.events) render(e2, args.json);
|
|
280470
280502
|
let cursor = initial.cursor;
|
|
280471
280503
|
if (!args.follow) return;
|
|
280472
|
-
if (!args.json) console.log(` ${
|
|
280504
|
+
if (!args.json) console.log(` ${import_picocolors10.default.dim("watching for new activity \u2026 (Ctrl-C to stop)")}
|
|
280473
280505
|
`);
|
|
280474
280506
|
for (; ; ) {
|
|
280475
280507
|
await sleep2(1500);
|
|
@@ -280486,8 +280518,8 @@ async function logs(argv) {
|
|
|
280486
280518
|
|
|
280487
280519
|
// src/cli/webhooks.ts
|
|
280488
280520
|
init_cjs_shims();
|
|
280489
|
-
var
|
|
280490
|
-
var
|
|
280521
|
+
var import_fs8 = require("fs");
|
|
280522
|
+
var import_picocolors11 = __toESM(require_picocolors(), 1);
|
|
280491
280523
|
var ENV_KEY = "ABLO_WEBHOOK_SECRET";
|
|
280492
280524
|
function flag(args, name) {
|
|
280493
280525
|
const inline = args.find((a) => a.startsWith(`${name}=`));
|
|
@@ -280514,12 +280546,12 @@ function requireKey(mode2) {
|
|
|
280514
280546
|
const apiKey = resolveApiKey(mode2);
|
|
280515
280547
|
if (!apiKey) {
|
|
280516
280548
|
console.error(
|
|
280517
|
-
|
|
280549
|
+
import_picocolors11.default.red(" No API key.") + import_picocolors11.default.dim(` Run ${import_picocolors11.default.bold("ablo login")} or set ${import_picocolors11.default.bold("ABLO_API_KEY")}.`)
|
|
280518
280550
|
);
|
|
280519
280551
|
process.exit(1);
|
|
280520
280552
|
}
|
|
280521
280553
|
if (!apiKey.startsWith("sk_")) {
|
|
280522
|
-
console.error(
|
|
280554
|
+
console.error(import_picocolors11.default.red(" Managing webhooks requires a secret key ") + import_picocolors11.default.dim("(sk_test_ / sk_live_)."));
|
|
280523
280555
|
process.exit(1);
|
|
280524
280556
|
}
|
|
280525
280557
|
return apiKey;
|
|
@@ -280535,22 +280567,22 @@ async function api(apiKey, method, path, body) {
|
|
|
280535
280567
|
...body ? { body: JSON.stringify(body) } : {}
|
|
280536
280568
|
}).catch(() => null);
|
|
280537
280569
|
if (!res) {
|
|
280538
|
-
console.error(
|
|
280570
|
+
console.error(import_picocolors11.default.red(` Couldn't reach ${baseUrl()}.`));
|
|
280539
280571
|
process.exit(1);
|
|
280540
280572
|
}
|
|
280541
280573
|
if (!res.ok) {
|
|
280542
280574
|
const err = await res.json().catch(() => ({}));
|
|
280543
|
-
console.error(
|
|
280575
|
+
console.error(import_picocolors11.default.red(` Request failed (${res.status}): ${err.message ?? err.reason ?? ""}`));
|
|
280544
280576
|
process.exit(1);
|
|
280545
280577
|
}
|
|
280546
280578
|
return await res.json();
|
|
280547
280579
|
}
|
|
280548
280580
|
function writeSecretToEnv(secret) {
|
|
280549
|
-
const file = (0,
|
|
280581
|
+
const file = (0, import_fs8.existsSync)(".env.local") ? ".env.local" : (0, import_fs8.existsSync)(".env") ? ".env" : ".env.local";
|
|
280550
280582
|
const line = `${ENV_KEY}=${secret}`;
|
|
280551
280583
|
let next;
|
|
280552
|
-
if ((0,
|
|
280553
|
-
const existing = (0,
|
|
280584
|
+
if ((0, import_fs8.existsSync)(file)) {
|
|
280585
|
+
const existing = (0, import_fs8.readFileSync)(file, "utf-8");
|
|
280554
280586
|
next = new RegExp(`^${ENV_KEY}=.*$`, "m").test(existing) ? existing.replace(new RegExp(`^${ENV_KEY}=.*$`, "m"), line) : `${existing.replace(/\n*$/, "")}
|
|
280555
280587
|
${line}
|
|
280556
280588
|
`;
|
|
@@ -280558,15 +280590,15 @@ ${line}
|
|
|
280558
280590
|
next = `${line}
|
|
280559
280591
|
`;
|
|
280560
280592
|
}
|
|
280561
|
-
(0,
|
|
280593
|
+
(0, import_fs8.writeFileSync)(file, next);
|
|
280562
280594
|
return file;
|
|
280563
280595
|
}
|
|
280564
280596
|
function printEndpoint(e2) {
|
|
280565
|
-
const dot = e2.status === "enabled" ?
|
|
280566
|
-
const health = e2.last_error ?
|
|
280567
|
-
console.log(` ${dot} ${
|
|
280597
|
+
const dot = e2.status === "enabled" ? import_picocolors11.default.green("\u25CF") : import_picocolors11.default.red("\u25CF");
|
|
280598
|
+
const health = e2.last_error ? import_picocolors11.default.red(` last error: ${e2.last_error}`) : "";
|
|
280599
|
+
console.log(` ${dot} ${import_picocolors11.default.bold(e2.id)} ${e2.url}`);
|
|
280568
280600
|
console.log(
|
|
280569
|
-
|
|
280601
|
+
import_picocolors11.default.dim(
|
|
280570
280602
|
` ${e2.status} \xB7 ${e2.environment} \xB7 events ${e2.enabled_events.join(",")} \xB7 cursor ${e2.cursor ?? "\u2014"}${health}`
|
|
280571
280603
|
)
|
|
280572
280604
|
);
|
|
@@ -280578,7 +280610,7 @@ async function webhooks(argv) {
|
|
|
280578
280610
|
if (sub === "create") {
|
|
280579
280611
|
const url = positional(rest);
|
|
280580
280612
|
if (!url) {
|
|
280581
|
-
console.error(
|
|
280613
|
+
console.error(import_picocolors11.default.red(" Usage: ") + brand("ablo webhooks create <url>"));
|
|
280582
280614
|
process.exit(1);
|
|
280583
280615
|
}
|
|
280584
280616
|
const apiKey = requireKey(mode2);
|
|
@@ -280590,8 +280622,8 @@ async function webhooks(argv) {
|
|
|
280590
280622
|
});
|
|
280591
280623
|
const file = writeSecretToEnv(created.secret);
|
|
280592
280624
|
console.log(`
|
|
280593
|
-
${
|
|
280594
|
-
console.log(` ${
|
|
280625
|
+
${import_picocolors11.default.green("\u2713")} Registered ${import_picocolors11.default.bold(created.id)} \u2192 ${created.url}`);
|
|
280626
|
+
console.log(` ${import_picocolors11.default.green("\u2713")} Wrote ${import_picocolors11.default.bold(ENV_KEY)} to ${import_picocolors11.default.bold(file)} ${import_picocolors11.default.dim("(shown once)")}
|
|
280595
280627
|
`);
|
|
280596
280628
|
return;
|
|
280597
280629
|
}
|
|
@@ -280599,7 +280631,7 @@ async function webhooks(argv) {
|
|
|
280599
280631
|
const apiKey = requireKey(mode2);
|
|
280600
280632
|
const { data } = await api(apiKey, "GET", "");
|
|
280601
280633
|
if (data.length === 0) {
|
|
280602
|
-
console.log(
|
|
280634
|
+
console.log(import_picocolors11.default.dim(" No webhook endpoints. ") + brand("ablo webhooks create <url>"));
|
|
280603
280635
|
return;
|
|
280604
280636
|
}
|
|
280605
280637
|
console.log();
|
|
@@ -280610,40 +280642,40 @@ async function webhooks(argv) {
|
|
|
280610
280642
|
if (sub === "roll") {
|
|
280611
280643
|
const id = positional(rest);
|
|
280612
280644
|
if (!id) {
|
|
280613
|
-
console.error(
|
|
280645
|
+
console.error(import_picocolors11.default.red(" Usage: ") + brand("ablo webhooks roll <id>"));
|
|
280614
280646
|
process.exit(1);
|
|
280615
280647
|
}
|
|
280616
280648
|
const apiKey = requireKey(mode2);
|
|
280617
280649
|
const rolled = await api(apiKey, "POST", `/${id}/roll_secret`);
|
|
280618
280650
|
const file = writeSecretToEnv(rolled.secret);
|
|
280619
280651
|
console.log(`
|
|
280620
|
-
${
|
|
280652
|
+
${import_picocolors11.default.green("\u2713")} Rolled secret for ${import_picocolors11.default.bold(id)} \u2192 ${import_picocolors11.default.bold(file)} ${import_picocolors11.default.dim("(old secret now invalid)")}
|
|
280621
280653
|
`);
|
|
280622
280654
|
return;
|
|
280623
280655
|
}
|
|
280624
280656
|
if (sub === "enable") {
|
|
280625
280657
|
const id = positional(rest);
|
|
280626
280658
|
if (!id) {
|
|
280627
|
-
console.error(
|
|
280659
|
+
console.error(import_picocolors11.default.red(" Usage: ") + brand("ablo webhooks enable <id>"));
|
|
280628
280660
|
process.exit(1);
|
|
280629
280661
|
}
|
|
280630
280662
|
const apiKey = requireKey(mode2);
|
|
280631
280663
|
const e2 = await api(apiKey, "POST", `/${id}/enable`);
|
|
280632
|
-
console.log(` ${
|
|
280664
|
+
console.log(` ${import_picocolors11.default.green("\u2713")} Re-enabled ${import_picocolors11.default.bold(e2.id)}`);
|
|
280633
280665
|
return;
|
|
280634
280666
|
}
|
|
280635
280667
|
if (sub === "rm" || sub === "delete") {
|
|
280636
280668
|
const id = positional(rest);
|
|
280637
280669
|
if (!id) {
|
|
280638
|
-
console.error(
|
|
280670
|
+
console.error(import_picocolors11.default.red(" Usage: ") + brand("ablo webhooks rm <id>"));
|
|
280639
280671
|
process.exit(1);
|
|
280640
280672
|
}
|
|
280641
280673
|
const apiKey = requireKey(mode2);
|
|
280642
280674
|
await api(apiKey, "DELETE", `/${id}`);
|
|
280643
|
-
console.log(` ${
|
|
280675
|
+
console.log(` ${import_picocolors11.default.green("\u2713")} Removed ${import_picocolors11.default.bold(id)}`);
|
|
280644
280676
|
return;
|
|
280645
280677
|
}
|
|
280646
|
-
console.log(` ${
|
|
280678
|
+
console.log(` ${import_picocolors11.default.bold("Usage:")}`);
|
|
280647
280679
|
console.log(` ${brand("ablo webhooks create <url>")} Register an endpoint; writes ${ENV_KEY}`);
|
|
280648
280680
|
console.log(` ${brand("ablo webhooks list")} List endpoints + delivery health`);
|
|
280649
280681
|
console.log(` ${brand("ablo webhooks roll <id>")} Mint a fresh signing secret`);
|
|
@@ -280654,7 +280686,7 @@ async function webhooks(argv) {
|
|
|
280654
280686
|
|
|
280655
280687
|
// src/cli/check.ts
|
|
280656
280688
|
init_cjs_shims();
|
|
280657
|
-
var
|
|
280689
|
+
var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
280658
280690
|
var import_schema5 = require("@abloatai/ablo/schema");
|
|
280659
280691
|
var DEFAULT_SCHEMA_PATH4 = "ablo/schema.ts";
|
|
280660
280692
|
var DEFAULT_EXPORT4 = "schema";
|
|
@@ -280689,13 +280721,13 @@ async function check(argv) {
|
|
|
280689
280721
|
try {
|
|
280690
280722
|
args = parseCheckArgs(argv);
|
|
280691
280723
|
} catch (err) {
|
|
280692
|
-
console.error(
|
|
280724
|
+
console.error(import_picocolors12.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
280693
280725
|
process.exit(1);
|
|
280694
280726
|
}
|
|
280695
280727
|
const dbUrl = process.env.DATABASE_URL ?? process.env.ABLO_DATABASE_URL;
|
|
280696
280728
|
if (!dbUrl) {
|
|
280697
280729
|
console.error(
|
|
280698
|
-
|
|
280730
|
+
import_picocolors12.default.red(` No database.`) + import_picocolors12.default.dim(` Set ${import_picocolors12.default.bold("DATABASE_URL")} to the Postgres you want Ablo to adopt.`)
|
|
280699
280731
|
);
|
|
280700
280732
|
process.exit(1);
|
|
280701
280733
|
}
|
|
@@ -280710,7 +280742,7 @@ async function check(argv) {
|
|
|
280710
280742
|
[args.appSchema]
|
|
280711
280743
|
);
|
|
280712
280744
|
} catch (err) {
|
|
280713
|
-
console.error(
|
|
280745
|
+
console.error(import_picocolors12.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
|
|
280714
280746
|
await sql.end({ timeout: 2 });
|
|
280715
280747
|
process.exit(1);
|
|
280716
280748
|
}
|
|
@@ -280725,7 +280757,7 @@ async function check(argv) {
|
|
|
280725
280757
|
set.add(r2.column_name);
|
|
280726
280758
|
}
|
|
280727
280759
|
console.log(`
|
|
280728
|
-
${brand("ablo")} ${
|
|
280760
|
+
${brand("ablo")} ${import_picocolors12.default.dim("check")} ${import_picocolors12.default.dim(`schema "${args.appSchema}"`)}
|
|
280729
280761
|
`);
|
|
280730
280762
|
const declaredTables = /* @__PURE__ */ new Set();
|
|
280731
280763
|
let errors = 0;
|
|
@@ -280735,7 +280767,7 @@ async function check(argv) {
|
|
|
280735
280767
|
declaredTables.add(table);
|
|
280736
280768
|
const present = colsByTable.get(table);
|
|
280737
280769
|
if (!present) {
|
|
280738
|
-
console.log(` ${
|
|
280770
|
+
console.log(` ${import_picocolors12.default.red("\u2717")} ${import_picocolors12.default.bold(key)} ${import_picocolors12.default.dim("\u2192")} table ${import_picocolors12.default.bold(table)} ${import_picocolors12.default.red("not found")}`);
|
|
280739
280771
|
errors++;
|
|
280740
280772
|
continue;
|
|
280741
280773
|
}
|
|
@@ -280757,26 +280789,26 @@ async function check(argv) {
|
|
|
280757
280789
|
if (!present.has(col)) problems.push(`missing column "${col}" (field ${fieldName})`);
|
|
280758
280790
|
}
|
|
280759
280791
|
if (problems.length > 0) {
|
|
280760
|
-
console.log(` ${
|
|
280761
|
-
for (const p2 of problems) console.log(` ${
|
|
280762
|
-
for (const w2 of warns) console.log(` ${
|
|
280792
|
+
console.log(` ${import_picocolors12.default.red("\u2717")} ${import_picocolors12.default.bold(key)} ${import_picocolors12.default.dim("\u2192")} ${table}`);
|
|
280793
|
+
for (const p2 of problems) console.log(` ${import_picocolors12.default.red("\u2022")} ${p2}`);
|
|
280794
|
+
for (const w2 of warns) console.log(` ${import_picocolors12.default.yellow("\u2022")} ${w2}`);
|
|
280763
280795
|
errors++;
|
|
280764
280796
|
} else if (warns.length > 0) {
|
|
280765
|
-
console.log(` ${
|
|
280766
|
-
for (const w2 of warns) console.log(` ${
|
|
280797
|
+
console.log(` ${import_picocolors12.default.yellow("!")} ${import_picocolors12.default.bold(key)} ${import_picocolors12.default.dim("\u2192")} ${table}`);
|
|
280798
|
+
for (const w2 of warns) console.log(` ${import_picocolors12.default.yellow("\u2022")} ${w2}`);
|
|
280767
280799
|
warnings++;
|
|
280768
280800
|
} else {
|
|
280769
|
-
console.log(` ${
|
|
280801
|
+
console.log(` ${import_picocolors12.default.green("\u2713")} ${import_picocolors12.default.bold(key)} ${import_picocolors12.default.dim(`\u2192 ${table} (id, ${orgCol ?? "no org"} ok)`)}`);
|
|
280770
280802
|
}
|
|
280771
280803
|
}
|
|
280772
280804
|
const modelCount = Object.keys(schemaJson.models).length;
|
|
280773
280805
|
const ignored = [...colsByTable.keys()].filter((t) => !declaredTables.has(t)).length;
|
|
280774
280806
|
console.log(
|
|
280775
280807
|
`
|
|
280776
|
-
${modelCount} model${modelCount === 1 ? "" : "s"} \xB7 ${
|
|
280808
|
+
${modelCount} model${modelCount === 1 ? "" : "s"} \xB7 ${import_picocolors12.default.green(`${modelCount - errors - warnings} ok`)}` + (warnings ? ` \xB7 ${import_picocolors12.default.yellow(`${warnings} warning${warnings === 1 ? "" : "s"}`)}` : "") + (errors ? ` \xB7 ${import_picocolors12.default.red(`${errors} error${errors === 1 ? "" : "s"}`)}` : "")
|
|
280777
280809
|
);
|
|
280778
280810
|
if (ignored > 0) {
|
|
280779
|
-
console.log(` ${
|
|
280811
|
+
console.log(` ${import_picocolors12.default.dim(`${ignored} other table${ignored === 1 ? "" : "s"} in your database \u2014 ignored by Ablo`)}`);
|
|
280780
280812
|
}
|
|
280781
280813
|
console.log();
|
|
280782
280814
|
process.exit(errors > 0 ? 1 : 0);
|
|
@@ -280784,7 +280816,7 @@ async function check(argv) {
|
|
|
280784
280816
|
|
|
280785
280817
|
// src/cli/upgrade.ts
|
|
280786
280818
|
init_cjs_shims();
|
|
280787
|
-
var
|
|
280819
|
+
var import_picocolors13 = __toESM(require_picocolors(), 1);
|
|
280788
280820
|
var import_ts_morph = __toESM(require_ts_morph(), 1);
|
|
280789
280821
|
var DEFAULT_GLOBS = ["app/**/*.{ts,tsx}", "src/**/*.{ts,tsx}", "ablo/**/*.{ts,tsx}", "lib/**/*.{ts,tsx}"];
|
|
280790
280822
|
var VERB_ARGS = {
|
|
@@ -280862,7 +280894,7 @@ async function upgrade(argv) {
|
|
|
280862
280894
|
project.addSourceFilesAtPaths(globs.length > 0 ? globs : DEFAULT_GLOBS);
|
|
280863
280895
|
const files = project.getSourceFiles();
|
|
280864
280896
|
if (files.length === 0) {
|
|
280865
|
-
console.log(
|
|
280897
|
+
console.log(import_picocolors13.default.yellow(' No .ts/.tsx files found. Pass a glob, e.g. `ablo upgrade "src/**/*.tsx"`.'));
|
|
280866
280898
|
return;
|
|
280867
280899
|
}
|
|
280868
280900
|
const edits = [];
|
|
@@ -280936,39 +280968,39 @@ async function upgrade(argv) {
|
|
|
280936
280968
|
const rel = (f) => f.replace(cwd + "/", "");
|
|
280937
280969
|
console.log();
|
|
280938
280970
|
if (edits.length === 0 && manual.length === 0) {
|
|
280939
|
-
console.log(
|
|
280971
|
+
console.log(import_picocolors13.default.green(" \u2713 Nothing to migrate \u2014 your code is already on the current API."));
|
|
280940
280972
|
return;
|
|
280941
280973
|
}
|
|
280942
280974
|
if (edits.length > 0) {
|
|
280943
|
-
console.log(
|
|
280975
|
+
console.log(import_picocolors13.default.bold(` ${write ? "Applied" : "Would apply"} ${edits.length} change${edits.length === 1 ? "" : "s"}:`));
|
|
280944
280976
|
for (const e2 of edits) {
|
|
280945
|
-
console.log(` ${
|
|
280946
|
-
console.log(` ${
|
|
280947
|
-
console.log(` ${
|
|
280977
|
+
console.log(` ${import_picocolors13.default.dim(`${rel(e2.file)}:${e2.line}`)} ${import_picocolors13.default.cyan(e2.rule)}`);
|
|
280978
|
+
console.log(` ${import_picocolors13.default.red("-")} ${e2.before}`);
|
|
280979
|
+
console.log(` ${import_picocolors13.default.green("+")} ${e2.after}`);
|
|
280948
280980
|
}
|
|
280949
280981
|
}
|
|
280950
280982
|
if (manual.length > 0) {
|
|
280951
280983
|
console.log();
|
|
280952
|
-
console.log(
|
|
280984
|
+
console.log(import_picocolors13.default.bold(import_picocolors13.default.yellow(` ${manual.length} spot${manual.length === 1 ? "" : "s"} need manual review (structural):`)));
|
|
280953
280985
|
for (const m2 of manual) {
|
|
280954
|
-
console.log(` ${
|
|
280955
|
-
console.log(` ${
|
|
280986
|
+
console.log(` ${import_picocolors13.default.dim(`${rel(m2.file)}:${m2.line}`)} ${import_picocolors13.default.yellow(m2.rule)}`);
|
|
280987
|
+
console.log(` ${import_picocolors13.default.dim(m2.snippet)}`);
|
|
280956
280988
|
console.log(` \u2192 ${m2.hint}`);
|
|
280957
280989
|
}
|
|
280958
280990
|
}
|
|
280959
280991
|
console.log();
|
|
280960
280992
|
if (write) {
|
|
280961
280993
|
await project.save();
|
|
280962
|
-
console.log(
|
|
280994
|
+
console.log(import_picocolors13.default.green(` \u2713 Wrote ${edits.length} change${edits.length === 1 ? "" : "s"}. Review the diff, run your typecheck.`));
|
|
280963
280995
|
} else {
|
|
280964
|
-
console.log(
|
|
280996
|
+
console.log(import_picocolors13.default.dim(" Dry run. Re-run with `--write` to apply the auto-fixes above (manual items are never auto-written)."));
|
|
280965
280997
|
}
|
|
280966
280998
|
}
|
|
280967
280999
|
|
|
280968
281000
|
// src/cli/pull.ts
|
|
280969
281001
|
init_cjs_shims();
|
|
280970
|
-
var
|
|
280971
|
-
var
|
|
281002
|
+
var import_picocolors14 = __toESM(require_picocolors(), 1);
|
|
281003
|
+
var import_fs9 = require("fs");
|
|
280972
281004
|
var DEFAULT_OUT2 = "ablo/schema.ts";
|
|
280973
281005
|
var DEFAULT_IMPORT = "@abloatai/ablo/schema";
|
|
280974
281006
|
var TENANCY_COLUMN = "organization_id";
|
|
@@ -281079,53 +281111,53 @@ async function pull(argv) {
|
|
|
281079
281111
|
try {
|
|
281080
281112
|
args = parsePullArgs(argv);
|
|
281081
281113
|
} catch (err) {
|
|
281082
|
-
console.error(
|
|
281114
|
+
console.error(import_picocolors14.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
281083
281115
|
process.exit(1);
|
|
281084
281116
|
}
|
|
281085
281117
|
const dbUrl = process.env.DATABASE_URL ?? process.env.ABLO_DATABASE_URL;
|
|
281086
281118
|
if (!dbUrl) {
|
|
281087
|
-
console.error(
|
|
281119
|
+
console.error(import_picocolors14.default.red(` No database.`) + import_picocolors14.default.dim(` Set ${import_picocolors14.default.bold("DATABASE_URL")} to the Postgres to pull from.`));
|
|
281088
281120
|
process.exit(1);
|
|
281089
281121
|
}
|
|
281090
|
-
if ((0,
|
|
281122
|
+
if ((0, import_fs9.existsSync)(args.out) && !args.force) {
|
|
281091
281123
|
console.error(
|
|
281092
|
-
|
|
281124
|
+
import_picocolors14.default.red(` ${args.out} already exists.`) + import_picocolors14.default.dim(` Re-run with ${import_picocolors14.default.bold("--force")} to overwrite.`)
|
|
281093
281125
|
);
|
|
281094
281126
|
process.exit(1);
|
|
281095
281127
|
}
|
|
281096
281128
|
console.log(`
|
|
281097
|
-
${brand("ablo")} ${
|
|
281129
|
+
${brand("ablo")} ${import_picocolors14.default.dim("pull")} ${import_picocolors14.default.dim(`schema "${args.appSchema}"`)}
|
|
281098
281130
|
`);
|
|
281099
281131
|
let result;
|
|
281100
281132
|
try {
|
|
281101
281133
|
result = await buildSchemaSourceFromDb({ dbUrl, appSchema: args.appSchema, importPath: args.importPath });
|
|
281102
281134
|
} catch (err) {
|
|
281103
|
-
console.error(
|
|
281135
|
+
console.error(import_picocolors14.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
|
|
281104
281136
|
process.exit(1);
|
|
281105
281137
|
}
|
|
281106
281138
|
if (result.models.length === 0) {
|
|
281107
281139
|
console.error(
|
|
281108
|
-
|
|
281140
|
+
import_picocolors14.default.yellow(` No adoptable tables found`) + import_picocolors14.default.dim(` (a model needs an ${import_picocolors14.default.bold("id")} + ${import_picocolors14.default.bold("organization_id")} column).`)
|
|
281109
281141
|
);
|
|
281110
281142
|
process.exit(1);
|
|
281111
281143
|
}
|
|
281112
|
-
(0,
|
|
281113
|
-
console.log(` ${
|
|
281114
|
-
console.log(` ${
|
|
281144
|
+
(0, import_fs9.writeFileSync)(args.out, result.source);
|
|
281145
|
+
console.log(` ${import_picocolors14.default.green("\u2713")} wrote ${import_picocolors14.default.bold(args.out)} ${import_picocolors14.default.dim(`(${result.models.length} models)`)}`);
|
|
281146
|
+
console.log(` ${import_picocolors14.default.dim(`models: ${result.models.join(", ")}`)}`);
|
|
281115
281147
|
if (result.skipped > 0) {
|
|
281116
|
-
console.log(` ${
|
|
281148
|
+
console.log(` ${import_picocolors14.default.dim(`${result.skipped} table(s) skipped \u2014 no id/organization_id`)}`);
|
|
281117
281149
|
}
|
|
281118
281150
|
console.log(
|
|
281119
281151
|
`
|
|
281120
|
-
${
|
|
281152
|
+
${import_picocolors14.default.dim("Introspection is lossy (enums, JSON shape, relations). Review the file, then")} ${import_picocolors14.default.bold("ablo check")}.
|
|
281121
281153
|
`
|
|
281122
281154
|
);
|
|
281123
281155
|
}
|
|
281124
281156
|
|
|
281125
281157
|
// src/cli/prisma-pull.ts
|
|
281126
281158
|
init_cjs_shims();
|
|
281127
|
-
var
|
|
281128
|
-
var
|
|
281159
|
+
var import_picocolors15 = __toESM(require_picocolors(), 1);
|
|
281160
|
+
var import_fs10 = require("fs");
|
|
281129
281161
|
|
|
281130
281162
|
// src/cli/schema-ir.ts
|
|
281131
281163
|
init_cjs_shims();
|
|
@@ -281402,56 +281434,56 @@ async function prismaPull(argv) {
|
|
|
281402
281434
|
try {
|
|
281403
281435
|
args = parsePrismaPullArgs(argv);
|
|
281404
281436
|
} catch (err) {
|
|
281405
|
-
console.error(
|
|
281437
|
+
console.error(import_picocolors15.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
281406
281438
|
process.exit(1);
|
|
281407
281439
|
}
|
|
281408
|
-
if (!(0,
|
|
281440
|
+
if (!(0, import_fs10.existsSync)(args.schema)) {
|
|
281409
281441
|
console.error(
|
|
281410
|
-
|
|
281442
|
+
import_picocolors15.default.red(` No Prisma schema at ${import_picocolors15.default.bold(args.schema)}.`) + import_picocolors15.default.dim(` Pass a path: ${import_picocolors15.default.bold("ablo pull prisma <path>")}.`)
|
|
281411
281443
|
);
|
|
281412
281444
|
process.exit(1);
|
|
281413
281445
|
}
|
|
281414
|
-
if ((0,
|
|
281446
|
+
if ((0, import_fs10.existsSync)(args.out) && !args.force) {
|
|
281415
281447
|
console.error(
|
|
281416
|
-
|
|
281448
|
+
import_picocolors15.default.red(` ${args.out} already exists.`) + import_picocolors15.default.dim(` Re-run with ${import_picocolors15.default.bold("--force")} to overwrite.`)
|
|
281417
281449
|
);
|
|
281418
281450
|
process.exit(1);
|
|
281419
281451
|
}
|
|
281420
281452
|
console.log(`
|
|
281421
|
-
${brand("ablo")} ${
|
|
281453
|
+
${brand("ablo")} ${import_picocolors15.default.dim("pull prisma")} ${import_picocolors15.default.dim(args.schema)}
|
|
281422
281454
|
`);
|
|
281423
281455
|
let result;
|
|
281424
281456
|
try {
|
|
281425
|
-
const src = (0,
|
|
281457
|
+
const src = (0, import_fs10.readFileSync)(args.schema, "utf8");
|
|
281426
281458
|
result = buildSchemaSourceFromPrisma({ src, importPath: args.importPath });
|
|
281427
281459
|
} catch (err) {
|
|
281428
|
-
console.error(
|
|
281460
|
+
console.error(import_picocolors15.default.red(` Couldn't parse the schema: ${err instanceof Error ? err.message : String(err)}`));
|
|
281429
281461
|
process.exit(1);
|
|
281430
281462
|
}
|
|
281431
281463
|
if (result.models.length === 0) {
|
|
281432
281464
|
console.error(
|
|
281433
|
-
|
|
281465
|
+
import_picocolors15.default.yellow(` No adoptable models found`) + import_picocolors15.default.dim(` (a model needs an ${import_picocolors15.default.bold("id")} + ${import_picocolors15.default.bold("organizationId")} / ${import_picocolors15.default.bold("organization_id")}).`)
|
|
281434
281466
|
);
|
|
281435
281467
|
process.exit(1);
|
|
281436
281468
|
}
|
|
281437
|
-
(0,
|
|
281438
|
-
console.log(` ${
|
|
281439
|
-
console.log(` ${
|
|
281469
|
+
(0, import_fs10.writeFileSync)(args.out, result.source);
|
|
281470
|
+
console.log(` ${import_picocolors15.default.green("\u2713")} wrote ${import_picocolors15.default.bold(args.out)} ${import_picocolors15.default.dim(`(${result.models.length} models)`)}`);
|
|
281471
|
+
console.log(` ${import_picocolors15.default.dim(`models: ${result.models.join(", ")}`)}`);
|
|
281440
281472
|
if (result.skipped.length > 0) {
|
|
281441
|
-
console.log(` ${
|
|
281442
|
-
for (const s of result.skipped) console.log(` ${
|
|
281473
|
+
console.log(` ${import_picocolors15.default.dim(`${result.skipped.length} model(s) skipped:`)}`);
|
|
281474
|
+
for (const s of result.skipped) console.log(` ${import_picocolors15.default.dim(`- ${s.name}: ${s.reason}`)}`);
|
|
281443
281475
|
}
|
|
281444
281476
|
console.log(
|
|
281445
281477
|
`
|
|
281446
|
-
${
|
|
281478
|
+
${import_picocolors15.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors15.default.bold("ablo check")}.
|
|
281447
281479
|
`
|
|
281448
281480
|
);
|
|
281449
281481
|
}
|
|
281450
281482
|
|
|
281451
281483
|
// src/cli/drizzle-pull.ts
|
|
281452
281484
|
init_cjs_shims();
|
|
281453
|
-
var
|
|
281454
|
-
var
|
|
281485
|
+
var import_picocolors16 = __toESM(require_picocolors(), 1);
|
|
281486
|
+
var import_fs11 = require("fs");
|
|
281455
281487
|
var import_path6 = require("path");
|
|
281456
281488
|
var DEFAULT_OUT4 = "ablo/schema.ts";
|
|
281457
281489
|
var DEFAULT_IMPORT3 = "@abloatai/ablo/schema";
|
|
@@ -281586,27 +281618,27 @@ async function drizzlePull(argv) {
|
|
|
281586
281618
|
try {
|
|
281587
281619
|
args = parseDrizzlePullArgs(argv);
|
|
281588
281620
|
} catch (err) {
|
|
281589
|
-
console.error(
|
|
281621
|
+
console.error(import_picocolors16.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
281590
281622
|
process.exit(1);
|
|
281591
281623
|
}
|
|
281592
281624
|
if (!args.schema) {
|
|
281593
281625
|
console.error(
|
|
281594
|
-
|
|
281626
|
+
import_picocolors16.default.red(` No Drizzle schema given.`) + import_picocolors16.default.dim(` Pass the module: ${import_picocolors16.default.bold("ablo pull drizzle src/db/schema.ts")}.`)
|
|
281595
281627
|
);
|
|
281596
281628
|
process.exit(1);
|
|
281597
281629
|
}
|
|
281598
|
-
if (!(0,
|
|
281599
|
-
console.error(
|
|
281630
|
+
if (!(0, import_fs11.existsSync)(args.schema)) {
|
|
281631
|
+
console.error(import_picocolors16.default.red(` No file at ${import_picocolors16.default.bold(args.schema)}.`));
|
|
281600
281632
|
process.exit(1);
|
|
281601
281633
|
}
|
|
281602
|
-
if ((0,
|
|
281634
|
+
if ((0, import_fs11.existsSync)(args.out) && !args.force) {
|
|
281603
281635
|
console.error(
|
|
281604
|
-
|
|
281636
|
+
import_picocolors16.default.red(` ${args.out} already exists.`) + import_picocolors16.default.dim(` Re-run with ${import_picocolors16.default.bold("--force")} to overwrite.`)
|
|
281605
281637
|
);
|
|
281606
281638
|
process.exit(1);
|
|
281607
281639
|
}
|
|
281608
281640
|
console.log(`
|
|
281609
|
-
${brand("ablo")} ${
|
|
281641
|
+
${brand("ablo")} ${import_picocolors16.default.dim("pull drizzle")} ${import_picocolors16.default.dim(args.schema)}
|
|
281610
281642
|
`);
|
|
281611
281643
|
let result;
|
|
281612
281644
|
try {
|
|
@@ -281614,33 +281646,33 @@ async function drizzlePull(argv) {
|
|
|
281614
281646
|
result = await buildSchemaSourceFromDrizzle({ mod, importPath: args.importPath });
|
|
281615
281647
|
} catch (err) {
|
|
281616
281648
|
const msg = err instanceof Error ? err.message : String(err);
|
|
281617
|
-
const hint = /Cannot find package 'drizzle-orm'/.test(msg) ?
|
|
281618
|
-
console.error(
|
|
281649
|
+
const hint = /Cannot find package 'drizzle-orm'/.test(msg) ? import_picocolors16.default.dim(` (install ${import_picocolors16.default.bold("drizzle-orm")} in this project)`) : "";
|
|
281650
|
+
console.error(import_picocolors16.default.red(` Couldn't load the schema: ${msg}`) + hint);
|
|
281619
281651
|
process.exit(1);
|
|
281620
281652
|
}
|
|
281621
281653
|
if (result.models.length === 0) {
|
|
281622
281654
|
console.error(
|
|
281623
|
-
|
|
281655
|
+
import_picocolors16.default.yellow(` No adoptable tables found`) + import_picocolors16.default.dim(` (a table needs an ${import_picocolors16.default.bold("id")} + ${import_picocolors16.default.bold("organization_id")} column).`)
|
|
281624
281656
|
);
|
|
281625
281657
|
process.exit(1);
|
|
281626
281658
|
}
|
|
281627
|
-
(0,
|
|
281628
|
-
console.log(` ${
|
|
281629
|
-
console.log(` ${
|
|
281659
|
+
(0, import_fs11.writeFileSync)(args.out, result.source);
|
|
281660
|
+
console.log(` ${import_picocolors16.default.green("\u2713")} wrote ${import_picocolors16.default.bold(args.out)} ${import_picocolors16.default.dim(`(${result.models.length} models)`)}`);
|
|
281661
|
+
console.log(` ${import_picocolors16.default.dim(`models: ${result.models.join(", ")}`)}`);
|
|
281630
281662
|
if (result.skipped.length > 0) {
|
|
281631
|
-
console.log(` ${
|
|
281632
|
-
for (const s of result.skipped) console.log(` ${
|
|
281663
|
+
console.log(` ${import_picocolors16.default.dim(`${result.skipped.length} table(s) skipped:`)}`);
|
|
281664
|
+
for (const s of result.skipped) console.log(` ${import_picocolors16.default.dim(`- ${s.name}: ${s.reason}`)}`);
|
|
281633
281665
|
}
|
|
281634
281666
|
console.log(
|
|
281635
281667
|
`
|
|
281636
|
-
${
|
|
281668
|
+
${import_picocolors16.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors16.default.bold("ablo check")}.
|
|
281637
281669
|
`
|
|
281638
281670
|
);
|
|
281639
281671
|
}
|
|
281640
281672
|
|
|
281641
281673
|
// src/cli/index.ts
|
|
281642
281674
|
var LOGO = `
|
|
281643
|
-
${brand("ablo")} ${
|
|
281675
|
+
${brand("ablo")} ${import_picocolors17.default.dim("sync engine")}
|
|
281644
281676
|
`;
|
|
281645
281677
|
async function main() {
|
|
281646
281678
|
const command = process.argv[2];
|
|
@@ -281659,7 +281691,8 @@ async function main() {
|
|
|
281659
281691
|
} else if (command === "webhooks") {
|
|
281660
281692
|
await webhooks(process.argv.slice(3));
|
|
281661
281693
|
} else if (command === "dev") {
|
|
281662
|
-
|
|
281694
|
+
console.log(import_picocolors17.default.dim(" `ablo dev` is now `ablo push --watch` \u2014 running that."));
|
|
281695
|
+
await dev([...process.argv.slice(3), "--watch"]);
|
|
281663
281696
|
} else if (command === "check") {
|
|
281664
281697
|
await check(process.argv.slice(3));
|
|
281665
281698
|
} else if (command === "pull") {
|
|
@@ -281674,20 +281707,27 @@ async function main() {
|
|
|
281674
281707
|
} else if (command === "migrate") {
|
|
281675
281708
|
await migrate(process.argv.slice(3));
|
|
281676
281709
|
} else if (command === "push") {
|
|
281677
|
-
|
|
281710
|
+
const rest = process.argv.slice(3);
|
|
281711
|
+
const advanced = rest.some((a) => ["--force", "--rename", "--backfill", "--url"].includes(a));
|
|
281712
|
+
const liveKey = (process.env.ABLO_API_KEY ?? "").startsWith("sk_live_");
|
|
281713
|
+
if (advanced || liveKey) {
|
|
281714
|
+
await push(rest);
|
|
281715
|
+
} else {
|
|
281716
|
+
await dev(rest);
|
|
281717
|
+
}
|
|
281678
281718
|
} else if (command === "upgrade") {
|
|
281679
281719
|
await upgrade(process.argv.slice(3));
|
|
281680
281720
|
} else if (command === "generate") {
|
|
281681
281721
|
await generate(process.argv.slice(3));
|
|
281682
281722
|
} else if (command === "schema") {
|
|
281683
281723
|
console.error(
|
|
281684
|
-
` ${
|
|
281724
|
+
` ${import_picocolors17.default.red("\u2717")} \`ablo schema push\` was renamed to \`${brand("ablo push")}\`.`
|
|
281685
281725
|
);
|
|
281686
281726
|
console.error(` Run \`ablo push${process.argv.slice(4).join(" ") ? " " + process.argv.slice(4).join(" ") : ""}\` instead.`);
|
|
281687
281727
|
process.exitCode = 1;
|
|
281688
281728
|
} else {
|
|
281689
281729
|
console.log(LOGO);
|
|
281690
|
-
console.log(` ${
|
|
281730
|
+
console.log(` ${import_picocolors17.default.bold("Usage:")}`);
|
|
281691
281731
|
console.log(` npx ablo init Scaffold ablo/ directory + starter schema`);
|
|
281692
281732
|
console.log(` npx ablo init --yes [--framework nextjs] Non-interactive (agents/CI): no prompts, flag-driven`);
|
|
281693
281733
|
console.log(` [--auth apikey] [--storage direct|endpoint] [--no-agent] [--no-pull] [--no-install] [--no-login]`);
|
|
@@ -281712,10 +281752,10 @@ async function main() {
|
|
|
281712
281752
|
console.log(` npx ablo generate Emit TypeScript types from your schema`);
|
|
281713
281753
|
console.log(` npx ablo generate --out path.ts Write generated types to a path`);
|
|
281714
281754
|
console.log();
|
|
281715
|
-
console.log(` ${
|
|
281755
|
+
console.log(` ${import_picocolors17.default.bold("Schema workflow:")}`);
|
|
281716
281756
|
console.log(` The server holds its own copy of your schema \u2014 edit ${brand("ablo/schema.ts")}, then`);
|
|
281717
281757
|
console.log(` run ${brand("ablo push")} (or keep ${brand("ablo dev")} running) before the server will accept`);
|
|
281718
|
-
console.log(` writes to new or changed models. Skip it and writes fail with ${
|
|
281758
|
+
console.log(` writes to new or changed models. Skip it and writes fail with ${import_picocolors17.default.yellow("server_execute_unknown_model")}.`);
|
|
281719
281759
|
console.log();
|
|
281720
281760
|
}
|
|
281721
281761
|
}
|
|
@@ -281752,7 +281792,7 @@ function parseInitArgs(args) {
|
|
|
281752
281792
|
function detectOrm(override) {
|
|
281753
281793
|
if (override === "prisma" || override === "drizzle" || override === "none") return override;
|
|
281754
281794
|
try {
|
|
281755
|
-
const pkg = JSON.parse((0,
|
|
281795
|
+
const pkg = JSON.parse((0, import_fs12.readFileSync)("package.json", "utf-8"));
|
|
281756
281796
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
281757
281797
|
if (deps["@prisma/client"] || deps["prisma"]) return "prisma";
|
|
281758
281798
|
if (deps["drizzle-orm"]) return "drizzle";
|
|
@@ -281783,8 +281823,8 @@ async function chooseBool(flagValue, fallback, interactive, prompt) {
|
|
|
281783
281823
|
async function init(args = []) {
|
|
281784
281824
|
const opts = parseInitArgs(args);
|
|
281785
281825
|
const interactive = Boolean(process.stdin.isTTY) && !opts.yes && !process.env.CI;
|
|
281786
|
-
Ie(`${brand("ablo")} ${
|
|
281787
|
-
if (!(0,
|
|
281826
|
+
Ie(`${brand("ablo")} ${import_picocolors17.default.dim("sync engine")}`);
|
|
281827
|
+
if (!(0, import_fs12.existsSync)("package.json")) {
|
|
281788
281828
|
xe("No package.json found. Run this from your project root.");
|
|
281789
281829
|
process.exit(1);
|
|
281790
281830
|
}
|
|
@@ -281860,14 +281900,14 @@ async function init(args = []) {
|
|
|
281860
281900
|
);
|
|
281861
281901
|
}
|
|
281862
281902
|
const abloDir = "ablo";
|
|
281863
|
-
(0,
|
|
281903
|
+
(0, import_fs12.mkdirSync)(abloDir, { recursive: true });
|
|
281864
281904
|
const created = [];
|
|
281865
281905
|
let schemaSource = generateSchema();
|
|
281866
281906
|
let schemaNote = "";
|
|
281867
281907
|
if (pullExisting) {
|
|
281868
281908
|
const dbUrl = process.env.DATABASE_URL ?? process.env.ABLO_DATABASE_URL;
|
|
281869
281909
|
if (!dbUrl) {
|
|
281870
|
-
schemaNote =
|
|
281910
|
+
schemaNote = import_picocolors17.default.dim(" (no DATABASE_URL \u2014 wrote starter; run `ablo pull` later)");
|
|
281871
281911
|
} else {
|
|
281872
281912
|
try {
|
|
281873
281913
|
const pulled = await buildSchemaSourceFromDb({
|
|
@@ -281877,60 +281917,60 @@ async function init(args = []) {
|
|
|
281877
281917
|
});
|
|
281878
281918
|
if (pulled.models.length > 0) {
|
|
281879
281919
|
schemaSource = pulled.source;
|
|
281880
|
-
schemaNote =
|
|
281920
|
+
schemaNote = import_picocolors17.default.dim(` (pulled ${pulled.models.length} models)`);
|
|
281881
281921
|
} else {
|
|
281882
|
-
schemaNote =
|
|
281922
|
+
schemaNote = import_picocolors17.default.dim(" (no adoptable tables \u2014 wrote starter)");
|
|
281883
281923
|
}
|
|
281884
281924
|
} catch {
|
|
281885
|
-
schemaNote =
|
|
281925
|
+
schemaNote = import_picocolors17.default.dim(" (pull failed \u2014 wrote starter)");
|
|
281886
281926
|
}
|
|
281887
281927
|
}
|
|
281888
281928
|
}
|
|
281889
|
-
(0,
|
|
281929
|
+
(0, import_fs12.writeFileSync)((0, import_path7.join)(abloDir, "schema.ts"), schemaSource);
|
|
281890
281930
|
created.push(`${abloDir}/schema.ts${schemaNote}`);
|
|
281891
|
-
(0,
|
|
281931
|
+
(0, import_fs12.writeFileSync)((0, import_path7.join)(abloDir, "index.ts"), generateSyncConfig(auth, storage));
|
|
281892
281932
|
created.push(`${abloDir}/index.ts`);
|
|
281893
281933
|
const orm = detectOrm(opts.orm);
|
|
281894
281934
|
if (storage === "endpoint") {
|
|
281895
|
-
(0,
|
|
281935
|
+
(0, import_fs12.writeFileSync)((0, import_path7.join)(abloDir, "data-source.ts"), generateDataSource(orm));
|
|
281896
281936
|
created.push(`${abloDir}/data-source.ts${orm === "drizzle" ? " (Drizzle)" : " (Prisma)"}`);
|
|
281897
281937
|
}
|
|
281898
281938
|
const envFile = framework === "nextjs" ? ".env.local" : ".env";
|
|
281899
|
-
if (!(0,
|
|
281900
|
-
(0,
|
|
281939
|
+
if (!(0, import_fs12.existsSync)(envFile)) {
|
|
281940
|
+
(0, import_fs12.writeFileSync)(envFile, generateEnv(storage));
|
|
281901
281941
|
created.push(envFile);
|
|
281902
281942
|
} else {
|
|
281903
|
-
const existing = (0,
|
|
281943
|
+
const existing = (0, import_fs12.readFileSync)(envFile, "utf-8");
|
|
281904
281944
|
if (!existing.includes("ABLO_")) {
|
|
281905
|
-
(0,
|
|
281906
|
-
created.push(`${envFile} ${
|
|
281945
|
+
(0, import_fs12.writeFileSync)(envFile, existing + "\n" + generateEnv(storage));
|
|
281946
|
+
created.push(`${envFile} ${import_picocolors17.default.dim("(appended)")}`);
|
|
281907
281947
|
} else {
|
|
281908
|
-
created.push(`${envFile} ${
|
|
281948
|
+
created.push(`${envFile} ${import_picocolors17.default.dim("(already configured)")}`);
|
|
281909
281949
|
}
|
|
281910
281950
|
}
|
|
281911
281951
|
if (agent) {
|
|
281912
|
-
(0,
|
|
281952
|
+
(0, import_fs12.writeFileSync)((0, import_path7.join)(abloDir, "agent.ts"), generateAgent());
|
|
281913
281953
|
created.push(`${abloDir}/agent.ts`);
|
|
281914
281954
|
}
|
|
281915
281955
|
if (framework === "nextjs") {
|
|
281916
281956
|
if (storage === "endpoint") {
|
|
281917
281957
|
const webhookDir = (0, import_path7.join)("app", "api", "ablo", "webhooks");
|
|
281918
|
-
(0,
|
|
281919
|
-
(0,
|
|
281958
|
+
(0, import_fs12.mkdirSync)(webhookDir, { recursive: true });
|
|
281959
|
+
(0, import_fs12.writeFileSync)((0, import_path7.join)(webhookDir, "route.ts"), generateWebhookRoute(orm));
|
|
281920
281960
|
created.push(`${webhookDir}/route.ts${orm === "prisma" ? " (Prisma mirror)" : " (add your database write)"}`);
|
|
281921
281961
|
}
|
|
281922
|
-
(0,
|
|
281923
|
-
created.push(`app/providers.tsx ${
|
|
281962
|
+
(0, import_fs12.writeFileSync)((0, import_path7.join)("app", "providers.tsx"), generateProviders());
|
|
281963
|
+
created.push(`app/providers.tsx ${import_picocolors17.default.dim("(wrap app/layout.tsx in <Providers>)")}`);
|
|
281924
281964
|
const sessionDir = (0, import_path7.join)("app", "api", "ablo-session");
|
|
281925
|
-
(0,
|
|
281926
|
-
(0,
|
|
281927
|
-
created.push(`app/api/ablo-session/route.ts ${
|
|
281965
|
+
(0, import_fs12.mkdirSync)(sessionDir, { recursive: true });
|
|
281966
|
+
(0, import_fs12.writeFileSync)((0, import_path7.join)(sessionDir, "route.ts"), generateSessionRoute());
|
|
281967
|
+
created.push(`app/api/ablo-session/route.ts ${import_picocolors17.default.dim("(wire your auth)")}`);
|
|
281928
281968
|
}
|
|
281929
281969
|
if (framework !== "vanilla") {
|
|
281930
|
-
(0,
|
|
281970
|
+
(0, import_fs12.writeFileSync)((0, import_path7.join)(abloDir, "TaskList.tsx"), generateComponent());
|
|
281931
281971
|
created.push(`${abloDir}/TaskList.tsx`);
|
|
281932
281972
|
}
|
|
281933
|
-
Me(created.map((f) => `${
|
|
281973
|
+
Me(created.map((f) => `${import_picocolors17.default.green("\u2713")} ${f}`).join("\n"), "Created");
|
|
281934
281974
|
const pm = detectPackageManager();
|
|
281935
281975
|
if (opts.install) {
|
|
281936
281976
|
const s = Y2();
|
|
@@ -281939,38 +281979,43 @@ async function init(args = []) {
|
|
|
281939
281979
|
(0, import_child_process2.execSync)(`${pm} add @abloatai/ablo`, { stdio: "ignore" });
|
|
281940
281980
|
s.stop("Installed @abloatai/ablo");
|
|
281941
281981
|
} catch {
|
|
281942
|
-
s.stop(`${
|
|
281982
|
+
s.stop(`${import_picocolors17.default.yellow("!")} Couldn't auto-install \u2014 run ${import_picocolors17.default.bold(`${pm} install @abloatai/ablo`)}`);
|
|
281943
281983
|
}
|
|
281944
281984
|
}
|
|
281945
281985
|
const steps = [
|
|
281946
|
-
`Get a ${
|
|
281947
|
-
`Run ${
|
|
281948
|
-
`Set ${
|
|
281949
|
-
`Run ${
|
|
281986
|
+
`Get a ${import_picocolors17.default.bold("sk_test_")} key at ${import_picocolors17.default.cyan("https://abloatai.com")}`,
|
|
281987
|
+
`Run ${import_picocolors17.default.bold("npx ablo login")} (or add ${import_picocolors17.default.bold("ABLO_API_KEY")} to ${import_picocolors17.default.bold(envFile)})`,
|
|
281988
|
+
`Set ${import_picocolors17.default.bold("DATABASE_URL")} in ${import_picocolors17.default.bold(envFile)} \u2014 your Postgres is the system of record; rows live there, never with Ablo`,
|
|
281989
|
+
`Run ${import_picocolors17.default.bold("npx ablo dev")} \u2014 pushes your schema definition and watches for changes`,
|
|
281950
281990
|
...storage === "direct" ? [
|
|
281951
|
-
`Provision your DB: ${
|
|
281991
|
+
`Provision your DB: ${import_picocolors17.default.bold("npx ablo migrate")} (creates your synced-model tables with row-level security; keep your own migrations for everything else)`
|
|
281952
281992
|
] : [
|
|
281953
|
-
`Provision your DB: ${
|
|
281993
|
+
`Provision your DB: ${import_picocolors17.default.bold("npx ablo migrate")} (creates your Ablo-model tables + the adapter tables; keep your own migrations for everything else), then mount ${import_picocolors17.default.bold(`${abloDir}/data-source.ts`)} at ${import_picocolors17.default.bold("/api/ablo/source")}`
|
|
281954
281994
|
],
|
|
281955
281995
|
...framework === "nextjs" ? [
|
|
281956
|
-
`Wrap ${
|
|
281996
|
+
`Wrap ${import_picocolors17.default.bold("app/layout.tsx")} in ${import_picocolors17.default.bold("<Providers>")} (app/providers.tsx) and add your auth to ${import_picocolors17.default.bold("app/api/ablo-session/route.ts")}`
|
|
281957
281997
|
] : [],
|
|
281958
|
-
`Run ${
|
|
281998
|
+
`Run ${import_picocolors17.default.bold(`${pm} run dev`)} and open two browser tabs \u2014 changes sync in real-time`,
|
|
281959
281999
|
...agent ? [
|
|
281960
|
-
`Run ${
|
|
281961
|
-
`Run ${
|
|
282000
|
+
`Run ${import_picocolors17.default.bold(`npx tsx ${abloDir}/agent.ts`)} \u2014 an AI teammate edits the same tasks`,
|
|
282001
|
+
`Run ${import_picocolors17.default.bold("npx ablo logs")} to watch human + agent commits stream by`
|
|
281962
282002
|
] : []
|
|
281963
282003
|
];
|
|
281964
282004
|
Me(steps.map((s, i) => `${i + 1}. ${s}`).join("\n"), "Next steps");
|
|
282005
|
+
const existingKey = resolveApiKey("sandbox");
|
|
282006
|
+
if (existingKey) {
|
|
282007
|
+
Se(`Already authorized ${import_picocolors17.default.dim(`(${existingKey.slice(0, 11)}\u2026)`)} \u2014 run ${import_picocolors17.default.bold("npx ablo push")} next. ${import_picocolors17.default.dim("Docs:")} https://abloatai.com/docs`);
|
|
282008
|
+
return;
|
|
282009
|
+
}
|
|
281965
282010
|
if (interactive && opts.login) {
|
|
281966
282011
|
const loginNow = await ye({ message: "Log in now? (opens your browser)", initialValue: true });
|
|
281967
282012
|
if (!pD(loginNow) && loginNow) {
|
|
281968
|
-
Se(`${
|
|
282013
|
+
Se(`${import_picocolors17.default.dim("Docs:")} https://abloatai.com/docs`);
|
|
281969
282014
|
await login();
|
|
281970
282015
|
return;
|
|
281971
282016
|
}
|
|
281972
282017
|
}
|
|
281973
|
-
Se(`Run ${
|
|
282018
|
+
Se(`Run ${import_picocolors17.default.bold("npx ablo login")} when ready. ${import_picocolors17.default.dim("Docs:")} https://abloatai.com/docs`);
|
|
281974
282019
|
}
|
|
281975
282020
|
function generateSchema() {
|
|
281976
282021
|
return `import { defineSchema, model, relation, z } from '@abloatai/ablo/schema';
|
|
@@ -282324,9 +282369,9 @@ async function getCurrentUser(): Promise<{ id: string } | null> {
|
|
|
282324
282369
|
`;
|
|
282325
282370
|
}
|
|
282326
282371
|
function detectPackageManager() {
|
|
282327
|
-
if ((0,
|
|
282328
|
-
if ((0,
|
|
282329
|
-
if ((0,
|
|
282372
|
+
if ((0, import_fs12.existsSync)("pnpm-lock.yaml")) return "pnpm";
|
|
282373
|
+
if ((0, import_fs12.existsSync)("yarn.lock")) return "yarn";
|
|
282374
|
+
if ((0, import_fs12.existsSync)("bun.lockb")) return "bun";
|
|
282330
282375
|
return "npm";
|
|
282331
282376
|
}
|
|
282332
282377
|
main().catch(console.error);
|