sandlot 0.1.2 → 0.1.3
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/README.md +138 -408
- package/dist/build-emitter.d.ts +31 -13
- package/dist/build-emitter.d.ts.map +1 -1
- package/dist/builder.d.ts +370 -0
- package/dist/builder.d.ts.map +1 -0
- package/dist/bundler.d.ts +1 -1
- package/dist/bundler.d.ts.map +1 -1
- package/dist/commands/compile.d.ts +13 -0
- package/dist/commands/compile.d.ts.map +1 -0
- package/dist/commands/index.d.ts +17 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/packages.d.ts +17 -0
- package/dist/commands/packages.d.ts.map +1 -0
- package/dist/commands/run.d.ts +40 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/types.d.ts +141 -0
- package/dist/commands/types.d.ts.map +1 -0
- package/dist/fs.d.ts +53 -49
- package/dist/fs.d.ts.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +249 -427
- package/dist/internal.js +111 -87
- package/dist/runner.d.ts +314 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/sandbox-manager.d.ts +45 -21
- package/dist/sandbox-manager.d.ts.map +1 -1
- package/dist/sandbox.d.ts +144 -62
- package/dist/sandbox.d.ts.map +1 -1
- package/dist/shared-modules.d.ts +22 -3
- package/dist/shared-modules.d.ts.map +1 -1
- package/dist/shared-resources.d.ts +0 -3
- package/dist/shared-resources.d.ts.map +1 -1
- package/dist/typechecker.d.ts +1 -1
- package/package.json +2 -11
- package/src/build-emitter.ts +32 -29
- package/src/builder.ts +498 -0
- package/src/bundler.ts +24 -36
- package/src/commands/compile.ts +236 -0
- package/src/commands/index.ts +51 -0
- package/src/commands/packages.ts +154 -0
- package/src/commands/run.ts +245 -0
- package/src/commands/types.ts +172 -0
- package/src/fs.ts +82 -221
- package/src/index.ts +17 -12
- package/src/sandbox.ts +217 -149
- package/src/shared-modules.ts +74 -4
- package/src/shared-resources.ts +0 -3
- package/src/typechecker.ts +1 -1
- package/dist/react.d.ts +0 -159
- package/dist/react.d.ts.map +0 -1
- package/dist/react.js +0 -149
- package/src/commands.ts +0 -733
- package/src/sandbox-manager.ts +0 -409
package/dist/index.js
CHANGED
|
@@ -7,47 +7,14 @@ var DEFAULT_DIR_MODE = 493;
|
|
|
7
7
|
var DEFAULT_SYMLINK_MODE = 511;
|
|
8
8
|
var DEFAULT_MAX_SIZE_BYTES = 50 * 1024 * 1024;
|
|
9
9
|
|
|
10
|
-
class
|
|
10
|
+
class Filesystem {
|
|
11
11
|
entries;
|
|
12
|
-
db = null;
|
|
13
|
-
dbName;
|
|
14
12
|
maxSizeBytes;
|
|
15
|
-
|
|
16
|
-
constructor(entries, db, dbName, maxSizeBytes) {
|
|
13
|
+
constructor(entries, maxSizeBytes) {
|
|
17
14
|
this.entries = entries;
|
|
18
|
-
this.db = db;
|
|
19
|
-
this.dbName = dbName;
|
|
20
15
|
this.maxSizeBytes = maxSizeBytes;
|
|
21
16
|
}
|
|
22
|
-
static
|
|
23
|
-
const dbName = options.dbName ?? "sandlot-fs";
|
|
24
|
-
const maxSizeBytes = options.maxSizeBytes ?? DEFAULT_MAX_SIZE_BYTES;
|
|
25
|
-
const db = await IndexedDbFs.openDatabase(dbName);
|
|
26
|
-
const entries = await IndexedDbFs.loadEntries(db);
|
|
27
|
-
if (entries.size === 0) {
|
|
28
|
-
entries.set("/", {
|
|
29
|
-
type: "directory",
|
|
30
|
-
mode: DEFAULT_DIR_MODE,
|
|
31
|
-
mtime: new Date
|
|
32
|
-
});
|
|
33
|
-
if (options.initialFiles) {
|
|
34
|
-
for (const [path, value] of Object.entries(options.initialFiles)) {
|
|
35
|
-
const normalizedPath = IndexedDbFs.normalizePath(path);
|
|
36
|
-
const init = IndexedDbFs.parseFileInit(value);
|
|
37
|
-
IndexedDbFs.ensureParentDirs(entries, normalizedPath);
|
|
38
|
-
entries.set(normalizedPath, {
|
|
39
|
-
type: "file",
|
|
40
|
-
content: init.content,
|
|
41
|
-
mode: init.mode ?? DEFAULT_FILE_MODE,
|
|
42
|
-
mtime: init.mtime ?? new Date
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
const fs = new IndexedDbFs(entries, db, dbName, maxSizeBytes);
|
|
48
|
-
return fs;
|
|
49
|
-
}
|
|
50
|
-
static createInMemory(options = {}) {
|
|
17
|
+
static create(options = {}) {
|
|
51
18
|
const maxSizeBytes = options.maxSizeBytes ?? DEFAULT_MAX_SIZE_BYTES;
|
|
52
19
|
const entries = new Map;
|
|
53
20
|
entries.set("/", {
|
|
@@ -57,9 +24,9 @@ class IndexedDbFs {
|
|
|
57
24
|
});
|
|
58
25
|
if (options.initialFiles) {
|
|
59
26
|
for (const [path, value] of Object.entries(options.initialFiles)) {
|
|
60
|
-
const normalizedPath =
|
|
61
|
-
const init =
|
|
62
|
-
|
|
27
|
+
const normalizedPath = Filesystem.normalizePath(path);
|
|
28
|
+
const init = Filesystem.parseFileInit(value);
|
|
29
|
+
Filesystem.ensureParentDirs(entries, normalizedPath);
|
|
63
30
|
entries.set(normalizedPath, {
|
|
64
31
|
type: "file",
|
|
65
32
|
content: init.content,
|
|
@@ -68,31 +35,21 @@ class IndexedDbFs {
|
|
|
68
35
|
});
|
|
69
36
|
}
|
|
70
37
|
}
|
|
71
|
-
return new
|
|
38
|
+
return new Filesystem(entries, maxSizeBytes);
|
|
72
39
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
const tx = this.db.transaction("entries", "readwrite");
|
|
78
|
-
const store = tx.objectStore("entries");
|
|
79
|
-
await this.promisifyRequest(store.clear());
|
|
40
|
+
getFiles() {
|
|
41
|
+
const files = {};
|
|
80
42
|
for (const [path, entry] of this.entries) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return;
|
|
43
|
+
if (entry.type === "file") {
|
|
44
|
+
if (typeof entry.content === "string") {
|
|
45
|
+
files[path] = entry.content;
|
|
46
|
+
} else {
|
|
47
|
+
const base64 = this.encodeBase64(entry.content);
|
|
48
|
+
files[path] = `data:application/octet-stream;base64,${base64}`;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
90
51
|
}
|
|
91
|
-
|
|
92
|
-
this.dirty = false;
|
|
93
|
-
}
|
|
94
|
-
isDirty() {
|
|
95
|
-
return this.dirty;
|
|
52
|
+
return files;
|
|
96
53
|
}
|
|
97
54
|
getSize() {
|
|
98
55
|
let size = 0;
|
|
@@ -108,12 +65,6 @@ class IndexedDbFs {
|
|
|
108
65
|
}
|
|
109
66
|
return size;
|
|
110
67
|
}
|
|
111
|
-
close() {
|
|
112
|
-
if (this.db) {
|
|
113
|
-
this.db.close();
|
|
114
|
-
this.db = null;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
68
|
async readFile(path, options) {
|
|
118
69
|
const normalizedPath = this.normalizePath(path);
|
|
119
70
|
const entry = this.resolveSymlinks(normalizedPath);
|
|
@@ -159,7 +110,6 @@ class IndexedDbFs {
|
|
|
159
110
|
mode: existing?.mode ?? DEFAULT_FILE_MODE,
|
|
160
111
|
mtime: new Date
|
|
161
112
|
});
|
|
162
|
-
this.dirty = true;
|
|
163
113
|
}
|
|
164
114
|
async appendFile(path, content, options) {
|
|
165
115
|
const normalizedPath = this.normalizePath(path);
|
|
@@ -211,7 +161,6 @@ class IndexedDbFs {
|
|
|
211
161
|
mode: DEFAULT_DIR_MODE,
|
|
212
162
|
mtime: new Date
|
|
213
163
|
});
|
|
214
|
-
this.dirty = true;
|
|
215
164
|
}
|
|
216
165
|
async readdir(path) {
|
|
217
166
|
const normalizedPath = this.normalizePath(path);
|
|
@@ -287,7 +236,6 @@ class IndexedDbFs {
|
|
|
287
236
|
}
|
|
288
237
|
}
|
|
289
238
|
this.entries.delete(normalizedPath);
|
|
290
|
-
this.dirty = true;
|
|
291
239
|
}
|
|
292
240
|
async cp(src, dest, options) {
|
|
293
241
|
const srcPath = this.normalizePath(src);
|
|
@@ -314,7 +262,6 @@ class IndexedDbFs {
|
|
|
314
262
|
this.ensureParentDirs(destPath);
|
|
315
263
|
this.entries.set(destPath, this.cloneEntry(entry));
|
|
316
264
|
}
|
|
317
|
-
this.dirty = true;
|
|
318
265
|
}
|
|
319
266
|
async mv(src, dest) {
|
|
320
267
|
const srcPath = this.normalizePath(src);
|
|
@@ -341,7 +288,6 @@ class IndexedDbFs {
|
|
|
341
288
|
this.entries.delete(srcPath);
|
|
342
289
|
this.entries.set(destPath, entry);
|
|
343
290
|
}
|
|
344
|
-
this.dirty = true;
|
|
345
291
|
}
|
|
346
292
|
resolvePath(base, path) {
|
|
347
293
|
if (path.startsWith("/")) {
|
|
@@ -371,7 +317,6 @@ class IndexedDbFs {
|
|
|
371
317
|
}
|
|
372
318
|
entry.mode = mode;
|
|
373
319
|
entry.mtime = new Date;
|
|
374
|
-
this.dirty = true;
|
|
375
320
|
}
|
|
376
321
|
async symlink(target, linkPath) {
|
|
377
322
|
const normalizedLinkPath = this.normalizePath(linkPath);
|
|
@@ -385,7 +330,6 @@ class IndexedDbFs {
|
|
|
385
330
|
mode: DEFAULT_SYMLINK_MODE,
|
|
386
331
|
mtime: new Date
|
|
387
332
|
});
|
|
388
|
-
this.dirty = true;
|
|
389
333
|
}
|
|
390
334
|
async link(existingPath, newPath) {
|
|
391
335
|
const srcPath = this.normalizePath(existingPath);
|
|
@@ -407,7 +351,6 @@ class IndexedDbFs {
|
|
|
407
351
|
mode: entry.mode,
|
|
408
352
|
mtime: new Date
|
|
409
353
|
});
|
|
410
|
-
this.dirty = true;
|
|
411
354
|
}
|
|
412
355
|
async readlink(path) {
|
|
413
356
|
const normalizedPath = this.normalizePath(path);
|
|
@@ -453,10 +396,9 @@ class IndexedDbFs {
|
|
|
453
396
|
throw new Error(`ENOENT: no such file or directory, utimes '${path}'`);
|
|
454
397
|
}
|
|
455
398
|
entry.mtime = mtime;
|
|
456
|
-
this.dirty = true;
|
|
457
399
|
}
|
|
458
400
|
normalizePath(path) {
|
|
459
|
-
return
|
|
401
|
+
return Filesystem.normalizePath(path);
|
|
460
402
|
}
|
|
461
403
|
static normalizePath(path) {
|
|
462
404
|
if (!path || path === ".")
|
|
@@ -484,8 +426,7 @@ class IndexedDbFs {
|
|
|
484
426
|
return lastSlash === 0 ? "/" : path.slice(0, lastSlash);
|
|
485
427
|
}
|
|
486
428
|
ensureParentDirs(path) {
|
|
487
|
-
|
|
488
|
-
this.dirty = true;
|
|
429
|
+
Filesystem.ensureParentDirs(this.entries, path);
|
|
489
430
|
}
|
|
490
431
|
static ensureParentDirs(entries, path) {
|
|
491
432
|
const parts = path.split("/").filter(Boolean);
|
|
@@ -562,17 +503,20 @@ class IndexedDbFs {
|
|
|
562
503
|
return new TextDecoder("utf-8").decode(buffer);
|
|
563
504
|
}
|
|
564
505
|
if (encoding === "base64") {
|
|
565
|
-
|
|
566
|
-
for (let i = 0;i < buffer.byteLength; i++) {
|
|
567
|
-
binary += String.fromCharCode(buffer[i]);
|
|
568
|
-
}
|
|
569
|
-
return btoa(binary);
|
|
506
|
+
return this.encodeBase64(buffer);
|
|
570
507
|
}
|
|
571
508
|
if (encoding === "hex") {
|
|
572
509
|
return Array.from(buffer).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
573
510
|
}
|
|
574
511
|
return new TextDecoder("utf-8").decode(buffer);
|
|
575
512
|
}
|
|
513
|
+
encodeBase64(buffer) {
|
|
514
|
+
let binary = "";
|
|
515
|
+
for (let i = 0;i < buffer.byteLength; i++) {
|
|
516
|
+
binary += String.fromCharCode(buffer[i]);
|
|
517
|
+
}
|
|
518
|
+
return btoa(binary);
|
|
519
|
+
}
|
|
576
520
|
concatBuffers(a, b) {
|
|
577
521
|
const result = new Uint8Array(a.byteLength + b.byteLength);
|
|
578
522
|
result.set(a, 0);
|
|
@@ -585,77 +529,9 @@ class IndexedDbFs {
|
|
|
585
529
|
}
|
|
586
530
|
return value;
|
|
587
531
|
}
|
|
588
|
-
static openDatabase(dbName) {
|
|
589
|
-
return new Promise((resolve, reject) => {
|
|
590
|
-
const request = indexedDB.open(dbName, 1);
|
|
591
|
-
request.onerror = () => reject(request.error);
|
|
592
|
-
request.onsuccess = () => resolve(request.result);
|
|
593
|
-
request.onupgradeneeded = (event) => {
|
|
594
|
-
const db = event.target.result;
|
|
595
|
-
if (!db.objectStoreNames.contains("entries")) {
|
|
596
|
-
db.createObjectStore("entries", { keyPath: "path" });
|
|
597
|
-
}
|
|
598
|
-
};
|
|
599
|
-
});
|
|
600
|
-
}
|
|
601
|
-
static async loadEntries(db) {
|
|
602
|
-
const tx = db.transaction("entries", "readonly");
|
|
603
|
-
const store = tx.objectStore("entries");
|
|
604
|
-
return new Promise((resolve, reject) => {
|
|
605
|
-
const request = store.getAll();
|
|
606
|
-
request.onerror = () => reject(request.error);
|
|
607
|
-
request.onsuccess = () => {
|
|
608
|
-
const entries = new Map;
|
|
609
|
-
for (const record of request.result) {
|
|
610
|
-
entries.set(record.path, IndexedDbFs.deserializeEntry(record.entry));
|
|
611
|
-
}
|
|
612
|
-
resolve(entries);
|
|
613
|
-
};
|
|
614
|
-
});
|
|
615
|
-
}
|
|
616
|
-
serializeEntry(entry) {
|
|
617
|
-
if (entry.type === "file" && entry.content instanceof Uint8Array) {
|
|
618
|
-
return {
|
|
619
|
-
...entry,
|
|
620
|
-
content: Array.from(entry.content),
|
|
621
|
-
contentType: "uint8array",
|
|
622
|
-
mtime: entry.mtime.toISOString()
|
|
623
|
-
};
|
|
624
|
-
}
|
|
625
|
-
return {
|
|
626
|
-
...entry,
|
|
627
|
-
mtime: entry.mtime.toISOString()
|
|
628
|
-
};
|
|
629
|
-
}
|
|
630
|
-
static deserializeEntry(data) {
|
|
631
|
-
const mtime = new Date(data.mtime);
|
|
632
|
-
if (data.type === "file") {
|
|
633
|
-
let content = data.content;
|
|
634
|
-
if (data.contentType === "uint8array" && Array.isArray(content)) {
|
|
635
|
-
content = new Uint8Array(content);
|
|
636
|
-
}
|
|
637
|
-
return { type: "file", content, mode: data.mode, mtime };
|
|
638
|
-
}
|
|
639
|
-
if (data.type === "symlink") {
|
|
640
|
-
return { type: "symlink", target: data.target, mode: data.mode, mtime };
|
|
641
|
-
}
|
|
642
|
-
return { type: "directory", mode: data.mode, mtime };
|
|
643
|
-
}
|
|
644
|
-
promisifyRequest(request) {
|
|
645
|
-
return new Promise((resolve, reject) => {
|
|
646
|
-
request.onerror = () => reject(request.error);
|
|
647
|
-
request.onsuccess = () => resolve(request.result);
|
|
648
|
-
});
|
|
649
|
-
}
|
|
650
|
-
promisifyTransaction(tx) {
|
|
651
|
-
return new Promise((resolve, reject) => {
|
|
652
|
-
tx.onerror = () => reject(tx.error);
|
|
653
|
-
tx.oncomplete = () => resolve();
|
|
654
|
-
});
|
|
655
|
-
}
|
|
656
532
|
}
|
|
657
|
-
function
|
|
658
|
-
return
|
|
533
|
+
function createFilesystem(options) {
|
|
534
|
+
return Filesystem.create(options);
|
|
659
535
|
}
|
|
660
536
|
|
|
661
537
|
// src/packages.ts
|
|
@@ -1122,16 +998,18 @@ var GLOBAL_KEY = "__sandlot_shared_modules__";
|
|
|
1122
998
|
|
|
1123
999
|
class SharedModuleRegistry {
|
|
1124
1000
|
modules = new Map;
|
|
1001
|
+
exportNames = new Map;
|
|
1125
1002
|
constructor() {
|
|
1126
1003
|
globalThis[GLOBAL_KEY] = this;
|
|
1127
1004
|
}
|
|
1128
1005
|
register(moduleId, module) {
|
|
1129
1006
|
this.modules.set(moduleId, module);
|
|
1007
|
+
this.exportNames.set(moduleId, introspectExports(module));
|
|
1130
1008
|
return this;
|
|
1131
1009
|
}
|
|
1132
1010
|
registerAll(modules) {
|
|
1133
1011
|
for (const [id, mod] of Object.entries(modules)) {
|
|
1134
|
-
this.
|
|
1012
|
+
this.register(id, mod);
|
|
1135
1013
|
}
|
|
1136
1014
|
return this;
|
|
1137
1015
|
}
|
|
@@ -1152,13 +1030,44 @@ class SharedModuleRegistry {
|
|
|
1152
1030
|
list() {
|
|
1153
1031
|
return [...this.modules.keys()];
|
|
1154
1032
|
}
|
|
1033
|
+
getExportNames(moduleId) {
|
|
1034
|
+
return this.exportNames.get(moduleId) ?? [];
|
|
1035
|
+
}
|
|
1155
1036
|
clear() {
|
|
1156
1037
|
this.modules.clear();
|
|
1038
|
+
this.exportNames.clear();
|
|
1157
1039
|
}
|
|
1158
1040
|
get size() {
|
|
1159
1041
|
return this.modules.size;
|
|
1160
1042
|
}
|
|
1161
1043
|
}
|
|
1044
|
+
function introspectExports(module) {
|
|
1045
|
+
if (module === null || module === undefined) {
|
|
1046
|
+
return [];
|
|
1047
|
+
}
|
|
1048
|
+
if (typeof module !== "object" && typeof module !== "function") {
|
|
1049
|
+
return [];
|
|
1050
|
+
}
|
|
1051
|
+
const exports = [];
|
|
1052
|
+
for (const key of Object.keys(module)) {
|
|
1053
|
+
if (isValidIdentifier(key)) {
|
|
1054
|
+
exports.push(key);
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
return exports;
|
|
1058
|
+
}
|
|
1059
|
+
function isValidIdentifier(name) {
|
|
1060
|
+
if (name.length === 0)
|
|
1061
|
+
return false;
|
|
1062
|
+
if (!/^[a-zA-Z_$]/.test(name))
|
|
1063
|
+
return false;
|
|
1064
|
+
if (!/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name))
|
|
1065
|
+
return false;
|
|
1066
|
+
const reserved = ["default", "class", "function", "var", "let", "const", "import", "export"];
|
|
1067
|
+
if (reserved.includes(name))
|
|
1068
|
+
return false;
|
|
1069
|
+
return true;
|
|
1070
|
+
}
|
|
1162
1071
|
var defaultRegistry = null;
|
|
1163
1072
|
function getSharedModuleRegistry() {
|
|
1164
1073
|
if (!defaultRegistry) {
|
|
@@ -1178,6 +1087,9 @@ function unregisterSharedModule(moduleId) {
|
|
|
1178
1087
|
function clearSharedModules() {
|
|
1179
1088
|
getSharedModuleRegistry().clear();
|
|
1180
1089
|
}
|
|
1090
|
+
function getSharedModuleExports(moduleId) {
|
|
1091
|
+
return getSharedModuleRegistry().getExportNames(moduleId);
|
|
1092
|
+
}
|
|
1181
1093
|
function getSharedModuleRuntimeCode(moduleId) {
|
|
1182
1094
|
return `
|
|
1183
1095
|
(function() {
|
|
@@ -1375,55 +1287,12 @@ ${generateNamedExports(args.path)}
|
|
|
1375
1287
|
};
|
|
1376
1288
|
}
|
|
1377
1289
|
function generateNamedExports(moduleId) {
|
|
1378
|
-
const
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
"useEffect",
|
|
1382
|
-
"useContext",
|
|
1383
|
-
"useReducer",
|
|
1384
|
-
"useCallback",
|
|
1385
|
-
"useMemo",
|
|
1386
|
-
"useRef",
|
|
1387
|
-
"useImperativeHandle",
|
|
1388
|
-
"useLayoutEffect",
|
|
1389
|
-
"useDebugValue",
|
|
1390
|
-
"useDeferredValue",
|
|
1391
|
-
"useTransition",
|
|
1392
|
-
"useId",
|
|
1393
|
-
"useSyncExternalStore",
|
|
1394
|
-
"useInsertionEffect",
|
|
1395
|
-
"useOptimistic",
|
|
1396
|
-
"useActionState",
|
|
1397
|
-
"createElement",
|
|
1398
|
-
"cloneElement",
|
|
1399
|
-
"createContext",
|
|
1400
|
-
"forwardRef",
|
|
1401
|
-
"lazy",
|
|
1402
|
-
"memo",
|
|
1403
|
-
"startTransition",
|
|
1404
|
-
"Children",
|
|
1405
|
-
"Component",
|
|
1406
|
-
"PureComponent",
|
|
1407
|
-
"Fragment",
|
|
1408
|
-
"Profiler",
|
|
1409
|
-
"StrictMode",
|
|
1410
|
-
"Suspense",
|
|
1411
|
-
"version",
|
|
1412
|
-
"isValidElement"
|
|
1413
|
-
],
|
|
1414
|
-
"react-dom": ["createPortal", "flushSync", "version"],
|
|
1415
|
-
"react-dom/client": ["createRoot", "hydrateRoot"],
|
|
1416
|
-
"react-dom/server": ["renderToString", "renderToStaticMarkup", "renderToPipeableStream"]
|
|
1417
|
-
};
|
|
1418
|
-
const exports = knownExports[moduleId];
|
|
1419
|
-
if (!exports) {
|
|
1420
|
-
return `
|
|
1421
|
-
// Dynamic re-export for unknown module
|
|
1422
|
-
export const __moduleProxy__ = __sandlot_mod__;
|
|
1423
|
-
`;
|
|
1424
|
-
}
|
|
1425
|
-
return exports.map((name) => `export const ${name} = __sandlot_mod__.${name};`).join(`
|
|
1290
|
+
const exports = getSharedModuleExports(moduleId);
|
|
1291
|
+
if (exports.length > 0) {
|
|
1292
|
+
return exports.map((name) => `export const ${name} = __sandlot_mod__.${name};`).join(`
|
|
1426
1293
|
`);
|
|
1294
|
+
}
|
|
1295
|
+
return `// No exports discovered for "${moduleId}" - use default import or call registerSharedModules() first`;
|
|
1427
1296
|
}
|
|
1428
1297
|
async function bundle(options) {
|
|
1429
1298
|
await initBundler();
|
|
@@ -1466,7 +1335,8 @@ async function bundle(options) {
|
|
|
1466
1335
|
globalName,
|
|
1467
1336
|
target,
|
|
1468
1337
|
external,
|
|
1469
|
-
plugins: [plugin]
|
|
1338
|
+
plugins: [plugin],
|
|
1339
|
+
jsx: "automatic"
|
|
1470
1340
|
});
|
|
1471
1341
|
const code = result.outputFiles?.[0]?.text ?? "";
|
|
1472
1342
|
return {
|
|
@@ -1489,7 +1359,21 @@ async function bundleAndImport(options) {
|
|
|
1489
1359
|
}
|
|
1490
1360
|
}
|
|
1491
1361
|
|
|
1492
|
-
// src/commands.ts
|
|
1362
|
+
// src/commands/types.ts
|
|
1363
|
+
function formatEsbuildMessages(messages) {
|
|
1364
|
+
if (messages.length === 0)
|
|
1365
|
+
return "";
|
|
1366
|
+
return messages.map((msg) => {
|
|
1367
|
+
if (msg.location) {
|
|
1368
|
+
const { file, line, column } = msg.location;
|
|
1369
|
+
const loc = file ? `${file}${line ? `:${line}` : ""}${column ? `:${column}` : ""}` : "";
|
|
1370
|
+
return loc ? `${loc}: ${msg.text}` : msg.text;
|
|
1371
|
+
}
|
|
1372
|
+
return msg.text;
|
|
1373
|
+
}).join(`
|
|
1374
|
+
`);
|
|
1375
|
+
}
|
|
1376
|
+
// src/commands/compile.ts
|
|
1493
1377
|
import { defineCommand } from "just-bash/browser";
|
|
1494
1378
|
|
|
1495
1379
|
// src/typechecker.ts
|
|
@@ -1880,20 +1764,7 @@ async function hasExport(result, exportName) {
|
|
|
1880
1764
|
return exportName in module;
|
|
1881
1765
|
}
|
|
1882
1766
|
|
|
1883
|
-
// src/commands.ts
|
|
1884
|
-
function formatEsbuildMessages(messages) {
|
|
1885
|
-
if (messages.length === 0)
|
|
1886
|
-
return "";
|
|
1887
|
-
return messages.map((msg) => {
|
|
1888
|
-
if (msg.location) {
|
|
1889
|
-
const { file, line, column } = msg.location;
|
|
1890
|
-
const loc = file ? `${file}${line ? `:${line}` : ""}${column ? `:${column}` : ""}` : "";
|
|
1891
|
-
return loc ? `${loc}: ${msg.text}` : msg.text;
|
|
1892
|
-
}
|
|
1893
|
-
return msg.text;
|
|
1894
|
-
}).join(`
|
|
1895
|
-
`);
|
|
1896
|
-
}
|
|
1767
|
+
// src/commands/compile.ts
|
|
1897
1768
|
function createTscCommand(deps) {
|
|
1898
1769
|
const { fs, libFiles, tsconfigPath } = deps;
|
|
1899
1770
|
return defineCommand("tsc", async (args, _ctx) => {
|
|
@@ -1958,7 +1829,7 @@ ${formatDiagnosticsForAgent(result.diagnostics.filter((d) => d.category === "war
|
|
|
1958
1829
|
});
|
|
1959
1830
|
}
|
|
1960
1831
|
function createBuildCommand(deps) {
|
|
1961
|
-
const { fs, libFiles, tsconfigPath, onBuild, sharedModules } = deps;
|
|
1832
|
+
const { fs, libFiles, tsconfigPath, onBuild, getValidation, sharedModules } = deps;
|
|
1962
1833
|
return defineCommand("build", async (args, _ctx) => {
|
|
1963
1834
|
let entryPoint = null;
|
|
1964
1835
|
let skipTypecheck = false;
|
|
@@ -2030,8 +1901,39 @@ ${formatted}
|
|
|
2030
1901
|
minify,
|
|
2031
1902
|
sharedModules
|
|
2032
1903
|
});
|
|
1904
|
+
let loadedModule;
|
|
1905
|
+
try {
|
|
1906
|
+
loadedModule = await loadModule(bundleResult);
|
|
1907
|
+
} catch (err) {
|
|
1908
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
1909
|
+
return {
|
|
1910
|
+
stdout: "",
|
|
1911
|
+
stderr: `Build failed: Module failed to load.
|
|
1912
|
+
|
|
1913
|
+
${errorMessage}
|
|
1914
|
+
`,
|
|
1915
|
+
exitCode: 1
|
|
1916
|
+
};
|
|
1917
|
+
}
|
|
1918
|
+
const validateFn = getValidation?.();
|
|
1919
|
+
let validatedModule = loadedModule;
|
|
1920
|
+
if (validateFn) {
|
|
1921
|
+
try {
|
|
1922
|
+
validatedModule = validateFn(loadedModule);
|
|
1923
|
+
} catch (err) {
|
|
1924
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
1925
|
+
return {
|
|
1926
|
+
stdout: "",
|
|
1927
|
+
stderr: `Build failed: Validation error.
|
|
1928
|
+
|
|
1929
|
+
${errorMessage}
|
|
1930
|
+
`,
|
|
1931
|
+
exitCode: 1
|
|
1932
|
+
};
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
2033
1935
|
if (onBuild) {
|
|
2034
|
-
await onBuild(bundleResult);
|
|
1936
|
+
await onBuild({ bundle: bundleResult, module: validatedModule });
|
|
2035
1937
|
}
|
|
2036
1938
|
let output = `Build successful!
|
|
2037
1939
|
`;
|
|
@@ -2047,6 +1949,15 @@ ${formatted}
|
|
|
2047
1949
|
}
|
|
2048
1950
|
output += `Bundled: ${bundleResult.includedFiles.length} file(s)
|
|
2049
1951
|
`;
|
|
1952
|
+
const exportNames = Object.keys(loadedModule).filter((k) => !k.startsWith("__"));
|
|
1953
|
+
if (exportNames.length > 0) {
|
|
1954
|
+
output += `Exports: ${exportNames.join(", ")}
|
|
1955
|
+
`;
|
|
1956
|
+
}
|
|
1957
|
+
if (validateFn) {
|
|
1958
|
+
output += `Validation: passed
|
|
1959
|
+
`;
|
|
1960
|
+
}
|
|
2050
1961
|
if (bundleResult.warnings.length > 0) {
|
|
2051
1962
|
output += `
|
|
2052
1963
|
Build warnings:
|
|
@@ -2078,9 +1989,11 @@ ${formatDiagnosticsForAgent(warnings)}
|
|
|
2078
1989
|
}
|
|
2079
1990
|
});
|
|
2080
1991
|
}
|
|
1992
|
+
// src/commands/packages.ts
|
|
1993
|
+
import { defineCommand as defineCommand2 } from "just-bash/browser";
|
|
2081
1994
|
function createInstallCommand(deps) {
|
|
2082
1995
|
const { fs, typesCache } = deps;
|
|
2083
|
-
return
|
|
1996
|
+
return defineCommand2("install", async (args, _ctx) => {
|
|
2084
1997
|
if (args.length === 0) {
|
|
2085
1998
|
return {
|
|
2086
1999
|
stdout: "",
|
|
@@ -2134,7 +2047,7 @@ Examples:
|
|
|
2134
2047
|
}
|
|
2135
2048
|
function createUninstallCommand(deps) {
|
|
2136
2049
|
const { fs } = deps;
|
|
2137
|
-
return
|
|
2050
|
+
return defineCommand2("uninstall", async (args, _ctx) => {
|
|
2138
2051
|
if (args.length === 0) {
|
|
2139
2052
|
return {
|
|
2140
2053
|
stdout: "",
|
|
@@ -2179,7 +2092,7 @@ function createUninstallCommand(deps) {
|
|
|
2179
2092
|
}
|
|
2180
2093
|
function createListCommand(deps) {
|
|
2181
2094
|
const { fs } = deps;
|
|
2182
|
-
return
|
|
2095
|
+
return defineCommand2("list", async (_args, _ctx) => {
|
|
2183
2096
|
try {
|
|
2184
2097
|
const packages = await listPackages(fs);
|
|
2185
2098
|
if (packages.length === 0) {
|
|
@@ -2209,9 +2122,11 @@ function createListCommand(deps) {
|
|
|
2209
2122
|
}
|
|
2210
2123
|
});
|
|
2211
2124
|
}
|
|
2125
|
+
// src/commands/run.ts
|
|
2126
|
+
import { defineCommand as defineCommand3 } from "just-bash/browser";
|
|
2212
2127
|
function createRunCommand(deps) {
|
|
2213
2128
|
const { fs, libFiles, tsconfigPath, runOptions = {}, sharedModules } = deps;
|
|
2214
|
-
return
|
|
2129
|
+
return defineCommand3("run", async (args, _ctx) => {
|
|
2215
2130
|
let entryPoint = null;
|
|
2216
2131
|
let skipTypecheck = runOptions.skipTypecheck ?? false;
|
|
2217
2132
|
let timeout = runOptions.timeout ?? 30000;
|
|
@@ -2388,6 +2303,7 @@ ${err.stack}` : "";
|
|
|
2388
2303
|
}
|
|
2389
2304
|
});
|
|
2390
2305
|
}
|
|
2306
|
+
// src/commands/index.ts
|
|
2391
2307
|
function createDefaultCommands(deps) {
|
|
2392
2308
|
return [
|
|
2393
2309
|
createTscCommand(deps),
|
|
@@ -2597,9 +2513,7 @@ function hasDefaultResources() {
|
|
|
2597
2513
|
// src/build-emitter.ts
|
|
2598
2514
|
class BuildEmitter {
|
|
2599
2515
|
listeners = new Set;
|
|
2600
|
-
lastResult = null;
|
|
2601
2516
|
emit = async (result) => {
|
|
2602
|
-
this.lastResult = result;
|
|
2603
2517
|
const promises = [];
|
|
2604
2518
|
for (const listener of this.listeners) {
|
|
2605
2519
|
const ret = listener(result);
|
|
@@ -2615,245 +2529,155 @@ class BuildEmitter {
|
|
|
2615
2529
|
this.listeners.delete(callback);
|
|
2616
2530
|
};
|
|
2617
2531
|
}
|
|
2618
|
-
waitFor() {
|
|
2619
|
-
if (this.lastResult) {
|
|
2620
|
-
const result = this.lastResult;
|
|
2621
|
-
this.lastResult = null;
|
|
2622
|
-
return Promise.resolve(result);
|
|
2623
|
-
}
|
|
2624
|
-
return new Promise((resolve) => {
|
|
2625
|
-
const unsub = this.on((result) => {
|
|
2626
|
-
unsub();
|
|
2627
|
-
this.lastResult = null;
|
|
2628
|
-
resolve(result);
|
|
2629
|
-
});
|
|
2630
|
-
});
|
|
2631
|
-
}
|
|
2632
2532
|
}
|
|
2633
2533
|
|
|
2634
2534
|
// src/sandbox.ts
|
|
2635
2535
|
async function createSandbox(options = {}) {
|
|
2636
|
-
const {
|
|
2637
|
-
fsOptions = {},
|
|
2638
|
-
tsconfigPath = "/tsconfig.json",
|
|
2639
|
-
resources: providedResources,
|
|
2640
|
-
onBuild: onBuildCallback,
|
|
2641
|
-
customCommands = [],
|
|
2642
|
-
sharedModules
|
|
2643
|
-
} = options;
|
|
2644
|
-
const fsPromise = IndexedDbFs.create(fsOptions);
|
|
2645
|
-
const resourcesPromise = providedResources ? Promise.resolve(providedResources) : getDefaultResources();
|
|
2646
|
-
const bundlerPromise = initBundler();
|
|
2647
|
-
const [fs, resources] = await Promise.all([fsPromise, resourcesPromise, bundlerPromise]);
|
|
2648
|
-
const libFiles = resources.libFiles;
|
|
2649
|
-
const typesCache = resources.typesCache;
|
|
2650
|
-
const buildEmitter = new BuildEmitter;
|
|
2651
|
-
if (onBuildCallback) {
|
|
2652
|
-
buildEmitter.on(onBuildCallback);
|
|
2653
|
-
}
|
|
2654
|
-
const commandDeps = {
|
|
2655
|
-
fs,
|
|
2656
|
-
libFiles,
|
|
2657
|
-
tsconfigPath,
|
|
2658
|
-
onBuild: buildEmitter.emit,
|
|
2659
|
-
typesCache,
|
|
2660
|
-
sharedModules
|
|
2661
|
-
};
|
|
2662
|
-
const defaultCommands = createDefaultCommands(commandDeps);
|
|
2663
|
-
const bash = new Bash({
|
|
2664
|
-
fs,
|
|
2665
|
-
cwd: "/",
|
|
2666
|
-
customCommands: [...defaultCommands, ...customCommands]
|
|
2667
|
-
});
|
|
2668
|
-
return {
|
|
2669
|
-
fs,
|
|
2670
|
-
bash,
|
|
2671
|
-
isDirty: () => fs.isDirty(),
|
|
2672
|
-
save: () => fs.save(),
|
|
2673
|
-
close: () => fs.close(),
|
|
2674
|
-
onBuild: (callback) => buildEmitter.on(callback)
|
|
2675
|
-
};
|
|
2676
|
-
}
|
|
2677
|
-
async function createInMemorySandbox(options = {}) {
|
|
2678
2536
|
const {
|
|
2679
2537
|
initialFiles,
|
|
2538
|
+
maxFilesystemSize,
|
|
2680
2539
|
tsconfigPath = "/tsconfig.json",
|
|
2681
2540
|
resources: providedResources,
|
|
2682
2541
|
onBuild: onBuildCallback,
|
|
2683
2542
|
customCommands = [],
|
|
2684
|
-
sharedModules
|
|
2543
|
+
sharedModules,
|
|
2544
|
+
bashOptions = {}
|
|
2685
2545
|
} = options;
|
|
2546
|
+
const fs = Filesystem.create({
|
|
2547
|
+
initialFiles,
|
|
2548
|
+
maxSizeBytes: maxFilesystemSize
|
|
2549
|
+
});
|
|
2686
2550
|
const resourcesPromise = providedResources ? Promise.resolve(providedResources) : getDefaultResources();
|
|
2687
2551
|
const bundlerPromise = initBundler();
|
|
2688
|
-
const fs = IndexedDbFs.createInMemory({ initialFiles });
|
|
2689
2552
|
const [resources] = await Promise.all([resourcesPromise, bundlerPromise]);
|
|
2690
2553
|
const libFiles = resources.libFiles;
|
|
2691
2554
|
const typesCache = resources.typesCache;
|
|
2555
|
+
if (sharedModules && sharedModules.length > 0) {
|
|
2556
|
+
const basePackages = new Set;
|
|
2557
|
+
for (const moduleId of sharedModules) {
|
|
2558
|
+
const { packageName } = parseImportPath(moduleId);
|
|
2559
|
+
basePackages.add(packageName);
|
|
2560
|
+
}
|
|
2561
|
+
await Promise.all(Array.from(basePackages).map(async (packageName) => {
|
|
2562
|
+
try {
|
|
2563
|
+
await installPackage(fs, packageName, { cache: typesCache });
|
|
2564
|
+
} catch (err) {
|
|
2565
|
+
console.warn(`[sandlot] Failed to install types for shared module "${packageName}":`, err);
|
|
2566
|
+
}
|
|
2567
|
+
}));
|
|
2568
|
+
}
|
|
2692
2569
|
const buildEmitter = new BuildEmitter;
|
|
2570
|
+
let lastBuild = null;
|
|
2571
|
+
buildEmitter.on((result) => {
|
|
2572
|
+
lastBuild = result;
|
|
2573
|
+
});
|
|
2693
2574
|
if (onBuildCallback) {
|
|
2694
2575
|
buildEmitter.on(onBuildCallback);
|
|
2695
2576
|
}
|
|
2577
|
+
let validationFn = null;
|
|
2696
2578
|
const commandDeps = {
|
|
2697
2579
|
fs,
|
|
2698
2580
|
libFiles,
|
|
2699
2581
|
tsconfigPath,
|
|
2700
2582
|
onBuild: buildEmitter.emit,
|
|
2583
|
+
getValidation: () => validationFn,
|
|
2701
2584
|
typesCache,
|
|
2702
2585
|
sharedModules
|
|
2703
2586
|
};
|
|
2704
2587
|
const defaultCommands = createDefaultCommands(commandDeps);
|
|
2705
2588
|
const bash = new Bash({
|
|
2589
|
+
...bashOptions,
|
|
2706
2590
|
fs,
|
|
2707
|
-
cwd: "/",
|
|
2708
2591
|
customCommands: [...defaultCommands, ...customCommands]
|
|
2709
2592
|
});
|
|
2710
2593
|
return {
|
|
2711
2594
|
fs,
|
|
2712
2595
|
bash,
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2596
|
+
get lastBuild() {
|
|
2597
|
+
return lastBuild;
|
|
2598
|
+
},
|
|
2599
|
+
getState: () => ({ files: fs.getFiles() }),
|
|
2600
|
+
onBuild: (callback) => buildEmitter.on(callback),
|
|
2601
|
+
setValidation: (fn) => {
|
|
2602
|
+
validationFn = fn;
|
|
2603
|
+
},
|
|
2604
|
+
clearValidation: () => {
|
|
2605
|
+
validationFn = null;
|
|
2606
|
+
}
|
|
2717
2607
|
};
|
|
2718
2608
|
}
|
|
2719
|
-
// src/
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
initPromise = null;
|
|
2726
|
-
nextId = 1;
|
|
2727
|
-
options;
|
|
2728
|
-
constructor(options = {}) {
|
|
2729
|
-
this.options = {
|
|
2730
|
-
libs: options.libs ?? getDefaultBrowserLibs(),
|
|
2731
|
-
...options
|
|
2732
|
-
};
|
|
2733
|
-
}
|
|
2734
|
-
async initialize() {
|
|
2735
|
-
if (this.initialized)
|
|
2736
|
-
return;
|
|
2737
|
-
if (this.initPromise) {
|
|
2738
|
-
await this.initPromise;
|
|
2739
|
-
return;
|
|
2740
|
-
}
|
|
2741
|
-
this.initPromise = this.doInitialize();
|
|
2742
|
-
await this.initPromise;
|
|
2743
|
-
this.initialized = true;
|
|
2744
|
-
}
|
|
2745
|
-
async doInitialize() {
|
|
2746
|
-
this.resources = await createSharedResources({
|
|
2747
|
-
libs: this.options.libs,
|
|
2748
|
-
skipLibs: this.options.skipLibs,
|
|
2749
|
-
skipBundler: this.options.skipBundler
|
|
2750
|
-
});
|
|
2751
|
-
}
|
|
2752
|
-
async createSandbox(options = {}) {
|
|
2753
|
-
await this.initialize();
|
|
2754
|
-
const {
|
|
2755
|
-
id = `sandbox-${this.nextId++}`,
|
|
2756
|
-
fsOptions = {},
|
|
2757
|
-
initialFiles,
|
|
2758
|
-
tsconfigPath = "/tsconfig.json",
|
|
2759
|
-
onBuild,
|
|
2760
|
-
customCommands = [],
|
|
2761
|
-
inMemory = true,
|
|
2762
|
-
sharedModules = this.options.sharedModules
|
|
2763
|
-
} = options;
|
|
2764
|
-
let fs;
|
|
2765
|
-
if (inMemory) {
|
|
2766
|
-
fs = IndexedDbFs.createInMemory({
|
|
2767
|
-
initialFiles,
|
|
2768
|
-
maxSizeBytes: fsOptions.maxSizeBytes
|
|
2769
|
-
});
|
|
2770
|
-
} else {
|
|
2771
|
-
fs = await IndexedDbFs.create({
|
|
2772
|
-
dbName: fsOptions.dbName ?? id,
|
|
2773
|
-
initialFiles,
|
|
2774
|
-
maxSizeBytes: fsOptions.maxSizeBytes
|
|
2775
|
-
});
|
|
2609
|
+
// src/builder.ts
|
|
2610
|
+
function createBuilder(options) {
|
|
2611
|
+
return async (prompt, callOptions) => {
|
|
2612
|
+
const sandbox = options.sandbox ?? await createSandbox(options.sandboxOptions);
|
|
2613
|
+
if (callOptions?.validate) {
|
|
2614
|
+
sandbox.setValidation(callOptions.validate);
|
|
2776
2615
|
}
|
|
2777
|
-
const
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
}
|
|
2781
|
-
const commandDeps = {
|
|
2782
|
-
fs,
|
|
2783
|
-
libFiles: this.resources.libFiles,
|
|
2784
|
-
tsconfigPath,
|
|
2785
|
-
onBuild: buildEmitter.emit,
|
|
2786
|
-
typesCache: this.resources.typesCache,
|
|
2787
|
-
sharedModules
|
|
2788
|
-
};
|
|
2789
|
-
const defaultCommands = createDefaultCommands(commandDeps);
|
|
2790
|
-
const bash = new Bash2({
|
|
2791
|
-
fs,
|
|
2792
|
-
cwd: "/",
|
|
2793
|
-
customCommands: [...defaultCommands, ...customCommands]
|
|
2616
|
+
const captured = { output: null };
|
|
2617
|
+
const unsubscribe = sandbox.onBuild((output) => {
|
|
2618
|
+
captured.output = output;
|
|
2794
2619
|
});
|
|
2795
|
-
const
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
}
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
return Array.from(this.sandboxes.values());
|
|
2815
|
-
}
|
|
2816
|
-
closeSandbox(id) {
|
|
2817
|
-
const sandbox = this.sandboxes.get(id);
|
|
2818
|
-
if (sandbox) {
|
|
2819
|
-
sandbox.close();
|
|
2820
|
-
return true;
|
|
2821
|
-
}
|
|
2822
|
-
return false;
|
|
2823
|
-
}
|
|
2824
|
-
destroyAll() {
|
|
2825
|
-
for (const sandbox of this.sandboxes.values()) {
|
|
2826
|
-
sandbox.fs.close();
|
|
2620
|
+
const { timeout, signal } = callOptions ?? {};
|
|
2621
|
+
let timeoutId;
|
|
2622
|
+
let abortController;
|
|
2623
|
+
if (timeout !== undefined || signal !== undefined) {
|
|
2624
|
+
abortController = new AbortController;
|
|
2625
|
+
if (timeout !== undefined) {
|
|
2626
|
+
timeoutId = setTimeout(() => {
|
|
2627
|
+
abortController.abort(new Error(`Build timed out after ${timeout}ms`));
|
|
2628
|
+
}, timeout);
|
|
2629
|
+
}
|
|
2630
|
+
if (signal !== undefined) {
|
|
2631
|
+
if (signal.aborted) {
|
|
2632
|
+
abortController.abort(signal.reason);
|
|
2633
|
+
} else {
|
|
2634
|
+
signal.addEventListener("abort", () => {
|
|
2635
|
+
abortController.abort(signal.reason);
|
|
2636
|
+
}, { once: true });
|
|
2637
|
+
}
|
|
2638
|
+
}
|
|
2827
2639
|
}
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2640
|
+
let result;
|
|
2641
|
+
let error = null;
|
|
2642
|
+
try {
|
|
2643
|
+
const buildPromise = options.build(sandbox, prompt);
|
|
2644
|
+
if (abortController) {
|
|
2645
|
+
const abortPromise = new Promise((_, reject) => {
|
|
2646
|
+
abortController.signal.addEventListener("abort", () => {
|
|
2647
|
+
const err = abortController.signal.reason instanceof Error ? abortController.signal.reason : new Error("Build aborted");
|
|
2648
|
+
err.name = "AbortError";
|
|
2649
|
+
reject(err);
|
|
2650
|
+
}, { once: true });
|
|
2651
|
+
if (abortController.signal.aborted) {
|
|
2652
|
+
const err = abortController.signal.reason instanceof Error ? abortController.signal.reason : new Error("Build aborted");
|
|
2653
|
+
err.name = "AbortError";
|
|
2654
|
+
reject(err);
|
|
2655
|
+
}
|
|
2656
|
+
});
|
|
2657
|
+
result = await Promise.race([buildPromise, abortPromise]);
|
|
2658
|
+
} else {
|
|
2659
|
+
result = await buildPromise;
|
|
2660
|
+
}
|
|
2661
|
+
} catch (err) {
|
|
2662
|
+
error = err instanceof Error ? err : new Error(String(err));
|
|
2663
|
+
} finally {
|
|
2664
|
+
if (timeoutId !== undefined) {
|
|
2665
|
+
clearTimeout(timeoutId);
|
|
2666
|
+
}
|
|
2667
|
+
unsubscribe();
|
|
2668
|
+
if (callOptions?.validate) {
|
|
2669
|
+
sandbox.clearValidation();
|
|
2670
|
+
}
|
|
2835
2671
|
}
|
|
2836
|
-
|
|
2837
|
-
}
|
|
2838
|
-
getDirtySandboxes() {
|
|
2839
|
-
return Array.from(this.sandboxes.entries()).filter(([_, sandbox]) => sandbox.isDirty()).map(([id]) => id);
|
|
2840
|
-
}
|
|
2841
|
-
getStats() {
|
|
2672
|
+
const buildOutput = captured.output;
|
|
2842
2673
|
return {
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2674
|
+
result,
|
|
2675
|
+
error,
|
|
2676
|
+
bundle: buildOutput?.bundle ?? null,
|
|
2677
|
+
module: buildOutput?.module ?? null,
|
|
2678
|
+
sandbox
|
|
2847
2679
|
};
|
|
2848
|
-
}
|
|
2849
|
-
getResources() {
|
|
2850
|
-
return this.resources;
|
|
2851
|
-
}
|
|
2852
|
-
}
|
|
2853
|
-
async function createSandboxManager(options = {}) {
|
|
2854
|
-
const manager = new SandboxManager(options);
|
|
2855
|
-
await manager.initialize();
|
|
2856
|
-
return manager;
|
|
2680
|
+
};
|
|
2857
2681
|
}
|
|
2858
2682
|
|
|
2859
2683
|
// src/index.ts
|
|
@@ -2890,22 +2714,20 @@ export {
|
|
|
2890
2714
|
createUninstallCommand,
|
|
2891
2715
|
createTscCommand,
|
|
2892
2716
|
createSharedResources,
|
|
2893
|
-
createSandboxManager,
|
|
2894
2717
|
createSandbox,
|
|
2895
2718
|
createRunCommand,
|
|
2896
2719
|
createListCommand,
|
|
2897
2720
|
createInstallCommand,
|
|
2898
|
-
|
|
2899
|
-
createInMemoryFs,
|
|
2721
|
+
createFilesystem,
|
|
2900
2722
|
createDefaultCommands,
|
|
2723
|
+
createBuilder,
|
|
2901
2724
|
createBuildCommand,
|
|
2902
2725
|
clearSharedModules,
|
|
2903
2726
|
clearDefaultResources,
|
|
2904
2727
|
bundleToUrl,
|
|
2905
2728
|
bundleAndImport,
|
|
2906
2729
|
bundle,
|
|
2907
|
-
SandboxManager,
|
|
2908
2730
|
ModuleLoadError,
|
|
2909
|
-
|
|
2731
|
+
Filesystem,
|
|
2910
2732
|
ExportNotFoundError
|
|
2911
2733
|
};
|