@webpieces/api-doc-model 0.4.803 → 0.4.805
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 +19 -2
- package/package.json +2 -1
- package/src/extract/ApiDocExtractor.d.ts +80 -7
- package/src/extract/ApiDocExtractor.js +272 -40
- package/src/extract/ApiDocExtractor.js.map +1 -1
- package/src/extract/ConstantFolder.d.ts +16 -3
- package/src/extract/ConstantFolder.js +42 -3
- package/src/extract/ConstantFolder.js.map +1 -1
- package/src/extract/JsDoc.d.ts +10 -0
- package/src/extract/JsDoc.js +18 -2
- package/src/extract/JsDoc.js.map +1 -1
- package/src/extract/TypeResolver.d.ts +9 -0
- package/src/extract/TypeResolver.js +32 -7
- package/src/extract/TypeResolver.js.map +1 -1
- package/src/index.d.ts +8 -4
- package/src/index.js +13 -4
- package/src/index.js.map +1 -1
- package/src/model/ApiDocModel.d.ts +162 -13
- package/src/model/ApiDocModel.js +129 -14
- package/src/model/ApiDocModel.js.map +1 -1
- package/src/render/McpRenderError.d.ts +27 -0
- package/src/render/McpRenderError.js +36 -0
- package/src/render/McpRenderError.js.map +1 -0
- package/src/render/McpSchemaRenderer.d.ts +79 -0
- package/src/render/McpSchemaRenderer.js +235 -0
- package/src/render/McpSchemaRenderer.js.map +1 -0
- package/src/render/McpToolDefinition.d.ts +44 -0
- package/src/render/McpToolDefinition.js +44 -0
- package/src/render/McpToolDefinition.js.map +1 -0
package/src/model/ApiDocModel.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ApiDocModel = exports.DocumentedEndpoint = exports.DocumentedAuth = exports.DocumentedMcpTool = exports.DocumentedEndpointOptions = exports.DocumentedType = exports.DocumentedField = exports.UnionDiscriminator = exports.UnmappedType = void 0;
|
|
3
|
+
exports.ApiDocModel = exports.DocumentedEndpoint = exports.DocumentedAuth = exports.DocumentedApiKey = exports.DocumentedApiKeyCredential = exports.DocumentedMcpTool = exports.DocumentedEndpointOptions = exports.DocumentedType = exports.DocumentedField = exports.UnionDiscriminator = exports.UnmappedType = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* The model classes. Every one of them is a CLASS with an explicit constructor per `CLAUDE.md` §1 —
|
|
6
6
|
* these are data-only structures, and a renderer (#982) builds nothing, it only reads.
|
|
@@ -53,6 +53,7 @@ class DocumentedField {
|
|
|
53
53
|
format;
|
|
54
54
|
min;
|
|
55
55
|
max;
|
|
56
|
+
mcpHeader;
|
|
56
57
|
constructor(name, type,
|
|
57
58
|
/**
|
|
58
59
|
* OPTIONAL (`name?: string`) — the property may be ABSENT. Distinguished from
|
|
@@ -75,7 +76,18 @@ class DocumentedField {
|
|
|
75
76
|
/** `@WpMin(n)` — numeric fields only; anything else is a build failure. */
|
|
76
77
|
min,
|
|
77
78
|
/** `@WpMax(n)` — numeric fields only; anything else is a build failure. */
|
|
78
|
-
max
|
|
79
|
+
max,
|
|
80
|
+
/**
|
|
81
|
+
* The `@mcpHeader <token>` JSDoc tag — the MCP 2026 SEP-2243 header this PRIMITIVE field is
|
|
82
|
+
* mirrored into (`Mcp-Param-{token}`). Undefined for every field that is not mirrored, which
|
|
83
|
+
* is nearly all of them.
|
|
84
|
+
*
|
|
85
|
+
* It is documentation and therefore lives in JSDoc, next to the sentence describing the
|
|
86
|
+
* field, rather than in a decorator argument. The runtime spells it `WpMcpHeader` inside
|
|
87
|
+
* `@WpDtoField`; the two are proved identical by the equivalence gate (#983) before #984
|
|
88
|
+
* deletes the decorator spelling.
|
|
89
|
+
*/
|
|
90
|
+
mcpHeader) {
|
|
79
91
|
this.name = name;
|
|
80
92
|
this.type = type;
|
|
81
93
|
this.optional = optional;
|
|
@@ -85,6 +97,7 @@ class DocumentedField {
|
|
|
85
97
|
this.format = format;
|
|
86
98
|
this.min = min;
|
|
87
99
|
this.max = max;
|
|
100
|
+
this.mcpHeader = mcpHeader;
|
|
88
101
|
}
|
|
89
102
|
}
|
|
90
103
|
exports.DocumentedField = DocumentedField;
|
|
@@ -118,7 +131,7 @@ class DocumentedType {
|
|
|
118
131
|
}
|
|
119
132
|
}
|
|
120
133
|
exports.DocumentedType = DocumentedType;
|
|
121
|
-
/** `@Endpoint(path, kind, options?)`'s
|
|
134
|
+
/** `@Endpoint(httpMethod, path, operation, kind, options?)`'s LAST argument, as a document sees it. */
|
|
122
135
|
class DocumentedEndpointOptions {
|
|
123
136
|
formPost;
|
|
124
137
|
calledBy;
|
|
@@ -132,38 +145,108 @@ class DocumentedEndpointOptions {
|
|
|
132
145
|
}
|
|
133
146
|
}
|
|
134
147
|
exports.DocumentedEndpointOptions = DocumentedEndpointOptions;
|
|
135
|
-
/**
|
|
148
|
+
/**
|
|
149
|
+
* The `@WpMcpTool(...)` declaration, when the method carries one — the TWO facts the source cannot
|
|
150
|
+
* otherwise state, and nothing else.
|
|
151
|
+
*
|
|
152
|
+
* `description` is deliberately NOT read off the decorator. The method's JSDoc is the description, for
|
|
153
|
+
* the agent and for the partner alike, byte-identical: two authored copies of one paragraph is the
|
|
154
|
+
* two-spellings shim, and its failure mode is concrete — the partner reads the JSDoc in the OpenAPI
|
|
155
|
+
* document while the agent reads the decorator string in `tools/list`, and they drift the first time
|
|
156
|
+
* somebody edits one. (The field still exists on the decorator; #984 deletes it across its 29 call
|
|
157
|
+
* sites. Nothing here reads it, so nothing here depends on a field that is about to disappear.)
|
|
158
|
+
*
|
|
159
|
+
* The three side-effect hints are not read either: they are COMPUTED from the endpoint's `operation`
|
|
160
|
+
* by `mcpHintsForOperation` in `@webpieces/core-util`, which is the one place that mapping lives.
|
|
161
|
+
* `READ | WRITE_IDEMPOTENT | WRITE` already says whether repeating a call is safe, so a hand-declared
|
|
162
|
+
* hint would be a second answer to a question the contract has answered.
|
|
163
|
+
*/
|
|
136
164
|
class DocumentedMcpTool {
|
|
137
165
|
name;
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
166
|
+
constructor(
|
|
167
|
+
/**
|
|
168
|
+
* The STABLE protocol name. Deliberately independent of the method name, because renaming a
|
|
169
|
+
* method must not break a saved agent workflow.
|
|
170
|
+
*/
|
|
171
|
+
name) {
|
|
142
172
|
this.name = name;
|
|
143
|
-
this.hints = hints;
|
|
144
173
|
}
|
|
145
174
|
}
|
|
146
175
|
exports.DocumentedMcpTool = DocumentedMcpTool;
|
|
176
|
+
/**
|
|
177
|
+
* ONE credential of an api-key regime, PARSED — `{ in: 'header', name: 'x-api-key' }` or
|
|
178
|
+
* `{ in: 'bearer' }`.
|
|
179
|
+
*
|
|
180
|
+
* Parsed rather than left as source text because it is the one auth argument a renderer must turn
|
|
181
|
+
* into a STRUCTURE: an OpenAPI `securityScheme` is `{type: apiKey, in, name}` or
|
|
182
|
+
* `{type: http, scheme: bearer}`, and those are different documents. A renderer handed the string
|
|
183
|
+
* `"{ in: 'header', name: 'x-api-key' }"` would have to parse TypeScript to emit either one, which
|
|
184
|
+
* is this package's job and not a renderer's.
|
|
185
|
+
*/
|
|
186
|
+
class DocumentedApiKeyCredential {
|
|
187
|
+
location;
|
|
188
|
+
name;
|
|
189
|
+
description;
|
|
190
|
+
constructor(
|
|
191
|
+
/** `header` or `bearer`, verbatim from the declaration. */
|
|
192
|
+
location,
|
|
193
|
+
/** The header name. Undefined for `bearer`, whose location IS `Authorization`. */
|
|
194
|
+
name,
|
|
195
|
+
/** The prose a docs site renders on its authorization card. */
|
|
196
|
+
description) {
|
|
197
|
+
this.location = location;
|
|
198
|
+
this.name = name;
|
|
199
|
+
this.description = description;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
exports.DocumentedApiKeyCredential = DocumentedApiKeyCredential;
|
|
203
|
+
/** `@WpAuthApiKey(regime, credentials)`, parsed. See {@link DocumentedApiKeyCredential}. */
|
|
204
|
+
class DocumentedApiKey {
|
|
205
|
+
regime;
|
|
206
|
+
credentials;
|
|
207
|
+
constructor(regime,
|
|
208
|
+
/**
|
|
209
|
+
* Every credential the regime requires, IN DECLARATION ORDER. They are an AND — all of them
|
|
210
|
+
* are presented together — and the order is the order a published document lists them in.
|
|
211
|
+
*/
|
|
212
|
+
credentials) {
|
|
213
|
+
this.regime = regime;
|
|
214
|
+
this.credentials = credentials;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
exports.DocumentedApiKey = DocumentedApiKey;
|
|
147
218
|
/** WHICH credential an endpoint demands — `@WpAuthPublic`, `@WpAuthJwt`, … — verbatim from the source. */
|
|
148
219
|
class DocumentedAuth {
|
|
149
220
|
decorator;
|
|
150
|
-
|
|
221
|
+
argumentTexts;
|
|
222
|
+
apiKey;
|
|
151
223
|
constructor(
|
|
152
224
|
/** The decorator name as written, e.g. `WpAuthJwt`. */
|
|
153
225
|
decorator,
|
|
154
|
-
/**
|
|
155
|
-
|
|
226
|
+
/** Every argument's text, verbatim and in order. Empty for `@WpAuthPublic()`. */
|
|
227
|
+
argumentTexts,
|
|
228
|
+
/**
|
|
229
|
+
* The PARSED api-key declaration, set only for `@WpAuthApiKey`. Every other decorator's
|
|
230
|
+
* argument is prose or a role list that a document quotes rather than restructures, so
|
|
231
|
+
* {@link argumentTexts} is all they need — see {@link DocumentedApiKeyCredential} for why
|
|
232
|
+
* this one is different.
|
|
233
|
+
*/
|
|
234
|
+
apiKey) {
|
|
156
235
|
this.decorator = decorator;
|
|
157
|
-
this.
|
|
236
|
+
this.argumentTexts = argumentTexts;
|
|
237
|
+
this.apiKey = apiKey;
|
|
158
238
|
}
|
|
159
239
|
}
|
|
160
240
|
exports.DocumentedAuth = DocumentedAuth;
|
|
161
241
|
/** One `@Endpoint` method of one contract. */
|
|
162
242
|
class DocumentedEndpoint {
|
|
163
243
|
methodName;
|
|
244
|
+
httpMethod;
|
|
164
245
|
path;
|
|
246
|
+
operation;
|
|
165
247
|
kind;
|
|
166
248
|
hidden;
|
|
249
|
+
openWorld;
|
|
167
250
|
options;
|
|
168
251
|
auth;
|
|
169
252
|
mcpTool;
|
|
@@ -174,10 +257,29 @@ class DocumentedEndpoint {
|
|
|
174
257
|
request;
|
|
175
258
|
response;
|
|
176
259
|
constructor(methodName,
|
|
260
|
+
/**
|
|
261
|
+
* `GET` or `POST`, constant-folded from `@Endpoint`'s FIRST argument. A document cannot be
|
|
262
|
+
* written without it — the verb is the key an operation hangs under in `paths`.
|
|
263
|
+
*/
|
|
264
|
+
httpMethod,
|
|
177
265
|
/** The path, constant-folded. A const that cannot be folded is a HARD FAILURE, never a guess. */
|
|
178
266
|
path,
|
|
267
|
+
/**
|
|
268
|
+
* `read` | `write-idempotent` | `write`, verbatim. The SIDE-EFFECT contract, which is
|
|
269
|
+
* independent of the verb: webpieces POSTs a read. A renderer publishes it rather than
|
|
270
|
+
* inferring safety from the verb, which for this framework would be wrong.
|
|
271
|
+
*/
|
|
272
|
+
operation,
|
|
179
273
|
/** `rpc` | `cloudtasks` | `cron` | `external`, verbatim — this package invents no taxonomy. */
|
|
180
|
-
kind,
|
|
274
|
+
kind,
|
|
275
|
+
/**
|
|
276
|
+
* `{ hidden: true }` — this method is absent from the CUSTOMER document. It stays in the
|
|
277
|
+
* private one, and in the MCP one when it is a tool. WHICH documents the CONTRACT feeds at
|
|
278
|
+
* all is a different, class-level decision; see {@link ApiDocModel.apiTypes}.
|
|
279
|
+
*/
|
|
280
|
+
hidden,
|
|
281
|
+
/** `{ openWorld: true }` — this operation may touch systems outside this service. */
|
|
282
|
+
openWorld, options, auth, mcpTool,
|
|
181
283
|
/** `@WpMcpAuthJwt(...)`'s argument text, when present. */
|
|
182
284
|
mcpAuthText,
|
|
183
285
|
/** `@MaskLog({...})` — field name -> mask mode. */
|
|
@@ -185,9 +287,12 @@ class DocumentedEndpoint {
|
|
|
185
287
|
/** The `@mcp` override. See {@link DocumentedField.mcpDescription}. */
|
|
186
288
|
mcpDescription, request, response) {
|
|
187
289
|
this.methodName = methodName;
|
|
290
|
+
this.httpMethod = httpMethod;
|
|
188
291
|
this.path = path;
|
|
292
|
+
this.operation = operation;
|
|
189
293
|
this.kind = kind;
|
|
190
294
|
this.hidden = hidden;
|
|
295
|
+
this.openWorld = openWorld;
|
|
191
296
|
this.options = options;
|
|
192
297
|
this.auth = auth;
|
|
193
298
|
this.mcpTool = mcpTool;
|
|
@@ -203,6 +308,7 @@ exports.DocumentedEndpoint = DocumentedEndpoint;
|
|
|
203
308
|
/** ONE extraction pass over ONE contract file. Both #982's renderers read exactly this. */
|
|
204
309
|
class ApiDocModel {
|
|
205
310
|
contractName;
|
|
311
|
+
apiTypes;
|
|
206
312
|
basePath;
|
|
207
313
|
description;
|
|
208
314
|
endpoints;
|
|
@@ -211,6 +317,14 @@ class ApiDocModel {
|
|
|
211
317
|
constructor(
|
|
212
318
|
/** The contract class name, e.g. `SaveApi`. */
|
|
213
319
|
contractName,
|
|
320
|
+
/**
|
|
321
|
+
* WHICH generated documents this contract feeds — `svc-to-svc`, `external-customer`, `mcp`,
|
|
322
|
+
* verbatim from `@ApiType(...)`, defaulting to `svc-to-svc` alone when it declares nothing.
|
|
323
|
+
*
|
|
324
|
+
* A named list rather than a falsy default, because the grant has to be the TOKEN: a default
|
|
325
|
+
* that reached customers would publish a contract whose author typed nothing about it.
|
|
326
|
+
*/
|
|
327
|
+
apiTypes,
|
|
214
328
|
/** `@ApiPath(...)`, constant-folded. */
|
|
215
329
|
basePath,
|
|
216
330
|
/** The JSDoc on the contract class, links flattened. */
|
|
@@ -220,6 +334,7 @@ class ApiDocModel {
|
|
|
220
334
|
/** Everything that could not be represented — recorded, not dropped. */
|
|
221
335
|
unmapped) {
|
|
222
336
|
this.contractName = contractName;
|
|
337
|
+
this.apiTypes = apiTypes;
|
|
223
338
|
this.basePath = basePath;
|
|
224
339
|
this.description = description;
|
|
225
340
|
this.endpoints = endpoints;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApiDocModel.js","sourceRoot":"","sources":["../../../../../../packages/docs/api-doc-model/src/model/ApiDocModel.ts"],"names":[],"mappings":"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","sourcesContent":["import { TypeRef } from './TypeRef';\n\n/**\n * The model classes. Every one of them is a CLASS with an explicit constructor per `CLAUDE.md` §1 —\n * these are data-only structures, and a renderer (#982) builds nothing, it only reads.\n *\n * Nothing in this file imports anything but {@link TypeRef}: the package depends on `typescript` and\n * NOTHING else, so it can be pointed at any upstream project's contract. One app-specific import\n * here would end that, which is why `responsibilities.md` states the constraint rather than leaving\n * it to be discovered.\n */\n\n/** A type the extractor could not represent. RECORDED, never dropped — #982's guard needs a name. */\nexport class UnmappedType {\n constructor(\n /** The verbatim TypeScript type text, e.g. `Map<string, Widget>`. */\n readonly typeText: string,\n /** Pointer-style location: `path/to/File.ts:12:5`. */\n readonly location: string,\n /** Why it could not be mapped, in one sentence a renderer can print. */\n readonly reason: string,\n ) {}\n}\n\n/** The DERIVED discriminator of a union — never invented, only observed. See {@link DocumentedType}. */\nexport class UnionDiscriminator {\n constructor(\n /** The property every branch carries. */\n readonly propertyName: string,\n /** branch type name -> the single string literal that branch's property holds. */\n readonly branchValues: ReadonlyMap<string, string>,\n ) {}\n}\n\n/** One field of one DTO. */\nexport class DocumentedField {\n constructor(\n readonly name: string,\n readonly type: TypeRef,\n /**\n * OPTIONAL (`name?: string`) — the property may be ABSENT. Distinguished from\n * {@link nullable} on purpose: `{}` and `{name: null}` are different wire documents, and a\n * renderer that conflates them emits a schema that rejects one of them.\n */\n readonly optional: boolean,\n /** NULLABLE (`name: string | null`) — the property is present and may hold `null`. */\n readonly nullable: boolean,\n /** The JSDoc body, links flattened. Empty string when undocumented. */\n readonly description: string,\n /**\n * The `@mcp` block tag — an OPTIONAL agent-facing override. Undefined means \"no override\",\n * and a renderer falls back to {@link description}; the fallback is NOT applied here so a\n * renderer can tell a deliberate agent-facing sentence from a reused human one.\n */\n readonly mcpDescription: string | undefined,\n /** The `@format` tag, lifted onto the SCALAR (on an array, onto the ITEM). */\n readonly format: string | undefined,\n /** `@WpMin(n)` — numeric fields only; anything else is a build failure. */\n readonly min: number | undefined,\n /** `@WpMax(n)` — numeric fields only; anything else is a build failure. */\n readonly max: number | undefined,\n ) {}\n}\n\n/** One named type reachable from a contract: an object DTO, a string-literal enum, or a union. */\nexport class DocumentedType {\n constructor(\n readonly name: string,\n readonly description: string,\n /** Object shape. Empty for an enum or a union. */\n readonly fields: readonly DocumentedField[],\n /** Set for a string-literal union that has a name. */\n readonly enumValues: readonly string[],\n /** Set for a union of named object types. */\n readonly unionRefNames: readonly string[],\n /** Set only when EVERY branch carries the same property typed as one string literal. */\n readonly discriminator: UnionDiscriminator | undefined,\n /** An index signature (`[k: string]: X`) — the OPEN-MAP half of an object that also has fields. */\n readonly indexSignatureValue: TypeRef | undefined,\n ) {}\n}\n\n/** `@Endpoint(path, kind, options?)`'s third argument, as far as a document cares. */\nexport class DocumentedEndpointOptions {\n constructor(\n readonly formPost: boolean,\n /** `calledBy` — REQUIRED by the decorator for `external`, absent otherwise. */\n readonly calledBy: string | undefined,\n readonly callerKind: string | undefined,\n ) {}\n}\n\n/** The `@WpMcpTool(...)` declaration, when the method carries one. */\nexport class DocumentedMcpTool {\n constructor(\n readonly name: string,\n /** The tool hints an agent reads — `readOnly`, `destructive`, `idempotent`, `openWorld`. */\n readonly hints: ReadonlyMap<string, boolean>,\n ) {}\n}\n\n/** WHICH credential an endpoint demands — `@WpAuthPublic`, `@WpAuthJwt`, … — verbatim from the source. */\nexport class DocumentedAuth {\n constructor(\n /** The decorator name as written, e.g. `WpAuthJwt`. */\n readonly decorator: string,\n /** Its argument text, verbatim, when it took one. Undefined for `@WpAuthPublic()`. */\n readonly argumentText: string | undefined,\n ) {}\n}\n\n/** One `@Endpoint` method of one contract. */\nexport class DocumentedEndpoint {\n constructor(\n readonly methodName: string,\n /** The path, constant-folded. A const that cannot be folded is a HARD FAILURE, never a guess. */\n readonly path: string,\n /** `rpc` | `cloudtasks` | `cron` | `external`, verbatim — this package invents no taxonomy. */\n readonly kind: string,\n readonly hidden: boolean,\n readonly options: DocumentedEndpointOptions,\n readonly auth: DocumentedAuth | undefined,\n readonly mcpTool: DocumentedMcpTool | undefined,\n /** `@WpMcpAuthJwt(...)`'s argument text, when present. */\n readonly mcpAuthText: string | undefined,\n /** `@MaskLog({...})` — field name -> mask mode. */\n readonly maskLog: ReadonlyMap<string, string>,\n readonly description: string,\n /** The `@mcp` override. See {@link DocumentedField.mcpDescription}. */\n readonly mcpDescription: string | undefined,\n readonly request: TypeRef | undefined,\n readonly response: TypeRef | undefined,\n ) {}\n}\n\n/** ONE extraction pass over ONE contract file. Both #982's renderers read exactly this. */\nexport class ApiDocModel {\n constructor(\n /** The contract class name, e.g. `SaveApi`. */\n readonly contractName: string,\n /** `@ApiPath(...)`, constant-folded. */\n readonly basePath: string,\n /** The JSDoc on the contract class, links flattened. */\n readonly description: string,\n readonly endpoints: readonly DocumentedEndpoint[],\n /** Every named type reachable from the endpoints, by name. A `$ref` target for a renderer. */\n readonly types: ReadonlyMap<string, DocumentedType>,\n /** Everything that could not be represented — recorded, not dropped. */\n readonly unmapped: readonly UnmappedType[],\n ) {}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ApiDocModel.js","sourceRoot":"","sources":["../../../../../../packages/docs/api-doc-model/src/model/ApiDocModel.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;GAQG;AAEH,qGAAqG;AACrG,MAAa,YAAY;IAGR;IAEA;IAEA;IANb;IACI,qEAAqE;IAC5D,QAAgB;IACzB,sDAAsD;IAC7C,QAAgB;IACzB,wEAAwE;IAC/D,MAAc;QAJd,aAAQ,GAAR,QAAQ,CAAQ;QAEhB,aAAQ,GAAR,QAAQ,CAAQ;QAEhB,WAAM,GAAN,MAAM,CAAQ;IACxB,CAAC;CACP;AATD,oCASC;AAED,wGAAwG;AACxG,MAAa,kBAAkB;IAGd;IAEA;IAJb;IACI,yCAAyC;IAChC,YAAoB;IAC7B,kFAAkF;IACzE,YAAyC;QAFzC,iBAAY,GAAZ,YAAY,CAAQ;QAEpB,iBAAY,GAAZ,YAAY,CAA6B;IACnD,CAAC;CACP;AAPD,gDAOC;AAED,4BAA4B;AAC5B,MAAa,eAAe;IAEX;IACA;IAMA;IAEA;IAEA;IAMA;IAEA;IAEA;IAEA;IAWA;IAnCb,YACa,IAAY,EACZ,IAAa;IACtB;;;;OAIG;IACM,QAAiB;IAC1B,sFAAsF;IAC7E,QAAiB;IAC1B,uEAAuE;IAC9D,WAAmB;IAC5B;;;;OAIG;IACM,cAAkC;IAC3C,8EAA8E;IACrE,MAA0B;IACnC,2EAA2E;IAClE,GAAuB;IAChC,2EAA2E;IAClE,GAAuB;IAChC;;;;;;;;;OASG;IACM,SAA6B;QAlC7B,SAAI,GAAJ,IAAI,CAAQ;QACZ,SAAI,GAAJ,IAAI,CAAS;QAMb,aAAQ,GAAR,QAAQ,CAAS;QAEjB,aAAQ,GAAR,QAAQ,CAAS;QAEjB,gBAAW,GAAX,WAAW,CAAQ;QAMnB,mBAAc,GAAd,cAAc,CAAoB;QAElC,WAAM,GAAN,MAAM,CAAoB;QAE1B,QAAG,GAAH,GAAG,CAAoB;QAEvB,QAAG,GAAH,GAAG,CAAoB;QAWvB,cAAS,GAAT,SAAS,CAAoB;IACvC,CAAC;CACP;AAtCD,0CAsCC;AAED,kGAAkG;AAClG,MAAa,cAAc;IAEV;IACA;IAEA;IAEA;IAEA;IAEA;IAEA;IAZb,YACa,IAAY,EACZ,WAAmB;IAC5B,kDAAkD;IACzC,MAAkC;IAC3C,sDAAsD;IAC7C,UAA6B;IACtC,6CAA6C;IACpC,aAAgC;IACzC,wFAAwF;IAC/E,aAA6C;IACtD,mGAAmG;IAC1F,mBAAwC;QAXxC,SAAI,GAAJ,IAAI,CAAQ;QACZ,gBAAW,GAAX,WAAW,CAAQ;QAEnB,WAAM,GAAN,MAAM,CAA4B;QAElC,eAAU,GAAV,UAAU,CAAmB;QAE7B,kBAAa,GAAb,aAAa,CAAmB;QAEhC,kBAAa,GAAb,aAAa,CAAgC;QAE7C,wBAAmB,GAAnB,mBAAmB,CAAqB;IAClD,CAAC;CACP;AAfD,wCAeC;AAED,uGAAuG;AACvG,MAAa,yBAAyB;IAErB;IAEA;IACA;IAJb,YACa,QAAiB;IAC1B,+EAA+E;IACtE,QAA4B,EAC5B,UAA8B;QAH9B,aAAQ,GAAR,QAAQ,CAAS;QAEjB,aAAQ,GAAR,QAAQ,CAAoB;QAC5B,eAAU,GAAV,UAAU,CAAoB;IACxC,CAAC;CACP;AAPD,8DAOC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAa,iBAAiB;IAMb;IALb;IACI;;;OAGG;IACM,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;IACtB,CAAC;CACP;AARD,8CAQC;AAED;;;;;;;;;GASG;AACH,MAAa,0BAA0B;IAGtB;IAEA;IAEA;IANb;IACI,2DAA2D;IAClD,QAAgB;IACzB,kFAAkF;IACzE,IAAwB;IACjC,+DAA+D;IACtD,WAA+B;QAJ/B,aAAQ,GAAR,QAAQ,CAAQ;QAEhB,SAAI,GAAJ,IAAI,CAAoB;QAExB,gBAAW,GAAX,WAAW,CAAoB;IACzC,CAAC;CACP;AATD,gEASC;AAED,4FAA4F;AAC5F,MAAa,gBAAgB;IAEZ;IAKA;IANb,YACa,MAAc;IACvB;;;OAGG;IACM,WAAkD;QALlD,WAAM,GAAN,MAAM,CAAQ;QAKd,gBAAW,GAAX,WAAW,CAAuC;IAC5D,CAAC;CACP;AATD,4CASC;AAED,0GAA0G;AAC1G,MAAa,cAAc;IAGV;IAEA;IAOA;IAXb;IACI,uDAAuD;IAC9C,SAAiB;IAC1B,iFAAiF;IACxE,aAAgC;IACzC;;;;;OAKG;IACM,MAAoC;QATpC,cAAS,GAAT,SAAS,CAAQ;QAEjB,kBAAa,GAAb,aAAa,CAAmB;QAOhC,WAAM,GAAN,MAAM,CAA8B;IAC9C,CAAC;CACP;AAdD,wCAcC;AAED,8CAA8C;AAC9C,MAAa,kBAAkB;IAEd;IAKA;IAEA;IAMA;IAEA;IAMA;IAEA;IACA;IACA;IACA;IAEA;IAEA;IACA;IAEA;IACA;IACA;IApCb,YACa,UAAkB;IAC3B;;;OAGG;IACM,UAAkB;IAC3B,iGAAiG;IACxF,IAAY;IACrB;;;;OAIG;IACM,SAAiB;IAC1B,+FAA+F;IACtF,IAAY;IACrB;;;;OAIG;IACM,MAAe;IACxB,qFAAqF;IAC5E,SAAkB,EAClB,OAAkC,EAClC,IAAgC,EAChC,OAAsC;IAC/C,0DAA0D;IACjD,WAA+B;IACxC,mDAAmD;IAC1C,OAAoC,EACpC,WAAmB;IAC5B,uEAAuE;IAC9D,cAAkC,EAClC,OAA4B,EAC5B,QAA6B;QAnC7B,eAAU,GAAV,UAAU,CAAQ;QAKlB,eAAU,GAAV,UAAU,CAAQ;QAElB,SAAI,GAAJ,IAAI,CAAQ;QAMZ,cAAS,GAAT,SAAS,CAAQ;QAEjB,SAAI,GAAJ,IAAI,CAAQ;QAMZ,WAAM,GAAN,MAAM,CAAS;QAEf,cAAS,GAAT,SAAS,CAAS;QAClB,YAAO,GAAP,OAAO,CAA2B;QAClC,SAAI,GAAJ,IAAI,CAA4B;QAChC,YAAO,GAAP,OAAO,CAA+B;QAEtC,gBAAW,GAAX,WAAW,CAAoB;QAE/B,YAAO,GAAP,OAAO,CAA6B;QACpC,gBAAW,GAAX,WAAW,CAAQ;QAEnB,mBAAc,GAAd,cAAc,CAAoB;QAClC,YAAO,GAAP,OAAO,CAAqB;QAC5B,aAAQ,GAAR,QAAQ,CAAqB;IACvC,CAAC;CACP;AAvCD,gDAuCC;AAED,2FAA2F;AAC3F,MAAa,WAAW;IAGP;IAQA;IAEA;IAEA;IACA;IAEA;IAEA;IAnBb;IACI,+CAA+C;IACtC,YAAoB;IAC7B;;;;;;OAMG;IACM,QAA2B;IACpC,wCAAwC;IAC/B,QAAgB;IACzB,wDAAwD;IAC/C,WAAmB,EACnB,SAAwC;IACjD,8FAA8F;IACrF,KAA0C;IACnD,wEAAwE;IAC/D,QAAiC;QAjBjC,iBAAY,GAAZ,YAAY,CAAQ;QAQpB,aAAQ,GAAR,QAAQ,CAAmB;QAE3B,aAAQ,GAAR,QAAQ,CAAQ;QAEhB,gBAAW,GAAX,WAAW,CAAQ;QACnB,cAAS,GAAT,SAAS,CAA+B;QAExC,UAAK,GAAL,KAAK,CAAqC;QAE1C,aAAQ,GAAR,QAAQ,CAAyB;IAC3C,CAAC;CACP;AAtBD,kCAsBC","sourcesContent":["import { TypeRef } from './TypeRef';\n\n/**\n * The model classes. Every one of them is a CLASS with an explicit constructor per `CLAUDE.md` §1 —\n * these are data-only structures, and a renderer (#982) builds nothing, it only reads.\n *\n * Nothing in this file imports anything but {@link TypeRef}: the package depends on `typescript` and\n * NOTHING else, so it can be pointed at any upstream project's contract. One app-specific import\n * here would end that, which is why `responsibilities.md` states the constraint rather than leaving\n * it to be discovered.\n */\n\n/** A type the extractor could not represent. RECORDED, never dropped — #982's guard needs a name. */\nexport class UnmappedType {\n constructor(\n /** The verbatim TypeScript type text, e.g. `Map<string, Widget>`. */\n readonly typeText: string,\n /** Pointer-style location: `path/to/File.ts:12:5`. */\n readonly location: string,\n /** Why it could not be mapped, in one sentence a renderer can print. */\n readonly reason: string,\n ) {}\n}\n\n/** The DERIVED discriminator of a union — never invented, only observed. See {@link DocumentedType}. */\nexport class UnionDiscriminator {\n constructor(\n /** The property every branch carries. */\n readonly propertyName: string,\n /** branch type name -> the single string literal that branch's property holds. */\n readonly branchValues: ReadonlyMap<string, string>,\n ) {}\n}\n\n/** One field of one DTO. */\nexport class DocumentedField {\n constructor(\n readonly name: string,\n readonly type: TypeRef,\n /**\n * OPTIONAL (`name?: string`) — the property may be ABSENT. Distinguished from\n * {@link nullable} on purpose: `{}` and `{name: null}` are different wire documents, and a\n * renderer that conflates them emits a schema that rejects one of them.\n */\n readonly optional: boolean,\n /** NULLABLE (`name: string | null`) — the property is present and may hold `null`. */\n readonly nullable: boolean,\n /** The JSDoc body, links flattened. Empty string when undocumented. */\n readonly description: string,\n /**\n * The `@mcp` block tag — an OPTIONAL agent-facing override. Undefined means \"no override\",\n * and a renderer falls back to {@link description}; the fallback is NOT applied here so a\n * renderer can tell a deliberate agent-facing sentence from a reused human one.\n */\n readonly mcpDescription: string | undefined,\n /** The `@format` tag, lifted onto the SCALAR (on an array, onto the ITEM). */\n readonly format: string | undefined,\n /** `@WpMin(n)` — numeric fields only; anything else is a build failure. */\n readonly min: number | undefined,\n /** `@WpMax(n)` — numeric fields only; anything else is a build failure. */\n readonly max: number | undefined,\n /**\n * The `@mcpHeader <token>` JSDoc tag — the MCP 2026 SEP-2243 header this PRIMITIVE field is\n * mirrored into (`Mcp-Param-{token}`). Undefined for every field that is not mirrored, which\n * is nearly all of them.\n *\n * It is documentation and therefore lives in JSDoc, next to the sentence describing the\n * field, rather than in a decorator argument. The runtime spells it `WpMcpHeader` inside\n * `@WpDtoField`; the two are proved identical by the equivalence gate (#983) before #984\n * deletes the decorator spelling.\n */\n readonly mcpHeader: string | undefined,\n ) {}\n}\n\n/** One named type reachable from a contract: an object DTO, a string-literal enum, or a union. */\nexport class DocumentedType {\n constructor(\n readonly name: string,\n readonly description: string,\n /** Object shape. Empty for an enum or a union. */\n readonly fields: readonly DocumentedField[],\n /** Set for a string-literal union that has a name. */\n readonly enumValues: readonly string[],\n /** Set for a union of named object types. */\n readonly unionRefNames: readonly string[],\n /** Set only when EVERY branch carries the same property typed as one string literal. */\n readonly discriminator: UnionDiscriminator | undefined,\n /** An index signature (`[k: string]: X`) — the OPEN-MAP half of an object that also has fields. */\n readonly indexSignatureValue: TypeRef | undefined,\n ) {}\n}\n\n/** `@Endpoint(httpMethod, path, operation, kind, options?)`'s LAST argument, as a document sees it. */\nexport class DocumentedEndpointOptions {\n constructor(\n readonly formPost: boolean,\n /** `calledBy` — REQUIRED by the decorator for `external`, absent otherwise. */\n readonly calledBy: string | undefined,\n readonly callerKind: string | undefined,\n ) {}\n}\n\n/**\n * The `@WpMcpTool(...)` declaration, when the method carries one — the TWO facts the source cannot\n * otherwise state, and nothing else.\n *\n * `description` is deliberately NOT read off the decorator. The method's JSDoc is the description, for\n * the agent and for the partner alike, byte-identical: two authored copies of one paragraph is the\n * two-spellings shim, and its failure mode is concrete — the partner reads the JSDoc in the OpenAPI\n * document while the agent reads the decorator string in `tools/list`, and they drift the first time\n * somebody edits one. (The field still exists on the decorator; #984 deletes it across its 29 call\n * sites. Nothing here reads it, so nothing here depends on a field that is about to disappear.)\n *\n * The three side-effect hints are not read either: they are COMPUTED from the endpoint's `operation`\n * by `mcpHintsForOperation` in `@webpieces/core-util`, which is the one place that mapping lives.\n * `READ | WRITE_IDEMPOTENT | WRITE` already says whether repeating a call is safe, so a hand-declared\n * hint would be a second answer to a question the contract has answered.\n */\nexport class DocumentedMcpTool {\n constructor(\n /**\n * The STABLE protocol name. Deliberately independent of the method name, because renaming a\n * method must not break a saved agent workflow.\n */\n readonly name: string,\n ) {}\n}\n\n/**\n * ONE credential of an api-key regime, PARSED — `{ in: 'header', name: 'x-api-key' }` or\n * `{ in: 'bearer' }`.\n *\n * Parsed rather than left as source text because it is the one auth argument a renderer must turn\n * into a STRUCTURE: an OpenAPI `securityScheme` is `{type: apiKey, in, name}` or\n * `{type: http, scheme: bearer}`, and those are different documents. A renderer handed the string\n * `\"{ in: 'header', name: 'x-api-key' }\"` would have to parse TypeScript to emit either one, which\n * is this package's job and not a renderer's.\n */\nexport class DocumentedApiKeyCredential {\n constructor(\n /** `header` or `bearer`, verbatim from the declaration. */\n readonly location: string,\n /** The header name. Undefined for `bearer`, whose location IS `Authorization`. */\n readonly name: string | undefined,\n /** The prose a docs site renders on its authorization card. */\n readonly description: string | undefined,\n ) {}\n}\n\n/** `@WpAuthApiKey(regime, credentials)`, parsed. See {@link DocumentedApiKeyCredential}. */\nexport class DocumentedApiKey {\n constructor(\n readonly regime: string,\n /**\n * Every credential the regime requires, IN DECLARATION ORDER. They are an AND — all of them\n * are presented together — and the order is the order a published document lists them in.\n */\n readonly credentials: readonly DocumentedApiKeyCredential[],\n ) {}\n}\n\n/** WHICH credential an endpoint demands — `@WpAuthPublic`, `@WpAuthJwt`, … — verbatim from the source. */\nexport class DocumentedAuth {\n constructor(\n /** The decorator name as written, e.g. `WpAuthJwt`. */\n readonly decorator: string,\n /** Every argument's text, verbatim and in order. Empty for `@WpAuthPublic()`. */\n readonly argumentTexts: readonly string[],\n /**\n * The PARSED api-key declaration, set only for `@WpAuthApiKey`. Every other decorator's\n * argument is prose or a role list that a document quotes rather than restructures, so\n * {@link argumentTexts} is all they need — see {@link DocumentedApiKeyCredential} for why\n * this one is different.\n */\n readonly apiKey: DocumentedApiKey | undefined,\n ) {}\n}\n\n/** One `@Endpoint` method of one contract. */\nexport class DocumentedEndpoint {\n constructor(\n readonly methodName: string,\n /**\n * `GET` or `POST`, constant-folded from `@Endpoint`'s FIRST argument. A document cannot be\n * written without it — the verb is the key an operation hangs under in `paths`.\n */\n readonly httpMethod: string,\n /** The path, constant-folded. A const that cannot be folded is a HARD FAILURE, never a guess. */\n readonly path: string,\n /**\n * `read` | `write-idempotent` | `write`, verbatim. The SIDE-EFFECT contract, which is\n * independent of the verb: webpieces POSTs a read. A renderer publishes it rather than\n * inferring safety from the verb, which for this framework would be wrong.\n */\n readonly operation: string,\n /** `rpc` | `cloudtasks` | `cron` | `external`, verbatim — this package invents no taxonomy. */\n readonly kind: string,\n /**\n * `{ hidden: true }` — this method is absent from the CUSTOMER document. It stays in the\n * private one, and in the MCP one when it is a tool. WHICH documents the CONTRACT feeds at\n * all is a different, class-level decision; see {@link ApiDocModel.apiTypes}.\n */\n readonly hidden: boolean,\n /** `{ openWorld: true }` — this operation may touch systems outside this service. */\n readonly openWorld: boolean,\n readonly options: DocumentedEndpointOptions,\n readonly auth: DocumentedAuth | undefined,\n readonly mcpTool: DocumentedMcpTool | undefined,\n /** `@WpMcpAuthJwt(...)`'s argument text, when present. */\n readonly mcpAuthText: string | undefined,\n /** `@MaskLog({...})` — field name -> mask mode. */\n readonly maskLog: ReadonlyMap<string, string>,\n readonly description: string,\n /** The `@mcp` override. See {@link DocumentedField.mcpDescription}. */\n readonly mcpDescription: string | undefined,\n readonly request: TypeRef | undefined,\n readonly response: TypeRef | undefined,\n ) {}\n}\n\n/** ONE extraction pass over ONE contract file. Both #982's renderers read exactly this. */\nexport class ApiDocModel {\n constructor(\n /** The contract class name, e.g. `SaveApi`. */\n readonly contractName: string,\n /**\n * WHICH generated documents this contract feeds — `svc-to-svc`, `external-customer`, `mcp`,\n * verbatim from `@ApiType(...)`, defaulting to `svc-to-svc` alone when it declares nothing.\n *\n * A named list rather than a falsy default, because the grant has to be the TOKEN: a default\n * that reached customers would publish a contract whose author typed nothing about it.\n */\n readonly apiTypes: readonly string[],\n /** `@ApiPath(...)`, constant-folded. */\n readonly basePath: string,\n /** The JSDoc on the contract class, links flattened. */\n readonly description: string,\n readonly endpoints: readonly DocumentedEndpoint[],\n /** Every named type reachable from the endpoints, by name. A `$ref` target for a renderer. */\n readonly types: ReadonlyMap<string, DocumentedType>,\n /** Everything that could not be represented — recorded, not dropped. */\n readonly unmapped: readonly UnmappedType[],\n ) {}\n}\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE failure type the MCP renderer throws. A render either produces a COMPLETE set of tool
|
|
3
|
+
* definitions or throws this — it never emits a schema with a hole in it.
|
|
4
|
+
*
|
|
5
|
+
* An empty JSON Schema means "anything", so a field the renderer could not give a shape to would be
|
|
6
|
+
* published to agents as an unconstrained parameter. That is the same green-build-publishes-a-
|
|
7
|
+
* shapeless-field defect `SchemaRenderer`'s unmapped guard exists to stop, and here it is a THROW
|
|
8
|
+
* because the MCP projection has no document-level place to collect them into: a tool list is a flat
|
|
9
|
+
* array, and a tool with one shapeless parameter is a tool an agent will call wrongly.
|
|
10
|
+
*
|
|
11
|
+
* It carries `location` and `cure` as FIELDS, per `.claude/review/error-output.md`, and hand-numbers
|
|
12
|
+
* nothing. It is a sibling of `ApiDocExtractionError` rather than the same class because the two
|
|
13
|
+
* failures have different cures: an extraction failure is answered by editing the CONTRACT, and a
|
|
14
|
+
* render failure by editing the contract OR by accepting that MCP's schema subset cannot carry that
|
|
15
|
+
* shape at all.
|
|
16
|
+
*/
|
|
17
|
+
export declare class McpRenderError extends Error {
|
|
18
|
+
/** `Contract.method` or `Dto.field` — the declaration to open, not a file offset. */
|
|
19
|
+
readonly location: string;
|
|
20
|
+
/** What to do instead, in one sentence. No numbering — the caller's renderer owns that. */
|
|
21
|
+
readonly cure: string;
|
|
22
|
+
constructor(message: string,
|
|
23
|
+
/** `Contract.method` or `Dto.field` — the declaration to open, not a file offset. */
|
|
24
|
+
location: string,
|
|
25
|
+
/** What to do instead, in one sentence. No numbering — the caller's renderer owns that. */
|
|
26
|
+
cure: string);
|
|
27
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.McpRenderError = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* The ONE failure type the MCP renderer throws. A render either produces a COMPLETE set of tool
|
|
6
|
+
* definitions or throws this — it never emits a schema with a hole in it.
|
|
7
|
+
*
|
|
8
|
+
* An empty JSON Schema means "anything", so a field the renderer could not give a shape to would be
|
|
9
|
+
* published to agents as an unconstrained parameter. That is the same green-build-publishes-a-
|
|
10
|
+
* shapeless-field defect `SchemaRenderer`'s unmapped guard exists to stop, and here it is a THROW
|
|
11
|
+
* because the MCP projection has no document-level place to collect them into: a tool list is a flat
|
|
12
|
+
* array, and a tool with one shapeless parameter is a tool an agent will call wrongly.
|
|
13
|
+
*
|
|
14
|
+
* It carries `location` and `cure` as FIELDS, per `.claude/review/error-output.md`, and hand-numbers
|
|
15
|
+
* nothing. It is a sibling of `ApiDocExtractionError` rather than the same class because the two
|
|
16
|
+
* failures have different cures: an extraction failure is answered by editing the CONTRACT, and a
|
|
17
|
+
* render failure by editing the contract OR by accepting that MCP's schema subset cannot carry that
|
|
18
|
+
* shape at all.
|
|
19
|
+
*/
|
|
20
|
+
class McpRenderError extends Error {
|
|
21
|
+
location;
|
|
22
|
+
cure;
|
|
23
|
+
constructor(message,
|
|
24
|
+
/** `Contract.method` or `Dto.field` — the declaration to open, not a file offset. */
|
|
25
|
+
location,
|
|
26
|
+
/** What to do instead, in one sentence. No numbering — the caller's renderer owns that. */
|
|
27
|
+
cure) {
|
|
28
|
+
super(`${message} (${location})`);
|
|
29
|
+
this.location = location;
|
|
30
|
+
this.cure = cure;
|
|
31
|
+
this.name = 'McpRenderError';
|
|
32
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.McpRenderError = McpRenderError;
|
|
36
|
+
//# sourceMappingURL=McpRenderError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"McpRenderError.js","sourceRoot":"","sources":["../../../../../../packages/docs/api-doc-model/src/render/McpRenderError.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;GAeG;AACH,MAAa,cAAe,SAAQ,KAAK;IAIxB;IAEA;IALb,YACI,OAAe;IACf,qFAAqF;IAC5E,QAAgB;IACzB,2FAA2F;IAClF,IAAY;QAErB,KAAK,CAAC,GAAG,OAAO,KAAK,QAAQ,GAAG,CAAC,CAAC;QAJzB,aAAQ,GAAR,QAAQ,CAAQ;QAEhB,SAAI,GAAJ,IAAI,CAAQ;QAGrB,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC7B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACtD,CAAC;CACJ;AAZD,wCAYC","sourcesContent":["/**\n * The ONE failure type the MCP renderer throws. A render either produces a COMPLETE set of tool\n * definitions or throws this — it never emits a schema with a hole in it.\n *\n * An empty JSON Schema means \"anything\", so a field the renderer could not give a shape to would be\n * published to agents as an unconstrained parameter. That is the same green-build-publishes-a-\n * shapeless-field defect `SchemaRenderer`'s unmapped guard exists to stop, and here it is a THROW\n * because the MCP projection has no document-level place to collect them into: a tool list is a flat\n * array, and a tool with one shapeless parameter is a tool an agent will call wrongly.\n *\n * It carries `location` and `cure` as FIELDS, per `.claude/review/error-output.md`, and hand-numbers\n * nothing. It is a sibling of `ApiDocExtractionError` rather than the same class because the two\n * failures have different cures: an extraction failure is answered by editing the CONTRACT, and a\n * render failure by editing the contract OR by accepting that MCP's schema subset cannot carry that\n * shape at all.\n */\nexport class McpRenderError extends Error {\n constructor(\n message: string,\n /** `Contract.method` or `Dto.field` — the declaration to open, not a file offset. */\n readonly location: string,\n /** What to do instead, in one sentence. No numbering — the caller's renderer owns that. */\n readonly cure: string,\n ) {\n super(`${message} (${location})`);\n this.name = 'McpRenderError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n"]}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { ApiDocModel } from '../model/ApiDocModel';
|
|
2
|
+
import { McpToolDefinition } from './McpToolDefinition';
|
|
3
|
+
/**
|
|
4
|
+
* `ApiDocModel` -> the MCP tool list, in exactly the shape `DtoSchemaBuilder` produces at boot from
|
|
5
|
+
* reflect-metadata.
|
|
6
|
+
*
|
|
7
|
+
* ## Why this exists at all, and why it is READ-ONLY
|
|
8
|
+
*
|
|
9
|
+
* #984 wants the MCP runtime off reflect-metadata, which deletes every erasure-repair argument of
|
|
10
|
+
* `@WpDtoField` — `required`, `arrayItems`, `integer`, `minimum`, `maximum`, `enumValues`. That is a
|
|
11
|
+
* behaviour change on a live protocol surface, and its failure mode is silent: a tool whose input
|
|
12
|
+
* schema quietly loses a `required` entry or an `enum` starts failing agent calls at RUNTIME, not at
|
|
13
|
+
* build. This renderer plus the equivalence spec beside it turn "the compiler can obviously replace
|
|
14
|
+
* those arguments" from a plausible argument into a MEASURED one (#983).
|
|
15
|
+
*
|
|
16
|
+
* ## It deliberately reproduces `DtoSchemaBuilder`, defect-for-defect
|
|
17
|
+
*
|
|
18
|
+
* Where MCP's `ApiJsonSchema` subset could express MORE than the runtime does, this renderer emits
|
|
19
|
+
* what the RUNTIME emits, and the gate's report names the difference. Three concrete cases:
|
|
20
|
+
*
|
|
21
|
+
* - **NULLABLE is not rendered.** `ApiJsonSchema.type` holds one string, so `type: [T, "null"]` is
|
|
22
|
+
* not expressible in the type the runtime publishes. The compiler can SEE `externalId: string | null`
|
|
23
|
+
* and the runtime cannot; emitting it here would fail the gate on a difference that is a runtime
|
|
24
|
+
* capability GAP rather than an extractor bug, and hide the real mismatches under it.
|
|
25
|
+
* - **A nested DTO is INLINED**, with the FIELD's prose on it, because `buildAt` inlines and then
|
|
26
|
+
* `fieldSchema` overwrites `description`. MCP has no `$ref`.
|
|
27
|
+
* - **A bound on an ARRAY of numbers** is put on the ITEM, where OpenAPI puts it; the runtime cannot
|
|
28
|
+
* express it at all (`@WpDtoField` rejects numeric constraints on a non-`Number` field).
|
|
29
|
+
*
|
|
30
|
+
* Making the comparison agree by WEAKENING it would destroy the only thing the gate is for, so every
|
|
31
|
+
* one of those is a documented, deliberate reproduction rather than a relaxation.
|
|
32
|
+
*/
|
|
33
|
+
export declare class McpSchemaRenderer {
|
|
34
|
+
private readonly model;
|
|
35
|
+
constructor(model: ApiDocModel);
|
|
36
|
+
/** Every `@WpMcpTool` method of the contract, in declaration order. */
|
|
37
|
+
render(): readonly McpToolDefinition[];
|
|
38
|
+
private tool;
|
|
39
|
+
/**
|
|
40
|
+
* `operation` verbatim from the model, mapped back onto the REAL constant.
|
|
41
|
+
*
|
|
42
|
+
* A `switch` and not a cast, because the model carries the operation as a string and a cast would
|
|
43
|
+
* hand `mcpHintsForOperation` a value it has no case for — which, for a function whose three arms
|
|
44
|
+
* are exhaustive, means falling off the end and publishing a tool with NO hints.
|
|
45
|
+
*/
|
|
46
|
+
private static operationOf;
|
|
47
|
+
/** A tool's input/output schema: always a closed object, exactly as `DtoSchemaBuilder.build` is. */
|
|
48
|
+
private rootSchema;
|
|
49
|
+
private namedType;
|
|
50
|
+
/**
|
|
51
|
+
* One object DTO. CLOSED (`additionalProperties: false`), `required` only when non-empty — both
|
|
52
|
+
* exactly as `DtoSchemaBuilder.buildAt` writes them, because that is what is being compared.
|
|
53
|
+
*
|
|
54
|
+
* The cycle stop is `parents`, and it THROWS rather than truncating, which is again what the
|
|
55
|
+
* runtime does: an inline schema cannot express a recursive DTO, and one that silently stopped a
|
|
56
|
+
* level down would publish a shape the server does not accept.
|
|
57
|
+
*/
|
|
58
|
+
private objectSchema;
|
|
59
|
+
/**
|
|
60
|
+
* One FIELD: its type, then the prose and the constraints that hang off the field.
|
|
61
|
+
*
|
|
62
|
+
* The ORDER matters and mirrors `fieldSchema`: the type is built first and `description` is
|
|
63
|
+
* written over whatever the type produced, so a nested DTO carries the FIELD's sentence rather
|
|
64
|
+
* than the DTO's. `@WpMin` / `@WpMax` land on the numeric LEAF — on an array, on the item — for
|
|
65
|
+
* the same reason `SchemaRenderer` puts them there: a `minimum` on an array means nothing.
|
|
66
|
+
*/
|
|
67
|
+
private fieldSchema;
|
|
68
|
+
/**
|
|
69
|
+
* `@mcpHeader` mirrors a PRIMITIVE parameter into `Mcp-Param-{name}` (MCP 2026 SEP-2243). The
|
|
70
|
+
* three conditions are the runtime's, restated against the compiler's view of the field, so a
|
|
71
|
+
* declaration the server would reject at boot fails the document build instead.
|
|
72
|
+
*/
|
|
73
|
+
private static assertHeaderFits;
|
|
74
|
+
/** One resolved type, with no field-level prose or constraints on it. */
|
|
75
|
+
private typeSchema;
|
|
76
|
+
/** A named type: a string enum becomes `enum`, an object DTO is INLINED (MCP has no `$ref`). */
|
|
77
|
+
private referencedSchema;
|
|
78
|
+
private static primitive;
|
|
79
|
+
}
|