@plenary/cli 0.6.0 → 1.0.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/README.md +1 -1
- package/dist/index.js +51 -22
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -133,7 +133,7 @@ function resolveContext(opts, io) {
|
|
|
133
133
|
return {
|
|
134
134
|
io,
|
|
135
135
|
baseUrl: baseUrl ? baseUrl.replace(/\/+$/, "") : void 0,
|
|
136
|
-
apiKey: opts.apiKey ?? env.
|
|
136
|
+
apiKey: opts.apiKey ?? env.PLENARY_CLI_API_KEY,
|
|
137
137
|
siteKey: opts.site ?? env.PLENARY_SITE_KEY ?? file.siteKey,
|
|
138
138
|
locale: opts.locale ?? env.PLENARY_LOCALE ?? file.locale,
|
|
139
139
|
metadataDir: env.PLENARY_METADATA_DIR ?? file.metadataDir ?? DEFAULT_METADATA_DIR,
|
|
@@ -240,7 +240,7 @@ async function credentialHeaders(ctx, mode) {
|
|
|
240
240
|
const token = await sessionAccessToken(ctx);
|
|
241
241
|
if (token) return { Authorization: `Bearer ${token}` };
|
|
242
242
|
if (mode === "required") {
|
|
243
|
-
throw usageError("no credential: pass --api-key, set
|
|
243
|
+
throw usageError("no credential: pass --api-key, set PLENARY_CLI_API_KEY, or run `plenary login`");
|
|
244
244
|
}
|
|
245
245
|
return {};
|
|
246
246
|
}
|
|
@@ -484,7 +484,7 @@ function registerAdmin(program, io) {
|
|
|
484
484
|
const res = await request(ctx, "GET", `api-keys/${encodeURIComponent(id)}`, { auth: "session" });
|
|
485
485
|
io.stdout.write(toJson(res.data) + "\n");
|
|
486
486
|
});
|
|
487
|
-
keys.command("create").description("Create an API key; the secret is printed once, alone on stdout").requiredOption("-n, --name <name>").option("-t, --type <private|public>", "key type", "private").option("--description <text>").option("-g, --grant <spec>", "private keys: key[,site=<key>][,model=<uuid>] (repeatable)", collect, []).option("--site <key>", "
|
|
487
|
+
keys.command("create").description("Create an API key; the secret is printed once, alone on stdout").requiredOption("-n, --name <name>").option("-t, --type <private|public>", "key type", "private").option("--description <text>").option("-g, --grant <spec>", "private keys: key[,site=<key>][,model=<uuid>] (repeatable)", collect, []).option("--site <key>", "the site the key belongs to: a public key reads it, a private key's grants are held to it").option("--expires <iso>", "expiry timestamp").option("--origin <origin>", "an allowed browser origin (repeatable)", collect, []).option("--rate-limit <n>", "requests per minute, 0 = unlimited", "0").option("--include-drafts", "public keys: read drafts too").action(
|
|
488
488
|
async (flags, cmd) => {
|
|
489
489
|
const ctx = resolveContext(cmd.optsWithGlobals(), io);
|
|
490
490
|
if (flags.type !== "private" && flags.type !== "public") throw usageError("--type must be private or public");
|
|
@@ -495,7 +495,7 @@ function registerAdmin(program, io) {
|
|
|
495
495
|
is_active: true,
|
|
496
496
|
expires_at: flags.expires ?? null,
|
|
497
497
|
grants: flags.grant.map(parseGrant),
|
|
498
|
-
|
|
498
|
+
...flags.site ? { site_key: flags.site } : {},
|
|
499
499
|
allowed_origins: flags.origin,
|
|
500
500
|
rate_limit_per_minute: Number(flags.rateLimit),
|
|
501
501
|
include_drafts: Boolean(flags.includeDrafts)
|
|
@@ -686,17 +686,20 @@ $XDG_CONFIG_HOME/plenary/credentials.json, keyed by instance.`
|
|
|
686
686
|
`Session ${stored.identifier ?? "user"} (${me.data.role_name ?? me.data.role}), used for admin commands${ctx.apiKey ? "" : " and content"}`
|
|
687
687
|
);
|
|
688
688
|
}
|
|
689
|
-
if (lines.length === 0) lines.push("no credentials: set
|
|
689
|
+
if (lines.length === 0) lines.push("no credentials: set PLENARY_CLI_API_KEY or run `plenary login`");
|
|
690
690
|
io.stdout.write((ctx.json ? toJson(out) : lines.join("\n")) + "\n");
|
|
691
691
|
});
|
|
692
692
|
}
|
|
693
693
|
|
|
694
694
|
// src/commands/catalog.ts
|
|
695
|
+
function siteQuery(siteKey) {
|
|
696
|
+
return siteKey ? { query: { site_key: siteKey } } : void 0;
|
|
697
|
+
}
|
|
695
698
|
function registerCatalog(program, io, name) {
|
|
696
699
|
const group = program.command(name).description(name === "models" ? "Content models and objects" : "Forms");
|
|
697
700
|
group.command("list").description(`List ${name}`).action(async (_opts, cmd) => {
|
|
698
701
|
const ctx = resolveContext(cmd.optsWithGlobals(), io);
|
|
699
|
-
const res = await request(ctx, "GET", name);
|
|
702
|
+
const res = await request(ctx, "GET", name, siteQuery(ctx.siteKey));
|
|
700
703
|
if (ctx.json) {
|
|
701
704
|
io.stdout.write(toJson(res.data) + "\n");
|
|
702
705
|
return;
|
|
@@ -712,7 +715,7 @@ function registerCatalog(program, io, name) {
|
|
|
712
715
|
});
|
|
713
716
|
group.command("get").description(`Show one of the ${name} by key or id`).argument("<key>").option("--yaml", "print the YAML file the metadata commands use").action(async (key, opts, cmd) => {
|
|
714
717
|
const ctx = resolveContext(cmd.optsWithGlobals(), io);
|
|
715
|
-
const res = await request(ctx, "GET", `${name}/${encodeURIComponent(key)}
|
|
718
|
+
const res = await request(ctx, "GET", `${name}/${encodeURIComponent(key)}`, siteQuery(ctx.siteKey));
|
|
716
719
|
const m = res.data;
|
|
717
720
|
if (opts.yaml) {
|
|
718
721
|
const yaml = await request(ctx, "GET", `${name}/${m.id}/yaml`);
|
|
@@ -728,7 +731,7 @@ function registerCatalog(program, io, name) {
|
|
|
728
731
|
["Kind", m.kind],
|
|
729
732
|
["Name", `${m.name_singular} / ${m.name_plural}`],
|
|
730
733
|
["Id", m.id],
|
|
731
|
-
["
|
|
734
|
+
["Site", m.site_key || "-"],
|
|
732
735
|
["Active", m.active ? "yes" : "no"]
|
|
733
736
|
];
|
|
734
737
|
if (m.description) head.push(["Description", m.description]);
|
|
@@ -1237,13 +1240,26 @@ function detail(c) {
|
|
|
1237
1240
|
}
|
|
1238
1241
|
|
|
1239
1242
|
// src/commands/metadata.ts
|
|
1240
|
-
function
|
|
1243
|
+
function siteOf(ctx, opts) {
|
|
1244
|
+
return opts.allSites ? void 0 : ctx.siteKey;
|
|
1245
|
+
}
|
|
1246
|
+
function kindsOf(opts, site) {
|
|
1247
|
+
let kinds;
|
|
1241
1248
|
try {
|
|
1242
|
-
|
|
1249
|
+
kinds = parseKinds(opts.only);
|
|
1243
1250
|
} catch (err) {
|
|
1244
1251
|
throw usageError(`--only: ${err.message}`);
|
|
1245
1252
|
}
|
|
1253
|
+
if (!site) return kinds;
|
|
1254
|
+
if (opts.only && opts.only !== "all" && kinds.includes("roles")) {
|
|
1255
|
+
throw usageError(`roles are instance-wide and not part of site ${site}'s tree; use --all-sites`);
|
|
1256
|
+
}
|
|
1257
|
+
return kinds.filter((k) => k !== "roles");
|
|
1246
1258
|
}
|
|
1259
|
+
function isSiteAnswer(data, site) {
|
|
1260
|
+
return !site || data.site_key === site;
|
|
1261
|
+
}
|
|
1262
|
+
var UNSCOPED_SERVER = (site) => `this server predates per-site metadata: it answered for every site, not just ${site}`;
|
|
1247
1263
|
function treeRoot(ctx, opts) {
|
|
1248
1264
|
return opts.dir ? path5.resolve(ctx.io.cwd, opts.dir) : path5.resolve(ctx.projectRoot, ctx.metadataDir);
|
|
1249
1265
|
}
|
|
@@ -1265,44 +1281,57 @@ async function metadataRequest(ctx, method, opts, needsWholeTree) {
|
|
|
1265
1281
|
}
|
|
1266
1282
|
}
|
|
1267
1283
|
async function runImport(ctx, root, opts, apply) {
|
|
1268
|
-
const
|
|
1284
|
+
const site = siteOf(ctx, opts);
|
|
1285
|
+
const kinds = kindsOf(opts, site);
|
|
1269
1286
|
const files = readTreeOrFail(root, kinds);
|
|
1270
1287
|
const prune = Boolean(opts.prune);
|
|
1271
1288
|
const body = { files, apply: false, prune };
|
|
1289
|
+
const query = site ? { site_key: site } : void 0;
|
|
1272
1290
|
const wholeTree = prune || files.some((f) => !/^(models|forms)\//.test(f.path));
|
|
1273
|
-
let res = await metadataRequest(ctx, "POST", { body }, wholeTree);
|
|
1291
|
+
let res = await metadataRequest(ctx, "POST", { body, query }, wholeTree);
|
|
1292
|
+
if (!isSiteAnswer(res.data, site)) {
|
|
1293
|
+
if (prune) throw usageError(`${UNSCOPED_SERVER(site)}; --prune would delete other sites' models (use --all-sites if that is meant)`);
|
|
1294
|
+
ctx.io.stderr.write(`warning: ${UNSCOPED_SERVER(site)}
|
|
1295
|
+
`);
|
|
1296
|
+
}
|
|
1274
1297
|
const deletes = res.data.changes.filter((c) => c.action === "delete");
|
|
1275
1298
|
if (apply) {
|
|
1276
1299
|
if (deletes.length > 0) {
|
|
1277
1300
|
if (!ctx.json) ctx.io.stdout.write(formatPlan(res.data, Boolean(opts.verbose)) + "\n");
|
|
1278
1301
|
await confirm(ctx.io, `Delete ${deletes.length} ${deletes.length === 1 ? "entity" : "entities"} from the instance?`, Boolean(opts.yes));
|
|
1279
1302
|
}
|
|
1280
|
-
res = await metadataRequest(ctx, "POST", { body: { ...body, apply: true } }, wholeTree);
|
|
1303
|
+
res = await metadataRequest(ctx, "POST", { body: { ...body, apply: true }, query }, wholeTree);
|
|
1281
1304
|
}
|
|
1282
1305
|
if (ctx.json) ctx.io.stdout.write(toJson(res.data) + "\n");
|
|
1283
1306
|
else ctx.io.stdout.write(formatPlan(res.data, Boolean(opts.verbose)) + "\n");
|
|
1284
1307
|
}
|
|
1285
1308
|
var onlyOption = ["--only <kinds>", "comma list of models, forms, roles, sites (default: all)"];
|
|
1309
|
+
var allSitesOption = ["--all-sites", "the whole instance, not just the configured site (roles need this)"];
|
|
1286
1310
|
function registerMetadata(program, io) {
|
|
1287
1311
|
const metadata = program.command("metadata").description("Keep a directory of model and form YAML in step with the instance").addHelpText(
|
|
1288
1312
|
"after",
|
|
1289
1313
|
`
|
|
1290
1314
|
The tree is models/, forms/, roles/ and sites/ under the metadata directory
|
|
1291
1315
|
("metadataDir" in plenary.json, default ./plenary), one <key>.yaml per
|
|
1292
|
-
entity.
|
|
1316
|
+
entity. With a site configured (--site, PLENARY_SITE_KEY or "siteKey" in
|
|
1317
|
+
plenary.json) the tree is that site's alone: its models, forms and site file,
|
|
1318
|
+
never roles, and --prune deletes only within it. --all-sites moves the whole
|
|
1319
|
+
instance. Models and forms need an API key or a session; roles and sites need
|
|
1293
1320
|
a user session (plenary login). See docs/CLI.md.`
|
|
1294
1321
|
);
|
|
1295
|
-
metadata.command("pull").description("Write every model, form, role and site the credential may read into the directory").option("--dir <path>", "metadata directory (default: the configured one)").option(...onlyOption).action(async (opts, cmd) => {
|
|
1322
|
+
metadata.command("pull").description("Write every model, form, role and site the credential may read into the directory").option("--dir <path>", "metadata directory (default: the configured one)").option(...onlyOption).option(...allSitesOption).action(async (opts, cmd) => {
|
|
1296
1323
|
const ctx = resolveContext(cmd.optsWithGlobals(), io);
|
|
1297
1324
|
const root = treeRoot(ctx, opts);
|
|
1298
|
-
const
|
|
1325
|
+
const site = siteOf(ctx, opts);
|
|
1326
|
+
const kinds = kindsOf(opts, site);
|
|
1299
1327
|
const wholeTree = kinds.some((k) => k === "roles" || k === "sites") && Boolean(opts.only);
|
|
1300
1328
|
const res = await metadataRequest(
|
|
1301
1329
|
ctx,
|
|
1302
1330
|
"GET",
|
|
1303
|
-
{ query: { only: kinds.join(",") } },
|
|
1331
|
+
{ query: { only: kinds.join(","), ...site ? { site_key: site } : {} } },
|
|
1304
1332
|
wholeTree
|
|
1305
1333
|
);
|
|
1334
|
+
if (!isSiteAnswer(res.data, site)) throw usageError(`${UNSCOPED_SERVER(site)}; pull with --all-sites for the whole instance`);
|
|
1306
1335
|
const result = writeTree(root, res.data.files, kinds);
|
|
1307
1336
|
const omitted = res.data.omitted ?? [];
|
|
1308
1337
|
if (ctx.json) {
|
|
@@ -1324,11 +1353,11 @@ ${result.stale.map((p) => ` ${p}`).join("\n")}
|
|
|
1324
1353
|
`);
|
|
1325
1354
|
}
|
|
1326
1355
|
});
|
|
1327
|
-
metadata.command("diff").description("Preview what push would change, without writing anything").option("--dir <path>", "metadata directory (default: the configured one)").option(...onlyOption).option("--prune", "include what push --prune would delete").option("--verbose", "list unchanged entities too").action(async (opts, cmd) => {
|
|
1356
|
+
metadata.command("diff").description("Preview what push would change, without writing anything").option("--dir <path>", "metadata directory (default: the configured one)").option(...onlyOption).option(...allSitesOption).option("--prune", "include what push --prune would delete").option("--verbose", "list unchanged entities too").action(async (opts, cmd) => {
|
|
1328
1357
|
const ctx = resolveContext(cmd.optsWithGlobals(), io);
|
|
1329
1358
|
await runImport(ctx, treeRoot(ctx, opts), opts, false);
|
|
1330
1359
|
});
|
|
1331
|
-
metadata.command("push").description("Apply the directory to the instance (creates and updates; deletes only with --prune)").option("--dir <path>", "metadata directory (default: the configured one)").option(...onlyOption).option("--prune", "also delete entities absent from the directory, within the kinds it holds").option("-y, --yes", "do not ask before pruning").option("--dry-run", "same as diff").option("--verbose", "list unchanged entities too").addHelpText(
|
|
1360
|
+
metadata.command("push").description("Apply the directory to the instance (creates and updates; deletes only with --prune)").option("--dir <path>", "metadata directory (default: the configured one)").option(...onlyOption).option(...allSitesOption).option("--prune", "also delete entities absent from the directory, within the kinds (and site) it holds").option("-y, --yes", "do not ask before pruning").option("--dry-run", "same as diff").option("--verbose", "list unchanged entities too").addHelpText(
|
|
1332
1361
|
"after",
|
|
1333
1362
|
`
|
|
1334
1363
|
--prune deletes only within the kinds present in the directory: a tree with
|
|
@@ -1423,7 +1452,7 @@ function registerStatus(program, io) {
|
|
|
1423
1452
|
lines.push(`Status unreachable (HTTP ${health.status})`);
|
|
1424
1453
|
}
|
|
1425
1454
|
if (me?.principal === "api_key") {
|
|
1426
|
-
lines.push(`Credential ${me.key_type} API key "${me.name}" (${me.grants.length} grant${me.grants.length === 1 ? "" : "s"}${me.
|
|
1455
|
+
lines.push(`Credential ${me.key_type} API key "${me.name}" (${me.grants.length} grant${me.grants.length === 1 ? "" : "s"}${me.site_key ? `, site ${me.site_key}` : ", instance-wide"})`);
|
|
1427
1456
|
} else if (me?.principal === "user") {
|
|
1428
1457
|
lines.push(`Credential user session (stored login), role ${me.role_name ?? me.role}`);
|
|
1429
1458
|
} else if (credentialError) {
|
|
@@ -1431,7 +1460,7 @@ function registerStatus(program, io) {
|
|
|
1431
1460
|
} else if (undescribed) {
|
|
1432
1461
|
lines.push("Credential API key accepted (this server predates API-key support on /auth/me and cannot describe the key)");
|
|
1433
1462
|
} else {
|
|
1434
|
-
lines.push("Credential none (set
|
|
1463
|
+
lines.push("Credential none (set PLENARY_CLI_API_KEY, pass --api-key, or run `plenary login`)");
|
|
1435
1464
|
}
|
|
1436
1465
|
if (ctx.configPath) lines.push(`Config ${ctx.configPath}`);
|
|
1437
1466
|
io.stdout.write(lines.join("\n") + "\n");
|
|
@@ -1449,7 +1478,7 @@ function version() {
|
|
|
1449
1478
|
}
|
|
1450
1479
|
}
|
|
1451
1480
|
function createProgram(io) {
|
|
1452
|
-
const program = new Command("plenary").description("Command-line client for the Plenary API").version(version(), "-v, --version").option("--base-url <url>", "instance URL (PLENARY_BASE_URL)").option("--api-key <key>", "API key (
|
|
1481
|
+
const program = new Command("plenary").description("Command-line client for the Plenary API").version(version(), "-v, --version").option("--base-url <url>", "instance URL (PLENARY_BASE_URL)").option("--api-key <key>", "API key (PLENARY_CLI_API_KEY)").option("--site <key>", "site key (PLENARY_SITE_KEY)").option("--locale <code>", "locale (PLENARY_LOCALE)").option("--config <path>", "plenary.json to use (default: nearest, searching upward)").option("--json", "print machine-readable JSON").option("--debug", "print requests and stack traces to stderr").showHelpAfterError("(run with --help for usage)").exitOverride().configureOutput({
|
|
1453
1482
|
writeOut: (s) => io.stdout.write(s),
|
|
1454
1483
|
writeErr: (s) => io.stderr.write(s)
|
|
1455
1484
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/output.ts","../src/errors.ts","../src/config.ts","../src/api/http.ts","../src/session.ts","../src/input.ts","../src/commands/admin.ts","../src/commands/api.ts","../src/commands/auth.ts","../src/commands/catalog.ts","../src/entries/client.ts","../src/entries/query.ts","../src/commands/entries.ts","../src/commands/formentries.ts","../src/commands/media.ts","../src/commands/metadata.ts","../src/metadata/dir.ts","../src/metadata/plan.ts","../src/commands/init.ts","../src/commands/status.ts","../src/index.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { Command, CommanderError } from \"commander\";\nimport type { Io } from \"./config.js\";\nimport { describeError, exitCodeFor } from \"./output.js\";\nimport { registerAdmin } from \"./commands/admin.js\";\nimport { registerApi } from \"./commands/api.js\";\nimport { registerAuth } from \"./commands/auth.js\";\nimport { registerCatalog } from \"./commands/catalog.js\";\nimport { registerEntries } from \"./commands/entries.js\";\nimport { registerFormEntries } from \"./commands/formentries.js\";\nimport { registerMedia } from \"./commands/media.js\";\nimport { registerMetadata } from \"./commands/metadata.js\";\nimport { registerInit } from \"./commands/init.js\";\nimport { registerStatus } from \"./commands/status.js\";\n\nfunction version(): string {\n try {\n const pkg = JSON.parse(readFileSync(new URL(\"../package.json\", import.meta.url), \"utf8\")) as { version: string };\n return pkg.version;\n } catch {\n return \"0.0.0\";\n }\n}\n\nexport function createProgram(io: Io): Command {\n const program = new Command(\"plenary\")\n .description(\"Command-line client for the Plenary API\")\n .version(version(), \"-v, --version\")\n .option(\"--base-url <url>\", \"instance URL (PLENARY_BASE_URL)\")\n .option(\"--api-key <key>\", \"API key (PLENARY_API_KEY)\")\n .option(\"--site <key>\", \"site key (PLENARY_SITE_KEY)\")\n .option(\"--locale <code>\", \"locale (PLENARY_LOCALE)\")\n .option(\"--config <path>\", \"plenary.json to use (default: nearest, searching upward)\")\n .option(\"--json\", \"print machine-readable JSON\")\n .option(\"--debug\", \"print requests and stack traces to stderr\")\n .showHelpAfterError(\"(run with --help for usage)\")\n .exitOverride()\n .configureOutput({\n writeOut: (s) => io.stdout.write(s),\n writeErr: (s) => io.stderr.write(s),\n });\n\n registerInit(program, io);\n registerAuth(program, io);\n registerStatus(program, io);\n registerMetadata(program, io);\n registerCatalog(program, io, \"models\");\n registerFormEntries(registerCatalog(program, io, \"forms\"), io);\n registerEntries(program, io);\n registerMedia(program, io);\n registerAdmin(program, io);\n registerApi(program, io);\n return program;\n}\n\n/** Runs one invocation and returns the exit code; never throws. */\nexport async function run(argv: string[], io: Io): Promise<number> {\n const program = createProgram(io);\n try {\n await program.parseAsync(argv, { from: \"user\" });\n return 0;\n } catch (err) {\n if (err instanceof CommanderError) {\n // Commander has already written help or its own message.\n return exitCodeFor(err);\n }\n const debug = Boolean(program.opts<{ debug?: boolean }>().debug);\n const message = describeError(err, debug);\n if (message !== \"plenary: \") io.stderr.write(message + \"\\n\");\n return exitCodeFor(err);\n }\n}\n","import { PlenaryError } from \"@plenary/client\";\nimport { CommanderError } from \"commander\";\nimport { CliError } from \"./errors.js\";\n\n/** Renders rows as aligned columns; the first row is the header when `header` is set. */\nexport function formatTable(rows: string[][], header?: string[]): string {\n const all = header ? [header, ...rows] : rows;\n if (all.length === 0) return \"\";\n const widths: number[] = [];\n for (const row of all) {\n row.forEach((cell, i) => {\n widths[i] = Math.max(widths[i] ?? 0, cell.length);\n });\n }\n return all\n .map((row) =>\n row\n .map((cell, i) => (i === row.length - 1 ? cell : cell.padEnd(widths[i] ?? 0)))\n .join(\" \")\n .trimEnd(),\n )\n .join(\"\\n\");\n}\n\nexport function toJson(value: unknown): string {\n return JSON.stringify(value, null, 2);\n}\n\n/** One line for stderr describing why a command failed. */\nexport function describeError(err: unknown, debug = false): string {\n if (err instanceof PlenaryError) {\n let line = `plenary: ${err.code} (HTTP ${err.status})`;\n if (err.vars && Object.keys(err.vars).length > 0) {\n line += \"\\n\" + Object.entries(err.vars).map(([k, v]) => ` ${k}: ${fmtVar(v)}`).join(\"\\n\");\n }\n return line;\n }\n if (err instanceof CliError) return `plenary: ${err.message}`;\n if (err instanceof Error) {\n const cause = err.cause instanceof Error ? `: ${err.cause.message}` : \"\";\n return debug && err.stack ? err.stack : `plenary: ${err.message}${cause}`;\n }\n return `plenary: ${String(err)}`;\n}\n\nexport function exitCodeFor(err: unknown): number {\n if (err instanceof CliError) return err.exitCode;\n if (err instanceof CommanderError) return err.exitCode === 0 ? 0 : 2;\n return 1;\n}\n\nfunction fmtVar(v: unknown): string {\n return typeof v === \"string\" ? v : JSON.stringify(v);\n}\n","/**\n * An error the CLI raised itself (as opposed to one the server returned).\n * exitCode 2 is a usage problem — a missing credential, a malformed flag —\n * and 1 is everything else.\n */\nexport class CliError extends Error {\n readonly exitCode: number;\n\n constructor(message: string, exitCode = 1) {\n super(message);\n this.name = \"CliError\";\n this.exitCode = exitCode;\n }\n}\n\nexport function usageError(message: string): CliError {\n return new CliError(message, 2);\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { usageError } from \"./errors.js\";\n\n/** The streams and environment a run reads and writes — injected so tests can capture them. */\nexport interface Io {\n stdout: NodeJS.WritableStream;\n stderr: NodeJS.WritableStream;\n stdin: NodeJS.ReadableStream;\n env: NodeJS.ProcessEnv;\n cwd: string;\n fetch: typeof globalThis.fetch;\n /** Whether stdin is a terminal: prompts are only ever issued when it is. */\n isTTY: boolean;\n}\n\n/** The global options every command accepts (declared on the root program). */\nexport interface GlobalOptions {\n baseUrl?: string;\n apiKey?: string;\n site?: string;\n locale?: string;\n config?: string;\n json?: boolean;\n debug?: boolean;\n}\n\n/** The shape of `plenary.json`. Never holds a credential. */\nexport interface ProjectConfig {\n baseUrl?: string;\n siteKey?: string;\n locale?: string;\n metadataDir?: string;\n}\n\n/** Everything a command needs, resolved once per invocation. */\nexport interface Context {\n io: Io;\n baseUrl?: string;\n apiKey?: string;\n siteKey?: string;\n locale?: string;\n metadataDir: string;\n /** The directory holding plenary.json, or the cwd when there is none. */\n projectRoot: string;\n configPath?: string;\n json: boolean;\n debug: boolean;\n /** The access token minted from a stored session, once this run has one. */\n sessionToken?: string;\n}\n\nexport const CONFIG_FILE = \"plenary.json\";\nexport const DEFAULT_METADATA_DIR = \"plenary\";\n\n/** Walks up from `from` and returns the first plenary.json found, if any. */\nexport function findConfigFile(from: string): string | undefined {\n let dir = path.resolve(from);\n for (;;) {\n const candidate = path.join(dir, CONFIG_FILE);\n if (existsSync(candidate)) return candidate;\n const parent = path.dirname(dir);\n if (parent === dir) return undefined;\n dir = parent;\n }\n}\n\nconst CONFIG_KEYS: ReadonlyArray<keyof ProjectConfig> = [\"baseUrl\", \"siteKey\", \"locale\", \"metadataDir\"];\n\nexport function readProjectConfig(file: string): ProjectConfig {\n let parsed: unknown;\n try {\n parsed = JSON.parse(readFileSync(file, \"utf8\"));\n } catch (err) {\n throw usageError(`${file}: ${(err as Error).message}`);\n }\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n throw usageError(`${file}: expected a JSON object`);\n }\n const out: ProjectConfig = {};\n for (const [key, value] of Object.entries(parsed)) {\n if (!(CONFIG_KEYS as readonly string[]).includes(key)) {\n throw usageError(`${file}: unknown key \"${key}\"`);\n }\n if (typeof value !== \"string\") {\n throw usageError(`${file}: \"${key}\" must be a string`);\n }\n out[key as keyof ProjectConfig] = value;\n }\n return out;\n}\n\n/**\n * Reads the PLENARY_* lines of a .env file. Deliberately minimal — `KEY=value`,\n * optional surrounding quotes, `#` comments — because a project that needs\n * more has a real env loader already.\n */\nexport function readDotEnv(file: string): Record<string, string> {\n const out: Record<string, string> = {};\n let text: string;\n try {\n text = readFileSync(file, \"utf8\");\n } catch {\n return out;\n }\n for (const raw of text.split(\"\\n\")) {\n const line = raw.trim();\n if (line === \"\" || line.startsWith(\"#\")) continue;\n const m = /^(?:export\\s+)?(PLENARY_[A-Z0-9_]+)=(.*)$/.exec(line);\n if (!m) continue;\n let value = (m[2] ?? \"\").trim();\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n out[m[1] as string] = value;\n }\n return out;\n}\n\n/**\n * Resolves the run context. Precedence, highest first: flag, process\n * environment, `.env` beside plenary.json (or in the cwd), plenary.json,\n * default.\n */\nexport function resolveContext(opts: GlobalOptions, io: Io): Context {\n const configPath = opts.config ? path.resolve(io.cwd, opts.config) : findConfigFile(io.cwd);\n if (opts.config && !existsSync(configPath as string)) {\n throw usageError(`config file not found: ${configPath}`);\n }\n const file = configPath ? readProjectConfig(configPath) : {};\n const projectRoot = configPath ? path.dirname(configPath) : io.cwd;\n const env = { ...readDotEnv(path.join(projectRoot, \".env\")), ...pick(io.env) };\n\n const baseUrl = opts.baseUrl ?? env.PLENARY_BASE_URL ?? file.baseUrl;\n return {\n io,\n baseUrl: baseUrl ? baseUrl.replace(/\\/+$/, \"\") : undefined,\n apiKey: opts.apiKey ?? env.PLENARY_API_KEY,\n siteKey: opts.site ?? env.PLENARY_SITE_KEY ?? file.siteKey,\n locale: opts.locale ?? env.PLENARY_LOCALE ?? file.locale,\n metadataDir: env.PLENARY_METADATA_DIR ?? file.metadataDir ?? DEFAULT_METADATA_DIR,\n projectRoot,\n configPath,\n json: opts.json ?? false,\n debug: opts.debug ?? false,\n };\n}\n\n/** Only the PLENARY_* variables, and only those actually set. */\nfunction pick(env: NodeJS.ProcessEnv): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(env)) {\n if (k.startsWith(\"PLENARY_\") && v !== undefined && v !== \"\") out[k] = v;\n }\n return out;\n}\n\nexport function requireBaseUrl(ctx: Context): string {\n if (!ctx.baseUrl) {\n throw usageError(\n \"no base URL: pass --base-url, set PLENARY_BASE_URL, or run `plenary init`\",\n );\n }\n return ctx.baseUrl;\n}\n","import { errorFromResponse } from \"@plenary/client\";\nimport { requireBaseUrl, type Context } from \"../config.js\";\nimport { usageError } from \"../errors.js\";\nimport { sessionAccessToken } from \"../session.js\";\n\n/**\n * Which credential a request carries. A configured API key wins over a\n * stored session for content work, so a person's login never silently\n * becomes the actor of a deploy job that also has a key; a session is what\n * admin work needs, since a key can never hold admin:* capabilities.\n */\nexport type AuthMode = \"required\" | \"optional\" | \"none\" | \"session\";\n\nexport async function credentialHeaders(ctx: Context, mode: AuthMode): Promise<Record<string, string>> {\n if (mode === \"none\") return {};\n if (mode === \"session\") {\n const token = await sessionAccessToken(ctx);\n if (!token) throw usageError(\"this command needs a user session: run `plenary login`\");\n return { Authorization: `Bearer ${token}` };\n }\n if (ctx.apiKey) return { \"X-API-KEY\": ctx.apiKey };\n const token = await sessionAccessToken(ctx);\n if (token) return { Authorization: `Bearer ${token}` };\n if (mode === \"required\") {\n throw usageError(\"no credential: pass --api-key, set PLENARY_API_KEY, or run `plenary login`\");\n }\n return {};\n}\n\nexport interface RequestOptions {\n /** Query parameters; undefined values are dropped. */\n query?: Record<string, string | undefined>;\n /** A JSON body. */\n body?: unknown;\n /** A multipart body; wins over `body`. */\n form?: FormData;\n headers?: Record<string, string>;\n /**\n * \"required\" (default) refuses to run without a credential; \"optional\"\n * sends one when there is one; \"none\" never does (the health check);\n * \"session\" insists on a user login (admin routes).\n */\n auth?: AuthMode;\n /** Return a non-2xx response instead of throwing its PlenaryError. */\n allowError?: boolean;\n}\n\nexport interface ApiResponse<T = unknown> {\n status: number;\n ok: boolean;\n headers: Headers;\n /** The parsed JSON body, the text body for non-JSON responses, or null for 204. */\n data: T;\n}\n\n/** Turns `models` into `/api/v1/models`; a path that already starts with `/` is kept. */\nexport function apiPath(p: string): string {\n return p.startsWith(\"/\") ? p : `/api/v1/${p}`;\n}\n\nexport async function request<T = unknown>(\n ctx: Context,\n method: string,\n path: string,\n opts: RequestOptions = {},\n): Promise<ApiResponse<T>> {\n const base = requireBaseUrl(ctx);\n const headers: Record<string, string> = { ...opts.headers, ...(await credentialHeaders(ctx, opts.auth ?? \"required\")) };\n\n const url = new URL(base + apiPath(path));\n for (const [k, v] of Object.entries(opts.query ?? {})) {\n if (v !== undefined) url.searchParams.set(k, v);\n }\n\n let body: RequestInit[\"body\"];\n if (opts.form) {\n body = opts.form;\n } else if (opts.body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n body = JSON.stringify(opts.body);\n }\n\n if (ctx.debug) ctx.io.stderr.write(`> ${method} ${url}\\n`);\n const response = await ctx.io.fetch(url, { method, headers, body });\n const data = await parseBody(response);\n if (ctx.debug) ctx.io.stderr.write(`< ${response.status}\\n`);\n\n if (!response.ok && !opts.allowError) {\n throw errorFromResponse(response.status, data);\n }\n return { status: response.status, ok: response.ok, headers: response.headers, data: data as T };\n}\n\nasync function parseBody(response: Response): Promise<unknown> {\n if (response.status === 204) return null;\n const text = await response.text();\n if (text === \"\") return null;\n const type = response.headers.get(\"content-type\") ?? \"\";\n if (type.includes(\"json\")) {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n }\n return text;\n}\n","import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport path from \"node:path\";\nimport type { Context, Io } from \"./config.js\";\nimport { usageError } from \"./errors.js\";\n\n/** What login stores: never an access token, only the refresh token that mints one. */\nexport interface StoredSession {\n refresh_token: string;\n identifier?: string;\n updated_at: string;\n}\n\ntype Store = Record<string, StoredSession>;\n\n/** `$XDG_CONFIG_HOME/plenary/credentials.json`, `~/.config` by default. */\nexport function credentialsPath(io: Io): string {\n const base = io.env.XDG_CONFIG_HOME || path.join(io.env.HOME || homedir(), \".config\");\n return path.join(base, \"plenary\", \"credentials.json\");\n}\n\nfunction readStore(io: Io): Store {\n const file = credentialsPath(io);\n if (!existsSync(file)) return {};\n try {\n const parsed = JSON.parse(readFileSync(file, \"utf8\")) as unknown;\n return typeof parsed === \"object\" && parsed !== null ? (parsed as Store) : {};\n } catch {\n return {};\n }\n}\n\nfunction writeStore(io: Io, store: Store): void {\n const file = credentialsPath(io);\n mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });\n // Written whole and renamed into place, so a crash mid-write never leaves\n // a half file where a refresh token used to be.\n const tmp = `${file}.${process.pid}.tmp`;\n writeFileSync(tmp, JSON.stringify(store, null, 2) + \"\\n\", { mode: 0o600 });\n chmodSync(tmp, 0o600);\n renameSync(tmp, file);\n}\n\nexport function loadSession(io: Io, baseUrl: string): StoredSession | undefined {\n return readStore(io)[baseUrl];\n}\n\nexport function saveSession(io: Io, baseUrl: string, session: Omit<StoredSession, \"updated_at\">): void {\n const store = readStore(io);\n store[baseUrl] = { ...session, updated_at: new Date().toISOString() };\n writeStore(io, store);\n}\n\nexport function clearSession(io: Io, baseUrl: string): boolean {\n const store = readStore(io);\n if (!(baseUrl in store)) return false;\n delete store[baseUrl];\n writeStore(io, store);\n return true;\n}\n\ninterface RefreshResponse {\n status: string;\n access_token: string;\n refresh_token: string;\n}\n\n/**\n * The access token for this run, minted from the stored refresh token. The\n * rotated refresh token is written back before the access token is used for\n * anything, because presenting the old one again would revoke the family.\n * Undefined when there is no session for this instance.\n */\nexport async function sessionAccessToken(ctx: Context): Promise<string | undefined> {\n if (ctx.sessionToken) return ctx.sessionToken;\n const baseUrl = ctx.baseUrl;\n if (!baseUrl) return undefined;\n const stored = loadSession(ctx.io, baseUrl);\n if (!stored) return undefined;\n\n const response = await ctx.io.fetch(`${baseUrl}/api/v1/auth/refresh`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refresh_token: stored.refresh_token }),\n });\n const body = (await response.json().catch(() => null)) as RefreshResponse | { error?: { code?: string } } | null;\n if (!response.ok || !body || !(\"access_token\" in body)) {\n const code = (body as { error?: { code?: string } } | null)?.error?.code ?? `http_${response.status}`;\n if (response.status === 401) {\n clearSession(ctx.io, baseUrl);\n throw usageError(`session for ${baseUrl} is no longer valid (${code}): run \\`plenary login\\``);\n }\n throw usageError(`could not refresh the session for ${baseUrl} (${code})`);\n }\n saveSession(ctx.io, baseUrl, { refresh_token: body.refresh_token, identifier: stored.identifier });\n ctx.sessionToken = body.access_token;\n return body.access_token;\n}\n","import { readFileSync } from \"node:fs\";\nimport { createInterface } from \"node:readline/promises\";\nimport type { Io } from \"./config.js\";\nimport { usageError } from \"./errors.js\";\n\n/** `k=v` pairs → object; a repeated key keeps the last value. */\nexport function parsePairs(pairs: string[], sep: string, what: string): Record<string, string> {\n const out: Record<string, string> = {};\n for (const pair of pairs) {\n const i = pair.indexOf(sep);\n if (i <= 0) throw usageError(`invalid ${what} \"${pair}\": expected key${sep}value`);\n out[pair.slice(0, i).trim()] = pair.slice(i + 1).trim();\n }\n return out;\n}\n\n/** Inline text, `@file`, or `-` for stdin. */\nexport async function readText(data: string, stdin: NodeJS.ReadableStream): Promise<string> {\n if (data === \"-\") return readStream(stdin);\n if (data.startsWith(\"@\")) {\n try {\n return readFileSync(data.slice(1), \"utf8\");\n } catch (err) {\n throw usageError(`cannot read ${data.slice(1)}: ${(err as Error).message}`);\n }\n }\n return data;\n}\n\n/** Inline JSON, `@file`, or `-` for stdin; returns the parsed value. */\nexport async function readData(data: string, stdin: NodeJS.ReadableStream, flag = \"--data\"): Promise<unknown> {\n const text = await readText(data, stdin);\n try {\n return JSON.parse(text);\n } catch (err) {\n throw usageError(`${flag} is not valid JSON: ${(err as Error).message}`);\n }\n}\n\n/** Like readData, but insists on a JSON object. */\nexport async function readObject(\n data: string,\n stdin: NodeJS.ReadableStream,\n flag = \"--data\",\n): Promise<Record<string, unknown>> {\n const value = await readData(data, stdin, flag);\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw usageError(`${flag} must be a JSON object`);\n }\n return value as Record<string, unknown>;\n}\n\nexport async function readStream(stream: NodeJS.ReadableStream): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of stream) chunks.push(Buffer.from(chunk as Buffer | string));\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n\n/**\n * Asks before something destructive. `yes` (from -y) skips the question; a\n * run with no terminal and no -y is refused rather than silently answered.\n */\nexport async function confirm(io: Io, question: string, yes: boolean): Promise<void> {\n if (yes) return;\n if (!io.isTTY) throw usageError(`${question} — pass -y to confirm without a terminal`);\n const rl = createInterface({ input: io.stdin, output: io.stderr });\n try {\n const answer = (await rl.question(`${question} [y/N] `)).trim().toLowerCase();\n if (answer !== \"y\" && answer !== \"yes\") throw usageError(\"aborted\");\n } finally {\n rl.close();\n }\n}\n\n/** Prompts for one line on a terminal; without one, reads a line from stdin. */\nexport async function readLine(io: Io, prompt: string): Promise<string> {\n const rl = createInterface({ input: io.stdin, output: io.isTTY ? io.stderr : undefined, terminal: io.isTTY });\n try {\n if (!io.isTTY) {\n const it = rl[Symbol.asyncIterator]();\n const { value } = await it.next();\n return (value ?? \"\").trim();\n }\n return (await rl.question(prompt)).trim();\n } finally {\n rl.close();\n }\n}\n\n/**\n * Prompts for a secret without echoing it. On a terminal the input is put in\n * raw mode and read a key at a time; otherwise a line is read from stdin, so\n * a script can pipe a password in.\n */\nexport async function readSecret(io: Io, prompt: string): Promise<string> {\n const stdin = io.stdin as NodeJS.ReadableStream & { setRawMode?: (raw: boolean) => void };\n if (!io.isTTY || typeof stdin.setRawMode !== \"function\") return readLine(io, prompt);\n io.stderr.write(prompt);\n stdin.setRawMode(true);\n stdin.resume();\n try {\n return await new Promise<string>((resolve, reject) => {\n let value = \"\";\n const onData = (chunk: Buffer | string) => {\n for (const ch of String(chunk)) {\n const code = ch.charCodeAt(0);\n if (code === 3) {\n cleanup();\n reject(usageError(\"aborted\"));\n return;\n }\n if (code === 13 || code === 10) {\n cleanup();\n io.stderr.write(\"\\n\");\n resolve(value);\n return;\n }\n if (code === 127 || code === 8) value = value.slice(0, -1);\n else value += ch;\n }\n };\n const cleanup = () => {\n stdin.off(\"data\", onData);\n stdin.setRawMode?.(false);\n stdin.pause();\n };\n stdin.on(\"data\", onData);\n });\n } finally {\n stdin.setRawMode?.(false);\n }\n}\n","import type { Command } from \"commander\";\nimport { resolveContext, type GlobalOptions, type Io } from \"../config.js\";\nimport { request } from \"../api/http.js\";\nimport { usageError } from \"../errors.js\";\nimport { confirm } from \"../input.js\";\nimport { formatTable, toJson } from \"../output.js\";\n\ninterface Site {\n key: string;\n name: string;\n is_active: boolean;\n default_locale: string;\n locales: string[];\n timezone: string;\n}\n\ninterface RoleItem {\n key: string;\n name: string;\n description: string | null;\n is_system: boolean;\n grant_count: number;\n assigned_user_count: number;\n}\n\ninterface Grant {\n key: string;\n site_key?: string;\n content_model_id?: string;\n}\n\ninterface Role extends Omit<RoleItem, \"grant_count\" | \"assigned_user_count\"> {\n grants: Grant[];\n}\n\ninterface ApiKeyItem {\n id: string;\n name: string;\n key_type: string;\n is_active: boolean;\n last_used_at: string | null;\n expires_at: string | null;\n revoked_at: string | null;\n}\n\ninterface ApiKeyCreated extends ApiKeyItem {\n key: string;\n}\n\nfunction collect(value: string, previous: string[]): string[] {\n return [...previous, value];\n}\n\n/** `content:entries:read`, optionally `,site=<key>` and `,model=<uuid>`. */\nexport function parseGrant(spec: string): Grant {\n const [key, ...filters] = spec.split(\",\").map((s) => s.trim());\n if (!key) throw usageError(`invalid --grant \"${spec}\"`);\n const grant: Grant = { key };\n for (const f of filters) {\n const [name, value] = f.split(\"=\");\n if (name === \"site\" && value) grant.site_key = value;\n else if (name === \"model\" && value) grant.content_model_id = value;\n else throw usageError(`invalid --grant \"${spec}\": expected key[,site=<key>][,model=<uuid>]`);\n }\n return grant;\n}\n\nexport function registerAdmin(program: Command, io: Io): void {\n program\n .command(\"sites\")\n .description(\"Sites\")\n .command(\"list\")\n .description(\"List sites\")\n .action(async (_flags: unknown, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const res = await request<Site[]>(ctx, \"GET\", \"sites\");\n if (ctx.json) {\n io.stdout.write(toJson(res.data) + \"\\n\");\n return;\n }\n const rows = res.data.map((s) => [\n s.key,\n s.name,\n s.default_locale,\n s.locales.join(\",\"),\n s.timezone,\n s.is_active ? \"\" : \"inactive\",\n ]);\n io.stdout.write(formatTable(rows, [\"KEY\", \"NAME\", \"DEFAULT\", \"LOCALES\", \"TIMEZONE\", \"\"]) + \"\\n\");\n });\n\n const roles = program.command(\"roles\").description(\"Roles (needs a user session)\");\n roles\n .command(\"list\")\n .description(\"List roles\")\n .action(async (_flags: unknown, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const res = await request<RoleItem[]>(ctx, \"GET\", \"roles\", { auth: \"session\" });\n if (ctx.json) {\n io.stdout.write(toJson(res.data) + \"\\n\");\n return;\n }\n const rows = res.data.map((r) => [\n r.key,\n r.name,\n String(r.grant_count),\n String(r.assigned_user_count),\n r.is_system ? \"system\" : \"\",\n ]);\n io.stdout.write(formatTable(rows, [\"KEY\", \"NAME\", \"GRANTS\", \"USERS\", \"\"]) + \"\\n\");\n });\n roles\n .command(\"get\")\n .description(\"Show a role and its grants\")\n .argument(\"<key>\")\n .action(async (key: string, _flags: unknown, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const res = await request<Role>(ctx, \"GET\", `roles/${encodeURIComponent(key)}`, { auth: \"session\" });\n if (ctx.json) {\n io.stdout.write(toJson(res.data) + \"\\n\");\n return;\n }\n const r = res.data;\n const head = [\n [\"Key\", r.key],\n [\"Name\", r.name],\n [\"System\", r.is_system ? \"yes\" : \"no\"],\n ];\n if (r.description) head.push([\"Description\", r.description]);\n const grants = r.grants.map((g) => [g.key, g.site_key ?? \"\", g.content_model_id ?? \"\"]);\n io.stdout.write(formatTable(head) + \"\\n\\n\" + formatTable(grants, [\"GRANT\", \"SITE\", \"MODEL\"]) + \"\\n\");\n });\n\n const keys = program.command(\"api-keys\").description(\"API keys (needs a user session)\");\n keys\n .command(\"list\")\n .description(\"List API keys\")\n .action(async (_flags: unknown, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const res = await request<ApiKeyItem[]>(ctx, \"GET\", \"api-keys\", { auth: \"session\" });\n if (ctx.json) {\n io.stdout.write(toJson(res.data) + \"\\n\");\n return;\n }\n const rows = res.data.map((k) => [\n k.id,\n k.name,\n k.key_type,\n k.revoked_at ? \"revoked\" : k.is_active ? \"active\" : \"inactive\",\n k.last_used_at ?? \"never\",\n k.expires_at ?? \"\",\n ]);\n io.stdout.write(formatTable(rows, [\"ID\", \"NAME\", \"TYPE\", \"STATE\", \"LAST USED\", \"EXPIRES\"]) + \"\\n\");\n });\n keys\n .command(\"get\")\n .description(\"Show one API key (never its secret)\")\n .argument(\"<id>\")\n .action(async (id: string, _flags: unknown, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const res = await request(ctx, \"GET\", `api-keys/${encodeURIComponent(id)}`, { auth: \"session\" });\n io.stdout.write(toJson(res.data) + \"\\n\");\n });\n keys\n .command(\"create\")\n .description(\"Create an API key; the secret is printed once, alone on stdout\")\n .requiredOption(\"-n, --name <name>\")\n .option(\"-t, --type <private|public>\", \"key type\", \"private\")\n .option(\"--description <text>\")\n .option(\"-g, --grant <spec>\", \"private keys: key[,site=<key>][,model=<uuid>] (repeatable)\", collect, [])\n .option(\"--site <key>\", \"public keys: a site it may read (repeatable)\", collect, [])\n .option(\"--expires <iso>\", \"expiry timestamp\")\n .option(\"--origin <origin>\", \"an allowed browser origin (repeatable)\", collect, [])\n .option(\"--rate-limit <n>\", \"requests per minute, 0 = unlimited\", \"0\")\n .option(\"--include-drafts\", \"public keys: read drafts too\")\n .action(\n async (\n flags: {\n name: string;\n type: string;\n description?: string;\n grant: string[];\n site: string[];\n expires?: string;\n origin: string[];\n rateLimit: string;\n includeDrafts?: boolean;\n },\n cmd: Command,\n ) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n if (flags.type !== \"private\" && flags.type !== \"public\") throw usageError(\"--type must be private or public\");\n const body = {\n name: flags.name,\n description: flags.description ?? null,\n key_type: flags.type,\n is_active: true,\n expires_at: flags.expires ?? null,\n grants: flags.grant.map(parseGrant),\n sites: flags.site,\n allowed_origins: flags.origin,\n rate_limit_per_minute: Number(flags.rateLimit),\n include_drafts: Boolean(flags.includeDrafts),\n };\n const res = await request<ApiKeyCreated>(ctx, \"POST\", \"api-keys\", { auth: \"session\", body });\n if (ctx.json) {\n io.stdout.write(toJson(res.data) + \"\\n\");\n return;\n }\n io.stderr.write(\n `created ${flags.type} key \"${flags.name}\" (${res.data.id}); the secret follows and is not shown again\\n`,\n );\n io.stdout.write(res.data.key + \"\\n\");\n },\n );\n keys\n .command(\"delete\")\n .description(\"Delete an API key\")\n .argument(\"<id>\")\n .option(\"-y, --yes\", \"do not ask\")\n .action(async (id: string, flags: { yes?: boolean }, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n await confirm(io, `Delete API key ${id}?`, Boolean(flags.yes));\n await request(ctx, \"DELETE\", `api-keys/${encodeURIComponent(id)}`, { auth: \"session\" });\n io.stdout.write(`deleted ${id}\\n`);\n });\n}\n","import type { Command } from \"commander\";\nimport { resolveContext, type GlobalOptions, type Io } from \"../config.js\";\nimport { request } from \"../api/http.js\";\nimport { CliError, usageError } from \"../errors.js\";\nimport { parsePairs, readData } from \"../input.js\";\nimport { describeError, toJson } from \"../output.js\";\nimport { errorFromResponse } from \"@plenary/client\";\n\nconst METHODS = new Set([\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\", \"HEAD\"]);\n\nfunction collect(value: string, previous: string[]): string[] {\n return [...previous, value];\n}\n\nexport function registerApi(program: Command, io: Io): void {\n program\n .command(\"api\")\n .description(\"Call any API endpoint and print the response body\")\n .argument(\"<method>\", \"GET, POST, PUT, PATCH, DELETE, or HEAD\")\n .argument(\"<path>\", \"a path such as models or /api/v1/models\")\n .option(\"-d, --data <json>\", \"request body: inline JSON, @file, or - for stdin\")\n .option(\"-q, --query <key=value>\", \"query parameter (repeatable)\", collect, [])\n .option(\"-H, --header <key:value>\", \"request header (repeatable)\", collect, [])\n .option(\"-i, --include\", \"print the status line and response headers to stderr\")\n .addHelpText(\n \"after\",\n `\nExamples:\n plenary api GET models\n plenary api GET content/post -q site_key=main -q limit=5\n plenary api POST content/post -q site_key=main -d '{\"fields\":{\"title\":\"Hello\"}}'\n plenary api PUT models/<uuid> -d @model.json`,\n )\n .action(\n async (\n methodArg: string,\n path: string,\n opts: { data?: string; query: string[]; header: string[]; include?: boolean },\n cmd: Command,\n ) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const method = methodArg.toUpperCase();\n if (!METHODS.has(method)) throw usageError(`unsupported method \"${methodArg}\"`);\n\n const body = opts.data !== undefined ? await readData(opts.data, io.stdin) : undefined;\n const res = await request(ctx, method, path, {\n query: parsePairs(opts.query, \"=\", \"query parameter\"),\n headers: parsePairs(opts.header, \":\", \"header\"),\n body,\n auth: \"optional\",\n allowError: true,\n });\n\n if (opts.include) {\n io.stderr.write(`HTTP ${res.status}\\n`);\n res.headers.forEach((v: string, k: string) => io.stderr.write(`${k}: ${v}\\n`));\n io.stderr.write(\"\\n\");\n }\n if (res.data !== null) {\n io.stdout.write((typeof res.data === \"string\" ? res.data : toJson(res.data)) + \"\\n\");\n }\n if (!res.ok) {\n io.stderr.write(describeError(errorFromResponse(res.status, res.data)) + \"\\n\");\n throw new CliError(\"\", 1);\n }\n },\n );\n}\n","import type { Command } from \"commander\";\nimport { resolveContext, requireBaseUrl, type Context, type GlobalOptions, type Io } from \"../config.js\";\nimport { credentialHeaders, request } from \"../api/http.js\";\nimport { usageError } from \"../errors.js\";\nimport { readLine, readSecret } from \"../input.js\";\nimport { toJson } from \"../output.js\";\nimport { clearSession, credentialsPath, loadSession, saveSession } from \"../session.js\";\n\ntype LoginResponse =\n | { status: \"success\"; access_token: string; refresh_token: string }\n | { status: \"otp_sent\" | \"otp_required\"; challenge_id: string; otp_methods: Record<string, string> };\n\ninterface Tokens {\n access_token: string;\n refresh_token: string;\n}\n\ninterface MeUser {\n principal: \"user\";\n role: string;\n role_name?: string;\n}\n\n/** The password, then OTP, then tokens conversation, prompting only where needed. */\nasync function login(ctx: Context, identifier: string, password: string, otpMethod?: string): Promise<Tokens> {\n const io = ctx.io;\n const first = await request<LoginResponse>(ctx, \"POST\", \"auth/login\", {\n auth: \"none\",\n body: { identifier, password },\n });\n const res = first.data;\n if (res.status === \"success\") return res;\n\n const challengeId = res.challenge_id;\n const methods = Object.keys(res.otp_methods);\n if (res.status === \"otp_required\") {\n let method = otpMethod ?? (methods.length === 1 ? methods[0] : undefined);\n if (!method) {\n if (!io.isTTY) throw usageError(`2FA needs a delivery method: pass --otp-method ${methods.join(\"|\")}`);\n const shown = methods.map((m) => `${m} (${res.otp_methods[m]})`).join(\", \");\n method = await readLine(io, `Send the code by ${shown}? [${methods[0]}] `);\n if (method === \"\") method = methods[0];\n }\n if (!methods.includes(method as string)) throw usageError(`--otp-method must be one of ${methods.join(\", \")}`);\n await request(ctx, \"POST\", \"auth/login/otp/send\", {\n auth: \"none\",\n body: { challenge_id: challengeId, otp_method: method },\n });\n io.stderr.write(`code sent by ${method}\\n`);\n } else {\n io.stderr.write(`code sent to ${Object.values(res.otp_methods).join(\", \")}\\n`);\n }\n\n if (!io.isTTY) throw usageError(\"2FA needs a terminal to enter the code\");\n const code = await readLine(io, \"Code: \");\n const verified = await request<Tokens & { status: string }>(ctx, \"POST\", \"auth/login/otp/verify\", {\n auth: \"none\",\n body: { challenge_id: challengeId, otp_code: code },\n });\n return verified.data;\n}\n\nexport function registerAuth(program: Command, io: Io): void {\n program\n .command(\"login\")\n .description(\"Sign in as a user and keep the session for admin commands\")\n .option(\"-u, --identifier <email-or-username>\", \"or PLENARY_USERNAME\")\n .option(\"--otp-method <email|sms>\", \"how to receive a 2FA code when more than one way is offered\")\n .addHelpText(\n \"after\",\n `\nThe password is prompted for (never a flag); PLENARY_PASSWORD supplies it\nwithout a terminal. Only the refresh token is stored, in\n$XDG_CONFIG_HOME/plenary/credentials.json, keyed by instance.`,\n )\n .action(async (flags: { identifier?: string; otpMethod?: string }, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const baseUrl = requireBaseUrl(ctx);\n let identifier = flags.identifier ?? io.env.PLENARY_USERNAME;\n if (!identifier) {\n if (!io.isTTY) throw usageError(\"no identifier: pass --identifier or set PLENARY_USERNAME\");\n identifier = await readLine(io, \"Email or username: \");\n }\n let password = io.env.PLENARY_PASSWORD;\n if (!password) {\n if (!io.isTTY) throw usageError(\"no password: set PLENARY_PASSWORD or run on a terminal\");\n password = await readSecret(io, \"Password: \");\n }\n const tokens = await login(ctx, identifier, password, flags.otpMethod);\n saveSession(io, baseUrl, { refresh_token: tokens.refresh_token, identifier });\n ctx.sessionToken = tokens.access_token;\n\n const me = await request<MeUser>(ctx, \"GET\", \"auth/me\", { auth: \"session\" });\n if (ctx.json) {\n io.stdout.write(\n toJson({ base_url: baseUrl, identifier, role: me.data.role, credentials: credentialsPath(io) }) + \"\\n\",\n );\n return;\n }\n io.stdout.write(`logged in to ${baseUrl} as ${identifier} (${me.data.role_name ?? me.data.role})\\n`);\n });\n\n program\n .command(\"logout\")\n .description(\"Revoke the stored session for this instance\")\n .action(async (_flags: unknown, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const baseUrl = requireBaseUrl(ctx);\n const stored = loadSession(io, baseUrl);\n if (!stored) {\n io.stdout.write(`no session for ${baseUrl}\\n`);\n return;\n }\n // Logout is idempotent server-side; a failure there must not keep a\n // token on disk the person asked to be rid of.\n try {\n await request(ctx, \"POST\", \"auth/logout\", { auth: \"none\", body: { refresh_token: stored.refresh_token } });\n } finally {\n clearSession(io, baseUrl);\n }\n io.stdout.write(`logged out of ${baseUrl}\\n`);\n });\n\n program\n .command(\"whoami\")\n .description(\"Show the credentials this run would use\")\n .action(async (_flags: unknown, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const baseUrl = requireBaseUrl(ctx);\n const stored = loadSession(io, baseUrl);\n const out: Record<string, unknown> = { base_url: baseUrl, api_key: null, session: null };\n const lines: string[] = [];\n if (ctx.apiKey) {\n const me = await request<{ key_type?: string; name?: string; grants?: unknown[] }>(ctx, \"GET\", \"auth/me\", {\n auth: \"none\",\n headers: { \"X-API-KEY\": ctx.apiKey },\n allowError: true,\n });\n out.api_key = me.ok ? me.data : { error: (me.data as { error?: unknown } | null)?.error ?? me.status };\n if (me.ok && me.data.key_type) {\n lines.push(\n `API key ${me.data.key_type} \"${me.data.name}\" (${me.data.grants?.length ?? 0} grants), used for content commands`,\n );\n } else if (me.status === 403) {\n lines.push(\"API key accepted (this server cannot describe keys), used for content commands\");\n } else {\n lines.push(`API key rejected (HTTP ${me.status})`);\n }\n }\n if (stored) {\n const headers = await credentialHeaders(ctx, \"session\");\n const me = await request<MeUser>(ctx, \"GET\", \"auth/me\", { auth: \"none\", headers });\n out.session = { identifier: stored.identifier ?? null, role: me.data.role, role_name: me.data.role_name ?? null };\n lines.push(\n `Session ${stored.identifier ?? \"user\"} (${me.data.role_name ?? me.data.role}), used for admin commands${\n ctx.apiKey ? \"\" : \" and content\"\n }`,\n );\n }\n if (lines.length === 0) lines.push(\"no credentials: set PLENARY_API_KEY or run `plenary login`\");\n io.stdout.write((ctx.json ? toJson(out) : lines.join(\"\\n\")) + \"\\n\");\n });\n}\n","import type { Command } from \"commander\";\nimport { resolveContext, type GlobalOptions, type Io } from \"../config.js\";\nimport { request } from \"../api/http.js\";\nimport { formatTable, toJson } from \"../output.js\";\n\ninterface CatalogItem {\n id: string;\n key: string;\n kind: string;\n name_singular: string;\n active: boolean;\n fields_count: number;\n sites?: string[];\n}\n\ninterface CatalogField {\n key: string;\n name: string;\n type: string;\n required: boolean;\n localized: boolean;\n}\n\ninterface CatalogDetail extends CatalogItem {\n name_plural: string;\n description?: string;\n private: boolean;\n fields: CatalogField[];\n transformers?: unknown[];\n entry_count?: number;\n}\n\n/** `models` and `forms` are the same surface at two paths. */\nexport function registerCatalog(program: Command, io: Io, name: \"models\" | \"forms\"): Command {\n const group = program.command(name).description(name === \"models\" ? \"Content models and objects\" : \"Forms\");\n\n group\n .command(\"list\")\n .description(`List ${name}`)\n .action(async (_opts: unknown, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const res = await request<CatalogItem[]>(ctx, \"GET\", name);\n if (ctx.json) {\n io.stdout.write(toJson(res.data) + \"\\n\");\n return;\n }\n const rows = res.data.map((m) => [\n m.key,\n m.kind,\n m.name_singular,\n String(m.fields_count),\n m.active ? \"\" : \"inactive\",\n ]);\n io.stdout.write(formatTable(rows, [\"KEY\", \"KIND\", \"NAME\", \"FIELDS\", \"\"]) + \"\\n\");\n });\n\n group\n .command(\"get\")\n .description(`Show one of the ${name} by key or id`)\n .argument(\"<key>\")\n .option(\"--yaml\", \"print the YAML file the metadata commands use\")\n .action(async (key: string, opts: { yaml?: boolean }, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const res = await request<CatalogDetail>(ctx, \"GET\", `${name}/${encodeURIComponent(key)}`);\n const m = res.data;\n if (opts.yaml) {\n const yaml = await request<string>(ctx, \"GET\", `${name}/${m.id}/yaml`);\n io.stdout.write(yaml.data.endsWith(\"\\n\") ? yaml.data : yaml.data + \"\\n\");\n return;\n }\n if (ctx.json) {\n io.stdout.write(toJson(m) + \"\\n\");\n return;\n }\n const head = [\n [\"Key\", m.key],\n [\"Kind\", m.kind],\n [\"Name\", `${m.name_singular} / ${m.name_plural}`],\n [\"Id\", m.id],\n [\"Sites\", (m.sites ?? []).join(\", \") || \"-\"],\n [\"Active\", m.active ? \"yes\" : \"no\"],\n ];\n if (m.description) head.push([\"Description\", m.description]);\n if (m.entry_count !== undefined) head.push([\"Entries\", String(m.entry_count)]);\n const fields = m.fields.map((f) => [\n f.key,\n f.type,\n f.name,\n [f.required ? \"required\" : \"\", f.localized ? \"localized\" : \"\"].filter(Boolean).join(\", \"),\n ]);\n io.stdout.write(\n formatTable(head) + \"\\n\\n\" + formatTable(fields, [\"FIELD\", \"TYPE\", \"NAME\", \"\"]) + \"\\n\",\n );\n });\n\n return group;\n}\n","import { createClient, type PlenaryClient } from \"@plenary/client\";\nimport { requireBaseUrl, type Context } from \"../config.js\";\nimport { credentialHeaders, request } from \"../api/http.js\";\nimport { usageError } from \"../errors.js\";\n\ninterface Site {\n key: string;\n default_locale: string;\n}\n\nexport function requireSiteKey(ctx: Context): string {\n if (!ctx.siteKey) {\n throw usageError(\"no site key: pass --site, set PLENARY_SITE_KEY, or set siteKey in plenary.json\");\n }\n return ctx.siteKey;\n}\n\n/**\n * The locale every content read states. When none is configured it is the\n * site's default, which every authenticated principal may look up.\n */\nexport async function resolveLocale(ctx: Context, siteKey: string): Promise<string> {\n if (ctx.locale) return ctx.locale;\n const sites = await request<Site[]>(ctx, \"GET\", \"sites\");\n const site = sites.data.find((s) => s.key === siteKey);\n if (!site) throw usageError(`site \"${siteKey}\" not found on the instance`);\n return site.default_locale;\n}\n\n/**\n * A @plenary/client for this run: the content reads go through it. The\n * client only knows how to send an API key, so with a session instead the\n * fetch it is given swaps the key header for the bearer token.\n */\nexport async function contentClient(ctx: Context): Promise<PlenaryClient> {\n const siteKey = requireSiteKey(ctx);\n const baseUrl = requireBaseUrl(ctx);\n const auth = await credentialHeaders(ctx, \"required\");\n const apiKey = auth[\"X-API-KEY\"] ?? \"\";\n const fetch: typeof globalThis.fetch = apiKey\n ? ctx.io.fetch\n : (input, init = {}) => {\n const headers = new Headers(init.headers);\n headers.delete(\"X-API-KEY\");\n for (const [k, v] of Object.entries(auth)) headers.set(k, v);\n return ctx.io.fetch(input, { ...init, headers });\n };\n return createClient({ baseUrl, siteKey, apiKey, locale: await resolveLocale(ctx, siteKey), fetch });\n}\n","import type { ListOptions, ReadOptions, Sort, Where } from \"@plenary/client\";\nimport { usageError } from \"../errors.js\";\nimport { readData } from \"../input.js\";\n\n/** The flags shared by every listing command. */\nexport interface ListFlags {\n where?: string[];\n filters?: string;\n sort?: string[];\n limit?: string;\n offset?: string;\n include?: string;\n exclude?: string;\n hydrate?: string[];\n count?: boolean;\n}\n\nconst OPERATORS = new Set([\"$eq\", \"$ne\", \"$lt\", \"$lte\", \"$gt\", \"$gte\", \"$in\", \"$nin\", \"$like\", \"$ilike\", \"$is_null\"]);\n\n/**\n * `field=value` is equality; `field=$op:value` is one of the Content API's\n * operators, with `$in`/`$nin` taking a comma list and `$is_null` a boolean.\n */\nexport function parseWhere(specs: string[]): Where {\n const where: Where = {};\n for (const spec of specs) {\n const eq = spec.indexOf(\"=\");\n if (eq <= 0) throw usageError(`invalid --where \"${spec}\": expected field=value or field=$op:value`);\n const field = spec.slice(0, eq).trim();\n const raw = spec.slice(eq + 1);\n if (!raw.startsWith(\"$\")) {\n where[field] = raw;\n continue;\n }\n const colon = raw.indexOf(\":\");\n const op = colon === -1 ? raw : raw.slice(0, colon);\n const value = colon === -1 ? \"\" : raw.slice(colon + 1);\n if (!OPERATORS.has(op)) throw usageError(`invalid --where \"${spec}\": unknown operator ${op}`);\n let typed: unknown = value;\n if (op === \"$in\" || op === \"$nin\") typed = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n else if (op === \"$is_null\") typed = value === \"\" || value === \"true\";\n const existing = (where[field] ?? {}) as Record<string, unknown>;\n where[field] = { ...(typeof existing === \"object\" ? existing : {}), [op]: typed };\n }\n return where;\n}\n\n/** `field` or `field:desc`, in precedence order. */\nexport function parseSort(specs: string[]): Sort {\n const sort: Sort = {};\n for (const spec of specs) {\n const [field, dir = \"asc\"] = spec.split(\":\");\n if (!field || (dir !== \"asc\" && dir !== \"desc\")) {\n throw usageError(`invalid --sort \"${spec}\": expected field or field:asc|desc`);\n }\n sort[field] = dir;\n }\n return sort;\n}\n\nfunction parseHydrate(specs: string[]): ReadOptions[\"hydrate\"] {\n const out: Record<string, \"*\" | string[]> = {};\n for (const spec of specs) {\n const [field, list] = spec.split(\"=\");\n if (!field) throw usageError(`invalid --hydrate \"${spec}\"`);\n out[field] = list === undefined || list === \"*\" ? \"*\" : list.split(\",\");\n }\n return out;\n}\n\nfunction parseInt10(value: string | undefined, flag: string): number | undefined {\n if (value === undefined) return undefined;\n const n = Number(value);\n if (!Number.isInteger(n) || n < 0) throw usageError(`${flag} must be a non-negative integer`);\n return n;\n}\n\nexport async function toReadOptions(flags: ListFlags): Promise<ReadOptions> {\n const opts: ReadOptions = {};\n if (flags.include) opts.include = flags.include.split(\",\");\n if (flags.exclude) opts.exclude = flags.exclude.split(\",\");\n if (flags.hydrate?.length) opts.hydrate = parseHydrate(flags.hydrate);\n return opts;\n}\n\nexport async function toListOptions(flags: ListFlags, stdin: NodeJS.ReadableStream): Promise<ListOptions> {\n const opts: ListOptions = await toReadOptions(flags);\n if (flags.where?.length && flags.filters) throw usageError(\"--where and --filters are mutually exclusive\");\n if (flags.where?.length) opts.where = parseWhere(flags.where);\n if (flags.filters) opts.filters = (await readData(flags.filters, stdin, \"--filters\")) as ListOptions[\"filters\"];\n if (flags.sort?.length) opts.sort = parseSort(flags.sort);\n const limit = parseInt10(flags.limit, \"--limit\");\n const offset = parseInt10(flags.offset, \"--offset\");\n if (limit !== undefined) opts.limit = limit;\n if (offset !== undefined) opts.offset = offset;\n if (flags.count) opts.count = true;\n return opts;\n}\n","import type { Command } from \"commander\";\nimport type { Entry, ListOptions, PlenaryClient } from \"@plenary/client\";\nimport { resolveContext, type Context, type GlobalOptions, type Io } from \"../config.js\";\nimport { request } from \"../api/http.js\";\nimport { CliError, usageError } from \"../errors.js\";\nimport { confirm, readObject, readText } from \"../input.js\";\nimport { formatTable, toJson } from \"../output.js\";\nimport { contentClient, requireSiteKey } from \"../entries/client.js\";\nimport { toListOptions, toReadOptions, type ListFlags } from \"../entries/query.js\";\n\nfunction collect(value: string, previous: string[]): string[] {\n return [...previous, value];\n}\n\n/** The flags every listing command shares, declared once. */\nfunction withListFlags(cmd: Command): Command {\n return cmd\n .option(\"-w, --where <field=value>\", \"filter: field=value or field=$op:value (repeatable)\", collect, [])\n .option(\"--filters <json>\", \"a filter tree (inline JSON, @file, or -); excludes --where\")\n .option(\"-s, --sort <field[:dir]>\", \"sort field, asc unless :desc (repeatable, in precedence order)\", collect, [])\n .option(\"--limit <n>\", \"page size\")\n .option(\"--offset <n>\", \"rows to skip\")\n .option(\"--include <fields>\", \"comma-separated data fields to return\")\n .option(\"--exclude <fields>\", \"comma-separated data fields to omit\")\n .option(\"--hydrate <field[=subfields]>\", \"hydrate a reference field (repeatable)\", collect, [])\n .option(\"--count\", \"ask for the total and show it\");\n}\n\n/** The intrinsic flags a create or update accepts beside --data. */\ninterface WriteFlags {\n data?: string;\n slug?: string;\n folder?: string;\n note?: string;\n publishAt?: string;\n unpublishAt?: string;\n}\n\nfunction withWriteFlags(cmd: Command): Command {\n return cmd\n .option(\"-d, --data <json>\", \"the field values as a JSON object (inline, @file, or -)\")\n .option(\"--slug <slug>\")\n .option(\"--folder <id>\", \"content folder id\")\n .option(\"--note <text>\", \"revision note (required by models with Require Change Notes)\")\n .option(\"--publish-at <iso>\", \"schedule a publish\")\n .option(\"--unpublish-at <iso>\", \"schedule an unpublish\");\n}\n\n/** The write body the Content API takes. */\ninterface EntryBody {\n fields: Record<string, unknown>;\n slug?: string;\n locale?: string;\n folder_id?: string | null;\n publish_at?: string | null;\n unpublish_at?: string | null;\n note?: string;\n}\n\nfunction entryRow(e: Entry): string[] {\n return [e.id, e.status, e.slug ?? \"\", e.title ?? \"\", e.updated_at];\n}\n\nconst ENTRY_HEADER = [\"ID\", \"STATUS\", \"SLUG\", \"TITLE\", \"UPDATED\"];\n\nconst PAGE = 100;\n\n/** Every entry matching the options, one page at a time. */\nasync function* pageAll(client: PlenaryClient, model: string, opts: ListOptions): AsyncGenerator<Entry> {\n const limit = opts.limit ?? PAGE;\n let offset = opts.offset ?? 0;\n for (;;) {\n const { items } = await client.listEntries(model, { ...opts, limit, offset, count: false });\n for (const e of items) yield e;\n if (items.length < limit) return;\n offset += items.length;\n }\n}\n\nasync function publish(ctx: Context, id: string, action: \"publish\" | \"unpublish\"): Promise<Entry> {\n return (await request<Entry>(ctx, \"POST\", `content/${encodeURIComponent(id)}/${action}`)).data;\n}\n\nexport function registerEntries(program: Command, io: Io): void {\n const entries = program.command(\"entries\").description(\"Content entries\");\n\n withListFlags(entries.command(\"list\").description(\"List a model's entries\").argument(\"<model>\")).action(\n async (model: string, flags: ListFlags, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const client = await contentClient(ctx);\n const result = await client.listEntries(model, await toListOptions(flags, io.stdin));\n if (ctx.json) {\n io.stdout.write(toJson(result) + \"\\n\");\n return;\n }\n io.stdout.write(formatTable(result.items.map(entryRow), ENTRY_HEADER) + \"\\n\");\n if (result.total !== undefined) io.stdout.write(`${result.items.length} of ${result.total}\\n`);\n },\n );\n\n entries\n .command(\"get\")\n .description(\"Print one entry as JSON; omit the slug for a singleton\")\n .argument(\"<model>\")\n .argument(\"[slug-or-id]\")\n .option(\"--include <fields>\")\n .option(\"--exclude <fields>\")\n .option(\"--hydrate <field[=subfields]>\", \"hydrate a reference field (repeatable)\", collect, [])\n .action(async (model: string, slug: string | undefined, flags: ListFlags, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const client = await contentClient(ctx);\n const opts = await toReadOptions(flags);\n const entry = slug === undefined ? await client.getSingleton(model, opts) : await client.getEntry(model, slug, opts);\n io.stdout.write(toJson(entry) + \"\\n\");\n });\n\n withWriteFlags(entries.command(\"create\").description(\"Create a draft entry\").argument(\"<model>\"))\n .option(\"--publish\", \"publish it right after creating\")\n .action(async (model: string, flags: WriteFlags & { publish?: boolean }, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const siteKey = requireSiteKey(ctx);\n if (flags.data === undefined) throw usageError(\"--data is required\");\n const body: EntryBody = { fields: await readObject(flags.data, io.stdin) };\n if (ctx.locale) body.locale = ctx.locale;\n applyWriteFlags(body, flags);\n let entry = (\n await request<Entry>(ctx, \"POST\", `content/${encodeURIComponent(model)}`, { query: { site_key: siteKey }, body })\n ).data;\n if (flags.publish) entry = await publish(ctx, entry.id, \"publish\");\n report(ctx, entry, \"created\");\n });\n\n withWriteFlags(\n entries\n .command(\"update\")\n .description(\"Update an entry: --data is merged into its fields (a null removes one)\")\n .argument(\"<model>\")\n .argument(\"<slug-or-id>\"),\n ).action(async (model: string, slug: string, flags: WriteFlags, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const client = await contentClient(ctx);\n const current = await client.getEntry(model, slug);\n const fields: Record<string, unknown> = { ...current.data };\n if (flags.data !== undefined) {\n for (const [k, v] of Object.entries(await readObject(flags.data, io.stdin))) {\n if (v === null) delete fields[k];\n else fields[k] = v;\n }\n }\n // PUT replaces the whole entry, so everything not being changed is carried.\n const body: EntryBody = {\n fields,\n slug: current.slug ?? undefined,\n locale: current.locale ?? undefined,\n folder_id: current.folder_id,\n publish_at: current.publish_at,\n unpublish_at: current.unpublish_at,\n };\n applyWriteFlags(body, flags);\n const entry = (await request<Entry>(ctx, \"PUT\", `content/${encodeURIComponent(current.id)}`, { body })).data;\n report(ctx, entry, \"updated\");\n });\n\n entries\n .command(\"delete\")\n .description(\"Delete an entry (recoverable from history while the model tracks revisions)\")\n .argument(\"<id>\")\n .option(\"--note <text>\", \"revision note\")\n .option(\"-y, --yes\", \"do not ask\")\n .action(async (id: string, flags: { note?: string; yes?: boolean }, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n await confirm(io, `Delete entry ${id}?`, Boolean(flags.yes));\n await request(ctx, \"DELETE\", `content/${encodeURIComponent(id)}`, { query: { note: flags.note } });\n if (ctx.json) io.stdout.write(toJson({ id, deleted: true }) + \"\\n\");\n else io.stdout.write(`deleted ${id}\\n`);\n });\n\n for (const action of [\"publish\", \"unpublish\"] as const) {\n entries\n .command(action)\n .description(`${action === \"publish\" ? \"Publish\" : \"Unpublish\"} an entry now`)\n .argument(\"<id>\")\n .action(async (id: string, _flags: unknown, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n report(ctx, await publish(ctx, id, action), action === \"publish\" ? \"published\" : \"unpublished\");\n });\n }\n\n withListFlags(\n entries.command(\"export\").description(\"Write every matching entry to stdout as NDJSON\").argument(\"<model>\"),\n ).action(async (model: string, flags: ListFlags, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const client = await contentClient(ctx);\n for await (const e of pageAll(client, model, await toListOptions(flags, io.stdin))) {\n io.stdout.write(JSON.stringify(e) + \"\\n\");\n }\n });\n\n entries\n .command(\"import\")\n .description(\"Create one entry per NDJSON line (exported entries or {fields, slug, …} bodies)\")\n .argument(\"<model>\")\n .argument(\"<file>\", \"a file, or - for stdin\")\n .option(\"--publish\", \"publish each entry after creating it\")\n .addHelpText(\n \"after\",\n `\nEvery line is tried; a line that fails is reported with its number and the\nrun continues, exiting 1 at the end if any failed.`,\n )\n .action(async (model: string, file: string, flags: { publish?: boolean }, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const siteKey = requireSiteKey(ctx);\n const text = await readText(file === \"-\" ? \"-\" : `@${file}`, io.stdin);\n let failed = 0;\n let n = 0;\n for (const raw of text.split(\"\\n\")) {\n const line = raw.trim();\n if (line === \"\") continue;\n n++;\n try {\n const body = importBody(JSON.parse(line) as Record<string, unknown>, ctx);\n let entry = (\n await request<Entry>(ctx, \"POST\", `content/${encodeURIComponent(model)}`, {\n query: { site_key: siteKey },\n body,\n })\n ).data;\n if (flags.publish) entry = await publish(ctx, entry.id, \"publish\");\n io.stdout.write(`ok ${entry.id}${entry.slug ? ` ${entry.slug}` : \"\"}\\n`);\n } catch (err) {\n failed++;\n const why = err instanceof Error ? (err as { code?: string }).code ?? err.message : String(err);\n io.stdout.write(`fail line ${n}: ${why}\\n`);\n }\n }\n io.stderr.write(`${n - failed} created, ${failed} failed\\n`);\n if (failed) throw new CliError(\"\", 1);\n });\n}\n\nfunction applyWriteFlags(body: EntryBody, flags: WriteFlags): void {\n if (flags.slug !== undefined) body.slug = flags.slug;\n if (flags.folder !== undefined) body.folder_id = flags.folder;\n if (flags.publishAt !== undefined) body.publish_at = flags.publishAt;\n if (flags.unpublishAt !== undefined) body.unpublish_at = flags.unpublishAt;\n if (flags.note !== undefined) body.note = flags.note;\n}\n\n/** An exported entry (`data`) or a bare write body (`fields`) → the write body. */\nfunction importBody(line: Record<string, unknown>, ctx: Context): EntryBody {\n if (\"fields\" in line) return line as unknown as EntryBody;\n if (!(\"data\" in line)) throw usageError(\"expected an object with fields or data\");\n const e = line as Partial<Entry>;\n const body: EntryBody = { fields: (e.data ?? {}) as Record<string, unknown> };\n if (e.slug) body.slug = e.slug;\n if (e.locale ?? ctx.locale) body.locale = e.locale ?? ctx.locale;\n if (e.folder_id) body.folder_id = e.folder_id;\n if (e.publish_at) body.publish_at = e.publish_at;\n if (e.unpublish_at) body.unpublish_at = e.unpublish_at;\n return body;\n}\n\nfunction report(ctx: Context, entry: Entry, verb: string): void {\n if (ctx.json) ctx.io.stdout.write(toJson(entry) + \"\\n\");\n else ctx.io.stdout.write(`${verb} ${entry.id}${entry.slug ? ` ${entry.slug}` : \"\"} (${entry.status})\\n`);\n}\n","import type { Command } from \"commander\";\nimport { resolveContext, type Context, type GlobalOptions, type Io } from \"../config.js\";\nimport { request } from \"../api/http.js\";\nimport { formatTable, toJson } from \"../output.js\";\nimport { toListOptions, type ListFlags } from \"../entries/query.js\";\nimport type { ListOptions } from \"@plenary/client\";\n\ninterface FormEntry {\n id: string;\n form_key: string;\n site_key: string;\n status: string;\n created_at: string;\n data: Record<string, unknown>;\n}\n\nfunction collect(value: string, previous: string[]): string[] {\n return [...previous, value];\n}\n\n/**\n * Form-entry lists take the Content API's query engine, but not through\n * @plenary/client (which is the public delivery surface), so the options are\n * compiled to a query string here with the same rules.\n */\nfunction toQuery(ctx: Context, opts: ListOptions): Record<string, string> {\n const q: Record<string, string> = {};\n if (ctx.siteKey) q.site_key = ctx.siteKey;\n for (const [field, value] of Object.entries(opts.where ?? {})) {\n if (typeof value === \"object\" && value !== null) {\n for (const [op, v] of Object.entries(value as Record<string, unknown>)) {\n q[`where:${field}.${op}`] = Array.isArray(v) ? v.join(\",\") : String(v);\n }\n } else {\n q[`where:${field}`] = String(value);\n }\n }\n if (opts.filters) q.filters = JSON.stringify(opts.filters);\n for (const [field, dir] of Object.entries(opts.sort ?? {})) q[`sort:${field}`] = dir;\n if (opts.limit !== undefined) q.limit = String(opts.limit);\n if (opts.offset !== undefined) q.offset = String(opts.offset);\n if (opts.count) q.count = \"true\";\n return q;\n}\n\nconst PAGE = 100;\n\nexport function registerFormEntries(forms: Command, io: Io): void {\n const entries = forms.command(\"entries\").description(\"Form entries (what visitors submitted)\");\n\n const listFlags = (cmd: Command) =>\n cmd\n .option(\"-w, --where <field=value>\", \"filter: field=value or field=$op:value (repeatable)\", collect, [])\n .option(\"--filters <json>\", \"a filter tree (inline JSON, @file, or -)\")\n .option(\"-s, --sort <field[:dir]>\", \"sort field, asc unless :desc (repeatable)\", collect, [])\n .option(\"--limit <n>\")\n .option(\"--offset <n>\")\n .option(\"--count\", \"ask for the total and show it\");\n\n listFlags(entries.command(\"list\").description(\"List a form's entries\").argument(\"<form>\")).action(\n async (form: string, flags: ListFlags, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const opts = await toListOptions(flags, io.stdin);\n const res = await request<FormEntry[]>(ctx, \"GET\", `forms/${encodeURIComponent(form)}/entries`, {\n query: toQuery(ctx, opts),\n });\n const total = res.headers.get(\"X-Total-Count\");\n if (ctx.json) {\n io.stdout.write(toJson({ items: res.data, ...(total !== null ? { total: Number(total) } : {}) }) + \"\\n\");\n return;\n }\n const rows = res.data.map((e) => [e.id, e.status, e.site_key, e.created_at, summary(e.data)]);\n io.stdout.write(formatTable(rows, [\"ID\", \"STATUS\", \"SITE\", \"CREATED\", \"DATA\"]) + \"\\n\");\n if (total !== null) io.stdout.write(`${res.data.length} of ${total}\\n`);\n },\n );\n\n listFlags(entries.command(\"export\").description(\"Write every matching entry to stdout as NDJSON\").argument(\"<form>\")).action(\n async (form: string, flags: ListFlags, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const opts = await toListOptions(flags, io.stdin);\n const limit = opts.limit ?? PAGE;\n let offset = opts.offset ?? 0;\n for (;;) {\n const res = await request<FormEntry[]>(ctx, \"GET\", `forms/${encodeURIComponent(form)}/entries`, {\n query: toQuery(ctx, { ...opts, limit, offset, count: false }),\n });\n for (const e of res.data) io.stdout.write(JSON.stringify(e) + \"\\n\");\n if (res.data.length < limit) return;\n offset += res.data.length;\n }\n },\n );\n}\n\n/** The first few values, for a glance at what was submitted. */\nfunction summary(data: Record<string, unknown>): string {\n return Object.entries(data)\n .slice(0, 3)\n .map(([k, v]) => `${k}=${typeof v === \"string\" ? v : JSON.stringify(v)}`)\n .join(\" \");\n}\n","import { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { Command } from \"commander\";\nimport { resolveContext, type GlobalOptions, type Io } from \"../config.js\";\nimport { request } from \"../api/http.js\";\nimport { CliError, usageError } from \"../errors.js\";\nimport { formatTable, toJson } from \"../output.js\";\n\ninterface MediaItem {\n media_id: string;\n media_type: string;\n mime_type: string;\n file_name: string;\n file_size: number;\n path: string;\n visibility: string;\n original_url: string;\n created_at: string;\n}\n\nfunction size(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nexport function registerMedia(program: Command, io: Io): void {\n const media = program.command(\"media\").description(\"Media library\");\n\n media\n .command(\"upload\")\n .description(\"Upload one or more files\")\n .argument(\"<files...>\")\n .option(\"--folder <id>\", \"media folder id\")\n .option(\"--private\", \"store as a private asset\")\n .action(async (files: string[], flags: { folder?: string; private?: boolean }, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const uploaded: MediaItem[] = [];\n let failed = 0;\n for (const file of files) {\n let bytes: Buffer;\n try {\n bytes = readFileSync(file);\n } catch (err) {\n throw usageError(`cannot read ${file}: ${(err as Error).message}`);\n }\n const form = new FormData();\n form.append(\"upload_file\", new Blob([new Uint8Array(bytes)]), path.basename(file));\n if (flags.folder) form.append(\"folder_id\", flags.folder);\n if (flags.private) form.append(\"visibility\", \"private\");\n try {\n const res = await request<MediaItem>(ctx, \"POST\", \"media\", { form });\n uploaded.push(res.data);\n if (!ctx.json) io.stdout.write(`${res.data.media_id} ${res.data.file_name}\\n`);\n } catch (err) {\n if (files.length === 1) throw err;\n failed++;\n const code = (err as { code?: string }).code ?? (err as Error).message;\n io.stdout.write(`fail ${file}: ${code}\\n`);\n }\n }\n if (ctx.json) io.stdout.write(toJson(uploaded) + \"\\n\");\n if (failed) throw new CliError(\"\", 1);\n });\n\n media\n .command(\"list\")\n .description(\"List media\")\n .option(\"--search <text>\", \"match file names and captions\")\n .option(\"--path <prefix>\", \"only assets under this folder path\")\n .option(\"--limit <n>\")\n .option(\"--page <n>\")\n .action(async (flags: { search?: string; path?: string; limit?: string; page?: string }, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const res = await request<MediaItem[]>(ctx, \"GET\", \"media\", {\n query: { search: flags.search, path_prefix: flags.path, limit: flags.limit, page: flags.page },\n });\n if (ctx.json) {\n io.stdout.write(toJson(res.data) + \"\\n\");\n return;\n }\n const rows = res.data.map((m) => [m.media_id, m.media_type, m.file_name, size(m.file_size), m.path, m.visibility]);\n io.stdout.write(formatTable(rows, [\"ID\", \"TYPE\", \"FILE\", \"SIZE\", \"PATH\", \"VISIBILITY\"]) + \"\\n\");\n });\n\n media\n .command(\"get\")\n .description(\"Print one media item as JSON\")\n .argument(\"<id>\")\n .action(async (id: string, _flags: unknown, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const res = await request(ctx, \"GET\", `media/${encodeURIComponent(id)}`);\n io.stdout.write(toJson(res.data) + \"\\n\");\n });\n}\n","import path from \"node:path\";\nimport type { Command } from \"commander\";\nimport { resolveContext, type Context, type GlobalOptions, type Io } from \"../config.js\";\nimport { PlenaryError } from \"@plenary/client\";\nimport { request, type ApiResponse, type RequestOptions } from \"../api/http.js\";\nimport { usageError } from \"../errors.js\";\nimport { confirm } from \"../input.js\";\nimport { toJson } from \"../output.js\";\nimport { filterKinds, parseKinds, readTree, writeTree, type Kind, type YamlFile } from \"../metadata/dir.js\";\nimport { formatPlan, type ImportResult } from \"../metadata/plan.js\";\n\ninterface DirOption {\n dir?: string;\n only?: string;\n verbose?: boolean;\n dryRun?: boolean;\n prune?: boolean;\n yes?: boolean;\n}\n\nfunction kindsOf(opts: DirOption): Kind[] {\n try {\n return parseKinds(opts.only);\n } catch (err) {\n throw usageError(`--only: ${(err as Error).message}`);\n }\n}\n\n/** `--dir` is relative to the cwd; the configured directory to the config file. */\nfunction treeRoot(ctx: Context, opts: DirOption): string {\n return opts.dir ? path.resolve(ctx.io.cwd, opts.dir) : path.resolve(ctx.projectRoot, ctx.metadataDir);\n}\n\nfunction readTreeOrFail(root: string, kinds: Kind[]): YamlFile[] {\n const files = filterKinds(readTree(root), kinds);\n if (files.length === 0) throw usageError(`no YAML files under ${root}/{${kinds.join(\",\")}}`);\n return files;\n}\n\nconst OLDER_SERVER =\n \"this server predates the whole-tree metadata endpoints: it can sync models and forms only\";\n\n/**\n * The whole-tree route, falling back to the models-only one a server from\n * without them has, so an older instance keeps working for models and\n * forms. Roles, sites and --prune have nowhere to go there and are refused\n * with a message rather than a bare 404.\n */\nasync function metadataRequest<T>(\n ctx: Context,\n method: \"GET\" | \"POST\",\n opts: RequestOptions,\n needsWholeTree: boolean,\n): Promise<ApiResponse<T>> {\n const path = method === \"GET\" ? \"metadata\" : \"metadata/import\";\n try {\n return await request<T>(ctx, method, path, opts);\n } catch (err) {\n if (!(err instanceof PlenaryError) || err.status !== 404 || err.code !== \"http_404\") throw err;\n if (needsWholeTree) throw usageError(OLDER_SERVER);\n const fallback = method === \"GET\" ? \"metadata/models\" : \"metadata/models/import\";\n return request<T>(ctx, method, fallback, opts);\n }\n}\n\n/**\n * Both diff and push: the plan is always previewed first, and a push with\n * --prune is confirmed against that preview before anything is deleted.\n */\nasync function runImport(ctx: Context, root: string, opts: DirOption, apply: boolean): Promise<void> {\n const kinds = kindsOf(opts);\n const files = readTreeOrFail(root, kinds);\n const prune = Boolean(opts.prune);\n const body = { files, apply: false, prune };\n const wholeTree = prune || files.some((f) => !/^(models|forms)\\//.test(f.path));\n let res = await metadataRequest<ImportResult>(ctx, \"POST\", { body }, wholeTree);\n const deletes = res.data.changes.filter((c) => c.action === \"delete\");\n\n if (apply) {\n if (deletes.length > 0) {\n if (!ctx.json) ctx.io.stdout.write(formatPlan(res.data, Boolean(opts.verbose)) + \"\\n\");\n await confirm(ctx.io, `Delete ${deletes.length} ${deletes.length === 1 ? \"entity\" : \"entities\"} from the instance?`, Boolean(opts.yes));\n }\n res = await metadataRequest<ImportResult>(ctx, \"POST\", { body: { ...body, apply: true } }, wholeTree);\n }\n if (ctx.json) ctx.io.stdout.write(toJson(res.data) + \"\\n\");\n else ctx.io.stdout.write(formatPlan(res.data, Boolean(opts.verbose)) + \"\\n\");\n}\n\nconst onlyOption = [\"--only <kinds>\", \"comma list of models, forms, roles, sites (default: all)\"] as const;\n\nexport function registerMetadata(program: Command, io: Io): void {\n const metadata = program\n .command(\"metadata\")\n .description(\"Keep a directory of model and form YAML in step with the instance\")\n .addHelpText(\n \"after\",\n `\nThe tree is models/, forms/, roles/ and sites/ under the metadata directory\n(\"metadataDir\" in plenary.json, default ./plenary), one <key>.yaml per\nentity. Models and forms need an API key or a session; roles and sites need\na user session (plenary login). See docs/CLI.md.`,\n );\n\n metadata\n .command(\"pull\")\n .description(\"Write every model, form, role and site the credential may read into the directory\")\n .option(\"--dir <path>\", \"metadata directory (default: the configured one)\")\n .option(...onlyOption)\n .action(async (opts: DirOption, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const root = treeRoot(ctx, opts);\n const kinds = kindsOf(opts);\n const wholeTree = kinds.some((k) => k === \"roles\" || k === \"sites\") && Boolean(opts.only);\n const res = await metadataRequest<{ files: YamlFile[]; omitted?: string[] }>(\n ctx,\n \"GET\",\n { query: { only: kinds.join(\",\") } },\n wholeTree,\n );\n const result = writeTree(root, res.data.files, kinds);\n const omitted = res.data.omitted ?? [];\n if (ctx.json) {\n io.stdout.write(toJson({ dir: root, ...result, omitted }) + \"\\n\");\n return;\n }\n io.stdout.write(`wrote ${result.written.length} file${result.written.length === 1 ? \"\" : \"s\"} to ${root}\\n`);\n if (omitted.length) {\n io.stderr.write(`not included, the credential may not read them: ${omitted.join(\", \")}\\n`);\n }\n if (result.written.length === 0 && omitted.length === 0) {\n // The server answers a key that may read no models with an empty tree,\n // not a refusal, so say what the likely cause is.\n io.stderr.write(\"the server sent no models: the key may lack content:models:read (a public key never has it)\\n\");\n }\n if (result.stale.length) {\n io.stdout.write(`not on the server (left in place):\\n${result.stale.map((p) => ` ${p}`).join(\"\\n\")}\\n`);\n }\n });\n\n metadata\n .command(\"diff\")\n .description(\"Preview what push would change, without writing anything\")\n .option(\"--dir <path>\", \"metadata directory (default: the configured one)\")\n .option(...onlyOption)\n .option(\"--prune\", \"include what push --prune would delete\")\n .option(\"--verbose\", \"list unchanged entities too\")\n .action(async (opts: DirOption, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n await runImport(ctx, treeRoot(ctx, opts), opts, false);\n });\n\n metadata\n .command(\"push\")\n .description(\"Apply the directory to the instance (creates and updates; deletes only with --prune)\")\n .option(\"--dir <path>\", \"metadata directory (default: the configured one)\")\n .option(...onlyOption)\n .option(\"--prune\", \"also delete entities absent from the directory, within the kinds it holds\")\n .option(\"-y, --yes\", \"do not ask before pruning\")\n .option(\"--dry-run\", \"same as diff\")\n .option(\"--verbose\", \"list unchanged entities too\")\n .addHelpText(\n \"after\",\n `\n--prune deletes only within the kinds present in the directory: a tree with\nno roles/ cannot delete a role. System-owned roles are never touched and are\nreported as skipped. The plan is shown and confirmed before anything is\ndeleted; -y skips the question, and a run with no terminal needs it.`,\n )\n .action(async (opts: DirOption, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n await runImport(ctx, treeRoot(ctx, opts), opts, !opts.dryRun);\n });\n}\n","import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\n\n/** One file of a metadata tree, `path` relative to the tree's root. */\nexport interface YamlFile {\n path: string;\n content: string;\n}\n\n/** The directories the server reads and writes. */\nexport const MANAGED_DIRS = [\"models\", \"forms\", \"roles\", \"sites\"] as const;\nexport type Kind = (typeof MANAGED_DIRS)[number];\n\n/** `--only models,roles` → the kinds it names; empty or \"all\" → every kind. */\nexport function parseKinds(spec: string | undefined): Kind[] {\n if (!spec || spec === \"all\") return [...MANAGED_DIRS];\n const out: Kind[] = [];\n for (const raw of spec.split(\",\")) {\n const k = raw.trim() as Kind;\n if (!MANAGED_DIRS.includes(k)) throw new Error(`unknown kind \"${k}\" (want ${MANAGED_DIRS.join(\", \")} or all)`);\n if (!out.includes(k)) out.push(k);\n }\n return out;\n}\n\n/** Only the files under the named kinds' directories. */\nexport function filterKinds(files: YamlFile[], kinds: Kind[]): YamlFile[] {\n return files.filter((f) => kinds.includes(f.path.split(\"/\")[0] as Kind));\n}\n\n/** Every `models/*.yaml` and `forms/*.yaml` directly under `root`, sorted by path. */\nexport function readTree(root: string): YamlFile[] {\n const out: YamlFile[] = [];\n for (const rel of managedFiles(root)) {\n out.push({ path: rel, content: readFileSync(path.join(root, rel), \"utf8\") });\n }\n return out;\n}\n\nexport interface WriteResult {\n written: string[];\n /** Managed files already on disk that the server did not send — reported, never deleted. */\n stale: string[];\n}\n\n/**\n * Writes the server's files into `root`, creating directories as needed.\n * Stale files are only looked for under `kinds`, since a pull of models\n * alone says nothing about the roles on disk.\n */\nexport function writeTree(root: string, files: YamlFile[], kinds: Kind[] = [...MANAGED_DIRS]): WriteResult {\n const before = new Set(managedFiles(root).filter((p) => kinds.includes(p.split(\"/\")[0] as Kind)));\n const written: string[] = [];\n for (const f of [...files].sort((a, b) => a.path.localeCompare(b.path))) {\n if (!isTreePath(f.path)) continue;\n const abs = path.join(root, f.path);\n mkdirSync(path.dirname(abs), { recursive: true });\n writeFileSync(abs, f.content);\n written.push(f.path);\n before.delete(f.path);\n }\n return { written, stale: [...before].sort() };\n}\n\n/** `models/x.yaml` or `forms/x.yaml`, directly under the root; nothing else. */\nexport function isTreePath(p: string): boolean {\n const parts = p.split(\"/\");\n return (\n parts.length === 2 &&\n (MANAGED_DIRS as readonly string[]).includes(parts[0] as string) &&\n (parts[1] as string).endsWith(\".yaml\")\n );\n}\n\nfunction managedFiles(root: string): string[] {\n const out: string[] = [];\n for (const dir of MANAGED_DIRS) {\n const abs = path.join(root, dir);\n if (!existsSync(abs)) continue;\n for (const name of readdirSync(abs).sort()) {\n if (name.endsWith(\".yaml\")) out.push(`${dir}/${name}`);\n }\n }\n return out.sort();\n}\n","/** One row of the server's import plan. */\nexport interface ImportChange {\n key: string;\n kind: string;\n action: \"create\" | \"update\" | \"noop\" | \"delete\" | \"skip\";\n detail?: {\n fields_added: string[];\n fields_removed: string[];\n fields_changed: string[];\n attributes_changed: boolean;\n transformers_changed: boolean;\n };\n}\n\nexport interface ImportResult {\n applied: boolean;\n changes: ImportChange[];\n}\n\n/**\n * The plan as lines: one per create/update (noops too with `verbose`), then a\n * summary. `applied` picks the tense of the summary.\n */\nexport function formatPlan(result: ImportResult, verbose = false): string {\n const lines: string[] = [];\n const n = { create: 0, update: 0, delete: 0, skip: 0, noop: 0 };\n // Deletes first: they are what a person scanning a --prune plan must see.\n const ordered = [...result.changes].sort((a, b) => Number(b.action === \"delete\") - Number(a.action === \"delete\"));\n for (const c of ordered) {\n n[c.action]++;\n if (c.action === \"noop\" && !verbose) continue;\n const label = c.action === \"noop\" ? \"unchanged\" : c.action === \"skip\" ? \"skipped\" : c.action;\n const note = c.action === \"skip\" ? \" (system-owned)\" : detail(c);\n lines.push(`${label.padEnd(9)} ${c.kind.padEnd(10)} ${c.key}${note}`);\n }\n const parts = [`${n.create} to create`, `${n.update} to update`];\n if (n.delete) parts.push(`${n.delete} to delete`);\n if (n.skip) parts.push(`${n.skip} skipped`);\n parts.push(`${n.noop} unchanged`);\n if (n.create + n.update + n.delete === 0) {\n lines.push(`No changes: ${n.noop} unchanged${n.skip ? `, ${n.skip} skipped` : \"\"}.`);\n } else {\n lines.push(`${result.applied ? \"Applied\" : \"Plan\"}: ${parts.join(\", \")}.`);\n }\n return lines.join(\"\\n\");\n}\n\nfunction detail(c: ImportChange): string {\n const d = c.detail;\n if (!d) return \"\";\n const parts: string[] = [];\n if (d.fields_added.length) parts.push(`+${d.fields_added.join(\",\")}`);\n if (d.fields_changed.length) parts.push(`~${d.fields_changed.join(\",\")}`);\n if (d.fields_removed.length) parts.push(`-${d.fields_removed.join(\",\")}`);\n if (d.attributes_changed) parts.push(\"settings\");\n if (d.transformers_changed) parts.push(\"transformers\");\n return parts.length ? ` (${parts.join(\" \")})` : \"\";\n}\n","import { existsSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { createInterface } from \"node:readline/promises\";\nimport type { Command } from \"commander\";\nimport {\n CONFIG_FILE,\n DEFAULT_METADATA_DIR,\n resolveContext,\n type GlobalOptions,\n type Io,\n type ProjectConfig,\n} from \"../config.js\";\nimport { usageError } from \"../errors.js\";\n\nexport function registerInit(program: Command, io: Io): void {\n program\n .command(\"init\")\n .description(`Write a ${CONFIG_FILE} for this project (never a credential)`)\n .option(\"--dir <path>\", \"metadata directory, relative to the config file\", DEFAULT_METADATA_DIR)\n .option(\"-f, --force\", `overwrite an existing ${CONFIG_FILE}`)\n .addHelpText(\n \"after\",\n `\nThe base URL, site and locale come from --base-url, --site and --locale (or\ntheir PLENARY_* variables); anything missing is prompted for on a terminal.`,\n )\n .action(async (opts: { dir: string; force?: boolean }, cmd: Command) => {\n const target = path.join(io.cwd, CONFIG_FILE);\n if (existsSync(target) && !opts.force) {\n throw usageError(`${target} already exists (pass --force to overwrite)`);\n }\n const globals = cmd.optsWithGlobals<GlobalOptions>();\n // Read what the environment already says, but not a parent's plenary.json:\n // init describes this directory, not one above it.\n const ctx = resolveContext({ ...globals, config: undefined }, { ...io, cwd: path.parse(io.cwd).root });\n\n const baseUrl = globals.baseUrl ?? ctx.baseUrl ?? (await ask(io, \"Base URL (https://cms.example.com)\"));\n if (!baseUrl) throw usageError(\"a base URL is required: pass --base-url or set PLENARY_BASE_URL\");\n const siteKey = globals.site ?? ctx.siteKey ?? (await ask(io, \"Site key\", \"default\"));\n const locale = globals.locale ?? ctx.locale ?? (await ask(io, \"Locale\", \"en-us\"));\n\n const config: ProjectConfig = { baseUrl: baseUrl.replace(/\\/+$/, \"\") };\n if (siteKey) config.siteKey = siteKey;\n if (locale) config.locale = locale;\n if (opts.dir !== DEFAULT_METADATA_DIR) config.metadataDir = opts.dir;\n\n writeFileSync(target, JSON.stringify(config, null, 2) + \"\\n\");\n io.stdout.write(`wrote ${target}\\n`);\n });\n}\n\n/** Prompts on a terminal; returns the default (or undefined) without one. */\nasync function ask(io: Io, label: string, fallback?: string): Promise<string | undefined> {\n if (!io.isTTY) return fallback;\n const rl = createInterface({ input: io.stdin, output: io.stderr });\n try {\n const answer = (await rl.question(fallback ? `${label} [${fallback}]: ` : `${label}: `)).trim();\n return answer === \"\" ? fallback : answer;\n } finally {\n rl.close();\n }\n}\n","import type { Command } from \"commander\";\nimport { PlenaryError } from \"@plenary/client\";\nimport { resolveContext, type GlobalOptions, type Io } from \"../config.js\";\nimport { credentialHeaders, request } from \"../api/http.js\";\nimport { CliError } from \"../errors.js\";\nimport { toJson } from \"../output.js\";\n\ninterface Health {\n status: string;\n database: string;\n version: string;\n edition: string;\n license?: string;\n}\n\ninterface MeGrant {\n key: string;\n site_key?: string;\n content_model_id?: string;\n source: string;\n}\n\ntype Me =\n | { principal: \"api_key\"; key_id: string; key_type: string; name: string; grants: MeGrant[]; sites: string[] }\n | { principal: \"user\"; user_id: string; role: string; role_name?: string; grants: MeGrant[] };\n\nexport function registerStatus(program: Command, io: Io): void {\n program\n .command(\"status\")\n .description(\"Show the instance's health and which credential this run holds\")\n .action(async (_opts: unknown, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const health = await request<Health>(ctx, \"GET\", \"/api/v1/health\", { auth: \"none\", allowError: true });\n\n let me: Me | undefined;\n let credentialError: PlenaryError | undefined;\n // A server without API-key support on /auth/me answers /auth/me with 403 for a key it\n // accepted: the key authenticated, the server just cannot describe it.\n let undescribed = false;\n const headers = await credentialHeaders(ctx, \"optional\");\n if (Object.keys(headers).length > 0) {\n try {\n me = (await request<Me>(ctx, \"GET\", \"/api/v1/auth/me\", { auth: \"none\", headers })).data;\n } catch (err) {\n if (!(err instanceof PlenaryError)) throw err;\n if (err.status === 403) undescribed = true;\n else credentialError = err;\n }\n }\n\n const failed = !health.ok || credentialError !== undefined;\n if (ctx.json) {\n io.stdout.write(\n toJson({\n base_url: ctx.baseUrl,\n health: health.data,\n credential: me ?? null,\n credential_error: credentialError ? { status: credentialError.status, code: credentialError.code } : null,\n }) + \"\\n\",\n );\n if (failed) throw new CliError(\"\", 1);\n return;\n }\n\n const lines = [`Instance ${ctx.baseUrl}`];\n if (health.ok || (health.status === 503 && typeof health.data === \"object\")) {\n const h = health.data;\n lines.push(`Version ${h.version} (${h.edition})`);\n lines.push(`Status ${h.status}, database ${h.database}${h.license ? `, license ${h.license}` : \"\"}`);\n } else {\n lines.push(`Status unreachable (HTTP ${health.status})`);\n }\n if (me?.principal === \"api_key\") {\n lines.push(`Credential ${me.key_type} API key \"${me.name}\" (${me.grants.length} grant${me.grants.length === 1 ? \"\" : \"s\"}${\n me.sites.length ? `, sites ${me.sites.join(\", \")}` : \"\"\n })`);\n } else if (me?.principal === \"user\") {\n lines.push(`Credential user session (stored login), role ${me.role_name ?? me.role}`);\n } else if (credentialError) {\n lines.push(`Credential rejected: ${credentialError.code} (HTTP ${credentialError.status})`);\n } else if (undescribed) {\n lines.push(\"Credential API key accepted (this server predates API-key support on /auth/me and cannot describe the key)\");\n } else {\n lines.push(\"Credential none (set PLENARY_API_KEY, pass --api-key, or run `plenary login`)\");\n }\n if (ctx.configPath) lines.push(`Config ${ctx.configPath}`);\n io.stdout.write(lines.join(\"\\n\") + \"\\n\");\n // The report itself is the message; the exit code is the only extra signal.\n if (failed) throw new CliError(\"\", 1);\n });\n}\n","import { run } from \"./cli.js\";\n\nrun(process.argv.slice(2), {\n stdout: process.stdout,\n stderr: process.stderr,\n stdin: process.stdin,\n env: process.env,\n cwd: process.cwd(),\n fetch: globalThis.fetch,\n isTTY: Boolean(process.stdin.isTTY),\n}).then((code) => {\n process.exitCode = code;\n});\n"],"mappings":"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","names":["readFileSync","CommanderError","existsSync","readFileSync","path","path","existsSync","readFileSync","token","path","readFileSync","readFileSync","errorFromResponse","collect","path","collect","collect","PAGE","readFileSync","path","readFileSync","path","path","PlenaryError","existsSync","mkdirSync","readFileSync","writeFileSync","path","path","PlenaryError","existsSync","writeFileSync","path","createInterface","path","existsSync","writeFileSync","createInterface","PlenaryError","PlenaryError","readFileSync","CommanderError"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/output.ts","../src/errors.ts","../src/config.ts","../src/api/http.ts","../src/session.ts","../src/input.ts","../src/commands/admin.ts","../src/commands/api.ts","../src/commands/auth.ts","../src/commands/catalog.ts","../src/entries/client.ts","../src/entries/query.ts","../src/commands/entries.ts","../src/commands/formentries.ts","../src/commands/media.ts","../src/commands/metadata.ts","../src/metadata/dir.ts","../src/metadata/plan.ts","../src/commands/init.ts","../src/commands/status.ts","../src/index.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { Command, CommanderError } from \"commander\";\nimport type { Io } from \"./config.js\";\nimport { describeError, exitCodeFor } from \"./output.js\";\nimport { registerAdmin } from \"./commands/admin.js\";\nimport { registerApi } from \"./commands/api.js\";\nimport { registerAuth } from \"./commands/auth.js\";\nimport { registerCatalog } from \"./commands/catalog.js\";\nimport { registerEntries } from \"./commands/entries.js\";\nimport { registerFormEntries } from \"./commands/formentries.js\";\nimport { registerMedia } from \"./commands/media.js\";\nimport { registerMetadata } from \"./commands/metadata.js\";\nimport { registerInit } from \"./commands/init.js\";\nimport { registerStatus } from \"./commands/status.js\";\n\nfunction version(): string {\n try {\n const pkg = JSON.parse(readFileSync(new URL(\"../package.json\", import.meta.url), \"utf8\")) as { version: string };\n return pkg.version;\n } catch {\n return \"0.0.0\";\n }\n}\n\nexport function createProgram(io: Io): Command {\n const program = new Command(\"plenary\")\n .description(\"Command-line client for the Plenary API\")\n .version(version(), \"-v, --version\")\n .option(\"--base-url <url>\", \"instance URL (PLENARY_BASE_URL)\")\n .option(\"--api-key <key>\", \"API key (PLENARY_CLI_API_KEY)\")\n .option(\"--site <key>\", \"site key (PLENARY_SITE_KEY)\")\n .option(\"--locale <code>\", \"locale (PLENARY_LOCALE)\")\n .option(\"--config <path>\", \"plenary.json to use (default: nearest, searching upward)\")\n .option(\"--json\", \"print machine-readable JSON\")\n .option(\"--debug\", \"print requests and stack traces to stderr\")\n .showHelpAfterError(\"(run with --help for usage)\")\n .exitOverride()\n .configureOutput({\n writeOut: (s) => io.stdout.write(s),\n writeErr: (s) => io.stderr.write(s),\n });\n\n registerInit(program, io);\n registerAuth(program, io);\n registerStatus(program, io);\n registerMetadata(program, io);\n registerCatalog(program, io, \"models\");\n registerFormEntries(registerCatalog(program, io, \"forms\"), io);\n registerEntries(program, io);\n registerMedia(program, io);\n registerAdmin(program, io);\n registerApi(program, io);\n return program;\n}\n\n/** Runs one invocation and returns the exit code; never throws. */\nexport async function run(argv: string[], io: Io): Promise<number> {\n const program = createProgram(io);\n try {\n await program.parseAsync(argv, { from: \"user\" });\n return 0;\n } catch (err) {\n if (err instanceof CommanderError) {\n // Commander has already written help or its own message.\n return exitCodeFor(err);\n }\n const debug = Boolean(program.opts<{ debug?: boolean }>().debug);\n const message = describeError(err, debug);\n if (message !== \"plenary: \") io.stderr.write(message + \"\\n\");\n return exitCodeFor(err);\n }\n}\n","import { PlenaryError } from \"@plenary/client\";\nimport { CommanderError } from \"commander\";\nimport { CliError } from \"./errors.js\";\n\n/** Renders rows as aligned columns; the first row is the header when `header` is set. */\nexport function formatTable(rows: string[][], header?: string[]): string {\n const all = header ? [header, ...rows] : rows;\n if (all.length === 0) return \"\";\n const widths: number[] = [];\n for (const row of all) {\n row.forEach((cell, i) => {\n widths[i] = Math.max(widths[i] ?? 0, cell.length);\n });\n }\n return all\n .map((row) =>\n row\n .map((cell, i) => (i === row.length - 1 ? cell : cell.padEnd(widths[i] ?? 0)))\n .join(\" \")\n .trimEnd(),\n )\n .join(\"\\n\");\n}\n\nexport function toJson(value: unknown): string {\n return JSON.stringify(value, null, 2);\n}\n\n/** One line for stderr describing why a command failed. */\nexport function describeError(err: unknown, debug = false): string {\n if (err instanceof PlenaryError) {\n let line = `plenary: ${err.code} (HTTP ${err.status})`;\n if (err.vars && Object.keys(err.vars).length > 0) {\n line += \"\\n\" + Object.entries(err.vars).map(([k, v]) => ` ${k}: ${fmtVar(v)}`).join(\"\\n\");\n }\n return line;\n }\n if (err instanceof CliError) return `plenary: ${err.message}`;\n if (err instanceof Error) {\n const cause = err.cause instanceof Error ? `: ${err.cause.message}` : \"\";\n return debug && err.stack ? err.stack : `plenary: ${err.message}${cause}`;\n }\n return `plenary: ${String(err)}`;\n}\n\nexport function exitCodeFor(err: unknown): number {\n if (err instanceof CliError) return err.exitCode;\n if (err instanceof CommanderError) return err.exitCode === 0 ? 0 : 2;\n return 1;\n}\n\nfunction fmtVar(v: unknown): string {\n return typeof v === \"string\" ? v : JSON.stringify(v);\n}\n","/**\n * An error the CLI raised itself (as opposed to one the server returned).\n * exitCode 2 is a usage problem — a missing credential, a malformed flag —\n * and 1 is everything else.\n */\nexport class CliError extends Error {\n readonly exitCode: number;\n\n constructor(message: string, exitCode = 1) {\n super(message);\n this.name = \"CliError\";\n this.exitCode = exitCode;\n }\n}\n\nexport function usageError(message: string): CliError {\n return new CliError(message, 2);\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { usageError } from \"./errors.js\";\n\n/** The streams and environment a run reads and writes — injected so tests can capture them. */\nexport interface Io {\n stdout: NodeJS.WritableStream;\n stderr: NodeJS.WritableStream;\n stdin: NodeJS.ReadableStream;\n env: NodeJS.ProcessEnv;\n cwd: string;\n fetch: typeof globalThis.fetch;\n /** Whether stdin is a terminal: prompts are only ever issued when it is. */\n isTTY: boolean;\n}\n\n/** The global options every command accepts (declared on the root program). */\nexport interface GlobalOptions {\n baseUrl?: string;\n apiKey?: string;\n site?: string;\n locale?: string;\n config?: string;\n json?: boolean;\n debug?: boolean;\n}\n\n/** The shape of `plenary.json`. Never holds a credential. */\nexport interface ProjectConfig {\n baseUrl?: string;\n siteKey?: string;\n locale?: string;\n metadataDir?: string;\n}\n\n/** Everything a command needs, resolved once per invocation. */\nexport interface Context {\n io: Io;\n baseUrl?: string;\n apiKey?: string;\n siteKey?: string;\n locale?: string;\n metadataDir: string;\n /** The directory holding plenary.json, or the cwd when there is none. */\n projectRoot: string;\n configPath?: string;\n json: boolean;\n debug: boolean;\n /** The access token minted from a stored session, once this run has one. */\n sessionToken?: string;\n}\n\nexport const CONFIG_FILE = \"plenary.json\";\nexport const DEFAULT_METADATA_DIR = \"plenary\";\n\n/** Walks up from `from` and returns the first plenary.json found, if any. */\nexport function findConfigFile(from: string): string | undefined {\n let dir = path.resolve(from);\n for (;;) {\n const candidate = path.join(dir, CONFIG_FILE);\n if (existsSync(candidate)) return candidate;\n const parent = path.dirname(dir);\n if (parent === dir) return undefined;\n dir = parent;\n }\n}\n\nconst CONFIG_KEYS: ReadonlyArray<keyof ProjectConfig> = [\"baseUrl\", \"siteKey\", \"locale\", \"metadataDir\"];\n\nexport function readProjectConfig(file: string): ProjectConfig {\n let parsed: unknown;\n try {\n parsed = JSON.parse(readFileSync(file, \"utf8\"));\n } catch (err) {\n throw usageError(`${file}: ${(err as Error).message}`);\n }\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n throw usageError(`${file}: expected a JSON object`);\n }\n const out: ProjectConfig = {};\n for (const [key, value] of Object.entries(parsed)) {\n if (!(CONFIG_KEYS as readonly string[]).includes(key)) {\n throw usageError(`${file}: unknown key \"${key}\"`);\n }\n if (typeof value !== \"string\") {\n throw usageError(`${file}: \"${key}\" must be a string`);\n }\n out[key as keyof ProjectConfig] = value;\n }\n return out;\n}\n\n/**\n * Reads the PLENARY_* lines of a .env file. Deliberately minimal — `KEY=value`,\n * optional surrounding quotes, `#` comments — because a project that needs\n * more has a real env loader already.\n */\nexport function readDotEnv(file: string): Record<string, string> {\n const out: Record<string, string> = {};\n let text: string;\n try {\n text = readFileSync(file, \"utf8\");\n } catch {\n return out;\n }\n for (const raw of text.split(\"\\n\")) {\n const line = raw.trim();\n if (line === \"\" || line.startsWith(\"#\")) continue;\n const m = /^(?:export\\s+)?(PLENARY_[A-Z0-9_]+)=(.*)$/.exec(line);\n if (!m) continue;\n let value = (m[2] ?? \"\").trim();\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n out[m[1] as string] = value;\n }\n return out;\n}\n\n/**\n * Resolves the run context. Precedence, highest first: flag, process\n * environment, `.env` beside plenary.json (or in the cwd), plenary.json,\n * default.\n */\nexport function resolveContext(opts: GlobalOptions, io: Io): Context {\n const configPath = opts.config ? path.resolve(io.cwd, opts.config) : findConfigFile(io.cwd);\n if (opts.config && !existsSync(configPath as string)) {\n throw usageError(`config file not found: ${configPath}`);\n }\n const file = configPath ? readProjectConfig(configPath) : {};\n const projectRoot = configPath ? path.dirname(configPath) : io.cwd;\n const env = { ...readDotEnv(path.join(projectRoot, \".env\")), ...pick(io.env) };\n\n const baseUrl = opts.baseUrl ?? env.PLENARY_BASE_URL ?? file.baseUrl;\n return {\n io,\n baseUrl: baseUrl ? baseUrl.replace(/\\/+$/, \"\") : undefined,\n apiKey: opts.apiKey ?? env.PLENARY_CLI_API_KEY,\n siteKey: opts.site ?? env.PLENARY_SITE_KEY ?? file.siteKey,\n locale: opts.locale ?? env.PLENARY_LOCALE ?? file.locale,\n metadataDir: env.PLENARY_METADATA_DIR ?? file.metadataDir ?? DEFAULT_METADATA_DIR,\n projectRoot,\n configPath,\n json: opts.json ?? false,\n debug: opts.debug ?? false,\n };\n}\n\n/** Only the PLENARY_* variables, and only those actually set. */\nfunction pick(env: NodeJS.ProcessEnv): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(env)) {\n if (k.startsWith(\"PLENARY_\") && v !== undefined && v !== \"\") out[k] = v;\n }\n return out;\n}\n\nexport function requireBaseUrl(ctx: Context): string {\n if (!ctx.baseUrl) {\n throw usageError(\n \"no base URL: pass --base-url, set PLENARY_BASE_URL, or run `plenary init`\",\n );\n }\n return ctx.baseUrl;\n}\n","import { errorFromResponse } from \"@plenary/client\";\nimport { requireBaseUrl, type Context } from \"../config.js\";\nimport { usageError } from \"../errors.js\";\nimport { sessionAccessToken } from \"../session.js\";\n\n/**\n * Which credential a request carries. A configured API key wins over a\n * stored session for content work, so a person's login never silently\n * becomes the actor of a deploy job that also has a key; a session is what\n * admin work needs, since a key can never hold admin:* capabilities.\n */\nexport type AuthMode = \"required\" | \"optional\" | \"none\" | \"session\";\n\nexport async function credentialHeaders(ctx: Context, mode: AuthMode): Promise<Record<string, string>> {\n if (mode === \"none\") return {};\n if (mode === \"session\") {\n const token = await sessionAccessToken(ctx);\n if (!token) throw usageError(\"this command needs a user session: run `plenary login`\");\n return { Authorization: `Bearer ${token}` };\n }\n if (ctx.apiKey) return { \"X-API-KEY\": ctx.apiKey };\n const token = await sessionAccessToken(ctx);\n if (token) return { Authorization: `Bearer ${token}` };\n if (mode === \"required\") {\n throw usageError(\"no credential: pass --api-key, set PLENARY_CLI_API_KEY, or run `plenary login`\");\n }\n return {};\n}\n\nexport interface RequestOptions {\n /** Query parameters; undefined values are dropped. */\n query?: Record<string, string | undefined>;\n /** A JSON body. */\n body?: unknown;\n /** A multipart body; wins over `body`. */\n form?: FormData;\n headers?: Record<string, string>;\n /**\n * \"required\" (default) refuses to run without a credential; \"optional\"\n * sends one when there is one; \"none\" never does (the health check);\n * \"session\" insists on a user login (admin routes).\n */\n auth?: AuthMode;\n /** Return a non-2xx response instead of throwing its PlenaryError. */\n allowError?: boolean;\n}\n\nexport interface ApiResponse<T = unknown> {\n status: number;\n ok: boolean;\n headers: Headers;\n /** The parsed JSON body, the text body for non-JSON responses, or null for 204. */\n data: T;\n}\n\n/** Turns `models` into `/api/v1/models`; a path that already starts with `/` is kept. */\nexport function apiPath(p: string): string {\n return p.startsWith(\"/\") ? p : `/api/v1/${p}`;\n}\n\nexport async function request<T = unknown>(\n ctx: Context,\n method: string,\n path: string,\n opts: RequestOptions = {},\n): Promise<ApiResponse<T>> {\n const base = requireBaseUrl(ctx);\n const headers: Record<string, string> = { ...opts.headers, ...(await credentialHeaders(ctx, opts.auth ?? \"required\")) };\n\n const url = new URL(base + apiPath(path));\n for (const [k, v] of Object.entries(opts.query ?? {})) {\n if (v !== undefined) url.searchParams.set(k, v);\n }\n\n let body: RequestInit[\"body\"];\n if (opts.form) {\n body = opts.form;\n } else if (opts.body !== undefined) {\n headers[\"Content-Type\"] = \"application/json\";\n body = JSON.stringify(opts.body);\n }\n\n if (ctx.debug) ctx.io.stderr.write(`> ${method} ${url}\\n`);\n const response = await ctx.io.fetch(url, { method, headers, body });\n const data = await parseBody(response);\n if (ctx.debug) ctx.io.stderr.write(`< ${response.status}\\n`);\n\n if (!response.ok && !opts.allowError) {\n throw errorFromResponse(response.status, data);\n }\n return { status: response.status, ok: response.ok, headers: response.headers, data: data as T };\n}\n\nasync function parseBody(response: Response): Promise<unknown> {\n if (response.status === 204) return null;\n const text = await response.text();\n if (text === \"\") return null;\n const type = response.headers.get(\"content-type\") ?? \"\";\n if (type.includes(\"json\")) {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n }\n return text;\n}\n","import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport path from \"node:path\";\nimport type { Context, Io } from \"./config.js\";\nimport { usageError } from \"./errors.js\";\n\n/** What login stores: never an access token, only the refresh token that mints one. */\nexport interface StoredSession {\n refresh_token: string;\n identifier?: string;\n updated_at: string;\n}\n\ntype Store = Record<string, StoredSession>;\n\n/** `$XDG_CONFIG_HOME/plenary/credentials.json`, `~/.config` by default. */\nexport function credentialsPath(io: Io): string {\n const base = io.env.XDG_CONFIG_HOME || path.join(io.env.HOME || homedir(), \".config\");\n return path.join(base, \"plenary\", \"credentials.json\");\n}\n\nfunction readStore(io: Io): Store {\n const file = credentialsPath(io);\n if (!existsSync(file)) return {};\n try {\n const parsed = JSON.parse(readFileSync(file, \"utf8\")) as unknown;\n return typeof parsed === \"object\" && parsed !== null ? (parsed as Store) : {};\n } catch {\n return {};\n }\n}\n\nfunction writeStore(io: Io, store: Store): void {\n const file = credentialsPath(io);\n mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });\n // Written whole and renamed into place, so a crash mid-write never leaves\n // a half file where a refresh token used to be.\n const tmp = `${file}.${process.pid}.tmp`;\n writeFileSync(tmp, JSON.stringify(store, null, 2) + \"\\n\", { mode: 0o600 });\n chmodSync(tmp, 0o600);\n renameSync(tmp, file);\n}\n\nexport function loadSession(io: Io, baseUrl: string): StoredSession | undefined {\n return readStore(io)[baseUrl];\n}\n\nexport function saveSession(io: Io, baseUrl: string, session: Omit<StoredSession, \"updated_at\">): void {\n const store = readStore(io);\n store[baseUrl] = { ...session, updated_at: new Date().toISOString() };\n writeStore(io, store);\n}\n\nexport function clearSession(io: Io, baseUrl: string): boolean {\n const store = readStore(io);\n if (!(baseUrl in store)) return false;\n delete store[baseUrl];\n writeStore(io, store);\n return true;\n}\n\ninterface RefreshResponse {\n status: string;\n access_token: string;\n refresh_token: string;\n}\n\n/**\n * The access token for this run, minted from the stored refresh token. The\n * rotated refresh token is written back before the access token is used for\n * anything, because presenting the old one again would revoke the family.\n * Undefined when there is no session for this instance.\n */\nexport async function sessionAccessToken(ctx: Context): Promise<string | undefined> {\n if (ctx.sessionToken) return ctx.sessionToken;\n const baseUrl = ctx.baseUrl;\n if (!baseUrl) return undefined;\n const stored = loadSession(ctx.io, baseUrl);\n if (!stored) return undefined;\n\n const response = await ctx.io.fetch(`${baseUrl}/api/v1/auth/refresh`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refresh_token: stored.refresh_token }),\n });\n const body = (await response.json().catch(() => null)) as RefreshResponse | { error?: { code?: string } } | null;\n if (!response.ok || !body || !(\"access_token\" in body)) {\n const code = (body as { error?: { code?: string } } | null)?.error?.code ?? `http_${response.status}`;\n if (response.status === 401) {\n clearSession(ctx.io, baseUrl);\n throw usageError(`session for ${baseUrl} is no longer valid (${code}): run \\`plenary login\\``);\n }\n throw usageError(`could not refresh the session for ${baseUrl} (${code})`);\n }\n saveSession(ctx.io, baseUrl, { refresh_token: body.refresh_token, identifier: stored.identifier });\n ctx.sessionToken = body.access_token;\n return body.access_token;\n}\n","import { readFileSync } from \"node:fs\";\nimport { createInterface } from \"node:readline/promises\";\nimport type { Io } from \"./config.js\";\nimport { usageError } from \"./errors.js\";\n\n/** `k=v` pairs → object; a repeated key keeps the last value. */\nexport function parsePairs(pairs: string[], sep: string, what: string): Record<string, string> {\n const out: Record<string, string> = {};\n for (const pair of pairs) {\n const i = pair.indexOf(sep);\n if (i <= 0) throw usageError(`invalid ${what} \"${pair}\": expected key${sep}value`);\n out[pair.slice(0, i).trim()] = pair.slice(i + 1).trim();\n }\n return out;\n}\n\n/** Inline text, `@file`, or `-` for stdin. */\nexport async function readText(data: string, stdin: NodeJS.ReadableStream): Promise<string> {\n if (data === \"-\") return readStream(stdin);\n if (data.startsWith(\"@\")) {\n try {\n return readFileSync(data.slice(1), \"utf8\");\n } catch (err) {\n throw usageError(`cannot read ${data.slice(1)}: ${(err as Error).message}`);\n }\n }\n return data;\n}\n\n/** Inline JSON, `@file`, or `-` for stdin; returns the parsed value. */\nexport async function readData(data: string, stdin: NodeJS.ReadableStream, flag = \"--data\"): Promise<unknown> {\n const text = await readText(data, stdin);\n try {\n return JSON.parse(text);\n } catch (err) {\n throw usageError(`${flag} is not valid JSON: ${(err as Error).message}`);\n }\n}\n\n/** Like readData, but insists on a JSON object. */\nexport async function readObject(\n data: string,\n stdin: NodeJS.ReadableStream,\n flag = \"--data\",\n): Promise<Record<string, unknown>> {\n const value = await readData(data, stdin, flag);\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw usageError(`${flag} must be a JSON object`);\n }\n return value as Record<string, unknown>;\n}\n\nexport async function readStream(stream: NodeJS.ReadableStream): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of stream) chunks.push(Buffer.from(chunk as Buffer | string));\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n\n/**\n * Asks before something destructive. `yes` (from -y) skips the question; a\n * run with no terminal and no -y is refused rather than silently answered.\n */\nexport async function confirm(io: Io, question: string, yes: boolean): Promise<void> {\n if (yes) return;\n if (!io.isTTY) throw usageError(`${question} — pass -y to confirm without a terminal`);\n const rl = createInterface({ input: io.stdin, output: io.stderr });\n try {\n const answer = (await rl.question(`${question} [y/N] `)).trim().toLowerCase();\n if (answer !== \"y\" && answer !== \"yes\") throw usageError(\"aborted\");\n } finally {\n rl.close();\n }\n}\n\n/** Prompts for one line on a terminal; without one, reads a line from stdin. */\nexport async function readLine(io: Io, prompt: string): Promise<string> {\n const rl = createInterface({ input: io.stdin, output: io.isTTY ? io.stderr : undefined, terminal: io.isTTY });\n try {\n if (!io.isTTY) {\n const it = rl[Symbol.asyncIterator]();\n const { value } = await it.next();\n return (value ?? \"\").trim();\n }\n return (await rl.question(prompt)).trim();\n } finally {\n rl.close();\n }\n}\n\n/**\n * Prompts for a secret without echoing it. On a terminal the input is put in\n * raw mode and read a key at a time; otherwise a line is read from stdin, so\n * a script can pipe a password in.\n */\nexport async function readSecret(io: Io, prompt: string): Promise<string> {\n const stdin = io.stdin as NodeJS.ReadableStream & { setRawMode?: (raw: boolean) => void };\n if (!io.isTTY || typeof stdin.setRawMode !== \"function\") return readLine(io, prompt);\n io.stderr.write(prompt);\n stdin.setRawMode(true);\n stdin.resume();\n try {\n return await new Promise<string>((resolve, reject) => {\n let value = \"\";\n const onData = (chunk: Buffer | string) => {\n for (const ch of String(chunk)) {\n const code = ch.charCodeAt(0);\n if (code === 3) {\n cleanup();\n reject(usageError(\"aborted\"));\n return;\n }\n if (code === 13 || code === 10) {\n cleanup();\n io.stderr.write(\"\\n\");\n resolve(value);\n return;\n }\n if (code === 127 || code === 8) value = value.slice(0, -1);\n else value += ch;\n }\n };\n const cleanup = () => {\n stdin.off(\"data\", onData);\n stdin.setRawMode?.(false);\n stdin.pause();\n };\n stdin.on(\"data\", onData);\n });\n } finally {\n stdin.setRawMode?.(false);\n }\n}\n","import type { Command } from \"commander\";\nimport { resolveContext, type GlobalOptions, type Io } from \"../config.js\";\nimport { request } from \"../api/http.js\";\nimport { usageError } from \"../errors.js\";\nimport { confirm } from \"../input.js\";\nimport { formatTable, toJson } from \"../output.js\";\n\ninterface Site {\n key: string;\n name: string;\n is_active: boolean;\n default_locale: string;\n locales: string[];\n timezone: string;\n}\n\ninterface RoleItem {\n key: string;\n name: string;\n description: string | null;\n is_system: boolean;\n grant_count: number;\n assigned_user_count: number;\n}\n\ninterface Grant {\n key: string;\n site_key?: string;\n content_model_id?: string;\n}\n\ninterface Role extends Omit<RoleItem, \"grant_count\" | \"assigned_user_count\"> {\n grants: Grant[];\n}\n\ninterface ApiKeyItem {\n id: string;\n name: string;\n key_type: string;\n is_active: boolean;\n last_used_at: string | null;\n expires_at: string | null;\n revoked_at: string | null;\n}\n\ninterface ApiKeyCreated extends ApiKeyItem {\n key: string;\n}\n\nfunction collect(value: string, previous: string[]): string[] {\n return [...previous, value];\n}\n\n/** `content:entries:read`, optionally `,site=<key>` and `,model=<uuid>`. */\nexport function parseGrant(spec: string): Grant {\n const [key, ...filters] = spec.split(\",\").map((s) => s.trim());\n if (!key) throw usageError(`invalid --grant \"${spec}\"`);\n const grant: Grant = { key };\n for (const f of filters) {\n const [name, value] = f.split(\"=\");\n if (name === \"site\" && value) grant.site_key = value;\n else if (name === \"model\" && value) grant.content_model_id = value;\n else throw usageError(`invalid --grant \"${spec}\": expected key[,site=<key>][,model=<uuid>]`);\n }\n return grant;\n}\n\nexport function registerAdmin(program: Command, io: Io): void {\n program\n .command(\"sites\")\n .description(\"Sites\")\n .command(\"list\")\n .description(\"List sites\")\n .action(async (_flags: unknown, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const res = await request<Site[]>(ctx, \"GET\", \"sites\");\n if (ctx.json) {\n io.stdout.write(toJson(res.data) + \"\\n\");\n return;\n }\n const rows = res.data.map((s) => [\n s.key,\n s.name,\n s.default_locale,\n s.locales.join(\",\"),\n s.timezone,\n s.is_active ? \"\" : \"inactive\",\n ]);\n io.stdout.write(formatTable(rows, [\"KEY\", \"NAME\", \"DEFAULT\", \"LOCALES\", \"TIMEZONE\", \"\"]) + \"\\n\");\n });\n\n const roles = program.command(\"roles\").description(\"Roles (needs a user session)\");\n roles\n .command(\"list\")\n .description(\"List roles\")\n .action(async (_flags: unknown, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const res = await request<RoleItem[]>(ctx, \"GET\", \"roles\", { auth: \"session\" });\n if (ctx.json) {\n io.stdout.write(toJson(res.data) + \"\\n\");\n return;\n }\n const rows = res.data.map((r) => [\n r.key,\n r.name,\n String(r.grant_count),\n String(r.assigned_user_count),\n r.is_system ? \"system\" : \"\",\n ]);\n io.stdout.write(formatTable(rows, [\"KEY\", \"NAME\", \"GRANTS\", \"USERS\", \"\"]) + \"\\n\");\n });\n roles\n .command(\"get\")\n .description(\"Show a role and its grants\")\n .argument(\"<key>\")\n .action(async (key: string, _flags: unknown, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const res = await request<Role>(ctx, \"GET\", `roles/${encodeURIComponent(key)}`, { auth: \"session\" });\n if (ctx.json) {\n io.stdout.write(toJson(res.data) + \"\\n\");\n return;\n }\n const r = res.data;\n const head = [\n [\"Key\", r.key],\n [\"Name\", r.name],\n [\"System\", r.is_system ? \"yes\" : \"no\"],\n ];\n if (r.description) head.push([\"Description\", r.description]);\n const grants = r.grants.map((g) => [g.key, g.site_key ?? \"\", g.content_model_id ?? \"\"]);\n io.stdout.write(formatTable(head) + \"\\n\\n\" + formatTable(grants, [\"GRANT\", \"SITE\", \"MODEL\"]) + \"\\n\");\n });\n\n const keys = program.command(\"api-keys\").description(\"API keys (needs a user session)\");\n keys\n .command(\"list\")\n .description(\"List API keys\")\n .action(async (_flags: unknown, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const res = await request<ApiKeyItem[]>(ctx, \"GET\", \"api-keys\", { auth: \"session\" });\n if (ctx.json) {\n io.stdout.write(toJson(res.data) + \"\\n\");\n return;\n }\n const rows = res.data.map((k) => [\n k.id,\n k.name,\n k.key_type,\n k.revoked_at ? \"revoked\" : k.is_active ? \"active\" : \"inactive\",\n k.last_used_at ?? \"never\",\n k.expires_at ?? \"\",\n ]);\n io.stdout.write(formatTable(rows, [\"ID\", \"NAME\", \"TYPE\", \"STATE\", \"LAST USED\", \"EXPIRES\"]) + \"\\n\");\n });\n keys\n .command(\"get\")\n .description(\"Show one API key (never its secret)\")\n .argument(\"<id>\")\n .action(async (id: string, _flags: unknown, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const res = await request(ctx, \"GET\", `api-keys/${encodeURIComponent(id)}`, { auth: \"session\" });\n io.stdout.write(toJson(res.data) + \"\\n\");\n });\n keys\n .command(\"create\")\n .description(\"Create an API key; the secret is printed once, alone on stdout\")\n .requiredOption(\"-n, --name <name>\")\n .option(\"-t, --type <private|public>\", \"key type\", \"private\")\n .option(\"--description <text>\")\n .option(\"-g, --grant <spec>\", \"private keys: key[,site=<key>][,model=<uuid>] (repeatable)\", collect, [])\n .option(\"--site <key>\", \"the site the key belongs to: a public key reads it, a private key's grants are held to it\")\n .option(\"--expires <iso>\", \"expiry timestamp\")\n .option(\"--origin <origin>\", \"an allowed browser origin (repeatable)\", collect, [])\n .option(\"--rate-limit <n>\", \"requests per minute, 0 = unlimited\", \"0\")\n .option(\"--include-drafts\", \"public keys: read drafts too\")\n .action(\n async (\n flags: {\n name: string;\n type: string;\n description?: string;\n grant: string[];\n site?: string;\n expires?: string;\n origin: string[];\n rateLimit: string;\n includeDrafts?: boolean;\n },\n cmd: Command,\n ) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n if (flags.type !== \"private\" && flags.type !== \"public\") throw usageError(\"--type must be private or public\");\n const body = {\n name: flags.name,\n description: flags.description ?? null,\n key_type: flags.type,\n is_active: true,\n expires_at: flags.expires ?? null,\n grants: flags.grant.map(parseGrant),\n ...(flags.site ? { site_key: flags.site } : {}),\n allowed_origins: flags.origin,\n rate_limit_per_minute: Number(flags.rateLimit),\n include_drafts: Boolean(flags.includeDrafts),\n };\n const res = await request<ApiKeyCreated>(ctx, \"POST\", \"api-keys\", { auth: \"session\", body });\n if (ctx.json) {\n io.stdout.write(toJson(res.data) + \"\\n\");\n return;\n }\n io.stderr.write(\n `created ${flags.type} key \"${flags.name}\" (${res.data.id}); the secret follows and is not shown again\\n`,\n );\n io.stdout.write(res.data.key + \"\\n\");\n },\n );\n keys\n .command(\"delete\")\n .description(\"Delete an API key\")\n .argument(\"<id>\")\n .option(\"-y, --yes\", \"do not ask\")\n .action(async (id: string, flags: { yes?: boolean }, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n await confirm(io, `Delete API key ${id}?`, Boolean(flags.yes));\n await request(ctx, \"DELETE\", `api-keys/${encodeURIComponent(id)}`, { auth: \"session\" });\n io.stdout.write(`deleted ${id}\\n`);\n });\n}\n","import type { Command } from \"commander\";\nimport { resolveContext, type GlobalOptions, type Io } from \"../config.js\";\nimport { request } from \"../api/http.js\";\nimport { CliError, usageError } from \"../errors.js\";\nimport { parsePairs, readData } from \"../input.js\";\nimport { describeError, toJson } from \"../output.js\";\nimport { errorFromResponse } from \"@plenary/client\";\n\nconst METHODS = new Set([\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\", \"HEAD\"]);\n\nfunction collect(value: string, previous: string[]): string[] {\n return [...previous, value];\n}\n\nexport function registerApi(program: Command, io: Io): void {\n program\n .command(\"api\")\n .description(\"Call any API endpoint and print the response body\")\n .argument(\"<method>\", \"GET, POST, PUT, PATCH, DELETE, or HEAD\")\n .argument(\"<path>\", \"a path such as models or /api/v1/models\")\n .option(\"-d, --data <json>\", \"request body: inline JSON, @file, or - for stdin\")\n .option(\"-q, --query <key=value>\", \"query parameter (repeatable)\", collect, [])\n .option(\"-H, --header <key:value>\", \"request header (repeatable)\", collect, [])\n .option(\"-i, --include\", \"print the status line and response headers to stderr\")\n .addHelpText(\n \"after\",\n `\nExamples:\n plenary api GET models\n plenary api GET content/post -q site_key=main -q limit=5\n plenary api POST content/post -q site_key=main -d '{\"fields\":{\"title\":\"Hello\"}}'\n plenary api PUT models/<uuid> -d @model.json`,\n )\n .action(\n async (\n methodArg: string,\n path: string,\n opts: { data?: string; query: string[]; header: string[]; include?: boolean },\n cmd: Command,\n ) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const method = methodArg.toUpperCase();\n if (!METHODS.has(method)) throw usageError(`unsupported method \"${methodArg}\"`);\n\n const body = opts.data !== undefined ? await readData(opts.data, io.stdin) : undefined;\n const res = await request(ctx, method, path, {\n query: parsePairs(opts.query, \"=\", \"query parameter\"),\n headers: parsePairs(opts.header, \":\", \"header\"),\n body,\n auth: \"optional\",\n allowError: true,\n });\n\n if (opts.include) {\n io.stderr.write(`HTTP ${res.status}\\n`);\n res.headers.forEach((v: string, k: string) => io.stderr.write(`${k}: ${v}\\n`));\n io.stderr.write(\"\\n\");\n }\n if (res.data !== null) {\n io.stdout.write((typeof res.data === \"string\" ? res.data : toJson(res.data)) + \"\\n\");\n }\n if (!res.ok) {\n io.stderr.write(describeError(errorFromResponse(res.status, res.data)) + \"\\n\");\n throw new CliError(\"\", 1);\n }\n },\n );\n}\n","import type { Command } from \"commander\";\nimport { resolveContext, requireBaseUrl, type Context, type GlobalOptions, type Io } from \"../config.js\";\nimport { credentialHeaders, request } from \"../api/http.js\";\nimport { usageError } from \"../errors.js\";\nimport { readLine, readSecret } from \"../input.js\";\nimport { toJson } from \"../output.js\";\nimport { clearSession, credentialsPath, loadSession, saveSession } from \"../session.js\";\n\ntype LoginResponse =\n | { status: \"success\"; access_token: string; refresh_token: string }\n | { status: \"otp_sent\" | \"otp_required\"; challenge_id: string; otp_methods: Record<string, string> };\n\ninterface Tokens {\n access_token: string;\n refresh_token: string;\n}\n\ninterface MeUser {\n principal: \"user\";\n role: string;\n role_name?: string;\n}\n\n/** The password, then OTP, then tokens conversation, prompting only where needed. */\nasync function login(ctx: Context, identifier: string, password: string, otpMethod?: string): Promise<Tokens> {\n const io = ctx.io;\n const first = await request<LoginResponse>(ctx, \"POST\", \"auth/login\", {\n auth: \"none\",\n body: { identifier, password },\n });\n const res = first.data;\n if (res.status === \"success\") return res;\n\n const challengeId = res.challenge_id;\n const methods = Object.keys(res.otp_methods);\n if (res.status === \"otp_required\") {\n let method = otpMethod ?? (methods.length === 1 ? methods[0] : undefined);\n if (!method) {\n if (!io.isTTY) throw usageError(`2FA needs a delivery method: pass --otp-method ${methods.join(\"|\")}`);\n const shown = methods.map((m) => `${m} (${res.otp_methods[m]})`).join(\", \");\n method = await readLine(io, `Send the code by ${shown}? [${methods[0]}] `);\n if (method === \"\") method = methods[0];\n }\n if (!methods.includes(method as string)) throw usageError(`--otp-method must be one of ${methods.join(\", \")}`);\n await request(ctx, \"POST\", \"auth/login/otp/send\", {\n auth: \"none\",\n body: { challenge_id: challengeId, otp_method: method },\n });\n io.stderr.write(`code sent by ${method}\\n`);\n } else {\n io.stderr.write(`code sent to ${Object.values(res.otp_methods).join(\", \")}\\n`);\n }\n\n if (!io.isTTY) throw usageError(\"2FA needs a terminal to enter the code\");\n const code = await readLine(io, \"Code: \");\n const verified = await request<Tokens & { status: string }>(ctx, \"POST\", \"auth/login/otp/verify\", {\n auth: \"none\",\n body: { challenge_id: challengeId, otp_code: code },\n });\n return verified.data;\n}\n\nexport function registerAuth(program: Command, io: Io): void {\n program\n .command(\"login\")\n .description(\"Sign in as a user and keep the session for admin commands\")\n .option(\"-u, --identifier <email-or-username>\", \"or PLENARY_USERNAME\")\n .option(\"--otp-method <email|sms>\", \"how to receive a 2FA code when more than one way is offered\")\n .addHelpText(\n \"after\",\n `\nThe password is prompted for (never a flag); PLENARY_PASSWORD supplies it\nwithout a terminal. Only the refresh token is stored, in\n$XDG_CONFIG_HOME/plenary/credentials.json, keyed by instance.`,\n )\n .action(async (flags: { identifier?: string; otpMethod?: string }, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const baseUrl = requireBaseUrl(ctx);\n let identifier = flags.identifier ?? io.env.PLENARY_USERNAME;\n if (!identifier) {\n if (!io.isTTY) throw usageError(\"no identifier: pass --identifier or set PLENARY_USERNAME\");\n identifier = await readLine(io, \"Email or username: \");\n }\n let password = io.env.PLENARY_PASSWORD;\n if (!password) {\n if (!io.isTTY) throw usageError(\"no password: set PLENARY_PASSWORD or run on a terminal\");\n password = await readSecret(io, \"Password: \");\n }\n const tokens = await login(ctx, identifier, password, flags.otpMethod);\n saveSession(io, baseUrl, { refresh_token: tokens.refresh_token, identifier });\n ctx.sessionToken = tokens.access_token;\n\n const me = await request<MeUser>(ctx, \"GET\", \"auth/me\", { auth: \"session\" });\n if (ctx.json) {\n io.stdout.write(\n toJson({ base_url: baseUrl, identifier, role: me.data.role, credentials: credentialsPath(io) }) + \"\\n\",\n );\n return;\n }\n io.stdout.write(`logged in to ${baseUrl} as ${identifier} (${me.data.role_name ?? me.data.role})\\n`);\n });\n\n program\n .command(\"logout\")\n .description(\"Revoke the stored session for this instance\")\n .action(async (_flags: unknown, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const baseUrl = requireBaseUrl(ctx);\n const stored = loadSession(io, baseUrl);\n if (!stored) {\n io.stdout.write(`no session for ${baseUrl}\\n`);\n return;\n }\n // Logout is idempotent server-side; a failure there must not keep a\n // token on disk the person asked to be rid of.\n try {\n await request(ctx, \"POST\", \"auth/logout\", { auth: \"none\", body: { refresh_token: stored.refresh_token } });\n } finally {\n clearSession(io, baseUrl);\n }\n io.stdout.write(`logged out of ${baseUrl}\\n`);\n });\n\n program\n .command(\"whoami\")\n .description(\"Show the credentials this run would use\")\n .action(async (_flags: unknown, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const baseUrl = requireBaseUrl(ctx);\n const stored = loadSession(io, baseUrl);\n const out: Record<string, unknown> = { base_url: baseUrl, api_key: null, session: null };\n const lines: string[] = [];\n if (ctx.apiKey) {\n const me = await request<{ key_type?: string; name?: string; grants?: unknown[] }>(ctx, \"GET\", \"auth/me\", {\n auth: \"none\",\n headers: { \"X-API-KEY\": ctx.apiKey },\n allowError: true,\n });\n out.api_key = me.ok ? me.data : { error: (me.data as { error?: unknown } | null)?.error ?? me.status };\n if (me.ok && me.data.key_type) {\n lines.push(\n `API key ${me.data.key_type} \"${me.data.name}\" (${me.data.grants?.length ?? 0} grants), used for content commands`,\n );\n } else if (me.status === 403) {\n lines.push(\"API key accepted (this server cannot describe keys), used for content commands\");\n } else {\n lines.push(`API key rejected (HTTP ${me.status})`);\n }\n }\n if (stored) {\n const headers = await credentialHeaders(ctx, \"session\");\n const me = await request<MeUser>(ctx, \"GET\", \"auth/me\", { auth: \"none\", headers });\n out.session = { identifier: stored.identifier ?? null, role: me.data.role, role_name: me.data.role_name ?? null };\n lines.push(\n `Session ${stored.identifier ?? \"user\"} (${me.data.role_name ?? me.data.role}), used for admin commands${\n ctx.apiKey ? \"\" : \" and content\"\n }`,\n );\n }\n if (lines.length === 0) lines.push(\"no credentials: set PLENARY_CLI_API_KEY or run `plenary login`\");\n io.stdout.write((ctx.json ? toJson(out) : lines.join(\"\\n\")) + \"\\n\");\n });\n}\n","import type { Command } from \"commander\";\nimport { resolveContext, type GlobalOptions, type Io } from \"../config.js\";\nimport { request } from \"../api/http.js\";\nimport { formatTable, toJson } from \"../output.js\";\n\ninterface CatalogItem {\n id: string;\n key: string;\n kind: string;\n name_singular: string;\n active: boolean;\n fields_count: number;\n site_key?: string;\n}\n\ninterface CatalogField {\n key: string;\n name: string;\n type: string;\n required: boolean;\n localized: boolean;\n}\n\ninterface CatalogDetail extends CatalogItem {\n name_plural: string;\n description?: string;\n private: boolean;\n fields: CatalogField[];\n transformers?: unknown[];\n entry_count?: number;\n}\n\n/**\n * A model key is unique within its site only, so the configured site, when\n * there is one, narrows a list and says which model a key names.\n */\nfunction siteQuery(siteKey: string | undefined) {\n return siteKey ? { query: { site_key: siteKey } } : undefined;\n}\n\n/** `models` and `forms` are the same surface at two paths. */\nexport function registerCatalog(program: Command, io: Io, name: \"models\" | \"forms\"): Command {\n const group = program.command(name).description(name === \"models\" ? \"Content models and objects\" : \"Forms\");\n\n group\n .command(\"list\")\n .description(`List ${name}`)\n .action(async (_opts: unknown, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const res = await request<CatalogItem[]>(ctx, \"GET\", name, siteQuery(ctx.siteKey));\n if (ctx.json) {\n io.stdout.write(toJson(res.data) + \"\\n\");\n return;\n }\n const rows = res.data.map((m) => [\n m.key,\n m.kind,\n m.name_singular,\n String(m.fields_count),\n m.active ? \"\" : \"inactive\",\n ]);\n io.stdout.write(formatTable(rows, [\"KEY\", \"KIND\", \"NAME\", \"FIELDS\", \"\"]) + \"\\n\");\n });\n\n group\n .command(\"get\")\n .description(`Show one of the ${name} by key or id`)\n .argument(\"<key>\")\n .option(\"--yaml\", \"print the YAML file the metadata commands use\")\n .action(async (key: string, opts: { yaml?: boolean }, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const res = await request<CatalogDetail>(ctx, \"GET\", `${name}/${encodeURIComponent(key)}`, siteQuery(ctx.siteKey));\n const m = res.data;\n if (opts.yaml) {\n const yaml = await request<string>(ctx, \"GET\", `${name}/${m.id}/yaml`);\n io.stdout.write(yaml.data.endsWith(\"\\n\") ? yaml.data : yaml.data + \"\\n\");\n return;\n }\n if (ctx.json) {\n io.stdout.write(toJson(m) + \"\\n\");\n return;\n }\n const head = [\n [\"Key\", m.key],\n [\"Kind\", m.kind],\n [\"Name\", `${m.name_singular} / ${m.name_plural}`],\n [\"Id\", m.id],\n [\"Site\", m.site_key || \"-\"],\n [\"Active\", m.active ? \"yes\" : \"no\"],\n ];\n if (m.description) head.push([\"Description\", m.description]);\n if (m.entry_count !== undefined) head.push([\"Entries\", String(m.entry_count)]);\n const fields = m.fields.map((f) => [\n f.key,\n f.type,\n f.name,\n [f.required ? \"required\" : \"\", f.localized ? \"localized\" : \"\"].filter(Boolean).join(\", \"),\n ]);\n io.stdout.write(\n formatTable(head) + \"\\n\\n\" + formatTable(fields, [\"FIELD\", \"TYPE\", \"NAME\", \"\"]) + \"\\n\",\n );\n });\n\n return group;\n}\n","import { createClient, type PlenaryClient } from \"@plenary/client\";\nimport { requireBaseUrl, type Context } from \"../config.js\";\nimport { credentialHeaders, request } from \"../api/http.js\";\nimport { usageError } from \"../errors.js\";\n\ninterface Site {\n key: string;\n default_locale: string;\n}\n\nexport function requireSiteKey(ctx: Context): string {\n if (!ctx.siteKey) {\n throw usageError(\"no site key: pass --site, set PLENARY_SITE_KEY, or set siteKey in plenary.json\");\n }\n return ctx.siteKey;\n}\n\n/**\n * The locale every content read states. When none is configured it is the\n * site's default, which every authenticated principal may look up.\n */\nexport async function resolveLocale(ctx: Context, siteKey: string): Promise<string> {\n if (ctx.locale) return ctx.locale;\n const sites = await request<Site[]>(ctx, \"GET\", \"sites\");\n const site = sites.data.find((s) => s.key === siteKey);\n if (!site) throw usageError(`site \"${siteKey}\" not found on the instance`);\n return site.default_locale;\n}\n\n/**\n * A @plenary/client for this run: the content reads go through it. The\n * client only knows how to send an API key, so with a session instead the\n * fetch it is given swaps the key header for the bearer token.\n */\nexport async function contentClient(ctx: Context): Promise<PlenaryClient> {\n const siteKey = requireSiteKey(ctx);\n const baseUrl = requireBaseUrl(ctx);\n const auth = await credentialHeaders(ctx, \"required\");\n const apiKey = auth[\"X-API-KEY\"] ?? \"\";\n const fetch: typeof globalThis.fetch = apiKey\n ? ctx.io.fetch\n : (input, init = {}) => {\n const headers = new Headers(init.headers);\n headers.delete(\"X-API-KEY\");\n for (const [k, v] of Object.entries(auth)) headers.set(k, v);\n return ctx.io.fetch(input, { ...init, headers });\n };\n return createClient({ baseUrl, siteKey, apiKey, locale: await resolveLocale(ctx, siteKey), fetch });\n}\n","import type { ListOptions, ReadOptions, Sort, Where } from \"@plenary/client\";\nimport { usageError } from \"../errors.js\";\nimport { readData } from \"../input.js\";\n\n/** The flags shared by every listing command. */\nexport interface ListFlags {\n where?: string[];\n filters?: string;\n sort?: string[];\n limit?: string;\n offset?: string;\n include?: string;\n exclude?: string;\n hydrate?: string[];\n count?: boolean;\n}\n\nconst OPERATORS = new Set([\"$eq\", \"$ne\", \"$lt\", \"$lte\", \"$gt\", \"$gte\", \"$in\", \"$nin\", \"$like\", \"$ilike\", \"$is_null\"]);\n\n/**\n * `field=value` is equality; `field=$op:value` is one of the Content API's\n * operators, with `$in`/`$nin` taking a comma list and `$is_null` a boolean.\n */\nexport function parseWhere(specs: string[]): Where {\n const where: Where = {};\n for (const spec of specs) {\n const eq = spec.indexOf(\"=\");\n if (eq <= 0) throw usageError(`invalid --where \"${spec}\": expected field=value or field=$op:value`);\n const field = spec.slice(0, eq).trim();\n const raw = spec.slice(eq + 1);\n if (!raw.startsWith(\"$\")) {\n where[field] = raw;\n continue;\n }\n const colon = raw.indexOf(\":\");\n const op = colon === -1 ? raw : raw.slice(0, colon);\n const value = colon === -1 ? \"\" : raw.slice(colon + 1);\n if (!OPERATORS.has(op)) throw usageError(`invalid --where \"${spec}\": unknown operator ${op}`);\n let typed: unknown = value;\n if (op === \"$in\" || op === \"$nin\") typed = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n else if (op === \"$is_null\") typed = value === \"\" || value === \"true\";\n const existing = (where[field] ?? {}) as Record<string, unknown>;\n where[field] = { ...(typeof existing === \"object\" ? existing : {}), [op]: typed };\n }\n return where;\n}\n\n/** `field` or `field:desc`, in precedence order. */\nexport function parseSort(specs: string[]): Sort {\n const sort: Sort = {};\n for (const spec of specs) {\n const [field, dir = \"asc\"] = spec.split(\":\");\n if (!field || (dir !== \"asc\" && dir !== \"desc\")) {\n throw usageError(`invalid --sort \"${spec}\": expected field or field:asc|desc`);\n }\n sort[field] = dir;\n }\n return sort;\n}\n\nfunction parseHydrate(specs: string[]): ReadOptions[\"hydrate\"] {\n const out: Record<string, \"*\" | string[]> = {};\n for (const spec of specs) {\n const [field, list] = spec.split(\"=\");\n if (!field) throw usageError(`invalid --hydrate \"${spec}\"`);\n out[field] = list === undefined || list === \"*\" ? \"*\" : list.split(\",\");\n }\n return out;\n}\n\nfunction parseInt10(value: string | undefined, flag: string): number | undefined {\n if (value === undefined) return undefined;\n const n = Number(value);\n if (!Number.isInteger(n) || n < 0) throw usageError(`${flag} must be a non-negative integer`);\n return n;\n}\n\nexport async function toReadOptions(flags: ListFlags): Promise<ReadOptions> {\n const opts: ReadOptions = {};\n if (flags.include) opts.include = flags.include.split(\",\");\n if (flags.exclude) opts.exclude = flags.exclude.split(\",\");\n if (flags.hydrate?.length) opts.hydrate = parseHydrate(flags.hydrate);\n return opts;\n}\n\nexport async function toListOptions(flags: ListFlags, stdin: NodeJS.ReadableStream): Promise<ListOptions> {\n const opts: ListOptions = await toReadOptions(flags);\n if (flags.where?.length && flags.filters) throw usageError(\"--where and --filters are mutually exclusive\");\n if (flags.where?.length) opts.where = parseWhere(flags.where);\n if (flags.filters) opts.filters = (await readData(flags.filters, stdin, \"--filters\")) as ListOptions[\"filters\"];\n if (flags.sort?.length) opts.sort = parseSort(flags.sort);\n const limit = parseInt10(flags.limit, \"--limit\");\n const offset = parseInt10(flags.offset, \"--offset\");\n if (limit !== undefined) opts.limit = limit;\n if (offset !== undefined) opts.offset = offset;\n if (flags.count) opts.count = true;\n return opts;\n}\n","import type { Command } from \"commander\";\nimport type { Entry, ListOptions, PlenaryClient } from \"@plenary/client\";\nimport { resolveContext, type Context, type GlobalOptions, type Io } from \"../config.js\";\nimport { request } from \"../api/http.js\";\nimport { CliError, usageError } from \"../errors.js\";\nimport { confirm, readObject, readText } from \"../input.js\";\nimport { formatTable, toJson } from \"../output.js\";\nimport { contentClient, requireSiteKey } from \"../entries/client.js\";\nimport { toListOptions, toReadOptions, type ListFlags } from \"../entries/query.js\";\n\nfunction collect(value: string, previous: string[]): string[] {\n return [...previous, value];\n}\n\n/** The flags every listing command shares, declared once. */\nfunction withListFlags(cmd: Command): Command {\n return cmd\n .option(\"-w, --where <field=value>\", \"filter: field=value or field=$op:value (repeatable)\", collect, [])\n .option(\"--filters <json>\", \"a filter tree (inline JSON, @file, or -); excludes --where\")\n .option(\"-s, --sort <field[:dir]>\", \"sort field, asc unless :desc (repeatable, in precedence order)\", collect, [])\n .option(\"--limit <n>\", \"page size\")\n .option(\"--offset <n>\", \"rows to skip\")\n .option(\"--include <fields>\", \"comma-separated data fields to return\")\n .option(\"--exclude <fields>\", \"comma-separated data fields to omit\")\n .option(\"--hydrate <field[=subfields]>\", \"hydrate a reference field (repeatable)\", collect, [])\n .option(\"--count\", \"ask for the total and show it\");\n}\n\n/** The intrinsic flags a create or update accepts beside --data. */\ninterface WriteFlags {\n data?: string;\n slug?: string;\n folder?: string;\n note?: string;\n publishAt?: string;\n unpublishAt?: string;\n}\n\nfunction withWriteFlags(cmd: Command): Command {\n return cmd\n .option(\"-d, --data <json>\", \"the field values as a JSON object (inline, @file, or -)\")\n .option(\"--slug <slug>\")\n .option(\"--folder <id>\", \"content folder id\")\n .option(\"--note <text>\", \"revision note (required by models with Require Change Notes)\")\n .option(\"--publish-at <iso>\", \"schedule a publish\")\n .option(\"--unpublish-at <iso>\", \"schedule an unpublish\");\n}\n\n/** The write body the Content API takes. */\ninterface EntryBody {\n fields: Record<string, unknown>;\n slug?: string;\n locale?: string;\n folder_id?: string | null;\n publish_at?: string | null;\n unpublish_at?: string | null;\n note?: string;\n}\n\nfunction entryRow(e: Entry): string[] {\n return [e.id, e.status, e.slug ?? \"\", e.title ?? \"\", e.updated_at];\n}\n\nconst ENTRY_HEADER = [\"ID\", \"STATUS\", \"SLUG\", \"TITLE\", \"UPDATED\"];\n\nconst PAGE = 100;\n\n/** Every entry matching the options, one page at a time. */\nasync function* pageAll(client: PlenaryClient, model: string, opts: ListOptions): AsyncGenerator<Entry> {\n const limit = opts.limit ?? PAGE;\n let offset = opts.offset ?? 0;\n for (;;) {\n const { items } = await client.listEntries(model, { ...opts, limit, offset, count: false });\n for (const e of items) yield e;\n if (items.length < limit) return;\n offset += items.length;\n }\n}\n\nasync function publish(ctx: Context, id: string, action: \"publish\" | \"unpublish\"): Promise<Entry> {\n return (await request<Entry>(ctx, \"POST\", `content/${encodeURIComponent(id)}/${action}`)).data;\n}\n\nexport function registerEntries(program: Command, io: Io): void {\n const entries = program.command(\"entries\").description(\"Content entries\");\n\n withListFlags(entries.command(\"list\").description(\"List a model's entries\").argument(\"<model>\")).action(\n async (model: string, flags: ListFlags, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const client = await contentClient(ctx);\n const result = await client.listEntries(model, await toListOptions(flags, io.stdin));\n if (ctx.json) {\n io.stdout.write(toJson(result) + \"\\n\");\n return;\n }\n io.stdout.write(formatTable(result.items.map(entryRow), ENTRY_HEADER) + \"\\n\");\n if (result.total !== undefined) io.stdout.write(`${result.items.length} of ${result.total}\\n`);\n },\n );\n\n entries\n .command(\"get\")\n .description(\"Print one entry as JSON; omit the slug for a singleton\")\n .argument(\"<model>\")\n .argument(\"[slug-or-id]\")\n .option(\"--include <fields>\")\n .option(\"--exclude <fields>\")\n .option(\"--hydrate <field[=subfields]>\", \"hydrate a reference field (repeatable)\", collect, [])\n .action(async (model: string, slug: string | undefined, flags: ListFlags, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const client = await contentClient(ctx);\n const opts = await toReadOptions(flags);\n const entry = slug === undefined ? await client.getSingleton(model, opts) : await client.getEntry(model, slug, opts);\n io.stdout.write(toJson(entry) + \"\\n\");\n });\n\n withWriteFlags(entries.command(\"create\").description(\"Create a draft entry\").argument(\"<model>\"))\n .option(\"--publish\", \"publish it right after creating\")\n .action(async (model: string, flags: WriteFlags & { publish?: boolean }, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const siteKey = requireSiteKey(ctx);\n if (flags.data === undefined) throw usageError(\"--data is required\");\n const body: EntryBody = { fields: await readObject(flags.data, io.stdin) };\n if (ctx.locale) body.locale = ctx.locale;\n applyWriteFlags(body, flags);\n let entry = (\n await request<Entry>(ctx, \"POST\", `content/${encodeURIComponent(model)}`, { query: { site_key: siteKey }, body })\n ).data;\n if (flags.publish) entry = await publish(ctx, entry.id, \"publish\");\n report(ctx, entry, \"created\");\n });\n\n withWriteFlags(\n entries\n .command(\"update\")\n .description(\"Update an entry: --data is merged into its fields (a null removes one)\")\n .argument(\"<model>\")\n .argument(\"<slug-or-id>\"),\n ).action(async (model: string, slug: string, flags: WriteFlags, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const client = await contentClient(ctx);\n const current = await client.getEntry(model, slug);\n const fields: Record<string, unknown> = { ...current.data };\n if (flags.data !== undefined) {\n for (const [k, v] of Object.entries(await readObject(flags.data, io.stdin))) {\n if (v === null) delete fields[k];\n else fields[k] = v;\n }\n }\n // PUT replaces the whole entry, so everything not being changed is carried.\n const body: EntryBody = {\n fields,\n slug: current.slug ?? undefined,\n locale: current.locale ?? undefined,\n folder_id: current.folder_id,\n publish_at: current.publish_at,\n unpublish_at: current.unpublish_at,\n };\n applyWriteFlags(body, flags);\n const entry = (await request<Entry>(ctx, \"PUT\", `content/${encodeURIComponent(current.id)}`, { body })).data;\n report(ctx, entry, \"updated\");\n });\n\n entries\n .command(\"delete\")\n .description(\"Delete an entry (recoverable from history while the model tracks revisions)\")\n .argument(\"<id>\")\n .option(\"--note <text>\", \"revision note\")\n .option(\"-y, --yes\", \"do not ask\")\n .action(async (id: string, flags: { note?: string; yes?: boolean }, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n await confirm(io, `Delete entry ${id}?`, Boolean(flags.yes));\n await request(ctx, \"DELETE\", `content/${encodeURIComponent(id)}`, { query: { note: flags.note } });\n if (ctx.json) io.stdout.write(toJson({ id, deleted: true }) + \"\\n\");\n else io.stdout.write(`deleted ${id}\\n`);\n });\n\n for (const action of [\"publish\", \"unpublish\"] as const) {\n entries\n .command(action)\n .description(`${action === \"publish\" ? \"Publish\" : \"Unpublish\"} an entry now`)\n .argument(\"<id>\")\n .action(async (id: string, _flags: unknown, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n report(ctx, await publish(ctx, id, action), action === \"publish\" ? \"published\" : \"unpublished\");\n });\n }\n\n withListFlags(\n entries.command(\"export\").description(\"Write every matching entry to stdout as NDJSON\").argument(\"<model>\"),\n ).action(async (model: string, flags: ListFlags, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const client = await contentClient(ctx);\n for await (const e of pageAll(client, model, await toListOptions(flags, io.stdin))) {\n io.stdout.write(JSON.stringify(e) + \"\\n\");\n }\n });\n\n entries\n .command(\"import\")\n .description(\"Create one entry per NDJSON line (exported entries or {fields, slug, …} bodies)\")\n .argument(\"<model>\")\n .argument(\"<file>\", \"a file, or - for stdin\")\n .option(\"--publish\", \"publish each entry after creating it\")\n .addHelpText(\n \"after\",\n `\nEvery line is tried; a line that fails is reported with its number and the\nrun continues, exiting 1 at the end if any failed.`,\n )\n .action(async (model: string, file: string, flags: { publish?: boolean }, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const siteKey = requireSiteKey(ctx);\n const text = await readText(file === \"-\" ? \"-\" : `@${file}`, io.stdin);\n let failed = 0;\n let n = 0;\n for (const raw of text.split(\"\\n\")) {\n const line = raw.trim();\n if (line === \"\") continue;\n n++;\n try {\n const body = importBody(JSON.parse(line) as Record<string, unknown>, ctx);\n let entry = (\n await request<Entry>(ctx, \"POST\", `content/${encodeURIComponent(model)}`, {\n query: { site_key: siteKey },\n body,\n })\n ).data;\n if (flags.publish) entry = await publish(ctx, entry.id, \"publish\");\n io.stdout.write(`ok ${entry.id}${entry.slug ? ` ${entry.slug}` : \"\"}\\n`);\n } catch (err) {\n failed++;\n const why = err instanceof Error ? (err as { code?: string }).code ?? err.message : String(err);\n io.stdout.write(`fail line ${n}: ${why}\\n`);\n }\n }\n io.stderr.write(`${n - failed} created, ${failed} failed\\n`);\n if (failed) throw new CliError(\"\", 1);\n });\n}\n\nfunction applyWriteFlags(body: EntryBody, flags: WriteFlags): void {\n if (flags.slug !== undefined) body.slug = flags.slug;\n if (flags.folder !== undefined) body.folder_id = flags.folder;\n if (flags.publishAt !== undefined) body.publish_at = flags.publishAt;\n if (flags.unpublishAt !== undefined) body.unpublish_at = flags.unpublishAt;\n if (flags.note !== undefined) body.note = flags.note;\n}\n\n/** An exported entry (`data`) or a bare write body (`fields`) → the write body. */\nfunction importBody(line: Record<string, unknown>, ctx: Context): EntryBody {\n if (\"fields\" in line) return line as unknown as EntryBody;\n if (!(\"data\" in line)) throw usageError(\"expected an object with fields or data\");\n const e = line as Partial<Entry>;\n const body: EntryBody = { fields: (e.data ?? {}) as Record<string, unknown> };\n if (e.slug) body.slug = e.slug;\n if (e.locale ?? ctx.locale) body.locale = e.locale ?? ctx.locale;\n if (e.folder_id) body.folder_id = e.folder_id;\n if (e.publish_at) body.publish_at = e.publish_at;\n if (e.unpublish_at) body.unpublish_at = e.unpublish_at;\n return body;\n}\n\nfunction report(ctx: Context, entry: Entry, verb: string): void {\n if (ctx.json) ctx.io.stdout.write(toJson(entry) + \"\\n\");\n else ctx.io.stdout.write(`${verb} ${entry.id}${entry.slug ? ` ${entry.slug}` : \"\"} (${entry.status})\\n`);\n}\n","import type { Command } from \"commander\";\nimport { resolveContext, type Context, type GlobalOptions, type Io } from \"../config.js\";\nimport { request } from \"../api/http.js\";\nimport { formatTable, toJson } from \"../output.js\";\nimport { toListOptions, type ListFlags } from \"../entries/query.js\";\nimport type { ListOptions } from \"@plenary/client\";\n\ninterface FormEntry {\n id: string;\n form_key: string;\n site_key: string;\n status: string;\n created_at: string;\n data: Record<string, unknown>;\n}\n\nfunction collect(value: string, previous: string[]): string[] {\n return [...previous, value];\n}\n\n/**\n * Form-entry lists take the Content API's query engine, but not through\n * @plenary/client (which is the public delivery surface), so the options are\n * compiled to a query string here with the same rules.\n */\nfunction toQuery(ctx: Context, opts: ListOptions): Record<string, string> {\n const q: Record<string, string> = {};\n if (ctx.siteKey) q.site_key = ctx.siteKey;\n for (const [field, value] of Object.entries(opts.where ?? {})) {\n if (typeof value === \"object\" && value !== null) {\n for (const [op, v] of Object.entries(value as Record<string, unknown>)) {\n q[`where:${field}.${op}`] = Array.isArray(v) ? v.join(\",\") : String(v);\n }\n } else {\n q[`where:${field}`] = String(value);\n }\n }\n if (opts.filters) q.filters = JSON.stringify(opts.filters);\n for (const [field, dir] of Object.entries(opts.sort ?? {})) q[`sort:${field}`] = dir;\n if (opts.limit !== undefined) q.limit = String(opts.limit);\n if (opts.offset !== undefined) q.offset = String(opts.offset);\n if (opts.count) q.count = \"true\";\n return q;\n}\n\nconst PAGE = 100;\n\nexport function registerFormEntries(forms: Command, io: Io): void {\n const entries = forms.command(\"entries\").description(\"Form entries (what visitors submitted)\");\n\n const listFlags = (cmd: Command) =>\n cmd\n .option(\"-w, --where <field=value>\", \"filter: field=value or field=$op:value (repeatable)\", collect, [])\n .option(\"--filters <json>\", \"a filter tree (inline JSON, @file, or -)\")\n .option(\"-s, --sort <field[:dir]>\", \"sort field, asc unless :desc (repeatable)\", collect, [])\n .option(\"--limit <n>\")\n .option(\"--offset <n>\")\n .option(\"--count\", \"ask for the total and show it\");\n\n listFlags(entries.command(\"list\").description(\"List a form's entries\").argument(\"<form>\")).action(\n async (form: string, flags: ListFlags, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const opts = await toListOptions(flags, io.stdin);\n const res = await request<FormEntry[]>(ctx, \"GET\", `forms/${encodeURIComponent(form)}/entries`, {\n query: toQuery(ctx, opts),\n });\n const total = res.headers.get(\"X-Total-Count\");\n if (ctx.json) {\n io.stdout.write(toJson({ items: res.data, ...(total !== null ? { total: Number(total) } : {}) }) + \"\\n\");\n return;\n }\n const rows = res.data.map((e) => [e.id, e.status, e.site_key, e.created_at, summary(e.data)]);\n io.stdout.write(formatTable(rows, [\"ID\", \"STATUS\", \"SITE\", \"CREATED\", \"DATA\"]) + \"\\n\");\n if (total !== null) io.stdout.write(`${res.data.length} of ${total}\\n`);\n },\n );\n\n listFlags(entries.command(\"export\").description(\"Write every matching entry to stdout as NDJSON\").argument(\"<form>\")).action(\n async (form: string, flags: ListFlags, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const opts = await toListOptions(flags, io.stdin);\n const limit = opts.limit ?? PAGE;\n let offset = opts.offset ?? 0;\n for (;;) {\n const res = await request<FormEntry[]>(ctx, \"GET\", `forms/${encodeURIComponent(form)}/entries`, {\n query: toQuery(ctx, { ...opts, limit, offset, count: false }),\n });\n for (const e of res.data) io.stdout.write(JSON.stringify(e) + \"\\n\");\n if (res.data.length < limit) return;\n offset += res.data.length;\n }\n },\n );\n}\n\n/** The first few values, for a glance at what was submitted. */\nfunction summary(data: Record<string, unknown>): string {\n return Object.entries(data)\n .slice(0, 3)\n .map(([k, v]) => `${k}=${typeof v === \"string\" ? v : JSON.stringify(v)}`)\n .join(\" \");\n}\n","import { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { Command } from \"commander\";\nimport { resolveContext, type GlobalOptions, type Io } from \"../config.js\";\nimport { request } from \"../api/http.js\";\nimport { CliError, usageError } from \"../errors.js\";\nimport { formatTable, toJson } from \"../output.js\";\n\ninterface MediaItem {\n media_id: string;\n media_type: string;\n mime_type: string;\n file_name: string;\n file_size: number;\n path: string;\n visibility: string;\n original_url: string;\n created_at: string;\n}\n\nfunction size(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nexport function registerMedia(program: Command, io: Io): void {\n const media = program.command(\"media\").description(\"Media library\");\n\n media\n .command(\"upload\")\n .description(\"Upload one or more files\")\n .argument(\"<files...>\")\n .option(\"--folder <id>\", \"media folder id\")\n .option(\"--private\", \"store as a private asset\")\n .action(async (files: string[], flags: { folder?: string; private?: boolean }, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const uploaded: MediaItem[] = [];\n let failed = 0;\n for (const file of files) {\n let bytes: Buffer;\n try {\n bytes = readFileSync(file);\n } catch (err) {\n throw usageError(`cannot read ${file}: ${(err as Error).message}`);\n }\n const form = new FormData();\n form.append(\"upload_file\", new Blob([new Uint8Array(bytes)]), path.basename(file));\n if (flags.folder) form.append(\"folder_id\", flags.folder);\n if (flags.private) form.append(\"visibility\", \"private\");\n try {\n const res = await request<MediaItem>(ctx, \"POST\", \"media\", { form });\n uploaded.push(res.data);\n if (!ctx.json) io.stdout.write(`${res.data.media_id} ${res.data.file_name}\\n`);\n } catch (err) {\n if (files.length === 1) throw err;\n failed++;\n const code = (err as { code?: string }).code ?? (err as Error).message;\n io.stdout.write(`fail ${file}: ${code}\\n`);\n }\n }\n if (ctx.json) io.stdout.write(toJson(uploaded) + \"\\n\");\n if (failed) throw new CliError(\"\", 1);\n });\n\n media\n .command(\"list\")\n .description(\"List media\")\n .option(\"--search <text>\", \"match file names and captions\")\n .option(\"--path <prefix>\", \"only assets under this folder path\")\n .option(\"--limit <n>\")\n .option(\"--page <n>\")\n .action(async (flags: { search?: string; path?: string; limit?: string; page?: string }, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const res = await request<MediaItem[]>(ctx, \"GET\", \"media\", {\n query: { search: flags.search, path_prefix: flags.path, limit: flags.limit, page: flags.page },\n });\n if (ctx.json) {\n io.stdout.write(toJson(res.data) + \"\\n\");\n return;\n }\n const rows = res.data.map((m) => [m.media_id, m.media_type, m.file_name, size(m.file_size), m.path, m.visibility]);\n io.stdout.write(formatTable(rows, [\"ID\", \"TYPE\", \"FILE\", \"SIZE\", \"PATH\", \"VISIBILITY\"]) + \"\\n\");\n });\n\n media\n .command(\"get\")\n .description(\"Print one media item as JSON\")\n .argument(\"<id>\")\n .action(async (id: string, _flags: unknown, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const res = await request(ctx, \"GET\", `media/${encodeURIComponent(id)}`);\n io.stdout.write(toJson(res.data) + \"\\n\");\n });\n}\n","import path from \"node:path\";\nimport type { Command } from \"commander\";\nimport { resolveContext, type Context, type GlobalOptions, type Io } from \"../config.js\";\nimport { PlenaryError } from \"@plenary/client\";\nimport { request, type ApiResponse, type RequestOptions } from \"../api/http.js\";\nimport { usageError } from \"../errors.js\";\nimport { confirm } from \"../input.js\";\nimport { toJson } from \"../output.js\";\nimport { filterKinds, parseKinds, readTree, writeTree, type Kind, type YamlFile } from \"../metadata/dir.js\";\nimport { formatPlan, type ImportResult } from \"../metadata/plan.js\";\n\ninterface DirOption {\n dir?: string;\n only?: string;\n verbose?: boolean;\n dryRun?: boolean;\n prune?: boolean;\n yes?: boolean;\n allSites?: boolean;\n}\n\n/**\n * The site whose tree the command moves: the configured one (--site,\n * PLENARY_SITE_KEY, plenary.json) unless --all-sites asks for the whole\n * instance. A site's tree never holds roles, which are instance-wide.\n */\nfunction siteOf(ctx: Context, opts: DirOption): string | undefined {\n return opts.allSites ? undefined : ctx.siteKey;\n}\n\nfunction kindsOf(opts: DirOption, site?: string): Kind[] {\n let kinds: Kind[];\n try {\n kinds = parseKinds(opts.only);\n } catch (err) {\n throw usageError(`--only: ${(err as Error).message}`);\n }\n if (!site) return kinds;\n if (opts.only && opts.only !== \"all\" && kinds.includes(\"roles\")) {\n throw usageError(`roles are instance-wide and not part of site ${site}'s tree; use --all-sites`);\n }\n return kinds.filter((k) => k !== \"roles\");\n}\n\n/**\n * A server that predates per-site trees ignores site_key and answers for the\n * whole instance, so the echo is what says the answer is the site's alone.\n */\nfunction isSiteAnswer(data: { site_key?: string }, site: string | undefined): boolean {\n return !site || data.site_key === site;\n}\n\nconst UNSCOPED_SERVER = (site: string) =>\n `this server predates per-site metadata: it answered for every site, not just ${site}`;\n\n/** `--dir` is relative to the cwd; the configured directory to the config file. */\nfunction treeRoot(ctx: Context, opts: DirOption): string {\n return opts.dir ? path.resolve(ctx.io.cwd, opts.dir) : path.resolve(ctx.projectRoot, ctx.metadataDir);\n}\n\nfunction readTreeOrFail(root: string, kinds: Kind[]): YamlFile[] {\n const files = filterKinds(readTree(root), kinds);\n if (files.length === 0) throw usageError(`no YAML files under ${root}/{${kinds.join(\",\")}}`);\n return files;\n}\n\nconst OLDER_SERVER =\n \"this server predates the whole-tree metadata endpoints: it can sync models and forms only\";\n\n/**\n * The whole-tree route, falling back to the models-only one a server from\n * without them has, so an older instance keeps working for models and\n * forms. Roles, sites and --prune have nowhere to go there and are refused\n * with a message rather than a bare 404.\n */\nasync function metadataRequest<T>(\n ctx: Context,\n method: \"GET\" | \"POST\",\n opts: RequestOptions,\n needsWholeTree: boolean,\n): Promise<ApiResponse<T>> {\n const path = method === \"GET\" ? \"metadata\" : \"metadata/import\";\n try {\n return await request<T>(ctx, method, path, opts);\n } catch (err) {\n if (!(err instanceof PlenaryError) || err.status !== 404 || err.code !== \"http_404\") throw err;\n if (needsWholeTree) throw usageError(OLDER_SERVER);\n const fallback = method === \"GET\" ? \"metadata/models\" : \"metadata/models/import\";\n return request<T>(ctx, method, fallback, opts);\n }\n}\n\n/**\n * Both diff and push: the plan is always previewed first, and a push with\n * --prune is confirmed against that preview before anything is deleted.\n */\nasync function runImport(ctx: Context, root: string, opts: DirOption, apply: boolean): Promise<void> {\n const site = siteOf(ctx, opts);\n const kinds = kindsOf(opts, site);\n const files = readTreeOrFail(root, kinds);\n const prune = Boolean(opts.prune);\n const body = { files, apply: false, prune };\n const query = site ? { site_key: site } : undefined;\n const wholeTree = prune || files.some((f) => !/^(models|forms)\\//.test(f.path));\n let res = await metadataRequest<ImportResult>(ctx, \"POST\", { body, query }, wholeTree);\n // Pruning against a server that ignored the site would delete every other\n // site's models; refuse before anything is applied.\n if (!isSiteAnswer(res.data, site)) {\n if (prune) throw usageError(`${UNSCOPED_SERVER(site!)}; --prune would delete other sites' models (use --all-sites if that is meant)`);\n ctx.io.stderr.write(`warning: ${UNSCOPED_SERVER(site!)}\\n`);\n }\n const deletes = res.data.changes.filter((c) => c.action === \"delete\");\n\n if (apply) {\n if (deletes.length > 0) {\n if (!ctx.json) ctx.io.stdout.write(formatPlan(res.data, Boolean(opts.verbose)) + \"\\n\");\n await confirm(ctx.io, `Delete ${deletes.length} ${deletes.length === 1 ? \"entity\" : \"entities\"} from the instance?`, Boolean(opts.yes));\n }\n res = await metadataRequest<ImportResult>(ctx, \"POST\", { body: { ...body, apply: true }, query }, wholeTree);\n }\n if (ctx.json) ctx.io.stdout.write(toJson(res.data) + \"\\n\");\n else ctx.io.stdout.write(formatPlan(res.data, Boolean(opts.verbose)) + \"\\n\");\n}\n\nconst onlyOption = [\"--only <kinds>\", \"comma list of models, forms, roles, sites (default: all)\"] as const;\nconst allSitesOption = [\"--all-sites\", \"the whole instance, not just the configured site (roles need this)\"] as const;\n\nexport function registerMetadata(program: Command, io: Io): void {\n const metadata = program\n .command(\"metadata\")\n .description(\"Keep a directory of model and form YAML in step with the instance\")\n .addHelpText(\n \"after\",\n `\nThe tree is models/, forms/, roles/ and sites/ under the metadata directory\n(\"metadataDir\" in plenary.json, default ./plenary), one <key>.yaml per\nentity. With a site configured (--site, PLENARY_SITE_KEY or \"siteKey\" in\nplenary.json) the tree is that site's alone: its models, forms and site file,\nnever roles, and --prune deletes only within it. --all-sites moves the whole\ninstance. Models and forms need an API key or a session; roles and sites need\na user session (plenary login). See docs/CLI.md.`,\n );\n\n metadata\n .command(\"pull\")\n .description(\"Write every model, form, role and site the credential may read into the directory\")\n .option(\"--dir <path>\", \"metadata directory (default: the configured one)\")\n .option(...onlyOption)\n .option(...allSitesOption)\n .action(async (opts: DirOption, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const root = treeRoot(ctx, opts);\n const site = siteOf(ctx, opts);\n const kinds = kindsOf(opts, site);\n const wholeTree = kinds.some((k) => k === \"roles\" || k === \"sites\") && Boolean(opts.only);\n const res = await metadataRequest<{ files: YamlFile[]; omitted?: string[]; site_key?: string }>(\n ctx,\n \"GET\",\n { query: { only: kinds.join(\",\"), ...(site ? { site_key: site } : {}) } },\n wholeTree,\n );\n // Writing every site's models into one site's repository is never what\n // a pull meant, and a later push --prune would then own them.\n if (!isSiteAnswer(res.data, site)) throw usageError(`${UNSCOPED_SERVER(site!)}; pull with --all-sites for the whole instance`);\n const result = writeTree(root, res.data.files, kinds);\n const omitted = res.data.omitted ?? [];\n if (ctx.json) {\n io.stdout.write(toJson({ dir: root, ...result, omitted }) + \"\\n\");\n return;\n }\n io.stdout.write(`wrote ${result.written.length} file${result.written.length === 1 ? \"\" : \"s\"} to ${root}\\n`);\n if (omitted.length) {\n io.stderr.write(`not included, the credential may not read them: ${omitted.join(\", \")}\\n`);\n }\n if (result.written.length === 0 && omitted.length === 0) {\n // The server answers a key that may read no models with an empty tree,\n // not a refusal, so say what the likely cause is.\n io.stderr.write(\"the server sent no models: the key may lack content:models:read (a public key never has it)\\n\");\n }\n if (result.stale.length) {\n io.stdout.write(`not on the server (left in place):\\n${result.stale.map((p) => ` ${p}`).join(\"\\n\")}\\n`);\n }\n });\n\n metadata\n .command(\"diff\")\n .description(\"Preview what push would change, without writing anything\")\n .option(\"--dir <path>\", \"metadata directory (default: the configured one)\")\n .option(...onlyOption)\n .option(...allSitesOption)\n .option(\"--prune\", \"include what push --prune would delete\")\n .option(\"--verbose\", \"list unchanged entities too\")\n .action(async (opts: DirOption, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n await runImport(ctx, treeRoot(ctx, opts), opts, false);\n });\n\n metadata\n .command(\"push\")\n .description(\"Apply the directory to the instance (creates and updates; deletes only with --prune)\")\n .option(\"--dir <path>\", \"metadata directory (default: the configured one)\")\n .option(...onlyOption)\n .option(...allSitesOption)\n .option(\"--prune\", \"also delete entities absent from the directory, within the kinds (and site) it holds\")\n .option(\"-y, --yes\", \"do not ask before pruning\")\n .option(\"--dry-run\", \"same as diff\")\n .option(\"--verbose\", \"list unchanged entities too\")\n .addHelpText(\n \"after\",\n `\n--prune deletes only within the kinds present in the directory: a tree with\nno roles/ cannot delete a role. System-owned roles are never touched and are\nreported as skipped. The plan is shown and confirmed before anything is\ndeleted; -y skips the question, and a run with no terminal needs it.`,\n )\n .action(async (opts: DirOption, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n await runImport(ctx, treeRoot(ctx, opts), opts, !opts.dryRun);\n });\n}\n","import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\n\n/** One file of a metadata tree, `path` relative to the tree's root. */\nexport interface YamlFile {\n path: string;\n content: string;\n}\n\n/** The directories the server reads and writes. */\nexport const MANAGED_DIRS = [\"models\", \"forms\", \"roles\", \"sites\"] as const;\nexport type Kind = (typeof MANAGED_DIRS)[number];\n\n/** `--only models,roles` → the kinds it names; empty or \"all\" → every kind. */\nexport function parseKinds(spec: string | undefined): Kind[] {\n if (!spec || spec === \"all\") return [...MANAGED_DIRS];\n const out: Kind[] = [];\n for (const raw of spec.split(\",\")) {\n const k = raw.trim() as Kind;\n if (!MANAGED_DIRS.includes(k)) throw new Error(`unknown kind \"${k}\" (want ${MANAGED_DIRS.join(\", \")} or all)`);\n if (!out.includes(k)) out.push(k);\n }\n return out;\n}\n\n/** Only the files under the named kinds' directories. */\nexport function filterKinds(files: YamlFile[], kinds: Kind[]): YamlFile[] {\n return files.filter((f) => kinds.includes(f.path.split(\"/\")[0] as Kind));\n}\n\n/** Every `models/*.yaml` and `forms/*.yaml` directly under `root`, sorted by path. */\nexport function readTree(root: string): YamlFile[] {\n const out: YamlFile[] = [];\n for (const rel of managedFiles(root)) {\n out.push({ path: rel, content: readFileSync(path.join(root, rel), \"utf8\") });\n }\n return out;\n}\n\nexport interface WriteResult {\n written: string[];\n /** Managed files already on disk that the server did not send — reported, never deleted. */\n stale: string[];\n}\n\n/**\n * Writes the server's files into `root`, creating directories as needed.\n * Stale files are only looked for under `kinds`, since a pull of models\n * alone says nothing about the roles on disk.\n */\nexport function writeTree(root: string, files: YamlFile[], kinds: Kind[] = [...MANAGED_DIRS]): WriteResult {\n const before = new Set(managedFiles(root).filter((p) => kinds.includes(p.split(\"/\")[0] as Kind)));\n const written: string[] = [];\n for (const f of [...files].sort((a, b) => a.path.localeCompare(b.path))) {\n if (!isTreePath(f.path)) continue;\n const abs = path.join(root, f.path);\n mkdirSync(path.dirname(abs), { recursive: true });\n writeFileSync(abs, f.content);\n written.push(f.path);\n before.delete(f.path);\n }\n return { written, stale: [...before].sort() };\n}\n\n/** `models/x.yaml` or `forms/x.yaml`, directly under the root; nothing else. */\nexport function isTreePath(p: string): boolean {\n const parts = p.split(\"/\");\n return (\n parts.length === 2 &&\n (MANAGED_DIRS as readonly string[]).includes(parts[0] as string) &&\n (parts[1] as string).endsWith(\".yaml\")\n );\n}\n\nfunction managedFiles(root: string): string[] {\n const out: string[] = [];\n for (const dir of MANAGED_DIRS) {\n const abs = path.join(root, dir);\n if (!existsSync(abs)) continue;\n for (const name of readdirSync(abs).sort()) {\n if (name.endsWith(\".yaml\")) out.push(`${dir}/${name}`);\n }\n }\n return out.sort();\n}\n","/** One row of the server's import plan. */\nexport interface ImportChange {\n key: string;\n kind: string;\n action: \"create\" | \"update\" | \"noop\" | \"delete\" | \"skip\";\n detail?: {\n fields_added: string[];\n fields_removed: string[];\n fields_changed: string[];\n attributes_changed: boolean;\n transformers_changed: boolean;\n };\n}\n\nexport interface ImportResult {\n applied: boolean;\n changes: ImportChange[];\n /** The site the plan was made for; absent on a whole-instance import. */\n site_key?: string;\n}\n\n/**\n * The plan as lines: one per create/update (noops too with `verbose`), then a\n * summary. `applied` picks the tense of the summary.\n */\nexport function formatPlan(result: ImportResult, verbose = false): string {\n const lines: string[] = [];\n const n = { create: 0, update: 0, delete: 0, skip: 0, noop: 0 };\n // Deletes first: they are what a person scanning a --prune plan must see.\n const ordered = [...result.changes].sort((a, b) => Number(b.action === \"delete\") - Number(a.action === \"delete\"));\n for (const c of ordered) {\n n[c.action]++;\n if (c.action === \"noop\" && !verbose) continue;\n const label = c.action === \"noop\" ? \"unchanged\" : c.action === \"skip\" ? \"skipped\" : c.action;\n const note = c.action === \"skip\" ? \" (system-owned)\" : detail(c);\n lines.push(`${label.padEnd(9)} ${c.kind.padEnd(10)} ${c.key}${note}`);\n }\n const parts = [`${n.create} to create`, `${n.update} to update`];\n if (n.delete) parts.push(`${n.delete} to delete`);\n if (n.skip) parts.push(`${n.skip} skipped`);\n parts.push(`${n.noop} unchanged`);\n if (n.create + n.update + n.delete === 0) {\n lines.push(`No changes: ${n.noop} unchanged${n.skip ? `, ${n.skip} skipped` : \"\"}.`);\n } else {\n lines.push(`${result.applied ? \"Applied\" : \"Plan\"}: ${parts.join(\", \")}.`);\n }\n return lines.join(\"\\n\");\n}\n\nfunction detail(c: ImportChange): string {\n const d = c.detail;\n if (!d) return \"\";\n const parts: string[] = [];\n if (d.fields_added.length) parts.push(`+${d.fields_added.join(\",\")}`);\n if (d.fields_changed.length) parts.push(`~${d.fields_changed.join(\",\")}`);\n if (d.fields_removed.length) parts.push(`-${d.fields_removed.join(\",\")}`);\n if (d.attributes_changed) parts.push(\"settings\");\n if (d.transformers_changed) parts.push(\"transformers\");\n return parts.length ? ` (${parts.join(\" \")})` : \"\";\n}\n","import { existsSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { createInterface } from \"node:readline/promises\";\nimport type { Command } from \"commander\";\nimport {\n CONFIG_FILE,\n DEFAULT_METADATA_DIR,\n resolveContext,\n type GlobalOptions,\n type Io,\n type ProjectConfig,\n} from \"../config.js\";\nimport { usageError } from \"../errors.js\";\n\nexport function registerInit(program: Command, io: Io): void {\n program\n .command(\"init\")\n .description(`Write a ${CONFIG_FILE} for this project (never a credential)`)\n .option(\"--dir <path>\", \"metadata directory, relative to the config file\", DEFAULT_METADATA_DIR)\n .option(\"-f, --force\", `overwrite an existing ${CONFIG_FILE}`)\n .addHelpText(\n \"after\",\n `\nThe base URL, site and locale come from --base-url, --site and --locale (or\ntheir PLENARY_* variables); anything missing is prompted for on a terminal.`,\n )\n .action(async (opts: { dir: string; force?: boolean }, cmd: Command) => {\n const target = path.join(io.cwd, CONFIG_FILE);\n if (existsSync(target) && !opts.force) {\n throw usageError(`${target} already exists (pass --force to overwrite)`);\n }\n const globals = cmd.optsWithGlobals<GlobalOptions>();\n // Read what the environment already says, but not a parent's plenary.json:\n // init describes this directory, not one above it.\n const ctx = resolveContext({ ...globals, config: undefined }, { ...io, cwd: path.parse(io.cwd).root });\n\n const baseUrl = globals.baseUrl ?? ctx.baseUrl ?? (await ask(io, \"Base URL (https://cms.example.com)\"));\n if (!baseUrl) throw usageError(\"a base URL is required: pass --base-url or set PLENARY_BASE_URL\");\n const siteKey = globals.site ?? ctx.siteKey ?? (await ask(io, \"Site key\", \"default\"));\n const locale = globals.locale ?? ctx.locale ?? (await ask(io, \"Locale\", \"en-us\"));\n\n const config: ProjectConfig = { baseUrl: baseUrl.replace(/\\/+$/, \"\") };\n if (siteKey) config.siteKey = siteKey;\n if (locale) config.locale = locale;\n if (opts.dir !== DEFAULT_METADATA_DIR) config.metadataDir = opts.dir;\n\n writeFileSync(target, JSON.stringify(config, null, 2) + \"\\n\");\n io.stdout.write(`wrote ${target}\\n`);\n });\n}\n\n/** Prompts on a terminal; returns the default (or undefined) without one. */\nasync function ask(io: Io, label: string, fallback?: string): Promise<string | undefined> {\n if (!io.isTTY) return fallback;\n const rl = createInterface({ input: io.stdin, output: io.stderr });\n try {\n const answer = (await rl.question(fallback ? `${label} [${fallback}]: ` : `${label}: `)).trim();\n return answer === \"\" ? fallback : answer;\n } finally {\n rl.close();\n }\n}\n","import type { Command } from \"commander\";\nimport { PlenaryError } from \"@plenary/client\";\nimport { resolveContext, type GlobalOptions, type Io } from \"../config.js\";\nimport { credentialHeaders, request } from \"../api/http.js\";\nimport { CliError } from \"../errors.js\";\nimport { toJson } from \"../output.js\";\n\ninterface Health {\n status: string;\n database: string;\n version: string;\n edition: string;\n license?: string;\n}\n\ninterface MeGrant {\n key: string;\n site_key?: string;\n content_model_id?: string;\n source: string;\n}\n\ntype Me =\n | { principal: \"api_key\"; key_id: string; key_type: string; name: string; grants: MeGrant[]; site_key?: string }\n | { principal: \"user\"; user_id: string; role: string; role_name?: string; grants: MeGrant[] };\n\nexport function registerStatus(program: Command, io: Io): void {\n program\n .command(\"status\")\n .description(\"Show the instance's health and which credential this run holds\")\n .action(async (_opts: unknown, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const health = await request<Health>(ctx, \"GET\", \"/api/v1/health\", { auth: \"none\", allowError: true });\n\n let me: Me | undefined;\n let credentialError: PlenaryError | undefined;\n // A server without API-key support on /auth/me answers /auth/me with 403 for a key it\n // accepted: the key authenticated, the server just cannot describe it.\n let undescribed = false;\n const headers = await credentialHeaders(ctx, \"optional\");\n if (Object.keys(headers).length > 0) {\n try {\n me = (await request<Me>(ctx, \"GET\", \"/api/v1/auth/me\", { auth: \"none\", headers })).data;\n } catch (err) {\n if (!(err instanceof PlenaryError)) throw err;\n if (err.status === 403) undescribed = true;\n else credentialError = err;\n }\n }\n\n const failed = !health.ok || credentialError !== undefined;\n if (ctx.json) {\n io.stdout.write(\n toJson({\n base_url: ctx.baseUrl,\n health: health.data,\n credential: me ?? null,\n credential_error: credentialError ? { status: credentialError.status, code: credentialError.code } : null,\n }) + \"\\n\",\n );\n if (failed) throw new CliError(\"\", 1);\n return;\n }\n\n const lines = [`Instance ${ctx.baseUrl}`];\n if (health.ok || (health.status === 503 && typeof health.data === \"object\")) {\n const h = health.data;\n lines.push(`Version ${h.version} (${h.edition})`);\n lines.push(`Status ${h.status}, database ${h.database}${h.license ? `, license ${h.license}` : \"\"}`);\n } else {\n lines.push(`Status unreachable (HTTP ${health.status})`);\n }\n if (me?.principal === \"api_key\") {\n lines.push(`Credential ${me.key_type} API key \"${me.name}\" (${me.grants.length} grant${me.grants.length === 1 ? \"\" : \"s\"}${\n me.site_key ? `, site ${me.site_key}` : \", instance-wide\"\n })`);\n } else if (me?.principal === \"user\") {\n lines.push(`Credential user session (stored login), role ${me.role_name ?? me.role}`);\n } else if (credentialError) {\n lines.push(`Credential rejected: ${credentialError.code} (HTTP ${credentialError.status})`);\n } else if (undescribed) {\n lines.push(\"Credential API key accepted (this server predates API-key support on /auth/me and cannot describe the key)\");\n } else {\n lines.push(\"Credential none (set PLENARY_CLI_API_KEY, pass --api-key, or run `plenary login`)\");\n }\n if (ctx.configPath) lines.push(`Config ${ctx.configPath}`);\n io.stdout.write(lines.join(\"\\n\") + \"\\n\");\n // The report itself is the message; the exit code is the only extra signal.\n if (failed) throw new CliError(\"\", 1);\n });\n}\n","import { run } from \"./cli.js\";\n\nrun(process.argv.slice(2), {\n stdout: process.stdout,\n stderr: process.stderr,\n stdin: process.stdin,\n env: process.env,\n cwd: process.cwd(),\n fetch: globalThis.fetch,\n isTTY: Boolean(process.stdin.isTTY),\n}).then((code) => {\n process.exitCode = code;\n});\n"],"mappings":"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","names":["readFileSync","CommanderError","existsSync","readFileSync","path","path","existsSync","readFileSync","token","path","readFileSync","readFileSync","errorFromResponse","collect","path","collect","collect","PAGE","readFileSync","path","readFileSync","path","path","PlenaryError","existsSync","mkdirSync","readFileSync","writeFileSync","path","path","PlenaryError","existsSync","writeFileSync","path","createInterface","path","existsSync","writeFileSync","createInterface","PlenaryError","PlenaryError","readFileSync","CommanderError"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plenary/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Plenary command-line client: metadata sync, content automation, and a raw API escape hatch.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"commander": "^15.0.0",
|
|
17
17
|
"yaml": "^2.9.1",
|
|
18
|
-
"@plenary/client": "0.
|
|
18
|
+
"@plenary/client": "1.0.0"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/node": "^26.1.2"
|