@loro-dev/flock 2.1.2 → 3.0.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/README.md +8 -8
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +5 -6
- package/dist/index.d.ts +5 -6
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/_moon_flock.d.ts +3 -3
- package/src/_moon_flock.ts +1126 -1113
- package/src/index.ts +40 -46
package/src/index.ts
CHANGED
|
@@ -81,8 +81,7 @@ export type ExportBundle = { version: number, entries: Record<string, ExportReco
|
|
|
81
81
|
export type EntryClock = {
|
|
82
82
|
physicalTime: number;
|
|
83
83
|
logicalCounter: number;
|
|
84
|
-
|
|
85
|
-
peerId: Uint8Array;
|
|
84
|
+
peerId: string;
|
|
86
85
|
};
|
|
87
86
|
|
|
88
87
|
export type ExportPayload = {
|
|
@@ -181,30 +180,17 @@ export type EventBatch = {
|
|
|
181
180
|
events: Event[];
|
|
182
181
|
};
|
|
183
182
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
return hex;
|
|
183
|
+
const textEncoder = new TextEncoder();
|
|
184
|
+
|
|
185
|
+
function utf8ByteLength(value: string): number {
|
|
186
|
+
return textEncoder.encode(value).length;
|
|
190
187
|
}
|
|
191
188
|
|
|
192
|
-
function
|
|
193
|
-
|
|
194
|
-
throw new TypeError("peerId hex must have even length");
|
|
195
|
-
}
|
|
196
|
-
const bytes = new Uint8Array(hex.length / 2);
|
|
197
|
-
for (let i = 0; i < bytes.length; i += 1) {
|
|
198
|
-
const byte = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
199
|
-
if (Number.isNaN(byte)) {
|
|
200
|
-
throw new TypeError("peerId hex contains invalid characters");
|
|
201
|
-
}
|
|
202
|
-
bytes[i] = byte;
|
|
203
|
-
}
|
|
204
|
-
return bytes;
|
|
189
|
+
function isValidPeerId(peerId: unknown): peerId is string {
|
|
190
|
+
return typeof peerId === "string" && utf8ByteLength(peerId) < 128;
|
|
205
191
|
}
|
|
206
192
|
|
|
207
|
-
function createRandomPeerId():
|
|
193
|
+
function createRandomPeerId(): string {
|
|
208
194
|
const id = new Uint8Array(32);
|
|
209
195
|
if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") {
|
|
210
196
|
crypto.getRandomValues(id);
|
|
@@ -213,17 +199,17 @@ function createRandomPeerId(): Uint8Array {
|
|
|
213
199
|
id[i] = Math.floor(Math.random() * 256);
|
|
214
200
|
}
|
|
215
201
|
}
|
|
216
|
-
return id;
|
|
202
|
+
return Array.from(id, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
217
203
|
}
|
|
218
204
|
|
|
219
|
-
function normalizePeerId(peerId?:
|
|
205
|
+
function normalizePeerId(peerId?: string): string {
|
|
220
206
|
if (peerId === undefined) {
|
|
221
207
|
return createRandomPeerId();
|
|
222
208
|
}
|
|
223
|
-
if (!(peerId
|
|
224
|
-
throw new TypeError("peerId must be a
|
|
209
|
+
if (!isValidPeerId(peerId)) {
|
|
210
|
+
throw new TypeError("peerId must be a UTF-8 string under 128 bytes");
|
|
225
211
|
}
|
|
226
|
-
return
|
|
212
|
+
return peerId;
|
|
227
213
|
}
|
|
228
214
|
|
|
229
215
|
function encodeVersionVector(vv?: VersionVector): RawVersionVector | undefined {
|
|
@@ -235,6 +221,9 @@ function encodeVersionVector(vv?: VersionVector): RawVersionVector | undefined {
|
|
|
235
221
|
if (!entry) {
|
|
236
222
|
continue;
|
|
237
223
|
}
|
|
224
|
+
if (!isValidPeerId(peer)) {
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
238
227
|
const { physicalTime, logicalCounter } = entry;
|
|
239
228
|
if (typeof physicalTime !== "number" || Number.isNaN(physicalTime)) {
|
|
240
229
|
continue;
|
|
@@ -266,6 +255,9 @@ function decodeVersionVector(raw: unknown): VersionVector {
|
|
|
266
255
|
if (!Array.isArray(value) || value.length < 2) {
|
|
267
256
|
continue;
|
|
268
257
|
}
|
|
258
|
+
if (!isValidPeerId(peer)) {
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
269
261
|
const [physicalTime, logicalCounter] = value;
|
|
270
262
|
if (typeof physicalTime !== "number" || !Number.isFinite(physicalTime)) {
|
|
271
263
|
continue;
|
|
@@ -375,22 +367,21 @@ function cloneMetadata(metadata: unknown): MetadataMap | undefined {
|
|
|
375
367
|
}
|
|
376
368
|
|
|
377
369
|
function decodeClock(record: ExportRecord): EntryClock {
|
|
378
|
-
const
|
|
379
|
-
const
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
370
|
+
const rawClock = typeof record.c === "string" ? record.c : "";
|
|
371
|
+
const firstComma = rawClock.indexOf(",");
|
|
372
|
+
const secondComma = firstComma === -1 ? -1 : rawClock.indexOf(",", firstComma + 1);
|
|
373
|
+
if (firstComma === -1 || secondComma === -1) {
|
|
374
|
+
return { physicalTime: 0, logicalCounter: 0, peerId: "" };
|
|
375
|
+
}
|
|
376
|
+
const physicalTime = Number(rawClock.slice(0, firstComma));
|
|
377
|
+
const logicalCounter = Number(rawClock.slice(firstComma + 1, secondComma));
|
|
378
|
+
const peerIdRaw = rawClock.slice(secondComma + 1);
|
|
379
|
+
const peerId = isValidPeerId(peerIdRaw) ? peerIdRaw : "";
|
|
388
380
|
return {
|
|
389
381
|
physicalTime: Number.isFinite(physicalTime) ? physicalTime : 0,
|
|
390
382
|
logicalCounter: Number.isFinite(logicalCounter)
|
|
391
383
|
? Math.trunc(logicalCounter)
|
|
392
384
|
: 0,
|
|
393
|
-
peerIdHex,
|
|
394
385
|
peerId,
|
|
395
386
|
};
|
|
396
387
|
}
|
|
@@ -537,7 +528,7 @@ function isImportOptions(value: unknown): value is ImportOptions {
|
|
|
537
528
|
export class Flock {
|
|
538
529
|
private inner: ReturnType<typeof newFlock>;
|
|
539
530
|
|
|
540
|
-
constructor(peerId?:
|
|
531
|
+
constructor(peerId?: string) {
|
|
541
532
|
this.inner = newFlock(normalizePeerId(peerId));
|
|
542
533
|
}
|
|
543
534
|
|
|
@@ -547,8 +538,8 @@ export class Flock {
|
|
|
547
538
|
return flock;
|
|
548
539
|
}
|
|
549
540
|
|
|
550
|
-
static fromJson(bundle: ExportBundle, peerId:
|
|
551
|
-
const inner = from_json_ffi(bundle,
|
|
541
|
+
static fromJson(bundle: ExportBundle, peerId: string): Flock {
|
|
542
|
+
const inner = from_json_ffi(bundle, normalizePeerId(peerId));
|
|
552
543
|
return Flock.fromInner(inner as ReturnType<typeof newFlock>);
|
|
553
544
|
}
|
|
554
545
|
|
|
@@ -560,7 +551,7 @@ export class Flock {
|
|
|
560
551
|
check_invariants_ffi(this.inner);
|
|
561
552
|
}
|
|
562
553
|
|
|
563
|
-
setPeerId(peerId:
|
|
554
|
+
setPeerId(peerId: string): void {
|
|
564
555
|
set_peer_id(this.inner, normalizePeerId(peerId));
|
|
565
556
|
}
|
|
566
557
|
|
|
@@ -754,12 +745,15 @@ export class Flock {
|
|
|
754
745
|
return Number(get_max_physical_time_ffi(this.inner));
|
|
755
746
|
}
|
|
756
747
|
|
|
757
|
-
peerId():
|
|
758
|
-
const
|
|
759
|
-
if (typeof
|
|
748
|
+
peerId(): string {
|
|
749
|
+
const id = peer_id_ffi(this.inner);
|
|
750
|
+
if (typeof id !== "string") {
|
|
760
751
|
throw new TypeError("peerId ffi returned unexpected value");
|
|
761
752
|
}
|
|
762
|
-
|
|
753
|
+
if (!isValidPeerId(id)) {
|
|
754
|
+
throw new TypeError("peerId ffi returned an invalid string");
|
|
755
|
+
}
|
|
756
|
+
return id;
|
|
763
757
|
}
|
|
764
758
|
|
|
765
759
|
digest(): string {
|