@jcbuisson/express-x 1.4.0 → 1.4.2

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.4.0",
3
+ "version": "1.4.2",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "src/index.mjs",
package/src/server.mjs CHANGED
@@ -14,9 +14,16 @@ export function expressX(prisma, options = {}) {
14
14
  if (options.ws === undefined) options.ws = { ws_prefix: "expressx" }
15
15
 
16
16
  const services = {}
17
- const connections = {}
18
17
 
19
- let lastConnectionId = 1
18
+ app.connections = {}
19
+ let lastConnectionId = options.initialConnectionId || 1
20
+
21
+ app.printCnx = (label) => {
22
+ console.log(label)
23
+ for (const id in app.connections) {
24
+ console.log(`CNX ${id}, data ${JSON.stringify(app.connections[id].data)}`)
25
+ }
26
+ }
20
27
 
21
28
  // logging function - a winston logger must be configured first
22
29
  app.log = (severity, message) => {
@@ -62,20 +69,21 @@ export function expressX(prisma, options = {}) {
62
69
  const beforeMethodHooks = service?.hooks?.before && service.hooks.before[methodName] || []
63
70
  const beforeAllHooks = service?.hooks?.before?.all || []
64
71
  for (const hook of [...beforeMethodHooks, ...beforeAllHooks]) {
65
- context = await hook({ ...context, args })
72
+ await hook(context)
66
73
  }
67
74
 
68
75
  // call method
69
76
  const result = await method(...context.args)
70
- app.log('debug', 'result ' + JSON.stringify(result))
77
+ // put result into context
78
+ context.result = result
71
79
 
72
80
  // call 'after' hooks
73
81
  const afterMethodHooks = service?.hooks?.after && service.hooks.after[methodName] || []
74
82
  const afterAllHooks = service?.hooks?.after?.all || []
75
83
  for (const hook of [...afterMethodHooks, ...afterAllHooks]) {
76
- context = await hook({ ...context, result })
84
+ await hook(context)
77
85
  }
78
- return result
86
+ return context.result
79
87
  }
80
88
 
81
89
  // hooked version of method: `create`, etc., to be called from backend with no context
@@ -117,7 +125,8 @@ export function expressX(prisma, options = {}) {
117
125
  async function addHttpRest(path, service) {
118
126
  const context = {
119
127
  app,
120
- http: { name: service.name }
128
+ transport: 'http',
129
+ params: { name: service.name }
121
130
  }
122
131
 
123
132
  // introspect schema and return a map: field name => prisma type
@@ -133,7 +142,7 @@ export function expressX(prisma, options = {}) {
133
142
 
134
143
  app.post(path, async (req, res) => {
135
144
  app.log('verbose', `http request POST ${req.url}`)
136
- context.http.req = req
145
+ context.params.req = req
137
146
  try {
138
147
  const value = await service.__create(context, { data: req.body })
139
148
  publish(service, 'create', value)
@@ -146,7 +155,7 @@ export function expressX(prisma, options = {}) {
146
155
 
147
156
  app.get(path, async (req, res) => {
148
157
  app.log('verbose', `http request GET ${req.url}`)
149
- context.http.req = req
158
+ context.params.req = req
150
159
  const query = { ...req.query }
151
160
  try {
152
161
  // the values in `req.query` are all strings, but Prisma need proper types
@@ -182,7 +191,7 @@ export function expressX(prisma, options = {}) {
182
191
 
183
192
  app.get(`${path}/:id`, async (req, res) => {
184
193
  app.log('verbose', `http request GET ${req.url}`)
185
- context.http.req = req
194
+ context.params.req = req
186
195
  try {
187
196
  const value = await service.__findUnique(context, {
188
197
  where: {
@@ -199,7 +208,7 @@ export function expressX(prisma, options = {}) {
199
208
 
200
209
  app.patch(`${path}/:id`, async (req, res) => {
201
210
  app.log('verbose', `http request PATCH ${req.url}`)
202
- context.http.req = req
211
+ context.params.req = req
203
212
  try {
204
213
  const value = await service.__update(context, {
205
214
  where: {
@@ -217,7 +226,7 @@ export function expressX(prisma, options = {}) {
217
226
 
218
227
  app.delete(`${path}/:id`, async (req, res) => {
219
228
  app.log('verbose', `http request DELETE ${req.url}`)
220
- context.http.req = req
229
+ context.params.req = req
221
230
  try {
222
231
  const value = await service.__delete(context, {
223
232
  where: {
@@ -252,11 +261,13 @@ export function expressX(prisma, options = {}) {
252
261
  id: lastConnectionId++,
253
262
  socket,
254
263
  channelNames: new Set(),
255
- data: {},
264
+ data: {
265
+ a: 123
266
+ },
256
267
  }
257
268
  // store connection in cache
258
- connections[connection.id] = connection
259
- app.log('verbose', `active connection ids: ${Object.keys(connections)}`)
269
+ app.connections[connection.id] = connection
270
+ app.log('verbose', `Connection ids: ${Object.keys(app.connections)}`)
260
271
 
261
272
  // emit 'connection' event for app (expressjs extends EventEmitter)
262
273
  app.emit('connection', connection)
@@ -267,15 +278,22 @@ export function expressX(prisma, options = {}) {
267
278
  socket.on('disconnect', () => {
268
279
  app.log('verbose', `Client disconnected ${connection.id}`)
269
280
 
270
- // TODO: wait for 1mn before cleaning (a reconnection will use this data)
271
- // delete connections[connection.id]
281
+ // remove connection record after 1mn (leaves time in case of connection transfer)
282
+ setTimeout(() => {
283
+ app.log('verbose', `Delete connection ${connection.id}`)
284
+ delete app.connections[connection.id]
285
+ }, 60 * 1000)
272
286
  })
273
287
 
274
- // handle connection data transfer caused by a disconnection (page reload, network issue, etc.)
288
+
289
+ // handle connection data transfer caused by a disconnection/reconnection (page reload, network issue, etc.)
275
290
  socket.on('cnx-transfer', async ({ from, to }) => {
276
291
  app.log('verbose', `cnx-transfer from ${from} to ${to}`)
277
- connections[to] = connections[from]
278
- delete connections[from]
292
+ if (!app.connections[from]) return
293
+ app.connections[to] = app.connections[from]
294
+ app.connections[to].socket = socket
295
+ delete app.connections[from]
296
+ // app.printCnx('AFTER TRANSFER')
279
297
  })
280
298
 
281
299
 
@@ -292,11 +310,13 @@ export function expressX(prisma, options = {}) {
292
310
  if (serviceMethod) {
293
311
  const context = {
294
312
  app,
295
- ws: { connection, name, action, args },
313
+ transport: 'ws',
314
+ params: { connection, name, action, args },
296
315
  }
297
316
 
298
317
  try {
299
318
  const result = await serviceMethod(context, ...args)
319
+ app.log('verbose', `client-response ${uid} ${JSON.stringify(result)}`)
300
320
  socket.emit('client-response', {
301
321
  uid,
302
322
  result,
@@ -304,7 +324,7 @@ export function expressX(prisma, options = {}) {
304
324
  // pub/sub: send event on associated channels
305
325
  publish(service, action, result)
306
326
  } catch(err) {
307
- app.log('error', err)
327
+ app.log('error', err.toString())
308
328
  io.emit('client-response', {
309
329
  uid,
310
330
  error: err.toString(),
@@ -340,7 +360,7 @@ export function expressX(prisma, options = {}) {
340
360
  app.log('verbose', `publish channels ${service.name} ${action} ${channelNames}`)
341
361
  for (const channelName of channelNames) {
342
362
  app.log('verbose', `service-event ${service.name} ${action} ${channelName}`)
343
- const connectionList = Object.values(connections).filter(cnx => cnx.channelNames.has(channelName))
363
+ const connectionList = Object.values(app.connections).filter(cnx => cnx.channelNames.has(channelName))
344
364
  for (const connection of connectionList) {
345
365
  app.log('verbose', `emit to ${connection.id} ${service.name} ${action} ${result}`)
346
366
  connection.socket.emit('service-event', {
@@ -8,7 +8,7 @@ import { PrismaClient } from '@prisma/client'
8
8
  import { describe, it, before, after, beforeEach, afterEach } from 'node:test'
9
9
  import { strict as assert } from 'node:assert'
10
10
 
11
- import { expressX, expressXClient } from '../src/index.mjs'
11
+ import { expressX } from '../src/index.mjs'
12
12
 
13
13
  const prisma = new PrismaClient({
14
14
  datasources: {
@@ -144,41 +144,3 @@ describe('HTTP/REST API', () => {
144
144
  app.server.close()
145
145
  })
146
146
  })
147
-
148
-
149
- // test compatibility with client API
150
- describe('Client API', () => {
151
-
152
- let clientApp, socket
153
-
154
- before(async () => {
155
- await new Promise((resolve) => {
156
- app.server.listen(8008, () => {
157
- console.log(`App listening at http://localhost:8008`)
158
- resolve()
159
- })
160
- })
161
-
162
- socket = io('http://localhost:8008', { transports: ["websocket"] })
163
- clientApp = expressXClient(socket)
164
- })
165
-
166
- after(async () => {
167
- app.server.close()
168
- })
169
-
170
- it("can create a user", async () => {
171
- const user = await clientApp.service('User').create({
172
- data: {
173
- name: "chris",
174
- email: 'chris@mail.fr'
175
- },
176
- })
177
- assert(user.name === 'chris')
178
- })
179
-
180
- after(async () => {
181
- await socket.close()
182
- await app.server.close()
183
- })
184
- })