@crvouga/mockingbird-service-plane 1.0.0 → 1.0.2

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/CHANGELOG.md CHANGED
@@ -1,15 +1,24 @@
1
1
  # Changelog — @crvouga/mockingbird-service-plane
2
2
 
3
+ ## 1.0.2 (2026-09-26)
4
+
5
+ ### Fixes and improvements
6
+
7
+ - treat enum [""] branches as unset markers in form coercion ([7177835](https://github.com/crvouga/mockingbird/commit/7177835cc510e14245d6648ad2821daa694bb80c))
8
+
9
+ ## 1.0.1 (2026-09-25)
10
+
11
+ ### Fixes and improvements
12
+
13
+ - take the rejected-request byte count from content-length, never by reading the body ([a0e5fb2](https://github.com/crvouga/mockingbird/commit/a0e5fb2fc80ab725c3552b612f3f091fd6c857fb))
14
+ - reject a present body by media type, and log what a rejected request sent ([12e351a](https://github.com/crvouga/mockingbird/commit/12e351aba53cfb7b41e31a7809419455fc2902eb))
15
+
3
16
  ## 1.0.0 (2026-09-24)
4
17
 
5
18
  ### ⚠️ Breaking changes
6
19
 
7
20
  - vendor branding for every service; purge internal mocks and consumer names ([f689534](https://github.com/crvouga/mockingbird/commit/f6895343543550dafcb7d76b426cae7635e03226))
8
21
 
9
- ### Dependencies
10
-
11
- - `@crvouga/mockingbird-service-sqlite`
12
-
13
22
  ## 0.2.0 (2026-09-23)
14
23
 
15
24
  ### Features
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createRuntime
3
- } from "./chunk-AGRUDYY6.js";
3
+ } from "./chunk-K3US4BNI.js";
4
4
 
5
5
  // ../../adapters/node/dist/cli.js
6
6
  import { readFile } from "node:fs/promises";
@@ -208,7 +208,9 @@ var formatLog = (format) => {
208
208
  const ns = entry.namespace === "default" ? "" : ` [${entry.namespace}]`;
209
209
  const fault = entry.faultId ? ` fault=${entry.faultId}` : "";
210
210
  const adopted = entry.adopted ? " adopted" : "";
211
- console.log(`${entry.service} ${entry.method} ${entry.path} ${entry.status} ${op} ${entry.durationMs}ms${ns}${fault}${adopted}`);
211
+ const received = entry.request ? ` received=${entry.request.bodyBytes === null ? "?" : `${entry.request.bodyBytes}B`} ct=${entry.request.contentType ?? "-"}${entry.request.transferEncoding ? ` te=${entry.request.transferEncoding}` : ""}` : "";
212
+ const issues = entry.issues?.length ? ` issues=${entry.issues.slice(0, 3).map((issue) => `${issue.path || "$"}: ${issue.message}`).join("; ")}${entry.issues.length > 3 ? ` (+${entry.issues.length - 3})` : ""}` : "";
213
+ console.log(`${entry.service} ${entry.method} ${entry.path} ${entry.status} ${op} ${entry.durationMs}ms${ns}${fault}${adopted}${received}${issues}`);
212
214
  };
213
215
  };
214
216
  var asString = (value) => typeof value === "string" ? value : void 0;
@@ -352,4 +354,4 @@ export {
352
354
  createServer2 as createServer,
353
355
  serveTarget
354
356
  };
355
- //# sourceMappingURL=chunk-W2OH7G7O.js.map
357
+ //# sourceMappingURL=chunk-JLZLGS2O.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../adapters/node/src/cli.ts", "../../../adapters/node/src/serve.ts", "../../../adapters/node/src/listen.ts", "../src/server.ts"],
4
+ "sourcesContent": ["import { readFile } from \"node:fs/promises\"\nimport { type ParseArgsConfig, parseArgs } from \"node:util\"\nimport type { RequestLog, ServiceInstance, ServiceRuntime } from \"@crvouga/mockingbird-service\"\nimport { type Listening, listen } from \"./listen.js\"\n\nexport type CliOption = {\n type: \"string\" | \"boolean\"\n description: string\n /** Shown in help; the value placeholder, e.g. `<port>`. */\n value?: string\n default?: string | boolean\n}\n\nexport type CliValues = Record<string, string | boolean | undefined>\n\nexport type CliCommand = {\n summary: string\n usage?: string\n options?: Record<string, CliOption>\n /** Resolves to an exit code; a server command resolves only when it stops. */\n run(values: CliValues, positionals: string[]): Promise<number>\n}\n\nexport type CliSpec = {\n bin: string\n description: string\n commands: Record<string, CliCommand>\n}\n\nconst optionHelp = (options: Record<string, CliOption>): string[] =>\n Object.entries(options).map(([name, option]) => {\n const flag = `--${name}${option.type === \"string\" ? ` ${option.value ?? \"<value>\"}` : \"\"}`\n const fallback = option.default !== undefined ? ` (default: ${String(option.default)})` : \"\"\n return ` ${flag.padEnd(30)} ${option.description}${fallback}`\n })\n\nconst help = (spec: CliSpec): string =>\n [\n `${spec.bin} \u2014 ${spec.description}`,\n \"\",\n \"Usage:\",\n ` ${spec.bin} <command> [options]`,\n \"\",\n \"Commands:\",\n ...Object.entries(spec.commands).map(([name, c]) => ` ${name.padEnd(30)} ${c.summary}`),\n \"\",\n `Run \\`${spec.bin} <command> --help\\` for a command's options.`,\n ].join(\"\\n\")\n\nconst commandHelp = (spec: CliSpec, name: string, command: CliCommand): string =>\n [\n `${spec.bin} ${name} \u2014 ${command.summary}`,\n \"\",\n \"Usage:\",\n ` ${command.usage ?? `${spec.bin} ${name} [options]`}`,\n ...(command.options ? [\"\", \"Options:\", ...optionHelp(command.options)] : []),\n ].join(\"\\n\")\n\n/** Parse `argv` against `spec` and run the chosen command. Resolves to an exit code. */\nexport const runCli = async (spec: CliSpec, argv: string[]): Promise<number> => {\n // Two-word commands (`corpus pull`) win over one-word ones.\n const pair = argv.length >= 2 ? `${argv[0]} ${argv[1]}` : undefined\n const words = pair !== undefined && spec.commands[pair] ? 2 : 1\n const name = words === 2 ? pair : argv[0]\n const rest = argv.slice(words)\n if (name === undefined || name === \"--help\" || name === \"-h\" || name === \"help\") {\n console.log(help(spec))\n return 0\n }\n const command = spec.commands[name]\n if (!command) {\n console.error(`${spec.bin}: unknown command ${JSON.stringify(name)}\\n\\n${help(spec)}`)\n return 2\n }\n if (rest.includes(\"--help\") || rest.includes(\"-h\")) {\n console.log(commandHelp(spec, name, command))\n return 0\n }\n let parsed: { values: CliValues; positionals: string[] }\n try {\n parsed = parseArgs({\n args: rest,\n allowPositionals: true,\n strict: true,\n options: Object.fromEntries(\n Object.entries(command.options ?? {}).map(([key, option]) => [\n key,\n {\n type: option.type,\n ...(option.default !== undefined ? { default: option.default } : {}),\n },\n ]),\n ) as ParseArgsConfig[\"options\"],\n }) as { values: CliValues; positionals: string[] }\n } catch (error) {\n console.error(\n `${spec.bin} ${name}: ${error instanceof Error ? error.message : String(error)}\\n\\n${commandHelp(spec, name, command)}`,\n )\n return 2\n }\n return command.run(parsed.values, parsed.positionals)\n}\n\n// \u2500\u2500 serve \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport type LogFormat = \"pretty\" | \"json\" | \"off\"\n\nexport type CommonServeOptions = {\n adminKey: string | undefined\n seed: string | undefined\n onLog: ((entry: RequestLog) => void) | undefined\n}\n\n/**\n * What a service contributes to `serve`: how to build its runtime from CLI flags,\n * and what to say at startup. Every service's `./server` entry exports one as\n * `serveTarget`, which is also how `serve --config` finds services by name.\n */\nexport type ServeTarget = {\n name: string\n defaultPort: number\n /** Serve flags beyond the common ones. */\n options?: Record<string, CliOption>\n create(\n values: CliValues,\n common: CommonServeOptions,\n ): Promise<ServiceRuntime<ServiceInstance>> | ServiceRuntime<ServiceInstance>\n /** Startup lines after the listen address, e.g. the loaded corpus version. */\n banner?(runtime: ServiceRuntime<ServiceInstance>): string[]\n}\n\nconst COMMON_SERVE_OPTIONS: Record<string, CliOption> = {\n port: { type: \"string\", value: \"<port>\", description: \"Port to listen on\" },\n host: { type: \"string\", value: \"<host>\", description: \"Interface to bind\", default: \"127.0.0.1\" },\n \"admin-key\": {\n type: \"string\",\n value: \"<key>\",\n description: \"Require x-mockingbird-admin-key on /__admin/* (env MOCKINGBIRD_ADMIN_KEY)\",\n },\n seed: { type: \"string\", value: \"<seed>\", description: \"Seed for every random choice\" },\n log: {\n type: \"string\",\n value: \"<pretty|json|off>\",\n description: \"Request log format\",\n default: \"pretty\",\n },\n \"log-requests\": {\n type: \"boolean\",\n description:\n \"One JSON line per request: namespace, operationId, status, ids touched (never bodies). Same as --log json\",\n },\n config: {\n type: \"string\",\n value: \"<file>\",\n description: \"Serve every service in a mockingbird.json config instead\",\n },\n}\n\nconst formatLog = (format: LogFormat) => {\n if (format === \"off\") return undefined\n if (format === \"json\") return (entry: RequestLog) => console.log(JSON.stringify(entry))\n return (entry: RequestLog) => {\n const op = entry.operationId ?? (entry.unmatched ? \"UNMATCHED\" : \"-\")\n const ns = entry.namespace === \"default\" ? \"\" : ` [${entry.namespace}]`\n const fault = entry.faultId ? ` fault=${entry.faultId}` : \"\"\n const adopted = entry.adopted ? \" adopted\" : \"\"\n // A rejection says what arrived (never the body) and why the service refused it.\n const received = entry.request\n ? ` received=${entry.request.bodyBytes === null ? \"?\" : `${entry.request.bodyBytes}B`} ct=${entry.request.contentType ?? \"-\"}${\n entry.request.transferEncoding ? ` te=${entry.request.transferEncoding}` : \"\"\n }`\n : \"\"\n const issues = entry.issues?.length\n ? ` issues=${entry.issues\n .slice(0, 3)\n .map((issue) => `${issue.path || \"$\"}: ${issue.message}`)\n .join(\"; \")}${entry.issues.length > 3 ? ` (+${entry.issues.length - 3})` : \"\"}`\n : \"\"\n console.log(\n `${entry.service} ${entry.method} ${entry.path} ${entry.status} ${op} ${entry.durationMs}ms${ns}${fault}${adopted}${received}${issues}`,\n )\n }\n}\n\nconst asString = (value: string | boolean | undefined): string | undefined =>\n typeof value === \"string\" ? value : undefined\n\n/** A service entry in `mockingbird.json`. */\nexport type ConfigService = {\n port?: number\n host?: string\n adminKey?: string\n seed?: string\n /** Service-specific serve flags, by long name: `{ \"webhook-url\": \"\u2026\" }`. */\n options?: Record<string, string | boolean>\n}\n\nexport type MockingbirdConfig = {\n /** Keyed by service name: `junction` loads `@crvouga/mockingbird-service-junction`. */\n services: Record<string, ConfigService>\n log?: LogFormat\n}\n\nconst loadTarget = async (name: string, own: ServeTarget): Promise<ServeTarget> => {\n if (name === own.name) return own\n const specifier = `@crvouga/mockingbird-service-${name}/server`\n try {\n const mod = (await import(specifier)) as { serveTarget?: ServeTarget }\n if (!mod.serveTarget) throw new Error(`${specifier} exports no serveTarget`)\n return mod.serveTarget\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error)\n throw new Error(\n `cannot load service \"${name}\": ${reason}. Install @crvouga/mockingbird-service-${name}.`,\n )\n }\n}\n\nconst start = async (\n target: ServeTarget,\n values: CliValues,\n config: { port: number; host: string; adminKey?: string; seed?: string; log: LogFormat },\n): Promise<Listening> => {\n const runtime = await target.create(values, {\n adminKey: config.adminKey,\n seed: config.seed,\n onLog: formatLog(config.log),\n })\n const listening = await listen(runtime, { port: config.port, host: config.host })\n console.log(`${target.name} mock listening on ${listening.url}`)\n console.log(`${target.name} health: GET ${listening.url}/health`)\n console.log(\n `${target.name} admin: ${listening.url}/__admin (${config.adminKey ? \"x-mockingbird-admin-key required\" : \"open \u2014 pass --admin-key to lock\"})`,\n )\n for (const line of target.banner?.(runtime) ?? []) console.log(`${target.name} ${line}`)\n return listening\n}\n\nconst untilSignal = async (servers: Listening[]): Promise<number> =>\n new Promise((resolve) => {\n const stop = async () => {\n await Promise.allSettled(servers.map((s) => s.close()))\n resolve(0)\n }\n process.once(\"SIGINT\", stop)\n process.once(\"SIGTERM\", stop)\n })\n\n/** The standard `serve` command for a service, including multi-service `--config`. */\nexport const serveCommand = (target: ServeTarget): CliCommand => ({\n summary: `Serve the ${target.name} mock over HTTP`,\n options: { ...COMMON_SERVE_OPTIONS, ...target.options },\n async run(values) {\n const log = (\n values[\"log-requests\"] === true ? \"json\" : (asString(values.log) ?? \"pretty\")\n ) as LogFormat\n if (![\"pretty\", \"json\", \"off\"].includes(log)) {\n console.error(`--log must be pretty, json or off (got ${log})`)\n return 2\n }\n const configPath = asString(values.config)\n if (configPath !== undefined) {\n const config = JSON.parse(await readFile(configPath, \"utf8\")) as MockingbirdConfig\n const servers: Listening[] = []\n try {\n for (const [name, entry] of Object.entries(config.services ?? {})) {\n const each = await loadTarget(name, target)\n servers.push(\n await start(each, entry.options ?? {}, {\n port: entry.port ?? each.defaultPort,\n host: entry.host ?? \"127.0.0.1\",\n ...(entry.adminKey !== undefined ? { adminKey: entry.adminKey } : {}),\n ...(entry.seed !== undefined ? { seed: entry.seed } : {}),\n log: config.log ?? log,\n }),\n )\n }\n } catch (error) {\n await Promise.allSettled(servers.map((s) => s.close()))\n console.error(error instanceof Error ? error.message : String(error))\n return 1\n }\n return untilSignal(servers)\n }\n const port = asString(values.port)\n const adminKey = asString(values[\"admin-key\"]) ?? process.env.MOCKINGBIRD_ADMIN_KEY\n const seed = asString(values.seed)\n let listening: Listening\n try {\n listening = await start(target, values, {\n port: port === undefined ? target.defaultPort : Number.parseInt(port, 10),\n host: asString(values.host) ?? \"127.0.0.1\",\n ...(adminKey !== undefined ? { adminKey } : {}),\n ...(seed !== undefined ? { seed } : {}),\n log,\n })\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error))\n return 1\n }\n return untilSignal([listening])\n },\n})\n", "import { createServer } from \"node:http\"\nimport type { FetchAPI } from \"@crvouga/mockingbird-core\"\n\n/** Options for {@link serve}. */\nexport type NodeServeOptions = {\n port?: number\n host?: string\n}\n\n/**\n * Serve any Mockingbird {@link FetchAPI} over `node:http`.\n * Port defaults to `0`, so the OS assigns an ephemeral port (read from `server.address()`).\n */\nexport const serve = async (api: FetchAPI, options: NodeServeOptions = {}) => {\n const server = createServer(async (req, res) => {\n const chunks: Buffer[] = []\n for await (const chunk of req) {\n chunks.push(Buffer.from(chunk))\n }\n const body = Buffer.concat(chunks)\n const address = server.address()\n const port = typeof address === \"object\" && address !== null ? address.port : undefined\n const base = `http://${req.headers.host ?? `localhost:${port ?? 80}`}`\n const raw = req.url ?? \"/\"\n const url = new URL(raw.replace(/^\\/+/, \"/\"), base)\n const method = req.method ?? \"GET\"\n const init: RequestInit = { method, headers: req.headers as Record<string, string> }\n if (method !== \"GET\" && method !== \"HEAD\" && body.length > 0) {\n init.body = body\n }\n const aborted = new AbortController()\n res.once(\"close\", () => {\n if (!res.writableFinished) aborted.abort()\n })\n init.signal = aborted.signal\n const request = new Request(url, init)\n let response: Response\n try {\n response = await api.fetch(request)\n } catch (error) {\n // A `drop` fault: destroy the socket so the client sees the connection die.\n if ((error as { code?: string }).code === \"MOCKINGBIRD_DROP\") {\n req.socket.destroy()\n return\n }\n res.writeHead(500, { \"content-type\": \"application/json\" })\n res.end(\n JSON.stringify({\n error: {\n type: \"mockingbird_internal\",\n message: error instanceof Error ? error.message : String(error),\n },\n }),\n )\n return\n }\n // Headers#entries() joins repeated headers; Set-Cookie must stay one header per cookie.\n const headers: Record<string, string | string[]> = Object.fromEntries(response.headers)\n const cookies = response.headers.getSetCookie()\n if (cookies.length > 0) headers[\"set-cookie\"] = cookies\n if (!response.body) {\n res.writeHead(response.status, headers)\n res.end()\n return\n }\n // Stream the body chunk by chunk: event streams and long-polls must not be buffered.\n res.writeHead(response.status, headers)\n res.flushHeaders()\n const reader = response.body.getReader()\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n if (!res.write(value)) await new Promise<void>((resolve) => res.once(\"drain\", resolve))\n }\n res.end()\n } catch {\n res.destroy()\n } finally {\n reader.releaseLock()\n }\n })\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject)\n server.listen(options.port ?? 0, options.host, resolve)\n })\n return server\n}\n", "import type { Server } from \"node:http\"\nimport type { FetchAPI } from \"@crvouga/mockingbird-core\"\nimport { serve } from \"./serve.js\"\n\nexport type ListenOptions = {\n /** Default `0`: the OS picks a free port. */\n port?: number\n /** Default `127.0.0.1`: a mock should not be reachable off the machine by accident. */\n host?: string\n}\n\n/** A running server, with the address it actually bound. */\nexport type Listening = {\n url: string\n port: number\n host: string\n server: Server\n close(): Promise<void>\n}\n\nexport const listen = async (api: FetchAPI, options: ListenOptions = {}): Promise<Listening> => {\n const host = options.host ?? \"127.0.0.1\"\n const server = await serve(api, { port: options.port ?? 0, host })\n const address = server.address()\n const port = typeof address === \"object\" && address !== null ? address.port : (options.port ?? 0)\n const shown = host.includes(\":\") ? `[${host}]` : host\n return {\n url: `http://${shown}:${port}`,\n port,\n host,\n server,\n close: () =>\n new Promise<void>((resolve, reject) => {\n // Stop accepting first, then drop keep-alive sockets so close() can finish.\n server.close((error) => {\n if (error && (error as { code?: string }).code !== \"ERR_SERVER_NOT_RUNNING\") reject(error)\n else resolve()\n })\n server.closeAllConnections?.()\n }),\n }\n}\n", "/// <reference types=\"node\" />\nimport { type Listening, listen, type ServeTarget } from \"@crvouga/mockingbird-adapter-node\"\nimport { createRuntime, type PlaneRuntime, type PlaneRuntimeOptions } from \"./runtime.js\"\n\n/** Port `mockingbird-plane serve` listens on when none is given. */\nexport const DEFAULT_PORT = 8821\n\nexport type PlaneServerOptions = PlaneRuntimeOptions & {\n /** Default `0`: the OS picks a free port. */\n port?: number\n /** Default `127.0.0.1`. */\n host?: string\n}\n\nexport type PlaneServer = Listening & { runtime: PlaneRuntime }\n\n/** Serve the Plane mock over `node:http`. */\nexport const createServer = async (options: PlaneServerOptions = {}): Promise<PlaneServer> => {\n const { port, host, ...rest } = options\n const runtime = createRuntime(rest)\n const listening = await listen(runtime, {\n port: port ?? 0,\n ...(host !== undefined ? { host } : {}),\n })\n return { ...listening, runtime }\n}\n\nconst text = (value: string | boolean | undefined) =>\n typeof value === \"string\" ? value : undefined\n\n/** How `serve` (and `serve --config`) builds the Plane mock from flags. */\nexport const serveTarget: ServeTarget = {\n name: \"plane\",\n defaultPort: DEFAULT_PORT,\n options: {\n \"api-key\": {\n type: \"string\",\n value: \"<key>\",\n description: \"Accept only this X-API-Key (the app's PLANE_ACCESS_TOKEN); default: any key\",\n },\n \"rate-limit\": {\n type: \"string\",\n value: \"<per-minute>\",\n description: \"Answer 429 past this many requests per minute per key (Plane allows 60)\",\n },\n },\n create: (values, common) => {\n const key = text(values[\"api-key\"])\n const limit = text(values[\"rate-limit\"])\n return createRuntime({\n settings: {\n ...(key ? { apiKeys: [key] } : {}),\n ...(limit ? { rateLimitPerMinute: Number(limit) } : {}),\n },\n ...(common.adminKey !== undefined ? { adminKey: common.adminKey } : {}),\n ...(common.seed !== undefined ? { seed: common.seed } : {}),\n ...(common.onLog ? { onLog: common.onLog } : {}),\n })\n },\n banner: () => [\n \"auth: X-API-Key: <token>; projects are provisioned on first use with Plane's default states\",\n \"namespaces: x-mockingbird-namespace, /ns/<name>/\u2026, or PUT /__admin/credentials {<api key>: <ns>}\",\n ],\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["createServer"]
7
+ }
@@ -1400,6 +1400,90 @@ var operationMetadata = (operation) => {
1400
1400
 
1401
1401
  // ../core/dist/service.js
1402
1402
  import { Hono } from "hono";
1403
+
1404
+ // ../core/dist/validation.js
1405
+ var requestBodyOf = (context) => {
1406
+ const requestBody = context.operation.operation.requestBody;
1407
+ return requestBody ? deref(context.document, requestBody) : void 0;
1408
+ };
1409
+ var mediaTypeMatches = (accepted, actual) => {
1410
+ const pattern = mediaTypeOf(accepted) ?? accepted.toLowerCase();
1411
+ if (pattern === actual || pattern === "*/*")
1412
+ return true;
1413
+ const [type, subtype] = pattern.split("/");
1414
+ const [actualType, actualSubtype] = actual.split("/");
1415
+ if (type !== actualType && type !== "*")
1416
+ return false;
1417
+ if (subtype === void 0 || subtype === "*")
1418
+ return true;
1419
+ if (subtype.startsWith("*+"))
1420
+ return actualSubtype?.endsWith(subtype.slice(1)) === true;
1421
+ return false;
1422
+ };
1423
+ var acceptedKeyFor = (content, mediaType) => {
1424
+ if (!content || mediaType === void 0)
1425
+ return void 0;
1426
+ const keys = Object.keys(content);
1427
+ return keys.find((key) => mediaTypeOf(key) === mediaType) ?? keys.find((key) => mediaTypeMatches(key, mediaType));
1428
+ };
1429
+ var unsupportedMediaType = (context, options = {}) => {
1430
+ if (context.body.kind === "empty" && options.includeEmpty !== true)
1431
+ return void 0;
1432
+ const content = requestBodyOf(context)?.content;
1433
+ if (!content || Object.keys(content).length === 0)
1434
+ return void 0;
1435
+ const mediaType = mediaTypeOf(context.request.headers.get("content-type"));
1436
+ if (acceptedKeyFor(content, mediaType) !== void 0)
1437
+ return void 0;
1438
+ return { mediaType: mediaType ?? null, accepted: Object.keys(content) };
1439
+ };
1440
+ var recorded = /* @__PURE__ */ new WeakMap();
1441
+ var recordedIssues = (request) => recorded.get(request);
1442
+ var bodyIssues = (context, contentType = "application/json") => {
1443
+ const issues = findBodyIssues(context, contentType);
1444
+ if (issues.length > 0)
1445
+ recorded.set(context.request, issues);
1446
+ return issues;
1447
+ };
1448
+ var findBodyIssues = (context, contentType) => {
1449
+ const resolved = requestBodyOf(context);
1450
+ if (!resolved)
1451
+ return [];
1452
+ const unsupported = unsupportedMediaType(context);
1453
+ if (unsupported) {
1454
+ return [
1455
+ {
1456
+ path: "",
1457
+ kind: "media_type",
1458
+ message: unsupported.mediaType === null ? "request body has no content-type" : `request body media type ${unsupported.mediaType} is not supported`
1459
+ }
1460
+ ];
1461
+ }
1462
+ const key = acceptedKeyFor(resolved.content, mediaTypeOf(context.request.headers.get("content-type"))) ?? contentType;
1463
+ const schema = resolved.content?.[key]?.schema;
1464
+ if (!schema)
1465
+ return [];
1466
+ if (context.body.kind === "invalid") {
1467
+ return [
1468
+ {
1469
+ path: "",
1470
+ kind: "syntax",
1471
+ message: `request body is not valid ${context.body.mediaType}`
1472
+ }
1473
+ ];
1474
+ }
1475
+ const value = context.body.kind === "json" || context.body.kind === "form" || context.body.kind === "text" ? context.body.value : void 0;
1476
+ if (value === void 0) {
1477
+ return resolved.required && context.body.kind === "empty" ? [{ path: "", kind: "required", message: "request body is required" }] : [];
1478
+ }
1479
+ return validateValue(context.document, resolveSchema(context.document, schema), value).map((issue) => ({ path: issue.path.join("."), kind: "schema", message: issue.message }));
1480
+ };
1481
+
1482
+ // ../core/dist/service.js
1483
+ var withIssues = (request, response) => {
1484
+ const issues = response.status >= 400 ? recordedIssues(request) : void 0;
1485
+ return issues && issues.length > 0 ? annotateResponse(response, { issues }) : response;
1486
+ };
1403
1487
  var defineOperations = (handlers) => handlers;
1404
1488
  var OperationRegistryError = class extends Error {
1405
1489
  problems;
@@ -1485,9 +1569,7 @@ var createService = (options) => {
1485
1569
  now
1486
1570
  };
1487
1571
  const short = await options.before?.(context);
1488
- if (short)
1489
- return short;
1490
- return handler(context);
1572
+ return withIssues(request, short ?? await handler(context));
1491
1573
  };
1492
1574
  app.on(operation.method.toUpperCase(), honoPath(operation.path), route);
1493
1575
  }
@@ -1524,7 +1606,7 @@ var restoreNamespace = (sqlite, namespace, snapshot) => {
1524
1606
  };
1525
1607
 
1526
1608
  // ../core/dist/version.js
1527
- var PACKAGE_VERSION = true ? "1.0.0" : UNRELEASED_VERSION;
1609
+ var PACKAGE_VERSION = true ? "1.0.2" : UNRELEASED_VERSION;
1528
1610
 
1529
1611
  // ../core/dist/webhooks.js
1530
1612
  var json2 = (status, body) => new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json" } });
@@ -1964,8 +2046,15 @@ var createRuntime = (options) => {
1964
2046
  const started = monotonicNow();
1965
2047
  const url = new URL(request.url);
1966
2048
  const operationId = operationIdFor(request, url.pathname);
2049
+ const contentLength = request.headers.get("content-length");
2050
+ const received = {
2051
+ contentType: request.headers.get("content-type"),
2052
+ bodyBytes: contentLength !== null && /^\d+$/.test(contentLength) ? Number(contentLength) : null,
2053
+ transferEncoding: request.headers.get("transfer-encoding")
2054
+ };
1967
2055
  const log = (status, faultId, response2) => {
1968
2056
  const noted = response2 ? responseNotes(response2) : void 0;
2057
+ const rejected = status >= 400 && faultId === void 0;
1969
2058
  const entry = {
1970
2059
  service: options.name,
1971
2060
  namespace,
@@ -1977,7 +2066,9 @@ var createRuntime = (options) => {
1977
2066
  unmatched: options.document !== void 0 && operationId === void 0,
1978
2067
  ...faultId !== void 0 ? { faultId } : {},
1979
2068
  ...noted?.ids && Object.keys(noted.ids).length > 0 ? { ids: noted.ids } : {},
1980
- ...noted?.adopted ? { adopted: true } : {}
2069
+ ...noted?.adopted ? { adopted: true } : {},
2070
+ ...rejected ? { request: { ...received } } : {},
2071
+ ...rejected && noted?.issues && noted.issues.length > 0 ? { issues: noted.issues.map((issue) => ({ ...issue })) } : {}
1981
2072
  };
1982
2073
  metrics.record(entry);
1983
2074
  journal.record({ ...entry, at: new Date(clock.now()).toISOString() });
@@ -2184,25 +2275,6 @@ var presetRoutes = (presets, runtime) => ({
2184
2275
  }
2185
2276
  });
2186
2277
 
2187
- // ../core/dist/validation.js
2188
- var bodyIssues = (context, contentType = "application/json") => {
2189
- const requestBody = context.operation.operation.requestBody;
2190
- if (!requestBody)
2191
- return [];
2192
- const resolved = deref(context.document, requestBody);
2193
- const schema = resolved.content?.[contentType]?.schema;
2194
- if (!schema)
2195
- return [];
2196
- const value = context.body.kind === "json" || context.body.kind === "form" ? context.body.value : void 0;
2197
- if (context.body.kind === "invalid") {
2198
- return [{ path: "", message: `request body is not valid ${context.body.mediaType}` }];
2199
- }
2200
- if (value === void 0) {
2201
- return resolved.required ? [{ path: "", message: "request body is required" }] : [];
2202
- }
2203
- return validateValue(context.document, resolveSchema(context.document, schema), value).map((issue) => ({ path: issue.path.join("."), message: issue.message }));
2204
- };
2205
-
2206
2278
  // src/generated/openapi.ts
2207
2279
  var document = JSON.parse(`{"openapi":"3.1.0","info":{"title":"Plane REST API (Mockingbird subset)","description":"Stateful mock subset of Plane's public REST API v1 for one project: work items (cursor-paginated list, get, create, patch), comments, links, states and labels. Hand-authored from Plane's API reference and the consumer's zod schemas (plane-response.ts).\\n","version":"1","x-mockingbird-upstream":{"note":"Shapes from https://developers.plane.so/api-reference; consumer: apps/backend/src/modules/bug-reports/adapters/native-fetch-plane.adapter.ts, plane-http-client.ts, plane-response.ts."}},"servers":[{"url":"https://api.plane.so"}],"security":[{"apiKey":[]}],"paths":{"/api/v1/workspaces/{slug}/projects/{project_id}/work-items/":{"get":{"operationId":"ListWorkItems","description":"Cursor-paginated work items (\`cursor=<per_page>:<page>:<is_prev>\`).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"A page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkItemPage"}}}},"400":{"description":"Invalid cursor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"parameters":[{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/OrderBy"}]},"post":{"operationId":"CreateWorkItem","description":"Create a work item.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkItem"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWorkItemBody"}}}}},"parameters":[{"$ref":"#/components/parameters/Slug"},{"$ref":"#/components/parameters/ProjectId"}]},"/api/v1/workspaces/{slug}/projects/{project_id}/work-items/{work_item_id}/":{"parameters":[{"$ref":"#/components/parameters/Slug"},{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/WorkItemId"}],"get":{"operationId":"GetWorkItem","description":"One work item.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"The work item","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkItem"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}}},"patch":{"operationId":"UpdateWorkItem","description":"Partial update (the consumer sends \`state\` or \`labels\`).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkItem"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWorkItemBody"}}}}}},"/api/v1/workspaces/{slug}/projects/{project_id}/work-items/{work_item_id}/comments/":{"parameters":[{"$ref":"#/components/parameters/Slug"},{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/WorkItemId"}],"get":{"operationId":"ListComments","description":"Comments on a work item.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"A page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentPage"}}}},"400":{"description":"Invalid cursor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"parameters":[{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/Cursor"}]},"post":{"operationId":"CreateComment","description":"Add a comment.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Comment"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCommentBody"}}}}}},"/api/v1/workspaces/{slug}/projects/{project_id}/work-items/{work_item_id}/links/":{"parameters":[{"$ref":"#/components/parameters/Slug"},{"$ref":"#/components/parameters/ProjectId"},{"$ref":"#/components/parameters/WorkItemId"}],"get":{"operationId":"ListLinks","description":"Links on a work item.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"A page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkPage"}}}},"400":{"description":"Invalid cursor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"parameters":[{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/Cursor"}]},"post":{"operationId":"CreateLink","description":"Attach a link (the same URL twice is a 400).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Link"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The URL is already linked (carries the existing link id)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"429":{"$ref":"#/components/responses/Throttled"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLinkBody"}}}}}},"/api/v1/workspaces/{slug}/projects/{project_id}/states/":{"get":{"operationId":"ListStates","description":"The project's workflow states.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"A page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatePage"}}}},"400":{"description":"Invalid cursor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"parameters":[{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/Cursor"}]},"parameters":[{"$ref":"#/components/parameters/Slug"},{"$ref":"#/components/parameters/ProjectId"}]},"/api/v1/workspaces/{slug}/projects/{project_id}/labels/":{"get":{"operationId":"ListLabels","description":"The project's labels.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"A page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LabelPage"}}}},"400":{"description":"Invalid cursor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/Throttled"}},"parameters":[{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/Cursor"}]},"post":{"operationId":"CreateLabel","description":"Create a label (a duplicate name is a 409 carrying the existing id).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Label"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Duplicate name","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"429":{"$ref":"#/components/responses/Throttled"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateLabelBody"}}}}},"parameters":[{"$ref":"#/components/parameters/Slug"},{"$ref":"#/components/parameters/ProjectId"}]}},"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"X-API-Key"}},"parameters":{"Slug":{"name":"slug","in":"path","required":true,"schema":{"type":"string","enum":["acme"]}},"ProjectId":{"name":"project_id","in":"path","required":true,"schema":{"type":"string","enum":["33333333-3333-4333-8333-333333333333"]}},"WorkItemId":{"name":"work_item_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"work_item","missing":"00000000-0000-4000-8000-000000000000"}}},"PerPage":{"name":"per_page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}},"Cursor":{"name":"cursor","in":"query","required":false,"schema":{"type":"string","enum":["2:0:0","2:1:0","2:2:0","100:0:0"]}},"OrderBy":{"name":"order_by","in":"query","required":false,"schema":{"type":"string","enum":["-created_at","created_at","sequence_id","-sequence_id","name","-name"]}}},"responses":{"Unauthorized":{"description":"Missing or invalid X-API-Key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"NotFound":{"description":"Unknown workspace, project or item","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"Throttled":{"description":"Rate limited (60 requests per minute per key)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}}},"schemas":{"WorkItem":{"type":"object","required":["id","sequence_id","name","description_html","state","labels","priority","created_at","updated_at","project","workspace"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"work_item","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"sequence_id":{"type":"integer"},"name":{"type":"string"},"description_html":{"type":"string"},"description_stripped":{"type":["string","null"]},"priority":{"type":"string","enum":["urgent","high","medium","low","none"]},"state":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"labels":{"type":"array","items":{"type":"string","x-mockingbird-volatile":{"kind":"id"}}},"assignees":{"type":"array","items":{"type":"string"}},"parent":{"type":["string","null"]},"start_date":{"type":["string","null"]},"target_date":{"type":["string","null"]},"completed_at":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"timestamp"}},"archived_at":{"type":["string","null"]},"is_draft":{"type":"boolean"},"sort_order":{"type":"number"},"project":{"type":"string"},"workspace":{"type":"string"},"created_by":{"type":["string","null"]},"updated_by":{"type":["string","null"]},"created_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}}}},"State":{"type":"object","required":["id","name","group","color","sequence","default"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"state","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"name":{"type":"string"},"group":{"type":"string","enum":["backlog","unstarted","started","completed","cancelled","triage"]},"color":{"type":"string"},"sequence":{"type":"number"},"default":{"type":"boolean"},"description":{"type":"string"},"project":{"type":"string"},"workspace":{"type":"string"},"created_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}}}},"Label":{"type":"object","required":["id","name","color"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"label","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"name":{"type":"string"},"color":{"type":"string"},"description":{"type":"string"},"parent":{"type":["string","null"]},"sort_order":{"type":"number"},"project":{"type":"string"},"workspace":{"type":"string"},"created_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}}}},"Comment":{"type":"object","required":["id","comment_html","issue","created_at"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-volatile":{"kind":"id"}},"comment_html":{"type":"string"},"comment_stripped":{"type":"string"},"access":{"type":"string"},"issue":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"actor":{"type":["string","null"]},"project":{"type":"string"},"workspace":{"type":"string"},"created_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}}}},"Link":{"type":"object","required":["id","url","title","issue","created_at"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-volatile":{"kind":"id"}},"url":{"type":"string"},"title":{"type":["string","null"]},"metadata":{"type":"object"},"issue":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"project":{"type":"string"},"workspace":{"type":"string"},"created_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}}}},"WorkItemPage":{"type":"object","required":["results","next_cursor","prev_cursor","next_page_results","prev_page_results","count","total_count","total_pages","total_results"],"properties":{"grouped_by":{"type":["string","null"]},"sub_grouped_by":{"type":["string","null"]},"total_count":{"type":"integer"},"next_cursor":{"type":"string"},"prev_cursor":{"type":"string"},"next_page_results":{"type":"boolean"},"prev_page_results":{"type":"boolean"},"count":{"type":"integer"},"total_pages":{"type":"integer"},"total_results":{"type":"integer"},"extra_stats":{"type":["object","null"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/WorkItem"}}}},"StatePage":{"type":"object","required":["results","next_cursor","prev_cursor","next_page_results","prev_page_results","count","total_count","total_pages","total_results"],"properties":{"grouped_by":{"type":["string","null"]},"sub_grouped_by":{"type":["string","null"]},"total_count":{"type":"integer"},"next_cursor":{"type":"string"},"prev_cursor":{"type":"string"},"next_page_results":{"type":"boolean"},"prev_page_results":{"type":"boolean"},"count":{"type":"integer"},"total_pages":{"type":"integer"},"total_results":{"type":"integer"},"extra_stats":{"type":["object","null"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/State"}}}},"LabelPage":{"type":"object","required":["results","next_cursor","prev_cursor","next_page_results","prev_page_results","count","total_count","total_pages","total_results"],"properties":{"grouped_by":{"type":["string","null"]},"sub_grouped_by":{"type":["string","null"]},"total_count":{"type":"integer"},"next_cursor":{"type":"string"},"prev_cursor":{"type":"string"},"next_page_results":{"type":"boolean"},"prev_page_results":{"type":"boolean"},"count":{"type":"integer"},"total_pages":{"type":"integer"},"total_results":{"type":"integer"},"extra_stats":{"type":["object","null"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/Label"}}}},"CommentPage":{"type":"object","required":["results","next_cursor","prev_cursor","next_page_results","prev_page_results","count","total_count","total_pages","total_results"],"properties":{"grouped_by":{"type":["string","null"]},"sub_grouped_by":{"type":["string","null"]},"total_count":{"type":"integer"},"next_cursor":{"type":"string"},"prev_cursor":{"type":"string"},"next_page_results":{"type":"boolean"},"prev_page_results":{"type":"boolean"},"count":{"type":"integer"},"total_pages":{"type":"integer"},"total_results":{"type":"integer"},"extra_stats":{"type":["object","null"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/Comment"}}}},"LinkPage":{"type":"object","required":["results","next_cursor","prev_cursor","next_page_results","prev_page_results","count","total_count","total_pages","total_results"],"properties":{"grouped_by":{"type":["string","null"]},"sub_grouped_by":{"type":["string","null"]},"total_count":{"type":"integer"},"next_cursor":{"type":"string"},"prev_cursor":{"type":"string"},"next_page_results":{"type":"boolean"},"prev_page_results":{"type":"boolean"},"count":{"type":"integer"},"total_pages":{"type":"integer"},"total_results":{"type":"integer"},"extra_stats":{"type":["object","null"]},"results":{"type":"array","items":{"$ref":"#/components/schemas/Link"}}}},"CreateWorkItemBody":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":255},"description_html":{"type":"string","maxLength":2000},"state":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"state","missing":"00000000-0000-4000-8000-000000000000"}},"labels":{"type":"array","maxItems":3,"items":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"label","missing":"00000000-0000-4000-8000-000000000000"}}},"priority":{"type":"string","enum":["urgent","high","medium","low","none"]}}},"UpdateWorkItemBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"description_html":{"type":"string","maxLength":2000},"state":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"state","missing":"00000000-0000-4000-8000-000000000000"}},"labels":{"type":"array","maxItems":3,"items":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"label","missing":"00000000-0000-4000-8000-000000000000"}}},"priority":{"type":"string","enum":["urgent","high","medium","low","none"]}}},"CreateCommentBody":{"type":"object","required":["comment_html"],"properties":{"comment_html":{"type":"string","minLength":1,"maxLength":2000},"access":{"type":"string","enum":["INTERNAL","EXTERNAL"]}}},"CreateLinkBody":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri","pattern":"^https://","maxLength":200},"title":{"type":"string","minLength":1,"maxLength":255}}},"CreateLabelBody":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":255},"color":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"description":{"type":"string","maxLength":255}}},"ErrorBody":{"type":"object","properties":{"error":{"type":"string"},"detail":{"type":"string"},"id":{"type":"string"}}},"ValidationError":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}}}}`);
2208
2280
  var operationIds = ["ListWorkItems", "CreateWorkItem", "GetWorkItem", "UpdateWorkItem", "ListComments", "CreateComment", "ListLinks", "CreateLink", "ListStates", "ListLabels", "CreateLabel"];
@@ -2808,4 +2880,4 @@ export {
2808
2880
  apiKeyCredential,
2809
2881
  PlaneAPI
2810
2882
  };
2811
- //# sourceMappingURL=chunk-AGRUDYY6.js.map
2883
+ //# sourceMappingURL=chunk-K3US4BNI.js.map