wooks 0.0.1-beta.0

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.
Files changed (105) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +522 -0
  3. package/dist/src/composables/body.d.ts +17 -0
  4. package/dist/src/composables/body.d.ts.map +1 -0
  5. package/dist/src/composables/cookies.d.ts +13 -0
  6. package/dist/src/composables/cookies.d.ts.map +1 -0
  7. package/dist/src/composables/core-test.d.ts +19 -0
  8. package/dist/src/composables/core-test.d.ts.map +1 -0
  9. package/dist/src/composables/core.d.ts +30 -0
  10. package/dist/src/composables/core.d.ts.map +1 -0
  11. package/dist/src/composables/header-accept.d.ts +9 -0
  12. package/dist/src/composables/header-accept.d.ts.map +1 -0
  13. package/dist/src/composables/header-authorization.d.ts +20 -0
  14. package/dist/src/composables/header-authorization.d.ts.map +1 -0
  15. package/dist/src/composables/header-set-cache-control.d.ts +9 -0
  16. package/dist/src/composables/header-set-cache-control.d.ts.map +1 -0
  17. package/dist/src/composables/headers.d.ts +11 -0
  18. package/dist/src/composables/headers.d.ts.map +1 -0
  19. package/dist/src/composables/index.d.ts +11 -0
  20. package/dist/src/composables/index.d.ts.map +1 -0
  21. package/dist/src/composables/req-res.d.ts +34 -0
  22. package/dist/src/composables/req-res.d.ts.map +1 -0
  23. package/dist/src/composables/search-params.d.ts +13 -0
  24. package/dist/src/composables/search-params.d.ts.map +1 -0
  25. package/dist/src/composables/tests/body.spec.d.ts +2 -0
  26. package/dist/src/composables/tests/body.spec.d.ts.map +1 -0
  27. package/dist/src/composables/tests/cookies.spec.d.ts +2 -0
  28. package/dist/src/composables/tests/cookies.spec.d.ts.map +1 -0
  29. package/dist/src/composables/tests/core.spec.d.ts +2 -0
  30. package/dist/src/composables/tests/core.spec.d.ts.map +1 -0
  31. package/dist/src/composables/tests/headers.spec.d.ts +2 -0
  32. package/dist/src/composables/tests/headers.spec.d.ts.map +1 -0
  33. package/dist/src/composables/tests/req-res.spec.d.ts +2 -0
  34. package/dist/src/composables/tests/req-res.spec.d.ts.map +1 -0
  35. package/dist/src/composables/tests/search-params.spec.d.ts +2 -0
  36. package/dist/src/composables/tests/search-params.spec.d.ts.map +1 -0
  37. package/dist/src/content-types/index.d.ts +97 -0
  38. package/dist/src/content-types/index.d.ts.map +1 -0
  39. package/dist/src/e2e.spec.d.ts +2 -0
  40. package/dist/src/e2e.spec.d.ts.map +1 -0
  41. package/dist/src/errors/error-renderer.d.ts +9 -0
  42. package/dist/src/errors/error-renderer.d.ts.map +1 -0
  43. package/dist/src/errors/errors.spec.d.ts +2 -0
  44. package/dist/src/errors/errors.spec.d.ts.map +1 -0
  45. package/dist/src/errors/index.d.ts +3 -0
  46. package/dist/src/errors/index.d.ts.map +1 -0
  47. package/dist/src/errors/wooks-error.d.ts +20 -0
  48. package/dist/src/errors/wooks-error.d.ts.map +1 -0
  49. package/dist/src/http.d.ts +7 -0
  50. package/dist/src/http.d.ts.map +1 -0
  51. package/dist/src/index.d.ts +8 -0
  52. package/dist/src/index.d.ts.map +1 -0
  53. package/dist/src/mime/extensions.d.ts +1184 -0
  54. package/dist/src/mime/extensions.d.ts.map +1 -0
  55. package/dist/src/mime/index.d.ts +2 -0
  56. package/dist/src/mime/index.d.ts.map +1 -0
  57. package/dist/src/mime/mime.spec.d.ts +2 -0
  58. package/dist/src/mime/mime.spec.d.ts.map +1 -0
  59. package/dist/src/response/core.d.ts +30 -0
  60. package/dist/src/response/core.d.ts.map +1 -0
  61. package/dist/src/response/factory.d.ts +4 -0
  62. package/dist/src/response/factory.d.ts.map +1 -0
  63. package/dist/src/response/index.d.ts +4 -0
  64. package/dist/src/response/index.d.ts.map +1 -0
  65. package/dist/src/response/renderer.d.ts +8 -0
  66. package/dist/src/response/renderer.d.ts.map +1 -0
  67. package/dist/src/response/response.spec.d.ts +2 -0
  68. package/dist/src/response/response.spec.d.ts.map +1 -0
  69. package/dist/src/serve-file/serve-file.d.ts +20 -0
  70. package/dist/src/serve-file/serve-file.d.ts.map +1 -0
  71. package/dist/src/serve-file/serve-file.spec.d.ts +2 -0
  72. package/dist/src/serve-file/serve-file.spec.d.ts.map +1 -0
  73. package/dist/src/server.d.ts +26 -0
  74. package/dist/src/server.d.ts.map +1 -0
  75. package/dist/src/status-codes/index.d.ts +135 -0
  76. package/dist/src/status-codes/index.d.ts.map +1 -0
  77. package/dist/src/types.d.ts +5 -0
  78. package/dist/src/types.d.ts.map +1 -0
  79. package/dist/src/utils/banner.d.ts +2 -0
  80. package/dist/src/utils/banner.d.ts.map +1 -0
  81. package/dist/src/utils/body-compressor.d.ts +8 -0
  82. package/dist/src/utils/body-compressor.d.ts.map +1 -0
  83. package/dist/src/utils/cache-control.d.ts +14 -0
  84. package/dist/src/utils/cache-control.d.ts.map +1 -0
  85. package/dist/src/utils/panic.d.ts +2 -0
  86. package/dist/src/utils/panic.d.ts.map +1 -0
  87. package/dist/src/utils/set-cookie.d.ts +16 -0
  88. package/dist/src/utils/set-cookie.d.ts.map +1 -0
  89. package/dist/src/utils/tests/body-compressor.spec.d.ts +2 -0
  90. package/dist/src/utils/tests/body-compressor.spec.d.ts.map +1 -0
  91. package/dist/src/utils/tests/set-cookie.spec.d.ts +2 -0
  92. package/dist/src/utils/tests/set-cookie.spec.d.ts.map +1 -0
  93. package/dist/src/utils/tests/time.spec.d.ts +2 -0
  94. package/dist/src/utils/tests/time.spec.d.ts.map +1 -0
  95. package/dist/src/utils/tests/url-search-params.spec.d.ts +2 -0
  96. package/dist/src/utils/tests/url-search-params.spec.d.ts.map +1 -0
  97. package/dist/src/utils/time.d.ts +5 -0
  98. package/dist/src/utils/time.d.ts.map +1 -0
  99. package/dist/src/utils/url-search-params.d.ts +6 -0
  100. package/dist/src/utils/url-search-params.d.ts.map +1 -0
  101. package/dist/wooks.cjs.prod.js +2679 -0
  102. package/dist/wooks.d.ts +550 -0
  103. package/dist/wooks.esm-bundler.js +2644 -0
  104. package/index.js +2 -0
  105. package/package.json +86 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 prostojs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,522 @@
1
+ # Wooks
2
+
3
+ **!!! This is work-in-progress library, breaking changes are expected !!!**
4
+
5
+ Wooks is a Web Application Framework with hooks.
6
+
7
+ As an alternative for `express` and `fastify`, `wooks` brings the whole different approach for processing http requests.
8
+ It utilizes such a technique as you can see in React Hooks or Vue Composables. It has only a dependency on [@prostojs/router](https://github.com/prostojs/router) (an alternative to `find-my-way` used by `fastify`) which is a very fast (see benchmarks [here](https://github.com/prostojs/router-benchmark)) and robust URI router.
9
+
10
+ `wooks` supports cookie parsing and serving files out of the box with no impact on performance.
11
+
12
+ The main ideas behind wooks are:
13
+
14
+ 1. Never mutate request object (`req`). Accumulate a request context in a separate object(s) instead;
15
+ 2. Never parse anything (cookies, body) before it is really requested by the request handler;
16
+ 3. Get rid of complex predefined data objects containing everything (cookies, headers, body, parsed body etc.) and use composable functions (hooks) instead;
17
+ 4. Get rid of tons of dependencies (middlewares) and implement everything that is needed for web app in a simple way.
18
+
19
+
20
+ ## Quick Start
21
+
22
+ ```js
23
+ const { Wooks } = require('wooks')
24
+
25
+ const app = new Wooks()
26
+
27
+ app.get('test', () => {
28
+ return { message: 'hello world!' }
29
+ })
30
+
31
+ app.listen(3000, () => { console.log('Wooks Server is up on port 3000') })
32
+ ```
33
+
34
+ ## Install
35
+
36
+ `npm install wooks`
37
+
38
+ ## Routes
39
+
40
+ It supports static, parametric and wildcard routes with regex expressions (see details in [@prostojs/router](https://github.com/prostojs/router))
41
+
42
+ Static route:
43
+ ```js
44
+ app.get('static/route', () => {})
45
+ ```
46
+
47
+ Parametric route:
48
+ ```js
49
+ app.get('parametric/:param1/:param2/...', () => {})
50
+ ```
51
+
52
+ Wildcard route:
53
+ ```js
54
+ app.get('wildcard/*', () => {})
55
+ ```
56
+
57
+ Complex wildcard route (use as many asterisks as you need and even specify a static parts after them):
58
+ ```js
59
+ app.get('wildcard/start-*/*.html', () => {})
60
+ ```
61
+
62
+
63
+ ## URL Parameters
64
+
65
+ To get access to URL parameters use composable function `useRouteParams`
66
+
67
+ ```js
68
+ import { useRouteParams } from 'wooks'
69
+ app.get('parametric/:param1/:param2/...', () => {
70
+ const { routeParams, getRouteParam } = useRouteParams()
71
+ // presume we had a request on `/parametric/value1/value2`
72
+ console.log('param1=' + getRouteParam('param1'))
73
+ // prints "param1=value1"
74
+ console.log('param2=' + getRouteParam('param2'))
75
+ // prints "param2=value2"
76
+ console.log(routeParams)
77
+ // prints {
78
+ // param1: "value1",
79
+ // param2: "value2"
80
+ // }
81
+ })
82
+ ```
83
+
84
+ ## Query Parameters
85
+
86
+ To get access to Query parameters use composable function `useSearchParams`
87
+
88
+ ```js
89
+ import { useSearchParams } from 'wooks'
90
+ app.get('with-query', () => {
91
+ const { jsonSearchParams, urlSearchParams } = useSearchParams()
92
+ // presume we had a request on `/with-query?param1=abc&param2=cde`
93
+ console.log('param1=' + urlSearchParams('param1'))
94
+ // prints "param1=abc"
95
+ console.log('param2=' + urlSearchParams('param2'))
96
+ // prints "param1=cde"
97
+ console.log(jsonSearchParams)
98
+ // prints {
99
+ // param1: "abc",
100
+ // param2: "cde"
101
+ // }
102
+ })
103
+ ```
104
+
105
+ ## Request
106
+
107
+ To get a reference to the raw request instance use composable function `useRequest`
108
+
109
+ You probably don't need a `rawRequest` unless you are developing some new feature. All the base use-cases covered with other composable functions.
110
+
111
+ ```js
112
+ import { useRequest } from 'wooks'
113
+ app.get('test', () => {
114
+ const { rawRequest } = useRequest()
115
+ })
116
+ ```
117
+
118
+ ### Request Method, Headers, ...
119
+
120
+ `useRequest` provides some more shortcuts for useful data
121
+
122
+ ```js
123
+ import { useRequest } from 'wooks'
124
+ app.get('test', async () => {
125
+ const {
126
+ url, // request url (string)
127
+ method, // request method (string)
128
+ headers, // request headers (object)
129
+ rawBody, // request body ((): Promise<Buffer>)
130
+ } = useRequest()
131
+
132
+ const body = await rawBody() // body as a Buffer
133
+ })
134
+ ```
135
+
136
+ ### Request Cookies
137
+
138
+ Cookies are not parsed unless requested. Composable function `useCookies` provides cookie getter and raw cookies string.
139
+
140
+ ```js
141
+ import { useCookies } from 'wooks'
142
+ app.get('test', async () => {
143
+ const {
144
+ rawCookies, // "cookie" from headers (string | undefined)
145
+ getCookie, // cookie getter ((name): string | null)
146
+ } = useCookies()
147
+
148
+ console.log(getCookie('session'))
149
+ // prints the value of the cookie with the name "session"
150
+ })
151
+ ```
152
+
153
+ ### Request Body Parser
154
+
155
+ Function `useBody` provides utilities for getting decoded and parsed body.
156
+
157
+ Body parser supports json, string, multipart/form-data and application/x-www-form-urlencoded content-types.
158
+
159
+ Body parser does not parse every request's body. The parsing happens only when you call `parseBody` function.
160
+
161
+ The request handler is invoked even before the request body was sent to the server.
162
+
163
+ ```js
164
+ import { useBody } from 'wooks'
165
+ app.post('test', async () => {
166
+ const {
167
+ isJson, // checks if content-type is "application/json" : () => boolean;
168
+ isHtml, // checks if content-type is "text/html" : () => boolean;
169
+ isXml, // checks if content-type is "application/xml" : () => boolean;
170
+ isText, // checks if content-type is "text/plain" : () => boolean;
171
+ isBinary, // checks if content-type is binary : () => boolean;
172
+ isFormData, // checks if content-type is "multipart/form-data" : () => boolean;
173
+ isUrlencoded, // checks if content-type is "application/x-www-form-urlencoded" : () => boolean;
174
+ isCompressed, // checks content-encoding : () => boolean | undefined;
175
+ contentEncodings, // returns an array of encodings : () => string[];
176
+ parseBody, // parses body according to content-type : <T = unknown>() => Promise<T>;
177
+ rawBody, // returns raw body Buffer : () => Promise<Buffer>;
178
+ } = useBody()
179
+
180
+ // the handler got the control, but the body isn't loaded yet
181
+ //...
182
+
183
+ console.log(await parseBody())
184
+
185
+ // after `await parseBody()` the body was loaded and parsed
186
+ // ...
187
+ })
188
+ ```
189
+
190
+ ### Request Authorization
191
+
192
+ `useAuthorization` function provides useful helpers for auth-headers:
193
+
194
+ ```js
195
+ import { useAuthorization } from 'wooks'
196
+ app.get('test', async () => {
197
+ const {
198
+ authorization, // the raw value of "authorization" header : string
199
+ authType, // the auth type (Bearer/Basic) : string
200
+ authRawCredentials, // the auth credentials that follow auth type : string
201
+ isBasic, // true if authType === 'Basic' : () => boolean
202
+ isBearer, // true if authType === 'Bearer' : () => boolean
203
+ basicCredentials, // parsed basic auth credentials : () => { username: string, password: string }
204
+ } = useAuthorization()
205
+
206
+ if (isBasic()) {
207
+ const { username, password } = basicCredentials()
208
+ console.log({ username, password })
209
+ } else if (isBearer()) {
210
+ const token = authRawCredentials
211
+ console.log({ token })
212
+ } else {
213
+ // unknown or empty authorization header
214
+ }
215
+ })
216
+ ```
217
+
218
+ ## Response
219
+
220
+ The easiest way to respond to the request is to return some value from handler function like this:
221
+ ```js
222
+ app.get('string_response', () => {
223
+ return 'hello world!'
224
+ // responds with:
225
+ // 200
226
+ // Content-Length: ...
227
+ // Content-Type: text/plain
228
+ // hello world!
229
+ })
230
+ ```
231
+
232
+ Whatever is returned from the handler is the response. `Content-Type` and `Content-Length` headers will be calculated accordingly.
233
+
234
+ If a handler returns a json object, it will be stringified and the header `Content-Type` will be set to `application/json` automatically:
235
+ ```js
236
+ app.get('json_response', () => {
237
+ return { value: 'hello world!' }
238
+ // responds with:
239
+ // 200
240
+ // Content-Length: ...
241
+ // Content-Type: application/json
242
+ // { "value": "hello world!" }
243
+ })
244
+ ```
245
+
246
+ **Supported response types:**
247
+ 1. string (text/plain, text/html, application/xml - depending on the content)
248
+ 2. object/array (application/json)
249
+ 3. boolean (text/plain)
250
+ 4. readable stream (you must specify `Content-Type` and `Content-Length` headers yourself)
251
+
252
+ **Raw Response**: When it is needed to take the full control of the response, use composable function `useResponse`
253
+
254
+ When you get a raw response instance you take away the control of the response on yourself. The framework will not process the output of the handler in this case.
255
+
256
+ An example of using raw response instance:
257
+ ```js
258
+ import { useResponse } from 'wooks'
259
+ app.get('test', () => {
260
+ const { rawResponse } = useResponse()
261
+ const res = rawResponse()
262
+ res.writeHead(200, {})
263
+ res.end('ok')
264
+ })
265
+ ```
266
+
267
+ If you don't want to take away a responsibility for the response but still need a raw response instance you can use `{ passthrough: true }` as an argument.
268
+ The next example does the same thing as the previous example using `passthrough` options:
269
+
270
+ ```js
271
+ import { useResponse } from 'wooks'
272
+ app.get('test', () => {
273
+ const { rawResponse } = useResponse()
274
+ const res = rawResponse({ passthrough: true })
275
+ return 'ok'
276
+ })
277
+ ```
278
+
279
+ ### Response Headers
280
+
281
+ A function `useSetHeaders` provides variety of response headers helpers:
282
+
283
+ ```js
284
+ import { useSetHeaders, contentTypes } from 'wooks'
285
+ app.get('test', async () => {
286
+ const {
287
+ setHeader, //sets header: (name: string, value: string | number) => void;
288
+ removeHeader, //removes header: (name: string) => void;
289
+ setContentType, //sets "Content-Type": (value: string) => void;
290
+ headers, //Object with response headers: Record<string, string>;
291
+ enableCors, //sets "Access-Control-Allow-Origin": (origin?: string) => void;
292
+ } = useSetHeaders()
293
+
294
+ setContentType(contentTypes.application.json)
295
+ setHeader('server', 'myServer v1.0')
296
+ enableCors()
297
+ return '{ "value": "OK" }'
298
+ })
299
+ ```
300
+
301
+ ### Response Cookies (Set-Cookie)
302
+
303
+ A function `useSetCookies` provides variety of set-cookie helpers:
304
+
305
+ ```js
306
+ import { useSetCookies } from 'wooks'
307
+ app.get('test', async () => {
308
+ const {
309
+ setCookie, // sets cookie : (name: string, value: string, attrs?) => void;
310
+ removeCookie, // removes cookie from setlist : (name: string) => void;
311
+ clearCookies, // removes all the cookies from setlist : () => void;
312
+ cookies, // returns a value of Set-Cookie header: () => string[];
313
+ } = useSetCookies()
314
+
315
+ setCookie('session', {
316
+ expires: '2029-01-01', // Date | string | number;
317
+ maxAge: '1h', // number | TProstoTimeMultiString;
318
+ domain: 'my-domain', // string;
319
+ path: '/home', // string;
320
+ secure: true, // boolean;
321
+ httpOnly: false, // boolean;
322
+ sameSite: true, // boolean | 'Lax' | 'None' | 'Strict';
323
+ })
324
+ })
325
+ ```
326
+
327
+ ### Response Status
328
+
329
+ It's possible to control the response status via `status` function that is available in `useResponse()`
330
+
331
+ ```js
332
+ import { useResponse } from 'wooks'
333
+ app.get('test', async () => {
334
+ const { status } = useResponse()
335
+ status(201) // sets status 201 for the response
336
+ console.log(status()) // when called with no argument returns the status
337
+ return 'response with status 201'
338
+ })
339
+ ```
340
+
341
+ ### Cache-Control
342
+
343
+ `useSetCacheControl` function provides helpers for headers responsible for cache control
344
+
345
+ ```js
346
+ import { useSetCacheControl } from 'wooks'
347
+ app.get('static/*', () => {
348
+ const {
349
+ setAge, // sets Age (v: number | TProstoTimeMultiString) => void
350
+ setExpires, // sets Expires (v: Date | string | number) => void
351
+ setPragmaNoCache, // sets Pragma: no-cache (v: boolean) => void
352
+ setCacheControl, // sets Cache-Control (data: TCacheControl) => void
353
+ } = useSetCacheControl()
354
+
355
+ setAge('2h 15m')
356
+ setExpires('2022-05-05')
357
+ setCacheControl({
358
+ mustRevalidate: true,
359
+ noCache: false,
360
+ noStore: false,
361
+ noTransform: true,
362
+ public: true,
363
+ private: 'field',
364
+ proxyRevalidate: true,
365
+ maxAge: '3h 30m 12s',
366
+ sMaxage: '2h 27m 54s',
367
+ })
368
+ })
369
+ ```
370
+
371
+ ### Serve File (Serve-Static)
372
+
373
+ Function `serveFile` returns a readable stream and prepares all the neccessary response headers (like content-length, content-type etc).
374
+
375
+ It can handle etag and range as well.
376
+
377
+ ```js
378
+ serveFile(filePath, options)
379
+ ```
380
+
381
+ **serveFile options**
382
+ ```ts
383
+ {
384
+ // Any header to add
385
+ headers?: Record<string, string>
386
+
387
+ // Cache-Control header
388
+ cacheControl?: TCacheControl
389
+
390
+ // Expires header
391
+ expires?: Date | string | number
392
+
393
+ // when true a header "Pragma: no-cache" will be added
394
+ pragmaNoCache?: boolean
395
+
396
+ // the base directory path
397
+ baseDir?: string
398
+
399
+ // default extension will be added to the filePath
400
+ defaultExt?: string
401
+
402
+ // when true lists files in directory
403
+ listDirectory?: boolean
404
+
405
+ // put 'index.html'
406
+ // to automatically serve it from the folder
407
+ index?: string
408
+ }
409
+ ```
410
+
411
+ Built-in file server example:
412
+
413
+ ```js
414
+ import { serveFile, useRouteParams } from 'wooks'
415
+ app.get('static/*', () => {
416
+ const { getRouteParam } = useRouteParams()
417
+ return serveFile(getRouteParam('*'), { cacheControl: { maxAge: '10m' } })
418
+ })
419
+ ```
420
+
421
+ `cacheControl` here is the same object as used in `useSetCacheControl().setCacheControl({ ... })`
422
+
423
+ ## Error Handling
424
+
425
+ All the exeptions occured in handler are cought by the framework and interpreted as Server Error 500.
426
+
427
+
428
+ ```js
429
+ app.get('error', () => {
430
+ throw new Error('Some Error')
431
+ // A call of this endpoint will result in
432
+ // 500 Internal Server Error
433
+ // "Some Error"
434
+ })
435
+ ```
436
+
437
+ By default the Error Handler renders the response according to the `Accept` request header:
438
+ - if it accepts 'application/json' then the response will be in JSON format
439
+ - else if it accepts 'text/html' then the response will be in HTML format
440
+ - else if it accepts 'text/plain' then the response will be rendered in a plain text
441
+ - else the response will be in JSON format anyways
442
+
443
+ It's possible to return your own error:
444
+
445
+ ```js
446
+ import { WooksError } from 'wooks'
447
+ app.get('error', () => {
448
+ throw new WooksError('429', 'My Description')
449
+ // A call of this endpoint will result in
450
+ // 429 Too Many Requests
451
+ // "My Description"
452
+ })
453
+ ```
454
+
455
+ In this case if you have an alternative (fallback) handler for the same route the error may not occure, the next handler will be called instead.
456
+
457
+ As an alternative you may not throw the error but return its instance:
458
+
459
+ ```js
460
+ import { WooksError } from 'wooks'
461
+ app.get('error', () => {
462
+ return new WooksError('429', 'My Description')
463
+ // A call of this endpoint will result in
464
+ // 429 Too Many Requests
465
+ // "My Description"
466
+ })
467
+ ```
468
+
469
+ In this case if you have an alternative (fallback) handler for the same route the error will occure anyways as you explicitly return its instance.
470
+
471
+ ## Alternative (Fallback) Handler
472
+
473
+ It's possible to assign several handlers for the same route. Every next handler will work as a fallback for the previous one.
474
+
475
+ The fallback handler is called only when exception is thrown out of the previous handler.
476
+
477
+ If the previous handler returns an Error Instance then the fallback handler won't be called.
478
+
479
+ For example you serve files, but for some 'not found' files you want to do something else:
480
+
481
+ ```js
482
+ import { Wooks, serveFile, useRouteParams } from 'wooks'
483
+ const app = new Wooks()
484
+
485
+ app.get('static/*', () => {
486
+ const { getRouteParam } = useRouteParams()
487
+ // serveFile will throw 404 error if the file is not found
488
+ return serveFile(getRouteParam('*'), { maxAge: '10m' })
489
+ })
490
+
491
+ app.get('static/*', () => {
492
+ // this handler will be called every time the file is not found
493
+ return 'Here\'s my fallback response'
494
+ })
495
+
496
+ app.listen(3000)
497
+ ```
498
+
499
+ In order to prevent the fallback to be invoked you must return an Error Instance explicitly:
500
+
501
+ ```js
502
+ import { Wooks, serveFile, useRouteParams } from 'wooks'
503
+ const app = new Wooks()
504
+
505
+ app.get('static/*', () => {
506
+ const { getRouteParam } = useRouteParams()
507
+ try {
508
+ return serveFile(getRouteParam('*'), { maxAge: '10m' })
509
+ }
510
+ catch (e) {
511
+ // now we catch error and return it explicitly
512
+ return e
513
+ }
514
+ })
515
+
516
+ app.get('static/*', () => {
517
+ // this handler will be never called now
518
+ return 'Here\'s my fallback response which is never (ever) called'
519
+ })
520
+
521
+ app.listen(3000)
522
+ ```
@@ -0,0 +1,17 @@
1
+ /// <reference types="node" />
2
+ import { TBodyCompressor } from '../utils/body-compressor';
3
+ export declare function useBody(): {
4
+ isJson: () => boolean;
5
+ isHtml: () => boolean;
6
+ isXml: () => boolean;
7
+ isText: () => boolean;
8
+ isBinary: () => boolean;
9
+ isFormData: () => boolean;
10
+ isUrlencoded: () => boolean;
11
+ isCompressed: () => boolean | undefined;
12
+ contentEncodings: () => string[];
13
+ parseBody: <T = unknown>() => Promise<T>;
14
+ rawBody: () => Promise<Buffer>;
15
+ };
16
+ export declare function registerBodyCompressor(name: string, compressor: TBodyCompressor): void;
17
+ //# sourceMappingURL=body.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"body.d.ts","sourceRoot":"","sources":["../../../src/composables/body.ts"],"names":[],"mappings":";AAIA,OAAO,EAAe,eAAe,EAAkB,MAAM,0BAA0B,CAAA;AAkBvF,wBAAgB,OAAO;;;;;;;;;4BAqEU,MAAM,EAAE;;;EAmGxC;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,QAK/E"}
@@ -0,0 +1,13 @@
1
+ import { TCookieAttributes } from '../utils/set-cookie';
2
+ export declare type TCookiesCache = Record<string, string | null>;
3
+ export declare function useCookies(): {
4
+ rawCookies: string | undefined;
5
+ getCookie: (name: string) => string | null;
6
+ };
7
+ export declare function useSetCookies(): {
8
+ setCookie: (name: string, value: string, attrs?: Partial<TCookieAttributes>) => void;
9
+ removeCookie: (name: string) => void;
10
+ clearCookies: () => void;
11
+ cookies: () => string[];
12
+ };
13
+ //# sourceMappingURL=cookies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../../../src/composables/cookies.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgB,iBAAiB,EAAkB,MAAM,qBAAqB,CAAA;AAErF,oBAAY,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAA;AAGzD,wBAAgB,UAAU;;sBAIG,MAAM;EAgBlC;AAED,wBAAgB,aAAa;sBAGA,MAAM,SAAS,MAAM,UAAU,QAAQ,iBAAiB,CAAC;yBAWtD,MAAM;;mBAJd,MAAM,EAAE;EAkB/B"}
@@ -0,0 +1,19 @@
1
+ /// <reference types="node" />
2
+ import { TProstoParamsType } from '@prostojs/router';
3
+ import { TCookiesCache } from './cookies';
4
+ import { TAuthCache } from './header-authorization';
5
+ export interface TTestHttpContext {
6
+ params?: TProstoParamsType;
7
+ url: string;
8
+ headers?: Record<string, string>;
9
+ method?: string;
10
+ cachedContext?: {
11
+ cookies?: TCookiesCache;
12
+ authorization?: TAuthCache;
13
+ body?: unknown;
14
+ rawBody?: string | Buffer | Promise<Buffer>;
15
+ [name: string | symbol]: unknown;
16
+ };
17
+ }
18
+ export declare function setTestHttpContext(options: TTestHttpContext): void;
19
+ //# sourceMappingURL=core-test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core-test.d.ts","sourceRoot":"","sources":["../../../src/composables/core-test.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAIzC,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAEnD,MAAM,WAAW,gBAAgB;IAC7B,MAAM,CAAC,EAAE,iBAAiB,CAAA;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,aAAa,CAAC,EAAE;QACZ,OAAO,CAAC,EAAE,aAAa,CAAA;QACvB,aAAa,CAAC,EAAE,UAAU,CAAA;QAC1B,IAAI,CAAC,EAAE,OAAO,CAAA;QACd,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;QAC3C,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;KACnC,CAAA;CACJ;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,QA2B3D"}
@@ -0,0 +1,30 @@
1
+ /// <reference types="node" />
2
+ import { TProstoParamsType } from '@prostojs/router';
3
+ import { IncomingMessage, ServerResponse } from 'http';
4
+ export interface TCurrentWooksContext {
5
+ req: IncomingMessage;
6
+ res: ServerResponse;
7
+ params: TProstoParamsType;
8
+ customContext: TWooksCustomContext;
9
+ }
10
+ export declare type TWooksCustomContext = Record<string | symbol, unknown>;
11
+ export declare function useCurrentWooksContext(): {
12
+ getCtx: () => TCurrentWooksContext;
13
+ restoreCtx: () => void;
14
+ };
15
+ export declare function clearCurrentWooksContext(): void;
16
+ export declare function setCurrentWooksContext(req: IncomingMessage, res: ServerResponse, params: TProstoParamsType, customContext: TWooksCustomContext): void;
17
+ export declare const innerCacheSymbols: {
18
+ searchParams: symbol;
19
+ cookies: symbol;
20
+ accept: symbol;
21
+ authorization: symbol;
22
+ setHeader: symbol;
23
+ setCookies: symbol;
24
+ status: symbol;
25
+ response: symbol;
26
+ request: symbol;
27
+ };
28
+ export declare function useCacheObject<T = unknown>(name: symbol | string): T;
29
+ export declare function clearCacheObject(name: symbol | string): void;
30
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../src/composables/core.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAA;AAGtD,MAAM,WAAW,oBAAoB;IACjC,GAAG,EAAE,eAAe,CAAA;IACpB,GAAG,EAAE,cAAc,CAAA;IACnB,MAAM,EAAE,iBAAiB,CAAA;IACzB,aAAa,EAAE,mBAAmB,CAAA;CACrC;AAID,oBAAY,mBAAmB,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC,CAAA;AAElE,wBAAgB,sBAAsB;;;EASrC;AAED,wBAAgB,wBAAwB,SAEvC;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,iBAAiB,EAAE,aAAa,EAAE,mBAAmB,QAE9I;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;CAU7B,CAAA;AAED,wBAAgB,cAAc,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,CAAC,CAIpE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,QAkBrD"}
@@ -0,0 +1,9 @@
1
+ export declare function useAccept(): {
2
+ accept: string | undefined;
3
+ accepts: (mime: string) => boolean;
4
+ acceptsJson: () => boolean;
5
+ acceptsXml: () => boolean;
6
+ acceptsText: () => boolean;
7
+ acceptsHtml: () => boolean;
8
+ };
9
+ //# sourceMappingURL=header-accept.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"header-accept.d.ts","sourceRoot":"","sources":["../../../src/composables/header-accept.ts"],"names":[],"mappings":"AAIA,wBAAgB,SAAS;;oBAGE,MAAM;;;;;EAchC"}
@@ -0,0 +1,20 @@
1
+ export declare type TAuthCache = {
2
+ type: string | null;
3
+ credentials: string | null;
4
+ basicCredentials: {
5
+ username: string;
6
+ password: string;
7
+ } | null;
8
+ };
9
+ export declare function useAuthorization(): {
10
+ authorization: string | undefined;
11
+ authType: () => string | null;
12
+ authRawCredentials: () => string | null;
13
+ isBasic: () => boolean;
14
+ isBearer: () => boolean;
15
+ basicCredentials: () => {
16
+ username: string;
17
+ password: string;
18
+ } | null;
19
+ };
20
+ //# sourceMappingURL=header-authorization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"header-authorization.d.ts","sourceRoot":"","sources":["../../../src/composables/header-authorization.ts"],"names":[],"mappings":"AAGA,oBAAY,UAAU,GAAG;IACrB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,gBAAgB,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;CAClE,CAAA;AAED,wBAAgB,gBAAgB;;;;;;;;;;EA4C/B"}