/** * The `ByteSource` contract guard. * * Layer 5, and the only file in `io/` that imports nothing from `io/`: every adapter here calls * into this one and it calls into none of them. Nothing here knows anything about EDF. * * It said "the only file in `io/` that imports an error class" until 0.6.58, which `bytes.ts`, * `http.ts` and `read.ts` each disprove by raising one of their own. What is true is the * dependency direction, and it is the load-bearing half: a guard the adapters could not all * reach would be a contract checked in some of them. * * The contract is one sentence — a read resolves with EXACTLY `length` bytes or rejects, it * never pads and never truncates — and it is *checked on every call*, including calls into a * source the caller wrote. A source that quietly returns a short buffer is indistinguishable * from a truncated file, so without this guard the parser would confidently report the wrong * cause for the wrong thing. */ import { isByteArray } from '../bytes/latin1.js'; import type { AbortSignalLike, ByteSource, ReadOptions } from '../types.js'; /** * The byte count of a genuine byte array, or `undefined` for anything else — which is why * `EdfSourceError.receivedLength` is `number | undefined` rather than `number`. * * Reading `.length` off the value was not enough, even though the message it feeds already * promised to detect "a value that is not a byte array". A `string`, a `number[]` and a * `{ length }` object all satisfied it and then threw an unrelated `TypeError` deeper in — noisy, * but at least loud. The case that was not loud is a typed-array view of the WRONG signedness: * `Int8Array` has one byte per element, so it passes a length check, and `decodeInt16` then * sign-extends an already-signed element a second time. A file holding `[-32768, -1, 200, 32767]` * decodes as `[-98304, -65537, -65592, -65537]` with no error anywhere — fabricated microvolts. * * The test is on the built-in tag, not on `instanceof` and not on `BYTES_PER_ELEMENT`. * `instanceof Uint8Array` is false across a realm boundary, and a `Uint8Array` from a worker or an * iframe is a perfectly good byte array — the same reason `io/bytes.ts` reaches for * `ArrayBuffer.isView`. `BYTES_PER_ELEMENT === 1` looks like the right test and is not: `Int8Array` * has one byte per element too, so it is exactly the dangerous case that check would admit. * * `Object.prototype.toString` reads `Symbol.toStringTag` off the TypedArray prototype, which every * realm agrees on. It admits `Uint8Array` — including Node's `Buffer`, a subclass that inherits the * tag — and `Uint8ClampedArray`, and rejects `Int8Array`, every wider view, and `DataView`. * * The test itself lives in `bytes/latin1.ts` at Layer 0, which is the lowest module that needs it; * this re-export is what `byteSource` and the rest of `io/` reach it by (0.6.121). */ export { isByteArray }; /** * Enforces the exact-length contract and returns the value unchanged so it can wrap a read * expression directly. */ export declare function assertExactRead(received: Uint8Array, offset: number, length: number): Uint8Array; /** * Validates a requested range against the source length, with the real numbers in the message. * * Offsets are plain JS numbers throughout edfcore — exact to 2^53 — so this checks * safe-integer-ness rather than truncating with `| 0`, which silently wraps past 2 GiB. */ export declare function assertReadRange(offset: number, length: number, byteLength: number): void; /** * Aborts a read when the caller's signal is already aborted. * * `DOMException` cannot be named without the DOM lib, and the thing consumers actually branch * on is `error.name === 'AbortError'`, so that is what this produces. */ export declare function throwIfAborted(options?: ReadOptions): void; /** * The SIGNAL passed as the options rather than as the field on them. * * 0.6.130, 0.6.140 and 0.6.154 each refused a bare value where an options object belongs, and the * argument is always the same: every option here is a field on an object, so the value a caller * means is the option. This is that mistake made with an OBJECT, so none of those guards can see * it — `typeof options === 'object'` is true of an `AbortSignal`. * * It is also the likeliest spelling of it. The field is named `signal`, the thing a caller holds * is named `signal`, and `fetch(url, signal)` for `fetch(url, { signal })` is a mistake this * ecosystem makes constantly. `readWindow(recording, selection, controller.signal)` reads as * correct at the call site. * * `options?.signal` was then `undefined`, so the read ran to completion and RESOLVED WITH DATA. * Nothing distinguishes that from a read that finished before the abort, which is the ordinary * outcome a caller is already handling — so a viewer that cancels on every scroll cancelled * nothing, and neither the reads nor their memory stopped. * * Named by shape, not by class, for the reason `bytes.ts` gives: `instanceof` is false across a * realm boundary, and `AbortSignalLike` is published as `aborted` and nothing more, so the shim a * consumer writes has to be recognised too. */ export declare function assertReadOptions(options: unknown): void; /** * The same check against a signal that was resolved by the caller. * * A source can carry its own signal as well as the one passed per read, and the effective signal * is `readOptions?.signal ?? sourceOptions?.signal`. That cannot be handed back to * `throwIfAborted` as an object literal, because `exactOptionalPropertyTypes` refuses * `{ signal: undefined }` where the property is declared optional. */ export declare function throwIfSignalAborted(signal?: AbortSignalLike): void; /** * The source is a `ByteSource` before anything reads from it. * * This is the first argument of the first call, and passing the bytes themselves — `openEdf(bytes)` * rather than `openEdf(byteSource(bytes))` — is the likeliest mistake anyone makes with this * library. Until 0.4.444 it produced `TypeError: source.read is not a function`, which names * neither edfcore, nor the adapter that was missing, nor the one word that fixes it; `undefined` * produced a `TypeError` about a property of undefined instead, from a different line. * * `byteSource` itself has refused a wrong argument by name since the beginning, and says what to * pass instead. This is the same courtesy one call earlier, where more people meet it. * * Checked structurally — a `read` function and a numeric `byteLength` — because a `ByteSource` is * an interface a caller may implement, and `api-sources.md` documents writing one. */ export declare function assertByteSource(source: unknown): asserts source is ByteSource; //# sourceMappingURL=source.d.ts.map