/** * The Node adapters — importable only as `edfcore/node`, and NOT reachable from the universal * entry, which is the point. * * Layer 7. Keeping this module out of everything `edfcore` can reach is what lets the universal * entry be bundled for a browser without a polyfill and without a resolution alias, and a * `public-api.test.ts` walks the module graph from `src/index.ts` for `node:` to prove exactly * that. * * Two wordings have been wrong here. It said "the ONLY module in edfcore that imports anything * from `node:`" until 0.3.84 — `src/cli.ts` imports `node:fs/promises` and `node:process` and * ships as the `bin` entry, a Node program by definition that no import path reaches. The fix then * said "the only module REACHABLE FROM THE UNIVERSAL ENTRY that imports anything from `node:`", * which asserts the opposite of the invariant and contradicts the paragraph directly below it * (fixed in 0.3.103). Both shipped in `dist/node.d.ts` as this subpath's hover text. * * Two decisions are load-bearing. * * 1. Reads are POSITIONAL and LOOP. `FileHandle.read` is allowed to return fewer bytes than asked * — a signal interrupted the syscall, the file lives on a network mount — and a `ByteSource` * that passed a short buffer on would be indistinguishable from a truncated file. The loop * runs until `length` bytes have arrived; a genuine end of file falls out as an * `EdfSourceError` naming both counts. * 2. `fs.openAsBlob` is NEVER used, however tempting `blobSource(await openAsBlob(path))` looks. * It reports `size` modulo 2**32 and yields zeros above 4 GiB, which turns a 13 GB BDF into a * file that reads as silence with no error anywhere. * * TYPING. `src/` compiles with `types: []`, so `@types/node` is not available and must never be: * the published `.d.ts` may not reference it, or every consumer inherits a dependency on it. The * import below is therefore UNTYPED, and the minimal structural shape edfcore needs is declared * here instead — `FileHandleLike` and `NodeFsPromises`. A standing CI job compiles a consumer * against the real `@types/node` and asserts `fs.promises.FileHandle` is still assignable, which * is what stops the two drifting. * * The suppression on the import is the unconditional `ts-ignore` directive rather than * `@ts-expect-error`, and that is not laziness. Whether the specifier resolves depends on whether * a `@types/node` happens to be reachable at all: `config/tsconfig.build.json` compiles `src/` * alone and it is not, while `tsconfig.json` also pulls in a dev tool carrying a triple-slash * reference to it and it may be. `@ts-expect-error` errors for being UNUSED in the second case, so * it would break whichever of the two configurations the machine happens to disagree with. */ import type { ClosableByteSource } from './types.js'; /** * The RETURN type of both functions below, and the option bag their `read` takes. * * Re-exported because a consumer importing only `edfcore/node` could otherwise not name what * `fileSource` hands back — the subpath's whole output — and had to reach into the root entry to * write a single annotation (added in 0.3.44). */ export type { ByteSource, ClosableByteSource, ReadOptions } from './types.js'; /** * A positional reader with a lifetime. A real `fs.promises.FileHandle` satisfies this. * * Structural on purpose, so `@types/node` never enters the published `.d.ts` and so a test double * — or a handle from another runtime with the same API — is usable without a cast. */ export interface FileHandleLike { read(buffer: Uint8Array, offset: number, length: number, position: number): Promise<{ bytesRead: number; }>; close(): Promise; } /** * A `ByteSource` over an open file handle. * * `byteLength` is supplied by the caller rather than read from the handle, because the two ways * of learning it differ in what they promise: `fileSource` takes it from the handle it just * opened, while a caller wrapping a handle it already had may know something better (a range it * intends to expose, a size it verified). Neither is guessed here. * * `close()` closes the handle. edfcore has no other lifetime mechanism yet — * `Symbol.asyncDispose` is not Baseline yet — so a caller that opened a file is the one that * closes it. */ export declare function fileHandleSource(handle: FileHandleLike, byteLength: number): ClosableByteSource; /** * Open a file for reading and expose it as a `ByteSource`. * * The size comes from the handle rather than from a separate `stat(path)` call, so the size and * the bytes describe the same file even if the path is replaced between the two — on a rotating * log or a rsync target that is not hypothetical. * * The handle is closed if anything goes wrong before it has an owner; after that, closing is the * caller's job through `source.close()`. */ export declare function fileSource(path: string): Promise; //# sourceMappingURL=node.d.ts.map