@jcbuisson/express-x 1.3.7 → 1.4.0
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/package.json +1 -2
- package/src/index.mjs +0 -2
- package/src/server.mjs +13 -3
- package/test/index.test.js +9 -2
- package/src/client.mjs +0 -95
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jcbuisson/express-x",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.mjs",
|
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
},
|
|
19
19
|
"keywords": [],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@jcbuisson/express-x-client": "^1.0.10",
|
|
22
21
|
"@prisma/client": "^4.10.1",
|
|
23
22
|
"axios": "^1.4.0",
|
|
24
23
|
"bcryptjs": "^2.4.3",
|
package/src/index.mjs
CHANGED
package/src/server.mjs
CHANGED
|
@@ -120,7 +120,7 @@ export function expressX(prisma, options = {}) {
|
|
|
120
120
|
http: { name: service.name }
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
// introspect schema
|
|
123
|
+
// introspect schema and return a map: field name => prisma type
|
|
124
124
|
async function getTypesMap() {
|
|
125
125
|
const dmmf = await service.prisma._getDmmf()
|
|
126
126
|
const fieldDescriptions = dmmf.modelMap[service.name].fields
|
|
@@ -252,10 +252,11 @@ export function expressX(prisma, options = {}) {
|
|
|
252
252
|
id: lastConnectionId++,
|
|
253
253
|
socket,
|
|
254
254
|
channelNames: new Set(),
|
|
255
|
+
data: {},
|
|
255
256
|
}
|
|
256
257
|
// store connection in cache
|
|
257
258
|
connections[connection.id] = connection
|
|
258
|
-
app.log('verbose', `active
|
|
259
|
+
app.log('verbose', `active connection ids: ${Object.keys(connections)}`)
|
|
259
260
|
|
|
260
261
|
// emit 'connection' event for app (expressjs extends EventEmitter)
|
|
261
262
|
app.emit('connection', connection)
|
|
@@ -265,7 +266,16 @@ export function expressX(prisma, options = {}) {
|
|
|
265
266
|
|
|
266
267
|
socket.on('disconnect', () => {
|
|
267
268
|
app.log('verbose', `Client disconnected ${connection.id}`)
|
|
268
|
-
|
|
269
|
+
|
|
270
|
+
// TODO: wait for 1mn before cleaning (a reconnection will use this data)
|
|
271
|
+
// delete connections[connection.id]
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
// handle connection data transfer caused by a disconnection (page reload, network issue, etc.)
|
|
275
|
+
socket.on('cnx-transfer', async ({ from, to }) => {
|
|
276
|
+
app.log('verbose', `cnx-transfer from ${from} to ${to}`)
|
|
277
|
+
connections[to] = connections[from]
|
|
278
|
+
delete connections[from]
|
|
269
279
|
})
|
|
270
280
|
|
|
271
281
|
|
package/test/index.test.js
CHANGED
|
@@ -2,17 +2,24 @@
|
|
|
2
2
|
import bodyParser from 'body-parser'
|
|
3
3
|
import axios from 'axios'
|
|
4
4
|
import io from 'socket.io-client'
|
|
5
|
+
import { PrismaClient } from '@prisma/client'
|
|
5
6
|
|
|
6
7
|
|
|
7
|
-
// import { assert } from 'chai'
|
|
8
8
|
import { describe, it, before, after, beforeEach, afterEach } from 'node:test'
|
|
9
9
|
import { strict as assert } from 'node:assert'
|
|
10
10
|
|
|
11
11
|
import { expressX, expressXClient } from '../src/index.mjs'
|
|
12
12
|
|
|
13
|
+
const prisma = new PrismaClient({
|
|
14
|
+
datasources: {
|
|
15
|
+
db: {
|
|
16
|
+
url: "file:./dev.db",
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
})
|
|
13
20
|
|
|
14
21
|
// `app` is a regular express application, enhanced with services and real-time features
|
|
15
|
-
const app = expressX()
|
|
22
|
+
const app = expressX(prisma)
|
|
16
23
|
|
|
17
24
|
|
|
18
25
|
|
package/src/client.mjs
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { v4 } from 'uuid'
|
|
3
|
-
|
|
4
|
-
export function expressXClient(socket, options={}) {
|
|
5
|
-
if (options.debug === undefined) options.debug = false
|
|
6
|
-
|
|
7
|
-
const waitingPromisesByUid = {}
|
|
8
|
-
const action2service2handlers = {}
|
|
9
|
-
let onConnectionCallback = null
|
|
10
|
-
let onDisconnectionCallback = null
|
|
11
|
-
|
|
12
|
-
const setConnectionCallback = (callback) => {
|
|
13
|
-
onConnectionCallback = callback
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const setDisconnectionCallback = (callback) => {
|
|
17
|
-
onDisconnectionCallback = callback
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// on connection
|
|
21
|
-
socket.on("connected", async (connectionId) => {
|
|
22
|
-
if (options.debug) console.log('connected', connectionId)
|
|
23
|
-
if (onConnectionCallback) onConnectionCallback(connectionId)
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
// on receiving response from service request
|
|
27
|
-
socket.on('client-response', ({ uid, error, result }) => {
|
|
28
|
-
if (options.debug) console.log('client-response', uid, error, result)
|
|
29
|
-
if (!waitingPromisesByUid[uid]) return // may not exist because a timeout removed it
|
|
30
|
-
const [resolve, reject] = waitingPromisesByUid[uid]
|
|
31
|
-
if (error) {
|
|
32
|
-
reject(error)
|
|
33
|
-
} else {
|
|
34
|
-
resolve(result)
|
|
35
|
-
}
|
|
36
|
-
delete waitingPromisesByUid[uid]
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
// on receiving events from pub/sub
|
|
40
|
-
socket.on('service-event', ({ name, action, result }) => {
|
|
41
|
-
if (!action2service2handlers[action]) action2service2handlers[action] = {}
|
|
42
|
-
const serviceHandlers = action2service2handlers[action]
|
|
43
|
-
const handler = serviceHandlers[name]
|
|
44
|
-
if (handler) handler(result)
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
async function serviceMethodRequest(name, action, ...args) {
|
|
48
|
-
const uid = v4()
|
|
49
|
-
// create a promise which will resolve or reject by an event 'client-response'
|
|
50
|
-
const promise = new Promise((resolve, reject) => {
|
|
51
|
-
waitingPromisesByUid[uid] = [resolve, reject]
|
|
52
|
-
// a 5s timeout may also reject the promise
|
|
53
|
-
setTimeout(() => {
|
|
54
|
-
delete waitingPromisesByUid[uid]
|
|
55
|
-
reject(`Error: timeout on service '${name}', action '${action}', args: ${args}`)
|
|
56
|
-
}, 5000)
|
|
57
|
-
})
|
|
58
|
-
// send request to server through websocket
|
|
59
|
-
socket.emit('client-request', {
|
|
60
|
-
uid,
|
|
61
|
-
name,
|
|
62
|
-
action,
|
|
63
|
-
args,
|
|
64
|
-
})
|
|
65
|
-
return promise
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function service(name) {
|
|
69
|
-
const service = {
|
|
70
|
-
// associate a handler to a pub/sub event for this service
|
|
71
|
-
on: (action, handler) => {
|
|
72
|
-
if (!action2service2handlers[action]) action2service2handlers[action] = {}
|
|
73
|
-
const serviceHandlers = action2service2handlers[action]
|
|
74
|
-
serviceHandlers[name] = handler
|
|
75
|
-
},
|
|
76
|
-
}
|
|
77
|
-
// use a Proxy to allow for any method name for a service
|
|
78
|
-
const handler = {
|
|
79
|
-
get(service, action) {
|
|
80
|
-
if (!(action in service)) {
|
|
81
|
-
// newly used property `action`: define it as a service method request function
|
|
82
|
-
service[action] = (...args) => serviceMethodRequest(name, action, ...args)
|
|
83
|
-
}
|
|
84
|
-
return service[action]
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return new Proxy(service, handler)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return {
|
|
91
|
-
setConnectionCallback,
|
|
92
|
-
setDisconnectionCallback,
|
|
93
|
-
service,
|
|
94
|
-
}
|
|
95
|
-
}
|