@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.
Files changed (161) hide show
  1. package/package.json +63 -0
  2. package/src/abort/AbortController.ts +23 -0
  3. package/src/abort/AbortSignal.ts +152 -0
  4. package/src/abort/index.ts +2 -0
  5. package/src/accessibility.ts +12 -0
  6. package/src/arraybuffer-detach.ts +109 -0
  7. package/src/base64/base64.ts +168 -0
  8. package/src/base64/index.ts +1 -0
  9. package/src/blob/Blob.ts +259 -0
  10. package/src/blob/File.ts +59 -0
  11. package/src/blob/FormData.ts +323 -0
  12. package/src/blob/index.ts +3 -0
  13. package/src/bootstrap.ts +1946 -0
  14. package/src/broadcast/BroadcastChannel.ts +280 -0
  15. package/src/broadcast/index.ts +5 -0
  16. package/src/cache/Cache.ts +349 -0
  17. package/src/cache/CacheStorage.ts +89 -0
  18. package/src/cache/index.ts +27 -0
  19. package/src/camera/index.ts +6202 -0
  20. package/src/camera/processor.worker.ts +194 -0
  21. package/src/camera/scene.ts +195 -0
  22. package/src/clipboard/Clipboard.ts +129 -0
  23. package/src/clipboard/ClipboardItem.ts +97 -0
  24. package/src/clipboard/index.ts +6 -0
  25. package/src/clone/index.ts +1 -0
  26. package/src/clone/structuredClone.ts +389 -0
  27. package/src/clone/transferableSymbols.ts +2 -0
  28. package/src/compression/CompressionStream.ts +146 -0
  29. package/src/compression/DecompressionStream.ts +342 -0
  30. package/src/compression/index.ts +4 -0
  31. package/src/console/Console.ts +341 -0
  32. package/src/console/index.ts +2 -0
  33. package/src/core/accessibility-state.ts +263 -0
  34. package/src/core/accessibility.ts +184 -0
  35. package/src/core/agent-state.ts +37 -0
  36. package/src/core/diagnostics-logs.ts +144 -0
  37. package/src/core/host-call-bridge.ts +16 -0
  38. package/src/core/i18n-helpers.ts +189 -0
  39. package/src/core/locale-state.ts +253 -0
  40. package/src/core/locale.ts +95 -0
  41. package/src/crypto/Crypto.ts +2743 -0
  42. package/src/crypto/index.ts +1 -0
  43. package/src/diagnostics/logs.ts +7 -0
  44. package/src/encoding/TextDecoder.ts +1181 -0
  45. package/src/encoding/TextDecoderStream.ts +58 -0
  46. package/src/encoding/TextEncoder.ts +180 -0
  47. package/src/encoding/TextEncoderStream.ts +39 -0
  48. package/src/encoding/index.ts +8 -0
  49. package/src/events/CloseEvent.ts +91 -0
  50. package/src/events/DOMException.ts +409 -0
  51. package/src/events/ErrorEvent.ts +39 -0
  52. package/src/events/Event.ts +151 -0
  53. package/src/events/EventTarget.ts +280 -0
  54. package/src/events/FocusEvent.ts +27 -0
  55. package/src/events/KeyboardEvent.ts +46 -0
  56. package/src/events/MessageEvent.ts +61 -0
  57. package/src/events/ProgressEvent.ts +33 -0
  58. package/src/events/PromiseRejectionEvent.ts +31 -0
  59. package/src/events/index.ts +52 -0
  60. package/src/eventsource/EventSource.ts +371 -0
  61. package/src/eventsource/index.ts +2 -0
  62. package/src/fetch/Headers.ts +642 -0
  63. package/src/fetch/Request.ts +760 -0
  64. package/src/fetch/Response.ts +543 -0
  65. package/src/fetch/body.ts +1256 -0
  66. package/src/fetch/cookie-jar.ts +566 -0
  67. package/src/fetch/demo.ts +207 -0
  68. package/src/fetch/errors.ts +101 -0
  69. package/src/fetch/fetch.ts +2610 -0
  70. package/src/fetch/index.ts +101 -0
  71. package/src/fetch/native-bridge.ts +65 -0
  72. package/src/fetch/types.ts +258 -0
  73. package/src/filereader/FileReader.ts +236 -0
  74. package/src/filereader/index.ts +1 -0
  75. package/src/fs/Dirent.ts +39 -0
  76. package/src/fs/ExactFile.ts +450 -0
  77. package/src/fs/Stats.ts +80 -0
  78. package/src/fs/index.ts +944 -0
  79. package/src/fs/promises.ts +386 -0
  80. package/src/fs/shared.ts +328 -0
  81. package/src/http-server/index.js +697 -0
  82. package/src/http-server/index.ts +27 -0
  83. package/src/identity.generated.ts +14 -0
  84. package/src/index.ts +283 -0
  85. package/src/indexeddb/IDBCursor.ts +188 -0
  86. package/src/indexeddb/IDBDatabase.ts +343 -0
  87. package/src/indexeddb/IDBFactory.ts +269 -0
  88. package/src/indexeddb/IDBIndex.ts +194 -0
  89. package/src/indexeddb/IDBKeyRange.ts +109 -0
  90. package/src/indexeddb/IDBObjectStore.ts +468 -0
  91. package/src/indexeddb/IDBRequest.ts +163 -0
  92. package/src/indexeddb/IDBTransaction.ts +207 -0
  93. package/src/indexeddb/index.ts +34 -0
  94. package/src/indexeddb/utils.ts +52 -0
  95. package/src/inspect/index.ts +1 -0
  96. package/src/inspect/inspect.ts +465 -0
  97. package/src/internal/detect.ts +104 -0
  98. package/src/locale.ts +10 -0
  99. package/src/location/index.ts +1059 -0
  100. package/src/locks/LockManager.ts +460 -0
  101. package/src/locks/index.ts +12 -0
  102. package/src/media/VideoFrame.ts +58 -0
  103. package/src/messaging/MessageChannel.ts +31 -0
  104. package/src/messaging/MessagePort.ts +180 -0
  105. package/src/messaging/index.ts +2 -0
  106. package/src/messaging.ts +247 -0
  107. package/src/native/NativeModules.ts +354 -0
  108. package/src/native/index.ts +1 -0
  109. package/src/navigator/Navigator.ts +351 -0
  110. package/src/navigator/index.ts +1 -0
  111. package/src/node/Buffer.ts +1786 -0
  112. package/src/node/index.ts +4 -0
  113. package/src/node/path.ts +495 -0
  114. package/src/node/process.ts +2528 -0
  115. package/src/performance/Performance.ts +532 -0
  116. package/src/performance/index.ts +21 -0
  117. package/src/polyfills/array.ts +236 -0
  118. package/src/polyfills/arraybuffer.ts +172 -0
  119. package/src/polyfills/groupby.ts +85 -0
  120. package/src/polyfills/index.ts +85 -0
  121. package/src/polyfills/intl.ts +1956 -0
  122. package/src/polyfills/iterator.ts +479 -0
  123. package/src/polyfills/promise.ts +37 -0
  124. package/src/polyfills/set.ts +245 -0
  125. package/src/polyfills/string.ts +85 -0
  126. package/src/polyfills/typedarray.ts +110 -0
  127. package/src/promise-rejection-tracking.ts +464 -0
  128. package/src/react-native/index.ts +388 -0
  129. package/src/runtime-entry.ts +55 -0
  130. package/src/scheduling/AnimationFrame.ts +105 -0
  131. package/src/scheduling/IdleCallback.ts +167 -0
  132. package/src/scheduling/index.ts +13 -0
  133. package/src/security/Capabilities.ts +1146 -0
  134. package/src/security/Permissions.ts +392 -0
  135. package/src/security/capability-bits.generated.ts +63 -0
  136. package/src/security/index.ts +16 -0
  137. package/src/sqlite/Database.ts +456 -0
  138. package/src/sqlite/Statement.ts +206 -0
  139. package/src/sqlite/constants.ts +79 -0
  140. package/src/sqlite/errors.ts +25 -0
  141. package/src/sqlite/index.ts +34 -0
  142. package/src/sqlite/module.js +438 -0
  143. package/src/storage/Storage.ts +291 -0
  144. package/src/storage/StorageManager.ts +91 -0
  145. package/src/storage/index.ts +3 -0
  146. package/src/stream-compat.ts +47 -0
  147. package/src/streams/ReadableStream.ts +4131 -0
  148. package/src/streams/TransformStream.ts +375 -0
  149. package/src/streams/WritableStream.ts +866 -0
  150. package/src/streams/index.ts +41 -0
  151. package/src/timers/Timers.ts +296 -0
  152. package/src/timers/index.ts +11 -0
  153. package/src/url/URL.ts +656 -0
  154. package/src/url/URLPattern.ts +850 -0
  155. package/src/url/URLSearchParams.ts +244 -0
  156. package/src/url/index.ts +9 -0
  157. package/src/websocket/WebSocket.ts +770 -0
  158. package/src/websocket/WebSocketError.ts +52 -0
  159. package/src/websocket/WebSocketStream.ts +628 -0
  160. package/src/websocket/index.ts +7 -0
  161. package/src/window/index.ts +872 -0
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Fetch API
3
+ *
4
+ * Web-standard Fetch API implementation for the Ibex runtime.
5
+ * Follows the WHATWG Fetch Standard with native platform integration.
6
+ *
7
+ * @see https://fetch.spec.whatwg.org/
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { fetch, Headers, Request, Response } from '@exact/runtime/fetch';
12
+ *
13
+ * // Simple GET request
14
+ * const response = await fetch('https://api.example.com/data');
15
+ * const data = await response.json();
16
+ *
17
+ * // POST with JSON body
18
+ * const response = await fetch('https://api.example.com/users', {
19
+ * method: 'POST',
20
+ * headers: { 'Content-Type': 'application/json' },
21
+ * body: JSON.stringify({ name: 'John' }),
22
+ * });
23
+ *
24
+ * // With AbortController
25
+ * const controller = new AbortController();
26
+ * setTimeout(() => controller.abort(), 5000);
27
+ * const response = await fetch('https://api.example.com/slow', {
28
+ * signal: controller.signal,
29
+ * });
30
+ * ```
31
+ */
32
+
33
+ // Core fetch function
34
+ export { fetch, fetchPolyfill, setNativeFetchModule, isNativeFetchModuleInitialized, installFetchGlobals } from './fetch.js';
35
+
36
+ // Native bridge
37
+ export {
38
+ isNativeFetchAvailable,
39
+ createNativeFetchModule,
40
+ initializeNativeFetch,
41
+ } from './native-bridge.js';
42
+
43
+ // Classes
44
+ export { Headers } from './Headers.js';
45
+ export { Request, type RequestInput } from './Request.js';
46
+ export { Response } from './Response.js';
47
+
48
+ // Cookie jar
49
+ export { cookieJar, CookieJar, setRuntimeOrigin, getRuntimeOrigin } from './cookie-jar.js';
50
+ export type { StoredCookie } from './cookie-jar.js';
51
+
52
+ // Errors
53
+ export { FetchError, AbortError, NetworkError, URLError, BodyConsumedError } from './errors.js';
54
+
55
+ // Types
56
+ export type {
57
+ // Request types
58
+ RequestInit,
59
+ RequestMethod,
60
+ RequestMode,
61
+ RequestCredentials,
62
+ RequestCache,
63
+ RequestRedirect,
64
+ ReferrerPolicy,
65
+ RequestDuplex,
66
+
67
+ // Response types
68
+ ResponseInit,
69
+ ResponseType,
70
+
71
+ // Headers types
72
+ HeadersInit,
73
+
74
+ // Body types
75
+ BodyInit,
76
+ BufferSource,
77
+
78
+ // Native bridge types
79
+ NativeRequestInit,
80
+ NativeResponse,
81
+ NativeStreamingResponse,
82
+ NativeFetchModule,
83
+ } from './types.js';
84
+
85
+ // Body utilities (for advanced usage)
86
+ export {
87
+ bodyToUint8Array,
88
+ readableStreamToUint8Array,
89
+ concatUint8Arrays,
90
+ parseJson,
91
+ parseText,
92
+ parseMultipartFormData,
93
+ extractBoundary,
94
+ isBlob,
95
+ isFormData,
96
+ isArrayBuffer,
97
+ isArrayBufferView,
98
+ } from './body.js';
99
+
100
+ // Stream utilities
101
+ export { isReadableStream } from '../streams/index.js';
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Native Fetch Bridge
3
+ *
4
+ * Bridges the C++ __nativeFetch function to the TypeScript NativeFetchModule interface.
5
+ * This allows the TypeScript fetch implementation to use the native HTTP layer.
6
+ */
7
+
8
+ import type { NativeFetchModule, NativeRequestInit, NativeResponse } from './types.js';
9
+ import { setNativeFetchModule } from './fetch.js';
10
+
11
+ // Declare the global __nativeFetch function installed by C++
12
+ declare global {
13
+ /**
14
+ * Native fetch function installed by ExactHermesBridge.cpp
15
+ * @param url - Request URL
16
+ * @param init - Native request init object
17
+ * @param body - Request body as Uint8Array or null
18
+ * @returns Promise resolving to NativeResponse
19
+ */
20
+ function __nativeFetch(
21
+ url: string,
22
+ init: NativeRequestInit,
23
+ body: Uint8Array | null
24
+ ): Promise<NativeResponse>;
25
+ }
26
+
27
+ /**
28
+ * Check if the native fetch bridge is available
29
+ */
30
+ export function isNativeFetchAvailable(): boolean {
31
+ return typeof __nativeFetch === 'function';
32
+ }
33
+
34
+ /**
35
+ * Create a NativeFetchModule that wraps the C++ __nativeFetch function
36
+ */
37
+ export function createNativeFetchModule(): NativeFetchModule | null {
38
+ if (!isNativeFetchAvailable()) {
39
+ return null;
40
+ }
41
+
42
+ return {
43
+ __exactNativeBridge: true,
44
+ fetch: (
45
+ url: string,
46
+ init: NativeRequestInit,
47
+ body: Uint8Array | null
48
+ ): Promise<NativeResponse> => {
49
+ return __nativeFetch(url, init, body);
50
+ },
51
+ };
52
+ }
53
+
54
+ /**
55
+ * Auto-initialize the native fetch module if available.
56
+ * Call this during runtime bootstrap.
57
+ */
58
+ export function initializeNativeFetch(): boolean {
59
+ const module = createNativeFetchModule();
60
+ if (module) {
61
+ setNativeFetchModule(module);
62
+ return true;
63
+ }
64
+ return false;
65
+ }
@@ -0,0 +1,258 @@
1
+ /**
2
+ * Fetch API Type Definitions
3
+ *
4
+ * Based on the WHATWG Fetch Standard with extensions for Ibex runtime.
5
+ * @see https://fetch.spec.whatwg.org/
6
+ */
7
+
8
+ // =============================================================================
9
+ // Request Types
10
+ // =============================================================================
11
+
12
+ export type RequestMethod =
13
+ | 'GET'
14
+ | 'POST'
15
+ | 'PUT'
16
+ | 'DELETE'
17
+ | 'PATCH'
18
+ | 'HEAD'
19
+ | 'OPTIONS'
20
+ | 'CONNECT'
21
+ | 'TRACE';
22
+
23
+ export type RequestMode = 'cors' | 'no-cors' | 'same-origin' | 'navigate';
24
+
25
+ export type RequestCredentials = 'omit' | 'same-origin' | 'include';
26
+
27
+ export type RequestCache =
28
+ | 'default'
29
+ | 'no-store'
30
+ | 'reload'
31
+ | 'no-cache'
32
+ | 'force-cache'
33
+ | 'only-if-cached';
34
+
35
+ export type RequestRedirect = 'follow' | 'error' | 'manual';
36
+
37
+ export type ReferrerPolicy =
38
+ | ''
39
+ | 'no-referrer'
40
+ | 'no-referrer-when-downgrade'
41
+ | 'same-origin'
42
+ | 'origin'
43
+ | 'strict-origin'
44
+ | 'origin-when-cross-origin'
45
+ | 'strict-origin-when-cross-origin'
46
+ | 'unsafe-url';
47
+
48
+ export type RequestDuplex = 'half';
49
+ export type TlsCertificateSource = string | ArrayBufferView | Array<string | ArrayBufferView>;
50
+
51
+ export interface FetchTlsOptions {
52
+ ca?: TlsCertificateSource;
53
+ cert?: TlsCertificateSource;
54
+ key?: TlsCertificateSource;
55
+ pfx?: TlsCertificateSource;
56
+ passphrase?: string;
57
+ servername?: string;
58
+ rejectUnauthorized?: boolean;
59
+ checkServerIdentity?: (hostname: string, cert: unknown) => Error | null | undefined;
60
+ [key: string]: unknown;
61
+ }
62
+
63
+ /**
64
+ * Request initialization options.
65
+ */
66
+ export interface RequestInit {
67
+ /** HTTP method (GET, POST, etc.) */
68
+ method?: string;
69
+ /** Request headers */
70
+ headers?: HeadersInit;
71
+ /** Request body */
72
+ body?: BodyInit | null;
73
+ /** Request mode for CORS */
74
+ mode?: RequestMode;
75
+ /** Credentials mode */
76
+ credentials?: RequestCredentials;
77
+ /** Cache mode */
78
+ cache?: RequestCache;
79
+ /** Redirect handling mode */
80
+ redirect?: RequestRedirect;
81
+ /** Referrer URL */
82
+ referrer?: string;
83
+ /** Referrer policy */
84
+ referrerPolicy?: ReferrerPolicy;
85
+ /** Subresource integrity hash */
86
+ integrity?: string;
87
+ /** Abort signal for cancellation */
88
+ signal?: AbortSignal | null;
89
+ /** Abort the request after this many milliseconds. Set to 0 to disable the default timeout. */
90
+ timeout?: number;
91
+ /** Required for streaming uploads */
92
+ duplex?: RequestDuplex;
93
+ /** Keep connection alive after page unloads (not supported) */
94
+ keepalive?: boolean;
95
+ /** Disable automatic content decoding and suppress Accept-Encoding injection */
96
+ decompress?: boolean;
97
+ /** Connect over a Unix domain socket instead of TCP. Bun compatibility extension. */
98
+ unix?: string;
99
+ /** Configure TLS certificate validation for HTTPS requests. Bun compatibility extension. */
100
+ tls?: FetchTlsOptions;
101
+ }
102
+
103
+ // =============================================================================
104
+ // Response Types
105
+ // =============================================================================
106
+
107
+ export type ResponseType =
108
+ | 'basic'
109
+ | 'cors'
110
+ | 'default'
111
+ | 'error'
112
+ | 'opaque'
113
+ | 'opaqueredirect';
114
+
115
+ /**
116
+ * Response initialization options.
117
+ */
118
+ export interface ResponseInit {
119
+ /** HTTP status code */
120
+ status?: number;
121
+ /** HTTP status text */
122
+ statusText?: string;
123
+ /** Response headers */
124
+ headers?: HeadersInit;
125
+ }
126
+
127
+ // =============================================================================
128
+ // Headers Types
129
+ // =============================================================================
130
+
131
+ export type HeadersInit =
132
+ | Headers
133
+ | Record<string, string>
134
+ | Iterable<[string, string]>
135
+ | [string, string][];
136
+
137
+ // =============================================================================
138
+ // Body Types
139
+ // =============================================================================
140
+
141
+ export type BodyInit =
142
+ | Blob
143
+ | BufferSource
144
+ | FormData
145
+ | URLSearchParams
146
+ | ReadableStream<Uint8Array>
147
+ | string;
148
+
149
+ export type BufferSource = ArrayBuffer | ArrayBufferView;
150
+
151
+ // =============================================================================
152
+ // Native Bridge Types
153
+ // =============================================================================
154
+
155
+ /**
156
+ * Native request initialization passed to the native layer.
157
+ */
158
+ export interface NativeRequestInit {
159
+ method: string;
160
+ headers: [string, string][];
161
+ credentials: RequestCredentials;
162
+ redirect: RequestRedirect;
163
+ decompress?: boolean;
164
+ signal?: AbortSignal | null;
165
+ }
166
+
167
+ /**
168
+ * Native response data returned from the native layer.
169
+ */
170
+ export interface NativeResponse {
171
+ status: number;
172
+ statusText: string;
173
+ headers: [string, string][];
174
+ url: string;
175
+ redirected: boolean;
176
+ body: ArrayBuffer | null;
177
+ }
178
+
179
+ /**
180
+ * Native streaming response data.
181
+ */
182
+ export interface NativeStreamingResponse {
183
+ status: number;
184
+ statusText: string;
185
+ headers: [string, string][];
186
+ url: string;
187
+ redirected: boolean;
188
+ }
189
+
190
+ /**
191
+ * Interface for the native fetch module.
192
+ * This will be implemented by the native layer (Swift/Kotlin/Rust).
193
+ */
194
+ export interface NativeFetchModule {
195
+ /** Internal marker for the real native bridge implementation. */
196
+ __exactNativeBridge?: boolean;
197
+ /**
198
+ * Perform a fetch request.
199
+ * @param url The request URL
200
+ * @param init Request options
201
+ * @param body Request body as Uint8Array (if any)
202
+ * @returns Promise resolving to native response
203
+ */
204
+ fetch(
205
+ url: string,
206
+ init: NativeRequestInit,
207
+ body: Uint8Array | null
208
+ ): Promise<NativeResponse>;
209
+
210
+ /**
211
+ * Perform a streaming fetch request.
212
+ * @param url The request URL
213
+ * @param init Request options
214
+ * @param body Request body as Uint8Array (if any)
215
+ * @param onHeaders Callback when headers are received
216
+ * @param onData Callback when data chunk is received
217
+ * @param onComplete Callback when response is complete
218
+ * @param onError Callback when error occurs
219
+ * @returns Function to cancel the request
220
+ */
221
+ fetchStreaming?(
222
+ url: string,
223
+ init: NativeRequestInit,
224
+ body: Uint8Array | null,
225
+ onHeaders: (response: NativeStreamingResponse) => void,
226
+ onData: (chunk: Uint8Array) => void,
227
+ onComplete: () => void,
228
+ onError: (error: Error) => void
229
+ ): () => void;
230
+
231
+ /**
232
+ * Perform a fetch request with a streaming upload body.
233
+ * The native layer calls onBodyChunk repeatedly to pull body chunks,
234
+ * receiving null when the body is fully sent.
235
+ *
236
+ * Per spec (half-duplex): the request body is fully sent before
237
+ * the response starts streaming.
238
+ *
239
+ * @param url The request URL
240
+ * @param init Request options
241
+ * @param onBodyChunk Async callback that returns the next body chunk,
242
+ * or null when the body is complete
243
+ * @param onHeaders Callback when response headers are received
244
+ * @param onData Callback when response data chunk is received
245
+ * @param onComplete Callback when response is complete
246
+ * @param onError Callback when error occurs
247
+ * @returns Function to cancel the request
248
+ */
249
+ fetchStreamingUpload?(
250
+ url: string,
251
+ init: NativeRequestInit,
252
+ onBodyChunk: () => Promise<Uint8Array | null>,
253
+ onHeaders: (response: NativeStreamingResponse) => void,
254
+ onData: (chunk: Uint8Array) => void,
255
+ onComplete: () => void,
256
+ onError: (error: Error) => void
257
+ ): () => void;
258
+ }
@@ -0,0 +1,236 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * FileReader implementation for Ibex runtime (Legacy API)
4
+ *
5
+ * @see https://w3c.github.io/FileAPI/#dfn-filereader
6
+ *
7
+ * Note: Modern code should use Blob.arrayBuffer(), Blob.text(), etc.
8
+ * This is provided for compatibility with legacy libraries.
9
+ */
10
+
11
+ import { EventTarget } from '../events/EventTarget';
12
+ import { Event } from '../events/Event';
13
+ import { ProgressEvent } from '../events/ProgressEvent';
14
+ import { DOMException, createInvalidStateError, createNotSupportedError } from '../events/DOMException';
15
+ import { Blob } from '../blob/Blob';
16
+
17
+ // FileReader states
18
+ const EMPTY = 0;
19
+ const LOADING = 1;
20
+ const DONE = 2;
21
+
22
+ /**
23
+ * FileReader enables asynchronous reading of file or blob contents.
24
+ */
25
+ export class FileReader extends EventTarget {
26
+ static readonly EMPTY = EMPTY;
27
+ static readonly LOADING = LOADING;
28
+ static readonly DONE = DONE;
29
+
30
+ readonly EMPTY = EMPTY;
31
+ readonly LOADING = LOADING;
32
+ readonly DONE = DONE;
33
+
34
+ #readyState: number = EMPTY;
35
+ #result: string | ArrayBuffer | null = null;
36
+ #error: DOMException | null = null;
37
+ #aborted = false;
38
+
39
+ // Event handlers
40
+ onloadstart: ((this: FileReader, ev: ProgressEvent) => any) | null = null;
41
+ onprogress: ((this: FileReader, ev: ProgressEvent) => any) | null = null;
42
+ onload: ((this: FileReader, ev: ProgressEvent) => any) | null = null;
43
+ onabort: ((this: FileReader, ev: ProgressEvent) => any) | null = null;
44
+ onerror: ((this: FileReader, ev: ProgressEvent) => any) | null = null;
45
+ onloadend: ((this: FileReader, ev: ProgressEvent) => any) | null = null;
46
+
47
+ get readyState(): number {
48
+ return this.#readyState;
49
+ }
50
+
51
+ get result(): string | ArrayBuffer | null {
52
+ return this.#result;
53
+ }
54
+
55
+ get error(): DOMException | null {
56
+ return this.#error;
57
+ }
58
+
59
+ /**
60
+ * Check if reader is ready to start a new read operation.
61
+ * Throws InvalidStateError if already loading.
62
+ */
63
+ #checkReadyState(): void {
64
+ if (this.#readyState === LOADING) {
65
+ throw createInvalidStateError('FileReader is already loading');
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Read blob as ArrayBuffer.
71
+ */
72
+ readAsArrayBuffer(blob: Blob): void {
73
+ this.#checkReadyState();
74
+ this.#read(blob, 'arraybuffer');
75
+ }
76
+
77
+ /**
78
+ * Read blob as binary string.
79
+ * @deprecated Use readAsArrayBuffer instead.
80
+ */
81
+ readAsBinaryString(blob: Blob): void {
82
+ this.#checkReadyState();
83
+ this.#read(blob, 'binarystring');
84
+ }
85
+
86
+ /**
87
+ * Read blob as text.
88
+ */
89
+ readAsText(blob: Blob, encoding?: string): void {
90
+ this.#checkReadyState();
91
+ this.#read(blob, 'text', encoding);
92
+ }
93
+
94
+ /**
95
+ * Read blob as data URL.
96
+ */
97
+ readAsDataURL(blob: Blob): void {
98
+ this.#checkReadyState();
99
+ this.#read(blob, 'dataurl');
100
+ }
101
+
102
+ /**
103
+ * Abort the read operation.
104
+ */
105
+ abort(): void {
106
+ if (this.#readyState === EMPTY || this.#readyState === DONE) {
107
+ this.#result = null;
108
+ return;
109
+ }
110
+
111
+ if (this.#readyState === LOADING) {
112
+ this.#readyState = DONE;
113
+ this.#result = null;
114
+ this.#aborted = true;
115
+
116
+ this.#fireEvent('abort');
117
+ this.#fireEvent('loadend');
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Internal read implementation.
123
+ */
124
+ async #read(blob: Blob, format: 'arraybuffer' | 'binarystring' | 'text' | 'dataurl', encoding?: string): Promise<void> {
125
+ // State check is done in #checkReadyState() before calling this method
126
+ this.#readyState = LOADING;
127
+ this.#result = null;
128
+ this.#error = null;
129
+ this.#aborted = false;
130
+
131
+ this.#fireProgressEvent('loadstart', 0, blob.size);
132
+
133
+ try {
134
+ // Read the blob data
135
+ const buffer = await blob.arrayBuffer();
136
+
137
+ if (this.#aborted) {
138
+ return;
139
+ }
140
+
141
+ // Fire progress event
142
+ this.#fireProgressEvent('progress', buffer.byteLength, blob.size);
143
+
144
+ // Convert to requested format
145
+ switch (format) {
146
+ case 'arraybuffer':
147
+ this.#result = buffer;
148
+ break;
149
+
150
+ case 'binarystring': {
151
+ const bytes = new Uint8Array(buffer);
152
+ let result = '';
153
+ for (let i = 0; i < bytes.length; i++) {
154
+ result += String.fromCharCode(bytes[i]);
155
+ }
156
+ this.#result = result;
157
+ break;
158
+ }
159
+
160
+ case 'text': {
161
+ const decoder = new TextDecoder(encoding || 'utf-8');
162
+ this.#result = decoder.decode(buffer);
163
+ break;
164
+ }
165
+
166
+ case 'dataurl': {
167
+ const bytes = new Uint8Array(buffer);
168
+ let binary = '';
169
+ for (let i = 0; i < bytes.length; i++) {
170
+ binary += String.fromCharCode(bytes[i]);
171
+ }
172
+ const base64 = btoa(binary);
173
+ const mimeType = blob.type || 'application/octet-stream';
174
+ this.#result = `data:${mimeType};base64,${base64}`;
175
+ break;
176
+ }
177
+ }
178
+
179
+ this.#readyState = DONE;
180
+ this.#fireProgressEvent('load', buffer.byteLength, blob.size);
181
+ this.#fireProgressEvent('loadend', buffer.byteLength, blob.size);
182
+
183
+ } catch (err) {
184
+ if (this.#aborted) {
185
+ return;
186
+ }
187
+
188
+ this.#readyState = DONE;
189
+ this.#error = new DOMException(
190
+ err instanceof Error ? err.message : 'Read failed',
191
+ 'NotReadableError'
192
+ );
193
+
194
+ this.#fireProgressEvent('error', 0, blob.size);
195
+ this.#fireProgressEvent('loadend', 0, blob.size);
196
+ }
197
+ }
198
+
199
+ /**
200
+ * Fire a simple event.
201
+ */
202
+ #fireEvent(type: string): void {
203
+ const event = new Event(type);
204
+
205
+ const handler = (this as any)[`on${type}`];
206
+ if (handler) {
207
+ handler.call(this, event);
208
+ }
209
+
210
+ this.dispatchEvent(event);
211
+ }
212
+
213
+ /**
214
+ * Fire a progress event.
215
+ */
216
+ #fireProgressEvent(type: string, loaded: number, total: number): void {
217
+ const event = new ProgressEvent(type, {
218
+ lengthComputable: total > 0,
219
+ loaded,
220
+ total,
221
+ });
222
+
223
+ const handler = (this as any)[`on${type}`];
224
+ if (handler) {
225
+ handler.call(this, event);
226
+ }
227
+
228
+ this.dispatchEvent(event);
229
+ }
230
+
231
+ get [Symbol.toStringTag](): string {
232
+ return 'FileReader';
233
+ }
234
+ }
235
+
236
+ export default FileReader;
@@ -0,0 +1 @@
1
+ export { FileReader } from './FileReader';
@@ -0,0 +1,39 @@
1
+ import { Stats } from './Stats';
2
+
3
+ export class Dirent {
4
+ readonly name: string;
5
+ private readonly stats: Stats;
6
+
7
+ constructor(name: string, stats: Stats) {
8
+ this.name = name;
9
+ this.stats = stats;
10
+ }
11
+
12
+ isFile(): boolean {
13
+ return this.stats.isFile();
14
+ }
15
+
16
+ isDirectory(): boolean {
17
+ return this.stats.isDirectory();
18
+ }
19
+
20
+ isBlockDevice(): boolean {
21
+ return this.stats.isBlockDevice();
22
+ }
23
+
24
+ isCharacterDevice(): boolean {
25
+ return this.stats.isCharacterDevice();
26
+ }
27
+
28
+ isSymbolicLink(): boolean {
29
+ return this.stats.isSymbolicLink();
30
+ }
31
+
32
+ isFIFO(): boolean {
33
+ return this.stats.isFIFO();
34
+ }
35
+
36
+ isSocket(): boolean {
37
+ return this.stats.isSocket();
38
+ }
39
+ }