express-zod-api 29.0.0-beta.2 → 29.0.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -5
- package/README.md +9 -13
- package/dist/documentation-helpers-CwgXjxwT.d.ts +30 -0
- package/dist/documentation.d.ts +75 -0
- package/dist/documentation.js +1 -0
- package/dist/index.d.ts +42 -899
- package/dist/index.js +4 -7
- package/dist/integration.d.ts +85 -0
- package/dist/integration.js +4 -0
- package/dist/json-schema-helpers-C1xkaMOk.js +1 -0
- package/dist/peer-helpers-BFaGRU7x.js +1 -0
- package/dist/routing-walker-Uax31V_v.js +1 -0
- package/dist/routing-xQnwfH2D.d.ts +739 -0
- package/package.json +13 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,15 @@
|
|
|
5
5
|
### v29.0.0
|
|
6
6
|
|
|
7
7
|
- Supported Node.js versions: `^22.19.0 || ^24.11.0 || ^26.0.0`;
|
|
8
|
+
- Major changes to the package distribution:
|
|
9
|
+
- `Documentation` and `Depicter` type moved to the `express-zod-api/documentation` subpath;
|
|
10
|
+
- `Integration` and `Producer` type moved to the `express-zod-api/integration` subpath;
|
|
11
|
+
- Several types and interfaces are no longer exposed:
|
|
12
|
+
- `CommonConfig`, `AppConfig`, `ServerConfig` — use `createConfig()` instead;
|
|
13
|
+
- `ApiResponse` — use `createApiResponse()` instead (new);
|
|
14
|
+
- `CacheControl` and `CachePolicy` — use `createCacheMiddleware()` or `EndpointsFactory::useCacheMiddleware()`;
|
|
15
|
+
- `FlatObject`, `IOSchema` and every type ending with `Security`;
|
|
16
|
+
- The public nature of these types was a workaround for user-side type declarations, but it's solved differently.
|
|
8
17
|
- Breaking change to the `cors` config option:
|
|
9
18
|
- Changed from `boolean | HeadersProvider` to `boolean | RequestHandler`;
|
|
10
19
|
- You can now use the well-known `cors` package or pass a conventional `RequestHandler` directly.
|
|
@@ -17,18 +26,25 @@
|
|
|
17
26
|
- The hooks (`beforeRouting` and `afterRouting` config options) are no longer async;
|
|
18
27
|
- `beforeRouting` now runs after the installation of globally enabled parsers;
|
|
19
28
|
- Added new `beforeParsers` hook that runs before all parsers are installed.
|
|
20
|
-
- The static async method `Integration::create()` removed — use `new Integration()` instead;
|
|
21
29
|
- The `createServer()` function is now synchronous — that should simplify the daily routines for beginners;
|
|
22
30
|
- Added HTTP QUERY method support (RFC 10008):
|
|
23
31
|
- The QUERY method is like GET but with a body — safe, idempotent, and cacheable;
|
|
24
32
|
- Default input sources for QUERY: `["query", "body", "params"]` (from the lowest priority to highest);
|
|
25
33
|
- Supported by `Integration` and `Documentation` generators.
|
|
26
|
-
- Changes to `Documentation
|
|
27
|
-
- `serverUrl` renamed to `server` and now also accepts OpenAPI's ServerObject;
|
|
28
|
-
- `title` and `version` must be wrapped into `info`, assignable with OpenAPI's InfoObject;
|
|
29
|
-
-
|
|
34
|
+
- Changes to `Documentation`:
|
|
35
|
+
- `serverUrl` constructor option renamed to `server` and now also accepts OpenAPI's ServerObject;
|
|
36
|
+
- `title` option and `version` must be wrapped into `info`, assignable with OpenAPI's InfoObject;
|
|
37
|
+
- Now produces OpenAPI 3.2.0 with better SSE support and other features.
|
|
38
|
+
- Changes to `Integration`:
|
|
39
|
+
- The static async method `create()` removed — use `new Integration()` instead;
|
|
40
|
+
- Removed `typescript` option from constructor — now imported statically.
|
|
41
|
+
- Consider using [the automated migration](https://www.npmjs.com/package/@express-zod-api/migration).
|
|
30
42
|
|
|
31
43
|
```diff
|
|
44
|
+
- import { Integration, Documentation, type Producer, type Depicter } from "express-zod-api";
|
|
45
|
+
+ import { Integration, type Producer } from "express-zod-api/integration";
|
|
46
|
+
+ import { Documentation, type Depicter } from "express-zod-api/documentation";
|
|
47
|
+
|
|
32
48
|
const config = createConfig({
|
|
33
49
|
- cors: () => ({ origin: "https://example.com" }),
|
|
34
50
|
+ cors: cors({ origin: "https://example.com" }), // import cors from "cors"
|
package/README.md
CHANGED
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-

|
|
6
|
+

|
|
7
|
+
[](https://coveralls.io/github/RobinTail/express-zod-api)
|
|
8
8
|
|
|
9
9
|

|
|
10
|
-

|
|
11
10
|

|
|
12
11
|

|
|
13
12
|
|
|
@@ -1214,7 +1213,7 @@ safety between your API and frontend. Make sure you have `typescript` installed.
|
|
|
1214
1213
|
and using the async `printFormatted()` method.
|
|
1215
1214
|
|
|
1216
1215
|
```ts
|
|
1217
|
-
import { Integration } from "express-zod-api";
|
|
1216
|
+
import { Integration } from "express-zod-api/integration";
|
|
1218
1217
|
|
|
1219
1218
|
const client = new Integration({
|
|
1220
1219
|
routing,
|
|
@@ -1244,7 +1243,7 @@ new Subscription("get /v1/events/stream", {}).on("time", (time) => {}); // Serve
|
|
|
1244
1243
|
You can generate the specification of your API and write it to a `.yaml` file, that can be used as the documentation:
|
|
1245
1244
|
|
|
1246
1245
|
```ts
|
|
1247
|
-
import { Documentation } from "express-zod-api";
|
|
1246
|
+
import { Documentation } from "express-zod-api/documentation";
|
|
1248
1247
|
|
|
1249
1248
|
const yamlString = new Documentation({
|
|
1250
1249
|
routing, // the same routing and config that you use to start the server
|
|
@@ -1288,7 +1287,8 @@ endpoints is available for that purpose. In order to establish the constraints o
|
|
|
1288
1287
|
should be declared as keys of `TagOverrides` interface. Consider the following example:
|
|
1289
1288
|
|
|
1290
1289
|
```ts
|
|
1291
|
-
import { defaultEndpointsFactory
|
|
1290
|
+
import { defaultEndpointsFactory } from "express-zod-api";
|
|
1291
|
+
import { Documentation } from "express-zod-api/documentation";
|
|
1292
1292
|
|
|
1293
1293
|
// Add similar declaration once, somewhere in your code, preferably near config
|
|
1294
1294
|
declare module "express-zod-api" {
|
|
@@ -1347,12 +1347,8 @@ handling rule for multiple brands, use the exposed types `Depicter` and `Produce
|
|
|
1347
1347
|
```ts
|
|
1348
1348
|
import ts from "typescript";
|
|
1349
1349
|
import { z } from "zod";
|
|
1350
|
-
import {
|
|
1351
|
-
|
|
1352
|
-
Integration,
|
|
1353
|
-
Depicter,
|
|
1354
|
-
Producer,
|
|
1355
|
-
} from "express-zod-api";
|
|
1350
|
+
import { Documentation, type Depicter } from "express-zod-api/documentation";
|
|
1351
|
+
import { Integration, type Producer } from "express-zod-api/integration";
|
|
1356
1352
|
|
|
1357
1353
|
const myBrand = Symbol("MamaToldMeImSpecial"); // I recommend to use symbols for this purpose
|
|
1358
1354
|
const myBrandedSchema = z.string().xBrand(myBrand); // requires Zod Plugin, or .meta({ "x-brand": myBrand })
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { D as ClientMethod, f as Tag } from "./routing-xQnwfH2D.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { ReferenceObject, SchemaObjectValue, TagObject } from "openapi3-ts/oas32";
|
|
4
|
+
interface ReqResCommons {
|
|
5
|
+
makeRef: (key: object | string, value: SchemaObjectValue | ReferenceObject, proposedName?: string) => ReferenceObject;
|
|
6
|
+
path: string;
|
|
7
|
+
method: ClientMethod;
|
|
8
|
+
}
|
|
9
|
+
interface OpenAPIContext extends ReqResCommons {
|
|
10
|
+
isResponse: boolean;
|
|
11
|
+
}
|
|
12
|
+
type Depicter = (
|
|
13
|
+
zodCtx: {
|
|
14
|
+
zodSchema: z.core.$ZodType;
|
|
15
|
+
jsonSchema: z.core.JSONSchema.BaseSchema;
|
|
16
|
+
},
|
|
17
|
+
oasCtx: OpenAPIContext,
|
|
18
|
+
) => z.core.JSONSchema.BaseSchema | SchemaObjectValue;
|
|
19
|
+
/** @desc Using defaultIsHeader when returns null or undefined */
|
|
20
|
+
type IsHeader = (name: string, method: ClientMethod, path: string) => boolean | null | undefined;
|
|
21
|
+
type BrandHandling = Record<string | symbol, Depicter>;
|
|
22
|
+
interface TagDetails extends Pick<TagObject, "summary" | "description" | "externalDocs" | "kind"> {
|
|
23
|
+
/** @desc shorthand for externalDocs.url */
|
|
24
|
+
url?: string;
|
|
25
|
+
parent?: Tag;
|
|
26
|
+
}
|
|
27
|
+
declare const depictTags: (tags: Partial<Record<Tag, string | TagDetails>>) => TagObject[];
|
|
28
|
+
/** @desc Ensures the summary string does not exceed the limit */
|
|
29
|
+
declare const trimSummary: (summary?: string, limit?: number) => string | undefined;
|
|
30
|
+
export { depictTags as a, OpenAPIContext as i, Depicter as n, trimSummary as o, IsHeader as r, BrandHandling as t };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { M as ResponseVariant, g as CommonConfig, t as Routing } from "./routing-xQnwfH2D.js";
|
|
2
|
+
import {
|
|
3
|
+
a as depictTags,
|
|
4
|
+
n as Depicter,
|
|
5
|
+
o as trimSummary,
|
|
6
|
+
r as IsHeader,
|
|
7
|
+
t as BrandHandling,
|
|
8
|
+
} from "./documentation-helpers-CwgXjxwT.js";
|
|
9
|
+
import { InfoObject, OpenApiBuilder, ServerObject } from "openapi3-ts/oas32";
|
|
10
|
+
type Component = `${ResponseVariant}Response` | "requestParameter" | "requestBody";
|
|
11
|
+
/** @desc user defined function that creates a component description from its properties */
|
|
12
|
+
type Descriptor = (
|
|
13
|
+
props: Record<"method" | "path" | "operationId", string> & {
|
|
14
|
+
statusCode?: number;
|
|
15
|
+
},
|
|
16
|
+
) => string;
|
|
17
|
+
type Summarizer = (params: { summary?: string; description?: string; trim: typeof trimSummary }) => string | undefined;
|
|
18
|
+
interface DocumentationParams {
|
|
19
|
+
/**
|
|
20
|
+
* @desc The metadata about the API
|
|
21
|
+
* @default { title: "Generated by Express Zod API", version: "0.0.0" }
|
|
22
|
+
* */
|
|
23
|
+
info?: InfoObject;
|
|
24
|
+
/**
|
|
25
|
+
* @desc Server URL(s) or their complete definitions
|
|
26
|
+
* @default []
|
|
27
|
+
* */
|
|
28
|
+
server?: string | ServerObject | Array<string | ServerObject>;
|
|
29
|
+
routing: Routing;
|
|
30
|
+
config: CommonConfig;
|
|
31
|
+
/**
|
|
32
|
+
* @desc Descriptions of various components based on their properties (method, path, operationId).
|
|
33
|
+
* @desc When composition set to "components", component name is generated from this description
|
|
34
|
+
* @default () => `${method} ${path} ${component}`
|
|
35
|
+
* */
|
|
36
|
+
descriptions?: Partial<Record<Component, Descriptor>>;
|
|
37
|
+
/**
|
|
38
|
+
* @desc The function that ensures the maximum length for summary fields. Can optionally make them from descriptions.
|
|
39
|
+
* @see defaultSummarizer
|
|
40
|
+
* @see trimSummary
|
|
41
|
+
* */
|
|
42
|
+
summarizer?: Summarizer;
|
|
43
|
+
/**
|
|
44
|
+
* @desc Depict the HEAD method for each Endpoint supporting the GET method (feature of Express)
|
|
45
|
+
* @default true
|
|
46
|
+
* */
|
|
47
|
+
hasHeadMethod?: boolean;
|
|
48
|
+
/** @default inline */
|
|
49
|
+
composition?: "inline" | "components";
|
|
50
|
+
/**
|
|
51
|
+
* @desc Handling rules for your own schemas branded with `x-brand` metadata.
|
|
52
|
+
* @desc Keys: brands (recommended to use unique symbols).
|
|
53
|
+
* @desc Values: functions having Zod context as first argument, second one is the framework context.
|
|
54
|
+
* @example { MyBrand: ({ zodSchema, jsonSchema }) => ({ type: "object" })
|
|
55
|
+
* @link https://www.npmjs.com/package/@express-zod-api/zod-plugin
|
|
56
|
+
*/
|
|
57
|
+
brandHandling?: BrandHandling;
|
|
58
|
+
/**
|
|
59
|
+
* @desc Ability to configure recognition of headers among other input data
|
|
60
|
+
* @desc Only applicable when "headers" is present within inputSources config option
|
|
61
|
+
* @see defaultIsHeader
|
|
62
|
+
* @link https://www.iana.org/assignments/http-fields/http-fields.xhtml
|
|
63
|
+
* */
|
|
64
|
+
isHeader?: IsHeader;
|
|
65
|
+
/**
|
|
66
|
+
* @desc Extended description of tags used in endpoints. For enforcing constraints:
|
|
67
|
+
* @see TagOverrides
|
|
68
|
+
* @example { users: "About users", files: { description: "About files", url: "https://example.com" } }
|
|
69
|
+
* */
|
|
70
|
+
tags?: Parameters<typeof depictTags>[0];
|
|
71
|
+
}
|
|
72
|
+
declare class Documentation extends OpenApiBuilder {
|
|
73
|
+
constructor({ hasHeadMethod, ...rest }: DocumentationParams);
|
|
74
|
+
}
|
|
75
|
+
export { type Depicter, Documentation };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{A as e,F as t,G as n,H as r,J as i,K as a,M as o,N as s,O as c,Q as l,U as u,V as d,Y as f,g as p,n as m,o as h,q as g,t as _,v,x as y,z as b}from"./routing-walker-Uax31V_v.js";import{t as x}from"./json-schema-helpers-C1xkaMOk.js";import{z as S}from"zod";import*as C from"ramda";import{OpenApiBuilder as w,isReferenceObject as T,isSchemaObject as E}from"openapi3-ts/oas32";const D=e=>u(e)&&`or`in e,O=e=>u(e)&&`and`in e,k=e=>!O(e)&&!D(e),A=e=>{let n=C.filter(k,e),r=C.chain(C.prop(`and`),C.filter(O,e)),[i,a]=C.partition(k,r),o=C.concat(n,i),s=C.filter(D,e);return C.map(C.prop(`or`),C.concat(s,a)).reduce((e,n)=>t(e,C.map(e=>k(e)?[e]:e.and,n),([e,t])=>C.concat(e,t)),C.reject(C.isEmpty,[o]))},j=(e,t)=>O(e)?C.chain(e=>j(e,t),e.and):D(e)?C.chain(e=>j(e,t),e.or):e.type===t?[e.name]:[],M=(e,t)=>new Set(C.chain(e=>j(e,t),e));let ee;const te=()=>ee??=new Set(`a-im.accept.accept-additions.accept-charset.accept-datetime.accept-encoding.accept-features.accept-language.accept-signature.access-control.access-control-request-headers.access-control-request-method.alpn.alt-used.amp-cache-transform.apply-to-redirect-ref.authorization.available-dictionary.c-ext.c-man.c-opt.c-pep.c-pep-info.cache-control.cal-managed-id.caldav-timezones.capsule-protocol.cdn-loop.cert-not-after.cert-not-before.client-cert.client-cert-chain.close.cmcd-object.cmcd-request.cmcd-session.cmcd-status.cmsd-dynamic.cmsd-static.concealed-auth-export.configuration-context.connection.content-digest.content-disposition.content-encoding.content-id.content-language.content-length.content-location.content-md5.content-range.content-script-type.content-type.cookie.cookie2.cta-common-access-token.dasl.date.dav.default-style.delta-base.deprecation.depth.derived-from.destination.detached-jws.dictionary-id.differential-id.digest.dpop.early-data.ediint-features.expect.expect-ct.ext.forwarded.from.getprofile.hobareg.host.http2-settings.if.if-match.if-modified-since.if-none-match.if-range.if-schedule-tag-match.if-unmodified-since.im.include-referred-token-binding-id.incremental.isolation.keep-alive.label.last-event-id.link.link-template.lock-token.man.max-forwards.memento-datetime.meter.method-check.method-check-expires.mime-version.negotiate.odata-entityid.odata-isolation.odata-maxversion.odata-version.opt.ordering-type.origin.origin-agent-cluster.oscore.oslc-core-version.overwrite.pep.pep-info.permissions-policy.pics-label.ping-from.ping-to.position.pragma.prefer.preference-applied.priority.profileobject.protocol.protocol-info.protocol-query.protocol-request.proxy-authorization.proxy-features.proxy-instruction.range.redirect-ref.referer.referer-root.referrer-policy.repeatability-client-id.repeatability-first-sent.repeatability-request-id.repeatability-result.replay-nonce.reporting-endpoints.repr-digest.safe.schedule-reply.schedule-tag.sec-fetch-storage-access.sec-gpc.sec-purpose.sec-token-binding.sec-websocket-extensions.sec-websocket-key.sec-websocket-protocol.sec-websocket-version.security-scheme.signature.signature-input.slug.soapaction.status-uri.sunset.surrogate-capability.tcn.te.timeout.topic.traceparent.tracestate.trailer.transfer-encoding.ttl.upgrade.urgency.uri.user-agent.variant-vary.via.want-content-digest.want-digest.want-repr-digest.want-unencoded-digest.warning.x-content-type-options.x-frame-options`.split(`.`)),ne={integer:0,number:0,string:``,boolean:!1,object:{},null:null,array:[]},re=e=>e.replace(g,e=>`{${e.slice(1)}}`),ie=({},e)=>{if(e.isResponse)throw new y(`Please use ez.upload() only for input.`,e);return{type:`string`,format:`binary`}},N=({jsonSchema:e})=>({...e,externalDocs:{description:`raw binary data`,url:`https://swagger.io/specification/#working-with-binary-data`}}),P=({zodSchema:e,jsonSchema:t})=>{if(!n(e,`union`)||!(`discriminator`in e._zod.def))return t;let r=e._zod.def.discriminator;return{...t,discriminator:t.discriminator??{propertyName:r}}},F=C.tryCatch(({jsonSchema:e})=>{if(!e.allOf)throw`no allOf`;return x(e,`throw`)},(e,{jsonSchema:t})=>t),I=({jsonSchema:e})=>{if(!e.anyOf||!e.anyOf.length)return e;let t=e.anyOf[0];return Object.assign(t,{type:U(t.type)})},L=e=>e,R=({jsonSchema:e},t)=>{if(t.isResponse)throw new y(`Please use ez.dateOut() for output.`,t);return e},z=({jsonSchema:e},t)=>{if(!t.isResponse)throw new y(`Please use ez.dateIn() for input.`,t);return e},B=()=>({type:`string`,format:`bigint`,pattern:`^-?\\d+$`}),V=({zodSchema:e,jsonSchema:t})=>e._zod.def.rest===null?{...t,items:{not:{}}}:t,H=e=>{let t=Array.isArray(e.type)?e.type[0]:e.type;return ne?.[t]},U=e=>e===`null`?e:typeof e==`string`?[e,`null`]:e&&[...new Set(e).add(`null`)],W=({zodSchema:e,jsonSchema:t},i)=>{let a=e._zod.def[i.isResponse?`out`:`in`],o=e._zod.def[i.isResponse?`in`:`out`];if(!n(a,`transform`))return t;let s=L(X(o,{ctx:i}));if(E(s))if(i.isResponse){let e=r(a,H(s));if(e&&[`number`,`string`,`boolean`].includes(e))return{...t,type:e}}else{let{type:e,...t}=s;return{...t,format:`${t.format||e} (preprocessed)`}}return t},G=({jsonSchema:e})=>{if(e.type!==`object`)return e;let t=e;return!t.properties||!(`raw`in t.properties)||!u(t.properties.raw)?e:t.properties.raw},K=e=>e.length?C.fromPairs(C.zip(C.times(e=>`example${e+1}`,e.length),C.map(C.objOf(`dataValue`),e))):void 0,q=(e,t)=>t?.has(e)||e.startsWith(`x-`)||te().has(e),J=({path:e,method:t,request:n,inputSources:r,makeRef:i,composition:o,isHeader:s,securityHeaders:c,securityCookies:l,description:f=`${t.toUpperCase()} ${e} Parameter`})=>{let p=x(n),m=d(e),h=r.includes(`query`),g=r.includes(`params`),_=r.includes(`headers`),v=r.includes(`cookies`)||r.includes(`signedCookies`),y=n=>{if(g&&m.includes(n))return`path`;if(v&&l?.has(n))return`cookie`;if(_&&(s?.(n,t,e)??q(n,c)))return`header`;if(h&&t!==`query`)return`query`};return Object.entries(p.properties).reduce((e,[t,n])=>{if(!u(n))return e;let r=y(t);if(!r)return e;let s=L(n),c=o===`components`?i(n.id||JSON.stringify(n),s,n.id||a(f,t)):s;return e.concat({name:t,in:r,deprecated:n.deprecated,required:p.required?.includes(t)||!1,description:s.description||f,schema:c,examples:K(E(s)&&s.examples?.length?s.examples:C.pluck(t,p.examples?.filter(C.both(u,C.has(t)))||[]))})},[])},Y={nullable:I,union:P,bigint:B,intersection:F,tuple:V,pipe:W,[e]:R,[c]:z,[v]:ie,[p]:G,[o]:N},ae=(e,t,n)=>{let r=[e,t],i=e=>/schema\d+$/.test(e)?void 0:e;for(let e=0;e<r.length;e++){let a=r[e];if(C.is(Object,a)){if(T(a)&&!a.$ref.startsWith(`#/components`)){let e=a.$ref.split(`/`).pop(),r=t[e];r&&(a.$ref=n.makeRef(r.id||r,L(r),r.id||i(e)).$ref);continue}r.push(...C.values(a))}C.is(Array,a)&&r.push(...C.values(a))}return e},X=(e,{ctx:t,rules:n=Y})=>{let{$defs:r={},properties:i={}}=S.toJSONSchema(S.object({subject:e}),{unrepresentable:`any`,io:t.isResponse?`output`:`input`,override:e=>{let r=s(e.zodSchema),i=n[r&&r in n?r:e.zodSchema._zod.def.type];if(i){let n={...i(e,t)};for(let t in e.jsonSchema)delete e.jsonSchema[t];Object.assign(e.jsonSchema,n)}}});return ae(u(i.subject)?i.subject:{},r,t)},Z=(e,t)=>{if(T(e))return[e,!1];let n=!1,r=C.map(e=>{let[r,i]=Z(e,t);return n||=i,r}),i=C.omit(t),a={properties:i,examples:C.map(i),required:C.without(t),allOf:r,oneOf:r,anyOf:r},o=C.evolve(a,e);return[o,n||!!o.required?.length]},oe=({method:e,path:t,schema:n,mimeTypes:r,variant:o,makeRef:s,composition:c,hasMultipleStatusCodes:u,statusCode:d,brandHandling:p,description:m=`${e.toUpperCase()} ${t} ${f(o)} response ${u?d:``}`.trim()})=>{if(!i(e,r))return{description:m};let h=L(X(n,{rules:{...p,...Y},ctx:{isResponse:!0,makeRef:s,path:t,method:e}})),g=[];E(h)&&h.examples&&(g.push(...h.examples),delete h.examples);let _=c===`components`?s(n,h,a(m)):h;return{description:m,content:C.fromPairs(r.map(e=>[e,{[e===l.sse?`itemSchema`:`schema`]:_,examples:K(g)}]))}},se=({format:e})=>{let t={type:`http`,scheme:`bearer`};return e&&(t.bearerFormat=e),t},ce=({name:e},t)=>{let n={type:`apiKey`,in:`query`,name:e};return t?.includes(`body`)&&(t?.includes(`query`)?(n[`x-in-alternative`]=`body`,n.description=`${e} CAN also be supplied within the request body`):(n[`x-in-actual`]=`body`,n.description=`${e} MUST be supplied within the request body instead of query`)),n},le=({name:e})=>({type:`apiKey`,in:`header`,name:e}),ue=({name:e})=>({type:`apiKey`,in:`cookie`,name:e}),de=({url:e})=>({type:`openIdConnect`,openIdConnectUrl:e}),fe=({flows:e={},oauth2MetadataUrl:t})=>({type:`oauth2`,flows:C.map(e=>({...e,scopes:e.scopes||{}}),C.reject(C.isNil,e)),oauth2MetadataUrl:t}),pe=(e,t=[])=>{let n=e=>e.type===`basic`?{type:`http`,scheme:`basic`}:e.type===`bearer`?se(e):e.type===`input`?ce(e,t):e.type===`header`?le(e):e.type===`cookie`?ue(e):e.type===`openid`?de(e):fe(e);return e.map(e=>e.map(({deprecated:e,...t})=>({...n(t),deprecated:e})))},me=(e,t,n)=>e.map(e=>e.reduce((e,r)=>{let i=n(r),a=[`oauth2`,`openIdConnect`].includes(r.type);return Object.assign(e,{[i]:a?t:[]})},{})),Q=({schema:e,brandHandling:t,makeRef:n,path:r,method:i})=>X(e,{rules:{...t,...Y},ctx:{isResponse:!1,makeRef:n,path:r,method:i}}),he=({method:e,path:t,schema:n,request:r,mimeType:i,makeRef:o,composition:s,paramNames:c,description:d=`${e.toUpperCase()} ${t} Request body`})=>{let[f,p]=Z(r,c),m=L(f),h=[];E(m)&&m.examples&&(h.push(...m.examples),delete m.examples);let g={schema:s===`components`?o(n,m,a(d)):m,examples:K(h.length?h:x(r).examples?.filter(e=>u(e)&&!Array.isArray(e)).map(C.omit(c))||[])},_={description:d,content:{[i]:g}};return(p||i===l.raw)&&(_.required=!0),_},ge=e=>Object.entries(e).reduce((e,[t,n])=>{if(!n)return e;if(typeof n==`string`)return e.concat({name:t,description:n});let{url:r,...i}=n,a={...i,name:t};return r&&(a.externalDocs={...a.externalDocs,url:r}),e.concat(a)},[]),_e=(e,t=50)=>!e||e.length<=t?e:e.slice(0,Math.max(1,t||0)-1)+`…`,$=e=>e.length?e.slice():void 0,ve=({description:e,summary:t=e,trim:n})=>n(t);var ye=class extends w{#e=new Map;#t=new Map;#n=new Map;#r(e,t,n){let r=this.#n.get(e);if(!r){let t=+!n;do r=`${n??`Schema`}${t?this.#n.size+t:``}`,t++;while(this.rootDoc.components?.schemas?.[r]);this.#n.set(e,r)}return this.addSchema(r,t),{$ref:`#/components/schemas/${r}`}}#i(e,t,n){let r=n||a(t,e),i=this.#t.get(r);if(i===void 0)return this.#t.set(r,1),r;if(n)throw new y(`Duplicated operationId: "${n}"`,{method:t,isResponse:!1,path:e});return i++,this.#t.set(r,i),`${r}${i}`}#a(e){let t=JSON.stringify(e);for(let e in this.rootDoc.components?.securitySchemes||{})if(t===JSON.stringify(this.rootDoc.components?.securitySchemes?.[e]))return e;let n=(this.#e.get(e.type)||0)+1;return this.#e.set(e.type,n),`${e.type.toUpperCase()}_${n}`}#o({tags:e,server:t,info:n={title:`Generated by Express Zod API`,version:`0.0.0`}}){if(this.addInfo(n),e&&(this.rootDoc.tags=ge(e)),t)for(let e of Array.isArray(t)?t:[t])this.addServer(typeof e==`string`?{url:e}:e)}#s({config:e,descriptions:t,brandHandling:n,isHeader:r,summarizer:i=ve,composition:a=`inline`}){return(o,s,c)=>{let u={path:s,method:o,endpoint:c,composition:a,brandHandling:n,makeRef:this.#r.bind(this)},{description:d,summary:f,scopes:p,inputSchema:m}=c,g=b(o,e.inputSources),_=this.#i(s,o,c.getOperationId(o)),v=Q({...u,schema:m}),y=J({...u,inputSources:g,isHeader:r,securityHeaders:M(c.security,`header`),securityCookies:M(c.security,`cookie`),request:v,description:t?.requestParameter?.({method:o,path:s,operationId:_})}),x={};for(let e of h){let n=c.getResponses(e);for(let{mimeTypes:r,schema:i,statusCodes:a}of n)for(let c of a)x[c]=oe({...u,variant:e,schema:i,mimeTypes:r,statusCode:c,hasMultipleStatusCodes:n.length>1||a.length>1,description:t?.[`${e}Response`]?.({method:o,path:s,operationId:_,statusCode:c})})}let S=g.includes(`body`)?he({...u,request:v,paramNames:C.pluck(`name`,y),schema:m,mimeType:l[c.getProbableRequestType(o)],description:t?.requestBody?.({method:o,path:s,operationId:_})}):void 0,w=me(pe(A(c.security),g),p,e=>{let t=this.#a(e);return this.addSecurityScheme(t,e),t}),T={operationId:_,summary:i({summary:f,description:d,trim:_e}),description:d,deprecated:c.isDeprecated||void 0,tags:$(c.tags),parameters:$(y),requestBody:S,security:$(w),responses:x};this.addPath(re(s),{[o]:T})}}constructor({hasHeadMethod:e=!0,...t}){super(),this.#o(t);let n=this.#s(t),r=e?m(n):n;_({...t,onEndpoint:r})}};export{ye as Documentation};
|