@zveltio/cli 3.0.0-beta.78 → 3.0.0-beta.80
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/index.js +98 -33
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -4028,7 +4028,7 @@ var CORE_FIELD_TS_TYPES = {
|
|
|
4028
4028
|
smallint: "number",
|
|
4029
4029
|
real: "number",
|
|
4030
4030
|
decimal: "number",
|
|
4031
|
-
money: "
|
|
4031
|
+
money: "string",
|
|
4032
4032
|
varchar: "string",
|
|
4033
4033
|
char: "string",
|
|
4034
4034
|
time: "string",
|
|
@@ -4042,12 +4042,12 @@ var CORE_FIELD_TS_TYPES = {
|
|
|
4042
4042
|
xml: "string",
|
|
4043
4043
|
bit: "string",
|
|
4044
4044
|
varbit: "string",
|
|
4045
|
-
int4range: "
|
|
4046
|
-
int8range: "
|
|
4047
|
-
numrange: "
|
|
4048
|
-
daterange: "
|
|
4049
|
-
tsrange: "
|
|
4050
|
-
tstzrange: "
|
|
4045
|
+
int4range: "string",
|
|
4046
|
+
int8range: "string",
|
|
4047
|
+
numrange: "string",
|
|
4048
|
+
daterange: "string",
|
|
4049
|
+
tsrange: "string",
|
|
4050
|
+
tstzrange: "string"
|
|
4051
4051
|
};
|
|
4052
4052
|
function emitCollectionTypes(collection, tsTypeOf = (t) => CORE_FIELD_TS_TYPES[t]) {
|
|
4053
4053
|
const typeName = collection.name.charAt(0).toUpperCase() + collection.name.slice(1);
|
|
@@ -4146,7 +4146,7 @@ import { join as join10 } from "path";
|
|
|
4146
4146
|
|
|
4147
4147
|
// ../sdk/dist/validate/migration-parse.js
|
|
4148
4148
|
function parseMigrationSql(raw) {
|
|
4149
|
-
const downIdx = raw.search(/^--\s*DOWN\
|
|
4149
|
+
const downIdx = raw.search(/^--\s*DOWN\s*$/im);
|
|
4150
4150
|
if (downIdx < 0) {
|
|
4151
4151
|
return { up: raw.trim(), down: null };
|
|
4152
4152
|
}
|
|
@@ -4374,6 +4374,7 @@ var SHARED_MESSAGE_KEYS = new Set([
|
|
|
4374
4374
|
]);
|
|
4375
4375
|
|
|
4376
4376
|
// ../sdk/dist/validate/index.js
|
|
4377
|
+
var CREDENTIAL_HEADERS = ["authorization", "cookie", "proxy-authorization", "x-api-key"];
|
|
4377
4378
|
var SEMVER_RE = /^\d+\.\d+\.\d+(?:-[A-Za-z0-9.-]+)?$/;
|
|
4378
4379
|
var KNOWN_CATEGORIES = new Set([
|
|
4379
4380
|
"auth",
|
|
@@ -4464,13 +4465,38 @@ function validateManifest(input) {
|
|
|
4464
4465
|
}
|
|
4465
4466
|
}
|
|
4466
4467
|
if (obj.apiKeyRoutes !== undefined) {
|
|
4467
|
-
const routes = Array.isArray(obj.apiKeyRoutes) ? obj.apiKeyRoutes : [
|
|
4468
|
+
const routes = Array.isArray(obj.apiKeyRoutes) ? obj.apiKeyRoutes : [];
|
|
4469
|
+
if (!Array.isArray(obj.apiKeyRoutes)) {
|
|
4470
|
+
out.push(err("MANIFEST_BAD_API_KEY_ROUTE", '"apiKeyRoutes" must be an array'));
|
|
4471
|
+
}
|
|
4468
4472
|
for (const r of routes) {
|
|
4469
4473
|
if (typeof r !== "string" || !/^(GET|POST|PUT|PATCH|DELETE) \S+$/.test(r)) {
|
|
4470
4474
|
out.push(err("MANIFEST_BAD_API_KEY_ROUTE", `apiKeyRoutes entry ${JSON.stringify(r)} must be "<GET|POST|PUT|PATCH|DELETE> <pattern>"`));
|
|
4471
4475
|
}
|
|
4472
4476
|
}
|
|
4473
4477
|
}
|
|
4478
|
+
if (obj.forwardCredentials !== undefined) {
|
|
4479
|
+
const fwd = obj.forwardCredentials;
|
|
4480
|
+
const publicRoutes = Array.isArray(obj.publicRoutes) ? obj.publicRoutes : [];
|
|
4481
|
+
if (!fwd || typeof fwd !== "object" || Array.isArray(fwd)) {
|
|
4482
|
+
out.push(err("MANIFEST_BAD_FORWARD_CREDENTIALS", '"forwardCredentials" must map a route to headers'));
|
|
4483
|
+
} else {
|
|
4484
|
+
for (const [route, names] of Object.entries(fwd)) {
|
|
4485
|
+
if (!publicRoutes.includes(route)) {
|
|
4486
|
+
out.push(err("MANIFEST_BAD_FORWARD_CREDENTIALS", `forwardCredentials names "${route}", which is not a publicRoutes entry`));
|
|
4487
|
+
}
|
|
4488
|
+
if (!Array.isArray(names)) {
|
|
4489
|
+
out.push(err("MANIFEST_BAD_FORWARD_CREDENTIALS", `forwardCredentials "${route}" must be an array of header names`));
|
|
4490
|
+
continue;
|
|
4491
|
+
}
|
|
4492
|
+
for (const n of names) {
|
|
4493
|
+
if (typeof n !== "string" || !CREDENTIAL_HEADERS.includes(n)) {
|
|
4494
|
+
out.push(err("MANIFEST_BAD_FORWARD_CREDENTIALS", `forwardCredentials "${route}": ${JSON.stringify(n)} is not one of ${CREDENTIAL_HEADERS.join(", ")}`));
|
|
4495
|
+
}
|
|
4496
|
+
}
|
|
4497
|
+
}
|
|
4498
|
+
}
|
|
4499
|
+
}
|
|
4474
4500
|
if (typeof obj.category === "string" && !KNOWN_CATEGORIES.has(obj.category)) {
|
|
4475
4501
|
out.push(warn("MANIFEST_UNKNOWN_CATEGORY", `category "${obj.category}" isn't in the known set \u2014 typo? Known: ${[...KNOWN_CATEGORIES].sort().join(", ")}`));
|
|
4476
4502
|
}
|
|
@@ -6041,7 +6067,7 @@ function typesFromFiles(collection, dir, outputPath) {
|
|
|
6041
6067
|
|
|
6042
6068
|
// src/commands/schema.ts
|
|
6043
6069
|
import { existsSync as existsSync16, mkdirSync as mkdirSync6, readdirSync as readdirSync7, readFileSync as readFileSync8, rmSync, writeFileSync as writeFileSync6 } from "fs";
|
|
6044
|
-
import { dirname as dirname5, join as join15 } from "path";
|
|
6070
|
+
import { dirname as dirname5, join as join15, resolve as resolve4, sep } from "path";
|
|
6045
6071
|
import { createInterface as createInterface2 } from "readline";
|
|
6046
6072
|
async function schemaPullCommand(opts) {
|
|
6047
6073
|
const dir = opts.dir || "./schema";
|
|
@@ -6057,8 +6083,17 @@ async function schemaPullCommand(opts) {
|
|
|
6057
6083
|
process.exit(1);
|
|
6058
6084
|
}
|
|
6059
6085
|
const { files } = await res.json();
|
|
6060
|
-
|
|
6061
|
-
|
|
6086
|
+
const root = resolve4(dir);
|
|
6087
|
+
const inside = root.endsWith(sep) ? root : root + sep;
|
|
6088
|
+
const writes = Object.entries(files).map(([path, content]) => {
|
|
6089
|
+
const target = resolve4(root, path);
|
|
6090
|
+
if (!target.startsWith(inside)) {
|
|
6091
|
+
console.error(`Schema export named a path outside ${dir}: ${path}`);
|
|
6092
|
+
process.exit(1);
|
|
6093
|
+
}
|
|
6094
|
+
return [target, content];
|
|
6095
|
+
});
|
|
6096
|
+
for (const [target, content] of writes) {
|
|
6062
6097
|
mkdirSync6(dirname5(target), { recursive: true });
|
|
6063
6098
|
writeFileSync6(target, content);
|
|
6064
6099
|
}
|
|
@@ -6090,18 +6125,24 @@ function readSchemaDir(dir) {
|
|
|
6090
6125
|
}
|
|
6091
6126
|
return files;
|
|
6092
6127
|
}
|
|
6093
|
-
async function postSchema(engineUrl, route, files, allowDestructive = false) {
|
|
6128
|
+
async function postSchema(engineUrl, route, files, allowDestructive = false, adoptRules = false) {
|
|
6094
6129
|
const res = await fetch(`${engineUrl}/api/admin/schema/${route}`, {
|
|
6095
6130
|
method: "POST",
|
|
6096
6131
|
headers: {
|
|
6097
6132
|
Authorization: `Bearer ${process.env.ZVELTIO_API_KEY || ""}`,
|
|
6098
6133
|
"Content-Type": "application/json"
|
|
6099
6134
|
},
|
|
6100
|
-
body: JSON.stringify({ files, allowDestructive })
|
|
6135
|
+
body: JSON.stringify({ files, allowDestructive, ...adoptRules ? { adopt_rules: true } : {} })
|
|
6101
6136
|
});
|
|
6102
6137
|
if (!res.ok) {
|
|
6103
6138
|
const body = await res.json().catch(() => null);
|
|
6104
6139
|
console.error(`Schema ${route} failed: ${res.status} ${body?.detail ?? res.statusText}`);
|
|
6140
|
+
if (body?.code === "existing_rules") {
|
|
6141
|
+
for (const r of body.errors ?? []) {
|
|
6142
|
+
console.error(` ${r.object}: ${r.subject} ${r.action} in ${r.domain}`);
|
|
6143
|
+
}
|
|
6144
|
+
console.error(" Delete these rules, or rerun with --adopt-rules to keep them on the new collection.");
|
|
6145
|
+
}
|
|
6105
6146
|
if (res.status === 401 || res.status === 403) {
|
|
6106
6147
|
console.error(" Set ZVELTIO_API_KEY to a key of an instance admin.");
|
|
6107
6148
|
}
|
|
@@ -6146,15 +6187,15 @@ The plan has destructive steps; nothing was changed. Rerun with --allow-destruct
|
|
|
6146
6187
|
}
|
|
6147
6188
|
if (!opts.yes) {
|
|
6148
6189
|
const rl2 = createInterface2({ input: process.stdin, output: process.stdout });
|
|
6149
|
-
const answer = await new Promise((
|
|
6150
|
-
Apply these changes? Type "yes" to continue: `,
|
|
6190
|
+
const answer = await new Promise((resolve5) => rl2.question(`
|
|
6191
|
+
Apply these changes? Type "yes" to continue: `, resolve5));
|
|
6151
6192
|
rl2.close();
|
|
6152
6193
|
if (answer.trim().toLowerCase() !== "yes") {
|
|
6153
6194
|
console.log("Cancelled; nothing was changed.");
|
|
6154
6195
|
return;
|
|
6155
6196
|
}
|
|
6156
6197
|
}
|
|
6157
|
-
const applied = await postSchema(engineUrl, "apply", files, opts.allowDestructive);
|
|
6198
|
+
const applied = await postSchema(engineUrl, "apply", files, opts.allowDestructive, opts.adoptRules);
|
|
6158
6199
|
console.log(`Applied ${applied.length} change(s).`);
|
|
6159
6200
|
}
|
|
6160
6201
|
|
|
@@ -6171,7 +6212,7 @@ async function installCommand(name, opts) {
|
|
|
6171
6212
|
await installFromPath(name, opts.path, engineUrl, opts.force ?? false);
|
|
6172
6213
|
return;
|
|
6173
6214
|
}
|
|
6174
|
-
await installFromCatalog(name, engineUrl);
|
|
6215
|
+
await installFromCatalog(name, engineUrl, opts.approveForwardCredentials ?? false);
|
|
6175
6216
|
}
|
|
6176
6217
|
async function installFromPath(name, sourcePath, engineUrl, force) {
|
|
6177
6218
|
if (!existsSync17(join16(sourcePath, "manifest.json"))) {
|
|
@@ -6233,7 +6274,7 @@ async function installFromPath(name, sourcePath, engineUrl, force) {
|
|
|
6233
6274
|
console.log(` ZVELTIO_EXTENSIONS=...,${category}/${extName}
|
|
6234
6275
|
`);
|
|
6235
6276
|
}
|
|
6236
|
-
async function installFromCatalog(name, engineUrl) {
|
|
6277
|
+
async function installFromCatalog(name, engineUrl, approveForward) {
|
|
6237
6278
|
console.log(` Checking engine catalog at ${engineUrl}...`);
|
|
6238
6279
|
let catalogRes;
|
|
6239
6280
|
try {
|
|
@@ -6284,11 +6325,30 @@ Available extensions:`);
|
|
|
6284
6325
|
\u2705 Extension "${entry.displayName || entry.name}" is already active.`);
|
|
6285
6326
|
return;
|
|
6286
6327
|
}
|
|
6328
|
+
const forward = entry.forwarded_credentials ?? {};
|
|
6329
|
+
const forwardPairs = Object.entries(forward).flatMap(([route, headers]) => headers.map((h) => `${route}: ${h}`));
|
|
6330
|
+
const approval = approveForward ? { forward_credentials: forward } : undefined;
|
|
6287
6331
|
if (entry.is_installed) {
|
|
6288
6332
|
console.log(` Already installed. Enabling...`);
|
|
6333
|
+
if (approval && forwardPairs.length > 0) {
|
|
6334
|
+
const res = await fetch(`${engineUrl}/api/marketplace/${entry.name}/approve-forward-credentials`, {
|
|
6335
|
+
method: "POST",
|
|
6336
|
+
headers: { "Content-Type": "application/json" },
|
|
6337
|
+
body: JSON.stringify(approval)
|
|
6338
|
+
}).catch(() => null);
|
|
6339
|
+
if (!res?.ok) {
|
|
6340
|
+
console.error(`\u274C Credential forwarding approval failed: HTTP ${res?.status ?? "unreachable"}`);
|
|
6341
|
+
process.exit(1);
|
|
6342
|
+
}
|
|
6343
|
+
console.log(` \u2713 Credential forwarding approved (${forwardPairs.join(", ")})`);
|
|
6344
|
+
}
|
|
6289
6345
|
} else {
|
|
6290
6346
|
const installRes = await fetch(`${engineUrl}/api/marketplace/${entry.name}/install`, {
|
|
6291
|
-
method: "POST"
|
|
6347
|
+
method: "POST",
|
|
6348
|
+
...approval && {
|
|
6349
|
+
headers: { "Content-Type": "application/json" },
|
|
6350
|
+
body: JSON.stringify(approval)
|
|
6351
|
+
}
|
|
6292
6352
|
}).catch(() => null);
|
|
6293
6353
|
if (!installRes?.ok) {
|
|
6294
6354
|
const err2 = await installRes?.json().catch(() => ({}));
|
|
@@ -6302,6 +6362,11 @@ Available extensions:`);
|
|
|
6302
6362
|
console.log(` \u2713 Marked as installed`);
|
|
6303
6363
|
}
|
|
6304
6364
|
}
|
|
6365
|
+
if (forwardPairs.length > 0 && !approval) {
|
|
6366
|
+
console.log(` \u26A0\uFE0F Asks for the caller's credentials on: ${forwardPairs.join(", ")}`);
|
|
6367
|
+
console.log(` Not forwarded until approved: re-run with --approve-forward-credentials,`);
|
|
6368
|
+
console.log(` or approve it in Studio \u2192 Marketplace.`);
|
|
6369
|
+
}
|
|
6305
6370
|
const enableRes = await fetch(`${engineUrl}/api/marketplace/${entry.name}/enable`, {
|
|
6306
6371
|
method: "POST"
|
|
6307
6372
|
}).catch(() => null);
|
|
@@ -6345,12 +6410,12 @@ async function activateViaApi(name, category, engineUrl) {
|
|
|
6345
6410
|
// src/commands/create-god.ts
|
|
6346
6411
|
import { createInterface as createInterface3 } from "readline";
|
|
6347
6412
|
async function prompt(rl2, question) {
|
|
6348
|
-
return new Promise((
|
|
6349
|
-
rl2.question(question,
|
|
6413
|
+
return new Promise((resolve5) => {
|
|
6414
|
+
rl2.question(question, resolve5);
|
|
6350
6415
|
});
|
|
6351
6416
|
}
|
|
6352
6417
|
async function promptHidden(question) {
|
|
6353
|
-
return new Promise((
|
|
6418
|
+
return new Promise((resolve5) => {
|
|
6354
6419
|
process.stdout.write(question);
|
|
6355
6420
|
const stdin = process.stdin;
|
|
6356
6421
|
const wasPaused = stdin.isPaused();
|
|
@@ -6369,7 +6434,7 @@ async function promptHidden(question) {
|
|
|
6369
6434
|
stdin.off("data", handler);
|
|
6370
6435
|
process.stdout.write(`
|
|
6371
6436
|
`);
|
|
6372
|
-
|
|
6437
|
+
resolve5(value);
|
|
6373
6438
|
} else if (char === "\x7F") {
|
|
6374
6439
|
if (value.length > 0)
|
|
6375
6440
|
value = value.slice(0, -1);
|
|
@@ -6622,9 +6687,9 @@ var rollbackCommand = new Command("rollback").description("Rollback database mig
|
|
|
6622
6687
|
input: process.stdin,
|
|
6623
6688
|
output: process.stdout
|
|
6624
6689
|
});
|
|
6625
|
-
const answer = await new Promise((
|
|
6690
|
+
const answer = await new Promise((resolve5) => {
|
|
6626
6691
|
rl2.question(`
|
|
6627
|
-
\u26A0\uFE0F This will rollback schema changes. Type "yes" to continue: `,
|
|
6692
|
+
\u26A0\uFE0F This will rollback schema changes. Type "yes" to continue: `, resolve5);
|
|
6628
6693
|
});
|
|
6629
6694
|
rl2.close();
|
|
6630
6695
|
if (answer.trim().toLowerCase() !== "yes") {
|
|
@@ -6941,8 +7006,8 @@ function compareVersions(a, b) {
|
|
|
6941
7006
|
return 0;
|
|
6942
7007
|
}
|
|
6943
7008
|
async function readLine() {
|
|
6944
|
-
return new Promise((
|
|
6945
|
-
process.stdin.once("data", (data) =>
|
|
7009
|
+
return new Promise((resolve5) => {
|
|
7010
|
+
process.stdin.once("data", (data) => resolve5(data.toString().trim()));
|
|
6946
7011
|
});
|
|
6947
7012
|
}
|
|
6948
7013
|
|
|
@@ -7074,7 +7139,7 @@ async function getLocalVersion() {
|
|
|
7074
7139
|
// package.json
|
|
7075
7140
|
var package_default = {
|
|
7076
7141
|
name: "@zveltio/cli",
|
|
7077
|
-
version: "3.0.0-beta.
|
|
7142
|
+
version: "3.0.0-beta.80",
|
|
7078
7143
|
type: "module",
|
|
7079
7144
|
bin: {
|
|
7080
7145
|
zveltio: "./dist/index.js"
|
|
@@ -7089,7 +7154,7 @@ var package_default = {
|
|
|
7089
7154
|
dev: "bun run --watch src/index.ts"
|
|
7090
7155
|
},
|
|
7091
7156
|
dependencies: {
|
|
7092
|
-
"@zveltio/sdk": "3.0.0-beta.
|
|
7157
|
+
"@zveltio/sdk": "3.0.0-beta.80",
|
|
7093
7158
|
commander: "^12.1.0"
|
|
7094
7159
|
},
|
|
7095
7160
|
devDependencies: {
|
|
@@ -7121,11 +7186,11 @@ program2.command("generate-types [collection]").description("Generate TypeScript
|
|
|
7121
7186
|
var schema = program2.command("schema").description("Schema as code: the live schema as reviewable JSON files");
|
|
7122
7187
|
schema.command("pull").description("Write the live schema to ./schema (collections, roles)").option("--dir <path>", "Schema directory", "./schema").option("--url <url>", "Engine URL (env: ZVELTIO_URL)").action(schemaPullCommand);
|
|
7123
7188
|
schema.command("diff").description("Print what apply would change to match ./schema; exits 1 on drift").option("--dir <path>", "Schema directory", "./schema").option("--url <url>", "Engine URL (env: ZVELTIO_URL)").action(schemaDiffCommand);
|
|
7124
|
-
schema.command("apply").description("Make the instance match ./schema; shows the plan and asks first").option("--dir <path>", "Schema directory", "./schema").option("--url <url>", "Engine URL (env: ZVELTIO_URL)").option("--yes", "Apply without asking").option("--allow-destructive", "Run drops and type changes that a migration in migrations/ names").action(schemaApplyCommand);
|
|
7125
|
-
program2.command("install <name>").description("Install a Zveltio extension from marketplace or local path").option("--path <path>", "Install from local directory (offline)").option("--url <url>", "Engine URL for marketplace install", "http://localhost:3000").option("--force", "Overwrite existing extension (local install only)").action((name, opts) => installCommand(name, opts));
|
|
7189
|
+
schema.command("apply").description("Make the instance match ./schema; shows the plan and asks first").option("--dir <path>", "Schema directory", "./schema").option("--url <url>", "Engine URL (env: ZVELTIO_URL)").option("--yes", "Apply without asking").option("--allow-destructive", "Run drops and type changes that a migration in migrations/ names").option("--adopt-rules", "Create collections even when access rules already name them").action(schemaApplyCommand);
|
|
7190
|
+
program2.command("install <name>").description("Install a Zveltio extension from marketplace or local path").option("--path <path>", "Install from local directory (offline)").option("--url <url>", "Engine URL for marketplace install", "http://localhost:3000").option("--force", "Overwrite existing extension (local install only)").option("--approve-forward-credentials", "Approve the caller-credential forwarding the extension's manifest declares").action((name, opts) => installCommand(name, opts));
|
|
7126
7191
|
var extensions = program2.command("extensions").description("Manage Zveltio extensions");
|
|
7127
7192
|
extensions.command("list").description("List all available and installed extensions").option("--url <url>", "Engine URL", "http://localhost:3000").option("--category <category>", "Filter by category").option("--json", "Output as JSON").action((opts) => extensionsListCommand(opts));
|
|
7128
|
-
extensions.command("install <name>").description("Install an extension from the marketplace or local path").option("--path <path>", "Install from local directory (offline)").option("--url <url>", "Engine URL", "http://localhost:3000").option("--force", "Overwrite existing extension (local install only)").action((name, opts) => installCommand(name, opts));
|
|
7193
|
+
extensions.command("install <name>").description("Install an extension from the marketplace or local path").option("--path <path>", "Install from local directory (offline)").option("--url <url>", "Engine URL", "http://localhost:3000").option("--force", "Overwrite existing extension (local install only)").option("--approve-forward-credentials", "Approve the caller-credential forwarding the extension's manifest declares").action((name, opts) => installCommand(name, opts));
|
|
7129
7194
|
extensions.command("enable <name>").description("Enable an installed extension").option("--url <url>", "Engine URL", "http://localhost:3000").action(async (name, opts) => {
|
|
7130
7195
|
const url = opts.url || "http://localhost:3000";
|
|
7131
7196
|
const res = await fetch(`${url}/api/marketplace/${name}/enable`, { method: "POST" }).catch(() => null);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zveltio/cli",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.80",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"zveltio": "./dist/index.js"
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"dev": "bun run --watch src/index.ts"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@zveltio/sdk": "3.0.0-beta.
|
|
18
|
+
"@zveltio/sdk": "3.0.0-beta.80",
|
|
19
19
|
"commander": "^12.1.0"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|