@velarscript/web 0.29.2 → 0.30.1

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 (72) hide show
  1. package/README.md +10 -2
  2. package/dist/analysis/look-values.d.ts +76 -1
  3. package/dist/analysis/look-values.d.ts.map +1 -1
  4. package/dist/analysis/look-values.js +193 -0
  5. package/dist/analysis/look-values.js.map +1 -1
  6. package/dist/analysis/reactive-names.d.ts +50 -0
  7. package/dist/analysis/reactive-names.d.ts.map +1 -0
  8. package/dist/analysis/reactive-names.js +199 -0
  9. package/dist/analysis/reactive-names.js.map +1 -0
  10. package/dist/analysis/watch-cycles.d.ts +28 -0
  11. package/dist/analysis/watch-cycles.d.ts.map +1 -1
  12. package/dist/analysis/watch-cycles.js +47 -0
  13. package/dist/analysis/watch-cycles.js.map +1 -1
  14. package/dist/analyzer.d.ts +5 -1
  15. package/dist/analyzer.d.ts.map +1 -1
  16. package/dist/analyzer.js +50 -60
  17. package/dist/analyzer.js.map +1 -1
  18. package/dist/compiler.d.ts +1 -1
  19. package/dist/compiler.js +2 -2
  20. package/dist/compiler.js.map +1 -1
  21. package/dist/css-string.d.ts +4 -10
  22. package/dist/css-string.d.ts.map +1 -1
  23. package/dist/css-string.js +4 -27
  24. package/dist/css-string.js.map +1 -1
  25. package/dist/emitter.d.ts.map +1 -1
  26. package/dist/emitter.js +11 -2090
  27. package/dist/emitter.js.map +1 -1
  28. package/dist/lexer.js +63 -43
  29. package/dist/lexer.js.map +1 -1
  30. package/dist/look-static.d.ts +15 -1
  31. package/dist/look-static.d.ts.map +1 -1
  32. package/dist/look-static.js +30 -11
  33. package/dist/look-static.js.map +1 -1
  34. package/dist/look.d.ts +4 -4
  35. package/dist/look.d.ts.map +1 -1
  36. package/dist/look.js +4 -4
  37. package/dist/look.js.map +1 -1
  38. package/dist/parser.js +1 -2
  39. package/dist/parser.js.map +1 -1
  40. package/dist/runtime-sources.generated.d.ts +89 -0
  41. package/dist/runtime-sources.generated.d.ts.map +1 -0
  42. package/dist/runtime-sources.generated.js +96 -0
  43. package/dist/runtime-sources.generated.js.map +1 -0
  44. package/dist/runtime.d.ts +18 -0
  45. package/dist/runtime.d.ts.map +1 -1
  46. package/dist/runtime.js +31 -3742
  47. package/dist/runtime.js.map +1 -1
  48. package/package.json +3 -3
  49. package/dist/browser-host-runtime.d.ts +0 -23
  50. package/dist/browser-host-runtime.d.ts.map +0 -1
  51. package/dist/browser-host-runtime.js +0 -29
  52. package/dist/browser-host-runtime.js.map +0 -1
  53. package/dist/reactive-bridge-runtime.d.ts +0 -6
  54. package/dist/reactive-bridge-runtime.d.ts.map +0 -1
  55. package/dist/reactive-bridge-runtime.js +0 -114
  56. package/dist/reactive-bridge-runtime.js.map +0 -1
  57. package/dist/realtime-client-runtime.d.ts +0 -3
  58. package/dist/realtime-client-runtime.d.ts.map +0 -1
  59. package/dist/realtime-client-runtime.js +0 -382
  60. package/dist/realtime-client-runtime.js.map +0 -1
  61. package/dist/runtime-foundation.d.ts +0 -7
  62. package/dist/runtime-foundation.d.ts.map +0 -1
  63. package/dist/runtime-foundation.js +0 -1676
  64. package/dist/runtime-foundation.js.map +0 -1
  65. package/dist/websocket-runtime.d.ts +0 -2
  66. package/dist/websocket-runtime.d.ts.map +0 -1
  67. package/dist/websocket-runtime.js +0 -37
  68. package/dist/websocket-runtime.js.map +0 -1
  69. package/dist/worker-runtime.d.ts +0 -2
  70. package/dist/worker-runtime.d.ts.map +0 -1
  71. package/dist/worker-runtime.js +0 -83
  72. package/dist/worker-runtime.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"runtime-foundation.js","sourceRoot":"","sources":["../src/runtime-foundation.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export declare const VELAR_WEB_WEBSOCKET_RUNTIME: string;
2
- //# sourceMappingURL=websocket-runtime.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"websocket-runtime.d.ts","sourceRoot":"","sources":["../src/websocket-runtime.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,2BAA2B,QAmC3B,CAAC"}
@@ -1,37 +0,0 @@
1
- export const VELAR_WEB_WEBSOCKET_RUNTIME = String.raw `
2
- const __velarNativeWebSocket = globalThis.WebSocket;
3
- const __velarWebSocketConnections = new WeakMap();
4
- function __velarWsInteger(value, fallback, minimum, maximum, name) { if (value === undefined || value === null) return fallback; if (!Number.isSafeInteger(value) || value < minimum || value > maximum) throw new RangeError(name + " must be an integer from " + minimum + " through " + maximum); return value; }
5
- function __velarWsDuration(value, fallback) { if (value === undefined || value === null) return fallback; if (typeof value !== "string") throw new TypeError("WebSocket timeout must be Duration"); const match = /^([+-]?(?:\d+(?:\.\d+)?|\.\d+))(ms|s)$/.exec(value); if (!match) throw new TypeError("WebSocket timeout must be Duration such as 5s"); const result = Number(match[1]) * (match[2] === "s" ? 1000 : 1); if (!Number.isFinite(result) || result < 0 || result > 2147483647) throw new RangeError("WebSocket timeout is outside the supported range"); return result; }
6
- function __velarWsOptions(options = {}) { if (options === null || typeof options !== "object" || Array.isArray(options)) throw new TypeError("WebSocket options must be a record"); return { maxMessageBytes: __velarWsInteger(options.maxMessageBytes, 16 * 1024 * 1024, 1, 64 * 1024 * 1024, "maxMessageBytes"), maxQueuedMessages: __velarWsInteger(options.maxQueuedMessages, 256, 1, 10000, "maxQueuedMessages"), maxQueuedBytes: __velarWsInteger(options.maxQueuedBytes, 16 * 1024 * 1024, 1, 64 * 1024 * 1024, "maxQueuedBytes"), maxPendingSendBytes: __velarWsInteger(options.maxPendingSendBytes, 16 * 1024 * 1024, 1, 64 * 1024 * 1024, "maxPendingSendBytes") }; }
7
- function __velarWsUtf8(value) { return new TextEncoder().encode(value).byteLength; }
8
- function __velarWsBytes(value) { if (!(value instanceof Uint8Array)) return null; const output = new Uint8Array(value.byteLength); output.set(value); return output; }
9
- export class WebSocketBackpressureError extends Error { constructor(message = "WebSocket backpressure limit exceeded") { super(message); this.name = "WebSocketBackpressureError"; } }
10
- export class WebSocketClosedError extends Error { constructor(message = "WebSocket is closed") { super(message); this.name = "WebSocketClosedError"; } }
11
- export class WebSocketProtocolError extends Error { constructor(message = "WebSocket protocol error") { super(message); this.name = "WebSocketProtocolError"; } }
12
- export class WebSocketTimeoutError extends Error { constructor(message = "WebSocket timed out") { super(message); this.name = "WebSocketTimeoutError"; } }
13
- // Bytes that already left the socket stay sent, so a waiter past the flush watermark resolves even when the connection finishes in the same turn; only what is still buffered fails.
14
- function __velarWsFailSends(state) { if (state.drainTimer !== null) { clearTimeout(state.drainTimer); state.drainTimer = null; } const flushed = state.sentBytes - state.socket.bufferedAmount; for (const waiter of state.sendWaiters) { if (flushed >= waiter.target) waiter.resolve(null); else waiter.reject(new WebSocketClosedError()); } state.sendWaiters.clear(); }
15
- function __velarWsWatchDrain(state) { if (state.drainTimer !== null || state.sendWaiters.size === 0) return; state.drainTimer = setTimeout(() => __velarWsDrain(state), state.drainDelay); }
16
- function __velarWsDrain(state) { state.drainTimer = null; if (state.finished) { __velarWsFailSends(state); return; } const flushed = state.sentBytes - state.socket.bufferedAmount; let settled = false; for (const waiter of state.sendWaiters) if (flushed >= waiter.target) { state.sendWaiters.delete(waiter); waiter.resolve(null); settled = true; } state.drainDelay = settled ? 1 : Math.min(state.drainDelay * 2, 32); __velarWsWatchDrain(state); }
17
- function __velarWsResolveClose(state, code = 1006, reason = "") { if (state.closeInfo !== null) return; state.closeInfo = Object.freeze({code, reason}); state.resolveCloseInfo(state.closeInfo); }
18
- function __velarWsFinish(state, code = 1000, reason = "") { __velarWsResolveClose(state, code, reason); if (state.finished) return; state.finished = true; if (state.waiter) { state.waiter.resolve(null); state.waiter = null; } __velarWsFailSends(state); }
19
- function __velarWsAbort(state, code = 1006, reason = "") { __velarWsResolveClose(state, code, reason); state.finished = true; state.queue.length = 0; state.queuedBytes = 0; if (state.waiter) { state.waiter.resolve(null); state.waiter = null; } __velarWsFailSends(state); }
20
- function __velarWsRejectReceive(state, socket, code, reason) { __velarWsAbort(state, code, reason); socket.close(code, reason); }
21
- function __velarWsWrap(socket, options) { let resolveCloseInfo; const closeInfoPromise = new Promise(resolve => { resolveCloseInfo = resolve; }); const value = Object.create(__velarWsConnectionPrototype); value.origin = null; const state = { socket, options, queue: [], queuedBytes: 0, waiter: null, finished: false, closePromise: null, closeInfo: null, closeInfoPromise, resolveCloseInfo, sendWaiters: new Set(), sentBytes: 0, drainTimer: null, drainDelay: 1 }; __velarWebSocketConnections.set(value, state); socket.binaryType = "arraybuffer";
22
- socket.addEventListener("message", event => { if (state.finished) return; let message; let size; if (typeof event.data === "string") { size = __velarWsUtf8(event.data); if (size > options.maxMessageBytes) { __velarWsRejectReceive(state, socket, 4009, "Message too large"); return; } message = event.data; } else if (event.data instanceof ArrayBuffer) { size = event.data.byteLength; if (size > options.maxMessageBytes) { __velarWsRejectReceive(state, socket, 4009, "Message too large"); return; } message = new Uint8Array(event.data); } else { __velarWsRejectReceive(state, socket, 4003, "Unsupported message type"); return; } if (state.waiter) { const waiter = state.waiter; state.waiter = null; waiter.resolve(message); } else if (state.queue.length >= options.maxQueuedMessages || state.queuedBytes + size > options.maxQueuedBytes) __velarWsRejectReceive(state, socket, 4009, "Unread message queue full"); else { state.queue.push(message); state.queuedBytes += size; } });
23
- socket.addEventListener("close", event => __velarWsFinish(state, event.code, event.reason)); socket.addEventListener("error", () => { if (state.waiter) { state.waiter.reject(new WebSocketProtocolError()); state.waiter = null; } __velarWsAbort(state); }); return Object.freeze(value); }
24
- const __velarWsConnectionPrototype = Object.freeze({
25
- state() { const state = __velarWebSocketConnections.get(this); if (!state) throw new TypeError("WebSocket state requires a connection"); return state.socket.readyState === __velarNativeWebSocket.CONNECTING ? "connecting" : state.socket.readyState === __velarNativeWebSocket.OPEN ? "open" : state.socket.readyState === __velarNativeWebSocket.CLOSING ? "closing" : "closed"; },
26
- send(message) { const state = __velarWebSocketConnections.get(this); if (!state) throw new TypeError("WebSocket.send requires a connection"); if (state.socket.readyState !== __velarNativeWebSocket.OPEN) return Promise.reject(new WebSocketClosedError()); const bytes = typeof message === "string" ? null : __velarWsBytes(message); if (bytes === null && typeof message !== "string") return Promise.reject(new TypeError("WebSocket.send requires text or Bytes")); const size = bytes?.byteLength ?? __velarWsUtf8(message); if (size > state.options.maxMessageBytes) return Promise.reject(new RangeError("WebSocket message exceeds maxMessageBytes")); if (state.socket.bufferedAmount + size > state.options.maxPendingSendBytes) return Promise.reject(new WebSocketBackpressureError()); state.socket.send(bytes ?? message); state.sentBytes += size; const target = state.sentBytes; return new Promise((resolve, reject) => { if (state.finished) { reject(new WebSocketClosedError()); return; } if (state.sentBytes - state.socket.bufferedAmount >= target) { resolve(null); return; } state.sendWaiters.add({ resolve, reject, target }); state.drainDelay = 1; __velarWsWatchDrain(state); }); },
27
- next() { const state = __velarWebSocketConnections.get(this); if (!state) throw new TypeError("WebSocket.next requires a connection"); if (state.queue.length) { const message = state.queue.shift(); state.queuedBytes -= typeof message === "string" ? __velarWsUtf8(message) : message.byteLength; return Promise.resolve(message); } if (state.finished) return Promise.resolve(null); if (state.waiter) return Promise.reject(new WebSocketBackpressureError("Only one WebSocket.next call may wait at a time")); return new Promise((resolve, reject) => { state.waiter = { resolve, reject }; }); },
28
- closeInfo() { const state = __velarWebSocketConnections.get(this); if (!state) throw new TypeError("WebSocket.closeInfo requires a connection"); return state.closeInfoPromise; },
29
- close(code = 1000, reason = "") { const state = __velarWebSocketConnections.get(this); if (!state) throw new TypeError("WebSocket.close requires a connection"); if (!Number.isSafeInteger(code) || code < 1000 || code > 4999) return Promise.reject(new RangeError("WebSocket close code must be from 1000 through 4999")); if (typeof reason !== "string" || __velarWsUtf8(reason) > 123) return Promise.reject(new RangeError("WebSocket close reason cannot exceed 123 UTF-8 bytes")); if (state.finished) return Promise.resolve(null); if (!state.closePromise) { state.closePromise = new Promise(resolve => state.socket.addEventListener("close", () => resolve(null), { once: true })); state.socket.close(code, reason); } return state.closePromise; },
30
- });
31
- const __velarWsCloseType = Object.freeze({ is(value) { return value !== null && typeof value === "object" && Number.isSafeInteger(value.code) && typeof value.reason === "string"; }, parse(value) { if (!this.is(value)) throw new TypeError("Value does not match WebSocketClose"); return value; } });
32
- const __velarWsConnectionType = Object.freeze({ is(value) { return __velarWebSocketConnections.has(value); }, parse(value) { if (!this.is(value)) throw new TypeError("Value does not match WebSocketConnection"); return value; } });
33
- export const WebSocketConnection = __velarWsConnectionType;
34
- export const WebSocketClose = __velarWsCloseType;
35
- export function connect(url, options = {}) { if (typeof __velarNativeWebSocket !== "function") return Promise.reject(new Error("The browser WebSocket API is unavailable")); if (typeof url !== "string" || !/^wss?:\/\//u.test(url)) return Promise.reject(new TypeError("WebSocket URL must start with ws:// or wss://")); const limits = __velarWsOptions(options); const timeout = __velarWsDuration(options.timeout, 10000); return new Promise((resolve, reject) => { const socket = new __velarNativeWebSocket(url); const timer = setTimeout(() => { socket.close(); reject(new WebSocketTimeoutError("WebSocket connection timed out")); }, timeout); socket.addEventListener("open", () => { clearTimeout(timer); resolve(__velarWsWrap(socket, limits)); }, { once: true }); socket.addEventListener("error", () => { clearTimeout(timer); reject(new WebSocketProtocolError("WebSocket connection failed")); }, { once: true }); }); }
36
- `.trimStart();
37
- //# sourceMappingURL=websocket-runtime.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"websocket-runtime.js","sourceRoot":"","sources":["../src/websocket-runtime.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,2BAA2B,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCpD,CAAC,SAAS,EAAE,CAAC"}
@@ -1,2 +0,0 @@
1
- export declare const VELAR_WEB_WORKER_RUNTIME: string;
2
- //# sourceMappingURL=worker-runtime.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"worker-runtime.d.ts","sourceRoot":"","sources":["../src/worker-runtime.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,wBAAwB,QAiFxB,CAAC"}
@@ -1,83 +0,0 @@
1
- export const VELAR_WEB_WORKER_RUNTIME = String.raw `
2
- import { workerEntries as __velarWorkerEntries } from "velar/worker-manifest";
3
- import { Cancellation, CancellationError, TaskTimeoutError } from "velar/task";
4
- import { Bytes as __velarWorkerBinaryRuntime } from "velar/binary";
5
-
6
- const __velarNativeWorker = globalThis.Worker;
7
- const __velarWorkerStates = new WeakMap();
8
- const __velarWorkerPoolStates = new WeakMap();
9
- let __velarWorkerServerInstalled = false;
10
- const __velarWorkerStructuredClone = globalThis.structuredClone;
11
- const __velarWorkerCancelGrace = 1000;
12
- function __velarWorkerInteger(value, minimum, maximum, name) { if (!Number.isSafeInteger(value) || value < minimum || value > maximum) throw new RangeError(name + " must be an integer from " + minimum + " through " + maximum); return value; }
13
- function __velarWorkerRuntimeType(value, name) { if ((typeof value !== "object" && typeof value !== "function") || value === null || typeof value.parse !== "function" || typeof value.is !== "function") throw new TypeError(name + " must be a runtime Type"); return value; }
14
- function __velarWorkerDuration(value) { if (value === null) return 0; if (typeof value !== "string") throw new TypeError("Worker timeout must be Duration or null"); const match = /^([+-]?(?:\d+(?:\.\d+)?|\.\d+))(ms|s)$/.exec(value); if (!match) throw new TypeError("Worker timeout must be Duration such as 200ms or 2s"); const milliseconds = Number(match[1]) * (match[2] === "s" ? 1000 : 1); if (!Number.isFinite(milliseconds) || milliseconds < 0 || milliseconds > 2147483647) throw new RangeError("Worker timeout is outside the supported range"); return milliseconds; }
15
- function __velarWorkerTransfer(value, adopt = false) {
16
- const transfers = []; const buffers = new Set(); const objects = new Set(); const pending = [{ value, depth: 0 }]; let visited = 0; let transferBytes = 0;
17
- while (pending.length > 0 && visited < 10000 && transfers.length < 1024) {
18
- const current = pending.pop(); const item = current.value; visited += 1;
19
- if (item === null || (typeof item !== "object" && typeof item !== "function") || objects.has(item)) continue; objects.add(item);
20
- if (ArrayBuffer.isView(item)) { const supported = item instanceof Uint8Array || item instanceof Uint16Array || item instanceof Uint32Array || item instanceof Float32Array; const buffer = item.buffer; if (supported && buffer instanceof ArrayBuffer && item.byteOffset === 0 && item.byteLength === buffer.byteLength && transferBytes + buffer.byteLength <= 64 * 1024 * 1024) { if (adopt) __velarWorkerBinaryRuntime.__velarAdoptTransferredBuffer(item); if (buffer.byteLength > 0 && !buffers.has(buffer)) { buffers.add(buffer); transfers.push(buffer); transferBytes += buffer.byteLength; } } continue; }
21
- if (current.depth >= 32) continue; const depth = current.depth + 1;
22
- if (item instanceof Map) { for (const [key, nested] of item) pending.push({ value: key, depth }, { value: nested, depth }); continue; }
23
- if (item instanceof Set) { for (const nested of item) pending.push({ value: nested, depth }); continue; }
24
- for (const key of Object.keys(item)) pending.push({ value: item[key], depth });
25
- }
26
- return transfers;
27
- }
28
- function __velarWorkerOutbound(value, source) {
29
- const transfers = __velarWorkerTransfer(value);
30
- if (transfers.length === 0) return { value, transfers };
31
- const sourceTransfers = new Set(__velarWorkerTransfer(source));
32
- if (!transfers.some(buffer => sourceTransfers.has(buffer))) return { value, transfers };
33
- if (typeof __velarWorkerStructuredClone !== "function") throw new Error("The structured clone API is unavailable");
34
- const snapshot = __velarWorkerStructuredClone(value);
35
- return { value: snapshot, transfers: __velarWorkerTransfer(snapshot) };
36
- }
37
- function __velarWorkerInbound(Type, value) {
38
- if (!Type.is(value)) return Type.parse(value);
39
- __velarWorkerTransfer(value, true);
40
- return value;
41
- }
42
- function __velarWorkerFailure(error) { return { name: typeof error?.name === "string" ? error.name : "Error", message: typeof error?.message === "string" ? error.message : String(error), stack: typeof error?.stack === "string" ? error.stack : "" }; }
43
- export class WorkerBackpressureError extends Error { constructor(message = "Worker queue is full") { super(message); this.name = "WorkerBackpressureError"; } }
44
- export class WorkerCallError extends Error { constructor(message = "Worker call failed") { super(message); this.name = "WorkerCallError"; } }
45
- export class WorkerCrashedError extends Error { constructor(message = "Worker crashed") { super(message); this.name = "WorkerCrashedError"; } }
46
- export class WorkerClosedError extends Error { constructor(message = "Worker is closed") { super(message); this.name = "WorkerClosedError"; } }
47
- function __velarWorkerRejectAll(state, failure) { if (state.closed) return; state.closed = true; for (const pending of state.pending.values()) { if (pending.timer) clearTimeout(pending.timer); pending.unsubscribe(); pending.reject(failure); } state.pending.clear(); for (const timer of state.abandoned.values()) clearTimeout(timer); state.abandoned.clear(); }
48
- function __velarWorkerCrash(state, failure) { __velarWorkerRejectAll(state, failure); state.instance.terminate(); }
49
- const __velarWorkerPrototype = Object.freeze({
50
- call(request, cancellation = null, timeout = null) {
51
- const state = __velarWorkerStates.get(this); if (!state) throw new TypeError("Worker.call requires a Worker receiver"); if (state.closed) return Promise.reject(new WorkerClosedError());
52
- if (state.pending.size >= state.capacity) return Promise.reject(new WorkerBackpressureError("Worker queue capacity " + state.capacity + " is full"));
53
- if (cancellation !== null && !Cancellation.is(cancellation)) return Promise.reject(new TypeError("Worker cancellation must be Cancellation or null"));
54
- let validated; try { validated = state.RequestType.parse(request); } catch (error) { return Promise.reject(error); }
55
- let outbound; try { outbound = __velarWorkerOutbound(validated, request); } catch (error) { return Promise.reject(error); }
56
- const milliseconds = __velarWorkerDuration(timeout); const id = state.nextId++;
57
- return new Promise((resolve, reject) => { const pending = { resolve, reject, cancel: null, reason: "Worker call cancelled", timeout, timer: null, unsubscribe: () => null }; state.pending.set(id, pending); state.instance.postMessage({ kind: "call", id, value: outbound.value }, outbound.transfers); if (cancellation !== null) pending.unsubscribe = Cancellation.__velarOn(cancellation, reason => { if (!state.pending.has(id) || pending.cancel) return; pending.cancel = "cancel"; pending.reason = reason ?? pending.reason; state.instance.postMessage({ kind: "cancel", id, reason: pending.reason }); }); if (milliseconds > 0) pending.timer = setTimeout(() => { if (!state.pending.has(id) || pending.cancel) return; state.pending.delete(id); pending.unsubscribe(); state.instance.postMessage({ kind: "cancel", id, reason: "Worker call timed out" }); state.abandoned.set(id, setTimeout(() => __velarWorkerCrash(state, new WorkerCrashedError("Worker did not acknowledge a cancelled call within " + __velarWorkerCancelGrace + "ms")), __velarWorkerCancelGrace)); reject(new TaskTimeoutError("Worker call timed out after " + timeout)); }, milliseconds); });
58
- },
59
- async close() { const state = __velarWorkerStates.get(this); if (!state) throw new TypeError("Worker.close requires a Worker receiver"); if (state.closed) return null; __velarWorkerRejectAll(state, new WorkerClosedError()); state.instance.terminate(); return null; },
60
- });
61
- function __velarWorkerClient(name, RequestType, ResponseType, capacity) {
62
- if (typeof __velarNativeWorker !== "function") throw new Error("The browser Worker API is unavailable"); if (typeof name !== "string" || !Object.hasOwn(__velarWorkerEntries, name)) throw new RangeError("Unknown worker entry '" + String(name) + "'"); RequestType = __velarWorkerRuntimeType(RequestType, "Worker request Type"); ResponseType = __velarWorkerRuntimeType(ResponseType, "Worker response Type"); capacity = __velarWorkerInteger(capacity, 1, 10000, "Worker capacity");
63
- const instance = new __velarNativeWorker(new URL("../" + __velarWorkerEntries[name], import.meta.url), { type: "module", name: "velar:" + name }); const value = Object.create(__velarWorkerPrototype); const state = { instance, RequestType, ResponseType, capacity, nextId: 1, pending: new Map(), abandoned: new Map(), closed: false }; __velarWorkerStates.set(value, state);
64
- instance.addEventListener("message", event => { const message = event.data; if (!message || !Number.isSafeInteger(message.id)) { __velarWorkerCrash(state, new WorkerCrashedError("Worker returned an invalid message")); return; } const grace = state.abandoned.get(message.id); if (grace !== undefined) { clearTimeout(grace); state.abandoned.delete(message.id); } if (message.kind === "cancel-ack") return; const pending = state.pending.get(message.id); if (!pending) return; state.pending.delete(message.id); if (pending.timer) clearTimeout(pending.timer); pending.unsubscribe(); if (pending.cancel === "cancel") { pending.reject(new CancellationError(pending.reason)); return; } if (!message.ok) { const remote = message.error ?? {}; const failure = new WorkerCallError((remote.name ? remote.name + ": " : "") + (remote.message ?? "Worker call failed")); if (typeof remote.stack === "string" && remote.stack) failure.stack += "\nRemote worker:\n" + remote.stack; pending.reject(failure); return; } try { pending.resolve(__velarWorkerInbound(state.ResponseType, message.value)); } catch (error) { pending.reject(error); } });
65
- instance.addEventListener("error", event => __velarWorkerCrash(state, new WorkerCrashedError(event.message || "Worker crashed"))); instance.addEventListener("messageerror", () => __velarWorkerCrash(state, new WorkerCrashedError("Worker returned an unreadable message"))); return Object.freeze(value);
66
- }
67
- const __velarWorkerPoolPrototype = Object.freeze({
68
- call(request, cancellation = null, timeout = null) { const state = __velarWorkerPoolStates.get(this); if (!state) throw new TypeError("WorkerPool.call requires a WorkerPool receiver"); if (state.closed) return Promise.reject(new WorkerClosedError("Worker pool is closed")); let total = 0; let selected = null; let load = 0; for (const item of state.workers) { const member = __velarWorkerStates.get(item); if (member.closed) continue; total += member.pending.size; if (selected === null || member.pending.size < load) { selected = item; load = member.pending.size; } } if (selected === null) return Promise.reject(new WorkerCrashedError("Worker pool has no live workers")); if (total >= state.capacity) return Promise.reject(new WorkerBackpressureError("Worker pool queue capacity " + state.capacity + " is full")); return selected.call(request, cancellation, timeout); },
69
- broadcast(request, cancellation = null, timeout = null) { const state = __velarWorkerPoolStates.get(this); if (!state) throw new TypeError("WorkerPool.broadcast requires a WorkerPool receiver"); if (state.closed) return Promise.reject(new WorkerClosedError("Worker pool is closed")); const live = []; let total = 0; for (const item of state.workers) { const member = __velarWorkerStates.get(item); if (member.closed) continue; live.push(item); total += member.pending.size; if (member.pending.size >= member.capacity) return Promise.reject(new WorkerBackpressureError("Worker pool member queue capacity " + member.capacity + " is full")); } if (live.length === 0) return Promise.reject(new WorkerCrashedError("Worker pool has no live workers")); if (total + live.length > state.capacity) return Promise.reject(new WorkerBackpressureError("Worker pool queue capacity " + state.capacity + " cannot accept a broadcast to " + live.length + " workers")); return Promise.all(live.map(item => item.call(request, cancellation, timeout))); },
70
- async close() { const state = __velarWorkerPoolStates.get(this); if (!state) throw new TypeError("WorkerPool.close requires a WorkerPool receiver"); if (state.closed) return null; state.closed = true; await Promise.all(state.workers.map(item => item.close())); return null; },
71
- });
72
- const __velarWorkerType = Object.freeze({ is(value) { return __velarWorkerStates.has(value); }, parse(value) { if (!this.is(value)) throw new TypeError("Value does not match Worker"); return value; } });
73
- const __velarWorkerPoolType = Object.freeze({ is(value) { return __velarWorkerPoolStates.has(value); }, parse(value) { if (!this.is(value)) throw new TypeError("Value does not match WorkerPool"); return value; } });
74
- export const Worker = Object.freeze({ ...__velarWorkerType, of() { return __velarWorkerType; } }); export const WorkerPool = Object.freeze({ ...__velarWorkerPoolType, of() { return __velarWorkerPoolType; } });
75
- export function worker(name, RequestType, ResponseType, capacity = 64) { return __velarWorkerClient(name, RequestType, ResponseType, capacity); }
76
- export function workerPool(name, RequestType, ResponseType, size, capacity = 256) { size = __velarWorkerInteger(size, 1, 32, "Worker pool size"); capacity = __velarWorkerInteger(capacity, size, 10000, "Worker pool capacity"); const workers = Array.from({ length: size }, () => __velarWorkerClient(name, RequestType, ResponseType, Math.ceil(capacity / size))); const value = Object.create(__velarWorkerPoolPrototype); __velarWorkerPoolStates.set(value, { workers, capacity, closed: false }); return Object.freeze(value); }
77
- export function serveWorker(RequestType, ResponseType, handler, capacity = 64) {
78
- if (__velarWorkerServerInstalled) throw new Error("A worker entry may call serveWorker() only once"); RequestType = __velarWorkerRuntimeType(RequestType, "Worker request Type"); ResponseType = __velarWorkerRuntimeType(ResponseType, "Worker response Type"); if (typeof handler !== "function") throw new TypeError("serveWorker handler must be an async function"); capacity = __velarWorkerInteger(capacity, 1, 10000, "Worker capacity"); __velarWorkerServerInstalled = true;
79
- const queue = []; const active = new Map(); let running = false; const drain = async () => { if (running) return; running = true; while (queue.length) { const message = queue.shift(); const cancellation = Cancellation.__velarCreate(); active.set(message.id, cancellation); try { const request = __velarWorkerInbound(RequestType, message.value); const handled = await handler(request, cancellation); const result = ResponseType.parse(handled); const outbound = __velarWorkerOutbound(result, handled); globalThis.postMessage({ id: message.id, ok: true, value: outbound.value }, { transfer: outbound.transfers }); } catch (error) { globalThis.postMessage({ id: message.id, ok: false, error: __velarWorkerFailure(error) }); } finally { active.delete(message.id); } } running = false; };
80
- globalThis.addEventListener("message", event => { const message = event.data; if (!message || !Number.isSafeInteger(message.id)) return; if (message.kind === "cancel") { globalThis.postMessage({ id: message.id, kind: "cancel-ack" }); const cancellation = active.get(message.id); if (cancellation) Cancellation.__velarCancel(cancellation, typeof message.reason === "string" ? message.reason : "Worker call cancelled"); else { const index = queue.findIndex(item => item.id === message.id); if (index >= 0) { queue.splice(index, 1); globalThis.postMessage({ id: message.id, ok: false, error: __velarWorkerFailure(new CancellationError(typeof message.reason === "string" ? message.reason : "Worker call cancelled")) }); } } return; } if (message.kind !== "call") return; if (queue.length + active.size >= capacity) { globalThis.postMessage({ id: message.id, ok: false, error: __velarWorkerFailure(new WorkerBackpressureError()) }); return; } queue.push(message); drain(); }); return null;
81
- }
82
- `.trimStart();
83
- //# sourceMappingURL=worker-runtime.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"worker-runtime.js","sourceRoot":"","sources":["../src/worker-runtime.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiFjD,CAAC,SAAS,EAAE,CAAC"}