@ccheever/exact-ibex-runtime 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +63 -0
- package/src/abort/AbortController.ts +23 -0
- package/src/abort/AbortSignal.ts +152 -0
- package/src/abort/index.ts +2 -0
- package/src/accessibility.ts +12 -0
- package/src/arraybuffer-detach.ts +109 -0
- package/src/base64/base64.ts +168 -0
- package/src/base64/index.ts +1 -0
- package/src/blob/Blob.ts +259 -0
- package/src/blob/File.ts +59 -0
- package/src/blob/FormData.ts +323 -0
- package/src/blob/index.ts +3 -0
- package/src/bootstrap.ts +1946 -0
- package/src/broadcast/BroadcastChannel.ts +280 -0
- package/src/broadcast/index.ts +5 -0
- package/src/cache/Cache.ts +349 -0
- package/src/cache/CacheStorage.ts +89 -0
- package/src/cache/index.ts +27 -0
- package/src/camera/index.ts +6202 -0
- package/src/camera/processor.worker.ts +194 -0
- package/src/camera/scene.ts +195 -0
- package/src/clipboard/Clipboard.ts +129 -0
- package/src/clipboard/ClipboardItem.ts +97 -0
- package/src/clipboard/index.ts +6 -0
- package/src/clone/index.ts +1 -0
- package/src/clone/structuredClone.ts +389 -0
- package/src/clone/transferableSymbols.ts +2 -0
- package/src/compression/CompressionStream.ts +146 -0
- package/src/compression/DecompressionStream.ts +342 -0
- package/src/compression/index.ts +4 -0
- package/src/console/Console.ts +341 -0
- package/src/console/index.ts +2 -0
- package/src/core/accessibility-state.ts +263 -0
- package/src/core/accessibility.ts +184 -0
- package/src/core/agent-state.ts +37 -0
- package/src/core/diagnostics-logs.ts +144 -0
- package/src/core/host-call-bridge.ts +16 -0
- package/src/core/i18n-helpers.ts +189 -0
- package/src/core/locale-state.ts +253 -0
- package/src/core/locale.ts +95 -0
- package/src/crypto/Crypto.ts +2743 -0
- package/src/crypto/index.ts +1 -0
- package/src/diagnostics/logs.ts +7 -0
- package/src/encoding/TextDecoder.ts +1181 -0
- package/src/encoding/TextDecoderStream.ts +58 -0
- package/src/encoding/TextEncoder.ts +180 -0
- package/src/encoding/TextEncoderStream.ts +39 -0
- package/src/encoding/index.ts +8 -0
- package/src/events/CloseEvent.ts +91 -0
- package/src/events/DOMException.ts +409 -0
- package/src/events/ErrorEvent.ts +39 -0
- package/src/events/Event.ts +151 -0
- package/src/events/EventTarget.ts +280 -0
- package/src/events/FocusEvent.ts +27 -0
- package/src/events/KeyboardEvent.ts +46 -0
- package/src/events/MessageEvent.ts +61 -0
- package/src/events/ProgressEvent.ts +33 -0
- package/src/events/PromiseRejectionEvent.ts +31 -0
- package/src/events/index.ts +52 -0
- package/src/eventsource/EventSource.ts +371 -0
- package/src/eventsource/index.ts +2 -0
- package/src/fetch/Headers.ts +642 -0
- package/src/fetch/Request.ts +760 -0
- package/src/fetch/Response.ts +543 -0
- package/src/fetch/body.ts +1256 -0
- package/src/fetch/cookie-jar.ts +566 -0
- package/src/fetch/demo.ts +207 -0
- package/src/fetch/errors.ts +101 -0
- package/src/fetch/fetch.ts +2610 -0
- package/src/fetch/index.ts +101 -0
- package/src/fetch/native-bridge.ts +65 -0
- package/src/fetch/types.ts +258 -0
- package/src/filereader/FileReader.ts +236 -0
- package/src/filereader/index.ts +1 -0
- package/src/fs/Dirent.ts +39 -0
- package/src/fs/ExactFile.ts +450 -0
- package/src/fs/Stats.ts +80 -0
- package/src/fs/index.ts +944 -0
- package/src/fs/promises.ts +386 -0
- package/src/fs/shared.ts +328 -0
- package/src/http-server/index.js +697 -0
- package/src/http-server/index.ts +27 -0
- package/src/identity.generated.ts +14 -0
- package/src/index.ts +283 -0
- package/src/indexeddb/IDBCursor.ts +188 -0
- package/src/indexeddb/IDBDatabase.ts +343 -0
- package/src/indexeddb/IDBFactory.ts +269 -0
- package/src/indexeddb/IDBIndex.ts +194 -0
- package/src/indexeddb/IDBKeyRange.ts +109 -0
- package/src/indexeddb/IDBObjectStore.ts +468 -0
- package/src/indexeddb/IDBRequest.ts +163 -0
- package/src/indexeddb/IDBTransaction.ts +207 -0
- package/src/indexeddb/index.ts +34 -0
- package/src/indexeddb/utils.ts +52 -0
- package/src/inspect/index.ts +1 -0
- package/src/inspect/inspect.ts +465 -0
- package/src/internal/detect.ts +104 -0
- package/src/locale.ts +10 -0
- package/src/location/index.ts +1059 -0
- package/src/locks/LockManager.ts +460 -0
- package/src/locks/index.ts +12 -0
- package/src/media/VideoFrame.ts +58 -0
- package/src/messaging/MessageChannel.ts +31 -0
- package/src/messaging/MessagePort.ts +180 -0
- package/src/messaging/index.ts +2 -0
- package/src/messaging.ts +247 -0
- package/src/native/NativeModules.ts +354 -0
- package/src/native/index.ts +1 -0
- package/src/navigator/Navigator.ts +351 -0
- package/src/navigator/index.ts +1 -0
- package/src/node/Buffer.ts +1786 -0
- package/src/node/index.ts +4 -0
- package/src/node/path.ts +495 -0
- package/src/node/process.ts +2528 -0
- package/src/performance/Performance.ts +532 -0
- package/src/performance/index.ts +21 -0
- package/src/polyfills/array.ts +236 -0
- package/src/polyfills/arraybuffer.ts +172 -0
- package/src/polyfills/groupby.ts +85 -0
- package/src/polyfills/index.ts +85 -0
- package/src/polyfills/intl.ts +1956 -0
- package/src/polyfills/iterator.ts +479 -0
- package/src/polyfills/promise.ts +37 -0
- package/src/polyfills/set.ts +245 -0
- package/src/polyfills/string.ts +85 -0
- package/src/polyfills/typedarray.ts +110 -0
- package/src/promise-rejection-tracking.ts +464 -0
- package/src/react-native/index.ts +388 -0
- package/src/runtime-entry.ts +55 -0
- package/src/scheduling/AnimationFrame.ts +105 -0
- package/src/scheduling/IdleCallback.ts +167 -0
- package/src/scheduling/index.ts +13 -0
- package/src/security/Capabilities.ts +1146 -0
- package/src/security/Permissions.ts +392 -0
- package/src/security/capability-bits.generated.ts +63 -0
- package/src/security/index.ts +16 -0
- package/src/sqlite/Database.ts +456 -0
- package/src/sqlite/Statement.ts +206 -0
- package/src/sqlite/constants.ts +79 -0
- package/src/sqlite/errors.ts +25 -0
- package/src/sqlite/index.ts +34 -0
- package/src/sqlite/module.js +438 -0
- package/src/storage/Storage.ts +291 -0
- package/src/storage/StorageManager.ts +91 -0
- package/src/storage/index.ts +3 -0
- package/src/stream-compat.ts +47 -0
- package/src/streams/ReadableStream.ts +4131 -0
- package/src/streams/TransformStream.ts +375 -0
- package/src/streams/WritableStream.ts +866 -0
- package/src/streams/index.ts +41 -0
- package/src/timers/Timers.ts +296 -0
- package/src/timers/index.ts +11 -0
- package/src/url/URL.ts +656 -0
- package/src/url/URLPattern.ts +850 -0
- package/src/url/URLSearchParams.ts +244 -0
- package/src/url/index.ts +9 -0
- package/src/websocket/WebSocket.ts +770 -0
- package/src/websocket/WebSocketError.ts +52 -0
- package/src/websocket/WebSocketStream.ts +628 -0
- package/src/websocket/index.ts +7 -0
- package/src/window/index.ts +872 -0
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LockManager - Web Locks API Implementation (single-context, pure JS)
|
|
3
|
+
*
|
|
4
|
+
* Provides a mechanism for coordinating access to shared resources within
|
|
5
|
+
* a single JavaScript execution context. Supports exclusive and shared
|
|
6
|
+
* lock modes, queuing, steal, ifAvailable, and AbortSignal cancellation.
|
|
7
|
+
*
|
|
8
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Web_Locks_API
|
|
9
|
+
* @see https://w3c.github.io/web-locks/
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Represents a held or pending lock.
|
|
14
|
+
*/
|
|
15
|
+
export interface Lock {
|
|
16
|
+
readonly name: string;
|
|
17
|
+
readonly mode: LockMode;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type LockMode = "exclusive" | "shared";
|
|
21
|
+
|
|
22
|
+
export interface LockOptions {
|
|
23
|
+
/** Lock mode: 'exclusive' (default) or 'shared'. */
|
|
24
|
+
mode?: LockMode;
|
|
25
|
+
/** If true, the callback receives null instead of waiting when the lock is unavailable. */
|
|
26
|
+
ifAvailable?: boolean;
|
|
27
|
+
/** If true, preempts any existing locks on the same resource. */
|
|
28
|
+
steal?: boolean;
|
|
29
|
+
/** An AbortSignal to cancel a pending lock request. */
|
|
30
|
+
signal?: AbortSignal;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type LockGrantedCallback = (lock: Lock | null) => Promise<any> | any;
|
|
34
|
+
|
|
35
|
+
export interface LockManagerSnapshot {
|
|
36
|
+
held: Lock[];
|
|
37
|
+
pending: Lock[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Internal representation of a queued lock request.
|
|
42
|
+
*/
|
|
43
|
+
interface LockRequest {
|
|
44
|
+
name: string;
|
|
45
|
+
mode: LockMode;
|
|
46
|
+
callback: LockGrantedCallback;
|
|
47
|
+
resolve: (value: any) => void;
|
|
48
|
+
reject: (reason: any) => void;
|
|
49
|
+
signal?: AbortSignal;
|
|
50
|
+
abortHandler?: () => void;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Internal representation of a held lock with a release handle.
|
|
55
|
+
*/
|
|
56
|
+
interface HeldLockEntry {
|
|
57
|
+
name: string;
|
|
58
|
+
mode: LockMode;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* LockManager coordinates exclusive and shared access to named resources.
|
|
63
|
+
*
|
|
64
|
+
* Exclusive locks block all other lock requests for the same resource.
|
|
65
|
+
* Shared locks allow other shared locks but block exclusive requests.
|
|
66
|
+
* Pending requests are processed in FIFO order.
|
|
67
|
+
*/
|
|
68
|
+
export class LockManager {
|
|
69
|
+
/** Map from lock name to array of currently held lock entries. */
|
|
70
|
+
#held: Map<string, HeldLockEntry[]> = new Map();
|
|
71
|
+
|
|
72
|
+
/** Map from lock name to ordered queue of pending requests. */
|
|
73
|
+
#pending: Map<string, LockRequest[]> = new Map();
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Request a lock.
|
|
77
|
+
*
|
|
78
|
+
* @overload
|
|
79
|
+
* @param name - The resource name to lock.
|
|
80
|
+
* @param callback - Called with the Lock when granted.
|
|
81
|
+
*/
|
|
82
|
+
request(name: string, callback: LockGrantedCallback): Promise<any>;
|
|
83
|
+
/**
|
|
84
|
+
* Request a lock with options.
|
|
85
|
+
*
|
|
86
|
+
* @overload
|
|
87
|
+
* @param name - The resource name to lock.
|
|
88
|
+
* @param options - Lock request options.
|
|
89
|
+
* @param callback - Called with the Lock (or null if ifAvailable and unavailable).
|
|
90
|
+
*/
|
|
91
|
+
request(name: string, options: LockOptions, callback: LockGrantedCallback): Promise<any>;
|
|
92
|
+
request(
|
|
93
|
+
name: string,
|
|
94
|
+
optionsOrCallback: LockOptions | LockGrantedCallback,
|
|
95
|
+
maybeCallback?: LockGrantedCallback,
|
|
96
|
+
): Promise<any> {
|
|
97
|
+
let options: LockOptions;
|
|
98
|
+
let callback: LockGrantedCallback;
|
|
99
|
+
|
|
100
|
+
if (typeof optionsOrCallback === "function") {
|
|
101
|
+
options = {};
|
|
102
|
+
callback = optionsOrCallback;
|
|
103
|
+
} else {
|
|
104
|
+
options = optionsOrCallback;
|
|
105
|
+
callback = maybeCallback!;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (typeof callback !== "function") {
|
|
109
|
+
throw new TypeError("LockManager.request: callback must be a function");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (typeof name !== "string") {
|
|
113
|
+
throw new TypeError("LockManager.request: name must be a string");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Validate name: must not start with '-'
|
|
117
|
+
if (name.startsWith("-")) {
|
|
118
|
+
throw new DOMException(
|
|
119
|
+
`LockManager.request: names starting with '-' are reserved`,
|
|
120
|
+
"NotSupportedError",
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const mode: LockMode = options.mode ?? "exclusive";
|
|
125
|
+
if (mode !== "exclusive" && mode !== "shared") {
|
|
126
|
+
throw new TypeError(`LockManager.request: invalid mode '${mode}'`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (options.steal && options.ifAvailable) {
|
|
130
|
+
throw new DOMException(
|
|
131
|
+
"LockManager.request: 'steal' and 'ifAvailable' cannot be used together",
|
|
132
|
+
"NotSupportedError",
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (options.steal && mode !== "exclusive") {
|
|
137
|
+
throw new DOMException(
|
|
138
|
+
"LockManager.request: 'steal' is only supported for exclusive locks",
|
|
139
|
+
"NotSupportedError",
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (options.signal && options.steal) {
|
|
144
|
+
throw new DOMException(
|
|
145
|
+
"LockManager.request: 'signal' and 'steal' cannot be used together",
|
|
146
|
+
"NotSupportedError",
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Check if signal is already aborted
|
|
151
|
+
if (options.signal?.aborted) {
|
|
152
|
+
return Promise.reject(options.signal.reason);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Handle steal
|
|
156
|
+
if (options.steal) {
|
|
157
|
+
return this.#stealLock(name, callback);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Handle ifAvailable
|
|
161
|
+
if (options.ifAvailable) {
|
|
162
|
+
return this.#requestIfAvailable(name, mode, callback);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Normal lock acquisition: either grant immediately or queue
|
|
166
|
+
return this.#requestLock(name, mode, callback, options.signal);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Returns a snapshot of the currently held and pending locks.
|
|
171
|
+
*/
|
|
172
|
+
async query(): Promise<LockManagerSnapshot> {
|
|
173
|
+
const held: Lock[] = [];
|
|
174
|
+
const pending: Lock[] = [];
|
|
175
|
+
|
|
176
|
+
for (const [, locks] of this.#held) {
|
|
177
|
+
for (const entry of locks) {
|
|
178
|
+
held.push({ name: entry.name, mode: entry.mode });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
for (const [, requests] of this.#pending) {
|
|
183
|
+
for (const req of requests) {
|
|
184
|
+
pending.push({ name: req.name, mode: req.mode });
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return { held, pending };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Steal a lock: abort all existing holders and pending requests, then grant.
|
|
193
|
+
*/
|
|
194
|
+
#stealLock(name: string, callback: LockGrantedCallback): Promise<any> {
|
|
195
|
+
// Clear all held locks for this name
|
|
196
|
+
this.#held.delete(name);
|
|
197
|
+
|
|
198
|
+
// Reject all pending requests for this name
|
|
199
|
+
const existingPending = this.#pending.get(name);
|
|
200
|
+
if (existingPending) {
|
|
201
|
+
for (const req of existingPending) {
|
|
202
|
+
this.#cleanupAbortHandler(req);
|
|
203
|
+
req.reject(new DOMException("Lock broken by steal request", "AbortError"));
|
|
204
|
+
}
|
|
205
|
+
this.#pending.delete(name);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Grant the lock immediately
|
|
209
|
+
return this.#grantAndRun(name, "exclusive", callback);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Try to acquire a lock without waiting. Returns null to callback if unavailable.
|
|
214
|
+
*/
|
|
215
|
+
#requestIfAvailable(
|
|
216
|
+
name: string,
|
|
217
|
+
mode: LockMode,
|
|
218
|
+
callback: LockGrantedCallback,
|
|
219
|
+
): Promise<any> {
|
|
220
|
+
if (this.#canAcquire(name, mode)) {
|
|
221
|
+
return this.#grantAndRun(name, mode, callback);
|
|
222
|
+
}
|
|
223
|
+
// Not available - call callback with null (no lock held)
|
|
224
|
+
return this.#invokeCallback(callback, null);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Normal lock request: grant immediately if possible, otherwise queue.
|
|
229
|
+
*/
|
|
230
|
+
#requestLock(
|
|
231
|
+
name: string,
|
|
232
|
+
mode: LockMode,
|
|
233
|
+
callback: LockGrantedCallback,
|
|
234
|
+
signal?: AbortSignal,
|
|
235
|
+
): Promise<any> {
|
|
236
|
+
if (this.#canAcquire(name, mode)) {
|
|
237
|
+
return this.#grantAndRun(name, mode, callback);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Queue the request
|
|
241
|
+
return new Promise<any>((resolve, reject) => {
|
|
242
|
+
const request: LockRequest = {
|
|
243
|
+
name,
|
|
244
|
+
mode,
|
|
245
|
+
callback,
|
|
246
|
+
resolve,
|
|
247
|
+
reject,
|
|
248
|
+
signal,
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
// Set up abort handler
|
|
252
|
+
if (signal) {
|
|
253
|
+
const abortHandler = () => {
|
|
254
|
+
this.#removePendingRequest(name, request);
|
|
255
|
+
request.reject(signal.reason);
|
|
256
|
+
};
|
|
257
|
+
request.abortHandler = abortHandler;
|
|
258
|
+
signal.addEventListener("abort", abortHandler, { once: true });
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
let queue = this.#pending.get(name);
|
|
262
|
+
if (!queue) {
|
|
263
|
+
queue = [];
|
|
264
|
+
this.#pending.set(name, queue);
|
|
265
|
+
}
|
|
266
|
+
queue.push(request);
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Check if a lock can be granted immediately for the given name and mode.
|
|
272
|
+
* Considers the pending queue to prevent writer starvation.
|
|
273
|
+
*/
|
|
274
|
+
#canAcquire(name: string, mode: LockMode): boolean {
|
|
275
|
+
const held = this.#held.get(name);
|
|
276
|
+
if (!held || held.length === 0) {
|
|
277
|
+
// Also check: if there's a pending queue for this name, new requests
|
|
278
|
+
// should go behind them (FIFO fairness), unless the queue is empty.
|
|
279
|
+
const pendingQueue = this.#pending.get(name);
|
|
280
|
+
if (pendingQueue && pendingQueue.length > 0) {
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (mode === "shared") {
|
|
287
|
+
// All held must be shared
|
|
288
|
+
if (!held.every((h) => h.mode === "shared")) return false;
|
|
289
|
+
|
|
290
|
+
// And no pending exclusive requests (prevent writer starvation)
|
|
291
|
+
const pendingQueue = this.#pending.get(name);
|
|
292
|
+
if (pendingQueue && pendingQueue.some((p) => p.mode === "exclusive")) {
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return true;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Exclusive needs no held locks
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Check if a lock can be granted, used when draining the queue.
|
|
305
|
+
* Does not consider pending queue for starvation (we process FIFO).
|
|
306
|
+
*/
|
|
307
|
+
#canAcquireDirect(name: string, mode: LockMode): boolean {
|
|
308
|
+
const held = this.#held.get(name);
|
|
309
|
+
if (!held || held.length === 0) {
|
|
310
|
+
return true;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (mode === "shared") {
|
|
314
|
+
return held.every((h) => h.mode === "shared");
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Grant a lock, run the callback, and release the lock when the callback finishes.
|
|
322
|
+
* Returns the promise that resolves to the callback's return value.
|
|
323
|
+
*/
|
|
324
|
+
#grantAndRun(
|
|
325
|
+
name: string,
|
|
326
|
+
mode: LockMode,
|
|
327
|
+
callback: LockGrantedCallback,
|
|
328
|
+
): Promise<any> {
|
|
329
|
+
const lock: Lock = Object.freeze({ name, mode });
|
|
330
|
+
const entry: HeldLockEntry = { name, mode };
|
|
331
|
+
|
|
332
|
+
// Register as held
|
|
333
|
+
let heldList = this.#held.get(name);
|
|
334
|
+
if (!heldList) {
|
|
335
|
+
heldList = [];
|
|
336
|
+
this.#held.set(name, heldList);
|
|
337
|
+
}
|
|
338
|
+
heldList.push(entry);
|
|
339
|
+
|
|
340
|
+
// Run callback
|
|
341
|
+
const result = this.#invokeCallback(callback, lock);
|
|
342
|
+
|
|
343
|
+
// On completion (success or failure), release the lock and process queue
|
|
344
|
+
return result.then(
|
|
345
|
+
(value) => {
|
|
346
|
+
this.#releaseLock(name, entry);
|
|
347
|
+
return value;
|
|
348
|
+
},
|
|
349
|
+
(err) => {
|
|
350
|
+
this.#releaseLock(name, entry);
|
|
351
|
+
throw err;
|
|
352
|
+
},
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Invoke the user callback safely, wrapping the result in a promise.
|
|
358
|
+
*/
|
|
359
|
+
#invokeCallback(callback: LockGrantedCallback, lock: Lock | null): Promise<any> {
|
|
360
|
+
try {
|
|
361
|
+
const result = callback(lock);
|
|
362
|
+
return Promise.resolve(result);
|
|
363
|
+
} catch (err) {
|
|
364
|
+
return Promise.reject(err);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Release a held lock and process the pending queue.
|
|
370
|
+
*/
|
|
371
|
+
#releaseLock(name: string, entry: HeldLockEntry): void {
|
|
372
|
+
const heldList = this.#held.get(name);
|
|
373
|
+
if (heldList) {
|
|
374
|
+
const idx = heldList.indexOf(entry);
|
|
375
|
+
if (idx !== -1) {
|
|
376
|
+
heldList.splice(idx, 1);
|
|
377
|
+
}
|
|
378
|
+
if (heldList.length === 0) {
|
|
379
|
+
this.#held.delete(name);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
this.#processQueue(name);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Remove a pending request from the queue (e.g., on abort).
|
|
387
|
+
*/
|
|
388
|
+
#removePendingRequest(name: string, request: LockRequest): void {
|
|
389
|
+
const queue = this.#pending.get(name);
|
|
390
|
+
if (!queue) return;
|
|
391
|
+
const idx = queue.indexOf(request);
|
|
392
|
+
if (idx !== -1) {
|
|
393
|
+
queue.splice(idx, 1);
|
|
394
|
+
}
|
|
395
|
+
if (queue.length === 0) {
|
|
396
|
+
this.#pending.delete(name);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Clean up abort event listener for a request.
|
|
402
|
+
*/
|
|
403
|
+
#cleanupAbortHandler(request: LockRequest): void {
|
|
404
|
+
if (request.abortHandler && request.signal) {
|
|
405
|
+
request.signal.removeEventListener("abort", request.abortHandler);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Process the pending queue for a given lock name, granting as many as possible.
|
|
411
|
+
*/
|
|
412
|
+
#processQueue(name: string): void {
|
|
413
|
+
const queue = this.#pending.get(name);
|
|
414
|
+
if (!queue || queue.length === 0) return;
|
|
415
|
+
|
|
416
|
+
while (queue.length > 0) {
|
|
417
|
+
const next = queue[0];
|
|
418
|
+
|
|
419
|
+
if (!this.#canAcquireDirect(name, next.mode)) {
|
|
420
|
+
break;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Remove from queue
|
|
424
|
+
queue.shift();
|
|
425
|
+
this.#cleanupAbortHandler(next);
|
|
426
|
+
|
|
427
|
+
if (queue.length === 0) {
|
|
428
|
+
this.#pending.delete(name);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// Grant the lock and run the callback. The result flows back through
|
|
432
|
+
// the original promise that was returned from request().
|
|
433
|
+
this.#grantAndRun(name, next.mode, next.callback).then(
|
|
434
|
+
next.resolve,
|
|
435
|
+
next.reject,
|
|
436
|
+
);
|
|
437
|
+
|
|
438
|
+
// If we just granted an exclusive lock, stop processing
|
|
439
|
+
if (next.mode === "exclusive") {
|
|
440
|
+
break;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// If we granted a shared lock, continue granting other shared locks
|
|
444
|
+
// at the front of the queue
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
get [Symbol.toStringTag](): string {
|
|
449
|
+
return "LockManager";
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// DOMException polyfill for this module
|
|
454
|
+
class DOMException extends Error {
|
|
455
|
+
readonly code: number = 0;
|
|
456
|
+
constructor(message: string, name: string) {
|
|
457
|
+
super(message);
|
|
458
|
+
this.name = name;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { createDataCloneError } from "../events/DOMException";
|
|
2
|
+
import {
|
|
3
|
+
structuredCloneCloneSymbol,
|
|
4
|
+
structuredCloneTransferSymbol,
|
|
5
|
+
} from "../clone/transferableSymbols";
|
|
6
|
+
|
|
7
|
+
export interface VideoFrameInit {
|
|
8
|
+
format?: string;
|
|
9
|
+
timestamp?: number;
|
|
10
|
+
codedWidth?: number;
|
|
11
|
+
codedHeight?: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class VideoFrame {
|
|
15
|
+
_exactData: any;
|
|
16
|
+
_exactClosed = false;
|
|
17
|
+
format: string | null;
|
|
18
|
+
timestamp: number | undefined;
|
|
19
|
+
codedWidth: number | undefined;
|
|
20
|
+
codedHeight: number | undefined;
|
|
21
|
+
|
|
22
|
+
constructor(data: any, init: VideoFrameInit = {}) {
|
|
23
|
+
this._exactData = data;
|
|
24
|
+
this.format = init.format ?? null;
|
|
25
|
+
this.timestamp = init.timestamp;
|
|
26
|
+
this.codedWidth = init.codedWidth;
|
|
27
|
+
this.codedHeight = init.codedHeight;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
close(): void {
|
|
31
|
+
this._exactClosed = true;
|
|
32
|
+
this.format = null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
[structuredCloneCloneSymbol](): VideoFrame {
|
|
36
|
+
if (this._exactClosed || this.format === null) {
|
|
37
|
+
throw createDataCloneError();
|
|
38
|
+
}
|
|
39
|
+
return new VideoFrame(this._exactData, {
|
|
40
|
+
format: this.format,
|
|
41
|
+
timestamp: this.timestamp,
|
|
42
|
+
codedWidth: this.codedWidth,
|
|
43
|
+
codedHeight: this.codedHeight,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
[structuredCloneTransferSymbol](): VideoFrame {
|
|
48
|
+
const clone = this[structuredCloneCloneSymbol]();
|
|
49
|
+
this.close();
|
|
50
|
+
return clone;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
get [Symbol.toStringTag](): string {
|
|
54
|
+
return "VideoFrame";
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export default VideoFrame;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MessageChannel implementation for Ibex runtime
|
|
3
|
+
*
|
|
4
|
+
* Creates a pair of connected MessagePorts for two-way communication.
|
|
5
|
+
* @see https://html.spec.whatwg.org/multipage/web-messaging.html#message-channels
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { MessagePort } from './MessagePort';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* MessageChannel creates a new channel with two connected ports.
|
|
12
|
+
* Messages sent through port1 are received by port2 and vice versa.
|
|
13
|
+
*/
|
|
14
|
+
export class MessageChannel {
|
|
15
|
+
readonly port1: MessagePort;
|
|
16
|
+
readonly port2: MessagePort;
|
|
17
|
+
|
|
18
|
+
constructor() {
|
|
19
|
+
this.port1 = new MessagePort();
|
|
20
|
+
this.port2 = new MessagePort();
|
|
21
|
+
|
|
22
|
+
// Set up the bidirectional connection
|
|
23
|
+
MessagePort._pair(this.port1, this.port2);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
get [Symbol.toStringTag](): string {
|
|
27
|
+
return 'MessageChannel';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default MessageChannel;
|