@alleninstitute/vis-core 0.0.6

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.
@@ -0,0 +1 @@
1
+ {"mappings":"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","sources":["packages/core/src/index.ts","packages/core/src/render-queue.ts","packages/core/src/dataset-cache.ts","packages/core/src/layers/layer-2D.ts","packages/core/src/layers/buffer-pair.ts","packages/core/src/resources.ts","packages/core/src/errors.ts","packages/core/src/colors.ts","packages/core/src/logger.ts","packages/core/src/abstract/async-frame.ts","packages/core/src/abstract/render-server.ts","packages/core/src/shared-priority-cache/priority-cache.ts","packages/core/src/shared-priority-cache/min-heap.ts","packages/core/src/shared-priority-cache/keyed-heap.ts","packages/core/src/shared-priority-cache/shared-cache.ts","packages/core/src/shared-priority-cache/utils.ts","packages/core/src/workers/messages.ts","packages/core/src/workers/worker-pool.ts"],"sourcesContent":["export { beginLongRunningFrame } from './render-queue';\nexport { AsyncDataCache } from './dataset-cache';\nexport { ReglLayer2D } from './layers/layer-2D';\nexport * from './layers/buffer-pair';\nexport * from './resources';\nexport * from './errors';\nexport * from './colors';\n\nexport {\n beginFrame,\n buildAsyncRenderer,\n type RenderFrameConfig,\n} from './abstract/async-frame';\nexport type {\n CachedTexture,\n CachedVertexBuffer,\n ReglCacheEntry,\n Renderer,\n} from './abstract/types';\nexport { RenderServer } from './abstract/render-server';\n\nexport { Logger, logger } from './logger';\nexport { PriorityCache, AsyncPriorityCache, type Cacheable } from './shared-priority-cache/priority-cache';\nexport { SharedPriorityCache } from './shared-priority-cache/shared-cache';\n\nexport {\n type WorkerMessage,\n type WorkerMessageWithId,\n isWorkerMessage,\n isWorkerMessageWithId,\n HEARTBEAT_RATE_MS,\n} from './workers/messages';\n\nexport { WorkerPool, type WorkerInit } from './workers/worker-pool';\n","import partial from 'lodash/partial';\nimport type { AsyncDataCache } from './dataset-cache';\n\n/**\n * FrameLifecycle type that defines the functions a user can call to interact with the frame lifecycle.\n *\n * Currently only supports `cancelFrame` to allow the user to cancel the frame on an ad-hoc basis.\n */\nexport type FrameLifecycle = {\n cancelFrame: (reason?: string) => void;\n};\n\n/**\n * NormalStatus type that defines the possible non-error statuses for a frame.\n *\n * `begun` - The frame has started running\n *\n * `finished` - The frame has finished running\n *\n * `cancelled` - The frame was cancelled by the user\n *\n * `finished_synchronously` - The frame finished synchronously\n *\n * `progress` - The frame is still running and has not finished\n */\nexport type NormalStatus = 'begun' | 'finished' | 'cancelled' | 'finished_synchronously' | 'progress';\nexport type RenderCallback = (event: { status: NormalStatus } | { status: 'error'; error: unknown }) => void;\n/**\n * `beingLongRunningFrame` starts a long-running frame that will render a list of items asynchronously based on\n * the provided data, settings, and rendering functions.\n *\n * The frame will run until all items have been rendered, or until the user cancels the frame. It will update the\n * provided cache so that the data is available for other frames that may be running. This function is safe to call\n * multiple times in different areas of your code, as it will complete quickly if/when all the data is already cached and available.\n *\n * You can listen for the status of the frame, allowing you to make decisions based on the progress of the frame.\n *\n * In addition, you can cancel the frame at any time, which will stop the frame from running and prevent any further\n * rendering or data fetching from occurring.\n *\n * @deprecated consider using beginFrame instead\n * @param maximumInflightAsyncTasks The maximum number of async tasks to run at once.\n * @param queueProcessingIntervalMS The length of time to wait between processing the queue in milliseconds.\n * @param items An array of generic items to render\n * @param mutableCache The asynchronous cache used to store the data\n * @param settings Flexible object of settings related to the items that are being rendered\n * @param requestsForItem a function which returns a mapping of \"columns\" to async functions that would fetch the column\n * @param render The main render function that will be called once all data is available\n * @param lifecycleCallback Callback function so they user can be notified of the status of the frame\n * @param cacheKeyForRequest A function for generating a cache key for a given request key, item, and settings. Defaults to the request key if not provided.\n * @param queueTimeBudgetMS the maximum ammount of time (milliseconds) to spend rendering before yeilding to allow other work to run - rendering will resume next frame (@param queueProcessingIntervalMS)\n * @returns A FrameLifecycle object with a cancelFrame function to allow users to cancel the frame when necessary\n */\nexport function beginLongRunningFrame<Column, Item, Settings>(\n maximumInflightAsyncTasks: number,\n queueProcessingIntervalMS: number,\n items: Item[],\n mutableCache: AsyncDataCache<string, string, Column>,\n settings: Settings,\n requestsForItem: (item: Item, settings: Settings, signal?: AbortSignal) => Record<string, () => Promise<Column>>,\n render: (item: Item, settings: Settings, columns: Record<string, Column | undefined>) => void,\n lifecycleCallback: RenderCallback,\n cacheKeyForRequest: (requestKey: string, item: Item, settings: Settings) => string = (key) => key,\n queueTimeBudgetMS: number = queueProcessingIntervalMS / 3,\n): FrameLifecycle {\n const abort = new AbortController();\n const queue: Item[] = [];\n const taskCancelCallbacks: Array<() => void> = [];\n\n const reportNormalStatus = (status: NormalStatus) => {\n // we want to report our status, however the flow of events can be confusing -\n // our callers anticipate an asynchronous (long running) frame to be started,\n // but there are scenarios in which the whole thing is completely synchronous\n // callers who are scheduling things may be surprised that their frame finished\n // before the code that handles it appears to start. thus, we make the entire lifecycle callback\n // system async, to prevent surprises.\n Promise.resolve().then(() => lifecycleCallback({ status }));\n };\n // when starting a frame, we greedily attempt to render any tasks that are already in the cache\n // however, if there is too much overhead (or too many tasks) we would risk hogging the main thread\n // thus - obey the limit (its a soft limit)\n const startTime = performance.now();\n\n for (let i = 0; i < items.length; i += 1) {\n const itemToRender = items[i];\n const requestFns = requestsForItem(itemToRender, settings, abort.signal);\n const cacheKey = (rq: string) => cacheKeyForRequest(rq, itemToRender, settings);\n const cacheKeys = Object.keys(requestFns).map(cacheKey);\n\n if (mutableCache.areKeysAllCached(cacheKeys)) {\n const result = mutableCache.cacheAndUse(requestFns, partial(render, itemToRender, settings), cacheKey);\n if (result !== undefined) {\n // this is a problem - the cache reported that all the keys are in the cache, however this result is a cancellation callback,\n // which indicates that the item could not be rendered right away, which should be impossible...\n // TODO\n taskCancelCallbacks.push(result);\n }\n } else {\n // areKeysAllCached returned false - enqueue for later\n queue.push(itemToRender);\n }\n if (performance.now() - startTime > queueTimeBudgetMS) {\n // we've used up all our time - enqueue all remaining tasks\n if (i < items.length - 1) {\n queue.push(...items.slice(i + 1));\n }\n break;\n }\n }\n\n if (queue.length === 0) {\n // we did all the work - it was already cached\n reportNormalStatus('finished_synchronously');\n return { cancelFrame: () => {} };\n }\n // TODO: Re-examine lifecycle reporting, potentially unify all statuses into a single type\n reportNormalStatus('begun');\n if (queue.length !== items.length) {\n // We did some work, but there's some left\n reportNormalStatus('progress');\n }\n const doWorkOnQueue = (intervalId: number) => {\n // try our best to cleanup if something goes awry\n const startWorkTime = performance.now();\n const cleanupOnError = (err: unknown) => {\n // clear the queue and the staging area (inFlight)\n for (const cancelMe of taskCancelCallbacks) {\n cancelMe();\n }\n queue.splice(0, queue.length);\n // stop fetching\n abort.abort(err);\n clearInterval(intervalId);\n // pass the error somewhere better:\n lifecycleCallback({ status: 'error', error: err });\n };\n while (mutableCache.getNumPendingTasks() < Math.max(maximumInflightAsyncTasks, 1)) {\n if (queue.length < 1) {\n // we cant add anything to the in-flight staging area, the final task\n // is already in flight\n if (mutableCache.getNumPendingTasks() < 1) {\n // we do want to wait for that last in-flight task to actually finish though:\n clearInterval(intervalId);\n reportNormalStatus('finished');\n }\n return;\n }\n\n const itemToRender = queue.shift();\n if (itemToRender === undefined) {\n // This should logically never happen, but if it does something is wrong so we emit an error\n cleanupOnError(new Error('Internal error: itemToRender was undefined'));\n return;\n }\n\n const toCacheKey = (rq: string) => cacheKeyForRequest(rq, itemToRender, settings);\n try {\n const result = mutableCache.cacheAndUse(\n requestsForItem(itemToRender, settings, abort.signal),\n partial(render, itemToRender, settings),\n toCacheKey,\n () => reportNormalStatus('progress'),\n );\n if (result !== undefined) {\n // put this cancel callback in a list where we can invoke if something goes wrong\n // note that it is harmless to cancel a task that was completed\n taskCancelCallbacks.push(result);\n }\n } catch (err) {\n cleanupOnError(err);\n }\n if (performance.now() - startWorkTime > queueTimeBudgetMS) {\n // used up all our time - leave remaining work for later\n break;\n }\n }\n };\n const interval = setInterval(() => doWorkOnQueue(interval), queueProcessingIntervalMS);\n\n // return a function to allow our caller to cancel the frame - guaranteed that no settings/data will be\n // touched/referenced after cancellation, unless the author of render() did some super weird bad things\n return {\n cancelFrame: (reason?: string) => {\n for (const cancelMe of taskCancelCallbacks) {\n cancelMe();\n }\n abort.abort(new DOMException(reason, 'AbortError'));\n clearInterval(interval);\n reportNormalStatus('cancelled');\n },\n };\n}\n","type MaybePromise<D> = D | Promise<D>;\ntype RecordKey = string | number | symbol;\nexport interface AsyncCache<SemanticKey extends RecordKey, CacheKey extends RecordKey, D> {\n isCached(k: CacheKey): boolean;\n getCachedUNSAFE(k: CacheKey): D | undefined;\n cacheAndUse(\n workingSet: Record<SemanticKey, () => Promise<D>>,\n use: (items: Record<SemanticKey, D>) => void,\n cacheKey: (semantic: SemanticKey) => CacheKey,\n ): cancelFn | undefined;\n}\n\ntype useFn<K extends RecordKey, D> = (items: Record<K, D>) => void;\ntype cancelFn = () => void;\ntype MutablePendingRequest<SemanticKey extends RecordKey, CacheKey extends RecordKey, D> = {\n runner: useFn<SemanticKey, D>;\n awaiting: Map<CacheKey, Set<SemanticKey>>;\n blocking: Set<CacheKey>; // these are the cache keys associated with the items in 'ready' - we keep them around to make it easy to make sure we dont delete something we assume we have\n // while an outstanding task is waiting on more data\n ready: Record<SemanticKey, D>;\n};\n// return true if the request is completely satisfied, false if its still awaiting more entries\nfunction updatePendingRequest<SemanticKey extends RecordKey, CacheKey extends RecordKey, D>(\n req: MutablePendingRequest<SemanticKey, CacheKey, D>,\n key: SemanticKey,\n cacheKey: CacheKey,\n item: D,\n): boolean {\n if (req.awaiting.has(cacheKey)) {\n const remaningAwaited = req.awaiting.get(cacheKey);\n // we just fullfilled one - remove it from awaiting\n remaningAwaited?.delete(key);\n if ((remaningAwaited?.size ?? 0) < 1) {\n req.awaiting.delete(cacheKey);\n }\n req.blocking.add(cacheKey);\n req.ready[key] = item;\n }\n return req.awaiting.size === 0;\n}\ntype MutableCacheEntry<D> = {\n data: MaybePromise<D>;\n lastRequestedTimestamp: number;\n abort: AbortController;\n};\n\n/**\n * `AsyncDataCache` asynchronous data cache, useful for minimizing network requests by caching the results of\n * a network request and returning the cached result if the request has already been made previously\n * for a given key.\n *\n * It is generalizable over any type of data.\n *\n * @example\n * const getMyData = ()=>fetch('https://example.com/data.json');\n * myCache.cache('myKey', getMyData).then((data)=>{console.log('its here now (and we cached it) ', data)});\n * }\n \n */\nexport class AsyncDataCache<SemanticKey extends RecordKey, CacheKey extends RecordKey, D>\n implements AsyncCache<SemanticKey, CacheKey, D>\n{\n private limit: number;\n private size: (d: D) => number;\n private destroyer: (d: D) => void;\n private entries: Map<CacheKey, MutableCacheEntry<D>>;\n private pendingRequests: Set<MutablePendingRequest<SemanticKey, CacheKey, D>>;\n\n /**\n * the intended use of this cache is to store resources used for rendering. Because the specific contents are generic, a simple interface must be provided\n * to support LRU cache eviction\n * occasionally, it can be necessary to manage these resources more explicitly (see https://stackoverflow.com/a/31250301 for a great example)\n * @param destroy a function which safely releases the resources owned by an entry in this cache - for normal garbage-collected objects, a no-op function will suffice.\n * @param size a function which returns the size of a resource - this is used only in relation to the cacheLimit\n * @param cacheLimit a limit (in whatever units are returned by the size() parameter) to place on cache contents\n * note that this limit is not a hard limit - old entries are evicted when new data is fetched, but the limit may be exceeded occasionally\n * a reasonable implementation may simply return 1 for size, and a desired occupancy count for the limit\n */\n constructor(destroy: (data: D) => void, size: (data: D) => number, cacheLimit: number) {\n this.size = size;\n this.destroyer = destroy;\n this.limit = cacheLimit;\n this.entries = new Map<CacheKey, MutableCacheEntry<D>>();\n this.pendingRequests = new Set<MutablePendingRequest<SemanticKey, CacheKey, D>>();\n }\n private usedSpace() {\n // Map uses iterators, so we're in for-loop territory here\n let sum = 0;\n for (const entry of this.entries.values()) {\n sum += entry.data instanceof Promise ? 0 : this.size(entry.data);\n }\n return sum;\n }\n private countRequests() {\n const reqCounts: Record<CacheKey, number> = {} as Record<CacheKey, number>;\n for (const req of this.pendingRequests) {\n for (const key of [...req.blocking, ...req.awaiting.keys()]) {\n if (!reqCounts[key]) {\n reqCounts[key] = 0;\n }\n reqCounts[key] += 1;\n }\n }\n return reqCounts;\n }\n // if the cache is full, sort candidates which are not currently requested by their last-used timestamps\n // evict those items until the cache is no longer full\n private evictIfFull() {\n // find entries which have 0 pending requests, and are not themselves promises...\n let used = this.usedSpace();\n const candidates: {\n key: CacheKey;\n data: D;\n lastRequestedTimestamp: number;\n }[] = [];\n if (used > this.limit) {\n // its potentially a bit slow to do this:\n const counts = this.countRequests();\n this.entries.forEach((entry, key) => {\n if (!(entry.data instanceof Promise) && (counts[key] ?? 0) < 1) {\n candidates.push({\n key,\n data: entry.data,\n lastRequestedTimestamp: entry.lastRequestedTimestamp,\n });\n }\n });\n const priority = candidates.sort((a, b) => a.lastRequestedTimestamp - b.lastRequestedTimestamp);\n for (const evictMe of priority) {\n used -= this.size(evictMe.data);\n this.destroyer(evictMe.data);\n this.entries.delete(evictMe.key);\n if (used < this.limit) {\n return;\n }\n }\n }\n }\n\n /**\n * `isCached` checks if the entry is in the cache with a resolved promise.\n *\n * @param key The entry key to check for in the cache\n * @returns True if the entry in the cache has been resolved, false if there is no entry with that key or the promise is still pending\n */\n isCached(key: CacheKey): boolean {\n // the key exists, and the value associated is not a promise\n return this.entries.has(key) && !(this.entries.get(key)?.data instanceof Promise);\n }\n\n /**\n * `areKeysAllCached` checks if all the keys provided are in the cache with resolved promises.\n *\n * Useful for checking if all the data needed for a particular operation is already in the cache.\n *\n * @param cacheKeys A list of keys to check for in the cache\n * @returns True if all keys are cached, false if any are not in the cache\n */\n areKeysAllCached(cacheKeys: readonly CacheKey[]): boolean {\n return cacheKeys.every((key) => this.isCached(key));\n }\n\n /**\n * @deprecated to alert (external) users to avoid calling this!\n * `getCachedUNSAFE` gets an entry from the cache for the given key (if the promise is resolved).\n * because of how eviction works - this method should be considered unsafe! consider the following\n * @example\n * const entry = cache.getCachedUnsafe('whatever')\n * const otherStuff = await fetch('....')\n * ... more code\n * doSomethingCool(entry, otherStuff)\n *\n * by the time the caller gets to the doSomethingCool call, the resources bound to the cache entry\n * may have been disposed!\n * do note that if you use a cache-entry synchronously (no awaits!) after requesting it, you're likely to not\n * encounter any issues, however its a much more robust practice to simply refactor like so:\n *\n * const otherStuff = await fetch('...')\n * cache.cacheAndUse({...}, (...args)=>doSomethingCool(otherStuff, ..args), ...)\n *\n * @param key Entry key to look up in the cache\n * @returns The entry (D) if it is present, or undefined if it is not\n */\n getCachedUNSAFE(key: CacheKey): D | undefined {\n const entry = this.entries.get(key);\n if (!entry) return undefined;\n\n entry.lastRequestedTimestamp = performance.now();\n return entry.data instanceof Promise ? undefined : entry?.data;\n }\n getNumPendingTasks(): number {\n return this.pendingRequests.size;\n }\n private dataArrived(key: SemanticKey, cacheKey: CacheKey, data: D) {\n this.evictIfFull(); // we just got some data - is there room in the cache?\n const mutableEntry = this.entries.get(cacheKey);\n if (mutableEntry) {\n mutableEntry.data = data;\n }\n const removeUs: MutablePendingRequest<SemanticKey, CacheKey, D>[] = [];\n for (const req of this.pendingRequests) {\n if (updatePendingRequest(req, key, cacheKey, data)) {\n req.runner(req.ready);\n removeUs.push(req);\n }\n }\n for (const finished of removeUs) {\n this.pendingRequests.delete(finished);\n }\n }\n private prepareCache(semanticKey: SemanticKey, cacheKey: CacheKey, getter: (signal: AbortSignal) => Promise<D>) {\n let promise: Promise<D>;\n const entry = this.entries.get(cacheKey);\n const data = entry?.data;\n // we either return early (data is cached)\n // or we initialize promise (either getter() or a pre-existing request for the same cachekey)\n // if we dont return early, we hook up a call to dataArrived to promise\n if (data) {\n if (data instanceof Promise) {\n promise = data;\n } else {\n // we could simply \"return data\"\n // however getCachedUnsafe updates its \"last-requested timestamp\"\n const resolvedCacheData = this.getCachedUNSAFE(cacheKey);\n if (!resolvedCacheData) throw new Error('unexpected undefined data');\n return resolvedCacheData;\n }\n } else {\n const abort = new AbortController();\n promise = getter(abort.signal);\n this.entries.set(cacheKey, {\n data: promise,\n lastRequestedTimestamp: performance.now(),\n abort,\n });\n }\n return promise.then((data) => {\n this.dataArrived(semanticKey, cacheKey, data);\n });\n }\n cacheAndUse(\n workingSet: Record<SemanticKey, (signal: AbortSignal) => Promise<D>>,\n use: (items: Record<SemanticKey, D>) => void,\n toCacheKey: (semanticKey: SemanticKey) => CacheKey,\n // TODO: consider removing taskFinished - it would be more simple to let the caller handle this in their use() function\n taskFinished?: () => void,\n ): cancelFn | undefined {\n const keys: SemanticKey[] = Object.keys(workingSet) as SemanticKey[];\n const req: MutablePendingRequest<SemanticKey, CacheKey, D> = {\n awaiting: new Map<CacheKey, Set<SemanticKey>>(),\n ready: {} as Record<SemanticKey, D>,\n runner: use,\n blocking: new Set<CacheKey>(),\n };\n for (const k of keys) {\n if (req.awaiting.has(toCacheKey(k))) {\n req.awaiting.get(toCacheKey(k))?.add(k);\n } else {\n req.awaiting.set(toCacheKey(k), new Set<SemanticKey>([k]));\n }\n }\n for (const semanticKey of keys) {\n const result = this.prepareCache(semanticKey, toCacheKey(semanticKey), workingSet[semanticKey]);\n if (result instanceof Promise) {\n const prom = taskFinished !== undefined ? result.then(taskFinished) : result;\n prom.catch((_reason) => {\n // delete the failed entry from the cache\n // also remove the entire request it belongs to\n this.entries.delete(toCacheKey(semanticKey));\n this.pendingRequests.delete(req);\n // note that catches get chained - so any catch handlers that came in with this promise\n // still get called\n });\n } else {\n if (updatePendingRequest(req, semanticKey, toCacheKey(semanticKey), result)) {\n use(req.ready);\n if (taskFinished !== undefined) {\n Promise.resolve().then(taskFinished); // we did the task synchronously...\n }\n\n // early return in the case that everything was cached!\n // the only thing this short-circuits is pendingRequests.add(req)\n // (because of course it isn't pending, because we just did it!)\n return undefined;\n }\n }\n }\n this.pendingRequests.add(req);\n return () => {\n this.pendingRequests.delete(req);\n };\n }\n}\n","import { Box2D, type box2D, type vec2 } from '@alleninstitute/vis-geometry';\nimport type REGL from 'regl';\nimport type { FrameLifecycle, RenderCallback } from '../render-queue';\nimport { type BufferPair, swapBuffers } from './buffer-pair';\n// a helper to render a 2D layer, using regl\nimport type { Image, ImageRenderer, RenderFn } from './types';\n\ntype EventType = Parameters<RenderCallback>[0];\ntype RequiredSettings = { camera: { view: box2D }; callback: RenderCallback };\n\nexport class ReglLayer2D<Renderable, RenderSettings extends RequiredSettings> {\n private buffers: BufferPair<Image>;\n private renderFn: RenderFn<Renderable, RenderSettings>;\n private runningFrame: FrameLifecycle | null;\n private regl: REGL.Regl;\n private renderImg: ImageRenderer;\n constructor(\n regl: REGL.Regl,\n imgRenderer: ImageRenderer,\n renderFn: RenderFn<Renderable, RenderSettings & RequiredSettings>,\n resolution: vec2,\n ) {\n this.buffers = {\n readFrom: {\n resolution,\n texture: regl.framebuffer(...resolution),\n bounds: undefined,\n },\n writeTo: {\n resolution,\n texture: regl.framebuffer(...resolution),\n bounds: undefined,\n },\n };\n this.renderImg = imgRenderer;\n this.regl = regl;\n this.runningFrame = null;\n this.renderFn = renderFn;\n }\n destroy() {\n this.runningFrame?.cancelFrame('destroy this layer');\n this.buffers.readFrom.texture.destroy();\n this.buffers.writeTo.texture.destroy();\n }\n renderingInProgress() {\n return this.runningFrame !== null;\n }\n\n getRenderResults(stage: 'prev' | 'cur') {\n return stage === 'cur' ? this.buffers.writeTo : this.buffers.readFrom;\n }\n onChange(\n props: {\n readonly data: Readonly<Renderable>;\n readonly settings: Readonly<RenderSettings>;\n },\n cancel = true,\n ) {\n if (cancel && this.runningFrame) {\n this.runningFrame.cancelFrame();\n this.runningFrame = null;\n const { readFrom, writeTo } = this.buffers;\n // copy our work to the prev-buffer...\n if (readFrom.bounds && writeTo.bounds && Box2D.intersection(readFrom.bounds, writeTo.bounds)) {\n const [width, height] = writeTo.resolution;\n this.renderImg({\n box: Box2D.toFlatArray(writeTo.bounds),\n img: writeTo.texture,\n target: readFrom.texture,\n viewport: {\n x: 0,\n y: 0,\n width,\n height,\n },\n view: Box2D.toFlatArray(readFrom.bounds),\n });\n }\n this.regl.clear({\n framebuffer: this.buffers.writeTo.texture,\n color: [0, 0, 0, 0],\n depth: 1,\n });\n }\n const { data, settings } = props;\n const { camera, callback } = settings;\n this.buffers.writeTo.bounds = camera.view;\n\n const wrapCallback: RenderSettings = {\n ...settings,\n callback: (ev: EventType) => {\n const { status } = ev;\n switch (status) {\n case 'finished':\n case 'finished_synchronously':\n this.buffers = swapBuffers(this.buffers);\n // only erase... if we would have cancelled...\n if (cancel) {\n this.regl.clear({\n framebuffer: this.buffers.writeTo.texture,\n color: [0, 0, 0, 0],\n depth: 1,\n });\n }\n this.runningFrame = null;\n break;\n }\n callback?.(ev);\n },\n };\n this.runningFrame = this.renderFn(this.buffers.writeTo.texture, data, wrapCallback);\n }\n}\n","export type BufferPair<T> = {\n writeTo: T;\n readFrom: T;\n};\nexport function swapBuffers<T>(doubleBuffer: BufferPair<T>) {\n const { readFrom, writeTo } = doubleBuffer;\n return { readFrom: writeTo, writeTo: readFrom };\n}\n","import { VisError } from './errors';\n\nconst RESOURCE_TYPE_S3 = 's3' as const;\nconst RESOURCE_TYPE_HTTPS = 'https' as const;\n\nexport type HttpsResource = {\n type: typeof RESOURCE_TYPE_HTTPS;\n url: string;\n};\n\nexport type S3Resource = {\n type: typeof RESOURCE_TYPE_S3;\n url: string;\n region: string;\n};\n\nexport function createHttpsResource(url: string) {\n return {\n type: RESOURCE_TYPE_HTTPS,\n url,\n };\n}\n\nexport function createS3Resource(url: string, region: string): S3Resource {\n return {\n type: RESOURCE_TYPE_S3,\n region,\n url,\n };\n}\n\nexport function isS3Resource(res: WebResource): res is S3Resource {\n return res && res.type === RESOURCE_TYPE_S3;\n}\n\nexport function isHttpsResource(res: WebResource): res is HttpsResource {\n return res && res.type === RESOURCE_TYPE_HTTPS;\n}\n\nexport type WebResource = HttpsResource | S3Resource;\n\nconst S3_REGION_BASIC_REGEX = /[a-z]+-[a-z]+-[1-9]/;\n\nfunction httpsFromS3Bucket(url: string, region: string) {\n // maybe region is controlled via the url or another arg in the future, so lets make it a variable\n const endOfBucket = url.indexOf('/', 5);\n const bucket = url.slice(5, endOfBucket);\n const path = url.slice(endOfBucket + 1);\n\n return `https://${bucket}.s3.${region}.amazonaws.com/${path}`;\n}\n\nfunction isValidS3URL(url: string): boolean {\n return !!url && url.length >= 6 && url.slice(0, 5) === 's3://';\n}\n\nfunction isValidS3Region(region: string): boolean {\n return !!region && S3_REGION_BASIC_REGEX.test(region);\n}\n\nexport function getResourceUrl(res: WebResource): string {\n if (res.type === 's3') {\n if (!isValidS3URL(res.url)) {\n throw new VisError('cannot get WebResource URL: invalid S3 URL');\n }\n if (!isValidS3Region(res.region)) {\n throw new VisError('cannot get WebResource URL: invalid S3 Region');\n }\n return httpsFromS3Bucket(res.url, res.region);\n }\n return res.url;\n}\n","export class VisError extends Error {}\n","import type { vec3, vec4 } from '@alleninstitute/vis-geometry';\nimport { logger } from './logger';\n\n// Tests for optional #, then 3 or 6 hex digits\nconst RGB_COLOR_REGEX = /^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;\n// Tests for optional #, then 4 or 8 hex digits\nconst RGBA_COLOR_REGEX = /^#?([0-9a-fA-F]{4}|[0-9a-fA-F]{8})$/;\n\n/**\n * Converts a color hash string to a vec3 RGB color vector.\n *\n * @param colorHashStr A string representing a color in hex format, e.g., '#f00' or 'ff0000'.\n * @param normalized A boolean indicating whether to normalize the color values to the range [0, 1]. Defaults to true.\n * @returns A vec3 array representing the RGB color vector. If the input is invalid, returns [0, 0, 0].\n */\nexport function makeRGBColorVector(colorHashStr: string, normalized = true): vec3 {\n if (!colorHashStr || !RGB_COLOR_REGEX.test(colorHashStr)) {\n logger.warn('invalid color hash string; returning black color vector (0, 0, 0)');\n return [0, 0, 0];\n }\n const hasHash = colorHashStr.charAt(0) === '#';\n const sanitizedColorHashStr = hasHash ? colorHashStr : `#${colorHashStr}`;\n\n const redCode =\n sanitizedColorHashStr.length === 4\n ? sanitizedColorHashStr.charAt(1) + sanitizedColorHashStr.charAt(1)\n : sanitizedColorHashStr.slice(1, 3);\n const greenCode =\n sanitizedColorHashStr.length === 4\n ? sanitizedColorHashStr.charAt(2) + sanitizedColorHashStr.charAt(2)\n : sanitizedColorHashStr.slice(3, 5);\n const blueCode =\n sanitizedColorHashStr.length === 4\n ? sanitizedColorHashStr.charAt(3) + sanitizedColorHashStr.charAt(3)\n : sanitizedColorHashStr.slice(5, 7);\n\n const divisor = normalized ? 255 : 1;\n return [\n Number.parseInt(redCode, 16) / divisor,\n Number.parseInt(greenCode, 16) / divisor,\n Number.parseInt(blueCode, 16) / divisor,\n ];\n}\n\n/**\n * Converts a color hash string to a vec4 RGBA color vector.\n *\n * @param colorHashStr A string representing a color in hex format, e.g., '#f00f' or 'ff0000ff'.\n * @param normalized A boolean indicating whether to normalize the color values to the range [0, 1]. Defaults to true.\n * @returns A vec3 array representing the RGB color vector. If the input is invalid, returns [0, 0, 0, 0].\n */\nexport function makeRGBAColorVector(colorHashStr: string, normalized = true): vec4 {\n if (!colorHashStr) {\n logger.warn('invalid color hash string; returning transparent black color vector (0, 0, 0, 0)');\n return [0, 0, 0, 0];\n }\n\n if (RGBA_COLOR_REGEX.test(colorHashStr)) {\n const hashHash = colorHashStr.charAt(0) === '#';\n const sanitizedColorHashStr = hashHash ? colorHashStr : `#${colorHashStr}`;\n\n const redCode =\n sanitizedColorHashStr.length === 5\n ? sanitizedColorHashStr.charAt(1) + sanitizedColorHashStr.charAt(1)\n : sanitizedColorHashStr.slice(1, 3);\n const greenCode =\n sanitizedColorHashStr.length === 5\n ? sanitizedColorHashStr.charAt(2) + sanitizedColorHashStr.charAt(2)\n : sanitizedColorHashStr.slice(3, 5);\n const blueCode =\n sanitizedColorHashStr.length === 5\n ? sanitizedColorHashStr.charAt(3) + sanitizedColorHashStr.charAt(3)\n : sanitizedColorHashStr.slice(5, 7);\n const alphaCode =\n sanitizedColorHashStr.length === 5\n ? sanitizedColorHashStr.charAt(4) + sanitizedColorHashStr.charAt(4)\n : sanitizedColorHashStr.slice(7, 9);\n const divisor = normalized ? 255 : 1;\n return [\n Number.parseInt(redCode, 16) / divisor,\n Number.parseInt(greenCode, 16) / divisor,\n Number.parseInt(blueCode, 16) / divisor,\n Number.parseInt(alphaCode, 16) / divisor,\n ];\n }\n if (RGB_COLOR_REGEX.test(colorHashStr)) {\n const rgb = makeRGBColorVector(colorHashStr, normalized);\n return [...rgb, normalized ? 1.0 : 255.0];\n }\n logger.warn('invalid color hash string; returning transparent black color vector (0, 0, 0, 0)');\n return [0, 0, 0, 0];\n}\n","type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'none';\n\nexport class Logger {\n private level: LogLevel;\n private name: string;\n\n constructor(name: string, level: LogLevel = 'warn') {\n this.name = name;\n this.level = level;\n }\n\n setLevel(level: LogLevel) {\n this.level = level;\n }\n\n private shouldLog(level: LogLevel): boolean {\n const levels: LogLevel[] = ['debug', 'info', 'warn', 'error', 'none'];\n return levels.indexOf(level) >= levels.indexOf(this.level);\n }\n\n private formatMessage(level: LogLevel, message: string): string {\n const timestamp = new Date().toISOString();\n return `[${timestamp}] [${this.name}] [${level.toUpperCase()}] ${message}`;\n }\n\n debug(message: string, ...optionalParams: unknown[]) {\n if (this.shouldLog('debug')) {\n // biome-ignore lint/suspicious/noConsole: This is a logger\n console.debug(this.formatMessage('debug', message), ...optionalParams);\n }\n }\n\n dir(obj: unknown, ...optionalParams: unknown[]) {\n if (this.shouldLog('debug')) {\n // biome-ignore lint/suspicious/noConsole: This is a logger\n console.log(this.formatMessage('debug', 'See object below'), ...optionalParams);\n // biome-ignore lint/suspicious/noConsole: This is a logger\n console.dir(obj);\n }\n }\n\n info(message: string, ...optionalParams: unknown[]) {\n if (this.shouldLog('info')) {\n // biome-ignore lint/suspicious/noConsole: This is a logger\n console.info(this.formatMessage('info', message), ...optionalParams);\n }\n }\n\n warn(message: string, ...optionalParams: unknown[]) {\n if (this.shouldLog('warn')) {\n // biome-ignore lint/suspicious/noConsole: This is a logger\n console.warn(this.formatMessage('warn', message), ...optionalParams);\n }\n }\n\n error(message: string, ...optionalParams: unknown[]) {\n if (this.shouldLog('error')) {\n // biome-ignore lint/suspicious/noConsole: This is a logger\n console.error(this.formatMessage('error', message), ...optionalParams);\n }\n }\n}\n\nexport const logger = new Logger('default');\n","import partial from 'lodash/partial';\nimport type REGL from 'regl';\nimport type { AsyncDataCache } from '../dataset-cache';\nimport type { ReglCacheEntry, Renderer } from './types';\n\n/// THIS file is a copy of render-queue, but with some changes made that I hope will make the idea of beginLongRunningFrame easier to use ///\n// TODO: delete (or make deprecated) the old one\n// the most obvious difference: a config parameter, rather than a function over 11 arguments!\n// the second difference is more subtle - you'll notice an \"isPrepared\" parameter, which we use to deal with some competing interests\n// 1. it would be nice to write render functions that use objects (see the type GpuData) rather than records from strings to the data we want\n// 2. this desire is complicated by our desire to share GPU-resident data if possible! because different renderers might want different \"objects\" to render which *could* all share raw gpu resources\n// it becomes very difficult to express the types of such a system statically.\n// SO: by having render-authors provide a type-guard, we can safely (provided the guard is reasonable) cast a record<string, gpuStuff> to a nice, friendly object 'GpuData' at runtime!\n// note also: the cache is set up to dissuade users from holding on to references to data in the cache - its still possible of course (this is typescript!) but the whole system is set up to accept\n// a generic useWithCache(...) function, which also makes this tricky\n\nexport type FrameLifecycle = {\n cancelFrame: (reason?: string) => void;\n};\n\nexport type FrameBegin = { status: 'begin' };\nexport type FrameProgress<Dataset, Item> = {\n status: 'progress';\n dataset: Dataset;\n renderedItems: ReadonlyArray<Item>;\n};\nexport type FrameCancelled = { status: 'cancelled' };\nexport type FrameFinished = { status: 'finished' };\nexport type FrameError = { status: 'error'; error: unknown };\n\nexport type AsyncFrameEvent<Dataset, Item> =\n | FrameBegin\n | FrameProgress<Dataset, Item>\n | FrameFinished\n | FrameCancelled\n | FrameError;\nexport type RenderCallback<Dataset, Item> = (event: AsyncFrameEvent<Dataset, Item>) => void;\n\nexport type RenderFrameConfig<\n Dataset,\n Item,\n Settings,\n RqKey extends string,\n CacheKey extends string,\n CacheEntryType,\n GpuData extends Record<RqKey, CacheEntryType>,\n> = {\n maximumInflightAsyncTasks: number; // Maximum number of in-flight fetches to run at any time for this frame\n queueProcessingIntervalMS: number; // The length of time to wait between processing the queue in milliseconds.\n queueTimeBudgetMS: number; // Spend at most (soft limit) this many milliseconds working on the queue at a time\n items: Item[]; // the items to render\n mutableCache: AsyncDataCache<RqKey, CacheKey, CacheEntryType>; // the cached results of fetching item contents\n dataset: Dataset; // the dataset comprised of all Items\n settings: Settings; // the settings (anything that is the same for the entire frame, think colors, point-sizes etc.)\n requestsForItem: (\n item: Item,\n dataset: Dataset,\n settings: Settings,\n signal?: AbortSignal,\n ) => Record<RqKey, (signal: AbortSignal) => Promise<CacheEntryType>>;\n lifecycleCallback: RenderCallback<Dataset, Item>;\n cacheKeyForRequest: (item: Item, requestKey: RqKey, dataset: Dataset, settings: Settings) => CacheKey;\n isPrepared: (cacheData: Record<RqKey, CacheEntryType | undefined>) => cacheData is GpuData;\n renderItem: (item: Item, dataset: Dataset, settings: Settings, gpuData: GpuData) => void;\n};\n\nexport function beginFrame<\n Dataset,\n Item,\n Settings,\n RqKey extends string,\n CacheKey extends string,\n CacheEntryType,\n GpuData extends Record<RqKey, CacheEntryType>,\n>(config: RenderFrameConfig<Dataset, Item, Settings, RqKey, CacheKey, CacheEntryType, GpuData>): FrameLifecycle {\n const {\n maximumInflightAsyncTasks,\n queueTimeBudgetMS,\n queueProcessingIntervalMS,\n cacheKeyForRequest,\n settings,\n items,\n mutableCache,\n lifecycleCallback,\n renderItem,\n requestsForItem,\n isPrepared,\n dataset,\n } = config;\n\n const abort = new AbortController();\n const queue: Item[] = [...items];\n const taskCancelCallbacks: Array<() => void> = [];\n const renderItemWrapper = (itemToRender: Item, maybe: Record<RqKey, CacheEntryType | undefined>) => {\n if (isPrepared(maybe) && !abort.signal.aborted) {\n renderItem(itemToRender, dataset, settings, maybe);\n }\n };\n const reportStatus = (event: AsyncFrameEvent<Dataset, Item>, synchronous: boolean) => {\n if (event.status !== 'cancelled' && abort.signal.aborted) {\n return;\n }\n // we want to report our status, however the flow of events can be confusing -\n // our callers anticipate an asynchronous (long running) frame to be started,\n // but there are scenarios in which the whole thing is completely synchronous\n // callers who are scheduling things may be surprised that their frame finished\n // before the code that handles it appears to start. thus, we make the entire lifecycle callback\n // system async, to prevent surprises.\n if (synchronous) {\n lifecycleCallback(event);\n } else {\n Promise.resolve().then(() => lifecycleCallback(event));\n }\n };\n\n const doWorkOnQueue = (intervalId: number, synchronous = false) => {\n // try our best to cleanup if something goes awry\n const startWorkTime = performance.now();\n const cleanupOnError = (err: unknown) => {\n // clear the queue and the staging area (inFlight)\n for (const cancelMe of taskCancelCallbacks) {\n cancelMe();\n }\n queue.splice(0, queue.length);\n // stop fetching\n abort.abort(err);\n clearInterval(intervalId);\n // pass the error somewhere better:\n reportStatus({ status: 'error', error: err }, synchronous);\n };\n while (mutableCache.getNumPendingTasks() < Math.max(maximumInflightAsyncTasks, 1)) {\n // We know there are items in the queue because of the check above, so we assert the type exist\n const itemToRender = queue.shift();\n if (!itemToRender) {\n break;\n }\n const toCacheKey = (rq: RqKey) => cacheKeyForRequest(itemToRender, rq, dataset, settings);\n try {\n const result = mutableCache.cacheAndUse(\n requestsForItem(itemToRender, dataset, settings, abort.signal),\n partial(renderItemWrapper, itemToRender),\n toCacheKey,\n () => reportStatus({ status: 'progress', dataset, renderedItems: [itemToRender] }, synchronous),\n );\n if (result !== undefined) {\n // put this cancel callback in a list where we can invoke if something goes wrong\n // note that it is harmless to cancel a task that was completed\n taskCancelCallbacks.push(result);\n }\n } catch (err) {\n cleanupOnError(err);\n }\n if (performance.now() - startWorkTime > queueTimeBudgetMS) {\n // used up all our time - leave remaining work for later\n break;\n }\n }\n if (queue.length < 1) {\n // we cant add anything to the in-flight staging area, the final task\n // is already in flight\n if (mutableCache.getNumPendingTasks() < 1) {\n // we do want to wait for that last in-flight task to actually finish though:\n clearInterval(intervalId);\n reportStatus({ status: 'finished' }, synchronous);\n }\n return;\n }\n };\n\n reportStatus({ status: 'begin' }, true);\n const interval = setInterval(() => doWorkOnQueue(interval), queueProcessingIntervalMS);\n if (queue.length > 0) {\n doWorkOnQueue(interval, false);\n }\n return {\n cancelFrame: (reason?: string) => {\n abort.abort(new DOMException(reason, 'AbortError'));\n for (const cancelMe of taskCancelCallbacks) {\n cancelMe();\n }\n clearInterval(interval);\n reportStatus({ status: 'cancelled' }, true);\n },\n };\n}\ntype QueueOptions = {\n queueProcessingIntervalMS?: number;\n maximumInflightAsyncTasks?: number;\n queueTimeBudgetMS?: number;\n};\nconst defaultQueueOptions = {\n queueProcessingIntervalMS: 33,\n maximumInflightAsyncTasks: 5,\n queueTimeBudgetMS: 16,\n} as const;\n\nexport function buildAsyncRenderer<\n Dataset,\n Item,\n Settings,\n SemanticKey extends string,\n CacheKeyType extends string,\n GpuData extends Record<SemanticKey, ReglCacheEntry>,\n>(renderer: Renderer<Dataset, Item, Settings, GpuData>, queueOptions?: QueueOptions) {\n return (\n data: Dataset,\n settings: Settings,\n callback: RenderCallback<Dataset, Item>,\n target: REGL.Framebuffer2D | null,\n cache: AsyncDataCache<SemanticKey, CacheKeyType, ReglCacheEntry>,\n ) => {\n const { renderItem, isPrepared, cacheKey, fetchItemContent, getVisibleItems } = renderer;\n const config: RenderFrameConfig<Dataset, Item, Settings, string, string, ReglCacheEntry, GpuData> = {\n ...defaultQueueOptions,\n ...queueOptions,\n cacheKeyForRequest: cacheKey,\n dataset: data,\n isPrepared: isPrepared,\n items: getVisibleItems(data, settings),\n lifecycleCallback: callback,\n mutableCache: cache,\n renderItem: partial(renderItem, target),\n requestsForItem: fetchItemContent,\n settings,\n };\n return beginFrame(config);\n };\n}\n","import { Vec2, type vec2 } from '@alleninstitute/vis-geometry';\nimport REGL from 'regl';\nimport { AsyncDataCache } from '../dataset-cache';\nimport type { FrameLifecycle } from '../render-queue';\nimport type { AsyncFrameEvent, RenderCallback } from './async-frame';\nimport type { ReglCacheEntry } from './types';\nimport { logger } from '../logger';\n\nfunction destroyer(item: ReglCacheEntry) {\n switch (item.type) {\n case 'texture':\n item.texture.destroy();\n break;\n case 'buffer':\n item.buffer.destroy();\n break;\n }\n}\n// return the size, in bytes, of some cached entity!\nfunction sizeOf(item: ReglCacheEntry) {\n return Math.max(1, item.bytes ?? 0);\n}\nconst oneMB = 1024 * 1024;\n\ntype ClientEntry = {\n frame: FrameLifecycle | null;\n image: REGL.Framebuffer2D;\n resolution: vec2;\n copyBuffer: ArrayBuffer;\n updateRequested: Compositor | null;\n};\ntype ServerActions = {\n copyToClient: (composite: Compositor) => void;\n};\ntype Compositor = (ctx: CanvasRenderingContext2D, glImage: ImageData) => void;\ntype RenderEvent<D, I> = AsyncFrameEvent<D, I> & {\n target: REGL.Framebuffer2D | null;\n server: ServerActions;\n};\ntype ServerCallback<D, I> = (event: RenderEvent<D, I>) => void;\ntype RenderFrameFn<D, I> = (\n target: REGL.Framebuffer2D | null,\n cache: AsyncDataCache<string, string, ReglCacheEntry>,\n callback: RenderCallback<D, I>,\n) => FrameLifecycle | null;\n\ntype Client = HTMLCanvasElement;\nexport class RenderServer {\n private canvas: OffscreenCanvas;\n private refreshRequested: boolean;\n regl: REGL.Regl;\n cache: AsyncDataCache<string, string, ReglCacheEntry>;\n private clients: Map<Client, ClientEntry>;\n private maxSize: vec2;\n constructor(maxSize: vec2, extensions: string[], cacheByteLimit: number = 2000 * oneMB) {\n this.canvas = new OffscreenCanvas(10, 10); // we always render to private buffers, so we dont need a real resolution here...\n this.clients = new Map();\n this.maxSize = maxSize;\n this.refreshRequested = false;\n const gl = this.canvas.getContext('webgl', {\n alpha: true,\n preserveDrawingBuffer: false,\n antialias: true,\n premultipliedAlpha: true,\n });\n if (!gl) {\n throw new Error('WebGL not supported!');\n }\n const regl = REGL({\n gl,\n extensions,\n });\n this.regl = regl;\n this.cache = new AsyncDataCache<string, string, ReglCacheEntry>(destroyer, sizeOf, cacheByteLimit);\n }\n private copyToClient(frameInfo: ClientEntry, client: Client) {\n // note: compared transferImageFromBitmap(transferImageToBitmap()), drawImage(canvas) and a few other variations\n // this method seems to have the most consistent performance across various browsers\n const { resolution, copyBuffer, image, updateRequested } = frameInfo;\n const [width, height] = resolution;\n if (updateRequested) {\n try {\n // read directly from the framebuffer to which we render:\n this.regl?.read({\n framebuffer: image,\n x: 0,\n y: 0,\n width,\n height,\n data: new Uint8Array(copyBuffer),\n });\n // then put those bytes in the client canvas:\n const ctx = client.getContext('2d');\n\n if (!ctx) {\n logger.error('Could not get 2d context');\n throw new Error('Could not get 2d context');\n }\n\n const img = new ImageData(new Uint8ClampedArray(copyBuffer), width, height);\n updateRequested(ctx, img);\n } catch {\n logger.error(\n 'error - we tried to copy to a client buffer, but maybe it got unmounted? that can happen, its ok',\n );\n }\n }\n }\n private onAnimationFrame() {\n if (this.refreshRequested) {\n for (const [client, entry] of this.clients) {\n if (entry.updateRequested) {\n this.copyToClient(entry, client);\n // mark our progress:\n entry.updateRequested = null;\n }\n }\n this.refreshRequested = false;\n }\n }\n private requestComposition(client: Client, composite: Compositor) {\n const c = this.clients.get(client);\n if (c) {\n if (!c.updateRequested) {\n c.updateRequested = composite;\n if (!this.refreshRequested) {\n this.refreshRequested = true;\n // as of 2023, requestAnimationFrame should be generally available globally in both workers* and a window\n // if this becomes an issue, we can have our caller pass requestAnimationFrame in to the constructor\n requestAnimationFrame(() => this.onAnimationFrame());\n }\n }\n }\n }\n private clientFrameFinished(client: Client) {\n const C = this.clients.get(client);\n if (C) {\n C.frame = null;\n }\n }\n destroyClient(client: Client) {\n const C = this.clients.get(client);\n if (C) {\n C.frame?.cancelFrame();\n }\n this.clients.delete(client);\n }\n private prepareToRenderToClient(client: Client) {\n const previousEntry = this.clients.get(client);\n if (previousEntry) {\n previousEntry.updateRequested = null;\n // the client is mutable - so every time we get a request, we have to check to see if it got resized\n if (client.width !== previousEntry.resolution[0] || client.height !== previousEntry.resolution[1]) {\n // handle resizing by deleting previously allocated resources:\n previousEntry.image.destroy();\n // the rest will get GC'd normally\n } else {\n // use the existing resources!\n return previousEntry;\n }\n }\n const resolution = Vec2.min(this.maxSize, [client.width, client.height]);\n const copyBuffer = new ArrayBuffer(resolution[0] * resolution[1] * 4);\n const image = this.regl.framebuffer(...resolution);\n return { resolution, copyBuffer, image };\n }\n beginRendering<D, I>(renderFn: RenderFrameFn<D, I>, callback: ServerCallback<D, I>, client: Client) {\n if (this.regl) {\n const clientFrame = this.clients.get(client);\n if (clientFrame?.frame) {\n clientFrame.frame.cancelFrame();\n this.regl.clear({\n framebuffer: clientFrame.image,\n color: [0, 0, 0, 0],\n depth: 1,\n });\n clientFrame.updateRequested = null;\n }\n const { image, resolution, copyBuffer } = this.prepareToRenderToClient(client);\n const hijack: RenderCallback<D, I> = (e) => {\n callback({\n ...e,\n target: image,\n server: {\n copyToClient: (compose: Compositor) => {\n this.requestComposition(client, compose);\n },\n },\n });\n if (e.status === 'finished' || e.status === 'cancelled') {\n this.clientFrameFinished(client);\n }\n };\n this.clients.set(client, {\n frame: null,\n image,\n copyBuffer,\n resolution,\n updateRequested: null,\n });\n // this is worded rather awkwardly, because sometimes the frameLifecycle object returned by renderFn() represents\n // a frame that is already finished!\n // this is a good thing for performance, but potentially confusing - so we do our book-keeping before we actually start rendering:\n const aboutToStart = this.clients.get(client); // this is the record we just put into the clients map - TS just wants to be sure it really exists:\n if (aboutToStart) {\n const frame = renderFn(image, this.cache, hijack);\n if (frame) {\n aboutToStart.frame = {\n cancelFrame: (reason?: string) => {\n frame.cancelFrame(reason);\n aboutToStart.updateRequested = null;\n },\n };\n }\n }\n }\n }\n}\n","import { MinHeap } from './min-heap';\nimport { KeyedMinHeap } from './keyed-heap';\n\ntype CacheKey = string;\nexport interface Cacheable {\n destroy?: () => void;\n sizeInBytes: () => number;\n}\n\nexport interface Store<K extends {}, V> {\n set(k: K, v: V): void;\n get(k: K): V | undefined;\n has(k: K): boolean;\n delete(k: K): void;\n keys(): Iterable<K>;\n values(): Iterable<V>;\n}\n\nexport type ScoreFn = (k: CacheKey) => number;\n\ntype PendingCacheable<T extends Cacheable> = {\n key: CacheKey;\n fetch: (sig: AbortSignal) => Promise<T>;\n};\n\nfunction negate(fn: ScoreFn) {\n return (k: CacheKey) => -fn(k);\n}\n\nexport type FetchResult = { status: 'success' } | { status: 'failure'; reason: unknown };\n\nexport class PriorityCache<T extends Cacheable> {\n #store: Store<CacheKey, T>;\n #evictPriority: MinHeap<CacheKey>;\n #limit: number;\n #used: number;\n #score: ScoreFn;\n\n // items with lower scores will be evicted before items with high scores\n constructor(store: Store<CacheKey, T>, score: ScoreFn, limitInBytes: number) {\n this.#store = store;\n this.#score = score;\n this.#evictPriority = new MinHeap<CacheKey>(5000, score);\n this.#limit = limitInBytes;\n this.#used = 0;\n }\n\n protected get score(): ScoreFn {\n return this.#score;\n }\n\n // add {key:item} to the cache - return false (and fail) if the key is already present\n // may evict items to make room\n // return true on success\n put(key: CacheKey, item: T): boolean {\n if (this.#store.has(key)) {\n return false;\n }\n const size = this.sanitizedSize(item);\n if (this.#used + size > this.#limit) {\n this.evictUntil(Math.max(0, this.#limit - size));\n }\n this.#evictPriority.addItem(key);\n this.#store.set(key, item);\n this.#used += size;\n return true;\n }\n private sanitizedSize(item: T) {\n const givenSize = item.sizeInBytes?.() ?? 0;\n const size = Number.isFinite(givenSize) ? Math.max(0, givenSize) : 0;\n return size;\n }\n\n // it is expected that the score function is not \"pure\" -\n // it has a closure over data that changes over time, representing changing priorities\n // thus - the owner of this cache has a responsibility to notify the cache when significant\n // changes in priority occur!\n reprioritize(score?: ScoreFn | undefined) {\n this.#evictPriority.rebuild(score);\n }\n\n get(key: CacheKey): T | undefined {\n return this.#store.get(key);\n }\n\n has(key: CacheKey): boolean {\n return this.#store.has(key);\n }\n\n cached(key: CacheKey): boolean {\n return this.#store.has(key);\n }\n\n isFull(): boolean {\n return this.#used >= this.#limit;\n }\n\n private evictLowestPriority() {\n const evictMe = this.#evictPriority.popMinItem();\n if (evictMe === null) return false;\n\n const data = this.#store.get(evictMe);\n if (data) {\n data.destroy?.();\n this.#store.delete(evictMe);\n const size = this.sanitizedSize(data);\n this.#used -= size;\n }\n return true;\n }\n\n private evictUntil(targetUsedBytes: number) {\n while (this.#used > targetUsedBytes) {\n if (!this.evictLowestPriority()) {\n // note: evictLowestPriority mutates this.used\n return; // all items evicted...\n }\n }\n }\n}\n\nexport class AsyncPriorityCache<T extends Cacheable> extends PriorityCache<T> {\n #fetchPriority: KeyedMinHeap<PendingCacheable<T>, CacheKey>;\n #pendingFetches: Map<CacheKey, AbortController>;\n #MAX_INFLIGHT_FETCHES: number;\n #notify: undefined | ((k: CacheKey, result: FetchResult) => void);\n\n // items with lower scores will be evicted before items with high scores\n constructor(\n store: Store<CacheKey, T>,\n score: (k: CacheKey) => number,\n limitInBytes: number,\n maxFetches: number,\n onDataArrived?: (key: CacheKey, result: FetchResult) => void,\n ) {\n super(store, score, limitInBytes);\n\n this.#fetchPriority = new KeyedMinHeap<PendingCacheable<T>, CacheKey>(5000, negate(score), (pr) => pr.key);\n this.#pendingFetches = new Map();\n this.#MAX_INFLIGHT_FETCHES = maxFetches;\n this.#notify = onDataArrived;\n }\n\n enqueue(key: CacheKey, fetcher: (abort: AbortSignal) => Promise<T>): boolean {\n // enqueue the item, if we dont already have it, or are not already asking\n if (!this.has(key) && !this.#pendingFetches.has(key) && !this.#fetchPriority.hasItemWithKey(key)) {\n this.#fetchPriority.addItem({ key, fetch: fetcher });\n this.#fetchToLimit();\n return true;\n }\n return false;\n }\n\n async #beginFetch({ key, fetch }: PendingCacheable<T>) {\n const abort = new AbortController();\n this.#pendingFetches.set(key, abort);\n return fetch(abort.signal)\n .then((resource) => {\n this.put(key, resource);\n this.#notify?.(key, { status: 'success' });\n })\n .catch((reason) => {\n this.#notify?.(key, { status: 'failure', reason });\n })\n .finally(() => {\n this.#pendingFetches.delete(key);\n this.#fetchToLimit();\n });\n }\n\n #fetchToLimit() {\n let toFetch = Math.max(0, this.#MAX_INFLIGHT_FETCHES - this.#pendingFetches.size);\n for (let i = 0; i < toFetch; i++) {\n const fetchMe = this.#fetchPriority.popMinItemWithScore();\n if (fetchMe !== null) {\n if (fetchMe.score !== 0) {\n this.#beginFetch(fetchMe.item);\n } else {\n toFetch += 1; // increasing the loop limit inside the loop... a bit sketchy\n }\n } else {\n // if we hit a null, we can stop early - the fetch queue is empty\n break;\n }\n }\n }\n\n // it is expected that the score function is not \"pure\" -\n // it has a closure over data that changes over time, representing changing priorities\n // thus - the owner of this cache has a responsibility to notify the cache when significant\n // changes in priority occur!\n override reprioritize(score?: ScoreFn | undefined) {\n super.reprioritize(score);\n const sc = score ?? this.score;\n this.#fetchPriority.rebuild(negate(sc));\n for (const [key, abort] of this.#pendingFetches) {\n if (sc(key) === 0) {\n abort.abort('deprioritized');\n this.#pendingFetches.delete(key);\n }\n }\n }\n\n pending(key: CacheKey): boolean {\n return this.#fetchPriority.hasItemWithKey(key) || this.#pendingFetches.has(key);\n }\n\n cachedOrPending(key: CacheKey): boolean {\n return this.cached(key) || this.pending(key);\n }\n}\n","// TS note: T extends {} is saying \"T may not be null\"\nexport class MinHeap<T extends {}> {\n private entries: T[];\n private score: (t: T) => number;\n private curSize: number;\n constructor(size: number, scoreSystem: (t: T) => number) {\n this.score = scoreSystem;\n this.entries = new Array<T>(size);\n this.curSize = 0;\n }\n private parent(i: number) {\n return Math.floor((i - 1) / 2);\n }\n private left(i: number) {\n return Math.floor(2 * i + 1);\n }\n private right(i: number) {\n return Math.floor(2 * i + 2);\n }\n private swap(i: number, j: number) {\n const tmp = this.entries[i];\n this.entries[i] = this.entries[j];\n this.entries[j] = tmp;\n }\n addItem(t: T, score?: number) {\n this.entries[this.curSize] = t;\n this.curSize += 1;\n const myIndex = this.curSize - 1;\n let i = myIndex;\n const myScore = score ?? this.score(t);\n while (\n i !== 0 &&\n this.score(this.entries[this.parent(i)]) > (i === myIndex ? myScore : this.score(this.entries[i]))\n ) {\n this.swap(i, this.parent(i));\n i = this.parent(i);\n }\n }\n private heapify(i: number) {\n const l = this.left(i);\n const r = this.right(i);\n let smallest = i;\n if (l < this.curSize && this.score(this.entries[l]) < this.score(this.entries[i])) {\n smallest = l;\n }\n if (r < this.curSize && this.score(this.entries[r]) < this.score(this.entries[smallest])) {\n smallest = r;\n }\n if (smallest !== i) {\n this.swap(i, smallest);\n this.heapify(smallest);\n }\n }\n rebuild(score?: (t: T) => number) {\n this.score = score ?? this.score;\n for (let i = this.curSize - 1; i >= 0; i -= 1) {\n this.heapify(i);\n }\n }\n popItem(i: number): T | null {\n while (i !== 0) {\n this.swap(i, this.parent(i));\n /** biome-ignore lint/style/noParameterAssign: a great example of why we should ditch this linter */\n i = this.parent(i);\n }\n return this.popMinItem();\n }\n peekMinItem(): T | null {\n if (this.curSize < 1) {\n return null;\n }\n return this.entries[0];\n }\n popMinItem(): T | null {\n if (this.curSize < 1) {\n return null;\n }\n const item = this.entries[0];\n this.curSize -= 1;\n if (this.curSize > 0) {\n this.entries[0] = this.entries[this.curSize];\n this.heapify(0);\n }\n return item;\n }\n popMinItemWithScore(): { item: T; score: number } | null {\n const t = this.popMinItem();\n return t === null ? null : { item: t, score: this.score(t) };\n }\n}\n","import { MinHeap } from './min-heap';\n\n// its a min-heap, however items must have a key associated with them,\n// this enables the keyedHeap to efficiently implement the has() function\n// this also means its not possible to store duplicates in the heap\nexport class KeyedMinHeap<T, K extends string> {\n private heap: MinHeap<K>;\n private items: Map<K, T>;\n private keyFn: (t: T) => K;\n constructor(size: number, scoreSystem: (k: K) => number, keyFn: (t: T) => K) {\n this.heap = new MinHeap<K>(size, scoreSystem);\n this.keyFn = keyFn;\n this.items = new Map();\n }\n\n addItem(item: T) {\n const key = this.keyFn(item);\n if (!this.items.has(key)) {\n this.heap.addItem(key);\n this.items.set(key, item);\n }\n }\n popMinItem(): T | null {\n const min = this.heap.popMinItem();\n if (min !== null) {\n const item = this.items.get(min) ?? null;\n this.items.delete(min);\n return item;\n }\n return null;\n }\n popMinItemWithScore(): null | { item: T; score: number } {\n const entry = this.heap.popMinItemWithScore();\n if (entry !== null) {\n const key = entry.item;\n const item = this.items.get(key);\n this.items.delete(key);\n return item ? { item, score: entry.score } : null;\n }\n return null;\n }\n has(item: T) {\n return this.items.has(this.keyFn(item));\n }\n rebuild(score?: (k: K) => number) {\n this.heap.rebuild(score);\n }\n hasItemWithKey(k: K) {\n return this.items.has(k);\n }\n}\n","import { type Store, type Cacheable, type FetchResult, AsyncPriorityCache } from './priority-cache';\nimport { mergeAndAdd, prioritizeCacheKeys, priorityDelta } from './utils';\nimport uniqueId from 'lodash/uniqueId';\n\n// goal: we want clients of the cache to experience a type-safe interface -\n// they expect that the things coming out of the cache are the type they expect (what they put in it)\n// this is not strictly true, as the cache is shared, and other clients may use different types\n// also also - there will not be a 1:1 relation between items and\n// explanation of terms:\n// Item = a placeholder for something in the cache, used as a key in the cache. good examples:\n// metadata {url, bounds} for a tile in a larger dataset.\n// ItemContent = the actual heavy data that Item is a placeholder for - for example one or more arrays of\n// raw data used by the client of the cache - the value we are caching.\ntype CacheInterface<Item, ItemContent extends Record<string, Cacheable>> = {\n get: (k: Item) => ItemContent | undefined;\n has: (k: Item) => boolean;\n unsubscribeFromCache: () => void;\n setPriorities: (low: Iterable<Item>, high: Iterable<Item>) => void;\n};\n\nexport type ClientSpec<Item, ItemContent extends Record<string, Cacheable>> = {\n isValue: (v: Record<string, Cacheable | undefined>) => v is ItemContent;\n cacheKeys: (item: Item) => { [k in keyof ItemContent]: string };\n onDataArrived?: (cacheKey: string, result: FetchResult) => void;\n fetch: (item: Item) => { [k in keyof ItemContent]: (abort: AbortSignal) => Promise<Cacheable> };\n};\n\ntype KV<T extends Record<string, unknown>> = readonly [keyof T, T[keyof T]];\n\nfunction entries<T extends Record<string, unknown>>(t: T): ReadonlyArray<KV<T>> {\n return Object.entries(t) as ReadonlyArray<KV<T>>;\n}\nfunction mapFields<R extends Record<string, unknown>, Result>(\n r: R,\n fn: (v: R[keyof R]) => Result,\n): { [k in keyof R]: Result } {\n return entries(r).reduce(\n (acc, [k, v]) => {\n acc[k] = fn(v);\n return acc;\n },\n {} as { [k in keyof R]: Result },\n );\n}\n\ntype Client = {\n priorities: Record<string, number>;\n notify:\n | undefined\n | ((cacheKey: string, result: { status: 'success' } | { status: 'failure'; reason: unknown }) => void);\n};\nexport class SharedPriorityCache {\n private cache: AsyncPriorityCache<Cacheable>;\n private clients: Record<string, Client>;\n private importance: Record<string, number>;\n constructor(store: Store<string, Cacheable>, limitInBytes: number, max_concurrent_fetches = 10) {\n this.importance = {};\n this.clients = {};\n this.cache = new AsyncPriorityCache(\n store,\n (ck) => this.importance[ck] ?? 0,\n limitInBytes,\n max_concurrent_fetches,\n (ck, result) => this.onCacheEntryArrived(ck, result),\n );\n }\n registerClient<Item, ItemContent extends Record<string, Cacheable>>(\n spec: ClientSpec<Item, ItemContent>,\n ): CacheInterface<Item, ItemContent> {\n const id = uniqueId('client');\n this.clients[id] = { priorities: {}, notify: spec.onDataArrived };\n\n const enqueuePriorities = (spec: ClientSpec<Item, ItemContent>, items: Iterable<Item>) => {\n for (const item of items) {\n const keys = spec.cacheKeys(item);\n Object.entries(spec.fetch(item)).forEach(([sk, fetcher]) => {\n const ck = keys[sk];\n if (ck !== undefined) {\n this.cache.enqueue(ck, fetcher);\n }\n });\n }\n };\n const setPriorities = (low: Iterable<Item>, high: Iterable<Item>) => {\n const client = this.clients[id];\n\n if (!client) return; // the client can hold onto a reference to this interface, even after they call unregister - this prevents a crash in that scenario\n\n const updated = mergeAndAdd(prioritizeCacheKeys(spec, low, 1), prioritizeCacheKeys(spec, high, 2));\n let changed = 0;\n priorityDelta(client.priorities, updated, (cacheKey, delta) => {\n changed += delta !== 0 ? 1 : 0;\n this.updateImportance(cacheKey, delta);\n });\n if (changed === 0) {\n // nothing changed at all - no need to reprioritize, nor enqueue requests\n return;\n }\n this.cache.reprioritize((ck) => this.importance[ck] ?? 0);\n client.priorities = updated;\n\n // note: many keys may already be cached, or requested - its harmless to re-request them.\n // there is obviously some overhead, but in testing it seems fine\n enqueuePriorities(spec, high);\n enqueuePriorities(spec, low);\n };\n\n return {\n get: (k: Item) => {\n const keys = spec.cacheKeys(k);\n const v = mapFields<Record<string, string>, Cacheable | undefined>(keys, (k) => this.cache.get(k));\n return spec.isValue(v) ? v : undefined;\n },\n has: (k: Item) => {\n const atLeastOneMissing = Object.values(spec.cacheKeys(k)).some((ck) => !this.cache.has(ck));\n return !atLeastOneMissing;\n },\n\n unsubscribeFromCache: () => {\n setPriorities([], []); // mark that this client has no priorities, which will decrement the counts for all\n // priorities it used to have\n delete this.clients[id];\n },\n setPriorities,\n };\n }\n private onCacheEntryArrived(key: string, result: FetchResult) {\n // find any clients that want this...\n // and notify them\n for (const cid of Object.keys(this.clients)) {\n const client = this.clients[cid];\n if ((client.priorities[key] ?? 0) > 0) {\n client.notify?.(key, result);\n }\n }\n }\n private updateImportance(key: string, delta: number) {\n this.importance[key] = Math.max(0, (this.importance[key] ?? 0) + delta);\n }\n}\n","import type { Cacheable } from './priority-cache';\nimport type { ClientSpec } from './shared-cache';\n\n// some utils for tracking changing priorities in our priority cache\n\nexport function prioritizeCacheKeys<Item, ItemContent extends Record<string, Cacheable>>(\n spec: ClientSpec<Item, ItemContent>,\n items: Iterable<Item>,\n priority: 1 | 2,\n) {\n const pri: Record<string, number> = {};\n for (const item of items) {\n const keys = spec.cacheKeys(item);\n for (const cacheKey of Object.values(keys)) {\n pri[cacheKey] = (pri[cacheKey] ?? 0) + priority;\n }\n }\n return pri;\n}\nexport function mergeAndAdd(A: Record<string, number>, B: Record<string, number>) {\n const sum: Record<string, number> = {};\n for (const a in A) {\n sum[a] = A[a] + (B[a] ?? 0);\n }\n for (const b in B) {\n if (!(b in A)) {\n sum[b] = B[b];\n } // else we've already dealt with it\n }\n return sum;\n}\nexport function priorityDelta(\n old: Record<string, number>,\n current: Record<string, number>,\n update: (key: string, value: number) => void,\n) {\n for (const o in old) {\n const curPri = current[o] ?? 0;\n const prevPri = old[o];\n update(o, curPri - prevPri);\n }\n for (const c in current) {\n if (!(c in old)) {\n update(c, current[c]);\n } // else we've already dealt with the diff\n }\n}\n","export type WorkerMessage = {\n type: string;\n};\n\nexport type WorkerMessageWithId = WorkerMessage & {\n id: string;\n};\n\nexport function isWorkerMessage(val: unknown): val is WorkerMessage {\n return (\n val !== undefined &&\n val !== null &&\n typeof val === 'object' &&\n 'type' in val &&\n typeof val.type === 'string' &&\n val.type.length > 0\n );\n}\n\nexport function isWorkerMessageWithId(val: unknown): val is WorkerMessageWithId {\n return isWorkerMessage(val) && 'id' in val && typeof val.id === 'string' && val.id.length > 0;\n}\n\nexport type HeartbeatMessage = {\n type: 'heartbeat';\n};\n\nexport function isHeartbeatMessage(val: unknown): val is HeartbeatMessage {\n return isWorkerMessage(val) && val.type === 'heartbeat';\n}\n\nexport const HEARTBEAT_RATE_MS = 500;\n","import { v4 as uuidv4 } from 'uuid';\nimport { logger } from '../logger';\nimport { isHeartbeatMessage, isWorkerMessageWithId, type WorkerMessage, type WorkerMessageWithId } from './messages';\n\ntype PromiseResolve<T extends WorkerMessageWithId> = (t: T) => void;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n// biome-ignore lint/suspicious/noExplicitAny: This is aligned with the standard Promise API\ntype PromiseReject = (reason: any) => void;\n\ntype MessageValidator<T> = TypeGuardFunction<unknown, T>;\n\ntype TypeGuardFunction<T, S extends T> = (value: T) => value is S;\n\nexport type WorkerInstantiationCallback = () => Worker;\n\nexport type WorkerInit = URL | WorkerInstantiationCallback;\n\ntype MessagePromise = {\n validator: MessageValidator<WorkerMessageWithId>;\n resolve: PromiseResolve<WorkerMessageWithId>;\n reject: PromiseReject;\n promise: Promise<WorkerMessageWithId>;\n};\n\nexport enum WorkerStatus {\n Available = 'Available',\n Unresponsive = 'Unresponsive',\n}\n\nexport class WorkerPool {\n #workers: Worker[];\n #promises: Map<string, MessagePromise>;\n #timeOfPreviousHeartbeat: Map<number, number>;\n #which: number;\n\n constructor(size: number, workerInit: WorkerInit) {\n this.#workers = new Array(size);\n this.#timeOfPreviousHeartbeat = new Map();\n for (let i = 0; i < size; i++) {\n if (workerInit instanceof URL) {\n this.#workers[i] = new Worker(workerInit, { type: 'module' });\n } else {\n this.#workers[i] = workerInit();\n }\n this.#workers[i].onmessage = (msg) => this.#handleMessage(i, msg);\n this.#timeOfPreviousHeartbeat.set(i, 0);\n }\n this.#promises = new Map();\n this.#which = 0;\n }\n /**\n * Warning - nothing in this class should be considered useable after\n * calling this method - any/all methods called should be expected to be\n * completely unreliable. dont call me unless you're about to dispose of all references to this object\n */\n destroy() {\n for (let i = 0; i < this.#workers.length; i++) {\n this.#workers[i].terminate();\n }\n this.#workers = [];\n }\n #handleMessage(workerIndex: number, msg: MessageEvent<unknown>) {\n const { data } = msg;\n if (isHeartbeatMessage(data)) {\n this.#timeOfPreviousHeartbeat.set(workerIndex, Date.now());\n return;\n }\n if (isWorkerMessageWithId(data)) {\n logger.debug(`worker ${workerIndex} responded to a message`);\n const { id } = data;\n const messagePromise = this.#promises.get(id);\n if (messagePromise === undefined) {\n logger.warn('unexpected message from worker');\n return;\n }\n this.#promises.delete(id);\n if (!messagePromise.validator(data)) {\n const reason = 'invalid response from worker: message type did not match expected type';\n logger.error(reason);\n messagePromise.reject(new Error(reason));\n return;\n }\n messagePromise.resolve(data);\n } else {\n logger.debug(`worker ${workerIndex} received an invalid message`);\n const reason = 'encountered an invalid message; skipping';\n logger.warn(reason);\n }\n }\n\n #roundRobin() {\n this.#which = (this.#which + 1) % this.#workers.length;\n }\n\n async submitRequest(\n message: WorkerMessage,\n responseValidator: MessageValidator<WorkerMessageWithId>,\n transfers: Transferable[],\n signal?: AbortSignal | undefined,\n ): Promise<WorkerMessageWithId> {\n if (this.#workers.length < 1) {\n return Promise.reject('this woorker pool has been disposed');\n }\n const reqId = `rq${uuidv4()}`;\n const workerIndex = this.#which;\n const messageWithId = { ...message, id: reqId };\n const messagePromise = this.#createMessagePromise(responseValidator);\n logger.debug(`worker ${workerIndex} being handed a request`);\n\n this.#promises.set(reqId, messagePromise);\n\n if (signal) {\n signal.addEventListener('abort', () => {\n this.#sendMessageToWorker(workerIndex, { type: 'cancel', id: reqId }, []);\n messagePromise.reject('cancelled');\n });\n }\n\n this.#sendMessageToWorker(workerIndex, messageWithId, transfers);\n this.#roundRobin();\n return messagePromise.promise;\n }\n\n #sendMessageToWorker(workerIndex: number, message: WorkerMessageWithId, transfers: Transferable[]) {\n const worker = this.#workers[workerIndex];\n if (worker === undefined) {\n throw new Error('cannot send message to worker: index invalid');\n }\n worker.postMessage(message, transfers);\n }\n\n #createMessagePromise(responseValidator: MessageValidator<WorkerMessageWithId>): MessagePromise {\n const { promise, resolve, reject } = Promise.withResolvers<WorkerMessageWithId>();\n\n return {\n validator: responseValidator,\n resolve,\n reject,\n promise,\n };\n }\n\n #isValidIndex(index: number): boolean {\n const len = this.#workers.length;\n return index < len && index >= 0;\n }\n\n getStatus(workerIndex: number): WorkerStatus {\n if (!this.#isValidIndex(workerIndex)) {\n throw new Error('invalid worker index');\n }\n const lastHeartbeat = this.#timeOfPreviousHeartbeat.get(workerIndex) ?? 0;\n if (lastHeartbeat === 0) {\n return WorkerStatus.Unresponsive;\n }\n const delta = Date.now() - lastHeartbeat;\n if (delta && delta > 1500) {\n return WorkerStatus.Unresponsive;\n }\n return WorkerStatus.Available;\n }\n\n getStatuses(): ReadonlyMap<number, WorkerStatus> {\n return this.#workers.reduce<Map<number, WorkerStatus>>((acc, _w, i) => {\n const delta = Date.now() - (this.#timeOfPreviousHeartbeat.get(i) ?? 0);\n if (delta && delta > 1500) {\n acc.set(i, WorkerStatus.Unresponsive);\n } else {\n acc.set(i, WorkerStatus.Available);\n }\n return acc;\n }, new Map());\n }\n}\n"],"names":[],"version":3,"file":"main.js.map"}