@abloatai/ablo 0.9.4 → 0.9.6
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 +563 -363
- 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.d.ts +1 -0
- package/dist/errorCodes.js +16 -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 +45 -14
- package/llms-full.txt +10 -1
- package/llms.txt +5 -3
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -125060,7 +125060,7 @@ ${lanes.join("\n")}
|
|
|
125060
125060
|
}
|
|
125061
125061
|
}
|
|
125062
125062
|
function createImportCallExpressionAMD(arg, containsLexicalThis) {
|
|
125063
|
-
const
|
|
125063
|
+
const resolve6 = factory2.createUniqueName("resolve");
|
|
125064
125064
|
const reject = factory2.createUniqueName("reject");
|
|
125065
125065
|
const parameters = [
|
|
125066
125066
|
factory2.createParameterDeclaration(
|
|
@@ -125069,7 +125069,7 @@ ${lanes.join("\n")}
|
|
|
125069
125069
|
/*dotDotDotToken*/
|
|
125070
125070
|
void 0,
|
|
125071
125071
|
/*name*/
|
|
125072
|
-
|
|
125072
|
+
resolve6
|
|
125073
125073
|
),
|
|
125074
125074
|
factory2.createParameterDeclaration(
|
|
125075
125075
|
/*modifiers*/
|
|
@@ -125086,7 +125086,7 @@ ${lanes.join("\n")}
|
|
|
125086
125086
|
factory2.createIdentifier("require"),
|
|
125087
125087
|
/*typeArguments*/
|
|
125088
125088
|
void 0,
|
|
125089
|
-
[factory2.createArrayLiteralExpression([arg || factory2.createOmittedExpression()]),
|
|
125089
|
+
[factory2.createArrayLiteralExpression([arg || factory2.createOmittedExpression()]), resolve6, reject]
|
|
125090
125090
|
)
|
|
125091
125091
|
)
|
|
125092
125092
|
]);
|
|
@@ -211695,8 +211695,8 @@ Additional information: BADCLIENT: Bad error code, ${badCode} not found in range
|
|
|
211695
211695
|
installPackage(options) {
|
|
211696
211696
|
this.packageInstallId++;
|
|
211697
211697
|
const request = { kind: "installPackage", ...options, id: this.packageInstallId };
|
|
211698
|
-
const promise = new Promise((
|
|
211699
|
-
(this.packageInstalledPromise ?? (this.packageInstalledPromise = /* @__PURE__ */ new Map())).set(this.packageInstallId, { resolve:
|
|
211698
|
+
const promise = new Promise((resolve6, reject) => {
|
|
211699
|
+
(this.packageInstalledPromise ?? (this.packageInstalledPromise = /* @__PURE__ */ new Map())).set(this.packageInstallId, { resolve: resolve6, reject });
|
|
211700
211700
|
});
|
|
211701
211701
|
this.installer.send(request);
|
|
211702
211702
|
return promise;
|
|
@@ -213965,7 +213965,7 @@ var require_path_browserify = __commonJS({
|
|
|
213965
213965
|
}
|
|
213966
213966
|
var posix = {
|
|
213967
213967
|
// path.resolve([from ...], to)
|
|
213968
|
-
resolve: function
|
|
213968
|
+
resolve: function resolve6() {
|
|
213969
213969
|
var resolvedPath = "";
|
|
213970
213970
|
var resolvedAbsolute = false;
|
|
213971
213971
|
var cwd;
|
|
@@ -218865,41 +218865,41 @@ var require_queue = __commonJS({
|
|
|
218865
218865
|
queue.drained = drained;
|
|
218866
218866
|
return queue;
|
|
218867
218867
|
function push2(value) {
|
|
218868
|
-
var p2 = new Promise(function(
|
|
218868
|
+
var p2 = new Promise(function(resolve6, reject) {
|
|
218869
218869
|
pushCb(value, function(err, result) {
|
|
218870
218870
|
if (err) {
|
|
218871
218871
|
reject(err);
|
|
218872
218872
|
return;
|
|
218873
218873
|
}
|
|
218874
|
-
|
|
218874
|
+
resolve6(result);
|
|
218875
218875
|
});
|
|
218876
218876
|
});
|
|
218877
218877
|
p2.catch(noop3);
|
|
218878
218878
|
return p2;
|
|
218879
218879
|
}
|
|
218880
218880
|
function unshift(value) {
|
|
218881
|
-
var p2 = new Promise(function(
|
|
218881
|
+
var p2 = new Promise(function(resolve6, reject) {
|
|
218882
218882
|
unshiftCb(value, function(err, result) {
|
|
218883
218883
|
if (err) {
|
|
218884
218884
|
reject(err);
|
|
218885
218885
|
return;
|
|
218886
218886
|
}
|
|
218887
|
-
|
|
218887
|
+
resolve6(result);
|
|
218888
218888
|
});
|
|
218889
218889
|
});
|
|
218890
218890
|
p2.catch(noop3);
|
|
218891
218891
|
return p2;
|
|
218892
218892
|
}
|
|
218893
218893
|
function drained() {
|
|
218894
|
-
var p2 = new Promise(function(
|
|
218894
|
+
var p2 = new Promise(function(resolve6) {
|
|
218895
218895
|
process.nextTick(function() {
|
|
218896
218896
|
if (queue.idle()) {
|
|
218897
|
-
|
|
218897
|
+
resolve6();
|
|
218898
218898
|
} else {
|
|
218899
218899
|
var previousDrain = queue.drain;
|
|
218900
218900
|
queue.drain = function() {
|
|
218901
218901
|
if (typeof previousDrain === "function") previousDrain();
|
|
218902
|
-
|
|
218902
|
+
resolve6();
|
|
218903
218903
|
queue.drain = previousDrain;
|
|
218904
218904
|
};
|
|
218905
218905
|
}
|
|
@@ -219396,9 +219396,9 @@ var require_stream3 = __commonJS({
|
|
|
219396
219396
|
});
|
|
219397
219397
|
}
|
|
219398
219398
|
_getStat(filepath) {
|
|
219399
|
-
return new Promise((
|
|
219399
|
+
return new Promise((resolve6, reject) => {
|
|
219400
219400
|
this._stat(filepath, this._fsStatSettings, (error, stats) => {
|
|
219401
|
-
return error === null ?
|
|
219401
|
+
return error === null ? resolve6(stats) : reject(error);
|
|
219402
219402
|
});
|
|
219403
219403
|
});
|
|
219404
219404
|
}
|
|
@@ -219423,10 +219423,10 @@ var require_async5 = __commonJS({
|
|
|
219423
219423
|
this._readerStream = new stream_1.default(this._settings);
|
|
219424
219424
|
}
|
|
219425
219425
|
dynamic(root, options) {
|
|
219426
|
-
return new Promise((
|
|
219426
|
+
return new Promise((resolve6, reject) => {
|
|
219427
219427
|
this._walkAsync(root, options, (error, entries) => {
|
|
219428
219428
|
if (error === null) {
|
|
219429
|
-
|
|
219429
|
+
resolve6(entries);
|
|
219430
219430
|
} else {
|
|
219431
219431
|
reject(error);
|
|
219432
219432
|
}
|
|
@@ -219436,10 +219436,10 @@ var require_async5 = __commonJS({
|
|
|
219436
219436
|
async static(patterns, options) {
|
|
219437
219437
|
const entries = [];
|
|
219438
219438
|
const stream = this._readerStream.static(patterns, options);
|
|
219439
|
-
return new Promise((
|
|
219439
|
+
return new Promise((resolve6, reject) => {
|
|
219440
219440
|
stream.once("error", reject);
|
|
219441
219441
|
stream.on("data", (entry) => entries.push(entry));
|
|
219442
|
-
stream.once("end", () =>
|
|
219442
|
+
stream.once("end", () => resolve6(entries));
|
|
219443
219443
|
});
|
|
219444
219444
|
}
|
|
219445
219445
|
};
|
|
@@ -252345,12 +252345,12 @@ type XMLHttpRequestResponseType = "" | "arraybuffer" | "blob" | "document" | "js
|
|
|
252345
252345
|
};
|
|
252346
252346
|
var NodeRuntimeFileSystem = class {
|
|
252347
252347
|
delete(path2) {
|
|
252348
|
-
return new Promise((
|
|
252348
|
+
return new Promise((resolve6, reject) => {
|
|
252349
252349
|
fs__namespace.rm(path2, { recursive: true }, (err) => {
|
|
252350
252350
|
if (err)
|
|
252351
252351
|
reject(err);
|
|
252352
252352
|
else
|
|
252353
|
-
|
|
252353
|
+
resolve6();
|
|
252354
252354
|
});
|
|
252355
252355
|
});
|
|
252356
252356
|
}
|
|
@@ -252369,12 +252369,12 @@ type XMLHttpRequestResponseType = "" | "arraybuffer" | "blob" | "document" | "js
|
|
|
252369
252369
|
}));
|
|
252370
252370
|
}
|
|
252371
252371
|
readFile(filePath, encoding = "utf-8") {
|
|
252372
|
-
return new Promise((
|
|
252372
|
+
return new Promise((resolve6, reject) => {
|
|
252373
252373
|
fs__namespace.readFile(filePath, encoding, (err, data) => {
|
|
252374
252374
|
if (err)
|
|
252375
252375
|
reject(err);
|
|
252376
252376
|
else
|
|
252377
|
-
|
|
252377
|
+
resolve6(data);
|
|
252378
252378
|
});
|
|
252379
252379
|
});
|
|
252380
252380
|
}
|
|
@@ -252382,12 +252382,12 @@ type XMLHttpRequestResponseType = "" | "arraybuffer" | "blob" | "document" | "js
|
|
|
252382
252382
|
return fs__namespace.readFileSync(filePath, encoding);
|
|
252383
252383
|
}
|
|
252384
252384
|
async writeFile(filePath, fileText) {
|
|
252385
|
-
await new Promise((
|
|
252385
|
+
await new Promise((resolve6, reject) => {
|
|
252386
252386
|
fs__namespace.writeFile(filePath, fileText, (err) => {
|
|
252387
252387
|
if (err)
|
|
252388
252388
|
reject(err);
|
|
252389
252389
|
else
|
|
252390
|
-
|
|
252390
|
+
resolve6();
|
|
252391
252391
|
});
|
|
252392
252392
|
});
|
|
252393
252393
|
}
|
|
@@ -252401,12 +252401,12 @@ type XMLHttpRequestResponseType = "" | "arraybuffer" | "blob" | "document" | "js
|
|
|
252401
252401
|
fs__namespace.mkdirSync(dirPath, { recursive: true });
|
|
252402
252402
|
}
|
|
252403
252403
|
move(srcPath, destPath) {
|
|
252404
|
-
return new Promise((
|
|
252404
|
+
return new Promise((resolve6, reject) => {
|
|
252405
252405
|
fs__namespace.rename(srcPath, destPath, (err) => {
|
|
252406
252406
|
if (err)
|
|
252407
252407
|
reject(err);
|
|
252408
252408
|
else
|
|
252409
|
-
|
|
252409
|
+
resolve6();
|
|
252410
252410
|
});
|
|
252411
252411
|
});
|
|
252412
252412
|
}
|
|
@@ -252414,12 +252414,12 @@ type XMLHttpRequestResponseType = "" | "arraybuffer" | "blob" | "document" | "js
|
|
|
252414
252414
|
fs__namespace.renameSync(srcPath, destPath);
|
|
252415
252415
|
}
|
|
252416
252416
|
copy(srcPath, destPath) {
|
|
252417
|
-
return new Promise((
|
|
252417
|
+
return new Promise((resolve6, reject) => {
|
|
252418
252418
|
fs__namespace.copyFile(srcPath, destPath, (err) => {
|
|
252419
252419
|
if (err)
|
|
252420
252420
|
reject(err);
|
|
252421
252421
|
else
|
|
252422
|
-
|
|
252422
|
+
resolve6();
|
|
252423
252423
|
});
|
|
252424
252424
|
});
|
|
252425
252425
|
}
|
|
@@ -252427,15 +252427,15 @@ type XMLHttpRequestResponseType = "" | "arraybuffer" | "blob" | "document" | "js
|
|
|
252427
252427
|
fs__namespace.copyFileSync(srcPath, destPath);
|
|
252428
252428
|
}
|
|
252429
252429
|
stat(path2) {
|
|
252430
|
-
return new Promise((
|
|
252430
|
+
return new Promise((resolve6, reject) => {
|
|
252431
252431
|
fs__namespace.stat(path2, (err, stat) => {
|
|
252432
252432
|
if (err) {
|
|
252433
252433
|
if (err.code === "ENOENT" || err.code === "ENOTDIR")
|
|
252434
|
-
|
|
252434
|
+
resolve6(void 0);
|
|
252435
252435
|
else
|
|
252436
252436
|
reject(err);
|
|
252437
252437
|
} else {
|
|
252438
|
-
|
|
252438
|
+
resolve6(stat);
|
|
252439
252439
|
}
|
|
252440
252440
|
});
|
|
252441
252441
|
});
|
|
@@ -276700,9 +276700,9 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
|
|
|
276700
276700
|
};
|
|
276701
276701
|
|
|
276702
276702
|
// src/cli/index.ts
|
|
276703
|
-
var
|
|
276704
|
-
var
|
|
276705
|
-
var
|
|
276703
|
+
var import_picocolors17 = __toESM(require_picocolors(), 1);
|
|
276704
|
+
var import_fs12 = require("fs");
|
|
276705
|
+
var import_path7 = require("path");
|
|
276706
276706
|
var import_child_process2 = require("child_process");
|
|
276707
276707
|
|
|
276708
276708
|
// src/cli/migrate.ts
|
|
@@ -276775,6 +276775,7 @@ var ERROR_CODES = {
|
|
|
276775
276775
|
issuer_register_forbidden: wire("permission", 403, false, "Registering a trusted issuer requires a secret (sk_) API key."),
|
|
276776
276776
|
capability_invalid: wire("capability", 403, false, "The capability is unknown, revoked, or expired."),
|
|
276777
276777
|
test_database_not_registered: wire("permission", 403, false, "Test mode requires a registered dev database for this org \u2014 run `npx ablo init`, or construct the client with `databaseUrl` using your test key."),
|
|
276778
|
+
tenant_routing_failed: wire("server", 500, true, "The org's registered database could not be resolved or dialed. Ablo never falls back to shared storage for a dedicated tenant \u2014 retry, and check the datasource status if it persists."),
|
|
276778
276779
|
database_role_cannot_enforce_rls: wire("permission", 403, false, "The connected database role cannot enforce row-level security (superuser or BYPASSRLS)."),
|
|
276779
276780
|
database_role_unreadable: wire("permission", 403, false, "The connected database role could not be introspected."),
|
|
276780
276781
|
database_tables_unforced_rls: wire("permission", 403, false, "Synced tables in the connected database do not have FORCE ROW LEVEL SECURITY applied."),
|
|
@@ -276786,13 +276787,22 @@ var ERROR_CODES = {
|
|
|
276786
276787
|
byo_tenant_tables_unforced_rls: wire("permission", 403, false, "Tenant tables do not have RLS forced under the direct Postgres connector role."),
|
|
276787
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."),
|
|
276788
276789
|
// ── claim / intent conflict (409) ──────────────────────────────────
|
|
276789
|
-
|
|
276790
|
-
|
|
276791
|
-
|
|
276792
|
-
|
|
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)."),
|
|
276793
276803
|
malformed_claim: wire("claim", 400, false, "The claim payload was malformed."),
|
|
276794
|
-
model_claimed: wire("claim", 409,
|
|
276795
|
-
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."),
|
|
276796
276806
|
model_claim_not_configured: client("claim", "Claiming was requested on a model that has no claim configuration."),
|
|
276797
276807
|
// ── stale context / idempotency (409) ──────────────────────────────
|
|
276798
276808
|
stale_context: wire("conflict", 409, true, "The write carried a readAt watermark that is now stale; re-read and retry."),
|
|
@@ -277087,8 +277097,8 @@ var ErrorBodyShapeSchema = import_zod2.z.object({
|
|
|
277087
277097
|
}).passthrough();
|
|
277088
277098
|
|
|
277089
277099
|
// src/cli/migrate.ts
|
|
277090
|
-
var
|
|
277091
|
-
var
|
|
277100
|
+
var import_picocolors4 = __toESM(require_picocolors(), 1);
|
|
277101
|
+
var import_fs5 = require("fs");
|
|
277092
277102
|
|
|
277093
277103
|
// node_modules/postgres/src/index.js
|
|
277094
277104
|
init_cjs_shims();
|
|
@@ -277106,9 +277116,9 @@ var originError = /* @__PURE__ */ Symbol("OriginError");
|
|
|
277106
277116
|
var CLOSE = {};
|
|
277107
277117
|
var Query = class extends Promise {
|
|
277108
277118
|
constructor(strings, args, handler, canceller, options = {}) {
|
|
277109
|
-
let
|
|
277119
|
+
let resolve6, reject;
|
|
277110
277120
|
super((a, b4) => {
|
|
277111
|
-
|
|
277121
|
+
resolve6 = a;
|
|
277112
277122
|
reject = b4;
|
|
277113
277123
|
});
|
|
277114
277124
|
this.tagged = Array.isArray(strings.raw);
|
|
@@ -277119,7 +277129,7 @@ var Query = class extends Promise {
|
|
|
277119
277129
|
this.options = options;
|
|
277120
277130
|
this.state = null;
|
|
277121
277131
|
this.statement = null;
|
|
277122
|
-
this.resolve = (x2) => (this.active = false,
|
|
277132
|
+
this.resolve = (x2) => (this.active = false, resolve6(x2));
|
|
277123
277133
|
this.reject = (x2) => (this.active = false, reject(x2));
|
|
277124
277134
|
this.active = false;
|
|
277125
277135
|
this.cancelled = null;
|
|
@@ -277167,12 +277177,12 @@ var Query = class extends Promise {
|
|
|
277167
277177
|
if (this.executed && !this.active)
|
|
277168
277178
|
return { done: true };
|
|
277169
277179
|
prev && prev();
|
|
277170
|
-
const promise = new Promise((
|
|
277180
|
+
const promise = new Promise((resolve6, reject) => {
|
|
277171
277181
|
this.cursorFn = (value) => {
|
|
277172
|
-
|
|
277182
|
+
resolve6({ value, done: false });
|
|
277173
277183
|
return new Promise((r2) => prev = r2);
|
|
277174
277184
|
};
|
|
277175
|
-
this.resolve = () => (this.active = false,
|
|
277185
|
+
this.resolve = () => (this.active = false, resolve6({ done: true }));
|
|
277176
277186
|
this.reject = (x2) => (this.active = false, reject(x2));
|
|
277177
277187
|
});
|
|
277178
277188
|
this.execute();
|
|
@@ -277804,12 +277814,12 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
|
|
|
277804
277814
|
x2.on("drain", drain);
|
|
277805
277815
|
return x2;
|
|
277806
277816
|
}
|
|
277807
|
-
async function cancel({ pid, secret },
|
|
277817
|
+
async function cancel({ pid, secret }, resolve6, reject) {
|
|
277808
277818
|
try {
|
|
277809
277819
|
cancelMessage = bytes_default().i32(16).i32(80877102).i32(pid).i32(secret).end(16);
|
|
277810
277820
|
await connect();
|
|
277811
277821
|
socket.once("error", reject);
|
|
277812
|
-
socket.once("close",
|
|
277822
|
+
socket.once("close", resolve6);
|
|
277813
277823
|
} catch (error2) {
|
|
277814
277824
|
reject(error2);
|
|
277815
277825
|
}
|
|
@@ -278758,7 +278768,7 @@ function parseEvent(x2) {
|
|
|
278758
278768
|
init_cjs_shims();
|
|
278759
278769
|
var import_stream2 = __toESM(require("stream"), 1);
|
|
278760
278770
|
function largeObject(sql, oid, mode2 = 131072 | 262144) {
|
|
278761
|
-
return new Promise(async (
|
|
278771
|
+
return new Promise(async (resolve6, reject) => {
|
|
278762
278772
|
await sql.begin(async (sql2) => {
|
|
278763
278773
|
let finish;
|
|
278764
278774
|
!oid && ([{ oid }] = await sql2`select lo_creat(-1) as oid`);
|
|
@@ -278784,7 +278794,7 @@ function largeObject(sql, oid, mode2 = 131072 | 262144) {
|
|
|
278784
278794
|
) seek
|
|
278785
278795
|
`
|
|
278786
278796
|
};
|
|
278787
|
-
|
|
278797
|
+
resolve6(lo);
|
|
278788
278798
|
return new Promise(async (r2) => finish = r2);
|
|
278789
278799
|
async function readable({
|
|
278790
278800
|
highWaterMark = 2048 * 8,
|
|
@@ -278958,8 +278968,8 @@ function Postgres(a, b4) {
|
|
|
278958
278968
|
}
|
|
278959
278969
|
async function reserve() {
|
|
278960
278970
|
const queue = queue_default();
|
|
278961
|
-
const c = open.length ? open.shift() : await new Promise((
|
|
278962
|
-
const query = { reserve:
|
|
278971
|
+
const c = open.length ? open.shift() : await new Promise((resolve6, reject) => {
|
|
278972
|
+
const query = { reserve: resolve6, reject };
|
|
278963
278973
|
queries.push(query);
|
|
278964
278974
|
closed.length && connect(closed.shift(), query);
|
|
278965
278975
|
});
|
|
@@ -278996,9 +279006,9 @@ function Postgres(a, b4) {
|
|
|
278996
279006
|
let uncaughtError, result;
|
|
278997
279007
|
name && await sql2`savepoint ${sql2(name)}`;
|
|
278998
279008
|
try {
|
|
278999
|
-
result = await new Promise((
|
|
279009
|
+
result = await new Promise((resolve6, reject) => {
|
|
279000
279010
|
const x2 = fn2(sql2);
|
|
279001
|
-
Promise.resolve(Array.isArray(x2) ? Promise.all(x2) : x2).then(
|
|
279011
|
+
Promise.resolve(Array.isArray(x2) ? Promise.all(x2) : x2).then(resolve6, reject);
|
|
279002
279012
|
});
|
|
279003
279013
|
if (uncaughtError)
|
|
279004
279014
|
throw uncaughtError;
|
|
@@ -279055,8 +279065,8 @@ function Postgres(a, b4) {
|
|
|
279055
279065
|
return c.execute(query) ? move(c, busy) : move(c, full);
|
|
279056
279066
|
}
|
|
279057
279067
|
function cancel(query) {
|
|
279058
|
-
return new Promise((
|
|
279059
|
-
query.state ? query.active ? connection_default(options).cancel(query.state,
|
|
279068
|
+
return new Promise((resolve6, reject) => {
|
|
279069
|
+
query.state ? query.active ? connection_default(options).cancel(query.state, resolve6, reject) : query.cancelled = { resolve: resolve6, reject } : (queries.remove(query), query.cancelled = true, query.reject(Errors.generic("57014", "canceling statement due to user request")), resolve6());
|
|
279060
279070
|
});
|
|
279061
279071
|
}
|
|
279062
279072
|
async function end({ timeout = null } = {}) {
|
|
@@ -279075,11 +279085,11 @@ function Postgres(a, b4) {
|
|
|
279075
279085
|
async function close() {
|
|
279076
279086
|
await Promise.all(connections.map((c) => c.end()));
|
|
279077
279087
|
}
|
|
279078
|
-
async function destroy(
|
|
279088
|
+
async function destroy(resolve6) {
|
|
279079
279089
|
await Promise.all(connections.map((c) => c.terminate()));
|
|
279080
279090
|
while (queries.length)
|
|
279081
279091
|
queries.shift().reject(Errors.connection("CONNECTION_DESTROYED", options));
|
|
279082
|
-
|
|
279092
|
+
resolve6();
|
|
279083
279093
|
}
|
|
279084
279094
|
function connect(c, query) {
|
|
279085
279095
|
move(c, connecting);
|
|
@@ -279224,32 +279234,198 @@ function osUsername() {
|
|
|
279224
279234
|
}
|
|
279225
279235
|
}
|
|
279226
279236
|
|
|
279237
|
+
// src/cli/dbRole.ts
|
|
279238
|
+
init_cjs_shims();
|
|
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");
|
|
279243
|
+
var DEFAULT_SCOPED_ROLE = "ablo_app";
|
|
279244
|
+
async function detectRoleSafety(sql) {
|
|
279245
|
+
const rows = await sql`SELECT rolname, rolsuper, rolbypassrls FROM pg_roles WHERE rolname = current_user`;
|
|
279246
|
+
const row = rows[0];
|
|
279247
|
+
if (!row) return { role: "unknown", superuser: false, bypassRls: false, unsafe: false };
|
|
279248
|
+
return {
|
|
279249
|
+
role: row.rolname,
|
|
279250
|
+
superuser: row.rolsuper,
|
|
279251
|
+
bypassRls: row.rolbypassrls,
|
|
279252
|
+
unsafe: row.rolsuper || row.rolbypassrls
|
|
279253
|
+
};
|
|
279254
|
+
}
|
|
279255
|
+
function generateRolePassword() {
|
|
279256
|
+
return (0, import_crypto2.randomBytes)(24).toString("base64url");
|
|
279257
|
+
}
|
|
279258
|
+
function scramSha256Verifier(password, iterations = 4096) {
|
|
279259
|
+
const salt = (0, import_crypto2.randomBytes)(16);
|
|
279260
|
+
const saltedPassword = (0, import_crypto2.pbkdf2Sync)(password, salt, iterations, 32, "sha256");
|
|
279261
|
+
const clientKey = (0, import_crypto2.createHmac)("sha256", saltedPassword).update("Client Key").digest();
|
|
279262
|
+
const storedKey = (0, import_crypto2.createHash)("sha256").update(clientKey).digest();
|
|
279263
|
+
const serverKey = (0, import_crypto2.createHmac)("sha256", saltedPassword).update("Server Key").digest();
|
|
279264
|
+
return `SCRAM-SHA-256$${iterations}:${salt.toString("base64")}$${storedKey.toString("base64")}:${serverKey.toString("base64")}`;
|
|
279265
|
+
}
|
|
279266
|
+
function scopedRoleStatements(input) {
|
|
279267
|
+
const role = input.role ?? DEFAULT_SCOPED_ROLE;
|
|
279268
|
+
const q2 = (id) => `"${id.replace(/"/g, '""')}"`;
|
|
279269
|
+
const pw = (input.passwordMode ?? "scram-verifier") === "scram-verifier" ? scramSha256Verifier(input.password) : input.password.replace(/'/g, "''");
|
|
279270
|
+
return [
|
|
279271
|
+
`DO $$ BEGIN
|
|
279272
|
+
CREATE ROLE ${q2(role)} LOGIN PASSWORD '${pw}'
|
|
279273
|
+
NOSUPERUSER NOBYPASSRLS NOCREATEDB NOCREATEROLE;
|
|
279274
|
+
EXCEPTION WHEN duplicate_object THEN
|
|
279275
|
+
-- Rerun: rotate ONLY the password. Re-asserting attributes here trips
|
|
279276
|
+
-- managed-Postgres permission walls (Neon: "permission denied to alter
|
|
279277
|
+
-- role" for attribute changes by non-superusers); the attributes were set
|
|
279278
|
+
-- at creation, and the server-side probe still audits the live role.
|
|
279279
|
+
ALTER ROLE ${q2(role)} WITH LOGIN PASSWORD '${pw}';
|
|
279280
|
+
END $$;`,
|
|
279281
|
+
`GRANT CREATE, CONNECT ON DATABASE ${q2(input.database)} TO ${q2(role)};`,
|
|
279282
|
+
`GRANT CREATE, USAGE ON SCHEMA public TO ${q2(role)};`
|
|
279283
|
+
];
|
|
279284
|
+
}
|
|
279285
|
+
function rewriteDatabaseUrl(ownerUrl, role, password) {
|
|
279286
|
+
const url = new URL(ownerUrl);
|
|
279287
|
+
url.username = role;
|
|
279288
|
+
url.password = password;
|
|
279289
|
+
return url.toString();
|
|
279290
|
+
}
|
|
279291
|
+
async function createScopedRole(ownerUrl, options) {
|
|
279292
|
+
const role = options?.role ?? DEFAULT_SCOPED_ROLE;
|
|
279293
|
+
const password = generateRolePassword();
|
|
279294
|
+
const database = new URL(ownerUrl).pathname.replace(/^\//, "") || "postgres";
|
|
279295
|
+
const sql = src_default(ownerUrl, { max: 1, prepare: false, onnotice: () => {
|
|
279296
|
+
} });
|
|
279297
|
+
try {
|
|
279298
|
+
try {
|
|
279299
|
+
for (const statement of scopedRoleStatements({ database, role, password })) {
|
|
279300
|
+
await sql.unsafe(statement);
|
|
279301
|
+
}
|
|
279302
|
+
} catch (err) {
|
|
279303
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
279304
|
+
if (!/plaintext password/i.test(message)) throw err;
|
|
279305
|
+
for (const statement of scopedRoleStatements({ database, role, password, passwordMode: "plaintext" })) {
|
|
279306
|
+
await sql.unsafe(statement);
|
|
279307
|
+
}
|
|
279308
|
+
}
|
|
279309
|
+
} finally {
|
|
279310
|
+
await sql.end({ timeout: 5 });
|
|
279311
|
+
}
|
|
279312
|
+
return { role, databaseUrl: rewriteDatabaseUrl(ownerUrl, role, password) };
|
|
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
|
+
}
|
|
279402
|
+
|
|
279227
279403
|
// src/cli/migrate.ts
|
|
279228
279404
|
var import_schema2 = require("@abloatai/ablo/schema");
|
|
279229
279405
|
var import_source = require("@abloatai/ablo/source");
|
|
279230
279406
|
|
|
279231
279407
|
// src/cli/push.ts
|
|
279232
279408
|
init_cjs_shims();
|
|
279233
|
-
var
|
|
279234
|
-
var
|
|
279235
|
-
var
|
|
279409
|
+
var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
279410
|
+
var import_fs4 = require("fs");
|
|
279411
|
+
var import_path3 = require("path");
|
|
279236
279412
|
var import_schema = require("@abloatai/ablo/schema");
|
|
279237
279413
|
|
|
279238
279414
|
// src/cli/config.ts
|
|
279239
279415
|
init_cjs_shims();
|
|
279240
279416
|
var import_os2 = require("os");
|
|
279241
|
-
var
|
|
279242
|
-
var
|
|
279417
|
+
var import_path2 = require("path");
|
|
279418
|
+
var import_fs3 = require("fs");
|
|
279243
279419
|
function configDir() {
|
|
279244
279420
|
if (process.env.ABLO_CONFIG_DIR) return process.env.ABLO_CONFIG_DIR;
|
|
279245
279421
|
const xdg = process.env.XDG_CONFIG_HOME;
|
|
279246
|
-
return xdg ? (0,
|
|
279422
|
+
return xdg ? (0, import_path2.join)(xdg, "ablo") : (0, import_path2.join)((0, import_os2.homedir)(), ".config", "ablo");
|
|
279247
279423
|
}
|
|
279248
279424
|
function configPath() {
|
|
279249
|
-
return (0,
|
|
279425
|
+
return (0, import_path2.join)(configDir(), "config.json");
|
|
279250
279426
|
}
|
|
279251
279427
|
function credentialsPath() {
|
|
279252
|
-
return (0,
|
|
279428
|
+
return (0, import_path2.join)(configDir(), "credentials.json");
|
|
279253
279429
|
}
|
|
279254
279430
|
function asKeyEntry(value) {
|
|
279255
279431
|
if (value && typeof value === "object" && typeof value.apiKey === "string") {
|
|
@@ -279258,9 +279434,9 @@ function asKeyEntry(value) {
|
|
|
279258
279434
|
return void 0;
|
|
279259
279435
|
}
|
|
279260
279436
|
function readJson(path) {
|
|
279261
|
-
if (!(0,
|
|
279437
|
+
if (!(0, import_fs3.existsSync)(path)) return null;
|
|
279262
279438
|
try {
|
|
279263
|
-
const parsed = JSON.parse((0,
|
|
279439
|
+
const parsed = JSON.parse((0, import_fs3.readFileSync)(path, "utf-8"));
|
|
279264
279440
|
return parsed && typeof parsed === "object" ? parsed : null;
|
|
279265
279441
|
} catch {
|
|
279266
279442
|
return null;
|
|
@@ -279297,14 +279473,14 @@ function readConfig() {
|
|
|
279297
279473
|
}
|
|
279298
279474
|
function writeConfig(cfg) {
|
|
279299
279475
|
const dir = configDir();
|
|
279300
|
-
(0,
|
|
279301
|
-
(0,
|
|
279476
|
+
(0, import_fs3.mkdirSync)(dir, { recursive: true, mode: 448 });
|
|
279477
|
+
(0, import_fs3.writeFileSync)(configPath(), `${JSON.stringify({ mode: cfg.mode }, null, 2)}
|
|
279302
279478
|
`, { mode: 384 });
|
|
279303
279479
|
const credentials = {
|
|
279304
279480
|
...cfg.sandbox ? { sandbox: cfg.sandbox } : {},
|
|
279305
279481
|
...cfg.production ? { production: cfg.production } : {}
|
|
279306
279482
|
};
|
|
279307
|
-
(0,
|
|
279483
|
+
(0, import_fs3.writeFileSync)(credentialsPath(), `${JSON.stringify(credentials, null, 2)}
|
|
279308
279484
|
`, { mode: 384 });
|
|
279309
279485
|
return credentialsPath();
|
|
279310
279486
|
}
|
|
@@ -279325,8 +279501,8 @@ function normalizeMode(value) {
|
|
|
279325
279501
|
function clearCredential() {
|
|
279326
279502
|
let removed = false;
|
|
279327
279503
|
for (const path of [configPath(), credentialsPath()]) {
|
|
279328
|
-
if ((0,
|
|
279329
|
-
(0,
|
|
279504
|
+
if ((0, import_fs3.existsSync)(path)) {
|
|
279505
|
+
(0, import_fs3.rmSync)(path);
|
|
279330
279506
|
removed = true;
|
|
279331
279507
|
}
|
|
279332
279508
|
}
|
|
@@ -279355,7 +279531,7 @@ var DEFAULT_URL = "https://api.abloatai.com";
|
|
|
279355
279531
|
function fmtSignal(s) {
|
|
279356
279532
|
const sig = s;
|
|
279357
279533
|
const where = sig.field ? `${sig.model}.${sig.field}` : sig.model;
|
|
279358
|
-
return ` \u2022 ${
|
|
279534
|
+
return ` \u2022 ${import_picocolors3.default.bold(where ?? "?")} \u2014 ${sig.detail ?? ""}`;
|
|
279359
279535
|
}
|
|
279360
279536
|
async function pushSchema(schema, args) {
|
|
279361
279537
|
const schemaJson = JSON.parse((0, import_schema.serializeSchema)(schema));
|
|
@@ -279433,10 +279609,10 @@ function parsePushArgs(argv) {
|
|
|
279433
279609
|
return { schemaPath, exportName, url, apiKey: process.env.ABLO_API_KEY, force, renames, backfills };
|
|
279434
279610
|
}
|
|
279435
279611
|
async function loadSchema(schemaPath, exportName) {
|
|
279436
|
-
const abs = (0,
|
|
279437
|
-
if (!(0,
|
|
279612
|
+
const abs = (0, import_path3.resolve)(process.cwd(), schemaPath);
|
|
279613
|
+
if (!(0, import_fs4.existsSync)(abs)) {
|
|
279438
279614
|
throw new AbloValidationError(
|
|
279439
|
-
`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>")}.`,
|
|
279440
279616
|
{ code: "cli_invalid_arguments" }
|
|
279441
279617
|
);
|
|
279442
279618
|
}
|
|
@@ -279447,7 +279623,7 @@ async function loadSchema(schemaPath, exportName) {
|
|
|
279447
279623
|
const schema = mod[exportName] ?? nested?.[exportName];
|
|
279448
279624
|
if (!schema || typeof schema !== "object" || !("models" in schema)) {
|
|
279449
279625
|
throw new AbloValidationError(
|
|
279450
|
-
`${
|
|
279626
|
+
`${import_picocolors3.default.bold(schemaPath)} has no \`${exportName}\` export that looks like a Schema. Did you \`export const ${exportName} = defineSchema({ ... })\`?`,
|
|
279451
279627
|
{ code: "cli_invalid_arguments" }
|
|
279452
279628
|
);
|
|
279453
279629
|
}
|
|
@@ -279458,30 +279634,30 @@ async function push(argv) {
|
|
|
279458
279634
|
try {
|
|
279459
279635
|
args = parsePushArgs(argv);
|
|
279460
279636
|
} catch (err) {
|
|
279461
|
-
console.error(
|
|
279637
|
+
console.error(import_picocolors3.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
279462
279638
|
process.exit(1);
|
|
279463
279639
|
}
|
|
279464
279640
|
if (!args.apiKey) args.apiKey = resolveApiKey();
|
|
279465
279641
|
if (!args.apiKey) {
|
|
279466
279642
|
console.error(
|
|
279467
|
-
|
|
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).`)
|
|
279468
279644
|
);
|
|
279469
279645
|
process.exit(1);
|
|
279470
279646
|
}
|
|
279471
279647
|
const schema = await loadSchema(args.schemaPath, args.exportName);
|
|
279472
279648
|
const hash = (0, import_schema.schemaHash)(schema);
|
|
279473
279649
|
console.log(
|
|
279474
|
-
` 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)}`
|
|
279475
279651
|
);
|
|
279476
279652
|
const { ok: resOk, status: status2, body, bodyText } = await pushSchema(schema, args);
|
|
279477
279653
|
if (resOk) {
|
|
279478
279654
|
if (body.unchanged) {
|
|
279479
|
-
console.log(` ${
|
|
279655
|
+
console.log(` ${import_picocolors3.default.dim("\u25CB")} No changes \u2014 schema already active (v${body.version}).`);
|
|
279480
279656
|
} else {
|
|
279481
|
-
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})`)}`);
|
|
279482
279658
|
if (Array.isArray(body.warnings) && body.warnings.length > 0) {
|
|
279483
|
-
console.log(
|
|
279484
|
-
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)));
|
|
279485
279661
|
}
|
|
279486
279662
|
}
|
|
279487
279663
|
return;
|
|
@@ -279489,20 +279665,20 @@ async function push(argv) {
|
|
|
279489
279665
|
if (status2 === 409) {
|
|
279490
279666
|
const unexecutable = Array.isArray(body.unexecutable) ? body.unexecutable : [];
|
|
279491
279667
|
const warnings = Array.isArray(body.warnings) ? body.warnings : [];
|
|
279492
|
-
console.error(
|
|
279668
|
+
console.error(import_picocolors3.default.red(" Incompatible change \u2014 this push is not safe to apply as-is."));
|
|
279493
279669
|
if (unexecutable.length > 0) {
|
|
279494
|
-
console.error(
|
|
279495
|
-
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)));
|
|
279496
279672
|
}
|
|
279497
279673
|
if (warnings.length > 0) {
|
|
279498
|
-
console.error(
|
|
279499
|
-
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)));
|
|
279500
279676
|
}
|
|
279501
|
-
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.`));
|
|
279502
279678
|
} else if (status2 === 403) {
|
|
279503
|
-
console.error(
|
|
279679
|
+
console.error(import_picocolors3.default.red(` Forbidden: ${body.message ?? body.reason ?? "key lacks schema:push scope"}`));
|
|
279504
279680
|
} else {
|
|
279505
|
-
console.error(
|
|
279681
|
+
console.error(import_picocolors3.default.red(` Push failed (${status2}): ${body.message ?? body.reason ?? bodyText}`));
|
|
279506
279682
|
}
|
|
279507
279683
|
process.exit(1);
|
|
279508
279684
|
}
|
|
@@ -279550,8 +279726,8 @@ function planFor(schema, targetSchema = "public") {
|
|
|
279550
279726
|
}
|
|
279551
279727
|
var log = {
|
|
279552
279728
|
info: (msg, fields) => console.log(`[migrate] ${msg}`, fields),
|
|
279553
|
-
warn: (msg, fields) => console.warn(
|
|
279554
|
-
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)
|
|
279555
279731
|
};
|
|
279556
279732
|
var PG_LOCK_NOT_AVAILABLE = "55P03";
|
|
279557
279733
|
var LOCK_TIMEOUT = process.env.ABLO_SCHEMA_LOCK_TIMEOUT ?? process.env.ABLO_DDL_LOCK_TIMEOUT ?? "5s";
|
|
@@ -279595,7 +279771,7 @@ async function applyStatements(dbUrl, targetSchema, statements, concurrent = [])
|
|
|
279595
279771
|
if (pg.code === PG_LOCK_NOT_AVAILABLE && attempt < MAX_LOCK_ATTEMPTS) {
|
|
279596
279772
|
const backoffMs = Math.min(6e4, 10 * 2 ** attempt) + Math.floor(Math.random() * 50);
|
|
279597
279773
|
log.warn("schema change blocked by a lock; backing off and retrying", { targetSchema, attempt, backoffMs });
|
|
279598
|
-
await new Promise((
|
|
279774
|
+
await new Promise((resolve6) => setTimeout(resolve6, backoffMs));
|
|
279599
279775
|
continue;
|
|
279600
279776
|
}
|
|
279601
279777
|
throw err;
|
|
@@ -279626,7 +279802,7 @@ async function migrate(argv) {
|
|
|
279626
279802
|
try {
|
|
279627
279803
|
args = parseMigrateArgs(argv);
|
|
279628
279804
|
} catch (err) {
|
|
279629
|
-
console.error(
|
|
279805
|
+
console.error(import_picocolors4.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
279630
279806
|
process.exit(1);
|
|
279631
279807
|
}
|
|
279632
279808
|
const schema = await loadSchema(args.schemaPath, args.exportName);
|
|
@@ -279637,11 +279813,11 @@ async function migrate(argv) {
|
|
|
279637
279813
|
].join("\n");
|
|
279638
279814
|
const totalStatements = plan.statements.length + plan.concurrent.length;
|
|
279639
279815
|
console.log(
|
|
279640
|
-
` ${
|
|
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`)}`
|
|
279641
279817
|
);
|
|
279642
279818
|
if (args.outputFile) {
|
|
279643
|
-
(0,
|
|
279644
|
-
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)}`);
|
|
279645
279821
|
return;
|
|
279646
279822
|
}
|
|
279647
279823
|
if (args.dryRun) {
|
|
@@ -279650,12 +279826,13 @@ async function migrate(argv) {
|
|
|
279650
279826
|
}
|
|
279651
279827
|
const dbUrl = process.env.DATABASE_URL ?? process.env.ABLO_DATABASE_URL;
|
|
279652
279828
|
if (!dbUrl) {
|
|
279653
|
-
console.error(
|
|
279829
|
+
console.error(import_picocolors4.default.red(" Set DATABASE_URL (or ABLO_DATABASE_URL) to apply, or use --dry-run to preview."));
|
|
279654
279830
|
process.exit(1);
|
|
279655
279831
|
}
|
|
279832
|
+
const effectiveUrl = await ensureScopedRoleInteractive(dbUrl);
|
|
279656
279833
|
try {
|
|
279657
|
-
await applyStatements(
|
|
279658
|
-
console.log(` ${
|
|
279834
|
+
await applyStatements(effectiveUrl, args.targetSchema, plan.statements, plan.concurrent);
|
|
279835
|
+
console.log(` ${import_picocolors4.default.green("\u2713")} Migration complete`);
|
|
279659
279836
|
} catch {
|
|
279660
279837
|
process.exit(1);
|
|
279661
279838
|
}
|
|
@@ -279663,9 +279840,9 @@ async function migrate(argv) {
|
|
|
279663
279840
|
|
|
279664
279841
|
// src/cli/generate.ts
|
|
279665
279842
|
init_cjs_shims();
|
|
279666
|
-
var
|
|
279667
|
-
var
|
|
279668
|
-
var
|
|
279843
|
+
var import_fs6 = require("fs");
|
|
279844
|
+
var import_path4 = require("path");
|
|
279845
|
+
var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
279669
279846
|
var import_schema3 = require("@abloatai/ablo/schema");
|
|
279670
279847
|
var DEFAULT_SCHEMA_PATH3 = "ablo/schema.ts";
|
|
279671
279848
|
var DEFAULT_EXPORT3 = "schema";
|
|
@@ -279697,7 +279874,7 @@ async function generate(argv) {
|
|
|
279697
279874
|
try {
|
|
279698
279875
|
args = parseGenerateArgs(argv);
|
|
279699
279876
|
} catch (err) {
|
|
279700
|
-
console.error(
|
|
279877
|
+
console.error(import_picocolors5.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
279701
279878
|
process.exit(1);
|
|
279702
279879
|
}
|
|
279703
279880
|
let source;
|
|
@@ -279706,20 +279883,20 @@ async function generate(argv) {
|
|
|
279706
279883
|
const schemaJson = JSON.parse((0, import_schema3.serializeSchema)(schema));
|
|
279707
279884
|
source = (0, import_schema3.generateTypes)(schemaJson);
|
|
279708
279885
|
} catch (err) {
|
|
279709
|
-
console.error(
|
|
279886
|
+
console.error(import_picocolors5.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
279710
279887
|
process.exit(1);
|
|
279711
279888
|
}
|
|
279712
|
-
const abs = (0,
|
|
279713
|
-
(0,
|
|
279714
|
-
(0,
|
|
279715
|
-
console.log(` ${
|
|
279889
|
+
const abs = (0, import_path4.resolve)(process.cwd(), args.out);
|
|
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)}`);
|
|
279716
279893
|
}
|
|
279717
279894
|
|
|
279718
279895
|
// src/cli/dev.ts
|
|
279719
279896
|
init_cjs_shims();
|
|
279720
|
-
var
|
|
279721
|
-
var
|
|
279722
|
-
var
|
|
279897
|
+
var import_picocolors6 = __toESM(require_picocolors(), 1);
|
|
279898
|
+
var import_fs7 = require("fs");
|
|
279899
|
+
var import_path5 = require("path");
|
|
279723
279900
|
var import_schema4 = require("@abloatai/ablo/schema");
|
|
279724
279901
|
|
|
279725
279902
|
// src/cli/theme.ts
|
|
@@ -279740,7 +279917,7 @@ function parseDevArgs(argv) {
|
|
|
279740
279917
|
let schemaPath = DEFAULT_SCHEMA_PATH;
|
|
279741
279918
|
let exportName = DEFAULT_EXPORT;
|
|
279742
279919
|
let url = process.env.ABLO_API_URL ?? DEFAULT_URL;
|
|
279743
|
-
let watchEnabled =
|
|
279920
|
+
let watchEnabled = false;
|
|
279744
279921
|
for (let i = 0; i < argv.length; i++) {
|
|
279745
279922
|
const arg = argv[i];
|
|
279746
279923
|
switch (arg) {
|
|
@@ -279753,6 +279930,9 @@ function parseDevArgs(argv) {
|
|
|
279753
279930
|
case "--url":
|
|
279754
279931
|
url = argv[++i] ?? url;
|
|
279755
279932
|
break;
|
|
279933
|
+
case "--watch":
|
|
279934
|
+
watchEnabled = true;
|
|
279935
|
+
break;
|
|
279756
279936
|
case "--no-watch":
|
|
279757
279937
|
watchEnabled = false;
|
|
279758
279938
|
break;
|
|
@@ -279767,58 +279947,58 @@ function classifyKey(apiKey) {
|
|
|
279767
279947
|
if (!apiKey) {
|
|
279768
279948
|
return {
|
|
279769
279949
|
ok: false,
|
|
279770
|
-
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")}.`
|
|
279771
279951
|
};
|
|
279772
279952
|
}
|
|
279773
279953
|
if (apiKey.startsWith("sk_test_")) return { ok: true };
|
|
279774
279954
|
if (apiKey.startsWith("sk_live_")) {
|
|
279775
279955
|
return {
|
|
279776
279956
|
ok: false,
|
|
279777
|
-
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.`
|
|
279778
279958
|
};
|
|
279779
279959
|
}
|
|
279780
279960
|
if (apiKey.startsWith("rk_")) {
|
|
279781
279961
|
return {
|
|
279782
279962
|
ok: false,
|
|
279783
|
-
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.`
|
|
279784
279964
|
};
|
|
279785
279965
|
}
|
|
279786
|
-
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")}).` };
|
|
279787
279967
|
}
|
|
279788
279968
|
function wireEnvLocal(apiKey, cwd = process.cwd()) {
|
|
279789
|
-
const envPath = (0,
|
|
279969
|
+
const envPath = (0, import_path5.resolve)(cwd, ".env.local");
|
|
279790
279970
|
const line = `ABLO_API_KEY=${apiKey}`;
|
|
279791
279971
|
let action;
|
|
279792
|
-
if (!(0,
|
|
279793
|
-
(0,
|
|
279972
|
+
if (!(0, import_fs7.existsSync)(envPath)) {
|
|
279973
|
+
(0, import_fs7.writeFileSync)(envPath, `${line}
|
|
279794
279974
|
`, { mode: 384 });
|
|
279795
|
-
action = `Created ${
|
|
279975
|
+
action = `Created ${import_picocolors6.default.bold(".env.local")} with ${import_picocolors6.default.bold("ABLO_API_KEY")}`;
|
|
279796
279976
|
} else {
|
|
279797
|
-
const content = (0,
|
|
279977
|
+
const content = (0, import_fs7.readFileSync)(envPath, "utf8");
|
|
279798
279978
|
const match = content.match(/^ABLO_API_KEY=(.*)$/m);
|
|
279799
279979
|
if (!match) {
|
|
279800
|
-
(0,
|
|
279980
|
+
(0, import_fs7.appendFileSync)(envPath, `${content.endsWith("\n") || content.length === 0 ? "" : "\n"}${line}
|
|
279801
279981
|
`);
|
|
279802
|
-
action = `Added ${
|
|
279982
|
+
action = `Added ${import_picocolors6.default.bold("ABLO_API_KEY")} to ${import_picocolors6.default.bold(".env.local")}`;
|
|
279803
279983
|
} else if (match[1] === apiKey) {
|
|
279804
|
-
action = `${
|
|
279984
|
+
action = `${import_picocolors6.default.bold(".env.local")} already has this key`;
|
|
279805
279985
|
} else {
|
|
279806
|
-
(0,
|
|
279807
|
-
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)`)}`;
|
|
279808
279988
|
}
|
|
279809
279989
|
}
|
|
279810
|
-
const gitignorePath = (0,
|
|
279811
|
-
const gitignore = (0,
|
|
279990
|
+
const gitignorePath = (0, import_path5.resolve)(cwd, ".gitignore");
|
|
279991
|
+
const gitignore = (0, import_fs7.existsSync)(gitignorePath) ? (0, import_fs7.readFileSync)(gitignorePath, "utf8") : "";
|
|
279812
279992
|
const ignored = /^(\.env\.local|\.env\*|\.env\.\*|\.env.*)$/m.test(gitignore);
|
|
279813
279993
|
let gitignoreNote = "";
|
|
279814
279994
|
if (!ignored) {
|
|
279815
|
-
(0,
|
|
279995
|
+
(0, import_fs7.writeFileSync)(
|
|
279816
279996
|
gitignorePath,
|
|
279817
279997
|
`${gitignore.endsWith("\n") || gitignore.length === 0 ? gitignore : `${gitignore}
|
|
279818
279998
|
`}.env.local
|
|
279819
279999
|
`
|
|
279820
280000
|
);
|
|
279821
|
-
gitignoreNote = ` Added ${
|
|
280001
|
+
gitignoreNote = ` Added ${import_picocolors6.default.bold(".env.local")} to ${import_picocolors6.default.bold(".gitignore")} so the key can't be committed.`;
|
|
279822
280002
|
}
|
|
279823
280003
|
return `${action}.${gitignoreNote}`;
|
|
279824
280004
|
}
|
|
@@ -279833,7 +280013,7 @@ async function runPush(schema, args) {
|
|
|
279833
280013
|
if (ok) {
|
|
279834
280014
|
return {
|
|
279835
280015
|
ok: true,
|
|
279836
|
-
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})`)}`
|
|
279837
280017
|
};
|
|
279838
280018
|
}
|
|
279839
280019
|
if (status2 === 409) {
|
|
@@ -279841,47 +280021,49 @@ async function runPush(schema, args) {
|
|
|
279841
280021
|
const warnings = Array.isArray(body.warnings) ? body.warnings : [];
|
|
279842
280022
|
const lines = [
|
|
279843
280023
|
"Incompatible schema change \u2014 not safe to apply as-is.",
|
|
279844
|
-
...unexecutable.map((u2) =>
|
|
279845
|
-
...warnings.map((w2) =>
|
|
279846
|
-
|
|
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.`)
|
|
279847
280027
|
];
|
|
279848
280028
|
return { ok: false, message: lines.join("\n") };
|
|
279849
280029
|
}
|
|
279850
280030
|
if (status2 === 403) {
|
|
280031
|
+
const serverSays = body.message ?? body.reason;
|
|
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")}.`;
|
|
279851
280033
|
return {
|
|
279852
280034
|
ok: false,
|
|
279853
|
-
message:
|
|
279854
|
-
` +
|
|
279855
|
-
`Use a ${import_picocolors5.default.bold("sandbox")} key, or one with ${import_picocolors5.default.bold("schema authoring")} enabled at ${import_picocolors5.default.cyan("https://abloatai.com")}.`
|
|
279856
|
-
)
|
|
280035
|
+
message: `${serverSays ?? "This key can't author schema (missing schema:push scope)."}
|
|
280036
|
+
` + import_picocolors6.default.dim(hint)
|
|
279857
280037
|
};
|
|
279858
280038
|
}
|
|
279859
|
-
return { ok: false, message: `Push failed (${status2}): ${body.reason ?? bodyText}` };
|
|
280039
|
+
return { ok: false, message: `Push failed (${status2}): ${body.message ?? body.reason ?? bodyText}` };
|
|
279860
280040
|
}
|
|
279861
280041
|
async function dev(argv) {
|
|
279862
280042
|
let args;
|
|
279863
280043
|
try {
|
|
279864
280044
|
args = parseDevArgs(argv);
|
|
279865
280045
|
} catch (err) {
|
|
279866
|
-
console.error(
|
|
280046
|
+
console.error(import_picocolors6.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
279867
280047
|
process.exit(1);
|
|
279868
280048
|
}
|
|
279869
280049
|
if (!args.apiKey) args.apiKey = resolveApiKey("sandbox");
|
|
279870
280050
|
const key = classifyKey(args.apiKey);
|
|
279871
280051
|
if (!key.ok) {
|
|
279872
|
-
console.error(
|
|
280052
|
+
console.error(import_picocolors6.default.red(` ${key.reason}`));
|
|
279873
280053
|
process.exit(1);
|
|
279874
280054
|
}
|
|
279875
280055
|
console.log(`
|
|
279876
|
-
${brand("ablo")} ${
|
|
280056
|
+
${brand("ablo")} ${import_picocolors6.default.dim("sync engine \u2014 dev")} ${import_picocolors6.default.dim("(sandbox)")}
|
|
279877
280057
|
`);
|
|
280058
|
+
const projectDbUrl = readProjectDatabaseUrl();
|
|
280059
|
+
if (projectDbUrl) await ensureScopedRoleInteractive(projectDbUrl);
|
|
279878
280060
|
const schema = await loadSchema(args.schemaPath, args.exportName);
|
|
279879
280061
|
const modelCount = Object.keys(schema.models).length;
|
|
279880
280062
|
console.log(
|
|
279881
|
-
` ${
|
|
280063
|
+
` ${import_picocolors6.default.dim("schema")} ${import_picocolors6.default.bold(args.schemaPath)} ${import_picocolors6.default.dim(`(${modelCount} models, hash ${(0, import_schema4.schemaHash)(schema)})`)}`
|
|
279882
280064
|
);
|
|
279883
|
-
console.log(` ${
|
|
279884
|
-
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}
|
|
279885
280067
|
`);
|
|
279886
280068
|
const s = Y2();
|
|
279887
280069
|
s.start("Pushing schema definition (sandbox)");
|
|
@@ -279890,20 +280072,20 @@ async function dev(argv) {
|
|
|
279890
280072
|
if (!first.ok) process.exit(1);
|
|
279891
280073
|
if (process.env.ABLO_API_KEY) {
|
|
279892
280074
|
console.log(`
|
|
279893
|
-
${
|
|
280075
|
+
${import_picocolors6.default.green("\u2713")} ${import_picocolors6.default.bold("ABLO_API_KEY")} is set in this shell \u2014 the SDK reads it directly.`);
|
|
279894
280076
|
} else {
|
|
279895
280077
|
console.log(`
|
|
279896
|
-
${
|
|
279897
|
-
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")}`);
|
|
279898
280080
|
}
|
|
279899
280081
|
console.log(` Your app is wired for the sandbox.`);
|
|
279900
280082
|
if (!args.watch) return;
|
|
279901
|
-
const abs = (0,
|
|
279902
|
-
console.log(` ${
|
|
280083
|
+
const abs = (0, import_path5.resolve)(process.cwd(), args.schemaPath);
|
|
280084
|
+
console.log(` ${import_picocolors6.default.dim(`watching ${args.schemaPath} \u2026 (Ctrl-C to stop)`)}
|
|
279903
280085
|
`);
|
|
279904
280086
|
let timer2 = null;
|
|
279905
280087
|
let pushing = false;
|
|
279906
|
-
const watcher = (0,
|
|
280088
|
+
const watcher = (0, import_fs7.watch)(abs, () => {
|
|
279907
280089
|
if (timer2) clearTimeout(timer2);
|
|
279908
280090
|
timer2 = setTimeout(() => {
|
|
279909
280091
|
void rePush();
|
|
@@ -279919,7 +280101,7 @@ async function dev(argv) {
|
|
|
279919
280101
|
const r2 = await runPush(next, args);
|
|
279920
280102
|
s2.stop(r2.message, r2.ok ? 0 : 1);
|
|
279921
280103
|
} catch (err) {
|
|
279922
|
-
s2.stop(
|
|
280104
|
+
s2.stop(import_picocolors6.default.red(`schema reload failed: ${err instanceof Error ? err.message : String(err)}`), 1);
|
|
279923
280105
|
} finally {
|
|
279924
280106
|
pushing = false;
|
|
279925
280107
|
}
|
|
@@ -279927,7 +280109,7 @@ async function dev(argv) {
|
|
|
279927
280109
|
const stop = () => {
|
|
279928
280110
|
watcher.close();
|
|
279929
280111
|
console.log(`
|
|
279930
|
-
${
|
|
280112
|
+
${import_picocolors6.default.dim("stopped.")}`);
|
|
279931
280113
|
process.exit(0);
|
|
279932
280114
|
};
|
|
279933
280115
|
process.on("SIGINT", stop);
|
|
@@ -279939,7 +280121,7 @@ async function dev(argv) {
|
|
|
279939
280121
|
// src/cli/login.ts
|
|
279940
280122
|
init_cjs_shims();
|
|
279941
280123
|
var import_child_process = require("child_process");
|
|
279942
|
-
var
|
|
280124
|
+
var import_picocolors7 = __toESM(require_picocolors(), 1);
|
|
279943
280125
|
var CLIENT_ID = "ablo-cli";
|
|
279944
280126
|
var AUTH_URL = (process.env.ABLO_AUTH_URL ?? "https://www.abloatai.com").replace(/\/+$/, "");
|
|
279945
280127
|
var sleep = (ms) => new Promise((r2) => setTimeout(r2, ms));
|
|
@@ -279955,16 +280137,21 @@ function openBrowser(url) {
|
|
|
279955
280137
|
}
|
|
279956
280138
|
async function deviceLogin() {
|
|
279957
280139
|
Ie(`${brand("ablo")} login`);
|
|
279958
|
-
const
|
|
279959
|
-
|
|
279960
|
-
|
|
279961
|
-
|
|
279962
|
-
|
|
279963
|
-
|
|
279964
|
-
|
|
279965
|
-
|
|
279966
|
-
|
|
279967
|
-
|
|
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;
|
|
279968
280155
|
}
|
|
279969
280156
|
const codeRes = await fetch(`${AUTH_URL}/api/auth/device/code`, {
|
|
279970
280157
|
method: "POST",
|
|
@@ -279978,9 +280165,9 @@ async function deviceLogin() {
|
|
|
279978
280165
|
const code = await codeRes.json();
|
|
279979
280166
|
const approvePath = `/cli?user_code=${code.user_code}`;
|
|
279980
280167
|
const url = account === "signup" ? `${AUTH_URL}/signup?next=${encodeURIComponent(approvePath)}` : code.verification_uri_complete ?? code.verification_uri;
|
|
279981
|
-
Me(`${
|
|
280168
|
+
Me(`${import_picocolors7.default.bold(code.user_code)}
|
|
279982
280169
|
|
|
279983
|
-
${
|
|
280170
|
+
${import_picocolors7.default.dim(url)}`, "Approve in your browser");
|
|
279984
280171
|
openBrowser(url);
|
|
279985
280172
|
const s = Y2();
|
|
279986
280173
|
s.start("Waiting for approval\u2026");
|
|
@@ -280038,7 +280225,7 @@ ${import_picocolors6.default.dim(url)}`, "Approve in your browser");
|
|
|
280038
280225
|
if (reason) M2.error(reason);
|
|
280039
280226
|
else if (provRes) M2.error(`Key provisioning returned ${provRes.status} from ${AUTH_URL}/api/cli/provision-key.`);
|
|
280040
280227
|
M2.error(
|
|
280041
|
-
`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")}.`
|
|
280042
280229
|
);
|
|
280043
280230
|
process.exit(1);
|
|
280044
280231
|
}
|
|
@@ -280054,7 +280241,7 @@ ${import_picocolors6.default.dim(url)}`, "Approve in your browser");
|
|
|
280054
280241
|
...prov.live ? { production: entry(prov.live) } : {}
|
|
280055
280242
|
});
|
|
280056
280243
|
s.stop(`Saved keys to ${path}`);
|
|
280057
|
-
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.`);
|
|
280058
280245
|
}
|
|
280059
280246
|
async function login() {
|
|
280060
280247
|
await deviceLogin();
|
|
@@ -280062,20 +280249,20 @@ async function login() {
|
|
|
280062
280249
|
function logout() {
|
|
280063
280250
|
const removed = clearCredential();
|
|
280064
280251
|
if (removed) {
|
|
280065
|
-
console.log(` ${
|
|
280252
|
+
console.log(` ${import_picocolors7.default.green("\u2713")} Logged out ${import_picocolors7.default.dim(`(credentials removed from ${configDir()})`)}`);
|
|
280066
280253
|
} else {
|
|
280067
|
-
console.log(` ${
|
|
280254
|
+
console.log(` ${import_picocolors7.default.dim("\u25CB")} Not logged in \u2014 nothing to remove.`);
|
|
280068
280255
|
}
|
|
280069
280256
|
if (process.env.ABLO_API_KEY) {
|
|
280070
280257
|
console.log(
|
|
280071
|
-
|
|
280258
|
+
import_picocolors7.default.dim(` Note: ${import_picocolors7.default.bold("ABLO_API_KEY")} is still set in this shell and takes precedence.`)
|
|
280072
280259
|
);
|
|
280073
280260
|
}
|
|
280074
280261
|
}
|
|
280075
280262
|
|
|
280076
280263
|
// src/cli/mode.ts
|
|
280077
280264
|
init_cjs_shims();
|
|
280078
|
-
var
|
|
280265
|
+
var import_picocolors8 = __toESM(require_picocolors(), 1);
|
|
280079
280266
|
var PREFIX = { sandbox: "sk_test_", production: "rk_live_" };
|
|
280080
280267
|
function hintFor(m2, current) {
|
|
280081
280268
|
const parts = [];
|
|
@@ -280085,10 +280272,10 @@ function hintFor(m2, current) {
|
|
|
280085
280272
|
}
|
|
280086
280273
|
function apply(m2) {
|
|
280087
280274
|
setMode(m2);
|
|
280088
|
-
console.log(` ${
|
|
280275
|
+
console.log(` ${import_picocolors8.default.green("\u2713")} now in ${import_picocolors8.default.bold(m2)}`);
|
|
280089
280276
|
if (!getKeyEntry(m2)) {
|
|
280090
280277
|
console.log(
|
|
280091
|
-
|
|
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`)}.`)
|
|
280092
280279
|
);
|
|
280093
280280
|
}
|
|
280094
280281
|
}
|
|
@@ -280101,14 +280288,14 @@ async function mode(argv) {
|
|
|
280101
280288
|
}
|
|
280102
280289
|
if (arg) {
|
|
280103
280290
|
console.error(
|
|
280104
|
-
|
|
280291
|
+
import_picocolors8.default.red(` unknown mode: ${arg}`) + import_picocolors8.default.dim(` (expected ${import_picocolors8.default.bold("sandbox")} or ${import_picocolors8.default.bold("production")})`)
|
|
280105
280292
|
);
|
|
280106
280293
|
process.exit(1);
|
|
280107
280294
|
}
|
|
280108
280295
|
const current = getMode();
|
|
280109
280296
|
if (!process.stdin.isTTY || process.env.CI) {
|
|
280110
280297
|
console.error(
|
|
280111
|
-
|
|
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})`)
|
|
280112
280299
|
);
|
|
280113
280300
|
process.exit(1);
|
|
280114
280301
|
}
|
|
@@ -280129,13 +280316,13 @@ async function mode(argv) {
|
|
|
280129
280316
|
|
|
280130
280317
|
// src/cli/status.ts
|
|
280131
280318
|
init_cjs_shims();
|
|
280132
|
-
var
|
|
280319
|
+
var import_picocolors9 = __toESM(require_picocolors(), 1);
|
|
280133
280320
|
function expiryLabel(iso) {
|
|
280134
280321
|
const ms = Date.parse(iso) - Date.now();
|
|
280135
280322
|
if (Number.isNaN(ms)) return "";
|
|
280136
|
-
if (ms <= 0) return
|
|
280323
|
+
if (ms <= 0) return import_picocolors9.default.red("expired");
|
|
280137
280324
|
const days = Math.floor(ms / (24 * 60 * 60 * 1e3));
|
|
280138
|
-
return
|
|
280325
|
+
return import_picocolors9.default.dim(days > 0 ? `expires in ${days}d` : "expires <1d");
|
|
280139
280326
|
}
|
|
280140
280327
|
async function ping(apiUrl) {
|
|
280141
280328
|
const ctrl = new AbortController();
|
|
@@ -280154,36 +280341,36 @@ async function status() {
|
|
|
280154
280341
|
const cfg = readConfig();
|
|
280155
280342
|
const mode2 = getMode();
|
|
280156
280343
|
console.log(`
|
|
280157
|
-
${brand("ablo")} ${
|
|
280344
|
+
${brand("ablo")} ${import_picocolors9.default.dim("status")}
|
|
280158
280345
|
`);
|
|
280159
280346
|
if (process.env.ABLO_API_KEY) {
|
|
280160
280347
|
console.log(
|
|
280161
|
-
` ${
|
|
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)")}`
|
|
280162
280349
|
);
|
|
280163
280350
|
} else if (!cfg) {
|
|
280164
|
-
console.log(` ${
|
|
280351
|
+
console.log(` ${import_picocolors9.default.yellow("!")} Not logged in \u2014 run ${import_picocolors9.default.bold("ablo login")}.`);
|
|
280165
280352
|
}
|
|
280166
|
-
console.log(` ${
|
|
280353
|
+
console.log(` ${import_picocolors9.default.dim("mode")} ${import_picocolors9.default.bold(mode2)}`);
|
|
280167
280354
|
for (const m2 of ["sandbox", "production"]) {
|
|
280168
280355
|
const entry = getKeyEntry(m2);
|
|
280169
|
-
const marker = m2 === mode2 ?
|
|
280356
|
+
const marker = m2 === mode2 ? import_picocolors9.default.green("\u25CF") : import_picocolors9.default.dim("\u25CB");
|
|
280170
280357
|
if (entry) {
|
|
280171
280358
|
const exp = entry.expiresAt ? ` ${expiryLabel(entry.expiresAt)}` : "";
|
|
280172
|
-
console.log(` ${marker} ${m2.padEnd(10)} ${
|
|
280359
|
+
console.log(` ${marker} ${m2.padEnd(10)} ${import_picocolors9.default.dim(`${entry.apiKey.slice(0, 12)}\u2026`)}${exp}`);
|
|
280173
280360
|
} else {
|
|
280174
|
-
console.log(` ${marker} ${m2.padEnd(10)} ${
|
|
280361
|
+
console.log(` ${marker} ${m2.padEnd(10)} ${import_picocolors9.default.dim("\u2014 no key")}`);
|
|
280175
280362
|
}
|
|
280176
280363
|
}
|
|
280177
280364
|
const org = getKeyEntry(mode2)?.organizationId;
|
|
280178
|
-
if (org) console.log(` ${
|
|
280179
|
-
process.stdout.write(` ${
|
|
280180
|
-
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"));
|
|
280181
280368
|
console.log();
|
|
280182
280369
|
}
|
|
280183
280370
|
|
|
280184
280371
|
// src/cli/logs.ts
|
|
280185
280372
|
init_cjs_shims();
|
|
280186
|
-
var
|
|
280373
|
+
var import_picocolors10 = __toESM(require_picocolors(), 1);
|
|
280187
280374
|
function parseLogsArgs(argv) {
|
|
280188
280375
|
const args = {
|
|
280189
280376
|
follow: true,
|
|
@@ -280247,10 +280434,10 @@ function resolveSince(since) {
|
|
|
280247
280434
|
var sleep2 = (ms) => new Promise((r2) => setTimeout(r2, ms));
|
|
280248
280435
|
function colorOp(op) {
|
|
280249
280436
|
const label = op.padEnd(6);
|
|
280250
|
-
if (op === "create") return
|
|
280251
|
-
if (op === "update") return
|
|
280252
|
-
if (op === "delete") return
|
|
280253
|
-
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);
|
|
280254
280441
|
}
|
|
280255
280442
|
function render(e2, json) {
|
|
280256
280443
|
if (json) {
|
|
@@ -280259,21 +280446,21 @@ function render(e2, json) {
|
|
|
280259
280446
|
return;
|
|
280260
280447
|
}
|
|
280261
280448
|
const t = new Date(e2.at).toLocaleTimeString();
|
|
280262
|
-
const actor = e2.actor ?
|
|
280263
|
-
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}`);
|
|
280264
280451
|
}
|
|
280265
280452
|
async function logs(argv) {
|
|
280266
280453
|
let args;
|
|
280267
280454
|
try {
|
|
280268
280455
|
args = parseLogsArgs(argv);
|
|
280269
280456
|
} catch (err) {
|
|
280270
|
-
console.error(
|
|
280457
|
+
console.error(import_picocolors10.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
280271
280458
|
process.exit(1);
|
|
280272
280459
|
}
|
|
280273
280460
|
const apiKey = resolveApiKey(args.mode);
|
|
280274
280461
|
if (!apiKey) {
|
|
280275
280462
|
console.error(
|
|
280276
|
-
|
|
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")}.`)
|
|
280277
280464
|
);
|
|
280278
280465
|
process.exit(1);
|
|
280279
280466
|
}
|
|
@@ -280287,7 +280474,7 @@ async function logs(argv) {
|
|
|
280287
280474
|
if (!res) return null;
|
|
280288
280475
|
if (!res.ok) {
|
|
280289
280476
|
const body = await res.json().catch(() => ({}));
|
|
280290
|
-
console.error(
|
|
280477
|
+
console.error(import_picocolors10.default.red(` logs failed (${res.status}): ${body.reason ?? body.message ?? ""}`));
|
|
280291
280478
|
process.exit(1);
|
|
280292
280479
|
}
|
|
280293
280480
|
const json = await res.json();
|
|
@@ -280298,7 +280485,7 @@ async function logs(argv) {
|
|
|
280298
280485
|
}
|
|
280299
280486
|
if (!args.json) {
|
|
280300
280487
|
console.log(`
|
|
280301
|
-
${brand("ablo")} ${
|
|
280488
|
+
${brand("ablo")} ${import_picocolors10.default.dim("logs")} ${import_picocolors10.default.dim(`(${args.mode ?? "active"} mode)`)}
|
|
280302
280489
|
`);
|
|
280303
280490
|
}
|
|
280304
280491
|
const initial = await fetchPage({
|
|
@@ -280308,13 +280495,13 @@ async function logs(argv) {
|
|
|
280308
280495
|
...args.op ? { op: args.op } : {}
|
|
280309
280496
|
});
|
|
280310
280497
|
if (!initial) {
|
|
280311
|
-
console.error(
|
|
280498
|
+
console.error(import_picocolors10.default.red(` Couldn't reach ${baseUrl2}.`));
|
|
280312
280499
|
process.exit(1);
|
|
280313
280500
|
}
|
|
280314
280501
|
for (const e2 of initial.events) render(e2, args.json);
|
|
280315
280502
|
let cursor = initial.cursor;
|
|
280316
280503
|
if (!args.follow) return;
|
|
280317
|
-
if (!args.json) console.log(` ${
|
|
280504
|
+
if (!args.json) console.log(` ${import_picocolors10.default.dim("watching for new activity \u2026 (Ctrl-C to stop)")}
|
|
280318
280505
|
`);
|
|
280319
280506
|
for (; ; ) {
|
|
280320
280507
|
await sleep2(1500);
|
|
@@ -280331,8 +280518,8 @@ async function logs(argv) {
|
|
|
280331
280518
|
|
|
280332
280519
|
// src/cli/webhooks.ts
|
|
280333
280520
|
init_cjs_shims();
|
|
280334
|
-
var
|
|
280335
|
-
var
|
|
280521
|
+
var import_fs8 = require("fs");
|
|
280522
|
+
var import_picocolors11 = __toESM(require_picocolors(), 1);
|
|
280336
280523
|
var ENV_KEY = "ABLO_WEBHOOK_SECRET";
|
|
280337
280524
|
function flag(args, name) {
|
|
280338
280525
|
const inline = args.find((a) => a.startsWith(`${name}=`));
|
|
@@ -280359,12 +280546,12 @@ function requireKey(mode2) {
|
|
|
280359
280546
|
const apiKey = resolveApiKey(mode2);
|
|
280360
280547
|
if (!apiKey) {
|
|
280361
280548
|
console.error(
|
|
280362
|
-
|
|
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")}.`)
|
|
280363
280550
|
);
|
|
280364
280551
|
process.exit(1);
|
|
280365
280552
|
}
|
|
280366
280553
|
if (!apiKey.startsWith("sk_")) {
|
|
280367
|
-
console.error(
|
|
280554
|
+
console.error(import_picocolors11.default.red(" Managing webhooks requires a secret key ") + import_picocolors11.default.dim("(sk_test_ / sk_live_)."));
|
|
280368
280555
|
process.exit(1);
|
|
280369
280556
|
}
|
|
280370
280557
|
return apiKey;
|
|
@@ -280380,22 +280567,22 @@ async function api(apiKey, method, path, body) {
|
|
|
280380
280567
|
...body ? { body: JSON.stringify(body) } : {}
|
|
280381
280568
|
}).catch(() => null);
|
|
280382
280569
|
if (!res) {
|
|
280383
|
-
console.error(
|
|
280570
|
+
console.error(import_picocolors11.default.red(` Couldn't reach ${baseUrl()}.`));
|
|
280384
280571
|
process.exit(1);
|
|
280385
280572
|
}
|
|
280386
280573
|
if (!res.ok) {
|
|
280387
280574
|
const err = await res.json().catch(() => ({}));
|
|
280388
|
-
console.error(
|
|
280575
|
+
console.error(import_picocolors11.default.red(` Request failed (${res.status}): ${err.message ?? err.reason ?? ""}`));
|
|
280389
280576
|
process.exit(1);
|
|
280390
280577
|
}
|
|
280391
280578
|
return await res.json();
|
|
280392
280579
|
}
|
|
280393
280580
|
function writeSecretToEnv(secret) {
|
|
280394
|
-
const file = (0,
|
|
280581
|
+
const file = (0, import_fs8.existsSync)(".env.local") ? ".env.local" : (0, import_fs8.existsSync)(".env") ? ".env" : ".env.local";
|
|
280395
280582
|
const line = `${ENV_KEY}=${secret}`;
|
|
280396
280583
|
let next;
|
|
280397
|
-
if ((0,
|
|
280398
|
-
const existing = (0,
|
|
280584
|
+
if ((0, import_fs8.existsSync)(file)) {
|
|
280585
|
+
const existing = (0, import_fs8.readFileSync)(file, "utf-8");
|
|
280399
280586
|
next = new RegExp(`^${ENV_KEY}=.*$`, "m").test(existing) ? existing.replace(new RegExp(`^${ENV_KEY}=.*$`, "m"), line) : `${existing.replace(/\n*$/, "")}
|
|
280400
280587
|
${line}
|
|
280401
280588
|
`;
|
|
@@ -280403,15 +280590,15 @@ ${line}
|
|
|
280403
280590
|
next = `${line}
|
|
280404
280591
|
`;
|
|
280405
280592
|
}
|
|
280406
|
-
(0,
|
|
280593
|
+
(0, import_fs8.writeFileSync)(file, next);
|
|
280407
280594
|
return file;
|
|
280408
280595
|
}
|
|
280409
280596
|
function printEndpoint(e2) {
|
|
280410
|
-
const dot = e2.status === "enabled" ?
|
|
280411
|
-
const health = e2.last_error ?
|
|
280412
|
-
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}`);
|
|
280413
280600
|
console.log(
|
|
280414
|
-
|
|
280601
|
+
import_picocolors11.default.dim(
|
|
280415
280602
|
` ${e2.status} \xB7 ${e2.environment} \xB7 events ${e2.enabled_events.join(",")} \xB7 cursor ${e2.cursor ?? "\u2014"}${health}`
|
|
280416
280603
|
)
|
|
280417
280604
|
);
|
|
@@ -280423,7 +280610,7 @@ async function webhooks(argv) {
|
|
|
280423
280610
|
if (sub === "create") {
|
|
280424
280611
|
const url = positional(rest);
|
|
280425
280612
|
if (!url) {
|
|
280426
|
-
console.error(
|
|
280613
|
+
console.error(import_picocolors11.default.red(" Usage: ") + brand("ablo webhooks create <url>"));
|
|
280427
280614
|
process.exit(1);
|
|
280428
280615
|
}
|
|
280429
280616
|
const apiKey = requireKey(mode2);
|
|
@@ -280435,8 +280622,8 @@ async function webhooks(argv) {
|
|
|
280435
280622
|
});
|
|
280436
280623
|
const file = writeSecretToEnv(created.secret);
|
|
280437
280624
|
console.log(`
|
|
280438
|
-
${
|
|
280439
|
-
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)")}
|
|
280440
280627
|
`);
|
|
280441
280628
|
return;
|
|
280442
280629
|
}
|
|
@@ -280444,7 +280631,7 @@ async function webhooks(argv) {
|
|
|
280444
280631
|
const apiKey = requireKey(mode2);
|
|
280445
280632
|
const { data } = await api(apiKey, "GET", "");
|
|
280446
280633
|
if (data.length === 0) {
|
|
280447
|
-
console.log(
|
|
280634
|
+
console.log(import_picocolors11.default.dim(" No webhook endpoints. ") + brand("ablo webhooks create <url>"));
|
|
280448
280635
|
return;
|
|
280449
280636
|
}
|
|
280450
280637
|
console.log();
|
|
@@ -280455,40 +280642,40 @@ async function webhooks(argv) {
|
|
|
280455
280642
|
if (sub === "roll") {
|
|
280456
280643
|
const id = positional(rest);
|
|
280457
280644
|
if (!id) {
|
|
280458
|
-
console.error(
|
|
280645
|
+
console.error(import_picocolors11.default.red(" Usage: ") + brand("ablo webhooks roll <id>"));
|
|
280459
280646
|
process.exit(1);
|
|
280460
280647
|
}
|
|
280461
280648
|
const apiKey = requireKey(mode2);
|
|
280462
280649
|
const rolled = await api(apiKey, "POST", `/${id}/roll_secret`);
|
|
280463
280650
|
const file = writeSecretToEnv(rolled.secret);
|
|
280464
280651
|
console.log(`
|
|
280465
|
-
${
|
|
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)")}
|
|
280466
280653
|
`);
|
|
280467
280654
|
return;
|
|
280468
280655
|
}
|
|
280469
280656
|
if (sub === "enable") {
|
|
280470
280657
|
const id = positional(rest);
|
|
280471
280658
|
if (!id) {
|
|
280472
|
-
console.error(
|
|
280659
|
+
console.error(import_picocolors11.default.red(" Usage: ") + brand("ablo webhooks enable <id>"));
|
|
280473
280660
|
process.exit(1);
|
|
280474
280661
|
}
|
|
280475
280662
|
const apiKey = requireKey(mode2);
|
|
280476
280663
|
const e2 = await api(apiKey, "POST", `/${id}/enable`);
|
|
280477
|
-
console.log(` ${
|
|
280664
|
+
console.log(` ${import_picocolors11.default.green("\u2713")} Re-enabled ${import_picocolors11.default.bold(e2.id)}`);
|
|
280478
280665
|
return;
|
|
280479
280666
|
}
|
|
280480
280667
|
if (sub === "rm" || sub === "delete") {
|
|
280481
280668
|
const id = positional(rest);
|
|
280482
280669
|
if (!id) {
|
|
280483
|
-
console.error(
|
|
280670
|
+
console.error(import_picocolors11.default.red(" Usage: ") + brand("ablo webhooks rm <id>"));
|
|
280484
280671
|
process.exit(1);
|
|
280485
280672
|
}
|
|
280486
280673
|
const apiKey = requireKey(mode2);
|
|
280487
280674
|
await api(apiKey, "DELETE", `/${id}`);
|
|
280488
|
-
console.log(` ${
|
|
280675
|
+
console.log(` ${import_picocolors11.default.green("\u2713")} Removed ${import_picocolors11.default.bold(id)}`);
|
|
280489
280676
|
return;
|
|
280490
280677
|
}
|
|
280491
|
-
console.log(` ${
|
|
280678
|
+
console.log(` ${import_picocolors11.default.bold("Usage:")}`);
|
|
280492
280679
|
console.log(` ${brand("ablo webhooks create <url>")} Register an endpoint; writes ${ENV_KEY}`);
|
|
280493
280680
|
console.log(` ${brand("ablo webhooks list")} List endpoints + delivery health`);
|
|
280494
280681
|
console.log(` ${brand("ablo webhooks roll <id>")} Mint a fresh signing secret`);
|
|
@@ -280499,7 +280686,7 @@ async function webhooks(argv) {
|
|
|
280499
280686
|
|
|
280500
280687
|
// src/cli/check.ts
|
|
280501
280688
|
init_cjs_shims();
|
|
280502
|
-
var
|
|
280689
|
+
var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
280503
280690
|
var import_schema5 = require("@abloatai/ablo/schema");
|
|
280504
280691
|
var DEFAULT_SCHEMA_PATH4 = "ablo/schema.ts";
|
|
280505
280692
|
var DEFAULT_EXPORT4 = "schema";
|
|
@@ -280534,13 +280721,13 @@ async function check(argv) {
|
|
|
280534
280721
|
try {
|
|
280535
280722
|
args = parseCheckArgs(argv);
|
|
280536
280723
|
} catch (err) {
|
|
280537
|
-
console.error(
|
|
280724
|
+
console.error(import_picocolors12.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
280538
280725
|
process.exit(1);
|
|
280539
280726
|
}
|
|
280540
280727
|
const dbUrl = process.env.DATABASE_URL ?? process.env.ABLO_DATABASE_URL;
|
|
280541
280728
|
if (!dbUrl) {
|
|
280542
280729
|
console.error(
|
|
280543
|
-
|
|
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.`)
|
|
280544
280731
|
);
|
|
280545
280732
|
process.exit(1);
|
|
280546
280733
|
}
|
|
@@ -280555,7 +280742,7 @@ async function check(argv) {
|
|
|
280555
280742
|
[args.appSchema]
|
|
280556
280743
|
);
|
|
280557
280744
|
} catch (err) {
|
|
280558
|
-
console.error(
|
|
280745
|
+
console.error(import_picocolors12.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
|
|
280559
280746
|
await sql.end({ timeout: 2 });
|
|
280560
280747
|
process.exit(1);
|
|
280561
280748
|
}
|
|
@@ -280570,7 +280757,7 @@ async function check(argv) {
|
|
|
280570
280757
|
set.add(r2.column_name);
|
|
280571
280758
|
}
|
|
280572
280759
|
console.log(`
|
|
280573
|
-
${brand("ablo")} ${
|
|
280760
|
+
${brand("ablo")} ${import_picocolors12.default.dim("check")} ${import_picocolors12.default.dim(`schema "${args.appSchema}"`)}
|
|
280574
280761
|
`);
|
|
280575
280762
|
const declaredTables = /* @__PURE__ */ new Set();
|
|
280576
280763
|
let errors = 0;
|
|
@@ -280580,7 +280767,7 @@ async function check(argv) {
|
|
|
280580
280767
|
declaredTables.add(table);
|
|
280581
280768
|
const present = colsByTable.get(table);
|
|
280582
280769
|
if (!present) {
|
|
280583
|
-
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")}`);
|
|
280584
280771
|
errors++;
|
|
280585
280772
|
continue;
|
|
280586
280773
|
}
|
|
@@ -280602,26 +280789,26 @@ async function check(argv) {
|
|
|
280602
280789
|
if (!present.has(col)) problems.push(`missing column "${col}" (field ${fieldName})`);
|
|
280603
280790
|
}
|
|
280604
280791
|
if (problems.length > 0) {
|
|
280605
|
-
console.log(` ${
|
|
280606
|
-
for (const p2 of problems) console.log(` ${
|
|
280607
|
-
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}`);
|
|
280608
280795
|
errors++;
|
|
280609
280796
|
} else if (warns.length > 0) {
|
|
280610
|
-
console.log(` ${
|
|
280611
|
-
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}`);
|
|
280612
280799
|
warnings++;
|
|
280613
280800
|
} else {
|
|
280614
|
-
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)`)}`);
|
|
280615
280802
|
}
|
|
280616
280803
|
}
|
|
280617
280804
|
const modelCount = Object.keys(schemaJson.models).length;
|
|
280618
280805
|
const ignored = [...colsByTable.keys()].filter((t) => !declaredTables.has(t)).length;
|
|
280619
280806
|
console.log(
|
|
280620
280807
|
`
|
|
280621
|
-
${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"}`)}` : "")
|
|
280622
280809
|
);
|
|
280623
280810
|
if (ignored > 0) {
|
|
280624
|
-
console.log(` ${
|
|
280811
|
+
console.log(` ${import_picocolors12.default.dim(`${ignored} other table${ignored === 1 ? "" : "s"} in your database \u2014 ignored by Ablo`)}`);
|
|
280625
280812
|
}
|
|
280626
280813
|
console.log();
|
|
280627
280814
|
process.exit(errors > 0 ? 1 : 0);
|
|
@@ -280629,7 +280816,7 @@ async function check(argv) {
|
|
|
280629
280816
|
|
|
280630
280817
|
// src/cli/upgrade.ts
|
|
280631
280818
|
init_cjs_shims();
|
|
280632
|
-
var
|
|
280819
|
+
var import_picocolors13 = __toESM(require_picocolors(), 1);
|
|
280633
280820
|
var import_ts_morph = __toESM(require_ts_morph(), 1);
|
|
280634
280821
|
var DEFAULT_GLOBS = ["app/**/*.{ts,tsx}", "src/**/*.{ts,tsx}", "ablo/**/*.{ts,tsx}", "lib/**/*.{ts,tsx}"];
|
|
280635
280822
|
var VERB_ARGS = {
|
|
@@ -280707,7 +280894,7 @@ async function upgrade(argv) {
|
|
|
280707
280894
|
project.addSourceFilesAtPaths(globs.length > 0 ? globs : DEFAULT_GLOBS);
|
|
280708
280895
|
const files = project.getSourceFiles();
|
|
280709
280896
|
if (files.length === 0) {
|
|
280710
|
-
console.log(
|
|
280897
|
+
console.log(import_picocolors13.default.yellow(' No .ts/.tsx files found. Pass a glob, e.g. `ablo upgrade "src/**/*.tsx"`.'));
|
|
280711
280898
|
return;
|
|
280712
280899
|
}
|
|
280713
280900
|
const edits = [];
|
|
@@ -280781,39 +280968,39 @@ async function upgrade(argv) {
|
|
|
280781
280968
|
const rel = (f) => f.replace(cwd + "/", "");
|
|
280782
280969
|
console.log();
|
|
280783
280970
|
if (edits.length === 0 && manual.length === 0) {
|
|
280784
|
-
console.log(
|
|
280971
|
+
console.log(import_picocolors13.default.green(" \u2713 Nothing to migrate \u2014 your code is already on the current API."));
|
|
280785
280972
|
return;
|
|
280786
280973
|
}
|
|
280787
280974
|
if (edits.length > 0) {
|
|
280788
|
-
console.log(
|
|
280975
|
+
console.log(import_picocolors13.default.bold(` ${write ? "Applied" : "Would apply"} ${edits.length} change${edits.length === 1 ? "" : "s"}:`));
|
|
280789
280976
|
for (const e2 of edits) {
|
|
280790
|
-
console.log(` ${
|
|
280791
|
-
console.log(` ${
|
|
280792
|
-
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}`);
|
|
280793
280980
|
}
|
|
280794
280981
|
}
|
|
280795
280982
|
if (manual.length > 0) {
|
|
280796
280983
|
console.log();
|
|
280797
|
-
console.log(
|
|
280984
|
+
console.log(import_picocolors13.default.bold(import_picocolors13.default.yellow(` ${manual.length} spot${manual.length === 1 ? "" : "s"} need manual review (structural):`)));
|
|
280798
280985
|
for (const m2 of manual) {
|
|
280799
|
-
console.log(` ${
|
|
280800
|
-
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)}`);
|
|
280801
280988
|
console.log(` \u2192 ${m2.hint}`);
|
|
280802
280989
|
}
|
|
280803
280990
|
}
|
|
280804
280991
|
console.log();
|
|
280805
280992
|
if (write) {
|
|
280806
280993
|
await project.save();
|
|
280807
|
-
console.log(
|
|
280994
|
+
console.log(import_picocolors13.default.green(` \u2713 Wrote ${edits.length} change${edits.length === 1 ? "" : "s"}. Review the diff, run your typecheck.`));
|
|
280808
280995
|
} else {
|
|
280809
|
-
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)."));
|
|
280810
280997
|
}
|
|
280811
280998
|
}
|
|
280812
280999
|
|
|
280813
281000
|
// src/cli/pull.ts
|
|
280814
281001
|
init_cjs_shims();
|
|
280815
|
-
var
|
|
280816
|
-
var
|
|
281002
|
+
var import_picocolors14 = __toESM(require_picocolors(), 1);
|
|
281003
|
+
var import_fs9 = require("fs");
|
|
280817
281004
|
var DEFAULT_OUT2 = "ablo/schema.ts";
|
|
280818
281005
|
var DEFAULT_IMPORT = "@abloatai/ablo/schema";
|
|
280819
281006
|
var TENANCY_COLUMN = "organization_id";
|
|
@@ -280924,53 +281111,53 @@ async function pull(argv) {
|
|
|
280924
281111
|
try {
|
|
280925
281112
|
args = parsePullArgs(argv);
|
|
280926
281113
|
} catch (err) {
|
|
280927
|
-
console.error(
|
|
281114
|
+
console.error(import_picocolors14.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
280928
281115
|
process.exit(1);
|
|
280929
281116
|
}
|
|
280930
281117
|
const dbUrl = process.env.DATABASE_URL ?? process.env.ABLO_DATABASE_URL;
|
|
280931
281118
|
if (!dbUrl) {
|
|
280932
|
-
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.`));
|
|
280933
281120
|
process.exit(1);
|
|
280934
281121
|
}
|
|
280935
|
-
if ((0,
|
|
281122
|
+
if ((0, import_fs9.existsSync)(args.out) && !args.force) {
|
|
280936
281123
|
console.error(
|
|
280937
|
-
|
|
281124
|
+
import_picocolors14.default.red(` ${args.out} already exists.`) + import_picocolors14.default.dim(` Re-run with ${import_picocolors14.default.bold("--force")} to overwrite.`)
|
|
280938
281125
|
);
|
|
280939
281126
|
process.exit(1);
|
|
280940
281127
|
}
|
|
280941
281128
|
console.log(`
|
|
280942
|
-
${brand("ablo")} ${
|
|
281129
|
+
${brand("ablo")} ${import_picocolors14.default.dim("pull")} ${import_picocolors14.default.dim(`schema "${args.appSchema}"`)}
|
|
280943
281130
|
`);
|
|
280944
281131
|
let result;
|
|
280945
281132
|
try {
|
|
280946
281133
|
result = await buildSchemaSourceFromDb({ dbUrl, appSchema: args.appSchema, importPath: args.importPath });
|
|
280947
281134
|
} catch (err) {
|
|
280948
|
-
console.error(
|
|
281135
|
+
console.error(import_picocolors14.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
|
|
280949
281136
|
process.exit(1);
|
|
280950
281137
|
}
|
|
280951
281138
|
if (result.models.length === 0) {
|
|
280952
281139
|
console.error(
|
|
280953
|
-
|
|
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).`)
|
|
280954
281141
|
);
|
|
280955
281142
|
process.exit(1);
|
|
280956
281143
|
}
|
|
280957
|
-
(0,
|
|
280958
|
-
console.log(` ${
|
|
280959
|
-
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(", ")}`)}`);
|
|
280960
281147
|
if (result.skipped > 0) {
|
|
280961
|
-
console.log(` ${
|
|
281148
|
+
console.log(` ${import_picocolors14.default.dim(`${result.skipped} table(s) skipped \u2014 no id/organization_id`)}`);
|
|
280962
281149
|
}
|
|
280963
281150
|
console.log(
|
|
280964
281151
|
`
|
|
280965
|
-
${
|
|
281152
|
+
${import_picocolors14.default.dim("Introspection is lossy (enums, JSON shape, relations). Review the file, then")} ${import_picocolors14.default.bold("ablo check")}.
|
|
280966
281153
|
`
|
|
280967
281154
|
);
|
|
280968
281155
|
}
|
|
280969
281156
|
|
|
280970
281157
|
// src/cli/prisma-pull.ts
|
|
280971
281158
|
init_cjs_shims();
|
|
280972
|
-
var
|
|
280973
|
-
var
|
|
281159
|
+
var import_picocolors15 = __toESM(require_picocolors(), 1);
|
|
281160
|
+
var import_fs10 = require("fs");
|
|
280974
281161
|
|
|
280975
281162
|
// src/cli/schema-ir.ts
|
|
280976
281163
|
init_cjs_shims();
|
|
@@ -281247,57 +281434,57 @@ async function prismaPull(argv) {
|
|
|
281247
281434
|
try {
|
|
281248
281435
|
args = parsePrismaPullArgs(argv);
|
|
281249
281436
|
} catch (err) {
|
|
281250
|
-
console.error(
|
|
281437
|
+
console.error(import_picocolors15.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
281251
281438
|
process.exit(1);
|
|
281252
281439
|
}
|
|
281253
|
-
if (!(0,
|
|
281440
|
+
if (!(0, import_fs10.existsSync)(args.schema)) {
|
|
281254
281441
|
console.error(
|
|
281255
|
-
|
|
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>")}.`)
|
|
281256
281443
|
);
|
|
281257
281444
|
process.exit(1);
|
|
281258
281445
|
}
|
|
281259
|
-
if ((0,
|
|
281446
|
+
if ((0, import_fs10.existsSync)(args.out) && !args.force) {
|
|
281260
281447
|
console.error(
|
|
281261
|
-
|
|
281448
|
+
import_picocolors15.default.red(` ${args.out} already exists.`) + import_picocolors15.default.dim(` Re-run with ${import_picocolors15.default.bold("--force")} to overwrite.`)
|
|
281262
281449
|
);
|
|
281263
281450
|
process.exit(1);
|
|
281264
281451
|
}
|
|
281265
281452
|
console.log(`
|
|
281266
|
-
${brand("ablo")} ${
|
|
281453
|
+
${brand("ablo")} ${import_picocolors15.default.dim("pull prisma")} ${import_picocolors15.default.dim(args.schema)}
|
|
281267
281454
|
`);
|
|
281268
281455
|
let result;
|
|
281269
281456
|
try {
|
|
281270
|
-
const src = (0,
|
|
281457
|
+
const src = (0, import_fs10.readFileSync)(args.schema, "utf8");
|
|
281271
281458
|
result = buildSchemaSourceFromPrisma({ src, importPath: args.importPath });
|
|
281272
281459
|
} catch (err) {
|
|
281273
|
-
console.error(
|
|
281460
|
+
console.error(import_picocolors15.default.red(` Couldn't parse the schema: ${err instanceof Error ? err.message : String(err)}`));
|
|
281274
281461
|
process.exit(1);
|
|
281275
281462
|
}
|
|
281276
281463
|
if (result.models.length === 0) {
|
|
281277
281464
|
console.error(
|
|
281278
|
-
|
|
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")}).`)
|
|
281279
281466
|
);
|
|
281280
281467
|
process.exit(1);
|
|
281281
281468
|
}
|
|
281282
|
-
(0,
|
|
281283
|
-
console.log(` ${
|
|
281284
|
-
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(", ")}`)}`);
|
|
281285
281472
|
if (result.skipped.length > 0) {
|
|
281286
|
-
console.log(` ${
|
|
281287
|
-
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}`)}`);
|
|
281288
281475
|
}
|
|
281289
281476
|
console.log(
|
|
281290
281477
|
`
|
|
281291
|
-
${
|
|
281478
|
+
${import_picocolors15.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors15.default.bold("ablo check")}.
|
|
281292
281479
|
`
|
|
281293
281480
|
);
|
|
281294
281481
|
}
|
|
281295
281482
|
|
|
281296
281483
|
// src/cli/drizzle-pull.ts
|
|
281297
281484
|
init_cjs_shims();
|
|
281298
|
-
var
|
|
281299
|
-
var
|
|
281300
|
-
var
|
|
281485
|
+
var import_picocolors16 = __toESM(require_picocolors(), 1);
|
|
281486
|
+
var import_fs11 = require("fs");
|
|
281487
|
+
var import_path6 = require("path");
|
|
281301
281488
|
var DEFAULT_OUT4 = "ablo/schema.ts";
|
|
281302
281489
|
var DEFAULT_IMPORT3 = "@abloatai/ablo/schema";
|
|
281303
281490
|
var BASE_FIELD_NAMES2 = /* @__PURE__ */ new Set(["id", "organizationId", "createdBy", "createdAt", "updatedAt"]);
|
|
@@ -281423,7 +281610,7 @@ function parseDrizzlePullArgs(argv) {
|
|
|
281423
281610
|
async function loadModule(path) {
|
|
281424
281611
|
const { createJiti } = await import("jiti");
|
|
281425
281612
|
const jiti = createJiti(process.cwd());
|
|
281426
|
-
const mod = await jiti.import((0,
|
|
281613
|
+
const mod = await jiti.import((0, import_path6.resolve)(path));
|
|
281427
281614
|
return mod;
|
|
281428
281615
|
}
|
|
281429
281616
|
async function drizzlePull(argv) {
|
|
@@ -281431,27 +281618,27 @@ async function drizzlePull(argv) {
|
|
|
281431
281618
|
try {
|
|
281432
281619
|
args = parseDrizzlePullArgs(argv);
|
|
281433
281620
|
} catch (err) {
|
|
281434
|
-
console.error(
|
|
281621
|
+
console.error(import_picocolors16.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
281435
281622
|
process.exit(1);
|
|
281436
281623
|
}
|
|
281437
281624
|
if (!args.schema) {
|
|
281438
281625
|
console.error(
|
|
281439
|
-
|
|
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")}.`)
|
|
281440
281627
|
);
|
|
281441
281628
|
process.exit(1);
|
|
281442
281629
|
}
|
|
281443
|
-
if (!(0,
|
|
281444
|
-
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)}.`));
|
|
281445
281632
|
process.exit(1);
|
|
281446
281633
|
}
|
|
281447
|
-
if ((0,
|
|
281634
|
+
if ((0, import_fs11.existsSync)(args.out) && !args.force) {
|
|
281448
281635
|
console.error(
|
|
281449
|
-
|
|
281636
|
+
import_picocolors16.default.red(` ${args.out} already exists.`) + import_picocolors16.default.dim(` Re-run with ${import_picocolors16.default.bold("--force")} to overwrite.`)
|
|
281450
281637
|
);
|
|
281451
281638
|
process.exit(1);
|
|
281452
281639
|
}
|
|
281453
281640
|
console.log(`
|
|
281454
|
-
${brand("ablo")} ${
|
|
281641
|
+
${brand("ablo")} ${import_picocolors16.default.dim("pull drizzle")} ${import_picocolors16.default.dim(args.schema)}
|
|
281455
281642
|
`);
|
|
281456
281643
|
let result;
|
|
281457
281644
|
try {
|
|
@@ -281459,33 +281646,33 @@ async function drizzlePull(argv) {
|
|
|
281459
281646
|
result = await buildSchemaSourceFromDrizzle({ mod, importPath: args.importPath });
|
|
281460
281647
|
} catch (err) {
|
|
281461
281648
|
const msg = err instanceof Error ? err.message : String(err);
|
|
281462
|
-
const hint = /Cannot find package 'drizzle-orm'/.test(msg) ?
|
|
281463
|
-
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);
|
|
281464
281651
|
process.exit(1);
|
|
281465
281652
|
}
|
|
281466
281653
|
if (result.models.length === 0) {
|
|
281467
281654
|
console.error(
|
|
281468
|
-
|
|
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).`)
|
|
281469
281656
|
);
|
|
281470
281657
|
process.exit(1);
|
|
281471
281658
|
}
|
|
281472
|
-
(0,
|
|
281473
|
-
console.log(` ${
|
|
281474
|
-
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(", ")}`)}`);
|
|
281475
281662
|
if (result.skipped.length > 0) {
|
|
281476
|
-
console.log(` ${
|
|
281477
|
-
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}`)}`);
|
|
281478
281665
|
}
|
|
281479
281666
|
console.log(
|
|
281480
281667
|
`
|
|
281481
|
-
${
|
|
281668
|
+
${import_picocolors16.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors16.default.bold("ablo check")}.
|
|
281482
281669
|
`
|
|
281483
281670
|
);
|
|
281484
281671
|
}
|
|
281485
281672
|
|
|
281486
281673
|
// src/cli/index.ts
|
|
281487
281674
|
var LOGO = `
|
|
281488
|
-
${brand("ablo")} ${
|
|
281675
|
+
${brand("ablo")} ${import_picocolors17.default.dim("sync engine")}
|
|
281489
281676
|
`;
|
|
281490
281677
|
async function main() {
|
|
281491
281678
|
const command = process.argv[2];
|
|
@@ -281504,7 +281691,8 @@ async function main() {
|
|
|
281504
281691
|
} else if (command === "webhooks") {
|
|
281505
281692
|
await webhooks(process.argv.slice(3));
|
|
281506
281693
|
} else if (command === "dev") {
|
|
281507
|
-
|
|
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"]);
|
|
281508
281696
|
} else if (command === "check") {
|
|
281509
281697
|
await check(process.argv.slice(3));
|
|
281510
281698
|
} else if (command === "pull") {
|
|
@@ -281519,20 +281707,27 @@ async function main() {
|
|
|
281519
281707
|
} else if (command === "migrate") {
|
|
281520
281708
|
await migrate(process.argv.slice(3));
|
|
281521
281709
|
} else if (command === "push") {
|
|
281522
|
-
|
|
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
|
+
}
|
|
281523
281718
|
} else if (command === "upgrade") {
|
|
281524
281719
|
await upgrade(process.argv.slice(3));
|
|
281525
281720
|
} else if (command === "generate") {
|
|
281526
281721
|
await generate(process.argv.slice(3));
|
|
281527
281722
|
} else if (command === "schema") {
|
|
281528
281723
|
console.error(
|
|
281529
|
-
` ${
|
|
281724
|
+
` ${import_picocolors17.default.red("\u2717")} \`ablo schema push\` was renamed to \`${brand("ablo push")}\`.`
|
|
281530
281725
|
);
|
|
281531
281726
|
console.error(` Run \`ablo push${process.argv.slice(4).join(" ") ? " " + process.argv.slice(4).join(" ") : ""}\` instead.`);
|
|
281532
281727
|
process.exitCode = 1;
|
|
281533
281728
|
} else {
|
|
281534
281729
|
console.log(LOGO);
|
|
281535
|
-
console.log(` ${
|
|
281730
|
+
console.log(` ${import_picocolors17.default.bold("Usage:")}`);
|
|
281536
281731
|
console.log(` npx ablo init Scaffold ablo/ directory + starter schema`);
|
|
281537
281732
|
console.log(` npx ablo init --yes [--framework nextjs] Non-interactive (agents/CI): no prompts, flag-driven`);
|
|
281538
281733
|
console.log(` [--auth apikey] [--storage direct|endpoint] [--no-agent] [--no-pull] [--no-install] [--no-login]`);
|
|
@@ -281557,10 +281752,10 @@ async function main() {
|
|
|
281557
281752
|
console.log(` npx ablo generate Emit TypeScript types from your schema`);
|
|
281558
281753
|
console.log(` npx ablo generate --out path.ts Write generated types to a path`);
|
|
281559
281754
|
console.log();
|
|
281560
|
-
console.log(` ${
|
|
281755
|
+
console.log(` ${import_picocolors17.default.bold("Schema workflow:")}`);
|
|
281561
281756
|
console.log(` The server holds its own copy of your schema \u2014 edit ${brand("ablo/schema.ts")}, then`);
|
|
281562
281757
|
console.log(` run ${brand("ablo push")} (or keep ${brand("ablo dev")} running) before the server will accept`);
|
|
281563
|
-
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")}.`);
|
|
281564
281759
|
console.log();
|
|
281565
281760
|
}
|
|
281566
281761
|
}
|
|
@@ -281597,7 +281792,7 @@ function parseInitArgs(args) {
|
|
|
281597
281792
|
function detectOrm(override) {
|
|
281598
281793
|
if (override === "prisma" || override === "drizzle" || override === "none") return override;
|
|
281599
281794
|
try {
|
|
281600
|
-
const pkg = JSON.parse((0,
|
|
281795
|
+
const pkg = JSON.parse((0, import_fs12.readFileSync)("package.json", "utf-8"));
|
|
281601
281796
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
281602
281797
|
if (deps["@prisma/client"] || deps["prisma"]) return "prisma";
|
|
281603
281798
|
if (deps["drizzle-orm"]) return "drizzle";
|
|
@@ -281628,8 +281823,8 @@ async function chooseBool(flagValue, fallback, interactive, prompt) {
|
|
|
281628
281823
|
async function init(args = []) {
|
|
281629
281824
|
const opts = parseInitArgs(args);
|
|
281630
281825
|
const interactive = Boolean(process.stdin.isTTY) && !opts.yes && !process.env.CI;
|
|
281631
|
-
Ie(`${brand("ablo")} ${
|
|
281632
|
-
if (!(0,
|
|
281826
|
+
Ie(`${brand("ablo")} ${import_picocolors17.default.dim("sync engine")}`);
|
|
281827
|
+
if (!(0, import_fs12.existsSync)("package.json")) {
|
|
281633
281828
|
xe("No package.json found. Run this from your project root.");
|
|
281634
281829
|
process.exit(1);
|
|
281635
281830
|
}
|
|
@@ -281705,14 +281900,14 @@ async function init(args = []) {
|
|
|
281705
281900
|
);
|
|
281706
281901
|
}
|
|
281707
281902
|
const abloDir = "ablo";
|
|
281708
|
-
(0,
|
|
281903
|
+
(0, import_fs12.mkdirSync)(abloDir, { recursive: true });
|
|
281709
281904
|
const created = [];
|
|
281710
281905
|
let schemaSource = generateSchema();
|
|
281711
281906
|
let schemaNote = "";
|
|
281712
281907
|
if (pullExisting) {
|
|
281713
281908
|
const dbUrl = process.env.DATABASE_URL ?? process.env.ABLO_DATABASE_URL;
|
|
281714
281909
|
if (!dbUrl) {
|
|
281715
|
-
schemaNote =
|
|
281910
|
+
schemaNote = import_picocolors17.default.dim(" (no DATABASE_URL \u2014 wrote starter; run `ablo pull` later)");
|
|
281716
281911
|
} else {
|
|
281717
281912
|
try {
|
|
281718
281913
|
const pulled = await buildSchemaSourceFromDb({
|
|
@@ -281722,60 +281917,60 @@ async function init(args = []) {
|
|
|
281722
281917
|
});
|
|
281723
281918
|
if (pulled.models.length > 0) {
|
|
281724
281919
|
schemaSource = pulled.source;
|
|
281725
|
-
schemaNote =
|
|
281920
|
+
schemaNote = import_picocolors17.default.dim(` (pulled ${pulled.models.length} models)`);
|
|
281726
281921
|
} else {
|
|
281727
|
-
schemaNote =
|
|
281922
|
+
schemaNote = import_picocolors17.default.dim(" (no adoptable tables \u2014 wrote starter)");
|
|
281728
281923
|
}
|
|
281729
281924
|
} catch {
|
|
281730
|
-
schemaNote =
|
|
281925
|
+
schemaNote = import_picocolors17.default.dim(" (pull failed \u2014 wrote starter)");
|
|
281731
281926
|
}
|
|
281732
281927
|
}
|
|
281733
281928
|
}
|
|
281734
|
-
(0,
|
|
281929
|
+
(0, import_fs12.writeFileSync)((0, import_path7.join)(abloDir, "schema.ts"), schemaSource);
|
|
281735
281930
|
created.push(`${abloDir}/schema.ts${schemaNote}`);
|
|
281736
|
-
(0,
|
|
281931
|
+
(0, import_fs12.writeFileSync)((0, import_path7.join)(abloDir, "index.ts"), generateSyncConfig(auth, storage));
|
|
281737
281932
|
created.push(`${abloDir}/index.ts`);
|
|
281738
281933
|
const orm = detectOrm(opts.orm);
|
|
281739
281934
|
if (storage === "endpoint") {
|
|
281740
|
-
(0,
|
|
281935
|
+
(0, import_fs12.writeFileSync)((0, import_path7.join)(abloDir, "data-source.ts"), generateDataSource(orm));
|
|
281741
281936
|
created.push(`${abloDir}/data-source.ts${orm === "drizzle" ? " (Drizzle)" : " (Prisma)"}`);
|
|
281742
281937
|
}
|
|
281743
281938
|
const envFile = framework === "nextjs" ? ".env.local" : ".env";
|
|
281744
|
-
if (!(0,
|
|
281745
|
-
(0,
|
|
281939
|
+
if (!(0, import_fs12.existsSync)(envFile)) {
|
|
281940
|
+
(0, import_fs12.writeFileSync)(envFile, generateEnv(storage));
|
|
281746
281941
|
created.push(envFile);
|
|
281747
281942
|
} else {
|
|
281748
|
-
const existing = (0,
|
|
281943
|
+
const existing = (0, import_fs12.readFileSync)(envFile, "utf-8");
|
|
281749
281944
|
if (!existing.includes("ABLO_")) {
|
|
281750
|
-
(0,
|
|
281751
|
-
created.push(`${envFile} ${
|
|
281945
|
+
(0, import_fs12.writeFileSync)(envFile, existing + "\n" + generateEnv(storage));
|
|
281946
|
+
created.push(`${envFile} ${import_picocolors17.default.dim("(appended)")}`);
|
|
281752
281947
|
} else {
|
|
281753
|
-
created.push(`${envFile} ${
|
|
281948
|
+
created.push(`${envFile} ${import_picocolors17.default.dim("(already configured)")}`);
|
|
281754
281949
|
}
|
|
281755
281950
|
}
|
|
281756
281951
|
if (agent) {
|
|
281757
|
-
(0,
|
|
281952
|
+
(0, import_fs12.writeFileSync)((0, import_path7.join)(abloDir, "agent.ts"), generateAgent());
|
|
281758
281953
|
created.push(`${abloDir}/agent.ts`);
|
|
281759
281954
|
}
|
|
281760
281955
|
if (framework === "nextjs") {
|
|
281761
281956
|
if (storage === "endpoint") {
|
|
281762
|
-
const webhookDir = (0,
|
|
281763
|
-
(0,
|
|
281764
|
-
(0,
|
|
281957
|
+
const webhookDir = (0, import_path7.join)("app", "api", "ablo", "webhooks");
|
|
281958
|
+
(0, import_fs12.mkdirSync)(webhookDir, { recursive: true });
|
|
281959
|
+
(0, import_fs12.writeFileSync)((0, import_path7.join)(webhookDir, "route.ts"), generateWebhookRoute(orm));
|
|
281765
281960
|
created.push(`${webhookDir}/route.ts${orm === "prisma" ? " (Prisma mirror)" : " (add your database write)"}`);
|
|
281766
281961
|
}
|
|
281767
|
-
(0,
|
|
281768
|
-
created.push(`app/providers.tsx ${
|
|
281769
|
-
const sessionDir = (0,
|
|
281770
|
-
(0,
|
|
281771
|
-
(0,
|
|
281772
|
-
created.push(`app/api/ablo-session/route.ts ${
|
|
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>)")}`);
|
|
281964
|
+
const sessionDir = (0, import_path7.join)("app", "api", "ablo-session");
|
|
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)")}`);
|
|
281773
281968
|
}
|
|
281774
281969
|
if (framework !== "vanilla") {
|
|
281775
|
-
(0,
|
|
281970
|
+
(0, import_fs12.writeFileSync)((0, import_path7.join)(abloDir, "TaskList.tsx"), generateComponent());
|
|
281776
281971
|
created.push(`${abloDir}/TaskList.tsx`);
|
|
281777
281972
|
}
|
|
281778
|
-
Me(created.map((f) => `${
|
|
281973
|
+
Me(created.map((f) => `${import_picocolors17.default.green("\u2713")} ${f}`).join("\n"), "Created");
|
|
281779
281974
|
const pm = detectPackageManager();
|
|
281780
281975
|
if (opts.install) {
|
|
281781
281976
|
const s = Y2();
|
|
@@ -281784,38 +281979,43 @@ async function init(args = []) {
|
|
|
281784
281979
|
(0, import_child_process2.execSync)(`${pm} add @abloatai/ablo`, { stdio: "ignore" });
|
|
281785
281980
|
s.stop("Installed @abloatai/ablo");
|
|
281786
281981
|
} catch {
|
|
281787
|
-
s.stop(`${
|
|
281982
|
+
s.stop(`${import_picocolors17.default.yellow("!")} Couldn't auto-install \u2014 run ${import_picocolors17.default.bold(`${pm} install @abloatai/ablo`)}`);
|
|
281788
281983
|
}
|
|
281789
281984
|
}
|
|
281790
281985
|
const steps = [
|
|
281791
|
-
`Get a ${
|
|
281792
|
-
`Run ${
|
|
281793
|
-
`Set ${
|
|
281794
|
-
`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`,
|
|
281795
281990
|
...storage === "direct" ? [
|
|
281796
|
-
`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)`
|
|
281797
281992
|
] : [
|
|
281798
|
-
`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")}`
|
|
281799
281994
|
],
|
|
281800
281995
|
...framework === "nextjs" ? [
|
|
281801
|
-
`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")}`
|
|
281802
281997
|
] : [],
|
|
281803
|
-
`Run ${
|
|
281998
|
+
`Run ${import_picocolors17.default.bold(`${pm} run dev`)} and open two browser tabs \u2014 changes sync in real-time`,
|
|
281804
281999
|
...agent ? [
|
|
281805
|
-
`Run ${
|
|
281806
|
-
`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`
|
|
281807
282002
|
] : []
|
|
281808
282003
|
];
|
|
281809
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
|
+
}
|
|
281810
282010
|
if (interactive && opts.login) {
|
|
281811
282011
|
const loginNow = await ye({ message: "Log in now? (opens your browser)", initialValue: true });
|
|
281812
282012
|
if (!pD(loginNow) && loginNow) {
|
|
281813
|
-
Se(`${
|
|
282013
|
+
Se(`${import_picocolors17.default.dim("Docs:")} https://abloatai.com/docs`);
|
|
281814
282014
|
await login();
|
|
281815
282015
|
return;
|
|
281816
282016
|
}
|
|
281817
282017
|
}
|
|
281818
|
-
Se(`Run ${
|
|
282018
|
+
Se(`Run ${import_picocolors17.default.bold("npx ablo login")} when ready. ${import_picocolors17.default.dim("Docs:")} https://abloatai.com/docs`);
|
|
281819
282019
|
}
|
|
281820
282020
|
function generateSchema() {
|
|
281821
282021
|
return `import { defineSchema, model, relation, z } from '@abloatai/ablo/schema';
|
|
@@ -282169,9 +282369,9 @@ async function getCurrentUser(): Promise<{ id: string } | null> {
|
|
|
282169
282369
|
`;
|
|
282170
282370
|
}
|
|
282171
282371
|
function detectPackageManager() {
|
|
282172
|
-
if ((0,
|
|
282173
|
-
if ((0,
|
|
282174
|
-
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";
|
|
282175
282375
|
return "npm";
|
|
282176
282376
|
}
|
|
282177
282377
|
main().catch(console.error);
|