@syncular/core 0.0.6-206 → 0.0.6-211
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/schemas/sync.d.ts
CHANGED
|
@@ -251,7 +251,7 @@ export declare const SyncSnapshotChunkRefSchema: z.ZodObject<{
|
|
|
251
251
|
id: z.ZodString;
|
|
252
252
|
byteLength: z.ZodNumber;
|
|
253
253
|
sha256: z.ZodString;
|
|
254
|
-
encoding: z.ZodLiteral<"json-row-
|
|
254
|
+
encoding: z.ZodLiteral<"json-row-frame-v1">;
|
|
255
255
|
compression: z.ZodLiteral<"gzip">;
|
|
256
256
|
}, z.core.$strip>;
|
|
257
257
|
export type SyncSnapshotChunkRef = z.infer<typeof SyncSnapshotChunkRefSchema>;
|
|
@@ -262,7 +262,7 @@ export declare const SyncSnapshotSchema: z.ZodObject<{
|
|
|
262
262
|
id: z.ZodString;
|
|
263
263
|
byteLength: z.ZodNumber;
|
|
264
264
|
sha256: z.ZodString;
|
|
265
|
-
encoding: z.ZodLiteral<"json-row-
|
|
265
|
+
encoding: z.ZodLiteral<"json-row-frame-v1">;
|
|
266
266
|
compression: z.ZodLiteral<"gzip">;
|
|
267
267
|
}, z.core.$strip>>>;
|
|
268
268
|
isFirstPage: z.ZodBoolean;
|
|
@@ -307,7 +307,7 @@ export declare const SyncPullSubscriptionResponseSchema: z.ZodObject<{
|
|
|
307
307
|
id: z.ZodString;
|
|
308
308
|
byteLength: z.ZodNumber;
|
|
309
309
|
sha256: z.ZodString;
|
|
310
|
-
encoding: z.ZodLiteral<"json-row-
|
|
310
|
+
encoding: z.ZodLiteral<"json-row-frame-v1">;
|
|
311
311
|
compression: z.ZodLiteral<"gzip">;
|
|
312
312
|
}, z.core.$strip>>>;
|
|
313
313
|
isFirstPage: z.ZodBoolean;
|
|
@@ -355,7 +355,7 @@ export declare const SyncPullResponseSchema: z.ZodObject<{
|
|
|
355
355
|
id: z.ZodString;
|
|
356
356
|
byteLength: z.ZodNumber;
|
|
357
357
|
sha256: z.ZodString;
|
|
358
|
-
encoding: z.ZodLiteral<"json-row-
|
|
358
|
+
encoding: z.ZodLiteral<"json-row-frame-v1">;
|
|
359
359
|
compression: z.ZodLiteral<"gzip">;
|
|
360
360
|
}, z.core.$strip>>>;
|
|
361
361
|
isFirstPage: z.ZodBoolean;
|
|
@@ -474,7 +474,7 @@ export declare const SyncCombinedResponseSchema: z.ZodObject<{
|
|
|
474
474
|
id: z.ZodString;
|
|
475
475
|
byteLength: z.ZodNumber;
|
|
476
476
|
sha256: z.ZodString;
|
|
477
|
-
encoding: z.ZodLiteral<"json-row-
|
|
477
|
+
encoding: z.ZodLiteral<"json-row-frame-v1">;
|
|
478
478
|
compression: z.ZodLiteral<"gzip">;
|
|
479
479
|
}, z.core.$strip>>>;
|
|
480
480
|
isFirstPage: z.ZodBoolean;
|
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @syncular/core - Snapshot chunk encoding helpers
|
|
3
3
|
*/
|
|
4
|
-
export declare const SYNC_SNAPSHOT_CHUNK_ENCODING = "json-row-
|
|
4
|
+
export declare const SYNC_SNAPSHOT_CHUNK_ENCODING = "json-row-frame-v1";
|
|
5
5
|
export type SyncSnapshotChunkEncoding = typeof SYNC_SNAPSHOT_CHUNK_ENCODING;
|
|
6
6
|
export declare const SYNC_SNAPSHOT_CHUNK_COMPRESSION = "gzip";
|
|
7
7
|
export type SyncSnapshotChunkCompression = typeof SYNC_SNAPSHOT_CHUNK_COMPRESSION;
|
|
8
|
-
export declare const SYNC_SNAPSHOT_CHUNK_MAGIC: Uint8Array<ArrayBuffer>;
|
|
9
8
|
/**
|
|
10
|
-
* Encode rows as
|
|
9
|
+
* Encode rows as framed JSON bytes without the format header.
|
|
11
10
|
*/
|
|
12
11
|
export declare function encodeSnapshotRowFrames(rows: readonly unknown[]): Uint8Array;
|
|
13
12
|
/**
|
|
14
13
|
* Encode rows as framed JSON bytes with a format header.
|
|
15
14
|
*
|
|
16
15
|
* Format:
|
|
17
|
-
* - 4-byte magic header ("
|
|
16
|
+
* - 4-byte magic header ("SRF1")
|
|
18
17
|
* - repeated frames of:
|
|
19
18
|
* - 4-byte big-endian payload byte length
|
|
20
|
-
* - UTF-8 JSON
|
|
19
|
+
* - UTF-8 JSON payload
|
|
21
20
|
*/
|
|
22
21
|
export declare function encodeSnapshotRows(rows: readonly unknown[]): Uint8Array;
|
|
23
22
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshot-chunks.d.ts","sourceRoot":"","sources":["../src/snapshot-chunks.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,4BAA4B,
|
|
1
|
+
{"version":3,"file":"snapshot-chunks.d.ts","sourceRoot":"","sources":["../src/snapshot-chunks.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,4BAA4B,sBAAsB,CAAC;AAChE,MAAM,MAAM,yBAAyB,GAAG,OAAO,4BAA4B,CAAC;AAE5E,eAAO,MAAM,+BAA+B,SAAS,CAAC;AACtD,MAAM,MAAM,4BAA4B,GACtC,OAAO,+BAA+B,CAAC;AAazC;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,GAAG,UAAU,CA0B5E;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,GAAG,UAAU,CASvE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,EAAE,CAmC/D"}
|
package/dist/snapshot-chunks.js
CHANGED
|
@@ -1,61 +1,68 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @syncular/core - Snapshot chunk encoding helpers
|
|
3
3
|
*/
|
|
4
|
-
export const SYNC_SNAPSHOT_CHUNK_ENCODING = 'json-row-
|
|
4
|
+
export const SYNC_SNAPSHOT_CHUNK_ENCODING = 'json-row-frame-v1';
|
|
5
5
|
export const SYNC_SNAPSHOT_CHUNK_COMPRESSION = 'gzip';
|
|
6
|
-
|
|
7
|
-
0x53, 0x42, 0x46, 0x32,
|
|
8
|
-
]); // "SBF2"
|
|
6
|
+
const SNAPSHOT_ROW_FRAME_MAGIC = new Uint8Array([0x53, 0x52, 0x46, 0x31]); // "SRF1"
|
|
9
7
|
const FRAME_LENGTH_BYTES = 4;
|
|
10
8
|
const MAX_FRAME_BYTE_LENGTH = 0xffff_ffff;
|
|
11
9
|
const snapshotRowFrameEncoder = new TextEncoder();
|
|
12
10
|
const snapshotRowFrameDecoder = new TextDecoder();
|
|
13
|
-
function
|
|
14
|
-
|
|
11
|
+
function normalizeRowJson(row) {
|
|
12
|
+
const serialized = JSON.stringify(row);
|
|
13
|
+
return serialized === undefined ? 'null' : serialized;
|
|
15
14
|
}
|
|
16
15
|
/**
|
|
17
|
-
* Encode rows as
|
|
16
|
+
* Encode rows as framed JSON bytes without the format header.
|
|
18
17
|
*/
|
|
19
18
|
export function encodeSnapshotRowFrames(rows) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
const payloads = [];
|
|
20
|
+
let totalByteLength = 0;
|
|
21
|
+
for (const row of rows) {
|
|
22
|
+
const payload = snapshotRowFrameEncoder.encode(normalizeRowJson(row));
|
|
23
|
+
if (payload.length > MAX_FRAME_BYTE_LENGTH) {
|
|
24
|
+
throw new Error(`Snapshot row payload exceeds ${MAX_FRAME_BYTE_LENGTH} bytes`);
|
|
25
|
+
}
|
|
26
|
+
payloads.push(payload);
|
|
27
|
+
totalByteLength += FRAME_LENGTH_BYTES + payload.length;
|
|
26
28
|
}
|
|
27
|
-
const encoded = new Uint8Array(
|
|
29
|
+
const encoded = new Uint8Array(totalByteLength);
|
|
28
30
|
const view = new DataView(encoded.buffer, encoded.byteOffset, encoded.length);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
let offset = 0;
|
|
32
|
+
for (const payload of payloads) {
|
|
33
|
+
view.setUint32(offset, payload.length, false);
|
|
34
|
+
offset += FRAME_LENGTH_BYTES;
|
|
35
|
+
encoded.set(payload, offset);
|
|
36
|
+
offset += payload.length;
|
|
37
|
+
}
|
|
31
38
|
return encoded;
|
|
32
39
|
}
|
|
33
40
|
/**
|
|
34
41
|
* Encode rows as framed JSON bytes with a format header.
|
|
35
42
|
*
|
|
36
43
|
* Format:
|
|
37
|
-
* - 4-byte magic header ("
|
|
44
|
+
* - 4-byte magic header ("SRF1")
|
|
38
45
|
* - repeated frames of:
|
|
39
46
|
* - 4-byte big-endian payload byte length
|
|
40
|
-
* - UTF-8 JSON
|
|
47
|
+
* - UTF-8 JSON payload
|
|
41
48
|
*/
|
|
42
49
|
export function encodeSnapshotRows(rows) {
|
|
43
50
|
const framedRows = encodeSnapshotRowFrames(rows);
|
|
44
|
-
const totalByteLength =
|
|
51
|
+
const totalByteLength = SNAPSHOT_ROW_FRAME_MAGIC.length + framedRows.length;
|
|
45
52
|
const encoded = new Uint8Array(totalByteLength);
|
|
46
|
-
encoded.set(
|
|
47
|
-
encoded.set(framedRows,
|
|
53
|
+
encoded.set(SNAPSHOT_ROW_FRAME_MAGIC, 0);
|
|
54
|
+
encoded.set(framedRows, SNAPSHOT_ROW_FRAME_MAGIC.length);
|
|
48
55
|
return encoded;
|
|
49
56
|
}
|
|
50
57
|
/**
|
|
51
58
|
* Decode framed JSON bytes into rows.
|
|
52
59
|
*/
|
|
53
60
|
export function decodeSnapshotRows(bytes) {
|
|
54
|
-
if (bytes.length <
|
|
61
|
+
if (bytes.length < SNAPSHOT_ROW_FRAME_MAGIC.length) {
|
|
55
62
|
throw new Error('Snapshot chunk payload is too small');
|
|
56
63
|
}
|
|
57
|
-
for (let index = 0; index <
|
|
58
|
-
const expected =
|
|
64
|
+
for (let index = 0; index < SNAPSHOT_ROW_FRAME_MAGIC.length; index += 1) {
|
|
65
|
+
const expected = SNAPSHOT_ROW_FRAME_MAGIC[index];
|
|
59
66
|
const actual = bytes[index];
|
|
60
67
|
if (actual !== expected) {
|
|
61
68
|
throw new Error('Unexpected snapshot chunk format');
|
|
@@ -63,7 +70,7 @@ export function decodeSnapshotRows(bytes) {
|
|
|
63
70
|
}
|
|
64
71
|
const rows = [];
|
|
65
72
|
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.length);
|
|
66
|
-
let offset =
|
|
73
|
+
let offset = SNAPSHOT_ROW_FRAME_MAGIC.length;
|
|
67
74
|
while (offset < bytes.length) {
|
|
68
75
|
if (offset + FRAME_LENGTH_BYTES > bytes.length) {
|
|
69
76
|
throw new Error('Snapshot chunk payload ended mid-frame header');
|
|
@@ -75,11 +82,7 @@ export function decodeSnapshotRows(bytes) {
|
|
|
75
82
|
}
|
|
76
83
|
const payload = bytes.subarray(offset, offset + payloadLength);
|
|
77
84
|
offset += payloadLength;
|
|
78
|
-
|
|
79
|
-
if (!Array.isArray(parsed)) {
|
|
80
|
-
throw new Error('Snapshot chunk frame payload must be a JSON array');
|
|
81
|
-
}
|
|
82
|
-
rows.push(...parsed);
|
|
85
|
+
rows.push(JSON.parse(snapshotRowFrameDecoder.decode(payload)));
|
|
83
86
|
}
|
|
84
87
|
return rows;
|
|
85
88
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshot-chunks.js","sourceRoot":"","sources":["../src/snapshot-chunks.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,CAAC,MAAM,4BAA4B,GAAG,
|
|
1
|
+
{"version":3,"file":"snapshot-chunks.js","sourceRoot":"","sources":["../src/snapshot-chunks.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/snapshot-chunks.ts
CHANGED
|
@@ -2,44 +2,52 @@
|
|
|
2
2
|
* @syncular/core - Snapshot chunk encoding helpers
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
export const SYNC_SNAPSHOT_CHUNK_ENCODING = 'json-row-
|
|
5
|
+
export const SYNC_SNAPSHOT_CHUNK_ENCODING = 'json-row-frame-v1';
|
|
6
6
|
export type SyncSnapshotChunkEncoding = typeof SYNC_SNAPSHOT_CHUNK_ENCODING;
|
|
7
7
|
|
|
8
8
|
export const SYNC_SNAPSHOT_CHUNK_COMPRESSION = 'gzip';
|
|
9
9
|
export type SyncSnapshotChunkCompression =
|
|
10
10
|
typeof SYNC_SNAPSHOT_CHUNK_COMPRESSION;
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
0x53, 0x42, 0x46, 0x32,
|
|
14
|
-
]); // "SBF2"
|
|
12
|
+
const SNAPSHOT_ROW_FRAME_MAGIC = new Uint8Array([0x53, 0x52, 0x46, 0x31]); // "SRF1"
|
|
15
13
|
const FRAME_LENGTH_BYTES = 4;
|
|
16
14
|
const MAX_FRAME_BYTE_LENGTH = 0xffff_ffff;
|
|
17
15
|
const snapshotRowFrameEncoder = new TextEncoder();
|
|
18
16
|
const snapshotRowFrameDecoder = new TextDecoder();
|
|
19
17
|
|
|
20
|
-
function
|
|
21
|
-
|
|
18
|
+
function normalizeRowJson(row: unknown): string {
|
|
19
|
+
const serialized = JSON.stringify(row);
|
|
20
|
+
return serialized === undefined ? 'null' : serialized;
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
/**
|
|
25
|
-
* Encode rows as
|
|
24
|
+
* Encode rows as framed JSON bytes without the format header.
|
|
26
25
|
*/
|
|
27
26
|
export function encodeSnapshotRowFrames(rows: readonly unknown[]): Uint8Array {
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
const payloads: Uint8Array[] = [];
|
|
28
|
+
let totalByteLength = 0;
|
|
29
|
+
|
|
30
|
+
for (const row of rows) {
|
|
31
|
+
const payload = snapshotRowFrameEncoder.encode(normalizeRowJson(row));
|
|
32
|
+
if (payload.length > MAX_FRAME_BYTE_LENGTH) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
`Snapshot row payload exceeds ${MAX_FRAME_BYTE_LENGTH} bytes`
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
payloads.push(payload);
|
|
38
|
+
totalByteLength += FRAME_LENGTH_BYTES + payload.length;
|
|
30
39
|
}
|
|
31
40
|
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
);
|
|
41
|
+
const encoded = new Uint8Array(totalByteLength);
|
|
42
|
+
const view = new DataView(encoded.buffer, encoded.byteOffset, encoded.length);
|
|
43
|
+
let offset = 0;
|
|
44
|
+
for (const payload of payloads) {
|
|
45
|
+
view.setUint32(offset, payload.length, false);
|
|
46
|
+
offset += FRAME_LENGTH_BYTES;
|
|
47
|
+
encoded.set(payload, offset);
|
|
48
|
+
offset += payload.length;
|
|
37
49
|
}
|
|
38
50
|
|
|
39
|
-
const encoded = new Uint8Array(FRAME_LENGTH_BYTES + payload.length);
|
|
40
|
-
const view = new DataView(encoded.buffer, encoded.byteOffset, encoded.length);
|
|
41
|
-
view.setUint32(0, payload.length, false);
|
|
42
|
-
encoded.set(payload, FRAME_LENGTH_BYTES);
|
|
43
51
|
return encoded;
|
|
44
52
|
}
|
|
45
53
|
|
|
@@ -47,18 +55,18 @@ export function encodeSnapshotRowFrames(rows: readonly unknown[]): Uint8Array {
|
|
|
47
55
|
* Encode rows as framed JSON bytes with a format header.
|
|
48
56
|
*
|
|
49
57
|
* Format:
|
|
50
|
-
* - 4-byte magic header ("
|
|
58
|
+
* - 4-byte magic header ("SRF1")
|
|
51
59
|
* - repeated frames of:
|
|
52
60
|
* - 4-byte big-endian payload byte length
|
|
53
|
-
* - UTF-8 JSON
|
|
61
|
+
* - UTF-8 JSON payload
|
|
54
62
|
*/
|
|
55
63
|
export function encodeSnapshotRows(rows: readonly unknown[]): Uint8Array {
|
|
56
64
|
const framedRows = encodeSnapshotRowFrames(rows);
|
|
57
|
-
const totalByteLength =
|
|
65
|
+
const totalByteLength = SNAPSHOT_ROW_FRAME_MAGIC.length + framedRows.length;
|
|
58
66
|
|
|
59
67
|
const encoded = new Uint8Array(totalByteLength);
|
|
60
|
-
encoded.set(
|
|
61
|
-
encoded.set(framedRows,
|
|
68
|
+
encoded.set(SNAPSHOT_ROW_FRAME_MAGIC, 0);
|
|
69
|
+
encoded.set(framedRows, SNAPSHOT_ROW_FRAME_MAGIC.length);
|
|
62
70
|
|
|
63
71
|
return encoded;
|
|
64
72
|
}
|
|
@@ -67,12 +75,12 @@ export function encodeSnapshotRows(rows: readonly unknown[]): Uint8Array {
|
|
|
67
75
|
* Decode framed JSON bytes into rows.
|
|
68
76
|
*/
|
|
69
77
|
export function decodeSnapshotRows(bytes: Uint8Array): unknown[] {
|
|
70
|
-
if (bytes.length <
|
|
78
|
+
if (bytes.length < SNAPSHOT_ROW_FRAME_MAGIC.length) {
|
|
71
79
|
throw new Error('Snapshot chunk payload is too small');
|
|
72
80
|
}
|
|
73
81
|
|
|
74
|
-
for (let index = 0; index <
|
|
75
|
-
const expected =
|
|
82
|
+
for (let index = 0; index < SNAPSHOT_ROW_FRAME_MAGIC.length; index += 1) {
|
|
83
|
+
const expected = SNAPSHOT_ROW_FRAME_MAGIC[index];
|
|
76
84
|
const actual = bytes[index];
|
|
77
85
|
if (actual !== expected) {
|
|
78
86
|
throw new Error('Unexpected snapshot chunk format');
|
|
@@ -81,7 +89,7 @@ export function decodeSnapshotRows(bytes: Uint8Array): unknown[] {
|
|
|
81
89
|
|
|
82
90
|
const rows: unknown[] = [];
|
|
83
91
|
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.length);
|
|
84
|
-
let offset =
|
|
92
|
+
let offset = SNAPSHOT_ROW_FRAME_MAGIC.length;
|
|
85
93
|
|
|
86
94
|
while (offset < bytes.length) {
|
|
87
95
|
if (offset + FRAME_LENGTH_BYTES > bytes.length) {
|
|
@@ -97,11 +105,7 @@ export function decodeSnapshotRows(bytes: Uint8Array): unknown[] {
|
|
|
97
105
|
|
|
98
106
|
const payload = bytes.subarray(offset, offset + payloadLength);
|
|
99
107
|
offset += payloadLength;
|
|
100
|
-
|
|
101
|
-
if (!Array.isArray(parsed)) {
|
|
102
|
-
throw new Error('Snapshot chunk frame payload must be a JSON array');
|
|
103
|
-
}
|
|
104
|
-
rows.push(...parsed);
|
|
108
|
+
rows.push(JSON.parse(snapshotRowFrameDecoder.decode(payload)));
|
|
105
109
|
}
|
|
106
110
|
|
|
107
111
|
return rows;
|