jinaga-server 3.0.1 → 3.1.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/dist/http/router.js +25 -8
- package/dist/http/router.js.map +1 -1
- package/dist/http/serializer.d.ts +11 -0
- package/dist/http/serializer.js +68 -0
- package/dist/http/serializer.js.map +1 -0
- package/http/sans-auth/Load json.http +64 -0
- package/integration-test/jinaga-test/Dockerfile +1 -1
- package/integration-test/jinaga-test/package-lock.json +143 -55
- package/integration-test/jinaga-test/package.json +2 -2
- package/package.json +3 -3
- package/replicator/package-lock.json +149 -47
- package/replicator/package.json +1 -1
- package/src/http/router.ts +35 -10
- package/src/http/serializer.ts +81 -0
- package/test/http/serializerSpec.ts +140 -0
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@stablelib/base64": "^1.0.1",
|
|
17
|
-
"express": "^4.
|
|
17
|
+
"express": "^4.19.2",
|
|
18
18
|
"jest": "^29.7.0",
|
|
19
19
|
"jest-compact-reporter": "^1.2.9",
|
|
20
|
-
"jinaga": "^6.0.
|
|
20
|
+
"jinaga": "^6.0.1",
|
|
21
21
|
"node-forge": "^1.3.0",
|
|
22
22
|
"pg": "^8.11.3"
|
|
23
23
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jinaga-server",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "Data management for web and mobile applications.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"typescript": "^4.7.2"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"express": "^4.
|
|
51
|
-
"jinaga": "^6.0.
|
|
50
|
+
"express": "^4.19.2",
|
|
51
|
+
"jinaga": "^6.0.1",
|
|
52
52
|
"node-forge": "^1.3.1",
|
|
53
53
|
"pg": "^8.11.3"
|
|
54
54
|
}
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"cors": "^2.8.5",
|
|
13
|
-
"express": "^4.18.
|
|
14
|
-
"pg": "
|
|
13
|
+
"express": "^4.18.3",
|
|
14
|
+
"pg": "8.11.3"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"@types/cors": "^2.8.12",
|
|
@@ -122,12 +122,12 @@
|
|
|
122
122
|
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
|
|
123
123
|
},
|
|
124
124
|
"node_modules/body-parser": {
|
|
125
|
-
"version": "1.20.
|
|
126
|
-
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.
|
|
127
|
-
"integrity": "sha512-
|
|
125
|
+
"version": "1.20.2",
|
|
126
|
+
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
|
|
127
|
+
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
|
|
128
128
|
"dependencies": {
|
|
129
129
|
"bytes": "3.1.2",
|
|
130
|
-
"content-type": "~1.0.
|
|
130
|
+
"content-type": "~1.0.5",
|
|
131
131
|
"debug": "2.6.9",
|
|
132
132
|
"depd": "2.0.0",
|
|
133
133
|
"destroy": "1.2.0",
|
|
@@ -135,7 +135,7 @@
|
|
|
135
135
|
"iconv-lite": "0.4.24",
|
|
136
136
|
"on-finished": "2.4.1",
|
|
137
137
|
"qs": "6.11.0",
|
|
138
|
-
"raw-body": "2.5.
|
|
138
|
+
"raw-body": "2.5.2",
|
|
139
139
|
"type-is": "~1.6.18",
|
|
140
140
|
"unpipe": "1.0.0"
|
|
141
141
|
},
|
|
@@ -161,12 +161,18 @@
|
|
|
161
161
|
}
|
|
162
162
|
},
|
|
163
163
|
"node_modules/call-bind": {
|
|
164
|
-
"version": "1.0.
|
|
165
|
-
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.
|
|
166
|
-
"integrity": "sha512-
|
|
167
|
-
"dependencies": {
|
|
168
|
-
"
|
|
169
|
-
"
|
|
164
|
+
"version": "1.0.7",
|
|
165
|
+
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
|
|
166
|
+
"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
|
|
167
|
+
"dependencies": {
|
|
168
|
+
"es-define-property": "^1.0.0",
|
|
169
|
+
"es-errors": "^1.3.0",
|
|
170
|
+
"function-bind": "^1.1.2",
|
|
171
|
+
"get-intrinsic": "^1.2.4",
|
|
172
|
+
"set-function-length": "^1.2.1"
|
|
173
|
+
},
|
|
174
|
+
"engines": {
|
|
175
|
+
"node": ">= 0.4"
|
|
170
176
|
},
|
|
171
177
|
"funding": {
|
|
172
178
|
"url": "https://github.com/sponsors/ljharb"
|
|
@@ -184,9 +190,9 @@
|
|
|
184
190
|
}
|
|
185
191
|
},
|
|
186
192
|
"node_modules/content-type": {
|
|
187
|
-
"version": "1.0.
|
|
188
|
-
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.
|
|
189
|
-
"integrity": "sha512-
|
|
193
|
+
"version": "1.0.5",
|
|
194
|
+
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
|
|
195
|
+
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
|
|
190
196
|
"engines": {
|
|
191
197
|
"node": ">= 0.6"
|
|
192
198
|
}
|
|
@@ -224,6 +230,22 @@
|
|
|
224
230
|
"ms": "2.0.0"
|
|
225
231
|
}
|
|
226
232
|
},
|
|
233
|
+
"node_modules/define-data-property": {
|
|
234
|
+
"version": "1.1.4",
|
|
235
|
+
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
|
|
236
|
+
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
|
|
237
|
+
"dependencies": {
|
|
238
|
+
"es-define-property": "^1.0.0",
|
|
239
|
+
"es-errors": "^1.3.0",
|
|
240
|
+
"gopd": "^1.0.1"
|
|
241
|
+
},
|
|
242
|
+
"engines": {
|
|
243
|
+
"node": ">= 0.4"
|
|
244
|
+
},
|
|
245
|
+
"funding": {
|
|
246
|
+
"url": "https://github.com/sponsors/ljharb"
|
|
247
|
+
}
|
|
248
|
+
},
|
|
227
249
|
"node_modules/depd": {
|
|
228
250
|
"version": "2.0.0",
|
|
229
251
|
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
|
@@ -254,6 +276,25 @@
|
|
|
254
276
|
"node": ">= 0.8"
|
|
255
277
|
}
|
|
256
278
|
},
|
|
279
|
+
"node_modules/es-define-property": {
|
|
280
|
+
"version": "1.0.0",
|
|
281
|
+
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
|
|
282
|
+
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
|
|
283
|
+
"dependencies": {
|
|
284
|
+
"get-intrinsic": "^1.2.4"
|
|
285
|
+
},
|
|
286
|
+
"engines": {
|
|
287
|
+
"node": ">= 0.4"
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
"node_modules/es-errors": {
|
|
291
|
+
"version": "1.3.0",
|
|
292
|
+
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
|
293
|
+
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
|
294
|
+
"engines": {
|
|
295
|
+
"node": ">= 0.4"
|
|
296
|
+
}
|
|
297
|
+
},
|
|
257
298
|
"node_modules/escape-html": {
|
|
258
299
|
"version": "1.0.3",
|
|
259
300
|
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
|
@@ -268,13 +309,13 @@
|
|
|
268
309
|
}
|
|
269
310
|
},
|
|
270
311
|
"node_modules/express": {
|
|
271
|
-
"version": "4.18.
|
|
272
|
-
"resolved": "https://registry.npmjs.org/express/-/express-4.18.
|
|
273
|
-
"integrity": "sha512-
|
|
312
|
+
"version": "4.18.3",
|
|
313
|
+
"resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz",
|
|
314
|
+
"integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==",
|
|
274
315
|
"dependencies": {
|
|
275
316
|
"accepts": "~1.3.8",
|
|
276
317
|
"array-flatten": "1.1.1",
|
|
277
|
-
"body-parser": "1.20.
|
|
318
|
+
"body-parser": "1.20.2",
|
|
278
319
|
"content-disposition": "0.5.4",
|
|
279
320
|
"content-type": "~1.0.4",
|
|
280
321
|
"cookie": "0.5.0",
|
|
@@ -342,32 +383,62 @@
|
|
|
342
383
|
}
|
|
343
384
|
},
|
|
344
385
|
"node_modules/function-bind": {
|
|
345
|
-
"version": "1.1.
|
|
346
|
-
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.
|
|
347
|
-
"integrity": "sha512-
|
|
386
|
+
"version": "1.1.2",
|
|
387
|
+
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
|
388
|
+
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
|
389
|
+
"funding": {
|
|
390
|
+
"url": "https://github.com/sponsors/ljharb"
|
|
391
|
+
}
|
|
348
392
|
},
|
|
349
393
|
"node_modules/get-intrinsic": {
|
|
350
|
-
"version": "1.2.
|
|
351
|
-
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.
|
|
352
|
-
"integrity": "sha512-
|
|
394
|
+
"version": "1.2.4",
|
|
395
|
+
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
|
|
396
|
+
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
|
|
397
|
+
"dependencies": {
|
|
398
|
+
"es-errors": "^1.3.0",
|
|
399
|
+
"function-bind": "^1.1.2",
|
|
400
|
+
"has-proto": "^1.0.1",
|
|
401
|
+
"has-symbols": "^1.0.3",
|
|
402
|
+
"hasown": "^2.0.0"
|
|
403
|
+
},
|
|
404
|
+
"engines": {
|
|
405
|
+
"node": ">= 0.4"
|
|
406
|
+
},
|
|
407
|
+
"funding": {
|
|
408
|
+
"url": "https://github.com/sponsors/ljharb"
|
|
409
|
+
}
|
|
410
|
+
},
|
|
411
|
+
"node_modules/gopd": {
|
|
412
|
+
"version": "1.0.1",
|
|
413
|
+
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
|
|
414
|
+
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
|
|
353
415
|
"dependencies": {
|
|
354
|
-
"
|
|
355
|
-
"has": "^1.0.3",
|
|
356
|
-
"has-symbols": "^1.0.3"
|
|
416
|
+
"get-intrinsic": "^1.1.3"
|
|
357
417
|
},
|
|
358
418
|
"funding": {
|
|
359
419
|
"url": "https://github.com/sponsors/ljharb"
|
|
360
420
|
}
|
|
361
421
|
},
|
|
362
|
-
"node_modules/has": {
|
|
363
|
-
"version": "1.0.
|
|
364
|
-
"resolved": "https://registry.npmjs.org/has/-/has-1.0.
|
|
365
|
-
"integrity": "sha512-
|
|
422
|
+
"node_modules/has-property-descriptors": {
|
|
423
|
+
"version": "1.0.2",
|
|
424
|
+
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
|
425
|
+
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
|
|
366
426
|
"dependencies": {
|
|
367
|
-
"
|
|
427
|
+
"es-define-property": "^1.0.0"
|
|
368
428
|
},
|
|
429
|
+
"funding": {
|
|
430
|
+
"url": "https://github.com/sponsors/ljharb"
|
|
431
|
+
}
|
|
432
|
+
},
|
|
433
|
+
"node_modules/has-proto": {
|
|
434
|
+
"version": "1.0.3",
|
|
435
|
+
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
|
|
436
|
+
"integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
|
|
369
437
|
"engines": {
|
|
370
|
-
"node": ">= 0.4
|
|
438
|
+
"node": ">= 0.4"
|
|
439
|
+
},
|
|
440
|
+
"funding": {
|
|
441
|
+
"url": "https://github.com/sponsors/ljharb"
|
|
371
442
|
}
|
|
372
443
|
},
|
|
373
444
|
"node_modules/has-symbols": {
|
|
@@ -381,6 +452,17 @@
|
|
|
381
452
|
"url": "https://github.com/sponsors/ljharb"
|
|
382
453
|
}
|
|
383
454
|
},
|
|
455
|
+
"node_modules/hasown": {
|
|
456
|
+
"version": "2.0.2",
|
|
457
|
+
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
|
458
|
+
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
|
459
|
+
"dependencies": {
|
|
460
|
+
"function-bind": "^1.1.2"
|
|
461
|
+
},
|
|
462
|
+
"engines": {
|
|
463
|
+
"node": ">= 0.4"
|
|
464
|
+
}
|
|
465
|
+
},
|
|
384
466
|
"node_modules/http-errors": {
|
|
385
467
|
"version": "2.0.0",
|
|
386
468
|
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
|
|
@@ -493,9 +575,9 @@
|
|
|
493
575
|
}
|
|
494
576
|
},
|
|
495
577
|
"node_modules/object-inspect": {
|
|
496
|
-
"version": "1.
|
|
497
|
-
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.
|
|
498
|
-
"integrity": "sha512-
|
|
578
|
+
"version": "1.13.1",
|
|
579
|
+
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
|
|
580
|
+
"integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
|
|
499
581
|
"funding": {
|
|
500
582
|
"url": "https://github.com/sponsors/ljharb"
|
|
501
583
|
}
|
|
@@ -682,9 +764,9 @@
|
|
|
682
764
|
}
|
|
683
765
|
},
|
|
684
766
|
"node_modules/raw-body": {
|
|
685
|
-
"version": "2.5.
|
|
686
|
-
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.
|
|
687
|
-
"integrity": "sha512-
|
|
767
|
+
"version": "2.5.2",
|
|
768
|
+
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
|
|
769
|
+
"integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
|
|
688
770
|
"dependencies": {
|
|
689
771
|
"bytes": "3.1.2",
|
|
690
772
|
"http-errors": "2.0.0",
|
|
@@ -761,19 +843,39 @@
|
|
|
761
843
|
"node": ">= 0.8.0"
|
|
762
844
|
}
|
|
763
845
|
},
|
|
846
|
+
"node_modules/set-function-length": {
|
|
847
|
+
"version": "1.2.2",
|
|
848
|
+
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
|
|
849
|
+
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
|
|
850
|
+
"dependencies": {
|
|
851
|
+
"define-data-property": "^1.1.4",
|
|
852
|
+
"es-errors": "^1.3.0",
|
|
853
|
+
"function-bind": "^1.1.2",
|
|
854
|
+
"get-intrinsic": "^1.2.4",
|
|
855
|
+
"gopd": "^1.0.1",
|
|
856
|
+
"has-property-descriptors": "^1.0.2"
|
|
857
|
+
},
|
|
858
|
+
"engines": {
|
|
859
|
+
"node": ">= 0.4"
|
|
860
|
+
}
|
|
861
|
+
},
|
|
764
862
|
"node_modules/setprototypeof": {
|
|
765
863
|
"version": "1.2.0",
|
|
766
864
|
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
|
767
865
|
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
|
|
768
866
|
},
|
|
769
867
|
"node_modules/side-channel": {
|
|
770
|
-
"version": "1.0.
|
|
771
|
-
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.
|
|
772
|
-
"integrity": "sha512-
|
|
868
|
+
"version": "1.0.6",
|
|
869
|
+
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
|
|
870
|
+
"integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
|
|
773
871
|
"dependencies": {
|
|
774
|
-
"call-bind": "^1.0.
|
|
775
|
-
"
|
|
776
|
-
"
|
|
872
|
+
"call-bind": "^1.0.7",
|
|
873
|
+
"es-errors": "^1.3.0",
|
|
874
|
+
"get-intrinsic": "^1.2.4",
|
|
875
|
+
"object-inspect": "^1.13.1"
|
|
876
|
+
},
|
|
877
|
+
"engines": {
|
|
878
|
+
"node": ">= 0.4"
|
|
777
879
|
},
|
|
778
880
|
"funding": {
|
|
779
881
|
"url": "https://github.com/sponsors/ljharb"
|
package/replicator/package.json
CHANGED
package/src/http/router.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { Handler, Router } from "express";
|
|
1
|
+
import { Handler, MediaType, Response, Router } from "express";
|
|
2
2
|
import {
|
|
3
3
|
Authorization,
|
|
4
4
|
Declaration,
|
|
5
|
+
FactEnvelope,
|
|
5
6
|
FactManager,
|
|
6
7
|
FactRecord,
|
|
7
8
|
FactReference,
|
|
@@ -29,6 +30,7 @@ import {
|
|
|
29
30
|
} from "jinaga";
|
|
30
31
|
|
|
31
32
|
import { Stream } from "./stream";
|
|
33
|
+
import { GraphSerializer } from "./serializer";
|
|
32
34
|
|
|
33
35
|
interface ParsedQs { [key: string]: undefined | string | string[] | ParsedQs | ParsedQs[] }
|
|
34
36
|
|
|
@@ -132,7 +134,8 @@ function getAuthenticate<U>(method: ((req: RequestUser, params?: { [key: string]
|
|
|
132
134
|
|
|
133
135
|
function post<T, U>(
|
|
134
136
|
parse: (input: any) => T,
|
|
135
|
-
method: (user: RequestUser, message: T, params?: { [key: string]: string }) => Promise<U
|
|
137
|
+
method: (user: RequestUser, message: T, params?: { [key: string]: string }) => Promise<U>,
|
|
138
|
+
output: (result: U, res: Response, accepts: (type: string) => string | false) => void
|
|
136
139
|
): Handler {
|
|
137
140
|
return (req, res, next) => {
|
|
138
141
|
const user = <RequestUser>req.user;
|
|
@@ -147,8 +150,7 @@ function post<T, U>(
|
|
|
147
150
|
next();
|
|
148
151
|
}
|
|
149
152
|
else {
|
|
150
|
-
res.type
|
|
151
|
-
res.send(JSON.stringify(response));
|
|
153
|
+
output(response, res, (type) => req.accepts(type));
|
|
152
154
|
next();
|
|
153
155
|
}
|
|
154
156
|
})
|
|
@@ -272,6 +274,29 @@ function serializeUserIdentity(user: RequestUser | null): UserIdentity | null {
|
|
|
272
274
|
};
|
|
273
275
|
}
|
|
274
276
|
|
|
277
|
+
function outputGraph(result: FactEnvelope[], res: Response, accepts: (type: string) => string | false) {
|
|
278
|
+
if (accepts("application/x-jinaga-graph-v1")) {
|
|
279
|
+
res.type("application/x-jinaga-graph-v1");
|
|
280
|
+
const serializer = new GraphSerializer(
|
|
281
|
+
(chunk: string) => res.write(chunk)
|
|
282
|
+
);
|
|
283
|
+
serializer.serialize(result);
|
|
284
|
+
res.end();
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
res.type("json");
|
|
288
|
+
const loadResponse: LoadResponse = {
|
|
289
|
+
facts: result.map(r => r.fact)
|
|
290
|
+
};
|
|
291
|
+
res.send(JSON.stringify(loadResponse));
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function outputFeeds(result: FeedsResponse, res: Response, accepts: (type: string) => string | false) {
|
|
296
|
+
res.type("json");
|
|
297
|
+
res.send(JSON.stringify(result));
|
|
298
|
+
}
|
|
299
|
+
|
|
275
300
|
export interface RequestUser {
|
|
276
301
|
provider: string;
|
|
277
302
|
id: string;
|
|
@@ -286,7 +311,8 @@ export class HttpRouter {
|
|
|
286
311
|
router.get('/login', getAuthenticate(user => this.login(user)));
|
|
287
312
|
router.post('/load', post(
|
|
288
313
|
parseLoadMessage,
|
|
289
|
-
(user, loadMessage) => this.load(user, loadMessage)
|
|
314
|
+
(user, loadMessage) => this.load(user, loadMessage),
|
|
315
|
+
outputGraph
|
|
290
316
|
));
|
|
291
317
|
router.post('/save', postCreate(
|
|
292
318
|
parseSaveMessage,
|
|
@@ -297,7 +323,8 @@ export class HttpRouter {
|
|
|
297
323
|
router.post('/write', postStringCreate((user, input: string) => this.write(user, input)));
|
|
298
324
|
router.post('/feeds', post(
|
|
299
325
|
parseString,
|
|
300
|
-
(user, input: string) => this.feeds(user, input)
|
|
326
|
+
(user, input: string, accepts) => this.feeds(user, input),
|
|
327
|
+
outputFeeds
|
|
301
328
|
));
|
|
302
329
|
router.get('/feeds/:hash', getOrStream<FeedResponse>(
|
|
303
330
|
(user, params, query) => this.feed(user, params, query),
|
|
@@ -317,13 +344,11 @@ export class HttpRouter {
|
|
|
317
344
|
};
|
|
318
345
|
}
|
|
319
346
|
|
|
320
|
-
private async load(user: RequestUser, loadMessage: LoadMessage): Promise<
|
|
347
|
+
private async load(user: RequestUser, loadMessage: LoadMessage): Promise<FactEnvelope[]> {
|
|
321
348
|
const userIdentity = serializeUserIdentity(user);
|
|
322
349
|
const result = await this.authorization.load(userIdentity, loadMessage.references);
|
|
323
350
|
const facts = result.map(r => r.fact);
|
|
324
|
-
return
|
|
325
|
-
facts
|
|
326
|
-
};
|
|
351
|
+
return result;
|
|
327
352
|
}
|
|
328
353
|
|
|
329
354
|
private async save(user: RequestUser | null, saveMessage: SaveMessage): Promise<void> {
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { FactEnvelope, FactReference, PredecessorCollection } from "jinaga";
|
|
2
|
+
|
|
3
|
+
type IndexPredecessorCollection = {
|
|
4
|
+
[role: string]: number | number[];
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export class GraphSerializer
|
|
8
|
+
{
|
|
9
|
+
private index = 0;
|
|
10
|
+
private indexByFactReference: { [key: string]: number } = {};
|
|
11
|
+
private publicKeys: string[] = [];
|
|
12
|
+
|
|
13
|
+
constructor(
|
|
14
|
+
private readonly write: (chunk: string) => void
|
|
15
|
+
) {}
|
|
16
|
+
|
|
17
|
+
serialize(result: FactEnvelope[]) {
|
|
18
|
+
// Write the facts
|
|
19
|
+
for (const fact of result) {
|
|
20
|
+
// Skip facts that have already been written
|
|
21
|
+
const key = fact.fact.type + ":" + fact.fact.hash;
|
|
22
|
+
if (this.indexByFactReference.hasOwnProperty(key)) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Write any new public keys
|
|
27
|
+
for (const signature of fact.signatures) {
|
|
28
|
+
if (!this.publicKeys.includes(signature.publicKey)) {
|
|
29
|
+
const pkIndex = this.publicKeys.length;
|
|
30
|
+
const publicKey = JSON.stringify(signature.publicKey);
|
|
31
|
+
this.write(`PK${pkIndex.toString()}\n${publicKey}\n\n`);
|
|
32
|
+
this.publicKeys.push(signature.publicKey);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Write the fact
|
|
37
|
+
const factType = JSON.stringify(fact.fact.type);
|
|
38
|
+
const predecessorIndexes = JSON.stringify(this.getPredecessorIndexes(fact.fact.predecessors));
|
|
39
|
+
const factFields = JSON.stringify(fact.fact.fields);
|
|
40
|
+
|
|
41
|
+
let output = `${factType}\n${predecessorIndexes}\n${factFields}`;
|
|
42
|
+
|
|
43
|
+
// Write the signatures
|
|
44
|
+
for (const signature of fact.signatures) {
|
|
45
|
+
const publicKeyIndex = this.publicKeys.indexOf(signature.publicKey);
|
|
46
|
+
const publicKey = `PK${publicKeyIndex.toString()}`;
|
|
47
|
+
const signatureString = JSON.stringify(signature.signature);
|
|
48
|
+
|
|
49
|
+
output += `\n${publicKey}\n${signatureString}`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
output += "\n\n";
|
|
53
|
+
|
|
54
|
+
this.write(output);
|
|
55
|
+
|
|
56
|
+
this.indexByFactReference[key] = this.index;
|
|
57
|
+
this.index++;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private getPredecessorIndexes(predecessors: PredecessorCollection): IndexPredecessorCollection {
|
|
62
|
+
const result: IndexPredecessorCollection = {};
|
|
63
|
+
for (const role in predecessors) {
|
|
64
|
+
const reference = predecessors[role];
|
|
65
|
+
if (Array.isArray(reference)) {
|
|
66
|
+
result[role] = reference.map(r => this.getFactIndex(r));
|
|
67
|
+
} else {
|
|
68
|
+
result[role] = this.getFactIndex(reference);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private getFactIndex(reference: FactReference): number {
|
|
75
|
+
const key = reference.type + ":" + reference.hash;
|
|
76
|
+
if (!this.indexByFactReference.hasOwnProperty(key)) {
|
|
77
|
+
throw new Error(`Fact reference not found in graph: ${key}`);
|
|
78
|
+
}
|
|
79
|
+
return this.indexByFactReference[key];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { GraphSerializer } from "../../src/http/serializer";
|
|
2
|
+
|
|
3
|
+
describe("GraphSerializer", () => {
|
|
4
|
+
it("should write an empty graph", () => {
|
|
5
|
+
let output = "";
|
|
6
|
+
const serializer = new GraphSerializer(chunk => {
|
|
7
|
+
output += chunk;
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
serializer.serialize([]);
|
|
11
|
+
|
|
12
|
+
expect(output).toBe("");
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("should write a graph with one fact without signatures", () => {
|
|
16
|
+
let output = "";
|
|
17
|
+
const serializer = new GraphSerializer(chunk => {
|
|
18
|
+
output += chunk;
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
serializer.serialize([{
|
|
22
|
+
fact: {
|
|
23
|
+
type: "MyApp.Root",
|
|
24
|
+
hash: "roothash",
|
|
25
|
+
fields: {
|
|
26
|
+
identifier: "root"
|
|
27
|
+
},
|
|
28
|
+
predecessors: {}
|
|
29
|
+
},
|
|
30
|
+
signatures: []
|
|
31
|
+
}]);
|
|
32
|
+
|
|
33
|
+
expect(output).toBe("\"MyApp.Root\"\n{}\n{\"identifier\":\"root\"}\n\n");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should write a graph with two facts without signatures", () => {
|
|
37
|
+
let output = "";
|
|
38
|
+
const serializer = new GraphSerializer(chunk => {
|
|
39
|
+
output += chunk;
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
serializer.serialize([{
|
|
43
|
+
fact: {
|
|
44
|
+
type: "MyApp.Root",
|
|
45
|
+
hash: "roothash",
|
|
46
|
+
fields: {},
|
|
47
|
+
predecessors: {}
|
|
48
|
+
},
|
|
49
|
+
signatures: []
|
|
50
|
+
}, {
|
|
51
|
+
fact: {
|
|
52
|
+
type: "MyApp.Child",
|
|
53
|
+
hash: "childhash",
|
|
54
|
+
fields: {},
|
|
55
|
+
predecessors: {
|
|
56
|
+
root: {
|
|
57
|
+
type: "MyApp.Root",
|
|
58
|
+
hash: "roothash"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
signatures: []
|
|
63
|
+
}]);
|
|
64
|
+
|
|
65
|
+
expect(output).toBe("\"MyApp.Root\"\n{}\n{}\n\n\"MyApp.Child\"\n{\"root\":0}\n{}\n\n");
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("should not repeat a fact", () => {
|
|
69
|
+
let output = "";
|
|
70
|
+
const serializer = new GraphSerializer(chunk => {
|
|
71
|
+
output += chunk;
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
serializer.serialize([{
|
|
75
|
+
fact: {
|
|
76
|
+
type: "MyApp.Root",
|
|
77
|
+
hash: "roothash",
|
|
78
|
+
fields: {},
|
|
79
|
+
predecessors: {}
|
|
80
|
+
},
|
|
81
|
+
signatures: []
|
|
82
|
+
}, {
|
|
83
|
+
fact: {
|
|
84
|
+
type: "MyApp.Root",
|
|
85
|
+
hash: "roothash",
|
|
86
|
+
fields: {},
|
|
87
|
+
predecessors: {}
|
|
88
|
+
},
|
|
89
|
+
signatures: []
|
|
90
|
+
}]);
|
|
91
|
+
|
|
92
|
+
expect(output).toBe("\"MyApp.Root\"\n{}\n{}\n\n");
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("should write a graph with two facts with signatures", () => {
|
|
96
|
+
let output = "";
|
|
97
|
+
const serializer = new GraphSerializer(chunk => {
|
|
98
|
+
output += chunk;
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
serializer.serialize([{
|
|
102
|
+
fact: {
|
|
103
|
+
type: "MyApp.Root",
|
|
104
|
+
hash: "roothash",
|
|
105
|
+
fields: {},
|
|
106
|
+
predecessors: {}
|
|
107
|
+
},
|
|
108
|
+
signatures: [{
|
|
109
|
+
publicKey: "public",
|
|
110
|
+
signature: "signature"
|
|
111
|
+
}]
|
|
112
|
+
}, {
|
|
113
|
+
fact: {
|
|
114
|
+
type: "MyApp.Child",
|
|
115
|
+
hash: "childhash",
|
|
116
|
+
fields: {},
|
|
117
|
+
predecessors: {
|
|
118
|
+
root: {
|
|
119
|
+
type: "MyApp.Root",
|
|
120
|
+
hash: "roothash"
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
signatures: [{
|
|
125
|
+
publicKey: "public",
|
|
126
|
+
signature: "signature1"
|
|
127
|
+
}, {
|
|
128
|
+
publicKey: "public2",
|
|
129
|
+
signature: "signature2"
|
|
130
|
+
}]
|
|
131
|
+
}]);
|
|
132
|
+
|
|
133
|
+
expect(output).toBe(
|
|
134
|
+
"PK0\n\"public\"\n\n" +
|
|
135
|
+
"\"MyApp.Root\"\n{}\n{}\nPK0\n\"signature\"\n\n" +
|
|
136
|
+
"PK1\n\"public2\"\n\n" +
|
|
137
|
+
"\"MyApp.Child\"\n{\"root\":0}\n{}\nPK0\n\"signature1\"\nPK1\n\"signature2\"\n\n"
|
|
138
|
+
);
|
|
139
|
+
});
|
|
140
|
+
});
|