@sockethub/server 5.0.0-alpha.3

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 (118) hide show
  1. package/LICENSE +165 -0
  2. package/README.md +136 -0
  3. package/bin/sockethub +3 -0
  4. package/coverage/tmp/coverage-93126-1649152190997-0.json +1 -0
  5. package/dist/bootstrap/init.d.ts +18 -0
  6. package/dist/bootstrap/init.js +63 -0
  7. package/dist/bootstrap/init.js.map +1 -0
  8. package/dist/bootstrap/platforms.js +75 -0
  9. package/dist/common.d.ts +3 -0
  10. package/dist/common.js +20 -0
  11. package/dist/common.js.map +1 -0
  12. package/dist/config.d.ts +6 -0
  13. package/dist/config.js +102 -0
  14. package/dist/config.js.map +1 -0
  15. package/dist/crypto.d.ts +10 -0
  16. package/dist/crypto.js +38 -0
  17. package/dist/crypto.js.map +1 -0
  18. package/dist/defaults.json +28 -0
  19. package/dist/index.d.ts +2 -0
  20. package/dist/index.js +25 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/janitor.d.ts +15 -0
  23. package/dist/janitor.js +89 -0
  24. package/dist/janitor.js.map +1 -0
  25. package/dist/listener.d.ts +28 -0
  26. package/dist/listener.js +91 -0
  27. package/dist/listener.js.map +1 -0
  28. package/dist/middleware/create-activity-object.d.ts +6 -0
  29. package/dist/middleware/create-activity-object.js +19 -0
  30. package/dist/middleware/create-activity-object.js.map +1 -0
  31. package/dist/middleware/expand-activity-stream.d.ts +2 -0
  32. package/dist/middleware/expand-activity-stream.js +33 -0
  33. package/dist/middleware/expand-activity-stream.js.map +1 -0
  34. package/dist/middleware/expand-activity-stream.test.data.d.ts +480 -0
  35. package/dist/middleware/expand-activity-stream.test.data.js +360 -0
  36. package/dist/middleware/expand-activity-stream.test.data.js.map +1 -0
  37. package/dist/middleware/store-credentials.d.ts +3 -0
  38. package/dist/middleware/store-credentials.js +19 -0
  39. package/dist/middleware/store-credentials.js.map +1 -0
  40. package/dist/middleware/validate.d.ts +2 -0
  41. package/dist/middleware/validate.js +58 -0
  42. package/dist/middleware/validate.js.map +1 -0
  43. package/dist/middleware/validate.test.data.d.ts +532 -0
  44. package/dist/middleware/validate.test.data.js +263 -0
  45. package/dist/middleware/validate.test.data.js.map +1 -0
  46. package/dist/middleware.d.ts +10 -0
  47. package/dist/middleware.js +54 -0
  48. package/dist/middleware.js.map +1 -0
  49. package/dist/platform-instance.d.ts +77 -0
  50. package/dist/platform-instance.js +211 -0
  51. package/dist/platform-instance.js.map +1 -0
  52. package/dist/platform.d.ts +6 -0
  53. package/dist/platform.js +187 -0
  54. package/dist/platform.js.map +1 -0
  55. package/dist/process-manager.d.ts +11 -0
  56. package/dist/process-manager.js +78 -0
  57. package/dist/process-manager.js.map +1 -0
  58. package/dist/routes.d.ts +13 -0
  59. package/dist/routes.js +83 -0
  60. package/dist/routes.js.map +1 -0
  61. package/dist/sockethub.d.ts +39 -0
  62. package/dist/sockethub.js +119 -0
  63. package/dist/sockethub.js.map +1 -0
  64. package/dist/store.d.ts +5 -0
  65. package/dist/store.js +17 -0
  66. package/dist/store.js.map +1 -0
  67. package/package.json +103 -0
  68. package/sockethub.config.example.json +33 -0
  69. package/src/bootstrap/init.d.ts +8 -0
  70. package/src/bootstrap/init.ts +83 -0
  71. package/src/bootstrap/platforms.js +75 -0
  72. package/src/common.test.ts +54 -0
  73. package/src/common.ts +14 -0
  74. package/src/config.d.ts +2 -0
  75. package/src/config.test.ts +28 -0
  76. package/src/config.ts +94 -0
  77. package/src/crypto.d.ts +5 -0
  78. package/src/crypto.test.ts +41 -0
  79. package/src/crypto.ts +41 -0
  80. package/src/defaults.json +28 -0
  81. package/src/index.ts +28 -0
  82. package/src/janitor.d.ts +8 -0
  83. package/src/janitor.ts +89 -0
  84. package/src/listener.ts +79 -0
  85. package/src/middleware/create-activity-object.test.ts +10 -0
  86. package/src/middleware/create-activity-object.ts +13 -0
  87. package/src/middleware/expand-activity-stream.test.data.ts +365 -0
  88. package/src/middleware/expand-activity-stream.test.ts +78 -0
  89. package/src/middleware/expand-activity-stream.ts +27 -0
  90. package/src/middleware/store-credentials.test.ts +73 -0
  91. package/src/middleware/store-credentials.ts +16 -0
  92. package/src/middleware/validate.d.ts +1 -0
  93. package/src/middleware/validate.test.data.ts +261 -0
  94. package/src/middleware/validate.test.ts +83 -0
  95. package/src/middleware/validate.ts +49 -0
  96. package/src/middleware.d.ts +21 -0
  97. package/src/middleware.test.ts +154 -0
  98. package/src/middleware.ts +52 -0
  99. package/src/platform-instance.test.ts +237 -0
  100. package/src/platform-instance.ts +242 -0
  101. package/src/platform.ts +191 -0
  102. package/src/process-manager.ts +64 -0
  103. package/src/routes.test.ts +100 -0
  104. package/src/routes.ts +98 -0
  105. package/src/sockethub.d.ts +1 -0
  106. package/src/sockethub.ts +165 -0
  107. package/src/store.test.ts +28 -0
  108. package/src/store.ts +17 -0
  109. package/test/init-suite.js +41 -0
  110. package/test/queue.functional.test.js +0 -0
  111. package/test/sockethub-suite.js +25 -0
  112. package/tsconfig.json +18 -0
  113. package/views/examples/dummy.ejs +93 -0
  114. package/views/examples/feeds.ejs +90 -0
  115. package/views/examples/irc.ejs +239 -0
  116. package/views/examples/shared.js +72 -0
  117. package/views/examples/xmpp.ejs +191 -0
  118. package/views/index.ejs +17 -0
package/src/janitor.ts ADDED
@@ -0,0 +1,89 @@
1
+ import debug from 'debug';
2
+
3
+ import PlatformInstance, { platformInstances } from './platform-instance';
4
+ import listener, { SocketInstance } from "./listener";
5
+
6
+ const rmLog = debug('sockethub:server:janitor');
7
+
8
+ const TICK = 15000;
9
+ let alreadyCalled: boolean = false;
10
+ let cycleCount: number = 0; // a counter for each setInterval call
11
+ let reportCount: number = 0; // number of times a report is printed
12
+
13
+ /**
14
+ * Every TICK the Janitor will compare existing platform instances with socket.ids (aka. sessionId)
15
+ * If all of the sessionIds associated with a platformInstance have no corresponding socket.id
16
+ * (from the http.io socket.io instance), then the platformInstance will first be flagged, if after
17
+ * the next TICK the same state is determined, the platform will be destroyed (this allows for page
18
+ * refreshes not destroying platform instances)
19
+ */
20
+ function janitorCycle() {
21
+ if (! alreadyCalled) { alreadyCalled = true; }
22
+ else { return; }
23
+ rmLog('initializing resource manager');
24
+ setInterval(async () => {
25
+ cycleCount++;
26
+ const sockets: Array<SocketInstance> = await listener.io.fetchSockets();
27
+
28
+ if (! (cycleCount % 4)) {
29
+ reportCount++;
30
+ rmLog(`socket sessions: ${sockets.length} platform instances: ${platformInstances.size}`);
31
+ }
32
+
33
+ for (let platformInstance of platformInstances.values()) {
34
+ removeStaleSocketSessions(platformInstance, sockets);
35
+ // Static platforms are for global use, not tied to a unique to session / eg. credentials)
36
+ if ((! platformInstance.global) && (platformInstance.sessions.size === 0)) {
37
+ removeStalePlatformInstance(platformInstance);
38
+ } else {
39
+ platformInstance.flaggedForTermination = false;
40
+ }
41
+ }
42
+ }, TICK);
43
+ }
44
+
45
+ function socketExists(sessionId: string, sockets: Array<SocketInstance>) {
46
+ for (let socket of sockets) {
47
+ if (socket.id === sessionId) {
48
+ return true;
49
+ }
50
+ }
51
+ return false;
52
+ }
53
+
54
+ function removeSessionCallbacks(platformInstance: PlatformInstance, sessionId: string) {
55
+ for (const key in platformInstance.sessionCallbacks) {
56
+ platformInstance.sessionCallbacks[key].delete(sessionId);
57
+ }
58
+ }
59
+
60
+ function removeStaleSocketSessions(platformInstance: PlatformInstance,
61
+ sockets: Array<SocketInstance>) {
62
+ for (const sessionId of platformInstance.sessions.values()) {
63
+ if (! socketExists(sessionId, sockets)) {
64
+ rmLog('removing stale socket session reference ' + sessionId + ' in platform instance '
65
+ + platformInstance.id);
66
+ platformInstance.sessions.delete(sessionId);
67
+ removeSessionCallbacks(platformInstance, sessionId);
68
+ }
69
+ }
70
+ }
71
+
72
+ function removeStalePlatformInstance(platformInstance: PlatformInstance) {
73
+ if (platformInstance.flaggedForTermination) {
74
+ rmLog(`terminating platform instance ${platformInstance.id}`);
75
+ platformInstance.destroy(); // terminate
76
+ } else {
77
+ rmLog(`flagging for termination platform instance ${platformInstance.id} ` +
78
+ `(no registered sessions found)`);
79
+ platformInstance.flaggedForTermination = true;
80
+ }
81
+ }
82
+
83
+ const janitor = {
84
+ clean: janitorCycle,
85
+ alreadyCalled: alreadyCalled,
86
+ cycleCount: cycleCount,
87
+ reportCount: reportCount
88
+ };
89
+ export default janitor;
@@ -0,0 +1,79 @@
1
+ import debug from 'debug';
2
+ import bodyParser from 'body-parser';
3
+ import express from 'express';
4
+ import * as HTTP from 'http';
5
+ import { Server } from 'socket.io';
6
+
7
+ import config from './config';
8
+ import routes from './routes';
9
+
10
+ const log = debug('sockethub:server:listener');
11
+
12
+ /**
13
+ * Handles the initialization and access of Sockethub resources.
14
+ *
15
+ * - HTTP Server
16
+ * - Express (serves resources and example routes)
17
+ * - Socket.io (bidirectional websocket communication)
18
+ */
19
+ class Listener {
20
+ io: Server;
21
+ http: HTTP.Server;
22
+
23
+ /**
24
+ * Starts the services needed for Sockethub to operate. After this command completes,
25
+ * the `http` and `io` class properties will be set.
26
+ */
27
+ start() {
28
+ // initialize express and socket.io objects
29
+ const app = Listener.initExpress();
30
+ this.http = new HTTP.Server(app);
31
+ this.io = new Server(this.http, {
32
+ path: config.get('sockethub:path'),
33
+ cors: {
34
+ origin: "*",
35
+ methods: [ "GET", "POST" ]
36
+ }
37
+ });
38
+ routes.setup(app);
39
+ this.startHttp();
40
+ }
41
+
42
+ private startHttp() {
43
+ this.http.listen(config.get('sockethub:port'), config.get('sockethub:host'), () => {
44
+ log(`sockethub listening on ` +
45
+ `http://${config.get('sockethub:host')}:${config.get('sockethub:port')}`);
46
+ });
47
+ };
48
+
49
+ private static initExpress() {
50
+ let app = express();
51
+ // templating engines
52
+ app.set('view engine', 'ejs');
53
+ // use bodyParser
54
+ app.use(bodyParser.urlencoded({extended: true}));
55
+ app.use(bodyParser.json());
56
+ return app;
57
+ }
58
+ }
59
+
60
+ const listener = new Listener();
61
+
62
+ export interface SocketInstance {
63
+ id: string;
64
+ emit: Function;
65
+ }
66
+
67
+ export async function getSocket(sessionId: string): Promise<SocketInstance> {
68
+ const sockets: Array<SocketInstance> = await listener.io.fetchSockets();
69
+ return new Promise((resolve, reject) => {
70
+ for (let socket of sockets) {
71
+ if (sessionId === socket.id) {
72
+ return resolve(socket);
73
+ }
74
+ }
75
+ return reject(`unable to find socket for sessionId ${sessionId}`);
76
+ });
77
+ }
78
+
79
+ export default listener;
@@ -0,0 +1,10 @@
1
+ import createActivityObject from "./create-activity-object";
2
+
3
+ describe('Middleware: createActivityObject', () => {
4
+ it('Calls activity.Object.create with incoming data', (done) => {
5
+ // @ts-ignore
6
+ createActivityObject({foo: 'bar'}, (msg) => {
7
+ done();
8
+ });
9
+ });
10
+ });
@@ -0,0 +1,13 @@
1
+ import ActivityStreams from '@sockethub/activity-streams';
2
+ import config from "../config";
3
+ const activity = ActivityStreams(config.get('activity-streams:opts'));
4
+
5
+ /**
6
+ * A simple middleware wrapper for the activity-streams Object.create method.
7
+ * @param obj
8
+ * @param done
9
+ */
10
+ export default function createActivityObject(obj: any, done: Function) {
11
+ activity.Object.create(obj);
12
+ done(obj);
13
+ }
@@ -0,0 +1,365 @@
1
+ export default [
2
+ {
3
+ "name": "not an object",
4
+ "valid": false,
5
+ "type": "message",
6
+ "input": "hello world",
7
+ "error": "Error: message received is not an object."
8
+ },
9
+ {
10
+ "name": "basic invalid type",
11
+ "valid":true,
12
+ "type":"credentials",
13
+ "input":{
14
+ "id":"foo",
15
+ "type":"send",
16
+ "context":"dummy",
17
+ "actor":{
18
+ "id":"dood@irc.freenode.net",
19
+ "type":"person",
20
+ "name":"dood"
21
+ },
22
+ "target":{
23
+ "id":"irc.freenode.net/service",
24
+ "type":"person",
25
+ "name":"service"
26
+ },
27
+ "object":{
28
+ "type":"credentials"
29
+ }
30
+ },
31
+ "output": "same"
32
+ },
33
+ {
34
+ "name": "basic valid type",
35
+ "valid":true,
36
+ "type":"credentials",
37
+ "input":{
38
+ "id":"foo",
39
+ "type":"credentials",
40
+ "context":"dummy",
41
+ "actor":{
42
+ "id":"dood@irc.freenode.net",
43
+ "type":"person",
44
+ "name":"dood"
45
+ },
46
+ "target":{
47
+ "id":"irc.freenode.net/service",
48
+ "type":"person",
49
+ "name":"service"
50
+ },
51
+ "object":{
52
+ "type":"credentials"
53
+ }
54
+ },
55
+ "output":"same"
56
+ },
57
+ {
58
+ "name":"new format",
59
+ "valid":true,
60
+ "type":"credentials",
61
+ "input":{
62
+ "type":"credentials",
63
+ "context":"irc",
64
+ "actor":{
65
+ "id":"sh-9K3Vk@irc.freenode.net",
66
+ "type":"person",
67
+ "name":"sh-9K3Vk",
68
+ "image":{
69
+ "height":250,
70
+ "mediaType":"image/jpeg",
71
+ "url":"http://example.org/image.jpg",
72
+ "width":250
73
+ },
74
+ "url":"http://sockethub.org"
75
+ },
76
+ "object":{
77
+ "type":"credentials",
78
+ "nick":"sh-9K3Vk",
79
+ "port":6667,
80
+ "secure":false,
81
+ "server":"irc.freenode.net"
82
+ }
83
+ },
84
+ "output":"same"
85
+ },
86
+ {
87
+ "name":"no type specified",
88
+ "valid":false,
89
+ "type":"credentials",
90
+ "input":{
91
+ "actor":"hyper_rau@localhost",
92
+ "context":"xmpp",
93
+ "object":{
94
+ "username":"hyper_rau",
95
+ "password":"123",
96
+ "server":"localhost",
97
+ "port":5222,
98
+ "resource":"laptop"
99
+ }
100
+ },
101
+ "error": "Error: activity stream must contain a type property."
102
+ },
103
+ {
104
+ "name": "expand unknown actor",
105
+ "type": "message",
106
+ "valid": "true",
107
+ "input": {
108
+ "context": "foo",
109
+ "type": "bar",
110
+ "actor": "foo@bar",
111
+ "object": {
112
+ "content": "bar"
113
+ }
114
+ },
115
+ "output": {
116
+ "context": "foo",
117
+ "type": "bar",
118
+ "actor": {
119
+ "id": "foo@bar"
120
+ },
121
+ "object": {
122
+ "content": "bar"
123
+ }
124
+ }
125
+ },
126
+ {
127
+ "name": "expand unknown actor 2",
128
+ "type": "message",
129
+ "valid": "true",
130
+ "input": {
131
+ "context": "foo",
132
+ "type": "bar",
133
+ "actor": "someone@example.org/resource",
134
+ "object": {
135
+ "content": "bar"
136
+ }
137
+ },
138
+ "output": {
139
+ "context": "foo",
140
+ "type": "bar",
141
+ "actor": {
142
+ "id": "someone@example.org/resource"
143
+ },
144
+ "object": {
145
+ "content": "bar"
146
+ }
147
+ }
148
+ },
149
+ {
150
+ "name": "expand unknown actor 2",
151
+ "type": "message",
152
+ "valid": "true",
153
+ "input": {
154
+ "context": "foo",
155
+ "type": "bar",
156
+ "actor": "xmpp:someone@example.org/resource",
157
+ "object": {
158
+ "content": "bar"
159
+ }
160
+ },
161
+ "output": {
162
+ "context": "foo",
163
+ "type": "bar",
164
+ "actor": {
165
+ "id": "xmpp:someone@example.org/resource"
166
+ },
167
+ "object": {
168
+ "content": "bar"
169
+ }
170
+ }
171
+ },
172
+ {
173
+ "name":"person",
174
+ "type":"message",
175
+ "valid":true,
176
+ "input":{
177
+ "context": "some context",
178
+ "type": "some type",
179
+ "actor": "blah",
180
+ "object": {}
181
+ },
182
+ "output": {
183
+ "context": "some context",
184
+ "type": "some type",
185
+ "actor": {
186
+ "id":"blah",
187
+ "type":"person",
188
+ "name":"dood"
189
+ },
190
+ "object": {}
191
+ }
192
+ },
193
+ {
194
+ "name":"person with extras",
195
+ "valid":true,
196
+ "type":"message",
197
+ "input": {
198
+ "context": "some context",
199
+ "type": "some type",
200
+ "actor": "blah2",
201
+ "object": {}
202
+ },
203
+ "output": {
204
+ "context": "some context",
205
+ "type": "some type",
206
+ "actor": {
207
+ "id":"blah2",
208
+ "type":"person",
209
+ "name":"bob",
210
+ "hello":"there",
211
+ "i":[
212
+ "am",
213
+ "extras"
214
+ ]
215
+ },
216
+ "object": {}
217
+ }
218
+ },
219
+ {
220
+ "name":"bad parent object",
221
+ "valid":false,
222
+ "type":"message",
223
+ "input":{
224
+ "string":"this is a string",
225
+ "array":[
226
+ "this",
227
+ "is",
228
+ {
229
+ "an":"array"
230
+ }
231
+ ],
232
+ "as":{
233
+ "id":"blah",
234
+ "type":"send",
235
+ "context":"hello",
236
+ "actor":{
237
+ "name":"dood"
238
+ },
239
+ "target":{
240
+ "type":"person",
241
+ "name":"bob"
242
+ },
243
+ "object":{
244
+ "type":"credentials"
245
+ }
246
+ },
247
+ "noId":{
248
+ "name":"dood"
249
+ },
250
+ "noId2":{
251
+ "type":"person",
252
+ "name":"bob"
253
+ },
254
+ "noDisplayName":{
255
+ "id":"larg"
256
+ }
257
+ },
258
+ "error": "Error: activity stream must contain a context property"
259
+ },
260
+ {
261
+ "name":"no actor specified",
262
+ "valid":false,
263
+ "type":"message",
264
+ "input":{
265
+ "type": "some type",
266
+ "context":"xmpp",
267
+ "object":{
268
+ "type": "error",
269
+ "content": "error message"
270
+ }
271
+ },
272
+ "error": "Error: activity stream must contain an actor property."
273
+ },
274
+ {
275
+ "name":"expand actor and target of unknowns",
276
+ "valid":true,
277
+ "type":"message",
278
+ "input":{
279
+ "actor":"irc://uuu@localhost",
280
+ "type":"join",
281
+ "context":"irc",
282
+ "target":"irc://irc.dooder.net/a-room"
283
+ },
284
+ "output":{
285
+ "actor":{
286
+ "id":"irc://uuu@localhost"
287
+ },
288
+ "type":"join",
289
+ "context":"irc",
290
+ "target":{
291
+ "id":"irc://irc.dooder.net/a-room"
292
+ }
293
+ }
294
+ },
295
+ {
296
+ "name":"expand actor and target of unknowns",
297
+ "valid":true,
298
+ "type":"message",
299
+ "input":{
300
+ "actor":"hyper_rau@localhost",
301
+ "type":"join",
302
+ "context":"xmpp",
303
+ "object":{
304
+
305
+ },
306
+ "target":"dooder"
307
+ },
308
+ "output":{
309
+ "actor":{
310
+ "id":"hyper_rau@localhost"
311
+ },
312
+ "type":"join",
313
+ "context":"xmpp",
314
+ "object":{
315
+
316
+ },
317
+ "target":{
318
+ "id":"dooder"
319
+ }
320
+ }
321
+ },
322
+ {
323
+ "name":"expand known person",
324
+ "valid":true,
325
+ "type":"message",
326
+ "input":{
327
+ "actor":"sh-9K3Vk@irc.freenode.net",
328
+ "target":"blah3",
329
+ "type":"send",
330
+ "context":"irc",
331
+ "object":{
332
+
333
+ }
334
+ },
335
+ "output":{
336
+ "actor":{
337
+ "id":"sh-9K3Vk@irc.freenode.net",
338
+ "type":"person",
339
+ "name":"sh-9K3Vk",
340
+ "image":{
341
+ "height":250,
342
+ "mediaType":"image/jpeg",
343
+ "url":"http://example.org/image.jpg",
344
+ "width":250
345
+ },
346
+ "url":"http://sockethub.org"
347
+ },
348
+ "target":{
349
+ "id":"blah3",
350
+ "type":"person",
351
+ "name":"bob",
352
+ "hello":"there",
353
+ "i":[
354
+ "am",
355
+ "extras"
356
+ ]
357
+ },
358
+ "type":"send",
359
+ "context":"irc",
360
+ "object":{
361
+
362
+ }
363
+ }
364
+ }
365
+ ];
@@ -0,0 +1,78 @@
1
+ import { expect } from 'chai';
2
+
3
+ import expandActivityStream from "./expand-activity-stream";
4
+
5
+ import asObjects from "./expand-activity-stream.test.data";
6
+ import ActivityStreams from '@sockethub/activity-streams';
7
+
8
+ const activity = ActivityStreams();
9
+ // register known activity objects
10
+ [
11
+ {
12
+ "id":"blah",
13
+ "type":"person",
14
+ "name":"dood"
15
+ },
16
+ {
17
+ "id":"blah2",
18
+ "type":"person",
19
+ "name":"bob",
20
+ "hello":"there",
21
+ "i":[
22
+ "am",
23
+ "extras"
24
+ ]
25
+ },
26
+ {
27
+ "id":"sh-9K3Vk@irc.freenode.net",
28
+ "type":"person",
29
+ "name":"sh-9K3Vk",
30
+ "image":{
31
+ "height":250,
32
+ "mediaType":"image/jpeg",
33
+ "url":"http://example.org/image.jpg",
34
+ "width":250
35
+ },
36
+ "url":"http://sockethub.org"
37
+ },
38
+ {
39
+ "id":"blah3",
40
+ "type":"person",
41
+ "name":"bob",
42
+ "hello":"there",
43
+ "i":[
44
+ "am",
45
+ "extras"
46
+ ]
47
+ }
48
+ ].forEach((obj) => {
49
+ activity.Object.create(obj);
50
+ });
51
+
52
+ describe('Middleware: Expand Activity Stream', () => {
53
+ describe('AS object expansion', () => {
54
+ asObjects.forEach((obj) => {
55
+ it(`${obj.type}: ${obj.name}, should ${obj.valid ? 'pass' : 'fail'}`, (done) => {
56
+ // @ts-ignore
57
+ expandActivityStream(obj.input, (msg) => {
58
+ if (obj.output) {
59
+ if (obj.output === 'same') {
60
+ expect(obj.input).to.eql(msg);
61
+ } else {
62
+ expect(obj.output).to.eql(msg);
63
+ }
64
+ }
65
+ if (obj.valid) {
66
+ expect(msg instanceof Error).to.be.false;
67
+ } else {
68
+ expect(msg instanceof Error).to.be.true;
69
+ if (obj.error) {
70
+ expect(obj.error).to.equal(msg.toString());
71
+ }
72
+ }
73
+ done();
74
+ });
75
+ });
76
+ });
77
+ });
78
+ });
@@ -0,0 +1,27 @@
1
+ import ActivityStreams from '@sockethub/activity-streams';
2
+ import { IActivityStream } from "@sockethub/schemas";
3
+
4
+ import config from "../config";
5
+
6
+ const activity = ActivityStreams(config.get('activity-streams:opts'));
7
+
8
+ function ensureObject(msg: any) {
9
+ return !((typeof msg !== 'object') || (Array.isArray(msg)));
10
+ }
11
+
12
+ export default function expandActivityStream(msg: IActivityStream, done: Function) {
13
+ if (! ensureObject(msg)) {
14
+ done(new Error(`message received is not an object.`));
15
+ } else if (typeof msg.context !== 'string') {
16
+ done(new Error('activity stream must contain a context property'));
17
+ } else if (typeof msg.type !== 'string') {
18
+ done(new Error('activity stream must contain a type property.'));
19
+ } else {
20
+ msg = activity.Stream(msg);
21
+ if (! msg.actor) {
22
+ done(new Error('activity stream must contain an actor property.'));
23
+ } else {
24
+ done(msg);
25
+ }
26
+ }
27
+ }