@ai-ecoverse/slicc-kernel 1.152.0 → 1.152.2

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 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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",
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?(\n path: string,\n offset: number,\n bytes: Uint8Array,\n transfer?: boolean,\n options?: PwriteOptions\n ): 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 fileIdWrites?(): number;\n}\n\nexport interface PwriteOptions {\n create?: false;\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;;;AChCO,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;;;ACjYO,SAAS,YAAY,UAA0B;AACpD,SAAO,qBAAqB,QAAQ;AACtC;;;AC6KO,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;;;AC9KA,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;",
6
6
  "names": ["parentOf"]
7
7
  }
@@ -1165,12 +1165,22 @@ var init_wasi_files = __esm({
1165
1165
  }
1166
1166
  return this.data;
1167
1167
  }
1168
+ spoiled = false;
1169
+ spoil() {
1170
+ this.spoiled = true;
1171
+ this.dirty = false;
1172
+ }
1173
+ live() {
1174
+ if (this.spoiled) throw new WasiError("ESTALE");
1175
+ }
1168
1176
  size() {
1177
+ this.live();
1169
1178
  if (this.ranged) return this.ranged.size();
1170
1179
  this.load();
1171
1180
  return this.length;
1172
1181
  }
1173
1182
  pread(max, at) {
1183
+ this.live();
1174
1184
  if (this.ranged) return this.ranged.read(at, max);
1175
1185
  const bytes = this.load();
1176
1186
  const n = Math.max(0, Math.min(max, this.length - at));
@@ -1180,6 +1190,7 @@ var init_wasi_files = __esm({
1180
1190
  if (this.maxFile !== void 0 && end > this.maxFile) throw new WasiError("EFBIG");
1181
1191
  }
1182
1192
  pwrite(bytes, at) {
1193
+ this.live();
1183
1194
  if (bytes.length === 0) return 0;
1184
1195
  const end = at + bytes.length;
1185
1196
  this.fits(end);
@@ -1199,6 +1210,7 @@ var init_wasi_files = __esm({
1199
1210
  return bytes.length;
1200
1211
  }
1201
1212
  append(bytes) {
1213
+ this.live();
1202
1214
  const { append } = this.fs;
1203
1215
  if (!append || this.orphaned) return void 0;
1204
1216
  this.moved?.(false);
@@ -1211,6 +1223,7 @@ var init_wasi_files = __esm({
1211
1223
  return end;
1212
1224
  }
1213
1225
  truncate(size) {
1226
+ this.live();
1214
1227
  this.fits(size);
1215
1228
  this.dirty = true;
1216
1229
  if (this.ranged) {
@@ -1246,6 +1259,7 @@ var init_wasi_files = __esm({
1246
1259
  return this.dirty;
1247
1260
  }
1248
1261
  contents() {
1262
+ this.live();
1249
1263
  if (this.ranged) return this.ranged.read(0, this.ranged.size());
1250
1264
  return this.load().slice(0, this.length);
1251
1265
  }
@@ -3945,6 +3959,15 @@ var init_wasi_fds = __esm({
3945
3959
  }
3946
3960
  }
3947
3961
  }
3962
+ synced(file) {
3963
+ try {
3964
+ file.flush();
3965
+ this.reported.delete(file.buffer);
3966
+ } catch (err) {
3967
+ this.reported.add(file.buffer);
3968
+ throw err;
3969
+ }
3970
+ }
3948
3971
  flushEarly() {
3949
3972
  for (const buffer of this.buffers.values()) {
3950
3973
  try {
@@ -3971,6 +3994,7 @@ var init_wasi_fds = __esm({
3971
3994
  try {
3972
3995
  buffer.prefetch();
3973
3996
  } catch {
3997
+ buffer.spoil();
3974
3998
  }
3975
3999
  }
3976
4000
  }
@@ -6295,7 +6319,7 @@ var init_wasi_host = __esm({
6295
6319
  }
6296
6320
  sync(fd) {
6297
6321
  const e = this.fds.get(fd);
6298
- if (e.type === "file") e.file.flush();
6322
+ if (e.type === "file") this.fds.synced(e.file);
6299
6323
  else if (e.type === "device") this.interrupted?.();
6300
6324
  else if (e.type === "kernel") {
6301
6325
  const kind = this.fds.kind(fd, e);
@@ -7189,7 +7213,7 @@ var KERNEL_VERSION, OS_RELEASE;
7189
7213
  var init_version = __esm({
7190
7214
  "src/version.ts"() {
7191
7215
  "use strict";
7192
- KERNEL_VERSION = true ? "1.152.0" : "0.0.0-dev";
7216
+ KERNEL_VERSION = true ? "1.152.2" : "0.0.0-dev";
7193
7217
  OS_RELEASE = "6.0.0-slicc";
7194
7218
  }
7195
7219
  });
@@ -11439,6 +11463,8 @@ var init_procfs = __esm({
11439
11463
  slicc_rename_ack_busy: (listing2) => `${listing2.renameAcks?.busy ?? 0}
11440
11464
  `,
11441
11465
  slicc_stale_fds: (listing2) => `${listing2.staleFds ?? 0}
11466
+ `,
11467
+ slicc_file_ids: (listing2) => `${listing2.fileIds ?? 0}
11442
11468
  `,
11443
11469
  slicc_rename_acks: (listing2) => {
11444
11470
  const samples = [...listing2.renameAcks?.ackMs ?? []].sort((a, b) => a - b);