galbe 0.2.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,264 @@
1
+ import type { STArray, STJson, STLiteral, STObject, STProps, STSchema, STUnion } from '../../../src/schema'
2
+
3
+ import { Galbe } from '../../../src'
4
+ import { walkRoutes, HttpStatus } from '../../../src/util'
5
+ import { Kind, Optional } from '../../../src/schema'
6
+
7
+ import { OpenAPIV3 } from 'openapi-types'
8
+
9
+ type SchemaType = { type: string; format: string; isJson: boolean }
10
+
11
+ const schemaToMedia = ({ type, format, isJson }: SchemaType) =>
12
+ isJson || (type && ['object', 'number', 'boolean', 'array'].includes(type))
13
+ ? 'application/json'
14
+ : format === 'byte'
15
+ ? 'application/octet-stream'
16
+ : type === 'string'
17
+ ? 'text/plain'
18
+ : '*/*'
19
+
20
+ export const OpenAPISerializer = async (g: Galbe, version = '3.0.3'): Promise<OpenAPIV3.Document> => {
21
+ let paths: any = {}
22
+ let components: OpenAPIV3.ComponentsObject = {
23
+ securitySchemes: {},
24
+ schemas: {},
25
+ parameters: {},
26
+ requestBodies: {},
27
+ responses: {}
28
+ }
29
+
30
+ const schemaToOpenapi = (
31
+ schema: STSchema
32
+ ): { schema: OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject; isJson?: boolean } => {
33
+ let s = {}
34
+ let kind = schema[Kind]
35
+ let isJson = false
36
+
37
+ let pattern = schema?.pattern?.toString()
38
+ if (pattern) pattern = pattern.substring(1, pattern.length - 1)
39
+
40
+ let minLength = schema?.minLength
41
+ let maxLength = schema?.maxLength
42
+ let minimum = schema?.min
43
+ let maximum = schema?.max
44
+ let exclusiveMinimum = schema?.exclusiveMin
45
+ let exclusiveMaximum = schema?.exclusiveMax
46
+ let minItems = schema?.minItems
47
+ let maxItems = schema?.maxItems
48
+ let uniqueItems = schema?.unique
49
+
50
+ if (components.schemas && (schema.id as string) in components.schemas) {
51
+ //@ts-ignore
52
+ return { schema: { $ref: `#/components/schemas/${schema.id}` } }
53
+ }
54
+ // TODO add constraints min, max etc.
55
+ if (kind === 'boolean') s = { type: 'boolean' }
56
+ else if (kind === 'byteArray') s = { type: 'string', format: 'byte' }
57
+ else if (kind === 'number')
58
+ s = {
59
+ type: 'number',
60
+ ...(exclusiveMinimum ? { exclusiveMinimum } : {}),
61
+ ...(exclusiveMaximum ? { exclusiveMaximum } : {}),
62
+ ...(minimum ? { minimum } : {}),
63
+ ...(maximum ? { maximum } : {})
64
+ }
65
+ else if (kind === 'integer')
66
+ s = {
67
+ type: 'integer',
68
+ ...(exclusiveMinimum ? { exclusiveMinimum } : {}),
69
+ ...(exclusiveMaximum ? { exclusiveMaximum } : {}),
70
+ ...(minimum ? { minimum } : {}),
71
+ ...(maximum ? { maximum } : {})
72
+ }
73
+ else if (kind === 'string')
74
+ s = {
75
+ type: 'string',
76
+ ...(pattern ? { pattern } : {}),
77
+ ...(minLength ? { minLength } : {}),
78
+ ...(maxLength ? { maxLength } : {})
79
+ }
80
+ else if (kind === 'any') s = { type: 'string' }
81
+ else if (kind === 'literal') {
82
+ let value = (schema as STLiteral).value
83
+ s = { type: 'string', enum: [value] }
84
+ } else if (kind === 'array') {
85
+ s = {
86
+ type: 'array',
87
+ items: schemaToOpenapi((schema as STArray).items).schema,
88
+ ...(minItems ? { minItems } : {}),
89
+ ...(maxItems ? { maxItems } : {}),
90
+ ...(uniqueItems ? { uniqueItems } : {})
91
+ }
92
+ } else if (kind === 'object') {
93
+ let props = (schema as STObject).props || {}
94
+ let required = Object.entries(props)
95
+ .filter(([_, v]) => !v?.[Optional])
96
+ .map(([k, _]) => k)
97
+ s = {
98
+ type: 'object',
99
+ properties: Object.fromEntries(Object.entries(props).map(([k, v]) => [k, schemaToOpenapi(v).schema])),
100
+ ...(required.length ? { required } : {})
101
+ }
102
+ } else if (kind === 'json') {
103
+ let props = ((schema as STJson).props || {}) as STProps
104
+ let type = (schema as STJson).type
105
+ if (type === 'unknown') type = 'object'
106
+ let required = Object.entries(props)
107
+ .filter(([_, v]) => !v?.[Optional])
108
+ .map(([k, _]) => k)
109
+ isJson = true
110
+ s = {
111
+ type: type,
112
+ ...(type === 'object'
113
+ ? {
114
+ properties: Object.fromEntries(Object.entries(props).map(([k, v]) => [k, schemaToOpenapi(v).schema])),
115
+ ...(required.length ? { required } : {})
116
+ }
117
+ : {})
118
+ }
119
+ } else if (kind === 'union') {
120
+ let anyOf = (schema as STUnion).anyOf
121
+ s = {
122
+ anyOf: anyOf.map(s => schemaToOpenapi(s).schema)
123
+ }
124
+ }
125
+ s = { title: schema.title, description: schema.description, ...s }
126
+ if (components.schemas && schema.id) {
127
+ components.schemas[schema.id] = s
128
+ return { schema: { $ref: `#/components/schemas/${schema.id}` } }
129
+ }
130
+ return { schema: s, isJson }
131
+ }
132
+
133
+ const resolveRef = (schema: OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject): OpenAPIV3.SchemaObject => {
134
+ if (!(schema as OpenAPIV3.ReferenceObject)?.$ref) return schema as OpenAPIV3.SchemaObject
135
+ let ref = (schema as OpenAPIV3.ReferenceObject)?.$ref
136
+ let match = ref.match('^#/components/(schemas|requestBodies|responses)/(.*)$')
137
+ if (!match) throw new Error(`Invalid schema ref ${ref}`)
138
+ let [_, kind, refPath] = match as [string, keyof typeof components, string]
139
+ //@ts-ignore
140
+ return refPath.split('/').reduce((c, k) => {
141
+ if (c && k in c) return c[k]
142
+ else return undefined
143
+ }, components[kind])
144
+ }
145
+
146
+ const parseParam = (key: string, param: STSchema, kind: 'query' | 'header' | 'path' | 'cookie') => {
147
+ let { schema } = schemaToOpenapi({ ...param, [Optional]: false })
148
+ let p: OpenAPIV3.ParameterObject = {
149
+ name: key,
150
+ in: kind,
151
+ description: param?.description,
152
+ required: kind === 'path' ? true : !param[Optional] || undefined,
153
+ deprecated: param.deprecated,
154
+ schema
155
+ }
156
+ if (components.parameters && param.id) components.parameters[param.id] = p
157
+ return p
158
+ }
159
+
160
+ const metaRoutes = g.meta?.reduce(
161
+ (routes, c) => ({ ...routes, ...c.routes }),
162
+ {} as Record<string, Record<string, Record<string, any>>>
163
+ )
164
+ walkRoutes(g.router.routes, r => {
165
+ let meta = metaRoutes?.[r.path]?.[r.method]
166
+ let path = r.path.replaceAll(/:([^\/]+)/g, '{$1}')
167
+ if (!(path in paths)) paths[path] = {}
168
+ let tags = [...(meta?.tags?.split(' ')?.map((t: string) => t.trim()) || []), ...(meta?.tag || [])]
169
+ let security: Record<string, any> = []
170
+
171
+ let pathParam = r.schema?.params
172
+ ? Object.entries(r.schema?.params as Record<string, STSchema>).map(([k, v]) => parseParam(k, v, 'path'))
173
+ : []
174
+ let queryParam = r.schema?.query
175
+ ? Object.entries(r.schema?.query as Record<string, STSchema>).map(([k, v]) => parseParam(k, v, 'query'))
176
+ : []
177
+ let headerParam = r.schema?.headers
178
+ ? Object.entries(r.schema?.headers as Record<string, STSchema>)
179
+ .map(([k, v]) => {
180
+ let p = parseParam(k, v, 'header')
181
+ if (k.match(/authorization/i)) {
182
+ // TODO: handle other auth methods
183
+ if (v.pattern && v?.pattern?.toString() === '/^Bearer /') {
184
+ security.push({ bearerAuth: [] })
185
+ components.securitySchemes = { bearerAuth: { type: 'http', scheme: 'bearer' } }
186
+ return null
187
+ }
188
+ }
189
+ return p
190
+ })
191
+ .filter(p => p)
192
+ : []
193
+ // TODO cookieParam
194
+ let parameters = [...pathParam, ...queryParam, ...headerParam]
195
+
196
+ let requestBody
197
+ if (r.schema.body) {
198
+ let { schema, isJson } = schemaToOpenapi(r.schema.body)
199
+ let { type, format } = resolveRef(schema)
200
+ let media = schemaToMedia({ type, format, isJson } as SchemaType)
201
+ requestBody = {
202
+ description: r.schema.body.description,
203
+ required: !r.schema.body[Optional],
204
+ content: {
205
+ [media]: { schema }
206
+ }
207
+ }
208
+ if (r.schema.body.id && components.requestBodies) {
209
+ components.requestBodies[r.schema.body.id] = requestBody
210
+ requestBody = { $ref: `#/components/requestBodies/${r.schema.body.id}` }
211
+ }
212
+ }
213
+ let responses
214
+ if (r.schema.response && Object.keys(r.schema.response).length) {
215
+ responses = Object.fromEntries(
216
+ Object.entries(r.schema.response).map(([status, v]) => {
217
+ let s = Number(status) as keyof typeof HttpStatus
218
+ let { schema, isJson } = schemaToOpenapi(v)
219
+ let { type, format } = resolveRef(schema)
220
+ let media = schemaToMedia({ type, format, isJson } as SchemaType)
221
+ let response: OpenAPIV3.ResponseObject = {
222
+ description: v.description || HttpStatus[Number(s) as keyof typeof HttpStatus] || 'Response',
223
+ content: { [media]: { schema: schema } }
224
+ }
225
+ if (components.responses && r.schema.response?.[s].id) {
226
+ components.responses[r.schema.response?.[s].id as string] = response
227
+ //@ts-ignore
228
+ response = { $ref: `#/components/responses/${r.schema.response?.[s].id}` }
229
+ }
230
+ return [s, response]
231
+ })
232
+ )
233
+ } else {
234
+ responses = {
235
+ default: { description: HttpStatus[200] }
236
+ }
237
+ }
238
+ paths[path][r.method] = {
239
+ tags: tags.length ? tags : undefined,
240
+ summary: meta?.head,
241
+ operationId: meta?.operationId,
242
+ parameters: parameters.length ? parameters : undefined,
243
+ requestBody,
244
+ responses,
245
+ ...(security.length ? { security } : {}),
246
+ deprecated: meta?.deprecated ? true : undefined
247
+ }
248
+ })
249
+
250
+ //@ts-ignore
251
+ components = Object.entries(components).reduce((p, [k, v]) => {
252
+ if (Object.keys(v).length) p[k] = v
253
+ return p
254
+ }, {} as Record<string, OpenAPIV3.ComponentsObject>)
255
+ return {
256
+ openapi: version,
257
+ info: {
258
+ title: 'Galbe app',
259
+ version: '0.1.0'
260
+ },
261
+ paths,
262
+ components: Object.keys(components)?.length ? components : undefined
263
+ }
264
+ }
package/src/extras.ts ADDED
@@ -0,0 +1 @@
1
+ export { OpenAPISerializer } from './extras/spec/openapi.serializer'
package/src/index.ts CHANGED
@@ -11,6 +11,7 @@ import type {
11
11
  ErrorHandler,
12
12
  GalbePlugin,
13
13
  STBody,
14
+ STResponse,
14
15
  STParams,
15
16
  STHeaders,
16
17
  STQuery
@@ -18,26 +19,28 @@ import type {
18
19
 
19
20
  import server from './server'
20
21
  import { GalbeRouter } from './router'
21
- import { defineRoutes } from './routes'
22
- import { logRoute } from './util'
23
22
  import { SchemaType, type STObject, type Static } from './schema'
24
23
 
25
24
  const overloadDiscriminer = <
25
+ M extends Method,
26
26
  Path extends string,
27
27
  H extends STHeaders,
28
28
  P extends Partial<STParams<Path>>,
29
29
  Q extends STQuery,
30
- B extends STBody
30
+ B extends STBody,
31
+ R extends STResponse
31
32
  >(
32
33
  galbe: Galbe,
33
- method: Method,
34
+ method: M,
34
35
  path: Path,
35
36
  arg2:
36
- | RequestSchema<Path, H, P, Q, B>
37
- | Hook<Path, RequestSchema<Path, H, P, Q, B>>[]
38
- | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
39
- arg3?: Hook<Path, RequestSchema<Path, H, P, Q, B>>[] | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
40
- arg4?: Handler<Path, RequestSchema<Path, H, P, Q, B>>
37
+ | RequestSchema<M, Path, H, P, Q, B, R>
38
+ | Hook<M, Path, RequestSchema<M, Path, H, P, Q, B, R>>[]
39
+ | Handler<M, Path, RequestSchema<M, Path, H, P, Q, B, R>>,
40
+ arg3?:
41
+ | Hook<M, Path, RequestSchema<M, Path, H, P, Q, B, R>>[]
42
+ | Handler<M, Path, RequestSchema<M, Path, H, P, Q, B, R>>,
43
+ arg4?: Handler<M, Path, RequestSchema<M, Path, H, P, Q, B, R>>
41
44
  ) => {
42
45
  const defaultSchema = {}
43
46
  if (typeof arg2 === 'function') {
@@ -53,26 +56,31 @@ const overloadDiscriminer = <
53
56
  throw new Error('Undefined route signature')
54
57
  }
55
58
  const galbeMethod = <
59
+ M extends Method,
56
60
  Path extends string,
57
61
  H extends STHeaders,
58
62
  P extends Partial<STParams<Path>>,
59
63
  Q extends STQuery,
60
- B extends STBody
64
+ B extends STBody,
65
+ R extends STResponse
61
66
  >(
62
67
  _galbe: Galbe,
63
- method: Method,
68
+ method: M,
64
69
  path: Path,
65
- schema: RequestSchema<Path, H, P, Q, B> | undefined,
66
- hooks: Hook<Path, RequestSchema<Path, H, P, Q, B>>[] | undefined,
67
- handler: Handler<Path, RequestSchema<Path, H, P, Q, B>>
70
+ schema: RequestSchema<M, Path, H, P, Q, B, R> | undefined,
71
+ hooks: Hook<M, Path, RequestSchema<M, Path, H, P, Q, B, R>>[] | undefined,
72
+ handler: Handler<M, Path, RequestSchema<M, Path, H, P, Q, B, R>>
68
73
  ) => {
69
74
  schema = schema ?? {}
70
75
  hooks = hooks || []
71
- const context: Context<Path, typeof schema> = {
76
+ const context: Context<M, Path, typeof schema> = {
72
77
  headers: {} as Static<STObject<Exclude<(typeof schema)['headers'], undefined>>>,
73
78
  params: {} as any,
74
79
  query: {} as Static<STObject<Exclude<(typeof schema)['query'], undefined>>>,
75
- body: {} as Static<Exclude<(typeof schema)['body'], undefined>>,
80
+ //@ts-ignore
81
+ body: ['get', 'options', 'head'].includes(method)
82
+ ? null
83
+ : ({} as Static<Exclude<(typeof schema)['body'], undefined>>),
76
84
  request: {} as Request,
77
85
  state: {},
78
86
  set: {} as {
@@ -92,11 +100,11 @@ const galbeMethod = <
92
100
  }
93
101
  }
94
102
 
103
+ /** Galbe Schema Type builder. See {@link https://galbe.dev/documentation/schemas#schema-types Schema Types} */
95
104
  export const $T = new SchemaType()
96
105
 
97
106
  export { RequestError } from './types'
98
107
 
99
- const indexRoutes: { method: string; path: string }[] = []
100
108
  /**
101
109
  * #### Galbe Server
102
110
  * Instanciate a Galbe web server
@@ -116,7 +124,6 @@ export class Galbe {
116
124
  router: GalbeRouter
117
125
  errorHandler?: ErrorHandler
118
126
  listening: boolean = false
119
- #prepare: boolean = false
120
127
  server?: Server
121
128
  plugins: GalbePlugin[] = []
122
129
  constructor(config?: GalbeConfig) {
@@ -126,35 +133,32 @@ export class Galbe {
126
133
  prefix: this.config?.basePath || '',
127
134
  cacheEnabled: this.config?.router?.cacheEnabled
128
135
  })
136
+ this.config.requestValidator = config?.requestValidator ?? { enabled: true }
137
+ this.config.responseValidator = config?.responseValidator ?? { enabled: true }
129
138
  }
130
139
  private add(route: any) {
131
140
  this.router.add(route)
132
- if (Bun.env.BUN_ENV === 'development') {
133
- if (!this.#prepare) indexRoutes.push({ method: route.method, path: route.path })
134
- else logRoute(route)
135
- }
141
+ return route
136
142
  }
137
143
  async use(plugin: GalbePlugin) {
138
144
  this.plugins.push(plugin)
139
145
  }
146
+ async init() {
147
+ for (const p of this.plugins) {
148
+ if (p.init) await p.init(this.config?.plugin?.[p.name] || {}, this)
149
+ }
150
+ }
140
151
  async listen(port?: number) {
141
152
  port = port || this.config?.port || 3000
142
153
  this.config.port = port
143
154
  if (this.listening) this.stop()
155
+ await this.init()
156
+ this.server = await server(this, port)
144
157
  if (Bun.env.BUN_ENV === 'development') {
145
- this.#prepare = true
146
- console.log('🏗️ \x1b[1;30mConstructing routes\x1b[0m')
147
- for (const r of indexRoutes) logRoute(r)
148
- await defineRoutes(this.config || {}, this)
149
- console.log('\n✅ \x1b[1;30mdone\x1b[0m')
150
- this.server = await server(this, port)
151
158
  const url = `http://localhost:${port}${this.config?.basePath || ''}`
152
- console.log(`\n\x1b[1;30m🚀 API running at\x1b[0m \x1b[4;34m${url}\x1b[0m`)
153
- } else {
154
- this.server = await server(this, port)
159
+ console.log(`\x1b[1;30m🚀 Server running at\x1b[0m \x1b[4;34m${url}\x1b[0m\n`)
155
160
  }
156
161
  this.listening = true
157
- this.#prepare = false
158
162
  return this.server
159
163
  }
160
164
  stop() {
@@ -163,96 +167,134 @@ export class Galbe {
163
167
  onError(handler: ErrorHandler) {
164
168
  this.errorHandler = handler
165
169
  }
166
- get: Endpoint = <
170
+ get: Endpoint<'get'> = <
167
171
  Path extends string,
168
- H extends STHeaders,
169
172
  P extends Partial<STParams<Path>>,
173
+ H extends STHeaders,
170
174
  Q extends STQuery,
171
- B extends STBody
175
+ B extends undefined,
176
+ R extends STResponse
172
177
  >(
173
178
  path: Path,
174
179
  arg2:
175
- | RequestSchema<Path, H, P, Q, B>
176
- | Hook<Path, RequestSchema<Path, H, P, Q, B>>[]
177
- | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
178
- arg3?: Hook<Path, RequestSchema<Path, H, P, Q, B>>[] | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
179
- arg4?: Handler<Path, RequestSchema<Path, H, P, Q, B>>
180
+ | RequestSchema<'get', Path, H, P, Q, B, R>
181
+ | Hook<'get', Path, RequestSchema<'get', Path, H, P, Q, B, R>>[]
182
+ | Handler<'get', Path, RequestSchema<'get', Path, H, P, Q, B, R>>,
183
+ arg3?:
184
+ | Hook<'get', Path, RequestSchema<'get', Path, H, P, Q, B, R>>[]
185
+ | Handler<'get', Path, RequestSchema<'get', Path, H, P, Q, B, R>>,
186
+ arg4?: Handler<'get', Path, RequestSchema<'get', Path, H, P, Q, B, R>>
187
+ //@ts-ignore
180
188
  ) => this.add(overloadDiscriminer(this, 'get', path, arg2, arg3, arg4))
181
- post: Endpoint = <
189
+ post: Endpoint<'post'> = <
182
190
  Path extends string,
183
- H extends STHeaders,
184
191
  P extends Partial<STParams<Path>>,
192
+ H extends STHeaders,
185
193
  Q extends STQuery,
186
- B extends STBody
194
+ B extends STBody,
195
+ R extends STResponse
187
196
  >(
188
197
  path: Path,
189
198
  arg2:
190
- | RequestSchema<Path, H, P, Q, B>
191
- | Hook<Path, RequestSchema<Path, H, P, Q, B>>[]
192
- | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
193
- arg3?: Hook<Path, RequestSchema<Path, H, P, Q, B>>[] | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
194
- arg4?: Handler<Path, RequestSchema<Path, H, P, Q, B>>
199
+ | RequestSchema<'post', Path, H, P, Q, B, R>
200
+ | Hook<'post', Path, RequestSchema<'post', Path, H, P, Q, B, R>>[]
201
+ | Handler<'post', Path, RequestSchema<'post', Path, H, P, Q, B, R>>,
202
+ arg3?:
203
+ | Hook<'post', Path, RequestSchema<'post', Path, H, P, Q, B, R>>[]
204
+ | Handler<'post', Path, RequestSchema<'post', Path, H, P, Q, B, R>>,
205
+ arg4?: Handler<'post', Path, RequestSchema<'post', Path, H, P, Q, B, R>>
206
+ //@ts-ignore
195
207
  ) => this.add(overloadDiscriminer(this, 'post', path, arg2, arg3, arg4))
196
- put: Endpoint = <
208
+ put: Endpoint<'put'> = <
197
209
  Path extends string,
198
- H extends STHeaders,
199
210
  P extends Partial<STParams<Path>>,
211
+ H extends STHeaders,
200
212
  Q extends STQuery,
201
- B extends STBody
213
+ B extends STBody,
214
+ R extends STResponse
202
215
  >(
203
216
  path: Path,
204
217
  arg2:
205
- | RequestSchema<Path, H, P, Q, B>
206
- | Hook<Path, RequestSchema<Path, H, P, Q, B>>[]
207
- | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
208
- arg3?: Hook<Path, RequestSchema<Path, H, P, Q, B>>[] | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
209
- arg4?: Handler<Path, RequestSchema<Path, H, P, Q, B>>
218
+ | RequestSchema<'put', Path, H, P, Q, B, R>
219
+ | Hook<'put', Path, RequestSchema<'put', Path, H, P, Q, B, R>>[]
220
+ | Handler<'put', Path, RequestSchema<'put', Path, H, P, Q, B, R>>,
221
+ arg3?:
222
+ | Hook<'put', Path, RequestSchema<'put', Path, H, P, Q, B, R>>[]
223
+ | Handler<'put', Path, RequestSchema<'put', Path, H, P, Q, B, R>>,
224
+ arg4?: Handler<'put', Path, RequestSchema<'put', Path, H, P, Q, B, R>>
210
225
  ) => this.add(overloadDiscriminer(this, 'put', path, arg2, arg3, arg4))
211
- patch: Endpoint = <
226
+ patch: Endpoint<'patch'> = <
212
227
  Path extends string,
213
- H extends STHeaders,
214
228
  P extends Partial<STParams<Path>>,
229
+ H extends STHeaders,
215
230
  Q extends STQuery,
216
- B extends STBody
231
+ B extends STBody,
232
+ R extends STResponse
217
233
  >(
218
234
  path: Path,
219
235
  arg2:
220
- | RequestSchema<Path, H, P, Q, B>
221
- | Hook<Path, RequestSchema<Path, H, P, Q, B>>[]
222
- | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
223
- arg3?: Hook<Path, RequestSchema<Path, H, P, Q, B>>[] | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
224
- arg4?: Handler<Path, RequestSchema<Path, H, P, Q, B>>
236
+ | RequestSchema<'patch', Path, H, P, Q, B, R>
237
+ | Hook<'patch', Path, RequestSchema<'patch', Path, H, P, Q, B, R>>[]
238
+ | Handler<'patch', Path, RequestSchema<'patch', Path, H, P, Q, B, R>>,
239
+ arg3?:
240
+ | Hook<'patch', Path, RequestSchema<'patch', Path, H, P, Q, B, R>>[]
241
+ | Handler<'patch', Path, RequestSchema<'patch', Path, H, P, Q, B, R>>,
242
+ arg4?: Handler<'patch', Path, RequestSchema<'patch', Path, H, P, Q, B, R>>
225
243
  ) => this.add(overloadDiscriminer(this, 'patch', path, arg2, arg3, arg4))
226
- delete: Endpoint = <
244
+ delete: Endpoint<'delete'> = <
227
245
  Path extends string,
228
- H extends STHeaders,
229
246
  P extends Partial<STParams<Path>>,
247
+ H extends STHeaders,
230
248
  Q extends STQuery,
231
- B extends STBody
249
+ B extends STBody,
250
+ R extends STResponse
232
251
  >(
233
252
  path: Path,
234
253
  arg2:
235
- | RequestSchema<Path, H, P, Q, B>
236
- | Hook<Path, RequestSchema<Path, H, P, Q, B>>[]
237
- | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
238
- arg3?: Hook<Path, RequestSchema<Path, H, P, Q, B>>[] | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
239
- arg4?: Handler<Path, RequestSchema<Path, H, P, Q, B>>
254
+ | RequestSchema<'delete', Path, H, P, Q, B, R>
255
+ | Hook<'delete', Path, RequestSchema<'delete', Path, H, P, Q, B, R>>[]
256
+ | Handler<'delete', Path, RequestSchema<'delete', Path, H, P, Q, B, R>>,
257
+ arg3?:
258
+ | Hook<'delete', Path, RequestSchema<'delete', Path, H, P, Q, B, R>>[]
259
+ | Handler<'delete', Path, RequestSchema<'delete', Path, H, P, Q, B, R>>,
260
+ arg4?: Handler<'delete', Path, RequestSchema<'delete', Path, H, P, Q, B, R>>
240
261
  ) => this.add(overloadDiscriminer(this, 'delete', path, arg2, arg3, arg4))
241
- options: Endpoint = <
262
+ options: Endpoint<'options'> = <
242
263
  Path extends string,
243
- H extends STHeaders,
244
264
  P extends Partial<STParams<Path>>,
265
+ H extends STHeaders,
245
266
  Q extends STQuery,
246
- B extends STBody
267
+ B extends STBody,
268
+ R extends STResponse
247
269
  >(
248
270
  path: Path,
249
271
  arg2:
250
- | RequestSchema<Path, H, P, Q, B>
251
- | Hook<Path, RequestSchema<Path, H, P, Q, B>>[]
252
- | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
253
- arg3?: Hook<Path, RequestSchema<Path, H, P, Q, B>>[] | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
254
- arg4?: Handler<Path, RequestSchema<Path, H, P, Q, B>>
272
+ | RequestSchema<'options', Path, H, P, Q, B, R>
273
+ | Hook<'options', Path, RequestSchema<'options', Path, H, P, Q, B, R>>[]
274
+ | Handler<'options', Path, RequestSchema<'options', Path, H, P, Q, B, R>>,
275
+ arg3?:
276
+ | Hook<'options', Path, RequestSchema<'options', Path, H, P, Q, B, R>>[]
277
+ | Handler<'options', Path, RequestSchema<'options', Path, H, P, Q, B, R>>,
278
+ arg4?: Handler<'options', Path, RequestSchema<'options', Path, H, P, Q, B, R>>
255
279
  ) => this.add(overloadDiscriminer(this, 'options', path, arg2, arg3, arg4))
280
+ head: Endpoint<'head'> = <
281
+ Path extends string,
282
+ P extends Partial<STParams<Path>>,
283
+ H extends STHeaders,
284
+ Q extends STQuery,
285
+ B extends STBody,
286
+ R extends STResponse
287
+ >(
288
+ path: Path,
289
+ arg2:
290
+ | RequestSchema<'head', Path, H, P, Q, B, R>
291
+ | Hook<'head', Path, RequestSchema<'head', Path, H, P, Q, B, R>>[]
292
+ | Handler<'head', Path, RequestSchema<'head', Path, H, P, Q, B, R>>,
293
+ arg3?:
294
+ | Hook<'head', Path, RequestSchema<'head', Path, H, P, Q, B, R>>[]
295
+ | Handler<'head', Path, RequestSchema<'head', Path, H, P, Q, B, R>>,
296
+ arg4?: Handler<'head', Path, RequestSchema<'head', Path, H, P, Q, B, R>>
297
+ ) => this.add(overloadDiscriminer(this, 'head', path, arg2, arg3, arg4))
256
298
  }
257
299
 
258
300
  export * from './types'