jinaga-server 3.0.0 → 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.
@@ -10,8 +10,8 @@
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "cors": "^2.8.5",
13
- "express": "^4.18.1",
14
- "pg": "^8.11.3"
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.1",
126
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
127
- "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
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.4",
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.1",
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.2",
165
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
166
- "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
167
- "dependencies": {
168
- "function-bind": "^1.1.1",
169
- "get-intrinsic": "^1.0.2"
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.4",
188
- "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
189
- "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
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.2",
272
- "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
273
- "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
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.1",
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.1",
346
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
347
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
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.0",
351
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
352
- "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
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
- "function-bind": "^1.1.1",
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.3",
364
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
365
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
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
- "function-bind": "^1.1.1"
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.0"
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.12.3",
497
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
498
- "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
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.1",
686
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
687
- "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
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.4",
771
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
772
- "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
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.0",
775
- "get-intrinsic": "^1.0.2",
776
- "object-inspect": "^1.9.0"
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"
@@ -16,7 +16,7 @@
16
16
  "license": "MIT",
17
17
  "dependencies": {
18
18
  "cors": "^2.8.5",
19
- "express": "^4.18.1",
19
+ "express": "^4.18.3",
20
20
  "pg": "8.11.3"
21
21
  },
22
22
  "devDependencies": {
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "target": "es6",
4
+ "lib": [ "ES2019" ],
4
5
  "module": "commonjs",
5
6
  "sourceMap": true,
6
7
  "baseUrl": "./dist",
@@ -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
 
@@ -64,7 +66,7 @@ function getOrStream<U>(
64
66
  })
65
67
  .done(() => {
66
68
  clearTimeout(timeout);
67
- res.socket.end();
69
+ res.socket?.end();
68
70
  });
69
71
  }
70
72
  })
@@ -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("json");
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<LoadResponse> {
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
+ }
@@ -1,5 +1,5 @@
1
1
  import { FactReference, Label, Match, PathCondition } from "jinaga";
2
- import { FactTypeMap, RoleMap, ensureGetFactTypeId, getFactTypeId, getRoleId } from "./maps";
2
+ import { FactTypeMap, RoleMap, getFactTypeId, getRoleId } from "./maps";
3
3
 
4
4
  export interface FactDescription {
5
5
  type: string;
@@ -323,9 +323,13 @@ export class QueryDescriptionBuider {
323
323
  if (givenIndex < 0) {
324
324
  throw new Error(`No input parameter found for label ${condition.labelRight}`);
325
325
  }
326
+ const factTypeId = getFactTypeId(this.factTypes, start[givenIndex].type);
327
+ if (!factTypeId) {
328
+ return { queryDescription: QueryDescription.unsatisfiable, knownFacts };
329
+ }
326
330
  const { queryDescription: newQueryDescription, factDescription } = queryDescription.withInputParameter(
327
331
  given[givenIndex],
328
- ensureGetFactTypeId(this.factTypes, start[givenIndex].type),
332
+ factTypeId,
329
333
  start[givenIndex].hash,
330
334
  path
331
335
  );