@secure-exec/browser 0.1.1-rc.2 → 0.2.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/driver.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { createCommandExecutorStub, createFsStub, createNetworkStub } from "@secure-exec/core";
2
- import type { NetworkAdapter, Permissions, SystemDriver, VirtualFileSystem } from "@secure-exec/core";
2
+ import type { Permissions, VirtualFileSystem } from "@secure-exec/core";
3
+ import type { NetworkAdapter, SystemDriver } from "@secure-exec/core";
3
4
  export interface BrowserRuntimeSystemOptions {
4
5
  filesystem: "opfs" | "memory";
5
6
  networkEnabled: boolean;
@@ -23,16 +24,23 @@ export declare class OpfsFileSystem implements VirtualFileSystem {
23
24
  }>>;
24
25
  writeFile(path: string, content: string | Uint8Array): Promise<void>;
25
26
  createDir(path: string): Promise<void>;
26
- mkdir(path: string): Promise<void>;
27
+ mkdir(path: string, _options?: {
28
+ recursive?: boolean;
29
+ }): Promise<void>;
27
30
  exists(path: string): Promise<boolean>;
28
31
  stat(path: string): Promise<{
29
32
  mode: number;
30
33
  size: number;
31
34
  isDirectory: boolean;
35
+ isSymbolicLink: boolean;
32
36
  atimeMs: number;
33
37
  mtimeMs: number;
34
38
  ctimeMs: number;
35
39
  birthtimeMs: number;
40
+ ino: number;
41
+ nlink: number;
42
+ uid: number;
43
+ gid: number;
36
44
  }>;
37
45
  removeFile(path: string): Promise<void>;
38
46
  removeDir(path: string): Promise<void>;
@@ -43,17 +51,23 @@ export declare class OpfsFileSystem implements VirtualFileSystem {
43
51
  mode: number;
44
52
  size: number;
45
53
  isDirectory: boolean;
46
- isSymbolicLink?: boolean;
54
+ isSymbolicLink: boolean;
47
55
  atimeMs: number;
48
56
  mtimeMs: number;
49
57
  ctimeMs: number;
50
58
  birthtimeMs: number;
59
+ ino: number;
60
+ nlink: number;
61
+ uid: number;
62
+ gid: number;
51
63
  }>;
52
64
  link(_oldPath: string, _newPath: string): Promise<void>;
53
65
  chmod(_path: string, _mode: number): Promise<void>;
54
66
  chown(_path: string, _uid: number, _gid: number): Promise<void>;
55
67
  utimes(_path: string, _atime: number, _mtime: number): Promise<void>;
56
68
  truncate(path: string, length: number): Promise<void>;
69
+ realpath(path: string): Promise<string>;
70
+ pread(path: string, offset: number, length: number): Promise<Uint8Array>;
57
71
  }
58
72
  export interface BrowserDriverOptions {
59
73
  filesystem?: "opfs" | "memory";
package/dist/driver.js CHANGED
@@ -103,7 +103,7 @@ export class OpfsFileSystem {
103
103
  await this.getDirHandle(parent, false);
104
104
  await this.getDirHandle(normalized, true);
105
105
  }
106
- async mkdir(path) {
106
+ async mkdir(path, _options) {
107
107
  const parts = splitPath(path);
108
108
  let current = "";
109
109
  for (const part of parts) {
@@ -134,10 +134,15 @@ export class OpfsFileSystem {
134
134
  mode: S_IFREG | 0o644,
135
135
  size: file.size,
136
136
  isDirectory: false,
137
+ isSymbolicLink: false,
137
138
  atimeMs: file.lastModified,
138
139
  mtimeMs: file.lastModified,
139
140
  ctimeMs: file.lastModified,
140
141
  birthtimeMs: file.lastModified,
142
+ ino: 0,
143
+ nlink: 1,
144
+ uid: 0,
145
+ gid: 0,
141
146
  };
142
147
  }
143
148
  catch {
@@ -149,10 +154,15 @@ export class OpfsFileSystem {
149
154
  mode: S_IFDIR | 0o755,
150
155
  size: 4096,
151
156
  isDirectory: true,
157
+ isSymbolicLink: false,
152
158
  atimeMs: now,
153
159
  mtimeMs: now,
154
160
  ctimeMs: now,
155
161
  birthtimeMs: now,
162
+ ino: 0,
163
+ nlink: 2,
164
+ uid: 0,
165
+ gid: 0,
156
166
  };
157
167
  }
158
168
  catch {
@@ -207,6 +217,16 @@ export class OpfsFileSystem {
207
217
  await writable.truncate(length);
208
218
  await writable.close();
209
219
  }
220
+ async realpath(path) {
221
+ const normalized = normalizePath(path);
222
+ if (await this.exists(normalized))
223
+ return normalized;
224
+ throw new Error(`ENOENT: no such file or directory, realpath '${normalized}'`);
225
+ }
226
+ async pread(path, offset, length) {
227
+ const data = await this.readFile(path);
228
+ return data.slice(offset, offset + length);
229
+ }
210
230
  }
211
231
  /** Create an OPFS-backed filesystem, falling back to in-memory if OPFS is unavailable. */
212
232
  export async function createOpfsFileSystem() {
package/dist/index.d.ts CHANGED
@@ -3,3 +3,6 @@ export type { BrowserDriverOptions, BrowserRuntimeSystemOptions, } from "./drive
3
3
  export { createBrowserRuntimeDriverFactory, } from "./runtime-driver.js";
4
4
  export type { BrowserRuntimeDriverFactoryOptions, } from "./runtime-driver.js";
5
5
  export { createInMemoryFileSystem } from "@secure-exec/core";
6
+ export { InMemoryFileSystem } from "./os-filesystem.js";
7
+ export { BrowserWorkerAdapter } from "./worker-adapter.js";
8
+ export type { WorkerHandle } from "./worker-adapter.js";
package/dist/index.js CHANGED
@@ -1,3 +1,5 @@
1
1
  export { createBrowserDriver, createBrowserNetworkAdapter, createOpfsFileSystem, } from "./driver.js";
2
2
  export { createBrowserRuntimeDriverFactory, } from "./runtime-driver.js";
3
3
  export { createInMemoryFileSystem } from "@secure-exec/core";
4
+ export { InMemoryFileSystem } from "./os-filesystem.js";
5
+ export { BrowserWorkerAdapter } from "./worker-adapter.js";
@@ -0,0 +1,47 @@
1
+ /**
2
+ * In-memory filesystem for browser environments.
3
+ *
4
+ * Expanded from the original secure-exec InMemoryFileSystem with POSIX
5
+ * extensions (symlinks, hard links, chmod, chown, utimes, truncate)
6
+ * needed by the kernel VFS interface.
7
+ */
8
+ import type { VirtualFileSystem, VirtualStat, VirtualDirEntry } from "@secure-exec/core";
9
+ export declare class InMemoryFileSystem implements VirtualFileSystem {
10
+ private entries;
11
+ constructor();
12
+ readFile(path: string): Promise<Uint8Array>;
13
+ readTextFile(path: string): Promise<string>;
14
+ readDir(path: string): Promise<string[]>;
15
+ readDirWithTypes(path: string): Promise<VirtualDirEntry[]>;
16
+ writeFile(path: string, content: string | Uint8Array): Promise<void>;
17
+ createDir(path: string): Promise<void>;
18
+ mkdir(path: string, options?: {
19
+ recursive?: boolean;
20
+ }): Promise<void>;
21
+ exists(path: string): Promise<boolean>;
22
+ stat(path: string): Promise<VirtualStat>;
23
+ removeFile(path: string): Promise<void>;
24
+ removeDir(path: string): Promise<void>;
25
+ realpath(path: string): Promise<string>;
26
+ rename(oldPath: string, newPath: string): Promise<void>;
27
+ symlink(target: string, linkPath: string): Promise<void>;
28
+ readlink(path: string): Promise<string>;
29
+ lstat(path: string): Promise<VirtualStat>;
30
+ link(oldPath: string, newPath: string): Promise<void>;
31
+ chmod(path: string, mode: number): Promise<void>;
32
+ chown(path: string, uid: number, gid: number): Promise<void>;
33
+ utimes(path: string, atime: number, mtime: number): Promise<void>;
34
+ truncate(path: string, length: number): Promise<void>;
35
+ pread(path: string, offset: number, length: number): Promise<Uint8Array>;
36
+ /**
37
+ * Resolve symlinks to get the final path. Returns the normalized path
38
+ * after following all symlinks.
39
+ */
40
+ private resolvePath;
41
+ /** Resolve a path and return the entry (following symlinks). */
42
+ private resolveEntry;
43
+ private newDir;
44
+ private toStat;
45
+ private enoent;
46
+ }
47
+ export declare function createInMemoryFileSystem(): InMemoryFileSystem;
@@ -0,0 +1,384 @@
1
+ /**
2
+ * In-memory filesystem for browser environments.
3
+ *
4
+ * Expanded from the original secure-exec InMemoryFileSystem with POSIX
5
+ * extensions (symlinks, hard links, chmod, chown, utimes, truncate)
6
+ * needed by the kernel VFS interface.
7
+ */
8
+ const S_IFREG = 0o100000;
9
+ const S_IFDIR = 0o040000;
10
+ const S_IFLNK = 0o120000;
11
+ const MAX_SYMLINK_DEPTH = 40;
12
+ function normalizePath(path) {
13
+ if (!path)
14
+ return "/";
15
+ let normalized = path.startsWith("/") ? path : `/${path}`;
16
+ normalized = normalized.replace(/\/+/g, "/");
17
+ if (normalized.length > 1 && normalized.endsWith("/")) {
18
+ normalized = normalized.slice(0, -1);
19
+ }
20
+ // Resolve . and ..
21
+ const parts = normalized.split("/");
22
+ const resolved = [];
23
+ for (const part of parts) {
24
+ if (part === "." || part === "")
25
+ continue;
26
+ if (part === "..") {
27
+ resolved.pop();
28
+ }
29
+ else {
30
+ resolved.push(part);
31
+ }
32
+ }
33
+ return "/" + resolved.join("/") || "/";
34
+ }
35
+ function dirname(path) {
36
+ const parts = normalizePath(path).split("/").filter(Boolean);
37
+ if (parts.length <= 1)
38
+ return "/";
39
+ return "/" + parts.slice(0, -1).join("/");
40
+ }
41
+ let nextIno = 1;
42
+ export class InMemoryFileSystem {
43
+ entries = new Map();
44
+ constructor() {
45
+ // Root directory
46
+ this.entries.set("/", this.newDir());
47
+ }
48
+ // --- Core operations ---
49
+ async readFile(path) {
50
+ const entry = this.resolveEntry(path);
51
+ if (!entry || entry.type !== "file") {
52
+ throw this.enoent("open", path);
53
+ }
54
+ entry.atimeMs = Date.now();
55
+ return entry.data;
56
+ }
57
+ async readTextFile(path) {
58
+ const data = await this.readFile(path);
59
+ return new TextDecoder().decode(data);
60
+ }
61
+ async readDir(path) {
62
+ return (await this.readDirWithTypes(path)).map((e) => e.name);
63
+ }
64
+ async readDirWithTypes(path) {
65
+ const resolved = this.resolvePath(path);
66
+ const dir = this.entries.get(resolved);
67
+ if (!dir || dir.type !== "dir") {
68
+ throw this.enoent("scandir", path);
69
+ }
70
+ const prefix = resolved === "/" ? "/" : resolved + "/";
71
+ const names = new Map();
72
+ for (const [entryPath, entry] of this.entries) {
73
+ if (entryPath.startsWith(prefix)) {
74
+ const rest = entryPath.slice(prefix.length);
75
+ if (rest && !rest.includes("/")) {
76
+ names.set(rest, {
77
+ name: rest,
78
+ isDirectory: entry.type === "dir",
79
+ isSymbolicLink: entry.type === "symlink",
80
+ });
81
+ }
82
+ }
83
+ }
84
+ return Array.from(names.values());
85
+ }
86
+ async writeFile(path, content) {
87
+ const normalized = normalizePath(path);
88
+ // Ensure parent exists
89
+ await this.mkdir(dirname(normalized), { recursive: true });
90
+ const data = typeof content === "string"
91
+ ? new TextEncoder().encode(content)
92
+ : content;
93
+ const existing = this.entries.get(normalized);
94
+ if (existing && existing.type === "file") {
95
+ existing.data = data;
96
+ existing.mtimeMs = Date.now();
97
+ existing.ctimeMs = Date.now();
98
+ return;
99
+ }
100
+ const now = Date.now();
101
+ this.entries.set(normalized, {
102
+ type: "file",
103
+ data,
104
+ mode: S_IFREG | 0o644,
105
+ uid: 1000,
106
+ gid: 1000,
107
+ nlink: 1,
108
+ ino: nextIno++,
109
+ atimeMs: now,
110
+ mtimeMs: now,
111
+ ctimeMs: now,
112
+ birthtimeMs: now,
113
+ });
114
+ }
115
+ async createDir(path) {
116
+ const normalized = normalizePath(path);
117
+ const parent = dirname(normalized);
118
+ if (!this.entries.has(parent)) {
119
+ throw this.enoent("mkdir", path);
120
+ }
121
+ if (!this.entries.has(normalized)) {
122
+ this.entries.set(normalized, this.newDir());
123
+ }
124
+ }
125
+ async mkdir(path, options) {
126
+ const normalized = normalizePath(path);
127
+ if (options?.recursive !== false) {
128
+ // Recursive: create all missing parents
129
+ const parts = normalized.split("/").filter(Boolean);
130
+ let current = "";
131
+ for (const part of parts) {
132
+ current += "/" + part;
133
+ if (!this.entries.has(current)) {
134
+ this.entries.set(current, this.newDir());
135
+ }
136
+ }
137
+ }
138
+ else {
139
+ await this.createDir(path);
140
+ }
141
+ }
142
+ async exists(path) {
143
+ try {
144
+ const resolved = this.resolvePath(path);
145
+ return this.entries.has(resolved);
146
+ }
147
+ catch {
148
+ return false;
149
+ }
150
+ }
151
+ async stat(path) {
152
+ const entry = this.resolveEntry(path);
153
+ if (!entry)
154
+ throw this.enoent("stat", path);
155
+ return this.toStat(entry);
156
+ }
157
+ async removeFile(path) {
158
+ const resolved = this.resolvePath(path);
159
+ const entry = this.entries.get(resolved);
160
+ if (!entry || entry.type === "dir") {
161
+ throw this.enoent("unlink", path);
162
+ }
163
+ this.entries.delete(resolved);
164
+ }
165
+ async removeDir(path) {
166
+ const resolved = this.resolvePath(path);
167
+ if (resolved === "/") {
168
+ throw new Error("EPERM: operation not permitted, rmdir '/'");
169
+ }
170
+ const entry = this.entries.get(resolved);
171
+ if (!entry || entry.type !== "dir") {
172
+ throw this.enoent("rmdir", path);
173
+ }
174
+ // Check if empty
175
+ const prefix = resolved + "/";
176
+ for (const key of this.entries.keys()) {
177
+ if (key.startsWith(prefix)) {
178
+ throw new Error(`ENOTEMPTY: directory not empty, rmdir '${path}'`);
179
+ }
180
+ }
181
+ this.entries.delete(resolved);
182
+ }
183
+ async realpath(path) {
184
+ return this.resolvePath(path);
185
+ }
186
+ async rename(oldPath, newPath) {
187
+ const oldResolved = this.resolvePath(oldPath);
188
+ const newNorm = normalizePath(newPath);
189
+ const entry = this.entries.get(oldResolved);
190
+ if (!entry)
191
+ throw this.enoent("rename", oldPath);
192
+ // Ensure parent of target exists
193
+ if (!this.entries.has(dirname(newNorm))) {
194
+ throw this.enoent("rename", newPath);
195
+ }
196
+ if (entry.type !== "dir") {
197
+ this.entries.set(newNorm, entry);
198
+ this.entries.delete(oldResolved);
199
+ return;
200
+ }
201
+ // Move directory and all children
202
+ const prefix = oldResolved + "/";
203
+ const toMove = [];
204
+ for (const [key, val] of this.entries) {
205
+ if (key === oldResolved || key.startsWith(prefix)) {
206
+ toMove.push([key, val]);
207
+ }
208
+ }
209
+ for (const [key] of toMove) {
210
+ this.entries.delete(key);
211
+ }
212
+ for (const [key, val] of toMove) {
213
+ const newKey = key === oldResolved
214
+ ? newNorm
215
+ : newNorm + key.slice(oldResolved.length);
216
+ this.entries.set(newKey, val);
217
+ }
218
+ }
219
+ // --- Symlinks ---
220
+ async symlink(target, linkPath) {
221
+ const normalized = normalizePath(linkPath);
222
+ if (this.entries.has(normalized)) {
223
+ throw new Error(`EEXIST: file already exists, symlink '${linkPath}'`);
224
+ }
225
+ const now = Date.now();
226
+ this.entries.set(normalized, {
227
+ type: "symlink",
228
+ target,
229
+ mode: S_IFLNK | 0o777,
230
+ uid: 1000,
231
+ gid: 1000,
232
+ nlink: 1,
233
+ ino: nextIno++,
234
+ atimeMs: now,
235
+ mtimeMs: now,
236
+ ctimeMs: now,
237
+ birthtimeMs: now,
238
+ });
239
+ }
240
+ async readlink(path) {
241
+ const normalized = normalizePath(path);
242
+ const entry = this.entries.get(normalized);
243
+ if (!entry || entry.type !== "symlink") {
244
+ throw this.enoent("readlink", path);
245
+ }
246
+ return entry.target;
247
+ }
248
+ async lstat(path) {
249
+ const normalized = normalizePath(path);
250
+ const entry = this.entries.get(normalized);
251
+ if (!entry)
252
+ throw this.enoent("lstat", path);
253
+ return this.toStat(entry);
254
+ }
255
+ // --- Links ---
256
+ async link(oldPath, newPath) {
257
+ const entry = this.resolveEntry(oldPath);
258
+ if (!entry || entry.type !== "file") {
259
+ throw this.enoent("link", oldPath);
260
+ }
261
+ const newNorm = normalizePath(newPath);
262
+ if (this.entries.has(newNorm)) {
263
+ throw new Error(`EEXIST: file already exists, link '${newPath}'`);
264
+ }
265
+ entry.nlink++;
266
+ this.entries.set(newNorm, entry);
267
+ }
268
+ // --- Permissions & Metadata ---
269
+ async chmod(path, mode) {
270
+ const entry = this.resolveEntry(path);
271
+ if (!entry)
272
+ throw this.enoent("chmod", path);
273
+ // Preserve file type bits, update permission bits
274
+ entry.mode = (entry.mode & 0o170000) | (mode & 0o7777);
275
+ entry.ctimeMs = Date.now();
276
+ }
277
+ async chown(path, uid, gid) {
278
+ const entry = this.resolveEntry(path);
279
+ if (!entry)
280
+ throw this.enoent("chown", path);
281
+ entry.uid = uid;
282
+ entry.gid = gid;
283
+ entry.ctimeMs = Date.now();
284
+ }
285
+ async utimes(path, atime, mtime) {
286
+ const entry = this.resolveEntry(path);
287
+ if (!entry)
288
+ throw this.enoent("utimes", path);
289
+ entry.atimeMs = atime;
290
+ entry.mtimeMs = mtime;
291
+ entry.ctimeMs = Date.now();
292
+ }
293
+ async truncate(path, length) {
294
+ const entry = this.resolveEntry(path);
295
+ if (!entry || entry.type !== "file") {
296
+ throw this.enoent("truncate", path);
297
+ }
298
+ if (length < entry.data.length) {
299
+ entry.data = entry.data.slice(0, length);
300
+ }
301
+ else if (length > entry.data.length) {
302
+ const newData = new Uint8Array(length);
303
+ newData.set(entry.data);
304
+ entry.data = newData;
305
+ }
306
+ entry.mtimeMs = Date.now();
307
+ entry.ctimeMs = Date.now();
308
+ }
309
+ async pread(path, offset, length) {
310
+ const entry = this.resolveEntry(path);
311
+ if (!entry || entry.type !== "file") {
312
+ throw this.enoent("open", path);
313
+ }
314
+ entry.atimeMs = Date.now();
315
+ if (offset >= entry.data.length)
316
+ return new Uint8Array(0);
317
+ return entry.data.slice(offset, Math.min(offset + length, entry.data.length));
318
+ }
319
+ // --- Helpers ---
320
+ /**
321
+ * Resolve symlinks to get the final path. Returns the normalized path
322
+ * after following all symlinks.
323
+ */
324
+ resolvePath(path, depth = 0) {
325
+ if (depth > MAX_SYMLINK_DEPTH) {
326
+ throw new Error(`ELOOP: too many levels of symbolic links, '${path}'`);
327
+ }
328
+ const normalized = normalizePath(path);
329
+ const entry = this.entries.get(normalized);
330
+ if (!entry)
331
+ return normalized;
332
+ if (entry.type === "symlink") {
333
+ const target = entry.target.startsWith("/")
334
+ ? entry.target
335
+ : dirname(normalized) + "/" + entry.target;
336
+ return this.resolvePath(target, depth + 1);
337
+ }
338
+ return normalized;
339
+ }
340
+ /** Resolve a path and return the entry (following symlinks). */
341
+ resolveEntry(path) {
342
+ const resolved = this.resolvePath(path);
343
+ return this.entries.get(resolved);
344
+ }
345
+ newDir() {
346
+ const now = Date.now();
347
+ return {
348
+ type: "dir",
349
+ mode: S_IFDIR | 0o755,
350
+ uid: 1000,
351
+ gid: 1000,
352
+ nlink: 2,
353
+ ino: nextIno++,
354
+ atimeMs: now,
355
+ mtimeMs: now,
356
+ ctimeMs: now,
357
+ birthtimeMs: now,
358
+ };
359
+ }
360
+ toStat(entry) {
361
+ return {
362
+ mode: entry.mode,
363
+ size: entry.type === "file" ? entry.data.length : 4096,
364
+ isDirectory: entry.type === "dir",
365
+ isSymbolicLink: entry.type === "symlink",
366
+ atimeMs: entry.atimeMs,
367
+ mtimeMs: entry.mtimeMs,
368
+ ctimeMs: entry.ctimeMs,
369
+ birthtimeMs: entry.birthtimeMs,
370
+ ino: entry.ino,
371
+ nlink: entry.nlink,
372
+ uid: entry.uid,
373
+ gid: entry.gid,
374
+ };
375
+ }
376
+ enoent(op, path) {
377
+ const err = new Error(`ENOENT: no such file or directory, ${op} '${path}'`);
378
+ err.code = "ENOENT";
379
+ return err;
380
+ }
381
+ }
382
+ export function createInMemoryFileSystem() {
383
+ return new InMemoryFileSystem();
384
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Browser worker adapter.
3
+ *
4
+ * Wraps the Web Worker API for spawning Workers.
5
+ * Requires COOP/COEP headers for SharedArrayBuffer support.
6
+ */
7
+ export interface WorkerHandle {
8
+ postMessage(data: unknown, transferList?: Transferable[]): void;
9
+ onMessage(handler: (data: unknown) => void): void;
10
+ onError(handler: (err: Error) => void): void;
11
+ onExit(handler: (code: number) => void): void;
12
+ terminate(): void;
13
+ }
14
+ export declare class BrowserWorkerAdapter {
15
+ /**
16
+ * Spawn a Web Worker for the given script URL.
17
+ */
18
+ static create(scriptUrl: string | URL, options?: {
19
+ workerData?: unknown;
20
+ }): WorkerHandle;
21
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Browser worker adapter.
3
+ *
4
+ * Wraps the Web Worker API for spawning Workers.
5
+ * Requires COOP/COEP headers for SharedArrayBuffer support.
6
+ */
7
+ export class BrowserWorkerAdapter {
8
+ /**
9
+ * Spawn a Web Worker for the given script URL.
10
+ */
11
+ static create(scriptUrl, options) {
12
+ const worker = new Worker(scriptUrl, { type: "module" });
13
+ // Send workerData as the initial message (Web Workers don't have
14
+ // a constructor option for this like Node's worker_threads)
15
+ if (options?.workerData !== undefined) {
16
+ worker.postMessage({
17
+ type: "init",
18
+ workerData: options.workerData,
19
+ });
20
+ }
21
+ return {
22
+ postMessage(data, transferList) {
23
+ worker.postMessage(data, transferList ?? []);
24
+ },
25
+ onMessage(handler) {
26
+ worker.addEventListener("message", (e) => handler(e.data));
27
+ },
28
+ onError(handler) {
29
+ worker.addEventListener("error", (e) => handler(new Error(e.message)));
30
+ },
31
+ onExit(_handler) {
32
+ // Web Workers don't have an exit event — the terminate()
33
+ // caller is responsible for cleanup
34
+ },
35
+ terminate() {
36
+ worker.terminate();
37
+ },
38
+ };
39
+ }
40
+ }
package/dist/worker.js CHANGED
@@ -75,7 +75,7 @@ function revivePermissions(serialized) {
75
75
  }
76
76
  /**
77
77
  * Wrap a sync function in the bridge calling convention (`applySync`) so
78
- * bridge code can call it the same way it calls isolated-vm References.
78
+ * bridge code can call it the same way it calls bridge References.
79
79
  */
80
80
  function makeApplySync(fn) {
81
81
  const applySync = (_ctx, args) => fn(...args);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@secure-exec/browser",
3
- "version": "0.1.1-rc.2",
3
+ "version": "0.2.0-rc.1",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "main": "./dist/index.js",
@@ -39,11 +39,21 @@
39
39
  "types": "./dist/permission-validation.d.ts",
40
40
  "import": "./dist/permission-validation.js",
41
41
  "default": "./dist/permission-validation.js"
42
+ },
43
+ "./internal/os-filesystem": {
44
+ "types": "./dist/os-filesystem.d.ts",
45
+ "import": "./dist/os-filesystem.js",
46
+ "default": "./dist/os-filesystem.js"
47
+ },
48
+ "./internal/worker-adapter": {
49
+ "types": "./dist/worker-adapter.d.ts",
50
+ "import": "./dist/worker-adapter.js",
51
+ "default": "./dist/worker-adapter.js"
42
52
  }
43
53
  },
44
54
  "dependencies": {
45
55
  "sucrase": "^3.35.0",
46
- "@secure-exec/core": "0.1.1-rc.2"
56
+ "@secure-exec/core": "0.2.0-rc.1"
47
57
  },
48
58
  "devDependencies": {
49
59
  "@types/node": "^22.10.2",