@plenary/cli 0.3.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/LICENSE +21 -0
- package/README.md +33 -0
- package/dist/index.js +1043 -0
- package/dist/index.js.map +1 -0
- package/package.json +30 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/output.ts","../src/errors.ts","../src/config.ts","../src/api/http.ts","../src/input.ts","../src/commands/api.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 { registerApi } from \"./commands/api.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 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 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}\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\nexport function requireApiKey(ctx: Context): string {\n if (!ctx.apiKey) {\n throw usageError(\"no credential: pass --api-key or set PLENARY_API_KEY\");\n }\n return ctx.apiKey;\n}\n","import { errorFromResponse } from \"@plenary/client\";\nimport { requireApiKey, requireBaseUrl, type Context } from \"../config.js\";\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 key; \"optional\" sends one\n * when present; \"none\" never sends one (the health check).\n */\n auth?: \"required\" | \"optional\" | \"none\";\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 auth = opts.auth ?? \"required\";\n const headers: Record<string, string> = { ...opts.headers };\n if (auth === \"required\") headers[\"X-API-KEY\"] = requireApiKey(ctx);\n else if (auth === \"optional\" && ctx.apiKey) headers[\"X-API-KEY\"] = ctx.apiKey;\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 { 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","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, 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 { requireApiKey, requireBaseUrl, type Context } from \"../config.js\";\nimport { 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/** A @plenary/client for this run: the content reads go through it. */\nexport async function contentClient(ctx: Context): Promise<PlenaryClient> {\n const siteKey = requireSiteKey(ctx);\n return createClient({\n baseUrl: requireBaseUrl(ctx),\n siteKey,\n apiKey: requireApiKey(ctx),\n locale: await resolveLocale(ctx, siteKey),\n fetch: ctx.io.fetch,\n });\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 { request } from \"../api/http.js\";\nimport { usageError } from \"../errors.js\";\nimport { toJson } from \"../output.js\";\nimport { readTree, writeTree, type YamlFile } from \"../metadata/dir.js\";\nimport { formatPlan, type ImportResult } from \"../metadata/plan.js\";\n\ninterface DirOption {\n dir?: string;\n verbose?: boolean;\n dryRun?: boolean;\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): YamlFile[] {\n const files = readTree(root);\n if (files.length === 0) throw usageError(`no YAML files under ${root}/models or ${root}/forms`);\n return files;\n}\n\nasync function runImport(ctx: Context, root: string, apply: boolean, verbose: boolean): Promise<void> {\n const files = readTreeOrFail(root);\n const res = await request<ImportResult>(ctx, \"POST\", \"metadata/models/import\", { body: { files, apply } });\n if (ctx.json) ctx.io.stdout.write(toJson(res.data) + \"\\n\");\n else ctx.io.stdout.write(formatPlan(res.data, verbose) + \"\\n\");\n}\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/<key>.yaml and forms/<key>.yaml under the metadata\ndirectory (\"metadataDir\" in plenary.json, default ./plenary). See\ndocs/CONTENT_MODELS.md, \"YAML import and export\".`,\n );\n\n metadata\n .command(\"pull\")\n .description(\"Write every model and form the key may read into the directory\")\n .option(\"--dir <path>\", \"metadata directory (default: the configured one)\")\n .action(async (opts: DirOption, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n const root = treeRoot(ctx, opts);\n const res = await request<{ files: YamlFile[] }>(ctx, \"GET\", \"metadata/models\");\n const result = writeTree(root, res.data.files);\n if (ctx.json) {\n io.stdout.write(toJson({ dir: root, ...result }) + \"\\n\");\n return;\n }\n io.stdout.write(`wrote ${result.written.length} file${result.written.length === 1 ? \"\" : \"s\"} to ${root}\\n`);\n if (result.written.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(\"--verbose\", \"list unchanged models too\")\n .action(async (opts: DirOption, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n await runImport(ctx, treeRoot(ctx, opts), false, Boolean(opts.verbose));\n });\n\n metadata\n .command(\"push\")\n .description(\"Apply the directory to the instance (creates and updates; never deletes)\")\n .option(\"--dir <path>\", \"metadata directory (default: the configured one)\")\n .option(\"--dry-run\", \"same as diff\")\n .option(\"--verbose\", \"list unchanged models too\")\n .action(async (opts: DirOption, cmd: Command) => {\n const ctx = resolveContext(cmd.optsWithGlobals<GlobalOptions>(), io);\n await runImport(ctx, treeRoot(ctx, opts), !opts.dryRun, Boolean(opts.verbose));\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; the same rule as the console. */\nexport const MANAGED_DIRS = [\"models\", \"forms\"] as const;\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/** Writes the server's files into `root`, creating directories as needed. */\nexport function writeTree(root: string, files: YamlFile[]): WriteResult {\n const before = new Set(managedFiles(root));\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\";\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 let creates = 0;\n let updates = 0;\n let noops = 0;\n for (const c of result.changes) {\n if (c.action === \"create\") creates++;\n else if (c.action === \"update\") updates++;\n else noops++;\n if (c.action === \"noop\" && !verbose) continue;\n const label = c.action === \"noop\" ? \"unchanged\" : c.action;\n lines.push(`${label.padEnd(9)} ${c.kind.padEnd(10)} ${c.key}${detail(c)}`);\n }\n const counts = `${creates} to create, ${updates} to update, ${noops} unchanged`;\n if (creates + updates === 0) lines.push(`No changes: ${noops} unchanged.`);\n else lines.push(result.applied ? `Applied: ${counts}.` : `Plan: ${counts}.`);\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 { 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 if (ctx.apiKey) {\n try {\n me = (await request<Me>(ctx, \"GET\", \"/api/v1/auth/me\")).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, 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 or pass --api-key)\");\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","path","readFileSync","readFileSync","errorFromResponse","path","collect","collect","PAGE","readFileSync","path","readFileSync","path","path","existsSync","readFileSync","path","path","existsSync","writeFileSync","path","createInterface","path","existsSync","writeFileSync","createInterface","PlenaryError","PlenaryError","readFileSync","CommanderError"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@plenary/cli",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Plenary command-line client: metadata sync, content automation, and a raw API escape hatch.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"plenary": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">=20"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"commander": "^15.0.0",
|
|
17
|
+
"yaml": "^2.9.1",
|
|
18
|
+
"@plenary/client": "0.3.0"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/node": "^26.1.2"
|
|
22
|
+
},
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsup",
|
|
26
|
+
"dev": "tsup --watch",
|
|
27
|
+
"test": "vitest run",
|
|
28
|
+
"typecheck": "tsc --noEmit"
|
|
29
|
+
}
|
|
30
|
+
}
|