@rljson/rljson 0.0.75 → 0.0.76

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.
@@ -0,0 +1,41 @@
1
+ import { InsertHistoryTimeId } from '../insertHistory/insertHistory.ts';
2
+ import { ConnectorPayload } from './connector-payload.ts';
3
+ /**
4
+ * Client → Server request for missing refs on a specific route.
5
+ *
6
+ * Sent on the `${route}:gapfill:req` event when a Connector detects
7
+ * a gap in the sequence numbers it has received from a peer.
8
+ */
9
+ export type GapFillRequest = {
10
+ /** The route for which refs are missing. */
11
+ route: string;
12
+ /** The last sequence number the client has successfully processed. */
13
+ afterSeq: number;
14
+ /**
15
+ * Alternative / additional anchor: the last known InsertHistory timeId.
16
+ * The server may use this to determine the starting point if sequence
17
+ * numbers are unavailable.
18
+ */
19
+ afterTimeId?: InsertHistoryTimeId;
20
+ };
21
+ /**
22
+ * Server → Client response containing the missing refs.
23
+ *
24
+ * Sent on the `${route}:gapfill:res` event in response to a
25
+ * `GapFillRequest`. The `refs` array is ordered chronologically
26
+ * (oldest first).
27
+ */
28
+ export type GapFillResponse = {
29
+ /** The route this response corresponds to. */
30
+ route: string;
31
+ /** Ordered list of missing payloads (oldest first). */
32
+ refs: ConnectorPayload[];
33
+ };
34
+ /**
35
+ * Returns an example GapFillRequest.
36
+ */
37
+ export declare const gapFillRequestExample: () => GapFillRequest;
38
+ /**
39
+ * Returns an example GapFillResponse with two missing refs.
40
+ */
41
+ export declare const gapFillResponseExample: () => GapFillResponse;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Feature flags for hardened sync behavior.
3
+ *
4
+ * All flags default to `false` / `undefined`, so existing code that
5
+ * does not set a `SyncConfig` continues to work exactly as before.
6
+ *
7
+ * | Flag | Concept | Effect when enabled |
8
+ * |-------------------------|----------------------|----------------------------------------|
9
+ * | `causalOrdering` | Predecessor chain | Attach `seq` + `p` to payloads; |
10
+ * | | | detect gaps; request gap-fill |
11
+ * | `requireAck` | Acknowledgment | Wait for server ACK after send |
12
+ * | `ackTimeoutMs` | Acknowledgment | Timeout before treating ACK as failed |
13
+ * | `includeClientIdentity` | Client identity | Attach `c` + `t` to payloads |
14
+ * | `maxDedupSetSize` | Memory management | Cap dedup sets; default 10 000 |
15
+ */
16
+ export type SyncConfig = {
17
+ /**
18
+ * When `true`, the Connector attaches a monotonic `seq` number and
19
+ * causal predecessor timeIds (`p`) to every outgoing payload. Receiving
20
+ * Connectors detect sequence gaps and request gap-fill from the server.
21
+ */
22
+ causalOrdering?: boolean;
23
+ /**
24
+ * When `true`, the Connector awaits a server-side `AckPayload` after
25
+ * sending a ref. The `sendWithAck()` method becomes available.
26
+ */
27
+ requireAck?: boolean;
28
+ /**
29
+ * Timeout in milliseconds for awaiting an ACK from the server.
30
+ * Only meaningful when `requireAck` is `true`.
31
+ * Defaults to `10_000` (10 seconds) when not specified.
32
+ */
33
+ ackTimeoutMs?: number;
34
+ /**
35
+ * When `true`, the Connector attaches the stable `ClientId` (`c`) and
36
+ * a wall-clock timestamp (`t`) to every outgoing payload.
37
+ */
38
+ includeClientIdentity?: boolean;
39
+ /**
40
+ * Maximum number of entries per dedup set generation before rotation.
41
+ * The Connector uses two-generation eviction: when the current generation
42
+ * exceeds this limit, it becomes the previous generation and a new empty
43
+ * set is created. Lookups check both generations.
44
+ * Defaults to `10_000` when not specified.
45
+ */
46
+ maxDedupSetSize?: number;
47
+ /**
48
+ * Interval in milliseconds for the server to broadcast its latest ref
49
+ * to all connected clients as a heartbeat. This acts as a fallback
50
+ * in case the initial bootstrap message on connect was missed.
51
+ *
52
+ * When `undefined` or `0`, no periodic heartbeat is sent — only the
53
+ * immediate bootstrap on `addSocket()` is active.
54
+ *
55
+ * Recommended value: `30_000` (30 seconds) or higher.
56
+ */
57
+ bootstrapHeartbeatMs?: number;
58
+ };
59
+ /**
60
+ * Default SyncConfig — all features disabled (backward-compatible mode).
61
+ */
62
+ export declare const syncConfigDefault: () => SyncConfig;
63
+ /**
64
+ * Returns an example SyncConfig with all features enabled.
65
+ */
66
+ export declare const syncConfigFullExample: () => SyncConfig;
67
+ /**
68
+ * Returns an example SyncConfig with only causal ordering enabled.
69
+ */
70
+ export declare const syncConfigCausalOnlyExample: () => SyncConfig;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The set of socket event names used by the sync protocol for a given route.
3
+ * Using this helper avoids hard-coding event name strings across layers
4
+ * and prevents typos.
5
+ * @example
6
+ * ```ts
7
+ * const events = syncEvents('/sharedTree');
8
+ * socket.on(events.ref, handleRef);
9
+ * socket.on(events.ack, handleAck);
10
+ * socket.emit(events.gapFillReq, request);
11
+ * ```
12
+ */
13
+ export type SyncEventNames = {
14
+ /** Bidirectional: ref broadcast (existing event). */
15
+ ref: string;
16
+ /** Server → Client: delivery acknowledgment. */
17
+ ack: string;
18
+ /** Client → Server: individual client ACK of a received ref. */
19
+ ackClient: string;
20
+ /** Client → Server: request missing refs. */
21
+ gapFillReq: string;
22
+ /** Server → Client: supply missing refs. */
23
+ gapFillRes: string;
24
+ /** Server → Client: bootstrap latest ref on connect / heartbeat. */
25
+ bootstrap: string;
26
+ };
27
+ /**
28
+ * Creates typed, route-specific socket event names for the sync protocol.
29
+ * @param route - The route string (e.g. `"/sharedTree"`)
30
+ * @returns An object with all sync event names derived from the route
31
+ */
32
+ export declare const syncEvents: (route: string) => SyncEventNames;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rljson/rljson",
3
- "version": "0.0.75",
3
+ "version": "0.0.76",
4
4
  "description": "The RLJSON data format specification",
5
5
  "homepage": "https://github.com/rljson/rljson",
6
6
  "bugs": "https://github.com/rljson/rljson/issues",
@@ -20,23 +20,23 @@
20
20
  ],
21
21
  "type": "module",
22
22
  "devDependencies": {
23
- "@types/node": "^25.1.0",
24
- "@typescript-eslint/eslint-plugin": "^8.54.0",
25
- "@typescript-eslint/parser": "^8.54.0",
23
+ "@types/node": "^25.2.3",
24
+ "@typescript-eslint/eslint-plugin": "^8.55.0",
25
+ "@typescript-eslint/parser": "^8.55.0",
26
26
  "@vitest/coverage-v8": "^4.0.18",
27
27
  "cross-env": "^10.1.0",
28
28
  "eslint": "^9.39.2",
29
29
  "eslint-plugin-jsdoc": "^62.5.0",
30
30
  "eslint-plugin-tsdoc": "^0.5.0",
31
- "globals": "^17.2.0",
31
+ "globals": "^17.3.0",
32
32
  "jsdoc": "^4.0.5",
33
- "read-pkg": "^10.0.0",
33
+ "read-pkg": "^10.1.0",
34
34
  "typescript": "~5.9.3",
35
- "typescript-eslint": "^8.54.0",
35
+ "typescript-eslint": "^8.55.0",
36
36
  "vite": "^7.3.1",
37
37
  "vite-node": "^5.3.0",
38
38
  "vite-plugin-dts": "^4.5.4",
39
- "vite-tsconfig-paths": "^6.0.5",
39
+ "vite-tsconfig-paths": "^6.1.0",
40
40
  "vitest": "^4.0.18",
41
41
  "vitest-dom": "^0.1.1"
42
42
  },