galbe 0.1.6 → 0.1.8

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,240 @@
1
+ # Shemas
2
+
3
+ Galbe provides a custom Schema Type processor that offers type safety, data parsing, and validation. The primary purpose of this feature is to simplify request input validation and error handling automatically. Additionally, it enhances the developer's experience by inferring static TypeScript types from schema definitions.
4
+
5
+ ## Schema Types
6
+
7
+ To start using Schema definitions, import `$T` from the `galbe` library:
8
+
9
+ ```js
10
+ import { $T } from 'galbe'
11
+ ```
12
+
13
+ Here the list of available Schema types in Galbe:
14
+
15
+ #### Boolean
16
+
17
+ Schema Type matching `boolean` values.
18
+
19
+ ```ts
20
+ const boolSchema = $T.boolean()
21
+ ```
22
+
23
+ #### String
24
+
25
+ Schema Type matching `string` vlues.
26
+
27
+ ```ts
28
+ const strSchema = $T.string(options)
29
+ ```
30
+
31
+ #### Number
32
+
33
+ Schema Type matching `number` values.
34
+
35
+ ```ts
36
+ const numSchema = $T.number(options)
37
+ ```
38
+
39
+ #### Integer
40
+
41
+ Schema Type matching integer `number` values.
42
+
43
+ ```ts
44
+ const intSchema = $T.integer(options)
45
+ ```
46
+
47
+ #### Any
48
+
49
+ Schema Type matching `any` of the previous Schema Types.
50
+
51
+ ```ts
52
+ const anySchema = $T.any()
53
+ ```
54
+
55
+ #### Array
56
+
57
+ Schema Type matching `array` values.
58
+
59
+ ```ts
60
+ const arraySchema = $T.array($T.any(), options)
61
+ ```
62
+
63
+ #### Optional
64
+
65
+ Makes any type optional. This allows for `undefined` values.
66
+
67
+ ```ts
68
+ const optionalSchema = $T.optional($T.string())
69
+ ```
70
+
71
+ #### Union
72
+
73
+ Creates an union of Schema Types.
74
+
75
+ ```ts
76
+ const unionSchema = $T.union([$T.string(), $T.number()])
77
+ ```
78
+
79
+ ## Request Schema definition
80
+
81
+ The Request Schema definition allows you to define a schema for your request on your [Route Definition](routes.md#route-defintion). It must be defined right after the path of your route.
82
+
83
+ ```js
84
+ const schema = {}
85
+ galbe.get('/foo/:bar', schema, ctx => {})
86
+ ```
87
+
88
+ The Request Schema has four optional properties:
89
+
90
+ ### headers
91
+
92
+ ```ts
93
+ headers: { [key: string]: STString | STBoolean | STNumber | STInteger | STLiteral }
94
+ ```
95
+
96
+ This is a key-value object where each key represents a request header name, and the value is the associated Schema.
97
+
98
+ **Example**:
99
+
100
+ ```ts
101
+ const schema = {
102
+ headers: {
103
+ 'User-Agent': $T.optional($T.string({ pattern: '^Bun' }))
104
+ }
105
+ }
106
+ ```
107
+
108
+ ### params
109
+
110
+ ```ts
111
+ params: { [key: string]: STString | STBoolean | STNumber | STInteger | STLiteral }
112
+ ```
113
+
114
+ This is a key-value object where each key represents a request path parameter name, and the value is the associated Schema.
115
+
116
+ **Example**:
117
+
118
+ ```ts
119
+ const schema = {
120
+ params: {
121
+ name: $T.string(),
122
+ age: $T.integer({ min: 0 })
123
+ }
124
+ }
125
+ ```
126
+
127
+ > [!WARNING]
128
+ > Every key should match an existing [route path](routes.md#route-defintion) parameter. Otherwise Typescript will show an error.
129
+ >
130
+ > By default, if no schema is defined for a given parameter. Galbe will assume it is of type `string`.
131
+
132
+ ### query
133
+
134
+ ```ts
135
+ query: { [key: string]: STString | STBoolean | STNumber | STInteger | STLiteral }
136
+ ```
137
+
138
+ This is a key-value object where each key represents a request query parameter name, and the value is the associated Schema.
139
+
140
+ **Example**:
141
+
142
+ ```ts
143
+ const schema = {
144
+ query: {
145
+ name: $T.literal('Galbe'),
146
+ list: $T.array($T.number())
147
+ }
148
+ }
149
+ ```
150
+
151
+ ### body
152
+
153
+ <!-- prettier-ignore -->
154
+ ```ts
155
+ body: STByteArray | STString | STBoolean | STNumber | STInteger | STLiteral |
156
+ STObject | STMulripartForm | STUrlForm
157
+ ```
158
+
159
+ #### Json
160
+
161
+ To define an `application/json` request body, use `STObject` Schema Type. Example:
162
+
163
+ ```ts
164
+ const jsonBody = $T.object({
165
+ name: $T.string(),
166
+ age: $T.integer({ min: 0 })
167
+ })
168
+ ```
169
+
170
+ #### Multipart
171
+
172
+ To define a `multipart/form-data` request body, use `TMultipartForm` Schema Type. Example:
173
+
174
+ ```ts
175
+ const multipartBody = $T.multipartForm({
176
+ name: $T.string(),
177
+ age: $T.integer({ minimum: 0 })
178
+ })
179
+ ```
180
+
181
+ #### Url Form
182
+
183
+ To define an `application/x-www-form-urlencoded` request body, use `TUrlForm` Schema Type. Example:
184
+
185
+ ```ts
186
+ const urlBody = $T.urlForm({
187
+ name: $T.string(),
188
+ age: $T.integer({ minimum: 0 })
189
+ })
190
+ ```
191
+
192
+ #### Stream
193
+
194
+ Some body request types can be streamed by using `STStream` Schema Type wrapper. The streamable Schema Types are `STByteArray`, `STString`, `STUrlForm` and `STMultipartForm`. This can be usefull to imporve performances in case you have heavy body payloads and you want to perform early validations on the body.
195
+
196
+ Let's look at a concrete example where this could be useful. Imagine you want a `multipart/form-data` body request that has two properties: `username` and `heavyImageFile`. In a normal case, you would define something like this:
197
+
198
+ ```ts
199
+ galbe.post(
200
+ 'user/create',
201
+ {
202
+ body: $T.multipartForm({
203
+ username: $T.string(),
204
+ heavyImageFile: $T.byteArray()
205
+ })
206
+ },
207
+ ctx => {
208
+ // At that point, the full body request has been processed
209
+ if(!isValid(ctx.body.username))
210
+ throw new RequestError({ status: 400 })
211
+ else ctx.set.status = 201
212
+ }
213
+ })
214
+ ```
215
+
216
+ This means that in the case where the username wouldn't pass the validation, the full request body, including the `heavyImageFile`, would have been processed for nothing, as it is not used. This would induce unnecessary time and resource consumption.
217
+
218
+ The `STStream` Schema Type wrapper was created to remediate to remediate this issue. In practice it allows you to perform validations on the fly. Now in your handler, instead of receiving an object as `ctx.body`, you will receive an [AsyncGenerator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator).
219
+
220
+ ```ts
221
+ galbe.post(
222
+ 'user/create',
223
+ {
224
+ body: $T.stream($T.multipartForm({
225
+ username: $T.string(),
226
+ heavyImageFile: $T.byteArray()
227
+ }))
228
+ },
229
+ ctx => {
230
+ // At that point, the body has not been processed yet.
231
+ for await (const [key, value] of ctx.body) {
232
+ if (key === "username" && !isValid(value)) {
233
+ // Returns an early response before heavyImageFile is processed
234
+ throw new RequestError({ status: 400 })
235
+ }
236
+ }
237
+ ctx.set.status = 201
238
+ }
239
+ })
240
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "galbe",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "Fast, lightweight and highly customizable JavaScript web framework based on Bun",
5
5
  "author": "Pierre Caillaud M (https://github.com/pierre-cm)",
6
6
  "type": "module",
@@ -41,7 +41,6 @@
41
41
  "typescript": "^5.0.0"
42
42
  },
43
43
  "dependencies": {
44
- "@sinclair/typebox": "^0.31.28",
45
44
  "@swc/core": "^1.3.107",
46
45
  "@swc/wasm": "^1.4.0",
47
46
  "acorn": "^8.11.2",
package/src/index.ts CHANGED
@@ -1,62 +1,43 @@
1
1
  import type { Server } from 'bun'
2
- import type {
3
- ArrayOptions,
4
- NumericOptions,
5
- ObjectOptions,
6
- SchemaOptions,
7
- Static,
8
- StringOptions,
9
- TAny,
10
- TArray,
11
- TBoolean,
12
- TInteger,
13
- TLiteral,
14
- TLiteralValue,
15
- TNever,
16
- TNumber,
17
- TObject,
18
- TOptional,
19
- TProperties,
20
- TSchema,
21
- TString,
22
- TUnion
23
- } from '@sinclair/typebox'
24
2
  import type { RouteFileMeta } from './routes'
25
3
  import type {
26
4
  GalbeConfig,
27
5
  Method,
28
- Schema,
6
+ RequestSchema,
29
7
  Hook,
30
8
  Handler,
31
9
  Endpoint,
32
10
  Context,
33
11
  ErrorHandler,
34
12
  GalbePlugin,
35
- TStream,
36
- TMultipartProperties,
37
- TMultipartForm,
38
- TUrlFormProperties,
39
- TUrlForm,
40
- TBody,
41
- TByteArray,
42
- TStreamable,
43
- MultipartFormData
13
+ STBody,
14
+ STParams,
15
+ STHeaders,
16
+ STQuery
44
17
  } from './types'
45
18
 
46
- import { TypeClone, Kind, TypeBuilder, Optional, TypeGuard } from '@sinclair/typebox'
47
19
  import server from './server'
48
20
  import { GalbeRouter } from './router'
49
21
  import { defineRoutes } from './routes'
50
- import { Stream } from './types'
51
22
  import { logRoute } from './util'
23
+ import { SchemaType, type STObject, type Static } from './schema'
52
24
 
53
- const overloadDiscriminer = <H extends TProperties, P extends TProperties, Q extends TProperties, B extends TBody>(
25
+ const overloadDiscriminer = <
26
+ Path extends string,
27
+ H extends STHeaders,
28
+ P extends Partial<STParams<Path>>,
29
+ Q extends STQuery,
30
+ B extends STBody
31
+ >(
54
32
  galbe: Galbe,
55
33
  method: Method,
56
- path: string,
57
- arg2: Schema<H, P, Q, B> | Hook<Schema<H, P, Q, B>>[] | Handler<Schema<H, P, Q, B>>,
58
- arg3?: Hook<Schema<H, P, Q, B>>[] | Handler<Schema<H, P, Q, B>>,
59
- arg4?: Handler<Schema<H, P, Q, B>>
34
+ path: Path,
35
+ 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>>
60
41
  ) => {
61
42
  const defaultSchema = {}
62
43
  if (typeof arg2 === 'function') {
@@ -69,22 +50,28 @@ const overloadDiscriminer = <H extends TProperties, P extends TProperties, Q ext
69
50
  else if (typeof arg3 === 'function') return galbeMethod(galbe, method, path, arg2, undefined, arg3)
70
51
  }
71
52
  }
72
- throw new Error('Undefined endpoint signature')
53
+ throw new Error('Undefined route signature')
73
54
  }
74
- const galbeMethod = <H extends TProperties, P extends TProperties, Q extends TProperties, B extends TBody>(
55
+ const galbeMethod = <
56
+ Path extends string,
57
+ H extends STHeaders,
58
+ P extends Partial<STParams<Path>>,
59
+ Q extends STQuery,
60
+ B extends STBody
61
+ >(
75
62
  _galbe: Galbe,
76
63
  method: Method,
77
- path: string,
78
- schema: Schema<H, P, Q, B> | undefined,
79
- hooks: Hook<Schema<H, P, Q, B>>[] | undefined,
80
- handler: Handler<Schema<H, P, Q, B>>
64
+ 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>>
81
68
  ) => {
82
69
  schema = schema ?? {}
83
70
  hooks = hooks || []
84
- const context: Context<typeof schema> = {
85
- headers: {} as Static<TObject<Exclude<(typeof schema)['headers'], undefined>>>,
86
- params: {} as Static<TObject<Exclude<(typeof schema)['params'], undefined>>>,
87
- query: {} as Static<TObject<Exclude<(typeof schema)['query'], undefined>>>,
71
+ const context: Context<Path, typeof schema> = {
72
+ headers: {} as Static<STObject<Exclude<(typeof schema)['headers'], undefined>>>,
73
+ params: {} as any,
74
+ query: {} as Static<STObject<Exclude<(typeof schema)['query'], undefined>>>,
88
75
  body: {} as Static<Exclude<(typeof schema)['body'], undefined>>,
89
76
  request: {} as Request,
90
77
  state: {},
@@ -96,7 +83,6 @@ const galbeMethod = <H extends TProperties, P extends TProperties, Q extends TPr
96
83
  redirect?: string
97
84
  }
98
85
  }
99
- //@ts-ignore
100
86
  return {
101
87
  method,
102
88
  path,
@@ -107,145 +93,7 @@ const galbeMethod = <H extends TProperties, P extends TProperties, Q extends TPr
107
93
  }
108
94
  }
109
95
 
110
- export class TypeboxTypeBuilder extends TypeBuilder {
111
- /** `[Json]` Creates an Optional property */
112
- public Optional<T extends TSchema>(schema: T): TOptional<T> {
113
- return { ...TypeClone.Type(schema), [Optional]: 'Optional' }
114
- }
115
- /** `[Json]` Creates an Any type */
116
- public Any(options: SchemaOptions = {}): TAny {
117
- return this.Create({ ...options, [Kind]: 'Any' })
118
- }
119
- /** `[Json]` Creates an Array type */
120
- public Array<T extends TSchema>(schema: T, options: ArrayOptions = {}): TArray<T> {
121
- return this.Create({ ...options, [Kind]: 'Array', type: 'array', items: TypeClone.Type(schema) })
122
- }
123
- /** `[Json]` Creates a Boolean type */
124
- public Boolean(options: SchemaOptions = {}): TBoolean {
125
- return this.Create({ ...options, [Kind]: 'Boolean', type: 'boolean' })
126
- }
127
- /** `[Json]` Creates an Integer type */
128
- public Integer(options: NumericOptions<number> = {}): TInteger {
129
- return this.Create({ ...options, [Kind]: 'Integer', type: 'integer' })
130
- }
131
- /** `[Json]` Creates a Literal type */
132
- public Literal<T extends TLiteralValue>(value: T, options: SchemaOptions = {}): TLiteral<T> {
133
- return this.Create({
134
- ...options,
135
- [Kind]: 'Literal',
136
- const: value,
137
- type: typeof value as 'string' | 'number' | 'boolean'
138
- })
139
- }
140
- /** `[Json]` Creates a Number type */
141
- public Number(options: NumericOptions<number> = {}): TNumber {
142
- return this.Create({ ...options, [Kind]: 'Number', type: 'number' })
143
- }
144
- /** `[Json]` Creates an Object type */
145
- public Object<T extends TProperties>(properties: T, options: ObjectOptions = {}): TObject<T> {
146
- const propertyKeys = Object.getOwnPropertyNames(properties)
147
- const optionalKeys = propertyKeys.filter(key => TypeGuard.TOptional(properties[key]))
148
- const requiredKeys = propertyKeys.filter(name => !optionalKeys.includes(name))
149
- const clonedAdditionalProperties = TypeGuard.TSchema(options.additionalProperties)
150
- ? { additionalProperties: TypeClone.Type(options.additionalProperties) }
151
- : {}
152
- const clonedProperties = propertyKeys.reduce(
153
- (acc, key) => ({ ...acc, [key]: TypeClone.Type(properties[key]) }),
154
- {} as TProperties
155
- )
156
- return requiredKeys.length > 0
157
- ? this.Create({
158
- ...options,
159
- ...clonedAdditionalProperties,
160
- [Kind]: 'Object',
161
- type: 'object',
162
- properties: clonedProperties,
163
- required: requiredKeys
164
- })
165
- : this.Create({
166
- ...options,
167
- ...clonedAdditionalProperties,
168
- [Kind]: 'Object',
169
- type: 'object',
170
- properties: clonedProperties
171
- })
172
- }
173
- /** `[Json]` Creates a String type */
174
- public String(options: StringOptions = {}): TString {
175
- return this.Create({ ...options, [Kind]: 'String', type: 'string' })
176
- }
177
- /** `[Json]` Creates a Union type */
178
- public Union(anyOf: [], options?: SchemaOptions): TNever
179
- /** `[Json]` Creates a Union type */
180
- public Union<T extends [TSchema]>(anyOf: [...T], options?: SchemaOptions): T[0]
181
- /** `[Json]` Creates a Union type */
182
- public Union<T extends TSchema[]>(anyOf: [...T], options?: SchemaOptions): TUnion<T>
183
- /** `[Json]` Creates a Union type */
184
- public Union(union: TSchema[], options: SchemaOptions = {}) {
185
- // prettier-ignore
186
- return (() => {
187
- const anyOf = union
188
- if (anyOf.length === 0) throw new Error("Union type must decalre at least one schema")
189
- if (anyOf.length === 1) return this.Create(TypeClone.Type(anyOf[0], options))
190
- const clonedAnyOf = TypeClone.Rest(anyOf)
191
- return this.Create({ ...options, [Kind]: 'Union', anyOf: clonedAnyOf })
192
- })()
193
- }
194
- }
195
-
196
- class GalbeTypeBuilder extends TypeboxTypeBuilder {
197
- /** `[Galbe]` Creates an Stream type */
198
- public Stream<T extends TUrlForm>(
199
- schema: T
200
- ): Omit<TStream<T>, 'static'> & { static: AsyncGenerator<[string, string | number | boolean]>; params: unknown[] }
201
- public Stream<T extends TMultipartForm>(
202
- schema: T
203
- ): Omit<TStream<T>, 'static'> & { static: AsyncGenerator<MultipartFormData, void, unknown>; params: unknown[] }
204
- public Stream<T extends TByteArray>(
205
- schema: T
206
- ): Omit<TStream<T>, 'static'> & { static: AsyncGenerator<Uint8Array>; params: unknown[] }
207
- public Stream<T extends TString>(
208
- schema: T
209
- ): Omit<TStream<T>, 'static'> & { static: AsyncGenerator<string>; params: unknown[] }
210
- public Stream<T extends TStreamable>(schema: T): TStream<T> {
211
- return {
212
- ...TypeClone.Type(schema),
213
- [Stream]: 'Stream'
214
- }
215
- }
216
- /** `[Galbe]` Creates an ByteArray type */
217
- public ByteArray(): TByteArray {
218
- return this.Create({ [Kind]: 'ByteArray', type: 'byteArray', params: {} })
219
- }
220
- /** `[Galbe]` Creates an MultipartForm type */
221
- public MultipartForm<T extends TMultipartProperties>(properties?: T): TMultipartForm {
222
- if (!properties) return this.Create({ [Kind]: 'MultipartForm', type: 'multipartForm' })
223
- const propertyKeys = Object.getOwnPropertyNames(properties)
224
- const clonedProperties = propertyKeys.reduce(
225
- //@ts-ignore
226
- (acc, key) => ({ ...acc, [key]: TypeClone.Type(properties[key]) }),
227
- {} as TProperties
228
- )
229
- return this.Create({
230
- [Kind]: 'MultipartForm',
231
- type: 'multipartForm',
232
- properties: clonedProperties
233
- })
234
- }
235
- /** `[Galbe]` Creates an UrlForm type */
236
- public UrlForm<T extends TUrlFormProperties>(properties?: T): TUrlForm {
237
- if (!properties) return this.Create({ [Kind]: 'UrlForm', type: 'urlForm' })
238
- const propertyKeys = Object.getOwnPropertyNames(properties)
239
- const clonedProperties = propertyKeys.reduce(
240
- //@ts-ignore
241
- (acc, key) => ({ ...acc, [key]: TypeClone.Type(properties[key]) }),
242
- {} as TProperties
243
- )
244
- return this.Create({ [Kind]: 'UrlForm', type: 'urlForm', properties: clonedProperties })
245
- }
246
- }
247
-
248
- export const T = new GalbeTypeBuilder()
96
+ export const $T = new SchemaType()
249
97
 
250
98
  export { RequestError } from './types'
251
99
 
@@ -274,6 +122,7 @@ export class Galbe {
274
122
  plugins: GalbePlugin[] = []
275
123
  constructor(config?: GalbeConfig) {
276
124
  this.config = config ?? {}
125
+ this.config.routes = this.config.routes ?? true
277
126
  this.router = new GalbeRouter(this.config?.basePath || '')
278
127
  }
279
128
  private add(route: any) {
@@ -312,41 +161,95 @@ export class Galbe {
312
161
  onError(handler: ErrorHandler) {
313
162
  this.errorHandler = handler
314
163
  }
315
- get: Endpoint = <H extends TProperties, P extends TProperties, Q extends TProperties, B extends TBody>(
316
- path: string,
317
- arg2: Schema<H, P, Q, B> | Hook<Schema<H, P, Q, B>>[] | Handler<Schema<H, P, Q, B>>,
318
- arg3?: Hook<Schema<H, P, Q, B>>[] | Handler<Schema<H, P, Q, B>>,
319
- arg4?: Handler<Schema<H, P, Q, B>>
164
+ get: Endpoint = <
165
+ Path extends string,
166
+ H extends STHeaders,
167
+ P extends Partial<STParams<Path>>,
168
+ Q extends STQuery,
169
+ B extends STBody
170
+ >(
171
+ path: Path,
172
+ arg2:
173
+ | RequestSchema<Path, H, P, Q, B>
174
+ | Hook<Path, RequestSchema<Path, H, P, Q, B>>[]
175
+ | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
176
+ arg3?: Hook<Path, RequestSchema<Path, H, P, Q, B>>[] | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
177
+ arg4?: Handler<Path, RequestSchema<Path, H, P, Q, B>>
320
178
  ) => this.add(overloadDiscriminer(this, 'get', path, arg2, arg3, arg4))
321
- post: Endpoint = <H extends TProperties, P extends TProperties, Q extends TProperties, B extends TBody>(
322
- path: string,
323
- arg2: Schema<H, P, Q, B> | Hook<Schema<H, P, Q, B>>[] | Handler<Schema<H, P, Q, B>>,
324
- arg3?: Hook<Schema<H, P, Q, B>>[] | Handler<Schema<H, P, Q, B>>,
325
- arg4?: Handler<Schema<H, P, Q, B>>
179
+ post: Endpoint = <
180
+ Path extends string,
181
+ H extends STHeaders,
182
+ P extends Partial<STParams<Path>>,
183
+ Q extends STQuery,
184
+ B extends STBody
185
+ >(
186
+ path: Path,
187
+ arg2:
188
+ | RequestSchema<Path, H, P, Q, B>
189
+ | Hook<Path, RequestSchema<Path, H, P, Q, B>>[]
190
+ | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
191
+ arg3?: Hook<Path, RequestSchema<Path, H, P, Q, B>>[] | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
192
+ arg4?: Handler<Path, RequestSchema<Path, H, P, Q, B>>
326
193
  ) => this.add(overloadDiscriminer(this, 'post', path, arg2, arg3, arg4))
327
- put: Endpoint = <H extends TProperties, P extends TProperties, Q extends TProperties, B extends TBody>(
328
- path: string,
329
- arg2: Schema<H, P, Q, B> | Hook<Schema<H, P, Q, B>>[] | Handler<Schema<H, P, Q, B>>,
330
- arg3?: Hook<Schema<H, P, Q, B>>[] | Handler<Schema<H, P, Q, B>>,
331
- arg4?: Handler<Schema<H, P, Q, B>>
194
+ put: Endpoint = <
195
+ Path extends string,
196
+ H extends STHeaders,
197
+ P extends Partial<STParams<Path>>,
198
+ Q extends STQuery,
199
+ B extends STBody
200
+ >(
201
+ path: Path,
202
+ arg2:
203
+ | RequestSchema<Path, H, P, Q, B>
204
+ | Hook<Path, RequestSchema<Path, H, P, Q, B>>[]
205
+ | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
206
+ arg3?: Hook<Path, RequestSchema<Path, H, P, Q, B>>[] | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
207
+ arg4?: Handler<Path, RequestSchema<Path, H, P, Q, B>>
332
208
  ) => this.add(overloadDiscriminer(this, 'put', path, arg2, arg3, arg4))
333
- patch: Endpoint = <H extends TProperties, P extends TProperties, Q extends TProperties, B extends TBody>(
334
- path: string,
335
- arg2: Schema<H, P, Q, B> | Hook<Schema<H, P, Q, B>>[] | Handler<Schema<H, P, Q, B>>,
336
- arg3?: Hook<Schema<H, P, Q, B>>[] | Handler<Schema<H, P, Q, B>>,
337
- arg4?: Handler<Schema<H, P, Q, B>>
209
+ patch: Endpoint = <
210
+ Path extends string,
211
+ H extends STHeaders,
212
+ P extends Partial<STParams<Path>>,
213
+ Q extends STQuery,
214
+ B extends STBody
215
+ >(
216
+ path: Path,
217
+ arg2:
218
+ | RequestSchema<Path, H, P, Q, B>
219
+ | Hook<Path, RequestSchema<Path, H, P, Q, B>>[]
220
+ | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
221
+ arg3?: Hook<Path, RequestSchema<Path, H, P, Q, B>>[] | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
222
+ arg4?: Handler<Path, RequestSchema<Path, H, P, Q, B>>
338
223
  ) => this.add(overloadDiscriminer(this, 'patch', path, arg2, arg3, arg4))
339
- delete: Endpoint = <H extends TProperties, P extends TProperties, Q extends TProperties, B extends TBody>(
340
- path: string,
341
- arg2: Schema<H, P, Q, B> | Hook<Schema<H, P, Q, B>>[] | Handler<Schema<H, P, Q, B>>,
342
- arg3?: Hook<Schema<H, P, Q, B>>[] | Handler<Schema<H, P, Q, B>>,
343
- arg4?: Handler<Schema<H, P, Q, B>>
224
+ delete: Endpoint = <
225
+ Path extends string,
226
+ H extends STHeaders,
227
+ P extends Partial<STParams<Path>>,
228
+ Q extends STQuery,
229
+ B extends STBody
230
+ >(
231
+ path: Path,
232
+ arg2:
233
+ | RequestSchema<Path, H, P, Q, B>
234
+ | Hook<Path, RequestSchema<Path, H, P, Q, B>>[]
235
+ | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
236
+ arg3?: Hook<Path, RequestSchema<Path, H, P, Q, B>>[] | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
237
+ arg4?: Handler<Path, RequestSchema<Path, H, P, Q, B>>
344
238
  ) => this.add(overloadDiscriminer(this, 'delete', path, arg2, arg3, arg4))
345
- options: Endpoint = <H extends TProperties, P extends TProperties, Q extends TProperties, B extends TBody>(
346
- path: string,
347
- arg2: Schema<H, P, Q, B> | Hook<Schema<H, P, Q, B>>[] | Handler<Schema<H, P, Q, B>>,
348
- arg3?: Hook<Schema<H, P, Q, B>>[] | Handler<Schema<H, P, Q, B>>,
349
- arg4?: Handler<Schema<H, P, Q, B>>
239
+ options: Endpoint = <
240
+ Path extends string,
241
+ H extends STHeaders,
242
+ P extends Partial<STParams<Path>>,
243
+ Q extends STQuery,
244
+ B extends STBody
245
+ >(
246
+ path: Path,
247
+ arg2:
248
+ | RequestSchema<Path, H, P, Q, B>
249
+ | Hook<Path, RequestSchema<Path, H, P, Q, B>>[]
250
+ | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
251
+ arg3?: Hook<Path, RequestSchema<Path, H, P, Q, B>>[] | Handler<Path, RequestSchema<Path, H, P, Q, B>>,
252
+ arg4?: Handler<Path, RequestSchema<Path, H, P, Q, B>>
350
253
  ) => this.add(overloadDiscriminer(this, 'options', path, arg2, arg3, arg4))
351
254
  }
352
255