@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
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ccheever/exact-ibex-runtime",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "JavaScript runtime and polyfill layer for Ibex",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.ts",
|
|
7
|
+
"types": "src/index.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./src/index.ts",
|
|
11
|
+
"types": "./src/index.ts"
|
|
12
|
+
},
|
|
13
|
+
"./bootstrap": {
|
|
14
|
+
"import": "./src/bootstrap.ts",
|
|
15
|
+
"types": "./src/bootstrap.ts"
|
|
16
|
+
},
|
|
17
|
+
"./camera": {
|
|
18
|
+
"import": "./src/camera/index.ts",
|
|
19
|
+
"types": "./src/camera/index.ts"
|
|
20
|
+
},
|
|
21
|
+
"./events": {
|
|
22
|
+
"import": "./src/events/index.ts",
|
|
23
|
+
"types": "./src/events/index.ts"
|
|
24
|
+
},
|
|
25
|
+
"./fetch": {
|
|
26
|
+
"import": "./src/fetch/index.ts",
|
|
27
|
+
"types": "./src/fetch/index.ts"
|
|
28
|
+
},
|
|
29
|
+
"./fetch/native-bridge": {
|
|
30
|
+
"import": "./src/fetch/native-bridge.ts",
|
|
31
|
+
"types": "./src/fetch/native-bridge.ts"
|
|
32
|
+
},
|
|
33
|
+
"./http-server": {
|
|
34
|
+
"import": "./src/http-server/index.js",
|
|
35
|
+
"types": "./src/http-server/index.ts"
|
|
36
|
+
},
|
|
37
|
+
"./internal/detect": {
|
|
38
|
+
"import": "./src/internal/detect.ts",
|
|
39
|
+
"types": "./src/internal/detect.ts"
|
|
40
|
+
},
|
|
41
|
+
"./location": {
|
|
42
|
+
"import": "./src/location/index.ts",
|
|
43
|
+
"types": "./src/location/index.ts"
|
|
44
|
+
},
|
|
45
|
+
"./react-native": {
|
|
46
|
+
"import": "./src/react-native/index.ts",
|
|
47
|
+
"types": "./src/react-native/index.ts"
|
|
48
|
+
},
|
|
49
|
+
"./runtime-entry": {
|
|
50
|
+
"import": "./src/runtime-entry.ts",
|
|
51
|
+
"types": "./src/runtime-entry.ts"
|
|
52
|
+
},
|
|
53
|
+
"./security": {
|
|
54
|
+
"import": "./src/security/index.ts",
|
|
55
|
+
"types": "./src/security/index.ts"
|
|
56
|
+
},
|
|
57
|
+
"./security/Permissions": {
|
|
58
|
+
"import": "./src/security/Permissions.ts",
|
|
59
|
+
"types": "./src/security/Permissions.ts"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"dependencies": {}
|
|
63
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AbortController - Web Standard AbortController Implementation
|
|
3
|
+
*
|
|
4
|
+
* @see https://dom.spec.whatwg.org/#interface-abortcontroller
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { AbortSignal } from "./AbortSignal";
|
|
8
|
+
|
|
9
|
+
export class AbortController {
|
|
10
|
+
private _signal: AbortSignal;
|
|
11
|
+
|
|
12
|
+
constructor() {
|
|
13
|
+
this._signal = new AbortSignal();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
get signal(): AbortSignal {
|
|
17
|
+
return this._signal;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
abort(reason?: any): void {
|
|
21
|
+
(this._signal as any)._abort(reason);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AbortSignal - Web Standard AbortSignal Implementation
|
|
3
|
+
*
|
|
4
|
+
* @see https://dom.spec.whatwg.org/#interface-abortsignal
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Event, EventTarget } from "../events";
|
|
8
|
+
import { DOMException } from "../events";
|
|
9
|
+
|
|
10
|
+
const ABORT_SIGNAL_BRAND = Symbol.for("@exact/AbortSignal");
|
|
11
|
+
|
|
12
|
+
export function isAbortSignal(value: unknown): value is AbortSignal {
|
|
13
|
+
if (typeof value !== "object" || value === null) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if ((value as { [ABORT_SIGNAL_BRAND]?: true })[ABORT_SIGNAL_BRAND] === true) {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
return (
|
|
23
|
+
typeof (value as { aborted?: unknown }).aborted === "boolean" &&
|
|
24
|
+
"reason" in (value as object) &&
|
|
25
|
+
typeof (value as { addEventListener?: unknown }).addEventListener === "function" &&
|
|
26
|
+
typeof (value as { removeEventListener?: unknown }).removeEventListener === "function"
|
|
27
|
+
);
|
|
28
|
+
} catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class AbortSignal extends EventTarget {
|
|
34
|
+
private [ABORT_SIGNAL_BRAND] = true;
|
|
35
|
+
|
|
36
|
+
private _aborted: boolean = false;
|
|
37
|
+
private _reason: any = undefined;
|
|
38
|
+
|
|
39
|
+
// Event handler property
|
|
40
|
+
onabort: ((this: AbortSignal, ev: Event) => any) | null = null;
|
|
41
|
+
|
|
42
|
+
constructor() {
|
|
43
|
+
super();
|
|
44
|
+
// Private constructor - use static methods or AbortController
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
get aborted(): boolean {
|
|
48
|
+
return this._aborted;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get reason(): any {
|
|
52
|
+
return this._reason;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
throwIfAborted(): void {
|
|
56
|
+
if (this._aborted) {
|
|
57
|
+
throw this._reason;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Abort the signal
|
|
63
|
+
* @internal - Called by AbortController
|
|
64
|
+
*/
|
|
65
|
+
_abort(reason?: any): void {
|
|
66
|
+
if (this._aborted) return;
|
|
67
|
+
|
|
68
|
+
this._aborted = true;
|
|
69
|
+
this._reason =
|
|
70
|
+
reason === undefined
|
|
71
|
+
? new DOMException("The operation was aborted.", "AbortError")
|
|
72
|
+
: reason;
|
|
73
|
+
|
|
74
|
+
// Dispatch abort event
|
|
75
|
+
const event = new Event("abort");
|
|
76
|
+
|
|
77
|
+
// Call handler property
|
|
78
|
+
if (this.onabort) {
|
|
79
|
+
try {
|
|
80
|
+
this.onabort.call(this, event);
|
|
81
|
+
} catch (e) {
|
|
82
|
+
console.error("Error in onabort handler:", e);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Dispatch to listeners
|
|
87
|
+
this.dispatchEvent(event);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Create an already-aborted signal
|
|
92
|
+
*/
|
|
93
|
+
static abort(reason?: any): AbortSignal {
|
|
94
|
+
const signal = new AbortSignal();
|
|
95
|
+
signal._abort(reason);
|
|
96
|
+
return signal;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Create a signal that aborts after a timeout
|
|
101
|
+
*/
|
|
102
|
+
static timeout(milliseconds: number): AbortSignal {
|
|
103
|
+
const signal = new AbortSignal();
|
|
104
|
+
|
|
105
|
+
setTimeout(() => {
|
|
106
|
+
signal._abort(new DOMException("The operation timed out.", "TimeoutError"));
|
|
107
|
+
}, milliseconds);
|
|
108
|
+
|
|
109
|
+
return signal;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Create a signal that aborts when any of the given signals abort
|
|
114
|
+
*/
|
|
115
|
+
static any(signals: AbortSignal[]): AbortSignal {
|
|
116
|
+
const signal = new AbortSignal();
|
|
117
|
+
|
|
118
|
+
// Check if any signal is already aborted
|
|
119
|
+
for (const s of signals) {
|
|
120
|
+
if (s.aborted) {
|
|
121
|
+
signal._abort(s.reason);
|
|
122
|
+
return signal;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Listen for abort on all signals
|
|
127
|
+
const listeners = new Map<AbortSignal, () => void>();
|
|
128
|
+
const cleanup = () => {
|
|
129
|
+
for (const [source, listener] of listeners) {
|
|
130
|
+
source.removeEventListener("abort", listener);
|
|
131
|
+
}
|
|
132
|
+
listeners.clear();
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const onAbort = () => {
|
|
136
|
+
for (const s of signals) {
|
|
137
|
+
if (s.aborted) {
|
|
138
|
+
cleanup();
|
|
139
|
+
signal._abort(s.reason);
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
for (const s of signals) {
|
|
146
|
+
listeners.set(s, onAbort);
|
|
147
|
+
s.addEventListener("abort", onAbort, { once: true });
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return signal;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export {
|
|
2
|
+
_resetExactAccessibilityForTests,
|
|
3
|
+
announceForAccessibility,
|
|
4
|
+
focusElementForAccessibility,
|
|
5
|
+
getExactAccessibilitySnapshot,
|
|
6
|
+
installExactAccessibilityGlobal,
|
|
7
|
+
refreshExactAccessibility,
|
|
8
|
+
subscribeExactAccessibilityChanges,
|
|
9
|
+
type AccessibilityInfoEvent,
|
|
10
|
+
type AccessibilityInfoKey,
|
|
11
|
+
type ExactAccessibilitySnapshot,
|
|
12
|
+
} from "./core/accessibility.js";
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
const DETACHED_ARRAY_BUFFERS = Symbol.for("exact.detachedArrayBuffers");
|
|
2
|
+
const NON_TRANSFERABLE_ARRAY_BUFFERS = Symbol.for("exact.nonTransferableArrayBuffers");
|
|
3
|
+
const PATCHED_ARRAY_BUFFER_BYTE_LENGTH = Symbol.for("exact.patchedArrayBufferByteLength");
|
|
4
|
+
|
|
5
|
+
function getDetachedArrayBuffers(): WeakSet<ArrayBuffer> | null {
|
|
6
|
+
if (typeof WeakSet !== "function") {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
const globalObject = globalThis as any;
|
|
10
|
+
let detached = globalObject[DETACHED_ARRAY_BUFFERS] as WeakSet<ArrayBuffer> | undefined;
|
|
11
|
+
if (!detached) {
|
|
12
|
+
detached = new WeakSet<ArrayBuffer>();
|
|
13
|
+
globalObject[DETACHED_ARRAY_BUFFERS] = detached;
|
|
14
|
+
}
|
|
15
|
+
return detached;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function getNonTransferableArrayBuffers(): WeakSet<ArrayBuffer> | null {
|
|
19
|
+
if (typeof WeakSet !== "function") {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
const globalObject = globalThis as any;
|
|
23
|
+
let buffers = globalObject[NON_TRANSFERABLE_ARRAY_BUFFERS] as WeakSet<ArrayBuffer> | undefined;
|
|
24
|
+
if (!buffers) {
|
|
25
|
+
buffers = new WeakSet<ArrayBuffer>();
|
|
26
|
+
globalObject[NON_TRANSFERABLE_ARRAY_BUFFERS] = buffers;
|
|
27
|
+
}
|
|
28
|
+
return buffers;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function installDetachedArrayBufferByteLengthPatch(): void {
|
|
32
|
+
const proto = ArrayBuffer.prototype as ArrayBuffer & {
|
|
33
|
+
[PATCHED_ARRAY_BUFFER_BYTE_LENGTH]?: boolean;
|
|
34
|
+
};
|
|
35
|
+
if (proto[PATCHED_ARRAY_BUFFER_BYTE_LENGTH]) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const descriptor = Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, "byteLength");
|
|
40
|
+
if (!descriptor?.get) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
Object.defineProperty(ArrayBuffer.prototype, "byteLength", {
|
|
46
|
+
get: function byteLength(this: ArrayBuffer): number {
|
|
47
|
+
if (getDetachedArrayBuffers()?.has(this)) {
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
50
|
+
return descriptor.get!.call(this);
|
|
51
|
+
},
|
|
52
|
+
enumerable: descriptor.enumerable ?? false,
|
|
53
|
+
configurable: descriptor.configurable ?? true,
|
|
54
|
+
});
|
|
55
|
+
Object.defineProperty(proto, PATCHED_ARRAY_BUFFER_BYTE_LENGTH, {
|
|
56
|
+
value: true,
|
|
57
|
+
configurable: true,
|
|
58
|
+
});
|
|
59
|
+
} catch (_error) {
|
|
60
|
+
// Environments that refuse to patch the prototype will continue to rely
|
|
61
|
+
// on the WeakSet-based detached tracking.
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
installDetachedArrayBufferByteLengthPatch();
|
|
66
|
+
|
|
67
|
+
export function isDetachedArrayBuffer(buffer: ArrayBuffer): boolean {
|
|
68
|
+
const detached = getDetachedArrayBuffers();
|
|
69
|
+
if (detached?.has(buffer)) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
if (buffer.byteLength !== 0) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
new Uint8Array(buffer);
|
|
77
|
+
return false;
|
|
78
|
+
} catch (_error) {
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function markDetachedArrayBuffer(buffer: ArrayBuffer): void {
|
|
84
|
+
const byteLength = buffer.byteLength;
|
|
85
|
+
if (byteLength > 0) {
|
|
86
|
+
new Uint8Array(buffer).fill(0);
|
|
87
|
+
}
|
|
88
|
+
const detached = getDetachedArrayBuffers();
|
|
89
|
+
detached?.add(buffer);
|
|
90
|
+
try {
|
|
91
|
+
Object.defineProperty(buffer, "byteLength", {
|
|
92
|
+
value: 0,
|
|
93
|
+
writable: false,
|
|
94
|
+
enumerable: false,
|
|
95
|
+
configurable: true,
|
|
96
|
+
});
|
|
97
|
+
} catch (_error) {
|
|
98
|
+
// Fall back to the WeakSet-based detached tracking when ArrayBuffer
|
|
99
|
+
// instances reject own-property shadowing for byteLength.
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function isNonTransferableArrayBuffer(buffer: ArrayBuffer): boolean {
|
|
104
|
+
return getNonTransferableArrayBuffers()?.has(buffer) ?? false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function markNonTransferableArrayBuffer(buffer: ArrayBuffer): void {
|
|
108
|
+
getNonTransferableArrayBuffers()?.add(buffer);
|
|
109
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base64 Encoding - atob/btoa
|
|
3
|
+
*
|
|
4
|
+
* @see https://html.spec.whatwg.org/multipage/webappapis.html#atob
|
|
5
|
+
*
|
|
6
|
+
* Note: These only handle Latin-1 (bytes 0-255).
|
|
7
|
+
* For Unicode, use TextEncoder first.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Base64 character set
|
|
11
|
+
const BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
12
|
+
|
|
13
|
+
// Reverse lookup table
|
|
14
|
+
const BASE64_LOOKUP = new Uint8Array(256);
|
|
15
|
+
for (let i = 0; i < BASE64_CHARS.length; i++) {
|
|
16
|
+
BASE64_LOOKUP[BASE64_CHARS.charCodeAt(i)] = i;
|
|
17
|
+
}
|
|
18
|
+
BASE64_LOOKUP["=".charCodeAt(0)] = 0; // Padding
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* btoa - Encode a binary string to Base64
|
|
22
|
+
*
|
|
23
|
+
* @param data Binary string (each char code must be 0-255)
|
|
24
|
+
* @returns Base64 encoded string
|
|
25
|
+
* @throws DOMException if string contains characters outside Latin-1
|
|
26
|
+
*/
|
|
27
|
+
export function btoa(data: string): string {
|
|
28
|
+
if (data === undefined || data === null) {
|
|
29
|
+
data = "undefined";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const str = String(data);
|
|
33
|
+
const bytes: number[] = [];
|
|
34
|
+
|
|
35
|
+
for (let i = 0; i < str.length; i++) {
|
|
36
|
+
const charCode = str.charCodeAt(i);
|
|
37
|
+
if (charCode > 255) {
|
|
38
|
+
throw new DOMException(
|
|
39
|
+
"The string to be encoded contains characters outside of the Latin1 range.",
|
|
40
|
+
"InvalidCharacterError"
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
bytes.push(charCode);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Encode to Base64
|
|
47
|
+
let result = "";
|
|
48
|
+
let i = 0;
|
|
49
|
+
|
|
50
|
+
while (i < bytes.length) {
|
|
51
|
+
const b1 = bytes[i++] ?? 0;
|
|
52
|
+
const b2 = bytes[i++];
|
|
53
|
+
const b3 = bytes[i++];
|
|
54
|
+
|
|
55
|
+
result += BASE64_CHARS[b1 >> 2];
|
|
56
|
+
result += BASE64_CHARS[((b1 & 0x03) << 4) | ((b2 ?? 0) >> 4)];
|
|
57
|
+
|
|
58
|
+
if (b2 !== undefined) {
|
|
59
|
+
result += BASE64_CHARS[((b2 & 0x0f) << 2) | ((b3 ?? 0) >> 6)];
|
|
60
|
+
} else {
|
|
61
|
+
result += "=";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (b3 !== undefined) {
|
|
65
|
+
result += BASE64_CHARS[b3 & 0x3f];
|
|
66
|
+
} else {
|
|
67
|
+
result += "=";
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* atob - Decode a Base64 string to binary
|
|
76
|
+
*
|
|
77
|
+
* @param data Base64 encoded string
|
|
78
|
+
* @returns Decoded binary string
|
|
79
|
+
* @throws DOMException if string is not valid Base64
|
|
80
|
+
*/
|
|
81
|
+
export function atob(data: string): string {
|
|
82
|
+
if (data === undefined || data === null) {
|
|
83
|
+
throw new DOMException(
|
|
84
|
+
"The string to be decoded is not correctly encoded.",
|
|
85
|
+
"InvalidCharacterError"
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Step 1: Strip ASCII whitespace (0x09, 0x0A, 0x0C, 0x0D, 0x20)
|
|
90
|
+
let str = "";
|
|
91
|
+
const raw = String(data);
|
|
92
|
+
for (let i = 0; i < raw.length; i++) {
|
|
93
|
+
const c = raw.charCodeAt(i);
|
|
94
|
+
if (c !== 0x09 && c !== 0x0a && c !== 0x0c && c !== 0x0d && c !== 0x20) {
|
|
95
|
+
str += raw[i];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (str.length === 0) {
|
|
100
|
+
return "";
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Step 2: If length mod 4 === 0, strip up to 2 trailing '='
|
|
104
|
+
let len = str.length;
|
|
105
|
+
if (len % 4 === 0) {
|
|
106
|
+
if (str[len - 1] === "=") { len--; }
|
|
107
|
+
if (str[len - 1] === "=") { len--; }
|
|
108
|
+
str = str.slice(0, len);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Step 3: If remaining length mod 4 === 1, throw
|
|
112
|
+
if (str.length % 4 === 1) {
|
|
113
|
+
throw new DOMException(
|
|
114
|
+
"The string to be decoded is not correctly encoded.",
|
|
115
|
+
"InvalidCharacterError"
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Step 4: Validate characters - only [A-Za-z0-9+/] allowed (no '=' at this point)
|
|
120
|
+
for (let i = 0; i < str.length; i++) {
|
|
121
|
+
if (!BASE64_CHARS.includes(str[i])) {
|
|
122
|
+
throw new DOMException(
|
|
123
|
+
"The string to be decoded is not correctly encoded.",
|
|
124
|
+
"InvalidCharacterError"
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Step 5: Pad with '=' to make length a multiple of 4
|
|
130
|
+
const remainder = str.length % 4;
|
|
131
|
+
if (remainder === 2) {
|
|
132
|
+
str += "==";
|
|
133
|
+
} else if (remainder === 3) {
|
|
134
|
+
str += "=";
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Decode
|
|
138
|
+
const result: number[] = [];
|
|
139
|
+
let i = 0;
|
|
140
|
+
|
|
141
|
+
while (i < str.length) {
|
|
142
|
+
const c1 = BASE64_LOOKUP[str.charCodeAt(i++)];
|
|
143
|
+
const c2 = BASE64_LOOKUP[str.charCodeAt(i++)];
|
|
144
|
+
const c3 = BASE64_LOOKUP[str.charCodeAt(i++)];
|
|
145
|
+
const c4 = BASE64_LOOKUP[str.charCodeAt(i++)];
|
|
146
|
+
|
|
147
|
+
result.push((c1 << 2) | (c2 >> 4));
|
|
148
|
+
|
|
149
|
+
if (str[i - 2] !== "=") {
|
|
150
|
+
result.push(((c2 & 0x0f) << 4) | (c3 >> 2));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (str[i - 1] !== "=") {
|
|
154
|
+
result.push(((c3 & 0x03) << 6) | c4);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return String.fromCharCode(...result);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// DOMException for this module (avoid circular dependency)
|
|
162
|
+
class DOMException extends Error {
|
|
163
|
+
readonly code: number = 0;
|
|
164
|
+
constructor(message: string, name: string) {
|
|
165
|
+
super(message);
|
|
166
|
+
this.name = name;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { atob, btoa } from "./base64";
|