@kingsleyweb/bun-ui 0.0.0-stage → 3.0.0-rc.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/LICENSE +21 -0
- package/README.md +80 -2
- package/app/docs/App.tsx +72 -0
- package/app/docs/api/client.ts +303 -0
- package/app/docs/api/contract.ts +24 -0
- package/app/docs/api/docs.ts +38 -0
- package/app/docs/api/errors.ts +144 -0
- package/app/docs/boot.tsx +58 -0
- package/app/docs/components/Badge.tsx +65 -0
- package/app/docs/components/Button.tsx +37 -0
- package/app/docs/components/Card.tsx +41 -0
- package/app/docs/components/ConfirmDialog.tsx +173 -0
- package/app/docs/components/CopyButton.tsx +68 -0
- package/app/docs/components/Dialog.tsx +230 -0
- package/app/docs/components/EmptyState.tsx +34 -0
- package/app/docs/components/ErrorView.tsx +70 -0
- package/app/docs/components/Field.tsx +93 -0
- package/app/docs/components/JsonEditor.tsx +151 -0
- package/app/docs/components/JsonView.tsx +338 -0
- package/app/docs/components/KeyValue.tsx +63 -0
- package/app/docs/components/ProblemBanner.tsx +116 -0
- package/app/docs/components/ScreenErrorBoundary.tsx +141 -0
- package/app/docs/components/Spinner.tsx +33 -0
- package/app/docs/components/Table.tsx +33 -0
- package/app/docs/components/Tabs.tsx +226 -0
- package/app/docs/components/classNames.ts +4 -0
- package/app/docs/components/components.css +691 -0
- package/app/docs/components/copy.ts +89 -0
- package/app/docs/components/fieldContext.ts +29 -0
- package/app/docs/components/inputValues.ts +142 -0
- package/app/docs/components/inputs.tsx +387 -0
- package/app/docs/components/jsonParse.ts +338 -0
- package/app/docs/components/listKeys.ts +30 -0
- package/app/docs/config.ts +86 -0
- package/app/docs/context.ts +33 -0
- package/app/docs/embed.ts +74 -0
- package/app/docs/env.d.ts +2 -0
- package/app/docs/format.ts +9 -0
- package/app/docs/hooks/useUrlTab.ts +16 -0
- package/app/docs/main.tsx +11 -0
- package/app/docs/queryClient.ts +54 -0
- package/app/docs/router.tsx +194 -0
- package/app/docs/routing.ts +194 -0
- package/app/docs/screens/docs/document.ts +27 -0
- package/app/docs/screens/docs/http/OperationView.tsx +407 -0
- package/app/docs/screens/docs/http/Sidebar.tsx +190 -0
- package/app/docs/screens/docs/http/TryItPanel.tsx +603 -0
- package/app/docs/screens/docs/http/http.css +405 -0
- package/app/docs/screens/docs/http/index.tsx +395 -0
- package/app/docs/screens/docs/http/model.ts +604 -0
- package/app/docs/screens/docs/http/tryIt.ts +455 -0
- package/app/docs/screens/docs/permissions.ts +6 -0
- package/app/docs/screens/docs/schema/Prose.tsx +43 -0
- package/app/docs/screens/docs/schema/SchemaTree.tsx +319 -0
- package/app/docs/screens/docs/schema/index.ts +30 -0
- package/app/docs/screens/docs/schema/resolve.ts +466 -0
- package/app/docs/screens/docs/schema/schema.css +137 -0
- package/app/docs/screens/docs/schema/skeleton.ts +92 -0
- package/app/docs/screens/docs/viewer.tsx +154 -0
- package/app/docs/screens/docs/ws/InlineText.tsx +25 -0
- package/app/docs/screens/docs/ws/PayloadSchema.tsx +39 -0
- package/app/docs/screens/docs/ws/format.ts +82 -0
- package/app/docs/screens/docs/ws/index.tsx +286 -0
- package/app/docs/screens/docs/ws/items.tsx +786 -0
- package/app/docs/screens/docs/ws/model.ts +1178 -0
- package/app/docs/screens/docs/ws/panels.tsx +440 -0
- package/app/docs/screens/docs/ws/ws.css +231 -0
- package/app/docs/shortcuts.ts +94 -0
- package/app/docs/styles/base.css +847 -0
- package/app/docs/styles/tokens.css +143 -0
- package/app/docs/theme.ts +56 -0
- package/app/kit/unauthorized.ts +222 -0
- package/dist/docs/assets/main-0rchxtv5.js +18 -0
- package/dist/docs/assets/main-0rchxtv5.js.map +99 -0
- package/dist/docs/assets/main-cqgyvs86.css +1 -0
- package/dist/docs/manifest.json +26 -0
- package/dist/jobs/assets/AddFlowDialog-h6xkgx9b.js +6 -0
- package/dist/jobs/assets/AddFlowDialog-h6xkgx9b.js.map +11 -0
- package/dist/jobs/assets/AddFlowDialog-n7gtc84v.css +1 -0
- package/dist/jobs/assets/added-cbwsxv3e.js +4 -0
- package/dist/jobs/assets/added-cbwsxv3e.js.map +11 -0
- package/dist/jobs/assets/bodies-yyw5hmrp.js +6 -0
- package/dist/jobs/assets/bodies-yyw5hmrp.js.map +10 -0
- package/dist/jobs/assets/channel-tgkvqm8y.js +4 -0
- package/dist/jobs/assets/channel-tgkvqm8y.js.map +10 -0
- package/dist/jobs/assets/channelChecks-s4yz4yhw.js +4 -0
- package/dist/jobs/assets/channelChecks-s4yz4yhw.js.map +10 -0
- package/dist/jobs/assets/index-02427smp.css +1 -0
- package/dist/jobs/assets/index-09z2cjft.js +4 -0
- package/dist/jobs/assets/index-09z2cjft.js.map +16 -0
- package/dist/jobs/assets/index-18bn0gvy.css +1 -0
- package/dist/jobs/assets/index-47pxmyxn.js +4 -0
- package/dist/jobs/assets/index-47pxmyxn.js.map +10 -0
- package/dist/jobs/assets/index-4e55z986.js +4 -0
- package/dist/jobs/assets/index-4e55z986.js.map +11 -0
- package/dist/jobs/assets/index-5c933424.js +4 -0
- package/dist/jobs/assets/index-5c933424.js.map +18 -0
- package/dist/jobs/assets/index-5kbyqspm.css +1 -0
- package/dist/jobs/assets/index-5ng37hk6.css +1 -0
- package/dist/jobs/assets/index-5w8w7fvc.css +1 -0
- package/dist/jobs/assets/index-71qs5qyx.css +1 -0
- package/dist/jobs/assets/index-btpg4r8b.css +1 -0
- package/dist/jobs/assets/index-d5r5n0mm.js +4 -0
- package/dist/jobs/assets/index-d5r5n0mm.js.map +23 -0
- package/dist/jobs/assets/index-e0yy2skq.css +1 -0
- package/dist/jobs/assets/index-hs60b25v.js +10 -0
- package/dist/jobs/assets/index-hs60b25v.js.map +62 -0
- package/dist/jobs/assets/index-k2smrr70.js +4 -0
- package/dist/jobs/assets/index-k2smrr70.js.map +9 -0
- package/dist/jobs/assets/index-q24jw3w9.js +4 -0
- package/dist/jobs/assets/index-q24jw3w9.js.map +32 -0
- package/dist/jobs/assets/index-qfb80xen.css +1 -0
- package/dist/jobs/assets/index-rtynx6wj.js +4 -0
- package/dist/jobs/assets/index-rtynx6wj.js.map +10 -0
- package/dist/jobs/assets/live-6k7s6358.js +4 -0
- package/dist/jobs/assets/live-6k7s6358.js.map +10 -0
- package/dist/jobs/assets/main-0jmeh6mq.js +6 -0
- package/dist/jobs/assets/main-0jmeh6mq.js.map +12 -0
- package/dist/jobs/assets/main-3yj6bv90.js +5 -0
- package/dist/jobs/assets/main-3yj6bv90.js.map +10 -0
- package/dist/jobs/assets/main-4g69fn3x.js +5 -0
- package/dist/jobs/assets/main-4g69fn3x.js.map +10 -0
- package/dist/jobs/assets/main-4gte3eqq.js +5 -0
- package/dist/jobs/assets/main-4gte3eqq.js.map +10 -0
- package/dist/jobs/assets/main-4j1fcevh.js +5 -0
- package/dist/jobs/assets/main-4j1fcevh.js.map +10 -0
- package/dist/jobs/assets/main-54qwkz28.css +1 -0
- package/dist/jobs/assets/main-5grjvsy7.js +5 -0
- package/dist/jobs/assets/main-5grjvsy7.js.map +11 -0
- package/dist/jobs/assets/main-5zbx60gq.js +5 -0
- package/dist/jobs/assets/main-5zbx60gq.js.map +11 -0
- package/dist/jobs/assets/main-9prgjhg4.js +5 -0
- package/dist/jobs/assets/main-9prgjhg4.js.map +10 -0
- package/dist/jobs/assets/main-a250ffk7.js +17 -0
- package/dist/jobs/assets/main-a250ffk7.js.map +115 -0
- package/dist/jobs/assets/main-d6ge7w08.js +5 -0
- package/dist/jobs/assets/main-d6ge7w08.js.map +10 -0
- package/dist/jobs/assets/main-gngzht43.js +5 -0
- package/dist/jobs/assets/main-gngzht43.js.map +10 -0
- package/dist/jobs/assets/main-hg0hrg8j.js +5 -0
- package/dist/jobs/assets/main-hg0hrg8j.js.map +10 -0
- package/dist/jobs/assets/main-hm1ng3yg.js +5 -0
- package/dist/jobs/assets/main-hm1ng3yg.js.map +12 -0
- package/dist/jobs/assets/main-jkvd92z9.js +5 -0
- package/dist/jobs/assets/main-jkvd92z9.js.map +10 -0
- package/dist/jobs/assets/main-jv5xqd13.js +5 -0
- package/dist/jobs/assets/main-jv5xqd13.js.map +21 -0
- package/dist/jobs/assets/main-jxre7w93.js +5 -0
- package/dist/jobs/assets/main-jxre7w93.js.map +23 -0
- package/dist/jobs/assets/main-kwmqkjfx.js +5 -0
- package/dist/jobs/assets/main-kwmqkjfx.js.map +11 -0
- package/dist/jobs/assets/main-n9cf6bxm.js +5 -0
- package/dist/jobs/assets/main-n9cf6bxm.js.map +11 -0
- package/dist/jobs/assets/main-pegp0ygb.js +5 -0
- package/dist/jobs/assets/main-pegp0ygb.js.map +10 -0
- package/dist/jobs/assets/main-qr573853.js +5 -0
- package/dist/jobs/assets/main-qr573853.js.map +12 -0
- package/dist/jobs/assets/main-rq97rdr4.js +4 -0
- package/dist/jobs/assets/main-rq97rdr4.js.map +22 -0
- package/dist/jobs/assets/main-szjdmydc.js +5 -0
- package/dist/jobs/assets/main-szjdmydc.js.map +13 -0
- package/dist/jobs/assets/main-tnbhrm9n.js +7 -0
- package/dist/jobs/assets/main-tnbhrm9n.js.map +11 -0
- package/dist/jobs/assets/main-ts19j4n0.js +5 -0
- package/dist/jobs/assets/main-ts19j4n0.js.map +25 -0
- package/dist/jobs/assets/main-w93x1dzs.js +5 -0
- package/dist/jobs/assets/main-w93x1dzs.js.map +10 -0
- package/dist/jobs/assets/sections-0ksdxs8m.css +1 -0
- package/dist/jobs/assets/sections-0y7w4fb4.js +4 -0
- package/dist/jobs/assets/sections-0y7w4fb4.js.map +10 -0
- package/dist/jobs/assets/sse-mn0t0fh7.js +5 -0
- package/dist/jobs/assets/sse-mn0t0fh7.js.map +11 -0
- package/dist/jobs/assets/sseChecks-t7tcm7ra.js +4 -0
- package/dist/jobs/assets/sseChecks-t7tcm7ra.js.map +10 -0
- package/dist/jobs/assets/validation-ysjfy072.js +4 -0
- package/dist/jobs/assets/validation-ysjfy072.js.map +9 -0
- package/dist/jobs/manifest.json +511 -0
- package/dts/docs/assets.d.ts +144 -0
- package/dts/docs/assets.d.ts.map +1 -0
- package/dts/docs/browser/config.d.ts +61 -0
- package/dts/docs/browser/config.d.ts.map +1 -0
- package/dts/docs/browser/index.d.ts +12 -0
- package/dts/docs/browser/index.d.ts.map +1 -0
- package/dts/docs/docsUi.d.ts +42 -0
- package/dts/docs/docsUi.d.ts.map +1 -0
- package/dts/docs/hosted.d.ts +22 -0
- package/dts/docs/hosted.d.ts.map +1 -0
- package/dts/docs/index.d.ts +18 -0
- package/dts/docs/index.d.ts.map +1 -0
- package/dts/docs/shell.d.ts +57 -0
- package/dts/docs/shell.d.ts.map +1 -0
- package/dts/docs/types.d.ts +137 -0
- package/dts/docs/types.d.ts.map +1 -0
- package/dts/index.d.ts +21 -0
- package/dts/index.d.ts.map +1 -0
- package/dts/jobs/assets.d.ts +157 -0
- package/dts/jobs/assets.d.ts.map +1 -0
- package/dts/jobs/browser/config.d.ts +67 -0
- package/dts/jobs/browser/config.d.ts.map +1 -0
- package/dts/jobs/browser/index.d.ts +10 -0
- package/dts/jobs/browser/index.d.ts.map +1 -0
- package/dts/jobs/browser/unauthorized.d.ts +9 -0
- package/dts/jobs/browser/unauthorized.d.ts.map +1 -0
- package/dts/jobs/index.d.ts +24 -0
- package/dts/jobs/index.d.ts.map +1 -0
- package/dts/jobs/jobsUi.d.ts +63 -0
- package/dts/jobs/jobsUi.d.ts.map +1 -0
- package/dts/jobs/shell.d.ts +77 -0
- package/dts/jobs/shell.d.ts.map +1 -0
- package/dts/jobs/types.d.ts +146 -0
- package/dts/jobs/types.d.ts.map +1 -0
- package/dts/kit/browser/shared.d.ts +10 -0
- package/dts/kit/browser/shared.d.ts.map +1 -0
- package/dts/kit/browser/unauthorized.d.ts +74 -0
- package/dts/kit/browser/unauthorized.d.ts.map +1 -0
- package/dts/kit/unauthorized.d.ts +47 -0
- package/dts/kit/unauthorized.d.ts.map +1 -0
- package/guides/docs.md +170 -0
- package/guides/jobs.md +1120 -0
- package/lib/docs/assets.ts +427 -0
- package/lib/docs/browser/config.ts +66 -0
- package/lib/docs/browser/index.ts +24 -0
- package/lib/docs/docsUi.ts +623 -0
- package/lib/docs/hosted.ts +31 -0
- package/lib/docs/index.ts +37 -0
- package/lib/docs/shell.ts +156 -0
- package/lib/docs/types.ts +149 -0
- package/lib/index.ts +27 -0
- package/lib/jobs/assets.ts +448 -0
- package/lib/jobs/browser/config.ts +65 -0
- package/lib/jobs/browser/index.ts +9 -0
- package/lib/jobs/browser/unauthorized.ts +11 -0
- package/lib/jobs/index.ts +41 -0
- package/lib/jobs/jobsUi.ts +709 -0
- package/lib/jobs/shell.ts +205 -0
- package/lib/jobs/types.ts +162 -0
- package/lib/kit/browser/shared.ts +11 -0
- package/lib/kit/browser/unauthorized.ts +114 -0
- package/lib/kit/unauthorized.ts +222 -0
- package/package.json +198 -4
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../bun-contract/lib/model.ts", "../bun-contract/lib/protoKeys.ts", "../bun-contract/lib/issues.ts", "../bun-contract/lib/logger.ts", "../bun-contract/lib/media.ts", "../bun-contract/lib/schemas.ts", "../bun-contract/lib/transport.ts", "../bun-contract/lib/guard.ts", "../bun-contract/lib/channel.ts", "../bun-contract/lib/http.ts", "../bun-contract/lib/unknownKeys.ts", "../bun-client/lib/validation.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * The contract model: what a transport declares, what a contract holds, and\n * the static types derived from it.\n *\n * Types only, apart from the {@link CONTRACT} and {@link VARIANTS} symbols,\n * {@link variantsOf} and {@link isPromiseLike}. Nothing here imports a\n * Bun or Node API, so the module is safe in a browser bundle\n * (`@kingsleyweb/bun-contract`, re-exported as `@kingsleyweb/bun-common/contract`).\n *\n * See `docs/plans/bun-validate/README.md` §4.1 for the design.\n */\nimport type { ContractLoggerLike } from \"./logger\";\nimport type { StandardSchemaV1 } from \"./standardSchema\";\nimport type { ChannelMeta } from \"./channel\";\n\n// ---------------------------------------------------------------------------\n// Declarations\n// ---------------------------------------------------------------------------\n\n/** A value, or a promise of one: what the runner and the guards return. */\nexport type MaybePromise<T> = T | Promise<T>;\n\n/**\n * Whether `value` is a thenable (an object or function with a callable\n * `then`), not only a native `Promise`: what the Promises/A+ resolution\n * procedure adopts. A vendor's `validate` or a hook may answer with one, and\n * reading it as a settled value would take its `issues` as absent. Hand it\n * to `Promise.resolve()`, so its rejection is a rejected Promise like any\n * other.\n */\nexport function isPromiseLike(value: unknown): value is PromiseLike<unknown> {\n return (\n (typeof value === \"object\" || typeof value === \"function\") &&\n value !== null &&\n typeof (value as { then?: unknown }).then === \"function\"\n );\n}\n\n/** Any Standard Schema: the only schema type the core knows. */\nexport type Schema = StandardSchemaV1;\n\n/**\n * One schema per media type, as OpenAPI's `content` keys a body\n * (`\"application/json\"`, `\"text/plain\"`). At runtime a message's media type\n * matches a key case-insensitively with parameters stripped on both sides (a\n * key's own parameters are kept for documents), and `type/*` and `*\\/*` keys\n * match too, the most specific key winning: an exact `type/subtype`, then\n * `type/*`, then `*\\/*`. A key that is not a media type, or two keys that are\n * the same once bare and lower-cased, are refused when declared. A `null`\n * value declares the media type with no body: a message sent as it must\n * carry none.\n */\nexport interface MediaMap {\n /** The schema for a body sent as this media type; `null`: this media type, with no body. */\n readonly [mediaType: string]: Schema | null;\n}\n\n/**\n * One part's declaration: a schema, media-type variants (only for a part the\n * transport lists in {@link SideSpec.media}), or `null` for \"must be absent\"\n * (a 204's body).\n */\nexport type PartDecl = Schema | MediaMap | null;\n\n/**\n * How a part travels on the wire, recorded as data on each described row so a\n * client or document generator can apply it (plan §4.12 m3). The core never\n * applies it: what a receiver gets is each schema's output.\n *\n * - `path-string`: a path parameter, always a string.\n * - `querystring`: parsed from the query string.\n * - `header-string`: a header value, a string (or a list of them).\n * - `cookie-string`: a request cookie's value.\n * - `signed-cookie`: a request cookie whose signature was verified.\n * - `set-cookie`: a cookie set by a response.\n * - `body`: the part's value as the transport serialises it (a JSON body, a\n * frame's or a record's payload). The default.\n */\nexport type ContractEncoding =\n | \"path-string\"\n | \"querystring\"\n | \"header-string\"\n | \"cookie-string\"\n | \"signed-cookie\"\n | \"set-cookie\"\n | \"body\";\n\n/**\n * What kind of value a described row is (plan §4.12 M4): a whole value, a\n * stream of chunks, server-sent events, or an opaque body declared without\n * being read. A row is `\"value\"` unless one of bun-common's response body\n * helpers declared it: `chunks()`, `sse()` (whose events are expanded into\n * the row's `nested` rows) or `opaque()`.\n */\nexport type ContractKind = \"value\" | \"chunks\" | \"sse\" | \"opaque\";\n\n/**\n * What the wire does to a transport's values (plan Q-C5), recorded as data\n * for client types to apply: `\"json\"` when values cross as JSON (a `Date`\n * arrives as a string), `\"identity\"` when they arrive as sent (an in-process\n * broker).\n */\nexport type ContractWire = \"json\" | \"identity\";\n\n/** What a transport declares about one side of its messages. */\nexport interface SideSpec {\n /** The part names a message on this side may carry, e.g. `[\"params\", \"query\", \"body\"]`. */\n readonly parts: readonly string[];\n /**\n * The name of the field that selects a variant (`\"status\"`, `\"type\"`,\n * `\"topic\"`); absent when the side has one shape. It cannot also be a part.\n */\n readonly key?: string;\n /** The parts whose declaration may be a {@link MediaMap} (HTTP's `body`). Default: none. */\n readonly media?: readonly string[];\n /** Each part's wire {@link ContractEncoding}; a part not listed is `\"body\"`. */\n readonly encodings?: { readonly [part: string]: ContractEncoding };\n}\n\n/** What `defineTransport` takes: a name and the shape of each side it has. */\nexport interface TransportSpec {\n /** The transport's name, for logs, issues' context and generated documents. */\n readonly name: string;\n /** What the wire does to values ({@link ContractWire}). Default `\"json\"`. */\n readonly wire?: ContractWire;\n /** Messages the contract's owner receives (an HTTP request, a consumed record). */\n readonly inbound?: SideSpec;\n /** Messages the contract's owner sends (an HTTP response, a produced record, an SSE event). */\n readonly outbound?: SideSpec;\n}\n\n/** A side of a contract: what its owner receives, or what it sends. */\nexport type Side = \"inbound\" | \"outbound\";\n\n/** The failure policy, the same three words on every transport: skip the check, log and pass, or fail. */\nexport type Policy = \"off\" | \"warn\" | \"error\";\n\n/** The part names a side declares. */\ntype PartNames<S extends SideSpec> = S[\"parts\"][number];\n\n/** The part names a side lets take a {@link MediaMap}. */\ntype MediaNames<S extends SideSpec> = S[\"media\"] extends readonly string[]\n ? S[\"media\"][number]\n : never;\n\n/** The parts of one message shape, as a contract declares them. */\nexport type PartsDef<S extends SideSpec> = {\n readonly [P in PartNames<S>]?: P extends MediaNames<S>\n ? PartDecl\n : Schema | null;\n};\n\n/** A side as a contract declares it: one {@link PartsDef}, or one per key when the side is keyed. */\nexport type SideDef<S extends SideSpec> = S[\"key\"] extends string\n ? { readonly [key: string]: PartsDef<S> }\n : PartsDef<S>;\n\n/** A contract's declaration for transport `T`. */\nexport interface ContractDef<T extends TransportSpec> {\n /** The inbound side's schemas. */\n readonly inbound?: T[\"inbound\"] extends SideSpec\n ? SideDef<T[\"inbound\"]>\n : never;\n /** The outbound side's schemas. */\n readonly outbound?: T[\"outbound\"] extends SideSpec\n ? SideDef<T[\"outbound\"]>\n : never;\n}\n\n/** Documentation a generator reads alongside the schemas. */\nexport interface ContractMeta {\n /**\n * A stable name (an operation id, a channel name). For an HTTP route, an\n * `operationId` given by the route's own documentation (`.describe()`, plan\n * §4.12 m7) wins over this.\n */\n readonly name?: string;\n /** Prose for the generated document. */\n readonly description?: string;\n /**\n * A channel's meta (AD (e), approved 2026-10-26): present on a contract\n * `channelContract()` built — the path, envelope, replies, binary,\n * subprotocol, topics, SSE fallback and upgrade request schemas\n * ({@link ChannelMeta}), which a contract's rows alone do not carry. A\n * document generator reads it to tell a `websocket` contract is a channel\n * and to document its upgrade side.\n */\n readonly channel?: ChannelMeta;\n}\n\n/**\n * Where a contract is found at runtime: a non-enumerable property under\n * `Symbol.for(\"bun-validate.contract\")`, so copies of this package (and of\n * bun-common, which re-exports it) in one process agree on it.\n */\nexport const CONTRACT: unique symbol = Symbol.for(\"bun-validate.contract\");\n\n/**\n * Where a keyed side's key declared as several whole **variants** keeps\n * them (HTTP's `variants()`, plan §4.4.6): a property of the key's parts\n * object under `Symbol.for(\"bun-validate.variants\")`, holding a\n * {@link VariantsDecl}. Such a key declares no part of its own; each variant\n * declares its parts in full, and `describeContract` gives each a row with\n * its `variant`. Internal.\n *\n * @internal\n */\nexport const VARIANTS: unique symbol = Symbol.for(\"bun-validate.variants\");\n\n/**\n * One variant of a key, as a contract records it: its name, its parts in\n * full, and what documents say about when it is sent.\n *\n * @internal\n */\nexport interface VariantDecl {\n /** The variant's name, the author's (`\"admin\"`). */\n readonly name: string;\n /** The variant's parts, keyed by the transport's part names, each declared as a key's are (a schema, a media map or `null`). */\n readonly parts: object;\n /** Whether the variant applies only to some requests (it has a `when`); a `when` itself is never described. */\n readonly conditional: boolean;\n /** What documents say instead of the `when`; absent when none was given. */\n readonly description?: string;\n}\n\n/**\n * A key's variants, and the discriminant that selects one, as a contract\n * records them under {@link VARIANTS}.\n *\n * @internal\n */\nexport interface VariantsDecl {\n /** The variants, in declaration order. */\n readonly variants: readonly VariantDecl[];\n /**\n * The discriminant: the part (`\"headers\"`, `\"cookies\"`) and the name in it\n * whose value selects the variant, and each selectable variant's value (an\n * exact string, `true` for any value, `null` for absence). Absent when the\n * key has none.\n */\n readonly by?: {\n /** The part the discriminant is in. */\n readonly part: string;\n /** The header (lower-case) or cookie name. */\n readonly name: string;\n /** Variant name to the value that selects it; a variant not listed is not selected by it. */\n readonly values: Readonly<Record<string, string | true | null>>;\n };\n}\n\n/** The {@link VariantsDecl} a key's parts object carries, if it declares variants. */\nexport function variantsOf(parts: unknown): VariantsDecl | undefined {\n return typeof parts === \"object\" && parts !== null\n ? (parts as { [VARIANTS]?: VariantsDecl })[VARIANTS]\n : undefined;\n}\n\n/** Something carrying contract `C` (a handler, a router layer, a queue definition). */\nexport interface Carries<C> {\n /** The contract, reachable through `getContract`. */\n readonly [CONTRACT]: C;\n}\n\n/** A contract: the transport it is for, its schemas, and its documentation. */\nexport interface Contract<\n T extends TransportSpec = TransportSpec,\n D = ContractDef<T>,\n> extends Carries<Contract<T, D>> {\n /** The transport's declaration, so generators know part and key names. */\n readonly transport: T;\n /** The schemas, exactly as declared. */\n readonly def: D;\n /** Documentation metadata. */\n readonly meta: ContractMeta;\n}\n\n/** Any contract, for functions that walk one without its types. */\nexport type AnyContract = Contract<TransportSpec, unknown>;\n\n// ---------------------------------------------------------------------------\n// Issues and guard options\n// ---------------------------------------------------------------------------\n\n/**\n * One validation issue, flattened. Never carries the received value: the\n * message is scrubbed of it (or replaced, with `messages: \"generic\"`), and\n * only the path's keys are kept.\n *\n * @typeParam TTarget The part names; BunValidate's request side narrows it\n * to its targets.\n */\nexport interface ValidationIssue<TTarget extends string = string> {\n /** The part that failed (`\"body\"`, `\"payload\"`), or the key field (`\"status\"`, `\"type\"`) for an undeclared key. */\n target: TTarget;\n /** What is wrong, from the schema, with any quoted received value withheld. */\n message: string;\n /** Dotted path within the part, `\"\"` for the part itself (or always, with `redactPaths`). */\n path: string;\n /** The declared key (the status, message type, event, topic or method), on a keyed side. */\n key?: string;\n /** The declared media type, on a media-typed part. */\n mediaType?: string;\n /**\n * The variant of the key the issue was checked against (HTTP's\n * `variants()`, plan §4.4.6, Q-H19): a name the contract's author chose.\n * Absent on a key with no variants, and on an issue about the key as a\n * whole (`The response matches no acceptable variant (…)`).\n */\n variant?: string;\n}\n\n/** A flattened outcome: the parsed value, or every issue. */\nexport type StandardOutcome<T, TTarget extends string = string> =\n { ok: true; value: T } | { ok: false; issues: ValidationIssue<TTarget>[] };\n\n/** Where a guard found its issues, for logs and telemetry. Never carries a received value. */\nexport interface IssueContext {\n /** The transport's name. */\n transport: string;\n /** The side checked. */\n side: Side;\n /** The declared key, on a keyed side; absent when the key was not declared. */\n key?: string;\n /** The policy in force: `\"warn\"` or `\"error\"` (`\"off\"` never reports). */\n policy: Policy;\n}\n\n/** How a guard enforces a side, and how issues are worded. */\nexport interface GuardOptions {\n /**\n * What a mismatch does. Default `\"error\"`. A receiver given `\"warn\"` or\n * `\"off\"` is typed to hand on `unknown`, because it may pass a message\n * its schemas did not parse (plan Q-C1).\n */\n policy?: Policy;\n /**\n * Receives `\"warn\"`'s one log line per failing message (no values), and a\n * failure of `onIssues`. Any {@link ContractLoggerLike}: an object with\n * `warn(message, fields)` and `error(message, fields)`, or a function taking\n * each record. Default the console. Once bun-common is loaded, every logger\n * its `resolveLogger` adapts (pino, winston, …) is called its own way, and\n * the default is bun-common's console logger (`lib/logger.ts`).\n */\n logger?: ContractLoggerLike;\n /**\n * Telemetry hook (an OpenTelemetry `validation.failed` span event), called\n * once per failing message under `\"warn\"` and `\"error\"`, never on a passing\n * one. Unset, it costs nothing. If it throws, the error is logged and the\n * guard answers as if it had not.\n */\n onIssues?: (\n issues: readonly ValidationIssue[],\n context: IssueContext,\n ) => void;\n /**\n * An undeclared key on a keyed side: an issue (`\"report\"`, the default) or\n * passed through unchecked (`\"allow\"`).\n */\n undeclaredKey?: \"report\" | \"allow\";\n /**\n * Replace every issue's `path` with `\"\"`, for schemas keyed by user data\n * (an e-mail-keyed record, an unknown key's name), since a path names keys\n * the sender chose. Default `false` (plan Q-C2).\n */\n redactPaths?: boolean;\n /**\n * `\"generic\"` replaces every issue message with `Invalid value` (plus the\n * vendor's issue code when it has one), for deployments that need a\n * guarantee rather than the default scrub, which withholds only messages\n * found to quote a received value (plan Q-C3).\n */\n messages?: \"generic\";\n /**\n * Which prototype-pollution keys a receiver deletes from what arrived,\n * in place, before its schemas run. `\"nest\"` (the default) is Nest\n * 12.2.0's rule: every own `__proto__` and `prototype` key and every own\n * `constructor` key, recursively, so a legitimate `prototype` or\n * `constructor` field is deleted too. `\"minimal\"` deletes only own\n * `__proto__` keys and own `constructor` keys whose value is an object\n * with an own `prototype`. A sender never strips (it hands back its\n * owner's message as given), so it ignores this. Anything else throws a\n * `TypeError` when the guard is built.\n */\n stripProtoKeys?: \"nest\" | \"minimal\";\n}\n\n// ---------------------------------------------------------------------------\n// Static types derived from a contract\n// ---------------------------------------------------------------------------\n\n/** What a receiver gets from a schema: its output. */\nexport type ReceiveOf<S extends Schema> = StandardSchemaV1.InferOutput<S>;\n\n/** Values `WireInput` takes as they are, without mapping their members. */\ntype WireLeaf =\n | string\n | number\n | boolean\n | bigint\n | symbol\n | null\n | undefined\n | Date\n | RegExp\n | ((...args: never[]) => unknown)\n | ArrayBuffer\n | ArrayBufferView\n | ReadonlyMap<unknown, unknown>\n | ReadonlySet<unknown>\n | PromiseLike<unknown>;\n\n/** `X`, or `unknown` when `X` is `never`. */\ntype OrUnknown<X> = [X] extends [never] ? unknown : X;\n\n/** The output type at key `K`, across every member of an output union that has it. */\ntype OutputAt<O, K> = OrUnknown<\n NonNullable<O> extends infer N\n ? N extends unknown\n ? K extends keyof N\n ? N[K]\n : never\n : never\n : never\n>;\n\n/** Maps an object, array or tuple input member by member (homomorphic, so optionality and arrays survive). */\ntype WireMembers<I, O> = { [K in keyof I]: DeepWire<I[K], OutputAt<O, K>> };\n\n/** The wire view of input `I` whose output is `O`: see {@link WireInput}. */\ntype DeepWire<I, O> = unknown extends I\n ? O\n : I extends WireLeaf\n ? I\n : I extends object\n ? WireMembers<I, O>\n : I;\n\n/**\n * What a sender is held to, **field by field** (plan §4.1.4, §4.12 M1): each\n * field's input type, or its output where the input is `unknown` (a\n * coercion), with the input's optionality; deep through objects, arrays and\n * tuples. So `z.object({ page: z.coerce.number(), q: z.string().default(\"\") })`\n * sends as `{ page: number; q?: string }`.\n */\nexport type WireInput<S extends Schema> = DeepWire<\n StandardSchemaV1.InferInput<S>,\n StandardSchemaV1.InferOutput<S>\n>;\n\n/** Whose view of a message: the sender's or the receiver's. */\nexport type Role = \"send\" | \"receive\";\n\n/** One schema's type in a role's view. */\ntype Of<S extends Schema, R extends Role> = R extends \"send\"\n ? WireInput<S>\n : ReceiveOf<S>;\n\n/** Flattens an intersection for readable hovers. */\ntype Simplify<T> = { [K in keyof T]: T[K] } & {};\n\n/** A media-typed part's value: the media type it was sent as, and the value. */\nexport type MediaValue<M extends MediaMap, R extends Role> = {\n [K in keyof M & string]: M[K] extends Schema\n ? { mediaType: K; value: Of<M[K], R> }\n : { mediaType: K; value?: undefined };\n}[keyof M & string];\n\n/** One part's value in a role's view. */\nexport type PartValue<P, R extends Role> = P extends null\n ? undefined\n : P extends Schema\n ? Of<P, R>\n : P extends MediaMap\n ? MediaValue<P, R>\n : never;\n\n/** A message's parts in a role's view; a part that may be `undefined` is optional. */\nexport type PartsView<P, R extends Role> = Simplify<\n {\n [\n K in keyof P as undefined extends PartValue<P[K], R> ? never : K\n ]: PartValue<P[K], R>;\n } & {\n [\n K in keyof P as undefined extends PartValue<P[K], R> ? K : never\n ]?: PartValue<P[K], R>;\n }\n>;\n\n/** The transport's declaration of side `Sd`. */\ntype SpecOf<C, Sd extends Side> =\n C extends Contract<infer T, unknown>\n ? T[Sd] extends SideSpec\n ? T[Sd]\n : never\n : never;\n\n/** The contract's declaration of side `Sd`. */\ntype DefOf<C, Sd extends Side> =\n C extends Contract<TransportSpec, infer D>\n ? D extends { readonly [K in Sd]?: infer X }\n ? X\n : never\n : never;\n\n/** The keys a keyed side declares (`200 | 404`, `\"chat.post\"`). */\nexport type KeysOf<C, Sd extends Side> = keyof DefOf<C, Sd> & (string | number);\n\n/** One key's parts in a role's view. */\nexport type PartsOf<\n C,\n Sd extends Side,\n K extends KeysOf<C, Sd>,\n R extends Role,\n> = PartsView<DefOf<C, Sd>[K], R>;\n\n/** A whole message in a role's view: flat, with the transport's key field when the side is keyed. */\nexport type MessageOf<C, Sd extends Side, R extends Role> = SpecOf<\n C,\n Sd\n>[\"key\"] extends infer N extends string\n ? {\n [K in KeysOf<C, Sd>]: Simplify<\n { [F in N]: K } & PartsView<DefOf<C, Sd>[K], R>\n >;\n }[KeysOf<C, Sd>]\n : PartsView<DefOf<C, Sd>, R>;\n\n/** What a receiver of side `Sd` gets: each part's output. */\nexport type Received<C, Sd extends Side> = MessageOf<C, Sd, \"receive\">;\n\n/** What a sender of side `Sd` is held to: each part's {@link WireInput}. */\nexport type Sent<C, Sd extends Side> = MessageOf<C, Sd, \"send\">;\n\n// ---------------------------------------------------------------------------\n// Declaring a transport and a contract\n// ---------------------------------------------------------------------------\n\n/** Every key of `D` outside `Allowed`, mapped to `never`. */\ntype NoExtra<D, Allowed extends PropertyKey> = {\n [K in Exclude<keyof D, Allowed>]: never;\n};\n\n/** Rejects parts a side does not declare, per key when the side is keyed. */\ntype StrictSide<S, D> = S extends SideSpec\n ? S[\"key\"] extends string\n ? { [K in keyof D]: NoExtra<D[K], PartNames<S>> }\n : NoExtra<D, PartNames<S>>\n : never;\n\n/**\n * Rejects a part or side the transport does not declare. A `const` generic's\n * inference skips excess-property checks, so without this\n * `http.contract({ inbound: { bdy } })` compiled.\n */\nexport type StrictDef<T extends TransportSpec, D> = {\n [K in keyof D & Side]: StrictSide<T[K], D[K]>;\n} & NoExtra<D, Side>;\n\n/** A declared transport: its spec, and the factory for contracts typed against it. */\nexport interface Transport<T extends TransportSpec> {\n /** The declaration passed to `defineTransport`. */\n readonly spec: T;\n /**\n * Creates a contract; an undeclared side or part, or a media map on a part\n * that takes none, is a type error and a `TypeError`.\n */\n readonly contract: <const D extends ContractDef<T>>(\n def: D & StrictDef<T, D>,\n meta?: ContractMeta,\n ) => Contract<T, D>;\n}\n",
|
|
6
|
+
"/**\n * Strips the prototype-pollution keys from a received value before a schema\n * runs on it, as Nest 12.2.0's `stripProtoKeys`\n * (`@nestjs/common/utils/strip-proto-keys.util.js`) does in its\n * `ValidationPipe` and `StandardSchemaValidationPipe`.\n *\n * `JSON.parse('{\"__proto__\":{…}}')` makes an own `__proto__` key, and a\n * vendor that copies keys with plain assignment either crashes on it (yup:\n * `field.resolve is not a function`, a 500) or sets the output's prototype\n * from it. Stripping it first makes the schema see what Nest's pipes let it\n * see (the default rule, `\"nest\"`), or, under `\"minimal\"`, removes only the\n * keys that pollute.\n *\n * Browser-safe, like the rest of `lib/contract/`: no `node:util`, so a\n * typed array is told apart with `ArrayBuffer.isView` (a `DataView` aside,\n * which `util.types.isTypedArray` also rejects; Nest's walk finds nothing to\n * strip in one either way).\n */\n\nimport type { GuardOptions } from \"./model\";\n\n/**\n * Built-in types whose instances are neither stripped nor walked, Nest's\n * `BUILT_IN_TYPES`: their own state is not data a client sent.\n */\nconst BUILT_IN_TYPES: readonly unknown[] = [\n Date,\n RegExp,\n Error,\n Map,\n Set,\n WeakMap,\n WeakSet,\n];\n\n/** Whether `value` is an instance of one of {@link BUILT_IN_TYPES}. */\nfunction isBuiltIn(value: object): boolean {\n return (\n value instanceof Date ||\n value instanceof RegExp ||\n value instanceof Error ||\n value instanceof Map ||\n value instanceof Set ||\n value instanceof WeakMap ||\n value instanceof WeakSet\n );\n}\n\n/**\n * Which prototype-pollution keys are stripped (the `stripProtoKeys` option):\n * `\"nest\"`, Nest 12.2.0's rule, or `\"minimal\"`, only the keys that pollute.\n */\nexport type ProtoKeyRule = NonNullable<GuardOptions[\"stripProtoKeys\"]>;\n\n/**\n * `value` as a {@link ProtoKeyRule}, `undefined` for unset; anything else\n * throws a `TypeError` naming `owner`, as `messages` and `redactPaths`\n * refuse a value they do not take.\n */\nexport function checkProtoKeyRule(\n owner: string,\n value: unknown,\n): ProtoKeyRule | undefined {\n if (value === undefined || value === \"nest\" || value === \"minimal\") {\n return value;\n }\n throw new TypeError(\n `${owner}: stripProtoKeys must be \"nest\" or \"minimal\" (or unset)`,\n );\n}\n\n/**\n * Deletes, in place and recursively, the prototype-pollution keys of\n * `value`, by `rule`:\n *\n * - `\"nest\"` (the default): exactly Nest 12.2.0's `stripProtoKeys`, every\n * own `__proto__` and `prototype` key and every own `constructor` key\n * (unless the object's `constructor` is one of the built-in types),\n * whatever their values, so a legitimate `prototype` or `constructor`\n * field goes too.\n * - `\"minimal\"`: only every own `__proto__` key, and every own\n * `constructor` key whose value is an object with an own `prototype` key\n * (`{\"constructor\":{\"prototype\":{…}}}`); a `prototype` field, and a\n * `constructor` that is a string, a number or an object without\n * `prototype`, are kept.\n *\n * Under either, `null`, primitives, typed arrays and instances of `Date`,\n * `RegExp`, `Error`, `Map`, `Set`, `WeakMap` and `WeakSet` are left alone;\n * an array's items are walked (only those present, so a sparse array's\n * length costs nothing); any other object's keys are deleted and its\n * enumerable values (`for…in`) walked.\n *\n * Allocates nothing and deletes nothing when there is nothing to strip (each\n * key is looked up before it is deleted, so an object's shape is left as it\n * was), and is synchronous. Like Nest's, it walks without a cycle check: the\n * values it is given are parsed input, which cannot be cyclic.\n */\nexport function stripProtoKeys(\n value: unknown,\n rule: ProtoKeyRule = \"nest\",\n): void {\n if (\n value === null ||\n typeof value !== \"object\" ||\n (ArrayBuffer.isView(value) && !(value instanceof DataView))\n ) {\n return;\n }\n if (isBuiltIn(value)) return;\n const record = value as Record<string, unknown>;\n if (Array.isArray(value)) {\n // `for…in` visits the items present, as Nest's `Object.values()` does,\n // without allocating the array of them.\n for (const index in record) stripProtoKeys(record[index], rule);\n return;\n }\n if (Object.hasOwn(record, \"__proto__\")) {\n Reflect.deleteProperty(record, \"__proto__\");\n }\n if (rule === \"nest\") {\n if (Object.hasOwn(record, \"prototype\")) {\n Reflect.deleteProperty(record, \"prototype\");\n }\n // Whatever its value: a falsy one (null, 0, false, \"\") shadows the\n // prototype's all the same (Nest's comment).\n if (\n Object.hasOwn(record, \"constructor\") &&\n !BUILT_IN_TYPES.includes(record.constructor)\n ) {\n Reflect.deleteProperty(record, \"constructor\");\n }\n } else if (Object.hasOwn(record, \"constructor\")) {\n const constructor: unknown = record.constructor;\n if (\n typeof constructor === \"object\" &&\n constructor !== null &&\n Object.hasOwn(constructor, \"prototype\")\n ) {\n Reflect.deleteProperty(record, \"constructor\");\n }\n }\n for (const key in record) stripProtoKeys(record[key], rule);\n}\n",
|
|
7
|
+
"/**\n * The one runner (`validateStandard`) and the one issue shape.\n *\n * Every issue the core produces keeps the rule of plan §4.1.6: it never\n * carries the received value. Vendors quote it in their messages (valibot\n * always, arktype, yup, zod for an unknown key), so a message found to quote\n * a received value is replaced by a generic one; only the path's keys are\n * copied, never a segment's value. The scrub runs only on failure.\n *\n * A message is compared with what its issue is about: the value at the\n * issue's path (its leaves, and its keys when it is an object) and the\n * path's own keys (an unknown key reported at its own path, valibot's and\n * arktype's, is the path's last). Not the rest of the value, nor the keys\n * beside it, so a schema's own words (`Expected one of \"waiting\", \"active\"`,\n * `Expected \"job\"`) survive another field holding `\"waiting\"` or named\n * `job`. A root issue, or a path the value does not lead along, is compared\n * with the whole value; so is every issue under the `\"whole\"`\n * {@link ScrubScope}. That fallback also compares the value's keys of three\n * or more characters unquoted, as whole words (yup's `unspecified keys: …`),\n * and so does a path-scoped issue with the keys of the value at its path\n * (yup's `o field has unspecified keys: …` at `o`): a `refine` on an object\n * whose message names one of its keys is withheld, unless it reports at\n * that key's own path.\n */\nimport type { StandardSchemaV1 } from \"./standardSchema\";\nimport type {\n GuardOptions,\n MaybePromise,\n Schema,\n StandardOutcome,\n ValidationIssue,\n} from \"./model\";\nimport { isPromiseLike } from \"./model\";\nimport { checkProtoKeyRule, stripProtoKeys } from \"./protoKeys\";\n\n/** The issue-wording options a runner honours. */\nexport type IssueFormat = Pick<GuardOptions, \"messages\" | \"redactPaths\">;\n\n/**\n * What of the received value an issue's message is compared with.\n * `\"path\"` (a schema's issues): the value at the issue's path, its keys of\n * three or more characters unquoted too, and the path's keys; the whole\n * value for a root issue, its keys likewise. `\"whole\"` (a response `refine`'s, which sees\n * every part): the whole received value, wherever the issue points.\n */\nexport type ScrubScope = \"path\" | \"whole\";\n\n/** `validateStandard`'s options: the issue wording, and the proto-key rule. */\nexport type RunOptions = Pick<\n GuardOptions,\n \"messages\" | \"redactPaths\" | \"stripProtoKeys\"\n>;\n\n/** At most this many received leaves are compared with a message. */\nconst MAX_LEAVES = 256;\n/** And none deeper than this. */\nconst MAX_DEPTH = 8;\n/** A vendor code safe to quote: a short identifier, never data. */\nconst SAFE_CODE = /^[\\w.:-]{1,64}$/;\n\n/**\n * Applies `f` to a value or a promise of one, staying synchronous when the\n * input is. Not named `then`: a module exporting `then` is a thenable, and\n * `await import()` of it would call that function.\n */\nexport function andThen<A, B>(\n value: MaybePromise<A>,\n f: (resolved: A) => MaybePromise<B>,\n): MaybePromise<B> {\n return isPromiseLike(value)\n ? Promise.resolve(value as PromiseLike<A>).then(f)\n : f(value);\n}\n\n/** The vendor's issue code (zod, arktype) or type (valibot), when it is a safe identifier. */\nfunction issueCode(issue: StandardSchemaV1.Issue): string | undefined {\n const { code, type } = issue as { code?: unknown; type?: unknown };\n const found = typeof code === \"string\" ? code : type;\n return typeof found === \"string\" && SAFE_CODE.test(found) ? found : undefined;\n}\n\n/** The generic message that replaces a vendor's. */\nfunction genericMessage(issue: StandardSchemaV1.Issue): string {\n const code = issueCode(issue);\n return code === undefined ? \"Invalid value\" : `Invalid value (${code})`;\n}\n\n/** Escapes `text` for use inside a regular expression. */\nconst escape = (text: string): string =>\n text.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n\n/**\n * Whether a short token (a one- or two-character string or number, a\n * boolean) is quoted as a received value: after a word vendors use for it (`received 7`,\n * `(was true)`, `` value was: `7` ``), or in quotes.\n */\nfunction quotesShort(message: string, token: string): boolean {\n const t = escape(token);\n return new RegExp(\n `(?:received|was|value|got|given)[^A-Za-z0-9]{0,4}${t}(?![\\\\w.])|[\"'\\`]${t}[\"'\\`]`,\n \"i\",\n ).test(message);\n}\n\n/** Records the tokens of one leaf that a message must not contain. */\ninterface Forbidden {\n /** Substrings that must not appear (long strings and numbers, quoted forms). */\n plain: string[];\n /** Short tokens matched only in a quoting context ({@link quotesShort}). */\n short: string[];\n /**\n * Keys of three or more characters, matched unquoted as whole words\n * ({@link namesKey}); filled from the whole value, or under `\"path\"` the\n * value at the issue's path.\n * Capped at `MAX_LEAVES` on their own, so they never crowd out a leaf.\n */\n keys: string[];\n}\n\n/**\n * Whether `message` names `key` as a whole word: not inside a longer word,\n * so `state` is not found in `statement`.\n */\nfunction namesKey(message: string, key: string): boolean {\n return new RegExp(`(?<!\\\\w)${escape(key)}(?!\\\\w)`).test(message);\n}\n\n/**\n * Adds `value`'s leaves (and quoted keys) to `out`, and with `bareKeys` its\n * keys of three or more characters unquoted; bounded, run only on failure.\n */\nfunction collect(\n value: unknown,\n out: Forbidden,\n depth: number,\n bareKeys = false,\n): void {\n if (out.plain.length + out.short.length >= MAX_LEAVES) return;\n switch (typeof value) {\n case \"string\":\n if (value.length >= 3) out.plain.push(value);\n else if (value.length > 0) {\n out.plain.push(JSON.stringify(value));\n out.short.push(value);\n }\n return;\n case \"number\":\n case \"bigint\": {\n const text = String(value);\n if (text.length >= 3) out.plain.push(text);\n else out.short.push(text);\n return;\n }\n case \"boolean\":\n out.short.push(String(value));\n return;\n case \"object\": {\n if (value === null || depth >= MAX_DEPTH) return;\n if (value instanceof Date) {\n if (!Number.isNaN(value.getTime())) out.plain.push(value.toISOString());\n return;\n }\n if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) return;\n const isArray = Array.isArray(value);\n for (const k of Object.keys(value)) {\n if (!isArray) {\n out.plain.push(JSON.stringify(k));\n if (bareKeys && k.length >= 3 && out.keys.length < MAX_LEAVES) {\n out.keys.push(k);\n }\n }\n collect(\n (value as Record<string, unknown>)[k],\n out,\n depth + 1,\n bareKeys,\n );\n if (out.plain.length + out.short.length >= MAX_LEAVES) return;\n }\n }\n }\n}\n\n/** The segment's key, whether the vendor gives a bare key or a `{ key }` object. */\nfunction segmentKey(\n segment: PropertyKey | StandardSchemaV1.PathSegment,\n): PropertyKey {\n return typeof segment === \"object\" && segment !== null && \"key\" in segment\n ? segment.key\n : segment;\n}\n\n/** Where an issue's path leads in the received value. */\ninterface AtPath {\n /** The value at the path; `undefined` when its last key is absent. */\n value: unknown;\n /** The object or array holding {@link AtPath.value}; `undefined` for the root. */\n holder: object | undefined;\n}\n\n/**\n * Walks `path` through `received`, or `undefined` when the path does not\n * lead along it (a segment past a value that is not an object).\n */\nfunction atPath(\n received: unknown,\n path: StandardSchemaV1.Issue[\"path\"],\n): AtPath | undefined {\n let value = received;\n let holder: object | undefined;\n for (const segment of path ?? []) {\n if (typeof value !== \"object\" || value === null) return undefined;\n holder = value;\n value = (value as Record<PropertyKey, unknown>)[segmentKey(segment)];\n }\n return { value, holder };\n}\n\n/**\n * Whether `issue`'s message quotes anything received, each bounded. Under\n * `\"path\"`: the value at the issue's path (its leaves, and its keys when it\n * is an object) and the path's own keys (quoted); the whole value for a\n * root issue or a path that does not lead along it; either way with the\n * compared value's keys of three or more characters also unquoted\n * ({@link namesKey}). Under `\"whole\"`: the value at the path first, so it is\n * inside the bound, then the whole value, keys quoted only.\n */\nfunction quotesReceived(\n issue: StandardSchemaV1.Issue,\n received: unknown,\n scope: ScrubScope,\n): boolean {\n const message = issue.message;\n const tokens: Forbidden = { plain: [], short: [], keys: [] };\n const at = atPath(received, issue.path);\n if (at === undefined || at.holder === undefined) {\n // The whole value: a root issue, or a path that does not lead along it.\n collect(received, tokens, 0, true);\n } else {\n // Under \"path\", the keys at the path unquoted too (yup's nested\n // `unspecified keys: …`); a response refine's \"whole\" stays quoted.\n collect(at.value, tokens, 0, scope === \"path\");\n if (scope === \"whole\") collect(received, tokens, 0);\n }\n for (const segment of issue.path ?? []) {\n const key = segmentKey(segment);\n if (typeof key === \"string\") tokens.plain.push(JSON.stringify(key));\n }\n for (const token of tokens.plain) {\n if (message.includes(token)) return true;\n }\n for (const token of tokens.short) {\n if (quotesShort(message, token)) return true;\n }\n for (const key of tokens.keys) {\n if (namesKey(message, key)) return true;\n }\n return false;\n}\n\n/** The issue's message with any received value withheld, per `format`. */\nfunction scrubbedMessage(\n issue: StandardSchemaV1.Issue,\n received: unknown,\n format: IssueFormat | undefined,\n scope: ScrubScope,\n): string {\n if (format?.messages === \"generic\") return genericMessage(issue);\n const message = typeof issue.message === \"string\" ? issue.message : \"\";\n if (message.length === 0) return genericMessage(issue);\n return quotesReceived(issue, received, scope)\n ? genericMessage(issue)\n : message;\n}\n\n/** Renders a Standard Schema issue path as a dotted string of its keys. */\nexport function formatPath(issue: StandardSchemaV1.Issue): string {\n if (!issue.path || issue.path.length === 0) return \"\";\n return issue.path.map((segment) => String(segmentKey(segment))).join(\".\");\n}\n\n/**\n * Flattens a vendor's issues into {@link ValidationIssue}s for one part.\n * Run only on failure.\n *\n * @param issues The vendor's issues.\n * @param received The value they are about, which their messages must not quote.\n * @param target The part's name, reported on every issue.\n * @param key The declared key, reported on every issue.\n * @param mediaType The declared media type, reported on every issue.\n * @param format How issues are worded: `messages: \"generic\"` and `redactPaths`.\n * @param scope What of `received` a message is compared with (a {@link ScrubScope}).\n * Default `\"path\"`; a response `refine` passes `\"whole\"`.\n */\nexport function toIssues<TTarget extends string>(\n issues: readonly StandardSchemaV1.Issue[],\n received: unknown,\n target: TTarget,\n key: string | undefined,\n mediaType: string | undefined,\n format: IssueFormat | undefined,\n scope: ScrubScope = \"path\",\n): ValidationIssue<TTarget>[] {\n return issues.map((issue) => {\n const out: ValidationIssue<TTarget> = {\n target,\n message: scrubbedMessage(issue, received, format, scope),\n path: format?.redactPaths === true ? \"\" : formatPath(issue),\n };\n if (key !== undefined) out.key = key;\n if (mediaType !== undefined) out.mediaType = mediaType;\n return out;\n });\n}\n\n/**\n * Runs `schema` on `value`, with the key given raw (a status may be the\n * number `200`), converting it to a string only if there are issues. The\n * guards' entry point; {@link validateStandard} is the public one.\n */\nexport function runSchema<T, TTarget extends string>(\n schema: Schema,\n value: unknown,\n target: TTarget,\n key: string | number | undefined,\n mediaType: string | undefined,\n format: IssueFormat | undefined,\n): MaybePromise<StandardOutcome<T, TTarget>> {\n const settle = (\n result: StandardSchemaV1.Result<unknown>,\n ): StandardOutcome<T, TTarget> =>\n result.issues\n ? {\n ok: false,\n issues: toIssues(\n result.issues,\n value,\n target,\n key === undefined ? undefined : String(key),\n mediaType,\n format,\n ),\n }\n : { ok: true, value: result.value as T };\n const result = schema[\"~standard\"].validate(value);\n // Any thenable is async, not only a Promise: a vendor's own thenable would\n // otherwise read as a result with no `issues`, a pass.\n return isPromiseLike(result)\n ? Promise.resolve(result).then(settle)\n : settle(result);\n}\n\n/**\n * The one runner (plan V-D2): validates `value` with `schema` and flattens\n * any issues under `target`, with no received value in them.\n *\n * Synchronous when the vendor is (zod, valibot, arktype, a hand-rolled sync\n * schema); a Promise only when the vendor returns one (yup, an async schema).\n *\n * Given `options.stripProtoKeys`, `value`'s prototype-pollution keys are\n * stripped in place first, by that rule: `\"nest\"`, Nest 12's (every own\n * `__proto__` and `prototype` key, and `constructor` keys, recursively), or\n * `\"minimal\"` (own `__proto__` keys, and `constructor` keys holding an object\n * with a `prototype`). Unset, nothing is stripped: this runner also checks\n * values a server built itself (a response body, whose `__proto__`-named key\n * is data). The input entry points pass a rule, `\"nest\"` by default:\n * `validate()`'s request targets, the guards' receivers and bun-nest's pipes.\n * A caller validating untrusted input itself must pass `stripProtoKeys` too.\n * A `{\"__proto__\": …}` body would otherwise crash yup (a 500) or reach a\n * vendor that assigns it.\n *\n * @param schema Any Standard Schema.\n * @param value The value to check; given `stripProtoKeys`, its prototype-pollution keys are deleted.\n * @param target The part's name, reported on every issue (`\"body\"`, `\"payload\"`).\n * @param key The declared key, reported on every issue (a status, a message type).\n * @param mediaType The declared media type, reported on every issue.\n * @param options How issues are worded (`messages: \"generic\"` and\n * `redactPaths`), and which proto keys are stripped (`stripProtoKeys`:\n * none when unset; anything but `\"nest\"` or `\"minimal\"` throws a\n * `TypeError`).\n */\nexport function validateStandard<S extends Schema, TTarget extends string>(\n schema: S,\n value: unknown,\n target: TTarget,\n key?: string,\n mediaType?: string,\n options?: RunOptions,\n): MaybePromise<StandardOutcome<StandardSchemaV1.InferOutput<S>, TTarget>> {\n const rule = checkProtoKeyRule(\"validateStandard()\", options?.stripProtoKeys);\n if (rule !== undefined) stripProtoKeys(value, rule);\n return runSchema(schema, value, target, key, mediaType, options);\n}\n",
|
|
8
|
+
"/**\n * Where the contract core's few log lines go, with no logging library behind\n * it: a guard under `\"warn\"` writes one warning per failing message, a guard\n * whose `onIssues` hook throws writes one error, and `mergeContracts` warns\n * about a refinement. Those are the only records, so the core asks for the\n * smallest logger that can take them ({@link ContractLogger}) or a function\n * taking each record ({@link ContractLogSink}).\n *\n * On its own the package resolves a `logger` option itself: nothing means\n * the console, a function is called with each record, and an object's\n * `warn`/`error` are called with `(message, fields)`. bun-common installs\n * its own resolver ({@link setLoggerResolver}) when its contract entry\n * loads, so there the option keeps accepting every logger bun-common's\n * `resolveLogger` adapts (pino and bunyan take their fields first, and are\n * called that way), and an absent one is bun-common's console logger.\n *\n * Browser-safe: no import at all.\n */\n\n/**\n * One record handed to a {@link ContractLogSink}. Its fields are those of\n * bun-common's `LogEvent` that a record must have, so a bun-common `LogSink`\n * is a {@link ContractLogSink}.\n */\nexport interface ContractLogEvent {\n /** The level: the core writes only warnings and errors. */\n level: \"warn\" | \"error\";\n /** The message, e.g. `\"contract mismatch\"`. */\n message: string;\n /**\n * The `Error` behind the record, lifted from `fields.error` when that is\n * one; absent otherwise.\n */\n error?: Error;\n /** The record's structured fields (transport, side, issues). */\n fields: Record<string, unknown>;\n /** Fields bound to the logger; always empty here, kept for `LogEvent`'s shape. */\n bindings: Record<string, unknown>;\n /** When the record was made (`Date.now()`). */\n time: number;\n}\n\n/** A function taking each record; bun-common's `LogSink` is one. */\nexport type ContractLogSink = (event: ContractLogEvent) => void;\n\n/**\n * The two methods the contract core calls, each with a message and\n * structured fields. bun-common's `Logger` and the console are this shape.\n */\nexport interface ContractLogger {\n /** Writes a warning: the message and its fields. */\n warn: (message: string, fields?: Record<string, unknown>) => void;\n /** Writes an error: the message and its fields. */\n error: (message: string, fields?: Record<string, unknown>) => void;\n}\n\n/**\n * What a `logger` option accepts: a {@link ContractLogger} or a\n * {@link ContractLogSink}. Every logger bun-common's `LoggerLike` names\n * (its `Logger`, a `LogSink`, pino, bunyan, winston, consola, log4js, tslog,\n * a NestJS or console-like logger) is one of the two, structurally; how it\n * is called depends on the resolver (see the module's comment).\n */\nexport type ContractLoggerLike = ContractLogger | ContractLogSink;\n\n/**\n * Turns a `logger` option, or its absence, into the logger the core writes\n * to. Called once per guard or merge, on its first record.\n */\nexport type ContractLoggerResolver = (\n input: ContractLoggerLike | undefined,\n) => ContractLogger;\n\n/**\n * The host's console, as far as the default logger uses it. Browsers, Bun\n * and Node all have one; declared here so the package type-checks, and builds\n * its declarations, with no environment's types (it imports none).\n */\ndeclare const console: {\n /** Writes a warning. */\n warn: (...data: unknown[]) => void;\n /** Writes an error. */\n error: (...data: unknown[]) => void;\n};\n\n/** The console, as a {@link ContractLogger}; the default when no logger is given. */\nconst consoleLogger: ContractLogger = {\n warn: (message, fields) => {\n if (fields === undefined) console.warn(message);\n else console.warn(message, fields);\n },\n error: (message, fields) => {\n if (fields === undefined) console.error(message);\n else console.error(message, fields);\n },\n};\n\n/** A logger writing each record to `sink`. */\nfunction sinkLogger(sink: ContractLogSink): ContractLogger {\n const write =\n (level: ContractLogEvent[\"level\"]) =>\n (message: string, fields: Record<string, unknown> = {}): void => {\n const error = fields.error;\n sink({\n level,\n message,\n ...(error instanceof Error ? { error } : {}),\n fields,\n bindings: {},\n time: Date.now(),\n });\n };\n return { warn: write(\"warn\"), error: write(\"error\") };\n}\n\n/**\n * The package's own resolution, used until a resolver is installed: the\n * console for nothing, a sink for a function, the object itself when it has\n * `warn` and `error` methods.\n *\n * @throws {TypeError} For anything else, naming what is accepted.\n */\nexport function defaultLoggerResolver(\n input: ContractLoggerLike | undefined,\n): ContractLogger {\n if (input === undefined || input === null) return consoleLogger;\n if (typeof input === \"function\") return sinkLogger(input);\n if (\n typeof input === \"object\" &&\n typeof input.warn === \"function\" &&\n typeof input.error === \"function\"\n ) {\n return input;\n }\n throw new TypeError(\n \"Unrecognised logger. Pass an object with warn(message, fields) and error(message, fields), or a function taking each log record.\",\n );\n}\n\n/** The installed resolver; `undefined` means {@link defaultLoggerResolver}. */\nlet installed: ContractLoggerResolver | undefined;\n\n/**\n * Installs how a `logger` option is resolved, for every guard and merge\n * made afterwards in this copy of the package; `undefined` restores\n * {@link defaultLoggerResolver}. bun-common calls it when its contract entry\n * loads. Internal: not exported from the package's root.\n *\n * @param resolver The resolver, or `undefined` for the default.\n * @returns The resolver it replaced (`undefined` when it was the default), so a caller can put it back.\n */\nexport function setLoggerResolver(\n resolver: ContractLoggerResolver | undefined,\n): ContractLoggerResolver | undefined {\n const previous = installed;\n installed = resolver;\n return previous;\n}\n\n/**\n * Resolves a `logger` option with the installed resolver, or the default.\n *\n * @param input The option's value; `undefined` when none was given.\n */\nexport function resolveContractLogger(\n input: ContractLoggerLike | undefined,\n): ContractLogger {\n return (installed ?? defaultLoggerResolver)(input);\n}\n",
|
|
9
|
+
"/**\n * Media-type keys (plan Q-C4, Q-C14, §4.12 m2): how a declared media map is\n * matched against the media type a message travels as.\n *\n * - Keys are **bare** `type/subtype`, matched **case-insensitively**.\n * - **Parameters are stripped on both sides**: a declared\n * `text/plain; version=0.0.4` and a sent `text/plain;charset=utf-8` both\n * match as `text/plain`. The declared key, parameters included, is kept as\n * written for documents.\n * - **Wildcards** `type/*` and `*\\/*` are keys too, and **the most specific\n * key wins**: an exact `type/subtype`, then `type/*`, then `*\\/*`.\n * - Two keys that are the same once bare and lower-cased (`text/plain` and\n * `Text/Plain; charset=utf-8`) would tie, so a map holding both is refused\n * when it is declared, as is a key that is not a media type (`json`,\n * `*\\/json`, `text/x*`).\n *\n * Nothing here imports a Bun or Node API (browser-safe, like the rest of\n * `lib/contract/`). Internal: the names are not exported from the package.\n */\n\n/** A token of RFC 9110's `type` or `subtype` (`tchar`s), already lower-cased. */\nconst TOKEN = /^[!#$%&'*+.^\\w`|~-]+$/;\n\n/** A declared media key, parsed once. */\nexport interface MediaKey {\n /** The key as declared, parameters and case included (what documents show). */\n readonly declared: string;\n /** The bare, lower-cased `type/subtype` (`text/plain`, `text/*`, `*\\/*`). */\n readonly bare: string;\n /** The lower-cased type (`text`, or `*`). */\n readonly type: string;\n /** How specific the key is: `2` exact, `1` for `type/*`, `0` for `*\\/*`. */\n readonly specificity: 0 | 1 | 2;\n}\n\n/**\n * The bare, lower-cased `type/subtype` of a media type or `Content-Type`\n * value: parameters (`; charset=utf-8`) and surrounding space dropped.\n *\n * @param mediaType A media type as declared or sent.\n */\nexport function bareMediaType(mediaType: string): string {\n const semi = mediaType.indexOf(\";\");\n return (semi === -1 ? mediaType : mediaType.slice(0, semi))\n .trim()\n .toLowerCase();\n}\n\n/**\n * Parses a declared media key, or answers `undefined` when it is not a media\n * type a map can be keyed by: `type/subtype`, `type/*` or `*\\/*`, with\n * optional parameters. A `*` anywhere else (`*\\/json`, `text/x*`) is refused.\n *\n * @param declared The key as written in the map.\n */\nexport function parseMediaKey(declared: string): MediaKey | undefined {\n const bare = bareMediaType(declared);\n const slash = bare.indexOf(\"/\");\n if (slash <= 0 || slash !== bare.lastIndexOf(\"/\")) return undefined;\n const type = bare.slice(0, slash);\n const subtype = bare.slice(slash + 1);\n if (!TOKEN.test(type) || !TOKEN.test(subtype)) return undefined;\n if (type === \"*\") {\n return subtype === \"*\"\n ? { declared, bare, type, specificity: 0 }\n : undefined;\n }\n if (type.includes(\"*\")) return undefined;\n if (subtype === \"*\") return { declared, bare, type, specificity: 1 };\n if (subtype.includes(\"*\")) return undefined;\n return { declared, bare, type, specificity: 2 };\n}\n\n/**\n * A media map compiled for matching: one lookup per specificity, so a match\n * costs at most three `Map` reads.\n */\nexport interface MediaMatcher<V> {\n /**\n * The entry a message sent as `mediaType` (a full `Content-Type` value is\n * fine) falls under: the exact key, else its `type/*`, else `*\\/*`; or\n * `undefined` when none is declared.\n */\n match: (mediaType: string) => [key: MediaKey, value: V] | undefined;\n /** Every declared key, as written, in declaration order (for messages). */\n readonly declared: readonly string[];\n}\n\n/**\n * Compiles a media map. Throws a `TypeError` for a key that is not a media\n * type and for two keys that tie (the same once bare and lower-cased).\n *\n * @param map The map, media key to value.\n * @param where Names the declaration in the error (`validate().responses[200].content`).\n */\nexport function compileMediaMap<V>(\n map: Readonly<Record<string, V>>,\n where: string,\n): MediaMatcher<V> {\n const byBare = new Map<string, [MediaKey, V]>();\n const declared: string[] = [];\n for (const [key, value] of Object.entries(map)) {\n const parsed = parseMediaKey(key);\n if (parsed === undefined) {\n throw new TypeError(\n `${where}: ${JSON.stringify(key)} is not a media type (type/subtype, type/* or */*)`,\n );\n }\n const tie = byBare.get(parsed.bare);\n if (tie !== undefined) {\n throw new TypeError(\n `${where}: ${JSON.stringify(tie[0].declared)} and ${JSON.stringify(key)} are the same media type once parameters and case are ignored`,\n );\n }\n byBare.set(parsed.bare, [parsed, value]);\n declared.push(key);\n }\n const any = byBare.get(\"*/*\");\n return {\n declared,\n match: (mediaType: string): [MediaKey, V] | undefined => {\n const bare = bareMediaType(mediaType);\n const exact = byBare.get(bare);\n if (exact !== undefined && exact[0].specificity === 2) return exact;\n const slash = bare.indexOf(\"/\");\n if (slash > 0) {\n const family = byBare.get(`${bare.slice(0, slash)}/*`);\n if (family !== undefined) return family;\n }\n return any;\n },\n };\n}\n",
|
|
10
|
+
"/**\n * Schemas the core builds: `recordOf` (a schema over a record of schemas),\n * `documented` (a JSON Schema that documents and never checks), and the\n * markers describeContract reads.\n */\nimport type { StandardJSONSchemaV1, StandardSchemaV1 } from \"./standardSchema\";\nimport type { AnyContract, ContractKind, MaybePromise, Schema } from \"./model\";\nimport { isPromiseLike } from \"./model\";\n\n/**\n * A Standard JSON Schema converter (`~standard.jsonSchema`): one JSON Schema\n * for what a schema accepts, one for what it produces. The vendored spec's\n * `StandardJSONSchemaV1.Converter`, under a shorter internal name.\n *\n * @internal\n */\nexport type JsonSchemaConverter = StandardJSONSchemaV1.Converter;\n\n/**\n * A JSON Schema given to `documented()` or `toStandardSchema()`: one JSON\n * Schema object (the same for input and output, whatever the target), or a\n * {@link JsonSchemaConverter}. Its name is not approved.\n *\n * @internal\n */\nexport type JsonSchemaSource = Record<string, unknown> | JsonSchemaConverter;\n\n/** A Standard Schema whose `~standard` also carries a JSON Schema converter. */\nexport interface SchemaWithJson<\n Input = unknown,\n Output = Input,\n> extends StandardSchemaV1<Input, Output> {\n /** The Standard Schema properties, with the converter. */\n readonly \"~standard\": StandardSchemaV1.Props<Input, Output> & {\n /** The JSON Schema converter (Standard JSON Schema). */\n readonly jsonSchema: JsonSchemaConverter;\n };\n}\n\n/** Marks a schema as documentation only (`documented()`). */\nconst DOCUMENTED: unique symbol = Symbol.for(\"bun-validate.documented\");\n/** Marks a schema with its body kind (`chunks()`, `sse()`, `opaque()`). */\nconst KIND: unique symbol = Symbol.for(\"bun-validate.kind\");\n/** Marks a schema with the contract its rows expand into (an `sse()` body's events, plan §4.12 M4). */\nconst NESTED: unique symbol = Symbol.for(\"bun-validate.nested\");\n/** Marks a schema the framework declared on its own (plan §4.12 m5). */\nconst IMPLICIT: unique symbol = Symbol.for(\"bun-validate.implicit\");\n\n/** Whether `source` is a converter rather than one JSON Schema object. */\nfunction isConverter(source: JsonSchemaSource): source is JsonSchemaConverter {\n return (\n typeof (source as Partial<JsonSchemaConverter>).input === \"function\" &&\n typeof (source as Partial<JsonSchemaConverter>).output === \"function\"\n );\n}\n\n/**\n * The host's `structuredClone` (browsers, Bun, Node 17+). Declared here so\n * the package type-checks, and builds its declarations, with no\n * environment's types (it imports none).\n */\ndeclare function structuredClone<T>(value: T): T;\n\n/** A converter from a {@link JsonSchemaSource}; a plain object is returned as a copy each call. */\nexport function toConverter(source: JsonSchemaSource): JsonSchemaConverter {\n if (isConverter(source)) return source;\n const copy = (): Record<string, unknown> =>\n structuredClone<Record<string, unknown>>(source);\n return { input: copy, output: copy };\n}\n\n/** The converter a schema carries in `~standard.jsonSchema`, if any. */\nexport function jsonSchemaOf(schema: Schema): JsonSchemaConverter | undefined {\n const converter = (schema[\"~standard\"] as { jsonSchema?: unknown })\n .jsonSchema;\n return typeof converter === \"object\" &&\n converter !== null &&\n typeof (converter as Partial<JsonSchemaConverter>).input === \"function\" &&\n typeof (converter as Partial<JsonSchemaConverter>).output === \"function\"\n ? (converter as JsonSchemaConverter)\n : undefined;\n}\n\n/** Whether `schema` came from `documented()`: it documents, and never checks. */\nexport function isDocumented(schema: unknown): boolean {\n return (\n typeof schema === \"object\" &&\n schema !== null &&\n (schema as { [DOCUMENTED]?: unknown })[DOCUMENTED] === true\n );\n}\n\n/**\n * Marks `schema` as a body of `kind`, read by `describeContract`. Returns\n * `schema`. For `chunks()`, `sse()` and `opaque()`; not exported.\n *\n * @internal\n */\nexport function markKind<S extends object>(schema: S, kind: ContractKind): S {\n Object.defineProperty(schema, KIND, {\n value: kind,\n enumerable: false,\n configurable: true,\n });\n return schema;\n}\n\n/**\n * Marks `schema` as declared by the framework rather than the app (a\n * validator's own failure status, plan §4.12 m5): `describeContract` flags\n * its rows `implicit`, and `mergeContracts` lets any declared schema for the\n * same part win over it. Returns `schema`. Not exported.\n *\n * @internal\n */\nexport function markImplicit<S extends object>(schema: S): S {\n Object.defineProperty(schema, IMPLICIT, {\n value: true,\n enumerable: false,\n configurable: true,\n });\n return schema;\n}\n\n/** Whether `markImplicit` marked `schema`. */\nexport function isImplicit(schema: unknown): boolean {\n return (\n typeof schema === \"object\" &&\n schema !== null &&\n (schema as { [IMPLICIT]?: unknown })[IMPLICIT] === true\n );\n}\n\n/** The kind `markKind` recorded on `schema`; `\"value\"` when none. */\nexport function kindOf(schema: unknown): ContractKind {\n if (typeof schema !== \"object\" || schema === null) return \"value\";\n const kind = (schema as { [KIND]?: unknown })[KIND];\n return kind === \"chunks\" || kind === \"sse\" || kind === \"opaque\"\n ? kind\n : \"value\";\n}\n\n/**\n * The media type an `opaque(mediaType)` declaration carries; `undefined` for\n * any other schema, `opaque()` included. Such a declaration is a whole\n * status's spec, so a media map refuses it as a value.\n *\n * @internal\n */\nexport function opaqueMediaType(schema: unknown): string | undefined {\n if (kindOf(schema) !== \"opaque\") return undefined;\n const mediaType = (schema as { mediaType?: unknown }).mediaType;\n return typeof mediaType === \"string\" ? mediaType : undefined;\n}\n\n/**\n * A pass-through Standard Schema for a part known only as JSON Schema\n * (docs-only responses, routes documented for Swagger): it **documents and\n * never checks**. Its `validate` hands back what it is given, and a guard\n * skips it entirely; its `~standard.jsonSchema` returns `jsonSchema` for\n * input and output (plan Q-C12). When layers are merged, a checking schema\n * for the same part wins over it, with a warning if the two disagree.\n *\n * @typeParam T The type it claims (nothing checks it). Default `unknown`.\n * @param jsonSchema One JSON Schema object, or a converter.\n *\n * @example\n * ```ts\n * const Legacy = documented<{ id: string }>({\n * type: \"object\",\n * properties: { id: { type: \"string\" } },\n * required: [\"id\"],\n * });\n * ```\n */\nexport function documented<T = unknown>(\n jsonSchema: JsonSchemaSource,\n): SchemaWithJson<T, T> {\n if (typeof jsonSchema !== \"object\" || jsonSchema === null) {\n throw new TypeError(\n \"documented(): expected a JSON Schema object or converter\",\n );\n }\n const schema: SchemaWithJson<T, T> = {\n \"~standard\": {\n version: 1,\n vendor: \"bun-common/documented\",\n validate: (value: unknown) => ({ value: value as T }),\n jsonSchema: toConverter(jsonSchema),\n },\n };\n Object.defineProperty(schema, DOCUMENTED, { value: true, enumerable: false });\n return schema;\n}\n\n/** `$schema` taken off a member's JSON Schema, since the record states it once. */\nfunction withoutDialect(\n json: Record<string, unknown>,\n): [Record<string, unknown>, unknown] {\n const { $schema, ...rest } = json;\n return [rest, $schema];\n}\n\n/** The record's JSON Schema in one direction, composed from its members'. */\nfunction composeJson(\n members: readonly (readonly [string, JsonSchemaConverter])[],\n direction: \"input\" | \"output\",\n options: StandardJSONSchemaV1.Options,\n): Record<string, unknown> {\n const properties: Record<string, unknown> = {};\n let dialect: unknown;\n for (const [key, converter] of members) {\n const [json, $schema] = withoutDialect(converter[direction](options));\n properties[key] = json;\n dialect ??= $schema;\n }\n return {\n ...(dialect === undefined ? {} : { $schema: dialect }),\n type: \"object\",\n properties,\n required: members.map(([key]) => key),\n };\n}\n\n/**\n * A Standard Schema over a record of schemas (a flow's children results, a\n * gRPC metadata map): each key is checked by its own schema, and the output\n * holds the declared keys only. Synchronous when every member is. When every\n * member carries `~standard.jsonSchema`, so does the record, composed from\n * theirs (plan §4.12 m10); otherwise it carries none.\n *\n * @param schemas The member schemas, by key.\n * @param options The record schema's options.\n * @param options.vendor The vendor it reports; default `\"bun-common\"`.\n */\nexport function recordOf<const M extends Readonly<Record<string, Schema>>>(\n schemas: M,\n options: {\n /** The vendor the record schema reports. Default `\"bun-common\"`. */\n readonly vendor?: string;\n } = {},\n): StandardSchemaV1<\n { -readonly [K in keyof M]: StandardSchemaV1.InferInput<M[K]> },\n { -readonly [K in keyof M]: StandardSchemaV1.InferOutput<M[K]> }\n> {\n type Out = { -readonly [K in keyof M]: StandardSchemaV1.InferOutput<M[K]> };\n const entries = Object.entries(schemas);\n const validate = (\n value: unknown,\n ): MaybePromise<StandardSchemaV1.Result<Out>> => {\n if (typeof value !== \"object\" || value === null) {\n return { issues: [{ message: \"Expected an object\", path: [] }] };\n }\n const results = entries.map(([key, schema]) =>\n schema[\"~standard\"].validate((value as Record<string, unknown>)[key]),\n );\n const finish = (\n settled: readonly StandardSchemaV1.Result<unknown>[],\n ): StandardSchemaV1.Result<Out> => {\n const out: Record<string, unknown> = {};\n const issues: StandardSchemaV1.Issue[] = [];\n settled.forEach((result, i) => {\n const key = entries[i][0];\n if (result.issues) {\n for (const issue of result.issues) {\n const code = (issue as { code?: unknown }).code;\n issues.push({\n message: issue.message,\n path: [key, ...(issue.path ?? [])],\n ...(typeof code === \"string\" ? { code } : {}),\n });\n }\n } else out[key] = result.value;\n });\n return issues.length > 0 ? { issues } : { value: out as Out };\n };\n // Promise.all adopts any thenable a member answers with, not only a Promise.\n return results.some(isPromiseLike)\n ? Promise.all(results).then(finish)\n : finish(results as StandardSchemaV1.Result<unknown>[]);\n };\n const converters = entries.map(\n ([key, schema]) => [key, jsonSchemaOf(schema)] as const,\n );\n const props: StandardSchemaV1.Props<unknown, Out> & {\n jsonSchema?: JsonSchemaConverter;\n } = {\n version: 1,\n vendor: options.vendor ?? \"bun-common\",\n validate,\n };\n if (converters.every(([, c]) => c !== undefined)) {\n const members = converters as readonly (readonly [\n string,\n JsonSchemaConverter,\n ])[];\n props.jsonSchema = {\n input: (o) => composeJson(members, \"input\", o),\n output: (o) => composeJson(members, \"output\", o),\n };\n }\n return { \"~standard\": props } as StandardSchemaV1<\n { -readonly [K in keyof M]: StandardSchemaV1.InferInput<M[K]> },\n Out\n >;\n}\n\n/**\n * Records on `schema` the contract its row expands into: an `sse()` body\n * carries its events as an SSE contract (keyed by `event`, parts `data` and\n * `id`), so `describeContract` lists them as the row's `nested` rows,\n * identical to an SSE writer's own (plan §4.12 M4). Returns `schema`. Not\n * exported.\n *\n * @internal\n */\nexport function markNested<S extends object>(\n schema: S,\n contract: AnyContract,\n): S {\n Object.defineProperty(schema, NESTED, {\n value: contract,\n enumerable: false,\n configurable: true,\n });\n return schema;\n}\n\n/** The contract `markNested` recorded on `schema`, if any. */\nexport function nestedOf(schema: unknown): AnyContract | undefined {\n if (typeof schema !== \"object\" || schema === null) return undefined;\n return (schema as { [NESTED]?: AnyContract })[NESTED];\n}\n",
|
|
11
|
+
"/**\n * Declaring transports and contracts, and carrying contracts at runtime.\n */\nimport type {\n AnyContract,\n Carries,\n Contract,\n ContractDef,\n ContractMeta,\n Side,\n SideSpec,\n StrictDef,\n Transport,\n TransportSpec,\n} from \"./model\";\nimport { compileMediaMap } from \"./media\";\nimport { CONTRACT } from \"./model\";\nimport { opaqueMediaType } from \"./schemas\";\n\n/** The two sides, in canonical order. */\nexport const SIDES: readonly Side[] = [\"inbound\", \"outbound\"];\n\n/** Whether `value` is a Standard Schema (it has a `~standard` object with a `validate` function). */\nexport function isSchema(\n value: unknown,\n): value is { \"~standard\": { validate: unknown } } {\n if (typeof value !== \"object\" && typeof value !== \"function\") return false;\n if (value === null) return false;\n const props = (value as { \"~standard\"?: unknown })[\"~standard\"];\n return (\n typeof props === \"object\" &&\n props !== null &&\n typeof (props as { validate?: unknown }).validate === \"function\"\n );\n}\n\n/** Whether `value` is a plain object (an object literal, or one with a null prototype). */\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== \"object\" || value === null) return false;\n const proto = Object.getPrototypeOf(value) as unknown;\n return proto === Object.prototype || proto === null;\n}\n\n/** Checks one side of a transport declaration; throws a `TypeError` naming the mistake. */\nfunction checkSideSpec(name: string, side: Side, spec: SideSpec): void {\n const where = `defineTransport(\"${name}\").${side}`;\n if (!Array.isArray(spec.parts)) {\n throw new TypeError(`${where}: \"parts\" must be an array of part names`);\n }\n const seen = new Set<string>();\n for (const part of spec.parts) {\n if (typeof part !== \"string\" || part.length === 0) {\n throw new TypeError(\n `${where}: every part name must be a non-empty string`,\n );\n }\n if (seen.has(part)) {\n throw new TypeError(`${where}: the part \"${part}\" is listed twice`);\n }\n seen.add(part);\n }\n if (spec.key !== undefined) {\n if (typeof spec.key !== \"string\" || spec.key.length === 0) {\n throw new TypeError(`${where}: \"key\" must be a non-empty string`);\n }\n if (seen.has(spec.key)) {\n throw new TypeError(\n `${where}: the key \"${spec.key}\" cannot also be a part`,\n );\n }\n }\n for (const part of spec.media ?? []) {\n if (!seen.has(part)) {\n throw new TypeError(`${where}: media part \"${part}\" is not a part`);\n }\n }\n for (const part of Object.keys(spec.encodings ?? {})) {\n if (!seen.has(part)) {\n throw new TypeError(`${where}: the encoding for \"${part}\" names no part`);\n }\n }\n}\n\n/** Checks one message shape's part declarations against its side. */\nfunction checkParts(where: string, spec: SideSpec, parts: unknown): void {\n if (!isPlainObject(parts)) {\n throw new TypeError(`${where}: expected an object of parts`);\n }\n for (const [part, decl] of Object.entries(parts)) {\n if (!spec.parts.includes(part)) {\n throw new TypeError(\n `${where}: \"${part}\" is not a part (${spec.parts.join(\", \")})`,\n );\n }\n if (decl === undefined || decl === null || isSchema(decl)) continue;\n if (!(spec.media ?? []).includes(part)) {\n throw new TypeError(\n `${where}: \"${part}\" must be a Standard Schema or null`,\n );\n }\n if (!isPlainObject(decl)) {\n throw new TypeError(\n `${where}: \"${part}\" must be a Standard Schema, a media map or null`,\n );\n }\n for (const [mediaType, schema] of Object.entries(decl)) {\n if (schema !== null && !isSchema(schema)) {\n throw new TypeError(\n `${where}: \"${part}\" media type \"${mediaType}\" must be a Standard Schema or null`,\n );\n }\n const own = opaqueMediaType(schema);\n if (own !== undefined) {\n throw new TypeError(\n `${where}: \"${part}\" media type \"${mediaType}\": opaque(${JSON.stringify(own)}) names a second media type; inside a media map write opaque()`,\n );\n }\n }\n // Every key a media type, no two tying once bare (plan Q-C14).\n compileMediaMap(decl, `${where}: \"${part}\"`);\n }\n}\n\n/** Checks a contract's declaration against its transport; throws a `TypeError` naming the mistake. */\nexport function checkContractDef(spec: TransportSpec, def: unknown): void {\n if (!isPlainObject(def)) {\n throw new TypeError(`${spec.name}.contract(): expected an object of sides`);\n }\n for (const [side, sideDef] of Object.entries(def)) {\n if (sideDef === undefined) continue;\n const s =\n side === \"inbound\" || side === \"outbound\" ? spec[side] : undefined;\n if (s === undefined) {\n throw new TypeError(`${spec.name}.contract(): no ${side} side`);\n }\n const where = `${spec.name}.contract().${side}`;\n if (s.key === undefined) {\n checkParts(where, s, sideDef);\n continue;\n }\n if (!isPlainObject(sideDef)) {\n throw new TypeError(`${where}: expected an object keyed by ${s.key}`);\n }\n for (const [key, parts] of Object.entries(sideDef)) {\n checkParts(`${where}[${JSON.stringify(key)}]`, s, parts);\n }\n }\n}\n\n/**\n * Builds a contract object without checking its declaration (the caller\n * has). It carries itself, so `getContract(contract)` is the contract.\n */\nexport function makeContract<T extends TransportSpec, D>(\n spec: T,\n def: D,\n meta: ContractMeta,\n): Contract<T, D> {\n const contract = { transport: spec, def, meta } as Contract<T, D>;\n return attachContract(contract, contract);\n}\n\n/**\n * Declares a transport by its part and key names (plan §4.1.1); typing,\n * validation and document rows follow from it. A key that is also a part, a\n * media part or encoding that names no part, and a repeated part are\n * `TypeError`s.\n *\n * @param spec The transport's name and sides.\n *\n * @example\n * ```ts\n * const udp = defineTransport({\n * name: \"udp\",\n * inbound: { key: \"type\", parts: [\"payload\"] },\n * outbound: { key: \"type\", parts: [\"payload\"] },\n * });\n * const chat = udp.contract({\n * inbound: { \"chat.post\": { payload: z.object({ text: z.string() }) } },\n * outbound: { \"chat.ack\": { payload: z.object({ seq: z.number() }) } },\n * });\n * ```\n */\nexport function defineTransport<const T extends TransportSpec>(\n spec: T,\n): Transport<T> {\n if (typeof spec?.name !== \"string\" || spec.name.length === 0) {\n throw new TypeError('defineTransport(): \"name\" must be a non-empty string');\n }\n if (\n spec.wire !== undefined &&\n spec.wire !== \"json\" &&\n spec.wire !== \"identity\"\n ) {\n throw new TypeError(\n `defineTransport(\"${spec.name}\"): \"wire\" is \"json\" or \"identity\"`,\n );\n }\n for (const side of SIDES) {\n const s = spec[side];\n if (s !== undefined) checkSideSpec(spec.name, side, s);\n }\n const contract = <const D extends ContractDef<T>>(\n def: D & StrictDef<T, D>,\n meta: ContractMeta = {},\n ): Contract<T, D> => {\n checkContractDef(spec, def);\n return makeContract(spec, def as D, meta);\n };\n return { spec, contract };\n}\n\n/**\n * The reflect-metadata polyfill's API, when it is loaded (a Nest application's\n * always is). This package neither imports nor types it: the structural view\n * keeps this module usable where the polyfill is absent.\n */\nconst reflectMeta = Reflect as unknown as {\n getMetadata?: (key: unknown, target: object) => unknown;\n defineMetadata?: (key: unknown, value: unknown, target: object) => void;\n};\n\n/**\n * Makes `contract` reachable from `target` through {@link getContract}: a\n * non-enumerable property, so code that enumerates the target sees nothing\n * new. Attaching again replaces it. Returns `target`, typed as carrying it.\n *\n * When the reflect-metadata polyfill is loaded, the contract is ALSO written\n * as metadata under the same symbol, so a framework that copies metadata when\n * it wraps a handler (NestJS's `RouterExplorer.copyMetadataToCallback`) keeps\n * it attached to the wrapper — without one, a Nest controller method's\n * contract would stay behind on the unwrapped method, invisible to\n * `listRoutes` and the document generators.\n *\n * @param target What carries the contract: a handler, a layer, a definition.\n * @param contract The contract to carry.\n */\nexport function attachContract<X extends object, C>(\n target: X,\n contract: C,\n): X & Carries<C> {\n Object.defineProperty(target, CONTRACT, {\n value: contract,\n enumerable: false,\n writable: false,\n configurable: true,\n });\n reflectMeta.defineMetadata?.(CONTRACT, contract, target);\n return target as X & Carries<C>;\n}\n\n/**\n * The contract `carrier` carries: typed when its type says which, otherwise\n * `AnyContract | undefined` (anything without one, primitives included).\n *\n * Reads the own property first, then — when the reflect-metadata polyfill is\n * loaded — the metadata under the same symbol (what a framework's metadata\n * copy carries onto a wrapped handler; see {@link attachContract}).\n *\n * @param carrier A handler, a layer, a definition, or a contract itself.\n */\nexport function getContract<C>(carrier: Carries<C>): C;\nexport function getContract(carrier: unknown): AnyContract | undefined;\nexport function getContract(carrier: unknown): unknown {\n if (\n (typeof carrier !== \"object\" && typeof carrier !== \"function\") ||\n carrier === null\n ) {\n return undefined;\n }\n return (\n (carrier as Partial<Carries<unknown>>)[CONTRACT] ??\n reflectMeta.getMetadata?.(CONTRACT, carrier)\n );\n}\n\n/**\n * Copies the contract `inner` carries onto `wrapper`, for middleware that\n * wraps another (`deferred(validate(schemas))`) and would otherwise hide its\n * contract from a route listing (plan §4.12 M5). A no-op when `inner` carries\n * none. Returns `wrapper`.\n *\n * @param wrapper The function or object registered in `inner`'s place.\n * @param inner What it wraps.\n */\nexport function forwardContract<W extends object, I>(\n wrapper: W,\n inner: I,\n): W & (I extends Carries<infer C> ? Carries<C> : unknown) {\n const contract = getContract(inner);\n if (contract !== undefined) attachContract(wrapper, contract);\n return wrapper as W & (I extends Carries<infer C> ? Carries<C> : unknown);\n}\n",
|
|
12
|
+
"/**\n * Guards: one compiled check per contract side, under one policy.\n *\n * A **receiver** parses, handing on each part's output; a **sender** checks\n * and hands back the very message it was given (plan §4.1.3). A guard\n * returns a {@link ContractError} rather than throwing, and is compiled once\n * with a plan per key, which keeps a side or key with no schema free: the\n * same message back, synchronously, with nothing allocated.\n */\nimport type { IssueFormat } from \"./issues\";\nimport type { ContractLogger } from \"./logger\";\nimport type { MediaMatcher } from \"./media\";\nimport type { ProtoKeyRule } from \"./protoKeys\";\nimport type {\n AnyContract,\n GuardOptions,\n IssueContext,\n MaybePromise,\n MediaMap,\n PartDecl,\n Policy,\n Received,\n Schema,\n Sent,\n Side,\n StandardOutcome,\n ValidationIssue,\n} from \"./model\";\nimport { runSchema } from \"./issues\";\nimport { resolveContractLogger } from \"./logger\";\nimport { compileMediaMap } from \"./media\";\nimport { variantsOf } from \"./model\";\nimport { checkProtoKeyRule, stripProtoKeys } from \"./protoKeys\";\nimport { isDocumented } from \"./schemas\";\nimport { isSchema } from \"./transport\";\n\n/** Raised (or returned by a guard) when a message fails its contract under `\"error\"`. */\nexport class ContractError extends Error {\n /** Every issue, value-free. */\n readonly issues: readonly ValidationIssue[];\n /** Where the issues were found. */\n readonly context: IssueContext;\n\n /**\n * @param issues The issues found; their messages and paths go into the\n * error's message, which therefore holds no received value either.\n * @param context Where they were found.\n */\n constructor(issues: readonly ValidationIssue[], context: IssueContext) {\n const where = `${context.transport} ${context.side}${context.key === undefined ? \"\" : ` ${context.key}`}`;\n const summary = issues\n .map((i) => `${i.target}${i.path ? `.${i.path}` : \"\"}: ${i.message}`)\n .join(\"; \");\n super(`${where} failed its contract: ${summary}`);\n this.name = \"ContractError\";\n this.issues = issues;\n this.context = context;\n }\n}\n\n/**\n * A compiled check of one side. A receiver's resolves to the parsed message\n * (each part's output); a sender's to the very message it was given, since\n * the sender's value is what goes on the wire. Either resolves to a\n * {@link ContractError} on a mismatch under `\"error\"`; it never throws one.\n */\nexport interface Guard<In, Out> {\n /** Checks `message`; synchronous when every schema it runs is. */\n (message: In): MaybePromise<Out | ContractError>;\n /**\n * `false` when the side has nothing to check (no schema, or `\"off\"`): the\n * guard is then the identity, and an adapter may skip the call.\n */\n readonly checks: boolean;\n /**\n * Whether a message with this key would be checked at all, so a router or\n * topic table can decide once per key, beside its handler, and skip the\n * guard where it is `false` (plan Q-C6). `true` for an undeclared key under\n * `undeclaredKey: \"report\"`; on an unkeyed side it is {@link checks}.\n */\n readonly checksKey: (key: string | number) => boolean;\n}\n\n/** The parts a message shape checks, in the order the contract declares them. */\ntype Plan = readonly (readonly [part: string, decl: PartDecl])[];\n\n/** Whether a part declaration does nothing at runtime: `documented()`, or a media map of only those. */\nfunction documentsOnly(decl: PartDecl): boolean {\n if (decl === null) return false;\n if (isSchema(decl)) return isDocumented(decl);\n const members = Object.values(decl);\n return members.length > 0 && members.every(isDocumented);\n}\n\n/** The parts of one message shape worth checking. */\nfunction toPlan(parts: object): Plan {\n return Object.entries(parts).filter(\n ([, decl]) => decl !== undefined && !documentsOnly(decl as PartDecl),\n ) as [string, PartDecl][];\n}\n\n/** A key in canonical integer form (`\"200\"`), which a message may also give as a number. */\nconst INTEGER_KEY = /^(?:0|[1-9]\\d*)$/;\n\n/** The guard of a side with nothing to check: returns its argument, allocates nothing. */\nconst identity: Guard<unknown, unknown> = Object.assign(\n (message: unknown): unknown => message,\n { checks: false, checksKey: (_key: string | number): boolean => false },\n);\n\n/** Each media map's compiled matcher, built on its first message. */\nconst MATCHERS = new WeakMap<MediaMap, MediaMatcher<Schema | null>>();\n\n/**\n * The declared entry a media type falls under (`lib/contract/media.ts`):\n * parameters stripped on both sides, case ignored, the most specific key\n * winning (exact, then `type/*`, then `*\\/*`).\n */\nfunction mediaEntry(\n map: MediaMap,\n mediaType: string,\n): [declared: string, schema: Schema | null] | undefined {\n let matcher = MATCHERS.get(map);\n if (matcher === undefined) {\n matcher = compileMediaMap<Schema | null>(map, \"contract media map\");\n MATCHERS.set(map, matcher);\n }\n const found = matcher.match(mediaType);\n return found === undefined ? undefined : [found[0].declared, found[1]];\n}\n\n/** The declared keys, for an undeclared-key message: never the key received. */\nfunction declaredList(keys: readonly string[]): string {\n const shown = keys.slice(0, 10).join(\", \");\n return keys.length > 10 ? `${shown}, …` : shown;\n}\n\n/**\n * Checks one part of a message. A receiver's part is what arrived, so its\n * prototype-pollution keys are stripped in place by `strip`'s rule before\n * the schema runs, as `validateStandard` does; a sender's (`strip`\n * `undefined`) is the owner's own message, handed back as given, so it is\n * never touched.\n */\nfunction checkPart(\n part: string,\n decl: PartDecl,\n value: unknown,\n key: string | number | undefined,\n format: IssueFormat,\n strip: ProtoKeyRule | undefined,\n): MaybePromise<StandardOutcome<unknown>> {\n if (decl === null) {\n if (value === undefined) return { ok: true, value };\n const issue: ValidationIssue = {\n target: part,\n message: `No ${part} is declared here`,\n path: \"\",\n };\n if (key !== undefined) issue.key = String(key);\n return { ok: false, issues: [issue] };\n }\n if (isSchema(decl)) {\n if (strip !== undefined) stripProtoKeys(value, strip);\n return runSchema(decl, value, part, key, undefined, format);\n }\n const media = value as { mediaType?: unknown; value?: unknown } | undefined;\n const found =\n typeof media?.mediaType === \"string\"\n ? mediaEntry(decl, media.mediaType)\n : undefined;\n if (found === undefined) {\n const issue: ValidationIssue = {\n target: part,\n message: `This media type is not declared (${Object.keys(decl).join(\", \")})`,\n path: \"\",\n };\n if (key !== undefined) issue.key = String(key);\n return { ok: false, issues: [issue] };\n }\n const [declared, schema] = found;\n if (schema === null) {\n // This media type is declared with no body.\n if (media!.value === undefined) return { ok: true, value };\n const issue: ValidationIssue = {\n target: part,\n message: `No ${part} is declared for this media type`,\n path: \"\",\n mediaType: declared,\n };\n if (key !== undefined) issue.key = String(key);\n return { ok: false, issues: [issue] };\n }\n if (strip !== undefined) stripProtoKeys(media!.value, strip);\n const outcome = runSchema(schema, media!.value, part, key, declared, format);\n const wrap = (o: StandardOutcome<unknown>): StandardOutcome<unknown> =>\n o.ok\n ? { ok: true, value: { mediaType: media!.mediaType, value: o.value } }\n : o;\n return outcome instanceof Promise ? outcome.then(wrap) : wrap(outcome);\n}\n\n/**\n * Throws a `TypeError` when the side declares a key (or, unkeyed, its one\n * shape) with variants (HTTP's `variants()`, plan §4.4.6): the guards do not\n * check variants yet, and passing such a message unchecked would be a silent\n * hole. `validate()`'s response gate checks them.\n */\nfunction refuseVariants(\n transport: string,\n side: Side,\n def: Record<string, object> | undefined,\n keyName: string | undefined,\n): void {\n if (def === undefined) return;\n const found =\n keyName === undefined\n ? variantsOf(def) === undefined\n ? undefined\n : \"\"\n : Object.keys(def).find((k) => variantsOf(def[k]) !== undefined);\n if (found === undefined) return;\n throw new TypeError(\n `${transport} ${side}${found === \"\" ? \"\" : ` ${keyName} ${JSON.stringify(found)}`} is declared with variants(), which the contract core's guards (createSender, createReceiver) do not check yet; HTTP's validate() checks them`,\n );\n}\n\n/** Compiles one side of `contract` into a guard. */\nfunction compile(\n contract: AnyContract,\n side: Side,\n options: GuardOptions,\n parse: boolean,\n): Guard<unknown, unknown> {\n const policy: Policy = options.policy ?? \"error\";\n const undeclaredKey = options.undeclaredKey ?? \"report\";\n const { onIssues } = options;\n // A receiver strips by this rule; a sender ignores it (it never strips),\n // though a value neither rule names is refused on either.\n const rule =\n checkProtoKeyRule(\n parse ? \"createReceiver()\" : \"createSender()\",\n options.stripProtoKeys,\n ) ?? \"nest\";\n const strip = parse ? rule : undefined;\n const format: IssueFormat = {\n ...(options.messages === undefined ? {} : { messages: options.messages }),\n ...(options.redactPaths === undefined\n ? {}\n : { redactPaths: options.redactPaths }),\n };\n const spec = contract.transport[side];\n const def = (contract.def as Partial<Record<Side, Record<string, object>>>)[\n side\n ];\n const keyName = spec?.key;\n refuseVariants(contract.transport.name, side, def, keyName);\n const single: Plan =\n def === undefined || keyName !== undefined ? [] : toPlan(def);\n\n // \"off\", no side declared, or an unkeyed side without schemas: nothing to do per message.\n if (\n policy === \"off\" ||\n spec === undefined ||\n def === undefined ||\n (keyName === undefined && single.length === 0)\n ) {\n return identity;\n }\n\n const plans = new Map<string | number, Plan>();\n const declaredKeys: string[] = [];\n if (keyName !== undefined) {\n for (const [k, parts] of Object.entries(def)) {\n const plan = toPlan(parts);\n plans.set(k, plan);\n if (INTEGER_KEY.test(k)) plans.set(Number(k), plan);\n declaredKeys.push(k);\n }\n // A keyed side whose every key is schema-free and whose undeclared keys\n // pass: nothing to do per message either.\n if (\n undeclaredKey === \"allow\" &&\n [...plans.values()].every((p) => p.length === 0)\n ) {\n return identity;\n }\n }\n\n const transport = contract.transport.name;\n let logger: ContractLogger | undefined;\n const log = (): ContractLogger =>\n (logger ??= resolveContractLogger(options.logger));\n\n const fail = (\n message: unknown,\n issues: ValidationIssue[],\n key: string | undefined,\n ): unknown => {\n const context: IssueContext =\n key === undefined\n ? { transport, side, policy }\n : { transport, side, key, policy };\n if (onIssues !== undefined) {\n try {\n onIssues(issues, context);\n } catch (error) {\n log().error(\"contract onIssues hook failed\", {\n transport,\n side,\n error,\n });\n }\n }\n if (policy === \"error\") return new ContractError(issues, context);\n log().warn(\"contract mismatch\", {\n transport,\n side,\n ...(key === undefined ? {} : { key }),\n issues: issues.map((i) => ({\n target: i.target,\n path: i.path,\n message: i.message,\n ...(i.key === undefined ? {} : { key: i.key }),\n ...(i.mediaType === undefined ? {} : { mediaType: i.mediaType }),\n })),\n });\n return message;\n };\n\n const finish = (\n message: unknown,\n plan: Plan,\n settled: readonly StandardOutcome<unknown>[],\n key: string | undefined,\n ): unknown => {\n let issues: ValidationIssue[] | undefined;\n for (const outcome of settled) {\n if (!outcome.ok) (issues ??= []).push(...outcome.issues);\n }\n if (issues !== undefined) return fail(message, issues, key);\n if (!parse) return message;\n const out: Record<string, unknown> =\n typeof message === \"object\" && message !== null\n ? { ...(message as Record<string, unknown>) }\n : {};\n for (let i = 0; i < plan.length; i++) {\n out[plan[i][0]] = (settled[i] as { value: unknown }).value;\n }\n return out;\n };\n\n const guard = (message: unknown): MaybePromise<unknown> => {\n const msg =\n typeof message === \"object\" && message !== null\n ? (message as Record<string, unknown>)\n : undefined;\n let plan = single;\n let rawKey: string | number | undefined;\n if (keyName !== undefined) {\n const given = msg?.[keyName];\n const found =\n typeof given === \"string\" || typeof given === \"number\"\n ? plans.get(given)\n : undefined;\n if (found === undefined) {\n if (undeclaredKey === \"allow\") return message;\n return fail(\n message,\n [\n {\n target: keyName,\n message: `This ${keyName} is not declared (${declaredList(declaredKeys)})`,\n path: \"\",\n },\n ],\n undefined,\n );\n }\n // A key with no schema: the same message back, nothing allocated.\n if (found.length === 0) return message;\n plan = found;\n rawKey = given as string | number;\n }\n const results: MaybePromise<StandardOutcome<unknown>>[] = Array.from({\n length: plan.length,\n });\n let pending = false;\n for (let i = 0; i < plan.length; i++) {\n const [part, decl] = plan[i];\n const result = checkPart(part, decl, msg?.[part], rawKey, format, strip);\n results[i] = result;\n pending ||= result instanceof Promise;\n }\n const key = rawKey === undefined ? undefined : String(rawKey);\n return pending\n ? Promise.all(results).then((settled) =>\n finish(message, plan, settled, key),\n )\n : finish(message, plan, results as StandardOutcome<unknown>[], key);\n };\n\n const checksKey =\n keyName === undefined\n ? (_key: string | number): boolean => true\n : (key: string | number): boolean => {\n const plan = plans.get(key);\n return plan === undefined\n ? undeclaredKey === \"report\"\n : plan.length > 0;\n };\n return Object.assign(guard, { checks: true, checksKey });\n}\n\n/**\n * Compiles a receiver for one side of `contract`: it **parses**, so what it\n * hands on carries each part's output (a `z.coerce.date()` arrives as a\n * `Date`).\n *\n * Under `\"error\"` (the default) a mismatch is a {@link ContractError}. Under\n * `\"warn\"` it is logged and the raw message handed on, and under `\"off\"`\n * nothing is checked, so with either (or a policy only known to be a\n * {@link Policy}) the receiver is typed to hand on `unknown` (plan Q-C1).\n * A side declaring a key with variants (HTTP's `variants()`) throws a\n * `TypeError` here: the guards do not check variants yet.\n *\n * @param contract The contract.\n * @param side The side its owner receives (`\"inbound\"` on a server).\n * @param options Policy, logger, `onIssues`, undeclared keys, issue wording.\n */\nexport function createReceiver<C extends AnyContract, Sd extends Side>(\n contract: C,\n side: Sd,\n options?: GuardOptions & {\n /** `\"error\"`, or left out: the receiver's output is typed as parsed. */\n policy?: \"error\";\n },\n): Guard<unknown, Received<C, Sd>>;\nexport function createReceiver<C extends AnyContract, Sd extends Side>(\n contract: C,\n side: Sd,\n options: GuardOptions,\n): Guard<unknown, unknown>;\nexport function createReceiver(\n contract: AnyContract,\n side: Side,\n options?: GuardOptions,\n): Guard<unknown, unknown> {\n return compile(contract, side, options ?? {}, true);\n}\n\n/**\n * Compiles a sender for one side of `contract`: it **checks**, and resolves\n * to the very message it was given, which is what goes on the wire. Its\n * input is typed by {@link Sent}: each field's input, or its output where\n * the input is `unknown`. Takes all three policies. A side declaring a key\n * with variants (HTTP's `variants()`) throws a `TypeError` here: the guards\n * do not check variants yet.\n *\n * @param contract The contract.\n * @param side The side its owner sends (`\"outbound\"` on a server).\n * @param options Policy, logger, `onIssues`, undeclared keys, issue wording.\n */\nexport function createSender<C extends AnyContract, Sd extends Side>(\n contract: C,\n side: Sd,\n options?: GuardOptions,\n): Guard<Sent<C, Sd>, Sent<C, Sd>> {\n return compile(contract, side, options ?? {}, false) as Guard<\n Sent<C, Sd>,\n Sent<C, Sd>\n >;\n}\n",
|
|
13
|
+
"/**\n * A WebSocket channel's pure contract half (bun-validate V8, plan\n * `docs/plans/bun-validate/` §4.6.1, §4.12 M7/m12): the `websocket`\n * transport (both sides keyed by `type`, one part `data`), the channel's\n * declaration shape, the frame shapes (the error frame included), and\n * `channelContract()`, building the contract the server binding\n * (bun-common's `defineChannel`, `lib/channel.ts` there) and a browser client share. Nothing\n * here imports a Bun or Node API, so this module is browser-safe.\n */\nimport type { StandardSchemaV1 } from \"./standardSchema\";\nimport type { AnyContract, Policy, ValidationIssue } from \"./model\";\nimport { documented } from \"./schemas\";\nimport { defineTransport } from \"./transport\";\n\n/* ------------------------------------------------------------------ *\n * The transport and the declaration\n * ------------------------------------------------------------------ */\n\n/**\n * The WebSocket transport: both sides keyed by the message's `type`, one\n * part, `data`. A channel's contract is declared with\n * {@link channelContract}; the transport is exported for documents'\n * and the typed client's reading of its spec.\n */\nexport const wsTransport = defineTransport({\n name: \"websocket\",\n inbound: { key: \"type\", parts: [\"data\"] },\n outbound: { key: \"type\", parts: [\"data\"] },\n});\n\n/**\n * The upgrade request's schemas (bun-common's `validate()` targets minus\n * `body`: an upgrade is a GET). Checked before the upgrade answers 101; a\n * failure answers the refusal and no socket opens.\n */\nexport type ChannelRequestSchemas = {\n readonly [\n P in \"params\" | \"query\" | \"headers\" | \"cookies\" | \"signedCookies\"\n ]?: StandardSchemaV1;\n};\n\n/** A channel's message map (`receives` or `sends`): message type to its data's schema, or `null` for no data. */\nexport type ChannelMessages = Readonly<Record<string, StandardSchemaV1 | null>>;\n\n/** What a channel carries beside its schemas (plan §4.12 M7): read by the typed client's channel model. */\nexport interface ChannelMeta {\n /** The route path the channel is served on. */\n readonly path: string;\n /**\n * The upgrade request's schemas, when declared (AD (e)): the contract's rows\n * carry only the messages, so a document generator reaches the checked\n * upgrade side (`params`/`query`/`headers`/`cookies`/`signedCookies`)\n * through here.\n */\n readonly request?: ChannelRequestSchemas;\n /** The envelope: the frame's correlation field, `\"id\"` by default. */\n readonly envelope: { readonly idField: string };\n /** An inbound type to the outbound type answering it, where one does. */\n readonly replies: Readonly<Record<string, string>>;\n /** Whether binary frames are accepted: the client may send the JSON envelope as a binary frame (decoded as UTF-8, checked like a text frame). Default `false`: a binary frame is an `UNSUPPORTED_DATA` error. */\n readonly binary: boolean;\n /** The subprotocol the upgrade answers, when one is set. */\n readonly subprotocol: string | undefined;\n /** The topics the channel publishes on, when declared. */\n readonly topics: readonly string[] | undefined;\n /** An SSE endpoint carrying the same messages, when one exists. */\n readonly fallback: string | undefined;\n}\n\n/** What {@link channelContract} takes (and {@link defineChannel}). */\nexport interface ChannelSpec {\n /** The route path the channel is served on. */\n readonly path: string;\n /** The upgrade request's schemas (checked before the 101). */\n readonly request?: ChannelRequestSchemas;\n /** Client → server messages, keyed by `type`; a `null` value means the message carries no data. */\n readonly receives: ChannelMessages;\n /** Server → client messages, keyed by `type`; the implicit `error` frame is added when none is declared. */\n readonly sends: ChannelMessages;\n /** The policies: `in` for received frames (default `\"error\"`), `out` for sent ones (default `\"error\"`). */\n readonly messageValidation?: { readonly in?: Policy; readonly out?: Policy };\n /** Close with `1007` on an invalid frame instead of answering it and staying open. Default `false`. */\n readonly closeOnInvalid?: boolean;\n /** Binary frames are accepted: the client may send the JSON envelope as a binary frame (decoded as UTF-8, checked like a text frame). Default `false`. */\n readonly binary?: boolean;\n /** The subprotocol the upgrade answers with. */\n readonly subprotocol?: string;\n /** The envelope's correlation field. Default `\"id\"`. */\n readonly envelope?: { readonly idField?: string };\n /** An inbound type to the outbound type answering it, where one does. */\n readonly replies?: Readonly<Record<string, string>>;\n /** The topics the channel publishes on, when declared. */\n readonly topics?: readonly string[];\n /** An SSE endpoint carrying the same messages, when one exists. */\n readonly fallback?: string;\n /** A stable name and prose for generated documents. */\n readonly meta?: { readonly name?: string; readonly description?: string };\n}\n\n/* ------------------------------------------------------------------ *\n * The frames\n * ------------------------------------------------------------------ */\n\n/** The wire envelope of a typed channel message. */\nexport interface ChannelMessage<T = string, D = unknown> {\n /** The message's type (the key of the channel's maps). */\n type: T;\n /** The correlation id, when the frame carries one. */\n id?: string;\n /** The message's data. */\n data?: D;\n}\n\n/** The error codes a channel answers with (Q10's shape). */\nexport type ChannelErrorCode =\n \"VALIDATION\" | \"UNKNOWN_MESSAGE\" | \"UNSUPPORTED_DATA\";\n\n/**\n * The error frame (plan §8.1 Q10): an invalid message is answered\n * `{ type: \"error\", id?, code: \"VALIDATION\", status: 400, issues }` (the\n * bun-jobs socket's shape plus the issues, value-free), an unknown message\n * type with `code: \"UNKNOWN_MESSAGE\"`, and a binary frame the channel did\n * not declare with `code: \"UNSUPPORTED_DATA\"`. The socket stays open, unless\n * the channel sets `closeOnInvalid` (then it closes with `1007`).\n */\nexport interface ChannelErrorFrame {\n /** `\"error\"`. */\n type: \"error\";\n /** The offending frame's id, echoed. */\n id?: string;\n /** What failed. */\n code: ChannelErrorCode;\n /** 400. */\n status: number;\n /** Every issue (value-free), for a `VALIDATION`. */\n issues?: readonly ValidationIssue[];\n /** What went wrong, for a non-validation error. */\n detail?: string;\n}\n\n/** The error frame for one issue list, or one detail. */\nexport function channelErrorFrame(\n code: ChannelErrorCode,\n body: { issues?: readonly ValidationIssue[]; detail?: string },\n id?: string,\n): ChannelErrorFrame {\n return {\n type: \"error\",\n ...(id === undefined ? {} : { id }),\n code,\n status: 400,\n ...(body.issues === undefined ? {} : { issues: body.issues }),\n ...(body.detail === undefined ? {} : { detail: body.detail }),\n };\n}\n\n/** The implicit `error` frame's payload, as JSON Schema (M6's `documented()`), for the declared outbound key. */\nconst ERROR_PAYLOAD_JSON = {\n type: \"object\",\n properties: {\n code: { enum: [\"VALIDATION\", \"UNKNOWN_MESSAGE\", \"UNSUPPORTED_DATA\"] },\n status: { type: \"integer\" },\n detail: { type: \"string\" },\n issues: { type: \"array\", items: { type: \"object\" } },\n },\n required: [\"code\", \"status\"],\n} as const;\n\n/* ------------------------------------------------------------------ *\n * The contract\n * ------------------------------------------------------------------ */\n\n/** A side's declaration normalized: each message type to its parts (`null` is `{ data: null }`, plan M7/P5). */\nfunction normalizeSide(\n messages: ChannelMessages,\n side: string,\n): Record<string, { data: StandardSchemaV1 | null }> {\n const out: Record<string, { data: StandardSchemaV1 | null }> = {};\n for (const [type, schema] of Object.entries(messages)) {\n if (schema !== null && !isStandardSchema(schema)) {\n throw new TypeError(\n `defineChannel(): the ${side} \"${type}\" must be a Standard Schema or null`,\n );\n }\n out[type] = { data: schema };\n }\n return out;\n}\n\n/** Whether `value` is a Standard Schema (has a `~standard.validate`). */\nfunction isStandardSchema(value: unknown): value is StandardSchemaV1 {\n if (\n (typeof value !== \"object\" && typeof value !== \"function\") ||\n value === null\n ) {\n return false;\n }\n const props = (value as { \"~standard\"?: { validate?: unknown } })[\n \"~standard\"\n ];\n return typeof props?.validate === \"function\";\n}\n\n/** A channel's contract: the `websocket` transport's, built from the spec, with the channel's meta (M7) and its spec carried. */\nexport interface ChannelContract<S extends ChannelSpec = ChannelSpec> {\n /** The contract (both sides of the `websocket` transport, the implicit `error` key declared). */\n readonly contract: AnyContract;\n /** The channel's meta (the typed client reads it). */\n readonly meta: ChannelMeta;\n /** The channel's spec, as declared. */\n readonly spec: S;\n}\n\n/**\n * Builds a channel's contract from its spec: both sides of the `websocket`\n * transport (each message type normalized to `{ data }`, a `null` entry\n * meaning no data), with the implicit `error` frame as a declared outbound\n * key (documents read it through `describeContract`), and the channel's meta\n * (M7) carried. Browser-safe; the server binding is bun-common's\n * `defineChannel`.\n *\n * @param spec The channel's declaration. A `receives`/`sends` entry that is\n * not a Standard Schema or `null` throws a `TypeError` here, at the\n * declaration.\n */\nexport function channelContract<const S extends ChannelSpec>(\n spec: S,\n): ChannelContract<S> {\n if (typeof spec?.path !== \"string\" || !spec.path.startsWith(\"/\")) {\n throw new TypeError(\n 'defineChannel(): \"path\" must be a route path (starting with \"/\")',\n );\n }\n const receives = normalizeSide(spec.receives, \"receives\");\n const sends = normalizeSide(spec.sends, \"sends\");\n if (!(\"error\" in sends)) {\n sends.error = { data: documented(ERROR_PAYLOAD_JSON) };\n }\n const meta: ChannelMeta = {\n path: spec.path,\n ...(spec.request === undefined ? {} : { request: spec.request }),\n envelope: { idField: spec.envelope?.idField ?? \"id\" },\n replies: spec.replies ?? {},\n binary: spec.binary === true,\n subprotocol: spec.subprotocol,\n topics: spec.topics,\n fallback: spec.fallback,\n };\n const contract = wsTransport.contract(\n { inbound: receives, outbound: sends },\n {\n name: spec.meta?.name ?? spec.path,\n description: spec.meta?.description,\n // The channel meta rides on the contract (AD (e)): `describeContract`'s\n // meta carries it, which is how the AsyncAPI generator reads the\n // upgrade side, replies, subprotocol, topics and SSE fallback of a\n // channel it finds through a route listing.\n channel: meta,\n },\n );\n return { contract, meta, spec };\n}\n",
|
|
14
|
+
"/**\n * HTTP, declared through the core (plan §4.1.1): one request shape, and\n * responses keyed by status, each with headers, cookies and a body keyed by\n * media type. `validate()` builds its contracts on it.\n *\n * The inbound parts are listed in the order BunValidate checks them\n * (headers first, so a cheap header check fails before a body is read);\n * `cookies` and `signedCookies` are declared for V2, which adds them as\n * `validate()` targets.\n */\nimport { defineTransport } from \"./transport\";\n\n/**\n * The HTTP transport. Its exported name is not approved (internal); reach a\n * validator's contract with `getContract(middleware)`.\n *\n * @internal\n */\nexport const httpTransport = defineTransport({\n name: \"http\",\n wire: \"json\",\n inbound: {\n parts: [\"headers\", \"cookies\", \"signedCookies\", \"params\", \"query\", \"body\"],\n media: [\"body\"],\n encodings: {\n headers: \"header-string\",\n cookies: \"cookie-string\",\n signedCookies: \"signed-cookie\",\n params: \"path-string\",\n query: \"querystring\",\n body: \"body\",\n },\n },\n outbound: {\n key: \"status\",\n parts: [\"headers\", \"cookies\", \"body\"],\n media: [\"body\"],\n encodings: {\n headers: \"header-string\",\n cookies: \"set-cookie\",\n body: \"body\",\n },\n },\n});\n",
|
|
15
|
+
"/**\n * Finding the keys a schema dropped: a value's own keys that its validated\n * output no longer has. zod's `z.object()` (and valibot's `object`, yup's\n * `stripUnknown`, arktype's `\"+\": \"delete\"`) strips every key it does not\n * declare and reports nothing, so a field a client sent, or a server added,\n * disappears without a trace. Comparing the input with the output finds them\n * whatever the vendor: used by bun-common's `validate({ unknownKeys })` and\n * bun-client's `validate.unknownKeys`.\n *\n * Internal: reachable by deep import only, not from the package's entry.\n */\n\n/** How deep {@link droppedKeys} walks before it stops looking. */\nconst MAX_DEPTH = 32;\n\n/** Whether `value` is a plain object: `{}` or `Object.create(null)`, not an array, a `Date` or a class instance. */\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== \"object\" || value === null) return false;\n const proto: unknown = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\n/** `key` appended to `path`, dot-joined as an issue's path is. */\nfunction join(path: string, key: string): string {\n return path === \"\" ? key : `${path}.${key}`;\n}\n\n/**\n * The paths (dot-joined, as an issue's `path`) of the keys `input` has and\n * `output` does not, walking both together through plain objects and\n * arrays: a key whose value is a plain object (or an array) in both is\n * looked into; a key missing from the output is reported once, without its\n * own keys. A value the schema replaced with something else (a transform to\n * a `Date`, a string, a class) is not looked into, and an output that is the\n * input itself drops nothing. At most `limit` paths are returned.\n *\n * @param input The value as it was given to the schema.\n * @param output The schema's output for it.\n * @param limit The most paths to return (default 20): a body with\n * thousands of unknown keys costs that many, not more.\n */\nexport function droppedKeys(\n input: unknown,\n output: unknown,\n limit = 20,\n): string[] {\n const found: string[] = [];\n const walk = (from: unknown, to: unknown, path: string, depth: number) => {\n if (from === to || depth > MAX_DEPTH || found.length >= limit) return;\n if (Array.isArray(from) && Array.isArray(to)) {\n const length = Math.min(from.length, to.length);\n for (let i = 0; i < length && found.length < limit; i++) {\n walk(from[i], to[i], join(path, String(i)), depth + 1);\n }\n return;\n }\n // The output must be a plain object (what a schema builds); the input\n // only an object, since a parsed query or a framework's body may carry a\n // prototype of its own.\n if (\n typeof from !== \"object\" ||\n from === null ||\n Array.isArray(from) ||\n !isPlainObject(to)\n ) {\n return;\n }\n const record = from as Record<string, unknown>;\n for (const key of Object.keys(record)) {\n if (found.length >= limit) return;\n if (!Object.hasOwn(to, key)) {\n found.push(join(path, key));\n } else {\n walk(record[key], to[key], join(path, key), depth + 1);\n }\n }\n };\n walk(input, output, \"\", 0);\n return found;\n}\n",
|
|
16
|
+
"/**\n * The checks (typed-client plan §5, PR-C4): the built-in schemas run through\n * bun-contract's guards, the very ones the server runs (D20, Q18), and BYO\n * schemas through its one runner, `validateStandard`. So a check on the\n * client and on the server agree on issue paths, value-free messages and\n * prototype-key stripping, by construction.\n *\n * **Loaded lazily.** `client.ts` imports this module with `import()` only\n * when a call has something to check, so a client with validation off (a\n * production default) never loads it, nor bun-contract, and a bundler that\n * splits puts both in their own chunk (`__tests__/budget.test.ts` measures\n * the two apart; `__tests__/bundleSafety.test.ts` proves the entry chunk\n * holds none of it).\n *\n * A request is the HTTP transport's inbound side, checked with a **sender**\n * (it hands back the message it was given, never touching it); a response is\n * the outbound side keyed by status, checked with a **receiver** (it strips\n * prototype-pollution keys from what arrived, as the server does from a\n * request). A built-in schema checks and changes nothing; a BYO schema's\n * output is what is sent or delivered (§5.4).\n */\nimport type {\n AnyContract,\n StandardOutcome,\n StandardSchemaV1,\n ValidationIssue,\n} from \"@kingsleyweb/bun-contract\";\nimport type {\n ClientError,\n ValidationError,\n ValidationErrorIssue,\n} from \"./errors\";\nimport type {\n FailureMode,\n PartValidation,\n RouteSchemas,\n SchemaSource,\n ValidationConfig,\n} from \"./types\";\nimport {\n channelContract,\n ContractError,\n createReceiver,\n createSender,\n validateStandard,\n} from \"@kingsleyweb/bun-contract\";\nimport { httpTransport } from \"@kingsleyweb/bun-contract/lib/http\";\nimport { droppedKeys } from \"@kingsleyweb/bun-contract/lib/unknownKeys\";\n\n// The runner, for `./sseChecks` (loaded with this module, by `./sse`), and\n// the guards and `channelContract` for `./channelChecks` (loaded the same\n// way, by `./channel`), so bun-contract's values are imported here alone.\nexport {\n channelContract,\n ContractError,\n createReceiver,\n createSender,\n validateStandard,\n};\n\n/** A request part the client checks. */\nexport type RequestPart = \"params\" | \"query\" | \"body\" | \"headers\" | \"files\";\n\n/** What runs for one part (or one response status), as the configuration resolved it. */\nexport interface PartPlan {\n /** Run the route's built-in schema for the part, when it has one. */\n readonly builtin: boolean;\n /** A BYO schema run after it. */\n readonly custom?: StandardSchemaV1;\n}\n\n/** A check's outcome: the values to send or deliver, and every issue found. */\nexport interface Checked<T> {\n /** The values: as given, except where a BYO schema passed (its output). */\n readonly value: T;\n /** Every issue, the built-in ones first; empty when everything passed. */\n readonly issues: readonly ValidationErrorIssue[];\n}\n\n/**\n * A compiled guard as this module calls it: a message in, the message (a\n * receiver's parsed) or a `ContractError` out, maybe asynchronously.\n */\ntype Check = (message: Record<string, unknown>) => unknown;\n\n/** The guards compiled for one route's schemas, by the parts or status they check. */\nconst GUARDS = new WeakMap<RouteSchemas, Map<string, Check>>();\n\n/** The guard for `id` of `route`, compiled once by `build`. */\nfunction cached(route: RouteSchemas, id: string, build: () => Check): Check {\n let byId = GUARDS.get(route);\n if (byId === undefined) {\n byId = new Map();\n GUARDS.set(route, byId);\n }\n let guard = byId.get(id);\n if (guard === undefined) {\n guard = build();\n byId.set(id, guard);\n }\n return guard;\n}\n\n/** The HTTP contract of `def`, built through the server's own transport. */\nfunction contractOf(def: object): AnyContract {\n return httpTransport.contract(def as never);\n}\n\n/**\n * A guard's issues, marked as the built-in schema's, with a response's\n * `body` target named `response` (its `headers` keep theirs).\n */\nexport function builtinIssues(\n issues: readonly ValidationIssue[],\n response: boolean,\n): ValidationErrorIssue[] {\n return issues.map((issue) => ({\n ...issue,\n target: (response && issue.target === \"body\"\n ? \"response\"\n : issue.target) as ValidationErrorIssue[\"target\"],\n source: \"builtin\",\n }));\n}\n\n/**\n * A route's schema for a body, as a guard checks it: a bun-common `chunks()`\n * declaration (a server's own module may hold one) is its chunk schema, so\n * a streamed NDJSON status is checked line by line against it.\n */\nfunction bodySchema(schema: StandardSchemaV1 | null): StandardSchemaV1 | null {\n const declared = schema as { kind?: unknown; chunk?: unknown } | null;\n return declared !== null &&\n declared.kind === \"chunks\" &&\n typeof declared.chunk === \"object\" &&\n declared.chunk !== null &&\n \"~standard\" in declared.chunk\n ? (declared.chunk as StandardSchemaV1)\n : schema;\n}\n\n/** A BYO schema's issues, marked as such. */\nexport function customIssues(\n issues: readonly ValidationIssue[],\n): ValidationErrorIssue[] {\n return issues.map((issue) => ({\n ...issue,\n target: issue.target as ValidationErrorIssue[\"target\"],\n source: \"custom\",\n }));\n}\n\n/**\n * Checks request parts (§5.4): the built-in schemas of the parts whose plan\n * asks for them, all at once through one sender (the files, which the HTTP\n * transport has no part for, through the same runner on their own), then\n * each part's BYO schema, on the value as given (a sender's output is its\n * input). A BYO schema that passes replaces its part's value with its\n * output.\n *\n * @param route The route's built-in schemas; `undefined` when it has none.\n * @param plans What runs, per part; a part not listed is not checked.\n * @param values The parts' values, as the call gives them.\n */\nexport async function checkRequest(\n route: RouteSchemas | undefined,\n plans: Partial<Record<RequestPart, PartPlan>>,\n values: Partial<Record<RequestPart, unknown>>,\n): Promise<Checked<Partial<Record<RequestPart, unknown>>>> {\n const parts = Object.keys(plans) as RequestPart[];\n const issues: ValidationErrorIssue[] = [];\n const builtin = parts.filter(\n (part) =>\n part !== \"files\" && plans[part]!.builtin && route?.[part] !== undefined,\n );\n if (route !== undefined && builtin.length > 0) {\n const guard = cached(\n route,\n `request:${builtin.join(\",\")}`,\n () =>\n createSender(\n contractOf({\n inbound: Object.fromEntries(\n builtin.map((part) => [part, route[part]]),\n ),\n }),\n \"inbound\",\n ) as unknown as Check,\n );\n const message = Object.fromEntries(\n builtin.map((part) => [part, values[part]]),\n );\n const outcome = await guard(message);\n if (outcome instanceof ContractError)\n issues.push(...builtinIssues(outcome.issues, false));\n }\n if (plans.files?.builtin === true && route?.files !== undefined) {\n const result: StandardOutcome<unknown> = await validateStandard(\n route.files,\n values.files,\n \"files\",\n );\n if (!result.ok) issues.push(...builtinIssues(result.issues, false));\n }\n const out = { ...values };\n for (const part of parts) {\n const custom = plans[part]!.custom;\n if (custom === undefined) continue;\n const result: StandardOutcome<unknown> = await validateStandard(\n custom,\n values[part],\n part,\n );\n if (result.ok) out[part] = result.value;\n else issues.push(...customIssues(result.issues));\n }\n return { value: out, issues };\n}\n\n/** What a response check runs (§5.4–§5.6): the body's plan, and whether the built-in headers schema runs. */\nexport interface ResponsePlan extends PartPlan {\n /** Run the status's built-in headers schema, when it has one. */\n readonly headers: boolean;\n}\n\n/** What a response check is given: the body, the headers, or both. */\nexport interface ResponseInput {\n /** Check the body (`false` for one left unread, or the headers alone). */\n readonly checkBody: boolean;\n /** The body as the client read it (JSON parsed, text, …). */\n readonly body?: unknown;\n /** The headers as they arrived, by lower-case name; `undefined` leaves them unchecked (an NDJSON line). */\n readonly headers?: Readonly<Record<string, string>>;\n}\n\n/**\n * Checks a response (§5.4–§5.6): the status's built-in schemas, its\n * declared headers and its body, through one receiver (which strips\n * prototype-pollution keys from the body in place), then the BYO schema,\n * on the body, on the built-in schema's output when that passed and on the\n * body when it failed. A BYO schema that passes makes its output the value\n * delivered; otherwise the body is delivered as it arrived. Headers are\n * checked, never changed.\n *\n * @param route The route's built-in schemas; `undefined` when it has none.\n * @param status The response's status.\n * @param plan What runs for this status.\n * @param input The body and the headers, and which of them to check.\n */\nexport async function checkResponse(\n route: RouteSchemas | undefined,\n status: number,\n plan: ResponsePlan,\n input: ResponseInput,\n): Promise<Checked<unknown>> {\n const issues: ValidationErrorIssue[] = [];\n let parsed: { ok: true; value: unknown } | undefined;\n const body =\n input.checkBody && plan.builtin && route?.responses?.[status] !== undefined;\n const headers =\n input.headers !== undefined &&\n plan.headers &&\n route?.responseHeaders?.[status] !== undefined;\n if (route !== undefined && (body || headers)) {\n const guard = cached(\n route,\n `response:${body ? \"body\" : \"\"}:${headers ? \"headers\" : \"\"}`,\n () => {\n const statuses = new Set([\n ...(body ? Object.keys(route.responses ?? {}) : []),\n ...(headers ? Object.keys(route.responseHeaders ?? {}) : []),\n ]);\n return createReceiver(\n contractOf({\n outbound: Object.fromEntries(\n [...statuses].map((code) => {\n const parts: Record<string, unknown> = {};\n const declared = route.responseHeaders?.[Number(code)];\n if (headers && declared !== undefined) parts.headers = declared;\n const schema = route.responses?.[Number(code)];\n if (body && schema !== undefined)\n parts.body = bodySchema(schema);\n return [code, parts];\n }),\n ),\n }),\n \"outbound\",\n { undeclaredKey: \"allow\" },\n );\n },\n );\n const message: Record<string, unknown> = { status };\n if (headers) message.headers = { ...input.headers };\n if (body) message.body = input.body;\n const outcome = await guard(message);\n if (outcome instanceof ContractError)\n issues.push(...builtinIssues(outcome.issues, true));\n else if (body)\n parsed = { ok: true, value: (outcome as { body: unknown }).body };\n }\n let value = input.body;\n if (input.checkBody && plan.custom !== undefined) {\n const result: StandardOutcome<unknown> = await validateStandard(\n plan.custom,\n parsed === undefined ? input.body : parsed.value,\n \"response\",\n String(status),\n undefined,\n { stripProtoKeys: \"nest\" },\n );\n if (result.ok) value = result.value;\n else issues.push(...customIssues(result.issues));\n }\n return { value, issues };\n}\n\n/**\n * One part a BYO schema checked: its name (`\"query\"`, `\"body\"`,\n * `\"response\"`), what the schema was given, and its output (falsy when no\n * BYO schema ran: nothing to review).\n */\ntype Reviewed = readonly [\n target: ValidationErrorIssue[\"target\"],\n input: unknown,\n output: unknown,\n];\n\n/**\n * `validate.unknownKeys` (`ValidationConfig.unknownKeys`): reviews BYO\n * schemas' outputs against what they were given (bun-contract's\n * `droppedKeys`): under `\"warn\"` logs the keys each dropped\n * (`<call>: the custom <target> schema dropped keys: a, b.c`); under\n * `\"reject\"` adds an `Unrecognized key` issue per key to `issues`.\n *\n * @param mode `\"warn\"` or `\"reject\"`.\n * @param call The route key, for the warning.\n * @param status The response's status, as the issues' `key`; `undefined` for a request part.\n * @param issues The call's issues so far, returned as they are when nothing is added.\n * @param logger Where `\"warn\"` writes.\n * @param parts The parts to review.\n */\nfunction reviewDropped(\n mode: \"warn\" | \"reject\",\n call: string,\n status: number | undefined,\n issues: readonly ValidationErrorIssue[],\n logger: Pick<Console, \"warn\">,\n ...parts: Reviewed[]\n): readonly ValidationErrorIssue[] {\n const found: ValidationErrorIssue[] = [];\n for (const [target, input, output] of parts) {\n // A schema that failed hands back its input: nothing was dropped.\n const paths = output ? droppedKeys(input, output) : [];\n if (paths.length === 0) continue;\n if (mode === \"warn\") {\n logger.warn(\n `${call}: the custom ${target} schema dropped keys: ${paths.join(\", \")}`,\n );\n continue;\n }\n for (const path of paths)\n found.push({\n target,\n message: \"Unrecognized key\",\n path,\n source: \"custom\",\n ...(status === undefined ? {} : { key: String(status) }),\n });\n }\n return found.length === 0 ? issues : [...issues, ...found];\n}\n\n/* ------------------------------------------------------------------------ */\n/* The configuration (§6.2), resolved per call. */\n/* ------------------------------------------------------------------------ */\n\n/** The request parts, in the order they are checked and reported. */\nconst REQUEST_PARTS: readonly RequestPart[] = [\n \"params\",\n \"query\",\n \"body\",\n \"headers\",\n \"files\",\n];\n\n/** One part's (or one status's) validation, as the levels resolved it. */\ninterface PartState {\n /** Run the built-in schema. */\n enabled: boolean;\n /** The BYO schema, run after it. */\n custom: StandardSchemaV1 | undefined;\n /** Run only the BYO schema. */\n replace: boolean;\n}\n\n/** One call's validation, every level merged. */\ninterface ResolvedValidation {\n /** Each request part's. */\n parts: Record<RequestPart, PartState>;\n /** Every response status's, unless {@link statuses} has its own. */\n response: PartState;\n /** Per-status settings. */\n statuses: Map<number, PartState>;\n /** What a request failure does. */\n onRequest: FailureMode;\n /** What a response failure does. */\n onResponse: FailureMode;\n /** The keys a BYO schema dropped: looked for unless `\"strip\"`. */\n unknownKeys: \"strip\" | \"warn\" | \"reject\";\n}\n\n/** A part turned off: nothing runs, BYO included. */\nconst offState = (): PartState => ({\n enabled: false,\n custom: undefined,\n replace: false,\n});\n\n/** Applies one level's entry for a part (§6.2): `true` on, `false` off, an object per key. */\nfunction applyPart(state: PartState, entry: PartValidation | undefined): void {\n if (entry === undefined) return;\n if (entry === false) {\n Object.assign(state, offState());\n return;\n }\n if (entry === true) {\n state.enabled = true;\n return;\n }\n if (entry.enabled !== undefined) state.enabled = entry.enabled;\n if (entry.custom !== undefined) state.custom = entry.custom;\n if (entry.replace !== undefined) state.replace = entry.replace;\n}\n\n/**\n * Merges the validation levels (client, route, call) over the mode's\n * defaults: per key, later winning; a `false` turns everything under it\n * off until a later level turns it back on.\n */\nfunction resolveValidation(\n development: boolean,\n levels: readonly (ValidationConfig | false | undefined)[],\n): ResolvedValidation {\n const fresh = (): PartState => ({\n enabled: development,\n custom: undefined,\n replace: false,\n });\n const out: ResolvedValidation = {\n parts: {\n params: fresh(),\n query: fresh(),\n body: fresh(),\n headers: fresh(),\n files: fresh(),\n },\n response: fresh(),\n statuses: new Map(),\n onRequest: \"throw\",\n onResponse: \"warn\",\n unknownKeys: \"strip\",\n };\n for (const level of levels) {\n if (level === undefined) continue;\n if (level === false) {\n for (const part of REQUEST_PARTS) out.parts[part] = offState();\n out.response = offState();\n out.statuses.clear();\n continue;\n }\n if (level.request !== undefined)\n for (const part of REQUEST_PARTS)\n applyPart(out.parts[part], level.request);\n for (const part of REQUEST_PARTS) applyPart(out.parts[part], level[part]);\n const response = level.response;\n if (typeof response === \"boolean\") {\n applyPart(out.response, response);\n for (const state of out.statuses.values()) applyPart(state, response);\n } else if (response !== undefined) {\n for (const [code, entry] of Object.entries(response)) {\n const status = Number(code);\n const state = out.statuses.get(status) ?? { ...out.response };\n applyPart(state, entry);\n out.statuses.set(status, state);\n }\n }\n if (level.unknownKeys !== undefined) out.unknownKeys = level.unknownKeys;\n const failure = level.onFailure;\n if (typeof failure === \"string\" || typeof failure === \"function\") {\n out.onRequest = failure;\n out.onResponse = failure;\n } else if (failure !== undefined) {\n if (failure.request !== undefined) out.onRequest = failure.request;\n if (failure.response !== undefined) out.onResponse = failure.response;\n }\n }\n return out;\n}\n\n/** What runs for a part, when anything does: the built-in schema (if there is a source) and the BYO one. */\nfunction planOf(state: PartState, schemas: boolean): PartPlan | undefined {\n const builtin = schemas && state.enabled && !state.replace;\n if (!builtin && state.custom === undefined) return undefined;\n return state.custom === undefined\n ? { builtin }\n : { builtin, custom: state.custom };\n}\n\n/**\n * What runs for a response status, when anything does: the body's plan, and\n * the built-in headers schema, which `replace` leaves on (it replaces the\n * body's built-in schema, the one a BYO schema stands in for).\n */\nfunction responsePlanOf(\n state: PartState,\n schemas: boolean,\n): ResponsePlan | undefined {\n const body = planOf(state, schemas);\n const headers = schemas && state.enabled;\n if (body === undefined && !headers) return undefined;\n return body === undefined\n ? { builtin: false, headers }\n : { ...body, headers };\n}\n\n/** A `Headers`' entries as an object, by lower-case name. */\nfunction headersObject(headers: Headers): Record<string, string> {\n const out: Record<string, string> = {};\n headers.forEach((value, name) => {\n out[name] = value;\n });\n return out;\n}\n\n/* ------------------------------------------------------------------------ */\n/* The checks a client runs. */\n/* ------------------------------------------------------------------------ */\n\n/** What checks an event stream's events (`CallChecks.events`). */\nexport interface EventsPlan {\n /** What runs for the stream's status. */\n readonly plan: PartPlan;\n /** The route's built-in schemas; `undefined` when the plan runs none. */\n readonly route: RouteSchemas | undefined;\n /** What a failure does, as the levels resolved it (`sse()` adds `\"drop\"`). */\n readonly mode: FailureMode | \"drop\";\n}\n\n/** What `createClient` hands the checks when it first loads them. */\nexport interface ChecksContext {\n /** The client's mode is development (its defaults turn checks on). */\n readonly development: boolean;\n /** The built-in schemas' source, as configured. */\n readonly source:\n | SchemaSource<Record<string, unknown>>\n | (() => Promise<SchemaSource<Record<string, unknown>>>)\n | undefined;\n /** Where `\"warn\"` writes. */\n readonly logger: Pick<Console, \"warn\">;\n /**\n * The error classes, handed over rather than imported, so a bundler that\n * splits keeps `./errors` in the entry chunk alone instead of moving it to\n * a chunk both load.\n */\n readonly errors: {\n /** {@link ClientError}. */\n readonly ClientError: typeof ClientError;\n /** {@link ValidationError}. */\n readonly ValidationError: typeof ValidationError;\n };\n}\n\n/** One call's checks: the request parts, the headers as sent, and the response. */\nexport interface CallChecks {\n /**\n * Checks the params, query, body and files before anything is built (§5.4):\n * resolves to the options to send (a passing BYO schema's output in its\n * part's place), or rejects under `\"throw\"`. A `raw` body (a `FormData`,\n * `URLSearchParams`, `Blob`, buffer or stream, which passes through as it\n * is) is not checked, nor are the files (a `FormData` carries its own).\n */\n readonly request: <\n O extends {\n params?: unknown;\n query?: unknown;\n body?: unknown;\n files?: unknown;\n },\n >(\n options: O,\n raw: boolean,\n ) => Promise<O>;\n /** Checks the headers as sent, on the first attempt; `undefined` when nothing checks them. */\n readonly headers: ((request: Request) => Promise<void>) | undefined;\n /**\n * Checks a declared status's body (§5.5), and its headers (§5.6) when\n * they are given: resolves to what to deliver, or rejects under\n * `\"throw\"`. An NDJSON line is checked without them.\n */\n readonly response: (\n status: number,\n body: unknown,\n headers?: Headers,\n ) => Promise<unknown>;\n /**\n * Checks a declared status's headers alone (§5.6), for a body left unread\n * (a stream, or a download as `\"stream\"`): resolves, or rejects under\n * `\"throw\"`.\n */\n readonly responseHeaders: (status: number, headers: Headers) => Promise<void>;\n /**\n * What checks an event stream's events (`sse.md` §3.3), as the stream's\n * status says: the plan, the route's built-in schemas (loaded when the\n * plan runs them) and the failure mode; `undefined` when nothing checks\n * them. `./sseChecks` runs the checks, so an HTTP-only client's checks\n * carry none of that code.\n */\n readonly events: (status: number) => Promise<EventsPlan | undefined>;\n}\n\n/** The checks of one client: each call's, from its route key and its validation levels. */\nexport type Checks = (\n key: string,\n levels: readonly (ValidationConfig | false | undefined)[],\n) => CallChecks;\n\n/**\n * Builds a client's checks: the schema source, loaded on first use (a\n * failed load is retried by the next call), and the failure modes.\n */\nexport function createChecks(context: ChecksContext): Checks {\n const { source, logger } = context;\n const { ClientError, ValidationError } = context.errors;\n const hasSource = source !== undefined;\n let loaded:\n Promise<Readonly<Record<string, RouteSchemas | undefined>>> | undefined;\n const loadSchemas = (\n key: string,\n ): Promise<Readonly<Record<string, RouteSchemas | undefined>>> => {\n loaded ??= (async () => {\n let module: SchemaSource<Record<string, unknown>> | undefined;\n try {\n module = typeof source === \"function\" ? await source() : source;\n } catch (error) {\n loaded = undefined;\n throw new ClientError(`${key}: the built-in schemas failed to load`, {\n key,\n cause: error,\n });\n }\n const schemas = (module as { schemas?: unknown } | undefined)?.schemas;\n if (typeof schemas !== \"object\" || schemas === null) {\n loaded = undefined;\n throw new ClientError(\n `${key}: the schema source has no \\`schemas\\` object (a module generated by \\`bun-client generate --zod\\` exports one)`,\n { key },\n );\n }\n return schemas as Readonly<Record<string, RouteSchemas | undefined>>;\n })();\n return loaded;\n };\n\n /** The route's built-in schemas, when a plan runs one. */\n const routeOf = async (\n key: string,\n plans: readonly PartPlan[],\n ): Promise<RouteSchemas | undefined> =>\n plans.some((plan) => plan.builtin)\n ? (await loadSchemas(key))[key]\n : undefined;\n\n /** The route's built-in schemas, when a response plan runs one (its headers' only when they are given). */\n const responseRouteOf = async (\n key: string,\n plan: ResponsePlan,\n headers: boolean,\n ): Promise<RouteSchemas | undefined> =>\n plan.builtin || (headers && plan.headers)\n ? (await loadSchemas(key))[key]\n : undefined;\n\n /** Applies a failure mode: throws, warns, or calls the hook. */\n const failed = (mode: FailureMode, error: ValidationError): void => {\n if (mode === \"throw\") throw error;\n if (mode === \"warn\") logger.warn(error.message);\n else mode(error);\n };\n\n return (key, levels) => {\n const validation = resolveValidation(context.development, levels);\n const headersPlan = planOf(validation.parts.headers, hasSource);\n return {\n request: async (options, raw) => {\n const plans: Partial<Record<RequestPart, PartPlan>> = {};\n for (const part of [\"params\", \"query\", \"body\", \"files\"] as const) {\n // A pre-built body carries its own fields and files.\n if (raw && (part === \"body\" || part === \"files\")) continue;\n const plan = planOf(validation.parts[part], hasSource);\n if (plan !== undefined) plans[part] = plan;\n }\n const list = Object.values(plans);\n if (list.length === 0) return options;\n // The server sees an absent params or query as an empty object.\n const checked = await checkRequest(await routeOf(key, list), plans, {\n params: options.params ?? {},\n query: options.query ?? {},\n body: options.body,\n files: options.files ?? {},\n });\n const value = checked.value;\n let issues = checked.issues;\n if (validation.unknownKeys !== \"strip\")\n issues = reviewDropped(\n validation.unknownKeys,\n key,\n undefined,\n issues,\n logger,\n [\"query\", options.query, plans.query?.custom && value.query],\n [\"body\", options.body, plans.body?.custom && value.body],\n );\n if (issues.length > 0)\n failed(\n validation.onRequest,\n new ValidationError(key, \"request\", issues),\n );\n const out: Record<string, unknown> = { ...options };\n for (const part of Object.keys(plans))\n out[part] = value[part as RequestPart];\n return out as typeof options;\n },\n headers:\n headersPlan === undefined\n ? undefined\n : async (request) => {\n const { issues } = await checkRequest(\n await routeOf(key, [headersPlan]),\n { headers: headersPlan },\n { headers: headersObject(request.headers) },\n );\n if (issues.length > 0)\n failed(\n validation.onRequest,\n new ValidationError(key, \"request\", issues),\n );\n },\n response: async (status, body, headers) => {\n const plan = responsePlanOf(\n validation.statuses.get(status) ?? validation.response,\n hasSource,\n );\n if (plan === undefined) return body;\n const checked = await checkResponse(\n await responseRouteOf(key, plan, headers !== undefined),\n status,\n plan,\n {\n checkBody: true,\n body,\n ...(headers === undefined\n ? {}\n : { headers: headersObject(headers) }),\n },\n );\n const value = checked.value;\n let issues = checked.issues;\n if (validation.unknownKeys !== \"strip\")\n issues = reviewDropped(\n validation.unknownKeys,\n key,\n status,\n issues,\n logger,\n [\"response\", body, plan.custom && value],\n );\n if (issues.length > 0) {\n failed(\n validation.onResponse,\n new ValidationError(key, \"response\", issues, status),\n );\n return body;\n }\n return value;\n },\n responseHeaders: async (status, headers) => {\n const plan = responsePlanOf(\n validation.statuses.get(status) ?? validation.response,\n hasSource,\n );\n if (plan === undefined || !plan.headers) return;\n const { issues } = await checkResponse(\n await responseRouteOf(key, plan, true),\n status,\n plan,\n { checkBody: false, headers: headersObject(headers) },\n );\n if (issues.length > 0)\n failed(\n validation.onResponse,\n new ValidationError(key, \"response\", issues, status),\n );\n },\n events: async (status) => {\n const plan = planOf(\n validation.statuses.get(status) ?? validation.response,\n hasSource,\n );\n return plan === undefined\n ? undefined\n : {\n plan,\n route: await routeOf(key, [plan]),\n mode: validation.onResponse as FailureMode | \"drop\",\n };\n },\n };\n };\n}\n"
|
|
17
|
+
],
|
|
18
|
+
"mappings": "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",
|
|
19
|
+
"debugId": "00CD9124281B829264756E2164756E21",
|
|
20
|
+
"names": []
|
|
21
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{G,K,tr,nr,N,n,e,t,f,Fe,ie,Te,E,ot,zt,o,h,u,I}from"./main-a250ffk7.js";import{Ie,A}from"./main-0jmeh6mq.js";import{F}from"./main-pegp0ygb.js";class j extends Error{key;constructor(r,O={}){super(r,{cause:O.cause});this.name="ClientError",this.key=O.key}}class Ht extends j{status;error;response;constructor(r,O,s,D){super(`HTTP ${r} from ${D??s.url}`,{key:D});this.name="HttpError",this.status=r,this.error=O,this.response=s}}class X extends j{status;declared;response;constructor(r,O,s){super(`${s??r.url} answered ${r.status}, which it does not declare (declared: ${O.join(", ")})`,{key:s});this.name="UnexpectedStatusError",this.status=r.status,this.declared=O,this.response=r}}class Ge extends j{constructor(r,O={}){super(r,O);this.name="NetworkError"}}class Gt extends j{timeout;constructor(r,O){super(`${O??"Request"} timed out after ${r} ms`,{key:O});this.name="TimeoutError",this.timeout=r}}class Qe extends j{direction;status;issues;constructor(r,O,s,D){let i=s.map((_)=>`${_.target}${_.path?`.${_.path}`:""}: ${_.message}`).join("; ");super(`${r} ${O==="response"?`response ${D}`:O} failed validation: ${i}`,{key:r});this.name="ValidationError",this.direction=O,this.status=D,this.issues=s}}class jn extends j{code;status;issues;detail;type;constructor(r,O,s){super(`${r}${s===void 0?"":` ${s}`}: the server answered ${O.code}${O.detail===void 0?"":` (${O.detail})`}`,{key:r});this.name="ChannelError",this.code=O.code,this.status=O.status,this.issues=O.issues??[],this.detail=O.detail,this.type=s}}class Cr extends j{type;id;timeout;constructor(r,O,s,D){super(`${r} ${O}: no reply within ${D} ms`,{key:r});this.name="RequestTimeoutError",this.type=O,this.id=s,this.timeout=D}}class Lr extends j{code;reason;constructor(r,O,s){super(`${r}: the socket closed (${O}${s?` ${s}`:""}) before the reply`,{key:r});this.name="DisconnectedError",this.code=O,this.reason=s}}class Qt extends j{code;reason;constructor(r,O,s){super(`${r}: ${O}${s===void 0?"":` (${s})`}`,{key:r});this.name="ChannelClosedError",this.code=s,this.reason=O}}var Er=/^[$_\p{ID_Start}]$/u,Nr=/^[$\u200C\u200D\p{ID_Continue}]$/u,Se=new Map;function sr(r,O){if(r[O]==='"'){let D="",i=O+1;while(i<r.length&&r[i]!=='"'){if(r[i]==="\\")i++;D+=r[i]??"",i++}return[D,i+1]}let s=O;if(Er.test(r[s]??""))do s++;while(Nr.test(r[s]??""));return[r.slice(O,s),s]}function Dr(r,O){let s=0,D=O;do{if(r[D]==="\\")D++;else if(r[D]==="(")s++;else if(r[D]===")")s--;D++}while(s>0&&D<r.length);return D}function ge(r,O=0){let s=[],D="",i=()=>{if(D)s.push({kind:"text",value:D});D=""};while(O<r.length){let _=r[O];if(_==="\\")D+=r[O+1]??"",O+=2;else if(_==="}")return i(),[s,O+1];else if(_==="{"){i();let[m,V]=ge(r,O+1);s.push({kind:"group",tokens:m}),O=V}else if(_===":"||_==="*"){let[m,V]=sr(r,O+1);if(!m){D+=_,O++;continue}if(i(),O=V,_==="*"){s.push({kind:"wildcard",name:m});continue}if(r[O]==="(")O=Dr(r,O);let v=r[O]==="?";if(v){O++;let Y=s.at(-1);if(Y?.kind==="text"&&Y.value.endsWith("/")){if(Y.value=Y.value.slice(0,-1),!Y.value)s.pop();s.push({kind:"group",tokens:[{kind:"text",value:"/"},{kind:"param",name:m,optional:!1}]});continue}}s.push({kind:"param",name:m,optional:v})}else D+=_,O++}return i(),[s,O]}function Ve(r){return encodeURIComponent(String(r))}function fe(r,O){let s="",D=[];for(let i of r)if(i.kind==="text")s+=i.value;else if(i.kind==="group"){let[_,m]=fe(i.tokens,O);if(!m.length)s+=_}else{let _=Object.hasOwn(O,i.name)?O[i.name]:void 0;if(_===void 0||_===null){if(!(i.kind==="param"&&i.optional))D.push(i.name);continue}if(i.kind==="wildcard"){let m=Array.isArray(_)?_:[_];if(!m.length){D.push(i.name);continue}s+=m.map(Ve).join("/")}else s+=Ve(_)}return[s,D]}function Ce(r,O={},s){let D=Se.get(r);if(!D)D=ge(r)[0],Se.set(r,D);let[i,_]=fe(D,O);if(_.length)throw new j(`Missing path param${_.length>1?"s":""} ${_.map((m)=>`"${m}"`).join(", ")} for ${r}`,{key:s});return i}var Me=new Set(["__proto__","constructor","prototype"]);function Je(r){return encodeURIComponent(r).replace(/\./g,"%2E")}function ye(r){switch(typeof r){case"string":return r;case"number":case"boolean":case"bigint":return String(r)}if(r instanceof Date)return r.toISOString();return}function te(r,O,s){if(s===void 0||s===null)return;let D=ye(s);if(D!==void 0){r.push([O,D]);return}if(Array.isArray(s)){let i=s.filter((m)=>m!==void 0&&m!==null);if(i.every((m)=>ye(m)!==void 0)&&i.length>1)for(let m of i)te(r,O,m);else i.forEach((m,V)=>te(r,`${O}[${V}]`,m));return}if(typeof s==="object")for(let[i,_]of Object.entries(s)){if(Me.has(i)||i==="")continue;te(r,`${O}.${Je(i)}`,_)}}function Ne(r){if(r===null||typeof r!=="object")return[];let O=[];for(let[s,D]of Object.entries(r)){if(Me.has(s)||s==="")continue;te(O,Je(s),D)}return O}function se(r){return Ne(r).map(([O,s])=>`${O}=${encodeURIComponent(s)}`).join("&")}function De(r,O,s=Math.random){let D=Math.max(1,Math.floor(r)),i=Math.min(O.baseMs*2**(D-1),O.maxMs);if(!O.jitter)return Math.max(0,i);let _=i*O.jitter;return Math.max(0,i+(s()*2-1)*_)}function Kn(r,O=Date.now()){if(r===null)return;let s=r.trim();if(/^\d+$/.test(s))return Number(s)*1000;if(!/[a-z]{3}/i.test(s))return;let D=Date.parse(s);if(Number.isNaN(D))return;return Math.max(0,D-O)}var he=Object.freeze({attempts:2,methods:Object.freeze(["GET","HEAD","OPTIONS","PUT","DELETE"]),on:Object.freeze([408,429,500,502,503,504,"network"]),baseMs:300,maxMs:1e4,jitter:0.5,respectRetryAfter:!0}),Ar=30000,ir=new Set([204,205,304]),Ir=["get","post","put","patch","delete","head","options"],ar,ae=()=>ar??=(G("yyw5hmrp"),import("./bodies-yyw5hmrp.js"));function _r(r){return typeof r==="object"&&Object.entries(r).some(([O,s])=>O!=="onFailure"&&s!==!1&&s!==void 0)}function ur(){try{return"production"}catch{return"development"}}function Rr(r){let O=he;for(let s of r){if(s===void 0)continue;if(s===!1){O=!1;continue}let D=O===!1?he:O,i=Object.fromEntries(Object.entries(s).filter(([,_])=>_!==void 0));O={...D,...i}}return O}function Ae(r){return typeof FormData<"u"&&r instanceof FormData||typeof URLSearchParams<"u"&&r instanceof URLSearchParams||typeof Blob<"u"&&r instanceof Blob||typeof ReadableStream<"u"&&r instanceof ReadableStream||r instanceof ArrayBuffer||ArrayBuffer.isView(r)}function W(r){return r.reason}function Tr(r,O){return new Promise((s,D)=>{let i=()=>D(W(O));O.addEventListener("abort",i,{once:!0}),r.then((_)=>{O.removeEventListener("abort",i),s(_)},(_)=>{O.removeEventListener("abort",i),D(_)})})}function Be(r,O){return new Promise((s,D)=>{if(O.aborted){D(W(O));return}let i,_=()=>{clearTimeout(i),D(W(O))};i=setTimeout(()=>{O.removeEventListener("abort",_),s()},r),O.addEventListener("abort",_,{once:!0})})}async function Oe(r){try{await r.body?.cancel()}catch{}}function dr(r){return/^application\/(?:[\w.-]+\+)?json\b/i.test(r)}async function ve(r,O,s,D,i,_){if(O==="HEAD"||ir.has(r.status))return await Oe(r),{value:void 0};let m=r.headers.get("content-type")??"";if(i===void 0){if(/^text\/event-stream\b/i.test(m))return{value:void 0,unread:!0};if(dr(m)){let V=await r.text();if(!V)return{value:void 0};try{return{value:JSON.parse(V)}}catch(v){throw new j(`${s} answered ${r.status} with a body that is not JSON`,{key:s,cause:v})}}if(!m||/^text\//i.test(m)){let V=await r.text();return{value:V===""?void 0:V}}}return(await ae()).read(r,D,i,_,s,j)}class Ye{config;#r;generation=0;#e;constructor(r){this.config=r}async token(){if(this.#r!==void 0)return this.#r;let r=this.config?.token;return(typeof r==="function"?await r():r)??void 0}triggers(r){if(!this.config?.refresh)return!1;return(this.config.on??[401]).includes(r)}refreshFor(r){if(this.#e)return this.#e;if(r!==this.generation)return Promise.resolve(!0);let O=this.config.refresh;return this.#e=(async()=>{try{let s=await O();if(s===null)return!1;return this.#r=s??void 0,this.generation++,!0}finally{this.#e=void 0}})(),this.#e}}function _e(r={}){let O=new Ye(r.auth),s=r.logger??console,D=r.routes??{},i=r.manifest??{},_=(r.mode??ur())==="development",m,V=()=>m??=(G("ysjfy072"),import("./validation-ysjfy072.js")).then((a)=>a.createChecks({development:_,source:r.schemas,logger:s,errors:{ClientError:j,ValidationError:Qe}})),v=(a,R)=>{let T=D[a]??{};return{timeout:R.timeout??T.timeout??r.timeout??Ar,retry:Rr([r.retry,T.retry,R.retry]),throwOnError:R.throwOnError??r.throwOnError??!1,undeclaredStatus:R.undeclaredStatus??r.undeclaredStatus??"throw",headers:[r.headers,T.headers,R.headers],middleware:[...r.middleware??[],...T.middleware??[],...R.middleware??[]]}},Y=(a,R,T)=>{let d=se(R.query);return`${r.baseUrl??""}${Ce(a,R.params,T)}${d?`?${d}`:""}`},ee=(a,R)=>{if(/^[a-z][a-z\d+.-]*:/i.test(a))return a;let T=globalThis.location?.href;if(T)return new URL(a,T).href;if(r.fetch)return new URL(a,"http://localhost").href;throw new j(`${R}: "${a}" is relative, and there is no page to resolve it against; give an absolute baseUrl, or a fetch that serves relative requests`,{key:R})},g=async(a,R,T,d,U,c,l)=>{let P={method:a.method,credentials:r.credentials??"same-origin",signal:U,body:T.body,headers:T.type===void 0?void 0:{"content-type":T.type}};if(typeof ReadableStream<"u"&&T.body instanceof ReadableStream)P.duplex="half";let b={...a,attempt:c,request:new Request(R,P)};for(let y of d.headers){if(y===void 0)continue;let S=typeof y==="function"?await y(b):y;new Headers(Array.isArray(S)||S instanceof Headers?S:JSON.parse(JSON.stringify(S))).forEach((H,x)=>{b.request.headers.set(x,H)})}let q=O.generation,w=await O.token();if(w!==void 0&&!b.request.headers.has("authorization"))b.request.headers.set("authorization",`Bearer ${w}`);if(c===1&&l!==void 0)await l(b.request);let k=async(y)=>{let S=d.middleware[y];if(S)return S(b,()=>k(y+1));if(U.aborted)throw W(U);try{return await Tr((r.fetch??fetch)(b.request),U)}catch(H){if(U.aborted)throw W(U);throw new Ge(`${b.key}: fetch failed`,{key:b.key,cause:H})}};return{response:await k(0),generation:q}},C=async(a,R,T,d,U,c,l)=>{let P=d.retry!==!1&&d.retry.methods.some((b)=>b.toUpperCase()===a.method)&&!(typeof ReadableStream<"u"&&T.body instanceof ReadableStream)?d.retry:void 0;for(let b=1;;b++){let q=c+b-1,w,k;try{w=await g(a,R,T,d,U,q,l)}catch(S){if(U.aborted)throw W(U);if(!(S instanceof Ge))throw S;k=S}if(!P||b>P.attempts){if(w)return{...w,attempts:q};throw k}if(w){let{response:S}=w;if(!P.on.includes(S.status))return{...w,attempts:q};let H=P.respectRetryAfter?Kn(S.headers.get("retry-after")):void 0,x=H===void 0?De(b,P):Math.min(H,P.maxMs);await Oe(S),s.debug(`${a.key}: ${S.status}, retry ${b} of ${P.attempts} in ${Math.round(x)} ms`),await Be(x,U);continue}if(!P.on.includes("network"))throw k;let y=De(b,P);s.debug(`${a.key}: network failure, retry ${b} of ${P.attempts} in ${Math.round(y)} ms`),await Be(y,U)}},M=async(a,R,T,d,U,c)=>{let l=a.status,P=i[R],b=P?.statuses;if(b&&!b.includes(l)){if(d.throwOnError||d.undeclaredStatus==="throw")throw new X(a,b,R);let S=(await ve(a,T,R,c)).value;return{ok:!1,status:l,error:S,response:a}}let q=await ve(a,T,R,c,P?.chunks?.[l],U&&((S)=>U.response(l,S))),{filename:w,value:k}=q;if(U!==void 0&&q.unread)try{await U.responseHeaders(l,a.headers)}catch(S){throw await Oe(a),S}else if(U!==void 0)k=await U.response(l,q.value,a.headers);let y=l>=200&&l<300;if(d.throwOnError){if(y)return k;throw new Ht(l,k,a,R)}return y?{ok:y,status:l,data:k,...w===void 0?{}:{filename:w},response:a}:{ok:y,status:l,error:k,response:a}},B=async(a,R,T)=>{let d=a.body;if(R)return{body:(await ae()).formDataOf(Ne(d),a.files)};if(d===void 0)return{};if(Ae(d))return{body:d};if(T==="urlencoded"&&typeof d==="object"&&d!==null)return{body:se(d),type:"application/x-www-form-urlencoded"};return{body:JSON.stringify(d),type:"application/json"}},J=async(a,R={})=>{let T=a.indexOf(" ");if(T<1)throw new j(`"${a}" is not a route key ("VERB /path")`,{key:a});let d=a.slice(0,T).toUpperCase(),U=a.slice(T+1),c=v(a,R),l=[r.validate,D[a]?.validate,R.validate],P=_&&r.schemas!==void 0||l.some(_r)?(await V())(a,l):void 0,b=i[a]?.bodyType,q=R.files!==void 0&&R.files!==null&&Object.values(R.files).some((Z)=>Z!=null),w=q||b==="multipart"&&typeof R.body==="object"&&R.body!==null&&!Ae(R.body),k=q?{...R,files:(await ae()).normaliseFiles(R.files)}:R,y=P===void 0?k:await P.request(k,Ae(k.body)),S=ee(Y(U,y,a),a),H=await B(y,w,b),x=new AbortController,Or=c.timeout===!1?void 0:setTimeout(()=>x.abort(new Gt(c.timeout,a)),c.timeout),oe=y.signal?AbortSignal.any([y.signal,x.signal]):x.signal,Pe={key:a,method:d,path:U,options:y};try{let{response:Z,generation:pe,attempts:be}=await C(Pe,S,H,c,oe,1,P?.headers);if(O.triggers(Z.status)&&await O.refreshFor(pe))await Oe(Z),{response:Z,generation:pe,attempts:be}=await C(Pe,S,H,c,oe,be+1);return await M(Z,a,d,c,P,y.as)}catch(Z){if(oe.aborted)throw W(oe);throw Z}finally{clearTimeout(Or)}},L={request:J,url:(a,R={})=>Y(a,R,a),[Symbol.for("@kingsleyweb/bun-client")]:r};for(let a of Ir){let R=a.toUpperCase();L[a]=(T,d)=>J(`${R} ${T}`,d)}let p=new Map;for(let[a,R]of Object.entries(i))if(R?.operationId)p.set(R.operationId,a);return L.op=new Proxy({},{get:(a,R)=>{if(typeof R!=="string")return;let T=p.get(R);if(!T)return()=>Promise.reject(new j(`No operation "${R}" in the client's manifest`));return(d)=>J(T,d)}}),L}var de=new WeakMap;function re(r){let O=de.get(r);if(O)return O;let s={etags:new Map,pending:new Map,headerTags:new Map};return O=s,de.set(r,s),r.getQueryCache().subscribe((D)=>{let i=D.query.queryHash;if(D.type==="removed"){s.etags.delete(i),s.pending.delete(i),s.headerTags.delete(i);return}if(D.type!=="updated"||D.action.type!=="success")return;if(D.action.manual){s.etags.delete(i),s.pending.delete(i);return}if(!s.pending.has(i))return;let _=s.pending.get(i);if(s.pending.delete(i),_==null)s.etags.delete(i);else s.etags.set(i,_)}),s}function ue(r){let O=r.headers.get("cache-tag"),s=r.headers.get("surrogate-key");if(O===null&&s===null)return;let D=new Set;for(let i of O?.split(",")??[])if(i.trim())D.add(i.trim());for(let i of s?.split(/\s+/)??[])if(i)D.add(i);return[...D]}function mr(r){return/(?:^|,)\s*no-store\s*(?:,|$)/i.test(r.headers.get("cache-control")??"")}function Ee(r,O){let s=r.getQueryCache();return s.get(Te(O))??s.find({queryKey:O,exact:!0})}function He(r,O){let s=O.meta?.tags,D=new Set(Array.isArray(s)?s.filter((i)=>typeof i==="string"):[]);for(let i of de.get(r)?.headerTags.get(O.queryHash)??[])D.add(i);return[...D]}function we(r,O,s,D){let i=new Set(O);if(i.size===0)return Promise.resolve();return r.invalidateQueries({...s,predicate:(_)=>He(r,_).some((m)=>i.has(m))},D)}var cr=Symbol.for("@kingsleyweb/bun-client/query#live"),lr;function pr(r,O,s={}){let D,i=!1;return(lr??=(G("6k7s6358"),import("./live-6k7s6358.js"))).then((_)=>{if(!i)D=_.startLive(r,O,s,He)},(_)=>{(r[Symbol.for("@kingsleyweb/bun-client")]?.logger??console).error("live(): could not load",_)}),()=>{i=!0,D?.()}}var br=Symbol.for("@kingsleyweb/bun-client/graphql");function qe(r){let O={};for(let[s,D]of Object.entries(r??{}))if(D!==void 0&&D!==null)O[s]=String(D);return O}var Sr=/\{([^{}]+)\}/g;function Re(r,O){let s=[];for(let D of r??[]){let i=!1,_=D.replace(Sr,(m,V)=>{let v=O?.[V];if(v===void 0||v===null)return i=!0,"";return String(v)});if(!i&&!s.includes(_))s.push(_)}return s}function z(r){return typeof r==="object"&&r!==null?r:{}}function We(r,O={}){let s=r,D=O.manifest??{},i=(g)=>({params:qe(g.params),query:{...g.query}}),_=async(g,C,M,B)=>{let J,L=async(p,a)=>{if(B!==void 0)p.request.headers.set("if-none-match",B);return J=await a(),J};try{return{data:await s.request(g,{...C,signal:M,throwOnError:!0,middleware:[...C.middleware??[],L]}),response:J}}catch(p){return{error:p,response:J}}};return{key:(g,C)=>C===void 0?[g]:[g,i(C)],query:(g,C)=>{let M=`GET ${g}`,B=C??{};return{queryKey:[M,i(B)],queryFn:async(J)=>{let L=re(J.client),p=Ee(J.client,J.queryKey),a=p?.queryHash,R=p?.state.data,T=a!==void 0&&R!==void 0?L.etags.get(a):void 0,d=await _(M,B,J.signal,T),{response:U}=d,c=T!==void 0&&U?.status===304;if(d.error!==void 0&&!c)throw d.error;if(c&&d.error!==void 0)await U?.body?.cancel().catch(()=>{return});if(a!==void 0){let l=U&&ue(U);if(l!==void 0)L.headerTags.set(a,l);else if(!c)L.headerTags.delete(a);L.pending.set(a,U===void 0||mr(U)?null:U.headers.get("etag")??(c?T:null))}return c?R:d.data},meta:{tags:Re(D[M]?.cache?.tags,B.params)}}},infinite:(g,C,M)=>{let B=`GET ${g}`,{[M.pageParam]:J,...L}=C.query??{},p={...C,query:L};return{queryKey:[B,i(p),"infinite"],queryFn:async(a)=>{let R=a.pageParam===void 0||a.pageParam===null?L:{...L,[M.pageParam]:a.pageParam},T=await _(B,{...p,query:R},a.signal,void 0),d=T.response&&ue(T.response);if(d!==void 0){let U=Ee(a.client,a.queryKey)?.queryHash;if(U!==void 0){let c=re(a.client),l=c.headerTags.get(U)??[];c.headerTags.set(U,[...new Set([...l,...d])])}}if(T.error!==void 0)throw T.error;return T.data},initialPageParam:"initialPageParam"in M?M.initialPageParam:J,getNextPageParam:M.next,...M.previous===void 0?{}:{getPreviousPageParam:M.previous},meta:{tags:Re(D[B]?.cache?.tags,p.params)}}},mutation:(g,C={})=>{let M=D[g]?.cache?.invalidates??[],B=Object.entries(C.optimistic??{}).filter((L)=>typeof L[1]==="function"),J=(L,p,a)=>L.getQueryCache().findAll({queryKey:[p]}).filter((R)=>{let T=R.queryKey;if(T.length!==2)return!1;let d=z(z(T[1]).params);return Object.entries(d).every(([U,c])=>!(U in a)||a[U]===c)});return{mutationKey:[g],mutationFn:(L)=>s.request(g,{...C.validate===void 0?{}:{validate:C.validate},...z(L),throwOnError:!0}),onMutate:async(L,p)=>{let a=[],R=re(p.client);if(B.length===0)return{written:a};let T=qe(z(z(L).params));for(let[d]of B)await p.client.cancelQueries({queryKey:[d]});for(let[d,U]of B)for(let c of J(p.client,d,T)){let l=c.state.data;if(l===void 0)continue;let P=U(l,L);if(P===void 0)continue;a.push({queryKey:c.queryKey,data:l,dataUpdatedAt:c.state.dataUpdatedAt,etag:R.etags.get(c.queryHash)}),p.client.setQueryData(c.queryKey,P)}return{written:a}},onError:(L,p,a,R)=>{let T=re(R.client);for(let{queryKey:d,data:U,dataUpdatedAt:c,etag:l}of[...a?.written??[]].reverse()){let P=Ee(R.client,d);if(P===void 0)continue;if(P.setState({data:U,dataUpdatedAt:c}),l!==void 0)T.etags.set(P.queryHash,l)}},onSuccess:async(L,p,a,R)=>{await we(R.client,Re(M,z(z(p).params)))},onSettled:async(L,p,a,R,T)=>{await Promise.all((R?.written??[]).map(({queryKey:d})=>T.client.invalidateQueries({queryKey:d,exact:!0})))},meta:{invalidates:[...M]}}},graphql:(g,C,M,B={})=>{let J=g[br];if(J===void 0)throw TypeError("q.graphql() takes a client from createGraphQLClient (./graphql)");let L=J.describe(C),{tags:p,...a}=B;return{queryKey:[J.url,L.name??L.source,M??{}],queryFn:async(R)=>{let T,d=async(U,c)=>T=await c();try{return(await g.query(C,M,{...a,signal:R.signal,throwOnError:!0,throwOnGraphQLErrors:!0,middleware:[...a.middleware??[],d]})).data}finally{let U=Ee(R.client,R.queryKey)?.queryHash,c=T&&ue(T);if(U!==void 0){let l=re(R.client);if(c!==void 0)l.headerTags.set(U,c);else if(T!==void 0)l.headerTags.delete(U)}}},meta:{tags:[...p??[]]}}},invalidateTags:we,[cr]:(g,C)=>pr(s,g,C)}}var Ue={"GET /analytics/jobs":{operationId:"getJobsAnalytics",statuses:[200,400,401,403]},"GET /analytics/runners":{operationId:"getRunnersAnalytics",statuses:[200,400,401,403]},"GET /analytics/workers":{operationId:"getWorkersAnalytics",statuses:[200,400,401,403]},"GET /asyncapi.json":{operationId:"getAsyncApiDocument",statuses:[200,401,403]},"GET /definitions":{operationId:"listDefinitions",statuses:[200,401,403]},"GET /demand":{operationId:"listQueueDemand",statuses:[200,400,401,403]},"GET /meta":{operationId:"getMeta",statuses:[200,401,403]},"GET /meta/permissions":{operationId:"getPermissions",statuses:[200,400,401,403]},"GET /openapi.json":{operationId:"getOpenApiDocument",statuses:[200,401,403]},"GET /overview":{operationId:"getOverview",statuses:[200,400,401,403]},"GET /overview/added":{operationId:"getAddedByState",statuses:[200,400,401,403]},"GET /providers":{operationId:"listProviders",statuses:[200,401,403]},"GET /providers/:id/schema":{operationId:"getProviderSchema",statuses:[200,400,401,403,404]},"POST /providers/:id/validate":{operationId:"validateProvider",statuses:[200,400,401,403,404,413,415]},"GET /queues":{operationId:"listQueues",statuses:[200,400,401,403]},"GET /queues/:queue":{operationId:"getQueue",statuses:[200,400,401,403,404]},"GET /queues/:queue/analytics/jobs":{operationId:"getQueueJobsAnalytics",statuses:[200,400,401,403,404]},"GET /queues/:queue/analytics/workers/:key":{operationId:"getWorkerAnalytics",statuses:[200,400,401,403,404]},"POST /queues/:queue/clean":{operationId:"cleanQueue",statuses:[200,400,401,403,404,413,415]},"GET /queues/:queue/counts":{operationId:"getQueueCounts",statuses:[200,400,401,403,404]},"GET /queues/:queue/counts/added":{operationId:"getQueueAddedByState",statuses:[200,400,401,403,404]},"GET /queues/:queue/demand":{operationId:"getQueueDemand",statuses:[200,400,401,403,404]},"POST /queues/:queue/drain":{operationId:"drainQueue",statuses:[200,400,401,403,404,413,415]},"POST /queues/:queue/flows":{operationId:"addFlow",statuses:[200,201,400,401,403,404,413,415]},"GET /queues/:queue/job-defaults":{operationId:"getJobDefaults",statuses:[200,400,401,403,404]},"PUT /queues/:queue/job-defaults":{operationId:"setJobDefaults",statuses:[200,400,401,403,404,409,413,415]},"DELETE /queues/:queue/job-defaults":{operationId:"resetJobDefaults",statuses:[200,400,401,403,404,409,413,415]},"POST /queues/:queue/job-defaults/apply":{operationId:"applyJobDefaults",statuses:[200,400,401,403,404,409,413,415]},"GET /queues/:queue/jobs":{operationId:"listJobs",statuses:[200,400,401,403,404]},"POST /queues/:queue/jobs":{operationId:"addJob",statuses:[200,201,400,401,403,404,413,415]},"GET /queues/:queue/jobs/:id":{operationId:"getJob",statuses:[200,400,401,403,404]},"PATCH /queues/:queue/jobs/:id":{operationId:"updateJob",statuses:[200,400,401,403,404,409,413,415]},"DELETE /queues/:queue/jobs/:id":{operationId:"removeJob",statuses:[204,400,401,403,404,409,413,415]},"GET /queues/:queue/jobs/:id/children":{operationId:"getJobChildren",statuses:[200,400,401,403,404]},"POST /queues/:queue/jobs/:id/fail":{operationId:"failJob",statuses:[200,400,401,403,404,409,413,415]},"GET /queues/:queue/jobs/:id/logs":{operationId:"getJobLogs",statuses:[200,400,401,403,404]},"DELETE /queues/:queue/jobs/:id/logs":{operationId:"clearJobLogs",statuses:[200,400,401,403,404,409,413,415]},"POST /queues/:queue/jobs/:id/promote":{operationId:"promoteJob",statuses:[200,400,401,403,404,409,413,415]},"POST /queues/:queue/jobs/:id/retry":{operationId:"retryJob",statuses:[200,400,401,403,404,409,413,415]},"POST /queues/:queue/jobs/lookup":{operationId:"lookupJobs",statuses:[200,400,401,403,404,413]},"POST /queues/:queue/jobs/promote":{operationId:"promoteJobs",statuses:[200,400,401,403,404,413,415]},"POST /queues/:queue/jobs/remove":{operationId:"removeJobs",statuses:[200,400,401,403,404,413,415]},"POST /queues/:queue/jobs/retry":{operationId:"retryJobs",statuses:[200,400,401,403,404,413,415]},"POST /queues/:queue/jobs/retry-all":{operationId:"retryAllJobs",statuses:[200,400,401,403,404,409,413,415]},"GET /queues/:queue/limits":{operationId:"getQueueLimits",statuses:[200,400,401,403,404]},"PUT /queues/:queue/limits":{operationId:"setQueueLimits",statuses:[200,400,401,403,404,409,413,415]},"DELETE /queues/:queue/limits":{operationId:"removeQueueLimits",statuses:[200,400,401,403,404,409,413,415]},"POST /queues/:queue/pause":{operationId:"pauseQueue",statuses:[200,400,401,403,404,413,415]},"GET /queues/:queue/repeatables":{operationId:"listRepeatables",statuses:[200,400,401,403,404]},"DELETE /queues/:queue/repeatables/:key":{operationId:"removeRepeatable",statuses:[204,400,401,403,404,413,415]},"POST /queues/:queue/repeatables/:key/disable":{operationId:"disableRepeatable",statuses:[200,400,401,403,404,413,415]},"POST /queues/:queue/repeatables/:key/enable":{operationId:"enableRepeatable",statuses:[200,400,401,403,404,413,415]},"POST /queues/:queue/resume":{operationId:"resumeQueue",statuses:[200,400,401,403,404,413,415]},"GET /queues/:queue/summon":{operationId:"getQueueSummon",statuses:[200,400,401,403,404,409,503]},"POST /queues/:queue/summon":{operationId:"summonQueue",statuses:[200,400,401,403,404,409,413,415,503]},"POST /queues/:queue/summon/reset":{operationId:"resetQueueSummon",statuses:[200,400,401,403,404,409,413,415,503]},"GET /queues/:queue/throughput":{operationId:"getQueueThroughput",statuses:[200,400,401,403,404]},"GET /queues/:queue/worker-configs":{operationId:"listWorkerConfigs",statuses:[200,400,401,403,404]},"PUT /queues/:queue/worker-configs/:key":{operationId:"configureWorker",statuses:[200,400,401,403,404,409,413,415]},"DELETE /queues/:queue/worker-configs/:key":{operationId:"resetWorkerConfig",statuses:[200,400,401,403,404,409,413,415]},"GET /queues/:queue/workers":{operationId:"listQueueWorkers",statuses:[200,400,401,403,404]},"GET /queues/:queue/workers/:worker":{operationId:"getWorker",statuses:[200,400,401,403,404,410]},"POST /queues/:queue/workers/:worker/pause":{operationId:"pauseWorker",statuses:[200,202,400,401,403,404,409,410,413,415]},"POST /queues/:queue/workers/:worker/resume":{operationId:"resumeWorker",statuses:[200,202,400,401,403,404,409,410,413,415]},"POST /queues/:queue/workers/:worker/start":{operationId:"startWorker",statuses:[200,202,400,401,403,404,409,410,413,415]},"POST /queues/:queue/workers/:worker/stop":{operationId:"stopWorker",statuses:[200,202,400,401,403,404,409,410,413,415]},"GET /runners":{operationId:"listRunners",statuses:[200,401,403]},"GET /runners/:runner":{operationId:"getRunner",statuses:[200,400,401,403,404]},"GET /runners/:runner/analytics":{operationId:"getRunnerAnalytics",statuses:[200,400,401,403,404]},"PUT /runners/:runner/config":{operationId:"configureRunner",statuses:[200,400,401,403,404,409,413,415]},"DELETE /runners/:runner/config":{operationId:"resetRunnerConfig",statuses:[200,400,401,403,404,409,413,415]},"GET /runners/:runner/history":{operationId:"getRunnerHistory",statuses:[200,400,401,403,404]},"DELETE /runners/:runner/history":{operationId:"clearRunnerHistory",statuses:[200,400,401,403,404,413,415]},"POST /runners/:runner/kill":{operationId:"killRunner",statuses:[200,202,400,401,403,404,409,413,415]},"POST /runners/:runner/pause":{operationId:"pauseRunner",statuses:[200,400,401,403,404,413,415]},"POST /runners/:runner/resume":{operationId:"resumeRunner",statuses:[200,400,401,403,404,413,415]},"GET /runners/:runner/runs/:runId/logs":{operationId:"getRunLogs",statuses:[200,400,401,403,404,409]},"PUT /runners/:runner/schedule":{operationId:"rescheduleRunner",statuses:[200,400,401,403,404,413,415]},"GET /runners/:runner/stats":{operationId:"getRunnerStats",statuses:[200,400,401,403,404]},"POST /runners/:runner/stats/reset":{operationId:"resetRunnerStats",statuses:[204,400,401,403,404,409,413,415]},"POST /runners/:runner/trigger":{operationId:"triggerRunner",statuses:[200,202,400,401,403,404,409,413,415]},"GET /summon":{operationId:"listSummonControllers",statuses:[200,401,403]},"GET /summon/groups":{operationId:"listSummonGroups",statuses:[200,401,403]},"GET /summon/groups/:group":{operationId:"getSummonGroup",statuses:[200,400,401,403,409,503]},"POST /summon/groups/:group/reset":{operationId:"resetSummonGroup",statuses:[200,400,401,403,409,413,415,503]},"GET /workers":{operationId:"listWorkers",statuses:[200,400,401,403]}};var Ke=new WeakMap;function Q(r){let O=Ke.get(r);if(O===void 0){let s=_e({baseUrl:r.base,manifest:Ue,fetch:(D)=>Fr(r,D),headers:(D)=>r.headers(D.method),middleware:[gr(r)],retry:!1,timeout:!1});O={client:s,q:We(s,{manifest:Ue})},Ke.set(r,O)}return O}async function Fr(r,O){let s={};O.headers.forEach((i,_)=>{s[_]=i});let D={method:O.method,headers:s,credentials:O.credentials,signal:O.signal};if(O.method!=="GET"&&O.method!=="HEAD"){let i=await O.text();if(i!=="")D.body=i}return r.fetch(O.url,D)}function Vr(r){let O=r.split(";")[0]?.trim().toLowerCase()??"";return O==="application/json"||O.endsWith("+json")}function gr(r){return async(O,s)=>{let D=await s();if(!D.ok||D.status===204||Vr(D.headers.get("content-type")??""))return D;let i=await D.clone().text();if(i==="")return D;throw new K({kind:"parse",status:D.status,code:"INVALID_RESPONSE",title:"The API answered something other than JSON",detail:i.trim().slice(0,300)||void 0,instance:fr(r,O.request.url)})}}function fr(r,O){let{pathname:s}=new URL(O,"http://localhost");return s.startsWith(r.base)?s.slice(r.base.length):s}function me(r,O){if(tr(r.error))return K.fromProblem({...r.error,status:r.status});return new K({kind:"http",status:r.status,code:`HTTP_${r.status}`,title:r.response.statusText||`Request failed (${r.status})`,...typeof r.error==="string"&&r.error.trim()!==""?{detail:r.error.trim().slice(0,300)}:{},instance:O})}async function ce(r,O){if(r instanceof X){let s=await r.response.text().catch(()=>"");return nr(r.response,s,O)}if(r instanceof Ge){let s=r.cause;return new K({kind:"network",status:0,code:"NETWORK_ERROR",title:"The API could not be reached",detail:s instanceof Error?s.message:String(s),instance:O,cause:s})}return r}async function ne(r,O){let s;try{s=await r}catch(D){throw await ce(D,O)}if(s.ok)return s.data;throw me(s,O)}var yr="SUMMON_NOT_CONFIGURED",ke={status:(r,O)=>Q(r).q.key("GET /queues/:queue/summon",{params:{queue:O}}),list:(r)=>Q(r).q.key("GET /summon",{}),groups:(r)=>Q(r).q.key("GET /summon/groups",{}),changed:(r,O)=>[ke.status(r,O),Q(r).q.key("GET /summon"),Q(r).q.key("GET /summon/groups")]};function le(r,O=""){return`/queues/${encodeURIComponent(r)}/summon${O}`}function $e(r){return typeof r.queue==="string"&&typeof r.local==="boolean"&&typeof r.inert==="boolean"&&Array.isArray(r.pending)&&typeof r.failures==="number"}function Mr(r){return ot(r)&&typeof r.queue==="string"&&(r.budget===void 0||ot(r.budget))}function Jr(r){return ot(r)&&typeof r.name==="string"&&ot(r.budget)&&ot(r.queues)}async function $n(r,O,s){let D=le(O),i;try{i=await Q(r).client.get("/queues/:queue/summon",{params:{queue:O},signal:s})}catch(_){throw await ce(_,D)}if(i.ok)return zt(i.data,$e,"a queue's summon status",D);if(i.status===409&&i.error.code===yr||i.status===404)return null;throw me(i,D)}async function Uo(r,O,s){let D=le(O),i=await ne(Q(r).client.post("/queues/:queue/summon",{params:{queue:O},body:{force:s}}),D);return zt(i,(_)=>typeof _.action==="string","a summon check",D)}async function wo(r,O){let D=await ne(Q(r).client.get("/summon",{signal:O}),"/summon");return zt(D,(i)=>Array.isArray(i.controllers)&&i.controllers.every(Mr),"the summon controllers","/summon")}async function ko(r,O){let D=await ne(Q(r).client.get("/summon/groups",{signal:O}),"/summon/groups");return zt(D,(i)=>Array.isArray(i.groups)&&i.groups.every(Jr),"the summon groups","/summon/groups")}async function xo(r,O,s={}){let D=le(O,"/reset"),i=await ne(Q(r).client.post("/queues/:queue/summon/reset",{params:{queue:O},body:s.budget===!0?{budget:!0}:void 0}),D);return zt(i,$e,"a queue's summon status",D)}function xe(r){return`/queues/${encodeURIComponent(r)}?panel=summon`}function je(r){return`/summon?group=${encodeURIComponent(r)}`}var hr=86400000,Br={hour:"this hour",day:"today"};function ft(r,O){let s=new Date(r).toISOString(),D=s.slice(11,16);if(Math.abs(r-O)>=hr)return`${s.slice(0,10)} ${D} UTC`;return D==="00:00"?"midnight UTC":`${D} UTC`}function ze(r,O,s,D,i){let _=Math.max(0,s-O),m=Br[r];return{window:r,used:O,limit:s,remaining:_,exhausted:O>=s,resetsAt:D,left:`${o(_)} of ${o(s)} left ${m}`,usedText:`${o(O)} of ${o(s)} used ${m}`,resetAt:ft(D,i)}}function Gr(r){return r.off===!0||r.limitsUnknown!==!0&&(r.perHour===void 0||r.perDay===void 0)}function Xe(r){return r.off!==!0&&r.limitsUnknown===!0}function yn(r){if(Gr(r)||Xe(r))return;return`Used ${o(r.hour)} of ${o(r.perHour??0)} this hour, ${o(r.day)} of ${o(r.perDay??0)} today (UTC)`}function er(r,O,s={}){let D=`Counts reset at ${ft(r.hourResetsAt,O)} and at ${ft(r.dayResetsAt,O)}`;if(Xe(r))return{state:"unknown",text:`${o(r.hour)} this hour, ${o(r.day)} today (UTC), limits unknown`,hint:`Its limits are set where its controller runs, and show here after its next summon attempt. ${D}`};if(r.off===!0||r.perHour===void 0||r.perDay===void 0){if(s.group===!0&&r.off===!0)return{state:"off",text:"Off: the group's budget applies",resets:`This queue's own count: ${o(r.hour)} this hour, ${o(r.day)} today (UTC). ${D}`};return{state:"off",text:`Off: ${o(r.hour)} this hour, ${o(r.day)} today (UTC), no limit`,resets:D}}let i=ze("hour",r.hour,r.perHour,r.hourResetsAt,O),_=ze("day",r.day,r.perDay,r.dayResetsAt,O);return{state:"on",hour:i,day:_,exhausted:i.exhausted||_.exhausted,usedText:yn(r)??""}}function Ze({budget:r,testId:O,group:s=!1}){let D=Ie(),i=er(r,D,{group:s});if(i.state==="unknown")return e("span",{className:"summon-budget","data-testid":O,"data-limits-unknown":"true",title:i.hint,children:i.text});if(i.state==="off")return e("span",{className:"summon-budget","data-testid":O,title:i.resets,children:i.text});return t("span",{className:"summon-budget","data-testid":O,"data-exhausted":i.exhausted,title:i.usedText,children:[e(rr,{view:i.hour,testId:`${O}-hour`}),e("span",{className:"visually-hidden",children:"; "}),e(rr,{view:i.day,testId:`${O}-day`})]})}function rr({view:r,testId:O}){let s=Math.max(r.limit,1);return t("span",{className:N("summon-budget-window",r.exhausted&&"is-exhausted"),"data-testid":O,"data-exhausted":r.exhausted,title:r.usedText,children:[e("meter",{className:"summon-budget-meter",min:0,max:s,low:s*0.2,high:s*0.5,optimum:s,value:Math.min(r.remaining,s),"aria-hidden":"true"}),t("span",{children:[r.exhausted&&t(n,{children:[e(f,{tone:"warning",title:"Nothing is summoned until this window resets.",children:"Exhausted"})," "]}),r.left,", resets at ",r.resetAt," (",e(A,{value:r.resetsAt}),")"]})]})}function Wn(r){return Object.entries(r.queues).map(([O,s])=>({queue:O,day:s.day,lastAt:s.lastAt})).sort((O,s)=>s.day-O.day||(O.queue<s.queue?-1:O.queue>s.queue?1:0))}function Yn(r,O){let s=Object.entries(r.circuits??{});if(s.length>0)return s.sort(([D],[i])=>D<i?-1:D>i?1:0).map(([D,i])=>({kind:D,failures:i.failures,openUntil:i.openUntil,openedBy:i.openedBy}));if(r.circuit===void 0)return[];return[{kind:O,failures:r.circuit.failures,openUntil:r.circuit.openUntil,openedBy:r.circuit.openedBy}]}function Le(r){return r===void 0||r===""?"this summoner":r}function jt(r){return r.unit==="shared"}var zn="One summoned process serves every queue of this group.";function Pr(r){return jt(r)?"Shared":"Per queue"}function or(r){return jt(r)?{heading:"Attempts serving each queue today",note:"One attempt serves every queue of the unit, so each counts it: these do not add up to the group's budget.",empty:"No attempts served the unit's queues today.",tableLabel:`Attempts serving each queue of the group ${r.name} today`}:{heading:"Charged today",note:void 0,empty:"No attempts charged to the group today.",tableLabel:`Attempts charged to the group ${r.name} today`}}var Mo="Today, per queue",Fo="For a per-queue group, each count is the attempts that queue charged to the group today. For a shared unit, each attempt is counted on every queue it served, so the counts do not add up to the group's.",Vo="each attempt serves every queue";function Bo({group:r,queue:O,kind:s}){let D=Wn(r),i=Yn(r,s),_=or(r);return t("section",{className:"summon-group","data-testid":"summon-group","aria-label":`Summon group ${r.name}`,children:[t("h3",{className:"summon-heading",children:["Summon group ",e(vr,{name:r.name}),jt(r)&&t(n,{children:[" ",e(f,{tone:"neutral",title:zn,testId:"summon-group-unit",children:"Shared unit"})]})]}),e(F,{items:[{key:"group-budget",label:"Group budget",value:e(Ze,{budget:r.budget,testId:"summon-group-budget"}),hint:yn(r.budget)},...i.map((m)=>({key:`circuit-${m.kind??""}`,label:`Shared circuit, ${Le(m.kind)}`,value:e(Ur,{circuit:m})}))]}),e("h4",{className:"summon-subheading",children:_.heading}),_.note!==void 0&&D.length>0&&e("p",{className:"muted summon-group-note","data-testid":"summon-group-shares-note",children:_.note}),D.length===0?e("p",{className:"muted","data-testid":"summon-group-shares-empty",children:_.empty}):e(kr,{label:_.tableLabel,queue:O,shares:D})]})}function vr({name:r}){let O=ie("summonList")===!0,s=ie("summonStoredStatus")===!0,D=Fe()("queues.list");if(!(O&&s&&D))return e("span",{"data-testid":"summon-group-name",children:r});return e(E,{to:je(r),title:`The group ${r} on the Summoning screen`,"data-testid":"summon-group-name",children:r})}function kr({label:r,queue:O,shares:s}){return t(I,{label:r,children:[e("thead",{children:t("tr",{children:[e("th",{scope:"col",children:"Queue"}),e("th",{scope:"col",className:"num",children:"Attempts today"}),e("th",{scope:"col",children:"Last"})]})}),e("tbody",{children:s.map((D)=>{let i=D.queue===O;return t("tr",{"data-testid":`summon-group-share-${D.queue}`,"aria-current":i?"true":void 0,className:N(i&&"is-current"),children:[t("th",{scope:"row",children:[e(E,{to:xe(D.queue),title:`The Summon tab of ${D.queue}`,children:D.queue}),i&&e("span",{className:"muted",children:" (this queue)"})]}),e("td",{className:"num",children:o(D.day)}),e("td",{children:e(A,{value:D.lastAt})})]},D.queue)})})]})}function Ur({circuit:r,compact:O=!1,testId:s}){let D=Ie(),i=Le(r.kind),_=s??`summon-group-circuit-${r.kind===void 0||r.kind===""?"this-summoner":r.kind}`,m=`${h(r.failures,"consecutive failure")} across the group`,V=r.openedBy,v=V?.detail===void 0?void 0:u(V.detail),Y=r.openUntil;if(Y===void 0)return O?t("span",{"data-testid":_,"data-open":"false",title:m,children:[i,": closed"]}):t("span",{"data-testid":_,"data-open":"false",children:[e(f,{tone:"success",children:"Closed"})," ",e("span",{className:"muted",children:m})]});let ee=V!==void 0&&t(n,{children:[", opened by"," ",e(E,{to:xe(V.queue),title:`The Summon tab of ${V.queue}`,children:V.queue})]});if(O)return t("span",{className:"summon-group-circuit is-open","data-testid":_,"data-open":"true",title:v===void 0?m:`${m}: ${v}`,children:[i,": open until ",ft(Y,D)," (",e(A,{value:Y}),")",ee]});return t("span",{className:"summon-group-circuit is-open","data-testid":_,"data-open":"true",children:[e(f,{tone:"warning",title:"After repeated failures across the group nothing is summoned for this kind until then, apart from one trial attempt.",children:"Open"})," ","until ",ft(Y,D)," (",e(A,{value:Y}),")",ee,v!==void 0&&t("span",{className:"muted",children:[" — ",v]})]})}
|
|
2
|
+
export{j,Ht,Ge,Gt,Qe,jn,Cr,Lr,Qt,Kn,ke,$n,Uo,wo,ko,xo,xe,ft,yn,Ze,Wn,Yn,jt,zn,Pr,Mo,Fo,Vo,Bo,Ur};
|
|
3
|
+
|
|
4
|
+
//# debugId=A1DEEB98C12EE59964756E2164756E21
|
|
5
|
+
//# sourceMappingURL=main-jxre7w93.js.map
|