@dunx/http 2.5.0 → 3.0.1
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 +31 -909
- package/dist/chunk-25g22350.js +58 -0
- package/dist/chunk-b699cfes.js +130 -0
- package/dist/chunk-f6pw36av.js +1299 -0
- package/dist/{chunk-jh7jk0bn.js → chunk-sz4pvqxy.js} +1 -57
- package/dist/client/module.d.ts +2 -7
- package/dist/client/service.d.ts +11 -22
- package/dist/client.d.ts +1 -2
- package/dist/client.js +12 -142
- package/dist/compression/compression.d.ts +7 -12
- package/dist/compression/options.d.ts +11 -23
- package/dist/health/indicators.d.ts +5 -10
- package/dist/index.d.ts +13 -21
- package/dist/index.js +102 -1484
- package/dist/internal.d.ts +36 -0
- package/dist/internal.js +154 -0
- package/dist/route/metadata.d.ts +6 -9
- package/dist/route/schema.d.ts +27 -55
- package/dist/server/application.d.ts +33 -89
- package/dist/server/client-address.d.ts +6 -13
- package/dist/server/errors.d.ts +24 -55
- package/dist/server/request-id.d.ts +6 -11
- package/dist/server/request-logging.d.ts +29 -101
- package/dist/server/routes.d.ts +7 -19
- package/dist/server/trace-context.d.ts +6 -10
- package/dist/static/files.d.ts +5 -13
- package/dist/static/module.d.ts +10 -19
- package/dist/throttle/guard.d.ts +6 -9
- package/dist/throttle/module.d.ts +6 -8
- package/dist/throttle/store.d.ts +11 -20
- package/dist/ws/middleware.d.ts +12 -21
- package/dist/ws/redis-relay.d.ts +9 -19
- package/package.json +6 -2
package/dist/index.js
CHANGED
|
@@ -1,253 +1,75 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
|
-
HttpStatusCode,
|
|
4
3
|
TRACEPARENT_HEADER,
|
|
5
4
|
TRACESTATE_HEADER,
|
|
6
|
-
TraceContext
|
|
5
|
+
TraceContext
|
|
6
|
+
} from "./chunk-25g22350.js";
|
|
7
|
+
import {
|
|
8
|
+
ApiHidden,
|
|
9
|
+
CompressionEncoding,
|
|
10
|
+
CompressionOptions,
|
|
11
|
+
Controller,
|
|
12
|
+
DEFAULT_RELAY_CHANNEL,
|
|
13
|
+
Delete,
|
|
14
|
+
ErrorFilter,
|
|
15
|
+
Get,
|
|
16
|
+
HEALTH_REPORT_SCHEMA,
|
|
17
|
+
HIDDEN,
|
|
18
|
+
HandlerKind,
|
|
19
|
+
HealthController,
|
|
20
|
+
HealthOptions,
|
|
21
|
+
HealthRegistry,
|
|
22
|
+
HiddenHealthController,
|
|
23
|
+
HttpError,
|
|
24
|
+
PUBLIC,
|
|
25
|
+
Patch,
|
|
26
|
+
Post,
|
|
27
|
+
Public,
|
|
28
|
+
Put,
|
|
29
|
+
REQUEST_ID_HEADER,
|
|
30
|
+
ROLES,
|
|
31
|
+
RawBody,
|
|
32
|
+
RedisRelay,
|
|
33
|
+
RequestIds,
|
|
34
|
+
Roles,
|
|
35
|
+
StaticOptions,
|
|
36
|
+
UNMATCHED,
|
|
37
|
+
UseGuards,
|
|
38
|
+
ValidationError,
|
|
39
|
+
assertNoCollisions,
|
|
40
|
+
assertNoGatewayCollisions,
|
|
41
|
+
buildFallback,
|
|
42
|
+
buildRoutes,
|
|
43
|
+
buildWebSocket,
|
|
44
|
+
decodeRelay,
|
|
45
|
+
defaultErrorMapper,
|
|
46
|
+
defaultRelayError,
|
|
47
|
+
discoverGateways,
|
|
48
|
+
discoverRoutes,
|
|
49
|
+
encode,
|
|
50
|
+
encodeRelay,
|
|
51
|
+
errorMapper,
|
|
52
|
+
joinPath,
|
|
53
|
+
markGateway,
|
|
54
|
+
markHandler,
|
|
55
|
+
mergeMeta,
|
|
56
|
+
meta,
|
|
57
|
+
metaKey,
|
|
58
|
+
metaOf,
|
|
59
|
+
negotiate,
|
|
60
|
+
observe,
|
|
61
|
+
toErrorMapper,
|
|
62
|
+
withUpgradeRoutes
|
|
63
|
+
} from "./chunk-f6pw36av.js";
|
|
64
|
+
import {
|
|
65
|
+
HttpStatusCode,
|
|
7
66
|
__decorateElement,
|
|
8
67
|
__decoratorMetadata,
|
|
9
68
|
__decoratorStart,
|
|
10
|
-
__privateAdd,
|
|
11
|
-
__privateGet,
|
|
12
69
|
__runInitializers
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
|
|
15
|
-
// src/route/marker.ts
|
|
16
|
-
var ROUTE = Symbol.for("dunx.route");
|
|
17
|
-
var CONTROLLER = Symbol.for("dunx.controller");
|
|
18
|
-
var defaultStatusFor = (method) => method === "POST" ? HttpStatusCode.CREATED : HttpStatusCode.OK;
|
|
19
|
-
var resolvePath = (path) => typeof path === "function" ? path() : path;
|
|
20
|
-
var markRoute = (target, meta) => {
|
|
21
|
-
Object.defineProperty(target, ROUTE, { value: meta, configurable: true });
|
|
22
|
-
};
|
|
23
|
-
var routeMetaOf = (value) => typeof value === "function" ? value[ROUTE] : undefined;
|
|
24
|
-
var markController = (target, prefix) => {
|
|
25
|
-
Object.defineProperty(target, CONTROLLER, {
|
|
26
|
-
value: prefix,
|
|
27
|
-
configurable: true
|
|
28
|
-
});
|
|
29
|
-
};
|
|
30
|
-
var prefixOf = (target) => target[CONTROLLER] ?? "";
|
|
31
|
-
|
|
32
|
-
// src/route/decorators.ts
|
|
33
|
-
var Controller = (prefix = "") => (target) => {
|
|
34
|
-
markController(target, prefix);
|
|
35
|
-
return target;
|
|
36
|
-
};
|
|
37
|
-
var verb = (method) => (path = "/", options) => (value, _context) => {
|
|
38
|
-
markRoute(value, { method, path, options });
|
|
39
|
-
return value;
|
|
40
|
-
};
|
|
41
|
-
var Get = verb("GET");
|
|
42
|
-
var Post = verb("POST");
|
|
43
|
-
var Put = verb("PUT");
|
|
44
|
-
var Patch = verb("PATCH");
|
|
45
|
-
var Delete = verb("DELETE");
|
|
46
|
-
// src/route/discover.ts
|
|
47
|
-
import { markedMethods } from "@dunx/core";
|
|
48
|
-
|
|
49
|
-
// src/route/metadata.ts
|
|
50
|
-
var META = Symbol.for("dunx.meta");
|
|
51
|
-
var GUARDS = Symbol.for("dunx.guards");
|
|
52
|
-
var metaKey = (name) => ({
|
|
53
|
-
name,
|
|
54
|
-
id: Symbol(name)
|
|
55
|
-
});
|
|
56
|
-
var write = (target, key, value) => {
|
|
57
|
-
const record = new Map(target[META]);
|
|
58
|
-
record.set(key.id, value);
|
|
59
|
-
Object.defineProperty(target, META, { value: record, configurable: true });
|
|
60
|
-
};
|
|
61
|
-
var meta = (key, value) => (target) => {
|
|
62
|
-
write(target, key, value);
|
|
63
|
-
return target;
|
|
64
|
-
};
|
|
65
|
-
var ROLES = metaKey("roles");
|
|
66
|
-
var PUBLIC = metaKey("public");
|
|
67
|
-
var HIDDEN = metaKey("hidden");
|
|
68
|
-
var UNMATCHED = metaKey("unmatched");
|
|
69
|
-
var Roles = (...roles) => meta(ROLES, roles);
|
|
70
|
-
var Public = () => meta(PUBLIC, true);
|
|
71
|
-
var ApiHidden = () => meta(HIDDEN, true);
|
|
72
|
-
var UseGuards = (...guards) => (target) => {
|
|
73
|
-
const existing = target[GUARDS] ?? [];
|
|
74
|
-
const merged = Object.hasOwn(target, GUARDS) ? [...guards, ...existing] : [...existing, ...guards];
|
|
75
|
-
Object.defineProperty(target, GUARDS, {
|
|
76
|
-
value: merged,
|
|
77
|
-
configurable: true
|
|
78
|
-
});
|
|
79
|
-
return target;
|
|
80
|
-
};
|
|
81
|
-
var guardsOf = (target) => target[GUARDS] ?? [];
|
|
82
|
-
var metaOf = (target) => target[META];
|
|
83
|
-
var mergeMeta = (...targets) => {
|
|
84
|
-
const merged = new Map;
|
|
85
|
-
for (const target of targets) {
|
|
86
|
-
const record = target[META];
|
|
87
|
-
if (record)
|
|
88
|
-
for (const [id, value] of record)
|
|
89
|
-
merged.set(id, value);
|
|
90
|
-
}
|
|
91
|
-
return merged;
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
// src/route/discover.ts
|
|
95
|
-
var joinPath = (prefix, path) => {
|
|
96
|
-
const joined = `/${prefix}/${path}`.replace(/\/{2,}/g, "/");
|
|
97
|
-
return joined.length > 1 ? joined.replace(/\/$/, "") : "/";
|
|
98
|
-
};
|
|
99
|
-
var discoverRoutes = (instance) => {
|
|
100
|
-
const klass = instance.constructor;
|
|
101
|
-
const prefix = prefixOf(klass);
|
|
102
|
-
const classGuards = guardsOf(klass);
|
|
103
|
-
const members = instance;
|
|
104
|
-
return markedMethods(Object.getPrototypeOf(instance), routeMetaOf).map(({ name, meta: meta2, value: marked }) => ({
|
|
105
|
-
method: meta2.method,
|
|
106
|
-
path: joinPath(prefix, resolvePath(meta2.path)),
|
|
107
|
-
controller: klass.name,
|
|
108
|
-
handlerName: name,
|
|
109
|
-
handler: members[name].bind(instance),
|
|
110
|
-
options: meta2.options,
|
|
111
|
-
meta: mergeMeta(klass, marked),
|
|
112
|
-
classMeta: metaOf(klass),
|
|
113
|
-
guards: [...classGuards, ...guardsOf(marked)]
|
|
114
|
-
}));
|
|
115
|
-
};
|
|
116
|
-
// src/inspect.ts
|
|
117
|
-
import {
|
|
118
|
-
collectModules,
|
|
119
|
-
dependenciesOf,
|
|
120
|
-
readControllers
|
|
121
|
-
} from "@dunx/core";
|
|
122
|
-
|
|
123
|
-
// src/ws/discover.ts
|
|
124
|
-
import {
|
|
125
|
-
AppError,
|
|
126
|
-
classOf,
|
|
127
|
-
markedMethods as markedMethods2
|
|
128
|
-
} from "@dunx/core";
|
|
129
|
-
|
|
130
|
-
// src/ws/marker.ts
|
|
131
|
-
var HANDLER = Symbol.for("dunx.ws.handler");
|
|
132
|
-
var GATEWAY = Symbol.for("dunx.ws.gateway");
|
|
133
|
-
var HandlerKind = Object.freeze({
|
|
134
|
-
UPGRADE: "upgrade",
|
|
135
|
-
OPEN: "open",
|
|
136
|
-
MESSAGE: "message",
|
|
137
|
-
CLOSE: "close",
|
|
138
|
-
DRAIN: "drain",
|
|
139
|
-
PING: "ping",
|
|
140
|
-
PONG: "pong"
|
|
141
|
-
});
|
|
142
|
-
var markHandler = (target, meta2) => {
|
|
143
|
-
Object.defineProperty(target, HANDLER, { value: meta2, configurable: true });
|
|
144
|
-
};
|
|
145
|
-
var handlerMetaOf = (value) => typeof value === "function" ? value[HANDLER] : undefined;
|
|
146
|
-
var markGateway = (target, path) => {
|
|
147
|
-
Object.defineProperty(target, GATEWAY, { value: path, configurable: true });
|
|
148
|
-
};
|
|
149
|
-
var gatewayPathOf = (target) => target[GATEWAY] ?? "/";
|
|
150
|
-
var isGateway = (target) => target[GATEWAY] !== undefined;
|
|
151
|
-
|
|
152
|
-
// src/ws/discover.ts
|
|
153
|
-
var normalizePath = (path) => {
|
|
154
|
-
const joined = `/${path}`.replace(/\/{2,}/g, "/");
|
|
155
|
-
return joined.length > 1 ? joined.replace(/\/$/, "") : "/";
|
|
156
|
-
};
|
|
157
|
-
var eachHandler = (start) => markedMethods2(start, handlerMetaOf);
|
|
158
|
-
var discoverGateway = (instance) => {
|
|
159
|
-
const klass = instance.constructor;
|
|
160
|
-
const members = instance;
|
|
161
|
-
return {
|
|
162
|
-
name: klass.name,
|
|
163
|
-
path: normalizePath(gatewayPathOf(klass)),
|
|
164
|
-
handlers: eachHandler(Object.getPrototypeOf(instance)).map(({ name, meta: meta2 }) => ({
|
|
165
|
-
kind: meta2.kind,
|
|
166
|
-
event: meta2.event,
|
|
167
|
-
method: name,
|
|
168
|
-
invoke: members[name].bind(instance)
|
|
169
|
-
}))
|
|
170
|
-
};
|
|
171
|
-
};
|
|
172
|
-
var findHandlerMethod = (ctor) => eachHandler(ctor.prototype)[0]?.name;
|
|
173
|
-
var discoverGateways = (modules, resolve) => {
|
|
174
|
-
const discovered = [];
|
|
175
|
-
for (const module of modules) {
|
|
176
|
-
for (const entry of module.options.providers ?? []) {
|
|
177
|
-
const candidate = classOf(entry);
|
|
178
|
-
if (!candidate)
|
|
179
|
-
continue;
|
|
180
|
-
if (isGateway(candidate.ctor)) {
|
|
181
|
-
discovered.push(discoverGateway(resolve(candidate.token)));
|
|
182
|
-
continue;
|
|
183
|
-
}
|
|
184
|
-
const orphan = findHandlerMethod(candidate.ctor);
|
|
185
|
-
if (orphan !== undefined) {
|
|
186
|
-
throw new AppError(`${candidate.ctor.name}.${orphan}() is a websocket handler, but ` + `${candidate.ctor.name} is not a gateway. Decorate the class with ` + "@Gateway(path), or drop the handler decorator.");
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
return discovered;
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
// src/inspect.ts
|
|
194
|
-
var vendorOf = (schema) => schema?.["~standard"]?.vendor;
|
|
195
|
-
var validatesIn = (options) => {
|
|
196
|
-
const body = vendorOf(options?.body);
|
|
197
|
-
const query = vendorOf(options?.query);
|
|
198
|
-
const params = vendorOf(options?.params);
|
|
199
|
-
return {
|
|
200
|
-
...body === undefined ? {} : { body },
|
|
201
|
-
...query === undefined ? {} : { query },
|
|
202
|
-
...params === undefined ? {} : { params }
|
|
203
|
-
};
|
|
204
|
-
};
|
|
205
|
-
var rolesIn = (route) => {
|
|
206
|
-
const roles = route.meta?.get(ROLES.id);
|
|
207
|
-
if (roles === undefined || roles === null)
|
|
208
|
-
return null;
|
|
209
|
-
return (Array.isArray(roles) ? roles : [roles]).map(String);
|
|
210
|
-
};
|
|
211
|
-
var nodeFor = (route, module) => ({
|
|
212
|
-
method: route.method,
|
|
213
|
-
path: route.path,
|
|
214
|
-
controller: route.controller,
|
|
215
|
-
handler: route.handlerName,
|
|
216
|
-
module,
|
|
217
|
-
public: route.meta?.get(PUBLIC.id) === true,
|
|
218
|
-
roles: rolesIn(route),
|
|
219
|
-
guards: (route.guards ?? []).map((guard) => guard.name),
|
|
220
|
-
hidden: route.meta?.get(HIDDEN.id) === true,
|
|
221
|
-
validates: validatesIn(route.options),
|
|
222
|
-
status: route.options?.status ?? null,
|
|
223
|
-
responses: Object.keys(route.options?.response ?? {}).map(Number)
|
|
224
|
-
});
|
|
225
|
-
var routesOf = (root) => collectModules(root).flatMap((module) => readControllers(module).flatMap((controller) => {
|
|
226
|
-
const { prototype } = controller;
|
|
227
|
-
return discoverRoutes(Object.create(prototype)).map((route) => nodeFor(route, module.name));
|
|
228
|
-
}));
|
|
229
|
-
var gatewayFor = (ctor, module) => {
|
|
230
|
-
const { name, path, handlers } = discoverGateway(Object.create(ctor.prototype));
|
|
231
|
-
return {
|
|
232
|
-
name,
|
|
233
|
-
path,
|
|
234
|
-
module,
|
|
235
|
-
dependencies: dependenciesOf(ctor),
|
|
236
|
-
handlers: handlers.map((handler) => ({
|
|
237
|
-
kind: handler.kind,
|
|
238
|
-
event: handler.event ?? null,
|
|
239
|
-
method: handler.method
|
|
240
|
-
}))
|
|
241
|
-
};
|
|
242
|
-
};
|
|
243
|
-
var classOf2 = (entry) => {
|
|
244
|
-
if (typeof entry === "function")
|
|
245
|
-
return entry;
|
|
246
|
-
return entry.provider.kind === "class" ? entry.provider.ctor : undefined;
|
|
247
|
-
};
|
|
248
|
-
var gatewaysOf = (root) => collectModules(root).flatMap((module) => (module.options.providers ?? []).map(classOf2).filter((ctor) => ctor !== undefined).filter(isGateway).map((ctor) => gatewayFor(ctor, module.name)));
|
|
70
|
+
} from "./chunk-sz4pvqxy.js";
|
|
249
71
|
// src/server/client-address.ts
|
|
250
|
-
import { AppError
|
|
72
|
+
import { AppError } from "@dunx/core";
|
|
251
73
|
var trustedHops = (setting) => {
|
|
252
74
|
if (setting === true)
|
|
253
75
|
return 1;
|
|
@@ -261,7 +83,7 @@ class ClientAddress {
|
|
|
261
83
|
of(req) {
|
|
262
84
|
const source = sources.get(this);
|
|
263
85
|
if (!source) {
|
|
264
|
-
throw new
|
|
86
|
+
throw new AppError("ClientAddress has no server yet. The address comes from the live Bun " + "server, so it is only available once listen() has run.");
|
|
265
87
|
}
|
|
266
88
|
const hops = trustedHops(source.trustProxy);
|
|
267
89
|
if (hops > 0) {
|
|
@@ -276,432 +98,17 @@ class ClientAddress {
|
|
|
276
98
|
var attachAddressSource = (target, source) => {
|
|
277
99
|
sources.set(target, source);
|
|
278
100
|
};
|
|
279
|
-
// src/server/context.ts
|
|
280
|
-
var EMPTY = new Map;
|
|
281
|
-
var buildContext = (route) => {
|
|
282
|
-
const record = route.meta ?? EMPTY;
|
|
283
|
-
return Object.freeze({
|
|
284
|
-
controller: route.controller,
|
|
285
|
-
handler: route.handlerName,
|
|
286
|
-
method: route.method,
|
|
287
|
-
path: route.path,
|
|
288
|
-
parsesBody: route.options?.body !== undefined,
|
|
289
|
-
get: (key) => record.get(key.id)
|
|
290
|
-
});
|
|
291
|
-
};
|
|
292
|
-
// src/server/cors.ts
|
|
293
|
-
var ORIGIN = "access-control-allow-origin";
|
|
294
|
-
var allowedOrigin = (options, requested) => {
|
|
295
|
-
const origin = options.origin ?? "*";
|
|
296
|
-
if (typeof origin === "string") {
|
|
297
|
-
if (origin !== "*")
|
|
298
|
-
return origin === requested ? origin : undefined;
|
|
299
|
-
if (!options.credentials)
|
|
300
|
-
return "*";
|
|
301
|
-
return requested ?? undefined;
|
|
302
|
-
}
|
|
303
|
-
if (requested === null)
|
|
304
|
-
return;
|
|
305
|
-
const allowed = typeof origin === "function" ? origin(requested) : origin.includes(requested);
|
|
306
|
-
return allowed ? requested : undefined;
|
|
307
|
-
};
|
|
308
|
-
var applyCors = (options, req, response) => {
|
|
309
|
-
const origin = allowedOrigin(options, req.headers.get("origin"));
|
|
310
|
-
if (origin === undefined)
|
|
311
|
-
return response;
|
|
312
|
-
response.headers.set(ORIGIN, origin);
|
|
313
|
-
if (origin !== "*")
|
|
314
|
-
response.headers.append("vary", "Origin");
|
|
315
|
-
if (options.credentials) {
|
|
316
|
-
response.headers.set("access-control-allow-credentials", "true");
|
|
317
|
-
}
|
|
318
|
-
if (options.exposedHeaders?.length) {
|
|
319
|
-
response.headers.set("access-control-expose-headers", options.exposedHeaders.join(", "));
|
|
320
|
-
}
|
|
321
|
-
return response;
|
|
322
|
-
};
|
|
323
|
-
var withCors = (options, handler) => {
|
|
324
|
-
return async (req) => applyCors(options, req, await handler(req));
|
|
325
|
-
};
|
|
326
|
-
var preflight = (options, methods) => {
|
|
327
|
-
const allowMethods = (options.methods ?? methods).join(", ");
|
|
328
|
-
return async (req) => {
|
|
329
|
-
const response = applyCors(options, req, new Response(null, { status: HttpStatusCode.NO_CONTENT }));
|
|
330
|
-
if (!response.headers.has(ORIGIN))
|
|
331
|
-
return response;
|
|
332
|
-
response.headers.set("access-control-allow-methods", allowMethods);
|
|
333
|
-
const allowHeaders = options.allowedHeaders ?? (req.headers.get("access-control-request-headers") ?? "").split(",").map((header) => header.trim()).filter((header) => header.length > 0);
|
|
334
|
-
if (allowHeaders.length > 0) {
|
|
335
|
-
response.headers.set("access-control-allow-headers", allowHeaders.join(", "));
|
|
336
|
-
}
|
|
337
|
-
if (options.maxAge !== undefined) {
|
|
338
|
-
response.headers.set("access-control-max-age", String(options.maxAge));
|
|
339
|
-
}
|
|
340
|
-
return response;
|
|
341
|
-
};
|
|
342
|
-
};
|
|
343
|
-
// src/server/errors.ts
|
|
344
|
-
import { AppError as AppError3, ConsoleLogger } from "@dunx/core";
|
|
345
|
-
class HttpError extends AppError3 {
|
|
346
|
-
status;
|
|
347
|
-
name = "HttpError";
|
|
348
|
-
headers;
|
|
349
|
-
constructor(status, message, options) {
|
|
350
|
-
super(message, options);
|
|
351
|
-
this.status = status;
|
|
352
|
-
this.headers = options?.headers;
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
Object.defineProperty(HttpError, Symbol.for("dunx.deps"), {
|
|
356
|
-
value: () => [{ unresolved: "readonly status: number" }, { unresolved: "message: string" }, { unresolved: "options?: HttpErrorOptions" }]
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
class ValidationError extends HttpError {
|
|
360
|
-
source;
|
|
361
|
-
issues;
|
|
362
|
-
name = "ValidationError";
|
|
363
|
-
constructor(source, issues) {
|
|
364
|
-
super(HttpStatusCode.BAD_REQUEST, `Invalid ${source}`);
|
|
365
|
-
this.source = source;
|
|
366
|
-
this.issues = issues;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
Object.defineProperty(ValidationError, Symbol.for("dunx.deps"), {
|
|
370
|
-
value: () => [{ unresolved: "readonly source: InputSource" }, { unresolved: "readonly issues: readonly ValidationIssue[]" }]
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
class ErrorFilter {
|
|
374
|
-
}
|
|
375
|
-
var isErrorFilter = (handler) => typeof handler === "function" && typeof handler.prototype?.catch === "function";
|
|
376
|
-
var toErrorMapper = (handler, resolve) => isErrorFilter(handler) ? (error, req) => resolve(handler).catch(error, req) : handler;
|
|
377
|
-
var errorMapper = (logger) => (error) => {
|
|
378
|
-
if (error instanceof ValidationError) {
|
|
379
|
-
return Response.json({ error: error.message, status: error.status, issues: error.issues }, {
|
|
380
|
-
status: error.status,
|
|
381
|
-
...error.headers && { headers: error.headers }
|
|
382
|
-
});
|
|
383
|
-
}
|
|
384
|
-
if (error instanceof HttpError) {
|
|
385
|
-
return Response.json({ error: error.message, status: error.status }, {
|
|
386
|
-
status: error.status,
|
|
387
|
-
...error.headers && { headers: error.headers }
|
|
388
|
-
});
|
|
389
|
-
}
|
|
390
|
-
logger.error("Unhandled error", error);
|
|
391
|
-
return Response.json({
|
|
392
|
-
error: "Internal Server Error",
|
|
393
|
-
status: HttpStatusCode.INTERNAL_SERVER_ERROR
|
|
394
|
-
}, { status: HttpStatusCode.INTERNAL_SERVER_ERROR });
|
|
395
|
-
};
|
|
396
|
-
var defaultErrorMapper = errorMapper(new ConsoleLogger);
|
|
397
101
|
// src/server/factory.ts
|
|
398
102
|
import {
|
|
399
|
-
collectModules
|
|
400
|
-
AppError as
|
|
103
|
+
collectModules,
|
|
104
|
+
AppError as AppError4,
|
|
401
105
|
AppFactory,
|
|
402
106
|
Logger as Logger4,
|
|
403
107
|
provide,
|
|
404
|
-
readControllers
|
|
108
|
+
readControllers,
|
|
405
109
|
RequestContext as RequestContext3
|
|
406
110
|
} from "@dunx/core";
|
|
407
111
|
|
|
408
|
-
// src/ws/envelope.ts
|
|
409
|
-
var encode = (event, data) => JSON.stringify({ event, data });
|
|
410
|
-
var decode = (message) => {
|
|
411
|
-
if (typeof message !== "string")
|
|
412
|
-
return;
|
|
413
|
-
let parsed;
|
|
414
|
-
try {
|
|
415
|
-
parsed = JSON.parse(message);
|
|
416
|
-
} catch {
|
|
417
|
-
return;
|
|
418
|
-
}
|
|
419
|
-
if (typeof parsed !== "object" || parsed === null)
|
|
420
|
-
return;
|
|
421
|
-
const { event, data } = parsed;
|
|
422
|
-
return typeof event === "string" ? { event, data } : undefined;
|
|
423
|
-
};
|
|
424
|
-
|
|
425
|
-
// src/ws/middleware.ts
|
|
426
|
-
var composeSocket = (middleware, ctx) => middleware.reduceRight((next, current) => (frame, run) => current.handle(frame, ctx, () => next(frame, run)), (_frame, run) => run());
|
|
427
|
-
var observe = (next, done) => {
|
|
428
|
-
let result;
|
|
429
|
-
try {
|
|
430
|
-
result = next();
|
|
431
|
-
} catch (error) {
|
|
432
|
-
done(error, undefined);
|
|
433
|
-
throw error;
|
|
434
|
-
}
|
|
435
|
-
if (result instanceof Promise) {
|
|
436
|
-
return result.then((value) => {
|
|
437
|
-
done(undefined, value);
|
|
438
|
-
return value;
|
|
439
|
-
}, (error) => {
|
|
440
|
-
done(error, undefined);
|
|
441
|
-
throw error;
|
|
442
|
-
});
|
|
443
|
-
}
|
|
444
|
-
done(undefined, result);
|
|
445
|
-
return result;
|
|
446
|
-
};
|
|
447
|
-
|
|
448
|
-
// src/ws/runtime.ts
|
|
449
|
-
import { AppError as AppError4 } from "@dunx/core";
|
|
450
|
-
var slotOf = (handler) => handler.kind === HandlerKind.MESSAGE && handler.event !== undefined ? `message ${JSON.stringify(handler.event)}` : handler.kind;
|
|
451
|
-
var buildRuntime = (gateway) => {
|
|
452
|
-
if (gateway.handlers.length === 0) {
|
|
453
|
-
throw new AppError4(`${gateway.name} is registered as a gateway but declares no handlers. ` + "Add an @OnMessage/@OnOpen/... method, or drop the @Gateway decorator.");
|
|
454
|
-
}
|
|
455
|
-
const owners = new Map;
|
|
456
|
-
const events = new Map;
|
|
457
|
-
for (const handler of gateway.handlers) {
|
|
458
|
-
const slot = slotOf(handler);
|
|
459
|
-
const existing = owners.get(slot);
|
|
460
|
-
if (existing) {
|
|
461
|
-
throw new AppError4(`Handler collision in ${gateway.name}: ${slot} is claimed by ` + `${existing.method}() and by ${handler.method}(). One handler per event.`);
|
|
462
|
-
}
|
|
463
|
-
owners.set(slot, handler);
|
|
464
|
-
if (handler.kind === HandlerKind.MESSAGE && handler.event !== undefined) {
|
|
465
|
-
events.set(handler.event, handler.invoke);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
const at = (slot) => owners.get(slot)?.invoke;
|
|
469
|
-
return {
|
|
470
|
-
name: gateway.name,
|
|
471
|
-
path: gateway.path,
|
|
472
|
-
upgrade: at(HandlerKind.UPGRADE),
|
|
473
|
-
open: at(HandlerKind.OPEN),
|
|
474
|
-
close: at(HandlerKind.CLOSE),
|
|
475
|
-
drain: at(HandlerKind.DRAIN),
|
|
476
|
-
ping: at(HandlerKind.PING),
|
|
477
|
-
pong: at(HandlerKind.PONG),
|
|
478
|
-
raw: at(HandlerKind.MESSAGE),
|
|
479
|
-
events
|
|
480
|
-
};
|
|
481
|
-
};
|
|
482
|
-
var buildGateways = (discovered) => {
|
|
483
|
-
const byPath = new Map;
|
|
484
|
-
for (const gateway of discovered) {
|
|
485
|
-
const existing = byPath.get(gateway.path);
|
|
486
|
-
if (existing) {
|
|
487
|
-
throw new AppError4(`Gateway path collision: ${gateway.path} is served by ${existing.name} ` + `and by ${gateway.name}. One gateway per path.`);
|
|
488
|
-
}
|
|
489
|
-
byPath.set(gateway.path, buildRuntime(gateway));
|
|
490
|
-
}
|
|
491
|
-
return byPath;
|
|
492
|
-
};
|
|
493
|
-
var someHandler = (gateways, pick) => {
|
|
494
|
-
for (const gateway of gateways)
|
|
495
|
-
if (pick(gateway) !== undefined)
|
|
496
|
-
return true;
|
|
497
|
-
return false;
|
|
498
|
-
};
|
|
499
|
-
|
|
500
|
-
// src/ws/adapter.ts
|
|
501
|
-
var RUNTIME = Symbol.for("dunx.ws.runtime");
|
|
502
|
-
var UNCLAIMED = Symbol.for("dunx.ws.unclaimed");
|
|
503
|
-
var defaultOnError = (error, socket) => {
|
|
504
|
-
console.error(`[dunx/http] ${socket.data.path} handler failed:`, error);
|
|
505
|
-
};
|
|
506
|
-
var reportedByMiddleware = () => {
|
|
507
|
-
return;
|
|
508
|
-
};
|
|
509
|
-
var unreported = (middleware) => "Socket middleware is installed and none of it sets reportsErrors, so a " + "throwing gateway handler is reported nowhere: the console fallback is off " + "whenever middleware wraps the handler. Set reportsErrors on the one that " + "records a failure, or pass websocket.onError. Installed: " + `${middleware.map((entry) => entry.constructor.name).join(", ")}.`;
|
|
510
|
-
var runtimeOf = (socket) => socket.data[RUNTIME];
|
|
511
|
-
var isBinary = (value) => value instanceof ArrayBuffer || ArrayBuffer.isView(value);
|
|
512
|
-
var replyRaw = (socket, value) => {
|
|
513
|
-
if (value === undefined)
|
|
514
|
-
return;
|
|
515
|
-
socket.send(typeof value === "string" || isBinary(value) ? value : JSON.stringify(value));
|
|
516
|
-
};
|
|
517
|
-
var settle = (result, socket, onError, then) => {
|
|
518
|
-
if (result instanceof Promise) {
|
|
519
|
-
result.then((value) => {
|
|
520
|
-
if (!then)
|
|
521
|
-
return;
|
|
522
|
-
try {
|
|
523
|
-
then(value);
|
|
524
|
-
} catch (error) {
|
|
525
|
-
onError(error, socket);
|
|
526
|
-
}
|
|
527
|
-
}, (error) => onError(error, socket));
|
|
528
|
-
return;
|
|
529
|
-
}
|
|
530
|
-
if (then)
|
|
531
|
-
then(result);
|
|
532
|
-
};
|
|
533
|
-
var framing = (kind) => {
|
|
534
|
-
if (kind === HandlerKind.CLOSE) {
|
|
535
|
-
return (args) => ({
|
|
536
|
-
socket: args[0],
|
|
537
|
-
data: { code: args[1], reason: args[2] }
|
|
538
|
-
});
|
|
539
|
-
}
|
|
540
|
-
if (kind === HandlerKind.OPEN || kind === HandlerKind.DRAIN) {
|
|
541
|
-
return (args) => ({ socket: args[0], data: undefined });
|
|
542
|
-
}
|
|
543
|
-
return (args) => ({ socket: args[1], data: args[0] });
|
|
544
|
-
};
|
|
545
|
-
var NOTHING = () => {
|
|
546
|
-
return;
|
|
547
|
-
};
|
|
548
|
-
var through = (gateway, middleware, kind, event, invoke) => {
|
|
549
|
-
const ctx = {
|
|
550
|
-
gateway: gateway.name,
|
|
551
|
-
path: gateway.path,
|
|
552
|
-
kind,
|
|
553
|
-
event
|
|
554
|
-
};
|
|
555
|
-
const dispatch = composeSocket(middleware, ctx);
|
|
556
|
-
const frameOf = framing(kind);
|
|
557
|
-
const run = invoke ?? NOTHING;
|
|
558
|
-
return (...args) => dispatch(frameOf(args), () => run(...args));
|
|
559
|
-
};
|
|
560
|
-
var withMiddleware = (gateway, middleware) => {
|
|
561
|
-
const wrap = (kind, event, invoke) => through(gateway, middleware, kind, event, invoke);
|
|
562
|
-
const optional = (kind, invoke) => invoke === undefined ? undefined : wrap(kind, undefined, invoke);
|
|
563
|
-
return {
|
|
564
|
-
...gateway,
|
|
565
|
-
open: wrap(HandlerKind.OPEN, undefined, gateway.open),
|
|
566
|
-
close: wrap(HandlerKind.CLOSE, undefined, gateway.close),
|
|
567
|
-
drain: optional(HandlerKind.DRAIN, gateway.drain),
|
|
568
|
-
ping: optional(HandlerKind.PING, gateway.ping),
|
|
569
|
-
pong: optional(HandlerKind.PONG, gateway.pong),
|
|
570
|
-
raw: optional(HandlerKind.MESSAGE, gateway.raw),
|
|
571
|
-
events: new Map([...gateway.events].map(([event, invoke]) => [
|
|
572
|
-
event,
|
|
573
|
-
wrap(HandlerKind.MESSAGE, event, invoke)
|
|
574
|
-
]))
|
|
575
|
-
};
|
|
576
|
-
};
|
|
577
|
-
var unclaimedDispatch = (gateway, middleware) => (frame, event) => composeSocket(middleware, {
|
|
578
|
-
gateway: gateway.name,
|
|
579
|
-
path: gateway.path,
|
|
580
|
-
kind: HandlerKind.MESSAGE,
|
|
581
|
-
event
|
|
582
|
-
})(frame, () => {
|
|
583
|
-
return;
|
|
584
|
-
});
|
|
585
|
-
var buildWebSocket = (discovered, options = {}, middleware = []) => {
|
|
586
|
-
const byPath = buildGateways(discovered);
|
|
587
|
-
const wrapped = middleware.length === 0 ? byPath : new Map([...byPath].map(([path, gateway]) => [
|
|
588
|
-
path,
|
|
589
|
-
withMiddleware(gateway, middleware)
|
|
590
|
-
]));
|
|
591
|
-
const gateways = [...wrapped.values()];
|
|
592
|
-
const onError = options.onError ?? (middleware.length === 0 ? defaultOnError : reportedByMiddleware);
|
|
593
|
-
const reports = options.onError !== undefined || middleware.some((entry) => entry.reportsErrors === true);
|
|
594
|
-
const { onError: _onError, ...socketOptions } = options;
|
|
595
|
-
const run = (invoke, args, ws, then) => {
|
|
596
|
-
try {
|
|
597
|
-
settle(invoke(...args), ws, onError, then);
|
|
598
|
-
} catch (error) {
|
|
599
|
-
onError(error, ws);
|
|
600
|
-
}
|
|
601
|
-
};
|
|
602
|
-
const websocket = {
|
|
603
|
-
...socketOptions,
|
|
604
|
-
message(ws, message) {
|
|
605
|
-
const gateway = runtimeOf(ws);
|
|
606
|
-
let event;
|
|
607
|
-
if (gateway.events.size > 0) {
|
|
608
|
-
const envelope = decode(message);
|
|
609
|
-
const handler = envelope && gateway.events.get(envelope.event);
|
|
610
|
-
if (envelope && handler) {
|
|
611
|
-
run(handler, [envelope.data, ws], ws, (value) => {
|
|
612
|
-
if (value !== undefined)
|
|
613
|
-
ws.send(encode(envelope.event, value));
|
|
614
|
-
});
|
|
615
|
-
return;
|
|
616
|
-
}
|
|
617
|
-
event = envelope?.event;
|
|
618
|
-
}
|
|
619
|
-
if (gateway.raw) {
|
|
620
|
-
run(gateway.raw, [message, ws], ws, (value) => replyRaw(ws, value));
|
|
621
|
-
return;
|
|
622
|
-
}
|
|
623
|
-
const unclaimed2 = ws.data[UNCLAIMED];
|
|
624
|
-
if (!unclaimed2)
|
|
625
|
-
return;
|
|
626
|
-
try {
|
|
627
|
-
settle(unclaimed2({ socket: ws, data: message }, event), ws, onError, undefined);
|
|
628
|
-
} catch (error) {
|
|
629
|
-
onError(error, ws);
|
|
630
|
-
}
|
|
631
|
-
},
|
|
632
|
-
...someHandler(gateways, (g) => g.open) && {
|
|
633
|
-
open(ws) {
|
|
634
|
-
const { open } = runtimeOf(ws);
|
|
635
|
-
if (open)
|
|
636
|
-
run(open, [ws], ws, undefined);
|
|
637
|
-
}
|
|
638
|
-
},
|
|
639
|
-
...someHandler(gateways, (g) => g.close) && {
|
|
640
|
-
close(ws, code, reason) {
|
|
641
|
-
const { close } = runtimeOf(ws);
|
|
642
|
-
if (close)
|
|
643
|
-
run(close, [ws, code, reason], ws, undefined);
|
|
644
|
-
}
|
|
645
|
-
},
|
|
646
|
-
...someHandler(gateways, (g) => g.drain) && {
|
|
647
|
-
drain(ws) {
|
|
648
|
-
const { drain } = runtimeOf(ws);
|
|
649
|
-
if (drain)
|
|
650
|
-
run(drain, [ws], ws, undefined);
|
|
651
|
-
}
|
|
652
|
-
},
|
|
653
|
-
...someHandler(gateways, (g) => g.ping) && {
|
|
654
|
-
ping(ws, data) {
|
|
655
|
-
const { ping } = runtimeOf(ws);
|
|
656
|
-
if (ping)
|
|
657
|
-
run(ping, [data, ws], ws, undefined);
|
|
658
|
-
}
|
|
659
|
-
},
|
|
660
|
-
...someHandler(gateways, (g) => g.pong) && {
|
|
661
|
-
pong(ws, data) {
|
|
662
|
-
const { pong } = runtimeOf(ws);
|
|
663
|
-
if (pong)
|
|
664
|
-
run(pong, [data, ws], ws, undefined);
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
};
|
|
668
|
-
const unclaimed = new Map(middleware.length === 0 ? [] : gateways.map((gateway) => [
|
|
669
|
-
gateway,
|
|
670
|
-
unclaimedDispatch(gateway, middleware)
|
|
671
|
-
]));
|
|
672
|
-
const accept = (req, server, gateway, context) => {
|
|
673
|
-
const fallback = unclaimed.get(gateway);
|
|
674
|
-
const data = {
|
|
675
|
-
path: gateway.path,
|
|
676
|
-
context,
|
|
677
|
-
id: crypto.randomUUID(),
|
|
678
|
-
[RUNTIME]: gateway,
|
|
679
|
-
...fallback === undefined ? {} : { [UNCLAIMED]: fallback }
|
|
680
|
-
};
|
|
681
|
-
return server.upgrade(req, { data }) ? undefined : new Response("Expected a WebSocket upgrade", { status: 426 });
|
|
682
|
-
};
|
|
683
|
-
const upgradeHandler = (gateway) => (req, server) => {
|
|
684
|
-
if (!gateway.upgrade)
|
|
685
|
-
return accept(req, server, gateway, undefined);
|
|
686
|
-
const result = gateway.upgrade(req);
|
|
687
|
-
if (result instanceof Promise) {
|
|
688
|
-
return result.then((value) => value instanceof Response ? value : accept(req, server, gateway, value));
|
|
689
|
-
}
|
|
690
|
-
return result instanceof Response ? result : accept(req, server, gateway, result);
|
|
691
|
-
};
|
|
692
|
-
return {
|
|
693
|
-
websocket,
|
|
694
|
-
routes: new Map(gateways.map((gateway) => [gateway.path, upgradeHandler(gateway)])),
|
|
695
|
-
paths: [...byPath.keys()],
|
|
696
|
-
warnings: middleware.length > 0 && !reports ? [unreported(middleware)] : [],
|
|
697
|
-
gateways: gateways.map((gateway) => ({
|
|
698
|
-
name: gateway.name,
|
|
699
|
-
path: gateway.path,
|
|
700
|
-
events: [...gateway.events.keys()]
|
|
701
|
-
}))
|
|
702
|
-
};
|
|
703
|
-
};
|
|
704
|
-
|
|
705
112
|
// src/ws/logging.ts
|
|
706
113
|
import { Logger, LogLevel, RequestContext } from "@dunx/core";
|
|
707
114
|
var LIFECYCLE_LABEL = {
|
|
@@ -746,7 +153,7 @@ class SocketLoggingMiddleware {
|
|
|
746
153
|
const label = ctx.event ?? LIFECYCLE_LABEL[ctx.kind] ?? ctx.kind;
|
|
747
154
|
const connectionId = frame.socket.data.id;
|
|
748
155
|
const started = Bun.nanoseconds();
|
|
749
|
-
const
|
|
156
|
+
const write = (error, value) => {
|
|
750
157
|
const entry = {
|
|
751
158
|
gateway: ctx.gateway,
|
|
752
159
|
path: ctx.path,
|
|
@@ -760,8 +167,8 @@ class SocketLoggingMiddleware {
|
|
|
760
167
|
this.#emit(error === undefined ? level : this.#errorLevel, line, entry);
|
|
761
168
|
};
|
|
762
169
|
if (!this.#correlate)
|
|
763
|
-
return observe(next,
|
|
764
|
-
return this.context.runWithContext({ connectionId, event: label, flow: "ws", context: ctx.gateway }, () => observe(next,
|
|
170
|
+
return observe(next, write);
|
|
171
|
+
return this.context.runWithContext({ connectionId, event: label, flow: "ws", context: ctx.gateway }, () => observe(next, write));
|
|
765
172
|
}
|
|
766
173
|
#emit(level, line, entry) {
|
|
767
174
|
switch (level) {
|
|
@@ -797,42 +204,10 @@ class SocketLoggingMiddleware {
|
|
|
797
204
|
return text.length > this.#limit ? `[${text.length} chars]` : data;
|
|
798
205
|
}
|
|
799
206
|
}
|
|
800
|
-
Object.defineProperty(SocketLoggingMiddleware, Symbol.for("dunx.deps"), {
|
|
801
|
-
value: () => [Logger, RequestContext, { unresolved: "options: SocketLoggingOptions = {}" }]
|
|
802
|
-
});
|
|
803
|
-
|
|
804
|
-
// src/ws/pubsub.ts
|
|
805
|
-
import { AppError as AppError5 } from "@dunx/core";
|
|
806
|
-
|
|
807
|
-
// src/ws/relay.ts
|
|
808
|
-
var DEFAULT_RELAY_CHANNEL = "dunx:ws";
|
|
809
|
-
var defaultRelayError = (error, phase) => {
|
|
810
|
-
console.warn(`[dunx/http] the websocket relay could not ${phase}. Fan-out is local to ` + "this process until it recovers:", error);
|
|
811
|
-
};
|
|
812
|
-
var toBytes = (data) => ArrayBuffer.isView(data) ? new Uint8Array(data.buffer, data.byteOffset, data.byteLength) : new Uint8Array(data);
|
|
813
|
-
var encodeRelay = (origin, topic, data) => typeof data === "string" ? JSON.stringify({ o: origin, t: topic, d: data }) : JSON.stringify({
|
|
814
|
-
o: origin,
|
|
815
|
-
t: topic,
|
|
816
|
-
d: Buffer.from(toBytes(data)).toString("base64"),
|
|
817
|
-
b: 1
|
|
818
|
-
});
|
|
819
|
-
var decodeRelay = (message) => {
|
|
820
|
-
let parsed;
|
|
821
|
-
try {
|
|
822
|
-
parsed = JSON.parse(message);
|
|
823
|
-
} catch {
|
|
824
|
-
return;
|
|
825
|
-
}
|
|
826
|
-
if (typeof parsed !== "object" || parsed === null)
|
|
827
|
-
return;
|
|
828
|
-
const { o, t, d, b } = parsed;
|
|
829
|
-
if (typeof o !== "string" || typeof t !== "string" || typeof d !== "string") {
|
|
830
|
-
return;
|
|
831
|
-
}
|
|
832
|
-
return { origin: o, topic: t, data: b ? Buffer.from(d, "base64") : d };
|
|
833
|
-
};
|
|
207
|
+
Object.defineProperty(SocketLoggingMiddleware, Symbol.for("dunx.deps"), { value: () => [Logger, RequestContext, { unresolved: "options: SocketLoggingOptions = {}", optional: true }] });
|
|
834
208
|
|
|
835
209
|
// src/ws/pubsub.ts
|
|
210
|
+
import { AppError as AppError2 } from "@dunx/core";
|
|
836
211
|
class PubSub {
|
|
837
212
|
#origin = Bun.randomUUIDv7();
|
|
838
213
|
#server;
|
|
@@ -857,7 +232,7 @@ class PubSub {
|
|
|
857
232
|
}
|
|
858
233
|
async relayThrough(relay, options = {}) {
|
|
859
234
|
if (this.#relay) {
|
|
860
|
-
throw new
|
|
235
|
+
throw new AppError2("PubSub already relays. Two subscriptions on one channel would deliver " + "every relayed message twice - pass HttpOptions.relay or call " + "relayThrough(), not both.");
|
|
861
236
|
}
|
|
862
237
|
this.#relay = relay;
|
|
863
238
|
this.#channel = options.channel ?? DEFAULT_RELAY_CHANNEL;
|
|
@@ -953,7 +328,7 @@ class PubSub {
|
|
|
953
328
|
}
|
|
954
329
|
#live() {
|
|
955
330
|
if (!this.#server) {
|
|
956
|
-
throw new
|
|
331
|
+
throw new AppError2("PubSub has no server yet. Publish once the server is listening: " + "HttpApp.listen() is what attaches it.");
|
|
957
332
|
}
|
|
958
333
|
return this.#server;
|
|
959
334
|
}
|
|
@@ -961,7 +336,7 @@ class PubSub {
|
|
|
961
336
|
|
|
962
337
|
// src/server/application.ts
|
|
963
338
|
import {
|
|
964
|
-
AppError as
|
|
339
|
+
AppError as AppError3,
|
|
965
340
|
Logger as Logger3,
|
|
966
341
|
runtimeInfo,
|
|
967
342
|
ShutdownHooks,
|
|
@@ -974,47 +349,6 @@ import {
|
|
|
974
349
|
Logger as Logger2,
|
|
975
350
|
RequestContext as RequestContext2
|
|
976
351
|
} from "@dunx/core";
|
|
977
|
-
|
|
978
|
-
// src/server/raw-body.ts
|
|
979
|
-
var WANTED = Symbol.for("dunx.http.rawBody.wanted");
|
|
980
|
-
var TEXT = Symbol.for("dunx.http.rawBody.text");
|
|
981
|
-
|
|
982
|
-
class RawBody {
|
|
983
|
-
static want(req) {
|
|
984
|
-
req[WANTED] = true;
|
|
985
|
-
}
|
|
986
|
-
static wanted(req) {
|
|
987
|
-
return req[WANTED] === true;
|
|
988
|
-
}
|
|
989
|
-
static record(req, text) {
|
|
990
|
-
req[TEXT] = text;
|
|
991
|
-
}
|
|
992
|
-
static read(req) {
|
|
993
|
-
return req[TEXT];
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
|
|
997
|
-
// src/server/request-id.ts
|
|
998
|
-
var REQUEST_ID_HEADER = "x-request-id";
|
|
999
|
-
var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1000
|
-
var traceId = (inbound) => inbound !== null && inbound.length === 36 && UUID.test(inbound) ? inbound : crypto.randomUUID();
|
|
1001
|
-
var ID = Symbol.for("dunx.http.requestId");
|
|
1002
|
-
|
|
1003
|
-
class RequestIds {
|
|
1004
|
-
static assign(req) {
|
|
1005
|
-
const id = traceId(req.headers.get(REQUEST_ID_HEADER));
|
|
1006
|
-
req[ID] = id;
|
|
1007
|
-
return id;
|
|
1008
|
-
}
|
|
1009
|
-
static stamp(response, req) {
|
|
1010
|
-
const id = req[ID];
|
|
1011
|
-
if (id !== undefined)
|
|
1012
|
-
response.headers.set(REQUEST_ID_HEADER, id);
|
|
1013
|
-
return response;
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
// src/server/request-logging.ts
|
|
1018
352
|
var parse = (text, limit) => {
|
|
1019
353
|
if (limit === 0)
|
|
1020
354
|
return;
|
|
@@ -1210,248 +544,7 @@ class RequestLoggingMiddleware {
|
|
|
1210
544
|
return response.clone().text().then((text) => parse(text, this.#limit));
|
|
1211
545
|
}
|
|
1212
546
|
}
|
|
1213
|
-
Object.defineProperty(RequestLoggingMiddleware, Symbol.for("dunx.deps"), {
|
|
1214
|
-
value: () => [Logger2, RequestContext2, { unresolved: "options: RequestLoggingOptions = {}" }]
|
|
1215
|
-
});
|
|
1216
|
-
|
|
1217
|
-
// src/server/routes.ts
|
|
1218
|
-
import { AppError as AppError6 } from "@dunx/core";
|
|
1219
|
-
|
|
1220
|
-
// src/server/input.ts
|
|
1221
|
-
var grouped = (entries) => {
|
|
1222
|
-
const collected = {};
|
|
1223
|
-
entries.forEach((value, key) => {
|
|
1224
|
-
const existing = collected[key];
|
|
1225
|
-
if (existing === undefined)
|
|
1226
|
-
collected[key] = value;
|
|
1227
|
-
else if (Array.isArray(existing))
|
|
1228
|
-
existing.push(value);
|
|
1229
|
-
else
|
|
1230
|
-
collected[key] = [existing, value];
|
|
1231
|
-
});
|
|
1232
|
-
return collected;
|
|
1233
|
-
};
|
|
1234
|
-
var asJson = (req) => req.json();
|
|
1235
|
-
var asUrlEncoded = async (req) => grouped(new URLSearchParams(await req.text()));
|
|
1236
|
-
var asMultipart = async (req) => grouped(await req.formData());
|
|
1237
|
-
var asText = (req) => req.text();
|
|
1238
|
-
var parserFor = (media) => {
|
|
1239
|
-
if (media === "application/json" || media.endsWith("+json"))
|
|
1240
|
-
return asJson;
|
|
1241
|
-
if (media === "application/x-www-form-urlencoded")
|
|
1242
|
-
return asUrlEncoded;
|
|
1243
|
-
if (media === "multipart/form-data")
|
|
1244
|
-
return asMultipart;
|
|
1245
|
-
if (media.startsWith("text/"))
|
|
1246
|
-
return asText;
|
|
1247
|
-
return;
|
|
1248
|
-
};
|
|
1249
|
-
var JSON_MEDIA = "application/json";
|
|
1250
|
-
var mediaTypeOf = (req) => {
|
|
1251
|
-
const header = req.headers.get("content-type");
|
|
1252
|
-
if (header === JSON_MEDIA || header === null)
|
|
1253
|
-
return JSON_MEDIA;
|
|
1254
|
-
const end = header.indexOf(";");
|
|
1255
|
-
const media = (end === -1 ? header : header.slice(0, end)).trim();
|
|
1256
|
-
return media === "" ? JSON_MEDIA : media.toLowerCase();
|
|
1257
|
-
};
|
|
1258
|
-
var flatten = (issue) => {
|
|
1259
|
-
const path = issue.path?.map((segment) => String(typeof segment === "object" ? segment.key : segment)).join(".");
|
|
1260
|
-
return path === undefined || path === "" ? { message: issue.message } : { message: issue.message, path };
|
|
1261
|
-
};
|
|
1262
|
-
var accept = (source, result) => {
|
|
1263
|
-
if (result.issues !== undefined) {
|
|
1264
|
-
throw new ValidationError(source, result.issues.map(flatten));
|
|
1265
|
-
}
|
|
1266
|
-
return result.value;
|
|
1267
|
-
};
|
|
1268
|
-
var fillWith = (draft, source, schema, value) => {
|
|
1269
|
-
const result = schema["~standard"].validate(value);
|
|
1270
|
-
if (result instanceof Promise) {
|
|
1271
|
-
return result.then((settled) => {
|
|
1272
|
-
draft[source] = accept(source, settled);
|
|
1273
|
-
return draft;
|
|
1274
|
-
});
|
|
1275
|
-
}
|
|
1276
|
-
draft[source] = accept(source, result);
|
|
1277
|
-
return draft;
|
|
1278
|
-
};
|
|
1279
|
-
var bodyFill = (schema) => (draft) => {
|
|
1280
|
-
const media = mediaTypeOf(draft.req);
|
|
1281
|
-
const parse2 = parserFor(media);
|
|
1282
|
-
if (parse2 === undefined) {
|
|
1283
|
-
throw new HttpError(HttpStatusCode.UNSUPPORTED_MEDIA_TYPE, `Unsupported content type "${media}". Declared bodies accept ` + "application/json, application/x-www-form-urlencoded, multipart/form-data or text/*.");
|
|
1284
|
-
}
|
|
1285
|
-
const read = parse2 === asJson && RawBody.wanted(draft.req) ? draft.req.text().then((text) => {
|
|
1286
|
-
RawBody.record(draft.req, text);
|
|
1287
|
-
return JSON.parse(text);
|
|
1288
|
-
}) : parse2(draft.req);
|
|
1289
|
-
return read.then((value) => fillWith(draft, "body", schema, value), (error) => {
|
|
1290
|
-
throw new HttpError(HttpStatusCode.BAD_REQUEST, `Malformed ${media} body`, { cause: error });
|
|
1291
|
-
});
|
|
1292
|
-
};
|
|
1293
|
-
var searchOf = (url) => {
|
|
1294
|
-
const start = url.indexOf("?");
|
|
1295
|
-
if (start === -1)
|
|
1296
|
-
return "";
|
|
1297
|
-
const end = url.indexOf("#", start + 1);
|
|
1298
|
-
return end === -1 ? url.slice(start + 1) : url.slice(start + 1, end);
|
|
1299
|
-
};
|
|
1300
|
-
var queryFill = (schema) => (draft) => {
|
|
1301
|
-
const params = new URLSearchParams(searchOf(draft.req.url));
|
|
1302
|
-
return fillWith(draft, "query", schema, grouped(params));
|
|
1303
|
-
};
|
|
1304
|
-
var paramsFill = (schema) => (draft) => fillWith(draft, "params", schema, draft.req.params);
|
|
1305
|
-
var then = (first, second) => (draft) => {
|
|
1306
|
-
const started = first(draft);
|
|
1307
|
-
return started instanceof Promise ? started.then(second) : second(started);
|
|
1308
|
-
};
|
|
1309
|
-
var buildInputReader = (options) => {
|
|
1310
|
-
const fills = [];
|
|
1311
|
-
if (options?.body !== undefined)
|
|
1312
|
-
fills.push(bodyFill(options.body));
|
|
1313
|
-
if (options?.query !== undefined)
|
|
1314
|
-
fills.push(queryFill(options.query));
|
|
1315
|
-
if (options?.params !== undefined)
|
|
1316
|
-
fills.push(paramsFill(options.params));
|
|
1317
|
-
if (fills.length === 0)
|
|
1318
|
-
return (req) => ({ req });
|
|
1319
|
-
const fill = fills.reduce(then);
|
|
1320
|
-
return (req) => fill({ req });
|
|
1321
|
-
};
|
|
1322
|
-
|
|
1323
|
-
// src/server/middleware.ts
|
|
1324
|
-
var compose = (middleware, ctx, handler) => middleware.reduceRight((next, current) => (req) => current.handle(req, ctx, () => next(req)), handler);
|
|
1325
|
-
|
|
1326
|
-
// src/server/routes.ts
|
|
1327
|
-
var construct = (guard) => new guard;
|
|
1328
|
-
var toResponse = (value, status) => {
|
|
1329
|
-
if (value instanceof Response)
|
|
1330
|
-
return value;
|
|
1331
|
-
if (value === undefined || value === null) {
|
|
1332
|
-
return new Response(null, { status: HttpStatusCode.NO_CONTENT });
|
|
1333
|
-
}
|
|
1334
|
-
return Response.json(value, { status });
|
|
1335
|
-
};
|
|
1336
|
-
var statusFor = (route) => route.options?.status ?? defaultStatusFor(route.method);
|
|
1337
|
-
var assertNoCollisions = (discovered) => {
|
|
1338
|
-
const owners = new Map;
|
|
1339
|
-
for (const route of discovered) {
|
|
1340
|
-
const key = `${route.method} ${route.path}`;
|
|
1341
|
-
const owner = `${route.controller}.${route.handlerName}`;
|
|
1342
|
-
const existing = owners.get(key);
|
|
1343
|
-
if (existing !== undefined) {
|
|
1344
|
-
throw new AppError6(`Route collision: ${key} is declared by ${existing} and by ${owner}. ` + "Bun would keep only one of them.");
|
|
1345
|
-
}
|
|
1346
|
-
owners.set(key, owner);
|
|
1347
|
-
}
|
|
1348
|
-
};
|
|
1349
|
-
var assertNoGatewayCollisions = (discovered, gatewayPaths) => {
|
|
1350
|
-
const gateways = new Set(gatewayPaths);
|
|
1351
|
-
for (const route of discovered) {
|
|
1352
|
-
if (gateways.has(route.path)) {
|
|
1353
|
-
throw new AppError6(`Gateway path collision: ${route.path} is served by a gateway and by ` + `${route.controller}.${route.handlerName}(). The upgrade is a route too, ` + "so one of them would be dropped.");
|
|
1354
|
-
}
|
|
1355
|
-
}
|
|
1356
|
-
};
|
|
1357
|
-
var withUpgradeRoutes = (routes, gateways) => {
|
|
1358
|
-
const merged = { ...routes };
|
|
1359
|
-
for (const [path, upgrade] of gateways)
|
|
1360
|
-
merged[path] = { GET: upgrade };
|
|
1361
|
-
return merged;
|
|
1362
|
-
};
|
|
1363
|
-
var unmatchedContext = (req, isPublic) => Object.freeze({
|
|
1364
|
-
controller: "(unmatched)",
|
|
1365
|
-
handler: "(none)",
|
|
1366
|
-
method: req.method,
|
|
1367
|
-
path: new URL(req.url).pathname,
|
|
1368
|
-
parsesBody: false,
|
|
1369
|
-
get: (key) => {
|
|
1370
|
-
if (key.id === UNMATCHED.id)
|
|
1371
|
-
return true;
|
|
1372
|
-
if (key.id === PUBLIC.id && isPublic)
|
|
1373
|
-
return true;
|
|
1374
|
-
return;
|
|
1375
|
-
}
|
|
1376
|
-
});
|
|
1377
|
-
var buildFallback = (middleware = [], onError = defaultErrorMapper, cors, notFound = "guarded") => {
|
|
1378
|
-
const miss = () => {
|
|
1379
|
-
throw new HttpError(HttpStatusCode.NOT_FOUND, "NOT_FOUND");
|
|
1380
|
-
};
|
|
1381
|
-
const run = async (req) => {
|
|
1382
|
-
try {
|
|
1383
|
-
return await compose(middleware, unmatchedContext(req, notFound === "public"), miss)(req);
|
|
1384
|
-
} catch (error) {
|
|
1385
|
-
return RequestIds.stamp(onError(error, req), req);
|
|
1386
|
-
}
|
|
1387
|
-
};
|
|
1388
|
-
return cors ? withCors(cors, run) : run;
|
|
1389
|
-
};
|
|
1390
|
-
var directOr = (guarded, route, read, status, onError, noMiddleware) => {
|
|
1391
|
-
if (!noMiddleware)
|
|
1392
|
-
return guarded;
|
|
1393
|
-
const settle2 = (value, req) => {
|
|
1394
|
-
try {
|
|
1395
|
-
return toResponse(value, status);
|
|
1396
|
-
} catch (error) {
|
|
1397
|
-
return onError(error, req);
|
|
1398
|
-
}
|
|
1399
|
-
};
|
|
1400
|
-
const invoke = (input, req) => {
|
|
1401
|
-
try {
|
|
1402
|
-
const value = route.handler(input);
|
|
1403
|
-
return value instanceof Promise ? value.then((resolved) => settle2(resolved, req), (error) => onError(error, req)) : settle2(value, req);
|
|
1404
|
-
} catch (error) {
|
|
1405
|
-
return onError(error, req);
|
|
1406
|
-
}
|
|
1407
|
-
};
|
|
1408
|
-
return (req) => {
|
|
1409
|
-
try {
|
|
1410
|
-
const input = read(req);
|
|
1411
|
-
return input instanceof Promise ? input.then((resolved) => invoke(resolved, req), (error) => onError(error, req)) : invoke(input, req);
|
|
1412
|
-
} catch (error) {
|
|
1413
|
-
return onError(error, req);
|
|
1414
|
-
}
|
|
1415
|
-
};
|
|
1416
|
-
};
|
|
1417
|
-
var buildRoutes = (discovered, middleware = [], onError = defaultErrorMapper, cors, resolve = construct) => {
|
|
1418
|
-
assertNoCollisions(discovered);
|
|
1419
|
-
const routes = {};
|
|
1420
|
-
const instances = new Map;
|
|
1421
|
-
const guardOf = (guard, from) => {
|
|
1422
|
-
const existing = instances.get(guard);
|
|
1423
|
-
if (existing)
|
|
1424
|
-
return existing;
|
|
1425
|
-
const created = resolve(guard, from);
|
|
1426
|
-
instances.set(guard, created);
|
|
1427
|
-
return created;
|
|
1428
|
-
};
|
|
1429
|
-
for (const route of discovered) {
|
|
1430
|
-
const read = buildInputReader(route.options);
|
|
1431
|
-
const status = statusFor(route);
|
|
1432
|
-
const chain = [
|
|
1433
|
-
...middleware,
|
|
1434
|
-
...(route.moduleMiddleware ?? []).map((entry) => guardOf(entry, route.module)),
|
|
1435
|
-
...(route.guards ?? []).map((guard) => guardOf(guard, route.module))
|
|
1436
|
-
];
|
|
1437
|
-
const chained = compose(chain, buildContext(route), async (req) => toResponse(await route.handler(await read(req)), status));
|
|
1438
|
-
const guarded = async (req) => {
|
|
1439
|
-
try {
|
|
1440
|
-
return await chained(req);
|
|
1441
|
-
} catch (error) {
|
|
1442
|
-
return RequestIds.stamp(onError(error, req), req);
|
|
1443
|
-
}
|
|
1444
|
-
};
|
|
1445
|
-
const byMethod = routes[route.path] ??= {};
|
|
1446
|
-
byMethod[route.method] = cors ? withCors(cors, guarded) : directOr(guarded, route, read, status, onError, chain.length === 0);
|
|
1447
|
-
}
|
|
1448
|
-
if (cors) {
|
|
1449
|
-
for (const byMethod of Object.values(routes)) {
|
|
1450
|
-
byMethod.OPTIONS = preflight(cors, Object.keys(byMethod));
|
|
1451
|
-
}
|
|
1452
|
-
}
|
|
1453
|
-
return routes;
|
|
1454
|
-
};
|
|
547
|
+
Object.defineProperty(RequestLoggingMiddleware, Symbol.for("dunx.deps"), { value: () => [Logger2, RequestContext2, { unresolved: "options: RequestLoggingOptions = {}", optional: true }] });
|
|
1455
548
|
|
|
1456
549
|
// src/server/settings.ts
|
|
1457
550
|
var defaultSettings = () => ({ "trust proxy": false });
|
|
@@ -1634,12 +727,10 @@ class HttpApplication {
|
|
|
1634
727
|
#assertNotStarted(hook) {
|
|
1635
728
|
if (!this.#started)
|
|
1636
729
|
return;
|
|
1637
|
-
throw new
|
|
730
|
+
throw new AppError3(`${hook} must be called before listen(). The route table and the middleware ` + "chain are folded into one closure per route when the server binds, so " + "this call could not take effect.");
|
|
1638
731
|
}
|
|
1639
732
|
}
|
|
1640
|
-
Object.defineProperty(HttpApplication, Symbol.for("dunx.deps"), {
|
|
1641
|
-
value: () => [{ unresolved: "app: App", typeOnly: "App" }, { unresolved: "discovered: readonly DiscoveredRoute[]" }, { unresolved: "options: HttpOptions" }, { unresolved: "root: ModuleRef", typeOnly: "ModuleRef" }, { unresolved: "websocket?: WebSocketRuntime", typeOnly: "WebSocketRuntime" }]
|
|
1642
|
-
});
|
|
733
|
+
Object.defineProperty(HttpApplication, Symbol.for("dunx.deps"), { value: () => [{ unresolved: "app: App", typeOnly: "App" }, { unresolved: "discovered: readonly DiscoveredRoute[]" }, { unresolved: "options: HttpOptions" }, { unresolved: "root: ModuleRef", typeOnly: "ModuleRef" }, { unresolved: "websocket?: WebSocketRuntime", typeOnly: "WebSocketRuntime" }] });
|
|
1643
734
|
|
|
1644
735
|
// src/server/factory.ts
|
|
1645
736
|
class HttpModule {
|
|
@@ -1669,14 +760,14 @@ class HttpFactory {
|
|
|
1669
760
|
exports: providers.map((entry) => typeof entry === "function" ? entry : entry.token)
|
|
1670
761
|
};
|
|
1671
762
|
const app = await AppFactory.create(scope, options.overrides ? { overrides: options.overrides } : {});
|
|
1672
|
-
const modules =
|
|
763
|
+
const modules = collectModules(scope);
|
|
1673
764
|
const discovered = [];
|
|
1674
765
|
for (const module of modules) {
|
|
1675
766
|
const moduleMiddleware = module.options.middleware ?? [];
|
|
1676
|
-
for (const controller of
|
|
767
|
+
for (const controller of readControllers(module)) {
|
|
1677
768
|
const routes = discoverRoutes(app.get(controller, module.ref));
|
|
1678
769
|
if (routes.length === 0) {
|
|
1679
|
-
throw new
|
|
770
|
+
throw new AppError4(`${controller.name} is registered as a controller but declares no routes. ` + "Add a @Get/@Post/... method, or move it to providers.");
|
|
1680
771
|
}
|
|
1681
772
|
discovered.push(...routes.map((route) => ({
|
|
1682
773
|
...route,
|
|
@@ -1703,29 +794,6 @@ class HttpFactory {
|
|
|
1703
794
|
}
|
|
1704
795
|
// src/static/files.ts
|
|
1705
796
|
import { join, normalize, resolve } from "path";
|
|
1706
|
-
|
|
1707
|
-
// src/static/options.ts
|
|
1708
|
-
class StaticOptions {
|
|
1709
|
-
root;
|
|
1710
|
-
path;
|
|
1711
|
-
maxAge;
|
|
1712
|
-
immutable;
|
|
1713
|
-
constructor(init) {
|
|
1714
|
-
this.root = init.root;
|
|
1715
|
-
this.path = normalizePrefix(init.path ?? "/");
|
|
1716
|
-
this.maxAge = init.maxAge ?? 60;
|
|
1717
|
-
this.immutable = init.immutable ?? (() => false);
|
|
1718
|
-
}
|
|
1719
|
-
}
|
|
1720
|
-
Object.defineProperty(StaticOptions, Symbol.for("dunx.deps"), {
|
|
1721
|
-
value: () => [{ unresolved: "init: StaticOptionsInit" }]
|
|
1722
|
-
});
|
|
1723
|
-
var normalizePrefix = (path) => {
|
|
1724
|
-
const trimmed = path.split("/").filter(Boolean).join("/");
|
|
1725
|
-
return trimmed === "" ? "/" : `/${trimmed}`;
|
|
1726
|
-
};
|
|
1727
|
-
|
|
1728
|
-
// src/static/files.ts
|
|
1729
797
|
class StaticFiles {
|
|
1730
798
|
#options;
|
|
1731
799
|
#root;
|
|
@@ -1777,9 +845,7 @@ class StaticFiles {
|
|
|
1777
845
|
});
|
|
1778
846
|
}
|
|
1779
847
|
}
|
|
1780
|
-
Object.defineProperty(StaticFiles, Symbol.for("dunx.deps"), {
|
|
1781
|
-
value: () => [StaticOptions]
|
|
1782
|
-
});
|
|
848
|
+
Object.defineProperty(StaticFiles, Symbol.for("dunx.deps"), { value: () => [StaticOptions] });
|
|
1783
849
|
// src/static/module.ts
|
|
1784
850
|
import {
|
|
1785
851
|
Module,
|
|
@@ -1824,101 +890,6 @@ StaticModule = __decorateElement(_init, 0, "StaticModule", _dec, StaticModule);
|
|
|
1824
890
|
__runInitializers(_init, 1, StaticModule);
|
|
1825
891
|
__decoratorMetadata(_init, StaticModule);
|
|
1826
892
|
let _StaticModule = StaticModule;
|
|
1827
|
-
// src/compression/negotiate.ts
|
|
1828
|
-
var quality = (params) => {
|
|
1829
|
-
for (const param of params) {
|
|
1830
|
-
const [key, value] = param.split("=");
|
|
1831
|
-
if (key?.trim().toLowerCase() !== "q")
|
|
1832
|
-
continue;
|
|
1833
|
-
const q = Number.parseFloat(value ?? "");
|
|
1834
|
-
return Number.isFinite(q) && q >= 0 && q <= 1 ? q : 1;
|
|
1835
|
-
}
|
|
1836
|
-
return 1;
|
|
1837
|
-
};
|
|
1838
|
-
var negotiate = (header, offered) => {
|
|
1839
|
-
if (header === null)
|
|
1840
|
-
return;
|
|
1841
|
-
const accepted = new Map;
|
|
1842
|
-
for (const element of header.split(",")) {
|
|
1843
|
-
const [name, ...params] = element.split(";");
|
|
1844
|
-
const token = name?.trim().toLowerCase();
|
|
1845
|
-
if (token === undefined || token === "")
|
|
1846
|
-
continue;
|
|
1847
|
-
accepted.set(token, quality(params));
|
|
1848
|
-
}
|
|
1849
|
-
const wildcard = accepted.get("*");
|
|
1850
|
-
let best;
|
|
1851
|
-
let bestQuality = 0;
|
|
1852
|
-
for (const encoding of offered) {
|
|
1853
|
-
const q = accepted.get(encoding) ?? wildcard ?? 0;
|
|
1854
|
-
if (q > bestQuality) {
|
|
1855
|
-
best = encoding;
|
|
1856
|
-
bestQuality = q;
|
|
1857
|
-
}
|
|
1858
|
-
}
|
|
1859
|
-
return best;
|
|
1860
|
-
};
|
|
1861
|
-
|
|
1862
|
-
// src/compression/options.ts
|
|
1863
|
-
var CompressionEncoding = Object.freeze({
|
|
1864
|
-
ZSTD: "zstd",
|
|
1865
|
-
GZIP: "gzip"
|
|
1866
|
-
});
|
|
1867
|
-
var COMPRESSIBLE = new Set([
|
|
1868
|
-
"application/graphql",
|
|
1869
|
-
"application/graphql-response+json",
|
|
1870
|
-
"application/javascript",
|
|
1871
|
-
"application/json",
|
|
1872
|
-
"application/manifest+json",
|
|
1873
|
-
"application/wasm",
|
|
1874
|
-
"application/x-javascript",
|
|
1875
|
-
"application/x-ndjson",
|
|
1876
|
-
"application/xml",
|
|
1877
|
-
"image/svg+xml"
|
|
1878
|
-
]);
|
|
1879
|
-
var isCompressibleType = (contentType) => {
|
|
1880
|
-
if (contentType === null)
|
|
1881
|
-
return false;
|
|
1882
|
-
const type = contentType.split(";")[0]?.trim().toLowerCase() ?? "";
|
|
1883
|
-
if (type.startsWith("text/"))
|
|
1884
|
-
return true;
|
|
1885
|
-
if (type.endsWith("+json") || type.endsWith("+xml"))
|
|
1886
|
-
return true;
|
|
1887
|
-
return COMPRESSIBLE.has(type);
|
|
1888
|
-
};
|
|
1889
|
-
var encodable = (encoding) => {
|
|
1890
|
-
const sync = encoding === CompressionEncoding.ZSTD ? Bun.zstdCompressSync : Bun.gzipSync;
|
|
1891
|
-
if (typeof sync !== "function")
|
|
1892
|
-
return false;
|
|
1893
|
-
try {
|
|
1894
|
-
new CompressionStream(encoding);
|
|
1895
|
-
return true;
|
|
1896
|
-
} catch {
|
|
1897
|
-
return false;
|
|
1898
|
-
}
|
|
1899
|
-
};
|
|
1900
|
-
|
|
1901
|
-
class CompressionOptions {
|
|
1902
|
-
encodings;
|
|
1903
|
-
threshold;
|
|
1904
|
-
filter;
|
|
1905
|
-
constructor(init = {}) {
|
|
1906
|
-
this.encodings = init.encodings ?? [
|
|
1907
|
-
CompressionEncoding.ZSTD,
|
|
1908
|
-
CompressionEncoding.GZIP
|
|
1909
|
-
];
|
|
1910
|
-
const missing = this.encodings.filter((encoding) => !encodable(encoding));
|
|
1911
|
-
if (missing.length > 0) {
|
|
1912
|
-
throw new Error(`Bun ${Bun.version} cannot encode ${missing.join(", ")}. ` + "Pass `encodings` without it, or upgrade Bun.");
|
|
1913
|
-
}
|
|
1914
|
-
this.threshold = init.threshold ?? 1024;
|
|
1915
|
-
this.filter = init.filter ?? isCompressibleType;
|
|
1916
|
-
}
|
|
1917
|
-
}
|
|
1918
|
-
Object.defineProperty(CompressionOptions, Symbol.for("dunx.deps"), {
|
|
1919
|
-
value: () => [{ unresolved: "init: CompressionOptionsInit = {}" }]
|
|
1920
|
-
});
|
|
1921
|
-
|
|
1922
893
|
// src/compression/compression.ts
|
|
1923
894
|
var BODYLESS = new Set([204, 205, 304]);
|
|
1924
895
|
var BUFFER_LIMIT = 1024 * 1024;
|
|
@@ -2045,9 +1016,7 @@ class Compression {
|
|
|
2045
1016
|
});
|
|
2046
1017
|
}
|
|
2047
1018
|
}
|
|
2048
|
-
Object.defineProperty(Compression, Symbol.for("dunx.deps"), {
|
|
2049
|
-
value: () => [CompressionOptions]
|
|
2050
|
-
});
|
|
1019
|
+
Object.defineProperty(Compression, Symbol.for("dunx.deps"), { value: () => [CompressionOptions] });
|
|
2051
1020
|
// src/compression/module.ts
|
|
2052
1021
|
import {
|
|
2053
1022
|
Module as Module2,
|
|
@@ -2101,7 +1070,7 @@ var SkipThrottle = () => meta(SKIP_THROTTLE, true);
|
|
|
2101
1070
|
import { Logger as Logger5 } from "@dunx/core";
|
|
2102
1071
|
|
|
2103
1072
|
// src/throttle/options.ts
|
|
2104
|
-
import { AppError as
|
|
1073
|
+
import { AppError as AppError5 } from "@dunx/core";
|
|
2105
1074
|
|
|
2106
1075
|
class ThrottleOptions {
|
|
2107
1076
|
limit;
|
|
@@ -2112,13 +1081,13 @@ class ThrottleOptions {
|
|
|
2112
1081
|
store;
|
|
2113
1082
|
constructor(init) {
|
|
2114
1083
|
if (init.prefix.trim() === "") {
|
|
2115
|
-
throw new
|
|
1084
|
+
throw new AppError5("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' }.");
|
|
2116
1085
|
}
|
|
2117
1086
|
if (!Number.isInteger(init.limit) || init.limit < 1) {
|
|
2118
|
-
throw new
|
|
1087
|
+
throw new AppError5(`ThrottleModule needs a limit of at least 1; got ${init.limit}.`);
|
|
2119
1088
|
}
|
|
2120
1089
|
if (!Number.isInteger(init.windowSeconds) || init.windowSeconds < 1) {
|
|
2121
|
-
throw new
|
|
1090
|
+
throw new AppError5("ThrottleModule needs a windowSeconds of at least 1; got " + `${init.windowSeconds}.`);
|
|
2122
1091
|
}
|
|
2123
1092
|
this.limit = init.limit;
|
|
2124
1093
|
this.windowSeconds = init.windowSeconds;
|
|
@@ -2128,17 +1097,15 @@ class ThrottleOptions {
|
|
|
2128
1097
|
this.store = init.store;
|
|
2129
1098
|
}
|
|
2130
1099
|
}
|
|
2131
|
-
Object.defineProperty(ThrottleOptions, Symbol.for("dunx.deps"), {
|
|
2132
|
-
value: () => [{ unresolved: "init: ThrottleOptionsInit" }]
|
|
2133
|
-
});
|
|
1100
|
+
Object.defineProperty(ThrottleOptions, Symbol.for("dunx.deps"), { value: () => [{ unresolved: "init: ThrottleOptionsInit" }] });
|
|
2134
1101
|
|
|
2135
1102
|
// src/throttle/store.ts
|
|
2136
|
-
import { AppError as
|
|
1103
|
+
import { AppError as AppError6 } from "@dunx/core";
|
|
2137
1104
|
|
|
2138
1105
|
class ThrottleStore {
|
|
2139
1106
|
constructor() {
|
|
2140
1107
|
if (new.target === ThrottleStore) {
|
|
2141
|
-
throw new
|
|
1108
|
+
throw new AppError6("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.");
|
|
2142
1109
|
}
|
|
2143
1110
|
}
|
|
2144
1111
|
}
|
|
@@ -2160,9 +1127,7 @@ class RedisThrottleStore extends ThrottleStore {
|
|
|
2160
1127
|
return left > 0 ? left : undefined;
|
|
2161
1128
|
}
|
|
2162
1129
|
}
|
|
2163
|
-
Object.defineProperty(RedisThrottleStore, Symbol.for("dunx.deps"), {
|
|
2164
|
-
value: () => [{ unresolved: "private readonly redis: ThrottleRedis" }]
|
|
2165
|
-
});
|
|
1130
|
+
Object.defineProperty(RedisThrottleStore, Symbol.for("dunx.deps"), { value: () => [{ unresolved: "private readonly redis: ThrottleRedis" }] });
|
|
2166
1131
|
|
|
2167
1132
|
class MemoryThrottleStore extends ThrottleStore {
|
|
2168
1133
|
#windows = new Map;
|
|
@@ -2199,9 +1164,7 @@ class MemoryThrottleStore extends ThrottleStore {
|
|
|
2199
1164
|
this.#windows.clear();
|
|
2200
1165
|
}
|
|
2201
1166
|
}
|
|
2202
|
-
Object.defineProperty(MemoryThrottleStore, Symbol.for("dunx.deps"), {
|
|
2203
|
-
value: () => [{ unresolved: "maxKeys = 10_000" }]
|
|
2204
|
-
});
|
|
1167
|
+
Object.defineProperty(MemoryThrottleStore, Symbol.for("dunx.deps"), { value: () => [{ unresolved: "maxKeys = 10_000", optional: true }] });
|
|
2205
1168
|
|
|
2206
1169
|
// src/throttle/guard.ts
|
|
2207
1170
|
class ThrottleGuard {
|
|
@@ -2271,9 +1234,7 @@ class ThrottleGuard {
|
|
|
2271
1234
|
this.logger.warn("The rate limiter is unreachable, so requests are not being counted.", { reason: error.message });
|
|
2272
1235
|
}
|
|
2273
1236
|
}
|
|
2274
|
-
Object.defineProperty(ThrottleGuard, Symbol.for("dunx.deps"), {
|
|
2275
|
-
value: () => [ThrottleOptions, ThrottleStore, ClientAddress, Logger5]
|
|
2276
|
-
});
|
|
1237
|
+
Object.defineProperty(ThrottleGuard, Symbol.for("dunx.deps"), { value: () => [ThrottleOptions, ThrottleStore, ClientAddress, Logger5] });
|
|
2277
1238
|
// src/throttle/module.ts
|
|
2278
1239
|
import {
|
|
2279
1240
|
Logger as Logger6,
|
|
@@ -2347,99 +1308,6 @@ var OnMessage = (event) => (value) => {
|
|
|
2347
1308
|
markHandler(value, { kind: HandlerKind.MESSAGE, event });
|
|
2348
1309
|
return value;
|
|
2349
1310
|
};
|
|
2350
|
-
// src/ws/redis-relay.ts
|
|
2351
|
-
import { AppError as AppError11 } from "@dunx/core";
|
|
2352
|
-
var PROTOCOLS = [
|
|
2353
|
-
"redis:",
|
|
2354
|
-
"rediss:",
|
|
2355
|
-
"valkey:",
|
|
2356
|
-
"valkeys:",
|
|
2357
|
-
"redis+tls:",
|
|
2358
|
-
"redis+unix:",
|
|
2359
|
-
"redis+tls+unix:"
|
|
2360
|
-
];
|
|
2361
|
-
var defaultRelayUrl = () => process.env["VALKEY_URL"] ?? process.env["REDIS_URL"] ?? "redis://localhost:6379";
|
|
2362
|
-
var assertUrl = (url) => {
|
|
2363
|
-
let parsed;
|
|
2364
|
-
try {
|
|
2365
|
-
parsed = new URL(url);
|
|
2366
|
-
} catch {
|
|
2367
|
-
throw new AppError11(`${JSON.stringify(url)} is not a valid URL for the websocket relay. ` + "Expected something like redis://localhost:6379.");
|
|
2368
|
-
}
|
|
2369
|
-
if (!PROTOCOLS.includes(parsed.protocol)) {
|
|
2370
|
-
throw new AppError11(`Unsupported protocol ${JSON.stringify(parsed.protocol)} in ` + `${JSON.stringify(url)}. Expected one of ${PROTOCOLS.join(", ")}.`);
|
|
2371
|
-
}
|
|
2372
|
-
return url;
|
|
2373
|
-
};
|
|
2374
|
-
|
|
2375
|
-
class RedisRelay {
|
|
2376
|
-
#url;
|
|
2377
|
-
#options;
|
|
2378
|
-
#pub;
|
|
2379
|
-
#sub;
|
|
2380
|
-
#channel;
|
|
2381
|
-
constructor(options = {}) {
|
|
2382
|
-
this.#url = assertUrl(options.url ?? defaultRelayUrl());
|
|
2383
|
-
this.#options = {
|
|
2384
|
-
maxRetries: options.maxRetries ?? 0,
|
|
2385
|
-
...options.connectionTimeout !== undefined && {
|
|
2386
|
-
connectionTimeout: options.connectionTimeout
|
|
2387
|
-
},
|
|
2388
|
-
...options.tls !== undefined && { tls: options.tls }
|
|
2389
|
-
};
|
|
2390
|
-
}
|
|
2391
|
-
get url() {
|
|
2392
|
-
const parsed = new URL(this.#url);
|
|
2393
|
-
if (parsed.password)
|
|
2394
|
-
parsed.password = "***";
|
|
2395
|
-
return parsed.toString();
|
|
2396
|
-
}
|
|
2397
|
-
async publish(channel, message) {
|
|
2398
|
-
const client = this.#pub ??= new Bun.RedisClient(this.#url, this.#options);
|
|
2399
|
-
try {
|
|
2400
|
-
return await client.publish(channel, message);
|
|
2401
|
-
} catch (error) {
|
|
2402
|
-
if (this.#pub === client) {
|
|
2403
|
-
this.#pub = undefined;
|
|
2404
|
-
client.close();
|
|
2405
|
-
}
|
|
2406
|
-
throw error;
|
|
2407
|
-
}
|
|
2408
|
-
}
|
|
2409
|
-
async subscribe(channel, listener) {
|
|
2410
|
-
const client = this.#sub ??= new Bun.RedisClient(this.#url, this.#options);
|
|
2411
|
-
try {
|
|
2412
|
-
await client.connect();
|
|
2413
|
-
await client.subscribe(channel, listener);
|
|
2414
|
-
this.#channel = channel;
|
|
2415
|
-
} catch (error) {
|
|
2416
|
-
if (this.#sub === client) {
|
|
2417
|
-
this.#sub = undefined;
|
|
2418
|
-
client.close();
|
|
2419
|
-
}
|
|
2420
|
-
throw error;
|
|
2421
|
-
}
|
|
2422
|
-
}
|
|
2423
|
-
async close() {
|
|
2424
|
-
const sub = this.#sub;
|
|
2425
|
-
const channel = this.#channel;
|
|
2426
|
-
this.#pub?.close();
|
|
2427
|
-
this.#pub = undefined;
|
|
2428
|
-
this.#sub = undefined;
|
|
2429
|
-
this.#channel = undefined;
|
|
2430
|
-
if (!sub)
|
|
2431
|
-
return;
|
|
2432
|
-
if (channel !== undefined) {
|
|
2433
|
-
try {
|
|
2434
|
-
await sub.unsubscribe(channel);
|
|
2435
|
-
} catch {}
|
|
2436
|
-
}
|
|
2437
|
-
sub.close();
|
|
2438
|
-
}
|
|
2439
|
-
}
|
|
2440
|
-
Object.defineProperty(RedisRelay, Symbol.for("dunx.deps"), {
|
|
2441
|
-
value: () => [{ unresolved: "options: RedisRelayOptions = {}" }]
|
|
2442
|
-
});
|
|
2443
1311
|
// src/health/contracts.ts
|
|
2444
1312
|
class HealthIndicator {
|
|
2445
1313
|
critical = true;
|
|
@@ -2450,205 +1318,6 @@ class PingProbe {
|
|
|
2450
1318
|
|
|
2451
1319
|
class QueryProbe {
|
|
2452
1320
|
}
|
|
2453
|
-
// src/health/controller.ts
|
|
2454
|
-
import { inject } from "@dunx/core";
|
|
2455
|
-
|
|
2456
|
-
// src/health/report-schema.ts
|
|
2457
|
-
var state = {
|
|
2458
|
-
type: "string",
|
|
2459
|
-
enum: ["up", "down", "unknown"],
|
|
2460
|
-
description: "`unknown` is not `down`: a probe that timed out has told you nothing."
|
|
2461
|
-
};
|
|
2462
|
-
var HEALTH_REPORT_SCHEMA = Object.freeze({
|
|
2463
|
-
$id: "HealthReport",
|
|
2464
|
-
type: "object",
|
|
2465
|
-
description: "What the probe found. `up` answers 200 and anything else answers 503.",
|
|
2466
|
-
properties: {
|
|
2467
|
-
status: state,
|
|
2468
|
-
draining: {
|
|
2469
|
-
type: "boolean",
|
|
2470
|
-
description: "The process is shutting down, or something holds it out."
|
|
2471
|
-
},
|
|
2472
|
-
uptimeMs: {
|
|
2473
|
-
type: "integer",
|
|
2474
|
-
description: "Measured on a monotonic clock, so it never goes backwards."
|
|
2475
|
-
},
|
|
2476
|
-
checks: {
|
|
2477
|
-
type: "array",
|
|
2478
|
-
items: {
|
|
2479
|
-
type: "object",
|
|
2480
|
-
properties: {
|
|
2481
|
-
name: { type: "string" },
|
|
2482
|
-
state,
|
|
2483
|
-
critical: {
|
|
2484
|
-
type: "boolean",
|
|
2485
|
-
description: "A failure here sheds traffic. Memory and disk do not."
|
|
2486
|
-
},
|
|
2487
|
-
ms: { type: "integer", description: "How long the check took." },
|
|
2488
|
-
detail: {
|
|
2489
|
-
type: "string",
|
|
2490
|
-
description: "A latency, a version, or a failure message."
|
|
2491
|
-
}
|
|
2492
|
-
},
|
|
2493
|
-
required: ["name", "state", "critical", "ms"]
|
|
2494
|
-
}
|
|
2495
|
-
}
|
|
2496
|
-
},
|
|
2497
|
-
required: ["status", "draining", "uptimeMs", "checks"]
|
|
2498
|
-
});
|
|
2499
|
-
|
|
2500
|
-
// src/health/registry.ts
|
|
2501
|
-
var bounded = async (indicator, timeoutMs) => {
|
|
2502
|
-
let timer;
|
|
2503
|
-
const timeout = new Promise((resolve2) => {
|
|
2504
|
-
timer = setTimeout(() => resolve2({ state: "unknown", detail: `no answer in ${timeoutMs} ms` }), timeoutMs);
|
|
2505
|
-
timer.unref?.();
|
|
2506
|
-
});
|
|
2507
|
-
try {
|
|
2508
|
-
return await Promise.race([
|
|
2509
|
-
Promise.resolve().then(() => indicator.check()).catch((error) => ({
|
|
2510
|
-
state: "down",
|
|
2511
|
-
detail: error instanceof Error ? error.message : String(error)
|
|
2512
|
-
})),
|
|
2513
|
-
timeout
|
|
2514
|
-
]);
|
|
2515
|
-
} finally {
|
|
2516
|
-
if (timer)
|
|
2517
|
-
clearTimeout(timer);
|
|
2518
|
-
}
|
|
2519
|
-
};
|
|
2520
|
-
var worst = (checks) => {
|
|
2521
|
-
const critical = checks.filter((check) => check.critical);
|
|
2522
|
-
if (critical.some((check) => check.state === "down"))
|
|
2523
|
-
return "down";
|
|
2524
|
-
if (critical.some((check) => check.state === "unknown"))
|
|
2525
|
-
return "unknown";
|
|
2526
|
-
return "up";
|
|
2527
|
-
};
|
|
2528
|
-
|
|
2529
|
-
class HealthOptions {
|
|
2530
|
-
liveness;
|
|
2531
|
-
readiness;
|
|
2532
|
-
timeoutMs;
|
|
2533
|
-
routes;
|
|
2534
|
-
documented;
|
|
2535
|
-
drainDelayMs;
|
|
2536
|
-
constructor(init = {}) {
|
|
2537
|
-
this.liveness = init.liveness ?? [];
|
|
2538
|
-
this.readiness = init.readiness ?? [];
|
|
2539
|
-
this.timeoutMs = init.timeoutMs ?? 2000;
|
|
2540
|
-
this.routes = init.routes ?? true;
|
|
2541
|
-
this.documented = init.documented ?? true;
|
|
2542
|
-
this.drainDelayMs = Math.max(0, init.drainDelayMs ?? 0);
|
|
2543
|
-
}
|
|
2544
|
-
}
|
|
2545
|
-
Object.defineProperty(HealthOptions, Symbol.for("dunx.deps"), {
|
|
2546
|
-
value: () => [{ unresolved: "init: HealthOptionsInit = {}" }]
|
|
2547
|
-
});
|
|
2548
|
-
|
|
2549
|
-
class HealthRegistry {
|
|
2550
|
-
options;
|
|
2551
|
-
readiness_;
|
|
2552
|
-
#startedAt = performance.now();
|
|
2553
|
-
constructor(options, readiness_) {
|
|
2554
|
-
this.options = options;
|
|
2555
|
-
this.readiness_ = readiness_;
|
|
2556
|
-
}
|
|
2557
|
-
async report(indicators) {
|
|
2558
|
-
const checks = await Promise.all(indicators.map(async (indicator) => {
|
|
2559
|
-
const started = performance.now();
|
|
2560
|
-
const result = await bounded(indicator, this.options.timeoutMs);
|
|
2561
|
-
return {
|
|
2562
|
-
name: indicator.name,
|
|
2563
|
-
state: result.state,
|
|
2564
|
-
critical: indicator.critical,
|
|
2565
|
-
ms: Math.round(performance.now() - started),
|
|
2566
|
-
...result.detail === undefined ? {} : { detail: result.detail }
|
|
2567
|
-
};
|
|
2568
|
-
}));
|
|
2569
|
-
return {
|
|
2570
|
-
status: worst(checks),
|
|
2571
|
-
draining: this.readiness_.draining,
|
|
2572
|
-
uptimeMs: Math.round(performance.now() - this.#startedAt),
|
|
2573
|
-
checks
|
|
2574
|
-
};
|
|
2575
|
-
}
|
|
2576
|
-
liveness() {
|
|
2577
|
-
return this.report(this.options.liveness);
|
|
2578
|
-
}
|
|
2579
|
-
async readiness() {
|
|
2580
|
-
const report = await this.report(this.options.readiness);
|
|
2581
|
-
if (!this.readiness_.draining)
|
|
2582
|
-
return report;
|
|
2583
|
-
return {
|
|
2584
|
-
...report,
|
|
2585
|
-
status: "down",
|
|
2586
|
-
checks: [
|
|
2587
|
-
{
|
|
2588
|
-
name: "readiness",
|
|
2589
|
-
state: "down",
|
|
2590
|
-
critical: true,
|
|
2591
|
-
ms: 0,
|
|
2592
|
-
detail: this.readiness_.reason ?? "not accepting traffic"
|
|
2593
|
-
},
|
|
2594
|
-
...report.checks
|
|
2595
|
-
]
|
|
2596
|
-
};
|
|
2597
|
-
}
|
|
2598
|
-
}
|
|
2599
|
-
Object.defineProperty(HealthRegistry, Symbol.for("dunx.deps"), {
|
|
2600
|
-
value: () => [HealthOptions, { unresolved: "private readonly readiness_: Readiness", typeOnly: "Readiness" }]
|
|
2601
|
-
});
|
|
2602
|
-
|
|
2603
|
-
// src/health/controller.ts
|
|
2604
|
-
var probeResponses = {
|
|
2605
|
-
response: { 200: HEALTH_REPORT_SCHEMA, 503: HEALTH_REPORT_SCHEMA }
|
|
2606
|
-
};
|
|
2607
|
-
var answer = (report) => Response.json(report, { status: report.status === "up" ? 200 : 503 });
|
|
2608
|
-
var _dec = [
|
|
2609
|
-
Controller("health")
|
|
2610
|
-
];
|
|
2611
|
-
var _dec2 = [
|
|
2612
|
-
Public(),
|
|
2613
|
-
Get("/live", probeResponses)
|
|
2614
|
-
];
|
|
2615
|
-
var _dec3 = [
|
|
2616
|
-
Public(),
|
|
2617
|
-
Get("/ready", probeResponses)
|
|
2618
|
-
];
|
|
2619
|
-
var _health = new WeakMap;
|
|
2620
|
-
var _init = __decoratorStart(undefined);
|
|
2621
|
-
|
|
2622
|
-
class HealthController {
|
|
2623
|
-
constructor() {
|
|
2624
|
-
__privateAdd(this, _health, inject(HealthRegistry));
|
|
2625
|
-
__runInitializers(_init, 5, this);
|
|
2626
|
-
}
|
|
2627
|
-
async live() {
|
|
2628
|
-
return answer(await __privateGet(this, _health).liveness());
|
|
2629
|
-
}
|
|
2630
|
-
async ready() {
|
|
2631
|
-
return answer(await __privateGet(this, _health).readiness());
|
|
2632
|
-
}
|
|
2633
|
-
}
|
|
2634
|
-
__decorateElement(_init, 1, "live", _dec2, HealthController);
|
|
2635
|
-
__decorateElement(_init, 1, "ready", _dec3, HealthController);
|
|
2636
|
-
HealthController = __decorateElement(_init, 0, "HealthController", _dec, HealthController);
|
|
2637
|
-
__runInitializers(_init, 1, HealthController);
|
|
2638
|
-
__decoratorMetadata(_init, HealthController);
|
|
2639
|
-
let _HealthController = HealthController;
|
|
2640
|
-
var _dec = [
|
|
2641
|
-
ApiHidden()
|
|
2642
|
-
];
|
|
2643
|
-
var _base = HealthController;
|
|
2644
|
-
var _init = __decoratorStart(_base);
|
|
2645
|
-
|
|
2646
|
-
class HiddenHealthController extends _base {
|
|
2647
|
-
}
|
|
2648
|
-
HiddenHealthController = __decorateElement(_init, 0, "HiddenHealthController", _dec, HiddenHealthController);
|
|
2649
|
-
__runInitializers(_init, 1, HiddenHealthController);
|
|
2650
|
-
__decoratorMetadata(_init, HiddenHealthController);
|
|
2651
|
-
let _HiddenHealthController = HiddenHealthController;
|
|
2652
1321
|
// src/health/indicators.ts
|
|
2653
1322
|
import { statfs } from "fs/promises";
|
|
2654
1323
|
var ms = (started) => Math.round(performance.now() - started);
|
|
@@ -2666,9 +1335,7 @@ class RedisIndicator extends HealthIndicator {
|
|
|
2666
1335
|
return { state: "up", detail: `${ms(started)} ms` };
|
|
2667
1336
|
}
|
|
2668
1337
|
}
|
|
2669
|
-
Object.defineProperty(RedisIndicator, Symbol.for("dunx.deps"), {
|
|
2670
|
-
value: () => [{ unresolved: "private readonly redis: PingProbe", typeOnly: "PingProbe" }]
|
|
2671
|
-
});
|
|
1338
|
+
Object.defineProperty(RedisIndicator, Symbol.for("dunx.deps"), { value: () => [{ unresolved: "private readonly redis: PingProbe", typeOnly: "PingProbe" }] });
|
|
2672
1339
|
|
|
2673
1340
|
class DatabaseIndicator extends HealthIndicator {
|
|
2674
1341
|
db;
|
|
@@ -2683,9 +1350,7 @@ class DatabaseIndicator extends HealthIndicator {
|
|
|
2683
1350
|
return { state: "up", detail: `${ms(started)} ms` };
|
|
2684
1351
|
}
|
|
2685
1352
|
}
|
|
2686
|
-
Object.defineProperty(DatabaseIndicator, Symbol.for("dunx.deps"), {
|
|
2687
|
-
value: () => [{ unresolved: "private readonly db: QueryProbe", typeOnly: "QueryProbe" }]
|
|
2688
|
-
});
|
|
1353
|
+
Object.defineProperty(DatabaseIndicator, Symbol.for("dunx.deps"), { value: () => [{ unresolved: "private readonly db: QueryProbe", typeOnly: "QueryProbe" }] });
|
|
2689
1354
|
|
|
2690
1355
|
class MemoryOptions {
|
|
2691
1356
|
maxRssBytes;
|
|
@@ -2693,9 +1358,7 @@ class MemoryOptions {
|
|
|
2693
1358
|
this.maxRssBytes = init.maxRssBytes;
|
|
2694
1359
|
}
|
|
2695
1360
|
}
|
|
2696
|
-
Object.defineProperty(MemoryOptions, Symbol.for("dunx.deps"), {
|
|
2697
|
-
value: () => [{ unresolved: "init: MemoryOptionsInit" }]
|
|
2698
|
-
});
|
|
1361
|
+
Object.defineProperty(MemoryOptions, Symbol.for("dunx.deps"), { value: () => [{ unresolved: "init: MemoryOptionsInit" }] });
|
|
2699
1362
|
var MIB = 1024 * 1024;
|
|
2700
1363
|
var mib = (bytes) => `${Math.round(bytes / MIB)} MiB`;
|
|
2701
1364
|
|
|
@@ -2713,9 +1376,7 @@ class MemoryIndicator extends HealthIndicator {
|
|
|
2713
1376
|
return rss > this.options.maxRssBytes ? { state: "down", detail } : { state: "up", detail };
|
|
2714
1377
|
}
|
|
2715
1378
|
}
|
|
2716
|
-
Object.defineProperty(MemoryIndicator, Symbol.for("dunx.deps"), {
|
|
2717
|
-
value: () => [MemoryOptions]
|
|
2718
|
-
});
|
|
1379
|
+
Object.defineProperty(MemoryIndicator, Symbol.for("dunx.deps"), { value: () => [MemoryOptions] });
|
|
2719
1380
|
|
|
2720
1381
|
class DiskOptions {
|
|
2721
1382
|
path;
|
|
@@ -2725,9 +1386,7 @@ class DiskOptions {
|
|
|
2725
1386
|
this.maxUsedFraction = init.maxUsedFraction;
|
|
2726
1387
|
}
|
|
2727
1388
|
}
|
|
2728
|
-
Object.defineProperty(DiskOptions, Symbol.for("dunx.deps"), {
|
|
2729
|
-
value: () => [{ unresolved: "init: DiskOptionsInit" }]
|
|
2730
|
-
});
|
|
1389
|
+
Object.defineProperty(DiskOptions, Symbol.for("dunx.deps"), { value: () => [{ unresolved: "init: DiskOptionsInit" }] });
|
|
2731
1390
|
|
|
2732
1391
|
class DiskIndicator extends HealthIndicator {
|
|
2733
1392
|
options;
|
|
@@ -2748,9 +1407,7 @@ class DiskIndicator extends HealthIndicator {
|
|
|
2748
1407
|
return used > this.options.maxUsedFraction ? { state: "down", detail } : { state: "up", detail };
|
|
2749
1408
|
}
|
|
2750
1409
|
}
|
|
2751
|
-
Object.defineProperty(DiskIndicator, Symbol.for("dunx.deps"), {
|
|
2752
|
-
value: () => [DiskOptions]
|
|
2753
|
-
});
|
|
1410
|
+
Object.defineProperty(DiskIndicator, Symbol.for("dunx.deps"), { value: () => [DiskOptions] });
|
|
2754
1411
|
// src/health/module.ts
|
|
2755
1412
|
import {
|
|
2756
1413
|
Module as Module4,
|
|
@@ -2764,9 +1421,7 @@ class ReadinessOptions {
|
|
|
2764
1421
|
this.drainDelayMs = Math.max(0, init.drainDelayMs ?? 0);
|
|
2765
1422
|
}
|
|
2766
1423
|
}
|
|
2767
|
-
Object.defineProperty(ReadinessOptions, Symbol.for("dunx.deps"), {
|
|
2768
|
-
value: () => [{ unresolved: "init: ReadinessOptionsInit = {}" }]
|
|
2769
|
-
});
|
|
1424
|
+
Object.defineProperty(ReadinessOptions, Symbol.for("dunx.deps"), { value: () => [{ unresolved: "init: ReadinessOptionsInit = {}", optional: true }] });
|
|
2770
1425
|
|
|
2771
1426
|
class Readiness {
|
|
2772
1427
|
options;
|
|
@@ -2794,9 +1449,7 @@ class Readiness {
|
|
|
2794
1449
|
}
|
|
2795
1450
|
}
|
|
2796
1451
|
}
|
|
2797
|
-
Object.defineProperty(Readiness, Symbol.for("dunx.deps"), {
|
|
2798
|
-
value: () => [ReadinessOptions]
|
|
2799
|
-
});
|
|
1452
|
+
Object.defineProperty(Readiness, Symbol.for("dunx.deps"), { value: () => [ReadinessOptions] });
|
|
2800
1453
|
|
|
2801
1454
|
// src/health/module.ts
|
|
2802
1455
|
var wiring = (options) => [
|
|
@@ -2868,13 +1521,11 @@ export {
|
|
|
2868
1521
|
Get,
|
|
2869
1522
|
HEALTH_REPORT_SCHEMA,
|
|
2870
1523
|
HIDDEN,
|
|
2871
|
-
HandlerKind,
|
|
2872
1524
|
HealthController,
|
|
2873
1525
|
HealthIndicator,
|
|
2874
1526
|
HealthModule,
|
|
2875
1527
|
HealthOptions,
|
|
2876
1528
|
HealthRegistry,
|
|
2877
|
-
HiddenHealthController,
|
|
2878
1529
|
HttpError,
|
|
2879
1530
|
HttpFactory,
|
|
2880
1531
|
HttpStatusCode,
|
|
@@ -2923,43 +1574,10 @@ export {
|
|
|
2923
1574
|
UNMATCHED,
|
|
2924
1575
|
UseGuards,
|
|
2925
1576
|
ValidationError,
|
|
2926
|
-
assertNoCollisions,
|
|
2927
|
-
assertNoGatewayCollisions,
|
|
2928
|
-
buildContext,
|
|
2929
|
-
buildGateways,
|
|
2930
|
-
buildRoutes,
|
|
2931
|
-
buildRuntime,
|
|
2932
|
-
buildWebSocket,
|
|
2933
|
-
compose,
|
|
2934
|
-
composeSocket,
|
|
2935
|
-
decode,
|
|
2936
|
-
decodeRelay,
|
|
2937
1577
|
defaultErrorMapper,
|
|
2938
|
-
defaultRelayUrl,
|
|
2939
|
-
defaultStatusFor,
|
|
2940
|
-
discoverGateway,
|
|
2941
|
-
discoverGateways,
|
|
2942
|
-
discoverRoutes,
|
|
2943
|
-
encode,
|
|
2944
|
-
encodeRelay,
|
|
2945
1578
|
errorMapper,
|
|
2946
|
-
gatewaysOf,
|
|
2947
|
-
guardsOf,
|
|
2948
|
-
isCompressibleType,
|
|
2949
|
-
isErrorFilter,
|
|
2950
|
-
isGateway,
|
|
2951
|
-
joinPath,
|
|
2952
1579
|
mergeMeta,
|
|
2953
1580
|
meta,
|
|
2954
1581
|
metaKey,
|
|
2955
|
-
metaOf
|
|
2956
|
-
negotiate,
|
|
2957
|
-
normalizePath,
|
|
2958
|
-
normalizePrefix,
|
|
2959
|
-
observe,
|
|
2960
|
-
preflight,
|
|
2961
|
-
routesOf,
|
|
2962
|
-
toErrorMapper,
|
|
2963
|
-
withCors,
|
|
2964
|
-
withUpgradeRoutes
|
|
1582
|
+
metaOf
|
|
2965
1583
|
};
|