@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,450 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* ExactFile - Bun.file() compatible lazy file handle.
|
|
4
|
+
*
|
|
5
|
+
* Like Bun.file(), this returns a lazy reference to a file on disk.
|
|
6
|
+
* Nothing is read until you call .text(), .json(), .arrayBuffer(), .bytes(), etc.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* const f = Exact.file("package.json");
|
|
10
|
+
* const text = await f.text();
|
|
11
|
+
* const data = await f.json();
|
|
12
|
+
* const exists = await f.exists();
|
|
13
|
+
* console.log(f.name, f.size, f.type);
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
declare const __exactReadFile: (path: string) => Uint8Array;
|
|
17
|
+
declare const __exactWriteFile: (path: string, data: Uint8Array) => void;
|
|
18
|
+
declare const __exactStat: (path: string) => string;
|
|
19
|
+
declare const __exactAccess: (path: string, mode: number) => void;
|
|
20
|
+
declare const __exactEnsureFs: (() => void) | undefined;
|
|
21
|
+
|
|
22
|
+
// Common extension → MIME type map
|
|
23
|
+
const MIME_TYPES: Record<string, string> = {
|
|
24
|
+
'.txt': 'text/plain;charset=utf-8',
|
|
25
|
+
'.html': 'text/html;charset=utf-8',
|
|
26
|
+
'.htm': 'text/html;charset=utf-8',
|
|
27
|
+
'.css': 'text/css;charset=utf-8',
|
|
28
|
+
'.js': 'text/javascript;charset=utf-8',
|
|
29
|
+
'.mjs': 'text/javascript;charset=utf-8',
|
|
30
|
+
'.cjs': 'text/javascript;charset=utf-8',
|
|
31
|
+
'.ts': 'text/typescript;charset=utf-8',
|
|
32
|
+
'.tsx': 'text/typescript;charset=utf-8',
|
|
33
|
+
'.jsx': 'text/javascript;charset=utf-8',
|
|
34
|
+
'.json': 'application/json;charset=utf-8',
|
|
35
|
+
'.jsonl': 'application/x-ndjson;charset=utf-8',
|
|
36
|
+
'.xml': 'application/xml;charset=utf-8',
|
|
37
|
+
'.svg': 'image/svg+xml;charset=utf-8',
|
|
38
|
+
'.png': 'image/png',
|
|
39
|
+
'.jpg': 'image/jpeg',
|
|
40
|
+
'.jpeg': 'image/jpeg',
|
|
41
|
+
'.gif': 'image/gif',
|
|
42
|
+
'.webp': 'image/webp',
|
|
43
|
+
'.avif': 'image/avif',
|
|
44
|
+
'.ico': 'image/x-icon',
|
|
45
|
+
'.bmp': 'image/bmp',
|
|
46
|
+
'.tiff': 'image/tiff',
|
|
47
|
+
'.tif': 'image/tiff',
|
|
48
|
+
'.pdf': 'application/pdf',
|
|
49
|
+
'.zip': 'application/zip',
|
|
50
|
+
'.gz': 'application/gzip',
|
|
51
|
+
'.tar': 'application/x-tar',
|
|
52
|
+
'.wasm': 'application/wasm',
|
|
53
|
+
'.mp3': 'audio/mpeg',
|
|
54
|
+
'.mp4': 'video/mp4',
|
|
55
|
+
'.webm': 'video/webm',
|
|
56
|
+
'.ogg': 'audio/ogg',
|
|
57
|
+
'.wav': 'audio/wav',
|
|
58
|
+
'.woff': 'font/woff',
|
|
59
|
+
'.woff2': 'font/woff2',
|
|
60
|
+
'.ttf': 'font/ttf',
|
|
61
|
+
'.otf': 'font/otf',
|
|
62
|
+
'.md': 'text/markdown;charset=utf-8',
|
|
63
|
+
'.yaml': 'text/yaml;charset=utf-8',
|
|
64
|
+
'.yml': 'text/yaml;charset=utf-8',
|
|
65
|
+
'.toml': 'text/toml;charset=utf-8',
|
|
66
|
+
'.csv': 'text/csv;charset=utf-8',
|
|
67
|
+
'.sh': 'application/x-sh',
|
|
68
|
+
'.sql': 'application/sql',
|
|
69
|
+
'.wgsl': 'text/wgsl;charset=utf-8',
|
|
70
|
+
'.glsl': 'text/plain;charset=utf-8',
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
function getMimeType(path: string): string {
|
|
74
|
+
const dot = path.lastIndexOf('.');
|
|
75
|
+
if (dot === -1) return 'application/octet-stream';
|
|
76
|
+
const ext = path.slice(dot).toLowerCase();
|
|
77
|
+
return MIME_TYPES[ext] || 'application/octet-stream';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function decodeBytes(bytes: Uint8Array): string {
|
|
81
|
+
if (typeof TextDecoder !== 'undefined') {
|
|
82
|
+
const decoded = new TextDecoder('utf-8').decode(bytes);
|
|
83
|
+
if (
|
|
84
|
+
bytes.length >= 3 &&
|
|
85
|
+
bytes[0] === 0xef &&
|
|
86
|
+
bytes[1] === 0xbb &&
|
|
87
|
+
bytes[2] === 0xbf &&
|
|
88
|
+
decoded.charCodeAt(0) !== 0xfeff
|
|
89
|
+
) {
|
|
90
|
+
return `\uFEFF${decoded}`;
|
|
91
|
+
}
|
|
92
|
+
return decoded;
|
|
93
|
+
}
|
|
94
|
+
let result = '';
|
|
95
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
96
|
+
result += String.fromCharCode(bytes[i]);
|
|
97
|
+
}
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function toUint8Array(data: string | Uint8Array | ArrayBuffer | ArrayBufferView): Uint8Array {
|
|
102
|
+
if (typeof data === 'string') {
|
|
103
|
+
if (typeof TextEncoder !== 'undefined') {
|
|
104
|
+
return new TextEncoder().encode(data);
|
|
105
|
+
}
|
|
106
|
+
const buf = new Uint8Array(data.length * 3);
|
|
107
|
+
let offset = 0;
|
|
108
|
+
for (let i = 0; i < data.length; i++) {
|
|
109
|
+
const code = data.charCodeAt(i);
|
|
110
|
+
if (code < 0x80) {
|
|
111
|
+
buf[offset++] = code;
|
|
112
|
+
} else if (code < 0x800) {
|
|
113
|
+
buf[offset++] = 0xc0 | (code >> 6);
|
|
114
|
+
buf[offset++] = 0x80 | (code & 0x3f);
|
|
115
|
+
} else {
|
|
116
|
+
buf[offset++] = 0xe0 | (code >> 12);
|
|
117
|
+
buf[offset++] = 0x80 | ((code >> 6) & 0x3f);
|
|
118
|
+
buf[offset++] = 0x80 | (code & 0x3f);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return buf.slice(0, offset);
|
|
122
|
+
}
|
|
123
|
+
if (data instanceof Uint8Array) return data;
|
|
124
|
+
if (data instanceof ArrayBuffer) return new Uint8Array(data);
|
|
125
|
+
if (ArrayBuffer.isView(data)) return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
126
|
+
return new Uint8Array(data as any);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
let _exactFsInitialized = false;
|
|
130
|
+
|
|
131
|
+
function ensureExactFs(): void {
|
|
132
|
+
if (_exactFsInitialized) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const g = globalThis as any;
|
|
137
|
+
const hasFsPrimitives =
|
|
138
|
+
typeof g.__exactReadFile === 'function' &&
|
|
139
|
+
typeof g.__exactWriteFile === 'function' &&
|
|
140
|
+
typeof g.__exactStat === 'function' &&
|
|
141
|
+
typeof g.__exactAccess === 'function';
|
|
142
|
+
|
|
143
|
+
if (!hasFsPrimitives && typeof g.__exactEnsureFs === 'function') {
|
|
144
|
+
g.__exactEnsureFs();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
_exactFsInitialized =
|
|
148
|
+
typeof g.__exactReadFile === 'function' ||
|
|
149
|
+
typeof g.__exactWriteFile === 'function' ||
|
|
150
|
+
typeof g.__exactStat === 'function' ||
|
|
151
|
+
typeof g.__exactAccess === 'function';
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface ExactFileOptions {
|
|
155
|
+
type?: string;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
type ExactFilePathLike =
|
|
159
|
+
| string
|
|
160
|
+
| {
|
|
161
|
+
pathname?: string;
|
|
162
|
+
href?: string;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
function normalizeExactFilePath(path: ExactFilePathLike): string {
|
|
166
|
+
if (typeof path === 'string') {
|
|
167
|
+
return path;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (path && typeof path === 'object') {
|
|
171
|
+
if (typeof path.pathname === 'string' && path.pathname) {
|
|
172
|
+
return decodeURIComponent(path.pathname);
|
|
173
|
+
}
|
|
174
|
+
if (typeof path.href === 'string' && path.href.startsWith('file:')) {
|
|
175
|
+
return decodeURIComponent(path.href.replace(/^file:\/\//, ''));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return String(path);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Lazy file reference compatible with Bun.file().
|
|
184
|
+
*
|
|
185
|
+
* Properties:
|
|
186
|
+
* - name: string (the file path)
|
|
187
|
+
* - size: number (file size in bytes, 0 if not found)
|
|
188
|
+
* - type: string (MIME type inferred from extension)
|
|
189
|
+
* - lastModified: number (mtime in ms since epoch)
|
|
190
|
+
*
|
|
191
|
+
* Methods:
|
|
192
|
+
* - text(): Promise<string>
|
|
193
|
+
* - json(): Promise<any>
|
|
194
|
+
* - arrayBuffer(): Promise<ArrayBuffer>
|
|
195
|
+
* - bytes(): Promise<Uint8Array>
|
|
196
|
+
* - slice(begin?, end?): Blob
|
|
197
|
+
* - exists(): Promise<boolean>
|
|
198
|
+
* - stat(): Promise<{size, mtime_ms, ...} | null>
|
|
199
|
+
*/
|
|
200
|
+
export class ExactFile {
|
|
201
|
+
readonly name: string;
|
|
202
|
+
readonly type: string;
|
|
203
|
+
|
|
204
|
+
constructor(path: ExactFilePathLike, options?: ExactFileOptions) {
|
|
205
|
+
const normalizedPath = normalizeExactFilePath(path);
|
|
206
|
+
this.name = normalizedPath;
|
|
207
|
+
this.type = options?.type || getMimeType(normalizedPath);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
get size(): number {
|
|
211
|
+
ensureExactFs();
|
|
212
|
+
try {
|
|
213
|
+
const json = __exactStat(this.name);
|
|
214
|
+
const info = JSON.parse(json);
|
|
215
|
+
return info.size;
|
|
216
|
+
} catch {
|
|
217
|
+
return 0;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
get lastModified(): number {
|
|
222
|
+
ensureExactFs();
|
|
223
|
+
try {
|
|
224
|
+
const json = __exactStat(this.name);
|
|
225
|
+
const info = JSON.parse(json);
|
|
226
|
+
return info.mtime_ms;
|
|
227
|
+
} catch {
|
|
228
|
+
return 0;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async text(): Promise<string> {
|
|
233
|
+
ensureExactFs();
|
|
234
|
+
const bytes = __exactReadFile(this.name);
|
|
235
|
+
return decodeBytes(bytes);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
async json(): Promise<any> {
|
|
239
|
+
const text = await this.text();
|
|
240
|
+
return JSON.parse(text);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async arrayBuffer(): Promise<ArrayBuffer> {
|
|
244
|
+
ensureExactFs();
|
|
245
|
+
const bytes = __exactReadFile(this.name);
|
|
246
|
+
return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async bytes(): Promise<Uint8Array> {
|
|
250
|
+
ensureExactFs();
|
|
251
|
+
return __exactReadFile(this.name);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
_getBytes(): Uint8Array {
|
|
255
|
+
ensureExactFs();
|
|
256
|
+
return __exactReadFile(this.name);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
async exists(): Promise<boolean> {
|
|
260
|
+
ensureExactFs();
|
|
261
|
+
try {
|
|
262
|
+
__exactAccess(this.name, 0);
|
|
263
|
+
return true;
|
|
264
|
+
} catch {
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
async stat(): Promise<{
|
|
270
|
+
size: number;
|
|
271
|
+
mtime_ms: number;
|
|
272
|
+
is_dir: boolean;
|
|
273
|
+
is_file: boolean;
|
|
274
|
+
mode: number;
|
|
275
|
+
} | null> {
|
|
276
|
+
ensureExactFs();
|
|
277
|
+
try {
|
|
278
|
+
const json = __exactStat(this.name);
|
|
279
|
+
return JSON.parse(json);
|
|
280
|
+
} catch {
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
slice(begin?: number, end?: number, contentType?: string): Blob {
|
|
286
|
+
ensureExactFs();
|
|
287
|
+
const bytes = __exactReadFile(this.name);
|
|
288
|
+
const sliced = bytes.slice(begin ?? 0, end ?? bytes.length);
|
|
289
|
+
return new Blob([sliced], { type: contentType || this.type });
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// stream() returns a ReadableStream if available
|
|
293
|
+
stream(): ReadableStream<Uint8Array> {
|
|
294
|
+
ensureExactFs();
|
|
295
|
+
const name = this.name;
|
|
296
|
+
return new ReadableStream<Uint8Array>({
|
|
297
|
+
start(controller) {
|
|
298
|
+
try {
|
|
299
|
+
const bytes = __exactReadFile(name);
|
|
300
|
+
controller.enqueue(bytes);
|
|
301
|
+
controller.close();
|
|
302
|
+
} catch (err) {
|
|
303
|
+
controller.error(err);
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// writer() returns a simple FileSink-like object
|
|
310
|
+
writer(): { write(data: string | Uint8Array | ArrayBuffer): number; end(): void; flush(): void } {
|
|
311
|
+
const name = this.name;
|
|
312
|
+
let started = false;
|
|
313
|
+
return {
|
|
314
|
+
write(data: string | Uint8Array | ArrayBuffer): number {
|
|
315
|
+
ensureExactFs();
|
|
316
|
+
const bytes = toUint8Array(data);
|
|
317
|
+
if (!started) {
|
|
318
|
+
__exactWriteFile(name, bytes);
|
|
319
|
+
started = true;
|
|
320
|
+
} else {
|
|
321
|
+
// Append after first write
|
|
322
|
+
const g = globalThis as any;
|
|
323
|
+
if (typeof g.__exactAppendFile === 'function') {
|
|
324
|
+
g.__exactAppendFile(name, bytes);
|
|
325
|
+
} else {
|
|
326
|
+
// Fallback: read + concat + write
|
|
327
|
+
const existing = __exactReadFile(name);
|
|
328
|
+
const combined = new Uint8Array(existing.length + bytes.length);
|
|
329
|
+
combined.set(existing);
|
|
330
|
+
combined.set(bytes, existing.length);
|
|
331
|
+
__exactWriteFile(name, combined);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return bytes.length;
|
|
335
|
+
},
|
|
336
|
+
end() { /* no-op, writes are synchronous */ },
|
|
337
|
+
flush() { /* no-op, writes are synchronous */ },
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
toString(): string {
|
|
342
|
+
return `ExactFile("${this.name}")`;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Make it work with JSON.stringify
|
|
346
|
+
toJSON(): { name: string; type: string; size: number; lastModified: number } {
|
|
347
|
+
return {
|
|
348
|
+
name: this.name,
|
|
349
|
+
type: this.type,
|
|
350
|
+
size: this.size,
|
|
351
|
+
lastModified: this.lastModified,
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Exact.write(dest, data) - Write data to a file.
|
|
358
|
+
* Compatible with Bun.write().
|
|
359
|
+
*
|
|
360
|
+
* @param dest - File path or ExactFile object
|
|
361
|
+
* @param data - String, Uint8Array, ArrayBuffer, Blob, or Response
|
|
362
|
+
* @returns Promise<number> - bytes written
|
|
363
|
+
*/
|
|
364
|
+
export async function exactWrite(
|
|
365
|
+
dest: string | ExactFile,
|
|
366
|
+
data: string | Uint8Array | ArrayBuffer | ArrayBufferView | Blob | Response,
|
|
367
|
+
): Promise<number> {
|
|
368
|
+
ensureExactFs();
|
|
369
|
+
const path = typeof dest === 'string' ? dest : dest.name;
|
|
370
|
+
|
|
371
|
+
let bytes: Uint8Array;
|
|
372
|
+
|
|
373
|
+
if (typeof data === 'string') {
|
|
374
|
+
bytes = toUint8Array(data);
|
|
375
|
+
} else if (data instanceof Uint8Array) {
|
|
376
|
+
bytes = data;
|
|
377
|
+
} else if (data instanceof ArrayBuffer) {
|
|
378
|
+
bytes = new Uint8Array(data);
|
|
379
|
+
} else if (ArrayBuffer.isView(data)) {
|
|
380
|
+
bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
381
|
+
} else if (typeof Blob !== 'undefined' && data instanceof Blob) {
|
|
382
|
+
const ab = await data.arrayBuffer();
|
|
383
|
+
bytes = new Uint8Array(ab);
|
|
384
|
+
} else if (typeof Response !== 'undefined' && data instanceof Response) {
|
|
385
|
+
const ab = await data.arrayBuffer();
|
|
386
|
+
bytes = new Uint8Array(ab);
|
|
387
|
+
} else {
|
|
388
|
+
bytes = toUint8Array(String(data));
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
__exactWriteFile(path, bytes);
|
|
392
|
+
return bytes.length;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function defineGlobalValue(target: any, key: string, value: unknown): void {
|
|
396
|
+
Object.defineProperty(target, key, {
|
|
397
|
+
value,
|
|
398
|
+
configurable: true,
|
|
399
|
+
enumerable: true,
|
|
400
|
+
writable: true,
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
export interface ExactGlobalInstallResult {
|
|
405
|
+
file: (path: ExactFilePathLike, options?: ExactFileOptions) => ExactFile;
|
|
406
|
+
write: typeof exactWrite;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Install Exact and Bun globals with file() and write() methods.
|
|
411
|
+
*/
|
|
412
|
+
export function installExactGlobal(): ExactGlobalInstallResult {
|
|
413
|
+
const g = globalThis as any;
|
|
414
|
+
|
|
415
|
+
// Create or extend Exact object
|
|
416
|
+
if (!g.Exact) {
|
|
417
|
+
g.Exact = {};
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const file = (path: ExactFilePathLike, options?: ExactFileOptions) => new ExactFile(path, options);
|
|
421
|
+
const write = exactWrite;
|
|
422
|
+
|
|
423
|
+
defineGlobalValue(g.Exact, 'file', file);
|
|
424
|
+
defineGlobalValue(g.Exact, 'write', write);
|
|
425
|
+
|
|
426
|
+
// Version info
|
|
427
|
+
if (!g.Exact.version) g.Exact.version = '0.1.0';
|
|
428
|
+
if (!g.Exact.platform) g.Exact.platform = 'cli';
|
|
429
|
+
|
|
430
|
+
// Alias Bun to Exact (Bun may be read-only in Bun's own test runner)
|
|
431
|
+
try {
|
|
432
|
+
if (!g.Bun) {
|
|
433
|
+
g.Bun = g.Exact;
|
|
434
|
+
} else {
|
|
435
|
+
// Augment existing Bun object with Exact.file and Exact.write
|
|
436
|
+
const bunFileDescriptor = Object.getOwnPropertyDescriptor(g.Bun, 'file');
|
|
437
|
+
if (!bunFileDescriptor || bunFileDescriptor.get || bunFileDescriptor.value == null) {
|
|
438
|
+
defineGlobalValue(g.Bun, 'file', file);
|
|
439
|
+
}
|
|
440
|
+
const bunWriteDescriptor = Object.getOwnPropertyDescriptor(g.Bun, 'write');
|
|
441
|
+
if (!bunWriteDescriptor || bunWriteDescriptor.get || bunWriteDescriptor.value == null) {
|
|
442
|
+
defineGlobalValue(g.Bun, 'write', write);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
} catch (_e) {
|
|
446
|
+
// Bun is read-only (e.g. in Bun's native test runner) — skip aliasing
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
return { file, write };
|
|
450
|
+
}
|
package/src/fs/Stats.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js-compatible Stats class.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export class Stats {
|
|
6
|
+
dev: number = 0;
|
|
7
|
+
ino: number = 0;
|
|
8
|
+
mode: number;
|
|
9
|
+
nlink: number = 1;
|
|
10
|
+
uid: number = 0;
|
|
11
|
+
gid: number = 0;
|
|
12
|
+
rdev: number = 0;
|
|
13
|
+
size: number;
|
|
14
|
+
blksize: number = 4096;
|
|
15
|
+
blocks: number;
|
|
16
|
+
atimeMs: number;
|
|
17
|
+
mtimeMs: number;
|
|
18
|
+
ctimeMs: number;
|
|
19
|
+
birthtimeMs: number;
|
|
20
|
+
atime: Date;
|
|
21
|
+
mtime: Date;
|
|
22
|
+
ctime: Date;
|
|
23
|
+
birthtime: Date;
|
|
24
|
+
|
|
25
|
+
private _isFile: boolean;
|
|
26
|
+
private _isDirectory: boolean;
|
|
27
|
+
private _isSymlink: boolean;
|
|
28
|
+
|
|
29
|
+
constructor(raw: {
|
|
30
|
+
size: number;
|
|
31
|
+
mtime_ms: number;
|
|
32
|
+
is_dir: boolean;
|
|
33
|
+
is_file: boolean;
|
|
34
|
+
is_symlink?: boolean;
|
|
35
|
+
mode: number;
|
|
36
|
+
}) {
|
|
37
|
+
this.size = raw.size;
|
|
38
|
+
this.mode = raw.mode;
|
|
39
|
+
this.blocks = Math.ceil(raw.size / 512);
|
|
40
|
+
this.mtimeMs = raw.mtime_ms;
|
|
41
|
+
this.atimeMs = raw.mtime_ms;
|
|
42
|
+
this.ctimeMs = raw.mtime_ms;
|
|
43
|
+
this.birthtimeMs = raw.mtime_ms;
|
|
44
|
+
this.mtime = new Date(raw.mtime_ms);
|
|
45
|
+
this.atime = new Date(raw.mtime_ms);
|
|
46
|
+
this.ctime = new Date(raw.mtime_ms);
|
|
47
|
+
this.birthtime = new Date(raw.mtime_ms);
|
|
48
|
+
this._isFile = raw.is_file;
|
|
49
|
+
this._isDirectory = raw.is_dir;
|
|
50
|
+
this._isSymlink = raw.is_symlink ?? false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
isFile(): boolean {
|
|
54
|
+
return this._isFile;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
isDirectory(): boolean {
|
|
58
|
+
return this._isDirectory;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
isBlockDevice(): boolean {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
isCharacterDevice(): boolean {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
isSymbolicLink(): boolean {
|
|
70
|
+
return this._isSymlink;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
isFIFO(): boolean {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
isSocket(): boolean {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
}
|