loro-repo 0.1.0 → 0.3.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 +3 -0
- package/dist/{index.d.cts → index-DsCaL9JX.d.cts} +159 -111
- package/dist/{index.d.ts → index-tq65q3qY.d.ts} +160 -112
- package/dist/index.cjs +1620 -835
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1596 -840
- package/dist/index.js.map +1 -1
- package/package.json +8 -5
package/README.md
CHANGED
|
@@ -74,6 +74,9 @@ await handle.close();
|
|
|
74
74
|
- `IndexedDBStorageAdaptor` (`src/storage/indexeddb.ts`)
|
|
75
75
|
Browser storage for metadata snapshots, doc snapshots/updates, and cached assets. Swap it out for SQLite/LevelDB/file-system adaptors when running on desktop or server environments.
|
|
76
76
|
|
|
77
|
+
- `FileSystemStorageAdaptor` (`src/storage/filesystem.ts`)
|
|
78
|
+
Node-friendly persistence layer that writes metadata snapshots, doc snapshots/updates, and assets to the local file system. Point it at a writable directory (defaults to `.loro-repo` in your current working folder) when building Electron apps, desktop sync daemons, or tests that need durable state without IndexedDB.
|
|
79
|
+
|
|
77
80
|
- Asset transports
|
|
78
81
|
Bring your own `AssetTransportAdapter` (HTTP uploads, peer meshes, S3, etc.). LoroRepo dedupes via SHA-256 assetIds while your adaptor decides how to encrypt/store the bytes.
|
|
79
82
|
|
|
@@ -15,6 +15,14 @@ type GlobalBlob = typeof globalThis extends {
|
|
|
15
15
|
* Binary content accepted by asset ingestion helpers.
|
|
16
16
|
*/
|
|
17
17
|
type AssetContent = GlobalBlob | ArrayBufferView | ReadableStream<Uint8Array>;
|
|
18
|
+
interface RepoAssetMetadata {
|
|
19
|
+
readonly assetId: AssetId;
|
|
20
|
+
readonly size: number;
|
|
21
|
+
readonly createdAt: number;
|
|
22
|
+
readonly mime?: string;
|
|
23
|
+
readonly policy?: string;
|
|
24
|
+
readonly tag?: string;
|
|
25
|
+
}
|
|
18
26
|
/**
|
|
19
27
|
* JSON-compatible leaf value used for document metadata.
|
|
20
28
|
*/
|
|
@@ -48,10 +56,6 @@ interface LoroRepoOptions<_Meta extends JsonObject = JsonObject> {
|
|
|
48
56
|
* Optional adapter that moves asset payloads while keeping metadata in sync.
|
|
49
57
|
*/
|
|
50
58
|
readonly assetTransportAdapter?: AssetTransportAdapter;
|
|
51
|
-
/**
|
|
52
|
-
* Factory invoked when a document handle needs to be materialised.
|
|
53
|
-
*/
|
|
54
|
-
readonly docFactory?: (docId: string) => Promise<LoroDoc>;
|
|
55
59
|
/**
|
|
56
60
|
* Debounce duration in milliseconds before persisting document frontier metadata
|
|
57
61
|
* after local edits. Defaults to 1000 ms when omitted.
|
|
@@ -160,6 +164,8 @@ interface TransportAdapter {
|
|
|
160
164
|
* Persists metadata, documents, and asset payloads on behalf of the repo.
|
|
161
165
|
*/
|
|
162
166
|
interface StorageAdapter {
|
|
167
|
+
init?(): Promise<void>;
|
|
168
|
+
close?(): void;
|
|
163
169
|
/**
|
|
164
170
|
* Writes document snapshots, queued updates, assets, or meta bundles to durable storage.
|
|
165
171
|
*/
|
|
@@ -212,6 +218,8 @@ interface AssetUploadMetadata {
|
|
|
212
218
|
* Moves binary assets between peers or infrastructure-specific storage.
|
|
213
219
|
*/
|
|
214
220
|
interface AssetTransportAdapter {
|
|
221
|
+
init?(): Promise<void>;
|
|
222
|
+
close?(): void;
|
|
215
223
|
/**
|
|
216
224
|
* Uploads a raw asset payload using transport-managed metadata.
|
|
217
225
|
*/
|
|
@@ -334,47 +342,57 @@ interface RepoDocHandle {
|
|
|
334
342
|
*/
|
|
335
343
|
readonly doc: LoroDoc;
|
|
336
344
|
/**
|
|
337
|
-
*
|
|
345
|
+
* Sync with the transport adaptor once.
|
|
338
346
|
*/
|
|
339
|
-
readonly
|
|
347
|
+
readonly syncOnce: () => Promise<void>;
|
|
340
348
|
/**
|
|
341
|
-
*
|
|
349
|
+
* Join the realtime collaboration room.
|
|
342
350
|
*/
|
|
343
|
-
|
|
351
|
+
readonly joinRoom: (auth?: Uint8Array) => Promise<TransportSubscription>;
|
|
344
352
|
}
|
|
345
|
-
interface UpsertDocMetaOptions {}
|
|
346
353
|
/**
|
|
347
354
|
* Provenance discriminant attached to every repo event.
|
|
348
355
|
*/
|
|
349
356
|
type RepoEventBy = "local" | "sync" | "live";
|
|
350
357
|
/**
|
|
351
|
-
* Unified event envelope emitted by `watch`.
|
|
358
|
+
* Unified event envelope types emitted by `watch`.
|
|
352
359
|
*/
|
|
353
|
-
type
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
360
|
+
type RepoEventType<Meta extends JsonObject = JsonObject> = {
|
|
361
|
+
"doc-metadata": {
|
|
362
|
+
readonly kind: "doc-metadata";
|
|
363
|
+
readonly docId: string;
|
|
364
|
+
readonly patch: Partial<Meta>;
|
|
365
|
+
readonly by: RepoEventBy;
|
|
366
|
+
};
|
|
367
|
+
"doc-frontiers": {
|
|
368
|
+
readonly kind: "doc-frontiers";
|
|
369
|
+
readonly docId: string;
|
|
370
|
+
readonly frontiers: Frontiers;
|
|
371
|
+
readonly by: RepoEventBy;
|
|
372
|
+
};
|
|
373
|
+
"asset-metadata": {
|
|
374
|
+
readonly kind: "asset-metadata";
|
|
375
|
+
readonly asset: AssetDownload;
|
|
376
|
+
readonly by: RepoEventBy;
|
|
377
|
+
};
|
|
378
|
+
"asset-link": {
|
|
379
|
+
readonly kind: "asset-link";
|
|
380
|
+
readonly docId: string;
|
|
381
|
+
readonly assetId: AssetId;
|
|
382
|
+
readonly by: RepoEventBy;
|
|
383
|
+
};
|
|
384
|
+
"asset-unlink": {
|
|
385
|
+
readonly kind: "asset-unlink";
|
|
386
|
+
readonly docId: string;
|
|
387
|
+
readonly assetId: AssetId;
|
|
388
|
+
readonly by: RepoEventBy;
|
|
389
|
+
};
|
|
377
390
|
};
|
|
391
|
+
/**
|
|
392
|
+
* Discriminant union of all possible repo event types.
|
|
393
|
+
*/
|
|
394
|
+
type RepoEventKind = keyof RepoEventType;
|
|
395
|
+
type RepoEvent<Meta extends JsonObject = JsonObject> = RepoEventType<Meta>[keyof RepoEventType<Meta>];
|
|
378
396
|
/**
|
|
379
397
|
* Listener signature for `watch`.
|
|
380
398
|
*/
|
|
@@ -565,106 +583,136 @@ declare class IndexedDBStorageAdaptor implements StorageAdapter {
|
|
|
565
583
|
private createError;
|
|
566
584
|
}
|
|
567
585
|
//#endregion
|
|
568
|
-
//#region src/
|
|
569
|
-
interface
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
readonly
|
|
575
|
-
|
|
586
|
+
//#region src/storage/filesystem.d.ts
|
|
587
|
+
interface FileSystemStorageAdaptorOptions {
|
|
588
|
+
/**
|
|
589
|
+
* Base directory where metadata, document snapshots, and assets will be stored.
|
|
590
|
+
* Defaults to `.loro-repo` inside the current working directory.
|
|
591
|
+
*/
|
|
592
|
+
readonly baseDir?: string;
|
|
593
|
+
/**
|
|
594
|
+
* Subdirectory dedicated to document persistence. Defaults to `docs`.
|
|
595
|
+
*/
|
|
596
|
+
readonly docsDirName?: string;
|
|
597
|
+
/**
|
|
598
|
+
* Subdirectory dedicated to asset blobs. Defaults to `assets`.
|
|
599
|
+
*/
|
|
600
|
+
readonly assetsDirName?: string;
|
|
601
|
+
/**
|
|
602
|
+
* File name for the metadata snapshot bundle. Defaults to `meta.json`.
|
|
603
|
+
*/
|
|
604
|
+
readonly metaFileName?: string;
|
|
605
|
+
}
|
|
606
|
+
declare class FileSystemStorageAdaptor implements StorageAdapter {
|
|
607
|
+
private readonly baseDir;
|
|
608
|
+
private readonly docsDir;
|
|
609
|
+
private readonly assetsDir;
|
|
610
|
+
private readonly metaPath;
|
|
611
|
+
private readonly initPromise;
|
|
612
|
+
private updateCounter;
|
|
613
|
+
constructor(options?: FileSystemStorageAdaptorOptions);
|
|
614
|
+
save(payload: StorageSavePayload): Promise<void>;
|
|
615
|
+
deleteAsset(assetId: AssetId): Promise<void>;
|
|
616
|
+
loadDoc(docId: string): Promise<LoroDoc | undefined>;
|
|
617
|
+
loadMeta(): Promise<Flock | undefined>;
|
|
618
|
+
loadAsset(assetId: AssetId): Promise<Uint8Array | undefined>;
|
|
619
|
+
private ensureLayout;
|
|
620
|
+
private writeDocSnapshot;
|
|
621
|
+
private enqueueDocUpdate;
|
|
622
|
+
private writeAsset;
|
|
623
|
+
private docDir;
|
|
624
|
+
private docSnapshotPath;
|
|
625
|
+
private docUpdatesDir;
|
|
626
|
+
private assetPath;
|
|
576
627
|
}
|
|
628
|
+
//#endregion
|
|
629
|
+
//#region src/index.d.ts
|
|
577
630
|
declare class LoroRepo<Meta extends JsonObject = JsonObject> {
|
|
578
631
|
readonly options: LoroRepoOptions<Meta>;
|
|
632
|
+
private _destroyed;
|
|
579
633
|
private readonly transport?;
|
|
580
634
|
private readonly storage?;
|
|
581
|
-
private readonly assetTransport?;
|
|
582
|
-
private readonly docFactory;
|
|
583
635
|
private metaFlock;
|
|
584
|
-
private readonly
|
|
585
|
-
private readonly
|
|
586
|
-
private readonly
|
|
587
|
-
private readonly
|
|
588
|
-
private readonly
|
|
589
|
-
private readonly
|
|
590
|
-
private readonly
|
|
591
|
-
private readonly
|
|
592
|
-
private
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
private
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
636
|
+
private readonly eventBus;
|
|
637
|
+
private readonly docManager;
|
|
638
|
+
private readonly metadataManager;
|
|
639
|
+
private readonly assetManager;
|
|
640
|
+
private readonly assetTransport?;
|
|
641
|
+
private readonly flockHydrator;
|
|
642
|
+
private readonly state;
|
|
643
|
+
private readonly syncRunner;
|
|
644
|
+
private constructor();
|
|
645
|
+
static create<Meta extends JsonObject = JsonObject>(options: LoroRepoOptions<Meta>): Promise<LoroRepo<Meta>>;
|
|
646
|
+
/**
|
|
647
|
+
* Load meta from storage.
|
|
648
|
+
*
|
|
649
|
+
* You need to call this before all other operations to make the app functioning correctly.
|
|
650
|
+
* Though we do that implicitly already
|
|
651
|
+
*/
|
|
652
|
+
private ready;
|
|
653
|
+
/**
|
|
654
|
+
* Sync selected data via the transport adaptor
|
|
655
|
+
* @param options
|
|
656
|
+
*/
|
|
604
657
|
sync(options?: RepoSyncOptions): Promise<void>;
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
private readAssetMetadataFromFlock;
|
|
612
|
-
private handleAssetRemoval;
|
|
613
|
-
private emit;
|
|
658
|
+
/**
|
|
659
|
+
* Start syncing the metadata (Flock) room. It will establish a realtime connection to the transport adaptor.
|
|
660
|
+
* All changes on the room will be synced to the Flock, and all changes on the Flock will be synced to the room.
|
|
661
|
+
* @param params
|
|
662
|
+
* @returns
|
|
663
|
+
*/
|
|
614
664
|
joinMetaRoom(params?: TransportJoinParams): Promise<TransportSubscription>;
|
|
665
|
+
/**
|
|
666
|
+
* Start syncing the given doc. It will establish a realtime connection to the transport adaptor.
|
|
667
|
+
* All changes on the doc will be synced to the transport, and all changes on the transport will be synced to the doc.
|
|
668
|
+
*
|
|
669
|
+
* All the changes on the room will be reflected on the same doc you get from `repo.openCollaborativeDoc(docId)`
|
|
670
|
+
* @param docId
|
|
671
|
+
* @param params
|
|
672
|
+
* @returns
|
|
673
|
+
*/
|
|
615
674
|
joinDocRoom(docId: string, params?: TransportJoinParams): Promise<TransportSubscription>;
|
|
616
|
-
|
|
617
|
-
|
|
675
|
+
/**
|
|
676
|
+
* Opens a document that is automatically persisted to the configured storage adapter.
|
|
677
|
+
*
|
|
678
|
+
* - Edits are saved to storage (debounced).
|
|
679
|
+
* - Frontiers are synced to the metadata (Flock).
|
|
680
|
+
* - Realtime collaboration is NOT enabled by default; use `joinDocRoom` to connect.
|
|
681
|
+
*/
|
|
682
|
+
openPersistedDoc(docId: string): Promise<RepoDocHandle>;
|
|
683
|
+
upsertDocMeta(docId: string, patch: Partial<Meta>): Promise<void>;
|
|
618
684
|
getDocMeta(docId: string): Promise<Meta | undefined>;
|
|
619
685
|
listDoc(query?: ListDocQuery): Promise<RepoDocMeta<Meta>[]>;
|
|
620
|
-
|
|
686
|
+
getMeta(): Flock;
|
|
621
687
|
watch(listener: RepoEventListener<Meta>, filter?: RepoEventFilter<Meta>): RepoWatchHandle;
|
|
622
688
|
/**
|
|
623
|
-
* Opens
|
|
624
|
-
*
|
|
689
|
+
* Opens a detached `LoroDoc` snapshot.
|
|
690
|
+
*
|
|
691
|
+
* - **No Persistence**: Edits to this document are NOT saved to storage.
|
|
692
|
+
* - **No Sync**: This document does not participate in realtime updates.
|
|
693
|
+
* - **Use Case**: Ideal for read-only history inspection, temporary drafts, or conflict resolution without affecting the main state.
|
|
625
694
|
*/
|
|
626
|
-
|
|
695
|
+
openDetachedDoc(docId: string): Promise<LoroDoc>;
|
|
627
696
|
/**
|
|
628
|
-
*
|
|
629
|
-
*
|
|
697
|
+
* Explicitly unloads a document from memory.
|
|
698
|
+
*
|
|
699
|
+
* - **Persists Immediately**: Forces a save of the document's current state to storage.
|
|
700
|
+
* - **Frees Memory**: Removes the document from the internal cache.
|
|
701
|
+
* - **Note**: If the document is currently being synced (via `joinDocRoom`), you should also unsubscribe from the room to fully release resources.
|
|
630
702
|
*/
|
|
631
|
-
|
|
703
|
+
unloadDoc(docId: string): Promise<void>;
|
|
704
|
+
flush(): Promise<void>;
|
|
632
705
|
uploadAsset(params: UploadAssetOptions): Promise<AssetId>;
|
|
633
|
-
whenDocInSyncWithRemote(docId: string): Promise<void>;
|
|
634
706
|
linkAsset(docId: string, params: LinkAssetOptions): Promise<AssetId>;
|
|
635
707
|
fetchAsset(assetId: AssetId): Promise<AssetDownload>;
|
|
636
708
|
unlinkAsset(docId: string, assetId: AssetId): Promise<void>;
|
|
637
709
|
listAssets(docId: string): Promise<RepoAssetMetadata[]>;
|
|
638
710
|
ensureAsset(assetId: AssetId): Promise<AssetDownload>;
|
|
639
|
-
private createAssetDownload;
|
|
640
|
-
private materializeAsset;
|
|
641
|
-
private updateDocAssetMetadata;
|
|
642
711
|
gcAssets(options?: GarbageCollectionOptions): Promise<number>;
|
|
643
|
-
private onDocHandleClose;
|
|
644
|
-
private ensureDoc;
|
|
645
|
-
private materializeDetachedDoc;
|
|
646
|
-
private exportDocSnapshot;
|
|
647
712
|
private persistMeta;
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
private pushEventBy;
|
|
651
|
-
private popEventBy;
|
|
652
|
-
private resolveEventBy;
|
|
653
|
-
private ensureMetaLiveMonitor;
|
|
654
|
-
private applyMetaFlockEvents;
|
|
655
|
-
private registerDoc;
|
|
656
|
-
private ensureDocSubscription;
|
|
657
|
-
private rememberAsset;
|
|
658
|
-
private scheduleDocFrontierUpdate;
|
|
659
|
-
private mergeRepoEventBy;
|
|
660
|
-
private runScheduledDocFrontierUpdate;
|
|
661
|
-
private flushScheduledDocFrontierUpdate;
|
|
662
|
-
private onDocEvent;
|
|
663
|
-
private getAssetMetadata;
|
|
664
|
-
private updateDocFrontiers;
|
|
665
|
-
private hydrateMetadataFromFlock;
|
|
666
|
-
private shouldNotify;
|
|
713
|
+
get destroyed(): boolean;
|
|
714
|
+
destroy(): Promise<void>;
|
|
667
715
|
}
|
|
668
716
|
//#endregion
|
|
669
|
-
export { AssetContent, AssetDownload, AssetId, AssetTransportAdapter, AssetUploadMetadata, BroadcastChannelTransportAdapter, type BroadcastChannelTransportOptions, GarbageCollectionOptions, IndexedDBStorageAdaptor, type IndexedDBStorageAdaptorOptions, JsonObject, JsonValue, LinkAssetOptions, ListDocQuery, LoroRepo, LoroRepoOptions, RepoAssetMetadata, RepoDocHandle, RepoDocMeta, RepoEvent, RepoEventBy, RepoEventFilter, RepoEventListener, type RepoSyncOptions, RepoWatchHandle, StorageAdapter, StorageSavePayload, SyncScope, TransportAdapter, type TransportJoinParams, type TransportSubscription, TransportSyncRequest, type TransportSyncResult, UploadAssetOptions,
|
|
670
|
-
//# sourceMappingURL=index.d.cts.map
|
|
717
|
+
export { AssetContent, AssetDownload, AssetId, AssetTransportAdapter, AssetUploadMetadata, BroadcastChannelTransportAdapter, type BroadcastChannelTransportOptions, FileSystemStorageAdaptor, type FileSystemStorageAdaptorOptions, GarbageCollectionOptions, IndexedDBStorageAdaptor, type IndexedDBStorageAdaptorOptions, JsonObject, JsonValue, LinkAssetOptions, ListDocQuery, LoroRepo, LoroRepoOptions, RepoAssetMetadata, RepoDocHandle, RepoDocMeta, RepoEvent, RepoEventBy, RepoEventFilter, RepoEventKind, RepoEventListener, RepoEventType, type RepoSyncOptions, RepoWatchHandle, StorageAdapter, StorageSavePayload, SyncScope, TransportAdapter, type TransportJoinParams, type TransportSubscription, TransportSyncRequest, type TransportSyncResult, UploadAssetOptions, WebSocketTransportAdapter, WebSocketTransportOptions };
|
|
718
|
+
//# sourceMappingURL=index-DsCaL9JX.d.cts.map
|