edfcore 0.3.77 → 0.3.79

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/CHANGELOG.md CHANGED
@@ -6,6 +6,41 @@ alone does not tell you whether you were affected.
6
6
  edfcore is pre-1.0. Patch releases have carried behaviour changes where the old behaviour was a
7
7
  defect; those are called out below.
8
8
 
9
+ ## 0.3.79
10
+
11
+ - **Fixed** `cachedSource` leaving an aborting caller pending for the whole underlying block read.
12
+ - 0.3.43 stopped one reader's signal cancelling a block other readers were waiting on — right, and
13
+ unchanged — and justified it by saying `read` "already polls each caller's own signal before and
14
+ after `Promise.all`, so an aborting caller still rejects promptly". The only poll that can fire
15
+ is the one **after** the gather. So the caller's promise settled when the bytes it no longer
16
+ wanted arrived, and with the signal no longer reaching the source, nothing was watching it at
17
+ all. A viewer aborting a scrolled-past window held that promise for the full fetch.
18
+ - `read` now races the caller's own signal against the gather. The shared block read is untouched:
19
+ other readers still get it, and losing the race leaves nothing dangling, because the block
20
+ promises are already attached inside `blockFor`.
21
+ - `AbortSignalLike` is `{ aborted: boolean }` and nothing more, so a signal that carries no
22
+ `addEventListener` cannot be watched and the post-gather poll remains the answer for it. A real
23
+ `AbortSignal` — what callers actually pass — is watched and rejects the moment it fires, with the
24
+ same `AbortError` `throwIfAborted` produces, so nothing branching on `error.name` can tell which
25
+ route rejected it.
26
+
27
+ ## 0.3.78
28
+
29
+ - **Fixed** `sample-grid.ts` sending a reader to `onsetTicks` where `sample-locate.ts` sends them to
30
+ `onsetTicksFromFirstRecord`, for the identical refusal.
31
+ - Both modules refuse an annotations channel with the same sentence — it holds TAL text, so it has
32
+ no sample grid — and then name different fields to use instead. The grid puts sample 0 at
33
+ `t = 0`, which is the start of record 0: the **rebased** axis. `onsetTicks` is on the header's
34
+ timebase, and the two differ by the sub-second offset record 0's timekeeping TAL may declare.
35
+ - On a file with a 0.25 s offset, `gridSampleStartTicks(signal, 4, d)` is 10000000 and the event
36
+ written at that instant reports `onsetTicks` 12500000. The reader was sent to the field that
37
+ does not line up with the numbers the module they had just called returns. `sample-locate.ts`
38
+ had it right.
39
+ - The guard reads both refusals out of the source and requires them to name the same field. Its
40
+ first version passed with the bug reinstated, because the explanatory comment above the message
41
+ names both fields and the slice picked it up — it now strips comment lines before matching, and
42
+ says so, since that is the only reason it works.
43
+
9
44
  ## 0.3.77
10
45
 
11
46
  - **Fixed** `validateRecording`'s scan-budget refusal offering advice that does not work on the
@@ -109,5 +109,5 @@ export declare const SIGNAL_FIELD_BLOCK_OFFSETS: {
109
109
  readonly reserved: 224;
110
110
  };
111
111
  /** Published package version. Kept in sync with package.json by a test. */
112
- export declare const VERSION = "0.3.77";
112
+ export declare const VERSION = "0.3.79";
113
113
  //# sourceMappingURL=constants.d.ts.map
package/dist/constants.js CHANGED
@@ -79,5 +79,5 @@ export const SIGNAL_FIELD_BLOCK_OFFSETS = {
79
79
  reserved: 224,
80
80
  };
81
81
  /** Published package version. Kept in sync with package.json by a test. */
82
- export const VERSION = '0.3.77';
82
+ export const VERSION = '0.3.79';
83
83
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cached.d.ts","sourceRoot":"","sources":["../../src/io/cached.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAe,MAAM,aAAa,CAAC;AAmBzE,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,UAAU,CA4InF"}
1
+ {"version":3,"file":"cached.d.ts","sourceRoot":"","sources":["../../src/io/cached.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAmB,UAAU,EAAE,YAAY,EAAe,MAAM,aAAa,CAAC;AAiE1F,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,UAAU,CAqKnF"}
package/dist/io/cached.js CHANGED
@@ -30,6 +30,41 @@ function passThrough(source) {
30
30
  },
31
31
  };
32
32
  }
33
+ function isWatchable(signal) {
34
+ const candidate = signal;
35
+ return (typeof candidate?.addEventListener === 'function' &&
36
+ typeof candidate.removeEventListener === 'function');
37
+ }
38
+ /**
39
+ * A promise that rejects when `signal` aborts, plus the teardown for its listener.
40
+ *
41
+ * `undefined` when the signal cannot be watched, which is the caller's cue to fall back to polling.
42
+ * The rejection is the same `AbortError` `throwIfAborted` produces, so a caller branching on
43
+ * `error.name` cannot tell which route rejected it.
44
+ */
45
+ function watchSignal(signal) {
46
+ if (signal === undefined || !isWatchable(signal))
47
+ return undefined;
48
+ let dispose = () => { };
49
+ const aborted = new Promise((_resolve, reject) => {
50
+ const onAbort = () => {
51
+ const error = new Error('The read was aborted through options.signal.');
52
+ error.name = 'AbortError';
53
+ reject(error);
54
+ };
55
+ if (signal.aborted) {
56
+ onAbort();
57
+ return;
58
+ }
59
+ signal.addEventListener('abort', onAbort);
60
+ dispose = () => {
61
+ signal.removeEventListener('abort', onAbort);
62
+ };
63
+ });
64
+ // Losing the race must not surface as an unhandled rejection.
65
+ aborted.catch(() => { });
66
+ return { aborted, dispose: () => dispose() };
67
+ }
33
68
  export function cachedSource(source, options) {
34
69
  const byteLength = source.byteLength;
35
70
  const maxBytes = Math.max(0, Math.floor(requireFiniteOption(options?.maxBytes, 'maxBytes', DEFAULT_MAX_BYTES)));
@@ -77,11 +112,17 @@ export function cachedSource(source, options) {
77
112
  * it: a blank panel and no error anywhere. Which reader died depended on which touched the
78
113
  * block first (fixed in 0.3.43).
79
114
  *
80
- * `read` already polls each caller's own signal before and after `Promise.all`, so an aborting
81
- * caller still rejects promptly it simply no longer decides for anyone else. The cost is that
82
- * an abort does not tear down the underlying request, which is the right trade for a read whose
83
- * result other readers are waiting on: the bytes are valid and already paid for, so they are
84
- * admitted to the cache.
115
+ * The caller no longer decides for anyone else, and the cost is that an abort does not tear down
116
+ * the underlying requestthe right trade for a read whose result other readers are waiting on:
117
+ * the bytes are valid and already paid for, so they are admitted to the cache.
118
+ *
119
+ * This used to claim that the polls around `Promise.all` left an aborting caller rejecting
120
+ * "promptly". They did not: the only poll that can fire is the one AFTER the gather, so the
121
+ * caller's promise stayed pending for the whole underlying block read and settled only when the
122
+ * bytes it no longer wanted arrived. With the signal no longer reaching the source, nothing else
123
+ * was watching it. `read` now RACES the caller's own signal against the gather when the signal
124
+ * can be watched, so it rejects at abort time while the shared read continues untouched — which
125
+ * is what 0.3.43 decided, rather than what it wrote down (fixed in 0.3.79).
85
126
  */
86
127
  async function fetchBlock(index, options) {
87
128
  const start = index * blockBytes;
@@ -136,7 +177,27 @@ export function cachedSource(source, options) {
136
177
  for (let index = firstBlock; index <= lastBlock; index += 1) {
137
178
  pending.push(blockFor(index, options));
138
179
  }
139
- const resolved = await Promise.all(pending);
180
+ /*
181
+ * Raced, not merely awaited. `AbortSignalLike` is `{ aborted: boolean }` and nothing more, so
182
+ * a signal that carries no `addEventListener` cannot be watched and the post-gather poll
183
+ * below is still the only answer for it. A real `AbortSignal` — what every caller in
184
+ * practice passes — is watched, and rejects the moment it fires.
185
+ *
186
+ * The gather is NOT cancelled either way: `pending` holds the shared block promises, other
187
+ * readers are waiting on them, and their rejections must not become unhandled. They are
188
+ * already attached inside `blockFor`, so losing the race leaves nothing dangling.
189
+ */
190
+ const watch = watchSignal(options?.signal);
191
+ let resolved;
192
+ try {
193
+ resolved =
194
+ watch === undefined
195
+ ? await Promise.all(pending)
196
+ : await Promise.race([Promise.all(pending), watch.aborted]);
197
+ }
198
+ finally {
199
+ watch?.dispose();
200
+ }
140
201
  throwIfAborted(options);
141
202
  const out = new Uint8Array(length);
142
203
  for (const [position, block] of resolved.entries()) {
@@ -1 +1 @@
1
- {"version":3,"file":"cached.js","sourceRoot":"","sources":["../../src/io/cached.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cached.js","sourceRoot":"","sources":["../../src/io/cached.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"sample-grid.d.ts","sourceRoot":"","sources":["../src/sample-grid.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AA0B/D;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,MAAM,EACf,mBAAmB,EAAE,MAAM,GAC1B,iBAAiB,CAoBnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,MAAM,EACnB,mBAAmB,EAAE,MAAM,GAC1B,MAAM,CAcR;AAED,+EAA+E;AAC/E,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,MAAM,EACnB,mBAAmB,EAAE,MAAM,GAC1B,MAAM,CAKR"}
1
+ {"version":3,"file":"sample-grid.d.ts","sourceRoot":"","sources":["../src/sample-grid.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAgC/D;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,MAAM,EACf,mBAAmB,EAAE,MAAM,GAC1B,iBAAiB,CAoBnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,MAAM,EACnB,mBAAmB,EAAE,MAAM,GAC1B,MAAM,CAcR;AAED,+EAA+E;AAC/E,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,MAAM,EACnB,mBAAmB,EAAE,MAAM,GAC1B,MAAM,CAKR"}
@@ -46,7 +46,13 @@ function assertGrid(signal, recordDurationTicks) {
46
46
  if (signal.kind === 'annotations') {
47
47
  throw new RangeError(`signal ${signal.index} (${JSON.stringify(signal.label)}) is an annotations channel, ` +
48
48
  'whose region holds TAL text rather than samples, so it has no sample grid. Next: use ' +
49
- 'onsetTicks on the annotations themselves.');
49
+ // `onsetTicksFromFirstRecord`, not `onsetTicks`. This grid puts sample 0 at t = 0, which
50
+ // is the start of record 0 — the rebased axis — and `onsetTicks` is on the HEADER's
51
+ // timebase. They differ by the sub-second offset record 0's timekeeping TAL may declare:
52
+ // on a file with a 0.25 s offset, `gridSampleStartTicks(signal, 4, d)` is 10000000 and the
53
+ // event at that instant reports `onsetTicks` 12500000. `sample-locate.ts` names the right
54
+ // one for the identical refusal (fixed in 0.3.78).
55
+ 'onsetTicksFromFirstRecord on the annotations themselves.');
50
56
  }
51
57
  if (signal.samplesPerRecord <= 0) {
52
58
  throw new RangeError(`signal ${signal.index} (${JSON.stringify(signal.label)}) declares ` +
@@ -1 +1 @@
1
- {"version":3,"file":"sample-grid.js","sourceRoot":"","sources":["../src/sample-grid.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sample-grid.js","sourceRoot":"","sources":["../src/sample-grid.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edfcore",
3
- "version": "0.3.77",
3
+ "version": "0.3.79",
4
4
  "description": "Modern, typed, zero-dependency reader for EDF, EDF+, BDF and BDF+ biosignal files. Works in browsers and Node with true random access.",
5
5
  "keywords": [
6
6
  "edf",
package/src/constants.ts CHANGED
@@ -93,4 +93,4 @@ export const SIGNAL_FIELD_BLOCK_OFFSETS = {
93
93
  } as const;
94
94
 
95
95
  /** Published package version. Kept in sync with package.json by a test. */
96
- export const VERSION = '0.3.77';
96
+ export const VERSION = '0.3.79';
package/src/io/cached.ts CHANGED
@@ -16,7 +16,7 @@
16
16
  */
17
17
 
18
18
  import { requireFiniteOption } from '../options.js';
19
- import type { ByteSource, CacheOptions, ReadOptions } from '../types.js';
19
+ import type { AbortSignalLike, ByteSource, CacheOptions, ReadOptions } from '../types.js';
20
20
  import { assertExactRead, assertReadRange, throwIfAborted } from './source.js';
21
21
 
22
22
  const DEFAULT_BLOCK_BYTES = 1024 * 1024;
@@ -35,6 +35,52 @@ function passThrough(source: ByteSource): ByteSource {
35
35
  };
36
36
  }
37
37
 
38
+ /** The shape a real `AbortSignal` has and `AbortSignalLike` does not promise. */
39
+ interface WatchableSignal {
40
+ addEventListener(type: 'abort', listener: () => void): void;
41
+ removeEventListener(type: 'abort', listener: () => void): void;
42
+ }
43
+
44
+ function isWatchable(signal: unknown): signal is AbortSignalLike & WatchableSignal {
45
+ const candidate = signal as { addEventListener?: unknown; removeEventListener?: unknown } | null;
46
+ return (
47
+ typeof candidate?.addEventListener === 'function' &&
48
+ typeof candidate.removeEventListener === 'function'
49
+ );
50
+ }
51
+
52
+ /**
53
+ * A promise that rejects when `signal` aborts, plus the teardown for its listener.
54
+ *
55
+ * `undefined` when the signal cannot be watched, which is the caller's cue to fall back to polling.
56
+ * The rejection is the same `AbortError` `throwIfAborted` produces, so a caller branching on
57
+ * `error.name` cannot tell which route rejected it.
58
+ */
59
+ function watchSignal(
60
+ signal: AbortSignalLike | undefined,
61
+ ): { aborted: Promise<never>; dispose: () => void } | undefined {
62
+ if (signal === undefined || !isWatchable(signal)) return undefined;
63
+ let dispose = (): void => {};
64
+ const aborted = new Promise<never>((_resolve, reject) => {
65
+ const onAbort = (): void => {
66
+ const error = new Error('The read was aborted through options.signal.');
67
+ error.name = 'AbortError';
68
+ reject(error);
69
+ };
70
+ if (signal.aborted) {
71
+ onAbort();
72
+ return;
73
+ }
74
+ signal.addEventListener('abort', onAbort);
75
+ dispose = () => {
76
+ signal.removeEventListener('abort', onAbort);
77
+ };
78
+ });
79
+ // Losing the race must not surface as an unhandled rejection.
80
+ aborted.catch(() => {});
81
+ return { aborted, dispose: () => dispose() };
82
+ }
83
+
38
84
  export function cachedSource(source: ByteSource, options?: CacheOptions): ByteSource {
39
85
  const byteLength = source.byteLength;
40
86
  const maxBytes = Math.max(
@@ -90,11 +136,17 @@ export function cachedSource(source: ByteSource, options?: CacheOptions): ByteSo
90
136
  * it: a blank panel and no error anywhere. Which reader died depended on which touched the
91
137
  * block first (fixed in 0.3.43).
92
138
  *
93
- * `read` already polls each caller's own signal before and after `Promise.all`, so an aborting
94
- * caller still rejects promptly it simply no longer decides for anyone else. The cost is that
95
- * an abort does not tear down the underlying request, which is the right trade for a read whose
96
- * result other readers are waiting on: the bytes are valid and already paid for, so they are
97
- * admitted to the cache.
139
+ * The caller no longer decides for anyone else, and the cost is that an abort does not tear down
140
+ * the underlying requestthe right trade for a read whose result other readers are waiting on:
141
+ * the bytes are valid and already paid for, so they are admitted to the cache.
142
+ *
143
+ * This used to claim that the polls around `Promise.all` left an aborting caller rejecting
144
+ * "promptly". They did not: the only poll that can fire is the one AFTER the gather, so the
145
+ * caller's promise stayed pending for the whole underlying block read and settled only when the
146
+ * bytes it no longer wanted arrived. With the signal no longer reaching the source, nothing else
147
+ * was watching it. `read` now RACES the caller's own signal against the gather when the signal
148
+ * can be watched, so it rejects at abort time while the shared read continues untouched — which
149
+ * is what 0.3.43 decided, rather than what it wrote down (fixed in 0.3.79).
98
150
  */
99
151
  async function fetchBlock(index: number, options?: ReadOptions): Promise<Uint8Array> {
100
152
  const start = index * blockBytes;
@@ -152,7 +204,26 @@ export function cachedSource(source: ByteSource, options?: CacheOptions): ByteSo
152
204
  for (let index = firstBlock; index <= lastBlock; index += 1) {
153
205
  pending.push(blockFor(index, options));
154
206
  }
155
- const resolved = await Promise.all(pending);
207
+ /*
208
+ * Raced, not merely awaited. `AbortSignalLike` is `{ aborted: boolean }` and nothing more, so
209
+ * a signal that carries no `addEventListener` cannot be watched and the post-gather poll
210
+ * below is still the only answer for it. A real `AbortSignal` — what every caller in
211
+ * practice passes — is watched, and rejects the moment it fires.
212
+ *
213
+ * The gather is NOT cancelled either way: `pending` holds the shared block promises, other
214
+ * readers are waiting on them, and their rejections must not become unhandled. They are
215
+ * already attached inside `blockFor`, so losing the race leaves nothing dangling.
216
+ */
217
+ const watch = watchSignal(options?.signal);
218
+ let resolved: Uint8Array[];
219
+ try {
220
+ resolved =
221
+ watch === undefined
222
+ ? await Promise.all(pending)
223
+ : await Promise.race([Promise.all(pending), watch.aborted]);
224
+ } finally {
225
+ watch?.dispose();
226
+ }
156
227
  throwIfAborted(options);
157
228
 
158
229
  const out = new Uint8Array(length);
@@ -50,7 +50,13 @@ function assertGrid(signal: EdfSignal, recordDurationTicks: bigint): void {
50
50
  throw new RangeError(
51
51
  `signal ${signal.index} (${JSON.stringify(signal.label)}) is an annotations channel, ` +
52
52
  'whose region holds TAL text rather than samples, so it has no sample grid. Next: use ' +
53
- 'onsetTicks on the annotations themselves.',
53
+ // `onsetTicksFromFirstRecord`, not `onsetTicks`. This grid puts sample 0 at t = 0, which
54
+ // is the start of record 0 — the rebased axis — and `onsetTicks` is on the HEADER's
55
+ // timebase. They differ by the sub-second offset record 0's timekeeping TAL may declare:
56
+ // on a file with a 0.25 s offset, `gridSampleStartTicks(signal, 4, d)` is 10000000 and the
57
+ // event at that instant reports `onsetTicks` 12500000. `sample-locate.ts` names the right
58
+ // one for the identical refusal (fixed in 0.3.78).
59
+ 'onsetTicksFromFirstRecord on the annotations themselves.',
54
60
  );
55
61
  }
56
62
  if (signal.samplesPerRecord <= 0) {