loro-repo 0.5.2 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +175 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +175 -46
- package/dist/index.js.map +1 -1
- package/dist/storage/filesystem.cjs +43 -10
- package/dist/storage/filesystem.cjs.map +1 -1
- package/dist/storage/filesystem.d.cts +6 -1
- package/dist/storage/filesystem.d.ts +6 -1
- package/dist/storage/filesystem.js +43 -10
- package/dist/storage/filesystem.js.map +1 -1
- package/dist/storage/indexeddb.cjs +47 -9
- package/dist/storage/indexeddb.cjs.map +1 -1
- package/dist/storage/indexeddb.d.cts +5 -0
- package/dist/storage/indexeddb.d.ts +5 -0
- package/dist/storage/indexeddb.js +47 -9
- package/dist/storage/indexeddb.js.map +1 -1
- package/dist/types.d.cts +5 -0
- package/dist/types.d.ts +5 -0
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["entry: WatchEntry<Meta>","LoroDoc","promises: Promise<void>[]","by: RepoEventBy","chunks: Uint8Array[]","arr: JsonValue[]","obj: JsonObject","patch: JsonObject","json: JsonObject","scanOptions: ScanOptions","entries: RepoDocMeta<Meta>[]","next: JsonObject","outPatch: JsonObject","docMeta: JsonObject","metadata","metadata: RepoAssetMetadata","storedBytes: Uint8Array | undefined","removed: AssetId[]","removedAssets: Array<[AssetId, AssetRecord]>","recordedEvents: FlockEvent[]","wrapped: TransportSubscription","Flock"],"sources":["../src/internal/event-bus.ts","../src/internal/logging.ts","../src/internal/doc-manager.ts","../src/utils.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 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","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, PeerID, type LoroEventBatch, type VersionVector } from \"loro-crdt\";\n\nimport type {\n JsonObject,\n RepoEventBy,\n StorageAdapter,\n} from \"../types\";\nimport { RepoEventBus } from \"./event-bus\";\nimport { logAsyncError } from \"./logging\";\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}\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\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 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 }\n\n async openPersistedDoc(\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 vv = doc.version();\n const existingFrontiers = this.readFrontiersFromFlock(docId);\n let mutated = false;\n const metaFlock = this.metaFlock;\n\n for (const f of frontiers) {\n const current = existingFrontiers.get(f.peer);\n if (current !== f.counter) {\n metaFlock.put([\"f\", docId, f.peer], f.counter);\n mutated = true;\n }\n }\n\n if (mutated) {\n for (const [peer, counter] of existingFrontiers) {\n const docCounterEnd = vv.get(peer as PeerID);\n if (docCounterEnd != null && docCounterEnd > counter) {\n metaFlock.delete([\"f\", docId, peer]);\n }\n }\n\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 }\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 }\n\n private get metaFlock(): Flock {\n return this.getMetaFlock();\n }\n\n private readFrontiersFromFlock(docId: string): Map<string, number> {\n const rows = this.metaFlock.scan({ prefix: [\"f\", docId] });\n const frontiers = new Map<string, number>();\n for (const row of rows) {\n if (!Array.isArray(row.key) || row.key.length < 3) continue;\n const peer = row.key[2];\n const counter = row.value;\n if (typeof peer !== \"string\") continue;\n if (typeof counter !== \"number\" || !Number.isFinite(counter)) continue;\n frontiers.set(peer, counter);\n }\n return frontiers;\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 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 { 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 normalized = [...frontiers]\n .map((frontier) => {\n const peer = (frontier as { peer?: unknown }).peer;\n const counter = (frontier as { counter?: unknown }).counter;\n if (\n typeof peer !== \"string\" ||\n typeof counter !== \"number\" ||\n !Number.isFinite(counter)\n ) {\n return undefined;\n }\n return { peer, counter };\n })\n .filter(\n (\n entry,\n ): entry is {\n peer: string;\n counter: number;\n } => Boolean(entry),\n )\n .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 = normalized.map((entry) => ({\n peer: entry.peer,\n counter: entry.counter,\n }));\n return { json, key: stableStringify(json) };\n}\n\nexport function includesFrontiers(\n vv: VersionVector,\n frontiers: Frontiers,\n): boolean {\n for (const frontier of frontiers) {\n const peer = frontier.peer;\n const counter = frontier.counter;\n if (typeof peer !== \"string\" || typeof counter !== \"number\") continue;\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","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 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 const previousValue = base\n ? (base[key] as JsonValue | undefined)\n : undefined;\n if (jsonEquals(previousValue, rawValue)) {\n continue;\n }\n\n const storageKey = key === \"tombstone\" ? \"$tombstone\" : key;\n console.log(\"upserting\", rawValue);\n this.metaFlock.put([\"m\", docId, storageKey], rawValue);\n next[key] = rawValue;\n outPatch[key] = rawValue;\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: 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(query?: ListDocQuery): {\n startKey?: string;\n endKey?: string;\n } {\n if (!query) {\n return {};\n }\n\n const prefix =\n 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 }\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 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 }\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 }\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}\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 };\n}\n","import { Flock } from \"@loro-dev/flock\";\nimport { LoroDoc } from \"loro-crdt\";\n\nexport * from \"./types\";\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;\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) {\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 });\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): 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.openPersistedDoc(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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["entry: WatchEntry<Meta>","LoroDoc","promises: Promise<void>[]","by: RepoEventBy","chunks: Uint8Array[]","arr: JsonValue[]","obj: JsonObject","patch: JsonObject","json: JsonObject","scanOptions: ScanOptions","entries: RepoDocMeta<Meta>[]","next: JsonObject","outPatch: JsonObject","docMeta: JsonObject","metadata","metadata: RepoAssetMetadata","storedBytes: Uint8Array | undefined","removed: AssetId[]","removedAssets: Array<[AssetId, AssetRecord]>","recordedEvents: FlockEvent[]","wrapped: TransportSubscription","entries: ExportBundle[\"entries\"]","Flock"],"sources":["../src/internal/event-bus.ts","../src/internal/logging.ts","../src/internal/doc-manager.ts","../src/utils.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/internal/meta-persister.ts","../src/index.ts"],"sourcesContent":["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","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, PeerID, type LoroEventBatch, type VersionVector } from \"loro-crdt\";\n\nimport type {\n JsonObject,\n RepoEventBy,\n StorageAdapter,\n} from \"../types\";\nimport { RepoEventBus } from \"./event-bus\";\nimport { logAsyncError } from \"./logging\";\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}\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\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 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 }\n\n async openPersistedDoc(\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 vv = doc.version();\n const existingFrontiers = this.readFrontiersFromFlock(docId);\n let mutated = false;\n const metaFlock = this.metaFlock;\n\n for (const f of frontiers) {\n const current = existingFrontiers.get(f.peer);\n if (current !== f.counter) {\n metaFlock.put([\"f\", docId, f.peer], f.counter);\n mutated = true;\n }\n }\n\n if (mutated) {\n for (const [peer, counter] of existingFrontiers) {\n const docCounterEnd = vv.get(peer as PeerID);\n if (docCounterEnd != null && docCounterEnd > counter) {\n metaFlock.delete([\"f\", docId, peer]);\n }\n }\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 }\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 }\n\n private get metaFlock(): Flock {\n return this.getMetaFlock();\n }\n\n private readFrontiersFromFlock(docId: string): Map<string, number> {\n const rows = this.metaFlock.scan({ prefix: [\"f\", docId] });\n const frontiers = new Map<string, number>();\n for (const row of rows) {\n if (!Array.isArray(row.key) || row.key.length < 3) continue;\n const peer = row.key[2];\n const counter = row.value;\n if (typeof peer !== \"string\") continue;\n if (typeof counter !== \"number\" || !Number.isFinite(counter)) continue;\n frontiers.set(peer, counter);\n }\n return frontiers;\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 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 { 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 normalized = [...frontiers]\n .map((frontier) => {\n const peer = (frontier as { peer?: unknown }).peer;\n const counter = (frontier as { counter?: unknown }).counter;\n if (\n typeof peer !== \"string\" ||\n typeof counter !== \"number\" ||\n !Number.isFinite(counter)\n ) {\n return undefined;\n }\n return { peer, counter };\n })\n .filter(\n (\n entry,\n ): entry is {\n peer: string;\n counter: number;\n } => Boolean(entry),\n )\n .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 = normalized.map((entry) => ({\n peer: entry.peer,\n counter: entry.counter,\n }));\n return { json, key: stableStringify(json) };\n}\n\nexport function includesFrontiers(\n vv: VersionVector,\n frontiers: Frontiers,\n): boolean {\n for (const frontier of frontiers) {\n const peer = frontier.peer;\n const counter = frontier.counter;\n if (typeof peer !== \"string\" || typeof counter !== \"number\") continue;\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","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 state: RepoState;\n}\n\nexport class MetadataManager<Meta extends JsonObject> {\n private readonly getMetaFlock: () => Flock;\n private readonly eventBus: RepoEventBus<Meta>;\n private readonly state: RepoState;\n\n constructor(options: MetadataManagerOptions<Meta>) {\n this.getMetaFlock = options.getMetaFlock;\n this.eventBus = options.eventBus;\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 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 const previousValue = base\n ? (base[key] as JsonValue | undefined)\n : undefined;\n if (jsonEquals(previousValue, rawValue)) {\n continue;\n }\n\n const storageKey = key === \"tombstone\" ? \"$tombstone\" : key;\n this.metaFlock.put([\"m\", docId, storageKey], rawValue);\n next[key] = rawValue;\n outPatch[key] = rawValue;\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 this.eventBus.emit({\n kind: \"doc-metadata\",\n docId,\n patch: 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(query?: ListDocQuery): {\n startKey?: string;\n endKey?: string;\n } {\n if (!query) {\n return {};\n }\n\n const prefix =\n 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 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 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.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 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 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 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\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 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\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 }\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 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 }\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 }\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}\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\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 }\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 } 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 })\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 })().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}\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 };\n}\n","import { type ExportBundle, type Flock, type VersionVector } from \"@loro-dev/flock\";\n\nimport type { StorageAdapter } from \"../types\";\n\nconst textEncoder = new TextEncoder();\nconst DEFAULT_META_PERSIST_DEBOUNCE_MS = 5_000;\n\ninterface MetaPersisterOptions {\n readonly getMetaFlock: () => Flock;\n readonly storage?: StorageAdapter;\n readonly debounceMs?: number;\n}\n\nexport class MetaPersister {\n private readonly getMetaFlock: () => Flock;\n private readonly storage?: StorageAdapter;\n private readonly debounceMs: number;\n\n private lastPersistedVersion?: VersionVector;\n private unsubscribe?: () => void;\n private flushPromise: Promise<void> = Promise.resolve();\n private flushTimer?: ReturnType<typeof setTimeout>;\n private forceFullOnNextFlush = false;\n private destroyed = false;\n\n constructor(options: MetaPersisterOptions) {\n this.getMetaFlock = options.getMetaFlock;\n this.storage = options.storage;\n const configuredDebounce = options.debounceMs;\n this.debounceMs =\n typeof configuredDebounce === \"number\" && Number.isFinite(configuredDebounce) && configuredDebounce >= 0\n ? configuredDebounce\n : DEFAULT_META_PERSIST_DEBOUNCE_MS;\n }\n\n start(initialVersion: VersionVector | undefined): void {\n this.lastPersistedVersion = initialVersion;\n if (this.unsubscribe) return;\n this.unsubscribe = this.metaFlock.subscribe(() => {\n this.scheduleFlush();\n });\n }\n\n async destroy(): Promise<void> {\n this.destroyed = true;\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = undefined;\n }\n if (this.unsubscribe) {\n this.unsubscribe();\n this.unsubscribe = undefined;\n }\n await this.flushNow();\n }\n\n async flushNow(forceFull = false): Promise<void> {\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = undefined;\n }\n await this.flush(forceFull);\n }\n\n private scheduleFlush(): void {\n if (this.destroyed) return;\n if (this.debounceMs === 0) {\n void this.flush();\n return;\n }\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n }\n this.flushTimer = setTimeout(() => {\n this.flushTimer = undefined;\n void this.flush();\n }, this.debounceMs);\n }\n\n private async flush(forceFull = false): Promise<void> {\n if (forceFull) this.forceFullOnNextFlush = true;\n const run = this.flushPromise.catch(() => {}).then(() => this.flushInternal());\n this.flushPromise = run;\n await run;\n }\n\n private async flushInternal(): Promise<void> {\n const flock = this.metaFlock;\n const currentVersion = flock.version();\n if (this.lastPersistedVersion && this.versionsEqual(currentVersion, this.lastPersistedVersion)) {\n this.forceFullOnNextFlush = false;\n return;\n }\n\n const baseline = this.forceFullOnNextFlush ? undefined : this.lastPersistedVersion;\n const rawBundle = baseline ? flock.exportJson(baseline) : flock.exportJson();\n const bundle = baseline ? this.stripUnchangedEntries(rawBundle, baseline) : rawBundle;\n if (Object.keys(bundle.entries).length === 0) {\n this.forceFullOnNextFlush = false;\n this.lastPersistedVersion = currentVersion;\n return;\n }\n\n const encoded = textEncoder.encode(JSON.stringify(bundle));\n\n if (!this.storage) {\n this.lastPersistedVersion = currentVersion;\n this.forceFullOnNextFlush = false;\n return;\n }\n\n try {\n await this.storage.save({ type: \"meta\", update: encoded });\n } catch (error) {\n throw error;\n }\n this.lastPersistedVersion = currentVersion;\n this.forceFullOnNextFlush = false;\n }\n\n private get metaFlock(): Flock {\n return this.getMetaFlock();\n }\n\n private stripUnchangedEntries(bundle: ExportBundle, baseline: VersionVector): ExportBundle {\n const entries: ExportBundle[\"entries\"] = {};\n for (const [key, record] of Object.entries(bundle.entries)) {\n const clock = this.parseClock(record.c);\n if (!clock) {\n entries[key] = record;\n continue;\n }\n const baselineEntry = baseline[clock.peerIdHex];\n if (!baselineEntry) {\n entries[key] = record;\n continue;\n }\n const isNewer =\n clock.physicalTime > baselineEntry.physicalTime ||\n (clock.physicalTime === baselineEntry.physicalTime && clock.logicalCounter > baselineEntry.logicalCounter);\n if (isNewer) {\n entries[key] = record;\n }\n }\n return { version: bundle.version, entries };\n }\n\n private parseClock(raw: unknown): { physicalTime: number; logicalCounter: number; peerIdHex: string } | undefined {\n if (typeof raw !== \"string\") return undefined;\n const [physicalTimeStr, logicalCounterStr, peerIdHex] = raw.split(\",\");\n if (!physicalTimeStr || !logicalCounterStr || !peerIdHex) return undefined;\n const physicalTime = Number(physicalTimeStr);\n const logicalCounter = Number(logicalCounterStr);\n if (!Number.isFinite(physicalTime) || !Number.isFinite(logicalCounter)) return undefined;\n return { physicalTime, logicalCounter, peerIdHex };\n }\n\n private versionsEqual(a?: VersionVector, b?: VersionVector): boolean {\n if (!a || !b) return false;\n const aKeys = Object.keys(a);\n const bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) return false;\n for (const key of aKeys) {\n const aEntry = a[key];\n const bEntry = b[key];\n if (!aEntry || !bEntry) return false;\n if (aEntry.physicalTime !== bEntry.physicalTime || aEntry.logicalCounter !== bEntry.logicalCounter) {\n return false;\n }\n }\n return true;\n }\n}\n","import { Flock } from \"@loro-dev/flock\";\nimport { LoroDoc } from \"loro-crdt\";\n\nexport * from \"./types\";\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\";\nimport { MetaPersister } from \"./internal/meta-persister\";\nconst DEFAULT_DOC_FRONTIER_DEBOUNCE_MS = 1_000;\n\nexport class LoroRepo<Meta extends JsonObject = JsonObject> {\n readonly options: LoroRepoOptions;\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 private readonly metaPersister: MetaPersister;\n\n private constructor(options: LoroRepoOptions) {\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 });\n this.metadataManager = new MetadataManager<Meta>({\n getMetaFlock: () => this.metaFlock,\n eventBus: this.eventBus,\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 state: this.state,\n });\n this.metaPersister = new MetaPersister({\n getMetaFlock: () => this.metaFlock,\n storage: this.storage,\n debounceMs: options.metaPersistDebounceMs,\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 });\n }\n\n static async create<Meta extends JsonObject = JsonObject>(options: LoroRepoOptions): 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 this.metaPersister.start(this.metaFlock.version());\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 const subscription = await this.syncRunner.joinMetaRoom(params);\n return {\n unsubscribe: subscription.unsubscribe,\n get connected() {\n return subscription.connected;\n },\n firstSyncedWithRemote: subscription.firstSyncedWithRemote.then(async () => {\n await this.metaPersister.flushNow();\n }),\n };\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.openPersistedDoc(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 await this.metaPersister.flushNow();\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 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.metaPersister.destroy();\n await this.syncRunner.destroy();\n this.assetTransport?.close?.();\n this.storage?.close?.();\n await this.transport?.close();\n }\n}\n"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -17,6 +17,7 @@ declare class LoroRepo<Meta extends JsonObject = JsonObject> {
|
|
|
17
17
|
private readonly flockHydrator;
|
|
18
18
|
private readonly state;
|
|
19
19
|
private readonly syncRunner;
|
|
20
|
+
private readonly metaPersister;
|
|
20
21
|
private constructor();
|
|
21
22
|
static create<Meta extends JsonObject = JsonObject>(options: LoroRepoOptions): Promise<LoroRepo<Meta>>;
|
|
22
23
|
/**
|
|
@@ -85,7 +86,6 @@ declare class LoroRepo<Meta extends JsonObject = JsonObject> {
|
|
|
85
86
|
listAssets(docId: string): Promise<RepoAssetMetadata[]>;
|
|
86
87
|
ensureAsset(assetId: AssetId): Promise<AssetDownload>;
|
|
87
88
|
gcAssets(options?: GarbageCollectionOptions): Promise<number>;
|
|
88
|
-
private persistMeta;
|
|
89
89
|
get destroyed(): boolean;
|
|
90
90
|
destroy(): Promise<void>;
|
|
91
91
|
}
|