@sockethub/server 5.0.0-alpha.4 → 5.0.0-alpha.6

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.
Files changed (105) hide show
  1. package/README.md +54 -60
  2. package/bin/sockethub +4 -3
  3. package/package.json +42 -54
  4. package/res/socket.io.js +4908 -0
  5. package/res/sockethub-client.js +602 -0
  6. package/res/sockethub-client.min.js +19 -0
  7. package/sockethub.config.example.json +2 -3
  8. package/src/bootstrap/init.d.ts +16 -13
  9. package/src/bootstrap/init.test.ts +211 -0
  10. package/src/bootstrap/init.ts +152 -76
  11. package/src/bootstrap/load-platforms.ts +151 -0
  12. package/src/config.test.ts +27 -22
  13. package/src/config.ts +82 -86
  14. package/src/defaults.json +24 -16
  15. package/src/index.ts +61 -22
  16. package/src/janitor.test.ts +191 -169
  17. package/src/janitor.ts +141 -118
  18. package/src/listener.ts +148 -58
  19. package/src/middleware/create-activity-object.test.ts +28 -8
  20. package/src/middleware/create-activity-object.ts +16 -10
  21. package/src/middleware/expand-activity-stream.test.data.ts +331 -345
  22. package/src/middleware/expand-activity-stream.test.ts +65 -66
  23. package/src/middleware/expand-activity-stream.ts +26 -21
  24. package/src/middleware/store-credentials.test.ts +74 -60
  25. package/src/middleware/store-credentials.ts +14 -8
  26. package/src/middleware/validate.test.data.ts +240 -242
  27. package/src/middleware/validate.test.ts +39 -78
  28. package/src/middleware/validate.ts +62 -36
  29. package/src/middleware.test.ts +168 -138
  30. package/src/middleware.ts +57 -55
  31. package/src/platform-instance.test.ts +508 -214
  32. package/src/platform-instance.ts +324 -231
  33. package/src/platform.test.ts +375 -0
  34. package/src/platform.ts +306 -117
  35. package/src/process-manager.ts +75 -51
  36. package/src/routes.test.ts +43 -89
  37. package/src/routes.ts +40 -78
  38. package/src/sentry.test.ts +106 -0
  39. package/src/sentry.ts +19 -0
  40. package/src/sockethub.ts +190 -129
  41. package/src/util.ts +5 -0
  42. package/coverage/tmp/coverage-39338-1663949520416-0.json +0 -1
  43. package/dist/bootstrap/init.d.ts +0 -18
  44. package/dist/bootstrap/init.js +0 -64
  45. package/dist/bootstrap/init.js.map +0 -1
  46. package/dist/bootstrap/platforms.js +0 -75
  47. package/dist/config.d.ts +0 -12
  48. package/dist/config.js +0 -107
  49. package/dist/config.js.map +0 -1
  50. package/dist/defaults.json +0 -28
  51. package/dist/index.d.ts +0 -1
  52. package/dist/index.js +0 -29
  53. package/dist/index.js.map +0 -1
  54. package/dist/janitor.d.ts +0 -30
  55. package/dist/janitor.js +0 -120
  56. package/dist/janitor.js.map +0 -1
  57. package/dist/listener.d.ts +0 -31
  58. package/dist/listener.js +0 -94
  59. package/dist/listener.js.map +0 -1
  60. package/dist/middleware/create-activity-object.d.ts +0 -8
  61. package/dist/middleware/create-activity-object.js +0 -19
  62. package/dist/middleware/create-activity-object.js.map +0 -1
  63. package/dist/middleware/expand-activity-stream.d.ts +0 -3
  64. package/dist/middleware/expand-activity-stream.js +0 -36
  65. package/dist/middleware/expand-activity-stream.js.map +0 -1
  66. package/dist/middleware/expand-activity-stream.test.data.d.ts +0 -480
  67. package/dist/middleware/expand-activity-stream.test.data.js +0 -360
  68. package/dist/middleware/expand-activity-stream.test.data.js.map +0 -1
  69. package/dist/middleware/store-credentials.d.ts +0 -3
  70. package/dist/middleware/store-credentials.js +0 -9
  71. package/dist/middleware/store-credentials.js.map +0 -1
  72. package/dist/middleware/validate.d.ts +0 -2
  73. package/dist/middleware/validate.js +0 -56
  74. package/dist/middleware/validate.js.map +0 -1
  75. package/dist/middleware/validate.test.data.d.ts +0 -532
  76. package/dist/middleware/validate.test.data.js +0 -263
  77. package/dist/middleware/validate.test.data.js.map +0 -1
  78. package/dist/middleware.d.ts +0 -21
  79. package/dist/middleware.js +0 -56
  80. package/dist/middleware.js.map +0 -1
  81. package/dist/platform-instance.d.ts +0 -78
  82. package/dist/platform-instance.js +0 -226
  83. package/dist/platform-instance.js.map +0 -1
  84. package/dist/platform.d.ts +0 -6
  85. package/dist/platform.js +0 -176
  86. package/dist/platform.js.map +0 -1
  87. package/dist/process-manager.d.ts +0 -11
  88. package/dist/process-manager.js +0 -82
  89. package/dist/process-manager.js.map +0 -1
  90. package/dist/routes.d.ts +0 -13
  91. package/dist/routes.js +0 -83
  92. package/dist/routes.js.map +0 -1
  93. package/dist/sockethub.d.ts +0 -18
  94. package/dist/sockethub.js +0 -112
  95. package/dist/sockethub.js.map +0 -1
  96. package/src/bootstrap/platforms.js +0 -75
  97. package/test/init-suite.js +0 -41
  98. package/test/sockethub-suite.js +0 -25
  99. package/tsconfig.json +0 -18
  100. package/views/examples/dummy.ejs +0 -95
  101. package/views/examples/feeds.ejs +0 -90
  102. package/views/examples/irc.ejs +0 -239
  103. package/views/examples/shared.js +0 -72
  104. package/views/examples/xmpp.ejs +0 -217
  105. package/views/index.ejs +0 -17
@@ -1,100 +1,54 @@
1
- import { expect } from 'chai';
2
- import * as sinon from 'sinon';
1
+ import { afterEach, describe, expect, it } from "bun:test";
3
2
  import { existsSync } from "fs";
3
+ import * as sinon from "sinon";
4
4
 
5
- import routes, { basePaths, examplePaths, examplePages, IRoutePaths } from "./routes";
5
+ import routes, { basePaths, type IRoutePaths } from "./routes.js";
6
6
 
7
- describe('routes/base', () => {
8
-
9
- afterEach(() => {
10
- sinon.restore();
11
- });
12
-
13
- it('can find each of the base files it serves', () => {
14
- Object.values(basePaths).forEach((fwd: string) => {
15
- try {
16
- expect(existsSync(fwd)).to.be.true;
17
- } catch (e) {
18
- throw new Error(`Unable to resolve path ${fwd}`);
19
- }
7
+ describe("routes/base", () => {
8
+ afterEach(() => {
9
+ sinon.restore();
20
10
  });
21
- });
22
11
 
23
- it('can find each of the example files it serves', () => {
24
- Object.values(examplePaths).forEach((fwd: string) => {
25
- try {
26
- expect(existsSync(fwd)).to.be.true;
27
- } catch (e) {
28
- throw new Error(`Unable to resolve path ${fwd}`);
29
- }
12
+ it("can find each of the base files it serves", () => {
13
+ Object.values(basePaths).forEach((fwd: string) => {
14
+ try {
15
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
16
+ expect(existsSync(fwd)).toBeTrue();
17
+ } catch (e) {
18
+ throw new Error(`Unable to resolve path ${fwd}`);
19
+ }
20
+ });
30
21
  });
31
- });
32
22
 
33
- it('can find each of the example page files it serves', () => {
34
- Object.values(examplePages).forEach((fwd: string) => {
35
- try {
36
- expect(existsSync(fwd)).to.be.true;
37
- } catch (e) {
38
- throw new Error(`Unable to resolve path ${fwd}`);
39
- }
23
+ it("adds base routes", () => {
24
+ const app = {
25
+ get: sinon.spy(),
26
+ };
27
+ routes.setup(app);
28
+ sinon.assert.callCount(app.get, Object.keys(basePaths).length);
40
29
  });
41
- });
42
-
43
- it('adds base routes', () => {
44
- const app = {
45
- get: sinon.spy()
46
- };
47
- routes.setup(app, false);
48
- sinon.assert.callCount(
49
- app.get,
50
- Object.keys(basePaths).length
51
- );
52
- });
53
30
 
54
- it('adds base and example routes', () => {
55
- const app = {
56
- get: sinon.spy()
57
- };
58
- routes.setup(app, true);
59
- sinon.assert.callCount(
60
- app.get,
61
- Object.keys(basePaths).length
62
- + Object.keys(examplePaths).length
63
- + Object.keys(examplePages).length
64
- );
65
- });
66
-
67
- it('handles calls to base routes as expected', () => {
68
- let routeHandlers: any = {};
69
- let app = {
70
- get: (path: string | number, route: any) => {
71
- routeHandlers[path] = route;
72
- }
73
- };
74
- routes.setup(app, true);
75
-
76
- function verifyPathRoutes(pathMap: IRoutePaths) {
77
- Object.keys(pathMap).forEach((path) => {
78
- const res = {
79
- setHeader: sinon.spy(),
80
- sendFile: sinon.spy()
31
+ it("handles calls to base routes as expected", () => {
32
+ const routeHandlers: any = {};
33
+ const app = {
34
+ get: (path: string | number, route: any) => {
35
+ routeHandlers[path] = route;
36
+ },
81
37
  };
82
- expect(pathMap[path].endsWith('.ejs')).to.be.false;
83
- routeHandlers[path]({url: path}, res);
84
- sinon.assert.called(res.setHeader);
85
- sinon.assert.calledWith(res.sendFile, pathMap[path]);
86
- });
87
- }
88
- verifyPathRoutes(basePaths);
89
- verifyPathRoutes(examplePaths);
90
-
91
- Object.keys(examplePages).forEach((path) => {
92
- const res = {
93
- render: sinon.spy()
94
- };
95
- expect(examplePages[path].endsWith('.ejs')).to.be.true;
96
- routeHandlers[path]({url: path}, res);
97
- sinon.assert.called(res.render);
38
+ routes.setup(app);
39
+
40
+ function verifyPathRoutes(pathMap: IRoutePaths) {
41
+ Object.keys(pathMap).forEach((path) => {
42
+ const res = {
43
+ setHeader: sinon.spy(),
44
+ sendFile: sinon.spy(),
45
+ };
46
+ expect(pathMap[path].endsWith(".ejs")).toBeFalse();
47
+ routeHandlers[path]({ url: path }, res);
48
+ sinon.assert.called(res.setHeader);
49
+ sinon.assert.calledWith(res.sendFile, pathMap[path]);
50
+ });
51
+ }
52
+ verifyPathRoutes(basePaths);
98
53
  });
99
- });
100
- });
54
+ });
package/src/routes.ts CHANGED
@@ -1,99 +1,61 @@
1
- import path from 'path';
2
- import config from "./config";
3
- import debug from 'debug';
1
+ import path from "node:path";
2
+ import debug from "debug";
4
3
 
5
- const debug_scope = process.env.DEBUG || '',
6
- logger = debug('sockethub:server:routes'),
7
- address = config.get('public:protocol') + '://' +
8
- config.get('public:host') + ':' +
9
- config.get('public:port') +
10
- config.get('public:path');
4
+ import { __dirname } from "./util.js";
5
+
6
+ const logger = debug("sockethub:server:routes");
11
7
 
12
8
  export interface IRoutePaths {
13
- [key: string]: string;
9
+ [key: string]: string;
14
10
  }
15
11
 
16
12
  export const basePaths: IRoutePaths = {
17
- '/sockethub-client.js':
18
- path.resolve(`${__dirname}/../node_modules/@sockethub/client/dist/sockethub-client.js`),
19
- '/sockethub-client.min.js':
20
- path.resolve(`${__dirname}/../node_modules/@sockethub/client/dist/sockethub-client.min.js`),
21
- '/sockethub-client.js.map':
22
- path.resolve(`${__dirname}/../node_modules/@sockethub/client/dist/sockethub-client.js.map`),
23
- '/socket.io.js': path.resolve(`${__dirname}/../node_modules/socket.io/client-dist/socket.io.js`)
24
- };
25
-
26
- export const examplePaths: IRoutePaths = {
27
- '/jquery.js': path.resolve(`${__dirname}/../node_modules/jquery/dist/jquery.min.js`),
28
- '/jquery.min.map': path.resolve(`${__dirname}/../node_modules/jquery/dist/jquery.min.map`),
29
- '/examples/shared.js': path.resolve(`${__dirname}/../views/examples/shared.js`)
13
+ "/sockethub-client.js": path.resolve(
14
+ __dirname,
15
+ "..",
16
+ "res",
17
+ "sockethub-client.js",
18
+ ),
19
+ "/sockethub-client.min.js": path.resolve(
20
+ __dirname,
21
+ "..",
22
+ "res",
23
+ "sockethub-client.min.js",
24
+ ),
25
+ "/socket.io.js": path.resolve(__dirname, "..", "res", "socket.io.js"),
30
26
  };
31
27
 
32
- export const examplePages: IRoutePaths = {
33
- '/': path.resolve(`${__dirname}/../views/index.ejs`),
34
- '/examples/dummy': path.resolve(`${__dirname}/../views/examples/dummy.ejs`),
35
- '/examples/feeds': path.resolve(`${__dirname}/../views/examples/feeds.ejs`),
36
- '/examples/irc': path.resolve(`${__dirname}/../views/examples/irc.ejs`),
37
- '/examples/xmpp': path.resolve(`${__dirname}/../views/examples/xmpp.ejs`)
38
- };
39
-
40
-
41
28
  function prepFileRoutes(pathMap) {
42
- const _routes = [];
43
- Object.keys(pathMap).forEach((key) => {
44
- _routes.push({
45
- meta: {
46
- method: 'GET',
47
- path: key
48
- },
49
- route: (req, res) => {
50
- logger(`serving resource ${req.url}`);
51
- res.setHeader('Access-Control-Allow-Origin', '*');
52
- res.sendFile(pathMap[req.url]);
53
- }
54
- });
55
- });
56
- return _routes;
29
+ const _routes = [];
30
+ for (const key of Object.keys(pathMap)) {
31
+ _routes.push({
32
+ meta: {
33
+ method: "GET",
34
+ path: key,
35
+ },
36
+ route: (req, res) => {
37
+ logger(`serving resource ${req.url}`);
38
+ res.setHeader("Access-Control-Allow-Origin", "*");
39
+ res.sendFile(pathMap[req.url]);
40
+ },
41
+ });
42
+ }
43
+ return _routes;
57
44
  }
58
45
  const baseRoutes = prepFileRoutes(basePaths);
59
- const exampleRoutes = prepFileRoutes(examplePaths);
60
-
61
-
62
- Object.keys(examplePages).forEach((key) => {
63
- exampleRoutes.push({
64
- meta: {
65
- method: 'GET',
66
- path: key
67
- },
68
- route: (req, res) => {
69
- logger(`serving page ${req.url}`);
70
- res.render(examplePages[req.url], {
71
- debug_scope: debug_scope,
72
- address: address,
73
- });
74
- }
75
- });
76
- });
77
46
 
78
47
  function addRoute(app) {
79
- return (route) => {
80
- app[route.meta.method.toLowerCase()](
81
- route.meta.path,
82
- route.route
83
- );
84
- };
48
+ return (route) => {
49
+ app[route.meta.method.toLowerCase()](route.meta.path, route.route);
50
+ };
85
51
  }
86
52
 
87
53
  /**
88
54
  * Setup
89
55
  */
90
56
  const routes = {
91
- setup: function (app: unknown,
92
- examplesEnabled: boolean = config.get('examples:enabled') as boolean) {
93
- baseRoutes.forEach(addRoute(app));
94
- if (examplesEnabled) {
95
- exampleRoutes.forEach(addRoute(app));
96
- }
97
- }
57
+ setup: (app: unknown) => {
58
+ baseRoutes.forEach(addRoute(app));
59
+ },
98
60
  };
99
61
  export default routes;
@@ -0,0 +1,106 @@
1
+ import { beforeEach, describe, expect, it, mock } from "bun:test";
2
+ import { join } from "path";
3
+
4
+ // Mock config to avoid loading real configuration
5
+ const mockConfig = {
6
+ get: mock((key: string) => {
7
+ if (key === "sentry:dsn") {
8
+ return "https://ffc702eb2f3b24d9e06ca20e1ef1fd09@o4508859714895872.ingest.de.sentry.io/4508859718369360";
9
+ }
10
+ if (key === "sentry") {
11
+ return {
12
+ dsn: "https://ffc702eb2f3b24d9e06ca20e1ef1fd09@o4508859714895872.ingest.de.sentry.io/4508859718369360",
13
+ environment: "test",
14
+ traceSampleRate: 1.0
15
+ };
16
+ }
17
+ return null;
18
+ })
19
+ };
20
+
21
+ describe("Sentry Integration Bug - Issue #918", () => {
22
+ beforeEach(() => {
23
+ // Clear any existing Sentry instances
24
+ delete require.cache[require.resolve("./sentry.js")];
25
+ mockConfig.get.mockClear();
26
+ });
27
+
28
+ it("should reproduce 'A Proxy's target should be an Object' error", async () => {
29
+ // This test reproduces the bug by initializing Sentry with Bun server instrumentation
30
+ // The error occurs when Sentry's Bun integration tries to instrument server options
31
+ let sentryError: Error | null = null;
32
+
33
+ try {
34
+ // Create a proper mock that implements the config interface
35
+ const configPath = require.resolve("./config.js");
36
+
37
+ // Clear the config from cache first
38
+ delete require.cache[configPath];
39
+
40
+ // Mock the config module before importing sentry
41
+ require.cache[configPath] = {
42
+ exports: {
43
+ default: mockConfig,
44
+ __esModule: true
45
+ },
46
+ loaded: true,
47
+ children: [],
48
+ parent: null,
49
+ filename: configPath,
50
+ id: configPath,
51
+ paths: [],
52
+ };
53
+
54
+ // Import Sentry module which triggers initialization
55
+ const sentryPath = require.resolve("./sentry.js");
56
+ delete require.cache[sentryPath]; // Clear sentry from cache
57
+ await import("./sentry.js");
58
+ } catch (error) {
59
+ sentryError = error as Error;
60
+ }
61
+
62
+ // With the upgrade to @sentry/bun 10.15.0, this should now work without the Proxy error
63
+ // If we're still on the old version, we'd expect the Proxy error
64
+ // If we're on the new version, Sentry should initialize successfully
65
+ if (sentryError) {
66
+ // If there's still an error, it should NOT be the Proxy error (since we upgraded)
67
+ expect(sentryError.message).not.toContain("A Proxy's 'target' should be an Object");
68
+ } else {
69
+ // Success - the upgrade fixed the issue
70
+ expect(sentryError).toBeNull();
71
+ }
72
+ });
73
+
74
+ it("should verify the Sentry version has been upgraded to fix the bug", () => {
75
+ // This test documents that the problematic version has been fixed
76
+ const packageJson = require("../package.json");
77
+ const currentVersion = packageJson.dependencies["@sentry/bun"];
78
+
79
+ // Should now be version 10.x or higher (which fixes the Proxy bug)
80
+ expect(currentVersion).toMatch(/^(\^?10\.|^10\.|latest)/);
81
+
82
+ // Document the bug details for reference
83
+ const bugInfo = {
84
+ brokenVersion: "9.5.0",
85
+ fixedVersion: "10.15.0",
86
+ bugDescription: "A Proxy's 'target' should be an Object",
87
+ location: "instrumentBunServeOptions in @sentry/bun"
88
+ };
89
+
90
+ expect(bugInfo.brokenVersion).toBe("9.5.0");
91
+ });
92
+ });
93
+
94
+ describe("Sentry Integration Workaround", () => {
95
+ it("should suggest disabling Sentry DSN as temporary workaround", () => {
96
+ // Document the workaround: set sentry.dsn to empty string or remove it
97
+ const workaroundConfig = {
98
+ sentry: {
99
+ dsn: "", // Empty DSN disables Sentry
100
+ environment: "production"
101
+ }
102
+ };
103
+
104
+ expect(workaroundConfig.sentry.dsn).toBe("");
105
+ });
106
+ });
package/src/sentry.ts ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * This file is only imported if sentry reporting is enabled in the Sockethub config.
3
+ */
4
+
5
+ import * as Sentry from "@sentry/bun";
6
+ import debug from "debug";
7
+ import config from "./config";
8
+
9
+ const logger = debug("sockethub:sentry");
10
+ if (!config.get("sentry:dsn")) {
11
+ throw new Error("Sentry attempted initialization with no DSN provided");
12
+ }
13
+ logger("initialized");
14
+ Sentry.init(config.get("sentry"));
15
+
16
+ export function reportError(err: Error): void {
17
+ logger("reporting error");
18
+ Sentry.captureException(err);
19
+ }