@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jcbuisson/express-x",
3
- "version": "1.3.7",
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
@@ -1,11 +1,9 @@
1
1
 
2
2
  import { expressX } from './server.mjs'
3
- import { expressXClient } from './client.mjs'
4
3
  import { hashPassword, protect, setSessionJWT, } from './common-hooks.mjs'
5
4
 
6
5
  export {
7
6
  expressX,
8
- expressXClient,
9
7
 
10
8
  hashPassword,
11
9
  protect,
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 connections ${Object.keys(connections)}`)
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
- delete connections[connection.id]
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
 
@@ -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
- }