@loro-dev/streams-crdt 0.15.1 → 0.16.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 +11 -8
- package/dist/flock.d.ts +1 -1
- package/dist/flock.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/loro.d.ts +9 -11
- package/dist/loro.js +43 -3
- package/dist/loro.js.map +1 -1
- package/dist/{stream-id-CVCOLgSp.d.ts → stream-id-BEEukuNT.d.ts} +33 -3
- package/dist/{stream-id-BygPTNvQ.js → stream-id-DwQujw_H.js} +195 -65
- package/dist/stream-id-DwQujw_H.js.map +1 -0
- package/package.json +2 -2
- package/dist/stream-id-BygPTNvQ.js.map +0 -1
package/README.md
CHANGED
|
@@ -232,26 +232,29 @@ const transport = new StreamsCrdt({
|
|
|
232
232
|
adapter: createLoroDocAdapter(doc),
|
|
233
233
|
shardUrls: {
|
|
234
234
|
bootstrap: [
|
|
235
|
-
"https://control-a.
|
|
236
|
-
"https://control-b.
|
|
235
|
+
"https://control-a.streams.example.com",
|
|
236
|
+
"https://control-b.streams.example.com",
|
|
237
237
|
],
|
|
238
238
|
catchup: [
|
|
239
|
-
"https://control-a.
|
|
240
|
-
"https://control-b.
|
|
239
|
+
"https://control-a.streams.example.com",
|
|
240
|
+
"https://control-b.streams.example.com",
|
|
241
241
|
],
|
|
242
242
|
largePost: [
|
|
243
|
-
"https://write-a.
|
|
244
|
-
"https://write-b.
|
|
243
|
+
"https://write-a.streams.example.com",
|
|
244
|
+
"https://write-b.streams.example.com",
|
|
245
245
|
],
|
|
246
246
|
other: [
|
|
247
|
-
"https://live-a.
|
|
248
|
-
"https://live-b.
|
|
247
|
+
"https://live-a.streams.example.com",
|
|
248
|
+
"https://live-b.streams.example.com",
|
|
249
249
|
],
|
|
250
250
|
largePostMinBytes: 64 * 1024,
|
|
251
251
|
},
|
|
252
252
|
});
|
|
253
253
|
```
|
|
254
254
|
|
|
255
|
+
The hostnames above are placeholders. Configure your own origins to route to the
|
|
256
|
+
same gateway; this transport does not provision DNS or deploy a proxy Worker.
|
|
257
|
+
|
|
255
258
|
Shard entries must be origin URLs with no path, query, or hash. Each transport
|
|
256
259
|
instance rotates through the configured origins per operation, with a randomized
|
|
257
260
|
starting point so multiple tabs are less likely to all begin on the same shard.
|
package/dist/flock.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as WriteOnlyAppendResult, A as PayloadProtectionProviderConfig, B as StreamsAuthProvider, C as LocalSyncStats, D as PayloadProtectionOpenInput, E as PayloadProtectionKind, F as Result, G as TransportCreateStreamSuccess, H as StreamsCrdtShardUrlsOptions, I as SnapshotCodec, J as TransportJoinParams, K as TransportDeleteStreamSuccess, L as SnapshotTransformHook, M as PayloadProtectionSealInput, N as PayloadProtectionSealResult, O as PayloadProtectionOptions, P as PayloadProtectionWritePolicy, Q as TransportSyncSuccess, R as SnapshotUploadOptions, S as JsonValue, T as PayloadProtectionFailureReason, U as TransportCatchupParams, V as StreamsCrdtOptions, W as TransportCatchupSuccess, X as TransportSnapshotUploadSuccess, Y as TransportRoomStatus, Z as TransportSubscription, _ as EphemeralStreamCrdtOptions, a as StreamsCrdt, at as RemoteCursor, b as IsolatedCrdtAdapter, c as CrdtApplyReturn, ct as createInitialRemoteCursor, d as E2eeOptions, et as BeforeRemoteCursorSaveContext, f as E2eeProvider, g as EphemeralStreamAdaptor, h as E2eeWritePolicy, i as EphemeralStreamCrdt, it as IndexedDbRemoteCursorStoreOptions, j as PayloadProtectionReadPolicy, k as PayloadProtectionProvider, l as CrdtUnresolvedSpan, m as E2eeReadPolicy, n as PayloadProtectionError, nt as InMemoryRemoteCursorStore, o as CrdtAdapter, ot as RemoteCursorSaveSource, p as E2eeProviderConfig, q as TransportError, r as LocalAppendFailedError, rt as IndexedDbRemoteCursorStore, s as CrdtApplyOutcome, st as RemoteCursorStore, t as isValidRillId, tt as BeforeRemoteCursorSaveHook, u as CrdtUpdateBatch, v as EphemeralStreamJoinParams, w as PayloadProtectionContext, x as JsonObject, y as EphemeralStreamSubscription, z as StreamsAuthContext } from "./stream-id-
|
|
1
|
+
import { $ as WriteOnlyAppendResult, A as PayloadProtectionProviderConfig, B as StreamsAuthProvider, C as LocalSyncStats, D as PayloadProtectionOpenInput, E as PayloadProtectionKind, F as Result, G as TransportCreateStreamSuccess, H as StreamsCrdtShardUrlsOptions, I as SnapshotCodec, J as TransportJoinParams, K as TransportDeleteStreamSuccess, L as SnapshotTransformHook, M as PayloadProtectionSealInput, N as PayloadProtectionSealResult, O as PayloadProtectionOptions, P as PayloadProtectionWritePolicy, Q as TransportSyncSuccess, R as SnapshotUploadOptions, S as JsonValue, T as PayloadProtectionFailureReason, U as TransportCatchupParams, V as StreamsCrdtOptions, W as TransportCatchupSuccess, X as TransportSnapshotUploadSuccess, Y as TransportRoomStatus, Z as TransportSubscription, _ as EphemeralStreamCrdtOptions, a as StreamsCrdt, at as RemoteCursor, b as IsolatedCrdtAdapter, c as CrdtApplyReturn, ct as createInitialRemoteCursor, d as E2eeOptions, et as BeforeRemoteCursorSaveContext, f as E2eeProvider, g as EphemeralStreamAdaptor, h as E2eeWritePolicy, i as EphemeralStreamCrdt, it as IndexedDbRemoteCursorStoreOptions, j as PayloadProtectionReadPolicy, k as PayloadProtectionProvider, l as CrdtUnresolvedSpan, m as E2eeReadPolicy, n as PayloadProtectionError, nt as InMemoryRemoteCursorStore, o as CrdtAdapter, ot as RemoteCursorSaveSource, p as E2eeProviderConfig, q as TransportError, r as LocalAppendFailedError, rt as IndexedDbRemoteCursorStore, s as CrdtApplyOutcome, st as RemoteCursorStore, t as isValidRillId, tt as BeforeRemoteCursorSaveHook, u as CrdtUpdateBatch, v as EphemeralStreamJoinParams, w as PayloadProtectionContext, x as JsonObject, y as EphemeralStreamSubscription, z as StreamsAuthContext } from "./stream-id-BEEukuNT.js";
|
|
2
2
|
import { ExportBundle, Flock, VersionVector, VersionVector as VersionVector$1 } from "@loro-dev/flock-wasm";
|
|
3
3
|
|
|
4
4
|
//#region src/flock.d.ts
|
package/dist/flock.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as createInitialRemoteCursor, c as PayloadProtectionError, i as IndexedDbRemoteCursorStore, n as StreamsCrdt, o as EphemeralStreamCrdt, r as InMemoryRemoteCursorStore, s as LocalAppendFailedError, t as isValidRillId } from "./stream-id-
|
|
1
|
+
import { a as createInitialRemoteCursor, c as PayloadProtectionError, i as IndexedDbRemoteCursorStore, n as StreamsCrdt, o as EphemeralStreamCrdt, r as InMemoryRemoteCursorStore, s as LocalAppendFailedError, t as isValidRillId } from "./stream-id-DwQujw_H.js";
|
|
2
2
|
import { Flock } from "@loro-dev/flock-wasm";
|
|
3
3
|
//#region src/flock.ts
|
|
4
4
|
function isAfter(entry, current) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { $ as WriteOnlyAppendResult, A as PayloadProtectionProviderConfig, B as StreamsAuthProvider, C as LocalSyncStats, D as PayloadProtectionOpenInput, E as PayloadProtectionKind, F as Result, G as TransportCreateStreamSuccess, H as StreamsCrdtShardUrlsOptions, I as SnapshotCodec, J as TransportJoinParams, K as TransportDeleteStreamSuccess, L as SnapshotTransformHook, M as PayloadProtectionSealInput, N as PayloadProtectionSealResult, O as PayloadProtectionOptions, P as PayloadProtectionWritePolicy, Q as TransportSyncSuccess, R as SnapshotUploadOptions, S as JsonValue, T as PayloadProtectionFailureReason, U as TransportCatchupParams, V as StreamsCrdtOptions, W as TransportCatchupSuccess, X as TransportSnapshotUploadSuccess, Y as TransportRoomStatus, Z as TransportSubscription, _ as EphemeralStreamCrdtOptions, a as StreamsCrdt, at as RemoteCursor, b as IsolatedCrdtAdapter, c as CrdtApplyReturn, ct as createInitialRemoteCursor, d as E2eeOptions, et as BeforeRemoteCursorSaveContext, f as E2eeProvider, g as EphemeralStreamAdaptor, h as E2eeWritePolicy, i as EphemeralStreamCrdt, it as IndexedDbRemoteCursorStoreOptions, j as PayloadProtectionReadPolicy, k as PayloadProtectionProvider, l as CrdtUnresolvedSpan, m as E2eeReadPolicy, n as PayloadProtectionError, nt as InMemoryRemoteCursorStore, o as CrdtAdapter, ot as RemoteCursorSaveSource, p as E2eeProviderConfig, q as TransportError, r as LocalAppendFailedError, rt as IndexedDbRemoteCursorStore, s as CrdtApplyOutcome, st as RemoteCursorStore, t as isValidRillId, tt as BeforeRemoteCursorSaveHook, u as CrdtUpdateBatch, v as EphemeralStreamJoinParams, w as PayloadProtectionContext, x as JsonObject, y as EphemeralStreamSubscription, z as StreamsAuthContext } from "./stream-id-
|
|
1
|
+
import { $ as WriteOnlyAppendResult, A as PayloadProtectionProviderConfig, B as StreamsAuthProvider, C as LocalSyncStats, D as PayloadProtectionOpenInput, E as PayloadProtectionKind, F as Result, G as TransportCreateStreamSuccess, H as StreamsCrdtShardUrlsOptions, I as SnapshotCodec, J as TransportJoinParams, K as TransportDeleteStreamSuccess, L as SnapshotTransformHook, M as PayloadProtectionSealInput, N as PayloadProtectionSealResult, O as PayloadProtectionOptions, P as PayloadProtectionWritePolicy, Q as TransportSyncSuccess, R as SnapshotUploadOptions, S as JsonValue, T as PayloadProtectionFailureReason, U as TransportCatchupParams, V as StreamsCrdtOptions, W as TransportCatchupSuccess, X as TransportSnapshotUploadSuccess, Y as TransportRoomStatus, Z as TransportSubscription, _ as EphemeralStreamCrdtOptions, a as StreamsCrdt, at as RemoteCursor, b as IsolatedCrdtAdapter, c as CrdtApplyReturn, ct as createInitialRemoteCursor, d as E2eeOptions, et as BeforeRemoteCursorSaveContext, f as E2eeProvider, g as EphemeralStreamAdaptor, h as E2eeWritePolicy, i as EphemeralStreamCrdt, it as IndexedDbRemoteCursorStoreOptions, j as PayloadProtectionReadPolicy, k as PayloadProtectionProvider, l as CrdtUnresolvedSpan, m as E2eeReadPolicy, n as PayloadProtectionError, nt as InMemoryRemoteCursorStore, o as CrdtAdapter, ot as RemoteCursorSaveSource, p as E2eeProviderConfig, q as TransportError, r as LocalAppendFailedError, rt as IndexedDbRemoteCursorStore, s as CrdtApplyOutcome, st as RemoteCursorStore, t as isValidRillId, tt as BeforeRemoteCursorSaveHook, u as CrdtUpdateBatch, v as EphemeralStreamJoinParams, w as PayloadProtectionContext, x as JsonObject, y as EphemeralStreamSubscription, z as StreamsAuthContext } from "./stream-id-BEEukuNT.js";
|
|
2
2
|
export { BeforeRemoteCursorSaveContext, BeforeRemoteCursorSaveHook, CrdtAdapter, CrdtApplyOutcome, CrdtApplyReturn, CrdtUnresolvedSpan, CrdtUpdateBatch, PayloadProtectionError as E2eeError, PayloadProtectionError, E2eeOptions, E2eeProvider, E2eeProviderConfig, E2eeReadPolicy, E2eeWritePolicy, EphemeralStreamAdaptor, EphemeralStreamCrdt, EphemeralStreamCrdtOptions, EphemeralStreamJoinParams, EphemeralStreamSubscription, InMemoryRemoteCursorStore, IndexedDbRemoteCursorStore, IndexedDbRemoteCursorStoreOptions, IsolatedCrdtAdapter, JsonObject, JsonValue, LocalAppendFailedError, LocalSyncStats, PayloadProtectionContext, PayloadProtectionFailureReason, PayloadProtectionKind, PayloadProtectionOpenInput, PayloadProtectionOptions, PayloadProtectionProvider, PayloadProtectionProviderConfig, PayloadProtectionReadPolicy, PayloadProtectionSealInput, PayloadProtectionSealResult, PayloadProtectionWritePolicy, RemoteCursor, RemoteCursorSaveSource, RemoteCursorStore, Result, SnapshotCodec, SnapshotTransformHook, SnapshotUploadOptions, StreamsAuthContext, StreamsAuthProvider, StreamsCrdt, StreamsCrdtOptions, StreamsCrdtShardUrlsOptions, TransportCatchupParams, TransportCatchupSuccess, TransportCreateStreamSuccess, TransportDeleteStreamSuccess, TransportError, TransportJoinParams, TransportRoomStatus, TransportSnapshotUploadSuccess, TransportSubscription, TransportSyncSuccess, WriteOnlyAppendResult, createInitialRemoteCursor, isValidRillId };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as createInitialRemoteCursor, c as PayloadProtectionError, i as IndexedDbRemoteCursorStore, n as StreamsCrdt, o as EphemeralStreamCrdt, r as InMemoryRemoteCursorStore, s as LocalAppendFailedError, t as isValidRillId } from "./stream-id-
|
|
1
|
+
import { a as createInitialRemoteCursor, c as PayloadProtectionError, i as IndexedDbRemoteCursorStore, n as StreamsCrdt, o as EphemeralStreamCrdt, r as InMemoryRemoteCursorStore, s as LocalAppendFailedError, t as isValidRillId } from "./stream-id-DwQujw_H.js";
|
|
2
2
|
export { PayloadProtectionError as E2eeError, PayloadProtectionError, EphemeralStreamCrdt, InMemoryRemoteCursorStore, IndexedDbRemoteCursorStore, LocalAppendFailedError, StreamsCrdt, createInitialRemoteCursor, isValidRillId };
|
package/dist/loro.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as WriteOnlyAppendResult, A as PayloadProtectionProviderConfig, B as StreamsAuthProvider, C as LocalSyncStats, D as PayloadProtectionOpenInput, E as PayloadProtectionKind, F as Result, G as TransportCreateStreamSuccess, H as StreamsCrdtShardUrlsOptions, I as SnapshotCodec, J as TransportJoinParams, K as TransportDeleteStreamSuccess, L as SnapshotTransformHook, M as PayloadProtectionSealInput, N as PayloadProtectionSealResult, O as PayloadProtectionOptions, P as PayloadProtectionWritePolicy, Q as TransportSyncSuccess, R as SnapshotUploadOptions, S as JsonValue, T as PayloadProtectionFailureReason, U as TransportCatchupParams, V as StreamsCrdtOptions, W as TransportCatchupSuccess, X as TransportSnapshotUploadSuccess, Y as TransportRoomStatus, Z as TransportSubscription, _ as EphemeralStreamCrdtOptions, a as StreamsCrdt, at as RemoteCursor, b as IsolatedCrdtAdapter, c as CrdtApplyReturn, ct as createInitialRemoteCursor, d as E2eeOptions, et as BeforeRemoteCursorSaveContext, f as E2eeProvider, g as EphemeralStreamAdaptor, h as E2eeWritePolicy, i as EphemeralStreamCrdt, it as IndexedDbRemoteCursorStoreOptions, j as PayloadProtectionReadPolicy, k as PayloadProtectionProvider, l as CrdtUnresolvedSpan, m as E2eeReadPolicy, n as PayloadProtectionError, nt as InMemoryRemoteCursorStore, o as CrdtAdapter, ot as RemoteCursorSaveSource, p as E2eeProviderConfig, q as TransportError, r as LocalAppendFailedError, rt as IndexedDbRemoteCursorStore, s as CrdtApplyOutcome, st as RemoteCursorStore, t as isValidRillId, tt as BeforeRemoteCursorSaveHook, u as CrdtUpdateBatch, v as EphemeralStreamJoinParams, w as PayloadProtectionContext, x as JsonObject, y as EphemeralStreamSubscription, z as StreamsAuthContext } from "./stream-id-
|
|
1
|
+
import { $ as WriteOnlyAppendResult, A as PayloadProtectionProviderConfig, B as StreamsAuthProvider, C as LocalSyncStats, D as PayloadProtectionOpenInput, E as PayloadProtectionKind, F as Result, G as TransportCreateStreamSuccess, H as StreamsCrdtShardUrlsOptions, I as SnapshotCodec, J as TransportJoinParams, K as TransportDeleteStreamSuccess, L as SnapshotTransformHook, M as PayloadProtectionSealInput, N as PayloadProtectionSealResult, O as PayloadProtectionOptions, P as PayloadProtectionWritePolicy, Q as TransportSyncSuccess, R as SnapshotUploadOptions, S as JsonValue, T as PayloadProtectionFailureReason, U as TransportCatchupParams, V as StreamsCrdtOptions, W as TransportCatchupSuccess, X as TransportSnapshotUploadSuccess, Y as TransportRoomStatus, Z as TransportSubscription, _ as EphemeralStreamCrdtOptions, a as StreamsCrdt, at as RemoteCursor, b as IsolatedCrdtAdapter, c as CrdtApplyReturn, ct as createInitialRemoteCursor, d as E2eeOptions, et as BeforeRemoteCursorSaveContext, f as E2eeProvider, g as EphemeralStreamAdaptor, h as E2eeWritePolicy, i as EphemeralStreamCrdt, it as IndexedDbRemoteCursorStoreOptions, j as PayloadProtectionReadPolicy, k as PayloadProtectionProvider, l as CrdtUnresolvedSpan, m as E2eeReadPolicy, n as PayloadProtectionError, nt as InMemoryRemoteCursorStore, o as CrdtAdapter, ot as RemoteCursorSaveSource, p as E2eeProviderConfig, q as TransportError, r as LocalAppendFailedError, rt as IndexedDbRemoteCursorStore, s as CrdtApplyOutcome, st as RemoteCursorStore, t as isValidRillId, tt as BeforeRemoteCursorSaveHook, u as CrdtUpdateBatch, v as EphemeralStreamJoinParams, w as PayloadProtectionContext, x as JsonObject, y as EphemeralStreamSubscription, z as StreamsAuthContext } from "./stream-id-BEEukuNT.js";
|
|
2
2
|
import { LoroDoc } from "loro-crdt";
|
|
3
3
|
|
|
4
4
|
//#region src/loro.d.ts
|
|
@@ -27,19 +27,17 @@ interface LoroEphemeralStoreLike {
|
|
|
27
27
|
subscribeLocalUpdates(listener: (update: Uint8Array) => void): () => void;
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
|
-
*
|
|
30
|
+
* Reads the key of a single-entry Loro ephemeral update.
|
|
31
31
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* adaptor: EphemeralStoreAdaptor(store),
|
|
38
|
-
* });
|
|
39
|
-
* ```
|
|
32
|
+
* Loro encodes updates as a postcard `Vec<{ key: &str, value, timestamp }>`,
|
|
33
|
+
* so a local `set`/`delete` starts with `varint(1)`, `varint(keyLen)`, key
|
|
34
|
+
* bytes. Only that prefix is read; the value is never decoded. Anything else
|
|
35
|
+
* (several entries, malformed bytes) returns `undefined`, which keeps the
|
|
36
|
+
* update as its own queue entry.
|
|
40
37
|
*/
|
|
38
|
+
declare function loroEphemeralUpdateKey(update: Uint8Array): string | undefined;
|
|
41
39
|
declare function EphemeralStoreAdaptor(store: LoroEphemeralStoreLike): EphemeralStreamAdaptor;
|
|
42
40
|
declare const createLoroEphemeralStoreAdaptor: typeof EphemeralStoreAdaptor;
|
|
43
41
|
//#endregion
|
|
44
|
-
export { BeforeRemoteCursorSaveContext, BeforeRemoteCursorSaveHook, CrdtAdapter, CrdtApplyOutcome, CrdtApplyReturn, CrdtUnresolvedSpan, CrdtUpdateBatch, PayloadProtectionError as E2eeError, PayloadProtectionError, E2eeOptions, E2eeProvider, E2eeProviderConfig, E2eeReadPolicy, E2eeWritePolicy, EphemeralStoreAdaptor, EphemeralStreamAdaptor, EphemeralStreamCrdt, EphemeralStreamCrdtOptions, EphemeralStreamJoinParams, EphemeralStreamSubscription, InMemoryRemoteCursorStore, IndexedDbRemoteCursorStore, IndexedDbRemoteCursorStoreOptions, IsolatedCrdtAdapter, JsonObject, JsonValue, LocalAppendFailedError, LocalSyncStats, LoroEphemeralStoreLike, PayloadProtectionContext, PayloadProtectionFailureReason, PayloadProtectionKind, PayloadProtectionOpenInput, PayloadProtectionOptions, PayloadProtectionProvider, PayloadProtectionProviderConfig, PayloadProtectionReadPolicy, PayloadProtectionSealInput, PayloadProtectionSealResult, PayloadProtectionWritePolicy, RemoteCursor, RemoteCursorSaveSource, RemoteCursorStore, Result, SnapshotCodec, SnapshotTransformHook, SnapshotUploadOptions, StreamsAuthContext, StreamsAuthProvider, StreamsCrdt, StreamsCrdtOptions, StreamsCrdtShardUrlsOptions, TransportCatchupParams, TransportCatchupSuccess, TransportCreateStreamSuccess, TransportDeleteStreamSuccess, TransportError, TransportJoinParams, TransportRoomStatus, TransportSnapshotUploadSuccess, TransportSubscription, TransportSyncSuccess, WriteOnlyAppendResult, createInitialRemoteCursor, createLoroDocAdapter, createLoroEphemeralStoreAdaptor, isValidRillId };
|
|
42
|
+
export { BeforeRemoteCursorSaveContext, BeforeRemoteCursorSaveHook, CrdtAdapter, CrdtApplyOutcome, CrdtApplyReturn, CrdtUnresolvedSpan, CrdtUpdateBatch, PayloadProtectionError as E2eeError, PayloadProtectionError, E2eeOptions, E2eeProvider, E2eeProviderConfig, E2eeReadPolicy, E2eeWritePolicy, EphemeralStoreAdaptor, EphemeralStreamAdaptor, EphemeralStreamCrdt, EphemeralStreamCrdtOptions, EphemeralStreamJoinParams, EphemeralStreamSubscription, InMemoryRemoteCursorStore, IndexedDbRemoteCursorStore, IndexedDbRemoteCursorStoreOptions, IsolatedCrdtAdapter, JsonObject, JsonValue, LocalAppendFailedError, LocalSyncStats, LoroEphemeralStoreLike, PayloadProtectionContext, PayloadProtectionFailureReason, PayloadProtectionKind, PayloadProtectionOpenInput, PayloadProtectionOptions, PayloadProtectionProvider, PayloadProtectionProviderConfig, PayloadProtectionReadPolicy, PayloadProtectionSealInput, PayloadProtectionSealResult, PayloadProtectionWritePolicy, RemoteCursor, RemoteCursorSaveSource, RemoteCursorStore, Result, SnapshotCodec, SnapshotTransformHook, SnapshotUploadOptions, StreamsAuthContext, StreamsAuthProvider, StreamsCrdt, StreamsCrdtOptions, StreamsCrdtShardUrlsOptions, TransportCatchupParams, TransportCatchupSuccess, TransportCreateStreamSuccess, TransportDeleteStreamSuccess, TransportError, TransportJoinParams, TransportRoomStatus, TransportSnapshotUploadSuccess, TransportSubscription, TransportSyncSuccess, WriteOnlyAppendResult, createInitialRemoteCursor, createLoroDocAdapter, createLoroEphemeralStoreAdaptor, isValidRillId, loroEphemeralUpdateKey };
|
|
45
43
|
//# sourceMappingURL=loro.d.ts.map
|
package/dist/loro.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as createInitialRemoteCursor, c as PayloadProtectionError, i as IndexedDbRemoteCursorStore, n as StreamsCrdt, o as EphemeralStreamCrdt, r as InMemoryRemoteCursorStore, s as LocalAppendFailedError, t as isValidRillId } from "./stream-id-
|
|
1
|
+
import { a as createInitialRemoteCursor, c as PayloadProtectionError, i as IndexedDbRemoteCursorStore, n as StreamsCrdt, o as EphemeralStreamCrdt, r as InMemoryRemoteCursorStore, s as LocalAppendFailedError, t as isValidRillId } from "./stream-id-DwQujw_H.js";
|
|
2
2
|
import { LoroDoc, VersionVector, decodeImportBlobMeta } from "loro-crdt";
|
|
3
3
|
//#region src/loro.ts
|
|
4
4
|
function batchImportUpdates(doc, updates) {
|
|
@@ -244,6 +244,45 @@ function createLoroDocAdapter(doc) {
|
|
|
244
244
|
* });
|
|
245
245
|
* ```
|
|
246
246
|
*/
|
|
247
|
+
const utf8Decoder = new TextDecoder("utf-8", {
|
|
248
|
+
fatal: true,
|
|
249
|
+
ignoreBOM: true
|
|
250
|
+
});
|
|
251
|
+
/**
|
|
252
|
+
* Reads the key of a single-entry Loro ephemeral update.
|
|
253
|
+
*
|
|
254
|
+
* Loro encodes updates as a postcard `Vec<{ key: &str, value, timestamp }>`,
|
|
255
|
+
* so a local `set`/`delete` starts with `varint(1)`, `varint(keyLen)`, key
|
|
256
|
+
* bytes. Only that prefix is read; the value is never decoded. Anything else
|
|
257
|
+
* (several entries, malformed bytes) returns `undefined`, which keeps the
|
|
258
|
+
* update as its own queue entry.
|
|
259
|
+
*/
|
|
260
|
+
function loroEphemeralUpdateKey(update) {
|
|
261
|
+
const count = readVarUint(update, 0);
|
|
262
|
+
if (count == null || count.value !== 1) return;
|
|
263
|
+
const keyLength = readVarUint(update, count.next);
|
|
264
|
+
if (keyLength == null) return;
|
|
265
|
+
const end = keyLength.next + keyLength.value;
|
|
266
|
+
if (end > update.byteLength) return;
|
|
267
|
+
try {
|
|
268
|
+
return utf8Decoder.decode(update.subarray(keyLength.next, end));
|
|
269
|
+
} catch {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function readVarUint(bytes, offset) {
|
|
274
|
+
let value = 0;
|
|
275
|
+
for (let i = 0; i < 5; i += 1) {
|
|
276
|
+
const index = offset + i;
|
|
277
|
+
if (index >= bytes.byteLength) return;
|
|
278
|
+
const byte = bytes[index];
|
|
279
|
+
value += (byte & 127) * 2 ** (7 * i);
|
|
280
|
+
if ((byte & 128) === 0) return {
|
|
281
|
+
value,
|
|
282
|
+
next: index + 1
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
}
|
|
247
286
|
function EphemeralStoreAdaptor(store) {
|
|
248
287
|
let applyingRemoteDepth = 0;
|
|
249
288
|
return {
|
|
@@ -263,11 +302,12 @@ function EphemeralStoreAdaptor(store) {
|
|
|
263
302
|
return () => {
|
|
264
303
|
unsubscribeLocalUpdates();
|
|
265
304
|
};
|
|
266
|
-
}
|
|
305
|
+
},
|
|
306
|
+
localUpdateKey: loroEphemeralUpdateKey
|
|
267
307
|
};
|
|
268
308
|
}
|
|
269
309
|
const createLoroEphemeralStoreAdaptor = EphemeralStoreAdaptor;
|
|
270
310
|
//#endregion
|
|
271
|
-
export { PayloadProtectionError as E2eeError, PayloadProtectionError, EphemeralStoreAdaptor, EphemeralStreamCrdt, InMemoryRemoteCursorStore, IndexedDbRemoteCursorStore, LocalAppendFailedError, StreamsCrdt, createInitialRemoteCursor, createLoroDocAdapter, createLoroEphemeralStoreAdaptor, isValidRillId };
|
|
311
|
+
export { PayloadProtectionError as E2eeError, PayloadProtectionError, EphemeralStoreAdaptor, EphemeralStreamCrdt, InMemoryRemoteCursorStore, IndexedDbRemoteCursorStore, LocalAppendFailedError, StreamsCrdt, createInitialRemoteCursor, createLoroDocAdapter, createLoroEphemeralStoreAdaptor, isValidRillId, loroEphemeralUpdateKey };
|
|
272
312
|
|
|
273
313
|
//# sourceMappingURL=loro.js.map
|
package/dist/loro.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loro.js","names":[],"sources":["../src/loro.ts"],"sourcesContent":["import {\n decodeImportBlobMeta,\n LoroDoc,\n VersionVector,\n} from \"loro-crdt\";\n\nimport type {\n CrdtAdapter,\n CrdtApplyOutcome,\n CrdtUnresolvedSpan,\n JsonObject,\n} from \"./types\";\nimport type { EphemeralStreamAdaptor } from \"./types\";\n\nexport { EphemeralStreamCrdt } from \"./ephemeral-runtime\";\nexport { StreamsCrdt } from \"./transport-runtime\";\nexport * from \"./shared\";\n\ntype CounterSpan = {\n readonly start: number;\n readonly end: number;\n};\n\ntype LoroImportStatus = {\n readonly success: Map<string | number | bigint, CounterSpan>;\n readonly pending: Map<string | number | bigint, CounterSpan> | null;\n};\n\nfunction batchImportUpdates(\n doc: LoroDoc,\n updates: Uint8Array[],\n): LoroImportStatus {\n if (\"batchImport\" in doc && typeof doc.batchImport === \"function\") {\n return doc.batchImport(updates) as LoroImportStatus;\n }\n return doc.importBatch(updates) as LoroImportStatus;\n}\n\ntype PeerId = `${number}`;\ntype DocVersionRecord = Record<PeerId, number>;\n\nfunction toDocVersionRecord(version: VersionVector): DocVersionRecord {\n const out = {} as DocVersionRecord;\n for (const [peer, counter] of version.toJSON()) {\n out[peer as PeerId] = counter;\n }\n return out;\n}\n\nfunction toDocVersionMap(version: JsonObject): Map<PeerId, number> {\n const out = new Map<PeerId, number>();\n for (const [peer, counter] of Object.entries(version)) {\n if (typeof counter === \"number\" && Number.isFinite(counter)) {\n out.set(peer as PeerId, counter);\n }\n }\n return out;\n}\n\nfunction mergeDocVersions(\n base: DocVersionRecord,\n incoming: DocVersionRecord,\n): DocVersionRecord {\n const merged = new Map<PeerId, number>();\n for (const [peer, counter] of Object.entries(base)) {\n merged.set(peer as PeerId, counter);\n }\n for (const [peer, counter] of Object.entries(incoming)) {\n const peerId = peer as PeerId;\n merged.set(peerId, Math.max(merged.get(peerId) ?? 0, counter));\n }\n return toDocVersionRecord(VersionVector.parseJSON(merged));\n}\n\nfunction hasUpdatesSince(\n fromVersion: DocVersionRecord,\n currentVersion: DocVersionRecord,\n): boolean {\n for (const [peer, counter] of Object.entries(currentVersion)) {\n if (counter > (fromVersion[peer as PeerId] ?? 0)) {\n return true;\n }\n }\n return false;\n}\n\nfunction extractVersionFromUpdate(update: Uint8Array): DocVersionRecord | null {\n try {\n const meta = decodeImportBlobMeta(update, false);\n return toDocVersionRecord(meta.partialEndVersionVector);\n } catch {\n return null;\n }\n}\n\nfunction assertDocAttached(doc: LoroDoc): void {\n if (!doc.isDetached()) {\n return;\n }\n throw new Error(\n \"LoroDoc must be attached before using streams-crdt; \" +\n \"call checkoutToLatest() or attach() first\",\n );\n}\n\nfunction normalizePeerId(peer: string | number | bigint): PeerId {\n return `${peer}` as PeerId;\n}\n\nfunction isValidSpan(span: CounterSpan): boolean {\n return (\n Number.isSafeInteger(span.start) &&\n Number.isSafeInteger(span.end) &&\n span.start < span.end\n );\n}\n\nclass UnresolvedSpanTracker {\n private readonly spans = new Map<PeerId, CounterSpan[]>();\n\n addAll(pending: LoroImportStatus[\"pending\"]): void {\n if (pending == null) {\n return;\n }\n for (const [peer, span] of pending) {\n this.add(normalizePeerId(peer), span);\n }\n }\n\n resolveAll(success: LoroImportStatus[\"success\"]): void {\n for (const [peer, span] of success) {\n this.resolve(normalizePeerId(peer), span);\n }\n }\n\n isEmpty(): boolean {\n return this.spans.size === 0;\n }\n\n toArray(): CrdtUnresolvedSpan[] {\n const out: CrdtUnresolvedSpan[] = [];\n for (const [peer, spans] of this.spans) {\n for (const span of spans) {\n out.push({ peer, start: span.start, end: span.end });\n }\n }\n return out;\n }\n\n reset(): void {\n this.spans.clear();\n }\n\n private add(peer: PeerId, incoming: CounterSpan): void {\n if (!isValidSpan(incoming)) {\n return;\n }\n const existing = this.spans.get(peer) ?? [];\n existing.push({ start: incoming.start, end: incoming.end });\n existing.sort((a, b) => a.start - b.start || a.end - b.end);\n const merged: CounterSpan[] = [];\n for (const span of existing) {\n const last = merged[merged.length - 1];\n if (last == null || span.start > last.end) {\n merged.push({ start: span.start, end: span.end });\n } else {\n merged[merged.length - 1] = {\n start: last.start,\n end: Math.max(last.end, span.end),\n };\n }\n }\n this.spans.set(peer, merged);\n }\n\n private resolve(peer: PeerId, applied: CounterSpan): void {\n if (!isValidSpan(applied)) {\n return;\n }\n const existing = this.spans.get(peer);\n if (existing == null) {\n return;\n }\n const remaining: CounterSpan[] = [];\n for (const span of existing) {\n if (applied.end <= span.start || applied.start >= span.end) {\n remaining.push(span);\n continue;\n }\n if (span.start < applied.start) {\n remaining.push({ start: span.start, end: applied.start });\n }\n if (applied.end < span.end) {\n remaining.push({ start: applied.end, end: span.end });\n }\n }\n if (remaining.length === 0) {\n this.spans.delete(peer);\n } else {\n this.spans.set(peer, remaining);\n }\n }\n}\n\nfunction trackImportStatus(\n tracker: UnresolvedSpanTracker,\n status: LoroImportStatus,\n): void {\n tracker.addAll(status.pending);\n tracker.resolveAll(status.success);\n}\n\nfunction versionFromImportSuccess(status: LoroImportStatus): DocVersionRecord {\n const version: DocVersionRecord = {};\n for (const [peer, span] of status.success) {\n if (!isValidSpan(span)) {\n continue;\n }\n const peerId = normalizePeerId(peer);\n version[peerId] = Math.max(version[peerId] ?? 0, span.end);\n }\n return version;\n}\n\nfunction versionFromSnapshotImport(\n snapshot: Uint8Array,\n status: LoroImportStatus,\n tracker: UnresolvedSpanTracker,\n): DocVersionRecord {\n if (!tracker.isEmpty()) {\n return versionFromImportSuccess(status);\n }\n return extractVersionFromUpdate(snapshot) ?? versionFromImportSuccess(status);\n}\n\nfunction applyOutcome(\n version: DocVersionRecord,\n tracker: UnresolvedSpanTracker,\n): CrdtApplyOutcome<JsonObject> {\n const unresolved = tracker.toArray();\n return {\n version,\n complete: unresolved.length === 0,\n ...(unresolved.length === 0 ? {} : { unresolved }),\n };\n}\n\n/**\n * Creates a `CrdtAdapter` for one `LoroDoc`.\n *\n * The `LoroDoc` must be attached (not detached or checked out to a historical\n * version). If the document is detached, call `doc.checkoutToLatest()` or\n * `doc.attach()` before passing it here.\n *\n * @example\n * ```ts\n * const doc = new LoroDoc();\n * const adapter = createLoroDocAdapter(doc);\n * const transport = new StreamsCrdt({ streamUrl, adapter, auth });\n * ```\n */\nexport function createLoroDocAdapter(\n doc: LoroDoc,\n): CrdtAdapter<JsonObject> {\n const unresolved = new UnresolvedSpanTracker();\n return {\n emptyVersion: () => ({}),\n mergeVersions: (base, incoming) =>\n mergeDocVersions(base as DocVersionRecord, incoming as DocVersionRecord),\n exportSnapshot: () => {\n assertDocAttached(doc);\n return doc.export({ mode: \"snapshot\" });\n },\n applySnapshot: (snapshot) => {\n assertDocAttached(doc);\n const status = doc.import(snapshot) as LoroImportStatus;\n unresolved.reset();\n trackImportStatus(unresolved, status);\n return applyOutcome(\n versionFromSnapshotImport(snapshot, status, unresolved),\n unresolved,\n );\n },\n exportUpdates: (fromVersion) => {\n assertDocAttached(doc);\n const currentVersion = toDocVersionRecord(doc.version());\n if (\n !hasUpdatesSince(\n fromVersion as DocVersionRecord,\n currentVersion,\n )\n ) {\n return undefined;\n }\n const updates = [\n doc.export({\n mode: \"update\",\n from: VersionVector.parseJSON(toDocVersionMap(fromVersion)),\n }),\n ].filter((update) => update.byteLength > 0);\n if (updates.length === 0) {\n return undefined;\n }\n let version: DocVersionRecord = {};\n for (const update of updates) {\n const next = extractVersionFromUpdate(update);\n if (next != null) {\n version = mergeDocVersions(version, next);\n }\n }\n return {\n updates,\n version,\n };\n },\n applyRemoteUpdates: (updates, remoterVersion) => {\n assertDocAttached(doc);\n if (updates.length > 0) {\n const status = batchImportUpdates(doc, updates);\n trackImportStatus(unresolved, status);\n const version = mergeDocVersions(\n remoterVersion as DocVersionRecord,\n versionFromImportSuccess(status),\n );\n return applyOutcome(version, unresolved);\n }\n return applyOutcome(remoterVersion as DocVersionRecord, unresolved);\n },\n createIsolatedAdapter: () => {\n let isolatedDoc = new LoroDoc();\n const isolatedUnresolved = new UnresolvedSpanTracker();\n return {\n applySnapshot: (snapshot) => {\n isolatedDoc = new LoroDoc();\n isolatedUnresolved.reset();\n if (snapshot.byteLength > 0) {\n const status = isolatedDoc.import(snapshot) as LoroImportStatus;\n trackImportStatus(isolatedUnresolved, status);\n return applyOutcome(\n versionFromSnapshotImport(snapshot, status, isolatedUnresolved),\n isolatedUnresolved,\n );\n }\n return applyOutcome({}, isolatedUnresolved);\n },\n applyRemoteUpdates: (updates, remoterVersion) => {\n if (updates.length > 0) {\n const status = batchImportUpdates(isolatedDoc, updates);\n trackImportStatus(isolatedUnresolved, status);\n const version = mergeDocVersions(\n remoterVersion as DocVersionRecord,\n versionFromImportSuccess(status),\n );\n return applyOutcome(version, isolatedUnresolved);\n }\n return applyOutcome(\n remoterVersion as DocVersionRecord,\n isolatedUnresolved,\n );\n },\n };\n },\n subscribeLocalUpdates: (listener) => {\n assertDocAttached(doc);\n return doc.subscribeLocalUpdates((update) => {\n const version = extractVersionFromUpdate(update) ?? {};\n listener({ updates: [update], version });\n });\n },\n };\n}\n\n/**\n * Structural subset of Loro's `EphemeralStore`.\n */\nexport interface LoroEphemeralStoreLike {\n /** Applies one opaque Loro ephemeral update. */\n apply(update: Uint8Array): void;\n /** Subscribes to locally produced ephemeral updates. */\n subscribeLocalUpdates(listener: (update: Uint8Array) => void): () => void;\n}\n\n/**\n * Creates an ephemeral stream adaptor for a Loro `EphemeralStore`.\n *\n * @example\n * ```ts\n * const room = new EphemeralStreamCrdt({\n * streamUrl,\n * auth,\n * adaptor: EphemeralStoreAdaptor(store),\n * });\n * ```\n */\nexport function EphemeralStoreAdaptor(\n store: LoroEphemeralStoreLike,\n): EphemeralStreamAdaptor {\n let applyingRemoteDepth = 0;\n return {\n applyRemoteUpdates: (updates) => {\n applyingRemoteDepth += 1;\n try {\n for (const update of updates) {\n store.apply(update);\n }\n } finally {\n applyingRemoteDepth -= 1;\n }\n },\n subscribeLocalUpdates: (listener) => {\n const unsubscribeLocalUpdates = store.subscribeLocalUpdates((update) => {\n if (applyingRemoteDepth > 0) {\n return;\n }\n listener(update);\n });\n return () => {\n unsubscribeLocalUpdates();\n };\n },\n };\n}\n\nexport const createLoroEphemeralStoreAdaptor = EphemeralStoreAdaptor;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"loro.js","names":[],"sources":["../src/loro.ts"],"sourcesContent":["import {\n decodeImportBlobMeta,\n LoroDoc,\n VersionVector,\n} from \"loro-crdt\";\n\nimport type {\n CrdtAdapter,\n CrdtApplyOutcome,\n CrdtUnresolvedSpan,\n JsonObject,\n} from \"./types\";\nimport type { EphemeralStreamAdaptor } from \"./types\";\n\nexport { EphemeralStreamCrdt } from \"./ephemeral-runtime\";\nexport { StreamsCrdt } from \"./transport-runtime\";\nexport * from \"./shared\";\n\ntype CounterSpan = {\n readonly start: number;\n readonly end: number;\n};\n\ntype LoroImportStatus = {\n readonly success: Map<string | number | bigint, CounterSpan>;\n readonly pending: Map<string | number | bigint, CounterSpan> | null;\n};\n\nfunction batchImportUpdates(\n doc: LoroDoc,\n updates: Uint8Array[],\n): LoroImportStatus {\n if (\"batchImport\" in doc && typeof doc.batchImport === \"function\") {\n return doc.batchImport(updates) as LoroImportStatus;\n }\n return doc.importBatch(updates) as LoroImportStatus;\n}\n\ntype PeerId = `${number}`;\ntype DocVersionRecord = Record<PeerId, number>;\n\nfunction toDocVersionRecord(version: VersionVector): DocVersionRecord {\n const out = {} as DocVersionRecord;\n for (const [peer, counter] of version.toJSON()) {\n out[peer as PeerId] = counter;\n }\n return out;\n}\n\nfunction toDocVersionMap(version: JsonObject): Map<PeerId, number> {\n const out = new Map<PeerId, number>();\n for (const [peer, counter] of Object.entries(version)) {\n if (typeof counter === \"number\" && Number.isFinite(counter)) {\n out.set(peer as PeerId, counter);\n }\n }\n return out;\n}\n\nfunction mergeDocVersions(\n base: DocVersionRecord,\n incoming: DocVersionRecord,\n): DocVersionRecord {\n const merged = new Map<PeerId, number>();\n for (const [peer, counter] of Object.entries(base)) {\n merged.set(peer as PeerId, counter);\n }\n for (const [peer, counter] of Object.entries(incoming)) {\n const peerId = peer as PeerId;\n merged.set(peerId, Math.max(merged.get(peerId) ?? 0, counter));\n }\n return toDocVersionRecord(VersionVector.parseJSON(merged));\n}\n\nfunction hasUpdatesSince(\n fromVersion: DocVersionRecord,\n currentVersion: DocVersionRecord,\n): boolean {\n for (const [peer, counter] of Object.entries(currentVersion)) {\n if (counter > (fromVersion[peer as PeerId] ?? 0)) {\n return true;\n }\n }\n return false;\n}\n\nfunction extractVersionFromUpdate(update: Uint8Array): DocVersionRecord | null {\n try {\n const meta = decodeImportBlobMeta(update, false);\n return toDocVersionRecord(meta.partialEndVersionVector);\n } catch {\n return null;\n }\n}\n\nfunction assertDocAttached(doc: LoroDoc): void {\n if (!doc.isDetached()) {\n return;\n }\n throw new Error(\n \"LoroDoc must be attached before using streams-crdt; \" +\n \"call checkoutToLatest() or attach() first\",\n );\n}\n\nfunction normalizePeerId(peer: string | number | bigint): PeerId {\n return `${peer}` as PeerId;\n}\n\nfunction isValidSpan(span: CounterSpan): boolean {\n return (\n Number.isSafeInteger(span.start) &&\n Number.isSafeInteger(span.end) &&\n span.start < span.end\n );\n}\n\nclass UnresolvedSpanTracker {\n private readonly spans = new Map<PeerId, CounterSpan[]>();\n\n addAll(pending: LoroImportStatus[\"pending\"]): void {\n if (pending == null) {\n return;\n }\n for (const [peer, span] of pending) {\n this.add(normalizePeerId(peer), span);\n }\n }\n\n resolveAll(success: LoroImportStatus[\"success\"]): void {\n for (const [peer, span] of success) {\n this.resolve(normalizePeerId(peer), span);\n }\n }\n\n isEmpty(): boolean {\n return this.spans.size === 0;\n }\n\n toArray(): CrdtUnresolvedSpan[] {\n const out: CrdtUnresolvedSpan[] = [];\n for (const [peer, spans] of this.spans) {\n for (const span of spans) {\n out.push({ peer, start: span.start, end: span.end });\n }\n }\n return out;\n }\n\n reset(): void {\n this.spans.clear();\n }\n\n private add(peer: PeerId, incoming: CounterSpan): void {\n if (!isValidSpan(incoming)) {\n return;\n }\n const existing = this.spans.get(peer) ?? [];\n existing.push({ start: incoming.start, end: incoming.end });\n existing.sort((a, b) => a.start - b.start || a.end - b.end);\n const merged: CounterSpan[] = [];\n for (const span of existing) {\n const last = merged[merged.length - 1];\n if (last == null || span.start > last.end) {\n merged.push({ start: span.start, end: span.end });\n } else {\n merged[merged.length - 1] = {\n start: last.start,\n end: Math.max(last.end, span.end),\n };\n }\n }\n this.spans.set(peer, merged);\n }\n\n private resolve(peer: PeerId, applied: CounterSpan): void {\n if (!isValidSpan(applied)) {\n return;\n }\n const existing = this.spans.get(peer);\n if (existing == null) {\n return;\n }\n const remaining: CounterSpan[] = [];\n for (const span of existing) {\n if (applied.end <= span.start || applied.start >= span.end) {\n remaining.push(span);\n continue;\n }\n if (span.start < applied.start) {\n remaining.push({ start: span.start, end: applied.start });\n }\n if (applied.end < span.end) {\n remaining.push({ start: applied.end, end: span.end });\n }\n }\n if (remaining.length === 0) {\n this.spans.delete(peer);\n } else {\n this.spans.set(peer, remaining);\n }\n }\n}\n\nfunction trackImportStatus(\n tracker: UnresolvedSpanTracker,\n status: LoroImportStatus,\n): void {\n tracker.addAll(status.pending);\n tracker.resolveAll(status.success);\n}\n\nfunction versionFromImportSuccess(status: LoroImportStatus): DocVersionRecord {\n const version: DocVersionRecord = {};\n for (const [peer, span] of status.success) {\n if (!isValidSpan(span)) {\n continue;\n }\n const peerId = normalizePeerId(peer);\n version[peerId] = Math.max(version[peerId] ?? 0, span.end);\n }\n return version;\n}\n\nfunction versionFromSnapshotImport(\n snapshot: Uint8Array,\n status: LoroImportStatus,\n tracker: UnresolvedSpanTracker,\n): DocVersionRecord {\n if (!tracker.isEmpty()) {\n return versionFromImportSuccess(status);\n }\n return extractVersionFromUpdate(snapshot) ?? versionFromImportSuccess(status);\n}\n\nfunction applyOutcome(\n version: DocVersionRecord,\n tracker: UnresolvedSpanTracker,\n): CrdtApplyOutcome<JsonObject> {\n const unresolved = tracker.toArray();\n return {\n version,\n complete: unresolved.length === 0,\n ...(unresolved.length === 0 ? {} : { unresolved }),\n };\n}\n\n/**\n * Creates a `CrdtAdapter` for one `LoroDoc`.\n *\n * The `LoroDoc` must be attached (not detached or checked out to a historical\n * version). If the document is detached, call `doc.checkoutToLatest()` or\n * `doc.attach()` before passing it here.\n *\n * @example\n * ```ts\n * const doc = new LoroDoc();\n * const adapter = createLoroDocAdapter(doc);\n * const transport = new StreamsCrdt({ streamUrl, adapter, auth });\n * ```\n */\nexport function createLoroDocAdapter(\n doc: LoroDoc,\n): CrdtAdapter<JsonObject> {\n const unresolved = new UnresolvedSpanTracker();\n return {\n emptyVersion: () => ({}),\n mergeVersions: (base, incoming) =>\n mergeDocVersions(base as DocVersionRecord, incoming as DocVersionRecord),\n exportSnapshot: () => {\n assertDocAttached(doc);\n return doc.export({ mode: \"snapshot\" });\n },\n applySnapshot: (snapshot) => {\n assertDocAttached(doc);\n const status = doc.import(snapshot) as LoroImportStatus;\n unresolved.reset();\n trackImportStatus(unresolved, status);\n return applyOutcome(\n versionFromSnapshotImport(snapshot, status, unresolved),\n unresolved,\n );\n },\n exportUpdates: (fromVersion) => {\n assertDocAttached(doc);\n const currentVersion = toDocVersionRecord(doc.version());\n if (\n !hasUpdatesSince(\n fromVersion as DocVersionRecord,\n currentVersion,\n )\n ) {\n return undefined;\n }\n const updates = [\n doc.export({\n mode: \"update\",\n from: VersionVector.parseJSON(toDocVersionMap(fromVersion)),\n }),\n ].filter((update) => update.byteLength > 0);\n if (updates.length === 0) {\n return undefined;\n }\n let version: DocVersionRecord = {};\n for (const update of updates) {\n const next = extractVersionFromUpdate(update);\n if (next != null) {\n version = mergeDocVersions(version, next);\n }\n }\n return {\n updates,\n version,\n };\n },\n applyRemoteUpdates: (updates, remoterVersion) => {\n assertDocAttached(doc);\n if (updates.length > 0) {\n const status = batchImportUpdates(doc, updates);\n trackImportStatus(unresolved, status);\n const version = mergeDocVersions(\n remoterVersion as DocVersionRecord,\n versionFromImportSuccess(status),\n );\n return applyOutcome(version, unresolved);\n }\n return applyOutcome(remoterVersion as DocVersionRecord, unresolved);\n },\n createIsolatedAdapter: () => {\n let isolatedDoc = new LoroDoc();\n const isolatedUnresolved = new UnresolvedSpanTracker();\n return {\n applySnapshot: (snapshot) => {\n isolatedDoc = new LoroDoc();\n isolatedUnresolved.reset();\n if (snapshot.byteLength > 0) {\n const status = isolatedDoc.import(snapshot) as LoroImportStatus;\n trackImportStatus(isolatedUnresolved, status);\n return applyOutcome(\n versionFromSnapshotImport(snapshot, status, isolatedUnresolved),\n isolatedUnresolved,\n );\n }\n return applyOutcome({}, isolatedUnresolved);\n },\n applyRemoteUpdates: (updates, remoterVersion) => {\n if (updates.length > 0) {\n const status = batchImportUpdates(isolatedDoc, updates);\n trackImportStatus(isolatedUnresolved, status);\n const version = mergeDocVersions(\n remoterVersion as DocVersionRecord,\n versionFromImportSuccess(status),\n );\n return applyOutcome(version, isolatedUnresolved);\n }\n return applyOutcome(\n remoterVersion as DocVersionRecord,\n isolatedUnresolved,\n );\n },\n };\n },\n subscribeLocalUpdates: (listener) => {\n assertDocAttached(doc);\n return doc.subscribeLocalUpdates((update) => {\n const version = extractVersionFromUpdate(update) ?? {};\n listener({ updates: [update], version });\n });\n },\n };\n}\n\n/**\n * Structural subset of Loro's `EphemeralStore`.\n */\nexport interface LoroEphemeralStoreLike {\n /** Applies one opaque Loro ephemeral update. */\n apply(update: Uint8Array): void;\n /** Subscribes to locally produced ephemeral updates. */\n subscribeLocalUpdates(listener: (update: Uint8Array) => void): () => void;\n}\n\n/**\n * Creates an ephemeral stream adaptor for a Loro `EphemeralStore`.\n *\n * @example\n * ```ts\n * const room = new EphemeralStreamCrdt({\n * streamUrl,\n * auth,\n * adaptor: EphemeralStoreAdaptor(store),\n * });\n * ```\n */\n// `ignoreBOM` keeps a leading U+FEFF as part of the key; the default strips\n// it and would alias \"\\uFEFFa\" with \"a\".\nconst utf8Decoder = new TextDecoder(\"utf-8\", { fatal: true, ignoreBOM: true });\n\n/**\n * Reads the key of a single-entry Loro ephemeral update.\n *\n * Loro encodes updates as a postcard `Vec<{ key: &str, value, timestamp }>`,\n * so a local `set`/`delete` starts with `varint(1)`, `varint(keyLen)`, key\n * bytes. Only that prefix is read; the value is never decoded. Anything else\n * (several entries, malformed bytes) returns `undefined`, which keeps the\n * update as its own queue entry.\n */\nexport function loroEphemeralUpdateKey(\n update: Uint8Array,\n): string | undefined {\n const count = readVarUint(update, 0);\n if (count == null || count.value !== 1) {\n return undefined;\n }\n const keyLength = readVarUint(update, count.next);\n if (keyLength == null) {\n return undefined;\n }\n const end = keyLength.next + keyLength.value;\n if (end > update.byteLength) {\n return undefined;\n }\n try {\n return utf8Decoder.decode(update.subarray(keyLength.next, end));\n } catch {\n return undefined;\n }\n}\n\nfunction readVarUint(\n bytes: Uint8Array,\n offset: number,\n): { value: number; next: number } | undefined {\n let value = 0;\n for (let i = 0; i < 5; i += 1) {\n const index = offset + i;\n if (index >= bytes.byteLength) {\n return undefined;\n }\n const byte = bytes[index]!;\n value += (byte & 0x7f) * 2 ** (7 * i);\n if ((byte & 0x80) === 0) {\n return { value, next: index + 1 };\n }\n }\n return undefined;\n}\n\nexport function EphemeralStoreAdaptor(\n store: LoroEphemeralStoreLike,\n): EphemeralStreamAdaptor {\n let applyingRemoteDepth = 0;\n return {\n applyRemoteUpdates: (updates) => {\n applyingRemoteDepth += 1;\n try {\n for (const update of updates) {\n store.apply(update);\n }\n } finally {\n applyingRemoteDepth -= 1;\n }\n },\n subscribeLocalUpdates: (listener) => {\n const unsubscribeLocalUpdates = store.subscribeLocalUpdates((update) => {\n if (applyingRemoteDepth > 0) {\n return;\n }\n listener(update);\n });\n return () => {\n unsubscribeLocalUpdates();\n };\n },\n localUpdateKey: loroEphemeralUpdateKey,\n };\n}\n\nexport const createLoroEphemeralStoreAdaptor = EphemeralStoreAdaptor;\n"],"mappings":"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"}
|
|
@@ -470,7 +470,7 @@ interface StreamsCrdtShardUrlsOptions {
|
|
|
470
470
|
* Origin URLs used for `GET <stream>/bootstrap`.
|
|
471
471
|
*
|
|
472
472
|
* Each entry should be an origin URL such as
|
|
473
|
-
* `https://control-a.
|
|
473
|
+
* `https://control-a.streams.example.com`. The transport keeps the
|
|
474
474
|
* stream path and query from `streamUrl` and only replaces the request origin.
|
|
475
475
|
* If omitted, `other` is used as the fallback pool for bootstrap requests.
|
|
476
476
|
*/
|
|
@@ -532,6 +532,13 @@ interface PayloadProtectionContext {
|
|
|
532
532
|
readonly protocol: "loro-streams-crdt-payload-protection";
|
|
533
533
|
readonly version: 2;
|
|
534
534
|
readonly kind: PayloadProtectionKind;
|
|
535
|
+
/**
|
|
536
|
+
* Opaque Durable Streams continuation offset for `kind: "snapshot"`.
|
|
537
|
+
* Absent for `update_batch`. streams-crdt does not parse the token, bind
|
|
538
|
+
* bucket/Org/role, or treat it as a timestamp. Providers that authenticate
|
|
539
|
+
* snapshot position MUST bind this exact string.
|
|
540
|
+
*/
|
|
541
|
+
readonly continuationOffset?: string;
|
|
535
542
|
}
|
|
536
543
|
interface PayloadProtectionSealInput {
|
|
537
544
|
readonly plaintext: Uint8Array;
|
|
@@ -719,6 +726,15 @@ interface EphemeralStreamAdaptor {
|
|
|
719
726
|
applyRemoteUpdates(updates: readonly Uint8Array[]): MaybePromise<void>;
|
|
720
727
|
/** Subscribes to local ephemeral updates. Returns an unsubscribe function. */
|
|
721
728
|
subscribeLocalUpdates(listener: (update: Uint8Array) => void): () => void;
|
|
729
|
+
/**
|
|
730
|
+
* Optional. Returns the single key a local update writes (set or delete),
|
|
731
|
+
* or `undefined` when it writes several keys or the key is unknown. The
|
|
732
|
+
* write queue then drops a queued, not yet sent update once a newer update
|
|
733
|
+
* for the same key is queued, so a burst on one key cannot delay others.
|
|
734
|
+
* Only return a key when a newer update for it fully replaces the older
|
|
735
|
+
* one for every receiver. Bodies are still sent exactly as emitted.
|
|
736
|
+
*/
|
|
737
|
+
localUpdateKey?(update: Uint8Array): string | undefined;
|
|
722
738
|
}
|
|
723
739
|
interface EphemeralStreamJoinParams {
|
|
724
740
|
/** Called when the live ephemeral subscription status changes. */
|
|
@@ -1331,7 +1347,21 @@ declare class EphemeralStreamCrdt {
|
|
|
1331
1347
|
private runReadLoop;
|
|
1332
1348
|
private enqueueLocal;
|
|
1333
1349
|
private flushPendingLocal;
|
|
1334
|
-
private
|
|
1350
|
+
private localUpdateKey;
|
|
1351
|
+
/**
|
|
1352
|
+
* Pops superseded entries off the head and returns the next entry to send,
|
|
1353
|
+
* marking it in-flight so later same-key updates queue behind it.
|
|
1354
|
+
*/
|
|
1355
|
+
private nextPendingLocal;
|
|
1356
|
+
/** Drops superseded markers once they dominate the queue (amortized O(1)). */
|
|
1357
|
+
private maybeRebuildPendingLocal;
|
|
1358
|
+
/**
|
|
1359
|
+
* Completes waiters that tracked `chainId`. Each chain is acknowledged
|
|
1360
|
+
* exactly once (its entry is never superseded after it goes in flight), so
|
|
1361
|
+
* a waiter resolves only after every chain live at call time has had its
|
|
1362
|
+
* latest value acknowledged.
|
|
1363
|
+
*/
|
|
1364
|
+
private notifyChainAcknowledged;
|
|
1335
1365
|
private rejectSyncWaiters;
|
|
1336
1366
|
private setReadStatus;
|
|
1337
1367
|
private setWriteStatus;
|
|
@@ -1365,4 +1395,4 @@ declare class PayloadProtectionError extends Error {
|
|
|
1365
1395
|
declare function isValidRillId(id: string): boolean;
|
|
1366
1396
|
//#endregion
|
|
1367
1397
|
export { WriteOnlyAppendResult as $, PayloadProtectionProviderConfig as A, StreamsAuthProvider as B, LocalSyncStats as C, PayloadProtectionOpenInput as D, PayloadProtectionKind as E, Result as F, TransportCreateStreamSuccess as G, StreamsCrdtShardUrlsOptions as H, SnapshotCodec as I, TransportJoinParams as J, TransportDeleteStreamSuccess as K, SnapshotTransformHook as L, PayloadProtectionSealInput as M, PayloadProtectionSealResult as N, PayloadProtectionOptions as O, PayloadProtectionWritePolicy as P, TransportSyncSuccess as Q, SnapshotUploadOptions as R, JsonValue as S, PayloadProtectionFailureReason as T, TransportCatchupParams as U, StreamsCrdtOptions as V, TransportCatchupSuccess as W, TransportSnapshotUploadSuccess as X, TransportRoomStatus as Y, TransportSubscription as Z, EphemeralStreamCrdtOptions as _, StreamsCrdt as a, RemoteCursor as at, IsolatedCrdtAdapter as b, CrdtApplyReturn as c, createInitialRemoteCursor as ct, E2eeOptions as d, BeforeRemoteCursorSaveContext as et, E2eeProvider as f, EphemeralStreamAdaptor as g, E2eeWritePolicy as h, EphemeralStreamCrdt as i, IndexedDbRemoteCursorStoreOptions as it, PayloadProtectionReadPolicy as j, PayloadProtectionProvider as k, CrdtUnresolvedSpan as l, E2eeReadPolicy as m, PayloadProtectionError as n, InMemoryRemoteCursorStore as nt, CrdtAdapter as o, RemoteCursorSaveSource as ot, E2eeProviderConfig as p, TransportError as q, LocalAppendFailedError as r, IndexedDbRemoteCursorStore as rt, CrdtApplyOutcome as s, RemoteCursorStore as st, isValidRillId as t, BeforeRemoteCursorSaveHook as tt, CrdtUpdateBatch as u, EphemeralStreamJoinParams as v, PayloadProtectionContext as w, JsonObject as x, EphemeralStreamSubscription as y, StreamsAuthContext as z };
|
|
1368
|
-
//# sourceMappingURL=stream-id-
|
|
1398
|
+
//# sourceMappingURL=stream-id-BEEukuNT.d.ts.map
|