@adep/web-container 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -134,8 +134,17 @@ function resolvePackageEntry(meta, pkgDirAbs, condition) {
134
134
  if (typeof exp !== "object" || Array.isArray(exp)) {
135
135
  throw new ResolveError(`${context} \u5F62\u6001\u4E0D\u652F\u6301\uFF08exports \u53EA\u80FD\u662F\u5B57\u7B26\u4E32\u6216\u5BF9\u8C61\uFF09`);
136
136
  }
137
- const dot = exp["."];
137
+ const table = exp;
138
+ const dot = table["."];
139
+ const order = condition === "import" ? IMPORT_CONDITION_ORDER : REQUIRE_CONDITION_ORDER;
140
+ const resolveRel = (rel) => withinPackage(pkgDirAbs, rel, context);
138
141
  if (dot === void 0) {
142
+ const keys = Object.keys(table);
143
+ if (keys.length > 0 && keys.every((key) => !key.startsWith("."))) {
144
+ const shorthand = pickConditionTarget(table, order, resolveRel, context);
145
+ if (shorthand !== null) return shorthand;
146
+ throw new ResolveError(`${context}\uFF1A\u5305\u6839\u6761\u4EF6\u5BF9\u8C61\u91CC\u6CA1\u6709 ${order.join("/")} \u5165\u53E3`);
147
+ }
139
148
  throw new ResolveError(
140
149
  `${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`
141
150
  );
@@ -146,8 +155,6 @@ function resolvePackageEntry(meta, pkgDirAbs, condition) {
146
155
  if (typeof dot !== "object" || Array.isArray(dot)) {
147
156
  throw new ResolveError(`${context}\uFF1Aexports["."] \u5F62\u6001\u4E0D\u652F\u6301\uFF08\u4EC5\u63A5\u53D7\u5B57\u7B26\u4E32\u6216\u6761\u4EF6\u5BF9\u8C61\uFF09`);
148
157
  }
149
- const order = condition === "import" ? IMPORT_CONDITION_ORDER : REQUIRE_CONDITION_ORDER;
150
- const resolveRel = (rel) => withinPackage(pkgDirAbs, rel, context);
151
158
  const hit = pickConditionTarget(dot, order, resolveRel, context);
152
159
  if (hit !== null) return hit;
153
160
  throw new ResolveError(`${context}\uFF1Aexports["."] \u6761\u4EF6\u5BF9\u8C61\u91CC\u6CA1\u6709 ${order.join("/")} \u5165\u53E3`);
@@ -346,6 +353,28 @@ var init_strip_types = __esm({
346
353
  }
347
354
  return "";
348
355
  }
356
+ /**
357
+ * `interface` / `type` 声明之前若有 `export` 关键字,返回该关键字的起始下标,否则原样返回。
358
+ *
359
+ * 为什么必须吞掉:`export interface X { … }` 里 `interface` 分支只擦它自己那一段,
360
+ * 留下的孤立 `export` 是**非法 JS**——浏览器解析模块时直接
361
+ * `SyntaxError: Unexpected token 'export'`(实测 countdown 项目 `lib/auth.ts` 的
362
+ * `export interface AppUser`:整条预览链路因此白屏)。`export type X = …` 由 `export`
363
+ * 分支整条擦除,不受影响。
364
+ *
365
+ * 判据分两步:token 回看确认前一个显著 token 就是 `export`(避免误吞 `re-export` 之类
366
+ * 同名标识符——那会在下面按字符再校验一次);位置则往前跳空白后左推 6 个字符,并要求
367
+ * 再前一个字符不是标识符字符(`xexport interface` 不吞)。
368
+ */
369
+ includeLeadingExport(start) {
370
+ if (this.tokenAt(2) !== "export") return start;
371
+ let end = start - 1;
372
+ while (end >= 0 && /\s/.test(this.src[end])) end--;
373
+ if (end < 5 || this.src.slice(end - 5, end + 1) !== "export") return start;
374
+ const before = this.src[end - 6];
375
+ if (before !== void 0 && IDENT_PART.test(before)) return start;
376
+ return end - 5;
377
+ }
349
378
  /** 擦除 `[from, to)`:填等长空格,换行照抄——擦完行号与原文件一致。 */
350
379
  erase(from, to) {
351
380
  for (let j = Math.max(from, 0); j < to; j++) this.chars[j] = this.src[j] === "\n" ? "\n" : " ";
@@ -485,19 +514,31 @@ var init_strip_types = __esm({
485
514
  }
486
515
  switch (word) {
487
516
  case "interface": {
488
- const after = this.skipWhitespaceFrom(this.skipNameAndParams(start + word.length));
517
+ const heritage = this.skipInterfaceExtends(this.skipNameAndParams(start + word.length));
518
+ const after = heritage === null ? null : this.skipWhitespaceFrom(heritage);
489
519
  if (after === null || this.src[after] !== "{") return;
490
520
  const end = this.scanBalanced(after, "{", "}");
491
- this.erase(start, end);
521
+ this.erase(this.includeLeadingExport(start), end);
492
522
  this.i = end;
493
523
  this.pushToken("erased");
494
524
  return;
495
525
  }
496
526
  case "type": {
527
+ if (this.frames[this.frames.length - 1]?.specifierList === true) {
528
+ const specifierEnd = this.scanTypeOnlySpecifier(this.i);
529
+ if (specifierEnd !== null) {
530
+ this.erase(start, specifierEnd);
531
+ this.i = specifierEnd;
532
+ } else {
533
+ this.erase(start, start + word.length);
534
+ }
535
+ this.pushToken("erased");
536
+ return;
537
+ }
497
538
  const after = this.skipWhitespaceFrom(this.skipNameAndParams(this.i));
498
539
  if (after === null || this.src[after] !== "=") return;
499
540
  const end = this.scanTypeExpression(after + 1, true);
500
- this.erase(start, end);
541
+ this.erase(this.includeLeadingExport(start), end);
501
542
  this.i = end;
502
543
  this.pushToken("erased");
503
544
  return;
@@ -524,16 +565,20 @@ var init_strip_types = __esm({
524
565
  this.pushToken("erased");
525
566
  return;
526
567
  }
527
- case "class":
528
- this.pendingClassBody = true;
568
+ case "class": {
569
+ const next = this.skipWhitespaceFrom(this.i);
570
+ if (next !== null && (this.src[next] === "{" || IDENT_START.test(this.src[next]))) {
571
+ this.pendingClassBody = true;
572
+ }
529
573
  return;
574
+ }
530
575
  case "as":
531
576
  case "satisfies": {
532
577
  if (this.frames[this.frames.length - 1]?.specifierList === true) return;
533
578
  if (this.tokenAt(2) === "*" || this.tokenAt(2) === "type") return;
534
579
  const nextChar = this.skipWhitespaceFrom(this.i);
535
580
  if (nextChar === null || "=,:]})".includes(this.src[nextChar])) return;
536
- const end = this.scanTypeExpression(this.i, false);
581
+ const end = this.scanTypeExpression(this.i, true);
537
582
  this.erase(start, end);
538
583
  this.i = end;
539
584
  return;
@@ -669,6 +714,62 @@ var init_strip_types = __esm({
669
714
  this.i = end;
670
715
  return true;
671
716
  }
717
+ /**
718
+ * `interface X extends A, B<T> {` 的继承子句:返回接口体 `{` 的下标。
719
+ *
720
+ * 不处理 `extends` 会让 `interface` 分支取不到 `{` 而**整条不擦**——`export interface
721
+ * DecodedEvent extends CountdownEvent { … }` 原样留在产物里,浏览器解析即
722
+ * `SyntaxError: Unexpected token 'export'`(实测 countdown 的 lib/date.ts;同项目两个
723
+ * `.vue` 产物是它的级联失败)。无 `extends` 时原样返回入参(等价旧行为);遇到字符串 /
724
+ * 配不平的泛型一律返回 null(判不准就不擦)。
725
+ */
726
+ skipInterfaceExtends(from) {
727
+ if (from === null) return null;
728
+ const j = this.skipWhitespaceFrom(from);
729
+ if (j === null || !this.src.startsWith("extends", j) || IDENT_PART.test(this.src[j + 7] ?? "")) {
730
+ return j;
731
+ }
732
+ let k = this.skipWhitespaceFrom(j + 7);
733
+ while (k !== null) {
734
+ const c = this.src[k];
735
+ if (c === "{" || c === ";") return k;
736
+ if (c === "<") {
737
+ const end = this.scanTypeParams(k);
738
+ if (end === null) return null;
739
+ k = end;
740
+ continue;
741
+ }
742
+ if (c === "'" || c === '"' || c === "`") return null;
743
+ k = this.skipWhitespaceFrom(k + 1);
744
+ }
745
+ return null;
746
+ }
747
+ /**
748
+ * 「仅类型说明符」`type X [as Y]` 的擦除终点(返回应擦到、不含的下标)。
749
+ *
750
+ * - `type` 之后不是标识符 → null(调用方退化为只擦关键字,不猜);
751
+ * - 连带**其后的**逗号一起擦(`{ type A, b }` → `{ b }`);末位说明符没有逗号,
752
+ * 留下的 `{ a, }` 是合法尾逗号,无需回首删前导逗号;
753
+ * - `as Y` 重命名一并擦除(只影响类型侧,运行时无绑定)。
754
+ */
755
+ scanTypeOnlySpecifier(from) {
756
+ let j = this.skipWhitespaceFrom(from);
757
+ if (j === null || !IDENT_START.test(this.src[j])) return null;
758
+ j++;
759
+ while (j < this.src.length && IDENT_PART.test(this.src[j])) j++;
760
+ const asAt = this.skipWhitespaceFrom(j);
761
+ if (asAt !== null && this.src.startsWith("as", asAt) && !IDENT_PART.test(this.src[asAt + 2] ?? "")) {
762
+ const nameAt = this.skipWhitespaceFrom(asAt + 2);
763
+ if (nameAt !== null && IDENT_START.test(this.src[nameAt])) {
764
+ let k = nameAt + 1;
765
+ while (k < this.src.length && IDENT_PART.test(this.src[k])) k++;
766
+ j = k;
767
+ }
768
+ }
769
+ const next = this.skipWhitespaceFrom(j);
770
+ if (next !== null && this.src[next] === ",") return next + 1;
771
+ return j;
772
+ }
672
773
  /**
673
774
  * `{` 是 import / export 的说明符列表吗——`{ a as b }` 覆盖 `import { … }`、
674
775
  * `export { … }` 与 `import def, { … }` 三种写法(后者说明符花括号的前驱 token 是 `,`)。
@@ -729,7 +830,7 @@ var init_strip_types = __esm({
729
830
  const generic = this.scanTypeParams(j);
730
831
  return generic === null ? j : generic;
731
832
  }
732
- /** `<T, U extends X>`:返回 `>` 之后的下标;跨到 `)` `]` `;` 换行前配不平则 null。 */
833
+ /** `<T, U extends X>`:返回 `>` 之后的下标;尖括号内任何非 `<`/`>` 字符(含 `]` `;` `\n` `)`)都是合法类型字符,配不平自然到文件尾返回 null。 */
733
834
  scanTypeParams(from) {
734
835
  if (this.src[from] !== "<") return null;
735
836
  let depth = 0;
@@ -740,8 +841,7 @@ var init_strip_types = __esm({
740
841
  else if (c === ">") {
741
842
  depth--;
742
843
  if (depth === 0) return j + 1;
743
- } else if (c === ")" || c === "]" || c === ";" || c === "\n") return null;
744
- else if (c === "'" || c === '"') j = this.scanQuoted(j) - 1;
844
+ } else if (c === "'" || c === '"') j = this.scanQuoted(j) - 1;
745
845
  else if (c === "`") j = this.scanTemplate(j) - 1;
746
846
  }
747
847
  return null;
@@ -873,13 +973,14 @@ var init_strip_types = __esm({
873
973
  /**
874
974
  * 行尾处类型是否仍在继续:`type Id = string\n | number` 要接得上,
875
975
  * 而 `const x: Foo\nconst y = 1` 必须停。判据是两侧的非空邻字——
876
- * 前一个是连接符(`| & < > = , . ? : (`)或后一个是连接符 / 闭合符(`| & , . ? : ) ] } >`)。
976
+ * 前一个是连接符(`| & < = , . ? : (`,不含 `>`——`Foo<T>` 后换行是语句边界,
977
+ * 含 `>` 会把下一行的 `try` 等吞进类型区间)或后一个是连接符 / 闭合符(`| & , . ? : ) ] } >`)。
877
978
  */
878
979
  typeContinuesAt(index) {
879
980
  for (let j = index - 1; j >= 0; j--) {
880
981
  const c = this.src[j];
881
982
  if (/\s/.test(c)) continue;
882
- if ("|&<>=,.?:(".includes(c)) return true;
983
+ if ("|&<=,.?:(".includes(c)) return true;
883
984
  break;
884
985
  }
885
986
  for (let j = index + 1; j < this.src.length; j++) {
@@ -893,6 +994,206 @@ var init_strip_types = __esm({
893
994
  }
894
995
  });
895
996
 
997
+ // packages/web-container/src/css-imports.ts
998
+ function isLocalSpec(spec) {
999
+ return spec.startsWith("./") || spec.startsWith("../") || spec.startsWith("/");
1000
+ }
1001
+ function skipString(css, start) {
1002
+ const quote = css[start];
1003
+ let i = start + 1;
1004
+ while (i < css.length) {
1005
+ if (css[i] === "\\") {
1006
+ i += 2;
1007
+ continue;
1008
+ }
1009
+ if (css[i] === quote) return i + 1;
1010
+ i++;
1011
+ }
1012
+ return css.length;
1013
+ }
1014
+ function matchParen(text, open) {
1015
+ let depth = 0;
1016
+ let i = open;
1017
+ while (i < text.length) {
1018
+ const ch = text[i];
1019
+ if (ch === '"' || ch === "'") {
1020
+ i = skipString(text, i);
1021
+ continue;
1022
+ }
1023
+ if (ch === "(") depth++;
1024
+ else if (ch === ")") {
1025
+ depth--;
1026
+ if (depth === 0) return i;
1027
+ }
1028
+ i++;
1029
+ }
1030
+ return text.length;
1031
+ }
1032
+ function parseSpecifier(css, from) {
1033
+ let i = from;
1034
+ while (i < css.length && /\s/.test(css[i])) i++;
1035
+ const urlHead = /^url\s*\(/i.exec(css.slice(i, i + 8));
1036
+ if (urlHead !== null) {
1037
+ const open = i + urlHead[0].length - 1;
1038
+ const close = matchParen(css, open);
1039
+ if (close >= css.length) return { spec: null, next: i };
1040
+ const inner = css.slice(open + 1, close).trim();
1041
+ const quoted = inner.startsWith('"') || inner.startsWith("'");
1042
+ return { spec: quoted ? inner.slice(1, -1).trim() : inner, next: close + 1 };
1043
+ }
1044
+ const quote = css[i];
1045
+ if (quote === '"' || quote === "'") {
1046
+ const end = skipString(css, i);
1047
+ if (css[end - 1] !== quote) return { spec: null, next: i };
1048
+ return { spec: css.slice(i + 1, end - 1), next: end };
1049
+ }
1050
+ return { spec: null, next: i };
1051
+ }
1052
+ function parseImport(css, start) {
1053
+ const parsed = parseSpecifier(css, start + IMPORT_KEYWORD.length);
1054
+ if (parsed.spec === null) return null;
1055
+ let j = parsed.next;
1056
+ let depth = 0;
1057
+ while (j < css.length) {
1058
+ const ch = css[j];
1059
+ if (ch === '"' || ch === "'") {
1060
+ j = skipString(css, j);
1061
+ continue;
1062
+ }
1063
+ if (ch === "(") depth++;
1064
+ else if (ch === ")") depth--;
1065
+ else if (ch === ";" && depth <= 0) break;
1066
+ else if (ch === "{" || ch === "}") return null;
1067
+ j++;
1068
+ }
1069
+ if (j >= css.length) return null;
1070
+ return {
1071
+ start,
1072
+ end: j + 1,
1073
+ spec: parsed.spec,
1074
+ conditions: css.slice(parsed.next, j).trim(),
1075
+ raw: css.slice(start, j + 1)
1076
+ };
1077
+ }
1078
+ function scanCssImports(css) {
1079
+ const hits = [];
1080
+ let i = 0;
1081
+ while (i < css.length) {
1082
+ const ch = css[i];
1083
+ if (ch === "/" && css[i + 1] === "*") {
1084
+ const close = css.indexOf("*/", i + 2);
1085
+ i = close === -1 ? css.length : close + 2;
1086
+ continue;
1087
+ }
1088
+ if (ch === '"' || ch === "'") {
1089
+ i = skipString(css, i);
1090
+ continue;
1091
+ }
1092
+ if (ch === "@" && /^@import(?![-\w])/i.test(css.slice(i, i + IMPORT_KEYWORD.length + 1))) {
1093
+ const hit = parseImport(css, i);
1094
+ if (hit !== null) {
1095
+ hits.push(hit);
1096
+ i = hit.end;
1097
+ continue;
1098
+ }
1099
+ }
1100
+ i++;
1101
+ }
1102
+ return hits;
1103
+ }
1104
+ function stripCharset(css) {
1105
+ return css.replace(/^\uFEFF/, "").replace(/^\s*@charset\s+(["'])[^"']*\1\s*;/i, "");
1106
+ }
1107
+ function splitImportConditions(conditions) {
1108
+ let rest = conditions.trim();
1109
+ let layer = null;
1110
+ const layerFn = /^layer\s*\(/i.exec(rest);
1111
+ if (layerFn !== null) {
1112
+ const open = layerFn[0].length - 1;
1113
+ const close = matchParen(rest, open);
1114
+ layer = rest.slice(open + 1, close).trim();
1115
+ rest = rest.slice(close + 1).trim();
1116
+ } else if (/^layer(?![-\w(])/i.test(rest)) {
1117
+ layer = "";
1118
+ rest = rest.slice("layer".length).trim();
1119
+ }
1120
+ let supports = "";
1121
+ const supportsFn = /^supports\s*\(/i.exec(rest);
1122
+ if (supportsFn !== null) {
1123
+ const open = supportsFn[0].length - 1;
1124
+ const close = matchParen(rest, open);
1125
+ supports = rest.slice(open + 1, close).trim();
1126
+ rest = rest.slice(close + 1).trim();
1127
+ }
1128
+ return { layer, supports, media: rest };
1129
+ }
1130
+ function applyImportConditions(css, conditions) {
1131
+ if (conditions === "") return css;
1132
+ const { layer, supports, media } = splitImportConditions(conditions);
1133
+ let out = css;
1134
+ if (supports !== "") out = `@supports ${supports} {
1135
+ ${out}
1136
+ }`;
1137
+ if (layer !== null) out = layer === "" ? `@layer {
1138
+ ${out}
1139
+ }` : `@layer ${layer} {
1140
+ ${out}
1141
+ }`;
1142
+ if (media !== "") out = `@media ${media} {
1143
+ ${out}
1144
+ }`;
1145
+ return out;
1146
+ }
1147
+ function expand(css, importerAbs, resolver, seen) {
1148
+ const hits = scanCssImports(css);
1149
+ if (hits.length === 0) return css;
1150
+ const parts = [];
1151
+ let cursor = 0;
1152
+ for (const hit of hits) {
1153
+ parts.push(css.slice(cursor, hit.start));
1154
+ parts.push(expandHit(hit, importerAbs, resolver, seen));
1155
+ cursor = hit.end;
1156
+ }
1157
+ parts.push(css.slice(cursor));
1158
+ return parts.join("");
1159
+ }
1160
+ function expandHit(hit, importerAbs, resolver, seen) {
1161
+ if (hit.spec === null) return hit.raw;
1162
+ const spec = hit.spec.trim();
1163
+ if (spec === "" || EXTERNAL_SPEC.test(spec)) return hit.raw;
1164
+ const abs = resolver.resolve(spec, importerAbs);
1165
+ if (abs === null) {
1166
+ if (isLocalSpec(spec))
1167
+ throw new CssImportError(
1168
+ `CSS @import \u627E\u4E0D\u5230\u6587\u4EF6 "${spec}"\uFF08\u5728 ${importerAbs} \u4E2D\uFF09\u2014\u2014\u76F8\u5BF9\u8DEF\u5F84\u6309\u8BE5\u6587\u4EF6\u7684\u6240\u5728\u76EE\u5F55\u89E3\u6790\uFF0C\u8BF7\u68C0\u67E5\u8DEF\u5F84\u662F\u5426\u6B63\u786E\u3002`
1169
+ );
1170
+ return hit.raw;
1171
+ }
1172
+ if (!abs.toLowerCase().endsWith(".css")) return hit.raw;
1173
+ if (seen.has(abs)) return "";
1174
+ seen.add(abs);
1175
+ const source = resolver.read(abs);
1176
+ if (source === null) return hit.raw;
1177
+ return applyImportConditions(expand(stripCharset(source), abs, resolver, seen), hit.conditions);
1178
+ }
1179
+ function inlineCssImports(css, importerAbs, resolver) {
1180
+ return expand(css, importerAbs, resolver, /* @__PURE__ */ new Set([importerAbs]));
1181
+ }
1182
+ var CssImportError, IMPORT_KEYWORD, EXTERNAL_SPEC;
1183
+ var init_css_imports = __esm({
1184
+ "packages/web-container/src/css-imports.ts"() {
1185
+ "use strict";
1186
+ CssImportError = class extends Error {
1187
+ constructor(message) {
1188
+ super(message);
1189
+ this.name = "CssImportError";
1190
+ }
1191
+ };
1192
+ IMPORT_KEYWORD = "@import";
1193
+ EXTERNAL_SPEC = /^(?:[A-Za-z][A-Za-z0-9+.-]*:|\/\/)/i;
1194
+ }
1195
+ });
1196
+
896
1197
  // packages/web-container/src/preview-server.ts
897
1198
  var preview_server_exports = {};
898
1199
  __export(preview_server_exports, {
@@ -906,6 +1207,20 @@ function resolveLocal(vfs, src, baseDir) {
906
1207
  if (!vfs.exists(abs) || vfs.isDirectory(abs)) return null;
907
1208
  return abs;
908
1209
  }
1210
+ function cssResolverOf(vfs) {
1211
+ return {
1212
+ read: (abs) => vfs.exists(abs) && !vfs.isDirectory(abs) ? vfs.readFile(abs) : null,
1213
+ resolve: (spec, importerAbs) => {
1214
+ if (spec.startsWith("./") || spec.startsWith("../") || spec.startsWith("/"))
1215
+ return resolveLocal(vfs, spec, dirname(importerAbs));
1216
+ try {
1217
+ return resolveImport(vfs, spec, importerAbs, "import");
1218
+ } catch {
1219
+ return null;
1220
+ }
1221
+ }
1222
+ };
1223
+ }
909
1224
  function inlineAssets(html, vfs, baseDir) {
910
1225
  let out = html.replace(
911
1226
  /<script\b([^>]*?)\bsrc\s*=\s*(["'])(.*?)\2([^>]*)><\/script>/gi,
@@ -922,7 +1237,13 @@ function inlineAssets(html, vfs, baseDir) {
922
1237
  (whole, _pre, _q, _post, _r, orig) => {
923
1238
  const abs = resolveLocal(vfs, orig, baseDir);
924
1239
  if (abs === null) return whole;
925
- return `<style>${vfs.readFile(abs)}</style>`;
1240
+ const css = vfs.readFile(abs);
1241
+ try {
1242
+ return `<style>${inlineCssImports(css, abs, cssResolverOf(vfs))}</style>`;
1243
+ } catch (error) {
1244
+ if (error instanceof CssImportError) return `<style>${css}</style>`;
1245
+ throw error;
1246
+ }
926
1247
  }
927
1248
  );
928
1249
  return out;
@@ -995,6 +1316,8 @@ var init_preview_server = __esm({
995
1316
  "packages/web-container/src/preview-server.ts"() {
996
1317
  "use strict";
997
1318
  init_path();
1319
+ init_node_resolve();
1320
+ init_css_imports();
998
1321
  EXTERNAL_SRC = /(?:^https?:)?\/\//i;
999
1322
  }
1000
1323
  });
@@ -1294,12 +1617,76 @@ var init_function_fetch_proxy = __esm({
1294
1617
  }
1295
1618
  });
1296
1619
 
1620
+ // packages/web-container/src/console-relay.ts
1621
+ var CONSOLE_RELAY_SCRIPT;
1622
+ var init_console_relay = __esm({
1623
+ "packages/web-container/src/console-relay.ts"() {
1624
+ "use strict";
1625
+ CONSOLE_RELAY_SCRIPT = [
1626
+ "(function () {",
1627
+ " if (window.__adepErrorRelayInstalled) return;",
1628
+ " window.__adepErrorRelayInstalled = true;",
1629
+ ' var LEVELS = { log: "log", info: "info", warn: "warn", error: "error", debug: "log" };',
1630
+ " function fmt(value) {",
1631
+ " try {",
1632
+ ' if (typeof value === "string") return value;',
1633
+ ' if (value === undefined) return "undefined";',
1634
+ " var seen = [];",
1635
+ " var json = JSON.stringify(value, function (key, val) {",
1636
+ ' if (val instanceof Error) return val.stack || (val.name + ": " + val.message);',
1637
+ ' if (typeof val === "function") return "[Function " + (val.name || "anonymous") + "]";',
1638
+ ' if (typeof val === "bigint") return String(val) + "n";',
1639
+ ' if (val && typeof val === "object") {',
1640
+ ' if (seen.indexOf(val) !== -1) return "[Circular]";',
1641
+ " seen.push(val);",
1642
+ " }",
1643
+ " return val;",
1644
+ " });",
1645
+ " return json === undefined ? String(value) : json;",
1646
+ " } catch {",
1647
+ " return String(value);",
1648
+ " }",
1649
+ " }",
1650
+ " function send(level, args) {",
1651
+ " try {",
1652
+ " if (window.parent === window) return;",
1653
+ ' var text = Array.prototype.map.call(args, fmt).join(" ");',
1654
+ ' window.parent.postMessage({ source: "adep-ide-preview", kind: "console", level: level, text: text }, "*");',
1655
+ " } catch {",
1656
+ " }",
1657
+ " }",
1658
+ " Object.keys(LEVELS).forEach(function (name) {",
1659
+ " var native = console[name];",
1660
+ " console[name] = function () {",
1661
+ " send(LEVELS[name], arguments);",
1662
+ " native.apply(console, arguments);",
1663
+ " };",
1664
+ " });",
1665
+ " window.addEventListener('error', function (event) {",
1666
+ ' var text = event.message || "Script error";',
1667
+ " if (event.filename) {",
1668
+ ' text += " (" + event.filename + ":" + event.lineno + ":" + event.colno + ")";',
1669
+ " }",
1670
+ ' send("error", [text]);',
1671
+ " });",
1672
+ " window.addEventListener('unhandledrejection', function (event) {",
1673
+ " var reason = event.reason;",
1674
+ ' var text = reason && reason.stack ? String(reason.stack) : "Unhandled rejection: " + fmt(reason);',
1675
+ ' send("error", [text]);',
1676
+ " });",
1677
+ "})();",
1678
+ ""
1679
+ ].join("\n");
1680
+ }
1681
+ });
1682
+
1297
1683
  // packages/web-container/src/vite-dev.ts
1298
1684
  var vite_dev_exports = {};
1299
1685
  __export(vite_dev_exports, {
1300
1686
  ViteDevError: () => ViteDevError,
1301
1687
  createViteServer: () => createViteServer,
1302
- scanEsmSpecifiers: () => scanEsmSpecifiers
1688
+ scanEsmSpecifiers: () => scanEsmSpecifiers,
1689
+ scanRequireSpecifiers: () => scanRequireSpecifiers
1303
1690
  });
1304
1691
  function tokenize2(source) {
1305
1692
  const tokens = [];
@@ -1397,6 +1784,20 @@ function scanEsmSpecifiers(source) {
1397
1784
  }
1398
1785
  return hits;
1399
1786
  }
1787
+ function scanRequireSpecifiers(source) {
1788
+ const tokens = tokenize2(source);
1789
+ const hits = [];
1790
+ for (let i = 0; i + 3 < tokens.length; i++) {
1791
+ const call = tokens[i];
1792
+ if (call.kind !== "ident" || call.text !== "require") continue;
1793
+ if (tokens[i + 1]?.text !== "(") continue;
1794
+ const arg = tokens[i + 2];
1795
+ if (arg.kind !== "string") continue;
1796
+ if (tokens[i + 3]?.text !== ")") continue;
1797
+ hits.push({ specifier: arg.text.slice(1, -1), start: arg.start, end: arg.end });
1798
+ }
1799
+ return hits;
1800
+ }
1400
1801
  function cssModule(css) {
1401
1802
  return [
1402
1803
  `const css = ${JSON.stringify(css)};`,
@@ -1427,6 +1828,113 @@ function jsonModule(source, abs) {
1427
1828
  }
1428
1829
  return `export default ${source.trim()};`;
1429
1830
  }
1831
+ function stripShebang(source) {
1832
+ if (!source.startsWith("#!")) return source;
1833
+ const nl = source.indexOf("\n");
1834
+ return nl === -1 ? "" : source.slice(nl + 1);
1835
+ }
1836
+ function hasEsmSyntax(source) {
1837
+ const tokens = tokenize2(source);
1838
+ for (let i = 0; i < tokens.length; i++) {
1839
+ const tok = tokens[i];
1840
+ if (tok.kind !== "ident") continue;
1841
+ if (tok.text === "export") return true;
1842
+ if (tok.text === "import" && tokens[i + 1]?.text !== "(") return true;
1843
+ }
1844
+ return false;
1845
+ }
1846
+ function isCommonJs(abs, source) {
1847
+ if (abs.endsWith(".cjs")) return true;
1848
+ if (!abs.endsWith(".js")) return false;
1849
+ if (hasEsmSyntax(source)) return false;
1850
+ return /\bmodule\s*\.\s*exports\b|\bexports\s*\.|\brequire\s*\(/.test(source);
1851
+ }
1852
+ function collectCjsExportNames(source) {
1853
+ const tokens = tokenize2(source);
1854
+ const names = /* @__PURE__ */ new Set();
1855
+ const isIdent = (index) => {
1856
+ const tok = tokens[index];
1857
+ return tok?.kind === "ident" && VALID_IDENT.test(tok.text) ? tok.text : null;
1858
+ };
1859
+ for (let i = 0; i < tokens.length; i++) {
1860
+ const tok = tokens[i];
1861
+ if (tok.kind !== "ident") continue;
1862
+ if (tok.text === "exports") {
1863
+ const name = isIdent(i + 2);
1864
+ if (tokens[i + 1]?.text === "." && name !== null && tokens[i + 3]?.text === "=")
1865
+ names.add(name);
1866
+ continue;
1867
+ }
1868
+ if (tok.text === "module") {
1869
+ const name = isIdent(i + 4);
1870
+ if (tokens[i + 1]?.text === "." && tokens[i + 2]?.text === "exports" && tokens[i + 3]?.text === "." && name !== null && tokens[i + 5]?.text === "=") {
1871
+ names.add(name);
1872
+ }
1873
+ if (tokens[i + 1]?.text === "." && tokens[i + 2]?.text === "exports" && tokens[i + 3]?.text === "=" && tokens[i + 4]?.text === "{") {
1874
+ let depth = 0;
1875
+ for (let j = i + 4; j < tokens.length; j++) {
1876
+ const t = tokens[j];
1877
+ if (t.kind === "string" || t.kind === "template") continue;
1878
+ if (t.text === "{") depth++;
1879
+ else if (t.text === "}") {
1880
+ depth--;
1881
+ if (depth === 0) break;
1882
+ } else if (depth === 1) {
1883
+ const prev = tokens[j - 1]?.text;
1884
+ const key = isIdent(j);
1885
+ const next = tokens[j + 1]?.text;
1886
+ if (key !== null && (prev === "{" || prev === ",") && (next === ":" || next === "," || next === "}")) {
1887
+ names.add(key);
1888
+ }
1889
+ }
1890
+ }
1891
+ continue;
1892
+ }
1893
+ continue;
1894
+ }
1895
+ if (tok.text === "Object") {
1896
+ if (tokens[i + 1]?.text === "." && tokens[i + 2]?.text === "defineProperty" && tokens[i + 3]?.text === "(" && tokens[i + 4]?.text === "exports" && tokens[i + 5]?.text === "," && tokens[i + 6]?.kind === "string") {
1897
+ names.add(tokens[i + 6].text.slice(1, -1));
1898
+ }
1899
+ }
1900
+ }
1901
+ names.delete("default");
1902
+ return [...names].filter((name) => VALID_IDENT.test(name) && !CJS_INTERNALS.has(name));
1903
+ }
1904
+ function wrapCommonJs(abs, source) {
1905
+ const specifiers = [...new Set(scanRequireSpecifiers(source).map((hit) => hit.specifier))];
1906
+ const prelude = specifiers.map(
1907
+ (spec, index) => `import * as ${CJS_PREFIX}Dep${index} from ${JSON.stringify(CJS_SPECIFIER_PREFIX + spec)};`
1908
+ );
1909
+ const entries = specifiers.map(
1910
+ (spec, index) => `${JSON.stringify(spec)}: ${CJS_PREFIX}Dep${index}`
1911
+ );
1912
+ const names = collectCjsExportNames(source);
1913
+ const detail = JSON.stringify(
1914
+ `${abs} \u91CC\u7684 require() \u8BF4\u660E\u7B26\u65E0\u6CD5\u89E3\u6790\uFF08Node \u5185\u5EFA\u6A21\u5757\u6D4F\u89C8\u5668\u4E0D\u63D0\u4F9B / \u4F9D\u8D56\u672A\u5B89\u88C5 / \u52A8\u6001\u62FC\u63A5\uFF09`
1915
+ );
1916
+ return [
1917
+ ...prelude,
1918
+ `const ${CJS_PREFIX}Map = { ${entries.join(", ")} };`,
1919
+ `const ${CJS_PREFIX}Require = (id) => {`,
1920
+ ` const ns = ${CJS_PREFIX}Map[id];`,
1921
+ ` if (ns === undefined || ns.${CJS_PREFIX}Unresolved === true)`,
1922
+ ` throw new Error('require(' + JSON.stringify(id) + ') \u65E0\u6CD5\u89E3\u6790\uFF1A' + ${detail});`,
1923
+ ` return ns[${JSON.stringify(CJS_EXPORTS_MARKER)}] !== undefined ? ns[${JSON.stringify(CJS_EXPORTS_MARKER)}] : ns;`,
1924
+ `};`,
1925
+ `const ${CJS_PREFIX}Module = { exports: {} };`,
1926
+ "(function (module, exports, require) {",
1927
+ source,
1928
+ `}).call(${CJS_PREFIX}Module.exports, ${CJS_PREFIX}Module, ${CJS_PREFIX}Module.exports, ${CJS_PREFIX}Require);`,
1929
+ `const ${CJS_EXPORTS_MARKER}Value = ${CJS_PREFIX}Module.exports;`,
1930
+ `export const ${CJS_EXPORTS_MARKER} = ${CJS_EXPORTS_MARKER}Value;`,
1931
+ `const ${CJS_PREFIX}Default = ${CJS_EXPORTS_MARKER}Value && ${CJS_EXPORTS_MARKER}Value.__esModule ? ${CJS_EXPORTS_MARKER}Value.default : ${CJS_EXPORTS_MARKER}Value;`,
1932
+ `export default ${CJS_PREFIX}Default;`,
1933
+ ...names.map(
1934
+ (name) => `export const ${name} = ${CJS_EXPORTS_MARKER}Value[${JSON.stringify(name)}];`
1935
+ )
1936
+ ].join("\n");
1937
+ }
1430
1938
  function resolveWithSuffixes(vfs, base) {
1431
1939
  if (vfs.exists(base) && !vfs.isDirectory(base)) return base;
1432
1940
  const asFile2 = VITE_RESOLVE_SUFFIXES.map((suffix) => `${base}${suffix}`);
@@ -1473,15 +1981,42 @@ function createViteServer(vfs, options = {}) {
1473
1981
  [/\bprocess\s*\.\s*env\s*\.\s*NODE_ENV\b/g, JSON.stringify("development")],
1474
1982
  [/\b__VUE_OPTIONS_API__\b/g, "true"],
1475
1983
  [/\b__VUE_PROD_DEVTOOLS__\b/g, "false"],
1476
- [/\b__VUE_PROD_HYDRATION_MISMATCH_DETAILS__\b/g, "false"]
1984
+ [/\b__VUE_PROD_HYDRATION_MISMATCH_DETAILS__\b/g, "false"],
1985
+ [
1986
+ /\bimport\s*\.\s*meta\s*\.\s*env\b/g,
1987
+ '({ BASE_URL: "/", MODE: "development", DEV: true, PROD: false, SSR: false })'
1988
+ ]
1477
1989
  ];
1478
1990
  function applyDefines(code) {
1479
1991
  let out = code;
1480
1992
  for (const [pattern, value] of DEFINES) out = out.replace(pattern, value);
1481
1993
  return out;
1482
1994
  }
1995
+ const cssResolver = {
1996
+ read: (abs) => vfs.exists(abs) && !vfs.isDirectory(abs) ? vfs.readFile(abs) : null,
1997
+ resolve: (spec, importerAbs) => {
1998
+ if (spec.startsWith("./") || spec.startsWith("../") || spec.startsWith("/")) {
1999
+ const base = spec.startsWith("/") ? absoluteFromRoot(spec) : join(dirname(importerAbs), spec);
2000
+ const target = resolveWithSuffixes(vfs, base);
2001
+ return vfs.exists(target) && !vfs.isDirectory(target) ? target : null;
2002
+ }
2003
+ try {
2004
+ return resolveImport(vfs, spec, importerAbs, "import");
2005
+ } catch {
2006
+ return null;
2007
+ }
2008
+ }
2009
+ };
2010
+ function inlineCss(css, importerAbs) {
2011
+ try {
2012
+ return inlineCssImports(css, importerAbs, cssResolver);
2013
+ } catch (error) {
2014
+ if (error instanceof CssImportError) throw new ViteDevError("CSS_IMPORT", error.message);
2015
+ throw error;
2016
+ }
2017
+ }
1483
2018
  function transformModule2(abs, source) {
1484
- if (abs.endsWith(".css")) return cssModule(source);
2019
+ if (abs.endsWith(".css")) return cssModule(inlineCss(source, abs));
1485
2020
  if (abs.endsWith(".json")) return jsonModule(source, abs);
1486
2021
  if (abs.endsWith(".vue")) {
1487
2022
  if (sfcCompiler === void 0)
@@ -1491,7 +2026,9 @@ function createViteServer(vfs, options = {}) {
1491
2026
  );
1492
2027
  const compiled = sfcCompiler(source, abs);
1493
2028
  return [
1494
- ...compiled.styles.map((css, index) => inlineStyleBlock(css, `${abs}#${index}`)),
2029
+ ...compiled.styles.map(
2030
+ (css, index) => inlineStyleBlock(inlineCss(css, abs), `${abs}#${index}`)
2031
+ ),
1495
2032
  applyDefines(stripTypes(compiled.script))
1496
2033
  ].join("\n");
1497
2034
  }
@@ -1500,37 +2037,65 @@ function createViteServer(vfs, options = {}) {
1500
2037
  "JSX_UNSUPPORTED",
1501
2038
  `${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`
1502
2039
  );
1503
- if (abs.endsWith(".ts") || abs.endsWith(".mts")) return applyDefines(stripTypes(source));
1504
- return applyDefines(source);
2040
+ const bare = stripShebang(source);
2041
+ if (abs.endsWith(".ts") || abs.endsWith(".mts")) return applyDefines(stripTypes(bare));
2042
+ if (isCommonJs(abs, bare)) return applyDefines(wrapCommonJs(abs, bare));
2043
+ return applyDefines(bare);
1505
2044
  }
1506
2045
  function absoluteFromRoot(spec) {
1507
2046
  return join(root, spec.replace(/^\/+/, ""));
1508
2047
  }
1509
- async function resolveSpecifier(spec, importerAbs) {
1510
- if (EXTERNAL_SPECIFIER.test(spec) || DATA_OR_BLOB.test(spec)) return spec;
1511
- let target;
2048
+ function resolveToAbs(spec, importerAbs) {
1512
2049
  if (spec.startsWith("./") || spec.startsWith("../") || spec.startsWith("/")) {
1513
2050
  const base = spec.startsWith("/") ? absoluteFromRoot(spec) : join(dirname(importerAbs), spec);
1514
- target = resolveWithSuffixes(vfs, base);
2051
+ const target = resolveWithSuffixes(vfs, base);
1515
2052
  if (!vfs.exists(target) || vfs.isDirectory(target))
1516
2053
  throw new ViteDevError(
1517
2054
  "RESOLVE",
1518
2055
  `\u627E\u4E0D\u5230\u6A21\u5757 "${spec}"\uFF08\u81EA ${importerAbs}\uFF1B\u8BD5\u8FC7\u6269\u5C55\u540D ${VITE_RESOLVE_SUFFIXES.join("/")} \u4E0E\u76EE\u5F55 index\uFF09`
1519
2056
  );
1520
- } else {
1521
- try {
1522
- target = resolveImport(vfs, spec, importerAbs, "import");
1523
- } catch (error) {
1524
- if (error instanceof ResolveError)
1525
- throw new ViteDevError(
1526
- "RESOLVE",
1527
- `${error.message}
2057
+ return target;
2058
+ }
2059
+ try {
2060
+ return resolveImport(vfs, spec, importerAbs, "import");
2061
+ } catch (error) {
2062
+ if (error instanceof ResolveError)
2063
+ throw new ViteDevError(
2064
+ "RESOLVE",
2065
+ `${error.message}
1528
2066
  \uFF08\u5728 ${importerAbs} \u4E2D import "${spec}"\uFF09`
1529
- );
1530
- throw error;
2067
+ );
2068
+ throw error;
2069
+ }
2070
+ }
2071
+ const cjsStubSources = /* @__PURE__ */ new Map();
2072
+ function cjsStubUrl(spec) {
2073
+ let abs = cjsStubSources.get(spec);
2074
+ if (abs === void 0) {
2075
+ abs = `${INLINE_PREFIX}cjs_stub_${cjsStubSources.size}.mjs`;
2076
+ cjsStubSources.set(spec, abs);
2077
+ inlineSources.set(
2078
+ abs,
2079
+ [
2080
+ `export const ${CJS_PREFIX}Unresolved = true;`,
2081
+ `export const ${CJS_PREFIX}Specifier = ${JSON.stringify(spec)};`,
2082
+ "export default undefined;"
2083
+ ].join("\n")
2084
+ );
2085
+ }
2086
+ return loadModuleUrl(abs);
2087
+ }
2088
+ async function resolveSpecifier(spec, importerAbs) {
2089
+ if (spec.startsWith(CJS_SPECIFIER_PREFIX)) {
2090
+ const original = spec.slice(CJS_SPECIFIER_PREFIX.length);
2091
+ try {
2092
+ return await loadModuleUrl(resolveToAbs(original, importerAbs));
2093
+ } catch {
2094
+ return cjsStubUrl(original);
1531
2095
  }
1532
2096
  }
1533
- return loadModuleUrl(target);
2097
+ if (EXTERNAL_SPECIFIER.test(spec) || DATA_OR_BLOB.test(spec)) return spec;
2098
+ return loadModuleUrl(resolveToAbs(spec, importerAbs));
1534
2099
  }
1535
2100
  async function loadModuleUrl(abs) {
1536
2101
  const cached = moduleUrls.get(abs);
@@ -1622,14 +2187,15 @@ function createViteServer(vfs, options = {}) {
1622
2187
  );
1623
2188
  const urls = await Promise.all(entryModuleUrls);
1624
2189
  html = html.replace(/__adep_vite_entry_(\d+)__/g, (_m, idx) => urls[Number(idx)] ?? "");
1625
- const interceptor = `<script>${FN_FETCH_INTERCEPTOR_SCRIPT}</script>`;
1626
- html = /<head[^>]*>/i.test(html) ? html.replace(/<head[^>]*>/i, (m) => `${m}${interceptor}`) : `${interceptor}${html}`;
2190
+ const preludeScripts = `<script>${CONSOLE_RELAY_SCRIPT}</script><script>${FN_FETCH_INTERCEPTOR_SCRIPT}</script>`;
2191
+ html = /<head[^>]*>/i.test(html) ? html.replace(/<head[^>]*>/i, (m) => `${m}${preludeScripts}`) : `${preludeScripts}${html}`;
1627
2192
  const hmr = hmrScript(channelName);
1628
2193
  return /<\/body>/i.test(html) ? html.replace(/<\/(body)>/i, `${hmr}</$1>`) : html + hmr;
1629
2194
  }
1630
2195
  async function rebuild() {
1631
2196
  moduleUrls = /* @__PURE__ */ new Map();
1632
2197
  inlineSources = /* @__PURE__ */ new Map();
2198
+ cjsStubSources.clear();
1633
2199
  inlineSeq = 0;
1634
2200
  let doc;
1635
2201
  try {
@@ -1639,6 +2205,7 @@ function createViteServer(vfs, options = {}) {
1639
2205
  }
1640
2206
  const changed = lastDoc !== null && doc !== lastDoc;
1641
2207
  lastDoc = doc;
2208
+ if (!changed && currentUrl !== "") return;
1642
2209
  if (currentUrl !== "") revokeObjectURL(currentUrl);
1643
2210
  currentUrl = createObjectURL(new Blob([doc], { type: "text/html" }));
1644
2211
  if (changed) {
@@ -1677,7 +2244,7 @@ function createViteServer(vfs, options = {}) {
1677
2244
  const unsubscribeMutate = vfs.onMutate(scheduleRebuild);
1678
2245
  return server;
1679
2246
  }
1680
- 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;
2247
+ var ViteDevError, REGEX_PRECEDING_CHARS, REGEX_PRECEDING_KEYWORDS, isIdentStart, isIdentPart, CJS_PREFIX, CJS_EXPORTS_MARKER, CJS_SPECIFIER_PREFIX, VALID_IDENT, CJS_INTERNALS, VITE_RESOLVE_SUFFIXES, INLINE_PREFIX, EXTERNAL_SPECIFIER, DATA_OR_BLOB, MODULE_SCRIPT_SRC_RE, MODULE_SCRIPT_INLINE_RE;
1681
2248
  var init_vite_dev = __esm({
1682
2249
  "packages/web-container/src/vite-dev.ts"() {
1683
2250
  "use strict";
@@ -1686,6 +2253,8 @@ var init_vite_dev = __esm({
1686
2253
  init_strip_types();
1687
2254
  init_preview_server();
1688
2255
  init_function_fetch_proxy();
2256
+ init_console_relay();
2257
+ init_css_imports();
1689
2258
  ViteDevError = class extends Error {
1690
2259
  constructor(reason, message) {
1691
2260
  super(message);
@@ -1734,6 +2303,22 @@ var init_vite_dev = __esm({
1734
2303
  ]);
1735
2304
  isIdentStart = (ch) => /[A-Za-z_$]/.test(ch);
1736
2305
  isIdentPart = (ch) => /[A-Za-z0-9_$]/.test(ch);
2306
+ CJS_PREFIX = "__adepCjs";
2307
+ CJS_EXPORTS_MARKER = `${CJS_PREFIX}Exports`;
2308
+ CJS_SPECIFIER_PREFIX = `${CJS_PREFIX}Spec:`;
2309
+ VALID_IDENT = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
2310
+ CJS_INTERNALS = /* @__PURE__ */ new Set([
2311
+ "module",
2312
+ "exports",
2313
+ "require",
2314
+ // 互操作标记而非用户导出:Babel 产物会 defineProperty(exports, "__esModule"),转发它没有意义。
2315
+ "__esModule",
2316
+ `${CJS_EXPORTS_MARKER}`,
2317
+ `${CJS_PREFIX}Default`,
2318
+ `${CJS_PREFIX}Map`,
2319
+ `${CJS_PREFIX}Module`,
2320
+ `${CJS_PREFIX}Require`
2321
+ ]);
1737
2322
  VITE_RESOLVE_SUFFIXES = [".ts", ".js", ".mjs", ".mts", ".vue", ".json", ".css"];
1738
2323
  INLINE_PREFIX = "/__vite_inline_";
1739
2324
  EXTERNAL_SPECIFIER = /^(?:https?:)?\/\//i;
@@ -2793,7 +3378,7 @@ async function unpackNpmTarball(bytes) {
2793
3378
 
2794
3379
  // packages/web-container/src/npm-client.ts
2795
3380
  init_node_resolve();
2796
- var DEFAULT_MAX_INSTALL_DEPTH = 5;
3381
+ var DEFAULT_MAX_INSTALL_DEPTH = 25;
2797
3382
  var defaultFetch = (url, init) => globalThis.fetch(url, init).then((res) => res);
2798
3383
  function parseSpec(spec) {
2799
3384
  if (spec.startsWith("@")) {
@@ -2818,29 +3403,50 @@ async function relayFetch(fetchImpl, url, what) {
2818
3403
  throw new Error(`${what} \u5931\u8D25\uFF1A\u65E0\u6CD5\u8BBF\u95EE npm \u4E2D\u7EE7\uFF08${url}\uFF0C${reason}\uFF09`, { cause: error });
2819
3404
  }
2820
3405
  }
3406
+ var RATE_LIMIT_MAX_RETRIES = 120;
3407
+ var DEFAULT_RETRY_AFTER_MS = 1e3;
3408
+ var MAX_RETRY_AFTER_MS = 6e4;
3409
+ var defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
3410
+ function retryAfterMs(res) {
3411
+ const raw = res.headers["retry-after"];
3412
+ const seconds = raw === void 0 ? Number.NaN : Number.parseFloat(raw);
3413
+ if (!Number.isFinite(seconds) || seconds <= 0) return DEFAULT_RETRY_AFTER_MS;
3414
+ return Math.min(seconds * 1e3, MAX_RETRY_AFTER_MS);
3415
+ }
2821
3416
  function createNpmClient(options) {
2822
3417
  const fetchImpl = options.fetchImpl ?? defaultFetch;
2823
3418
  const base = options.baseUrl.replace(/\/+$/, "");
2824
3419
  const storage = options.storage;
2825
3420
  const maxDepth = options.maxDepth ?? DEFAULT_MAX_INSTALL_DEPTH;
3421
+ const sleep = options.sleep ?? defaultSleep;
3422
+ async function relayRequest(url, what) {
3423
+ for (let attempt = 0; ; attempt += 1) {
3424
+ const res = await relayFetch(fetchImpl, url, what);
3425
+ if (res.status !== 429) return res;
3426
+ if (attempt >= RATE_LIMIT_MAX_RETRIES) {
3427
+ throw new Error(
3428
+ `${what} \u5931\u8D25\uFF1Anpm \u4E2D\u7EE7\u9650\u901F\uFF08HTTP 429\uFF09\uFF0C\u5DF2\u6309 Retry-After \u9000\u907F\u91CD\u8BD5 ${attempt} \u6B21\u4ECD\u88AB\u62D2\u2014\u2014\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002`
3429
+ );
3430
+ }
3431
+ await sleep(retryAfterMs(res));
3432
+ }
3433
+ }
2826
3434
  async function resolvePackage(name, spec) {
2827
3435
  const params = new URLSearchParams({ name });
2828
3436
  if (spec !== void 0) params.set("spec", spec);
2829
- const res = await relayFetch(
2830
- fetchImpl,
3437
+ const res = await relayRequest(
2831
3438
  `${base}/package?${params.toString()}`,
2832
3439
  `\u89E3\u6790\u5305 ${name}@${spec ?? "latest"}`
2833
3440
  );
2834
3441
  if (!res.ok) {
2835
3442
  throw new Error(
2836
- `\u89E3\u6790\u5305\u5931\u8D25 ${name}@${spec ?? "latest"}\uFF1AHTTP ${res.status}\uFF08\u4E0D\u5728\u767D\u540D\u5355\u6216\u5305\u4E0D\u5B58\u5728\u65F6\u7531\u4E2D\u7EE7\u62D2\u7EDD\uFF09`
3443
+ `\u89E3\u6790\u5305\u5931\u8D25 ${name}@${spec ?? "latest"}\uFF1AHTTP ${res.status}\uFF08\u4E2D\u7EE7\u62D2\u7EDD\uFF1A\u5305\u4E0D\u5B58\u5728 / registry \u4E0D\u53EF\u8FBE / registry \u975E\u767D\u540D\u5355\uFF09`
2837
3444
  );
2838
3445
  }
2839
3446
  return await res.json();
2840
3447
  }
2841
3448
  async function fetchAndUnpack(name, version) {
2842
- const res = await relayFetch(
2843
- fetchImpl,
3449
+ const res = await relayRequest(
2844
3450
  `${base}/tarball?${new URLSearchParams({ name, version }).toString()}`,
2845
3451
  `\u4E0B\u8F7D tarball ${name}@${version}`
2846
3452
  );
@@ -2864,17 +3470,12 @@ function createNpmClient(options) {
2864
3470
  return null;
2865
3471
  }
2866
3472
  }
2867
- async function collect(name, spec, depth, path, staged, onStack, visited, packages, distTagsByName) {
3473
+ async function collect(name, spec, depth, path, staged, visited, packages, distTagsByName) {
2868
3474
  if (depth > maxDepth) {
2869
3475
  throw new Error(
2870
3476
  `\u4F9D\u8D56\u5C42\u7EA7\u8D85\u8FC7\u4E0A\u9650\uFF08${maxDepth}\uFF09\uFF1A${[...path, name].join(" \u2192 ")}\u3002\u8BF7\u6539\u7528\u66F4\u8F7B\u7684\u5305\u6216\u7ECF\u670D\u52A1\u7AEF\u53D1\u5E03\u94FE\u8DEF\u5B89\u88C5\uFF08FN-009 \u5B9E\u65F6\u88C5\u8F7D\uFF09\u3002`
2871
3477
  );
2872
3478
  }
2873
- if (onStack.has(name)) {
2874
- throw new Error(
2875
- `\u68C0\u6D4B\u5230\u5FAA\u73AF\u4F9D\u8D56\uFF1A${[...path, name].join(" \u2192 ")}\u3002\u6D4F\u89C8\u5668\u5B89\u88C5\u4E0D\u652F\u6301\u73AF\u72B6\u4F9D\u8D56\u6811\uFF0C\u8BF7\u79FB\u9664\u73AF\u4E0A\u5305\u7684\u76F8\u4E92\u58F0\u660E\u3002`
2876
- );
2877
- }
2878
3479
  const meta = await resolvePackage(name, spec);
2879
3480
  distTagsByName.set(meta.name, meta.distTags ?? []);
2880
3481
  const key = `${meta.name}@${meta.version}`;
@@ -2898,8 +3499,6 @@ function createNpmClient(options) {
2898
3499
  }
2899
3500
  Object.assign(deps, pkgMeta.dependencies ?? {});
2900
3501
  }
2901
- const nextStack = new Set(onStack);
2902
- nextStack.add(meta.name);
2903
3502
  for (const [depName, depSpec] of Object.entries(deps)) {
2904
3503
  await collect(
2905
3504
  depName,
@@ -2907,7 +3506,6 @@ function createNpmClient(options) {
2907
3506
  depth + 1,
2908
3507
  [...path, meta.name],
2909
3508
  staged,
2910
- nextStack,
2911
3509
  visited,
2912
3510
  packages,
2913
3511
  distTagsByName
@@ -2916,7 +3514,7 @@ function createNpmClient(options) {
2916
3514
  }
2917
3515
  return {
2918
3516
  async registries() {
2919
- const res = await relayFetch(fetchImpl, `${base}/registry`, "\u83B7\u53D6 registry \u5217\u8868");
3517
+ const res = await relayRequest(`${base}/registry`, "\u83B7\u53D6 registry \u5217\u8868");
2920
3518
  if (!res.ok) throw new Error(`\u83B7\u53D6 registry \u5217\u8868\u5931\u8D25\uFF1AHTTP ${res.status}`);
2921
3519
  const body = await res.json();
2922
3520
  return body.registries;
@@ -2926,7 +3524,7 @@ function createNpmClient(options) {
2926
3524
  const staged = /* @__PURE__ */ new Map();
2927
3525
  const packages = [];
2928
3526
  const distTagsByName = /* @__PURE__ */ new Map();
2929
- await collect(name, spec, 1, [], staged, /* @__PURE__ */ new Set(), /* @__PURE__ */ new Set(), packages, distTagsByName);
3527
+ await collect(name, spec, 1, [], staged, /* @__PURE__ */ new Set(), packages, distTagsByName);
2930
3528
  const root = packages[0] ?? { name, version: spec ?? "latest" };
2931
3529
  const downloaded = staged.size > 0;
2932
3530
  for (const [path, contents] of staged) storage.writeFile(path, contents);
@@ -5487,6 +6085,7 @@ function stripQuotes(raw) {
5487
6085
  const t = raw.trim();
5488
6086
  if (/^'.*'$/.test(t)) return t.slice(1, -1);
5489
6087
  if (/^".*"$/.test(t)) return t.slice(1, -1);
6088
+ if (/^NULL$/i.test(t)) return null;
5490
6089
  return t;
5491
6090
  }
5492
6091
  function parseCreateTable(ddl) {
@@ -5507,50 +6106,109 @@ function parseCreateTable(ddl) {
5507
6106
  }
5508
6107
  return { name, columns };
5509
6108
  }
5510
- function parseWhereClauses(whereRaw, cursor) {
5511
- const clauses = [];
5512
- for (const part of whereRaw.split(/\s+AND\s+/i)) {
5513
- const t = part.trim();
5514
- if (t.length === 0) continue;
5515
- if (/\bIS\s+NULL\b/i.test(t)) {
5516
- const col2 = ident(t.split(/\s+IS\s+NULL\b/i)[0] ?? "");
5517
- clauses.push({ column: col2, operator: "IS NULL", value: null, list: false });
5518
- continue;
5519
- }
5520
- if (/\bIS\s+NOT\s+NULL\b/i.test(t)) {
5521
- const col2 = ident(t.split(/\s+IS\s+NOT\s+NULL\b/i)[0] ?? "");
5522
- clauses.push({ column: col2, operator: "IS NOT NULL", value: null, list: false });
5523
- continue;
5524
- }
5525
- const opMatch = /^\s*((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_]*))\s*(=|!=|>=|<=|>|<|like|in|not\s+in)\s*(.+)$/i.exec(
5526
- t
5527
- );
5528
- if (opMatch === null) continue;
5529
- const col = ident(opMatch[1] ?? "");
5530
- const op = (opMatch[3] ?? opMatch[2] ?? "").toLowerCase();
5531
- const rhs = (opMatch[4] ?? "").trim();
5532
- if (op === "in" || op === "not in") {
5533
- const inner = rhs.replace(/^\(|\)$/g, "");
5534
- const items = splitListItems(inner);
5535
- const list = items.map((item) => {
5536
- if (item.trim() === "?") return cursor.take();
5537
- return stripQuotes(item);
5538
- });
5539
- clauses.push({ column: col, operator: op, value: list, list: true });
6109
+ function splitTopLevel(raw, token) {
6110
+ const parts = [];
6111
+ let depth = 0;
6112
+ let inQuote = false;
6113
+ let buffer = "";
6114
+ const n = raw.length;
6115
+ const isTokenAt = (i) => {
6116
+ const word = raw.slice(i, i + token.length);
6117
+ if (word.toUpperCase() !== token) return false;
6118
+ const before = i === 0 ? "" : raw[i - 1] ?? "";
6119
+ const after = raw[i + token.length] ?? "";
6120
+ return !/[A-Za-z0-9_.]/.test(before) && !/[A-Za-z0-9_.]/.test(after);
6121
+ };
6122
+ for (let i = 0; i < n; i += 1) {
6123
+ const ch = raw[i] ?? "";
6124
+ if (ch === "'") {
6125
+ if (inQuote && raw[i + 1] === "'") {
6126
+ buffer += ch + (raw[i + 1] ?? "");
6127
+ i += 1;
6128
+ continue;
6129
+ }
6130
+ inQuote = !inQuote;
6131
+ buffer += ch;
5540
6132
  continue;
5541
6133
  }
5542
- let value;
5543
- if (rhs === "?") {
5544
- value = cursor.take();
6134
+ if (!inQuote && ch === "(") depth += 1;
6135
+ else if (!inQuote && ch === ")") depth -= 1;
6136
+ if (!inQuote && depth === 0 && isTokenAt(i)) {
6137
+ parts.push(buffer);
6138
+ buffer = "";
6139
+ i += token.length - 1;
5545
6140
  } else {
5546
- value = stripQuotes(rhs);
6141
+ buffer += ch;
5547
6142
  }
5548
- clauses.push({ column: col, operator: op, value, list: false });
5549
6143
  }
5550
- return clauses;
6144
+ parts.push(buffer);
6145
+ return parts;
5551
6146
  }
5552
- function matchWhere(clauses, row) {
5553
- return clauses.every((c) => matchValue(row[c.column], c));
6147
+ function unqualifyColumn(raw) {
6148
+ const t = raw.trim();
6149
+ const dot = t.lastIndexOf(".");
6150
+ if (dot > 0 && /^[A-Za-z_][A-Za-z0-9_]*\./.test(t)) return t.slice(dot + 1);
6151
+ return t;
6152
+ }
6153
+ function parseLeftJoins(tail) {
6154
+ const joins = [];
6155
+ const re = /LEFT\s+JOIN\s+((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_]*))\s+([A-Za-z_][A-Za-z0-9_]*)\s+ON\s+([A-Za-z_][A-Za-z0-9_.]*)\s*=\s*([A-Za-z_][A-Za-z0-9_.]*)/gi;
6156
+ let m;
6157
+ while ((m = re.exec(tail)) !== null) {
6158
+ joins.push({
6159
+ table: ident(m[1] ?? ""),
6160
+ alias: m[3] ?? "",
6161
+ leftCol: unqualifyColumn(m[4] ?? ""),
6162
+ rightCol: unqualifyColumn(m[5] ?? "")
6163
+ });
6164
+ }
6165
+ return joins;
6166
+ }
6167
+ function parseWhereClauses(whereRaw, cursor) {
6168
+ const parseAndGroup = (andRaw) => {
6169
+ const clauses = [];
6170
+ for (const part of splitTopLevel(andRaw, "AND")) {
6171
+ const t = part.trim();
6172
+ if (t.length === 0) continue;
6173
+ if (/\bIS\s+NULL\b/i.test(t)) {
6174
+ clauses.push({ column: unqualifyColumn(ident(t.split(/\s+IS\s+NULL\b/i)[0] ?? "")), operator: "IS NULL", value: null, list: false });
6175
+ continue;
6176
+ }
6177
+ if (/\bIS\s+NOT\s+NULL\b/i.test(t)) {
6178
+ clauses.push({ column: unqualifyColumn(ident(t.split(/\s+IS\s+NOT\s+NULL\b/i)[0] ?? "")), operator: "IS NOT NULL", value: null, list: false });
6179
+ continue;
6180
+ }
6181
+ const opMatch = /^\s*((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_.]*))\s*(=|!=|>=|<=|>|<|like|in|not\s+in)\s*(.+)$/i.exec(
6182
+ t
6183
+ );
6184
+ if (opMatch === null) continue;
6185
+ const col = unqualifyColumn(ident(opMatch[1] ?? ""));
6186
+ const op = (opMatch[3] ?? opMatch[2] ?? "").toLowerCase();
6187
+ const rhs = (opMatch[4] ?? "").trim();
6188
+ if (op === "in" || op === "not in") {
6189
+ const inner = rhs.replace(/^\(|\)$/g, "");
6190
+ const items = splitListItems(inner);
6191
+ const list = items.map((item) => {
6192
+ if (item.trim() === "?") return cursor.take();
6193
+ return stripQuotes(item);
6194
+ });
6195
+ clauses.push({ column: col, operator: op, value: list, list: true });
6196
+ continue;
6197
+ }
6198
+ let value;
6199
+ if (rhs === "?") {
6200
+ value = cursor.take();
6201
+ } else {
6202
+ value = stripQuotes(rhs);
6203
+ }
6204
+ clauses.push({ column: col, operator: op, value, list: false });
6205
+ }
6206
+ return clauses;
6207
+ };
6208
+ return splitTopLevel(whereRaw, "OR").map((group) => group.trim()).filter((group) => group.length > 0).map(parseAndGroup);
6209
+ }
6210
+ function matchWhere(groups, row) {
6211
+ return groups.some((clauses) => clauses.every((c) => matchValue(row[c.column], c)));
5554
6212
  }
5555
6213
  function splitListItems(inner) {
5556
6214
  const items = [];
@@ -5570,6 +6228,168 @@ function splitListItems(inner) {
5570
6228
  items.push(buffer);
5571
6229
  return items;
5572
6230
  }
6231
+ var ExcludedRef = class {
6232
+ constructor(column) {
6233
+ this.column = column;
6234
+ }
6235
+ };
6236
+ var ColumnRef = class {
6237
+ constructor(column) {
6238
+ this.column = column;
6239
+ }
6240
+ };
6241
+ var ExprRef = class {
6242
+ constructor(source) {
6243
+ this.source = source;
6244
+ }
6245
+ };
6246
+ function resolveSetValue(value, existing, row) {
6247
+ if (value instanceof ExcludedRef) return row[value.column];
6248
+ if (value instanceof ColumnRef) return existing[value.column];
6249
+ if (value instanceof ExprRef) return evalArithmetic(value.source, existing, row);
6250
+ return value;
6251
+ }
6252
+ function evalArithmetic(src, existing, row) {
6253
+ const num = (v) => {
6254
+ const n2 = Number(v);
6255
+ return Number.isFinite(n2) ? n2 : 0;
6256
+ };
6257
+ let i = 0;
6258
+ const n = src.length;
6259
+ const skip = () => {
6260
+ while (i < n && /\s/.test(src[i] ?? "")) i += 1;
6261
+ };
6262
+ const peek = () => {
6263
+ skip();
6264
+ return i < n ? src[i] ?? "" : null;
6265
+ };
6266
+ const parseIdent = () => {
6267
+ skip();
6268
+ const m = /^([A-Za-z_][A-Za-z0-9_]*)/.exec(src.slice(i));
6269
+ if (m === null) return null;
6270
+ i += (m[1] ?? "").length;
6271
+ skip();
6272
+ let col = ident(m[1] ?? "");
6273
+ let excluded = false;
6274
+ if (src[i] === ".") {
6275
+ const m2 = /^\.([A-Za-z_][A-Za-z0-9_]*)/.exec(src.slice(i));
6276
+ if (m2 !== null) {
6277
+ i += (m2[0] ?? "").length;
6278
+ if (col.toLowerCase() === "excluded") excluded = true;
6279
+ col = ident(m2[1] ?? "");
6280
+ }
6281
+ }
6282
+ return { col, excluded };
6283
+ };
6284
+ const parseFactor = () => {
6285
+ const ch = peek();
6286
+ if (ch === "(") {
6287
+ i += 1;
6288
+ const v = parseExpr();
6289
+ skip();
6290
+ if (src[i] === ")") i += 1;
6291
+ return v;
6292
+ }
6293
+ const numMatch = /^(\d+(?:\.\d+)?)/.exec(src.slice(i));
6294
+ if (numMatch !== null) {
6295
+ i += (numMatch[1] ?? "").length;
6296
+ return Number(numMatch[1]);
6297
+ }
6298
+ const id = parseIdent();
6299
+ if (id !== null) {
6300
+ const v = id.excluded ? row[id.col] : existing[id.col];
6301
+ return num(v);
6302
+ }
6303
+ return 0;
6304
+ };
6305
+ const parseTerm = () => {
6306
+ let v = parseFactor();
6307
+ for (; ; ) {
6308
+ const ch = peek();
6309
+ if (ch !== "*" && ch !== "/") return v;
6310
+ i += 1;
6311
+ const rhs = parseFactor();
6312
+ v = ch === "*" ? v * rhs : rhs === 0 ? v : v / rhs;
6313
+ }
6314
+ };
6315
+ const parseExpr = () => {
6316
+ let v = parseTerm();
6317
+ for (; ; ) {
6318
+ const ch = peek();
6319
+ if (ch !== "+" && ch !== "-") return v;
6320
+ i += 1;
6321
+ const rhs = parseTerm();
6322
+ v = ch === "+" ? v + rhs : v - rhs;
6323
+ }
6324
+ };
6325
+ return parseExpr();
6326
+ }
6327
+ function splitInsertTuples(body) {
6328
+ const tuples = [];
6329
+ let i = 0;
6330
+ const n = body.length;
6331
+ while (i < n) {
6332
+ while (i < n && (body[i] === " " || body[i] === " " || body[i] === "\n" || body[i] === "\r" || body[i] === ",")) {
6333
+ i += 1;
6334
+ }
6335
+ if (i >= n) break;
6336
+ if (body[i] !== "(") {
6337
+ return { tuples, conflict: body.slice(i).trim() };
6338
+ }
6339
+ let depth = 0;
6340
+ let j = i;
6341
+ for (; j < n; j += 1) {
6342
+ if (body[j] === "(") depth += 1;
6343
+ else if (body[j] === ")") {
6344
+ depth -= 1;
6345
+ if (depth === 0) break;
6346
+ }
6347
+ }
6348
+ if (j >= n) return { tuples, conflict: null };
6349
+ tuples.push(body.slice(i + 1, j));
6350
+ i = j + 1;
6351
+ }
6352
+ return { tuples, conflict: null };
6353
+ }
6354
+ function parseConflictClause(clause, cursor, fallbackCols) {
6355
+ const m = /^ON\s+CONFLICT(?:\s*\(([^)]*)\))?\s+DO\s+(UPDATE\s+SET\s+([\s\S]+)|NOTHING\s*)$/i.exec(
6356
+ clause.trim()
6357
+ );
6358
+ if (m === null) {
6359
+ throw new SimDbError("DB_UNSAFE_OP", `\u65E0\u6CD5\u89E3\u6790 ON CONFLICT \u5B50\u53E5\uFF1A${clause.trim().slice(0, 60)}\u2026`);
6360
+ }
6361
+ const colsRaw = m[1];
6362
+ const cols = colsRaw === void 0 ? fallbackCols : colsRaw.split(",").map(ident);
6363
+ if (cols.length === 0) throw new SimDbError("DB_UNSAFE_OP", "ON CONFLICT \u51B2\u7A81\u5217\u4E3A\u7A7A");
6364
+ const action = m[2] ?? "";
6365
+ if (/^NOTHING/i.test(action)) return { cols, sets: [] };
6366
+ const setRaw = m[3] ?? "";
6367
+ const sets = splitListItems(setRaw).map((part) => {
6368
+ const eq = /^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*([\s\S]+)$/i.exec(part.trim());
6369
+ if (eq === null) {
6370
+ throw new SimDbError("DB_UNSAFE_OP", `\u65E0\u6CD5\u89E3\u6790 SET \u8D4B\u503C\uFF1A${part.trim().slice(0, 60)}\u2026`);
6371
+ }
6372
+ const col = ident(eq[1] ?? "");
6373
+ const rhs = (eq[2] ?? "").trim();
6374
+ let value;
6375
+ if (rhs === "?") {
6376
+ value = cursor.take();
6377
+ } else {
6378
+ const ex = /^excluded\.([A-Za-z_][A-Za-z0-9_]*)$/i.exec(rhs);
6379
+ if (ex !== null) {
6380
+ value = new ExcludedRef(ident(ex[1] ?? ""));
6381
+ } else if (/^([A-Za-z_][A-Za-z0-9_]*)$/.test(rhs) && !/^NULL$/i.test(rhs)) {
6382
+ value = new ColumnRef(ident(rhs));
6383
+ } else if (/^'.*'$/.test(rhs) || /^".*"$/.test(rhs) || /^NULL$/i.test(rhs)) {
6384
+ value = stripQuotes(rhs);
6385
+ } else {
6386
+ value = new ExprRef(rhs);
6387
+ }
6388
+ }
6389
+ return { col, value };
6390
+ });
6391
+ return { cols, sets };
6392
+ }
5573
6393
  function matchValue(value, clause) {
5574
6394
  const op = clause.operator;
5575
6395
  if (op === "IS NULL") return value === null || value === void 0;
@@ -5723,16 +6543,36 @@ var SimSqlEngine = class {
5723
6543
  const valueBody = match[4].trim();
5724
6544
  const cursor = new ParamCursor(params);
5725
6545
  const table = this.ensureTable(tableName);
6546
+ const { tuples, conflict } = splitInsertTuples(valueBody);
6547
+ if (tuples.length === 0) throw new SimDbError("DB_UNSAFE_OP", "INSERT \u7F3A\u5C11 VALUES \u5143\u7EC4");
6548
+ const conflictSpec = conflict === null ? null : parseConflictClause(
6549
+ conflict,
6550
+ cursor,
6551
+ table.columns.filter((c) => c.primaryKey).map((c) => c.name)
6552
+ );
5726
6553
  let inserted = 0;
5727
- for (const group of splitListItems(valueBody)) {
5728
- const inner = group.trim().replace(/^\(|\)$/g, "");
5729
- const values = splitListItems(inner).map(
6554
+ for (const tuple of tuples) {
6555
+ const values = splitListItems(tuple).map(
5730
6556
  (item) => item.trim() === "?" ? cursor.take() : stripQuotes(item)
5731
6557
  );
5732
6558
  const row = {};
5733
6559
  cols.forEach((col, i) => {
5734
6560
  row[col] = values[i] ?? null;
5735
6561
  });
6562
+ if (conflictSpec !== null) {
6563
+ const existing = table.rows.find(
6564
+ (r) => conflictSpec.cols.every((c) => r[c] === row[c])
6565
+ );
6566
+ if (existing !== void 0) {
6567
+ const oldRow = { ...existing };
6568
+ for (const set of conflictSpec.sets) {
6569
+ existing[set.col] = resolveSetValue(set.value, oldRow, row);
6570
+ }
6571
+ inserted += 1;
6572
+ void this.persist();
6573
+ continue;
6574
+ }
6575
+ }
5736
6576
  this.applyAutoincrement(table, row);
5737
6577
  table.rows.push(row);
5738
6578
  inserted += 1;
@@ -5801,6 +6641,20 @@ var SimSqlEngine = class {
5801
6641
  return project(this.catalog(), selectRaw);
5802
6642
  }
5803
6643
  const table = this.ensureTable(tableName);
6644
+ let rows = table.rows;
6645
+ const joins = parseLeftJoins(tail);
6646
+ if (joins.length > 0) {
6647
+ rows = table.rows.map((row) => {
6648
+ const merged = { ...row };
6649
+ for (const j of joins) {
6650
+ const joined = this.tables[j.table]?.rows.find((jr) => jr[j.leftCol] === merged[j.rightCol]);
6651
+ if (joined !== void 0) {
6652
+ for (const [k, v] of Object.entries(joined)) merged[`${j.alias}.${k}`] = v;
6653
+ }
6654
+ }
6655
+ return merged;
6656
+ });
6657
+ }
5804
6658
  const whereMatch = /\bWHERE\b/i.exec(tail);
5805
6659
  const orderMatch = /\bORDER\s+BY\b/i.exec(tail);
5806
6660
  const limitMatch = /\bLIMIT\b/i.exec(tail);
@@ -5809,7 +6663,6 @@ var SimSqlEngine = class {
5809
6663
  whereMatch.index + whereMatch[0].length,
5810
6664
  indexAfter(whereMatch.index, [orderMatch, limitMatch, offsetMatch], tail)
5811
6665
  );
5812
- let rows = table.rows;
5813
6666
  if (whereRaw.trim().length > 0) {
5814
6667
  const clauses = parseWhereClauses(whereRaw, cursor);
5815
6668
  rows = rows.filter((row) => matchWhere(clauses, row));
@@ -5819,9 +6672,9 @@ var SimSqlEngine = class {
5819
6672
  orderMatch.index + orderMatch[0].length,
5820
6673
  indexAfter(orderMatch.index, [limitMatch, offsetMatch], tail)
5821
6674
  );
5822
- const oc = /^\s*((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_]*))\s+(asc|desc)/i.exec(orderRaw);
6675
+ const oc = /^\s*((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_.]*))\s+(asc|desc)/i.exec(orderRaw);
5823
6676
  if (oc !== null) {
5824
- const col = ident(oc[1]);
6677
+ const col = unqualifyColumn(ident(oc[1]));
5825
6678
  const dir = oc[3].toLowerCase();
5826
6679
  rows = [...rows].toSorted((a, b) => {
5827
6680
  const av = a[col];
@@ -5866,6 +6719,15 @@ function indexAfter(start, matches, tail) {
5866
6719
  const end = candidates.length === 0 ? -1 : Math.min(...candidates);
5867
6720
  return end === -1 ? tail.length : end;
5868
6721
  }
6722
+ function parseSelectItem(raw) {
6723
+ const t = raw.trim();
6724
+ const as = /\s+AS\s+([A-Za-z_][A-Za-z0-9_]*)$/i.exec(t);
6725
+ let name = as === null ? t : t.slice(0, as.index).trim();
6726
+ if (unqualifyColumn(name) === "*") return { name: "", qualified: "", alias: "", star: true };
6727
+ const qualified = /^[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*$/.test(name) ? ident(name) : "";
6728
+ const plain = unqualifyColumn(ident(name));
6729
+ return { name: plain, qualified, alias: as === null ? plain : ident(as[1] ?? ""), star: false };
6730
+ }
5869
6731
  function project(rows, selectRaw) {
5870
6732
  if (/^count\s*\(\s*\*/i.test(selectRaw) || /^count\s*\(\s*1\)/i.test(selectRaw)) {
5871
6733
  const alias = selectRaw.match(/\bAS\s+([A-Za-z_][A-Za-z0-9_]*)/i)?.[1] ?? "n";
@@ -5876,10 +6738,21 @@ function project(rows, selectRaw) {
5876
6738
  return [{ [constMatch[2]]: Number(constMatch[1]) }];
5877
6739
  }
5878
6740
  if (selectRaw.trim() === "*") return rows;
5879
- const cols = selectRaw.split(",").map((s) => ident(s.trim()));
6741
+ const items = selectRaw.split(",").map(parseSelectItem);
6742
+ const valueOf = (row, item) => item.qualified !== "" && row[item.qualified] !== void 0 ? row[item.qualified] : row[item.name];
6743
+ if (items.some((item) => item.star)) {
6744
+ return rows.map((row) => {
6745
+ const out = { ...row };
6746
+ for (const item of items) {
6747
+ if (item.star) continue;
6748
+ out[item.alias] = valueOf(row, item);
6749
+ }
6750
+ return out;
6751
+ });
6752
+ }
5880
6753
  return rows.map((row) => {
5881
6754
  const out = {};
5882
- for (const col of cols) out[col] = row[col];
6755
+ for (const item of items) out[item.alias] = valueOf(row, item);
5883
6756
  return out;
5884
6757
  });
5885
6758
  }
@@ -7078,9 +7951,11 @@ async function createBrowserSimRuntime(options) {
7078
7951
 
7079
7952
  // packages/web-container/src/index.ts
7080
7953
  init_function_fetch_proxy();
7954
+ init_console_relay();
7081
7955
  export {
7082
7956
  BUNDLE_MODULE_PATH_PREFIX,
7083
7957
  COMPLETABLE_COMMANDS,
7958
+ CONSOLE_RELAY_SCRIPT,
7084
7959
  DEFAULT_MAX_INSTALL_DEPTH,
7085
7960
  EXTRA_COMMANDS,
7086
7961
  FN_FETCH_INTERCEPTOR_SCRIPT,