@abloatai/cli 0.56.0 → 0.57.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +75 -13
- package/package.json +3 -3
package/dist/cli.cjs
CHANGED
|
@@ -3970,7 +3970,7 @@ var init_observeCliError = __esm({
|
|
|
3970
3970
|
import_errorObservation = require("@abloatai/transaction/errorObservation");
|
|
3971
3971
|
import_errors5 = require("@abloatai/transaction/errors");
|
|
3972
3972
|
dsn = process.env.ABLO_CLI_SENTRY_DSN ?? "https://1ac154bff10b06836e1ea9de9e0d92f0@o4510928209772544.ingest.de.sentry.io/4511660691423312" ?? "";
|
|
3973
|
-
release = process.env.ABLO_CLI_RELEASE ?? "@abloatai/cli@0.
|
|
3973
|
+
release = process.env.ABLO_CLI_RELEASE ?? "@abloatai/cli@0.57.0";
|
|
3974
3974
|
initialized = false;
|
|
3975
3975
|
nativeProcessExit = process.exit.bind(process);
|
|
3976
3976
|
exitBoundaryInstalled = false;
|
|
@@ -4297,7 +4297,7 @@ var init_src2 = __esm({
|
|
|
4297
4297
|
|
|
4298
4298
|
// src/cliEnvironment.ts
|
|
4299
4299
|
function cliVersion() {
|
|
4300
|
-
return "0.
|
|
4300
|
+
return "0.57.0";
|
|
4301
4301
|
}
|
|
4302
4302
|
function cliOs() {
|
|
4303
4303
|
const value = (0, import_node_os.platform)();
|
|
@@ -4372,7 +4372,9 @@ function trackCliSchemaPushAttempted() {
|
|
|
4372
4372
|
}
|
|
4373
4373
|
function flushProductAnalytics(options = {}) {
|
|
4374
4374
|
if (flushInFlight) return flushInFlight;
|
|
4375
|
-
flushInFlight = flushOnce(options).catch(() =>
|
|
4375
|
+
flushInFlight = flushOnce(options).catch((error) => {
|
|
4376
|
+
void error;
|
|
4377
|
+
}).finally(() => {
|
|
4376
4378
|
flushInFlight = null;
|
|
4377
4379
|
});
|
|
4378
4380
|
return flushInFlight;
|
|
@@ -4395,8 +4397,8 @@ function queueEvent(eventName, properties) {
|
|
|
4395
4397
|
state.queue = [...state.queue, parsed].slice(-MAX_QUEUED_EVENTS);
|
|
4396
4398
|
writeState(state);
|
|
4397
4399
|
if (disclose) {
|
|
4398
|
-
|
|
4399
|
-
"Ablo collects limited usage analytics. Run `ablo telemetry disable` to opt out or `ablo telemetry status` for details
|
|
4400
|
+
process.stderr.write(
|
|
4401
|
+
"Ablo collects limited usage analytics. Run `ablo telemetry disable` to opt out or `ablo telemetry status` for details.\n"
|
|
4400
4402
|
);
|
|
4401
4403
|
}
|
|
4402
4404
|
} catch {
|
|
@@ -4473,8 +4475,9 @@ function writeState(state) {
|
|
|
4473
4475
|
function environmentBlocker() {
|
|
4474
4476
|
if (process.env.ABLO_TELEMETRY_DISABLED === "1") return "ABLO_TELEMETRY_DISABLED";
|
|
4475
4477
|
if (process.env.DO_NOT_TRACK === "1") return "DO_NOT_TRACK";
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
+
return TELEMETRY_BLOCKING_ENV.slice(2).find(
|
|
4479
|
+
(name) => truthyEnvironmentValue(process.env[name])
|
|
4480
|
+
) ?? null;
|
|
4478
4481
|
}
|
|
4479
4482
|
function truthyEnvironmentValue(value) {
|
|
4480
4483
|
return value !== void 0 && value !== "" && value !== "0" && value.toLowerCase() !== "false";
|
|
@@ -4502,7 +4505,7 @@ function runTelemetryCommand(argv) {
|
|
|
4502
4505
|
if (status2.blockedBy) console.log(`Environment override: ${status2.blockedBy}`);
|
|
4503
4506
|
console.log(`Queued events: ${status2.queuedEvents}`);
|
|
4504
4507
|
}
|
|
4505
|
-
var import_node_crypto2, import_node_fs, import_node_path, TELEMETRY_FILE_VERSION, MAX_QUEUED_EVENTS, MAX_FLUSH_EVENTS, DEFAULT_FLUSH_TIMEOUT_MS, flushInFlight;
|
|
4508
|
+
var import_node_crypto2, import_node_fs, import_node_path, TELEMETRY_FILE_VERSION, MAX_QUEUED_EVENTS, MAX_FLUSH_EVENTS, DEFAULT_FLUSH_TIMEOUT_MS, flushInFlight, TELEMETRY_BLOCKING_ENV;
|
|
4506
4509
|
var init_telemetry = __esm({
|
|
4507
4510
|
"src/telemetry.ts"() {
|
|
4508
4511
|
"use strict";
|
|
@@ -4519,6 +4522,16 @@ var init_telemetry = __esm({
|
|
|
4519
4522
|
MAX_FLUSH_EVENTS = 20;
|
|
4520
4523
|
DEFAULT_FLUSH_TIMEOUT_MS = 800;
|
|
4521
4524
|
flushInFlight = null;
|
|
4525
|
+
TELEMETRY_BLOCKING_ENV = [
|
|
4526
|
+
"ABLO_TELEMETRY_DISABLED",
|
|
4527
|
+
"DO_NOT_TRACK",
|
|
4528
|
+
"CI",
|
|
4529
|
+
"GITHUB_ACTIONS",
|
|
4530
|
+
"GITLAB_CI",
|
|
4531
|
+
"BUILDKITE",
|
|
4532
|
+
"CIRCLECI",
|
|
4533
|
+
"TF_BUILD"
|
|
4534
|
+
];
|
|
4522
4535
|
}
|
|
4523
4536
|
});
|
|
4524
4537
|
|
|
@@ -288767,6 +288780,9 @@ async function check(argv) {
|
|
|
288767
288780
|
}
|
|
288768
288781
|
const schema = await loadSchema(args.schemaPath, args.exportName);
|
|
288769
288782
|
const schemaJson = JSON.parse((0, import_schema9.serializeSchema)(schema));
|
|
288783
|
+
const accessFindings = new Map(
|
|
288784
|
+
(0, import_schema9.auditSchemaAccessPolicies)(schemaJson).map((finding) => [finding.model, finding])
|
|
288785
|
+
);
|
|
288770
288786
|
console.log(`
|
|
288771
288787
|
${brand("ablo")} ${import_picocolors25.default.dim("check")} ${import_picocolors25.default.dim(`schema "${args.appSchema}"`)}
|
|
288772
288788
|
`);
|
|
@@ -288807,6 +288823,12 @@ async function check(argv) {
|
|
|
288807
288823
|
}
|
|
288808
288824
|
const problems = [];
|
|
288809
288825
|
const warns = [];
|
|
288826
|
+
const accessFinding = accessFindings.get(key);
|
|
288827
|
+
if (accessFinding) {
|
|
288828
|
+
problems.push(
|
|
288829
|
+
`[${accessFinding.code}] ${accessFinding.message} Fix: ${accessFinding.fix}`
|
|
288830
|
+
);
|
|
288831
|
+
}
|
|
288810
288832
|
if (!present.has("id")) problems.push('missing primary key "id"');
|
|
288811
288833
|
const orgCol = (0, import_schema9.tenancyColumn)((0, import_schema9.resolveTenancy)(model));
|
|
288812
288834
|
if (orgCol && !present.has(orgCol)) {
|
|
@@ -289751,8 +289773,21 @@ export async function POST(request: Request): Promise<Response> {
|
|
|
289751
289773
|
);
|
|
289752
289774
|
}
|
|
289753
289775
|
|
|
289776
|
+
const authorizedScope = await authorizeActiveWorkspace(user.id);
|
|
289777
|
+
if (!authorizedScope) {
|
|
289778
|
+
return Response.json(
|
|
289779
|
+
credentialEndpointErrorSchema.parse({
|
|
289780
|
+
error: { code: 'policy_denied', message: 'Workspace membership is stale or revoked' },
|
|
289781
|
+
}),
|
|
289782
|
+
{ status: 403, headers: noStore },
|
|
289783
|
+
);
|
|
289784
|
+
}
|
|
289785
|
+
|
|
289754
289786
|
const { token, expiresAt } = await sync.sessions.create({
|
|
289755
289787
|
user: { id: user.id },
|
|
289788
|
+
// These ids came from the server-side membership lookup below. Never take
|
|
289789
|
+
// organization, workspace, team, or group ids from the request body.
|
|
289790
|
+
syncGroups: authorizedScope.syncGroups,
|
|
289756
289791
|
can: { records: ['read', 'create', 'update'] },
|
|
289757
289792
|
});
|
|
289758
289793
|
return Response.json(
|
|
@@ -289776,6 +289811,27 @@ async function getCurrentUser(): Promise<{ id: string } | null> {
|
|
|
289776
289811
|
const session = await auth.api.getSession({ headers: await headers() });
|
|
289777
289812
|
return session?.user ? { id: session.user.id } : null;
|
|
289778
289813
|
}
|
|
289814
|
+
|
|
289815
|
+
type AuthorizedWorkspace = {
|
|
289816
|
+
workspaceId: string;
|
|
289817
|
+
syncGroups: readonly [\`workspace:\${string}\`, ...\`\${string}:\${string}\`[]];
|
|
289818
|
+
};
|
|
289819
|
+
|
|
289820
|
+
async function authorizeActiveWorkspace(userId: string): Promise<AuthorizedWorkspace | null> {
|
|
289821
|
+
void userId;
|
|
289822
|
+
// REQUIRED: query your membership table here, immediately before minting.
|
|
289823
|
+
// Read the active workspace from the server-side session, verify this user has
|
|
289824
|
+
// an active membership, and derive every team/group id on the server. Return
|
|
289825
|
+
// null for a stale or revoked membership. This refusal keeps a newly generated
|
|
289826
|
+
// route from turning "signed in" into workspace authorization by accident.
|
|
289827
|
+
//
|
|
289828
|
+
// Example after your membership query:
|
|
289829
|
+
// return {
|
|
289830
|
+
// workspaceId: membership.workspaceId,
|
|
289831
|
+
// syncGroups: [\`workspace:\${membership.workspaceId}\`],
|
|
289832
|
+
// };
|
|
289833
|
+
return null;
|
|
289834
|
+
}
|
|
289779
289835
|
`;
|
|
289780
289836
|
}
|
|
289781
289837
|
|
|
@@ -289808,7 +289864,7 @@ export const schema = defineSchema({
|
|
|
289808
289864
|
});
|
|
289809
289865
|
`;
|
|
289810
289866
|
}
|
|
289811
|
-
function generateSyncConfig(auth) {
|
|
289867
|
+
function generateSyncConfig(auth, options = {}) {
|
|
289812
289868
|
const authLine = auth === "apikey" ? "" : auth === "firebase" ? `
|
|
289813
289869
|
auth: async () => {
|
|
289814
289870
|
const { getAuth } = await import('firebase/auth');
|
|
@@ -289820,7 +289876,7 @@ function generateSyncConfig(auth) {
|
|
|
289820
289876
|
// auth: async () => { const { data } = await supabase.auth.getSession(); return data.session?.access_token ?? ''; },` : auth === "betterauth" ? `
|
|
289821
289877
|
// auth: async () => { const session = await authClient.getSession(); return session?.token ?? ''; },` : `
|
|
289822
289878
|
// auth: () => 'your-jwt-token', // replace with your auth provider`;
|
|
289823
|
-
return
|
|
289879
|
+
return `${options.serverOnly ? "import 'server-only';\n\n" : ""}import Ablo from '@abloatai/ablo';
|
|
289824
289880
|
import { schema } from './schema';
|
|
289825
289881
|
|
|
289826
289882
|
// SERVER-ONLY client \u2014 it holds your \`sk_\` key. Use it from server code: the
|
|
@@ -289982,7 +290038,10 @@ export async function POST(req: Request): Promise<Response> {
|
|
|
289982
290038
|
const model: unknown = Reflect.get(prisma, event.model); // prisma.record, prisma.task, \u2026
|
|
289983
290039
|
if (!isModelDelegate(model)) continue; // a model you don't mirror locally \u2014 skip it
|
|
289984
290040
|
if (event.data === null) {
|
|
289985
|
-
await model.delete({ where: { id: event.objectId } }).catch(() => {
|
|
290041
|
+
await model.delete({ where: { id: event.objectId } }).catch((error) => {
|
|
290042
|
+
// Idempotent replay: a missing local row is already the desired state.
|
|
290043
|
+
void error;
|
|
290044
|
+
});
|
|
289986
290045
|
} else {
|
|
289987
290046
|
await model.upsert({ where: { id: event.objectId }, create: event.data, update: event.data });
|
|
289988
290047
|
}
|
|
@@ -290062,7 +290121,7 @@ async function main() {
|
|
|
290062
290121
|
main().catch((err) => {
|
|
290063
290122
|
// Ablo errors stringify to one clean line (code + message + docs link),
|
|
290064
290123
|
// never a stack/object dump \u2014 see AbloError.toString().
|
|
290065
|
-
|
|
290124
|
+
process.stderr.write(String(err) + '\\n');
|
|
290066
290125
|
process.exit(1);
|
|
290067
290126
|
});
|
|
290068
290127
|
`;
|
|
@@ -290413,7 +290472,10 @@ async function runInit(args = []) {
|
|
|
290413
290472
|
}
|
|
290414
290473
|
}
|
|
290415
290474
|
files.push({ path: (0, import_node_path5.join)(abloDir, "schema.ts"), content: schemaSource, note: schemaNote });
|
|
290416
|
-
files.push({
|
|
290475
|
+
files.push({
|
|
290476
|
+
path: (0, import_node_path5.join)(abloDir, "index.ts"),
|
|
290477
|
+
content: generateSyncConfig(auth, { serverOnly: framework === "nextjs" })
|
|
290478
|
+
});
|
|
290417
290479
|
files.push({ path: (0, import_node_path5.join)(abloDir, "register.ts"), content: generateRegister() });
|
|
290418
290480
|
const orm = detectOrm(opts.orm);
|
|
290419
290481
|
if (storage === "endpoint") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abloatai/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.57.0",
|
|
4
4
|
"description": "The ablo command line: set up Ablo, connect your database, and push your schema from the terminal.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -35,10 +35,10 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@sentry/node": "^10.18.0",
|
|
38
|
-
"@abloatai/transaction": "^0.
|
|
38
|
+
"@abloatai/transaction": "^0.57.0",
|
|
39
39
|
"jiti": "^2.7.0",
|
|
40
40
|
"zod": "^4.4.3",
|
|
41
|
-
"@abloatai/humans": "^0.
|
|
41
|
+
"@abloatai/humans": "^0.57.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@ablo/product-analytics": "file:../product-analytics",
|