@loro-dev/streams-crdt 0.6.1 → 0.7.1
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 +305 -1
- package/dist/flock.d.ts +2 -2
- package/dist/flock.js +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/loro.d.ts +2 -2
- package/dist/loro.js +2 -2
- package/dist/{stream-id-Dr8ZBpUQ.d.ts → stream-id-CS7SzuLW.d.ts} +148 -2
- package/dist/{stream-id-0dTFsiaO.js → stream-id-D0qcbI5c.js} +697 -163
- package/dist/stream-id-D0qcbI5c.js.map +1 -0
- package/package.json +5 -3
- package/dist/stream-id-0dTFsiaO.js.map +0 -1
|
@@ -213,7 +213,21 @@ type TransportError = {
|
|
|
213
213
|
readonly code: "unknown";
|
|
214
214
|
readonly retryable: false;
|
|
215
215
|
readonly message: string;
|
|
216
|
+
} | {
|
|
217
|
+
readonly code: "payload_protection_error";
|
|
218
|
+
readonly retryable: false;
|
|
219
|
+
readonly reason: "plaintext_forbidden" | "missing_read_key" | "decrypt_failed" | "invalid_envelope" | "wrong_payload_kind" | "encrypt_failed";
|
|
220
|
+
readonly keyId?: string;
|
|
221
|
+
readonly message: string;
|
|
216
222
|
};
|
|
223
|
+
interface WriteOnlyAppendResult<TVersion extends JsonObject> {
|
|
224
|
+
/** Whether this call found and appended local CRDT updates. */
|
|
225
|
+
readonly appended: boolean;
|
|
226
|
+
/** Server tail offset returned by the append request. Omitted when `appended` is false. */
|
|
227
|
+
readonly nextOffset?: string;
|
|
228
|
+
/** Local CRDT version exported by this runtime's append-only path. */
|
|
229
|
+
readonly localVersion: TVersion;
|
|
230
|
+
}
|
|
217
231
|
/**
|
|
218
232
|
* Result payload returned by `createStream()`.
|
|
219
233
|
*/
|
|
@@ -232,6 +246,13 @@ interface TransportDeleteStreamSuccess {
|
|
|
232
246
|
interface TransportSyncSuccess<TVersion extends JsonObject = JsonObject> {
|
|
233
247
|
readonly cursor: RemoteCursor<TVersion>;
|
|
234
248
|
}
|
|
249
|
+
/**
|
|
250
|
+
* Result payload returned by the internal snapshot upload test hook.
|
|
251
|
+
*/
|
|
252
|
+
interface TransportSnapshotUploadSuccess {
|
|
253
|
+
readonly snapshotOffset: string;
|
|
254
|
+
readonly snapshotByteLength: number;
|
|
255
|
+
}
|
|
235
256
|
/**
|
|
236
257
|
* Optional parameters for a `join()` call.
|
|
237
258
|
*
|
|
@@ -282,6 +303,54 @@ interface SnapshotCodec {
|
|
|
282
303
|
readonly compress: SnapshotTransformHook;
|
|
283
304
|
readonly decompress: SnapshotTransformHook;
|
|
284
305
|
}
|
|
306
|
+
type PayloadProtectionReadPolicy = "encrypted-only" | "allow-plaintext";
|
|
307
|
+
type PayloadProtectionWritePolicy = "encrypt" | "plaintext";
|
|
308
|
+
type PayloadProtectionScope = string | {
|
|
309
|
+
readonly bucketId: string;
|
|
310
|
+
readonly streamId: string;
|
|
311
|
+
};
|
|
312
|
+
interface PayloadProtectionKey {
|
|
313
|
+
readonly id: string;
|
|
314
|
+
readonly key: CryptoKey | Uint8Array;
|
|
315
|
+
}
|
|
316
|
+
type PayloadProtectionKeyProvider = () => MaybePromise<readonly PayloadProtectionKey[]>;
|
|
317
|
+
interface PayloadProtectionEncryptionOptions {
|
|
318
|
+
/**
|
|
319
|
+
* Stable encryption context authenticated with every encrypted payload.
|
|
320
|
+
*
|
|
321
|
+
* Prefer bucket/stream identity or an application-stable string. Do not use
|
|
322
|
+
* a full gateway URL unless old encrypted bytes should become unreadable
|
|
323
|
+
* after host/proxy migration.
|
|
324
|
+
*/
|
|
325
|
+
readonly scope: PayloadProtectionScope;
|
|
326
|
+
/** Key used for new encrypted writes. Required when writePolicy is "encrypt". */
|
|
327
|
+
readonly writeKey?: PayloadProtectionKey;
|
|
328
|
+
/**
|
|
329
|
+
* Keys accepted for remote encrypted reads.
|
|
330
|
+
*
|
|
331
|
+
* When omitted, `writeKey` is also used as the only read key.
|
|
332
|
+
*/
|
|
333
|
+
readonly readKeys?: readonly PayloadProtectionKey[] | PayloadProtectionKeyProvider;
|
|
334
|
+
}
|
|
335
|
+
interface PayloadProtectionOptions {
|
|
336
|
+
/**
|
|
337
|
+
* Remote plaintext policy. Defaults to "encrypted-only" when
|
|
338
|
+
* E2EE is provided.
|
|
339
|
+
*/
|
|
340
|
+
readonly readPolicy?: PayloadProtectionReadPolicy;
|
|
341
|
+
/**
|
|
342
|
+
* Local write policy. Defaults to "encrypt" when E2EE is provided.
|
|
343
|
+
*/
|
|
344
|
+
readonly writePolicy?: PayloadProtectionWritePolicy;
|
|
345
|
+
readonly encryption?: PayloadProtectionEncryptionOptions;
|
|
346
|
+
}
|
|
347
|
+
type E2eeReadPolicy = PayloadProtectionReadPolicy;
|
|
348
|
+
type E2eeWritePolicy = PayloadProtectionWritePolicy;
|
|
349
|
+
type E2eeScope = PayloadProtectionScope;
|
|
350
|
+
type E2eeKey = PayloadProtectionKey;
|
|
351
|
+
type E2eeKeyProvider = PayloadProtectionKeyProvider;
|
|
352
|
+
type E2eeEncryptionOptions = PayloadProtectionEncryptionOptions;
|
|
353
|
+
type E2eeOptions = PayloadProtectionOptions;
|
|
285
354
|
/**
|
|
286
355
|
* Active live subscription returned by `join()`.
|
|
287
356
|
*
|
|
@@ -295,6 +364,14 @@ interface TransportSubscription {
|
|
|
295
364
|
readonly connected: boolean;
|
|
296
365
|
/** Current room status. */
|
|
297
366
|
readonly status: TransportRoomStatus;
|
|
367
|
+
/**
|
|
368
|
+
* The last transport error observed, if any.
|
|
369
|
+
*
|
|
370
|
+
* Updated when the room transitions to `"error"` or `"disconnected"`.
|
|
371
|
+
* Cleared on successful recovery. Callers can inspect this to decide
|
|
372
|
+
* whether to retry, surface auth failure, or mark the room as terminal.
|
|
373
|
+
*/
|
|
374
|
+
readonly lastError?: TransportError;
|
|
298
375
|
/** Registers a status listener. Returns an unsubscribe function. */
|
|
299
376
|
readonly onStatusChange: (listener: (status: "connecting" | TransportRoomStatus) => void) => () => void;
|
|
300
377
|
/**
|
|
@@ -309,6 +386,9 @@ interface TransportSubscription {
|
|
|
309
386
|
*
|
|
310
387
|
* The promise rejects if the flush encounters a non-recoverable error or
|
|
311
388
|
* all subscriptions are closed before all pending changes are confirmed.
|
|
389
|
+
*
|
|
390
|
+
* If the initial join sync has failed and not yet recovered, the promise
|
|
391
|
+
* rejects immediately with a structured error indicating the failure.
|
|
312
392
|
*/
|
|
313
393
|
readonly waitUntilSynced: () => Promise<void>;
|
|
314
394
|
}
|
|
@@ -437,6 +517,16 @@ interface StreamsCrdtOptions<TVersion extends JsonObject> {
|
|
|
437
517
|
* the server.
|
|
438
518
|
*/
|
|
439
519
|
readonly snapshotCodec?: SnapshotCodec;
|
|
520
|
+
/**
|
|
521
|
+
* E2EE and mixed encrypted/plaintext payload behavior.
|
|
522
|
+
*/
|
|
523
|
+
readonly e2ee?: E2eeOptions;
|
|
524
|
+
/**
|
|
525
|
+
* Deprecated alias for `e2ee`.
|
|
526
|
+
*
|
|
527
|
+
* Prefer `e2ee`. Passing both `e2ee` and `payloadProtection` is an error.
|
|
528
|
+
*/
|
|
529
|
+
readonly payloadProtection?: PayloadProtectionOptions;
|
|
440
530
|
readonly snapshotUpload?: SnapshotUploadOptions;
|
|
441
531
|
readonly reconnectConfig?: Partial<ReconnectConfig>;
|
|
442
532
|
readonly debug?: boolean;
|
|
@@ -445,9 +535,25 @@ interface StreamsCrdtLike<TVersion extends JsonObject> {
|
|
|
445
535
|
createStream(): Promise<Result<TransportCreateStreamSuccess, TransportError>>;
|
|
446
536
|
deleteStream(): Promise<Result<TransportDeleteStreamSuccess, TransportError>>;
|
|
447
537
|
sync(): Promise<Result<TransportSyncSuccess<TVersion>, TransportError>>;
|
|
538
|
+
/**
|
|
539
|
+
* Appends only locally observed batches without reading remote state first.
|
|
540
|
+
*
|
|
541
|
+
* This is the write-only path for actors that may POST but may not bootstrap,
|
|
542
|
+
* catch up, or join live reads. It must not be mixed with `sync()`/`join()`
|
|
543
|
+
* on the same instance, and `close()` permanently disables it for that
|
|
544
|
+
* instance.
|
|
545
|
+
*/
|
|
546
|
+
appendWriteOnly(): Promise<Result<WriteOnlyAppendResult<TVersion>, TransportError>>;
|
|
448
547
|
join(params?: TransportJoinParams): Promise<Result<TransportSubscription, TransportError>>;
|
|
449
548
|
/** Resets retry state and immediately attempts to reconnect all rooms. */
|
|
450
549
|
rejoin(): void;
|
|
550
|
+
/**
|
|
551
|
+
* Closes the active join and releases transport-owned resources.
|
|
552
|
+
*
|
|
553
|
+
* If this instance was using `appendWriteOnly()`, closing also tears down the
|
|
554
|
+
* write-only subscription. Create a new instance to use the write-only path
|
|
555
|
+
* again later.
|
|
556
|
+
*/
|
|
451
557
|
close(): Promise<void>;
|
|
452
558
|
getSnapshotOffset(): Promise<Result<string | null, TransportError>>;
|
|
453
559
|
readonly streamUrl: string;
|
|
@@ -468,6 +574,10 @@ declare class StreamsCrdt<TVersion extends JsonObject> implements StreamsCrdtLik
|
|
|
468
574
|
private readonly cursorManager;
|
|
469
575
|
private readonly volatileCursorManager;
|
|
470
576
|
private readonly decodeSnapshot?;
|
|
577
|
+
private readonly encodeSnapshot?;
|
|
578
|
+
private readonly decodeUpdateItems?;
|
|
579
|
+
private readonly encodeUpdateItems?;
|
|
580
|
+
private readonly measureUpdateItemsByteLength?;
|
|
471
581
|
private readonly reconnectConfig;
|
|
472
582
|
private readonly debug;
|
|
473
583
|
private readonly beforeRemoteCursorSave?;
|
|
@@ -475,6 +585,10 @@ declare class StreamsCrdt<TVersion extends JsonObject> implements StreamsCrdtLik
|
|
|
475
585
|
private readonly producerId;
|
|
476
586
|
private producerEpoch;
|
|
477
587
|
private nextProducerSeq;
|
|
588
|
+
private readonly pendingWriteOnly;
|
|
589
|
+
private writeOnlyCursor;
|
|
590
|
+
private unsubscribeWriteOnlyLocal?;
|
|
591
|
+
private writeOnlyDisabledReason?;
|
|
478
592
|
private joinState?;
|
|
479
593
|
private opQueue;
|
|
480
594
|
/**
|
|
@@ -486,6 +600,8 @@ declare class StreamsCrdt<TVersion extends JsonObject> implements StreamsCrdtLik
|
|
|
486
600
|
* Creates a transport for one stream URL and one local adapter instance.
|
|
487
601
|
*/
|
|
488
602
|
constructor(options: StreamsCrdtOptions<TVersion>);
|
|
603
|
+
private composeSnapshotDecoder;
|
|
604
|
+
private composeSnapshotEncoder;
|
|
489
605
|
/**
|
|
490
606
|
* Stops any active live join and releases transport-owned state.
|
|
491
607
|
*/
|
|
@@ -505,6 +621,13 @@ declare class StreamsCrdt<TVersion extends JsonObject> implements StreamsCrdtLik
|
|
|
505
621
|
* Reads the latest remote snapshot offset, if the server exposes one.
|
|
506
622
|
*/
|
|
507
623
|
getSnapshotOffset(): Promise<Result<string | null, TransportError>>;
|
|
624
|
+
/**
|
|
625
|
+
* Uploads a full adapter snapshot at the current remote tail.
|
|
626
|
+
*
|
|
627
|
+
* @internal Intended for end-to-end tests that must deterministically create
|
|
628
|
+
* a remote snapshot without waiting for the best-effort join() debounce.
|
|
629
|
+
*/
|
|
630
|
+
uploadSnapshotForTesting(): Promise<Result<TransportSnapshotUploadSuccess, TransportError>>;
|
|
508
631
|
/**
|
|
509
632
|
* Explicitly creates the target stream.
|
|
510
633
|
*/
|
|
@@ -517,6 +640,14 @@ declare class StreamsCrdt<TVersion extends JsonObject> implements StreamsCrdtLik
|
|
|
517
640
|
* Runs one bootstrap/catch-up cycle without entering live mode.
|
|
518
641
|
*/
|
|
519
642
|
sync(): Promise<Result<TransportSyncSuccess<TVersion>, TransportError>>;
|
|
643
|
+
/**
|
|
644
|
+
* Appends local CRDT updates without reading the stream first.
|
|
645
|
+
*
|
|
646
|
+
* Use this for write-only actors whose auth token may POST to the stream but
|
|
647
|
+
* may not bootstrap, catch up, or join live reads. The method does not save a
|
|
648
|
+
* RemoteCursorStore cursor and does not apply remote updates.
|
|
649
|
+
*/
|
|
650
|
+
appendWriteOnly(): Promise<Result<WriteOnlyAppendResult<TVersion>, TransportError>>;
|
|
520
651
|
/**
|
|
521
652
|
* Replays remote state, flushes queued local updates, then enters live read mode.
|
|
522
653
|
*/
|
|
@@ -558,7 +689,9 @@ declare class StreamsCrdt<TVersion extends JsonObject> implements StreamsCrdtLik
|
|
|
558
689
|
*
|
|
559
690
|
* Returns `undefined` when the queue is empty.
|
|
560
691
|
*/
|
|
692
|
+
private drainQueuedBatch;
|
|
561
693
|
private drainPendingBatch;
|
|
694
|
+
private drainPendingWriteOnlyBatch;
|
|
562
695
|
private flushPendingLocal;
|
|
563
696
|
/**
|
|
564
697
|
* Decrements all sync waiters by the number of flushed batches and
|
|
@@ -573,10 +706,23 @@ declare class StreamsCrdt<TVersion extends JsonObject> implements StreamsCrdtLik
|
|
|
573
706
|
private recomputeJoinStatus;
|
|
574
707
|
private computeOverallStatus;
|
|
575
708
|
private enqueueExclusive;
|
|
709
|
+
private measureAppendBodyByteLength;
|
|
710
|
+
private disableWriteOnlyMode;
|
|
576
711
|
private logDebug;
|
|
577
712
|
private logError;
|
|
578
713
|
}
|
|
579
714
|
//#endregion
|
|
715
|
+
//#region src/payload-protection.d.ts
|
|
716
|
+
type PayloadProtectionFailureReason = "plaintext_forbidden" | "missing_read_key" | "decrypt_failed" | "invalid_envelope" | "wrong_payload_kind" | "encrypt_failed";
|
|
717
|
+
declare class PayloadProtectionError extends Error {
|
|
718
|
+
readonly reason: PayloadProtectionFailureReason;
|
|
719
|
+
readonly keyId?: string;
|
|
720
|
+
constructor(reason: PayloadProtectionFailureReason, message: string, options?: {
|
|
721
|
+
readonly keyId?: string;
|
|
722
|
+
readonly cause?: unknown;
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
//#endregion
|
|
580
726
|
//#region src/stream-id.d.ts
|
|
581
727
|
/**
|
|
582
728
|
* Validates a stream id accepted by `createStreamUrl()`.
|
|
@@ -595,5 +741,5 @@ declare function createStreamUrl(input: {
|
|
|
595
741
|
baseUrl?: string;
|
|
596
742
|
}): string;
|
|
597
743
|
//#endregion
|
|
598
|
-
export {
|
|
599
|
-
//# sourceMappingURL=stream-id-
|
|
744
|
+
export { StreamsAuthProvider as A, WriteOnlyAppendResult as B, PayloadProtectionScope as C, SnapshotTransformHook as D, SnapshotCodec as E, TransportJoinParams as F, IndexedDbRemoteCursorStoreOptions as G, BeforeRemoteCursorSaveHook as H, TransportRoomStatus as I, RemoteCursorStore as J, RemoteCursor as K, TransportSnapshotUploadSuccess as L, TransportCreateStreamSuccess as M, TransportDeleteStreamSuccess as N, SnapshotUploadOptions as O, TransportError as P, TransportSubscription as R, PayloadProtectionReadPolicy as S, Result as T, InMemoryRemoteCursorStore as U, BeforeRemoteCursorSaveContext as V, IndexedDbRemoteCursorStore as W, createInitialRemoteCursor as Y, JsonValue as _, StreamsCrdt as a, PayloadProtectionKeyProvider as b, E2eeEncryptionOptions as c, E2eeOptions as d, E2eeReadPolicy as f, JsonObject as g, IsolatedCrdtAdapter as h, PayloadProtectionError as i, StreamsCrdtOptions as j, StreamsAuthContext as k, E2eeKey as l, E2eeWritePolicy as m, isValidBucketId as n, CrdtAdapter as o, E2eeScope as p, RemoteCursorSaveSource as q, isValidRillId as r, CrdtUpdateBatch as s, createStreamUrl as t, E2eeKeyProvider as u, PayloadProtectionEncryptionOptions as v, PayloadProtectionWritePolicy as w, PayloadProtectionOptions as x, PayloadProtectionKey as y, TransportSyncSuccess as z };
|
|
745
|
+
//# sourceMappingURL=stream-id-CS7SzuLW.d.ts.map
|