@rvoh/psychic-websockets 0.2.4 → 0.3.1
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/cjs/src/cable/index.js +24 -1
- package/dist/cjs/src/cable/ws.js +88 -17
- package/dist/cjs/src/error/ws/InvalidWsPathError.js +15 -0
- package/dist/cjs/src/error/ws/MissingWsRedisConnection.js +1 -1
- package/dist/cjs/src/index.js +5 -5
- package/dist/cjs/src/psychic-app-websockets/cache.js +17 -0
- package/dist/cjs/src/{psychic-application-websockets → psychic-app-websockets}/index.js +8 -8
- package/dist/esm/src/cable/index.js +29 -6
- package/dist/esm/src/cable/ws.js +89 -16
- package/dist/esm/src/error/ws/InvalidWsPathError.js +12 -0
- package/dist/esm/src/error/ws/MissingWsRedisConnection.js +1 -1
- package/dist/esm/src/index.js +1 -1
- package/dist/esm/src/psychic-app-websockets/cache.js +12 -0
- package/dist/esm/src/{psychic-application-websockets → psychic-app-websockets}/index.js +8 -8
- package/dist/types/src/cable/index.d.ts +27 -4
- package/dist/types/src/cable/ws.d.ts +85 -6
- package/dist/types/src/error/ws/InvalidWsPathError.d.ts +5 -0
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/psychic-app-websockets/cache.d.ts +4 -0
- package/dist/types/src/{psychic-application-websockets → psychic-app-websockets}/index.d.ts +12 -12
- package/package.json +11 -11
- package/dist/cjs/src/psychic-application-websockets/cache.js +0 -17
- package/dist/esm/src/psychic-application-websockets/cache.js +0 -12
- package/dist/types/src/psychic-application-websockets/cache.d.ts +0 -4
|
@@ -6,7 +6,7 @@ const socketio = require("socket.io");
|
|
|
6
6
|
const yoctocolors_1 = require("yoctocolors");
|
|
7
7
|
const MissingWsRedisConnection_js_1 = require("../error/ws/MissingWsRedisConnection.js");
|
|
8
8
|
const EnvInternal_js_1 = require("../helpers/EnvInternal.js");
|
|
9
|
-
const index_js_1 = require("../psychic-
|
|
9
|
+
const index_js_1 = require("../psychic-app-websockets/index.js");
|
|
10
10
|
class Cable {
|
|
11
11
|
app;
|
|
12
12
|
io;
|
|
@@ -17,6 +17,12 @@ class Cable {
|
|
|
17
17
|
this.app = app;
|
|
18
18
|
this.config = config;
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* @internal
|
|
22
|
+
*
|
|
23
|
+
* creates a new http server and binds it to a new socket.io server.
|
|
24
|
+
* this is automatically called when you call `start`.
|
|
25
|
+
*/
|
|
20
26
|
connect() {
|
|
21
27
|
if (this.io)
|
|
22
28
|
return;
|
|
@@ -25,6 +31,10 @@ class Cable {
|
|
|
25
31
|
this.httpServer = psychic_1.PsychicServer.createPsychicHttpInstance(this.app, this.config.psychicApp.sslCredentials);
|
|
26
32
|
this.io = new socketio.Server(this.httpServer, { cors: this.config.psychicApp.corsOptions });
|
|
27
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* builds an http server and a socket.io server, binding to redis
|
|
36
|
+
* to enable redis pubsub, then starts the http server.
|
|
37
|
+
*/
|
|
28
38
|
async start(port) {
|
|
29
39
|
this.connect();
|
|
30
40
|
for (const hook of this.config.hooks.wsStart) {
|
|
@@ -62,6 +72,9 @@ class Cable {
|
|
|
62
72
|
port: parseInt((port || psychicAppWebsockets.psychicApp.port).toString()),
|
|
63
73
|
});
|
|
64
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* stops the socket.io server, closing out of all redis connections
|
|
77
|
+
*/
|
|
65
78
|
async stop() {
|
|
66
79
|
try {
|
|
67
80
|
await this.io?.close();
|
|
@@ -78,6 +91,11 @@ class Cable {
|
|
|
78
91
|
}
|
|
79
92
|
}
|
|
80
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* @internal
|
|
96
|
+
*
|
|
97
|
+
* stops the socket.io server, closing out of all redis connections
|
|
98
|
+
*/
|
|
81
99
|
async listen({ port }) {
|
|
82
100
|
return new Promise(accept => {
|
|
83
101
|
this.httpServer.listen(port, () => {
|
|
@@ -93,6 +111,11 @@ class Cable {
|
|
|
93
111
|
});
|
|
94
112
|
});
|
|
95
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* @internal
|
|
116
|
+
*
|
|
117
|
+
* establishes redis pubsub mechanisms
|
|
118
|
+
*/
|
|
96
119
|
bindToRedis() {
|
|
97
120
|
const pubClient = this.config.websocketOptions.connection;
|
|
98
121
|
const subClient = this.config.websocketOptions.subConnection;
|
package/dist/cjs/src/cable/ws.js
CHANGED
|
@@ -1,18 +1,61 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.InvalidWsPathError = void 0;
|
|
4
3
|
const dream_1 = require("@rvoh/dream");
|
|
5
4
|
const redis_emitter_1 = require("@socket.io/redis-emitter");
|
|
6
5
|
const EnvInternal_js_1 = require("../helpers/EnvInternal.js");
|
|
7
|
-
const index_js_1 = require("../psychic-
|
|
6
|
+
const index_js_1 = require("../psychic-app-websockets/index.js");
|
|
8
7
|
const redisWsKey_js_1 = require("./redisWsKey.js");
|
|
8
|
+
const InvalidWsPathError_js_1 = require("../error/ws/InvalidWsPathError.js");
|
|
9
9
|
class Ws {
|
|
10
10
|
allowedPaths;
|
|
11
|
+
/**
|
|
12
|
+
* @internal
|
|
13
|
+
*
|
|
14
|
+
* the socket.io redis emitter instance, used to emit
|
|
15
|
+
* messages through redis to distributed websocket clusters
|
|
16
|
+
*/
|
|
11
17
|
io;
|
|
18
|
+
/**
|
|
19
|
+
* @internal
|
|
20
|
+
*
|
|
21
|
+
* the redis client used to bind socket.io to the redis emitter
|
|
22
|
+
*/
|
|
12
23
|
redisClient;
|
|
24
|
+
/**
|
|
25
|
+
* @internal
|
|
26
|
+
*
|
|
27
|
+
* the redis client used to bind socket.io to the redis emitter
|
|
28
|
+
*/
|
|
13
29
|
booted = false;
|
|
30
|
+
/**
|
|
31
|
+
* @internal
|
|
32
|
+
*
|
|
33
|
+
* the namespace used when connecting socket.io
|
|
34
|
+
* this will default to '/' if it is not provided
|
|
35
|
+
*/
|
|
14
36
|
namespace;
|
|
37
|
+
/**
|
|
38
|
+
* @internal
|
|
39
|
+
*
|
|
40
|
+
* when registering your application's users with psychic-websockets,
|
|
41
|
+
* you need to provide the following:
|
|
42
|
+
* 1. an identifier for your user (i.e. user.id)
|
|
43
|
+
* 2. a redisKeyPrefix, which is used to prefix your id before storing it in redis
|
|
44
|
+
*
|
|
45
|
+
* this enables you to have multiple namespaces in redis to safely store ids,
|
|
46
|
+
* i.e.
|
|
47
|
+
*
|
|
48
|
+
* `user:1`
|
|
49
|
+
* `admin-user:1`
|
|
50
|
+
*/
|
|
15
51
|
redisKeyPrefix;
|
|
52
|
+
/**
|
|
53
|
+
* call this method to bind a socket to a particular identifier
|
|
54
|
+
*
|
|
55
|
+
* @param socket - the socket.io socket instance
|
|
56
|
+
* @param id - the identifier you wish to bind to this socket instance
|
|
57
|
+
* @param redisKeyPrefix - (optional) the prefix you wish to use to couple to this id (defaults to 'user')
|
|
58
|
+
*/
|
|
16
59
|
static async register(socket, id, redisKeyPrefix = 'user') {
|
|
17
60
|
const psychicWebsocketsApp = index_js_1.default.getOrFail();
|
|
18
61
|
const redisClient = psychicWebsocketsApp.websocketOptions.connection;
|
|
@@ -37,11 +80,34 @@ class Ws {
|
|
|
37
80
|
message: 'Successfully connected to psychic websockets',
|
|
38
81
|
});
|
|
39
82
|
}
|
|
40
|
-
constructor(allowedPaths, {
|
|
83
|
+
constructor(allowedPaths, {
|
|
84
|
+
/**
|
|
85
|
+
* the namespace used when connecting socket.io
|
|
86
|
+
* this will default to '/' if it is not provided
|
|
87
|
+
*/
|
|
88
|
+
namespace = '/',
|
|
89
|
+
/**
|
|
90
|
+
* when registering your application's users with psychic-websockets,
|
|
91
|
+
* you need to provide the following:
|
|
92
|
+
* 1. an identifier for your user (i.e. user.id)
|
|
93
|
+
* 2. a redisKeyPrefix, which is used to prefix your id before storing it in redis
|
|
94
|
+
*
|
|
95
|
+
* this enables you to have multiple namespaces in redis to safely store ids,
|
|
96
|
+
* i.e.
|
|
97
|
+
*
|
|
98
|
+
* `user:1`
|
|
99
|
+
* `admin-user:1`
|
|
100
|
+
*/
|
|
101
|
+
redisKeyPrefix = 'user', } = {}) {
|
|
41
102
|
this.allowedPaths = allowedPaths;
|
|
42
103
|
this.namespace = namespace;
|
|
43
104
|
this.redisKeyPrefix = redisKeyPrefix;
|
|
44
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* @internal
|
|
108
|
+
*
|
|
109
|
+
* establishes a new socket.io-redis emitter
|
|
110
|
+
*/
|
|
45
111
|
boot() {
|
|
46
112
|
if (this.booted)
|
|
47
113
|
return;
|
|
@@ -50,36 +116,41 @@ class Ws {
|
|
|
50
116
|
this.io = new redis_emitter_1.Emitter(this.redisClient).of(this.namespace);
|
|
51
117
|
this.booted = true;
|
|
52
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* emits data to the requested id (or dream instance) and path
|
|
121
|
+
*
|
|
122
|
+
* ```ts
|
|
123
|
+
* await ws.emit(123, '/ops/howyadoin', { hello: 'world' })
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
53
126
|
async emit(id, path,
|
|
54
127
|
// eslint-disable-next-line
|
|
55
128
|
data = {}) {
|
|
56
129
|
if (this.allowedPaths.length && !this.allowedPaths.includes(path))
|
|
57
|
-
throw new
|
|
130
|
+
throw new InvalidWsPathError_js_1.default(path);
|
|
58
131
|
this.boot();
|
|
59
132
|
const socketIds = await this.findSocketIds(id?.isDreamInstance ? id.primaryKeyValue : id);
|
|
60
133
|
for (const socketId of socketIds) {
|
|
61
134
|
this.io.to(socketId).emit(path, data);
|
|
62
135
|
}
|
|
63
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* @internal
|
|
139
|
+
*
|
|
140
|
+
* used to find a redis key matching the id
|
|
141
|
+
*/
|
|
64
142
|
async findSocketIds(id) {
|
|
65
143
|
this.boot();
|
|
66
144
|
return (0, dream_1.uniq)(await this.redisClient.lrange(this.redisKey(id), 0, -1));
|
|
67
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* @internal
|
|
148
|
+
*
|
|
149
|
+
* builds a redis key using the provided identifier and the redisKeyPrefix provided
|
|
150
|
+
* when this Ws instance was constructed.
|
|
151
|
+
*/
|
|
68
152
|
redisKey(userId) {
|
|
69
153
|
return (0, redisWsKey_js_1.default)(userId, this.redisKeyPrefix);
|
|
70
154
|
}
|
|
71
155
|
}
|
|
72
156
|
exports.default = Ws;
|
|
73
|
-
class InvalidWsPathError extends Error {
|
|
74
|
-
invalidPath;
|
|
75
|
-
constructor(invalidPath) {
|
|
76
|
-
super();
|
|
77
|
-
this.invalidPath = invalidPath;
|
|
78
|
-
}
|
|
79
|
-
get message() {
|
|
80
|
-
return `
|
|
81
|
-
Invalid path passed to Ws: "${this.invalidPath}"
|
|
82
|
-
`;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
exports.InvalidWsPathError = InvalidWsPathError;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
class InvalidWsPathError extends Error {
|
|
4
|
+
invalidPath;
|
|
5
|
+
constructor(invalidPath) {
|
|
6
|
+
super();
|
|
7
|
+
this.invalidPath = invalidPath;
|
|
8
|
+
}
|
|
9
|
+
get message() {
|
|
10
|
+
return `
|
|
11
|
+
Invalid path passed to Ws: "${this.invalidPath}"
|
|
12
|
+
`;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.default = InvalidWsPathError;
|
|
@@ -11,7 +11,7 @@ In conf/app.ts, either:
|
|
|
11
11
|
1.) disable websockets by omitting the call to psy.set('websockets', ...), OR
|
|
12
12
|
2.) provide a redis connection for your websockets, as shown below:
|
|
13
13
|
|
|
14
|
-
export default async (psy:
|
|
14
|
+
export default async (psy: PsychicApp) => {
|
|
15
15
|
...
|
|
16
16
|
|
|
17
17
|
psy.set('websockets', {
|
package/dist/cjs/src/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
var index_js_1 = require("./
|
|
5
|
-
Object.defineProperty(exports, "
|
|
6
|
-
var index_js_2 = require("./cable/index.js");
|
|
7
|
-
Object.defineProperty(exports, "Cable", { enumerable: true, get: function () { return index_js_2.default; } });
|
|
3
|
+
exports.PsychicAppWebsockets = exports.Ws = exports.Cable = void 0;
|
|
4
|
+
var index_js_1 = require("./cable/index.js");
|
|
5
|
+
Object.defineProperty(exports, "Cable", { enumerable: true, get: function () { return index_js_1.default; } });
|
|
8
6
|
var ws_js_1 = require("./cable/ws.js");
|
|
9
7
|
Object.defineProperty(exports, "Ws", { enumerable: true, get: function () { return ws_js_1.default; } });
|
|
8
|
+
var index_js_2 = require("./psychic-app-websockets/index.js");
|
|
9
|
+
Object.defineProperty(exports, "PsychicAppWebsockets", { enumerable: true, get: function () { return index_js_2.default; } });
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cachePsychicAppWebsockets = cachePsychicAppWebsockets;
|
|
4
|
+
exports.getCachedPsychicAppWebsockets = getCachedPsychicAppWebsockets;
|
|
5
|
+
exports.getCachedPsychicAppWebsocketsOrFail = getCachedPsychicAppWebsocketsOrFail;
|
|
6
|
+
let _psychicAppWebsockets = undefined;
|
|
7
|
+
function cachePsychicAppWebsockets(psychicAppWebsockets) {
|
|
8
|
+
_psychicAppWebsockets = psychicAppWebsockets;
|
|
9
|
+
}
|
|
10
|
+
function getCachedPsychicAppWebsockets() {
|
|
11
|
+
return _psychicAppWebsockets;
|
|
12
|
+
}
|
|
13
|
+
function getCachedPsychicAppWebsocketsOrFail() {
|
|
14
|
+
if (!_psychicAppWebsockets)
|
|
15
|
+
throw new Error('must call `cachePsychicAppWebsockets` before loading cached psychic application websockets');
|
|
16
|
+
return _psychicAppWebsockets;
|
|
17
|
+
}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const index_js_1 = require("../cable/index.js");
|
|
4
4
|
const cache_js_1 = require("./cache.js");
|
|
5
|
-
class
|
|
5
|
+
class PsychicAppWebsockets {
|
|
6
6
|
static async init(psychicApp, cb) {
|
|
7
|
-
const psychicWsApp = new
|
|
7
|
+
const psychicWsApp = new PsychicAppWebsockets(psychicApp);
|
|
8
8
|
await cb(psychicWsApp);
|
|
9
9
|
psychicApp.on('server:shutdown', async (psychicServer) => {
|
|
10
10
|
const cable = psychicServer.$attached.cable;
|
|
@@ -20,17 +20,17 @@ class PsychicApplicationWebsockets {
|
|
|
20
20
|
psychicServer.attach('cable', cable);
|
|
21
21
|
return cable.httpServer;
|
|
22
22
|
});
|
|
23
|
-
(0, cache_js_1.
|
|
23
|
+
(0, cache_js_1.cachePsychicAppWebsockets)(psychicWsApp);
|
|
24
24
|
return psychicWsApp;
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
27
|
* Returns the cached psychic application if it has been set.
|
|
28
28
|
* If it has not been set, an exception is raised.
|
|
29
29
|
*
|
|
30
|
-
* The psychic application can be set by calling
|
|
30
|
+
* The psychic application can be set by calling PsychicApp#init
|
|
31
31
|
*/
|
|
32
32
|
static getOrFail() {
|
|
33
|
-
return (0, cache_js_1.
|
|
33
|
+
return (0, cache_js_1.getCachedPsychicAppWebsocketsOrFail)();
|
|
34
34
|
}
|
|
35
35
|
psychicApp;
|
|
36
36
|
static log(...args) {
|
|
@@ -61,7 +61,7 @@ class PsychicApplicationWebsockets {
|
|
|
61
61
|
this._hooks.wsConnect.push(cb);
|
|
62
62
|
break;
|
|
63
63
|
default:
|
|
64
|
-
throw new Error(`unrecognized event provided to
|
|
64
|
+
throw new Error(`unrecognized event provided to PsychicAppWebsockets#on: ${hookEventType}`);
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
set(option, value) {
|
|
@@ -79,8 +79,8 @@ class PsychicApplicationWebsockets {
|
|
|
79
79
|
};
|
|
80
80
|
break;
|
|
81
81
|
default:
|
|
82
|
-
throw new Error(`Unhandled option type passed to
|
|
82
|
+
throw new Error(`Unhandled option type passed to PsychicAppWebsockets#set: ${option}`);
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
|
-
exports.default =
|
|
86
|
+
exports.default = PsychicAppWebsockets;
|
|
@@ -4,7 +4,7 @@ import * as socketio from 'socket.io';
|
|
|
4
4
|
import colors from 'yoctocolors';
|
|
5
5
|
import MissingWsRedisConnection from '../error/ws/MissingWsRedisConnection.js';
|
|
6
6
|
import EnvInternal from '../helpers/EnvInternal.js';
|
|
7
|
-
import
|
|
7
|
+
import PsychicAppWebsockets from '../psychic-app-websockets/index.js';
|
|
8
8
|
export default class Cable {
|
|
9
9
|
app;
|
|
10
10
|
io;
|
|
@@ -15,6 +15,12 @@ export default class Cable {
|
|
|
15
15
|
this.app = app;
|
|
16
16
|
this.config = config;
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* @internal
|
|
20
|
+
*
|
|
21
|
+
* creates a new http server and binds it to a new socket.io server.
|
|
22
|
+
* this is automatically called when you call `start`.
|
|
23
|
+
*/
|
|
18
24
|
connect() {
|
|
19
25
|
if (this.io)
|
|
20
26
|
return;
|
|
@@ -23,6 +29,10 @@ export default class Cable {
|
|
|
23
29
|
this.httpServer = PsychicServer.createPsychicHttpInstance(this.app, this.config.psychicApp.sslCredentials);
|
|
24
30
|
this.io = new socketio.Server(this.httpServer, { cors: this.config.psychicApp.corsOptions });
|
|
25
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* builds an http server and a socket.io server, binding to redis
|
|
34
|
+
* to enable redis pubsub, then starts the http server.
|
|
35
|
+
*/
|
|
26
36
|
async start(port) {
|
|
27
37
|
this.connect();
|
|
28
38
|
for (const hook of this.config.hooks.wsStart) {
|
|
@@ -55,11 +65,14 @@ export default class Cable {
|
|
|
55
65
|
}
|
|
56
66
|
});
|
|
57
67
|
this.bindToRedis();
|
|
58
|
-
const psychicAppWebsockets =
|
|
68
|
+
const psychicAppWebsockets = PsychicAppWebsockets.getOrFail();
|
|
59
69
|
await this.listen({
|
|
60
70
|
port: parseInt((port || psychicAppWebsockets.psychicApp.port).toString()),
|
|
61
71
|
});
|
|
62
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* stops the socket.io server, closing out of all redis connections
|
|
75
|
+
*/
|
|
63
76
|
async stop() {
|
|
64
77
|
try {
|
|
65
78
|
await this.io?.close();
|
|
@@ -76,11 +89,16 @@ export default class Cable {
|
|
|
76
89
|
}
|
|
77
90
|
}
|
|
78
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* @internal
|
|
94
|
+
*
|
|
95
|
+
* stops the socket.io server, closing out of all redis connections
|
|
96
|
+
*/
|
|
79
97
|
async listen({ port }) {
|
|
80
98
|
return new Promise(accept => {
|
|
81
99
|
this.httpServer.listen(port, () => {
|
|
82
100
|
if (!EnvInternal.isTest) {
|
|
83
|
-
const app =
|
|
101
|
+
const app = PsychicAppWebsockets.getOrFail().psychicApp;
|
|
84
102
|
app.logger.info(PsychicServer.asciiLogo());
|
|
85
103
|
app.logger.info('\n');
|
|
86
104
|
app.logger.info(colors.cyan('socket server started '));
|
|
@@ -91,6 +109,11 @@ export default class Cable {
|
|
|
91
109
|
});
|
|
92
110
|
});
|
|
93
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* @internal
|
|
114
|
+
*
|
|
115
|
+
* establishes redis pubsub mechanisms
|
|
116
|
+
*/
|
|
94
117
|
bindToRedis() {
|
|
95
118
|
const pubClient = this.config.websocketOptions.connection;
|
|
96
119
|
const subClient = this.config.websocketOptions.subConnection;
|
|
@@ -99,16 +122,16 @@ export default class Cable {
|
|
|
99
122
|
this.redisConnections.push(pubClient);
|
|
100
123
|
this.redisConnections.push(subClient);
|
|
101
124
|
pubClient.on('error', error => {
|
|
102
|
-
|
|
125
|
+
PsychicAppWebsockets.log('PUB CLIENT ERROR', error);
|
|
103
126
|
});
|
|
104
127
|
subClient.on('error', error => {
|
|
105
|
-
|
|
128
|
+
PsychicAppWebsockets.log('sub CLIENT ERROR', error);
|
|
106
129
|
});
|
|
107
130
|
try {
|
|
108
131
|
this.io.adapter(createAdapter(pubClient, subClient));
|
|
109
132
|
}
|
|
110
133
|
catch (error) {
|
|
111
|
-
|
|
134
|
+
PsychicAppWebsockets.log('FAILED TO ADAPT', error);
|
|
112
135
|
}
|
|
113
136
|
}
|
|
114
137
|
}
|
package/dist/esm/src/cable/ws.js
CHANGED
|
@@ -1,17 +1,61 @@
|
|
|
1
1
|
import { DateTime, uniq } from '@rvoh/dream';
|
|
2
2
|
import { Emitter } from '@socket.io/redis-emitter';
|
|
3
3
|
import EnvInternal from '../helpers/EnvInternal.js';
|
|
4
|
-
import
|
|
4
|
+
import PsychicAppWebsockets from '../psychic-app-websockets/index.js';
|
|
5
5
|
import redisWsKey from './redisWsKey.js';
|
|
6
|
+
import InvalidWsPathError from '../error/ws/InvalidWsPathError.js';
|
|
6
7
|
export default class Ws {
|
|
7
8
|
allowedPaths;
|
|
9
|
+
/**
|
|
10
|
+
* @internal
|
|
11
|
+
*
|
|
12
|
+
* the socket.io redis emitter instance, used to emit
|
|
13
|
+
* messages through redis to distributed websocket clusters
|
|
14
|
+
*/
|
|
8
15
|
io;
|
|
16
|
+
/**
|
|
17
|
+
* @internal
|
|
18
|
+
*
|
|
19
|
+
* the redis client used to bind socket.io to the redis emitter
|
|
20
|
+
*/
|
|
9
21
|
redisClient;
|
|
22
|
+
/**
|
|
23
|
+
* @internal
|
|
24
|
+
*
|
|
25
|
+
* the redis client used to bind socket.io to the redis emitter
|
|
26
|
+
*/
|
|
10
27
|
booted = false;
|
|
28
|
+
/**
|
|
29
|
+
* @internal
|
|
30
|
+
*
|
|
31
|
+
* the namespace used when connecting socket.io
|
|
32
|
+
* this will default to '/' if it is not provided
|
|
33
|
+
*/
|
|
11
34
|
namespace;
|
|
35
|
+
/**
|
|
36
|
+
* @internal
|
|
37
|
+
*
|
|
38
|
+
* when registering your application's users with psychic-websockets,
|
|
39
|
+
* you need to provide the following:
|
|
40
|
+
* 1. an identifier for your user (i.e. user.id)
|
|
41
|
+
* 2. a redisKeyPrefix, which is used to prefix your id before storing it in redis
|
|
42
|
+
*
|
|
43
|
+
* this enables you to have multiple namespaces in redis to safely store ids,
|
|
44
|
+
* i.e.
|
|
45
|
+
*
|
|
46
|
+
* `user:1`
|
|
47
|
+
* `admin-user:1`
|
|
48
|
+
*/
|
|
12
49
|
redisKeyPrefix;
|
|
50
|
+
/**
|
|
51
|
+
* call this method to bind a socket to a particular identifier
|
|
52
|
+
*
|
|
53
|
+
* @param socket - the socket.io socket instance
|
|
54
|
+
* @param id - the identifier you wish to bind to this socket instance
|
|
55
|
+
* @param redisKeyPrefix - (optional) the prefix you wish to use to couple to this id (defaults to 'user')
|
|
56
|
+
*/
|
|
13
57
|
static async register(socket, id, redisKeyPrefix = 'user') {
|
|
14
|
-
const psychicWebsocketsApp =
|
|
58
|
+
const psychicWebsocketsApp = PsychicAppWebsockets.getOrFail();
|
|
15
59
|
const redisClient = psychicWebsocketsApp.websocketOptions.connection;
|
|
16
60
|
const interpretedId = id?.isDreamInstance ? id.primaryKeyValue : id;
|
|
17
61
|
const key = redisWsKey(interpretedId, redisKeyPrefix);
|
|
@@ -34,19 +78,49 @@ export default class Ws {
|
|
|
34
78
|
message: 'Successfully connected to psychic websockets',
|
|
35
79
|
});
|
|
36
80
|
}
|
|
37
|
-
constructor(allowedPaths, {
|
|
81
|
+
constructor(allowedPaths, {
|
|
82
|
+
/**
|
|
83
|
+
* the namespace used when connecting socket.io
|
|
84
|
+
* this will default to '/' if it is not provided
|
|
85
|
+
*/
|
|
86
|
+
namespace = '/',
|
|
87
|
+
/**
|
|
88
|
+
* when registering your application's users with psychic-websockets,
|
|
89
|
+
* you need to provide the following:
|
|
90
|
+
* 1. an identifier for your user (i.e. user.id)
|
|
91
|
+
* 2. a redisKeyPrefix, which is used to prefix your id before storing it in redis
|
|
92
|
+
*
|
|
93
|
+
* this enables you to have multiple namespaces in redis to safely store ids,
|
|
94
|
+
* i.e.
|
|
95
|
+
*
|
|
96
|
+
* `user:1`
|
|
97
|
+
* `admin-user:1`
|
|
98
|
+
*/
|
|
99
|
+
redisKeyPrefix = 'user', } = {}) {
|
|
38
100
|
this.allowedPaths = allowedPaths;
|
|
39
101
|
this.namespace = namespace;
|
|
40
102
|
this.redisKeyPrefix = redisKeyPrefix;
|
|
41
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* @internal
|
|
106
|
+
*
|
|
107
|
+
* establishes a new socket.io-redis emitter
|
|
108
|
+
*/
|
|
42
109
|
boot() {
|
|
43
110
|
if (this.booted)
|
|
44
111
|
return;
|
|
45
|
-
const psychicWebsocketsApp =
|
|
112
|
+
const psychicWebsocketsApp = PsychicAppWebsockets.getOrFail();
|
|
46
113
|
this.redisClient = psychicWebsocketsApp.websocketOptions.connection;
|
|
47
114
|
this.io = new Emitter(this.redisClient).of(this.namespace);
|
|
48
115
|
this.booted = true;
|
|
49
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* emits data to the requested id (or dream instance) and path
|
|
119
|
+
*
|
|
120
|
+
* ```ts
|
|
121
|
+
* await ws.emit(123, '/ops/howyadoin', { hello: 'world' })
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
50
124
|
async emit(id, path,
|
|
51
125
|
// eslint-disable-next-line
|
|
52
126
|
data = {}) {
|
|
@@ -58,23 +132,22 @@ export default class Ws {
|
|
|
58
132
|
this.io.to(socketId).emit(path, data);
|
|
59
133
|
}
|
|
60
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* @internal
|
|
137
|
+
*
|
|
138
|
+
* used to find a redis key matching the id
|
|
139
|
+
*/
|
|
61
140
|
async findSocketIds(id) {
|
|
62
141
|
this.boot();
|
|
63
142
|
return uniq(await this.redisClient.lrange(this.redisKey(id), 0, -1));
|
|
64
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* @internal
|
|
146
|
+
*
|
|
147
|
+
* builds a redis key using the provided identifier and the redisKeyPrefix provided
|
|
148
|
+
* when this Ws instance was constructed.
|
|
149
|
+
*/
|
|
65
150
|
redisKey(userId) {
|
|
66
151
|
return redisWsKey(userId, this.redisKeyPrefix);
|
|
67
152
|
}
|
|
68
153
|
}
|
|
69
|
-
export class InvalidWsPathError extends Error {
|
|
70
|
-
invalidPath;
|
|
71
|
-
constructor(invalidPath) {
|
|
72
|
-
super();
|
|
73
|
-
this.invalidPath = invalidPath;
|
|
74
|
-
}
|
|
75
|
-
get message() {
|
|
76
|
-
return `
|
|
77
|
-
Invalid path passed to Ws: "${this.invalidPath}"
|
|
78
|
-
`;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
@@ -9,7 +9,7 @@ In conf/app.ts, either:
|
|
|
9
9
|
1.) disable websockets by omitting the call to psy.set('websockets', ...), OR
|
|
10
10
|
2.) provide a redis connection for your websockets, as shown below:
|
|
11
11
|
|
|
12
|
-
export default async (psy:
|
|
12
|
+
export default async (psy: PsychicApp) => {
|
|
13
13
|
...
|
|
14
14
|
|
|
15
15
|
psy.set('websockets', {
|
package/dist/esm/src/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { default as PsychicApplicationWebsockets } from './psychic-application-websockets/index.js';
|
|
2
1
|
export { default as Cable } from './cable/index.js';
|
|
3
2
|
export { default as Ws } from './cable/ws.js';
|
|
3
|
+
export { default as PsychicAppWebsockets } from './psychic-app-websockets/index.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
let _psychicAppWebsockets = undefined;
|
|
2
|
+
export function cachePsychicAppWebsockets(psychicAppWebsockets) {
|
|
3
|
+
_psychicAppWebsockets = psychicAppWebsockets;
|
|
4
|
+
}
|
|
5
|
+
export function getCachedPsychicAppWebsockets() {
|
|
6
|
+
return _psychicAppWebsockets;
|
|
7
|
+
}
|
|
8
|
+
export function getCachedPsychicAppWebsocketsOrFail() {
|
|
9
|
+
if (!_psychicAppWebsockets)
|
|
10
|
+
throw new Error('must call `cachePsychicAppWebsockets` before loading cached psychic application websockets');
|
|
11
|
+
return _psychicAppWebsockets;
|
|
12
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import Cable from '../cable/index.js';
|
|
2
|
-
import {
|
|
3
|
-
export default class
|
|
2
|
+
import { cachePsychicAppWebsockets, getCachedPsychicAppWebsocketsOrFail } from './cache.js';
|
|
3
|
+
export default class PsychicAppWebsockets {
|
|
4
4
|
static async init(psychicApp, cb) {
|
|
5
|
-
const psychicWsApp = new
|
|
5
|
+
const psychicWsApp = new PsychicAppWebsockets(psychicApp);
|
|
6
6
|
await cb(psychicWsApp);
|
|
7
7
|
psychicApp.on('server:shutdown', async (psychicServer) => {
|
|
8
8
|
const cable = psychicServer.$attached.cable;
|
|
@@ -18,17 +18,17 @@ export default class PsychicApplicationWebsockets {
|
|
|
18
18
|
psychicServer.attach('cable', cable);
|
|
19
19
|
return cable.httpServer;
|
|
20
20
|
});
|
|
21
|
-
|
|
21
|
+
cachePsychicAppWebsockets(psychicWsApp);
|
|
22
22
|
return psychicWsApp;
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
25
|
* Returns the cached psychic application if it has been set.
|
|
26
26
|
* If it has not been set, an exception is raised.
|
|
27
27
|
*
|
|
28
|
-
* The psychic application can be set by calling
|
|
28
|
+
* The psychic application can be set by calling PsychicApp#init
|
|
29
29
|
*/
|
|
30
30
|
static getOrFail() {
|
|
31
|
-
return
|
|
31
|
+
return getCachedPsychicAppWebsocketsOrFail();
|
|
32
32
|
}
|
|
33
33
|
psychicApp;
|
|
34
34
|
static log(...args) {
|
|
@@ -59,7 +59,7 @@ export default class PsychicApplicationWebsockets {
|
|
|
59
59
|
this._hooks.wsConnect.push(cb);
|
|
60
60
|
break;
|
|
61
61
|
default:
|
|
62
|
-
throw new Error(`unrecognized event provided to
|
|
62
|
+
throw new Error(`unrecognized event provided to PsychicAppWebsockets#on: ${hookEventType}`);
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
set(option, value) {
|
|
@@ -77,7 +77,7 @@ export default class PsychicApplicationWebsockets {
|
|
|
77
77
|
};
|
|
78
78
|
break;
|
|
79
79
|
default:
|
|
80
|
-
throw new Error(`Unhandled option type passed to
|
|
80
|
+
throw new Error(`Unhandled option type passed to PsychicAppWebsockets#set: ${option}`);
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
}
|
|
@@ -1,19 +1,42 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Express } from 'express';
|
|
2
2
|
import * as http from 'http';
|
|
3
3
|
import * as socketio from 'socket.io';
|
|
4
|
-
import
|
|
4
|
+
import PsychicAppWebsockets from '../psychic-app-websockets/index.js';
|
|
5
5
|
export default class Cable {
|
|
6
|
-
app:
|
|
6
|
+
app: Express;
|
|
7
7
|
io: socketio.Server | undefined;
|
|
8
8
|
httpServer: http.Server;
|
|
9
9
|
private config;
|
|
10
10
|
private redisConnections;
|
|
11
|
-
constructor(app:
|
|
11
|
+
constructor(app: Express, config: PsychicAppWebsockets);
|
|
12
|
+
/**
|
|
13
|
+
* @internal
|
|
14
|
+
*
|
|
15
|
+
* creates a new http server and binds it to a new socket.io server.
|
|
16
|
+
* this is automatically called when you call `start`.
|
|
17
|
+
*/
|
|
12
18
|
connect(): void;
|
|
19
|
+
/**
|
|
20
|
+
* builds an http server and a socket.io server, binding to redis
|
|
21
|
+
* to enable redis pubsub, then starts the http server.
|
|
22
|
+
*/
|
|
13
23
|
start(port?: number): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* stops the socket.io server, closing out of all redis connections
|
|
26
|
+
*/
|
|
14
27
|
stop(): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* @internal
|
|
30
|
+
*
|
|
31
|
+
* stops the socket.io server, closing out of all redis connections
|
|
32
|
+
*/
|
|
15
33
|
listen({ port }: {
|
|
16
34
|
port: number | string;
|
|
17
35
|
}): Promise<unknown>;
|
|
36
|
+
/**
|
|
37
|
+
* @internal
|
|
38
|
+
*
|
|
39
|
+
* establishes redis pubsub mechanisms
|
|
40
|
+
*/
|
|
18
41
|
bindToRedis(): void;
|
|
19
42
|
}
|
|
@@ -3,23 +3,102 @@ import { Emitter } from '@socket.io/redis-emitter';
|
|
|
3
3
|
import { Socket } from 'socket.io';
|
|
4
4
|
export default class Ws<AllowedPaths extends readonly string[]> {
|
|
5
5
|
allowedPaths: AllowedPaths & readonly string[];
|
|
6
|
+
/**
|
|
7
|
+
* @internal
|
|
8
|
+
*
|
|
9
|
+
* the socket.io redis emitter instance, used to emit
|
|
10
|
+
* messages through redis to distributed websocket clusters
|
|
11
|
+
*/
|
|
6
12
|
io: Emitter;
|
|
13
|
+
/**
|
|
14
|
+
* @internal
|
|
15
|
+
*
|
|
16
|
+
* the redis client used to bind socket.io to the redis emitter
|
|
17
|
+
*/
|
|
7
18
|
private redisClient;
|
|
19
|
+
/**
|
|
20
|
+
* @internal
|
|
21
|
+
*
|
|
22
|
+
* the redis client used to bind socket.io to the redis emitter
|
|
23
|
+
*/
|
|
8
24
|
private booted;
|
|
25
|
+
/**
|
|
26
|
+
* @internal
|
|
27
|
+
*
|
|
28
|
+
* the namespace used when connecting socket.io
|
|
29
|
+
* this will default to '/' if it is not provided
|
|
30
|
+
*/
|
|
9
31
|
private namespace;
|
|
32
|
+
/**
|
|
33
|
+
* @internal
|
|
34
|
+
*
|
|
35
|
+
* when registering your application's users with psychic-websockets,
|
|
36
|
+
* you need to provide the following:
|
|
37
|
+
* 1. an identifier for your user (i.e. user.id)
|
|
38
|
+
* 2. a redisKeyPrefix, which is used to prefix your id before storing it in redis
|
|
39
|
+
*
|
|
40
|
+
* this enables you to have multiple namespaces in redis to safely store ids,
|
|
41
|
+
* i.e.
|
|
42
|
+
*
|
|
43
|
+
* `user:1`
|
|
44
|
+
* `admin-user:1`
|
|
45
|
+
*/
|
|
10
46
|
private redisKeyPrefix;
|
|
47
|
+
/**
|
|
48
|
+
* call this method to bind a socket to a particular identifier
|
|
49
|
+
*
|
|
50
|
+
* @param socket - the socket.io socket instance
|
|
51
|
+
* @param id - the identifier you wish to bind to this socket instance
|
|
52
|
+
* @param redisKeyPrefix - (optional) the prefix you wish to use to couple to this id (defaults to 'user')
|
|
53
|
+
*/
|
|
11
54
|
static register(socket: Socket, id: IdType | Dream, redisKeyPrefix?: string): Promise<void>;
|
|
12
|
-
constructor(allowedPaths: AllowedPaths & readonly string[], {
|
|
55
|
+
constructor(allowedPaths: AllowedPaths & readonly string[], {
|
|
56
|
+
/**
|
|
57
|
+
* the namespace used when connecting socket.io
|
|
58
|
+
* this will default to '/' if it is not provided
|
|
59
|
+
*/
|
|
60
|
+
namespace,
|
|
61
|
+
/**
|
|
62
|
+
* when registering your application's users with psychic-websockets,
|
|
63
|
+
* you need to provide the following:
|
|
64
|
+
* 1. an identifier for your user (i.e. user.id)
|
|
65
|
+
* 2. a redisKeyPrefix, which is used to prefix your id before storing it in redis
|
|
66
|
+
*
|
|
67
|
+
* this enables you to have multiple namespaces in redis to safely store ids,
|
|
68
|
+
* i.e.
|
|
69
|
+
*
|
|
70
|
+
* `user:1`
|
|
71
|
+
* `admin-user:1`
|
|
72
|
+
*/
|
|
73
|
+
redisKeyPrefix, }?: {
|
|
13
74
|
namespace?: string;
|
|
14
75
|
redisKeyPrefix?: string;
|
|
15
76
|
});
|
|
77
|
+
/**
|
|
78
|
+
* @internal
|
|
79
|
+
*
|
|
80
|
+
* establishes a new socket.io-redis emitter
|
|
81
|
+
*/
|
|
16
82
|
boot(): void;
|
|
83
|
+
/**
|
|
84
|
+
* emits data to the requested id (or dream instance) and path
|
|
85
|
+
*
|
|
86
|
+
* ```ts
|
|
87
|
+
* await ws.emit(123, '/ops/howyadoin', { hello: 'world' })
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
17
90
|
emit<T extends Ws<AllowedPaths>, const P extends AllowedPaths[number]>(this: T, id: IdType | Dream, path: P, data?: any): Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* @internal
|
|
93
|
+
*
|
|
94
|
+
* used to find a redis key matching the id
|
|
95
|
+
*/
|
|
18
96
|
findSocketIds(id: IdType): Promise<string[]>;
|
|
97
|
+
/**
|
|
98
|
+
* @internal
|
|
99
|
+
*
|
|
100
|
+
* builds a redis key using the provided identifier and the redisKeyPrefix provided
|
|
101
|
+
* when this Ws instance was constructed.
|
|
102
|
+
*/
|
|
19
103
|
private redisKey;
|
|
20
104
|
}
|
|
21
|
-
export declare class InvalidWsPathError extends Error {
|
|
22
|
-
private invalidPath;
|
|
23
|
-
constructor(invalidPath: string);
|
|
24
|
-
get message(): string;
|
|
25
|
-
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { default as PsychicApplicationWebsockets } from './psychic-application-websockets/index.js';
|
|
2
1
|
export { default as Cable } from './cable/index.js';
|
|
3
2
|
export { default as Ws } from './cable/ws.js';
|
|
3
|
+
export { default as PsychicAppWebsockets } from './psychic-app-websockets/index.js';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import PsychicAppWebsockets from './index.js';
|
|
2
|
+
export declare function cachePsychicAppWebsockets(psychicAppWebsockets: PsychicAppWebsockets): void;
|
|
3
|
+
export declare function getCachedPsychicAppWebsockets(): PsychicAppWebsockets | undefined;
|
|
4
|
+
export declare function getCachedPsychicAppWebsocketsOrFail(): PsychicAppWebsockets;
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PsychicApp } from '@rvoh/psychic';
|
|
2
2
|
import { Cluster, Redis } from 'ioredis';
|
|
3
3
|
import { Socket, Server as SocketServer } from 'socket.io';
|
|
4
|
-
export default class
|
|
5
|
-
static init(psychicApp:
|
|
4
|
+
export default class PsychicAppWebsockets {
|
|
5
|
+
static init(psychicApp: PsychicApp, cb: (app: PsychicAppWebsockets) => void | Promise<void>): Promise<PsychicAppWebsockets>;
|
|
6
6
|
/**
|
|
7
7
|
* Returns the cached psychic application if it has been set.
|
|
8
8
|
* If it has not been set, an exception is raised.
|
|
9
9
|
*
|
|
10
|
-
* The psychic application can be set by calling
|
|
10
|
+
* The psychic application can be set by calling PsychicApp#init
|
|
11
11
|
*/
|
|
12
|
-
static getOrFail():
|
|
13
|
-
psychicApp:
|
|
14
|
-
static log(...args: Parameters<typeof
|
|
15
|
-
constructor(psychicApp:
|
|
12
|
+
static getOrFail(): PsychicAppWebsockets;
|
|
13
|
+
psychicApp: PsychicApp;
|
|
14
|
+
static log(...args: Parameters<typeof PsychicApp.log>): void;
|
|
15
|
+
constructor(psychicApp: PsychicApp);
|
|
16
16
|
private _websocketOptions;
|
|
17
17
|
get websocketOptions(): PsychicWebsocketOptions & {
|
|
18
18
|
subConnection?: RedisOrRedisClusterConnection;
|
|
19
19
|
};
|
|
20
20
|
private _hooks;
|
|
21
|
-
get hooks():
|
|
21
|
+
get hooks(): PsychicAppWebsocketsHooks;
|
|
22
22
|
on<T extends PsychicWebsocketsHookEventType>(hookEventType: T, cb: T extends 'ws:start' ? (server: SocketServer) => void | Promise<void> : T extends 'ws:connect' ? (socket: Socket) => void | Promise<void> : never): void;
|
|
23
|
-
set<Opt extends
|
|
23
|
+
set<Opt extends PsychicAppWebsocketsOption>(option: Opt, value: unknown): void;
|
|
24
24
|
}
|
|
25
25
|
interface PsychicWebsocketOptions {
|
|
26
26
|
connection: Redis;
|
|
27
27
|
}
|
|
28
|
-
export type
|
|
28
|
+
export type PsychicAppWebsocketsOption = 'websockets';
|
|
29
29
|
export type PsychicWebsocketsHookEventType = 'ws:start' | 'ws:connect';
|
|
30
|
-
export interface
|
|
30
|
+
export interface PsychicAppWebsocketsHooks {
|
|
31
31
|
wsStart: ((server: SocketServer) => void | Promise<void>)[];
|
|
32
32
|
wsConnect: ((socket: Socket) => void | Promise<void>)[];
|
|
33
33
|
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@rvoh/psychic-websockets",
|
|
4
4
|
"description": "Websocket system for Psychic applications",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.3.1",
|
|
6
6
|
"author": "RVO Health",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -25,16 +25,16 @@
|
|
|
25
25
|
"scripts": {
|
|
26
26
|
"client": "yarn --cwd=./client start",
|
|
27
27
|
"client:fspec": "BROWSER=none VITE_PSYCHIC_ENV=test yarn --cwd=./client start",
|
|
28
|
-
"psy": "NODE_ENV=${NODE_ENV:-test} yarn
|
|
29
|
-
"
|
|
30
|
-
"
|
|
28
|
+
"psy": "NODE_ENV=${NODE_ENV:-test} yarn psy:ts",
|
|
29
|
+
"psy:js": "node ./dist/test-app/src/cli/index.js",
|
|
30
|
+
"psy:ts": "tsx ./test-app/src/cli/index.ts",
|
|
31
31
|
"build": "echo \"building cjs...\" && rm -rf dist && npx tsc -p ./tsconfig.cjs.build.json && echo \"building esm...\" && npx tsc -p ./tsconfig.esm.build.json",
|
|
32
32
|
"uspec": "vitest --config ./spec/unit/vite.config.ts",
|
|
33
33
|
"fspec": "vitest run --config=./spec/features/vite.config.ts",
|
|
34
34
|
"fspec:hanging": "vitest run --config=./spec/features/vite.config.ts --reporter=hanging-process",
|
|
35
35
|
"format": "yarn run prettier . --write",
|
|
36
36
|
"lint": "yarn run eslint --no-warn-ignored \"src/**/*.ts\" && yarn run prettier . --check",
|
|
37
|
-
"dev": "NODE_ENV=development WORKER_COUNT=0
|
|
37
|
+
"dev": "NODE_ENV=development WORKER_COUNT=0 tsx ./test-app/main.ts",
|
|
38
38
|
"prepack": "yarn build"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
@@ -48,10 +48,10 @@
|
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@eslint/js": "=9.0.0",
|
|
51
|
-
"@rvoh/dream": "^0.
|
|
52
|
-
"@rvoh/dream-spec-helpers": "^0.2.
|
|
53
|
-
"@rvoh/psychic": "^0.
|
|
54
|
-
"@rvoh/psychic-spec-helpers": "^0.
|
|
51
|
+
"@rvoh/dream": "^0.39.0",
|
|
52
|
+
"@rvoh/dream-spec-helpers": "^0.2.4",
|
|
53
|
+
"@rvoh/psychic": "^0.31.0",
|
|
54
|
+
"@rvoh/psychic-spec-helpers": "^0.6.0",
|
|
55
55
|
"@socket.io/redis-adapter": "^8.3.0",
|
|
56
56
|
"@socket.io/redis-emitter": "^5.1.0",
|
|
57
57
|
"@types/express": "^4",
|
|
@@ -72,8 +72,8 @@
|
|
|
72
72
|
"socket.io-adapter": "^2.5.5",
|
|
73
73
|
"socket.io-client": "^4.8.1",
|
|
74
74
|
"supertest": "^7.0.0",
|
|
75
|
-
"ts-node": "^10.9.2",
|
|
76
75
|
"tslib": "^2.7.0",
|
|
76
|
+
"tsx": "^4.19.3",
|
|
77
77
|
"typedoc": "^0.26.6",
|
|
78
78
|
"typescript": "^5.8.2",
|
|
79
79
|
"typescript-eslint": "=7.18.0",
|
|
@@ -83,4 +83,4 @@
|
|
|
83
83
|
"dependencies": {
|
|
84
84
|
"yoctocolors": "^2.1.1"
|
|
85
85
|
}
|
|
86
|
-
}
|
|
86
|
+
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.cachePsychicApplicationWebsockets = cachePsychicApplicationWebsockets;
|
|
4
|
-
exports.getCachedPsychicApplicationWebsockets = getCachedPsychicApplicationWebsockets;
|
|
5
|
-
exports.getCachedPsychicApplicationWebsocketsOrFail = getCachedPsychicApplicationWebsocketsOrFail;
|
|
6
|
-
let _psychicAppWebsockets = undefined;
|
|
7
|
-
function cachePsychicApplicationWebsockets(psychicAppWebsockets) {
|
|
8
|
-
_psychicAppWebsockets = psychicAppWebsockets;
|
|
9
|
-
}
|
|
10
|
-
function getCachedPsychicApplicationWebsockets() {
|
|
11
|
-
return _psychicAppWebsockets;
|
|
12
|
-
}
|
|
13
|
-
function getCachedPsychicApplicationWebsocketsOrFail() {
|
|
14
|
-
if (!_psychicAppWebsockets)
|
|
15
|
-
throw new Error('must call `cachePsychicApplicationWebsockets` before loading cached psychic application websockets');
|
|
16
|
-
return _psychicAppWebsockets;
|
|
17
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
let _psychicAppWebsockets = undefined;
|
|
2
|
-
export function cachePsychicApplicationWebsockets(psychicAppWebsockets) {
|
|
3
|
-
_psychicAppWebsockets = psychicAppWebsockets;
|
|
4
|
-
}
|
|
5
|
-
export function getCachedPsychicApplicationWebsockets() {
|
|
6
|
-
return _psychicAppWebsockets;
|
|
7
|
-
}
|
|
8
|
-
export function getCachedPsychicApplicationWebsocketsOrFail() {
|
|
9
|
-
if (!_psychicAppWebsockets)
|
|
10
|
-
throw new Error('must call `cachePsychicApplicationWebsockets` before loading cached psychic application websockets');
|
|
11
|
-
return _psychicAppWebsockets;
|
|
12
|
-
}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import PsychicApplicationWebsockets from './index.js';
|
|
2
|
-
export declare function cachePsychicApplicationWebsockets(psychicAppWebsockets: PsychicApplicationWebsockets): void;
|
|
3
|
-
export declare function getCachedPsychicApplicationWebsockets(): PsychicApplicationWebsockets | undefined;
|
|
4
|
-
export declare function getCachedPsychicApplicationWebsocketsOrFail(): PsychicApplicationWebsockets;
|