@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 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;
@@ -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. " + "'*' allows any website to connect visitors' " + "browsers to this instance; public deployments " + "should set an explicit origin or comma-separated " + "list of origins.",
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.14",
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.14",
70351
- "@sockethub/data-layer": "^1.0.0-alpha.14",
70352
- "@sockethub/logger": "^1.0.0-alpha.14",
70353
- "@sockethub/schemas": "^3.0.0-alpha.14",
70354
- "@sockethub/util": "^1.0.0-alpha.2",
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.14",
70386
- "@sockethub/platform-dummy": "^3.0.0-alpha.14",
70387
- "@sockethub/platform-feeds": "^4.0.0-alpha.14",
70388
- "@sockethub/platform-irc": "^4.0.0-alpha.14",
70389
- "@sockethub/platform-metadata": "^1.0.1-alpha.9",
70390
- "@sockethub/platform-xmpp": "^5.0.0-alpha.14"
70391
- },
70392
- gitHead: "4bc8ffa00d29aa78e59e269ac6e5ea9859ec01a8",
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 = log5;
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 log5(...args) {
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 = log5;
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 log5(...args) {
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 log9(...args) {
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: log9,
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(log10) {
139709
+ function estimateLogSizeInBytes(log11) {
139708
139710
  let weight = 0;
139709
- if (log10.message) {
139710
- weight += log10.message.length * 2;
139711
+ if (log11.message) {
139712
+ weight += log11.message.length * 2;
139711
139713
  }
139712
- return weight + estimateAttributesSizeInBytes(log10.attributes);
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 log10 = originalConsoleMethods[level];
140958
- log10?.apply(GLOBAL_OBJ.console, args);
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 log10(...args) {
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
- log10("Worker error", err);
148639
+ log11("Worker error", err);
148638
148640
  });
148639
148641
  worker.once("exit", (code) => {
148640
- log10("Worker exit", code);
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", (log11) => {
150329
- log11.attributes = {
150330
- ...log11.attributes,
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 log5 = createLogger("server:listener");
187524
- log5.info(`sockethub v${packageJson.version}`);
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
- log5.debug(`examples resolved from @sockethub/examples: ${examplesDir}`);
187611
+ log6.debug(`examples resolved from @sockethub/examples: ${examplesDir}`);
187553
187612
  return examplesDir;
187554
187613
  }
187555
- log5.debug(`@sockethub/examples found but build directory missing: ${examplesDir}`);
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
- log5.debug(`examples request ${req.path}`);
187654
+ log6.debug(`examples request ${req.path}`);
187596
187655
  res.sendFile(examplesIndex);
187597
187656
  });
187598
- log5.info(`examples served at http://${config_default.get("sockethub:host")}:${config_default.get("sockethub:port")}`);
187657
+ log6.info(`examples served at http://${config_default.get("sockethub:host")}:${config_default.get("sockethub:port")}`);
187599
187658
  }
187600
187659
  static corsOrigin() {
187601
- const configured = (config_default.get("sockethub:cors:origin") || "*").trim();
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
- log5.info(`sockethub listening on ws://${config_default.get("sockethub:host")}:${config_default.get("sockethub:port")}`);
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
- async shutdown() {
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 log6 = createLogger("server:http:actions");
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(getConfig("sockethub:cors:origin"), req.headers.origin);
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
- log6.error(`idempotency lookup error for ${requestId}: ${String(err)}`);
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
- log6.error(`idempotency store error for ${requestId}: ${String(err)}`);
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
- log6.error(`credentials store teardown failed for ${sessionId}: ${String(err)}`);
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
- log6.error(`failed to finalize idempotency for ${requestId}: ${String(err)}`);
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
- log6.error(`failed to persist idempotency result for ${requestId}: ${String(err)}`);
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
- log6.debug(`http actions request closed early ${requestId}`);
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
- log6.info(`http actions enabled at ${routePath}`);
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
- let pi;
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 log7 = createLogger("server:rate-limiter");
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
- log7.debug(`dropping event for blocked socket ${socket.id}; blocked until ${new Date(state.blockedUntil).toISOString()}`);
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
- log7.warn(`rate limit exceeded for ${socket.id}: ${state.count} requests in ${cfg.windowMs}ms, blocking for ${cfg.blockDurationMs}ms`);
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 log8 = createLogger("server:core");
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
- log8.debug(`session id: ${this.parentId}`);
189243
+ log9.debug(`session id: ${this.parentId}`);
189187
189244
  }
189188
189245
  async boot() {
189189
189246
  if (this.status) {
189190
- log8.warn("Sockethub.boot() called more than once");
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
- log8.error(err);
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
- log8.warn(`credentialCheck.reconnectIpSource=proxy enabled; only use this behind a trusted reverse proxy that overwrites '${proxyHeader}'`);
189264
+ log9.warn(`credentialCheck.reconnectIpSource=proxy enabled; only use this behind a trusted reverse proxy that overwrites '${proxyHeader}'`);
189208
189265
  }
189209
- log8.debug("active platforms: ", [...init2.platforms.keys()]);
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
- log8.debug("registering handlers");
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
- log8.debug(`purged ${removed} credential store keys on shutdown`);
189282
+ log9.debug(`purged ${removed} credential store keys on shutdown`);
189226
189283
  } catch (err) {
189227
- log8.warn(`failed to purge credential store keys: ${err}`);
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 log11 = createLogger("server:init");
189383
+ const log12 = createLogger("server:init");
189327
189384
  if (config_default.get("sentry:dsn")) {
189328
- log11.info("initializing sentry");
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=8E3E410F19F7010D64756E2164756E21
189439
+ //# debugId=97DEBF2943991B6764756E2164756E21