@bendyline/docblocks 1.1.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -11
- package/dist/chunk-6IYMTYMQ.js +1692 -0
- package/dist/chunk-6IYMTYMQ.js.map +1 -0
- package/dist/chunk-AEHCVWU5.js +25 -0
- package/dist/chunk-AEHCVWU5.js.map +1 -0
- package/dist/chunk-B56KWCSE.js +802 -0
- package/dist/chunk-B56KWCSE.js.map +1 -0
- package/dist/{chunk-ME76RUMR.js → chunk-BNKV7MTO.js} +15 -1
- package/dist/chunk-BNKV7MTO.js.map +1 -0
- package/dist/chunk-BXMF5YQJ.js +149 -0
- package/dist/chunk-BXMF5YQJ.js.map +1 -0
- package/dist/chunk-COYQXQK3.js +1071 -0
- package/dist/chunk-COYQXQK3.js.map +1 -0
- package/dist/chunk-DN7A33LL.js +780 -0
- package/dist/chunk-DN7A33LL.js.map +1 -0
- package/dist/chunk-EZKJZUNJ.js +13 -0
- package/dist/chunk-EZKJZUNJ.js.map +1 -0
- package/dist/chunk-FA7UNOXK.js +20 -0
- package/dist/chunk-FA7UNOXK.js.map +1 -0
- package/dist/chunk-FNW556FN.js +75 -0
- package/dist/chunk-FNW556FN.js.map +1 -0
- package/dist/chunk-GM5YXU4L.js +29 -0
- package/dist/chunk-GM5YXU4L.js.map +1 -0
- package/dist/chunk-JS6XFWQK.js +225 -0
- package/dist/chunk-JS6XFWQK.js.map +1 -0
- package/dist/chunk-MNSZ7EZN.js +111 -0
- package/dist/chunk-MNSZ7EZN.js.map +1 -0
- package/dist/chunk-P3DVZQ6S.js +228 -0
- package/dist/chunk-P3DVZQ6S.js.map +1 -0
- package/dist/chunk-P4WATND4.js +52 -0
- package/dist/chunk-P4WATND4.js.map +1 -0
- package/dist/chunk-RVPGQBWR.js +169 -0
- package/dist/chunk-RVPGQBWR.js.map +1 -0
- package/dist/chunk-U722UUFN.js +9 -0
- package/dist/chunk-U722UUFN.js.map +1 -0
- package/dist/chunk-VTCSF7VS.js +553 -0
- package/dist/chunk-VTCSF7VS.js.map +1 -0
- package/dist/chunk-WJKYY5QR.js +1350 -0
- package/dist/chunk-WJKYY5QR.js.map +1 -0
- package/dist/chunk-XUML3MKV.js +945 -0
- package/dist/chunk-XUML3MKV.js.map +1 -0
- package/dist/document/index.d.ts +358 -0
- package/dist/document/index.js +25 -0
- package/dist/document/index.js.map +1 -0
- package/dist/filesystem/electron.d.ts +73 -0
- package/dist/filesystem/electron.js +17 -0
- package/dist/filesystem/electron.js.map +1 -0
- package/dist/filesystem/index.d.ts +228 -8
- package/dist/filesystem/index.js +133 -6
- package/dist/filesystem/index.js.map +1 -1
- package/dist/filesystem/indexeddb.d.ts +284 -0
- package/dist/filesystem/indexeddb.js +23 -0
- package/dist/filesystem/indexeddb.js.map +1 -0
- package/dist/filesystem/memory.d.ts +152 -0
- package/dist/filesystem/memory.js +13 -0
- package/dist/filesystem/memory.js.map +1 -0
- package/dist/filesystem/native.d.ts +136 -0
- package/dist/filesystem/native.js +28 -0
- package/dist/filesystem/native.js.map +1 -0
- package/dist/host/index.d.ts +32 -6
- package/dist/host/index.js +26 -27
- package/dist/host/index.js.map +1 -1
- package/dist/index.d.ts +14 -9
- package/dist/index.js +204 -8
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.d.ts +33 -0
- package/dist/mcp/index.js +32 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/zod.d.ts +5765 -0
- package/dist/mcp/zod.js +724 -0
- package/dist/mcp/zod.js.map +1 -0
- package/dist/share/index.d.ts +43 -0
- package/dist/share/index.js +13 -0
- package/dist/share/index.js.map +1 -0
- package/dist/types-BEg5SQ1_.d.ts +301 -0
- package/dist/types-CX893hgH.d.ts +468 -0
- package/dist/types-CueK0tvU.d.ts +501 -0
- package/dist/vscode/index.d.ts +220 -0
- package/dist/vscode/index.js +383 -0
- package/dist/vscode/index.js.map +1 -0
- package/dist/workspace/index.d.ts +141 -3
- package/dist/workspace/index.js +28 -1
- package/dist/workspace/index.js.map +1 -1
- package/dist/workspace-path-CWVrcuPL.d.ts +21 -0
- package/package.json +50 -5
- package/dist/chunk-GUNM43XZ.js +0 -63
- package/dist/chunk-GUNM43XZ.js.map +0 -1
- package/dist/chunk-IM7LCQJ6.js +0 -850
- package/dist/chunk-IM7LCQJ6.js.map +0 -1
- package/dist/chunk-ME76RUMR.js.map +0 -1
- package/dist/filesystem/electron-provider.d.ts +0 -32
- package/dist/filesystem/electron-provider.d.ts.map +0 -1
- package/dist/filesystem/electron-provider.js +0 -64
- package/dist/filesystem/electron-provider.js.map +0 -1
- package/dist/filesystem/file-media-provider.d.ts +0 -23
- package/dist/filesystem/file-media-provider.d.ts.map +0 -1
- package/dist/filesystem/file-media-provider.js +0 -85
- package/dist/filesystem/file-media-provider.js.map +0 -1
- package/dist/filesystem/filesystem-content-container.d.ts +0 -24
- package/dist/filesystem/filesystem-content-container.d.ts.map +0 -1
- package/dist/filesystem/filesystem-content-container.js +0 -116
- package/dist/filesystem/filesystem-content-container.js.map +0 -1
- package/dist/filesystem/index.d.ts.map +0 -1
- package/dist/filesystem/indexeddb-content-container.d.ts +0 -20
- package/dist/filesystem/indexeddb-content-container.d.ts.map +0 -1
- package/dist/filesystem/indexeddb-content-container.js +0 -93
- package/dist/filesystem/indexeddb-content-container.js.map +0 -1
- package/dist/filesystem/indexeddb-provider.d.ts +0 -32
- package/dist/filesystem/indexeddb-provider.d.ts.map +0 -1
- package/dist/filesystem/indexeddb-provider.js +0 -295
- package/dist/filesystem/indexeddb-provider.js.map +0 -1
- package/dist/filesystem/native-provider.d.ts +0 -45
- package/dist/filesystem/native-provider.d.ts.map +0 -1
- package/dist/filesystem/native-provider.js +0 -336
- package/dist/filesystem/native-provider.js.map +0 -1
- package/dist/filesystem/types.d.ts +0 -50
- package/dist/filesystem/types.d.ts.map +0 -1
- package/dist/filesystem/types.js +0 -8
- package/dist/filesystem/types.js.map +0 -1
- package/dist/host/index.d.ts.map +0 -1
- package/dist/host/types.d.ts +0 -149
- package/dist/host/types.d.ts.map +0 -1
- package/dist/host/types.js +0 -10
- package/dist/host/types.js.map +0 -1
- package/dist/index-pgBHBQ9G.d.ts +0 -213
- package/dist/index.d.ts.map +0 -1
- package/dist/workspace/index.d.ts.map +0 -1
- package/dist/workspace/types.d.ts +0 -29
- package/dist/workspace/types.d.ts.map +0 -1
- package/dist/workspace/types.js +0 -6
- package/dist/workspace/types.js.map +0 -1
- package/dist/workspace/workspace-manager.d.ts +0 -35
- package/dist/workspace/workspace-manager.d.ts.map +0 -1
- package/dist/workspace/workspace-manager.js +0 -82
- package/dist/workspace/workspace-manager.js.map +0 -1
- package/src/filesystem/electron-provider.ts +0 -88
- package/src/filesystem/file-media-provider.ts +0 -103
- package/src/filesystem/filesystem-content-container.ts +0 -126
- package/src/filesystem/index.ts +0 -24
- package/src/filesystem/indexeddb-content-container.ts +0 -104
- package/src/filesystem/indexeddb-provider.ts +0 -345
- package/src/filesystem/native-provider.ts +0 -384
- package/src/filesystem/types.ts +0 -69
- package/src/host/index.ts +0 -47
- package/src/host/types.ts +0 -153
- package/src/index.ts +0 -9
- package/src/workspace/index.ts +0 -10
- package/src/workspace/types.ts +0 -29
- package/src/workspace/workspace-manager.ts +0 -90
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/filesystem/legacy-v2-adapter.ts","../src/filesystem/move-entry.ts","../src/filesystem/dbk-workspace.ts","../src/filesystem/filesystem-content-container.ts","../src/filesystem/file-media-provider.ts"],"sourcesContent":["import { FsError, fsErrorFromUnknown, type FsOperation } from './fs-error.js';\nimport type { FileSystemEntry, FileSystemProvider } from './types.js';\nimport {\n parseFileSystemVersion,\n type FileSystemAtomicity,\n type FileSystemCaseSensitivity,\n type FileSystemCreateDirectoryOptions,\n type FileSystemDirectorySnapshot,\n type FileSystemDurability,\n type FileSystemEntrySnapshot,\n type FileSystemFileRead,\n type FileSystemFileSnapshot,\n type FileSystemMoveOptions,\n type FileSystemProviderCapabilities,\n type FileSystemProviderV2,\n type FileSystemRemoveOptions,\n type FileSystemRemoveResult,\n type FileSystemSnapshot,\n type FileSystemSnapshotEntry,\n type FileSystemSnapshotFile,\n type FileSystemSymlinkPolicy,\n type FileSystemVersion,\n type FileSystemWatchListener,\n type FileSystemWatchOptions,\n type FileSystemWatchSubscription,\n type FileSystemWriteOptions,\n} from './v2.js';\nimport {\n WORKSPACE_ROOT,\n parseWorkspacePath,\n workspacePathBasename,\n workspacePathContains,\n workspacePathDirname,\n workspacePathToLegacy,\n type WorkspacePath,\n} from './workspace-path.js';\nimport { bytesEqual, copyBytes } from './internal/bytes.js';\nimport { compareSnapshotsByName, compareText } from './internal/entry-order.js';\n\nexport type LegacyFilePayloadModel =\n | 'split'\n | 'binary-first-text-fallback'\n | 'binary-authoritative';\n\nexport interface LegacyFileSystemProviderV2AdapterOptions {\n /**\n * Split stores expose independent raw text and binary channels and reject\n * dual payloads. Binary-first stores synthesize text for binary records, so\n * the adapter only asks for text after readBinary() returns null. Binary-\n * authoritative stores expose every file through readBinary().\n */\n readonly payloadModel: LegacyFilePayloadModel;\n readonly writeAtomicity?: FileSystemAtomicity;\n readonly moveAtomicity?: FileSystemAtomicity;\n readonly caseSensitivity?: FileSystemCaseSensitivity;\n readonly symlinkPolicy?: FileSystemSymlinkPolicy;\n readonly durability?: FileSystemDurability;\n /** Optional ownership hook; omitted when the adapter does not own the v1 provider. */\n readonly dispose?: () => void | Promise<void>;\n}\n\ninterface CapturedTree {\n readonly entries: ReadonlyMap<WorkspacePath, FileSystemSnapshotEntry>;\n readonly version: FileSystemVersion;\n}\n\nconst EPOCH = new Date(0).toISOString();\n\n/**\n * Correctness bridge for hardened v1 providers while storage backends migrate.\n *\n * The adapter deliberately serializes every observable operation. This makes a\n * version check and its mutation indivisible among v2 callers, but cannot make\n * calls that bypass the adapter participate in that boundary. Content-derived\n * versions make those external changes visible on the next adapter operation.\n */\nexport class LegacyFileSystemProviderV2Adapter implements FileSystemProviderV2 {\n public readonly id: string;\n public readonly label: string;\n public readonly capabilities: FileSystemProviderCapabilities;\n\n private operationTail: Promise<void> = Promise.resolve();\n private readonly subscriptions = new Set<FileSystemWatchSubscription>();\n private closing = false;\n private disposed = false;\n private disposePromise: Promise<void> | null = null;\n\n public constructor(\n private readonly provider: FileSystemProvider,\n private readonly options: LegacyFileSystemProviderV2AdapterOptions,\n ) {\n this.id = provider.id;\n this.label = provider.label;\n this.capabilities = Object.freeze({\n writeAtomicity: options.writeAtomicity ?? 'none',\n moveAtomicity: options.moveAtomicity ?? 'none',\n // A tree snapshot spans multiple v1 calls; callers that bypass this\n // adapter can still interleave, even though adapter operations serialize.\n snapshotAtomicity: 'none',\n conditionalWrite: 'process',\n recursiveRemove: true,\n watch: false,\n caseSensitivity: options.caseSensitivity ?? 'platform',\n symlinkPolicy: options.symlinkPolicy ?? 'unsupported',\n durability: options.durability ?? 'best-effort',\n });\n }\n\n public async stat(path: WorkspacePath): Promise<FileSystemEntrySnapshot | null> {\n const canonical = this.canonical(path);\n return this.enqueue('stat', async () => {\n const entry = (await this.captureTree('stat')).entries.get(canonical);\n return entry ? copyEntrySnapshot(entry) : null;\n });\n }\n\n public async readFile(path: WorkspacePath): Promise<FileSystemFileRead | null> {\n const canonical = this.canonical(path);\n return this.enqueue('read', async () => {\n const entry = (await this.captureTree('read')).entries.get(canonical);\n if (!entry) return null;\n if (entry.kind !== 'file') {\n throw this.error('type-mismatch', 'read', canonical, 'Expected a file, found a directory.');\n }\n return Object.freeze({ entry: fileMetadata(entry), data: entry.data.slice(0) });\n });\n }\n\n public async readDirectory(path: WorkspacePath): Promise<readonly FileSystemEntrySnapshot[]> {\n const canonical = this.canonical(path);\n return this.enqueue('list', async () => {\n const tree = await this.captureTree('list');\n const entry = tree.entries.get(canonical);\n if (!entry) throw this.error('not-found', 'list', canonical, 'Directory does not exist.');\n if (entry.kind !== 'directory') {\n throw this.error('type-mismatch', 'list', canonical, 'Expected a directory, found a file.');\n }\n const children = [...tree.entries.entries()]\n .filter(([entryPath]) => entryPath && workspacePathDirname(entryPath) === canonical)\n .map(([, child]) => copyEntrySnapshot(child))\n .sort(compareSnapshotsByName);\n return Object.freeze(children);\n });\n }\n\n public async writeFile(\n path: WorkspacePath,\n data: ArrayBuffer | Uint8Array,\n options: FileSystemWriteOptions = {},\n ): Promise<FileSystemFileSnapshot> {\n const canonical = this.canonicalNonRoot(path, 'write');\n const ownedData = copyBytes(data);\n return this.enqueue('write', async () => {\n const tree = await this.captureTree('write');\n const existing = tree.entries.get(canonical);\n if (existing?.kind === 'directory') {\n throw this.error(\n 'type-mismatch',\n 'write',\n canonical,\n 'Cannot replace a directory with a file.',\n );\n }\n\n const mode = options.mode ?? 'upsert';\n if (mode === 'create' && existing) {\n throw this.error('already-exists', 'write', canonical, 'File already exists.');\n }\n if (mode === 'replace' && !existing) {\n throw this.error('not-found', 'write', canonical, 'File does not exist.');\n }\n this.assertExpectedVersion(existing, options.expectedVersion, 'write', canonical);\n this.assertParents(tree, canonical, options.createParents ?? false, 'write');\n\n await this.invoke(\n () => this.provider.writeBinary(workspacePathToLegacy(canonical), ownedData),\n 'write',\n canonical,\n );\n const written = (await this.captureTree('write')).entries.get(canonical);\n if (written?.kind !== 'file' || !bytesEqual(written.data, ownedData)) {\n throw this.error(\n 'io',\n 'write',\n canonical,\n 'The legacy provider did not persist the requested bytes.',\n );\n }\n return fileMetadata(written);\n });\n }\n\n public async createDirectory(\n path: WorkspacePath,\n options: FileSystemCreateDirectoryOptions = {},\n ): Promise<FileSystemDirectorySnapshot> {\n const canonical = this.canonical(path);\n return this.enqueue('create-directory', async () => {\n const tree = await this.captureTree('create-directory');\n const existing = tree.entries.get(canonical);\n if (existing) {\n if (existing.kind !== 'directory') {\n throw this.error(\n 'type-mismatch',\n 'create-directory',\n canonical,\n 'Cannot replace a file with a directory.',\n );\n }\n if ((options.mode ?? 'ensure') === 'create') {\n throw this.error(\n 'already-exists',\n 'create-directory',\n canonical,\n 'Directory already exists.',\n );\n }\n return copyDirectorySnapshot(existing);\n }\n\n this.assertParents(tree, canonical, options.createParents ?? false, 'create-directory');\n await this.invoke(\n () => this.provider.createDirectory(workspacePathToLegacy(canonical)),\n 'create-directory',\n canonical,\n );\n const created = (await this.captureTree('create-directory')).entries.get(canonical);\n if (created?.kind !== 'directory') {\n throw this.error(\n 'io',\n 'create-directory',\n canonical,\n 'The legacy provider did not create the directory.',\n );\n }\n return copyDirectorySnapshot(created);\n });\n }\n\n public async remove(\n path: WorkspacePath,\n options: FileSystemRemoveOptions = {},\n ): Promise<FileSystemRemoveResult> {\n const canonical = this.canonicalNonRoot(path, 'remove');\n return this.enqueue('remove', async () => {\n const tree = await this.captureTree('remove');\n const existing = tree.entries.get(canonical);\n if (!existing) {\n if ((options.missing ?? 'error') === 'ignore') {\n return Object.freeze({ removed: false, version: tree.version });\n }\n throw this.error('not-found', 'remove', canonical, 'Entry does not exist.');\n }\n this.assertExpectedVersion(existing, options.expectedVersion, 'remove', canonical);\n if (\n existing.kind === 'directory' &&\n !options.recursive &&\n [...tree.entries.keys()].some((candidate) =>\n workspacePathContains(canonical, candidate, false),\n )\n ) {\n throw this.error('not-empty', 'remove', canonical, 'Directory is not empty.');\n }\n\n await this.invoke(\n () => this.provider.delete(workspacePathToLegacy(canonical)),\n 'remove',\n canonical,\n );\n const after = await this.captureTree('remove');\n if (\n [...after.entries.keys()].some((candidate) => workspacePathContains(canonical, candidate))\n ) {\n throw this.error(\n 'io',\n 'remove',\n canonical,\n 'The legacy provider did not remove the complete entry.',\n );\n }\n return Object.freeze({ removed: true, version: after.version });\n });\n }\n\n public async move(\n oldPath: WorkspacePath,\n newPath: WorkspacePath,\n options: FileSystemMoveOptions = {},\n ): Promise<FileSystemEntrySnapshot> {\n const sourcePath = this.canonicalNonRoot(oldPath, 'move');\n const destinationPath = this.canonicalNonRoot(newPath, 'move');\n return this.enqueue('move', async () => {\n const tree = await this.captureTree('move');\n const source = tree.entries.get(sourcePath);\n if (!source) throw this.error('not-found', 'move', sourcePath, 'Source does not exist.');\n this.assertExpectedVersion(source, options.expectedVersion, 'move', sourcePath);\n if (sourcePath === destinationPath) return copyEntrySnapshot(source);\n if (tree.entries.has(destinationPath)) {\n throw new FsError('already-exists', 'Destination already exists.', {\n operation: 'move',\n path: sourcePath,\n destinationPath,\n });\n }\n if (\n source.kind === 'directory' &&\n workspacePathContains(sourcePath, destinationPath, false)\n ) {\n throw new FsError('invalid-path', 'Cannot move a directory into itself.', {\n operation: 'move',\n path: sourcePath,\n destinationPath,\n });\n }\n this.assertParents(tree, destinationPath, options.createParents ?? false, 'move');\n\n const sourceEntries = [...tree.entries.entries()].filter(([candidate]) =>\n workspacePathContains(sourcePath, candidate),\n );\n await this.invoke(\n () =>\n this.provider.rename(\n workspacePathToLegacy(sourcePath),\n workspacePathToLegacy(destinationPath),\n ),\n 'move',\n sourcePath,\n destinationPath,\n );\n\n const after = await this.captureTree('move');\n if (\n [...after.entries.keys()].some((candidate) => workspacePathContains(sourcePath, candidate))\n ) {\n throw this.error(\n 'io',\n 'move',\n sourcePath,\n 'The legacy provider left source entries behind.',\n );\n }\n for (const [oldEntryPath, oldEntry] of sourceEntries) {\n const suffix = oldEntryPath.slice(sourcePath.length);\n const movedPath = parseWorkspacePath(`${destinationPath}${suffix}`);\n const moved = after.entries.get(movedPath);\n if (!moved || moved.kind !== oldEntry.kind || moved.version !== oldEntry.version) {\n throw new FsError(\n 'io',\n 'The legacy provider did not move the complete entry unchanged.',\n {\n operation: 'move',\n path: oldEntryPath,\n destinationPath: movedPath,\n },\n );\n }\n }\n return copyEntrySnapshot(after.entries.get(destinationPath)!);\n });\n }\n\n public async snapshot(): Promise<FileSystemSnapshot> {\n return this.enqueue('snapshot', async () => {\n const tree = await this.captureTree('snapshot');\n const entries = [...tree.entries.values()]\n .sort((left, right) => compareText(left.path, right.path))\n .map((entry) => copySnapshotEntry(entry));\n return Object.freeze({ version: tree.version, entries: Object.freeze(entries) });\n });\n }\n\n public watch(\n _listener: FileSystemWatchListener,\n options: FileSystemWatchOptions = {},\n ): FileSystemWatchSubscription {\n this.assertAccepting('watch');\n const error = new FsError(\n 'not-supported',\n 'The legacy adapter cannot observe external changes.',\n {\n operation: 'watch',\n },\n );\n let closed = false;\n let disposePromise: Promise<void> | null = null;\n const ready = Promise.reject(error);\n void ready.catch((caught: FsError) => {\n try {\n options.onError?.(caught);\n } catch {\n // An observational error callback cannot change subscription state.\n }\n });\n const subscription: FileSystemWatchSubscription = {\n get closed() {\n return closed;\n },\n ready,\n dispose: () => {\n if (disposePromise) return disposePromise;\n closed = true;\n this.subscriptions.delete(subscription);\n disposePromise = Promise.resolve();\n return disposePromise;\n },\n };\n this.subscriptions.add(subscription);\n return subscription;\n }\n\n public dispose(): Promise<void> {\n if (this.disposePromise) return this.disposePromise;\n this.closing = true;\n const run = this.operationTail.then(async () => {\n try {\n await Promise.all([...this.subscriptions].map((subscription) => subscription.dispose()));\n await this.options.dispose?.();\n } catch (error: unknown) {\n throw fsErrorFromUnknown(error, { operation: 'dispose' });\n } finally {\n this.disposed = true;\n }\n });\n this.operationTail = run.then(\n () => undefined,\n () => undefined,\n );\n this.disposePromise = run;\n return run;\n }\n\n private enqueue<T>(operation: FsOperation, task: () => Promise<T>): Promise<T> {\n this.assertAccepting(operation);\n const run = this.operationTail.then(task);\n this.operationTail = run.then(\n () => undefined,\n () => undefined,\n );\n return run;\n }\n\n private assertAccepting(operation: FsOperation): void {\n if (!this.closing && !this.disposed) return;\n throw new FsError('disposed', 'Filesystem provider is disposed.', { operation });\n }\n\n private canonical(path: WorkspacePath): WorkspacePath {\n return parseWorkspacePath(path);\n }\n\n private canonicalNonRoot(path: WorkspacePath, operation: FsOperation): WorkspacePath {\n const canonical = this.canonical(path);\n if (!canonical) {\n throw this.error(\n 'invalid-path',\n operation,\n canonical,\n 'The workspace root is not an entry target.',\n );\n }\n return canonical;\n }\n\n private assertExpectedVersion(\n entry: FileSystemSnapshotEntry | undefined,\n expected: FileSystemVersion | null | undefined,\n operation: FsOperation,\n path: WorkspacePath,\n ): void {\n if (expected === undefined) return;\n if (expected === null ? !entry : entry?.version === expected) return;\n throw this.error(\n 'conflict',\n operation,\n path,\n 'Entry version does not match the expected version.',\n );\n }\n\n private assertParents(\n tree: CapturedTree,\n path: WorkspacePath,\n createParents: boolean,\n operation: FsOperation,\n ): void {\n let parent = workspacePathDirname(path);\n const parents: WorkspacePath[] = [];\n while (parent) {\n parents.unshift(parent);\n parent = workspacePathDirname(parent);\n }\n for (const candidate of parents) {\n const entry = tree.entries.get(candidate);\n if (entry?.kind === 'file') {\n throw this.error('type-mismatch', operation, candidate, 'A parent path is a file.');\n }\n if (!entry && !createParents) {\n throw this.error('not-found', operation, candidate, 'Parent directory does not exist.');\n }\n }\n }\n\n private async captureTree(operation: FsOperation): Promise<CapturedTree> {\n const entries = new Map<WorkspacePath, FileSystemSnapshotEntry>();\n const visiting = new Set<WorkspacePath>();\n\n const visitDirectory = async (path: WorkspacePath): Promise<FileSystemDirectorySnapshot> => {\n if (visiting.has(path)) {\n throw this.error('io', operation, path, 'The legacy provider returned a directory cycle.');\n }\n visiting.add(path);\n const listed = await this.invoke(\n () => this.provider.readDirectory(workspacePathToLegacy(path)),\n operation,\n path,\n );\n if (!Array.isArray(listed)) {\n throw this.error(\n 'io',\n operation,\n path,\n 'The legacy provider returned an invalid directory listing.',\n );\n }\n const children: FileSystemSnapshotEntry[] = [];\n const seen = new Set<WorkspacePath>();\n for (const candidate of listed as readonly unknown[]) {\n if (!isLegacyEntry(candidate)) {\n throw this.error(\n 'io',\n operation,\n path,\n 'The legacy provider returned an invalid directory entry.',\n );\n }\n const legacyEntry = candidate;\n const childPath = parseWorkspacePath(legacyEntry.path);\n if (\n !childPath ||\n workspacePathDirname(childPath) !== path ||\n workspacePathBasename(childPath) !== legacyEntry.name\n ) {\n throw this.error(\n 'io',\n operation,\n path,\n 'The legacy provider returned a non-child entry.',\n );\n }\n if (seen.has(childPath) || entries.has(childPath)) {\n throw this.error(\n 'io',\n operation,\n childPath,\n 'The legacy provider returned duplicate entry paths.',\n );\n }\n seen.add(childPath);\n\n if (legacyEntry.kind === 'directory') {\n children.push(await visitDirectory(childPath));\n } else {\n const file = await this.captureFile(childPath, operation);\n entries.set(childPath, file);\n children.push(file);\n }\n }\n children.sort(compareSnapshotsByName);\n const version = await contentVersion(\n 'directory',\n new TextEncoder().encode(\n children\n .map((child) => `${child.kind}\\0${child.name.length}:${child.name}\\0${child.version}`)\n .join('\\n'),\n ),\n operation,\n path,\n );\n const directory = Object.freeze({\n kind: 'directory' as const,\n path,\n name: workspacePathBasename(path),\n size: null,\n version,\n lastModified: newestLastModified(children),\n });\n entries.set(path, directory);\n visiting.delete(path);\n return directory;\n };\n\n const root = await visitDirectory(WORKSPACE_ROOT);\n return { entries, version: root.version };\n }\n\n private async captureFile(\n path: WorkspacePath,\n operation: FsOperation,\n ): Promise<FileSystemSnapshotFile> {\n const legacyPath = workspacePathToLegacy(path);\n let data: ArrayBuffer | null;\n if (this.options.payloadModel === 'binary-authoritative') {\n const binary = await this.invoke(() => this.provider.readBinary(legacyPath), operation, path);\n data = binary ? binary.slice(0) : null;\n } else if (this.options.payloadModel === 'binary-first-text-fallback') {\n const binary = await this.invoke(() => this.provider.readBinary(legacyPath), operation, path);\n if (binary) {\n data = binary.slice(0);\n } else {\n const text = await this.invoke(() => this.provider.readFile(legacyPath), operation, path);\n data = text === null ? null : new TextEncoder().encode(text).buffer;\n }\n } else {\n const binary = await this.invoke(() => this.provider.readBinary(legacyPath), operation, path);\n const text = await this.invoke(() => this.provider.readFile(legacyPath), operation, path);\n if (binary !== null && text !== null) {\n throw this.error(\n 'conflict',\n operation,\n path,\n 'The split legacy store contains both text and binary payloads.',\n );\n }\n data = binary\n ? binary.slice(0)\n : text === null\n ? null\n : new TextEncoder().encode(text).buffer;\n }\n if (!data) {\n throw this.error(\n 'io',\n operation,\n path,\n 'The legacy provider listed a file without a payload.',\n );\n }\n\n const meta = await this.invoke(() => this.provider.stat(legacyPath), operation, path);\n if (\n !meta ||\n parseWorkspacePath(meta.path) !== path ||\n meta.name !== workspacePathBasename(path) ||\n meta.size !== data.byteLength ||\n !Number.isFinite(Date.parse(meta.lastModified))\n ) {\n throw this.error(\n 'io',\n operation,\n path,\n 'The legacy provider returned inconsistent file metadata.',\n );\n }\n return Object.freeze({\n kind: 'file' as const,\n path,\n name: workspacePathBasename(path),\n size: data.byteLength,\n version: await contentVersion('file', new Uint8Array(data), operation, path),\n lastModified: meta.lastModified,\n data,\n });\n }\n\n private async invoke<T>(\n task: () => Promise<T>,\n operation: FsOperation,\n path?: WorkspacePath,\n destinationPath?: WorkspacePath,\n ): Promise<T> {\n try {\n return await task();\n } catch (error: unknown) {\n throw fsErrorFromUnknown(error, { operation, path, destinationPath });\n }\n }\n\n private error(\n code: ConstructorParameters<typeof FsError>[0],\n operation: FsOperation,\n path: WorkspacePath,\n message: string,\n ): FsError {\n return new FsError(code, message, { operation, path });\n }\n}\n\nasync function contentVersion(\n kind: 'file' | 'directory',\n data: Uint8Array,\n operation: FsOperation,\n path: WorkspacePath,\n): Promise<FileSystemVersion> {\n const prefix = new TextEncoder().encode(`${kind}\\0`);\n const input = new Uint8Array(prefix.byteLength + data.byteLength);\n input.set(prefix);\n input.set(data, prefix.byteLength);\n let digest: ArrayBuffer;\n try {\n digest = await globalThis.crypto.subtle.digest('SHA-256', input.buffer as ArrayBuffer);\n } catch (error: unknown) {\n throw fsErrorFromUnknown(error, { operation, path, defaultCode: 'not-supported' });\n }\n const hex = [...new Uint8Array(digest)]\n .map((value) => value.toString(16).padStart(2, '0'))\n .join('');\n return parseFileSystemVersion(`sha256:${hex}`);\n}\n\nfunction isLegacyEntry(value: unknown): value is FileSystemEntry {\n if (!value || typeof value !== 'object') return false;\n const candidate = value as Partial<Record<keyof FileSystemEntry, unknown>>;\n return (\n (candidate.kind === 'file' || candidate.kind === 'directory') &&\n typeof candidate.name === 'string' &&\n typeof candidate.path === 'string'\n );\n}\n\nfunction fileMetadata(file: FileSystemSnapshotFile): FileSystemFileSnapshot {\n return Object.freeze({\n kind: 'file',\n path: file.path,\n name: file.name,\n size: file.size,\n version: file.version,\n lastModified: file.lastModified,\n });\n}\n\nfunction copyDirectorySnapshot(\n directory: FileSystemDirectorySnapshot,\n): FileSystemDirectorySnapshot {\n return Object.freeze({ ...directory });\n}\n\nfunction copyEntrySnapshot(entry: FileSystemSnapshotEntry): FileSystemEntrySnapshot {\n return entry.kind === 'file' ? fileMetadata(entry) : copyDirectorySnapshot(entry);\n}\n\nfunction copySnapshotEntry(entry: FileSystemSnapshotEntry): FileSystemSnapshotEntry {\n return entry.kind === 'file'\n ? Object.freeze({ ...fileMetadata(entry), data: entry.data.slice(0) })\n : copyDirectorySnapshot(entry);\n}\n\nfunction newestLastModified(children: readonly FileSystemSnapshotEntry[]): string {\n let newest = 0;\n for (const child of children) {\n const timestamp = Date.parse(child.lastModified);\n if (Number.isFinite(timestamp)) newest = Math.max(newest, timestamp);\n }\n return newest ? new Date(newest).toISOString() : EPOCH;\n}\n","import { getFileSystemProviderV2, type FileSystemProvider } from './types.js';\nimport {\n describeEntryMove,\n describePartialMove,\n FileSystemMoveRecoveryError,\n FileSystemPartialMoveError,\n} from './move-error.js';\nimport { parseWorkspacePath } from './workspace-path.js';\n\nfunction normalisePath(path: string): string {\n return parseWorkspacePath(path);\n}\n\nfunction dirname(path: string): string {\n const slash = path.lastIndexOf('/');\n return slash < 0 ? '' : path.slice(0, slash);\n}\n\nfunction basename(path: string): string {\n const slash = path.lastIndexOf('/');\n return slash < 0 ? path : path.slice(slash + 1);\n}\n\n/** Return the hidden companion directory used for a document's media and versions. */\nexport function documentCompanionPath(documentPath: string): string {\n const rooted = documentPath.replace(/\\\\/g, '/').startsWith('/');\n const clean = parseWorkspacePath(documentPath);\n if (!clean) throw new Error('The workspace root has no document companion path.');\n const parent = dirname(clean);\n const name = basename(clean).replace(/\\.[^.]+$/, '');\n if (parent) return `${parent}/${name}_files`;\n return rooted ? `/${name}_files` : `${name}_files`;\n}\n\nfunction isMarkdownPath(path: string): boolean {\n return /\\.md$/i.test(basename(path));\n}\n\n/**\n * Move an explorer entry without overwriting an existing entry. Markdown files\n * carry their hidden `<basename>_files` companion directory with them.\n */\nexport async function moveFileSystemEntry(\n provider: FileSystemProvider,\n oldPath: string,\n newPath: string,\n kind: 'file' | 'directory',\n): Promise<void> {\n const providerV2 = getFileSystemProviderV2(provider);\n const exists = (candidate: string): Promise<boolean> =>\n providerV2\n ? providerV2.stat(parseWorkspacePath(candidate)).then((entry) => entry !== null)\n : provider.exists(candidate);\n const move = (source: string, destination: string): Promise<void> =>\n providerV2\n ? providerV2\n .move(parseWorkspacePath(source), parseWorkspacePath(destination), {\n createParents: true,\n })\n .then(() => undefined)\n : provider.rename(source, destination);\n\n const oldNormalised = normalisePath(oldPath);\n const newNormalised = normalisePath(newPath);\n if (oldNormalised === newNormalised) return;\n\n if (kind === 'directory' && newNormalised.startsWith(`${oldNormalised}/`)) {\n throw new Error('A folder cannot be moved into itself.');\n }\n if (await exists(newPath)) {\n throw new Error(`An entry named \"${basename(newPath)}\" already exists there.`);\n }\n\n let oldCompanion: string | null = null;\n let newCompanion: string | null = null;\n if (kind === 'file' && isMarkdownPath(oldPath)) {\n const candidate = documentCompanionPath(oldPath);\n if (await exists(candidate)) {\n oldCompanion = candidate;\n newCompanion = documentCompanionPath(newPath);\n if (\n normalisePath(oldCompanion) !== normalisePath(newCompanion) &&\n (await exists(newCompanion))\n ) {\n throw new Error(`The companion folder \"${basename(newCompanion)}\" already exists there.`);\n }\n }\n }\n\n try {\n await move(oldPath, newPath);\n } catch (error: unknown) {\n const state = await describeEntryMove(provider, oldPath, newPath);\n if (state.source === 'present' && state.destination === 'missing') throw error;\n throw new FileSystemMoveRecoveryError(oldPath, newPath, state, error);\n }\n if (!oldCompanion || !newCompanion) return;\n\n try {\n await move(oldCompanion, newCompanion);\n } catch (error: unknown) {\n // Keep the document and its assets together when the second half fails.\n try {\n await move(newPath, oldPath);\n } catch (rollbackError: unknown) {\n const state = await describePartialMove(\n provider,\n oldPath,\n newPath,\n oldCompanion,\n newCompanion,\n );\n throw new FileSystemPartialMoveError(\n oldPath,\n newPath,\n oldCompanion,\n newCompanion,\n state,\n error,\n rollbackError,\n );\n }\n const state = await describePartialMove(provider, oldPath, newPath, oldCompanion, newCompanion);\n const restoredSourceOnly =\n state.source === 'present' &&\n state.destination === 'missing' &&\n state.companionSource === 'present' &&\n state.companionDestination === 'missing';\n if (!restoredSourceOnly) {\n throw new FileSystemPartialMoveError(\n oldPath,\n newPath,\n oldCompanion,\n newCompanion,\n state,\n error,\n null,\n );\n }\n throw error;\n }\n}\n","import type { ContentContainer } from '@bendyline/squisq/storage';\nimport { documentCompanionPath } from './move-entry.js';\nimport type {\n MemoryFileSystemProvider,\n MemoryFileSystemSnapshot,\n MemoryFileSystemSnapshotFile,\n} from './memory-provider.js';\n\nexport type DbkWorkspaceAssetLayout = 'auto' | 'preserve' | 'companion';\n\nexport interface DbkWorkspaceSnapshotOptions {\n /** Provider-relative path of the transient workspace's active markdown file. */\n targetDocumentPath: string;\n /**\n * `preserve` treats the DBK as a serialized workspace tree. `companion`\n * rebases secondary Markdown files beneath `<document>_files/`. `auto`\n * preserves a DBK whose primary path already matches the target, otherwise\n * rebasing the secondary documents into the companion directory.\n */\n assetLayout?: DbkWorkspaceAssetLayout;\n}\n\nexport interface DbkWorkspaceSnapshot extends MemoryFileSystemSnapshot {\n readonly sourceDocumentPath: string;\n readonly targetDocumentPath: string;\n readonly documentContent: string;\n readonly assetLayout: Exclude<DbkWorkspaceAssetLayout, 'auto'>;\n}\n\nfunction normaliseRelativePath(path: string, label: string): string {\n if (\n path.includes('\\\\') ||\n /^[a-zA-Z]:/u.test(path) ||\n [...path].some((character) => {\n const codePoint = character.codePointAt(0) ?? 0;\n return codePoint <= 0x1f || codePoint === 0x7f;\n })\n ) {\n throw new Error(`DBK ${label} must use a safe forward-slash path: ${path}`);\n }\n const normalized = path.replace(/^\\/+|\\/+$/g, '').replace(/\\/+/g, '/');\n const segments = normalized ? normalized.split('/') : [];\n if (segments.length === 0 || segments.some((segment) => segment === '.' || segment === '..')) {\n throw new Error(`DBK ${label} must not be empty or traverse directories: ${path}`);\n }\n return segments.join('/');\n}\n\nfunction decodeMarkdownFile(data: ArrayBuffer, path: string): string {\n let content: string;\n try {\n content = new TextDecoder('utf-8', { fatal: true }).decode(data);\n } catch {\n throw new Error(`The external DBK contains invalid UTF-8 Markdown: ${path}`);\n }\n if (content.includes('\\0')) {\n throw new Error(`The external DBK contains a NUL character in Markdown: ${path}`);\n }\n return content;\n}\n\nfunction joinPath(parent: string, child: string): string {\n return `${parent.replace(/\\/+$/g, '')}/${child.replace(/^\\/+/, '')}`;\n}\n\n/**\n * Fully materialize and validate a DBK container before touching its target\n * provider. Transient workspace DBKs are intentionally Markdown-only: every\n * member must be a valid UTF-8 `.md` file. A missing, unreadable, binary, or\n * differently typed entry fails the snapshot as a whole.\n */\nexport async function createDbkWorkspaceSnapshot(\n source: ContentContainer,\n options: DbkWorkspaceSnapshotOptions,\n): Promise<DbkWorkspaceSnapshot> {\n const targetDocumentPath = normaliseRelativePath(\n options.targetDocumentPath,\n 'target document path',\n );\n const discoveredDocumentPath = await source.getDocumentPath();\n if (!discoveredDocumentPath)\n throw new Error('The external DBK has no primary markdown document.');\n const sourceDocumentPath = normaliseRelativePath(discoveredDocumentPath, 'primary document path');\n const requestedLayout = options.assetLayout ?? 'auto';\n const assetLayout: Exclude<DbkWorkspaceAssetLayout, 'auto'> =\n requestedLayout === 'auto'\n ? sourceDocumentPath === targetDocumentPath\n ? 'preserve'\n : 'companion'\n : requestedLayout;\n const companionPath = normaliseRelativePath(\n documentCompanionPath(targetDocumentPath),\n 'companion directory path',\n );\n\n const listed = await source.listFiles();\n const entries = [...listed].sort((a, b) => a.path.localeCompare(b.path));\n const seenSourcePaths = new Set<string>();\n const validatedEntries: Array<{ sourcePath: string; containerPath: string }> = [];\n const files: MemoryFileSystemSnapshotFile[] = [];\n let documentContent: string | null = null;\n\n for (const entry of entries) {\n const sourcePath = normaliseRelativePath(entry.path, 'entry path');\n if (seenSourcePaths.has(sourcePath)) {\n throw new Error(`The external DBK contains duplicate paths: ${sourcePath}`);\n }\n seenSourcePaths.add(sourcePath);\n if (!/\\.md$/iu.test(sourcePath)) {\n throw new Error(\n `The external DBK is corrupt: only Markdown (.md) files are allowed (${sourcePath}).`,\n );\n }\n validatedEntries.push({ sourcePath, containerPath: entry.path });\n }\n\n for (const entry of validatedEntries) {\n const { sourcePath } = entry;\n const data = await source.readFile(entry.containerPath);\n if (data === null) {\n throw new Error(`The external DBK changed while reading: ${sourcePath}`);\n }\n const content = decodeMarkdownFile(data, sourcePath);\n if (sourcePath === sourceDocumentPath) {\n documentContent = content;\n files.push({ kind: 'text', path: targetDocumentPath, content: documentContent });\n continue;\n }\n\n const targetPath =\n assetLayout === 'preserve' ? sourcePath : joinPath(companionPath, sourcePath);\n files.push({ kind: 'text', path: targetPath, content });\n }\n\n if (documentContent === null) {\n throw new Error(`The external DBK did not include its primary document: ${sourceDocumentPath}`);\n }\n\n return {\n sourceDocumentPath,\n targetDocumentPath,\n documentContent,\n assetLayout,\n files,\n };\n}\n\n/**\n * Replace a transient DBK workspace as one logical operation.\n *\n * Container reads and validation happen before provider mutation. The memory\n * provider then stages and swaps the full tree synchronously, which removes\n * stale files and guarantees the old tree survives any failed replacement.\n */\nexport async function replaceMemoryWorkspaceFromDbk(\n provider: MemoryFileSystemProvider,\n source: ContentContainer,\n options: DbkWorkspaceSnapshotOptions,\n): Promise<DbkWorkspaceSnapshot> {\n const expectedTreeVersion = provider.treeVersion;\n const snapshot = await createDbkWorkspaceSnapshot(source, options);\n provider.replaceContents(snapshot, expectedTreeVersion);\n return snapshot;\n}\n","/**\n * FileSystemContentContainer — a ContentContainer backed by any\n * FileSystemProvider, scoped to a sub-path (e.g., \".docblocks/media/\").\n *\n * Used by the Electron desktop app so media lives inside the workspace\n * folder (visible as regular files) rather than in a separate IndexedDB\n * origin that only the app can see.\n */\n\nimport type { ContentContainer, ContentEntry } from '@bendyline/squisq/storage';\nimport { findDocumentPath } from '@bendyline/squisq/storage';\nimport { FsError } from './fs-error.js';\nimport { getFileSystemProviderV2, type FileSystemProvider } from './types.js';\nimport { parseWorkspacePath, workspacePathContains, workspacePathJoin } from './workspace-path.js';\nimport { guessMimeType } from './internal/mime.js';\n\nfunction joinPrefix(prefix: string, p: string): string {\n return workspacePathJoin(parseWorkspacePath(prefix), p);\n}\n\nexport class FileSystemContentContainer implements ContentContainer {\n private readonly prefix: string;\n\n constructor(\n private readonly provider: FileSystemProvider,\n prefix = '.docblocks/media',\n ) {\n this.prefix = parseWorkspacePath(prefix);\n }\n\n async readFile(path: string): Promise<ArrayBuffer | null> {\n const full = joinPrefix(this.prefix, path);\n const providerV2 = getFileSystemProviderV2(this.provider);\n if (providerV2) return (await providerV2.readFile(parseWorkspacePath(full)))?.data ?? null;\n const binary = await this.provider.readBinary(full);\n if (binary) return binary;\n // IndexedDB-backed workspaces store text via `writeFile(string)` and\n // binary via `writeBinary(ArrayBuffer)` under separate keys, so a\n // markdown file written through the text API is invisible to\n // `readBinary`. Fall back to text-then-UTF-8 so consumers like the\n // recursive HTML export can resolve sibling `.md` links uniformly\n // across browser and native workspaces.\n const text = await this.provider.readFile(full);\n if (text === null) return null;\n return new TextEncoder().encode(text).buffer as ArrayBuffer;\n }\n\n async writeFile(path: string, data: ArrayBuffer | Uint8Array, _mimeType?: string): Promise<void> {\n const full = joinPrefix(this.prefix, path);\n const providerV2 = getFileSystemProviderV2(this.provider);\n if (providerV2) {\n await providerV2.writeFile(parseWorkspacePath(full), data, {\n mode: 'upsert',\n createParents: true,\n });\n return;\n }\n await this.provider.writeBinary(full, data);\n }\n\n async removeFile(path: string): Promise<void> {\n const full = joinPrefix(this.prefix, path);\n const providerV2 = getFileSystemProviderV2(this.provider);\n if (providerV2) {\n await providerV2.remove(parseWorkspacePath(full), { missing: 'ignore' });\n return;\n }\n await this.provider.delete(full);\n }\n\n async listFiles(prefix?: string): Promise<ContentEntry[]> {\n const entries: ContentEntry[] = [];\n const providerV2 = getFileSystemProviderV2(this.provider);\n const root = parseWorkspacePath(this.prefix);\n type ListedEntry = {\n readonly kind: 'file' | 'directory';\n readonly path: string;\n readonly size?: number | null;\n };\n const walk = async (dir: string) => {\n let children: readonly ListedEntry[];\n try {\n children = providerV2\n ? await providerV2.readDirectory(parseWorkspacePath(dir))\n : await this.provider.readDirectory(dir);\n } catch (error: unknown) {\n // An absent container root means an empty container. Every other\n // storage fault (including a subtree disappearing mid-snapshot)\n // remains observable to backup/export callers.\n if (dir === root && error instanceof FsError && error.code === 'not-found') return;\n throw error;\n }\n for (const child of children) {\n if (child.kind === 'directory') {\n await walk(child.path);\n } else {\n const childPath = parseWorkspacePath(child.path);\n const prefixPath = parseWorkspacePath(this.prefix);\n if (!workspacePathContains(prefixPath, childPath)) continue;\n const rel = childPath === prefixPath ? '' : childPath.slice(prefixPath.length + 1);\n if (prefix && !rel.startsWith(prefix)) continue;\n const size = child.size ?? (await this.provider.stat(child.path))?.size ?? 0;\n entries.push({\n path: rel,\n mimeType: guessMimeType(rel),\n size,\n });\n }\n }\n };\n await walk(root);\n return entries;\n }\n\n async exists(path: string): Promise<boolean> {\n const full = joinPrefix(this.prefix, path);\n const providerV2 = getFileSystemProviderV2(this.provider);\n return providerV2\n ? (await providerV2.stat(parseWorkspacePath(full))) !== null\n : this.provider.exists(full);\n }\n\n async getDocumentPath(): Promise<string | null> {\n return findDocumentPath(await this.listFiles());\n }\n\n async readDocument(): Promise<string | null> {\n const docPath = await this.getDocumentPath();\n if (!docPath) return null;\n const data = await this.readFile(docPath);\n if (!data) return null;\n return new TextDecoder().decode(data);\n }\n\n async writeDocument(markdown: string, filename?: string): Promise<void> {\n const name = filename ?? 'index.md';\n const data = new TextEncoder().encode(markdown);\n await this.writeFile(name, data, 'text/markdown');\n }\n}\n","/**\n * createFileMediaProvider — per-file media storage following the pandoc /\n * Word convention: a markdown file `notes.md` gets a sibling folder\n * `notes_files/` that holds its images, audio, and video.\n *\n * Given:\n * • `container` — a ContentContainer scoped to the markdown file's\n * parent directory (so `readFile('notes_files/image.png')` maps to the\n * parent-relative path)\n * • `markdownBasename` — e.g. `\"notes.md\"`\n *\n * Returns a MediaProvider that:\n * • Writes new media under `{basename}_files/{name}` in the parent dir\n * • Returns the folder-qualified path (`notes_files/image.png`) from\n * addMedia so the markdown stays portable outside DocBlocks\n * • Resolves both bare (`image.png`) and folder-qualified\n * (`notes_files/image.png`) references — so legacy markdown and\n * exports from other tools both work\n */\n\nimport type { MediaProvider, MediaEntry } from '@bendyline/squisq/schemas';\nimport type { ContentContainer } from '@bendyline/squisq/storage';\n\nfunction stripExt(name: string): string {\n return name.replace(/\\.[^.]+$/, '');\n}\n\nexport function createFileMediaProvider(\n container: ContentContainer,\n markdownBasename: string,\n): MediaProvider {\n const folder = stripExt(markdownBasename) + '_files';\n const prefix = folder + '/';\n const blobUrlCache = new Map<string, string>();\n\n function toKey(ref: string): string {\n const clean = ref.replace(/^\\/+/, '');\n return clean.startsWith(prefix) ? clean : prefix + clean;\n }\n\n return {\n async resolveUrl(ref: string): Promise<string> {\n const key = toKey(ref);\n const cached = blobUrlCache.get(key);\n if (cached) return cached;\n\n const data = await container.readFile(key);\n if (!data) return ref;\n\n const entries = await container.listFiles();\n const entry = entries.find((e) => e.path === key);\n const mimeType = entry?.mimeType ?? 'application/octet-stream';\n\n const url = URL.createObjectURL(new Blob([data], { type: mimeType }));\n blobUrlCache.set(key, url);\n return url;\n },\n\n async listMedia(): Promise<MediaEntry[]> {\n const entries = await container.listFiles(prefix);\n return entries\n .filter((e) => !e.path.toLowerCase().endsWith('.md'))\n .map((e) => ({\n name: e.path,\n mimeType: e.mimeType,\n size: e.size,\n }));\n },\n\n async addMedia(\n name: string,\n data: ArrayBuffer | Blob | Uint8Array,\n mimeType: string,\n ): Promise<string> {\n const key = toKey(name);\n const cached = blobUrlCache.get(key);\n if (cached) {\n URL.revokeObjectURL(cached);\n blobUrlCache.delete(key);\n }\n const buffer = data instanceof Blob ? new Uint8Array(await data.arrayBuffer()) : data;\n await container.writeFile(key, buffer, mimeType);\n return key;\n },\n\n async removeMedia(ref: string): Promise<void> {\n const key = toKey(ref);\n const cached = blobUrlCache.get(key);\n if (cached) {\n URL.revokeObjectURL(cached);\n blobUrlCache.delete(key);\n }\n await container.removeFile(key);\n },\n\n dispose(): void {\n for (const url of blobUrlCache.values()) {\n URL.revokeObjectURL(url);\n }\n blobUrlCache.clear();\n },\n };\n}\n"],"mappings":"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","names":["state"]}
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import { q as FileSystemProvider } from '../types-BEg5SQ1_.js';
|
|
2
|
+
import '../workspace-path-CWVrcuPL.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Synchronous crash-recovery journal for dirty document snapshots.
|
|
6
|
+
*
|
|
7
|
+
* The journal deliberately depends on a tiny injected Storage-like contract
|
|
8
|
+
* instead of reading `window.localStorage` at module load time. This keeps the
|
|
9
|
+
* document package usable in Node, Electron main, VS Code extension hosts, and
|
|
10
|
+
* tests while allowing browser renderers to use localStorage for a best-effort
|
|
11
|
+
* write that completes before the current JavaScript turn ends.
|
|
12
|
+
*/
|
|
13
|
+
declare const DOCUMENT_RECOVERY_JOURNAL_STORAGE_KEY = "docblocks:document-recovery:v1";
|
|
14
|
+
declare const DOCUMENT_RECOVERY_JOURNAL_SCHEMA_VERSION = 1;
|
|
15
|
+
interface DocumentRecoveryStorage {
|
|
16
|
+
getItem(key: string): string | null;
|
|
17
|
+
setItem(key: string, value: string): void;
|
|
18
|
+
removeItem(key: string): void;
|
|
19
|
+
}
|
|
20
|
+
interface DocumentRecoveryRecord {
|
|
21
|
+
/** Stable commit-target key, including the workspace/provider scope. */
|
|
22
|
+
targetKey: string;
|
|
23
|
+
/** DocumentSession generation that produced this snapshot. */
|
|
24
|
+
generation: number;
|
|
25
|
+
/** Monotonic DocumentSession revision represented by `content`. */
|
|
26
|
+
revision: number;
|
|
27
|
+
/** Complete markdown snapshot. */
|
|
28
|
+
content: string;
|
|
29
|
+
/**
|
|
30
|
+
* Content last acknowledged by the commit target when this draft was made.
|
|
31
|
+
* Recovery may be applied automatically only when storage still matches this
|
|
32
|
+
* baseline; otherwise the caller must surface an external-change conflict.
|
|
33
|
+
*/
|
|
34
|
+
persistedContent: string | null;
|
|
35
|
+
/** Time the dirty record for this target was first created. */
|
|
36
|
+
createdAt: number;
|
|
37
|
+
/** Time the record was most recently replaced. */
|
|
38
|
+
updatedAt: number;
|
|
39
|
+
}
|
|
40
|
+
interface DocumentRecoveryWrite {
|
|
41
|
+
targetKey: string;
|
|
42
|
+
generation: number;
|
|
43
|
+
revision: number;
|
|
44
|
+
content: string;
|
|
45
|
+
persistedContent: string | null;
|
|
46
|
+
}
|
|
47
|
+
interface DocumentRecoveryAcknowledgement {
|
|
48
|
+
targetKey: string;
|
|
49
|
+
generation: number;
|
|
50
|
+
/** Highest revision durably acknowledged by the commit target. */
|
|
51
|
+
persistedRevision: number;
|
|
52
|
+
}
|
|
53
|
+
type DocumentRecoveryWriteFailure = 'invalid-record' | 'record-too-large' | 'storage-unavailable' | 'quota-exceeded';
|
|
54
|
+
type DocumentRecoveryWriteResult = {
|
|
55
|
+
status: 'stored';
|
|
56
|
+
evicted: number;
|
|
57
|
+
} | {
|
|
58
|
+
status: 'unchanged';
|
|
59
|
+
evicted: 0;
|
|
60
|
+
} | {
|
|
61
|
+
status: 'ignored-stale';
|
|
62
|
+
evicted: 0;
|
|
63
|
+
} | {
|
|
64
|
+
status: 'rejected';
|
|
65
|
+
reason: DocumentRecoveryWriteFailure;
|
|
66
|
+
evicted: number;
|
|
67
|
+
};
|
|
68
|
+
interface DocumentRecoveryJournalOptions {
|
|
69
|
+
storageKey?: string;
|
|
70
|
+
/** Maximum number of document records retained. Defaults to 20. */
|
|
71
|
+
maxEntries?: number;
|
|
72
|
+
/** Conservative UTF-16 estimate for the whole serialized journal. */
|
|
73
|
+
maxStorageBytes?: number;
|
|
74
|
+
/** Conservative UTF-16 estimate for one serialized record. */
|
|
75
|
+
maxRecordBytes?: number;
|
|
76
|
+
/** Records older than this are discarded while reading. Defaults to 7 days. */
|
|
77
|
+
maxAgeMs?: number;
|
|
78
|
+
/** Tolerated clock skew for records dated in the future. Defaults to 5 minutes. */
|
|
79
|
+
maxFutureSkewMs?: number;
|
|
80
|
+
/** Injected for deterministic tests. */
|
|
81
|
+
now?: () => number;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Best-effort, synchronous recovery storage.
|
|
85
|
+
*
|
|
86
|
+
* Normal save acknowledgement is the only automatic path that removes the
|
|
87
|
+
* current record. Explicit discard, age expiry, corruption repair, and bounded
|
|
88
|
+
* eviction are intentional exceptions: callers can discard after the user
|
|
89
|
+
* rejects recovery, and the journal must never grow without limit.
|
|
90
|
+
*/
|
|
91
|
+
declare class DocumentRecoveryJournal {
|
|
92
|
+
private readonly storage;
|
|
93
|
+
private readonly storageKey;
|
|
94
|
+
private readonly maxEntries;
|
|
95
|
+
private readonly maxStorageBytes;
|
|
96
|
+
private readonly maxRecordBytes;
|
|
97
|
+
private readonly maxAgeMs;
|
|
98
|
+
private readonly maxFutureSkewMs;
|
|
99
|
+
private readonly now;
|
|
100
|
+
constructor(storage: DocumentRecoveryStorage | null, options?: DocumentRecoveryJournalOptions);
|
|
101
|
+
/**
|
|
102
|
+
* Synchronously persist the latest dirty snapshot for a target.
|
|
103
|
+
* Storage/quota failures are returned, never thrown into an editor onChange.
|
|
104
|
+
*/
|
|
105
|
+
write(input: DocumentRecoveryWrite): DocumentRecoveryWriteResult;
|
|
106
|
+
/** Return the recoverable snapshot for one target, if present and valid. */
|
|
107
|
+
lookup(targetKey: string, generation?: number): DocumentRecoveryRecord | null;
|
|
108
|
+
/** List valid records, newest first. Optionally restrict to one target. */
|
|
109
|
+
list(targetKey?: string): DocumentRecoveryRecord[];
|
|
110
|
+
/**
|
|
111
|
+
* Clear a record only when the same generation has durably acknowledged at
|
|
112
|
+
* least the journaled revision. A stale acknowledgement cannot erase a newer
|
|
113
|
+
* crash-recovery snapshot.
|
|
114
|
+
*/
|
|
115
|
+
acknowledge(input: DocumentRecoveryAcknowledgement): boolean;
|
|
116
|
+
/** Explicitly discard recovery data after a user or lifecycle decision. */
|
|
117
|
+
discard(targetKey: string, generation?: number): boolean;
|
|
118
|
+
private load;
|
|
119
|
+
private persistBounded;
|
|
120
|
+
private persistExact;
|
|
121
|
+
private tryRemove;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Resolve browser localStorage on demand. Importing this module never touches
|
|
125
|
+
* browser globals, and access errors (sandboxing/security settings) yield null.
|
|
126
|
+
*/
|
|
127
|
+
declare function getDefaultDocumentRecoveryStorage(): DocumentRecoveryStorage | null;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Framework-neutral document persistence contracts.
|
|
131
|
+
*
|
|
132
|
+
* A DocumentSession owns one logical document at a time. Storage-specific
|
|
133
|
+
* adapters implement DocumentCommitTarget; the session owns revisions,
|
|
134
|
+
* serialization, lifecycle transitions, and conflict state.
|
|
135
|
+
*/
|
|
136
|
+
|
|
137
|
+
type DocumentSaveReason = 'autosave' | 'manual' | 'transition' | 'close' | 'backup' | 'conflict';
|
|
138
|
+
type DocumentExternalVersion = string | number | null;
|
|
139
|
+
interface DocumentCommitRequest {
|
|
140
|
+
/** Stable key for the target this commit was created for. */
|
|
141
|
+
targetKey: string;
|
|
142
|
+
/** Latest complete document snapshot to persist. */
|
|
143
|
+
content: string;
|
|
144
|
+
/** Monotonic session revision represented by content. */
|
|
145
|
+
revision: number;
|
|
146
|
+
/** Most recent revision acknowledged by this target. */
|
|
147
|
+
persistedRevision: number;
|
|
148
|
+
/** Content last acknowledged by the target, or null if it did not exist. */
|
|
149
|
+
persistedContent: string | null;
|
|
150
|
+
reason: DocumentSaveReason;
|
|
151
|
+
}
|
|
152
|
+
interface DocumentCommitResult {
|
|
153
|
+
/** Optional backend version (mtime, TextDocument.version, etag, and so on). */
|
|
154
|
+
version?: DocumentExternalVersion;
|
|
155
|
+
}
|
|
156
|
+
interface DocumentCommitTarget {
|
|
157
|
+
readonly key: string;
|
|
158
|
+
commit(request: DocumentCommitRequest): Promise<DocumentCommitResult | void>;
|
|
159
|
+
}
|
|
160
|
+
type DocumentSessionStatus = 'idle' | 'saved' | 'dirty' | 'saving' | 'error' | 'conflict' | 'closed';
|
|
161
|
+
type DocumentSessionLifecycle = 'open' | 'transitioning' | 'closing' | 'closed';
|
|
162
|
+
interface DocumentExternalSnapshot {
|
|
163
|
+
/** Target key captured before the external read began. */
|
|
164
|
+
targetKey: string;
|
|
165
|
+
/** Monotonic observation number assigned by the target watcher. */
|
|
166
|
+
sequence?: number;
|
|
167
|
+
/** Null represents an externally deleted document. */
|
|
168
|
+
content: string | null;
|
|
169
|
+
version?: DocumentExternalVersion;
|
|
170
|
+
}
|
|
171
|
+
interface DocumentSessionConflict {
|
|
172
|
+
targetKey: string;
|
|
173
|
+
localContent: string;
|
|
174
|
+
localRevision: number;
|
|
175
|
+
externalContent: string | null;
|
|
176
|
+
externalVersion: DocumentExternalVersion;
|
|
177
|
+
}
|
|
178
|
+
interface DocumentSessionSnapshot {
|
|
179
|
+
targetKey: string | null;
|
|
180
|
+
content: string;
|
|
181
|
+
revision: number;
|
|
182
|
+
persistedRevision: number;
|
|
183
|
+
persistedContent: string | null;
|
|
184
|
+
savingRevision: number | null;
|
|
185
|
+
generation: number;
|
|
186
|
+
status: DocumentSessionStatus;
|
|
187
|
+
lifecycle: DocumentSessionLifecycle;
|
|
188
|
+
frozen: boolean;
|
|
189
|
+
error: Error | null;
|
|
190
|
+
conflict: DocumentSessionConflict | null;
|
|
191
|
+
}
|
|
192
|
+
interface DocumentSessionOptions {
|
|
193
|
+
autoSaveDelayMs?: number;
|
|
194
|
+
/** Whether edits schedule automatic persistence. Manual and lifecycle flushes remain available. */
|
|
195
|
+
autoSaveEnabled?: boolean;
|
|
196
|
+
/**
|
|
197
|
+
* Bounded delays used after an automatic save fails. Each entry permits
|
|
198
|
+
* one retry; exhausting the list leaves the session in error state until
|
|
199
|
+
* the user edits again or explicitly flushes it. Conflicts never retry.
|
|
200
|
+
*/
|
|
201
|
+
autoSaveRetryDelaysMs?: readonly number[];
|
|
202
|
+
/** Optional synchronous crash-recovery journal owned by this session. */
|
|
203
|
+
recoveryJournal?: DocumentRecoveryJournal | null;
|
|
204
|
+
}
|
|
205
|
+
/** Scope captured by an editor instance when it mounts. */
|
|
206
|
+
interface DocumentSessionEditScope {
|
|
207
|
+
targetKey: string;
|
|
208
|
+
generation: number;
|
|
209
|
+
}
|
|
210
|
+
/** Result produced while a session transition is frozen. */
|
|
211
|
+
interface DocumentSessionTransition {
|
|
212
|
+
target: DocumentCommitTarget | null;
|
|
213
|
+
content: string;
|
|
214
|
+
}
|
|
215
|
+
type DocumentExternalChangeResult = 'applied' | 'conflict' | 'ignored';
|
|
216
|
+
type DocumentConflictStrategy = 'use-local' | 'use-external';
|
|
217
|
+
|
|
218
|
+
type SessionListener = () => void;
|
|
219
|
+
/**
|
|
220
|
+
* Raised by a commit target when optimistic external-change verification
|
|
221
|
+
* fails. The session converts it into durable conflict state.
|
|
222
|
+
*/
|
|
223
|
+
declare class DocumentCommitConflictError extends Error {
|
|
224
|
+
readonly externalContent: string | null;
|
|
225
|
+
readonly externalVersion: string | number | null;
|
|
226
|
+
constructor(message: string, externalContent: string | null, externalVersion?: string | number | null);
|
|
227
|
+
}
|
|
228
|
+
declare class DocumentSessionConflictError extends Error {
|
|
229
|
+
readonly conflict: DocumentSessionConflict;
|
|
230
|
+
constructor(conflict: DocumentSessionConflict);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* A revisioned, serialized persistence boundary for one active document.
|
|
234
|
+
*
|
|
235
|
+
* Invariants:
|
|
236
|
+
* - only drain() calls target.commit();
|
|
237
|
+
* - at most one commit is in flight;
|
|
238
|
+
* - revisions never decrease, including across target transitions;
|
|
239
|
+
* - destructive operations wait for an in-flight commit and run last;
|
|
240
|
+
* - a target is never changed by a React effect cleanup.
|
|
241
|
+
*/
|
|
242
|
+
declare class DocumentSession {
|
|
243
|
+
private readonly autoSaveDelayMs;
|
|
244
|
+
private readonly autoSaveRetryDelaysMs;
|
|
245
|
+
private readonly recoveryJournal;
|
|
246
|
+
private readonly listeners;
|
|
247
|
+
private autoSaveEnabled;
|
|
248
|
+
private target;
|
|
249
|
+
private content;
|
|
250
|
+
private persistedContent;
|
|
251
|
+
private revision;
|
|
252
|
+
private persistedRevision;
|
|
253
|
+
private savingRevision;
|
|
254
|
+
private savingContent;
|
|
255
|
+
private generation;
|
|
256
|
+
private externalSequence;
|
|
257
|
+
private lifecycle;
|
|
258
|
+
private frozen;
|
|
259
|
+
private error;
|
|
260
|
+
private conflict;
|
|
261
|
+
private autoSaveTimer;
|
|
262
|
+
private autoSaveRetryAttempt;
|
|
263
|
+
private drainPromise;
|
|
264
|
+
private haltDrain;
|
|
265
|
+
private operationTail;
|
|
266
|
+
private snapshot;
|
|
267
|
+
constructor(options?: DocumentSessionOptions);
|
|
268
|
+
readonly subscribe: (listener: SessionListener) => (() => void);
|
|
269
|
+
readonly getSnapshot: () => DocumentSessionSnapshot;
|
|
270
|
+
/** Enable or disable automatic persistence without weakening explicit or lifecycle flushes. */
|
|
271
|
+
setAutoSaveEnabled(enabled: boolean): void;
|
|
272
|
+
/**
|
|
273
|
+
* Record a complete local snapshot and schedule its persistence.
|
|
274
|
+
* Returns the assigned monotonic revision.
|
|
275
|
+
*/
|
|
276
|
+
edit(content: string, scope: DocumentSessionEditScope): number;
|
|
277
|
+
/**
|
|
278
|
+
* Persist the revision current when flush() is called. A later edit may
|
|
279
|
+
* advance the session again, but commits remain strictly serialized.
|
|
280
|
+
*/
|
|
281
|
+
flush(reason?: DocumentSaveReason): Promise<DocumentSessionSnapshot>;
|
|
282
|
+
/**
|
|
283
|
+
* Flush the old document, then replace it with a new clean baseline.
|
|
284
|
+
* UI state should change only after this promise resolves.
|
|
285
|
+
*/
|
|
286
|
+
transitionTo(target: DocumentCommitTarget | null, content: string): Promise<DocumentSessionSnapshot>;
|
|
287
|
+
/**
|
|
288
|
+
* Freeze and flush the current document before reading the next one. The
|
|
289
|
+
* loader may return null when a navigation request was superseded, leaving
|
|
290
|
+
* the current target active and clean.
|
|
291
|
+
*/
|
|
292
|
+
transitionWithLoad(load: () => Promise<DocumentSessionTransition | null>): Promise<DocumentSessionSnapshot | null>;
|
|
293
|
+
/**
|
|
294
|
+
* Flush the current path, run the storage move, and only then swap the
|
|
295
|
+
* commit target. No edit can enter between those steps.
|
|
296
|
+
*/
|
|
297
|
+
retarget(nextTarget: DocumentCommitTarget, moveStorage: () => Promise<void>): Promise<DocumentSessionSnapshot>;
|
|
298
|
+
/**
|
|
299
|
+
* Cancel queued writes, wait for an already-running write, then delete.
|
|
300
|
+
* The deletion is therefore the final storage operation for this target.
|
|
301
|
+
*/
|
|
302
|
+
delete(deleteStorage: () => Promise<void>): Promise<DocumentSessionSnapshot>;
|
|
303
|
+
/**
|
|
304
|
+
* Discard queued changes and detach without mutating storage. This is used
|
|
305
|
+
* for explicitly abandoned sessions, never as an implicit effect cleanup.
|
|
306
|
+
*/
|
|
307
|
+
cancel(): Promise<DocumentSessionSnapshot>;
|
|
308
|
+
/**
|
|
309
|
+
* Observe a filesystem/host change captured for targetKey. Clean sessions
|
|
310
|
+
* adopt it. Dirty or saving sessions preserve local text and enter conflict.
|
|
311
|
+
*/
|
|
312
|
+
observeExternal(change: DocumentExternalSnapshot): DocumentExternalChangeResult;
|
|
313
|
+
resolveConflict(strategy: DocumentConflictStrategy): Promise<DocumentSessionSnapshot>;
|
|
314
|
+
/**
|
|
315
|
+
* Freeze edits and flush through the latest revision. A successful call
|
|
316
|
+
* remains frozen until cancelClose(); the owning host may now destroy it.
|
|
317
|
+
*/
|
|
318
|
+
prepareClose(): Promise<DocumentSessionSnapshot>;
|
|
319
|
+
/** Resume editing when a host cancels a prepared close. */
|
|
320
|
+
cancelClose(): void;
|
|
321
|
+
private performTransition;
|
|
322
|
+
private scheduleAutoSave;
|
|
323
|
+
private clearAutoSaveTimer;
|
|
324
|
+
private ensureDrain;
|
|
325
|
+
private drain;
|
|
326
|
+
private awaitActiveDrain;
|
|
327
|
+
/**
|
|
328
|
+
* Rehydrate a synchronous crash snapshot after the durable baseline has
|
|
329
|
+
* been read. A matching baseline is safe to resume as dirty; a changed
|
|
330
|
+
* baseline becomes an explicit conflict and is never auto-overwritten.
|
|
331
|
+
*/
|
|
332
|
+
private restoreRecoverySnapshot;
|
|
333
|
+
private writeRecoverySnapshot;
|
|
334
|
+
private discardRecoverySnapshot;
|
|
335
|
+
private detach;
|
|
336
|
+
private assertNotPreparingClose;
|
|
337
|
+
private enqueueOperation;
|
|
338
|
+
private createSnapshot;
|
|
339
|
+
private computeStatus;
|
|
340
|
+
private emit;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
interface FileSystemDocumentTargetOptions {
|
|
344
|
+
/**
|
|
345
|
+
* Compare the current file with the session's persisted baseline before
|
|
346
|
+
* replacing it. Enabled by default.
|
|
347
|
+
*/
|
|
348
|
+
verifyExternalChanges?: boolean;
|
|
349
|
+
onCommitted?: (content: string, revision: number) => void;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Adapt a FileSystemProvider path to the commit protocol used by
|
|
353
|
+
* DocumentSession. The optimistic read catches external edits/deletions
|
|
354
|
+
* before a local write recreates or silently replaces them.
|
|
355
|
+
*/
|
|
356
|
+
declare function createFileSystemDocumentTarget(provider: FileSystemProvider, path: string, options?: FileSystemDocumentTargetOptions): DocumentCommitTarget;
|
|
357
|
+
|
|
358
|
+
export { DOCUMENT_RECOVERY_JOURNAL_SCHEMA_VERSION, DOCUMENT_RECOVERY_JOURNAL_STORAGE_KEY, DocumentCommitConflictError, type DocumentCommitRequest, type DocumentCommitResult, type DocumentCommitTarget, type DocumentConflictStrategy, type DocumentExternalChangeResult, type DocumentExternalSnapshot, type DocumentExternalVersion, type DocumentRecoveryAcknowledgement, DocumentRecoveryJournal, type DocumentRecoveryJournalOptions, type DocumentRecoveryRecord, type DocumentRecoveryStorage, type DocumentRecoveryWrite, type DocumentRecoveryWriteFailure, type DocumentRecoveryWriteResult, type DocumentSaveReason, DocumentSession, type DocumentSessionConflict, DocumentSessionConflictError, type DocumentSessionEditScope, type DocumentSessionLifecycle, type DocumentSessionOptions, type DocumentSessionSnapshot, type DocumentSessionStatus, type DocumentSessionTransition, type FileSystemDocumentTargetOptions, createFileSystemDocumentTarget, getDefaultDocumentRecoveryStorage };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DOCUMENT_RECOVERY_JOURNAL_SCHEMA_VERSION,
|
|
3
|
+
DOCUMENT_RECOVERY_JOURNAL_STORAGE_KEY,
|
|
4
|
+
DocumentCommitConflictError,
|
|
5
|
+
DocumentRecoveryJournal,
|
|
6
|
+
DocumentSession,
|
|
7
|
+
DocumentSessionConflictError,
|
|
8
|
+
createFileSystemDocumentTarget,
|
|
9
|
+
getDefaultDocumentRecoveryStorage
|
|
10
|
+
} from "../chunk-COYQXQK3.js";
|
|
11
|
+
import "../chunk-MNSZ7EZN.js";
|
|
12
|
+
import "../chunk-FA7UNOXK.js";
|
|
13
|
+
import "../chunk-JS6XFWQK.js";
|
|
14
|
+
import "../chunk-EZKJZUNJ.js";
|
|
15
|
+
export {
|
|
16
|
+
DOCUMENT_RECOVERY_JOURNAL_SCHEMA_VERSION,
|
|
17
|
+
DOCUMENT_RECOVERY_JOURNAL_STORAGE_KEY,
|
|
18
|
+
DocumentCommitConflictError,
|
|
19
|
+
DocumentRecoveryJournal,
|
|
20
|
+
DocumentSession,
|
|
21
|
+
DocumentSessionConflictError,
|
|
22
|
+
createFileSystemDocumentTarget,
|
|
23
|
+
getDefaultDocumentRecoveryStorage
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { s as FileSystemProviderV2, r as FileSystemProviderCapabilities, k as FileSystemEntrySnapshot, m as FileSystemFileRead, K as FileSystemWriteOptions, n as FileSystemFileSnapshot, g as FileSystemCreateDirectoryOptions, h as FileSystemDirectorySnapshot, u as FileSystemRemoveOptions, v as FileSystemRemoveResult, o as FileSystemMoveOptions, w as FileSystemSnapshot, C as FileSystemWatchEvent, H as FileSystemWatchOptions, I as FileSystemWatchSubscription, q as FileSystemProvider, F as FileCommitResult, j as FileSystemEntry, b as FileMeta } from '../types-BEg5SQ1_.js';
|
|
2
|
+
import { a as WorkspacePath } from '../workspace-path-CWVrcuPL.js';
|
|
3
|
+
export { isElectronHost } from '../host/index.js';
|
|
4
|
+
import '../types-CueK0tvU.js';
|
|
5
|
+
|
|
6
|
+
/** Pure renderer-side client for the typed Electron filesystem v2 transport. */
|
|
7
|
+
declare class ElectronFileSystemProviderV2 implements FileSystemProviderV2 {
|
|
8
|
+
readonly id: string;
|
|
9
|
+
readonly label: string;
|
|
10
|
+
readonly capabilities: FileSystemProviderCapabilities;
|
|
11
|
+
private readonly rootPath;
|
|
12
|
+
private readonly instanceId;
|
|
13
|
+
private readonly watchers;
|
|
14
|
+
private readonly subscriptions;
|
|
15
|
+
private readonly inFlight;
|
|
16
|
+
private openPromise;
|
|
17
|
+
private removeWatchBridge;
|
|
18
|
+
private disposePromise;
|
|
19
|
+
private hostOpened;
|
|
20
|
+
private disposed;
|
|
21
|
+
constructor(id: string, label: string, rootPath: string);
|
|
22
|
+
getRootPath(): string;
|
|
23
|
+
stat(path: WorkspacePath): Promise<FileSystemEntrySnapshot | null>;
|
|
24
|
+
readFile(path: WorkspacePath): Promise<FileSystemFileRead | null>;
|
|
25
|
+
readDirectory(path: WorkspacePath): Promise<readonly FileSystemEntrySnapshot[]>;
|
|
26
|
+
writeFile(path: WorkspacePath, data: ArrayBuffer | Uint8Array, options?: FileSystemWriteOptions): Promise<FileSystemFileSnapshot>;
|
|
27
|
+
createDirectory(path: WorkspacePath, options?: FileSystemCreateDirectoryOptions): Promise<FileSystemDirectorySnapshot>;
|
|
28
|
+
remove(path: WorkspacePath, options?: FileSystemRemoveOptions): Promise<FileSystemRemoveResult>;
|
|
29
|
+
move(oldPath: WorkspacePath, newPath: WorkspacePath, options?: FileSystemMoveOptions): Promise<FileSystemEntrySnapshot>;
|
|
30
|
+
snapshot(): Promise<FileSystemSnapshot>;
|
|
31
|
+
watch(listener: (event: FileSystemWatchEvent) => void, options?: FileSystemWatchOptions): FileSystemWatchSubscription;
|
|
32
|
+
dispose(): Promise<void>;
|
|
33
|
+
private request;
|
|
34
|
+
private ensureOpen;
|
|
35
|
+
private ensureWatchBridge;
|
|
36
|
+
private handleWatchMessage;
|
|
37
|
+
private assertOpen;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* ElectronFileSystemProvider — implements FileSystemProvider by delegating
|
|
42
|
+
* to the Electron desktop host's fs IPC bridge. Every operation is scoped
|
|
43
|
+
* to an opaque workspace id that the main process resolves against its
|
|
44
|
+
* registered workspace authority.
|
|
45
|
+
*
|
|
46
|
+
* This file has no Electron dependency — it is a pure IPC client that
|
|
47
|
+
* relies on the `docBlocksHost` global installed by the preload script.
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
declare class ElectronFileSystemProvider implements FileSystemProvider {
|
|
51
|
+
readonly id: string;
|
|
52
|
+
readonly label: string;
|
|
53
|
+
readonly v2: ElectronFileSystemProviderV2;
|
|
54
|
+
private readonly rootPath;
|
|
55
|
+
constructor(id: string, label: string, rootPath: string);
|
|
56
|
+
/** Absolute path this provider is rooted at. */
|
|
57
|
+
getRootPath(): string;
|
|
58
|
+
readFile(path: string): Promise<string | null>;
|
|
59
|
+
writeFile(path: string, content: string): Promise<void>;
|
|
60
|
+
commitFile(path: string, content: string, expectedContent: string | null): Promise<FileCommitResult>;
|
|
61
|
+
delete(path: string): Promise<void>;
|
|
62
|
+
rename(oldPath: string, newPath: string): Promise<void>;
|
|
63
|
+
readDirectory(path: string): Promise<FileSystemEntry[]>;
|
|
64
|
+
exists(path: string): Promise<boolean>;
|
|
65
|
+
createDirectory(path: string): Promise<void>;
|
|
66
|
+
stat(path: string): Promise<FileMeta | null>;
|
|
67
|
+
readBinary(path: string): Promise<ArrayBuffer | null>;
|
|
68
|
+
writeBinary(path: string, data: ArrayBuffer | Uint8Array): Promise<void>;
|
|
69
|
+
/** Subscribe to external change notifications under this root. */
|
|
70
|
+
watch(onChange: (changedPath: string) => void): () => void;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export { ElectronFileSystemProvider, ElectronFileSystemProviderV2 };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ElectronFileSystemProvider,
|
|
3
|
+
ElectronFileSystemProviderV2
|
|
4
|
+
} from "../chunk-VTCSF7VS.js";
|
|
5
|
+
import {
|
|
6
|
+
isElectronHost
|
|
7
|
+
} from "../chunk-BNKV7MTO.js";
|
|
8
|
+
import "../chunk-FNW556FN.js";
|
|
9
|
+
import "../chunk-U722UUFN.js";
|
|
10
|
+
import "../chunk-P4WATND4.js";
|
|
11
|
+
import "../chunk-JS6XFWQK.js";
|
|
12
|
+
export {
|
|
13
|
+
ElectronFileSystemProvider,
|
|
14
|
+
ElectronFileSystemProviderV2,
|
|
15
|
+
isElectronHost
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=electron.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|