@nanobpm/urban 0.87.1 → 0.88.1

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.
@@ -1,3 +1,4 @@
1
+ import { type OpenApiDoc, type OpenApiSchema, type OperationInfo } from "../../../openapi/spec.ts";
1
2
  import type { AppApi, RuntimeContext } from "../context.ts";
2
3
  import type { HttpRequest } from "../host.ts";
3
4
  import { type Route } from "../router.ts";
@@ -64,6 +65,33 @@ export declare function readHeader(headers: Record<string, string | string[] | u
64
65
  * required is enough to have missing (or whitespace-only) calls rejected rather than silently
65
66
  * substituted with an empty string. */
66
67
  export declare function missingRequiredArgs(inputSchema: Record<string, unknown>, args: Record<string, unknown>): string[];
68
+ /** The operation's effective request-body schema for classifying a tool-call `body`: P0's resolved,
69
+ * `$ref`-free schema ({@link OperationInfo.requestBodySchemaResolved}, produced by
70
+ * `collectOperations`). As defence in depth, if that metadata is somehow still a bare `$ref` (it
71
+ * should never be after resolution), re-resolve it via {@link resolveSchema} against `doc` so the
72
+ * classification below never keys off an opaque `#/components/...` pointer. */
73
+ export declare function effectiveRequestBodySchema(op: OperationInfo, doc: OpenApiDoc | undefined): OpenApiSchema | undefined;
74
+ /** Whether the operation declares a STRUCTURED (object/array) request body — the shapes the app door
75
+ * expects as a JSON object/array rather than a bare scalar. Classified from the RESOLVED schema so a
76
+ * `$ref`-bodied op (e.g. `previewDeliveryGraph`, whose object `type` is only visible after P0's
77
+ * resolution) is recognized, not merely an inline-`type` object body. */
78
+ export declare function structuredBodyKind(schema: OpenApiSchema | undefined): "object" | "array" | undefined;
79
+ /** Normalize a tool-call `body` argument for FAITHFUL transport (ADR 0067). A client that saw an
80
+ * opaque input schema — or that coerces non-primitive args — may send `body` as a pre-encoded JSON
81
+ * *string* instead of the object/array the operation declares. Left as-is, `toHttpRequest`'s
82
+ * `JSON.stringify` would DOUBLE-encode it into a quoted string and the door would reject it with
83
+ * "expected object, got string". So when the op declares an object/array body and `body` arrives as
84
+ * a string, parse it once so it round-trips as the structured value. A genuine object/array argument
85
+ * passes through untouched (still serialized by the transport). A string that does not parse to the
86
+ * declared shape is a CLEAR tool error naming the expected shape — never a silently double-encoded
87
+ * (and 4xx-rejected) request. */
88
+ export declare function normalizeBodyArg(op: OperationInfo, args: Record<string, unknown>, doc: OpenApiDoc | undefined): {
89
+ ok: true;
90
+ args: Record<string, unknown>;
91
+ } | {
92
+ ok: false;
93
+ error: string;
94
+ };
67
95
  /**
68
96
  * Mount the runtime-served MCP surface at `/app/mcp` (ADR 0067). Returns a single `*`-method route
69
97
  * (mounted unconditionally, like `/app/agent`); the handler bridges the host request/response seam
@@ -286,7 +286,7 @@ function toHttpRequest(op, args, forwardHeaders) {
286
286
  * `collectOperations`). As defence in depth, if that metadata is somehow still a bare `$ref` (it
287
287
  * should never be after resolution), re-resolve it via {@link resolveSchema} against `doc` so the
288
288
  * classification below never keys off an opaque `#/components/...` pointer. */
289
- function effectiveRequestBodySchema(op, doc) {
289
+ export function effectiveRequestBodySchema(op, doc) {
290
290
  const schema = op.requestBodySchemaResolved ?? op.requestBodySchema;
291
291
  if (schema?.$ref)
292
292
  return doc ? resolveSchema(doc, schema) : undefined;
@@ -296,7 +296,7 @@ function effectiveRequestBodySchema(op, doc) {
296
296
  * expects as a JSON object/array rather than a bare scalar. Classified from the RESOLVED schema so a
297
297
  * `$ref`-bodied op (e.g. `previewDeliveryGraph`, whose object `type` is only visible after P0's
298
298
  * resolution) is recognized, not merely an inline-`type` object body. */
299
- function structuredBodyKind(schema) {
299
+ export function structuredBodyKind(schema) {
300
300
  if (!schema)
301
301
  return undefined;
302
302
  if (isObjectSchema(schema))
@@ -314,7 +314,7 @@ function structuredBodyKind(schema) {
314
314
  * passes through untouched (still serialized by the transport). A string that does not parse to the
315
315
  * declared shape is a CLEAR tool error naming the expected shape — never a silently double-encoded
316
316
  * (and 4xx-rejected) request. */
317
- function normalizeBodyArg(op, args, doc) {
317
+ export function normalizeBodyArg(op, args, doc) {
318
318
  const body = args.body;
319
319
  const kind = structuredBodyKind(effectiveRequestBodySchema(op, doc));
320
320
  if (body === undefined || kind === undefined || typeof body !== "string") {