@syncular/client 0.0.6-204 → 0.0.6-206
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/engine/SyncEngine.d.ts +3 -0
- package/dist/engine/SyncEngine.d.ts.map +1 -1
- package/dist/engine/SyncEngine.js +60 -5
- package/dist/engine/SyncEngine.js.map +1 -1
- package/dist/pull-engine.d.ts.map +1 -1
- package/dist/pull-engine.js +66 -138
- package/dist/pull-engine.js.map +1 -1
- package/package.json +3 -3
- package/src/engine/SyncEngine.test.ts +182 -5
- package/src/engine/SyncEngine.ts +80 -5
- package/src/pull-engine.test.ts +10 -10
- package/src/pull-engine.ts +102 -160
|
@@ -795,19 +795,19 @@ describe('SyncEngine WS inline apply', () => {
|
|
|
795
795
|
expect(state.error?.httpStatus).toBe(429);
|
|
796
796
|
expect(state.retryCount).toBe(1);
|
|
797
797
|
expect(state.isRetrying).toBe(true);
|
|
798
|
-
expect(delays).toEqual([
|
|
798
|
+
expect(delays).toEqual([1000]);
|
|
799
799
|
|
|
800
800
|
await engine.sync();
|
|
801
801
|
state = engine.getState();
|
|
802
802
|
expect(state.retryCount).toBe(2);
|
|
803
803
|
expect(state.isRetrying).toBe(true);
|
|
804
|
-
expect(delays).toEqual([
|
|
804
|
+
expect(delays).toEqual([1000, 2000]);
|
|
805
805
|
|
|
806
806
|
await engine.sync();
|
|
807
807
|
state = engine.getState();
|
|
808
808
|
expect(state.retryCount).toBe(3);
|
|
809
809
|
expect(state.isRetrying).toBe(true);
|
|
810
|
-
expect(delays).toEqual([2000, 4000
|
|
810
|
+
expect(delays).toEqual([1000, 2000, 4000]);
|
|
811
811
|
expect(syncAttempts).toBe(3);
|
|
812
812
|
|
|
813
813
|
engine.destroy();
|
|
@@ -819,6 +819,183 @@ describe('SyncEngine WS inline apply', () => {
|
|
|
819
819
|
}
|
|
820
820
|
});
|
|
821
821
|
|
|
822
|
+
it('uses a shorter capped recovery retry delay after a recent successful read-only sync', async () => {
|
|
823
|
+
let syncAttempts = 0;
|
|
824
|
+
const delayedFailureTransport: SyncTransport = {
|
|
825
|
+
async sync() {
|
|
826
|
+
syncAttempts += 1;
|
|
827
|
+
if (syncAttempts === 1) {
|
|
828
|
+
return { ok: true, subscriptions: [] };
|
|
829
|
+
}
|
|
830
|
+
throw new SyncTransportError('service unavailable', 503);
|
|
831
|
+
},
|
|
832
|
+
async fetchSnapshotChunk() {
|
|
833
|
+
return new Uint8Array();
|
|
834
|
+
},
|
|
835
|
+
};
|
|
836
|
+
const handlers: ClientHandlerCollection<TestDb> = [
|
|
837
|
+
{
|
|
838
|
+
table: 'tasks',
|
|
839
|
+
async applySnapshot() {},
|
|
840
|
+
async clearAll() {},
|
|
841
|
+
async applyChange() {},
|
|
842
|
+
},
|
|
843
|
+
];
|
|
844
|
+
|
|
845
|
+
const delays: number[] = [];
|
|
846
|
+
const timeoutHandles: Array<ReturnType<typeof setTimeout>> = [];
|
|
847
|
+
const originalSetTimeout = globalThis.setTimeout;
|
|
848
|
+
const patchedSetTimeout: typeof globalThis.setTimeout = (
|
|
849
|
+
_handler,
|
|
850
|
+
timeout,
|
|
851
|
+
..._args
|
|
852
|
+
) => {
|
|
853
|
+
const delayMs = typeof timeout === 'number' ? timeout : 0;
|
|
854
|
+
delays.push(delayMs);
|
|
855
|
+
const handle = originalSetTimeout(() => {}, 60_000);
|
|
856
|
+
timeoutHandles.push(handle);
|
|
857
|
+
return handle;
|
|
858
|
+
};
|
|
859
|
+
globalThis.setTimeout = patchedSetTimeout;
|
|
860
|
+
|
|
861
|
+
try {
|
|
862
|
+
const engine = new SyncEngine<TestDb>({
|
|
863
|
+
db,
|
|
864
|
+
transport: delayedFailureTransport,
|
|
865
|
+
handlers,
|
|
866
|
+
actorId: 'u1',
|
|
867
|
+
clientId: 'client-recovery-retry',
|
|
868
|
+
subscriptions: [
|
|
869
|
+
{
|
|
870
|
+
id: 'sub-1',
|
|
871
|
+
table: 'tasks',
|
|
872
|
+
scopes: {},
|
|
873
|
+
},
|
|
874
|
+
],
|
|
875
|
+
stateId: 'default',
|
|
876
|
+
pollIntervalMs: 60_000,
|
|
877
|
+
maxRetries: 5,
|
|
878
|
+
});
|
|
879
|
+
|
|
880
|
+
await engine.start();
|
|
881
|
+
expect(engine.getState().lastSyncAt).not.toBeNull();
|
|
882
|
+
|
|
883
|
+
await engine.sync();
|
|
884
|
+
let state = engine.getState();
|
|
885
|
+
expect(state.error?.code).toBe('NETWORK_ERROR');
|
|
886
|
+
expect(state.retryCount).toBe(1);
|
|
887
|
+
expect(state.isRetrying).toBe(true);
|
|
888
|
+
|
|
889
|
+
await engine.sync();
|
|
890
|
+
state = engine.getState();
|
|
891
|
+
expect(state.retryCount).toBe(2);
|
|
892
|
+
|
|
893
|
+
await engine.sync();
|
|
894
|
+
state = engine.getState();
|
|
895
|
+
expect(state.retryCount).toBe(3);
|
|
896
|
+
|
|
897
|
+
await engine.sync();
|
|
898
|
+
state = engine.getState();
|
|
899
|
+
expect(state.retryCount).toBe(4);
|
|
900
|
+
expect(delays).toEqual([250, 500, 1000, 1000]);
|
|
901
|
+
|
|
902
|
+
engine.destroy();
|
|
903
|
+
} finally {
|
|
904
|
+
globalThis.setTimeout = originalSetTimeout;
|
|
905
|
+
for (const handle of timeoutHandles) {
|
|
906
|
+
clearTimeout(handle);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
});
|
|
910
|
+
|
|
911
|
+
it('uses deterministic jitter for realtime reconnect sync and catchup scheduling', () => {
|
|
912
|
+
const handlers: ClientHandlerCollection<TestDb> = [
|
|
913
|
+
{
|
|
914
|
+
table: 'tasks',
|
|
915
|
+
async applySnapshot() {},
|
|
916
|
+
async clearAll() {},
|
|
917
|
+
async applyChange() {},
|
|
918
|
+
},
|
|
919
|
+
];
|
|
920
|
+
|
|
921
|
+
const delays: number[] = [];
|
|
922
|
+
const timeoutHandles: Array<ReturnType<typeof setTimeout>> = [];
|
|
923
|
+
const originalSetTimeout = globalThis.setTimeout;
|
|
924
|
+
const patchedSetTimeout: typeof globalThis.setTimeout = (
|
|
925
|
+
_handler,
|
|
926
|
+
timeout,
|
|
927
|
+
..._args
|
|
928
|
+
) => {
|
|
929
|
+
const delayMs = typeof timeout === 'number' ? timeout : 0;
|
|
930
|
+
delays.push(delayMs);
|
|
931
|
+
const handle = originalSetTimeout(() => {}, 60_000);
|
|
932
|
+
timeoutHandles.push(handle);
|
|
933
|
+
return handle;
|
|
934
|
+
};
|
|
935
|
+
globalThis.setTimeout = patchedSetTimeout;
|
|
936
|
+
|
|
937
|
+
try {
|
|
938
|
+
const engineA = new SyncEngine<TestDb>({
|
|
939
|
+
db,
|
|
940
|
+
transport: noopTransport,
|
|
941
|
+
handlers,
|
|
942
|
+
actorId: 'u1',
|
|
943
|
+
clientId: 'client-reconnect-jitter',
|
|
944
|
+
subscriptions: [],
|
|
945
|
+
stateId: 'default',
|
|
946
|
+
});
|
|
947
|
+
const engineB = new SyncEngine<TestDb>({
|
|
948
|
+
db,
|
|
949
|
+
transport: noopTransport,
|
|
950
|
+
handlers,
|
|
951
|
+
actorId: 'u1',
|
|
952
|
+
clientId: 'client-reconnect-jitter',
|
|
953
|
+
subscriptions: [],
|
|
954
|
+
stateId: 'default',
|
|
955
|
+
});
|
|
956
|
+
|
|
957
|
+
const scheduleReconnectSyncA = Reflect.get(
|
|
958
|
+
engineA,
|
|
959
|
+
'scheduleRealtimeReconnectSync'
|
|
960
|
+
);
|
|
961
|
+
const scheduleReconnectCatchupA = Reflect.get(
|
|
962
|
+
engineA,
|
|
963
|
+
'scheduleRealtimeReconnectCatchupSync'
|
|
964
|
+
);
|
|
965
|
+
const scheduleReconnectSyncB = Reflect.get(
|
|
966
|
+
engineB,
|
|
967
|
+
'scheduleRealtimeReconnectSync'
|
|
968
|
+
);
|
|
969
|
+
|
|
970
|
+
if (
|
|
971
|
+
typeof scheduleReconnectSyncA !== 'function' ||
|
|
972
|
+
typeof scheduleReconnectCatchupA !== 'function' ||
|
|
973
|
+
typeof scheduleReconnectSyncB !== 'function'
|
|
974
|
+
) {
|
|
975
|
+
throw new Error('Expected reconnect scheduling helpers to be callable');
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
scheduleReconnectSyncA.call(engineA);
|
|
979
|
+
scheduleReconnectCatchupA.call(engineA);
|
|
980
|
+
scheduleReconnectSyncB.call(engineB);
|
|
981
|
+
|
|
982
|
+
expect(delays.length).toBe(3);
|
|
983
|
+
expect(delays[0]).toBeGreaterThanOrEqual(0);
|
|
984
|
+
expect(delays[0]).toBeLessThanOrEqual(250);
|
|
985
|
+
expect(delays[1]).toBeGreaterThanOrEqual(500);
|
|
986
|
+
expect(delays[1]).toBeLessThanOrEqual(750);
|
|
987
|
+
expect(delays[2]).toBe(delays[0]);
|
|
988
|
+
|
|
989
|
+
engineA.destroy();
|
|
990
|
+
engineB.destroy();
|
|
991
|
+
} finally {
|
|
992
|
+
globalThis.setTimeout = originalSetTimeout;
|
|
993
|
+
for (const handle of timeoutHandles) {
|
|
994
|
+
clearTimeout(handle);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
});
|
|
998
|
+
|
|
822
999
|
it('keeps push failures retryable on 503 and preserves pending outbox state', async () => {
|
|
823
1000
|
let sawPushRequest = false;
|
|
824
1001
|
const unavailablePushTransport: SyncTransport = {
|
|
@@ -953,7 +1130,7 @@ describe('SyncEngine WS inline apply', () => {
|
|
|
953
1130
|
id: 'chunk-retry-1',
|
|
954
1131
|
byteLength: payload.length,
|
|
955
1132
|
sha256: '',
|
|
956
|
-
encoding: 'json-row-frame-
|
|
1133
|
+
encoding: 'json-row-batch-frame-v2',
|
|
957
1134
|
compression: 'gzip',
|
|
958
1135
|
},
|
|
959
1136
|
],
|
|
@@ -1045,7 +1222,7 @@ describe('SyncEngine WS inline apply', () => {
|
|
|
1045
1222
|
const state = engine.getState();
|
|
1046
1223
|
expect(state.retryCount).toBe(0);
|
|
1047
1224
|
expect(state.isRetrying).toBe(false);
|
|
1048
|
-
expect(delays[0]).toBe(
|
|
1225
|
+
expect(delays[0]).toBe(1000);
|
|
1049
1226
|
expect(chunkFetchCalls).toBeGreaterThanOrEqual(2);
|
|
1050
1227
|
expect(syncCalls).toBeGreaterThanOrEqual(2);
|
|
1051
1228
|
|
package/src/engine/SyncEngine.ts
CHANGED
|
@@ -75,7 +75,11 @@ const DEFAULT_MAX_RETRIES = 5;
|
|
|
75
75
|
const INITIAL_RETRY_DELAY_MS = 1000;
|
|
76
76
|
const MAX_RETRY_DELAY_MS = 60000;
|
|
77
77
|
const EXPONENTIAL_FACTOR = 2;
|
|
78
|
+
const RECOVERY_RETRY_DELAY_MS = 250;
|
|
79
|
+
const MAX_RECOVERY_RETRY_DELAY_MS = 1000;
|
|
80
|
+
const RECOVERY_RETRY_WINDOW_MS = 120000;
|
|
78
81
|
const REALTIME_RECONNECT_CATCHUP_DELAY_MS = 500;
|
|
82
|
+
const REALTIME_RECONNECT_SYNC_JITTER_MS = 250;
|
|
79
83
|
const DEFAULT_AWAIT_TIMEOUT_MS = 60_000;
|
|
80
84
|
const DEFAULT_INSPECTOR_EVENT_LIMIT = 100;
|
|
81
85
|
const MAX_INSPECTOR_EVENT_LIMIT = 500;
|
|
@@ -88,6 +92,27 @@ function calculateRetryDelay(attemptIndex: number): number {
|
|
|
88
92
|
);
|
|
89
93
|
}
|
|
90
94
|
|
|
95
|
+
function calculateRecoveryRetryDelay(attemptIndex: number): number {
|
|
96
|
+
return Math.min(
|
|
97
|
+
RECOVERY_RETRY_DELAY_MS * EXPONENTIAL_FACTOR ** attemptIndex,
|
|
98
|
+
MAX_RECOVERY_RETRY_DELAY_MS
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function calculateDeterministicClientJitter(
|
|
103
|
+
clientId: string,
|
|
104
|
+
maxJitterMs: number
|
|
105
|
+
): number {
|
|
106
|
+
if (maxJitterMs <= 0 || clientId.length === 0) return 0;
|
|
107
|
+
|
|
108
|
+
let hash = 0;
|
|
109
|
+
for (let index = 0; index < clientId.length; index += 1) {
|
|
110
|
+
hash = (hash * 31 + clientId.charCodeAt(index)) >>> 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return hash % (maxJitterMs + 1);
|
|
114
|
+
}
|
|
115
|
+
|
|
91
116
|
function isRealtimeTransport(
|
|
92
117
|
transport: unknown
|
|
93
118
|
): transport is RealtimeTransportLike {
|
|
@@ -310,6 +335,8 @@ export class SyncEngine<DB extends SyncClientDb = SyncClientDb> {
|
|
|
310
335
|
private syncRequestedWhileRunning = false;
|
|
311
336
|
private retryTimeoutId: ReturnType<typeof setTimeout> | null = null;
|
|
312
337
|
private realtimeCatchupTimeoutId: ReturnType<typeof setTimeout> | null = null;
|
|
338
|
+
private realtimeReconnectSyncTimeoutId: ReturnType<typeof setTimeout> | null =
|
|
339
|
+
null;
|
|
313
340
|
private dataChangeDebounceTimeoutId: ReturnType<typeof setTimeout> | null =
|
|
314
341
|
null;
|
|
315
342
|
private pendingDataChangeScopes = new Set<string>();
|
|
@@ -1704,6 +1731,10 @@ export class SyncEngine<DB extends SyncClientDb = SyncClientDb> {
|
|
|
1704
1731
|
clearTimeout(this.realtimeCatchupTimeoutId);
|
|
1705
1732
|
this.realtimeCatchupTimeoutId = null;
|
|
1706
1733
|
}
|
|
1734
|
+
if (this.realtimeReconnectSyncTimeoutId) {
|
|
1735
|
+
clearTimeout(this.realtimeReconnectSyncTimeoutId);
|
|
1736
|
+
this.realtimeReconnectSyncTimeoutId = null;
|
|
1737
|
+
}
|
|
1707
1738
|
}
|
|
1708
1739
|
|
|
1709
1740
|
/**
|
|
@@ -1980,7 +2011,7 @@ export class SyncEngine<DB extends SyncClientDb = SyncClientDb> {
|
|
|
1980
2011
|
// Schedule retry if under max retries
|
|
1981
2012
|
const maxRetries = this.config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
1982
2013
|
if (error.retryable && this.state.retryCount < maxRetries) {
|
|
1983
|
-
this.scheduleRetry();
|
|
2014
|
+
this.scheduleRetry(error);
|
|
1984
2015
|
}
|
|
1985
2016
|
this.flushReconnectBatchedDataChangesIfReady();
|
|
1986
2017
|
|
|
@@ -2338,12 +2369,22 @@ export class SyncEngine<DB extends SyncClientDb = SyncClientDb> {
|
|
|
2338
2369
|
}
|
|
2339
2370
|
}
|
|
2340
2371
|
|
|
2341
|
-
private
|
|
2372
|
+
private shouldUseRecoveryRetryDelay(error?: SyncError): boolean {
|
|
2373
|
+
if (!error || error.code !== 'NETWORK_ERROR') return false;
|
|
2374
|
+
if (this.state.pendingCount > 0) return false;
|
|
2375
|
+
if (this.state.lastSyncAt === null) return false;
|
|
2376
|
+
return Date.now() - this.state.lastSyncAt <= RECOVERY_RETRY_WINDOW_MS;
|
|
2377
|
+
}
|
|
2378
|
+
|
|
2379
|
+
private scheduleRetry(error?: SyncError): void {
|
|
2342
2380
|
if (this.retryTimeoutId) {
|
|
2343
2381
|
clearTimeout(this.retryTimeoutId);
|
|
2344
2382
|
}
|
|
2345
2383
|
|
|
2346
|
-
const
|
|
2384
|
+
const attemptIndex = Math.max(0, this.state.retryCount - 1);
|
|
2385
|
+
const delay = this.shouldUseRecoveryRetryDelay(error)
|
|
2386
|
+
? calculateRecoveryRetryDelay(attemptIndex)
|
|
2387
|
+
: calculateRetryDelay(attemptIndex);
|
|
2347
2388
|
if (this.state.pendingCount > 0) {
|
|
2348
2389
|
countSyncMetric('sync.outbox.retry_count', 1, {
|
|
2349
2390
|
attributes: {
|
|
@@ -2524,9 +2565,14 @@ export class SyncEngine<DB extends SyncClientDb = SyncClientDb> {
|
|
|
2524
2565
|
fallbackReason: null,
|
|
2525
2566
|
});
|
|
2526
2567
|
this.stopFallbackPolling();
|
|
2527
|
-
this.triggerSyncInBackground(undefined, 'realtime connected state');
|
|
2528
2568
|
if (wasConnectedBefore) {
|
|
2569
|
+
this.scheduleRealtimeReconnectSync();
|
|
2529
2570
|
this.scheduleRealtimeReconnectCatchupSync();
|
|
2571
|
+
} else {
|
|
2572
|
+
this.triggerSyncInBackground(
|
|
2573
|
+
undefined,
|
|
2574
|
+
'realtime connected state'
|
|
2575
|
+
);
|
|
2530
2576
|
}
|
|
2531
2577
|
break;
|
|
2532
2578
|
}
|
|
@@ -2555,6 +2601,10 @@ export class SyncEngine<DB extends SyncClientDb = SyncClientDb> {
|
|
|
2555
2601
|
clearTimeout(this.realtimeCatchupTimeoutId);
|
|
2556
2602
|
this.realtimeCatchupTimeoutId = null;
|
|
2557
2603
|
}
|
|
2604
|
+
if (this.realtimeReconnectSyncTimeoutId) {
|
|
2605
|
+
clearTimeout(this.realtimeReconnectSyncTimeoutId);
|
|
2606
|
+
this.realtimeReconnectSyncTimeoutId = null;
|
|
2607
|
+
}
|
|
2558
2608
|
if (this.realtimePresenceUnsub) {
|
|
2559
2609
|
this.realtimePresenceUnsub();
|
|
2560
2610
|
this.realtimePresenceUnsub = null;
|
|
@@ -2575,6 +2625,11 @@ export class SyncEngine<DB extends SyncClientDb = SyncClientDb> {
|
|
|
2575
2625
|
clearTimeout(this.realtimeCatchupTimeoutId);
|
|
2576
2626
|
}
|
|
2577
2627
|
|
|
2628
|
+
const jitterMs = calculateDeterministicClientJitter(
|
|
2629
|
+
this.config.clientId ?? '',
|
|
2630
|
+
REALTIME_RECONNECT_SYNC_JITTER_MS
|
|
2631
|
+
);
|
|
2632
|
+
|
|
2578
2633
|
this.realtimeCatchupTimeoutId = setTimeout(() => {
|
|
2579
2634
|
this.realtimeCatchupTimeoutId = null;
|
|
2580
2635
|
|
|
@@ -2582,7 +2637,27 @@ export class SyncEngine<DB extends SyncClientDb = SyncClientDb> {
|
|
|
2582
2637
|
if (this.state.connectionState !== 'connected') return;
|
|
2583
2638
|
|
|
2584
2639
|
this.triggerSyncInBackground(undefined, 'realtime reconnect catchup');
|
|
2585
|
-
}, REALTIME_RECONNECT_CATCHUP_DELAY_MS);
|
|
2640
|
+
}, REALTIME_RECONNECT_CATCHUP_DELAY_MS + jitterMs);
|
|
2641
|
+
}
|
|
2642
|
+
|
|
2643
|
+
private scheduleRealtimeReconnectSync(): void {
|
|
2644
|
+
if (this.realtimeReconnectSyncTimeoutId) {
|
|
2645
|
+
clearTimeout(this.realtimeReconnectSyncTimeoutId);
|
|
2646
|
+
}
|
|
2647
|
+
|
|
2648
|
+
const jitterMs = calculateDeterministicClientJitter(
|
|
2649
|
+
this.config.clientId ?? '',
|
|
2650
|
+
REALTIME_RECONNECT_SYNC_JITTER_MS
|
|
2651
|
+
);
|
|
2652
|
+
|
|
2653
|
+
this.realtimeReconnectSyncTimeoutId = setTimeout(() => {
|
|
2654
|
+
this.realtimeReconnectSyncTimeoutId = null;
|
|
2655
|
+
|
|
2656
|
+
if (this.isDestroyed || !this.isEnabled()) return;
|
|
2657
|
+
if (this.state.connectionState !== 'connected') return;
|
|
2658
|
+
|
|
2659
|
+
this.triggerSyncInBackground(undefined, 'realtime connected state');
|
|
2660
|
+
}, jitterMs);
|
|
2586
2661
|
}
|
|
2587
2662
|
|
|
2588
2663
|
private startFallbackPolling(): void {
|
package/src/pull-engine.test.ts
CHANGED
|
@@ -133,7 +133,7 @@ describe('applyPullResponse chunk streaming', () => {
|
|
|
133
133
|
id: 'chunk-1',
|
|
134
134
|
byteLength: compressed.length,
|
|
135
135
|
sha256: '',
|
|
136
|
-
encoding: 'json-row-frame-
|
|
136
|
+
encoding: 'json-row-batch-frame-v2',
|
|
137
137
|
compression: 'gzip',
|
|
138
138
|
},
|
|
139
139
|
],
|
|
@@ -258,14 +258,14 @@ describe('applyPullResponse chunk streaming', () => {
|
|
|
258
258
|
id: 'chunk-1',
|
|
259
259
|
byteLength: firstChunk.length,
|
|
260
260
|
sha256: '',
|
|
261
|
-
encoding: 'json-row-frame-
|
|
261
|
+
encoding: 'json-row-batch-frame-v2',
|
|
262
262
|
compression: 'gzip',
|
|
263
263
|
},
|
|
264
264
|
{
|
|
265
265
|
id: 'chunk-2',
|
|
266
266
|
byteLength: secondChunk.length,
|
|
267
267
|
sha256: '',
|
|
268
|
-
encoding: 'json-row-frame-
|
|
268
|
+
encoding: 'json-row-batch-frame-v2',
|
|
269
269
|
compression: 'gzip',
|
|
270
270
|
},
|
|
271
271
|
],
|
|
@@ -374,14 +374,14 @@ describe('applyPullResponse chunk streaming', () => {
|
|
|
374
374
|
id: 'chunk-1',
|
|
375
375
|
byteLength: firstChunk.length,
|
|
376
376
|
sha256: '',
|
|
377
|
-
encoding: 'json-row-frame-
|
|
377
|
+
encoding: 'json-row-batch-frame-v2',
|
|
378
378
|
compression: 'gzip',
|
|
379
379
|
},
|
|
380
380
|
{
|
|
381
381
|
id: 'chunk-2',
|
|
382
382
|
byteLength: secondChunk.length,
|
|
383
383
|
sha256: '',
|
|
384
|
-
encoding: 'json-row-frame-
|
|
384
|
+
encoding: 'json-row-batch-frame-v2',
|
|
385
385
|
compression: 'gzip',
|
|
386
386
|
},
|
|
387
387
|
],
|
|
@@ -497,7 +497,7 @@ describe('applyPullResponse chunk streaming', () => {
|
|
|
497
497
|
id: 'chunk-1',
|
|
498
498
|
byteLength: chunk.length,
|
|
499
499
|
sha256: 'deadbeef',
|
|
500
|
-
encoding: 'json-row-frame-
|
|
500
|
+
encoding: 'json-row-batch-frame-v2',
|
|
501
501
|
compression: 'gzip',
|
|
502
502
|
},
|
|
503
503
|
],
|
|
@@ -592,7 +592,7 @@ describe('applyPullResponse chunk streaming', () => {
|
|
|
592
592
|
id: 'chunk-1',
|
|
593
593
|
byteLength: chunk.length,
|
|
594
594
|
sha256: 'expected-hash',
|
|
595
|
-
encoding: 'json-row-frame-
|
|
595
|
+
encoding: 'json-row-batch-frame-v2',
|
|
596
596
|
compression: 'gzip',
|
|
597
597
|
},
|
|
598
598
|
],
|
|
@@ -700,14 +700,14 @@ describe('applyPullResponse chunk streaming', () => {
|
|
|
700
700
|
id: 'chunk-1',
|
|
701
701
|
byteLength: firstChunk.length,
|
|
702
702
|
sha256: 'hash-1',
|
|
703
|
-
encoding: 'json-row-frame-
|
|
703
|
+
encoding: 'json-row-batch-frame-v2',
|
|
704
704
|
compression: 'gzip',
|
|
705
705
|
},
|
|
706
706
|
{
|
|
707
707
|
id: 'chunk-2',
|
|
708
708
|
byteLength: secondChunk.length,
|
|
709
709
|
sha256: 'hash-2',
|
|
710
|
-
encoding: 'json-row-frame-
|
|
710
|
+
encoding: 'json-row-batch-frame-v2',
|
|
711
711
|
compression: 'gzip',
|
|
712
712
|
},
|
|
713
713
|
],
|
|
@@ -804,7 +804,7 @@ describe('applyPullResponse chunk streaming', () => {
|
|
|
804
804
|
id: 'chunk-1',
|
|
805
805
|
byteLength: chunk.length,
|
|
806
806
|
sha256: '',
|
|
807
|
-
encoding: 'json-row-frame-
|
|
807
|
+
encoding: 'json-row-batch-frame-v2',
|
|
808
808
|
compression: 'gzip',
|
|
809
809
|
},
|
|
810
810
|
],
|