@abloatai/ablo 0.33.0 → 0.34.1
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/AGENTS.md +2 -0
- package/CHANGELOG.md +22 -0
- package/dist/cli.cjs +500 -383
- package/dist/client/Ablo.js +3 -2
- package/dist/client/createModelProxy.d.ts +53 -10
- package/dist/client/createModelProxy.js +24 -5
- package/dist/client/httpTransport.js +1 -0
- package/dist/client/resourceTypes.d.ts +10 -1
- package/dist/client/wsMutationExecutor.d.ts +2 -2
- package/dist/client/wsMutationExecutor.js +1 -1
- package/dist/coordination/index.d.ts +2 -2
- package/dist/coordination/index.js +1 -1
- package/dist/coordination/schema.d.ts +20 -0
- package/dist/coordination/schema.js +22 -0
- package/dist/errorCodes.d.ts +1 -1
- package/dist/errorCodes.js +1 -1
- package/dist/interfaces/index.d.ts +13 -1
- package/dist/react/AbloProvider.d.ts +8 -8
- package/dist/react/AbloProvider.js +6 -6
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +2 -2
- package/dist/server/commit.d.ts +8 -1
- package/dist/surface.d.ts +1 -1
- package/dist/surface.js +2 -1
- package/dist/sync/SyncWebSocket.d.ts +3 -3
- package/dist/sync/SyncWebSocket.js +4 -4
- package/dist/sync/commitFrames.d.ts +2 -2
- package/dist/sync/commitFrames.js +5 -1
- package/dist/transactions/TransactionQueue.d.ts +4 -1
- package/dist/transactions/TransactionQueue.js +18 -0
- package/dist/transactions/commitEnvelope.d.ts +8 -0
- package/dist/transactions/commitEnvelope.js +2 -1
- package/dist/transactions/durableWriteStore.d.ts +8 -0
- package/dist/wire/frames.d.ts +17 -1
- package/dist/wire/frames.js +2 -1
- package/docs/client-behavior.md +1 -1
- package/docs/coordination.md +5 -5
- package/docs/groups.md +50 -0
- package/docs/identity.md +2 -2
- package/docs/index.md +2 -0
- package/docs/migration.md +29 -5
- package/docs/operating-on-your-database.md +109 -0
- package/docs/react.md +9 -9
- package/llms.txt +1 -1
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -787,8 +787,8 @@ ${import_picocolors2.default.gray(d2)} ${t}
|
|
|
787
787
|
if (i) process.stdout.write(`${I2} ${l2}...`);
|
|
788
788
|
else if (t === "timer") process.stdout.write(`${I2} ${l2} ${O2(g2)}`);
|
|
789
789
|
else {
|
|
790
|
-
const
|
|
791
|
-
process.stdout.write(`${I2} ${l2}${
|
|
790
|
+
const z9 = ".".repeat(Math.floor(w2)).slice(0, 3);
|
|
791
|
+
process.stdout.write(`${I2} ${l2}${z9}`);
|
|
792
792
|
}
|
|
793
793
|
h2 = h2 + 1 < n.length ? h2 + 1 : 0, w2 = w2 < n.length ? w2 + 0.125 : 0;
|
|
794
794
|
}, r2);
|
|
@@ -909,7 +909,7 @@ var init_errorCodes = __esm({
|
|
|
909
909
|
model_claimed: wire("claim", 409, false, "Another participant holds a claim on this row. Read `claim.state` to see who holds it, or queue behind them with a claim of your own."),
|
|
910
910
|
model_claimed_timeout: wire("claim", 409, false, "Another participant held a claim on this row and did not release it in time. Retry, or read `claim.state` to see who holds it."),
|
|
911
911
|
model_claim_not_configured: client("claim", "Claiming requires the collaboration runtime, which the standard Ablo({ schema, apiKey }) client wires up for every model automatically \u2014 there is no per-model claim configuration to add. This appears only when a model proxy is constructed directly without that runtime (an internal/advanced path)."),
|
|
912
|
-
|
|
912
|
+
model_join_not_configured: client("claim", "join() opens a presence/claim subscription and needs a live WebSocket, so it is unavailable on the HTTP transport and on model proxies built without a socket. Use the standard Ablo({ schema, apiKey }) client (default WebSocket transport)."),
|
|
913
913
|
// ── stale context / idempotency (409) ──────────────────────────────
|
|
914
914
|
// Not retryable at the transport: the rejected request carries its frozen
|
|
915
915
|
// `readAt`, so resending the identical payload can never succeed. Recovery
|
|
@@ -1199,7 +1199,7 @@ var init_roles = __esm({
|
|
|
1199
1199
|
});
|
|
1200
1200
|
|
|
1201
1201
|
// src/coordination/schema.ts
|
|
1202
|
-
var import_zod3, targetRangeSchema, participantKindSchema, wireParticipantKindSchema, targetRefSchema, onStaleModeSchema, writeGuardSchema, staleNotificationSchema, readDependencySchema, claimStatusSchema, grantStampFields, wireClaimBaseSchema, wireClaimSummarySchema, claimErrorSchema, wireClaimSchema, claimRejectionSchema, claimLostSchema, modelTargetSchema, modelClaimSchema, claimBeginPayloadSchema, claimAbandonPayloadSchema, claimReorderPayloadSchema, claimHeartbeatFieldsSchema, claimHeartbeatPayloadSchema, claimHeartbeatAckPayloadSchema, claimHeartbeatBatchPayloadSchema, claimHeartbeatBatchAckPayloadSchema, updateSubscriptionPayloadSchema, subscriptionAckPayloadSchema, commitOperationTypeSchema, commitOperationSchema, presenceKindSchema, presenceActivitySchema, presenceUpdateFrameSchema;
|
|
1202
|
+
var import_zod3, targetRangeSchema, participantKindSchema, wireParticipantKindSchema, targetRefSchema, onStaleModeSchema, writeGuardSchema, staleNotificationSchema, readDependencySchema, trackDependencySchema, claimStatusSchema, grantStampFields, wireClaimBaseSchema, wireClaimSummarySchema, claimErrorSchema, wireClaimSchema, claimRejectionSchema, claimLostSchema, modelTargetSchema, modelClaimSchema, claimBeginPayloadSchema, claimAbandonPayloadSchema, claimReorderPayloadSchema, claimHeartbeatFieldsSchema, claimHeartbeatPayloadSchema, claimHeartbeatAckPayloadSchema, claimHeartbeatBatchPayloadSchema, claimHeartbeatBatchAckPayloadSchema, updateSubscriptionPayloadSchema, subscriptionAckPayloadSchema, commitOperationTypeSchema, commitOperationSchema, presenceKindSchema, presenceActivitySchema, presenceUpdateFrameSchema;
|
|
1203
1203
|
var init_schema = __esm({
|
|
1204
1204
|
"src/coordination/schema.ts"() {
|
|
1205
1205
|
"use strict";
|
|
@@ -1284,6 +1284,17 @@ var init_schema = __esm({
|
|
|
1284
1284
|
onStale: onStaleModeSchema.optional()
|
|
1285
1285
|
})
|
|
1286
1286
|
]);
|
|
1287
|
+
trackDependencySchema = import_zod3.z.union([
|
|
1288
|
+
import_zod3.z.object({
|
|
1289
|
+
model: import_zod3.z.string(),
|
|
1290
|
+
id: import_zod3.z.string(),
|
|
1291
|
+
readAt: import_zod3.z.number().optional()
|
|
1292
|
+
}),
|
|
1293
|
+
import_zod3.z.object({
|
|
1294
|
+
group: import_zod3.z.string(),
|
|
1295
|
+
readAt: import_zod3.z.number().optional()
|
|
1296
|
+
})
|
|
1297
|
+
]);
|
|
1287
1298
|
claimStatusSchema = import_zod3.z.enum([
|
|
1288
1299
|
"active",
|
|
1289
1300
|
"committed",
|
|
@@ -5594,7 +5605,8 @@ async function registerDirectDataSource(opts) {
|
|
|
5594
5605
|
console.log(
|
|
5595
5606
|
`
|
|
5596
5607
|
${import_picocolors6.default.green("\u2713")} Registered${body2.host ? ` ${import_picocolors6.default.dim(body2.host)}` : ""}${body2.id ? ` ${import_picocolors6.default.dim(`(${body2.id})`)}` : ""} as a direct DataSource (${statusNote}).
|
|
5597
|
-
|
|
5608
|
+
Your database is connected. Reads follow its replication stream; writes go through Ablo
|
|
5609
|
+
and land in your own tables. Check the connection anytime with ${import_picocolors6.default.cyan("ablo connect check")}.
|
|
5598
5610
|
`
|
|
5599
5611
|
);
|
|
5600
5612
|
return true;
|
|
@@ -5829,12 +5841,130 @@ var init_disconnect = __esm({
|
|
|
5829
5841
|
}
|
|
5830
5842
|
});
|
|
5831
5843
|
|
|
5844
|
+
// src/cli/connectOwnership.ts
|
|
5845
|
+
function ownershipBlockers(rows) {
|
|
5846
|
+
return rows.filter((row) => !row.can_manage && !row.is_superuser).map((row) => ({
|
|
5847
|
+
relation: row.relation,
|
|
5848
|
+
owner: row.owner,
|
|
5849
|
+
canGrantInherit: row.can_grant_inherit
|
|
5850
|
+
}));
|
|
5851
|
+
}
|
|
5852
|
+
function ownershipRemediation(blockers, admin) {
|
|
5853
|
+
const grantableByOwner = /* @__PURE__ */ new Map();
|
|
5854
|
+
for (const blocker of blockers) {
|
|
5855
|
+
grantableByOwner.set(
|
|
5856
|
+
blocker.owner,
|
|
5857
|
+
(grantableByOwner.get(blocker.owner) ?? false) || blocker.canGrantInherit
|
|
5858
|
+
);
|
|
5859
|
+
}
|
|
5860
|
+
const resolvedOwners = /* @__PURE__ */ new Set();
|
|
5861
|
+
const inheritGrants = [];
|
|
5862
|
+
for (const [owner, grantable] of grantableByOwner) {
|
|
5863
|
+
if (grantable) {
|
|
5864
|
+
inheritGrants.push(`GRANT ${quoteIdent(owner)} TO ${quoteIdent(admin)} WITH INHERIT TRUE;`);
|
|
5865
|
+
resolvedOwners.add(owner);
|
|
5866
|
+
}
|
|
5867
|
+
}
|
|
5868
|
+
const unresolved = blockers.filter((blocker) => !resolvedOwners.has(blocker.owner));
|
|
5869
|
+
return { inheritGrants, unresolved };
|
|
5870
|
+
}
|
|
5871
|
+
async function publishedTableBlockers(sql, tables) {
|
|
5872
|
+
const scoped = tables.length > 0;
|
|
5873
|
+
const raw = await sql.unsafe(
|
|
5874
|
+
`SELECT format('%I.%I', n.nspname, c.relname) AS relation, ${OWNERSHIP_COLUMNS}
|
|
5875
|
+
${OWNERSHIP_FROM}
|
|
5876
|
+
WHERE c.relkind = 'r'
|
|
5877
|
+
AND n.nspname = 'public'
|
|
5878
|
+
AND c.relname <> 'ablo_idempotency'
|
|
5879
|
+
${scoped ? "AND c.relname = ANY($1)" : ""}`,
|
|
5880
|
+
scoped ? [tables] : []
|
|
5881
|
+
);
|
|
5882
|
+
return ownershipBlockers(import_zod7.z.array(ownedRelationRowSchema).parse(raw));
|
|
5883
|
+
}
|
|
5884
|
+
async function ledgerBlocker(sql) {
|
|
5885
|
+
const raw = await sql.unsafe(
|
|
5886
|
+
`SELECT format('%I.%I', n.nspname, c.relname) AS relation, ${OWNERSHIP_COLUMNS}
|
|
5887
|
+
${OWNERSHIP_FROM}
|
|
5888
|
+
WHERE c.relkind = 'r'
|
|
5889
|
+
AND n.nspname = 'public'
|
|
5890
|
+
AND c.relname = 'ablo_idempotency'`
|
|
5891
|
+
);
|
|
5892
|
+
const rows = import_zod7.z.array(ownedRelationRowSchema).parse(raw);
|
|
5893
|
+
const row = rows[0];
|
|
5894
|
+
if (!row) return null;
|
|
5895
|
+
return ownershipBlockers([row])[0] ?? null;
|
|
5896
|
+
}
|
|
5897
|
+
function formatUnresolvedOwnership(unresolved, admin, target) {
|
|
5898
|
+
const list = unresolved.map((b4) => `${b4.relation} (owned by ${b4.owner})`).join("\n ");
|
|
5899
|
+
const owners = [...new Set(unresolved.map((b4) => b4.owner))];
|
|
5900
|
+
const ownerNames = owners.map((o2) => import_picocolors8.default.bold(o2)).join(", ");
|
|
5901
|
+
const grants = owners.map((o2) => `GRANT ${quoteIdent(o2)} TO ${quoteIdent(admin)} WITH INHERIT TRUE;`).join(" ");
|
|
5902
|
+
const one = unresolved.length === 1;
|
|
5903
|
+
const hasLedger = unresolved.some((b4) => b4.relation.endsWith(".ablo_idempotency"));
|
|
5904
|
+
return import_picocolors8.default.red(
|
|
5905
|
+
`
|
|
5906
|
+
${import_picocolors8.default.bold(String(unresolved.length))} relation${one ? "" : "s"} on ${target} ${one ? "is" : "are"} owned by a role ${import_picocolors8.default.bold(admin)} can't manage or take over:`
|
|
5907
|
+
) + `
|
|
5908
|
+
${list}
|
|
5909
|
+
|
|
5910
|
+
Apply grants your admin inheritance of an owning role for you when it may, but ${admin}
|
|
5911
|
+
isn't a member with admin option of ${ownerNames}, so it can't here. Re-run ${import_picocolors8.default.bold("--url")} as a
|
|
5912
|
+
role that owns ${one ? "it" : "them"}, or have a role with admin option on ${ownerNames} (or a
|
|
5913
|
+
superuser) run:
|
|
5914
|
+
${import_picocolors8.default.cyan(grants)}
|
|
5915
|
+
` + (hasLedger ? `
|
|
5916
|
+
For ${import_picocolors8.default.bold("ablo_idempotency")} you can instead drop it \u2014 it holds only idempotency replay
|
|
5917
|
+
records, safe to drop when no commit is in flight \u2014 and Ablo recreates it under this admin:
|
|
5918
|
+
${import_picocolors8.default.cyan("DROP TABLE ablo_idempotency;")}
|
|
5919
|
+
` : "");
|
|
5920
|
+
}
|
|
5921
|
+
var import_zod7, import_picocolors8, ownedRelationRowSchema, OWNERSHIP_COLUMNS, OWNERSHIP_FROM;
|
|
5922
|
+
var init_connectOwnership = __esm({
|
|
5923
|
+
"src/cli/connectOwnership.ts"() {
|
|
5924
|
+
"use strict";
|
|
5925
|
+
init_cjs_shims();
|
|
5926
|
+
import_zod7 = require("zod");
|
|
5927
|
+
import_picocolors8 = __toESM(require_picocolors(), 1);
|
|
5928
|
+
init_connectSetup();
|
|
5929
|
+
ownedRelationRowSchema = import_zod7.z.object({
|
|
5930
|
+
/** Schema-qualified relation, e.g. `public.documents`. */
|
|
5931
|
+
relation: import_zod7.z.string(),
|
|
5932
|
+
owner: import_zod7.z.string(),
|
|
5933
|
+
/**
|
|
5934
|
+
* The admin can act as the owner for grants — it owns the relation OR is an
|
|
5935
|
+
* INHERITing member of the owning role (`pg_has_role(current_user, owner,
|
|
5936
|
+
* 'USAGE')`). A plain NOINHERIT membership is false: the plan doesn't
|
|
5937
|
+
* `SET ROLE`, so the grant would fail.
|
|
5938
|
+
*/
|
|
5939
|
+
can_manage: import_zod7.z.boolean(),
|
|
5940
|
+
is_superuser: import_zod7.z.boolean(),
|
|
5941
|
+
/**
|
|
5942
|
+
* The admin is a member of the owning role WITH admin option, so it can run
|
|
5943
|
+
* `GRANT <owner> TO <admin> WITH INHERIT TRUE` itself to gain the inheritance
|
|
5944
|
+
* the grants need — the runnable fix reassigning ownership can't be.
|
|
5945
|
+
*/
|
|
5946
|
+
can_grant_inherit: import_zod7.z.boolean()
|
|
5947
|
+
});
|
|
5948
|
+
OWNERSHIP_COLUMNS = `
|
|
5949
|
+
pg_get_userbyid(c.relowner) AS owner,
|
|
5950
|
+
pg_has_role(current_user, c.relowner, 'USAGE') AS can_manage,
|
|
5951
|
+
r.rolsuper AS is_superuser,
|
|
5952
|
+
EXISTS (
|
|
5953
|
+
SELECT 1 FROM pg_auth_members m
|
|
5954
|
+
WHERE m.member = r.oid AND m.roleid = c.relowner AND m.admin_option
|
|
5955
|
+
) AS can_grant_inherit`;
|
|
5956
|
+
OWNERSHIP_FROM = `
|
|
5957
|
+
FROM pg_class c
|
|
5958
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
5959
|
+
JOIN pg_roles r ON r.rolname = current_user`;
|
|
5960
|
+
}
|
|
5961
|
+
});
|
|
5962
|
+
|
|
5832
5963
|
// src/cli/connectApply.ts
|
|
5833
5964
|
var connectApply_exports = {};
|
|
5834
5965
|
__export(connectApply_exports, {
|
|
5835
5966
|
connectApplyPlan: () => connectApplyPlan,
|
|
5836
5967
|
detectProvider: () => detectProvider,
|
|
5837
|
-
ledgerBlockedBy: () => ledgerBlockedBy,
|
|
5838
5968
|
logicalReplicationGuidance: () => logicalReplicationGuidance,
|
|
5839
5969
|
passwordClause: () => passwordClause,
|
|
5840
5970
|
postRegistrationOutcome: () => postRegistrationOutcome,
|
|
@@ -5890,7 +6020,16 @@ EXCEPTION WHEN duplicate_object THEN NULL;
|
|
|
5890
6020
|
END $$;`
|
|
5891
6021
|
];
|
|
5892
6022
|
const publicationDetail = reconcile2?.sql.length === 0 ? "already publishing exactly these tables \u2014 nothing to change" : tables.length > 0 ? `a read stream of the ${tables.length} table${tables.length === 1 ? "" : "s"} you chose` : "a read stream of your tables";
|
|
6023
|
+
const ownStep = input.inheritGrants && input.inheritGrants.length > 0 ? [
|
|
6024
|
+
{
|
|
6025
|
+
key: "own",
|
|
6026
|
+
title: "Let this admin manage tables owned by another role",
|
|
6027
|
+
detail: "your admin inherits the owning role so the steps below apply \u2014 reversible, no ownership change",
|
|
6028
|
+
sql: input.inheritGrants
|
|
6029
|
+
}
|
|
6030
|
+
] : [];
|
|
5893
6031
|
return [
|
|
6032
|
+
...ownStep,
|
|
5894
6033
|
...walStep,
|
|
5895
6034
|
{
|
|
5896
6035
|
key: "publication",
|
|
@@ -5932,15 +6071,15 @@ function printPlan2(steps, showSql) {
|
|
|
5932
6071
|
console.log(` This sets up your database for Ablo:
|
|
5933
6072
|
`);
|
|
5934
6073
|
for (const step of steps) {
|
|
5935
|
-
console.log(` ${
|
|
6074
|
+
console.log(` ${import_picocolors9.default.green("\u2022")} ${step.title}`);
|
|
5936
6075
|
if (showSql) {
|
|
5937
6076
|
for (const statement of step.sql) {
|
|
5938
|
-
for (const line of statement.split("\n")) console.log(` ${
|
|
6077
|
+
for (const line of statement.split("\n")) console.log(` ${import_picocolors9.default.dim(line)}`);
|
|
5939
6078
|
}
|
|
5940
6079
|
}
|
|
5941
6080
|
}
|
|
5942
6081
|
console.log(
|
|
5943
|
-
|
|
6082
|
+
import_picocolors9.default.dim(
|
|
5944
6083
|
`
|
|
5945
6084
|
Your admin password stays on this machine.${showSql ? "" : " (--show-sql for the exact statements)"}
|
|
5946
6085
|
`
|
|
@@ -5953,24 +6092,6 @@ async function adminCanCreateRoles(sql) {
|
|
|
5953
6092
|
);
|
|
5954
6093
|
return rows[0] ?? null;
|
|
5955
6094
|
}
|
|
5956
|
-
function ledgerBlockedBy(row) {
|
|
5957
|
-
if (!row || row.is_owner || row.is_superuser) return null;
|
|
5958
|
-
return row.owner;
|
|
5959
|
-
}
|
|
5960
|
-
async function unmanageableLedgerOwner(sql) {
|
|
5961
|
-
const rows = await sql.unsafe(
|
|
5962
|
-
`SELECT pg_get_userbyid(c.relowner) AS owner,
|
|
5963
|
-
c.relowner = r.oid AS is_owner,
|
|
5964
|
-
r.rolsuper AS is_superuser
|
|
5965
|
-
FROM pg_class c
|
|
5966
|
-
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
5967
|
-
JOIN pg_roles r ON r.rolname = current_user
|
|
5968
|
-
WHERE c.relkind = 'r'
|
|
5969
|
-
AND c.relname = 'ablo_idempotency'
|
|
5970
|
-
AND n.nspname = 'public'`
|
|
5971
|
-
);
|
|
5972
|
-
return ledgerBlockedBy(rows[0]);
|
|
5973
|
-
}
|
|
5974
6095
|
function detectProvider(hostOrTarget) {
|
|
5975
6096
|
const host = hostOrTarget.toLowerCase();
|
|
5976
6097
|
if (host.includes("neon.tech")) return "neon";
|
|
@@ -6029,8 +6150,8 @@ async function runConnectApply(args) {
|
|
|
6029
6150
|
const adminUrl = args.url ?? readProjectAdminDatabaseUrl();
|
|
6030
6151
|
if (!adminUrl) {
|
|
6031
6152
|
console.error(
|
|
6032
|
-
|
|
6033
|
-
` Pass ${
|
|
6153
|
+
import_picocolors9.default.red(" No admin connection string.") + import_picocolors9.default.dim(
|
|
6154
|
+
` Pass ${import_picocolors9.default.bold("--url <admin-conn>")} (or set ${import_picocolors9.default.bold("DATABASE_URL")}) and re-run.`
|
|
6034
6155
|
)
|
|
6035
6156
|
);
|
|
6036
6157
|
process.exit(1);
|
|
@@ -6045,19 +6166,19 @@ async function runConnectApply(args) {
|
|
|
6045
6166
|
const apiKey = resolveApiKey();
|
|
6046
6167
|
if (!apiKey) {
|
|
6047
6168
|
console.error(
|
|
6048
|
-
|
|
6049
|
-
` Run ${
|
|
6169
|
+
import_picocolors9.default.red(" Not logged in.") + import_picocolors9.default.dim(
|
|
6170
|
+
` Run ${import_picocolors9.default.bold("ablo login")} (or set ${import_picocolors9.default.bold("ABLO_API_KEY")}) so Ablo knows which project to register this database for.`
|
|
6050
6171
|
)
|
|
6051
6172
|
);
|
|
6052
6173
|
process.exit(1);
|
|
6053
6174
|
}
|
|
6054
6175
|
console.log(
|
|
6055
6176
|
`
|
|
6056
|
-
${brand("ablo")} ${
|
|
6177
|
+
${brand("ablo")} ${import_picocolors9.default.dim(verb)} ${import_picocolors9.default.dim(rotating ? "re-key the scoped roles" : "set up your database for Ablo")}
|
|
6057
6178
|
`
|
|
6058
6179
|
);
|
|
6059
6180
|
console.log(
|
|
6060
|
-
` ${
|
|
6181
|
+
` ${import_picocolors9.default.dim("\u2192")} ${import_picocolors9.default.bold(target)}${adminSource === "DATABASE_URL" ? import_picocolors9.default.dim(" (admin via DATABASE_URL)") : ""}
|
|
6061
6182
|
`
|
|
6062
6183
|
);
|
|
6063
6184
|
const admin = src_default(adminUrl, {
|
|
@@ -6073,31 +6194,25 @@ async function runConnectApply(args) {
|
|
|
6073
6194
|
} catch (err) {
|
|
6074
6195
|
await admin.end({ timeout: 2 }).catch(() => void 0);
|
|
6075
6196
|
const pg = err ?? {};
|
|
6076
|
-
console.error(
|
|
6197
|
+
console.error(import_picocolors9.default.red(` Couldn't connect: ${pg.message ?? String(err)}`));
|
|
6077
6198
|
process.exit(1);
|
|
6078
6199
|
}
|
|
6079
6200
|
if (!capability || !(capability.rolsuper || capability.rolcreaterole)) {
|
|
6080
6201
|
await admin.end({ timeout: 2 });
|
|
6081
6202
|
console.error(
|
|
6082
|
-
|
|
6203
|
+
import_picocolors9.default.red(` ${capability?.rolname ?? "This role"} can't create roles.`) + import_picocolors9.default.dim(` Point ${import_picocolors9.default.bold("--url")} at your owner/admin connection and re-run.`)
|
|
6083
6204
|
);
|
|
6084
6205
|
process.exit(1);
|
|
6085
6206
|
}
|
|
6086
|
-
const
|
|
6087
|
-
|
|
6207
|
+
const ledger = await ledgerBlocker(admin).catch(() => null);
|
|
6208
|
+
const foreignTables = await publishedTableBlockers(admin, args.tables).catch(() => []);
|
|
6209
|
+
const { inheritGrants, unresolved } = ownershipRemediation(
|
|
6210
|
+
[...ledger ? [ledger] : [], ...foreignTables],
|
|
6211
|
+
capability.rolname
|
|
6212
|
+
);
|
|
6213
|
+
if (unresolved.length > 0) {
|
|
6088
6214
|
await admin.end({ timeout: 2 });
|
|
6089
|
-
console.error(
|
|
6090
|
-
import_picocolors8.default.red(
|
|
6091
|
-
`
|
|
6092
|
-
${import_picocolors8.default.bold("ablo_idempotency")} already exists on ${target}, owned by ${import_picocolors8.default.bold(blockingOwner)}, but you connected as ${import_picocolors8.default.bold(capability.rolname)}.`
|
|
6093
|
-
) + `
|
|
6094
|
-
Ablo's setup grants the writer role access to this ledger, and Postgres reserves that
|
|
6095
|
-
for the table's owner. Either re-run pointing ${import_picocolors8.default.bold("--url")} at ${import_picocolors8.default.bold(blockingOwner)}'s connection,
|
|
6096
|
-
or drop the existing ledger so Ablo recreates it under this admin \u2014 it holds only
|
|
6097
|
-
idempotency replay records, safe to drop when no commit is in flight:
|
|
6098
|
-
${import_picocolors8.default.cyan("DROP TABLE ablo_idempotency;")}
|
|
6099
|
-
`
|
|
6100
|
-
);
|
|
6215
|
+
console.error(formatUnresolvedOwnership(unresolved, capability.rolname, target));
|
|
6101
6216
|
process.exit(1);
|
|
6102
6217
|
}
|
|
6103
6218
|
const provider = detectProvider(target);
|
|
@@ -6118,18 +6233,19 @@ async function runConnectApply(args) {
|
|
|
6118
6233
|
},
|
|
6119
6234
|
walAlreadyLogical: walReady,
|
|
6120
6235
|
provider,
|
|
6121
|
-
existingPublication
|
|
6236
|
+
existingPublication,
|
|
6237
|
+
inheritGrants
|
|
6122
6238
|
});
|
|
6123
6239
|
const steps = buildPlan("scram-verifier");
|
|
6124
6240
|
if (pubReconcile.removed.length > 0 || pubReconcile.recreated) {
|
|
6125
6241
|
console.log(
|
|
6126
|
-
` ${
|
|
6242
|
+
` ${import_picocolors9.default.yellow("!")} ${import_picocolors9.default.bold(ABLO_PUBLICATION)} already publishes a different set; reconciling to your ${import_picocolors9.default.bold("--tables")}:`
|
|
6127
6243
|
);
|
|
6128
|
-
for (const t of pubReconcile.added) console.log(` ${
|
|
6244
|
+
for (const t of pubReconcile.added) console.log(` ${import_picocolors9.default.green("+")} ${t}`);
|
|
6129
6245
|
for (const t of pubReconcile.removed)
|
|
6130
|
-
console.log(` ${
|
|
6246
|
+
console.log(` ${import_picocolors9.default.red("-")} ${t} ${import_picocolors9.default.dim("(stops replicating to Ablo)")}`);
|
|
6131
6247
|
if (pubReconcile.recreated && existingPublication.allTables)
|
|
6132
|
-
console.log(` ${
|
|
6248
|
+
console.log(` ${import_picocolors9.default.red("-")} ${import_picocolors9.default.dim("every other table (was FOR ALL TABLES)")}`);
|
|
6133
6249
|
console.log();
|
|
6134
6250
|
}
|
|
6135
6251
|
printPlan2(steps, args.showSql);
|
|
@@ -6137,7 +6253,7 @@ async function runConnectApply(args) {
|
|
|
6137
6253
|
if (!process.stdout.isTTY) {
|
|
6138
6254
|
await admin.end({ timeout: 2 });
|
|
6139
6255
|
console.error(
|
|
6140
|
-
|
|
6256
|
+
import_picocolors9.default.dim(` Re-run with ${import_picocolors9.default.bold("--yes")} to apply this in a non-interactive session.
|
|
6141
6257
|
`)
|
|
6142
6258
|
);
|
|
6143
6259
|
process.exit(1);
|
|
@@ -6149,7 +6265,7 @@ async function runConnectApply(args) {
|
|
|
6149
6265
|
if (pD(proceed) || !proceed) {
|
|
6150
6266
|
await admin.end({ timeout: 2 });
|
|
6151
6267
|
console.log(
|
|
6152
|
-
|
|
6268
|
+
import_picocolors9.default.dim(` Nothing applied. Run ${import_picocolors9.default.bold("ablo connect")} to see the manual recipe.
|
|
6153
6269
|
`)
|
|
6154
6270
|
);
|
|
6155
6271
|
process.exit(0);
|
|
@@ -6161,8 +6277,8 @@ async function runConnectApply(args) {
|
|
|
6161
6277
|
await admin.end({ timeout: 2 }).catch(() => void 0);
|
|
6162
6278
|
const pg = err ?? {};
|
|
6163
6279
|
console.error(
|
|
6164
|
-
|
|
6165
|
-
Setup stopped: ${pg.message ?? String(err)}`) +
|
|
6280
|
+
import_picocolors9.default.red(`
|
|
6281
|
+
Setup stopped: ${pg.message ?? String(err)}`) + import_picocolors9.default.dim(` Every step is safe to re-run.
|
|
6166
6282
|
`)
|
|
6167
6283
|
);
|
|
6168
6284
|
process.exit(1);
|
|
@@ -6173,14 +6289,14 @@ async function runConnectApply(args) {
|
|
|
6173
6289
|
const replicationUrl = rewriteDatabaseUrl(adminUrl, role, replicationPassword);
|
|
6174
6290
|
const writeUrl = rewriteDatabaseUrl(adminUrl, writeRole, writePassword);
|
|
6175
6291
|
console.log(`
|
|
6176
|
-
${
|
|
6292
|
+
${import_picocolors9.default.green("\u2713")} Roles ${rotating ? "re-keyed" : "created"}.
|
|
6177
6293
|
`);
|
|
6178
6294
|
if (!walReady) {
|
|
6179
6295
|
console.error(
|
|
6180
|
-
` ${
|
|
6296
|
+
` ${import_picocolors9.default.yellow("!")} One step left \u2014 logical replication isn't on yet.
|
|
6181
6297
|
${logicalReplicationGuidance(provider)}.
|
|
6182
6298
|
|
|
6183
|
-
Then re-run: ${
|
|
6299
|
+
Then re-run: ${import_picocolors9.default.cyan(`npx ablo ${verb}`)}
|
|
6184
6300
|
`
|
|
6185
6301
|
);
|
|
6186
6302
|
process.exit(1);
|
|
@@ -6197,15 +6313,15 @@ async function runConnectApply(args) {
|
|
|
6197
6313
|
items = await probeReadiness(verifier);
|
|
6198
6314
|
} catch {
|
|
6199
6315
|
items = null;
|
|
6200
|
-
console.log(
|
|
6316
|
+
console.log(import_picocolors9.default.dim(` Couldn't verify from here; Ablo will validate from its own network.
|
|
6201
6317
|
`));
|
|
6202
6318
|
}
|
|
6203
6319
|
await verifier.end({ timeout: 2 }).catch(() => void 0);
|
|
6204
6320
|
const failed = items?.filter((i) => !i.ok) ?? [];
|
|
6205
6321
|
if (failed.length > 0) {
|
|
6206
|
-
for (const item of failed) console.log(` ${
|
|
6322
|
+
for (const item of failed) console.log(` ${import_picocolors9.default.yellow("!")} ${item.label}`);
|
|
6207
6323
|
console.log(`
|
|
6208
|
-
${
|
|
6324
|
+
${import_picocolors9.default.dim("Resolve, then re-run")} ${import_picocolors9.default.cyan(`npx ablo ${verb}`)}
|
|
6209
6325
|
`);
|
|
6210
6326
|
process.exit(1);
|
|
6211
6327
|
}
|
|
@@ -6220,20 +6336,21 @@ async function runConnectApply(args) {
|
|
|
6220
6336
|
const outcome = postRegistrationOutcome({ rotating, registered });
|
|
6221
6337
|
if (outcome.notice) {
|
|
6222
6338
|
console.error(`
|
|
6223
|
-
${
|
|
6339
|
+
${import_picocolors9.default.red(outcome.notice.split("\n").join("\n "))}
|
|
6224
6340
|
`);
|
|
6225
6341
|
}
|
|
6226
6342
|
process.exit(outcome.exitCode);
|
|
6227
6343
|
}
|
|
6228
|
-
var
|
|
6344
|
+
var import_picocolors9;
|
|
6229
6345
|
var init_connectApply = __esm({
|
|
6230
6346
|
"src/cli/connectApply.ts"() {
|
|
6231
6347
|
"use strict";
|
|
6232
6348
|
init_cjs_shims();
|
|
6233
|
-
|
|
6349
|
+
import_picocolors9 = __toESM(require_picocolors(), 1);
|
|
6234
6350
|
init_src();
|
|
6235
6351
|
init_dist2();
|
|
6236
6352
|
init_connectSetup();
|
|
6353
|
+
init_connectOwnership();
|
|
6237
6354
|
init_dbRole();
|
|
6238
6355
|
init_config();
|
|
6239
6356
|
init_push();
|
|
@@ -218258,11 +218375,11 @@ var require_commonjs2 = __commonJS({
|
|
|
218258
218375
|
if (pad) {
|
|
218259
218376
|
const need = width - c.length;
|
|
218260
218377
|
if (need > 0) {
|
|
218261
|
-
const
|
|
218378
|
+
const z9 = new Array(need + 1).join("0");
|
|
218262
218379
|
if (i < 0) {
|
|
218263
|
-
c = "-" +
|
|
218380
|
+
c = "-" + z9 + c.slice(1);
|
|
218264
218381
|
} else {
|
|
218265
|
-
c =
|
|
218382
|
+
c = z9 + c;
|
|
218266
218383
|
}
|
|
218267
218384
|
}
|
|
218268
218385
|
}
|
|
@@ -282191,7 +282308,7 @@ Node text: ${this.#forgottenText}`;
|
|
|
282191
282308
|
// src/cli/index.ts
|
|
282192
282309
|
init_cjs_shims();
|
|
282193
282310
|
init_dist2();
|
|
282194
|
-
var
|
|
282311
|
+
var import_picocolors24 = __toESM(require_picocolors(), 1);
|
|
282195
282312
|
var import_fs12 = require("fs");
|
|
282196
282313
|
var import_path7 = require("path");
|
|
282197
282314
|
var import_child_process3 = require("child_process");
|
|
@@ -282382,7 +282499,7 @@ async function migrate(argv) {
|
|
|
282382
282499
|
// src/cli/connect.ts
|
|
282383
282500
|
init_cjs_shims();
|
|
282384
282501
|
init_errors();
|
|
282385
|
-
var
|
|
282502
|
+
var import_picocolors10 = __toESM(require_picocolors(), 1);
|
|
282386
282503
|
init_src();
|
|
282387
282504
|
init_dbRole();
|
|
282388
282505
|
init_config();
|
|
@@ -282614,7 +282731,7 @@ function printConnectRecipe(args) {
|
|
|
282614
282731
|
});
|
|
282615
282732
|
console.log(
|
|
282616
282733
|
`
|
|
282617
|
-
${brand("ablo")} ${
|
|
282734
|
+
${brand("ablo")} ${import_picocolors10.default.dim("connect")} ${import_picocolors10.default.dim("direct writes + WAL-settled sync")}
|
|
282618
282735
|
`
|
|
282619
282736
|
);
|
|
282620
282737
|
console.log(
|
|
@@ -282622,29 +282739,29 @@ function printConnectRecipe(args) {
|
|
|
282622
282739
|
observes what committed, orders it with external writes, and confirms it in the sync log.
|
|
282623
282740
|
Your database stays authoritative; Ablo never owns or migrates your application tables.
|
|
282624
282741
|
|
|
282625
|
-
${
|
|
282626
|
-
connection and leaves your app holding only ${
|
|
282627
|
-
run this once against your Postgres ${
|
|
282742
|
+
${import_picocolors10.default.bold("ablo connect apply")} runs every step below for you from a one-time admin
|
|
282743
|
+
connection and leaves your app holding only ${import_picocolors10.default.bold("ABLO_API_KEY")}. To do it by hand,
|
|
282744
|
+
run this once against your Postgres ${import_picocolors10.default.dim("(as a superuser / DB owner)")}:
|
|
282628
282745
|
`
|
|
282629
282746
|
);
|
|
282630
282747
|
console.log(
|
|
282631
|
-
` ${
|
|
282748
|
+
` ${import_picocolors10.default.bold("1.")} Enable logical decoding ${import_picocolors10.default.dim("(then RESTART Postgres \u2014 wal_level is not reloadable)")}`
|
|
282632
282749
|
);
|
|
282633
|
-
console.log(` ${
|
|
282750
|
+
console.log(` ${import_picocolors10.default.cyan(sql[0])}`);
|
|
282634
282751
|
console.log(
|
|
282635
|
-
|
|
282636
|
-
` Managed hosts don't take ALTER SYSTEM: on Amazon RDS / Aurora set ${
|
|
282752
|
+
import_picocolors10.default.dim(
|
|
282753
|
+
` Managed hosts don't take ALTER SYSTEM: on Amazon RDS / Aurora set ${import_picocolors10.default.bold("rds.logical_replication = 1")}
|
|
282637
282754
|
in the parameter group and reboot; on Neon or Supabase enable logical replication in the
|
|
282638
|
-
project settings. ${
|
|
282755
|
+
project settings. ${import_picocolors10.default.bold("ablo connect apply")} detects the host and does the right thing.`
|
|
282639
282756
|
)
|
|
282640
282757
|
);
|
|
282641
282758
|
console.log(`
|
|
282642
|
-
${
|
|
282643
|
-
console.log(` ${
|
|
282759
|
+
${import_picocolors10.default.bold("2.")} Publish the tables Ablo should read`);
|
|
282760
|
+
console.log(` ${import_picocolors10.default.cyan(sql[1])}`);
|
|
282644
282761
|
if (args.tables.length === 0) {
|
|
282645
282762
|
console.log(
|
|
282646
|
-
|
|
282647
|
-
` (Scope it with ${
|
|
282763
|
+
import_picocolors10.default.dim(
|
|
282764
|
+
` (Scope it with ${import_picocolors10.default.bold("ablo connect --tables a,b,c")} to publish a subset.)`
|
|
282648
282765
|
)
|
|
282649
282766
|
);
|
|
282650
282767
|
}
|
|
@@ -282653,52 +282770,52 @@ function printConnectRecipe(args) {
|
|
|
282653
282770
|
const writerStatements = sql.slice(writerStart);
|
|
282654
282771
|
console.log(
|
|
282655
282772
|
`
|
|
282656
|
-
${
|
|
282773
|
+
${import_picocolors10.default.bold("3.")} Create the scoped replication role ${import_picocolors10.default.dim("(pick your own replication password)")}`
|
|
282657
282774
|
);
|
|
282658
282775
|
for (const statement of replicationStatements) {
|
|
282659
|
-
for (const line of statement.split("\n")) console.log(` ${
|
|
282776
|
+
for (const line of statement.split("\n")) console.log(` ${import_picocolors10.default.cyan(line)}`);
|
|
282660
282777
|
}
|
|
282661
282778
|
console.log(
|
|
282662
|
-
|
|
282779
|
+
import_picocolors10.default.dim(
|
|
282663
282780
|
` On Amazon RDS, the REPLICATION attribute is granted, not set directly:
|
|
282664
|
-
${
|
|
282781
|
+
${import_picocolors10.default.bold(`GRANT rds_replication TO ${quoteIdent(args.role)};`)}`
|
|
282665
282782
|
)
|
|
282666
282783
|
);
|
|
282667
282784
|
console.log(
|
|
282668
282785
|
`
|
|
282669
|
-
${
|
|
282786
|
+
${import_picocolors10.default.bold("4.")} Create the separate DML role and the idempotency ledger ` + import_picocolors10.default.dim("(pick your own write password)")
|
|
282670
282787
|
);
|
|
282671
282788
|
for (const statement of writerStatements) {
|
|
282672
|
-
for (const line of statement.split("\n")) console.log(` ${
|
|
282789
|
+
for (const line of statement.split("\n")) console.log(` ${import_picocolors10.default.cyan(line)}`);
|
|
282673
282790
|
}
|
|
282674
282791
|
console.log(
|
|
282675
|
-
|
|
282792
|
+
import_picocolors10.default.dim(
|
|
282676
282793
|
` The writer gets row DML + ledger access only. It has no REPLICATION, schema CREATE,
|
|
282677
282794
|
role administration, database creation, ownership, or customer-table DDL. Direct uses
|
|
282678
|
-
${
|
|
282679
|
-
Each ledger row carries an ${
|
|
282795
|
+
${import_picocolors10.default.bold("ablo_idempotency")} but no outbox; WAL carries the committed row changes.
|
|
282796
|
+
Each ledger row carries an ${import_picocolors10.default.bold("expires_at")}; the writer can't DELETE (tamper-
|
|
282680
282797
|
resistance), so prune it from your own admin/cron when convenient:
|
|
282681
|
-
${
|
|
282798
|
+
${import_picocolors10.default.bold("DELETE FROM ablo_idempotency WHERE expires_at < now();")}`
|
|
282682
282799
|
)
|
|
282683
282800
|
);
|
|
282684
282801
|
console.log(
|
|
282685
282802
|
`
|
|
282686
|
-
${
|
|
282687
|
-
Ablo holds them from here, so your app keeps only ${
|
|
282688
|
-
${
|
|
282689
|
-
${
|
|
282690
|
-
${
|
|
282803
|
+
${import_picocolors10.default.bold("5.")} Register the two roles with Ablo. Set them just long enough to register \u2014
|
|
282804
|
+
Ablo holds them from here, so your app keeps only ${import_picocolors10.default.bold("ABLO_API_KEY")}:
|
|
282805
|
+
${import_picocolors10.default.bold("ABLO_REPLICATION_DATABASE_URL")} ${import_picocolors10.default.dim(`\u2192 ${args.role} (replication only)`)}
|
|
282806
|
+
${import_picocolors10.default.bold("ABLO_WRITE_DATABASE_URL")} ${import_picocolors10.default.dim(`\u2192 ${args.writeRole} (DML only)`)}
|
|
282807
|
+
${import_picocolors10.default.cyan("npx ablo connect register")}
|
|
282691
282808
|
`
|
|
282692
282809
|
);
|
|
282693
282810
|
console.log(
|
|
282694
|
-
` ${
|
|
282695
|
-
${
|
|
282811
|
+
` ${import_picocolors10.default.bold("6.")} Verify readiness ${import_picocolors10.default.dim("(checked from Ablo\u2019s side \u2014 needs only ABLO_API_KEY):")}
|
|
282812
|
+
${import_picocolors10.default.cyan("npx ablo connect check")}
|
|
282696
282813
|
`
|
|
282697
282814
|
);
|
|
282698
282815
|
console.log(
|
|
282699
|
-
|
|
282816
|
+
import_picocolors10.default.dim(
|
|
282700
282817
|
` Reachable databases use this direct path. If no inbound route can be established, use the
|
|
282701
|
-
signed ${
|
|
282818
|
+
signed ${import_picocolors10.default.bold("dataSource()")} endpoint fallback; its correlated events confirm writes
|
|
282702
282819
|
without an Ablo-side customer database socket.`
|
|
282703
282820
|
)
|
|
282704
282821
|
);
|
|
@@ -282713,11 +282830,11 @@ var SYNC_INFRA_RELATIONS = [
|
|
|
282713
282830
|
var SYNC_INFRA_TYPES = ["participant_kind", "backfill_provenance", "confirmation_state"];
|
|
282714
282831
|
function printCheckItem(item) {
|
|
282715
282832
|
if (item.ok) {
|
|
282716
|
-
console.log(` ${
|
|
282833
|
+
console.log(` ${import_picocolors10.default.green("\u2713")} ${item.label}`);
|
|
282717
282834
|
} else {
|
|
282718
|
-
console.log(` ${
|
|
282835
|
+
console.log(` ${import_picocolors10.default.red("\u2717")} ${item.label}`);
|
|
282719
282836
|
if (item.fix) {
|
|
282720
|
-
for (const line of item.fix.split("\n")) console.log(` ${
|
|
282837
|
+
for (const line of item.fix.split("\n")) console.log(` ${import_picocolors10.default.red("\u2022")} ${line}`);
|
|
282721
282838
|
}
|
|
282722
282839
|
}
|
|
282723
282840
|
}
|
|
@@ -282738,7 +282855,7 @@ async function probeDirectWriteReadiness(sql, opts = {}) {
|
|
|
282738
282855
|
ok: false,
|
|
282739
282856
|
label: `ABLO_WRITE_DATABASE_URL is not a scoped DML role`,
|
|
282740
282857
|
fix: `Use ${ABLO_WRITE_ROLE} from the setup recipe: NOSUPERUSER, NOBYPASSRLS, NOCREATEDB, NOCREATEROLE, NOREPLICATION.`
|
|
282741
|
-
} : { ok: true, label: `write role ${
|
|
282858
|
+
} : { ok: true, label: `write role ${import_picocolors10.default.bold(role?.rolname ?? ABLO_WRITE_ROLE)} is DML-only` }
|
|
282742
282859
|
);
|
|
282743
282860
|
const schemaRows = await sql.unsafe(
|
|
282744
282861
|
`SELECT
|
|
@@ -282765,10 +282882,10 @@ async function probeDirectWriteReadiness(sql, opts = {}) {
|
|
|
282765
282882
|
);
|
|
282766
282883
|
const ledger = ledgerRows[0];
|
|
282767
282884
|
items.push(
|
|
282768
|
-
ledger?.present && ledger.writes && !ledger.deletes ? { ok: true, label: `${
|
|
282885
|
+
ledger?.present && ledger.writes && !ledger.deletes ? { ok: true, label: `${import_picocolors10.default.bold("ablo_idempotency")} is durable and protected from DELETE` } : {
|
|
282769
282886
|
ok: false,
|
|
282770
|
-
label: `${
|
|
282771
|
-
fix: `Apply the DML-role and idempotency-ledger statements printed by ${
|
|
282887
|
+
label: `${import_picocolors10.default.bold("ablo_idempotency")} is missing or has unsafe grants`,
|
|
282888
|
+
fix: `Apply the DML-role and idempotency-ledger statements printed by ${import_picocolors10.default.bold("ablo connect")}.`
|
|
282772
282889
|
}
|
|
282773
282890
|
);
|
|
282774
282891
|
const tableRows = await sql.unsafe(
|
|
@@ -282857,8 +282974,8 @@ function requireScopedUrl(kind, verb) {
|
|
|
282857
282974
|
const resolved = readProjectReplicationUrlWithSource();
|
|
282858
282975
|
if (resolved) return resolved.url;
|
|
282859
282976
|
console.error(
|
|
282860
|
-
|
|
282861
|
-
` Set ${
|
|
282977
|
+
import_picocolors10.default.red(" No replication connection found (checked process env, .env.local, .env).") + import_picocolors10.default.dim(
|
|
282978
|
+
` Set ${import_picocolors10.default.bold("ABLO_REPLICATION_DATABASE_URL")} to the ${ABLO_REPLICATION_ROLE} connection printed by ${import_picocolors10.default.bold("ablo connect")}, then re-run ${import_picocolors10.default.bold(`ablo connect ${verb}`)}.`
|
|
282862
282979
|
)
|
|
282863
282980
|
);
|
|
282864
282981
|
process.exit(1);
|
|
@@ -282866,8 +282983,8 @@ function requireScopedUrl(kind, verb) {
|
|
|
282866
282983
|
const dbUrl = readProjectWriteDatabaseUrl();
|
|
282867
282984
|
if (dbUrl) return dbUrl;
|
|
282868
282985
|
console.error(
|
|
282869
|
-
|
|
282870
|
-
` Set it to the ${ABLO_WRITE_ROLE} connection printed by ${
|
|
282986
|
+
import_picocolors10.default.red(" No ABLO_WRITE_DATABASE_URL found (checked process env, .env.local, .env).") + import_picocolors10.default.dim(
|
|
282987
|
+
` Set it to the ${ABLO_WRITE_ROLE} connection printed by ${import_picocolors10.default.bold("ablo connect")}, then re-run ${import_picocolors10.default.bold(`ablo connect ${verb}`)}. The replication credential is never reused for DML.`
|
|
282871
282988
|
)
|
|
282872
282989
|
);
|
|
282873
282990
|
process.exit(1);
|
|
@@ -282883,7 +283000,7 @@ async function probeAndReport(dbUrl, kind = "replication") {
|
|
|
282883
283000
|
const dial = dialFailureReason(err);
|
|
282884
283001
|
if (dial) return { kind: "no-dial", reason: dial };
|
|
282885
283002
|
const pg = err ?? {};
|
|
282886
|
-
console.error(
|
|
283003
|
+
console.error(import_picocolors10.default.red(` Couldn't read the database: ${pg.message ?? String(err)}`));
|
|
282887
283004
|
process.exit(1);
|
|
282888
283005
|
}
|
|
282889
283006
|
await sql.end({ timeout: 2 });
|
|
@@ -282893,14 +283010,14 @@ async function probeAndReport(dbUrl, kind = "replication") {
|
|
|
282893
283010
|
async function runCheck() {
|
|
282894
283011
|
console.log(
|
|
282895
283012
|
`
|
|
282896
|
-
${brand("ablo")} ${
|
|
283013
|
+
${brand("ablo")} ${import_picocolors10.default.dim("connect check")} ${import_picocolors10.default.dim("direct-write + WAL readiness")}
|
|
282897
283014
|
`
|
|
282898
283015
|
);
|
|
282899
283016
|
const apiKey = resolveApiKey();
|
|
282900
283017
|
if (!apiKey) {
|
|
282901
283018
|
console.error(
|
|
282902
|
-
|
|
282903
|
-
` Run ${
|
|
283019
|
+
import_picocolors10.default.red(" No API key found.") + import_picocolors10.default.dim(
|
|
283020
|
+
` Run ${import_picocolors10.default.bold("ablo login")} (or set ${import_picocolors10.default.bold("ABLO_API_KEY")}), then re-run ${import_picocolors10.default.bold("ablo connect check")}.`
|
|
282904
283021
|
)
|
|
282905
283022
|
);
|
|
282906
283023
|
process.exit(1);
|
|
@@ -282910,19 +283027,19 @@ async function runCheck() {
|
|
|
282910
283027
|
if (!result.ok) {
|
|
282911
283028
|
if (result.code === "no_data_source_registered") {
|
|
282912
283029
|
console.error(
|
|
282913
|
-
` ${
|
|
282914
|
-
` +
|
|
282915
|
-
` Connect one with ${
|
|
283030
|
+
` ${import_picocolors10.default.yellow("\u2014")} No database is connected to this plane yet, so there's nothing to check.
|
|
283031
|
+
` + import_picocolors10.default.dim(
|
|
283032
|
+
` Connect one with ${import_picocolors10.default.bold("ablo connect apply")}, then re-run ${import_picocolors10.default.bold("ablo connect check")}.
|
|
282916
283033
|
`
|
|
282917
283034
|
)
|
|
282918
283035
|
);
|
|
282919
283036
|
process.exit(1);
|
|
282920
283037
|
}
|
|
282921
|
-
console.error(
|
|
283038
|
+
console.error(import_picocolors10.default.red(` The check failed: ${result.message}`));
|
|
282922
283039
|
if (result.code === "forbidden") {
|
|
282923
283040
|
console.error(
|
|
282924
|
-
|
|
282925
|
-
` Checking a connected database needs a ${
|
|
283041
|
+
import_picocolors10.default.dim(
|
|
283042
|
+
` Checking a connected database needs a ${import_picocolors10.default.bold("secret")} key (sk_\u2026). Run ${import_picocolors10.default.bold("ablo login")} for one.`
|
|
282926
283043
|
)
|
|
282927
283044
|
);
|
|
282928
283045
|
}
|
|
@@ -282931,12 +283048,12 @@ async function runCheck() {
|
|
|
282931
283048
|
}
|
|
282932
283049
|
if (!result.reachable) {
|
|
282933
283050
|
console.error(
|
|
282934
|
-
` ${
|
|
283051
|
+
` ${import_picocolors10.default.red("\u2717")} Ablo's infrastructure can't reach your database${result.reason ? ` ${import_picocolors10.default.dim(`(${result.reason})`)}` : ""}.`
|
|
282935
283052
|
);
|
|
282936
283053
|
console.error(
|
|
282937
|
-
|
|
283054
|
+
import_picocolors10.default.dim(
|
|
282938
283055
|
` Direct needs a route Ablo's servers can dial \u2014 public allowlist, PrivateLink, peering,
|
|
282939
|
-
or VPN. Only when no inbound route can exist, use the signed ${
|
|
283056
|
+
or VPN. Only when no inbound route can exist, use the signed ${import_picocolors10.default.bold("dataSource()")} endpoint fallback.
|
|
282940
283057
|
`
|
|
282941
283058
|
)
|
|
282942
283059
|
);
|
|
@@ -282949,14 +283066,14 @@ async function runCheck() {
|
|
|
282949
283066
|
console.log();
|
|
282950
283067
|
if (result.ready) {
|
|
282951
283068
|
console.log(
|
|
282952
|
-
` ${
|
|
283069
|
+
` ${import_picocolors10.default.green("\u2713")} Ready \u2014 checked from Ablo's infrastructure. Ablo can apply scoped DML and settle it from WAL.
|
|
282953
283070
|
`
|
|
282954
283071
|
);
|
|
282955
283072
|
process.exit(0);
|
|
282956
283073
|
}
|
|
282957
283074
|
const count = result.failures.length;
|
|
282958
283075
|
console.log(
|
|
282959
|
-
` ${
|
|
283076
|
+
` ${import_picocolors10.default.red(`${count} item${count === 1 ? "" : "s"} to fix`)} ${import_picocolors10.default.dim(`\u2014 apply the fixes above, then re-run ${import_picocolors10.default.bold("ablo connect check")}.`)}
|
|
282960
283077
|
`
|
|
282961
283078
|
);
|
|
282962
283079
|
process.exit(1);
|
|
@@ -282967,22 +283084,22 @@ async function runRegister(args) {
|
|
|
282967
283084
|
const apiKey = resolveApiKey();
|
|
282968
283085
|
if (!apiKey) {
|
|
282969
283086
|
console.error(
|
|
282970
|
-
|
|
282971
|
-
` Run ${
|
|
283087
|
+
import_picocolors10.default.red(" Not logged in.") + import_picocolors10.default.dim(
|
|
283088
|
+
` Run ${import_picocolors10.default.bold("ablo login")} (or set ${import_picocolors10.default.bold("ABLO_API_KEY")}) so Ablo knows which project to register this database for.`
|
|
282972
283089
|
)
|
|
282973
283090
|
);
|
|
282974
283091
|
process.exit(1);
|
|
282975
283092
|
}
|
|
282976
283093
|
console.log(
|
|
282977
283094
|
`
|
|
282978
|
-
${brand("ablo")} ${
|
|
283095
|
+
${brand("ablo")} ${import_picocolors10.default.dim("connect register")} ${import_picocolors10.default.dim("register a direct DataSource")}
|
|
282979
283096
|
`
|
|
282980
283097
|
);
|
|
282981
|
-
console.log(` ${
|
|
283098
|
+
console.log(` ${import_picocolors10.default.bold("Replication role")}
|
|
282982
283099
|
`);
|
|
282983
283100
|
const replication = await probeAndReport(dbUrl, "replication");
|
|
282984
283101
|
console.log(`
|
|
282985
|
-
${
|
|
283102
|
+
${import_picocolors10.default.bold("Direct-write role")}
|
|
282986
283103
|
`);
|
|
282987
283104
|
const write = await probeAndReport(writeDbUrl, "write");
|
|
282988
283105
|
const noDial = [
|
|
@@ -282992,7 +283109,7 @@ async function runRegister(args) {
|
|
|
282992
283109
|
const failures = (replication.kind === "probed" ? replication.failures : 0) + (write.kind === "probed" ? write.failures : 0);
|
|
282993
283110
|
if (noDial.length > 0) {
|
|
282994
283111
|
console.log(
|
|
282995
|
-
` This machine can't reach one or both scoped connections (${
|
|
283112
|
+
` This machine can't reach one or both scoped connections (${import_picocolors10.default.dim(noDial.join("; "))}) \u2014 continuing anyway.
|
|
282996
283113
|
Ablo validates both credentials from the infrastructure that will use them and refuses
|
|
282997
283114
|
registration unless replication and direct DML are both ready.
|
|
282998
283115
|
`
|
|
@@ -283001,7 +283118,7 @@ async function runRegister(args) {
|
|
|
283001
283118
|
if (failures > 0) {
|
|
283002
283119
|
console.log(
|
|
283003
283120
|
`
|
|
283004
|
-
${
|
|
283121
|
+
${import_picocolors10.default.red(`${failures} item${failures === 1 ? "" : "s"} to fix`)} ${import_picocolors10.default.dim("\u2014 direct registration requires both scoped roles. Fix the above, then re-run.")}
|
|
283005
283122
|
`
|
|
283006
283123
|
);
|
|
283007
283124
|
process.exit(1);
|
|
@@ -283025,31 +283142,31 @@ async function runScan() {
|
|
|
283025
283142
|
artifacts = await auditTenantSyncInfra(sql);
|
|
283026
283143
|
} catch (err) {
|
|
283027
283144
|
const pg = err ?? {};
|
|
283028
|
-
console.error(
|
|
283145
|
+
console.error(import_picocolors10.default.red(` Couldn't audit the database: ${pg.message ?? String(err)}`));
|
|
283029
283146
|
await sql.end({ timeout: 2 });
|
|
283030
283147
|
process.exit(1);
|
|
283031
283148
|
}
|
|
283032
283149
|
await sql.end({ timeout: 2 });
|
|
283033
283150
|
console.log(
|
|
283034
283151
|
`
|
|
283035
|
-
${brand("ablo")} ${
|
|
283152
|
+
${brand("ablo")} ${import_picocolors10.default.dim("connect scan")} ${import_picocolors10.default.dim("audit for leftover Ablo sync infrastructure")}
|
|
283036
283153
|
`
|
|
283037
283154
|
);
|
|
283038
283155
|
const present = artifacts.filter((a) => a.present);
|
|
283039
283156
|
if (present.length === 0) {
|
|
283040
|
-
console.log(` ${
|
|
283157
|
+
console.log(` ${import_picocolors10.default.green("\u2713")} No deprecated Ablo sync infrastructure found in public.
|
|
283041
283158
|
`);
|
|
283042
283159
|
process.exit(0);
|
|
283043
283160
|
}
|
|
283044
283161
|
for (const artifact of present) {
|
|
283045
283162
|
const label = artifact.kind === "type" ? "type" : "relation";
|
|
283046
|
-
console.log(` ${
|
|
283163
|
+
console.log(` ${import_picocolors10.default.yellow("!")} ${label} ${import_picocolors10.default.bold(`public.${artifact.name}`)} exists`);
|
|
283047
283164
|
}
|
|
283048
283165
|
console.log(
|
|
283049
283166
|
`
|
|
283050
|
-
${
|
|
283167
|
+
${import_picocolors10.default.yellow(`${present.length} artifact${present.length === 1 ? "" : "s"} found`)} ` + import_picocolors10.default.dim(
|
|
283051
283168
|
"\u2014 do not drop automatically. Confirm the org/environment is log-authoritative, then follow "
|
|
283052
|
-
) +
|
|
283169
|
+
) + import_picocolors10.default.bold("docs/runbooks/wal-stage5-customer-db-infra-cleanup.md") + import_picocolors10.default.dim(".\n")
|
|
283053
283170
|
);
|
|
283054
283171
|
process.exit(1);
|
|
283055
283172
|
}
|
|
@@ -283063,7 +283180,7 @@ async function connect(argv) {
|
|
|
283063
283180
|
try {
|
|
283064
283181
|
args = parseConnectArgs(argv);
|
|
283065
283182
|
} catch (err) {
|
|
283066
|
-
console.error(
|
|
283183
|
+
console.error(import_picocolors10.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
283067
283184
|
process.exit(1);
|
|
283068
283185
|
}
|
|
283069
283186
|
if (args.apply || args.rotate) {
|
|
@@ -283119,7 +283236,7 @@ init_cjs_shims();
|
|
|
283119
283236
|
init_errors();
|
|
283120
283237
|
var import_fs6 = require("fs");
|
|
283121
283238
|
var import_path4 = require("path");
|
|
283122
|
-
var
|
|
283239
|
+
var import_picocolors11 = __toESM(require_picocolors(), 1);
|
|
283123
283240
|
var import_schema4 = require("@abloatai/ablo/schema");
|
|
283124
283241
|
init_push();
|
|
283125
283242
|
var DEFAULT_SCHEMA_PATH3 = "ablo/schema.ts";
|
|
@@ -283152,7 +283269,7 @@ async function generate(argv) {
|
|
|
283152
283269
|
try {
|
|
283153
283270
|
args = parseGenerateArgs(argv);
|
|
283154
283271
|
} catch (err) {
|
|
283155
|
-
console.error(
|
|
283272
|
+
console.error(import_picocolors11.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
283156
283273
|
process.exit(1);
|
|
283157
283274
|
}
|
|
283158
283275
|
let source;
|
|
@@ -283161,20 +283278,20 @@ async function generate(argv) {
|
|
|
283161
283278
|
const schemaJson = JSON.parse((0, import_schema4.serializeSchema)(schema));
|
|
283162
283279
|
source = (0, import_schema4.generateTypes)(schemaJson);
|
|
283163
283280
|
} catch (err) {
|
|
283164
|
-
console.error(
|
|
283281
|
+
console.error(import_picocolors11.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
283165
283282
|
process.exit(1);
|
|
283166
283283
|
}
|
|
283167
283284
|
const abs = (0, import_path4.resolve)(process.cwd(), args.out);
|
|
283168
283285
|
(0, import_fs6.mkdirSync)((0, import_path4.dirname)(abs), { recursive: true });
|
|
283169
283286
|
(0, import_fs6.writeFileSync)(abs, source);
|
|
283170
|
-
console.log(` ${
|
|
283287
|
+
console.log(` ${import_picocolors11.default.green("\u2713")} Generated types \u2192 ${import_picocolors11.default.bold(args.out)}`);
|
|
283171
283288
|
}
|
|
283172
283289
|
|
|
283173
283290
|
// src/cli/dev.ts
|
|
283174
283291
|
init_cjs_shims();
|
|
283175
283292
|
init_errors();
|
|
283176
283293
|
init_credentialPolicy();
|
|
283177
|
-
var
|
|
283294
|
+
var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
283178
283295
|
init_dist2();
|
|
283179
283296
|
var import_fs7 = require("fs");
|
|
283180
283297
|
var import_path5 = require("path");
|
|
@@ -283216,25 +283333,25 @@ function classifyKey(apiKey, activeMode) {
|
|
|
283216
283333
|
if (!apiKey) {
|
|
283217
283334
|
return {
|
|
283218
283335
|
ok: false,
|
|
283219
|
-
reason: `No API key. Run ${
|
|
283336
|
+
reason: `No API key. Run ${import_picocolors12.default.bold("npx ablo login")} for the sandbox dev loop \u2014 or set ${import_picocolors12.default.bold("ABLO_API_KEY")} (${import_picocolors12.default.bold("sk_test_")} = sandbox; ${import_picocolors12.default.bold("sk_live_")} = deliberate production deploy). ` + import_picocolors12.default.dim(`Mode is currently '${activeMode}'.`)
|
|
283220
283337
|
};
|
|
283221
283338
|
}
|
|
283222
283339
|
if (apiKey.startsWith("sk_test_")) return { ok: true };
|
|
283223
283340
|
if (apiKey.startsWith("sk_live_")) {
|
|
283224
283341
|
return {
|
|
283225
283342
|
ok: false,
|
|
283226
|
-
reason: `Production schema deploys run one-shot: ${
|
|
283343
|
+
reason: `Production schema deploys run one-shot: ${import_picocolors12.default.bold("ABLO_API_KEY=sk_live_\u2026 npx ablo push")} (or ${import_picocolors12.default.bold("ablo mode production")}). ${import_picocolors12.default.bold("--watch")} is sandbox-only.`
|
|
283227
283344
|
};
|
|
283228
283345
|
}
|
|
283229
283346
|
if (classifyCredentialKind(apiKey) === "restricted") {
|
|
283230
283347
|
return {
|
|
283231
283348
|
ok: false,
|
|
283232
|
-
reason: `Restricted (${
|
|
283349
|
+
reason: `Restricted (${import_picocolors12.default.bold("rk_")}) keys can't push schema. Use a secret key: ${import_picocolors12.default.bold("sk_test_")} for the sandbox dev loop, or ${import_picocolors12.default.bold("sk_live_")} with ${import_picocolors12.default.bold("npx ablo push")} for a production deploy.`
|
|
283233
283350
|
};
|
|
283234
283351
|
}
|
|
283235
283352
|
return {
|
|
283236
283353
|
ok: false,
|
|
283237
|
-
reason: `${
|
|
283354
|
+
reason: `${import_picocolors12.default.bold("ABLO_API_KEY")} is not an Ablo key \u2014 expected ${import_picocolors12.default.bold("sk_test_\u2026")} (sandbox) or ${import_picocolors12.default.bold("sk_live_\u2026")} (production deploy via ${import_picocolors12.default.bold("npx ablo push")}).`
|
|
283238
283355
|
};
|
|
283239
283356
|
}
|
|
283240
283357
|
function wireEnvLocal(apiKey, cwd = process.cwd()) {
|
|
@@ -283244,7 +283361,7 @@ function wireEnvLocal(apiKey, cwd = process.cwd()) {
|
|
|
283244
283361
|
if (!(0, import_fs7.existsSync)(envPath)) {
|
|
283245
283362
|
(0, import_fs7.writeFileSync)(envPath, `${line}
|
|
283246
283363
|
`, { mode: 384 });
|
|
283247
|
-
action = `Created ${
|
|
283364
|
+
action = `Created ${import_picocolors12.default.bold(".env.local")} with ${import_picocolors12.default.bold("ABLO_API_KEY")}`;
|
|
283248
283365
|
} else {
|
|
283249
283366
|
const content = (0, import_fs7.readFileSync)(envPath, "utf8");
|
|
283250
283367
|
const match = /^ABLO_API_KEY=(.*)$/m.exec(content);
|
|
@@ -283252,12 +283369,12 @@ function wireEnvLocal(apiKey, cwd = process.cwd()) {
|
|
|
283252
283369
|
if (!match) {
|
|
283253
283370
|
(0, import_fs7.appendFileSync)(envPath, `${content.endsWith("\n") || content.length === 0 ? "" : "\n"}${line}
|
|
283254
283371
|
`);
|
|
283255
|
-
action = `Added ${
|
|
283372
|
+
action = `Added ${import_picocolors12.default.bold("ABLO_API_KEY")} to ${import_picocolors12.default.bold(".env.local")}`;
|
|
283256
283373
|
} else if (existing === apiKey) {
|
|
283257
|
-
action = `${
|
|
283374
|
+
action = `${import_picocolors12.default.bold(".env.local")} already has this key`;
|
|
283258
283375
|
} else {
|
|
283259
283376
|
(0, import_fs7.writeFileSync)(envPath, content.replace(/^ABLO_API_KEY=.*$/m, line));
|
|
283260
|
-
action = `Updated ${
|
|
283377
|
+
action = `Updated ${import_picocolors12.default.bold("ABLO_API_KEY")} in ${import_picocolors12.default.bold(".env.local")} ${import_picocolors12.default.dim(`(was ${existing.slice(0, 12)}\u2026)`)}`;
|
|
283261
283378
|
}
|
|
283262
283379
|
}
|
|
283263
283380
|
const gitignorePath = (0, import_path5.resolve)(cwd, ".gitignore");
|
|
@@ -283271,7 +283388,7 @@ function wireEnvLocal(apiKey, cwd = process.cwd()) {
|
|
|
283271
283388
|
`}.env.local
|
|
283272
283389
|
`
|
|
283273
283390
|
);
|
|
283274
|
-
gitignoreNote = ` Added ${
|
|
283391
|
+
gitignoreNote = ` Added ${import_picocolors12.default.bold(".env.local")} to ${import_picocolors12.default.bold(".gitignore")} so the key can't be committed.`;
|
|
283275
283392
|
}
|
|
283276
283393
|
return `${action}.${gitignoreNote}`;
|
|
283277
283394
|
}
|
|
@@ -283286,7 +283403,7 @@ async function runPush(schema, args) {
|
|
|
283286
283403
|
if (ok) {
|
|
283287
283404
|
return {
|
|
283288
283405
|
ok: true,
|
|
283289
|
-
message: body.unchanged ? `schema unchanged ${
|
|
283406
|
+
message: body.unchanged ? `schema unchanged ${import_picocolors12.default.dim(`(v${body.version})`)}` : `schema pushed (sandbox) ${import_picocolors12.default.dim(`(v${body.version}, hash ${body.hash})`)}`
|
|
283290
283407
|
};
|
|
283291
283408
|
}
|
|
283292
283409
|
if (status2 === 409) {
|
|
@@ -283296,33 +283413,33 @@ async function runPush(schema, args) {
|
|
|
283296
283413
|
(s) => s.shadowed != null
|
|
283297
283414
|
);
|
|
283298
283415
|
const lines = [
|
|
283299
|
-
|
|
283416
|
+
import_picocolors12.default.bold("Incompatible schema change \u2014 not safe to apply as-is."),
|
|
283300
283417
|
"",
|
|
283301
|
-
...unexecutable.map((u2) =>
|
|
283302
|
-
...warnings.map((w2) =>
|
|
283418
|
+
...unexecutable.map((u2) => import_picocolors12.default.red(fmtSignal(u2))),
|
|
283419
|
+
...warnings.map((w2) => import_picocolors12.default.yellow(fmtSignal(w2))),
|
|
283303
283420
|
"",
|
|
283304
283421
|
...hasShadowed ? [
|
|
283305
|
-
|
|
283422
|
+
import_picocolors12.default.dim(
|
|
283306
283423
|
" These models exist in the baseline above but not in your push. Sandbox readers"
|
|
283307
283424
|
),
|
|
283308
|
-
|
|
283425
|
+
import_picocolors12.default.dim(
|
|
283309
283426
|
" fall back to the production schema until you push your own, so applying this drops them."
|
|
283310
283427
|
),
|
|
283311
283428
|
""
|
|
283312
283429
|
] : [],
|
|
283313
|
-
|
|
283314
|
-
` Fix: ${
|
|
283430
|
+
import_picocolors12.default.dim(
|
|
283431
|
+
` Fix: ${import_picocolors12.default.bold("ablo push --force")} to apply anyway, or ${import_picocolors12.default.bold("--rename old:new")} if you renamed a model.`
|
|
283315
283432
|
)
|
|
283316
283433
|
];
|
|
283317
283434
|
return { ok: false, message: lines.join("\n") };
|
|
283318
283435
|
}
|
|
283319
283436
|
if (status2 === 403) {
|
|
283320
283437
|
const serverSays = body.message ?? body.reason;
|
|
283321
|
-
const hint = body.code === "database_role_cannot_enforce_rls" ? `Run ${
|
|
283438
|
+
const hint = body.code === "database_role_cannot_enforce_rls" ? `Run ${import_picocolors12.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_picocolors12.default.bold("sandbox")} key with ${import_picocolors12.default.bold("schema:push")} \u2014 manage keys at ${import_picocolors12.default.cyan("https://abloatai.com")}.`;
|
|
283322
283439
|
return {
|
|
283323
283440
|
ok: false,
|
|
283324
283441
|
message: `${serverSays ?? "This key can't author schema (missing schema:push scope)."}
|
|
283325
|
-
` +
|
|
283442
|
+
` + import_picocolors12.default.dim(hint)
|
|
283326
283443
|
};
|
|
283327
283444
|
}
|
|
283328
283445
|
return { ok: false, message: `Push failed (${status2}): ${body.message ?? body.reason ?? bodyText}` };
|
|
@@ -283332,25 +283449,25 @@ async function dev(argv) {
|
|
|
283332
283449
|
try {
|
|
283333
283450
|
args = parseDevArgs(argv);
|
|
283334
283451
|
} catch (err) {
|
|
283335
|
-
console.error(
|
|
283452
|
+
console.error(import_picocolors12.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
283336
283453
|
process.exit(1);
|
|
283337
283454
|
}
|
|
283338
283455
|
if (!args.apiKey) args.apiKey = resolveEffectiveApiKey("sandbox").key;
|
|
283339
283456
|
const key = classifyKey(args.apiKey, getMode());
|
|
283340
283457
|
if (!key.ok) {
|
|
283341
|
-
console.error(
|
|
283458
|
+
console.error(import_picocolors12.default.red(` ${key.reason}`));
|
|
283342
283459
|
process.exit(1);
|
|
283343
283460
|
}
|
|
283344
283461
|
console.log(`
|
|
283345
|
-
${brand("ablo")} ${
|
|
283462
|
+
${brand("ablo")} ${import_picocolors12.default.dim("push")} ${import_picocolors12.default.dim("(sandbox)")}
|
|
283346
283463
|
`);
|
|
283347
283464
|
const schema = await loadSchema(args.schemaPath, args.exportName);
|
|
283348
283465
|
const modelCount = Object.keys(schema.models).length;
|
|
283349
283466
|
console.log(
|
|
283350
|
-
` ${
|
|
283467
|
+
` ${import_picocolors12.default.dim("schema")} ${import_picocolors12.default.bold(args.schemaPath)} ${import_picocolors12.default.dim(`(${modelCount} models, hash ${(0, import_schema5.schemaHash)(schema)})`)}`
|
|
283351
283468
|
);
|
|
283352
|
-
console.log(` ${
|
|
283353
|
-
console.log(` ${
|
|
283469
|
+
console.log(` ${import_picocolors12.default.dim("key")} ${args.apiKey.slice(0, 12)}\u2026`);
|
|
283470
|
+
console.log(` ${import_picocolors12.default.dim("api")} ${args.url}
|
|
283354
283471
|
`);
|
|
283355
283472
|
const s = Y2();
|
|
283356
283473
|
s.start("Pushing schema definition (sandbox)");
|
|
@@ -283359,16 +283476,16 @@ async function dev(argv) {
|
|
|
283359
283476
|
if (!first.ok) process.exit(1);
|
|
283360
283477
|
if (process.env.ABLO_API_KEY) {
|
|
283361
283478
|
console.log(`
|
|
283362
|
-
${
|
|
283479
|
+
${import_picocolors12.default.green("\u2713")} ${import_picocolors12.default.bold("ABLO_API_KEY")} is set in this shell \u2014 the SDK reads it directly.`);
|
|
283363
283480
|
} else {
|
|
283364
283481
|
console.log(`
|
|
283365
|
-
${
|
|
283366
|
-
console.log(` ${
|
|
283482
|
+
${import_picocolors12.default.green("\u2713")} ${wireEnvLocal(args.apiKey)}`);
|
|
283483
|
+
console.log(` ${import_picocolors12.default.dim("Frameworks load it automatically; plain Node: node --env-file=.env.local app.ts")}`);
|
|
283367
283484
|
}
|
|
283368
283485
|
console.log(` Your app is wired for the sandbox.`);
|
|
283369
283486
|
if (!args.watch) return;
|
|
283370
283487
|
const abs = (0, import_path5.resolve)(process.cwd(), args.schemaPath);
|
|
283371
|
-
console.log(` ${
|
|
283488
|
+
console.log(` ${import_picocolors12.default.dim(`watching ${args.schemaPath} \u2026 (Ctrl-C to stop)`)}
|
|
283372
283489
|
`);
|
|
283373
283490
|
let timer2 = null;
|
|
283374
283491
|
let pushing = false;
|
|
@@ -283388,7 +283505,7 @@ async function dev(argv) {
|
|
|
283388
283505
|
const r2 = await runPush(next, args);
|
|
283389
283506
|
s2.stop(r2.message, r2.ok ? 0 : 1);
|
|
283390
283507
|
} catch (err) {
|
|
283391
|
-
s2.stop(
|
|
283508
|
+
s2.stop(import_picocolors12.default.red(`schema reload failed: ${err instanceof Error ? err.message : String(err)}`), 1);
|
|
283392
283509
|
} finally {
|
|
283393
283510
|
pushing = false;
|
|
283394
283511
|
}
|
|
@@ -283396,7 +283513,7 @@ async function dev(argv) {
|
|
|
283396
283513
|
const stop = () => {
|
|
283397
283514
|
watcher.close();
|
|
283398
283515
|
console.log(`
|
|
283399
|
-
${
|
|
283516
|
+
${import_picocolors12.default.dim("stopped.")}`);
|
|
283400
283517
|
process.exit(0);
|
|
283401
283518
|
};
|
|
283402
283519
|
process.on("SIGINT", stop);
|
|
@@ -283408,7 +283525,7 @@ async function dev(argv) {
|
|
|
283408
283525
|
// src/cli/login.ts
|
|
283409
283526
|
init_cjs_shims();
|
|
283410
283527
|
var import_child_process2 = require("child_process");
|
|
283411
|
-
var
|
|
283528
|
+
var import_picocolors13 = __toESM(require_picocolors(), 1);
|
|
283412
283529
|
init_dist2();
|
|
283413
283530
|
init_config();
|
|
283414
283531
|
init_theme();
|
|
@@ -283469,9 +283586,9 @@ async function deviceLogin(argv, deps = {}) {
|
|
|
283469
283586
|
const code = await codeRes.json();
|
|
283470
283587
|
const approvePath = `/cli?user_code=${code.user_code}`;
|
|
283471
283588
|
const url = account === "signup" ? `${DASHBOARD_URL}/signup?next=${encodeURIComponent(approvePath)}` : `${DASHBOARD_URL}${approvePath}`;
|
|
283472
|
-
Me(`${
|
|
283589
|
+
Me(`${import_picocolors13.default.bold(code.user_code)}
|
|
283473
283590
|
|
|
283474
|
-
${
|
|
283591
|
+
${import_picocolors13.default.dim(url)}`, "Approve in your browser");
|
|
283475
283592
|
openUrl(url);
|
|
283476
283593
|
const s = Y2();
|
|
283477
283594
|
s.start("Waiting for approval\u2026");
|
|
@@ -283538,7 +283655,7 @@ ${import_picocolors12.default.dim(url)}`, "Approve in your browser");
|
|
|
283538
283655
|
if (reason) M2.error(reason);
|
|
283539
283656
|
else if (provRes) M2.error(`Key provisioning returned ${provRes.status} from ${DASHBOARD_URL}/api/cli/provision-key.`);
|
|
283540
283657
|
M2.error(
|
|
283541
|
-
`The browser approval succeeded but the key handoff failed. Try again, or grab a ${
|
|
283658
|
+
`The browser approval succeeded but the key handoff failed. Try again, or grab a ${import_picocolors13.default.bold("sk_test_")} key from the dashboard and set ${import_picocolors13.default.bold("ABLO_API_KEY")}.`
|
|
283542
283659
|
);
|
|
283543
283660
|
process.exit(1);
|
|
283544
283661
|
}
|
|
@@ -283558,9 +283675,9 @@ ${import_picocolors12.default.dim(url)}`, "Approve in your browser");
|
|
|
283558
283675
|
{ mode: "sandbox", activeProject: prov.project ?? void 0 }
|
|
283559
283676
|
);
|
|
283560
283677
|
s.stop(`Saved keys to ${path}`);
|
|
283561
|
-
const where = prov.project ? ` ${
|
|
283678
|
+
const where = prov.project ? ` ${import_picocolors13.default.dim(`(project ${prov.project.slug})`)}` : "";
|
|
283562
283679
|
Se(
|
|
283563
|
-
`${
|
|
283680
|
+
`${import_picocolors13.default.green("\u2713")} Logged in ${import_picocolors13.default.dim("(sandbox)")}${where}. Run ${import_picocolors13.default.bold("npx ablo push")} to push your schema.`
|
|
283564
283681
|
);
|
|
283565
283682
|
}
|
|
283566
283683
|
async function login(argv = [], deps = {}) {
|
|
@@ -283569,13 +283686,13 @@ async function login(argv = [], deps = {}) {
|
|
|
283569
283686
|
function logout() {
|
|
283570
283687
|
const removed = clearCredential();
|
|
283571
283688
|
if (removed) {
|
|
283572
|
-
console.log(` ${
|
|
283689
|
+
console.log(` ${import_picocolors13.default.green("\u2713")} Logged out ${import_picocolors13.default.dim(`(credentials removed from ${configDir()})`)}`);
|
|
283573
283690
|
} else {
|
|
283574
|
-
console.log(` ${
|
|
283691
|
+
console.log(` ${import_picocolors13.default.dim("\u25CB")} Not logged in \u2014 nothing to remove.`);
|
|
283575
283692
|
}
|
|
283576
283693
|
if (process.env.ABLO_API_KEY) {
|
|
283577
283694
|
console.log(
|
|
283578
|
-
|
|
283695
|
+
import_picocolors13.default.dim(` Note: ${import_picocolors13.default.bold("ABLO_API_KEY")} is still set in this shell and takes precedence.`)
|
|
283579
283696
|
);
|
|
283580
283697
|
}
|
|
283581
283698
|
}
|
|
@@ -283585,7 +283702,7 @@ init_config();
|
|
|
283585
283702
|
|
|
283586
283703
|
// src/cli/mode.ts
|
|
283587
283704
|
init_cjs_shims();
|
|
283588
|
-
var
|
|
283705
|
+
var import_picocolors14 = __toESM(require_picocolors(), 1);
|
|
283589
283706
|
init_dist2();
|
|
283590
283707
|
init_config();
|
|
283591
283708
|
var PREFIX = { sandbox: "sk_test_", production: "rk_live_" };
|
|
@@ -283597,10 +283714,10 @@ function hintFor(m2, current) {
|
|
|
283597
283714
|
}
|
|
283598
283715
|
function apply(m2) {
|
|
283599
283716
|
setMode(m2);
|
|
283600
|
-
console.log(` ${
|
|
283717
|
+
console.log(` ${import_picocolors14.default.green("\u2713")} now in ${import_picocolors14.default.bold(m2)}`);
|
|
283601
283718
|
if (!getKeyEntry(m2)) {
|
|
283602
283719
|
console.log(
|
|
283603
|
-
|
|
283720
|
+
import_picocolors14.default.dim(` No ${m2} key stored \u2014 run ${import_picocolors14.default.bold("ablo login")} or ${import_picocolors14.default.bold(`ablo login --api-key ${PREFIX[m2]}\u2026`)}.`)
|
|
283604
283721
|
);
|
|
283605
283722
|
}
|
|
283606
283723
|
}
|
|
@@ -283613,14 +283730,14 @@ async function mode(argv) {
|
|
|
283613
283730
|
}
|
|
283614
283731
|
if (arg) {
|
|
283615
283732
|
console.error(
|
|
283616
|
-
|
|
283733
|
+
import_picocolors14.default.red(` unknown mode: ${arg}`) + import_picocolors14.default.dim(` (expected ${import_picocolors14.default.bold("sandbox")} or ${import_picocolors14.default.bold("production")})`)
|
|
283617
283734
|
);
|
|
283618
283735
|
process.exit(1);
|
|
283619
283736
|
}
|
|
283620
283737
|
const current = getMode();
|
|
283621
283738
|
if (!process.stdin.isTTY || process.env.CI) {
|
|
283622
283739
|
console.error(
|
|
283623
|
-
|
|
283740
|
+
import_picocolors14.default.red(" `ablo mode` needs an argument without a TTY: ") + import_picocolors14.default.bold("ablo mode sandbox") + import_picocolors14.default.dim(" | ") + import_picocolors14.default.bold("ablo mode production") + import_picocolors14.default.dim(` (current: ${current})`)
|
|
283624
283741
|
);
|
|
283625
283742
|
process.exit(1);
|
|
283626
283743
|
}
|
|
@@ -283644,7 +283761,7 @@ init_projects();
|
|
|
283644
283761
|
|
|
283645
283762
|
// src/cli/status.ts
|
|
283646
283763
|
init_cjs_shims();
|
|
283647
|
-
var
|
|
283764
|
+
var import_picocolors15 = __toESM(require_picocolors(), 1);
|
|
283648
283765
|
init_config();
|
|
283649
283766
|
init_target();
|
|
283650
283767
|
init_theme();
|
|
@@ -283652,9 +283769,9 @@ init_push();
|
|
|
283652
283769
|
function expiryLabel(iso) {
|
|
283653
283770
|
const ms = Date.parse(iso) - Date.now();
|
|
283654
283771
|
if (Number.isNaN(ms)) return "";
|
|
283655
|
-
if (ms <= 0) return
|
|
283772
|
+
if (ms <= 0) return import_picocolors15.default.red("expired");
|
|
283656
283773
|
const days = Math.floor(ms / (24 * 60 * 60 * 1e3));
|
|
283657
|
-
return
|
|
283774
|
+
return import_picocolors15.default.dim(days > 0 ? `expires in ${days}d` : "expires <1d");
|
|
283658
283775
|
}
|
|
283659
283776
|
async function ping(apiUrl2) {
|
|
283660
283777
|
const ctrl = new AbortController();
|
|
@@ -283738,27 +283855,27 @@ function formatConflict(conflict) {
|
|
|
283738
283855
|
function printTargetLines(target, localProject) {
|
|
283739
283856
|
const confirmed = target?.confirmed ?? null;
|
|
283740
283857
|
if (confirmed?.organizationId) {
|
|
283741
|
-
console.log(` ${
|
|
283858
|
+
console.log(` ${import_picocolors15.default.dim("org")} ${import_picocolors15.default.dim(confirmed.organizationId)}`);
|
|
283742
283859
|
}
|
|
283743
283860
|
let projectLine;
|
|
283744
283861
|
if (confirmed?.project) {
|
|
283745
283862
|
const p2 = confirmed.project;
|
|
283746
|
-
projectLine = p2.isDefault ? `${
|
|
283863
|
+
projectLine = p2.isDefault ? `${import_picocolors15.default.bold("default")} ${import_picocolors15.default.dim("(org-default)")}` : `${import_picocolors15.default.bold(p2.slug)} ${import_picocolors15.default.dim(`(${p2.id})`)}`;
|
|
283747
283864
|
} else if (confirmed) {
|
|
283748
|
-
projectLine = `${
|
|
283865
|
+
projectLine = `${import_picocolors15.default.bold("default")} ${import_picocolors15.default.dim("(org-default)")}`;
|
|
283749
283866
|
} else if (localProject) {
|
|
283750
|
-
projectLine = `${
|
|
283867
|
+
projectLine = `${import_picocolors15.default.bold(localProject.slug)} ${import_picocolors15.default.dim(`(${localProject.id})`)} ${import_picocolors15.default.yellow("(unconfirmed)")}`;
|
|
283751
283868
|
} else {
|
|
283752
|
-
projectLine = `${
|
|
283869
|
+
projectLine = `${import_picocolors15.default.bold("default")} ${target ? import_picocolors15.default.yellow("(unconfirmed)") : import_picocolors15.default.dim("(org-default)")}`;
|
|
283753
283870
|
}
|
|
283754
|
-
console.log(` ${
|
|
283871
|
+
console.log(` ${import_picocolors15.default.dim("project")} ${projectLine}`);
|
|
283755
283872
|
const env = confirmed?.environment ?? target?.keyEnv ?? null;
|
|
283756
283873
|
if (env) {
|
|
283757
|
-
const suffix = confirmed ? "" : ` ${
|
|
283758
|
-
console.log(` ${
|
|
283874
|
+
const suffix = confirmed ? "" : ` ${import_picocolors15.default.yellow("(unconfirmed)")}`;
|
|
283875
|
+
console.log(` ${import_picocolors15.default.dim("env")} ${import_picocolors15.default.bold(env)}${suffix}`);
|
|
283759
283876
|
}
|
|
283760
283877
|
for (const m2 of target?.mismatches ?? []) {
|
|
283761
|
-
console.log(` ${
|
|
283878
|
+
console.log(` ${import_picocolors15.default.yellow("\u26A0")} ${import_picocolors15.default.yellow(describeMismatch(m2))}`);
|
|
283762
283879
|
}
|
|
283763
283880
|
}
|
|
283764
283881
|
async function status(args = []) {
|
|
@@ -283829,80 +283946,80 @@ async function status(args = []) {
|
|
|
283829
283946
|
return;
|
|
283830
283947
|
}
|
|
283831
283948
|
console.log(`
|
|
283832
|
-
${brand("ablo")} ${
|
|
283949
|
+
${brand("ablo")} ${import_picocolors15.default.dim("status")}
|
|
283833
283950
|
`);
|
|
283834
283951
|
if (effective.key && effective.source && effective.source !== "stored") {
|
|
283835
283952
|
const label = effective.source === "env" ? "ABLO_API_KEY env" : effective.source;
|
|
283836
283953
|
console.log(
|
|
283837
|
-
` ${
|
|
283954
|
+
` ${import_picocolors15.default.dim("key")} ${effective.key.slice(0, 12)}\u2026 ${import_picocolors15.default.dim(`(${label} \u2014 overrides stored)`)}`
|
|
283838
283955
|
);
|
|
283839
283956
|
} else if (!cfg) {
|
|
283840
|
-
console.log(` ${
|
|
283957
|
+
console.log(` ${import_picocolors15.default.yellow("!")} Not logged in \u2014 run ${import_picocolors15.default.bold("ablo login")}.`);
|
|
283841
283958
|
}
|
|
283842
|
-
console.log(` ${
|
|
283959
|
+
console.log(` ${import_picocolors15.default.dim("mode")} ${import_picocolors15.default.bold(mode2)}`);
|
|
283843
283960
|
const activeEntry = getKeyEntry(mode2);
|
|
283844
283961
|
const key = describeEffectiveKey(mode2, process.env.ABLO_API_KEY, activeEntry);
|
|
283845
283962
|
if (key.keyMismatch) {
|
|
283846
|
-
console.log(` ${
|
|
283963
|
+
console.log(` ${import_picocolors15.default.yellow("!")} ${import_picocolors15.default.yellow(key.keyMismatch.message)}`);
|
|
283847
283964
|
}
|
|
283848
283965
|
const activeProject = getActiveProject();
|
|
283849
283966
|
printTargetLines(target, activeProject);
|
|
283850
283967
|
for (const m2 of ["sandbox", "production"]) {
|
|
283851
283968
|
const entry = getKeyEntry(m2);
|
|
283852
|
-
const marker = m2 === mode2 ?
|
|
283969
|
+
const marker = m2 === mode2 ? import_picocolors15.default.green("\u25CF") : import_picocolors15.default.dim("\u25CB");
|
|
283853
283970
|
if (entry) {
|
|
283854
283971
|
const exp = entry.expiresAt ? ` ${expiryLabel(entry.expiresAt)}` : "";
|
|
283855
|
-
console.log(` ${marker} ${m2.padEnd(10)} ${
|
|
283972
|
+
console.log(` ${marker} ${m2.padEnd(10)} ${import_picocolors15.default.dim(`${entry.apiKey.slice(0, 12)}\u2026`)}${exp}`);
|
|
283856
283973
|
} else {
|
|
283857
|
-
console.log(` ${marker} ${m2.padEnd(10)} ${
|
|
283974
|
+
console.log(` ${marker} ${m2.padEnd(10)} ${import_picocolors15.default.dim("\u2014 no key")}`);
|
|
283858
283975
|
}
|
|
283859
283976
|
}
|
|
283860
283977
|
const org = target?.confirmed?.organizationId ?? activeEntry?.organizationId;
|
|
283861
283978
|
const plan = resolvePushPlan();
|
|
283862
283979
|
console.log(
|
|
283863
|
-
` ${
|
|
283980
|
+
` ${import_picocolors15.default.dim("push")} ${plan.apiKey ? `${import_picocolors15.default.bold(plan.flow)} ${import_picocolors15.default.dim(`with ${plan.apiKey.slice(0, 12)}\u2026 (${plan.source})`)}` : `${import_picocolors15.default.bold(plan.flow)} ${import_picocolors15.default.yellow("\u2014 no credential")} ${import_picocolors15.default.dim(`(run ${import_picocolors15.default.bold("ablo login")} or set ${import_picocolors15.default.bold("ABLO_API_KEY")})`)}`}`
|
|
283864
283981
|
);
|
|
283865
|
-
process.stdout.write(` ${
|
|
283982
|
+
process.stdout.write(` ${import_picocolors15.default.dim("api")} ${apiUrl2} `);
|
|
283866
283983
|
const reachable = await ping(apiUrl2);
|
|
283867
|
-
console.log(reachable ?
|
|
283984
|
+
console.log(reachable ? import_picocolors15.default.green("reachable") : import_picocolors15.default.red("unreachable"));
|
|
283868
283985
|
if (reachable) {
|
|
283869
283986
|
const introspectKey = effective.key;
|
|
283870
283987
|
const pushed = await fetchPushedSchema(apiUrl2, introspectKey);
|
|
283871
283988
|
if (pushed?.active) {
|
|
283872
|
-
const when = pushed.pushedAt ? ` ${
|
|
283873
|
-
const ver = pushed.version != null ? ` ${
|
|
283874
|
-
const hashLabel = pushed.hash ? ` ${
|
|
283875
|
-
console.log(` ${
|
|
283989
|
+
const when = pushed.pushedAt ? ` ${import_picocolors15.default.dim(`@ ${pushed.pushedAt.slice(0, 10)}`)}` : "";
|
|
283990
|
+
const ver = pushed.version != null ? ` ${import_picocolors15.default.dim(`(rev ${pushed.version})`)}` : "";
|
|
283991
|
+
const hashLabel = pushed.hash ? ` ${import_picocolors15.default.dim(`hash ${pushed.hash}`)}` : "";
|
|
283992
|
+
console.log(` ${import_picocolors15.default.dim("schema")} ${import_picocolors15.default.bold(`${pushed.models.length} models pushed`)}${ver}${hashLabel}${when}`);
|
|
283876
283993
|
for (const m2 of pushed.models) {
|
|
283877
|
-
const tn = m2.typename === m2.key ?
|
|
283994
|
+
const tn = m2.typename === m2.key ? import_picocolors15.default.dim(`typename=${m2.typename}`) : import_picocolors15.default.yellow(`typename=${m2.typename}`);
|
|
283878
283995
|
const conflict = formatConflict(m2.conflict);
|
|
283879
|
-
const conflictStr2 = conflict ? ` ${
|
|
283880
|
-
console.log(` ${
|
|
283996
|
+
const conflictStr2 = conflict ? ` ${import_picocolors15.default.dim(`conflict=${conflict}`)}` : "";
|
|
283997
|
+
console.log(` ${import_picocolors15.default.dim("\u2022")} ${m2.key.padEnd(14)} ${tn}${conflictStr2}`);
|
|
283881
283998
|
}
|
|
283882
283999
|
} else if (pushed && !pushed.active) {
|
|
283883
|
-
console.log(` ${
|
|
284000
|
+
console.log(` ${import_picocolors15.default.dim("schema")} ${import_picocolors15.default.yellow("none pushed")} ${import_picocolors15.default.dim(`(run ${import_picocolors15.default.bold("ablo push")} or ${import_picocolors15.default.bold("ablo dev")})`)}`);
|
|
283884
284001
|
}
|
|
283885
284002
|
const firstPushedModel = pushed?.active ? pushed.models[0] : void 0;
|
|
283886
284003
|
if (firstPushedModel !== void 0) {
|
|
283887
284004
|
const probe = await probeDataPlane(apiUrl2, introspectKey, firstPushedModel.typename);
|
|
283888
284005
|
if (probe.status === "no_database") {
|
|
283889
|
-
console.log(` ${
|
|
284006
|
+
console.log(` ${import_picocolors15.default.dim("data")} ${import_picocolors15.default.red("\u2717 no database registered")}${org ? import_picocolors15.default.dim(` for org ${org}`) : ""}`);
|
|
283890
284007
|
console.log(
|
|
283891
|
-
` ${
|
|
283892
|
-
`reads/writes will fail with ${
|
|
284008
|
+
` ${import_picocolors15.default.dim(
|
|
284009
|
+
`reads/writes will fail with ${import_picocolors15.default.bold("tenant_routing_failed")}. Connect one with ${import_picocolors15.default.bold("ablo connect")}, or point ${import_picocolors15.default.bold("ABLO_API_KEY")} at an org that has a database.`
|
|
283893
284010
|
)}`
|
|
283894
284011
|
);
|
|
283895
284012
|
} else if (probe.status === "intermittent") {
|
|
283896
|
-
console.log(` ${
|
|
284013
|
+
console.log(` ${import_picocolors15.default.dim("data")} ${import_picocolors15.default.red(`\u2717 database routing is intermittent`)} ${import_picocolors15.default.dim(`(${probe.ok} ok / ${probe.failed} failed of ${probe.ok + probe.failed})`)}${org ? import_picocolors15.default.dim(` for org ${org}`) : ""}`);
|
|
283897
284014
|
console.log(
|
|
283898
|
-
` ${
|
|
283899
|
-
`some reads/writes fail with ${
|
|
284015
|
+
` ${import_picocolors15.default.dim(
|
|
284016
|
+
`some reads/writes fail with ${import_picocolors15.default.bold("tenant_routing_failed")} \u2014 the registration is unstable. Re-establish it with ${import_picocolors15.default.bold("ablo connect")} (or check for a recent server redeploy).`
|
|
283900
284017
|
)}`
|
|
283901
284018
|
);
|
|
283902
284019
|
} else if (probe.status === "forbidden") {
|
|
283903
|
-
console.log(` ${
|
|
284020
|
+
console.log(` ${import_picocolors15.default.dim("data")} ${import_picocolors15.default.yellow("? key not authorized to read")}${probe.detail ? import_picocolors15.default.dim(` (${probe.detail})`) : ""}`);
|
|
283904
284021
|
} else if (probe.status === "unknown") {
|
|
283905
|
-
console.log(` ${
|
|
284022
|
+
console.log(` ${import_picocolors15.default.dim("data")} ${import_picocolors15.default.yellow(`? data-plane check inconclusive (${probe.detail})`)}`);
|
|
283906
284023
|
}
|
|
283907
284024
|
}
|
|
283908
284025
|
}
|
|
@@ -283912,7 +284029,7 @@ async function status(args = []) {
|
|
|
283912
284029
|
// src/cli/logs.ts
|
|
283913
284030
|
init_cjs_shims();
|
|
283914
284031
|
init_errors();
|
|
283915
|
-
var
|
|
284032
|
+
var import_picocolors16 = __toESM(require_picocolors(), 1);
|
|
283916
284033
|
init_config();
|
|
283917
284034
|
init_theme();
|
|
283918
284035
|
init_push();
|
|
@@ -283979,10 +284096,10 @@ function resolveSince(since) {
|
|
|
283979
284096
|
var sleep2 = (ms) => new Promise((r2) => setTimeout(r2, ms));
|
|
283980
284097
|
function colorOp(op) {
|
|
283981
284098
|
const label = op.padEnd(6);
|
|
283982
|
-
if (op === "create") return
|
|
283983
|
-
if (op === "update") return
|
|
283984
|
-
if (op === "delete") return
|
|
283985
|
-
return
|
|
284099
|
+
if (op === "create") return import_picocolors16.default.green(label);
|
|
284100
|
+
if (op === "update") return import_picocolors16.default.yellow(label);
|
|
284101
|
+
if (op === "delete") return import_picocolors16.default.red(label);
|
|
284102
|
+
return import_picocolors16.default.dim(label);
|
|
283986
284103
|
}
|
|
283987
284104
|
function render(e2, json) {
|
|
283988
284105
|
if (json) {
|
|
@@ -283991,21 +284108,21 @@ function render(e2, json) {
|
|
|
283991
284108
|
return;
|
|
283992
284109
|
}
|
|
283993
284110
|
const t = new Date(e2.at).toLocaleTimeString();
|
|
283994
|
-
const actor = e2.actor ?
|
|
283995
|
-
console.log(` ${
|
|
284111
|
+
const actor = e2.actor ? import_picocolors16.default.dim(` ${e2.actor}`) : "";
|
|
284112
|
+
console.log(` ${import_picocolors16.default.dim(t)} ${colorOp(e2.op)} ${import_picocolors16.default.bold(e2.model)} ${import_picocolors16.default.dim(e2.recordId)}${actor}`);
|
|
283996
284113
|
}
|
|
283997
284114
|
async function logs(argv) {
|
|
283998
284115
|
let args;
|
|
283999
284116
|
try {
|
|
284000
284117
|
args = parseLogsArgs(argv);
|
|
284001
284118
|
} catch (err) {
|
|
284002
|
-
console.error(
|
|
284119
|
+
console.error(import_picocolors16.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
284003
284120
|
process.exit(1);
|
|
284004
284121
|
}
|
|
284005
284122
|
const apiKey = resolveApiKey(args.mode);
|
|
284006
284123
|
if (!apiKey) {
|
|
284007
284124
|
console.error(
|
|
284008
|
-
|
|
284125
|
+
import_picocolors16.default.red(` No API key.`) + import_picocolors16.default.dim(` Run ${import_picocolors16.default.bold("ablo login")} or set ${import_picocolors16.default.bold("ABLO_API_KEY")}.`)
|
|
284009
284126
|
);
|
|
284010
284127
|
process.exit(1);
|
|
284011
284128
|
}
|
|
@@ -284019,7 +284136,7 @@ async function logs(argv) {
|
|
|
284019
284136
|
if (!res) return null;
|
|
284020
284137
|
if (!res.ok) {
|
|
284021
284138
|
const body = await res.json().catch(() => ({}));
|
|
284022
|
-
console.error(
|
|
284139
|
+
console.error(import_picocolors16.default.red(` logs failed (${res.status}): ${body.reason ?? body.message ?? ""}`));
|
|
284023
284140
|
process.exit(1);
|
|
284024
284141
|
}
|
|
284025
284142
|
const json = await res.json();
|
|
@@ -284030,7 +284147,7 @@ async function logs(argv) {
|
|
|
284030
284147
|
}
|
|
284031
284148
|
if (!args.json) {
|
|
284032
284149
|
console.log(`
|
|
284033
|
-
${brand("ablo")} ${
|
|
284150
|
+
${brand("ablo")} ${import_picocolors16.default.dim("logs")} ${import_picocolors16.default.dim(`(${args.mode ?? "active"} mode)`)}
|
|
284034
284151
|
`);
|
|
284035
284152
|
}
|
|
284036
284153
|
const initial = await fetchPage({
|
|
@@ -284040,13 +284157,13 @@ async function logs(argv) {
|
|
|
284040
284157
|
...args.op ? { op: args.op } : {}
|
|
284041
284158
|
});
|
|
284042
284159
|
if (!initial) {
|
|
284043
|
-
console.error(
|
|
284160
|
+
console.error(import_picocolors16.default.red(` Couldn't reach ${baseUrl2}.`));
|
|
284044
284161
|
process.exit(1);
|
|
284045
284162
|
}
|
|
284046
284163
|
for (const e2 of initial.events) render(e2, args.json);
|
|
284047
284164
|
let cursor = initial.cursor;
|
|
284048
284165
|
if (!args.follow) return;
|
|
284049
|
-
if (!args.json) console.log(` ${
|
|
284166
|
+
if (!args.json) console.log(` ${import_picocolors16.default.dim("watching for new activity \u2026 (Ctrl-C to stop)")}
|
|
284050
284167
|
`);
|
|
284051
284168
|
for (; ; ) {
|
|
284052
284169
|
await sleep2(1500);
|
|
@@ -284064,7 +284181,7 @@ async function logs(argv) {
|
|
|
284064
284181
|
// src/cli/webhooks.ts
|
|
284065
284182
|
init_cjs_shims();
|
|
284066
284183
|
var import_fs8 = require("fs");
|
|
284067
|
-
var
|
|
284184
|
+
var import_picocolors17 = __toESM(require_picocolors(), 1);
|
|
284068
284185
|
init_credentialPolicy();
|
|
284069
284186
|
init_config();
|
|
284070
284187
|
init_theme();
|
|
@@ -284097,12 +284214,12 @@ function requireKey2(mode2) {
|
|
|
284097
284214
|
const apiKey = resolveApiKey(mode2);
|
|
284098
284215
|
if (!apiKey) {
|
|
284099
284216
|
console.error(
|
|
284100
|
-
|
|
284217
|
+
import_picocolors17.default.red(" No API key.") + import_picocolors17.default.dim(` Run ${import_picocolors17.default.bold("ablo login")} or set ${import_picocolors17.default.bold("ABLO_API_KEY")}.`)
|
|
284101
284218
|
);
|
|
284102
284219
|
process.exit(1);
|
|
284103
284220
|
}
|
|
284104
284221
|
if (classifyCredentialKind(apiKey) !== "secret") {
|
|
284105
|
-
console.error(
|
|
284222
|
+
console.error(import_picocolors17.default.red(" Managing webhooks requires a secret key ") + import_picocolors17.default.dim("(sk_test_ / sk_live_)."));
|
|
284106
284223
|
process.exit(1);
|
|
284107
284224
|
}
|
|
284108
284225
|
return apiKey;
|
|
@@ -284118,12 +284235,12 @@ async function api(apiKey, method, path, body) {
|
|
|
284118
284235
|
...body ? { body: JSON.stringify(body) } : {}
|
|
284119
284236
|
}).catch(() => null);
|
|
284120
284237
|
if (!res) {
|
|
284121
|
-
console.error(
|
|
284238
|
+
console.error(import_picocolors17.default.red(` Couldn't reach ${baseUrl()}.`));
|
|
284122
284239
|
process.exit(1);
|
|
284123
284240
|
}
|
|
284124
284241
|
if (!res.ok) {
|
|
284125
284242
|
const err = await res.json().catch(() => ({}));
|
|
284126
|
-
console.error(
|
|
284243
|
+
console.error(import_picocolors17.default.red(` Request failed (${res.status}): ${err.message ?? err.reason ?? ""}`));
|
|
284127
284244
|
process.exit(1);
|
|
284128
284245
|
}
|
|
284129
284246
|
return await res.json();
|
|
@@ -284145,11 +284262,11 @@ ${line}
|
|
|
284145
284262
|
return file;
|
|
284146
284263
|
}
|
|
284147
284264
|
function printEndpoint(e2) {
|
|
284148
|
-
const dot = e2.status === "enabled" ?
|
|
284149
|
-
const health = e2.last_error ?
|
|
284150
|
-
console.log(` ${dot} ${
|
|
284265
|
+
const dot = e2.status === "enabled" ? import_picocolors17.default.green("\u25CF") : import_picocolors17.default.red("\u25CF");
|
|
284266
|
+
const health = e2.last_error ? import_picocolors17.default.red(` last error: ${e2.last_error}`) : "";
|
|
284267
|
+
console.log(` ${dot} ${import_picocolors17.default.bold(e2.id)} ${e2.url}`);
|
|
284151
284268
|
console.log(
|
|
284152
|
-
|
|
284269
|
+
import_picocolors17.default.dim(
|
|
284153
284270
|
` ${e2.status} \xB7 ${e2.environment} \xB7 events ${e2.enabled_events.join(",")} \xB7 cursor ${e2.cursor ?? "\u2014"}${health}`
|
|
284154
284271
|
)
|
|
284155
284272
|
);
|
|
@@ -284161,7 +284278,7 @@ async function webhooks(argv) {
|
|
|
284161
284278
|
if (sub === "create") {
|
|
284162
284279
|
const url = positional(rest);
|
|
284163
284280
|
if (!url) {
|
|
284164
|
-
console.error(
|
|
284281
|
+
console.error(import_picocolors17.default.red(" Usage: ") + brand("ablo webhooks create <url>"));
|
|
284165
284282
|
process.exit(1);
|
|
284166
284283
|
}
|
|
284167
284284
|
const apiKey = requireKey2(mode2);
|
|
@@ -284173,8 +284290,8 @@ async function webhooks(argv) {
|
|
|
284173
284290
|
});
|
|
284174
284291
|
const file = writeSecretToEnv(created.secret);
|
|
284175
284292
|
console.log(`
|
|
284176
|
-
${
|
|
284177
|
-
console.log(` ${
|
|
284293
|
+
${import_picocolors17.default.green("\u2713")} Registered ${import_picocolors17.default.bold(created.id)} \u2192 ${created.url}`);
|
|
284294
|
+
console.log(` ${import_picocolors17.default.green("\u2713")} Wrote ${import_picocolors17.default.bold(ENV_KEY)} to ${import_picocolors17.default.bold(file)} ${import_picocolors17.default.dim("(shown once)")}
|
|
284178
284295
|
`);
|
|
284179
284296
|
return;
|
|
284180
284297
|
}
|
|
@@ -284182,7 +284299,7 @@ async function webhooks(argv) {
|
|
|
284182
284299
|
const apiKey = requireKey2(mode2);
|
|
284183
284300
|
const { data } = await api(apiKey, "GET", "");
|
|
284184
284301
|
if (data.length === 0) {
|
|
284185
|
-
console.log(
|
|
284302
|
+
console.log(import_picocolors17.default.dim(" No webhook endpoints. ") + brand("ablo webhooks create <url>"));
|
|
284186
284303
|
return;
|
|
284187
284304
|
}
|
|
284188
284305
|
console.log();
|
|
@@ -284193,40 +284310,40 @@ async function webhooks(argv) {
|
|
|
284193
284310
|
if (sub === "roll") {
|
|
284194
284311
|
const id = positional(rest);
|
|
284195
284312
|
if (!id) {
|
|
284196
|
-
console.error(
|
|
284313
|
+
console.error(import_picocolors17.default.red(" Usage: ") + brand("ablo webhooks roll <id>"));
|
|
284197
284314
|
process.exit(1);
|
|
284198
284315
|
}
|
|
284199
284316
|
const apiKey = requireKey2(mode2);
|
|
284200
284317
|
const rolled = await api(apiKey, "POST", `/${id}/roll_secret`);
|
|
284201
284318
|
const file = writeSecretToEnv(rolled.secret);
|
|
284202
284319
|
console.log(`
|
|
284203
|
-
${
|
|
284320
|
+
${import_picocolors17.default.green("\u2713")} Rolled secret for ${import_picocolors17.default.bold(id)} \u2192 ${import_picocolors17.default.bold(file)} ${import_picocolors17.default.dim("(old secret now invalid)")}
|
|
284204
284321
|
`);
|
|
284205
284322
|
return;
|
|
284206
284323
|
}
|
|
284207
284324
|
if (sub === "enable") {
|
|
284208
284325
|
const id = positional(rest);
|
|
284209
284326
|
if (!id) {
|
|
284210
|
-
console.error(
|
|
284327
|
+
console.error(import_picocolors17.default.red(" Usage: ") + brand("ablo webhooks enable <id>"));
|
|
284211
284328
|
process.exit(1);
|
|
284212
284329
|
}
|
|
284213
284330
|
const apiKey = requireKey2(mode2);
|
|
284214
284331
|
const e2 = await api(apiKey, "POST", `/${id}/enable`);
|
|
284215
|
-
console.log(` ${
|
|
284332
|
+
console.log(` ${import_picocolors17.default.green("\u2713")} Re-enabled ${import_picocolors17.default.bold(e2.id)}`);
|
|
284216
284333
|
return;
|
|
284217
284334
|
}
|
|
284218
284335
|
if (sub === "rm" || sub === "delete") {
|
|
284219
284336
|
const id = positional(rest);
|
|
284220
284337
|
if (!id) {
|
|
284221
|
-
console.error(
|
|
284338
|
+
console.error(import_picocolors17.default.red(" Usage: ") + brand("ablo webhooks rm <id>"));
|
|
284222
284339
|
process.exit(1);
|
|
284223
284340
|
}
|
|
284224
284341
|
const apiKey = requireKey2(mode2);
|
|
284225
284342
|
await api(apiKey, "DELETE", `/${id}`);
|
|
284226
|
-
console.log(` ${
|
|
284343
|
+
console.log(` ${import_picocolors17.default.green("\u2713")} Removed ${import_picocolors17.default.bold(id)}`);
|
|
284227
284344
|
return;
|
|
284228
284345
|
}
|
|
284229
|
-
console.log(` ${
|
|
284346
|
+
console.log(` ${import_picocolors17.default.bold("Usage:")}`);
|
|
284230
284347
|
console.log(` ${brand("ablo webhooks create <url>")} Register an endpoint; writes ${ENV_KEY}`);
|
|
284231
284348
|
console.log(` ${brand("ablo webhooks list")} List endpoints + delivery health`);
|
|
284232
284349
|
console.log(` ${brand("ablo webhooks roll <id>")} Mint a fresh signing secret`);
|
|
@@ -284238,7 +284355,7 @@ async function webhooks(argv) {
|
|
|
284238
284355
|
// src/cli/check.ts
|
|
284239
284356
|
init_cjs_shims();
|
|
284240
284357
|
init_errors();
|
|
284241
|
-
var
|
|
284358
|
+
var import_picocolors18 = __toESM(require_picocolors(), 1);
|
|
284242
284359
|
init_src();
|
|
284243
284360
|
var import_schema6 = require("@abloatai/ablo/schema");
|
|
284244
284361
|
init_push();
|
|
@@ -284276,13 +284393,13 @@ async function check(argv) {
|
|
|
284276
284393
|
try {
|
|
284277
284394
|
args = parseCheckArgs(argv);
|
|
284278
284395
|
} catch (err) {
|
|
284279
|
-
console.error(
|
|
284396
|
+
console.error(import_picocolors18.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
284280
284397
|
process.exit(1);
|
|
284281
284398
|
}
|
|
284282
284399
|
const dbUrl = process.env.DATABASE_URL ?? process.env.ABLO_DATABASE_URL;
|
|
284283
284400
|
if (!dbUrl) {
|
|
284284
284401
|
console.error(
|
|
284285
|
-
|
|
284402
|
+
import_picocolors18.default.red(` No database.`) + import_picocolors18.default.dim(` Set ${import_picocolors18.default.bold("DATABASE_URL")} to the Postgres you want Ablo to adopt.`)
|
|
284286
284403
|
);
|
|
284287
284404
|
process.exit(1);
|
|
284288
284405
|
}
|
|
@@ -284297,7 +284414,7 @@ async function check(argv) {
|
|
|
284297
284414
|
[args.appSchema]
|
|
284298
284415
|
);
|
|
284299
284416
|
} catch (err) {
|
|
284300
|
-
console.error(
|
|
284417
|
+
console.error(import_picocolors18.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
|
|
284301
284418
|
await sql.end({ timeout: 2 });
|
|
284302
284419
|
process.exit(1);
|
|
284303
284420
|
}
|
|
@@ -284312,7 +284429,7 @@ async function check(argv) {
|
|
|
284312
284429
|
set.add(r2.column_name);
|
|
284313
284430
|
}
|
|
284314
284431
|
console.log(`
|
|
284315
|
-
${brand("ablo")} ${
|
|
284432
|
+
${brand("ablo")} ${import_picocolors18.default.dim("check")} ${import_picocolors18.default.dim(`schema "${args.appSchema}"`)}
|
|
284316
284433
|
`);
|
|
284317
284434
|
const declaredTables = /* @__PURE__ */ new Set();
|
|
284318
284435
|
let errors = 0;
|
|
@@ -284322,7 +284439,7 @@ async function check(argv) {
|
|
|
284322
284439
|
declaredTables.add(table);
|
|
284323
284440
|
const present = colsByTable.get(table);
|
|
284324
284441
|
if (!present) {
|
|
284325
|
-
console.log(` ${
|
|
284442
|
+
console.log(` ${import_picocolors18.default.red("\u2717")} ${import_picocolors18.default.bold(key)} ${import_picocolors18.default.dim("\u2192")} table ${import_picocolors18.default.bold(table)} ${import_picocolors18.default.red("not found")}`);
|
|
284326
284443
|
errors++;
|
|
284327
284444
|
continue;
|
|
284328
284445
|
}
|
|
@@ -284344,26 +284461,26 @@ async function check(argv) {
|
|
|
284344
284461
|
if (!present.has(col)) problems.push(`missing column "${col}" (field ${fieldName})`);
|
|
284345
284462
|
}
|
|
284346
284463
|
if (problems.length > 0) {
|
|
284347
|
-
console.log(` ${
|
|
284348
|
-
for (const p2 of problems) console.log(` ${
|
|
284349
|
-
for (const w2 of warns) console.log(` ${
|
|
284464
|
+
console.log(` ${import_picocolors18.default.red("\u2717")} ${import_picocolors18.default.bold(key)} ${import_picocolors18.default.dim("\u2192")} ${table}`);
|
|
284465
|
+
for (const p2 of problems) console.log(` ${import_picocolors18.default.red("\u2022")} ${p2}`);
|
|
284466
|
+
for (const w2 of warns) console.log(` ${import_picocolors18.default.yellow("\u2022")} ${w2}`);
|
|
284350
284467
|
errors++;
|
|
284351
284468
|
} else if (warns.length > 0) {
|
|
284352
|
-
console.log(` ${
|
|
284353
|
-
for (const w2 of warns) console.log(` ${
|
|
284469
|
+
console.log(` ${import_picocolors18.default.yellow("!")} ${import_picocolors18.default.bold(key)} ${import_picocolors18.default.dim("\u2192")} ${table}`);
|
|
284470
|
+
for (const w2 of warns) console.log(` ${import_picocolors18.default.yellow("\u2022")} ${w2}`);
|
|
284354
284471
|
warnings++;
|
|
284355
284472
|
} else {
|
|
284356
|
-
console.log(` ${
|
|
284473
|
+
console.log(` ${import_picocolors18.default.green("\u2713")} ${import_picocolors18.default.bold(key)} ${import_picocolors18.default.dim(`\u2192 ${table} (id, ${orgCol ?? "no org"} ok)`)}`);
|
|
284357
284474
|
}
|
|
284358
284475
|
}
|
|
284359
284476
|
const modelCount = Object.keys(schemaJson.models).length;
|
|
284360
284477
|
const ignored = [...colsByTable.keys()].filter((t) => !declaredTables.has(t)).length;
|
|
284361
284478
|
console.log(
|
|
284362
284479
|
`
|
|
284363
|
-
${modelCount} model${modelCount === 1 ? "" : "s"} \xB7 ${
|
|
284480
|
+
${modelCount} model${modelCount === 1 ? "" : "s"} \xB7 ${import_picocolors18.default.green(`${modelCount - errors - warnings} ok`)}` + (warnings ? ` \xB7 ${import_picocolors18.default.yellow(`${warnings} warning${warnings === 1 ? "" : "s"}`)}` : "") + (errors ? ` \xB7 ${import_picocolors18.default.red(`${errors} error${errors === 1 ? "" : "s"}`)}` : "")
|
|
284364
284481
|
);
|
|
284365
284482
|
if (ignored > 0) {
|
|
284366
|
-
console.log(` ${
|
|
284483
|
+
console.log(` ${import_picocolors18.default.dim(`${ignored} other table${ignored === 1 ? "" : "s"} in your database \u2014 ignored by Ablo`)}`);
|
|
284367
284484
|
}
|
|
284368
284485
|
console.log();
|
|
284369
284486
|
process.exit(errors > 0 ? 1 : 0);
|
|
@@ -284371,7 +284488,7 @@ async function check(argv) {
|
|
|
284371
284488
|
|
|
284372
284489
|
// src/cli/upgrade.ts
|
|
284373
284490
|
init_cjs_shims();
|
|
284374
|
-
var
|
|
284491
|
+
var import_picocolors19 = __toESM(require_picocolors(), 1);
|
|
284375
284492
|
var import_ts_morph = __toESM(require_ts_morph(), 1);
|
|
284376
284493
|
var DEFAULT_GLOBS = ["app/**/*.{ts,tsx}", "src/**/*.{ts,tsx}", "ablo/**/*.{ts,tsx}", "lib/**/*.{ts,tsx}"];
|
|
284377
284494
|
var VERB_ARGS = {
|
|
@@ -284449,7 +284566,7 @@ async function upgrade(argv) {
|
|
|
284449
284566
|
project.addSourceFilesAtPaths(globs.length > 0 ? globs : DEFAULT_GLOBS);
|
|
284450
284567
|
const files = project.getSourceFiles();
|
|
284451
284568
|
if (files.length === 0) {
|
|
284452
|
-
console.log(
|
|
284569
|
+
console.log(import_picocolors19.default.yellow(' No .ts/.tsx files found. Pass a glob, e.g. `ablo upgrade "src/**/*.tsx"`.'));
|
|
284453
284570
|
return;
|
|
284454
284571
|
}
|
|
284455
284572
|
const edits = [];
|
|
@@ -284523,39 +284640,39 @@ async function upgrade(argv) {
|
|
|
284523
284640
|
const rel = (f) => f.replace(cwd + "/", "");
|
|
284524
284641
|
console.log();
|
|
284525
284642
|
if (edits.length === 0 && manual.length === 0) {
|
|
284526
|
-
console.log(
|
|
284643
|
+
console.log(import_picocolors19.default.green(" \u2713 Nothing to migrate \u2014 your code is already on the current API."));
|
|
284527
284644
|
return;
|
|
284528
284645
|
}
|
|
284529
284646
|
if (edits.length > 0) {
|
|
284530
|
-
console.log(
|
|
284647
|
+
console.log(import_picocolors19.default.bold(` ${write ? "Applied" : "Would apply"} ${edits.length} change${edits.length === 1 ? "" : "s"}:`));
|
|
284531
284648
|
for (const e2 of edits) {
|
|
284532
|
-
console.log(` ${
|
|
284533
|
-
console.log(` ${
|
|
284534
|
-
console.log(` ${
|
|
284649
|
+
console.log(` ${import_picocolors19.default.dim(`${rel(e2.file)}:${e2.line}`)} ${import_picocolors19.default.cyan(e2.rule)}`);
|
|
284650
|
+
console.log(` ${import_picocolors19.default.red("-")} ${e2.before}`);
|
|
284651
|
+
console.log(` ${import_picocolors19.default.green("+")} ${e2.after}`);
|
|
284535
284652
|
}
|
|
284536
284653
|
}
|
|
284537
284654
|
if (manual.length > 0) {
|
|
284538
284655
|
console.log();
|
|
284539
|
-
console.log(
|
|
284656
|
+
console.log(import_picocolors19.default.bold(import_picocolors19.default.yellow(` ${manual.length} spot${manual.length === 1 ? "" : "s"} need manual review (structural):`)));
|
|
284540
284657
|
for (const m2 of manual) {
|
|
284541
|
-
console.log(` ${
|
|
284542
|
-
console.log(` ${
|
|
284658
|
+
console.log(` ${import_picocolors19.default.dim(`${rel(m2.file)}:${m2.line}`)} ${import_picocolors19.default.yellow(m2.rule)}`);
|
|
284659
|
+
console.log(` ${import_picocolors19.default.dim(m2.snippet)}`);
|
|
284543
284660
|
console.log(` \u2192 ${m2.hint}`);
|
|
284544
284661
|
}
|
|
284545
284662
|
}
|
|
284546
284663
|
console.log();
|
|
284547
284664
|
if (write) {
|
|
284548
284665
|
await project.save();
|
|
284549
|
-
console.log(
|
|
284666
|
+
console.log(import_picocolors19.default.green(` \u2713 Wrote ${edits.length} change${edits.length === 1 ? "" : "s"}. Review the diff, run your typecheck.`));
|
|
284550
284667
|
} else {
|
|
284551
|
-
console.log(
|
|
284668
|
+
console.log(import_picocolors19.default.dim(" Dry run. Re-run with `--write` to apply the auto-fixes above (manual items are never auto-written)."));
|
|
284552
284669
|
}
|
|
284553
284670
|
}
|
|
284554
284671
|
|
|
284555
284672
|
// src/cli/pull.ts
|
|
284556
284673
|
init_cjs_shims();
|
|
284557
284674
|
init_errors();
|
|
284558
|
-
var
|
|
284675
|
+
var import_picocolors20 = __toESM(require_picocolors(), 1);
|
|
284559
284676
|
init_src();
|
|
284560
284677
|
var import_fs9 = require("fs");
|
|
284561
284678
|
init_theme();
|
|
@@ -284669,45 +284786,45 @@ async function pull(argv) {
|
|
|
284669
284786
|
try {
|
|
284670
284787
|
args = parsePullArgs(argv);
|
|
284671
284788
|
} catch (err) {
|
|
284672
|
-
console.error(
|
|
284789
|
+
console.error(import_picocolors20.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
284673
284790
|
process.exit(1);
|
|
284674
284791
|
}
|
|
284675
284792
|
const dbUrl = process.env.DATABASE_URL ?? process.env.ABLO_DATABASE_URL;
|
|
284676
284793
|
if (!dbUrl) {
|
|
284677
|
-
console.error(
|
|
284794
|
+
console.error(import_picocolors20.default.red(` No database.`) + import_picocolors20.default.dim(` Set ${import_picocolors20.default.bold("DATABASE_URL")} to the Postgres to pull from.`));
|
|
284678
284795
|
process.exit(1);
|
|
284679
284796
|
}
|
|
284680
284797
|
if ((0, import_fs9.existsSync)(args.out) && !args.force) {
|
|
284681
284798
|
console.error(
|
|
284682
|
-
|
|
284799
|
+
import_picocolors20.default.red(` ${args.out} already exists.`) + import_picocolors20.default.dim(` Re-run with ${import_picocolors20.default.bold("--force")} to overwrite.`)
|
|
284683
284800
|
);
|
|
284684
284801
|
process.exit(1);
|
|
284685
284802
|
}
|
|
284686
284803
|
console.log(`
|
|
284687
|
-
${brand("ablo")} ${
|
|
284804
|
+
${brand("ablo")} ${import_picocolors20.default.dim("pull")} ${import_picocolors20.default.dim(`schema "${args.appSchema}"`)}
|
|
284688
284805
|
`);
|
|
284689
284806
|
let result;
|
|
284690
284807
|
try {
|
|
284691
284808
|
result = await buildSchemaSourceFromDb({ dbUrl, appSchema: args.appSchema, importPath: args.importPath });
|
|
284692
284809
|
} catch (err) {
|
|
284693
|
-
console.error(
|
|
284810
|
+
console.error(import_picocolors20.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
|
|
284694
284811
|
process.exit(1);
|
|
284695
284812
|
}
|
|
284696
284813
|
if (result.models.length === 0) {
|
|
284697
284814
|
console.error(
|
|
284698
|
-
|
|
284815
|
+
import_picocolors20.default.yellow(` No adoptable tables found`) + import_picocolors20.default.dim(` (a model needs an ${import_picocolors20.default.bold("id")} + ${import_picocolors20.default.bold("organization_id")} column).`)
|
|
284699
284816
|
);
|
|
284700
284817
|
process.exit(1);
|
|
284701
284818
|
}
|
|
284702
284819
|
(0, import_fs9.writeFileSync)(args.out, result.source);
|
|
284703
|
-
console.log(` ${
|
|
284704
|
-
console.log(` ${
|
|
284820
|
+
console.log(` ${import_picocolors20.default.green("\u2713")} wrote ${import_picocolors20.default.bold(args.out)} ${import_picocolors20.default.dim(`(${result.models.length} models)`)}`);
|
|
284821
|
+
console.log(` ${import_picocolors20.default.dim(`models: ${result.models.join(", ")}`)}`);
|
|
284705
284822
|
if (result.skipped > 0) {
|
|
284706
|
-
console.log(` ${
|
|
284823
|
+
console.log(` ${import_picocolors20.default.dim(`${result.skipped} table(s) skipped \u2014 no id/organization_id`)}`);
|
|
284707
284824
|
}
|
|
284708
284825
|
console.log(
|
|
284709
284826
|
`
|
|
284710
|
-
${
|
|
284827
|
+
${import_picocolors20.default.dim("Introspection is lossy (enums, JSON shape, relations). Review the file, then")} ${import_picocolors20.default.bold("ablo check")}.
|
|
284711
284828
|
`
|
|
284712
284829
|
);
|
|
284713
284830
|
}
|
|
@@ -284715,7 +284832,7 @@ async function pull(argv) {
|
|
|
284715
284832
|
// src/cli/prismaPull.ts
|
|
284716
284833
|
init_cjs_shims();
|
|
284717
284834
|
init_errors();
|
|
284718
|
-
var
|
|
284835
|
+
var import_picocolors21 = __toESM(require_picocolors(), 1);
|
|
284719
284836
|
var import_fs10 = require("fs");
|
|
284720
284837
|
init_theme();
|
|
284721
284838
|
|
|
@@ -285000,55 +285117,55 @@ async function prismaPull(argv) {
|
|
|
285000
285117
|
try {
|
|
285001
285118
|
args = parsePrismaPullArgs(argv);
|
|
285002
285119
|
} catch (err) {
|
|
285003
|
-
console.error(
|
|
285120
|
+
console.error(import_picocolors21.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
285004
285121
|
process.exit(1);
|
|
285005
285122
|
}
|
|
285006
285123
|
if (!(0, import_fs10.existsSync)(args.schema)) {
|
|
285007
285124
|
console.error(
|
|
285008
|
-
|
|
285125
|
+
import_picocolors21.default.red(` No Prisma schema at ${import_picocolors21.default.bold(args.schema)}.`) + import_picocolors21.default.dim(` Pass a path: ${import_picocolors21.default.bold("ablo pull prisma <path>")}.`)
|
|
285009
285126
|
);
|
|
285010
285127
|
process.exit(1);
|
|
285011
285128
|
}
|
|
285012
285129
|
if ((0, import_fs10.existsSync)(args.out) && !args.force) {
|
|
285013
285130
|
console.error(
|
|
285014
|
-
|
|
285131
|
+
import_picocolors21.default.red(` ${args.out} already exists.`) + import_picocolors21.default.dim(` Re-run with ${import_picocolors21.default.bold("--force")} to overwrite.`)
|
|
285015
285132
|
);
|
|
285016
285133
|
process.exit(1);
|
|
285017
285134
|
}
|
|
285018
285135
|
console.log(`
|
|
285019
|
-
${brand("ablo")} ${
|
|
285136
|
+
${brand("ablo")} ${import_picocolors21.default.dim("pull prisma")} ${import_picocolors21.default.dim(args.schema)}
|
|
285020
285137
|
`);
|
|
285021
285138
|
let result;
|
|
285022
285139
|
try {
|
|
285023
285140
|
const src = (0, import_fs10.readFileSync)(args.schema, "utf8");
|
|
285024
285141
|
result = buildSchemaSourceFromPrisma({ src, importPath: args.importPath });
|
|
285025
285142
|
} catch (err) {
|
|
285026
|
-
console.error(
|
|
285143
|
+
console.error(import_picocolors21.default.red(` Couldn't parse the schema: ${err instanceof Error ? err.message : String(err)}`));
|
|
285027
285144
|
process.exit(1);
|
|
285028
285145
|
}
|
|
285029
285146
|
if (result.models.length === 0) {
|
|
285030
285147
|
console.error(
|
|
285031
|
-
|
|
285148
|
+
import_picocolors21.default.yellow(` No adoptable models found`) + import_picocolors21.default.dim(` (a model needs an ${import_picocolors21.default.bold("id")} + ${import_picocolors21.default.bold("organizationId")} / ${import_picocolors21.default.bold("organization_id")}).`)
|
|
285032
285149
|
);
|
|
285033
285150
|
process.exit(1);
|
|
285034
285151
|
}
|
|
285035
285152
|
(0, import_fs10.writeFileSync)(args.out, result.source);
|
|
285036
|
-
console.log(` ${
|
|
285037
|
-
console.log(` ${
|
|
285153
|
+
console.log(` ${import_picocolors21.default.green("\u2713")} wrote ${import_picocolors21.default.bold(args.out)} ${import_picocolors21.default.dim(`(${result.models.length} models)`)}`);
|
|
285154
|
+
console.log(` ${import_picocolors21.default.dim(`models: ${result.models.join(", ")}`)}`);
|
|
285038
285155
|
if (result.skipped.length > 0) {
|
|
285039
|
-
console.log(` ${
|
|
285040
|
-
for (const s of result.skipped) console.log(` ${
|
|
285156
|
+
console.log(` ${import_picocolors21.default.dim(`${result.skipped.length} model(s) skipped:`)}`);
|
|
285157
|
+
for (const s of result.skipped) console.log(` ${import_picocolors21.default.dim(`- ${s.name}: ${s.reason}`)}`);
|
|
285041
285158
|
}
|
|
285042
285159
|
console.log(
|
|
285043
285160
|
`
|
|
285044
|
-
${
|
|
285161
|
+
${import_picocolors21.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors21.default.bold("ablo check")}.
|
|
285045
285162
|
`
|
|
285046
285163
|
);
|
|
285047
285164
|
}
|
|
285048
285165
|
|
|
285049
285166
|
// src/cli/drizzlePull.ts
|
|
285050
285167
|
init_cjs_shims();
|
|
285051
|
-
var
|
|
285168
|
+
var import_picocolors22 = __toESM(require_picocolors(), 1);
|
|
285052
285169
|
init_errors();
|
|
285053
285170
|
var import_fs11 = require("fs");
|
|
285054
285171
|
var import_path6 = require("path");
|
|
@@ -285187,27 +285304,27 @@ async function drizzlePull(argv) {
|
|
|
285187
285304
|
try {
|
|
285188
285305
|
args = parseDrizzlePullArgs(argv);
|
|
285189
285306
|
} catch (err) {
|
|
285190
|
-
console.error(
|
|
285307
|
+
console.error(import_picocolors22.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
285191
285308
|
process.exit(1);
|
|
285192
285309
|
}
|
|
285193
285310
|
if (!args.schema) {
|
|
285194
285311
|
console.error(
|
|
285195
|
-
|
|
285312
|
+
import_picocolors22.default.red(` No Drizzle schema given.`) + import_picocolors22.default.dim(` Pass the module: ${import_picocolors22.default.bold("ablo pull drizzle src/db/schema.ts")}.`)
|
|
285196
285313
|
);
|
|
285197
285314
|
process.exit(1);
|
|
285198
285315
|
}
|
|
285199
285316
|
if (!(0, import_fs11.existsSync)(args.schema)) {
|
|
285200
|
-
console.error(
|
|
285317
|
+
console.error(import_picocolors22.default.red(` No file at ${import_picocolors22.default.bold(args.schema)}.`));
|
|
285201
285318
|
process.exit(1);
|
|
285202
285319
|
}
|
|
285203
285320
|
if ((0, import_fs11.existsSync)(args.out) && !args.force) {
|
|
285204
285321
|
console.error(
|
|
285205
|
-
|
|
285322
|
+
import_picocolors22.default.red(` ${args.out} already exists.`) + import_picocolors22.default.dim(` Re-run with ${import_picocolors22.default.bold("--force")} to overwrite.`)
|
|
285206
285323
|
);
|
|
285207
285324
|
process.exit(1);
|
|
285208
285325
|
}
|
|
285209
285326
|
console.log(`
|
|
285210
|
-
${brand("ablo")} ${
|
|
285327
|
+
${brand("ablo")} ${import_picocolors22.default.dim("pull drizzle")} ${import_picocolors22.default.dim(args.schema)}
|
|
285211
285328
|
`);
|
|
285212
285329
|
let result;
|
|
285213
285330
|
try {
|
|
@@ -285215,26 +285332,26 @@ async function drizzlePull(argv) {
|
|
|
285215
285332
|
result = await buildSchemaSourceFromDrizzle({ mod, importPath: args.importPath });
|
|
285216
285333
|
} catch (err) {
|
|
285217
285334
|
const msg = err instanceof Error ? err.message : String(err);
|
|
285218
|
-
const hint = msg.includes("Cannot find package 'drizzle-orm'") ?
|
|
285219
|
-
console.error(
|
|
285335
|
+
const hint = msg.includes("Cannot find package 'drizzle-orm'") ? import_picocolors22.default.dim(` (install ${import_picocolors22.default.bold("drizzle-orm")} in this project)`) : "";
|
|
285336
|
+
console.error(import_picocolors22.default.red(` Couldn't load the schema: ${msg}`) + hint);
|
|
285220
285337
|
process.exit(1);
|
|
285221
285338
|
}
|
|
285222
285339
|
if (result.models.length === 0) {
|
|
285223
285340
|
console.error(
|
|
285224
|
-
|
|
285341
|
+
import_picocolors22.default.yellow(` No adoptable tables found`) + import_picocolors22.default.dim(` (a table needs an ${import_picocolors22.default.bold("id")} + ${import_picocolors22.default.bold("organization_id")} column).`)
|
|
285225
285342
|
);
|
|
285226
285343
|
process.exit(1);
|
|
285227
285344
|
}
|
|
285228
285345
|
(0, import_fs11.writeFileSync)(args.out, result.source);
|
|
285229
|
-
console.log(` ${
|
|
285230
|
-
console.log(` ${
|
|
285346
|
+
console.log(` ${import_picocolors22.default.green("\u2713")} wrote ${import_picocolors22.default.bold(args.out)} ${import_picocolors22.default.dim(`(${result.models.length} models)`)}`);
|
|
285347
|
+
console.log(` ${import_picocolors22.default.dim(`models: ${result.models.join(", ")}`)}`);
|
|
285231
285348
|
if (result.skipped.length > 0) {
|
|
285232
|
-
console.log(` ${
|
|
285233
|
-
for (const s of result.skipped) console.log(` ${
|
|
285349
|
+
console.log(` ${import_picocolors22.default.dim(`${result.skipped.length} table(s) skipped:`)}`);
|
|
285350
|
+
for (const s of result.skipped) console.log(` ${import_picocolors22.default.dim(`- ${s.name}: ${s.reason}`)}`);
|
|
285234
285351
|
}
|
|
285235
285352
|
console.log(
|
|
285236
285353
|
`
|
|
285237
|
-
${
|
|
285354
|
+
${import_picocolors22.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors22.default.bold("ablo check")}.
|
|
285238
285355
|
`
|
|
285239
285356
|
);
|
|
285240
285357
|
}
|
|
@@ -285244,7 +285361,7 @@ init_theme();
|
|
|
285244
285361
|
|
|
285245
285362
|
// src/cli/renderError.ts
|
|
285246
285363
|
init_cjs_shims();
|
|
285247
|
-
var
|
|
285364
|
+
var import_picocolors23 = __toESM(require_picocolors(), 1);
|
|
285248
285365
|
init_errors();
|
|
285249
285366
|
init_theme();
|
|
285250
285367
|
var RECOVERY_HINT = {
|
|
@@ -285266,15 +285383,15 @@ function isStringArray(v2) {
|
|
|
285266
285383
|
function renderKnownDetails(details, line) {
|
|
285267
285384
|
if (!details) return;
|
|
285268
285385
|
const { retryAfterSeconds, missingIds, requiredCapability, unexecutable, errors } = details;
|
|
285269
|
-
if (typeof retryAfterSeconds === "number") line(` ${
|
|
285386
|
+
if (typeof retryAfterSeconds === "number") line(` ${import_picocolors23.default.dim("retry")} after ${retryAfterSeconds}s`);
|
|
285270
285387
|
if (isStringArray(missingIds) && missingIds.length > 0) {
|
|
285271
285388
|
const shown = missingIds.slice(0, 5).join(", ");
|
|
285272
285389
|
const more = missingIds.length > 5 ? ` (+${missingIds.length - 5} more)` : "";
|
|
285273
|
-
line(` ${
|
|
285390
|
+
line(` ${import_picocolors23.default.dim("missing")} ${shown}${more}`);
|
|
285274
285391
|
}
|
|
285275
|
-
if (typeof requiredCapability === "string") line(` ${
|
|
285392
|
+
if (typeof requiredCapability === "string") line(` ${import_picocolors23.default.dim("needs")} ${requiredCapability}`);
|
|
285276
285393
|
if (Array.isArray(unexecutable) && unexecutable.length > 0) {
|
|
285277
|
-
line(` ${
|
|
285394
|
+
line(` ${import_picocolors23.default.dim("blocked")} ${unexecutable.length} change(s) can't be applied \u2014 see \`unexecutable\` (--verbose)`);
|
|
285278
285395
|
}
|
|
285279
285396
|
if (Array.isArray(errors)) {
|
|
285280
285397
|
for (const e2 of errors.slice(0, 8)) {
|
|
@@ -285282,7 +285399,7 @@ function renderKnownDetails(details, line) {
|
|
|
285282
285399
|
const rec = e2;
|
|
285283
285400
|
const where = typeof rec.param === "string" ? `${rec.param}: ` : "";
|
|
285284
285401
|
const msg = typeof rec.message === "string" ? rec.message : "";
|
|
285285
|
-
if (msg) line(` ${
|
|
285402
|
+
if (msg) line(` ${import_picocolors23.default.dim("\xB7")} ${where}${msg}`);
|
|
285286
285403
|
}
|
|
285287
285404
|
}
|
|
285288
285405
|
}
|
|
@@ -285293,22 +285410,22 @@ function renderCliError(err, opts = {}) {
|
|
|
285293
285410
|
});
|
|
285294
285411
|
const verbose = opts.verbose ?? (process.argv.includes("--verbose") || process.env.ABLO_VERBOSE === "1");
|
|
285295
285412
|
if (err instanceof AbloError) {
|
|
285296
|
-
const codeTag = err.code ? ` ${
|
|
285413
|
+
const codeTag = err.code ? ` ${import_picocolors23.default.dim(`[${err.code}]`)}` : "";
|
|
285297
285414
|
line("");
|
|
285298
|
-
line(` ${brand("ablo")} ${
|
|
285415
|
+
line(` ${brand("ablo")} ${import_picocolors23.default.red("\u2717")} ${import_picocolors23.default.bold(titleForType(err.type))}${codeTag}`);
|
|
285299
285416
|
line("");
|
|
285300
285417
|
line(` ${err.message}`);
|
|
285301
|
-
if (err.param) line(` ${
|
|
285418
|
+
if (err.param) line(` ${import_picocolors23.default.dim("field")} ${err.param}`);
|
|
285302
285419
|
renderKnownDetails(err.details, line);
|
|
285303
285420
|
const hint = err.code ? RECOVERY_HINT[classifyRecovery(err.code)] : void 0;
|
|
285304
|
-
if (hint) line(` ${
|
|
285305
|
-
if (err.docUrl) line(` ${
|
|
285306
|
-
if (err.requestId) line(` ${
|
|
285421
|
+
if (hint) line(` ${import_picocolors23.default.dim(hint)}`);
|
|
285422
|
+
if (err.docUrl) line(` ${import_picocolors23.default.dim("docs")} ${err.docUrl}`);
|
|
285423
|
+
if (err.requestId) line(` ${import_picocolors23.default.dim("ref")} ${err.requestId}`);
|
|
285307
285424
|
if (verbose) {
|
|
285308
285425
|
if (err.details && Object.keys(err.details).length > 0) {
|
|
285309
|
-
line(` ${
|
|
285426
|
+
line(` ${import_picocolors23.default.dim("details")} ${JSON.stringify(err.details)}`);
|
|
285310
285427
|
}
|
|
285311
|
-
if (err.stack) line(
|
|
285428
|
+
if (err.stack) line(import_picocolors23.default.dim(err.stack));
|
|
285312
285429
|
}
|
|
285313
285430
|
line("");
|
|
285314
285431
|
process.exitCode = 1;
|
|
@@ -285316,16 +285433,16 @@ function renderCliError(err, opts = {}) {
|
|
|
285316
285433
|
}
|
|
285317
285434
|
const message = err instanceof Error ? err.message : String(err);
|
|
285318
285435
|
line("");
|
|
285319
|
-
line(` ${brand("ablo")} ${
|
|
285320
|
-
if (verbose && err instanceof Error && err.stack) line(
|
|
285321
|
-
else line(` ${
|
|
285436
|
+
line(` ${brand("ablo")} ${import_picocolors23.default.red("\u2717")} ${message}`);
|
|
285437
|
+
if (verbose && err instanceof Error && err.stack) line(import_picocolors23.default.dim(err.stack));
|
|
285438
|
+
else line(` ${import_picocolors23.default.dim("Run with --verbose for the full error.")}`);
|
|
285322
285439
|
line("");
|
|
285323
285440
|
process.exitCode = 1;
|
|
285324
285441
|
}
|
|
285325
285442
|
|
|
285326
285443
|
// src/cli/index.ts
|
|
285327
285444
|
var LOGO = `
|
|
285328
|
-
${brand("ablo")} ${
|
|
285445
|
+
${brand("ablo")} ${import_picocolors24.default.dim("sync engine")}
|
|
285329
285446
|
`;
|
|
285330
285447
|
var SUBCOMMAND_USAGE = {
|
|
285331
285448
|
connect: CONNECT_USAGE,
|
|
@@ -285360,7 +285477,7 @@ async function main() {
|
|
|
285360
285477
|
const devArgs = process.argv.slice(3);
|
|
285361
285478
|
const oneShot = devArgs.includes("--no-watch");
|
|
285362
285479
|
console.log(
|
|
285363
|
-
|
|
285480
|
+
import_picocolors24.default.dim(
|
|
285364
285481
|
oneShot ? " `ablo dev --no-watch` is `ablo push` (push once, no watcher) \u2014 running that." : " `ablo dev` is now `ablo push --watch` \u2014 running that."
|
|
285365
285482
|
)
|
|
285366
285483
|
);
|
|
@@ -285389,14 +285506,14 @@ async function main() {
|
|
|
285389
285506
|
const guard = guardActiveProjectKey();
|
|
285390
285507
|
if (!guard.ok && guard.available.length > 0 && !rest.includes("--url")) {
|
|
285391
285508
|
console.error(
|
|
285392
|
-
` ${
|
|
285509
|
+
` ${import_picocolors24.default.yellow("\u26A0")} active project ${import_picocolors24.default.bold(guard.activeProfile)} has no stored key ${import_picocolors24.default.dim(
|
|
285393
285510
|
`(you have keys for: ${guard.available.join(", ")})`
|
|
285394
285511
|
)}`
|
|
285395
285512
|
);
|
|
285396
285513
|
const loginCmd = guard.activeProfile === "default" ? "ablo login" : `ablo login --project ${guard.activeProfile}`;
|
|
285397
285514
|
console.error(
|
|
285398
|
-
|
|
285399
|
-
` Mint one with ${
|
|
285515
|
+
import_picocolors24.default.dim(
|
|
285516
|
+
` Mint one with ${import_picocolors24.default.bold(loginCmd)}, or switch with ${import_picocolors24.default.bold("ablo projects use <slug>")}.`
|
|
285400
285517
|
)
|
|
285401
285518
|
);
|
|
285402
285519
|
process.exitCode = 1;
|
|
@@ -285414,13 +285531,13 @@ async function main() {
|
|
|
285414
285531
|
await generate(process.argv.slice(3));
|
|
285415
285532
|
} else if (command === "schema") {
|
|
285416
285533
|
console.error(
|
|
285417
|
-
` ${
|
|
285534
|
+
` ${import_picocolors24.default.red("\u2717")} \`ablo schema push\` was renamed to \`${brand("ablo push")}\`.`
|
|
285418
285535
|
);
|
|
285419
285536
|
console.error(` Run \`ablo push${process.argv.slice(4).join(" ") ? " " + process.argv.slice(4).join(" ") : ""}\` instead.`);
|
|
285420
285537
|
process.exitCode = 1;
|
|
285421
285538
|
} else {
|
|
285422
285539
|
console.log(LOGO);
|
|
285423
|
-
console.log(` ${
|
|
285540
|
+
console.log(` ${import_picocolors24.default.bold("Usage:")}`);
|
|
285424
285541
|
console.log(` npx ablo init Scaffold ablo/ directory + starter schema`);
|
|
285425
285542
|
console.log(` npx ablo init --yes [--framework nextjs] Non-interactive (agents/CI): no prompts, flag-driven`);
|
|
285426
285543
|
console.log(` [--auth apikey] [--storage replication|endpoint] [--project <slug>] [--no-project]`);
|
|
@@ -285457,10 +285574,10 @@ async function main() {
|
|
|
285457
285574
|
console.log(` npx ablo generate Emit TypeScript types from your schema`);
|
|
285458
285575
|
console.log(` npx ablo generate --out path.ts Write generated types to a path`);
|
|
285459
285576
|
console.log();
|
|
285460
|
-
console.log(` ${
|
|
285577
|
+
console.log(` ${import_picocolors24.default.bold("Schema workflow:")}`);
|
|
285461
285578
|
console.log(` The server holds its own copy of your schema \u2014 edit ${brand("ablo/schema.ts")}, then`);
|
|
285462
285579
|
console.log(` run ${brand("ablo push")} (or keep ${brand("ablo dev")} running) before the server will accept`);
|
|
285463
|
-
console.log(` writes to new or changed models. Skip it and writes fail with ${
|
|
285580
|
+
console.log(` writes to new or changed models. Skip it and writes fail with ${import_picocolors24.default.yellow("server_execute_unknown_model")}.`);
|
|
285464
285581
|
console.log();
|
|
285465
285582
|
}
|
|
285466
285583
|
}
|
|
@@ -285511,7 +285628,7 @@ async function ensureInitProject(opts) {
|
|
|
285511
285628
|
const ensured = await ensureProject(slug);
|
|
285512
285629
|
if (ensured) {
|
|
285513
285630
|
console.log(
|
|
285514
|
-
` ${
|
|
285631
|
+
` ${import_picocolors24.default.green("\u2713")} ${ensured.created ? "Created" : "Using"} project ${import_picocolors24.default.bold(ensured.slug)} ${import_picocolors24.default.dim(`(${ensured.id})`)} \u2014 keys you mint for it are isolated from the org's other apps.`
|
|
285515
285632
|
);
|
|
285516
285633
|
}
|
|
285517
285634
|
}
|
|
@@ -285553,7 +285670,7 @@ async function chooseBool(flagValue, fallback, interactive, prompt) {
|
|
|
285553
285670
|
async function init(args = []) {
|
|
285554
285671
|
const opts = parseInitArgs(args);
|
|
285555
285672
|
const interactive = Boolean(process.stdin.isTTY) && !opts.yes && !process.env.CI;
|
|
285556
|
-
Ie(`${brand("ablo")} ${
|
|
285673
|
+
Ie(`${brand("ablo")} ${import_picocolors24.default.dim("sync engine")}`);
|
|
285557
285674
|
if (!(0, import_fs12.existsSync)("package.json")) {
|
|
285558
285675
|
xe("No package.json found. Run this from your project root.");
|
|
285559
285676
|
process.exit(1);
|
|
@@ -285631,7 +285748,7 @@ async function init(args = []) {
|
|
|
285631
285748
|
if (pullExisting) {
|
|
285632
285749
|
const dbUrl = process.env.DATABASE_URL ?? process.env.ABLO_DATABASE_URL;
|
|
285633
285750
|
if (!dbUrl) {
|
|
285634
|
-
schemaNote =
|
|
285751
|
+
schemaNote = import_picocolors24.default.dim(" (no DATABASE_URL \u2014 wrote starter; run `ablo pull` later)");
|
|
285635
285752
|
} else {
|
|
285636
285753
|
try {
|
|
285637
285754
|
const pulled = await buildSchemaSourceFromDb({
|
|
@@ -285641,12 +285758,12 @@ async function init(args = []) {
|
|
|
285641
285758
|
});
|
|
285642
285759
|
if (pulled.models.length > 0) {
|
|
285643
285760
|
schemaSource = pulled.source;
|
|
285644
|
-
schemaNote =
|
|
285761
|
+
schemaNote = import_picocolors24.default.dim(` (pulled ${pulled.models.length} models)`);
|
|
285645
285762
|
} else {
|
|
285646
|
-
schemaNote =
|
|
285763
|
+
schemaNote = import_picocolors24.default.dim(" (no adoptable tables \u2014 wrote starter)");
|
|
285647
285764
|
}
|
|
285648
285765
|
} catch {
|
|
285649
|
-
schemaNote =
|
|
285766
|
+
schemaNote = import_picocolors24.default.dim(" (pull failed \u2014 wrote starter)");
|
|
285650
285767
|
}
|
|
285651
285768
|
}
|
|
285652
285769
|
}
|
|
@@ -285672,14 +285789,14 @@ async function init(args = []) {
|
|
|
285672
285789
|
const existing = (0, import_fs12.readFileSync)(envFile, "utf-8");
|
|
285673
285790
|
if (!existing.includes("ABLO_")) {
|
|
285674
285791
|
(0, import_fs12.writeFileSync)(envFile, existing + "\n" + envBody);
|
|
285675
|
-
created.push(`${envFile} ${
|
|
285792
|
+
created.push(`${envFile} ${import_picocolors24.default.dim("(appended)")}`);
|
|
285676
285793
|
} else {
|
|
285677
|
-
created.push(`${envFile} ${
|
|
285794
|
+
created.push(`${envFile} ${import_picocolors24.default.dim("(already configured)")}`);
|
|
285678
285795
|
}
|
|
285679
285796
|
}
|
|
285680
285797
|
if (wireRealKey && resolvedKey) {
|
|
285681
285798
|
wireEnvLocal(resolvedKey);
|
|
285682
|
-
created.push(`.env.local ${
|
|
285799
|
+
created.push(`.env.local ${import_picocolors24.default.dim("(ABLO_API_KEY set from your login)")}`);
|
|
285683
285800
|
}
|
|
285684
285801
|
if (agent) {
|
|
285685
285802
|
(0, import_fs12.writeFileSync)((0, import_path7.join)(abloDir, "agent.ts"), generateAgent());
|
|
@@ -285694,17 +285811,17 @@ async function init(args = []) {
|
|
|
285694
285811
|
}
|
|
285695
285812
|
const providersPath = (0, import_path7.join)(layout.appBase, "providers.tsx");
|
|
285696
285813
|
(0, import_fs12.writeFileSync)(providersPath, generateProviders());
|
|
285697
|
-
created.push(`${providersPath} ${
|
|
285814
|
+
created.push(`${providersPath} ${import_picocolors24.default.dim(`(wrap ${(0, import_path7.join)(layout.appBase, "layout.tsx")} in <Providers>)`)}`);
|
|
285698
285815
|
const sessionDir = (0, import_path7.join)(layout.appBase, "api", "ablo-session");
|
|
285699
285816
|
(0, import_fs12.mkdirSync)(sessionDir, { recursive: true });
|
|
285700
285817
|
(0, import_fs12.writeFileSync)((0, import_path7.join)(sessionDir, "route.ts"), generateSessionRoute());
|
|
285701
|
-
created.push(`${(0, import_path7.join)(sessionDir, "route.ts")} ${
|
|
285818
|
+
created.push(`${(0, import_path7.join)(sessionDir, "route.ts")} ${import_picocolors24.default.dim("(wire your auth)")}`);
|
|
285702
285819
|
}
|
|
285703
285820
|
if (framework !== "vanilla") {
|
|
285704
285821
|
(0, import_fs12.writeFileSync)((0, import_path7.join)(abloDir, "TaskList.tsx"), generateComponent());
|
|
285705
285822
|
created.push(`${abloDir}/TaskList.tsx`);
|
|
285706
285823
|
}
|
|
285707
|
-
Me(created.map((f) => `${
|
|
285824
|
+
Me(created.map((f) => `${import_picocolors24.default.green("\u2713")} ${f}`).join("\n"), "Created");
|
|
285708
285825
|
const pm = detectPackageManager();
|
|
285709
285826
|
if (opts.install) {
|
|
285710
285827
|
const s = Y2();
|
|
@@ -285713,47 +285830,47 @@ async function init(args = []) {
|
|
|
285713
285830
|
(0, import_child_process3.execSync)(`${pm} add @abloatai/ablo`, { stdio: "ignore" });
|
|
285714
285831
|
s.stop("Installed @abloatai/ablo");
|
|
285715
285832
|
} catch {
|
|
285716
|
-
s.stop(`${
|
|
285833
|
+
s.stop(`${import_picocolors24.default.yellow("!")} Couldn't auto-install \u2014 run ${import_picocolors24.default.bold(`${pm} install @abloatai/ablo`)}`);
|
|
285717
285834
|
}
|
|
285718
285835
|
}
|
|
285719
285836
|
const steps = [
|
|
285720
|
-
`Get a ${
|
|
285721
|
-
`Run ${
|
|
285722
|
-
`Set ${
|
|
285723
|
-
`Run ${
|
|
285837
|
+
`Get a ${import_picocolors24.default.bold("sk_test_")} key at ${import_picocolors24.default.cyan("https://abloatai.com")}`,
|
|
285838
|
+
`Run ${import_picocolors24.default.bold("npx ablo login")} (or add ${import_picocolors24.default.bold("ABLO_API_KEY")} to ${import_picocolors24.default.bold(envFile)})`,
|
|
285839
|
+
`Set ${import_picocolors24.default.bold("DATABASE_URL")} in ${import_picocolors24.default.bold(envFile)} \u2014 your Postgres is the system of record; rows live there, never with Ablo`,
|
|
285840
|
+
`Run ${import_picocolors24.default.bold("npx ablo dev")} \u2014 pushes your schema definition and watches for changes`,
|
|
285724
285841
|
...storage === "replication" ? [
|
|
285725
|
-
`Connect your database \u2014 ${
|
|
285726
|
-
`Verify it \u2014 ${
|
|
285727
|
-
`Register it \u2014 ${
|
|
285842
|
+
`Connect your database \u2014 ${import_picocolors24.default.bold("npx ablo connect")} prints the one-time logical-replication setup SQL to run on your Postgres`,
|
|
285843
|
+
`Verify it \u2014 ${import_picocolors24.default.bold("npx ablo connect check")} walks wal_level, the publication, the role, and replica identity, with the exact fix for anything missing`,
|
|
285844
|
+
`Register it \u2014 ${import_picocolors24.default.bold("npx ablo connect register")} tells Ablo to start replicating; your app keeps writing through your own backend while Ablo tails the WAL`
|
|
285728
285845
|
] : [
|
|
285729
|
-
`Provision your DB: ${
|
|
285846
|
+
`Provision your DB: ${import_picocolors24.default.bold("npx ablo migrate")} (creates your Ablo-model tables + the adapter tables; keep your own migrations for everything else), then mount ${import_picocolors24.default.bold(`${abloDir}/data-source.ts`)} at ${import_picocolors24.default.bold("/api/ablo/source")}`
|
|
285730
285847
|
],
|
|
285731
285848
|
...framework === "nextjs" ? [
|
|
285732
|
-
`Wrap ${
|
|
285849
|
+
`Wrap ${import_picocolors24.default.bold((0, import_path7.join)(layout.appBase, "layout.tsx"))} in ${import_picocolors24.default.bold("<Providers>")} (${(0, import_path7.join)(layout.appBase, "providers.tsx")}) and add your auth to ${import_picocolors24.default.bold((0, import_path7.join)(layout.appBase, "api", "ablo-session", "route.ts"))}`
|
|
285733
285850
|
] : [],
|
|
285734
|
-
`Run ${
|
|
285851
|
+
`Run ${import_picocolors24.default.bold(`${pm} run dev`)} and open two browser tabs \u2014 changes sync in real-time`,
|
|
285735
285852
|
...agent ? [
|
|
285736
|
-
`Run ${
|
|
285737
|
-
`Run ${
|
|
285853
|
+
`Run ${import_picocolors24.default.bold(`npx tsx ${abloDir}/agent.ts`)} \u2014 an AI teammate edits the same tasks`,
|
|
285854
|
+
`Run ${import_picocolors24.default.bold("npx ablo logs")} to watch human + agent commits stream by`
|
|
285738
285855
|
] : []
|
|
285739
285856
|
];
|
|
285740
285857
|
Me(steps.map((s, i) => `${i + 1}. ${s}`).join("\n"), "Next steps");
|
|
285741
285858
|
const existingKey = resolveApiKey("sandbox");
|
|
285742
285859
|
if (existingKey) {
|
|
285743
285860
|
await ensureInitProject(opts);
|
|
285744
|
-
Se(`Already authorized ${
|
|
285861
|
+
Se(`Already authorized ${import_picocolors24.default.dim(`(${existingKey.slice(0, 11)}\u2026)`)} \u2014 run ${import_picocolors24.default.bold("npx ablo push")} next. ${import_picocolors24.default.dim("Docs:")} https://abloatai.com/docs`);
|
|
285745
285862
|
return;
|
|
285746
285863
|
}
|
|
285747
285864
|
if (interactive && opts.login) {
|
|
285748
285865
|
const loginNow = await ye({ message: "Log in now? (opens your browser)", initialValue: true });
|
|
285749
285866
|
if (!pD(loginNow) && loginNow) {
|
|
285750
|
-
Se(`${
|
|
285867
|
+
Se(`${import_picocolors24.default.dim("Docs:")} https://abloatai.com/docs`);
|
|
285751
285868
|
await login();
|
|
285752
285869
|
await ensureInitProject(opts);
|
|
285753
285870
|
return;
|
|
285754
285871
|
}
|
|
285755
285872
|
}
|
|
285756
|
-
Se(`Run ${
|
|
285873
|
+
Se(`Run ${import_picocolors24.default.bold("npx ablo login")} when ready. ${import_picocolors24.default.dim("Docs:")} https://abloatai.com/docs`);
|
|
285757
285874
|
}
|
|
285758
285875
|
function generateSchema() {
|
|
285759
285876
|
return `import { defineSchema, model, relation, z } from '@abloatai/ablo/schema';
|