loro-repo 0.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 +132 -0
- package/dist/index.cjs +2173 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +670 -0
- package/dist/index.d.ts +670 -0
- package/dist/index.js +2170 -0
- package/dist/index.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["subscription: TransportSubscription","session: MetadataSession","session: DocSession","resolve!: () => void","listener: MetaListener","listener: DocListener","state: DocChannelState","doc: LoroDoc","consolidated: Uint8Array","queue: Uint8Array[]","chunks: Uint8Array[]","bytesToHex","arr: JsonValue[]","obj: JsonObject","patch: JsonObject","json: JsonObject","record: JsonObject","recordedEvents: FlockEvent[]","added: AssetId[]","removed: AssetId[]","docMeta: JsonObject","affectedDocs: string[]","wrapped: TransportSubscription","next: JsonObject","outPatch: JsonObject","canonical: JsonValue | undefined","entries: RepoDocMeta<Meta>[]","entry: WatchEntry<Meta>","metadata","metadata: RepoAssetMetadata","storedBytes: Uint8Array | undefined","by: RepoEventBy","removedAssets: Array<[AssetId, AssetRecord]>"],"sources":["../src/loro-adaptor.ts","../src/transport/websocket.ts","../src/transport/broadcast-channel.ts","../src/storage/indexeddb.ts","../src/index.ts"],"sourcesContent":["import { Flock } from \"@loro-dev/flock\";\nimport { LoroDoc } from \"loro-crdt\";\nimport {\n FlockAdaptor,\n type FlockAdaptorConfig,\n LoroAdaptor,\n type LoroAdaptorConfig,\n} from \"loro-adaptors\";\n\nexport type RepoLoroAdaptorConfig = LoroAdaptorConfig;\nexport type RepoFlockAdaptorConfig = FlockAdaptorConfig;\n\nexport { LoroAdaptor as RepoLoroAdaptor } from \"loro-adaptors\";\nexport { FlockAdaptor as RepoFlockAdaptor } from \"loro-adaptors\";\n\nexport function createRepoLoroAdaptor(\n config: RepoLoroAdaptorConfig = {},\n): LoroAdaptor {\n return new LoroAdaptor(new LoroDoc(), config);\n}\n\nexport function createRepoLoroAdaptorFromDoc(\n doc: LoroDoc,\n config: RepoLoroAdaptorConfig = {},\n): LoroAdaptor {\n return new LoroAdaptor(doc, config);\n}\n\nexport interface RepoCreateFlockAdaptorOptions extends RepoFlockAdaptorConfig {\n peerId?: Uint8Array;\n}\n\nexport function createRepoFlockAdaptor(\n options: RepoCreateFlockAdaptorOptions = {},\n): FlockAdaptor {\n const { peerId, ...config } = options;\n const flock = new Flock(peerId);\n return new FlockAdaptor(flock, config);\n}\n\nexport function createRepoFlockAdaptorFromDoc(\n flock: Flock,\n config: RepoFlockAdaptorConfig = {},\n): FlockAdaptor {\n return new FlockAdaptor(flock, config);\n}\n","import { Flock } from \"@loro-dev/flock\";\nimport { LoroDoc } from \"loro-crdt\";\nimport { createLoroAdaptorFromDoc, type CrdtDocAdaptor } from \"loro-adaptors\";\nimport { CrdtType, bytesToHex } from \"loro-protocol\";\nimport {\n LoroWebsocketClient,\n type LoroWebsocketClientOptions,\n type LoroWebsocketClientRoom,\n} from \"loro-websocket\";\n\nimport {\n createRepoFlockAdaptorFromDoc,\n type RepoFlockAdaptorConfig,\n} from \"../loro-adaptor\";\n\nimport type {\n RepoSyncOptions,\n TransportAdapter,\n TransportJoinParams,\n TransportSubscription,\n TransportSyncResult,\n} from \"../types\";\n\ntype MetadataSession = {\n adaptor: CrdtDocAdaptor;\n room: LoroWebsocketClientRoom;\n firstSynced: Promise<void>;\n flock: Flock;\n roomId: string;\n auth?: Uint8Array;\n refCount: number;\n};\n\ntype DocSession = {\n adaptor: CrdtDocAdaptor;\n room: LoroWebsocketClientRoom;\n firstSynced: Promise<void>;\n doc: LoroDoc;\n roomId: string;\n refCount: number;\n};\n\nfunction withTimeout<T>(promise: Promise<T>, timeoutMs?: number): Promise<T> {\n if (!timeoutMs || timeoutMs <= 0) {\n return promise;\n }\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(new Error(`Operation timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n promise\n .then((value) => {\n clearTimeout(timer);\n resolve(value);\n })\n .catch((error) => {\n clearTimeout(timer);\n reject(error);\n });\n });\n}\n\nfunction normalizeRoomId(roomId: unknown, fallback: string): string {\n if (typeof roomId === \"string\" && roomId.length > 0) {\n return roomId;\n }\n if (roomId instanceof Uint8Array && roomId.length > 0) {\n try {\n return bytesToHex(roomId);\n } catch {\n return fallback;\n }\n }\n return fallback;\n}\n\nexport interface WebSocketTransportOptions {\n /**\n * WebSocket endpoint provided to the loro-websocket client.\n */\n readonly url: string;\n /**\n * Optional loro-websocket client configuration.\n */\n readonly client?: Omit<LoroWebsocketClientOptions, \"url\">;\n /**\n * Metadata room identifier. When omitted, metadata synchronisation is disabled.\n */\n readonly metadataRoomId?: string;\n /**\n * Overrides the CRDT type advertised for the metadata room (defaults to `%FLO`).\n * Only `%FLO` is supported.\n */\n readonly metadataCrdtType?: string;\n /**\n * Optional adaptor configuration for metadata joins.\n */\n readonly metadataAdaptorConfig?: RepoFlockAdaptorConfig;\n /**\n * Static auth payload for metadata joins.\n */\n readonly metadataAuth?: Uint8Array;\n /**\n * Factory that maps document ids to room identifiers. Defaults to the doc id.\n */\n readonly docRoomId?: (docId: string) => string;\n /**\n * Optional auth provider for document joins.\n */\n readonly docAuth?: (docId: string) => Uint8Array | undefined;\n}\n\nfunction bytesEqual(a?: Uint8Array, b?: Uint8Array): boolean {\n if (a === b) return true;\n if (!a || !b) return false;\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i += 1) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n}\n\n/**\n * loro-websocket backed {@link TransportAdapter} implementation for LoroRepo.\n */\nexport class WebSocketTransportAdapter implements TransportAdapter {\n private readonly options: WebSocketTransportOptions;\n private client?: LoroWebsocketClient;\n private metadataSession?: MetadataSession;\n private readonly docSessions = new Map<string, DocSession>();\n\n constructor(options: WebSocketTransportOptions) {\n this.options = options;\n }\n\n async connect(_options?: { timeout?: number }): Promise<void> {\n const client = this.ensureClient();\n await client.connect();\n await client.waitConnected();\n }\n\n async close(): Promise<void> {\n for (const [docId] of this.docSessions) {\n await this.leaveDocSession(docId).catch(() => {});\n }\n this.docSessions.clear();\n\n await this.teardownMetadataSession().catch(() => {});\n\n if (this.client) {\n this.client.destroy();\n this.client = undefined;\n }\n }\n\n isConnected(): boolean {\n return this.client?.getStatus() === \"connected\";\n }\n\n async syncMeta(\n flock: Flock,\n options?: { timeout?: number },\n ): Promise<TransportSyncResult> {\n if (!this.options.metadataRoomId) {\n return { ok: true };\n }\n try {\n const session = await this.ensureMetadataSession(flock, {\n roomId: this.options.metadataRoomId,\n auth: this.options.metadataAuth,\n });\n await withTimeout(session.firstSynced, options?.timeout);\n return { ok: true };\n } catch {\n return { ok: false };\n }\n }\n\n joinMetaRoom(\n flock: Flock,\n params?: TransportJoinParams,\n ): TransportSubscription {\n const fallback = this.options.metadataRoomId ?? \"\";\n const roomId = normalizeRoomId(params?.roomId, fallback);\n if (!roomId) {\n throw new Error(\"Metadata room id not configured\");\n }\n const auth = params?.auth ?? this.options.metadataAuth;\n const ensure = this.ensureMetadataSession(flock, {\n roomId,\n auth,\n });\n const firstSynced = ensure.then((session) => session.firstSynced);\n const getConnected = () => this.isConnected();\n const subscription: TransportSubscription = {\n unsubscribe: () => {\n void ensure.then((session) => {\n session.refCount = Math.max(0, session.refCount - 1);\n if (session.refCount === 0) {\n void this.teardownMetadataSession(session).catch(() => {});\n }\n });\n },\n firstSyncedWithRemote: firstSynced,\n get connected() {\n return getConnected();\n },\n };\n void ensure.then((session) => {\n session.refCount += 1;\n });\n return subscription;\n }\n\n async syncDoc(\n docId: string,\n doc: LoroDoc,\n options?: { timeout?: number },\n ): Promise<TransportSyncResult> {\n try {\n const session = await this.ensureDocSession(docId, doc, {});\n await withTimeout(session.firstSynced, options?.timeout);\n return { ok: true };\n } catch {\n return { ok: false };\n }\n }\n\n joinDocRoom(\n docId: string,\n doc: LoroDoc,\n params?: TransportJoinParams,\n ): TransportSubscription {\n const ensure = this.ensureDocSession(docId, doc, params ?? {});\n const firstSynced = ensure.then((session) => session.firstSynced);\n const getConnected = () => this.isConnected();\n const subscription: TransportSubscription = {\n unsubscribe: () => {\n void ensure.then((session) => {\n session.refCount = Math.max(0, session.refCount - 1);\n if (session.refCount === 0) {\n void this.leaveDocSession(docId).catch(() => {});\n }\n });\n },\n firstSyncedWithRemote: firstSynced,\n get connected() {\n return getConnected();\n },\n };\n void ensure.then((session) => {\n session.refCount += 1;\n });\n return subscription;\n }\n\n private ensureClient(): LoroWebsocketClient {\n if (this.client) {\n return this.client;\n }\n const { url, client: clientOptions } = this.options;\n const client = new LoroWebsocketClient({\n url,\n ...clientOptions,\n });\n this.client = client;\n return client;\n }\n\n private async ensureMetadataSession(\n flock: Flock,\n params: { roomId: string; auth?: Uint8Array },\n ): Promise<MetadataSession> {\n const client = this.ensureClient();\n await client.waitConnected();\n\n if (\n this.metadataSession &&\n this.metadataSession.flock === flock &&\n this.metadataSession.roomId === params.roomId &&\n bytesEqual(this.metadataSession.auth, params.auth)\n ) {\n return this.metadataSession;\n }\n\n if (this.metadataSession) {\n await this.teardownMetadataSession(this.metadataSession).catch(() => {});\n }\n\n const configuredType = this.options.metadataCrdtType;\n if (configuredType && configuredType !== CrdtType.Flock) {\n throw new Error(\n `metadataCrdtType must be ${CrdtType.Flock} when syncing Flock metadata`,\n );\n }\n const adaptor = createRepoFlockAdaptorFromDoc(\n flock,\n this.options.metadataAdaptorConfig ?? {},\n );\n const room = await client.join({\n roomId: params.roomId,\n crdtAdaptor: adaptor,\n auth: params.auth,\n });\n const firstSynced = room.waitForReachingServerVersion();\n const session: MetadataSession = {\n adaptor,\n room,\n firstSynced,\n flock,\n roomId: params.roomId,\n auth: params.auth,\n refCount: 0,\n };\n this.metadataSession = session;\n return session;\n }\n\n private async teardownMetadataSession(\n session?: MetadataSession,\n ): Promise<void> {\n const target = session ?? this.metadataSession;\n if (!target) return;\n if (this.metadataSession === target) {\n this.metadataSession = undefined;\n }\n const { adaptor, room } = target;\n try {\n await room.leave();\n } catch {\n await room.destroy().catch(() => {});\n }\n adaptor.destroy();\n }\n\n private async ensureDocSession(\n docId: string,\n doc: LoroDoc,\n params: TransportJoinParams,\n ): Promise<DocSession> {\n const client = this.ensureClient();\n await client.waitConnected();\n\n const existing = this.docSessions.get(docId);\n const derivedRoomId = this.options.docRoomId?.(docId) ?? docId;\n const roomId = normalizeRoomId(params.roomId, derivedRoomId);\n const auth = params.auth ?? this.options.docAuth?.(docId);\n\n if (existing && existing.doc === doc && existing.roomId === roomId) {\n return existing;\n }\n\n if (existing) {\n await this.leaveDocSession(docId).catch(() => {});\n }\n\n const adaptor = createLoroAdaptorFromDoc(doc);\n const room = await client.join({\n roomId,\n crdtAdaptor: adaptor,\n auth,\n });\n const firstSynced = room.waitForReachingServerVersion();\n const session: DocSession = {\n adaptor,\n room,\n firstSynced,\n doc,\n roomId,\n refCount: 0,\n };\n this.docSessions.set(docId, session);\n return session;\n }\n\n private async leaveDocSession(docId: string): Promise<void> {\n const session = this.docSessions.get(docId);\n if (!session) return;\n this.docSessions.delete(docId);\n try {\n await session.room.leave();\n } catch {\n await session.room.destroy().catch(() => {});\n }\n session.adaptor.destroy();\n }\n}\n\nexport type {\n TransportJoinParams,\n TransportSubscription,\n TransportSyncResult,\n RepoSyncOptions,\n};\n","import { Flock } from \"@loro-dev/flock\";\nimport { LoroDoc } from \"loro-crdt\";\nimport type {\n TransportAdapter,\n TransportJoinParams,\n TransportSubscription,\n TransportSyncResult,\n} from \"../types\";\n\ntype BroadcastChannelMessageEvent<T = unknown> = {\n data: T;\n};\n\ninterface BroadcastChannelLike {\n readonly name?: string;\n onmessage?: ((event: BroadcastChannelMessageEvent) => void) | null;\n onmessageerror?: ((event: BroadcastChannelMessageEvent) => void) | null;\n postMessage(message: unknown): void;\n addEventListener(\n type: \"message\",\n listener: (event: BroadcastChannelMessageEvent) => void,\n ): void;\n removeEventListener(\n type: \"message\",\n listener: (event: BroadcastChannelMessageEvent) => void,\n ): void;\n close(): void;\n}\n\ntype BroadcastChannelConstructor = new (name: string) => BroadcastChannelLike;\n\ndeclare const BroadcastChannel:\n | BroadcastChannelConstructor\n | undefined;\n\ntype FlockExport = Awaited<ReturnType<Flock[\"exportJson\"]>>;\n\ntype BroadcastMessage =\n | {\n kind: \"meta-export\";\n from: string;\n bundle: FlockExport;\n }\n | {\n kind: \"meta-request\";\n from: string;\n };\n\ntype DocMessage =\n | {\n kind: \"doc-update\";\n docId: string;\n from: string;\n mode: \"snapshot\" | \"update\";\n payload: Uint8Array;\n }\n | {\n kind: \"doc-request\";\n docId: string;\n from: string;\n };\n\ntype MetaListener = {\n flock: Flock;\n unsubscribe: () => void;\n muted: boolean;\n resolveFirst: () => void;\n firstSynced: Promise<void>;\n};\n\ntype MetaChannelState = {\n channel: BroadcastChannelLike;\n listeners: Set<MetaListener>;\n onMessage: (event: BroadcastChannelMessageEvent) => void;\n};\n\ntype DocListener = {\n doc: LoroDoc;\n unsubscribe: () => void;\n muted: boolean;\n resolveFirst: () => void;\n firstSynced: Promise<void>;\n};\n\ntype DocChannelState = {\n channel: BroadcastChannelLike;\n listeners: Set<DocListener>;\n onMessage: (event: BroadcastChannelMessageEvent) => void;\n};\n\nfunction deferred(): {\n promise: Promise<void>;\n resolve: () => void;\n} {\n let resolve!: () => void;\n const promise = new Promise<void>((res) => {\n resolve = res;\n });\n return { promise, resolve };\n}\n\nfunction randomInstanceId(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n return Math.random().toString(36).slice(2);\n}\n\nfunction ensureBroadcastChannel(): BroadcastChannelConstructor {\n if (typeof BroadcastChannel === \"undefined\") {\n throw new Error(\"BroadcastChannel API is not available in this environment\");\n }\n return BroadcastChannel;\n}\n\nfunction encodeDocChannelId(docId: string): string {\n try {\n return encodeURIComponent(docId);\n } catch {\n return docId.replace(/[^a-z0-9_-]/gi, \"_\");\n }\n}\n\nfunction postChannelMessage(\n channel: BroadcastChannelLike,\n message: BroadcastMessage | DocMessage,\n): void {\n // BroadcastChannel.postMessage does not accept targetOrigin, so we intentionally\n // bypass the unicorn/require-post-message-target-origin rule here.\n // eslint-disable-next-line unicorn/require-post-message-target-origin\n channel.postMessage(message);\n}\n\nexport interface BroadcastChannelTransportOptions {\n /**\n * Namespace used to derive broadcast channel names. Defaults to `loro-repo`.\n */\n readonly namespace?: string;\n /**\n * Explicit channel name for metadata broadcasts. When omitted, resolves to `${namespace}-meta`.\n */\n readonly metaChannelName?: string;\n}\n\n/**\n * TransportAdapter that relies on the BroadcastChannel API to fan out metadata\n * and document updates between browser tabs within the same origin.\n */\nexport class BroadcastChannelTransportAdapter implements TransportAdapter {\n private readonly instanceId = randomInstanceId();\n private readonly namespace: string;\n private readonly metaChannelName: string;\n private connected = false;\n\n private metaState?: MetaChannelState;\n private readonly docStates = new Map<string, DocChannelState>();\n\n constructor(options: BroadcastChannelTransportOptions = {}) {\n ensureBroadcastChannel();\n this.namespace = options.namespace ?? \"loro-repo\";\n this.metaChannelName = options.metaChannelName ?? `${this.namespace}-meta`;\n }\n\n async connect(): Promise<void> {\n this.connected = true;\n }\n\n async close(): Promise<void> {\n this.connected = false;\n if (this.metaState) {\n for (const entry of this.metaState.listeners) {\n entry.unsubscribe();\n }\n this.metaState.channel.close();\n this.metaState = undefined;\n }\n for (const [docId] of this.docStates) {\n this.teardownDocChannel(docId);\n }\n this.docStates.clear();\n }\n\n isConnected(): boolean {\n return this.connected;\n }\n\n async syncMeta(\n flock: Flock,\n _options?: { timeout?: number },\n ): Promise<TransportSyncResult> {\n const subscription = this.joinMetaRoom(flock);\n subscription.firstSyncedWithRemote.catch(() => undefined);\n await subscription.firstSyncedWithRemote;\n subscription.unsubscribe();\n return { ok: true };\n }\n\n joinMetaRoom(\n flock: Flock,\n _params?: TransportJoinParams,\n ): TransportSubscription {\n const state = this.ensureMetaChannel();\n const { promise, resolve } = deferred();\n const listener: MetaListener = {\n flock,\n muted: false,\n unsubscribe: flock.subscribe(() => {\n if (listener.muted) return;\n void Promise.resolve(flock.exportJson()).then((bundle) => {\n postChannelMessage(state.channel, {\n kind: \"meta-export\",\n from: this.instanceId,\n bundle,\n } satisfies BroadcastMessage);\n });\n }),\n resolveFirst: resolve,\n firstSynced: promise,\n };\n state.listeners.add(listener);\n\n // Request current state from peers and share our snapshot.\n postChannelMessage(state.channel, {\n kind: \"meta-request\",\n from: this.instanceId,\n } satisfies BroadcastMessage);\n void Promise.resolve(flock.exportJson()).then((bundle) => {\n postChannelMessage(state.channel, {\n kind: \"meta-export\",\n from: this.instanceId,\n bundle,\n } satisfies BroadcastMessage);\n });\n\n // Resolve immediately if nothing arrives.\n queueMicrotask(() => resolve());\n\n const subscription: TransportSubscription = {\n unsubscribe: () => {\n listener.unsubscribe();\n state.listeners.delete(listener);\n if (!state.listeners.size) {\n state.channel.removeEventListener(\"message\", state.onMessage);\n state.channel.close();\n this.metaState = undefined;\n }\n },\n firstSyncedWithRemote: listener.firstSynced,\n get connected() {\n return true;\n },\n };\n return subscription;\n }\n\n async syncDoc(\n docId: string,\n doc: LoroDoc,\n _options?: { timeout?: number },\n ): Promise<TransportSyncResult> {\n const subscription = this.joinDocRoom(docId, doc);\n subscription.firstSyncedWithRemote.catch(() => undefined);\n await subscription.firstSyncedWithRemote;\n subscription.unsubscribe();\n return { ok: true };\n }\n\n joinDocRoom(\n docId: string,\n doc: LoroDoc,\n _params?: TransportJoinParams,\n ): TransportSubscription {\n const state = this.ensureDocChannel(docId);\n const { promise, resolve } = deferred();\n const listener: DocListener = {\n doc,\n muted: false,\n unsubscribe: doc.subscribe(() => {\n if (listener.muted) return;\n const payload = doc.export({ mode: \"update\" });\n postChannelMessage(state.channel, {\n kind: \"doc-update\",\n docId,\n from: this.instanceId,\n mode: \"update\",\n payload,\n } satisfies DocMessage);\n }),\n resolveFirst: resolve,\n firstSynced: promise,\n };\n state.listeners.add(listener);\n\n postChannelMessage(state.channel, {\n kind: \"doc-request\",\n docId,\n from: this.instanceId,\n } satisfies DocMessage);\n postChannelMessage(state.channel, {\n kind: \"doc-update\",\n docId,\n from: this.instanceId,\n mode: \"snapshot\",\n payload: doc.export({ mode: \"snapshot\" }),\n } satisfies DocMessage);\n\n queueMicrotask(() => resolve());\n\n const subscription: TransportSubscription = {\n unsubscribe: () => {\n listener.unsubscribe();\n state.listeners.delete(listener);\n if (!state.listeners.size) {\n this.teardownDocChannel(docId);\n }\n },\n firstSyncedWithRemote: listener.firstSynced,\n get connected() {\n return true;\n },\n };\n return subscription;\n }\n\n private ensureMetaChannel(): MetaChannelState {\n if (this.metaState) {\n return this.metaState;\n }\n const Channel = ensureBroadcastChannel();\n const channel = new Channel(this.metaChannelName);\n const listeners = new Set<MetaListener>();\n const onMessage = (event: BroadcastChannelMessageEvent) => {\n const message = event.data as BroadcastMessage | undefined;\n if (!message || message.from === this.instanceId) {\n return;\n }\n if (message.kind === \"meta-export\") {\n for (const entry of listeners) {\n entry.muted = true;\n entry.flock.importJson(message.bundle);\n entry.muted = false;\n entry.resolveFirst();\n }\n } else if (message.kind === \"meta-request\") {\n const first = listeners.values().next().value;\n if (!first) return;\n void Promise.resolve(first.flock.exportJson()).then((bundle) => {\n postChannelMessage(channel, {\n kind: \"meta-export\",\n from: this.instanceId,\n bundle,\n } satisfies BroadcastMessage);\n });\n }\n };\n channel.addEventListener(\"message\", onMessage);\n this.metaState = { channel, listeners, onMessage };\n return this.metaState;\n }\n\n private ensureDocChannel(docId: string): DocChannelState {\n const existing = this.docStates.get(docId);\n if (existing) return existing;\n const Channel = ensureBroadcastChannel();\n const channelName = `${this.namespace}-doc-${encodeDocChannelId(docId)}`;\n const channel = new Channel(channelName);\n const listeners = new Set<DocListener>();\n const onMessage = (event: BroadcastChannelMessageEvent) => {\n const message = event.data as DocMessage | undefined;\n if (!message || message.from === this.instanceId) {\n return;\n }\n if (message.kind === \"doc-update\") {\n for (const entry of listeners) {\n entry.muted = true;\n entry.doc.import(message.payload);\n entry.muted = false;\n entry.resolveFirst();\n }\n } else if (message.kind === \"doc-request\") {\n const first = listeners.values().next().value;\n if (!first) return;\n const payload =\n message.docId === docId\n ? first.doc.export({ mode: \"snapshot\" })\n : undefined;\n if (!payload) return;\n postChannelMessage(channel, {\n kind: \"doc-update\",\n docId,\n from: this.instanceId,\n mode: \"snapshot\",\n payload,\n } satisfies DocMessage);\n }\n };\n channel.addEventListener(\"message\", onMessage);\n const state: DocChannelState = { channel, listeners, onMessage };\n this.docStates.set(docId, state);\n return state;\n }\n\n private teardownDocChannel(docId: string): void {\n const state = this.docStates.get(docId);\n if (!state) return;\n for (const entry of state.listeners) {\n entry.unsubscribe();\n }\n state.channel.removeEventListener(\"message\", state.onMessage);\n state.channel.close();\n this.docStates.delete(docId);\n }\n}\n","import { Flock } from \"@loro-dev/flock\";\nimport { LoroDoc } from \"loro-crdt\";\n\nimport type {\n AssetId,\n StorageAdapter,\n StorageSavePayload,\n} from \"../types\";\nimport type { ExportBundle } from \"@loro-dev/flock\";\n\nconst DEFAULT_DB_NAME = \"loro-repo\";\nconst DEFAULT_DB_VERSION = 1;\nconst DEFAULT_DOC_STORE = \"docs\";\nconst DEFAULT_META_STORE = \"meta\";\nconst DEFAULT_ASSET_STORE = \"assets\";\nconst DEFAULT_DOC_UPDATE_STORE = \"doc-updates\";\nconst DEFAULT_META_KEY = \"snapshot\";\n\ntype EventListenerOptions = {\n once?: boolean;\n};\n\ntype IDBFactory = {\n open(name: string, version?: number): IDBOpenDBRequest;\n};\n\ntype IDBOpenDBRequest = {\n result: IDBDatabase;\n error: unknown;\n onupgradeneeded: ((event: unknown) => void) | null;\n onsuccess: ((event: unknown) => void) | null;\n onerror: ((event: unknown) => void) | null;\n addEventListener(\n type: string,\n listener: (event: unknown) => void,\n options?: EventListenerOptions,\n ): void;\n};\n\ntype ObjectStoreNames = {\n contains?(name: string): boolean;\n length?: number;\n item?(index: number): string | null;\n};\n\ntype IDBDatabase = {\n close(): void;\n createObjectStore(name: string): IDBObjectStore;\n transaction(\n storeName: string,\n mode?: IDBTransactionMode,\n ): IDBTransaction;\n objectStoreNames: ObjectStoreNames;\n};\n\ntype IDBTransactionMode = \"readonly\" | \"readwrite\";\n\ntype IDBTransaction = {\n objectStore(name: string): IDBObjectStore;\n oncomplete: ((event: unknown) => void) | null;\n onerror: ((event: unknown) => void) | null;\n onabort: ((event: unknown) => void) | null;\n error: unknown;\n addEventListener(\n type: string,\n listener: (event: unknown) => void,\n options?: EventListenerOptions,\n ): void;\n};\n\ntype IDBObjectStore = {\n put(value: unknown, key?: unknown): IDBRequest<unknown>;\n get(key: unknown): IDBRequest<unknown>;\n delete(key: unknown): IDBRequest<unknown>;\n};\n\ntype IDBRequest<T> = {\n onsuccess: ((event: unknown) => void) | null;\n onerror: ((event: unknown) => void) | null;\n result: T;\n error: unknown;\n addEventListener(\n type: string,\n listener: (event: unknown) => void,\n options?: EventListenerOptions,\n ): void;\n};\n\nconst textDecoder = new TextDecoder();\n\nfunction describeUnknown(cause: unknown): string {\n if (typeof cause === \"string\") return cause;\n if (typeof cause === \"number\" || typeof cause === \"boolean\") {\n return String(cause);\n }\n if (typeof cause === \"bigint\") {\n return cause.toString();\n }\n if (typeof cause === \"symbol\") {\n return cause.description ?? cause.toString();\n }\n if (typeof cause === \"function\") {\n return `[function ${cause.name ?? \"anonymous\"}]`;\n }\n if (cause && typeof cause === \"object\") {\n try {\n return JSON.stringify(cause);\n } catch {\n return \"[object]\";\n }\n }\n return String(cause);\n}\n\nexport interface IndexedDBStorageAdaptorOptions {\n readonly dbName?: string;\n readonly version?: number;\n readonly docStoreName?: string;\n readonly docUpdateStoreName?: string;\n readonly metaStoreName?: string;\n readonly assetStoreName?: string;\n readonly metaKey?: string;\n}\n\nexport class IndexedDBStorageAdaptor implements StorageAdapter {\n private readonly idb: IDBFactory;\n private readonly dbName: string;\n private readonly version: number;\n private readonly docStore: string;\n private readonly docUpdateStore: string;\n private readonly metaStore: string;\n private readonly assetStore: string;\n private readonly metaKey: string;\n private dbPromise?: Promise<IDBDatabase>;\n private closed = false;\n\n constructor(options: IndexedDBStorageAdaptorOptions = {}) {\n const idbFactory = (globalThis as { indexedDB?: IDBFactory }).indexedDB;\n if (!idbFactory) {\n throw new Error(\"IndexedDB is not available in this environment\");\n }\n this.idb = idbFactory;\n this.dbName = options.dbName ?? DEFAULT_DB_NAME;\n this.version = options.version ?? DEFAULT_DB_VERSION;\n this.docStore = options.docStoreName ?? DEFAULT_DOC_STORE;\n this.docUpdateStore = options.docUpdateStoreName ?? DEFAULT_DOC_UPDATE_STORE;\n this.metaStore = options.metaStoreName ?? DEFAULT_META_STORE;\n this.assetStore = options.assetStoreName ?? DEFAULT_ASSET_STORE;\n this.metaKey = options.metaKey ?? DEFAULT_META_KEY;\n }\n\n async save(payload: StorageSavePayload): Promise<void> {\n const db = await this.ensureDb();\n switch (payload.type) {\n case \"doc-snapshot\": {\n const snapshot = payload.snapshot.slice();\n await this.storeMergedSnapshot(db, payload.docId, snapshot);\n break;\n }\n case \"doc-update\": {\n const update = payload.update.slice();\n await this.appendDocUpdate(db, payload.docId, update);\n break;\n }\n case \"asset\": {\n const bytes = payload.data.slice();\n await this.putBinary(db, this.assetStore, payload.assetId, bytes);\n break;\n }\n case \"meta\": {\n const bytes = payload.update.slice();\n await this.putBinary(db, this.metaStore, this.metaKey, bytes);\n break;\n }\n default:\n throw new Error(\"Unsupported storage payload type\");\n }\n }\n\n async deleteAsset(assetId: AssetId): Promise<void> {\n const db = await this.ensureDb();\n await this.deleteKey(db, this.assetStore, assetId);\n }\n\n async loadDoc(docId: string): Promise<LoroDoc | undefined> {\n const db = await this.ensureDb();\n const snapshot = await this.getBinaryFromDb(db, this.docStore, docId);\n const pendingUpdates = await this.getDocUpdates(db, docId);\n\n if (!snapshot && pendingUpdates.length === 0) {\n return undefined;\n }\n\n let doc: LoroDoc;\n try {\n doc = snapshot ? LoroDoc.fromSnapshot(snapshot) : new LoroDoc();\n } catch (error) {\n throw this.createError(\n `Failed to hydrate document snapshot for \"${docId}\"`,\n error,\n );\n }\n\n let appliedUpdates = false;\n for (const update of pendingUpdates) {\n try {\n doc.import(update);\n appliedUpdates = true;\n } catch (error) {\n throw this.createError(\n `Failed to apply queued document update for \"${docId}\"`,\n error,\n );\n }\n }\n\n if (appliedUpdates) {\n let consolidated: Uint8Array;\n try {\n consolidated = doc.export({ mode: \"snapshot\" });\n } catch (error) {\n throw this.createError(\n `Failed to export consolidated snapshot for \"${docId}\"`,\n error,\n );\n }\n await this.writeSnapshot(db, docId, consolidated);\n await this.clearDocUpdates(db, docId);\n }\n\n return doc;\n }\n\n async loadMeta(): Promise<Flock | undefined> {\n const bytes = await this.getBinary(this.metaStore, this.metaKey);\n if (!bytes) return undefined;\n try {\n const json = textDecoder.decode(bytes);\n const bundle = JSON.parse(json) as ExportBundle;\n const flock = new Flock();\n flock.importJson(bundle);\n return flock;\n } catch (error) {\n throw this.createError(\"Failed to hydrate metadata snapshot\", error);\n }\n }\n\n async loadAsset(assetId: AssetId): Promise<Uint8Array | undefined> {\n const bytes = await this.getBinary(this.assetStore, assetId);\n return bytes ?? undefined;\n }\n\n async close(): Promise<void> {\n this.closed = true;\n const db = await this.dbPromise;\n if (db) {\n db.close();\n }\n this.dbPromise = undefined;\n }\n\n private async ensureDb(): Promise<IDBDatabase> {\n if (this.closed) {\n throw new Error(\"IndexedDBStorageAdaptor has been closed\");\n }\n if (!this.dbPromise) {\n this.dbPromise = new Promise((resolve, reject) => {\n const request = this.idb.open(this.dbName, this.version);\n request.addEventListener(\"upgradeneeded\", () => {\n const db = request.result;\n this.ensureStore(db, this.docStore);\n this.ensureStore(db, this.docUpdateStore);\n this.ensureStore(db, this.metaStore);\n this.ensureStore(db, this.assetStore);\n });\n request.addEventListener(\n \"success\",\n () => resolve(request.result),\n { once: true },\n );\n request.addEventListener(\n \"error\",\n () => {\n reject(\n this.createError(\n `Failed to open IndexedDB database \"${this.dbName}\"`,\n request.error,\n ),\n );\n },\n { once: true },\n );\n });\n }\n return this.dbPromise;\n }\n\n private ensureStore(db: IDBDatabase, storeName: string): void {\n const names = db.objectStoreNames;\n if (this.storeExists(names, storeName)) return;\n db.createObjectStore(storeName);\n }\n\n private storeExists(names: ObjectStoreNames, storeName: string): boolean {\n if (typeof names.contains === \"function\") {\n return names.contains(storeName);\n }\n const length = names.length ?? 0;\n for (let index = 0; index < length; index += 1) {\n const value = names.item?.(index);\n if (value === storeName) return true;\n }\n return false;\n }\n\n private async storeMergedSnapshot(\n db: IDBDatabase,\n docId: string,\n incoming: Uint8Array,\n ): Promise<void> {\n await this.runInTransaction(db, this.docStore, \"readwrite\", async (store) => {\n const existingRaw = await this.wrapRequest(store.get(docId), \"read\");\n const existing = await this.normalizeBinary(existingRaw);\n const merged = this.mergeSnapshots(docId, existing, incoming);\n await this.wrapRequest(store.put(merged, docId), \"write\");\n });\n }\n\n private mergeSnapshots(\n docId: string,\n existing: Uint8Array | undefined,\n incoming: Uint8Array,\n ): Uint8Array {\n try {\n const doc = existing ? LoroDoc.fromSnapshot(existing) : new LoroDoc();\n doc.import(incoming);\n return doc.export({ mode: \"snapshot\" });\n } catch (error) {\n throw this.createError(`Failed to merge snapshot for \"${docId}\"`, error);\n }\n }\n\n private async appendDocUpdate(\n db: IDBDatabase,\n docId: string,\n update: Uint8Array,\n ): Promise<void> {\n await this.runInTransaction(\n db,\n this.docUpdateStore,\n \"readwrite\",\n async (store) => {\n const raw = await this.wrapRequest(store.get(docId), \"read\");\n const queue = await this.normalizeUpdateQueue(raw);\n queue.push(update.slice());\n await this.wrapRequest(store.put({ updates: queue }, docId), \"write\");\n },\n );\n }\n\n private async getDocUpdates(\n db: IDBDatabase,\n docId: string,\n ): Promise<Uint8Array[]> {\n const raw = await this.runInTransaction(\n db,\n this.docUpdateStore,\n \"readonly\",\n (store) => this.wrapRequest(store.get(docId), \"read\"),\n );\n return this.normalizeUpdateQueue(raw);\n }\n\n private async clearDocUpdates(\n db: IDBDatabase,\n docId: string,\n ): Promise<void> {\n await this.runInTransaction(\n db,\n this.docUpdateStore,\n \"readwrite\",\n (store) => this.wrapRequest(store.delete(docId), \"delete\"),\n );\n }\n\n private async writeSnapshot(\n db: IDBDatabase,\n docId: string,\n snapshot: Uint8Array,\n ): Promise<void> {\n await this.putBinary(db, this.docStore, docId, snapshot.slice());\n }\n\n private async getBinaryFromDb(\n db: IDBDatabase,\n storeName: string,\n key: string,\n ): Promise<Uint8Array | undefined> {\n const value = await this.runInTransaction(\n db,\n storeName,\n \"readonly\",\n (store) => this.wrapRequest(store.get(key), \"read\"),\n );\n return this.normalizeBinary(value);\n }\n\n private async normalizeUpdateQueue(value: unknown): Promise<Uint8Array[]> {\n if (value == null) return [];\n const list = Array.isArray(value)\n ? value\n : typeof value === \"object\" && value !== null\n ? (value as { updates?: unknown }).updates\n : undefined;\n\n if (!Array.isArray(list)) return [];\n\n const queue: Uint8Array[] = [];\n for (const entry of list) {\n const bytes = await this.normalizeBinary(entry);\n if (bytes) {\n queue.push(bytes);\n }\n }\n return queue;\n }\n\n private async putBinary(\n db: IDBDatabase,\n storeName: string,\n key: string,\n value: Uint8Array,\n ): Promise<void> {\n await this.runInTransaction(db, storeName, \"readwrite\", (store) =>\n this.wrapRequest(store.put(value, key), \"write\"),\n );\n }\n\n private async deleteKey(\n db: IDBDatabase,\n storeName: string,\n key: string,\n ): Promise<void> {\n await this.runInTransaction(db, storeName, \"readwrite\", (store) =>\n this.wrapRequest(store.delete(key), \"delete\"),\n );\n }\n\n private async getBinary(\n storeName: string,\n key: string,\n ): Promise<Uint8Array | undefined> {\n const db = await this.ensureDb();\n return this.getBinaryFromDb(db, storeName, key);\n }\n\n private runInTransaction<T>(\n db: IDBDatabase,\n storeName: string,\n mode: IDBTransactionMode,\n executor: (store: IDBObjectStore) => Promise<T>,\n ): Promise<T> {\n const tx = db.transaction(storeName, mode);\n const store = tx.objectStore(storeName);\n const completion = new Promise<void>((resolve, reject) => {\n tx.addEventListener(\n \"complete\",\n () => resolve(),\n { once: true },\n );\n tx.addEventListener(\n \"abort\",\n () =>\n reject(\n this.createError(\"IndexedDB transaction aborted\", tx.error),\n ),\n { once: true },\n );\n tx.addEventListener(\n \"error\",\n () =>\n reject(\n this.createError(\"IndexedDB transaction failed\", tx.error),\n ),\n { once: true },\n );\n });\n return Promise.all([executor(store), completion]).then(([result]) => result);\n }\n\n private wrapRequest<T>(\n request: IDBRequest<T>,\n action: string,\n ): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n request.addEventListener(\n \"success\",\n () => resolve(request.result),\n { once: true },\n );\n request.addEventListener(\n \"error\",\n () =>\n reject(\n this.createError(\n `IndexedDB request failed during ${action}`,\n request.error,\n ),\n ),\n { once: true },\n );\n });\n }\n\n private async normalizeBinary(value: unknown): Promise<Uint8Array | undefined> {\n if (value == null) return undefined;\n if (value instanceof Uint8Array) {\n return value.slice();\n }\n if (ArrayBuffer.isView(value)) {\n return new Uint8Array(\n value.buffer,\n value.byteOffset,\n value.byteLength,\n ).slice();\n }\n if (value instanceof ArrayBuffer) {\n return new Uint8Array(value.slice(0));\n }\n if (\n typeof value === \"object\" &&\n value !== null &&\n \"arrayBuffer\" in value\n ) {\n const candidate = value as {\n arrayBuffer?: unknown;\n };\n if (typeof candidate.arrayBuffer === \"function\") {\n const buffer = await candidate.arrayBuffer();\n return new Uint8Array(buffer);\n }\n }\n return undefined;\n }\n\n private createError(message: string, cause: unknown): Error {\n if (cause instanceof Error) {\n return new Error(`${message}: ${cause.message}`, { cause });\n }\n if (cause !== undefined && cause !== null) {\n return new Error(`${message}: ${describeUnknown(cause)}`);\n }\n return new Error(message);\n }\n}\n","import { Flock, type Event as FlockEvent } from \"@loro-dev/flock\";\nimport {\n Frontiers,\n LoroDoc,\n VersionVector,\n type LoroEventBatch,\n} from \"loro-crdt\";\n\nexport * from \"./types\";\nexport * from \"./transport\";\nexport {\n BroadcastChannelTransportAdapter,\n type BroadcastChannelTransportOptions,\n} from \"./transport/broadcast-channel\";\nexport {\n IndexedDBStorageAdaptor,\n type IndexedDBStorageAdaptorOptions,\n} from \"./storage/indexeddb\";\n\nimport type {\n AssetContent,\n AssetDownload,\n AssetId,\n AssetTransportAdapter,\n GarbageCollectionOptions,\n JsonObject,\n JsonValue,\n ListDocQuery,\n LoroRepoOptions,\n LinkAssetOptions,\n RepoDocHandle,\n RepoDocMeta,\n RepoEvent,\n RepoEventBy,\n RepoEventFilter,\n RepoEventListener,\n RepoSyncOptions,\n RepoWatchHandle,\n StorageAdapter,\n TransportAdapter,\n TransportJoinParams,\n TransportSubscription,\n UploadAssetOptions,\n UpsertDocMetaOptions,\n} from \"./types\";\n\nconst textEncoder = new TextEncoder();\nconst DEFAULT_DOC_FRONTIER_DEBOUNCE_MS = 1_000;\n\nfunction logAsyncError(context: string): (error: unknown) => void {\n return (error: unknown) => {\n if (error instanceof Error) {\n console.error(`[loro-repo] ${context} failed: ${error.message}`, error);\n } else {\n console.error(\n `[loro-repo] ${context} failed with non-error reason:`,\n error,\n );\n }\n };\n}\n\nasync function streamToUint8Array(\n stream: ReadableStream<Uint8Array>,\n): Promise<Uint8Array> {\n const reader = stream.getReader();\n const chunks: Uint8Array[] = [];\n let total = 0;\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value) {\n chunks.push(value);\n total += value.byteLength;\n }\n }\n const buffer = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n buffer.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return buffer;\n}\n\nasync function assetContentToUint8Array(\n content: AssetContent,\n): Promise<Uint8Array> {\n if (content instanceof Uint8Array) {\n return content;\n }\n if (ArrayBuffer.isView(content)) {\n return new Uint8Array(\n content.buffer.slice(\n content.byteOffset,\n content.byteOffset + content.byteLength,\n ),\n );\n }\n if (typeof Blob !== \"undefined\" && content instanceof Blob) {\n return new Uint8Array(await content.arrayBuffer());\n }\n if (\n typeof ReadableStream !== \"undefined\" &&\n content instanceof ReadableStream\n ) {\n return streamToUint8Array(content);\n }\n throw new TypeError(\"Unsupported asset content type\");\n}\n\ntype PossibleCrypto = {\n subtle?: {\n digest: (\n algorithm: string,\n data: ArrayBufferView | ArrayBuffer,\n ) => Promise<ArrayBuffer>;\n };\n};\n\nfunction bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes, (byte) => byte.toString(16).padStart(2, \"0\")).join(\n \"\",\n );\n}\n\nasync function computeSha256(bytes: Uint8Array): Promise<string> {\n const globalCrypto = (globalThis as { crypto?: PossibleCrypto }).crypto;\n if (\n globalCrypto?.subtle &&\n typeof globalCrypto.subtle.digest === \"function\"\n ) {\n const digest = await globalCrypto.subtle.digest(\"SHA-256\", bytes);\n return bytesToHex(new Uint8Array(digest));\n }\n try {\n const { createHash } = await import(\"node:crypto\");\n const hash = createHash(\"sha256\");\n hash.update(bytes);\n return hash.digest(\"hex\");\n } catch {\n throw new Error(\"SHA-256 digest is not available in this environment\");\n }\n}\n\nexport interface RepoAssetMetadata {\n readonly assetId: AssetId;\n readonly size: number;\n readonly createdAt: number;\n readonly mime?: string;\n readonly policy?: string;\n readonly tag?: string;\n}\n\nfunction cloneJsonValue(value: unknown): JsonValue | undefined {\n if (value === null) return null;\n if (typeof value === \"string\" || typeof value === \"boolean\") {\n return value;\n }\n if (typeof value === \"number\") {\n return Number.isFinite(value) ? value : undefined;\n }\n if (Array.isArray(value)) {\n const arr: JsonValue[] = [];\n for (const entry of value) {\n const cloned = cloneJsonValue(entry);\n if (cloned !== undefined) {\n arr.push(cloned);\n }\n }\n return arr;\n }\n if (value && typeof value === \"object\") {\n const input = value as Record<string, unknown>;\n const obj: JsonObject = {};\n for (const [key, entry] of Object.entries(input)) {\n const cloned = cloneJsonValue(entry);\n if (cloned !== undefined) {\n obj[key] = cloned;\n }\n }\n return obj;\n }\n return undefined;\n}\n\nfunction cloneJsonObject(value: JsonObject): JsonObject {\n const cloned = cloneJsonValue(value);\n if (cloned && typeof cloned === \"object\" && !Array.isArray(cloned)) {\n return cloned;\n }\n return {};\n}\n\nfunction asJsonObject(value: unknown): JsonObject | undefined {\n const cloned = cloneJsonValue(value);\n if (cloned && typeof cloned === \"object\" && !Array.isArray(cloned)) {\n return cloned;\n }\n return undefined;\n}\n\nfunction isJsonObjectValue(value: JsonValue): value is JsonObject {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction stableStringify(value: JsonValue): string {\n if (value === null || typeof value !== \"object\") {\n return JSON.stringify(value);\n }\n if (Array.isArray(value)) {\n return `[${value.map(stableStringify).join(\",\")}]`;\n }\n if (!isJsonObjectValue(value)) {\n return JSON.stringify(value);\n }\n const entries = Object.keys(value)\n .sort()\n .map((key) => `${JSON.stringify(key)}:${stableStringify(value[key])}`);\n return `{${entries.join(\",\")}}`;\n}\n\nfunction jsonEquals(\n a: JsonValue | undefined,\n b: JsonValue | undefined,\n): boolean {\n if (a === undefined && b === undefined) return true;\n if (a === undefined || b === undefined) return false;\n return stableStringify(a) === stableStringify(b);\n}\n\nfunction diffJsonObjects(\n previous: JsonObject | undefined,\n next: JsonObject,\n): JsonObject {\n const patch: JsonObject = {};\n const keys = new Set<string>([\n ...Object.keys(next),\n ...(previous ? Object.keys(previous) : []),\n ]);\n for (const key of keys) {\n const prevValue = previous\n ? (previous[key] as JsonValue | undefined)\n : undefined;\n if (!Object.prototype.hasOwnProperty.call(next, key)) {\n patch[key] = null;\n continue;\n }\n const nextValue = next[key];\n if (!jsonEquals(prevValue, nextValue)) {\n const cloned = cloneJsonValue(nextValue);\n if (cloned !== undefined) {\n patch[key] = cloned;\n }\n }\n }\n return patch;\n}\n\nfunction assetMetaToJson(meta: RepoAssetMetadata): JsonObject {\n const json: JsonObject = {\n assetId: meta.assetId,\n size: meta.size,\n createdAt: meta.createdAt,\n };\n if (meta.mime !== undefined) json.mime = meta.mime;\n if (meta.policy !== undefined) json.policy = meta.policy;\n if (meta.tag !== undefined) json.tag = meta.tag;\n return json;\n}\n\nfunction assetMetaFromJson(value: unknown): RepoAssetMetadata | undefined {\n const obj = asJsonObject(value);\n if (!obj) return undefined;\n const assetId = typeof obj.assetId === \"string\" ? obj.assetId : undefined;\n if (!assetId) return undefined;\n const size = typeof obj.size === \"number\" ? obj.size : undefined;\n const createdAt =\n typeof obj.createdAt === \"number\" ? obj.createdAt : undefined;\n if (size === undefined || createdAt === undefined) return undefined;\n const meta: RepoAssetMetadata = {\n assetId,\n size,\n createdAt,\n ...(typeof obj.mime === \"string\" ? { mime: obj.mime } : {}),\n ...(typeof obj.policy === \"string\" ? { policy: obj.policy } : {}),\n ...(typeof obj.tag === \"string\" ? { tag: obj.tag } : {}),\n };\n return meta;\n}\n\nfunction assetMetadataEqual(\n a: RepoAssetMetadata | undefined,\n b: RepoAssetMetadata | undefined,\n): boolean {\n if (!a && !b) return true;\n if (!a || !b) return false;\n return (\n stableStringify(assetMetaToJson(a)) === stableStringify(assetMetaToJson(b))\n );\n}\n\nfunction cloneRepoAssetMetadata(meta: RepoAssetMetadata): RepoAssetMetadata {\n return {\n assetId: meta.assetId,\n size: meta.size,\n createdAt: meta.createdAt,\n ...(meta.mime !== undefined ? { mime: meta.mime } : {}),\n ...(meta.policy !== undefined ? { policy: meta.policy } : {}),\n ...(meta.tag !== undefined ? { tag: meta.tag } : {}),\n };\n}\n\nfunction toReadableStream(bytes: Uint8Array): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controller.enqueue(bytes);\n controller.close();\n },\n });\n}\n\nfunction computeVersionVector(doc: LoroDoc): VersionVector {\n const candidate = doc as unknown as {\n frontiers?: () => unknown;\n frontiersToVV?: (frontiers: unknown) => VersionVector;\n version?: () => VersionVector;\n };\n if (\n typeof candidate.frontiers === \"function\" &&\n typeof candidate.frontiersToVV === \"function\"\n ) {\n const frontiers = candidate.frontiers();\n return candidate.frontiersToVV(frontiers);\n }\n if (typeof candidate.version === \"function\") {\n return candidate.version();\n }\n return {} as VersionVector;\n}\n\nfunction emptyFrontiers(): Frontiers {\n return [];\n}\n\nfunction getDocFrontiers(doc: LoroDoc): Frontiers {\n const candidate = doc as unknown as { frontiers?: () => Frontiers | undefined };\n if (typeof candidate.frontiers === \"function\") {\n const result = candidate.frontiers();\n if (result) {\n return result;\n }\n }\n return emptyFrontiers();\n}\n\nfunction versionVectorToJson(vv: VersionVector): JsonObject {\n const map = vv.toJSON();\n const record: JsonObject = {};\n if (map instanceof Map) {\n const entries = Array.from(map.entries()).sort(([a], [b]) =>\n String(a).localeCompare(String(b)),\n );\n for (const [peer, counter] of entries) {\n if (typeof counter !== \"number\" || !Number.isFinite(counter)) continue;\n const key = typeof peer === \"string\" ? peer : JSON.stringify(peer);\n record[key] = counter;\n }\n }\n return record;\n}\n\nfunction canonicalizeVersionVector(vv: VersionVector): {\n json: JsonObject;\n key: string;\n} {\n const json = versionVectorToJson(vv);\n return { json, key: stableStringify(json) };\n}\n\ntype WatchEntry<Meta extends JsonObject> = {\n listener: RepoEventListener<Meta>;\n filter: RepoEventFilter<Meta>;\n};\n\ntype AssetRecord = {\n metadata: RepoAssetMetadata;\n data?: Uint8Array;\n};\n\ntype OrphanedAssetRecord = {\n metadata: RepoAssetMetadata;\n deletedAt: number;\n};\n\ntype PendingDocFrontierUpdate = {\n timeout: ReturnType<typeof setTimeout>;\n doc: LoroDoc;\n by: RepoEventBy;\n};\n\nclass RepoDocHandleImpl implements RepoDocHandle {\n readonly doc: LoroDoc;\n readonly whenSyncedWithRemote: Promise<void>;\n private readonly docId: string;\n private readonly onClose: (docId: string, doc: LoroDoc) => Promise<void>;\n\n constructor(\n docId: string,\n doc: LoroDoc,\n whenSyncedWithRemote: Promise<void>,\n onClose: (docId: string, doc: LoroDoc) => Promise<void>,\n ) {\n this.docId = docId;\n this.doc = doc;\n this.whenSyncedWithRemote = whenSyncedWithRemote;\n this.onClose = onClose;\n }\n\n async close(): Promise<void> {\n await this.onClose(this.docId, this.doc);\n }\n}\n\nfunction matchesQuery(\n docId: string,\n _metadata: JsonObject,\n query?: ListDocQuery,\n): boolean {\n if (!query) return true;\n if (query.prefix && !docId.startsWith(query.prefix)) return false;\n if (query.start && docId < query.start) return false;\n if (query.end && docId > query.end) return false;\n return true;\n}\n\nexport class LoroRepo<Meta extends JsonObject = JsonObject> {\n readonly options: LoroRepoOptions<Meta>;\n private readonly transport?: TransportAdapter;\n private readonly storage?: StorageAdapter;\n private readonly assetTransport?: AssetTransportAdapter;\n private readonly docFactory: (docId: string) => Promise<LoroDoc>;\n\n private metaFlock: Flock = new Flock();\n private readonly metadata = new Map<string, JsonObject>();\n private readonly docs = new Map<string, LoroDoc>();\n private readonly docRefs = new Map<string, number>();\n private readonly docSubscriptions = new Map<string, () => void>();\n private readonly docAssets = new Map<string, Map<AssetId, RepoAssetMetadata>>();\n private readonly assets = new Map<AssetId, AssetRecord>();\n private readonly orphanedAssets = new Map<AssetId, OrphanedAssetRecord>();\n private readonly assetToDocRefs = new Map<AssetId, Set<string>>();\n private readonly docFrontierKeys = new Map<string, Set<string>>();\n private readonly docFrontierUpdates = new Map<\n string,\n PendingDocFrontierUpdate\n >();\n private readonly docPersistedVersions = new Map<string, VersionVector>();\n private readonly docFrontierDebounceMs: number;\n private readonly watchers = new Set<WatchEntry<Meta>>();\n private readonly eventByStack: RepoEventBy[] = [];\n private metaRoomSubscription?: TransportSubscription;\n private unsubscribeMetaFlock?: () => void;\n private readyPromise?: Promise<void>;\n\n constructor(options: LoroRepoOptions<Meta>) {\n this.options = options;\n this.transport = options.transportAdapter;\n this.storage = options.storageAdapter;\n this.assetTransport = options.assetTransportAdapter;\n this.docFactory = options.docFactory ?? (async () => new LoroDoc());\n const configuredDebounce = options.docFrontierDebounceMs;\n this.docFrontierDebounceMs =\n typeof configuredDebounce === \"number\" &&\n Number.isFinite(configuredDebounce) &&\n configuredDebounce >= 0\n ? configuredDebounce\n : DEFAULT_DOC_FRONTIER_DEBOUNCE_MS;\n }\n\n async ready(): Promise<void> {\n if (!this.readyPromise) {\n this.readyPromise = this.initialize();\n }\n await this.readyPromise;\n }\n\n private async initialize(): Promise<void> {\n if (this.storage) {\n const snapshot = await this.storage.loadMeta();\n if (snapshot) {\n this.metaFlock = snapshot;\n }\n }\n this.hydrateMetadataFromFlock(\"sync\");\n }\n\n async sync(options: RepoSyncOptions = {}): Promise<void> {\n await this.ready();\n const { scope = \"full\", docIds } = options;\n if (!this.transport) return;\n\n if (!this.transport.isConnected()) {\n await this.transport.connect();\n }\n\n if (scope === \"meta\" || scope === \"full\") {\n this.pushEventBy(\"sync\");\n const recordedEvents: FlockEvent[] = [];\n const unsubscribe = this.metaFlock.subscribe((batch) => {\n if (batch.source === \"local\") return;\n recordedEvents.push(...batch.events);\n });\n try {\n const result = await this.transport.syncMeta(this.metaFlock);\n if (!result.ok) {\n throw new Error(\"Metadata sync failed\");\n }\n if (recordedEvents.length > 0) {\n this.applyMetaFlockEvents(recordedEvents, \"sync\");\n } else {\n this.hydrateMetadataFromFlock(\"sync\");\n }\n await this.persistMeta();\n } finally {\n unsubscribe();\n this.popEventBy();\n }\n }\n\n if (scope === \"doc\" || scope === \"full\") {\n const targets = docIds ?? Array.from(this.metadata.keys());\n for (const docId of targets) {\n const doc = await this.ensureDoc(docId);\n this.pushEventBy(\"sync\");\n try {\n const result = await this.transport.syncDoc(docId, doc);\n if (!result.ok) {\n throw new Error(`Document sync failed for ${docId}`);\n }\n } finally {\n this.popEventBy();\n }\n await this.persistDoc(docId, doc);\n await this.updateDocFrontiers(docId, doc, \"sync\");\n }\n }\n }\n\n private refreshDocMetadataEntry(docId: string, by: RepoEventBy): void {\n const previous = this.metadata.get(docId);\n const next = this.readDocMetadataFromFlock(docId);\n\n if (!next) {\n if (previous) {\n this.metadata.delete(docId);\n this.emit({\n kind: \"doc-metadata\",\n docId,\n patch: {} as Partial<Meta>,\n by,\n });\n }\n return;\n }\n\n this.metadata.set(docId, next);\n const patch = diffJsonObjects(previous, next);\n if (!previous || Object.keys(patch).length > 0) {\n this.emit({\n kind: \"doc-metadata\",\n docId,\n patch: patch as Partial<Meta>,\n by,\n });\n }\n }\n\n private refreshDocAssetsEntry(docId: string, by: RepoEventBy): void {\n const mapping = this.readDocAssetsFromFlock(docId);\n const previous = this.docAssets.get(docId);\n\n if (!mapping.size) {\n if (previous?.size) {\n this.docAssets.delete(docId);\n for (const assetId of previous.keys()) {\n this.emit({ kind: \"asset-unlink\", docId, assetId, by });\n const stillReferenced = Array.from(this.docAssets.values()).some((assets) =>\n assets.has(assetId),\n );\n if (!stillReferenced) {\n const record = this.assets.get(assetId);\n if (record) {\n const existing = this.orphanedAssets.get(assetId);\n const deletedAt = existing?.deletedAt ?? Date.now();\n this.orphanedAssets.set(assetId, {\n metadata: record.metadata,\n deletedAt,\n });\n }\n }\n }\n }\n return;\n }\n\n this.docAssets.set(docId, mapping);\n\n const added: AssetId[] = [];\n const removed: AssetId[] = [];\n\n if (previous) {\n for (const assetId of previous.keys()) {\n if (!mapping.has(assetId)) {\n removed.push(assetId);\n }\n }\n }\n\n for (const assetId of mapping.keys()) {\n if (!previous || !previous.has(assetId)) {\n added.push(assetId);\n }\n }\n\n for (const assetId of removed) {\n this.emit({ kind: \"asset-unlink\", docId, assetId, by });\n const stillReferenced = Array.from(this.docAssets.values()).some((assets) =>\n assets.has(assetId),\n );\n if (!stillReferenced) {\n const record = this.assets.get(assetId);\n if (record) {\n const existing = this.orphanedAssets.get(assetId);\n const deletedAt = existing?.deletedAt ?? Date.now();\n this.orphanedAssets.set(assetId, {\n metadata: record.metadata,\n deletedAt,\n });\n }\n }\n }\n for (const assetId of added) {\n this.emit({ kind: \"asset-link\", docId, assetId, by });\n }\n }\n\n private refreshAssetMetadataEntry(assetId: AssetId, by: RepoEventBy): void {\n const previous = this.assets.get(assetId);\n const raw = this.metaFlock.get([\"a\", assetId]);\n const metadata = assetMetaFromJson(raw);\n\n if (!metadata) {\n this.handleAssetRemoval(assetId, by);\n return;\n }\n\n const existingData = previous?.data;\n this.rememberAsset(metadata, existingData);\n\n for (const assets of this.docAssets.values()) {\n if (assets.has(assetId)) {\n assets.set(assetId, cloneRepoAssetMetadata(metadata));\n }\n }\n\n if (!previous || !assetMetadataEqual(previous.metadata, metadata)) {\n this.emit({\n kind: \"asset-metadata\",\n asset: this.createAssetDownload(assetId, metadata, existingData),\n by,\n });\n }\n }\n\n private refreshDocFrontierKeys(docId: string): void {\n const rows = this.metaFlock.scan({ prefix: [\"f\", docId] });\n const keys = new Set<string>();\n for (const row of rows) {\n if (!Array.isArray(row.key) || row.key.length < 3) continue;\n const frontierKey = row.key[2];\n if (typeof frontierKey === \"string\") {\n keys.add(frontierKey);\n }\n }\n if (keys.size > 0) {\n this.docFrontierKeys.set(docId, keys);\n } else {\n this.docFrontierKeys.delete(docId);\n }\n }\n\n private readDocMetadataFromFlock(docId: string): JsonObject | undefined {\n const rows = this.metaFlock.scan({ prefix: [\"m\", docId] });\n if (!rows.length) return undefined;\n const docMeta: JsonObject = {};\n let populated = false;\n for (const row of rows) {\n if (!Array.isArray(row.key) || row.key.length < 2) continue;\n if (row.key.length === 2) {\n const obj = asJsonObject(row.value);\n if (!obj) continue;\n for (const [field, value] of Object.entries(obj)) {\n const cloned = cloneJsonValue(value);\n if (cloned !== undefined) {\n docMeta[field] = cloned;\n populated = true;\n }\n }\n continue;\n }\n const fieldKey = row.key[2];\n if (typeof fieldKey !== \"string\") continue;\n if (fieldKey === \"$tombstone\") {\n docMeta.tombstone = Boolean(row.value);\n populated = true;\n continue;\n }\n const jsonValue = cloneJsonValue(row.value);\n if (jsonValue === undefined) continue;\n docMeta[fieldKey] = jsonValue;\n populated = true;\n }\n return populated ? docMeta : undefined;\n }\n\n private readDocAssetsFromFlock(docId: string): Map<AssetId, RepoAssetMetadata> {\n const rows = this.metaFlock.scan({ prefix: [\"ld\", docId] });\n const mapping = new Map<AssetId, RepoAssetMetadata>();\n for (const row of rows) {\n if (!Array.isArray(row.key) || row.key.length < 3) continue;\n const assetId = row.key[2];\n if (typeof assetId !== \"string\") continue;\n const truthy = row.value !== undefined && row.value !== null && row.value !== false;\n if (!truthy) continue;\n let metadata = this.assets.get(assetId)?.metadata;\n if (!metadata) {\n metadata = this.readAssetMetadataFromFlock(assetId);\n if (!metadata) continue;\n this.rememberAsset(metadata);\n }\n mapping.set(assetId, cloneRepoAssetMetadata(metadata));\n }\n return mapping;\n }\n\n private readAssetMetadataFromFlock(assetId: AssetId): RepoAssetMetadata | undefined {\n const raw = this.metaFlock.get([\"a\", assetId]);\n return assetMetaFromJson(raw);\n }\n\n private handleAssetRemoval(assetId: AssetId, by: RepoEventBy): void {\n const record = this.assets.get(assetId);\n if (!record) return;\n this.assets.delete(assetId);\n const existing = this.orphanedAssets.get(assetId);\n const deletedAt = existing?.deletedAt ?? Date.now();\n this.orphanedAssets.set(assetId, {\n metadata: record.metadata,\n deletedAt,\n });\n\n const affectedDocs: string[] = [];\n for (const [docId, assets] of this.docAssets) {\n if (assets.delete(assetId)) {\n if (assets.size === 0) {\n this.docAssets.delete(docId);\n }\n affectedDocs.push(docId);\n }\n }\n\n for (const docId of affectedDocs) {\n this.emit({ kind: \"asset-unlink\", docId, assetId, by });\n }\n }\n\n private emit(event: RepoEvent<Meta>): void {\n for (const entry of this.watchers) {\n if (this.shouldNotify(entry.filter, event)) {\n entry.listener(event);\n }\n }\n }\n async joinMetaRoom(\n params?: TransportJoinParams,\n ): Promise<TransportSubscription> {\n await this.ready();\n if (!this.transport) {\n throw new Error(\"Transport adapter not configured\");\n }\n if (!this.transport.isConnected()) {\n await this.transport.connect();\n }\n if (this.metaRoomSubscription) {\n return this.metaRoomSubscription;\n }\n\n this.ensureMetaLiveMonitor();\n\n const subscription = this.transport.joinMetaRoom(this.metaFlock, params);\n const wrapped: TransportSubscription = {\n unsubscribe: () => {\n subscription.unsubscribe();\n if (this.metaRoomSubscription === wrapped) {\n this.metaRoomSubscription = undefined;\n }\n if (this.unsubscribeMetaFlock) {\n this.unsubscribeMetaFlock();\n this.unsubscribeMetaFlock = undefined;\n }\n },\n firstSyncedWithRemote: subscription.firstSyncedWithRemote,\n get connected() {\n return subscription.connected;\n },\n };\n\n this.metaRoomSubscription = wrapped;\n void subscription.firstSyncedWithRemote\n .then(async () => {\n const by = this.resolveEventBy(\"live\");\n this.hydrateMetadataFromFlock(by);\n await this.persistMeta();\n })\n .catch(logAsyncError(\"meta room first sync\"));\n\n return wrapped;\n }\n\n async joinDocRoom(\n docId: string,\n params?: TransportJoinParams,\n ): Promise<TransportSubscription> {\n await this.ready();\n if (!this.transport) {\n throw new Error(\"Transport adapter not configured\");\n }\n if (!this.transport.isConnected()) {\n await this.transport.connect();\n }\n const doc = await this.ensureDoc(docId);\n const subscription = this.transport.joinDocRoom(docId, doc, params);\n void subscription.firstSyncedWithRemote.catch(\n logAsyncError(`doc ${docId} first sync`),\n );\n return subscription;\n }\n\n async close(): Promise<void> {\n for (const unsubscribe of this.docSubscriptions.values()) {\n try {\n unsubscribe();\n } catch {\n // ignore\n }\n }\n this.docSubscriptions.clear();\n this.metaRoomSubscription?.unsubscribe();\n this.metaRoomSubscription = undefined;\n if (this.unsubscribeMetaFlock) {\n this.unsubscribeMetaFlock();\n this.unsubscribeMetaFlock = undefined;\n }\n const pendingDocIds = Array.from(this.docFrontierUpdates.keys());\n for (const docId of pendingDocIds) {\n try {\n await this.flushScheduledDocFrontierUpdate(docId);\n } catch (error) {\n logAsyncError(`doc ${docId} frontier flush on close`)(error);\n }\n }\n this.docFrontierUpdates.clear();\n this.watchers.clear();\n this.docs.clear();\n this.docRefs.clear();\n this.metadata.clear();\n this.docAssets.clear();\n this.assets.clear();\n this.docFrontierKeys.clear();\n this.docPersistedVersions.clear();\n this.readyPromise = undefined;\n await this.transport?.close();\n }\n\n async upsertDocMeta(\n docId: string,\n patch: Partial<Meta>,\n _options: UpsertDocMetaOptions = {},\n ): Promise<void> {\n await this.ready();\n const base = this.metadata.get(docId);\n const next: JsonObject = base ? cloneJsonObject(base) : {};\n const outPatch: JsonObject = {};\n let changed = false;\n\n const patchObject = patch as unknown as JsonObject;\n for (const key of Object.keys(patchObject)) {\n const rawValue = patchObject[key];\n if (rawValue === undefined) continue;\n\n let canonical: JsonValue | undefined;\n if (key === \"tombstone\") {\n canonical = Boolean(rawValue);\n } else {\n canonical = cloneJsonValue(rawValue);\n }\n if (canonical === undefined) continue;\n\n const previousValue = base\n ? (base[key] as JsonValue | undefined)\n : undefined;\n if (jsonEquals(previousValue, canonical)) {\n continue;\n }\n\n const storageKey = key === \"tombstone\" ? \"$tombstone\" : key;\n this.metaFlock.put([\"m\", docId, storageKey], canonical);\n\n const stored = cloneJsonValue(canonical) ?? canonical;\n next[key] = stored;\n outPatch[key] = cloneJsonValue(stored) ?? stored;\n changed = true;\n }\n\n if (!changed) {\n if (!this.metadata.has(docId)) {\n this.metadata.set(docId, next);\n }\n return;\n }\n\n this.metadata.set(docId, next);\n await this.persistMeta();\n this.emit({\n kind: \"doc-metadata\",\n docId,\n patch: cloneJsonObject(outPatch) as Partial<Meta>,\n by: \"local\",\n });\n }\n\n async getDocMeta(docId: string): Promise<Meta | undefined> {\n await this.ready();\n const metadata = this.metadata.get(docId);\n return metadata ? (cloneJsonObject(metadata) as Meta) : undefined;\n }\n\n async listDoc(query?: ListDocQuery): Promise<RepoDocMeta<Meta>[]> {\n await this.ready();\n const entries: RepoDocMeta<Meta>[] = [];\n for (const [docId, metadata] of this.metadata.entries()) {\n if (!matchesQuery(docId, metadata, query)) continue;\n entries.push({ docId, meta: cloneJsonObject(metadata) as Meta });\n }\n entries.sort((a, b) =>\n a.docId < b.docId ? -1 : a.docId > b.docId ? 1 : 0,\n );\n if (query?.limit !== undefined) {\n return entries.slice(0, query.limit);\n }\n return entries;\n }\n\n getMetaReplica(): Flock {\n return this.metaFlock;\n }\n\n watch(\n listener: RepoEventListener<Meta>,\n filter: RepoEventFilter<Meta> = {},\n ): RepoWatchHandle {\n const entry: WatchEntry<Meta> = { listener, filter };\n this.watchers.add(entry);\n return {\n unsubscribe: () => {\n this.watchers.delete(entry);\n },\n };\n }\n\n /**\n * Opens the repo-managed collaborative document, registers it for persistence,\n * and schedules a doc-level sync so `whenSyncedWithRemote` resolves after remote backfills.\n */\n async openCollaborativeDoc(docId: string): Promise<RepoDocHandle> {\n const doc = await this.ensureDoc(docId);\n const refs = this.docRefs.get(docId) ?? 0;\n this.docRefs.set(docId, refs + 1);\n const whenSyncedWithRemote = this.whenDocInSyncWithRemote(docId);\n return new RepoDocHandleImpl(\n docId,\n doc,\n whenSyncedWithRemote,\n async (id, instance) => this.onDocHandleClose(id, instance),\n );\n }\n\n /**\n * Opens a detached `LoroDoc` snapshot that never registers with the repo, meaning\n * it neither participates in remote subscriptions nor persists edits back to storage.\n */\n async openDetachedDoc(docId: string): Promise<RepoDocHandle> {\n await this.ready();\n const doc = await this.materializeDetachedDoc(docId);\n return new RepoDocHandleImpl(docId, doc, Promise.resolve(), async () => {});\n }\n\n async uploadAsset(params: UploadAssetOptions): Promise<AssetId> {\n await this.ready();\n const bytes = await assetContentToUint8Array(params.content);\n const assetId = await computeSha256(bytes);\n\n if (params.assetId && params.assetId !== assetId) {\n throw new Error(\"Provided assetId does not match content digest\");\n }\n\n const existing = this.assets.get(assetId);\n if (existing) {\n if (!existing.data) {\n const clone = bytes.slice();\n existing.data = clone;\n if (this.storage) {\n await this.storage.save({\n type: \"asset\",\n assetId,\n data: clone.slice(),\n });\n }\n }\n let metadataMutated = false;\n const metadata = { ...existing.metadata };\n if (params.mime && metadata.mime !== params.mime) {\n metadata.mime = params.mime;\n metadataMutated = true;\n }\n if (params.policy && metadata.policy !== params.policy) {\n metadata.policy = params.policy;\n metadataMutated = true;\n }\n if (params.tag && metadata.tag !== params.tag) {\n metadata.tag = params.tag;\n metadataMutated = true;\n }\n if (\n params.createdAt !== undefined &&\n metadata.createdAt !== params.createdAt\n ) {\n metadata.createdAt = params.createdAt;\n metadataMutated = true;\n }\n if (metadataMutated) {\n existing.metadata = metadata;\n this.metaFlock.put([\"a\", assetId], assetMetaToJson(metadata));\n await this.persistMeta();\n this.emit({\n kind: \"asset-metadata\",\n asset: this.createAssetDownload(assetId, metadata, existing.data),\n by: \"local\",\n });\n }\n this.rememberAsset(existing.metadata);\n return assetId;\n }\n\n const metadata: RepoAssetMetadata = {\n assetId,\n size: bytes.byteLength,\n createdAt: params.createdAt ?? Date.now(),\n ...(params.mime ? { mime: params.mime } : {}),\n ...(params.policy ? { policy: params.policy } : {}),\n ...(params.tag ? { tag: params.tag } : {}),\n };\n\n if (this.assetTransport) {\n let shouldUpload = true;\n if (typeof this.assetTransport.ensure === \"function\") {\n shouldUpload = !(await this.assetTransport.ensure(assetId));\n }\n if (shouldUpload) {\n await this.assetTransport.upload(assetId, bytes, {\n mime: params.mime,\n policy: params.policy,\n tag: params.tag,\n });\n }\n }\n\n const storedBytes = bytes.slice();\n\n if (this.storage) {\n await this.storage.save({\n type: \"asset\",\n assetId,\n data: storedBytes.slice(),\n });\n }\n\n this.rememberAsset(metadata, storedBytes);\n\n for (const assets of this.docAssets.values()) {\n if (assets.has(assetId)) {\n assets.set(assetId, metadata);\n }\n }\n\n this.metaFlock.put([\"a\", assetId], assetMetaToJson(metadata));\n await this.persistMeta();\n\n this.emit({\n kind: \"asset-metadata\",\n asset: this.createAssetDownload(assetId, metadata, storedBytes),\n by: \"local\",\n });\n\n return assetId;\n }\n\n async whenDocInSyncWithRemote(docId: string): Promise<void> {\n await this.ready();\n await this.ensureDoc(docId);\n await this.sync({ scope: \"doc\", docIds: [docId] });\n }\n\n async linkAsset(docId: string, params: LinkAssetOptions): Promise<AssetId> {\n await this.ready();\n const bytes = await assetContentToUint8Array(params.content);\n const assetId = await computeSha256(bytes);\n\n if (params.assetId && params.assetId !== assetId) {\n throw new Error(\"Provided assetId does not match content digest\");\n }\n\n let metadata: RepoAssetMetadata;\n let storedBytes: Uint8Array | undefined;\n let created = false;\n\n const existing = this.assets.get(assetId);\n if (existing) {\n metadata = existing.metadata;\n if (!existing.data) {\n const clone = bytes.slice();\n existing.data = clone;\n if (this.storage) {\n await this.storage.save({\n type: \"asset\",\n assetId,\n data: clone.slice(),\n });\n }\n }\n let nextMetadata = metadata;\n let metadataMutated = false;\n if (params.mime && params.mime !== nextMetadata.mime) {\n nextMetadata = { ...nextMetadata, mime: params.mime };\n metadataMutated = true;\n }\n if (params.policy && params.policy !== nextMetadata.policy) {\n nextMetadata = { ...nextMetadata, policy: params.policy };\n metadataMutated = true;\n }\n if (params.tag && params.tag !== nextMetadata.tag) {\n nextMetadata = { ...nextMetadata, tag: params.tag };\n metadataMutated = true;\n }\n if (\n params.createdAt !== undefined &&\n params.createdAt !== nextMetadata.createdAt\n ) {\n nextMetadata = { ...nextMetadata, createdAt: params.createdAt };\n metadataMutated = true;\n }\n if (metadataMutated) {\n existing.metadata = nextMetadata;\n metadata = nextMetadata;\n this.metaFlock.put([\"a\", assetId], assetMetaToJson(metadata));\n await this.persistMeta();\n this.emit({\n kind: \"asset-metadata\",\n asset: this.createAssetDownload(assetId, metadata, existing.data),\n by: \"local\",\n });\n } else {\n metadata = existing.metadata;\n }\n storedBytes = existing.data;\n this.rememberAsset(metadata);\n } else {\n metadata = {\n assetId,\n size: bytes.byteLength,\n createdAt: params.createdAt ?? Date.now(),\n ...(params.mime ? { mime: params.mime } : {}),\n ...(params.policy ? { policy: params.policy } : {}),\n ...(params.tag ? { tag: params.tag } : {}),\n };\n\n if (this.assetTransport) {\n let shouldUpload = true;\n if (typeof this.assetTransport.ensure === \"function\") {\n shouldUpload = !(await this.assetTransport.ensure(assetId));\n }\n if (shouldUpload) {\n await this.assetTransport.upload(assetId, bytes, {\n mime: params.mime,\n policy: params.policy,\n tag: params.tag,\n });\n }\n }\n\n storedBytes = bytes.slice();\n\n if (this.storage) {\n await this.storage.save({\n type: \"asset\",\n assetId,\n data: storedBytes.slice(),\n });\n }\n\n this.rememberAsset(metadata, storedBytes);\n\n for (const assets of this.docAssets.values()) {\n if (assets.has(assetId)) {\n assets.set(assetId, metadata);\n }\n }\n\n this.metaFlock.put([\"a\", assetId], assetMetaToJson(metadata));\n created = true;\n }\n\n const mapping =\n this.docAssets.get(docId) ?? new Map<AssetId, RepoAssetMetadata>();\n mapping.set(assetId, metadata);\n this.docAssets.set(docId, mapping);\n \n // Maintain reverse index: assetId -> Set<docId>\n const refs = this.assetToDocRefs.get(assetId) ?? new Set<string>();\n refs.add(docId);\n this.assetToDocRefs.set(assetId, refs);\n \n this.metaFlock.put([\"ld\", docId, assetId], true);\n await this.persistMeta();\n\n this.emit({ kind: \"asset-link\", docId, assetId, by: \"local\" });\n if (created) {\n this.emit({\n kind: \"asset-metadata\",\n asset: this.createAssetDownload(assetId, metadata, storedBytes ?? bytes),\n by: \"local\",\n });\n }\n return assetId;\n }\n\n async fetchAsset(assetId: AssetId): Promise<AssetDownload> {\n await this.ready();\n const { metadata, bytes } = await this.materializeAsset(assetId);\n return this.createAssetDownload(assetId, metadata, bytes);\n }\n\n async unlinkAsset(docId: string, assetId: AssetId): Promise<void> {\n await this.ready();\n const mapping = this.docAssets.get(docId);\n if (!mapping || !mapping.has(assetId)) return;\n mapping.delete(assetId);\n if (mapping.size === 0) {\n this.docAssets.delete(docId);\n }\n\n this.metaFlock.delete([\"ld\", docId, assetId]);\n\n // Use reverse index for O(1) reference checking instead of O(n) scan\n const refs = this.assetToDocRefs.get(assetId);\n if (refs) {\n refs.delete(docId);\n if (refs.size === 0) {\n // Asset is no longer referenced by any document\n this.assetToDocRefs.delete(assetId);\n \n const record = this.assets.get(assetId);\n if (record) {\n this.orphanedAssets.set(assetId, {\n metadata: record.metadata,\n deletedAt: Date.now(),\n });\n }\n this.metaFlock.delete([\"a\", assetId]);\n this.assets.delete(assetId);\n }\n }\n\n await this.persistMeta();\n this.emit({ kind: \"asset-unlink\", docId, assetId, by: \"local\" });\n }\n\n async listAssets(docId: string): Promise<RepoAssetMetadata[]> {\n await this.ready();\n const mapping = this.docAssets.get(docId);\n if (!mapping) return [];\n return Array.from(mapping.values()).map((asset) => ({ ...asset }));\n }\n\n async ensureAsset(assetId: AssetId): Promise<AssetDownload> {\n return this.fetchAsset(assetId);\n }\n\n private createAssetDownload(\n assetId: AssetId,\n metadata: RepoAssetMetadata,\n initialBytes?: Uint8Array,\n ): AssetDownload {\n let cached = initialBytes ? initialBytes.slice() : undefined;\n return {\n assetId,\n size: metadata.size,\n createdAt: metadata.createdAt,\n mime: metadata.mime,\n policy: metadata.policy,\n tag: metadata.tag,\n content: async () => {\n if (!cached) {\n const result = await this.materializeAsset(assetId);\n cached = result.bytes.slice();\n }\n return toReadableStream(cached.slice());\n },\n };\n }\n\n private async materializeAsset(\n assetId: AssetId,\n ): Promise<{ metadata: RepoAssetMetadata; bytes: Uint8Array }> {\n let record = this.assets.get(assetId);\n if (record?.data) {\n return { metadata: record.metadata, bytes: record.data.slice() };\n }\n\n if (record && this.storage) {\n const stored = await this.storage.loadAsset(assetId);\n if (stored) {\n const clone = stored.slice();\n record.data = clone.slice();\n return { metadata: record.metadata, bytes: clone };\n }\n }\n\n if (!record && this.storage) {\n const stored = await this.storage.loadAsset(assetId);\n if (stored) {\n const metadata = this.getAssetMetadata(assetId);\n if (!metadata) {\n throw new Error(`Missing metadata for asset ${assetId}`);\n }\n const clone = stored.slice();\n this.assets.set(assetId, { metadata, data: clone.slice() });\n this.updateDocAssetMetadata(assetId, metadata);\n return { metadata, bytes: clone };\n }\n }\n\n if (!this.assetTransport) {\n throw new Error(`Asset ${assetId} is not available locally`);\n }\n\n const remote = await this.assetTransport.fetch(assetId);\n if (!remote) {\n throw new Error(`Asset ${assetId} missing from remote store`);\n }\n const remoteStream = await remote.content();\n const remoteBytes = await streamToUint8Array(remoteStream);\n const metadata: RepoAssetMetadata = {\n assetId,\n size: remote.size,\n createdAt: remote.createdAt,\n ...(remote.mime ? { mime: remote.mime } : {}),\n ...(remote.policy ? { policy: remote.policy } : {}),\n ...(remote.tag ? { tag: remote.tag } : {}),\n };\n\n this.assets.set(assetId, { metadata, data: remoteBytes.slice() });\n this.updateDocAssetMetadata(assetId, metadata);\n\n this.metaFlock.put([\"a\", assetId], assetMetaToJson(metadata));\n await this.persistMeta();\n\n if (this.storage) {\n await this.storage.save({\n type: \"asset\",\n assetId,\n data: remoteBytes.slice(),\n });\n }\n\n return { metadata, bytes: remoteBytes };\n }\n\n private updateDocAssetMetadata(\n assetId: AssetId,\n metadata: RepoAssetMetadata,\n ): void {\n for (const assets of this.docAssets.values()) {\n if (assets.has(assetId)) {\n assets.set(assetId, metadata);\n }\n }\n }\n\n async gcAssets(options: GarbageCollectionOptions = {}): Promise<number> {\n await this.ready();\n const { minKeepMs = 0 } = options;\n const now = Date.now();\n let removed = 0;\n for (const [assetId, orphan] of Array.from(this.orphanedAssets.entries())) {\n if (now - orphan.deletedAt < minKeepMs) {\n continue;\n }\n this.orphanedAssets.delete(assetId);\n if (this.storage?.deleteAsset) {\n try {\n await this.storage.deleteAsset(assetId);\n } catch (error) {\n logAsyncError(`asset ${assetId} delete`)(error);\n }\n }\n removed += 1;\n }\n return removed;\n }\n\n private async onDocHandleClose(docId: string, doc: LoroDoc): Promise<void> {\n const refs = this.docRefs.get(docId) ?? 0;\n if (refs <= 1) {\n this.docRefs.delete(docId);\n } else {\n this.docRefs.set(docId, refs - 1);\n }\n await this.persistDocUpdate(docId, doc);\n const flushed = await this.flushScheduledDocFrontierUpdate(docId);\n if (!flushed) {\n await this.updateDocFrontiers(docId, doc, \"local\");\n }\n }\n\n private async ensureDoc(docId: string): Promise<LoroDoc> {\n await this.ready();\n const cached = this.docs.get(docId);\n if (cached) {\n this.ensureDocSubscription(docId, cached);\n if (!this.docPersistedVersions.has(docId)) {\n this.docPersistedVersions.set(\n docId,\n cached.version(),\n );\n }\n return cached;\n }\n\n if (this.storage) {\n const stored = await this.storage.loadDoc(docId);\n if (stored) {\n this.registerDoc(docId, stored);\n return stored;\n }\n }\n\n const created = await this.docFactory(docId);\n this.registerDoc(docId, created);\n return created;\n }\n\n private async materializeDetachedDoc(docId: string): Promise<LoroDoc> {\n const doc = await this.docFactory(docId);\n const snapshot = await this.exportDocSnapshot(docId);\n if (snapshot) {\n doc.import(snapshot);\n }\n return doc;\n }\n\n private async exportDocSnapshot(\n docId: string,\n ): Promise<Uint8Array | undefined> {\n const cached = this.docs.get(docId);\n if (cached) {\n return cached.export({ mode: \"snapshot\" });\n }\n if (!this.storage) {\n return undefined;\n }\n const stored = await this.storage.loadDoc(docId);\n return stored?.export({ mode: \"snapshot\" });\n }\n\n private async persistMeta(): Promise<void> {\n if (!this.storage) return;\n const bundle = this.metaFlock.exportJson();\n const encoded = textEncoder.encode(JSON.stringify(bundle));\n await this.storage.save({ type: \"meta\", update: encoded });\n }\n\n private async persistDoc(docId: string, doc: LoroDoc): Promise<void> {\n const previousVersion = this.docPersistedVersions.get(docId);\n const nextVersion = doc.version();\n if (!this.storage) {\n this.docPersistedVersions.set(docId, nextVersion);\n return;\n }\n const snapshot = doc.export({ mode: \"snapshot\" });\n this.docPersistedVersions.set(docId, nextVersion);\n try {\n await this.storage.save({\n type: \"doc-snapshot\",\n docId,\n snapshot,\n });\n } catch (error) {\n if (previousVersion) {\n this.docPersistedVersions.set(docId, previousVersion);\n } else {\n this.docPersistedVersions.delete(docId);\n }\n throw error;\n }\n }\n\n private async persistDocUpdate(\n docId: string,\n doc: LoroDoc,\n ): Promise<void> {\n const previousVersion = this.docPersistedVersions.get(docId);\n const nextVersion = doc.version();\n if (!this.storage) {\n this.docPersistedVersions.set(docId, nextVersion);\n return;\n }\n\n if (!previousVersion) {\n await this.persistDoc(docId, doc);\n this.docPersistedVersions.set(docId, nextVersion);\n return;\n }\n\n const update = doc.export({ mode: \"update\", from: previousVersion });\n\n if (!update.length) {\n this.docPersistedVersions.set(docId, nextVersion);\n return;\n }\n\n this.docPersistedVersions.set(docId, nextVersion);\n try {\n await this.storage.save({\n type: \"doc-update\",\n docId,\n update,\n });\n } catch (error) {\n this.docPersistedVersions.set(docId, previousVersion);\n throw error;\n }\n }\n\n private pushEventBy(by: RepoEventBy): void {\n this.eventByStack.push(by);\n }\n\n private popEventBy(): void {\n this.eventByStack.pop();\n }\n\n private resolveEventBy(defaultBy: RepoEventBy): RepoEventBy {\n const index = this.eventByStack.length - 1;\n return index >= 0 ? this.eventByStack[index] : defaultBy;\n }\n\n private ensureMetaLiveMonitor(): void {\n if (this.unsubscribeMetaFlock) return;\n this.unsubscribeMetaFlock = this.metaFlock.subscribe((batch) => {\n if (batch.source === \"local\") return;\n const by = this.resolveEventBy(\"live\");\n void (async () => {\n this.applyMetaFlockEvents(batch.events, by);\n await this.persistMeta();\n })().catch(logAsyncError(\"meta live monitor sync\"));\n });\n }\n\n private applyMetaFlockEvents(events: FlockEvent[], by: RepoEventBy): void {\n if (!events.length) return;\n const docMetadataIds = new Set<string>();\n const docAssetIds = new Set<string>();\n const docFrontiersIds = new Set<string>();\n const assetIds = new Set<AssetId>();\n\n for (const event of events) {\n const key = event.key;\n if (!Array.isArray(key) || key.length === 0) continue;\n const root = key[0];\n if (root === \"m\") {\n const docId = key[1];\n if (typeof docId === \"string\") {\n docMetadataIds.add(docId);\n }\n } else if (root === \"a\") {\n const assetId = key[1];\n if (typeof assetId === \"string\") {\n assetIds.add(assetId);\n }\n } else if (root === \"ld\") {\n const docId = key[1];\n const assetId = key[2];\n if (typeof docId === \"string\") {\n docAssetIds.add(docId);\n }\n if (typeof assetId === \"string\") {\n assetIds.add(assetId);\n }\n } else if (root === \"f\") {\n const docId = key[1];\n if (typeof docId === \"string\") {\n docFrontiersIds.add(docId);\n }\n }\n }\n\n for (const assetId of assetIds) {\n this.refreshAssetMetadataEntry(assetId, by);\n }\n\n for (const docId of docMetadataIds) {\n this.refreshDocMetadataEntry(docId, by);\n }\n\n for (const docId of docAssetIds) {\n this.refreshDocAssetsEntry(docId, by);\n }\n\n for (const docId of docFrontiersIds) {\n this.refreshDocFrontierKeys(docId);\n }\n }\n\n private registerDoc(docId: string, doc: LoroDoc): void {\n this.docs.set(docId, doc);\n this.docPersistedVersions.set(docId, doc.version());\n this.ensureDocSubscription(docId, doc);\n }\n\n private ensureDocSubscription(docId: string, doc: LoroDoc): void {\n if (this.docSubscriptions.has(docId)) return;\n const unsubscribe = doc.subscribe((batch: LoroEventBatch) => {\n const stackBy = this.resolveEventBy(\"local\");\n const by: RepoEventBy =\n stackBy === \"local\" && batch.by === \"import\" ? \"live\" : stackBy;\n this.onDocEvent(docId, doc, batch, by);\n });\n if (typeof unsubscribe === \"function\") {\n this.docSubscriptions.set(docId, unsubscribe as () => void);\n }\n }\n\n private rememberAsset(metadata: RepoAssetMetadata, bytes?: Uint8Array): void {\n const data = bytes\n ? bytes.slice()\n : this.assets.get(metadata.assetId)?.data;\n this.assets.set(metadata.assetId, {\n metadata,\n data,\n });\n this.orphanedAssets.delete(metadata.assetId);\n }\n\n private scheduleDocFrontierUpdate(\n docId: string,\n doc: LoroDoc,\n by: RepoEventBy,\n ): void {\n const existing = this.docFrontierUpdates.get(docId);\n const effectiveBy = existing ? this.mergeRepoEventBy(existing.by, by) : by;\n if (existing) {\n clearTimeout(existing.timeout);\n }\n const delay =\n this.docFrontierDebounceMs > 0 ? this.docFrontierDebounceMs : 0;\n const timeout = setTimeout(\n () => this.runScheduledDocFrontierUpdate(docId),\n delay,\n );\n this.docFrontierUpdates.set(docId, { timeout, doc, by: effectiveBy });\n }\n\n private mergeRepoEventBy(\n current: RepoEventBy,\n next: RepoEventBy,\n ): RepoEventBy {\n if (current === next) return current;\n if (current === \"live\" || next === \"live\") return \"live\";\n if (current === \"sync\" || next === \"sync\") return \"sync\";\n return \"local\";\n }\n\n private runScheduledDocFrontierUpdate(docId: string): void {\n const pending = this.docFrontierUpdates.get(docId);\n if (!pending) return;\n this.docFrontierUpdates.delete(docId);\n this.pushEventBy(pending.by);\n void (async () => {\n try {\n await this.updateDocFrontiers(docId, pending.doc, pending.by);\n } finally {\n this.popEventBy();\n }\n })().catch(logAsyncError(`doc ${docId} frontier debounce`));\n }\n\n private async flushScheduledDocFrontierUpdate(\n docId: string,\n ): Promise<boolean> {\n const pending = this.docFrontierUpdates.get(docId);\n if (!pending) return false;\n clearTimeout(pending.timeout);\n this.docFrontierUpdates.delete(docId);\n this.pushEventBy(pending.by);\n try {\n await this.updateDocFrontiers(docId, pending.doc, pending.by);\n } finally {\n this.popEventBy();\n }\n return true;\n }\n\n private onDocEvent(\n docId: string,\n doc: LoroDoc,\n _batch: LoroEventBatch,\n by: RepoEventBy,\n ): void {\n void (async () => {\n const a = this.persistDocUpdate(docId, doc);\n if (by === \"local\") {\n this.scheduleDocFrontierUpdate(docId, doc, by);\n await a;\n return;\n }\n\n const b = this.flushScheduledDocFrontierUpdate(docId);\n const c = this.updateDocFrontiers(docId, doc, by);\n await Promise.all([a, b, c]);\n })().catch(logAsyncError(`doc ${docId} event processing`));\n }\n\n private getAssetMetadata(assetId: AssetId): RepoAssetMetadata | undefined {\n const record = this.assets.get(assetId);\n if (record) return record.metadata;\n for (const assets of this.docAssets.values()) {\n const metadata = assets.get(assetId);\n if (metadata) return metadata;\n }\n return undefined;\n }\n\n private async updateDocFrontiers(\n docId: string,\n doc: LoroDoc,\n defaultBy: RepoEventBy = \"local\",\n ): Promise<void> {\n const versionVector = computeVersionVector(doc);\n const { json, key } = canonicalizeVersionVector(versionVector);\n const existingKeys = this.docFrontierKeys.get(docId) ?? new Set<string>();\n let mutated = false;\n\n if (existingKeys.size !== 1 || !existingKeys.has(key)) {\n for (const entry of existingKeys) {\n this.metaFlock.delete([\"f\", docId, entry]);\n }\n this.metaFlock.put([\"f\", docId, key], json);\n this.docFrontierKeys.set(docId, new Set([key]));\n mutated = true;\n }\n\n if (mutated) {\n await this.persistMeta();\n }\n\n const by = this.resolveEventBy(defaultBy);\n const frontiers = getDocFrontiers(doc);\n this.emit({ kind: \"doc-frontiers\", docId, frontiers, by });\n }\n\n private hydrateMetadataFromFlock(by: RepoEventBy): void {\n const prevMetadata = new Map(this.metadata);\n const prevDocAssets = new Map(this.docAssets);\n const prevAssets = new Map(this.assets);\n\n const nextMetadata = new Map<string, JsonObject>();\n\n const metadataRows = this.metaFlock.scan({ prefix: [\"m\"] });\n for (const row of metadataRows) {\n if (!Array.isArray(row.key) || row.key.length < 2) continue;\n const docId = row.key[1];\n if (typeof docId !== \"string\") continue;\n\n let docMeta = nextMetadata.get(docId);\n if (!docMeta) {\n docMeta = {};\n nextMetadata.set(docId, docMeta);\n }\n\n if (row.key.length === 2) {\n const obj = asJsonObject(row.value);\n if (!obj) continue;\n for (const [field, value] of Object.entries(obj)) {\n const cloned = cloneJsonValue(value);\n if (cloned !== undefined) {\n docMeta[field] = cloned;\n }\n }\n continue;\n }\n\n const fieldKey = row.key[2];\n if (typeof fieldKey !== \"string\") continue;\n\n if (fieldKey === \"$tombstone\") {\n docMeta.tombstone = Boolean(row.value);\n continue;\n }\n\n const jsonValue = cloneJsonValue(row.value);\n if (jsonValue === undefined) continue;\n docMeta[fieldKey] = jsonValue;\n }\n\n const nextAssets = new Map<AssetId, AssetRecord>();\n const assetRows = this.metaFlock.scan({ prefix: [\"a\"] });\n for (const row of assetRows) {\n if (!Array.isArray(row.key) || row.key.length < 2) continue;\n const assetId = row.key[1];\n if (typeof assetId !== \"string\") continue;\n const metadata = assetMetaFromJson(row.value);\n if (!metadata) continue;\n const existing = this.assets.get(assetId);\n nextAssets.set(assetId, {\n metadata,\n data: existing?.data,\n });\n }\n\n const nextDocAssets = new Map<string, Map<AssetId, RepoAssetMetadata>>();\n const linkRows = this.metaFlock.scan({ prefix: [\"ld\"] });\n for (const row of linkRows) {\n if (!Array.isArray(row.key) || row.key.length < 3) continue;\n const docId = row.key[1];\n const assetId = row.key[2];\n if (typeof docId !== \"string\" || typeof assetId !== \"string\") continue;\n const metadata = nextAssets.get(assetId)?.metadata;\n if (!metadata) continue;\n const mapping =\n nextDocAssets.get(docId) ?? new Map<AssetId, RepoAssetMetadata>();\n mapping.set(assetId, metadata);\n nextDocAssets.set(docId, mapping);\n }\n\n const nextFrontierKeys = new Map<string, Set<string>>();\n const frontierRows = this.metaFlock.scan({ prefix: [\"f\"] });\n for (const row of frontierRows) {\n if (!Array.isArray(row.key) || row.key.length < 3) continue;\n const docId = row.key[1];\n const frontierKey = row.key[2];\n if (typeof docId !== \"string\" || typeof frontierKey !== \"string\")\n continue;\n const set = nextFrontierKeys.get(docId) ?? new Set<string>();\n set.add(frontierKey);\n nextFrontierKeys.set(docId, set);\n }\n\n // Remember assets that disappeared from metadata (remote unlink or tombstone)\n // so the GC path can eventually purge cached blobs even when the removal\n // happened on another peer or before process restart.\n const removedAssets: Array<[AssetId, AssetRecord]> = [];\n for (const [assetId, record] of prevAssets) {\n if (!nextAssets.has(assetId)) {\n removedAssets.push([assetId, record]);\n }\n }\n\n if (removedAssets.length > 0) {\n const now = Date.now();\n for (const [assetId, record] of removedAssets) {\n const existing = this.orphanedAssets.get(assetId);\n const deletedAt = existing?.deletedAt ?? now;\n this.orphanedAssets.set(assetId, {\n metadata: record.metadata,\n deletedAt,\n });\n }\n }\n\n this.metadata.clear();\n for (const [docId, meta] of nextMetadata) {\n this.metadata.set(docId, meta);\n }\n\n this.docAssets.clear();\n for (const [docId, assets] of nextDocAssets) {\n this.docAssets.set(docId, assets);\n }\n\n // Rebuild reverse index: assetId -> Set<docId>\n this.assetToDocRefs.clear();\n for (const [docId, assets] of nextDocAssets) {\n for (const assetId of assets.keys()) {\n const refs = this.assetToDocRefs.get(assetId) ?? new Set<string>();\n refs.add(docId);\n this.assetToDocRefs.set(assetId, refs);\n }\n }\n\n this.assets.clear();\n for (const record of nextAssets.values()) {\n this.rememberAsset(record.metadata, record.data);\n }\n\n this.docFrontierKeys.clear();\n for (const [docId, keys] of nextFrontierKeys) {\n this.docFrontierKeys.set(docId, keys);\n }\n\n const docIds = new Set<string>([\n ...prevMetadata.keys(),\n ...nextMetadata.keys(),\n ]);\n for (const docId of docIds) {\n const previous = prevMetadata.get(docId);\n const current = nextMetadata.get(docId);\n if (!current) {\n if (previous) {\n this.emit({\n kind: \"doc-metadata\",\n docId,\n patch: {} as Partial<Meta>,\n by,\n });\n }\n continue;\n }\n const patch = diffJsonObjects(previous, current);\n if (Object.keys(patch).length > 0) {\n this.emit({\n kind: \"doc-metadata\",\n docId,\n patch: patch as Partial<Meta>,\n by,\n });\n }\n }\n\n for (const [assetId, record] of nextAssets) {\n const previous = prevAssets.get(assetId)?.metadata;\n if (!assetMetadataEqual(previous, record.metadata)) {\n this.emit({\n kind: \"asset-metadata\",\n asset: this.createAssetDownload(\n assetId,\n record.metadata,\n record.data,\n ),\n by,\n });\n }\n }\n\n for (const [docId, assets] of nextDocAssets) {\n const previous = prevDocAssets.get(docId);\n for (const assetId of assets.keys()) {\n if (!previous || !previous.has(assetId)) {\n this.emit({ kind: \"asset-link\", docId, assetId, by });\n }\n }\n }\n\n for (const [docId, assets] of prevDocAssets) {\n const current = nextDocAssets.get(docId);\n for (const assetId of assets.keys()) {\n if (!current || !current.has(assetId)) {\n this.emit({ kind: \"asset-unlink\", docId, assetId, by });\n }\n }\n }\n }\n\n private shouldNotify(\n filter: RepoEventFilter<Meta>,\n event: RepoEvent<Meta>,\n ): boolean {\n if (!filter.docIds && !filter.kinds && !filter.metadataFields && !filter.by)\n return true;\n if (filter.kinds && !filter.kinds.includes(event.kind)) return false;\n if (filter.by && !filter.by.includes(event.by)) return false;\n\n const docId = (() => {\n if (event.kind === \"doc-metadata\" || event.kind === \"doc-frontiers\")\n return event.docId;\n if (event.kind === \"asset-link\" || event.kind === \"asset-unlink\")\n return event.docId;\n return undefined;\n })();\n\n if (filter.docIds && docId && !filter.docIds.includes(docId)) return false;\n if (filter.docIds && !docId) return false;\n\n if (filter.metadataFields && event.kind === \"doc-metadata\") {\n const keys = Object.keys(event.patch);\n if (!keys.some((key) => filter.metadataFields?.includes(key)))\n return false;\n }\n\n return true;\n }\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "loro-repo",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "Draft TypeScript definitions for the LoroRepo orchestrator.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=18"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@loro-dev/flock": "^1.0.0",
|
|
25
|
+
"loro-crdt": "^1.8.4",
|
|
26
|
+
"loro-websocket": "0.2.1",
|
|
27
|
+
"loro-protocol": "0.1.3",
|
|
28
|
+
"loro-adaptors": "0.2.1"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/loro-dev/flock"
|
|
36
|
+
},
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^22.18.6",
|
|
40
|
+
"tsdown": "^0.15.4",
|
|
41
|
+
"typescript": "^5.9.2",
|
|
42
|
+
"vitest": "^3.2.4",
|
|
43
|
+
"ws": "^8.18.3"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsdown",
|
|
47
|
+
"dev": "tsdown --watch",
|
|
48
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
49
|
+
"test": "vitest run",
|
|
50
|
+
"watch": "vitest",
|
|
51
|
+
"check": "pnpm typecheck && pnpm test"
|
|
52
|
+
}
|
|
53
|
+
}
|