@bendyline/docblocks 0.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.
Files changed (52) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +49 -0
  3. package/dist/chunk-GUNM43XZ.js +63 -0
  4. package/dist/chunk-GUNM43XZ.js.map +1 -0
  5. package/dist/chunk-NSVTXALR.js +559 -0
  6. package/dist/chunk-NSVTXALR.js.map +1 -0
  7. package/dist/filesystem/index.d.ts +5 -0
  8. package/dist/filesystem/index.d.ts.map +1 -0
  9. package/dist/filesystem/index.js +4 -0
  10. package/dist/filesystem/index.js.map +1 -0
  11. package/dist/filesystem/indexeddb-content-container.d.ts +20 -0
  12. package/dist/filesystem/indexeddb-content-container.d.ts.map +1 -0
  13. package/dist/filesystem/indexeddb-content-container.js +93 -0
  14. package/dist/filesystem/indexeddb-content-container.js.map +1 -0
  15. package/dist/filesystem/indexeddb-provider.d.ts +32 -0
  16. package/dist/filesystem/indexeddb-provider.d.ts.map +1 -0
  17. package/dist/filesystem/indexeddb-provider.js +253 -0
  18. package/dist/filesystem/indexeddb-provider.js.map +1 -0
  19. package/dist/filesystem/native-provider.d.ts +44 -0
  20. package/dist/filesystem/native-provider.d.ts.map +1 -0
  21. package/dist/filesystem/native-provider.js +302 -0
  22. package/dist/filesystem/native-provider.js.map +1 -0
  23. package/dist/filesystem/types.d.ts +50 -0
  24. package/dist/filesystem/types.d.ts.map +1 -0
  25. package/dist/filesystem/types.js +8 -0
  26. package/dist/filesystem/types.js.map +1 -0
  27. package/dist/index.d.ts +8 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +8 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/workspace/index.d.ts +3 -0
  32. package/dist/workspace/index.d.ts.map +1 -0
  33. package/dist/workspace/index.js +2 -0
  34. package/dist/workspace/index.js.map +1 -0
  35. package/dist/workspace/types.d.ts +15 -0
  36. package/dist/workspace/types.d.ts.map +1 -0
  37. package/dist/workspace/types.js +6 -0
  38. package/dist/workspace/types.js.map +1 -0
  39. package/dist/workspace/workspace-manager.d.ts +35 -0
  40. package/dist/workspace/workspace-manager.d.ts.map +1 -0
  41. package/dist/workspace/workspace-manager.js +82 -0
  42. package/dist/workspace/workspace-manager.js.map +1 -0
  43. package/package.json +59 -0
  44. package/src/filesystem/index.ts +20 -0
  45. package/src/filesystem/indexeddb-content-container.ts +104 -0
  46. package/src/filesystem/indexeddb-provider.ts +299 -0
  47. package/src/filesystem/native-provider.ts +348 -0
  48. package/src/filesystem/types.ts +69 -0
  49. package/src/index.ts +8 -0
  50. package/src/workspace/index.ts +10 -0
  51. package/src/workspace/types.ts +15 -0
  52. package/src/workspace/workspace-manager.ts +90 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/filesystem/indexeddb-provider.ts","../src/filesystem/indexeddb-content-container.ts","../src/filesystem/native-provider.ts"],"sourcesContent":["/**\n * IndexedDBFileSystemProvider — virtualises a filesystem on top of IndexedDB\n * using the LocalForageAdapter from @bendyline/squisq/storage.\n *\n * Key schema:\n * fs:{path}:content → string (text file contents)\n * fs:{path}:binary → ArrayBuffer (binary file contents)\n * fs:{path}:meta → FileMeta object\n * fs:dirs → Set<string> of known directory paths\n */\n\nimport { LocalForageAdapter } from '@bendyline/squisq/storage';\nimport type { FileSystemProvider, FileSystemEntry, FileMeta } from './types.js';\n\n// ── Helpers ────────────────────────────────────────────────────────\n\n/** Normalise a path: strip leading/trailing slashes, collapse doubles. */\nfunction normalisePath(p: string): string {\n return p.replace(/\\\\/g, '/').replace(/\\/+/g, '/').replace(/^\\//, '').replace(/\\/$/, '');\n}\n\n/** Get the parent directory of a path, or empty string for root-level. */\nfunction parentDir(p: string): string {\n const idx = p.lastIndexOf('/');\n return idx === -1 ? '' : p.slice(0, idx);\n}\n\n/** Get the filename component of a path. */\nfunction baseName(p: string): string {\n const idx = p.lastIndexOf('/');\n return idx === -1 ? p : p.slice(idx + 1);\n}\n\n// ── Key helpers ────────────────────────────────────────────────────\n\nfunction contentKey(path: string): string {\n return `fs:${path}:content`;\n}\n\nfunction binaryKey(path: string): string {\n return `fs:${path}:binary`;\n}\n\nfunction metaKey(path: string): string {\n return `fs:${path}:meta`;\n}\n\nconst DIRS_KEY = 'fs:dirs';\n\n// ── Implementation ─────────────────────────────────────────────────\n\nexport class IndexedDBFileSystemProvider implements FileSystemProvider {\n readonly id: string;\n readonly label: string;\n\n private store: LocalForageAdapter;\n\n constructor(id: string, label: string) {\n this.id = id;\n this.label = label;\n this.store = new LocalForageAdapter({\n name: `docblocks-fs-${id}`,\n storeName: 'files',\n });\n }\n\n // ── Directory tracking ──────────────────────────────────────────\n\n private async getDirs(): Promise<Set<string>> {\n const raw = await this.store.get<string[]>(DIRS_KEY);\n return new Set(raw ?? []);\n }\n\n private async saveDirs(dirs: Set<string>): Promise<void> {\n await this.store.set(DIRS_KEY, [...dirs]);\n }\n\n /** Ensure a directory (and all ancestors) are tracked. */\n private async ensureDir(dirPath: string): Promise<void> {\n if (!dirPath) return;\n const dirs = await this.getDirs();\n const parts = dirPath.split('/');\n let current = '';\n let changed = false;\n for (const part of parts) {\n current = current ? `${current}/${part}` : part;\n if (!dirs.has(current)) {\n dirs.add(current);\n changed = true;\n }\n }\n if (changed) {\n await this.saveDirs(dirs);\n }\n }\n\n // ── FileSystemProvider implementation ───────────────────────────\n\n async readFile(path: string): Promise<string | null> {\n const p = normalisePath(path);\n return this.store.get<string>(contentKey(p));\n }\n\n async writeFile(path: string, content: string): Promise<void> {\n const p = normalisePath(path);\n const parent = parentDir(p);\n if (parent) {\n await this.ensureDir(parent);\n }\n\n const meta: FileMeta = {\n name: baseName(p),\n path: p,\n size: new Blob([content]).size,\n lastModified: new Date().toISOString(),\n };\n\n await this.store.set(contentKey(p), content);\n await this.store.set(metaKey(p), meta);\n }\n\n async delete(path: string): Promise<void> {\n const p = normalisePath(path);\n\n // Remove file keys\n await this.store.remove(contentKey(p));\n await this.store.remove(binaryKey(p));\n await this.store.remove(metaKey(p));\n\n // If it was a directory, remove it and all children\n const dirs = await this.getDirs();\n if (dirs.has(p)) {\n const prefix = p + '/';\n const toRemove: string[] = [p];\n for (const d of dirs) {\n if (d.startsWith(prefix)) {\n toRemove.push(d);\n }\n }\n for (const d of toRemove) {\n dirs.delete(d);\n }\n await this.saveDirs(dirs);\n\n // Remove all file keys under this directory\n const allKeys = await this.store.keys();\n const filePrefix = `fs:${p}/`;\n const keysToRemove = allKeys.filter((k) => k.startsWith(filePrefix));\n await Promise.all(keysToRemove.map((k) => this.store.remove(k)));\n }\n }\n\n async rename(oldPath: string, newPath: string): Promise<void> {\n const op = normalisePath(oldPath);\n const np = normalisePath(newPath);\n\n // Read existing data\n const content = await this.store.get<string>(contentKey(op));\n const binary = await this.store.get<ArrayBuffer>(binaryKey(op));\n const meta = await this.store.get<FileMeta>(metaKey(op));\n\n // Write to new location\n if (content !== null) {\n await this.store.set(contentKey(np), content);\n }\n if (binary !== null) {\n await this.store.set(binaryKey(np), binary);\n }\n if (meta) {\n meta.name = baseName(np);\n meta.path = np;\n await this.store.set(metaKey(np), meta);\n }\n\n // Ensure parent dir of new path exists\n const newParent = parentDir(np);\n if (newParent) {\n await this.ensureDir(newParent);\n }\n\n // Delete old\n await this.store.remove(contentKey(op));\n await this.store.remove(binaryKey(op));\n await this.store.remove(metaKey(op));\n\n // Handle directory rename\n const dirs = await this.getDirs();\n if (dirs.has(op)) {\n dirs.delete(op);\n dirs.add(np);\n const oldPrefix = op + '/';\n const newPrefix = np + '/';\n for (const d of [...dirs]) {\n if (d.startsWith(oldPrefix)) {\n dirs.delete(d);\n dirs.add(newPrefix + d.slice(oldPrefix.length));\n }\n }\n await this.saveDirs(dirs);\n }\n }\n\n async readDirectory(path: string): Promise<FileSystemEntry[]> {\n const p = normalisePath(path);\n const dirs = await this.getDirs();\n const entries: FileSystemEntry[] = [];\n const seen = new Set<string>();\n\n // Find child directories\n const prefix = p ? p + '/' : '';\n for (const d of dirs) {\n if (!p && !d.includes('/')) {\n // Root-level directory\n if (!seen.has(d)) {\n seen.add(d);\n entries.push({ kind: 'directory', name: d, path: d });\n }\n } else if (p && d.startsWith(prefix)) {\n const rest = d.slice(prefix.length);\n if (!rest.includes('/')) {\n // Direct child directory\n if (!seen.has(rest)) {\n seen.add(rest);\n entries.push({ kind: 'directory', name: rest, path: d });\n }\n }\n }\n }\n\n // Find child files by scanning meta keys\n const allKeys = await this.store.keys();\n const metaPrefix = p ? `fs:${p}/` : 'fs:';\n const metaSuffix = ':meta';\n\n for (const key of allKeys) {\n if (!key.startsWith(metaPrefix) || !key.endsWith(metaSuffix)) continue;\n\n const filePath = key.slice(3, -metaSuffix.length); // strip \"fs:\" and \":meta\"\n const rel = p ? filePath.slice(prefix.length) : filePath;\n\n // Only direct children (no further slashes)\n if (rel.includes('/')) continue;\n\n if (!seen.has(rel)) {\n seen.add(rel);\n entries.push({ kind: 'file', name: rel, path: filePath });\n }\n }\n\n // Sort: directories first, then alphabetical\n entries.sort((a, b) => {\n if (a.kind !== b.kind) return a.kind === 'directory' ? -1 : 1;\n return a.name.localeCompare(b.name);\n });\n\n return entries;\n }\n\n async exists(path: string): Promise<boolean> {\n const p = normalisePath(path);\n const dirs = await this.getDirs();\n if (dirs.has(p)) return true;\n const meta = await this.store.get(metaKey(p));\n return meta !== null;\n }\n\n async createDirectory(path: string): Promise<void> {\n const p = normalisePath(path);\n await this.ensureDir(p);\n }\n\n async stat(path: string): Promise<FileMeta | null> {\n const p = normalisePath(path);\n return this.store.get<FileMeta>(metaKey(p));\n }\n\n async readBinary(path: string): Promise<ArrayBuffer | null> {\n const p = normalisePath(path);\n return this.store.get<ArrayBuffer>(binaryKey(p));\n }\n\n async writeBinary(path: string, data: ArrayBuffer | Uint8Array): Promise<void> {\n const p = normalisePath(path);\n const parent = parentDir(p);\n if (parent) {\n await this.ensureDir(parent);\n }\n\n const meta: FileMeta = {\n name: baseName(p),\n path: p,\n size: data.byteLength,\n lastModified: new Date().toISOString(),\n };\n\n await this.store.set(binaryKey(p), data);\n await this.store.set(metaKey(p), meta);\n }\n}\n","/**\n * IndexedDBContentContainer — a ContentContainer backed by IndexedDB.\n *\n * Uses a dedicated IndexedDBFileSystemProvider instance (separate store)\n * to persist media files across page refreshes.\n */\n\nimport type { ContentContainer, ContentEntry } from '@bendyline/squisq/storage';\nimport { findDocumentPath } from '@bendyline/squisq/storage';\nimport { IndexedDBFileSystemProvider } from './indexeddb-provider.js';\n\n// ── MIME type guessing ─────────────────────────────────────────────\n\nconst EXTENSION_MIME_MAP: Record<string, string> = {\n '.md': 'text/markdown',\n '.txt': 'text/plain',\n '.json': 'application/json',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.png': 'image/png',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.webp': 'image/webp',\n '.avif': 'image/avif',\n '.mp4': 'video/mp4',\n '.webm': 'video/webm',\n '.mp3': 'audio/mpeg',\n '.wav': 'audio/wav',\n '.ogg': 'audio/ogg',\n};\n\nfunction guessMimeType(path: string): string {\n const dot = path.lastIndexOf('.');\n if (dot === -1) return 'application/octet-stream';\n const ext = path.slice(dot).toLowerCase();\n return EXTENSION_MIME_MAP[ext] ?? 'application/octet-stream';\n}\n\n// ── Implementation ─────────────────────────────────────────────────\n\nexport class IndexedDBContentContainer implements ContentContainer {\n private provider: IndexedDBFileSystemProvider;\n\n constructor(workspaceId: string) {\n this.provider = new IndexedDBFileSystemProvider(`${workspaceId}-media`, 'Media Storage');\n }\n\n async readFile(path: string): Promise<ArrayBuffer | null> {\n return this.provider.readBinary(path);\n }\n\n async writeFile(path: string, data: ArrayBuffer | Uint8Array, _mimeType?: string): Promise<void> {\n await this.provider.writeBinary(path, data);\n }\n\n async removeFile(path: string): Promise<void> {\n await this.provider.delete(path);\n }\n\n async listFiles(prefix?: string): Promise<ContentEntry[]> {\n const entries: ContentEntry[] = [];\n const walk = async (dir: string) => {\n const children = await this.provider.readDirectory(dir);\n for (const child of children) {\n if (child.kind === 'directory') {\n await walk(child.path);\n } else {\n const filePath = child.path.replace(/^\\//, '');\n if (prefix && !filePath.startsWith(prefix)) continue;\n const meta = await this.provider.stat(child.path);\n entries.push({\n path: filePath,\n mimeType: guessMimeType(filePath),\n size: meta?.size ?? 0,\n });\n }\n }\n };\n await walk('/');\n return entries;\n }\n\n async exists(path: string): Promise<boolean> {\n return this.provider.exists(path);\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 * NativeFileSystemProvider — wraps the File System Access API\n * (window.showDirectoryPicker / FileSystemDirectoryHandle).\n *\n * Progressive enhancement: only available in browsers that support\n * the API (Chrome, Edge). Feature-detect with `isNativeFileSystemSupported()`.\n */\n\nimport type { FileSystemProvider, FileSystemEntry, FileMeta } from './types.js';\n\n// ── Feature detection ──────────────────────────────────────────────\n\nexport function isNativeFileSystemSupported(): boolean {\n return typeof globalThis !== 'undefined' && 'showDirectoryPicker' in globalThis;\n}\n\n// ── Handle persistence (IndexedDB, structured clone) ───────────────\n\nconst HANDLE_DB_NAME = 'docblocks-handles';\nconst HANDLE_STORE_NAME = 'directory-handles';\n\nfunction openHandleDB(): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const req = indexedDB.open(HANDLE_DB_NAME, 1);\n req.onupgradeneeded = () => {\n req.result.createObjectStore(HANDLE_STORE_NAME);\n };\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error);\n });\n}\n\n/** Persist a FileSystemDirectoryHandle so it survives page reloads. */\nexport async function storeDirectoryHandle(\n workspaceId: string,\n handle: FileSystemDirectoryHandle,\n): Promise<void> {\n const db = await openHandleDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(HANDLE_STORE_NAME, 'readwrite');\n tx.objectStore(HANDLE_STORE_NAME).put(handle, workspaceId);\n tx.oncomplete = () => {\n db.close();\n resolve();\n };\n tx.onerror = () => {\n db.close();\n reject(tx.error);\n };\n });\n}\n\n/** Retrieve a previously stored handle. Returns null if not found. */\nexport async function loadDirectoryHandle(\n workspaceId: string,\n): Promise<FileSystemDirectoryHandle | null> {\n const db = await openHandleDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(HANDLE_STORE_NAME, 'readonly');\n const req = tx.objectStore(HANDLE_STORE_NAME).get(workspaceId);\n req.onsuccess = () => {\n db.close();\n resolve(req.result ?? null);\n };\n req.onerror = () => {\n db.close();\n reject(req.error);\n };\n });\n}\n\n/** Remove a stored handle (e.g. when deleting a workspace). */\nexport async function removeDirectoryHandle(workspaceId: string): Promise<void> {\n const db = await openHandleDB();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(HANDLE_STORE_NAME, 'readwrite');\n tx.objectStore(HANDLE_STORE_NAME).delete(workspaceId);\n tx.oncomplete = () => {\n db.close();\n resolve();\n };\n tx.onerror = () => {\n db.close();\n reject(tx.error);\n };\n });\n}\n\n// ── Helpers ────────────────────────────────────────────────────────\n\nfunction normalisePath(p: string): string {\n return p.replace(/\\\\/g, '/').replace(/\\/+/g, '/').replace(/^\\//, '').replace(/\\/$/, '');\n}\n\n/**\n * Walk a chain of path segments to reach a FileSystemDirectoryHandle.\n * Returns null if any segment is missing.\n */\nasync function resolveDir(\n root: FileSystemDirectoryHandle,\n dirPath: string,\n): Promise<FileSystemDirectoryHandle | null> {\n if (!dirPath) return root;\n const parts = dirPath.split('/');\n let current = root;\n for (const part of parts) {\n try {\n current = await current.getDirectoryHandle(part);\n } catch {\n return null;\n }\n }\n return current;\n}\n\n/**\n * Walk path segments, creating directories as needed.\n */\nasync function resolveDirCreate(\n root: FileSystemDirectoryHandle,\n dirPath: string,\n): Promise<FileSystemDirectoryHandle> {\n if (!dirPath) return root;\n const parts = dirPath.split('/');\n let current = root;\n for (const part of parts) {\n current = await current.getDirectoryHandle(part, { create: true });\n }\n return current;\n}\n\nfunction parentDir(p: string): string {\n const idx = p.lastIndexOf('/');\n return idx === -1 ? '' : p.slice(0, idx);\n}\n\nfunction baseName(p: string): string {\n const idx = p.lastIndexOf('/');\n return idx === -1 ? p : p.slice(idx + 1);\n}\n\n// ── Implementation ─────────────────────────────────────────────────\n\nexport class NativeFileSystemProvider implements FileSystemProvider {\n readonly id: string;\n readonly label: string;\n\n private root: FileSystemDirectoryHandle;\n\n constructor(id: string, root: FileSystemDirectoryHandle) {\n this.id = id;\n this.label = root.name;\n this.root = root;\n }\n\n async readFile(path: string): Promise<string | null> {\n const p = normalisePath(path);\n const dir = await resolveDir(this.root, parentDir(p));\n if (!dir) return null;\n try {\n const fileHandle = await dir.getFileHandle(baseName(p));\n const file = await fileHandle.getFile();\n return file.text();\n } catch {\n return null;\n }\n }\n\n async writeFile(path: string, content: string): Promise<void> {\n const p = normalisePath(path);\n const dir = await resolveDirCreate(this.root, parentDir(p));\n const fileHandle = await dir.getFileHandle(baseName(p), { create: true });\n const writable = await fileHandle.createWritable();\n await writable.write(content);\n await writable.close();\n }\n\n async delete(path: string): Promise<void> {\n const p = normalisePath(path);\n const parent = parentDir(p);\n const name = baseName(p);\n const dir = await resolveDir(this.root, parent);\n if (!dir) return;\n await dir.removeEntry(name, { recursive: true });\n }\n\n async rename(oldPath: string, newPath: string): Promise<void> {\n const op = normalisePath(oldPath);\n const np = normalisePath(newPath);\n\n // The File System Access API doesn't have a native rename.\n // Read → write → delete.\n const content = await this.readFile(op);\n if (content !== null) {\n await this.writeFile(np, content);\n await this.delete(op);\n return;\n }\n\n // Try binary\n const binary = await this.readBinary(op);\n if (binary !== null) {\n await this.writeBinary(np, binary);\n await this.delete(op);\n }\n }\n\n async readDirectory(path: string): Promise<FileSystemEntry[]> {\n const p = normalisePath(path);\n const dir = await resolveDir(this.root, p);\n if (!dir) return [];\n\n const entries: FileSystemEntry[] = [];\n for await (const [name, handle] of dir as unknown as AsyncIterable<\n [string, FileSystemHandle]\n >) {\n const entryPath = p ? `${p}/${name}` : name;\n if (handle.kind === 'directory') {\n entries.push({ kind: 'directory', name, path: entryPath });\n } else {\n entries.push({ kind: 'file', name, path: entryPath });\n }\n }\n\n // Sort: directories first, then alphabetical\n entries.sort((a, b) => {\n if (a.kind !== b.kind) return a.kind === 'directory' ? -1 : 1;\n return a.name.localeCompare(b.name);\n });\n\n return entries;\n }\n\n async exists(path: string): Promise<boolean> {\n const p = normalisePath(path);\n const parent = parentDir(p);\n const name = baseName(p);\n const dir = await resolveDir(this.root, parent);\n if (!dir) return false;\n\n try {\n await dir.getFileHandle(name);\n return true;\n } catch {\n try {\n await dir.getDirectoryHandle(name);\n return true;\n } catch {\n return false;\n }\n }\n }\n\n async createDirectory(path: string): Promise<void> {\n const p = normalisePath(path);\n await resolveDirCreate(this.root, p);\n }\n\n async stat(path: string): Promise<FileMeta | null> {\n const p = normalisePath(path);\n const dir = await resolveDir(this.root, parentDir(p));\n if (!dir) return null;\n\n try {\n const fileHandle = await dir.getFileHandle(baseName(p));\n const file = await fileHandle.getFile();\n return {\n name: file.name,\n path: p,\n size: file.size,\n lastModified: new Date(file.lastModified).toISOString(),\n };\n } catch {\n return null;\n }\n }\n\n async readBinary(path: string): Promise<ArrayBuffer | null> {\n const p = normalisePath(path);\n const dir = await resolveDir(this.root, parentDir(p));\n if (!dir) return null;\n try {\n const fileHandle = await dir.getFileHandle(baseName(p));\n const file = await fileHandle.getFile();\n return file.arrayBuffer();\n } catch {\n return null;\n }\n }\n\n async writeBinary(path: string, data: ArrayBuffer | Uint8Array): Promise<void> {\n const p = normalisePath(path);\n const dir = await resolveDirCreate(this.root, parentDir(p));\n const fileHandle = await dir.getFileHandle(baseName(p), { create: true });\n const writable = await fileHandle.createWritable();\n if (data instanceof ArrayBuffer) {\n await writable.write(data);\n } else {\n await writable.write(data.buffer as ArrayBuffer);\n }\n await writable.close();\n }\n}\n\n/**\n * Prompt the user to pick a local folder and return a NativeFileSystemProvider.\n * The directory handle is persisted in IndexedDB so it can be restored later.\n * Throws if the user cancels or the API is unsupported.\n */\nexport async function openNativeFolder(): Promise<NativeFileSystemProvider> {\n if (!isNativeFileSystemSupported()) {\n throw new Error('File System Access API is not supported in this browser');\n }\n\n const handle = await (\n globalThis as unknown as { showDirectoryPicker: () => Promise<FileSystemDirectoryHandle> }\n ).showDirectoryPicker();\n const id = `native-${handle.name}-${Date.now()}`;\n await storeDirectoryHandle(id, handle);\n return new NativeFileSystemProvider(id, handle);\n}\n\n/**\n * Restore a previously opened native folder from a persisted handle.\n * Re-requests read/write permission (browser will show a prompt).\n * Returns null if the handle is not found or permission is denied.\n */\nexport async function restoreNativeFolder(\n workspaceId: string,\n): Promise<NativeFileSystemProvider | null> {\n const handle = await loadDirectoryHandle(workspaceId);\n if (!handle) return null;\n\n // Verify/request permission\n const opts = { mode: 'readwrite' as const };\n const h = handle as FileSystemDirectoryHandle & {\n queryPermission(desc: { mode: string }): Promise<string>;\n requestPermission(desc: { mode: string }): Promise<string>;\n };\n if ((await h.queryPermission(opts)) === 'granted') {\n return new NativeFileSystemProvider(workspaceId, handle);\n }\n if ((await h.requestPermission(opts)) === 'granted') {\n return new NativeFileSystemProvider(workspaceId, handle);\n }\n\n return null;\n}\n"],"mappings":"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","names":["normalisePath","parentDir","baseName"]}
@@ -0,0 +1,5 @@
1
+ export type { FileSystemProvider, FileSystemEntry, FileEntry, FolderEntry, FileMeta, } from './types.js';
2
+ export { IndexedDBFileSystemProvider } from './indexeddb-provider.js';
3
+ export { IndexedDBContentContainer } from './indexeddb-content-container.js';
4
+ export { NativeFileSystemProvider, isNativeFileSystemSupported, openNativeFolder, restoreNativeFolder, storeDirectoryHandle, loadDirectoryHandle, removeDirectoryHandle, } from './native-provider.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/filesystem/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,kBAAkB,EAClB,eAAe,EACf,SAAS,EACT,WAAW,EACX,QAAQ,GACT,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAC;AAE7E,OAAO,EACL,wBAAwB,EACxB,2BAA2B,EAC3B,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { IndexedDBFileSystemProvider } from './indexeddb-provider.js';
2
+ export { IndexedDBContentContainer } from './indexeddb-content-container.js';
3
+ export { NativeFileSystemProvider, isNativeFileSystemSupported, openNativeFolder, restoreNativeFolder, storeDirectoryHandle, loadDirectoryHandle, removeDirectoryHandle, } from './native-provider.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/filesystem/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAC;AAE7E,OAAO,EACL,wBAAwB,EACxB,2BAA2B,EAC3B,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * IndexedDBContentContainer — a ContentContainer backed by IndexedDB.
3
+ *
4
+ * Uses a dedicated IndexedDBFileSystemProvider instance (separate store)
5
+ * to persist media files across page refreshes.
6
+ */
7
+ import type { ContentContainer, ContentEntry } from '@bendyline/squisq/storage';
8
+ export declare class IndexedDBContentContainer implements ContentContainer {
9
+ private provider;
10
+ constructor(workspaceId: string);
11
+ readFile(path: string): Promise<ArrayBuffer | null>;
12
+ writeFile(path: string, data: ArrayBuffer | Uint8Array, _mimeType?: string): Promise<void>;
13
+ removeFile(path: string): Promise<void>;
14
+ listFiles(prefix?: string): Promise<ContentEntry[]>;
15
+ exists(path: string): Promise<boolean>;
16
+ getDocumentPath(): Promise<string | null>;
17
+ readDocument(): Promise<string | null>;
18
+ writeDocument(markdown: string, filename?: string): Promise<void>;
19
+ }
20
+ //# sourceMappingURL=indexeddb-content-container.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexeddb-content-container.d.ts","sourceRoot":"","sources":["../../src/filesystem/indexeddb-content-container.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAiChF,qBAAa,yBAA0B,YAAW,gBAAgB;IAChE,OAAO,CAAC,QAAQ,CAA8B;gBAElC,WAAW,EAAE,MAAM;IAIzB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAInD,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,UAAU,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI1F,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvC,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAuBnD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAItC,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAIzC,YAAY,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAQtC,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAKxE"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * IndexedDBContentContainer — a ContentContainer backed by IndexedDB.
3
+ *
4
+ * Uses a dedicated IndexedDBFileSystemProvider instance (separate store)
5
+ * to persist media files across page refreshes.
6
+ */
7
+ import { findDocumentPath } from '@bendyline/squisq/storage';
8
+ import { IndexedDBFileSystemProvider } from './indexeddb-provider.js';
9
+ // ── MIME type guessing ─────────────────────────────────────────────
10
+ const EXTENSION_MIME_MAP = {
11
+ '.md': 'text/markdown',
12
+ '.txt': 'text/plain',
13
+ '.json': 'application/json',
14
+ '.jpg': 'image/jpeg',
15
+ '.jpeg': 'image/jpeg',
16
+ '.png': 'image/png',
17
+ '.gif': 'image/gif',
18
+ '.svg': 'image/svg+xml',
19
+ '.webp': 'image/webp',
20
+ '.avif': 'image/avif',
21
+ '.mp4': 'video/mp4',
22
+ '.webm': 'video/webm',
23
+ '.mp3': 'audio/mpeg',
24
+ '.wav': 'audio/wav',
25
+ '.ogg': 'audio/ogg',
26
+ };
27
+ function guessMimeType(path) {
28
+ const dot = path.lastIndexOf('.');
29
+ if (dot === -1)
30
+ return 'application/octet-stream';
31
+ const ext = path.slice(dot).toLowerCase();
32
+ return EXTENSION_MIME_MAP[ext] ?? 'application/octet-stream';
33
+ }
34
+ // ── Implementation ─────────────────────────────────────────────────
35
+ export class IndexedDBContentContainer {
36
+ constructor(workspaceId) {
37
+ this.provider = new IndexedDBFileSystemProvider(`${workspaceId}-media`, 'Media Storage');
38
+ }
39
+ async readFile(path) {
40
+ return this.provider.readBinary(path);
41
+ }
42
+ async writeFile(path, data, _mimeType) {
43
+ await this.provider.writeBinary(path, data);
44
+ }
45
+ async removeFile(path) {
46
+ await this.provider.delete(path);
47
+ }
48
+ async listFiles(prefix) {
49
+ const entries = [];
50
+ const walk = async (dir) => {
51
+ const children = await this.provider.readDirectory(dir);
52
+ for (const child of children) {
53
+ if (child.kind === 'directory') {
54
+ await walk(child.path);
55
+ }
56
+ else {
57
+ const filePath = child.path.replace(/^\//, '');
58
+ if (prefix && !filePath.startsWith(prefix))
59
+ continue;
60
+ const meta = await this.provider.stat(child.path);
61
+ entries.push({
62
+ path: filePath,
63
+ mimeType: guessMimeType(filePath),
64
+ size: meta?.size ?? 0,
65
+ });
66
+ }
67
+ }
68
+ };
69
+ await walk('/');
70
+ return entries;
71
+ }
72
+ async exists(path) {
73
+ return this.provider.exists(path);
74
+ }
75
+ async getDocumentPath() {
76
+ return findDocumentPath(await this.listFiles());
77
+ }
78
+ async readDocument() {
79
+ const docPath = await this.getDocumentPath();
80
+ if (!docPath)
81
+ return null;
82
+ const data = await this.readFile(docPath);
83
+ if (!data)
84
+ return null;
85
+ return new TextDecoder().decode(data);
86
+ }
87
+ async writeDocument(markdown, filename) {
88
+ const name = filename ?? 'index.md';
89
+ const data = new TextEncoder().encode(markdown);
90
+ await this.writeFile(name, data, 'text/markdown');
91
+ }
92
+ }
93
+ //# sourceMappingURL=indexeddb-content-container.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexeddb-content-container.js","sourceRoot":"","sources":["../../src/filesystem/indexeddb-content-container.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * IndexedDBFileSystemProvider — virtualises a filesystem on top of IndexedDB
3
+ * using the LocalForageAdapter from @bendyline/squisq/storage.
4
+ *
5
+ * Key schema:
6
+ * fs:{path}:content → string (text file contents)
7
+ * fs:{path}:binary → ArrayBuffer (binary file contents)
8
+ * fs:{path}:meta → FileMeta object
9
+ * fs:dirs → Set<string> of known directory paths
10
+ */
11
+ import type { FileSystemProvider, FileSystemEntry, FileMeta } from './types.js';
12
+ export declare class IndexedDBFileSystemProvider implements FileSystemProvider {
13
+ readonly id: string;
14
+ readonly label: string;
15
+ private store;
16
+ constructor(id: string, label: string);
17
+ private getDirs;
18
+ private saveDirs;
19
+ /** Ensure a directory (and all ancestors) are tracked. */
20
+ private ensureDir;
21
+ readFile(path: string): Promise<string | null>;
22
+ writeFile(path: string, content: string): Promise<void>;
23
+ delete(path: string): Promise<void>;
24
+ rename(oldPath: string, newPath: string): Promise<void>;
25
+ readDirectory(path: string): Promise<FileSystemEntry[]>;
26
+ exists(path: string): Promise<boolean>;
27
+ createDirectory(path: string): Promise<void>;
28
+ stat(path: string): Promise<FileMeta | null>;
29
+ readBinary(path: string): Promise<ArrayBuffer | null>;
30
+ writeBinary(path: string, data: ArrayBuffer | Uint8Array): Promise<void>;
31
+ }
32
+ //# sourceMappingURL=indexeddb-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexeddb-provider.d.ts","sourceRoot":"","sources":["../../src/filesystem/indexeddb-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAuChF,qBAAa,2BAA4B,YAAW,kBAAkB;IACpE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,OAAO,CAAC,KAAK,CAAqB;gBAEtB,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;YAWvB,OAAO;YAKP,QAAQ;IAItB,0DAA0D;YAC5C,SAAS;IAoBjB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAK9C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBvD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA+BnC,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkDvD,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAwDvD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQtC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5C,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAK5C,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAKrD,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAiB/E"}
@@ -0,0 +1,253 @@
1
+ /**
2
+ * IndexedDBFileSystemProvider — virtualises a filesystem on top of IndexedDB
3
+ * using the LocalForageAdapter from @bendyline/squisq/storage.
4
+ *
5
+ * Key schema:
6
+ * fs:{path}:content → string (text file contents)
7
+ * fs:{path}:binary → ArrayBuffer (binary file contents)
8
+ * fs:{path}:meta → FileMeta object
9
+ * fs:dirs → Set<string> of known directory paths
10
+ */
11
+ import { LocalForageAdapter } from '@bendyline/squisq/storage';
12
+ // ── Helpers ────────────────────────────────────────────────────────
13
+ /** Normalise a path: strip leading/trailing slashes, collapse doubles. */
14
+ function normalisePath(p) {
15
+ return p.replace(/\\/g, '/').replace(/\/+/g, '/').replace(/^\//, '').replace(/\/$/, '');
16
+ }
17
+ /** Get the parent directory of a path, or empty string for root-level. */
18
+ function parentDir(p) {
19
+ const idx = p.lastIndexOf('/');
20
+ return idx === -1 ? '' : p.slice(0, idx);
21
+ }
22
+ /** Get the filename component of a path. */
23
+ function baseName(p) {
24
+ const idx = p.lastIndexOf('/');
25
+ return idx === -1 ? p : p.slice(idx + 1);
26
+ }
27
+ // ── Key helpers ────────────────────────────────────────────────────
28
+ function contentKey(path) {
29
+ return `fs:${path}:content`;
30
+ }
31
+ function binaryKey(path) {
32
+ return `fs:${path}:binary`;
33
+ }
34
+ function metaKey(path) {
35
+ return `fs:${path}:meta`;
36
+ }
37
+ const DIRS_KEY = 'fs:dirs';
38
+ // ── Implementation ─────────────────────────────────────────────────
39
+ export class IndexedDBFileSystemProvider {
40
+ constructor(id, label) {
41
+ this.id = id;
42
+ this.label = label;
43
+ this.store = new LocalForageAdapter({
44
+ name: `docblocks-fs-${id}`,
45
+ storeName: 'files',
46
+ });
47
+ }
48
+ // ── Directory tracking ──────────────────────────────────────────
49
+ async getDirs() {
50
+ const raw = await this.store.get(DIRS_KEY);
51
+ return new Set(raw ?? []);
52
+ }
53
+ async saveDirs(dirs) {
54
+ await this.store.set(DIRS_KEY, [...dirs]);
55
+ }
56
+ /** Ensure a directory (and all ancestors) are tracked. */
57
+ async ensureDir(dirPath) {
58
+ if (!dirPath)
59
+ return;
60
+ const dirs = await this.getDirs();
61
+ const parts = dirPath.split('/');
62
+ let current = '';
63
+ let changed = false;
64
+ for (const part of parts) {
65
+ current = current ? `${current}/${part}` : part;
66
+ if (!dirs.has(current)) {
67
+ dirs.add(current);
68
+ changed = true;
69
+ }
70
+ }
71
+ if (changed) {
72
+ await this.saveDirs(dirs);
73
+ }
74
+ }
75
+ // ── FileSystemProvider implementation ───────────────────────────
76
+ async readFile(path) {
77
+ const p = normalisePath(path);
78
+ return this.store.get(contentKey(p));
79
+ }
80
+ async writeFile(path, content) {
81
+ const p = normalisePath(path);
82
+ const parent = parentDir(p);
83
+ if (parent) {
84
+ await this.ensureDir(parent);
85
+ }
86
+ const meta = {
87
+ name: baseName(p),
88
+ path: p,
89
+ size: new Blob([content]).size,
90
+ lastModified: new Date().toISOString(),
91
+ };
92
+ await this.store.set(contentKey(p), content);
93
+ await this.store.set(metaKey(p), meta);
94
+ }
95
+ async delete(path) {
96
+ const p = normalisePath(path);
97
+ // Remove file keys
98
+ await this.store.remove(contentKey(p));
99
+ await this.store.remove(binaryKey(p));
100
+ await this.store.remove(metaKey(p));
101
+ // If it was a directory, remove it and all children
102
+ const dirs = await this.getDirs();
103
+ if (dirs.has(p)) {
104
+ const prefix = p + '/';
105
+ const toRemove = [p];
106
+ for (const d of dirs) {
107
+ if (d.startsWith(prefix)) {
108
+ toRemove.push(d);
109
+ }
110
+ }
111
+ for (const d of toRemove) {
112
+ dirs.delete(d);
113
+ }
114
+ await this.saveDirs(dirs);
115
+ // Remove all file keys under this directory
116
+ const allKeys = await this.store.keys();
117
+ const filePrefix = `fs:${p}/`;
118
+ const keysToRemove = allKeys.filter((k) => k.startsWith(filePrefix));
119
+ await Promise.all(keysToRemove.map((k) => this.store.remove(k)));
120
+ }
121
+ }
122
+ async rename(oldPath, newPath) {
123
+ const op = normalisePath(oldPath);
124
+ const np = normalisePath(newPath);
125
+ // Read existing data
126
+ const content = await this.store.get(contentKey(op));
127
+ const binary = await this.store.get(binaryKey(op));
128
+ const meta = await this.store.get(metaKey(op));
129
+ // Write to new location
130
+ if (content !== null) {
131
+ await this.store.set(contentKey(np), content);
132
+ }
133
+ if (binary !== null) {
134
+ await this.store.set(binaryKey(np), binary);
135
+ }
136
+ if (meta) {
137
+ meta.name = baseName(np);
138
+ meta.path = np;
139
+ await this.store.set(metaKey(np), meta);
140
+ }
141
+ // Ensure parent dir of new path exists
142
+ const newParent = parentDir(np);
143
+ if (newParent) {
144
+ await this.ensureDir(newParent);
145
+ }
146
+ // Delete old
147
+ await this.store.remove(contentKey(op));
148
+ await this.store.remove(binaryKey(op));
149
+ await this.store.remove(metaKey(op));
150
+ // Handle directory rename
151
+ const dirs = await this.getDirs();
152
+ if (dirs.has(op)) {
153
+ dirs.delete(op);
154
+ dirs.add(np);
155
+ const oldPrefix = op + '/';
156
+ const newPrefix = np + '/';
157
+ for (const d of [...dirs]) {
158
+ if (d.startsWith(oldPrefix)) {
159
+ dirs.delete(d);
160
+ dirs.add(newPrefix + d.slice(oldPrefix.length));
161
+ }
162
+ }
163
+ await this.saveDirs(dirs);
164
+ }
165
+ }
166
+ async readDirectory(path) {
167
+ const p = normalisePath(path);
168
+ const dirs = await this.getDirs();
169
+ const entries = [];
170
+ const seen = new Set();
171
+ // Find child directories
172
+ const prefix = p ? p + '/' : '';
173
+ for (const d of dirs) {
174
+ if (!p && !d.includes('/')) {
175
+ // Root-level directory
176
+ if (!seen.has(d)) {
177
+ seen.add(d);
178
+ entries.push({ kind: 'directory', name: d, path: d });
179
+ }
180
+ }
181
+ else if (p && d.startsWith(prefix)) {
182
+ const rest = d.slice(prefix.length);
183
+ if (!rest.includes('/')) {
184
+ // Direct child directory
185
+ if (!seen.has(rest)) {
186
+ seen.add(rest);
187
+ entries.push({ kind: 'directory', name: rest, path: d });
188
+ }
189
+ }
190
+ }
191
+ }
192
+ // Find child files by scanning meta keys
193
+ const allKeys = await this.store.keys();
194
+ const metaPrefix = p ? `fs:${p}/` : 'fs:';
195
+ const metaSuffix = ':meta';
196
+ for (const key of allKeys) {
197
+ if (!key.startsWith(metaPrefix) || !key.endsWith(metaSuffix))
198
+ continue;
199
+ const filePath = key.slice(3, -metaSuffix.length); // strip "fs:" and ":meta"
200
+ const rel = p ? filePath.slice(prefix.length) : filePath;
201
+ // Only direct children (no further slashes)
202
+ if (rel.includes('/'))
203
+ continue;
204
+ if (!seen.has(rel)) {
205
+ seen.add(rel);
206
+ entries.push({ kind: 'file', name: rel, path: filePath });
207
+ }
208
+ }
209
+ // Sort: directories first, then alphabetical
210
+ entries.sort((a, b) => {
211
+ if (a.kind !== b.kind)
212
+ return a.kind === 'directory' ? -1 : 1;
213
+ return a.name.localeCompare(b.name);
214
+ });
215
+ return entries;
216
+ }
217
+ async exists(path) {
218
+ const p = normalisePath(path);
219
+ const dirs = await this.getDirs();
220
+ if (dirs.has(p))
221
+ return true;
222
+ const meta = await this.store.get(metaKey(p));
223
+ return meta !== null;
224
+ }
225
+ async createDirectory(path) {
226
+ const p = normalisePath(path);
227
+ await this.ensureDir(p);
228
+ }
229
+ async stat(path) {
230
+ const p = normalisePath(path);
231
+ return this.store.get(metaKey(p));
232
+ }
233
+ async readBinary(path) {
234
+ const p = normalisePath(path);
235
+ return this.store.get(binaryKey(p));
236
+ }
237
+ async writeBinary(path, data) {
238
+ const p = normalisePath(path);
239
+ const parent = parentDir(p);
240
+ if (parent) {
241
+ await this.ensureDir(parent);
242
+ }
243
+ const meta = {
244
+ name: baseName(p),
245
+ path: p,
246
+ size: data.byteLength,
247
+ lastModified: new Date().toISOString(),
248
+ };
249
+ await this.store.set(binaryKey(p), data);
250
+ await this.store.set(metaKey(p), meta);
251
+ }
252
+ }
253
+ //# sourceMappingURL=indexeddb-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexeddb-provider.js","sourceRoot":"","sources":["../../src/filesystem/indexeddb-provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * NativeFileSystemProvider — wraps the File System Access API
3
+ * (window.showDirectoryPicker / FileSystemDirectoryHandle).
4
+ *
5
+ * Progressive enhancement: only available in browsers that support
6
+ * the API (Chrome, Edge). Feature-detect with `isNativeFileSystemSupported()`.
7
+ */
8
+ import type { FileSystemProvider, FileSystemEntry, FileMeta } from './types.js';
9
+ export declare function isNativeFileSystemSupported(): boolean;
10
+ /** Persist a FileSystemDirectoryHandle so it survives page reloads. */
11
+ export declare function storeDirectoryHandle(workspaceId: string, handle: FileSystemDirectoryHandle): Promise<void>;
12
+ /** Retrieve a previously stored handle. Returns null if not found. */
13
+ export declare function loadDirectoryHandle(workspaceId: string): Promise<FileSystemDirectoryHandle | null>;
14
+ /** Remove a stored handle (e.g. when deleting a workspace). */
15
+ export declare function removeDirectoryHandle(workspaceId: string): Promise<void>;
16
+ export declare class NativeFileSystemProvider implements FileSystemProvider {
17
+ readonly id: string;
18
+ readonly label: string;
19
+ private root;
20
+ constructor(id: string, root: FileSystemDirectoryHandle);
21
+ readFile(path: string): Promise<string | null>;
22
+ writeFile(path: string, content: string): Promise<void>;
23
+ delete(path: string): Promise<void>;
24
+ rename(oldPath: string, newPath: string): Promise<void>;
25
+ readDirectory(path: string): Promise<FileSystemEntry[]>;
26
+ exists(path: string): Promise<boolean>;
27
+ createDirectory(path: string): Promise<void>;
28
+ stat(path: string): Promise<FileMeta | null>;
29
+ readBinary(path: string): Promise<ArrayBuffer | null>;
30
+ writeBinary(path: string, data: ArrayBuffer | Uint8Array): Promise<void>;
31
+ }
32
+ /**
33
+ * Prompt the user to pick a local folder and return a NativeFileSystemProvider.
34
+ * The directory handle is persisted in IndexedDB so it can be restored later.
35
+ * Throws if the user cancels or the API is unsupported.
36
+ */
37
+ export declare function openNativeFolder(): Promise<NativeFileSystemProvider>;
38
+ /**
39
+ * Restore a previously opened native folder from a persisted handle.
40
+ * Re-requests read/write permission (browser will show a prompt).
41
+ * Returns null if the handle is not found or permission is denied.
42
+ */
43
+ export declare function restoreNativeFolder(workspaceId: string): Promise<NativeFileSystemProvider | null>;
44
+ //# sourceMappingURL=native-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-provider.d.ts","sourceRoot":"","sources":["../../src/filesystem/native-provider.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAIhF,wBAAgB,2BAA2B,IAAI,OAAO,CAErD;AAkBD,uEAAuE;AACvE,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC,IAAI,CAAC,CAcf;AAED,sEAAsE;AACtE,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,yBAAyB,GAAG,IAAI,CAAC,CAc3C;AAED,+DAA+D;AAC/D,wBAAsB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAc9E;AAyDD,qBAAa,wBAAyB,YAAW,kBAAkB;IACjE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,OAAO,CAAC,IAAI,CAA4B;gBAE5B,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,yBAAyB;IAMjD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAa9C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASvD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASnC,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBvD,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IA0BvD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAoBtC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5C,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAmB5C,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAarD,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAY/E;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,wBAAwB,CAAC,CAW1E;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC,CAkB1C"}