@dunx/http 2.1.1 → 2.2.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/dist/index.d.ts +8 -1
- package/dist/index.js +529 -41
- package/dist/index.js.map +16 -9
- package/dist/server/application.d.ts +31 -0
- package/dist/server/errors.d.ts +15 -1
- package/dist/server/factory.d.ts +1 -0
- package/dist/server/routes.d.ts +20 -0
- package/dist/static/module.d.ts +36 -2
- package/dist/throttle/decorators.d.ts +22 -0
- package/dist/throttle/guard.d.ts +31 -0
- package/dist/throttle/module.d.ts +35 -0
- package/dist/throttle/options.d.ts +52 -0
- package/dist/throttle/store.d.ts +71 -0
- package/dist/ws/adapter.d.ts +2 -1
- package/dist/ws/logging.d.ts +67 -0
- package/dist/ws/middleware.d.ts +80 -0
- package/dist/ws/socket.d.ts +13 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -340,13 +340,15 @@ import { AppError as AppError3, ConsoleLogger } from "@dunx/core";
|
|
|
340
340
|
class HttpError extends AppError3 {
|
|
341
341
|
status;
|
|
342
342
|
name = "HttpError";
|
|
343
|
+
headers;
|
|
343
344
|
constructor(status, message, options) {
|
|
344
345
|
super(message, options);
|
|
345
346
|
this.status = status;
|
|
347
|
+
this.headers = options?.headers;
|
|
346
348
|
}
|
|
347
349
|
}
|
|
348
350
|
Object.defineProperty(HttpError, Symbol.for("dunx.deps"), {
|
|
349
|
-
value: () => [{ unresolved: "readonly status: number" }, { unresolved: "message: string" },
|
|
351
|
+
value: () => [{ unresolved: "readonly status: number" }, { unresolved: "message: string" }, { unresolved: "options?: HttpErrorOptions" }]
|
|
350
352
|
});
|
|
351
353
|
|
|
352
354
|
class ValidationError extends HttpError {
|
|
@@ -369,10 +371,16 @@ var isErrorFilter = (handler) => typeof handler === "function" && typeof handler
|
|
|
369
371
|
var toErrorMapper = (handler, resolve) => isErrorFilter(handler) ? (error, req) => resolve(handler).catch(error, req) : handler;
|
|
370
372
|
var errorMapper = (logger) => (error) => {
|
|
371
373
|
if (error instanceof ValidationError) {
|
|
372
|
-
return Response.json({ error: error.message, status: error.status, issues: error.issues }, {
|
|
374
|
+
return Response.json({ error: error.message, status: error.status, issues: error.issues }, {
|
|
375
|
+
status: error.status,
|
|
376
|
+
...error.headers && { headers: error.headers }
|
|
377
|
+
});
|
|
373
378
|
}
|
|
374
379
|
if (error instanceof HttpError) {
|
|
375
|
-
return Response.json({ error: error.message, status: error.status }, {
|
|
380
|
+
return Response.json({ error: error.message, status: error.status }, {
|
|
381
|
+
status: error.status,
|
|
382
|
+
...error.headers && { headers: error.headers }
|
|
383
|
+
});
|
|
376
384
|
}
|
|
377
385
|
logger.error("Unhandled error", error);
|
|
378
386
|
return Response.json({
|
|
@@ -386,10 +394,10 @@ import {
|
|
|
386
394
|
collectModules as collectModules2,
|
|
387
395
|
AppError as AppError8,
|
|
388
396
|
AppFactory,
|
|
389
|
-
Logger as
|
|
397
|
+
Logger as Logger4,
|
|
390
398
|
provide,
|
|
391
399
|
readControllers as readControllers2,
|
|
392
|
-
RequestContext as
|
|
400
|
+
RequestContext as RequestContext3
|
|
393
401
|
} from "@dunx/core";
|
|
394
402
|
|
|
395
403
|
// src/ws/envelope.ts
|
|
@@ -409,6 +417,29 @@ var decode = (message) => {
|
|
|
409
417
|
return typeof event === "string" ? { event, data } : undefined;
|
|
410
418
|
};
|
|
411
419
|
|
|
420
|
+
// src/ws/middleware.ts
|
|
421
|
+
var composeSocket = (middleware, ctx) => middleware.reduceRight((next, current) => (frame, run) => current.handle(frame, ctx, () => next(frame, run)), (_frame, run) => run());
|
|
422
|
+
var observe = (next, done) => {
|
|
423
|
+
let result;
|
|
424
|
+
try {
|
|
425
|
+
result = next();
|
|
426
|
+
} catch (error) {
|
|
427
|
+
done(error, undefined);
|
|
428
|
+
throw error;
|
|
429
|
+
}
|
|
430
|
+
if (result instanceof Promise) {
|
|
431
|
+
return result.then((value) => {
|
|
432
|
+
done(undefined, value);
|
|
433
|
+
return value;
|
|
434
|
+
}, (error) => {
|
|
435
|
+
done(error, undefined);
|
|
436
|
+
throw error;
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
done(undefined, result);
|
|
440
|
+
return result;
|
|
441
|
+
};
|
|
442
|
+
|
|
412
443
|
// src/ws/runtime.ts
|
|
413
444
|
import { AppError as AppError4 } from "@dunx/core";
|
|
414
445
|
var slotOf = (handler) => handler.kind === HandlerKind.MESSAGE && handler.event !== undefined ? `message ${JSON.stringify(handler.event)}` : handler.kind;
|
|
@@ -463,9 +494,13 @@ var someHandler = (gateways, pick) => {
|
|
|
463
494
|
|
|
464
495
|
// src/ws/adapter.ts
|
|
465
496
|
var RUNTIME = Symbol.for("dunx.ws.runtime");
|
|
497
|
+
var UNCLAIMED = Symbol.for("dunx.ws.unclaimed");
|
|
466
498
|
var defaultOnError = (error, socket) => {
|
|
467
499
|
console.error(`[dunx/http] ${socket.data.path} handler failed:`, error);
|
|
468
500
|
};
|
|
501
|
+
var reportedByMiddleware = () => {
|
|
502
|
+
return;
|
|
503
|
+
};
|
|
469
504
|
var runtimeOf = (socket) => socket.data[RUNTIME];
|
|
470
505
|
var isBinary = (value) => value instanceof ArrayBuffer || ArrayBuffer.isView(value);
|
|
471
506
|
var replyRaw = (socket, value) => {
|
|
@@ -489,10 +524,66 @@ var settle = (result, socket, onError, then) => {
|
|
|
489
524
|
if (then)
|
|
490
525
|
then(result);
|
|
491
526
|
};
|
|
492
|
-
var
|
|
527
|
+
var framing = (kind) => {
|
|
528
|
+
if (kind === HandlerKind.CLOSE) {
|
|
529
|
+
return (args) => ({
|
|
530
|
+
socket: args[0],
|
|
531
|
+
data: { code: args[1], reason: args[2] }
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
if (kind === HandlerKind.OPEN || kind === HandlerKind.DRAIN) {
|
|
535
|
+
return (args) => ({ socket: args[0], data: undefined });
|
|
536
|
+
}
|
|
537
|
+
return (args) => ({ socket: args[1], data: args[0] });
|
|
538
|
+
};
|
|
539
|
+
var NOTHING = () => {
|
|
540
|
+
return;
|
|
541
|
+
};
|
|
542
|
+
var through = (gateway, middleware, kind, event, invoke) => {
|
|
543
|
+
const ctx = {
|
|
544
|
+
gateway: gateway.name,
|
|
545
|
+
path: gateway.path,
|
|
546
|
+
kind,
|
|
547
|
+
event
|
|
548
|
+
};
|
|
549
|
+
const dispatch = composeSocket(middleware, ctx);
|
|
550
|
+
const frameOf = framing(kind);
|
|
551
|
+
const run = invoke ?? NOTHING;
|
|
552
|
+
return (...args) => dispatch(frameOf(args), () => run(...args));
|
|
553
|
+
};
|
|
554
|
+
var withMiddleware = (gateway, middleware) => {
|
|
555
|
+
const wrap = (kind, event, invoke) => through(gateway, middleware, kind, event, invoke);
|
|
556
|
+
const optional = (kind, invoke) => invoke === undefined ? undefined : wrap(kind, undefined, invoke);
|
|
557
|
+
return {
|
|
558
|
+
...gateway,
|
|
559
|
+
open: wrap(HandlerKind.OPEN, undefined, gateway.open),
|
|
560
|
+
close: wrap(HandlerKind.CLOSE, undefined, gateway.close),
|
|
561
|
+
drain: optional(HandlerKind.DRAIN, gateway.drain),
|
|
562
|
+
ping: optional(HandlerKind.PING, gateway.ping),
|
|
563
|
+
pong: optional(HandlerKind.PONG, gateway.pong),
|
|
564
|
+
raw: optional(HandlerKind.MESSAGE, gateway.raw),
|
|
565
|
+
events: new Map([...gateway.events].map(([event, invoke]) => [
|
|
566
|
+
event,
|
|
567
|
+
wrap(HandlerKind.MESSAGE, event, invoke)
|
|
568
|
+
]))
|
|
569
|
+
};
|
|
570
|
+
};
|
|
571
|
+
var unclaimedDispatch = (gateway, middleware) => (frame, event) => composeSocket(middleware, {
|
|
572
|
+
gateway: gateway.name,
|
|
573
|
+
path: gateway.path,
|
|
574
|
+
kind: HandlerKind.MESSAGE,
|
|
575
|
+
event
|
|
576
|
+
})(frame, () => {
|
|
577
|
+
return;
|
|
578
|
+
});
|
|
579
|
+
var buildWebSocket = (discovered, options = {}, middleware = []) => {
|
|
493
580
|
const byPath = buildGateways(discovered);
|
|
494
|
-
const
|
|
495
|
-
|
|
581
|
+
const wrapped = middleware.length === 0 ? byPath : new Map([...byPath].map(([path, gateway]) => [
|
|
582
|
+
path,
|
|
583
|
+
withMiddleware(gateway, middleware)
|
|
584
|
+
]));
|
|
585
|
+
const gateways = [...wrapped.values()];
|
|
586
|
+
const onError = options.onError ?? (middleware.length === 0 ? defaultOnError : reportedByMiddleware);
|
|
496
587
|
const { onError: _onError, ...socketOptions } = options;
|
|
497
588
|
const run = (invoke, args, ws, then) => {
|
|
498
589
|
try {
|
|
@@ -505,6 +596,7 @@ var buildWebSocket = (discovered, options = {}) => {
|
|
|
505
596
|
...socketOptions,
|
|
506
597
|
message(ws, message) {
|
|
507
598
|
const gateway = runtimeOf(ws);
|
|
599
|
+
let event;
|
|
508
600
|
if (gateway.events.size > 0) {
|
|
509
601
|
const envelope = decode(message);
|
|
510
602
|
const handler = envelope && gateway.events.get(envelope.event);
|
|
@@ -515,9 +607,19 @@ var buildWebSocket = (discovered, options = {}) => {
|
|
|
515
607
|
});
|
|
516
608
|
return;
|
|
517
609
|
}
|
|
610
|
+
event = envelope?.event;
|
|
518
611
|
}
|
|
519
612
|
if (gateway.raw) {
|
|
520
613
|
run(gateway.raw, [message, ws], ws, (value) => replyRaw(ws, value));
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
const unclaimed2 = ws.data[UNCLAIMED];
|
|
617
|
+
if (!unclaimed2)
|
|
618
|
+
return;
|
|
619
|
+
try {
|
|
620
|
+
settle(unclaimed2({ socket: ws, data: message }, event), ws, onError, undefined);
|
|
621
|
+
} catch (error) {
|
|
622
|
+
onError(error, ws);
|
|
521
623
|
}
|
|
522
624
|
},
|
|
523
625
|
...someHandler(gateways, (g) => g.open) && {
|
|
@@ -556,8 +658,19 @@ var buildWebSocket = (discovered, options = {}) => {
|
|
|
556
658
|
}
|
|
557
659
|
}
|
|
558
660
|
};
|
|
661
|
+
const unclaimed = new Map(middleware.length === 0 ? [] : gateways.map((gateway) => [
|
|
662
|
+
gateway,
|
|
663
|
+
unclaimedDispatch(gateway, middleware)
|
|
664
|
+
]));
|
|
559
665
|
const accept = (req, server, gateway, context) => {
|
|
560
|
-
const
|
|
666
|
+
const fallback = unclaimed.get(gateway);
|
|
667
|
+
const data = {
|
|
668
|
+
path: gateway.path,
|
|
669
|
+
context,
|
|
670
|
+
id: crypto.randomUUID(),
|
|
671
|
+
[RUNTIME]: gateway,
|
|
672
|
+
...fallback === undefined ? {} : { [UNCLAIMED]: fallback }
|
|
673
|
+
};
|
|
561
674
|
return server.upgrade(req, { data }) ? undefined : new Response("Expected a WebSocket upgrade", { status: 426 });
|
|
562
675
|
};
|
|
563
676
|
const upgradeHandler = (gateway) => (req, server) => {
|
|
@@ -581,6 +694,104 @@ var buildWebSocket = (discovered, options = {}) => {
|
|
|
581
694
|
};
|
|
582
695
|
};
|
|
583
696
|
|
|
697
|
+
// src/ws/logging.ts
|
|
698
|
+
import { Logger, LogLevel, RequestContext } from "@dunx/core";
|
|
699
|
+
var LIFECYCLE_LABEL = {
|
|
700
|
+
[HandlerKind.OPEN]: "connect",
|
|
701
|
+
[HandlerKind.CLOSE]: "disconnect"
|
|
702
|
+
};
|
|
703
|
+
var elapsedMs = (started) => Math.round((Bun.nanoseconds() - started) / 1e6);
|
|
704
|
+
|
|
705
|
+
class SocketLoggingMiddleware {
|
|
706
|
+
logger;
|
|
707
|
+
context;
|
|
708
|
+
#level;
|
|
709
|
+
#errorLevel;
|
|
710
|
+
#events;
|
|
711
|
+
#lifecycle;
|
|
712
|
+
#payload;
|
|
713
|
+
#limit;
|
|
714
|
+
#correlate;
|
|
715
|
+
constructor(logger, context, options = {}) {
|
|
716
|
+
this.logger = logger;
|
|
717
|
+
this.context = context;
|
|
718
|
+
this.#level = options.level ?? LogLevel.DEBUG;
|
|
719
|
+
this.#errorLevel = options.errorLevel ?? LogLevel.ERROR;
|
|
720
|
+
this.#events = options.events ?? {};
|
|
721
|
+
this.#lifecycle = options.lifecycle ?? this.#level;
|
|
722
|
+
this.#payload = options.payload ?? false;
|
|
723
|
+
this.#limit = options.maxPayloadLength ?? 512;
|
|
724
|
+
this.#correlate = options.correlate ?? true;
|
|
725
|
+
}
|
|
726
|
+
#levelFor(ctx) {
|
|
727
|
+
if (ctx.kind !== HandlerKind.MESSAGE)
|
|
728
|
+
return this.#lifecycle;
|
|
729
|
+
if (ctx.event === undefined)
|
|
730
|
+
return this.#level;
|
|
731
|
+
return this.#events[ctx.event] ?? this.#level;
|
|
732
|
+
}
|
|
733
|
+
handle(frame, ctx, next) {
|
|
734
|
+
const level = this.#levelFor(ctx);
|
|
735
|
+
if (level === false)
|
|
736
|
+
return next();
|
|
737
|
+
const label = ctx.event ?? LIFECYCLE_LABEL[ctx.kind] ?? ctx.kind;
|
|
738
|
+
const connectionId = frame.socket.data.id;
|
|
739
|
+
const started = Bun.nanoseconds();
|
|
740
|
+
const write2 = (error, value) => {
|
|
741
|
+
const entry = {
|
|
742
|
+
gateway: ctx.gateway,
|
|
743
|
+
path: ctx.path,
|
|
744
|
+
event: label,
|
|
745
|
+
connectionId,
|
|
746
|
+
elapsedMs: elapsedMs(started),
|
|
747
|
+
...this.#payload ? { payload: this.#brief(frame.data) } : {},
|
|
748
|
+
...error === undefined ? { replied: value !== undefined } : { err: error }
|
|
749
|
+
};
|
|
750
|
+
const line = `${ctx.path} ${label}`;
|
|
751
|
+
this.#emit(error === undefined ? level : this.#errorLevel, line, entry);
|
|
752
|
+
};
|
|
753
|
+
if (!this.#correlate)
|
|
754
|
+
return observe(next, write2);
|
|
755
|
+
return this.context.runWithContext({ connectionId, event: label, flow: "ws", context: ctx.gateway }, () => observe(next, write2));
|
|
756
|
+
}
|
|
757
|
+
#emit(level, line, entry) {
|
|
758
|
+
switch (level) {
|
|
759
|
+
case LogLevel.VERBOSE:
|
|
760
|
+
this.logger.verbose(line, entry);
|
|
761
|
+
return;
|
|
762
|
+
case LogLevel.DEBUG:
|
|
763
|
+
this.logger.debug(line, entry);
|
|
764
|
+
return;
|
|
765
|
+
case LogLevel.INFO:
|
|
766
|
+
this.logger.info(line, entry);
|
|
767
|
+
return;
|
|
768
|
+
case LogLevel.WARN:
|
|
769
|
+
this.logger.warn(line, entry);
|
|
770
|
+
return;
|
|
771
|
+
case LogLevel.ERROR:
|
|
772
|
+
this.logger.error(line, entry);
|
|
773
|
+
return;
|
|
774
|
+
default:
|
|
775
|
+
this.logger.fatal(line, entry);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
#brief(data) {
|
|
779
|
+
if (data === undefined || this.#limit === 0)
|
|
780
|
+
return;
|
|
781
|
+
if (typeof data === "string") {
|
|
782
|
+
return data.length > this.#limit ? `[${data.length} chars]` : data;
|
|
783
|
+
}
|
|
784
|
+
if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) {
|
|
785
|
+
return `[${data.byteLength} bytes]`;
|
|
786
|
+
}
|
|
787
|
+
const text = JSON.stringify(data) ?? "";
|
|
788
|
+
return text.length > this.#limit ? `[${text.length} chars]` : data;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
Object.defineProperty(SocketLoggingMiddleware, Symbol.for("dunx.deps"), {
|
|
792
|
+
value: () => [Logger, RequestContext, { unresolved: "options: SocketLoggingOptions = {}" }]
|
|
793
|
+
});
|
|
794
|
+
|
|
584
795
|
// src/ws/pubsub.ts
|
|
585
796
|
import { AppError as AppError5 } from "@dunx/core";
|
|
586
797
|
|
|
@@ -742,15 +953,17 @@ class PubSub {
|
|
|
742
953
|
// src/server/application.ts
|
|
743
954
|
import {
|
|
744
955
|
AppError as AppError7,
|
|
745
|
-
Logger as
|
|
956
|
+
Logger as Logger3,
|
|
746
957
|
runtimeInfo,
|
|
747
|
-
ShutdownHooks
|
|
958
|
+
ShutdownHooks,
|
|
959
|
+
teardownError,
|
|
960
|
+
teardownFailures as toFailures
|
|
748
961
|
} from "@dunx/core";
|
|
749
962
|
|
|
750
963
|
// src/server/request-logging.ts
|
|
751
964
|
import {
|
|
752
|
-
Logger,
|
|
753
|
-
RequestContext
|
|
965
|
+
Logger as Logger2,
|
|
966
|
+
RequestContext as RequestContext2
|
|
754
967
|
} from "@dunx/core";
|
|
755
968
|
var REQUEST_ID_HEADER = "x-request-id";
|
|
756
969
|
var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -768,7 +981,7 @@ var parse = (text, limit) => {
|
|
|
768
981
|
return text;
|
|
769
982
|
}
|
|
770
983
|
};
|
|
771
|
-
var
|
|
984
|
+
var elapsedMs2 = (started) => Math.round((Bun.nanoseconds() - started) / 1e6);
|
|
772
985
|
|
|
773
986
|
class RequestLoggingMiddleware {
|
|
774
987
|
logger;
|
|
@@ -870,7 +1083,7 @@ class RequestLoggingMiddleware {
|
|
|
870
1083
|
request,
|
|
871
1084
|
err: error,
|
|
872
1085
|
statusCode: status,
|
|
873
|
-
elapsedMs:
|
|
1086
|
+
elapsedMs: elapsedMs2(started)
|
|
874
1087
|
};
|
|
875
1088
|
const line = `${req.method} ${path} ${status}`;
|
|
876
1089
|
if (status < HttpStatusCode.INTERNAL_SERVER_ERROR) {
|
|
@@ -886,7 +1099,7 @@ class RequestLoggingMiddleware {
|
|
|
886
1099
|
...scope,
|
|
887
1100
|
request,
|
|
888
1101
|
statusCode: response.status,
|
|
889
|
-
elapsedMs:
|
|
1102
|
+
elapsedMs: elapsedMs2(started)
|
|
890
1103
|
});
|
|
891
1104
|
response.headers.set(REQUEST_ID_HEADER, requestId);
|
|
892
1105
|
return response;
|
|
@@ -897,7 +1110,7 @@ class RequestLoggingMiddleware {
|
|
|
897
1110
|
request,
|
|
898
1111
|
statusCode: response.status,
|
|
899
1112
|
...value === undefined ? {} : { responseBody: value },
|
|
900
|
-
elapsedMs:
|
|
1113
|
+
elapsedMs: elapsedMs2(started)
|
|
901
1114
|
});
|
|
902
1115
|
response.headers.set(REQUEST_ID_HEADER, requestId);
|
|
903
1116
|
return response;
|
|
@@ -923,7 +1136,7 @@ class RequestLoggingMiddleware {
|
|
|
923
1136
|
}
|
|
924
1137
|
}
|
|
925
1138
|
Object.defineProperty(RequestLoggingMiddleware, Symbol.for("dunx.deps"), {
|
|
926
|
-
value: () => [
|
|
1139
|
+
value: () => [Logger2, RequestContext2, { unresolved: "options: RequestLoggingOptions = {}" }]
|
|
927
1140
|
});
|
|
928
1141
|
|
|
929
1142
|
// src/server/routes.ts
|
|
@@ -1197,7 +1410,7 @@ class HttpApplication {
|
|
|
1197
1410
|
...options.requestLogging === false ? [] : [RequestLoggingMiddleware],
|
|
1198
1411
|
...options.middleware ?? []
|
|
1199
1412
|
];
|
|
1200
|
-
this.#onError = options.onError === undefined ? errorMapper(app.get(
|
|
1413
|
+
this.#onError = options.onError === undefined ? errorMapper(app.get(Logger3)) : toErrorMapper(options.onError, (token) => app.get(token, root));
|
|
1201
1414
|
this.#port = options.port ?? 3000;
|
|
1202
1415
|
this.#websocket = websocket;
|
|
1203
1416
|
this.#relay = options.relay;
|
|
@@ -1263,7 +1476,7 @@ class HttpApplication {
|
|
|
1263
1476
|
const pubsub = this.#app.get(PubSub);
|
|
1264
1477
|
pubsub.attach(this.#server);
|
|
1265
1478
|
if (this.#relay) {
|
|
1266
|
-
const logger = this.#app.get(
|
|
1479
|
+
const logger = this.#app.get(Logger3);
|
|
1267
1480
|
await pubsub.relayThrough(this.#relay, {
|
|
1268
1481
|
...this.#relayChannel !== undefined && {
|
|
1269
1482
|
channel: this.#relayChannel
|
|
@@ -1287,7 +1500,7 @@ class HttpApplication {
|
|
|
1287
1500
|
`${routes.length} route(s)`,
|
|
1288
1501
|
...gateways.length === 0 ? [] : [`${gateways.length} gateway(s)`]
|
|
1289
1502
|
].join(" and ");
|
|
1290
|
-
this.#app.get(
|
|
1503
|
+
this.#app.get(Logger3).info(`Serving ${subject}`, {
|
|
1291
1504
|
...runtimeInfo(),
|
|
1292
1505
|
routes: routes.map((route) => `${route.method} ${route.path}`),
|
|
1293
1506
|
...gateways.length === 0 ? {} : {
|
|
@@ -1304,12 +1517,25 @@ class HttpApplication {
|
|
|
1304
1517
|
}
|
|
1305
1518
|
async shutdown() {
|
|
1306
1519
|
this.#shuttingDown ??= (async () => {
|
|
1307
|
-
|
|
1308
|
-
|
|
1520
|
+
const failures = [];
|
|
1521
|
+
const step = async (run) => {
|
|
1522
|
+
try {
|
|
1523
|
+
await run();
|
|
1524
|
+
} catch (error) {
|
|
1525
|
+
failures.push(...toFailures(error));
|
|
1526
|
+
}
|
|
1527
|
+
};
|
|
1528
|
+
await step(() => this.#app.drain());
|
|
1529
|
+
await step(async () => this.#server?.stop(this.#websocket !== undefined));
|
|
1309
1530
|
this.#server = undefined;
|
|
1310
|
-
await this.#app.get(PubSub).close();
|
|
1311
|
-
|
|
1312
|
-
|
|
1531
|
+
await step(() => this.#app.get(PubSub).close());
|
|
1532
|
+
try {
|
|
1533
|
+
await step(() => this.#app.shutdown());
|
|
1534
|
+
} finally {
|
|
1535
|
+
this.#resolveClosed?.();
|
|
1536
|
+
}
|
|
1537
|
+
if (failures.length > 0)
|
|
1538
|
+
throw teardownError(failures);
|
|
1313
1539
|
})();
|
|
1314
1540
|
return this.#shuttingDown;
|
|
1315
1541
|
}
|
|
@@ -1343,10 +1569,18 @@ class HttpFactory {
|
|
|
1343
1569
|
static async create(root, options = {}) {
|
|
1344
1570
|
const logging = provide(RequestLoggingMiddleware, {
|
|
1345
1571
|
useFactory: (logger, context) => new RequestLoggingMiddleware(logger, context, typeof options.requestLogging === "object" ? options.requestLogging : {}),
|
|
1346
|
-
inject: [
|
|
1572
|
+
inject: [Logger4, RequestContext3]
|
|
1573
|
+
});
|
|
1574
|
+
const socketLogging = provide(SocketLoggingMiddleware, {
|
|
1575
|
+
useFactory: (logger, context) => new SocketLoggingMiddleware(logger, context, typeof options.socketLogging === "object" ? options.socketLogging : {}),
|
|
1576
|
+
inject: [Logger4, RequestContext3]
|
|
1347
1577
|
});
|
|
1348
1578
|
const services = [PubSub, ClientAddress];
|
|
1349
|
-
const providers =
|
|
1579
|
+
const providers = [
|
|
1580
|
+
...services,
|
|
1581
|
+
...options.requestLogging === false ? [] : [logging],
|
|
1582
|
+
...options.socketLogging === false ? [] : [socketLogging]
|
|
1583
|
+
];
|
|
1350
1584
|
const scope = {
|
|
1351
1585
|
module: HttpModule,
|
|
1352
1586
|
global: true,
|
|
@@ -1375,9 +1609,14 @@ class HttpFactory {
|
|
|
1375
1609
|
}
|
|
1376
1610
|
assertNoCollisions(discovered);
|
|
1377
1611
|
const gateways = discoverGateways(modules, (token) => app.get(token));
|
|
1378
|
-
const websocket = gateways.length > 0 ? buildWebSocket(gateways, options.websocket) : undefined;
|
|
1612
|
+
const websocket = gateways.length > 0 ? buildWebSocket(gateways, options.websocket, HttpFactory.#socketMiddleware(app, root, options)) : undefined;
|
|
1379
1613
|
return new HttpApplication(app, discovered, options, root, websocket);
|
|
1380
1614
|
}
|
|
1615
|
+
static #socketMiddleware(app, root, options) {
|
|
1616
|
+
const declared = options.socketMiddleware ?? [];
|
|
1617
|
+
const entries = options.socketLogging === false ? declared : [SocketLoggingMiddleware, ...declared];
|
|
1618
|
+
return entries.map((entry) => app.get(entry, root));
|
|
1619
|
+
}
|
|
1381
1620
|
}
|
|
1382
1621
|
// src/static/files.ts
|
|
1383
1622
|
import { join, normalize, resolve } from "path";
|
|
@@ -1502,6 +1741,242 @@ StaticModule = __decorateElement(_init, 0, "StaticModule", _dec, StaticModule);
|
|
|
1502
1741
|
__runInitializers(_init, 1, StaticModule);
|
|
1503
1742
|
__decoratorMetadata(_init, StaticModule);
|
|
1504
1743
|
let _StaticModule = StaticModule;
|
|
1744
|
+
// src/throttle/decorators.ts
|
|
1745
|
+
var THROTTLE = metaKey("throttle");
|
|
1746
|
+
var SKIP_THROTTLE = metaKey("skip-throttle");
|
|
1747
|
+
var Throttle = (limit) => meta(THROTTLE, limit);
|
|
1748
|
+
var SkipThrottle = () => meta(SKIP_THROTTLE, true);
|
|
1749
|
+
// src/throttle/guard.ts
|
|
1750
|
+
import { Logger as Logger5 } from "@dunx/core";
|
|
1751
|
+
|
|
1752
|
+
// src/throttle/options.ts
|
|
1753
|
+
import { AppError as AppError9 } from "@dunx/core";
|
|
1754
|
+
|
|
1755
|
+
class ThrottleOptions {
|
|
1756
|
+
limit;
|
|
1757
|
+
windowSeconds;
|
|
1758
|
+
prefix;
|
|
1759
|
+
headers;
|
|
1760
|
+
subject;
|
|
1761
|
+
store;
|
|
1762
|
+
constructor(init) {
|
|
1763
|
+
if (init.prefix.trim() === "") {
|
|
1764
|
+
throw new AppError9("ThrottleModule needs a prefix naming this application, and it has no " + "default: two apps sharing one Redis with one throttle namespace each " + "spend the other's budget. Pass something like { prefix: 'orders-api' }.");
|
|
1765
|
+
}
|
|
1766
|
+
if (!Number.isInteger(init.limit) || init.limit < 1) {
|
|
1767
|
+
throw new AppError9(`ThrottleModule needs a limit of at least 1; got ${init.limit}.`);
|
|
1768
|
+
}
|
|
1769
|
+
if (!Number.isInteger(init.windowSeconds) || init.windowSeconds < 1) {
|
|
1770
|
+
throw new AppError9("ThrottleModule needs a windowSeconds of at least 1; got " + `${init.windowSeconds}.`);
|
|
1771
|
+
}
|
|
1772
|
+
this.limit = init.limit;
|
|
1773
|
+
this.windowSeconds = init.windowSeconds;
|
|
1774
|
+
this.prefix = init.prefix;
|
|
1775
|
+
this.headers = init.headers ?? true;
|
|
1776
|
+
this.subject = init.subject;
|
|
1777
|
+
this.store = init.store;
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
Object.defineProperty(ThrottleOptions, Symbol.for("dunx.deps"), {
|
|
1781
|
+
value: () => [{ unresolved: "init: ThrottleOptionsInit" }]
|
|
1782
|
+
});
|
|
1783
|
+
|
|
1784
|
+
// src/throttle/store.ts
|
|
1785
|
+
import { AppError as AppError10 } from "@dunx/core";
|
|
1786
|
+
|
|
1787
|
+
class ThrottleStore {
|
|
1788
|
+
constructor() {
|
|
1789
|
+
if (new.target === ThrottleStore) {
|
|
1790
|
+
throw new AppError10("ThrottleStore is a contract, not an implementation. Bind one with " + "ThrottleModule.forRoot({ store: new RedisThrottleStore(redis) }), or " + "leave it out for the in-process MemoryThrottleStore.");
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
class RedisThrottleStore extends ThrottleStore {
|
|
1796
|
+
redis;
|
|
1797
|
+
constructor(redis) {
|
|
1798
|
+
super();
|
|
1799
|
+
this.redis = redis;
|
|
1800
|
+
}
|
|
1801
|
+
async hit(key, windowSeconds) {
|
|
1802
|
+
const used = await this.redis.incr(key);
|
|
1803
|
+
if (used === 1)
|
|
1804
|
+
await this.redis.expire(key, windowSeconds);
|
|
1805
|
+
return used;
|
|
1806
|
+
}
|
|
1807
|
+
async ttl(key) {
|
|
1808
|
+
const left = await this.redis.ttl(key);
|
|
1809
|
+
return left > 0 ? left : undefined;
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
Object.defineProperty(RedisThrottleStore, Symbol.for("dunx.deps"), {
|
|
1813
|
+
value: () => [{ unresolved: "private readonly redis: ThrottleRedis" }]
|
|
1814
|
+
});
|
|
1815
|
+
|
|
1816
|
+
class MemoryThrottleStore extends ThrottleStore {
|
|
1817
|
+
#windows = new Map;
|
|
1818
|
+
#maxKeys;
|
|
1819
|
+
constructor(maxKeys = 1e4) {
|
|
1820
|
+
super();
|
|
1821
|
+
this.#maxKeys = maxKeys;
|
|
1822
|
+
}
|
|
1823
|
+
hit(key, windowSeconds) {
|
|
1824
|
+
const now = Date.now();
|
|
1825
|
+
const existing = this.#windows.get(key);
|
|
1826
|
+
if (existing !== undefined && existing.expiresAt > now) {
|
|
1827
|
+
existing.count += 1;
|
|
1828
|
+
return Promise.resolve(existing.count);
|
|
1829
|
+
}
|
|
1830
|
+
if (this.#windows.size >= this.#maxKeys)
|
|
1831
|
+
this.#sweep(now);
|
|
1832
|
+
this.#windows.set(key, { count: 1, expiresAt: now + windowSeconds * 1000 });
|
|
1833
|
+
return Promise.resolve(1);
|
|
1834
|
+
}
|
|
1835
|
+
ttl(key) {
|
|
1836
|
+
const window = this.#windows.get(key);
|
|
1837
|
+
if (window === undefined)
|
|
1838
|
+
return Promise.resolve(undefined);
|
|
1839
|
+
const left = Math.ceil((window.expiresAt - Date.now()) / 1000);
|
|
1840
|
+
return Promise.resolve(left > 0 ? left : undefined);
|
|
1841
|
+
}
|
|
1842
|
+
#sweep(now) {
|
|
1843
|
+
for (const [key, window] of this.#windows) {
|
|
1844
|
+
if (window.expiresAt <= now)
|
|
1845
|
+
this.#windows.delete(key);
|
|
1846
|
+
}
|
|
1847
|
+
if (this.#windows.size >= this.#maxKeys)
|
|
1848
|
+
this.#windows.clear();
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
Object.defineProperty(MemoryThrottleStore, Symbol.for("dunx.deps"), {
|
|
1852
|
+
value: () => [{ unresolved: "maxKeys = 10_000" }]
|
|
1853
|
+
});
|
|
1854
|
+
|
|
1855
|
+
// src/throttle/guard.ts
|
|
1856
|
+
class ThrottleGuard {
|
|
1857
|
+
options;
|
|
1858
|
+
store;
|
|
1859
|
+
address;
|
|
1860
|
+
logger;
|
|
1861
|
+
#warned = false;
|
|
1862
|
+
constructor(options, store, address, logger) {
|
|
1863
|
+
this.options = options;
|
|
1864
|
+
this.store = store;
|
|
1865
|
+
this.address = address;
|
|
1866
|
+
this.logger = logger;
|
|
1867
|
+
}
|
|
1868
|
+
async handle(req, ctx, next) {
|
|
1869
|
+
if (ctx.get(UNMATCHED) === true)
|
|
1870
|
+
return next();
|
|
1871
|
+
if (ctx.get(SKIP_THROTTLE) === true)
|
|
1872
|
+
return next();
|
|
1873
|
+
const limit = ctx.get(THROTTLE) ?? this.options;
|
|
1874
|
+
const key = this.#key(req, ctx);
|
|
1875
|
+
const used = await this.#hit(key, limit.windowSeconds);
|
|
1876
|
+
if (used === undefined)
|
|
1877
|
+
return next();
|
|
1878
|
+
if (used > limit.limit) {
|
|
1879
|
+
const after = await this.#ttl(key) ?? limit.windowSeconds;
|
|
1880
|
+
throw new HttpError(HttpStatusCode.TOO_MANY_REQUESTS, `Rate limit exceeded: ${limit.limit} requests per ` + `${limit.windowSeconds}s`, this.options.headers ? {
|
|
1881
|
+
headers: {
|
|
1882
|
+
"retry-after": String(after),
|
|
1883
|
+
"ratelimit-limit": String(limit.limit),
|
|
1884
|
+
"ratelimit-remaining": "0",
|
|
1885
|
+
"ratelimit-reset": String(after)
|
|
1886
|
+
}
|
|
1887
|
+
} : undefined);
|
|
1888
|
+
}
|
|
1889
|
+
const response = await next();
|
|
1890
|
+
if (this.options.headers) {
|
|
1891
|
+
response.headers.set("ratelimit-limit", String(limit.limit));
|
|
1892
|
+
response.headers.set("ratelimit-remaining", String(Math.max(0, limit.limit - used)));
|
|
1893
|
+
}
|
|
1894
|
+
return response;
|
|
1895
|
+
}
|
|
1896
|
+
#key(req, ctx) {
|
|
1897
|
+
const subject = (this.options.subject ?? ((request) => this.address.of(request)))(req, ctx) ?? "anonymous";
|
|
1898
|
+
return `${this.options.prefix}:throttle:${ctx.controller}:${ctx.handler}:${subject}`;
|
|
1899
|
+
}
|
|
1900
|
+
async#hit(key, windowSeconds) {
|
|
1901
|
+
try {
|
|
1902
|
+
return await this.store.hit(key, windowSeconds);
|
|
1903
|
+
} catch (error) {
|
|
1904
|
+
this.#degraded(error);
|
|
1905
|
+
return;
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
async#ttl(key) {
|
|
1909
|
+
try {
|
|
1910
|
+
return await this.store.ttl(key);
|
|
1911
|
+
} catch (error) {
|
|
1912
|
+
this.#degraded(error);
|
|
1913
|
+
return;
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
#degraded(error) {
|
|
1917
|
+
if (this.#warned)
|
|
1918
|
+
return;
|
|
1919
|
+
this.#warned = true;
|
|
1920
|
+
this.logger.warn("The rate limiter is unreachable, so requests are not being counted.", { reason: error.message });
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
Object.defineProperty(ThrottleGuard, Symbol.for("dunx.deps"), {
|
|
1924
|
+
value: () => [ThrottleOptions, ThrottleStore, ClientAddress, Logger5]
|
|
1925
|
+
});
|
|
1926
|
+
// src/throttle/module.ts
|
|
1927
|
+
import {
|
|
1928
|
+
Logger as Logger6,
|
|
1929
|
+
Module as Module2,
|
|
1930
|
+
provide as provide3
|
|
1931
|
+
} from "@dunx/core";
|
|
1932
|
+
var EXPORTS = [ThrottleOptions, ThrottleStore, ThrottleGuard];
|
|
1933
|
+
var guard = () => provide3(ThrottleGuard, {
|
|
1934
|
+
useFactory: (options, store, address, logger) => new ThrottleGuard(options, store, address, logger),
|
|
1935
|
+
inject: [ThrottleOptions, ThrottleStore, ClientAddress, Logger6]
|
|
1936
|
+
});
|
|
1937
|
+
var store = () => provide3(ThrottleStore, {
|
|
1938
|
+
useFactory: (options) => options.store ?? new MemoryThrottleStore,
|
|
1939
|
+
inject: [ThrottleOptions]
|
|
1940
|
+
});
|
|
1941
|
+
var _dec = [
|
|
1942
|
+
Module2({})
|
|
1943
|
+
];
|
|
1944
|
+
var _init = __decoratorStart(undefined);
|
|
1945
|
+
|
|
1946
|
+
class ThrottleModule {
|
|
1947
|
+
static forRoot(init) {
|
|
1948
|
+
return {
|
|
1949
|
+
module: ThrottleModule,
|
|
1950
|
+
global: true,
|
|
1951
|
+
exports: EXPORTS,
|
|
1952
|
+
providers: [
|
|
1953
|
+
provide3(ThrottleOptions, { useValue: new ThrottleOptions(init) }),
|
|
1954
|
+
store(),
|
|
1955
|
+
guard()
|
|
1956
|
+
]
|
|
1957
|
+
};
|
|
1958
|
+
}
|
|
1959
|
+
static forRootAsync(config) {
|
|
1960
|
+
return {
|
|
1961
|
+
module: ThrottleModule,
|
|
1962
|
+
global: true,
|
|
1963
|
+
...config.imports && { imports: config.imports },
|
|
1964
|
+
exports: EXPORTS,
|
|
1965
|
+
providers: [
|
|
1966
|
+
provide3(ThrottleOptions, {
|
|
1967
|
+
useFactory: async (...deps) => new ThrottleOptions(await config.useFactory(...deps)),
|
|
1968
|
+
inject: config.inject ?? []
|
|
1969
|
+
}),
|
|
1970
|
+
store(),
|
|
1971
|
+
guard()
|
|
1972
|
+
]
|
|
1973
|
+
};
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
ThrottleModule = __decorateElement(_init, 0, "ThrottleModule", _dec, ThrottleModule);
|
|
1977
|
+
__runInitializers(_init, 1, ThrottleModule);
|
|
1978
|
+
__decoratorMetadata(_init, ThrottleModule);
|
|
1979
|
+
let _ThrottleModule = ThrottleModule;
|
|
1505
1980
|
// src/ws/decorators.ts
|
|
1506
1981
|
var Gateway = (path = "/") => (target) => {
|
|
1507
1982
|
markGateway(target, path);
|
|
@@ -1522,7 +1997,7 @@ var OnMessage = (event) => (value) => {
|
|
|
1522
1997
|
return value;
|
|
1523
1998
|
};
|
|
1524
1999
|
// src/ws/redis-relay.ts
|
|
1525
|
-
import { AppError as
|
|
2000
|
+
import { AppError as AppError11 } from "@dunx/core";
|
|
1526
2001
|
var PROTOCOLS = [
|
|
1527
2002
|
"redis:",
|
|
1528
2003
|
"rediss:",
|
|
@@ -1538,10 +2013,10 @@ var assertUrl = (url) => {
|
|
|
1538
2013
|
try {
|
|
1539
2014
|
parsed = new URL(url);
|
|
1540
2015
|
} catch {
|
|
1541
|
-
throw new
|
|
2016
|
+
throw new AppError11(`${JSON.stringify(url)} is not a valid URL for the websocket relay. ` + "Expected something like redis://localhost:6379.");
|
|
1542
2017
|
}
|
|
1543
2018
|
if (!PROTOCOLS.includes(parsed.protocol)) {
|
|
1544
|
-
throw new
|
|
2019
|
+
throw new AppError11(`Unsupported protocol ${JSON.stringify(parsed.protocol)} in ` + `${JSON.stringify(url)}. Expected one of ${PROTOCOLS.join(", ")}.`);
|
|
1545
2020
|
}
|
|
1546
2021
|
return url;
|
|
1547
2022
|
};
|
|
@@ -1867,8 +2342,8 @@ Object.defineProperty(DiskIndicator, Symbol.for("dunx.deps"), {
|
|
|
1867
2342
|
});
|
|
1868
2343
|
// src/health/module.ts
|
|
1869
2344
|
import {
|
|
1870
|
-
Module as
|
|
1871
|
-
provide as
|
|
2345
|
+
Module as Module3,
|
|
2346
|
+
provide as provide4
|
|
1872
2347
|
} from "@dunx/core";
|
|
1873
2348
|
|
|
1874
2349
|
// src/health/readiness.ts
|
|
@@ -1915,22 +2390,22 @@ Object.defineProperty(Readiness, Symbol.for("dunx.deps"), {
|
|
|
1915
2390
|
// src/health/module.ts
|
|
1916
2391
|
var wiring = (options) => [
|
|
1917
2392
|
...options,
|
|
1918
|
-
|
|
2393
|
+
provide4(ReadinessOptions, {
|
|
1919
2394
|
useFactory: (opts) => new ReadinessOptions({ drainDelayMs: opts.drainDelayMs }),
|
|
1920
2395
|
inject: [HealthOptions]
|
|
1921
2396
|
}),
|
|
1922
|
-
|
|
2397
|
+
provide4(Readiness, {
|
|
1923
2398
|
useFactory: (opts) => new Readiness(opts),
|
|
1924
2399
|
inject: [ReadinessOptions]
|
|
1925
2400
|
}),
|
|
1926
|
-
|
|
2401
|
+
provide4(HealthRegistry, {
|
|
1927
2402
|
useFactory: (opts, readiness) => new HealthRegistry(opts, readiness),
|
|
1928
2403
|
inject: [HealthOptions, Readiness]
|
|
1929
2404
|
})
|
|
1930
2405
|
];
|
|
1931
2406
|
var surface = [HealthOptions, HealthRegistry, Readiness];
|
|
1932
2407
|
var _dec = [
|
|
1933
|
-
|
|
2408
|
+
Module3({})
|
|
1934
2409
|
];
|
|
1935
2410
|
var _init = __decoratorStart(undefined);
|
|
1936
2411
|
|
|
@@ -1941,7 +2416,7 @@ class HealthModule {
|
|
|
1941
2416
|
module: HealthModule,
|
|
1942
2417
|
...options.routes ? { controllers: [HealthController] } : {},
|
|
1943
2418
|
exports: surface,
|
|
1944
|
-
providers: wiring([
|
|
2419
|
+
providers: wiring([provide4(HealthOptions, { useValue: options })])
|
|
1945
2420
|
};
|
|
1946
2421
|
}
|
|
1947
2422
|
static forRootAsync(config) {
|
|
@@ -1951,7 +2426,7 @@ class HealthModule {
|
|
|
1951
2426
|
...config.routes ?? true ? { controllers: [HealthController] } : {},
|
|
1952
2427
|
exports: surface,
|
|
1953
2428
|
providers: wiring([
|
|
1954
|
-
|
|
2429
|
+
provide4(HealthOptions, {
|
|
1955
2430
|
useFactory: async (...deps) => new HealthOptions(await config.useFactory(...deps)),
|
|
1956
2431
|
inject: config.inject ?? []
|
|
1957
2432
|
})
|
|
@@ -1969,6 +2444,7 @@ export {
|
|
|
1969
2444
|
toErrorMapper,
|
|
1970
2445
|
routesOf,
|
|
1971
2446
|
preflight,
|
|
2447
|
+
observe,
|
|
1972
2448
|
normalizePrefix,
|
|
1973
2449
|
normalizePath,
|
|
1974
2450
|
metaOf,
|
|
@@ -1990,6 +2466,7 @@ export {
|
|
|
1990
2466
|
defaultErrorMapper,
|
|
1991
2467
|
decodeRelay,
|
|
1992
2468
|
decode,
|
|
2469
|
+
composeSocket,
|
|
1993
2470
|
compose,
|
|
1994
2471
|
buildWebSocket,
|
|
1995
2472
|
buildRuntime,
|
|
@@ -2001,11 +2478,21 @@ export {
|
|
|
2001
2478
|
ValidationError,
|
|
2002
2479
|
UseGuards,
|
|
2003
2480
|
UNMATCHED,
|
|
2481
|
+
ThrottleStore,
|
|
2482
|
+
ThrottleOptions,
|
|
2483
|
+
ThrottleModule,
|
|
2484
|
+
ThrottleGuard,
|
|
2485
|
+
Throttle,
|
|
2486
|
+
THROTTLE,
|
|
2004
2487
|
StaticOptions,
|
|
2005
2488
|
StaticModule,
|
|
2006
2489
|
StaticFiles,
|
|
2490
|
+
SocketLoggingMiddleware,
|
|
2491
|
+
SkipThrottle,
|
|
2492
|
+
SKIP_THROTTLE,
|
|
2007
2493
|
Roles,
|
|
2008
2494
|
RequestLoggingMiddleware,
|
|
2495
|
+
RedisThrottleStore,
|
|
2009
2496
|
RedisRelay,
|
|
2010
2497
|
RedisIndicator,
|
|
2011
2498
|
ReadinessOptions,
|
|
@@ -2027,6 +2514,7 @@ export {
|
|
|
2027
2514
|
OnMessage,
|
|
2028
2515
|
OnDrain,
|
|
2029
2516
|
OnClose,
|
|
2517
|
+
MemoryThrottleStore,
|
|
2030
2518
|
MemoryOptions,
|
|
2031
2519
|
MemoryIndicator,
|
|
2032
2520
|
HttpStatusCode,
|
|
@@ -2052,5 +2540,5 @@ export {
|
|
|
2052
2540
|
ApiHidden
|
|
2053
2541
|
};
|
|
2054
2542
|
|
|
2055
|
-
//# debugId=
|
|
2543
|
+
//# debugId=80302AC7A1BB24E664756E2164756E21
|
|
2056
2544
|
//# sourceMappingURL=index.js.map
|