@interopio/gateway-server 0.14.0 → 0.15.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.cjs CHANGED
@@ -1,3313 +1,3 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/index.ts
31
- var index_exports = {};
32
- __export(index_exports, {
33
- GatewayServer: () => server_exports,
34
- default: () => index_default
35
- });
36
- module.exports = __toCommonJS(index_exports);
37
-
38
- // src/server.ts
39
- var server_exports = {};
40
- __export(server_exports, {
41
- Factory: () => Factory
42
- });
43
- var import_node_http2 = __toESM(require("node:http"), 1);
44
- var import_node_https = __toESM(require("node:https"), 1);
45
- var import_node_fs = require("node:fs");
46
- var import_node_async_hooks4 = require("node:async_hooks");
47
- var import_gateway6 = require("@interopio/gateway");
48
-
49
- // src/logger.ts
50
- var GatewayLogging = __toESM(require("@interopio/gateway/logging/core"), 1);
51
- function getLogger2(name) {
52
- return GatewayLogging.getLogger(`gateway.server.${name}`);
53
- }
54
- function regexAwareReplacer(_key, value) {
55
- return value instanceof RegExp ? value.toString() : value;
56
- }
57
-
58
- // src/gateway/ws/core.ts
59
- var import_gateway = require("@interopio/gateway");
60
- var import_node_async_hooks = require("node:async_hooks");
61
- var GatewayEncoders = import_gateway.IOGateway.Encoding;
62
- var log = getLogger2("ws");
63
- var codec = GatewayEncoders.json();
64
- function principalName(authentication) {
65
- let name;
66
- if (authentication.authenticated) {
67
- name = authentication.name;
68
- if (name === void 0) {
69
- if (authentication["principal"] !== void 0) {
70
- const principal = authentication["principal"];
71
- if (typeof principal === "object") {
72
- name = principal.name;
73
- }
74
- if (name === void 0) {
75
- if (principal === void 0) {
76
- name = "";
77
- } else {
78
- name = String(principal);
79
- }
80
- }
81
- }
82
- }
83
- }
84
- return name;
85
- }
86
- function initClient(socket, authenticationPromise, remoteAddress) {
87
- const key = `${remoteAddress?.address}:${remoteAddress?.port}`;
88
- const host = remoteAddress?.address ?? "<unknown>";
89
- const opts = {
90
- key,
91
- host,
92
- codec,
93
- onAuthenticate: async () => {
94
- const authentication = await authenticationPromise();
95
- if (authentication?.authenticated) {
96
- return { type: "success", user: principalName(authentication) };
97
- }
98
- throw new Error(`no valid client authentication ${key}`);
99
- },
100
- onPing: () => {
101
- socket.ping((err) => {
102
- if (err) {
103
- log.warn(`failed to ping ${key}`, err);
104
- } else {
105
- log.info(`ping sent to ${key}`);
106
- }
107
- });
108
- },
109
- onDisconnect: (reason) => {
110
- switch (reason) {
111
- case "inactive": {
112
- log.warn(`no heartbeat (ping) received from ${key}, closing socket`);
113
- socket.close(4001, "ping expected");
114
- break;
115
- }
116
- case "shutdown": {
117
- socket.close(1001, "shutdown");
118
- break;
119
- }
120
- }
121
- }
122
- };
123
- try {
124
- return this.client((data) => socket.send(data), opts);
125
- } catch (err) {
126
- log.warn(`${key} failed to create client`, err);
127
- }
128
- }
129
- async function create(environment) {
130
- log.info(`starting gateway on ${environment.endpoint}`);
131
- await this.start(environment);
132
- return async ({ socket, handshake }) => {
133
- const { logPrefix, remoteAddress, principal: principalPromise } = handshake;
134
- log.info(`${logPrefix}connected on gw using ${remoteAddress?.address}`);
135
- const client = initClient.call(this, socket, principalPromise, remoteAddress);
136
- if (!client) {
137
- log.error(`${logPrefix}gw client init failed`);
138
- socket.terminate();
139
- return;
140
- }
141
- socket.on("error", (err) => {
142
- log.error(`${logPrefix}websocket error: ${err}`, err);
143
- });
144
- const contextFn = environment.storage !== void 0 ? import_node_async_hooks.AsyncLocalStorage.snapshot() : void 0;
145
- socket.on("message", (data, _isBinary) => {
146
- if (Array.isArray(data)) {
147
- data = Buffer.concat(data);
148
- }
149
- if (contextFn !== void 0) {
150
- contextFn(() => client.send(data));
151
- } else {
152
- client.send(data);
153
- }
154
- });
155
- socket.on("close", (code) => {
156
- log.info(`${logPrefix}disconnected from gw. code: ${code}`);
157
- client.close();
158
- });
159
- };
160
- }
161
- var core_default = create;
162
-
163
- // src/common/compose.ts
164
- function compose(...middleware) {
165
- if (!Array.isArray(middleware)) {
166
- throw new Error("middleware must be array!");
167
- }
168
- const fns = middleware.flat();
169
- for (const fn of fns) {
170
- if (typeof fn !== "function") {
171
- throw new Error("middleware must be compose of functions!");
172
- }
173
- }
174
- return async function(ctx, next) {
175
- const dispatch = async (i, dispatchedCtx) => {
176
- const fn = i === fns.length ? next : fns[i];
177
- if (fn === void 0) {
178
- return;
179
- }
180
- let nextCalled = false;
181
- let nextResolved = false;
182
- const nextFn = async (nextCtx) => {
183
- if (nextCalled) {
184
- throw new Error("next() called multiple times");
185
- }
186
- nextCalled = true;
187
- try {
188
- return await dispatch(i + 1, nextCtx ?? dispatchedCtx);
189
- } finally {
190
- nextResolved = true;
191
- }
192
- };
193
- const result = await fn(dispatchedCtx, nextFn);
194
- if (nextCalled && !nextResolved) {
195
- throw new Error("middleware resolved before downstream.\n You are probably missing an await or return statement in your middleware function.");
196
- }
197
- return result;
198
- };
199
- return dispatch(0, ctx);
200
- };
201
- }
202
-
203
- // src/http/exchange.ts
204
- var import_tough_cookie = require("tough-cookie");
205
- function parseHost(headers2, defaultHost) {
206
- let host = headers2.get("x-forwarded-for");
207
- if (host === void 0) {
208
- host = headers2.get("x-forwarded-host");
209
- if (Array.isArray(host)) {
210
- host = host[0];
211
- }
212
- if (host) {
213
- const port = headers2.one("x-forwarded-port");
214
- if (port) {
215
- host = `${host}:${port}`;
216
- }
217
- }
218
- host ??= headers2.one("host");
219
- }
220
- if (Array.isArray(host)) {
221
- host = host[0];
222
- }
223
- if (host) {
224
- return host.split(",", 1)[0].trim();
225
- }
226
- return defaultHost;
227
- }
228
- function parseProtocol(headers2, defaultProtocol) {
229
- let proto = headers2.get("x-forwarded-proto");
230
- if (Array.isArray(proto)) {
231
- proto = proto[0];
232
- }
233
- if (proto !== void 0) {
234
- return proto.split(",", 1)[0].trim();
235
- }
236
- return defaultProtocol;
237
- }
238
- var AbstractHttpMessage = class {
239
- #headers;
240
- constructor(headers2) {
241
- this.#headers = headers2;
242
- }
243
- get headers() {
244
- return this.#headers;
245
- }
246
- };
247
- var AbstractHttpRequest = class _AbstractHttpRequest extends AbstractHttpMessage {
248
- static logIdCounter = 0;
249
- #id;
250
- get id() {
251
- if (this.#id === void 0) {
252
- this.#id = `${this.initId()}-${++_AbstractHttpRequest.logIdCounter}`;
253
- }
254
- return this.#id;
255
- }
256
- initId() {
257
- return "request";
258
- }
259
- get cookies() {
260
- return parseCookies(this.headers);
261
- }
262
- parseHost(defaultHost) {
263
- return parseHost(this.headers, defaultHost);
264
- }
265
- parseProtocol(defaultProtocol) {
266
- return parseProtocol(this.headers, defaultProtocol);
267
- }
268
- };
269
- var AbstractHttpResponse = class extends AbstractHttpMessage {
270
- get cookies() {
271
- return parseResponseCookies(this.headers);
272
- }
273
- setCookieValue(responseCookie) {
274
- const cookie = new import_tough_cookie.Cookie({
275
- key: responseCookie.name,
276
- value: responseCookie.value,
277
- maxAge: responseCookie.maxAge,
278
- domain: responseCookie.domain,
279
- path: responseCookie.path,
280
- secure: responseCookie.secure,
281
- httpOnly: responseCookie.httpOnly,
282
- sameSite: responseCookie.sameSite
283
- });
284
- return cookie.toString();
285
- }
286
- };
287
- function parseHeader(value) {
288
- const list = [];
289
- {
290
- let start2 = 0;
291
- let end = 0;
292
- for (let i = 0; i < value.length; i++) {
293
- switch (value.charCodeAt(i)) {
294
- case 32:
295
- if (start2 === end) {
296
- start2 = end = i + 1;
297
- }
298
- break;
299
- case 44:
300
- list.push(value.slice(start2, end));
301
- start2 = end = i + 1;
302
- break;
303
- default:
304
- end = end + 1;
305
- break;
306
- }
307
- }
308
- list.push(value.slice(start2, end));
309
- }
310
- return list;
311
- }
312
- function toList(values) {
313
- if (typeof values === "string") {
314
- values = [values];
315
- }
316
- if (typeof values === "number") {
317
- values = [String(values)];
318
- }
319
- const list = [];
320
- if (values) {
321
- for (const value of values) {
322
- if (value) {
323
- list.push(...parseHeader(value));
324
- }
325
- }
326
- }
327
- return list;
328
- }
329
- function parseCookies(headers2) {
330
- return headers2.list("cookie").map((s) => s.split(";").map((cs) => import_tough_cookie.Cookie.parse(cs))).flat(1).filter((tc) => tc !== void 0).map((tc) => {
331
- const result = Object.freeze({ name: tc.key, value: tc.value });
332
- return result;
333
- });
334
- }
335
- function parseResponseCookies(headers2) {
336
- return headers2.list("set-cookie").map((cookie) => {
337
- const parsed = import_tough_cookie.Cookie.parse(cookie);
338
- if (parsed) {
339
- const result = { name: parsed.key, value: parsed.value, maxAge: Number(parsed.maxAge ?? -1) };
340
- if (parsed.httpOnly) result.httpOnly = true;
341
- if (parsed.domain) result.domain = parsed.domain;
342
- if (parsed.path) result.path = parsed.path;
343
- if (parsed.secure) result.secure = true;
344
- if (parsed.httpOnly) result.httpOnly = true;
345
- if (parsed.sameSite) result.sameSite = parsed.sameSite;
346
- return Object.freeze(result);
347
- }
348
- }).filter((cookie) => cookie !== void 0);
349
- }
350
- var AbstractHttpHeaders = class {
351
- constructor() {
352
- }
353
- toList(name) {
354
- const values = this.get(name);
355
- return toList(values);
356
- }
357
- };
358
- var MapHttpHeaders = class extends Map {
359
- get(name) {
360
- return super.get(name.toLowerCase());
361
- }
362
- one(name) {
363
- return this.get(name)?.[0];
364
- }
365
- list(name) {
366
- const values = super.get(name.toLowerCase());
367
- return toList(values);
368
- }
369
- set(name, value) {
370
- if (typeof value === "number") {
371
- value = String(value);
372
- }
373
- if (typeof value === "string") {
374
- value = [value];
375
- }
376
- if (value) {
377
- return super.set(name.toLowerCase(), value);
378
- } else {
379
- super.delete(name.toLowerCase());
380
- return this;
381
- }
382
- }
383
- add(name, value) {
384
- const prev = super.get(name.toLowerCase());
385
- if (typeof value === "string") {
386
- value = [value];
387
- }
388
- if (prev) {
389
- value = prev.concat(value);
390
- }
391
- this.set(name, value);
392
- return this;
393
- }
394
- };
395
-
396
- // src/http/status.ts
397
- var DefaultHttpStatusCode = class {
398
- #value;
399
- constructor(value) {
400
- this.#value = value;
401
- }
402
- get value() {
403
- return this.#value;
404
- }
405
- toString() {
406
- return this.#value.toString();
407
- }
408
- };
409
- var HttpStatus = class _HttpStatus {
410
- static CONTINUE = new _HttpStatus(100, "Continue");
411
- static SWITCHING_PROTOCOLS = new _HttpStatus(101, "Switching Protocols");
412
- // 2xx Success
413
- static OK = new _HttpStatus(200, "OK");
414
- static CREATED = new _HttpStatus(201, "Created");
415
- static ACCEPTED = new _HttpStatus(202, "Accepted");
416
- static NON_AUTHORITATIVE_INFORMATION = new _HttpStatus(203, "Non-Authoritative Information");
417
- static NO_CONTENT = new _HttpStatus(204, "No Content");
418
- static RESET_CONTENT = new _HttpStatus(205, "Reset Content");
419
- static PARTIAL_CONTENT = new _HttpStatus(206, "Partial Content");
420
- static MULTI_STATUS = new _HttpStatus(207, "Multi-Status");
421
- static IM_USED = new _HttpStatus(226, "IM Used");
422
- // 3xx Redirection
423
- static MULTIPLE_CHOICES = new _HttpStatus(300, "Multiple Choices");
424
- static MOVED_PERMANENTLY = new _HttpStatus(301, "Moved Permanently");
425
- // 4xx Client Error
426
- static BAD_REQUEST = new _HttpStatus(400, "Bad Request");
427
- static UNAUTHORIZED = new _HttpStatus(401, "Unauthorized");
428
- static FORBIDDEN = new _HttpStatus(403, "Forbidden");
429
- static NOT_FOUND = new _HttpStatus(404, "Not Found");
430
- static METHOD_NOT_ALLOWED = new _HttpStatus(405, "Method Not Allowed");
431
- static NOT_ACCEPTABLE = new _HttpStatus(406, "Not Acceptable");
432
- static PROXY_AUTHENTICATION_REQUIRED = new _HttpStatus(407, "Proxy Authentication Required");
433
- static REQUEST_TIMEOUT = new _HttpStatus(408, "Request Timeout");
434
- static CONFLICT = new _HttpStatus(409, "Conflict");
435
- static GONE = new _HttpStatus(410, "Gone");
436
- static LENGTH_REQUIRED = new _HttpStatus(411, "Length Required");
437
- static PRECONDITION_FAILED = new _HttpStatus(412, "Precondition Failed");
438
- static PAYLOAD_TOO_LARGE = new _HttpStatus(413, "Payload Too Large");
439
- static URI_TOO_LONG = new _HttpStatus(414, "URI Too Long");
440
- static UNSUPPORTED_MEDIA_TYPE = new _HttpStatus(415, "Unsupported Media Type");
441
- static EXPECTATION_FAILED = new _HttpStatus(417, "Expectation Failed");
442
- static IM_A_TEAPOT = new _HttpStatus(418, "I'm a teapot");
443
- static TOO_EARLY = new _HttpStatus(425, "Too Early");
444
- static UPGRADE_REQUIRED = new _HttpStatus(426, "Upgrade Required");
445
- static PRECONDITION_REQUIRED = new _HttpStatus(428, "Precondition Required");
446
- static TOO_MANY_REQUESTS = new _HttpStatus(429, "Too Many Requests");
447
- static REQUEST_HEADER_FIELDS_TOO_LARGE = new _HttpStatus(431, "Request Header Fields Too Large");
448
- static UNAVAILABLE_FOR_LEGAL_REASONS = new _HttpStatus(451, "Unavailable For Legal Reasons");
449
- // 5xx Server Error
450
- static INTERNAL_SERVER_ERROR = new _HttpStatus(500, "Internal Server Error");
451
- static NOT_IMPLEMENTED = new _HttpStatus(501, "Not Implemented");
452
- static BAD_GATEWAY = new _HttpStatus(502, "Bad Gateway");
453
- static SERVICE_UNAVAILABLE = new _HttpStatus(503, "Service Unavailable");
454
- static GATEWAY_TIMEOUT = new _HttpStatus(504, "Gateway Timeout");
455
- static HTTP_VERSION_NOT_SUPPORTED = new _HttpStatus(505, "HTTP Version Not Supported");
456
- static VARIANT_ALSO_NEGOTIATES = new _HttpStatus(506, "Variant Also Negotiates");
457
- static INSUFFICIENT_STORAGE = new _HttpStatus(507, "Insufficient Storage");
458
- static LOOP_DETECTED = new _HttpStatus(508, "Loop Detected");
459
- static NOT_EXTENDED = new _HttpStatus(510, "Not Extended");
460
- static NETWORK_AUTHENTICATION_REQUIRED = new _HttpStatus(511, "Network Authentication Required");
461
- static #VALUES = [];
462
- static {
463
- Object.keys(_HttpStatus).filter((key) => key !== "VALUES" && key !== "resolve").forEach((key) => {
464
- const value = _HttpStatus[key];
465
- if (value instanceof _HttpStatus) {
466
- Object.defineProperty(value, "name", { enumerable: true, value: key, writable: false });
467
- _HttpStatus.#VALUES.push(value);
468
- }
469
- });
470
- }
471
- static resolve(code) {
472
- for (const status of _HttpStatus.#VALUES) {
473
- if (status.value === code) {
474
- return status;
475
- }
476
- }
477
- }
478
- #value;
479
- #phrase;
480
- constructor(value, phrase) {
481
- this.#value = value;
482
- this.#phrase = phrase;
483
- }
484
- get value() {
485
- return this.#value;
486
- }
487
- get phrase() {
488
- return this.#phrase;
489
- }
490
- toString() {
491
- return `${this.#value} ${this["name"]}`;
492
- }
493
- };
494
- function httpStatusCode(value) {
495
- if (typeof value === "number") {
496
- if (value < 100 || value > 999) {
497
- throw new Error(`status code ${value} should be in range 100-999`);
498
- }
499
- const status = HttpStatus.resolve(value);
500
- if (status !== void 0) {
501
- return status;
502
- }
503
- return new DefaultHttpStatusCode(value);
504
- }
505
- return value;
506
- }
507
-
508
- // src/server/exchange.ts
509
- var import_node_http = __toESM(require("node:http"), 1);
510
- var ExtendedHttpIncomingMessage = class extends import_node_http.default.IncomingMessage {
511
- // circular reference to the exchange
512
- exchange;
513
- upgradeHead;
514
- get urlBang() {
515
- return this.url;
516
- }
517
- get socketEncrypted() {
518
- return this.socket["encrypted"] === true;
519
- }
520
- };
521
- var ExtendedHttpServerResponse = class extends import_node_http.default.ServerResponse {
522
- markHeadersSent() {
523
- this["_header"] = true;
524
- }
525
- getRawHeaderNames() {
526
- return super["getRawHeaderNames"]();
527
- }
528
- };
529
- var AbstractServerHttpRequest = class extends AbstractHttpRequest {
530
- };
531
- var AbstractServerHttpResponse = class extends AbstractHttpResponse {
532
- #cookies = [];
533
- #statusCode;
534
- #state = "new";
535
- #commitActions = [];
536
- setStatusCode(statusCode) {
537
- if (this.#state === "committed") {
538
- return false;
539
- } else {
540
- this.#statusCode = statusCode;
541
- return true;
542
- }
543
- }
544
- setRawStatusCode(statusCode) {
545
- return this.setStatusCode(statusCode === void 0 ? void 0 : httpStatusCode(statusCode));
546
- }
547
- get statusCode() {
548
- return this.#statusCode;
549
- }
550
- addCookie(cookie) {
551
- if (this.#state === "committed") {
552
- throw new Error(`Cannot add cookie ${JSON.stringify(cookie)} because HTTP response has already been committed`);
553
- }
554
- this.#cookies.push(cookie);
555
- return this;
556
- }
557
- beforeCommit(action) {
558
- this.#commitActions.push(action);
559
- }
560
- get commited() {
561
- const state = this.#state;
562
- return state !== "new" && state !== "commit-action-failed";
563
- }
564
- async body(body) {
565
- if (body instanceof ReadableStream) {
566
- throw new Error("ReadableStream body not supported yet");
567
- }
568
- const buffer = await body;
569
- try {
570
- return await this.doCommit(async () => {
571
- return await this.bodyInternal(Promise.resolve(buffer));
572
- }).catch((error) => {
573
- throw error;
574
- });
575
- } catch (error) {
576
- throw error;
577
- }
578
- }
579
- async end() {
580
- if (!this.commited) {
581
- return this.doCommit(async () => {
582
- return await this.bodyInternal(Promise.resolve());
583
- });
584
- } else {
585
- return Promise.resolve(false);
586
- }
587
- }
588
- doCommit(writeAction) {
589
- const state = this.#state;
590
- let allActions = Promise.resolve();
591
- if (state === "new") {
592
- this.#state = "committing";
593
- if (this.#commitActions.length > 0) {
594
- allActions = this.#commitActions.reduce(
595
- (acc, cur) => acc.then(() => cur()),
596
- Promise.resolve()
597
- ).catch((error) => {
598
- const state2 = this.#state;
599
- if (state2 === "committing") {
600
- this.#state = "commit-action-failed";
601
- }
602
- });
603
- }
604
- } else if (state === "commit-action-failed") {
605
- this.#state = "committing";
606
- } else {
607
- return Promise.resolve(false);
608
- }
609
- allActions = allActions.then(() => {
610
- this.applyStatusCode();
611
- this.applyHeaders();
612
- this.applyCookies();
613
- this.#state = "committed";
614
- });
615
- return allActions.then(async () => {
616
- return writeAction !== void 0 ? await writeAction() : true;
617
- });
618
- }
619
- applyStatusCode() {
620
- }
621
- applyHeaders() {
622
- }
623
- applyCookies() {
624
- }
625
- };
626
- var HttpServerRequest = class extends AbstractServerHttpRequest {
627
- #url;
628
- #cookies;
629
- #req;
630
- constructor(req) {
631
- super(new IncomingMessageHeaders(req));
632
- this.#req = req;
633
- }
634
- getNativeRequest() {
635
- return this.#req;
636
- }
637
- get upgrade() {
638
- return this.#req["upgrade"];
639
- }
640
- get http2() {
641
- return this.#req.httpVersionMajor >= 2;
642
- }
643
- get path() {
644
- return this.URL?.pathname;
645
- }
646
- get URL() {
647
- this.#url ??= new URL(this.#req.urlBang, `${this.protocol}://${this.host}`);
648
- return this.#url;
649
- }
650
- get query() {
651
- return this.URL?.search;
652
- }
653
- get method() {
654
- return this.#req.method;
655
- }
656
- get host() {
657
- let dh = void 0;
658
- if (this.#req.httpVersionMajor >= 2) {
659
- dh = this.#req.headers[":authority"];
660
- }
661
- dh ??= this.#req.socket.remoteAddress;
662
- return super.parseHost(dh);
663
- }
664
- get protocol() {
665
- let dp = void 0;
666
- if (this.#req.httpVersionMajor > 2) {
667
- dp = this.#req.headers[":scheme"];
668
- }
669
- dp ??= this.#req.socketEncrypted ? "https" : "http";
670
- return super.parseProtocol(dp);
671
- }
672
- get socket() {
673
- return this.#req.socket;
674
- }
675
- get remoteAddress() {
676
- const family = this.#req.socket.remoteFamily;
677
- const address = this.#req.socket.remoteAddress;
678
- const port = this.#req.socket.remotePort;
679
- if (!family || !address || !port) {
680
- return void 0;
681
- }
682
- return { family, address, port };
683
- }
684
- get cookies() {
685
- this.#cookies ??= super.cookies;
686
- return this.#cookies;
687
- }
688
- get body() {
689
- return import_node_http.default.IncomingMessage.toWeb(this.#req);
690
- }
691
- async blob() {
692
- const chunks = [];
693
- if (this.body !== void 0) {
694
- for await (const chunk of this.body) {
695
- chunks.push(chunk);
696
- }
697
- }
698
- return new Blob(chunks, { type: this.headers.one("content-type") || "application/octet-stream" });
699
- }
700
- async text() {
701
- const blob = await this.blob();
702
- return await blob.text();
703
- }
704
- async formData() {
705
- const blob = await this.blob();
706
- const text = await blob.text();
707
- return new URLSearchParams(text);
708
- }
709
- async json() {
710
- const blob = await this.blob();
711
- if (blob.size === 0) {
712
- return void 0;
713
- }
714
- const text = await blob.text();
715
- return JSON.parse(text);
716
- }
717
- initId() {
718
- const remoteIp = this.#req.socket.remoteAddress;
719
- if (!remoteIp) {
720
- throw new Error("Socket has no remote address");
721
- }
722
- return `${remoteIp}:${this.#req.socket.remotePort}`;
723
- }
724
- };
725
- var IncomingMessageHeaders = class extends AbstractHttpHeaders {
726
- #msg;
727
- constructor(msg) {
728
- super();
729
- this.#msg = msg;
730
- }
731
- has(name) {
732
- return this.#msg.headers[name] !== void 0;
733
- }
734
- get(name) {
735
- return this.#msg.headers[name];
736
- }
737
- list(name) {
738
- return super.toList(name);
739
- }
740
- one(name) {
741
- const value = this.#msg.headers[name];
742
- if (Array.isArray(value)) {
743
- return value[0];
744
- }
745
- return value;
746
- }
747
- keys() {
748
- return Object.keys(this.#msg.headers).values();
749
- }
750
- };
751
- var OutgoingMessageHeaders = class extends AbstractHttpHeaders {
752
- #msg;
753
- constructor(msg) {
754
- super();
755
- this.#msg = msg;
756
- }
757
- has(name) {
758
- return this.#msg.hasHeader(name);
759
- }
760
- keys() {
761
- return this.#msg.getHeaderNames().values();
762
- }
763
- get(name) {
764
- return this.#msg.getHeader(name);
765
- }
766
- one(name) {
767
- const value = this.#msg.getHeader(name);
768
- if (Array.isArray(value)) {
769
- return value[0];
770
- }
771
- return value;
772
- }
773
- set(name, value) {
774
- if (!this.#msg.headersSent) {
775
- if (Array.isArray(value)) {
776
- value = value.map((v) => typeof v === "number" ? String(v) : v);
777
- } else if (typeof value === "number") {
778
- value = String(value);
779
- }
780
- if (value) {
781
- this.#msg.setHeader(name, value);
782
- } else {
783
- this.#msg.removeHeader(name);
784
- }
785
- }
786
- return this;
787
- }
788
- add(name, value) {
789
- if (!this.#msg.headersSent) {
790
- this.#msg.appendHeader(name, value);
791
- }
792
- return this;
793
- }
794
- list(name) {
795
- return super.toList(name);
796
- }
797
- };
798
- var HttpServerResponse = class extends AbstractServerHttpResponse {
799
- #res;
800
- constructor(res) {
801
- super(new OutgoingMessageHeaders(res));
802
- this.#res = res;
803
- }
804
- getNativeResponse() {
805
- return this.#res;
806
- }
807
- get statusCode() {
808
- const status = super.statusCode;
809
- return status ?? { value: this.#res.statusCode };
810
- }
811
- applyStatusCode() {
812
- const status = super.statusCode;
813
- if (status !== void 0) {
814
- this.#res.statusCode = status.value;
815
- }
816
- }
817
- addCookie(cookie) {
818
- this.headers.add("Set-Cookie", super.setCookieValue(cookie));
819
- return this;
820
- }
821
- async bodyInternal(body) {
822
- if (!this.#res.headersSent) {
823
- if (body instanceof ReadableStream) {
824
- throw new Error("ReadableStream body not supported in response");
825
- } else {
826
- const chunk = await body;
827
- return await new Promise((resolve, reject) => {
828
- try {
829
- if (chunk === void 0) {
830
- this.#res.end(() => {
831
- resolve(true);
832
- });
833
- } else {
834
- if (!this.headers.has("content-length")) {
835
- if (typeof chunk === "string") {
836
- this.headers.set("content-length", Buffer.byteLength(chunk));
837
- } else if (chunk instanceof Blob) {
838
- this.headers.set("content-length", chunk.size);
839
- } else {
840
- this.headers.set("content-length", chunk.byteLength);
841
- }
842
- }
843
- this.#res.end(chunk, () => {
844
- resolve(true);
845
- });
846
- }
847
- } catch (e) {
848
- reject(e instanceof Error ? e : new Error(`end failed: ${e}`));
849
- }
850
- });
851
- }
852
- } else {
853
- return false;
854
- }
855
- }
856
- };
857
- var ServerHttpRequestDecorator = class _ServerHttpRequestDecorator {
858
- #delegate;
859
- constructor(request) {
860
- this.#delegate = request;
861
- }
862
- get delegate() {
863
- return this.#delegate;
864
- }
865
- get id() {
866
- return this.#delegate.id;
867
- }
868
- get method() {
869
- return this.#delegate.method;
870
- }
871
- get path() {
872
- return this.#delegate.path;
873
- }
874
- get protocol() {
875
- return this.#delegate.protocol;
876
- }
877
- get host() {
878
- return this.#delegate.host;
879
- }
880
- get URL() {
881
- return this.#delegate.URL;
882
- }
883
- get headers() {
884
- return this.#delegate.headers;
885
- }
886
- get cookies() {
887
- return this.#delegate.cookies;
888
- }
889
- get remoteAddress() {
890
- return this.#delegate.remoteAddress;
891
- }
892
- get upgrade() {
893
- return this.#delegate.upgrade;
894
- }
895
- get body() {
896
- return this.#delegate.body;
897
- }
898
- async blob() {
899
- return await this.#delegate.blob();
900
- }
901
- async text() {
902
- return await this.#delegate.text();
903
- }
904
- async formData() {
905
- return await this.#delegate.formData();
906
- }
907
- async json() {
908
- return await this.#delegate.json();
909
- }
910
- toString() {
911
- return `${_ServerHttpRequestDecorator.name} [delegate: ${this.delegate.toString()}]`;
912
- }
913
- static getNativeRequest(request) {
914
- if (request instanceof AbstractServerHttpRequest) {
915
- return request.getNativeRequest();
916
- } else if (request instanceof _ServerHttpRequestDecorator) {
917
- return _ServerHttpRequestDecorator.getNativeRequest(request.delegate);
918
- } else {
919
- throw new Error(`Cannot get native request from ${request.constructor.name}`);
920
- }
921
- }
922
- };
923
- var ServerHttpResponseDecorator = class _ServerHttpResponseDecorator {
924
- #delegate;
925
- constructor(response) {
926
- this.#delegate = response;
927
- }
928
- get delegate() {
929
- return this.#delegate;
930
- }
931
- setStatusCode(statusCode) {
932
- return this.delegate.setStatusCode(statusCode);
933
- }
934
- setRawStatusCode(statusCode) {
935
- return this.delegate.setRawStatusCode(statusCode);
936
- }
937
- get statusCode() {
938
- return this.delegate.statusCode;
939
- }
940
- get cookies() {
941
- return this.delegate.cookies;
942
- }
943
- addCookie(cookie) {
944
- this.delegate.addCookie(cookie);
945
- return this;
946
- }
947
- async end() {
948
- return await this.delegate.end();
949
- }
950
- async body(body) {
951
- return await this.#delegate.body(body);
952
- }
953
- get headers() {
954
- return this.#delegate.headers;
955
- }
956
- toString() {
957
- return `${_ServerHttpResponseDecorator.name} [delegate: ${this.delegate.toString()}]`;
958
- }
959
- static getNativeResponse(response) {
960
- if (response instanceof AbstractServerHttpResponse) {
961
- return response.getNativeResponse();
962
- } else if (response instanceof _ServerHttpResponseDecorator) {
963
- return _ServerHttpResponseDecorator.getNativeResponse(response.delegate);
964
- } else {
965
- throw new Error(`Cannot get native response from ${response.constructor.name}`);
966
- }
967
- }
968
- };
969
- var ServerWebExchangeDecorator = class _ServerWebExchangeDecorator {
970
- #delegate;
971
- constructor(exchange) {
972
- this.#delegate = exchange;
973
- }
974
- get delegate() {
975
- return this.#delegate;
976
- }
977
- get request() {
978
- return this.#delegate.request;
979
- }
980
- get response() {
981
- return this.#delegate.response;
982
- }
983
- attribute(name) {
984
- return this.#delegate.attribute(name);
985
- }
986
- principal() {
987
- return this.#delegate.principal();
988
- }
989
- get logPrefix() {
990
- return this.#delegate.logPrefix;
991
- }
992
- toString() {
993
- return `${_ServerWebExchangeDecorator.name} [delegate: ${this.delegate}]`;
994
- }
995
- };
996
- var DefaultWebExchange = class {
997
- request;
998
- response;
999
- #attributes = {};
1000
- #logId;
1001
- #logPrefix = "";
1002
- constructor(request, response) {
1003
- this.#attributes[LOG_ID_ATTRIBUTE] = request.id;
1004
- this.request = request;
1005
- this.response = response;
1006
- }
1007
- get method() {
1008
- return this.request.method;
1009
- }
1010
- get path() {
1011
- return this.request.path;
1012
- }
1013
- get attributes() {
1014
- return this.#attributes;
1015
- }
1016
- attribute(name) {
1017
- return this.attributes[name];
1018
- }
1019
- principal() {
1020
- return Promise.resolve(void 0);
1021
- }
1022
- get logPrefix() {
1023
- const value = this.attribute(LOG_ID_ATTRIBUTE);
1024
- if (this.#logId !== value) {
1025
- this.#logId = value;
1026
- this.#logPrefix = value !== void 0 ? `[${value}] ` : "";
1027
- }
1028
- return this.#logPrefix;
1029
- }
1030
- };
1031
- var LOG_ID_ATTRIBUTE = "io.interop.gateway.server.log_id";
1032
-
1033
- // src/server/address.ts
1034
- var import_node_os = require("node:os");
1035
- var PORT_RANGE_MATCHER = /^(\d+|(0x[\da-f]+))(-(\d+|(0x[\da-f]+)))?$/i;
1036
- function validPort(port) {
1037
- if (port > 65535) throw new Error(`bad port ${port}`);
1038
- return port;
1039
- }
1040
- function* portRange(port) {
1041
- if (typeof port === "string") {
1042
- for (const portRange2 of port.split(",")) {
1043
- const trimmed = portRange2.trim();
1044
- const matchResult = PORT_RANGE_MATCHER.exec(trimmed);
1045
- if (matchResult) {
1046
- const start2 = parseInt(matchResult[1]);
1047
- const end = parseInt(matchResult[4] ?? matchResult[1]);
1048
- for (let i = validPort(start2); i < validPort(end) + 1; i++) {
1049
- yield i;
1050
- }
1051
- } else {
1052
- throw new Error(`'${portRange2}' is not a valid port or range.`);
1053
- }
1054
- }
1055
- } else {
1056
- yield validPort(port);
1057
- }
1058
- }
1059
- var localIp = (() => {
1060
- function first(a) {
1061
- return a.length > 0 ? a[0] : void 0;
1062
- }
1063
- const addresses = Object.values((0, import_node_os.networkInterfaces)()).flatMap((details) => {
1064
- return (details ?? []).filter((info2) => info2.family === "IPv4");
1065
- }).reduce((acc, info2) => {
1066
- acc[info2.internal ? "internal" : "external"].push(info2);
1067
- return acc;
1068
- }, { internal: [], external: [] });
1069
- return (first(addresses.internal) ?? first(addresses.external))?.address;
1070
- })();
1071
-
1072
- // src/server/monitoring.ts
1073
- var import_node_v8 = require("node:v8");
1074
- var import_promises = require("node:fs/promises");
1075
- var log2 = getLogger2("monitoring");
1076
- var DEFAULT_OPTIONS = {
1077
- memoryLimit: 1024 * 1024 * 1024,
1078
- // 1GB
1079
- reportInterval: 10 * 60 * 1e3,
1080
- // 10 min
1081
- dumpLocation: ".",
1082
- // current folder
1083
- maxBackups: 10,
1084
- dumpPrefix: "Heap"
1085
- };
1086
- function fetchStats() {
1087
- return (0, import_node_v8.getHeapStatistics)();
1088
- }
1089
- async function dumpHeap(opts) {
1090
- const prefix = opts.dumpPrefix ?? "Heap";
1091
- const target = `${opts.dumpLocation}/${prefix}.heapsnapshot`;
1092
- if (log2.enabledFor("debug")) {
1093
- log2.debug(`starting heap dump in ${target}`);
1094
- }
1095
- await fileExists(opts.dumpLocation).catch(async (_) => {
1096
- if (log2.enabledFor("debug")) {
1097
- log2.debug(`dump location ${opts.dumpLocation} does not exists. Will try to create it`);
1098
- }
1099
- try {
1100
- await (0, import_promises.mkdir)(opts.dumpLocation, { recursive: true });
1101
- log2.info(`dump location dir ${opts.dumpLocation} successfully created`);
1102
- } catch (e) {
1103
- log2.error(`failed to create dump location ${opts.dumpLocation}`);
1104
- }
1105
- });
1106
- const dumpFileName = (0, import_node_v8.writeHeapSnapshot)(target);
1107
- log2.info(`heap dumped`);
1108
- try {
1109
- log2.debug(`rolling snapshot backups`);
1110
- const lastFileName = `${opts.dumpLocation}/${prefix}.${opts.maxBackups}.heapsnapshot`;
1111
- await fileExists(lastFileName).then(async () => {
1112
- if (log2.enabledFor("debug")) {
1113
- log2.debug(`deleting ${lastFileName}`);
1114
- }
1115
- try {
1116
- await (0, import_promises.unlink)(lastFileName);
1117
- } catch (e) {
1118
- log2.warn(`failed to delete ${lastFileName}`, e);
1119
- }
1120
- }).catch(() => {
1121
- });
1122
- for (let i = opts.maxBackups - 1; i > 0; i--) {
1123
- const currentFileName = `${opts.dumpLocation}/${prefix}.${i}.heapsnapshot`;
1124
- const nextFileName = `${opts.dumpLocation}/${prefix}.${i + 1}.heapsnapshot`;
1125
- await fileExists(currentFileName).then(async () => {
1126
- try {
1127
- await (0, import_promises.rename)(currentFileName, nextFileName);
1128
- } catch (e) {
1129
- log2.warn(`failed to rename ${currentFileName} to ${nextFileName}`, e);
1130
- }
1131
- }).catch(() => {
1132
- });
1133
- }
1134
- const firstFileName = `${opts.dumpLocation}/${prefix}.${1}.heapsnapshot`;
1135
- try {
1136
- await (0, import_promises.rename)(dumpFileName, firstFileName);
1137
- } catch (e) {
1138
- log2.warn(`failed to rename ${dumpFileName} to ${firstFileName}`, e);
1139
- }
1140
- log2.debug("snapshots rolled");
1141
- } catch (e) {
1142
- log2.error("error rolling backups", e);
1143
- throw e;
1144
- }
1145
- }
1146
- async function fileExists(path) {
1147
- if (log2.enabledFor("trace")) {
1148
- log2.debug(`checking file ${path}`);
1149
- }
1150
- await (0, import_promises.access)(path);
1151
- }
1152
- async function processStats(stats, state, opts) {
1153
- if (log2.enabledFor("debug")) {
1154
- log2.debug(`processing heap stats ${JSON.stringify(stats)}`);
1155
- }
1156
- const limit = Math.min(opts.memoryLimit, 0.95 * stats.heap_size_limit);
1157
- const used = stats.used_heap_size;
1158
- log2.info(`heap stats ${JSON.stringify(stats)}`);
1159
- if (used >= limit) {
1160
- log2.warn(`used heap ${used} bytes exceeds memory limit ${limit} bytes`);
1161
- if (state.memoryLimitExceeded) {
1162
- delete state.snapshot;
1163
- } else {
1164
- state.memoryLimitExceeded = true;
1165
- state.snapshot = true;
1166
- }
1167
- await dumpHeap(opts);
1168
- } else {
1169
- state.memoryLimitExceeded = false;
1170
- delete state.snapshot;
1171
- }
1172
- }
1173
- function start(opts) {
1174
- const merged = { ...DEFAULT_OPTIONS, ...opts };
1175
- let stopped = false;
1176
- const state = { memoryLimitExceeded: false };
1177
- const report = async () => {
1178
- const stats = fetchStats();
1179
- await processStats(stats, state, merged);
1180
- };
1181
- const interval = setInterval(report, merged.reportInterval);
1182
- const channel = async (command) => {
1183
- if (!stopped) {
1184
- command ??= "run";
1185
- switch (command) {
1186
- case "run": {
1187
- await report();
1188
- break;
1189
- }
1190
- case "dump": {
1191
- await dumpHeap(merged);
1192
- break;
1193
- }
1194
- case "stop": {
1195
- stopped = true;
1196
- clearInterval(interval);
1197
- log2.info("exit memory diagnostic");
1198
- break;
1199
- }
1200
- }
1201
- }
1202
- return stopped;
1203
- };
1204
- return { ...merged, channel };
1205
- }
1206
- async function run({ channel }, command) {
1207
- if (!await channel(command)) {
1208
- log2.warn(`cannot execute command "${command}" already closed`);
1209
- }
1210
- }
1211
- async function stop(m) {
1212
- return await run(m, "stop");
1213
- }
1214
-
1215
- // src/server/server-header.ts
1216
- var import_package = __toESM(require("@interopio/gateway-server/package.json"), 1);
1217
- var serverHeader = (server) => {
1218
- server ??= `${import_package.default.name} - v${import_package.default.version}`;
1219
- return async ({ response }, next) => {
1220
- if (server !== false && !response.headers.has("server")) {
1221
- response.headers.set("Server", server);
1222
- }
1223
- await next();
1224
- };
1225
- };
1226
- var server_header_default = (server) => serverHeader(server);
1227
-
1228
- // src/server/ws-client-verify.ts
1229
- var import_gateway2 = require("@interopio/gateway");
1230
- var log3 = getLogger2("gateway.ws.client-verify");
1231
- function acceptsMissing(originFilters) {
1232
- switch (originFilters.missing) {
1233
- case "allow":
1234
- // fall-through
1235
- case "whitelist":
1236
- return true;
1237
- case "block":
1238
- // fall-through
1239
- case "blacklist":
1240
- return false;
1241
- default:
1242
- return false;
1243
- }
1244
- }
1245
- function tryMatch(originFilters, origin) {
1246
- const block = originFilters.block ?? originFilters["blacklist"];
1247
- const allow = originFilters.allow ?? originFilters["whitelist"];
1248
- if (block.length > 0 && import_gateway2.IOGateway.Filtering.valuesMatch(block, origin)) {
1249
- log3.warn(`origin ${origin} matches block filter`);
1250
- return false;
1251
- } else if (allow.length > 0 && import_gateway2.IOGateway.Filtering.valuesMatch(allow, origin)) {
1252
- if (log3.enabledFor("debug")) {
1253
- log3.debug(`origin ${origin} matches allow filter`);
1254
- }
1255
- return true;
1256
- }
1257
- }
1258
- function acceptsNonMatched(originFilters) {
1259
- switch (originFilters.non_matched) {
1260
- case "allow":
1261
- // fall-through
1262
- case "whitelist":
1263
- return true;
1264
- case "block":
1265
- // fall-through
1266
- case "blacklist":
1267
- return false;
1268
- default:
1269
- return false;
1270
- }
1271
- }
1272
- function acceptsOrigin(origin, originFilters) {
1273
- if (!originFilters) {
1274
- return true;
1275
- }
1276
- if (!origin) {
1277
- return acceptsMissing(originFilters);
1278
- } else {
1279
- const matchResult = tryMatch(originFilters, origin);
1280
- if (matchResult) {
1281
- return matchResult;
1282
- } else {
1283
- return acceptsNonMatched(originFilters);
1284
- }
1285
- }
1286
- }
1287
- function regexifyOriginFilters(originFilters) {
1288
- if (originFilters) {
1289
- const block = (originFilters.block ?? originFilters.blacklist ?? []).map(import_gateway2.IOGateway.Filtering.regexify);
1290
- const allow = (originFilters.allow ?? originFilters.whitelist ?? []).map(import_gateway2.IOGateway.Filtering.regexify);
1291
- return {
1292
- non_matched: originFilters.non_matched ?? "allow",
1293
- missing: originFilters.missing ?? "allow",
1294
- allow,
1295
- block
1296
- };
1297
- }
1298
- }
1299
-
1300
- // src/server/util/matchers.ts
1301
- var or = (matchers) => {
1302
- return async (exchange) => {
1303
- for (const matcher of matchers) {
1304
- const result = await matcher(exchange);
1305
- if (result.match) {
1306
- return match();
1307
- }
1308
- }
1309
- return NO_MATCH;
1310
- };
1311
- };
1312
- var and = (matchers) => {
1313
- const matcher = async (exchange) => {
1314
- for (const matcher2 of matchers) {
1315
- const result = await matcher2(exchange);
1316
- if (!result.match) {
1317
- return NO_MATCH;
1318
- }
1319
- }
1320
- return match();
1321
- };
1322
- matcher.toString = () => `and(${matchers.map((m) => m.toString()).join(", ")})`;
1323
- return matcher;
1324
- };
1325
- var not = (matcher) => {
1326
- return async (exchange) => {
1327
- const result = await matcher(exchange);
1328
- return result.match ? NO_MATCH : match();
1329
- };
1330
- };
1331
- var anyExchange = async (_exchange) => {
1332
- return match();
1333
- };
1334
- anyExchange.toString = () => "any-exchange";
1335
- var EMPTY_OBJECT = Object.freeze({});
1336
- var NO_MATCH = Object.freeze({ match: false, variables: EMPTY_OBJECT });
1337
- var match = (variables = EMPTY_OBJECT) => {
1338
- return { match: true, variables };
1339
- };
1340
- var pattern = (pattern2, opts) => {
1341
- const method = opts?.method;
1342
- const matcher = async (exchange) => {
1343
- const request = exchange.request;
1344
- const path = request.path;
1345
- if (method !== void 0 && request.method !== method) {
1346
- return NO_MATCH;
1347
- }
1348
- if (typeof pattern2 === "string") {
1349
- if (path === pattern2) {
1350
- return match();
1351
- }
1352
- return NO_MATCH;
1353
- } else {
1354
- const match2 = pattern2.exec(path);
1355
- if (match2 === null) {
1356
- return NO_MATCH;
1357
- }
1358
- return { match: true, variables: { ...match2.groups } };
1359
- }
1360
- };
1361
- matcher.toString = () => {
1362
- return `pattern(${pattern2.toString()}, method=${method ?? "<any>"})`;
1363
- };
1364
- return matcher;
1365
- };
1366
- var mediaType = (opts) => {
1367
- const shouldIgnore = (requestedMediaType) => {
1368
- if (opts.ignoredMediaTypes !== void 0) {
1369
- for (const ignoredMediaType of opts.ignoredMediaTypes) {
1370
- if (requestedMediaType === ignoredMediaType || ignoredMediaType === "*/*") {
1371
- return true;
1372
- }
1373
- }
1374
- }
1375
- return false;
1376
- };
1377
- return async (exchange) => {
1378
- const request = exchange.request;
1379
- let requestMediaTypes;
1380
- try {
1381
- requestMediaTypes = request.headers.list("accept");
1382
- } catch (e) {
1383
- return NO_MATCH;
1384
- }
1385
- for (const requestedMediaType of requestMediaTypes) {
1386
- if (shouldIgnore(requestedMediaType)) {
1387
- continue;
1388
- }
1389
- for (const mediaType2 of opts.mediaTypes) {
1390
- if (requestedMediaType.startsWith(mediaType2)) {
1391
- return match();
1392
- }
1393
- }
1394
- }
1395
- return NO_MATCH;
1396
- };
1397
- };
1398
- var upgradeMatcher = async ({ request }) => {
1399
- const upgrade = request.upgrade && request.headers.one("upgrade")?.toLowerCase() === "websocket";
1400
- return upgrade ? match() : NO_MATCH;
1401
- };
1402
- upgradeMatcher.toString = () => "websocket upgrade";
1403
-
1404
- // src/app/route.ts
1405
- var import_gateway3 = require("@interopio/gateway");
1406
- async function configure(app, config, routes) {
1407
- const applyCors = (request, options) => {
1408
- if (options?.cors) {
1409
- const cors = options.cors === true ? {
1410
- allowOrigins: options.origins?.allow?.map(import_gateway3.IOGateway.Filtering.regexify),
1411
- allowMethods: request.method === void 0 ? ["*"] : [request.method],
1412
- allowCredentials: options.authorize?.access !== "permitted" ? true : void 0
1413
- } : options.cors;
1414
- const path = request.path;
1415
- routes.cors.push([path, cors]);
1416
- }
1417
- };
1418
- const configurer = new class {
1419
- handle(...handlers) {
1420
- handlers.forEach(({ request, options, handler }) => {
1421
- const matcher = pattern(import_gateway3.IOGateway.Filtering.regexify(request.path), { method: request.method });
1422
- if (options?.authorize) {
1423
- routes.authorize.push([matcher, options.authorize]);
1424
- }
1425
- applyCors(request, options);
1426
- const middleware = async (exchange, next) => {
1427
- const { match: match2, variables } = await matcher(exchange);
1428
- if (match2) {
1429
- await handler(exchange, variables);
1430
- } else {
1431
- await next();
1432
- }
1433
- };
1434
- routes.middleware.push(middleware);
1435
- });
1436
- }
1437
- socket(...sockets) {
1438
- for (const { path, factory, options } of sockets) {
1439
- const route = path ?? "/";
1440
- routes.sockets.set(route, {
1441
- default: path === void 0,
1442
- ping: options?.ping,
1443
- factory,
1444
- maxConnections: options?.maxConnections,
1445
- authorize: options?.authorize,
1446
- originFilters: regexifyOriginFilters(options?.origins)
1447
- });
1448
- }
1449
- }
1450
- }();
1451
- await app(configurer, config);
1452
- }
1453
-
1454
- // src/server/cors.ts
1455
- var import_gateway4 = require("@interopio/gateway");
1456
- function isSameOrigin(request) {
1457
- const origin = request.headers.one("origin");
1458
- if (origin === void 0) {
1459
- return true;
1460
- }
1461
- const url = request.URL;
1462
- const actualProtocol = url.protocol;
1463
- const actualHost = url.host;
1464
- const originUrl = URL.parse(origin);
1465
- const originHost = originUrl?.host;
1466
- const originProtocol = originUrl?.protocol;
1467
- return actualProtocol === originProtocol && actualHost === originHost;
1468
- }
1469
- function isCorsRequest(request) {
1470
- return request.headers.has("origin") && !isSameOrigin(request);
1471
- }
1472
- function isPreFlightRequest(request) {
1473
- return request.method === "OPTIONS" && request.headers.has("origin") && request.headers.has("access-control-request-method");
1474
- }
1475
- var VARY_HEADERS = ["Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers"];
1476
- var processRequest = (exchange, config) => {
1477
- const { request, response } = exchange;
1478
- const responseHeaders = response.headers;
1479
- if (!responseHeaders.has("Vary")) {
1480
- responseHeaders.set("Vary", VARY_HEADERS.join(", "));
1481
- } else {
1482
- const varyHeaders = responseHeaders.list("Vary");
1483
- for (const header of VARY_HEADERS) {
1484
- if (!varyHeaders.find((h) => h === header)) {
1485
- varyHeaders.push(header);
1486
- }
1487
- }
1488
- responseHeaders.set("Vary", varyHeaders.join(", "));
1489
- }
1490
- try {
1491
- if (!isCorsRequest(request)) {
1492
- return true;
1493
- }
1494
- } catch (e) {
1495
- if (logger.enabledFor("debug")) {
1496
- logger.debug(`reject: origin is malformed`);
1497
- }
1498
- rejectRequest(response);
1499
- return false;
1500
- }
1501
- if (responseHeaders.has("access-control-allow-origin")) {
1502
- if (logger.enabledFor("trace")) {
1503
- logger.debug(`skip: already contains "Access-Control-Allow-Origin"`);
1504
- }
1505
- return true;
1506
- }
1507
- const preFlightRequest = isPreFlightRequest(request);
1508
- if (config) {
1509
- return handleInternal(exchange, config, preFlightRequest);
1510
- }
1511
- if (preFlightRequest) {
1512
- rejectRequest(response);
1513
- return false;
1514
- }
1515
- return true;
1516
- };
1517
- var DEFAULT_PERMIT_ALL = ["*"];
1518
- var DEFAULT_PERMIT_METHODS = ["GET", "HEAD", "POST"];
1519
- var PERMIT_DEFAULT_CONFIG = {
1520
- allowOrigins: DEFAULT_PERMIT_ALL,
1521
- allowMethods: DEFAULT_PERMIT_METHODS,
1522
- allowHeaders: DEFAULT_PERMIT_ALL,
1523
- maxAge: 1800
1524
- // 30 minutes
1525
- };
1526
- function validateCorsConfig(config) {
1527
- if (config) {
1528
- const allowHeaders = config.allowHeaders;
1529
- if (allowHeaders && allowHeaders !== ALL) {
1530
- config = {
1531
- ...config,
1532
- allowHeaders: allowHeaders.map((header) => header.toLowerCase())
1533
- };
1534
- }
1535
- const allowOrigins = config.allowOrigins;
1536
- if (allowOrigins) {
1537
- if (allowOrigins === "*") {
1538
- validateAllowCredentials(config);
1539
- validateAllowPrivateNetwork(config);
1540
- } else {
1541
- config = {
1542
- ...config,
1543
- allowOrigins: allowOrigins.map((origin) => {
1544
- if (typeof origin === "string" && origin !== ALL) {
1545
- origin = import_gateway4.IOGateway.Filtering.regexify(origin);
1546
- if (typeof origin === "string") {
1547
- return trimTrailingSlash(origin).toLowerCase();
1548
- }
1549
- }
1550
- return origin;
1551
- })
1552
- };
1553
- }
1554
- }
1555
- return config;
1556
- }
1557
- }
1558
- function combine(source, other) {
1559
- if (other === void 0) {
1560
- return source !== void 0 ? source === ALL ? [ALL] : source : [];
1561
- }
1562
- if (source === void 0) {
1563
- return other === ALL ? [ALL] : other;
1564
- }
1565
- if (source == DEFAULT_PERMIT_ALL || source === DEFAULT_PERMIT_METHODS) {
1566
- return other === ALL ? [ALL] : other;
1567
- }
1568
- if (other == DEFAULT_PERMIT_ALL || other === DEFAULT_PERMIT_METHODS) {
1569
- return source === ALL ? [ALL] : source;
1570
- }
1571
- if (source === ALL || source.includes(ALL) || other === ALL || other.includes(ALL)) {
1572
- return [ALL];
1573
- }
1574
- const combined = /* @__PURE__ */ new Set();
1575
- source.forEach((v) => combined.add(v));
1576
- other.forEach((v) => combined.add(v));
1577
- return Array.from(combined);
1578
- }
1579
- var combineCorsConfig = (source, other) => {
1580
- if (other === void 0) {
1581
- return source;
1582
- }
1583
- const config = {
1584
- allowOrigins: combine(source.allowOrigins, other?.allowOrigins),
1585
- allowMethods: combine(source.allowMethods, other?.allowMethods),
1586
- allowHeaders: combine(source.allowHeaders, other?.allowHeaders),
1587
- exposeHeaders: combine(source.exposeHeaders, other?.exposeHeaders),
1588
- allowCredentials: other?.allowCredentials ?? source.allowCredentials,
1589
- allowPrivateNetwork: other?.allowPrivateNetwork ?? source.allowPrivateNetwork,
1590
- maxAge: other?.maxAge ?? source.maxAge
1591
- };
1592
- return config;
1593
- };
1594
- var corsFilter = (opts) => {
1595
- const source = opts.corsConfigSource;
1596
- const processor = opts.corsProcessor ?? processRequest;
1597
- return async (ctx, next) => {
1598
- const config = await source(ctx);
1599
- const isValid = processor(ctx, config);
1600
- if (!isValid || isPreFlightRequest(ctx.request)) {
1601
- return;
1602
- } else {
1603
- await next();
1604
- }
1605
- };
1606
- };
1607
- var cors_default = corsFilter;
1608
- var logger = getLogger2("cors");
1609
- function rejectRequest(response) {
1610
- response.setStatusCode(HttpStatus.FORBIDDEN);
1611
- }
1612
- function handleInternal(exchange, config, preFlightRequest) {
1613
- const { request, response } = exchange;
1614
- const responseHeaders = response.headers;
1615
- const requestOrigin = request.headers.one("origin");
1616
- const allowOrigin = checkOrigin(config, requestOrigin);
1617
- if (allowOrigin === void 0) {
1618
- if (logger.enabledFor("debug")) {
1619
- logger.debug(`reject: '${requestOrigin}' origin is not allowed`);
1620
- }
1621
- rejectRequest(response);
1622
- return false;
1623
- }
1624
- const requestMethod = getMethodToUse(request, preFlightRequest);
1625
- const allowMethods = checkMethods(config, requestMethod);
1626
- if (allowMethods === void 0) {
1627
- if (logger.enabledFor("debug")) {
1628
- logger.debug(`reject: HTTP '${requestMethod}' is not allowed`);
1629
- }
1630
- rejectRequest(response);
1631
- return false;
1632
- }
1633
- const requestHeaders = getHeadersToUse(request, preFlightRequest);
1634
- const allowHeaders = checkHeaders(config, requestHeaders);
1635
- if (preFlightRequest && allowHeaders === void 0) {
1636
- if (logger.enabledFor("debug")) {
1637
- logger.debug(`reject: headers '${requestHeaders}' are not allowed`);
1638
- }
1639
- rejectRequest(response);
1640
- return false;
1641
- }
1642
- responseHeaders.set("Access-Control-Allow-Origin", allowOrigin);
1643
- if (preFlightRequest) {
1644
- responseHeaders.set("Access-Control-Allow-Methods", allowMethods.join(","));
1645
- }
1646
- if (preFlightRequest && allowHeaders !== void 0 && allowHeaders.length > 0) {
1647
- responseHeaders.set("Access-Control-Allow-Headers", allowHeaders.join(", "));
1648
- }
1649
- const exposeHeaders = config.exposeHeaders;
1650
- if (exposeHeaders && exposeHeaders.length > 0) {
1651
- responseHeaders.set("Access-Control-Expose-Headers", exposeHeaders.join(", "));
1652
- }
1653
- if (config.allowCredentials) {
1654
- responseHeaders.set("Access-Control-Allow-Credentials", "true");
1655
- }
1656
- if (config.allowPrivateNetwork && request.headers.one("access-control-request-private-network") === "true") {
1657
- responseHeaders.set("Access-Control-Allow-Private-Network", "true");
1658
- }
1659
- if (preFlightRequest && config.maxAge !== void 0) {
1660
- responseHeaders.set("Access-Control-Max-Age", config.maxAge.toString());
1661
- }
1662
- return true;
1663
- }
1664
- var ALL = "*";
1665
- var DEFAULT_METHODS = ["GET", "HEAD"];
1666
- function validateAllowCredentials(config) {
1667
- if (config.allowCredentials === true && config.allowOrigins === ALL) {
1668
- throw new Error(`when allowCredentials is true allowOrigins cannot be "*"`);
1669
- }
1670
- }
1671
- function validateAllowPrivateNetwork(config) {
1672
- if (config.allowPrivateNetwork === true && config.allowOrigins === ALL) {
1673
- throw new Error(`when allowPrivateNetwork is true allowOrigins cannot be "*"`);
1674
- }
1675
- }
1676
- function checkOrigin(config, origin) {
1677
- if (origin) {
1678
- const allowedOrigins = config.allowOrigins;
1679
- if (allowedOrigins) {
1680
- if (allowedOrigins === ALL) {
1681
- validateAllowCredentials(config);
1682
- validateAllowPrivateNetwork(config);
1683
- return ALL;
1684
- }
1685
- const originToCheck = trimTrailingSlash(origin.toLowerCase());
1686
- for (const allowedOrigin of allowedOrigins) {
1687
- if (allowedOrigin === ALL || import_gateway4.IOGateway.Filtering.valueMatches(allowedOrigin, originToCheck)) {
1688
- return origin;
1689
- }
1690
- }
1691
- }
1692
- }
1693
- }
1694
- function checkMethods(config, requestMethod) {
1695
- if (requestMethod) {
1696
- const allowedMethods = config.allowMethods ?? DEFAULT_METHODS;
1697
- if (allowedMethods === ALL) {
1698
- return [requestMethod];
1699
- }
1700
- if (import_gateway4.IOGateway.Filtering.valuesMatch(allowedMethods, requestMethod)) {
1701
- return allowedMethods;
1702
- }
1703
- }
1704
- }
1705
- function checkHeaders(config, requestHeaders) {
1706
- if (requestHeaders === void 0) {
1707
- return;
1708
- }
1709
- if (requestHeaders.length == 0) {
1710
- return [];
1711
- }
1712
- const allowedHeaders = config.allowHeaders;
1713
- if (allowedHeaders === void 0) {
1714
- return;
1715
- }
1716
- const allowAnyHeader = allowedHeaders === ALL || allowedHeaders.includes(ALL);
1717
- const result = [];
1718
- for (const requestHeader of requestHeaders) {
1719
- const value = requestHeader?.trim();
1720
- if (value) {
1721
- if (allowAnyHeader) {
1722
- result.push(value);
1723
- } else {
1724
- for (const allowedHeader of allowedHeaders) {
1725
- if (value.toLowerCase() === allowedHeader) {
1726
- result.push(value);
1727
- break;
1728
- }
1729
- }
1730
- }
1731
- }
1732
- }
1733
- if (result.length > 0) {
1734
- return result;
1735
- }
1736
- }
1737
- function trimTrailingSlash(origin) {
1738
- return origin.endsWith("/") ? origin.slice(0, -1) : origin;
1739
- }
1740
- function getMethodToUse(request, isPreFlight) {
1741
- return isPreFlight ? request.headers.one("access-control-request-method") : request.method;
1742
- }
1743
- function getHeadersToUse(request, isPreFlight) {
1744
- const headers2 = request.headers;
1745
- return isPreFlight ? headers2.list("access-control-request-headers") : Array.from(headers2.keys());
1746
- }
1747
- var matchingCorsConfigSource = (opts) => {
1748
- return async (exchange) => {
1749
- for (const [matcher, config] of opts.mappings) {
1750
- if ((await matcher(exchange)).match) {
1751
- logger.debug(`resolved cors config on '${exchange.request.path}' using ${matcher}: ${JSON.stringify(config)}`);
1752
- return config;
1753
- }
1754
- }
1755
- };
1756
- };
1757
-
1758
- // src/app/cors.ts
1759
- var import_gateway5 = require("@interopio/gateway");
1760
- function createCorsConfigSource(context) {
1761
- const { sockets: routes, cors } = context;
1762
- const defaultCorsConfig = context.corsConfig === false ? void 0 : combineCorsConfig(PERMIT_DEFAULT_CONFIG, context.corsConfig);
1763
- const validatedConfigs = [];
1764
- for (const [path, route] of routes) {
1765
- let routeCorsConfig = defaultCorsConfig;
1766
- for (const [matcher, config2] of cors) {
1767
- if (import_gateway5.IOGateway.Filtering.valueMatches(matcher, path)) {
1768
- if (config2 === void 0) {
1769
- routeCorsConfig = void 0;
1770
- } else {
1771
- routeCorsConfig = routeCorsConfig === void 0 ? config2 : combineCorsConfig(routeCorsConfig, config2);
1772
- }
1773
- }
1774
- }
1775
- const config = context.corsConfig === false ? void 0 : {
1776
- allowOrigins: route.originFilters?.allow,
1777
- allowMethods: ["GET", "CONNECT", "OPTIONS"],
1778
- allowHeaders: [
1779
- "Upgrade",
1780
- "Connection",
1781
- "Origin",
1782
- "Sec-Websocket-Key",
1783
- "Sec-Websocket-Version",
1784
- "Sec-Websocket-Protocol",
1785
- "Sec-Websocket-Extensions"
1786
- ],
1787
- exposeHeaders: ["Sec-Websocket-Accept", "Sec-Websocket-Protocol", "Sec-Websocket-Extensions"],
1788
- allowCredentials: route.authorize?.access !== "permitted" ? true : void 0
1789
- };
1790
- routeCorsConfig = routeCorsConfig === void 0 ? config : combineCorsConfig(routeCorsConfig, config);
1791
- validatedConfigs.push([
1792
- and([upgradeMatcher, pattern(path)]),
1793
- validateCorsConfig(routeCorsConfig)
1794
- ]);
1795
- }
1796
- const appConfigs = [];
1797
- for (const [matcher, config] of cors) {
1798
- let [, routeCorsConfig] = appConfigs.find(([m]) => String(m) === String(matcher)) ?? [matcher, defaultCorsConfig];
1799
- routeCorsConfig = routeCorsConfig === void 0 ? config : combineCorsConfig(routeCorsConfig, config);
1800
- let added = false;
1801
- for (const entry of appConfigs) {
1802
- if (String(entry[0]) === String(matcher)) {
1803
- entry[1] = routeCorsConfig;
1804
- added = true;
1805
- break;
1806
- }
1807
- }
1808
- if (!added) {
1809
- appConfigs.push([matcher, routeCorsConfig]);
1810
- }
1811
- }
1812
- for (const [matcher, config] of appConfigs) {
1813
- validatedConfigs.push([pattern(matcher), validateCorsConfig(config)]);
1814
- }
1815
- validatedConfigs.push([pattern(/\/api\/.*/), validateCorsConfig(defaultCorsConfig)]);
1816
- return matchingCorsConfigSource({ mappings: validatedConfigs });
1817
- }
1818
-
1819
- // src/server/security/types.ts
1820
- function isAuthentication(principal) {
1821
- return principal !== void 0 && typeof principal["type"] === "string" && typeof principal["authenticated"] === "boolean";
1822
- }
1823
- var AuthenticationError = class extends Error {
1824
- _authentication;
1825
- get authentication() {
1826
- return this._authentication;
1827
- }
1828
- set authentication(value) {
1829
- if (value === void 0) {
1830
- throw new TypeError("Authentication cannot be undefined");
1831
- }
1832
- this._authentication = value;
1833
- }
1834
- };
1835
- var InsufficientAuthenticationError = class extends AuthenticationError {
1836
- };
1837
- var BadCredentialsError = class extends AuthenticationError {
1838
- };
1839
- var AccessDeniedError = class extends Error {
1840
- };
1841
- var AuthorizationDecision = class {
1842
- constructor(granted) {
1843
- this.granted = granted;
1844
- }
1845
- granted;
1846
- };
1847
- var DefaultAuthorizationManager = class {
1848
- #check;
1849
- constructor(check) {
1850
- this.#check = check;
1851
- }
1852
- async verify(authentication, object) {
1853
- const decision = await this.#check(authentication, object);
1854
- if (!decision?.granted) {
1855
- throw new AccessDeniedError("Access denied");
1856
- }
1857
- }
1858
- async authorize(authentication, object) {
1859
- return await this.#check(authentication, object);
1860
- }
1861
- };
1862
- var AuthenticationServiceError = class extends AuthenticationError {
1863
- };
1864
-
1865
- // src/server/security/http-headers.ts
1866
- var staticServerHttpHeadersWriter = (headers2) => {
1867
- return async (exchange) => {
1868
- let containsNoHeaders = true;
1869
- const { response } = exchange;
1870
- for (const name of headers2.keys()) {
1871
- if (response.headers.has(name)) {
1872
- containsNoHeaders = false;
1873
- }
1874
- }
1875
- if (containsNoHeaders) {
1876
- for (const [name, value] of headers2) {
1877
- response.headers.set(name, value);
1878
- }
1879
- }
1880
- };
1881
- };
1882
- var cacheControlServerHttpHeadersWriter = () => staticServerHttpHeadersWriter(
1883
- new MapHttpHeaders().add("cache-control", "no-cache, no-store, max-age=0, must-revalidate").add("pragma", "no-cache").add("expires", "0")
1884
- );
1885
- var contentTypeServerHttpHeadersWriter = () => staticServerHttpHeadersWriter(
1886
- new MapHttpHeaders().add("x-content-type-options", "nosniff")
1887
- );
1888
- var strictTransportSecurityServerHttpHeadersWriter = (maxAgeInSeconds, includeSubDomains, preload) => {
1889
- let headerValue = `max-age=${maxAgeInSeconds}`;
1890
- if (includeSubDomains) {
1891
- headerValue += " ; includeSubDomains";
1892
- }
1893
- if (preload) {
1894
- headerValue += " ; preload";
1895
- }
1896
- const delegate = staticServerHttpHeadersWriter(
1897
- new MapHttpHeaders().add("strict-transport-security", headerValue)
1898
- );
1899
- const isSecure = (exchange) => {
1900
- const protocol = exchange.request.URL.protocol;
1901
- return protocol === "https:";
1902
- };
1903
- return async (exchange) => {
1904
- if (isSecure(exchange)) {
1905
- await delegate(exchange);
1906
- }
1907
- };
1908
- };
1909
- var frameOptionsServerHttpHeadersWriter = (mode) => {
1910
- return staticServerHttpHeadersWriter(
1911
- new MapHttpHeaders().add("x-frame-options", mode)
1912
- );
1913
- };
1914
- var xssProtectionServerHttpHeadersWriter = (headerValue) => staticServerHttpHeadersWriter(
1915
- new MapHttpHeaders().add("x-xss-protection", headerValue)
1916
- );
1917
- var permissionsPolicyServerHttpHeadersWriter = (policyDirectives) => {
1918
- const delegate = policyDirectives === void 0 ? void 0 : staticServerHttpHeadersWriter(
1919
- new MapHttpHeaders().add("permissions-policy", policyDirectives)
1920
- );
1921
- return async (exchange) => {
1922
- if (delegate !== void 0) {
1923
- await delegate(exchange);
1924
- }
1925
- };
1926
- };
1927
- var contentSecurityPolicyServerHttpHeadersWriter = (policyDirectives, reportOnly) => {
1928
- const headerName = reportOnly ? "content-security-policy-report-only" : "content-security-policy";
1929
- const delegate = policyDirectives === void 0 ? void 0 : staticServerHttpHeadersWriter(
1930
- new MapHttpHeaders().add(headerName, policyDirectives)
1931
- );
1932
- return async (exchange) => {
1933
- if (delegate !== void 0) {
1934
- await delegate(exchange);
1935
- }
1936
- };
1937
- };
1938
- var refererPolicyServerHttpHeadersWriter = (policy = "no-referrer") => {
1939
- return staticServerHttpHeadersWriter(
1940
- new MapHttpHeaders().add("referer-policy", policy)
1941
- );
1942
- };
1943
- var crossOriginOpenerPolicyServerHttpHeadersWriter = (policy) => {
1944
- const delegate = policy === void 0 ? void 0 : staticServerHttpHeadersWriter(
1945
- new MapHttpHeaders().add("cross-origin-opener-policy", policy)
1946
- );
1947
- return async (exchange) => {
1948
- if (delegate !== void 0) {
1949
- await delegate(exchange);
1950
- }
1951
- };
1952
- };
1953
- var crossOriginEmbedderPolicyServerHttpHeadersWriter = (policy) => {
1954
- const delegate = policy === void 0 ? void 0 : staticServerHttpHeadersWriter(
1955
- new MapHttpHeaders().add("cross-origin-embedder-policy", policy)
1956
- );
1957
- return async (exchange) => {
1958
- if (delegate !== void 0) {
1959
- await delegate(exchange);
1960
- }
1961
- };
1962
- };
1963
- var crossOriginResourcePolicyServerHttpHeadersWriter = (policy) => {
1964
- const delegate = policy === void 0 ? void 0 : staticServerHttpHeadersWriter(
1965
- new MapHttpHeaders().add("cross-origin-resource-policy", policy)
1966
- );
1967
- return async (exchange) => {
1968
- if (delegate !== void 0) {
1969
- await delegate(exchange);
1970
- }
1971
- };
1972
- };
1973
- var compositeServerHttpHeadersWriter = (...writers) => {
1974
- return async (exchange) => {
1975
- for (const writer of writers) {
1976
- await writer(exchange);
1977
- }
1978
- };
1979
- };
1980
- function headers(opts) {
1981
- const writers = [];
1982
- if (!opts?.cache?.disabled) {
1983
- writers.push(cacheControlServerHttpHeadersWriter());
1984
- }
1985
- if (!opts?.contentType?.disabled) {
1986
- writers.push(contentTypeServerHttpHeadersWriter());
1987
- }
1988
- if (!opts?.hsts?.disabled) {
1989
- writers.push(strictTransportSecurityServerHttpHeadersWriter(opts?.hsts?.maxAge ?? 365 * 24 * 60 * 60, opts?.hsts?.includeSubDomains ?? true, opts?.hsts?.preload ?? false));
1990
- }
1991
- if (!opts?.frameOptions?.disabled) {
1992
- writers.push(frameOptionsServerHttpHeadersWriter(opts?.frameOptions?.mode ?? "DENY"));
1993
- }
1994
- if (!opts?.xss?.disabled) {
1995
- writers.push(xssProtectionServerHttpHeadersWriter(opts?.xss?.headerValue ?? "0"));
1996
- }
1997
- if (!opts?.permissionsPolicy?.disabled) {
1998
- writers.push(permissionsPolicyServerHttpHeadersWriter(opts?.permissionsPolicy?.policyDirectives));
1999
- }
2000
- if (!opts?.contentSecurityPolicy?.disabled) {
2001
- writers.push(contentSecurityPolicyServerHttpHeadersWriter(opts?.contentSecurityPolicy?.policyDirectives ?? "default-src 'self'", opts?.contentSecurityPolicy?.reportOnly));
2002
- }
2003
- if (!opts?.refererPolicy?.disabled) {
2004
- writers.push(refererPolicyServerHttpHeadersWriter(opts?.refererPolicy?.policy ?? "no-referrer"));
2005
- }
2006
- if (!opts?.crossOriginOpenerPolicy?.disabled) {
2007
- writers.push(crossOriginOpenerPolicyServerHttpHeadersWriter(opts?.crossOriginOpenerPolicy?.policy));
2008
- }
2009
- if (!opts?.crossOriginEmbedderPolicy?.disabled) {
2010
- writers.push(crossOriginEmbedderPolicyServerHttpHeadersWriter(opts?.crossOriginEmbedderPolicy?.policy));
2011
- }
2012
- if (!opts?.crossOriginResourcePolicy?.disabled) {
2013
- writers.push(crossOriginResourcePolicyServerHttpHeadersWriter(opts?.crossOriginResourcePolicy?.policy));
2014
- }
2015
- if (opts?.writers) {
2016
- writers.push(...opts.writers);
2017
- }
2018
- const writer = compositeServerHttpHeadersWriter(...writers);
2019
- return async (exchange, next) => {
2020
- await writer(exchange);
2021
- await next();
2022
- };
2023
- }
2024
-
2025
- // src/server/security/entry-point-failure-handler.ts
2026
- var serverAuthenticationEntryPointFailureHandler = (opts) => {
2027
- const entryPoint = opts.entryPoint;
2028
- const rethrowAuthenticationServiceError = opts?.rethrowAuthenticationServiceError ?? true;
2029
- return async ({ exchange }, error) => {
2030
- if (!rethrowAuthenticationServiceError) {
2031
- return entryPoint(exchange, error);
2032
- }
2033
- if (!(error instanceof AuthenticationServiceError)) {
2034
- return entryPoint(exchange, error);
2035
- }
2036
- throw error;
2037
- };
2038
- };
2039
-
2040
- // src/server/security/http-basic-entry-point.ts
2041
- var DEFAULT_REALM = "Realm";
2042
- var createHeaderValue = (realm) => {
2043
- return `Basic realm="${realm}"`;
2044
- };
2045
- var httpBasicEntryPoint = (opts) => {
2046
- const headerValue = createHeaderValue(opts?.realm ?? DEFAULT_REALM);
2047
- return async (exchange, _error) => {
2048
- const { response } = exchange;
2049
- response.setStatusCode(HttpStatus.UNAUTHORIZED);
2050
- response.headers.set("WWW-Authenticate", headerValue);
2051
- };
2052
- };
2053
-
2054
- // src/server/security/http-basic-converter.ts
2055
- var BASIC = "Basic ";
2056
- var httpBasicAuthenticationConverter = (opts) => {
2057
- return async (exchange) => {
2058
- const { request } = exchange;
2059
- const authorization = request.headers.one("authorization");
2060
- if (!authorization || !/basic/i.test(authorization.substring(0))) {
2061
- return;
2062
- }
2063
- const credentials = authorization.length <= BASIC.length ? "" : authorization.substring(BASIC.length);
2064
- const decoded = Buffer.from(credentials, "base64").toString(opts?.credentialsEncoding ?? "utf-8");
2065
- const parts = decoded.split(":", 2);
2066
- if (parts.length !== 2) {
2067
- return void 0;
2068
- }
2069
- return {
2070
- type: "UsernamePassword",
2071
- authenticated: false,
2072
- principal: parts[0],
2073
- credentials: parts[1]
2074
- };
2075
- };
2076
- };
2077
-
2078
- // src/server/security/security-context.ts
2079
- var import_node_async_hooks2 = require("node:async_hooks");
2080
- var AsyncStorageSecurityContextHolder = class _AsyncStorageSecurityContextHolder {
2081
- static hasSecurityContext(storage) {
2082
- return storage.getStore()?.securityContext !== void 0;
2083
- }
2084
- static async getSecurityContext(storage) {
2085
- return await storage.getStore()?.securityContext;
2086
- }
2087
- static clearSecurityContext(storage) {
2088
- delete storage.getStore()?.securityContext;
2089
- }
2090
- static withSecurityContext(securityContext) {
2091
- return (storage = new import_node_async_hooks2.AsyncLocalStorage()) => {
2092
- storage.getStore().securityContext = securityContext;
2093
- return storage;
2094
- };
2095
- }
2096
- static withAuthentication(authentication) {
2097
- return _AsyncStorageSecurityContextHolder.withSecurityContext(Promise.resolve({ authentication }));
2098
- }
2099
- static async getContext(storage) {
2100
- if (_AsyncStorageSecurityContextHolder.hasSecurityContext(storage)) {
2101
- return _AsyncStorageSecurityContextHolder.getSecurityContext(storage);
2102
- }
2103
- }
2104
- };
2105
-
2106
- // src/server/security/authentication-filter.ts
2107
- async function authenticate(exchange, next, token, managerResolver, successHandler, storage) {
2108
- const authManager = await managerResolver(exchange);
2109
- const authentication = await authManager?.(token);
2110
- if (authentication === void 0) {
2111
- throw new Error("No authentication manager found for the exchange");
2112
- }
2113
- try {
2114
- await onAuthenticationSuccess(authentication, { exchange, next }, successHandler, storage);
2115
- } catch (e) {
2116
- if (e instanceof AuthenticationError) {
2117
- }
2118
- throw e;
2119
- }
2120
- }
2121
- async function onAuthenticationSuccess(authentication, filterExchange, successHandler, storage) {
2122
- AsyncStorageSecurityContextHolder.withAuthentication(authentication)(storage);
2123
- await successHandler(filterExchange, authentication);
2124
- }
2125
- function authenticationFilter(opts) {
2126
- const auth = {
2127
- matcher: anyExchange,
2128
- successHandler: async ({ next }) => {
2129
- await next();
2130
- },
2131
- converter: httpBasicAuthenticationConverter({}),
2132
- failureHandler: serverAuthenticationEntryPointFailureHandler({ entryPoint: httpBasicEntryPoint({}) }),
2133
- ...opts
2134
- };
2135
- let managerResolver = auth.managerResolver;
2136
- if (managerResolver === void 0 && auth.manager !== void 0) {
2137
- const manager = auth.manager;
2138
- managerResolver = async (_exchange) => {
2139
- return manager;
2140
- };
2141
- }
2142
- if (managerResolver === void 0) {
2143
- throw new Error("Authentication filter requires a managerResolver or a manager");
2144
- }
2145
- return async (exchange, next) => {
2146
- const matchResult = await auth.matcher(exchange);
2147
- const token = matchResult.match ? await auth.converter(exchange) : void 0;
2148
- if (token === void 0) {
2149
- await next();
2150
- return;
2151
- }
2152
- try {
2153
- await authenticate(exchange, next, token, managerResolver, auth.successHandler, auth.storage);
2154
- } catch (error) {
2155
- if (error instanceof AuthenticationError) {
2156
- await auth.failureHandler({ exchange, next }, error);
2157
- return;
2158
- }
2159
- throw error;
2160
- }
2161
- };
2162
- }
2163
-
2164
- // src/server/security/http-status-entry-point.ts
2165
- var httpStatusEntryPoint = (opts) => {
2166
- return async (exchange, _error) => {
2167
- const response = exchange.response;
2168
- response.setStatusCode(opts.httpStatus);
2169
- };
2170
- };
2171
-
2172
- // src/server/security/delegating-entry-point.ts
2173
- var logger2 = getLogger2("auth.entry-point");
2174
- var delegatingEntryPoint = (opts) => {
2175
- const defaultEntryPoint = opts.defaultEntryPoint ?? (async ({ response }, _error) => {
2176
- response.setStatusCode(HttpStatus.UNAUTHORIZED);
2177
- await response.end();
2178
- });
2179
- return async (exchange, error) => {
2180
- for (const [matcher, entryPoint] of opts.entryPoints) {
2181
- if (logger2.enabledFor("debug")) {
2182
- logger2.debug(`trying to match using: ${matcher}`);
2183
- }
2184
- const match2 = await matcher(exchange);
2185
- if (match2.match) {
2186
- if (logger2.enabledFor("debug")) {
2187
- logger2.debug(`match found. using default entry point ${entryPoint}`);
2188
- }
2189
- return entryPoint(exchange, error);
2190
- }
2191
- }
2192
- if (logger2.enabledFor("debug")) {
2193
- logger2.debug(`no match found. using default entry point ${defaultEntryPoint}`);
2194
- }
2195
- return defaultEntryPoint(exchange, error);
2196
- };
2197
- };
2198
-
2199
- // src/server/security/delegating-success-handler.ts
2200
- var delegatingSuccessHandler = (handlers) => {
2201
- return async ({ exchange, next }, authentication) => {
2202
- for (const handler of handlers) {
2203
- await handler({ exchange, next }, authentication);
2204
- }
2205
- };
2206
- };
2207
-
2208
- // src/server/security/http-basic.ts
2209
- function httpBasic(opts) {
2210
- const xhrMatcher = async (exchange) => {
2211
- const headers2 = exchange.request.headers;
2212
- const h = headers2.list("X-Requested-With");
2213
- if (h.includes("XMLHttpRequest")) {
2214
- return match();
2215
- }
2216
- return NO_MATCH;
2217
- };
2218
- const defaultEntryPoint = delegatingEntryPoint({
2219
- entryPoints: [[xhrMatcher, httpStatusEntryPoint({ httpStatus: HttpStatus.UNAUTHORIZED })]],
2220
- defaultEntryPoint: httpBasicEntryPoint({})
2221
- });
2222
- const entryPoint = opts.entryPoint ?? defaultEntryPoint;
2223
- const manager = opts.manager;
2224
- const restMatcher = mediaType({
2225
- mediaTypes: [
2226
- "application/atom+xml",
2227
- "application/x-www-form-urlencoded",
2228
- "application/json",
2229
- "application/octet-stream",
2230
- "application/xml",
2231
- "multipart/form-data",
2232
- "text/xml"
2233
- ],
2234
- ignoredMediaTypes: ["*/*"]
2235
- });
2236
- const notHtmlMatcher = not(mediaType({ mediaTypes: ["text/html"] }));
2237
- const restNoHtmlMatcher = and([notHtmlMatcher, restMatcher]);
2238
- const preferredMatcher = or([xhrMatcher, restNoHtmlMatcher]);
2239
- opts.defaultEntryPoints.push([preferredMatcher, entryPoint]);
2240
- const failureHandler = opts.failureHandler ?? serverAuthenticationEntryPointFailureHandler({ entryPoint });
2241
- const successHandler = delegatingSuccessHandler(opts.successHandlers ?? opts.defaultSuccessHandlers);
2242
- const converter = httpBasicAuthenticationConverter({});
2243
- return authenticationFilter({
2244
- storage: opts.storage,
2245
- manager,
2246
- failureHandler,
2247
- successHandler,
2248
- converter
2249
- });
2250
- }
2251
-
2252
- // src/server/security/oauth2/token-error.ts
2253
- var BearerTokenErrorCodes = {
2254
- invalid_request: "invalid_request",
2255
- invalid_token: "invalid_token",
2256
- insufficient_scope: "insufficient_scope"
2257
- };
2258
- var DEFAULT_URI = "https://tools.ietf.org/html/rfc6750#section-3.1";
2259
- function invalidToken(message) {
2260
- return {
2261
- errorCode: BearerTokenErrorCodes.invalid_token,
2262
- httpStatus: HttpStatus.UNAUTHORIZED,
2263
- description: message,
2264
- uri: DEFAULT_URI
2265
- };
2266
- }
2267
- function invalidRequest(message) {
2268
- return {
2269
- errorCode: BearerTokenErrorCodes.invalid_request,
2270
- httpStatus: HttpStatus.BAD_REQUEST,
2271
- description: message,
2272
- uri: DEFAULT_URI
2273
- };
2274
- }
2275
-
2276
- // src/server/security/oauth2/token-converter.ts
2277
- var ACCESS_TOKEN_PARAMETER_NAME = "access_token";
2278
- var authorizationPattern = /^Bearer\s+(?<token>[a-zA-Z0-9-._~+/]+=*)$/i;
2279
- var Oauth2AuthenticationError = class extends AuthenticationError {
2280
- error;
2281
- constructor(error, message, options) {
2282
- super(message ?? (typeof error === "string" ? void 0 : error.description), options);
2283
- this.error = typeof error === "string" ? { errorCode: error } : error;
2284
- }
2285
- };
2286
- var isBearerTokenAuthenticationToken = (authentication) => {
2287
- return authentication.type === "BearerToken";
2288
- };
2289
- var serverBearerTokenAuthenticationConverter = (opts) => {
2290
- return async (exchange) => {
2291
- const { request } = exchange;
2292
- return Promise.all([
2293
- resolveFromAuthorizationHeader(request.headers, opts?.headerName).then((token) => token !== void 0 ? [token] : void 0),
2294
- resolveFromQueryString(request, opts?.uriQueryParameter),
2295
- resolveFromBody(exchange, opts?.formEncodedBodyParameter)
2296
- ]).then((rs) => rs.filter((r) => r !== void 0).flat(1)).then(resolveToken).then((token) => {
2297
- if (token) return { authenticated: false, type: "BearerToken", token };
2298
- });
2299
- };
2300
- };
2301
- async function resolveToken(accessTokens) {
2302
- if (accessTokens.length === 0) {
2303
- return;
2304
- }
2305
- if (accessTokens.length > 1) {
2306
- const error = invalidRequest("Found multiple access tokens in the request");
2307
- throw new Oauth2AuthenticationError(error);
2308
- }
2309
- const accessToken = accessTokens[0];
2310
- if (!accessToken || accessToken.length === 0) {
2311
- const error = invalidRequest("The requested access token parameter is an empty string");
2312
- throw new Oauth2AuthenticationError(error);
2313
- }
2314
- return accessToken;
2315
- }
2316
- async function resolveFromAuthorizationHeader(headers2, headerName = "authorization") {
2317
- const authorization = headers2.one(headerName);
2318
- if (!authorization || !/bearer/i.test(authorization.substring(0))) {
2319
- return;
2320
- }
2321
- const match2 = authorizationPattern.exec(authorization);
2322
- if (match2 === null) {
2323
- const error = invalidToken("Bearer token is malformed");
2324
- throw new Oauth2AuthenticationError(error);
2325
- }
2326
- return match2.groups?.token;
2327
- }
2328
- async function resolveTokens(parameters) {
2329
- const accessTokens = parameters.getAll(ACCESS_TOKEN_PARAMETER_NAME);
2330
- if (accessTokens.length === 0) {
2331
- return;
2332
- }
2333
- return accessTokens;
2334
- }
2335
- async function resolveFromQueryString(request, allow = false) {
2336
- if (!allow || request.method !== "GET") {
2337
- return;
2338
- }
2339
- return resolveTokens(request.URL.searchParams);
2340
- }
2341
- async function resolveFromBody(exchange, allow = false) {
2342
- const { request } = exchange;
2343
- if (!allow || "application/x-www-form-urlencoded" !== request.headers.one("content-type") || request.method !== "POST") {
2344
- return;
2345
- }
2346
- const parameters = await exchange.request.formData();
2347
- if (parameters) {
2348
- return resolveTokens(parameters);
2349
- }
2350
- }
2351
- var token_converter_default = serverBearerTokenAuthenticationConverter;
2352
-
2353
- // src/server/security/oauth2/token-entry-point.ts
2354
- function computeWWWAuthenticate(parameters) {
2355
- let wwwAuthenticate = "Bearer";
2356
- if (parameters.size !== 0) {
2357
- wwwAuthenticate += " ";
2358
- let i = 0;
2359
- for (const [key, value] of parameters) {
2360
- wwwAuthenticate += `${key}="${value}"`;
2361
- if (i !== parameters.size - 1) {
2362
- wwwAuthenticate += ", ";
2363
- }
2364
- i++;
2365
- }
2366
- }
2367
- return wwwAuthenticate;
2368
- }
2369
- var isBearerTokenError = (error) => {
2370
- return error.httpStatus !== void 0;
2371
- };
2372
- function getStatus(authError) {
2373
- if (authError instanceof Oauth2AuthenticationError) {
2374
- const { error } = authError;
2375
- if (isBearerTokenError(error)) {
2376
- return error.httpStatus;
2377
- }
2378
- }
2379
- return HttpStatus.UNAUTHORIZED;
2380
- }
2381
- function createParameters(authError, realm) {
2382
- const parameters = /* @__PURE__ */ new Map();
2383
- if (realm) {
2384
- parameters.set("realm", realm);
2385
- }
2386
- if (authError instanceof Oauth2AuthenticationError) {
2387
- const { error } = authError;
2388
- parameters.set("error", error.errorCode);
2389
- if (error.description) {
2390
- parameters.set("error_description", error.description);
2391
- }
2392
- if (error.uri) {
2393
- parameters.set("error_uri", error.uri);
2394
- }
2395
- if (isBearerTokenError(error) && error.scope) {
2396
- parameters.set("scope", error.scope);
2397
- }
2398
- }
2399
- return parameters;
2400
- }
2401
- var bearerTokenServerAuthenticationEntryPoint = (opts) => {
2402
- return async (exchange, error) => {
2403
- const status = getStatus(error);
2404
- const parameters = createParameters(error, opts?.realmName);
2405
- const wwwAuthenticate = computeWWWAuthenticate(parameters);
2406
- const { response } = exchange;
2407
- response.headers.set("WWW-Authenticate", wwwAuthenticate);
2408
- response.setStatusCode(status);
2409
- await response.end();
2410
- };
2411
- };
2412
- var token_entry_point_default = bearerTokenServerAuthenticationEntryPoint;
2413
-
2414
- // src/server/security/oauth2/jwt-auth-manager.ts
2415
- var jwtAuthConverter = (opts) => {
2416
- const principalClaimName = opts?.principalClaimName ?? "sub";
2417
- return (jwt) => {
2418
- const name = jwt.getClaimAsString(principalClaimName);
2419
- return { type: "JwtToken", authenticated: true, name };
2420
- };
2421
- };
2422
- var asyncJwtConverter = (converter) => {
2423
- return async (jwt) => {
2424
- return converter(jwt);
2425
- };
2426
- };
2427
- var JwtError = class extends Error {
2428
- };
2429
- var BadJwtError = class extends JwtError {
2430
- };
2431
- function onError(error) {
2432
- if (error instanceof BadJwtError) {
2433
- return new Oauth2AuthenticationError(invalidToken(error.message), error.message, { cause: error });
2434
- }
2435
- throw new AuthenticationServiceError(error.message, { cause: error });
2436
- }
2437
- function jwtAuthManager(opts) {
2438
- const decoder = opts.decoder;
2439
- const authConverter = opts.authConverter ?? asyncJwtConverter(jwtAuthConverter({}));
2440
- return async (authentication) => {
2441
- if (isBearerTokenAuthenticationToken(authentication)) {
2442
- const token = authentication.token;
2443
- try {
2444
- const jwt = await decoder(token);
2445
- return await authConverter(jwt);
2446
- } catch (e) {
2447
- if (e instanceof JwtError) {
2448
- throw onError(e);
2449
- }
2450
- throw e;
2451
- }
2452
- }
2453
- };
2454
- }
2455
-
2456
- // src/server/security/oauth2-resource-server.ts
2457
- function resourceServer(opts) {
2458
- const entryPoint = opts.entryPoint ?? token_entry_point_default({});
2459
- const converter = opts?.converter ?? token_converter_default({});
2460
- const failureHandler = opts.failureHandler ?? serverAuthenticationEntryPointFailureHandler({ entryPoint });
2461
- if (opts.managerResolver !== void 0) {
2462
- return authenticationFilter({
2463
- storage: opts.storage,
2464
- converter,
2465
- failureHandler,
2466
- managerResolver: opts.managerResolver
2467
- });
2468
- }
2469
- if (opts.jwt !== void 0) {
2470
- const manager = opts.jwt.manager ?? jwtAuthManager(opts.jwt);
2471
- return authenticationFilter({
2472
- storage: opts.storage,
2473
- converter,
2474
- failureHandler,
2475
- managerResolver: async (_exchange) => {
2476
- return manager;
2477
- }
2478
- });
2479
- }
2480
- throw new Error("Invalid resource server configuration: either managerResolver or jwt must be provided");
2481
- }
2482
-
2483
- // src/server/security/config.ts
2484
- var import_jwt = require("@interopio/gateway/jose/jwt");
2485
-
2486
- // src/server/security/error-filter.ts
2487
- async function commenceAuthentication(exchange, authentication, entryPoint) {
2488
- const cause = new InsufficientAuthenticationError(`Full authentication is required to access this resource.`);
2489
- const e = new AuthenticationError("Access Denied", { cause });
2490
- if (authentication) {
2491
- e.authentication = authentication;
2492
- }
2493
- await entryPoint(exchange, e);
2494
- }
2495
- function httpStatusAccessDeniedHandler(httpStatus) {
2496
- return async (exchange, _error) => {
2497
- exchange.response.setStatusCode(httpStatus);
2498
- exchange.response.headers.set("Content-Type", "text/plain; charset=utf-8");
2499
- const buffer = Buffer.from("Access Denied", "utf-8");
2500
- exchange.response.headers.set("Content-Length", buffer.length);
2501
- await exchange.response.body(buffer);
2502
- };
2503
- }
2504
- var errorFilter = (opts) => {
2505
- const accessDeniedHandler = httpStatusAccessDeniedHandler(HttpStatus.FORBIDDEN);
2506
- const authenticationEntryPoint = opts.authenticationEntryPoint ?? httpBasicEntryPoint();
2507
- return async (exchange, next) => {
2508
- try {
2509
- await next();
2510
- } catch (error) {
2511
- if (error instanceof AccessDeniedError) {
2512
- const principal = await exchange.principal();
2513
- if (!isAuthentication(principal)) {
2514
- await commenceAuthentication(exchange, void 0, authenticationEntryPoint);
2515
- } else {
2516
- if (!principal.authenticated) {
2517
- await accessDeniedHandler(exchange, error);
2518
- }
2519
- await commenceAuthentication(exchange, principal, authenticationEntryPoint);
2520
- }
2521
- return;
2522
- }
2523
- throw error;
2524
- }
2525
- };
2526
- };
2527
-
2528
- // src/server/security/delegating-authorization-manager.ts
2529
- var logger3 = getLogger2("security.auth");
2530
- function delegatingAuthorizationManager(opts) {
2531
- const check = async (authentication, exchange) => {
2532
- let decision;
2533
- for (const [matcher, manager] of opts.mappings) {
2534
- if ((await matcher(exchange))?.match) {
2535
- logger3.debug(`checking authorization on '${exchange.request.path}' using [${matcher}, ${manager}]`);
2536
- const checkResult = await manager.authorize(authentication, { exchange });
2537
- if (checkResult !== void 0) {
2538
- decision = checkResult;
2539
- break;
2540
- }
2541
- }
2542
- }
2543
- decision ??= new AuthorizationDecision(false);
2544
- return decision;
2545
- };
2546
- return new DefaultAuthorizationManager(check);
2547
- }
2548
-
2549
- // src/server/security/authorization-filter.ts
2550
- var logger4 = getLogger2("security.auth");
2551
- function authorizationFilter(opts) {
2552
- const { manager, storage } = opts;
2553
- return async (exchange, next) => {
2554
- const promise = AsyncStorageSecurityContextHolder.getContext(storage).then((c) => c?.authentication);
2555
- try {
2556
- await manager.verify(promise, exchange);
2557
- if (logger4.enabledFor("debug")) {
2558
- logger4.debug("authorization successful");
2559
- }
2560
- } catch (error) {
2561
- if (error instanceof AccessDeniedError) {
2562
- if (logger4.enabledFor("debug")) {
2563
- logger4.debug(`authorization failed: ${error.message}`);
2564
- }
2565
- }
2566
- throw error;
2567
- }
2568
- await next();
2569
- };
2570
- }
2571
-
2572
- // src/server/security/exchange-filter.ts
2573
- var SecurityContextServerWebExchange = class extends ServerWebExchangeDecorator {
2574
- #context;
2575
- constructor(exchange, context) {
2576
- super(exchange);
2577
- this.#context = context;
2578
- }
2579
- async principal() {
2580
- const context = await this.#context();
2581
- return context?.authentication;
2582
- }
2583
- };
2584
- var exchangeFilter = (opts) => {
2585
- const storage = opts.storage;
2586
- return async (exchange, next) => {
2587
- await next(new SecurityContextServerWebExchange(exchange, async () => await AsyncStorageSecurityContextHolder.getContext(storage)));
2588
- };
2589
- };
2590
-
2591
- // src/server/security/config.ts
2592
- var filterOrder = {
2593
- first: Number.MAX_SAFE_INTEGER,
2594
- http_headers: 1 * 100,
2595
- https_redirect: 2 * 100,
2596
- cors: 3 * 100,
2597
- http_basic: 6 * 100,
2598
- authentication: 8 * 100,
2599
- security_context_server_web_exchange: 15 * 100,
2600
- error_translation: 18 * 100,
2601
- authorization: 19 * 100,
2602
- last: Number.MAX_SAFE_INTEGER
2603
- };
2604
- var filterOrderSymbol = Symbol.for("filterOrder");
2605
- var config_default = (config, context) => {
2606
- const middleware = [];
2607
- class ServerHttpSecurity {
2608
- #authenticationEntryPoint;
2609
- #defaultEntryPoints = [];
2610
- manager;
2611
- get authenticationEntryPoint() {
2612
- if (this.#authenticationEntryPoint !== void 0 || this.#defaultEntryPoints.length === 0) {
2613
- return this.#authenticationEntryPoint;
2614
- }
2615
- if (this.#defaultEntryPoints.length === 1) {
2616
- return this.#defaultEntryPoints[0][1];
2617
- }
2618
- return delegatingEntryPoint({
2619
- entryPoints: this.#defaultEntryPoints,
2620
- defaultEntryPoint: this.#defaultEntryPoints[this.#defaultEntryPoints.length - 1][1]
2621
- });
2622
- }
2623
- build() {
2624
- if (config.headers !== void 0 && config.headers.disabled !== true) {
2625
- const writer = headers(config.headers);
2626
- writer[filterOrderSymbol] = filterOrder.http_headers;
2627
- middleware.push(writer);
2628
- }
2629
- if (config.cors?.disabled !== true && context.corsConfigSource !== void 0) {
2630
- const filter = cors_default({ corsConfigSource: context.corsConfigSource });
2631
- filter[filterOrderSymbol] = filterOrder.cors;
2632
- middleware.push(filter);
2633
- }
2634
- if (config.basic !== void 0 && config.basic?.disabled !== true) {
2635
- const username = config.basic.user?.name.toLowerCase();
2636
- const password = config.basic.user?.password ?? "";
2637
- const authorities = config.basic.user?.authorities ?? [];
2638
- const manager = async (auth) => {
2639
- const principal = auth["principal"];
2640
- const credentials = auth["credentials"];
2641
- if (principal.toLowerCase() !== username || credentials !== password) {
2642
- throw new BadCredentialsError("Invalid username or password");
2643
- }
2644
- return { type: "UsernamePassword", authenticated: true, principal, credentials, authorities: [...authorities] };
2645
- };
2646
- const defaultSuccessHandlers = [
2647
- async ({ exchange: _, next }, _authentication) => {
2648
- return next();
2649
- }
2650
- ];
2651
- const filter = httpBasic({
2652
- storage: context.storage,
2653
- manager,
2654
- defaultEntryPoints: this.#defaultEntryPoints,
2655
- defaultSuccessHandlers
2656
- });
2657
- filter[filterOrderSymbol] = filterOrder.http_basic;
2658
- middleware.push(filter);
2659
- }
2660
- if (config.jwt !== void 0 && config.jwt.disabled !== true) {
2661
- const verifier = (0, import_jwt.jwtVerifier)({
2662
- issuerBaseUri: config.jwt.issuerUri,
2663
- issuer: config.jwt.issuer,
2664
- audience: config.jwt.audience
2665
- });
2666
- const decoder = async (token) => {
2667
- try {
2668
- const { payload } = await verifier(token);
2669
- return {
2670
- subject: payload.sub,
2671
- getClaimAsString(claim) {
2672
- return payload[claim];
2673
- }
2674
- };
2675
- } catch (e) {
2676
- if (e instanceof import_jwt.JwtVerifyError) {
2677
- throw new BadJwtError(e.message, { cause: e });
2678
- }
2679
- throw new JwtError("error occurred while attempting to decoding jwt", { cause: e });
2680
- }
2681
- };
2682
- const authenticationConverter = token_converter_default({ uriQueryParameter: true });
2683
- const authenticationConverterMatcher = async (exchange) => {
2684
- try {
2685
- const a = await authenticationConverter(exchange);
2686
- if (a === void 0) {
2687
- return NO_MATCH;
2688
- }
2689
- return match();
2690
- } catch (e) {
2691
- return NO_MATCH;
2692
- }
2693
- };
2694
- const entryPoint = token_entry_point_default({});
2695
- this.#defaultEntryPoints.push([authenticationConverterMatcher, entryPoint]);
2696
- const filter = resourceServer({
2697
- storage: context.storage,
2698
- entryPoint,
2699
- converter: authenticationConverter,
2700
- jwt: { decoder }
2701
- });
2702
- filter[filterOrderSymbol] = filterOrder.authentication;
2703
- middleware.push(filter);
2704
- }
2705
- const exchangeF = exchangeFilter({ storage: context.storage });
2706
- middleware.push(exchangeF);
2707
- exchangeF[filterOrderSymbol] = filterOrder.security_context_server_web_exchange;
2708
- if (config.authorize !== void 0) {
2709
- const errorFf = errorFilter({ authenticationEntryPoint: this.authenticationEntryPoint });
2710
- errorFf[filterOrderSymbol] = filterOrder.error_translation;
2711
- middleware.push(errorFf);
2712
- const buildAuthorizationManager = (authorize) => {
2713
- const mappings = [];
2714
- let anyExchangeRegistered = false;
2715
- for (const [matcher, access2] of authorize ?? []) {
2716
- let serverMatcher;
2717
- if (matcher === "any-exchange") {
2718
- anyExchangeRegistered = true;
2719
- serverMatcher = anyExchange;
2720
- } else if (anyExchangeRegistered) {
2721
- throw new Error("Cannot register other matchers after 'any-exchange' matcher");
2722
- } else {
2723
- serverMatcher = matcher;
2724
- }
2725
- let manager2;
2726
- if (access2.access === "permitted") {
2727
- manager2 = new DefaultAuthorizationManager(async () => new AuthorizationDecision(true));
2728
- manager2.toString = () => "AuthorizationManager[permitted]";
2729
- } else if (access2.access === "denied") {
2730
- manager2 = new DefaultAuthorizationManager(async () => new AuthorizationDecision(false));
2731
- manager2.toString = () => "AuthorizationManager[denied]";
2732
- } else if (access2.access === "authenticated") {
2733
- manager2 = new DefaultAuthorizationManager(async (p) => {
2734
- const authentication = await p;
2735
- if (authentication !== void 0) {
2736
- return new AuthorizationDecision(authentication.authenticated);
2737
- }
2738
- return new AuthorizationDecision(false);
2739
- });
2740
- manager2.toString = () => "AuthorizationManager[authenticated]";
2741
- } else {
2742
- throw new Error(`Unknown access type: ${JSON.stringify(access2)}`);
2743
- }
2744
- mappings.push([serverMatcher, manager2]);
2745
- }
2746
- return delegatingAuthorizationManager({ mappings });
2747
- };
2748
- const manager = buildAuthorizationManager(config.authorize);
2749
- const filter = authorizationFilter({ manager, storage: context.storage });
2750
- filter[filterOrderSymbol] = filterOrder.authorization;
2751
- middleware.push(filter);
2752
- }
2753
- middleware.sort((a, b) => {
2754
- const aOrder = a[filterOrderSymbol] ?? filterOrder.last;
2755
- const bOrder = b[filterOrderSymbol] ?? filterOrder.last;
2756
- return aOrder - bOrder;
2757
- });
2758
- }
2759
- }
2760
- const security = new ServerHttpSecurity();
2761
- security.build();
2762
- return middleware;
2763
- };
2764
-
2765
- // src/app/auth.ts
2766
- function createSecurityConfig(context) {
2767
- const authorize = [];
2768
- const defaultAccess = { access: context.authConfig?.type !== "none" ? "authenticated" : "permitted" };
2769
- for (const [path, route] of context.sockets) {
2770
- const rule = route.authorize ?? defaultAccess;
2771
- let matcher = pattern(path, { method: "GET" });
2772
- matcher = and([upgradeMatcher, matcher]);
2773
- authorize.push([matcher, rule]);
2774
- }
2775
- authorize.push([pattern("/", { method: "GET" }), { access: "permitted" }]);
2776
- authorize.push([pattern("/favicon.ico", { method: "GET" }), { access: "permitted" }]);
2777
- authorize.push([pattern("/health", { method: "GET" }), { access: "permitted" }]);
2778
- if (context.authorize.length > 0) {
2779
- authorize.push(...context.authorize);
2780
- }
2781
- authorize.push(["any-exchange", defaultAccess]);
2782
- return {
2783
- authorize,
2784
- cors: {
2785
- disabled: context.corsConfig === false
2786
- },
2787
- basic: {
2788
- disabled: context.authConfig?.type !== "basic",
2789
- ...context.authConfig?.basic
2790
- },
2791
- jwt: {
2792
- disabled: context.authConfig?.type !== "oauth2",
2793
- ...context.authConfig?.oauth2?.jwt
2794
- }
2795
- };
2796
- }
2797
- async function httpSecurity(context) {
2798
- const corsConfigSource = createCorsConfigSource(context);
2799
- const config = createSecurityConfig(context);
2800
- const { storage } = context;
2801
- return config_default(config, { storage, corsConfigSource });
2802
- }
2803
-
2804
- // src/server/handler.ts
2805
- var import_node_async_hooks3 = require("node:async_hooks");
2806
- var HttpHeadResponseDecorator = class extends ServerHttpResponseDecorator {
2807
- };
2808
- var HandlerAdapter = class {
2809
- #logger;
2810
- #enableLoggingRequestDetails = false;
2811
- #delegate;
2812
- #storage;
2813
- constructor(logger7, delegate) {
2814
- this.#logger = logger7;
2815
- this.#delegate = delegate;
2816
- }
2817
- createExchange(request, response) {
2818
- const exchange = new DefaultWebExchange(request, response);
2819
- return exchange;
2820
- }
2821
- set storage(storage) {
2822
- this.#storage = storage;
2823
- }
2824
- set enableLoggingRequestDetails(value) {
2825
- this.#enableLoggingRequestDetails = value;
2826
- }
2827
- formatHeaders(headers2) {
2828
- let result = "{";
2829
- for (const key of headers2.keys()) {
2830
- if (!this.#enableLoggingRequestDetails) {
2831
- result += "masked, ";
2832
- break;
2833
- } else {
2834
- const value = headers2.get(key);
2835
- result += `"${key}": "${value}", `;
2836
- }
2837
- }
2838
- if (result.endsWith(", ")) {
2839
- result = result.slice(0, -2);
2840
- }
2841
- result += "}";
2842
- return result;
2843
- }
2844
- formatRequest(request) {
2845
- const query = request.URL.search;
2846
- return `HTTP ${request.method} "${request.path}${query}`;
2847
- }
2848
- logRequest(exchange) {
2849
- if (this.#logger.enabledFor("debug")) {
2850
- const trace = this.#logger.enabledFor("trace");
2851
- this.#logger.debug(`${exchange.logPrefix}${this.formatRequest(exchange.request)}${trace ? `, headers: ${this.formatHeaders(exchange.request.headers)}` : ""}"`);
2852
- }
2853
- }
2854
- logResponse(exchange) {
2855
- if (this.#logger.enabledFor("debug")) {
2856
- const trace = this.#logger.enabledFor("trace");
2857
- const status = exchange.response.statusCode;
2858
- this.#logger.debug(`${exchange.logPrefix}Completed ${status ?? "200 OK"}${trace ? `, headers: ${this.formatHeaders(exchange.response.headers)}` : ""}"`);
2859
- }
2860
- }
2861
- handleUnresolvedError(exchange, error) {
2862
- const { request, response, logPrefix } = exchange;
2863
- if (response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR)) {
2864
- this.#logger.error(`${logPrefix}500 Server Error for ${this.formatRequest(request)}`, error);
2865
- return;
2866
- }
2867
- this.#logger.error(`${logPrefix}Error [${error.message} for ${this.formatRequest(request)}, but already ended (${response.statusCode})`, error);
2868
- throw error;
2869
- }
2870
- async web(exchange) {
2871
- return await this.#delegate(exchange);
2872
- }
2873
- async http(request, response) {
2874
- const exchange = this.createExchange(request, response);
2875
- const callback = () => {
2876
- this.logRequest(exchange);
2877
- return this.web(exchange).then(() => {
2878
- this.logResponse(exchange);
2879
- }).catch((error) => {
2880
- this.handleUnresolvedError(exchange, error);
2881
- }).then(async () => {
2882
- await exchange.response.end();
2883
- });
2884
- };
2885
- await new Promise((resolve, reject) => {
2886
- if (this.#storage !== void 0) {
2887
- this.#storage.run({ exchange }, () => {
2888
- callback().then(() => resolve()).catch((error) => reject(error));
2889
- });
2890
- } else {
2891
- callback().then(() => resolve()).catch((error) => reject(error));
2892
- }
2893
- });
2894
- }
2895
- };
2896
- var WebHttpHandlerBuilder = class {
2897
- #webHandler;
2898
- #storage = new import_node_async_hooks3.AsyncLocalStorage();
2899
- #handlerDecorator;
2900
- storage(storage) {
2901
- this.#storage = storage;
2902
- return this;
2903
- }
2904
- httpHandlerDecorator(decorator) {
2905
- if (this.#handlerDecorator === void 0) {
2906
- this.#handlerDecorator = decorator;
2907
- } else {
2908
- const previousDecorator = this.#handlerDecorator;
2909
- this.#handlerDecorator = (handler) => {
2910
- handler = previousDecorator(handler);
2911
- return decorator(handler);
2912
- };
2913
- }
2914
- return this;
2915
- }
2916
- constructor(webHandler) {
2917
- this.#webHandler = webHandler;
2918
- }
2919
- build() {
2920
- const logger7 = getLogger2("http");
2921
- const adapter = new HandlerAdapter(logger7, this.#webHandler);
2922
- if (this.#storage !== void 0) adapter.storage = this.#storage;
2923
- adapter.enableLoggingRequestDetails = false;
2924
- const adapted = async (request, response) => adapter.http(request, response);
2925
- return this.#handlerDecorator ? this.#handlerDecorator(adapted) : adapted;
2926
- }
2927
- };
2928
-
2929
- // src/server/ws.ts
2930
- var import_ws = require("ws");
2931
-
2932
- // src/server/socket.ts
2933
- function createHandshakeInfo(req, protocol) {
2934
- const exchange = req?.exchange;
2935
- const request = exchange?.request ?? new HttpServerRequest(req);
2936
- const principalPromiseProvider = exchange?.principal;
2937
- const principal = principalPromiseProvider ? principalPromiseProvider.bind(exchange) : async function principal2() {
2938
- return void 0;
2939
- };
2940
- const url = request.URL;
2941
- const headers2 = new MapHttpHeaders();
2942
- for (const key of request.headers.keys()) {
2943
- headers2.set(key, request.headers.list(key));
2944
- }
2945
- const cookies = request.cookies;
2946
- const logPrefix = exchange?.logPrefix ?? `[${request.id}] `;
2947
- const remoteAddress = request.remoteAddress;
2948
- const handshake = {
2949
- url,
2950
- headers: headers2,
2951
- cookies,
2952
- principal,
2953
- protocol,
2954
- remoteAddress,
2955
- logPrefix
2956
- };
2957
- return handshake;
2958
- }
2959
- function webSockets(context) {
2960
- const sockets = async (exchange, next) => {
2961
- const request = exchange.request;
2962
- const path = request.path ?? "/";
2963
- const routes = context.sockets;
2964
- const route = routes.get(path) ?? Array.from(routes.values()).find((route2) => {
2965
- if (path === "/" && route2.default === true) {
2966
- return true;
2967
- }
2968
- });
2969
- if (route !== void 0) {
2970
- const { request: request2, response } = exchange;
2971
- const upgradeMatchResult = await upgradeMatcher(exchange);
2972
- if ((request2.method === "GET" || request2.method === "CONNECT") && upgradeMatchResult.match) {
2973
- if (route.upgradeStrategy !== void 0) {
2974
- route.upgradeStrategy(exchange);
2975
- return;
2976
- } else {
2977
- throw new Error(`No upgrade strategy defined for route on ${path}`);
2978
- }
2979
- } else {
2980
- if (route.default) {
2981
- await next();
2982
- return;
2983
- }
2984
- response.setStatusCode(HttpStatus.UPGRADE_REQUIRED);
2985
- response.headers.set("Upgrade", "websocket").set("Connection", "Upgrade").set("Content-Type", "text/plain");
2986
- const buffer = Buffer.from(`This service [${request2.path}] requires use of the websocket protocol.`, "utf-8");
2987
- await response.body(buffer);
2988
- }
2989
- } else {
2990
- await next();
2991
- }
2992
- };
2993
- return [sockets];
2994
- }
2995
-
2996
- // src/server/ws.ts
2997
- var ExtendedWebSocket = class extends import_ws.WebSocket {
2998
- constructor(first, second, options) {
2999
- super(null, void 0, options);
3000
- }
3001
- connected;
3002
- };
3003
- var logger5 = getLogger2("ws");
3004
- function upgradeStrategy(path, route, wss, onSocketError) {
3005
- return (exchange) => {
3006
- const { logPrefix, request } = exchange;
3007
- const req = ServerHttpRequestDecorator.getNativeRequest(request);
3008
- req.exchange = exchange;
3009
- const { socket, upgradeHead } = req;
3010
- const host = request.host;
3011
- socket.removeListener("error", onSocketError);
3012
- if (route.maxConnections !== void 0 && wss.clients?.size >= route.maxConnections) {
3013
- logger5.warn(`${logPrefix}dropping ws connection request on ${host}${path}. max connections exceeded.`);
3014
- socket.destroy();
3015
- return;
3016
- }
3017
- const origin = request.headers.one("origin");
3018
- if (!acceptsOrigin(origin, route.originFilters)) {
3019
- if (logger5.enabledFor("info")) {
3020
- logger5.info(`${logPrefix}dropping ws connection request on ${host}${path}. origin ${origin ?? "<missing>"}`);
3021
- }
3022
- socket.destroy();
3023
- return;
3024
- }
3025
- if (logger5.enabledFor("debug")) {
3026
- logger5.debug(`${logPrefix}accepted new ws connection request on ${host}${path}`);
3027
- }
3028
- wss.handleUpgrade(req, socket, upgradeHead, (client, req2) => {
3029
- wss.emit("connection", client, req2);
3030
- });
3031
- };
3032
- }
3033
- function applyHandshakeHeaders(headers2, response) {
3034
- const seen = /* @__PURE__ */ new Set();
3035
- headers2.forEach((header, index) => {
3036
- if (index === 0 && header.startsWith("HTTP/1.1 101 ")) {
3037
- response.setStatusCode(HttpStatus.SWITCHING_PROTOCOLS);
3038
- return;
3039
- }
3040
- const [name, value] = header.split(": ");
3041
- if (response.headers.has(name)) {
3042
- headers2[index] = `${name}: ${response.headers.one(name)}`;
3043
- } else {
3044
- response.headers.set(name, value);
3045
- }
3046
- seen.add(name.toLowerCase());
3047
- });
3048
- const nativeResponse = ServerHttpResponseDecorator.getNativeResponse(response);
3049
- for (const name of nativeResponse.getRawHeaderNames()) {
3050
- const nameLowerCase = name.toLowerCase();
3051
- if (!seen.has(nameLowerCase)) {
3052
- const value = response.headers.get(nameLowerCase);
3053
- if (value !== void 0) {
3054
- headers2.push(`${name}: ${value}`);
3055
- }
3056
- }
3057
- }
3058
- nativeResponse.markHeadersSent();
3059
- }
3060
- async function initRoute(path, route, endpoint, storage, onSocketError) {
3061
- try {
3062
- logger5.info(`creating ws server for [${path}]. max connections: ${route.maxConnections ?? "<unlimited>"}, origin filters: ${route.originFilters ? JSON.stringify(route.originFilters, regexAwareReplacer) : "<none>"}`);
3063
- const wss = new import_ws.WebSocketServer({
3064
- noServer: true,
3065
- WebSocket: ExtendedWebSocket,
3066
- autoPong: false
3067
- });
3068
- const handler = await route.factory({ endpoint, storage });
3069
- wss.on("error", (err) => {
3070
- logger5.error(`error starting the ws server for [${path}]`, err);
3071
- }).on("listening", () => {
3072
- logger5.info(`ws server for [${path}] is listening`);
3073
- }).on("headers", (headers2, request) => {
3074
- if (request.exchange !== void 0) {
3075
- const { response } = request.exchange;
3076
- applyHandshakeHeaders(headers2, response);
3077
- }
3078
- }).on("connection", (socket, request) => {
3079
- const handshake = createHandshakeInfo(request, socket.protocol);
3080
- socket.on("pong", () => socket.connected = true);
3081
- socket.on("ping", () => {
3082
- });
3083
- handler({ socket, handshake });
3084
- });
3085
- const pingInterval = route.ping;
3086
- if (pingInterval) {
3087
- const pingIntervalId = setInterval(() => {
3088
- for (const client of wss.clients) {
3089
- if (client.connected === false) {
3090
- client.terminate();
3091
- }
3092
- client.connected = false;
3093
- client.ping();
3094
- }
3095
- }, pingInterval);
3096
- wss.on("close", () => {
3097
- clearInterval(pingIntervalId);
3098
- });
3099
- }
3100
- route.upgradeStrategy = upgradeStrategy(path, route, wss, onSocketError);
3101
- route.close = async () => {
3102
- await handler.close?.call(handler);
3103
- logger5.info(`stopping ws server for [${path}]. clients: ${wss.clients?.size ?? 0}`);
3104
- wss.clients?.forEach((client) => {
3105
- client.terminate();
3106
- });
3107
- wss.close();
3108
- };
3109
- } catch (e) {
3110
- logger5.warn(`failed to init route ${path}`, e);
3111
- }
3112
- }
3113
-
3114
- // src/server.ts
3115
- var logger6 = getLogger2("app");
3116
- function secureContextOptions(ssl) {
3117
- const options = {};
3118
- if (ssl.key) options.key = (0, import_node_fs.readFileSync)(ssl.key);
3119
- if (ssl.cert) options.cert = (0, import_node_fs.readFileSync)(ssl.cert);
3120
- if (ssl.ca) options.ca = (0, import_node_fs.readFileSync)(ssl.ca);
3121
- return options;
3122
- }
3123
- async function createListener(builder, onSocketError) {
3124
- const httpHandler = builder.build();
3125
- return async (req, resOrUpgradeHead) => {
3126
- req.socket.addListener("error", onSocketError);
3127
- let res;
3128
- if (resOrUpgradeHead instanceof ExtendedHttpServerResponse) {
3129
- res = resOrUpgradeHead;
3130
- } else {
3131
- req.upgradeHead = resOrUpgradeHead;
3132
- res = new ExtendedHttpServerResponse(req);
3133
- res.assignSocket(req.socket);
3134
- }
3135
- const request = new HttpServerRequest(req);
3136
- const response = new HttpServerResponse(res);
3137
- const decoratedResponse = request.method === "HEAD" ? new HttpHeadResponseDecorator(response) : response;
3138
- await httpHandler(request, decoratedResponse);
3139
- };
3140
- }
3141
- function promisify(fn) {
3142
- return new Promise((resolve, reject) => {
3143
- const r = fn((err) => {
3144
- if (err) {
3145
- reject(err);
3146
- } else {
3147
- resolve(r);
3148
- }
3149
- });
3150
- });
3151
- }
3152
- function memoryMonitor(config) {
3153
- if (config) {
3154
- return start({
3155
- memoryLimit: config.memory_limit,
3156
- dumpLocation: config.dump_location,
3157
- dumpPrefix: config.dump_prefix,
3158
- reportInterval: config.report_interval,
3159
- maxBackups: config.max_backups
3160
- });
3161
- }
3162
- }
3163
- async function initBuilder(context) {
3164
- const storage = context.storage;
3165
- const security = await httpSecurity(context);
3166
- const sockets = webSockets(context);
3167
- const handler = compose(
3168
- server_header_default(context.serverHeader),
3169
- ...security,
3170
- ...sockets,
3171
- ...context.middleware,
3172
- // health check
3173
- async ({ request, response }, next) => {
3174
- if (request.method === "GET" && request.path === "/health") {
3175
- response.setStatusCode(HttpStatus.OK);
3176
- const buffer = Buffer.from("UP", "utf-8");
3177
- response.headers.set("Content-Type", "text/plain; charset=utf-8");
3178
- await response.body(buffer);
3179
- } else {
3180
- await next();
3181
- }
3182
- },
3183
- // home page
3184
- async ({ request, response }, next) => {
3185
- if (request.method === "GET" && request.path === "/") {
3186
- response.setStatusCode(HttpStatus.OK);
3187
- const buffer = Buffer.from("io.Gateway Server", "utf-8");
3188
- response.headers.set("Content-Type", "text/plain; charset=utf-8");
3189
- await response.body(buffer);
3190
- } else {
3191
- await next();
3192
- }
3193
- },
3194
- // not found
3195
- async ({ response }, _next) => {
3196
- response.setStatusCode(HttpStatus.NOT_FOUND);
3197
- await response.end();
3198
- }
3199
- );
3200
- return new WebHttpHandlerBuilder(handler).storage(storage);
3201
- }
3202
- var Factory = async (options) => {
3203
- const ssl = options.ssl;
3204
- const createServer = ssl ? (options2, handler) => import_node_https.default.createServer({ ...options2, ...secureContextOptions(ssl) }, handler) : (options2, handler) => import_node_http2.default.createServer(options2, handler);
3205
- const monitor = memoryMonitor(options.memory);
3206
- const context = {
3207
- middleware: [],
3208
- corsConfig: options.cors,
3209
- cors: [],
3210
- authConfig: options.auth,
3211
- authorize: [],
3212
- storage: new import_node_async_hooks4.AsyncLocalStorage(),
3213
- sockets: /* @__PURE__ */ new Map()
3214
- };
3215
- const gw = import_gateway6.IOGateway.Factory({ ...options.gateway });
3216
- if (options.gateway) {
3217
- const config = options.gateway;
3218
- await configure(async (configurer) => {
3219
- configurer.socket({ path: config.route, factory: core_default.bind(gw), options: config });
3220
- }, options, context);
3221
- }
3222
- if (options.app) {
3223
- await configure(options.app, options, context);
3224
- }
3225
- const ports = portRange(options.port ?? 0);
3226
- const host = options.host;
3227
- const onSocketError = (err) => logger6.error(`socket error: ${err}`, err);
3228
- const builder = await initBuilder(context);
3229
- const listener = await createListener(builder, onSocketError);
3230
- const serverP = new Promise((resolve, reject) => {
3231
- const server2 = createServer({
3232
- IncomingMessage: ExtendedHttpIncomingMessage,
3233
- ServerResponse: ExtendedHttpServerResponse,
3234
- ...options.http
3235
- }, listener);
3236
- server2.on("error", (e) => {
3237
- if (e["code"] === "EADDRINUSE") {
3238
- logger6.debug(`port ${e["port"]} already in use on address ${e["address"]}`);
3239
- const { value: port } = ports.next();
3240
- if (port) {
3241
- logger6.info(`retry starting server on port ${port} and host ${host ?? "<unspecified>"}`);
3242
- server2.close();
3243
- server2.listen(port, host);
3244
- } else {
3245
- logger6.warn(`all configured port(s) ${options.port} are in use. closing...`);
3246
- server2.close();
3247
- reject(e);
3248
- }
3249
- } else {
3250
- logger6.error(`server error: ${e.message}`, e);
3251
- reject(e);
3252
- }
3253
- });
3254
- server2.on("listening", async () => {
3255
- const info2 = server2.address();
3256
- for (const [path, route] of context.sockets) {
3257
- const endpoint = `${ssl ? "wss" : "ws"}://${localIp}:${info2.port}${path}`;
3258
- await initRoute(path, route, endpoint, context.storage, onSocketError);
3259
- }
3260
- logger6.info(`http server listening on ${info2.address}:${info2.port}`);
3261
- resolve(server2);
3262
- });
3263
- server2.on("upgrade", (req, _socket, head) => {
3264
- try {
3265
- listener(req, head);
3266
- } catch (err) {
3267
- logger6.error(`upgrade error: ${err}`, err);
3268
- }
3269
- }).on("close", async () => {
3270
- logger6.info(`http server closed.`);
3271
- });
3272
- try {
3273
- const { value: port } = ports.next();
3274
- server2.listen(port, host);
3275
- } catch (e) {
3276
- logger6.error(`error starting web socket server`, e);
3277
- reject(e instanceof Error ? e : new Error(`listen failed: ${e}`));
3278
- }
3279
- });
3280
- const server = await serverP;
3281
- return new class {
3282
- gateway = gw;
3283
- async close() {
3284
- for (const [path, route] of context.sockets) {
3285
- try {
3286
- if (route.close !== void 0) {
3287
- await route.close();
3288
- }
3289
- } catch (e) {
3290
- logger6.warn(`error closing route ${path}`, e);
3291
- }
3292
- }
3293
- await promisify((cb) => {
3294
- server.closeAllConnections();
3295
- server.close(cb);
3296
- });
3297
- if (monitor) {
3298
- await stop(monitor);
3299
- }
3300
- if (gw) {
3301
- await gw.stop();
3302
- }
3303
- }
3304
- }();
3305
- };
3306
-
3307
- // src/index.ts
3308
- var index_default = Factory;
3309
- // Annotate the CommonJS export names for ESM import in node:
3310
- 0 && (module.exports = {
3311
- GatewayServer
3312
- });
1
+ "use strict";var ur=Object.create;var se=Object.defineProperty;var lr=Object.getOwnPropertyDescriptor;var hr=Object.getOwnPropertyNames;var pr=Object.getPrototypeOf,fr=Object.prototype.hasOwnProperty;var at=(t,e)=>{for(var r in e)se(t,r,{get:e[r],enumerable:!0})},ct=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of hr(e))!fr.call(t,o)&&o!==r&&se(t,o,{get:()=>e[o],enumerable:!(n=lr(e,o))||n.enumerable});return t};var Z=(t,e,r)=>(r=t!=null?ur(pr(t)):{},ct(e||!t||!t.__esModule?se(r,"default",{value:t,enumerable:!0}):r,t)),gr=t=>ct(se({},"__esModule",{value:!0}),t);var $n={};at($n,{GatewayServer:()=>st,default:()=>In});module.exports=gr($n);var st={};at(st,{Factory:()=>it});var sr=Z(require("node:http"),1),ar=Z(require("node:https"),1),Ne=require("node:fs"),cr=require("node:async_hooks"),dr=require("@interopio/gateway");var Fe=Z(require("@interopio/gateway/logging/core"),1);function b(t){return Fe.getLogger(`gateway.server.${t}`)}function dt(t,e){return e instanceof RegExp?e.toString():e}var ut=require("@interopio/gateway"),lt=require("node:async_hooks"),mr=ut.IOGateway.Encoding,M=b("ws"),yr=mr.json();function Sr(t){let e;if(t.authenticated&&(e=t.name,e===void 0&&t.principal!==void 0)){let r=t.principal;typeof r=="object"&&(e=r.name),e===void 0&&(r===void 0?e="":e=String(r))}return e}function wr(t,e,r){let n=`${r?.address}:${r?.port}`,o=r?.address??"<unknown>",s={key:n,host:o,codec:yr,onAuthenticate:async()=>{let i=await e();if(i?.authenticated)return{type:"success",user:Sr(i)};throw new Error(`no valid client authentication ${n}`)},onPing:()=>{t.ping(i=>{i?M.warn(`failed to ping ${n}`,i):M.info(`ping sent to ${n}`)})},onDisconnect:i=>{switch(i){case"inactive":{M.warn(`no heartbeat (ping) received from ${n}, closing socket`),t.close(4001,"ping expected");break}case"shutdown":{t.close(1001,"shutdown");break}}}};try{return this.client(i=>t.send(i),s)}catch(i){M.warn(`${n} failed to create client`,i)}}async function br(t){return M.info(`starting gateway on ${t.endpoint}`),await this.start(t),async({socket:e,handshake:r})=>{let{logPrefix:n,remoteAddress:o,principal:s}=r;M.info(`${n}connected on gw using ${o?.address}`);let i=wr.call(this,e,s,o);if(!i){M.error(`${n}gw client init failed`),e.terminate();return}e.on("error",c=>{M.error(`${n}websocket error: ${c}`,c)});let a=t.storage!==void 0?lt.AsyncLocalStorage.snapshot():void 0;e.on("message",(c,d)=>{Array.isArray(c)&&(c=Buffer.concat(c)),a!==void 0?a(()=>i.send(c)):i.send(c)}),e.on("close",c=>{M.info(`${n}disconnected from gw. code: ${c}`),i.close()})}}var ht=br;function pt(...t){if(!Array.isArray(t))throw new Error("middleware must be array!");let e=t.flat();for(let r of e)if(typeof r!="function")throw new Error("middleware must be compose of functions!");return async function(r,n){let o=async(s,i)=>{let a=s===e.length?n:e[s];if(a===void 0)return;let c=!1,d=!1,l=await a(i,async g=>{if(c)throw new Error("next() called multiple times");c=!0;try{return await o(s+1,g??i)}finally{d=!0}});if(c&&!d)throw new Error(`middleware resolved before downstream.
2
+ You are probably missing an await or return statement in your middleware function.`);return l};return o(0,r)}}var ue=require("tough-cookie");function vr(t,e){let r=t.get("x-forwarded-for");if(r===void 0){if(r=t.get("x-forwarded-host"),Array.isArray(r)&&(r=r[0]),r){let n=t.one("x-forwarded-port");n&&(r=`${r}:${n}`)}r??=t.one("host")}return Array.isArray(r)&&(r=r[0]),r?r.split(",",1)[0].trim():e}function xr(t,e){let r=t.get("x-forwarded-proto");return Array.isArray(r)&&(r=r[0]),r!==void 0?r.split(",",1)[0].trim():e}var ae=class{#e;constructor(e){this.#e=e}get headers(){return this.#e}},ce=class t extends ae{static logIdCounter=0;#e;get id(){return this.#e===void 0&&(this.#e=`${this.initId()}-${++t.logIdCounter}`),this.#e}initId(){return"request"}get cookies(){return Cr(this.headers)}parseHost(e){return vr(this.headers,e)}parseProtocol(e){return xr(this.headers,e)}},de=class extends ae{get cookies(){return Ar(this.headers)}setCookieValue(e){return new ue.Cookie({key:e.name,value:e.value,maxAge:e.maxAge,domain:e.domain,path:e.path,secure:e.secure,httpOnly:e.httpOnly,sameSite:e.sameSite}).toString()}};function Er(t){let e=[];{let r=0,n=0;for(let o=0;o<t.length;o++)switch(t.charCodeAt(o)){case 32:r===n&&(r=n=o+1);break;case 44:e.push(t.slice(r,n)),r=n=o+1;break;default:n=n+1;break}e.push(t.slice(r,n))}return e}function ft(t){typeof t=="string"&&(t=[t]),typeof t=="number"&&(t=[String(t)]);let e=[];if(t)for(let r of t)r&&e.push(...Er(r));return e}function Cr(t){return t.list("cookie").map(e=>e.split(";").map(r=>ue.Cookie.parse(r))).flat(1).filter(e=>e!==void 0).map(e=>Object.freeze({name:e.key,value:e.value}))}function Ar(t){return t.list("set-cookie").map(e=>{let r=ue.Cookie.parse(e);if(r){let n={name:r.key,value:r.value,maxAge:Number(r.maxAge??-1)};return r.httpOnly&&(n.httpOnly=!0),r.domain&&(n.domain=r.domain),r.path&&(n.path=r.path),r.secure&&(n.secure=!0),r.httpOnly&&(n.httpOnly=!0),r.sameSite&&(n.sameSite=r.sameSite),Object.freeze(n)}}).filter(e=>e!==void 0)}var ee=class{constructor(){}toList(e){let r=this.get(e);return ft(r)}},v=class extends Map{get(e){return super.get(e.toLowerCase())}one(e){return this.get(e)?.[0]}list(e){let r=super.get(e.toLowerCase());return ft(r)}set(e,r){return typeof r=="number"&&(r=String(r)),typeof r=="string"&&(r=[r]),r?super.set(e.toLowerCase(),r):(super.delete(e.toLowerCase()),this)}add(e,r){let n=super.get(e.toLowerCase());return typeof r=="string"&&(r=[r]),n&&(r=n.concat(r)),this.set(e,r),this}};var Be=class{#e;constructor(e){this.#e=e}get value(){return this.#e}toString(){return this.#e.toString()}},f=class t{static CONTINUE=new t(100,"Continue");static SWITCHING_PROTOCOLS=new t(101,"Switching Protocols");static OK=new t(200,"OK");static CREATED=new t(201,"Created");static ACCEPTED=new t(202,"Accepted");static NON_AUTHORITATIVE_INFORMATION=new t(203,"Non-Authoritative Information");static NO_CONTENT=new t(204,"No Content");static RESET_CONTENT=new t(205,"Reset Content");static PARTIAL_CONTENT=new t(206,"Partial Content");static MULTI_STATUS=new t(207,"Multi-Status");static IM_USED=new t(226,"IM Used");static MULTIPLE_CHOICES=new t(300,"Multiple Choices");static MOVED_PERMANENTLY=new t(301,"Moved Permanently");static BAD_REQUEST=new t(400,"Bad Request");static UNAUTHORIZED=new t(401,"Unauthorized");static FORBIDDEN=new t(403,"Forbidden");static NOT_FOUND=new t(404,"Not Found");static METHOD_NOT_ALLOWED=new t(405,"Method Not Allowed");static NOT_ACCEPTABLE=new t(406,"Not Acceptable");static PROXY_AUTHENTICATION_REQUIRED=new t(407,"Proxy Authentication Required");static REQUEST_TIMEOUT=new t(408,"Request Timeout");static CONFLICT=new t(409,"Conflict");static GONE=new t(410,"Gone");static LENGTH_REQUIRED=new t(411,"Length Required");static PRECONDITION_FAILED=new t(412,"Precondition Failed");static PAYLOAD_TOO_LARGE=new t(413,"Payload Too Large");static URI_TOO_LONG=new t(414,"URI Too Long");static UNSUPPORTED_MEDIA_TYPE=new t(415,"Unsupported Media Type");static EXPECTATION_FAILED=new t(417,"Expectation Failed");static IM_A_TEAPOT=new t(418,"I'm a teapot");static TOO_EARLY=new t(425,"Too Early");static UPGRADE_REQUIRED=new t(426,"Upgrade Required");static PRECONDITION_REQUIRED=new t(428,"Precondition Required");static TOO_MANY_REQUESTS=new t(429,"Too Many Requests");static REQUEST_HEADER_FIELDS_TOO_LARGE=new t(431,"Request Header Fields Too Large");static UNAVAILABLE_FOR_LEGAL_REASONS=new t(451,"Unavailable For Legal Reasons");static INTERNAL_SERVER_ERROR=new t(500,"Internal Server Error");static NOT_IMPLEMENTED=new t(501,"Not Implemented");static BAD_GATEWAY=new t(502,"Bad Gateway");static SERVICE_UNAVAILABLE=new t(503,"Service Unavailable");static GATEWAY_TIMEOUT=new t(504,"Gateway Timeout");static HTTP_VERSION_NOT_SUPPORTED=new t(505,"HTTP Version Not Supported");static VARIANT_ALSO_NEGOTIATES=new t(506,"Variant Also Negotiates");static INSUFFICIENT_STORAGE=new t(507,"Insufficient Storage");static LOOP_DETECTED=new t(508,"Loop Detected");static NOT_EXTENDED=new t(510,"Not Extended");static NETWORK_AUTHENTICATION_REQUIRED=new t(511,"Network Authentication Required");static#e=[];static{Object.keys(t).filter(e=>e!=="VALUES"&&e!=="resolve").forEach(e=>{let r=t[e];r instanceof t&&(Object.defineProperty(r,"name",{enumerable:!0,value:e,writable:!1}),t.#e.push(r))})}static resolve(e){for(let r of t.#e)if(r.value===e)return r}#r;#t;constructor(e,r){this.#r=e,this.#t=r}get value(){return this.#r}get phrase(){return this.#t}toString(){return`${this.#r} ${this.name}`}};function gt(t){if(typeof t=="number"){if(t<100||t>999)throw new Error(`status code ${t} should be in range 100-999`);let e=f.resolve(t);return e!==void 0?e:new Be(t)}return t}var Se=Z(require("node:http"),1),le=class extends Se.default.IncomingMessage{exchange;upgradeHead;get urlBang(){return this.url}get socketEncrypted(){return this.socket.encrypted===!0}},q=class extends Se.default.ServerResponse{markHeadersSent(){this._header=!0}getRawHeaderNames(){return super.getRawHeaderNames()}},he=class extends ce{},pe=class extends de{#e=[];#r;#t="new";#o=[];setStatusCode(e){return this.#t==="committed"?!1:(this.#r=e,!0)}setRawStatusCode(e){return this.setStatusCode(e===void 0?void 0:gt(e))}get statusCode(){return this.#r}addCookie(e){if(this.#t==="committed")throw new Error(`Cannot add cookie ${JSON.stringify(e)} because HTTP response has already been committed`);return this.#e.push(e),this}beforeCommit(e){this.#o.push(e)}get commited(){let e=this.#t;return e!=="new"&&e!=="commit-action-failed"}async body(e){if(e instanceof ReadableStream)throw new Error("ReadableStream body not supported yet");let r=await e;try{return await this.doCommit(async()=>await this.bodyInternal(Promise.resolve(r))).catch(n=>{throw n})}catch(n){throw n}}async end(){return this.commited?Promise.resolve(!1):this.doCommit(async()=>await this.bodyInternal(Promise.resolve()))}doCommit(e){let r=this.#t,n=Promise.resolve();if(r==="new")this.#t="committing",this.#o.length>0&&(n=this.#o.reduce((o,s)=>o.then(()=>s()),Promise.resolve()).catch(o=>{this.#t==="committing"&&(this.#t="commit-action-failed")}));else if(r==="commit-action-failed")this.#t="committing";else return Promise.resolve(!1);return n=n.then(()=>{this.applyStatusCode(),this.applyHeaders(),this.applyCookies(),this.#t="committed"}),n.then(async()=>e!==void 0?await e():!0)}applyStatusCode(){}applyHeaders(){}applyCookies(){}},_=class extends he{#e;#r;#t;constructor(e){super(new De(e)),this.#t=e}getNativeRequest(){return this.#t}get upgrade(){return this.#t.upgrade}get http2(){return this.#t.httpVersionMajor>=2}get path(){return this.URL?.pathname}get URL(){return this.#e??=new URL(this.#t.urlBang,`${this.protocol}://${this.host}`),this.#e}get query(){return this.URL?.search}get method(){return this.#t.method}get host(){let e;return this.#t.httpVersionMajor>=2&&(e=this.#t.headers[":authority"]),e??=this.#t.socket.remoteAddress,super.parseHost(e)}get protocol(){let e;return this.#t.httpVersionMajor>2&&(e=this.#t.headers[":scheme"]),e??=this.#t.socketEncrypted?"https":"http",super.parseProtocol(e)}get socket(){return this.#t.socket}get remoteAddress(){let e=this.#t.socket.remoteFamily,r=this.#t.socket.remoteAddress,n=this.#t.socket.remotePort;if(!(!e||!r||!n))return{family:e,address:r,port:n}}get cookies(){return this.#r??=super.cookies,this.#r}get body(){return Se.default.IncomingMessage.toWeb(this.#t)}async blob(){let e=[];if(this.body!==void 0)for await(let r of this.body)e.push(r);return new Blob(e,{type:this.headers.one("content-type")||"application/octet-stream"})}async text(){return await(await this.blob()).text()}async formData(){let r=await(await this.blob()).text();return new URLSearchParams(r)}async json(){let e=await this.blob();if(e.size===0)return;let r=await e.text();return JSON.parse(r)}initId(){let e=this.#t.socket.remoteAddress;if(!e)throw new Error("Socket has no remote address");return`${e}:${this.#t.socket.remotePort}`}},De=class extends ee{#e;constructor(e){super(),this.#e=e}has(e){return this.#e.headers[e]!==void 0}get(e){return this.#e.headers[e]}list(e){return super.toList(e)}one(e){let r=this.#e.headers[e];return Array.isArray(r)?r[0]:r}keys(){return Object.keys(this.#e.headers).values()}},Ue=class extends ee{#e;constructor(e){super(),this.#e=e}has(e){return this.#e.hasHeader(e)}keys(){return this.#e.getHeaderNames().values()}get(e){return this.#e.getHeader(e)}one(e){let r=this.#e.getHeader(e);return Array.isArray(r)?r[0]:r}set(e,r){return this.#e.headersSent||(Array.isArray(r)?r=r.map(n=>typeof n=="number"?String(n):n):typeof r=="number"&&(r=String(r)),r?this.#e.setHeader(e,r):this.#e.removeHeader(e)),this}add(e,r){return this.#e.headersSent||this.#e.appendHeader(e,r),this}list(e){return super.toList(e)}},fe=class extends pe{#e;constructor(e){super(new Ue(e)),this.#e=e}getNativeResponse(){return this.#e}get statusCode(){return super.statusCode??{value:this.#e.statusCode}}applyStatusCode(){let e=super.statusCode;e!==void 0&&(this.#e.statusCode=e.value)}addCookie(e){return this.headers.add("Set-Cookie",super.setCookieValue(e)),this}async bodyInternal(e){if(this.#e.headersSent)return!1;if(e instanceof ReadableStream)throw new Error("ReadableStream body not supported in response");{let r=await e;return await new Promise((n,o)=>{try{r===void 0?this.#e.end(()=>{n(!0)}):(this.headers.has("content-length")||(typeof r=="string"?this.headers.set("content-length",Buffer.byteLength(r)):r instanceof Blob?this.headers.set("content-length",r.size):this.headers.set("content-length",r.byteLength)),this.#e.end(r,()=>{n(!0)}))}catch(s){o(s instanceof Error?s:new Error(`end failed: ${s}`))}})}}},ge=class t{#e;constructor(e){this.#e=e}get delegate(){return this.#e}get id(){return this.#e.id}get method(){return this.#e.method}get path(){return this.#e.path}get protocol(){return this.#e.protocol}get host(){return this.#e.host}get URL(){return this.#e.URL}get headers(){return this.#e.headers}get cookies(){return this.#e.cookies}get remoteAddress(){return this.#e.remoteAddress}get upgrade(){return this.#e.upgrade}get body(){return this.#e.body}async blob(){return await this.#e.blob()}async text(){return await this.#e.text()}async formData(){return await this.#e.formData()}async json(){return await this.#e.json()}toString(){return`${t.name} [delegate: ${this.delegate.toString()}]`}static getNativeRequest(e){if(e instanceof he)return e.getNativeRequest();if(e instanceof t)return t.getNativeRequest(e.delegate);throw new Error(`Cannot get native request from ${e.constructor.name}`)}},z=class t{#e;constructor(e){this.#e=e}get delegate(){return this.#e}setStatusCode(e){return this.delegate.setStatusCode(e)}setRawStatusCode(e){return this.delegate.setRawStatusCode(e)}get statusCode(){return this.delegate.statusCode}get cookies(){return this.delegate.cookies}addCookie(e){return this.delegate.addCookie(e),this}async end(){return await this.delegate.end()}async body(e){return await this.#e.body(e)}get headers(){return this.#e.headers}toString(){return`${t.name} [delegate: ${this.delegate.toString()}]`}static getNativeResponse(e){if(e instanceof pe)return e.getNativeResponse();if(e instanceof t)return t.getNativeResponse(e.delegate);throw new Error(`Cannot get native response from ${e.constructor.name}`)}},me=class t{#e;constructor(e){this.#e=e}get delegate(){return this.#e}get request(){return this.#e.request}get response(){return this.#e.response}attribute(e){return this.#e.attribute(e)}principal(){return this.#e.principal()}get logPrefix(){return this.#e.logPrefix}toString(){return`${t.name} [delegate: ${this.delegate}]`}},ye=class{request;response;#e={};#r;#t="";constructor(e,r){this.#e[mt]=e.id,this.request=e,this.response=r}get method(){return this.request.method}get path(){return this.request.path}get attributes(){return this.#e}attribute(e){return this.attributes[e]}principal(){return Promise.resolve(void 0)}get logPrefix(){let e=this.attribute(mt);return this.#r!==e&&(this.#r=e,this.#t=e!==void 0?`[${e}] `:""),this.#t}},mt="io.interop.gateway.server.log_id";var yt=require("node:os"),Hr=/^(\d+|(0x[\da-f]+))(-(\d+|(0x[\da-f]+)))?$/i;function qe(t){if(t>65535)throw new Error(`bad port ${t}`);return t}function*St(t){if(typeof t=="string")for(let e of t.split(",")){let r=e.trim(),n=Hr.exec(r);if(n){let o=parseInt(n[1]),s=parseInt(n[4]??n[1]);for(let i=qe(o);i<qe(s)+1;i++)yield i}else throw new Error(`'${e}' is not a valid port or range.`)}else yield qe(t)}var wt=(()=>{function t(r){return r.length>0?r[0]:void 0}let e=Object.values((0,yt.networkInterfaces)()).flatMap(r=>(r??[]).filter(n=>n.family==="IPv4")).reduce((r,n)=>(r[n.internal?"internal":"external"].push(n),r),{internal:[],external:[]});return(t(e.internal)??t(e.external))?.address})();var we=require("node:v8"),W=require("node:fs/promises"),y=b("monitoring"),Pr={memoryLimit:1024*1024*1024,reportInterval:600*1e3,dumpLocation:".",maxBackups:10,dumpPrefix:"Heap"};function Rr(){return(0,we.getHeapStatistics)()}async function bt(t){let e=t.dumpPrefix??"Heap",r=`${t.dumpLocation}/${e}.heapsnapshot`;y.enabledFor("debug")&&y.debug(`starting heap dump in ${r}`),await _e(t.dumpLocation).catch(async o=>{y.enabledFor("debug")&&y.debug(`dump location ${t.dumpLocation} does not exists. Will try to create it`);try{await(0,W.mkdir)(t.dumpLocation,{recursive:!0}),y.info(`dump location dir ${t.dumpLocation} successfully created`)}catch{y.error(`failed to create dump location ${t.dumpLocation}`)}});let n=(0,we.writeHeapSnapshot)(r);y.info("heap dumped");try{y.debug("rolling snapshot backups");let o=`${t.dumpLocation}/${e}.${t.maxBackups}.heapsnapshot`;await _e(o).then(async()=>{y.enabledFor("debug")&&y.debug(`deleting ${o}`);try{await(0,W.unlink)(o)}catch(i){y.warn(`failed to delete ${o}`,i)}}).catch(()=>{});for(let i=t.maxBackups-1;i>0;i--){let a=`${t.dumpLocation}/${e}.${i}.heapsnapshot`,c=`${t.dumpLocation}/${e}.${i+1}.heapsnapshot`;await _e(a).then(async()=>{try{await(0,W.rename)(a,c)}catch(d){y.warn(`failed to rename ${a} to ${c}`,d)}}).catch(()=>{})}let s=`${t.dumpLocation}/${e}.1.heapsnapshot`;try{await(0,W.rename)(n,s)}catch(i){y.warn(`failed to rename ${n} to ${s}`,i)}y.debug("snapshots rolled")}catch(o){throw y.error("error rolling backups",o),o}}async function _e(t){y.enabledFor("trace")&&y.debug(`checking file ${t}`),await(0,W.access)(t)}async function Tr(t,e,r){y.enabledFor("debug")&&y.debug(`processing heap stats ${JSON.stringify(t)}`);let n=Math.min(r.memoryLimit,.95*t.heap_size_limit),o=t.used_heap_size;y.info(`heap stats ${JSON.stringify(t)}`),o>=n?(y.warn(`used heap ${o} bytes exceeds memory limit ${n} bytes`),e.memoryLimitExceeded?delete e.snapshot:(e.memoryLimitExceeded=!0,e.snapshot=!0),await bt(r)):(e.memoryLimitExceeded=!1,delete e.snapshot)}function vt(t){let e={...Pr,...t},r=!1,n={memoryLimitExceeded:!1},o=async()=>{let a=Rr();await Tr(a,n,e)},s=setInterval(o,e.reportInterval);return{...e,channel:async a=>{if(!r)switch(a??="run",a){case"run":{await o();break}case"dump":{await bt(e);break}case"stop":{r=!0,clearInterval(s),y.info("exit memory diagnostic");break}}return r}}}async function kr({channel:t},e){await t(e)||y.warn(`cannot execute command "${e}" already closed`)}async function xt(t){return await kr(t,"stop")}var ze=Z(require("@interopio/gateway-server/package.json"),1),Mr=t=>(t??=`${ze.default.name} - v${ze.default.version}`,async({response:e},r)=>{t!==!1&&!e.headers.has("server")&&e.headers.set("Server",t),await r()}),Et=t=>Mr(t);var te=require("@interopio/gateway");var Ge=b("gateway.ws.client-verify");function Wr(t){switch(t.missing){case"allow":case"whitelist":return!0;case"block":case"blacklist":return!1;default:return!1}}function Lr(t,e){let r=t.block??t.blacklist,n=t.allow??t.whitelist;if(r.length>0&&te.IOGateway.Filtering.valuesMatch(r,e))return Ge.warn(`origin ${e} matches block filter`),!1;if(n.length>0&&te.IOGateway.Filtering.valuesMatch(n,e))return Ge.enabledFor("debug")&&Ge.debug(`origin ${e} matches allow filter`),!0}function Ir(t){switch(t.non_matched){case"allow":case"whitelist":return!0;case"block":case"blacklist":return!1;default:return!1}}function Ct(t,e){if(!e)return!0;if(t){let r=Lr(e,t);return r||Ir(e)}else return Wr(e)}function At(t){if(t){let e=(t.block??t.blacklist??[]).map(te.IOGateway.Filtering.regexify),r=(t.allow??t.whitelist??[]).map(te.IOGateway.Filtering.regexify);return{non_matched:t.non_matched??"allow",missing:t.missing??"allow",allow:r,block:e}}}var Ht=t=>async e=>{for(let r of t)if((await r(e)).match)return A();return E},G=t=>{let e=async r=>{for(let n of t)if(!(await n(r)).match)return E;return A()};return e.toString=()=>`and(${t.map(r=>r.toString()).join(", ")})`,e},Pt=t=>async e=>(await t(e)).match?E:A(),re=async t=>A();re.toString=()=>"any-exchange";var Rt=Object.freeze({}),E=Object.freeze({match:!1,variables:Rt}),A=(t=Rt)=>({match:!0,variables:t}),H=(t,e)=>{let r=e?.method,n=async o=>{let s=o.request,i=s.path;if(r!==void 0&&s.method!==r)return E;if(typeof t=="string")return i===t?A():E;{let a=t.exec(i);return a===null?E:{match:!0,variables:{...a.groups}}}};return n.toString=()=>`pattern(${t.toString()}, method=${r??"<any>"})`,n},je=t=>{let e=r=>{if(t.ignoredMediaTypes!==void 0){for(let n of t.ignoredMediaTypes)if(r===n||n==="*/*")return!0}return!1};return async r=>{let n=r.request,o;try{o=n.headers.list("accept")}catch{return E}for(let s of o)if(!e(s)){for(let i of t.mediaTypes)if(s.startsWith(i))return A()}return E}},D=async({request:t})=>t.upgrade&&t.headers.one("upgrade")?.toLowerCase()==="websocket"?A():E;D.toString=()=>"websocket upgrade";var Ve=require("@interopio/gateway");async function Je(t,e,r){let n=(s,i)=>{if(i?.cors){let a=i.cors===!0?{allowOrigins:i.origins?.allow?.map(Ve.IOGateway.Filtering.regexify),allowMethods:s.method===void 0?["*"]:[s.method],allowCredentials:i.authorize?.access!=="permitted"?!0:void 0}:i.cors,c=s.path;r.cors.push([c,a])}},o=new class{handle(...s){s.forEach(({request:i,options:a,handler:c})=>{let d=H(Ve.IOGateway.Filtering.regexify(i.path),{method:i.method});a?.authorize&&r.authorize.push([d,a.authorize]),n(i,a);let u=async(l,g)=>{let{match:p,variables:h}=await d(l);p?await c(l,h):await g()};r.middleware.push(u)})}socket(...s){for(let{path:i,factory:a,options:c}of s){let d=i??"/";r.sockets.set(d,{default:i===void 0,ping:c?.ping,factory:a,maxConnections:c?.maxConnections,authorize:c?.authorize,originFilters:At(c?.origins)})}}};await t(o,e)}var xe=require("@interopio/gateway");function Nr(t){let e=t.headers.one("origin");if(e===void 0)return!0;let r=t.URL,n=r.protocol,o=r.host,s=URL.parse(e),i=s?.host,a=s?.protocol;return n===a&&o===i}function Fr(t){return t.headers.has("origin")&&!Nr(t)}function kt(t){return t.method==="OPTIONS"&&t.headers.has("origin")&&t.headers.has("access-control-request-method")}var Tt=["Origin","Access-Control-Request-Method","Access-Control-Request-Headers"],Br=(t,e)=>{let{request:r,response:n}=t,o=n.headers;if(!o.has("Vary"))o.set("Vary",Tt.join(", "));else{let i=o.list("Vary");for(let a of Tt)i.find(c=>c===a)||i.push(a);o.set("Vary",i.join(", "))}try{if(!Fr(r))return!0}catch{return P.enabledFor("debug")&&P.debug("reject: origin is malformed"),ne(n),!1}if(o.has("access-control-allow-origin"))return P.enabledFor("trace")&&P.debug('skip: already contains "Access-Control-Allow-Origin"'),!0;let s=kt(r);return e?Ur(t,e,s):s?(ne(n),!1):!0},ve=["*"],Qe=["GET","HEAD","POST"],Ot={allowOrigins:ve,allowMethods:Qe,allowHeaders:ve,maxAge:1800};function Ee(t){if(t){let e=t.allowHeaders;e&&e!==S&&(t={...t,allowHeaders:e.map(n=>n.toLowerCase())});let r=t.allowOrigins;return r&&(r==="*"?(Wt(t),Lt(t)):t={...t,allowOrigins:r.map(n=>typeof n=="string"&&n!==S&&(n=xe.IOGateway.Filtering.regexify(n),typeof n=="string")?It(n).toLowerCase():n)}),t}}function be(t,e){if(e===void 0)return t!==void 0?t===S?[S]:t:[];if(t===void 0)return e===S?[S]:e;if(t==ve||t===Qe)return e===S?[S]:e;if(e==ve||e===Qe)return t===S?[S]:t;if(t===S||t.includes(S)||e===S||e.includes(S))return[S];let r=new Set;return t.forEach(n=>r.add(n)),e.forEach(n=>r.add(n)),Array.from(r)}var oe=(t,e)=>e===void 0?t:{allowOrigins:be(t.allowOrigins,e?.allowOrigins),allowMethods:be(t.allowMethods,e?.allowMethods),allowHeaders:be(t.allowHeaders,e?.allowHeaders),exposeHeaders:be(t.exposeHeaders,e?.exposeHeaders),allowCredentials:e?.allowCredentials??t.allowCredentials,allowPrivateNetwork:e?.allowPrivateNetwork??t.allowPrivateNetwork,maxAge:e?.maxAge??t.maxAge},Dr=t=>{let e=t.corsConfigSource,r=t.corsProcessor??Br;return async(n,o)=>{let s=await e(n);!r(n,s)||kt(n.request)||await o()}},Mt=Dr,P=b("cors");function ne(t){t.setStatusCode(f.FORBIDDEN)}function Ur(t,e,r){let{request:n,response:o}=t,s=o.headers,i=n.headers.one("origin"),a=_r(e,i);if(a===void 0)return P.enabledFor("debug")&&P.debug(`reject: '${i}' origin is not allowed`),ne(o),!1;let c=jr(n,r),d=zr(e,c);if(d===void 0)return P.enabledFor("debug")&&P.debug(`reject: HTTP '${c}' is not allowed`),ne(o),!1;let u=Vr(n,r),l=Gr(e,u);if(r&&l===void 0)return P.enabledFor("debug")&&P.debug(`reject: headers '${u}' are not allowed`),ne(o),!1;s.set("Access-Control-Allow-Origin",a),r&&s.set("Access-Control-Allow-Methods",d.join(",")),r&&l!==void 0&&l.length>0&&s.set("Access-Control-Allow-Headers",l.join(", "));let g=e.exposeHeaders;return g&&g.length>0&&s.set("Access-Control-Expose-Headers",g.join(", ")),e.allowCredentials&&s.set("Access-Control-Allow-Credentials","true"),e.allowPrivateNetwork&&n.headers.one("access-control-request-private-network")==="true"&&s.set("Access-Control-Allow-Private-Network","true"),r&&e.maxAge!==void 0&&s.set("Access-Control-Max-Age",e.maxAge.toString()),!0}var S="*",qr=["GET","HEAD"];function Wt(t){if(t.allowCredentials===!0&&t.allowOrigins===S)throw new Error('when allowCredentials is true allowOrigins cannot be "*"')}function Lt(t){if(t.allowPrivateNetwork===!0&&t.allowOrigins===S)throw new Error('when allowPrivateNetwork is true allowOrigins cannot be "*"')}function _r(t,e){if(e){let r=t.allowOrigins;if(r){if(r===S)return Wt(t),Lt(t),S;let n=It(e.toLowerCase());for(let o of r)if(o===S||xe.IOGateway.Filtering.valueMatches(o,n))return e}}}function zr(t,e){if(e){let r=t.allowMethods??qr;if(r===S)return[e];if(xe.IOGateway.Filtering.valuesMatch(r,e))return r}}function Gr(t,e){if(e===void 0)return;if(e.length==0)return[];let r=t.allowHeaders;if(r===void 0)return;let n=r===S||r.includes(S),o=[];for(let s of e){let i=s?.trim();if(i){if(n)o.push(i);else for(let a of r)if(i.toLowerCase()===a){o.push(i);break}}}if(o.length>0)return o}function It(t){return t.endsWith("/")?t.slice(0,-1):t}function jr(t,e){return e?t.headers.one("access-control-request-method"):t.method}function Vr(t,e){let r=t.headers;return e?r.list("access-control-request-headers"):Array.from(r.keys())}var $t=t=>async e=>{for(let[r,n]of t.mappings)if((await r(e)).match)return P.debug(`resolved cors config on '${e.request.path}' using ${r}: ${JSON.stringify(n)}`),n};var Nt=require("@interopio/gateway");function Ft(t){let{sockets:e,cors:r}=t,n=t.corsConfig===!1?void 0:oe(Ot,t.corsConfig),o=[];for(let[i,a]of e){let c=n;for(let[u,l]of r)Nt.IOGateway.Filtering.valueMatches(u,i)&&(l===void 0?c=void 0:c=c===void 0?l:oe(c,l));let d=t.corsConfig===!1?void 0:{allowOrigins:a.originFilters?.allow,allowMethods:["GET","CONNECT","OPTIONS"],allowHeaders:["Upgrade","Connection","Origin","Sec-Websocket-Key","Sec-Websocket-Version","Sec-Websocket-Protocol","Sec-Websocket-Extensions"],exposeHeaders:["Sec-Websocket-Accept","Sec-Websocket-Protocol","Sec-Websocket-Extensions"],allowCredentials:a.authorize?.access!=="permitted"?!0:void 0};c=c===void 0?d:oe(c,d),o.push([G([D,H(i)]),Ee(c)])}let s=[];for(let[i,a]of r){let[,c]=s.find(([u])=>String(u)===String(i))??[i,n];c=c===void 0?a:oe(c,a);let d=!1;for(let u of s)if(String(u[0])===String(i)){u[1]=c,d=!0;break}d||s.push([i,c])}for(let[i,a]of s)o.push([H(i),Ee(a)]);return o.push([H(/\/api\/.*/),Ee(n)]),$t({mappings:o})}function Bt(t){return t!==void 0&&typeof t.type=="string"&&typeof t.authenticated=="boolean"}var C=class extends Error{_authentication;get authentication(){return this._authentication}set authentication(e){if(e===void 0)throw new TypeError("Authentication cannot be undefined");this._authentication=e}},Ce=class extends C{},Ae=class extends C{};var U=class extends Error{},L=class{constructor(e){this.granted=e}granted},N=class{#e;constructor(e){this.#e=e}async verify(e,r){if(!(await this.#e(e,r))?.granted)throw new U("Access denied")}async authorize(e,r){return await this.#e(e,r)}},j=class extends C{};var R=t=>async e=>{let r=!0,{response:n}=e;for(let o of t.keys())n.headers.has(o)&&(r=!1);if(r)for(let[o,s]of t)n.headers.set(o,s)},Jr=()=>R(new v().add("cache-control","no-cache, no-store, max-age=0, must-revalidate").add("pragma","no-cache").add("expires","0")),Qr=()=>R(new v().add("x-content-type-options","nosniff")),Yr=(t,e,r)=>{let n=`max-age=${t}`;e&&(n+=" ; includeSubDomains"),r&&(n+=" ; preload");let o=R(new v().add("strict-transport-security",n)),s=i=>i.request.URL.protocol==="https:";return async i=>{s(i)&&await o(i)}},Kr=t=>R(new v().add("x-frame-options",t)),Xr=t=>R(new v().add("x-xss-protection",t)),Zr=t=>{let e=t===void 0?void 0:R(new v().add("permissions-policy",t));return async r=>{e!==void 0&&await e(r)}},en=(t,e)=>{let r=e?"content-security-policy-report-only":"content-security-policy",n=t===void 0?void 0:R(new v().add(r,t));return async o=>{n!==void 0&&await n(o)}},tn=(t="no-referrer")=>R(new v().add("referer-policy",t)),rn=t=>{let e=t===void 0?void 0:R(new v().add("cross-origin-opener-policy",t));return async r=>{e!==void 0&&await e(r)}},nn=t=>{let e=t===void 0?void 0:R(new v().add("cross-origin-embedder-policy",t));return async r=>{e!==void 0&&await e(r)}},on=t=>{let e=t===void 0?void 0:R(new v().add("cross-origin-resource-policy",t));return async r=>{e!==void 0&&await e(r)}},sn=(...t)=>async e=>{for(let r of t)await r(e)};function Ye(t){let e=[];t?.cache?.disabled||e.push(Jr()),t?.contentType?.disabled||e.push(Qr()),t?.hsts?.disabled||e.push(Yr(t?.hsts?.maxAge??365*24*60*60,t?.hsts?.includeSubDomains??!0,t?.hsts?.preload??!1)),t?.frameOptions?.disabled||e.push(Kr(t?.frameOptions?.mode??"DENY")),t?.xss?.disabled||e.push(Xr(t?.xss?.headerValue??"0")),t?.permissionsPolicy?.disabled||e.push(Zr(t?.permissionsPolicy?.policyDirectives)),t?.contentSecurityPolicy?.disabled||e.push(en(t?.contentSecurityPolicy?.policyDirectives??"default-src 'self'",t?.contentSecurityPolicy?.reportOnly)),t?.refererPolicy?.disabled||e.push(tn(t?.refererPolicy?.policy??"no-referrer")),t?.crossOriginOpenerPolicy?.disabled||e.push(rn(t?.crossOriginOpenerPolicy?.policy)),t?.crossOriginEmbedderPolicy?.disabled||e.push(nn(t?.crossOriginEmbedderPolicy?.policy)),t?.crossOriginResourcePolicy?.disabled||e.push(on(t?.crossOriginResourcePolicy?.policy)),t?.writers&&e.push(...t.writers);let r=sn(...e);return async(n,o)=>{await r(n),await o()}}var V=t=>{let e=t.entryPoint,r=t?.rethrowAuthenticationServiceError??!0;return async({exchange:n},o)=>{if(!r||!(o instanceof j))return e(n,o);throw o}};var an="Realm",cn=t=>`Basic realm="${t}"`,J=t=>{let e=cn(t?.realm??an);return async(r,n)=>{let{response:o}=r;o.setStatusCode(f.UNAUTHORIZED),o.headers.set("WWW-Authenticate",e)}};var Dt="Basic ",He=t=>async e=>{let{request:r}=e,n=r.headers.one("authorization");if(!n||!/basic/i.test(n.substring(0)))return;let o=n.length<=Dt.length?"":n.substring(Dt.length),i=Buffer.from(o,"base64").toString(t?.credentialsEncoding??"utf-8").split(":",2);if(i.length===2)return{type:"UsernamePassword",authenticated:!1,principal:i[0],credentials:i[1]}};var Ut=require("node:async_hooks"),F=class t{static hasSecurityContext(e){return e.getStore()?.securityContext!==void 0}static async getSecurityContext(e){return await e.getStore()?.securityContext}static clearSecurityContext(e){delete e.getStore()?.securityContext}static withSecurityContext(e){return(r=new Ut.AsyncLocalStorage)=>(r.getStore().securityContext=e,r)}static withAuthentication(e){return t.withSecurityContext(Promise.resolve({authentication:e}))}static async getContext(e){if(t.hasSecurityContext(e))return t.getSecurityContext(e)}};async function dn(t,e,r,n,o,s){let a=await(await n(t))?.(r);if(a===void 0)throw new Error("No authentication manager found for the exchange");try{await un(a,{exchange:t,next:e},o,s)}catch(c){throw c instanceof C,c}}async function un(t,e,r,n){F.withAuthentication(t)(n),await r(e,t)}function Q(t){let e={matcher:re,successHandler:async({next:n})=>{await n()},converter:He({}),failureHandler:V({entryPoint:J({})}),...t},r=e.managerResolver;if(r===void 0&&e.manager!==void 0){let n=e.manager;r=async o=>n}if(r===void 0)throw new Error("Authentication filter requires a managerResolver or a manager");return async(n,o)=>{let i=(await e.matcher(n)).match?await e.converter(n):void 0;if(i===void 0){await o();return}try{await dn(n,o,i,r,e.successHandler,e.storage)}catch(a){if(a instanceof C){await e.failureHandler({exchange:n,next:o},a);return}throw a}}}var qt=t=>async(e,r)=>{e.response.setStatusCode(t.httpStatus)};var Y=b("auth.entry-point"),Pe=t=>{let e=t.defaultEntryPoint??(async({response:r},n)=>{r.setStatusCode(f.UNAUTHORIZED),await r.end()});return async(r,n)=>{for(let[o,s]of t.entryPoints)if(Y.enabledFor("debug")&&Y.debug(`trying to match using: ${o}`),(await o(r)).match)return Y.enabledFor("debug")&&Y.debug(`match found. using default entry point ${s}`),s(r,n);return Y.enabledFor("debug")&&Y.debug(`no match found. using default entry point ${e}`),e(r,n)}};var _t=t=>async({exchange:e,next:r},n)=>{for(let o of t)await o({exchange:e,next:r},n)};function Ke(t){let e=async g=>g.request.headers.list("X-Requested-With").includes("XMLHttpRequest")?A():E,r=Pe({entryPoints:[[e,qt({httpStatus:f.UNAUTHORIZED})]],defaultEntryPoint:J({})}),n=t.entryPoint??r,o=t.manager,s=je({mediaTypes:["application/atom+xml","application/x-www-form-urlencoded","application/json","application/octet-stream","application/xml","multipart/form-data","text/xml"],ignoredMediaTypes:["*/*"]}),i=Pt(je({mediaTypes:["text/html"]})),a=G([i,s]),c=Ht([e,a]);t.defaultEntryPoints.push([c,n]);let d=t.failureHandler??V({entryPoint:n}),u=_t(t.successHandlers??t.defaultSuccessHandlers),l=He({});return Q({storage:t.storage,manager:o,failureHandler:d,successHandler:u,converter:l})}var zt={invalid_request:"invalid_request",invalid_token:"invalid_token",insufficient_scope:"insufficient_scope"},Gt="https://tools.ietf.org/html/rfc6750#section-3.1";function Re(t){return{errorCode:zt.invalid_token,httpStatus:f.UNAUTHORIZED,description:t,uri:Gt}}function Xe(t){return{errorCode:zt.invalid_request,httpStatus:f.BAD_REQUEST,description:t,uri:Gt}}var ln="access_token",hn=/^Bearer\s+(?<token>[a-zA-Z0-9-._~+/]+=*)$/i,k=class extends C{error;constructor(e,r,n){super(r??(typeof e=="string"?void 0:e.description),n),this.error=typeof e=="string"?{errorCode:e}:e}},jt=t=>t.type==="BearerToken",pn=t=>async e=>{let{request:r}=e;return Promise.all([gn(r.headers,t?.headerName).then(n=>n!==void 0?[n]:void 0),mn(r,t?.uriQueryParameter),yn(e,t?.formEncodedBodyParameter)]).then(n=>n.filter(o=>o!==void 0).flat(1)).then(fn).then(n=>{if(n)return{authenticated:!1,type:"BearerToken",token:n}})};async function fn(t){if(t.length===0)return;if(t.length>1){let r=Xe("Found multiple access tokens in the request");throw new k(r)}let e=t[0];if(!e||e.length===0){let r=Xe("The requested access token parameter is an empty string");throw new k(r)}return e}async function gn(t,e="authorization"){let r=t.one(e);if(!r||!/bearer/i.test(r.substring(0)))return;let n=hn.exec(r);if(n===null){let o=Re("Bearer token is malformed");throw new k(o)}return n.groups?.token}async function Vt(t){let e=t.getAll(ln);if(e.length!==0)return e}async function mn(t,e=!1){if(!(!e||t.method!=="GET"))return Vt(t.URL.searchParams)}async function yn(t,e=!1){let{request:r}=t;if(!e||r.headers.one("content-type")!=="application/x-www-form-urlencoded"||r.method!=="POST")return;let n=await t.request.formData();if(n)return Vt(n)}var Te=pn;function Sn(t){let e="Bearer";if(t.size!==0){e+=" ";let r=0;for(let[n,o]of t)e+=`${n}="${o}"`,r!==t.size-1&&(e+=", "),r++}return e}var Jt=t=>t.httpStatus!==void 0;function wn(t){if(t instanceof k){let{error:e}=t;if(Jt(e))return e.httpStatus}return f.UNAUTHORIZED}function bn(t,e){let r=new Map;if(e&&r.set("realm",e),t instanceof k){let{error:n}=t;r.set("error",n.errorCode),n.description&&r.set("error_description",n.description),n.uri&&r.set("error_uri",n.uri),Jt(n)&&n.scope&&r.set("scope",n.scope)}return r}var vn=t=>async(e,r)=>{let n=wn(r),o=bn(r,t?.realmName),s=Sn(o),{response:i}=e;i.headers.set("WWW-Authenticate",s),i.setStatusCode(n),await i.end()},ke=vn;var xn=t=>{let e=t?.principalClaimName??"sub";return r=>({type:"JwtToken",authenticated:!0,name:r.getClaimAsString(e)})},En=t=>async e=>t(e),K=class extends Error{},ie=class extends K{};function Cn(t){if(t instanceof ie)return new k(Re(t.message),t.message,{cause:t});throw new j(t.message,{cause:t})}function Ze(t){let e=t.decoder,r=t.authConverter??En(xn({}));return async n=>{if(jt(n)){let o=n.token;try{let s=await e(o);return await r(s)}catch(s){throw s instanceof K?Cn(s):s}}}}function et(t){let e=t.entryPoint??ke({}),r=t?.converter??Te({}),n=t.failureHandler??V({entryPoint:e});if(t.managerResolver!==void 0)return Q({storage:t.storage,converter:r,failureHandler:n,managerResolver:t.managerResolver});if(t.jwt!==void 0){let o=t.jwt.manager??Ze(t.jwt);return Q({storage:t.storage,converter:r,failureHandler:n,managerResolver:async s=>o})}throw new Error("Invalid resource server configuration: either managerResolver or jwt must be provided")}var Me=require("@interopio/gateway/jose/jwt");async function Qt(t,e,r){let n=new Ce("Full authentication is required to access this resource."),o=new C("Access Denied",{cause:n});e&&(o.authentication=e),await r(t,o)}function An(t){return async(e,r)=>{e.response.setStatusCode(t),e.response.headers.set("Content-Type","text/plain; charset=utf-8");let n=Buffer.from("Access Denied","utf-8");e.response.headers.set("Content-Length",n.length),await e.response.body(n)}}var Yt=t=>{let e=An(f.FORBIDDEN),r=t.authenticationEntryPoint??J();return async(n,o)=>{try{await o()}catch(s){if(s instanceof U){let i=await n.principal();Bt(i)?(i.authenticated||await e(n,s),await Qt(n,i,r)):await Qt(n,void 0,r);return}throw s}}};var Hn=b("security.auth");function tt(t){let e=async(r,n)=>{let o;for(let[s,i]of t.mappings)if((await s(n))?.match){Hn.debug(`checking authorization on '${n.request.path}' using [${s}, ${i}]`);let a=await i.authorize(r,{exchange:n});if(a!==void 0){o=a;break}}return o??=new L(!1),o};return new N(e)}var Oe=b("security.auth");function rt(t){let{manager:e,storage:r}=t;return async(n,o)=>{let s=F.getContext(r).then(i=>i?.authentication);try{await e.verify(s,n),Oe.enabledFor("debug")&&Oe.debug("authorization successful")}catch(i){throw i instanceof U&&Oe.enabledFor("debug")&&Oe.debug(`authorization failed: ${i.message}`),i}await o()}}var nt=class extends me{#e;constructor(e,r){super(e),this.#e=r}async principal(){return(await this.#e())?.authentication}},Kt=t=>{let e=t.storage;return async(r,n)=>{await n(new nt(r,async()=>await F.getContext(e)))}};var I={first:Number.MAX_SAFE_INTEGER,http_headers:100,https_redirect:200,cors:300,http_basic:600,authentication:800,security_context_server_web_exchange:1500,error_translation:1800,authorization:1900,last:Number.MAX_SAFE_INTEGER},$=Symbol.for("filterOrder"),Xt=(t,e)=>{let r=[];class n{#e;#r=[];manager;get authenticationEntryPoint(){return this.#e!==void 0||this.#r.length===0?this.#e:this.#r.length===1?this.#r[0][1]:Pe({entryPoints:this.#r,defaultEntryPoint:this.#r[this.#r.length-1][1]})}build(){if(t.headers!==void 0&&t.headers.disabled!==!0){let a=Ye(t.headers);a[$]=I.http_headers,r.push(a)}if(t.cors?.disabled!==!0&&e.corsConfigSource!==void 0){let a=Mt({corsConfigSource:e.corsConfigSource});a[$]=I.cors,r.push(a)}if(t.basic!==void 0&&t.basic?.disabled!==!0){let a=t.basic.user?.name.toLowerCase(),c=t.basic.user?.password??"",d=t.basic.user?.authorities??[],u=async p=>{let h=p.principal,w=p.credentials;if(h.toLowerCase()!==a||w!==c)throw new Ae("Invalid username or password");return{type:"UsernamePassword",authenticated:!0,principal:h,credentials:w,authorities:[...d]}},l=[async({exchange:p,next:h},w)=>h()],g=Ke({storage:e.storage,manager:u,defaultEntryPoints:this.#r,defaultSuccessHandlers:l});g[$]=I.http_basic,r.push(g)}if(t.jwt!==void 0&&t.jwt.disabled!==!0){let a=(0,Me.jwtVerifier)({issuerBaseUri:t.jwt.issuerUri,issuer:t.jwt.issuer,audience:t.jwt.audience}),c=async p=>{try{let{payload:h}=await a(p);return{subject:h.sub,getClaimAsString(w){return h[w]}}}catch(h){throw h instanceof Me.JwtVerifyError?new ie(h.message,{cause:h}):new K("error occurred while attempting to decoding jwt",{cause:h})}},d=Te({uriQueryParameter:!0}),u=async p=>{try{return await d(p)===void 0?E:A()}catch{return E}},l=ke({});this.#r.push([u,l]);let g=et({storage:e.storage,entryPoint:l,converter:d,jwt:{decoder:c}});g[$]=I.authentication,r.push(g)}let i=Kt({storage:e.storage});if(r.push(i),i[$]=I.security_context_server_web_exchange,t.authorize!==void 0){let a=Yt({authenticationEntryPoint:this.authenticationEntryPoint});a[$]=I.error_translation,r.push(a);let d=(l=>{let g=[],p=!1;for(let[h,w]of l??[]){let m;if(h==="any-exchange")p=!0,m=re;else{if(p)throw new Error("Cannot register other matchers after 'any-exchange' matcher");m=h}let x;if(w.access==="permitted")x=new N(async()=>new L(!0)),x.toString=()=>"AuthorizationManager[permitted]";else if(w.access==="denied")x=new N(async()=>new L(!1)),x.toString=()=>"AuthorizationManager[denied]";else if(w.access==="authenticated")x=new N(async X=>{let B=await X;return B!==void 0?new L(B.authenticated):new L(!1)}),x.toString=()=>"AuthorizationManager[authenticated]";else throw new Error(`Unknown access type: ${JSON.stringify(w)}`);g.push([m,x])}return tt({mappings:g})})(t.authorize),u=rt({manager:d,storage:e.storage});u[$]=I.authorization,r.push(u)}r.sort((a,c)=>{let d=a[$]??I.last,u=c[$]??I.last;return d-u})}}return new n().build(),r};function Pn(t){let e=[],r={access:t.authConfig?.type!=="none"?"authenticated":"permitted"};for(let[n,o]of t.sockets){let s=o.authorize??r,i=H(n,{method:"GET"});i=G([D,i]),e.push([i,s])}return e.push([H("/",{method:"GET"}),{access:"permitted"}]),e.push([H("/favicon.ico",{method:"GET"}),{access:"permitted"}]),e.push([H("/health",{method:"GET"}),{access:"permitted"}]),t.authorize.length>0&&e.push(...t.authorize),e.push(["any-exchange",r]),{authorize:e,cors:{disabled:t.corsConfig===!1},basic:{disabled:t.authConfig?.type!=="basic",...t.authConfig?.basic},jwt:{disabled:t.authConfig?.type!=="oauth2",...t.authConfig?.oauth2?.jwt}}}async function Zt(t){let e=Ft(t),r=Pn(t),{storage:n}=t;return Xt(r,{storage:n,corsConfigSource:e})}var er=require("node:async_hooks");var We=class extends z{},ot=class{#e;#r=!1;#t;#o;constructor(e,r){this.#e=e,this.#t=r}createExchange(e,r){return new ye(e,r)}set storage(e){this.#o=e}set enableLoggingRequestDetails(e){this.#r=e}formatHeaders(e){let r="{";for(let n of e.keys())if(this.#r){let o=e.get(n);r+=`"${n}": "${o}", `}else{r+="masked, ";break}return r.endsWith(", ")&&(r=r.slice(0,-2)),r+="}",r}formatRequest(e){let r=e.URL.search;return`HTTP ${e.method} "${e.path}${r}`}logRequest(e){if(this.#e.enabledFor("debug")){let r=this.#e.enabledFor("trace");this.#e.debug(`${e.logPrefix}${this.formatRequest(e.request)}${r?`, headers: ${this.formatHeaders(e.request.headers)}`:""}"`)}}logResponse(e){if(this.#e.enabledFor("debug")){let r=this.#e.enabledFor("trace"),n=e.response.statusCode;this.#e.debug(`${e.logPrefix}Completed ${n??"200 OK"}${r?`, headers: ${this.formatHeaders(e.response.headers)}`:""}"`)}}handleUnresolvedError(e,r){let{request:n,response:o,logPrefix:s}=e;if(o.setStatusCode(f.INTERNAL_SERVER_ERROR)){this.#e.error(`${s}500 Server Error for ${this.formatRequest(n)}`,r);return}throw this.#e.error(`${s}Error [${r.message} for ${this.formatRequest(n)}, but already ended (${o.statusCode})`,r),r}async web(e){return await this.#t(e)}async http(e,r){let n=this.createExchange(e,r),o=()=>(this.logRequest(n),this.web(n).then(()=>{this.logResponse(n)}).catch(s=>{this.handleUnresolvedError(n,s)}).then(async()=>{await n.response.end()}));await new Promise((s,i)=>{this.#o!==void 0?this.#o.run({exchange:n},()=>{o().then(()=>s()).catch(a=>i(a))}):o().then(()=>s()).catch(a=>i(a))})}},Le=class{#e;#r=new er.AsyncLocalStorage;#t;storage(e){return this.#r=e,this}httpHandlerDecorator(e){if(this.#t===void 0)this.#t=e;else{let r=this.#t;this.#t=n=>(n=r(n),e(n))}return this}constructor(e){this.#e=e}build(){let e=b("http"),r=new ot(e,this.#e);this.#r!==void 0&&(r.storage=this.#r),r.enableLoggingRequestDetails=!1;let n=async(o,s)=>r.http(o,s);return this.#t?this.#t(n):n}};var or=require("ws");function tr(t,e){let r=t?.exchange,n=r?.request??new _(t),o=r?.principal,s=o?o.bind(r):async function(){},i=n.URL,a=new v;for(let g of n.headers.keys())a.set(g,n.headers.list(g));let c=n.cookies,d=r?.logPrefix??`[${n.id}] `,u=n.remoteAddress;return{url:i,headers:a,cookies:c,principal:s,protocol:e,remoteAddress:u,logPrefix:d}}function rr(t){return[async(r,n)=>{let s=r.request.path??"/",i=t.sockets,a=i.get(s)??Array.from(i.values()).find(c=>{if(s==="/"&&c.default===!0)return!0});if(a!==void 0){let{request:c,response:d}=r,u=await D(r);if((c.method==="GET"||c.method==="CONNECT")&&u.match)if(a.upgradeStrategy!==void 0){a.upgradeStrategy(r);return}else throw new Error(`No upgrade strategy defined for route on ${s}`);else{if(a.default){await n();return}d.setStatusCode(f.UPGRADE_REQUIRED),d.headers.set("Upgrade","websocket").set("Connection","Upgrade").set("Content-Type","text/plain");let l=Buffer.from(`This service [${c.path}] requires use of the websocket protocol.`,"utf-8");await d.body(l)}}else await n()}]}var nr=require("ws"),Ie=class extends nr.WebSocket{constructor(e,r,n){super(null,void 0,n)}connected},$e=class t{static#e=Buffer.alloc(0);static#r=[0,Buffer.alloc(8)];#t;#o;#i;#s=!1;#n;constructor(e,r,n){this.#n=e,this.#o=typeof n=="number"?n:n?.interval,this.#t=typeof n=="number"||n?.data==="timestamp"?()=>t.#d(Date.now()):()=>t.#e,this.#o&&(this.#i=setInterval(()=>{let[o,s]=r();for(let i of s)this.#a(i,o)||this.#c(i,o)},this.#o))}#a(e,r){return e.connected===!1?(this.#n.enabledFor("debug")&&this.#n.debug(`terminating unresponsive ws client on [${r}]`),e.terminate(),!1):!0}#c(e,r){e.connected=!1;let n=this.#t();this.#n.enabledFor("trace")&&this.#n.trace(`pinging ws client on [${r}]`),e.ping(n,this.#s,o=>{o&&this.#n.enabledFor("warn")&&this.#n.warn(`failed to ping ws client on [${r}]`,o)})}static#d(e=Date.now()){if(e-t.#r[0]>0){let r=Buffer.allocUnsafe(8);r.writeBigInt64BE(BigInt(e),0),t.#r=[e,r]}return t.#r[1]}static#u(e){return e.length===8?Number(e.readBigInt64BE(0)):0}close(){clearInterval(this.#i)}handlePing(e,r,n){r.connected=!0,r.pong(n,!1,o=>{o&&this.#n.enabledFor("warn")&&this.#n.warn(`${e.logPrefix}failed to pong ws client [${e.remoteAddress?.address}:${e.remoteAddress?.port}]`,o)})}handlePong(e,r,n){if(r.connected=!0,this.#n.enabledFor("warn")){let o=t.#u(n);if(o>0){let s=Date.now()-o;this.#n.enabledFor("debug")&&this.#n.debug(`${e.logPrefix}ws client [${e.remoteAddress?.address}:${e.remoteAddress?.port}] ping-pong latency: ${s}ms`),this.#o&&s>this.#o/2&&this.#n.enabledFor("warn")&&this.#n.warn(`${e.logPrefix}ws client [${e.remoteAddress?.address}:${e.remoteAddress?.port}] high ping-pong latency: ${s}ms`)}}}};var T=b("ws");function Rn(t,e,r,n){return o=>{let{logPrefix:s,request:i}=o,a=ge.getNativeRequest(i);a.exchange=o;let{socket:c,upgradeHead:d}=a,u=i.host;if(c.removeListener("error",n),e.maxConnections!==void 0&&r.clients?.size>=e.maxConnections){T.warn(`${s}dropping ws connection request on ${u}${t}. max connections exceeded.`),c.destroy();return}let l=i.headers.one("origin");if(!Ct(l,e.originFilters)){T.enabledFor("info")&&T.info(`${s}dropping ws connection request on ${u}${t}. origin ${l??"<missing>"}`),c.destroy();return}T.enabledFor("debug")&&T.debug(`${s}accepted new ws connection request on ${u}${t}`),r.handleUpgrade(a,c,d,(g,p)=>{r.emit("connection",g,p)})}}function Tn(t,e){let r=new Set;t.forEach((o,s)=>{if(s===0&&o.startsWith("HTTP/1.1 101 ")){e.setStatusCode(f.SWITCHING_PROTOCOLS);return}let[i,a]=o.split(": ");e.headers.has(i)?t[s]=`${i}: ${e.headers.one(i)}`:e.headers.set(i,a),r.add(i.toLowerCase())});let n=z.getNativeResponse(e);for(let o of n.getRawHeaderNames()){let s=o.toLowerCase();if(!r.has(s)){let i=e.headers.get(s);i!==void 0&&t.push(`${o}: ${i}`)}}n.markHeadersSent()}async function ir(t,e,r,n,o){try{T.info(`creating ws server for [${t}]. max connections: ${e.maxConnections??"<unlimited>"}, origin filters: ${e.originFilters?JSON.stringify(e.originFilters,dt):"<none>"}, ping: ${typeof e.ping=="number"?e.ping+"ms":e.ping?JSON.stringify(e.ping):"<none>"}`);let s=new or.WebSocketServer({noServer:!0,WebSocket:Ie,autoPong:!1}),i=new $e(T.child("pings"),()=>[t,s.clients],e.ping),a=await e.factory({endpoint:r,storage:n});s.on("error",c=>{T.error(`error starting the ws server for [${t}]`,c)}).on("listening",()=>{T.info(`ws server for [${t}] is listening`)}).on("headers",(c,d)=>{if(d.exchange!==void 0){let{response:u}=d.exchange;Tn(c,u)}}).on("connection",(c,d)=>{let u=tr(d,c.protocol);c.on("pong",l=>{i.handlePong(u,c,l)}),c.on("ping",l=>{i.handlePing(u,c,l)}),a({socket:c,handshake:u})}),s.on("close",()=>{i.close()}),e.upgradeStrategy=Rn(t,e,s,o),e.close=async()=>{await a.close?.call(a),T.info(`stopping ws server for [${t}]. clients: ${s.clients?.size??0}`),s.clients?.forEach(c=>{c.terminate()}),s.close()}}catch(s){T.warn(`failed to init route ${t}`,s)}}var O=b("app");function kn(t){let e={};return t.key&&(e.key=(0,Ne.readFileSync)(t.key)),t.cert&&(e.cert=(0,Ne.readFileSync)(t.cert)),t.ca&&(e.ca=(0,Ne.readFileSync)(t.ca)),e}async function On(t,e){let r=t.build();return async(n,o)=>{n.socket.addListener("error",e);let s;o instanceof q?s=o:(n.upgradeHead=o,s=new q(n),s.assignSocket(n.socket));let i=new _(n),a=new fe(s),c=i.method==="HEAD"?new We(a):a;await r(i,c)}}function Mn(t){return new Promise((e,r)=>{let n=t(o=>{o?r(o):e(n)})})}function Wn(t){if(t)return vt({memoryLimit:t.memory_limit,dumpLocation:t.dump_location,dumpPrefix:t.dump_prefix,reportInterval:t.report_interval,maxBackups:t.max_backups})}async function Ln(t){let e=t.storage,r=await Zt(t),n=rr(t),o=pt(Et(t.serverHeader),...r,...n,...t.middleware,async({request:s,response:i},a)=>{if(s.method==="GET"&&s.path==="/health"){i.setStatusCode(f.OK);let c=Buffer.from("UP","utf-8");i.headers.set("Content-Type","text/plain; charset=utf-8"),await i.body(c)}else await a()},async({request:s,response:i},a)=>{if(s.method==="GET"&&s.path==="/"){i.setStatusCode(f.OK);let c=Buffer.from("io.Gateway Server","utf-8");i.headers.set("Content-Type","text/plain; charset=utf-8"),await i.body(c)}else await a()},async({response:s},i)=>{s.setStatusCode(f.NOT_FOUND),await s.end()});return new Le(o).storage(e)}var it=async t=>{let e=t.ssl,r=e?(p,h)=>ar.default.createServer({...p,...kn(e)},h):(p,h)=>sr.default.createServer(p,h),n=Wn(t.memory),o={middleware:[],corsConfig:t.cors,cors:[],authConfig:t.auth,authorize:[],storage:new cr.AsyncLocalStorage,sockets:new Map},s=dr.IOGateway.Factory({...t.gateway});if(t.gateway){let p=t.gateway;await Je(async h=>{h.socket({path:p.route,factory:ht.bind(s),options:p})},t,o)}t.app&&await Je(t.app,t,o);let i=St(t.port??0),a=t.host,c=p=>O.error(`socket error: ${p}`,p),d=await Ln(o),u=await On(d,c),g=await new Promise((p,h)=>{let w=r({IncomingMessage:le,ServerResponse:q,...t.http},u);w.on("error",m=>{if(m.code==="EADDRINUSE"){O.debug(`port ${m.port} already in use on address ${m.address}`);let{value:x}=i.next();x?(O.info(`retry starting server on port ${x} and host ${a??"<unspecified>"}`),w.close(),w.listen(x,a)):(O.warn(`all configured port(s) ${t.port} are in use. closing...`),w.close(),h(m))}else O.error(`server error: ${m.message}`,m),h(m)}),w.on("listening",async()=>{let m=w.address();for(let[x,X]of o.sockets){let B=`${e?"wss":"ws"}://${wt}:${m.port}${x}`;await ir(x,X,B,o.storage,c)}O.info(`http server listening on ${m.address}:${m.port}`),p(w)}),w.on("upgrade",(m,x,X)=>{try{u(m,X)}catch(B){O.error(`upgrade error: ${B}`,B)}}).on("close",async()=>{O.info("http server closed.")});try{let{value:m}=i.next();w.listen(m,a)}catch(m){O.error("error starting web socket server",m),h(m instanceof Error?m:new Error(`listen failed: ${m}`))}});return new class{gateway=s;async close(){for(let[p,h]of o.sockets)try{h.close!==void 0&&await h.close()}catch(w){O.warn(`error closing route ${p}`,w)}await Mn(p=>{g.closeAllConnections(),g.close(p)}),n&&await xt(n),s&&await s.stop()}}};var In=it;0&&(module.exports={GatewayServer});
3313
3
  //# sourceMappingURL=index.cjs.map