diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b7acea..c1c3e70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ Versions before 0.8.0 are in the [git tags](https://github.com/leemour/cli-core/ Every entry says what changed as a caller sees it, why, and what to watch for — the rules are [`docs/dev/CONVENTIONS.md`](docs/dev/CONVENTIONS.md#the-changelog). -## Unreleased +## 0.17.0 — 03.10.2026 ### Changed — may break callers @@ -15,7 +15,7 @@ Every entry says what changed as a caller sees it, why, and what to watch for ### Added -- API generators preserve explicit unions and Boolean literals, validate nested references, and emit schema definitions for shared command input traversal. RPC parameters can belong to the JSON body; multipart references retain their format. +- API generators preserve explicit unions and Boolean literals, validate nested references, and emit schema definitions for shared command input traversal. RPC parameters can belong to the JSON body; multipart references retain their format. Source adapters can mark secret fields so consumers keep them out of generated CLI arguments. ## 0.16.0 — 02.10.2026 diff --git a/package.json b/package.json index b5e151b..94c8448 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@leemour/cli-core", - "version": "0.16.0", + "version": "0.17.0", "description": "The parts every command line tool needs: output modes, terminal rendering, error model, exit codes, credentials, clocks", "license": "MIT", "author": "Viacheslav Ptsarev", diff --git a/src/codegen/manifest.ts b/src/codegen/manifest.ts index bd21bff..17fac5b 100644 --- a/src/codegen/manifest.ts +++ b/src/codegen/manifest.ts @@ -15,12 +15,13 @@ export interface ManifestOperation { parameters: readonly { name: string in: "path" | "query" | "header" | "body" + sensitive?: boolean required: boolean description?: string schema: SchemaNode }[] request?: { required: boolean; confidence: Confidence; schema?: string } - response?: { confidence: Confidence; schema?: string } + response?: { confidence: Confidence; schema?: string; sensitive?: boolean } } const withoutUndefined = (value: T): T => @@ -45,7 +46,11 @@ const toManifest = (operation: ApiOperation, tree: SchemaTree): ManifestOperatio }) : undefined, response: operation.response - ? withoutUndefined({ confidence: operation.response.confidence, schema: tree.responseName(operation.id) }) + ? withoutUndefined({ + confidence: operation.response.confidence, + schema: tree.responseName(operation.id), + sensitive: operation.response.schema?.sensitive, + }) : undefined, }) diff --git a/src/codegen/model.ts b/src/codegen/model.ts index 3fabc00..44833fe 100644 --- a/src/codegen/model.ts +++ b/src/codegen/model.ts @@ -30,6 +30,7 @@ export interface RpcBinding { export type Binding = HttpBinding | RpcBinding interface SchemaCommon { + sensitive?: boolean description?: string nullable?: boolean deprecated?: boolean @@ -82,6 +83,7 @@ export interface ApiSchema { export interface ApiParameter { name: string in: "path" | "query" | "header" | "body" + sensitive?: boolean required: boolean description?: string schema: SchemaNode diff --git a/src/codegen/unions.test.ts b/src/codegen/unions.test.ts index 1e94a57..dbfa151 100644 --- a/src/codegen/unions.test.ts +++ b/src/codegen/unions.test.ts @@ -18,7 +18,7 @@ const model: ApiModel = { source: { kind: "other" }, schemas: [ { id: "Address", schema: { type: "union", of: [{ type: "integer", format: "int64" }, { type: "string" }] } }, - { id: "File", schema: { type: "string", format: "binary" } }, + { id: "File", schema: { type: "string", format: "binary", sensitive: true } }, { id: "Node", schema: { @@ -40,7 +40,7 @@ const model: ApiModel = { binding: { kind: "rpc", name: "readNode" }, tags: [], parameters: [{ name: "address", in: "body", required: true, schema: { type: "ref", ref: "Address" } }], - response: { required: true, confidence: "contract", schema: { type: "ref", ref: "Node" } }, + response: { required: true, confidence: "contract", schema: { type: "ref", ref: "Node", sensitive: true } }, effect: "read", source: { location: "methods/readNode" }, }, @@ -103,9 +103,10 @@ describe("generated unions", () => { it("emits runtime definitions with source formats and resolves response references", async () => { const { definitions } = await import(join(root, "definitions.ts")) - expect(definitions.File).toEqual({ type: "string", format: "binary" }) + expect(definitions.File).toEqual({ type: "string", format: "binary", sensitive: true }) const { operations } = await import(join(root, "manifest.ts")) expect(operations[0].response.schema).toBe("Node") + expect(operations[0].response.sensitive).toBe(true) expect(definitions.Node.type).toBe("union") })