@nanolink/mirrors 1.1.75 → 1.1.76
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/README.md +40 -0
- package/dist/MirrorSync.d.ts +8 -0
- package/dist/MirrorSync.js +29 -1
- package/dist/MirrorSync.js.map +1 -1
- package/dist/data64.d.ts +24 -0
- package/dist/data64.js +71 -0
- package/dist/data64.js.map +1 -0
- package/dist/decoders.d.ts +11 -0
- package/dist/decoders.js +23 -0
- package/dist/decoders.js.map +1 -0
- package/dist/definitions/mirrors.d.ts +1 -0
- package/dist/definitions/mirrors.js +1 -0
- package/dist/definitions/mirrors.js.map +1 -1
- package/dist/definitions/opsubscriptions/index.d.ts +1 -0
- package/dist/definitions/opsubscriptions/index.js +1 -0
- package/dist/definitions/opsubscriptions/index.js.map +1 -1
- package/dist/definitions/opsubscriptions/triproutes.d.ts +1 -0
- package/dist/definitions/opsubscriptions/triproutes.js +12 -0
- package/dist/definitions/opsubscriptions/triproutes.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +11 -1
- package/dist/index.js.map +1 -1
- package/dist/triproute.d.ts +52 -0
- package/dist/triproute.js +135 -0
- package/dist/triproute.js.map +1 -0
- package/dist-compat/index.js +196 -2
- package/dist-compat/index.js.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.tripRouteKey = tripRouteKey;
|
|
4
|
+
exports.parseTripRouteKey = parseTripRouteKey;
|
|
5
|
+
exports.tripRoute = tripRoute;
|
|
6
|
+
exports.readVarint = readVarint;
|
|
7
|
+
exports.decodeTripRouteRecord = decodeTripRouteRecord;
|
|
8
|
+
const decoders_1 = require("./decoders");
|
|
9
|
+
const KEY = /^([^/]+)\/(-?\d+)\/(\d+)$/;
|
|
10
|
+
const ROUTE_SPEED_NONE = 65535;
|
|
11
|
+
const ROUTE_COORD_UNIT = 1e7;
|
|
12
|
+
const ROUTE_SPEED_UNIT = 10;
|
|
13
|
+
const HEX = '0123456789abcdef';
|
|
14
|
+
/** The mirror key of a chunk: `<vid>/<tripStart>/<chunk>`. */
|
|
15
|
+
function tripRouteKey(trackerVID, tripStart, chunk) {
|
|
16
|
+
return `${trackerVID}/${tripStart}/${chunk}`;
|
|
17
|
+
}
|
|
18
|
+
/** The parts of a mirror key, or null when it is not a trip route key. */
|
|
19
|
+
function parseTripRouteKey(id) {
|
|
20
|
+
const m = KEY.exec(id);
|
|
21
|
+
if (!m)
|
|
22
|
+
return null;
|
|
23
|
+
return { trackerVID: m[1], tripStart: Number(m[2]), chunk: Number(m[3]) };
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The route of one trip: the points of its contiguous chunks from 0, in
|
|
27
|
+
* order, stopping at the first chunk the mirror does not hold.
|
|
28
|
+
*/
|
|
29
|
+
function tripRoute(mirror, trackerVID, tripStart) {
|
|
30
|
+
const points = [];
|
|
31
|
+
for (let chunk = 0;; chunk++) {
|
|
32
|
+
const item = mirror.get(tripRouteKey(trackerVID, tripStart, chunk));
|
|
33
|
+
if (!item || !Array.isArray(item.points))
|
|
34
|
+
break;
|
|
35
|
+
for (const p of item.points)
|
|
36
|
+
points.push(p);
|
|
37
|
+
}
|
|
38
|
+
return points;
|
|
39
|
+
}
|
|
40
|
+
function hex(bytes, start, end) {
|
|
41
|
+
let s = '';
|
|
42
|
+
for (let i = start; i < end; i++)
|
|
43
|
+
s += HEX[bytes[i] >> 4] + HEX[bytes[i] & 15];
|
|
44
|
+
return s;
|
|
45
|
+
}
|
|
46
|
+
/** int64 LE as a number: two uint32 halves, lo + hi * 2^32 (hi signed). */
|
|
47
|
+
function int64(view, offset) {
|
|
48
|
+
return view.getInt32(offset + 4, true) * 4294967296 + view.getUint32(offset, true);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Reads a zigzag varint (Go's binary.Varint): LEB128 unsigned, then
|
|
52
|
+
* even -> n/2, odd -> -(n+1)/2.
|
|
53
|
+
*/
|
|
54
|
+
function readVarint(bytes, offset) {
|
|
55
|
+
let result = 0;
|
|
56
|
+
let scale = 1;
|
|
57
|
+
let at = offset;
|
|
58
|
+
for (;;) {
|
|
59
|
+
if (at >= bytes.length)
|
|
60
|
+
throw new Error('truncated statetriproute varint');
|
|
61
|
+
const byte = bytes[at++];
|
|
62
|
+
result += (byte & 0x7f) * scale;
|
|
63
|
+
if ((byte & 0x80) === 0)
|
|
64
|
+
break;
|
|
65
|
+
scale *= 128;
|
|
66
|
+
if (scale > Math.pow(2, 56))
|
|
67
|
+
throw new Error('statetriproute varint too long');
|
|
68
|
+
}
|
|
69
|
+
const signed = result % 2 === 0 ? result / 2 : -(result + 1) / 2;
|
|
70
|
+
return { value: signed, offset: at };
|
|
71
|
+
}
|
|
72
|
+
function routePoint(stamp, lon, lat, speed) {
|
|
73
|
+
return {
|
|
74
|
+
stamp,
|
|
75
|
+
longitude: lon / ROUTE_COORD_UNIT,
|
|
76
|
+
latitude: lat / ROUTE_COORD_UNIT,
|
|
77
|
+
speed: speed === ROUTE_SPEED_NONE ? null : speed / ROUTE_SPEED_UNIT,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Decodes a statetriproute record. The value is `[version: 12][count: u16]`
|
|
82
|
+
* and, with a count above 0, the first point absolute (stamp int64 LE,
|
|
83
|
+
* longitude and latitude int32 LE at 1e-7 degrees, speed uint16 LE at
|
|
84
|
+
* 0.1 km/h, 65535 for none) followed by every further point as four zigzag
|
|
85
|
+
* varints: the deltas of the stamp, the longitude, the latitude and the
|
|
86
|
+
* speed, in the same units. The key is `<vid>/<tripStart>/<chunk>`.
|
|
87
|
+
*/
|
|
88
|
+
function decodeTripRouteRecord(key, value) {
|
|
89
|
+
const parsed = parseTripRouteKey(key);
|
|
90
|
+
if (!parsed)
|
|
91
|
+
throw new Error(`invalid statetriproute key: ${key}`);
|
|
92
|
+
if (value.length < 14)
|
|
93
|
+
throw new Error(`statetriproute record too short: ${value.length}`);
|
|
94
|
+
const view = new DataView(value.buffer, value.byteOffset, value.byteLength);
|
|
95
|
+
const count = view.getUint16(12, true);
|
|
96
|
+
const points = [];
|
|
97
|
+
let offset = 14;
|
|
98
|
+
if (count > 0) {
|
|
99
|
+
if (value.length < 32)
|
|
100
|
+
throw new Error('truncated statetriproute first point');
|
|
101
|
+
let stamp = int64(view, 14);
|
|
102
|
+
let lon = view.getInt32(22, true);
|
|
103
|
+
let lat = view.getInt32(26, true);
|
|
104
|
+
let speed = view.getUint16(30, true);
|
|
105
|
+
points.push(routePoint(stamp, lon, lat, speed));
|
|
106
|
+
offset = 32;
|
|
107
|
+
for (let i = 1; i < count; i++) {
|
|
108
|
+
const dStamp = readVarint(value, offset);
|
|
109
|
+
const dLon = readVarint(value, dStamp.offset);
|
|
110
|
+
const dLat = readVarint(value, dLon.offset);
|
|
111
|
+
const dSpeed = readVarint(value, dLat.offset);
|
|
112
|
+
offset = dSpeed.offset;
|
|
113
|
+
stamp += dStamp.value;
|
|
114
|
+
lon += dLon.value;
|
|
115
|
+
lat += dLat.value;
|
|
116
|
+
speed += dSpeed.value;
|
|
117
|
+
if (speed < 0 || speed > ROUTE_SPEED_NONE)
|
|
118
|
+
throw new Error(`statetriproute point ${i} speed out of range`);
|
|
119
|
+
points.push(routePoint(stamp, lon, lat, speed));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (offset !== value.length)
|
|
123
|
+
throw new Error(`statetriproute has ${value.length - offset} trailing bytes`);
|
|
124
|
+
return {
|
|
125
|
+
id: key,
|
|
126
|
+
trackerVID: parsed.trackerVID,
|
|
127
|
+
tripStart: parsed.tripStart,
|
|
128
|
+
chunk: parsed.chunk,
|
|
129
|
+
points,
|
|
130
|
+
opVersion: hex(value, 0, 12),
|
|
131
|
+
deleted: false,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
(0, decoders_1.registerDecoder)('tripRoutes', decodeTripRouteRecord);
|
|
135
|
+
//# sourceMappingURL=triproute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"triproute.js","sourceRoot":"","sources":["../src/triproute.ts"],"names":[],"mappings":"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"}
|
package/dist-compat/index.js
CHANGED
|
@@ -71,13 +71,75 @@ __export(index_exports, {
|
|
|
71
71
|
SubscriptionClient: () => SubscriptionClient_default,
|
|
72
72
|
Subscriptions: () => Subscriptions,
|
|
73
73
|
TempSubscriptions: () => TempSubscriptions2,
|
|
74
|
+
decodeTripRouteRecord: () => decodeTripRouteRecord,
|
|
74
75
|
draftMirrors: () => draftMirrors,
|
|
75
|
-
exposedMirrors: () => exposedMirrors
|
|
76
|
+
exposedMirrors: () => exposedMirrors,
|
|
77
|
+
getDecoder: () => getDecoder,
|
|
78
|
+
parseTripRouteKey: () => parseTripRouteKey,
|
|
79
|
+
registerDecoder: () => registerDecoder,
|
|
80
|
+
tripRoute: () => tripRoute,
|
|
81
|
+
tripRouteKey: () => tripRouteKey
|
|
76
82
|
});
|
|
77
83
|
module.exports = __toCommonJS(index_exports);
|
|
78
84
|
|
|
79
85
|
// src/MirrorSync.ts
|
|
80
86
|
var import_eventemitter3 = __toESM(require("eventemitter3"));
|
|
87
|
+
|
|
88
|
+
// src/data64.ts
|
|
89
|
+
function base64ToBytes(data64) {
|
|
90
|
+
if (typeof Buffer !== "undefined" && typeof Buffer.from === "function") {
|
|
91
|
+
const buf = Buffer.from(data64, "base64");
|
|
92
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
93
|
+
}
|
|
94
|
+
if (typeof atob !== "function") throw new Error("data64: no base64 decoder available");
|
|
95
|
+
const binary = atob(data64);
|
|
96
|
+
const out = new Uint8Array(binary.length);
|
|
97
|
+
for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);
|
|
98
|
+
return out;
|
|
99
|
+
}
|
|
100
|
+
function utf8(bytes) {
|
|
101
|
+
if (typeof TextDecoder !== "undefined") return new TextDecoder().decode(bytes);
|
|
102
|
+
if (typeof Buffer !== "undefined") return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("utf8");
|
|
103
|
+
let s = "";
|
|
104
|
+
for (let i = 0; i < bytes.length; i++) s += String.fromCharCode(bytes[i]);
|
|
105
|
+
return s;
|
|
106
|
+
}
|
|
107
|
+
function readFrames(bytes) {
|
|
108
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
109
|
+
const frames = [];
|
|
110
|
+
let at = 0;
|
|
111
|
+
while (at < bytes.length) {
|
|
112
|
+
if (at + 2 > bytes.length) throw new Error(`data64: truncated key length at ${at}`);
|
|
113
|
+
const keyLength = view.getUint16(at, true);
|
|
114
|
+
at += 2;
|
|
115
|
+
if (at + keyLength + 2 > bytes.length) throw new Error(`data64: truncated key at ${at}`);
|
|
116
|
+
const key = utf8(bytes.subarray(at, at + keyLength));
|
|
117
|
+
at += keyLength;
|
|
118
|
+
const valueLength = view.getUint16(at, true);
|
|
119
|
+
at += 2;
|
|
120
|
+
if (at + valueLength > bytes.length) throw new Error(`data64: truncated value for '${key}' at ${at}`);
|
|
121
|
+
frames.push({ key, value: bytes.subarray(at, at + valueLength) });
|
|
122
|
+
at += valueLength;
|
|
123
|
+
}
|
|
124
|
+
return frames;
|
|
125
|
+
}
|
|
126
|
+
function decodeData64Frames(data64) {
|
|
127
|
+
return readFrames(base64ToBytes(data64));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/decoders.ts
|
|
131
|
+
var decoders = /* @__PURE__ */ new Map();
|
|
132
|
+
function registerDecoder(rootField, decoder) {
|
|
133
|
+
decoders.set(rootField, decoder);
|
|
134
|
+
}
|
|
135
|
+
function getDecoder(rootField) {
|
|
136
|
+
return decoders.get(rootField);
|
|
137
|
+
}
|
|
138
|
+
function decodeData64(data64, decoder) {
|
|
139
|
+
return decodeData64Frames(data64).map((f) => decoder(f.key, f.value));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// src/MirrorSync.ts
|
|
81
143
|
var MirrorSync = class extends import_eventemitter3.default {
|
|
82
144
|
constructor(client, options) {
|
|
83
145
|
super();
|
|
@@ -250,7 +312,11 @@ var MirrorSync = class extends import_eventemitter3.default {
|
|
|
250
312
|
break;
|
|
251
313
|
}
|
|
252
314
|
case "UPDATED" /* UPDATED */:
|
|
253
|
-
this.applyUpdated(msg.data);
|
|
315
|
+
if (msg.data !== void 0 && msg.data !== null) this.applyUpdated(msg.data);
|
|
316
|
+
if (typeof msg.data64 === "string") {
|
|
317
|
+
const items = this.decodeData64(firstKey, msg.data64);
|
|
318
|
+
if (items) this.applyUpdated(items);
|
|
319
|
+
}
|
|
254
320
|
break;
|
|
255
321
|
case "DELETED" /* DELETED */:
|
|
256
322
|
this.applyDeleted(msg.deleteId, msg.deleteVersion, msg.deleteOpVersion);
|
|
@@ -292,6 +358,26 @@ var MirrorSync = class extends import_eventemitter3.default {
|
|
|
292
358
|
this.subscribeInternal(this.currentVersion, this.currentOpVersion);
|
|
293
359
|
}, 0);
|
|
294
360
|
}
|
|
361
|
+
/**
|
|
362
|
+
* Decodes a `data64` frame through the decoder registered for the root
|
|
363
|
+
* field. No decoder, or a record that does not decode: emits 'error' and
|
|
364
|
+
* returns undefined so the frame is skipped; never throws.
|
|
365
|
+
*/
|
|
366
|
+
decodeData64(rootField, data64) {
|
|
367
|
+
const decoder = getDecoder(rootField);
|
|
368
|
+
if (!decoder) {
|
|
369
|
+
this.l("no data64 decoder", { rootField });
|
|
370
|
+
this.emit("error", new Error(`No data64 decoder registered for root field '${rootField}'`));
|
|
371
|
+
return void 0;
|
|
372
|
+
}
|
|
373
|
+
try {
|
|
374
|
+
return decodeData64(data64, decoder);
|
|
375
|
+
} catch (err) {
|
|
376
|
+
this.l("data64 decode failed", { rootField, err });
|
|
377
|
+
this.emit("error", err);
|
|
378
|
+
return void 0;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
295
381
|
normalizeItems(data) {
|
|
296
382
|
if (!data) return [];
|
|
297
383
|
return Array.isArray(data) ? data : [data];
|
|
@@ -2655,6 +2741,16 @@ var trackerState = `subscription trackerState($opVersion: String) {
|
|
|
2655
2741
|
}
|
|
2656
2742
|
}`;
|
|
2657
2743
|
|
|
2744
|
+
// src/definitions/opsubscriptions/triproutes.ts
|
|
2745
|
+
var tripRoutes = `subscription tripRoutes($opVersion: String, $trackerVIDs: [String!]) {
|
|
2746
|
+
tripRoutes(opversion: $opVersion, trackerVIDs: $trackerVIDs) {
|
|
2747
|
+
type
|
|
2748
|
+
data64
|
|
2749
|
+
deleteId
|
|
2750
|
+
deleteOpVersion
|
|
2751
|
+
}
|
|
2752
|
+
}`;
|
|
2753
|
+
|
|
2658
2754
|
// src/definitions/opsubscriptions/trips.ts
|
|
2659
2755
|
var trips2 = `subscription stateTrips($opVersion: String) {
|
|
2660
2756
|
stateTrips(opversion: $opVersion) {
|
|
@@ -2841,6 +2937,7 @@ var OpSubscriptions = {
|
|
|
2841
2937
|
stateLinks,
|
|
2842
2938
|
stateRefLinks,
|
|
2843
2939
|
trackerState,
|
|
2940
|
+
tripRoutes,
|
|
2844
2941
|
trips3: trips2
|
|
2845
2942
|
};
|
|
2846
2943
|
var RequiredMirrors = {
|
|
@@ -3203,6 +3300,103 @@ function draftMirrors() {
|
|
|
3203
3300
|
);
|
|
3204
3301
|
}
|
|
3205
3302
|
|
|
3303
|
+
// src/triproute.ts
|
|
3304
|
+
var KEY = /^([^/]+)\/(-?\d+)\/(\d+)$/;
|
|
3305
|
+
var ROUTE_SPEED_NONE = 65535;
|
|
3306
|
+
var ROUTE_COORD_UNIT = 1e7;
|
|
3307
|
+
var ROUTE_SPEED_UNIT = 10;
|
|
3308
|
+
var HEX = "0123456789abcdef";
|
|
3309
|
+
function tripRouteKey(trackerVID, tripStart, chunk) {
|
|
3310
|
+
return `${trackerVID}/${tripStart}/${chunk}`;
|
|
3311
|
+
}
|
|
3312
|
+
function parseTripRouteKey(id) {
|
|
3313
|
+
const m = KEY.exec(id);
|
|
3314
|
+
if (!m) return null;
|
|
3315
|
+
return { trackerVID: m[1], tripStart: Number(m[2]), chunk: Number(m[3]) };
|
|
3316
|
+
}
|
|
3317
|
+
function tripRoute(mirror, trackerVID, tripStart) {
|
|
3318
|
+
const points = [];
|
|
3319
|
+
for (let chunk = 0; ; chunk++) {
|
|
3320
|
+
const item = mirror.get(tripRouteKey(trackerVID, tripStart, chunk));
|
|
3321
|
+
if (!item || !Array.isArray(item.points)) break;
|
|
3322
|
+
for (const p of item.points) points.push(p);
|
|
3323
|
+
}
|
|
3324
|
+
return points;
|
|
3325
|
+
}
|
|
3326
|
+
function hex(bytes, start, end) {
|
|
3327
|
+
let s = "";
|
|
3328
|
+
for (let i = start; i < end; i++) s += HEX[bytes[i] >> 4] + HEX[bytes[i] & 15];
|
|
3329
|
+
return s;
|
|
3330
|
+
}
|
|
3331
|
+
function int64(view, offset) {
|
|
3332
|
+
return view.getInt32(offset + 4, true) * 4294967296 + view.getUint32(offset, true);
|
|
3333
|
+
}
|
|
3334
|
+
function readVarint(bytes, offset) {
|
|
3335
|
+
let result = 0;
|
|
3336
|
+
let scale = 1;
|
|
3337
|
+
let at = offset;
|
|
3338
|
+
for (; ; ) {
|
|
3339
|
+
if (at >= bytes.length) throw new Error("truncated statetriproute varint");
|
|
3340
|
+
const byte = bytes[at++];
|
|
3341
|
+
result += (byte & 127) * scale;
|
|
3342
|
+
if ((byte & 128) === 0) break;
|
|
3343
|
+
scale *= 128;
|
|
3344
|
+
if (scale > 2 ** 56) throw new Error("statetriproute varint too long");
|
|
3345
|
+
}
|
|
3346
|
+
const signed = result % 2 === 0 ? result / 2 : -(result + 1) / 2;
|
|
3347
|
+
return { value: signed, offset: at };
|
|
3348
|
+
}
|
|
3349
|
+
function routePoint(stamp, lon, lat, speed) {
|
|
3350
|
+
return {
|
|
3351
|
+
stamp,
|
|
3352
|
+
longitude: lon / ROUTE_COORD_UNIT,
|
|
3353
|
+
latitude: lat / ROUTE_COORD_UNIT,
|
|
3354
|
+
speed: speed === ROUTE_SPEED_NONE ? null : speed / ROUTE_SPEED_UNIT
|
|
3355
|
+
};
|
|
3356
|
+
}
|
|
3357
|
+
function decodeTripRouteRecord(key, value) {
|
|
3358
|
+
const parsed = parseTripRouteKey(key);
|
|
3359
|
+
if (!parsed) throw new Error(`invalid statetriproute key: ${key}`);
|
|
3360
|
+
if (value.length < 14) throw new Error(`statetriproute record too short: ${value.length}`);
|
|
3361
|
+
const view = new DataView(value.buffer, value.byteOffset, value.byteLength);
|
|
3362
|
+
const count = view.getUint16(12, true);
|
|
3363
|
+
const points = [];
|
|
3364
|
+
let offset = 14;
|
|
3365
|
+
if (count > 0) {
|
|
3366
|
+
if (value.length < 32) throw new Error("truncated statetriproute first point");
|
|
3367
|
+
let stamp = int64(view, 14);
|
|
3368
|
+
let lon = view.getInt32(22, true);
|
|
3369
|
+
let lat = view.getInt32(26, true);
|
|
3370
|
+
let speed = view.getUint16(30, true);
|
|
3371
|
+
points.push(routePoint(stamp, lon, lat, speed));
|
|
3372
|
+
offset = 32;
|
|
3373
|
+
for (let i = 1; i < count; i++) {
|
|
3374
|
+
const dStamp = readVarint(value, offset);
|
|
3375
|
+
const dLon = readVarint(value, dStamp.offset);
|
|
3376
|
+
const dLat = readVarint(value, dLon.offset);
|
|
3377
|
+
const dSpeed = readVarint(value, dLat.offset);
|
|
3378
|
+
offset = dSpeed.offset;
|
|
3379
|
+
stamp += dStamp.value;
|
|
3380
|
+
lon += dLon.value;
|
|
3381
|
+
lat += dLat.value;
|
|
3382
|
+
speed += dSpeed.value;
|
|
3383
|
+
if (speed < 0 || speed > ROUTE_SPEED_NONE) throw new Error(`statetriproute point ${i} speed out of range`);
|
|
3384
|
+
points.push(routePoint(stamp, lon, lat, speed));
|
|
3385
|
+
}
|
|
3386
|
+
}
|
|
3387
|
+
if (offset !== value.length) throw new Error(`statetriproute has ${value.length - offset} trailing bytes`);
|
|
3388
|
+
return {
|
|
3389
|
+
id: key,
|
|
3390
|
+
trackerVID: parsed.trackerVID,
|
|
3391
|
+
tripStart: parsed.tripStart,
|
|
3392
|
+
chunk: parsed.chunk,
|
|
3393
|
+
points,
|
|
3394
|
+
opVersion: hex(value, 0, 12),
|
|
3395
|
+
deleted: false
|
|
3396
|
+
};
|
|
3397
|
+
}
|
|
3398
|
+
registerDecoder("tripRoutes", decodeTripRouteRecord);
|
|
3399
|
+
|
|
3206
3400
|
// src/index.ts
|
|
3207
3401
|
var Connection = class extends SubscriptionClient_default {
|
|
3208
3402
|
constructor() {
|