routup 3.2.0 → 4.0.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.
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { RequestListener } from 'node:http';
3
2
  import type { Request } from '../../request';
4
3
  import type { Response } from '../../response';
@@ -20,6 +20,7 @@ export declare enum HeaderName {
20
20
  CONTENT_LENGTH = "content-length",
21
21
  CONTENT_RANGE = "content-range",
22
22
  CONTENT_TYPE = "content-type",
23
+ CONNECTION = "connection",
23
24
  COOKIE = "cookie",
24
25
  ETag = "etag",
25
26
  HOST = "host",
@@ -34,6 +35,7 @@ export declare enum HeaderName {
34
35
  RETRY_AFTER = "retry-after",
35
36
  SET_COOKIE = "set-cookie",
36
37
  TRANSFER_ENCODING = "transfer-encoding",
38
+ X_ACCEL_BUFFERING = "x-accel-buffering",
37
39
  X_FORWARDED_HOST = "x-forwarded-host",
38
40
  X_FORWARDED_FOR = "x-forwarded-for",
39
41
  X_FORWARDED_PROTO = "x-forwarded-proto"
@@ -12,7 +12,7 @@ export declare class Handler implements Dispatcher {
12
12
  protected _method: MethodName | undefined;
13
13
  constructor(handler: HandlerConfig);
14
14
  get type(): "error" | "core";
15
- get path(): Path | undefined;
15
+ get path(): string | undefined;
16
16
  get method(): MethodName | undefined;
17
17
  dispatch(event: DispatchEvent): Promise<void>;
18
18
  matchPath(path: string): boolean;
package/dist/index.cjs CHANGED
@@ -34,6 +34,7 @@ exports.HeaderName = void 0;
34
34
  HeaderName["CONTENT_LENGTH"] = "content-length";
35
35
  HeaderName["CONTENT_RANGE"] = "content-range";
36
36
  HeaderName["CONTENT_TYPE"] = "content-type";
37
+ HeaderName["CONNECTION"] = "connection";
37
38
  HeaderName["COOKIE"] = "cookie";
38
39
  HeaderName["ETag"] = "etag";
39
40
  HeaderName["HOST"] = "host";
@@ -48,6 +49,7 @@ exports.HeaderName = void 0;
48
49
  HeaderName["RETRY_AFTER"] = "retry-after";
49
50
  HeaderName["SET_COOKIE"] = "set-cookie";
50
51
  HeaderName["TRANSFER_ENCODING"] = "transfer-encoding";
52
+ HeaderName["X_ACCEL_BUFFERING"] = "x-accel-buffering";
51
53
  HeaderName["X_FORWARDED_HOST"] = "x-forwarded-host";
52
54
  HeaderName["X_FORWARDED_FOR"] = "x-forwarded-for";
53
55
  HeaderName["X_FORWARDED_PROTO"] = "x-forwarded-proto";
@@ -62,55 +64,6 @@ function isRequestCacheable(req, modifiedTime) {
62
64
  return new Date(modifiedSince) >= modifiedTime;
63
65
  }
64
66
 
65
- const envSymbol = Symbol.for('ReqEnv');
66
- function setRequestEnv(req, key, value) {
67
- if (envSymbol in req) {
68
- if (typeof key === 'object') {
69
- if (value) {
70
- req[envSymbol] = smob.merge(req[envSymbol], key);
71
- } else {
72
- req[envSymbol] = key;
73
- }
74
- } else {
75
- req[envSymbol][key] = value;
76
- }
77
- return;
78
- }
79
- if (typeof key === 'object') {
80
- req[envSymbol] = key;
81
- return;
82
- }
83
- req[envSymbol] = {
84
- [key]: value
85
- };
86
- }
87
- function useRequestEnv(req, key) {
88
- if (envSymbol in req) {
89
- if (typeof key === 'string') {
90
- return req[envSymbol][key];
91
- }
92
- return req[envSymbol];
93
- }
94
- if (typeof key === 'string') {
95
- return undefined;
96
- }
97
- return {};
98
- }
99
- function unsetRequestEnv(req, key) {
100
- if (envSymbol in req) {
101
- if (smob.hasOwnProperty(req[envSymbol], key)) {
102
- delete req[envSymbol][key];
103
- }
104
- }
105
- }
106
-
107
- function getRequestHeader(req, name) {
108
- return req.headers[name];
109
- }
110
- function setRequestHeader(req, name, value) {
111
- req.headers[name] = value;
112
- }
113
-
114
67
  /*
115
68
  Set-Cookie header field-values are sometimes comma joined in one string. This splits them without choking on commas
116
69
  that are within a single set-cookie field-value, such as in the Expires portion.
@@ -186,6 +139,12 @@ function setRequestHeader(req, name, value) {
186
139
  function isObject(item) {
187
140
  return !!item && typeof item === 'object' && !Array.isArray(item);
188
141
  }
142
+ function setProperty(record, property, value) {
143
+ record[property] = value;
144
+ }
145
+ function getProperty(req, property) {
146
+ return req[property];
147
+ }
189
148
 
190
149
  /**
191
150
  * Determine if object is a Stats object.
@@ -322,7 +281,7 @@ function basename(input, extension) {
322
281
  if (!lastSegment) {
323
282
  return input;
324
283
  }
325
- return extension && lastSegment.endsWith(extension) ? lastSegment.slice(0, -extension.length) : lastSegment;
284
+ return lastSegment;
326
285
  }
327
286
 
328
287
  function isPromise(p) {
@@ -378,12 +337,66 @@ function isWebResponse(input) {
378
337
  return typeof Response !== 'undefined' && input instanceof Response;
379
338
  }
380
339
 
381
- const NegotiatorSymbol = Symbol.for('ReqNegotiator');
340
+ const symbol$4 = Symbol.for('ReqEnv');
341
+ function setRequestEnv(req, key, value) {
342
+ const propertyValue = getProperty(req, symbol$4);
343
+ if (propertyValue) {
344
+ if (typeof key === 'object') {
345
+ if (value) {
346
+ setProperty(req, symbol$4, smob.merge(propertyValue, key));
347
+ } else {
348
+ setProperty(req, symbol$4, key);
349
+ }
350
+ } else {
351
+ propertyValue[key] = value;
352
+ setProperty(req, symbol$4, propertyValue);
353
+ }
354
+ return;
355
+ }
356
+ if (typeof key === 'object') {
357
+ setProperty(req, symbol$4, key);
358
+ return;
359
+ }
360
+ setProperty(req, symbol$4, {
361
+ [key]: value
362
+ });
363
+ }
364
+ function useRequestEnv(req, key) {
365
+ const propertyValue = getProperty(req, symbol$4);
366
+ if (propertyValue) {
367
+ if (typeof key !== 'undefined') {
368
+ return propertyValue[key];
369
+ }
370
+ return propertyValue;
371
+ }
372
+ if (typeof key !== 'undefined') {
373
+ return undefined;
374
+ }
375
+ return {};
376
+ }
377
+ function unsetRequestEnv(req, key) {
378
+ const propertyValue = getProperty(req, symbol$4);
379
+ if (smob.hasOwnProperty(propertyValue, key)) {
380
+ delete propertyValue[key];
381
+ }
382
+ }
383
+
384
+ function getRequestHeader(req, name) {
385
+ return req.headers[name];
386
+ }
387
+ function setRequestHeader(req, name, value) {
388
+ req.headers[name] = value;
389
+ }
390
+
391
+ const symbol$3 = Symbol.for('ReqNegotiator');
382
392
  function useRequestNegotiator(req) {
383
- if (NegotiatorSymbol in req) {
384
- return req[NegotiatorSymbol];
393
+ let value = getProperty(req, symbol$3);
394
+ if (value) {
395
+ return value;
385
396
  }
386
- return new Negotiator(req);
397
+ value = new Negotiator(req);
398
+ setProperty(req, symbol$3, value);
399
+ return value;
387
400
  }
388
401
 
389
402
  function getRequestAcceptableContentTypes(req) {
@@ -511,13 +524,10 @@ function findRouterOption(key, path) {
511
524
 
512
525
  const routerSymbol = Symbol.for('ReqRouterID');
513
526
  function setRequestRouterPath(req, path) {
514
- req[routerSymbol] = path;
527
+ setProperty(req, routerSymbol, path);
515
528
  }
516
529
  function useRequestRouterPath(req) {
517
- if (routerSymbol in req) {
518
- return req[routerSymbol];
519
- }
520
- return undefined;
530
+ return getProperty(req, routerSymbol);
521
531
  }
522
532
 
523
533
  function getRequestHostName(req, options) {
@@ -546,6 +556,10 @@ function getRequestHostName(req, options) {
546
556
  return index !== -1 ? hostname.substring(0, index) : hostname;
547
557
  }
548
558
 
559
+ function isRequestHTTP2(req) {
560
+ return typeof getRequestHeader(req, ':path') !== 'undefined' && typeof getRequestHeader(req, ':method') !== 'undefined';
561
+ }
562
+
549
563
  function getRequestIP(req, options) {
550
564
  options = options || {};
551
565
  let trustProxy;
@@ -558,32 +572,23 @@ function getRequestIP(req, options) {
558
572
  return addrs[addrs.length - 1];
559
573
  }
560
574
 
561
- const ReqMountPathSymbol = Symbol.for('ReqMountPath');
575
+ const symbol$2 = Symbol.for('ReqMountPath');
562
576
  function useRequestMountPath(req) {
563
- if (ReqMountPathSymbol in req) {
564
- return req[ReqMountPathSymbol];
565
- }
566
- return '/';
577
+ return getProperty(req, symbol$2) || '/';
567
578
  }
568
579
  function setRequestMountPath(req, basePath) {
569
- req[ReqMountPathSymbol] = basePath;
580
+ setProperty(req, symbol$2, basePath);
570
581
  }
571
582
 
572
- const ParamsSymbol = Symbol.for('ReqParams');
583
+ const symbol$1 = Symbol.for('ReqParams');
573
584
  function useRequestParams(req) {
574
- /* istanbul ignore next */ if ('params' in req) {
575
- return req.params;
576
- }
577
- if (ParamsSymbol in req) {
578
- return req[ParamsSymbol];
579
- }
580
- return {};
585
+ return getProperty(req, symbol$1) || getProperty(req, 'params') || {};
581
586
  }
582
587
  function useRequestParam(req, key) {
583
588
  return useRequestParams(req)[key];
584
589
  }
585
590
  function setRequestParams(req, data) {
586
- req[ParamsSymbol] = data;
591
+ setProperty(req, symbol$1, data);
587
592
  }
588
593
  function setRequestParam(req, key, value) {
589
594
  const params = useRequestParams(req);
@@ -593,18 +598,16 @@ function setRequestParam(req, key, value) {
593
598
 
594
599
  const PathSymbol = Symbol.for('ReqPath');
595
600
  function useRequestPath(req) {
596
- if ('path' in req) {
597
- return req.path;
598
- }
599
- if (PathSymbol in req) {
600
- return req[PathSymbol];
601
+ const path = getProperty(req, 'path') || getProperty(req, PathSymbol);
602
+ if (path) {
603
+ return path;
601
604
  }
602
605
  if (typeof req.url === 'undefined') {
603
606
  return '/';
604
607
  }
605
608
  const parsed = new URL(req.url, 'http://localhost/');
606
- req[PathSymbol] = parsed.pathname;
607
- return req[PathSymbol];
609
+ setProperty(req, PathSymbol, parsed.pathname);
610
+ return parsed.pathname;
608
611
  }
609
612
 
610
613
  function getRequestProtocol(req, options) {
@@ -751,15 +754,102 @@ function setResponseCacheHeaders(res, options) {
751
754
  res.setHeader('cache-control', cacheControls.join(', '));
752
755
  }
753
756
 
754
- const GoneSymbol = Symbol.for('ResGone');
757
+ const symbol = Symbol.for('ResGone');
755
758
  function isResponseGone(res) {
756
759
  if (res.headersSent || res.writableEnded) {
757
760
  return true;
758
761
  }
759
- if (GoneSymbol in res) {
760
- return res[GoneSymbol];
762
+ return getProperty(res, symbol) ?? false;
763
+ }
764
+ function setResponseGone(res, value) {
765
+ setProperty(res, symbol, value);
766
+ }
767
+
768
+ function serializeEventStreamMessage(message) {
769
+ let result = '';
770
+ if (message.id) {
771
+ result += `id: ${message.id}\n`;
761
772
  }
762
- return false;
773
+ if (message.event) {
774
+ result += `event: ${message.event}\n`;
775
+ }
776
+ if (typeof message.retry === 'number' && Number.isInteger(message.retry)) {
777
+ result += `retry: ${message.retry}\n`;
778
+ }
779
+ result += `data: ${message.data}\n\n`;
780
+ return result;
781
+ }
782
+
783
+ class EventStream {
784
+ open() {
785
+ this.response.req.on('close', ()=>this.end());
786
+ this.response.req.on('error', (err)=>{
787
+ this.emit('error', err);
788
+ this.end();
789
+ });
790
+ this.passThrough.on('data', (chunk)=>this.response.write(chunk));
791
+ this.passThrough.on('error', (err)=>{
792
+ this.emit('error', err);
793
+ this.end();
794
+ });
795
+ this.passThrough.on('close', ()=>this.end());
796
+ this.response.setHeader(exports.HeaderName.CONTENT_TYPE, 'text/event-stream');
797
+ this.response.setHeader(exports.HeaderName.CACHE_CONTROL, 'private, no-cache, no-store, no-transform, must-revalidate, max-age=0');
798
+ this.response.setHeader(exports.HeaderName.X_ACCEL_BUFFERING, 'no');
799
+ if (!isRequestHTTP2(this.response.req)) {
800
+ this.response.setHeader(exports.HeaderName.CONNECTION, 'keep-alive');
801
+ }
802
+ this.response.statusCode = 200;
803
+ }
804
+ write(message) {
805
+ if (typeof message === 'string') {
806
+ this.write({
807
+ data: message
808
+ });
809
+ return;
810
+ }
811
+ if (!this.passThrough.closed && this.passThrough.writable) {
812
+ this.passThrough.write(serializeEventStreamMessage(message));
813
+ }
814
+ }
815
+ end() {
816
+ if (this.flushed) return;
817
+ this.flushed = true;
818
+ if (!this.passThrough.closed) {
819
+ this.passThrough.end();
820
+ }
821
+ this.emit('close');
822
+ setResponseGone(this.response, true);
823
+ this.response.end();
824
+ }
825
+ on(event, listener) {
826
+ if (typeof this.eventHandlers[event] === 'undefined') {
827
+ this.eventHandlers[event] = [];
828
+ }
829
+ this.eventHandlers[event].push(listener);
830
+ }
831
+ emit(event, ...args) {
832
+ if (typeof this.eventHandlers[event] === 'undefined') {
833
+ return;
834
+ }
835
+ const listeners = this.eventHandlers[event].slice();
836
+ for(let i = 0; i < listeners.length; i++){
837
+ listeners[i].apply(this, args);
838
+ }
839
+ }
840
+ constructor(response){
841
+ this.response = response;
842
+ this.passThrough = new readableStream.PassThrough({
843
+ encoding: 'utf-8'
844
+ });
845
+ this.flushed = false;
846
+ this.eventHandlers = {};
847
+ this.open();
848
+ }
849
+ }
850
+
851
+ function createEventStream(response) {
852
+ return new EventStream(response);
763
853
  }
764
854
 
765
855
  function appendResponseHeader(res, name, value) {
@@ -1634,12 +1724,14 @@ class PathMatcher {
1634
1724
  this.regexpKeys = [];
1635
1725
  this.path = path;
1636
1726
  this.regexpOptions = options || {};
1637
- this.regexp = pathToRegexp.pathToRegexp(path, this.regexpKeys, options);
1727
+ const regexp = pathToRegexp.pathToRegexp(path, options);
1728
+ this.regexp = regexp;
1729
+ this.regexpKeys = regexp.keys;
1638
1730
  }
1639
1731
  }
1640
1732
 
1641
1733
  function isPath(input) {
1642
- return typeof input === 'string' || input instanceof RegExp;
1734
+ return typeof input === 'string';
1643
1735
  }
1644
1736
 
1645
1737
  class Handler {
@@ -1832,15 +1924,9 @@ class Router {
1832
1924
  this.pathMatcher = undefined;
1833
1925
  return;
1834
1926
  }
1835
- if (typeof value === 'string') {
1836
- this.pathMatcher = new PathMatcher(withLeadingSlash(withoutTrailingSlash(`${value}`)), {
1837
- end: false
1838
- });
1839
- } else {
1840
- this.pathMatcher = new PathMatcher(value, {
1841
- end: false
1842
- });
1843
- }
1927
+ this.pathMatcher = new PathMatcher(withLeadingSlash(withoutTrailingSlash(`${value}`)), {
1928
+ end: false
1929
+ });
1844
1930
  }
1845
1931
  // --------------------------------------------------
1846
1932
  async executePipelineStep(context) {
@@ -2062,11 +2148,7 @@ class Router {
2062
2148
  for(let i = 0; i < input.length; i++){
2063
2149
  const item = input[i];
2064
2150
  if (isPath(item)) {
2065
- if (typeof item === 'string') {
2066
- path = withLeadingSlash(item);
2067
- } else {
2068
- path = item;
2069
- }
2151
+ path = withLeadingSlash(item);
2070
2152
  continue;
2071
2153
  }
2072
2154
  if (isRouterInstance(item)) {
@@ -2141,6 +2223,7 @@ class Router {
2141
2223
 
2142
2224
  exports.DispatchErrorEvent = DispatchErrorEvent;
2143
2225
  exports.DispatchEvent = DispatchEvent;
2226
+ exports.EventStream = EventStream;
2144
2227
  exports.Handler = Handler;
2145
2228
  exports.HandlerSymbol = HandlerSymbol;
2146
2229
  exports.PathMatcher = PathMatcher;
@@ -2150,6 +2233,7 @@ exports.appendResponseHeader = appendResponseHeader;
2150
2233
  exports.appendResponseHeaderDirective = appendResponseHeaderDirective;
2151
2234
  exports.coreHandler = coreHandler;
2152
2235
  exports.createError = createError;
2236
+ exports.createEventStream = createEventStream;
2153
2237
  exports.createNodeDispatcher = createNodeDispatcher;
2154
2238
  exports.createRawDispatcher = createRawDispatcher;
2155
2239
  exports.createRequest = createRequest;
@@ -2179,6 +2263,7 @@ exports.isHandlerConfig = isHandlerConfig;
2179
2263
  exports.isPath = isPath;
2180
2264
  exports.isPlugin = isPlugin;
2181
2265
  exports.isRequestCacheable = isRequestCacheable;
2266
+ exports.isRequestHTTP2 = isRequestHTTP2;
2182
2267
  exports.isResponseGone = isResponseGone;
2183
2268
  exports.matchRequestContentType = matchRequestContentType;
2184
2269
  exports.send = send;
@@ -2198,6 +2283,7 @@ exports.setRequestParams = setRequestParams;
2198
2283
  exports.setRequestRouterPath = setRequestRouterPath;
2199
2284
  exports.setResponseCacheHeaders = setResponseCacheHeaders;
2200
2285
  exports.setResponseContentTypeByFileName = setResponseContentTypeByFileName;
2286
+ exports.setResponseGone = setResponseGone;
2201
2287
  exports.setResponseHeaderAttachment = setResponseHeaderAttachment;
2202
2288
  exports.setResponseHeaderContentType = setResponseHeaderContentType;
2203
2289
  exports.transformHeaderToTuples = transformHeaderToTuples;