loro-repo 0.3.0 → 0.4.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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["FlockAdaptor","subscription: TransportSubscription","LoroWebsocketClient","CrdtType","session: MetadataSession","LoroAdaptor","session: DocSession","resolve!: () => void","listener: MetaListener","listener: DocListener","state: DocChannelState","textDecoder","doc: LoroDoc","LoroDoc","consolidated: Uint8Array","Flock","queue: Uint8Array[]","path","LoroDoc","Flock","fs","entry: WatchEntry<Meta>","chunks: Uint8Array[]","arr: JsonValue[]","obj: JsonObject","patch: JsonObject","json: JsonObject","LoroDoc","oldFrontiers: Frontiers","promises: Promise<void>[]","by: RepoEventBy","scanOptions: ScanOptions","entries: RepoDocMeta<Meta>[]","next: JsonObject","outPatch: JsonObject","canonical: JsonValue | undefined","docMeta: JsonObject","metadata","metadata: RepoAssetMetadata","storedBytes: Uint8Array | undefined","removed: AssetId[]","removedAssets: Array<[AssetId, AssetRecord]>","recordedEvents: FlockEvent[]","wrapped: TransportSubscription","Flock"],"sources":["../src/loro-adaptor.ts","../src/internal/debug.ts","../src/transport/websocket.ts","../src/transport/broadcast-channel.ts","../src/storage/indexeddb.ts","../src/storage/filesystem.ts","../src/internal/event-bus.ts","../src/utils.ts","../src/internal/logging.ts","../src/internal/doc-manager.ts","../src/internal/metadata-manager.ts","../src/internal/asset-manager.ts","../src/internal/flock-hydrator.ts","../src/internal/sync-runner.ts","../src/internal/repo-state.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","type EnvRecord = Record<string, string | undefined>;\n\nconst getEnv = (): EnvRecord | undefined => {\n if (typeof globalThis !== \"object\" || globalThis === null) {\n return undefined;\n }\n const processLike = (globalThis as { process?: { env?: EnvRecord } }).process;\n return processLike?.env;\n};\n\nconst rawNamespaceConfig = (getEnv()?.LORO_REPO_DEBUG ?? \"\").trim();\n\nconst normalizedNamespaces =\n rawNamespaceConfig.length > 0\n ? rawNamespaceConfig\n .split(/[\\s,]+/)\n .map((token) => token.toLowerCase())\n .filter(Boolean)\n : [];\n\nconst wildcardTokens = new Set([\"*\", \"1\", \"true\", \"all\"]);\nconst namespaceSet = new Set(normalizedNamespaces);\nconst hasWildcard =\n namespaceSet.size > 0 &&\n normalizedNamespaces.some((token) => wildcardTokens.has(token));\n\nexport const isDebugEnabled = (namespace?: string): boolean => {\n if (!namespaceSet.size) {\n return false;\n }\n if (!namespace) {\n return hasWildcard;\n }\n const normalized = namespace.toLowerCase();\n if (hasWildcard) {\n return true;\n }\n if (namespaceSet.has(normalized)) {\n return true;\n }\n const [root] = normalized.split(\":\");\n return namespaceSet.has(root);\n};\n\nexport type DebugLogger = (...args: unknown[]) => void;\n\nexport const createDebugLogger = (namespace: string): DebugLogger => {\n const normalized = namespace.toLowerCase();\n return (...args: unknown[]) => {\n if (!isDebugEnabled(normalized)) {\n return;\n }\n const prefix = `[loro-repo:${namespace}]`;\n if (args.length === 0) {\n console.info(prefix);\n return;\n }\n console.info(prefix, ...args);\n };\n};\n","import { Flock } from \"@loro-dev/flock\";\nimport { LoroDoc } from \"loro-crdt\";\nimport { LoroAdaptor, 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\";\nimport { createDebugLogger } from \"../internal/debug\";\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\nconst debug = createDebugLogger(\"transport:websocket\");\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 debug(\"connect requested\", { status: client.getStatus() });\n try {\n await client.connect();\n debug(\"client.connect resolved\");\n await client.waitConnected();\n debug(\"client.waitConnected resolved\", { status: client.getStatus() });\n } catch (error) {\n debug(\"connect failed\", error);\n throw error;\n }\n }\n\n async close(): Promise<void> {\n debug(\"close requested\", {\n docSessions: this.docSessions.size,\n metadataSession: Boolean(this.metadataSession),\n });\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 const client = this.client;\n this.client = undefined;\n client.destroy();\n debug(\"websocket client destroyed\");\n }\n debug(\"close completed\");\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 debug(\"syncMeta skipped; metadata room not configured\");\n return { ok: true };\n }\n debug(\"syncMeta requested\", { roomId: this.options.metadataRoomId });\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 debug(\"syncMeta completed\", { roomId: this.options.metadataRoomId });\n return { ok: true };\n } catch (error) {\n debug(\"syncMeta failed\", error);\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 debug(\"joinMetaRoom requested\", {\n roomId,\n hasAuth: Boolean(auth && auth.length),\n });\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 debug(\"metadata session refCount decremented\", {\n roomId: session.roomId,\n refCount: session.refCount,\n });\n if (session.refCount === 0) {\n debug(\"tearing down metadata session due to refCount=0\", {\n roomId: session.roomId,\n });\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 debug(\"metadata session refCount incremented\", {\n roomId: session.roomId,\n refCount: session.refCount,\n });\n });\n return subscription;\n }\n\n async syncDoc(\n docId: string,\n doc: LoroDoc,\n options?: { timeout?: number },\n ): Promise<TransportSyncResult> {\n debug(\"syncDoc requested\", { docId });\n try {\n const session = await this.ensureDocSession(docId, doc, {});\n await withTimeout(session.firstSynced, options?.timeout);\n debug(\"syncDoc completed\", { docId, roomId: session.roomId });\n return { ok: true };\n } catch (error) {\n debug(\"syncDoc failed\", { docId, error });\n return { ok: false };\n }\n }\n\n joinDocRoom(\n docId: string,\n doc: LoroDoc,\n params?: TransportJoinParams,\n ): TransportSubscription {\n debug(\"joinDocRoom requested\", {\n docId,\n roomParamType: params?.roomId\n ? typeof params.roomId === \"string\"\n ? \"string\"\n : \"uint8array\"\n : undefined,\n hasAuthOverride: Boolean(params?.auth && params.auth.length),\n });\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 debug(\"doc session refCount decremented\", {\n docId,\n roomId: session.roomId,\n refCount: session.refCount,\n });\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 debug(\"doc session refCount incremented\", {\n docId,\n roomId: session.roomId,\n refCount: session.refCount,\n });\n });\n return subscription;\n }\n\n private ensureClient(): LoroWebsocketClient {\n if (this.client) {\n debug(\"reusing websocket client\", { status: this.client.getStatus() });\n return this.client;\n }\n const { url, client: clientOptions } = this.options;\n debug(\"creating websocket client\", {\n url,\n clientOptionsKeys: clientOptions ? Object.keys(clientOptions) : [],\n });\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 debug(\"ensureMetadataSession invoked\", {\n roomId: params.roomId,\n hasAuth: Boolean(params.auth && params.auth.length),\n });\n const client = this.ensureClient();\n await client.waitConnected();\n debug(\"websocket client ready for metadata session\", {\n status: client.getStatus(),\n });\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 debug(\"reusing metadata session\", {\n roomId: this.metadataSession.roomId,\n refCount: this.metadataSession.refCount,\n });\n return this.metadataSession;\n }\n\n if (this.metadataSession) {\n debug(\"tearing down previous metadata session\", {\n roomId: this.metadataSession.roomId,\n });\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 debug(\"joining metadata room\", {\n roomId: params.roomId,\n hasAuth: Boolean(params.auth && params.auth.length),\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 firstSynced.then(\n () => {\n debug(\"metadata session firstSynced resolved\", {\n roomId: params.roomId,\n });\n },\n (error) => {\n debug(\"metadata session firstSynced rejected\", {\n roomId: params.roomId,\n error,\n });\n },\n );\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 debug(\"teardownMetadataSession invoked\", { roomId: target.roomId });\n if (this.metadataSession === target) {\n this.metadataSession = undefined;\n }\n const { adaptor, room } = target;\n try {\n await room.leave();\n debug(\"metadata room left\", { roomId: target.roomId });\n } catch (error) {\n debug(\"metadata room leave failed; destroying\", {\n roomId: target.roomId,\n error,\n });\n await room.destroy().catch(() => { });\n }\n adaptor.destroy();\n debug(\"metadata session destroyed\", { roomId: target.roomId });\n }\n\n private async ensureDocSession(\n docId: string,\n doc: LoroDoc,\n params: TransportJoinParams,\n ): Promise<DocSession> {\n debug(\"ensureDocSession invoked\", { docId });\n const client = this.ensureClient();\n await client.waitConnected();\n debug(\"websocket client ready for doc session\", {\n docId,\n status: client.getStatus(),\n });\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 debug(\"doc session params resolved\", {\n docId,\n roomId,\n hasAuth: Boolean(auth && auth.length),\n });\n\n if (existing && existing.doc === doc && existing.roomId === roomId) {\n debug(\"reusing doc session\", {\n docId,\n roomId,\n refCount: existing.refCount,\n });\n return existing;\n }\n\n if (existing) {\n debug(\"doc session mismatch; leaving existing session\", {\n docId,\n previousRoomId: existing.roomId,\n nextRoomId: roomId,\n });\n await this.leaveDocSession(docId).catch(() => { });\n }\n\n const adaptor = new LoroAdaptor(doc);\n debug(\"joining doc room\", {\n docId,\n roomId,\n hasAuth: Boolean(auth && auth.length),\n });\n const room = await client.join({\n roomId,\n crdtAdaptor: adaptor,\n auth,\n });\n const firstSynced = room.waitForReachingServerVersion();\n firstSynced.then(\n () => {\n debug(\"doc session firstSynced resolved\", { docId, roomId });\n },\n (error) => {\n debug(\"doc session firstSynced rejected\", { docId, roomId, error });\n },\n );\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) {\n debug(\"leaveDocSession invoked but no session found\", { docId });\n return;\n }\n this.docSessions.delete(docId);\n debug(\"leaving doc session\", { docId, roomId: session.roomId });\n try {\n await session.room.leave();\n debug(\"doc room left\", { docId, roomId: session.roomId });\n } catch (error) {\n debug(\"doc room leave failed; destroying\", {\n docId,\n roomId: session.roomId,\n error,\n });\n await session.room.destroy().catch(() => { });\n }\n session.adaptor.destroy();\n debug(\"doc session destroyed\", { docId, roomId: session.roomId });\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 { promises as fs } from \"node:fs\";\nimport * as path from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\n\nimport { Flock, type ExportBundle } from \"@loro-dev/flock\";\nimport { LoroDoc } from \"loro-crdt\";\n\nimport type { AssetId, StorageAdapter, StorageSavePayload } from \"../types\";\n\nconst textDecoder = new TextDecoder();\n\nexport interface FileSystemStorageAdaptorOptions {\n /**\n * Base directory where metadata, document snapshots, and assets will be stored.\n * Defaults to `.loro-repo` inside the current working directory.\n */\n readonly baseDir?: string;\n /**\n * Subdirectory dedicated to document persistence. Defaults to `docs`.\n */\n readonly docsDirName?: string;\n /**\n * Subdirectory dedicated to asset blobs. Defaults to `assets`.\n */\n readonly assetsDirName?: string;\n /**\n * File name for the metadata snapshot bundle. Defaults to `meta.json`.\n */\n readonly metaFileName?: string;\n}\n\nexport class FileSystemStorageAdaptor implements StorageAdapter {\n private readonly baseDir: string;\n private readonly docsDir: string;\n private readonly assetsDir: string;\n private readonly metaPath: string;\n private readonly initPromise: Promise<void>;\n private updateCounter = 0;\n\n constructor(options: FileSystemStorageAdaptorOptions = {}) {\n this.baseDir = path.resolve(\n options.baseDir ?? path.join(process.cwd(), \".loro-repo\"),\n );\n this.docsDir = path.join(this.baseDir, options.docsDirName ?? \"docs\");\n this.assetsDir = path.join(this.baseDir, options.assetsDirName ?? \"assets\");\n this.metaPath = path.join(this.baseDir, options.metaFileName ?? \"meta.json\");\n this.initPromise = this.ensureLayout();\n }\n\n async save(payload: StorageSavePayload): Promise<void> {\n await this.initPromise;\n switch (payload.type) {\n case \"doc-snapshot\":\n await this.writeDocSnapshot(payload.docId, payload.snapshot);\n return;\n case \"doc-update\":\n await this.enqueueDocUpdate(payload.docId, payload.update);\n return;\n case \"asset\":\n await this.writeAsset(payload.assetId, payload.data);\n return;\n case \"meta\":\n await writeFileAtomic(this.metaPath, payload.update);\n return;\n default:\n throw new Error(`Unsupported payload type: ${(payload as { type: string }).type}`);\n }\n }\n\n async deleteAsset(assetId: AssetId): Promise<void> {\n await this.initPromise;\n const filePath = this.assetPath(assetId);\n await removeIfExists(filePath);\n }\n\n async loadDoc(docId: string): Promise<LoroDoc | undefined> {\n await this.initPromise;\n const snapshotPath = this.docSnapshotPath(docId);\n const snapshotBytes = await readFileIfExists(snapshotPath);\n const updateDir = this.docUpdatesDir(docId);\n const updateFiles = await listFiles(updateDir);\n\n if (!snapshotBytes && updateFiles.length === 0) {\n return undefined;\n }\n\n const doc = snapshotBytes\n ? LoroDoc.fromSnapshot(snapshotBytes)\n : new LoroDoc();\n\n if (updateFiles.length === 0) {\n return doc;\n }\n\n const updatePaths = updateFiles.map((file) => path.join(updateDir, file));\n for (const updatePath of updatePaths) {\n const update = await readFileIfExists(updatePath);\n if (!update) continue;\n doc.import(update);\n }\n\n await Promise.all(updatePaths.map((filePath) => removeIfExists(filePath)));\n\n const consolidated = doc.export({ mode: \"snapshot\" });\n await this.writeDocSnapshot(docId, consolidated);\n return doc;\n }\n\n async loadMeta(): Promise<Flock | undefined> {\n await this.initPromise;\n const bytes = await readFileIfExists(this.metaPath);\n if (!bytes) return undefined;\n try {\n const bundle = JSON.parse(textDecoder.decode(bytes)) as ExportBundle;\n const flock = new Flock();\n flock.importJson(bundle);\n return flock;\n } catch (error) {\n throw new Error(\"Failed to hydrate metadata snapshot\", { cause: error });\n }\n }\n\n async loadAsset(assetId: AssetId): Promise<Uint8Array | undefined> {\n await this.initPromise;\n return readFileIfExists(this.assetPath(assetId));\n }\n\n private async ensureLayout(): Promise<void> {\n await Promise.all([\n ensureDir(this.baseDir),\n ensureDir(this.docsDir),\n ensureDir(this.assetsDir),\n ]);\n }\n\n private async writeDocSnapshot(\n docId: string,\n snapshot: Uint8Array,\n ): Promise<void> {\n const targetDir = this.docDir(docId);\n await ensureDir(targetDir);\n await writeFileAtomic(this.docSnapshotPath(docId), snapshot);\n }\n\n private async enqueueDocUpdate(\n docId: string,\n update: Uint8Array,\n ): Promise<void> {\n const dir = this.docUpdatesDir(docId);\n await ensureDir(dir);\n const counter = (this.updateCounter = (this.updateCounter + 1) % 1_000_000);\n const timestamp = Date.now().toString().padStart(13, \"0\");\n const fileName = `${timestamp}-${counter.toString().padStart(6, \"0\")}.bin`;\n const filePath = path.join(dir, fileName);\n await writeFileAtomic(filePath, update);\n }\n\n private async writeAsset(assetId: AssetId, data: Uint8Array): Promise<void> {\n const filePath = this.assetPath(assetId);\n await ensureDir(path.dirname(filePath));\n await writeFileAtomic(filePath, data);\n }\n\n private docDir(docId: string): string {\n return path.join(this.docsDir, encodeComponent(docId));\n }\n\n private docSnapshotPath(docId: string): string {\n return path.join(this.docDir(docId), \"snapshot.bin\");\n }\n\n private docUpdatesDir(docId: string): string {\n return path.join(this.docDir(docId), \"updates\");\n }\n\n private assetPath(assetId: AssetId): string {\n return path.join(this.assetsDir, encodeComponent(assetId));\n }\n}\n\nfunction encodeComponent(value: string): string {\n return Buffer.from(value, \"utf8\").toString(\"base64url\");\n}\n\nasync function ensureDir(dir: string): Promise<void> {\n await fs.mkdir(dir, { recursive: true });\n}\n\nasync function readFileIfExists(filePath: string): Promise<Uint8Array | undefined> {\n try {\n const data = await fs.readFile(filePath);\n return new Uint8Array(data.buffer, data.byteOffset, data.byteLength).slice();\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return undefined;\n }\n throw error;\n }\n}\n\nasync function removeIfExists(filePath: string): Promise<void> {\n try {\n await fs.rm(filePath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return;\n }\n throw error;\n }\n}\n\nasync function listFiles(dir: string): Promise<string[]> {\n try {\n const entries = await fs.readdir(dir);\n return entries.sort();\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return [];\n }\n throw error;\n }\n}\n\nasync function writeFileAtomic(\n targetPath: string,\n data: Uint8Array,\n): Promise<void> {\n const dir = path.dirname(targetPath);\n await ensureDir(dir);\n const tempPath = path.join(dir, `.tmp-${randomUUID()}`);\n await fs.writeFile(tempPath, data);\n await fs.rename(tempPath, targetPath);\n}\n","import type {\n JsonObject,\n RepoEvent,\n RepoEventBy,\n RepoEventFilter,\n RepoEventListener,\n RepoWatchHandle,\n} from \"../types\";\n\ntype WatchEntry<Meta extends JsonObject> = {\n listener: RepoEventListener<Meta>;\n filter: RepoEventFilter<Meta>;\n};\n\nexport class RepoEventBus<Meta extends JsonObject> {\n private readonly watchers = new Set<WatchEntry<Meta>>();\n private readonly eventByStack: RepoEventBy[] = [];\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 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\n clear(): void {\n this.watchers.clear();\n this.eventByStack.length = 0;\n }\n\n pushEventBy(by: RepoEventBy): void {\n this.eventByStack.push(by);\n }\n\n popEventBy(): void {\n this.eventByStack.pop();\n }\n\n resolveEventBy(defaultBy: RepoEventBy): RepoEventBy {\n const index = this.eventByStack.length - 1;\n return index >= 0 ? this.eventByStack[index] : defaultBy;\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 }\n if (event.kind === \"asset-link\" || event.kind === \"asset-unlink\") {\n return event.docId;\n }\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\n return true;\n }\n}\n","import { Frontiers, LoroDoc, VersionVector } from \"loro-crdt\";\n\nimport type {\n AssetContent,\n JsonObject,\n JsonValue,\n ListDocQuery,\n RepoAssetMetadata,\n} from \"./types\";\n\ntype PossibleCrypto = {\n subtle?: {\n digest: (\n algorithm: string,\n data: ArrayBufferView | ArrayBuffer,\n ) => Promise<ArrayBuffer>;\n };\n};\n\nexport async 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\nexport async 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\nexport function bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes, (byte) => byte.toString(16).padStart(2, \"0\")).join(\n \"\",\n );\n}\n\nexport async 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 function 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\nexport function 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\nexport function 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 Boolean(value && typeof value === \"object\" && !Array.isArray(value));\n}\n\nexport function stableStringify(value: JsonValue): string {\n if (value === null) return \"null\";\n if (typeof value === \"string\") return JSON.stringify(value);\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return JSON.stringify(value);\n }\n if (Array.isArray(value)) {\n return `[${value.map(stableStringify).join(\",\")}]`;\n }\n if (!isJsonObjectValue(value)) {\n return \"null\";\n }\n const entries = Object.keys(value)\n .sort()\n .map((key) => `${JSON.stringify(key)}:${stableStringify(value[key])}`);\n return `{${entries.join(\",\")}}`;\n}\n\nexport function jsonEquals(a?: JsonValue, b?: JsonValue): 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\nexport function diffJsonObjects(\n previous: JsonObject | undefined,\n next: JsonObject,\n): JsonObject {\n const patch: JsonObject = {};\n const keys = new Set<string>();\n if (previous) {\n for (const key of Object.keys(previous)) keys.add(key);\n }\n for (const key of Object.keys(next)) keys.add(key);\n for (const key of keys) {\n const prevValue = previous ? previous[key] : undefined;\n const nextValue = next[key];\n if (!jsonEquals(prevValue, nextValue)) {\n if (nextValue === undefined && previous && key in previous) {\n patch[key] = null;\n continue;\n }\n const cloned = cloneJsonValue(nextValue);\n if (cloned !== undefined) {\n patch[key] = cloned;\n }\n }\n }\n return patch;\n}\n\nexport function 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\nexport function assetMetaFromJson(\n value: unknown,\n): 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\nexport function 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\nexport function cloneRepoAssetMetadata(\n meta: RepoAssetMetadata,\n): 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\nexport function toReadableStream(\n bytes: Uint8Array,\n): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controller.enqueue(bytes);\n controller.close();\n },\n });\n}\n\nexport function 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\nexport function emptyFrontiers(): Frontiers {\n return [];\n}\n\nexport function 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\nexport function canonicalizeVersionVector(vv: VersionVector): {\n json: JsonObject;\n key: string;\n} {\n const json = versionVectorToJson(vv);\n return { json, key: stableStringify(json) };\n}\n\nexport function canonicalizeFrontiers(frontiers: Frontiers): {\n json: JsonValue;\n key: string;\n} {\n const sorted = [...frontiers].sort((a, b) => {\n if (a.peer < b.peer) return -1;\n if (a.peer > b.peer) return 1;\n return a.counter - b.counter;\n });\n const json = sorted.map((f) => ({ peer: f.peer, counter: f.counter }));\n return { json, key: stableStringify(json) };\n}\n\nexport function includesFrontiers(\n vv: VersionVector,\n frontiers: Frontiers,\n): boolean {\n for (const { peer, counter } of frontiers) {\n const local = vv.get(peer) ?? 0;\n // Version Vector stores the *next* expected op counter (exclusive).\n // Frontiers store the *last* applied op counter (inclusive).\n // If local <= counter, it means the Version Vector has not yet reached (included) the Frontier op.\n if (local <= counter) return false;\n }\n return true;\n}\n\nexport function 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","export function 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","import { Flock } from \"@loro-dev/flock\";\nimport { LoroDoc, type LoroEventBatch, type VersionVector, type Frontiers } from \"loro-crdt\";\n\nimport type {\n JsonObject,\n RepoEventBy,\n StorageAdapter,\n} from \"../types\";\nimport { RepoEventBus } from \"./event-bus\";\nimport { canonicalizeFrontiers, includesFrontiers } from \"../utils\";\nimport { logAsyncError } from \"./logging\";\nimport type { RepoState } from \"./repo-state\";\n\ntype PendingDocFrontierUpdate = {\n timeout: ReturnType<typeof setTimeout>;\n doc: LoroDoc;\n by: RepoEventBy;\n};\n\ninterface DocManagerOptions<Meta extends JsonObject> {\n readonly storage?: StorageAdapter;\n readonly docFrontierDebounceMs: number;\n readonly getMetaFlock: () => Flock;\n readonly eventBus: RepoEventBus<Meta>;\n readonly persistMeta: () => Promise<void>;\n readonly state: RepoState;\n}\n\nexport class DocManager<Meta extends JsonObject> {\n private readonly storage?: StorageAdapter;\n private readonly docFrontierDebounceMs: number;\n private readonly getMetaFlock: () => Flock;\n private readonly eventBus: RepoEventBus<Meta>;\n private readonly persistMeta: () => Promise<void>;\n private readonly state: RepoState;\n\n private readonly docs = new Map<string, LoroDoc>();\n private readonly docSubscriptions = new Map<string, () => void>();\n private readonly docFrontierUpdates = new Map<\n string,\n PendingDocFrontierUpdate\n >();\n private readonly docPersistedVersions = new Map<string, VersionVector>();\n\n private get docFrontierKeys(): Map<string, Set<string>> {\n return this.state.docFrontierKeys;\n }\n constructor(options: DocManagerOptions<Meta>) {\n this.storage = options.storage;\n this.docFrontierDebounceMs = options.docFrontierDebounceMs;\n this.getMetaFlock = options.getMetaFlock;\n this.eventBus = options.eventBus;\n this.persistMeta = options.persistMeta;\n this.state = options.state;\n }\n\n async openCollaborativeDoc(\n docId: string,\n ): Promise<LoroDoc> {\n const doc = await this.ensureDoc(docId);\n return doc;\n }\n\n async openDetachedDoc(docId: string): Promise<LoroDoc> {\n const doc = await this.materializeDetachedDoc(docId);\n return doc\n }\n\n async ensureDoc(docId: string): Promise<LoroDoc> {\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(docId, cached.version());\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 = new LoroDoc();\n this.registerDoc(docId, created);\n return created;\n }\n\n async persistDoc(docId: string, doc: LoroDoc): Promise<void> {\n const previousVersion = this.docPersistedVersions.get(docId);\n const snapshot = doc.export({ mode: \"snapshot\" });\n const nextVersion = doc.version();\n if (!this.storage) {\n this.docPersistedVersions.set(docId, nextVersion);\n return;\n }\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 async updateDocFrontiers(\n docId: string,\n doc: LoroDoc,\n defaultBy: RepoEventBy,\n ): Promise<void> {\n const frontiers = doc.oplogFrontiers();\n const { json, key } = canonicalizeFrontiers(frontiers);\n const existingKeys = this.docFrontierKeys.get(docId) ?? new Set<string>();\n let mutated = false;\n\n const metaFlock = this.metaFlock;\n const vv = doc.version();\n\n for (const entry of existingKeys) {\n if (entry === key) continue;\n let oldFrontiers: Frontiers;\n try {\n oldFrontiers = JSON.parse(entry);\n } catch {\n continue;\n }\n\n if (includesFrontiers(vv, oldFrontiers)) {\n metaFlock.delete([\"f\", docId, entry]);\n mutated = true;\n }\n }\n\n if (!existingKeys.has(key)) {\n metaFlock.put([\"f\", docId, key], json);\n mutated = true;\n }\n\n if (mutated) {\n this.refreshDocFrontierKeys(docId);\n await this.persistMeta();\n }\n\n const by = this.eventBus.resolveEventBy(defaultBy);\n this.eventBus.emit({ kind: \"doc-frontiers\", docId, frontiers, by });\n }\n\n async flushScheduledDocFrontierUpdate(docId: string): 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.eventBus.pushEventBy(pending.by);\n try {\n await this.updateDocFrontiers(docId, pending.doc, pending.by);\n } finally {\n this.eventBus.popEventBy();\n }\n return true;\n }\n\n async unloadDoc(docId: string): Promise<void> {\n const doc = this.docs.get(docId);\n if (!doc) return;\n\n // 1. Flush any pending frontier updates\n await this.flushScheduledDocFrontierUpdate(docId);\n\n // 2. Persist the final state\n await this.persistDocUpdate(docId, doc);\n\n // 3. Update frontiers one last time if needed (local changes)\n // We assume \"local\" because we are unloading it from the local repo\n await this.updateDocFrontiers(docId, doc, \"local\");\n\n // 4. Cleanup subscriptions and map entries\n const unsubscribe = this.docSubscriptions.get(docId);\n unsubscribe?.();\n this.docSubscriptions.delete(docId);\n this.docs.delete(docId);\n this.docPersistedVersions.delete(docId);\n // We don't clear docFrontierKeys here because they are part of the metadata (Flock)\n // and should persist even if the doc is unloaded from memory.\n }\n\n async flush(): Promise<void> {\n const promises: Promise<void>[] = [];\n for (const [docId, doc] of this.docs) {\n promises.push(\n (async () => {\n await this.persistDocUpdate(docId, doc);\n await this.flushScheduledDocFrontierUpdate(docId);\n })()\n );\n }\n await Promise.all(promises);\n }\n\n async close(): Promise<void> {\n // Flush everything before closing\n await this.flush();\n\n for (const unsubscribe of this.docSubscriptions.values()) {\n try {\n unsubscribe();\n } catch {\n // ignore subscriber errors during shutdown\n }\n }\n this.docSubscriptions.clear();\n this.docFrontierUpdates.clear();\n this.docs.clear();\n this.docPersistedVersions.clear();\n this.docFrontierKeys.clear();\n }\n\n hydrateFrontierKeys(): void {\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 }\n const set = nextFrontierKeys.get(docId) ?? new Set<string>();\n set.add(frontierKey);\n nextFrontierKeys.set(docId, set);\n }\n this.docFrontierKeys.clear();\n for (const [docId, keys] of nextFrontierKeys) {\n this.docFrontierKeys.set(docId, keys);\n }\n }\n\n 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 if (row.value === undefined || row.value === null) 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 get metaFlock(): Flock {\n return this.getMetaFlock();\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.eventBus.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 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.eventBus.pushEventBy(pending.by);\n void (async () => {\n try {\n await this.updateDocFrontiers(docId, pending.doc, pending.by);\n } finally {\n this.eventBus.popEventBy();\n }\n })().catch(logAsyncError(`doc ${docId} frontier debounce`));\n }\n\n\n\n private async materializeDetachedDoc(docId: string): Promise<LoroDoc> {\n const snapshot = await this.exportDocSnapshot(docId);\n if (snapshot) {\n return LoroDoc.fromSnapshot(snapshot);\n }\n return new LoroDoc()\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 persistDocUpdate(docId: string, doc: LoroDoc): Promise<void> {\n const previousVersion = this.docPersistedVersions.get(docId);\n const nextVersion = doc.oplogVersion();\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 if (previousVersion.compare(nextVersion) === 0) {\n return;\n }\n\n const update = doc.export({ mode: \"update\", from: previousVersion });\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 onDocEvent(\n docId: string,\n doc: LoroDoc,\n _batch: LoroEventBatch,\n by: RepoEventBy,\n ): void {\n void (async () => {\n const persist = this.persistDocUpdate(docId, doc);\n if (by === \"local\") {\n this.scheduleDocFrontierUpdate(docId, doc, by);\n await persist;\n return;\n }\n\n const flushed = this.flushScheduledDocFrontierUpdate(docId);\n const updated = (async () => {\n this.eventBus.pushEventBy(by);\n try {\n await this.updateDocFrontiers(docId, doc, by);\n } finally {\n this.eventBus.popEventBy();\n }\n })();\n await Promise.all([persist, flushed, updated]);\n })().catch(logAsyncError(`doc ${docId} event processing`));\n }\n}\n","import { Flock } from \"@loro-dev/flock\";\nimport type { ScanOptions } from \"@loro-dev/flock\";\n\nimport type {\n JsonObject,\n JsonValue,\n ListDocQuery,\n RepoDocMeta,\n RepoEventBy,\n} from \"../types\";\nimport {\n asJsonObject,\n cloneJsonObject,\n cloneJsonValue,\n diffJsonObjects,\n jsonEquals,\n matchesQuery,\n} from \"../utils\";\nimport { RepoEventBus } from \"./event-bus\";\nimport type { RepoState } from \"./repo-state\";\n\ninterface MetadataManagerOptions<Meta extends JsonObject> {\n readonly getMetaFlock: () => Flock;\n readonly eventBus: RepoEventBus<Meta>;\n readonly persistMeta: () => Promise<void>;\n readonly state: RepoState;\n}\n\nexport class MetadataManager<Meta extends JsonObject> {\n private readonly getMetaFlock: () => Flock;\n private readonly eventBus: RepoEventBus<Meta>;\n private readonly persistMeta: () => Promise<void>;\n private readonly state: RepoState;\n\n constructor(options: MetadataManagerOptions<Meta>) {\n this.getMetaFlock = options.getMetaFlock;\n this.eventBus = options.eventBus;\n this.persistMeta = options.persistMeta;\n this.state = options.state;\n }\n\n getDocIds(): string[] {\n return Array.from(this.state.metadata.keys());\n }\n\n entries(): IterableIterator<[string, JsonObject]> {\n return this.state.metadata.entries();\n }\n\n get(docId: string): Meta | undefined {\n const metadata = this.state.metadata.get(docId);\n return metadata ? (cloneJsonObject(metadata) as Meta) : undefined;\n }\n\n listDoc(query?: ListDocQuery): RepoDocMeta<Meta>[] {\n if (query?.limit !== undefined && query.limit <= 0) {\n return [];\n }\n\n const { startKey, endKey } = this.computeDocRangeKeys(query);\n if (startKey && endKey && startKey >= endKey) {\n return [];\n }\n\n const scanOptions: ScanOptions = { prefix: [\"m\"] };\n if (startKey) {\n scanOptions.start = { kind: \"inclusive\", key: [\"m\", startKey] };\n }\n if (endKey) {\n scanOptions.end = { kind: \"exclusive\", key: [\"m\", endKey] };\n }\n\n const rows = this.metaFlock.scan(scanOptions);\n const seen = new Set<string>();\n const entries: RepoDocMeta<Meta>[] = [];\n\n for (const row of rows) {\n if (query?.limit !== undefined && entries.length >= query.limit) {\n break;\n }\n if (!Array.isArray(row.key) || row.key.length < 2) continue;\n const docId = row.key[1];\n if (typeof docId !== \"string\") continue;\n if (seen.has(docId)) continue;\n seen.add(docId);\n\n const metadata = this.state.metadata.get(docId);\n if (!metadata) continue;\n if (!matchesQuery(docId, metadata, query)) continue;\n\n entries.push({ docId, meta: cloneJsonObject(metadata) as Meta });\n if (query?.limit !== undefined && entries.length >= query.limit) {\n break;\n }\n }\n\n return entries;\n }\n\n async upsert(docId: string, patch: Partial<Meta>): Promise<void> {\n const base = this.state.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.state.metadata.has(docId)) {\n this.state.metadata.set(docId, next);\n }\n return;\n }\n\n this.state.metadata.set(docId, next);\n await this.persistMeta();\n this.eventBus.emit({\n kind: \"doc-metadata\",\n docId,\n patch: cloneJsonObject(outPatch) as Partial<Meta>,\n by: \"local\",\n });\n }\n\n refreshFromFlock(docId: string, by: RepoEventBy): void {\n const previous = this.state.metadata.get(docId);\n const next = this.readDocMetadataFromFlock(docId);\n\n if (!next) {\n if (previous) {\n this.state.metadata.delete(docId);\n this.eventBus.emit({\n kind: \"doc-metadata\",\n docId,\n patch: {} as Partial<Meta>,\n by,\n });\n }\n return;\n }\n\n this.state.metadata.set(docId, next);\n const patch = diffJsonObjects(previous, next);\n if (!previous || Object.keys(patch).length > 0) {\n this.eventBus.emit({\n kind: \"doc-metadata\",\n docId,\n patch: patch as Partial<Meta>,\n by,\n });\n }\n }\n\n replaceAll(nextMetadata: Map<string, JsonObject>, by: RepoEventBy): void {\n const prevMetadata = new Map(this.state.metadata);\n this.state.metadata.clear();\n for (const [docId, meta] of nextMetadata) {\n this.state.metadata.set(docId, meta);\n }\n\n const docIds = new Set<string>([\n ...prevMetadata.keys(),\n ...nextMetadata.keys(),\n ]);\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.eventBus.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 (!previous || Object.keys(patch).length > 0) {\n this.eventBus.emit({\n kind: \"doc-metadata\",\n docId,\n patch: patch as Partial<Meta>,\n by,\n });\n }\n }\n }\n\n clear(): void {\n this.state.metadata.clear();\n }\n\n private computeDocRangeKeys(\n query?: ListDocQuery,\n ): { startKey?: string; endKey?: string } {\n if (!query) {\n return {};\n }\n\n const prefix = query.prefix && query.prefix.length > 0 ? query.prefix : undefined;\n let startKey = query.start;\n if (prefix) {\n startKey = !startKey || prefix > startKey ? prefix : startKey;\n }\n\n let endKey = query.end;\n const prefixEnd = this.nextLexicographicString(prefix);\n if (prefixEnd) {\n endKey = !endKey || prefixEnd < endKey ? prefixEnd : endKey;\n }\n\n return { startKey, endKey };\n }\n\n private nextLexicographicString(value?: string): string | undefined {\n if (!value) return undefined;\n for (let i = value.length - 1; i >= 0; i -= 1) {\n const code = value.charCodeAt(i);\n if (code < 0xffff) {\n return `${value.slice(0, i)}${String.fromCharCode(code + 1)}`;\n }\n }\n return undefined;\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 get metaFlock(): Flock {\n return this.getMetaFlock();\n }\n}\n","import { Flock } from \"@loro-dev/flock\";\n\nimport type {\n AssetDownload,\n AssetId,\n AssetTransportAdapter,\n GarbageCollectionOptions,\n JsonObject,\n LinkAssetOptions,\n RepoAssetMetadata,\n RepoEventBy,\n StorageAdapter,\n UploadAssetOptions,\n} from \"../types\";\nimport {\n assetContentToUint8Array,\n assetMetaFromJson,\n assetMetaToJson,\n assetMetadataEqual,\n cloneRepoAssetMetadata,\n computeSha256,\n streamToUint8Array,\n toReadableStream,\n} from \"../utils\";\nimport { RepoEventBus } from \"./event-bus\";\nimport { logAsyncError } from \"./logging\";\nimport type { RepoState, AssetRecord, OrphanedAssetRecord } from \"./repo-state\";\n\ninterface AssetManagerOptions<Meta extends JsonObject> {\n readonly storage?: StorageAdapter;\n readonly assetTransport?: AssetTransportAdapter;\n readonly getMetaFlock: () => Flock;\n readonly eventBus: RepoEventBus<Meta>;\n readonly persistMeta: () => Promise<void>;\n readonly state: RepoState;\n}\n\nexport class AssetManager<Meta extends JsonObject> {\n private readonly storage?: StorageAdapter;\n private readonly assetTransport?: AssetTransportAdapter;\n private readonly getMetaFlock: () => Flock;\n private readonly eventBus: RepoEventBus<Meta>;\n private readonly persistMeta: () => Promise<void>;\n private readonly state: RepoState;\n private get docAssets(): Map<string, Map<AssetId, RepoAssetMetadata>> {\n return this.state.docAssets;\n }\n private get assets(): Map<AssetId, AssetRecord> {\n return this.state.assets;\n }\n private get orphanedAssets(): Map<AssetId, OrphanedAssetRecord> {\n return this.state.orphanedAssets;\n }\n private get assetToDocRefs(): Map<AssetId, Set<string>> {\n return this.state.assetToDocRefs;\n }\n\n constructor(options: AssetManagerOptions<Meta>) {\n this.storage = options.storage;\n this.assetTransport = options.assetTransport;\n this.getMetaFlock = options.getMetaFlock;\n this.eventBus = options.eventBus;\n this.persistMeta = options.persistMeta;\n this.state = options.state;\n }\n\n async uploadAsset(params: UploadAssetOptions): Promise<AssetId> {\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.eventBus.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 this.updateDocAssetMetadata(assetId, metadata);\n\n this.metaFlock.put([\"a\", assetId], assetMetaToJson(metadata));\n await this.persistMeta();\n\n this.eventBus.emit({\n kind: \"asset-metadata\",\n asset: this.createAssetDownload(assetId, metadata, storedBytes),\n by: \"local\",\n });\n\n return assetId;\n }\n\n async linkAsset(docId: string, params: LinkAssetOptions): Promise<AssetId> {\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.eventBus.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 this.updateDocAssetMetadata(assetId, metadata);\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 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.eventBus.emit({ kind: \"asset-link\", docId, assetId, by: \"local\" });\n if (created) {\n this.eventBus.emit({\n kind: \"asset-metadata\",\n asset: this.createAssetDownload(\n assetId,\n metadata,\n storedBytes ?? bytes,\n ),\n by: \"local\",\n });\n }\n return assetId;\n }\n\n async unlinkAsset(docId: string, assetId: AssetId): Promise<void> {\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 const refs = this.assetToDocRefs.get(assetId);\n if (refs) {\n refs.delete(docId);\n if (refs.size === 0) {\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.eventBus.emit({ kind: \"asset-unlink\", docId, assetId, by: \"local\" });\n }\n\n async listAssets(docId: string): Promise<RepoAssetMetadata[]> {\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 async fetchAsset(assetId: AssetId): Promise<AssetDownload> {\n const { metadata, bytes } = await this.materializeAsset(assetId);\n return this.createAssetDownload(assetId, metadata, bytes);\n }\n\n async gcAssets(options: GarbageCollectionOptions = {}): Promise<number> {\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 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.removeDocAssetReference(assetId, docId);\n this.eventBus.emit({ kind: \"asset-unlink\", docId, assetId, by });\n }\n }\n return;\n }\n\n this.docAssets.set(docId, mapping);\n\n const removed: AssetId[] = [];\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 removed) {\n this.removeDocAssetReference(assetId, docId);\n this.eventBus.emit({ kind: \"asset-unlink\", docId, assetId, by });\n }\n\n for (const assetId of mapping.keys()) {\n const isNew = !previous || !previous.has(assetId);\n this.addDocReference(assetId, docId);\n if (isNew) {\n this.eventBus.emit({ kind: \"asset-link\", docId, assetId, by });\n }\n }\n }\n\n 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 this.updateDocAssetMetadata(assetId, cloneRepoAssetMetadata(metadata));\n\n if (!previous || !assetMetadataEqual(previous.metadata, metadata)) {\n this.eventBus.emit({\n kind: \"asset-metadata\",\n asset: this.createAssetDownload(assetId, metadata, existingData),\n by,\n });\n }\n }\n\n hydrateFromFlock(by: RepoEventBy): void {\n const prevDocAssets = new Map(this.docAssets);\n const prevAssets = new Map(this.assets);\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 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.docAssets.clear();\n for (const [docId, assets] of nextDocAssets) {\n this.docAssets.set(docId, assets);\n }\n\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 for (const [assetId, record] of nextAssets) {\n const previous = prevAssets.get(assetId)?.metadata;\n if (!assetMetadataEqual(previous, record.metadata)) {\n this.eventBus.emit({\n kind: \"asset-metadata\",\n asset: this.createAssetDownload(assetId, record.metadata, record.data),\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.eventBus.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.eventBus.emit({ kind: \"asset-unlink\", docId, assetId, by });\n }\n }\n }\n }\n\n clear(): void {\n this.docAssets.clear();\n this.assets.clear();\n this.orphanedAssets.clear();\n this.assetToDocRefs.clear();\n }\n\n private readDocAssetsFromFlock(\n docId: string,\n ): 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 =\n 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(\n assetId: AssetId,\n ): 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 this.markAssetAsOrphan(assetId, record.metadata);\n\n const refs = this.assetToDocRefs.get(assetId);\n if (refs) {\n this.assetToDocRefs.delete(assetId);\n for (const docId of refs) {\n const assets = this.docAssets.get(docId);\n if (assets?.delete(assetId) && assets.size === 0) {\n this.docAssets.delete(docId);\n }\n this.eventBus.emit({ kind: \"asset-unlink\", docId, assetId, by });\n }\n return;\n }\n\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 this.eventBus.emit({ kind: \"asset-unlink\", docId, assetId, by });\n }\n }\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 const refs = this.assetToDocRefs.get(assetId);\n if (!refs) return;\n for (const docId of refs) {\n const assets = this.docAssets.get(docId);\n if (assets) {\n assets.set(assetId, metadata);\n }\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 addDocReference(assetId: AssetId, docId: string): void {\n const refs = this.assetToDocRefs.get(assetId) ?? new Set<string>();\n refs.add(docId);\n this.assetToDocRefs.set(assetId, refs);\n }\n\n private removeDocAssetReference(assetId: AssetId, docId: string): void {\n const refs = this.assetToDocRefs.get(assetId);\n if (!refs) return;\n refs.delete(docId);\n if (refs.size === 0) {\n this.assetToDocRefs.delete(assetId);\n this.markAssetAsOrphan(assetId);\n }\n }\n\n private markAssetAsOrphan(\n assetId: AssetId,\n metadataOverride?: RepoAssetMetadata,\n ): void {\n const metadata = metadataOverride ?? this.assets.get(assetId)?.metadata;\n if (!metadata) return;\n const existing = this.orphanedAssets.get(assetId);\n const deletedAt = existing?.deletedAt ?? Date.now();\n this.orphanedAssets.set(assetId, {\n metadata,\n deletedAt,\n });\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 get metaFlock(): Flock {\n return this.getMetaFlock();\n }\n}\n","import { Flock, type Event as FlockEvent } from \"@loro-dev/flock\";\n\nimport type { AssetId, JsonObject, RepoEventBy } from \"../types\";\nimport { asJsonObject, cloneJsonValue } from \"../utils\";\nimport { MetadataManager } from \"./metadata-manager\";\nimport { AssetManager } from \"./asset-manager\";\nimport { DocManager } from \"./doc-manager\";\n\ninterface FlockHydratorOptions<Meta extends JsonObject> {\n readonly getMetaFlock: () => Flock;\n readonly metadataManager: MetadataManager<Meta>;\n readonly assetManager: AssetManager<Meta>;\n readonly docManager: DocManager<Meta>;\n}\n\nexport class FlockHydrator<Meta extends JsonObject> {\n private readonly getMetaFlock: () => Flock;\n private readonly metadataManager: MetadataManager<Meta>;\n private readonly assetManager: AssetManager<Meta>;\n private readonly docManager: DocManager<Meta>;\n\n constructor(options: FlockHydratorOptions<Meta>) {\n this.getMetaFlock = options.getMetaFlock;\n this.metadataManager = options.metadataManager;\n this.assetManager = options.assetManager;\n this.docManager = options.docManager;\n }\n\n hydrateAll(by: RepoEventBy): void {\n const nextMetadata = this.readAllDocMetadata();\n this.metadataManager.replaceAll(nextMetadata, by);\n this.assetManager.hydrateFromFlock(by);\n this.docManager.hydrateFrontierKeys();\n }\n\n applyEvents(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 as 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 as 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.assetManager.refreshAssetMetadataEntry(assetId, by);\n }\n\n for (const docId of docMetadataIds) {\n this.metadataManager.refreshFromFlock(docId, by);\n }\n\n for (const docId of docAssetIds) {\n this.assetManager.refreshDocAssetsEntry(docId, by);\n }\n\n for (const docId of docFrontiersIds) {\n this.docManager.refreshDocFrontierKeys(docId);\n }\n }\n\n private readAllDocMetadata(): Map<string, JsonObject> {\n const nextMetadata = new Map<string, JsonObject>();\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 return nextMetadata;\n }\n\n private get metaFlock(): Flock {\n return this.getMetaFlock();\n }\n}\n","import { Flock, type Event as FlockEvent } from \"@loro-dev/flock\";\n\nimport type {\n JsonObject,\n RepoSyncOptions,\n StorageAdapter,\n TransportAdapter,\n TransportJoinParams,\n TransportSubscription,\n} from \"../types\";\nimport { RepoEventBus } from \"./event-bus\";\nimport { DocManager } from \"./doc-manager\";\nimport { MetadataManager } from \"./metadata-manager\";\nimport { AssetManager } from \"./asset-manager\";\nimport { FlockHydrator } from \"./flock-hydrator\";\nimport { logAsyncError } from \"./logging\";\n\ninterface SyncRunnerOptions<Meta extends JsonObject> {\n readonly storage?: StorageAdapter;\n readonly transport?: TransportAdapter;\n readonly eventBus: RepoEventBus<Meta>;\n readonly docManager: DocManager<Meta>;\n readonly metadataManager: MetadataManager<Meta>;\n readonly assetManager: AssetManager<Meta>;\n readonly flockHydrator: FlockHydrator<Meta>;\n readonly getMetaFlock: () => Flock;\n readonly mergeFlock: (snapshot: Flock) => void;\n readonly persistMeta: () => Promise<void>;\n}\n\n/**\n * Sync data between storage and transport layer\n */\nexport class SyncRunner<Meta extends JsonObject> {\n private readonly storage?: StorageAdapter;\n private readonly transport?: TransportAdapter;\n private readonly eventBus: RepoEventBus<Meta>;\n private readonly docManager: DocManager<Meta>;\n private readonly metadataManager: MetadataManager<Meta>;\n private readonly assetManager: AssetManager<Meta>;\n private readonly flockHydrator: FlockHydrator<Meta>;\n private readonly getMetaFlock: () => Flock;\n private readonly replaceMetaFlock: (snapshot: Flock) => void;\n private readonly persistMeta: () => Promise<void>;\n\n private readyPromise?: Promise<void>;\n private metaRoomSubscription?: TransportSubscription;\n private unsubscribeMetaFlock?: () => void;\n private readonly docSubscriptions = new Map<string, TransportSubscription>();\n\n constructor(options: SyncRunnerOptions<Meta>) {\n this.storage = options.storage;\n this.transport = options.transport;\n this.eventBus = options.eventBus;\n this.docManager = options.docManager;\n this.metadataManager = options.metadataManager;\n this.assetManager = options.assetManager;\n this.flockHydrator = options.flockHydrator;\n this.getMetaFlock = options.getMetaFlock;\n this.replaceMetaFlock = options.mergeFlock;\n this.persistMeta = options.persistMeta;\n }\n\n async ready(): Promise<void> {\n if (!this.readyPromise) {\n this.readyPromise = this.initialize();\n }\n await this.readyPromise;\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.eventBus.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.flockHydrator.applyEvents(recordedEvents, \"sync\");\n } else {\n this.flockHydrator.hydrateAll(\"sync\");\n }\n await this.persistMeta();\n } finally {\n unsubscribe();\n this.eventBus.popEventBy();\n }\n }\n\n if (scope === \"doc\" || scope === \"full\") {\n const targets = docIds ?? this.metadataManager.getDocIds();\n for (const docId of targets) {\n const doc = await this.docManager.ensureDoc(docId);\n this.eventBus.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.eventBus.popEventBy();\n }\n await this.docManager.persistDoc(docId, doc);\n await this.docManager.updateDocFrontiers(docId, doc, \"sync\");\n }\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.eventBus.resolveEventBy(\"live\");\n this.flockHydrator.hydrateAll(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\n const existing = this.docSubscriptions.get(docId);\n if (existing) {\n return existing;\n }\n\n const doc = await this.docManager.ensureDoc(docId);\n const subscription = this.transport.joinDocRoom(docId, doc, params);\n const wrapped: TransportSubscription = {\n unsubscribe: () => {\n subscription.unsubscribe();\n if (this.docSubscriptions.get(docId) === wrapped) {\n this.docSubscriptions.delete(docId);\n }\n },\n firstSyncedWithRemote: subscription.firstSyncedWithRemote,\n get connected() {\n return subscription.connected;\n },\n };\n\n this.docSubscriptions.set(docId, wrapped);\n void subscription.firstSyncedWithRemote.catch(\n logAsyncError(`doc ${docId} first sync`),\n );\n return wrapped;\n }\n\n async destroy(): Promise<void> {\n await this.docManager.close();\n this.metaRoomSubscription?.unsubscribe();\n this.metaRoomSubscription = undefined;\n for (const sub of this.docSubscriptions.values()) {\n sub.unsubscribe();\n }\n this.docSubscriptions.clear();\n if (this.unsubscribeMetaFlock) {\n this.unsubscribeMetaFlock();\n this.unsubscribeMetaFlock = undefined;\n }\n this.eventBus.clear();\n this.metadataManager.clear();\n this.assetManager.clear();\n this.readyPromise = undefined;\n await this.transport?.close();\n }\n\n private async initialize(): Promise<void> {\n if (this.storage) {\n const snapshot = await this.storage.loadMeta();\n if (snapshot) {\n this.replaceMetaFlock(snapshot);\n }\n }\n this.flockHydrator.hydrateAll(\"sync\");\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.eventBus.resolveEventBy(\"live\");\n void (async () => {\n this.flockHydrator.applyEvents(batch.events, by);\n await this.persistMeta();\n })().catch(logAsyncError(\"meta live monitor sync\"));\n });\n }\n\n private get metaFlock(): Flock {\n return this.getMetaFlock();\n }\n}\n","import type { AssetId, JsonObject, RepoAssetMetadata } from \"../types\";\n\nexport type AssetRecord = {\n metadata: RepoAssetMetadata;\n data?: Uint8Array;\n};\n\nexport type OrphanedAssetRecord = {\n metadata: RepoAssetMetadata;\n deletedAt: number;\n};\n\nexport interface RepoState {\n readonly metadata: Map<string, JsonObject>;\n readonly docAssets: Map<string, Map<AssetId, RepoAssetMetadata>>;\n readonly assets: Map<AssetId, AssetRecord>;\n readonly orphanedAssets: Map<AssetId, OrphanedAssetRecord>;\n readonly assetToDocRefs: Map<AssetId, Set<string>>;\n readonly docFrontierKeys: Map<string, Set<string>>;\n}\n\nexport function createRepoState(): RepoState {\n return {\n metadata: new Map<string, JsonObject>(),\n docAssets: new Map<string, Map<AssetId, RepoAssetMetadata>>(),\n assets: new Map<AssetId, AssetRecord>(),\n orphanedAssets: new Map<AssetId, OrphanedAssetRecord>(),\n assetToDocRefs: new Map<AssetId, Set<string>>(),\n docFrontierKeys: new Map<string, Set<string>>(),\n };\n}\n","import { Flock } from \"@loro-dev/flock\";\nimport { LoroDoc } 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\";\nexport {\n FileSystemStorageAdaptor,\n type FileSystemStorageAdaptorOptions,\n} from \"./storage/filesystem\";\n\nimport type {\n AssetDownload,\n AssetId,\n GarbageCollectionOptions,\n JsonObject,\n ListDocQuery,\n LoroRepoOptions,\n LinkAssetOptions,\n RepoAssetMetadata,\n RepoDocHandle,\n RepoDocMeta,\n RepoEventFilter,\n RepoEventListener,\n RepoSyncOptions,\n RepoWatchHandle,\n StorageAdapter,\n TransportAdapter,\n TransportJoinParams,\n TransportSubscription,\n UploadAssetOptions,\n AssetTransportAdapter,\n} from \"./types\";\n\nimport { RepoEventBus } from \"./internal/event-bus\";\nimport { DocManager } from \"./internal/doc-manager\";\nimport { MetadataManager } from \"./internal/metadata-manager\";\nimport { AssetManager } from \"./internal/asset-manager\";\nimport { FlockHydrator } from \"./internal/flock-hydrator\";\nimport { SyncRunner } from \"./internal/sync-runner\";\nimport { createRepoState, type RepoState } from \"./internal/repo-state\";\n\nconst textEncoder = new TextEncoder();\nconst DEFAULT_DOC_FRONTIER_DEBOUNCE_MS = 1_000;\n\nexport class LoroRepo<Meta extends JsonObject = JsonObject> {\n readonly options: LoroRepoOptions<Meta>;\n private _destroyed = false;\n private readonly transport?: TransportAdapter;\n private readonly storage?: StorageAdapter;\n private metaFlock: Flock = new Flock();\n private readonly eventBus: RepoEventBus<Meta>;\n private readonly docManager: DocManager<Meta>;\n private readonly metadataManager: MetadataManager<Meta>;\n private readonly assetManager: AssetManager<Meta>;\n private readonly assetTransport?: AssetTransportAdapter;\n private readonly flockHydrator: FlockHydrator<Meta>;\n private readonly state: RepoState;\n private readonly syncRunner: SyncRunner<Meta>;\n\n private 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.eventBus = new RepoEventBus<Meta>();\n this.state = createRepoState();\n const configuredDebounce = options.docFrontierDebounceMs;\n const docFrontierDebounceMs =\n typeof configuredDebounce === \"number\" &&\n Number.isFinite(configuredDebounce) &&\n configuredDebounce >= 0\n ? configuredDebounce\n : DEFAULT_DOC_FRONTIER_DEBOUNCE_MS;\n this.docManager = new DocManager<Meta>({\n storage: this.storage,\n docFrontierDebounceMs,\n getMetaFlock: () => this.metaFlock,\n eventBus: this.eventBus,\n persistMeta: () => this.persistMeta(),\n state: this.state,\n });\n this.metadataManager = new MetadataManager<Meta>({\n getMetaFlock: () => this.metaFlock,\n eventBus: this.eventBus,\n persistMeta: () => this.persistMeta(),\n state: this.state,\n });\n this.assetManager = new AssetManager<Meta>({\n storage: this.storage,\n assetTransport: this.assetTransport,\n getMetaFlock: () => this.metaFlock,\n eventBus: this.eventBus,\n persistMeta: () => this.persistMeta(),\n state: this.state,\n });\n this.flockHydrator = new FlockHydrator<Meta>({\n getMetaFlock: () => this.metaFlock,\n metadataManager: this.metadataManager,\n assetManager: this.assetManager,\n docManager: this.docManager,\n });\n this.syncRunner = new SyncRunner<Meta>({\n storage: this.storage,\n transport: this.transport,\n eventBus: this.eventBus,\n docManager: this.docManager,\n metadataManager: this.metadataManager,\n assetManager: this.assetManager,\n flockHydrator: this.flockHydrator,\n getMetaFlock: () => this.metaFlock,\n mergeFlock: (snapshot) => {\n this.metaFlock.merge(snapshot)\n },\n persistMeta: () => this.persistMeta(),\n });\n }\n\n static async create<Meta extends JsonObject = JsonObject>(options: LoroRepoOptions<Meta>): Promise<LoroRepo<Meta>> {\n const repo = new LoroRepo<Meta>(options);\n await repo.storage?.init?.();\n // Transport may not be valid because the client may be offline, and it would hurt DX if we wait for transport layer \n // to initialize here.\n await repo.ready();\n return repo;\n }\n\n /**\n * Load meta from storage.\n * \n * You need to call this before all other operations to make the app functioning correctly.\n * Though we do that implicitly already\n */\n private async ready(): Promise<void> {\n await this.syncRunner.ready();\n }\n\n /**\n * Sync selected data via the transport adaptor\n * @param options \n */\n async sync(options: RepoSyncOptions = {}): Promise<void> {\n await this.syncRunner.sync(options);\n }\n\n /**\n * Start syncing the metadata (Flock) room. It will establish a realtime connection to the transport adaptor.\n * All changes on the room will be synced to the Flock, and all changes on the Flock will be synced to the room.\n * @param params \n * @returns \n */\n async joinMetaRoom(\n params?: TransportJoinParams,\n ): Promise<TransportSubscription> {\n return this.syncRunner.joinMetaRoom(params);\n }\n\n /**\n * Start syncing the given doc. It will establish a realtime connection to the transport adaptor.\n * All changes on the doc will be synced to the transport, and all changes on the transport will be synced to the doc.\n * \n * All the changes on the room will be reflected on the same doc you get from `repo.openCollaborativeDoc(docId)`\n * @param docId \n * @param params \n * @returns \n */\n async joinDocRoom(\n docId: string,\n params?: TransportJoinParams,\n ): Promise<TransportSubscription> {\n return this.syncRunner.joinDocRoom(docId, params);\n }\n\n /**\n * Opens a document that is automatically persisted to the configured storage adapter.\n * \n * - Edits are saved to storage (debounced).\n * - Frontiers are synced to the metadata (Flock).\n * - Realtime collaboration is NOT enabled by default; use `joinDocRoom` to connect.\n */\n async openPersistedDoc(docId: string): Promise<RepoDocHandle> {\n return {\n doc: await this.docManager.openCollaborativeDoc(docId),\n syncOnce: () => {\n return this.sync({ scope: \"doc\", docIds: [docId] });\n },\n joinRoom: (auth) => {\n return this.syncRunner.joinDocRoom(docId, { auth })\n }\n }\n }\n\n async upsertDocMeta(\n docId: string,\n patch: Partial<Meta>,\n ): Promise<void> {\n await this.metadataManager.upsert(docId, patch);\n }\n\n async getDocMeta(docId: string): Promise<Meta | undefined> {\n return this.metadataManager.get(docId);\n }\n\n async listDoc(query?: ListDocQuery): Promise<RepoDocMeta<Meta>[]> {\n return this.metadataManager.listDoc(query);\n }\n\n getMeta(): Flock {\n return this.metaFlock;\n }\n\n watch(\n listener: RepoEventListener<Meta>,\n filter: RepoEventFilter<Meta> = {},\n ): RepoWatchHandle {\n return this.eventBus.watch(listener, filter);\n }\n\n /**\n * Opens a detached `LoroDoc` snapshot.\n * \n * - **No Persistence**: Edits to this document are NOT saved to storage.\n * - **No Sync**: This document does not participate in realtime updates.\n * - **Use Case**: Ideal for read-only history inspection, temporary drafts, or conflict resolution without affecting the main state.\n */\n async openDetachedDoc(docId: string): Promise<LoroDoc> {\n return this.docManager.openDetachedDoc(docId);\n }\n\n /**\n * Explicitly unloads a document from memory.\n * \n * - **Persists Immediately**: Forces a save of the document's current state to storage.\n * - **Frees Memory**: Removes the document from the internal cache.\n * - **Note**: If the document is currently being synced (via `joinDocRoom`), you should also unsubscribe from the room to fully release resources.\n */\n async unloadDoc(docId: string): Promise<void> {\n await this.docManager.unloadDoc(docId);\n }\n\n async flush(): Promise<void> {\n await this.docManager.flush();\n }\n\n async uploadAsset(params: UploadAssetOptions): Promise<AssetId> {\n return this.assetManager.uploadAsset(params);\n }\n\n async linkAsset(docId: string, params: LinkAssetOptions): Promise<AssetId> {\n return this.assetManager.linkAsset(docId, params);\n }\n\n async fetchAsset(assetId: AssetId): Promise<AssetDownload> {\n return this.assetManager.fetchAsset(assetId);\n }\n\n async unlinkAsset(docId: string, assetId: AssetId): Promise<void> {\n await this.assetManager.unlinkAsset(docId, assetId);\n }\n\n async listAssets(docId: string): Promise<RepoAssetMetadata[]> {\n return this.assetManager.listAssets(docId);\n }\n\n async ensureAsset(assetId: AssetId): Promise<AssetDownload> {\n return this.assetManager.ensureAsset(assetId);\n }\n\n async gcAssets(options: GarbageCollectionOptions = {}): Promise<number> {\n return this.assetManager.gcAssets(options);\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 get destroyed(): boolean {\n return this._destroyed;\n }\n\n async destroy(): Promise<void> {\n if (this._destroyed) return;\n this._destroyed = true;\n await this.syncRunner.destroy();\n this.assetTransport?.close?.();\n this.storage?.close?.();\n await this.transport?.close();\n }\n}\n\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["FlockAdaptor","subscription: TransportSubscription","LoroWebsocketClient","CrdtType","session: MetadataSession","LoroAdaptor","session: DocSession","resolve!: () => void","listener: MetaListener","listener: DocListener","state: DocChannelState","textDecoder","doc: LoroDoc","LoroDoc","consolidated: Uint8Array","Flock","queue: Uint8Array[]","path","LoroDoc","Flock","fs","entry: WatchEntry<Meta>","chunks: Uint8Array[]","arr: JsonValue[]","obj: JsonObject","patch: JsonObject","json: JsonObject","LoroDoc","oldFrontiers: Frontiers","promises: Promise<void>[]","by: RepoEventBy","scanOptions: ScanOptions","entries: RepoDocMeta<Meta>[]","next: JsonObject","outPatch: JsonObject","canonical: JsonValue | undefined","docMeta: JsonObject","metadata","metadata: RepoAssetMetadata","storedBytes: Uint8Array | undefined","removed: AssetId[]","removedAssets: Array<[AssetId, AssetRecord]>","recordedEvents: FlockEvent[]","wrapped: TransportSubscription","Flock"],"sources":["../src/loro-adaptor.ts","../src/internal/debug.ts","../src/transport/websocket.ts","../src/transport/broadcast-channel.ts","../src/storage/indexeddb.ts","../src/storage/filesystem.ts","../src/internal/event-bus.ts","../src/utils.ts","../src/internal/logging.ts","../src/internal/doc-manager.ts","../src/internal/metadata-manager.ts","../src/internal/asset-manager.ts","../src/internal/flock-hydrator.ts","../src/internal/sync-runner.ts","../src/internal/repo-state.ts","../src/index.ts"],"sourcesContent":["import { Flock } from \"@loro-dev/flock\";\nimport { LoroDoc } from \"loro-crdt\";\nimport {\n FlockAdaptor,\n type FlockAdaptorConfig,\n} from \"loro-adaptors/flock\";\nimport {\n LoroAdaptor,\n type LoroAdaptorConfig,\n} from \"loro-adaptors/loro\"\n\nexport type RepoLoroAdaptorConfig = LoroAdaptorConfig;\nexport type RepoFlockAdaptorConfig = FlockAdaptorConfig;\n\nexport { LoroAdaptor as RepoLoroAdaptor } from \"loro-adaptors/loro\";\nexport { FlockAdaptor as RepoFlockAdaptor } from \"loro-adaptors/flock\";\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","type EnvRecord = Record<string, string | undefined>;\n\nconst getEnv = (): EnvRecord | undefined => {\n if (typeof globalThis !== \"object\" || globalThis === null) {\n return undefined;\n }\n const processLike = (globalThis as { process?: { env?: EnvRecord } }).process;\n return processLike?.env;\n};\n\nconst rawNamespaceConfig = (getEnv()?.LORO_REPO_DEBUG ?? \"\").trim();\n\nconst normalizedNamespaces =\n rawNamespaceConfig.length > 0\n ? rawNamespaceConfig\n .split(/[\\s,]+/)\n .map((token) => token.toLowerCase())\n .filter(Boolean)\n : [];\n\nconst wildcardTokens = new Set([\"*\", \"1\", \"true\", \"all\"]);\nconst namespaceSet = new Set(normalizedNamespaces);\nconst hasWildcard =\n namespaceSet.size > 0 &&\n normalizedNamespaces.some((token) => wildcardTokens.has(token));\n\nexport const isDebugEnabled = (namespace?: string): boolean => {\n if (!namespaceSet.size) {\n return false;\n }\n if (!namespace) {\n return hasWildcard;\n }\n const normalized = namespace.toLowerCase();\n if (hasWildcard) {\n return true;\n }\n if (namespaceSet.has(normalized)) {\n return true;\n }\n const [root] = normalized.split(\":\");\n return namespaceSet.has(root);\n};\n\nexport type DebugLogger = (...args: unknown[]) => void;\n\nexport const createDebugLogger = (namespace: string): DebugLogger => {\n const normalized = namespace.toLowerCase();\n return (...args: unknown[]) => {\n if (!isDebugEnabled(normalized)) {\n return;\n }\n const prefix = `[loro-repo:${namespace}]`;\n if (args.length === 0) {\n console.info(prefix);\n return;\n }\n console.info(prefix, ...args);\n };\n};\n","import { Flock } from \"@loro-dev/flock\";\nimport { LoroDoc } from \"loro-crdt\";\nimport { type CrdtDocAdaptor } from \"loro-adaptors\"\nimport { LoroAdaptor } from \"loro-adaptors/loro\";\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\";\nimport { createDebugLogger } from \"../internal/debug\";\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\nconst debug = createDebugLogger(\"transport:websocket\");\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 debug(\"connect requested\", { status: client.getStatus() });\n try {\n await client.connect();\n debug(\"client.connect resolved\");\n await client.waitConnected();\n debug(\"client.waitConnected resolved\", { status: client.getStatus() });\n } catch (error) {\n debug(\"connect failed\", error);\n throw error;\n }\n }\n\n async close(): Promise<void> {\n debug(\"close requested\", {\n docSessions: this.docSessions.size,\n metadataSession: Boolean(this.metadataSession),\n });\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 const client = this.client;\n this.client = undefined;\n client.destroy();\n debug(\"websocket client destroyed\");\n }\n debug(\"close completed\");\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 debug(\"syncMeta skipped; metadata room not configured\");\n return { ok: true };\n }\n debug(\"syncMeta requested\", { roomId: this.options.metadataRoomId });\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 debug(\"syncMeta completed\", { roomId: this.options.metadataRoomId });\n return { ok: true };\n } catch (error) {\n debug(\"syncMeta failed\", error);\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 debug(\"joinMetaRoom requested\", {\n roomId,\n hasAuth: Boolean(auth && auth.length),\n });\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 debug(\"metadata session refCount decremented\", {\n roomId: session.roomId,\n refCount: session.refCount,\n });\n if (session.refCount === 0) {\n debug(\"tearing down metadata session due to refCount=0\", {\n roomId: session.roomId,\n });\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 debug(\"metadata session refCount incremented\", {\n roomId: session.roomId,\n refCount: session.refCount,\n });\n });\n return subscription;\n }\n\n async syncDoc(\n docId: string,\n doc: LoroDoc,\n options?: { timeout?: number },\n ): Promise<TransportSyncResult> {\n debug(\"syncDoc requested\", { docId });\n try {\n const session = await this.ensureDocSession(docId, doc, {});\n await withTimeout(session.firstSynced, options?.timeout);\n debug(\"syncDoc completed\", { docId, roomId: session.roomId });\n return { ok: true };\n } catch (error) {\n debug(\"syncDoc failed\", { docId, error });\n return { ok: false };\n }\n }\n\n joinDocRoom(\n docId: string,\n doc: LoroDoc,\n params?: TransportJoinParams,\n ): TransportSubscription {\n debug(\"joinDocRoom requested\", {\n docId,\n roomParamType: params?.roomId\n ? typeof params.roomId === \"string\"\n ? \"string\"\n : \"uint8array\"\n : undefined,\n hasAuthOverride: Boolean(params?.auth && params.auth.length),\n });\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 debug(\"doc session refCount decremented\", {\n docId,\n roomId: session.roomId,\n refCount: session.refCount,\n });\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 debug(\"doc session refCount incremented\", {\n docId,\n roomId: session.roomId,\n refCount: session.refCount,\n });\n });\n return subscription;\n }\n\n private ensureClient(): LoroWebsocketClient {\n if (this.client) {\n debug(\"reusing websocket client\", { status: this.client.getStatus() });\n return this.client;\n }\n const { url, client: clientOptions } = this.options;\n debug(\"creating websocket client\", {\n url,\n clientOptionsKeys: clientOptions ? Object.keys(clientOptions) : [],\n });\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 debug(\"ensureMetadataSession invoked\", {\n roomId: params.roomId,\n hasAuth: Boolean(params.auth && params.auth.length),\n });\n const client = this.ensureClient();\n await client.waitConnected();\n debug(\"websocket client ready for metadata session\", {\n status: client.getStatus(),\n });\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 debug(\"reusing metadata session\", {\n roomId: this.metadataSession.roomId,\n refCount: this.metadataSession.refCount,\n });\n return this.metadataSession;\n }\n\n if (this.metadataSession) {\n debug(\"tearing down previous metadata session\", {\n roomId: this.metadataSession.roomId,\n });\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 debug(\"joining metadata room\", {\n roomId: params.roomId,\n hasAuth: Boolean(params.auth && params.auth.length),\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 firstSynced.then(\n () => {\n debug(\"metadata session firstSynced resolved\", {\n roomId: params.roomId,\n });\n },\n (error) => {\n debug(\"metadata session firstSynced rejected\", {\n roomId: params.roomId,\n error,\n });\n },\n );\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 debug(\"teardownMetadataSession invoked\", { roomId: target.roomId });\n if (this.metadataSession === target) {\n this.metadataSession = undefined;\n }\n const { adaptor, room } = target;\n try {\n await room.leave();\n debug(\"metadata room left\", { roomId: target.roomId });\n } catch (error) {\n debug(\"metadata room leave failed; destroying\", {\n roomId: target.roomId,\n error,\n });\n await room.destroy().catch(() => { });\n }\n adaptor.destroy();\n debug(\"metadata session destroyed\", { roomId: target.roomId });\n }\n\n private async ensureDocSession(\n docId: string,\n doc: LoroDoc,\n params: TransportJoinParams,\n ): Promise<DocSession> {\n debug(\"ensureDocSession invoked\", { docId });\n const client = this.ensureClient();\n await client.waitConnected();\n debug(\"websocket client ready for doc session\", {\n docId,\n status: client.getStatus(),\n });\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 debug(\"doc session params resolved\", {\n docId,\n roomId,\n hasAuth: Boolean(auth && auth.length),\n });\n\n if (existing && existing.doc === doc && existing.roomId === roomId) {\n debug(\"reusing doc session\", {\n docId,\n roomId,\n refCount: existing.refCount,\n });\n return existing;\n }\n\n if (existing) {\n debug(\"doc session mismatch; leaving existing session\", {\n docId,\n previousRoomId: existing.roomId,\n nextRoomId: roomId,\n });\n await this.leaveDocSession(docId).catch(() => { });\n }\n\n const adaptor = new LoroAdaptor(doc);\n debug(\"joining doc room\", {\n docId,\n roomId,\n hasAuth: Boolean(auth && auth.length),\n });\n const room = await client.join({\n roomId,\n crdtAdaptor: adaptor,\n auth,\n });\n const firstSynced = room.waitForReachingServerVersion();\n firstSynced.then(\n () => {\n debug(\"doc session firstSynced resolved\", { docId, roomId });\n },\n (error) => {\n debug(\"doc session firstSynced rejected\", { docId, roomId, error });\n },\n );\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) {\n debug(\"leaveDocSession invoked but no session found\", { docId });\n return;\n }\n this.docSessions.delete(docId);\n debug(\"leaving doc session\", { docId, roomId: session.roomId });\n try {\n await session.room.leave();\n debug(\"doc room left\", { docId, roomId: session.roomId });\n } catch (error) {\n debug(\"doc room leave failed; destroying\", {\n docId,\n roomId: session.roomId,\n error,\n });\n await session.room.destroy().catch(() => { });\n }\n session.adaptor.destroy();\n debug(\"doc session destroyed\", { docId, roomId: session.roomId });\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 { promises as fs } from \"node:fs\";\nimport * as path from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\n\nimport { Flock, type ExportBundle } from \"@loro-dev/flock\";\nimport { LoroDoc } from \"loro-crdt\";\n\nimport type { AssetId, StorageAdapter, StorageSavePayload } from \"../types\";\n\nconst textDecoder = new TextDecoder();\n\nexport interface FileSystemStorageAdaptorOptions {\n /**\n * Base directory where metadata, document snapshots, and assets will be stored.\n * Defaults to `.loro-repo` inside the current working directory.\n */\n readonly baseDir?: string;\n /**\n * Subdirectory dedicated to document persistence. Defaults to `docs`.\n */\n readonly docsDirName?: string;\n /**\n * Subdirectory dedicated to asset blobs. Defaults to `assets`.\n */\n readonly assetsDirName?: string;\n /**\n * File name for the metadata snapshot bundle. Defaults to `meta.json`.\n */\n readonly metaFileName?: string;\n}\n\nexport class FileSystemStorageAdaptor implements StorageAdapter {\n private readonly baseDir: string;\n private readonly docsDir: string;\n private readonly assetsDir: string;\n private readonly metaPath: string;\n private readonly initPromise: Promise<void>;\n private updateCounter = 0;\n\n constructor(options: FileSystemStorageAdaptorOptions = {}) {\n this.baseDir = path.resolve(\n options.baseDir ?? path.join(process.cwd(), \".loro-repo\"),\n );\n this.docsDir = path.join(this.baseDir, options.docsDirName ?? \"docs\");\n this.assetsDir = path.join(this.baseDir, options.assetsDirName ?? \"assets\");\n this.metaPath = path.join(this.baseDir, options.metaFileName ?? \"meta.json\");\n this.initPromise = this.ensureLayout();\n }\n\n async save(payload: StorageSavePayload): Promise<void> {\n await this.initPromise;\n switch (payload.type) {\n case \"doc-snapshot\":\n await this.writeDocSnapshot(payload.docId, payload.snapshot);\n return;\n case \"doc-update\":\n await this.enqueueDocUpdate(payload.docId, payload.update);\n return;\n case \"asset\":\n await this.writeAsset(payload.assetId, payload.data);\n return;\n case \"meta\":\n await writeFileAtomic(this.metaPath, payload.update);\n return;\n default:\n throw new Error(`Unsupported payload type: ${(payload as { type: string }).type}`);\n }\n }\n\n async deleteAsset(assetId: AssetId): Promise<void> {\n await this.initPromise;\n const filePath = this.assetPath(assetId);\n await removeIfExists(filePath);\n }\n\n async loadDoc(docId: string): Promise<LoroDoc | undefined> {\n await this.initPromise;\n const snapshotPath = this.docSnapshotPath(docId);\n const snapshotBytes = await readFileIfExists(snapshotPath);\n const updateDir = this.docUpdatesDir(docId);\n const updateFiles = await listFiles(updateDir);\n\n if (!snapshotBytes && updateFiles.length === 0) {\n return undefined;\n }\n\n const doc = snapshotBytes\n ? LoroDoc.fromSnapshot(snapshotBytes)\n : new LoroDoc();\n\n if (updateFiles.length === 0) {\n return doc;\n }\n\n const updatePaths = updateFiles.map((file) => path.join(updateDir, file));\n for (const updatePath of updatePaths) {\n const update = await readFileIfExists(updatePath);\n if (!update) continue;\n doc.import(update);\n }\n\n await Promise.all(updatePaths.map((filePath) => removeIfExists(filePath)));\n\n const consolidated = doc.export({ mode: \"snapshot\" });\n await this.writeDocSnapshot(docId, consolidated);\n return doc;\n }\n\n async loadMeta(): Promise<Flock | undefined> {\n await this.initPromise;\n const bytes = await readFileIfExists(this.metaPath);\n if (!bytes) return undefined;\n try {\n const bundle = JSON.parse(textDecoder.decode(bytes)) as ExportBundle;\n const flock = new Flock();\n flock.importJson(bundle);\n return flock;\n } catch (error) {\n throw new Error(\"Failed to hydrate metadata snapshot\", { cause: error });\n }\n }\n\n async loadAsset(assetId: AssetId): Promise<Uint8Array | undefined> {\n await this.initPromise;\n return readFileIfExists(this.assetPath(assetId));\n }\n\n private async ensureLayout(): Promise<void> {\n await Promise.all([\n ensureDir(this.baseDir),\n ensureDir(this.docsDir),\n ensureDir(this.assetsDir),\n ]);\n }\n\n private async writeDocSnapshot(\n docId: string,\n snapshot: Uint8Array,\n ): Promise<void> {\n const targetDir = this.docDir(docId);\n await ensureDir(targetDir);\n await writeFileAtomic(this.docSnapshotPath(docId), snapshot);\n }\n\n private async enqueueDocUpdate(\n docId: string,\n update: Uint8Array,\n ): Promise<void> {\n const dir = this.docUpdatesDir(docId);\n await ensureDir(dir);\n const counter = (this.updateCounter = (this.updateCounter + 1) % 1_000_000);\n const timestamp = Date.now().toString().padStart(13, \"0\");\n const fileName = `${timestamp}-${counter.toString().padStart(6, \"0\")}.bin`;\n const filePath = path.join(dir, fileName);\n await writeFileAtomic(filePath, update);\n }\n\n private async writeAsset(assetId: AssetId, data: Uint8Array): Promise<void> {\n const filePath = this.assetPath(assetId);\n await ensureDir(path.dirname(filePath));\n await writeFileAtomic(filePath, data);\n }\n\n private docDir(docId: string): string {\n return path.join(this.docsDir, encodeComponent(docId));\n }\n\n private docSnapshotPath(docId: string): string {\n return path.join(this.docDir(docId), \"snapshot.bin\");\n }\n\n private docUpdatesDir(docId: string): string {\n return path.join(this.docDir(docId), \"updates\");\n }\n\n private assetPath(assetId: AssetId): string {\n return path.join(this.assetsDir, encodeComponent(assetId));\n }\n}\n\nfunction encodeComponent(value: string): string {\n return Buffer.from(value, \"utf8\").toString(\"base64url\");\n}\n\nasync function ensureDir(dir: string): Promise<void> {\n await fs.mkdir(dir, { recursive: true });\n}\n\nasync function readFileIfExists(filePath: string): Promise<Uint8Array | undefined> {\n try {\n const data = await fs.readFile(filePath);\n return new Uint8Array(data.buffer, data.byteOffset, data.byteLength).slice();\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return undefined;\n }\n throw error;\n }\n}\n\nasync function removeIfExists(filePath: string): Promise<void> {\n try {\n await fs.rm(filePath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return;\n }\n throw error;\n }\n}\n\nasync function listFiles(dir: string): Promise<string[]> {\n try {\n const entries = await fs.readdir(dir);\n return entries.sort();\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return [];\n }\n throw error;\n }\n}\n\nasync function writeFileAtomic(\n targetPath: string,\n data: Uint8Array,\n): Promise<void> {\n const dir = path.dirname(targetPath);\n await ensureDir(dir);\n const tempPath = path.join(dir, `.tmp-${randomUUID()}`);\n await fs.writeFile(tempPath, data);\n await fs.rename(tempPath, targetPath);\n}\n","import type {\n JsonObject,\n RepoEvent,\n RepoEventBy,\n RepoEventFilter,\n RepoEventListener,\n RepoWatchHandle,\n} from \"../types\";\n\ntype WatchEntry<Meta extends JsonObject> = {\n listener: RepoEventListener<Meta>;\n filter: RepoEventFilter<Meta>;\n};\n\nexport class RepoEventBus<Meta extends JsonObject> {\n private readonly watchers = new Set<WatchEntry<Meta>>();\n private readonly eventByStack: RepoEventBy[] = [];\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 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\n clear(): void {\n this.watchers.clear();\n this.eventByStack.length = 0;\n }\n\n pushEventBy(by: RepoEventBy): void {\n this.eventByStack.push(by);\n }\n\n popEventBy(): void {\n this.eventByStack.pop();\n }\n\n resolveEventBy(defaultBy: RepoEventBy): RepoEventBy {\n const index = this.eventByStack.length - 1;\n return index >= 0 ? this.eventByStack[index] : defaultBy;\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 }\n if (event.kind === \"asset-link\" || event.kind === \"asset-unlink\") {\n return event.docId;\n }\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\n return true;\n }\n}\n","import { Frontiers, LoroDoc, VersionVector } from \"loro-crdt\";\n\nimport type {\n AssetContent,\n JsonObject,\n JsonValue,\n ListDocQuery,\n RepoAssetMetadata,\n} from \"./types\";\n\ntype PossibleCrypto = {\n subtle?: {\n digest: (\n algorithm: string,\n data: ArrayBufferView | ArrayBuffer,\n ) => Promise<ArrayBuffer>;\n };\n};\n\nexport async 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\nexport async 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\nexport function bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes, (byte) => byte.toString(16).padStart(2, \"0\")).join(\n \"\",\n );\n}\n\nexport async 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 function 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\nexport function 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\nexport function 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 Boolean(value && typeof value === \"object\" && !Array.isArray(value));\n}\n\nexport function stableStringify(value: JsonValue): string {\n if (value === null) return \"null\";\n if (typeof value === \"string\") return JSON.stringify(value);\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return JSON.stringify(value);\n }\n if (Array.isArray(value)) {\n return `[${value.map(stableStringify).join(\",\")}]`;\n }\n if (!isJsonObjectValue(value)) {\n return \"null\";\n }\n const entries = Object.keys(value)\n .sort()\n .map((key) => `${JSON.stringify(key)}:${stableStringify(value[key])}`);\n return `{${entries.join(\",\")}}`;\n}\n\nexport function jsonEquals(a?: JsonValue, b?: JsonValue): 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\nexport function diffJsonObjects(\n previous: JsonObject | undefined,\n next: JsonObject,\n): JsonObject {\n const patch: JsonObject = {};\n const keys = new Set<string>();\n if (previous) {\n for (const key of Object.keys(previous)) keys.add(key);\n }\n for (const key of Object.keys(next)) keys.add(key);\n for (const key of keys) {\n const prevValue = previous ? previous[key] : undefined;\n const nextValue = next[key];\n if (!jsonEquals(prevValue, nextValue)) {\n if (nextValue === undefined && previous && key in previous) {\n patch[key] = null;\n continue;\n }\n const cloned = cloneJsonValue(nextValue);\n if (cloned !== undefined) {\n patch[key] = cloned;\n }\n }\n }\n return patch;\n}\n\nexport function 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\nexport function assetMetaFromJson(\n value: unknown,\n): 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\nexport function 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\nexport function cloneRepoAssetMetadata(\n meta: RepoAssetMetadata,\n): 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\nexport function toReadableStream(\n bytes: Uint8Array,\n): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controller.enqueue(bytes);\n controller.close();\n },\n });\n}\n\nexport function 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\nexport function emptyFrontiers(): Frontiers {\n return [];\n}\n\nexport function 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\nexport function canonicalizeVersionVector(vv: VersionVector): {\n json: JsonObject;\n key: string;\n} {\n const json = versionVectorToJson(vv);\n return { json, key: stableStringify(json) };\n}\n\nexport function canonicalizeFrontiers(frontiers: Frontiers): {\n json: JsonValue;\n key: string;\n} {\n const sorted = [...frontiers].sort((a, b) => {\n if (a.peer < b.peer) return -1;\n if (a.peer > b.peer) return 1;\n return a.counter - b.counter;\n });\n const json = sorted.map((f) => ({ peer: f.peer, counter: f.counter }));\n return { json, key: stableStringify(json) };\n}\n\nexport function includesFrontiers(\n vv: VersionVector,\n frontiers: Frontiers,\n): boolean {\n for (const { peer, counter } of frontiers) {\n const local = vv.get(peer) ?? 0;\n // Version Vector stores the *next* expected op counter (exclusive).\n // Frontiers store the *last* applied op counter (inclusive).\n // If local <= counter, it means the Version Vector has not yet reached (included) the Frontier op.\n if (local <= counter) return false;\n }\n return true;\n}\n\nexport function 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","export function 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","import { Flock } from \"@loro-dev/flock\";\nimport { LoroDoc, type LoroEventBatch, type VersionVector, type Frontiers } from \"loro-crdt\";\n\nimport type {\n JsonObject,\n RepoEventBy,\n StorageAdapter,\n} from \"../types\";\nimport { RepoEventBus } from \"./event-bus\";\nimport { canonicalizeFrontiers, includesFrontiers } from \"../utils\";\nimport { logAsyncError } from \"./logging\";\nimport type { RepoState } from \"./repo-state\";\n\ntype PendingDocFrontierUpdate = {\n timeout: ReturnType<typeof setTimeout>;\n doc: LoroDoc;\n by: RepoEventBy;\n};\n\ninterface DocManagerOptions<Meta extends JsonObject> {\n readonly storage?: StorageAdapter;\n readonly docFrontierDebounceMs: number;\n readonly getMetaFlock: () => Flock;\n readonly eventBus: RepoEventBus<Meta>;\n readonly persistMeta: () => Promise<void>;\n readonly state: RepoState;\n}\n\nexport class DocManager<Meta extends JsonObject> {\n private readonly storage?: StorageAdapter;\n private readonly docFrontierDebounceMs: number;\n private readonly getMetaFlock: () => Flock;\n private readonly eventBus: RepoEventBus<Meta>;\n private readonly persistMeta: () => Promise<void>;\n private readonly state: RepoState;\n\n private readonly docs = new Map<string, LoroDoc>();\n private readonly docSubscriptions = new Map<string, () => void>();\n private readonly docFrontierUpdates = new Map<\n string,\n PendingDocFrontierUpdate\n >();\n private readonly docPersistedVersions = new Map<string, VersionVector>();\n\n private get docFrontierKeys(): Map<string, Set<string>> {\n return this.state.docFrontierKeys;\n }\n constructor(options: DocManagerOptions<Meta>) {\n this.storage = options.storage;\n this.docFrontierDebounceMs = options.docFrontierDebounceMs;\n this.getMetaFlock = options.getMetaFlock;\n this.eventBus = options.eventBus;\n this.persistMeta = options.persistMeta;\n this.state = options.state;\n }\n\n async openCollaborativeDoc(\n docId: string,\n ): Promise<LoroDoc> {\n const doc = await this.ensureDoc(docId);\n return doc;\n }\n\n async openDetachedDoc(docId: string): Promise<LoroDoc> {\n const doc = await this.materializeDetachedDoc(docId);\n return doc\n }\n\n async ensureDoc(docId: string): Promise<LoroDoc> {\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(docId, cached.version());\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 = new LoroDoc();\n this.registerDoc(docId, created);\n return created;\n }\n\n async persistDoc(docId: string, doc: LoroDoc): Promise<void> {\n const previousVersion = this.docPersistedVersions.get(docId);\n const snapshot = doc.export({ mode: \"snapshot\" });\n const nextVersion = doc.version();\n if (!this.storage) {\n this.docPersistedVersions.set(docId, nextVersion);\n return;\n }\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 async updateDocFrontiers(\n docId: string,\n doc: LoroDoc,\n defaultBy: RepoEventBy,\n ): Promise<void> {\n const frontiers = doc.oplogFrontiers();\n const { json, key } = canonicalizeFrontiers(frontiers);\n const existingKeys = this.docFrontierKeys.get(docId) ?? new Set<string>();\n let mutated = false;\n\n const metaFlock = this.metaFlock;\n const vv = doc.version();\n\n for (const entry of existingKeys) {\n if (entry === key) continue;\n let oldFrontiers: Frontiers;\n try {\n oldFrontiers = JSON.parse(entry);\n } catch {\n continue;\n }\n\n if (includesFrontiers(vv, oldFrontiers)) {\n metaFlock.delete([\"f\", docId, entry]);\n mutated = true;\n }\n }\n\n if (!existingKeys.has(key)) {\n metaFlock.put([\"f\", docId, key], json);\n mutated = true;\n }\n\n if (mutated) {\n this.refreshDocFrontierKeys(docId);\n await this.persistMeta();\n }\n\n const by = this.eventBus.resolveEventBy(defaultBy);\n this.eventBus.emit({ kind: \"doc-frontiers\", docId, frontiers, by });\n }\n\n async flushScheduledDocFrontierUpdate(docId: string): 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.eventBus.pushEventBy(pending.by);\n try {\n await this.updateDocFrontiers(docId, pending.doc, pending.by);\n } finally {\n this.eventBus.popEventBy();\n }\n return true;\n }\n\n async unloadDoc(docId: string): Promise<void> {\n const doc = this.docs.get(docId);\n if (!doc) return;\n\n // 1. Flush any pending frontier updates\n await this.flushScheduledDocFrontierUpdate(docId);\n\n // 2. Persist the final state\n await this.persistDocUpdate(docId, doc);\n\n // 3. Update frontiers one last time if needed (local changes)\n // We assume \"local\" because we are unloading it from the local repo\n await this.updateDocFrontiers(docId, doc, \"local\");\n\n // 4. Cleanup subscriptions and map entries\n const unsubscribe = this.docSubscriptions.get(docId);\n unsubscribe?.();\n this.docSubscriptions.delete(docId);\n this.docs.delete(docId);\n this.docPersistedVersions.delete(docId);\n // We don't clear docFrontierKeys here because they are part of the metadata (Flock)\n // and should persist even if the doc is unloaded from memory.\n }\n\n async flush(): Promise<void> {\n const promises: Promise<void>[] = [];\n for (const [docId, doc] of this.docs) {\n promises.push(\n (async () => {\n await this.persistDocUpdate(docId, doc);\n await this.flushScheduledDocFrontierUpdate(docId);\n })()\n );\n }\n await Promise.all(promises);\n }\n\n async close(): Promise<void> {\n // Flush everything before closing\n await this.flush();\n\n for (const unsubscribe of this.docSubscriptions.values()) {\n try {\n unsubscribe();\n } catch {\n // ignore subscriber errors during shutdown\n }\n }\n this.docSubscriptions.clear();\n this.docFrontierUpdates.clear();\n this.docs.clear();\n this.docPersistedVersions.clear();\n this.docFrontierKeys.clear();\n }\n\n hydrateFrontierKeys(): void {\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 }\n const set = nextFrontierKeys.get(docId) ?? new Set<string>();\n set.add(frontierKey);\n nextFrontierKeys.set(docId, set);\n }\n this.docFrontierKeys.clear();\n for (const [docId, keys] of nextFrontierKeys) {\n this.docFrontierKeys.set(docId, keys);\n }\n }\n\n 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 if (row.value === undefined || row.value === null) 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 get metaFlock(): Flock {\n return this.getMetaFlock();\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.eventBus.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 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.eventBus.pushEventBy(pending.by);\n void (async () => {\n try {\n await this.updateDocFrontiers(docId, pending.doc, pending.by);\n } finally {\n this.eventBus.popEventBy();\n }\n })().catch(logAsyncError(`doc ${docId} frontier debounce`));\n }\n\n\n\n private async materializeDetachedDoc(docId: string): Promise<LoroDoc> {\n const snapshot = await this.exportDocSnapshot(docId);\n if (snapshot) {\n return LoroDoc.fromSnapshot(snapshot);\n }\n return new LoroDoc()\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 persistDocUpdate(docId: string, doc: LoroDoc): Promise<void> {\n const previousVersion = this.docPersistedVersions.get(docId);\n const nextVersion = doc.oplogVersion();\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 if (previousVersion.compare(nextVersion) === 0) {\n return;\n }\n\n const update = doc.export({ mode: \"update\", from: previousVersion });\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 onDocEvent(\n docId: string,\n doc: LoroDoc,\n _batch: LoroEventBatch,\n by: RepoEventBy,\n ): void {\n void (async () => {\n const persist = this.persistDocUpdate(docId, doc);\n if (by === \"local\") {\n this.scheduleDocFrontierUpdate(docId, doc, by);\n await persist;\n return;\n }\n\n const flushed = this.flushScheduledDocFrontierUpdate(docId);\n const updated = (async () => {\n this.eventBus.pushEventBy(by);\n try {\n await this.updateDocFrontiers(docId, doc, by);\n } finally {\n this.eventBus.popEventBy();\n }\n })();\n await Promise.all([persist, flushed, updated]);\n })().catch(logAsyncError(`doc ${docId} event processing`));\n }\n}\n","import { Flock } from \"@loro-dev/flock\";\nimport type { ScanOptions } from \"@loro-dev/flock\";\n\nimport type {\n JsonObject,\n JsonValue,\n ListDocQuery,\n RepoDocMeta,\n RepoEventBy,\n} from \"../types\";\nimport {\n asJsonObject,\n cloneJsonObject,\n cloneJsonValue,\n diffJsonObjects,\n jsonEquals,\n matchesQuery,\n} from \"../utils\";\nimport { RepoEventBus } from \"./event-bus\";\nimport type { RepoState } from \"./repo-state\";\n\ninterface MetadataManagerOptions<Meta extends JsonObject> {\n readonly getMetaFlock: () => Flock;\n readonly eventBus: RepoEventBus<Meta>;\n readonly persistMeta: () => Promise<void>;\n readonly state: RepoState;\n}\n\nexport class MetadataManager<Meta extends JsonObject> {\n private readonly getMetaFlock: () => Flock;\n private readonly eventBus: RepoEventBus<Meta>;\n private readonly persistMeta: () => Promise<void>;\n private readonly state: RepoState;\n\n constructor(options: MetadataManagerOptions<Meta>) {\n this.getMetaFlock = options.getMetaFlock;\n this.eventBus = options.eventBus;\n this.persistMeta = options.persistMeta;\n this.state = options.state;\n }\n\n getDocIds(): string[] {\n return Array.from(this.state.metadata.keys());\n }\n\n entries(): IterableIterator<[string, JsonObject]> {\n return this.state.metadata.entries();\n }\n\n get(docId: string): Meta | undefined {\n const metadata = this.state.metadata.get(docId);\n return metadata ? (cloneJsonObject(metadata) as Meta) : undefined;\n }\n\n listDoc(query?: ListDocQuery): RepoDocMeta<Meta>[] {\n if (query?.limit !== undefined && query.limit <= 0) {\n return [];\n }\n\n const { startKey, endKey } = this.computeDocRangeKeys(query);\n if (startKey && endKey && startKey >= endKey) {\n return [];\n }\n\n const scanOptions: ScanOptions = { prefix: [\"m\"] };\n if (startKey) {\n scanOptions.start = { kind: \"inclusive\", key: [\"m\", startKey] };\n }\n if (endKey) {\n scanOptions.end = { kind: \"exclusive\", key: [\"m\", endKey] };\n }\n\n const rows = this.metaFlock.scan(scanOptions);\n const seen = new Set<string>();\n const entries: RepoDocMeta<Meta>[] = [];\n\n for (const row of rows) {\n if (query?.limit !== undefined && entries.length >= query.limit) {\n break;\n }\n if (!Array.isArray(row.key) || row.key.length < 2) continue;\n const docId = row.key[1];\n if (typeof docId !== \"string\") continue;\n if (seen.has(docId)) continue;\n seen.add(docId);\n\n const metadata = this.state.metadata.get(docId);\n if (!metadata) continue;\n if (!matchesQuery(docId, metadata, query)) continue;\n\n entries.push({ docId, meta: cloneJsonObject(metadata) as Meta });\n if (query?.limit !== undefined && entries.length >= query.limit) {\n break;\n }\n }\n\n return entries;\n }\n\n async upsert(docId: string, patch: Partial<Meta>): Promise<void> {\n const base = this.state.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.state.metadata.has(docId)) {\n this.state.metadata.set(docId, next);\n }\n return;\n }\n\n this.state.metadata.set(docId, next);\n await this.persistMeta();\n this.eventBus.emit({\n kind: \"doc-metadata\",\n docId,\n patch: cloneJsonObject(outPatch) as Partial<Meta>,\n by: \"local\",\n });\n }\n\n refreshFromFlock(docId: string, by: RepoEventBy): void {\n const previous = this.state.metadata.get(docId);\n const next = this.readDocMetadataFromFlock(docId);\n\n if (!next) {\n if (previous) {\n this.state.metadata.delete(docId);\n this.eventBus.emit({\n kind: \"doc-metadata\",\n docId,\n patch: {} as Partial<Meta>,\n by,\n });\n }\n return;\n }\n\n this.state.metadata.set(docId, next);\n const patch = diffJsonObjects(previous, next);\n if (!previous || Object.keys(patch).length > 0) {\n this.eventBus.emit({\n kind: \"doc-metadata\",\n docId,\n patch: patch as Partial<Meta>,\n by,\n });\n }\n }\n\n replaceAll(nextMetadata: Map<string, JsonObject>, by: RepoEventBy): void {\n const prevMetadata = new Map(this.state.metadata);\n this.state.metadata.clear();\n for (const [docId, meta] of nextMetadata) {\n this.state.metadata.set(docId, meta);\n }\n\n const docIds = new Set<string>([\n ...prevMetadata.keys(),\n ...nextMetadata.keys(),\n ]);\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.eventBus.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 (!previous || Object.keys(patch).length > 0) {\n this.eventBus.emit({\n kind: \"doc-metadata\",\n docId,\n patch: patch as Partial<Meta>,\n by,\n });\n }\n }\n }\n\n clear(): void {\n this.state.metadata.clear();\n }\n\n private computeDocRangeKeys(\n query?: ListDocQuery,\n ): { startKey?: string; endKey?: string } {\n if (!query) {\n return {};\n }\n\n const prefix = query.prefix && query.prefix.length > 0 ? query.prefix : undefined;\n let startKey = query.start;\n if (prefix) {\n startKey = !startKey || prefix > startKey ? prefix : startKey;\n }\n\n let endKey = query.end;\n const prefixEnd = this.nextLexicographicString(prefix);\n if (prefixEnd) {\n endKey = !endKey || prefixEnd < endKey ? prefixEnd : endKey;\n }\n\n return { startKey, endKey };\n }\n\n private nextLexicographicString(value?: string): string | undefined {\n if (!value) return undefined;\n for (let i = value.length - 1; i >= 0; i -= 1) {\n const code = value.charCodeAt(i);\n if (code < 0xffff) {\n return `${value.slice(0, i)}${String.fromCharCode(code + 1)}`;\n }\n }\n return undefined;\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 get metaFlock(): Flock {\n return this.getMetaFlock();\n }\n}\n","import { Flock } from \"@loro-dev/flock\";\n\nimport type {\n AssetDownload,\n AssetId,\n AssetTransportAdapter,\n GarbageCollectionOptions,\n JsonObject,\n LinkAssetOptions,\n RepoAssetMetadata,\n RepoEventBy,\n StorageAdapter,\n UploadAssetOptions,\n} from \"../types\";\nimport {\n assetContentToUint8Array,\n assetMetaFromJson,\n assetMetaToJson,\n assetMetadataEqual,\n cloneRepoAssetMetadata,\n computeSha256,\n streamToUint8Array,\n toReadableStream,\n} from \"../utils\";\nimport { RepoEventBus } from \"./event-bus\";\nimport { logAsyncError } from \"./logging\";\nimport type { RepoState, AssetRecord, OrphanedAssetRecord } from \"./repo-state\";\n\ninterface AssetManagerOptions<Meta extends JsonObject> {\n readonly storage?: StorageAdapter;\n readonly assetTransport?: AssetTransportAdapter;\n readonly getMetaFlock: () => Flock;\n readonly eventBus: RepoEventBus<Meta>;\n readonly persistMeta: () => Promise<void>;\n readonly state: RepoState;\n}\n\nexport class AssetManager<Meta extends JsonObject> {\n private readonly storage?: StorageAdapter;\n private readonly assetTransport?: AssetTransportAdapter;\n private readonly getMetaFlock: () => Flock;\n private readonly eventBus: RepoEventBus<Meta>;\n private readonly persistMeta: () => Promise<void>;\n private readonly state: RepoState;\n private get docAssets(): Map<string, Map<AssetId, RepoAssetMetadata>> {\n return this.state.docAssets;\n }\n private get assets(): Map<AssetId, AssetRecord> {\n return this.state.assets;\n }\n private get orphanedAssets(): Map<AssetId, OrphanedAssetRecord> {\n return this.state.orphanedAssets;\n }\n private get assetToDocRefs(): Map<AssetId, Set<string>> {\n return this.state.assetToDocRefs;\n }\n\n constructor(options: AssetManagerOptions<Meta>) {\n this.storage = options.storage;\n this.assetTransport = options.assetTransport;\n this.getMetaFlock = options.getMetaFlock;\n this.eventBus = options.eventBus;\n this.persistMeta = options.persistMeta;\n this.state = options.state;\n }\n\n async uploadAsset(params: UploadAssetOptions): Promise<AssetId> {\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 // Ensure we have the data stored locally if possible\n if (this.storage) {\n const stored = await this.storage.loadAsset(assetId);\n if (!stored) {\n await this.storage.save({\n type: \"asset\",\n assetId,\n data: bytes.slice(),\n });\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.eventBus.emit({\n kind: \"asset-metadata\",\n asset: this.createAssetDownload(assetId, metadata, bytes),\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);\n this.markAssetAsOrphan(assetId, metadata); // Initially orphan until linked\n\n this.updateDocAssetMetadata(assetId, metadata);\n\n this.metaFlock.put([\"a\", assetId], assetMetaToJson(metadata));\n await this.persistMeta();\n\n this.eventBus.emit({\n kind: \"asset-metadata\",\n asset: this.createAssetDownload(assetId, metadata, storedBytes),\n by: \"local\",\n });\n\n return assetId;\n }\n\n async linkAsset(docId: string, params: LinkAssetOptions): Promise<AssetId> {\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 // Ensure storage\n if (this.storage) {\n const stored = await this.storage.loadAsset(assetId);\n if (!stored) {\n await this.storage.save({\n type: \"asset\",\n assetId,\n data: bytes.slice(),\n });\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.eventBus.emit({\n kind: \"asset-metadata\",\n asset: this.createAssetDownload(assetId, metadata, bytes),\n by: \"local\",\n });\n } else {\n metadata = existing.metadata;\n }\n storedBytes = bytes;\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);\n\n this.updateDocAssetMetadata(assetId, metadata);\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 this.addDocReference(assetId, docId);\n\n this.metaFlock.put([\"ld\", docId, assetId], true);\n await this.persistMeta();\n\n this.eventBus.emit({ kind: \"asset-link\", docId, assetId, by: \"local\" });\n if (created) {\n this.eventBus.emit({\n kind: \"asset-metadata\",\n asset: this.createAssetDownload(\n assetId,\n metadata,\n storedBytes ?? bytes,\n ),\n by: \"local\",\n });\n }\n return assetId;\n }\n\n async unlinkAsset(docId: string, assetId: AssetId): Promise<void> {\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 this.removeDocAssetReference(assetId, docId);\n // Do NOT delete global metadata [\"a\", assetId] automatically.\n // It will be cleaned up if we implement a global GC strategy,\n // or simply ignored. The binary is managed via orphan references.\n\n await this.persistMeta();\n this.eventBus.emit({ kind: \"asset-unlink\", docId, assetId, by: \"local\" });\n }\n\n async listAssets(docId: string): Promise<RepoAssetMetadata[]> {\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 async fetchAsset(assetId: AssetId): Promise<AssetDownload> {\n const { metadata, bytes } = await this.materializeAsset(assetId);\n return this.createAssetDownload(assetId, metadata, bytes);\n }\n\n async gcAssets(options: GarbageCollectionOptions = {}): Promise<number> {\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 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.removeDocAssetReference(assetId, docId);\n this.eventBus.emit({ kind: \"asset-unlink\", docId, assetId, by });\n }\n }\n return;\n }\n\n this.docAssets.set(docId, mapping);\n\n const removed: AssetId[] = [];\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 removed) {\n this.removeDocAssetReference(assetId, docId);\n this.eventBus.emit({ kind: \"asset-unlink\", docId, assetId, by });\n }\n\n for (const assetId of mapping.keys()) {\n const isNew = !previous || !previous.has(assetId);\n this.addDocReference(assetId, docId);\n if (isNew) {\n this.eventBus.emit({ kind: \"asset-link\", docId, assetId, by });\n }\n }\n }\n\n 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 this.rememberAsset(metadata);\n\n this.updateDocAssetMetadata(assetId, cloneRepoAssetMetadata(metadata));\n\n if (!previous || !assetMetadataEqual(previous.metadata, metadata)) {\n this.eventBus.emit({\n kind: \"asset-metadata\",\n asset: this.createAssetDownload(assetId, metadata),\n by,\n });\n }\n }\n\n hydrateFromFlock(by: RepoEventBy): void {\n const prevDocAssets = new Map(this.docAssets);\n const prevAssets = new Map(this.assets);\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 // No existing check needed for data preservation\n nextAssets.set(assetId, {\n metadata,\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 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.docAssets.clear();\n for (const [docId, assets] of nextDocAssets) {\n this.docAssets.set(docId, assets);\n }\n\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);\n }\n\n // Sync Orphans Logic\n for (const assetId of nextAssets.keys()) {\n const refs = this.assetToDocRefs.get(assetId);\n if (!refs || refs.size === 0) {\n // If refs are 0, it should be an orphan\n if (!this.orphanedAssets.has(assetId)) {\n this.markAssetAsOrphan(assetId, nextAssets.get(assetId)!.metadata);\n }\n } else {\n // If refs > 0, it is NOT an orphan\n this.orphanedAssets.delete(assetId);\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.eventBus.emit({\n kind: \"asset-metadata\",\n asset: this.createAssetDownload(assetId, record.metadata),\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.eventBus.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.eventBus.emit({ kind: \"asset-unlink\", docId, assetId, by });\n }\n }\n }\n }\n\n clear(): void {\n this.docAssets.clear();\n this.assets.clear();\n this.orphanedAssets.clear();\n this.assetToDocRefs.clear();\n }\n\n private readDocAssetsFromFlock(\n docId: string,\n ): 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 =\n 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(\n assetId: AssetId,\n ): 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 this.markAssetAsOrphan(assetId, record.metadata);\n\n const refs = this.assetToDocRefs.get(assetId);\n if (refs) {\n this.assetToDocRefs.delete(assetId);\n for (const docId of refs) {\n const assets = this.docAssets.get(docId);\n if (assets?.delete(assetId) && assets.size === 0) {\n this.docAssets.delete(docId);\n }\n this.eventBus.emit({ kind: \"asset-unlink\", docId, assetId, by });\n }\n return;\n }\n\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 this.eventBus.emit({ kind: \"asset-unlink\", docId, assetId, by });\n }\n }\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 const record = this.assets.get(assetId);\n \n // Removed in-memory data check\n \n if (record && this.storage) {\n const stored = await this.storage.loadAsset(assetId);\n if (stored) {\n return { metadata: record.metadata, bytes: stored };\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 // Removed data cache\n this.assets.set(assetId, { metadata });\n this.updateDocAssetMetadata(assetId, metadata);\n return { metadata, bytes: stored };\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 // Removed data cache\n this.assets.set(assetId, { metadata });\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 const refs = this.assetToDocRefs.get(assetId);\n if (!refs) return;\n for (const docId of refs) {\n const assets = this.docAssets.get(docId);\n if (assets) {\n assets.set(assetId, metadata);\n }\n }\n }\n\n private rememberAsset(metadata: RepoAssetMetadata): void {\n this.assets.set(metadata.assetId, {\n metadata,\n });\n // Removed auto-delete from orphans. Orphans managed by refs.\n }\n\n private addDocReference(assetId: AssetId, docId: string): void {\n const refs = this.assetToDocRefs.get(assetId) ?? new Set<string>();\n refs.add(docId);\n this.assetToDocRefs.set(assetId, refs);\n this.orphanedAssets.delete(assetId); // Ref added -> not orphan\n }\n\n private removeDocAssetReference(assetId: AssetId, docId: string): void {\n const refs = this.assetToDocRefs.get(assetId);\n if (!refs) return;\n refs.delete(docId);\n if (refs.size === 0) {\n this.assetToDocRefs.delete(assetId);\n this.markAssetAsOrphan(assetId); // Ref zero -> orphan\n }\n }\n\n private markAssetAsOrphan(\n assetId: AssetId,\n metadataOverride?: RepoAssetMetadata,\n ): void {\n const metadata = metadataOverride ?? this.assets.get(assetId)?.metadata;\n if (!metadata) return;\n const existing = this.orphanedAssets.get(assetId);\n const deletedAt = existing?.deletedAt ?? Date.now();\n this.orphanedAssets.set(assetId, {\n metadata,\n deletedAt,\n });\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 get metaFlock(): Flock {\n return this.getMetaFlock();\n }\n}","import { Flock, type Event as FlockEvent } from \"@loro-dev/flock\";\n\nimport type { AssetId, JsonObject, RepoEventBy } from \"../types\";\nimport { asJsonObject, cloneJsonValue } from \"../utils\";\nimport { MetadataManager } from \"./metadata-manager\";\nimport { AssetManager } from \"./asset-manager\";\nimport { DocManager } from \"./doc-manager\";\n\ninterface FlockHydratorOptions<Meta extends JsonObject> {\n readonly getMetaFlock: () => Flock;\n readonly metadataManager: MetadataManager<Meta>;\n readonly assetManager: AssetManager<Meta>;\n readonly docManager: DocManager<Meta>;\n}\n\nexport class FlockHydrator<Meta extends JsonObject> {\n private readonly getMetaFlock: () => Flock;\n private readonly metadataManager: MetadataManager<Meta>;\n private readonly assetManager: AssetManager<Meta>;\n private readonly docManager: DocManager<Meta>;\n\n constructor(options: FlockHydratorOptions<Meta>) {\n this.getMetaFlock = options.getMetaFlock;\n this.metadataManager = options.metadataManager;\n this.assetManager = options.assetManager;\n this.docManager = options.docManager;\n }\n\n hydrateAll(by: RepoEventBy): void {\n const nextMetadata = this.readAllDocMetadata();\n this.metadataManager.replaceAll(nextMetadata, by);\n this.assetManager.hydrateFromFlock(by);\n this.docManager.hydrateFrontierKeys();\n }\n\n applyEvents(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 as 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 as 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.assetManager.refreshAssetMetadataEntry(assetId, by);\n }\n\n for (const docId of docMetadataIds) {\n this.metadataManager.refreshFromFlock(docId, by);\n }\n\n for (const docId of docAssetIds) {\n this.assetManager.refreshDocAssetsEntry(docId, by);\n }\n\n for (const docId of docFrontiersIds) {\n this.docManager.refreshDocFrontierKeys(docId);\n }\n }\n\n private readAllDocMetadata(): Map<string, JsonObject> {\n const nextMetadata = new Map<string, JsonObject>();\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 return nextMetadata;\n }\n\n private get metaFlock(): Flock {\n return this.getMetaFlock();\n }\n}\n","import { Flock, type Event as FlockEvent } from \"@loro-dev/flock\";\n\nimport type {\n JsonObject,\n RepoSyncOptions,\n StorageAdapter,\n TransportAdapter,\n TransportJoinParams,\n TransportSubscription,\n} from \"../types\";\nimport { RepoEventBus } from \"./event-bus\";\nimport { DocManager } from \"./doc-manager\";\nimport { MetadataManager } from \"./metadata-manager\";\nimport { AssetManager } from \"./asset-manager\";\nimport { FlockHydrator } from \"./flock-hydrator\";\nimport { logAsyncError } from \"./logging\";\n\ninterface SyncRunnerOptions<Meta extends JsonObject> {\n readonly storage?: StorageAdapter;\n readonly transport?: TransportAdapter;\n readonly eventBus: RepoEventBus<Meta>;\n readonly docManager: DocManager<Meta>;\n readonly metadataManager: MetadataManager<Meta>;\n readonly assetManager: AssetManager<Meta>;\n readonly flockHydrator: FlockHydrator<Meta>;\n readonly getMetaFlock: () => Flock;\n readonly mergeFlock: (snapshot: Flock) => void;\n readonly persistMeta: () => Promise<void>;\n}\n\n/**\n * Sync data between storage and transport layer\n */\nexport class SyncRunner<Meta extends JsonObject> {\n private readonly storage?: StorageAdapter;\n private readonly transport?: TransportAdapter;\n private readonly eventBus: RepoEventBus<Meta>;\n private readonly docManager: DocManager<Meta>;\n private readonly metadataManager: MetadataManager<Meta>;\n private readonly assetManager: AssetManager<Meta>;\n private readonly flockHydrator: FlockHydrator<Meta>;\n private readonly getMetaFlock: () => Flock;\n private readonly replaceMetaFlock: (snapshot: Flock) => void;\n private readonly persistMeta: () => Promise<void>;\n\n private readyPromise?: Promise<void>;\n private metaRoomSubscription?: TransportSubscription;\n private unsubscribeMetaFlock?: () => void;\n private readonly docSubscriptions = new Map<string, TransportSubscription>();\n\n constructor(options: SyncRunnerOptions<Meta>) {\n this.storage = options.storage;\n this.transport = options.transport;\n this.eventBus = options.eventBus;\n this.docManager = options.docManager;\n this.metadataManager = options.metadataManager;\n this.assetManager = options.assetManager;\n this.flockHydrator = options.flockHydrator;\n this.getMetaFlock = options.getMetaFlock;\n this.replaceMetaFlock = options.mergeFlock;\n this.persistMeta = options.persistMeta;\n }\n\n async ready(): Promise<void> {\n if (!this.readyPromise) {\n this.readyPromise = this.initialize();\n }\n await this.readyPromise;\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.eventBus.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.flockHydrator.applyEvents(recordedEvents, \"sync\");\n } else {\n this.flockHydrator.hydrateAll(\"sync\");\n }\n await this.persistMeta();\n } finally {\n unsubscribe();\n this.eventBus.popEventBy();\n }\n }\n\n if (scope === \"doc\" || scope === \"full\") {\n const targets = docIds ?? this.metadataManager.getDocIds();\n for (const docId of targets) {\n const doc = await this.docManager.ensureDoc(docId);\n this.eventBus.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.eventBus.popEventBy();\n }\n await this.docManager.persistDoc(docId, doc);\n await this.docManager.updateDocFrontiers(docId, doc, \"sync\");\n }\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.eventBus.resolveEventBy(\"live\");\n this.flockHydrator.hydrateAll(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\n const existing = this.docSubscriptions.get(docId);\n if (existing) {\n return existing;\n }\n\n const doc = await this.docManager.ensureDoc(docId);\n const subscription = this.transport.joinDocRoom(docId, doc, params);\n const wrapped: TransportSubscription = {\n unsubscribe: () => {\n subscription.unsubscribe();\n if (this.docSubscriptions.get(docId) === wrapped) {\n this.docSubscriptions.delete(docId);\n }\n },\n firstSyncedWithRemote: subscription.firstSyncedWithRemote,\n get connected() {\n return subscription.connected;\n },\n };\n\n this.docSubscriptions.set(docId, wrapped);\n void subscription.firstSyncedWithRemote.catch(\n logAsyncError(`doc ${docId} first sync`),\n );\n return wrapped;\n }\n\n async destroy(): Promise<void> {\n await this.docManager.close();\n this.metaRoomSubscription?.unsubscribe();\n this.metaRoomSubscription = undefined;\n for (const sub of this.docSubscriptions.values()) {\n sub.unsubscribe();\n }\n this.docSubscriptions.clear();\n if (this.unsubscribeMetaFlock) {\n this.unsubscribeMetaFlock();\n this.unsubscribeMetaFlock = undefined;\n }\n this.eventBus.clear();\n this.metadataManager.clear();\n this.assetManager.clear();\n this.readyPromise = undefined;\n await this.transport?.close();\n }\n\n private async initialize(): Promise<void> {\n if (this.storage) {\n const snapshot = await this.storage.loadMeta();\n if (snapshot) {\n this.replaceMetaFlock(snapshot);\n }\n }\n this.flockHydrator.hydrateAll(\"sync\");\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.eventBus.resolveEventBy(\"live\");\n void (async () => {\n this.flockHydrator.applyEvents(batch.events, by);\n await this.persistMeta();\n })().catch(logAsyncError(\"meta live monitor sync\"));\n });\n }\n\n private get metaFlock(): Flock {\n return this.getMetaFlock();\n }\n}\n","import type { AssetId, JsonObject, RepoAssetMetadata } from \"../types\";\n\nexport type AssetRecord = {\n metadata: RepoAssetMetadata;\n};\n\nexport type OrphanedAssetRecord = {\n metadata: RepoAssetMetadata;\n deletedAt: number;\n};\n\nexport interface RepoState {\n readonly metadata: Map<string, JsonObject>;\n readonly docAssets: Map<string, Map<AssetId, RepoAssetMetadata>>;\n readonly assets: Map<AssetId, AssetRecord>;\n readonly orphanedAssets: Map<AssetId, OrphanedAssetRecord>;\n readonly assetToDocRefs: Map<AssetId, Set<string>>;\n readonly docFrontierKeys: Map<string, Set<string>>;\n}\n\nexport function createRepoState(): RepoState {\n return {\n metadata: new Map<string, JsonObject>(),\n docAssets: new Map<string, Map<AssetId, RepoAssetMetadata>>(),\n assets: new Map<AssetId, AssetRecord>(),\n orphanedAssets: new Map<AssetId, OrphanedAssetRecord>(),\n assetToDocRefs: new Map<AssetId, Set<string>>(),\n docFrontierKeys: new Map<string, Set<string>>(),\n };\n}\n","import { Flock } from \"@loro-dev/flock\";\nimport { LoroDoc } 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\";\nexport {\n FileSystemStorageAdaptor,\n type FileSystemStorageAdaptorOptions,\n} from \"./storage/filesystem\";\n\nimport type {\n AssetDownload,\n AssetId,\n GarbageCollectionOptions,\n JsonObject,\n ListDocQuery,\n LoroRepoOptions,\n LinkAssetOptions,\n RepoAssetMetadata,\n RepoDocHandle,\n RepoDocMeta,\n RepoEventFilter,\n RepoEventListener,\n RepoSyncOptions,\n RepoWatchHandle,\n StorageAdapter,\n TransportAdapter,\n TransportJoinParams,\n TransportSubscription,\n UploadAssetOptions,\n AssetTransportAdapter,\n} from \"./types\";\n\nimport { RepoEventBus } from \"./internal/event-bus\";\nimport { DocManager } from \"./internal/doc-manager\";\nimport { MetadataManager } from \"./internal/metadata-manager\";\nimport { AssetManager } from \"./internal/asset-manager\";\nimport { FlockHydrator } from \"./internal/flock-hydrator\";\nimport { SyncRunner } from \"./internal/sync-runner\";\nimport { createRepoState, type RepoState } from \"./internal/repo-state\";\n\nconst textEncoder = new TextEncoder();\nconst DEFAULT_DOC_FRONTIER_DEBOUNCE_MS = 1_000;\n\nexport class LoroRepo<Meta extends JsonObject = JsonObject> {\n readonly options: LoroRepoOptions<Meta>;\n private _destroyed = false;\n private readonly transport?: TransportAdapter;\n private readonly storage?: StorageAdapter;\n private metaFlock: Flock = new Flock();\n private readonly eventBus: RepoEventBus<Meta>;\n private readonly docManager: DocManager<Meta>;\n private readonly metadataManager: MetadataManager<Meta>;\n private readonly assetManager: AssetManager<Meta>;\n private readonly assetTransport?: AssetTransportAdapter;\n private readonly flockHydrator: FlockHydrator<Meta>;\n private readonly state: RepoState;\n private readonly syncRunner: SyncRunner<Meta>;\n\n private 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.eventBus = new RepoEventBus<Meta>();\n this.state = createRepoState();\n const configuredDebounce = options.docFrontierDebounceMs;\n const docFrontierDebounceMs =\n typeof configuredDebounce === \"number\" &&\n Number.isFinite(configuredDebounce) &&\n configuredDebounce >= 0\n ? configuredDebounce\n : DEFAULT_DOC_FRONTIER_DEBOUNCE_MS;\n this.docManager = new DocManager<Meta>({\n storage: this.storage,\n docFrontierDebounceMs,\n getMetaFlock: () => this.metaFlock,\n eventBus: this.eventBus,\n persistMeta: () => this.persistMeta(),\n state: this.state,\n });\n this.metadataManager = new MetadataManager<Meta>({\n getMetaFlock: () => this.metaFlock,\n eventBus: this.eventBus,\n persistMeta: () => this.persistMeta(),\n state: this.state,\n });\n this.assetManager = new AssetManager<Meta>({\n storage: this.storage,\n assetTransport: this.assetTransport,\n getMetaFlock: () => this.metaFlock,\n eventBus: this.eventBus,\n persistMeta: () => this.persistMeta(),\n state: this.state,\n });\n this.flockHydrator = new FlockHydrator<Meta>({\n getMetaFlock: () => this.metaFlock,\n metadataManager: this.metadataManager,\n assetManager: this.assetManager,\n docManager: this.docManager,\n });\n this.syncRunner = new SyncRunner<Meta>({\n storage: this.storage,\n transport: this.transport,\n eventBus: this.eventBus,\n docManager: this.docManager,\n metadataManager: this.metadataManager,\n assetManager: this.assetManager,\n flockHydrator: this.flockHydrator,\n getMetaFlock: () => this.metaFlock,\n mergeFlock: (snapshot) => {\n this.metaFlock.merge(snapshot)\n },\n persistMeta: () => this.persistMeta(),\n });\n }\n\n static async create<Meta extends JsonObject = JsonObject>(options: LoroRepoOptions<Meta>): Promise<LoroRepo<Meta>> {\n const repo = new LoroRepo<Meta>(options);\n await repo.storage?.init?.();\n // Transport may not be valid because the client may be offline, and it would hurt DX if we wait for transport layer \n // to initialize here.\n await repo.ready();\n return repo;\n }\n\n /**\n * Load meta from storage.\n * \n * You need to call this before all other operations to make the app functioning correctly.\n * Though we do that implicitly already\n */\n private async ready(): Promise<void> {\n await this.syncRunner.ready();\n }\n\n /**\n * Sync selected data via the transport adaptor\n * @param options \n */\n async sync(options: RepoSyncOptions = {}): Promise<void> {\n await this.syncRunner.sync(options);\n }\n\n /**\n * Start syncing the metadata (Flock) room. It will establish a realtime connection to the transport adaptor.\n * All changes on the room will be synced to the Flock, and all changes on the Flock will be synced to the room.\n * @param params \n * @returns \n */\n async joinMetaRoom(\n params?: TransportJoinParams,\n ): Promise<TransportSubscription> {\n return this.syncRunner.joinMetaRoom(params);\n }\n\n /**\n * Start syncing the given doc. It will establish a realtime connection to the transport adaptor.\n * All changes on the doc will be synced to the transport, and all changes on the transport will be synced to the doc.\n * \n * All the changes on the room will be reflected on the same doc you get from `repo.openCollaborativeDoc(docId)`\n * @param docId \n * @param params \n * @returns \n */\n async joinDocRoom(\n docId: string,\n params?: TransportJoinParams,\n ): Promise<TransportSubscription> {\n return this.syncRunner.joinDocRoom(docId, params);\n }\n\n /**\n * Opens a document that is automatically persisted to the configured storage adapter.\n * \n * - Edits are saved to storage (debounced).\n * - Frontiers are synced to the metadata (Flock).\n * - Realtime collaboration is NOT enabled by default; use `joinDocRoom` to connect.\n */\n async openPersistedDoc(docId: string): Promise<RepoDocHandle> {\n return {\n doc: await this.docManager.openCollaborativeDoc(docId),\n syncOnce: () => {\n return this.sync({ scope: \"doc\", docIds: [docId] });\n },\n joinRoom: (auth) => {\n return this.syncRunner.joinDocRoom(docId, { auth })\n }\n }\n }\n\n async upsertDocMeta(\n docId: string,\n patch: Partial<Meta>,\n ): Promise<void> {\n await this.metadataManager.upsert(docId, patch);\n }\n\n async getDocMeta(docId: string): Promise<Meta | undefined> {\n return this.metadataManager.get(docId);\n }\n\n async listDoc(query?: ListDocQuery): Promise<RepoDocMeta<Meta>[]> {\n return this.metadataManager.listDoc(query);\n }\n\n getMeta(): Flock {\n return this.metaFlock;\n }\n\n watch(\n listener: RepoEventListener<Meta>,\n filter: RepoEventFilter<Meta> = {},\n ): RepoWatchHandle {\n return this.eventBus.watch(listener, filter);\n }\n\n /**\n * Opens a detached `LoroDoc` snapshot.\n * \n * - **No Persistence**: Edits to this document are NOT saved to storage.\n * - **No Sync**: This document does not participate in realtime updates.\n * - **Use Case**: Ideal for read-only history inspection, temporary drafts, or conflict resolution without affecting the main state.\n */\n async openDetachedDoc(docId: string): Promise<LoroDoc> {\n return this.docManager.openDetachedDoc(docId);\n }\n\n /**\n * Explicitly unloads a document from memory.\n * \n * - **Persists Immediately**: Forces a save of the document's current state to storage.\n * - **Frees Memory**: Removes the document from the internal cache.\n * - **Note**: If the document is currently being synced (via `joinDocRoom`), you should also unsubscribe from the room to fully release resources.\n */\n async unloadDoc(docId: string): Promise<void> {\n await this.docManager.unloadDoc(docId);\n }\n\n async flush(): Promise<void> {\n await this.docManager.flush();\n }\n\n async uploadAsset(params: UploadAssetOptions): Promise<AssetId> {\n return this.assetManager.uploadAsset(params);\n }\n\n async linkAsset(docId: string, params: LinkAssetOptions): Promise<AssetId> {\n return this.assetManager.linkAsset(docId, params);\n }\n\n async fetchAsset(assetId: AssetId): Promise<AssetDownload> {\n return this.assetManager.fetchAsset(assetId);\n }\n\n async unlinkAsset(docId: string, assetId: AssetId): Promise<void> {\n await this.assetManager.unlinkAsset(docId, assetId);\n }\n\n async listAssets(docId: string): Promise<RepoAssetMetadata[]> {\n return this.assetManager.listAssets(docId);\n }\n\n async ensureAsset(assetId: AssetId): Promise<AssetDownload> {\n return this.assetManager.ensureAsset(assetId);\n }\n\n async gcAssets(options: GarbageCollectionOptions = {}): Promise<number> {\n return this.assetManager.gcAssets(options);\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 get destroyed(): boolean {\n return this._destroyed;\n }\n\n async destroy(): Promise<void> {\n if (this._destroyed) return;\n this._destroyed = true;\n await this.syncRunner.destroy();\n this.assetTransport?.close?.();\n this.storage?.close?.();\n await this.transport?.close();\n }\n}\n\n"],"mappings":"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"}