centrifuge 5.1.1 → 5.2.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/build/fossil.d.ts +6 -0
- package/build/index.js +200 -0
- package/build/index.mjs +200 -0
- package/build/protobuf/fossil.d.ts +6 -0
- package/build/protobuf/index.js +239 -0
- package/build/protobuf/index.mjs +239 -0
- package/build/protobuf/subscription.d.ts +3 -0
- package/build/protobuf/types.d.ts +2 -0
- package/build/subscription.d.ts +3 -0
- package/build/types.d.ts +2 -0
- package/dist/centrifuge.js +6 -5
- package/dist/centrifuge.js.map +4 -4
- package/dist/centrifuge.protobuf.js +5 -4
- package/dist/centrifuge.protobuf.js.map +4 -4
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -611,6 +611,9 @@ class Subscription extends EventEmitter$1 {
|
|
|
611
611
|
this._promiseId = 0;
|
|
612
612
|
this._inflight = false;
|
|
613
613
|
this._refreshTimeout = null;
|
|
614
|
+
this._delta = '';
|
|
615
|
+
this._delta_negotiated = false;
|
|
616
|
+
this._prevValue = null;
|
|
614
617
|
this._setOptions(options);
|
|
615
618
|
// @ts-ignore – we are hiding some symbols from public API autocompletion.
|
|
616
619
|
if (this._centrifuge._debugEnabled) {
|
|
@@ -755,6 +758,12 @@ class Subscription extends EventEmitter$1 {
|
|
|
755
758
|
this._offset = result.offset || 0;
|
|
756
759
|
this._epoch = result.epoch || '';
|
|
757
760
|
}
|
|
761
|
+
if (result.delta) {
|
|
762
|
+
this._delta_negotiated = true;
|
|
763
|
+
}
|
|
764
|
+
else {
|
|
765
|
+
this._delta_negotiated = false;
|
|
766
|
+
}
|
|
758
767
|
this._setState(exports.SubscriptionState.Subscribed);
|
|
759
768
|
// @ts-ignore – we are hiding some methods from public API autocompletion.
|
|
760
769
|
const ctx = this._centrifuge._getSubscribeContext(this.channel, result);
|
|
@@ -894,6 +903,9 @@ class Subscription extends EventEmitter$1 {
|
|
|
894
903
|
req.epoch = epoch;
|
|
895
904
|
}
|
|
896
905
|
}
|
|
906
|
+
if (this._delta) {
|
|
907
|
+
req.delta = this._delta;
|
|
908
|
+
}
|
|
897
909
|
const cmd = { subscribe: req };
|
|
898
910
|
this._inflight = true;
|
|
899
911
|
// @ts-ignore – we are hiding some symbols from public API autocompletion.
|
|
@@ -957,6 +969,12 @@ class Subscription extends EventEmitter$1 {
|
|
|
957
969
|
this._rejectPromises({ code: exports.errorCodes.subscriptionUnsubscribed, message: this.state });
|
|
958
970
|
}
|
|
959
971
|
_handlePublication(pub) {
|
|
972
|
+
if (this._delta && this._delta_negotiated) {
|
|
973
|
+
// @ts-ignore – we are hiding some methods from public API autocompletion.
|
|
974
|
+
const { newData, newPrevValue } = this._centrifuge._codec.applyDeltaIfNeeded(pub, this._prevValue);
|
|
975
|
+
pub.data = newData;
|
|
976
|
+
this._prevValue = newPrevValue;
|
|
977
|
+
}
|
|
960
978
|
// @ts-ignore – we are hiding some methods from public API autocompletion.
|
|
961
979
|
const ctx = this._centrifuge._getPublicationContext(this.channel, pub);
|
|
962
980
|
this.emit('publication', ctx);
|
|
@@ -1070,6 +1088,12 @@ class Subscription extends EventEmitter$1 {
|
|
|
1070
1088
|
if (options.joinLeave === true) {
|
|
1071
1089
|
this._joinLeave = true;
|
|
1072
1090
|
}
|
|
1091
|
+
if (options.delta) {
|
|
1092
|
+
if (options.delta !== 'fossil') {
|
|
1093
|
+
throw new Error('unsupported delta format');
|
|
1094
|
+
}
|
|
1095
|
+
this._delta = options.delta;
|
|
1096
|
+
}
|
|
1073
1097
|
}
|
|
1074
1098
|
_getOffset() {
|
|
1075
1099
|
const offset = this._offset;
|
|
@@ -1777,6 +1801,167 @@ class WebtransportTransport {
|
|
|
1777
1801
|
}
|
|
1778
1802
|
}
|
|
1779
1803
|
|
|
1804
|
+
/*
|
|
1805
|
+
Copyright 2014-2024 Dmitry Chestnykh (JavaScript port)
|
|
1806
|
+
Copyright 2007 D. Richard Hipp (original C version)
|
|
1807
|
+
|
|
1808
|
+
Fossil SCM delta compression algorithm, this is only the applyDelta part extracted
|
|
1809
|
+
from https://github.com/dchest/fossil-delta-js. The code was slightly modified
|
|
1810
|
+
to strip unnecessary parts. The copyright on top of this file is from the original
|
|
1811
|
+
repo on Github licensed under Simplified BSD License.
|
|
1812
|
+
*/
|
|
1813
|
+
const zValue = [
|
|
1814
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
1815
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
1816
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1,
|
|
1817
|
+
-1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
|
|
1818
|
+
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, 36, -1, 37,
|
|
1819
|
+
38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
|
|
1820
|
+
57, 58, 59, 60, 61, 62, -1, -1, -1, 63, -1,
|
|
1821
|
+
];
|
|
1822
|
+
// Reader reads bytes, chars, ints from array.
|
|
1823
|
+
class Reader {
|
|
1824
|
+
constructor(array) {
|
|
1825
|
+
this.a = array; // source array
|
|
1826
|
+
this.pos = 0; // current position in array
|
|
1827
|
+
}
|
|
1828
|
+
haveBytes() {
|
|
1829
|
+
return this.pos < this.a.length;
|
|
1830
|
+
}
|
|
1831
|
+
getByte() {
|
|
1832
|
+
const b = this.a[this.pos];
|
|
1833
|
+
this.pos++;
|
|
1834
|
+
if (this.pos > this.a.length)
|
|
1835
|
+
throw new RangeError("out of bounds");
|
|
1836
|
+
return b;
|
|
1837
|
+
}
|
|
1838
|
+
getChar() {
|
|
1839
|
+
return String.fromCharCode(this.getByte());
|
|
1840
|
+
}
|
|
1841
|
+
// Read base64-encoded unsigned integer.
|
|
1842
|
+
getInt() {
|
|
1843
|
+
let v = 0;
|
|
1844
|
+
let c;
|
|
1845
|
+
while (this.haveBytes() && (c = zValue[0x7f & this.getByte()]) >= 0) {
|
|
1846
|
+
v = (v << 6) + c;
|
|
1847
|
+
}
|
|
1848
|
+
this.pos--;
|
|
1849
|
+
return v >>> 0;
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
// Write writes an array.
|
|
1853
|
+
class Writer {
|
|
1854
|
+
constructor() {
|
|
1855
|
+
this.a = [];
|
|
1856
|
+
}
|
|
1857
|
+
toByteArray(sourceType) {
|
|
1858
|
+
if (Array.isArray(sourceType)) {
|
|
1859
|
+
return this.a;
|
|
1860
|
+
}
|
|
1861
|
+
return new Uint8Array(this.a);
|
|
1862
|
+
}
|
|
1863
|
+
// Copy from array at start to end.
|
|
1864
|
+
putArray(a, start, end) {
|
|
1865
|
+
this.a.push(...a.slice(start, end));
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
// Return a 32-bit checksum of the array.
|
|
1869
|
+
function checksum(arr) {
|
|
1870
|
+
let sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0, z = 0, N = arr.length;
|
|
1871
|
+
//TODO measure if this unrolling is helpful.
|
|
1872
|
+
while (N >= 16) {
|
|
1873
|
+
sum0 = (sum0 + arr[z + 0]) | 0;
|
|
1874
|
+
sum1 = (sum1 + arr[z + 1]) | 0;
|
|
1875
|
+
sum2 = (sum2 + arr[z + 2]) | 0;
|
|
1876
|
+
sum3 = (sum3 + arr[z + 3]) | 0;
|
|
1877
|
+
sum0 = (sum0 + arr[z + 4]) | 0;
|
|
1878
|
+
sum1 = (sum1 + arr[z + 5]) | 0;
|
|
1879
|
+
sum2 = (sum2 + arr[z + 6]) | 0;
|
|
1880
|
+
sum3 = (sum3 + arr[z + 7]) | 0;
|
|
1881
|
+
sum0 = (sum0 + arr[z + 8]) | 0;
|
|
1882
|
+
sum1 = (sum1 + arr[z + 9]) | 0;
|
|
1883
|
+
sum2 = (sum2 + arr[z + 10]) | 0;
|
|
1884
|
+
sum3 = (sum3 + arr[z + 11]) | 0;
|
|
1885
|
+
sum0 = (sum0 + arr[z + 12]) | 0;
|
|
1886
|
+
sum1 = (sum1 + arr[z + 13]) | 0;
|
|
1887
|
+
sum2 = (sum2 + arr[z + 14]) | 0;
|
|
1888
|
+
sum3 = (sum3 + arr[z + 15]) | 0;
|
|
1889
|
+
z += 16;
|
|
1890
|
+
N -= 16;
|
|
1891
|
+
}
|
|
1892
|
+
while (N >= 4) {
|
|
1893
|
+
sum0 = (sum0 + arr[z + 0]) | 0;
|
|
1894
|
+
sum1 = (sum1 + arr[z + 1]) | 0;
|
|
1895
|
+
sum2 = (sum2 + arr[z + 2]) | 0;
|
|
1896
|
+
sum3 = (sum3 + arr[z + 3]) | 0;
|
|
1897
|
+
z += 4;
|
|
1898
|
+
N -= 4;
|
|
1899
|
+
}
|
|
1900
|
+
sum3 = (((((sum3 + (sum2 << 8)) | 0) + (sum1 << 16)) | 0) + (sum0 << 24)) | 0;
|
|
1901
|
+
switch (N) {
|
|
1902
|
+
//@ts-ignore fallthrough is needed.
|
|
1903
|
+
case 3:
|
|
1904
|
+
sum3 = (sum3 + (arr[z + 2] << 8)) | 0; /* falls through */
|
|
1905
|
+
//@ts-ignore fallthrough is needed.
|
|
1906
|
+
case 2:
|
|
1907
|
+
sum3 = (sum3 + (arr[z + 1] << 16)) | 0; /* falls through */
|
|
1908
|
+
case 1:
|
|
1909
|
+
sum3 = (sum3 + (arr[z + 0] << 24)) | 0; /* falls through */
|
|
1910
|
+
}
|
|
1911
|
+
return sum3 >>> 0;
|
|
1912
|
+
}
|
|
1913
|
+
/**
|
|
1914
|
+
* Apply a delta byte array to a source byte array, returning the target byte array.
|
|
1915
|
+
*/
|
|
1916
|
+
function applyDelta(source, delta) {
|
|
1917
|
+
let total = 0;
|
|
1918
|
+
const zDelta = new Reader(delta);
|
|
1919
|
+
const lenSrc = source.length;
|
|
1920
|
+
const lenDelta = delta.length;
|
|
1921
|
+
const limit = zDelta.getInt();
|
|
1922
|
+
if (zDelta.getChar() !== "\n")
|
|
1923
|
+
throw new Error("size integer not terminated by '\\n'");
|
|
1924
|
+
const zOut = new Writer();
|
|
1925
|
+
while (zDelta.haveBytes()) {
|
|
1926
|
+
const cnt = zDelta.getInt();
|
|
1927
|
+
let ofst;
|
|
1928
|
+
switch (zDelta.getChar()) {
|
|
1929
|
+
case "@":
|
|
1930
|
+
ofst = zDelta.getInt();
|
|
1931
|
+
if (zDelta.haveBytes() && zDelta.getChar() !== ",")
|
|
1932
|
+
throw new Error("copy command not terminated by ','");
|
|
1933
|
+
total += cnt;
|
|
1934
|
+
if (total > limit)
|
|
1935
|
+
throw new Error("copy exceeds output file size");
|
|
1936
|
+
if (ofst + cnt > lenSrc)
|
|
1937
|
+
throw new Error("copy extends past end of input");
|
|
1938
|
+
zOut.putArray(source, ofst, ofst + cnt);
|
|
1939
|
+
break;
|
|
1940
|
+
case ":":
|
|
1941
|
+
total += cnt;
|
|
1942
|
+
if (total > limit)
|
|
1943
|
+
throw new Error("insert command gives an output larger than predicted");
|
|
1944
|
+
if (cnt > lenDelta)
|
|
1945
|
+
throw new Error("insert count exceeds size of delta");
|
|
1946
|
+
zOut.putArray(zDelta.a, zDelta.pos, zDelta.pos + cnt);
|
|
1947
|
+
zDelta.pos += cnt;
|
|
1948
|
+
break;
|
|
1949
|
+
case ";":
|
|
1950
|
+
{
|
|
1951
|
+
const out = zOut.toByteArray(source);
|
|
1952
|
+
if (cnt !== checksum(out))
|
|
1953
|
+
throw new Error("bad checksum");
|
|
1954
|
+
if (total !== limit)
|
|
1955
|
+
throw new Error("generated size does not match predicted size");
|
|
1956
|
+
return out;
|
|
1957
|
+
}
|
|
1958
|
+
default:
|
|
1959
|
+
throw new Error("unknown delta operator");
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
throw new Error("unterminated delta");
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1780
1965
|
/** @internal */
|
|
1781
1966
|
class JsonCodec {
|
|
1782
1967
|
name() {
|
|
@@ -1788,6 +1973,21 @@ class JsonCodec {
|
|
|
1788
1973
|
decodeReplies(data) {
|
|
1789
1974
|
return data.trim().split('\n').map(r => JSON.parse(r));
|
|
1790
1975
|
}
|
|
1976
|
+
applyDeltaIfNeeded(pub, prevValue) {
|
|
1977
|
+
let newData, newPrevValue;
|
|
1978
|
+
if (pub.delta) {
|
|
1979
|
+
// JSON string delta.
|
|
1980
|
+
const valueArray = applyDelta(prevValue, new TextEncoder().encode(pub.data));
|
|
1981
|
+
newData = JSON.parse(new TextDecoder().decode(valueArray));
|
|
1982
|
+
newPrevValue = valueArray;
|
|
1983
|
+
}
|
|
1984
|
+
else {
|
|
1985
|
+
// Full data as JSON string.
|
|
1986
|
+
newData = JSON.parse(pub.data);
|
|
1987
|
+
newPrevValue = new TextEncoder().encode(pub.data);
|
|
1988
|
+
}
|
|
1989
|
+
return { newData, newPrevValue };
|
|
1990
|
+
}
|
|
1791
1991
|
}
|
|
1792
1992
|
|
|
1793
1993
|
const defaults = {
|
package/build/index.mjs
CHANGED
|
@@ -609,6 +609,9 @@ class Subscription extends EventEmitter$1 {
|
|
|
609
609
|
this._promiseId = 0;
|
|
610
610
|
this._inflight = false;
|
|
611
611
|
this._refreshTimeout = null;
|
|
612
|
+
this._delta = '';
|
|
613
|
+
this._delta_negotiated = false;
|
|
614
|
+
this._prevValue = null;
|
|
612
615
|
this._setOptions(options);
|
|
613
616
|
// @ts-ignore – we are hiding some symbols from public API autocompletion.
|
|
614
617
|
if (this._centrifuge._debugEnabled) {
|
|
@@ -753,6 +756,12 @@ class Subscription extends EventEmitter$1 {
|
|
|
753
756
|
this._offset = result.offset || 0;
|
|
754
757
|
this._epoch = result.epoch || '';
|
|
755
758
|
}
|
|
759
|
+
if (result.delta) {
|
|
760
|
+
this._delta_negotiated = true;
|
|
761
|
+
}
|
|
762
|
+
else {
|
|
763
|
+
this._delta_negotiated = false;
|
|
764
|
+
}
|
|
756
765
|
this._setState(SubscriptionState.Subscribed);
|
|
757
766
|
// @ts-ignore – we are hiding some methods from public API autocompletion.
|
|
758
767
|
const ctx = this._centrifuge._getSubscribeContext(this.channel, result);
|
|
@@ -892,6 +901,9 @@ class Subscription extends EventEmitter$1 {
|
|
|
892
901
|
req.epoch = epoch;
|
|
893
902
|
}
|
|
894
903
|
}
|
|
904
|
+
if (this._delta) {
|
|
905
|
+
req.delta = this._delta;
|
|
906
|
+
}
|
|
895
907
|
const cmd = { subscribe: req };
|
|
896
908
|
this._inflight = true;
|
|
897
909
|
// @ts-ignore – we are hiding some symbols from public API autocompletion.
|
|
@@ -955,6 +967,12 @@ class Subscription extends EventEmitter$1 {
|
|
|
955
967
|
this._rejectPromises({ code: errorCodes.subscriptionUnsubscribed, message: this.state });
|
|
956
968
|
}
|
|
957
969
|
_handlePublication(pub) {
|
|
970
|
+
if (this._delta && this._delta_negotiated) {
|
|
971
|
+
// @ts-ignore – we are hiding some methods from public API autocompletion.
|
|
972
|
+
const { newData, newPrevValue } = this._centrifuge._codec.applyDeltaIfNeeded(pub, this._prevValue);
|
|
973
|
+
pub.data = newData;
|
|
974
|
+
this._prevValue = newPrevValue;
|
|
975
|
+
}
|
|
958
976
|
// @ts-ignore – we are hiding some methods from public API autocompletion.
|
|
959
977
|
const ctx = this._centrifuge._getPublicationContext(this.channel, pub);
|
|
960
978
|
this.emit('publication', ctx);
|
|
@@ -1068,6 +1086,12 @@ class Subscription extends EventEmitter$1 {
|
|
|
1068
1086
|
if (options.joinLeave === true) {
|
|
1069
1087
|
this._joinLeave = true;
|
|
1070
1088
|
}
|
|
1089
|
+
if (options.delta) {
|
|
1090
|
+
if (options.delta !== 'fossil') {
|
|
1091
|
+
throw new Error('unsupported delta format');
|
|
1092
|
+
}
|
|
1093
|
+
this._delta = options.delta;
|
|
1094
|
+
}
|
|
1071
1095
|
}
|
|
1072
1096
|
_getOffset() {
|
|
1073
1097
|
const offset = this._offset;
|
|
@@ -1775,6 +1799,167 @@ class WebtransportTransport {
|
|
|
1775
1799
|
}
|
|
1776
1800
|
}
|
|
1777
1801
|
|
|
1802
|
+
/*
|
|
1803
|
+
Copyright 2014-2024 Dmitry Chestnykh (JavaScript port)
|
|
1804
|
+
Copyright 2007 D. Richard Hipp (original C version)
|
|
1805
|
+
|
|
1806
|
+
Fossil SCM delta compression algorithm, this is only the applyDelta part extracted
|
|
1807
|
+
from https://github.com/dchest/fossil-delta-js. The code was slightly modified
|
|
1808
|
+
to strip unnecessary parts. The copyright on top of this file is from the original
|
|
1809
|
+
repo on Github licensed under Simplified BSD License.
|
|
1810
|
+
*/
|
|
1811
|
+
const zValue = [
|
|
1812
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
1813
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
1814
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1,
|
|
1815
|
+
-1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
|
|
1816
|
+
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, 36, -1, 37,
|
|
1817
|
+
38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
|
|
1818
|
+
57, 58, 59, 60, 61, 62, -1, -1, -1, 63, -1,
|
|
1819
|
+
];
|
|
1820
|
+
// Reader reads bytes, chars, ints from array.
|
|
1821
|
+
class Reader {
|
|
1822
|
+
constructor(array) {
|
|
1823
|
+
this.a = array; // source array
|
|
1824
|
+
this.pos = 0; // current position in array
|
|
1825
|
+
}
|
|
1826
|
+
haveBytes() {
|
|
1827
|
+
return this.pos < this.a.length;
|
|
1828
|
+
}
|
|
1829
|
+
getByte() {
|
|
1830
|
+
const b = this.a[this.pos];
|
|
1831
|
+
this.pos++;
|
|
1832
|
+
if (this.pos > this.a.length)
|
|
1833
|
+
throw new RangeError("out of bounds");
|
|
1834
|
+
return b;
|
|
1835
|
+
}
|
|
1836
|
+
getChar() {
|
|
1837
|
+
return String.fromCharCode(this.getByte());
|
|
1838
|
+
}
|
|
1839
|
+
// Read base64-encoded unsigned integer.
|
|
1840
|
+
getInt() {
|
|
1841
|
+
let v = 0;
|
|
1842
|
+
let c;
|
|
1843
|
+
while (this.haveBytes() && (c = zValue[0x7f & this.getByte()]) >= 0) {
|
|
1844
|
+
v = (v << 6) + c;
|
|
1845
|
+
}
|
|
1846
|
+
this.pos--;
|
|
1847
|
+
return v >>> 0;
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
// Write writes an array.
|
|
1851
|
+
class Writer {
|
|
1852
|
+
constructor() {
|
|
1853
|
+
this.a = [];
|
|
1854
|
+
}
|
|
1855
|
+
toByteArray(sourceType) {
|
|
1856
|
+
if (Array.isArray(sourceType)) {
|
|
1857
|
+
return this.a;
|
|
1858
|
+
}
|
|
1859
|
+
return new Uint8Array(this.a);
|
|
1860
|
+
}
|
|
1861
|
+
// Copy from array at start to end.
|
|
1862
|
+
putArray(a, start, end) {
|
|
1863
|
+
this.a.push(...a.slice(start, end));
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
// Return a 32-bit checksum of the array.
|
|
1867
|
+
function checksum(arr) {
|
|
1868
|
+
let sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0, z = 0, N = arr.length;
|
|
1869
|
+
//TODO measure if this unrolling is helpful.
|
|
1870
|
+
while (N >= 16) {
|
|
1871
|
+
sum0 = (sum0 + arr[z + 0]) | 0;
|
|
1872
|
+
sum1 = (sum1 + arr[z + 1]) | 0;
|
|
1873
|
+
sum2 = (sum2 + arr[z + 2]) | 0;
|
|
1874
|
+
sum3 = (sum3 + arr[z + 3]) | 0;
|
|
1875
|
+
sum0 = (sum0 + arr[z + 4]) | 0;
|
|
1876
|
+
sum1 = (sum1 + arr[z + 5]) | 0;
|
|
1877
|
+
sum2 = (sum2 + arr[z + 6]) | 0;
|
|
1878
|
+
sum3 = (sum3 + arr[z + 7]) | 0;
|
|
1879
|
+
sum0 = (sum0 + arr[z + 8]) | 0;
|
|
1880
|
+
sum1 = (sum1 + arr[z + 9]) | 0;
|
|
1881
|
+
sum2 = (sum2 + arr[z + 10]) | 0;
|
|
1882
|
+
sum3 = (sum3 + arr[z + 11]) | 0;
|
|
1883
|
+
sum0 = (sum0 + arr[z + 12]) | 0;
|
|
1884
|
+
sum1 = (sum1 + arr[z + 13]) | 0;
|
|
1885
|
+
sum2 = (sum2 + arr[z + 14]) | 0;
|
|
1886
|
+
sum3 = (sum3 + arr[z + 15]) | 0;
|
|
1887
|
+
z += 16;
|
|
1888
|
+
N -= 16;
|
|
1889
|
+
}
|
|
1890
|
+
while (N >= 4) {
|
|
1891
|
+
sum0 = (sum0 + arr[z + 0]) | 0;
|
|
1892
|
+
sum1 = (sum1 + arr[z + 1]) | 0;
|
|
1893
|
+
sum2 = (sum2 + arr[z + 2]) | 0;
|
|
1894
|
+
sum3 = (sum3 + arr[z + 3]) | 0;
|
|
1895
|
+
z += 4;
|
|
1896
|
+
N -= 4;
|
|
1897
|
+
}
|
|
1898
|
+
sum3 = (((((sum3 + (sum2 << 8)) | 0) + (sum1 << 16)) | 0) + (sum0 << 24)) | 0;
|
|
1899
|
+
switch (N) {
|
|
1900
|
+
//@ts-ignore fallthrough is needed.
|
|
1901
|
+
case 3:
|
|
1902
|
+
sum3 = (sum3 + (arr[z + 2] << 8)) | 0; /* falls through */
|
|
1903
|
+
//@ts-ignore fallthrough is needed.
|
|
1904
|
+
case 2:
|
|
1905
|
+
sum3 = (sum3 + (arr[z + 1] << 16)) | 0; /* falls through */
|
|
1906
|
+
case 1:
|
|
1907
|
+
sum3 = (sum3 + (arr[z + 0] << 24)) | 0; /* falls through */
|
|
1908
|
+
}
|
|
1909
|
+
return sum3 >>> 0;
|
|
1910
|
+
}
|
|
1911
|
+
/**
|
|
1912
|
+
* Apply a delta byte array to a source byte array, returning the target byte array.
|
|
1913
|
+
*/
|
|
1914
|
+
function applyDelta(source, delta) {
|
|
1915
|
+
let total = 0;
|
|
1916
|
+
const zDelta = new Reader(delta);
|
|
1917
|
+
const lenSrc = source.length;
|
|
1918
|
+
const lenDelta = delta.length;
|
|
1919
|
+
const limit = zDelta.getInt();
|
|
1920
|
+
if (zDelta.getChar() !== "\n")
|
|
1921
|
+
throw new Error("size integer not terminated by '\\n'");
|
|
1922
|
+
const zOut = new Writer();
|
|
1923
|
+
while (zDelta.haveBytes()) {
|
|
1924
|
+
const cnt = zDelta.getInt();
|
|
1925
|
+
let ofst;
|
|
1926
|
+
switch (zDelta.getChar()) {
|
|
1927
|
+
case "@":
|
|
1928
|
+
ofst = zDelta.getInt();
|
|
1929
|
+
if (zDelta.haveBytes() && zDelta.getChar() !== ",")
|
|
1930
|
+
throw new Error("copy command not terminated by ','");
|
|
1931
|
+
total += cnt;
|
|
1932
|
+
if (total > limit)
|
|
1933
|
+
throw new Error("copy exceeds output file size");
|
|
1934
|
+
if (ofst + cnt > lenSrc)
|
|
1935
|
+
throw new Error("copy extends past end of input");
|
|
1936
|
+
zOut.putArray(source, ofst, ofst + cnt);
|
|
1937
|
+
break;
|
|
1938
|
+
case ":":
|
|
1939
|
+
total += cnt;
|
|
1940
|
+
if (total > limit)
|
|
1941
|
+
throw new Error("insert command gives an output larger than predicted");
|
|
1942
|
+
if (cnt > lenDelta)
|
|
1943
|
+
throw new Error("insert count exceeds size of delta");
|
|
1944
|
+
zOut.putArray(zDelta.a, zDelta.pos, zDelta.pos + cnt);
|
|
1945
|
+
zDelta.pos += cnt;
|
|
1946
|
+
break;
|
|
1947
|
+
case ";":
|
|
1948
|
+
{
|
|
1949
|
+
const out = zOut.toByteArray(source);
|
|
1950
|
+
if (cnt !== checksum(out))
|
|
1951
|
+
throw new Error("bad checksum");
|
|
1952
|
+
if (total !== limit)
|
|
1953
|
+
throw new Error("generated size does not match predicted size");
|
|
1954
|
+
return out;
|
|
1955
|
+
}
|
|
1956
|
+
default:
|
|
1957
|
+
throw new Error("unknown delta operator");
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
throw new Error("unterminated delta");
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1778
1963
|
/** @internal */
|
|
1779
1964
|
class JsonCodec {
|
|
1780
1965
|
name() {
|
|
@@ -1786,6 +1971,21 @@ class JsonCodec {
|
|
|
1786
1971
|
decodeReplies(data) {
|
|
1787
1972
|
return data.trim().split('\n').map(r => JSON.parse(r));
|
|
1788
1973
|
}
|
|
1974
|
+
applyDeltaIfNeeded(pub, prevValue) {
|
|
1975
|
+
let newData, newPrevValue;
|
|
1976
|
+
if (pub.delta) {
|
|
1977
|
+
// JSON string delta.
|
|
1978
|
+
const valueArray = applyDelta(prevValue, new TextEncoder().encode(pub.data));
|
|
1979
|
+
newData = JSON.parse(new TextDecoder().decode(valueArray));
|
|
1980
|
+
newPrevValue = valueArray;
|
|
1981
|
+
}
|
|
1982
|
+
else {
|
|
1983
|
+
// Full data as JSON string.
|
|
1984
|
+
newData = JSON.parse(pub.data);
|
|
1985
|
+
newPrevValue = new TextEncoder().encode(pub.data);
|
|
1986
|
+
}
|
|
1987
|
+
return { newData, newPrevValue };
|
|
1988
|
+
}
|
|
1789
1989
|
}
|
|
1790
1990
|
|
|
1791
1991
|
const defaults = {
|