@zveltio/cli 3.0.0-beta.79 → 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 +79 -34
- 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);
|
|
@@ -4465,7 +4465,10 @@ function validateManifest(input) {
|
|
|
4465
4465
|
}
|
|
4466
4466
|
}
|
|
4467
4467
|
if (obj.apiKeyRoutes !== undefined) {
|
|
4468
|
-
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
|
+
}
|
|
4469
4472
|
for (const r of routes) {
|
|
4470
4473
|
if (typeof r !== "string" || !/^(GET|POST|PUT|PATCH|DELETE) \S+$/.test(r)) {
|
|
4471
4474
|
out.push(err("MANIFEST_BAD_API_KEY_ROUTE", `apiKeyRoutes entry ${JSON.stringify(r)} must be "<GET|POST|PUT|PATCH|DELETE> <pattern>"`));
|
|
@@ -4482,8 +4485,11 @@ function validateManifest(input) {
|
|
|
4482
4485
|
if (!publicRoutes.includes(route)) {
|
|
4483
4486
|
out.push(err("MANIFEST_BAD_FORWARD_CREDENTIALS", `forwardCredentials names "${route}", which is not a publicRoutes entry`));
|
|
4484
4487
|
}
|
|
4485
|
-
|
|
4486
|
-
|
|
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) {
|
|
4487
4493
|
if (typeof n !== "string" || !CREDENTIAL_HEADERS.includes(n)) {
|
|
4488
4494
|
out.push(err("MANIFEST_BAD_FORWARD_CREDENTIALS", `forwardCredentials "${route}": ${JSON.stringify(n)} is not one of ${CREDENTIAL_HEADERS.join(", ")}`));
|
|
4489
4495
|
}
|
|
@@ -6061,7 +6067,7 @@ function typesFromFiles(collection, dir, outputPath) {
|
|
|
6061
6067
|
|
|
6062
6068
|
// src/commands/schema.ts
|
|
6063
6069
|
import { existsSync as existsSync16, mkdirSync as mkdirSync6, readdirSync as readdirSync7, readFileSync as readFileSync8, rmSync, writeFileSync as writeFileSync6 } from "fs";
|
|
6064
|
-
import { dirname as dirname5, join as join15 } from "path";
|
|
6070
|
+
import { dirname as dirname5, join as join15, resolve as resolve4, sep } from "path";
|
|
6065
6071
|
import { createInterface as createInterface2 } from "readline";
|
|
6066
6072
|
async function schemaPullCommand(opts) {
|
|
6067
6073
|
const dir = opts.dir || "./schema";
|
|
@@ -6077,8 +6083,17 @@ async function schemaPullCommand(opts) {
|
|
|
6077
6083
|
process.exit(1);
|
|
6078
6084
|
}
|
|
6079
6085
|
const { files } = await res.json();
|
|
6080
|
-
|
|
6081
|
-
|
|
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) {
|
|
6082
6097
|
mkdirSync6(dirname5(target), { recursive: true });
|
|
6083
6098
|
writeFileSync6(target, content);
|
|
6084
6099
|
}
|
|
@@ -6110,18 +6125,24 @@ function readSchemaDir(dir) {
|
|
|
6110
6125
|
}
|
|
6111
6126
|
return files;
|
|
6112
6127
|
}
|
|
6113
|
-
async function postSchema(engineUrl, route, files, allowDestructive = false) {
|
|
6128
|
+
async function postSchema(engineUrl, route, files, allowDestructive = false, adoptRules = false) {
|
|
6114
6129
|
const res = await fetch(`${engineUrl}/api/admin/schema/${route}`, {
|
|
6115
6130
|
method: "POST",
|
|
6116
6131
|
headers: {
|
|
6117
6132
|
Authorization: `Bearer ${process.env.ZVELTIO_API_KEY || ""}`,
|
|
6118
6133
|
"Content-Type": "application/json"
|
|
6119
6134
|
},
|
|
6120
|
-
body: JSON.stringify({ files, allowDestructive })
|
|
6135
|
+
body: JSON.stringify({ files, allowDestructive, ...adoptRules ? { adopt_rules: true } : {} })
|
|
6121
6136
|
});
|
|
6122
6137
|
if (!res.ok) {
|
|
6123
6138
|
const body = await res.json().catch(() => null);
|
|
6124
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
|
+
}
|
|
6125
6146
|
if (res.status === 401 || res.status === 403) {
|
|
6126
6147
|
console.error(" Set ZVELTIO_API_KEY to a key of an instance admin.");
|
|
6127
6148
|
}
|
|
@@ -6166,15 +6187,15 @@ The plan has destructive steps; nothing was changed. Rerun with --allow-destruct
|
|
|
6166
6187
|
}
|
|
6167
6188
|
if (!opts.yes) {
|
|
6168
6189
|
const rl2 = createInterface2({ input: process.stdin, output: process.stdout });
|
|
6169
|
-
const answer = await new Promise((
|
|
6170
|
-
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));
|
|
6171
6192
|
rl2.close();
|
|
6172
6193
|
if (answer.trim().toLowerCase() !== "yes") {
|
|
6173
6194
|
console.log("Cancelled; nothing was changed.");
|
|
6174
6195
|
return;
|
|
6175
6196
|
}
|
|
6176
6197
|
}
|
|
6177
|
-
const applied = await postSchema(engineUrl, "apply", files, opts.allowDestructive);
|
|
6198
|
+
const applied = await postSchema(engineUrl, "apply", files, opts.allowDestructive, opts.adoptRules);
|
|
6178
6199
|
console.log(`Applied ${applied.length} change(s).`);
|
|
6179
6200
|
}
|
|
6180
6201
|
|
|
@@ -6191,7 +6212,7 @@ async function installCommand(name, opts) {
|
|
|
6191
6212
|
await installFromPath(name, opts.path, engineUrl, opts.force ?? false);
|
|
6192
6213
|
return;
|
|
6193
6214
|
}
|
|
6194
|
-
await installFromCatalog(name, engineUrl);
|
|
6215
|
+
await installFromCatalog(name, engineUrl, opts.approveForwardCredentials ?? false);
|
|
6195
6216
|
}
|
|
6196
6217
|
async function installFromPath(name, sourcePath, engineUrl, force) {
|
|
6197
6218
|
if (!existsSync17(join16(sourcePath, "manifest.json"))) {
|
|
@@ -6253,7 +6274,7 @@ async function installFromPath(name, sourcePath, engineUrl, force) {
|
|
|
6253
6274
|
console.log(` ZVELTIO_EXTENSIONS=...,${category}/${extName}
|
|
6254
6275
|
`);
|
|
6255
6276
|
}
|
|
6256
|
-
async function installFromCatalog(name, engineUrl) {
|
|
6277
|
+
async function installFromCatalog(name, engineUrl, approveForward) {
|
|
6257
6278
|
console.log(` Checking engine catalog at ${engineUrl}...`);
|
|
6258
6279
|
let catalogRes;
|
|
6259
6280
|
try {
|
|
@@ -6304,11 +6325,30 @@ Available extensions:`);
|
|
|
6304
6325
|
\u2705 Extension "${entry.displayName || entry.name}" is already active.`);
|
|
6305
6326
|
return;
|
|
6306
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;
|
|
6307
6331
|
if (entry.is_installed) {
|
|
6308
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
|
+
}
|
|
6309
6345
|
} else {
|
|
6310
6346
|
const installRes = await fetch(`${engineUrl}/api/marketplace/${entry.name}/install`, {
|
|
6311
|
-
method: "POST"
|
|
6347
|
+
method: "POST",
|
|
6348
|
+
...approval && {
|
|
6349
|
+
headers: { "Content-Type": "application/json" },
|
|
6350
|
+
body: JSON.stringify(approval)
|
|
6351
|
+
}
|
|
6312
6352
|
}).catch(() => null);
|
|
6313
6353
|
if (!installRes?.ok) {
|
|
6314
6354
|
const err2 = await installRes?.json().catch(() => ({}));
|
|
@@ -6322,6 +6362,11 @@ Available extensions:`);
|
|
|
6322
6362
|
console.log(` \u2713 Marked as installed`);
|
|
6323
6363
|
}
|
|
6324
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
|
+
}
|
|
6325
6370
|
const enableRes = await fetch(`${engineUrl}/api/marketplace/${entry.name}/enable`, {
|
|
6326
6371
|
method: "POST"
|
|
6327
6372
|
}).catch(() => null);
|
|
@@ -6365,12 +6410,12 @@ async function activateViaApi(name, category, engineUrl) {
|
|
|
6365
6410
|
// src/commands/create-god.ts
|
|
6366
6411
|
import { createInterface as createInterface3 } from "readline";
|
|
6367
6412
|
async function prompt(rl2, question) {
|
|
6368
|
-
return new Promise((
|
|
6369
|
-
rl2.question(question,
|
|
6413
|
+
return new Promise((resolve5) => {
|
|
6414
|
+
rl2.question(question, resolve5);
|
|
6370
6415
|
});
|
|
6371
6416
|
}
|
|
6372
6417
|
async function promptHidden(question) {
|
|
6373
|
-
return new Promise((
|
|
6418
|
+
return new Promise((resolve5) => {
|
|
6374
6419
|
process.stdout.write(question);
|
|
6375
6420
|
const stdin = process.stdin;
|
|
6376
6421
|
const wasPaused = stdin.isPaused();
|
|
@@ -6389,7 +6434,7 @@ async function promptHidden(question) {
|
|
|
6389
6434
|
stdin.off("data", handler);
|
|
6390
6435
|
process.stdout.write(`
|
|
6391
6436
|
`);
|
|
6392
|
-
|
|
6437
|
+
resolve5(value);
|
|
6393
6438
|
} else if (char === "\x7F") {
|
|
6394
6439
|
if (value.length > 0)
|
|
6395
6440
|
value = value.slice(0, -1);
|
|
@@ -6642,9 +6687,9 @@ var rollbackCommand = new Command("rollback").description("Rollback database mig
|
|
|
6642
6687
|
input: process.stdin,
|
|
6643
6688
|
output: process.stdout
|
|
6644
6689
|
});
|
|
6645
|
-
const answer = await new Promise((
|
|
6690
|
+
const answer = await new Promise((resolve5) => {
|
|
6646
6691
|
rl2.question(`
|
|
6647
|
-
\u26A0\uFE0F This will rollback schema changes. Type "yes" to continue: `,
|
|
6692
|
+
\u26A0\uFE0F This will rollback schema changes. Type "yes" to continue: `, resolve5);
|
|
6648
6693
|
});
|
|
6649
6694
|
rl2.close();
|
|
6650
6695
|
if (answer.trim().toLowerCase() !== "yes") {
|
|
@@ -6961,8 +7006,8 @@ function compareVersions(a, b) {
|
|
|
6961
7006
|
return 0;
|
|
6962
7007
|
}
|
|
6963
7008
|
async function readLine() {
|
|
6964
|
-
return new Promise((
|
|
6965
|
-
process.stdin.once("data", (data) =>
|
|
7009
|
+
return new Promise((resolve5) => {
|
|
7010
|
+
process.stdin.once("data", (data) => resolve5(data.toString().trim()));
|
|
6966
7011
|
});
|
|
6967
7012
|
}
|
|
6968
7013
|
|
|
@@ -7094,7 +7139,7 @@ async function getLocalVersion() {
|
|
|
7094
7139
|
// package.json
|
|
7095
7140
|
var package_default = {
|
|
7096
7141
|
name: "@zveltio/cli",
|
|
7097
|
-
version: "3.0.0-beta.
|
|
7142
|
+
version: "3.0.0-beta.80",
|
|
7098
7143
|
type: "module",
|
|
7099
7144
|
bin: {
|
|
7100
7145
|
zveltio: "./dist/index.js"
|
|
@@ -7109,7 +7154,7 @@ var package_default = {
|
|
|
7109
7154
|
dev: "bun run --watch src/index.ts"
|
|
7110
7155
|
},
|
|
7111
7156
|
dependencies: {
|
|
7112
|
-
"@zveltio/sdk": "3.0.0-beta.
|
|
7157
|
+
"@zveltio/sdk": "3.0.0-beta.80",
|
|
7113
7158
|
commander: "^12.1.0"
|
|
7114
7159
|
},
|
|
7115
7160
|
devDependencies: {
|
|
@@ -7141,11 +7186,11 @@ program2.command("generate-types [collection]").description("Generate TypeScript
|
|
|
7141
7186
|
var schema = program2.command("schema").description("Schema as code: the live schema as reviewable JSON files");
|
|
7142
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);
|
|
7143
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);
|
|
7144
|
-
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);
|
|
7145
|
-
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));
|
|
7146
7191
|
var extensions = program2.command("extensions").description("Manage Zveltio extensions");
|
|
7147
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));
|
|
7148
|
-
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));
|
|
7149
7194
|
extensions.command("enable <name>").description("Enable an installed extension").option("--url <url>", "Engine URL", "http://localhost:3000").action(async (name, opts) => {
|
|
7150
7195
|
const url = opts.url || "http://localhost:3000";
|
|
7151
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": {
|