meridian-sdk 0.3.0 → 0.3.2
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.
- package/README.md +29 -7
- package/dist/client.d.ts +7 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +11 -0
- package/dist/client.js.map +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +1 -0
- package/dist/constants.js.map +1 -1
- package/dist/transport/websocket.d.ts +8 -0
- package/dist/transport/websocket.d.ts.map +1 -1
- package/dist/transport/websocket.js +44 -2
- package/dist/transport/websocket.js.map +1 -1
- package/package.json +11 -1
- package/src/client.ts +13 -0
- package/src/constants.ts +1 -0
- package/src/transport/websocket.ts +45 -1
- package/test/offline-queue.test.ts +156 -0
package/README.md
CHANGED
|
@@ -5,9 +5,9 @@ TypeScript SDK for [Meridian](../README.md) — Effect-based, fully typed, msgpa
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
bun add meridian-sdk
|
|
8
|
+
bun add meridian-sdk
|
|
9
9
|
# or
|
|
10
|
-
npm install meridian-sdk
|
|
10
|
+
npm install meridian-sdk
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
## Quick start
|
|
@@ -16,7 +16,6 @@ npm install meridian-sdk effect msgpackr
|
|
|
16
16
|
import { Effect, Schema } from "effect";
|
|
17
17
|
import { MeridianClient } from "meridian-sdk";
|
|
18
18
|
|
|
19
|
-
// MeridianClient.create() parses + validates the token — returns Effect
|
|
20
19
|
const client = await Effect.runPromise(
|
|
21
20
|
MeridianClient.create({
|
|
22
21
|
url: "http://localhost:3000",
|
|
@@ -42,6 +41,11 @@ const room = client.presence("pr:room", Cursor);
|
|
|
42
41
|
room.heartbeat({ x: 100, y: 200 }, 30_000);
|
|
43
42
|
room.onChange(entries => console.log("online:", entries));
|
|
44
43
|
|
|
44
|
+
// CRDTMap — composite document with named CRDT fields
|
|
45
|
+
const doc = client.crdtmap("doc:settings");
|
|
46
|
+
doc.lwwSet("theme", "dark");
|
|
47
|
+
doc.incrementCounter("edits");
|
|
48
|
+
|
|
45
49
|
// Close WebSocket when done
|
|
46
50
|
client.close();
|
|
47
51
|
```
|
|
@@ -89,18 +93,36 @@ await Effect.runPromise(
|
|
|
89
93
|
| `client.orset(id, schema?)` | `ORSetHandle<T>` | Optional |
|
|
90
94
|
| `client.lwwregister(id, schema?)` | `LwwRegisterHandle<T>` | Optional |
|
|
91
95
|
| `client.presence(id, schema?)` | `PresenceHandle<T>` | Optional |
|
|
96
|
+
| `client.crdtmap(id)` | `CRDTMapHandle` | — |
|
|
92
97
|
|
|
93
98
|
Without a schema, `T = unknown`. With a schema, incoming deltas are validated at runtime via `Schema.decodeUnknownSync`.
|
|
94
99
|
|
|
100
|
+
### Offline queue
|
|
101
|
+
|
|
102
|
+
Operations sent while disconnected are buffered automatically and flushed in order on reconnect. No configuration needed — it works transparently for all CRDT handles.
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
// Check how many ops are pending (e.g. for a UI indicator)
|
|
106
|
+
client.pendingOpCount; // number
|
|
107
|
+
|
|
108
|
+
// Subscribe to connection state changes
|
|
109
|
+
const unsub = client.onStateChange(state => {
|
|
110
|
+
console.log("connection state:", state); // "CONNECTED" | "DISCONNECTED" | "CONNECTING" | "CLOSING"
|
|
111
|
+
});
|
|
112
|
+
unsub(); // unsubscribe
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The queue holds up to 500 ops. If the limit is reached, the oldest op is dropped to make room for the newest.
|
|
116
|
+
|
|
95
117
|
### HTTP client (`client.http`)
|
|
96
118
|
|
|
97
119
|
All methods return `Effect<T, HttpError | NetworkError>`:
|
|
98
120
|
|
|
99
121
|
```ts
|
|
100
|
-
client.http.getCrdt(ns, id)
|
|
101
|
-
client.http.postOp(ns, id, op)
|
|
102
|
-
client.http.syncCrdt(ns, id, sinceVc)
|
|
103
|
-
client.http.issueToken(ns, opts)
|
|
122
|
+
client.http.getCrdt(ns, id) // → Effect<CrdtGetResponse, ...>
|
|
123
|
+
client.http.postOp(ns, id, op) // → Effect<CrdtOpResponse, ...>
|
|
124
|
+
client.http.syncCrdt(ns, id, sinceVc?) // → Effect<CrdtGetResponse, ...>
|
|
125
|
+
client.http.issueToken(ns, opts) // → Effect<TokenIssueResponse, ...>
|
|
104
126
|
```
|
|
105
127
|
|
|
106
128
|
## Wire protocol
|
package/dist/client.d.ts
CHANGED
|
@@ -184,6 +184,13 @@ export declare class MeridianClient {
|
|
|
184
184
|
*/
|
|
185
185
|
crdtmap(crdtId: string): CRDTMapHandle;
|
|
186
186
|
waitForConnected(timeoutMs?: number): Promise<void>;
|
|
187
|
+
/** Number of ops buffered locally, waiting to be sent on reconnect. */
|
|
188
|
+
get pendingOpCount(): number;
|
|
189
|
+
/**
|
|
190
|
+
* Subscribe to connection state changes. Returns an unsubscribe function.
|
|
191
|
+
* Useful for building "syncing" indicators in the UI.
|
|
192
|
+
*/
|
|
193
|
+
onStateChange(listener: (state: import("./transport/websocket.js").WsState) => void): () => void;
|
|
187
194
|
/**
|
|
188
195
|
* Closes the underlying WebSocket connection.
|
|
189
196
|
*
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE7C,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAUlD,OAAO,KAAK,EAAa,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEtE,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,cAAc;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAE7B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAc;IACxC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAG1B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqC;IAC/D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsC;IAChE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA2C;IACrE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiD;IAC3E,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA8C;IACxE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoC;IAE9D,OAAO;IAsBP;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,MAAM,CAAC,MAAM,CACX,MAAM,EAAE,oBAAoB,GAC3B,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,eAAe,GAAG,iBAAiB,CAAC;IAMrE;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc;IAUxC;;;;;;;;;;;;;;;OAeG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe;IAU1C;;;;;;;;;;;;;;;;;OAiBG;IACH,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC;IAWnE;;;;;;;;;;;;;;;;;OAiBG;IACH,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC;IAW/E;;;;;;;;;;;;;;;;;;OAkBG;IACH,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC;IAWzE;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa;IAUtC,gBAAgB,CAAC,SAAS,SAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlD;;;;;;OAMG;IACH,KAAK,IAAI,IAAI;IAIb,OAAO,CAAC,eAAe;CAkCxB"}
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
CHANGED
|
@@ -252,6 +252,17 @@ export class MeridianClient {
|
|
|
252
252
|
waitForConnected(timeoutMs = 5_000) {
|
|
253
253
|
return this.transport.waitForConnected(timeoutMs);
|
|
254
254
|
}
|
|
255
|
+
/** Number of ops buffered locally, waiting to be sent on reconnect. */
|
|
256
|
+
get pendingOpCount() {
|
|
257
|
+
return this.transport.pendingOpCount;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Subscribe to connection state changes. Returns an unsubscribe function.
|
|
261
|
+
* Useful for building "syncing" indicators in the UI.
|
|
262
|
+
*/
|
|
263
|
+
onStateChange(listener) {
|
|
264
|
+
return this.transport.onStateChange(listener);
|
|
265
|
+
}
|
|
255
266
|
/**
|
|
256
267
|
* Closes the underlying WebSocket connection.
|
|
257
268
|
*
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/constants.d.ts
CHANGED
|
@@ -4,4 +4,5 @@ export declare const BACKOFF_MULTIPLIER = 2;
|
|
|
4
4
|
export declare const JITTER_MULTIPLIER = 0.2;
|
|
5
5
|
export declare const DEFAULT_TIMEOUT_MS = 5000;
|
|
6
6
|
export declare const TOKEN_SKEW_MS = 5000;
|
|
7
|
+
export declare const OFFLINE_QUEUE_MAX = 500;
|
|
7
8
|
//# sourceMappingURL=constants.d.ts.map
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,MAAM,CAAC;AACtC,eAAO,MAAM,cAAc,QAAS,CAAC;AACrC,eAAO,MAAM,kBAAkB,IAAI,CAAC;AACpC,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,kBAAkB,OAAQ,CAAC;AACxC,eAAO,MAAM,aAAa,OAAQ,CAAC"}
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,MAAM,CAAC;AACtC,eAAO,MAAM,cAAc,QAAS,CAAC;AACrC,eAAO,MAAM,kBAAkB,IAAI,CAAC;AACpC,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,kBAAkB,OAAQ,CAAC;AACxC,eAAO,MAAM,aAAa,OAAQ,CAAC;AACnC,eAAO,MAAM,iBAAiB,MAAM,CAAC"}
|
package/dist/constants.js
CHANGED
package/dist/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AACtC,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC;AACrC,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AACpC,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAC;AACrC,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,CAAC;AACxC,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,CAAC"}
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AACtC,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC;AACrC,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AACpC,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAC;AACrC,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,CAAC;AACxC,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,CAAC;AACnC,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAC"}
|
|
@@ -17,12 +17,19 @@ export declare class WsTransport {
|
|
|
17
17
|
private reconnectTimer;
|
|
18
18
|
private closed;
|
|
19
19
|
private readonly subscriptions;
|
|
20
|
+
private readonly pendingOps;
|
|
20
21
|
constructor(config: WsTransportConfig);
|
|
21
22
|
connect(): void;
|
|
22
23
|
close(): void;
|
|
23
24
|
subscribe(crdtId: string, sinceVc?: VectorClock): void;
|
|
24
25
|
updateClock(crdtId: string, vc: VectorClock): void;
|
|
25
26
|
send(msg: Parameters<typeof encodeClientMsg>[0]): void;
|
|
27
|
+
get pendingOpCount(): number;
|
|
28
|
+
/**
|
|
29
|
+
* Subscribe to connection state changes. Returns an unsubscribe function.
|
|
30
|
+
* Compatible with React's `useSyncExternalStore` subscribe parameter.
|
|
31
|
+
*/
|
|
32
|
+
onStateChange(listener: (state: WsState) => void): () => void;
|
|
26
33
|
get currentState(): WsState;
|
|
27
34
|
waitForConnected(timeoutMs?: number): Promise<void>;
|
|
28
35
|
private doConnect;
|
|
@@ -30,6 +37,7 @@ export declare class WsTransport {
|
|
|
30
37
|
private clearReconnectTimer;
|
|
31
38
|
private transitionTo;
|
|
32
39
|
private resubscribeAll;
|
|
40
|
+
private flushPendingOps;
|
|
33
41
|
private sendSubscribe;
|
|
34
42
|
}
|
|
35
43
|
//# sourceMappingURL=websocket.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../../src/transport/websocket.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAsC,MAAM,aAAa,CAAC;AAClF,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../../src/transport/websocket.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAsC,MAAM,aAAa,CAAC;AAClF,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAU3D,MAAM,MAAM,OAAO,GACf,cAAc,GACd,YAAY,GACZ,WAAW,GACX,SAAS,CAAC;AAEd,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,CAAC;IACpC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IAEtC,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAkC;IAChE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA+C;gBAE9D,MAAM,EAAE,iBAAiB;IAKrC,OAAO,IAAI,IAAI;IAMf,KAAK,IAAI,IAAI;IAQb,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,IAAI;IAO1D,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,GAAG,IAAI;IAIlD,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IAWtD,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED;;;OAGG;IACH,aAAa,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI;IAe7D,IAAI,YAAY,IAAI,OAAO,CAE1B;IAED,gBAAgB,CAAC,SAAS,SAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IA0B/D,OAAO,CAAC,SAAS;IAuCjB,OAAO,CAAC,iBAAiB;IAWzB,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,eAAe;IAavB,OAAO,CAAC,aAAa;CAMtB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { encodeClientMsg, decodeServerMsg, encodeVectorClock } from "../codec.js";
|
|
3
|
-
import { BACKOFF_INITIAL_MS, BACKOFF_MAX_MS, BACKOFF_MULTIPLIER, JITTER_MULTIPLIER, DEFAULT_TIMEOUT_MS, } from "../constants.js";
|
|
3
|
+
import { BACKOFF_INITIAL_MS, BACKOFF_MAX_MS, BACKOFF_MULTIPLIER, JITTER_MULTIPLIER, DEFAULT_TIMEOUT_MS, OFFLINE_QUEUE_MAX, } from "../constants.js";
|
|
4
4
|
export class WsTransport {
|
|
5
5
|
config;
|
|
6
6
|
maxBackoffMs;
|
|
@@ -10,6 +10,7 @@ export class WsTransport {
|
|
|
10
10
|
reconnectTimer = null;
|
|
11
11
|
closed = false;
|
|
12
12
|
subscriptions = new Map();
|
|
13
|
+
pendingOps = [];
|
|
13
14
|
constructor(config) {
|
|
14
15
|
this.config = config;
|
|
15
16
|
this.maxBackoffMs = config.maxBackoffMs ?? BACKOFF_MAX_MS;
|
|
@@ -22,6 +23,7 @@ export class WsTransport {
|
|
|
22
23
|
}
|
|
23
24
|
close() {
|
|
24
25
|
this.closed = true;
|
|
26
|
+
this.pendingOps.length = 0;
|
|
25
27
|
this.clearReconnectTimer();
|
|
26
28
|
this.transitionTo("CLOSING");
|
|
27
29
|
this.ws?.close(1000, "client close");
|
|
@@ -37,10 +39,36 @@ export class WsTransport {
|
|
|
37
39
|
}
|
|
38
40
|
send(msg) {
|
|
39
41
|
if (this.state !== "CONNECTED" || this.ws === null) {
|
|
40
|
-
|
|
42
|
+
if (this.pendingOps.length >= OFFLINE_QUEUE_MAX) {
|
|
43
|
+
this.pendingOps.shift(); // drop oldest to make room
|
|
44
|
+
}
|
|
45
|
+
this.pendingOps.push(msg);
|
|
46
|
+
return;
|
|
41
47
|
}
|
|
42
48
|
this.ws.send(encodeClientMsg(msg));
|
|
43
49
|
}
|
|
50
|
+
get pendingOpCount() {
|
|
51
|
+
return this.pendingOps.length;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Subscribe to connection state changes. Returns an unsubscribe function.
|
|
55
|
+
* Compatible with React's `useSyncExternalStore` subscribe parameter.
|
|
56
|
+
*/
|
|
57
|
+
onStateChange(listener) {
|
|
58
|
+
const prev = this.config.onStateChange;
|
|
59
|
+
this.config.onStateChange = (s) => {
|
|
60
|
+
prev?.(s);
|
|
61
|
+
listener(s);
|
|
62
|
+
};
|
|
63
|
+
return () => {
|
|
64
|
+
if (prev !== undefined) {
|
|
65
|
+
this.config.onStateChange = prev;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
delete this.config.onStateChange;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
44
72
|
get currentState() {
|
|
45
73
|
return this.state;
|
|
46
74
|
}
|
|
@@ -132,6 +160,20 @@ export class WsTransport {
|
|
|
132
160
|
for (const [crdtId, vc] of this.subscriptions) {
|
|
133
161
|
this.sendSubscribe(crdtId, vc);
|
|
134
162
|
}
|
|
163
|
+
this.flushPendingOps();
|
|
164
|
+
}
|
|
165
|
+
flushPendingOps() {
|
|
166
|
+
const ops = this.pendingOps.splice(0);
|
|
167
|
+
for (let i = 0; i < ops.length; i++) {
|
|
168
|
+
try {
|
|
169
|
+
this.ws.send(encodeClientMsg(ops[i]));
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
// WebSocket closed between open and flush — re-queue remaining ops.
|
|
173
|
+
this.pendingOps.unshift(...ops.slice(i));
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
135
177
|
}
|
|
136
178
|
sendSubscribe(crdtId, vc) {
|
|
137
179
|
if (this.ws === null || this.state !== "CONNECTED")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websocket.js","sourceRoot":"","sources":["../../src/transport/websocket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAElF,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,
|
|
1
|
+
{"version":3,"file":"websocket.js","sourceRoot":"","sources":["../../src/transport/websocket.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "meridian-sdk",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "TypeScript SDK for Meridian CRDT server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -30,5 +30,15 @@
|
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
32
|
"typescript": ">=5.0.0"
|
|
33
|
+
},
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/Chahine-tech/meridian.git",
|
|
38
|
+
"directory": "packages/sdk"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://github.com/Chahine-tech/meridian#readme",
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/Chahine-tech/meridian/issues"
|
|
33
43
|
}
|
|
34
44
|
}
|
package/src/client.ts
CHANGED
|
@@ -288,6 +288,19 @@ export class MeridianClient {
|
|
|
288
288
|
return this.transport.waitForConnected(timeoutMs);
|
|
289
289
|
}
|
|
290
290
|
|
|
291
|
+
/** Number of ops buffered locally, waiting to be sent on reconnect. */
|
|
292
|
+
get pendingOpCount(): number {
|
|
293
|
+
return this.transport.pendingOpCount;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Subscribe to connection state changes. Returns an unsubscribe function.
|
|
298
|
+
* Useful for building "syncing" indicators in the UI.
|
|
299
|
+
*/
|
|
300
|
+
onStateChange(listener: (state: import("./transport/websocket.js").WsState) => void): () => void {
|
|
301
|
+
return this.transport.onStateChange(listener);
|
|
302
|
+
}
|
|
303
|
+
|
|
291
304
|
/**
|
|
292
305
|
* Closes the underlying WebSocket connection.
|
|
293
306
|
*
|
package/src/constants.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
BACKOFF_MULTIPLIER,
|
|
8
8
|
JITTER_MULTIPLIER,
|
|
9
9
|
DEFAULT_TIMEOUT_MS,
|
|
10
|
+
OFFLINE_QUEUE_MAX,
|
|
10
11
|
} from "../constants.js";
|
|
11
12
|
|
|
12
13
|
export type WsState =
|
|
@@ -34,6 +35,7 @@ export class WsTransport {
|
|
|
34
35
|
private closed = false;
|
|
35
36
|
|
|
36
37
|
private readonly subscriptions = new Map<string, VectorClock>();
|
|
38
|
+
private readonly pendingOps: Parameters<typeof encodeClientMsg>[0][] = [];
|
|
37
39
|
|
|
38
40
|
constructor(config: WsTransportConfig) {
|
|
39
41
|
this.config = config;
|
|
@@ -48,6 +50,7 @@ export class WsTransport {
|
|
|
48
50
|
|
|
49
51
|
close(): void {
|
|
50
52
|
this.closed = true;
|
|
53
|
+
this.pendingOps.length = 0;
|
|
51
54
|
this.clearReconnectTimer();
|
|
52
55
|
this.transitionTo("CLOSING");
|
|
53
56
|
this.ws?.close(1000, "client close");
|
|
@@ -66,11 +69,38 @@ export class WsTransport {
|
|
|
66
69
|
|
|
67
70
|
send(msg: Parameters<typeof encodeClientMsg>[0]): void {
|
|
68
71
|
if (this.state !== "CONNECTED" || this.ws === null) {
|
|
69
|
-
|
|
72
|
+
if (this.pendingOps.length >= OFFLINE_QUEUE_MAX) {
|
|
73
|
+
this.pendingOps.shift(); // drop oldest to make room
|
|
74
|
+
}
|
|
75
|
+
this.pendingOps.push(msg);
|
|
76
|
+
return;
|
|
70
77
|
}
|
|
71
78
|
this.ws.send(encodeClientMsg(msg));
|
|
72
79
|
}
|
|
73
80
|
|
|
81
|
+
get pendingOpCount(): number {
|
|
82
|
+
return this.pendingOps.length;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Subscribe to connection state changes. Returns an unsubscribe function.
|
|
87
|
+
* Compatible with React's `useSyncExternalStore` subscribe parameter.
|
|
88
|
+
*/
|
|
89
|
+
onStateChange(listener: (state: WsState) => void): () => void {
|
|
90
|
+
const prev = this.config.onStateChange;
|
|
91
|
+
this.config.onStateChange = (s) => {
|
|
92
|
+
prev?.(s);
|
|
93
|
+
listener(s);
|
|
94
|
+
};
|
|
95
|
+
return () => {
|
|
96
|
+
if (prev !== undefined) {
|
|
97
|
+
this.config.onStateChange = prev;
|
|
98
|
+
} else {
|
|
99
|
+
delete (this.config as Partial<WsTransportConfig>).onStateChange;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
74
104
|
get currentState(): WsState {
|
|
75
105
|
return this.state;
|
|
76
106
|
}
|
|
@@ -168,6 +198,20 @@ export class WsTransport {
|
|
|
168
198
|
for (const [crdtId, vc] of this.subscriptions) {
|
|
169
199
|
this.sendSubscribe(crdtId, vc);
|
|
170
200
|
}
|
|
201
|
+
this.flushPendingOps();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
private flushPendingOps(): void {
|
|
205
|
+
const ops = this.pendingOps.splice(0);
|
|
206
|
+
for (let i = 0; i < ops.length; i++) {
|
|
207
|
+
try {
|
|
208
|
+
this.ws!.send(encodeClientMsg(ops[i]!));
|
|
209
|
+
} catch {
|
|
210
|
+
// WebSocket closed between open and flush — re-queue remaining ops.
|
|
211
|
+
this.pendingOps.unshift(...ops.slice(i));
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
171
215
|
}
|
|
172
216
|
|
|
173
217
|
private sendSubscribe(crdtId: string, vc: VectorClock): void {
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for WsTransport offline op queue.
|
|
3
|
+
*
|
|
4
|
+
* We stub the global WebSocket to control connection state without a real server.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, it, expect, beforeEach, afterEach } from "bun:test";
|
|
8
|
+
import { WsTransport } from "../src/transport/websocket.js";
|
|
9
|
+
import { OFFLINE_QUEUE_MAX } from "../src/constants.js";
|
|
10
|
+
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Fake WebSocket
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
type WsEventName = "open" | "message" | "close" | "error";
|
|
16
|
+
|
|
17
|
+
class FakeWebSocket {
|
|
18
|
+
binaryType: string = "arraybuffer";
|
|
19
|
+
readonly sent: Uint8Array[] = [];
|
|
20
|
+
private readonly listeners = new Map<WsEventName, (() => void)[]>();
|
|
21
|
+
closeCode: number | undefined;
|
|
22
|
+
closeReason: string | undefined;
|
|
23
|
+
|
|
24
|
+
addEventListener(event: WsEventName, handler: () => void): void {
|
|
25
|
+
const list = this.listeners.get(event) ?? [];
|
|
26
|
+
list.push(handler);
|
|
27
|
+
this.listeners.set(event, list);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
send(data: Uint8Array): void {
|
|
31
|
+
this.sent.push(data);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
close(code: number, reason: string): void {
|
|
35
|
+
this.closeCode = code;
|
|
36
|
+
this.closeReason = reason;
|
|
37
|
+
this.emit("close");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
emit(event: WsEventName): void {
|
|
41
|
+
for (const handler of this.listeners.get(event) ?? []) {
|
|
42
|
+
handler();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let fakeWs: FakeWebSocket;
|
|
48
|
+
|
|
49
|
+
// Patch globalThis.WebSocket before each test.
|
|
50
|
+
beforeEach(() => {
|
|
51
|
+
fakeWs = new FakeWebSocket();
|
|
52
|
+
(globalThis as unknown as Record<string, unknown>).WebSocket = function () {
|
|
53
|
+
return fakeWs;
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
afterEach(() => {
|
|
58
|
+
delete (globalThis as unknown as Record<string, unknown>).WebSocket;
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
function makeTransport(onStateChange?: (s: string) => void): WsTransport {
|
|
62
|
+
return new WsTransport({
|
|
63
|
+
url: "ws://localhost:3000",
|
|
64
|
+
token: "tok",
|
|
65
|
+
onMessage: () => {},
|
|
66
|
+
onStateChange,
|
|
67
|
+
// Use tiny backoff so reconnect tests don't wait
|
|
68
|
+
maxBackoffMs: 10,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// Tests
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
|
|
76
|
+
describe("WsTransport offline queue", () => {
|
|
77
|
+
it("buffers ops sent while DISCONNECTED", () => {
|
|
78
|
+
const t = makeTransport();
|
|
79
|
+
t.connect();
|
|
80
|
+
// Not yet open — state is CONNECTING
|
|
81
|
+
expect(t.currentState).toBe("CONNECTING");
|
|
82
|
+
|
|
83
|
+
t.send({ Op: { crdt_id: "gc:views", op_bytes: new Uint8Array([1]) } });
|
|
84
|
+
t.send({ Op: { crdt_id: "gc:views", op_bytes: new Uint8Array([2]) } });
|
|
85
|
+
|
|
86
|
+
expect(t.pendingOpCount).toBe(2);
|
|
87
|
+
expect(fakeWs.sent).toHaveLength(0);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("flushes buffered ops in order on reconnect (open event)", () => {
|
|
91
|
+
const t = makeTransport();
|
|
92
|
+
t.connect();
|
|
93
|
+
|
|
94
|
+
t.send({ Op: { crdt_id: "gc:views", op_bytes: new Uint8Array([1]) } });
|
|
95
|
+
t.send({ Op: { crdt_id: "gc:views", op_bytes: new Uint8Array([2]) } });
|
|
96
|
+
expect(t.pendingOpCount).toBe(2);
|
|
97
|
+
|
|
98
|
+
// Simulate server accepting the connection
|
|
99
|
+
fakeWs.emit("open");
|
|
100
|
+
|
|
101
|
+
expect(t.currentState).toBe("CONNECTED");
|
|
102
|
+
expect(t.pendingOpCount).toBe(0);
|
|
103
|
+
// fakeWs.sent contains: Subscribe msgs from resubscribeAll + 2 flushed ops
|
|
104
|
+
// We just verify the queue was drained and sends happened
|
|
105
|
+
expect(fakeWs.sent.length).toBeGreaterThanOrEqual(2);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("sends immediately when already CONNECTED", () => {
|
|
109
|
+
const t = makeTransport();
|
|
110
|
+
t.connect();
|
|
111
|
+
fakeWs.emit("open");
|
|
112
|
+
expect(t.currentState).toBe("CONNECTED");
|
|
113
|
+
|
|
114
|
+
const before = fakeWs.sent.length;
|
|
115
|
+
t.send({ Op: { crdt_id: "gc:views", op_bytes: new Uint8Array([42]) } });
|
|
116
|
+
|
|
117
|
+
expect(t.pendingOpCount).toBe(0);
|
|
118
|
+
expect(fakeWs.sent.length).toBe(before + 1);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("drops the oldest op when queue exceeds OFFLINE_QUEUE_MAX", () => {
|
|
122
|
+
const t = makeTransport();
|
|
123
|
+
t.connect();
|
|
124
|
+
// Fill the queue beyond the limit
|
|
125
|
+
for (let i = 0; i <= OFFLINE_QUEUE_MAX; i++) {
|
|
126
|
+
t.send({ Op: { crdt_id: "gc:x", op_bytes: new Uint8Array([i % 256]) } });
|
|
127
|
+
}
|
|
128
|
+
// Queue should be capped at OFFLINE_QUEUE_MAX
|
|
129
|
+
expect(t.pendingOpCount).toBe(OFFLINE_QUEUE_MAX);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("clears the queue on close()", () => {
|
|
133
|
+
const t = makeTransport();
|
|
134
|
+
t.connect();
|
|
135
|
+
|
|
136
|
+
t.send({ Op: { crdt_id: "gc:views", op_bytes: new Uint8Array([1]) } });
|
|
137
|
+
t.send({ Op: { crdt_id: "gc:views", op_bytes: new Uint8Array([2]) } });
|
|
138
|
+
expect(t.pendingOpCount).toBe(2);
|
|
139
|
+
|
|
140
|
+
t.close();
|
|
141
|
+
|
|
142
|
+
expect(t.pendingOpCount).toBe(0);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("does not send buffered ops after close()", () => {
|
|
146
|
+
const t = makeTransport();
|
|
147
|
+
t.connect();
|
|
148
|
+
|
|
149
|
+
t.send({ Op: { crdt_id: "gc:views", op_bytes: new Uint8Array([1]) } });
|
|
150
|
+
t.close();
|
|
151
|
+
|
|
152
|
+
// Even if open fires somehow, ops should not be sent
|
|
153
|
+
fakeWs.emit("open");
|
|
154
|
+
expect(fakeWs.sent).toHaveLength(0);
|
|
155
|
+
});
|
|
156
|
+
});
|