jinaga-server 3.1.0 → 3.1.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.
Files changed (37) hide show
  1. package/dist/http/line-reader.d.ts +2 -0
  2. package/dist/http/line-reader.js +68 -0
  3. package/dist/http/line-reader.js.map +1 -0
  4. package/dist/http/router.d.ts +4 -1
  5. package/dist/http/router.js +119 -15
  6. package/dist/http/router.js.map +1 -1
  7. package/dist/index.d.ts +1 -0
  8. package/dist/index.js +3 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/jinaga-server.d.ts +1 -0
  11. package/dist/jinaga-server.js +1 -1
  12. package/dist/jinaga-server.js.map +1 -1
  13. package/http/sans-auth/Feeds options.http +1 -0
  14. package/http/sans-auth/Save graph.http +6 -0
  15. package/http/sans-auth/Save json.http +13 -0
  16. package/http/with-auth/Create post with auth.http +24 -0
  17. package/http/with-auth/Define authorization rules.http +25 -0
  18. package/http/with-auth/Define distribution rules.http +30 -0
  19. package/http/with-auth/Feed sites.http +3 -0
  20. package/http/with-auth/Feeds options.http +1 -0
  21. package/http/with-auth/Feeds sites.http +32 -0
  22. package/http/with-auth/Get posts with auth.http +32 -0
  23. package/http/with-auth/Load titles.http +21 -0
  24. package/integration-test/jinaga-test/Dockerfile +1 -1
  25. package/package.json +2 -2
  26. package/replicator/index.ts +0 -2
  27. package/replicator/package-lock.json +12 -43
  28. package/replicator/package.json +1 -3
  29. package/src/http/line-reader.ts +69 -0
  30. package/src/http/router.ts +147 -19
  31. package/src/index.ts +1 -0
  32. package/src/jinaga-server.ts +2 -1
  33. package/dist/http/serializer.d.ts +0 -11
  34. package/dist/http/serializer.js +0 -68
  35. package/dist/http/serializer.js.map +0 -1
  36. package/src/http/serializer.ts +0 -81
  37. package/test/http/serializerSpec.ts +0 -140
@@ -0,0 +1,21 @@
1
+ POST {{replicatorUrl}}/load
2
+ Authorization: oauth2 authorization_code
3
+ Content-Type: application/json
4
+ Accept: application/x-jinaga-graph-v1
5
+
6
+ {
7
+ "references": [
8
+ {
9
+ "type": "Blog.Post",
10
+ "hash": "XiDu5OWoNUwZhTBs+mwHrxjBDlFjBmDIgEt9ZXmCeMq8uv3Tv89Am6GQSt2ppl4wGG1UWMFxd9tstg5NMSSjKg=="
11
+ },
12
+ {
13
+ "type": "Blog.Post.Title",
14
+ "hash": "n+hKtiGWHVu16UlxKY73Va+jsriQ/UxVFn3DCdXQEccWeXN5/SIxhWXmuMlfzelpHjuwPgCyeyid/jJrkJRRtQ=="
15
+ },
16
+ {
17
+ "type": "Blog.Post.Title",
18
+ "hash": "iuRHB3Zkj0P3+b7XPvbEzA/ANdJ3C8Bm1dJ/nW8I9Tb+9VdHQP5g2bpp8hwS4KqzecgG6KSG6VCNOY7RoaEsIQ=="
19
+ }
20
+ ]
21
+ }
@@ -1,4 +1,4 @@
1
- FROM node:20.11.0-bullseye-slim
1
+ FROM node:20.12-bullseye-slim
2
2
 
3
3
  WORKDIR /root
4
4
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jinaga-server",
3
- "version": "3.1.0",
3
+ "version": "3.1.1",
4
4
  "description": "Data management for web and mobile applications.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -48,7 +48,7 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "express": "^4.19.2",
51
- "jinaga": "^6.0.1",
51
+ "jinaga": "^6.1.1",
52
52
  "node-forge": "^1.3.1",
53
53
  "pg": "^8.11.3"
54
54
  }
@@ -1,4 +1,3 @@
1
- import cors = require("cors");
2
1
  import express = require("express");
3
2
  import * as http from "http";
4
3
  import { JinagaServer } from "../src";
@@ -15,7 +14,6 @@ const server = http.createServer(app);
15
14
  app.set('port', process.env.PORT || 8080);
16
15
  app.use(express.json());
17
16
  app.use(express.text());
18
- app.use(cors());
19
17
 
20
18
  const pgConnection = process.env.JINAGA_POSTGRESQL ||
21
19
  'postgresql://appuser:apppw@localhost:5432/appdb';
@@ -9,12 +9,10 @@
9
9
  "version": "1.0.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
- "cors": "^2.8.5",
13
- "express": "^4.18.3",
12
+ "express": "^4.19.2",
14
13
  "pg": "8.11.3"
15
14
  },
16
15
  "devDependencies": {
17
- "@types/cors": "^2.8.12",
18
16
  "@types/express": "^4.17.13",
19
17
  "typescript": "^4.7.4"
20
18
  }
@@ -38,23 +36,14 @@
38
36
  "@types/node": "*"
39
37
  }
40
38
  },
41
- "node_modules/@types/cors": {
42
- "version": "2.8.13",
43
- "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz",
44
- "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==",
45
- "dev": true,
46
- "dependencies": {
47
- "@types/node": "*"
48
- }
49
- },
50
39
  "node_modules/@types/express": {
51
- "version": "4.17.16",
52
- "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.16.tgz",
53
- "integrity": "sha512-LkKpqRZ7zqXJuvoELakaFYuETHjZkSol8EV6cNnyishutDBCCdv6+dsKPbKkCcIk57qRphOLY5sEgClw1bO3gA==",
40
+ "version": "4.17.21",
41
+ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz",
42
+ "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==",
54
43
  "dev": true,
55
44
  "dependencies": {
56
45
  "@types/body-parser": "*",
57
- "@types/express-serve-static-core": "^4.17.31",
46
+ "@types/express-serve-static-core": "^4.17.33",
58
47
  "@types/qs": "*",
59
48
  "@types/serve-static": "*"
60
49
  }
@@ -198,9 +187,9 @@
198
187
  }
199
188
  },
200
189
  "node_modules/cookie": {
201
- "version": "0.5.0",
202
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
203
- "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
190
+ "version": "0.6.0",
191
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
192
+ "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
204
193
  "engines": {
205
194
  "node": ">= 0.6"
206
195
  }
@@ -210,18 +199,6 @@
210
199
  "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
211
200
  "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
212
201
  },
213
- "node_modules/cors": {
214
- "version": "2.8.5",
215
- "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
216
- "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
217
- "dependencies": {
218
- "object-assign": "^4",
219
- "vary": "^1"
220
- },
221
- "engines": {
222
- "node": ">= 0.10"
223
- }
224
- },
225
202
  "node_modules/debug": {
226
203
  "version": "2.6.9",
227
204
  "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@@ -309,16 +286,16 @@
309
286
  }
310
287
  },
311
288
  "node_modules/express": {
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==",
289
+ "version": "4.19.2",
290
+ "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
291
+ "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
315
292
  "dependencies": {
316
293
  "accepts": "~1.3.8",
317
294
  "array-flatten": "1.1.1",
318
295
  "body-parser": "1.20.2",
319
296
  "content-disposition": "0.5.4",
320
297
  "content-type": "~1.0.4",
321
- "cookie": "0.5.0",
298
+ "cookie": "0.6.0",
322
299
  "cookie-signature": "1.0.6",
323
300
  "debug": "2.6.9",
324
301
  "depd": "2.0.0",
@@ -566,14 +543,6 @@
566
543
  "node": ">= 0.6"
567
544
  }
568
545
  },
569
- "node_modules/object-assign": {
570
- "version": "4.1.1",
571
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
572
- "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
573
- "engines": {
574
- "node": ">=0.10.0"
575
- }
576
- },
577
546
  "node_modules/object-inspect": {
578
547
  "version": "1.13.1",
579
548
  "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
@@ -15,12 +15,10 @@
15
15
  "author": "Michael L Perry",
16
16
  "license": "MIT",
17
17
  "dependencies": {
18
- "cors": "^2.8.5",
19
- "express": "^4.18.3",
18
+ "express": "^4.19.2",
20
19
  "pg": "8.11.3"
21
20
  },
22
21
  "devDependencies": {
23
- "@types/cors": "^2.8.12",
24
22
  "@types/express": "^4.17.13",
25
23
  "typescript": "^4.7.4"
26
24
  }
@@ -0,0 +1,69 @@
1
+ const PauseAt = 10;
2
+ const ResumeAt = 5;
3
+
4
+ export function createLineReader(stream: NodeJS.ReadableStream): () => Promise<string | null> {
5
+ // Store the bytes read so far that have not yet been processed.
6
+ let buffer = Buffer.alloc(0);
7
+ // Store a queue of promises that resolve to the next line read.
8
+ let promiseQueue: Promise<string | null>[] = [];
9
+ // Initialize the queue.
10
+ let resolve: (value: string | null) => void;
11
+ let reject: (reason: any) => void;
12
+ promiseQueue.push(new Promise<string | null>((res, rej) => { resolve = res; reject = rej; }));
13
+
14
+ stream.on('data', (data: Buffer) => {
15
+ let newline = -1;
16
+ // Look for the first newline in the data.
17
+ while ((newline = data.indexOf(10)) >= 0) {
18
+ // Extract the line from the data.
19
+ let line = Buffer.concat([buffer, data.slice(0, newline)]).toString();
20
+ data = data.slice(newline + 1);
21
+ buffer = Buffer.alloc(0);
22
+ if (line.charCodeAt(0) === 0xFEFF) {
23
+ // Remove BOM
24
+ line = line.slice(1);
25
+ }
26
+ // Resolve the promise with the line.
27
+ resolve(line);
28
+ // Create a new promise for the next line.
29
+ promiseQueue.push(new Promise<string | null>((res, rej) => { resolve = res; reject = rej; }));
30
+
31
+ // Apply backpressure if the promise queue gets too deep
32
+ if (promiseQueue.length > PauseAt) {
33
+ stream.pause();
34
+ }
35
+ }
36
+ // Append the remaining data to the buffer.
37
+ buffer = Buffer.concat([buffer, data]);
38
+ });
39
+
40
+ stream.on('end', () => {
41
+ // Extract the last line from the buffer.
42
+ let line = buffer.toString();
43
+ if (line.charCodeAt(0) === 0xFEFF) {
44
+ // Remove BOM
45
+ line = line.slice(1);
46
+ }
47
+ // If the stream ends with a newline, then don't add an empty line.
48
+ if (line.length > 0) {
49
+ resolve(line);
50
+ promiseQueue.push(new Promise<string | null>((res, rej) => { resolve = res; reject = rej; }));
51
+ }
52
+ resolve(null);
53
+ });
54
+
55
+ stream.on('error', (e: Error) => {
56
+ reject(e);
57
+ });
58
+
59
+ return () => {
60
+ if (promiseQueue.length === 0) {
61
+ throw new Error("Line reader has been closed.");
62
+ }
63
+ const promise = promiseQueue.shift()!;
64
+ if (stream.isPaused() && promiseQueue.length <= ResumeAt) {
65
+ stream.resume();
66
+ }
67
+ return promise;
68
+ };
69
+ }
@@ -1,4 +1,4 @@
1
- import { Handler, MediaType, Response, Router } from "express";
1
+ import { Handler, NextFunction, Request, Response, Router } from "express";
2
2
  import {
3
3
  Authorization,
4
4
  Declaration,
@@ -11,12 +11,14 @@ import {
11
11
  FeedResponse,
12
12
  FeedsResponse,
13
13
  Forbidden,
14
+ GraphDeserializer,
15
+ GraphSerializer,
16
+ GraphSource,
14
17
  LoadMessage,
15
18
  LoadResponse,
16
19
  ProfileMessage,
17
20
  ProjectedResult,
18
21
  ReferencesByName,
19
- SaveMessage,
20
22
  Specification,
21
23
  SpecificationParser,
22
24
  Trace,
@@ -28,9 +30,8 @@ import {
28
30
  parseLoadMessage,
29
31
  parseSaveMessage
30
32
  } from "jinaga";
31
-
32
33
  import { Stream } from "./stream";
33
- import { GraphSerializer } from "./serializer";
34
+ import { createLineReader } from "./line-reader";
34
35
 
35
36
  interface ParsedQs { [key: string]: undefined | string | string[] | ParsedQs | ParsedQs[] }
36
37
 
@@ -203,15 +204,12 @@ function postString<U>(method: (user: RequestUser, message: string) => Promise<U
203
204
  }
204
205
 
205
206
  function postCreate<T>(
206
- parse: (input: any) => T,
207
+ parse: (request: Request) => T,
207
208
  method: (user: RequestUser, message: T) => Promise<void>
208
209
  ): Handler {
209
210
  return (req, res, next) => {
210
211
  const user = <RequestUser>req.user;
211
- const message = parse(req.body);
212
- if (!message) {
213
- throw new Error('Ensure that you have called app.use(express.json()).');
214
- }
212
+ const message = parse(req);
215
213
  method(user, message)
216
214
  .then(_ => {
217
215
  res.sendStatus(201);
@@ -274,6 +272,29 @@ function serializeUserIdentity(user: RequestUser | null): UserIdentity | null {
274
272
  };
275
273
  }
276
274
 
275
+ function inputSaveMessage(req: Request): GraphSource {
276
+ if (req.is('application/x-jinaga-graph-v1')) {
277
+ // Convert the request into a function that reads one line at a time.
278
+ const readLine = createLineReader(req);
279
+
280
+ return new GraphDeserializer(readLine);
281
+ }
282
+ else {
283
+ return {
284
+ read: async (onEnvelopes) => {
285
+ const message = parseSaveMessage(req.body);
286
+ if (!message) {
287
+ throw new Error('Ensure that you have called app.use(express.json()).');
288
+ }
289
+ await onEnvelopes(message.facts.map(fact => ({
290
+ fact: fact,
291
+ signatures: []
292
+ })));
293
+ }
294
+ };
295
+ }
296
+ }
297
+
277
298
  function outputGraph(result: FactEnvelope[], res: Response, accepts: (type: string) => string | false) {
278
299
  if (accepts("application/x-jinaga-graph-v1")) {
279
300
  res.type("application/x-jinaga-graph-v1");
@@ -306,7 +327,12 @@ export interface RequestUser {
306
327
  export class HttpRouter {
307
328
  handler: Handler;
308
329
 
309
- constructor(private factManager: FactManager, private authorization: Authorization, private feedCache: FeedCache) {
330
+ constructor(
331
+ private factManager: FactManager,
332
+ private authorization: Authorization,
333
+ private feedCache: FeedCache,
334
+ private allowedOrigin: string | string[] | ((origin: string, callback: (err: Error | null, allow?: boolean) => void) => void)
335
+ ) {
310
336
  const router = Router();
311
337
  router.get('/login', getAuthenticate(user => this.login(user)));
312
338
  router.post('/load', post(
@@ -315,8 +341,8 @@ export class HttpRouter {
315
341
  outputGraph
316
342
  ));
317
343
  router.post('/save', postCreate(
318
- parseSaveMessage,
319
- (user, saveMessage) => this.save(user, saveMessage)
344
+ inputSaveMessage,
345
+ (user, graphSource) => this.save(user, graphSource)
320
346
  ));
321
347
 
322
348
  router.post('/read', postString((user, input: string) => this.read(user, input)));
@@ -330,6 +356,30 @@ export class HttpRouter {
330
356
  (user, params, query) => this.feed(user, params, query),
331
357
  (user, params, query) => this.streamFeed(user, params, query)));
332
358
 
359
+ // Respond to OPTIONS requests to describe the methods and content types
360
+ // that are supported.
361
+ this.setOptions(router, '/login')
362
+ .intendedForGet()
363
+ .returningContent();
364
+ this.setOptions(router, '/load')
365
+ .intendedForPost('application/json')
366
+ .returningContent();
367
+ this.setOptions(router, '/save')
368
+ .intendedForPost('application/json', 'application/x-jinaga-graph-v1')
369
+ .returningNoContent();
370
+ this.setOptions(router, '/read')
371
+ .intendedForPost('text/plain')
372
+ .returningContent();
373
+ this.setOptions(router, '/write')
374
+ .intendedForPost('text/plain')
375
+ .returningNoContent();
376
+ this.setOptions(router, '/feeds')
377
+ .intendedForPost('text/plain')
378
+ .returningContent();
379
+ this.setOptions(router, '/feeds/:hash')
380
+ .intendedForGet()
381
+ .returningContent();
382
+
333
383
  this.handler = router;
334
384
  }
335
385
 
@@ -347,17 +397,14 @@ export class HttpRouter {
347
397
  private async load(user: RequestUser, loadMessage: LoadMessage): Promise<FactEnvelope[]> {
348
398
  const userIdentity = serializeUserIdentity(user);
349
399
  const result = await this.authorization.load(userIdentity, loadMessage.references);
350
- const facts = result.map(r => r.fact);
351
400
  return result;
352
401
  }
353
402
 
354
- private async save(user: RequestUser | null, saveMessage: SaveMessage): Promise<void> {
403
+ private async save(user: RequestUser | null, graphSource: GraphSource): Promise<void> {
355
404
  const userIdentity = serializeUserIdentity(user);
356
- await this.authorization.save(userIdentity, saveMessage.facts
357
- .map(fact => ({
358
- fact: fact,
359
- signatures: []
360
- })));
405
+ await graphSource.read(async (envelopes) => {
406
+ await this.authorization.save(userIdentity, envelopes);
407
+ });
361
408
  }
362
409
 
363
410
  private async read(user: RequestUser | null, input: string): Promise<any[]> {
@@ -550,6 +597,77 @@ export class HttpRouter {
550
597
  return declaredFact.declared.reference;
551
598
  });
552
599
  }
600
+
601
+ private setOptions(router: Router, path: string): OptionsConfiguration {
602
+ const addOptions = (allowedMethods: string[], allowedHeaders: string[], allowedTypes: string[]) => {
603
+ router.options(path, this.applyAllowOrigin((req, res) => {
604
+ res.set('Allow', allowedMethods.join(', '));
605
+ res.set('Access-Control-Allow-Methods', allowedMethods.join(', '));
606
+ res.set('Access-Control-Allow-Headers', allowedHeaders.join(', '));
607
+ if (allowedTypes.length > 0) {
608
+ res.set('Accept-Post', allowedTypes.join(', '));
609
+ }
610
+ res.status(204).send();
611
+ }));
612
+ }
613
+
614
+ return {
615
+ intendedForGet: () => {
616
+ addOptions(['GET', 'OPTIONS'], ['Accept', 'Authorization'], []);
617
+ return {
618
+ returningContent: () => { },
619
+ returningNoContent: () => { }
620
+ };
621
+ },
622
+ intendedForPost: (...contentTypes: string[]) => {
623
+ return {
624
+ returningContent: () => {
625
+ addOptions(
626
+ ['POST', 'OPTIONS'],
627
+ ['Content-Type', 'Accept', 'Authorization'],
628
+ contentTypes);
629
+ },
630
+ returningNoContent: () => {
631
+ addOptions(
632
+ ['POST', 'OPTIONS'],
633
+ ['Content-Type', 'Authorization'],
634
+ contentTypes);
635
+ }
636
+ };
637
+ }
638
+ };
639
+ }
640
+
641
+ private applyAllowOrigin(sendResponse: (req: Request, res: Response) => void) {
642
+ // Specify the allowed origins.
643
+ return (req: Request, res: Response, next: NextFunction) => {
644
+ let requestOrigin = req.get('Origin');
645
+
646
+ if (typeof this.allowedOrigin === 'string') {
647
+ // If allowedOrigin is a string, use it as the value of the Access-Control-Allow-Origin header
648
+ res.set('Access-Control-Allow-Origin', this.allowedOrigin);
649
+ sendResponse(req, res);
650
+ } else if (Array.isArray(this.allowedOrigin)) {
651
+ // If allowedOrigin is an array, check if the request's origin is in the array
652
+ if (requestOrigin && this.allowedOrigin.includes(requestOrigin)) {
653
+ res.set('Access-Control-Allow-Origin', requestOrigin);
654
+ }
655
+ sendResponse(req, res);
656
+ } else if (typeof this.allowedOrigin === 'function' && requestOrigin) {
657
+ // If allowedOrigin is a function, call it with the request's origin
658
+ this.allowedOrigin(requestOrigin, (err, allow) => {
659
+ if (err) {
660
+ next(err);
661
+ } else if (allow) {
662
+ res.set('Access-Control-Allow-Origin', requestOrigin);
663
+ }
664
+ sendResponse(req, res);
665
+ });
666
+ } else {
667
+ sendResponse(req, res);
668
+ }
669
+ };
670
+ }
553
671
  }
554
672
 
555
673
  function parseString(input: any): string {
@@ -573,4 +691,14 @@ function extractResults(obj: any): any {
573
691
  else {
574
692
  return obj;
575
693
  }
694
+ }
695
+
696
+ interface OptionsConfiguration {
697
+ intendedForGet(): ResponseConfiguration;
698
+ intendedForPost(...contentTypes: string[]): ResponseConfiguration;
699
+ }
700
+
701
+ interface ResponseConfiguration {
702
+ returningContent(): void;
703
+ returningNoContent(): void;
576
704
  }
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@ export { AuthenticationDevice } from "./authentication/authentication-device";
2
2
  export { AuthenticationSession } from "./authentication/authentication-session";
3
3
  export { AuthorizationKeystore } from "./authorization/authorization-keystore";
4
4
  export { DistributedFactCache } from "./authorization/distributed-fact-cache";
5
+ export { createLineReader } from "./http/line-reader";
5
6
  export { HttpRouter, RequestUser } from "./http/router";
6
7
  export { Stream } from "./http/stream";
7
8
  export { JinagaServer, JinagaServerConfig, JinagaServerInstance, tracePool } from "./jinaga-server";
@@ -38,6 +38,7 @@ export type JinagaServerConfig = {
38
38
  model?: Model,
39
39
  authorization?: (a: AuthorizationRules) => AuthorizationRules,
40
40
  distribution?: (d: DistributionRules) => DistributionRules,
41
+ origin?: string | string[] | ((origin: string, callback: (err: Error | null, allow?: boolean) => void) => void),
41
42
  };
42
43
 
43
44
  export type JinagaServerInstance = {
@@ -67,7 +68,7 @@ export class JinagaServer {
67
68
  const network = new NetworkNoOp();
68
69
  const factManager = new FactManager(fork, source, store, network);
69
70
  const authorization = createAuthorization(authorizationRules, distributionRules, factManager, store, keystore);
70
- const router = new HttpRouter(factManager, authorization, feedCache);
71
+ const router = new HttpRouter(factManager, authorization, feedCache, config.origin || '*');
71
72
  const j: Jinaga = new Jinaga(authentication, factManager, syncStatusNotifier);
72
73
 
73
74
  async function close() {
@@ -1,11 +0,0 @@
1
- import { FactEnvelope } from "jinaga";
2
- export declare class GraphSerializer {
3
- private readonly write;
4
- private index;
5
- private indexByFactReference;
6
- private publicKeys;
7
- constructor(write: (chunk: string) => void);
8
- serialize(result: FactEnvelope[]): void;
9
- private getPredecessorIndexes;
10
- private getFactIndex;
11
- }
@@ -1,68 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GraphSerializer = void 0;
4
- class GraphSerializer {
5
- constructor(write) {
6
- this.write = write;
7
- this.index = 0;
8
- this.indexByFactReference = {};
9
- this.publicKeys = [];
10
- }
11
- serialize(result) {
12
- // Write the facts
13
- for (const fact of result) {
14
- // Skip facts that have already been written
15
- const key = fact.fact.type + ":" + fact.fact.hash;
16
- if (this.indexByFactReference.hasOwnProperty(key)) {
17
- continue;
18
- }
19
- // Write any new public keys
20
- for (const signature of fact.signatures) {
21
- if (!this.publicKeys.includes(signature.publicKey)) {
22
- const pkIndex = this.publicKeys.length;
23
- const publicKey = JSON.stringify(signature.publicKey);
24
- this.write(`PK${pkIndex.toString()}\n${publicKey}\n\n`);
25
- this.publicKeys.push(signature.publicKey);
26
- }
27
- }
28
- // Write the fact
29
- const factType = JSON.stringify(fact.fact.type);
30
- const predecessorIndexes = JSON.stringify(this.getPredecessorIndexes(fact.fact.predecessors));
31
- const factFields = JSON.stringify(fact.fact.fields);
32
- let output = `${factType}\n${predecessorIndexes}\n${factFields}`;
33
- // Write the signatures
34
- for (const signature of fact.signatures) {
35
- const publicKeyIndex = this.publicKeys.indexOf(signature.publicKey);
36
- const publicKey = `PK${publicKeyIndex.toString()}`;
37
- const signatureString = JSON.stringify(signature.signature);
38
- output += `\n${publicKey}\n${signatureString}`;
39
- }
40
- output += "\n\n";
41
- this.write(output);
42
- this.indexByFactReference[key] = this.index;
43
- this.index++;
44
- }
45
- }
46
- getPredecessorIndexes(predecessors) {
47
- const result = {};
48
- for (const role in predecessors) {
49
- const reference = predecessors[role];
50
- if (Array.isArray(reference)) {
51
- result[role] = reference.map(r => this.getFactIndex(r));
52
- }
53
- else {
54
- result[role] = this.getFactIndex(reference);
55
- }
56
- }
57
- return result;
58
- }
59
- getFactIndex(reference) {
60
- const key = reference.type + ":" + reference.hash;
61
- if (!this.indexByFactReference.hasOwnProperty(key)) {
62
- throw new Error(`Fact reference not found in graph: ${key}`);
63
- }
64
- return this.indexByFactReference[key];
65
- }
66
- }
67
- exports.GraphSerializer = GraphSerializer;
68
- //# sourceMappingURL=serializer.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"serializer.js","sourceRoot":"","sources":["../../src/http/serializer.ts"],"names":[],"mappings":"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"}