loom-browser 0.0.5 → 0.0.7

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.
Files changed (56) hide show
  1. package/dist/loom-data-worker.js +10458 -0
  2. package/dist/loom-data-worker.min.js +2 -0
  3. package/dist/loom-data-worker.min.js.map +1 -0
  4. package/dist/loom-react.esm.js +1276 -318
  5. package/dist/loom-react.esm.min.js +1 -1
  6. package/dist/loom-react.esm.min.js.map +1 -1
  7. package/dist/loom-worker.js +10591 -0
  8. package/dist/loom-worker.min.js +2 -0
  9. package/dist/loom-worker.min.js.map +1 -0
  10. package/dist/loom.esm.js +8513 -7651
  11. package/dist/loom.esm.min.js +1 -1
  12. package/dist/loom.esm.min.js.map +1 -1
  13. package/dist/loom.js +8516 -7651
  14. package/dist/loom.min.js +1 -1
  15. package/dist/loom.min.js.map +1 -1
  16. package/dist/tsconfig.src.tsbuildinfo +1 -1
  17. package/dist/types/bigwig/index.d.ts +2 -5
  18. package/dist/types/dataSourceWorkerProvider.d.ts +79 -0
  19. package/dist/types/dataSources/bigWigDataSource.d.ts +1 -3
  20. package/dist/types/dataSources/featureSourceFactory.d.ts +1 -2
  21. package/dist/types/dataSources/gtxDataSource.d.ts +1 -3
  22. package/dist/types/dataSources/memoryDataSource.d.ts +32 -0
  23. package/dist/types/dataSources/textFeatureSource.d.ts +0 -4
  24. package/dist/types/genomeBrowser.d.ts +56 -1
  25. package/dist/types/gtx/index.d.ts +1 -4
  26. package/dist/types/headlessGenomeBrowser.d.ts +72 -3
  27. package/dist/types/index.d.ts +11 -4
  28. package/dist/types/mainThreadDataSourceProvider.d.ts +19 -0
  29. package/dist/types/react/GenomeBrowserContext.d.ts +3 -0
  30. package/dist/types/react/LoomBrowser.d.ts +15 -1
  31. package/dist/types/react/tracks/BedTrack.d.ts +8 -3
  32. package/dist/types/react/tracks/WigTrack.d.ts +6 -3
  33. package/dist/types/react/ui/Navbar.d.ts +4 -1
  34. package/dist/types/session.d.ts +0 -3
  35. package/dist/types/svgFeatureOverlay.d.ts +27 -0
  36. package/dist/types/tabix/index.d.ts +0 -3
  37. package/dist/types/trackRegistry.d.ts +1 -4
  38. package/dist/types/tracks/annotation/annotationRenderer.d.ts +4 -1
  39. package/dist/types/tracks/annotation/annotationTrackCanvas.d.ts +9 -6
  40. package/dist/types/tracks/axis/axisRenderer.d.ts +2 -8
  41. package/dist/types/tracks/axis/index.d.ts +1 -1
  42. package/dist/types/tracks/baseTrackCanvas.d.ts +7 -1
  43. package/dist/types/tracks/interaction/interactionRenderer.d.ts +4 -1
  44. package/dist/types/tracks/trackLabel.d.ts +22 -0
  45. package/dist/types/tracks/wig/wigTrackCanvas.d.ts +2 -0
  46. package/dist/types/types.d.ts +22 -1
  47. package/dist/types/worker/dataSourceRegistry.d.ts +33 -0
  48. package/dist/types/worker/dataSourceWorkerScript.d.ts +13 -0
  49. package/dist/types/worker/unifiedWorkerScript.d.ts +17 -0
  50. package/dist/types/worker/webDataSourceWorkerProvider.d.ts +59 -0
  51. package/dist/types/worker/webUnifiedWorkerProvider.d.ts +64 -0
  52. package/dist/types/worker/webWorkerPool.d.ts +64 -0
  53. package/dist/types/worker/workerPoolScript.d.ts +17 -0
  54. package/dist/types/workerDataSource.d.ts +32 -0
  55. package/dist/types/workerProvider.d.ts +10 -3
  56. package/package.json +3 -1
@@ -0,0 +1,27 @@
1
+ /**
2
+ * SVG overlay for interactive feature highlighting.
3
+ *
4
+ * Positions transparent SVG `<rect>` elements on top of a track's canvas,
5
+ * providing native CSS `:hover` states and click targets without canvas repaints.
6
+ * Follows the same DOM-over-canvas pattern used by ROI overlays in GenomeBrowser.
7
+ *
8
+ * On hover, features get a tinted fill matching their own color plus a subtle
9
+ * glow/shadow effect, making the canvas-rendered feature feel highlighted.
10
+ */
11
+ import type { FeatureRect } from './types';
12
+ export declare class SVGFeatureOverlay {
13
+ private svg;
14
+ private group;
15
+ private defs;
16
+ /** Callback fired when a feature rect is clicked. */
17
+ onFeatureClick?: (rect: FeatureRect, event: MouseEvent) => void;
18
+ constructor(container: HTMLElement);
19
+ /** Rebuild SVG rects from feature geometry. */
20
+ update(rects: FeatureRect[]): void;
21
+ /** Suppress pointer events on overlay rects (e.g., during drag). */
22
+ setSuppressed(suppressed: boolean): void;
23
+ dispose(): void;
24
+ /** Create an SVG filter that produces a colored glow. */
25
+ private createGlowFilter;
26
+ private createRect;
27
+ }
@@ -5,12 +5,9 @@
5
5
  * All BGZF decompression, index parsing, and block fetching is handled
6
6
  * by @gmod/tabix internally.
7
7
  */
8
- import type { WorkerProvider } from '../workerProvider';
9
8
  export interface TabixReaderOptions {
10
9
  /** URL to the .tbi index file. Defaults to `url + '.tbi'`. */
11
10
  indexUrl?: string;
12
- /** @deprecated Worker dispatch is handled internally by @gmod/tabix. */
13
- workerProvider?: WorkerProvider;
14
11
  }
15
12
  export interface TabixHeader {
16
13
  nref: number;
@@ -13,13 +13,11 @@
13
13
  */
14
14
  import type { Locus, Track, DataSource, DataSourceConfig, TrackSessionConfig, SequenceProvider } from './types';
15
15
  import type { CanvasProvider } from './canvasProvider';
16
- import type { WorkerProvider } from './workerProvider';
17
16
  import type { RenderTheme } from './themes/renderTheme';
18
17
  /** Context passed to every track creator function. */
19
18
  export interface TrackCreatorContext {
20
19
  locus: Locus;
21
20
  canvasProvider: CanvasProvider;
22
- workerProvider?: WorkerProvider;
23
21
  theme?: Partial<RenderTheme>;
24
22
  /** Sequence provider from the genome, used by sequence tracks. */
25
23
  sequenceProvider?: SequenceProvider;
@@ -65,7 +63,7 @@ export declare function getTrackCreator(type: string): TrackCreator | undefined;
65
63
  * Mirrors igv.js `knownTrackTypes()` (js/trackFactory.ts).
66
64
  */
67
65
  export declare function knownTrackTypes(): Set<string>;
68
- export declare function createDataSource(config: DataSourceConfig, workerProvider?: WorkerProvider): DataSource;
66
+ export declare function createDataSource(config: DataSourceConfig): DataSource;
69
67
  /**
70
68
  * Create a track from a session config using the registry.
71
69
  *
@@ -75,7 +73,6 @@ export declare function createDataSource(config: DataSourceConfig, workerProvide
75
73
  */
76
74
  export declare function createTrackFromConfig(trackConfig: TrackSessionConfig, locus: Locus, options?: {
77
75
  canvasProvider?: CanvasProvider;
78
- workerProvider?: WorkerProvider;
79
76
  theme?: Partial<RenderTheme>;
80
77
  sequenceProvider?: SequenceProvider;
81
78
  }): CreatedTrack;
@@ -8,10 +8,13 @@
8
8
  * intron lines, strand arrows, labels, and per-feature colors.
9
9
  */
10
10
  import type { AnnotationFeature, AnnotationRenderConfig, RenderContext } from '../../types';
11
+ import type { TrackNameLabelOptions } from '../trackLabel';
11
12
  /**
12
13
  * Render a set of annotation features onto a canvas context.
13
14
  *
14
15
  * Features should already have `.row` assigned (via `pack()`).
15
16
  * The canvas should be sized and cleared before calling this.
16
17
  */
17
- export declare function renderAnnotationTrack(ctx: CanvasRenderingContext2D, features: AnnotationFeature[], config: AnnotationRenderConfig, rc: RenderContext): void;
18
+ export declare function renderAnnotationTrack(ctx: CanvasRenderingContext2D, features: AnnotationFeature[], config: AnnotationRenderConfig, rc: RenderContext,
19
+ /** Optional track name label overlay (top-left corner). */
20
+ trackLabel?: TrackNameLabelOptions): void;
@@ -10,9 +10,8 @@
10
10
  * const track = new AnnotationTrackCanvas(canvas, { locus, features })
11
11
  * track.attachTo(containerDiv)
12
12
  */
13
- import type { AnnotationFeature, AnnotationRenderConfig, Locus, RenderContext, AnnotationTrackSessionConfig, HitTestResult, AxisInfo, ContextMenuItem } from '../../types';
13
+ import type { AnnotationFeature, AnnotationRenderConfig, Locus, RenderContext, AnnotationTrackSessionConfig, HitTestResult, AxisInfo, ContextMenuItem, FeatureRect } from '../../types';
14
14
  import type { CanvasProvider } from '../../canvasProvider';
15
- import type { WorkerProvider } from '../../workerProvider';
16
15
  import type { RenderTheme } from '../../themes/renderTheme';
17
16
  import { BaseTrackCanvas } from '../baseTrackCanvas';
18
17
  export type { Locus } from '../../types';
@@ -29,8 +28,6 @@ export interface AnnotationTrackCanvasOptions {
29
28
  background?: string;
30
29
  /** Canvas provider for environment abstraction. Default: DOMCanvasProvider. */
31
30
  canvasProvider?: CanvasProvider;
32
- /** Worker provider for offloading CPU-intensive tasks (packing). */
33
- workerProvider?: WorkerProvider;
34
31
  /** Track name for axis label. */
35
32
  name?: string;
36
33
  }
@@ -39,21 +36,27 @@ export declare class AnnotationTrackCanvas extends BaseTrackCanvas<AnnotationRen
39
36
  private fixedHeight;
40
37
  private background;
41
38
  private _name;
42
- private workerProvider?;
39
+ /** User-set config overrides, re-applied on theme change. */
40
+ private _userOverrides;
41
+ private _userBackground;
43
42
  /** Most recently packed features, available after render(). */
44
43
  private packedFeatures;
45
44
  /** Whether packedFeatures was pre-computed by async worker (skip sync pack in computeHeight). */
46
45
  private packedReady;
47
46
  readonly type = "annotation";
48
47
  constructor(canvas: HTMLCanvasElement, options: AnnotationTrackCanvasOptions);
49
- /** Update features and re-render. Dispatches async pack when workerProvider is set. */
48
+ /** Set or clear the fixed pixel height. When set, overrides auto-computed row-based height. */
49
+ setFixedHeight(height: number | undefined): void;
50
+ /** Update features and re-render. */
50
51
  setFeatures(features: AnnotationFeature[]): void;
51
52
  protected computeHeight(_width: number): number;
52
53
  protected getBackground(): string;
53
54
  protected doRender(ctx: CanvasRenderingContext2D, _width: number, _height: number, rc: RenderContext): void;
54
55
  getAxisInfo(): AxisInfo | undefined;
55
56
  getContextMenuItems(_x: number, _y: number): ContextMenuItem[];
57
+ getFeatureRects(): FeatureRect[];
56
58
  hitTest(x: number, y: number): HitTestResult<AnnotationFeature>[];
59
+ setConfig(config: Partial<AnnotationRenderConfig>): void;
57
60
  setTheme(theme: RenderTheme): void;
58
61
  serializeConfig(theme: RenderTheme): AnnotationTrackSessionConfig;
59
62
  }
@@ -4,16 +4,10 @@
4
4
  * These are pure canvas renderers — they take a 2D context, axis info, and
5
5
  * dimensions, and paint the axis. No DOM, no state, no side effects.
6
6
  *
7
- * Two variants:
8
- * - renderQuantitativeAxis: tick marks + data range labels for numeric tracks (wig)
9
- * - renderLabelAxis: centered rotated text label for annotation tracks (gene)
7
+ * renderQuantitativeAxis: background, color strip, track label, and
8
+ * tick marks + data range labels (when data is available) for numeric tracks.
10
9
  */
11
10
  import type { AxisInfo } from '../../types';
12
11
  /** Format a number for axis labels (ported from igv.js paintAxis.ts). */
13
12
  export declare function prettyPrintNumber(n: number): string;
14
13
  export declare function renderQuantitativeAxis(ctx: CanvasRenderingContext2D, info: AxisInfo, width: number, height: number): void;
15
- /**
16
- * Paint a label-only axis (e.g., gene track name).
17
- * Renders a vertically-rotated centered text label.
18
- */
19
- export declare function renderLabelAxis(ctx: CanvasRenderingContext2D, info: AxisInfo, width: number, height: number): void;
@@ -1 +1 @@
1
- export { renderQuantitativeAxis, renderLabelAxis, prettyPrintNumber } from './axisRenderer';
1
+ export { renderQuantitativeAxis, prettyPrintNumber } from './axisRenderer';
@@ -12,7 +12,7 @@
12
12
  *
13
13
  * This eliminates ~80 lines of identical boilerplate per track type.
14
14
  */
15
- import type { Locus, RenderContext, Track, TrackSessionConfig, HitTestResult, ContextMenuItem } from '../types';
15
+ import type { Locus, RenderContext, Track, TrackSessionConfig, HitTestResult, ContextMenuItem, FeatureRect } from '../types';
16
16
  import type { RenderTheme } from '../themes/renderTheme';
17
17
  import type { CanvasProvider } from '../canvasProvider';
18
18
  export declare abstract class BaseTrackCanvas<TConfig> implements Track {
@@ -66,6 +66,12 @@ export declare abstract class BaseTrackCanvas<TConfig> implements Track {
66
66
  * Default: empty (no interactive features). Subclasses override.
67
67
  */
68
68
  hitTest(_x: number, _y: number): HitTestResult[];
69
+ /**
70
+ * Return feature bounding rectangles for the current render state.
71
+ * Used by SVG overlay system for hover/click interactivity.
72
+ * Default: empty (no overlay). Subclasses override for interactive tracks.
73
+ */
74
+ getFeatureRects(): FeatureRect[];
69
75
  /**
70
76
  * Return context menu items for a right-click at canvas-relative coordinates.
71
77
  * Default: undefined (no track-specific items). Subclasses override.
@@ -12,6 +12,7 @@
12
12
  * Layer 2 (Track Canvas): uses CanvasRenderingContext2D, no DOM.
13
13
  */
14
14
  import type { InteractionFeature, InteractionRenderConfig, RenderContext } from '../../types';
15
+ import type { TrackNameLabelOptions } from '../trackLabel';
15
16
  /** Draw state stored on features during rendering for hit-testing. */
16
17
  export type InteractionDrawState = NestedDrawState | ProportionalDrawState | RectDrawState;
17
18
  interface NestedDrawState {
@@ -44,7 +45,9 @@ export interface DrawnInteractionFeature extends InteractionFeature {
44
45
  * Stateless: all state is passed in, no side effects beyond canvas drawing
45
46
  * and attaching drawState to features for hit-testing.
46
47
  */
47
- export declare function renderInteractionTrack(ctx: CanvasRenderingContext2D, features: DrawnInteractionFeature[], config: InteractionRenderConfig, rc: RenderContext): void;
48
+ export declare function renderInteractionTrack(ctx: CanvasRenderingContext2D, features: DrawnInteractionFeature[], config: InteractionRenderConfig, rc: RenderContext,
49
+ /** Optional track name label overlay (top-left corner). */
50
+ trackLabel?: TrackNameLabelOptions): void;
48
51
  /**
49
52
  * Format a genomic position for popup display.
50
53
  */
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Shared track name overlay label — renders a horizontal label in the top-left
3
+ * corner of a track canvas with a semi-transparent background pill.
4
+ *
5
+ * Used by wig, annotation, and interaction tracks for consistent labeling.
6
+ * Layer 2 (Track Canvases): uses canvas API, no DOM.
7
+ */
8
+ export interface TrackNameLabelOptions {
9
+ /** Track name to display. */
10
+ name: string;
11
+ /** Background color for the pill (usually matches track background). */
12
+ background: string;
13
+ /** Text and border color. */
14
+ labelColor: string;
15
+ /** Extra vertical offset from top in pixels (e.g., to clear data range labels). Default: 0. */
16
+ topOffset?: number;
17
+ }
18
+ /**
19
+ * Render a track name as a horizontal overlay in the top-left corner.
20
+ * Draws a semi-transparent background pill behind the text for readability.
21
+ */
22
+ export declare function renderTrackNameLabel(ctx: CanvasRenderingContext2D, options: TrackNameLabelOptions, pixelHeight: number): void;
@@ -52,6 +52,8 @@ export declare class WigTrackCanvas extends BaseTrackCanvas<WigRenderConfig> {
52
52
  private _seqAbort;
53
53
  /** Callback invoked when the user changes the windowing function via context menu. */
54
54
  private _onWindowFunctionChange?;
55
+ /** User-set config overrides, re-applied on theme change. */
56
+ private _userOverrides;
55
57
  readonly type = "wig";
56
58
  constructor(canvas: HTMLCanvasElement, options: WigTrackCanvasOptions);
57
59
  /** Set a callback invoked when the user changes the windowing function via context menu. */
@@ -541,6 +541,24 @@ export interface HitTestResult<F = unknown> {
541
541
  feature: F;
542
542
  popupData: PopupDataItem[];
543
543
  }
544
+ /**
545
+ * A feature's visual bounding box in CSS pixel coordinates.
546
+ * Used by SVG overlay system for hover/click interactivity.
547
+ */
548
+ export interface FeatureRect {
549
+ /** Reference to the source feature. */
550
+ feature: unknown;
551
+ /** Left edge in CSS pixels. */
552
+ x: number;
553
+ /** Top edge in CSS pixels. */
554
+ y: number;
555
+ /** Width in CSS pixels. */
556
+ width: number;
557
+ /** Height in CSS pixels. */
558
+ height: number;
559
+ /** Resolved feature color (used for highlight tint). */
560
+ color?: string;
561
+ }
544
562
  /** Payload for trackclick / trackhover browser events. */
545
563
  export interface TrackInteractionEvent {
546
564
  track: Track;
@@ -736,7 +754,7 @@ export type SequenceSessionOverrides = Partial<SequenceRenderConfig>;
736
754
  /** Serializable subset of InteractionRenderConfig (all fields are already serializable). */
737
755
  export type InteractionSessionOverrides = Partial<InteractionRenderConfig>;
738
756
  /** Discriminated union for data source reconstruction. */
739
- export type DataSourceConfig = BigWigDataSourceConfig | GtxDataSourceConfig | UCSCDataSourceConfig | TextDataSourceConfig;
757
+ export type DataSourceConfig = BigWigDataSourceConfig | GtxDataSourceConfig | UCSCDataSourceConfig | TextDataSourceConfig | MemoryDataSourceConfig;
740
758
  export interface BigWigDataSourceConfig {
741
759
  type: 'bigwig';
742
760
  url: string;
@@ -763,6 +781,9 @@ export interface TextDataSourceConfig {
763
781
  /** Whether the file is indexed (tabix). When absent, auto-detected from indexURL presence. */
764
782
  indexed?: boolean;
765
783
  }
784
+ export interface MemoryDataSourceConfig {
785
+ type: 'memory';
786
+ }
766
787
  /** Strand value for genomic features. */
767
788
  export type Strand = '+' | '-' | '.';
768
789
  /** Known text genomic file formats supported by the format detection system. */
@@ -0,0 +1,33 @@
1
+ /**
2
+ * DataSourceRegistry — manages long-lived DataSource instances inside a worker.
3
+ *
4
+ * Creates DataSource instances from serializable DataSourceConfig, caches them
5
+ * by instanceId, and manages per-fetch AbortControllers for cancellation.
6
+ *
7
+ * Runs inside a web worker or Node worker_threads context.
8
+ * Layer 1 (Data + Layout): no DOM.
9
+ */
10
+ import type { DataSourceConfig, Locus } from '../types';
11
+ export declare class DataSourceRegistry {
12
+ private readonly instances;
13
+ private readonly inflightAborts;
14
+ /**
15
+ * Create a DataSource from a serializable config and register it.
16
+ * The DataSource persists until destroy() is called.
17
+ */
18
+ create(instanceId: string, config: DataSourceConfig): void;
19
+ /**
20
+ * Fetch features from a registered DataSource.
21
+ * Creates an internal AbortController for cancellation via cancel().
22
+ */
23
+ fetch(instanceId: string, fetchId: number, locus: Locus, bpPerPixel: number): Promise<unknown[]>;
24
+ /** Abort an in-flight fetch by its fetchId. */
25
+ cancel(fetchId: number): void;
26
+ /**
27
+ * Call a setter method on a registered DataSource.
28
+ * Used for serializable configuration updates (setCumulativeOffsets, setWindowFunction, etc.).
29
+ */
30
+ configure(instanceId: string, method: string, args: unknown[]): void;
31
+ /** Destroy a DataSource instance and clean up. */
32
+ destroy(instanceId: string): void;
33
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Web Worker entry point for DataSource-based data fetching.
3
+ *
4
+ * Hosts persistent DataSource instances that handle the full pipeline:
5
+ * network I/O → binary parsing → feature decoding → summarization.
6
+ *
7
+ * Communicates with the main thread via the DataSourceWorkerProvider protocol:
8
+ * create, fetch, configure, cancel, destroy messages.
9
+ *
10
+ * Signals readiness via postMessage({type: 'ready'}) after module initialization,
11
+ * following JBrowse 2's async worker init pattern (PR #2798).
12
+ */
13
+ export {};
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Unified Web Worker entry point — handles both stateless tasks and stateful data sources.
3
+ *
4
+ * Stateless tasks (pack, summarize, parseFeatures, etc.) are dispatched via handleTask().
5
+ * Stateful data sources (BigWig, Tabix, UCSC) are managed via DataSourceRegistry.
6
+ *
7
+ * Message protocol uses a discriminated union on the `type` field:
8
+ * - 'task' → stateless task dispatch (round-robin from main thread)
9
+ * - 'create' → create a persistent DataSource instance
10
+ * - 'fetch' → fetch features from a DataSource
11
+ * - 'configure' → call a setter on a DataSource
12
+ * - 'cancel' → abort an in-flight fetch
13
+ * - 'destroy' → remove a DataSource instance
14
+ *
15
+ * Signals readiness via postMessage({type: 'ready'}) after module initialization.
16
+ */
17
+ export {};
@@ -0,0 +1,59 @@
1
+ /**
2
+ * WebDataSourceWorkerProvider — browser implementation of DataSourceWorkerProvider.
3
+ *
4
+ * Creates a pool of web workers that host persistent DataSource instances.
5
+ * Uses sticky routing (URL hash → worker index) to preserve reader caches.
6
+ * Supports cancellation via cancel messages and async worker initialization.
7
+ *
8
+ * Usage:
9
+ * const provider = new WebDataSourceWorkerProvider({
10
+ * workerFactory: () => new Worker(new URL('./dataSourceWorkerScript.ts', import.meta.url)),
11
+ * poolSize: 4,
12
+ * })
13
+ * const browser = new HeadlessGenomeBrowser({ ..., dataSourceWorkerProvider: provider })
14
+ * // ...
15
+ * provider.dispose()
16
+ */
17
+ import type { DataSourceWorkerProvider } from '../dataSourceWorkerProvider';
18
+ import type { DataSourceConfig, Locus } from '../types';
19
+ export interface WebDataSourceWorkerProviderOptions {
20
+ /**
21
+ * URL to the data source worker script.
22
+ * Mutually exclusive with `workerFactory`.
23
+ */
24
+ workerUrl?: string | URL;
25
+ /**
26
+ * Factory function that creates Worker instances.
27
+ * Recommended for bundlers (webpack 5, Vite):
28
+ * workerFactory: () => new Worker(new URL('./dataSourceWorkerScript.ts', import.meta.url))
29
+ * Mutually exclusive with `workerUrl`.
30
+ */
31
+ workerFactory?: () => Worker;
32
+ /**
33
+ * Number of workers in the pool. DataSources are distributed via sticky routing.
34
+ * Default: 1.
35
+ */
36
+ poolSize?: number;
37
+ }
38
+ export declare class WebDataSourceWorkerProvider implements DataSourceWorkerProvider {
39
+ private workers;
40
+ private readyPromises;
41
+ private instanceToWorker;
42
+ private pendingFetches;
43
+ private nextFetchId;
44
+ constructor(options: WebDataSourceWorkerProviderOptions);
45
+ /** Number of workers in the pool. */
46
+ get poolSize(): number;
47
+ create(instanceId: string, config: DataSourceConfig): void;
48
+ fetch<F>(instanceId: string, locus: Locus, bpPerPixel: number, signal: AbortSignal): Promise<F[]>;
49
+ configure(instanceId: string, method: string, ...args: unknown[]): void;
50
+ destroy(instanceId: string): void;
51
+ dispose(): void;
52
+ /**
53
+ * Sticky routing: deterministically assign a DataSourceConfig to a worker
54
+ * based on its URL. All DataSources for the same URL go to the same worker,
55
+ * preserving reader caches (BigWig headers, Tabix indices).
56
+ */
57
+ private routeToWorker;
58
+ private send;
59
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * WebUnifiedWorkerProvider — single worker pool for both stateless tasks and stateful data sources.
3
+ *
4
+ * Implements both WorkerProvider (for CPU-intensive tasks like pack, summarize) and
5
+ * DataSourceWorkerProvider (for persistent DataSource instances in workers).
6
+ *
7
+ * Routing:
8
+ * - Stateless tasks: round-robin across pool
9
+ * - DataSource operations: sticky routing via URL hash (preserves reader caches)
10
+ *
11
+ * Usage:
12
+ * const provider = new WebUnifiedWorkerProvider({
13
+ * workerFactory: () => new Worker(new URL('./unifiedWorkerScript.ts', import.meta.url)),
14
+ * poolSize: 4,
15
+ * })
16
+ * const browser = new GenomeBrowser(container, { workerProvider: provider })
17
+ * // browser auto-detects DataSourceWorkerProvider support
18
+ * provider.dispose()
19
+ */
20
+ import type { WorkerProvider, WorkerTask, WorkerTaskResultMap } from '../workerProvider';
21
+ import type { DataSourceWorkerProvider } from '../dataSourceWorkerProvider';
22
+ import type { DataSourceConfig, Locus } from '../types';
23
+ export interface WebUnifiedWorkerProviderOptions {
24
+ /**
25
+ * URL to the unified worker script.
26
+ * Mutually exclusive with `workerFactory`.
27
+ */
28
+ workerUrl?: string | URL;
29
+ /**
30
+ * Factory function that creates Worker instances.
31
+ * Recommended for bundlers (webpack 5, Vite):
32
+ * workerFactory: () => new Worker(new URL('./unifiedWorkerScript.ts', import.meta.url))
33
+ * Mutually exclusive with `workerUrl`.
34
+ */
35
+ workerFactory?: () => Worker;
36
+ /**
37
+ * Number of workers in the pool. Default: 1.
38
+ */
39
+ poolSize?: number;
40
+ }
41
+ export declare class WebUnifiedWorkerProvider implements WorkerProvider, DataSourceWorkerProvider {
42
+ private workers;
43
+ private readyPromises;
44
+ private nextId;
45
+ private nextWorker;
46
+ private pending;
47
+ private instanceToWorker;
48
+ private pendingFetches;
49
+ private nextFetchId;
50
+ constructor(options: WebUnifiedWorkerProviderOptions);
51
+ /** Number of workers in the pool. */
52
+ get poolSize(): number;
53
+ execute<T extends WorkerTask>(task: T, transfer?: Transferable[]): Promise<WorkerTaskResultMap[T['task']]>;
54
+ create(instanceId: string, config: DataSourceConfig): void;
55
+ fetch<F>(instanceId: string, locus: Locus, bpPerPixel: number, signal: AbortSignal): Promise<F[]>;
56
+ configure(instanceId: string, method: string, ...args: unknown[]): void;
57
+ destroy(instanceId: string): void;
58
+ dispose(): void;
59
+ /**
60
+ * Sticky routing: deterministically assign a DataSourceConfig to a worker
61
+ * based on its URL. Preserves reader caches (BigWig headers, Tabix indices).
62
+ */
63
+ private routeToWorker;
64
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * WebWorkerPool — single worker pool for both stateless tasks and stateful data sources.
3
+ *
4
+ * Implements both WorkerProvider (for CPU-intensive tasks like pack, summarize) and
5
+ * DataSourceWorkerProvider (for persistent DataSource instances in workers).
6
+ *
7
+ * Routing:
8
+ * - Stateless tasks: round-robin across pool
9
+ * - DataSource operations: sticky routing via URL hash (preserves reader caches)
10
+ *
11
+ * Usage:
12
+ * const pool = new WebWorkerPool({
13
+ * workerFactory: () => new Worker(new URL('./workerPoolScript.ts', import.meta.url)),
14
+ * poolSize: 4,
15
+ * })
16
+ * const browser = new GenomeBrowser(container, { workerProvider: pool })
17
+ * // browser auto-detects DataSourceWorkerProvider support
18
+ * pool.dispose()
19
+ */
20
+ import type { WorkerProvider, WorkerTask, WorkerTaskResultMap } from '../workerProvider';
21
+ import type { DataSourceWorkerProvider } from '../dataSourceWorkerProvider';
22
+ import type { DataSourceConfig, Locus } from '../types';
23
+ export interface WebWorkerPoolOptions {
24
+ /**
25
+ * URL to the worker pool script.
26
+ * Mutually exclusive with `workerFactory`.
27
+ */
28
+ workerUrl?: string | URL;
29
+ /**
30
+ * Factory function that creates Worker instances.
31
+ * Recommended for bundlers (webpack 5, Vite):
32
+ * workerFactory: () => new Worker(new URL('./workerPoolScript.ts', import.meta.url))
33
+ * Mutually exclusive with `workerUrl`.
34
+ */
35
+ workerFactory?: () => Worker;
36
+ /**
37
+ * Number of workers in the pool. Default: 1.
38
+ */
39
+ poolSize?: number;
40
+ }
41
+ export declare class WebWorkerPool implements WorkerProvider, DataSourceWorkerProvider {
42
+ private workers;
43
+ private readyPromises;
44
+ private nextId;
45
+ private nextWorker;
46
+ private pending;
47
+ private instanceToWorker;
48
+ private pendingFetches;
49
+ private nextFetchId;
50
+ constructor(options: WebWorkerPoolOptions);
51
+ /** Number of workers in the pool. */
52
+ get poolSize(): number;
53
+ execute<T extends WorkerTask>(task: T, transfer?: Transferable[]): Promise<WorkerTaskResultMap[T['task']]>;
54
+ create(instanceId: string, config: DataSourceConfig): void;
55
+ fetch<F>(instanceId: string, locus: Locus, bpPerPixel: number, signal: AbortSignal): Promise<F[]>;
56
+ configure(instanceId: string, method: string, ...args: unknown[]): void;
57
+ destroy(instanceId: string): void;
58
+ dispose(): void;
59
+ /**
60
+ * Sticky routing: deterministically assign a DataSourceConfig to a worker
61
+ * based on its URL. Preserves reader caches (BigWig headers, Tabix indices).
62
+ */
63
+ private routeToWorker;
64
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Unified Web Worker entry point — handles both stateless tasks and stateful data sources.
3
+ *
4
+ * Stateless tasks (pack, summarize, parseFeatures, etc.) are dispatched via handleTask().
5
+ * Stateful data sources (BigWig, Tabix, UCSC) are managed via DataSourceRegistry.
6
+ *
7
+ * Message protocol uses a discriminated union on the `type` field:
8
+ * - 'task' → stateless task dispatch (round-robin from main thread)
9
+ * - 'create' → create a persistent DataSource instance
10
+ * - 'fetch' → fetch features from a DataSource
11
+ * - 'configure' → call a setter on a DataSource
12
+ * - 'cancel' → abort an in-flight fetch
13
+ * - 'destroy' → remove a DataSource instance
14
+ *
15
+ * Signals readiness via postMessage({type: 'ready'}) after module initialization.
16
+ */
17
+ export {};
@@ -0,0 +1,32 @@
1
+ /**
2
+ * WorkerDataSource — main-thread proxy that forwards DataSource.fetch() to a worker.
3
+ *
4
+ * Implements DataSource<F> so it's a drop-in replacement for any direct DataSource.
5
+ * The real DataSource instance lives inside a web worker; this proxy communicates
6
+ * via the DataSourceWorkerProvider.
7
+ *
8
+ * Non-serializable configuration (like chromosome name resolver functions) is
9
+ * stored locally on the proxy and applied before forwarding to the worker.
10
+ *
11
+ * Layer 1 (Data + Layout): no DOM.
12
+ */
13
+ import type { DataSource, Locus } from './types';
14
+ import type { CumulativeOffsets } from './genome/chromSizes';
15
+ import type { DataSourceWorkerProvider } from './dataSourceWorkerProvider';
16
+ import type { WindowFunction } from './types';
17
+ export declare class WorkerDataSource<F = unknown> implements DataSource<F> {
18
+ private readonly provider;
19
+ readonly instanceId: string;
20
+ private resolver?;
21
+ constructor(provider: DataSourceWorkerProvider, instanceId: string);
22
+ fetch(locus: Locus, bpPerPixel: number, signal: AbortSignal): Promise<F[]>;
23
+ /**
24
+ * Set a chromosome name resolver. Stored locally — the proxy resolves
25
+ * chromosome names before forwarding the locus to the worker.
26
+ */
27
+ setChromNameResolver(resolver: (chr: string) => string): void;
28
+ /** Forward cumulative offsets to the worker-resident DataSource. */
29
+ setCumulativeOffsets(offsets: CumulativeOffsets): void;
30
+ /** Forward window function change to the worker-resident DataSource. */
31
+ setWindowFunction(wf: WindowFunction): void;
32
+ }
@@ -11,8 +11,9 @@
11
11
  * - WebWorkerProvider — browser (Web Workers)
12
12
  * - NodeWorkerProvider — Node.js (worker_threads)
13
13
  */
14
- import type { AnnotationFeature, WigFeature, WindowFunction, TextFileFormat } from './types';
14
+ import type { AnnotationFeature, WigFeature, WindowFunction, TextFileFormat, DataSourceConfig, Locus } from './types';
15
15
  import type { FeatureHeader } from './formats/featureParser';
16
+ import type { DataSourceWorkerProvider } from './dataSourceWorkerProvider';
16
17
  export interface PackTask {
17
18
  task: 'pack';
18
19
  features: AnnotationFeature[];
@@ -65,11 +66,17 @@ export interface WorkerProvider {
65
66
  }
66
67
  /**
67
68
  * Runs all tasks on the main thread using direct function calls.
68
- * This is the default when no WorkerProvider is supplied.
69
+ * Implements both WorkerProvider (stateless tasks) and DataSourceWorkerProvider
70
+ * (stateful data sources) as the default fallback when no worker pool is available.
69
71
  */
70
- export declare class MainThreadProvider implements WorkerProvider {
72
+ export declare class MainThreadProvider implements WorkerProvider, DataSourceWorkerProvider {
73
+ private readonly dsInstances;
71
74
  execute<T extends WorkerTask>(task: T): Promise<WorkerTaskResultMap[T['task']]>;
72
75
  private dispatch;
76
+ create(instanceId: string, config: DataSourceConfig): void;
77
+ fetch<F>(instanceId: string, locus: Locus, bpPerPixel: number, signal: AbortSignal): Promise<F[]>;
78
+ configure(instanceId: string, method: string, ...args: unknown[]): void;
79
+ destroy(instanceId: string): void;
73
80
  dispose(): void;
74
81
  }
75
82
  /** Default worker provider: runs everything on the main thread. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loom-browser",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "main": "dist/loom.esm.js",
5
5
  "module": "dist/loom.esm.js",
6
6
  "types": "dist/types/index.d.ts",
@@ -83,6 +83,8 @@
83
83
  "devDependencies": {
84
84
  "@eslint/js": "^10.0.1",
85
85
  "@gmod/cram": "^5.0.5",
86
+ "@rollup/plugin-commonjs": "^29.0.2",
87
+ "@rollup/plugin-node-resolve": "^16.0.3",
86
88
  "@rollup/plugin-strip": "^3.0.1",
87
89
  "@rollup/plugin-terser": "^0.4.0",
88
90
  "@rollup/plugin-typescript": "^12.3.0",