dx-server 0.8.4 → 0.9.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.
package/README.md CHANGED
@@ -1,43 +1,126 @@
1
- # dx-server - modern, unopinionated, and satisfactory server
1
+ # dx-server
2
+
3
+ A modern, unopinionated, and performant Node.js server framework built on AsyncLocalStorage for elegant request/response handling without prop drilling.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/dx-server.svg)](https://www.npmjs.com/package/dx-server)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## Features
9
+
10
+ - 🚀 **Context-based architecture** - Access request/response from anywhere using AsyncLocalStorage
11
+ - 🔗 **Chainable middleware** - Elegant middleware composition with [jchain](https://www.npmjs.com/package/jchain)
12
+ - 🎯 **Type-safe** - Written in TypeScript with comprehensive type definitions
13
+ - 🔄 **Express compatible** - Use existing Express middleware and applications
14
+ - 📦 **Minimal dependencies** - Only one runtime dependency (`send` for static file serving, planned for removal)
15
+ - 🛡️ **Built-in body parsing** - JSON, text, URL-encoded, and raw body parsing with size limits
16
+ - 🗂️ **Static file serving** - Efficient static file handling with ETag support
17
+ - 🔀 **Modern routing** - URLPattern-based routing (not Express patterns)
18
+
19
+ ## Installation
2
20
 
3
- ## Install
4
21
  ```bash
22
+ # npm
23
+ npm install dx-server jchain
24
+
25
+ # yarn
5
26
  yarn add dx-server jchain
27
+
28
+ # pnpm
29
+ pnpm add dx-server jchain
6
30
  ```
7
31
 
8
- ## Usage
32
+ ### URLPattern Support
33
+
34
+ dx-server uses the [URLPattern API](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern) for routing, which is natively supported in Node.js v19.0.0 and later.
9
35
 
10
- Check below sample with comment for more details.
36
+ **For Node.js < 19.0.0**, you need to install a polyfill:
11
37
 
12
- Simple server
38
+ ```bash
39
+ npm install urlpattern-polyfill
40
+ ```
41
+
42
+ Then import it before using dx-server:
43
+
44
+ ```javascript
45
+ // Add this at the top of your entry file
46
+ import 'urlpattern-polyfill'
47
+
48
+ // Then import dx-server
49
+ import dxServer from 'dx-server'
50
+ ```
51
+
52
+ To check if your runtime supports URLPattern natively:
53
+
54
+ ```javascript
55
+ if (typeof URLPattern === 'undefined') {
56
+ console.log('URLPattern not supported, polyfill required')
57
+ }
58
+ ```
59
+
60
+ ### Future Roadmap
61
+
62
+ **Zero Dependencies**: The `send` package (currently used for static file serving) is planned for removal in a future version. This will make dx-server a true zero-dependency framework. Until then, if you don't need static file serving, the `send` dependency won't be loaded or affect your application.
63
+
64
+ ## Quick Start
65
+
66
+ ### Basic Server
13
67
 
14
68
  ```javascript
15
69
  import {Server} from 'node:http'
16
70
  import chain from 'jchain'
17
- import dxServer, {getReq, getRes, router, setHtml, setText,} from 'dx-server'
71
+ import dxServer, {getReq, getRes, router, setHtml, setText} from 'dx-server'
18
72
 
19
73
  new Server().on('request', (req, res) => chain(
20
- dxServer(req, res),
21
- async next => {
22
- try {
23
- getRes().setHeader('Cache-Control', 'no-cache')
24
- console.log(getReq().method, getReq().url)
25
- await next()
26
- } catch (e) {
27
- console.error(e)
28
- setHtml('internal server error', {status: 500})
29
- }
30
- },
31
- router.get({
32
- '/'() {setHtml('hello world')},
33
- '/health'() {setText('ok')}
34
- }),
35
- () => setHtml('not found', {status: 404}),
36
- )()
37
- ).listen(3000, () => console.log('server is listening at 3000'))
74
+ dxServer(req, res),
75
+ async next => {
76
+ try {
77
+ // Access req/res from anywhere - no prop drilling!
78
+ getRes().setHeader('Cache-Control', 'no-cache')
79
+ console.log(getReq().method, getReq().url)
80
+ await next()
81
+ } catch (e) {
82
+ console.error(e)
83
+ setHtml('internal server error', {status: 500})
84
+ }
85
+ },
86
+ router.get({
87
+ '/'() {setHtml('hello world')},
88
+ '/health'() {setText('ok')}
89
+ }),
90
+ () => setHtml('not found', {status: 404}),
91
+ )()).listen(3000, () => console.log('server is listening at 3000'))
92
+ ```
93
+
94
+ ### TypeScript Example
95
+
96
+ ```typescript
97
+ import {Server} from 'node:http'
98
+ import chain from 'jchain'
99
+ import dxServer, {router, setJson, getJson} from 'dx-server'
100
+
101
+ interface User {
102
+ id: number
103
+ name: string
104
+ }
105
+
106
+ new Server().on('request', (req, res) => chain(
107
+ dxServer(req, res),
108
+ router.post({
109
+ async '/api/users'() {
110
+ const body = await getJson<{name: string}>()
111
+ if (!body?.name) {
112
+ setJson({error: 'Name required'}, {status: 400})
113
+ return
114
+ }
115
+ const user: User = {id: 1, name: body.name}
116
+ setJson(user, {status: 201})
117
+ }
118
+ }),
119
+ () => setJson({error: 'Not found'}, {status: 404})
120
+ )()).listen(3000)
38
121
  ```
39
122
 
40
- File server:
123
+ ### Static File Server
41
124
 
42
125
  ```javascript
43
126
  import {Server} from 'node:http'
@@ -47,15 +130,19 @@ import {resolve, dirname} from 'node:path'
47
130
  import {fileURLToPath} from 'node:url'
48
131
 
49
132
  new Server().on('request', (req, res) => chain(
50
- dxServer(req, res),
51
- chainStatic('/*', {root: resolve(dirname(fileURLToPath(import.meta.url)), 'public')}),
52
- () => setHtml('not found', {status: 404}),
53
- )()
54
- ).listen(3000, () => console.log('server is listening at 3000'))
133
+ dxServer(req, res),
134
+ chainStatic('/*', {
135
+ root: resolve(dirname(fileURLToPath(import.meta.url)), 'public'),
136
+ index: ['index.html'],
137
+ dotfiles: 'deny'
138
+ }),
139
+ () => setHtml('not found', {status: 404}),
140
+ )()).listen(3000)
55
141
  ```
56
142
 
57
- More complex server with express.
58
- This sample additionally requires: `yarn install express morgan`
143
+ ### Production-Ready Server with Express Integration
144
+
145
+ This example requires: `npm install express morgan helmet cors`
59
146
 
60
147
 
61
148
  ```javascript
@@ -88,7 +175,7 @@ const authContext = makeDxContext(async () => {
88
175
  })
89
176
 
90
177
  const requireAuth = () => {
91
- if (!authContext.value) throw new ServerError('unauthorized', 401, 'unauthorized')
178
+ if (!authContext.value) throw new ServerError('Unauthorized', 401, 'UNAUTHORIZED')
92
179
  }
93
180
 
94
181
  const serverChain = chain(
@@ -148,7 +235,7 @@ const serverChain = chain(
148
235
  router.get('/', () => setHtml('ok')), // router.method() accepts 2 formats
149
236
  router.get('/health', () => setText('ok')),
150
237
  () => { // not found router
151
- throw new ServerError('not found', 404, 'not_found')
238
+ throw new ServerError('Not found', 404, 'NOT_FOUND')
152
239
  },
153
240
  )
154
241
 
@@ -169,196 +256,426 @@ await promisify(tcpServer.listen.bind(tcpServer))(3000)
169
256
  console.log('server is listening at 3000')
170
257
  ```
171
258
 
172
- ## Note:
259
+ ## Core Concepts
260
+
261
+ ### Context-Based Architecture
262
+
263
+ dx-server uses Node.js AsyncLocalStorage to provide request/response context globally, eliminating prop drilling:
264
+
265
+ ```javascript
266
+ // Access request/response from anywhere
267
+ import {getReq, getRes} from 'dx-server'
268
+
269
+ function someDeepFunction() {
270
+ const req = getReq() // No need to pass req through multiple layers
271
+ const res = getRes()
272
+ res.setHeader('X-Custom', 'value')
273
+ }
274
+ ```
275
+
276
+ ### Lazy Body Parsing
173
277
 
174
- `getBuffer, getJson, getRaw, getText, getUrlEncoded, getQuery` are all asynchronous functions.
175
- The associated results are calculated in the first time they are called and cached for subsequent calls.
278
+ Body parsing functions are asynchronous and cached per request:
176
279
 
177
- If you want to get these values synchronously, chain it, like follows:
178
280
  ```javascript
179
- import {getJson} from 'dx-server'
281
+ import {getJson, getText, getBuffer, getUrlEncoded} from 'dx-server'
282
+
283
+ // Async usage (lazy-loaded and cached)
284
+ const json = await getJson()
285
+ const text = await getText()
180
286
 
287
+ // Sync usage (requires chaining)
181
288
  chain(
182
- getJson.chain(/*option*/), // json body is parsed and stored in context in every request
183
- next => {
184
- console.log(getJson.value) // json body can be accessed synchronously
185
- return next()
186
- }
289
+ getJson.chain({bodyLimit: 1024 * 1024}), // 1MB limit
290
+ next => {
291
+ console.log(getJson.value) // Access synchronously
292
+ return next()
293
+ }
187
294
  )
188
295
  ```
189
296
 
190
- Context can be created using `makeDxContext` function:
297
+ ### Custom Contexts
298
+
299
+ Create reusable context objects with `makeDxContext`:
191
300
 
192
301
  ```javascript
193
- import {makeDxContext} from 'dx-server'
302
+ import {makeDxContext, getReq} from 'dx-server'
194
303
 
195
- const authContext = makeDxContext(() => {
196
- if (getReq().headers.authorization) return {id: 1, name: 'joe (authorized)'}
304
+ // Create auth context
305
+ const authContext = makeDxContext(async () => {
306
+ const token = getReq().headers.authorization
307
+ if (!token) return null
308
+ return await validateToken(token) // Your validation logic
197
309
  })
198
- const requireAuth = () => {
199
- if (!authContext.value) throw new Error('unauthorized')
200
- }
201
- chain(
202
- authContext.chain(),
203
- next => {
204
- requireAuth()
205
- return next()
206
- }
207
- )
208
- // or await authContext() to lazy load the context and don't require chaining authContext.chain()
310
+
311
+ // Use in middleware
209
312
  chain(
210
- async next => {
211
- console.log(await authContext())
212
- return next()
213
- }
313
+ authContext.chain(), // Initialize for all requests
314
+ next => {
315
+ if (!authContext.value) {
316
+ setJson({error: 'Unauthorized'}, {status: 401})
317
+ return
318
+ }
319
+ return next()
320
+ }
214
321
  )
322
+
215
323
  ```
216
324
 
217
- # API References
218
- All exported APIs:
325
+ ## API Reference
326
+
327
+ ### Main Exports
328
+
219
329
  ```javascript
220
330
  import dxServer, {
221
- getReq, getRes, getBuffer, getJson, getRaw, getText, getUrlEncoded, getQuery,
222
- setHtml, setJson, setText, setEmpty, setBuffer, setRedirect, setNodeStream, setWebStream, setFile,
223
- router, connectMiddlewares, chainStatic, makeDxContext
331
+ // Request/Response access
332
+ getReq, getRes,
333
+
334
+ // Request body parsers
335
+ getBuffer, getJson, getRaw, getText, getUrlEncoded, getQuery,
336
+
337
+ // Response setters
338
+ setHtml, setJson, setText, setEmpty, setBuffer, setRedirect,
339
+ setNodeStream, setWebStream, setFile,
340
+
341
+ // Utilities
342
+ router, connectMiddlewares, chainStatic, makeDxContext
224
343
  } from 'dx-server'
225
- import {expressApp, expressRouter} from 'dx-server/express' // requires express installed
344
+
345
+ // Express integration (requires express installed)
346
+ import {expressApp, expressRouter} from 'dx-server/express'
347
+
348
+ // Low-level helpers
226
349
  import {
227
- setBufferBodyDefaultOptions,
228
- bufferFromReq, jsonFromReq, rawFromReq, textFromReq, urlEncodedFromReq, queryFromReq,
350
+ setBufferBodyDefaultOptions,
351
+ bufferFromReq, jsonFromReq, rawFromReq, textFromReq,
352
+ urlEncodedFromReq, queryFromReq,
229
353
  } from 'dx-server/helpers'
230
354
  ```
231
355
 
232
- ## Basic
233
- ```javascript
234
- import dxServer, {
235
- getReq, getRes, getBuffer, getJson, getRaw, getText, getUrlEncoded, getQuery,
236
- setHtml, setJson, setText, setEmpty, setBuffer, setRedirect, setNodeStream, setWebStream, setFile,
237
- makeDxContext
238
- } from 'dx-server'
356
+ ### Core Functions
357
+
358
+ #### Request/Response Access
359
+ - **`getReq()`** - Get the current request object
360
+ - **`getRes()`** - Get the current response object
361
+
362
+ #### Body Parsers
363
+ All body parsers are async, lazy-loaded, and cached per request:
364
+
365
+ - **`getJson(options?)`** - Parse JSON body (requires `Content-Type: application/json`)
366
+ - **`getText(options?)`** - Parse text body (requires `Content-Type: text/plain`)
367
+ - **`getBuffer(options?)`** - Get raw buffer
368
+ - **`getRaw(options?)`** - Get raw body (requires `Content-Type: application/octet-stream`)
369
+ - **`getUrlEncoded(options?)`** - Parse URL-encoded form (requires `Content-Type: application/x-www-form-urlencoded`)
370
+ - **`getQuery(options?)`** - Parse query string parameters
371
+
372
+ Options:
373
+ ```typescript
374
+ {
375
+ bodyLimit?: number // Max body size in bytes (default: 100KB)
376
+ urlEncodedParser?: (search: string) => any
377
+ queryParser?: (search: string) => any
378
+ }
239
379
  ```
240
380
 
241
- - `getReq()`, `getRes()`: get request and response objects from anywhere.
381
+ #### Response Setters
382
+ - **`setJson(data, {status?, headers?})`** - Send JSON response
383
+ - **`setHtml(html, {status?, headers?})`** - Send HTML response
384
+ - **`setText(text, {status?, headers?})`** - Send plain text
385
+ - **`setBuffer(buffer, {status?, headers?})`** - Send buffer
386
+ - **`setFile(path, options?)`** - Send file
387
+ - **`setNodeStream(stream, {status?, headers?})`** - Send Node.js stream
388
+ - **`setWebStream(stream, {status?, headers?})`** - Send Web stream
389
+ - **`setRedirect(url, {status?, headers?})`** - Redirect response
390
+ - **`setEmpty({status?, headers?})`** - Send empty response
391
+
392
+ #### Context Management
393
+ - **`makeDxContext(fn)`** - Create a custom context object
394
+ ```javascript
395
+ const ctx = makeDxContext(() => computeValue())
396
+
397
+ // Access value
398
+ await ctx() // Lazy load
399
+ ctx.value // Sync access (after loading)
400
+ ctx.get(req) // Get for specific request
401
+
402
+ // Set value
403
+ ctx.value = newValue
404
+ ctx.set(req, newValue)
405
+ ```
406
+
407
+ #### Middleware Utilities
408
+ - **`connectMiddlewares(...middlewares)`** - Use Connect/Express middleware
409
+ - **`chainStatic(pattern, options)`** - Serve static files
410
+ ```javascript
411
+ chainStatic('/public/*', {
412
+ root: '/path/to/files',
413
+ index: ['index.html'],
414
+ dotfiles: 'deny',
415
+ etag: true,
416
+ lastModified: true
417
+ })
418
+ ```
419
+
420
+ ### Routing
421
+
422
+ dx-server uses [URLPattern API](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern) for routing, which differs from Express patterns:
423
+
424
+ ```javascript
425
+ import {router} from 'dx-server'
426
+
427
+ // Single route
428
+ router.get('/users/:id', ({matched}) => {
429
+ const {id} = matched.pathname.groups
430
+ setJson({userId: id})
431
+ })
242
432
 
243
- - `getBuffer()`, `getJson()`, `getRaw()`, `getText()`, `getUrlEncoded()`, `getQuery()`: get parsed request body, raw body, text body, url encoded body, query string from anywhere.
244
- These are DX context object, can be used as follows:
245
- - `const json = await getJson()`: lazily load the context, once loaded, it is cached for subsequent calls.
246
- No chaining is required.
247
- - Chain it to get the value synchronously: `chain(getJson.chain(), next => console.log(getJson.value))`. Note that the value is calculated in every request.
248
- - `ctx = makeDxContext(fn)`: create a DX context object.
249
- `fn` is called once per request to calculate the value.
250
- The value is cached for subsequent calls.
433
+ // Multiple routes
434
+ router.post({
435
+ '/api/users': () => { /* create user */ },
436
+ '/api/users/:id': ({matched}) => { /* update user */ },
437
+ '/api/users/:id/posts': ({matched}) => { /* get user posts */ }
438
+ })
439
+
440
+ // All HTTP methods supported
441
+ router.get(pattern, handler)
442
+ router.post(pattern, handler)
443
+ router.put(pattern, handler)
444
+ router.delete(pattern, handler)
445
+ router.patch(pattern, handler)
446
+ router.head(pattern, handler)
447
+ router.options(pattern, handler)
448
+ router.all(pattern, handler) // Any method
449
+
450
+ // Custom method
451
+ router.method('CUSTOM', pattern, handler)
452
+
453
+ // With prefix option
454
+ router.get({
455
+ '/users': listUsers,
456
+ '/users/:id': getUser
457
+ }, {prefix: '/api'}) // Routes become /api/users, /api/users/:id
458
+ ```
251
459
 
252
- - Context value can be accessed by:
460
+ #### URLPattern vs Express Patterns
253
461
 
254
- - `const value = await ctx()`: lazily load the context, once loaded, it is cached for subsequent calls.
255
- - `const value = ctx.value`: get the value synchronously. Note that the value must be fetched at least once before via `await ctx()` or by chaining `chain(ctx.chain())`.
256
- - `const value = ctx.get(req)`: similar condition as `ctx.value`.
462
+ | Pattern | URLPattern | Express |
463
+ |---------|------------|---------|
464
+ | Wildcard | `/api/*` | `/api/*` or `/api/(.*)` |
465
+ | Optional trailing slash | `{/}?` | `/path/?` |
466
+ | Named params | `/:id` | `/:id` |
467
+ | Optional params | `/:id?` | `/:id?` |
257
468
 
258
- - Context value can be set or overridden by:
469
+ **Important differences:**
470
+ - `'/foo'` matches `/foo` but NOT `/foo/`
471
+ - `'/foo/'` matches `/foo/` but NOT `/foo`
472
+ - Use `'/foo{/}?'` to match both
259
473
 
260
- - `ctx.value = value`.
261
- - `ctx.set(req, value)`.
474
+ ### Express Integration
262
475
 
263
- - `setHtml`, `setJson`, `setText`, `setEmpty`, `setBuffer`, `setRedirect`, `setNodeStream`, `setWebStream`, `setFile`: set response body.
476
+ dx-server seamlessly integrates with Express applications and middleware:
264
477
 
265
- - `connectMiddlewares(...middlewares)`: connect middlewares. For example:
266
478
  ```javascript
267
- import {connectMiddlewares} from 'dx-server'
268
- import morgan from 'morgan'
479
+ import {expressApp, expressRouter} from 'dx-server/express'
480
+ import express from 'express'
269
481
  import cors from 'cors'
482
+ import helmet from 'helmet'
270
483
 
271
- connectMiddlewares(
272
- morgan('common'),
273
- cors(),
484
+ chain(
485
+ // Use entire Express app
486
+ await expressApp(app => {
487
+ app.set('trust proxy', true)
488
+ app.set('json spaces', 2)
489
+ app.use(helmet())
490
+ app.use('/static', express.static('public'))
491
+ }),
492
+
493
+ // Or use Express router
494
+ expressRouter(router => {
495
+ router.use(cors())
496
+ router.get('/legacy', (req, res) => {
497
+ res.json({message: 'Express route'})
498
+ })
499
+ })
274
500
  )
275
501
  ```
276
502
 
277
- - `chainStatic(path, options)`: serve static files. For example:
503
+ ### Low-Level Helpers
504
+
505
+ Pure functions for custom implementations:
506
+
278
507
  ```javascript
279
- import {chainStatic} from 'dx-server'
280
- import {resolve, dirname} from 'node:path'
281
- import {fileURLToPath} from 'node:url'
508
+ import {
509
+ setBufferBodyDefaultOptions,
510
+ bufferFromReq, jsonFromReq, rawFromReq,
511
+ textFromReq, urlEncodedFromReq, queryFromReq
512
+ } from 'dx-server/helpers'
282
513
 
514
+ // Set global defaults
515
+ setBufferBodyDefaultOptions({
516
+ bodyLimit: 10 * 1024 * 1024, // 10MB
517
+ queryParser: (search) => myCustomParser(search)
518
+ })
519
+
520
+ // Use directly with req/res (no context required)
521
+ const json = await jsonFromReq(req, {bodyLimit: 1024})
522
+ const query = queryFromReq(req)
523
+ ```
524
+
525
+ ## Security Considerations
526
+
527
+ ### Body Size Limits
528
+ Always set appropriate body size limits to prevent DoS attacks:
529
+
530
+ ```javascript
283
531
  chain(
284
- chainStatic('/assets/*', {
285
- root: resolve(dirname(fileURLToPath(import.meta.url)), 'public'),
286
- getPathname(matched) {
287
- return new URL(getReq().url, 'http://localhost').pathname.slice('/assets'.length)
288
- },
289
- }),
532
+ getJson.chain({bodyLimit: 1024 * 1024}), // 1MB limit
533
+ // or globally:
534
+ dxServer(req, res, {bodyLimit: 5 * 1024 * 1024}) // 5MB
290
535
  )
291
536
  ```
292
537
 
293
- ## Routing
538
+ ### Error Handling
539
+ Never expose internal errors to clients:
540
+
294
541
  ```javascript
295
- import {router} from 'dx-server'
296
- ```
542
+ class AppError extends Error {
543
+ constructor(message, status = 400, code = 'ERROR') {
544
+ super(message)
545
+ this.status = status
546
+ this.code = code
547
+ }
548
+ }
297
549
 
298
- - `router.get`, `router.post`, `router.put`, `router.delete`, `router.patch`, `router.head`, `router.options`, `router.connect`, `router.trace`: create router.
299
- These functions accept 2 formats:
300
- - `router.get(routes: {[pattern: string]: Route}, options: RouterOptions)`: create multiple routes.
301
- - `router.get(pattern: string, handler: Route, options: RouterOptions)`: create route for GET method.
550
+ chain(
551
+ async next => {
552
+ try {
553
+ await next()
554
+ } catch (error) {
555
+ if (error instanceof AppError) {
556
+ setJson({error: error.message, code: error.code}, {status: error.status})
557
+ } else {
558
+ console.error(error) // Log for debugging
559
+ setJson({error: 'Internal server error'}, {status: 500})
560
+ }
561
+ }
562
+ }
563
+ )
564
+ ```
302
565
 
303
- - `router.all(...)`: same as `router.get()` but for any method.
304
- - `router.method()`: create router with custom method. Similar to `router.get()`, this function accepts 2 formats.
305
- - `router.method(method: string, routes: {[pattern: string]: Route}, options: RouterOptions)`: create multiple routes.
306
- - `router.method(method: string, pattern: string, handler: Route, options: RouterOptions)`: create route for `method` method.
566
+ ### Input Validation
567
+ Always validate input data:
307
568
 
308
- `RouterOptions` is defined as follows:
309
- ```typescript
310
- interface RouterOptions {
311
- prefix?: string
312
- }
569
+ ```javascript
570
+ router.post('/api/users', async () => {
571
+ const data = await getJson()
572
+
573
+ // Validate
574
+ if (!data?.email || !isValidEmail(data.email)) {
575
+ throw new AppError('Invalid email', 400, 'INVALID_EMAIL')
576
+ }
577
+
578
+ // Process...
579
+ })
313
580
  ```
314
581
 
315
- Patterns are matched using [URLPattern](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern).
316
- This does not always match the same as ExpressJS.
317
- For example, to match any path prefixed with `/api/`, use `/api/*`.
318
- Note the following:
319
- - `''` matches nothing.
320
- - `'/'` matches both https://example.com and https://example.com/.
321
- - `'/foo'` matches https://example.com/foo but not https://example.com/foo/.
322
- - `'/foo/'` matches https://example.com/foo/ but not https://example.com/foo.
582
+ ### Security Headers
583
+ Use security middleware:
323
584
 
324
- `Route` is defined as follows:
325
- ```typescript
326
- interface RouteContext {
327
- matched: URLPatternResult // result returned from URLPattern.exec(). To get params: matched.pathname.groups
328
- next(): any
329
- }
330
- type Route = (context: RouteContext) => any
585
+ ```javascript
586
+ import helmet from 'helmet'
587
+ import cors from 'cors'
588
+
589
+ chain(
590
+ connectMiddlewares(
591
+ helmet(),
592
+ cors({
593
+ origin: process.env.ALLOWED_ORIGINS?.split(','),
594
+ credentials: true
595
+ })
596
+ )
597
+ )
331
598
  ```
332
599
 
333
- ## Helpers
600
+ ## Advanced Examples
601
+
602
+ ### File Upload with Busboy
334
603
  ```javascript
335
- import {
336
- setBufferBodyDefaultOptions,
337
- bufferFromReq, jsonFromReq, rawFromReq, textFromReq, urlEncodedFromReq, queryFromReq,
338
- } from 'dx-server/helpers'
604
+ import busboy from 'busboy'
605
+
606
+ router.post('/upload', () => {
607
+ const req = getReq()
608
+ const bb = busboy({headers: req.headers, limits: {fileSize: 10 * 1024 * 1024}})
609
+
610
+ bb.on('file', (name, file, info) => {
611
+ // Handle file stream
612
+ })
613
+
614
+ req.pipe(bb)
615
+ })
339
616
  ```
340
617
 
341
- Helpers are all pure functions, and do not rely on any context.
342
- These functions are independent of the context and can be used anywhere, even outside of this package.
343
- They require request and response objects to be passed.
618
+ ### WebSocket Upgrade
619
+ ```javascript
620
+ import {WebSocketServer} from 'ws'
621
+
622
+ const wss = new WebSocketServer({noServer: true})
623
+
624
+ server.on('upgrade', (request, socket, head) => {
625
+ if (request.url === '/ws') {
626
+ wss.handleUpgrade(request, socket, head, (ws) => {
627
+ wss.emit('connection', ws, request)
628
+ })
629
+ }
630
+ })
631
+ ```
344
632
 
345
- ## ExpressJS
633
+ ### Rate Limiting
346
634
  ```javascript
347
- import {expressApp, expressRouter} from 'dx-server/express' // requires express installed
635
+ import rateLimit from 'express-rate-limit'
348
636
 
349
637
  chain(
350
- await expressApp(app => {// any express feature can be used. This requires express installed, with for e.g., `yarn add express`
351
- app.set('trust proxy', true)
352
- if (process.env.NODE_ENV !== 'production') app.set('json spaces', 2)
353
- app.use('/public', express.static('public'))
354
- }),
355
- expressRouter(router => {
356
- router.use(cors())
357
- }),
638
+ connectMiddlewares(
639
+ rateLimit({
640
+ windowMs: 15 * 60 * 1000, // 15 minutes
641
+ max: 100 // limit each IP to 100 requests per windowMs
642
+ })
643
+ )
358
644
  )
359
645
  ```
360
646
 
361
- ## Other functionalities
362
- - Download file: set the [Content-Disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition) header.
363
- - Upload file: recommend [busboy](https://www.npmjs.com/package/busboy) package.
364
- - Cookie: recommend [cookie](https://www.npmjs.com/package/cookie) package.
647
+ ## Performance Tips
648
+
649
+ 1. **Use lazy body parsing** - Only parse bodies when needed
650
+ 2. **Enable compression** at reverse proxy level (nginx, CDN)
651
+ 3. **Use streaming** for large responses:
652
+ ```javascript
653
+ import {createReadStream} from 'fs'
654
+ setNodeStream(createReadStream('large-file.pdf'))
655
+ ```
656
+ 4. **Cache contexts** that are expensive to compute
657
+ 5. **Use `chainStatic` with proper cache headers** for static assets
658
+
659
+ ## Migration from Express
660
+
661
+ ```javascript
662
+ // Express
663
+ app.get('/users/:id', (req, res) => {
664
+ const {id} = req.params
665
+ res.json({userId: id})
666
+ })
667
+
668
+ // dx-server
669
+ router.get('/users/:id', ({matched}) => {
670
+ const {id} = matched.pathname.groups
671
+ setJson({userId: id})
672
+ })
673
+ ```
674
+
675
+ ## Contributing
676
+
677
+ Contributions are welcome! Please feel free to submit a Pull Request.
678
+
679
+ ## License
680
+
681
+ MIT © [Sang Tran](https://github.com/tranvansang)
package/cjs/dx.js CHANGED
@@ -9,7 +9,7 @@ function makeDxContext(maker) {
9
9
  // wrap in an async function to ensure the maker is called only once
10
10
  const context = (...params) => getReq()[promiseSymbol] ??= (async () => getReq()[valueSymbol] = await maker(...params))();
11
11
  Object.defineProperty(context, 'value', {
12
- get() { return getReq()?.[valueSymbol]; },
12
+ get() { return getReq()[valueSymbol]; },
13
13
  set(value) {
14
14
  getReq()[promiseSymbol] = Promise.resolve(value);
15
15
  getReq()[valueSymbol] = value;
@@ -42,9 +42,9 @@ exports.dxServer = dxServer;
42
42
  // url: full url without server, protocol, port.
43
43
  // headers: if headers are repeated, they are joined by comma. Header names are lowercased.
44
44
  // rawHeaders: list of header name and value in a flat array. Case is preserved.
45
- function getReq() { return requestStorage.getStore()?.req; }
45
+ function getReq() { return requestStorage.getStore().req; }
46
46
  exports.getReq = getReq;
47
- function getRes() { return requestStorage.getStore()?.res; }
47
+ function getRes() { return requestStorage.getStore().res; }
48
48
  exports.getRes = getRes;
49
49
  function setText(text, { status } = {}) {
50
50
  const res = getRes();
@@ -132,4 +132,4 @@ exports.setRedirect = setRedirect;
132
132
  // https://github.com/jshttp/content-disposition/blob/1037e24e4790273da96645ad250061f39e77968c/index.js#L186
133
133
  // because in most applications, users can specify a simple filename which usually doesn't need to be validated.
134
134
  // we leave setDownload() implementation for users, for now.
135
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZHgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBRUEsdURBQWtEO0FBQ2xELGlEQUF1RDtBQXVCdkQsU0FBZ0IsYUFBYSxDQUszQixLQUE0QztJQUM3QyxNQUFNLGFBQWEsR0FBRyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUE7SUFDdkMsTUFBTSxXQUFXLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFBO0lBQ25DLG9FQUFvRTtJQUNwRSxNQUFNLE9BQU8sR0FBZ0MsQ0FBQyxHQUFHLE1BQWMsRUFBRSxFQUFFLENBQUMsTUFBTSxFQUFFLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxLQUFLLElBQUksRUFBRSxDQUFDLE1BQU0sRUFBRSxDQUFDLFdBQVcsQ0FBQyxHQUFHLE1BQU0sS0FBSyxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFBO0lBQzlKLE1BQU0sQ0FBQyxjQUFjLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRTtRQUN2QyxHQUFHLEtBQUksT0FBTyxNQUFNLEVBQUUsRUFBRSxDQUFDLFdBQVcsQ0FBQyxDQUFBLENBQUEsQ0FBQztRQUN0QyxHQUFHLENBQUMsS0FBSztZQUNSLE1BQU0sRUFBRSxDQUFDLGFBQWEsQ0FBQyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUE7WUFDaEQsTUFBTSxFQUFFLENBQUMsV0FBVyxDQUFDLEdBQUcsS0FBSyxDQUFBO1FBQzlCLENBQUM7S0FDRCxDQUFDLENBQUE7SUFDRixPQUFPLENBQUMsS0FBSyxHQUFHLENBQUMsR0FBRyxNQUFNLEVBQUUsRUFBRSxDQUFDLEtBQUssRUFBQyxJQUFJLEVBQUMsRUFBRTtRQUMzQyxNQUFNLE9BQU8sQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFBO1FBQ3hCLE9BQU8sSUFBSSxFQUFFLENBQUE7SUFDZCxDQUFDLENBQUE7SUFDRCxPQUFPLENBQUMsR0FBRyxHQUFHLENBQUMsR0FBRyxFQUFFLEtBQUssRUFBRSxFQUFFO1FBQzVCLEdBQUcsQ0FBQyxhQUFhLENBQUMsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFBO1FBQzNDLEdBQUcsQ0FBQyxXQUFXLENBQUMsR0FBRyxLQUFLLENBQUE7SUFDekIsQ0FBQyxDQUFBO0lBQ0QsT0FBTyxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBQTtJQUNyQyxPQUFPLE9BQU8sQ0FBQTtBQUNmLENBQUM7QUEzQkQsc0NBMkJDO0FBRUQsTUFBTSxjQUFjLEdBQUcsSUFBSSxvQ0FBaUIsRUFHeEMsQ0FBQTtBQUNKLE1BQU0sU0FBUyxHQUFHLGFBQWEsQ0FBWSxPQUFPLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBQyxHQUFHLE9BQU8sRUFBQyxDQUFDLENBQUMsQ0FBQTtBQUNyRSxTQUFnQixRQUFRLENBQ3ZCLEdBQW9CLEVBQ3BCLEdBQW1CLEVBQ25CLFVBR0ksRUFBRTtJQUVOLE9BQU8sS0FBSyxFQUFDLElBQUksRUFBQyxFQUFFO1FBQ25CLFNBQVMsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEVBQUMsR0FBRyxPQUFPLEVBQUMsQ0FBQyxDQUFBO1FBQ2hDLE1BQU0sTUFBTSxHQUFHLE1BQU0sY0FBYyxDQUFDLEdBQUcsQ0FBQyxFQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQTtRQUN6RCxNQUFNLElBQUEsdUJBQVEsRUFBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLFNBQVMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQTtRQUM1QyxPQUFPLE1BQU0sQ0FBQTtJQUNkLENBQUMsQ0FBQTtBQUNGLENBQUM7QUFkRCw0QkFjQztBQUVELGVBQWU7QUFDZixnREFBZ0Q7QUFDaEQsMkZBQTJGO0FBQzNGLGdGQUFnRjtBQUNoRixTQUFnQixNQUFNLEtBQXFCLE9BQU8sY0FBYyxDQUFDLFFBQVEsRUFBRSxFQUFFLEdBQUcsQ0FBQSxDQUFBLENBQUM7QUFBakYsd0JBQWlGO0FBQ2pGLFNBQWdCLE1BQU0sS0FBb0IsT0FBTyxjQUFjLENBQUMsUUFBUSxFQUFFLEVBQUUsR0FBRyxDQUFBLENBQUEsQ0FBQztBQUFoRix3QkFBZ0Y7QUFFaEYsU0FBZ0IsT0FBTyxDQUFDLElBQVksRUFBRSxFQUFDLE1BQU0sS0FBeUIsRUFBRTtJQUN2RSxNQUFNLEdBQUcsR0FBRyxNQUFNLEVBQUUsQ0FBQTtJQUNwQixNQUFNLEVBQUUsR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFBO0lBQzFCLElBQUksTUFBTTtRQUFFLEdBQUcsQ0FBQyxVQUFVLEdBQUcsTUFBTSxDQUFBO0lBQ25DLEVBQUUsQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFBO0lBQ2QsRUFBRSxDQUFDLElBQUksR0FBRyxNQUFNLENBQUE7QUFDakIsQ0FBQztBQU5ELDBCQU1DO0FBRUQsU0FBZ0IsUUFBUSxDQUFDLEVBQUMsTUFBTSxLQUF5QixFQUFFO0lBQzFELE1BQU0sR0FBRyxHQUFHLE1BQU0sRUFBRSxDQUFBO0lBQ3BCLE1BQU0sRUFBRSxHQUFHLFNBQVMsQ0FBQyxLQUFLLENBQUE7SUFDMUIsSUFBSSxNQUFNO1FBQUUsR0FBRyxDQUFDLFVBQVUsR0FBRyxNQUFNLENBQUE7SUFDbkMsRUFBRSxDQUFDLElBQUksR0FBRyxTQUFTLENBQUE7SUFDbkIsRUFBRSxDQUFDLElBQUksR0FBRyxPQUFPLENBQUE7QUFDbEIsQ0FBQztBQU5ELDRCQU1DO0FBRUQsU0FBZ0IsT0FBTyxDQUFDLElBQVksRUFBRSxPQUE0QixFQUFFO0lBQ25FLE9BQU8sQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUE7SUFDbkIsTUFBTSxFQUFFLEdBQUcsU0FBUyxDQUFDLEtBQUssQ0FBQTtJQUMxQixFQUFFLENBQUMsSUFBSSxHQUFHLE1BQU0sQ0FBQTtBQUNqQixDQUFDO0FBSkQsMEJBSUM7QUFFRCxTQUFnQixPQUFPLENBQUMsUUFBZ0IsRUFBRSxPQUFxQjtJQUM5RCxNQUFNLEVBQUUsR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFBO0lBQzFCLEVBQUUsQ0FBQyxJQUFJLEdBQUcsUUFBUSxDQUFBO0lBQ2xCLEVBQUUsQ0FBQyxJQUFJLEdBQUcsTUFBTSxDQUFBO0lBQ2hCLEVBQUUsQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFBO0FBQ3JCLENBQUM7QUFMRCwwQkFLQztBQUVELFNBQWdCLFNBQVMsQ0FBQyxNQUFjLEVBQUUsRUFBQyxNQUFNLEtBQXlCLEVBQUU7SUFDM0UsTUFBTSxHQUFHLEdBQUcsTUFBTSxFQUFFLENBQUE7SUFDcEIsTUFBTSxFQUFFLEdBQUcsU0FBUyxDQUFDLEtBQUssQ0FBQTtJQUMxQixJQUFJLE1BQU07UUFBRSxHQUFHLENBQUMsVUFBVSxHQUFHLE1BQU0sQ0FBQTtJQUNuQyxFQUFFLENBQUMsSUFBSSxHQUFHLE1BQU0sQ0FBQTtJQUNoQixFQUFFLENBQUMsSUFBSSxHQUFHLFFBQVEsQ0FBQTtBQUNuQixDQUFDO0FBTkQsOEJBTUM7QUFFRCxTQUFnQixhQUFhLENBQUMsTUFBZ0IsRUFBRSxFQUFDLE1BQU0sS0FBeUIsRUFBRTtJQUNqRixNQUFNLEdBQUcsR0FBRyxNQUFNLEVBQUUsQ0FBQTtJQUNwQixNQUFNLEVBQUUsR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFBO0lBQzFCLElBQUksTUFBTTtRQUFFLEdBQUcsQ0FBQyxVQUFVLEdBQUcsTUFBTSxDQUFBO0lBQ25DLEVBQUUsQ0FBQyxJQUFJLEdBQUcsTUFBTSxDQUFBO0lBQ2hCLEVBQUUsQ0FBQyxJQUFJLEdBQUcsWUFBWSxDQUFBO0FBQ3ZCLENBQUM7QUFORCxzQ0FNQztBQUVELFNBQWdCLFlBQVksQ0FBQyxNQUFzQixFQUFFLEVBQUMsTUFBTSxLQUF5QixFQUFFO0lBQ3RGLE1BQU0sR0FBRyxHQUFHLE1BQU0sRUFBRSxDQUFBO0lBQ3BCLE1BQU0sRUFBRSxHQUFHLFNBQVMsQ0FBQyxLQUFLLENBQUE7SUFDMUIsSUFBSSxNQUFNO1FBQUUsR0FBRyxDQUFDLFVBQVUsR0FBRyxNQUFNLENBQUE7SUFDbkMsRUFBRSxDQUFDLElBQUksR0FBRyxNQUFNLENBQUE7SUFDaEIsRUFBRSxDQUFDLElBQUksR0FBRyxXQUFXLENBQUE7QUFDdEIsQ0FBQztBQU5ELG9DQU1DO0FBRUQsU0FBZ0IsT0FBTyxDQUFDLElBQVMsRUFBRSxFQUFDLE1BQU0sS0FBeUIsRUFBRTtJQUNwRSxNQUFNLEdBQUcsR0FBRyxNQUFNLEVBQUUsQ0FBQTtJQUNwQixJQUFJLE1BQU07UUFBRSxHQUFHLENBQUMsVUFBVSxHQUFHLE1BQU0sQ0FBQTtJQUVuQyxNQUFNLEVBQUUsR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFBO0lBQzFCLEVBQUUsQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFBO0lBQ2QsRUFBRSxDQUFDLElBQUksR0FBRyxNQUFNLENBQUE7QUFDakIsQ0FBQztBQVBELDBCQU9DO0FBRUQsU0FBZ0IsV0FBVyxDQUFDLEdBQVcsRUFBRSxNQUFpQjtJQUN6RCxNQUFNLEdBQUcsR0FBRyxNQUFNLEVBQUUsQ0FBQTtJQUNwQixNQUFNLEVBQUUsR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFBO0lBQzFCLEdBQUcsQ0FBQyxVQUFVLEdBQUcsTUFBTSxDQUFBO0lBQ3ZCLEVBQUUsQ0FBQyxJQUFJLEdBQUcsR0FBRyxDQUFBO0lBQ2IsRUFBRSxDQUFDLElBQUksR0FBRyxVQUFVLENBQUE7QUFDckIsQ0FBQztBQU5ELGtDQU1DO0FBRUQsK0NBQStDO0FBQy9DLDRFQUE0RTtBQUU1RSxtREFBbUQ7QUFDbkQsdUJBQXVCO0FBQ3ZCLEtBQUs7QUFDTCxxSkFBcUo7QUFFckosd0ZBQXdGO0FBQ3hGLHNDQUFzQztBQUN0Qyw0R0FBNEc7QUFDNUcsZ0hBQWdIO0FBQ2hILDREQUE0RCJ9
135
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZHgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBRUEsdURBQWtEO0FBQ2xELGlEQUF1RDtBQXVCdkQsU0FBZ0IsYUFBYSxDQUszQixLQUE0QztJQUM3QyxNQUFNLGFBQWEsR0FBRyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUE7SUFDdkMsTUFBTSxXQUFXLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFBO0lBQ25DLG9FQUFvRTtJQUNwRSxNQUFNLE9BQU8sR0FBZ0MsQ0FBQyxHQUFHLE1BQWMsRUFBRSxFQUFFLENBQUMsTUFBTSxFQUFFLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxLQUFLLElBQUksRUFBRSxDQUFDLE1BQU0sRUFBRSxDQUFDLFdBQVcsQ0FBQyxHQUFHLE1BQU0sS0FBSyxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFBO0lBQzlKLE1BQU0sQ0FBQyxjQUFjLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRTtRQUN2QyxHQUFHLEtBQUksT0FBTyxNQUFNLEVBQUUsQ0FBQyxXQUFXLENBQUMsQ0FBQSxDQUFBLENBQUM7UUFDcEMsR0FBRyxDQUFDLEtBQUs7WUFDUixNQUFNLEVBQUUsQ0FBQyxhQUFhLENBQUMsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFBO1lBQ2hELE1BQU0sRUFBRSxDQUFDLFdBQVcsQ0FBQyxHQUFHLEtBQUssQ0FBQTtRQUM5QixDQUFDO0tBQ0QsQ0FBQyxDQUFBO0lBQ0YsT0FBTyxDQUFDLEtBQUssR0FBRyxDQUFDLEdBQUcsTUFBTSxFQUFFLEVBQUUsQ0FBQyxLQUFLLEVBQUMsSUFBSSxFQUFDLEVBQUU7UUFDM0MsTUFBTSxPQUFPLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQTtRQUN4QixPQUFPLElBQUksRUFBRSxDQUFBO0lBQ2QsQ0FBQyxDQUFBO0lBQ0QsT0FBTyxDQUFDLEdBQUcsR0FBRyxDQUFD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
package/cjs/router.js CHANGED
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.router = void 0;
4
4
  const dx_js_1 = require("./dx.js");
5
- require("urlpattern-polyfill");
6
5
  const bodyHelpers_js_1 = require("./bodyHelpers.js");
7
6
  // https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
8
7
  const allMethods = [
@@ -44,4 +43,4 @@ exports.router = {
44
43
  };
45
44
  for (const method of allMethods)
46
45
  exports.router[method] = exports.router.method.bind(exports.router, method);
47
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3JvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxtQ0FBeUM7QUFFekMsK0JBQTRCO0FBQzVCLHFEQUEyQztBQWtCM0MsNERBQTREO0FBQzVELE1BQU0sVUFBVSxHQUFHO0lBQ2xCLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsT0FBTztDQUNyRSxDQUFBO0FBK0JWLFNBQVMsVUFBVSxDQUNsQixNQUEwQixFQUFFLDZCQUE2QjtBQUN6RCxNQUF5QyxFQUN6QyxFQUFDLE1BQU0sR0FBRyxFQUFFLEVBQUUsR0FBRyxPQUFPLEtBQW1CLEVBQUU7SUFFN0MsT0FBTyxJQUFJLENBQUMsRUFBRTtRQUNiLE1BQU0sR0FBRyxHQUFHLElBQUEsY0FBTSxHQUFFLENBQUE7UUFDcEIsSUFBSSxNQUFNLEtBQUssU0FBUyxJQUFJLEdBQUcsQ0FBQyxNQUFNLEtBQUssTUFBTSxDQUFDLFdBQVcsRUFBRTtZQUFFLE9BQU8sSUFBSSxFQUFFLENBQUE7UUFDOUUsS0FBSyxNQUFNLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxJQUFJLE1BQU0sRUFBRSxDQUFDO1lBQzVDLHFCQUFxQjtZQUNyQixnRUFBZ0U7WUFDaEUsMEVBQTBFO1lBQzFFLDJFQUEyRTtZQUV4RSxzQ0FBc0M7WUFDdEMsMkVBQTJFO1lBQzNFLGtCQUFrQjtZQUNsQix3REFBd0Q7WUFDeEQsTUFBTSxPQUFPLEdBQUcsSUFBSSxVQUFVLENBQUMsRUFBQyxRQUFRLEVBQUUsR0FBRyxNQUFNLEdBQUcsT0FBTyxFQUFFLEVBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFDLFFBQVEsRUFBRSxJQUFBLDJCQUFVLEVBQUMsR0FBRyxDQUFDLENBQUMsUUFBUSxFQUFDLENBQUMsQ0FBQTtZQUM1RyxJQUFJLE9BQU87Z0JBQUUsT0FBTyxPQUFPLENBQUMsRUFBQyxPQUFPLEVBQUUsSUFBSSxFQUFDLENBQUMsQ0FBQTtRQUM3QyxDQUFDO1FBQ0QsT0FBTyxJQUFJLEVBQUUsQ0FBQTtJQUNkLENBQUMsQ0FBQTtBQUNGLENBQUM7QUFDWSxRQUFBLE1BQU0sR0FBVztJQUM3QixNQUFNLENBQUMsTUFBTSxFQUFFLEdBQUcsTUFBTTtRQUN2QixPQUFPLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxLQUFLLFFBQVE7WUFDbkMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUN6RCxDQUFDLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFBO0lBQzVELENBQUM7SUFDRCxHQUFHLENBQUMsR0FBRyxNQUFNO1FBQ1osT0FBTyxPQUFPLE1BQU0sQ0FBQyxDQUFDLENBQUMsS0FBSyxRQUFRO1lBQ25DLENBQUMsQ0FBQyxVQUFVLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDNUQsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxTQUFTLEVBQUUsTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQTtJQUMvRCxDQUFDO0NBQ0QsQ0FBQTtBQUVELEtBQUssTUFBTSxNQUFNLElBQUksVUFBVTtJQUFFLGNBQU0sQ0FBQyxNQUFNLENBQUMsR0FBRyxjQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxjQUFNLEVBQUUsTUFBTSxDQUFDLENBQUEifQ==
46
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3JvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxtQ0FBeUM7QUFDekMscURBQTJDO0FBa0IzQyw0REFBNEQ7QUFDNUQsTUFBTSxVQUFVLEdBQUc7SUFDbEIsS0FBSyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxPQUFPO0NBQ3JFLENBQUE7QUErQlYsU0FBUyxVQUFVLENBQ2xCLE1BQTBCLEVBQUUsNkJBQTZCO0FBQ3pELE1BQXlDLEVBQ3pDLEVBQUMsTUFBTSxHQUFHLEVBQUUsRUFBRSxHQUFHLE9BQU8sS0FBbUIsRUFBRTtJQUU3QyxPQUFPLElBQUksQ0FBQyxFQUFFO1FBQ2IsTUFBTSxHQUFHLEdBQUcsSUFBQSxjQUFNLEdBQUUsQ0FBQTtRQUNwQixJQUFJLE1BQU0sS0FBSyxTQUFTLElBQUksR0FBRyxDQUFDLE1BQU0sS0FBSyxNQUFNLENBQUMsV0FBVyxFQUFFO1lBQUUsT0FBTyxJQUFJLEVBQUUsQ0FBQTtRQUM5RSxLQUFLLE1BQU0sQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLElBQUksTUFBTSxFQUFFLENBQUM7WUFDNUMscUJBQXFCO1lBQ3JCLGdFQUFnRTtZQUNoRSwwRUFBMEU7WUFDMUUsMkVBQTJFO1lBRXhFLHNDQUFzQztZQUN0QywyRUFBMkU7WUFDM0Usa0JBQWtCO1lBQ2xCLHdEQUF3RDtZQUN4RCxNQUFNLE9BQU8sR0FBRyxJQUFJLFVBQVUsQ0FBQyxFQUFDLFFBQVEsRUFBRSxHQUFHLE1BQU0sR0FBRyxPQUFPLEVBQUUsRUFBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUMsUUFBUSxFQUFFLElBQUEsMkJBQVUsRUFBQyxHQUFHLENBQUMsQ0FBQyxRQUFRLEVBQUMsQ0FBQyxDQUFBO1lBQzVHLElBQUksT0FBTztnQkFBRSxPQUFPLE9BQU8sQ0FBQyxFQUFDLE9BQU8sRUFBRSxJQUFJLEVBQUMsQ0FBQyxDQUFBO1FBQzdDLENBQUM7UUFDRCxPQUFPLElBQUksRUFBRSxDQUFBO0lBQ2QsQ0FBQyxDQUFBO0FBQ0YsQ0FBQztBQUNZLFFBQUEsTUFBTSxHQUFXO0lBQzdCLE1BQU0sQ0FBQyxNQUFNLEVBQUUsR0FBRyxNQUFNO1FBQ3ZCLE9BQU8sT0FBTyxNQUFNLENBQUMsQ0FBQyxDQUFDLEtBQUssUUFBUTtZQUNuQyxDQUFDLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ3pELENBQUMsQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUE7SUFDNUQsQ0FBQztJQUNELEdBQUcsQ0FBQyxHQUFHLE1BQU07UUFDWixPQUFPLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxLQUFLLFFBQVE7WUFDbkMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUM1RCxDQUFDLENBQUMsVUFBVSxDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFBO0lBQy9ELENBQUM7Q0FDRCxDQUFBO0FBRUQsS0FBSyxNQUFNLE1BQU0sSUFBSSxVQUFVO0lBQUUsY0FBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLGNBQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLGNBQU0sRUFBRSxNQUFNLENBQUMsQ0FBQSJ9
package/esm/dx.js CHANGED
@@ -6,7 +6,7 @@ export function makeDxContext(maker) {
6
6
  // wrap in an async function to ensure the maker is called only once
7
7
  const context = (...params) => getReq()[promiseSymbol] ??= (async () => getReq()[valueSymbol] = await maker(...params))();
8
8
  Object.defineProperty(context, 'value', {
9
- get() { return getReq()?.[valueSymbol]; },
9
+ get() { return getReq()[valueSymbol]; },
10
10
  set(value) {
11
11
  getReq()[promiseSymbol] = Promise.resolve(value);
12
12
  getReq()[valueSymbol] = value;
@@ -37,8 +37,8 @@ export function dxServer(req, res, options = {}) {
37
37
  // url: full url without server, protocol, port.
38
38
  // headers: if headers are repeated, they are joined by comma. Header names are lowercased.
39
39
  // rawHeaders: list of header name and value in a flat array. Case is preserved.
40
- export function getReq() { return requestStorage.getStore()?.req; }
41
- export function getRes() { return requestStorage.getStore()?.res; }
40
+ export function getReq() { return requestStorage.getStore().req; }
41
+ export function getRes() { return requestStorage.getStore().res; }
42
42
  export function setText(text, { status } = {}) {
43
43
  const res = getRes();
44
44
  const dx = dxContext.value;
@@ -116,4 +116,4 @@ export function setRedirect(url, status) {
116
116
  // https://github.com/jshttp/content-disposition/blob/1037e24e4790273da96645ad250061f39e77968c/index.js#L186
117
117
  // because in most applications, users can specify a simple filename which usually doesn't need to be validated.
118
118
  // we leave setDownload() implementation for users, for now.
119
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZHgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFDLGlCQUFpQixFQUFDLE1BQU0sa0JBQWtCLENBQUE7QUFDbEQsT0FBTyxFQUFpQixRQUFRLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQTtBQXVCdkQsTUFBTSxVQUFVLGFBQWEsQ0FLM0IsS0FBNEM7SUFDN0MsTUFBTSxhQUFhLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFBO0lBQ3ZDLE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQTtJQUNuQyxvRUFBb0U7SUFDcEUsTUFBTSxPQUFPLEdBQWdDLENBQUMsR0FBRyxNQUFjLEVBQUUsRUFBRSxDQUFDLE1BQU0sRUFBRSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxXQUFXLENBQUMsR0FBRyxNQUFNLEtBQUssQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQTtJQUM5SixNQUFNLENBQUMsY0FBYyxDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUU7UUFDdkMsR0FBRyxLQUFJLE9BQU8sTUFBTSxFQUFFLEVBQUUsQ0FBQyxXQUFXLENBQUMsQ0FBQSxDQUFBLENBQUM7UUFDdEMsR0FBRyxDQUFDLEtBQUs7WUFDUixNQUFNLEVBQUUsQ0FBQyxhQUFhLENBQUMsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFBO1lBQ2hELE1BQU0sRUFBRSxDQUFDLFdBQVcsQ0FBQyxHQUFHLEtBQUssQ0FBQTtRQUM5QixDQUFDO0tBQ0QsQ0FBQyxDQUFBO0lBQ0YsT0FBTyxDQUFDLEtBQUssR0FBRyxDQUFDLEdBQUcsTUFBTSxFQUFFLEVBQUUsQ0FBQyxLQUFLLEVBQUMsSUFBSSxFQUFDLEVBQUU7UUFDM0MsTUFBTSxPQUFPLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQTtR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
119
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZHgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFDLGlCQUFpQixFQUFDLE1BQU0sa0JBQWtCLENBQUE7QUFDbEQsT0FBTyxFQUFpQixRQUFRLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQTtBQXVCdkQsTUFBTSxVQUFVLGFBQWEsQ0FLM0IsS0FBNEM7SUFDN0MsTUFBTSxhQUFhLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFBO0lBQ3ZDLE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQTtJQUNuQyxvRUFBb0U7SUFDcEUsTUFBTSxPQUFPLEdBQWdDLENBQUMsR0FBRyxNQUFjLEVBQUUsRUFBRSxDQUFDLE1BQU0sRUFBRSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxXQUFXLENBQUMsR0FBRyxNQUFNLEtBQUssQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQTtJQUM5SixNQUFNLENBQUMsY0FBYyxDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUU7UUFDdkMsR0FBRyxLQUFJLE9BQU8sTUFBTSxFQUFFLENBQUMsV0FBVyxDQUFDLENBQUEsQ0FBQSxDQUFDO1FBQ3BDLEdBQUcsQ0FBQyxLQUFLO1lBQ1IsTUFBTSxFQUFFLENBQUMsYUFBYSxDQUFDLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQTtZQUNoRCxNQUFNLEVBQUUsQ0FBQyxXQUFXLENBQUMsR0FBRyxLQUFLLENBQUE7UUFDOUIsQ0FBQztLQUNELENBQUMsQ0FBQTtJQUNGLE9BQU8sQ0FBQyxLQUFLLEdBQUcsQ0FBQyxHQUFHLE1BQU0sRUFBRSxFQUFFLENBQUMsS0FBSyxFQUFDLElBQUksRUFBQyxFQUFFO1FBQzNDLE1BQU0sT0FBTyxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUE7UUFDeEIs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
package/esm/router.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { getReq } from './dx.js';
2
- import 'urlpattern-polyfill';
3
2
  import { urlFromReq } from './bodyHelpers.js';
4
3
  // https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
5
4
  const allMethods = [
@@ -41,4 +40,4 @@ export const router = {
41
40
  };
42
41
  for (const method of allMethods)
43
42
  router[method] = router.method.bind(router, method);
44
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3JvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQVksTUFBTSxFQUFDLE1BQU0sU0FBUyxDQUFBO0FBRXpDLE9BQU8scUJBQXFCLENBQUE7QUFDNUIsT0FBTyxFQUFDLFVBQVUsRUFBQyxNQUFNLGtCQUFrQixDQUFBO0FBa0IzQyw0REFBNEQ7QUFDNUQsTUFBTSxVQUFVLEdBQUc7SUFDbEIsS0FBSyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxPQUFPO0NBQ3JFLENBQUE7QUErQlYsU0FBUyxVQUFVLENBQ2xCLE1BQTBCLEVBQUUsNkJBQTZCO0FBQ3pELE1BQXlDLEVBQ3pDLEVBQUMsTUFBTSxHQUFHLEVBQUUsRUFBRSxHQUFHLE9BQU8sS0FBbUIsRUFBRTtJQUU3QyxPQUFPLElBQUksQ0FBQyxFQUFFO1FBQ2IsTUFBTSxHQUFHLEdBQUcsTUFBTSxFQUFFLENBQUE7UUFDcEIsSUFBSSxNQUFNLEtBQUssU0FBUyxJQUFJLEdBQUcsQ0FBQyxNQUFNLEtBQUssTUFBTSxDQUFDLFdBQVcsRUFBRTtZQUFFLE9BQU8sSUFBSSxFQUFFLENBQUE7UUFDOUUsS0FBSyxNQUFNLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxJQUFJLE1BQU0sRUFBRSxDQUFDO1lBQzVDLHFCQUFxQjtZQUNyQixnRUFBZ0U7WUFDaEUsMEVBQTBFO1lBQzFFLDJFQUEyRTtZQUV4RSxzQ0FBc0M7WUFDdEMsMkVBQTJFO1lBQzNFLGtCQUFrQjtZQUNsQix3REFBd0Q7WUFDeEQsTUFBTSxPQUFPLEdBQUcsSUFBSSxVQUFVLENBQUMsRUFBQyxRQUFRLEVBQUUsR0FBRyxNQUFNLEdBQUcsT0FBTyxFQUFFLEVBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFDLFFBQVEsRUFBRSxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsUUFBUSxFQUFDLENBQUMsQ0FBQTtZQUM1RyxJQUFJLE9BQU87Z0JBQUUsT0FBTyxPQUFPLENBQUMsRUFBQyxPQUFPLEVBQUUsSUFBSSxFQUFDLENBQUMsQ0FBQTtRQUM3QyxDQUFDO1FBQ0QsT0FBTyxJQUFJLEVBQUUsQ0FBQTtJQUNkLENBQUMsQ0FBQTtBQUNGLENBQUM7QUFDRCxNQUFNLENBQUMsTUFBTSxNQUFNLEdBQVc7SUFDN0IsTUFBTSxDQUFDLE1BQU0sRUFBRSxHQUFHLE1BQU07UUFDdkIsT0FBTyxPQUFPLE1BQU0sQ0FBQyxDQUFDLENBQUMsS0FBSyxRQUFRO1lBQ25DLENBQUMsQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDekQsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQTtJQUM1RCxDQUFDO0lBQ0QsR0FBRyxDQUFDLEdBQUcsTUFBTTtRQUNaLE9BQU8sT0FBTyxNQUFNLENBQUMsQ0FBQyxDQUFDLEtBQUssUUFBUTtZQUNuQyxDQUFDLENBQUMsVUFBVSxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzVELENBQUMsQ0FBQyxVQUFVLENBQUMsU0FBUyxFQUFFLE1BQU0sQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUE7SUFDL0QsQ0FBQztDQUNELENBQUE7QUFFRCxLQUFLLE1BQU0sTUFBTSxJQUFJLFVBQVU7SUFBRSxNQUFNLENBQUMsTUFBTSxDQUFDLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxDQUFBIn0=
43
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3JvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQVksTUFBTSxFQUFDLE1BQU0sU0FBUyxDQUFBO0FBQ3pDLE9BQU8sRUFBQyxVQUFVLEVBQUMsTUFBTSxrQkFBa0IsQ0FBQTtBQWtCM0MsNERBQTREO0FBQzVELE1BQU0sVUFBVSxHQUFHO0lBQ2xCLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsT0FBTztDQUNyRSxDQUFBO0FBK0JWLFNBQVMsVUFBVSxDQUNsQixNQUEwQixFQUFFLDZCQUE2QjtBQUN6RCxNQUF5QyxFQUN6QyxFQUFDLE1BQU0sR0FBRyxFQUFFLEVBQUUsR0FBRyxPQUFPLEtBQW1CLEVBQUU7SUFFN0MsT0FBTyxJQUFJLENBQUMsRUFBRTtRQUNiLE1BQU0sR0FBRyxHQUFHLE1BQU0sRUFBRSxDQUFBO1FBQ3BCLElBQUksTUFBTSxLQUFLLFNBQVMsSUFBSSxHQUFHLENBQUMsTUFBTSxLQUFLLE1BQU0sQ0FBQyxXQUFXLEVBQUU7WUFBRSxPQUFPLElBQUksRUFBRSxDQUFBO1FBQzlFLEtBQUssTUFBTSxDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsSUFBSSxNQUFNLEVBQUUsQ0FBQztZQUM1QyxxQkFBcUI7WUFDckIsZ0VBQWdFO1lBQ2hFLDBFQUEwRTtZQUMxRSwyRUFBMkU7WUFFeEUsc0NBQXNDO1lBQ3RDLDJFQUEyRTtZQUMzRSxrQkFBa0I7WUFDbEIsd0RBQXdEO1lBQ3hELE1BQU0sT0FBTyxHQUFHLElBQUksVUFBVSxDQUFDLEVBQUMsUUFBUSxFQUFFLEdBQUcsTUFBTSxHQUFHLE9BQU8sRUFBRSxFQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBQyxRQUFRLEVBQUUsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDLFFBQVEsRUFBQyxDQUFDLENBQUE7WUFDNUcsSUFBSSxPQUFPO2dCQUFFLE9BQU8sT0FBTyxDQUFDLEVBQUMsT0FBTyxFQUFFLElBQUksRUFBQyxDQUFDLENBQUE7UUFDN0MsQ0FBQztRQUNELE9BQU8sSUFBSSxFQUFFLENBQUE7SUFDZCxDQUFDLENBQUE7QUFDRixDQUFDO0FBQ0QsTUFBTSxDQUFDLE1BQU0sTUFBTSxHQUFXO0lBQzdCLE1BQU0sQ0FBQyxNQUFNLEVBQUUsR0FBRyxNQUFNO1FBQ3ZCLE9BQU8sT0FBTyxNQUFNLENBQUMsQ0FBQyxDQUFDLEtBQUssUUFBUTtZQUNuQyxDQUFDLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ3pELENBQUMsQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUE7SUFDNUQsQ0FBQztJQUNELEdBQUcsQ0FBQyxHQUFHLE1BQU07UUFDWixPQUFPLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxLQUFLLFFBQVE7WUFDbkMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUM1RCxDQUFDLENBQUMsVUFBVSxDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFBO0lBQy9ELENBQUM7Q0FDRCxDQUFBO0FBRUQsS0FBSyxNQUFNLE1BQU0sSUFBSSxVQUFVO0lBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQSJ9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dx-server",
3
- "version": "0.8.4",
3
+ "version": "0.9.0",
4
4
  "main": "./cjs/index.js",
5
5
  "homepage": "https://github.com/tranvansang/dx-server",
6
6
  "repository": "https://github.com/tranvansang/dx-server",
@@ -24,6 +24,9 @@
24
24
  }
25
25
  },
26
26
  "type": "module",
27
+ "engines": {
28
+ "node": ">=16.0.0"
29
+ },
27
30
  "scripts": {
28
31
  "prepublishOnly": "./compile.sh"
29
32
  },
@@ -34,7 +37,6 @@
34
37
  "typescript": "^5.4.5"
35
38
  },
36
39
  "dependencies": {
37
- "send": "^0.18.0",
38
- "urlpattern-polyfill": "^10.0.0"
40
+ "send": "^0.18.0"
39
41
  }
40
42
  }
package/cjs/router.d.ts DELETED
@@ -1,43 +0,0 @@
1
- import { Chainable } from './dx.js';
2
- import 'urlpattern-polyfill';
3
- interface URLPatternOptions {
4
- }
5
- interface RouteContext {
6
- matched: URLPatternResult;
7
- next(): any;
8
- }
9
- interface Route {
10
- (context: RouteContext): any;
11
- }
12
- interface Routes {
13
- [k: string]: Route;
14
- }
15
- interface RouterOptions extends URLPatternOptions {
16
- prefix?: string;
17
- }
18
- type Router = {
19
- patch(routes: Routes, options?: RouterOptions): Chainable;
20
- patch(pattern: string, route: Route, options?: RouterOptions): Chainable;
21
- trace(routes: Routes, options?: RouterOptions): Chainable;
22
- trace(pattern: string, route: Route, options?: RouterOptions): Chainable;
23
- options(routes: Routes, options?: RouterOptions): Chainable;
24
- options(pattern: string, route: Route, options?: RouterOptions): Chainable;
25
- connect(routes: Routes, options?: RouterOptions): Chainable;
26
- connect(pattern: string, route: Route, options?: RouterOptions): Chainable;
27
- delete(routes: Routes, options?: RouterOptions): Chainable;
28
- delete(pattern: string, route: Route, options?: RouterOptions): Chainable;
29
- put(routes: Routes, options?: RouterOptions): Chainable;
30
- put(pattern: string, route: Route, options?: RouterOptions): Chainable;
31
- post(routes: Routes, options?: RouterOptions): Chainable;
32
- post(pattern: string, route: Route, options?: RouterOptions): Chainable;
33
- head(routes: Routes, options?: RouterOptions): Chainable;
34
- head(pattern: string, route: Route, options?: RouterOptions): Chainable;
35
- get(routes: Routes, options?: RouterOptions): Chainable;
36
- get(pattern: string, route: Route, options?: RouterOptions): Chainable;
37
- all(routes: Routes, options?: RouterOptions): Chainable;
38
- all(pattern: string, route: Route, options?: RouterOptions): Chainable;
39
- method(method: string, routes: Routes, options?: RouterOptions): Chainable;
40
- method(method: string, pattern: string, route: Route, options?: RouterOptions): Chainable;
41
- };
42
- export declare const router: Router;
43
- export {};
package/cjs/static.d.ts DELETED
@@ -1,5 +0,0 @@
1
- import { Chainable } from './dx.js';
2
- import { SendOptions } from 'send';
3
- export declare function chainStatic(pattern: string, { getPathname, ...options }: SendOptions & {
4
- getPathname?(matched: URLPatternResult): string;
5
- }): Chainable;
package/esm/router.d.ts DELETED
@@ -1,43 +0,0 @@
1
- import { Chainable } from './dx.js';
2
- import 'urlpattern-polyfill';
3
- interface URLPatternOptions {
4
- }
5
- interface RouteContext {
6
- matched: URLPatternResult;
7
- next(): any;
8
- }
9
- interface Route {
10
- (context: RouteContext): any;
11
- }
12
- interface Routes {
13
- [k: string]: Route;
14
- }
15
- interface RouterOptions extends URLPatternOptions {
16
- prefix?: string;
17
- }
18
- type Router = {
19
- patch(routes: Routes, options?: RouterOptions): Chainable;
20
- patch(pattern: string, route: Route, options?: RouterOptions): Chainable;
21
- trace(routes: Routes, options?: RouterOptions): Chainable;
22
- trace(pattern: string, route: Route, options?: RouterOptions): Chainable;
23
- options(routes: Routes, options?: RouterOptions): Chainable;
24
- options(pattern: string, route: Route, options?: RouterOptions): Chainable;
25
- connect(routes: Routes, options?: RouterOptions): Chainable;
26
- connect(pattern: string, route: Route, options?: RouterOptions): Chainable;
27
- delete(routes: Routes, options?: RouterOptions): Chainable;
28
- delete(pattern: string, route: Route, options?: RouterOptions): Chainable;
29
- put(routes: Routes, options?: RouterOptions): Chainable;
30
- put(pattern: string, route: Route, options?: RouterOptions): Chainable;
31
- post(routes: Routes, options?: RouterOptions): Chainable;
32
- post(pattern: string, route: Route, options?: RouterOptions): Chainable;
33
- head(routes: Routes, options?: RouterOptions): Chainable;
34
- head(pattern: string, route: Route, options?: RouterOptions): Chainable;
35
- get(routes: Routes, options?: RouterOptions): Chainable;
36
- get(pattern: string, route: Route, options?: RouterOptions): Chainable;
37
- all(routes: Routes, options?: RouterOptions): Chainable;
38
- all(pattern: string, route: Route, options?: RouterOptions): Chainable;
39
- method(method: string, routes: Routes, options?: RouterOptions): Chainable;
40
- method(method: string, pattern: string, route: Route, options?: RouterOptions): Chainable;
41
- };
42
- export declare const router: Router;
43
- export {};
package/esm/static.d.ts DELETED
@@ -1,5 +0,0 @@
1
- import { Chainable } from './dx.js';
2
- import { SendOptions } from 'send';
3
- export declare function chainStatic(pattern: string, { getPathname, ...options }: SendOptions & {
4
- getPathname?(matched: URLPatternResult): string;
5
- }): Chainable;