@kronos-ts/kronosdb 0.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.
Files changed (96) hide show
  1. package/dist/connection.d.ts +86 -0
  2. package/dist/connection.d.ts.map +1 -0
  3. package/dist/connection.js +133 -0
  4. package/dist/connection.js.map +1 -0
  5. package/dist/errors.d.ts +72 -0
  6. package/dist/errors.d.ts.map +1 -0
  7. package/dist/errors.js +149 -0
  8. package/dist/errors.js.map +1 -0
  9. package/dist/event-processor-info.d.ts +32 -0
  10. package/dist/event-processor-info.d.ts.map +1 -0
  11. package/dist/event-processor-info.js +24 -0
  12. package/dist/event-processor-info.js.map +1 -0
  13. package/dist/flow-controlled-sender.d.ts +12 -0
  14. package/dist/flow-controlled-sender.d.ts.map +1 -0
  15. package/dist/flow-controlled-sender.js +53 -0
  16. package/dist/flow-controlled-sender.js.map +1 -0
  17. package/dist/generated/command.d.ts +169 -0
  18. package/dist/generated/command.d.ts.map +1 -0
  19. package/dist/generated/command.js +964 -0
  20. package/dist/generated/command.js.map +1 -0
  21. package/dist/generated/common.d.ts +76 -0
  22. package/dist/generated/common.d.ts.map +1 -0
  23. package/dist/generated/common.js +648 -0
  24. package/dist/generated/common.js.map +1 -0
  25. package/dist/generated/eventstore.d.ts +337 -0
  26. package/dist/generated/eventstore.d.ts.map +1 -0
  27. package/dist/generated/eventstore.js +1757 -0
  28. package/dist/generated/eventstore.js.map +1 -0
  29. package/dist/generated/platform.d.ts +242 -0
  30. package/dist/generated/platform.d.ts.map +1 -0
  31. package/dist/generated/platform.js +1525 -0
  32. package/dist/generated/platform.js.map +1 -0
  33. package/dist/generated/query.d.ts +265 -0
  34. package/dist/generated/query.d.ts.map +1 -0
  35. package/dist/generated/query.js +2114 -0
  36. package/dist/generated/query.js.map +1 -0
  37. package/dist/generated/snapshot.d.ts +180 -0
  38. package/dist/generated/snapshot.d.ts.map +1 -0
  39. package/dist/generated/snapshot.js +861 -0
  40. package/dist/generated/snapshot.js.map +1 -0
  41. package/dist/index.d.ts +13 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +13 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/kronosdb-event-store.d.ts +17 -0
  46. package/dist/kronosdb-event-store.d.ts.map +1 -0
  47. package/dist/kronosdb-event-store.js +328 -0
  48. package/dist/kronosdb-event-store.js.map +1 -0
  49. package/dist/kronosdb-snapshot-store.d.ts +10 -0
  50. package/dist/kronosdb-snapshot-store.d.ts.map +1 -0
  51. package/dist/kronosdb-snapshot-store.js +79 -0
  52. package/dist/kronosdb-snapshot-store.js.map +1 -0
  53. package/dist/kronosdb.d.ts +53 -0
  54. package/dist/kronosdb.d.ts.map +1 -0
  55. package/dist/kronosdb.js +852 -0
  56. package/dist/kronosdb.js.map +1 -0
  57. package/dist/metadata-conversion.d.ts +37 -0
  58. package/dist/metadata-conversion.d.ts.map +1 -0
  59. package/dist/metadata-conversion.js +75 -0
  60. package/dist/metadata-conversion.js.map +1 -0
  61. package/dist/outbound-stream.d.ts +15 -0
  62. package/dist/outbound-stream.d.ts.map +1 -0
  63. package/dist/outbound-stream.js +39 -0
  64. package/dist/outbound-stream.js.map +1 -0
  65. package/dist/platform-service.d.ts +87 -0
  66. package/dist/platform-service.d.ts.map +1 -0
  67. package/dist/platform-service.js +218 -0
  68. package/dist/platform-service.js.map +1 -0
  69. package/dist/service-definitions.d.ts +187 -0
  70. package/dist/service-definitions.d.ts.map +1 -0
  71. package/dist/service-definitions.js +18 -0
  72. package/dist/service-definitions.js.map +1 -0
  73. package/dist/shutdown-latch.d.ts +18 -0
  74. package/dist/shutdown-latch.d.ts.map +1 -0
  75. package/dist/shutdown-latch.js +51 -0
  76. package/dist/shutdown-latch.js.map +1 -0
  77. package/package.json +69 -0
  78. package/src/connection.ts +235 -0
  79. package/src/errors.ts +173 -0
  80. package/src/event-processor-info.ts +53 -0
  81. package/src/flow-controlled-sender.ts +73 -0
  82. package/src/generated/command.ts +1226 -0
  83. package/src/generated/common.ts +770 -0
  84. package/src/generated/eventstore.ts +2241 -0
  85. package/src/generated/platform.ts +1914 -0
  86. package/src/generated/query.ts +2571 -0
  87. package/src/generated/snapshot.ts +1110 -0
  88. package/src/index.ts +87 -0
  89. package/src/kronosdb-event-store.ts +401 -0
  90. package/src/kronosdb-snapshot-store.ts +104 -0
  91. package/src/kronosdb.ts +1000 -0
  92. package/src/metadata-conversion.ts +85 -0
  93. package/src/outbound-stream.ts +52 -0
  94. package/src/platform-service.ts +297 -0
  95. package/src/service-definitions.ts +25 -0
  96. package/src/shutdown-latch.ts +74 -0
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Re-exports the generated gRPC service definitions for KronosDB.
3
+ * Used internally by the connector and can be passed to connectToKronosDb().
4
+ */
5
+ import { PlatformServiceDefinition } from "./generated/platform.js";
6
+ import { CommandServiceDefinition } from "./generated/command.js";
7
+ import { QueryServiceDefinition } from "./generated/query.js";
8
+ import { EventStoreDefinition } from "./generated/eventstore.js";
9
+ import { SnapshotStoreDefinition } from "./generated/snapshot.js";
10
+ export declare const kronosDbServiceDefinitions: {
11
+ readonly platform: {
12
+ readonly name: "PlatformService";
13
+ readonly fullName: "kronosdb.platform.PlatformService";
14
+ readonly methods: {
15
+ readonly getPlatformServer: {
16
+ readonly name: "GetPlatformServer";
17
+ readonly requestType: typeof import("./generated/platform.js").ClientIdentification;
18
+ readonly requestStream: false;
19
+ readonly responseType: typeof import("./generated/platform.js").PlatformInfo;
20
+ readonly responseStream: false;
21
+ readonly options: {};
22
+ };
23
+ readonly openStream: {
24
+ readonly name: "OpenStream";
25
+ readonly requestType: typeof import("./generated/platform.js").PlatformInbound;
26
+ readonly requestStream: true;
27
+ readonly responseType: typeof import("./generated/platform.js").PlatformOutbound;
28
+ readonly responseStream: true;
29
+ readonly options: {};
30
+ };
31
+ };
32
+ };
33
+ readonly commands: {
34
+ readonly name: "CommandService";
35
+ readonly fullName: "kronosdb.command.CommandService";
36
+ readonly methods: {
37
+ readonly openStream: {
38
+ readonly name: "OpenStream";
39
+ readonly requestType: typeof import("./generated/command.js").CommandHandlerOutbound;
40
+ readonly requestStream: true;
41
+ readonly responseType: typeof import("./generated/command.js").CommandHandlerInbound;
42
+ readonly responseStream: true;
43
+ readonly options: {};
44
+ };
45
+ readonly dispatch: {
46
+ readonly name: "Dispatch";
47
+ readonly requestType: typeof import("./generated/command.js").Command;
48
+ readonly requestStream: false;
49
+ readonly responseType: typeof import("./generated/command.js").CommandResponse;
50
+ readonly responseStream: false;
51
+ readonly options: {};
52
+ };
53
+ };
54
+ };
55
+ readonly queries: {
56
+ readonly name: "QueryService";
57
+ readonly fullName: "kronosdb.query.QueryService";
58
+ readonly methods: {
59
+ readonly openStream: {
60
+ readonly name: "OpenStream";
61
+ readonly requestType: typeof import("./generated/query.js").QueryHandlerOutbound;
62
+ readonly requestStream: true;
63
+ readonly responseType: typeof import("./generated/query.js").QueryHandlerInbound;
64
+ readonly responseStream: true;
65
+ readonly options: {};
66
+ };
67
+ readonly query: {
68
+ readonly name: "Query";
69
+ readonly requestType: typeof import("./generated/query.js").QueryRequest;
70
+ readonly requestStream: false;
71
+ readonly responseType: typeof import("./generated/query.js").QueryResponse;
72
+ readonly responseStream: true;
73
+ readonly options: {};
74
+ };
75
+ readonly subscription: {
76
+ readonly name: "Subscription";
77
+ readonly requestType: typeof import("./generated/query.js").SubscriptionQueryRequest;
78
+ readonly requestStream: true;
79
+ readonly responseType: typeof import("./generated/query.js").SubscriptionQueryResponse;
80
+ readonly responseStream: true;
81
+ readonly options: {};
82
+ };
83
+ };
84
+ };
85
+ readonly eventStore: {
86
+ readonly name: "EventStore";
87
+ readonly fullName: "kronosdb.eventstore.EventStore";
88
+ readonly methods: {
89
+ readonly append: {
90
+ readonly name: "Append";
91
+ readonly requestType: typeof import("./generated/eventstore.js").AppendRequest;
92
+ readonly requestStream: true;
93
+ readonly responseType: typeof import("./generated/eventstore.js").AppendResponse;
94
+ readonly responseStream: false;
95
+ readonly options: {};
96
+ };
97
+ readonly source: {
98
+ readonly name: "Source";
99
+ readonly requestType: typeof import("./generated/eventstore.js").SourceRequest;
100
+ readonly requestStream: false;
101
+ readonly responseType: typeof import("./generated/eventstore.js").SourceResponse;
102
+ readonly responseStream: true;
103
+ readonly options: {};
104
+ };
105
+ readonly stream: {
106
+ readonly name: "Stream";
107
+ readonly requestType: typeof import("./generated/eventstore.js").StreamControl;
108
+ readonly requestStream: true;
109
+ readonly responseType: typeof import("./generated/eventstore.js").StreamResponse;
110
+ readonly responseStream: true;
111
+ readonly options: {};
112
+ };
113
+ readonly getHead: {
114
+ readonly name: "GetHead";
115
+ readonly requestType: typeof import("./generated/eventstore.js").GetHeadRequest;
116
+ readonly requestStream: false;
117
+ readonly responseType: typeof import("./generated/eventstore.js").GetHeadResponse;
118
+ readonly responseStream: false;
119
+ readonly options: {};
120
+ };
121
+ readonly getTail: {
122
+ readonly name: "GetTail";
123
+ readonly requestType: typeof import("./generated/eventstore.js").GetTailRequest;
124
+ readonly requestStream: false;
125
+ readonly responseType: typeof import("./generated/eventstore.js").GetTailResponse;
126
+ readonly responseStream: false;
127
+ readonly options: {};
128
+ };
129
+ readonly getTags: {
130
+ readonly name: "GetTags";
131
+ readonly requestType: typeof import("./generated/eventstore.js").GetTagsRequest;
132
+ readonly requestStream: false;
133
+ readonly responseType: typeof import("./generated/eventstore.js").GetTagsResponse;
134
+ readonly responseStream: false;
135
+ readonly options: {};
136
+ };
137
+ readonly getSequenceAt: {
138
+ readonly name: "GetSequenceAt";
139
+ readonly requestType: typeof import("./generated/eventstore.js").GetSequenceAtRequest;
140
+ readonly requestStream: false;
141
+ readonly responseType: typeof import("./generated/eventstore.js").GetSequenceAtResponse;
142
+ readonly responseStream: false;
143
+ readonly options: {};
144
+ };
145
+ };
146
+ };
147
+ readonly snapshotStore: {
148
+ readonly name: "SnapshotStore";
149
+ readonly fullName: "kronosdb.snapshot.SnapshotStore";
150
+ readonly methods: {
151
+ readonly add: {
152
+ readonly name: "Add";
153
+ readonly requestType: typeof import("./generated/snapshot.js").AddSnapshotRequest;
154
+ readonly requestStream: false;
155
+ readonly responseType: typeof import("./generated/snapshot.js").AddSnapshotResponse;
156
+ readonly responseStream: false;
157
+ readonly options: {};
158
+ };
159
+ readonly delete: {
160
+ readonly name: "Delete";
161
+ readonly requestType: typeof import("./generated/snapshot.js").DeleteSnapshotsRequest;
162
+ readonly requestStream: false;
163
+ readonly responseType: typeof import("./generated/snapshot.js").DeleteSnapshotsResponse;
164
+ readonly responseStream: false;
165
+ readonly options: {};
166
+ };
167
+ readonly list: {
168
+ readonly name: "List";
169
+ readonly requestType: typeof import("./generated/snapshot.js").ListSnapshotsRequest;
170
+ readonly requestStream: false;
171
+ readonly responseType: typeof import("./generated/snapshot.js").ListSnapshotsResponse;
172
+ readonly responseStream: true;
173
+ readonly options: {};
174
+ };
175
+ readonly getLast: {
176
+ readonly name: "GetLast";
177
+ readonly requestType: typeof import("./generated/snapshot.js").GetLastSnapshotRequest;
178
+ readonly requestStream: false;
179
+ readonly responseType: typeof import("./generated/snapshot.js").GetLastSnapshotResponse;
180
+ readonly responseStream: false;
181
+ readonly options: {};
182
+ };
183
+ };
184
+ };
185
+ };
186
+ export { PlatformServiceDefinition, CommandServiceDefinition, QueryServiceDefinition, EventStoreDefinition, SnapshotStoreDefinition, };
187
+ //# sourceMappingURL=service-definitions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-definitions.d.ts","sourceRoot":"","sources":["../src/service-definitions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAA;AACnE,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAA;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAA;AAEjE,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAM7B,CAAA;AAEV,OAAO,EACL,yBAAyB,EACzB,wBAAwB,EACxB,sBAAsB,EACtB,oBAAoB,EACpB,uBAAuB,GACxB,CAAA"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Re-exports the generated gRPC service definitions for KronosDB.
3
+ * Used internally by the connector and can be passed to connectToKronosDb().
4
+ */
5
+ import { PlatformServiceDefinition } from "./generated/platform.js";
6
+ import { CommandServiceDefinition } from "./generated/command.js";
7
+ import { QueryServiceDefinition } from "./generated/query.js";
8
+ import { EventStoreDefinition } from "./generated/eventstore.js";
9
+ import { SnapshotStoreDefinition } from "./generated/snapshot.js";
10
+ export const kronosDbServiceDefinitions = {
11
+ platform: PlatformServiceDefinition,
12
+ commands: CommandServiceDefinition,
13
+ queries: QueryServiceDefinition,
14
+ eventStore: EventStoreDefinition,
15
+ snapshotStore: SnapshotStoreDefinition,
16
+ };
17
+ export { PlatformServiceDefinition, CommandServiceDefinition, QueryServiceDefinition, EventStoreDefinition, SnapshotStoreDefinition, };
18
+ //# sourceMappingURL=service-definitions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-definitions.js","sourceRoot":"","sources":["../src/service-definitions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAA;AACnE,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAA;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAA;AAEjE,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,QAAQ,EAAE,yBAAyB;IACnC,QAAQ,EAAE,wBAAwB;IAClC,OAAO,EAAE,sBAAsB;IAC/B,UAAU,EAAE,oBAAoB;IAChC,aAAa,EAAE,uBAAuB;CAC9B,CAAA;AAEV,OAAO,EACL,yBAAyB,EACzB,wBAAwB,EACxB,sBAAsB,EACtB,oBAAoB,EACpB,uBAAuB,GACxB,CAAA"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * A shutdown latch that tracks in-flight operations and enables
3
+ * graceful shutdown by draining pending work.
4
+ */
5
+ export interface ShutdownLatch {
6
+ registerActivity(): ActivityHandle;
7
+ initiateShutdown(): Promise<void>;
8
+ readonly shuttingDown: boolean;
9
+ readonly activeCount: number;
10
+ }
11
+ export interface ActivityHandle {
12
+ end(): void;
13
+ }
14
+ export declare class ShutdownInProgressError extends Error {
15
+ constructor(message?: string);
16
+ }
17
+ export declare function createShutdownLatch(): ShutdownLatch;
18
+ //# sourceMappingURL=shutdown-latch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shutdown-latch.d.ts","sourceRoot":"","sources":["../src/shutdown-latch.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,gBAAgB,IAAI,cAAc,CAAA;IAClC,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACjC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAA;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,IAAI,IAAI,CAAA;CACZ;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,OAAO,GAAE,MAA+B;CAIrD;AAED,wBAAgB,mBAAmB,IAAI,aAAa,CAmDnD"}
@@ -0,0 +1,51 @@
1
+ export class ShutdownInProgressError extends Error {
2
+ constructor(message = "Shutdown in progress") {
3
+ super(message);
4
+ this.name = "ShutdownInProgressError";
5
+ }
6
+ }
7
+ export function createShutdownLatch() {
8
+ let activeCount = 0;
9
+ let shuttingDown = false;
10
+ let drainResolve = null;
11
+ function checkDrained() {
12
+ if (shuttingDown && activeCount === 0 && drainResolve) {
13
+ drainResolve();
14
+ drainResolve = null;
15
+ }
16
+ }
17
+ return {
18
+ registerActivity() {
19
+ if (shuttingDown) {
20
+ throw new ShutdownInProgressError();
21
+ }
22
+ activeCount++;
23
+ let ended = false;
24
+ return {
25
+ end() {
26
+ if (ended)
27
+ return;
28
+ ended = true;
29
+ activeCount--;
30
+ checkDrained();
31
+ },
32
+ };
33
+ },
34
+ initiateShutdown() {
35
+ shuttingDown = true;
36
+ if (activeCount === 0) {
37
+ return Promise.resolve();
38
+ }
39
+ return new Promise((resolve) => {
40
+ drainResolve = resolve;
41
+ });
42
+ },
43
+ get shuttingDown() {
44
+ return shuttingDown;
45
+ },
46
+ get activeCount() {
47
+ return activeCount;
48
+ },
49
+ };
50
+ }
51
+ //# sourceMappingURL=shutdown-latch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shutdown-latch.js","sourceRoot":"","sources":["../src/shutdown-latch.ts"],"names":[],"mappings":"AAeA,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IAChD,YAAY,UAAkB,sBAAsB;QAClD,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAA;IACvC,CAAC;CACF;AAED,MAAM,UAAU,mBAAmB;IACjC,IAAI,WAAW,GAAG,CAAC,CAAA;IACnB,IAAI,YAAY,GAAG,KAAK,CAAA;IACxB,IAAI,YAAY,GAAwB,IAAI,CAAA;IAE5C,SAAS,YAAY;QACnB,IAAI,YAAY,IAAI,WAAW,KAAK,CAAC,IAAI,YAAY,EAAE,CAAC;YACtD,YAAY,EAAE,CAAA;YACd,YAAY,GAAG,IAAI,CAAA;QACrB,CAAC;IACH,CAAC;IAED,OAAO;QACL,gBAAgB;YACd,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,IAAI,uBAAuB,EAAE,CAAA;YACrC,CAAC;YAED,WAAW,EAAE,CAAA;YACb,IAAI,KAAK,GAAG,KAAK,CAAA;YAEjB,OAAO;gBACL,GAAG;oBACD,IAAI,KAAK;wBAAE,OAAM;oBACjB,KAAK,GAAG,IAAI,CAAA;oBACZ,WAAW,EAAE,CAAA;oBACb,YAAY,EAAE,CAAA;gBAChB,CAAC;aACF,CAAA;QACH,CAAC;QAED,gBAAgB;YACd,YAAY,GAAG,IAAI,CAAA;YAEnB,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC;gBACtB,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;YAC1B,CAAC;YAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBAC7B,YAAY,GAAG,OAAO,CAAA;YACxB,CAAC,CAAC,CAAA;QACJ,CAAC;QAED,IAAI,YAAY;YACd,OAAO,YAAY,CAAA;QACrB,CAAC;QAED,IAAI,WAAW;YACb,OAAO,WAAW,CAAA;QACpB,CAAC;KACF,CAAA;AACH,CAAC"}
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@kronos-ts/kronosdb",
3
+ "version": "0.1.0",
4
+ "description": "KronosDB extension for Kronos — native event store transport.",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "author": "Theo Emanuelsson",
8
+ "homepage": "https://github.com/KronosDB/kronos-ts/tree/main/packages/extensions/kronosdb#readme",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/KronosDB/kronos-ts.git",
12
+ "directory": "packages/extensions/kronosdb"
13
+ },
14
+ "bugs": {
15
+ "url": "https://github.com/KronosDB/kronos-ts/issues"
16
+ },
17
+ "keywords": [
18
+ "kronos",
19
+ "event-sourcing",
20
+ "cqrs",
21
+ "dcb",
22
+ "typescript",
23
+ "kronosdb"
24
+ ],
25
+ "sideEffects": false,
26
+ "main": "src/index.ts",
27
+ "types": "src/index.ts",
28
+ "files": [
29
+ "dist",
30
+ "src",
31
+ "!src/**/__tests__",
32
+ "!src/**/*.test.ts",
33
+ "!src/**/*.bench.ts"
34
+ ],
35
+ "scripts": {
36
+ "generate-proto": "grpc_tools_node_protoc --ts_proto_out=./src/generated --ts_proto_opt=outputServices=nice-grpc,outputServices=generic-definitions,useExactTypes=false,esModuleInterop=true,forceLong=bigint --proto_path=./proto ./proto/*.proto",
37
+ "build": "tsc -p tsconfig.json",
38
+ "clean": "rm -rf dist *.tsbuildinfo"
39
+ },
40
+ "publishConfig": {
41
+ "access": "public",
42
+ "main": "./dist/index.js",
43
+ "types": "./dist/index.d.ts",
44
+ "exports": {
45
+ ".": {
46
+ "types": "./dist/index.d.ts",
47
+ "default": "./dist/index.js"
48
+ }
49
+ }
50
+ },
51
+ "dependencies": {
52
+ "@kronos-ts/common": "workspace:*",
53
+ "@kronos-ts/app": "workspace:*",
54
+ "@kronos-ts/eventsourcing": "workspace:*",
55
+ "@kronos-ts/messaging": "workspace:*",
56
+ "@kronos-ts/modelling": "workspace:*",
57
+ "@bufbuild/protobuf": "^2.3",
58
+ "@grpc/grpc-js": "^1.12",
59
+ "nice-grpc": "^2.1",
60
+ "nice-grpc-common": "^2.0",
61
+ "zod": "^4.3.6"
62
+ },
63
+ "devDependencies": {
64
+ "grpc-tools": "^1.12",
65
+ "grpc_tools_node_protoc_ts": "^5.3",
66
+ "testcontainers": "^11.13.0",
67
+ "ts-proto": "^2.6"
68
+ }
69
+ }
@@ -0,0 +1,235 @@
1
+ import { createChannel, createClient, type Channel, type Client, type ChannelCredentials } from "nice-grpc"
2
+ import { ChannelCredentials as GrpcChannelCredentials } from "@grpc/grpc-js"
3
+ import { Metadata } from "nice-grpc"
4
+ import { readFileSync } from "node:fs"
5
+ import {
6
+ kronosDbServiceDefinitions,
7
+ PlatformServiceDefinition,
8
+ CommandServiceDefinition,
9
+ QueryServiceDefinition,
10
+ EventStoreDefinition,
11
+ SnapshotStoreDefinition,
12
+ } from "./service-definitions.js"
13
+
14
+ /**
15
+ * Configuration for connecting to KronosDB.
16
+ */
17
+ export interface KronosDbConnectionConfig {
18
+ /** Host of the KronosDB server. Defaults to "localhost". */
19
+ host?: string
20
+ /** gRPC port of the KronosDB server. Defaults to 50051. */
21
+ port?: number
22
+ /**
23
+ * Multiple server addresses for cluster deployments.
24
+ * Each entry is `"host:port"`. When provided, overrides `host` and `port`.
25
+ * The connector tries servers in order and fails over to the next on failure.
26
+ */
27
+ servers?: string[]
28
+ /** The context to connect to. Defaults to "default". */
29
+ context?: string
30
+ /** Name identifying this component to KronosDB. */
31
+ componentName: string
32
+ /** Unique client identifier. Defaults to a generated UUID. */
33
+ clientId?: string
34
+ /** Access token for authentication. Optional. */
35
+ token?: string
36
+ /** Reconnection interval in ms. Defaults to 2000. */
37
+ reconnectIntervalMs?: number
38
+ /** Maximum reconnection attempts before giving up. 0 = unlimited. Defaults to 0. */
39
+ maxReconnectAttempts?: number
40
+
41
+ /** gRPC keepalive ping interval in ms. Default: 30000. */
42
+ keepAliveTimeMs?: number
43
+ /** gRPC keepalive timeout in ms. Default: 10000. */
44
+ keepAliveTimeoutMs?: number
45
+ /** Allow keepalive pings without active RPCs. Default: true. */
46
+ keepAlivePermitWithoutCalls?: boolean
47
+
48
+ /** TLS/SSL configuration. */
49
+ ssl?: {
50
+ enabled: boolean
51
+ certFile?: string
52
+ clientCertFile?: string
53
+ clientKeyFile?: string
54
+ }
55
+ }
56
+
57
+ export type ConnectionState = "disconnected" | "connecting" | "connected" | "reconnecting" | "closed"
58
+
59
+ /**
60
+ * An active connection to KronosDB, providing typed gRPC clients
61
+ * for all services. Supports reconnection on failure.
62
+ */
63
+ export interface KronosDbConnection {
64
+ readonly channel: Channel
65
+ /** Platform service client. */
66
+ readonly platform: Client<typeof PlatformServiceDefinition>
67
+ /** Command service client. */
68
+ readonly commands: Client<typeof CommandServiceDefinition>
69
+ /** Query service client. */
70
+ readonly queries: Client<typeof QueryServiceDefinition>
71
+ /** Event store client. */
72
+ readonly eventStore: Client<typeof EventStoreDefinition>
73
+ /** Snapshot store client. */
74
+ readonly snapshotStore: Client<typeof SnapshotStoreDefinition>
75
+ /** The resolved configuration. `servers` and `ssl` stay optional — they have no defaults. */
76
+ readonly config: Omit<Required<KronosDbConnectionConfig>, "servers" | "ssl"> & {
77
+ servers?: KronosDbConnectionConfig["servers"]
78
+ ssl?: KronosDbConnectionConfig["ssl"]
79
+ }
80
+ readonly state: ConnectionState
81
+ onReconnect(callback: () => void): void
82
+ onDisconnect(callback: (error?: Error) => void): void
83
+ close(): void
84
+ reconnect(): Promise<void>
85
+ }
86
+
87
+ /**
88
+ * Creates gRPC metadata for KronosDB requests.
89
+ * Injects context and optional auth token as headers.
90
+ */
91
+ export function createKronosMetadata(config: { context: string; token: string }): Metadata {
92
+ const metadata = new Metadata()
93
+ metadata.set("kronosdb-context", config.context)
94
+ if (config.token) {
95
+ metadata.set("kronosdb-token", config.token)
96
+ }
97
+ return metadata
98
+ }
99
+
100
+ /**
101
+ * Connects to KronosDB and returns typed gRPC clients for all services.
102
+ *
103
+ * Configures gRPC channel-level keepalive to maintain persistent connections.
104
+ */
105
+ export function connectToKronosDb(config: KronosDbConnectionConfig): KronosDbConnection {
106
+ const serviceDefinitions = kronosDbServiceDefinitions
107
+ const resolvedConfig = {
108
+ host: config.host ?? "localhost",
109
+ port: config.port ?? 50051,
110
+ context: config.context ?? "default",
111
+ componentName: config.componentName,
112
+ clientId: config.clientId ?? crypto.randomUUID(),
113
+ token: config.token ?? "",
114
+ reconnectIntervalMs: config.reconnectIntervalMs ?? 2000,
115
+ maxReconnectAttempts: config.maxReconnectAttempts ?? 0,
116
+ keepAliveTimeMs: config.keepAliveTimeMs ?? 30000,
117
+ keepAliveTimeoutMs: config.keepAliveTimeoutMs ?? 10000,
118
+ keepAlivePermitWithoutCalls: config.keepAlivePermitWithoutCalls ?? true,
119
+ servers: config.servers,
120
+ ssl: config.ssl,
121
+ }
122
+
123
+ const sslConfig = config.ssl
124
+ let credentials: ChannelCredentials | undefined
125
+
126
+ if (sslConfig?.enabled) {
127
+ const rootCerts = sslConfig.certFile ? readFileSync(sslConfig.certFile) : null
128
+ const clientKey = sslConfig.clientKeyFile ? readFileSync(sslConfig.clientKeyFile) : null
129
+ const clientCert = sslConfig.clientCertFile ? readFileSync(sslConfig.clientCertFile) : null
130
+ credentials = GrpcChannelCredentials.createSsl(rootCerts, clientKey, clientCert) as ChannelCredentials
131
+ }
132
+
133
+ const channelOptions = {
134
+ "grpc.keepalive_time_ms": config.keepAliveTimeMs ?? 30000,
135
+ "grpc.keepalive_timeout_ms": config.keepAliveTimeoutMs ?? 10000,
136
+ "grpc.keepalive_permit_without_calls": (config.keepAlivePermitWithoutCalls ?? true) ? 1 : 0,
137
+ }
138
+
139
+ const serverAddresses = config.servers && config.servers.length > 0
140
+ ? config.servers
141
+ : [`${resolvedConfig.host}:${resolvedConfig.port}`]
142
+
143
+ let currentServerIndex = 0
144
+
145
+ function createGrpcChannel(): Channel {
146
+ const address = serverAddresses[currentServerIndex % serverAddresses.length]!
147
+ return credentials
148
+ ? createChannel(address, credentials, channelOptions)
149
+ : createChannel(address, undefined, channelOptions)
150
+ }
151
+
152
+ let channel = createGrpcChannel()
153
+ let state: ConnectionState = "connected"
154
+
155
+ const reconnectCallbacks: Array<() => void> = []
156
+ const disconnectCallbacks: Array<(error?: Error) => void> = []
157
+
158
+ function createClients() {
159
+ return {
160
+ platform: createClient(serviceDefinitions.platform, channel),
161
+ commands: createClient(serviceDefinitions.commands, channel),
162
+ queries: createClient(serviceDefinitions.queries, channel),
163
+ eventStore: createClient(serviceDefinitions.eventStore, channel),
164
+ snapshotStore: createClient(serviceDefinitions.snapshotStore, channel),
165
+ }
166
+ }
167
+
168
+ let clients = createClients()
169
+
170
+ const connection: KronosDbConnection = {
171
+ get channel() { return channel },
172
+ get platform() { return clients.platform },
173
+ get commands() { return clients.commands },
174
+ get queries() { return clients.queries },
175
+ get eventStore() { return clients.eventStore },
176
+ get snapshotStore() { return clients.snapshotStore },
177
+ config: resolvedConfig,
178
+
179
+ get state() { return state },
180
+
181
+ onReconnect(callback) {
182
+ reconnectCallbacks.push(callback)
183
+ },
184
+
185
+ onDisconnect(callback) {
186
+ disconnectCallbacks.push(callback)
187
+ },
188
+
189
+ close() {
190
+ state = "closed"
191
+ channel.close()
192
+ },
193
+
194
+ async reconnect() {
195
+ if (state === "closed") {
196
+ throw new Error("Connection is permanently closed")
197
+ }
198
+ if (state === "connected" || state === "connecting") return
199
+
200
+ state = "reconnecting"
201
+ const maxAttempts = resolvedConfig.maxReconnectAttempts
202
+ let attempt = 0
203
+
204
+ while (state === "reconnecting") {
205
+ attempt++
206
+ try {
207
+ currentServerIndex++
208
+ channel = createGrpcChannel()
209
+ clients = createClients()
210
+ state = "connected"
211
+
212
+ for (const cb of reconnectCallbacks) {
213
+ try { cb() } catch { /* ignore listener errors */ }
214
+ }
215
+ return
216
+ } catch (err) {
217
+ if (maxAttempts > 0 && attempt >= maxAttempts) {
218
+ state = "disconnected"
219
+ throw new Error(
220
+ `Failed to reconnect after ${attempt} attempts: ${err}`,
221
+ )
222
+ }
223
+
224
+ const delay = Math.min(
225
+ resolvedConfig.reconnectIntervalMs * Math.pow(2, attempt - 1),
226
+ 30000,
227
+ )
228
+ await new Promise((r) => setTimeout(r, delay))
229
+ }
230
+ }
231
+ },
232
+ }
233
+
234
+ return connection
235
+ }