@interopio/gateway-server 0.5.2-beta → 0.6.1-beta

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
@@ -169,7 +169,7 @@ var HttpServerRequest = class {
169
169
  this._body ??= new Promise((resolve, reject) => {
170
170
  const chunks = [];
171
171
  this._req.on("error", (err) => reject(err)).on("data", (chunk) => chunks.push(chunk)).on("end", () => {
172
- resolve(new Blob(chunks));
172
+ resolve(new Blob(chunks, { type: this.headers.one("content-type") }));
173
173
  });
174
174
  });
175
175
  return this._body;
@@ -186,74 +186,79 @@ var HttpServerRequest = class {
186
186
  }
187
187
  get json() {
188
188
  return this.body.then(async (blob) => {
189
- const json = JSON.parse(await blob.text());
189
+ if (blob.size === 0) {
190
+ return void 0;
191
+ }
192
+ const text = await blob.text();
193
+ const json = JSON.parse(text);
190
194
  return json;
191
195
  });
192
196
  }
193
197
  };
194
198
  var IncomingMessageHeaders = class {
195
- constructor(_msg) {
196
- this._msg = _msg;
199
+ #msg;
200
+ constructor(msg) {
201
+ this.#msg = msg;
197
202
  }
198
203
  has(name) {
199
- return this._msg.headers[name] !== void 0;
204
+ return this.#msg.headers[name] !== void 0;
200
205
  }
201
206
  get(name) {
202
- return this._msg.headers[name];
207
+ return this.#msg.headers[name];
203
208
  }
204
209
  list(name) {
205
- return toList(this._msg.headers[name]);
210
+ return toList(this.#msg.headers[name]);
206
211
  }
207
212
  one(name) {
208
- const value = this._msg.headers[name];
213
+ const value = this.#msg.headers[name];
209
214
  if (Array.isArray(value)) {
210
215
  return value[0];
211
216
  }
212
217
  return value;
213
218
  }
214
219
  keys() {
215
- return Object.keys(this._msg.headers).values();
220
+ return Object.keys(this.#msg.headers).values();
216
221
  }
217
222
  };
218
223
  var OutgoingMessageHeaders = class {
219
- _msg;
224
+ #msg;
220
225
  constructor(msg) {
221
- this._msg = msg;
226
+ this.#msg = msg;
222
227
  }
223
228
  has(name) {
224
- return this._msg.hasHeader(name);
229
+ return this.#msg.hasHeader(name);
225
230
  }
226
231
  keys() {
227
- return this._msg.getHeaderNames().values();
232
+ return this.#msg.getHeaderNames().values();
228
233
  }
229
234
  get(name) {
230
- return this._msg.getHeader(name);
235
+ return this.#msg.getHeader(name);
231
236
  }
232
237
  one(name) {
233
- const value = this._msg.getHeader(name);
238
+ const value = this.#msg.getHeader(name);
234
239
  if (Array.isArray(value)) {
235
240
  return value[0];
236
241
  }
237
242
  return value;
238
243
  }
239
244
  set(name, value) {
240
- if (!this._msg.headersSent) {
245
+ if (!this.#msg.headersSent) {
241
246
  if (Array.isArray(value)) {
242
247
  value = value.map((v) => typeof v === "number" ? String(v) : v);
243
248
  } else if (typeof value === "number") {
244
249
  value = String(value);
245
250
  }
246
251
  if (value) {
247
- this._msg.setHeader(name, value);
252
+ this.#msg.setHeader(name, value);
248
253
  } else {
249
- this._msg.removeHeader(name);
254
+ this.#msg.removeHeader(name);
250
255
  }
251
256
  }
252
257
  return this;
253
258
  }
254
259
  add(name, value) {
255
- if (!this._msg.headersSent) {
256
- this._msg.appendHeader(name, value);
260
+ if (!this.#msg.headersSent) {
261
+ this.#msg.appendHeader(name, value);
257
262
  }
258
263
  return this;
259
264
  }
@@ -301,7 +306,7 @@ var HttpServerResponse = class {
301
306
  }
302
307
  end(chunk) {
303
308
  if (!this._res.headersSent) {
304
- return new Promise((resolve, reject) => {
309
+ return new Promise((resolve) => {
305
310
  if (chunk === void 0) {
306
311
  this._res.end(() => {
307
312
  resolve(true);
@@ -331,6 +336,8 @@ var HttpServerResponse = class {
331
336
  }
332
337
  };
333
338
  var DefaultWebExchange = class extends WebExchange {
339
+ request;
340
+ response;
334
341
  constructor(request, response) {
335
342
  super();
336
343
  this.request = request;
@@ -419,6 +426,92 @@ var MapHttpHeaders = class extends Map {
419
426
  return this;
420
427
  }
421
428
  };
429
+ var MockHttpRequest = class {
430
+ #url;
431
+ #body;
432
+ headers = new MapHttpHeaders();
433
+ constructor(url, method) {
434
+ if (typeof url === "string") {
435
+ if (URL.canParse(url)) {
436
+ url = new URL(url);
437
+ } else if (URL.canParse(url, "http://localhost")) {
438
+ url = new URL(url, "http://localhost");
439
+ } else {
440
+ throw new TypeError("URL cannot parse url");
441
+ }
442
+ }
443
+ this.#url = url;
444
+ this.method = method ?? "GET";
445
+ this.headers.set("Host", this.#url.hostname);
446
+ this.path = this.#url.pathname ?? "/";
447
+ }
448
+ method;
449
+ path;
450
+ get host() {
451
+ return requestToHost(this, this.#url.host);
452
+ }
453
+ get protocol() {
454
+ return requestToProtocol(this, this.#url.protocol.slice(0, -1));
455
+ }
456
+ get cookies() {
457
+ return parseCookies(this);
458
+ }
459
+ get body() {
460
+ const body = this.#body;
461
+ return body ? Promise.resolve(body) : Promise.reject(new Error(`no body set`));
462
+ }
463
+ get json() {
464
+ return this.body.then(async (blob) => JSON.parse(await blob.text()));
465
+ }
466
+ get text() {
467
+ return this.body.then(async (blob) => await blob.text());
468
+ }
469
+ set body(value) {
470
+ this.#body = value;
471
+ if (!this.headers.has("content-type")) {
472
+ this.headers.set("content-type", value.type || "application/octet-stream");
473
+ }
474
+ }
475
+ get formData() {
476
+ return this.body.then(async (b) => new URLSearchParams(await b.text()));
477
+ }
478
+ get URL() {
479
+ return new URL(this.path + this.#url.search + this.#url.hash, `${this.protocol}://${this.host}`);
480
+ }
481
+ };
482
+ var MockHttpResponse = class {
483
+ statusCode;
484
+ headers = new MapHttpHeaders();
485
+ cookies = [];
486
+ addCookie(cookie) {
487
+ this.cookies.push(cookie);
488
+ return this;
489
+ }
490
+ _body;
491
+ async end(chunk) {
492
+ if (this._body) {
493
+ return false;
494
+ }
495
+ switch (typeof chunk) {
496
+ case "string":
497
+ this._body = new Blob([chunk], { type: "text/plain" });
498
+ break;
499
+ case "object":
500
+ if (chunk instanceof Blob) {
501
+ this._body = chunk;
502
+ } else if (chunk !== null) {
503
+ this._body = new Blob([JSON.stringify(chunk)], { type: "application/json" });
504
+ }
505
+ break;
506
+ case "undefined":
507
+ this._body = new Blob([]);
508
+ break;
509
+ default:
510
+ throw new Error(`Unsupported chunk type: ${typeof chunk}`);
511
+ }
512
+ return true;
513
+ }
514
+ };
422
515
 
423
516
  // src/gateway/ws/core.ts
424
517
  var import_gateway2 = require("@interopio/gateway");
@@ -589,22 +682,129 @@ var InMemoryNodeConnections = class {
589
682
  }
590
683
  };
591
684
 
685
+ // src/server/util/matchers.ts
686
+ var or = (matchers) => {
687
+ return async (exchange) => {
688
+ for (const matcher of matchers) {
689
+ const result = await matcher(exchange);
690
+ if (result.match) {
691
+ return { match: true };
692
+ }
693
+ }
694
+ return { match: false };
695
+ };
696
+ };
697
+ var and = (matchers) => {
698
+ const matcher = async (exchange) => {
699
+ for (const matcher2 of matchers) {
700
+ const result = await matcher2(exchange);
701
+ if (!result.match) {
702
+ return { match: false };
703
+ }
704
+ }
705
+ return { match: true };
706
+ };
707
+ matcher.toString = () => `and(${matchers.map((m) => m.toString()).join(", ")})`;
708
+ return matcher;
709
+ };
710
+ var not = (matcher) => {
711
+ return async (exchange) => {
712
+ const result = await matcher(exchange);
713
+ return { match: !result.match };
714
+ };
715
+ };
716
+ var anyExchange = async (_exchange) => {
717
+ return { match: true };
718
+ };
719
+ anyExchange.toString = () => "any-exchange";
720
+ var pattern = (pattern2, opts) => {
721
+ const method = opts?.method;
722
+ const matcher = async (exchange) => {
723
+ const request = exchange.request;
724
+ const path = request.path;
725
+ if (method !== void 0 && request.method !== method) {
726
+ return { match: false };
727
+ }
728
+ if (typeof pattern2 === "string") {
729
+ if (path === pattern2) {
730
+ return { match: true };
731
+ } else {
732
+ return { match: false };
733
+ }
734
+ } else {
735
+ const match = pattern2.exec(path);
736
+ if (match !== null) {
737
+ return { match: true };
738
+ } else {
739
+ return { match: false };
740
+ }
741
+ }
742
+ };
743
+ matcher.toString = () => {
744
+ return `pattern(${pattern2.toString()})${method ? ` method=${method}` : ""}`;
745
+ };
746
+ return matcher;
747
+ };
748
+ var mediaType = (opts) => {
749
+ const shouldIgnore = (requestedMediaType) => {
750
+ if (opts.ignoredMediaTypes !== void 0) {
751
+ for (const ignoredMediaType of opts.ignoredMediaTypes) {
752
+ if (requestedMediaType === ignoredMediaType || ignoredMediaType === "*/*") {
753
+ return true;
754
+ }
755
+ }
756
+ }
757
+ return false;
758
+ };
759
+ return async (exchange) => {
760
+ const request = exchange.request;
761
+ let requestMediaTypes;
762
+ try {
763
+ requestMediaTypes = request.headers.list("accept");
764
+ } catch (e) {
765
+ return { match: false };
766
+ }
767
+ for (const requestedMediaType of requestMediaTypes) {
768
+ if (shouldIgnore(requestedMediaType)) {
769
+ continue;
770
+ }
771
+ for (const mediaType2 of opts.mediaTypes) {
772
+ if (requestedMediaType.startsWith(mediaType2)) {
773
+ return { match: true };
774
+ }
775
+ }
776
+ }
777
+ return { match: false };
778
+ };
779
+ };
780
+ var upgradeMatcher = async ({ request }) => {
781
+ const match = request["_req"]?.["upgrade"] && request.headers.one("upgrade")?.toLowerCase() === "websocket";
782
+ return { match };
783
+ };
784
+ upgradeMatcher.toString = () => "websocket upgrade";
785
+
592
786
  // src/mesh/rest-directory/routes.ts
593
- function routes(connections) {
787
+ function routes(connections, config, authorize) {
788
+ config.cors.push(
789
+ [pattern("/api/nodes"), { allowMethods: ["GET", "POST"] }],
790
+ [pattern(/\/api\/nodes\/(?<nodeId>.*)/), { allowMethods: ["GET", "DELETE"] }]
791
+ );
792
+ if (authorize) {
793
+ config.authorize.push([pattern(/\/api\/nodes(\/.*)?/), authorize]);
794
+ }
594
795
  return [
595
796
  async (ctx, next) => {
596
797
  if (ctx.method === "POST" && ctx.path === "/api/nodes") {
597
798
  const json = await ctx.request.json;
598
799
  if (!Array.isArray(json)) {
599
800
  ctx.response.statusCode = 400;
600
- ctx.response._res.end();
801
+ await ctx.response.end();
601
802
  } else {
602
803
  const nodes = json;
603
804
  const result = connections.announce(nodes);
604
- const body = JSON.stringify(result);
605
- ctx.response.headers.set("content-type", "application/json");
805
+ const body = new Blob([JSON.stringify(result)], { type: "application/json" });
606
806
  ctx.response.statusCode = 200;
607
- ctx.response._res.end(body);
807
+ await ctx.response.end(body);
608
808
  }
609
809
  } else {
610
810
  await next();
@@ -615,7 +815,7 @@ function routes(connections) {
615
815
  const nodeId = path?.substring("/api/nodes/".length);
616
816
  connections.remove(nodeId);
617
817
  response.statusCode = 200;
618
- response._res.end();
818
+ await response.end();
619
819
  } else {
620
820
  await next();
621
821
  }
@@ -976,68 +1176,38 @@ var core_default4 = create4;
976
1176
 
977
1177
  // src/metrics/routes.ts
978
1178
  var logger5 = getLogger("metrics");
979
- var COOKIE_NAME = "GW_LOGIN";
980
- function loggedIn(auth, ctx) {
981
- if (auth) {
982
- const value = ctx.request.cookies.find((cookie) => cookie.name === COOKIE_NAME)?.value;
983
- return value && parseInt(value) > Date.now();
984
- }
985
- return true;
986
- }
987
- async function routes2(config) {
1179
+ async function routes2(config, { cors, authorize }) {
988
1180
  const { jsonFileAppender } = await import("@interopio/gateway/metrics/publisher/file");
989
1181
  const appender = jsonFileAppender(logger5);
990
1182
  await appender.open(config.file?.location ?? "metrics.ndjson", config.file?.append ?? true);
1183
+ cors.push([pattern("/api/metrics"), { allowMethods: ["GET", "POST"] }]);
1184
+ if (config.authorize) {
1185
+ authorize.push([pattern("/api/metrics"), config.authorize]);
1186
+ }
991
1187
  return [
992
1188
  async (ctx, next) => {
993
1189
  if (ctx.method === "GET" && ctx.path === "/api/metrics") {
994
- if (loggedIn(config.auth, ctx)) {
995
- ctx.response.statusCode = 200;
996
- } else {
997
- ctx.response.statusCode = 302;
998
- ctx.response.headers.set("location", "/api/login?redirectTo=/api/metrics");
999
- }
1000
- ctx.response._res.end();
1001
- } else {
1002
- await next();
1003
- }
1004
- },
1005
- async (ctx, next) => {
1006
- if (ctx.method === "GET" && ctx.path === "/api/login") {
1007
- const redirectTo = new URLSearchParams(ctx.request.query ?? void 0).get("redirectTo");
1008
- const expires = Date.now() + 180 * 1e3;
1009
- ctx.response.addCookie({ name: COOKIE_NAME, value: `${expires}`, maxAge: Infinity, path: "/api", sameSite: "strict" });
1010
- if (redirectTo) {
1011
- ctx.response.statusCode = 302;
1012
- ctx.response.headers.set("location", redirectTo);
1013
- } else {
1014
- ctx.response.statusCode = 200;
1015
- }
1016
- ctx.response._res.end();
1190
+ ctx.response.statusCode = 200;
1191
+ await ctx.response.end();
1017
1192
  } else {
1018
1193
  await next();
1019
1194
  }
1020
1195
  },
1021
- async (ctx, next) => {
1022
- if (ctx.method === "POST" && ctx.path === "/api/metrics") {
1023
- if (loggedIn(config.auth, ctx)) {
1024
- ctx.response.statusCode = 202;
1025
- ctx.response._res.end();
1026
- try {
1027
- const json = await ctx.request.json;
1028
- const update = json;
1029
- if (logger5.enabledFor("debug")) {
1030
- logger5.debug(`${JSON.stringify(update)}`);
1031
- }
1032
- if ((config.file?.status ?? false) || update.status === void 0) {
1033
- await appender.write(update);
1034
- }
1035
- } catch (e) {
1036
- logger5.error(`error processing metrics`, e);
1196
+ async ({ request, response }, next) => {
1197
+ if (request.method === "POST" && request.path === "/api/metrics") {
1198
+ response.statusCode = 202;
1199
+ await response.end();
1200
+ try {
1201
+ const json = await request.json;
1202
+ const update = json;
1203
+ if (logger5.enabledFor("debug")) {
1204
+ logger5.debug(`${JSON.stringify(update)}`);
1037
1205
  }
1038
- } else {
1039
- ctx.response.statusCode = 401;
1040
- ctx.response._res.end();
1206
+ if ((config.file?.status ?? false) || update.status === void 0) {
1207
+ await appender.write(update);
1208
+ }
1209
+ } catch (e) {
1210
+ logger5.error(`error processing metrics`, e);
1041
1211
  }
1042
1212
  } else {
1043
1213
  await next();
@@ -1118,9 +1288,9 @@ var localIp = (() => {
1118
1288
  return a.length > 0 ? a[0] : void 0;
1119
1289
  }
1120
1290
  const addresses = Object.values((0, import_node_os.networkInterfaces)()).flatMap((details) => {
1121
- return (details ?? []).filter((info) => info.family === "IPv4");
1122
- }).reduce((acc, info) => {
1123
- acc[info.internal ? "internal" : "external"].push(info);
1291
+ return (details ?? []).filter((info2) => info2.family === "IPv4");
1292
+ }).reduce((acc, info2) => {
1293
+ acc[info2.internal ? "internal" : "external"].push(info2);
1124
1294
  return acc;
1125
1295
  }, { internal: [], external: [] });
1126
1296
  return (first(addresses.internal) ?? first(addresses.external))?.address;
@@ -1267,7 +1437,7 @@ async function stop(m) {
1267
1437
  return await run(m, "stop");
1268
1438
  }
1269
1439
 
1270
- // src/server/ws-client-verify.ts
1440
+ // src/app/ws-client-verify.ts
1271
1441
  var import_gateway5 = require("@interopio/gateway");
1272
1442
  var log3 = getLogger("gateway.ws.client-verify");
1273
1443
  function acceptsMissing(originFilters) {
@@ -1339,272 +1509,57 @@ function regexifyOriginFilters(originFilters) {
1339
1509
  }
1340
1510
  }
1341
1511
 
1342
- // src/server/cors.ts
1343
- var import_gateway6 = require("@interopio/gateway");
1344
- function isSameOrigin(request) {
1345
- const origin = request.headers.one("origin");
1346
- if (origin === void 0) {
1347
- return true;
1348
- }
1349
- const url = request.URL;
1350
- const actualProtocol = url.protocol;
1351
- const actualHost = url.host;
1352
- const originUrl = new URL(origin);
1353
- const originHost = originUrl.host;
1354
- const originProtocol = originUrl.protocol;
1355
- return actualProtocol === originProtocol && actualHost === originHost;
1356
- }
1357
- function isCorsRequest(request) {
1358
- return request.headers.has("origin") && !isSameOrigin(request);
1359
- }
1360
- function isPreFlightRequest(request) {
1361
- return request.method === "OPTIONS" && request.headers.has("origin") && request.headers.has("access-control-request-method");
1362
- }
1363
- var VARY_HEADERS = ["Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers"];
1364
- function processRequest(exchange, config) {
1365
- const { request, response } = exchange;
1366
- const responseHeaders = response.headers;
1367
- if (!responseHeaders.has("Vary")) {
1368
- responseHeaders.set("Vary", VARY_HEADERS.join(", "));
1369
- } else {
1370
- const varyHeaders = responseHeaders.list("Vary");
1371
- for (const header of VARY_HEADERS) {
1372
- if (!varyHeaders.find((h) => h === header)) {
1373
- varyHeaders.push(header);
1374
- }
1512
+ // src/server/server-header.ts
1513
+ var import_package = __toESM(require("@interopio/gateway-server/package.json"), 1);
1514
+ var serverHeader = (server) => {
1515
+ server ??= `${import_package.default.name} - v${import_package.default.version}`;
1516
+ return async ({ response }, next) => {
1517
+ if (server !== false && !response.headers.has("server")) {
1518
+ response.headers.set("Server", server);
1375
1519
  }
1376
- responseHeaders.set("Vary", varyHeaders.join(", "));
1377
- }
1378
- try {
1379
- if (!isCorsRequest(request)) {
1520
+ await next();
1521
+ };
1522
+ };
1523
+ var server_header_default = (server) => serverHeader(server);
1524
+
1525
+ // src/app/route.ts
1526
+ function findSocketRoute({ request }, { sockets: routes3 }) {
1527
+ const path = request.path ?? "/";
1528
+ const route = routes3.get(path) ?? Array.from(routes3.values()).find((route2) => {
1529
+ if (path === "/" && route2.default === true) {
1380
1530
  return true;
1381
1531
  }
1382
- } catch (e) {
1383
- if (logger6.enabledFor("debug")) {
1384
- logger6.debug(`reject: origin is malformed`);
1385
- }
1386
- rejectRequest(response);
1387
- return false;
1388
- }
1389
- if (responseHeaders.has("access-control-allow-origin")) {
1390
- logger6.trace(`skip: already contains "Access-Control-Allow-Origin"`);
1391
- return true;
1392
- }
1393
- const preFlightRequest = isPreFlightRequest(request);
1394
- if (config) {
1395
- return handleInternal(exchange, config, preFlightRequest);
1396
- }
1397
- if (preFlightRequest) {
1398
- rejectRequest(response);
1399
- return false;
1400
- }
1401
- return true;
1532
+ });
1533
+ return [route, path];
1402
1534
  }
1403
- function validateConfig(config) {
1404
- if (config) {
1405
- const headers2 = config.headers;
1406
- if (headers2?.allow && headers2.allow !== ALL) {
1407
- headers2.allow = headers2.allow.map((header) => header.toLowerCase());
1408
- }
1409
- const origins = config.origins;
1410
- if (origins?.allow && origins.allow !== ALL) {
1411
- origins.allow = origins.allow.map((origin) => {
1412
- if (typeof origin === "string") {
1413
- return origin.toLowerCase();
1414
- }
1415
- return origin;
1416
- });
1535
+
1536
+ // src/server/security/http-headers.ts
1537
+ var staticServerHttpHeadersWriter = (headers2) => {
1538
+ return async (exchange) => {
1539
+ let containsNoHeaders = true;
1540
+ const { response } = exchange;
1541
+ for (const name of headers2.keys()) {
1542
+ if (response.headers.has(name)) {
1543
+ containsNoHeaders = false;
1544
+ }
1417
1545
  }
1418
- return config;
1419
- }
1420
- }
1421
- var handler = (config) => {
1422
- validateConfig(config);
1423
- return async (ctx, next) => {
1424
- const isValid = processRequest(ctx, config);
1425
- if (!isValid || isPreFlightRequest(ctx.request)) {
1426
- await ctx.response.end();
1427
- } else {
1428
- await next();
1546
+ if (containsNoHeaders) {
1547
+ for (const [name, value] of headers2) {
1548
+ response.headers.set(name, value);
1549
+ }
1429
1550
  }
1430
1551
  };
1431
1552
  };
1432
- var cors_default = (config) => [handler(config)];
1433
- var logger6 = getLogger("cors");
1434
- function rejectRequest(response) {
1435
- response.statusCode = 403;
1436
- }
1437
- function handleInternal(exchange, config, preFlightRequest) {
1438
- const { request, response } = exchange;
1439
- const responseHeaders = response.headers;
1440
- const requestOrigin = request.headers.one("origin");
1441
- const allowOrigin = checkOrigin(config, requestOrigin);
1442
- if (allowOrigin === void 0) {
1443
- if (logger6.enabledFor("debug")) {
1444
- logger6.debug(`reject: '${requestOrigin}' origin is not allowed`);
1445
- }
1446
- rejectRequest(response);
1447
- return false;
1448
- }
1449
- const requestMethod = getMethodToUse(request, preFlightRequest);
1450
- const allowMethods = checkMethods(config, requestMethod);
1451
- if (allowMethods === void 0) {
1452
- if (logger6.enabledFor("debug")) {
1453
- logger6.debug(`reject: HTTP '${requestMethod}' is not allowed`);
1454
- }
1455
- rejectRequest(response);
1456
- return false;
1457
- }
1458
- const requestHeaders = getHeadersToUse(request, preFlightRequest);
1459
- const allowHeaders = checkHeaders(config, requestHeaders);
1460
- if (preFlightRequest && allowHeaders === void 0) {
1461
- if (logger6.enabledFor("debug")) {
1462
- logger6.debug(`reject: headers '${requestHeaders}' are not allowed`);
1463
- }
1464
- rejectRequest(response);
1465
- return false;
1466
- }
1467
- responseHeaders.set("access-control-allow-origin", allowOrigin);
1468
- if (preFlightRequest) {
1469
- responseHeaders.set("access-control-allow-methods", allowMethods.join(","));
1470
- }
1471
- if (preFlightRequest && allowHeaders !== void 0 && allowHeaders.length > 0) {
1472
- responseHeaders.set("access-control-allow-headers", allowHeaders.join(", "));
1473
- }
1474
- const exposeHeaders = config.headers?.expose;
1475
- if (exposeHeaders && exposeHeaders.length > 0) {
1476
- responseHeaders.set("access-control-expose-headers", exposeHeaders.join(", "));
1477
- }
1478
- if (config.credentials?.allow) {
1479
- responseHeaders.set("access-control-allow-credentials", "true");
1480
- }
1481
- if (config.privateNetwork?.allow && request.headers.one("access-control-request-private-network") === "true") {
1482
- responseHeaders.set("access-control-allow-private-network", "true");
1483
- }
1484
- return true;
1485
- }
1486
- var ALL = "*";
1487
- var DEFAULT_METHODS = ["GET", "HEAD"];
1488
- function validateAllowCredentials(config) {
1489
- if (config.credentials?.allow === true && config.origins?.allow === ALL) {
1490
- throw new Error(`when credentials.allow is true origins.allow cannot be "*"`);
1491
- }
1492
- }
1493
- function validateAllowPrivateNetwork(config) {
1494
- if (config.privateNetwork?.allow === true && config.origins?.allow === ALL) {
1495
- throw new Error(`when privateNetwork.allow is true origins.allow cannot be "*"`);
1496
- }
1497
- }
1498
- function checkOrigin(config, origin) {
1499
- if (origin) {
1500
- const allowedOrigins = config.origins?.allow;
1501
- if (allowedOrigins) {
1502
- if (allowedOrigins === ALL) {
1503
- validateAllowCredentials(config);
1504
- validateAllowPrivateNetwork(config);
1505
- return ALL;
1506
- }
1507
- const originToCheck = trimTrailingSlash(origin.toLowerCase());
1508
- for (const allowedOrigin of allowedOrigins) {
1509
- if (allowedOrigin === ALL || import_gateway6.IOGateway.Filtering.valueMatches(allowedOrigin, originToCheck)) {
1510
- return origin;
1511
- }
1512
- }
1513
- }
1514
- }
1515
- }
1516
- function checkMethods(config, requestMethod) {
1517
- if (requestMethod) {
1518
- const allowedMethods = config.methods?.allow ?? DEFAULT_METHODS;
1519
- if (allowedMethods === ALL) {
1520
- return [requestMethod];
1521
- }
1522
- if (import_gateway6.IOGateway.Filtering.valuesMatch(allowedMethods, requestMethod)) {
1523
- return allowedMethods;
1524
- }
1525
- }
1526
- }
1527
- function checkHeaders(config, requestHeaders) {
1528
- if (requestHeaders === void 0) {
1529
- return;
1530
- }
1531
- if (requestHeaders.length == 0) {
1532
- return [];
1533
- }
1534
- const allowedHeaders = config.headers?.allow;
1535
- if (allowedHeaders === void 0) {
1536
- return;
1537
- }
1538
- const allowAnyHeader = allowedHeaders === ALL;
1539
- const result = [];
1540
- for (const requestHeader of requestHeaders) {
1541
- const value = requestHeader?.trim();
1542
- if (value) {
1543
- if (allowAnyHeader) {
1544
- result.push(value);
1545
- } else {
1546
- for (const allowedHeader of allowedHeaders) {
1547
- if (value.toLowerCase() == allowedHeader) {
1548
- result.push(value);
1549
- break;
1550
- }
1551
- }
1552
- }
1553
- }
1554
- }
1555
- if (result.length > 0) {
1556
- return result;
1557
- }
1558
- }
1559
- function trimTrailingSlash(origin) {
1560
- return origin.endsWith("/") ? origin.slice(0, -1) : origin;
1561
- }
1562
- function getMethodToUse(request, isPreFlight) {
1563
- return isPreFlight ? request.headers.one("access-control-request-method") : request.method;
1564
- }
1565
- function getHeadersToUse(request, isPreFlight) {
1566
- const headers2 = request.headers;
1567
- return isPreFlight ? headers2.list("access-control-request-headers") : Array.from(headers2.keys());
1568
- }
1569
-
1570
- // src/server/server-header.ts
1571
- var serverHeader = (server) => {
1572
- return async ({ response }, next) => {
1573
- if (!response.headers.has("server")) {
1574
- response.headers.set("Server", server);
1575
- }
1576
- await next();
1577
- };
1578
- };
1579
- var server_header_default = (server = "gateway-server") => serverHeader(server);
1580
-
1581
- // src/server/security/http-headers.ts
1582
- var staticServerHttpHeadersWriter = (headers2) => {
1583
- return async (exchange) => {
1584
- let containsNoHeaders = true;
1585
- const { response } = exchange;
1586
- for (const name of headers2.keys()) {
1587
- if (response.headers.has(name)) {
1588
- containsNoHeaders = false;
1589
- }
1590
- }
1591
- if (containsNoHeaders) {
1592
- for (const [name, value] of headers2) {
1593
- response.headers.set(name, value);
1594
- }
1595
- }
1596
- };
1597
- };
1598
- var cacheControlServerHttpHeadersWriter = () => staticServerHttpHeadersWriter(
1599
- new MapHttpHeaders().add("cache-control", "no-cache, no-store, max-age=0, must-revalidate").add("pragma", "no-cache").add("expires", "0")
1600
- );
1601
- var contentTypeServerHttpHeadersWriter = () => staticServerHttpHeadersWriter(
1602
- new MapHttpHeaders().add("x-content-type-options", "nosniff")
1603
- );
1604
- var strictTransportSecurityServerHttpHeadersWriter = (maxAgeInSeconds, includeSubDomains, preload) => {
1605
- let headerValue = `max-age=${maxAgeInSeconds}`;
1606
- if (includeSubDomains) {
1607
- headerValue += " ; includeSubDomains";
1553
+ var cacheControlServerHttpHeadersWriter = () => staticServerHttpHeadersWriter(
1554
+ new MapHttpHeaders().add("cache-control", "no-cache, no-store, max-age=0, must-revalidate").add("pragma", "no-cache").add("expires", "0")
1555
+ );
1556
+ var contentTypeServerHttpHeadersWriter = () => staticServerHttpHeadersWriter(
1557
+ new MapHttpHeaders().add("x-content-type-options", "nosniff")
1558
+ );
1559
+ var strictTransportSecurityServerHttpHeadersWriter = (maxAgeInSeconds, includeSubDomains, preload) => {
1560
+ let headerValue = `max-age=${maxAgeInSeconds}`;
1561
+ if (includeSubDomains) {
1562
+ headerValue += " ; includeSubDomains";
1608
1563
  }
1609
1564
  if (preload) {
1610
1565
  headerValue += " ; preload";
@@ -1764,18 +1719,18 @@ var AuthorizationDecision = class {
1764
1719
  granted;
1765
1720
  };
1766
1721
  var DefaultAuthorizationManager = class {
1767
- check;
1722
+ #check;
1768
1723
  constructor(check) {
1769
- this.check = check;
1724
+ this.#check = check;
1770
1725
  }
1771
1726
  async verify(authentication, object) {
1772
- const decision = await this.check(authentication, object);
1727
+ const decision = await this.#check(authentication, object);
1773
1728
  if (!decision?.granted) {
1774
1729
  throw new AccessDeniedError("Access denied");
1775
1730
  }
1776
1731
  }
1777
1732
  async authorize(authentication, object) {
1778
- return await this.check(authentication, object);
1733
+ return await this.#check(authentication, object);
1779
1734
  }
1780
1735
  };
1781
1736
  var AuthenticationServiceError = class extends AuthenticationError {
@@ -1829,71 +1784,6 @@ var httpBasicAuthenticationConverter = (opts) => {
1829
1784
  };
1830
1785
  };
1831
1786
 
1832
- // src/server/util/matchers.ts
1833
- var or = (matchers) => {
1834
- return async (exchange) => {
1835
- for (const matcher of matchers) {
1836
- const result = await matcher(exchange);
1837
- if (result.match) {
1838
- return { match: true };
1839
- }
1840
- }
1841
- return { match: false };
1842
- };
1843
- };
1844
- var and = (matchers) => {
1845
- return async (exchange) => {
1846
- for (const matcher of matchers) {
1847
- const result = await matcher(exchange);
1848
- if (!result.match) {
1849
- return { match: false };
1850
- }
1851
- }
1852
- return { match: true };
1853
- };
1854
- };
1855
- var not = (matcher) => {
1856
- return async (exchange) => {
1857
- const result = await matcher(exchange);
1858
- return { match: !result.match };
1859
- };
1860
- };
1861
- var anyExchange = async (_exchange) => {
1862
- return { match: true };
1863
- };
1864
- var mediaType = (opts) => {
1865
- const shouldIgnore = (requestedMediaType) => {
1866
- if (opts.ignoredMediaTypes !== void 0) {
1867
- for (const ignoredMediaType of opts.ignoredMediaTypes) {
1868
- if (requestedMediaType === ignoredMediaType || ignoredMediaType === "*/*") {
1869
- return true;
1870
- }
1871
- }
1872
- }
1873
- return false;
1874
- };
1875
- return async (exchange) => {
1876
- const request = exchange.request;
1877
- let requestMediaTypes;
1878
- try {
1879
- requestMediaTypes = request.headers.list("accept");
1880
- } catch (e) {
1881
- return { match: false };
1882
- }
1883
- for (const requestedMediaType of requestMediaTypes) {
1884
- if (shouldIgnore(requestedMediaType)) {
1885
- continue;
1886
- }
1887
- for (const mediaType2 of opts.mediaTypes) {
1888
- if (requestedMediaType.startsWith(mediaType2)) {
1889
- return { match: true };
1890
- }
1891
- }
1892
- }
1893
- return { match: false };
1894
- };
1895
- };
1896
-
1897
1787
  // src/server/security/security-context.ts
1898
1788
  var import_node_async_hooks = require("node:async_hooks");
1899
1789
  var AsyncStorageSecurityContextHolder = class _AsyncStorageSecurityContextHolder {
@@ -2207,6 +2097,7 @@ var httpStatusEntryPoint = (opts) => {
2207
2097
  };
2208
2098
 
2209
2099
  // src/server/security/delegating-entry-point.ts
2100
+ var logger6 = getLogger("auth.entry-point");
2210
2101
  var delegatingEntryPoint = (opts) => {
2211
2102
  const defaultEntryPoint = opts.defaultEntryPoint ?? (async ({ response }, _error) => {
2212
2103
  response.statusCode = 401;
@@ -2214,11 +2105,20 @@ var delegatingEntryPoint = (opts) => {
2214
2105
  });
2215
2106
  return async (exchange, error) => {
2216
2107
  for (const [matcher, entryPoint] of opts.entryPoints) {
2108
+ if (logger6.enabledFor("debug")) {
2109
+ logger6.debug(`trying to match using: ${matcher}`);
2110
+ }
2217
2111
  const match = await matcher(exchange);
2218
2112
  if (match.match) {
2113
+ if (logger6.enabledFor("debug")) {
2114
+ logger6.debug(`match found. using default entry point ${entryPoint}`);
2115
+ }
2219
2116
  return entryPoint(exchange, error);
2220
2117
  }
2221
2118
  }
2119
+ if (logger6.enabledFor("debug")) {
2120
+ logger6.debug(`no match found. using default entry point ${defaultEntryPoint}`);
2121
+ }
2222
2122
  return defaultEntryPoint(exchange, error);
2223
2123
  };
2224
2124
  };
@@ -2226,8 +2126,8 @@ var delegatingEntryPoint = (opts) => {
2226
2126
  // src/server/security/delegating-success-handler.ts
2227
2127
  var delegatingSuccessHandler = (handlers) => {
2228
2128
  return async ({ exchange, next }, authentication) => {
2229
- for (const handler2 of handlers) {
2230
- await handler2({ exchange, next }, authentication);
2129
+ for (const handler of handlers) {
2130
+ await handler({ exchange, next }, authentication);
2231
2131
  }
2232
2132
  };
2233
2133
  };
@@ -2321,14 +2221,21 @@ var errorFilter = (opts) => {
2321
2221
  };
2322
2222
 
2323
2223
  // src/server/security/authorization-filter.ts
2224
+ var logger7 = getLogger("security.auth");
2324
2225
  function authorizationFilter(opts) {
2325
2226
  const { manager, storage } = opts;
2326
2227
  return async (exchange, next) => {
2327
2228
  const promise = AsyncStorageSecurityContextHolder.getContext(storage).then((c) => c?.authentication);
2328
2229
  try {
2329
2230
  await manager.verify(promise, exchange);
2231
+ if (logger7.enabledFor("debug")) {
2232
+ logger7.debug("authorization successful");
2233
+ }
2330
2234
  } catch (error) {
2331
2235
  if (error instanceof AccessDeniedError) {
2236
+ if (logger7.enabledFor("debug")) {
2237
+ logger7.debug(`authorization failed: ${error.message}`);
2238
+ }
2332
2239
  }
2333
2240
  throw error;
2334
2241
  }
@@ -2337,12 +2244,14 @@ function authorizationFilter(opts) {
2337
2244
  }
2338
2245
 
2339
2246
  // src/server/security/delegating-authorization-manager.ts
2247
+ var logger8 = getLogger("auth");
2340
2248
  function delegatingAuthorizationManager(opts) {
2341
2249
  const check = async (authentication, exchange) => {
2342
2250
  let decision;
2343
2251
  for (const [matcher, manager] of opts.mappings) {
2344
2252
  if ((await matcher(exchange))?.match) {
2345
- const checkResult = await manager.check(authentication, { exchange });
2253
+ logger8.debug(`checking authorization on '${exchange.path}' using [${matcher}, ${manager}]`);
2254
+ const checkResult = await manager.authorize(authentication, { exchange });
2346
2255
  if (checkResult !== void 0) {
2347
2256
  decision = checkResult;
2348
2257
  break;
@@ -2355,6 +2264,308 @@ function delegatingAuthorizationManager(opts) {
2355
2264
  return new DefaultAuthorizationManager(check);
2356
2265
  }
2357
2266
 
2267
+ // src/server/cors.ts
2268
+ var import_gateway6 = require("@interopio/gateway");
2269
+ function isSameOrigin(request) {
2270
+ const origin = request.headers.one("origin");
2271
+ if (origin === void 0) {
2272
+ return true;
2273
+ }
2274
+ const url = request.URL;
2275
+ const actualProtocol = url.protocol;
2276
+ const actualHost = url.host;
2277
+ const originUrl = URL.parse(origin);
2278
+ const originHost = originUrl?.host;
2279
+ const originProtocol = originUrl?.protocol;
2280
+ return actualProtocol === originProtocol && actualHost === originHost;
2281
+ }
2282
+ function isCorsRequest(request) {
2283
+ return request.headers.has("origin") && !isSameOrigin(request);
2284
+ }
2285
+ function isPreFlightRequest(request) {
2286
+ return request.method === "OPTIONS" && request.headers.has("origin") && request.headers.has("access-control-request-method");
2287
+ }
2288
+ var VARY_HEADERS = ["Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers"];
2289
+ var processRequest = (exchange, config) => {
2290
+ const { request, response } = exchange;
2291
+ const responseHeaders = response.headers;
2292
+ if (!responseHeaders.has("Vary")) {
2293
+ responseHeaders.set("Vary", VARY_HEADERS.join(", "));
2294
+ } else {
2295
+ const varyHeaders = responseHeaders.list("Vary");
2296
+ for (const header of VARY_HEADERS) {
2297
+ if (!varyHeaders.find((h) => h === header)) {
2298
+ varyHeaders.push(header);
2299
+ }
2300
+ }
2301
+ responseHeaders.set("Vary", varyHeaders.join(", "));
2302
+ }
2303
+ try {
2304
+ if (!isCorsRequest(request)) {
2305
+ return true;
2306
+ }
2307
+ } catch (e) {
2308
+ if (logger9.enabledFor("debug")) {
2309
+ logger9.debug(`reject: origin is malformed`);
2310
+ }
2311
+ rejectRequest(response);
2312
+ return false;
2313
+ }
2314
+ if (responseHeaders.has("access-control-allow-origin")) {
2315
+ logger9.trace(`skip: already contains "Access-Control-Allow-Origin"`);
2316
+ return true;
2317
+ }
2318
+ const preFlightRequest = isPreFlightRequest(request);
2319
+ if (config) {
2320
+ return handleInternal(exchange, config, preFlightRequest);
2321
+ }
2322
+ if (preFlightRequest) {
2323
+ rejectRequest(response);
2324
+ return false;
2325
+ }
2326
+ return true;
2327
+ };
2328
+ var DEFAULT_PERMIT_ALL = ["*"];
2329
+ var DEFAULT_PERMIT_METHODS = ["GET", "HEAD", "POST"];
2330
+ var PERMIT_DEFAULT_CONFIG = {
2331
+ allowOrigins: DEFAULT_PERMIT_ALL,
2332
+ allowMethods: DEFAULT_PERMIT_METHODS,
2333
+ allowHeaders: DEFAULT_PERMIT_ALL,
2334
+ maxAge: 1800
2335
+ // 30 minutes
2336
+ };
2337
+ function validateCorsConfig(config) {
2338
+ if (config) {
2339
+ const allowHeaders = config.allowHeaders;
2340
+ if (allowHeaders && allowHeaders !== ALL) {
2341
+ config = {
2342
+ ...config,
2343
+ allowHeaders: allowHeaders.map((header) => header.toLowerCase())
2344
+ };
2345
+ }
2346
+ const allowOrigins = config.allowOrigins;
2347
+ if (allowOrigins) {
2348
+ if (allowOrigins === "*") {
2349
+ validateAllowCredentials(config);
2350
+ validateAllowPrivateNetwork(config);
2351
+ } else {
2352
+ config = {
2353
+ ...config,
2354
+ allowOrigins: allowOrigins.map((origin) => {
2355
+ if (typeof origin === "string" && origin !== ALL) {
2356
+ origin = import_gateway6.IOGateway.Filtering.regexify(origin);
2357
+ if (typeof origin === "string") {
2358
+ return trimTrailingSlash(origin).toLowerCase();
2359
+ }
2360
+ }
2361
+ return origin;
2362
+ })
2363
+ };
2364
+ }
2365
+ }
2366
+ return config;
2367
+ }
2368
+ }
2369
+ function combine(source, other) {
2370
+ if (other === void 0) {
2371
+ return source !== void 0 ? source === ALL ? [ALL] : source : [];
2372
+ }
2373
+ if (source === void 0) {
2374
+ return other === ALL ? [ALL] : other;
2375
+ }
2376
+ if (source == DEFAULT_PERMIT_ALL || source === DEFAULT_PERMIT_METHODS) {
2377
+ return other === ALL ? [ALL] : other;
2378
+ }
2379
+ if (other == DEFAULT_PERMIT_ALL || other === DEFAULT_PERMIT_METHODS) {
2380
+ return source === ALL ? [ALL] : source;
2381
+ }
2382
+ if (source === ALL || source.includes(ALL) || other === ALL || other.includes(ALL)) {
2383
+ return [ALL];
2384
+ }
2385
+ const combined = /* @__PURE__ */ new Set();
2386
+ source.forEach((v) => combined.add(v));
2387
+ other.forEach((v) => combined.add(v));
2388
+ return Array.from(combined);
2389
+ }
2390
+ var combineCorsConfig = (source, other) => {
2391
+ if (other === void 0) {
2392
+ return source;
2393
+ }
2394
+ const config = {
2395
+ allowOrigins: combine(source.allowOrigins, other?.allowOrigins),
2396
+ allowMethods: combine(source.allowMethods, other?.allowMethods),
2397
+ allowHeaders: combine(source.allowHeaders, other?.allowHeaders),
2398
+ exposeHeaders: combine(source.exposeHeaders, other?.exposeHeaders),
2399
+ allowCredentials: other?.allowCredentials ?? source.allowCredentials,
2400
+ allowPrivateNetwork: other?.allowPrivateNetwork ?? source.allowPrivateNetwork,
2401
+ maxAge: other?.maxAge ?? source.maxAge
2402
+ };
2403
+ return config;
2404
+ };
2405
+ var corsFilter = (opts) => {
2406
+ const source = opts.corsConfigSource;
2407
+ const processor = opts.corsProcessor ?? processRequest;
2408
+ return async (ctx, next) => {
2409
+ const config = await source(ctx);
2410
+ const isValid = processor(ctx, config);
2411
+ if (!isValid || isPreFlightRequest(ctx.request)) {
2412
+ return;
2413
+ } else {
2414
+ await next();
2415
+ }
2416
+ };
2417
+ };
2418
+ var cors_default = corsFilter;
2419
+ var logger9 = getLogger("cors");
2420
+ function rejectRequest(response) {
2421
+ response.statusCode = 403;
2422
+ }
2423
+ function handleInternal(exchange, config, preFlightRequest) {
2424
+ const { request, response } = exchange;
2425
+ const responseHeaders = response.headers;
2426
+ const requestOrigin = request.headers.one("origin");
2427
+ const allowOrigin = checkOrigin(config, requestOrigin);
2428
+ if (allowOrigin === void 0) {
2429
+ if (logger9.enabledFor("debug")) {
2430
+ logger9.debug(`reject: '${requestOrigin}' origin is not allowed`);
2431
+ }
2432
+ rejectRequest(response);
2433
+ return false;
2434
+ }
2435
+ const requestMethod = getMethodToUse(request, preFlightRequest);
2436
+ const allowMethods = checkMethods(config, requestMethod);
2437
+ if (allowMethods === void 0) {
2438
+ if (logger9.enabledFor("debug")) {
2439
+ logger9.debug(`reject: HTTP '${requestMethod}' is not allowed`);
2440
+ }
2441
+ rejectRequest(response);
2442
+ return false;
2443
+ }
2444
+ const requestHeaders = getHeadersToUse(request, preFlightRequest);
2445
+ const allowHeaders = checkHeaders(config, requestHeaders);
2446
+ if (preFlightRequest && allowHeaders === void 0) {
2447
+ if (logger9.enabledFor("debug")) {
2448
+ logger9.debug(`reject: headers '${requestHeaders}' are not allowed`);
2449
+ }
2450
+ rejectRequest(response);
2451
+ return false;
2452
+ }
2453
+ responseHeaders.set("Access-Control-Allow-Origin", allowOrigin);
2454
+ if (preFlightRequest) {
2455
+ responseHeaders.set("Access-Control-Allow-Methods", allowMethods.join(","));
2456
+ }
2457
+ if (preFlightRequest && allowHeaders !== void 0 && allowHeaders.length > 0) {
2458
+ responseHeaders.set("Access-Control-Allow-Headers", allowHeaders.join(", "));
2459
+ }
2460
+ const exposeHeaders = config.exposeHeaders;
2461
+ if (exposeHeaders && exposeHeaders.length > 0) {
2462
+ responseHeaders.set("Access-Control-Expose-Headers", exposeHeaders.join(", "));
2463
+ }
2464
+ if (config.allowCredentials) {
2465
+ responseHeaders.set("Access-Control-Allow-Credentials", "true");
2466
+ }
2467
+ if (config.allowPrivateNetwork && request.headers.one("access-control-request-private-network") === "true") {
2468
+ responseHeaders.set("Access-Control-Allow-Private-Network", "true");
2469
+ }
2470
+ if (preFlightRequest && config.maxAge !== void 0) {
2471
+ responseHeaders.set("Access-Control-Max-Age", config.maxAge.toString());
2472
+ }
2473
+ return true;
2474
+ }
2475
+ var ALL = "*";
2476
+ var DEFAULT_METHODS = ["GET", "HEAD"];
2477
+ function validateAllowCredentials(config) {
2478
+ if (config.allowCredentials === true && config.allowOrigins === ALL) {
2479
+ throw new Error(`when allowCredentials is true allowOrigins cannot be "*"`);
2480
+ }
2481
+ }
2482
+ function validateAllowPrivateNetwork(config) {
2483
+ if (config.allowPrivateNetwork === true && config.allowOrigins === ALL) {
2484
+ throw new Error(`when allowPrivateNetwork is true allowOrigins cannot be "*"`);
2485
+ }
2486
+ }
2487
+ function checkOrigin(config, origin) {
2488
+ if (origin) {
2489
+ const allowedOrigins = config.allowOrigins;
2490
+ if (allowedOrigins) {
2491
+ if (allowedOrigins === ALL) {
2492
+ validateAllowCredentials(config);
2493
+ validateAllowPrivateNetwork(config);
2494
+ return ALL;
2495
+ }
2496
+ const originToCheck = trimTrailingSlash(origin.toLowerCase());
2497
+ for (const allowedOrigin of allowedOrigins) {
2498
+ if (allowedOrigin === ALL || import_gateway6.IOGateway.Filtering.valueMatches(allowedOrigin, originToCheck)) {
2499
+ return origin;
2500
+ }
2501
+ }
2502
+ }
2503
+ }
2504
+ }
2505
+ function checkMethods(config, requestMethod) {
2506
+ if (requestMethod) {
2507
+ const allowedMethods = config.allowMethods ?? DEFAULT_METHODS;
2508
+ if (allowedMethods === ALL) {
2509
+ return [requestMethod];
2510
+ }
2511
+ if (import_gateway6.IOGateway.Filtering.valuesMatch(allowedMethods, requestMethod)) {
2512
+ return allowedMethods;
2513
+ }
2514
+ }
2515
+ }
2516
+ function checkHeaders(config, requestHeaders) {
2517
+ if (requestHeaders === void 0) {
2518
+ return;
2519
+ }
2520
+ if (requestHeaders.length == 0) {
2521
+ return [];
2522
+ }
2523
+ const allowedHeaders = config.allowHeaders;
2524
+ if (allowedHeaders === void 0) {
2525
+ return;
2526
+ }
2527
+ const allowAnyHeader = allowedHeaders === ALL || allowedHeaders.includes(ALL);
2528
+ const result = [];
2529
+ for (const requestHeader of requestHeaders) {
2530
+ const value = requestHeader?.trim();
2531
+ if (value) {
2532
+ if (allowAnyHeader) {
2533
+ result.push(value);
2534
+ } else {
2535
+ for (const allowedHeader of allowedHeaders) {
2536
+ if (value.toLowerCase() === allowedHeader) {
2537
+ result.push(value);
2538
+ break;
2539
+ }
2540
+ }
2541
+ }
2542
+ }
2543
+ }
2544
+ if (result.length > 0) {
2545
+ return result;
2546
+ }
2547
+ }
2548
+ function trimTrailingSlash(origin) {
2549
+ return origin.endsWith("/") ? origin.slice(0, -1) : origin;
2550
+ }
2551
+ function getMethodToUse(request, isPreFlight) {
2552
+ return isPreFlight ? request.headers.one("access-control-request-method") : request.method;
2553
+ }
2554
+ function getHeadersToUse(request, isPreFlight) {
2555
+ const headers2 = request.headers;
2556
+ return isPreFlight ? headers2.list("access-control-request-headers") : Array.from(headers2.keys());
2557
+ }
2558
+ var matchingCorsConfigSource = (opts) => {
2559
+ return async (exchange) => {
2560
+ for (const [matcher, config] of opts.mappings) {
2561
+ if ((await matcher(exchange)).match) {
2562
+ logger9.debug(`resolved cors config on '${exchange.path}' using ${matcher}: ${JSON.stringify(config)}`);
2563
+ return config;
2564
+ }
2565
+ }
2566
+ };
2567
+ };
2568
+
2358
2569
  // src/server/security/config.ts
2359
2570
  var filterOrder = {
2360
2571
  first: Number.MAX_SAFE_INTEGER,
@@ -2368,7 +2579,7 @@ var filterOrder = {
2368
2579
  last: Number.MAX_SAFE_INTEGER
2369
2580
  };
2370
2581
  var filterOrderSymbol = Symbol.for("filterOrder");
2371
- var config_default = (config, storage) => {
2582
+ var config_default = (config, context) => {
2372
2583
  const middleware = [];
2373
2584
  class ServerHttpSecurity {
2374
2585
  #authenticationEntryPoint;
@@ -2392,6 +2603,11 @@ var config_default = (config, storage) => {
2392
2603
  writer[filterOrderSymbol] = filterOrder.http_headers;
2393
2604
  middleware.push(writer);
2394
2605
  }
2606
+ if (config.cors?.disabled !== true && context.corsConfigSource !== void 0) {
2607
+ const filter = cors_default({ corsConfigSource: context.corsConfigSource });
2608
+ filter[filterOrderSymbol] = filterOrder.cors;
2609
+ middleware.push(filter);
2610
+ }
2395
2611
  if (config.basic !== void 0 && config.basic?.disabled !== true) {
2396
2612
  const username = config.basic.user?.name.toLowerCase();
2397
2613
  const password = config.basic.user?.password ?? "";
@@ -2410,7 +2626,7 @@ var config_default = (config, storage) => {
2410
2626
  }
2411
2627
  ];
2412
2628
  const filter = httpBasic({
2413
- storage,
2629
+ storage: context.storage,
2414
2630
  manager,
2415
2631
  defaultEntryPoints: this.#defaultEntryPoints,
2416
2632
  defaultSuccessHandlers
@@ -2420,20 +2636,43 @@ var config_default = (config, storage) => {
2420
2636
  }
2421
2637
  if (config.jwt !== void 0 && config.jwt.disabled !== true) {
2422
2638
  const verifier = (0, import_jwt.jwtVerifier)({
2423
- issuerBaseUri: config.jwt.issuerBaseUri,
2639
+ issuerBaseUri: config.jwt.issuerUri,
2424
2640
  issuer: config.jwt.issuer,
2425
2641
  audience: config.jwt.audience
2426
2642
  });
2427
2643
  const decoder = async (token) => {
2428
- const { payload } = await verifier(token);
2429
- return {
2430
- subject: payload.sub,
2431
- getClaimAsString(claim) {
2432
- return payload[claim];
2644
+ try {
2645
+ const { payload } = await verifier(token);
2646
+ return {
2647
+ subject: payload.sub,
2648
+ getClaimAsString(claim) {
2649
+ return payload[claim];
2650
+ }
2651
+ };
2652
+ } catch (e) {
2653
+ if (e instanceof import_jwt.JwtVerifyError) {
2654
+ throw new BadJwtError(e.message, { cause: e });
2433
2655
  }
2434
- };
2656
+ throw new JwtError("error occurred while attempting to decoding jwt", { cause: e });
2657
+ }
2435
2658
  };
2436
- const filter = resourceServer({ storage, jwt: { decoder } });
2659
+ const authenticationConverter = token_converter_default({ uriQueryParameter: true });
2660
+ const authenticationConverterMatcher = async (exchange) => {
2661
+ try {
2662
+ const a = await authenticationConverter(exchange);
2663
+ return { match: a !== void 0 };
2664
+ } catch (e) {
2665
+ return { match: false };
2666
+ }
2667
+ };
2668
+ const entryPoint = token_entry_point_default({});
2669
+ this.#defaultEntryPoints.push([authenticationConverterMatcher, entryPoint]);
2670
+ const filter = resourceServer({
2671
+ storage: context.storage,
2672
+ entryPoint,
2673
+ converter: authenticationConverter,
2674
+ jwt: { decoder }
2675
+ });
2437
2676
  filter[filterOrderSymbol] = filterOrder.authentication;
2438
2677
  middleware.push(filter);
2439
2678
  }
@@ -2455,10 +2694,12 @@ var config_default = (config, storage) => {
2455
2694
  serverMatcher = matcher;
2456
2695
  }
2457
2696
  let manager2;
2458
- if (access2.access === "permit-all") {
2697
+ if (access2.access === "permitted") {
2459
2698
  manager2 = new DefaultAuthorizationManager(async () => new AuthorizationDecision(true));
2460
- } else if (access2.access === "deny-all") {
2699
+ manager2.toString = () => "AuthorizationManager[permitted]";
2700
+ } else if (access2.access === "denied") {
2461
2701
  manager2 = new DefaultAuthorizationManager(async () => new AuthorizationDecision(false));
2702
+ manager2.toString = () => "AuthorizationManager[denied]";
2462
2703
  } else if (access2.access === "authenticated") {
2463
2704
  manager2 = new DefaultAuthorizationManager(async (p) => {
2464
2705
  const authentication = await p;
@@ -2467,6 +2708,7 @@ var config_default = (config, storage) => {
2467
2708
  }
2468
2709
  return new AuthorizationDecision(false);
2469
2710
  });
2711
+ manager2.toString = () => "AuthorizationManager[authenticated]";
2470
2712
  } else {
2471
2713
  throw new Error(`Unknown access type: ${JSON.stringify(access2)}`);
2472
2714
  }
@@ -2475,7 +2717,7 @@ var config_default = (config, storage) => {
2475
2717
  return delegatingAuthorizationManager({ mappings });
2476
2718
  };
2477
2719
  const manager = buildAuthorizationManager(config.authorize);
2478
- const filter = authorizationFilter({ manager, storage });
2720
+ const filter = authorizationFilter({ manager, storage: context.storage });
2479
2721
  filter[filterOrderSymbol] = filterOrder.authorization;
2480
2722
  middleware.push(filter);
2481
2723
  }
@@ -2491,8 +2733,80 @@ var config_default = (config, storage) => {
2491
2733
  return middleware;
2492
2734
  };
2493
2735
 
2736
+ // src/app/cors.ts
2737
+ function mockUpgradeExchange(path) {
2738
+ const request = new MockHttpRequest(path, "GET");
2739
+ request.headers.set("upgrade", "websocket");
2740
+ request["_req"] = { upgrade: true };
2741
+ return new DefaultWebExchange(request, new MockHttpResponse());
2742
+ }
2743
+ async function createCorsConfigSource(context) {
2744
+ const { sockets: routes3, cors } = context;
2745
+ const defaultCorsConfig = combineCorsConfig(PERMIT_DEFAULT_CONFIG, context.corsConfig);
2746
+ const validatedConfigs = [];
2747
+ for (const [path, route] of routes3) {
2748
+ let routeCorsConfig = defaultCorsConfig;
2749
+ const upgradeExchange = mockUpgradeExchange(path);
2750
+ for (const [matcher, config] of cors) {
2751
+ if ((await matcher(upgradeExchange)).match) {
2752
+ routeCorsConfig = combineCorsConfig(routeCorsConfig, config);
2753
+ }
2754
+ }
2755
+ routeCorsConfig = combineCorsConfig(routeCorsConfig, {
2756
+ allowOrigins: route.originFilters?.allow,
2757
+ allowMethods: ["GET", "CONNECT"],
2758
+ allowHeaders: ["upgrade", "connection", "origin", "sec-websocket-key", "sec-websocket-version", "sec-websocket-protocol", "sec-websocket-extensions"],
2759
+ exposeHeaders: ["sec-websocket-accept", "sec-websocket-protocol", "sec-websocket-extensions"],
2760
+ allowCredentials: route.authorize?.access !== "permitted"
2761
+ });
2762
+ validatedConfigs.push([and([upgradeMatcher, pattern(path)]), validateCorsConfig(routeCorsConfig)]);
2763
+ }
2764
+ for (const [matcher, config] of cors) {
2765
+ const routeCorsConfig = combineCorsConfig(defaultCorsConfig, config);
2766
+ validatedConfigs.push([matcher, validateCorsConfig(routeCorsConfig)]);
2767
+ }
2768
+ validatedConfigs.push([pattern(/\/api\/.*/), validateCorsConfig(defaultCorsConfig)]);
2769
+ return matchingCorsConfigSource({ mappings: validatedConfigs });
2770
+ }
2771
+
2772
+ // src/app/auth.ts
2773
+ function createSecurityConfig(context) {
2774
+ const authorize = [];
2775
+ const defaultAccess = { access: context.authConfig?.type !== "none" ? "authenticated" : "permitted" };
2776
+ for (const [path, route] of context.sockets) {
2777
+ const rule = route.authorize ?? defaultAccess;
2778
+ let matcher = pattern(path, { method: "GET" });
2779
+ matcher = and([upgradeMatcher, matcher]);
2780
+ authorize.push([matcher, rule]);
2781
+ }
2782
+ authorize.push([pattern("/", { method: "GET" }), { access: "permitted" }]);
2783
+ authorize.push([pattern("/favicon.ico", { method: "GET" }), { access: "permitted" }]);
2784
+ authorize.push([pattern("/health", { method: "GET" }), { access: "permitted" }]);
2785
+ if (context.authorize.length > 0) {
2786
+ authorize.push(...context.authorize);
2787
+ }
2788
+ authorize.push(["any-exchange", defaultAccess]);
2789
+ return {
2790
+ authorize,
2791
+ basic: {
2792
+ disabled: context.authConfig?.type !== "basic",
2793
+ ...context.authConfig?.basic
2794
+ },
2795
+ jwt: {
2796
+ disabled: context.authConfig?.type !== "oauth2",
2797
+ ...context.authConfig?.oauth2?.jwt
2798
+ }
2799
+ };
2800
+ }
2801
+ async function httpSecurity(context) {
2802
+ const corsConfigSource = await createCorsConfigSource(context);
2803
+ const config = createSecurityConfig(context);
2804
+ const { storage } = context;
2805
+ return config_default(config, { storage, corsConfigSource });
2806
+ }
2807
+
2494
2808
  // src/server.ts
2495
- var logger7 = getLogger("app");
2809
+ var logger10 = getLogger("app");
2496
2810
  function secureContextOptions(ssl) {
2497
2811
  const options = {};
2498
2812
  if (ssl.key) options.key = (0, import_node_fs.readFileSync)(ssl.key);
@@ -2500,60 +2814,38 @@ function secureContextOptions(ssl) {
2500
2814
  if (ssl.ca) options.ca = (0, import_node_fs.readFileSync)(ssl.ca);
2501
2815
  return options;
2502
2816
  }
2503
- function createListener(storage, middleware, routes3, onSocketError) {
2817
+ async function createListener(middleware, context, onSocketError) {
2818
+ const storage = context.storage;
2819
+ const security = await httpSecurity(context);
2504
2820
  const listener = compose(
2505
- server_header_default(),
2506
- ...config_default({
2507
- authorize: [
2508
- [async (exchange) => {
2509
- return { match: exchange.path === "/health" && exchange.method === "GET" };
2510
- }, { access: "permit-all" }],
2511
- // ['any-exchange', {access: 'authenticated'}],
2512
- ["any-exchange", { access: "permit-all" }]
2513
- ],
2514
- basic: {
2515
- disabled: true,
2516
- realm: "Gateway Server"
2517
- },
2518
- jwt: {
2519
- disabled: true
2520
- }
2521
- }, storage),
2522
- ...cors_default({
2523
- origins: { allow: [/http:\/\/localhost(:\d+)?/, /file:\//] },
2524
- methods: { allow: ["GET", "HEAD", "POST", "DELETE"] },
2525
- headers: { allow: "*" },
2526
- credentials: { allow: true }
2527
- }),
2528
- ...middleware,
2529
- async ({ request, response }, next) => {
2530
- const path = request.path ?? "/";
2531
- const route = routes3.get(path) ?? Array.from(routes3.values()).find((route2) => {
2532
- if (path === "/" && route2.default === true) {
2533
- return true;
2534
- }
2535
- });
2536
- if (route) {
2537
- if (request.method === "GET" && request._req["upgrade"] && request.headers.one("upgrade")?.toLowerCase() === "websocket") {
2821
+ server_header_default(context.serverHeader),
2822
+ ...security,
2823
+ // websocket upgrade handler
2824
+ async (exchange, next) => {
2825
+ const [route, path] = findSocketRoute(exchange, context);
2826
+ if (route !== void 0) {
2827
+ const { request, response } = exchange;
2828
+ const upgradeMatchResult = await upgradeMatcher(exchange);
2829
+ if ((request.method === "GET" || request.method === "CONNECT") && upgradeMatchResult.match) {
2538
2830
  const socket = request.socket;
2539
2831
  const host = request.host;
2540
- const info = socketKey(request._req.socket);
2541
- if (route?.wss) {
2832
+ const info2 = socketKey(request._req.socket);
2833
+ if (route.wss) {
2542
2834
  socket.removeListener("error", onSocketError);
2543
2835
  const wss = route.wss;
2544
2836
  if (route.maxConnections !== void 0 && wss.clients?.size >= route.maxConnections) {
2545
- logger7.warn(`${info} dropping ws connection request from ${host} on ${path}. max connections exceeded.`);
2837
+ logger10.warn(`${info2} dropping ws connection request from ${host} on ${path}. max connections exceeded.`);
2546
2838
  socket.destroy();
2547
2839
  return;
2548
2840
  }
2549
- const origin = request.headers["origin"];
2841
+ const origin = request.headers.one("origin");
2550
2842
  if (!acceptsOrigin(origin, route.originFilters)) {
2551
- logger7.info(`${info} dropping ws connection request from ${host} on ${path}. origin ${origin ?? "<missing>"}`);
2843
+ logger10.info(`${info2} dropping ws connection request from ${host} on ${path}. origin ${origin ?? "<missing>"}`);
2552
2844
  socket.destroy();
2553
2845
  return;
2554
2846
  }
2555
- if (logger7.enabledFor("debug")) {
2556
- logger7.debug(`${info} accepted new ws connection request from ${host} on ${path}`);
2847
+ if (logger10.enabledFor("debug")) {
2848
+ logger10.debug(`${info2} accepted new ws connection request from ${host} on ${path}`);
2557
2849
  }
2558
2850
  wss.handleUpgrade(request._req, socket, request._req["_upgradeHead"], (ws) => {
2559
2851
  response._res["_header"] = true;
@@ -2563,29 +2855,36 @@ function createListener(storage, middleware, routes3, onSocketError) {
2563
2855
  wss.emit("connection", ws, request._req);
2564
2856
  });
2565
2857
  } else {
2566
- logger7.warn(`${info} rejected upgrade request from ${host} on ${path}`);
2858
+ logger10.warn(`${info2} rejected upgrade request from ${host} on ${path}`);
2567
2859
  socket.destroy();
2568
2860
  }
2569
2861
  } else {
2570
- if (logger7.enabledFor("debug")) {
2571
- logger7.debug(`rejecting request for ${path} with method ${request.method} from ${request.socket.remoteAddress}:${request.socket.remotePort} with headers: ${JSON.stringify(request._req.rawHeaders)}`);
2862
+ if (route.default) {
2863
+ await next();
2864
+ return;
2865
+ }
2866
+ if (logger10.enabledFor("debug")) {
2867
+ logger10.debug(`rejecting request for ${path} with method ${request.method} from ${request.socket.remoteAddress}:${request.socket.remotePort} with headers: ${JSON.stringify(request._req.rawHeaders)}`);
2572
2868
  }
2573
2869
  response.statusCode = 426;
2574
- response._res.appendHeader("Upgrade", "websocket").appendHeader("Connection", "Upgrade").appendHeader("Content-Type", "text/plain");
2870
+ response.headers.set("Upgrade", "websocket").set("Connection", "Upgrade").set("Content-Type", "text/plain");
2575
2871
  await response.end(`This service [${request.path}] requires use of the websocket protocol.`);
2576
2872
  }
2577
2873
  } else {
2578
2874
  await next();
2579
2875
  }
2580
2876
  },
2877
+ ...middleware,
2878
+ // helth check
2581
2879
  async ({ request, response }, next) => {
2582
2880
  if (request.method === "GET" && request.path === "/health") {
2583
2881
  response.statusCode = 200;
2584
- response._res.end(import_node_http.default.STATUS_CODES[200]);
2882
+ await response.end(import_node_http.default.STATUS_CODES[200]);
2585
2883
  } else {
2586
2884
  await next();
2587
2885
  }
2588
2886
  },
2887
+ // home page
2589
2888
  async ({ request, response }, next) => {
2590
2889
  if (request.method === "GET" && request.path === "/") {
2591
2890
  await response.end(`io.Gateway Server`);
@@ -2593,7 +2892,8 @@ function createListener(storage, middleware, routes3, onSocketError) {
2593
2892
  await next();
2594
2893
  }
2595
2894
  },
2596
- async ({ request, response }, _next) => {
2895
+ // not found
2896
+ async ({ response }, _next) => {
2597
2897
  response.statusCode = 404;
2598
2898
  await response.end(import_node_http.default.STATUS_CODES[404]);
2599
2899
  }
@@ -2602,17 +2902,17 @@ function createListener(storage, middleware, routes3, onSocketError) {
2602
2902
  request.socket.addListener("error", onSocketError);
2603
2903
  const exchange = new DefaultWebExchange(new HttpServerRequest(request), new HttpServerResponse(response));
2604
2904
  return storage.run({ exchange }, async () => {
2605
- if (logger7.enabledFor("debug")) {
2905
+ if (logger10.enabledFor("debug")) {
2606
2906
  const socket = exchange.request._req.socket;
2607
- if (logger7.enabledFor("debug")) {
2608
- logger7.debug(`received ${exchange.method} request for ${exchange.path} from ${socket.remoteAddress}:${socket.remotePort}`);
2907
+ if (logger10.enabledFor("debug")) {
2908
+ logger10.debug(`received ${exchange.method} request for ${exchange.path} from ${socket.remoteAddress}:${socket.remotePort}`);
2609
2909
  }
2610
2910
  }
2611
2911
  try {
2612
2912
  return await listener(exchange);
2613
2913
  } catch (e) {
2614
- if (logger7.enabledFor("warn")) {
2615
- logger7.warn(`error processing request for ${exchange.path}`, e);
2914
+ if (logger10.enabledFor("warn")) {
2915
+ logger10.warn(`error processing request for ${exchange.path}`, e);
2616
2916
  }
2617
2917
  } finally {
2618
2918
  await exchange.response.end();
@@ -2647,65 +2947,75 @@ function regexAwareReplacer(_key, value) {
2647
2947
  }
2648
2948
  var Factory = async (options) => {
2649
2949
  const ssl = options.ssl;
2650
- const createServer = ssl ? (options2, handler2) => import_node_https.default.createServer({ ...options2, ...secureContextOptions(ssl) }, handler2) : (options2, handler2) => import_node_http.default.createServer(options2, handler2);
2950
+ const createServer = ssl ? (options2, handler) => import_node_https.default.createServer({ ...options2, ...secureContextOptions(ssl) }, handler) : (options2, handler) => import_node_http.default.createServer(options2, handler);
2651
2951
  const monitor = memoryMonitor(options.memory);
2652
2952
  const middleware = [];
2653
- const routes3 = /* @__PURE__ */ new Map();
2953
+ const context = {
2954
+ corsConfig: options.cors,
2955
+ cors: [],
2956
+ authConfig: options.auth,
2957
+ authorize: [],
2958
+ storage: new import_node_async_hooks2.AsyncLocalStorage(),
2959
+ sockets: /* @__PURE__ */ new Map()
2960
+ };
2654
2961
  const gw = import_gateway7.IOGateway.Factory({ ...options.gateway });
2655
2962
  if (options.gateway) {
2656
2963
  const config = options.gateway;
2657
- routes3.set(config.route ?? "/", {
2964
+ const route = config.route ?? "/";
2965
+ context.sockets.set(route, {
2658
2966
  default: config.route === void 0,
2659
2967
  ping: options.gateway.ping,
2660
2968
  factory: core_default.bind(gw),
2661
2969
  maxConnections: config.limits?.max_connections,
2970
+ authorize: config.authorize,
2662
2971
  originFilters: regexifyOriginFilters(config.origins)
2663
2972
  });
2664
2973
  }
2665
2974
  if (options.mesh) {
2666
2975
  const connections = new InMemoryNodeConnections(options.mesh.timeout ?? 6e4);
2667
- middleware.push(...routes_default(connections));
2976
+ const authorize = options.mesh.authorize;
2977
+ middleware.push(...routes_default(connections, context, authorize));
2668
2978
  const ping = options.mesh.ping ?? 3e4;
2669
- routes3.set("/broker", { factory: core_default2, ping });
2670
- routes3.set("/cluster", { factory: core_default4, ping });
2671
- routes3.set("/relays", { factory: core_default3, ping });
2979
+ const originFilters = regexifyOriginFilters(options.mesh.origins);
2980
+ context.sockets.set("/broker", { factory: core_default2, ping, originFilters, authorize });
2981
+ context.sockets.set("/cluster", { factory: core_default4, ping, originFilters, authorize });
2982
+ context.sockets.set("/relays", { factory: core_default3, ping, originFilters, authorize });
2672
2983
  }
2673
2984
  if (options.metrics) {
2674
- middleware.push(...await routes_default2(options.metrics));
2985
+ middleware.push(...await routes_default2(options.metrics, context));
2675
2986
  }
2676
2987
  const ports = portRange(options.port ?? 0);
2677
2988
  const host = options.host;
2678
- const storage = new import_node_async_hooks2.AsyncLocalStorage();
2989
+ const onSocketError = (err) => logger10.error(`socket error: ${err}`, err);
2990
+ const listener = await createListener(middleware, context, onSocketError);
2679
2991
  const serverP = new Promise((resolve, reject) => {
2680
- const onSocketError = (err) => logger7.error(`socket error: ${err}`, err);
2681
- const listener = createListener(storage, middleware, routes3, onSocketError);
2682
2992
  const server2 = createServer({}, listener);
2683
2993
  server2.on("error", (e) => {
2684
2994
  if (e["code"] === "EADDRINUSE") {
2685
- logger7.debug(`port ${e["port"]} already in use on address ${e["address"]}`);
2995
+ logger10.debug(`port ${e["port"]} already in use on address ${e["address"]}`);
2686
2996
  const { value: port } = ports.next();
2687
2997
  if (port) {
2688
- logger7.info(`retry starting server on port ${port} and host ${host ?? "<unspecified>"}`);
2998
+ logger10.info(`retry starting server on port ${port} and host ${host ?? "<unspecified>"}`);
2689
2999
  server2.close();
2690
3000
  server2.listen(port, host);
2691
3001
  } else {
2692
- logger7.warn(`all configured port(s) ${options.port} are in use. closing...`);
3002
+ logger10.warn(`all configured port(s) ${options.port} are in use. closing...`);
2693
3003
  server2.close();
2694
3004
  reject(e);
2695
3005
  }
2696
3006
  } else {
2697
- logger7.error(`server error: ${e.message}`, e);
3007
+ logger10.error(`server error: ${e.message}`, e);
2698
3008
  reject(e);
2699
3009
  }
2700
3010
  });
2701
3011
  server2.on("listening", async () => {
2702
- const info = server2.address();
2703
- for (const [path, route] of routes3) {
3012
+ const info2 = server2.address();
3013
+ for (const [path, route] of context.sockets) {
2704
3014
  try {
2705
- logger7.info(`creating ws server for [${path}]. max connections: ${route.maxConnections ?? "<unlimited>"}, origin filters: ${route.originFilters ? JSON.stringify(route.originFilters, regexAwareReplacer) : "<none>"}`);
3015
+ logger10.info(`creating ws server for [${path}]. max connections: ${route.maxConnections ?? "<unlimited>"}, origin filters: ${route.originFilters ? JSON.stringify(route.originFilters, regexAwareReplacer) : "<none>"}`);
2706
3016
  const wss = new import_ws.WebSocketServer({ noServer: true });
2707
- const endpoint = `${ssl ? "wss" : "ws"}://${localIp}:${info.port}${path}`;
2708
- const handler2 = await route.factory({ endpoint, wss, storage });
3017
+ const endpoint = `${ssl ? "wss" : "ws"}://${localIp}:${info2.port}${path}`;
3018
+ const handler = await route.factory({ endpoint, wss, storage: context.storage });
2709
3019
  const pingInterval = route.ping;
2710
3020
  if (pingInterval) {
2711
3021
  const pingIntervalId = setInterval(() => {
@@ -2722,12 +3032,12 @@ var Factory = async (options) => {
2722
3032
  });
2723
3033
  }
2724
3034
  route.wss = wss;
2725
- route.close = handler2.close?.bind(handler2);
3035
+ route.close = handler.close?.bind(handler);
2726
3036
  } catch (e) {
2727
- logger7.warn(`failed to init route ${path}`, e);
3037
+ logger10.warn(`failed to init route ${path}`, e);
2728
3038
  }
2729
3039
  }
2730
- logger7.info(`http server listening on ${info.address}:${info.port}`);
3040
+ logger10.info(`http server listening on ${info2.address}:${info2.port}`);
2731
3041
  resolve(server2);
2732
3042
  });
2733
3043
  server2.on("upgrade", (req, socket, head) => {
@@ -2738,16 +3048,16 @@ var Factory = async (options) => {
2738
3048
  res.assignSocket(socket);
2739
3049
  listener(req, res);
2740
3050
  } catch (err) {
2741
- logger7.error(`upgrade error: ${err}`, err);
3051
+ logger10.error(`upgrade error: ${err}`, err);
2742
3052
  }
2743
3053
  }).on("close", async () => {
2744
- logger7.info(`http server closed.`);
3054
+ logger10.info(`http server closed.`);
2745
3055
  });
2746
3056
  try {
2747
3057
  const { value: port } = ports.next();
2748
3058
  server2.listen(port, host);
2749
3059
  } catch (e) {
2750
- logger7.error(`error starting web socket server`, e);
3060
+ logger10.error(`error starting web socket server`, e);
2751
3061
  reject(e instanceof Error ? e : new Error(`listen failed: ${e}`));
2752
3062
  }
2753
3063
  });
@@ -2755,18 +3065,18 @@ var Factory = async (options) => {
2755
3065
  return new class {
2756
3066
  gateway = gw;
2757
3067
  async close() {
2758
- for (const [path, route] of routes3) {
3068
+ for (const [path, route] of context.sockets) {
2759
3069
  try {
2760
3070
  if (route.close) {
2761
3071
  await route.close();
2762
3072
  }
2763
- logger7.info(`stopping ws server for [${path}]. clients: ${route.wss?.clients?.size ?? 0}`);
3073
+ logger10.info(`stopping ws server for [${path}]. clients: ${route.wss?.clients?.size ?? 0}`);
2764
3074
  route.wss?.clients?.forEach((client) => {
2765
3075
  client.terminate();
2766
3076
  });
2767
3077
  route.wss?.close();
2768
3078
  } catch (e) {
2769
- logger7.warn(`error closing route ${path}`, e);
3079
+ logger10.warn(`error closing route ${path}`, e);
2770
3080
  }
2771
3081
  }
2772
3082
  await promisify((cb) => {