@sockethub/server 5.0.0-alpha.14 → 5.0.0-alpha.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cors.d.ts +30 -0
- package/dist/http/actions.d.ts +0 -8
- package/dist/index.js +155 -98
- package/dist/index.js.map +10 -9
- package/dist/platform-instance.d.ts +10 -1
- package/dist/platform.js +5 -3
- package/dist/platform.js.map +3 -3
- package/dist/process-manager.d.ts +10 -1
- package/package.json +13 -13
package/dist/cors.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse the `sockethub:cors:origin` config value into either `"*"` (any
|
|
3
|
+
* origin) or a normalized origin allow-list. Both the socket.io listener and
|
|
4
|
+
* the HTTP actions routes resolve their CORS policy through this single
|
|
5
|
+
* parser so the two transports can never drift apart.
|
|
6
|
+
*
|
|
7
|
+
* Browsers serialize the `Origin` request header as a lowercase
|
|
8
|
+
* `scheme://host[:port]` with default ports omitted and no trailing slash or
|
|
9
|
+
* path. Configured entries are normalized to that same serialization before
|
|
10
|
+
* matching, so values like `https://App.example.com/` still match what the
|
|
11
|
+
* browser actually sends. Entries that cannot yield a usable origin are
|
|
12
|
+
* dropped with a warning rather than left in the list where they would
|
|
13
|
+
* silently never match.
|
|
14
|
+
*
|
|
15
|
+
* A restrictive config that yields no valid origins returns an empty list
|
|
16
|
+
* (blocking all cross-origin requests) instead of falling back to `"*"`:
|
|
17
|
+
* when an operator attempted to restrict origins, failing closed is the only
|
|
18
|
+
* safe interpretation.
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseCorsOrigins(configured: unknown): "*" | Array<string>;
|
|
21
|
+
/**
|
|
22
|
+
* Resolve the `Access-Control-Allow-Origin` value for a request against an
|
|
23
|
+
* allow-list already parsed by `parseCorsOrigins`. Returns `"*"` when any
|
|
24
|
+
* origin is allowed, the request's own origin when it is in the allow-list,
|
|
25
|
+
* or `undefined` when it is not allowed (the browser then blocks the
|
|
26
|
+
* response). The request origin is run through the same URL normalization as
|
|
27
|
+
* the configured entries, so matching never depends on the client sending
|
|
28
|
+
* the canonical serialization.
|
|
29
|
+
*/
|
|
30
|
+
export declare function resolveAllowedOrigin(allowedOrigins: "*" | Array<string>, requestOrigin: string | undefined): string | undefined;
|
package/dist/http/actions.d.ts
CHANGED
|
@@ -24,14 +24,6 @@ interface HttpActionsDependencies {
|
|
|
24
24
|
createCredentialsStore?: (parentId: string, sessionId: string, secret: string, redisConfig: RedisConfig) => CredentialsStoreInterface;
|
|
25
25
|
getIdempotencyRedisConnection?: () => ReturnType<typeof getIdempotencyRedisConnection>;
|
|
26
26
|
}
|
|
27
|
-
/**
|
|
28
|
-
* Resolve the `Access-Control-Allow-Origin` value for a request, using the same
|
|
29
|
-
* `sockethub:cors:origin` config that governs socket.io. Returns `"*"` when any
|
|
30
|
-
* origin is allowed, the request's own origin when it is in a configured
|
|
31
|
-
* allow-list, or `undefined` when the origin is not allowed (the browser then
|
|
32
|
-
* blocks the response).
|
|
33
|
-
*/
|
|
34
|
-
export declare function resolveAllowedOrigin(configuredOrigin: string | undefined, requestOrigin: string | undefined): string | undefined;
|
|
35
27
|
declare function getIdempotencyRedisConnection(): import("ioredis").default;
|
|
36
28
|
export declare function registerHttpActionsRoutes(app: Express, options: HttpActionsOptions, deps?: HttpActionsDependencies): void;
|
|
37
29
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -28957,9 +28957,11 @@ function buildSchema() {
|
|
|
28957
28957
|
path: { format: String, default: "/sockethub" },
|
|
28958
28958
|
cors: {
|
|
28959
28959
|
origin: {
|
|
28960
|
-
doc: "Allowed CORS origin(s) for socket.io connections
|
|
28960
|
+
doc: "Allowed CORS origin(s) for socket.io connections " + "and the HTTP actions endpoint. '*' allows any " + "website to connect visitors' browsers to this " + "instance; public deployments should set an " + "explicit origin or comma-separated list of " + "origins.",
|
|
28961
28961
|
format: String,
|
|
28962
|
-
default: "*"
|
|
28962
|
+
default: "*",
|
|
28963
|
+
env: "SOCKETHUB_CORS_ORIGIN",
|
|
28964
|
+
arg: "cors.origin"
|
|
28963
28965
|
}
|
|
28964
28966
|
}
|
|
28965
28967
|
},
|
|
@@ -70297,7 +70299,7 @@ var require_package2 = __commonJS((exports, module) => {
|
|
|
70297
70299
|
module.exports = {
|
|
70298
70300
|
name: "@sockethub/server",
|
|
70299
70301
|
description: "A polyglot messaging service, server libraries",
|
|
70300
|
-
version: "5.0.0-alpha.
|
|
70302
|
+
version: "5.0.0-alpha.15",
|
|
70301
70303
|
type: "module",
|
|
70302
70304
|
private: false,
|
|
70303
70305
|
author: "Nick Jennings <nick@silverbucket.net>",
|
|
@@ -70347,11 +70349,11 @@ var require_package2 = __commonJS((exports, module) => {
|
|
|
70347
70349
|
homepage: "https://sockethub.org",
|
|
70348
70350
|
dependencies: {
|
|
70349
70351
|
"@sentry/node": "^10.36.0",
|
|
70350
|
-
"@sockethub/client": "^5.0.0-alpha.
|
|
70351
|
-
"@sockethub/data-layer": "^1.0.0-alpha.
|
|
70352
|
-
"@sockethub/logger": "^1.0.0-alpha.
|
|
70353
|
-
"@sockethub/schemas": "^3.0.0-alpha.
|
|
70354
|
-
"@sockethub/util": "^1.0.0-alpha.
|
|
70352
|
+
"@sockethub/client": "^5.0.0-alpha.15",
|
|
70353
|
+
"@sockethub/data-layer": "^1.0.0-alpha.15",
|
|
70354
|
+
"@sockethub/logger": "^1.0.0-alpha.15",
|
|
70355
|
+
"@sockethub/schemas": "^3.0.0-alpha.15",
|
|
70356
|
+
"@sockethub/util": "^1.0.0-alpha.3",
|
|
70355
70357
|
chalk: "^5.6.2",
|
|
70356
70358
|
convict: "^6.2.5",
|
|
70357
70359
|
ejs: "^3.1.10",
|
|
@@ -70382,14 +70384,14 @@ var require_package2 = __commonJS((exports, module) => {
|
|
|
70382
70384
|
"web-streams-polyfill": "^3.3.3"
|
|
70383
70385
|
},
|
|
70384
70386
|
optionalDependencies: {
|
|
70385
|
-
"@sockethub/examples": "^1.0.0-alpha.
|
|
70386
|
-
"@sockethub/platform-dummy": "^3.0.0-alpha.
|
|
70387
|
-
"@sockethub/platform-feeds": "^4.0.0-alpha.
|
|
70388
|
-
"@sockethub/platform-irc": "^4.0.0-alpha.
|
|
70389
|
-
"@sockethub/platform-metadata": "^1.0.1-alpha.
|
|
70390
|
-
"@sockethub/platform-xmpp": "^5.0.0-alpha.
|
|
70391
|
-
},
|
|
70392
|
-
gitHead: "
|
|
70387
|
+
"@sockethub/examples": "^1.0.0-alpha.15",
|
|
70388
|
+
"@sockethub/platform-dummy": "^3.0.0-alpha.15",
|
|
70389
|
+
"@sockethub/platform-feeds": "^4.0.0-alpha.15",
|
|
70390
|
+
"@sockethub/platform-irc": "^4.0.0-alpha.15",
|
|
70391
|
+
"@sockethub/platform-metadata": "^1.0.1-alpha.10",
|
|
70392
|
+
"@sockethub/platform-xmpp": "^5.0.0-alpha.15"
|
|
70393
|
+
},
|
|
70394
|
+
gitHead: "7f85c0aa1c317b56336af4149b29dc78afc5f2bd",
|
|
70393
70395
|
types: "./dist/index.d.ts"
|
|
70394
70396
|
};
|
|
70395
70397
|
});
|
|
@@ -121087,7 +121089,7 @@ var require_node7 = __commonJS((exports, module) => {
|
|
|
121087
121089
|
var tty2 = __require("tty");
|
|
121088
121090
|
var util = __require("util");
|
|
121089
121091
|
exports.init = init2;
|
|
121090
|
-
exports.log =
|
|
121092
|
+
exports.log = log6;
|
|
121091
121093
|
exports.formatArgs = formatArgs;
|
|
121092
121094
|
exports.save = save;
|
|
121093
121095
|
exports.load = load;
|
|
@@ -121219,7 +121221,7 @@ var require_node7 = __commonJS((exports, module) => {
|
|
|
121219
121221
|
}
|
|
121220
121222
|
return new Date().toISOString() + " ";
|
|
121221
121223
|
}
|
|
121222
|
-
function
|
|
121224
|
+
function log6(...args) {
|
|
121223
121225
|
return process.stderr.write(util.format(...args) + `
|
|
121224
121226
|
`);
|
|
121225
121227
|
}
|
|
@@ -126023,7 +126025,7 @@ var require_node8 = __commonJS((exports, module) => {
|
|
|
126023
126025
|
var tty2 = __require("tty");
|
|
126024
126026
|
var util = __require("util");
|
|
126025
126027
|
exports.init = init2;
|
|
126026
|
-
exports.log =
|
|
126028
|
+
exports.log = log6;
|
|
126027
126029
|
exports.formatArgs = formatArgs;
|
|
126028
126030
|
exports.save = save;
|
|
126029
126031
|
exports.load = load;
|
|
@@ -126155,7 +126157,7 @@ var require_node8 = __commonJS((exports, module) => {
|
|
|
126155
126157
|
}
|
|
126156
126158
|
return new Date().toISOString() + " ";
|
|
126157
126159
|
}
|
|
126158
|
-
function
|
|
126160
|
+
function log6(...args) {
|
|
126159
126161
|
return process.stderr.write(util.format(...args) + `
|
|
126160
126162
|
`);
|
|
126161
126163
|
}
|
|
@@ -135189,7 +135191,7 @@ function disable() {
|
|
|
135189
135191
|
function isEnabled() {
|
|
135190
135192
|
return _getLoggerSettings().enabled;
|
|
135191
135193
|
}
|
|
135192
|
-
function
|
|
135194
|
+
function log10(...args) {
|
|
135193
135195
|
_maybeLog("log", ...args);
|
|
135194
135196
|
}
|
|
135195
135197
|
function warn(...args) {
|
|
@@ -135233,7 +135235,7 @@ var init_debug_logger = __esm(() => {
|
|
|
135233
135235
|
enable,
|
|
135234
135236
|
disable,
|
|
135235
135237
|
isEnabled,
|
|
135236
|
-
log:
|
|
135238
|
+
log: log10,
|
|
135237
135239
|
warn,
|
|
135238
135240
|
error
|
|
135239
135241
|
};
|
|
@@ -139704,12 +139706,12 @@ function estimateMetricSizeInBytes(metric) {
|
|
|
139704
139706
|
weight += 8;
|
|
139705
139707
|
return weight + estimateAttributesSizeInBytes(metric.attributes);
|
|
139706
139708
|
}
|
|
139707
|
-
function estimateLogSizeInBytes(
|
|
139709
|
+
function estimateLogSizeInBytes(log11) {
|
|
139708
139710
|
let weight = 0;
|
|
139709
|
-
if (
|
|
139710
|
-
weight +=
|
|
139711
|
+
if (log11.message) {
|
|
139712
|
+
weight += log11.message.length * 2;
|
|
139711
139713
|
}
|
|
139712
|
-
return weight + estimateAttributesSizeInBytes(
|
|
139714
|
+
return weight + estimateAttributesSizeInBytes(log11.attributes);
|
|
139713
139715
|
}
|
|
139714
139716
|
function estimateAttributesSizeInBytes(attributes) {
|
|
139715
139717
|
if (!attributes) {
|
|
@@ -140954,8 +140956,8 @@ function instrumentConsole() {
|
|
|
140954
140956
|
return function(...args) {
|
|
140955
140957
|
const handlerData = { args, level };
|
|
140956
140958
|
triggerHandlers("console", handlerData);
|
|
140957
|
-
const
|
|
140958
|
-
|
|
140959
|
+
const log11 = originalConsoleMethods[level];
|
|
140960
|
+
log11?.apply(GLOBAL_OBJ.console, args);
|
|
140959
140961
|
};
|
|
140960
140962
|
});
|
|
140961
140963
|
});
|
|
@@ -148585,7 +148587,7 @@ var init_common = () => {};
|
|
|
148585
148587
|
|
|
148586
148588
|
// ../../node_modules/@sentry/node-core/build/esm/integrations/local-variables/local-variables-async.js
|
|
148587
148589
|
import { Worker as Worker3 } from "node:worker_threads";
|
|
148588
|
-
function
|
|
148590
|
+
function log11(...args) {
|
|
148589
148591
|
debug.log("[LocalVariables]", ...args);
|
|
148590
148592
|
}
|
|
148591
148593
|
var base64WorkerScript = "LyohIEBzZW50cnkvbm9kZS1jb3JlIDEwLjM2LjAgKDIxZWM4ZjEpIHwgaHR0cHM6Ly9naXRodWIuY29tL2dldHNlbnRyeS9zZW50cnktamF2YXNjcmlwdCAqLwppbXBvcnR7U2Vzc2lvbiBhcyBlfWZyb20ibm9kZTppbnNwZWN0b3IvcHJvbWlzZXMiO2ltcG9ydHt3b3JrZXJEYXRhIGFzIHR9ZnJvbSJub2RlOndvcmtlcl90aHJlYWRzIjtjb25zdCBuPWdsb2JhbFRoaXMsaT17fTtjb25zdCBvPSJfX1NFTlRSWV9FUlJPUl9MT0NBTF9WQVJJQUJMRVNfXyI7Y29uc3QgYT10O2Z1bmN0aW9uIHMoLi4uZSl7YS5kZWJ1ZyYmZnVuY3Rpb24oZSl7aWYoISgiY29uc29sZSJpbiBuKSlyZXR1cm4gZSgpO2NvbnN0IHQ9bi5jb25zb2xlLG89e30sYT1PYmplY3Qua2V5cyhpKTthLmZvckVhY2goZT0+e2NvbnN0IG49aVtlXTtvW2VdPXRbZV0sdFtlXT1ufSk7dHJ5e3JldHVybiBlKCl9ZmluYWxseXthLmZvckVhY2goZT0+e3RbZV09b1tlXX0pfX0oKCk9PmNvbnNvbGUubG9nKCJbTG9jYWxWYXJpYWJsZXMgV29ya2VyXSIsLi4uZSkpfWFzeW5jIGZ1bmN0aW9uIGMoZSx0LG4saSl7Y29uc3Qgbz1hd2FpdCBlLnBvc3QoIlJ1bnRpbWUuZ2V0UHJvcGVydGllcyIse29iamVjdElkOnQsb3duUHJvcGVydGllczohMH0pO2lbbl09by5yZXN1bHQuZmlsdGVyKGU9PiJsZW5ndGgiIT09ZS5uYW1lJiYhaXNOYU4ocGFyc2VJbnQoZS5uYW1lLDEwKSkpLnNvcnQoKGUsdCk9PnBhcnNlSW50KGUubmFtZSwxMCktcGFyc2VJbnQodC5uYW1lLDEwKSkubWFwKGU9PmUudmFsdWU/LnZhbHVlKX1hc3luYyBmdW5jdGlvbiByKGUsdCxuLGkpe2NvbnN0IG89YXdhaXQgZS5wb3N0KCJSdW50aW1lLmdldFByb3BlcnRpZXMiLHtvYmplY3RJZDp0LG93blByb3BlcnRpZXM6ITB9KTtpW25dPW8ucmVzdWx0Lm1hcChlPT5bZS5uYW1lLGUudmFsdWU/LnZhbHVlXSkucmVkdWNlKChlLFt0LG5dKT0+KGVbdF09bixlKSx7fSl9ZnVuY3Rpb24gdShlLHQpe2UudmFsdWUmJigidmFsdWUiaW4gZS52YWx1ZT92b2lkIDA9PT1lLnZhbHVlLnZhbHVlfHxudWxsPT09ZS52YWx1ZS52YWx1ZT90W2UubmFtZV09YDwke2UudmFsdWUudmFsdWV9PmA6dFtlLm5hbWVdPWUudmFsdWUudmFsdWU6ImRlc2NyaXB0aW9uImluIGUudmFsdWUmJiJmdW5jdGlvbiIhPT1lLnZhbHVlLnR5cGU/dFtlLm5hbWVdPWA8JHtlLnZhbHVlLmRlc2NyaXB0aW9ufT5gOiJ1bmRlZmluZWQiPT09ZS52YWx1ZS50eXBlJiYodFtlLm5hbWVdPSI8dW5kZWZpbmVkPiIpKX1hc3luYyBmdW5jdGlvbiBsKGUsdCl7Y29uc3Qgbj1hd2FpdCBlLnBvc3QoIlJ1bnRpbWUuZ2V0UHJvcGVydGllcyIse29iamVjdElkOnQsb3duUHJvcGVydGllczohMH0pLGk9e307Zm9yKGNvbnN0IHQgb2Ygbi5yZXN1bHQpaWYodC52YWx1ZT8ub2JqZWN0SWQmJiJBcnJheSI9PT10LnZhbHVlLmNsYXNzTmFtZSl7Y29uc3Qgbj10LnZhbHVlLm9iamVjdElkO2F3YWl0IGMoZSxuLHQubmFtZSxpKX1lbHNlIGlmKHQudmFsdWU/Lm9iamVjdElkJiYiT2JqZWN0Ij09PXQudmFsdWUuY2xhc3NOYW1lKXtjb25zdCBuPXQudmFsdWUub2JqZWN0SWQ7YXdhaXQgcihlLG4sdC5uYW1lLGkpfWVsc2UgdC52YWx1ZSYmdSh0LGkpO3JldHVybiBpfWxldCBmOyhhc3luYyBmdW5jdGlvbigpe2NvbnN0IHQ9bmV3IGU7dC5jb25uZWN0VG9NYWluVGhyZWFkKCkscygiQ29ubmVjdGVkIHRvIG1haW4gdGhyZWFkIik7bGV0IG49ITE7dC5vbigiRGVidWdnZXIucmVzdW1lZCIsKCk9PntuPSExfSksdC5vbigiRGVidWdnZXIucGF1c2VkIixlPT57bj0hMCxhc3luYyBmdW5jdGlvbihlLHtyZWFzb246dCxkYXRhOntvYmplY3RJZDpufSxjYWxsRnJhbWVzOml9KXtpZigiZXhjZXB0aW9uIiE9PXQmJiJwcm9taXNlUmVqZWN0aW9uIiE9PXQpcmV0dXJuO2lmKGY/LigpLG51bGw9PW4pcmV0dXJuO2NvbnN0IGE9W107Zm9yKGxldCB0PTA7dDxpLmxlbmd0aDt0Kyspe2NvbnN0e3Njb3BlQ2hhaW46bixmdW5jdGlvbk5hbWU6byx0aGlzOnN9PWlbdF0sYz1uLmZpbmQoZT0+ImxvY2FsIj09PWUudHlwZSkscj0iZ2xvYmFsIiE9PXMuY2xhc3NOYW1lJiZzLmNsYXNzTmFtZT9gJHtzLmNsYXNzTmFtZX0uJHtvfWA6bztpZih2b2lkIDA9PT1jPy5vYmplY3Qub2JqZWN0SWQpYVt0XT17ZnVuY3Rpb246cn07ZWxzZXtjb25zdCBuPWF3YWl0IGwoZSxjLm9iamVjdC5vYmplY3RJZCk7YVt0XT17ZnVuY3Rpb246cix2YXJzOm59fX1hd2FpdCBlLnBvc3QoIlJ1bnRpbWUuY2FsbEZ1bmN0aW9uT24iLHtmdW5jdGlvbkRlY2xhcmF0aW9uOmBmdW5jdGlvbigpIHsgdGhpcy4ke299ID0gdGhpcy4ke299IHx8ICR7SlNPTi5zdHJpbmdpZnkoYSl9OyB9YCxzaWxlbnQ6ITAsb2JqZWN0SWQ6bn0pLGF3YWl0IGUucG9zdCgiUnVudGltZS5yZWxlYXNlT2JqZWN0Iix7b2JqZWN0SWQ6bn0pfSh0LGUucGFyYW1zKS50aGVuKGFzeW5jKCk9PntuJiZhd2FpdCB0LnBvc3QoIkRlYnVnZ2VyLnJlc3VtZSIpfSxhc3luYyBlPT57biYmYXdhaXQgdC5wb3N0KCJEZWJ1Z2dlci5yZXN1bWUiKX0pfSksYXdhaXQgdC5wb3N0KCJEZWJ1Z2dlci5lbmFibGUiKTtjb25zdCBpPSExIT09YS5jYXB0dXJlQWxsRXhjZXB0aW9ucztpZihhd2FpdCB0LnBvc3QoIkRlYnVnZ2VyLnNldFBhdXNlT25FeGNlcHRpb25zIix7c3RhdGU6aT8iYWxsIjoidW5jYXVnaHQifSksaSl7Y29uc3QgZT1hLm1heEV4Y2VwdGlvbnNQZXJTZWNvbmR8fDUwO2Y9ZnVuY3Rpb24oZSx0LG4pe2xldCBpPTAsbz01LGE9MDtyZXR1cm4gc2V0SW50ZXJ2YWwoKCk9PnswPT09YT9pPmUmJihvKj0yLG4obyksbz44NjQwMCYmKG89ODY0MDApLGE9byk6KGEtPTEsMD09PWEmJnQoKSksaT0wfSwxZTMpLnVucmVmKCksKCk9PntpKz0xfX0oZSxhc3luYygpPT57cygiUmF0ZS1saW1pdCBsaWZ0ZWQuIiksYXdhaXQgdC5wb3N0KCJEZWJ1Z2dlci5zZXRQYXVzZU9uRXhjZXB0aW9ucyIse3N0YXRlOiJhbGwifSl9LGFzeW5jIGU9PntzKGBSYXRlLWxpbWl0IGV4Y2VlZGVkLiBEaXNhYmxpbmcgY2FwdHVyaW5nIG9mIGNhdWdodCBleGNlcHRpb25zIGZvciAke2V9IHNlY29uZHMuYCksYXdhaXQgdC5wb3N0KCJEZWJ1Z2dlci5zZXRQYXVzZU9uRXhjZXB0aW9ucyIse3N0YXRlOiJ1bmNhdWdodCJ9KX0pfX0pKCkuY2F0Y2goZT0+e3MoIkZhaWxlZCB0byBzdGFydCBkZWJ1Z2dlciIsZSl9KSxzZXRJbnRlcnZhbCgoKT0+e30sMWU0KTs=", localVariablesAsyncIntegration;
|
|
@@ -148634,10 +148636,10 @@ var init_local_variables_async = __esm(() => {
|
|
|
148634
148636
|
worker.terminate();
|
|
148635
148637
|
});
|
|
148636
148638
|
worker.once("error", (err) => {
|
|
148637
|
-
|
|
148639
|
+
log11("Worker error", err);
|
|
148638
148640
|
});
|
|
148639
148641
|
worker.once("exit", (code) => {
|
|
148640
|
-
|
|
148642
|
+
log11("Worker exit", code);
|
|
148641
148643
|
});
|
|
148642
148644
|
worker.unref();
|
|
148643
148645
|
}
|
|
@@ -150325,9 +150327,9 @@ var init_client2 = __esm(() => {
|
|
|
150325
150327
|
_INTERNAL_flushLogsBuffer(this);
|
|
150326
150328
|
};
|
|
150327
150329
|
if (serverName) {
|
|
150328
|
-
this.on("beforeCaptureLog", (
|
|
150329
|
-
|
|
150330
|
-
...
|
|
150330
|
+
this.on("beforeCaptureLog", (log12) => {
|
|
150331
|
+
log12.attributes = {
|
|
150332
|
+
...log12.attributes,
|
|
150331
150333
|
"server.address": serverName
|
|
150332
150334
|
};
|
|
150333
150335
|
});
|
|
@@ -187441,6 +187443,63 @@ class RedisStore {
|
|
|
187441
187443
|
// src/http/actions.ts
|
|
187442
187444
|
init_config();
|
|
187443
187445
|
|
|
187446
|
+
// src/cors.ts
|
|
187447
|
+
init_src();
|
|
187448
|
+
var log5 = createLogger("server:cors");
|
|
187449
|
+
function parseCorsOrigins(configured) {
|
|
187450
|
+
const raw = typeof configured === "string" ? configured.trim() : "";
|
|
187451
|
+
if (raw === "" || raw === "*") {
|
|
187452
|
+
return "*";
|
|
187453
|
+
}
|
|
187454
|
+
const origins = [];
|
|
187455
|
+
for (const entry of raw.split(",")) {
|
|
187456
|
+
const trimmed = entry.trim();
|
|
187457
|
+
if (trimmed.length === 0) {
|
|
187458
|
+
continue;
|
|
187459
|
+
}
|
|
187460
|
+
if (trimmed === "*") {
|
|
187461
|
+
log5.warn("cors origin list contains '*'; allowing any origin and " + "ignoring the other entries");
|
|
187462
|
+
return "*";
|
|
187463
|
+
}
|
|
187464
|
+
let origin;
|
|
187465
|
+
try {
|
|
187466
|
+
origin = new URL(trimmed).origin;
|
|
187467
|
+
} catch {
|
|
187468
|
+
log5.warn(`ignoring cors origin entry that is not a valid URL: "${trimmed}"` + " (origins must include a scheme, e.g. https://app.example.com)");
|
|
187469
|
+
continue;
|
|
187470
|
+
}
|
|
187471
|
+
if (origin === "null") {
|
|
187472
|
+
log5.warn(`ignoring cors origin entry with no usable origin: "${trimmed}"`);
|
|
187473
|
+
continue;
|
|
187474
|
+
}
|
|
187475
|
+
if (origin !== trimmed) {
|
|
187476
|
+
log5.warn(`normalized cors origin "${trimmed}" to "${origin}"`);
|
|
187477
|
+
}
|
|
187478
|
+
if (!origins.includes(origin)) {
|
|
187479
|
+
origins.push(origin);
|
|
187480
|
+
}
|
|
187481
|
+
}
|
|
187482
|
+
if (origins.length === 0) {
|
|
187483
|
+
log5.error("cors origin config contained no valid origins; all " + "cross-origin requests will be blocked");
|
|
187484
|
+
}
|
|
187485
|
+
return origins;
|
|
187486
|
+
}
|
|
187487
|
+
function resolveAllowedOrigin(allowedOrigins, requestOrigin) {
|
|
187488
|
+
if (allowedOrigins === "*") {
|
|
187489
|
+
return "*";
|
|
187490
|
+
}
|
|
187491
|
+
if (!requestOrigin) {
|
|
187492
|
+
return;
|
|
187493
|
+
}
|
|
187494
|
+
let normalized;
|
|
187495
|
+
try {
|
|
187496
|
+
normalized = new URL(requestOrigin).origin;
|
|
187497
|
+
} catch {
|
|
187498
|
+
return;
|
|
187499
|
+
}
|
|
187500
|
+
return allowedOrigins.includes(normalized) ? requestOrigin : undefined;
|
|
187501
|
+
}
|
|
187502
|
+
|
|
187444
187503
|
// src/message-handlers.ts
|
|
187445
187504
|
init_src2();
|
|
187446
187505
|
|
|
@@ -187520,8 +187579,8 @@ var routes_default = routes;
|
|
|
187520
187579
|
// src/listener.ts
|
|
187521
187580
|
var require2 = createRequire4(import.meta.url);
|
|
187522
187581
|
var packageJson = require2("../package.json");
|
|
187523
|
-
var
|
|
187524
|
-
|
|
187582
|
+
var log6 = createLogger("server:listener");
|
|
187583
|
+
log6.info(`sockethub v${packageJson.version}`);
|
|
187525
187584
|
|
|
187526
187585
|
class Listener {
|
|
187527
187586
|
app;
|
|
@@ -187549,10 +187608,10 @@ class Listener {
|
|
|
187549
187608
|
const examplesPkgPath = require2.resolve("@sockethub/examples/package.json");
|
|
187550
187609
|
const examplesDir = path3.join(path3.dirname(examplesPkgPath), "build");
|
|
187551
187610
|
if (existsSync2(examplesDir)) {
|
|
187552
|
-
|
|
187611
|
+
log6.debug(`examples resolved from @sockethub/examples: ${examplesDir}`);
|
|
187553
187612
|
return examplesDir;
|
|
187554
187613
|
}
|
|
187555
|
-
|
|
187614
|
+
log6.debug(`@sockethub/examples found but build directory missing: ${examplesDir}`);
|
|
187556
187615
|
return null;
|
|
187557
187616
|
} catch {
|
|
187558
187617
|
return null;
|
|
@@ -187592,25 +187651,17 @@ class Listener {
|
|
|
187592
187651
|
next();
|
|
187593
187652
|
return;
|
|
187594
187653
|
}
|
|
187595
|
-
|
|
187654
|
+
log6.debug(`examples request ${req.path}`);
|
|
187596
187655
|
res.sendFile(examplesIndex);
|
|
187597
187656
|
});
|
|
187598
|
-
|
|
187657
|
+
log6.info(`examples served at http://${config_default.get("sockethub:host")}:${config_default.get("sockethub:port")}`);
|
|
187599
187658
|
}
|
|
187600
187659
|
static corsOrigin() {
|
|
187601
|
-
|
|
187602
|
-
if (configured === "*" || configured === "") {
|
|
187603
|
-
return "*";
|
|
187604
|
-
}
|
|
187605
|
-
const origins = configured.split(",").map((origin) => origin.trim()).filter((origin) => origin.length > 0);
|
|
187606
|
-
if (origins.length === 0) {
|
|
187607
|
-
return "*";
|
|
187608
|
-
}
|
|
187609
|
-
return origins.length === 1 ? origins[0] : origins;
|
|
187660
|
+
return parseCorsOrigins(config_default.get("sockethub:cors:origin"));
|
|
187610
187661
|
}
|
|
187611
187662
|
startHttp() {
|
|
187612
187663
|
this.http.listen(config_default.get("sockethub:port"), config_default.get("sockethub:host"), () => {
|
|
187613
|
-
|
|
187664
|
+
log6.info(`sockethub listening on ws://${config_default.get("sockethub:host")}:${config_default.get("sockethub:port")}`);
|
|
187614
187665
|
});
|
|
187615
187666
|
}
|
|
187616
187667
|
static initExpress() {
|
|
@@ -187663,6 +187714,7 @@ class PlatformInstance {
|
|
|
187663
187714
|
heartbeatListener;
|
|
187664
187715
|
heartbeatFailureHandled = false;
|
|
187665
187716
|
replaced = false;
|
|
187717
|
+
shutdownResult;
|
|
187666
187718
|
actor;
|
|
187667
187719
|
constructor(params) {
|
|
187668
187720
|
this.id = params.identifier;
|
|
@@ -187722,7 +187774,13 @@ class PlatformInstance {
|
|
|
187722
187774
|
this.replaced = true;
|
|
187723
187775
|
this.flaggedForTermination = true;
|
|
187724
187776
|
}
|
|
187725
|
-
|
|
187777
|
+
shutdown() {
|
|
187778
|
+
if (!this.shutdownResult) {
|
|
187779
|
+
this.shutdownResult = this.teardown();
|
|
187780
|
+
}
|
|
187781
|
+
return this.shutdownResult;
|
|
187782
|
+
}
|
|
187783
|
+
async teardown() {
|
|
187726
187784
|
this.log.debug("platform process shutdown");
|
|
187727
187785
|
this.flaggedForTermination = true;
|
|
187728
187786
|
try {
|
|
@@ -188238,7 +188296,7 @@ function createMessageHandlers(options) {
|
|
|
188238
188296
|
}
|
|
188239
188297
|
let platformInstance;
|
|
188240
188298
|
try {
|
|
188241
|
-
platformInstance = processManager.get(platformId, msg.actor.id, platformSessionId, clientIp);
|
|
188299
|
+
platformInstance = await processManager.get(platformId, msg.actor.id, platformSessionId, clientIp);
|
|
188242
188300
|
} catch (err) {
|
|
188243
188301
|
next(attachError(err, msg));
|
|
188244
188302
|
return;
|
|
@@ -188285,7 +188343,7 @@ function hasHttpSessions(platformId) {
|
|
|
188285
188343
|
}
|
|
188286
188344
|
|
|
188287
188345
|
// src/http/actions.ts
|
|
188288
|
-
var
|
|
188346
|
+
var log7 = createLogger("server:http:actions");
|
|
188289
188347
|
var REQUEST_ID_HEADER = "x-request-id";
|
|
188290
188348
|
var SOCKETHUB_REQUEST_ID_HEADER = "x-sockethub-request-id";
|
|
188291
188349
|
var DEFAULT_HTTP_ACTIONS_PATH = "/sockethub-http";
|
|
@@ -188396,23 +188454,10 @@ function resolveConfigNumber(getConfig, key, fallback) {
|
|
|
188396
188454
|
}
|
|
188397
188455
|
return fallback;
|
|
188398
188456
|
}
|
|
188399
|
-
function resolveAllowedOrigin(configuredOrigin, requestOrigin) {
|
|
188400
|
-
const configured = (configuredOrigin ?? "*").trim();
|
|
188401
|
-
if (configured === "*" || configured === "") {
|
|
188402
|
-
return "*";
|
|
188403
|
-
}
|
|
188404
|
-
const allowed = configured.split(",").map((origin) => origin.trim()).filter((origin) => origin.length > 0);
|
|
188405
|
-
if (allowed.length === 0) {
|
|
188406
|
-
return "*";
|
|
188407
|
-
}
|
|
188408
|
-
if (requestOrigin && allowed.includes(requestOrigin)) {
|
|
188409
|
-
return requestOrigin;
|
|
188410
|
-
}
|
|
188411
|
-
return;
|
|
188412
|
-
}
|
|
188413
188457
|
function createCorsMiddleware(getConfig) {
|
|
188458
|
+
const allowedOrigins = parseCorsOrigins(getConfig("sockethub:cors:origin"));
|
|
188414
188459
|
return (req, res, next) => {
|
|
188415
|
-
const allowOrigin = resolveAllowedOrigin(
|
|
188460
|
+
const allowOrigin = resolveAllowedOrigin(allowedOrigins, req.headers.origin);
|
|
188416
188461
|
if (allowOrigin) {
|
|
188417
188462
|
res.setHeader("Access-Control-Allow-Origin", allowOrigin);
|
|
188418
188463
|
if (allowOrigin !== "*") {
|
|
@@ -188574,7 +188619,7 @@ function registerHttpActionsRoutes(app, options, deps = {}) {
|
|
|
188574
188619
|
requestId
|
|
188575
188620
|
});
|
|
188576
188621
|
} catch (err) {
|
|
188577
|
-
|
|
188622
|
+
log7.error(`idempotency lookup error for ${requestId}: ${String(err)}`);
|
|
188578
188623
|
res.status(503).json({
|
|
188579
188624
|
error: "idempotency store unavailable"
|
|
188580
188625
|
});
|
|
@@ -188640,7 +188685,7 @@ function registerHttpActionsRoutes(app, options, deps = {}) {
|
|
|
188640
188685
|
await idempotencyRedis.del(idempotencyKeys.listKey);
|
|
188641
188686
|
await idempotencyRedis.pexpire(idempotencyKeys.listKey, idempotencyTtlMs);
|
|
188642
188687
|
} catch (err) {
|
|
188643
|
-
|
|
188688
|
+
log7.error(`idempotency store error for ${requestId}: ${String(err)}`);
|
|
188644
188689
|
res.status(503).json({
|
|
188645
188690
|
error: "idempotency store unavailable"
|
|
188646
188691
|
});
|
|
@@ -188684,7 +188729,7 @@ function registerHttpActionsRoutes(app, options, deps = {}) {
|
|
|
188684
188729
|
}
|
|
188685
188730
|
platformIds.clear();
|
|
188686
188731
|
credentialsStore.teardown?.()?.catch((err) => {
|
|
188687
|
-
|
|
188732
|
+
log7.error(`credentials store teardown failed for ${sessionId}: ${String(err)}`);
|
|
188688
188733
|
});
|
|
188689
188734
|
if (requestTimeoutId) {
|
|
188690
188735
|
clearTimeout(requestTimeoutId);
|
|
@@ -188706,7 +188751,7 @@ function registerHttpActionsRoutes(app, options, deps = {}) {
|
|
|
188706
188751
|
};
|
|
188707
188752
|
if (useIdempotency && idempotencyRedis && idempotencyKeys) {
|
|
188708
188753
|
redisWriteChain = redisWriteChain.then(() => idempotencyRedis.set(idempotencyKeys.statusKey, "complete", "PX", idempotencyTtlMs)).catch((err) => {
|
|
188709
|
-
|
|
188754
|
+
log7.error(`failed to finalize idempotency for ${requestId}: ${String(err)}`);
|
|
188710
188755
|
}).finally(finish);
|
|
188711
188756
|
return;
|
|
188712
188757
|
}
|
|
@@ -188726,7 +188771,7 @@ function registerHttpActionsRoutes(app, options, deps = {}) {
|
|
|
188726
188771
|
return;
|
|
188727
188772
|
}
|
|
188728
188773
|
redisWriteChain = redisWriteChain.then(() => idempotencyRedis.rpush(idempotencyKeys.listKey, serialized)).then(() => idempotencyRedis.pexpire(idempotencyKeys.listKey, idempotencyTtlMs)).then(() => idempotencyRedis.pexpire(idempotencyKeys.statusKey, idempotencyTtlMs)).catch((err) => {
|
|
188729
|
-
|
|
188774
|
+
log7.error(`failed to persist idempotency result for ${requestId}: ${String(err)}`);
|
|
188730
188775
|
});
|
|
188731
188776
|
};
|
|
188732
188777
|
const writeErrorLine = (message) => {
|
|
@@ -188784,7 +188829,7 @@ function registerHttpActionsRoutes(app, options, deps = {}) {
|
|
|
188784
188829
|
scheduleIdleTimeout();
|
|
188785
188830
|
req.on("close", () => {
|
|
188786
188831
|
if (!responseClosed) {
|
|
188787
|
-
|
|
188832
|
+
log7.debug(`http actions request closed early ${requestId}`);
|
|
188788
188833
|
}
|
|
188789
188834
|
if (pending > 0) {
|
|
188790
188835
|
closeResponse();
|
|
@@ -188807,7 +188852,7 @@ function registerHttpActionsRoutes(app, options, deps = {}) {
|
|
|
188807
188852
|
}
|
|
188808
188853
|
});
|
|
188809
188854
|
});
|
|
188810
|
-
|
|
188855
|
+
log7.info(`http actions enabled at ${routePath}`);
|
|
188811
188856
|
}
|
|
188812
188857
|
|
|
188813
188858
|
// src/janitor.ts
|
|
@@ -188918,20 +188963,16 @@ class ProcessManager {
|
|
|
188918
188963
|
parentSecret1;
|
|
188919
188964
|
parentSecret2;
|
|
188920
188965
|
init;
|
|
188966
|
+
ensureChains = new Map;
|
|
188921
188967
|
constructor(parentId, parentSecret1, parentSecret2, init2) {
|
|
188922
188968
|
this.parentId = parentId;
|
|
188923
188969
|
this.parentSecret1 = parentSecret1;
|
|
188924
188970
|
this.parentSecret2 = parentSecret2;
|
|
188925
188971
|
this.init = init2;
|
|
188926
188972
|
}
|
|
188927
|
-
get(platform, actorId, sessionId, sessionIp) {
|
|
188973
|
+
async get(platform, actorId, sessionId, sessionIp) {
|
|
188928
188974
|
const platformDetails = this.init.platforms.get(platform);
|
|
188929
|
-
|
|
188930
|
-
if (platformDetails.config.persist) {
|
|
188931
|
-
pi = this.ensureProcess(platform, sessionId, actorId, sessionIp);
|
|
188932
|
-
} else {
|
|
188933
|
-
pi = this.ensureProcess(platform);
|
|
188934
|
-
}
|
|
188975
|
+
const pi = platformDetails.config.persist ? await this.ensureProcess(platform, sessionId, actorId, sessionIp) : await this.ensureProcess(platform);
|
|
188935
188976
|
pi.config = platformDetails.config;
|
|
188936
188977
|
pi.contextUrl = platformDetails.contextUrl;
|
|
188937
188978
|
return pi;
|
|
@@ -188957,6 +188998,22 @@ class ProcessManager {
|
|
|
188957
188998
|
}
|
|
188958
188999
|
ensureProcess(platform, sessionId, actor, sessionIp) {
|
|
188959
189000
|
const identifier = getPlatformId(platform, actor);
|
|
189001
|
+
const prior = this.ensureChains.get(identifier) ?? Promise.resolve();
|
|
189002
|
+
const run = prior.then(() => this.ensureProcessNow(identifier, platform, sessionId, actor, sessionIp));
|
|
189003
|
+
const settled = run.then(() => {
|
|
189004
|
+
return;
|
|
189005
|
+
}, () => {
|
|
189006
|
+
return;
|
|
189007
|
+
});
|
|
189008
|
+
this.ensureChains.set(identifier, settled);
|
|
189009
|
+
settled.then(() => {
|
|
189010
|
+
if (this.ensureChains.get(identifier) === settled) {
|
|
189011
|
+
this.ensureChains.delete(identifier);
|
|
189012
|
+
}
|
|
189013
|
+
});
|
|
189014
|
+
return run;
|
|
189015
|
+
}
|
|
189016
|
+
async ensureProcessNow(identifier, platform, sessionId, actor, sessionIp) {
|
|
188960
189017
|
const existing = platformInstances.get(identifier);
|
|
188961
189018
|
const reusable = existing && this.isProcessAlive(existing);
|
|
188962
189019
|
if (!reusable) {
|
|
@@ -188964,7 +189021,7 @@ class ProcessManager {
|
|
|
188964
189021
|
}
|
|
188965
189022
|
if (existing && !reusable) {
|
|
188966
189023
|
existing.markReplaced();
|
|
188967
|
-
existing.shutdown();
|
|
189024
|
+
await existing.shutdown();
|
|
188968
189025
|
}
|
|
188969
189026
|
const platformInstance = reusable ? existing : this.createPlatformInstance(identifier, platform, actor);
|
|
188970
189027
|
if (sessionId) {
|
|
@@ -189008,7 +189065,7 @@ var process_manager_default = ProcessManager;
|
|
|
189008
189065
|
// src/rate-limiter.ts
|
|
189009
189066
|
init_src();
|
|
189010
189067
|
init_src2();
|
|
189011
|
-
var
|
|
189068
|
+
var log8 = createLogger("server:rate-limiter");
|
|
189012
189069
|
var DEFAULT_CONFIG = {
|
|
189013
189070
|
windowMs: 1000,
|
|
189014
189071
|
maxRequests: 100,
|
|
@@ -189057,7 +189114,7 @@ function createRateLimiter(config2 = {}) {
|
|
|
189057
189114
|
}
|
|
189058
189115
|
if (state.blocked) {
|
|
189059
189116
|
if (now < state.blockedUntil) {
|
|
189060
|
-
|
|
189117
|
+
log8.debug(`dropping event for blocked socket ${socket.id}; blocked until ${new Date(state.blockedUntil).toISOString()}`);
|
|
189061
189118
|
const error = new Error("Rate limit exceeded");
|
|
189062
189119
|
next(error);
|
|
189063
189120
|
return;
|
|
@@ -189074,7 +189131,7 @@ function createRateLimiter(config2 = {}) {
|
|
|
189074
189131
|
if (state.count > cfg.maxRequests) {
|
|
189075
189132
|
state.blocked = true;
|
|
189076
189133
|
state.blockedUntil = now + cfg.blockDurationMs;
|
|
189077
|
-
|
|
189134
|
+
log8.warn(`rate limit exceeded for ${socket.id}: ${state.count} requests in ${cfg.windowMs}ms, blocking for ${cfg.blockDurationMs}ms`);
|
|
189078
189135
|
socket.emit("error", {
|
|
189079
189136
|
type: "Error",
|
|
189080
189137
|
"@context": buildCanonicalContext(ERROR_PLATFORM_CONTEXT_URL),
|
|
@@ -189096,7 +189153,7 @@ function cleanupClient(socketId) {
|
|
|
189096
189153
|
}
|
|
189097
189154
|
|
|
189098
189155
|
// src/sockethub.ts
|
|
189099
|
-
var
|
|
189156
|
+
var log9 = createLogger("server:core");
|
|
189100
189157
|
function normalizeIp2(ip) {
|
|
189101
189158
|
if (!ip) {
|
|
189102
189159
|
return "";
|
|
@@ -189183,16 +189240,16 @@ class Sockethub {
|
|
|
189183
189240
|
this.parentId = crypto.randId(16);
|
|
189184
189241
|
this.parentSecret1 = crypto.randToken(16);
|
|
189185
189242
|
this.parentSecret2 = crypto.randToken(16);
|
|
189186
|
-
|
|
189243
|
+
log9.debug(`session id: ${this.parentId}`);
|
|
189187
189244
|
}
|
|
189188
189245
|
async boot() {
|
|
189189
189246
|
if (this.status) {
|
|
189190
|
-
|
|
189247
|
+
log9.warn("Sockethub.boot() called more than once");
|
|
189191
189248
|
return;
|
|
189192
189249
|
}
|
|
189193
189250
|
this.status = true;
|
|
189194
189251
|
const init2 = await getInitObject().catch((err) => {
|
|
189195
|
-
|
|
189252
|
+
log9.error(err);
|
|
189196
189253
|
process.exit(1);
|
|
189197
189254
|
});
|
|
189198
189255
|
if (!init2) {
|
|
@@ -189204,9 +189261,9 @@ class Sockethub {
|
|
|
189204
189261
|
this.rateLimiter = createRateLimiter(config_default.get("rateLimiter"));
|
|
189205
189262
|
if (config_default.get("credentialCheck:reconnectIpSource") === "proxy") {
|
|
189206
189263
|
const proxyHeader = getProxyHeaderName();
|
|
189207
|
-
|
|
189264
|
+
log9.warn(`credentialCheck.reconnectIpSource=proxy enabled; only use this behind a trusted reverse proxy that overwrites '${proxyHeader}'`);
|
|
189208
189265
|
}
|
|
189209
|
-
|
|
189266
|
+
log9.debug("active platforms: ", [...init2.platforms.keys()]);
|
|
189210
189267
|
listener_default.start();
|
|
189211
189268
|
registerHttpActionsRoutes(listener_default.getApp(), {
|
|
189212
189269
|
processManager: this.processManager,
|
|
@@ -189214,7 +189271,7 @@ class Sockethub {
|
|
|
189214
189271
|
parentSecret1: this.parentSecret1
|
|
189215
189272
|
});
|
|
189216
189273
|
janitor_default.start();
|
|
189217
|
-
|
|
189274
|
+
log9.debug("registering handlers");
|
|
189218
189275
|
listener_default.io.on("connection", this.handleIncomingConnection.bind(this));
|
|
189219
189276
|
}
|
|
189220
189277
|
async shutdown() {
|
|
@@ -189222,9 +189279,9 @@ class Sockethub {
|
|
|
189222
189279
|
stopCleanup();
|
|
189223
189280
|
try {
|
|
189224
189281
|
const removed = await purgeCredentialsStores(this.parentId, config_default.get("redis"));
|
|
189225
|
-
|
|
189282
|
+
log9.debug(`purged ${removed} credential store keys on shutdown`);
|
|
189226
189283
|
} catch (err) {
|
|
189227
|
-
|
|
189284
|
+
log9.warn(`failed to purge credential store keys: ${err}`);
|
|
189228
189285
|
} finally {
|
|
189229
189286
|
await resetSharedCredentialsRedisConnection();
|
|
189230
189287
|
}
|
|
@@ -189323,9 +189380,9 @@ async function server() {
|
|
|
189323
189380
|
});
|
|
189324
189381
|
setLoggerContext("sockethub");
|
|
189325
189382
|
let sockethub;
|
|
189326
|
-
const
|
|
189383
|
+
const log12 = createLogger("server:init");
|
|
189327
189384
|
if (config_default.get("sentry:dsn")) {
|
|
189328
|
-
|
|
189385
|
+
log12.info("initializing sentry");
|
|
189329
189386
|
sentry = await Promise.resolve().then(() => (init_sentry(), exports_sentry));
|
|
189330
189387
|
}
|
|
189331
189388
|
try {
|
|
@@ -189379,4 +189436,4 @@ export {
|
|
|
189379
189436
|
server
|
|
189380
189437
|
};
|
|
189381
189438
|
|
|
189382
|
-
//# debugId=
|
|
189439
|
+
//# debugId=97DEBF2943991B6764756E2164756E21
|