@jcbuisson/express-x 1.4.0 → 1.4.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/package.json +1 -1
- package/src/server.mjs +43 -21
- package/test/index.test.js +1 -39
package/package.json
CHANGED
package/src/server.mjs
CHANGED
|
@@ -14,10 +14,17 @@ 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
|
|
|
18
|
+
app.connections = {}
|
|
19
19
|
let lastConnectionId = 1
|
|
20
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
|
+
}
|
|
27
|
+
|
|
21
28
|
// logging function - a winston logger must be configured first
|
|
22
29
|
app.log = (severity, message) => {
|
|
23
30
|
const logger = app.get('logger')
|
|
@@ -62,18 +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(
|
|
72
|
+
// context = await hook(context)
|
|
73
|
+
await hook(context)
|
|
66
74
|
}
|
|
67
75
|
|
|
68
76
|
// call method
|
|
69
77
|
const result = await method(...context.args)
|
|
70
|
-
|
|
78
|
+
// put result into context
|
|
79
|
+
context.result = result
|
|
71
80
|
|
|
72
81
|
// call 'after' hooks
|
|
73
82
|
const afterMethodHooks = service?.hooks?.after && service.hooks.after[methodName] || []
|
|
74
83
|
const afterAllHooks = service?.hooks?.after?.all || []
|
|
75
84
|
for (const hook of [...afterMethodHooks, ...afterAllHooks]) {
|
|
76
|
-
context = await hook(
|
|
85
|
+
// context = await hook(context)
|
|
86
|
+
await hook(context)
|
|
77
87
|
}
|
|
78
88
|
return result
|
|
79
89
|
}
|
|
@@ -117,7 +127,8 @@ export function expressX(prisma, options = {}) {
|
|
|
117
127
|
async function addHttpRest(path, service) {
|
|
118
128
|
const context = {
|
|
119
129
|
app,
|
|
120
|
-
|
|
130
|
+
transport: 'http',
|
|
131
|
+
params: { name: service.name }
|
|
121
132
|
}
|
|
122
133
|
|
|
123
134
|
// introspect schema and return a map: field name => prisma type
|
|
@@ -133,7 +144,7 @@ export function expressX(prisma, options = {}) {
|
|
|
133
144
|
|
|
134
145
|
app.post(path, async (req, res) => {
|
|
135
146
|
app.log('verbose', `http request POST ${req.url}`)
|
|
136
|
-
context.
|
|
147
|
+
context.params.req = req
|
|
137
148
|
try {
|
|
138
149
|
const value = await service.__create(context, { data: req.body })
|
|
139
150
|
publish(service, 'create', value)
|
|
@@ -146,7 +157,7 @@ export function expressX(prisma, options = {}) {
|
|
|
146
157
|
|
|
147
158
|
app.get(path, async (req, res) => {
|
|
148
159
|
app.log('verbose', `http request GET ${req.url}`)
|
|
149
|
-
context.
|
|
160
|
+
context.params.req = req
|
|
150
161
|
const query = { ...req.query }
|
|
151
162
|
try {
|
|
152
163
|
// the values in `req.query` are all strings, but Prisma need proper types
|
|
@@ -182,7 +193,7 @@ export function expressX(prisma, options = {}) {
|
|
|
182
193
|
|
|
183
194
|
app.get(`${path}/:id`, async (req, res) => {
|
|
184
195
|
app.log('verbose', `http request GET ${req.url}`)
|
|
185
|
-
context.
|
|
196
|
+
context.params.req = req
|
|
186
197
|
try {
|
|
187
198
|
const value = await service.__findUnique(context, {
|
|
188
199
|
where: {
|
|
@@ -199,7 +210,7 @@ export function expressX(prisma, options = {}) {
|
|
|
199
210
|
|
|
200
211
|
app.patch(`${path}/:id`, async (req, res) => {
|
|
201
212
|
app.log('verbose', `http request PATCH ${req.url}`)
|
|
202
|
-
context.
|
|
213
|
+
context.params.req = req
|
|
203
214
|
try {
|
|
204
215
|
const value = await service.__update(context, {
|
|
205
216
|
where: {
|
|
@@ -217,7 +228,7 @@ export function expressX(prisma, options = {}) {
|
|
|
217
228
|
|
|
218
229
|
app.delete(`${path}/:id`, async (req, res) => {
|
|
219
230
|
app.log('verbose', `http request DELETE ${req.url}`)
|
|
220
|
-
context.
|
|
231
|
+
context.params.req = req
|
|
221
232
|
try {
|
|
222
233
|
const value = await service.__delete(context, {
|
|
223
234
|
where: {
|
|
@@ -252,11 +263,13 @@ export function expressX(prisma, options = {}) {
|
|
|
252
263
|
id: lastConnectionId++,
|
|
253
264
|
socket,
|
|
254
265
|
channelNames: new Set(),
|
|
255
|
-
data: {
|
|
266
|
+
data: {
|
|
267
|
+
a: 123
|
|
268
|
+
},
|
|
256
269
|
}
|
|
257
270
|
// store connection in cache
|
|
258
|
-
connections[connection.id] = connection
|
|
259
|
-
app.log('verbose', `
|
|
271
|
+
app.connections[connection.id] = connection
|
|
272
|
+
app.log('verbose', `Connection ids: ${Object.keys(app.connections)}`)
|
|
260
273
|
|
|
261
274
|
// emit 'connection' event for app (expressjs extends EventEmitter)
|
|
262
275
|
app.emit('connection', connection)
|
|
@@ -267,15 +280,22 @@ export function expressX(prisma, options = {}) {
|
|
|
267
280
|
socket.on('disconnect', () => {
|
|
268
281
|
app.log('verbose', `Client disconnected ${connection.id}`)
|
|
269
282
|
|
|
270
|
-
//
|
|
271
|
-
|
|
283
|
+
// remove connection record after 1mn (leaves time in case of connection transfer)
|
|
284
|
+
setTimeout(() => {
|
|
285
|
+
app.log('verbose', `Delete connection ${connection.id}`)
|
|
286
|
+
delete app.connections[connection.id]
|
|
287
|
+
}, 60 * 1000)
|
|
272
288
|
})
|
|
273
289
|
|
|
274
|
-
|
|
290
|
+
|
|
291
|
+
// handle connection data transfer caused by a disconnection/reconnection (page reload, network issue, etc.)
|
|
275
292
|
socket.on('cnx-transfer', async ({ from, to }) => {
|
|
276
293
|
app.log('verbose', `cnx-transfer from ${from} to ${to}`)
|
|
277
|
-
|
|
278
|
-
|
|
294
|
+
if (!app.connections[from]) return
|
|
295
|
+
app.connections[to] = app.connections[from]
|
|
296
|
+
app.connections[to].socket = socket
|
|
297
|
+
delete app.connections[from]
|
|
298
|
+
// app.printCnx('AFTER TRANSFER')
|
|
279
299
|
})
|
|
280
300
|
|
|
281
301
|
|
|
@@ -292,11 +312,13 @@ export function expressX(prisma, options = {}) {
|
|
|
292
312
|
if (serviceMethod) {
|
|
293
313
|
const context = {
|
|
294
314
|
app,
|
|
295
|
-
|
|
315
|
+
transport: 'ws',
|
|
316
|
+
params: { connection, name, action, args },
|
|
296
317
|
}
|
|
297
318
|
|
|
298
319
|
try {
|
|
299
320
|
const result = await serviceMethod(context, ...args)
|
|
321
|
+
app.log('verbose', `client-response ${uid} ${JSON.stringify(result)}`)
|
|
300
322
|
socket.emit('client-response', {
|
|
301
323
|
uid,
|
|
302
324
|
result,
|
|
@@ -304,7 +326,7 @@ export function expressX(prisma, options = {}) {
|
|
|
304
326
|
// pub/sub: send event on associated channels
|
|
305
327
|
publish(service, action, result)
|
|
306
328
|
} catch(err) {
|
|
307
|
-
app.log('error', err)
|
|
329
|
+
app.log('error', err.toString())
|
|
308
330
|
io.emit('client-response', {
|
|
309
331
|
uid,
|
|
310
332
|
error: err.toString(),
|
|
@@ -340,7 +362,7 @@ export function expressX(prisma, options = {}) {
|
|
|
340
362
|
app.log('verbose', `publish channels ${service.name} ${action} ${channelNames}`)
|
|
341
363
|
for (const channelName of channelNames) {
|
|
342
364
|
app.log('verbose', `service-event ${service.name} ${action} ${channelName}`)
|
|
343
|
-
const connectionList = Object.values(connections).filter(cnx => cnx.channelNames.has(channelName))
|
|
365
|
+
const connectionList = Object.values(app.connections).filter(cnx => cnx.channelNames.has(channelName))
|
|
344
366
|
for (const connection of connectionList) {
|
|
345
367
|
app.log('verbose', `emit to ${connection.id} ${service.name} ${action} ${result}`)
|
|
346
368
|
connection.socket.emit('service-event', {
|
package/test/index.test.js
CHANGED
|
@@ -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
|
|
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
|
-
})
|