@furystack/entity-sync 3.0.2 → 3.0.4
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/CHANGELOG.md +219 -203
- package/LICENSE +339 -339
- package/README.md +83 -83
- package/package.json +2 -2
- package/src/client-sync-message.ts +28 -28
- package/src/index.ts +6 -6
- package/src/server-sync-message.ts +64 -64
- package/src/sync-change-entry.ts +9 -9
- package/src/sync-state.ts +20 -20
- package/src/sync-version.ts +18 -18
package/README.md
CHANGED
|
@@ -1,83 +1,83 @@
|
|
|
1
|
-
# @furystack/entity-sync
|
|
2
|
-
|
|
3
|
-
Shared protocol types for FuryStack entity synchronization over WebSocket.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install @furystack/entity-sync
|
|
9
|
-
# or
|
|
10
|
-
yarn add @furystack/entity-sync
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
## Overview
|
|
14
|
-
|
|
15
|
-
This package defines the wire protocol used between `@furystack/entity-sync-client` and `@furystack/entity-sync-service`. It exports only TypeScript types -- there is no runtime code.
|
|
16
|
-
|
|
17
|
-
### Protocol Flow
|
|
18
|
-
|
|
19
|
-
```
|
|
20
|
-
Client Server
|
|
21
|
-
│ │
|
|
22
|
-
│──── subscribe-entity / subscribe-collection ──▶│
|
|
23
|
-
│ │
|
|
24
|
-
│◀──── subscribed (snapshot or delta) ──────────│
|
|
25
|
-
│ │
|
|
26
|
-
│◀──── entity-added / entity-updated / ─────────│
|
|
27
|
-
│ entity-removed (incremental) │
|
|
28
|
-
│ │
|
|
29
|
-
│──── unsubscribe ──────────────────────────────▶│
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Types
|
|
33
|
-
|
|
34
|
-
### `SyncVersion`
|
|
35
|
-
|
|
36
|
-
Version metadata included in all server sync messages:
|
|
37
|
-
|
|
38
|
-
```ts
|
|
39
|
-
type SyncVersion = {
|
|
40
|
-
seq: number // Monotonically increasing sequence number per model
|
|
41
|
-
timestamp: string // ISO 8601 timestamp
|
|
42
|
-
}
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### `SyncChangeEntry`
|
|
46
|
-
|
|
47
|
-
A single entry in a delta replay, representing one change to an entity:
|
|
48
|
-
|
|
49
|
-
```ts
|
|
50
|
-
type SyncChangeEntry =
|
|
51
|
-
| { type: 'added'; entity: unknown; version: SyncVersion }
|
|
52
|
-
| { type: 'updated'; id: unknown; change: Record<string, unknown>; version: SyncVersion }
|
|
53
|
-
| { type: 'removed'; id: unknown; version: SyncVersion }
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### `ClientSyncMessage`
|
|
57
|
-
|
|
58
|
-
Messages sent from client to server:
|
|
59
|
-
|
|
60
|
-
- `subscribe-entity` -- subscribe to a single entity by primary key (with optional `lastSeq` for delta sync)
|
|
61
|
-
- `subscribe-collection` -- subscribe to a filtered, ordered collection (with optional `lastSeq`)
|
|
62
|
-
- `unsubscribe` -- remove a subscription by ID
|
|
63
|
-
|
|
64
|
-
### `ServerSyncMessage`
|
|
65
|
-
|
|
66
|
-
Messages sent from server to client:
|
|
67
|
-
|
|
68
|
-
- `subscribed` -- subscription confirmation with either a full `snapshot` or a `delta` (array of `SyncChangeEntry`)
|
|
69
|
-
- `entity-added` / `entity-updated` / `entity-removed` -- incremental changes pushed to active subscriptions
|
|
70
|
-
- `subscription-error` -- error response for a subscription request
|
|
71
|
-
|
|
72
|
-
### `SyncState<T>`
|
|
73
|
-
|
|
74
|
-
Client-side discriminated union representing the current state of a subscription:
|
|
75
|
-
|
|
76
|
-
```ts
|
|
77
|
-
type SyncState<T> =
|
|
78
|
-
| { status: 'connecting' }
|
|
79
|
-
| { status: 'cached'; data: T }
|
|
80
|
-
| { status: 'suspended'; data: T }
|
|
81
|
-
| { status: 'synced'; data: T }
|
|
82
|
-
| { status: 'error'; error: string }
|
|
83
|
-
```
|
|
1
|
+
# @furystack/entity-sync
|
|
2
|
+
|
|
3
|
+
Shared protocol types for FuryStack entity synchronization over WebSocket.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @furystack/entity-sync
|
|
9
|
+
# or
|
|
10
|
+
yarn add @furystack/entity-sync
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Overview
|
|
14
|
+
|
|
15
|
+
This package defines the wire protocol used between `@furystack/entity-sync-client` and `@furystack/entity-sync-service`. It exports only TypeScript types -- there is no runtime code.
|
|
16
|
+
|
|
17
|
+
### Protocol Flow
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
Client Server
|
|
21
|
+
│ │
|
|
22
|
+
│──── subscribe-entity / subscribe-collection ──▶│
|
|
23
|
+
│ │
|
|
24
|
+
│◀──── subscribed (snapshot or delta) ──────────│
|
|
25
|
+
│ │
|
|
26
|
+
│◀──── entity-added / entity-updated / ─────────│
|
|
27
|
+
│ entity-removed (incremental) │
|
|
28
|
+
│ │
|
|
29
|
+
│──── unsubscribe ──────────────────────────────▶│
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Types
|
|
33
|
+
|
|
34
|
+
### `SyncVersion`
|
|
35
|
+
|
|
36
|
+
Version metadata included in all server sync messages:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
type SyncVersion = {
|
|
40
|
+
seq: number // Monotonically increasing sequence number per model
|
|
41
|
+
timestamp: string // ISO 8601 timestamp
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### `SyncChangeEntry`
|
|
46
|
+
|
|
47
|
+
A single entry in a delta replay, representing one change to an entity:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
type SyncChangeEntry =
|
|
51
|
+
| { type: 'added'; entity: unknown; version: SyncVersion }
|
|
52
|
+
| { type: 'updated'; id: unknown; change: Record<string, unknown>; version: SyncVersion }
|
|
53
|
+
| { type: 'removed'; id: unknown; version: SyncVersion }
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### `ClientSyncMessage`
|
|
57
|
+
|
|
58
|
+
Messages sent from client to server:
|
|
59
|
+
|
|
60
|
+
- `subscribe-entity` -- subscribe to a single entity by primary key (with optional `lastSeq` for delta sync)
|
|
61
|
+
- `subscribe-collection` -- subscribe to a filtered, ordered collection (with optional `lastSeq`)
|
|
62
|
+
- `unsubscribe` -- remove a subscription by ID
|
|
63
|
+
|
|
64
|
+
### `ServerSyncMessage`
|
|
65
|
+
|
|
66
|
+
Messages sent from server to client:
|
|
67
|
+
|
|
68
|
+
- `subscribed` -- subscription confirmation with either a full `snapshot` or a `delta` (array of `SyncChangeEntry`)
|
|
69
|
+
- `entity-added` / `entity-updated` / `entity-removed` -- incremental changes pushed to active subscriptions
|
|
70
|
+
- `subscription-error` -- error response for a subscription request
|
|
71
|
+
|
|
72
|
+
### `SyncState<T>`
|
|
73
|
+
|
|
74
|
+
Client-side discriminated union representing the current state of a subscription:
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
type SyncState<T> =
|
|
78
|
+
| { status: 'connecting' }
|
|
79
|
+
| { status: 'cached'; data: T }
|
|
80
|
+
| { status: 'suspended'; data: T }
|
|
81
|
+
| { status: 'synced'; data: T }
|
|
82
|
+
| { status: 'error'; error: string }
|
|
83
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@furystack/entity-sync",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.4",
|
|
4
4
|
"description": "Shared protocol types for FuryStack entity synchronization",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
},
|
|
38
38
|
"homepage": "https://github.com/furystack/furystack",
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@furystack/core": "^17.1.
|
|
40
|
+
"@furystack/core": "^17.1.4"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"typescript": "^7.0.2"
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import type { FilterType } from '@furystack/core'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Messages sent from client to server over the WebSocket sync protocol.
|
|
5
|
-
* The `model` field is derived from `constructor.name` on both sides.
|
|
6
|
-
*/
|
|
7
|
-
export type ClientSyncMessage =
|
|
8
|
-
| {
|
|
9
|
-
type: 'subscribe-entity'
|
|
10
|
-
requestId: string
|
|
11
|
-
model: string
|
|
12
|
-
key: unknown
|
|
13
|
-
lastSeq?: string
|
|
14
|
-
}
|
|
15
|
-
| {
|
|
16
|
-
type: 'subscribe-collection'
|
|
17
|
-
requestId: string
|
|
18
|
-
model: string
|
|
19
|
-
filter?: FilterType<unknown>
|
|
20
|
-
top?: number
|
|
21
|
-
skip?: number
|
|
22
|
-
order?: Record<string, 'ASC' | 'DESC'>
|
|
23
|
-
lastSeq?: string
|
|
24
|
-
}
|
|
25
|
-
| {
|
|
26
|
-
type: 'unsubscribe'
|
|
27
|
-
subscriptionId: string
|
|
28
|
-
}
|
|
1
|
+
import type { FilterType } from '@furystack/core'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Messages sent from client to server over the WebSocket sync protocol.
|
|
5
|
+
* The `model` field is derived from `constructor.name` on both sides.
|
|
6
|
+
*/
|
|
7
|
+
export type ClientSyncMessage =
|
|
8
|
+
| {
|
|
9
|
+
type: 'subscribe-entity'
|
|
10
|
+
requestId: string
|
|
11
|
+
model: string
|
|
12
|
+
key: unknown
|
|
13
|
+
lastSeq?: string
|
|
14
|
+
}
|
|
15
|
+
| {
|
|
16
|
+
type: 'subscribe-collection'
|
|
17
|
+
requestId: string
|
|
18
|
+
model: string
|
|
19
|
+
filter?: FilterType<unknown>
|
|
20
|
+
top?: number
|
|
21
|
+
skip?: number
|
|
22
|
+
order?: Record<string, 'ASC' | 'DESC'>
|
|
23
|
+
lastSeq?: string
|
|
24
|
+
}
|
|
25
|
+
| {
|
|
26
|
+
type: 'unsubscribe'
|
|
27
|
+
subscriptionId: string
|
|
28
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export type * from './sync-version.js'
|
|
2
|
-
export type * from './sync-change-entry.js'
|
|
3
|
-
export type * from './client-sync-message.js'
|
|
4
|
-
export type * from './server-sync-message.js'
|
|
5
|
-
export type * from './sync-state.js'
|
|
6
|
-
export type { FilterType } from '@furystack/core'
|
|
1
|
+
export type * from './sync-version.js'
|
|
2
|
+
export type * from './sync-change-entry.js'
|
|
3
|
+
export type * from './client-sync-message.js'
|
|
4
|
+
export type * from './server-sync-message.js'
|
|
5
|
+
export type * from './sync-state.js'
|
|
6
|
+
export type { FilterType } from '@furystack/core'
|
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
import type { SyncChangeEntry } from './sync-change-entry.js'
|
|
2
|
-
import type { SyncVersion } from './sync-version.js'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Messages sent from server to client over the WebSocket sync protocol
|
|
6
|
-
*/
|
|
7
|
-
export type ServerSyncMessage =
|
|
8
|
-
| {
|
|
9
|
-
type: 'subscribed'
|
|
10
|
-
requestId: string
|
|
11
|
-
subscriptionId: string
|
|
12
|
-
model: string
|
|
13
|
-
/** The primary key field name (included for collection subscriptions) */
|
|
14
|
-
primaryKey?: string
|
|
15
|
-
mode: 'snapshot'
|
|
16
|
-
data: unknown
|
|
17
|
-
/** Total count of matching entities (ignoring top/skip). Included for collection subscriptions. */
|
|
18
|
-
totalCount?: number
|
|
19
|
-
version: SyncVersion
|
|
20
|
-
}
|
|
21
|
-
| {
|
|
22
|
-
type: 'subscribed'
|
|
23
|
-
requestId: string
|
|
24
|
-
subscriptionId: string
|
|
25
|
-
model: string
|
|
26
|
-
/** The primary key field name (included for collection subscriptions) */
|
|
27
|
-
primaryKey?: string
|
|
28
|
-
mode: 'delta'
|
|
29
|
-
changes: SyncChangeEntry[]
|
|
30
|
-
/** Total count of matching entities (ignoring top/skip). Included for collection subscriptions. */
|
|
31
|
-
totalCount?: number
|
|
32
|
-
version: SyncVersion
|
|
33
|
-
}
|
|
34
|
-
| {
|
|
35
|
-
type: 'entity-added'
|
|
36
|
-
subscriptionId: string
|
|
37
|
-
entity: unknown
|
|
38
|
-
version: SyncVersion
|
|
39
|
-
}
|
|
40
|
-
| {
|
|
41
|
-
type: 'entity-updated'
|
|
42
|
-
subscriptionId: string
|
|
43
|
-
id: unknown
|
|
44
|
-
change: Record<string, unknown>
|
|
45
|
-
version: SyncVersion
|
|
46
|
-
}
|
|
47
|
-
| {
|
|
48
|
-
type: 'entity-removed'
|
|
49
|
-
subscriptionId: string
|
|
50
|
-
id: unknown
|
|
51
|
-
version: SyncVersion
|
|
52
|
-
}
|
|
53
|
-
| {
|
|
54
|
-
type: 'collection-snapshot'
|
|
55
|
-
subscriptionId: string
|
|
56
|
-
data: unknown[]
|
|
57
|
-
totalCount: number
|
|
58
|
-
version: SyncVersion
|
|
59
|
-
}
|
|
60
|
-
| {
|
|
61
|
-
type: 'subscription-error'
|
|
62
|
-
requestId: string
|
|
63
|
-
error: string
|
|
64
|
-
}
|
|
1
|
+
import type { SyncChangeEntry } from './sync-change-entry.js'
|
|
2
|
+
import type { SyncVersion } from './sync-version.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Messages sent from server to client over the WebSocket sync protocol
|
|
6
|
+
*/
|
|
7
|
+
export type ServerSyncMessage =
|
|
8
|
+
| {
|
|
9
|
+
type: 'subscribed'
|
|
10
|
+
requestId: string
|
|
11
|
+
subscriptionId: string
|
|
12
|
+
model: string
|
|
13
|
+
/** The primary key field name (included for collection subscriptions) */
|
|
14
|
+
primaryKey?: string
|
|
15
|
+
mode: 'snapshot'
|
|
16
|
+
data: unknown
|
|
17
|
+
/** Total count of matching entities (ignoring top/skip). Included for collection subscriptions. */
|
|
18
|
+
totalCount?: number
|
|
19
|
+
version: SyncVersion
|
|
20
|
+
}
|
|
21
|
+
| {
|
|
22
|
+
type: 'subscribed'
|
|
23
|
+
requestId: string
|
|
24
|
+
subscriptionId: string
|
|
25
|
+
model: string
|
|
26
|
+
/** The primary key field name (included for collection subscriptions) */
|
|
27
|
+
primaryKey?: string
|
|
28
|
+
mode: 'delta'
|
|
29
|
+
changes: SyncChangeEntry[]
|
|
30
|
+
/** Total count of matching entities (ignoring top/skip). Included for collection subscriptions. */
|
|
31
|
+
totalCount?: number
|
|
32
|
+
version: SyncVersion
|
|
33
|
+
}
|
|
34
|
+
| {
|
|
35
|
+
type: 'entity-added'
|
|
36
|
+
subscriptionId: string
|
|
37
|
+
entity: unknown
|
|
38
|
+
version: SyncVersion
|
|
39
|
+
}
|
|
40
|
+
| {
|
|
41
|
+
type: 'entity-updated'
|
|
42
|
+
subscriptionId: string
|
|
43
|
+
id: unknown
|
|
44
|
+
change: Record<string, unknown>
|
|
45
|
+
version: SyncVersion
|
|
46
|
+
}
|
|
47
|
+
| {
|
|
48
|
+
type: 'entity-removed'
|
|
49
|
+
subscriptionId: string
|
|
50
|
+
id: unknown
|
|
51
|
+
version: SyncVersion
|
|
52
|
+
}
|
|
53
|
+
| {
|
|
54
|
+
type: 'collection-snapshot'
|
|
55
|
+
subscriptionId: string
|
|
56
|
+
data: unknown[]
|
|
57
|
+
totalCount: number
|
|
58
|
+
version: SyncVersion
|
|
59
|
+
}
|
|
60
|
+
| {
|
|
61
|
+
type: 'subscription-error'
|
|
62
|
+
requestId: string
|
|
63
|
+
error: string
|
|
64
|
+
}
|
package/src/sync-change-entry.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { SyncVersion } from './sync-version.js'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* A single entry in a delta replay, representing one change to an entity
|
|
5
|
-
*/
|
|
6
|
-
export type SyncChangeEntry =
|
|
7
|
-
| { type: 'added'; entity: unknown; version: SyncVersion }
|
|
8
|
-
| { type: 'updated'; id: unknown; change: Record<string, unknown>; version: SyncVersion }
|
|
9
|
-
| { type: 'removed'; id: unknown; version: SyncVersion }
|
|
1
|
+
import type { SyncVersion } from './sync-version.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A single entry in a delta replay, representing one change to an entity
|
|
5
|
+
*/
|
|
6
|
+
export type SyncChangeEntry =
|
|
7
|
+
| { type: 'added'; entity: unknown; version: SyncVersion }
|
|
8
|
+
| { type: 'updated'; id: unknown; change: Record<string, unknown>; version: SyncVersion }
|
|
9
|
+
| { type: 'removed'; id: unknown; version: SyncVersion }
|
package/src/sync-state.ts
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Discriminated union over the lifecycle of a subscribed entity or
|
|
3
|
-
* collection on the client:
|
|
4
|
-
*
|
|
5
|
-
* - `connecting` — handshake in progress, no `data` yet (or first load).
|
|
6
|
-
* - `cached` — local cache hit; rendering immediately while a `delta` sync
|
|
7
|
-
* confirms freshness.
|
|
8
|
-
* - `suspended` — connection dropped; the last-known `data` is still
|
|
9
|
-
* served while reconnect attempts run in the background.
|
|
10
|
-
* - `synced` — server confirmed our seq matches; `data` is authoritative.
|
|
11
|
-
* - `error` — terminal: subscription rejected; `error` carries the reason.
|
|
12
|
-
*
|
|
13
|
-
* Discriminate on `status` to narrow.
|
|
14
|
-
*/
|
|
15
|
-
export type SyncState<T> =
|
|
16
|
-
| { status: 'connecting' }
|
|
17
|
-
| { status: 'cached'; data: T }
|
|
18
|
-
| { status: 'suspended'; data: T }
|
|
19
|
-
| { status: 'synced'; data: T }
|
|
20
|
-
| { status: 'error'; error: string }
|
|
1
|
+
/**
|
|
2
|
+
* Discriminated union over the lifecycle of a subscribed entity or
|
|
3
|
+
* collection on the client:
|
|
4
|
+
*
|
|
5
|
+
* - `connecting` — handshake in progress, no `data` yet (or first load).
|
|
6
|
+
* - `cached` — local cache hit; rendering immediately while a `delta` sync
|
|
7
|
+
* confirms freshness.
|
|
8
|
+
* - `suspended` — connection dropped; the last-known `data` is still
|
|
9
|
+
* served while reconnect attempts run in the background.
|
|
10
|
+
* - `synced` — server confirmed our seq matches; `data` is authoritative.
|
|
11
|
+
* - `error` — terminal: subscription rejected; `error` carries the reason.
|
|
12
|
+
*
|
|
13
|
+
* Discriminate on `status` to narrow.
|
|
14
|
+
*/
|
|
15
|
+
export type SyncState<T> =
|
|
16
|
+
| { status: 'connecting' }
|
|
17
|
+
| { status: 'cached'; data: T }
|
|
18
|
+
| { status: 'suspended'; data: T }
|
|
19
|
+
| { status: 'synced'; data: T }
|
|
20
|
+
| { status: 'error'; error: string }
|
package/src/sync-version.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Version metadata included in all server sync messages.
|
|
3
|
-
*
|
|
4
|
-
* `seq` is an **opaque, ordered token** assigned by the server's underlying
|
|
5
|
-
* cross-node bus adapter — the broadcaster never invents the value, it only
|
|
6
|
-
* forwards what the bus stamps on each message. Clients **must not** compare
|
|
7
|
-
* seqs lexicographically or numerically: the only safe operations are
|
|
8
|
-
* round-tripping the value back to the server (via `lastSeq` on
|
|
9
|
-
* `ClientSyncMessage`) and equality. The string encoding lets adapters use
|
|
10
|
-
* native id formats — e.g. integer counters in-process, `<ms>-<n>` Redis
|
|
11
|
-
* Stream ids — without a translation layer.
|
|
12
|
-
*/
|
|
13
|
-
export type SyncVersion = {
|
|
14
|
-
/** Adapter-assigned, opaque, ordered per-topic identifier. */
|
|
15
|
-
seq: string
|
|
16
|
-
/** ISO 8601 timestamp, used for time-based changelog pruning */
|
|
17
|
-
timestamp: string
|
|
18
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Version metadata included in all server sync messages.
|
|
3
|
+
*
|
|
4
|
+
* `seq` is an **opaque, ordered token** assigned by the server's underlying
|
|
5
|
+
* cross-node bus adapter — the broadcaster never invents the value, it only
|
|
6
|
+
* forwards what the bus stamps on each message. Clients **must not** compare
|
|
7
|
+
* seqs lexicographically or numerically: the only safe operations are
|
|
8
|
+
* round-tripping the value back to the server (via `lastSeq` on
|
|
9
|
+
* `ClientSyncMessage`) and equality. The string encoding lets adapters use
|
|
10
|
+
* native id formats — e.g. integer counters in-process, `<ms>-<n>` Redis
|
|
11
|
+
* Stream ids — without a translation layer.
|
|
12
|
+
*/
|
|
13
|
+
export type SyncVersion = {
|
|
14
|
+
/** Adapter-assigned, opaque, ordered per-topic identifier. */
|
|
15
|
+
seq: string
|
|
16
|
+
/** ISO 8601 timestamp, used for time-based changelog pruning */
|
|
17
|
+
timestamp: string
|
|
18
|
+
}
|