@ai-ecoverse/slicc-kernel 1.147.10 → 1.148.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/dist/meta.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/fs/path-map.ts", "../src/fs/meta.ts", "../src/fs/notice.ts", "../src/fs/types.ts", "../src/meta.ts"],
4
- "sourcesContent": ["function parentOf(path: string): string | undefined {\n if (path === '/' || path === '') return undefined;\n const at = path.lastIndexOf('/');\n return at <= 0 ? '/' : path.slice(0, at);\n}\n\nexport class PathMap<V> {\n private readonly values = new Map<string, V>();\n private readonly children = new Map<string, Set<string>>();\n\n get size(): number {\n return this.values.size;\n }\n\n has(path: string): boolean {\n return this.values.has(path);\n }\n\n get(path: string): V | undefined {\n return this.values.get(path);\n }\n\n keys(): IterableIterator<string> {\n return this.values.keys();\n }\n\n set(path: string, value: V): this {\n if (!this.values.has(path)) this.link(path);\n this.values.set(path, value);\n return this;\n }\n\n delete(path: string): boolean {\n if (!this.values.delete(path)) return false;\n this.prune(path);\n return true;\n }\n\n subtree(root: string): string[] {\n const out: string[] = [];\n const stack = [root];\n for (let path = stack.pop(); path !== undefined; path = stack.pop()) {\n if (this.values.has(path)) out.push(path);\n const below = this.children.get(path);\n if (below) for (const child of below) stack.push(child);\n }\n return out;\n }\n\n entries(): IterableIterator<[string, V]> {\n return this.values.entries();\n }\n\n deleteTree(root: string): void {\n const stack = [root];\n for (let path = stack.pop(); path !== undefined; path = stack.pop()) {\n this.values.delete(path);\n const below = this.children.get(path);\n if (below) for (const child of below) stack.push(child);\n this.children.delete(path);\n }\n this.prune(root);\n }\n\n clear(): void {\n this.values.clear();\n this.children.clear();\n }\n\n private link(path: string): void {\n for (let child = path, parent = parentOf(path); parent !== undefined; ) {\n const set = this.children.get(parent);\n if (set?.has(child)) return;\n if (set) set.add(child);\n else this.children.set(parent, new Set([child]));\n child = parent;\n parent = parentOf(parent);\n }\n }\n\n private prune(path: string): void {\n for (let child = path, parent = parentOf(path); parent !== undefined; ) {\n if (this.values.has(child) || this.children.has(child)) return;\n const set = this.children.get(parent);\n set?.delete(child);\n if (set && set.size > 0) return;\n this.children.delete(parent);\n child = parent;\n parent = parentOf(parent);\n }\n }\n}\n", "import { PathMap } from './path-map.ts';\nexport interface MetaEntry {\n path: string;\n mode?: number;\n atimeMs?: number;\n mtimeMs?: number;\n mtimeFor?: number;\n timesAt?: number;\n timesBy?: string;\n ctimeMs?: number;\n ino?: number;\n link?: string;\n socket?: true;\n fifo?: true;\n dir?: string;\n uid?: number;\n gid?: number;\n heir?: [number, number];\n writes?: number;\n epoch?: number;\n vacated?: true;\n rename?: {\n from: string;\n to: string;\n at: number;\n replace?: true;\n lock?: string;\n root?: { ino: number; uid?: number; gid?: number; mode?: number };\n };\n}\n\nexport type MetaChange = (entry: MetaEntry | undefined) => MetaEntry | undefined;\n\nexport interface MetaUpdate {\n path: string;\n change: MetaChange;\n}\n\nexport interface MetaStore {\n get(paths: readonly string[]): Promise<Array<MetaEntry | undefined>>;\n fresh?(paths: readonly string[]): Promise<Array<MetaEntry | undefined>>;\n update(path: string, change: MetaChange): Promise<void>;\n updateMany?(changes: ReadonlyArray<MetaUpdate>): Promise<void>;\n move(\n from: string,\n to: string,\n root: (entry: MetaEntry | undefined) => MetaEntry,\n left?: MetaEntry\n ): Promise<void>;\n remove(paths: readonly string[], left?: MetaEntry): Promise<void>;\n links(dir: string): Promise<MetaEntry[]>;\n under(path: string): Promise<MetaEntry[]>;\n all(): Promise<MetaEntry[]>;\n absent?(path: string): boolean;\n removeFile?(path: string): Promise<void>;\n forgetTrees?(trees: readonly string[]): void;\n}\n\nexport const META_DB = 'slicc-kernel';\nexport const META_VERSION = 1;\nexport const META_STORE = 'entries';\n\nfunction parentOf(path: string): string {\n return path.slice(0, path.lastIndexOf('/')) || '/';\n}\n\nfunction moved(entry: MetaEntry, path: string): MetaEntry {\n return entry.link === undefined ? { ...entry, path } : { ...entry, path, dir: parentOf(path) };\n}\n\nfunction under(path: string, root: string): boolean {\n return path === root || path.startsWith(`${root}/`);\n}\n\nexport class MemoryMeta implements MetaStore {\n private readonly entries = new PathMap<MetaEntry>();\n\n async get(paths: readonly string[]): Promise<Array<MetaEntry | undefined>> {\n return paths.map((path) => this.entries.get(path));\n }\n\n async fresh(paths: readonly string[]): Promise<Array<MetaEntry | undefined>> {\n return this.get(paths);\n }\n\n async update(path: string, change: MetaChange): Promise<void> {\n this.set(path, change(this.entries.get(path)));\n }\n\n private set(path: string, entry: MetaEntry | undefined): void {\n if (entry) this.entries.set(path, entry);\n else this.entries.delete(path);\n }\n\n async move(\n from: string,\n to: string,\n root: (entry: MetaEntry | undefined) => MetaEntry,\n left?: MetaEntry\n ) {\n await this.remove([to]);\n const carried = this.entries.subtree(from).map((path) => this.entries.get(path) as MetaEntry);\n for (const entry of carried) this.entries.delete(entry.path);\n for (const entry of carried) {\n const path = to + entry.path.slice(from.length);\n if (path !== to) this.entries.set(path, moved(entry, path));\n }\n this.entries.set(to, moved(root(carried.find((entry) => entry.path === from)), to));\n if (left) this.entries.set(from, left);\n }\n\n async remove(paths: readonly string[], left?: MetaEntry): Promise<void> {\n for (const path of paths) this.entries.deleteTree(path);\n if (left) this.entries.set(left.path, left);\n }\n\n absent(path: string): boolean {\n return !this.entries.has(path);\n }\n\n async links(dir: string): Promise<MetaEntry[]> {\n return [...this.entries.entries()].map(([, e]) => e).filter((entry) => entry.dir === dir);\n }\n\n async under(path: string): Promise<MetaEntry[]> {\n return [...this.entries.entries()].map(([, e]) => e).filter((entry) => under(entry.path, path));\n }\n\n async all(): Promise<MetaEntry[]> {\n return [...this.entries.entries()].map(([, e]) => e);\n }\n}\n\nfunction descendants(path: string): IDBKeyRange {\n return IDBKeyRange.bound(`${path}/`, `${path}0`, false, true);\n}\n\nfunction settle<T>(transaction: IDBTransaction, value: () => T): Promise<T> {\n return new Promise((resolve, reject) => {\n transaction.oncomplete = () => resolve(value());\n transaction.onabort = () =>\n reject(transaction.error ?? new Error('metadata transaction aborted'));\n });\n}\n\ninterface Invalidation {\n paths?: readonly string[];\n trees?: readonly string[];\n moved?: { from: string; to: string };\n}\n\nconst REMOVE_BATCH = 256;\nconst REMOVE_WAIT_MS = 5;\n\nexport class IndexedDbMeta implements MetaStore {\n private readonly db: IDBDatabase;\n private readonly cache = new PathMap<MetaEntry | null>();\n private readonly channel: BroadcastChannel;\n private generation = 0;\n private readonly listeners = new Set<(change: Invalidation) => void>();\n\n listen(listener: (change: Invalidation) => void): void {\n this.listeners.add(listener);\n }\n\n constructor(db: IDBDatabase) {\n this.db = db;\n db.onversionchange = () => db.close();\n this.channel = new BroadcastChannel(`slicc-kernel-meta:${db.name}`);\n this.channel.onmessage = ({ data }) => {\n this.drop(data as Invalidation);\n for (const listener of this.listeners) listener(data as Invalidation);\n };\n (this.channel as BroadcastChannel & { unref?: () => void }).unref?.();\n }\n\n forgetTrees(trees: readonly string[]): void {\n this.drop({ trees: [...trees] });\n }\n\n private drop({ paths = [], trees = [] }: Invalidation): void {\n this.generation++;\n for (const path of paths) this.cache.delete(path);\n for (const tree of trees) this.cache.deleteTree(tree);\n }\n\n private changed(invalidation: Invalidation): void {\n this.drop(invalidation);\n this.channel.postMessage(invalidation);\n }\n\n private transaction(mode: IDBTransactionMode): [IDBTransaction, IDBObjectStore] {\n const transaction = this.db.transaction(META_STORE, mode);\n return [transaction, transaction.objectStore(META_STORE)];\n }\n\n async get(paths: readonly string[]): Promise<Array<MetaEntry | undefined>> {\n const missing = paths.filter((path) => !this.cache.has(path));\n if (missing.length > 0) {\n this.settleRemoves();\n const generation = this.generation;\n const [transaction, store] = this.transaction('readonly');\n const found = new Map<string, MetaEntry | null>();\n for (const path of missing) {\n const request = store.get(path);\n request.onsuccess = () => void found.set(path, request.result ?? null);\n }\n await settle(transaction, () => undefined);\n if (generation === this.generation)\n for (const [path, entry] of found) this.cache.set(path, entry);\n return paths.map(\n (path) => (found.has(path) ? found.get(path) : this.cache.get(path)) ?? undefined\n );\n }\n return paths.map((path) => this.cache.get(path) ?? undefined);\n }\n\n async fresh(paths: readonly string[]): Promise<Array<MetaEntry | undefined>> {\n const [transaction, store] = this.transaction('readonly');\n const requests = paths.map((path) => store.get(path));\n return settle(transaction, () =>\n requests.map((request) => (request.result as MetaEntry | undefined) ?? undefined)\n );\n }\n\n async update(path: string, change: MetaChange): Promise<void> {\n this.settleRemoves();\n const [transaction, store] = this.transaction('readwrite');\n const request = store.get(path);\n let next: MetaEntry | undefined;\n request.onsuccess = () => {\n next = change(request.result);\n if (next) store.put(next);\n else store.delete(path);\n };\n await settle(transaction, () => undefined);\n this.changed({ paths: [path] });\n this.cache.set(path, next ?? null);\n }\n\n async updateMany(changes: ReadonlyArray<MetaUpdate>): Promise<void> {\n if (changes.length === 0) return;\n this.settleRemoves();\n const [transaction, store] = this.transaction('readwrite');\n const next = new Map<string, MetaEntry | null>();\n for (const { path, change } of changes) {\n const request = store.get(path);\n request.onsuccess = () => {\n const entry = change(request.result);\n next.set(path, entry ?? null);\n if (entry) store.put(entry);\n else store.delete(path);\n };\n }\n await settle(transaction, () => undefined);\n this.changed({ paths: changes.map(({ path }) => path) });\n for (const [path, entry] of next) this.cache.set(path, entry);\n }\n\n close(): void {\n this.channel.close();\n this.db.close();\n }\n\n async move(\n from: string,\n to: string,\n root: (entry: MetaEntry | undefined) => MetaEntry,\n left?: MetaEntry\n ) {\n this.settleRemoves();\n const [transaction, store] = this.transaction('readwrite');\n store.delete(to);\n store.delete(descendants(to));\n const source = store.get(from);\n const below = store.getAll(descendants(from));\n below.onsuccess = () => {\n store.delete(from);\n store.delete(descendants(from));\n for (const entry of below.result as MetaEntry[]) {\n store.put(moved(entry, to + entry.path.slice(from.length)));\n }\n store.put(moved(root(source.result), to));\n if (left) store.put(left);\n };\n await settle(transaction, () => undefined);\n this.changed({ trees: [from, to], moved: { from, to } });\n }\n\n absent(path: string): boolean {\n return this.cache.has(path) && this.cache.get(path) === null;\n }\n\n private removing = new Map<string, string>();\n private removeTimer: ReturnType<typeof setTimeout> | undefined;\n\n async remove(paths: readonly string[], left?: MetaEntry): Promise<void> {\n this.settleRemoves();\n return this.removeNow(paths, left);\n }\n\n async removeFile(path: string): Promise<void> {\n const known = this.cache.get(path);\n if (!known) return this.remove([path]);\n this.generation++;\n this.cache.set(path, null);\n this.removing.set(path, JSON.stringify(known));\n if (this.removing.size >= REMOVE_BATCH) return this.flushRemoves();\n this.removeTimer ??= setTimeout(\n () => void this.flushRemoves().catch(() => undefined),\n REMOVE_WAIT_MS\n );\n }\n\n private async removeNow(paths: readonly string[], left?: MetaEntry): Promise<void> {\n const [transaction, store] = this.transaction('readwrite');\n for (const path of paths) {\n store.delete(path);\n store.delete(descendants(path));\n }\n if (left) store.put(left);\n await settle(transaction, () => undefined);\n this.changed({ trees: paths });\n if (left) this.cache.set(left.path, left);\n }\n\n private settleRemoves(): void {\n if (this.removing.size > 0) void this.flushRemoves().catch(() => undefined);\n }\n\n private flushRemoves(): Promise<void> {\n clearTimeout(this.removeTimer);\n this.removeTimer = undefined;\n const batch = this.removing;\n if (batch.size === 0) return Promise.resolve();\n this.removing = new Map();\n const [transaction, store] = this.transaction('readwrite');\n for (const [path, seen] of batch) {\n const request = store.get(path);\n request.onsuccess = () => {\n if (request.result && JSON.stringify(request.result) === seen) store.delete(path);\n };\n }\n const paths = [...batch.keys()];\n return settle(transaction, () => void this.channel.postMessage({ paths }));\n }\n\n async links(dir: string): Promise<MetaEntry[]> {\n this.settleRemoves();\n const [transaction, store] = this.transaction('readonly');\n const request = store.index('dir').getAll(dir);\n return settle(transaction, () => request.result as MetaEntry[]);\n }\n\n async under(path: string): Promise<MetaEntry[]> {\n this.settleRemoves();\n const [transaction, store] = this.transaction('readonly');\n const self = store.get(path);\n const below = store.getAll(descendants(path));\n return settle(transaction, () =>\n [self.result as MetaEntry | undefined, ...(below.result as MetaEntry[])].filter(\n (entry): entry is MetaEntry => entry !== undefined\n )\n );\n }\n\n async all(): Promise<MetaEntry[]> {\n this.settleRemoves();\n const [transaction, store] = this.transaction('readonly');\n const request = store.getAll();\n return settle(transaction, () => request.result as MetaEntry[]);\n }\n}\n\nexport function openMetaDb(name: string, factory: IDBFactory): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = factory.open(name, META_VERSION);\n request.onupgradeneeded = (event) => {\n if (event.oldVersion < 1) {\n request.result.createObjectStore(META_STORE, { keyPath: 'path' }).createIndex('dir', 'dir');\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n}\n\nexport async function openMeta(name: string, factory: IDBFactory): Promise<IndexedDbMeta> {\n return new IndexedDbMeta(await openMetaDb(name, factory));\n}\n", "export interface FsNotice {\n paths?: readonly string[];\n trees?: readonly string[];\n}\n\nexport function dirsChannel(metadata: string): string {\n return `slicc-kernel-dirs:${metadata}`;\n}\n\nexport function noticeOf(data: unknown): { paths: string[]; trees: string[]; outside?: true } {\n if (Array.isArray(data)) return { paths: data.filter((p) => typeof p === 'string'), trees: [] };\n const notice = (data ?? {}) as FsNotice;\n const strings = (list: unknown) =>\n Array.isArray(list) ? list.filter((p): p is string => typeof p === 'string') : [];\n return { paths: strings(notice.paths), trees: strings(notice.trees), outside: true };\n}\n", "export interface FsStat {\n isFile: boolean;\n isDirectory: boolean;\n isSymbolicLink: boolean;\n isSocket?: boolean;\n isFifo?: boolean;\n size: number;\n mode: number;\n mtime: Date;\n atime: Date;\n ctime: Date;\n ino: number;\n nlink?: number;\n dev?: number;\n readonly?: boolean;\n maxFile?: number;\n ranged?: boolean;\n linkable?: boolean;\n version?: string;\n uid?: number;\n gid?: number;\n}\n\nexport type UsersMode = 'off' | 'report' | 'enforce';\n\nexport const DEFAULT_USERS: UsersMode = 'enforce';\n\nexport interface Owner {\n uid: number;\n gid: number;\n}\n\nexport interface Perm {\n uid: number;\n gid: number;\n mode?: number;\n link?: string;\n}\n\nexport interface NewOwner extends Owner {\n mode?: number;\n parents?: number;\n socket?: boolean;\n fifo?: boolean;\n}\n\nexport interface CopyOptions {\n exclusive: boolean;\n owner?: NewOwner;\n}\n\nexport interface OwnerChange {\n uid?: number;\n gid?: number;\n follow?: boolean;\n kind?: 'chown' | 'adopt' | 'new';\n mode?: number;\n}\n\nexport interface HeldEntry {\n writeFile: KernelFs['writeFile'];\n direct: boolean;\n}\n\nexport interface Peers {\n joined(): Promise<unknown>;\n crowded(): boolean;\n watch(listener: (crowded: boolean) => void): void;\n fresh?(): void;\n}\n\nexport interface KernelFs {\n resolvePath(base: string, path: string): string;\n exclusive?<T>(path: string, run: (held: HeldEntry) => Promise<T>, follow?: boolean): Promise<T>;\n readFile(path: string): Promise<string>;\n readFileBuffer(path: string): Promise<Uint8Array>;\n writeFile(path: string, content: Uint8Array | string, owner?: NewOwner): Promise<void>;\n exists(path: string): Promise<boolean>;\n stat(path: string): Promise<FsStat>;\n lstat(path: string): Promise<FsStat>;\n readdir(path: string): Promise<string[]>;\n readdirStat(path: string): Promise<Array<[string, FsStat | null]>>;\n mkdir(path: string, options?: { recursive?: boolean; owner?: NewOwner }): Promise<void>;\n rm(\n path: string,\n options?: { recursive?: boolean; force?: boolean; file?: boolean }\n ): Promise<void>;\n rename(from: string, to: string): Promise<void>;\n link(from: string, to: string, follow?: boolean): Promise<void>;\n links?(path: string): boolean;\n symlink(target: string, path: string, owner?: NewOwner): Promise<void>;\n readlink(path: string): Promise<string>;\n realpath?(path: string, follow: boolean): Promise<string>;\n createExclusive?(path: string, owner?: NewOwner): Promise<void>;\n copyFile?(from: string, to: string, options: CopyOptions): Promise<void>;\n readonly rootName?: string;\n chown?(path: string, change: OwnerChange): Promise<void>;\n trackOwners?(): void;\n onPeer?(settle: () => Promise<void>): void;\n heldBy?(held: (dir: string) => readonly string[]): void;\n remoteChanges?(\n listener: (change: {\n paths: readonly string[];\n trees?: readonly string[];\n moved?: { from: string; to: string };\n content?: true;\n }) => void\n ): () => void;\n peers?(): Peers | undefined;\n crossings?(mounted: (path: string) => boolean): void;\n ancestry?(path: string): Promise<Array<Perm | undefined>>;\n hasOwner?(path: string): Promise<boolean>;\n chmod(path: string, mode: number): Promise<void>;\n append?(path: string, bytes: Uint8Array): Promise<number>;\n utimes(path: string, atime: Date, mtime: Date): Promise<void>;\n lutimes?(path: string, atime: Date, mtime: Date): Promise<void>;\n pread?(path: string, offset: number, length: number, version?: string): Promise<Uint8Array>;\n pwrite?(path: string, offset: number, bytes: Uint8Array, transfer?: boolean): Promise<void>;\n truncate?(path: string, size: number): Promise<void>;\n protect?(prefixes: readonly string[], versions?: boolean): void;\n unguarded?(): KernelFs;\n noLinks?(): KernelFs;\n mayChange?(path: string, follow: boolean, whole?: boolean): Promise<void>;\n commandTarget?(path: string): Promise<string | undefined>;\n readVersioned?(path: string, cached?: boolean): Promise<{ bytes: Uint8Array; version: string }>;\n version?(path: string, cached?: boolean): Promise<string>;\n opfsCalls?(): number;\n renameWaits?(): {\n acks: number;\n busy: number;\n waits: number;\n queries: number;\n ackMs: readonly number[];\n };\n opfsOps?(): number;\n}\n\nexport type RangedOps = Required<Pick<KernelFs, 'pread' | 'pwrite' | 'truncate'>>;\n\nexport function rangedOps(fs: Partial<RangedOps>): RangedOps | undefined {\n const { pread, pwrite, truncate } = fs;\n if (!pread || !pwrite || !truncate) return undefined;\n return { pread: pread.bind(fs), pwrite: pwrite.bind(fs), truncate: truncate.bind(fs) };\n}\n\nexport async function lutimesOf(\n fs: KernelFs,\n path: string,\n atime: Date,\n mtime: Date\n): Promise<void> {\n if (fs.lutimes) return fs.lutimes(path, atime, mtime);\n if ((await fs.lstat(path)).isSymbolicLink) throw fsError('EOPNOTSUPP', path);\n return fs.utimes(path, atime, mtime);\n}\n\nexport function mayLink(fs: { links?(path: string): boolean }, path: string): boolean {\n return fs.links?.(path) ?? true;\n}\n\nexport function modeOption(mode: unknown): number {\n if (!Number.isInteger(mode) || (mode as number) < 0 || (mode as number) > 0o7777) {\n throw fsError('EINVAL', `not a mode: ${String(mode)}`);\n }\n return mode as number;\n}\n\nexport function fsError(code: string, path: string): Error & { code: string } {\n return Object.assign(new Error(`${code}: ${path}`), { code });\n}\n\nexport function normalizePath(path: string): string {\n const parts: string[] = [];\n for (const part of path.split('/')) {\n if (part === '' || part === '.') continue;\n if (part === '..') parts.pop();\n else parts.push(part);\n }\n return `/${parts.join('/')}`;\n}\n\nexport function resolvePath(base: string, path: string): string {\n return normalizePath(path.startsWith('/') ? path : `${base}/${path}`);\n}\n\nexport function inodeOf(path: string): number {\n let h1 = 0xdeadbeef;\n let h2 = 0x41c6ce57;\n for (let i = 0; i < path.length; i++) {\n const c = path.charCodeAt(i);\n h1 = Math.imul(h1 ^ c, 2654435761);\n h2 = Math.imul(h2 ^ c, 1597334677);\n }\n h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);\n h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);\n return 4294967296 * (2097151 & h2) + (h1 >>> 0) || 1;\n}\n\nexport interface Redirect {\n of: string;\n to: string;\n}\n\nexport function redirected(of: string, to: string): Error {\n return Object.assign(fsError('EXDEV', `${of} leads to the mount at ${to}`), {\n redirect: { of: normalizePath(of), to: normalizePath(to) },\n });\n}\n\nexport function redirectOf(err: unknown): Redirect | undefined {\n return (err as { redirect?: Redirect } | null)?.redirect;\n}\n", "import { META_DB, type MetaEntry, openMeta } from './fs/meta.ts';\nimport { dirsChannel, type FsNotice } from './fs/notice.ts';\nimport { fsError, normalizePath } from './fs/types.ts';\n\nexport type { FsNotice };\n\nexport interface MetadataEntry {\n path: string;\n mode?: number;\n uid?: number;\n gid?: number;\n}\n\nexport interface WriteMetadataOptions {\n metadata?: string;\n indexedDB?: IDBFactory;\n}\n\nconst MAX_ID = 0xfffffffe;\n\nfunction id(value: unknown, what: string): number {\n if (!Number.isInteger(value) || (value as number) < 0 || (value as number) > MAX_ID) {\n throw fsError('EINVAL', `not a ${what}: ${String(value)}`);\n }\n return value as number;\n}\n\nfunction checked(entry: MetadataEntry): MetadataEntry {\n if (!String(entry.path).startsWith('/'))\n throw fsError('EINVAL', `not an absolute path: ${entry.path}`);\n const path = normalizePath(String(entry.path));\n if ((entry.uid === undefined) !== (entry.gid === undefined)) {\n throw fsError('EINVAL', `${path}: give both uid and gid, or neither`);\n }\n const mode = entry.mode;\n if (mode !== undefined && (!Number.isInteger(mode) || mode < 0 || mode > 0o7777)) {\n throw fsError('EINVAL', `${path}: not a mode: ${String(mode)}`);\n }\n return {\n path,\n ...(mode !== undefined ? { mode } : {}),\n ...(entry.uid !== undefined ? { uid: id(entry.uid, 'uid'), gid: id(entry.gid, 'gid') } : {}),\n };\n}\n\nasync function present(root: FileSystemDirectoryHandle, path: string): Promise<boolean> {\n const parts = path.split('/').filter(Boolean);\n let dir = root;\n for (const [i, name] of parts.entries()) {\n const last = i === parts.length - 1;\n try {\n dir = await dir.getDirectoryHandle(name);\n } catch {\n if (!last) return false;\n return dir.getFileHandle(name).then(\n () => true,\n () => false\n );\n }\n }\n return true;\n}\n\nexport async function writeMetadata(\n root: FileSystemDirectoryHandle,\n entries: readonly MetadataEntry[],\n options: WriteMetadataOptions = {}\n): Promise<void> {\n const merged = new Map<string, MetadataEntry>();\n for (const want of entries.map(checked))\n merged.set(want.path, { ...merged.get(want.path), ...want });\n const wanted = [...merged.values()];\n for (const { path } of wanted) {\n if (!(await present(root, path))) throw fsError('ENOENT', path);\n }\n const factory = options.indexedDB ?? globalThis.indexedDB;\n const store = await openMeta(options.metadata ?? META_DB, factory);\n const ctimeMs = Date.now();\n try {\n await store.updateMany(\n wanted.map((want) => ({\n path: want.path,\n change: (entry: MetaEntry | undefined): MetaEntry => ({\n ...entry,\n path: want.path,\n ...(want.mode !== undefined ? { mode: want.mode } : {}),\n ...(want.uid !== undefined ? { uid: want.uid, gid: want.gid as number } : {}),\n ctimeMs,\n }),\n }))\n );\n } finally {\n store.close();\n }\n}\n\nexport interface PostFsNoticeOptions {\n metadata?: string;\n}\n\nexport function postFsNotice(notice: FsNotice, options: PostFsNoticeOptions = {}): void {\n const absolute = (list: readonly string[] | undefined) =>\n (list ?? []).map((path) => {\n if (!String(path).startsWith('/')) throw fsError('EINVAL', `not an absolute path: ${path}`);\n return normalizePath(String(path));\n });\n const paths = absolute(notice.paths);\n const trees = absolute(notice.trees);\n if (paths.length === 0 && trees.length === 0) return;\n const channel = new BroadcastChannel(dirsChannel(options.metadata ?? META_DB));\n try {\n channel.postMessage({ paths, trees });\n } finally {\n channel.close();\n }\n}\n"],
5
- "mappings": ";AAAA,SAAS,SAAS,MAAkC;AAClD,MAAI,SAAS,OAAO,SAAS,GAAI,QAAO;AACxC,QAAM,KAAK,KAAK,YAAY,GAAG;AAC/B,SAAO,MAAM,IAAI,MAAM,KAAK,MAAM,GAAG,EAAE;AACzC;AAEO,IAAM,UAAN,MAAiB;AAAA,EACL,SAAS,oBAAI,IAAe;AAAA,EAC5B,WAAW,oBAAI,IAAyB;AAAA,EAEzD,IAAI,OAAe;AACjB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA,EAEA,IAAI,MAAuB;AACzB,WAAO,KAAK,OAAO,IAAI,IAAI;AAAA,EAC7B;AAAA,EAEA,IAAI,MAA6B;AAC/B,WAAO,KAAK,OAAO,IAAI,IAAI;AAAA,EAC7B;AAAA,EAEA,OAAiC;AAC/B,WAAO,KAAK,OAAO,KAAK;AAAA,EAC1B;AAAA,EAEA,IAAI,MAAc,OAAgB;AAChC,QAAI,CAAC,KAAK,OAAO,IAAI,IAAI,EAAG,MAAK,KAAK,IAAI;AAC1C,SAAK,OAAO,IAAI,MAAM,KAAK;AAC3B,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,MAAuB;AAC5B,QAAI,CAAC,KAAK,OAAO,OAAO,IAAI,EAAG,QAAO;AACtC,SAAK,MAAM,IAAI;AACf,WAAO;AAAA,EACT;AAAA,EAEA,QAAQ,MAAwB;AAC9B,UAAM,MAAgB,CAAC;AACvB,UAAM,QAAQ,CAAC,IAAI;AACnB,aAAS,OAAO,MAAM,IAAI,GAAG,SAAS,QAAW,OAAO,MAAM,IAAI,GAAG;AACnE,UAAI,KAAK,OAAO,IAAI,IAAI,EAAG,KAAI,KAAK,IAAI;AACxC,YAAM,QAAQ,KAAK,SAAS,IAAI,IAAI;AACpC,UAAI,MAAO,YAAW,SAAS,MAAO,OAAM,KAAK,KAAK;AAAA,IACxD;AACA,WAAO;AAAA,EACT;AAAA,EAEA,UAAyC;AACvC,WAAO,KAAK,OAAO,QAAQ;AAAA,EAC7B;AAAA,EAEA,WAAW,MAAoB;AAC7B,UAAM,QAAQ,CAAC,IAAI;AACnB,aAAS,OAAO,MAAM,IAAI,GAAG,SAAS,QAAW,OAAO,MAAM,IAAI,GAAG;AACnE,WAAK,OAAO,OAAO,IAAI;AACvB,YAAM,QAAQ,KAAK,SAAS,IAAI,IAAI;AACpC,UAAI,MAAO,YAAW,SAAS,MAAO,OAAM,KAAK,KAAK;AACtD,WAAK,SAAS,OAAO,IAAI;AAAA,IAC3B;AACA,SAAK,MAAM,IAAI;AAAA,EACjB;AAAA,EAEA,QAAc;AACZ,SAAK,OAAO,MAAM;AAClB,SAAK,SAAS,MAAM;AAAA,EACtB;AAAA,EAEQ,KAAK,MAAoB;AAC/B,aAAS,QAAQ,MAAM,SAAS,SAAS,IAAI,GAAG,WAAW,UAAa;AACtE,YAAM,MAAM,KAAK,SAAS,IAAI,MAAM;AACpC,UAAI,KAAK,IAAI,KAAK,EAAG;AACrB,UAAI,IAAK,KAAI,IAAI,KAAK;AAAA,UACjB,MAAK,SAAS,IAAI,QAAQ,oBAAI,IAAI,CAAC,KAAK,CAAC,CAAC;AAC/C,cAAQ;AACR,eAAS,SAAS,MAAM;AAAA,IAC1B;AAAA,EACF;AAAA,EAEQ,MAAM,MAAoB;AAChC,aAAS,QAAQ,MAAM,SAAS,SAAS,IAAI,GAAG,WAAW,UAAa;AACtE,UAAI,KAAK,OAAO,IAAI,KAAK,KAAK,KAAK,SAAS,IAAI,KAAK,EAAG;AACxD,YAAM,MAAM,KAAK,SAAS,IAAI,MAAM;AACpC,WAAK,OAAO,KAAK;AACjB,UAAI,OAAO,IAAI,OAAO,EAAG;AACzB,WAAK,SAAS,OAAO,MAAM;AAC3B,cAAQ;AACR,eAAS,SAAS,MAAM;AAAA,IAC1B;AAAA,EACF;AACF;;;ACjCO,IAAM,UAAU;AAChB,IAAM,eAAe;AACrB,IAAM,aAAa;AAE1B,SAASA,UAAS,MAAsB;AACtC,SAAO,KAAK,MAAM,GAAG,KAAK,YAAY,GAAG,CAAC,KAAK;AACjD;AAEA,SAAS,MAAM,OAAkB,MAAyB;AACxD,SAAO,MAAM,SAAS,SAAY,EAAE,GAAG,OAAO,KAAK,IAAI,EAAE,GAAG,OAAO,MAAM,KAAKA,UAAS,IAAI,EAAE;AAC/F;AAiEA,SAAS,YAAY,MAA2B;AAC9C,SAAO,YAAY,MAAM,GAAG,IAAI,KAAK,GAAG,IAAI,KAAK,OAAO,IAAI;AAC9D;AAEA,SAAS,OAAU,aAA6B,OAA4B;AAC1E,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,gBAAY,aAAa,MAAM,QAAQ,MAAM,CAAC;AAC9C,gBAAY,UAAU,MACpB,OAAO,YAAY,SAAS,IAAI,MAAM,8BAA8B,CAAC;AAAA,EACzE,CAAC;AACH;AAQA,IAAM,eAAe;AACrB,IAAM,iBAAiB;AAEhB,IAAM,gBAAN,MAAyC;AAAA,EAC7B;AAAA,EACA,QAAQ,IAAI,QAA0B;AAAA,EACtC;AAAA,EACT,aAAa;AAAA,EACJ,YAAY,oBAAI,IAAoC;AAAA,EAErE,OAAO,UAAgD;AACrD,SAAK,UAAU,IAAI,QAAQ;AAAA,EAC7B;AAAA,EAEA,YAAY,IAAiB;AAC3B,SAAK,KAAK;AACV,OAAG,kBAAkB,MAAM,GAAG,MAAM;AACpC,SAAK,UAAU,IAAI,iBAAiB,qBAAqB,GAAG,IAAI,EAAE;AAClE,SAAK,QAAQ,YAAY,CAAC,EAAE,KAAK,MAAM;AACrC,WAAK,KAAK,IAAoB;AAC9B,iBAAW,YAAY,KAAK,UAAW,UAAS,IAAoB;AAAA,IACtE;AACA,IAAC,KAAK,QAAsD,QAAQ;AAAA,EACtE;AAAA,EAEA,YAAY,OAAgC;AAC1C,SAAK,KAAK,EAAE,OAAO,CAAC,GAAG,KAAK,EAAE,CAAC;AAAA,EACjC;AAAA,EAEQ,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,GAAuB;AAC3D,SAAK;AACL,eAAW,QAAQ,MAAO,MAAK,MAAM,OAAO,IAAI;AAChD,eAAW,QAAQ,MAAO,MAAK,MAAM,WAAW,IAAI;AAAA,EACtD;AAAA,EAEQ,QAAQ,cAAkC;AAChD,SAAK,KAAK,YAAY;AACtB,SAAK,QAAQ,YAAY,YAAY;AAAA,EACvC;AAAA,EAEQ,YAAY,MAA4D;AAC9E,UAAM,cAAc,KAAK,GAAG,YAAY,YAAY,IAAI;AACxD,WAAO,CAAC,aAAa,YAAY,YAAY,UAAU,CAAC;AAAA,EAC1D;AAAA,EAEA,MAAM,IAAI,OAAiE;AACzE,UAAM,UAAU,MAAM,OAAO,CAAC,SAAS,CAAC,KAAK,MAAM,IAAI,IAAI,CAAC;AAC5D,QAAI,QAAQ,SAAS,GAAG;AACtB,WAAK,cAAc;AACnB,YAAM,aAAa,KAAK;AACxB,YAAM,CAAC,aAAa,KAAK,IAAI,KAAK,YAAY,UAAU;AACxD,YAAM,QAAQ,oBAAI,IAA8B;AAChD,iBAAW,QAAQ,SAAS;AAC1B,cAAM,UAAU,MAAM,IAAI,IAAI;AAC9B,gBAAQ,YAAY,MAAM,KAAK,MAAM,IAAI,MAAM,QAAQ,UAAU,IAAI;AAAA,MACvE;AACA,YAAM,OAAO,aAAa,MAAM,MAAS;AACzC,UAAI,eAAe,KAAK;AACtB,mBAAW,CAAC,MAAM,KAAK,KAAK,MAAO,MAAK,MAAM,IAAI,MAAM,KAAK;AAC/D,aAAO,MAAM;AAAA,QACX,CAAC,UAAU,MAAM,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,MAAM;AAAA,MAC1E;AAAA,IACF;AACA,WAAO,MAAM,IAAI,CAAC,SAAS,KAAK,MAAM,IAAI,IAAI,KAAK,MAAS;AAAA,EAC9D;AAAA,EAEA,MAAM,MAAM,OAAiE;AAC3E,UAAM,CAAC,aAAa,KAAK,IAAI,KAAK,YAAY,UAAU;AACxD,UAAM,WAAW,MAAM,IAAI,CAAC,SAAS,MAAM,IAAI,IAAI,CAAC;AACpD,WAAO;AAAA,MAAO;AAAA,MAAa,MACzB,SAAS,IAAI,CAAC,YAAa,QAAQ,UAAoC,MAAS;AAAA,IAClF;AAAA,EACF;AAAA,EAEA,MAAM,OAAO,MAAc,QAAmC;AAC5D,SAAK,cAAc;AACnB,UAAM,CAAC,aAAa,KAAK,IAAI,KAAK,YAAY,WAAW;AACzD,UAAM,UAAU,MAAM,IAAI,IAAI;AAC9B,QAAI;AACJ,YAAQ,YAAY,MAAM;AACxB,aAAO,OAAO,QAAQ,MAAM;AAC5B,UAAI,KAAM,OAAM,IAAI,IAAI;AAAA,UACnB,OAAM,OAAO,IAAI;AAAA,IACxB;AACA,UAAM,OAAO,aAAa,MAAM,MAAS;AACzC,SAAK,QAAQ,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;AAC9B,SAAK,MAAM,IAAI,MAAM,QAAQ,IAAI;AAAA,EACnC;AAAA,EAEA,MAAM,WAAW,SAAmD;AAClE,QAAI,QAAQ,WAAW,EAAG;AAC1B,SAAK,cAAc;AACnB,UAAM,CAAC,aAAa,KAAK,IAAI,KAAK,YAAY,WAAW;AACzD,UAAM,OAAO,oBAAI,IAA8B;AAC/C,eAAW,EAAE,MAAM,OAAO,KAAK,SAAS;AACtC,YAAM,UAAU,MAAM,IAAI,IAAI;AAC9B,cAAQ,YAAY,MAAM;AACxB,cAAM,QAAQ,OAAO,QAAQ,MAAM;AACnC,aAAK,IAAI,MAAM,SAAS,IAAI;AAC5B,YAAI,MAAO,OAAM,IAAI,KAAK;AAAA,YACrB,OAAM,OAAO,IAAI;AAAA,MACxB;AAAA,IACF;AACA,UAAM,OAAO,aAAa,MAAM,MAAS;AACzC,SAAK,QAAQ,EAAE,OAAO,QAAQ,IAAI,CAAC,EAAE,KAAK,MAAM,IAAI,EAAE,CAAC;AACvD,eAAW,CAAC,MAAM,KAAK,KAAK,KAAM,MAAK,MAAM,IAAI,MAAM,KAAK;AAAA,EAC9D;AAAA,EAEA,QAAc;AACZ,SAAK,QAAQ,MAAM;AACnB,SAAK,GAAG,MAAM;AAAA,EAChB;AAAA,EAEA,MAAM,KACJ,MACA,IACA,MACA,MACA;AACA,SAAK,cAAc;AACnB,UAAM,CAAC,aAAa,KAAK,IAAI,KAAK,YAAY,WAAW;AACzD,UAAM,OAAO,EAAE;AACf,UAAM,OAAO,YAAY,EAAE,CAAC;AAC5B,UAAM,SAAS,MAAM,IAAI,IAAI;AAC7B,UAAM,QAAQ,MAAM,OAAO,YAAY,IAAI,CAAC;AAC5C,UAAM,YAAY,MAAM;AACtB,YAAM,OAAO,IAAI;AACjB,YAAM,OAAO,YAAY,IAAI,CAAC;AAC9B,iBAAW,SAAS,MAAM,QAAuB;AAC/C,cAAM,IAAI,MAAM,OAAO,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM,CAAC,CAAC;AAAA,MAC5D;AACA,YAAM,IAAI,MAAM,KAAK,OAAO,MAAM,GAAG,EAAE,CAAC;AACxC,UAAI,KAAM,OAAM,IAAI,IAAI;AAAA,IAC1B;AACA,UAAM,OAAO,aAAa,MAAM,MAAS;AACzC,SAAK,QAAQ,EAAE,OAAO,CAAC,MAAM,EAAE,GAAG,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,EACzD;AAAA,EAEA,OAAO,MAAuB;AAC5B,WAAO,KAAK,MAAM,IAAI,IAAI,KAAK,KAAK,MAAM,IAAI,IAAI,MAAM;AAAA,EAC1D;AAAA,EAEQ,WAAW,oBAAI,IAAoB;AAAA,EACnC;AAAA,EAER,MAAM,OAAO,OAA0B,MAAiC;AACtE,SAAK,cAAc;AACnB,WAAO,KAAK,UAAU,OAAO,IAAI;AAAA,EACnC;AAAA,EAEA,MAAM,WAAW,MAA6B;AAC5C,UAAM,QAAQ,KAAK,MAAM,IAAI,IAAI;AACjC,QAAI,CAAC,MAAO,QAAO,KAAK,OAAO,CAAC,IAAI,CAAC;AACrC,SAAK;AACL,SAAK,MAAM,IAAI,MAAM,IAAI;AACzB,SAAK,SAAS,IAAI,MAAM,KAAK,UAAU,KAAK,CAAC;AAC7C,QAAI,KAAK,SAAS,QAAQ,aAAc,QAAO,KAAK,aAAa;AACjE,SAAK,gBAAgB;AAAA,MACnB,MAAM,KAAK,KAAK,aAAa,EAAE,MAAM,MAAM,MAAS;AAAA,MACpD;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,UAAU,OAA0B,MAAiC;AACjF,UAAM,CAAC,aAAa,KAAK,IAAI,KAAK,YAAY,WAAW;AACzD,eAAW,QAAQ,OAAO;AACxB,YAAM,OAAO,IAAI;AACjB,YAAM,OAAO,YAAY,IAAI,CAAC;AAAA,IAChC;AACA,QAAI,KAAM,OAAM,IAAI,IAAI;AACxB,UAAM,OAAO,aAAa,MAAM,MAAS;AACzC,SAAK,QAAQ,EAAE,OAAO,MAAM,CAAC;AAC7B,QAAI,KAAM,MAAK,MAAM,IAAI,KAAK,MAAM,IAAI;AAAA,EAC1C;AAAA,EAEQ,gBAAsB;AAC5B,QAAI,KAAK,SAAS,OAAO,EAAG,MAAK,KAAK,aAAa,EAAE,MAAM,MAAM,MAAS;AAAA,EAC5E;AAAA,EAEQ,eAA8B;AACpC,iBAAa,KAAK,WAAW;AAC7B,SAAK,cAAc;AACnB,UAAM,QAAQ,KAAK;AACnB,QAAI,MAAM,SAAS,EAAG,QAAO,QAAQ,QAAQ;AAC7C,SAAK,WAAW,oBAAI,IAAI;AACxB,UAAM,CAAC,aAAa,KAAK,IAAI,KAAK,YAAY,WAAW;AACzD,eAAW,CAAC,MAAM,IAAI,KAAK,OAAO;AAChC,YAAM,UAAU,MAAM,IAAI,IAAI;AAC9B,cAAQ,YAAY,MAAM;AACxB,YAAI,QAAQ,UAAU,KAAK,UAAU,QAAQ,MAAM,MAAM,KAAM,OAAM,OAAO,IAAI;AAAA,MAClF;AAAA,IACF;AACA,UAAM,QAAQ,CAAC,GAAG,MAAM,KAAK,CAAC;AAC9B,WAAO,OAAO,aAAa,MAAM,KAAK,KAAK,QAAQ,YAAY,EAAE,MAAM,CAAC,CAAC;AAAA,EAC3E;AAAA,EAEA,MAAM,MAAM,KAAmC;AAC7C,SAAK,cAAc;AACnB,UAAM,CAAC,aAAa,KAAK,IAAI,KAAK,YAAY,UAAU;AACxD,UAAM,UAAU,MAAM,MAAM,KAAK,EAAE,OAAO,GAAG;AAC7C,WAAO,OAAO,aAAa,MAAM,QAAQ,MAAqB;AAAA,EAChE;AAAA,EAEA,MAAM,MAAM,MAAoC;AAC9C,SAAK,cAAc;AACnB,UAAM,CAAC,aAAa,KAAK,IAAI,KAAK,YAAY,UAAU;AACxD,UAAM,OAAO,MAAM,IAAI,IAAI;AAC3B,UAAM,QAAQ,MAAM,OAAO,YAAY,IAAI,CAAC;AAC5C,WAAO;AAAA,MAAO;AAAA,MAAa,MACzB,CAAC,KAAK,QAAiC,GAAI,MAAM,MAAsB,EAAE;AAAA,QACvE,CAAC,UAA8B,UAAU;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,MAA4B;AAChC,SAAK,cAAc;AACnB,UAAM,CAAC,aAAa,KAAK,IAAI,KAAK,YAAY,UAAU;AACxD,UAAM,UAAU,MAAM,OAAO;AAC7B,WAAO,OAAO,aAAa,MAAM,QAAQ,MAAqB;AAAA,EAChE;AACF;AAEO,SAAS,WAAW,MAAc,SAA2C;AAClF,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,UAAU,QAAQ,KAAK,MAAM,YAAY;AAC/C,YAAQ,kBAAkB,CAAC,UAAU;AACnC,UAAI,MAAM,aAAa,GAAG;AACxB,gBAAQ,OAAO,kBAAkB,YAAY,EAAE,SAAS,OAAO,CAAC,EAAE,YAAY,OAAO,KAAK;AAAA,MAC5F;AAAA,IACF;AACA,YAAQ,YAAY,MAAM,QAAQ,QAAQ,MAAM;AAChD,YAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,EAC9C,CAAC;AACH;AAEA,eAAsB,SAAS,MAAc,SAA6C;AACxF,SAAO,IAAI,cAAc,MAAM,WAAW,MAAM,OAAO,CAAC;AAC1D;;;AChYO,SAAS,YAAY,UAA0B;AACpD,SAAO,qBAAqB,QAAQ;AACtC;;;ACgKO,SAAS,QAAQ,MAAc,MAAwC;AAC5E,SAAO,OAAO,OAAO,IAAI,MAAM,GAAG,IAAI,KAAK,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC;AAC9D;AAEO,SAAS,cAAc,MAAsB;AAClD,QAAM,QAAkB,CAAC;AACzB,aAAW,QAAQ,KAAK,MAAM,GAAG,GAAG;AAClC,QAAI,SAAS,MAAM,SAAS,IAAK;AACjC,QAAI,SAAS,KAAM,OAAM,IAAI;AAAA,QACxB,OAAM,KAAK,IAAI;AAAA,EACtB;AACA,SAAO,IAAI,MAAM,KAAK,GAAG,CAAC;AAC5B;;;ACjKA,IAAM,SAAS;AAEf,SAAS,GAAG,OAAgB,MAAsB;AAChD,MAAI,CAAC,OAAO,UAAU,KAAK,KAAM,QAAmB,KAAM,QAAmB,QAAQ;AACnF,UAAM,QAAQ,UAAU,SAAS,IAAI,KAAK,OAAO,KAAK,CAAC,EAAE;AAAA,EAC3D;AACA,SAAO;AACT;AAEA,SAAS,QAAQ,OAAqC;AACpD,MAAI,CAAC,OAAO,MAAM,IAAI,EAAE,WAAW,GAAG;AACpC,UAAM,QAAQ,UAAU,yBAAyB,MAAM,IAAI,EAAE;AAC/D,QAAM,OAAO,cAAc,OAAO,MAAM,IAAI,CAAC;AAC7C,MAAK,MAAM,QAAQ,YAAgB,MAAM,QAAQ,SAAY;AAC3D,UAAM,QAAQ,UAAU,GAAG,IAAI,qCAAqC;AAAA,EACtE;AACA,QAAM,OAAO,MAAM;AACnB,MAAI,SAAS,WAAc,CAAC,OAAO,UAAU,IAAI,KAAK,OAAO,KAAK,OAAO,OAAS;AAChF,UAAM,QAAQ,UAAU,GAAG,IAAI,iBAAiB,OAAO,IAAI,CAAC,EAAE;AAAA,EAChE;AACA,SAAO;AAAA,IACL;AAAA,IACA,GAAI,SAAS,SAAY,EAAE,KAAK,IAAI,CAAC;AAAA,IACrC,GAAI,MAAM,QAAQ,SAAY,EAAE,KAAK,GAAG,MAAM,KAAK,KAAK,GAAG,KAAK,GAAG,MAAM,KAAK,KAAK,EAAE,IAAI,CAAC;AAAA,EAC5F;AACF;AAEA,eAAe,QAAQ,MAAiC,MAAgC;AACtF,QAAM,QAAQ,KAAK,MAAM,GAAG,EAAE,OAAO,OAAO;AAC5C,MAAI,MAAM;AACV,aAAW,CAAC,GAAG,IAAI,KAAK,MAAM,QAAQ,GAAG;AACvC,UAAM,OAAO,MAAM,MAAM,SAAS;AAClC,QAAI;AACF,YAAM,MAAM,IAAI,mBAAmB,IAAI;AAAA,IACzC,QAAQ;AACN,UAAI,CAAC,KAAM,QAAO;AAClB,aAAO,IAAI,cAAc,IAAI,EAAE;AAAA,QAC7B,MAAM;AAAA,QACN,MAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAsB,cACpB,MACA,SACA,UAAgC,CAAC,GAClB;AACf,QAAM,SAAS,oBAAI,IAA2B;AAC9C,aAAW,QAAQ,QAAQ,IAAI,OAAO;AACpC,WAAO,IAAI,KAAK,MAAM,EAAE,GAAG,OAAO,IAAI,KAAK,IAAI,GAAG,GAAG,KAAK,CAAC;AAC7D,QAAM,SAAS,CAAC,GAAG,OAAO,OAAO,CAAC;AAClC,aAAW,EAAE,KAAK,KAAK,QAAQ;AAC7B,QAAI,CAAE,MAAM,QAAQ,MAAM,IAAI,EAAI,OAAM,QAAQ,UAAU,IAAI;AAAA,EAChE;AACA,QAAM,UAAU,QAAQ,aAAa,WAAW;AAChD,QAAM,QAAQ,MAAM,SAAS,QAAQ,YAAY,SAAS,OAAO;AACjE,QAAM,UAAU,KAAK,IAAI;AACzB,MAAI;AACF,UAAM,MAAM;AAAA,MACV,OAAO,IAAI,CAAC,UAAU;AAAA,QACpB,MAAM,KAAK;AAAA,QACX,QAAQ,CAAC,WAA6C;AAAA,UACpD,GAAG;AAAA,UACH,MAAM,KAAK;AAAA,UACX,GAAI,KAAK,SAAS,SAAY,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;AAAA,UACrD,GAAI,KAAK,QAAQ,SAAY,EAAE,KAAK,KAAK,KAAK,KAAK,KAAK,IAAc,IAAI,CAAC;AAAA,UAC3E;AAAA,QACF;AAAA,MACF,EAAE;AAAA,IACJ;AAAA,EACF,UAAE;AACA,UAAM,MAAM;AAAA,EACd;AACF;AAMO,SAAS,aAAa,QAAkB,UAA+B,CAAC,GAAS;AACtF,QAAM,WAAW,CAAC,UACf,QAAQ,CAAC,GAAG,IAAI,CAAC,SAAS;AACzB,QAAI,CAAC,OAAO,IAAI,EAAE,WAAW,GAAG,EAAG,OAAM,QAAQ,UAAU,yBAAyB,IAAI,EAAE;AAC1F,WAAO,cAAc,OAAO,IAAI,CAAC;AAAA,EACnC,CAAC;AACH,QAAM,QAAQ,SAAS,OAAO,KAAK;AACnC,QAAM,QAAQ,SAAS,OAAO,KAAK;AACnC,MAAI,MAAM,WAAW,KAAK,MAAM,WAAW,EAAG;AAC9C,QAAM,UAAU,IAAI,iBAAiB,YAAY,QAAQ,YAAY,OAAO,CAAC;AAC7E,MAAI;AACF,YAAQ,YAAY,EAAE,OAAO,MAAM,CAAC;AAAA,EACtC,UAAE;AACA,YAAQ,MAAM;AAAA,EAChB;AACF;",
4
+ "sourcesContent": ["function parentOf(path: string): string | undefined {\n if (path === '/' || path === '') return undefined;\n const at = path.lastIndexOf('/');\n return at <= 0 ? '/' : path.slice(0, at);\n}\n\nexport class PathMap<V> {\n private readonly values = new Map<string, V>();\n private readonly children = new Map<string, Set<string>>();\n\n get size(): number {\n return this.values.size;\n }\n\n has(path: string): boolean {\n return this.values.has(path);\n }\n\n get(path: string): V | undefined {\n return this.values.get(path);\n }\n\n keys(): IterableIterator<string> {\n return this.values.keys();\n }\n\n set(path: string, value: V): this {\n if (!this.values.has(path)) this.link(path);\n this.values.set(path, value);\n return this;\n }\n\n delete(path: string): boolean {\n if (!this.values.delete(path)) return false;\n this.prune(path);\n return true;\n }\n\n subtree(root: string): string[] {\n const out: string[] = [];\n const stack = [root];\n for (let path = stack.pop(); path !== undefined; path = stack.pop()) {\n if (this.values.has(path)) out.push(path);\n const below = this.children.get(path);\n if (below) for (const child of below) stack.push(child);\n }\n return out;\n }\n\n entries(): IterableIterator<[string, V]> {\n return this.values.entries();\n }\n\n deleteTree(root: string): void {\n const stack = [root];\n for (let path = stack.pop(); path !== undefined; path = stack.pop()) {\n this.values.delete(path);\n const below = this.children.get(path);\n if (below) for (const child of below) stack.push(child);\n this.children.delete(path);\n }\n this.prune(root);\n }\n\n clear(): void {\n this.values.clear();\n this.children.clear();\n }\n\n private link(path: string): void {\n for (let child = path, parent = parentOf(path); parent !== undefined; ) {\n const set = this.children.get(parent);\n if (set?.has(child)) return;\n if (set) set.add(child);\n else this.children.set(parent, new Set([child]));\n child = parent;\n parent = parentOf(parent);\n }\n }\n\n private prune(path: string): void {\n for (let child = path, parent = parentOf(path); parent !== undefined; ) {\n if (this.values.has(child) || this.children.has(child)) return;\n const set = this.children.get(parent);\n set?.delete(child);\n if (set && set.size > 0) return;\n this.children.delete(parent);\n child = parent;\n parent = parentOf(parent);\n }\n }\n}\n", "import { PathMap } from './path-map.ts';\nexport interface MetaEntry {\n path: string;\n mode?: number;\n atimeMs?: number;\n mtimeMs?: number;\n mtimeFor?: number;\n timesAt?: number;\n timesBy?: string;\n ctimeMs?: number;\n ino?: number;\n fid?: string;\n link?: string;\n socket?: true;\n fifo?: true;\n dir?: string;\n uid?: number;\n gid?: number;\n heir?: [number, number];\n writes?: number;\n epoch?: number;\n vacated?: true;\n rename?: {\n from: string;\n to: string;\n at: number;\n replace?: true;\n lock?: string;\n root?: { ino: number; uid?: number; gid?: number; mode?: number };\n };\n}\n\nexport type MetaChange = (entry: MetaEntry | undefined) => MetaEntry | undefined;\n\nexport interface MetaUpdate {\n path: string;\n change: MetaChange;\n}\n\nexport interface MetaStore {\n get(paths: readonly string[]): Promise<Array<MetaEntry | undefined>>;\n fresh?(paths: readonly string[]): Promise<Array<MetaEntry | undefined>>;\n update(path: string, change: MetaChange): Promise<void>;\n updateMany?(changes: ReadonlyArray<MetaUpdate>): Promise<void>;\n move(\n from: string,\n to: string,\n root: (entry: MetaEntry | undefined) => MetaEntry,\n left?: MetaEntry\n ): Promise<void>;\n remove(paths: readonly string[], left?: MetaEntry): Promise<void>;\n links(dir: string): Promise<MetaEntry[]>;\n under(path: string): Promise<MetaEntry[]>;\n all(): Promise<MetaEntry[]>;\n absent?(path: string): boolean;\n removeFile?(path: string): Promise<void>;\n forgetTrees?(trees: readonly string[]): void;\n}\n\nexport const META_DB = 'slicc-kernel';\nexport const META_VERSION = 1;\nexport const META_STORE = 'entries';\n\nfunction parentOf(path: string): string {\n return path.slice(0, path.lastIndexOf('/')) || '/';\n}\n\nfunction moved(entry: MetaEntry, path: string): MetaEntry {\n return entry.link === undefined ? { ...entry, path } : { ...entry, path, dir: parentOf(path) };\n}\n\nfunction under(path: string, root: string): boolean {\n return path === root || path.startsWith(`${root}/`);\n}\n\nexport class MemoryMeta implements MetaStore {\n private readonly entries = new PathMap<MetaEntry>();\n\n async get(paths: readonly string[]): Promise<Array<MetaEntry | undefined>> {\n return paths.map((path) => this.entries.get(path));\n }\n\n async fresh(paths: readonly string[]): Promise<Array<MetaEntry | undefined>> {\n return this.get(paths);\n }\n\n async update(path: string, change: MetaChange): Promise<void> {\n this.set(path, change(this.entries.get(path)));\n }\n\n private set(path: string, entry: MetaEntry | undefined): void {\n if (entry) this.entries.set(path, entry);\n else this.entries.delete(path);\n }\n\n async move(\n from: string,\n to: string,\n root: (entry: MetaEntry | undefined) => MetaEntry,\n left?: MetaEntry\n ) {\n await this.remove([to]);\n const carried = this.entries.subtree(from).map((path) => this.entries.get(path) as MetaEntry);\n for (const entry of carried) this.entries.delete(entry.path);\n for (const entry of carried) {\n const path = to + entry.path.slice(from.length);\n if (path !== to) this.entries.set(path, moved(entry, path));\n }\n this.entries.set(to, moved(root(carried.find((entry) => entry.path === from)), to));\n if (left) this.entries.set(from, left);\n }\n\n async remove(paths: readonly string[], left?: MetaEntry): Promise<void> {\n for (const path of paths) this.entries.deleteTree(path);\n if (left) this.entries.set(left.path, left);\n }\n\n absent(path: string): boolean {\n return !this.entries.has(path);\n }\n\n async links(dir: string): Promise<MetaEntry[]> {\n return [...this.entries.entries()].map(([, e]) => e).filter((entry) => entry.dir === dir);\n }\n\n async under(path: string): Promise<MetaEntry[]> {\n return [...this.entries.entries()].map(([, e]) => e).filter((entry) => under(entry.path, path));\n }\n\n async all(): Promise<MetaEntry[]> {\n return [...this.entries.entries()].map(([, e]) => e);\n }\n}\n\nfunction descendants(path: string): IDBKeyRange {\n return IDBKeyRange.bound(`${path}/`, `${path}0`, false, true);\n}\n\nfunction settle<T>(transaction: IDBTransaction, value: () => T): Promise<T> {\n return new Promise((resolve, reject) => {\n transaction.oncomplete = () => resolve(value());\n transaction.onabort = () =>\n reject(transaction.error ?? new Error('metadata transaction aborted'));\n });\n}\n\ninterface Invalidation {\n paths?: readonly string[];\n trees?: readonly string[];\n moved?: { from: string; to: string };\n}\n\nconst REMOVE_BATCH = 256;\nconst REMOVE_WAIT_MS = 5;\n\nexport class IndexedDbMeta implements MetaStore {\n private readonly db: IDBDatabase;\n private readonly cache = new PathMap<MetaEntry | null>();\n private readonly channel: BroadcastChannel;\n private generation = 0;\n private readonly listeners = new Set<(change: Invalidation) => void>();\n\n listen(listener: (change: Invalidation) => void): void {\n this.listeners.add(listener);\n }\n\n constructor(db: IDBDatabase) {\n this.db = db;\n db.onversionchange = () => db.close();\n this.channel = new BroadcastChannel(`slicc-kernel-meta:${db.name}`);\n this.channel.onmessage = ({ data }) => {\n this.drop(data as Invalidation);\n for (const listener of this.listeners) listener(data as Invalidation);\n };\n (this.channel as BroadcastChannel & { unref?: () => void }).unref?.();\n }\n\n forgetTrees(trees: readonly string[]): void {\n this.drop({ trees: [...trees] });\n }\n\n private drop({ paths = [], trees = [] }: Invalidation): void {\n this.generation++;\n for (const path of paths) this.cache.delete(path);\n for (const tree of trees) this.cache.deleteTree(tree);\n }\n\n private changed(invalidation: Invalidation): void {\n this.drop(invalidation);\n this.channel.postMessage(invalidation);\n }\n\n private transaction(mode: IDBTransactionMode): [IDBTransaction, IDBObjectStore] {\n const transaction = this.db.transaction(META_STORE, mode);\n return [transaction, transaction.objectStore(META_STORE)];\n }\n\n async get(paths: readonly string[]): Promise<Array<MetaEntry | undefined>> {\n const missing = paths.filter((path) => !this.cache.has(path));\n if (missing.length > 0) {\n this.settleRemoves();\n const generation = this.generation;\n const [transaction, store] = this.transaction('readonly');\n const found = new Map<string, MetaEntry | null>();\n for (const path of missing) {\n const request = store.get(path);\n request.onsuccess = () => void found.set(path, request.result ?? null);\n }\n await settle(transaction, () => undefined);\n if (generation === this.generation)\n for (const [path, entry] of found) this.cache.set(path, entry);\n return paths.map(\n (path) => (found.has(path) ? found.get(path) : this.cache.get(path)) ?? undefined\n );\n }\n return paths.map((path) => this.cache.get(path) ?? undefined);\n }\n\n async fresh(paths: readonly string[]): Promise<Array<MetaEntry | undefined>> {\n const [transaction, store] = this.transaction('readonly');\n const requests = paths.map((path) => store.get(path));\n return settle(transaction, () =>\n requests.map((request) => (request.result as MetaEntry | undefined) ?? undefined)\n );\n }\n\n async update(path: string, change: MetaChange): Promise<void> {\n this.settleRemoves();\n const [transaction, store] = this.transaction('readwrite');\n const request = store.get(path);\n let next: MetaEntry | undefined;\n request.onsuccess = () => {\n next = change(request.result);\n if (next) store.put(next);\n else store.delete(path);\n };\n await settle(transaction, () => undefined);\n this.changed({ paths: [path] });\n this.cache.set(path, next ?? null);\n }\n\n async updateMany(changes: ReadonlyArray<MetaUpdate>): Promise<void> {\n if (changes.length === 0) return;\n this.settleRemoves();\n const [transaction, store] = this.transaction('readwrite');\n const next = new Map<string, MetaEntry | null>();\n for (const { path, change } of changes) {\n const request = store.get(path);\n request.onsuccess = () => {\n const entry = change(request.result);\n next.set(path, entry ?? null);\n if (entry) store.put(entry);\n else store.delete(path);\n };\n }\n await settle(transaction, () => undefined);\n this.changed({ paths: changes.map(({ path }) => path) });\n for (const [path, entry] of next) this.cache.set(path, entry);\n }\n\n close(): void {\n this.channel.close();\n this.db.close();\n }\n\n async move(\n from: string,\n to: string,\n root: (entry: MetaEntry | undefined) => MetaEntry,\n left?: MetaEntry\n ) {\n this.settleRemoves();\n const [transaction, store] = this.transaction('readwrite');\n store.delete(to);\n store.delete(descendants(to));\n const source = store.get(from);\n const below = store.getAll(descendants(from));\n below.onsuccess = () => {\n store.delete(from);\n store.delete(descendants(from));\n for (const entry of below.result as MetaEntry[]) {\n store.put(moved(entry, to + entry.path.slice(from.length)));\n }\n store.put(moved(root(source.result), to));\n if (left) store.put(left);\n };\n await settle(transaction, () => undefined);\n this.changed({ trees: [from, to], moved: { from, to } });\n }\n\n absent(path: string): boolean {\n return this.cache.has(path) && this.cache.get(path) === null;\n }\n\n private removing = new Map<string, string>();\n private removeTimer: ReturnType<typeof setTimeout> | undefined;\n\n async remove(paths: readonly string[], left?: MetaEntry): Promise<void> {\n this.settleRemoves();\n return this.removeNow(paths, left);\n }\n\n async removeFile(path: string): Promise<void> {\n const known = this.cache.get(path);\n if (!known) return this.remove([path]);\n this.generation++;\n this.cache.set(path, null);\n this.removing.set(path, JSON.stringify(known));\n if (this.removing.size >= REMOVE_BATCH) return this.flushRemoves();\n this.removeTimer ??= setTimeout(\n () => void this.flushRemoves().catch(() => undefined),\n REMOVE_WAIT_MS\n );\n }\n\n private async removeNow(paths: readonly string[], left?: MetaEntry): Promise<void> {\n const [transaction, store] = this.transaction('readwrite');\n for (const path of paths) {\n store.delete(path);\n store.delete(descendants(path));\n }\n if (left) store.put(left);\n await settle(transaction, () => undefined);\n this.changed({ trees: paths });\n if (left) this.cache.set(left.path, left);\n }\n\n private settleRemoves(): void {\n if (this.removing.size > 0) void this.flushRemoves().catch(() => undefined);\n }\n\n private flushRemoves(): Promise<void> {\n clearTimeout(this.removeTimer);\n this.removeTimer = undefined;\n const batch = this.removing;\n if (batch.size === 0) return Promise.resolve();\n this.removing = new Map();\n const [transaction, store] = this.transaction('readwrite');\n for (const [path, seen] of batch) {\n const request = store.get(path);\n request.onsuccess = () => {\n if (request.result && JSON.stringify(request.result) === seen) store.delete(path);\n };\n }\n const paths = [...batch.keys()];\n return settle(transaction, () => void this.channel.postMessage({ paths }));\n }\n\n async links(dir: string): Promise<MetaEntry[]> {\n this.settleRemoves();\n const [transaction, store] = this.transaction('readonly');\n const request = store.index('dir').getAll(dir);\n return settle(transaction, () => request.result as MetaEntry[]);\n }\n\n async under(path: string): Promise<MetaEntry[]> {\n this.settleRemoves();\n const [transaction, store] = this.transaction('readonly');\n const self = store.get(path);\n const below = store.getAll(descendants(path));\n return settle(transaction, () =>\n [self.result as MetaEntry | undefined, ...(below.result as MetaEntry[])].filter(\n (entry): entry is MetaEntry => entry !== undefined\n )\n );\n }\n\n async all(): Promise<MetaEntry[]> {\n this.settleRemoves();\n const [transaction, store] = this.transaction('readonly');\n const request = store.getAll();\n return settle(transaction, () => request.result as MetaEntry[]);\n }\n}\n\nexport function openMetaDb(name: string, factory: IDBFactory): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = factory.open(name, META_VERSION);\n request.onupgradeneeded = (event) => {\n if (event.oldVersion < 1) {\n request.result.createObjectStore(META_STORE, { keyPath: 'path' }).createIndex('dir', 'dir');\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n });\n}\n\nexport async function openMeta(name: string, factory: IDBFactory): Promise<IndexedDbMeta> {\n return new IndexedDbMeta(await openMetaDb(name, factory));\n}\n", "export interface FsNotice {\n paths?: readonly string[];\n trees?: readonly string[];\n}\n\nexport function dirsChannel(metadata: string): string {\n return `slicc-kernel-dirs:${metadata}`;\n}\n\nexport function noticeOf(data: unknown): { paths: string[]; trees: string[]; outside?: true } {\n if (Array.isArray(data)) return { paths: data.filter((p) => typeof p === 'string'), trees: [] };\n const notice = (data ?? {}) as FsNotice;\n const strings = (list: unknown) =>\n Array.isArray(list) ? list.filter((p): p is string => typeof p === 'string') : [];\n return { paths: strings(notice.paths), trees: strings(notice.trees), outside: true };\n}\n", "export interface FsStat {\n isFile: boolean;\n isDirectory: boolean;\n isSymbolicLink: boolean;\n isSocket?: boolean;\n isFifo?: boolean;\n size: number;\n mode: number;\n mtime: Date;\n atime: Date;\n ctime: Date;\n ino: number;\n fid?: string;\n nlink?: number;\n dev?: number;\n readonly?: boolean;\n maxFile?: number;\n ranged?: boolean;\n linkable?: boolean;\n version?: string;\n uid?: number;\n gid?: number;\n}\n\nexport type UsersMode = 'off' | 'report' | 'enforce';\n\nexport const DEFAULT_USERS: UsersMode = 'enforce';\n\nexport interface Owner {\n uid: number;\n gid: number;\n}\n\nexport interface Perm {\n uid: number;\n gid: number;\n mode?: number;\n link?: string;\n}\n\nexport interface NewOwner extends Owner {\n mode?: number;\n parents?: number;\n socket?: boolean;\n fifo?: boolean;\n}\n\nexport interface CopyOptions {\n exclusive: boolean;\n owner?: NewOwner;\n}\n\nexport interface OwnerChange {\n uid?: number;\n gid?: number;\n follow?: boolean;\n kind?: 'chown' | 'adopt' | 'new';\n mode?: number;\n}\n\nexport interface HeldEntry {\n writeFile: KernelFs['writeFile'];\n direct: boolean;\n}\n\nexport interface Peers {\n joined(): Promise<unknown>;\n crowded(): boolean;\n watch(listener: (crowded: boolean) => void): void;\n fresh?(): void;\n}\n\nexport interface KernelFs {\n resolvePath(base: string, path: string): string;\n exclusive?<T>(path: string, run: (held: HeldEntry) => Promise<T>, follow?: boolean): Promise<T>;\n readFile(path: string): Promise<string>;\n readFileBuffer(path: string): Promise<Uint8Array>;\n writeFile(path: string, content: Uint8Array | string, owner?: NewOwner): Promise<void>;\n exists(path: string): Promise<boolean>;\n stat(path: string): Promise<FsStat>;\n lstat(path: string): Promise<FsStat>;\n readdir(path: string): Promise<string[]>;\n readdirStat(path: string): Promise<Array<[string, FsStat | null]>>;\n mkdir(path: string, options?: { recursive?: boolean; owner?: NewOwner }): Promise<void>;\n rm(\n path: string,\n options?: { recursive?: boolean; force?: boolean; file?: boolean }\n ): Promise<void>;\n rename(from: string, to: string): Promise<void>;\n link(from: string, to: string, follow?: boolean): Promise<void>;\n links?(path: string): boolean;\n symlink(target: string, path: string, owner?: NewOwner): Promise<void>;\n readlink(path: string): Promise<string>;\n realpath?(path: string, follow: boolean): Promise<string>;\n createExclusive?(path: string, owner?: NewOwner): Promise<void>;\n copyFile?(from: string, to: string, options: CopyOptions): Promise<void>;\n readonly rootName?: string;\n chown?(path: string, change: OwnerChange): Promise<void>;\n trackOwners?(): void;\n onPeer?(settle: () => Promise<void>): void;\n heldBy?(held: (dir: string) => readonly string[]): void;\n fileId?(path: string): Promise<string>;\n remoteChanges?(\n listener: (change: {\n paths: readonly string[];\n trees?: readonly string[];\n moved?: { from: string; to: string };\n content?: true;\n }) => void\n ): () => void;\n peers?(): Peers | undefined;\n crossings?(mounted: (path: string) => boolean): void;\n ancestry?(path: string): Promise<Array<Perm | undefined>>;\n hasOwner?(path: string): Promise<boolean>;\n chmod(path: string, mode: number): Promise<void>;\n append?(path: string, bytes: Uint8Array): Promise<number>;\n utimes(path: string, atime: Date, mtime: Date): Promise<void>;\n lutimes?(path: string, atime: Date, mtime: Date): Promise<void>;\n pread?(path: string, offset: number, length: number, version?: string): Promise<Uint8Array>;\n pwrite?(path: string, offset: number, bytes: Uint8Array, transfer?: boolean): Promise<void>;\n truncate?(path: string, size: number): Promise<void>;\n protect?(prefixes: readonly string[], versions?: boolean): void;\n unguarded?(): KernelFs;\n noLinks?(): KernelFs;\n mayChange?(path: string, follow: boolean, whole?: boolean): Promise<void>;\n commandTarget?(path: string): Promise<string | undefined>;\n readVersioned?(path: string, cached?: boolean): Promise<{ bytes: Uint8Array; version: string }>;\n version?(path: string, cached?: boolean): Promise<string>;\n opfsCalls?(): number;\n renameWaits?(): {\n acks: number;\n busy: number;\n waits: number;\n queries: number;\n ackMs: readonly number[];\n };\n opfsOps?(): number;\n}\n\nexport type RangedOps = Required<Pick<KernelFs, 'pread' | 'pwrite' | 'truncate'>>;\n\nexport function rangedOps(fs: Partial<RangedOps>): RangedOps | undefined {\n const { pread, pwrite, truncate } = fs;\n if (!pread || !pwrite || !truncate) return undefined;\n return { pread: pread.bind(fs), pwrite: pwrite.bind(fs), truncate: truncate.bind(fs) };\n}\n\nexport async function lutimesOf(\n fs: KernelFs,\n path: string,\n atime: Date,\n mtime: Date\n): Promise<void> {\n if (fs.lutimes) return fs.lutimes(path, atime, mtime);\n if ((await fs.lstat(path)).isSymbolicLink) throw fsError('EOPNOTSUPP', path);\n return fs.utimes(path, atime, mtime);\n}\n\nexport function mayLink(fs: { links?(path: string): boolean }, path: string): boolean {\n return fs.links?.(path) ?? true;\n}\n\nexport function modeOption(mode: unknown): number {\n if (!Number.isInteger(mode) || (mode as number) < 0 || (mode as number) > 0o7777) {\n throw fsError('EINVAL', `not a mode: ${String(mode)}`);\n }\n return mode as number;\n}\n\nexport function fsError(code: string, path: string): Error & { code: string } {\n return Object.assign(new Error(`${code}: ${path}`), { code });\n}\n\nexport function normalizePath(path: string): string {\n const parts: string[] = [];\n for (const part of path.split('/')) {\n if (part === '' || part === '.') continue;\n if (part === '..') parts.pop();\n else parts.push(part);\n }\n return `/${parts.join('/')}`;\n}\n\nexport function resolvePath(base: string, path: string): string {\n return normalizePath(path.startsWith('/') ? path : `${base}/${path}`);\n}\n\nexport function inodeOf(path: string): number {\n let h1 = 0xdeadbeef;\n let h2 = 0x41c6ce57;\n for (let i = 0; i < path.length; i++) {\n const c = path.charCodeAt(i);\n h1 = Math.imul(h1 ^ c, 2654435761);\n h2 = Math.imul(h2 ^ c, 1597334677);\n }\n h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);\n h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);\n return 4294967296 * (2097151 & h2) + (h1 >>> 0) || 1;\n}\n\nexport interface Redirect {\n of: string;\n to: string;\n}\n\nexport function redirected(of: string, to: string): Error {\n return Object.assign(fsError('EXDEV', `${of} leads to the mount at ${to}`), {\n redirect: { of: normalizePath(of), to: normalizePath(to) },\n });\n}\n\nexport function redirectOf(err: unknown): Redirect | undefined {\n return (err as { redirect?: Redirect } | null)?.redirect;\n}\n", "import { META_DB, type MetaEntry, openMeta } from './fs/meta.ts';\nimport { dirsChannel, type FsNotice } from './fs/notice.ts';\nimport { fsError, normalizePath } from './fs/types.ts';\n\nexport type { FsNotice };\n\nexport interface MetadataEntry {\n path: string;\n mode?: number;\n uid?: number;\n gid?: number;\n}\n\nexport interface WriteMetadataOptions {\n metadata?: string;\n indexedDB?: IDBFactory;\n}\n\nconst MAX_ID = 0xfffffffe;\n\nfunction id(value: unknown, what: string): number {\n if (!Number.isInteger(value) || (value as number) < 0 || (value as number) > MAX_ID) {\n throw fsError('EINVAL', `not a ${what}: ${String(value)}`);\n }\n return value as number;\n}\n\nfunction checked(entry: MetadataEntry): MetadataEntry {\n if (!String(entry.path).startsWith('/'))\n throw fsError('EINVAL', `not an absolute path: ${entry.path}`);\n const path = normalizePath(String(entry.path));\n if ((entry.uid === undefined) !== (entry.gid === undefined)) {\n throw fsError('EINVAL', `${path}: give both uid and gid, or neither`);\n }\n const mode = entry.mode;\n if (mode !== undefined && (!Number.isInteger(mode) || mode < 0 || mode > 0o7777)) {\n throw fsError('EINVAL', `${path}: not a mode: ${String(mode)}`);\n }\n return {\n path,\n ...(mode !== undefined ? { mode } : {}),\n ...(entry.uid !== undefined ? { uid: id(entry.uid, 'uid'), gid: id(entry.gid, 'gid') } : {}),\n };\n}\n\nasync function present(root: FileSystemDirectoryHandle, path: string): Promise<boolean> {\n const parts = path.split('/').filter(Boolean);\n let dir = root;\n for (const [i, name] of parts.entries()) {\n const last = i === parts.length - 1;\n try {\n dir = await dir.getDirectoryHandle(name);\n } catch {\n if (!last) return false;\n return dir.getFileHandle(name).then(\n () => true,\n () => false\n );\n }\n }\n return true;\n}\n\nexport async function writeMetadata(\n root: FileSystemDirectoryHandle,\n entries: readonly MetadataEntry[],\n options: WriteMetadataOptions = {}\n): Promise<void> {\n const merged = new Map<string, MetadataEntry>();\n for (const want of entries.map(checked))\n merged.set(want.path, { ...merged.get(want.path), ...want });\n const wanted = [...merged.values()];\n for (const { path } of wanted) {\n if (!(await present(root, path))) throw fsError('ENOENT', path);\n }\n const factory = options.indexedDB ?? globalThis.indexedDB;\n const store = await openMeta(options.metadata ?? META_DB, factory);\n const ctimeMs = Date.now();\n try {\n await store.updateMany(\n wanted.map((want) => ({\n path: want.path,\n change: (entry: MetaEntry | undefined): MetaEntry => ({\n ...entry,\n path: want.path,\n ...(want.mode !== undefined ? { mode: want.mode } : {}),\n ...(want.uid !== undefined ? { uid: want.uid, gid: want.gid as number } : {}),\n ctimeMs,\n }),\n }))\n );\n } finally {\n store.close();\n }\n}\n\nexport interface PostFsNoticeOptions {\n metadata?: string;\n}\n\nexport function postFsNotice(notice: FsNotice, options: PostFsNoticeOptions = {}): void {\n const absolute = (list: readonly string[] | undefined) =>\n (list ?? []).map((path) => {\n if (!String(path).startsWith('/')) throw fsError('EINVAL', `not an absolute path: ${path}`);\n return normalizePath(String(path));\n });\n const paths = absolute(notice.paths);\n const trees = absolute(notice.trees);\n if (paths.length === 0 && trees.length === 0) return;\n const channel = new BroadcastChannel(dirsChannel(options.metadata ?? META_DB));\n try {\n channel.postMessage({ paths, trees });\n } finally {\n channel.close();\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["parentOf"]
7
7
  }
@@ -696,6 +696,7 @@ function parseSyncFsStat(json2) {
696
696
  ...typeof s.atimeMs === "number" ? { atimeMs: s.atimeMs } : {},
697
697
  ...typeof s.ctimeMs === "number" ? { ctimeMs: s.ctimeMs } : {},
698
698
  ...typeof s.ino === "number" ? { ino: s.ino } : {},
699
+ ...typeof s.fid === "string" ? { fid: s.fid } : {},
699
700
  ...typeof s.nlink === "number" ? { nlink: s.nlink } : {},
700
701
  ...typeof s.dev === "number" ? { dev: s.dev } : {},
701
702
  ...s.readonly === true ? { readonly: true } : {},
@@ -2588,6 +2589,22 @@ var init_js_kernel = __esm({
2588
2589
  });
2589
2590
 
2590
2591
  // src/process/js/js-io.ts
2592
+ function readingInto(read2) {
2593
+ return (position, into, offset = 0, length = into.length - offset) => {
2594
+ const target = intoTarget(into, offset, length);
2595
+ const chunk = read2(position, length);
2596
+ target.into.set(chunk, target.at);
2597
+ return chunk.length;
2598
+ };
2599
+ }
2600
+ function readingIntoAsync(read2) {
2601
+ return async (position, into, offset = 0, length = into.length - offset) => {
2602
+ const target = intoTarget(into, offset, length);
2603
+ const chunk = await read2(position, length);
2604
+ target.into.set(chunk, target.at);
2605
+ return chunk.length;
2606
+ };
2607
+ }
2591
2608
  function intoTarget(into, offset, length) {
2592
2609
  if (!into) return void 0;
2593
2610
  if (!Number.isSafeInteger(offset) || offset < 0 || offset + length > into.length)
@@ -2947,6 +2964,13 @@ function allowed(may, what) {
2947
2964
  }
2948
2965
  function streamFile(fd, path, io, access) {
2949
2966
  const { live, end } = liveness(path);
2967
+ const readAsync = async (position, length) => {
2968
+ index2(position, "read");
2969
+ index2(length, "read");
2970
+ live();
2971
+ allowed(access.read, "read");
2972
+ return length === 0 ? new Uint8Array(0) : io.read(fd, Math.min(length, MAX_IO));
2973
+ };
2950
2974
  const file = {
2951
2975
  fd,
2952
2976
  path,
@@ -2954,13 +2978,8 @@ function streamFile(fd, path, io, access) {
2954
2978
  live();
2955
2979
  return 0;
2956
2980
  },
2957
- async read(position, length) {
2958
- index2(position, "read");
2959
- index2(length, "read");
2960
- live();
2961
- allowed(access.read, "read");
2962
- return length === 0 ? new Uint8Array(0) : io.read(fd, Math.min(length, MAX_IO));
2963
- },
2981
+ read: (position, length) => readAsync(position, length),
2982
+ readInto: readingIntoAsync((position, length) => readAsync(position, length)),
2964
2983
  async write(position, data) {
2965
2984
  index2(position, "write");
2966
2985
  live();
@@ -2984,6 +3003,13 @@ function streamFile(fd, path, io, access) {
2984
3003
  }
2985
3004
  function streamSyncFile(fd, path, io, access) {
2986
3005
  const { live, end } = liveness(path);
3006
+ const readSync = (position, length) => {
3007
+ index2(position, "read");
3008
+ index2(length, "read");
3009
+ live();
3010
+ allowed(access.read, "read");
3011
+ return length === 0 ? new Uint8Array(0) : io.read(fd, Math.min(length, MAX_IO));
3012
+ };
2987
3013
  const file = {
2988
3014
  fd,
2989
3015
  path,
@@ -2991,13 +3017,8 @@ function streamSyncFile(fd, path, io, access) {
2991
3017
  live();
2992
3018
  return 0;
2993
3019
  },
2994
- read(position, length) {
2995
- index2(position, "read");
2996
- index2(length, "read");
2997
- live();
2998
- allowed(access.read, "read");
2999
- return length === 0 ? new Uint8Array(0) : io.read(fd, Math.min(length, MAX_IO));
3000
- },
3020
+ read: (position, length) => readSync(position, length),
3021
+ readInto: readingInto((position, length) => readSync(position, length)),
3001
3022
  write(position, data) {
3002
3023
  index2(position, "write");
3003
3024
  live();
@@ -7164,7 +7185,7 @@ var KERNEL_VERSION, OS_RELEASE;
7164
7185
  var init_version = __esm({
7165
7186
  "src/version.ts"() {
7166
7187
  "use strict";
7167
- KERNEL_VERSION = true ? "1.147.10" : "0.0.0-dev";
7188
+ KERNEL_VERSION = true ? "1.148.0" : "0.0.0-dev";
7168
7189
  OS_RELEASE = "6.0.0-slicc";
7169
7190
  }
7170
7191
  });
@@ -11341,6 +11362,7 @@ function same(fs, path, id) {
11341
11362
  if (GONE2.has(err?.code ?? "")) return false;
11342
11363
  throw err;
11343
11364
  }
11365
+ if (id.startsWith("fid:")) return st.fid !== void 0 && id.startsWith(`fid:${st.fid}:`);
11344
11366
  const now = fileIdentity(st.ino, st.mtimeMs);
11345
11367
  return now === void 0 || now === id;
11346
11368
  }
@@ -11743,6 +11765,12 @@ function snapshotFile(path, bytes) {
11743
11765
  const live = () => {
11744
11766
  if (closed) throw new JsCallError("EBADF", path);
11745
11767
  };
11768
+ const read2 = (position, length) => {
11769
+ live();
11770
+ index2(position, "read");
11771
+ index2(length, "read");
11772
+ return bytes.slice(position, position + length);
11773
+ };
11746
11774
  return {
11747
11775
  fd: -1,
11748
11776
  path,
@@ -11750,12 +11778,8 @@ function snapshotFile(path, bytes) {
11750
11778
  live();
11751
11779
  return bytes.length;
11752
11780
  },
11753
- read: (position, length) => {
11754
- live();
11755
- index2(position, "read");
11756
- index2(length, "read");
11757
- return bytes.slice(position, position + length);
11758
- },
11781
+ read: read2,
11782
+ readInto: readingInto(read2),
11759
11783
  write: () => {
11760
11784
  throw new JsCallError("EBADF", path);
11761
11785
  },
@@ -15486,6 +15510,10 @@ async function fifoOpen(kernel, abs, options, io) {
15486
15510
  seekless(position, "read");
15487
15511
  return io.read(fd, length);
15488
15512
  },
15513
+ readInto: readingIntoAsync(async (position, length) => {
15514
+ seekless(position, "read");
15515
+ return io.read(fd, length);
15516
+ }),
15489
15517
  async write(position, data) {
15490
15518
  seekless(position, "write");
15491
15519
  await io.write(fd, data);