@syncular/core 0.59.0 → 0.60.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.
- package/dist/canonical-json.d.ts +20 -9
- package/dist/canonical-json.js +108 -6
- package/dist/constants.d.ts +5 -5
- package/dist/constants.js +5 -5
- package/dist/frames.d.ts +6 -3
- package/dist/frames.js +10 -4
- package/dist/message.d.ts +54 -13
- package/dist/message.js +279 -127
- package/dist/render.js +34 -11
- package/package.json +1 -1
- package/src/canonical-json.ts +135 -6
- package/src/constants.ts +5 -5
- package/src/frames.ts +10 -4
- package/src/message.ts +389 -155
- package/src/render.ts +34 -11
package/dist/canonical-json.d.ts
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* by code-unit, scope value lists sorted and deduplicated.
|
|
5
|
-
*
|
|
6
|
-
* Used for the scope digest (§3.5) and the `X-Syncular-Scopes` header
|
|
7
|
-
* (§5.5). Hashing itself is the host's job; this module only produces the
|
|
8
|
-
* canonical text.
|
|
9
|
-
*/
|
|
1
|
+
import type { FencedRecord } from './message.js';
|
|
2
|
+
/** A unit's scope map: one value per requested variable (§4.1). */
|
|
3
|
+
export type UnitScopes = Readonly<Record<string, string>>;
|
|
10
4
|
export declare function canonicalScopeJson(scopes: Readonly<Record<string, readonly string[]>>): string;
|
|
5
|
+
/** §4.1: the canonical JSON of a unit's scope map. */
|
|
6
|
+
export declare function canonicalUnitJson(scopes: UnitScopes): string;
|
|
7
|
+
/** §4.1: lowercase hex of the first 16 bytes of SHA-256 over the canonical
|
|
8
|
+
* JSON of the unit's scope map. */
|
|
9
|
+
export declare function unitId(scopes: UnitScopes): string;
|
|
10
|
+
/** §4.1: SHA-256 over the canonical JSON array of the units' scope maps in
|
|
11
|
+
* registration order, as 32 raw bytes. */
|
|
12
|
+
export declare function registrationDigest(units: readonly UnitScopes[]): Uint8Array;
|
|
13
|
+
/** One unit of the effective list as the echo digest sees it (§4.4). */
|
|
14
|
+
export interface UnitEcho {
|
|
15
|
+
id: string;
|
|
16
|
+
status: 'active' | 'revoked';
|
|
17
|
+
fenced: readonly FencedRecord[];
|
|
18
|
+
}
|
|
19
|
+
/** §4.4: SHA-256 over the canonical JSON array, in registration order, of
|
|
20
|
+
* `{"fenced":[…],"id":…,"status":…}` per unit, as 32 raw bytes. */
|
|
21
|
+
export declare function echoDigest(units: readonly UnitEcho[]): Uint8Array;
|
package/dist/canonical-json.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Canonical JSON for digests (SPEC.md §11.2)
|
|
3
|
-
* implementations: UTF-8, no insignificant whitespace,
|
|
4
|
-
* by code-unit, scope value lists sorted and
|
|
2
|
+
* Canonical JSON for digests (SPEC.md §11.2) and the digests over it —
|
|
3
|
+
* contractual across implementations: UTF-8, no insignificant whitespace,
|
|
4
|
+
* object keys sorted by code-unit, scope value lists sorted and
|
|
5
|
+
* deduplicated, every other array in its stated order.
|
|
5
6
|
*
|
|
6
|
-
* Used for the
|
|
7
|
-
* (§
|
|
8
|
-
* canonical text.
|
|
7
|
+
* Used for the unit id and registration digest (§4.1), the echo digest
|
|
8
|
+
* (§4.4), the scope digest (§3.5) and the `X-Syncular-Scopes` header (§5.5).
|
|
9
9
|
*/
|
|
10
|
+
import { utf8Encode } from './bytes.js';
|
|
10
11
|
export function canonicalScopeJson(scopes) {
|
|
11
12
|
const keys = Object.keys(scopes).sort();
|
|
12
13
|
const parts = keys.map((key) => {
|
|
@@ -16,3 +17,104 @@ export function canonicalScopeJson(scopes) {
|
|
|
16
17
|
});
|
|
17
18
|
return `{${parts.join(',')}}`;
|
|
18
19
|
}
|
|
20
|
+
/** §4.1: the canonical JSON of a unit's scope map. */
|
|
21
|
+
export function canonicalUnitJson(scopes) {
|
|
22
|
+
const keys = Object.keys(scopes).sort();
|
|
23
|
+
const parts = keys.map((key) => `${JSON.stringify(key)}:${JSON.stringify(scopes[key])}`);
|
|
24
|
+
return `{${parts.join(',')}}`;
|
|
25
|
+
}
|
|
26
|
+
/** §4.1: lowercase hex of the first 16 bytes of SHA-256 over the canonical
|
|
27
|
+
* JSON of the unit's scope map. */
|
|
28
|
+
export function unitId(scopes) {
|
|
29
|
+
let hex = '';
|
|
30
|
+
for (const byte of sha256(utf8Encode(canonicalUnitJson(scopes))).subarray(0, 16)) {
|
|
31
|
+
hex += byte.toString(16).padStart(2, '0');
|
|
32
|
+
}
|
|
33
|
+
return hex;
|
|
34
|
+
}
|
|
35
|
+
/** §4.1: SHA-256 over the canonical JSON array of the units' scope maps in
|
|
36
|
+
* registration order, as 32 raw bytes. */
|
|
37
|
+
export function registrationDigest(units) {
|
|
38
|
+
return sha256(utf8Encode(`[${units.map(canonicalUnitJson).join(',')}]`));
|
|
39
|
+
}
|
|
40
|
+
/** §4.4: SHA-256 over the canonical JSON array, in registration order, of
|
|
41
|
+
* `{"fenced":[…],"id":…,"status":…}` per unit, as 32 raw bytes. */
|
|
42
|
+
export function echoDigest(units) {
|
|
43
|
+
const entries = units.map((unit) => {
|
|
44
|
+
const fenced = unit.fenced.map((record) => `{"scopes":${canonicalScopeJson(record.scopes)},"status":${JSON.stringify(record.status)},"table":${JSON.stringify(record.table)}}`);
|
|
45
|
+
return `{"fenced":[${fenced.join(',')}],"id":${JSON.stringify(unit.id)},"status":${JSON.stringify(unit.status)}}`;
|
|
46
|
+
});
|
|
47
|
+
return sha256(utf8Encode(`[${entries.join(',')}]`));
|
|
48
|
+
}
|
|
49
|
+
// FIPS 180-4 SHA-256. Synchronous so the unit id is a plain function of the
|
|
50
|
+
// scope map on every runtime (WebCrypto digests are async only).
|
|
51
|
+
const K = new Uint32Array([
|
|
52
|
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
|
|
53
|
+
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
|
54
|
+
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
|
55
|
+
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
56
|
+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
|
57
|
+
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
|
58
|
+
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
|
|
59
|
+
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
60
|
+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
|
|
61
|
+
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
|
62
|
+
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
|
|
63
|
+
]);
|
|
64
|
+
function sha256(data) {
|
|
65
|
+
const padded = new Uint8Array(((data.length + 72) >>> 6) << 6);
|
|
66
|
+
padded.set(data);
|
|
67
|
+
padded[data.length] = 0x80;
|
|
68
|
+
const view = new DataView(padded.buffer);
|
|
69
|
+
view.setUint32(padded.length - 8, Math.floor(data.length / 0x20000000));
|
|
70
|
+
view.setUint32(padded.length - 4, (data.length * 8) >>> 0);
|
|
71
|
+
const h = [
|
|
72
|
+
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c,
|
|
73
|
+
0x1f83d9ab, 0x5be0cd19,
|
|
74
|
+
];
|
|
75
|
+
const w = new Uint32Array(64);
|
|
76
|
+
const rotr = (x, n) => (x >>> n) | (x << (32 - n));
|
|
77
|
+
for (let offset = 0; offset < padded.length; offset += 64) {
|
|
78
|
+
for (let i = 0; i < 16; i++)
|
|
79
|
+
w[i] = view.getUint32(offset + i * 4);
|
|
80
|
+
for (let i = 16; i < 64; i++) {
|
|
81
|
+
const a = w[i - 15];
|
|
82
|
+
const b = w[i - 2];
|
|
83
|
+
w[i] =
|
|
84
|
+
(rotr(b, 17) ^ rotr(b, 19) ^ (b >>> 10)) +
|
|
85
|
+
w[i - 7] +
|
|
86
|
+
(rotr(a, 7) ^ rotr(a, 18) ^ (a >>> 3)) +
|
|
87
|
+
w[i - 16];
|
|
88
|
+
}
|
|
89
|
+
let [a, b, c, d, e, f, g, hh] = h;
|
|
90
|
+
for (let i = 0; i < 64; i++) {
|
|
91
|
+
const t1 = hh +
|
|
92
|
+
(rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)) +
|
|
93
|
+
((e & f) ^ (~e & g)) +
|
|
94
|
+
K[i] +
|
|
95
|
+
w[i];
|
|
96
|
+
const t2 = (rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)) +
|
|
97
|
+
((a & b) ^ (a & c) ^ (b & c));
|
|
98
|
+
hh = g;
|
|
99
|
+
g = f;
|
|
100
|
+
f = e;
|
|
101
|
+
e = (d + t1) | 0;
|
|
102
|
+
d = c;
|
|
103
|
+
c = b;
|
|
104
|
+
b = a;
|
|
105
|
+
a = (t1 + t2) | 0;
|
|
106
|
+
}
|
|
107
|
+
h[0] = (h[0] + a) | 0;
|
|
108
|
+
h[1] = (h[1] + b) | 0;
|
|
109
|
+
h[2] = (h[2] + c) | 0;
|
|
110
|
+
h[3] = (h[3] + d) | 0;
|
|
111
|
+
h[4] = (h[4] + e) | 0;
|
|
112
|
+
h[5] = (h[5] + f) | 0;
|
|
113
|
+
h[6] = (h[6] + g) | 0;
|
|
114
|
+
h[7] = (h[7] + hh) | 0;
|
|
115
|
+
}
|
|
116
|
+
const out = new Uint8Array(32);
|
|
117
|
+
const outView = new DataView(out.buffer);
|
|
118
|
+
h.forEach((word, i) => outView.setUint32(i * 4, word));
|
|
119
|
+
return out;
|
|
120
|
+
}
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/** Protocol constants (SPEC.md §1.2, §9 are normative). */
|
|
2
2
|
/** Latest SSP2 envelope wire version emitted by current clients. */
|
|
3
|
-
export declare const PROTOCOL_WIRE_VERSION =
|
|
4
|
-
/** Oldest SSP2 envelope wire version accepted. Wire version
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
export declare const MINIMUM_PROTOCOL_WIRE_VERSION =
|
|
3
|
+
export declare const PROTOCOL_WIRE_VERSION = 4;
|
|
4
|
+
/** Oldest SSP2 envelope wire version accepted. Wire version 4 replaced
|
|
5
|
+
* per-table subscriptions with units and the replica cursor (§4); earlier
|
|
6
|
+
* versions are rejected as unknown (§9). */
|
|
7
|
+
export declare const MINIMUM_PROTOCOL_WIRE_VERSION = 4;
|
|
8
8
|
/** Wire versions implemented by the reference codec, oldest first. */
|
|
9
9
|
export declare const SUPPORTED_PROTOCOL_WIRE_VERSIONS: readonly number[];
|
|
10
10
|
/** Whether the reference codec implements this exact wire version. */
|
package/dist/constants.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/** Protocol constants (SPEC.md §1.2, §9 are normative). */
|
|
2
2
|
/** Latest SSP2 envelope wire version emitted by current clients. */
|
|
3
|
-
export const PROTOCOL_WIRE_VERSION =
|
|
4
|
-
/** Oldest SSP2 envelope wire version accepted. Wire version
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
export const MINIMUM_PROTOCOL_WIRE_VERSION =
|
|
3
|
+
export const PROTOCOL_WIRE_VERSION = 4;
|
|
4
|
+
/** Oldest SSP2 envelope wire version accepted. Wire version 4 replaced
|
|
5
|
+
* per-table subscriptions with units and the replica cursor (§4); earlier
|
|
6
|
+
* versions are rejected as unknown (§9). */
|
|
7
|
+
export const MINIMUM_PROTOCOL_WIRE_VERSION = 4;
|
|
8
8
|
/** Wire versions implemented by the reference codec, oldest first. */
|
|
9
9
|
export const SUPPORTED_PROTOCOL_WIRE_VERSIONS = Object.freeze(Array.from({
|
|
10
10
|
length: PROTOCOL_WIRE_VERSION - MINIMUM_PROTOCOL_WIRE_VERSION + 1,
|
package/dist/frames.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
/** Frame type registry for wire
|
|
1
|
+
/** Frame type registry for wire version 4 (SPEC.md §1.2). */
|
|
2
2
|
export declare const FrameType: {
|
|
3
3
|
readonly END: 0;
|
|
4
4
|
readonly REQ_HEADER: 1;
|
|
5
5
|
readonly PUSH_COMMIT: 2;
|
|
6
6
|
readonly PULL_HEADER: 3;
|
|
7
|
-
readonly
|
|
7
|
+
readonly UNIT: 4;
|
|
8
8
|
readonly ROUND_FAILURE: 5;
|
|
9
|
+
readonly PROGRESS: 6;
|
|
9
10
|
readonly RESP_HEADER: 16;
|
|
10
11
|
readonly PUSH_RESULT: 17;
|
|
11
12
|
readonly SUB_START: 18;
|
|
@@ -15,6 +16,8 @@ export declare const FrameType: {
|
|
|
15
16
|
readonly SUB_END: 22;
|
|
16
17
|
readonly LEASE: 25;
|
|
17
18
|
readonly PUSH_RESULT_DETAILS: 27;
|
|
19
|
+
readonly LIVE_START: 28;
|
|
20
|
+
readonly LIVE_END: 29;
|
|
18
21
|
readonly ERROR: 31;
|
|
19
22
|
};
|
|
20
23
|
export type FrameTypeName = keyof typeof FrameType;
|
|
@@ -22,5 +25,5 @@ export type FrameTypeName = keyof typeof FrameType;
|
|
|
22
25
|
export declare const REQUEST_FRAME_TYPES: ReadonlySet<number>;
|
|
23
26
|
/** Known response frame types (excluding END). */
|
|
24
27
|
export declare const RESPONSE_FRAME_TYPES: ReadonlySet<number>;
|
|
25
|
-
/** Every frame type with a defined layout in wire
|
|
28
|
+
/** Every frame type with a defined layout in wire version 4. */
|
|
26
29
|
export declare const KNOWN_FRAME_TYPES: ReadonlySet<number>;
|
package/dist/frames.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
/** Frame type registry for wire
|
|
1
|
+
/** Frame type registry for wire version 4 (SPEC.md §1.2). */
|
|
2
2
|
export const FrameType = {
|
|
3
3
|
END: 0x00,
|
|
4
4
|
REQ_HEADER: 0x01,
|
|
5
5
|
PUSH_COMMIT: 0x02,
|
|
6
6
|
PULL_HEADER: 0x03,
|
|
7
|
-
|
|
7
|
+
UNIT: 0x04,
|
|
8
8
|
ROUND_FAILURE: 0x05,
|
|
9
|
+
PROGRESS: 0x06,
|
|
9
10
|
RESP_HEADER: 0x10,
|
|
10
11
|
PUSH_RESULT: 0x11,
|
|
11
12
|
SUB_START: 0x12,
|
|
@@ -15,6 +16,8 @@ export const FrameType = {
|
|
|
15
16
|
SUB_END: 0x16,
|
|
16
17
|
LEASE: 0x19,
|
|
17
18
|
PUSH_RESULT_DETAILS: 0x1b,
|
|
19
|
+
LIVE_START: 0x1c,
|
|
20
|
+
LIVE_END: 0x1d,
|
|
18
21
|
ERROR: 0x1f,
|
|
19
22
|
};
|
|
20
23
|
/** Known request frame types (excluding END). */
|
|
@@ -22,8 +25,9 @@ export const REQUEST_FRAME_TYPES = new Set([
|
|
|
22
25
|
FrameType.REQ_HEADER,
|
|
23
26
|
FrameType.PUSH_COMMIT,
|
|
24
27
|
FrameType.PULL_HEADER,
|
|
25
|
-
FrameType.
|
|
28
|
+
FrameType.UNIT,
|
|
26
29
|
FrameType.ROUND_FAILURE,
|
|
30
|
+
FrameType.PROGRESS,
|
|
27
31
|
]);
|
|
28
32
|
/** Known response frame types (excluding END). */
|
|
29
33
|
export const RESPONSE_FRAME_TYPES = new Set([
|
|
@@ -36,9 +40,11 @@ export const RESPONSE_FRAME_TYPES = new Set([
|
|
|
36
40
|
FrameType.SUB_END,
|
|
37
41
|
FrameType.LEASE,
|
|
38
42
|
FrameType.PUSH_RESULT_DETAILS,
|
|
43
|
+
FrameType.LIVE_START,
|
|
44
|
+
FrameType.LIVE_END,
|
|
39
45
|
FrameType.ERROR,
|
|
40
46
|
]);
|
|
41
|
-
/** Every frame type with a defined layout in wire
|
|
47
|
+
/** Every frame type with a defined layout in wire version 4. */
|
|
42
48
|
export const KNOWN_FRAME_TYPES = new Set([
|
|
43
49
|
FrameType.END,
|
|
44
50
|
...REQUEST_FRAME_TYPES,
|
package/dist/message.d.ts
CHANGED
|
@@ -6,6 +6,9 @@ export interface ReqHeaderFrame {
|
|
|
6
6
|
schemaVersion: number;
|
|
7
7
|
/** Partition log identity; absent requests epoch acquisition. */
|
|
8
8
|
logEpoch?: string;
|
|
9
|
+
/** Identity of the sender's outbox sequence (§6.3.2, §7.1); absent for a
|
|
10
|
+
* sender without an outbox. Non-empty, at most 64 bytes. */
|
|
11
|
+
outboxId?: string;
|
|
9
12
|
}
|
|
10
13
|
export interface PushOperation {
|
|
11
14
|
table: string;
|
|
@@ -19,6 +22,8 @@ export interface PushOperation {
|
|
|
19
22
|
export interface PushCommitFrame {
|
|
20
23
|
type: 'PUSH_COMMIT';
|
|
21
24
|
clientCommitId: string;
|
|
25
|
+
/** Outbox sequence number (§6.3.2, §7.1); `0` without an outbox. */
|
|
26
|
+
clientSeq: number;
|
|
22
27
|
operations: PushOperation[];
|
|
23
28
|
}
|
|
24
29
|
export interface PullHeaderFrame {
|
|
@@ -28,14 +33,24 @@ export interface PullHeaderFrame {
|
|
|
28
33
|
maxSnapshotPages: number;
|
|
29
34
|
/** Bitmask (§4.2): bit 0 inline rows, 1 external rows, 2 sqlite, 3 signed URLs. */
|
|
30
35
|
accept: number;
|
|
36
|
+
/** The replica cursor (§4.5); `-1` when no unit is live. */
|
|
37
|
+
cursor: number;
|
|
38
|
+
/** §4.1 registration digest: exactly 32 bytes. */
|
|
39
|
+
registrationDigest: Uint8Array;
|
|
40
|
+
/** The last processed `LIVE_END.echoDigest`: empty or 32 bytes (§4.2). */
|
|
41
|
+
echoDigest: Uint8Array;
|
|
42
|
+
}
|
|
43
|
+
/** §4.3: one unit of a traveling registration list. */
|
|
44
|
+
export interface UnitFrame {
|
|
45
|
+
type: 'UNIT';
|
|
46
|
+
scopes: Record<string, string>;
|
|
31
47
|
}
|
|
32
|
-
|
|
33
|
-
|
|
48
|
+
/** §4.3: the progress of one catching-up unit. */
|
|
49
|
+
export interface ProgressFrame {
|
|
50
|
+
type: 'PROGRESS';
|
|
51
|
+
/** The unit id (§4.1): 32 lowercase hex characters. */
|
|
34
52
|
id: string;
|
|
35
|
-
|
|
36
|
-
scopes: ScopeMap;
|
|
37
|
-
/** Host-opaque JSON document, preserved verbatim. */
|
|
38
|
-
params?: string;
|
|
53
|
+
/** `-1`, the §4.7 pin while a resume token is held, or the unit cursor. */
|
|
39
54
|
cursor: number;
|
|
40
55
|
/** Opaque resume token JSON, round-tripped byte-for-byte (§4.7). */
|
|
41
56
|
bootstrapState?: string;
|
|
@@ -53,7 +68,7 @@ export interface RoundFailureFrame {
|
|
|
53
68
|
type: 'ROUND_FAILURE';
|
|
54
69
|
code: string;
|
|
55
70
|
}
|
|
56
|
-
export type RequestFrame = ReqHeaderFrame | RoundFailureFrame | PushCommitFrame | PullHeaderFrame |
|
|
71
|
+
export type RequestFrame = ReqHeaderFrame | RoundFailureFrame | PushCommitFrame | PullHeaderFrame | UnitFrame | ProgressFrame | UnknownFrame;
|
|
57
72
|
export interface RespHeaderFrame {
|
|
58
73
|
type: 'RESP_HEADER';
|
|
59
74
|
requiredSchemaVersion?: number;
|
|
@@ -118,20 +133,43 @@ export interface PushResultDetailsFrame {
|
|
|
118
133
|
details: RejectionDetails;
|
|
119
134
|
}>;
|
|
120
135
|
}
|
|
136
|
+
/** §4.4: one (unit, table) pair the wildcard fence touched. */
|
|
137
|
+
export interface FencedRecord {
|
|
138
|
+
table: string;
|
|
139
|
+
status: 'active' | 'revoked';
|
|
140
|
+
/** Effective lists of the variables the fence added; empty when revoked. */
|
|
141
|
+
scopes: ScopeMap;
|
|
142
|
+
}
|
|
121
143
|
export interface SubStartFrame {
|
|
122
144
|
type: 'SUB_START';
|
|
145
|
+
/** The unit id (§4.1): 32 lowercase hex characters. */
|
|
123
146
|
id: string;
|
|
124
147
|
status: 'active' | 'revoked' | 'reset';
|
|
125
148
|
reasonCode: string;
|
|
126
|
-
effectiveScopes: ScopeMap;
|
|
127
149
|
bootstrap: boolean;
|
|
150
|
+
/** The unit's echo, in ascending table order (§4.4). */
|
|
151
|
+
fenced: FencedRecord[];
|
|
152
|
+
}
|
|
153
|
+
export interface LiveStartFrame {
|
|
154
|
+
type: 'LIVE_START';
|
|
155
|
+
status: 'active' | 'reset' | 'unregistered';
|
|
156
|
+
reasonCode: string;
|
|
157
|
+
}
|
|
158
|
+
export interface LiveEndFrame {
|
|
159
|
+
type: 'LIVE_END';
|
|
160
|
+
/** Highest commitSeq the live section is complete through; `-1` for
|
|
161
|
+
* `reset` and `unregistered` (§4.4). */
|
|
162
|
+
throughSeq: number;
|
|
163
|
+
/** Echo digest of the request: empty or 32 bytes (§4.4). */
|
|
164
|
+
echoDigest: Uint8Array;
|
|
128
165
|
}
|
|
129
166
|
export interface CommitChange {
|
|
130
167
|
tableIndex: number;
|
|
131
168
|
rowId: string;
|
|
132
169
|
op: 'upsert' | 'delete';
|
|
133
|
-
/**
|
|
134
|
-
|
|
170
|
+
/** The row's `server_version` after the write, ≥ 1; a delete's is the
|
|
171
|
+
* version its tombstone records (§2.2, §4.5). */
|
|
172
|
+
rowVersion: number;
|
|
135
173
|
scopes: Record<string, string>;
|
|
136
174
|
/** Generated-row-codec bytes; present iff `op` is `upsert` (§4.5). */
|
|
137
175
|
row?: Uint8Array;
|
|
@@ -167,7 +205,7 @@ export interface SegmentInlineFrame {
|
|
|
167
205
|
export interface SubEndFrame {
|
|
168
206
|
type: 'SUB_END';
|
|
169
207
|
nextCursor: number;
|
|
170
|
-
/** Present iff the bootstrap is incomplete (§4.4). */
|
|
208
|
+
/** Present iff the unit's bootstrap is incomplete (§4.4). */
|
|
171
209
|
bootstrapState?: string;
|
|
172
210
|
}
|
|
173
211
|
export interface ErrorFrame {
|
|
@@ -179,7 +217,7 @@ export interface ErrorFrame {
|
|
|
179
217
|
recommendedAction: string;
|
|
180
218
|
details?: string;
|
|
181
219
|
}
|
|
182
|
-
export type ResponseFrame = RespHeaderFrame | LeaseFrame | PushResultFrame | PushResultDetailsFrame | SubStartFrame | CommitFrame | SegmentRefFrame | SegmentInlineFrame | SubEndFrame | ErrorFrame | UnknownFrame;
|
|
220
|
+
export type ResponseFrame = RespHeaderFrame | LeaseFrame | PushResultFrame | PushResultDetailsFrame | SubStartFrame | CommitFrame | SegmentRefFrame | SegmentInlineFrame | SubEndFrame | LiveStartFrame | LiveEndFrame | ErrorFrame | UnknownFrame;
|
|
183
221
|
export interface RequestMessage {
|
|
184
222
|
wireVersion: number;
|
|
185
223
|
msgKind: 'request';
|
|
@@ -193,6 +231,9 @@ export interface ResponseMessage {
|
|
|
193
231
|
export type SyncMessage = RequestMessage | ResponseMessage;
|
|
194
232
|
/** §1.5: `code` is a legal `ROUND_FAILURE` code (grammar and byte length). */
|
|
195
233
|
export declare function isRoundFailureCode(code: string): boolean;
|
|
196
|
-
export declare function
|
|
234
|
+
export declare function encodeRequest(message: RequestMessage): Uint8Array;
|
|
235
|
+
export declare function encodeResponse(message: ResponseMessage): Uint8Array;
|
|
197
236
|
export declare function encodeMessage(message: SyncMessage): Uint8Array;
|
|
237
|
+
export declare function decodeRequest(bytes: Uint8Array): RequestMessage;
|
|
238
|
+
export declare function decodeResponse(bytes: Uint8Array): ResponseMessage;
|
|
198
239
|
export declare function decodeMessage(bytes: Uint8Array): SyncMessage;
|