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