mindoodb 0.0.85 → 0.0.86

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 (235) hide show
  1. package/README-server.md +1 -0
  2. package/README.md +6 -4
  3. package/dist/cloudflare/DurableObjectSql.d.ts +56 -0
  4. package/dist/cloudflare/DurableObjectSql.d.ts.map +1 -0
  5. package/dist/cloudflare/DurableObjectSql.js +180 -0
  6. package/dist/cloudflare/DurableObjectSql.js.map +1 -0
  7. package/dist/cloudflare/MindooDatabaseObject.d.ts +86 -0
  8. package/dist/cloudflare/MindooDatabaseObject.d.ts.map +1 -0
  9. package/dist/cloudflare/MindooDatabaseObject.js +614 -0
  10. package/dist/cloudflare/MindooDatabaseObject.js.map +1 -0
  11. package/dist/cloudflare/MindooServerObject.d.ts +63 -0
  12. package/dist/cloudflare/MindooServerObject.d.ts.map +1 -0
  13. package/dist/cloudflare/MindooServerObject.js +521 -0
  14. package/dist/cloudflare/MindooServerObject.js.map +1 -0
  15. package/dist/cloudflare/WorkersCryptoAdapter.d.ts +7 -0
  16. package/dist/cloudflare/WorkersCryptoAdapter.d.ts.map +1 -0
  17. package/dist/cloudflare/WorkersCryptoAdapter.js +14 -0
  18. package/dist/cloudflare/WorkersCryptoAdapter.js.map +1 -0
  19. package/dist/cloudflare/host.d.ts +49 -0
  20. package/dist/cloudflare/host.d.ts.map +1 -0
  21. package/dist/cloudflare/host.js +104 -0
  22. package/dist/cloudflare/host.js.map +1 -0
  23. package/dist/cloudflare/http.d.ts +91 -0
  24. package/dist/cloudflare/http.d.ts.map +1 -0
  25. package/dist/cloudflare/http.js +266 -0
  26. package/dist/cloudflare/http.js.map +1 -0
  27. package/dist/cloudflare/index.d.ts +12 -0
  28. package/dist/cloudflare/index.d.ts.map +1 -0
  29. package/dist/cloudflare/index.js +20 -0
  30. package/dist/cloudflare/index.js.map +1 -0
  31. package/dist/cloudflare/storeRpc.d.ts +22 -0
  32. package/dist/cloudflare/storeRpc.d.ts.map +1 -0
  33. package/dist/cloudflare/storeRpc.js +85 -0
  34. package/dist/cloudflare/storeRpc.js.map +1 -0
  35. package/dist/cloudflare/types.d.ts +101 -0
  36. package/dist/cloudflare/types.d.ts.map +1 -0
  37. package/dist/cloudflare/types.js +10 -0
  38. package/dist/cloudflare/types.js.map +1 -0
  39. package/dist/cloudflare/worker.d.ts +25 -0
  40. package/dist/cloudflare/worker.d.ts.map +1 -0
  41. package/dist/cloudflare/worker.js +170 -0
  42. package/dist/cloudflare/worker.js.map +1 -0
  43. package/dist/core/BaseMindooDB.d.ts +28 -1
  44. package/dist/core/BaseMindooDB.d.ts.map +1 -1
  45. package/dist/core/BaseMindooDB.js +180 -86
  46. package/dist/core/BaseMindooDB.js.map +1 -1
  47. package/dist/core/BaseMindooTenant.d.ts +14 -0
  48. package/dist/core/BaseMindooTenant.d.ts.map +1 -1
  49. package/dist/core/BaseMindooTenant.js +46 -0
  50. package/dist/core/BaseMindooTenant.js.map +1 -1
  51. package/dist/core/BaseMindooTenantDirectory.d.ts +10 -0
  52. package/dist/core/BaseMindooTenantDirectory.d.ts.map +1 -1
  53. package/dist/core/BaseMindooTenantDirectory.js +79 -8
  54. package/dist/core/BaseMindooTenantDirectory.js.map +1 -1
  55. package/dist/core/ChangeDocDraft.d.ts +133 -0
  56. package/dist/core/ChangeDocDraft.d.ts.map +1 -0
  57. package/dist/core/ChangeDocDraft.js +492 -0
  58. package/dist/core/ChangeDocDraft.js.map +1 -0
  59. package/dist/core/appendonlystores/network/AuthenticationService.d.ts +8 -0
  60. package/dist/core/appendonlystores/network/AuthenticationService.d.ts.map +1 -1
  61. package/dist/core/appendonlystores/network/AuthenticationService.js +19 -0
  62. package/dist/core/appendonlystores/network/AuthenticationService.js.map +1 -1
  63. package/dist/core/appendonlystores/network/IrohStreamIO.d.ts.map +1 -1
  64. package/dist/core/appendonlystores/network/IrohStreamIO.js +3 -23
  65. package/dist/core/appendonlystores/network/IrohStreamIO.js.map +1 -1
  66. package/dist/core/appendonlystores/rpc/storeRpcCodec.d.ts.map +1 -1
  67. package/dist/core/appendonlystores/rpc/storeRpcCodec.js +3 -23
  68. package/dist/core/appendonlystores/rpc/storeRpcCodec.js.map +1 -1
  69. package/dist/core/appendonlystores/sqlite/SqliteContentAddressedStore.d.ts.map +1 -1
  70. package/dist/core/appendonlystores/sqlite/SqliteContentAddressedStore.js +21 -30
  71. package/dist/core/appendonlystores/sqlite/SqliteContentAddressedStore.js.map +1 -1
  72. package/dist/core/appendonlystores/sqlite/SqliteDriver.d.ts +37 -1
  73. package/dist/core/appendonlystores/sqlite/SqliteDriver.d.ts.map +1 -1
  74. package/dist/core/appendonlystores/sqlite/SqliteDriver.js +99 -40
  75. package/dist/core/appendonlystores/sqlite/SqliteDriver.js.map +1 -1
  76. package/dist/core/expressions/evaluateExpression.d.ts +8 -0
  77. package/dist/core/expressions/evaluateExpression.d.ts.map +1 -1
  78. package/dist/core/expressions/evaluateExpression.js +29 -4
  79. package/dist/core/expressions/evaluateExpression.js.map +1 -1
  80. package/dist/core/expressions/metadata.js +4 -4
  81. package/dist/core/expressions/metadata.js.map +1 -1
  82. package/dist/core/types.d.ts +61 -2
  83. package/dist/core/types.d.ts.map +1 -1
  84. package/dist/core/types.js.map +1 -1
  85. package/dist/core/uri/MindooURI.d.ts.map +1 -1
  86. package/dist/core/uri/MindooURI.js +3 -24
  87. package/dist/core/uri/MindooURI.js.map +1 -1
  88. package/dist/core/utils/base64.d.ts +17 -0
  89. package/dist/core/utils/base64.d.ts.map +1 -0
  90. package/dist/core/utils/base64.js +54 -0
  91. package/dist/core/utils/base64.js.map +1 -0
  92. package/dist/core/utils/idGeneration.d.ts.map +1 -1
  93. package/dist/core/utils/idGeneration.js +14 -3
  94. package/dist/core/utils/idGeneration.js.map +1 -1
  95. package/dist/node/server/FsServerDataStore.d.ts +23 -0
  96. package/dist/node/server/FsServerDataStore.d.ts.map +1 -0
  97. package/dist/node/server/FsServerDataStore.js +59 -0
  98. package/dist/node/server/FsServerDataStore.js.map +1 -0
  99. package/dist/node/server/IrohServerEndpoint.d.ts +1 -1
  100. package/dist/node/server/IrohServerEndpoint.d.ts.map +1 -1
  101. package/dist/node/server/IrohServerRpc.d.ts +5 -5
  102. package/dist/node/server/IrohServerRpc.d.ts.map +1 -1
  103. package/dist/node/server/IrohServerRpc.js +1 -1
  104. package/dist/node/server/IrohServerRpc.js.map +1 -1
  105. package/dist/node/server/MindooDBServer.d.ts +29 -150
  106. package/dist/node/server/MindooDBServer.d.ts.map +1 -1
  107. package/dist/node/server/MindooDBServer.js +160 -1573
  108. package/dist/node/server/MindooDBServer.js.map +1 -1
  109. package/dist/node/server/PurgedDocRegistry.d.ts +4 -27
  110. package/dist/node/server/PurgedDocRegistry.d.ts.map +1 -1
  111. package/dist/node/server/PurgedDocRegistry.js +6 -83
  112. package/dist/node/server/PurgedDocRegistry.js.map +1 -1
  113. package/dist/node/server/StoreFactory.d.ts +1 -1
  114. package/dist/node/server/StoreFactory.d.ts.map +1 -1
  115. package/dist/node/server/TenantManager.d.ts +16 -284
  116. package/dist/node/server/TenantManager.d.ts.map +1 -1
  117. package/dist/node/server/TenantManager.js +35 -1168
  118. package/dist/node/server/TenantManager.js.map +1 -1
  119. package/dist/node/server/add-to-network.js +1 -1
  120. package/dist/node/server/add-to-network.js.map +1 -1
  121. package/dist/node/server/config.d.ts +11 -15
  122. package/dist/node/server/config.d.ts.map +1 -1
  123. package/dist/node/server/config.js +30 -245
  124. package/dist/node/server/config.js.map +1 -1
  125. package/dist/node/server/expressAdapter.d.ts +23 -0
  126. package/dist/node/server/expressAdapter.d.ts.map +1 -0
  127. package/dist/node/server/expressAdapter.js +108 -0
  128. package/dist/node/server/expressAdapter.js.map +1 -0
  129. package/dist/node/server/nativeIrohStreamIO.d.ts +1 -1
  130. package/dist/node/server/nativeIrohStreamIO.d.ts.map +1 -1
  131. package/dist/node/server/peer/FileClusterAuditStorage.d.ts +16 -0
  132. package/dist/node/server/peer/FileClusterAuditStorage.d.ts.map +1 -0
  133. package/dist/node/server/peer/FileClusterAuditStorage.js +39 -0
  134. package/dist/node/server/peer/FileClusterAuditStorage.js.map +1 -0
  135. package/dist/node/server/peer/IrohPeerLink.d.ts +1 -1
  136. package/dist/node/server/peer/IrohPeerLink.d.ts.map +1 -1
  137. package/dist/node/server/peer/routes.d.ts +10 -44
  138. package/dist/node/server/peer/routes.d.ts.map +1 -1
  139. package/dist/node/server/peer/routes.js +33 -275
  140. package/dist/node/server/peer/routes.js.map +1 -1
  141. package/dist/node/server/resolveServerPassword.js +1 -1
  142. package/dist/node/server/resolveServerPassword.js.map +1 -1
  143. package/dist/node/server/server.js +1 -1
  144. package/dist/node/server/server.js.map +1 -1
  145. package/dist/node/server/serverinit.js +1 -1
  146. package/dist/node/server/serverinit.js.map +1 -1
  147. package/dist/server/CapabilityMatcher.d.ts +60 -0
  148. package/dist/server/CapabilityMatcher.d.ts.map +1 -0
  149. package/dist/server/CapabilityMatcher.js +138 -0
  150. package/dist/server/CapabilityMatcher.js.map +1 -0
  151. package/dist/server/DeviceDiscoveryService.d.ts +36 -0
  152. package/dist/server/DeviceDiscoveryService.d.ts.map +1 -0
  153. package/dist/server/DeviceDiscoveryService.js +165 -0
  154. package/dist/server/DeviceDiscoveryService.js.map +1 -0
  155. package/dist/server/PurgedDocRegistry.d.ts +35 -0
  156. package/dist/server/PurgedDocRegistry.d.ts.map +1 -0
  157. package/dist/server/PurgedDocRegistry.js +90 -0
  158. package/dist/server/PurgedDocRegistry.js.map +1 -0
  159. package/dist/server/ServerDataStore.d.ts +67 -0
  160. package/dist/server/ServerDataStore.d.ts.map +1 -0
  161. package/dist/server/ServerDataStore.js +88 -0
  162. package/dist/server/ServerDataStore.js.map +1 -0
  163. package/dist/server/SyncEventBus.d.ts +39 -0
  164. package/dist/server/SyncEventBus.d.ts.map +1 -0
  165. package/dist/server/SyncEventBus.js +41 -0
  166. package/dist/server/SyncEventBus.js.map +1 -0
  167. package/dist/server/SystemAdminAuth.d.ts +82 -0
  168. package/dist/server/SystemAdminAuth.d.ts.map +1 -0
  169. package/dist/server/SystemAdminAuth.js +228 -0
  170. package/dist/server/SystemAdminAuth.js.map +1 -0
  171. package/dist/server/TenantManager.d.ts +330 -0
  172. package/dist/server/TenantManager.d.ts.map +1 -0
  173. package/dist/server/TenantManager.js +1186 -0
  174. package/dist/server/TenantManager.js.map +1 -0
  175. package/dist/server/http/MindooDBServerCore.d.ts +313 -0
  176. package/dist/server/http/MindooDBServerCore.d.ts.map +1 -0
  177. package/dist/server/http/MindooDBServerCore.js +1403 -0
  178. package/dist/server/http/MindooDBServerCore.js.map +1 -0
  179. package/dist/server/http/types.d.ts +89 -0
  180. package/dist/server/http/types.d.ts.map +1 -0
  181. package/dist/server/http/types.js +29 -0
  182. package/dist/server/http/types.js.map +1 -0
  183. package/dist/server/index.d.ts +32 -0
  184. package/dist/server/index.d.ts.map +1 -0
  185. package/dist/server/index.js +76 -0
  186. package/dist/server/index.js.map +1 -0
  187. package/dist/server/peer/ClusterAuditLog.d.ts +71 -0
  188. package/dist/server/peer/ClusterAuditLog.d.ts.map +1 -0
  189. package/dist/server/peer/ClusterAuditLog.js +81 -0
  190. package/dist/server/peer/ClusterAuditLog.js.map +1 -0
  191. package/dist/server/peer/ClusterJobRunner.d.ts +43 -0
  192. package/dist/server/peer/ClusterJobRunner.d.ts.map +1 -0
  193. package/dist/server/peer/ClusterJobRunner.js +119 -0
  194. package/dist/server/peer/ClusterJobRunner.js.map +1 -0
  195. package/dist/server/peer/ClusterManager.d.ts +149 -0
  196. package/dist/server/peer/ClusterManager.d.ts.map +1 -0
  197. package/dist/server/peer/ClusterManager.js +292 -0
  198. package/dist/server/peer/ClusterManager.js.map +1 -0
  199. package/dist/server/peer/PeerAuthService.d.ts +69 -0
  200. package/dist/server/peer/PeerAuthService.d.ts.map +1 -0
  201. package/dist/server/peer/PeerAuthService.js +208 -0
  202. package/dist/server/peer/PeerAuthService.js.map +1 -0
  203. package/dist/server/peer/PeerReplicator.d.ts +303 -0
  204. package/dist/server/peer/PeerReplicator.d.ts.map +1 -0
  205. package/dist/server/peer/PeerReplicator.js +1071 -0
  206. package/dist/server/peer/PeerReplicator.js.map +1 -0
  207. package/dist/server/peer/clusterHttp.d.ts +113 -0
  208. package/dist/server/peer/clusterHttp.d.ts.map +1 -0
  209. package/dist/server/peer/clusterHttp.js +290 -0
  210. package/dist/server/peer/clusterHttp.js.map +1 -0
  211. package/dist/server/peer/types.d.ts +244 -0
  212. package/dist/server/peer/types.d.ts.map +1 -0
  213. package/dist/server/peer/types.js +189 -0
  214. package/dist/server/peer/types.js.map +1 -0
  215. package/dist/server/rateLimits.d.ts +119 -0
  216. package/dist/server/rateLimits.d.ts.map +1 -0
  217. package/dist/server/rateLimits.js +159 -0
  218. package/dist/server/rateLimits.js.map +1 -0
  219. package/dist/server/serverConfig.d.ts +37 -0
  220. package/dist/server/serverConfig.d.ts.map +1 -0
  221. package/dist/server/serverConfig.js +251 -0
  222. package/dist/server/serverConfig.js.map +1 -0
  223. package/dist/server/timestampProxy.d.ts +129 -0
  224. package/dist/server/timestampProxy.d.ts.map +1 -0
  225. package/dist/server/timestampProxy.js +361 -0
  226. package/dist/server/timestampProxy.js.map +1 -0
  227. package/dist/server/types.d.ts +267 -0
  228. package/dist/server/types.d.ts.map +1 -0
  229. package/dist/server/types.js +56 -0
  230. package/dist/server/types.js.map +1 -0
  231. package/dist/server/validation.d.ts +43 -0
  232. package/dist/server/validation.d.ts.map +1 -0
  233. package/dist/server/validation.js +104 -0
  234. package/dist/server/validation.js.map +1 -0
  235. package/package.json +9 -1
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ /**
3
+ * Glue between Express and the platform-neutral handlers in
4
+ * {@link MindooDBServerCore}: turns an Express request into a
5
+ * {@link ServerRequest} and writes a {@link ServerResponse} back.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.toServerRequest = toServerRequest;
9
+ exports.sendServerResponse = sendServerResponse;
10
+ exports.route = route;
11
+ exports.guard = guard;
12
+ const types_1 = require("../../server/http/types");
13
+ const compressionMiddleware_1 = require("./compressionMiddleware");
14
+ /** Snapshot of an Express request, including what earlier guards resolved. */
15
+ function toServerRequest(req) {
16
+ const rawBody = Buffer.isBuffer(req.body)
17
+ ? new Uint8Array(req.body.buffer, req.body.byteOffset, req.body.byteLength)
18
+ : undefined;
19
+ return {
20
+ method: req.method.toUpperCase(),
21
+ path: req.path,
22
+ params: req.params,
23
+ query: req.query,
24
+ headers: req.headers,
25
+ body: rawBody ? {} : req.body,
26
+ rawBody,
27
+ jsonBodyBytes: req.jsonBodyBytes,
28
+ httpVersion: req.httpVersion,
29
+ clientIp: req.ip,
30
+ tenantId: req.tenantId,
31
+ systemAdmin: req.systemAdmin,
32
+ syncPrincipal: req.syncPrincipal,
33
+ timestampPrincipal: req.timestampPrincipal,
34
+ peerName: req.peerName,
35
+ };
36
+ }
37
+ /** Copy what a guard resolved back onto the Express request for later middleware. */
38
+ function applyGuardResults(req, serverRequest) {
39
+ req.tenantId = serverRequest.tenantId;
40
+ req.systemAdmin = serverRequest.systemAdmin;
41
+ req.syncPrincipal = serverRequest.syncPrincipal;
42
+ req.timestampPrincipal = serverRequest.timestampPrincipal;
43
+ req.peerName = serverRequest.peerName;
44
+ }
45
+ /** Write a JSON or binary response. Event streams are the caller's business. */
46
+ async function sendServerResponse(req, res, response) {
47
+ if ((0, types_1.isJsonResponse)(response)) {
48
+ for (const [name, value] of Object.entries(response.headers ?? {})) {
49
+ res.setHeader(name, value);
50
+ }
51
+ res.status(response.status).json(response.json);
52
+ return;
53
+ }
54
+ if ((0, types_1.isBytesResponse)(response)) {
55
+ for (const [name, value] of Object.entries(response.headers)) {
56
+ res.setHeader(name, value);
57
+ }
58
+ res.status(response.status);
59
+ if (response.binaryEntryFrameBytes !== undefined) {
60
+ await (0, compressionMiddleware_1.sendBinaryEntryBody)(req, res, response.bytes, response.binaryEntryFrameBytes);
61
+ return;
62
+ }
63
+ const bytes = response.bytes;
64
+ res.send(Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength));
65
+ return;
66
+ }
67
+ throw new Error("Event stream responses must be handled by the route");
68
+ }
69
+ /**
70
+ * Express route handler running a core handler. Anything the handler did not
71
+ * turn into a response goes to the Express error handler, as a throw from a
72
+ * synchronous handler would.
73
+ */
74
+ function route(handler) {
75
+ return async (req, res, next) => {
76
+ try {
77
+ const response = await handler(toServerRequest(req));
78
+ await sendServerResponse(req, res, response);
79
+ }
80
+ catch (error) {
81
+ next(error);
82
+ }
83
+ };
84
+ }
85
+ /**
86
+ * Express middleware running a core guard: a returned response ends the
87
+ * request, null continues with the guard's results on the request.
88
+ */
89
+ function guard(check) {
90
+ return async (req, res, next) => {
91
+ const serverRequest = toServerRequest(req);
92
+ let rejection;
93
+ try {
94
+ rejection = await check(serverRequest);
95
+ }
96
+ catch (error) {
97
+ next(error);
98
+ return;
99
+ }
100
+ if (rejection) {
101
+ await sendServerResponse(req, res, rejection);
102
+ return;
103
+ }
104
+ applyGuardResults(req, serverRequest);
105
+ next();
106
+ };
107
+ }
108
+ //# sourceMappingURL=expressAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expressAdapter.js","sourceRoot":"","sources":["../../../src/node/server/expressAdapter.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { type IrohStreamIO } from "../../core/appendonlystores/network/IrohStreamIO";
2
- import type { ServerIrohConfig } from "./types";
2
+ import type { ServerIrohConfig } from "../../server/types";
3
3
  export interface NativeIrohStreamIO extends IrohStreamIO {
4
4
  endpointId?: string;
5
5
  close?(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"nativeIrohStreamIO.d.ts","sourceRoot":"","sources":["../../../src/node/server/nativeIrohStreamIO.ts"],"names":[],"mappings":"AAIA,OAAO,EAML,KAAK,YAAY,EAClB,MAAM,kDAAkD,CAAC;AAC1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD,MAAM,WAAW,kBAAmB,SAAQ,YAAY;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AA6BD,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,cAAc,eAAe,CAAC,GAAG,IAAI,CAAC,CAM3F;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,kBAAkB,CAAC,CAwE7B"}
1
+ {"version":3,"file":"nativeIrohStreamIO.d.ts","sourceRoot":"","sources":["../../../src/node/server/nativeIrohStreamIO.ts"],"names":[],"mappings":"AAIA,OAAO,EAML,KAAK,YAAY,EAClB,MAAM,kDAAkD,CAAC;AAC1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,MAAM,WAAW,kBAAmB,SAAQ,YAAY;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AA6BD,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,cAAc,eAAe,CAAC,GAAG,IAAI,CAAC,CAM3F;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,kBAAkB,CAAC,CAwE7B"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The cluster audit log on disk: `<dataDir>/cluster/audit.jsonl`, rotated to
3
+ * `audit.jsonl.<timestamp>` once it passes {@link DEFAULT_MAX_BYTES}. Only the
4
+ * active file is read back.
5
+ */
6
+ import type { ClusterAuditStorage } from "../../../server/peer/ClusterAuditLog";
7
+ export declare class FileClusterAuditStorage implements ClusterAuditStorage {
8
+ private readonly maxBytes;
9
+ private readonly dir;
10
+ private readonly file;
11
+ constructor(dataDir: string, maxBytes?: number);
12
+ appendLine(line: string): void;
13
+ readLines(): string[];
14
+ private rotateIfNeeded;
15
+ }
16
+ //# sourceMappingURL=FileClusterAuditStorage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileClusterAuditStorage.d.ts","sourceRoot":"","sources":["../../../../src/node/server/peer/FileClusterAuditStorage.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAKhF,qBAAa,uBAAwB,YAAW,mBAAmB;IAM/D,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAL3B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;gBAG5B,OAAO,EAAE,MAAM,EACE,QAAQ,GAAE,MAA0B;IAMvD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAM9B,SAAS,IAAI,MAAM,EAAE;IAKrB,OAAO,CAAC,cAAc;CAKvB"}
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ /**
3
+ * The cluster audit log on disk: `<dataDir>/cluster/audit.jsonl`, rotated to
4
+ * `audit.jsonl.<timestamp>` once it passes {@link DEFAULT_MAX_BYTES}. Only the
5
+ * active file is read back.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.FileClusterAuditStorage = void 0;
9
+ const fs_1 = require("fs");
10
+ const path_1 = require("path");
11
+ /** Rotate once the active file passes this size. */
12
+ const DEFAULT_MAX_BYTES = 5 * 1024 * 1024;
13
+ class FileClusterAuditStorage {
14
+ constructor(dataDir, maxBytes = DEFAULT_MAX_BYTES) {
15
+ this.maxBytes = maxBytes;
16
+ this.dir = (0, path_1.join)(dataDir, "cluster");
17
+ this.file = (0, path_1.join)(this.dir, "audit.jsonl");
18
+ }
19
+ appendLine(line) {
20
+ if (!(0, fs_1.existsSync)(this.dir))
21
+ (0, fs_1.mkdirSync)(this.dir, { recursive: true });
22
+ this.rotateIfNeeded();
23
+ (0, fs_1.appendFileSync)(this.file, `${line}\n`, "utf8");
24
+ }
25
+ readLines() {
26
+ if (!(0, fs_1.existsSync)(this.file))
27
+ return [];
28
+ return (0, fs_1.readFileSync)(this.file, "utf8").split("\n");
29
+ }
30
+ rotateIfNeeded() {
31
+ if (!(0, fs_1.existsSync)(this.file))
32
+ return;
33
+ if ((0, fs_1.statSync)(this.file).size < this.maxBytes)
34
+ return;
35
+ (0, fs_1.renameSync)(this.file, `${this.file}.${Date.now()}`);
36
+ }
37
+ }
38
+ exports.FileClusterAuditStorage = FileClusterAuditStorage;
39
+ //# sourceMappingURL=FileClusterAuditStorage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileClusterAuditStorage.js","sourceRoot":"","sources":["../../../../src/node/server/peer/FileClusterAuditStorage.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH,2BAA+F;AAC/F,+BAA4B;AAI5B,oDAAoD;AACpD,MAAM,iBAAiB,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAE1C,MAAa,uBAAuB;IAIlC,YACE,OAAe,EACE,WAAmB,iBAAiB;QAApC,aAAQ,GAAR,QAAQ,CAA4B;QAErD,IAAI,CAAC,GAAG,GAAG,IAAA,WAAI,EAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACpC,IAAI,CAAC,IAAI,GAAG,IAAA,WAAI,EAAC,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;IAC5C,CAAC;IAED,UAAU,CAAC,IAAY;QACrB,IAAI,CAAC,IAAA,eAAU,EAAC,IAAI,CAAC,GAAG,CAAC;YAAE,IAAA,cAAS,EAAC,IAAI,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACpE,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,IAAA,mBAAc,EAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,IAAI,EAAE,MAAM,CAAC,CAAC;IACjD,CAAC;IAED,SAAS;QACP,IAAI,CAAC,IAAA,eAAU,EAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,EAAE,CAAC;QACtC,OAAO,IAAA,iBAAY,EAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACrD,CAAC;IAEO,cAAc;QACpB,IAAI,CAAC,IAAA,eAAU,EAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO;QACnC,IAAI,IAAA,aAAQ,EAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ;YAAE,OAAO;QACrD,IAAA,eAAU,EAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACtD,CAAC;CACF;AA5BD,0DA4BC"}
@@ -3,7 +3,7 @@
3
3
  * change feed share the handshake; each in-flight call still owns its stream.
4
4
  */
5
5
  import { type IrohByteStream, type IrohRpcContext, type IrohStreamIO } from "../../../core/appendonlystores/network/IrohStreamIO";
6
- import type { SyncChangeEvent } from "../SyncEventBus";
6
+ import type { SyncChangeEvent } from "../../../server/SyncEventBus";
7
7
  export declare class IrohPeerLink {
8
8
  private readonly io;
9
9
  private readonly ticket;
@@ -1 +1 @@
1
- {"version":3,"file":"IrohPeerLink.d.ts","sourceRoot":"","sources":["../../../../src/node/server/peer/IrohPeerLink.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAIL,KAAK,cAAc,EAEnB,KAAK,cAAc,EAEnB,KAAK,YAAY,EAClB,MAAM,qDAAqD,CAAC;AAI7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,qBAAa,YAAY;IAKrB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM;IALzB,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,MAAM,CAAK;gBAGA,EAAE,EAAE,YAAY,EAChB,MAAM,EAAE,MAAM;YAGnB,gBAAgB;IAUxB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,GAAG,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;IAUlF;;;OAGG;IACH,UAAU,IAAI,YAAY;IAWpB,eAAe,CACnB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,EACzC,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,IAAI,CAAC;IA4CV,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAO7B;AAkBD,YAAY,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"IrohPeerLink.d.ts","sourceRoot":"","sources":["../../../../src/node/server/peer/IrohPeerLink.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAIL,KAAK,cAAc,EAEnB,KAAK,cAAc,EAEnB,KAAK,YAAY,EAClB,MAAM,qDAAqD,CAAC;AAI7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEpE,qBAAa,YAAY;IAKrB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM;IALzB,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,MAAM,CAAK;gBAGA,EAAE,EAAE,YAAY,EAChB,MAAM,EAAE,MAAM;YAGnB,gBAAgB;IAUxB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,GAAG,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;IAUlF;;;OAGG;IACH,UAAU,IAAI,YAAY;IAWpB,eAAe,CACnB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,EACzC,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,IAAI,CAAC;IA4CV,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAO7B;AAkBD,YAAY,EAAE,cAAc,EAAE,CAAC"}
@@ -1,37 +1,12 @@
1
1
  /**
2
- * HTTP surface for clustering, in two strictly separated halves.
3
- *
4
- * - {@link createPeerRouter} serves `/system/peer/*`: the server-to-server
5
- * protocol. Callers authenticate as a server listed in
6
- * `trusted-servers.json` and receive a peer JWT. No route here can
7
- * administer anything.
8
- * - {@link createClusterRouter} serves `/system/cluster/*`: the admin surface
9
- * for humans and consoles. Callers authenticate with a system-admin JWT and
10
- * pass the {@link CapabilityMatcher}. No route here can write entries.
11
- *
12
- * The split is the point. A peer must be able to replicate without being able
13
- * to reconfigure the node it replicates with, and an operator must be able to
14
- * administer without being able to forge data as a server identity.
15
- *
16
- * ## Fan-out, not proxy
17
- *
18
- * Every read endpoint answers for **this node only**. A console that wants a
19
- * cluster-wide view calls each node in turn and merges. The alternative — one
20
- * node proxying admin reads to its peers — would need an admin credential that
21
- * spans servers, and peers are separately administered by design: they trust
22
- * each other with encrypted data, not with each other's administration.
23
- *
24
- * ## Admin-blindness
25
- *
26
- * Nothing here returns a document id, an author key, or entry content. Status,
27
- * jobs and audit records carry counts, tenant/database ids and classified
28
- * reasons. A read-only auditor role must not become a metadata oracle over
29
- * data the server itself cannot decrypt.
2
+ * Express mounting of the cluster HTTP surface. The handlers, and the
3
+ * reasoning behind the split into `/system/peer/*` (server-to-server) and
4
+ * `/system/cluster/*` (administration), live in `server/peer/clusterHttp.ts`.
30
5
  */
31
6
  import { Router } from "express";
32
- import type { SyncEventBus } from "../SyncEventBus";
33
- import type { ClusterManager } from "./ClusterManager";
34
- import type { TrustedServer } from "../types";
7
+ import type { SyncEventBus } from "../../../server/SyncEventBus";
8
+ import type { ClusterManager } from "../../../server/peer/ClusterManager";
9
+ import { type ClusterAdminDeps } from "../../../server/peer/clusterHttp";
35
10
  declare global {
36
11
  namespace Express {
37
12
  interface Request {
@@ -44,23 +19,14 @@ export interface PeerRouterDeps {
44
19
  cluster: ClusterManager;
45
20
  eventBus: SyncEventBus;
46
21
  listTenants(): string[];
47
- listDatabases(tenantId: string): string[];
22
+ listDatabases(tenantId: string): string[] | Promise<string[]>;
48
23
  }
49
24
  export declare function createPeerRouter(deps: PeerRouterDeps): Router;
50
- export interface ClusterRouterDeps {
51
- cluster: ClusterManager;
52
- /** Read `trusted-servers.json`; used by peer CRUD. */
53
- listTrustedServers(): TrustedServer[];
54
- /** Persist a peer entry (add or replace by name). */
55
- saveTrustedServer(peer: TrustedServer): void;
56
- /** Remove a peer entry by name; false when it did not exist. */
57
- removeTrustedServer(name: string): boolean;
58
- }
25
+ export type ClusterRouterDeps = ClusterAdminDeps;
59
26
  /**
60
27
  * Admin surface. The caller mounts this behind the system-admin JWT
61
- * middleware, so capability rules in `config.json` decide who may read
62
- * (`GET /system/cluster/*`) and who may act (`POST`, `PATCH`, `DELETE`) —
63
- * that is how an auditor role gets status without getting control.
28
+ * middleware, so capability rules in `config.json` decide who may read and
29
+ * who may act.
64
30
  */
65
31
  export declare function createClusterRouter(deps: ClusterRouterDeps): Router;
66
32
  //# sourceMappingURL=routes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../../src/node/server/peer/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAE,MAAM,EAAkD,MAAM,SAAS,CAAC;AAGjF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAS9C,OAAO,CAAC,MAAM,CAAC;IAEb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,qEAAqE;YACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;SACnB;KACF;CACF;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,cAAc,CAAC;IACxB,QAAQ,EAAE,YAAY,CAAC;IACvB,WAAW,IAAI,MAAM,EAAE,CAAC;IACxB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC3C;AAKD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAyK7D;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,cAAc,CAAC;IACxB,sDAAsD;IACtD,kBAAkB,IAAI,aAAa,EAAE,CAAC;IACtC,qDAAqD;IACrD,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAAC;IAC7C,gEAAgE;IAChE,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CAC5C;AAUD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAoFnE"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../../src/node/server/peer/routes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAA+B,MAAM,SAAS,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,kCAAkC,CAAC;AAI1C,OAAO,CAAC,MAAM,CAAC;IAEb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,qEAAqE;YACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;SACnB;KACF;CACF;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,cAAc,CAAC;IACxB,QAAQ,EAAE,YAAY,CAAC;IACvB,WAAW,IAAI,MAAM,EAAE,CAAC;IACxB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAC/D;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAmD7D;AAED,MAAM,MAAM,iBAAiB,GAAG,gBAAgB,CAAC;AAEjD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAiBnE"}
@@ -1,126 +1,24 @@
1
1
  "use strict";
2
2
  /**
3
- * HTTP surface for clustering, in two strictly separated halves.
4
- *
5
- * - {@link createPeerRouter} serves `/system/peer/*`: the server-to-server
6
- * protocol. Callers authenticate as a server listed in
7
- * `trusted-servers.json` and receive a peer JWT. No route here can
8
- * administer anything.
9
- * - {@link createClusterRouter} serves `/system/cluster/*`: the admin surface
10
- * for humans and consoles. Callers authenticate with a system-admin JWT and
11
- * pass the {@link CapabilityMatcher}. No route here can write entries.
12
- *
13
- * The split is the point. A peer must be able to replicate without being able
14
- * to reconfigure the node it replicates with, and an operator must be able to
15
- * administer without being able to forge data as a server identity.
16
- *
17
- * ## Fan-out, not proxy
18
- *
19
- * Every read endpoint answers for **this node only**. A console that wants a
20
- * cluster-wide view calls each node in turn and merges. The alternative — one
21
- * node proxying admin reads to its peers — would need an admin credential that
22
- * spans servers, and peers are separately administered by design: they trust
23
- * each other with encrypted data, not with each other's administration.
24
- *
25
- * ## Admin-blindness
26
- *
27
- * Nothing here returns a document id, an author key, or entry content. Status,
28
- * jobs and audit records carry counts, tenant/database ids and classified
29
- * reasons. A read-only auditor role must not become a metadata oracle over
30
- * data the server itself cannot decrypt.
3
+ * Express mounting of the cluster HTTP surface. The handlers, and the
4
+ * reasoning behind the split into `/system/peer/*` (server-to-server) and
5
+ * `/system/cluster/*` (administration), live in `server/peer/clusterHttp.ts`.
31
6
  */
32
7
  Object.defineProperty(exports, "__esModule", { value: true });
33
8
  exports.createPeerRouter = createPeerRouter;
34
9
  exports.createClusterRouter = createClusterRouter;
35
10
  const express_1 = require("express");
36
- const bloom_1 = require("../../../core/appendonlystores/bloom");
37
- const types_1 = require("./types");
38
- /** Bound so a malicious or broken peer cannot make us allocate without limit. */
39
- const MAX_BLOOM_BITS = 1 << 22;
11
+ const clusterHttp_1 = require("../../../server/peer/clusterHttp");
12
+ const MindooDBServerCore_1 = require("../../../server/http/MindooDBServerCore");
13
+ const expressAdapter_1 = require("../expressAdapter");
40
14
  function createPeerRouter(deps) {
41
15
  const router = (0, express_1.Router)();
42
- const { cluster } = deps;
43
- const requirePeer = async (req, res, next) => {
44
- const auth = req.headers.authorization;
45
- if (!auth?.startsWith("Bearer ")) {
46
- res.status(401).json({ error: "Missing or invalid Authorization header" });
47
- return;
48
- }
49
- const payload = await cluster.auth.validateToken(auth.substring(7));
50
- if (!payload) {
51
- res.status(401).json({ error: "Invalid or expired peer token" });
52
- return;
53
- }
54
- req.peerName = payload.sub;
55
- next();
56
- };
57
- router.post("/challenge", async (req, res) => {
58
- const { publicsignkey } = req.body;
59
- if (typeof publicsignkey !== "string" || publicsignkey.length === 0) {
60
- res.status(400).json({ error: "publicsignkey is required" });
61
- return;
62
- }
63
- try {
64
- res.json({ challenge: await cluster.auth.generateChallenge(publicsignkey) });
65
- }
66
- catch {
67
- // Deliberately the same shape as a signature failure: an unauthenticated
68
- // caller must not be able to enumerate which servers we trust.
69
- res.status(401).json({ error: "Unknown peer" });
70
- }
71
- });
72
- router.post("/authenticate", async (req, res) => {
73
- const { challenge, signature } = req.body;
74
- if (typeof challenge !== "string" || typeof signature !== "string") {
75
- res.status(400).json({ error: "challenge and signature are required" });
76
- return;
77
- }
78
- const result = await cluster.auth.authenticate(challenge, new Uint8Array(Buffer.from(signature, "base64")));
79
- if (!result.success) {
80
- res.status(401).json({ error: result.error ?? "Authentication failed" });
81
- return;
82
- }
83
- res.json({ success: true, token: result.token });
84
- });
85
- /**
86
- * Tenant intersection.
87
- *
88
- * The caller sends a Bloom summary of the tenants it hosts; we answer with
89
- * the ids on *our* side that the filter might contain. Neither server ever
90
- * transmits its full tenant list, so a peer learns nothing about tenants it
91
- * does not already host. False positives are harmless: the caller intersects
92
- * the answer against its own authoritative list before replicating anything.
93
- */
94
- router.post("/tenant-bloom", requirePeer, (req, res) => {
95
- const { bloom } = req.body;
96
- if (!bloom || typeof bloom !== "object") {
97
- res.status(400).json({ error: "bloom summary is required" });
98
- return;
99
- }
100
- if (typeof bloom.bitCount !== "number" || bloom.bitCount <= 0 || bloom.bitCount > MAX_BLOOM_BITS) {
101
- res.status(400).json({ error: "Invalid bloom summary" });
102
- return;
103
- }
104
- const candidates = deps
105
- .listTenants()
106
- .filter((tenantId) => (0, bloom_1.bloomMightContainId)(bloom, tenantId));
107
- // Remember what this peer may see, so the event stream can be filtered to
108
- // the same set instead of announcing every tenant we host.
109
- cluster.recordPeerIntersection(req.peerName, candidates);
110
- res.json({ tenantIds: candidates });
111
- });
112
- router.get("/databases", requirePeer, (req, res) => {
113
- const tenantId = typeof req.query.tenantId === "string" ? req.query.tenantId : "";
114
- if (!tenantId) {
115
- res.status(400).json({ error: "tenantId is required" });
116
- return;
117
- }
118
- if (!cluster.peerMaySeeTenant(req.peerName, tenantId)) {
119
- res.status(404).json({ error: "Tenant not found" });
120
- return;
121
- }
122
- res.json({ databases: deps.listDatabases(tenantId) });
123
- });
16
+ const handlers = new clusterHttp_1.PeerHttpHandlers(deps);
17
+ const requirePeer = (0, expressAdapter_1.guard)((req) => handlers.peerGuard(req));
18
+ router.post("/challenge", (0, expressAdapter_1.route)((req) => handlers.challenge(req)));
19
+ router.post("/authenticate", (0, expressAdapter_1.route)((req) => handlers.authenticate(req)));
20
+ router.post("/tenant-bloom", requirePeer, (0, expressAdapter_1.route)((req) => handlers.tenantBloom(req)));
21
+ router.get("/databases", requirePeer, (0, expressAdapter_1.route)((req) => handlers.databases(req)));
124
22
  /**
125
23
  * Change feed for peers, across every shared tenant.
126
24
  *
@@ -139,26 +37,15 @@ function createPeerRouter(deps) {
139
37
  res.setHeader("Connection", "keep-alive");
140
38
  }
141
39
  res.flushHeaders();
142
- res.write(`event: hello\ndata: ${JSON.stringify({ protocolVersion: "sync-v5" })}\n\n`);
40
+ res.write((0, MindooDBServerCore_1.formatSyncHelloEvent)());
143
41
  const unsubscribe = deps.eventBus.subscribe((event) => {
144
- // Never tell a peer about its own push: it would pull back what it just
145
- // sent. The peer suppresses echoes too, but doing it here saves the
146
- // round trip entirely.
147
- if (event.originPeer === peerName)
148
- return;
149
- if (!cluster.peerMaySeeTenant(peerName, event.tenantId))
150
- return;
151
- res.write(`event: change\ndata: ${JSON.stringify({
152
- tenantId: event.tenantId,
153
- dbId: event.dbId,
154
- storeKind: event.storeKind,
155
- epoch: event.epoch,
156
- maxReceiptOrder: event.maxReceiptOrder,
157
- })}\n\n`);
42
+ const frame = (0, clusterHttp_1.formatPeerChangeEvent)(deps.cluster, peerName, event);
43
+ if (frame)
44
+ res.write(frame);
158
45
  });
159
46
  const heartbeat = setInterval(() => {
160
- res.write(`: heartbeat ${Date.now()}\n\n`);
161
- }, 30000);
47
+ res.write((0, MindooDBServerCore_1.formatSyncHeartbeat)(Date.now()));
48
+ }, MindooDBServerCore_1.SYNC_EVENT_HEARTBEAT_MS);
162
49
  const cleanup = () => {
163
50
  clearInterval(heartbeat);
164
51
  unsubscribe();
@@ -166,157 +53,28 @@ function createPeerRouter(deps) {
166
53
  req.on("close", cleanup);
167
54
  res.on("close", cleanup);
168
55
  });
169
- /**
170
- * Catch-up trigger from the calling peer.
171
- *
172
- * Peer A tells us "I have something for you"; we run our own replicator
173
- * toward A, which pulls it. Doing it this way rather than having A push
174
- * directly keeps one replicator per link in charge of cursors and ordering,
175
- * so the invariants hold no matter which side noticed the change first.
176
- */
177
- router.post("/sync", requirePeer, (req, res) => {
178
- const peerName = req.peerName;
179
- const replicator = cluster.getReplicator(peerName);
180
- if (!replicator) {
181
- res.status(409).json({
182
- error: `No outbound session configured for peer ${peerName} (missing url in trusted-servers.json)`,
183
- });
184
- return;
185
- }
186
- const { tenantId, dbId } = (req.body ?? {});
187
- // Fire and forget: the caller only needs to know we accepted the hint, and
188
- // holding the connection open for a full mirror would time out.
189
- void replicator.syncNow({ tenantId, dbId }).catch(() => undefined);
190
- res.status(202).json({ accepted: true });
191
- });
56
+ router.post("/sync", requirePeer, (0, expressAdapter_1.route)((req) => handlers.sync(req)));
192
57
  return router;
193
58
  }
194
- const ACTION_KINDS = {
195
- sync: "sync",
196
- "retry-rejected": "retry-rejected",
197
- "refresh-intersection": "refresh-intersection",
198
- pause: "pause",
199
- resume: "resume",
200
- };
201
59
  /**
202
60
  * Admin surface. The caller mounts this behind the system-admin JWT
203
- * middleware, so capability rules in `config.json` decide who may read
204
- * (`GET /system/cluster/*`) and who may act (`POST`, `PATCH`, `DELETE`) —
205
- * that is how an auditor role gets status without getting control.
61
+ * middleware, so capability rules in `config.json` decide who may read and
62
+ * who may act.
206
63
  */
207
64
  function createClusterRouter(deps) {
208
65
  const router = (0, express_1.Router)();
209
- const { cluster } = deps;
210
- const actor = (req) => req.systemAdmin?.username ?? "unknown";
211
- router.get("/topology", (_req, res) => {
212
- res.json(cluster.topology());
213
- });
214
- router.get("/status", (_req, res) => {
215
- res.json(cluster.status());
216
- });
217
- router.get("/status/tenants/:tenantId", (req, res) => {
218
- res.json(cluster.tenantStatus(req.params.tenantId.toLowerCase()));
219
- });
220
- router.get("/jobs", (req, res) => {
221
- const limit = Number.parseInt(String(req.query.limit ?? "50"), 10);
222
- res.json({ jobs: cluster.jobs.list(Number.isFinite(limit) ? limit : 50) });
223
- });
224
- router.get("/jobs/:jobId", (req, res) => {
225
- const job = cluster.jobs.get(req.params.jobId);
226
- if (!job) {
227
- res.status(404).json({ error: "Job not found" });
228
- return;
229
- }
230
- res.json(job);
231
- });
232
- router.get("/audit", (req, res) => {
233
- const limit = Number.parseInt(String(req.query.limit ?? "50"), 10);
234
- const before = typeof req.query.before === "string" ? req.query.before : undefined;
235
- res.json(cluster.audit.read({ limit: Number.isFinite(limit) ? limit : 50, before }));
236
- });
237
- router.post("/actions/:action", (req, res) => {
238
- const kind = ACTION_KINDS[req.params.action];
239
- if (!kind) {
240
- res.status(404).json({ error: `Unknown action: ${req.params.action}` });
241
- return;
242
- }
243
- const body = (req.body ?? {});
244
- const scope = {
245
- peer: typeof body.peer === "string" ? body.peer : undefined,
246
- tenantId: typeof body.tenantId === "string" ? body.tenantId.toLowerCase() : undefined,
247
- dbId: typeof body.dbId === "string" ? body.dbId : undefined,
248
- };
249
- const outcome = cluster.runAction(kind, scope, actor(req));
250
- if (!outcome.accepted) {
251
- res.status(400).json({ error: outcome.error });
252
- return;
253
- }
254
- // 202: the job is queued, not finished. Poll GET /jobs/:jobId.
255
- res.status(202).json({ jobId: outcome.job.id, job: outcome.job });
256
- });
257
- router.get("/peers", (_req, res) => {
258
- res.json({ peers: cluster.topology().peers });
259
- });
260
- router.post("/peers/:name", (req, res) => {
261
- upsertPeer(req, res, deps, "peer-create");
262
- });
263
- router.patch("/peers/:name", (req, res) => {
264
- upsertPeer(req, res, deps, "peer-update");
265
- });
266
- router.delete("/peers/:name", (req, res) => {
267
- const name = decodeURIComponent(req.params.name);
268
- if (!deps.removeTrustedServer(name)) {
269
- res.status(404).json({ error: "Peer not found" });
270
- return;
271
- }
272
- cluster.syncReplicators();
273
- cluster.auditPeerChange("peer-delete", name, actor(req));
274
- res.json({ success: true });
275
- });
66
+ const handlers = new clusterHttp_1.ClusterAdminHandlers(deps);
67
+ router.get("/topology", (0, expressAdapter_1.route)(() => handlers.topology()));
68
+ router.get("/status", (0, expressAdapter_1.route)(() => handlers.status()));
69
+ router.get("/status/tenants/:tenantId", (0, expressAdapter_1.route)((req) => handlers.tenantStatus(req)));
70
+ router.get("/jobs", (0, expressAdapter_1.route)((req) => handlers.jobs(req)));
71
+ router.get("/jobs/:jobId", (0, expressAdapter_1.route)((req) => handlers.job(req)));
72
+ router.get("/audit", (0, expressAdapter_1.route)((req) => handlers.audit(req)));
73
+ router.post("/actions/:action", (0, expressAdapter_1.route)((req) => handlers.action(req)));
74
+ router.get("/peers", (0, expressAdapter_1.route)(() => handlers.peers()));
75
+ router.post("/peers/:name", (0, expressAdapter_1.route)((req) => handlers.createPeer(req)));
76
+ router.patch("/peers/:name", (0, expressAdapter_1.route)((req) => handlers.updatePeer(req)));
77
+ router.delete("/peers/:name", (0, expressAdapter_1.route)((req) => handlers.deletePeer(req)));
276
78
  return router;
277
79
  }
278
- function upsertPeer(req, res, deps, action) {
279
- const name = decodeURIComponent(req.params.name);
280
- const existing = deps.listTrustedServers().find((peer) => peer.name === name);
281
- if (action === "peer-create" && existing) {
282
- res.status(409).json({ error: "Peer already exists" });
283
- return;
284
- }
285
- if (action === "peer-update" && !existing) {
286
- res.status(404).json({ error: "Peer not found" });
287
- return;
288
- }
289
- const body = req.body;
290
- const signingPublicKey = body.signingPublicKey ?? existing?.signingPublicKey;
291
- const encryptionPublicKey = body.encryptionPublicKey ?? existing?.encryptionPublicKey;
292
- if (!signingPublicKey || !encryptionPublicKey) {
293
- res.status(400).json({ error: "signingPublicKey and encryptionPublicKey are required" });
294
- return;
295
- }
296
- for (const [field, guard] of [
297
- ["direction", types_1.isPeerSyncDirection],
298
- ["role", types_1.isPeerRole],
299
- ["attachments", types_1.isPeerAttachmentMode],
300
- ]) {
301
- const value = body[field];
302
- if (value !== undefined && !guard(value)) {
303
- res.status(400).json({ error: `Invalid ${field}: ${String(value)}` });
304
- return;
305
- }
306
- }
307
- const peer = {
308
- ...existing,
309
- name,
310
- signingPublicKey,
311
- encryptionPublicKey,
312
- url: body.url ?? existing?.url,
313
- direction: body.direction ?? existing?.direction,
314
- role: body.role ?? existing?.role,
315
- attachments: body.attachments ?? existing?.attachments,
316
- };
317
- deps.saveTrustedServer(peer);
318
- deps.cluster.syncReplicators();
319
- deps.cluster.auditPeerChange(action, name, req.systemAdmin?.username ?? "unknown");
320
- res.status(action === "peer-create" ? 201 : 200).json({ success: true, peer });
321
- }
322
80
  //# sourceMappingURL=routes.js.map