@supalive/core 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 (175) hide show
  1. package/README.md +22 -0
  2. package/dist/src/client/caller_client.d.ts +42 -0
  3. package/dist/src/client/caller_client.d.ts.map +1 -0
  4. package/dist/src/client/caller_client.js +77 -0
  5. package/dist/src/client/caller_client.js.map +1 -0
  6. package/dist/src/client/client.d.ts +149 -0
  7. package/dist/src/client/client.d.ts.map +1 -0
  8. package/dist/src/client/client.js +308 -0
  9. package/dist/src/client/client.js.map +1 -0
  10. package/dist/src/client/index.d.ts +17 -0
  11. package/dist/src/client/index.d.ts.map +1 -0
  12. package/dist/src/client/index.js +19 -0
  13. package/dist/src/client/index.js.map +1 -0
  14. package/dist/src/client/sub_key.d.ts +20 -0
  15. package/dist/src/client/sub_key.d.ts.map +1 -0
  16. package/dist/src/client/sub_key.js +37 -0
  17. package/dist/src/client/sub_key.js.map +1 -0
  18. package/dist/src/client/ws_client_manager.d.ts +268 -0
  19. package/dist/src/client/ws_client_manager.d.ts.map +1 -0
  20. package/dist/src/client/ws_client_manager.js +1013 -0
  21. package/dist/src/client/ws_client_manager.js.map +1 -0
  22. package/dist/src/config.d.ts +117 -0
  23. package/dist/src/config.d.ts.map +1 -0
  24. package/dist/src/config.js +2 -0
  25. package/dist/src/config.js.map +1 -0
  26. package/dist/src/db/bytes.d.ts +4 -0
  27. package/dist/src/db/bytes.d.ts.map +1 -0
  28. package/dist/src/db/bytes.js +24 -0
  29. package/dist/src/db/bytes.js.map +1 -0
  30. package/dist/src/db/cache.d.ts +30 -0
  31. package/dist/src/db/cache.d.ts.map +1 -0
  32. package/dist/src/db/cache.js +153 -0
  33. package/dist/src/db/cache.js.map +1 -0
  34. package/dist/src/db/codec.d.ts +10 -0
  35. package/dist/src/db/codec.d.ts.map +1 -0
  36. package/dist/src/db/codec.js +73 -0
  37. package/dist/src/db/codec.js.map +1 -0
  38. package/dist/src/db/context.d.ts +28 -0
  39. package/dist/src/db/context.d.ts.map +1 -0
  40. package/dist/src/db/context.js +147 -0
  41. package/dist/src/db/context.js.map +1 -0
  42. package/dist/src/db/db.d.ts +154 -0
  43. package/dist/src/db/db.d.ts.map +1 -0
  44. package/dist/src/db/db.js +23 -0
  45. package/dist/src/db/db.js.map +1 -0
  46. package/dist/src/db/mysql.d.ts +120 -0
  47. package/dist/src/db/mysql.d.ts.map +1 -0
  48. package/dist/src/db/mysql.js +708 -0
  49. package/dist/src/db/mysql.js.map +1 -0
  50. package/dist/src/db/postgres.d.ts +116 -0
  51. package/dist/src/db/postgres.d.ts.map +1 -0
  52. package/dist/src/db/postgres.js +998 -0
  53. package/dist/src/db/postgres.js.map +1 -0
  54. package/dist/src/db/query.d.ts +174 -0
  55. package/dist/src/db/query.d.ts.map +1 -0
  56. package/dist/src/db/query.js +790 -0
  57. package/dist/src/db/query.js.map +1 -0
  58. package/dist/src/db/query_definition.d.ts +54 -0
  59. package/dist/src/db/query_definition.d.ts.map +1 -0
  60. package/dist/src/db/query_definition.js +47 -0
  61. package/dist/src/db/query_definition.js.map +1 -0
  62. package/dist/src/db/realtime_db.d.ts +19 -0
  63. package/dist/src/db/realtime_db.d.ts.map +1 -0
  64. package/dist/src/db/realtime_db.js +98 -0
  65. package/dist/src/db/realtime_db.js.map +1 -0
  66. package/dist/src/db/schema.d.ts +110 -0
  67. package/dist/src/db/schema.d.ts.map +1 -0
  68. package/dist/src/db/schema.js +47 -0
  69. package/dist/src/db/schema.js.map +1 -0
  70. package/dist/src/db/types_client_rpc.d.ts +157 -0
  71. package/dist/src/db/types_client_rpc.d.ts.map +1 -0
  72. package/dist/src/db/types_client_rpc.js +106 -0
  73. package/dist/src/db/types_client_rpc.js.map +1 -0
  74. package/dist/src/db/types_db.d.ts +236 -0
  75. package/dist/src/db/types_db.d.ts.map +1 -0
  76. package/dist/src/db/types_db.js +188 -0
  77. package/dist/src/db/types_db.js.map +1 -0
  78. package/dist/src/exports/mysql.d.ts +2 -0
  79. package/dist/src/exports/mysql.d.ts.map +1 -0
  80. package/dist/src/exports/mysql.js +2 -0
  81. package/dist/src/exports/mysql.js.map +1 -0
  82. package/dist/src/exports/postgres.d.ts +2 -0
  83. package/dist/src/exports/postgres.d.ts.map +1 -0
  84. package/dist/src/exports/postgres.js +2 -0
  85. package/dist/src/exports/postgres.js.map +1 -0
  86. package/dist/src/exports/procedure.d.ts +5 -0
  87. package/dist/src/exports/procedure.d.ts.map +1 -0
  88. package/dist/src/exports/procedure.js +5 -0
  89. package/dist/src/exports/procedure.js.map +1 -0
  90. package/dist/src/exports/server.d.ts +3 -0
  91. package/dist/src/exports/server.d.ts.map +1 -0
  92. package/dist/src/exports/server.js +3 -0
  93. package/dist/src/exports/server.js.map +1 -0
  94. package/dist/src/exports/types.d.ts +6 -0
  95. package/dist/src/exports/types.d.ts.map +1 -0
  96. package/dist/src/exports/types.js +6 -0
  97. package/dist/src/exports/types.js.map +1 -0
  98. package/dist/src/helper.d.ts +11 -0
  99. package/dist/src/helper.d.ts.map +1 -0
  100. package/dist/src/helper.js +45 -0
  101. package/dist/src/helper.js.map +1 -0
  102. package/dist/src/logger.d.ts +7 -0
  103. package/dist/src/logger.d.ts.map +1 -0
  104. package/dist/src/logger.js +45 -0
  105. package/dist/src/logger.js.map +1 -0
  106. package/dist/src/router/index.d.ts +4 -0
  107. package/dist/src/router/index.d.ts.map +1 -0
  108. package/dist/src/router/index.js +4 -0
  109. package/dist/src/router/index.js.map +1 -0
  110. package/dist/src/router/procedure.d.ts +204 -0
  111. package/dist/src/router/procedure.d.ts.map +1 -0
  112. package/dist/src/router/procedure.js +122 -0
  113. package/dist/src/router/procedure.js.map +1 -0
  114. package/dist/src/router/router.d.ts +88 -0
  115. package/dist/src/router/router.d.ts.map +1 -0
  116. package/dist/src/router/router.js +88 -0
  117. package/dist/src/router/router.js.map +1 -0
  118. package/dist/src/server/hash.d.ts +12 -0
  119. package/dist/src/server/hash.d.ts.map +1 -0
  120. package/dist/src/server/hash.js +20 -0
  121. package/dist/src/server/hash.js.map +1 -0
  122. package/dist/src/server/hash.test.d.ts +2 -0
  123. package/dist/src/server/hash.test.d.ts.map +1 -0
  124. package/dist/src/server/hash.test.js +43 -0
  125. package/dist/src/server/hash.test.js.map +1 -0
  126. package/dist/src/server/index.d.ts +8 -0
  127. package/dist/src/server/index.d.ts.map +1 -0
  128. package/dist/src/server/index.js +7 -0
  129. package/dist/src/server/index.js.map +1 -0
  130. package/dist/src/server/overlap-checker.d.ts +18 -0
  131. package/dist/src/server/overlap-checker.d.ts.map +1 -0
  132. package/dist/src/server/overlap-checker.js +247 -0
  133. package/dist/src/server/overlap-checker.js.map +1 -0
  134. package/dist/src/server/sub_hash.d.ts +23 -0
  135. package/dist/src/server/sub_hash.d.ts.map +1 -0
  136. package/dist/src/server/sub_hash.js +38 -0
  137. package/dist/src/server/sub_hash.js.map +1 -0
  138. package/dist/src/server/subscription-manager-client.d.ts +120 -0
  139. package/dist/src/server/subscription-manager-client.d.ts.map +1 -0
  140. package/dist/src/server/subscription-manager-client.js +207 -0
  141. package/dist/src/server/subscription-manager-client.js.map +1 -0
  142. package/dist/src/server/subscription-manager-types.d.ts +168 -0
  143. package/dist/src/server/subscription-manager-types.d.ts.map +1 -0
  144. package/dist/src/server/subscription-manager-types.js +94 -0
  145. package/dist/src/server/subscription-manager-types.js.map +1 -0
  146. package/dist/src/server/subscription-manager-worker-entry.d.ts +2 -0
  147. package/dist/src/server/subscription-manager-worker-entry.d.ts.map +1 -0
  148. package/dist/src/server/subscription-manager-worker-entry.js +127 -0
  149. package/dist/src/server/subscription-manager-worker-entry.js.map +1 -0
  150. package/dist/src/server/subscription-manager-worker-protocol.d.ts +40 -0
  151. package/dist/src/server/subscription-manager-worker-protocol.d.ts.map +1 -0
  152. package/dist/src/server/subscription-manager-worker-protocol.js +20 -0
  153. package/dist/src/server/subscription-manager-worker-protocol.js.map +1 -0
  154. package/dist/src/server/subscription-manager.d.ts +32 -0
  155. package/dist/src/server/subscription-manager.d.ts.map +1 -0
  156. package/dist/src/server/subscription-manager.js +249 -0
  157. package/dist/src/server/subscription-manager.js.map +1 -0
  158. package/dist/src/server/subscription-manager.test.d.ts +2 -0
  159. package/dist/src/server/subscription-manager.test.d.ts.map +1 -0
  160. package/dist/src/server/subscription-manager.test.js +610 -0
  161. package/dist/src/server/subscription-manager.test.js.map +1 -0
  162. package/dist/src/server/subscription-worker.d.ts +32 -0
  163. package/dist/src/server/subscription-worker.d.ts.map +1 -0
  164. package/dist/src/server/subscription-worker.js +190 -0
  165. package/dist/src/server/subscription-worker.js.map +1 -0
  166. package/dist/src/server/supalive-server.d.ts +158 -0
  167. package/dist/src/server/supalive-server.d.ts.map +1 -0
  168. package/dist/src/server/supalive-server.js +1048 -0
  169. package/dist/src/server/supalive-server.js.map +1 -0
  170. package/dist/src/server/types_server.d.ts +96 -0
  171. package/dist/src/server/types_server.d.ts.map +1 -0
  172. package/dist/src/server/types_server.js +36 -0
  173. package/dist/src/server/types_server.js.map +1 -0
  174. package/dist/tsconfig.tsbuildinfo +1 -0
  175. package/package.json +83 -0
@@ -0,0 +1,207 @@
1
+ import { Client } from "rpc-websockets";
2
+ import * as types from "./subscription-manager-types";
3
+ import { logger as baseLogger, logLevelOf } from "../logger";
4
+ import { supaliveStringify } from "../helper";
5
+ const logger = baseLogger.child({ name: "SUBS_MGR_CLIENT" }, { level: logLevelOf("SUB_MANAGER_CLIENT_LOG_LEVEL") });
6
+ export const subscriptionManagerDataPack = {
7
+ encode: (data) => supaliveStringify(data),
8
+ decode: (data) => JSON.parse(data),
9
+ };
10
+ /**
11
+ * RPC client for the (single) sub-manager process.
12
+ *
13
+ * Design (Convex-inspired):
14
+ * • The sub-manager is in-memory and ephemeral. There is no version
15
+ * protocol, no client-side registration registry, no OUT_OF_SYNC
16
+ * replay logic. All recovery is driven from the app server using
17
+ * state it already has (`serverSubscriptions`) plus registration
18
+ * records persisted to Redis at `sl:reg:<subId>`.
19
+ *
20
+ * • Out-of-order `updateSubscriptionReadSet` calls are filtered server
21
+ * side using `lastSnapshotTs` (monotonic DB commit timestamp).
22
+ *
23
+ * • On rpc-websockets reconnect, the client:
24
+ * 1. Transitions to `busy` (any in-flight `invalidateWriteset`
25
+ * buffers its writeSet).
26
+ * 2. Invokes the app server's `recoveryDriver` to re-register all
27
+ * known subs.
28
+ * 3. Flushes the buffer as one batched `invalidateWriteset` RPC and
29
+ * hands the resulting `affected[]` to `affectedHandler`.
30
+ * 4. Transitions to `ready`.
31
+ *
32
+ * • During an extended outage, the buffer is bounded; if exceeded, it
33
+ * is dropped and we rely on the commit-log replay built into
34
+ * `SubscriptionWorker.register()` to catch each sub up on the next
35
+ * re-register.
36
+ */
37
+ export class SubManagerClient {
38
+ client;
39
+ state = "busy";
40
+ hasConnectedOnce = false;
41
+ /** Resolves whenever state transitions to 'ready'. Replaced on each busy→ready cycle. */
42
+ readyPromise;
43
+ resolveReady;
44
+ /** Writeset entries accumulated while state === 'busy'. Flushed as one RPC after recovery. */
45
+ bufferedWriteSets = [];
46
+ bufferLimit;
47
+ bufferDroppedDuringOutage = false;
48
+ recoveryDriver;
49
+ affectedHandler;
50
+ constructor(urlOrOptions) {
51
+ const opts = typeof urlOrOptions === "string"
52
+ ? { url: urlOrOptions }
53
+ : urlOrOptions;
54
+ this.bufferLimit = opts.invalidateBufferLimit ?? 50_000;
55
+ this.readyPromise = new Promise((r) => { this.resolveReady = r; });
56
+ this.client = new Client(opts.url, {
57
+ dataPack: subscriptionManagerDataPack,
58
+ });
59
+ this.client.setAutoReconnect(true);
60
+ this.client.setMaxReconnects(0);
61
+ // Ensure the dataPack is set even if rpc-websockets doesn't pass it through to the Client constructor
62
+ this.client.dataPack = subscriptionManagerDataPack;
63
+ this.client.on("open", this.handleOpen.bind(this));
64
+ this.client.on("close", this.handleClose.bind(this));
65
+ this.client.on("error", (err) => logger.warn(err, "sub-manager client socket error"));
66
+ }
67
+ /**
68
+ * Wire up the app-server-driven recovery. Must be called before any
69
+ * disconnect/reconnect cycle for buffered writeSets to be flushed and
70
+ * subscriptions re-registered.
71
+ */
72
+ setRecoveryDriver(driver) {
73
+ this.recoveryDriver = driver;
74
+ }
75
+ /**
76
+ * Wire up the handler invoked when batched invalidate results land
77
+ * after recovery. The handler is expected to drive
78
+ * `reexecuteAffectedQuery` for each entry.
79
+ */
80
+ setAffectedHandler(handler) {
81
+ this.affectedHandler = handler;
82
+ }
83
+ // ─── RPC methods ────────────────────────────────────────────────────────
84
+ async registerSubscription(params) {
85
+ return this.call("registerSubscription", params, types.RegisterSubscriptionResultSchema);
86
+ }
87
+ async registerSubscriptionBatch(params) {
88
+ return this.call("registerSubscriptionBatch", params, types.RegisterSubscriptionBatchResultSchema);
89
+ }
90
+ async updateSubscriptionReadSet(params) {
91
+ return this.call("updateSubscriptionReadSet", params, types.UpdateSubscriptionReadSetResultSchema);
92
+ }
93
+ async unregisterSubscription(params) {
94
+ return this.call("unregisterSubscription", params, types.UnregisterSubscriptionResultSchema);
95
+ }
96
+ async unregisterSubscriptions(params) {
97
+ return this.call("unregisterSubscriptions", params, types.UnregisterSubscriptionsResultSchema);
98
+ }
99
+ /**
100
+ * Sends the writeSet to the sub-manager for invalidation, OR buffers it
101
+ * if the client is currently disconnected / recovering. Returns
102
+ * `{ affected: [] }` while buffering — the actual `affected` from the
103
+ * buffered batch is delivered via the registered `affectedHandler`
104
+ * after recovery completes.
105
+ */
106
+ async invalidateWriteset(params) {
107
+ if (this.state === "busy") {
108
+ this.appendToBuffer(params.writeSet);
109
+ return { affected: [] };
110
+ }
111
+ return this.call("invalidateWriteset", params, types.InvalidateWritesetResultSchema);
112
+ }
113
+ // ─── Internal ───────────────────────────────────────────────────────────
114
+ /**
115
+ * Single point through which RPCs go. Throws on transport / server error.
116
+ * `registerSubscription`, `updateSubscriptionReadSet`, and
117
+ * `unregisterSubscription` are NOT gated on the ready state: during a
118
+ * disconnect they will fail at the socket layer, and during recovery
119
+ * (which itself uses these methods) gating would deadlock.
120
+ */
121
+ async call(procName, params, resType) {
122
+ const result = await this.client.call(procName, params);
123
+ return resType.parse(result);
124
+ }
125
+ appendToBuffer(writeSet) {
126
+ if (this.bufferedWriteSets.length + writeSet.length > this.bufferLimit) {
127
+ if (!this.bufferDroppedDuringOutage) {
128
+ logger.warn(`Invalidate buffer would exceed ${this.bufferLimit}; dropping buffered entries. ` +
129
+ `Subscriptions will be caught up via commit-log replay on re-register.`);
130
+ this.bufferDroppedDuringOutage = true;
131
+ }
132
+ this.bufferedWriteSets = [];
133
+ return;
134
+ }
135
+ this.bufferedWriteSets.push(...writeSet);
136
+ }
137
+ async flushBuffer() {
138
+ if (this.bufferedWriteSets.length === 0)
139
+ return;
140
+ const writeSet = this.bufferedWriteSets;
141
+ this.bufferedWriteSets = [];
142
+ this.bufferDroppedDuringOutage = false;
143
+ try {
144
+ const result = await this.call("invalidateWriteset", { writeSet }, types.InvalidateWritesetResultSchema);
145
+ if (this.affectedHandler && result.affected.length > 0) {
146
+ await this.affectedHandler(result.affected);
147
+ }
148
+ }
149
+ catch (err) {
150
+ logger.error(err, "Failed to flush invalidate buffer after recovery");
151
+ }
152
+ }
153
+ markBusy() {
154
+ if (this.state === "busy")
155
+ return;
156
+ this.state = "busy";
157
+ this.readyPromise = new Promise((r) => { this.resolveReady = r; });
158
+ }
159
+ markReady() {
160
+ if (this.state === "ready")
161
+ return;
162
+ this.state = "ready";
163
+ this.resolveReady();
164
+ }
165
+ handleClose() {
166
+ logger.info("sub-manager client: socket closed");
167
+ this.markBusy();
168
+ }
169
+ handleOpen() {
170
+ if (!this.hasConnectedOnce) {
171
+ this.hasConnectedOnce = true;
172
+ logger.info("sub-manager client: initial connect");
173
+ this.markReady();
174
+ return;
175
+ }
176
+ logger.info("sub-manager client: reconnected — starting recovery");
177
+ void this.runRecovery();
178
+ }
179
+ async runRecovery() {
180
+ // Stay 'busy' for the duration of recovery so concurrent
181
+ // invalidateWriteset calls keep buffering.
182
+ try {
183
+ if (this.recoveryDriver) {
184
+ await this.recoveryDriver();
185
+ }
186
+ else {
187
+ logger.warn("sub-manager client: no recoveryDriver configured — skipping recovery step");
188
+ }
189
+ await this.flushBuffer();
190
+ }
191
+ catch (err) {
192
+ logger.error(err, "Recovery failed; state will be marked ready anyway");
193
+ }
194
+ finally {
195
+ logger.info("sub-manager client: recovery complete");
196
+ this.markReady();
197
+ }
198
+ }
199
+ /**
200
+ * Test/inspection helpers.
201
+ */
202
+ /** @internal */
203
+ isReady() { return this.state === "ready"; }
204
+ /** @internal */
205
+ bufferSize() { return this.bufferedWriteSets.length; }
206
+ }
207
+ //# sourceMappingURL=subscription-manager-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription-manager-client.js","sourceRoot":"","sources":["../../../src/server/subscription-manager-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,168 @@
1
+ import z from "zod";
2
+ import { RawReadEntry, ReadEntry } from "../db/types_db";
3
+ export declare const RegisterSubscriptionParamsSchema: z.ZodObject<{
4
+ subId: z.ZodString;
5
+ cacheKey: z.ZodString;
6
+ queryName: z.ZodString;
7
+ args: z.ZodUnknown;
8
+ queryIdentity: z.ZodString;
9
+ instanceName: z.ZodString;
10
+ lastSnapshotTs: z.ZodPipe<z.ZodString, z.ZodTransform<bigint, string>>;
11
+ }, z.core.$strip>;
12
+ export type RegisterSubscriptionParams = z.infer<typeof RegisterSubscriptionParamsSchema>;
13
+ export declare const RegisterSubscriptionResultSchema: z.ZodObject<{
14
+ cacheKey: z.ZodString;
15
+ recompute: z.ZodBoolean;
16
+ readSet: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
17
+ kind: z.ZodLiteral<"point">;
18
+ table: z.ZodString;
19
+ id: z.ZodString;
20
+ tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
21
+ expectedCommitTs: z.ZodOptional<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<bigint, string>>>>;
22
+ }, z.core.$strip>, z.ZodObject<{
23
+ kind: z.ZodLiteral<"range">;
24
+ table: z.ZodString;
25
+ tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
26
+ predicate: z.ZodType<import("../client").Predicate, unknown, z.core.$ZodTypeInternals<import("../client").Predicate, unknown>>;
27
+ columns: z.ZodArray<z.ZodString>;
28
+ orderBy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
29
+ limit: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
30
+ offset: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
31
+ }, z.core.$strip>]>>;
32
+ }, z.core.$strip>;
33
+ export type RegisterSubscriptionResult = z.infer<typeof RegisterSubscriptionResultSchema>;
34
+ export declare const RegisterSubscriptionBatchParamsSchema: z.ZodArray<z.ZodObject<{
35
+ subId: z.ZodString;
36
+ cacheKey: z.ZodString;
37
+ queryName: z.ZodString;
38
+ args: z.ZodUnknown;
39
+ queryIdentity: z.ZodString;
40
+ instanceName: z.ZodString;
41
+ lastSnapshotTs: z.ZodPipe<z.ZodString, z.ZodTransform<bigint, string>>;
42
+ }, z.core.$strip>>;
43
+ export type RegisterSubscriptionBatchParams = z.infer<typeof RegisterSubscriptionBatchParamsSchema>;
44
+ export declare const RegisterSubscriptionBatchResultSchema: z.ZodArray<z.ZodObject<{
45
+ cacheKey: z.ZodString;
46
+ recompute: z.ZodBoolean;
47
+ readSet: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
48
+ kind: z.ZodLiteral<"point">;
49
+ table: z.ZodString;
50
+ id: z.ZodString;
51
+ tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
52
+ expectedCommitTs: z.ZodOptional<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<bigint, string>>>>;
53
+ }, z.core.$strip>, z.ZodObject<{
54
+ kind: z.ZodLiteral<"range">;
55
+ table: z.ZodString;
56
+ tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
57
+ predicate: z.ZodType<import("../client").Predicate, unknown, z.core.$ZodTypeInternals<import("../client").Predicate, unknown>>;
58
+ columns: z.ZodArray<z.ZodString>;
59
+ orderBy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
60
+ limit: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
61
+ offset: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
62
+ }, z.core.$strip>]>>;
63
+ }, z.core.$strip>>;
64
+ export type RegisterSubscriptionBatchResult = z.infer<typeof RegisterSubscriptionBatchResultSchema>;
65
+ export declare const UpdateSubscriptionReadSetParamsSchema: z.ZodObject<{
66
+ cacheKey: z.ZodString;
67
+ subId: z.ZodString;
68
+ instanceName: z.ZodString;
69
+ lastSnapshotTs: z.ZodPipe<z.ZodString, z.ZodTransform<bigint, string>>;
70
+ readSet: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
71
+ kind: z.ZodLiteral<"point">;
72
+ table: z.ZodString;
73
+ id: z.ZodString;
74
+ tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
75
+ expectedCommitTs: z.ZodOptional<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<bigint, string>>>>;
76
+ }, z.core.$strip>, z.ZodObject<{
77
+ kind: z.ZodLiteral<"range">;
78
+ table: z.ZodString;
79
+ tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
80
+ predicate: z.ZodType<import("../client").Predicate, unknown, z.core.$ZodTypeInternals<import("../client").Predicate, unknown>>;
81
+ columns: z.ZodArray<z.ZodString>;
82
+ orderBy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
83
+ limit: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
84
+ offset: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
85
+ }, z.core.$strip>]>>;
86
+ }, z.core.$strip>;
87
+ export type UpdateSubscriptionReadSetParams = z.infer<typeof UpdateSubscriptionReadSetParamsSchema>;
88
+ /**
89
+ * `tracked: false` means the sub-manager has no record of this subId (e.g.
90
+ * a restart wiped state and the caller hasn't re-registered yet). The app
91
+ * server should treat this as a signal to register the sub before retrying.
92
+ */
93
+ export declare const UpdateSubscriptionReadSetResultSchema: z.ZodObject<{
94
+ tracked: z.ZodBoolean;
95
+ }, z.core.$strip>;
96
+ export type UpdateSubscriptionReadSetResult = z.infer<typeof UpdateSubscriptionReadSetResultSchema>;
97
+ export declare const UnregisterSubscriptionParamsSchema: z.ZodObject<{
98
+ subId: z.ZodString;
99
+ instanceName: z.ZodString;
100
+ }, z.core.$strip>;
101
+ export type UnregisterSubscriptionParams = z.infer<typeof UnregisterSubscriptionParamsSchema>;
102
+ export declare const UnregisterSubscriptionsParamsSchema: z.ZodArray<z.ZodObject<{
103
+ subId: z.ZodString;
104
+ instanceName: z.ZodString;
105
+ }, z.core.$strip>>;
106
+ export type UnregisterSubscriptionsParams = z.infer<typeof UnregisterSubscriptionsParamsSchema>;
107
+ export declare const UnregisterSubscriptionResultSchema: z.ZodObject<{
108
+ ok: z.ZodBoolean;
109
+ }, z.core.$strip>;
110
+ export type UnregisterSubscriptionResult = z.infer<typeof UnregisterSubscriptionResultSchema>;
111
+ export declare const UnregisterSubscriptionsResultSchema: z.ZodArray<z.ZodObject<{
112
+ ok: z.ZodBoolean;
113
+ }, z.core.$strip>>;
114
+ export type UnregisterSubscriptionsResult = z.infer<typeof UnregisterSubscriptionsResultSchema>;
115
+ export declare const InvalidateWritesetParamsSchema: z.ZodObject<{
116
+ writeSet: z.ZodArray<z.ZodObject<{
117
+ table: z.ZodString;
118
+ tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
119
+ id: z.ZodString;
120
+ op: z.ZodEnum<{
121
+ insert: "insert";
122
+ update: "update";
123
+ delete: "delete";
124
+ }>;
125
+ data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
126
+ prevData: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
127
+ expectedCommitTs: z.ZodOptional<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<bigint, string>>>>;
128
+ }, z.core.$strip>>;
129
+ }, z.core.$strip>;
130
+ export type InvalidateWritesetParams = z.infer<typeof InvalidateWritesetParamsSchema>;
131
+ export declare const AffectedSubscriptionSchema: z.ZodObject<{
132
+ subId: z.ZodString;
133
+ queryName: z.ZodString;
134
+ args: z.ZodUnknown;
135
+ cacheKey: z.ZodString;
136
+ notifyInstances: z.ZodArray<z.ZodString>;
137
+ }, z.core.$strip>;
138
+ export type AffectedSubscription = z.infer<typeof AffectedSubscriptionSchema>;
139
+ export declare const InvalidateWritesetResultSchema: z.ZodObject<{
140
+ affected: z.ZodArray<z.ZodObject<{
141
+ subId: z.ZodString;
142
+ queryName: z.ZodString;
143
+ args: z.ZodUnknown;
144
+ cacheKey: z.ZodString;
145
+ notifyInstances: z.ZodArray<z.ZodString>;
146
+ }, z.core.$strip>>;
147
+ }, z.core.$strip>;
148
+ export type InvalidateWritesetResult = z.infer<typeof InvalidateWritesetResultSchema>;
149
+ export declare const RegistrationRecordSchema: z.ZodObject<{
150
+ queryName: z.ZodString;
151
+ args: z.ZodUnknown;
152
+ queryIdentity: z.ZodString;
153
+ cacheKey: z.ZodString;
154
+ }, z.core.$strip>;
155
+ export type RegistrationRecord = z.infer<typeof RegistrationRecordSchema>;
156
+ export interface TrackedSubscription {
157
+ subId: string;
158
+ queryName: string;
159
+ args: unknown;
160
+ cacheKey: string;
161
+ lastSnapshotTs: bigint;
162
+ readSet: ReadEntry[];
163
+ rawReadSet: RawReadEntry[];
164
+ /** All app server instances that currently hold this subscription. */
165
+ instances: Set<string>;
166
+ timeout: NodeJS.Timeout | null;
167
+ }
168
+ //# sourceMappingURL=subscription-manager-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription-manager-types.d.ts","sourceRoot":"","sources":["../../../src/server/subscription-manager-types.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,KAAK,CAAC;AACpB,OAAO,EAAgB,YAAY,EAAE,SAAS,EAAqC,MAAM,gBAAgB,CAAC;AAY1G,eAAO,MAAM,gCAAgC;;;;;;;;iBAoB3C,CAAC;AACH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gCAAgC,CAAC,CAAC;AAE1F,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;iBAI3C,CAAC;AACH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gCAAgC,CAAC,CAAC;AAE1F,eAAO,MAAM,qCAAqC;;;;;;;;kBAA4C,CAAC;AAC/F,MAAM,MAAM,+BAA+B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qCAAqC,CAAC,CAAC;AAEpG,eAAO,MAAM,qCAAqC;;;;;;;;;;;;;;;;;;;kBAA4C,CAAC;AAC/F,MAAM,MAAM,+BAA+B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qCAAqC,CAAC,CAAC;AAEpG,eAAO,MAAM,qCAAqC;;;;;;;;;;;;;;;;;;;;;iBAMhD,CAAC;AACH,MAAM,MAAM,+BAA+B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qCAAqC,CAAC,CAAC;AAEpG;;;;GAIG;AACH,eAAO,MAAM,qCAAqC;;iBAEhD,CAAC;AACH,MAAM,MAAM,+BAA+B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qCAAqC,CAAC,CAAC;AAEpG,eAAO,MAAM,kCAAkC;;;iBAG7C,CAAC;AACH,MAAM,MAAM,4BAA4B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kCAAkC,CAAC,CAAC;AAE9F,eAAO,MAAM,mCAAmC;;;kBAA8C,CAAC;AAC/F,MAAM,MAAM,6BAA6B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mCAAmC,CAAC,CAAC;AAEhG,eAAO,MAAM,kCAAkC;;iBAAgC,CAAC;AAChF,MAAM,MAAM,4BAA4B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kCAAkC,CAAC,CAAC;AAE9F,eAAO,MAAM,mCAAmC;;kBAAyC,CAAC;AAC1F,MAAM,MAAM,6BAA6B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mCAAmC,CAAC,CAAC;AAEhG,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;iBAEzC,CAAC;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,CAAC;AAEtF,eAAO,MAAM,0BAA0B;;;;;;iBAarC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE9E,eAAO,MAAM,8BAA8B;;;;;;;;iBAEzC,CAAC;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,CAAC;AAStF,eAAO,MAAM,wBAAwB;;;;;iBAKnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,MAAM,WAAW,mBAAmB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,UAAU,EAAE,YAAY,EAAE,CAAC;IAC3B,sEAAsE;IACtE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;CAClC"}
@@ -0,0 +1,94 @@
1
+ import z from "zod";
2
+ import { BigIntSchema, ReadEntrySchema, WriteEntrySchema } from "../db/types_db";
3
+ // ─── RPC Schemas ──────────────────────────────────────────────────────────────
4
+ //
5
+ // The wire protocol intentionally has NO `_clientVersion` / `_resync` /
6
+ // `serverVersion` fields. Ordering of concurrent `updateSubscriptionReadSet`
7
+ // calls is enforced by `lastSnapshotTs` (which is monotonic — it comes from
8
+ // `Database.getLatestSnapshotTimestamp()`). Recovery after a sub-manager
9
+ // restart is driven by the app server iterating its own
10
+ // `serverSubscriptions` map and re-registering each one using params
11
+ // persisted in Redis under `sl:reg:<subId>`.
12
+ export const RegisterSubscriptionParamsSchema = z.object({
13
+ /**
14
+ * Caller-computed FNV-1a routing key + identity for this subscription.
15
+ * The sub-manager trusts these values rather than re-deriving them from
16
+ * (queryName, args, queryIdentity); this avoids one stringify+SHA1 per
17
+ * register RPC. Trust is fine: the sub-manager RPC channel is fully
18
+ * internal.
19
+ */
20
+ subId: z.string(),
21
+ cacheKey: z.string(),
22
+ queryName: z.string(),
23
+ args: z.unknown(),
24
+ /**
25
+ * Segmentation key used in the subId/cacheKey hash. Defaults to the
26
+ * authenticated user's id ("anonymous" when none), unless the
27
+ * procedure overrides it via `QueryConfig.queryIdentity`.
28
+ */
29
+ queryIdentity: z.string(),
30
+ instanceName: z.string(),
31
+ lastSnapshotTs: BigIntSchema,
32
+ });
33
+ export const RegisterSubscriptionResultSchema = z.object({
34
+ cacheKey: z.string(),
35
+ recompute: z.boolean(),
36
+ readSet: z.array(ReadEntrySchema),
37
+ });
38
+ export const RegisterSubscriptionBatchParamsSchema = z.array(RegisterSubscriptionParamsSchema);
39
+ export const RegisterSubscriptionBatchResultSchema = z.array(RegisterSubscriptionResultSchema);
40
+ export const UpdateSubscriptionReadSetParamsSchema = z.object({
41
+ cacheKey: z.string(),
42
+ subId: z.string(),
43
+ instanceName: z.string(),
44
+ lastSnapshotTs: BigIntSchema,
45
+ readSet: z.array(ReadEntrySchema),
46
+ });
47
+ /**
48
+ * `tracked: false` means the sub-manager has no record of this subId (e.g.
49
+ * a restart wiped state and the caller hasn't re-registered yet). The app
50
+ * server should treat this as a signal to register the sub before retrying.
51
+ */
52
+ export const UpdateSubscriptionReadSetResultSchema = z.object({
53
+ tracked: z.boolean(),
54
+ });
55
+ export const UnregisterSubscriptionParamsSchema = z.object({
56
+ subId: z.string(),
57
+ instanceName: z.string(),
58
+ });
59
+ export const UnregisterSubscriptionsParamsSchema = z.array(UnregisterSubscriptionParamsSchema);
60
+ export const UnregisterSubscriptionResultSchema = z.object({ ok: z.boolean() });
61
+ export const UnregisterSubscriptionsResultSchema = z.array(z.object({ ok: z.boolean() }));
62
+ export const InvalidateWritesetParamsSchema = z.object({
63
+ writeSet: z.array(WriteEntrySchema),
64
+ });
65
+ export const AffectedSubscriptionSchema = z.object({
66
+ subId: z.string(),
67
+ queryName: z.string(),
68
+ args: z.unknown(),
69
+ cacheKey: z.string(),
70
+ /**
71
+ * Every live instance that currently holds this subId. Routing rules:
72
+ * • If the writer is in this list, it recomputes locally and publishes
73
+ * an `update` to the rest (its own id is filtered by the publisher).
74
+ * • Otherwise the writer broadcasts a `recompute-race` to every entry;
75
+ * receivers race for a Redis lock and the winner recomputes.
76
+ */
77
+ notifyInstances: z.array(z.string()),
78
+ });
79
+ export const InvalidateWritesetResultSchema = z.object({
80
+ affected: z.array(AffectedSubscriptionSchema),
81
+ });
82
+ // ─── Registration record persisted to Redis ──────────────────────────────────
83
+ //
84
+ // Stored at `sl:reg:<subId>` by the sub-manager when a brand-new subscription
85
+ // is created, and deleted by the sub-manager when the last instance leaves.
86
+ // The app server reads this on reconnect to know how to re-register its
87
+ // known subIds.
88
+ export const RegistrationRecordSchema = z.object({
89
+ queryName: z.string(),
90
+ args: z.unknown(),
91
+ queryIdentity: z.string(),
92
+ cacheKey: z.string(),
93
+ });
94
+ //# sourceMappingURL=subscription-manager-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription-manager-types.js","sourceRoot":"","sources":["../../../src/server/subscription-manager-types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=subscription-manager-worker-entry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription-manager-worker-entry.d.ts","sourceRoot":"","sources":["../../../src/server/subscription-manager-worker-entry.ts"],"names":[],"mappings":""}
@@ -0,0 +1,127 @@
1
+ import { parentPort } from "node:worker_threads";
2
+ import Redis from "ioredis";
3
+ import { CacheLayer } from "../db/cache";
4
+ import { PgDatabase } from "../db/postgres";
5
+ import { MySqlDatabase } from "../db/mysql";
6
+ import { mapWriteSetToRaw } from "./overlap-checker";
7
+ import { InvalidateWritesetParamsSchema, RegisterSubscriptionBatchParamsSchema, RegisterSubscriptionParamsSchema, UnregisterSubscriptionParamsSchema, UnregisterSubscriptionsParamsSchema, UpdateSubscriptionReadSetParamsSchema, } from "./subscription-manager-types";
8
+ import { SubscriptionWorker } from "./subscription-worker";
9
+ import { MsgType, } from "./subscription-manager-worker-protocol";
10
+ import { logger as baseLogger } from "../logger";
11
+ if (!parentPort) {
12
+ throw new Error("subscription-manager-worker-entry must run inside a worker_threads Worker");
13
+ }
14
+ const port = parentPort;
15
+ const logger = baseLogger.child({ name: "SUBS_WRK_ENTRY" });
16
+ let worker = null;
17
+ let db = null;
18
+ let cache = null;
19
+ let redis = null;
20
+ async function init(payload) {
21
+ redis = new Redis(payload.upstash.redisUrl, {
22
+ connectTimeout: 15_000,
23
+ maxRetriesPerRequest: 5,
24
+ });
25
+ cache = new CacheLayer(redis, payload.cacheTTLSeconds);
26
+ if (payload.database.type === "postgres") {
27
+ db = new PgDatabase(logger.child({ database: "postgres", worker: payload.workerId }), {
28
+ ...payload.database,
29
+ connectionString: payload.database.connectionString,
30
+ max: payload.maxConnectionsPerWorker,
31
+ min: payload.database.minConnections ?? 1,
32
+ idleTimeoutMillis: payload.database.idleTimeoutMillis ?? 30_000,
33
+ connectionTimeoutMillis: payload.database.connectionTimeoutMillis ?? 7_000,
34
+ });
35
+ }
36
+ else {
37
+ db = new MySqlDatabase(logger.child({ database: "mysql", worker: payload.workerId }), {
38
+ ...payload.database,
39
+ connectionLimit: payload.maxConnectionsPerWorker,
40
+ idleTimeout: payload.database.idleTimeoutMillis ?? 30_000,
41
+ connectTimeout: payload.database.connectionTimeoutMillis ?? 7_000,
42
+ waitForConnections: true,
43
+ queueLimit: payload.database.queueLimit ?? 0,
44
+ });
45
+ }
46
+ worker = new SubscriptionWorker(payload.workerId, cache, db);
47
+ }
48
+ async function dispatch(req) {
49
+ if (req.type === MsgType.Init) {
50
+ await init(req.payload);
51
+ return null;
52
+ }
53
+ if (!worker) {
54
+ throw new Error("Worker received message before Init");
55
+ }
56
+ switch (req.type) {
57
+ case MsgType.Register: {
58
+ const params = RegisterSubscriptionParamsSchema.parse(req.payload);
59
+ return worker.register(params);
60
+ }
61
+ case MsgType.RegisterBatch: {
62
+ const params = RegisterSubscriptionBatchParamsSchema.parse(req.payload);
63
+ return Promise.all(params.map((p) => worker.register(p)));
64
+ }
65
+ case MsgType.UpdateReadSet: {
66
+ const params = UpdateSubscriptionReadSetParamsSchema.parse(req.payload);
67
+ return worker.updateReadSet(params);
68
+ }
69
+ case MsgType.Unregister: {
70
+ const params = UnregisterSubscriptionParamsSchema.parse(req.payload);
71
+ return worker.unregister(params);
72
+ }
73
+ case MsgType.Unregisters: {
74
+ const params = UnregisterSubscriptionsParamsSchema.parse(req.payload);
75
+ return worker.unregisters(params);
76
+ }
77
+ case MsgType.Invalidate: {
78
+ const { writeSet } = InvalidateWritesetParamsSchema.parse(req.payload);
79
+ const rawWriteSet = mapWriteSetToRaw(writeSet);
80
+ return worker.invalidate(rawWriteSet);
81
+ }
82
+ case MsgType.MinSubscriptionTs: {
83
+ const m = worker.minSubscriptionTs();
84
+ // bigint isn't structured-cloneable via JSON; postMessage handles
85
+ // bigints natively, so we return it as-is.
86
+ return m;
87
+ }
88
+ case MsgType.LatestSnapshotTs: {
89
+ return db.getLatestSnapshotTimestamp();
90
+ }
91
+ case MsgType.Prune: {
92
+ const ts = req.payload;
93
+ return db.pruneCommitLogsBefore(ts);
94
+ }
95
+ case MsgType.Shutdown: {
96
+ try {
97
+ await db?.close();
98
+ }
99
+ catch (_) { /* ignore */ }
100
+ try {
101
+ await redis?.quit?.();
102
+ }
103
+ catch (_) { /* ignore */ }
104
+ return null;
105
+ }
106
+ default: {
107
+ throw new Error(`Unknown MsgType: ${req.type}`);
108
+ }
109
+ }
110
+ }
111
+ port.on("message", async (req) => {
112
+ try {
113
+ const result = await dispatch(req);
114
+ const res = { reqId: req.reqId, ok: true, result };
115
+ port.postMessage(res);
116
+ }
117
+ catch (err) {
118
+ const e = err;
119
+ const res = {
120
+ reqId: req.reqId,
121
+ ok: false,
122
+ error: { message: e?.message ?? String(err), stack: e?.stack },
123
+ };
124
+ port.postMessage(res);
125
+ }
126
+ });
127
+ //# sourceMappingURL=subscription-manager-worker-entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription-manager-worker-entry.js","sourceRoot":"","sources":["../../../src/server/subscription-manager-worker-entry.ts"],"names":[],"mappings":"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"}