@adep/web-container 0.1.1 → 0.2.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.
@@ -79,9 +79,796 @@ var init_path = __esm({
79
79
  }
80
80
  });
81
81
 
82
- // src/preview.ts
83
- var preview_exports = {};
84
- __export(preview_exports, {
82
+ // src/node-resolve.ts
83
+ function parsePackageMeta(content, context) {
84
+ let parsed;
85
+ try {
86
+ parsed = JSON.parse(content);
87
+ } catch {
88
+ throw new ResolveError(`${context} \u4E0D\u662F\u5408\u6CD5 JSON`);
89
+ }
90
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
91
+ throw new ResolveError(`${context} \u9876\u5C42\u5FC5\u987B\u662F\u5BF9\u8C61`);
92
+ }
93
+ return parsed;
94
+ }
95
+ function withinPackage(pkgDirAbs, rel, context) {
96
+ if (typeof rel !== "string" || rel === "") {
97
+ throw new ResolveError(`${context}\uFF1A\u5165\u53E3\u8DEF\u5F84\u5FC5\u987B\u662F\u5B57\u7B26\u4E32`);
98
+ }
99
+ if (!rel.startsWith("./") && !rel.startsWith("../") && rel.startsWith("/")) {
100
+ throw new ResolveError(`${context}\uFF1A\u5165\u53E3\u8DEF\u5F84 "${rel}" \u5FC5\u987B\u662F\u5305\u5185\u76F8\u5BF9\u8DEF\u5F84\uFF08\u4EE5 ./ \u5F00\u5934\uFF09`);
101
+ }
102
+ const abs = join(pkgDirAbs, rel.startsWith(".") ? rel : `./${rel}`);
103
+ if (!abs.startsWith(`${pkgDirAbs}/`)) {
104
+ throw new ResolveError(`${context}\uFF1A\u5165\u53E3\u8DEF\u5F84 "${rel}" \u8D8A\u51FA\u5305\u76EE\u5F55\uFF0C\u5DF2\u62D2\u7EDD`);
105
+ }
106
+ return abs;
107
+ }
108
+ function resolvePackageEntry(meta, pkgDirAbs, condition) {
109
+ const context = `\u5305 ${meta.name ?? meta.version ?? pkgDirAbs} \u7684 exports/main \u58F0\u660E`;
110
+ const exp = meta.exports;
111
+ if (exp !== void 0 && exp !== null) {
112
+ if (typeof exp === "string") return withinPackage(pkgDirAbs, exp, context);
113
+ if (typeof exp !== "object" || Array.isArray(exp)) {
114
+ throw new ResolveError(`${context} \u5F62\u6001\u4E0D\u652F\u6301\uFF08exports \u53EA\u80FD\u662F\u5B57\u7B26\u4E32\u6216\u5BF9\u8C61\uFF09`);
115
+ }
116
+ const dot = exp["."];
117
+ if (dot === void 0) {
118
+ throw new ResolveError(
119
+ `${context} \u53EA\u58F0\u660E\u4E86\u5B50\u8DEF\u5F84\u6620\u5C04\u3001\u6CA1\u6709 "." \u5165\u53E3\uFF0C\u5F53\u524D\u4EC5\u652F\u6301 "." \u4E0E\u5B57\u7B26\u4E32\u5F62\u6001`
120
+ );
121
+ }
122
+ if (typeof dot === "string") return withinPackage(pkgDirAbs, dot, context);
123
+ if (dot === null)
124
+ throw new ResolveError(`${context}\uFF1Aexports["."] \u4E3A null\uFF08\u8BE5\u6761\u4EF6\u88AB\u663E\u5F0F\u6392\u9664\uFF09\uFF0C\u65E0\u6CD5\u89E3\u6790\u5165\u53E3`);
125
+ if (typeof dot !== "object" || Array.isArray(dot)) {
126
+ throw new ResolveError(`${context}\uFF1Aexports["."] \u5F62\u6001\u4E0D\u652F\u6301\uFF08\u4EC5\u63A5\u53D7\u5B57\u7B26\u4E32\u6216\u6761\u4EF6\u5BF9\u8C61\uFF09`);
127
+ }
128
+ const conditions = dot;
129
+ const order = condition === "import" ? ["import", "node", "default"] : ["require", "node", "default"];
130
+ for (const key of order) {
131
+ const value = conditions[key];
132
+ if (typeof value === "string") return withinPackage(pkgDirAbs, value, context);
133
+ if (value !== void 0 && (typeof value !== "object" || value === null)) {
134
+ throw new ResolveError(
135
+ `${context}\uFF1Aexports["."]["${key}"] \u5F62\u6001\u4E0D\u652F\u6301\uFF08\u4EC5\u63A5\u53D7\u5B57\u7B26\u4E32\u6216 null\uFF09`
136
+ );
137
+ }
138
+ }
139
+ throw new ResolveError(
140
+ `${context}\uFF1Aexports["."] \u6761\u4EF6\u5BF9\u8C61\u91CC\u6CA1\u6709 ${condition}/node/default \u5B57\u7B26\u4E32\u5165\u53E3\uFF08\u5B50\u8DEF\u5F84/\u5D4C\u5957\u6761\u4EF6\u4E0D\u652F\u6301\uFF09`
141
+ );
142
+ }
143
+ if (meta.main !== void 0) {
144
+ if (typeof meta.main !== "string") {
145
+ throw new ResolveError(`${context}\uFF1Amain \u5FC5\u987B\u662F\u5B57\u7B26\u4E32`);
146
+ }
147
+ return withinPackage(pkgDirAbs, meta.main, context);
148
+ }
149
+ return join(pkgDirAbs, "index.js");
150
+ }
151
+ function splitPackageSpecifier(spec) {
152
+ if (spec.startsWith("@")) {
153
+ const first = spec.indexOf("/");
154
+ if (first === -1) return { name: spec, subpath: "" };
155
+ const second = spec.indexOf("/", first + 1);
156
+ if (second === -1) return { name: spec, subpath: "" };
157
+ return { name: spec.slice(0, second), subpath: spec.slice(second + 1) };
158
+ }
159
+ const slash = spec.indexOf("/");
160
+ if (slash === -1) return { name: spec, subpath: "" };
161
+ return { name: spec.slice(0, slash), subpath: spec.slice(slash + 1) };
162
+ }
163
+ function asFile(fs, baseAbs) {
164
+ if (fs.exists(baseAbs) && !fsIsDirectory(fs, baseAbs)) return baseAbs;
165
+ for (const ext of RESOLVE_EXTENSIONS) {
166
+ const candidate = `${baseAbs}${ext}`;
167
+ if (fs.exists(candidate) && !fsIsDirectory(fs, candidate)) return candidate;
168
+ }
169
+ return null;
170
+ }
171
+ function asDirectory(fs, dirAbs) {
172
+ if (!fs.exists(dirAbs) || !fsIsDirectory(fs, dirAbs)) return null;
173
+ const manifest = `${dirAbs}/package.json`;
174
+ if (fs.exists(manifest)) {
175
+ const meta = parsePackageMeta(fs.readFile(manifest), manifest);
176
+ const entry = resolvePackageEntry(meta, dirAbs, "require");
177
+ const hit = asFile(fs, entry);
178
+ if (hit !== null) return hit;
179
+ }
180
+ return asFile(fs, join(dirAbs, "index"));
181
+ }
182
+ function fsIsDirectory(fs, path) {
183
+ const probe = fs;
184
+ return probe.isDirectory?.(path) ?? false;
185
+ }
186
+ function resolveImport(fs, specifier, fromFileAbs, condition = "require") {
187
+ if (specifier === "") throw new ResolveError("\u7A7A\u8BF4\u660E\u7B26\uFF1A\u65E0\u6CD5\u89E3\u6790\u6A21\u5757");
188
+ if (specifier.startsWith("./") || specifier.startsWith("../")) {
189
+ const base = join(dirname(fromFileAbs), specifier);
190
+ const hit = asFile(fs, base) ?? asDirectory(fs, base);
191
+ if (hit === null) {
192
+ throw new ResolveError(
193
+ `\u627E\u4E0D\u5230\u76F8\u5BF9\u6A21\u5757 "${specifier}"\uFF08\u81EA ${dirname(fromFileAbs)}\uFF0C\u8BD5\u8FC7\u6269\u5C55\u540D ${RESOLVE_EXTENSIONS.join("/")} \u4E0E\u76EE\u5F55\u7D22\u5F15\uFF09`
194
+ );
195
+ }
196
+ return hit;
197
+ }
198
+ if (specifier.startsWith("/")) {
199
+ const hit = asFile(fs, specifier) ?? asDirectory(fs, specifier);
200
+ if (hit === null) throw new ResolveError(`\u627E\u4E0D\u5230\u7EDD\u5BF9\u8DEF\u5F84\u6A21\u5757 "${specifier}"`);
201
+ return hit;
202
+ }
203
+ const { name, subpath } = splitPackageSpecifier(specifier);
204
+ if (name.startsWith("node:")) {
205
+ throw new ResolveError(`\u6D4F\u89C8\u5668\u6C99\u7BB1\u4E0D\u63D0\u4F9B Node \u5185\u5EFA\u6A21\u5757 "${specifier}"`);
206
+ }
207
+ let dir = dirname(fromFileAbs);
208
+ for (; ; ) {
209
+ const pkgDir = join(dir, "node_modules", name);
210
+ if (fs.exists(pkgDir) && fsIsDirectory(fs, pkgDir)) {
211
+ if (subpath === "") {
212
+ const manifest = `${pkgDir}/package.json`;
213
+ if (fs.exists(manifest)) {
214
+ const meta = parsePackageMeta(fs.readFile(manifest), manifest);
215
+ const entry = resolvePackageEntry(meta, pkgDir, condition);
216
+ const hit = asFile(fs, entry) ?? asDirectory(fs, entry);
217
+ if (hit !== null) return hit;
218
+ } else {
219
+ const hit = asFile(fs, join(pkgDir, "index")) ?? asDirectory(fs, pkgDir);
220
+ if (hit !== null) return hit;
221
+ }
222
+ } else {
223
+ const base = join(pkgDir, subpath);
224
+ const hit = asFile(fs, base) ?? asDirectory(fs, base);
225
+ if (hit !== null) return hit;
226
+ }
227
+ throw new ResolveError(
228
+ `\u5728 ${pkgDir} \u627E\u5230\u4E86\u5305 "${name}"\uFF0C\u4F46\u89E3\u6790\u8BF4\u660E\u7B26 "${specifier}" \u5931\u8D25\uFF08\u5B50\u8DEF\u5F84\u4E0D\u5B58\u5728\uFF0C\u6216 exports/main \u6307\u5411\u7684\u5165\u53E3\u6587\u4EF6\u7F3A\u5931\uFF09`
229
+ );
230
+ }
231
+ const parent = dirname(dir);
232
+ if (parent === dir) break;
233
+ dir = parent;
234
+ }
235
+ throw new ResolveError(
236
+ `\u627E\u4E0D\u5230\u5305 "${specifier}"\uFF1A${dirname(fromFileAbs)} \u53CA\u5176\u5404\u7EA7\u7236\u76EE\u5F55\u4E0B\u90FD\u6CA1\u6709 node_modules/${name}\uFF08\u5148\u5728\u7EC8\u7AEF npm install ${name}\uFF09`
237
+ );
238
+ }
239
+ var RESOLVE_EXTENSIONS, ResolveError;
240
+ var init_node_resolve = __esm({
241
+ "src/node-resolve.ts"() {
242
+ "use strict";
243
+ init_path();
244
+ RESOLVE_EXTENSIONS = [".js", ".mjs", ".cjs", ".json"];
245
+ ResolveError = class extends Error {
246
+ constructor(message) {
247
+ super(message);
248
+ this.name = "ResolveError";
249
+ }
250
+ };
251
+ }
252
+ });
253
+
254
+ // src/strip-types.ts
255
+ function isAnnotationLeader(token) {
256
+ return ANNOTATION_LEADERS.has(token) || TS_MODIFIERS.has(token);
257
+ }
258
+ function stripTypes(source) {
259
+ return new Eraser(source).run();
260
+ }
261
+ var UnsupportedTsSyntaxError, IDENT_START, IDENT_PART, DECL_KEYWORDS, TS_MODIFIERS, ANNOTATION_LEADERS, Eraser;
262
+ var init_strip_types = __esm({
263
+ "src/strip-types.ts"() {
264
+ "use strict";
265
+ UnsupportedTsSyntaxError = class extends Error {
266
+ constructor(construct, line) {
267
+ super(`\u4E0D\u53D7\u652F\u6301\u7684 TypeScript \u8BED\u6CD5\uFF1A${construct}\uFF08\u7B2C ${line} \u884C\uFF09\u2014\u2014\u6D4F\u89C8\u5668\u6D4B\u8BD5\u6C99\u7BB1\u53EA\u64E6\u9664\u7C7B\u578B\u6807\u6CE8`);
268
+ this.construct = construct;
269
+ this.line = line;
270
+ this.name = "UnsupportedTsSyntaxError";
271
+ }
272
+ };
273
+ IDENT_START = /[A-Za-z_$]/;
274
+ IDENT_PART = /[A-Za-z0-9_$]/;
275
+ DECL_KEYWORDS = /* @__PURE__ */ new Set(["const", "let", "var"]);
276
+ TS_MODIFIERS = /* @__PURE__ */ new Set([
277
+ "private",
278
+ "protected",
279
+ "public",
280
+ "readonly",
281
+ "abstract",
282
+ "override",
283
+ "declare"
284
+ ]);
285
+ ANNOTATION_LEADERS = /* @__PURE__ */ new Set(["(", ",", "{", ";", "erased", "modifier"]);
286
+ Eraser = class {
287
+ constructor(src) {
288
+ this.src = src;
289
+ this.chars = [...src];
290
+ }
291
+ chars;
292
+ tokens = [];
293
+ frames = [];
294
+ /** 刚消费 `class` 头:下一个 `{` 是类体起始。 */
295
+ pendingClassBody = false;
296
+ /** 刚消费 `=>`:其后的 `(` 是箭头函数参数列表(声明位)。 */
297
+ afterArrow = false;
298
+ /** 刚消费 `function` 关键字:其后的标识符是函数名,再后是参数列表。 */
299
+ afterFunctionKeyword = false;
300
+ /** 最近一次 `)` 闭合的是不是参数列表(返回值标注判据)。 */
301
+ justClosedDeclareParen = false;
302
+ i = 0;
303
+ run() {
304
+ while (this.i < this.src.length) {
305
+ if (/\s/.test(this.ch())) {
306
+ this.i++;
307
+ continue;
308
+ }
309
+ if (this.copyTrivia()) continue;
310
+ if (this.copyLiteral()) continue;
311
+ if (this.copyRegexIfNeeded()) continue;
312
+ if (this.readNumber()) continue;
313
+ const word = this.readWord();
314
+ if (word !== null) this.handleWord(word);
315
+ else this.handlePunctuation();
316
+ }
317
+ return this.chars.join("");
318
+ }
319
+ /* ———————————————————— 游标原语 ———————————————————— */
320
+ ch(offset = 0) {
321
+ return this.src[this.i + offset] ?? "";
322
+ }
323
+ /** 回看第 `back` 个显著 token(1 = 最近一个)。 */
324
+ tokenAt(back) {
325
+ return this.tokens[this.tokens.length - back] ?? "";
326
+ }
327
+ /** 擦除结果里 `from` 往前的最后一个非空白字符(看的是已擦除文本,不是原文)。 */
328
+ prevSignificantChar(from) {
329
+ for (let j = from; j >= 0; j--) {
330
+ const c = this.chars[j];
331
+ if (c !== " " && c !== " " && c !== "\n" && c !== "\r") return c;
332
+ }
333
+ return "";
334
+ }
335
+ /** 擦除 `[from, to)`:填等长空格,换行照抄——擦完行号与原文件一致。 */
336
+ erase(from, to) {
337
+ for (let j = Math.max(from, 0); j < to; j++) this.chars[j] = this.src[j] === "\n" ? "\n" : " ";
338
+ }
339
+ pushToken(token) {
340
+ this.afterArrow = token === "=>";
341
+ this.afterFunctionKeyword = token === "function";
342
+ this.tokens.push(token);
343
+ }
344
+ /** 数字面量整段消费(否则 `1.5` 会被拆成 `1` `.` `5`,`.` 参与判据时误判)。 */
345
+ readNumber() {
346
+ if (!/[0-9]/.test(this.ch())) return false;
347
+ let end = this.i;
348
+ while (end < this.src.length && /[0-9a-fA-FxXoObB._]/.test(this.src[end])) end++;
349
+ this.i = end;
350
+ this.pushToken("number");
351
+ return true;
352
+ }
353
+ readWord() {
354
+ if (!IDENT_START.test(this.ch())) return null;
355
+ let end = this.i;
356
+ while (end < this.src.length && IDENT_PART.test(this.src[end])) end++;
357
+ const word = this.src.slice(this.i, end);
358
+ this.i = end;
359
+ this.pushToken(word);
360
+ return word;
361
+ }
362
+ /* —————————————— 字面量与注释:整段跳过(内容永不参与判定) —————————————— */
363
+ copyTrivia() {
364
+ const head = this.ch();
365
+ const next = this.ch(1);
366
+ if (head === "/" && next === "/") {
367
+ while (this.i < this.src.length && this.ch() !== "\n") this.i++;
368
+ return true;
369
+ }
370
+ if (head === "/" && next === "*") {
371
+ const end = this.src.indexOf("*/", this.i + 2);
372
+ this.i = end === -1 ? this.src.length : end + 2;
373
+ return true;
374
+ }
375
+ return false;
376
+ }
377
+ copyLiteral() {
378
+ const head = this.ch();
379
+ if (head !== "'" && head !== '"' && head !== "`") return false;
380
+ this.i = head === "`" ? this.scanTemplate(this.i) : this.scanQuoted(this.i);
381
+ this.pushToken(head === "`" ? "template" : "string");
382
+ return true;
383
+ }
384
+ /** 引号串结束下标(未闭合则到行尾,把真实的语法错误留给求值期)。 */
385
+ scanQuoted(start) {
386
+ const quote = this.src[start];
387
+ let j = start + 1;
388
+ while (j < this.src.length) {
389
+ const c = this.src[j];
390
+ if (c === "\\") j += 2;
391
+ else if (c === quote) return j + 1;
392
+ else if (c === "\n") return j;
393
+ else j++;
394
+ }
395
+ return this.src.length;
396
+ }
397
+ /** 模板串结束下标(`${}` 内按大括号配平,内层字符串 / 模板一并识别)。 */
398
+ scanTemplate(start) {
399
+ let j = start + 1;
400
+ while (j < this.src.length) {
401
+ const c = this.src[j];
402
+ if (c === "\\") j += 2;
403
+ else if (c === "`") return j + 1;
404
+ else if (c === "$" && this.src[j + 1] === "{") j = this.scanInterpolation(j + 2);
405
+ else j++;
406
+ }
407
+ return this.src.length;
408
+ }
409
+ scanInterpolation(start) {
410
+ let depth = 1;
411
+ let j = start;
412
+ while (j < this.src.length) {
413
+ const c = this.src[j];
414
+ if (c === "\\") j += 2;
415
+ else if (c === "'" || c === '"') j = this.scanQuoted(j);
416
+ else if (c === "`") j = this.scanTemplate(j);
417
+ else if (c === "{") {
418
+ depth++;
419
+ j++;
420
+ } else if (c === "}") {
421
+ depth--;
422
+ j++;
423
+ if (depth === 0) return j;
424
+ } else j++;
425
+ }
426
+ return this.src.length;
427
+ }
428
+ /**
429
+ * 正则字面量:`/` 只在「运算符位」才是正则起始(前一个显著字符不是值结尾)。
430
+ * 判不准时按除号处理——除号后面不会有需要擦除的类型标注,最坏只是漏擦。
431
+ * 有了这条,`const url = /https:\/\//` 里的 `:` 与 `//` 才不会被人当语法(恒等用例之一)。
432
+ */
433
+ copyRegexIfNeeded() {
434
+ if (this.ch() !== "/") return false;
435
+ const prev = this.prevSignificantChar(this.i - 1);
436
+ const valueEnding = prev !== "" && (IDENT_PART.test(prev) || prev === ")" || prev === "]" || prev === "}" || prev === '"' || prev === "'" || prev === "`");
437
+ if (valueEnding) return false;
438
+ const end = this.scanRegex(this.i);
439
+ if (end === null) return false;
440
+ this.i = end;
441
+ this.pushToken("regex");
442
+ return true;
443
+ }
444
+ scanRegex(start) {
445
+ let j = start + 1;
446
+ let inClass = false;
447
+ while (j < this.src.length) {
448
+ const c = this.src[j];
449
+ if (c === "\\") {
450
+ j += 2;
451
+ continue;
452
+ }
453
+ if (c === "\n") return null;
454
+ if (c === "[") inClass = true;
455
+ else if (c === "]") inClass = false;
456
+ else if (c === "/" && !inClass) {
457
+ j++;
458
+ while (j < this.src.length && /[a-z]/i.test(this.src[j])) j++;
459
+ return j;
460
+ }
461
+ j++;
462
+ }
463
+ return null;
464
+ }
465
+ /* ———————————————— 关键字与声明结构 ———————————————— */
466
+ handleWord(word) {
467
+ const start = this.i - word.length;
468
+ if (this.tokenAt(2) === ".") {
469
+ this.consumeGenericsAfterName();
470
+ return;
471
+ }
472
+ switch (word) {
473
+ case "interface": {
474
+ const after = this.skipWhitespaceFrom(this.skipNameAndParams(start + word.length));
475
+ if (after === null || this.src[after] !== "{") return;
476
+ const end = this.scanBalanced(after, "{", "}");
477
+ this.erase(start, end);
478
+ this.i = end;
479
+ this.pushToken("erased");
480
+ return;
481
+ }
482
+ case "type": {
483
+ const after = this.skipWhitespaceFrom(this.skipNameAndParams(this.i));
484
+ if (after === null || this.src[after] !== "=") return;
485
+ const end = this.scanTypeExpression(after + 1, true);
486
+ this.erase(start, end);
487
+ this.i = end;
488
+ this.pushToken("erased");
489
+ return;
490
+ }
491
+ case "import":
492
+ case "export": {
493
+ if (!/^\s+type\b/.test(this.src.slice(this.i))) return;
494
+ const after = this.skipNameAndParams(this.i);
495
+ if (after === null) return;
496
+ const end = this.scanStatementEnd(after);
497
+ this.erase(start, end);
498
+ this.i = end;
499
+ this.pushToken("erased");
500
+ return;
501
+ }
502
+ case "enum":
503
+ case "namespace":
504
+ throw new UnsupportedTsSyntaxError(word, this.lineAt(start));
505
+ case "implements": {
506
+ let j = this.i;
507
+ while (j < this.src.length && this.src[j] !== "{" && this.src[j] !== ";") j++;
508
+ this.erase(start, j);
509
+ this.i = j;
510
+ this.pushToken("erased");
511
+ return;
512
+ }
513
+ case "class":
514
+ this.pendingClassBody = true;
515
+ return;
516
+ case "as":
517
+ case "satisfies": {
518
+ if (this.tokenAt(2) === "*" || this.tokenAt(2) === "type") return;
519
+ const nextChar = this.skipWhitespaceFrom(this.i);
520
+ if (nextChar === null || "=,:]})".includes(this.src[nextChar])) return;
521
+ const end = this.scanTypeExpression(this.i, false);
522
+ this.erase(start, end);
523
+ this.i = end;
524
+ return;
525
+ }
526
+ default: {
527
+ if (TS_MODIFIERS.has(word) && this.inClassBody()) {
528
+ const next = this.peekWord();
529
+ if (next === "" || /[{(=]/.test(next[0])) return;
530
+ this.erase(start, this.i);
531
+ this.pushToken("modifier");
532
+ return;
533
+ }
534
+ this.consumeGenericsAfterName();
535
+ }
536
+ }
537
+ }
538
+ peekWord() {
539
+ let j = this.i;
540
+ while (j < this.src.length && /\s/.test(this.src[j])) j++;
541
+ let end = j;
542
+ while (end < this.src.length && IDENT_PART.test(this.src[end])) end++;
543
+ return this.src.slice(j, end);
544
+ }
545
+ lineAt(index) {
546
+ let line = 1;
547
+ for (let j = 0; j < index; j++) if (this.src[j] === "\n") line++;
548
+ return line;
549
+ }
550
+ /** `:` 之前紧邻的是不是 `)`(返回值标注位;用于决定是否允许顶层 `=>` 续读)。 */
551
+ lastSignificantCharIsCloseParen(at) {
552
+ return this.prevSignificantChar(at - 1) === ")";
553
+ }
554
+ inClassBody() {
555
+ return this.frames[this.frames.length - 1]?.classBody === true;
556
+ }
557
+ /** 当前帧是不是声明位(参数列表 / 类体)——只有这里才允许把 `:` 判成标注。 */
558
+ inDeclarePosition() {
559
+ const frame = this.frames[this.frames.length - 1];
560
+ return frame !== void 0 && (frame.declare || frame.classBody);
561
+ }
562
+ /* ———————————————— 标点与括号帧 ———————————————— */
563
+ handlePunctuation() {
564
+ const c = this.ch();
565
+ const start = this.i;
566
+ if (c === "(" || c === "{" || c === "[") {
567
+ const frame = {
568
+ kind: c === "(" ? "paren" : c === "{" ? "brace" : "bracket",
569
+ declare: false,
570
+ classBody: false
571
+ };
572
+ if (c === "{" && this.pendingClassBody) {
573
+ frame.classBody = true;
574
+ this.pendingClassBody = false;
575
+ }
576
+ if (c === "(" && this.isDeclareParen(start)) frame.declare = true;
577
+ this.frames.push(frame);
578
+ this.i++;
579
+ this.pushToken(c);
580
+ return;
581
+ }
582
+ if (c === ")" || c === "}" || c === "]") {
583
+ const closed = this.frames.pop();
584
+ if (closed?.kind === "paren") this.justClosedDeclareParen = closed.declare;
585
+ this.i++;
586
+ this.pushToken(c);
587
+ return;
588
+ }
589
+ if (c === ":") {
590
+ if (this.ch(1) === ":") {
591
+ this.i++;
592
+ this.pushToken(":");
593
+ return;
594
+ }
595
+ const returnType = this.isAnnotationColon(start) && this.lastSignificantCharIsCloseParen(start);
596
+ if (returnType || this.isAnnotationColon(start)) {
597
+ const end = this.scanTypeExpression(start + 1, false, returnType);
598
+ this.erase(start, end);
599
+ this.i = end;
600
+ this.pushToken("erased");
601
+ return;
602
+ }
603
+ this.i++;
604
+ this.pushToken(":");
605
+ return;
606
+ }
607
+ if (c === "?" && this.ch(1) !== "?" && this.ch(1) !== ".") {
608
+ let j = start + 1;
609
+ while (j < this.src.length && (this.src[j] === " " || this.src[j] === " ")) j++;
610
+ if (this.src[j] === ":" && this.inDeclarePosition() && IDENT_PART.test(this.prevSignificantChar(start - 1))) {
611
+ const end = this.scanTypeExpression(j + 1, false);
612
+ this.erase(start, end);
613
+ this.i = end;
614
+ this.pushToken("erased");
615
+ return;
616
+ }
617
+ this.i++;
618
+ this.pushToken("?");
619
+ return;
620
+ }
621
+ if (c === "!" && this.ch(1) !== "=" && this.isPostfixBang(start)) {
622
+ this.erase(start, start + 1);
623
+ this.i++;
624
+ return;
625
+ }
626
+ if (c === "=" && this.ch(1) === ">") {
627
+ this.i += 2;
628
+ this.pushToken("=>");
629
+ return;
630
+ }
631
+ if (c === "<" && this.consumeLeadingGenerics(start)) return;
632
+ this.i++;
633
+ this.pushToken(c);
634
+ }
635
+ /** 空白跳跃(供声明结构找下一个非空白字符;不改游标,纯函数)。 */
636
+ skipWhitespaceFrom(index) {
637
+ if (index === null) return null;
638
+ let j = index;
639
+ while (j < this.src.length && /\s/.test(this.src[j])) j++;
640
+ return j;
641
+ }
642
+ /**
643
+ * 运算符位上的泛型参数列表(`const f = <T, >(x: T) => x`、`arr.map<T2>(...)` 之外的箭头形态):
644
+ * 前一个显著字符不是值结尾(否则是 `a < b` 比较),且 `>` 之后紧跟 `(` 才擦。
645
+ */
646
+ consumeLeadingGenerics(at) {
647
+ if (!"([{,=;:>!&|?".includes(this.prevSignificantChar(at - 1))) return false;
648
+ const end = this.scanTypeParams(at);
649
+ if (end === null) return false;
650
+ const after = this.skipWhitespaceFrom(end);
651
+ if (after === null || this.src[after] !== "(") return false;
652
+ this.erase(at, end);
653
+ this.i = end;
654
+ return true;
655
+ }
656
+ /**
657
+ * `(` 是否为参数列表(声明位):`function f(`、类体里的方法 `m(`、箭头 `=> (`,
658
+ * 以及出现在 `(` `,` `=` `>` `:` `[` `{` `}` `;` 之后(如 `map((v: T) => v)` 的内层括号)。
659
+ * 调用位 `foo(` 与控制流 `if (` `for (` 都不算。
660
+ * 误判成声明位也不足以擦掉什么:`:` 还要过 `isAnnotationColon` 的「名字前驱必须是
661
+ * `(` `,` `{` `;` 修饰符」这一关,而三元表达式的中间段前面必然是 `?`。
662
+ */
663
+ isDeclareParen(at) {
664
+ if (this.afterFunctionKeyword) return true;
665
+ if (this.tokenAt(2) === "function" && IDENT_START.test(this.tokenAt(1))) return true;
666
+ if (this.afterArrow) return true;
667
+ if (this.inClassBody() && IDENT_PART.test(this.prevSignificantChar(at - 1))) return true;
668
+ const prev = this.prevSignificantChar(at - 1);
669
+ return prev === "" || "(,=>:[{};".includes(prev);
670
+ }
671
+ /** `:` 是类型标注吗:看名字前驱 token 与所在帧(对象键、三元、`case` 一律排除)。 */
672
+ isAnnotationColon(at) {
673
+ const prev = this.prevSignificantChar(at - 1);
674
+ if (prev === ")") return this.justClosedDeclareParen;
675
+ if (prev === "}" || prev === "]") {
676
+ const frame = this.frames[this.frames.length - 1];
677
+ return frame?.kind === "paren" && frame.declare;
678
+ }
679
+ if (!IDENT_PART.test(prev)) return false;
680
+ if (this.tokenAt(1) === "number" || this.tokenAt(1) === "string") return false;
681
+ if (this.inDeclarePosition() && isAnnotationLeader(this.tokenAt(2))) return true;
682
+ return DECL_KEYWORDS.has(this.tokenAt(2));
683
+ }
684
+ /** 非空断言 `x!`:前一个显著字符是值结尾,且后一个非空白字符不是操作数起始。 */
685
+ isPostfixBang(at) {
686
+ const prev = this.prevSignificantChar(at - 1);
687
+ if (!(IDENT_PART.test(prev) || prev === ")" || prev === "]")) return false;
688
+ let j = at + 1;
689
+ while (j < this.src.length && (this.src[j] === " " || this.src[j] === " ")) j++;
690
+ const next = this.src[j] ?? "";
691
+ if (next === "") return true;
692
+ return !(IDENT_START.test(next) || /[0-9]/.test(next) || "(![~".includes(next));
693
+ }
694
+ /* ———————————————— 区间扫描(全部字符串 / 注释安全) ———————————————— */
695
+ /** 跳过「名字 + 泛型参数」;没有合法名字时返回 null(`{ type: 1 }` 因此落空)。 */
696
+ skipNameAndParams(from) {
697
+ let j = from;
698
+ while (j < this.src.length && /\s/.test(this.src[j])) j++;
699
+ const nameStart = j;
700
+ while (j < this.src.length && IDENT_PART.test(this.src[j])) j++;
701
+ if (j === nameStart) return null;
702
+ const generic = this.scanTypeParams(j);
703
+ return generic === null ? j : generic;
704
+ }
705
+ /** `<T, U extends X>`:返回 `>` 之后的下标;跨到 `)` `]` `;` 换行前配不平则 null。 */
706
+ scanTypeParams(from) {
707
+ if (this.src[from] !== "<") return null;
708
+ let depth = 0;
709
+ let j = from;
710
+ for (; j < this.src.length; j++) {
711
+ const c = this.src[j];
712
+ if (c === "<") depth++;
713
+ else if (c === ">") {
714
+ depth--;
715
+ if (depth === 0) return j + 1;
716
+ } else if (c === ")" || c === "]" || c === ";" || c === "\n") return null;
717
+ else if (c === "'" || c === '"') j = this.scanQuoted(j) - 1;
718
+ else if (c === "`") j = this.scanTemplate(j) - 1;
719
+ }
720
+ return null;
721
+ }
722
+ /**
723
+ * 消费「刚读出的标识符之后」的泛型实参 / 类型参数(`function f<T>(`、方法 `m<T>(`、`f<T>(x)`)。
724
+ * 只有 `>` 之后紧跟 `(` / `{` / `implements` 才算——`if (a < b) {` 里 `>` 之后是 `)`,故安全。
725
+ */
726
+ consumeGenericsAfterName() {
727
+ if (this.ch() !== "<") return;
728
+ const end = this.scanTypeParams(this.i);
729
+ if (end === null) return;
730
+ let j = end;
731
+ while (j < this.src.length && (this.src[j] === " " || this.src[j] === " ")) j++;
732
+ const after = this.src.slice(j);
733
+ if (!/^[({]/.test(after) && !/^implements\b/.test(after)) return;
734
+ this.erase(this.i, end);
735
+ this.i = end;
736
+ }
737
+ /** 括号配平:返回闭括号之后的下标(未配平则到文件尾)。 */
738
+ scanBalanced(from, open, close) {
739
+ let depth = 0;
740
+ let j = from;
741
+ while (j < this.src.length) {
742
+ const c = this.src[j];
743
+ if (c === "'" || c === '"') j = this.scanQuoted(j);
744
+ else if (c === "`") j = this.scanTemplate(j);
745
+ else if (c === "/" && (this.src[j + 1] === "/" || this.src[j + 1] === "*"))
746
+ j = this.skipComment(j);
747
+ else if (c === open) {
748
+ depth++;
749
+ j++;
750
+ } else if (c === close) {
751
+ depth--;
752
+ j++;
753
+ if (depth === 0) return j;
754
+ } else j++;
755
+ }
756
+ return this.src.length;
757
+ }
758
+ skipComment(from) {
759
+ if (this.src[from + 1] === "/") {
760
+ const end2 = this.src.indexOf("\n", from);
761
+ return end2 === -1 ? this.src.length : end2;
762
+ }
763
+ const end = this.src.indexOf("*/", from + 2);
764
+ return end === -1 ? this.src.length : end + 2;
765
+ }
766
+ /** 语句结束(`;` 或括号已配平时的行尾),用于 `import type …`。 */
767
+ scanStatementEnd(from) {
768
+ let depth = 0;
769
+ let j = from;
770
+ while (j < this.src.length) {
771
+ const c = this.src[j];
772
+ if (c === "'" || c === '"') j = this.scanQuoted(j);
773
+ else if (c === "`") j = this.scanTemplate(j);
774
+ else if (c === "{" || c === "(" || c === "[") {
775
+ depth++;
776
+ j++;
777
+ } else if (c === "}" || c === ")" || c === "]") {
778
+ depth--;
779
+ j++;
780
+ } else if (c === ";" || c === "\n" && depth <= 0) break;
781
+ else j++;
782
+ }
783
+ return j;
784
+ }
785
+ /**
786
+ * 类型表达式结束下标:消费标识符 / 字符串字面量类型 / 泛型实参 / 元组 / 对象类型 /
787
+ * 函数类型(含 `=>` 返回值)/ 联合与交叉;在深度 0 的 `= , ; ) ]` 与「已结束的行」处停下。
788
+ *
789
+ * 两处歧义的处理:
790
+ * - `function f(): { a: number } { … }`——还没消费过类型原子时遇到的 `{` 属于类型,
791
+ * 之后再遇 `{` 才是函数体;`type X = A` 的初始值花括号整体算类型(`leadingBraceIsType`)。
792
+ * - `const x: Foo = { … }`——在 `=` 处停,不会把右侧对象字面量吞掉。
793
+ */
794
+ scanTypeExpression(from, leadingBraceIsType, topLevelArrowEnds = false) {
795
+ let depth = 0;
796
+ let j = from;
797
+ let sawAtom = false;
798
+ while (j < this.src.length) {
799
+ const c = this.src[j];
800
+ if (c === "'" || c === '"') {
801
+ j = this.scanQuoted(j);
802
+ sawAtom = true;
803
+ } else if (c === "`") {
804
+ j = this.scanTemplate(j);
805
+ sawAtom = true;
806
+ } else if (c === "/" && (this.src[j + 1] === "/" || this.src[j + 1] === "*")) {
807
+ j = this.skipComment(j);
808
+ } else if (c === "(" || c === "[") {
809
+ depth++;
810
+ sawAtom = true;
811
+ j++;
812
+ } else if (c === ")" || c === "]") {
813
+ if (depth === 0) break;
814
+ depth--;
815
+ j++;
816
+ } else if (c === "{") {
817
+ if (depth === 0 && sawAtom && !leadingBraceIsType) break;
818
+ j = this.scanBalanced(j, "{", "}");
819
+ sawAtom = true;
820
+ } else if (c === "}") {
821
+ if (depth === 0) break;
822
+ depth--;
823
+ j++;
824
+ } else if (depth === 0 && (c === "," || c === ";")) break;
825
+ else if (depth === 0 && c === "=") {
826
+ if (this.src[j + 1] === ">" && !topLevelArrowEnds) {
827
+ j += 2;
828
+ continue;
829
+ }
830
+ break;
831
+ } else if (depth === 0 && c === "\n") {
832
+ if (!this.typeContinuesAt(j)) break;
833
+ j++;
834
+ } else if (c === "<") {
835
+ const generic = this.scanTypeParams(j);
836
+ if (generic === null) break;
837
+ j = generic;
838
+ sawAtom = true;
839
+ } else {
840
+ if (IDENT_PART.test(c)) sawAtom = true;
841
+ j++;
842
+ }
843
+ }
844
+ return j;
845
+ }
846
+ /**
847
+ * 行尾处类型是否仍在继续:`type Id = string\n | number` 要接得上,
848
+ * 而 `const x: Foo\nconst y = 1` 必须停。判据是两侧的非空邻字——
849
+ * 前一个是连接符(`| & < > = , . ? : (`)或后一个是连接符 / 闭合符(`| & , . ? : ) ] } >`)。
850
+ */
851
+ typeContinuesAt(index) {
852
+ for (let j = index - 1; j >= 0; j--) {
853
+ const c = this.src[j];
854
+ if (/\s/.test(c)) continue;
855
+ if ("|&<>=,.?:(".includes(c)) return true;
856
+ break;
857
+ }
858
+ for (let j = index + 1; j < this.src.length; j++) {
859
+ const c = this.src[j];
860
+ if (/\s/.test(c)) continue;
861
+ return "|&,.?:)]}>".includes(c);
862
+ }
863
+ return false;
864
+ }
865
+ };
866
+ }
867
+ });
868
+
869
+ // src/preview-server.ts
870
+ var preview_server_exports = {};
871
+ __export(preview_server_exports, {
85
872
  buildPreviewDocument: () => buildPreviewDocument,
86
873
  createPreviewServer: () => createPreviewServer,
87
874
  inlineAssets: () => inlineAssets
@@ -177,14 +964,657 @@ function createPreviewServer(vfs, options = {}) {
177
964
  };
178
965
  }
179
966
  var EXTERNAL_SRC;
180
- var init_preview = __esm({
181
- "src/preview.ts"() {
967
+ var init_preview_server = __esm({
968
+ "src/preview-server.ts"() {
182
969
  "use strict";
183
970
  init_path();
184
971
  EXTERNAL_SRC = /(?:^https?:)?\/\//i;
185
972
  }
186
973
  });
187
974
 
975
+ // src/function-fetch-proxy.ts
976
+ function parseBodyByContentType(rawBody, headers) {
977
+ if (rawBody === null) return void 0;
978
+ const contentType = headers["content-type"] ?? headers["Content-Type"] ?? headers["CONTENT-TYPE"] ?? "";
979
+ if (!/json/i.test(contentType)) return rawBody;
980
+ try {
981
+ return JSON.parse(rawBody);
982
+ } catch {
983
+ return rawBody;
984
+ }
985
+ }
986
+ function createFunctionFetchHandler(options) {
987
+ return async (event) => {
988
+ const data = event.data;
989
+ if (!data || data.__adepFnRequest !== true) return;
990
+ const source = event.source;
991
+ const post = source?.postMessage;
992
+ if (typeof post !== "function") return;
993
+ const reply = (payload) => {
994
+ try {
995
+ post.call(source, { __adepFnResponse: true, ...payload }, "*");
996
+ } catch {
997
+ }
998
+ };
999
+ try {
1000
+ const id = data.id;
1001
+ const method = String(data.method ?? "GET").toUpperCase();
1002
+ const url = String(data.url ?? "");
1003
+ const headers = typeof data.headers === "object" && data.headers !== null ? data.headers : {};
1004
+ const rawBody = typeof data.body === "string" ? data.body : data.body === null || data.body === void 0 ? null : String(data.body);
1005
+ const qIndex = url.indexOf("?");
1006
+ const pathPart = qIndex === -1 ? url : url.slice(0, qIndex);
1007
+ const queryPart = qIndex === -1 ? "" : url.slice(qIndex + 1);
1008
+ const match = pathPart.match(/^\/api\/([^/]+)(\/.*)?$/);
1009
+ if (match === null) {
1010
+ reply({
1011
+ id,
1012
+ status: 404,
1013
+ headers: { "content-type": "application/json" },
1014
+ body: JSON.stringify({
1015
+ error: { code: "FN_NOT_FOUND", message: `\u65E0\u6CD5\u89E3\u6790\u7684\u4E91\u51FD\u6570\u8DEF\u5F84: ${url}` }
1016
+ })
1017
+ });
1018
+ return;
1019
+ }
1020
+ const fnName = decodeURIComponent(match[1] ?? "");
1021
+ const subPath = match[2] ?? "/";
1022
+ const query = {};
1023
+ if (queryPart !== "") {
1024
+ try {
1025
+ new URLSearchParams(queryPart).forEach((value, key) => {
1026
+ query[key] = value;
1027
+ });
1028
+ } catch {
1029
+ }
1030
+ }
1031
+ const files = await options.getFunctionFiles(fnName);
1032
+ if (files === null || Object.keys(files).length === 0) {
1033
+ reply({
1034
+ id,
1035
+ status: 404,
1036
+ headers: { "content-type": "application/json" },
1037
+ body: JSON.stringify({
1038
+ error: {
1039
+ code: "FN_NOT_FOUND",
1040
+ message: `\u4E91\u51FD\u6570 "${fnName}" \u4E0D\u5B58\u5728\u6216\u5C1A\u672A\u52A0\u8F7D\u8349\u7A3F`
1041
+ }
1042
+ })
1043
+ });
1044
+ return;
1045
+ }
1046
+ const entry = files["index.ts"] !== void 0 ? "index.ts" : Object.keys(files)[0] ?? "";
1047
+ if (entry === "") {
1048
+ reply({
1049
+ id,
1050
+ status: 500,
1051
+ headers: { "content-type": "application/json" },
1052
+ body: JSON.stringify({
1053
+ error: { code: "FN_NO_ENTRY", message: `\u4E91\u51FD\u6570 "${fnName}" \u6CA1\u6709\u53EF\u6267\u884C\u6587\u4EF6` }
1054
+ })
1055
+ });
1056
+ return;
1057
+ }
1058
+ const body = parseBodyByContentType(rawBody, headers);
1059
+ const result = await options.runner.run({
1060
+ files,
1061
+ entry,
1062
+ request: {
1063
+ method,
1064
+ path: subPath,
1065
+ query,
1066
+ headers,
1067
+ ...body === void 0 ? {} : { body }
1068
+ },
1069
+ bundle: options.bundle
1070
+ });
1071
+ let status = result.status;
1072
+ let outBody;
1073
+ let outContentType = "application/json";
1074
+ if (result.error !== void 0) {
1075
+ if (status === 200) status = 500;
1076
+ outBody = JSON.stringify({ error: result.error });
1077
+ } else if (typeof result.body === "string") {
1078
+ outBody = result.body;
1079
+ outContentType = "text/plain; charset=utf-8";
1080
+ } else {
1081
+ outBody = JSON.stringify(result.body ?? null);
1082
+ }
1083
+ reply({ id, status, headers: { "content-type": outContentType }, body: outBody });
1084
+ } catch (error) {
1085
+ reply({
1086
+ id: data?.id,
1087
+ status: 500,
1088
+ headers: { "content-type": "application/json" },
1089
+ body: JSON.stringify({
1090
+ error: {
1091
+ code: "FN_PROXY_ERROR",
1092
+ message: error instanceof Error ? error.message : String(error)
1093
+ }
1094
+ })
1095
+ });
1096
+ }
1097
+ };
1098
+ }
1099
+ var FN_FETCH_INTERCEPTOR_SCRIPT;
1100
+ var init_function_fetch_proxy = __esm({
1101
+ "src/function-fetch-proxy.ts"() {
1102
+ "use strict";
1103
+ FN_FETCH_INTERCEPTOR_SCRIPT = (function() {
1104
+ var src = [
1105
+ "(function () {",
1106
+ " if (window.__adepFnProxyInstalled) return;",
1107
+ " window.__adepFnProxyInstalled = true;",
1108
+ " var ORIGINAL_FETCH = window.fetch.bind(window);",
1109
+ " var pending = {};",
1110
+ " var nextId = 1;",
1111
+ " var TIMEOUT_MS = 15000;",
1112
+ "",
1113
+ ' window.addEventListener("message", function (event) {',
1114
+ " var data = event.data;",
1115
+ " if (!data || data.__adepFnResponse !== true) return;",
1116
+ " var entry = pending[data.id];",
1117
+ " if (!entry) return;",
1118
+ " delete pending[data.id];",
1119
+ " clearTimeout(entry.timer);",
1120
+ " var headers;",
1121
+ " try { headers = new Headers(data.headers || {}); }",
1122
+ ' catch (e) { headers = new Headers({ "content-type": "text/plain" }); }',
1123
+ " var body = data.body == null ? null : data.body;",
1124
+ " try {",
1125
+ ' entry.resolve(new Response(body, { status: data.status || 200, statusText: "", headers: headers }));',
1126
+ " } catch (e2) {",
1127
+ ' entry.resolve(new Response(String(body), { status: data.status || 200, headers: { "content-type": "text/plain" } }));',
1128
+ " }",
1129
+ " });",
1130
+ "",
1131
+ " function readBody(input, init) {",
1132
+ ' if (typeof Request !== "undefined" && input instanceof Request) {',
1133
+ " return input.text().catch(function () { return null; });",
1134
+ " }",
1135
+ " var body = init && init.body !== undefined ? init.body : input;",
1136
+ " if (body == null) return Promise.resolve(null);",
1137
+ ' if (typeof body === "string") return Promise.resolve(body);',
1138
+ ' if (typeof ArrayBuffer !== "undefined" && body instanceof ArrayBuffer) {',
1139
+ " return Promise.resolve(new TextDecoder().decode(body));",
1140
+ " }",
1141
+ ' if (typeof Blob !== "undefined" && body instanceof Blob) return body.text();',
1142
+ ' if (typeof URLSearchParams !== "undefined" && body instanceof URLSearchParams) {',
1143
+ " return Promise.resolve(body.toString());",
1144
+ " }",
1145
+ " try { return Promise.resolve(String(body)); } catch (e) { return Promise.resolve(null); }",
1146
+ " }",
1147
+ "",
1148
+ " function collectHeaders(input, init) {",
1149
+ " var out = {};",
1150
+ " try { input.headers.forEach(function (v, k) { out[k] = v; }); } catch (e) {}",
1151
+ " if (init && init.headers) {",
1152
+ " try { new Headers(init.headers).forEach(function (v, k) { out[k] = v; }); } catch (e2) {}",
1153
+ " }",
1154
+ " return out;",
1155
+ " }",
1156
+ "",
1157
+ " window.fetch = function (input, init) {",
1158
+ " var urlStr;",
1159
+ " var method;",
1160
+ " var headers = {};",
1161
+ ' var isRequest = typeof Request !== "undefined" && input instanceof Request;',
1162
+ " if (isRequest) {",
1163
+ " urlStr = String(input.url);",
1164
+ ' method = (init && init.method) || input.method || "GET";',
1165
+ " headers = collectHeaders(input, init);",
1166
+ ' } else if (typeof input === "string" || (typeof URL !== "undefined" && input instanceof URL)) {',
1167
+ " urlStr = String(input);",
1168
+ ' method = (init && init.method) || "GET";',
1169
+ " try { new Headers(init && init.headers || {}).forEach(function (v, k) { headers[k] = v; }); } catch (e) {}",
1170
+ " } else {",
1171
+ " return ORIGINAL_FETCH(input, init);",
1172
+ " }",
1173
+ " var u;",
1174
+ " try { u = new URL(urlStr, document.baseURI); }",
1175
+ " catch (e) { return ORIGINAL_FETCH(input, init); }",
1176
+ ' if (u.pathname.indexOf("/api/") !== 0 && u.pathname !== "/api") {',
1177
+ " return ORIGINAL_FETCH(input, init);",
1178
+ " }",
1179
+ " if (window.parent === window) return ORIGINAL_FETCH(input, init);",
1180
+ ' method = (method || "GET").toUpperCase();',
1181
+ " var target = u.pathname + u.search;",
1182
+ " return readBody(input, init).then(function (textBody) {",
1183
+ " return new Promise(function (resolve) {",
1184
+ " var id = nextId++;",
1185
+ " var timer = setTimeout(function () {",
1186
+ " delete pending[id];",
1187
+ ` resolve(new Response('{"error":{"code":"FN_PROXY_TIMEOUT","message":"\\u4e91\\u51fd\\u6570\\u6267\\u884c\\u8d85\\u65f6"}}', { status: 504, headers: { "content-type": "application/json" } }));`,
1188
+ " }, TIMEOUT_MS);",
1189
+ " pending[id] = { resolve: resolve, timer: timer };",
1190
+ ' window.parent.postMessage({ __adepFnRequest: true, id: id, method: method, url: target, headers: headers, body: textBody }, "*");',
1191
+ " });",
1192
+ " });",
1193
+ " };",
1194
+ "})();"
1195
+ ].join("\n");
1196
+ return src;
1197
+ })();
1198
+ }
1199
+ });
1200
+
1201
+ // src/vite-dev.ts
1202
+ var vite_dev_exports = {};
1203
+ __export(vite_dev_exports, {
1204
+ ViteDevError: () => ViteDevError,
1205
+ createViteServer: () => createViteServer,
1206
+ scanEsmSpecifiers: () => scanEsmSpecifiers
1207
+ });
1208
+ function tokenize2(source) {
1209
+ const tokens = [];
1210
+ let i = 0;
1211
+ const n = source.length;
1212
+ while (i < n) {
1213
+ const ch = source[i];
1214
+ if (ch === " " || ch === " " || ch === "\n" || ch === "\r") {
1215
+ i++;
1216
+ continue;
1217
+ }
1218
+ if (ch === "/" && source[i + 1] === "/") {
1219
+ i = source.indexOf("\n", i);
1220
+ if (i === -1) break;
1221
+ continue;
1222
+ }
1223
+ if (ch === "/" && source[i + 1] === "*") {
1224
+ const close = source.indexOf("*/", i + 2);
1225
+ if (close === -1) break;
1226
+ i = close + 2;
1227
+ continue;
1228
+ }
1229
+ if (ch === "'" || ch === '"') {
1230
+ let j = i + 1;
1231
+ while (j < n && source[j] !== ch) {
1232
+ if (source[j] === "\\") j++;
1233
+ j++;
1234
+ }
1235
+ tokens.push({ kind: "string", text: source.slice(i, j + 1), start: i, end: j + 1 });
1236
+ i = j + 1;
1237
+ continue;
1238
+ }
1239
+ if (ch === "`") {
1240
+ let j = i + 1;
1241
+ while (j < n && source[j] !== "`") {
1242
+ if (source[j] === "\\") j++;
1243
+ j++;
1244
+ }
1245
+ tokens.push({ kind: "template", text: source.slice(i, j + 1), start: i, end: j + 1 });
1246
+ i = j + 1;
1247
+ continue;
1248
+ }
1249
+ if (ch === "/") {
1250
+ const prev = tokens[tokens.length - 1];
1251
+ const isRegex = prev === void 0 || prev.kind === "punct" && REGEX_PRECEDING_CHARS.has(prev.text) || prev.kind === "ident" && REGEX_PRECEDING_KEYWORDS.has(prev.text);
1252
+ if (isRegex) {
1253
+ let j = i + 1;
1254
+ let inClass = false;
1255
+ while (j < n) {
1256
+ const c = source[j];
1257
+ if (c === "\\") j++;
1258
+ else if (c === "[") inClass = true;
1259
+ else if (c === "]") inClass = false;
1260
+ else if (c === "/" && !inClass) break;
1261
+ else if (c === "\n") break;
1262
+ j++;
1263
+ }
1264
+ tokens.push({ kind: "punct", text: "/", start: i, end: i + 1 });
1265
+ i = j + 1;
1266
+ continue;
1267
+ }
1268
+ }
1269
+ if (isIdentStart(ch)) {
1270
+ let j = i + 1;
1271
+ while (j < n && isIdentPart(source[j])) j++;
1272
+ tokens.push({ kind: "ident", text: source.slice(i, j), start: i, end: j });
1273
+ i = j;
1274
+ continue;
1275
+ }
1276
+ tokens.push({ kind: "punct", text: ch, start: i, end: i + 1 });
1277
+ i++;
1278
+ }
1279
+ return tokens;
1280
+ }
1281
+ function scanEsmSpecifiers(source) {
1282
+ const tokens = tokenize2(source);
1283
+ const hits = [];
1284
+ for (let i = 1; i < tokens.length; i++) {
1285
+ const tok = tokens[i];
1286
+ if (tok.kind !== "string") continue;
1287
+ const prev = tokens[i - 1];
1288
+ const prev2 = tokens[i - 2];
1289
+ if (prev.kind !== "ident" && prev.kind !== "punct") continue;
1290
+ if (prev.kind === "ident" && prev.text === "import") {
1291
+ hits.push({ specifier: tok.text.slice(1, -1), start: tok.start, end: tok.end });
1292
+ continue;
1293
+ }
1294
+ if (prev.kind === "ident" && prev.text === "from" && !(prev2?.kind === "punct" && ["=", ":", ",", "(", "["].includes(prev2.text))) {
1295
+ hits.push({ specifier: tok.text.slice(1, -1), start: tok.start, end: tok.end });
1296
+ continue;
1297
+ }
1298
+ if (prev.kind === "punct" && prev.text === "(" && prev2?.kind === "ident" && prev2.text === "import") {
1299
+ hits.push({ specifier: tok.text.slice(1, -1), start: tok.start, end: tok.end });
1300
+ }
1301
+ }
1302
+ return hits;
1303
+ }
1304
+ function cssModule(css) {
1305
+ return [
1306
+ `const css = ${JSON.stringify(css)};`,
1307
+ 'const el = document.createElement("style");',
1308
+ 'el.setAttribute("data-adep-vite", "");',
1309
+ "el.textContent = css;",
1310
+ "document.head.appendChild(el);",
1311
+ "export default css;"
1312
+ ].join("\n");
1313
+ }
1314
+ function jsonModule(source, abs) {
1315
+ try {
1316
+ JSON.parse(source);
1317
+ } catch {
1318
+ throw new ViteDevError("JSON_PARSE", `${abs} \u4E0D\u662F\u5408\u6CD5 JSON`);
1319
+ }
1320
+ return `export default ${source.trim()};`;
1321
+ }
1322
+ function resolveWithSuffixes(vfs, base) {
1323
+ if (vfs.exists(base) && !vfs.isDirectory(base)) return base;
1324
+ const asFile2 = VITE_RESOLVE_SUFFIXES.map((suffix) => `${base}${suffix}`);
1325
+ const asIndex = VITE_RESOLVE_SUFFIXES.map((suffix) => join(base, `index${suffix}`));
1326
+ return asFile2.find((p) => vfs.exists(p) && !vfs.isDirectory(p)) ?? asIndex.find((p) => vfs.exists(p) && !vfs.isDirectory(p)) ?? base;
1327
+ }
1328
+ function hmrScript(name) {
1329
+ return `<script>(function(){if(typeof BroadcastChannel==='undefined')return;var bc=new BroadcastChannel(${JSON.stringify(
1330
+ name
1331
+ )});bc.onmessage=function(e){var d=e.data;if(d&&d.type==='update'&&d.url&&d.url!==location.href){location.replace(d.url);}};})();<\/script>`;
1332
+ }
1333
+ function createViteServer(vfs, options = {}) {
1334
+ const root = normalize(options.root ?? "/");
1335
+ const entry = options.entry ?? "index.html";
1336
+ const sfcCompiler = options.sfcCompiler;
1337
+ const createObjectURL = options.createObjectURL ?? ((blob) => URL.createObjectURL(blob));
1338
+ const revokeObjectURL = options.revokeObjectURL ?? ((url) => URL.revokeObjectURL(url));
1339
+ const channelName = `adep:vite:${Math.random().toString(36).slice(2)}`;
1340
+ const port = 5173;
1341
+ let moduleUrls = /* @__PURE__ */ new Map();
1342
+ const inFlight = /* @__PURE__ */ new Set();
1343
+ const stableUrls = /* @__PURE__ */ new Map();
1344
+ let inlineSources = /* @__PURE__ */ new Map();
1345
+ let currentUrl = "";
1346
+ let lastDoc = null;
1347
+ let bc = null;
1348
+ let touchTimer = null;
1349
+ let inlineSeq = 0;
1350
+ const scheduleRebuild = () => {
1351
+ if (touchTimer !== null) clearTimeout(touchTimer);
1352
+ touchTimer = setTimeout(() => {
1353
+ touchTimer = null;
1354
+ void rebuild();
1355
+ }, 100);
1356
+ };
1357
+ const broadcast = (url) => {
1358
+ try {
1359
+ bc ??= new BroadcastChannel(channelName);
1360
+ bc.postMessage({ type: "update", url });
1361
+ } catch {
1362
+ }
1363
+ };
1364
+ function transformModule2(abs, source) {
1365
+ if (abs.endsWith(".css")) return cssModule(source);
1366
+ if (abs.endsWith(".json")) return jsonModule(source, abs);
1367
+ if (abs.endsWith(".vue")) {
1368
+ if (sfcCompiler === void 0)
1369
+ throw new ViteDevError(
1370
+ "SFC_NO_COMPILER",
1371
+ `${abs} \u662F Vue SFC\uFF0C\u4F46\u5F53\u524D\u73AF\u5883\u672A\u88C5\u914D SFC \u7F16\u8BD1\u5668\uFF08IDE \u4FA7\u9700\u6CE8\u5165 vue/compiler-sfc\uFF09`
1372
+ );
1373
+ const compiled = sfcCompiler(source, abs);
1374
+ return [...compiled.styles.map((css) => cssModule(css)), compiled.script].join("\n");
1375
+ }
1376
+ if (abs.endsWith(".tsx") || abs.endsWith(".jsx"))
1377
+ throw new ViteDevError(
1378
+ "JSX_UNSUPPORTED",
1379
+ `${abs} \u4F7F\u7528 JSX\uFF1A\u6D4F\u89C8\u5668\u5185 vite \u53EA\u64E6\u9664 TS \u7C7B\u578B\u6807\u6CE8\uFF0C\u4E0D\u8F6C\u8BD1 JSX\uFF08\u8BF7\u7528 h() \u6E32\u67D3\u51FD\u6570\u6216 .vue SFC\uFF09`
1380
+ );
1381
+ if (abs.endsWith(".ts") || abs.endsWith(".mts")) return stripTypes(source);
1382
+ return source;
1383
+ }
1384
+ async function resolveSpecifier(spec, importerAbs) {
1385
+ if (EXTERNAL_SPECIFIER.test(spec) || DATA_OR_BLOB.test(spec)) return spec;
1386
+ let target;
1387
+ if (spec.startsWith("./") || spec.startsWith("../") || spec.startsWith("/")) {
1388
+ const base = spec.startsWith("/") ? spec : join(dirname(importerAbs), spec);
1389
+ target = resolveWithSuffixes(vfs, base);
1390
+ if (!vfs.exists(target) || vfs.isDirectory(target))
1391
+ throw new ViteDevError(
1392
+ "RESOLVE",
1393
+ `\u627E\u4E0D\u5230\u6A21\u5757 "${spec}"\uFF08\u81EA ${importerAbs}\uFF1B\u8BD5\u8FC7\u6269\u5C55\u540D ${VITE_RESOLVE_SUFFIXES.join("/")} \u4E0E\u76EE\u5F55 index\uFF09`
1394
+ );
1395
+ } else {
1396
+ try {
1397
+ target = resolveImport(vfs, spec, importerAbs, "import");
1398
+ } catch (error) {
1399
+ if (error instanceof ResolveError)
1400
+ throw new ViteDevError(
1401
+ "RESOLVE",
1402
+ `${error.message}
1403
+ \uFF08\u5728 ${importerAbs} \u4E2D import "${spec}"\uFF09`
1404
+ );
1405
+ throw error;
1406
+ }
1407
+ }
1408
+ return loadModuleUrl(target);
1409
+ }
1410
+ async function loadModuleUrl(abs) {
1411
+ const cached = moduleUrls.get(abs);
1412
+ if (cached !== void 0) return cached;
1413
+ if (inFlight.has(abs))
1414
+ throw new ViteDevError(
1415
+ "CYCLE",
1416
+ `\u5FAA\u73AF\u4F9D\u8D56\uFF1A${[...inFlight, abs].join(" \u2192 ")}\uFF08blob \u6A21\u5757\u94FE\u7684\u6539\u5199\u53D1\u751F\u5728\u52A0\u8F7D\u671F\uFF0C\u73AF\u65E0\u6CD5\u6210\u94FE\uFF1B\u8BF7\u62C6\u6389\u73AF\u6216\u6539\u7528\u52A8\u6001 import()\uFF09`
1417
+ );
1418
+ inFlight.add(abs);
1419
+ const pending = (async () => {
1420
+ const source = inlineSources.get(abs) ?? vfs.readFile(abs);
1421
+ const code = transformModule2(abs, source);
1422
+ const hits = scanEsmSpecifiers(code);
1423
+ const targets = await Promise.all(hits.map((hit) => resolveSpecifier(hit.specifier, abs)));
1424
+ let out = code;
1425
+ for (let i = hits.length - 1; i >= 0; i--) {
1426
+ const hit = hits[i];
1427
+ out = out.slice(0, hit.start) + JSON.stringify(targets[i]) + out.slice(hit.end);
1428
+ }
1429
+ const key = `${abs}\0${out}`;
1430
+ let url = stableUrls.get(key);
1431
+ if (url === void 0) {
1432
+ url = createObjectURL(new Blob([out], { type: "text/javascript" }));
1433
+ stableUrls.set(key, url);
1434
+ }
1435
+ return url;
1436
+ })();
1437
+ moduleUrls.set(abs, pending);
1438
+ try {
1439
+ return await pending;
1440
+ } catch (error) {
1441
+ moduleUrls.delete(abs);
1442
+ throw error;
1443
+ } finally {
1444
+ inFlight.delete(abs);
1445
+ }
1446
+ }
1447
+ const revokeStableUrls = () => {
1448
+ for (const url of stableUrls.values()) revokeObjectURL(url);
1449
+ stableUrls.clear();
1450
+ };
1451
+ function directoryListing2() {
1452
+ const rows = vfs.listDirectory(root).map((e) => `<li>${e.type === "file" ? "\u{1F4C4}" : "\u{1F4C1}"} <code>${e.path}</code></li>`).join("");
1453
+ return `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><title>vite \xB7 ${root}</title></head>
1454
+ <body style="font-family:system-ui;padding:24px"><h3>vite dev server \xB7 <code>${root}</code></h3>
1455
+ <p>\u672A\u627E\u5230\u5165\u53E3 <code>${entry}</code>\u3002\u5F53\u524D\u76EE\u5F55\u5185\u5BB9\uFF1A</p><ul>${rows}</ul>
1456
+ <p style="color:#64748b">\u5728 root \u4E0B\u521B\u5EFA ${entry}\uFF0C\u7528 &lt;script type="module" src="./main.ts"&gt; \u5F15\u5165\u6A21\u5757\u5165\u53E3\u3002</p></body></html>`;
1457
+ }
1458
+ function errorDocument(error) {
1459
+ const reason = error instanceof ViteDevError ? error.reason : "BUILD_FAILED";
1460
+ const message = error instanceof Error ? error.message : String(error);
1461
+ return `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><title>vite error</title></head>
1462
+ <body style="font-family:ui-monospace,monospace;background:#1a1c24;color:#e2e8f0;padding:24px">
1463
+ <h2 style="color:#f43f5e;margin-top:0">[vite] ${reason}</h2>
1464
+ <pre style="white-space:pre-wrap;word-break:break-all;line-height:1.7">${message.replace(/&/g, "&amp;").replace(/</g, "&lt;")}</pre>
1465
+ <p style="color:#94a3b8">\u4FEE\u590D\u4EE3\u7801\u540E\u9884\u89C8\u81EA\u52A8\u91CD\u5EFA\uFF1B\u4E5F\u53EF\u5728\u7EC8\u7AEF\u6267\u884C vite stop / vite &lt;dir&gt; \u91CD\u542F\u3002</p>
1466
+ </body></html>`;
1467
+ }
1468
+ async function buildDocument() {
1469
+ const entryAbs = join(root, entry);
1470
+ if (!vfs.exists(entryAbs) || vfs.isDirectory(entryAbs)) return directoryListing2();
1471
+ let html = vfs.readFile(entryAbs);
1472
+ html = inlineAssets(html, vfs, dirname(entryAbs));
1473
+ const entryModuleUrls = [];
1474
+ html = html.replace(
1475
+ MODULE_SCRIPT_SRC_RE,
1476
+ (_whole, pre, _q1, mid, _q2, src, post) => {
1477
+ const base = src.startsWith("/") ? normalize(src) : join(dirname(entryAbs), src);
1478
+ const abs = resolveWithSuffixes(vfs, base);
1479
+ if (!vfs.exists(abs) || vfs.isDirectory(abs))
1480
+ throw new ViteDevError(
1481
+ "RESOLVE",
1482
+ `\u5165\u53E3 module script \u627E\u4E0D\u5230 "${src}"\uFF08root: ${root}\uFF1B\u8BD5\u8FC7\u6269\u5C55\u540D ${VITE_RESOLVE_SUFFIXES.join("/")} \u4E0E\u76EE\u5F55 index\uFF09`
1483
+ );
1484
+ entryModuleUrls.push(loadModuleUrl(abs));
1485
+ return `<script${pre}${mid}src="__adep_vite_entry_${entryModuleUrls.length - 1}__"${post}><\/script>`;
1486
+ }
1487
+ );
1488
+ html = html.replace(
1489
+ MODULE_SCRIPT_INLINE_RE,
1490
+ (whole, pre, _q, post, body) => {
1491
+ if (/\bsrc\s*=/.test(pre + post)) return whole;
1492
+ const abs = `${INLINE_PREFIX}${inlineSeq++}.mjs`;
1493
+ inlineSources.set(abs, body);
1494
+ entryModuleUrls.push(loadModuleUrl(abs));
1495
+ return `<script${pre}${post}src="__adep_vite_entry_${entryModuleUrls.length - 1}__"><\/script>`;
1496
+ }
1497
+ );
1498
+ const urls = await Promise.all(entryModuleUrls);
1499
+ html = html.replace(/__adep_vite_entry_(\d+)__/g, (_m, idx) => urls[Number(idx)] ?? "");
1500
+ const interceptor = `<script>${FN_FETCH_INTERCEPTOR_SCRIPT}<\/script>`;
1501
+ html = /<head[^>]*>/i.test(html) ? html.replace(/<head[^>]*>/i, (m) => `${m}${interceptor}`) : `${interceptor}${html}`;
1502
+ const hmr = hmrScript(channelName);
1503
+ return /<\/body>/i.test(html) ? html.replace(/<\/(body)>/i, `${hmr}</$1>`) : html + hmr;
1504
+ }
1505
+ async function rebuild() {
1506
+ moduleUrls = /* @__PURE__ */ new Map();
1507
+ inlineSources = /* @__PURE__ */ new Map();
1508
+ inlineSeq = 0;
1509
+ let doc;
1510
+ try {
1511
+ doc = await buildDocument();
1512
+ } catch (error) {
1513
+ doc = errorDocument(error);
1514
+ }
1515
+ const changed = lastDoc !== null && doc !== lastDoc;
1516
+ lastDoc = doc;
1517
+ if (currentUrl !== "") revokeObjectURL(currentUrl);
1518
+ currentUrl = createObjectURL(new Blob([doc], { type: "text/html" }));
1519
+ if (changed) broadcast(currentUrl);
1520
+ }
1521
+ const server = {
1522
+ get url() {
1523
+ return currentUrl;
1524
+ },
1525
+ get port() {
1526
+ return port;
1527
+ },
1528
+ get root() {
1529
+ return root;
1530
+ },
1531
+ ready: rebuild(),
1532
+ touch() {
1533
+ scheduleRebuild();
1534
+ },
1535
+ async stop() {
1536
+ if (touchTimer !== null) {
1537
+ clearTimeout(touchTimer);
1538
+ touchTimer = null;
1539
+ }
1540
+ unsubscribeMutate();
1541
+ moduleUrls = /* @__PURE__ */ new Map();
1542
+ revokeStableUrls();
1543
+ if (currentUrl !== "") revokeObjectURL(currentUrl);
1544
+ currentUrl = "";
1545
+ bc?.close();
1546
+ bc = null;
1547
+ }
1548
+ };
1549
+ const unsubscribeMutate = vfs.onMutate(scheduleRebuild);
1550
+ return server;
1551
+ }
1552
+ var ViteDevError, REGEX_PRECEDING_CHARS, REGEX_PRECEDING_KEYWORDS, isIdentStart, isIdentPart, VITE_RESOLVE_SUFFIXES, INLINE_PREFIX, EXTERNAL_SPECIFIER, DATA_OR_BLOB, MODULE_SCRIPT_SRC_RE, MODULE_SCRIPT_INLINE_RE;
1553
+ var init_vite_dev = __esm({
1554
+ "src/vite-dev.ts"() {
1555
+ "use strict";
1556
+ init_path();
1557
+ init_node_resolve();
1558
+ init_strip_types();
1559
+ init_preview_server();
1560
+ init_function_fetch_proxy();
1561
+ ViteDevError = class extends Error {
1562
+ constructor(reason, message) {
1563
+ super(message);
1564
+ this.reason = reason;
1565
+ this.name = "ViteDevError";
1566
+ }
1567
+ };
1568
+ REGEX_PRECEDING_CHARS = /* @__PURE__ */ new Set([
1569
+ "=",
1570
+ "(",
1571
+ ",",
1572
+ "[",
1573
+ "!",
1574
+ "&",
1575
+ "|",
1576
+ "?",
1577
+ ":",
1578
+ ";",
1579
+ "{",
1580
+ "}",
1581
+ "^",
1582
+ "~",
1583
+ "<",
1584
+ ">",
1585
+ "+",
1586
+ "-",
1587
+ "*",
1588
+ "/",
1589
+ "%"
1590
+ ]);
1591
+ REGEX_PRECEDING_KEYWORDS = /* @__PURE__ */ new Set([
1592
+ "return",
1593
+ "typeof",
1594
+ "instanceof",
1595
+ "in",
1596
+ "of",
1597
+ "new",
1598
+ "delete",
1599
+ "void",
1600
+ "throw",
1601
+ "case",
1602
+ "do",
1603
+ "else",
1604
+ "yield",
1605
+ "await"
1606
+ ]);
1607
+ isIdentStart = (ch) => /[A-Za-z_$]/.test(ch);
1608
+ isIdentPart = (ch) => /[A-Za-z0-9_$]/.test(ch);
1609
+ VITE_RESOLVE_SUFFIXES = [".ts", ".js", ".mjs", ".mts", ".vue", ".json", ".css"];
1610
+ INLINE_PREFIX = "/__vite_inline_";
1611
+ EXTERNAL_SPECIFIER = /^(?:https?:)?\/\//i;
1612
+ DATA_OR_BLOB = /^(?:data|blob):/i;
1613
+ MODULE_SCRIPT_SRC_RE = /<script\b([^>]*?)\btype\s*=\s*(["'])module\2([^>]*?)\bsrc\s*=\s*(["'])(.*?)\4([^>]*)><\/script>/gi;
1614
+ MODULE_SCRIPT_INLINE_RE = /<script\b([^>]*?)\btype\s*=\s*(["'])module\2([^>]*)>([\s\S]*?)<\/script>/gi;
1615
+ }
1616
+ });
1617
+
188
1618
  // src/vfs.ts
189
1619
  init_path();
190
1620
  var ensureAbs = (path) => path.startsWith("/") ? normalize(path) : `/${normalize(path).replace(/^\/+/, "")}`;
@@ -395,6 +1825,9 @@ var VirtualFileSystem = class {
395
1825
  }
396
1826
  };
397
1827
 
1828
+ // src/container.ts
1829
+ init_path();
1830
+
398
1831
  // src/shell.ts
399
1832
  init_path();
400
1833
 
@@ -414,9 +1847,12 @@ var SHELL_COMMANDS = [
414
1847
  "cd",
415
1848
  "head",
416
1849
  "tail",
1850
+ "curl",
1851
+ "wget",
417
1852
  "test",
418
1853
  "node",
419
1854
  "js",
1855
+ "vite",
420
1856
  "help"
421
1857
  ];
422
1858
  var EXTRA_COMMANDS = ["npm"];
@@ -721,6 +2157,33 @@ var Shell = class {
721
2157
  }
722
2158
  break;
723
2159
  }
2160
+ case "curl": {
2161
+ const outcome = await this.runCurl(argv.slice(1));
2162
+ stdout = outcome.stdout;
2163
+ stderr = outcome.stderr;
2164
+ exitCode = outcome.code;
2165
+ break;
2166
+ }
2167
+ case "wget": {
2168
+ const outcome = await this.runWget(argv.slice(1));
2169
+ stdout = outcome.stdout;
2170
+ stderr = outcome.stderr;
2171
+ exitCode = outcome.code;
2172
+ break;
2173
+ }
2174
+ case "vite": {
2175
+ if (this.ctx.vite === void 0)
2176
+ return {
2177
+ code: 1,
2178
+ stdout: "",
2179
+ stderr: "vite: \u672A\u88C5\u914D\u524D\u7AEF\u5F00\u53D1\u670D\u52A1\u5668\uFF08bootstrap \u4F1A\u6CE8\u5165\uFF1B\u88F8 Shell \u9700\u81EA\u884C\u7ED9 ctx.vite\uFF09\n"
2180
+ };
2181
+ const outcome = await this.runVite(argv.slice(1));
2182
+ stdout = outcome.stdout;
2183
+ stderr = outcome.stderr;
2184
+ exitCode = outcome.code;
2185
+ break;
2186
+ }
724
2187
  default:
725
2188
  stderr = `${command}: command not found
726
2189
  `;
@@ -743,6 +2206,168 @@ var Shell = class {
743
2206
  }
744
2207
  return out;
745
2208
  }
2209
+ /**
2210
+ * `curl [选项] <url>`(常用旗标最小子集):
2211
+ * - 响应体默认写 stdout(可 `|` 管道 / `>` 重定向);`-o <file>` 写 VFS 文件、`-o -` 显式 stdout;
2212
+ * - `-i/--include` 输出响应头 + 体;`-I/--head` 发 HEAD 且只输出响应头;
2213
+ * - `-X/--request`、`-H/--header`(可多次)、`-d/--data`(可多次,`&` 拼接,隐含 POST 与表单头)、
2214
+ * `-A/--user-agent`、`-u/--user`(转 Basic 认证)、`-f/--fail`(HTTP ≥400 退出码 22);
2215
+ * - `-s/-S/-L/-k/-g/-N/--compressed` 等常见旗标接受但无效果(仿真环境本就静默/跟随重定向/不校验证书);
2216
+ * - 裸主机名(`example.com/x`)按 curl 语义补 `http://`;网络故障退出码 7,用法错误 2。
2217
+ */
2218
+ async runCurl(args) {
2219
+ const flags = parseCurlArgs(args);
2220
+ if (flags.url === null) {
2221
+ return { code: 2, stdout: "", stderr: "curl: \u672A\u63D0\u4F9B URL\uFF08\u7528\u6CD5\uFF1Acurl [\u9009\u9879] <url>\uFF09\n" };
2222
+ }
2223
+ const url = normalizeUrl(flags.url);
2224
+ if (url === null)
2225
+ return { code: 3, stdout: "", stderr: `curl: (3) URL \u683C\u5F0F\u9519\u8BEF\uFF1A${flags.url}
2226
+ ` };
2227
+ const method = flags.head ? "HEAD" : flags.method ?? (flags.data.length > 0 ? "POST" : "GET");
2228
+ const headers = { ...flags.headers };
2229
+ const body = flags.data.length > 0 ? flags.data.join("&") : void 0;
2230
+ if (body !== void 0 && !("content-type" in headers)) {
2231
+ headers["content-type"] = "application/x-www-form-urlencoded";
2232
+ }
2233
+ let res;
2234
+ try {
2235
+ res = await this.netRequest(url, {
2236
+ method,
2237
+ headers,
2238
+ ...body === void 0 ? {} : { body }
2239
+ });
2240
+ } catch (error) {
2241
+ if (error instanceof NetCommandError && error.kind === "no-net")
2242
+ return { code: 1, stdout: "", stderr: `curl: ${error.message}
2243
+ ` };
2244
+ return {
2245
+ code: 7,
2246
+ stdout: "",
2247
+ stderr: `curl: (7) \u65E0\u6CD5\u8FDE\u63A5\u4E3B\u673A\uFF1A${error instanceof Error ? error.message : String(error)}
2248
+ `
2249
+ };
2250
+ }
2251
+ const head = flags.head || flags.include ? formatResponseHead(res) : "";
2252
+ let stdout;
2253
+ if (flags.output !== null && flags.output !== "-") {
2254
+ this.ctx.vfs.writeFile(this.resolve(flags.output), res.body);
2255
+ stdout = head;
2256
+ } else {
2257
+ stdout = head + (flags.head ? "" : res.body);
2258
+ }
2259
+ if (flags.fail && !res.ok) {
2260
+ return { code: 22, stdout, stderr: `curl: (22) HTTP \u8BF7\u6C42\u8FD4\u56DE\u9519\u8BEF\u7801 ${res.status}
2261
+ ` };
2262
+ }
2263
+ return { code: 0, stdout, stderr: "" };
2264
+ }
2265
+ /**
2266
+ * `wget [选项] <url>`(常用旗标最小子集):
2267
+ * - 默认按 URL 末级路径名落 VFS 文件(目录形态落 `index.html`),过程信息走 stderr;
2268
+ * - `-O <file>` 指定文件名、`-O -` 输出到 stdout;`-q/--quiet` 静默;`-S/--server-response` 打印响应头;
2269
+ * - HTTP ≥400 / 网络失败退出码 1 且不落文件(与 GNU wget 默认一致)。
2270
+ */
2271
+ async runWget(args) {
2272
+ const flags = parseWgetArgs(args);
2273
+ if (flags.url === null) {
2274
+ return { code: 1, stdout: "", stderr: "wget: \u672A\u63D0\u4F9B URL\uFF08\u7528\u6CD5\uFF1Awget [\u9009\u9879] <url>\uFF09\n" };
2275
+ }
2276
+ const url = normalizeUrl(flags.url);
2277
+ if (url === null) return { code: 1, stdout: "", stderr: `wget: URL \u683C\u5F0F\u9519\u8BEF\uFF1A${flags.url}
2278
+ ` };
2279
+ let parsed;
2280
+ try {
2281
+ parsed = new URL(url);
2282
+ } catch {
2283
+ return { code: 1, stdout: "", stderr: `wget: URL \u683C\u5F0F\u9519\u8BEF\uFF1A${url}
2284
+ ` };
2285
+ }
2286
+ let res;
2287
+ try {
2288
+ res = await this.netRequest(url, { method: "GET" });
2289
+ } catch (error) {
2290
+ if (error instanceof NetCommandError && error.kind === "no-net")
2291
+ return { code: 1, stdout: "", stderr: `wget: ${error.message}
2292
+ ` };
2293
+ const reason = error instanceof Error ? error.message : String(error);
2294
+ return { code: 1, stdout: "", stderr: `wget: \u65E0\u6CD5\u4E0B\u8F7D ${url}\uFF1A${reason}
2295
+ ` };
2296
+ }
2297
+ const toStdout = flags.output === "-";
2298
+ const fileName = flags.output !== null && flags.output !== "-" ? flags.output : wgetFileName(parsed);
2299
+ let stderr = "";
2300
+ if (!flags.quiet) {
2301
+ const type = res.headers["content-type"] ?? "application/octet-stream";
2302
+ const length = res.headers["content-length"] ?? String(new TextEncoder().encode(res.body).byteLength);
2303
+ stderr += `\u6B63\u5728\u8FDE\u63A5 ${parsed.hostname}...
2304
+ `;
2305
+ stderr += `HTTP \u8BF7\u6C42\u5DF2\u53D1\u9001\uFF0C\u6B63\u5728\u7B49\u5F85\u54CD\u5E94... ${res.status}${res.statusText ? ` ${res.statusText}` : ""}
2306
+ `;
2307
+ if (flags.serverResponse) stderr += formatResponseHead(res);
2308
+ stderr += `\u957F\u5EA6\uFF1A${length} [${type}]
2309
+ `;
2310
+ if (!toStdout) stderr += `\u6B63\u5728\u4FDD\u5B58\u5230: \u201C${fileName}\u201D
2311
+ `;
2312
+ }
2313
+ if (!res.ok) {
2314
+ return { code: 1, stdout: "", stderr: `${stderr}wget: \u9519\u8BEF\uFF1A\u670D\u52A1\u5668\u8FD4\u56DE HTTP ${res.status}
2315
+ ` };
2316
+ }
2317
+ if (toStdout) return { code: 0, stdout: res.body, stderr };
2318
+ this.ctx.vfs.writeFile(this.resolve(fileName), res.body);
2319
+ if (!flags.quiet) stderr += `${fileName} \u5DF2\u4FDD\u5B58 [${res.body.length} \u5B57\u8282]
2320
+ `;
2321
+ return { code: 0, stdout: "", stderr };
2322
+ }
2323
+ /**
2324
+ * `vite [子命令|目录]`:
2325
+ * - `vite` / `vite dev [dir]`:启动浏览器内 Vite 兼容 dev server(`dir` 为 root,缺省 `/`;
2326
+ * `--port` 等旗标接受但无效果——端口是虚拟语义值);
2327
+ * - `vite stop`:停止并释放;
2328
+ * - `vite build`:首版明确不支持(dev 语义优先),如实报错。
2329
+ * dev server 常驻在容器层(`serverready` 事件 + HMR),命令本身立即返回——与真实
2330
+ * vite 的前台常驻进程形态不同,属仿真终端的取舍(见 vite-dev.ts 文件头)。
2331
+ */
2332
+ async runVite(args) {
2333
+ const positional = args.filter((a) => !a.startsWith("-"));
2334
+ const sub = positional[0] ?? "";
2335
+ if (sub === "stop") {
2336
+ const outcome2 = await this.ctx.vite.stop();
2337
+ return outcome2.code === 0 ? { ...outcome2, stderr: "" } : { code: outcome2.code, stdout: "", stderr: outcome2.stdout };
2338
+ }
2339
+ if (sub === "build")
2340
+ return {
2341
+ code: 1,
2342
+ stdout: "",
2343
+ stderr: "vite build: \u6682\u4E0D\u652F\u6301\uFF08\u6D4F\u89C8\u5668\u5185 vite \u9996\u7248\u53EA\u63D0\u4F9B dev server\uFF1B\u53D1\u5E03\u8D70\u524D\u7AEF\u53D1\u5E03\u7BA1\u7EBF\uFF09\n"
2344
+ };
2345
+ const rootArgs = sub === "" || sub === "dev" || sub === "serve" ? positional.slice(1) : [sub];
2346
+ const outcome = await this.ctx.vite.start(rootArgs);
2347
+ return outcome.code === 0 ? { ...outcome, stderr: "" } : { code: outcome.code, stdout: "", stderr: outcome.stdout };
2348
+ }
2349
+ /** 经 net 端口发请求;端口缺失 / 网络失败归一为 NetCommandError(curl/wget 各自映射退出码与文案)。 */
2350
+ async netRequest(url, init) {
2351
+ if (this.ctx.net === void 0) {
2352
+ throw new NetCommandError(
2353
+ "no-net",
2354
+ "\u672A\u6CE8\u5165\u7F51\u7EDC\u7AEF\u53E3\uFF08\u6D4F\u89C8\u5668\u7AEF\u7ECF\u5E73\u53F0 HTTP \u4E2D\u7EE7\u8BBF\u95EE\uFF1Bbootstrap \u9700\u63D0\u4F9B httpRelayBaseUrl\uFF09"
2355
+ );
2356
+ }
2357
+ try {
2358
+ const res = await this.ctx.net(url, init);
2359
+ return {
2360
+ ok: res.ok,
2361
+ status: res.status,
2362
+ statusText: res.statusText,
2363
+ headers: res.headers,
2364
+ body: await res.text()
2365
+ };
2366
+ } catch (error) {
2367
+ if (error instanceof NetCommandError) throw error;
2368
+ throw new NetCommandError("network", error instanceof Error ? error.message : String(error));
2369
+ }
2370
+ }
746
2371
  /**
747
2372
  * 对当前输入行求 Tab 补全候选(FE-022):命令位补内建命令名,参数位补 VFS 路径。
748
2373
  * 无候选不抛错(Tab 不该让终端报错),由调用方决定「不响应」还是「列出可能项」。
@@ -756,6 +2381,200 @@ var Shell = class {
756
2381
  return join(this.ctx.getCwd(), target);
757
2382
  }
758
2383
  };
2384
+ var NetCommandError = class extends Error {
2385
+ constructor(kind, message) {
2386
+ super(message);
2387
+ this.kind = kind;
2388
+ this.name = "NetCommandError";
2389
+ }
2390
+ };
2391
+ var CURL_BOOLEAN_NOOP = /* @__PURE__ */ new Set([
2392
+ "-s",
2393
+ "--silent",
2394
+ "-S",
2395
+ "--show-error",
2396
+ "-L",
2397
+ "--location",
2398
+ "-k",
2399
+ "--insecure",
2400
+ "-g",
2401
+ "--globoff",
2402
+ "-N",
2403
+ "--no-buffer",
2404
+ "--compressed",
2405
+ "-#",
2406
+ "--progress-bar",
2407
+ "-v",
2408
+ "--verbose",
2409
+ "-G",
2410
+ "--get"
2411
+ ]);
2412
+ var WGET_BOOLEAN_NOOP = /* @__PURE__ */ new Set([
2413
+ "--no-check-certificate",
2414
+ "-nc",
2415
+ "--no-clobber",
2416
+ "-c",
2417
+ "--continue",
2418
+ "-nv",
2419
+ "--no-verbose",
2420
+ "--content-on-error"
2421
+ ]);
2422
+ function matchValueFlag(arg, name, longNames, consume) {
2423
+ if (arg === name || longNames.includes(arg)) return { matched: true, value: consume() };
2424
+ for (const long of longNames) {
2425
+ if (arg.startsWith(`${long}=`)) return { matched: true, value: arg.slice(long.length + 1) };
2426
+ }
2427
+ return { matched: false, value: null };
2428
+ }
2429
+ function expandShortArgs(args, valueFlags) {
2430
+ const out = [];
2431
+ for (const arg of args) {
2432
+ const cluster = /^-([A-Za-z]+)$/.exec(arg);
2433
+ if (cluster === null) {
2434
+ out.push(arg);
2435
+ continue;
2436
+ }
2437
+ const chars = cluster[1];
2438
+ for (let j = 0; j < chars.length; j++) {
2439
+ const c = chars[j];
2440
+ out.push(`-${c}`);
2441
+ if (valueFlags.has(c)) {
2442
+ const rest = chars.slice(j + 1);
2443
+ if (rest !== "") out.push(rest);
2444
+ break;
2445
+ }
2446
+ }
2447
+ }
2448
+ return out;
2449
+ }
2450
+ function parseCurlArgs(rawArgs) {
2451
+ const args = expandShortArgs(rawArgs, /* @__PURE__ */ new Set(["X", "H", "d", "o", "A", "u", "m"]));
2452
+ const flags = {
2453
+ url: null,
2454
+ method: null,
2455
+ headers: {},
2456
+ data: [],
2457
+ include: false,
2458
+ head: false,
2459
+ output: null,
2460
+ fail: false
2461
+ };
2462
+ for (let i = 0; i < args.length; i++) {
2463
+ const arg = args[i];
2464
+ const consume = () => {
2465
+ const v = args[i + 1];
2466
+ if (v !== void 0) i++;
2467
+ return v ?? "";
2468
+ };
2469
+ let m = matchValueFlag(arg, "-X", ["--request"], consume);
2470
+ if (m.matched) {
2471
+ flags.method = (m.value ?? "").toUpperCase();
2472
+ continue;
2473
+ }
2474
+ m = matchValueFlag(arg, "-H", ["--header"], consume);
2475
+ if (m.matched) {
2476
+ const raw = m.value ?? "";
2477
+ const colon = raw.indexOf(":");
2478
+ if (colon > 0)
2479
+ flags.headers[raw.slice(0, colon).trim().toLowerCase()] = raw.slice(colon + 1).trim();
2480
+ continue;
2481
+ }
2482
+ m = matchValueFlag(arg, "-A", ["--user-agent"], consume);
2483
+ if (m.matched) {
2484
+ flags.headers["user-agent"] = m.value ?? "";
2485
+ continue;
2486
+ }
2487
+ m = matchValueFlag(arg, "-u", ["--user"], consume);
2488
+ if (m.matched) {
2489
+ flags.headers["authorization"] = `Basic ${btoa(m.value ?? "")}`;
2490
+ continue;
2491
+ }
2492
+ m = matchValueFlag(
2493
+ arg,
2494
+ "-d",
2495
+ ["--data", "--data-raw", "--data-binary", "--data-urlencode"],
2496
+ consume
2497
+ );
2498
+ if (m.matched) {
2499
+ flags.data.push(m.value ?? "");
2500
+ continue;
2501
+ }
2502
+ m = matchValueFlag(arg, "-o", ["--output"], consume);
2503
+ if (m.matched) {
2504
+ flags.output = m.value;
2505
+ continue;
2506
+ }
2507
+ m = matchValueFlag(arg, "-m", ["--max-time", "--connect-timeout"], consume);
2508
+ if (m.matched) continue;
2509
+ if (arg === "-i" || arg === "--include") {
2510
+ flags.include = true;
2511
+ continue;
2512
+ }
2513
+ if (arg === "-I" || arg === "--head") {
2514
+ flags.head = true;
2515
+ continue;
2516
+ }
2517
+ if (arg === "-f" || arg === "--fail") {
2518
+ flags.fail = true;
2519
+ continue;
2520
+ }
2521
+ if (CURL_BOOLEAN_NOOP.has(arg) || arg.startsWith("-")) continue;
2522
+ if (flags.url === null) flags.url = arg;
2523
+ }
2524
+ return flags;
2525
+ }
2526
+ function parseWgetArgs(rawArgs) {
2527
+ const args = expandShortArgs(rawArgs, /* @__PURE__ */ new Set(["O"]));
2528
+ const flags = { url: null, output: null, quiet: false, serverResponse: false };
2529
+ for (let i = 0; i < args.length; i++) {
2530
+ const arg = args[i];
2531
+ const consume = () => {
2532
+ const v = args[i + 1];
2533
+ if (v !== void 0) i++;
2534
+ return v ?? "";
2535
+ };
2536
+ const m = matchValueFlag(arg, "-O", ["--output-document"], consume);
2537
+ if (m.matched) {
2538
+ flags.output = m.value;
2539
+ continue;
2540
+ }
2541
+ if (arg === "-q" || arg === "--quiet") {
2542
+ flags.quiet = true;
2543
+ continue;
2544
+ }
2545
+ if (arg === "-S" || arg === "--server-response") {
2546
+ flags.serverResponse = true;
2547
+ continue;
2548
+ }
2549
+ if (WGET_BOOLEAN_NOOP.has(arg) || arg.startsWith("-")) continue;
2550
+ if (flags.url === null) flags.url = arg;
2551
+ }
2552
+ return flags;
2553
+ }
2554
+ function normalizeUrl(raw) {
2555
+ if (raw.startsWith("/")) return null;
2556
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(raw)) return raw;
2557
+ return `http://${raw}`;
2558
+ }
2559
+ function formatResponseHead(res) {
2560
+ const reason = res.statusText !== "" ? ` ${res.statusText}` : "";
2561
+ let head = `HTTP/1.1 ${res.status}${reason}\r
2562
+ `;
2563
+ for (const [key, value] of Object.entries(res.headers)) head += `${key}: ${value}\r
2564
+ `;
2565
+ return `${head}\r
2566
+ `;
2567
+ }
2568
+ function wgetFileName(url) {
2569
+ const segments = url.pathname.split("/").filter((s) => s !== "");
2570
+ const last = segments.length === 0 ? void 0 : segments[segments.length - 1];
2571
+ if (last === void 0) return "index.html";
2572
+ try {
2573
+ return decodeURIComponent(last);
2574
+ } catch {
2575
+ return last;
2576
+ }
2577
+ }
759
2578
 
760
2579
  // src/tar.ts
761
2580
  var BLOCK = 512;
@@ -780,237 +2599,72 @@ function parseOctalSize(bytes, start, length) {
780
2599
  }
781
2600
  function assertSafePath(path) {
782
2601
  if (path === "" || path.startsWith("/") || path.startsWith("\\"))
783
- throw new Error(`tar \u6761\u76EE\u8DEF\u5F84\u975E\u6CD5\uFF08\u7EDD\u5BF9\u8DEF\u5F84\u6216\u4E3A\u7A7A\uFF09\uFF1A"${path}"`);
784
- for (const segment of path.split("/")) {
785
- if (segment === "..") throw new Error(`tar \u6761\u76EE\u8DEF\u5F84\u542B ".." \u7A7F\u8D8A\uFF0C\u5DF2\u62D2\u7EDD\uFF1A"${path}"`);
786
- }
787
- }
788
- async function gunzip(bytes) {
789
- if (bytes.length < 2 || bytes[0] !== GZIP_MAGIC_0 || bytes[1] !== GZIP_MAGIC_1) {
790
- throw new Error("tarball \u4E0D\u662F gzip \u6570\u636E\uFF08\u7F3A\u5C11 1f 8b \u9B54\u6570\uFF09\uFF0C\u65E0\u6CD5\u89E3\u5305");
791
- }
792
- const stream = new Blob([bytes]).stream().pipeThrough(new DecompressionStream("gzip"));
793
- const buffer = await new Response(stream).arrayBuffer();
794
- return new Uint8Array(buffer);
795
- }
796
- function unpackTar(bytes) {
797
- const entries = [];
798
- let offset = 0;
799
- let longName = null;
800
- while (offset + BLOCK <= bytes.length) {
801
- const header = bytes.subarray(offset, offset + BLOCK);
802
- if (header.every((byte) => byte === 0)) break;
803
- const typeflag = String.fromCharCode(header[156]);
804
- const size = parseOctalSize(header, 124, 12);
805
- let name = readString(bytes, offset, 100);
806
- const prefix = readString(bytes, offset + 345, 155);
807
- if (prefix !== "") name = `${prefix}/${name}`;
808
- const dataStart = offset + BLOCK;
809
- const data = bytes.subarray(dataStart, dataStart + size);
810
- offset = dataStart + Math.ceil(size / BLOCK) * BLOCK;
811
- if (typeflag === "L") {
812
- longName = new TextDecoder("utf-8").decode(data).replace(/\0+$/g, "").trim();
813
- continue;
814
- }
815
- if (typeflag === "x" || typeflag === "g") continue;
816
- if (typeflag === "5") continue;
817
- if (typeflag !== "0" && typeflag !== "\0") {
818
- throw new Error(`tar \u6761\u76EE\u7C7B\u578B "${typeflag}" \u4E0D\u652F\u6301\uFF08\u53EA\u63A5\u53D7\u666E\u901A\u6587\u4EF6\u4E0E\u76EE\u5F55\uFF09\uFF1A"${name}"`);
819
- }
820
- if (longName !== null) {
821
- name = longName;
822
- longName = null;
823
- }
824
- assertSafePath(name);
825
- entries.push({ path: name, contents: new Uint8Array(data) });
826
- }
827
- return entries;
828
- }
829
- async function unpackNpmTarball(bytes) {
830
- const tar = unpackTar(await gunzip(bytes));
831
- if (tar.length === 0) throw new Error("tarball \u89E3\u5305\u540E\u4E3A\u7A7A\uFF0C\u6CA1\u6709\u4EFB\u4F55\u6587\u4EF6\u6761\u76EE");
832
- const out = [];
833
- for (const entry of tar) {
834
- if (!entry.path.startsWith("package/")) {
835
- throw new Error(
836
- `tarball \u9876\u5C42\u76EE\u5F55\u5F02\u5E38\uFF08npm registry \u5F52\u6863\u5E94\u5168\u90E8\u4F4D\u4E8E "package/" \u4E0B\uFF09\uFF1A"${entry.path}"`
837
- );
838
- }
839
- out.push({ path: entry.path.slice("package/".length), contents: entry.contents });
840
- }
841
- if (!out.some((entry) => entry.path === "package.json")) {
842
- throw new Error("tarball \u7F3A\u5C11 package.json\uFF0C\u62D2\u7EDD\u89E3\u5305");
843
- }
844
- return out;
845
- }
846
-
847
- // src/node-resolve.ts
848
- init_path();
849
- var RESOLVE_EXTENSIONS = [".js", ".mjs", ".cjs", ".json"];
850
- var ResolveError = class extends Error {
851
- constructor(message) {
852
- super(message);
853
- this.name = "ResolveError";
854
- }
855
- };
856
- function parsePackageMeta(content, context) {
857
- let parsed;
858
- try {
859
- parsed = JSON.parse(content);
860
- } catch {
861
- throw new ResolveError(`${context} \u4E0D\u662F\u5408\u6CD5 JSON`);
862
- }
863
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
864
- throw new ResolveError(`${context} \u9876\u5C42\u5FC5\u987B\u662F\u5BF9\u8C61`);
865
- }
866
- return parsed;
867
- }
868
- function withinPackage(pkgDirAbs, rel, context) {
869
- if (typeof rel !== "string" || rel === "") {
870
- throw new ResolveError(`${context}\uFF1A\u5165\u53E3\u8DEF\u5F84\u5FC5\u987B\u662F\u5B57\u7B26\u4E32`);
871
- }
872
- if (!rel.startsWith("./") && !rel.startsWith("../") && rel.startsWith("/")) {
873
- throw new ResolveError(`${context}\uFF1A\u5165\u53E3\u8DEF\u5F84 "${rel}" \u5FC5\u987B\u662F\u5305\u5185\u76F8\u5BF9\u8DEF\u5F84\uFF08\u4EE5 ./ \u5F00\u5934\uFF09`);
874
- }
875
- const abs = join(pkgDirAbs, rel.startsWith(".") ? rel : `./${rel}`);
876
- if (!abs.startsWith(`${pkgDirAbs}/`)) {
877
- throw new ResolveError(`${context}\uFF1A\u5165\u53E3\u8DEF\u5F84 "${rel}" \u8D8A\u51FA\u5305\u76EE\u5F55\uFF0C\u5DF2\u62D2\u7EDD`);
878
- }
879
- return abs;
880
- }
881
- function resolvePackageEntry(meta, pkgDirAbs, condition) {
882
- const context = `\u5305 ${meta.name ?? meta.version ?? pkgDirAbs} \u7684 exports/main \u58F0\u660E`;
883
- const exp = meta.exports;
884
- if (exp !== void 0 && exp !== null) {
885
- if (typeof exp === "string") return withinPackage(pkgDirAbs, exp, context);
886
- if (typeof exp !== "object" || Array.isArray(exp)) {
887
- throw new ResolveError(`${context} \u5F62\u6001\u4E0D\u652F\u6301\uFF08exports \u53EA\u80FD\u662F\u5B57\u7B26\u4E32\u6216\u5BF9\u8C61\uFF09`);
888
- }
889
- const dot = exp["."];
890
- if (dot === void 0) {
891
- throw new ResolveError(
892
- `${context} \u53EA\u58F0\u660E\u4E86\u5B50\u8DEF\u5F84\u6620\u5C04\u3001\u6CA1\u6709 "." \u5165\u53E3\uFF0C\u5F53\u524D\u4EC5\u652F\u6301 "." \u4E0E\u5B57\u7B26\u4E32\u5F62\u6001`
893
- );
894
- }
895
- if (typeof dot === "string") return withinPackage(pkgDirAbs, dot, context);
896
- if (dot === null)
897
- throw new ResolveError(`${context}\uFF1Aexports["."] \u4E3A null\uFF08\u8BE5\u6761\u4EF6\u88AB\u663E\u5F0F\u6392\u9664\uFF09\uFF0C\u65E0\u6CD5\u89E3\u6790\u5165\u53E3`);
898
- if (typeof dot !== "object" || Array.isArray(dot)) {
899
- throw new ResolveError(`${context}\uFF1Aexports["."] \u5F62\u6001\u4E0D\u652F\u6301\uFF08\u4EC5\u63A5\u53D7\u5B57\u7B26\u4E32\u6216\u6761\u4EF6\u5BF9\u8C61\uFF09`);
900
- }
901
- const conditions = dot;
902
- const order = condition === "import" ? ["import", "node", "default"] : ["require", "node", "default"];
903
- for (const key of order) {
904
- const value = conditions[key];
905
- if (typeof value === "string") return withinPackage(pkgDirAbs, value, context);
906
- if (value !== void 0 && (typeof value !== "object" || value === null)) {
907
- throw new ResolveError(
908
- `${context}\uFF1Aexports["."]["${key}"] \u5F62\u6001\u4E0D\u652F\u6301\uFF08\u4EC5\u63A5\u53D7\u5B57\u7B26\u4E32\u6216 null\uFF09`
909
- );
910
- }
911
- }
912
- throw new ResolveError(
913
- `${context}\uFF1Aexports["."] \u6761\u4EF6\u5BF9\u8C61\u91CC\u6CA1\u6709 ${condition}/node/default \u5B57\u7B26\u4E32\u5165\u53E3\uFF08\u5B50\u8DEF\u5F84/\u5D4C\u5957\u6761\u4EF6\u4E0D\u652F\u6301\uFF09`
914
- );
915
- }
916
- if (meta.main !== void 0) {
917
- if (typeof meta.main !== "string") {
918
- throw new ResolveError(`${context}\uFF1Amain \u5FC5\u987B\u662F\u5B57\u7B26\u4E32`);
919
- }
920
- return withinPackage(pkgDirAbs, meta.main, context);
921
- }
922
- return join(pkgDirAbs, "index.js");
923
- }
924
- function splitPackageSpecifier(spec) {
925
- if (spec.startsWith("@")) {
926
- const first = spec.indexOf("/");
927
- if (first === -1) return { name: spec, subpath: "" };
928
- const second = spec.indexOf("/", first + 1);
929
- if (second === -1) return { name: spec, subpath: "" };
930
- return { name: spec.slice(0, second), subpath: spec.slice(second + 1) };
931
- }
932
- const slash = spec.indexOf("/");
933
- if (slash === -1) return { name: spec, subpath: "" };
934
- return { name: spec.slice(0, slash), subpath: spec.slice(slash + 1) };
935
- }
936
- function asFile(fs, baseAbs) {
937
- if (fs.exists(baseAbs) && !fsIsDirectory(fs, baseAbs)) return baseAbs;
938
- for (const ext of RESOLVE_EXTENSIONS) {
939
- const candidate = `${baseAbs}${ext}`;
940
- if (fs.exists(candidate) && !fsIsDirectory(fs, candidate)) return candidate;
2602
+ throw new Error(`tar \u6761\u76EE\u8DEF\u5F84\u975E\u6CD5\uFF08\u7EDD\u5BF9\u8DEF\u5F84\u6216\u4E3A\u7A7A\uFF09\uFF1A"${path}"`);
2603
+ for (const segment of path.split("/")) {
2604
+ if (segment === "..") throw new Error(`tar \u6761\u76EE\u8DEF\u5F84\u542B ".." \u7A7F\u8D8A\uFF0C\u5DF2\u62D2\u7EDD\uFF1A"${path}"`);
941
2605
  }
942
- return null;
943
2606
  }
944
- function asDirectory(fs, dirAbs) {
945
- if (!fs.exists(dirAbs) || !fsIsDirectory(fs, dirAbs)) return null;
946
- const manifest = `${dirAbs}/package.json`;
947
- if (fs.exists(manifest)) {
948
- const meta = parsePackageMeta(fs.readFile(manifest), manifest);
949
- const entry = resolvePackageEntry(meta, dirAbs, "require");
950
- const hit = asFile(fs, entry);
951
- if (hit !== null) return hit;
2607
+ async function gunzip(bytes) {
2608
+ if (bytes.length < 2 || bytes[0] !== GZIP_MAGIC_0 || bytes[1] !== GZIP_MAGIC_1) {
2609
+ throw new Error("tarball \u4E0D\u662F gzip \u6570\u636E\uFF08\u7F3A\u5C11 1f 8b \u9B54\u6570\uFF09\uFF0C\u65E0\u6CD5\u89E3\u5305");
952
2610
  }
953
- return asFile(fs, join(dirAbs, "index"));
954
- }
955
- function fsIsDirectory(fs, path) {
956
- const probe = fs;
957
- return probe.isDirectory?.(path) ?? false;
2611
+ const stream = new Blob([bytes]).stream().pipeThrough(new DecompressionStream("gzip"));
2612
+ const buffer = await new Response(stream).arrayBuffer();
2613
+ return new Uint8Array(buffer);
958
2614
  }
959
- function resolveImport(fs, specifier, fromFileAbs, condition = "require") {
960
- if (specifier === "") throw new ResolveError("\u7A7A\u8BF4\u660E\u7B26\uFF1A\u65E0\u6CD5\u89E3\u6790\u6A21\u5757");
961
- if (specifier.startsWith("./") || specifier.startsWith("../")) {
962
- const base = join(dirname(fromFileAbs), specifier);
963
- const hit = asFile(fs, base) ?? asDirectory(fs, base);
964
- if (hit === null) {
965
- throw new ResolveError(
966
- `\u627E\u4E0D\u5230\u76F8\u5BF9\u6A21\u5757 "${specifier}"\uFF08\u81EA ${dirname(fromFileAbs)}\uFF0C\u8BD5\u8FC7\u6269\u5C55\u540D ${RESOLVE_EXTENSIONS.join("/")} \u4E0E\u76EE\u5F55\u7D22\u5F15\uFF09`
967
- );
2615
+ function unpackTar(bytes) {
2616
+ const entries = [];
2617
+ let offset = 0;
2618
+ let longName = null;
2619
+ while (offset + BLOCK <= bytes.length) {
2620
+ const header = bytes.subarray(offset, offset + BLOCK);
2621
+ if (header.every((byte) => byte === 0)) break;
2622
+ const typeflag = String.fromCharCode(header[156]);
2623
+ const size = parseOctalSize(header, 124, 12);
2624
+ let name = readString(bytes, offset, 100);
2625
+ const prefix = readString(bytes, offset + 345, 155);
2626
+ if (prefix !== "") name = `${prefix}/${name}`;
2627
+ const dataStart = offset + BLOCK;
2628
+ const data = bytes.subarray(dataStart, dataStart + size);
2629
+ offset = dataStart + Math.ceil(size / BLOCK) * BLOCK;
2630
+ if (typeflag === "L") {
2631
+ longName = new TextDecoder("utf-8").decode(data).replace(/\0+$/g, "").trim();
2632
+ continue;
968
2633
  }
969
- return hit;
970
- }
971
- if (specifier.startsWith("/")) {
972
- const hit = asFile(fs, specifier) ?? asDirectory(fs, specifier);
973
- if (hit === null) throw new ResolveError(`\u627E\u4E0D\u5230\u7EDD\u5BF9\u8DEF\u5F84\u6A21\u5757 "${specifier}"`);
974
- return hit;
975
- }
976
- const { name, subpath } = splitPackageSpecifier(specifier);
977
- if (name.startsWith("node:")) {
978
- throw new ResolveError(`\u6D4F\u89C8\u5668\u6C99\u7BB1\u4E0D\u63D0\u4F9B Node \u5185\u5EFA\u6A21\u5757 "${specifier}"`);
2634
+ if (typeflag === "x" || typeflag === "g") continue;
2635
+ if (typeflag === "5") continue;
2636
+ if (typeflag !== "0" && typeflag !== "\0") {
2637
+ throw new Error(`tar \u6761\u76EE\u7C7B\u578B "${typeflag}" \u4E0D\u652F\u6301\uFF08\u53EA\u63A5\u53D7\u666E\u901A\u6587\u4EF6\u4E0E\u76EE\u5F55\uFF09\uFF1A"${name}"`);
2638
+ }
2639
+ if (longName !== null) {
2640
+ name = longName;
2641
+ longName = null;
2642
+ }
2643
+ assertSafePath(name);
2644
+ entries.push({ path: name, contents: new Uint8Array(data) });
979
2645
  }
980
- let dir = dirname(fromFileAbs);
981
- for (; ; ) {
982
- const pkgDir = join(dir, "node_modules", name);
983
- if (fs.exists(pkgDir) && fsIsDirectory(fs, pkgDir)) {
984
- if (subpath === "") {
985
- const manifest = `${pkgDir}/package.json`;
986
- if (fs.exists(manifest)) {
987
- const meta = parsePackageMeta(fs.readFile(manifest), manifest);
988
- const entry = resolvePackageEntry(meta, pkgDir, condition);
989
- const hit = asFile(fs, entry) ?? asDirectory(fs, entry);
990
- if (hit !== null) return hit;
991
- } else {
992
- const hit = asFile(fs, join(pkgDir, "index")) ?? asDirectory(fs, pkgDir);
993
- if (hit !== null) return hit;
994
- }
995
- } else {
996
- const base = join(pkgDir, subpath);
997
- const hit = asFile(fs, base) ?? asDirectory(fs, base);
998
- if (hit !== null) return hit;
999
- }
1000
- throw new ResolveError(
1001
- `\u5728 ${pkgDir} \u627E\u5230\u4E86\u5305 "${name}"\uFF0C\u4F46\u89E3\u6790\u8BF4\u660E\u7B26 "${specifier}" \u5931\u8D25\uFF08\u5B50\u8DEF\u5F84\u4E0D\u5B58\u5728\uFF0C\u6216 exports/main \u6307\u5411\u7684\u5165\u53E3\u6587\u4EF6\u7F3A\u5931\uFF09`
2646
+ return entries;
2647
+ }
2648
+ async function unpackNpmTarball(bytes) {
2649
+ const tar = unpackTar(await gunzip(bytes));
2650
+ if (tar.length === 0) throw new Error("tarball \u89E3\u5305\u540E\u4E3A\u7A7A\uFF0C\u6CA1\u6709\u4EFB\u4F55\u6587\u4EF6\u6761\u76EE");
2651
+ const out = [];
2652
+ for (const entry of tar) {
2653
+ if (!entry.path.startsWith("package/")) {
2654
+ throw new Error(
2655
+ `tarball \u9876\u5C42\u76EE\u5F55\u5F02\u5E38\uFF08npm registry \u5F52\u6863\u5E94\u5168\u90E8\u4F4D\u4E8E "package/" \u4E0B\uFF09\uFF1A"${entry.path}"`
1002
2656
  );
1003
2657
  }
1004
- const parent = dirname(dir);
1005
- if (parent === dir) break;
1006
- dir = parent;
2658
+ out.push({ path: entry.path.slice("package/".length), contents: entry.contents });
1007
2659
  }
1008
- throw new ResolveError(
1009
- `\u627E\u4E0D\u5230\u5305 "${specifier}"\uFF1A${dirname(fromFileAbs)} \u53CA\u5176\u5404\u7EA7\u7236\u76EE\u5F55\u4E0B\u90FD\u6CA1\u6709 node_modules/${name}\uFF08\u5148\u5728\u7EC8\u7AEF npm install ${name}\uFF09`
1010
- );
2660
+ if (!out.some((entry) => entry.path === "package.json")) {
2661
+ throw new Error("tarball \u7F3A\u5C11 package.json\uFF0C\u62D2\u7EDD\u89E3\u5305");
2662
+ }
2663
+ return out;
1011
2664
  }
1012
2665
 
1013
2666
  // src/npm-client.ts
2667
+ init_node_resolve();
1014
2668
  var DEFAULT_MAX_INSTALL_DEPTH = 5;
1015
2669
  var defaultFetch = (url, init) => globalThis.fetch(url, init).then((res) => res);
1016
2670
  function parseSpec(spec) {
@@ -1161,7 +2815,58 @@ function createNpmClient(options) {
1161
2815
  };
1162
2816
  }
1163
2817
 
2818
+ // src/relay-fetch.ts
2819
+ var defaultFetch2 = (url, init) => globalThis.fetch(url, init).then((res) => res);
2820
+ function createRelayFetch(options) {
2821
+ const fetchImpl = options.fetchImpl ?? defaultFetch2;
2822
+ const base = options.baseUrl.replace(/\/+$/, "");
2823
+ return async (url, init) => {
2824
+ let res;
2825
+ try {
2826
+ res = await fetchImpl(`${base}/fetch`, {
2827
+ method: "POST",
2828
+ headers: { "content-type": "application/json" },
2829
+ body: JSON.stringify({
2830
+ url,
2831
+ method: init?.method ?? "GET",
2832
+ ...init?.headers === void 0 ? {} : { headers: init.headers },
2833
+ ...init?.body === void 0 ? {} : { body: init.body }
2834
+ })
2835
+ });
2836
+ } catch (error) {
2837
+ const reason = error instanceof Error ? error.message : String(error);
2838
+ throw new Error(`HTTP \u4E2D\u7EE7\u4E0D\u53EF\u8FBE\uFF08${base}/fetch\uFF0C${reason}\uFF09`, { cause: error });
2839
+ }
2840
+ if (!res.ok) {
2841
+ let message = `HTTP \u4E2D\u7EE7\u8FD4\u56DE ${res.status}`;
2842
+ try {
2843
+ const data = await res.json();
2844
+ if (data.error?.message) message = data.error.message;
2845
+ } catch {
2846
+ }
2847
+ throw new Error(message);
2848
+ }
2849
+ const env = await res.json();
2850
+ return {
2851
+ ok: env.ok,
2852
+ status: env.status,
2853
+ statusText: env.statusText,
2854
+ headers: env.headers ?? {},
2855
+ text: async () => env.body,
2856
+ json: async () => JSON.parse(env.body),
2857
+ arrayBuffer: async () => {
2858
+ const bytes = new TextEncoder().encode(env.body);
2859
+ return bytes.buffer.slice(
2860
+ bytes.byteOffset,
2861
+ bytes.byteOffset + bytes.byteLength
2862
+ );
2863
+ }
2864
+ };
2865
+ };
2866
+ }
2867
+
1164
2868
  // src/module-loader.ts
2869
+ init_node_resolve();
1165
2870
  function interopDefault(value) {
1166
2871
  if (value !== null && typeof value === "object" && "__esModule" in value) {
1167
2872
  return value.default;
@@ -1367,614 +3072,8 @@ function createWorkerRuntime(vfs, options = {}) {
1367
3072
  };
1368
3073
  }
1369
3074
 
1370
- // src/strip-types.ts
1371
- var UnsupportedTsSyntaxError = class extends Error {
1372
- constructor(construct, line) {
1373
- super(`\u4E0D\u53D7\u652F\u6301\u7684 TypeScript \u8BED\u6CD5\uFF1A${construct}\uFF08\u7B2C ${line} \u884C\uFF09\u2014\u2014\u6D4F\u89C8\u5668\u6D4B\u8BD5\u6C99\u7BB1\u53EA\u64E6\u9664\u7C7B\u578B\u6807\u6CE8`);
1374
- this.construct = construct;
1375
- this.line = line;
1376
- this.name = "UnsupportedTsSyntaxError";
1377
- }
1378
- };
1379
- var IDENT_START = /[A-Za-z_$]/;
1380
- var IDENT_PART = /[A-Za-z0-9_$]/;
1381
- var DECL_KEYWORDS = /* @__PURE__ */ new Set(["const", "let", "var"]);
1382
- var TS_MODIFIERS = /* @__PURE__ */ new Set([
1383
- "private",
1384
- "protected",
1385
- "public",
1386
- "readonly",
1387
- "abstract",
1388
- "override",
1389
- "declare"
1390
- ]);
1391
- var ANNOTATION_LEADERS = /* @__PURE__ */ new Set(["(", ",", "{", ";", "erased", "modifier"]);
1392
- function isAnnotationLeader(token) {
1393
- return ANNOTATION_LEADERS.has(token) || TS_MODIFIERS.has(token);
1394
- }
1395
- var Eraser = class {
1396
- constructor(src) {
1397
- this.src = src;
1398
- this.chars = [...src];
1399
- }
1400
- chars;
1401
- tokens = [];
1402
- frames = [];
1403
- /** 刚消费 `class` 头:下一个 `{` 是类体起始。 */
1404
- pendingClassBody = false;
1405
- /** 刚消费 `=>`:其后的 `(` 是箭头函数参数列表(声明位)。 */
1406
- afterArrow = false;
1407
- /** 刚消费 `function` 关键字:其后的标识符是函数名,再后是参数列表。 */
1408
- afterFunctionKeyword = false;
1409
- /** 最近一次 `)` 闭合的是不是参数列表(返回值标注判据)。 */
1410
- justClosedDeclareParen = false;
1411
- i = 0;
1412
- run() {
1413
- while (this.i < this.src.length) {
1414
- if (/\s/.test(this.ch())) {
1415
- this.i++;
1416
- continue;
1417
- }
1418
- if (this.copyTrivia()) continue;
1419
- if (this.copyLiteral()) continue;
1420
- if (this.copyRegexIfNeeded()) continue;
1421
- if (this.readNumber()) continue;
1422
- const word = this.readWord();
1423
- if (word !== null) this.handleWord(word);
1424
- else this.handlePunctuation();
1425
- }
1426
- return this.chars.join("");
1427
- }
1428
- /* ———————————————————— 游标原语 ———————————————————— */
1429
- ch(offset = 0) {
1430
- return this.src[this.i + offset] ?? "";
1431
- }
1432
- /** 回看第 `back` 个显著 token(1 = 最近一个)。 */
1433
- tokenAt(back) {
1434
- return this.tokens[this.tokens.length - back] ?? "";
1435
- }
1436
- /** 擦除结果里 `from` 往前的最后一个非空白字符(看的是已擦除文本,不是原文)。 */
1437
- prevSignificantChar(from) {
1438
- for (let j = from; j >= 0; j--) {
1439
- const c = this.chars[j];
1440
- if (c !== " " && c !== " " && c !== "\n" && c !== "\r") return c;
1441
- }
1442
- return "";
1443
- }
1444
- /** 擦除 `[from, to)`:填等长空格,换行照抄——擦完行号与原文件一致。 */
1445
- erase(from, to) {
1446
- for (let j = Math.max(from, 0); j < to; j++) this.chars[j] = this.src[j] === "\n" ? "\n" : " ";
1447
- }
1448
- pushToken(token) {
1449
- this.afterArrow = token === "=>";
1450
- this.afterFunctionKeyword = token === "function";
1451
- this.tokens.push(token);
1452
- }
1453
- /** 数字面量整段消费(否则 `1.5` 会被拆成 `1` `.` `5`,`.` 参与判据时误判)。 */
1454
- readNumber() {
1455
- if (!/[0-9]/.test(this.ch())) return false;
1456
- let end = this.i;
1457
- while (end < this.src.length && /[0-9a-fA-FxXoObB._]/.test(this.src[end])) end++;
1458
- this.i = end;
1459
- this.pushToken("number");
1460
- return true;
1461
- }
1462
- readWord() {
1463
- if (!IDENT_START.test(this.ch())) return null;
1464
- let end = this.i;
1465
- while (end < this.src.length && IDENT_PART.test(this.src[end])) end++;
1466
- const word = this.src.slice(this.i, end);
1467
- this.i = end;
1468
- this.pushToken(word);
1469
- return word;
1470
- }
1471
- /* —————————————— 字面量与注释:整段跳过(内容永不参与判定) —————————————— */
1472
- copyTrivia() {
1473
- const head = this.ch();
1474
- const next = this.ch(1);
1475
- if (head === "/" && next === "/") {
1476
- while (this.i < this.src.length && this.ch() !== "\n") this.i++;
1477
- return true;
1478
- }
1479
- if (head === "/" && next === "*") {
1480
- const end = this.src.indexOf("*/", this.i + 2);
1481
- this.i = end === -1 ? this.src.length : end + 2;
1482
- return true;
1483
- }
1484
- return false;
1485
- }
1486
- copyLiteral() {
1487
- const head = this.ch();
1488
- if (head !== "'" && head !== '"' && head !== "`") return false;
1489
- this.i = head === "`" ? this.scanTemplate(this.i) : this.scanQuoted(this.i);
1490
- this.pushToken(head === "`" ? "template" : "string");
1491
- return true;
1492
- }
1493
- /** 引号串结束下标(未闭合则到行尾,把真实的语法错误留给求值期)。 */
1494
- scanQuoted(start) {
1495
- const quote = this.src[start];
1496
- let j = start + 1;
1497
- while (j < this.src.length) {
1498
- const c = this.src[j];
1499
- if (c === "\\") j += 2;
1500
- else if (c === quote) return j + 1;
1501
- else if (c === "\n") return j;
1502
- else j++;
1503
- }
1504
- return this.src.length;
1505
- }
1506
- /** 模板串结束下标(`${}` 内按大括号配平,内层字符串 / 模板一并识别)。 */
1507
- scanTemplate(start) {
1508
- let j = start + 1;
1509
- while (j < this.src.length) {
1510
- const c = this.src[j];
1511
- if (c === "\\") j += 2;
1512
- else if (c === "`") return j + 1;
1513
- else if (c === "$" && this.src[j + 1] === "{") j = this.scanInterpolation(j + 2);
1514
- else j++;
1515
- }
1516
- return this.src.length;
1517
- }
1518
- scanInterpolation(start) {
1519
- let depth = 1;
1520
- let j = start;
1521
- while (j < this.src.length) {
1522
- const c = this.src[j];
1523
- if (c === "\\") j += 2;
1524
- else if (c === "'" || c === '"') j = this.scanQuoted(j);
1525
- else if (c === "`") j = this.scanTemplate(j);
1526
- else if (c === "{") {
1527
- depth++;
1528
- j++;
1529
- } else if (c === "}") {
1530
- depth--;
1531
- j++;
1532
- if (depth === 0) return j;
1533
- } else j++;
1534
- }
1535
- return this.src.length;
1536
- }
1537
- /**
1538
- * 正则字面量:`/` 只在「运算符位」才是正则起始(前一个显著字符不是值结尾)。
1539
- * 判不准时按除号处理——除号后面不会有需要擦除的类型标注,最坏只是漏擦。
1540
- * 有了这条,`const url = /https:\/\//` 里的 `:` 与 `//` 才不会被人当语法(恒等用例之一)。
1541
- */
1542
- copyRegexIfNeeded() {
1543
- if (this.ch() !== "/") return false;
1544
- const prev = this.prevSignificantChar(this.i - 1);
1545
- const valueEnding = prev !== "" && (IDENT_PART.test(prev) || prev === ")" || prev === "]" || prev === "}" || prev === '"' || prev === "'" || prev === "`");
1546
- if (valueEnding) return false;
1547
- const end = this.scanRegex(this.i);
1548
- if (end === null) return false;
1549
- this.i = end;
1550
- this.pushToken("regex");
1551
- return true;
1552
- }
1553
- scanRegex(start) {
1554
- let j = start + 1;
1555
- let inClass = false;
1556
- while (j < this.src.length) {
1557
- const c = this.src[j];
1558
- if (c === "\\") {
1559
- j += 2;
1560
- continue;
1561
- }
1562
- if (c === "\n") return null;
1563
- if (c === "[") inClass = true;
1564
- else if (c === "]") inClass = false;
1565
- else if (c === "/" && !inClass) {
1566
- j++;
1567
- while (j < this.src.length && /[a-z]/i.test(this.src[j])) j++;
1568
- return j;
1569
- }
1570
- j++;
1571
- }
1572
- return null;
1573
- }
1574
- /* ———————————————— 关键字与声明结构 ———————————————— */
1575
- handleWord(word) {
1576
- const start = this.i - word.length;
1577
- if (this.tokenAt(2) === ".") {
1578
- this.consumeGenericsAfterName();
1579
- return;
1580
- }
1581
- switch (word) {
1582
- case "interface": {
1583
- const after = this.skipWhitespaceFrom(this.skipNameAndParams(start + word.length));
1584
- if (after === null || this.src[after] !== "{") return;
1585
- const end = this.scanBalanced(after, "{", "}");
1586
- this.erase(start, end);
1587
- this.i = end;
1588
- this.pushToken("erased");
1589
- return;
1590
- }
1591
- case "type": {
1592
- const after = this.skipWhitespaceFrom(this.skipNameAndParams(this.i));
1593
- if (after === null || this.src[after] !== "=") return;
1594
- const end = this.scanTypeExpression(after + 1, true);
1595
- this.erase(start, end);
1596
- this.i = end;
1597
- this.pushToken("erased");
1598
- return;
1599
- }
1600
- case "import":
1601
- case "export": {
1602
- if (!/^\s+type\b/.test(this.src.slice(this.i))) return;
1603
- const after = this.skipNameAndParams(this.i);
1604
- if (after === null) return;
1605
- const end = this.scanStatementEnd(after);
1606
- this.erase(start, end);
1607
- this.i = end;
1608
- this.pushToken("erased");
1609
- return;
1610
- }
1611
- case "enum":
1612
- case "namespace":
1613
- throw new UnsupportedTsSyntaxError(word, this.lineAt(start));
1614
- case "implements": {
1615
- let j = this.i;
1616
- while (j < this.src.length && this.src[j] !== "{" && this.src[j] !== ";") j++;
1617
- this.erase(start, j);
1618
- this.i = j;
1619
- this.pushToken("erased");
1620
- return;
1621
- }
1622
- case "class":
1623
- this.pendingClassBody = true;
1624
- return;
1625
- case "as":
1626
- case "satisfies": {
1627
- if (this.tokenAt(2) === "*" || this.tokenAt(2) === "type") return;
1628
- const nextChar = this.skipWhitespaceFrom(this.i);
1629
- if (nextChar === null || "=,:]})".includes(this.src[nextChar])) return;
1630
- const end = this.scanTypeExpression(this.i, false);
1631
- this.erase(start, end);
1632
- this.i = end;
1633
- return;
1634
- }
1635
- default: {
1636
- if (TS_MODIFIERS.has(word) && this.inClassBody()) {
1637
- const next = this.peekWord();
1638
- if (next === "" || /[{(=]/.test(next[0])) return;
1639
- this.erase(start, this.i);
1640
- this.pushToken("modifier");
1641
- return;
1642
- }
1643
- this.consumeGenericsAfterName();
1644
- }
1645
- }
1646
- }
1647
- peekWord() {
1648
- let j = this.i;
1649
- while (j < this.src.length && /\s/.test(this.src[j])) j++;
1650
- let end = j;
1651
- while (end < this.src.length && IDENT_PART.test(this.src[end])) end++;
1652
- return this.src.slice(j, end);
1653
- }
1654
- lineAt(index) {
1655
- let line = 1;
1656
- for (let j = 0; j < index; j++) if (this.src[j] === "\n") line++;
1657
- return line;
1658
- }
1659
- /** `:` 之前紧邻的是不是 `)`(返回值标注位;用于决定是否允许顶层 `=>` 续读)。 */
1660
- lastSignificantCharIsCloseParen(at) {
1661
- return this.prevSignificantChar(at - 1) === ")";
1662
- }
1663
- inClassBody() {
1664
- return this.frames[this.frames.length - 1]?.classBody === true;
1665
- }
1666
- /** 当前帧是不是声明位(参数列表 / 类体)——只有这里才允许把 `:` 判成标注。 */
1667
- inDeclarePosition() {
1668
- const frame = this.frames[this.frames.length - 1];
1669
- return frame !== void 0 && (frame.declare || frame.classBody);
1670
- }
1671
- /* ———————————————— 标点与括号帧 ———————————————— */
1672
- handlePunctuation() {
1673
- const c = this.ch();
1674
- const start = this.i;
1675
- if (c === "(" || c === "{" || c === "[") {
1676
- const frame = {
1677
- kind: c === "(" ? "paren" : c === "{" ? "brace" : "bracket",
1678
- declare: false,
1679
- classBody: false
1680
- };
1681
- if (c === "{" && this.pendingClassBody) {
1682
- frame.classBody = true;
1683
- this.pendingClassBody = false;
1684
- }
1685
- if (c === "(" && this.isDeclareParen(start)) frame.declare = true;
1686
- this.frames.push(frame);
1687
- this.i++;
1688
- this.pushToken(c);
1689
- return;
1690
- }
1691
- if (c === ")" || c === "}" || c === "]") {
1692
- const closed = this.frames.pop();
1693
- if (closed?.kind === "paren") this.justClosedDeclareParen = closed.declare;
1694
- this.i++;
1695
- this.pushToken(c);
1696
- return;
1697
- }
1698
- if (c === ":") {
1699
- if (this.ch(1) === ":") {
1700
- this.i++;
1701
- this.pushToken(":");
1702
- return;
1703
- }
1704
- const returnType = this.isAnnotationColon(start) && this.lastSignificantCharIsCloseParen(start);
1705
- if (returnType || this.isAnnotationColon(start)) {
1706
- const end = this.scanTypeExpression(start + 1, false, returnType);
1707
- this.erase(start, end);
1708
- this.i = end;
1709
- this.pushToken("erased");
1710
- return;
1711
- }
1712
- this.i++;
1713
- this.pushToken(":");
1714
- return;
1715
- }
1716
- if (c === "?" && this.ch(1) !== "?" && this.ch(1) !== ".") {
1717
- let j = start + 1;
1718
- while (j < this.src.length && (this.src[j] === " " || this.src[j] === " ")) j++;
1719
- if (this.src[j] === ":" && this.inDeclarePosition() && IDENT_PART.test(this.prevSignificantChar(start - 1))) {
1720
- const end = this.scanTypeExpression(j + 1, false);
1721
- this.erase(start, end);
1722
- this.i = end;
1723
- this.pushToken("erased");
1724
- return;
1725
- }
1726
- this.i++;
1727
- this.pushToken("?");
1728
- return;
1729
- }
1730
- if (c === "!" && this.ch(1) !== "=" && this.isPostfixBang(start)) {
1731
- this.erase(start, start + 1);
1732
- this.i++;
1733
- return;
1734
- }
1735
- if (c === "=" && this.ch(1) === ">") {
1736
- this.i += 2;
1737
- this.pushToken("=>");
1738
- return;
1739
- }
1740
- if (c === "<" && this.consumeLeadingGenerics(start)) return;
1741
- this.i++;
1742
- this.pushToken(c);
1743
- }
1744
- /** 空白跳跃(供声明结构找下一个非空白字符;不改游标,纯函数)。 */
1745
- skipWhitespaceFrom(index) {
1746
- if (index === null) return null;
1747
- let j = index;
1748
- while (j < this.src.length && /\s/.test(this.src[j])) j++;
1749
- return j;
1750
- }
1751
- /**
1752
- * 运算符位上的泛型参数列表(`const f = <T, >(x: T) => x`、`arr.map<T2>(...)` 之外的箭头形态):
1753
- * 前一个显著字符不是值结尾(否则是 `a < b` 比较),且 `>` 之后紧跟 `(` 才擦。
1754
- */
1755
- consumeLeadingGenerics(at) {
1756
- if (!"([{,=;:>!&|?".includes(this.prevSignificantChar(at - 1))) return false;
1757
- const end = this.scanTypeParams(at);
1758
- if (end === null) return false;
1759
- const after = this.skipWhitespaceFrom(end);
1760
- if (after === null || this.src[after] !== "(") return false;
1761
- this.erase(at, end);
1762
- this.i = end;
1763
- return true;
1764
- }
1765
- /**
1766
- * `(` 是否为参数列表(声明位):`function f(`、类体里的方法 `m(`、箭头 `=> (`,
1767
- * 以及出现在 `(` `,` `=` `>` `:` `[` `{` `}` `;` 之后(如 `map((v: T) => v)` 的内层括号)。
1768
- * 调用位 `foo(` 与控制流 `if (` `for (` 都不算。
1769
- * 误判成声明位也不足以擦掉什么:`:` 还要过 `isAnnotationColon` 的「名字前驱必须是
1770
- * `(` `,` `{` `;` 修饰符」这一关,而三元表达式的中间段前面必然是 `?`。
1771
- */
1772
- isDeclareParen(at) {
1773
- if (this.afterFunctionKeyword) return true;
1774
- if (this.tokenAt(2) === "function" && IDENT_START.test(this.tokenAt(1))) return true;
1775
- if (this.afterArrow) return true;
1776
- if (this.inClassBody() && IDENT_PART.test(this.prevSignificantChar(at - 1))) return true;
1777
- const prev = this.prevSignificantChar(at - 1);
1778
- return prev === "" || "(,=>:[{};".includes(prev);
1779
- }
1780
- /** `:` 是类型标注吗:看名字前驱 token 与所在帧(对象键、三元、`case` 一律排除)。 */
1781
- isAnnotationColon(at) {
1782
- const prev = this.prevSignificantChar(at - 1);
1783
- if (prev === ")") return this.justClosedDeclareParen;
1784
- if (prev === "}" || prev === "]") {
1785
- const frame = this.frames[this.frames.length - 1];
1786
- return frame?.kind === "paren" && frame.declare;
1787
- }
1788
- if (!IDENT_PART.test(prev)) return false;
1789
- if (this.tokenAt(1) === "number" || this.tokenAt(1) === "string") return false;
1790
- if (this.inDeclarePosition() && isAnnotationLeader(this.tokenAt(2))) return true;
1791
- return DECL_KEYWORDS.has(this.tokenAt(2));
1792
- }
1793
- /** 非空断言 `x!`:前一个显著字符是值结尾,且后一个非空白字符不是操作数起始。 */
1794
- isPostfixBang(at) {
1795
- const prev = this.prevSignificantChar(at - 1);
1796
- if (!(IDENT_PART.test(prev) || prev === ")" || prev === "]")) return false;
1797
- let j = at + 1;
1798
- while (j < this.src.length && (this.src[j] === " " || this.src[j] === " ")) j++;
1799
- const next = this.src[j] ?? "";
1800
- if (next === "") return true;
1801
- return !(IDENT_START.test(next) || /[0-9]/.test(next) || "(![~".includes(next));
1802
- }
1803
- /* ———————————————— 区间扫描(全部字符串 / 注释安全) ———————————————— */
1804
- /** 跳过「名字 + 泛型参数」;没有合法名字时返回 null(`{ type: 1 }` 因此落空)。 */
1805
- skipNameAndParams(from) {
1806
- let j = from;
1807
- while (j < this.src.length && /\s/.test(this.src[j])) j++;
1808
- const nameStart = j;
1809
- while (j < this.src.length && IDENT_PART.test(this.src[j])) j++;
1810
- if (j === nameStart) return null;
1811
- const generic = this.scanTypeParams(j);
1812
- return generic === null ? j : generic;
1813
- }
1814
- /** `<T, U extends X>`:返回 `>` 之后的下标;跨到 `)` `]` `;` 换行前配不平则 null。 */
1815
- scanTypeParams(from) {
1816
- if (this.src[from] !== "<") return null;
1817
- let depth = 0;
1818
- let j = from;
1819
- for (; j < this.src.length; j++) {
1820
- const c = this.src[j];
1821
- if (c === "<") depth++;
1822
- else if (c === ">") {
1823
- depth--;
1824
- if (depth === 0) return j + 1;
1825
- } else if (c === ")" || c === "]" || c === ";" || c === "\n") return null;
1826
- else if (c === "'" || c === '"') j = this.scanQuoted(j) - 1;
1827
- else if (c === "`") j = this.scanTemplate(j) - 1;
1828
- }
1829
- return null;
1830
- }
1831
- /**
1832
- * 消费「刚读出的标识符之后」的泛型实参 / 类型参数(`function f<T>(`、方法 `m<T>(`、`f<T>(x)`)。
1833
- * 只有 `>` 之后紧跟 `(` / `{` / `implements` 才算——`if (a < b) {` 里 `>` 之后是 `)`,故安全。
1834
- */
1835
- consumeGenericsAfterName() {
1836
- if (this.ch() !== "<") return;
1837
- const end = this.scanTypeParams(this.i);
1838
- if (end === null) return;
1839
- let j = end;
1840
- while (j < this.src.length && (this.src[j] === " " || this.src[j] === " ")) j++;
1841
- const after = this.src.slice(j);
1842
- if (!/^[({]/.test(after) && !/^implements\b/.test(after)) return;
1843
- this.erase(this.i, end);
1844
- this.i = end;
1845
- }
1846
- /** 括号配平:返回闭括号之后的下标(未配平则到文件尾)。 */
1847
- scanBalanced(from, open, close) {
1848
- let depth = 0;
1849
- let j = from;
1850
- while (j < this.src.length) {
1851
- const c = this.src[j];
1852
- if (c === "'" || c === '"') j = this.scanQuoted(j);
1853
- else if (c === "`") j = this.scanTemplate(j);
1854
- else if (c === "/" && (this.src[j + 1] === "/" || this.src[j + 1] === "*"))
1855
- j = this.skipComment(j);
1856
- else if (c === open) {
1857
- depth++;
1858
- j++;
1859
- } else if (c === close) {
1860
- depth--;
1861
- j++;
1862
- if (depth === 0) return j;
1863
- } else j++;
1864
- }
1865
- return this.src.length;
1866
- }
1867
- skipComment(from) {
1868
- if (this.src[from + 1] === "/") {
1869
- const end2 = this.src.indexOf("\n", from);
1870
- return end2 === -1 ? this.src.length : end2;
1871
- }
1872
- const end = this.src.indexOf("*/", from + 2);
1873
- return end === -1 ? this.src.length : end + 2;
1874
- }
1875
- /** 语句结束(`;` 或括号已配平时的行尾),用于 `import type …`。 */
1876
- scanStatementEnd(from) {
1877
- let depth = 0;
1878
- let j = from;
1879
- while (j < this.src.length) {
1880
- const c = this.src[j];
1881
- if (c === "'" || c === '"') j = this.scanQuoted(j);
1882
- else if (c === "`") j = this.scanTemplate(j);
1883
- else if (c === "{" || c === "(" || c === "[") {
1884
- depth++;
1885
- j++;
1886
- } else if (c === "}" || c === ")" || c === "]") {
1887
- depth--;
1888
- j++;
1889
- } else if (c === ";" || c === "\n" && depth <= 0) break;
1890
- else j++;
1891
- }
1892
- return j;
1893
- }
1894
- /**
1895
- * 类型表达式结束下标:消费标识符 / 字符串字面量类型 / 泛型实参 / 元组 / 对象类型 /
1896
- * 函数类型(含 `=>` 返回值)/ 联合与交叉;在深度 0 的 `= , ; ) ]` 与「已结束的行」处停下。
1897
- *
1898
- * 两处歧义的处理:
1899
- * - `function f(): { a: number } { … }`——还没消费过类型原子时遇到的 `{` 属于类型,
1900
- * 之后再遇 `{` 才是函数体;`type X = A` 的初始值花括号整体算类型(`leadingBraceIsType`)。
1901
- * - `const x: Foo = { … }`——在 `=` 处停,不会把右侧对象字面量吞掉。
1902
- */
1903
- scanTypeExpression(from, leadingBraceIsType, topLevelArrowEnds = false) {
1904
- let depth = 0;
1905
- let j = from;
1906
- let sawAtom = false;
1907
- while (j < this.src.length) {
1908
- const c = this.src[j];
1909
- if (c === "'" || c === '"') {
1910
- j = this.scanQuoted(j);
1911
- sawAtom = true;
1912
- } else if (c === "`") {
1913
- j = this.scanTemplate(j);
1914
- sawAtom = true;
1915
- } else if (c === "/" && (this.src[j + 1] === "/" || this.src[j + 1] === "*")) {
1916
- j = this.skipComment(j);
1917
- } else if (c === "(" || c === "[") {
1918
- depth++;
1919
- sawAtom = true;
1920
- j++;
1921
- } else if (c === ")" || c === "]") {
1922
- if (depth === 0) break;
1923
- depth--;
1924
- j++;
1925
- } else if (c === "{") {
1926
- if (depth === 0 && sawAtom && !leadingBraceIsType) break;
1927
- j = this.scanBalanced(j, "{", "}");
1928
- sawAtom = true;
1929
- } else if (c === "}") {
1930
- if (depth === 0) break;
1931
- depth--;
1932
- j++;
1933
- } else if (depth === 0 && (c === "," || c === ";")) break;
1934
- else if (depth === 0 && c === "=") {
1935
- if (this.src[j + 1] === ">" && !topLevelArrowEnds) {
1936
- j += 2;
1937
- continue;
1938
- }
1939
- break;
1940
- } else if (depth === 0 && c === "\n") {
1941
- if (!this.typeContinuesAt(j)) break;
1942
- j++;
1943
- } else if (c === "<") {
1944
- const generic = this.scanTypeParams(j);
1945
- if (generic === null) break;
1946
- j = generic;
1947
- sawAtom = true;
1948
- } else {
1949
- if (IDENT_PART.test(c)) sawAtom = true;
1950
- j++;
1951
- }
1952
- }
1953
- return j;
1954
- }
1955
- /**
1956
- * 行尾处类型是否仍在继续:`type Id = string\n | number` 要接得上,
1957
- * 而 `const x: Foo\nconst y = 1` 必须停。判据是两侧的非空邻字——
1958
- * 前一个是连接符(`| & < > = , . ? : (`)或后一个是连接符 / 闭合符(`| & , . ? : ) ] } >`)。
1959
- */
1960
- typeContinuesAt(index) {
1961
- for (let j = index - 1; j >= 0; j--) {
1962
- const c = this.src[j];
1963
- if (/\s/.test(c)) continue;
1964
- if ("|&<>=,.?:(".includes(c)) return true;
1965
- break;
1966
- }
1967
- for (let j = index + 1; j < this.src.length; j++) {
1968
- const c = this.src[j];
1969
- if (/\s/.test(c)) continue;
1970
- return "|&,.?:)]}>".includes(c);
1971
- }
1972
- return false;
1973
- }
1974
- };
1975
- function stripTypes(source) {
1976
- return new Eraser(source).run();
1977
- }
3075
+ // src/test-runner.ts
3076
+ init_strip_types();
1978
3077
 
1979
3078
  // src/test-framework.ts
1980
3079
  var TestAssertionError = class extends Error {
@@ -2409,6 +3508,17 @@ function exampleTestSource(name = "example") {
2409
3508
  }
2410
3509
 
2411
3510
  // src/container.ts
3511
+ function viteBanner(server, fresh) {
3512
+ return [
3513
+ fresh ? ` VITE \u6D4F\u89C8\u5668\u5185 dev server \u5DF2\u5C31\u7EEA\uFF08root: ${server.root}\uFF09
3514
+ ` : ` vite dev server \u5DF2\u5728\u8FD0\u884C\uFF08root: ${server.root}\uFF09
3515
+ `,
3516
+ "\n",
3517
+ " \u279C Local: http://localhost:5173/\n",
3518
+ " \u279C \u9884\u89C8\uFF1A\u7EC8\u7AEF / IDE \u7684\u9884\u89C8\u9762\u677F\u5DF2\u5C31\u7EEA\uFF0C\u7F16\u8F91\u4FDD\u5B58\u540E\u81EA\u52A8\u5237\u65B0\uFF08HMR\uFF09\n",
3519
+ " \u279C \u505C\u6B62\uFF1Avite stop\uFF08\u6362\u76EE\u5F55\uFF1Avite <dir>\uFF09\n"
3520
+ ].join("");
3521
+ }
2412
3522
  function bootstrap(options) {
2413
3523
  const vfs = options.vfs ?? new VirtualFileSystem();
2414
3524
  if (options.initialTree !== void 0) vfs.mount(options.initialTree);
@@ -2427,12 +3537,46 @@ function bootstrap(options) {
2427
3537
  return { code: outcome.code, stdout: outcome.stdout, stderr: outcome.stderr };
2428
3538
  }
2429
3539
  };
3540
+ const net = options.net ?? createRelayFetch({
3541
+ baseUrl: options.httpRelayBaseUrl ?? "/api/v1/http-relay",
3542
+ ...options.fetchImpl === void 0 ? {} : { fetchImpl: options.fetchImpl }
3543
+ });
3544
+ let viteServer = null;
3545
+ const vite = {
3546
+ async start(args) {
3547
+ const target = args[0] ?? "/";
3548
+ const root = target.startsWith("/") ? normalize(target) : join(cwd, target);
3549
+ if (viteServer !== null && viteServer.root === root)
3550
+ return { code: 0, stdout: viteBanner(viteServer, false) };
3551
+ await viteServer?.stop();
3552
+ viteServer = null;
3553
+ const { createViteServer: createViteServer2 } = await Promise.resolve().then(() => (init_vite_dev(), vite_dev_exports));
3554
+ const server = createViteServer2(vfs, {
3555
+ root,
3556
+ ...options.viteCompiler === void 0 ? {} : { sfcCompiler: options.viteCompiler }
3557
+ });
3558
+ await server.ready;
3559
+ viteServer = server;
3560
+ emit("serverready", { port: server.port, url: server.url, kind: "vite", root: server.root });
3561
+ return { code: 0, stdout: viteBanner(server, true) };
3562
+ },
3563
+ async stop() {
3564
+ if (viteServer === null) return { code: 0, stdout: "vite: dev server \u672A\u5728\u8FD0\u884C\n" };
3565
+ const root = viteServer.root;
3566
+ await viteServer.stop();
3567
+ viteServer = null;
3568
+ return { code: 0, stdout: ` vite dev server \u5DF2\u505C\u6B62\uFF08root: ${root}\uFF09
3569
+ ` };
3570
+ }
3571
+ };
2430
3572
  const shell = new Shell({
2431
3573
  vfs,
2432
3574
  getCwd: () => cwd,
2433
3575
  setCwd,
2434
3576
  ...runtime === void 0 ? {} : { runtime },
2435
- test
3577
+ test,
3578
+ net,
3579
+ vite
2436
3580
  });
2437
3581
  const npmClient = createNpmClient({
2438
3582
  baseUrl: options.npmRelayBaseUrl,
@@ -2552,9 +3696,9 @@ function bootstrap(options) {
2552
3696
  },
2553
3697
  async preview(previewOptions) {
2554
3698
  if (preview === null) {
2555
- const { createPreviewServer: createPreviewServer2 } = await Promise.resolve().then(() => (init_preview(), preview_exports));
3699
+ const { createPreviewServer: createPreviewServer2 } = await Promise.resolve().then(() => (init_preview_server(), preview_server_exports));
2556
3700
  preview = createPreviewServer2(vfs, previewOptions);
2557
- emit("serverready", { port: preview.port, url: preview.url });
3701
+ emit("serverready", { port: preview.port, url: preview.url, kind: "preview" });
2558
3702
  }
2559
3703
  return { url: preview.url, port: preview.port };
2560
3704
  },
@@ -2563,11 +3707,15 @@ function bootstrap(options) {
2563
3707
  defaultRuntime?.close?.();
2564
3708
  await preview?.stop();
2565
3709
  preview = null;
3710
+ await viteServer?.stop();
3711
+ viteServer = null;
2566
3712
  }
2567
3713
  };
2568
3714
  }
2569
3715
 
2570
3716
  // src/index.ts
3717
+ init_node_resolve();
3718
+ init_vite_dev();
2571
3719
  init_path();
2572
3720
 
2573
3721
  // src/persistence.ts
@@ -2783,6 +3931,9 @@ function createCommandHistory(options) {
2783
3931
  };
2784
3932
  }
2785
3933
 
3934
+ // src/index.ts
3935
+ init_strip_types();
3936
+
2786
3937
  // src/offline/net.ts
2787
3938
  var HEALTH_CHECK_INTERVAL_MS = 3e4;
2788
3939
  var HEALTH_CHECK_TIMEOUT_MS = 5e3;
@@ -3046,7 +4197,6 @@ var publishQueue = new PublishQueue();
3046
4197
 
3047
4198
  // src/offline/workspace.ts
3048
4199
  var DB_NAME = "adep-offline-workspace";
3049
- var DB_VERSION = 1;
3050
4200
  function requestError(request) {
3051
4201
  return request.error ?? new Error("IndexedDB operation failed");
3052
4202
  }
@@ -3061,7 +4211,7 @@ var IndexedDBBackend = class {
3061
4211
  reject(new Error("IndexedDB not available"));
3062
4212
  return;
3063
4213
  }
3064
- const request = indexedDB.open(DB_NAME, DB_VERSION);
4214
+ const request = indexedDB.open(DB_NAME);
3065
4215
  request.onupgradeneeded = () => {
3066
4216
  };
3067
4217
  request.onsuccess = () => {
@@ -3088,10 +4238,12 @@ var IndexedDBBackend = class {
3088
4238
  };
3089
4239
  request.onsuccess = () => {
3090
4240
  this.db = request.result;
4241
+ this.initPromise = Promise.resolve(request.result);
3091
4242
  const tx2 = this.db.transaction(storeName, "readwrite");
3092
4243
  resolve(tx2.objectStore(storeName));
3093
4244
  };
3094
4245
  request.onerror = () => reject(requestError(request));
4246
+ request.onblocked = () => reject(new Error("IndexedDB \u5347\u7EA7\u88AB\u5176\u4ED6\u6807\u7B7E\u9875\u963B\u585E\uFF08adep-offline-workspace\uFF09"));
3095
4247
  });
3096
4248
  }
3097
4249
  const tx = db.transaction(storeName, "readwrite");
@@ -5373,6 +6525,7 @@ function transformModule(code) {
5373
6525
  }
5374
6526
 
5375
6527
  // src/sim/runner.ts
6528
+ init_strip_types();
5376
6529
  function safeStringify2(value) {
5377
6530
  if (typeof value === "string") return value;
5378
6531
  try {
@@ -5548,10 +6701,14 @@ async function createBrowserSimRuntime(options) {
5548
6701
  dispose: async () => void 0
5549
6702
  };
5550
6703
  }
6704
+
6705
+ // src/index.ts
6706
+ init_function_fetch_proxy();
5551
6707
  export {
5552
6708
  COMPLETABLE_COMMANDS,
5553
6709
  DEFAULT_MAX_INSTALL_DEPTH,
5554
6710
  EXTRA_COMMANDS,
6711
+ FN_FETCH_INTERCEPTOR_SCRIPT,
5555
6712
  RESOLVE_EXTENSIONS,
5556
6713
  ResolveError,
5557
6714
  SHELL_COMMANDS,
@@ -5560,6 +6717,7 @@ export {
5560
6717
  TestAssertionError,
5561
6718
  UnsupportedTsSyntaxError,
5562
6719
  VirtualFileSystem,
6720
+ ViteDevError,
5563
6721
  applyCompletion,
5564
6722
  bootstrap,
5565
6723
  buildCloudFromBundle,
@@ -5575,6 +6733,7 @@ export {
5575
6733
  createBrowserStorageDriver,
5576
6734
  createCommandHistory,
5577
6735
  createFsPersistence,
6736
+ createFunctionFetchHandler,
5578
6737
  createIdbSimKv,
5579
6738
  createIndexedDbFsBackend,
5580
6739
  createLocalPort,
@@ -5583,10 +6742,12 @@ export {
5583
6742
  createMemorySimKv,
5584
6743
  createNpmClient,
5585
6744
  createOfflineFunctionRunner,
6745
+ createRelayFetch,
5586
6746
  createRequire,
5587
6747
  createSandboxModuleGlobals,
5588
6748
  createTestRunner,
5589
6749
  createTestScope,
6750
+ createViteServer,
5590
6751
  createWorkerRuntime,
5591
6752
  deepEqual,
5592
6753
  displayPath,
@@ -5615,6 +6776,7 @@ export {
5615
6776
  resolvePackageEntry,
5616
6777
  restoreVfs,
5617
6778
  runCollectedTests,
6779
+ scanEsmSpecifiers,
5618
6780
  simDbKey,
5619
6781
  simStorageKey,
5620
6782
  snapshotVfs,