jinaga-server 1.1.4 → 2.0.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.
Files changed (84) hide show
  1. package/README.md +12 -0
  2. package/dist/authentication/authentication-device.d.ts +3 -2
  3. package/dist/authentication/authentication-device.js +6 -0
  4. package/dist/authentication/authentication-device.js.map +1 -1
  5. package/dist/authentication/authentication-impl.d.ts +3 -2
  6. package/dist/authentication/authentication-impl.js +6 -0
  7. package/dist/authentication/authentication-impl.js.map +1 -1
  8. package/dist/authentication/authentication-noop.d.ts +20 -0
  9. package/dist/authentication/authentication-noop.js +52 -0
  10. package/dist/authentication/authentication-noop.js.map +1 -0
  11. package/dist/authentication/authentication-session.d.ts +3 -2
  12. package/dist/authentication/authentication-session.js +6 -0
  13. package/dist/authentication/authentication-session.js.map +1 -1
  14. package/dist/authentication.d.ts +3 -2
  15. package/dist/authentication.js +6 -0
  16. package/dist/authentication.js.map +1 -1
  17. package/dist/authorization/authorization-keystore.d.ts +3 -4
  18. package/dist/authorization/authorization-keystore.js +9 -4
  19. package/dist/authorization/authorization-keystore.js.map +1 -1
  20. package/dist/debug.d.ts +1 -0
  21. package/dist/debug.js +30 -0
  22. package/dist/debug.js.map +1 -0
  23. package/dist/http/router.js.map +1 -1
  24. package/dist/jinaga-server.js +15 -7
  25. package/dist/jinaga-server.js.map +1 -1
  26. package/dist/memory/memory-keystore.js +0 -6
  27. package/dist/memory/memory-keystore.js.map +1 -1
  28. package/dist/postgres/connection.js +1 -0
  29. package/dist/postgres/connection.js.map +1 -1
  30. package/dist/postgres/maps.d.ts +7 -6
  31. package/dist/postgres/maps.js +9 -1
  32. package/dist/postgres/maps.js.map +1 -1
  33. package/dist/postgres/postgres-keystore.js +0 -6
  34. package/dist/postgres/postgres-keystore.js.map +1 -1
  35. package/dist/postgres/postgres-store.d.ts +1 -2
  36. package/dist/postgres/postgres-store.js +29 -24
  37. package/dist/postgres/postgres-store.js.map +1 -1
  38. package/dist/postgres/specification-result-sql.d.ts +4 -4
  39. package/dist/postgres/specification-result-sql.js +34 -24
  40. package/dist/postgres/specification-result-sql.js.map +1 -1
  41. package/dist/postgres/specification-sql.js.map +1 -1
  42. package/dist/postgres/sql.d.ts +1 -1
  43. package/dist/postgres/sql.js +15 -7
  44. package/dist/postgres/sql.js.map +1 -1
  45. package/dist/util/maps.d.ts +0 -0
  46. package/dist/util/maps.js +2 -0
  47. package/dist/util/maps.js.map +1 -0
  48. package/docs/sql/SQL Generator (projection).png +0 -0
  49. package/docs/sql/SQLFromSpecification.md +2 -0
  50. package/integration-test/jinaga-test/Dockerfile +2 -2
  51. package/integration-test/jinaga-test/jinaga.test.js +3 -3
  52. package/integration-test/jinaga-test/package-lock.json +745 -3484
  53. package/integration-test/jinaga-test/package.json +2 -0
  54. package/integration-test/run.sh +3 -3
  55. package/package.json +5 -6
  56. package/replicator/index.ts +31 -0
  57. package/replicator/package-lock.json +855 -0
  58. package/replicator/package.json +27 -0
  59. package/replicator/tsconfig.json +15 -0
  60. package/src/authentication/authentication-device.ts +11 -1
  61. package/src/authentication/authentication-impl.ts +9 -2
  62. package/src/authentication/authentication-noop.ts +65 -0
  63. package/src/authentication/authentication-session.ts +11 -1
  64. package/src/authentication.ts +12 -2
  65. package/src/authorization/authorization-keystore.ts +12 -7
  66. package/src/debug.ts +30 -0
  67. package/src/http/router.ts +2 -2
  68. package/src/jinaga-server.ts +18 -8
  69. package/src/memory/memory-keystore.ts +0 -6
  70. package/src/postgres/connection.ts +2 -1
  71. package/src/postgres/maps.ts +8 -0
  72. package/src/postgres/postgres-keystore.ts +2 -8
  73. package/src/postgres/postgres-store.ts +37 -30
  74. package/src/postgres/specification-result-sql.ts +56 -45
  75. package/src/postgres/specification-sql.ts +1 -1
  76. package/src/postgres/sql.ts +23 -12
  77. package/src/util/maps.ts +0 -0
  78. package/test/postgres/postgresReadSpec.ts +4 -1
  79. package/test/postgres/postgresSpec.ts +31 -31
  80. package/test/postgres/postgresSpecificationSpec.ts +1 -1
  81. package/tsconfig.json +1 -0
  82. package/tsconfig.test.json +26 -0
  83. package/docs/specification.txt +0 -41
  84. package/interactive/index.js +0 -56
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "jinaga-replicator",
3
+ "version": "1.0.0",
4
+ "description": "A unit of fact storage and distribution within a Jinaga network",
5
+ "main": "dist/replicator/index.js",
6
+ "scripts": {
7
+ "build": "tsc",
8
+ "test": "echo \"Error: no test specified\" && exit 1",
9
+ "start": "node dist/replicator"
10
+ },
11
+ "keywords": [
12
+ "Jinaga",
13
+ "CRDT"
14
+ ],
15
+ "author": "Michael L Perry",
16
+ "license": "MIT",
17
+ "dependencies": {
18
+ "cors": "^2.8.5",
19
+ "express": "^4.18.1",
20
+ "pg": "^8.7.3"
21
+ },
22
+ "devDependencies": {
23
+ "@types/cors": "^2.8.12",
24
+ "@types/express": "^4.17.13",
25
+ "typescript": "^4.7.4"
26
+ }
27
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es6",
4
+ "module": "commonjs",
5
+ "sourceMap": true,
6
+ "baseUrl": "./dist",
7
+ "outDir": "./dist",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "paths": {
13
+ }
14
+ }
15
+ }
@@ -1,17 +1,19 @@
1
1
  import {
2
2
  Channel,
3
3
  FactEnvelope,
4
+ FactFeed,
4
5
  FactRecord,
5
6
  FactReference,
6
7
  Feed,
7
8
  Fork,
8
9
  LoginResponse,
9
10
  Observable,
11
+ ProjectedResult,
10
12
  Query,
11
13
  Specification,
14
+ SpecificationListener,
12
15
  UserIdentity,
13
16
  } from "jinaga";
14
- import { FactFeed } from "jinaga/dist/storage";
15
17
 
16
18
  import { Keystore } from "../keystore";
17
19
  import { Authentication } from "./authentication";
@@ -40,6 +42,14 @@ export class AuthenticationDevice implements Authentication {
40
42
  return this.inner.from(fact, query);
41
43
  }
42
44
 
45
+ addSpecificationListener(specification: Specification, onResult: (results: ProjectedResult[]) => Promise<void>): SpecificationListener {
46
+ return this.inner.addSpecificationListener(specification, onResult);
47
+ }
48
+
49
+ removeSpecificationListener(listener: SpecificationListener): void {
50
+ this.inner.removeSpecificationListener(listener);
51
+ }
52
+
43
53
  save(envelopes: FactEnvelope[]): Promise<FactEnvelope[]> {
44
54
  return this.inner.save(envelopes);
45
55
  }
@@ -1,5 +1,4 @@
1
- import { Channel, FactEnvelope, FactRecord, FactReference, Feed, Fork, Observable, Query, Specification, WebClient } from "jinaga";
2
- import { FactFeed } from "jinaga/dist/storage";
1
+ import { Channel, FactEnvelope, FactFeed, FactRecord, FactReference, Feed, Fork, Observable, ProjectedResult, Query, Specification, SpecificationListener, WebClient } from "jinaga";
3
2
 
4
3
  import { Authentication } from "./authentication";
5
4
 
@@ -52,6 +51,14 @@ export class AuthenticationImpl implements Authentication {
52
51
  return this.inner.from(fact, query);
53
52
  }
54
53
 
54
+ addSpecificationListener(specification: Specification, onResult: (results: ProjectedResult[]) => Promise<void>): SpecificationListener {
55
+ return this.inner.addSpecificationListener(specification, onResult);
56
+ }
57
+
58
+ removeSpecificationListener(listener: SpecificationListener): void {
59
+ this.inner.removeSpecificationListener(listener);
60
+ }
61
+
55
62
  addChannel(fact: FactReference, query: Query): Channel {
56
63
  return this.inner.addChannel(fact, query);
57
64
  }
@@ -0,0 +1,65 @@
1
+ import { Channel, FactEnvelope, FactFeed, FactPath, FactRecord, FactReference, Feed, Fork, LoginResponse, Observable, ObservableSource, ProjectedResult, Query, Specification, SpecificationListener } from "jinaga";
2
+ import { Authentication } from "./authentication";
3
+
4
+ export class AuthenticationNoOp implements Authentication {
5
+
6
+ constructor(
7
+ private inner: ObservableSource
8
+ ) { }
9
+
10
+ login(): Promise<LoginResponse> {
11
+ throw new Error("No keystore is configured.");
12
+ }
13
+
14
+ local(): Promise<FactRecord> {
15
+ throw new Error("No keystore is configured.");
16
+ }
17
+
18
+ addChannel(fact: FactReference, query: Query): Channel {
19
+ throw new Error("No keystore is configured.");
20
+ }
21
+
22
+ removeChannel(channel: Channel): void {
23
+ throw new Error("No keystore is configured.");
24
+ }
25
+
26
+ from(fact: FactReference, query: Query): Observable {
27
+ return this.inner.from(fact, query);
28
+ }
29
+
30
+ addSpecificationListener(specification: Specification, onResult: (results: ProjectedResult[]) => Promise<void>): SpecificationListener {
31
+ return this.inner.addSpecificationListener(specification, onResult);
32
+ }
33
+
34
+ removeSpecificationListener(listener: SpecificationListener): void {
35
+ return this.inner.removeSpecificationListener(listener);
36
+ }
37
+
38
+ close(): Promise<void> {
39
+ return this.inner.close();
40
+ }
41
+
42
+ save(envelopes: FactEnvelope[]): Promise<FactEnvelope[]> {
43
+ return this.inner.save(envelopes);
44
+ }
45
+
46
+ query(start: FactReference, query: Query): Promise<FactPath[]> {
47
+ return this.inner.query(start, query);
48
+ }
49
+
50
+ read(start: FactReference[], specification: Specification): Promise<ProjectedResult[]> {
51
+ return this.inner.read(start, specification);
52
+ }
53
+
54
+ feed(feed: Feed, bookmark: string): Promise<FactFeed> {
55
+ return this.inner.feed(feed, bookmark);
56
+ }
57
+
58
+ whichExist(references: FactReference[]): Promise<FactReference[]> {
59
+ return this.inner.whichExist(references);
60
+ }
61
+
62
+ load(references: FactReference[]): Promise<FactRecord[]> {
63
+ return this.inner.load(references);
64
+ }
65
+ }
@@ -3,17 +3,19 @@ import {
3
3
  AuthorizationRules,
4
4
  Channel,
5
5
  FactEnvelope,
6
+ FactFeed,
6
7
  FactRecord,
7
8
  FactReference,
8
9
  Feed,
9
10
  LoginResponse,
10
11
  Observable,
11
12
  ObservableSource,
13
+ ProjectedResult,
12
14
  Query,
13
15
  Specification,
16
+ SpecificationListener,
14
17
  UserIdentity,
15
18
  } from "jinaga";
16
- import { FactFeed } from "jinaga/dist/storage";
17
19
 
18
20
  import { Keystore } from "../keystore";
19
21
  import { Authentication } from "./authentication";
@@ -64,6 +66,14 @@ export class AuthenticationSession implements Authentication {
64
66
  return this.inner.from(fact, query);
65
67
  }
66
68
 
69
+ addSpecificationListener(specification: Specification, onResult: (results: ProjectedResult[]) => Promise<void>): SpecificationListener {
70
+ return this.inner.addSpecificationListener(specification, onResult);
71
+ }
72
+
73
+ removeSpecificationListener(listener: SpecificationListener): void {
74
+ this.inner.removeSpecificationListener(listener);
75
+ }
76
+
67
77
  async save(envelopes: FactEnvelope[]): Promise<FactEnvelope[]> {
68
78
  const userFact = await this.keystore.getUserFact(this.userIdentity);
69
79
  const facts = envelopes.map(envelope => envelope.fact);
@@ -1,15 +1,17 @@
1
1
  import {
2
2
  FactEnvelope,
3
+ FactFeed,
3
4
  FactRecord,
4
5
  FactReference,
5
6
  Feed,
6
7
  Observable,
7
8
  ObservableSource,
9
+ ProjectedResult,
8
10
  Query,
9
11
  Specification,
10
- WebClient,
12
+ SpecificationListener,
13
+ WebClient
11
14
  } from "jinaga";
12
- import { FactFeed } from "jinaga/dist/storage";
13
15
 
14
16
  export class Principal {
15
17
 
@@ -55,4 +57,12 @@ export class Authentication implements ObservableSource {
55
57
  from(fact: FactReference, query: Query): Observable {
56
58
  return this.inner.from(fact, query);
57
59
  }
60
+
61
+ addSpecificationListener(specification: Specification, onResult: (results: ProjectedResult[]) => Promise<void>): SpecificationListener {
62
+ return this.inner.addSpecificationListener(specification, onResult);
63
+ }
64
+
65
+ removeSpecificationListener(listener: SpecificationListener): void {
66
+ this.inner.removeSpecificationListener(listener);
67
+ }
58
68
  }
@@ -3,15 +3,15 @@ import {
3
3
  AuthorizationEngine,
4
4
  AuthorizationRules,
5
5
  FactEnvelope,
6
+ FactFeed,
6
7
  FactRecord,
7
8
  FactReference,
8
9
  Feed,
9
10
  ObservableSource,
10
11
  Query,
11
12
  Specification,
12
- UserIdentity,
13
+ UserIdentity
13
14
  } from "jinaga";
14
- import { FactFeed } from "jinaga/dist/storage";
15
15
 
16
16
  import { Keystore } from "../keystore";
17
17
 
@@ -55,7 +55,7 @@ export class AuthorizationKeystore implements Authorization {
55
55
  return this.observableSource.load(references);
56
56
  }
57
57
 
58
- async save(userIdentity: UserIdentity, facts: FactRecord[]) {
58
+ async save(userIdentity: UserIdentity | null, facts: FactRecord[]) {
59
59
  if (!this.authorizationEngine) {
60
60
  const envelopes = await this.observableSource.save(facts.map(fact => ({
61
61
  fact,
@@ -64,10 +64,15 @@ export class AuthorizationKeystore implements Authorization {
64
64
  return envelopes.map(envelope => envelope.fact);
65
65
  }
66
66
 
67
- const userFact = await this.keystore.getUserFact(userIdentity);
67
+ const userFact = userIdentity ? await this.keystore.getUserFact(userIdentity) : null;
68
68
  const authorizedFacts = await this.authorizationEngine.authorizeFacts(facts, userFact);
69
- const signedFacts = await this.keystore.signFacts(userIdentity, authorizedFacts);
70
- const envelopes = await this.observableSource.save(signedFacts);
71
- return envelopes.map(envelope => envelope.fact);
69
+ if (userIdentity) {
70
+ const signedFacts = await this.keystore.signFacts(userIdentity, authorizedFacts);
71
+ const envelopes = await this.observableSource.save(signedFacts);
72
+ return envelopes.map(envelope => envelope.fact);
73
+ }
74
+ else {
75
+ return authorizedFacts;
76
+ }
72
77
  }
73
78
  }
package/src/debug.ts ADDED
@@ -0,0 +1,30 @@
1
+ import express from "express";
2
+ import http from "http";
3
+ import { JinagaServer } from "./jinaga-server";
4
+ import process from "process";
5
+
6
+ process.on('SIGINT', () => {
7
+ console.log("\n\nStopping replicator\n");
8
+ process.exit(0);
9
+ });
10
+
11
+ const app = express();
12
+ const server = http.createServer(app);
13
+
14
+ app.set('port', process.env.PORT || 8080);
15
+ app.use(express.json());
16
+ app.use(express.text());
17
+
18
+ const pgConnection = process.env.JINAGA_POSTGRESQL ||
19
+ 'postgresql://appuser:apppw@localhost:5432/appdb';
20
+ //'postgresql://repl:replpw@localhost:5432/replicator';
21
+ const { handler } = JinagaServer.create({
22
+ pgStore: pgConnection
23
+ });
24
+
25
+ app.use('/jinaga', handler);
26
+
27
+ server.listen(app.get('port'), () => {
28
+ console.log(` Replicator is running at http://localhost:${app.get('port')} in ${app.get('env')} mode`);
29
+ console.log(' Press CTRL-C to stop\n');
30
+ });
@@ -26,7 +26,7 @@ import { FeedCache } from "./feed-cache";
26
26
 
27
27
  interface ParsedQs { [key: string]: undefined | string | string[] | ParsedQs | ParsedQs[] }
28
28
 
29
- function get<U>(method: ((req: RequestUser, params?: { [key: string]: string }, query?: ParsedQs) => Promise<U>)): Handler {
29
+ function get<U>(method: ((req: RequestUser, params: { [key: string]: string }, query: ParsedQs) => Promise<U>)): Handler {
30
30
  return (req, res, next) => {
31
31
  const user = <RequestUser>req.user;
32
32
  method(user, req.params, req.query)
@@ -197,7 +197,7 @@ function postStringCreate(method: (user: RequestUser, message: string) => Promis
197
197
  };
198
198
  }
199
199
 
200
- function serializeUserIdentity(user: RequestUser) : UserIdentity {
200
+ function serializeUserIdentity(user: RequestUser) : UserIdentity | null {
201
201
  if (!user) {
202
202
  return null;
203
203
  }
@@ -18,6 +18,7 @@ import {
18
18
  } from "jinaga";
19
19
 
20
20
  import { AuthenticationDevice } from "./authentication/authentication-device";
21
+ import { AuthenticationNoOp } from "./authentication/authentication-noop";
21
22
  import { AuthenticationSession } from "./authentication/authentication-session";
22
23
  import { AuthorizationKeystore } from "./authorization/authorization-keystore";
23
24
  import { NodeHttpConnection } from "./http/node-http";
@@ -54,17 +55,18 @@ export class JinagaServer {
54
55
  const store = createStore(config);
55
56
  const source = new ObservableSourceImpl(store);
56
57
  const fork = createFork(config, source, syncStatusNotifier);
57
- const keystore = new PostgresKeystore(config.pgKeystore);
58
+ const keystore = createKeystore(config);
58
59
  const authorizationRules = config.authorization ? config.authorization(new AuthorizationRules()) : null;
59
60
  const authorization = createAuthorization(authorizationRules, fork, keystore);
60
61
  const feedCache = new MemoryFeedCache();
61
62
  const router = new HttpRouter(authorization, feedCache);
62
- const authentication = new AuthenticationDevice(fork, keystore, localDeviceIdentity);
63
- const memory = new MemoryStore();
64
- const j: Jinaga = new Jinaga(authentication, memory, syncStatusNotifier);
63
+ const authentication = createAuthentication(keystore, fork);
64
+ const j: Jinaga = new Jinaga(authentication, syncStatusNotifier);
65
65
 
66
66
  async function close() {
67
- await keystore.close();
67
+ if (keystore) {
68
+ await keystore.close();
69
+ }
68
70
  await store.close();
69
71
  }
70
72
  return {
@@ -104,6 +106,10 @@ function createFork(config: JinagaServerConfig, feed: ObservableSource, syncStat
104
106
  }
105
107
  }
106
108
 
109
+ function createKeystore(config: JinagaServerConfig) {
110
+ return config.pgKeystore ? new PostgresKeystore(config.pgKeystore) : null;
111
+ }
112
+
107
113
  function createAuthorization(authorizationRules: AuthorizationRules | null, feed: ObservableSource, keystore: Keystore | null): Authorization {
108
114
  if (keystore) {
109
115
  const authorization = new AuthorizationKeystore(feed, keystore, authorizationRules);
@@ -114,14 +120,18 @@ function createAuthorization(authorizationRules: AuthorizationRules | null, feed
114
120
  }
115
121
  }
116
122
 
117
- async function withSession(feed: ObservableSource, keystore: Keystore, authorizationRules: AuthorizationRules | null, req: Request, callback: ((j: Jinaga) => Promise<void>)) {
123
+ function createAuthentication(keystore: PostgresKeystore | null, fork: Fork) {
124
+ return keystore ? new AuthenticationDevice(fork, keystore, localDeviceIdentity) : new AuthenticationNoOp(fork);
125
+ }
126
+
127
+ async function withSession(feed: ObservableSource, keystore: Keystore | null, authorizationRules: AuthorizationRules | null, req: Request, callback: ((j: Jinaga) => Promise<void>)) {
118
128
  const user = <RequestUser>req.user;
119
129
  const userIdentity: UserIdentity = {
120
130
  provider: user.provider,
121
131
  id: user.id
122
132
  }
123
- const authentication = new AuthenticationSession(feed, keystore, authorizationRules, userIdentity, user.profile.displayName, localDeviceIdentity);
133
+ const authentication = keystore ? new AuthenticationSession(feed, keystore, authorizationRules, userIdentity, user.profile.displayName, localDeviceIdentity) : new AuthenticationNoOp(feed);
124
134
  const syncStatusNotifier = new SyncStatusNotifier();
125
- const j = new Jinaga(authentication, new MemoryStore(), syncStatusNotifier);
135
+ const j = new Jinaga(authentication, syncStatusNotifier);
126
136
  await callback(j);
127
137
  }
@@ -36,9 +36,6 @@ export class MemoryKeystore implements Keystore {
36
36
  }
37
37
 
38
38
  private getOrCreateIdentityFact(type: string, identity: UserIdentity): FactRecord {
39
- if (!identity) {
40
- return null;
41
- }
42
39
  const publicKey = this.getOrCreatePublicKey(identity);
43
40
  const predecessors: PredecessorCollection = {};
44
41
  const fields = {
@@ -49,9 +46,6 @@ export class MemoryKeystore implements Keystore {
49
46
  }
50
47
 
51
48
  private getIdentityFact(type: string, identity: UserIdentity): FactRecord {
52
- if (!identity) {
53
- return null;
54
- }
55
49
  const publicKey = this.getPublicKey(identity);
56
50
  const predecessors: PredecessorCollection = {};
57
51
  const fields = {
@@ -31,7 +31,7 @@ export class ConnectionFactory {
31
31
  })
32
32
  }
33
33
 
34
- async with<T>(callback: (connection: PoolClient) => Promise<T>) {
34
+ async with<T>(callback: (connection: PoolClient) => Promise<T>) : Promise<T> {
35
35
  let attempt = 0;
36
36
  const pause = [0, 0, 1000, 5000, 15000, 30000];
37
37
  while (attempt < pause.length) {
@@ -57,6 +57,7 @@ export class ConnectionFactory {
57
57
  await delay(pause[attempt]);
58
58
  }
59
59
  }
60
+ throw new Error("Number of attempts exceeded");
60
61
  }
61
62
 
62
63
  private async createClient() {
@@ -16,6 +16,14 @@ export function getFactTypeId(map: FactTypeMap, name: string) {
16
16
  return map.get(name);
17
17
  }
18
18
 
19
+ export function ensureGetFactTypeId(factTypes: FactTypeMap, name: string): number {
20
+ const factTypeId = getFactTypeId(factTypes, name);
21
+ if (factTypeId === undefined) {
22
+ throw new Error(`Unknown fact type ${name}`);
23
+ }
24
+ return factTypeId;
25
+ }
26
+
19
27
  export function mergeFactTypes(map1: FactTypeMap, map2: FactTypeMap) {
20
28
  return new Map<string, number>([...map1, ...map2]);
21
29
  }
@@ -50,9 +50,6 @@ export class PostgresKeystore implements Keystore {
50
50
  }
51
51
 
52
52
  private async getOrCreateIdentityFact(type: string, identity: UserIdentity): Promise<FactRecord> {
53
- if (!identity) {
54
- return null;
55
- }
56
53
  const { publicPem } = await this.getOrGenerateKeyPair(identity);
57
54
  const predecessors: PredecessorCollection = {};
58
55
  const fields = {
@@ -63,9 +60,6 @@ export class PostgresKeystore implements Keystore {
63
60
  }
64
61
 
65
62
  private async getIdentityFact(type: string, identity: UserIdentity): Promise<FactRecord> {
66
- if (!identity) {
67
- return null;
68
- }
69
63
  const { publicPem } = await this.getKeyPair(identity);
70
64
  const predecessors: PredecessorCollection = {};
71
65
  const fields = {
@@ -78,7 +72,7 @@ export class PostgresKeystore implements Keystore {
78
72
  private async getKeyPair(userIdentity: UserIdentity): Promise<KeyPair> {
79
73
  const key = getUserIdentityKey(userIdentity);
80
74
  if (this.cache.has(key)) {
81
- return this.cache.get(key);
75
+ return this.cache.get(key)!;
82
76
  }
83
77
  const keyPair = await this.connectionFactory.with(connection =>
84
78
  this.selectKeyPair(connection, userIdentity));
@@ -105,7 +99,7 @@ export class PostgresKeystore implements Keystore {
105
99
  private async getOrGenerateKeyPair(userIdentity: UserIdentity): Promise<KeyPair> {
106
100
  const key = getUserIdentityKey(userIdentity);
107
101
  if (this.cache.has(key)) {
108
- return this.cache.get(key);
102
+ return this.cache.get(key)!;
109
103
  }
110
104
  const keyPair = await this.connectionFactory.withTransaction(connection =>
111
105
  this.selectOrInsertKeyPair(connection, userIdentity));