@adep/web-container 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -105,6 +105,27 @@ function withinPackage(pkgDirAbs, rel, context) {
105
105
  }
106
106
  return abs;
107
107
  }
108
+ function pickConditionTarget(conditions, order, resolveRel, context) {
109
+ for (const key of order) {
110
+ const value = conditions[key];
111
+ if (value === void 0 || value === null) continue;
112
+ if (typeof value === "string") return resolveRel(value);
113
+ if (typeof value === "object" && !Array.isArray(value)) {
114
+ const nested = pickConditionTarget(
115
+ value,
116
+ order,
117
+ resolveRel,
118
+ context
119
+ );
120
+ if (nested !== null) return nested;
121
+ continue;
122
+ }
123
+ throw new ResolveError(
124
+ `${context}\uFF1Aexports["."]["${key}"] \u5F62\u6001\u4E0D\u652F\u6301\uFF08\u4EC5\u63A5\u53D7\u5B57\u7B26\u4E32 / null / \u6761\u4EF6\u5BF9\u8C61\uFF09`
125
+ );
126
+ }
127
+ return null;
128
+ }
108
129
  function resolvePackageEntry(meta, pkgDirAbs, condition) {
109
130
  const context = `\u5305 ${meta.name ?? meta.version ?? pkgDirAbs} \u7684 exports/main \u58F0\u660E`;
110
131
  const exp = meta.exports;
@@ -125,20 +146,11 @@ function resolvePackageEntry(meta, pkgDirAbs, condition) {
125
146
  if (typeof dot !== "object" || Array.isArray(dot)) {
126
147
  throw new ResolveError(`${context}\uFF1Aexports["."] \u5F62\u6001\u4E0D\u652F\u6301\uFF08\u4EC5\u63A5\u53D7\u5B57\u7B26\u4E32\u6216\u6761\u4EF6\u5BF9\u8C61\uFF09`);
127
148
  }
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
- );
149
+ const order = condition === "import" ? IMPORT_CONDITION_ORDER : REQUIRE_CONDITION_ORDER;
150
+ const resolveRel = (rel) => withinPackage(pkgDirAbs, rel, context);
151
+ const hit = pickConditionTarget(dot, order, resolveRel, context);
152
+ if (hit !== null) return hit;
153
+ throw new ResolveError(`${context}\uFF1Aexports["."] \u6761\u4EF6\u5BF9\u8C61\u91CC\u6CA1\u6709 ${order.join("/")} \u5165\u53E3`);
142
154
  }
143
155
  if (meta.main !== void 0) {
144
156
  if (typeof meta.main !== "string") {
@@ -236,11 +248,13 @@ function resolveImport(fs, specifier, fromFileAbs, condition = "require") {
236
248
  `\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
249
  );
238
250
  }
239
- var RESOLVE_EXTENSIONS, ResolveError;
251
+ var IMPORT_CONDITION_ORDER, REQUIRE_CONDITION_ORDER, RESOLVE_EXTENSIONS, ResolveError;
240
252
  var init_node_resolve = __esm({
241
253
  "src/node-resolve.ts"() {
242
254
  "use strict";
243
255
  init_path();
256
+ IMPORT_CONDITION_ORDER = ["browser", "import", "module", "default"];
257
+ REQUIRE_CONDITION_ORDER = ["require", "node", "default"];
244
258
  RESOLVE_EXTENSIONS = [".js", ".mjs", ".cjs", ".json"];
245
259
  ResolveError = class extends Error {
246
260
  constructor(message) {
@@ -515,6 +529,7 @@ var init_strip_types = __esm({
515
529
  return;
516
530
  case "as":
517
531
  case "satisfies": {
532
+ if (this.frames[this.frames.length - 1]?.specifierList === true) return;
518
533
  if (this.tokenAt(2) === "*" || this.tokenAt(2) === "type") return;
519
534
  const nextChar = this.skipWhitespaceFrom(this.i);
520
535
  if (nextChar === null || "=,:]})".includes(this.src[nextChar])) return;
@@ -567,7 +582,8 @@ var init_strip_types = __esm({
567
582
  const frame = {
568
583
  kind: c === "(" ? "paren" : c === "{" ? "brace" : "bracket",
569
584
  declare: false,
570
- classBody: false
585
+ classBody: false,
586
+ specifierList: c === "{" && this.isImportSpecifierBrace()
571
587
  };
572
588
  if (c === "{" && this.pendingClassBody) {
573
589
  frame.classBody = true;
@@ -654,8 +670,17 @@ var init_strip_types = __esm({
654
670
  return true;
655
671
  }
656
672
  /**
657
- * `(` 是否为参数列表(声明位):`function f(`、类体里的方法 `m(`、箭头 `=> (`,
658
- * 以及出现在 `(` `,` `=` `>` `:` `[` `{` `}` `;` 之后(如 `map((v: T) => v)` 的内层括号)。
673
+ * `{` import / export 的说明符列表吗——`{ a as b }` 覆盖 `import { … }`、
674
+ * `export { }` `import def, { }` 三种写法(后者说明符花括号的前驱 token `,`)。
675
+ */
676
+ isImportSpecifierBrace() {
677
+ const back1 = this.tokenAt(1);
678
+ if (back1 === "import" || back1 === "export") return true;
679
+ return back1 === "," && this.tokenAt(3) === "import";
680
+ }
681
+ /**
682
+ * `(` 是否为参数列表(声明位):`function f(`、`async` 箭头 `async (`、类体里的方法 `m(`、
683
+ * 箭头 `=> (`,以及出现在 `(` `,` `=` `>` `:` `[` `{` `}` `;` 之后(如 `map((v: T) => v)` 的内层括号)。
659
684
  * 调用位 `foo(` 与控制流 `if (` `for (` 都不算。
660
685
  * 误判成声明位也不足以擦掉什么:`:` 还要过 `isAnnotationColon` 的「名字前驱必须是
661
686
  * `(` `,` `{` `;` 修饰符」这一关,而三元表达式的中间段前面必然是 `?`。
@@ -664,6 +689,8 @@ var init_strip_types = __esm({
664
689
  if (this.afterFunctionKeyword) return true;
665
690
  if (this.tokenAt(2) === "function" && IDENT_START.test(this.tokenAt(1))) return true;
666
691
  if (this.afterArrow) return true;
692
+ if (this.tokenAt(1) === "async") return true;
693
+ if (this.tokenAt(1) === "return") return true;
667
694
  if (this.inClassBody() && IDENT_PART.test(this.prevSignificantChar(at - 1))) return true;
668
695
  const prev = this.prevSignificantChar(at - 1);
669
696
  return prev === "" || "(,=>:[{};".includes(prev);
@@ -1172,11 +1199,15 @@ var init_function_fetch_proxy = __esm({
1172
1199
  " }",
1173
1200
  " var u;",
1174
1201
  " try { u = new URL(urlStr, document.baseURI); }",
1175
- " catch (e) { return ORIGINAL_FETCH(input, init); }",
1202
+ " catch (e0) {",
1203
+ " try { u = new URL(urlStr, window.location.origin); }",
1204
+ " catch (e1) { return ORIGINAL_FETCH(input, init); }",
1205
+ " }",
1176
1206
  ' if (u.pathname.indexOf("/api/") !== 0 && u.pathname !== "/api") {',
1177
1207
  " return ORIGINAL_FETCH(input, init);",
1178
1208
  " }",
1179
- " if (window.parent === window) return ORIGINAL_FETCH(input, init);",
1209
+ " var bridgeWindow = window.parent !== window ? window.parent : window.opener;",
1210
+ " if (!bridgeWindow) return ORIGINAL_FETCH(input, init);",
1180
1211
  ' method = (method || "GET").toUpperCase();',
1181
1212
  " var target = u.pathname + u.search;",
1182
1213
  " return readBody(input, init).then(function (textBody) {",
@@ -1187,10 +1218,75 @@ var init_function_fetch_proxy = __esm({
1187
1218
  ` resolve(new Response('{"error":{"code":"FN_PROXY_TIMEOUT","message":"\\u4e91\\u51fd\\u6570\\u6267\\u884c\\u8d85\\u65f6"}}', { status: 504, headers: { "content-type": "application/json" } }));`,
1188
1219
  " }, TIMEOUT_MS);",
1189
1220
  " pending[id] = { resolve: resolve, timer: timer };",
1190
- ' window.parent.postMessage({ __adepFnRequest: true, id: id, method: method, url: target, headers: headers, body: textBody }, "*");',
1221
+ ' bridgeWindow.postMessage({ __adepFnRequest: true, id: id, method: method, url: target, headers: headers, body: textBody }, "*");',
1191
1222
  " });",
1192
1223
  " });",
1193
1224
  " };",
1225
+ "",
1226
+ " /* \u2014\u2014 blob URL SPA \u8DEF\u7531\u652F\u6301 \u2014\u2014",
1227
+ " blob: \u662F\u4E0D\u53EF\u5206\u5C42 scheme\uFF0Chistory.pushState('/about') \u5185\u90E8\u89E3\u6790\u76F8\u5BF9\u8DEF\u5F84\u4F1A\u629B",
1228
+ " TypeError \u2192 SPA history \u6A21\u5F0F\u8DEF\u7531\u5D29\u6E83\u3002patch pushState/replaceState\uFF0C\u5BF9\u76F8\u5BF9",
1229
+ " \u8DEF\u5F84\u76F4\u63A5\u541E\u6389\uFF08\u4E0D\u5BFC\u822A\u3001\u4E0D\u629B\u9519\uFF09\uFF0C\u8DEF\u7531\u5E93\u5185\u90E8\u72B6\u6001\u81EA\u884C\u66F4\u65B0\uFF1Blocation.pathname",
1230
+ " \u8986\u76D6\u4E3A\u5F53\u524D\u8DEF\u7531\u8DEF\u5F84\uFF0C\u4F9B\u8DEF\u7531\u5E93\u521D\u59CB\u5316\u65F6\u8BFB\u53D6\u3002sessionStorage \u6301\u4E45\u5316\uFF0C\u5237\u65B0\u540E\u6062\u590D\u3002 */",
1231
+ ' if (window.location.protocol === "blob:") {',
1232
+ ' var SPA_KEY = "__adep_spa_path";',
1233
+ ' var spaPath = "/";',
1234
+ " try {",
1235
+ " var _saved = window.sessionStorage.getItem(SPA_KEY);",
1236
+ " if (_saved) spaPath = _saved;",
1237
+ " } catch (e) {}",
1238
+ " try {",
1239
+ ' Object.defineProperty(window.location, "pathname", {',
1240
+ " get: function () { return spaPath; },",
1241
+ " configurable: true",
1242
+ " });",
1243
+ " } catch (e) {}",
1244
+ " var _origPush = window.history.pushState.bind(window.history);",
1245
+ " var _origReplace = window.history.replaceState.bind(window.history);",
1246
+ " function _isRelative(url) {",
1247
+ ' if (!url || typeof url !== "string") return false;',
1248
+ ' if (url.charAt(0) === "#") return false;',
1249
+ " if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(url)) return false;",
1250
+ " return true;",
1251
+ " }",
1252
+ " function _resolvePath(url) {",
1253
+ ' var qi = url.indexOf("?");',
1254
+ ' var hi = url.indexOf("#");',
1255
+ " var end = url.length;",
1256
+ " if (qi !== -1) end = qi;",
1257
+ " if (hi !== -1 && hi < end) end = hi;",
1258
+ " var p = url.slice(0, end);",
1259
+ ' if (p.charAt(0) !== "/") {',
1260
+ ' var base = spaPath.slice(0, spaPath.lastIndexOf("/") + 1);',
1261
+ " p = base + p;",
1262
+ " }",
1263
+ ' var parts = p.split("/");',
1264
+ " var out = [];",
1265
+ " for (var i = 0; i < parts.length; i++) {",
1266
+ " var seg = parts[i];",
1267
+ ' if (seg === "" || seg === ".") continue;',
1268
+ ' if (seg === "..") { out.pop(); continue; }',
1269
+ " out.push(seg);",
1270
+ " }",
1271
+ ' return "/" + out.join("/");',
1272
+ " }",
1273
+ " window.history.pushState = function (state, title, url) {",
1274
+ " if (_isRelative(url)) {",
1275
+ " spaPath = _resolvePath(url);",
1276
+ " try { window.sessionStorage.setItem(SPA_KEY, spaPath); } catch (e) {}",
1277
+ " return;",
1278
+ " }",
1279
+ " return _origPush(state, title, url);",
1280
+ " };",
1281
+ " window.history.replaceState = function (state, title, url) {",
1282
+ " if (_isRelative(url)) {",
1283
+ " spaPath = _resolvePath(url);",
1284
+ " try { window.sessionStorage.setItem(SPA_KEY, spaPath); } catch (e) {}",
1285
+ " return;",
1286
+ " }",
1287
+ " return _origReplace(state, title, url);",
1288
+ " };",
1289
+ " }",
1194
1290
  "})();"
1195
1291
  ].join("\n");
1196
1292
  return src;
@@ -1311,6 +1407,18 @@ function cssModule(css) {
1311
1407
  "export default css;"
1312
1408
  ].join("\n");
1313
1409
  }
1410
+ function inlineStyleBlock(css, key) {
1411
+ return [
1412
+ "{",
1413
+ `const css = ${JSON.stringify(css)};`,
1414
+ 'const el = document.createElement("style");',
1415
+ 'el.setAttribute("data-adep-vite", "");',
1416
+ `el.setAttribute("data-adep-style", ${JSON.stringify(key)});`,
1417
+ "el.textContent = css;",
1418
+ "document.head.appendChild(el);",
1419
+ "}"
1420
+ ].join("\n");
1421
+ }
1314
1422
  function jsonModule(source, abs) {
1315
1423
  try {
1316
1424
  JSON.parse(source);
@@ -1361,6 +1469,17 @@ function createViteServer(vfs, options = {}) {
1361
1469
  } catch {
1362
1470
  }
1363
1471
  };
1472
+ const DEFINES = [
1473
+ [/\bprocess\s*\.\s*env\s*\.\s*NODE_ENV\b/g, JSON.stringify("development")],
1474
+ [/\b__VUE_OPTIONS_API__\b/g, "true"],
1475
+ [/\b__VUE_PROD_DEVTOOLS__\b/g, "false"],
1476
+ [/\b__VUE_PROD_HYDRATION_MISMATCH_DETAILS__\b/g, "false"]
1477
+ ];
1478
+ function applyDefines(code) {
1479
+ let out = code;
1480
+ for (const [pattern, value] of DEFINES) out = out.replace(pattern, value);
1481
+ return out;
1482
+ }
1364
1483
  function transformModule2(abs, source) {
1365
1484
  if (abs.endsWith(".css")) return cssModule(source);
1366
1485
  if (abs.endsWith(".json")) return jsonModule(source, abs);
@@ -1371,21 +1490,27 @@ function createViteServer(vfs, options = {}) {
1371
1490
  `${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
1491
  );
1373
1492
  const compiled = sfcCompiler(source, abs);
1374
- return [...compiled.styles.map((css) => cssModule(css)), compiled.script].join("\n");
1493
+ return [
1494
+ ...compiled.styles.map((css, index) => inlineStyleBlock(css, `${abs}#${index}`)),
1495
+ applyDefines(stripTypes(compiled.script))
1496
+ ].join("\n");
1375
1497
  }
1376
1498
  if (abs.endsWith(".tsx") || abs.endsWith(".jsx"))
1377
1499
  throw new ViteDevError(
1378
1500
  "JSX_UNSUPPORTED",
1379
1501
  `${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
1502
  );
1381
- if (abs.endsWith(".ts") || abs.endsWith(".mts")) return stripTypes(source);
1382
- return source;
1503
+ if (abs.endsWith(".ts") || abs.endsWith(".mts")) return applyDefines(stripTypes(source));
1504
+ return applyDefines(source);
1505
+ }
1506
+ function absoluteFromRoot(spec) {
1507
+ return join(root, spec.replace(/^\/+/, ""));
1383
1508
  }
1384
1509
  async function resolveSpecifier(spec, importerAbs) {
1385
1510
  if (EXTERNAL_SPECIFIER.test(spec) || DATA_OR_BLOB.test(spec)) return spec;
1386
1511
  let target;
1387
1512
  if (spec.startsWith("./") || spec.startsWith("../") || spec.startsWith("/")) {
1388
- const base = spec.startsWith("/") ? spec : join(dirname(importerAbs), spec);
1513
+ const base = spec.startsWith("/") ? absoluteFromRoot(spec) : join(dirname(importerAbs), spec);
1389
1514
  target = resolveWithSuffixes(vfs, base);
1390
1515
  if (!vfs.exists(target) || vfs.isDirectory(target))
1391
1516
  throw new ViteDevError(
@@ -1474,7 +1599,7 @@ function createViteServer(vfs, options = {}) {
1474
1599
  html = html.replace(
1475
1600
  MODULE_SCRIPT_SRC_RE,
1476
1601
  (_whole, pre, _q1, mid, _q2, src, post) => {
1477
- const base = src.startsWith("/") ? normalize(src) : join(dirname(entryAbs), src);
1602
+ const base = src.startsWith("/") ? absoluteFromRoot(src) : join(dirname(entryAbs), src);
1478
1603
  const abs = resolveWithSuffixes(vfs, base);
1479
1604
  if (!vfs.exists(abs) || vfs.isDirectory(abs))
1480
1605
  throw new ViteDevError(
@@ -1482,7 +1607,7 @@ function createViteServer(vfs, options = {}) {
1482
1607
  `\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
1608
  );
1484
1609
  entryModuleUrls.push(loadModuleUrl(abs));
1485
- return `<script${pre}${mid}src="__adep_vite_entry_${entryModuleUrls.length - 1}__"${post}><\/script>`;
1610
+ return `<script${pre}${mid}src="__adep_vite_entry_${entryModuleUrls.length - 1}__"${post} type="module"><\/script>`;
1486
1611
  }
1487
1612
  );
1488
1613
  html = html.replace(
@@ -1492,7 +1617,7 @@ function createViteServer(vfs, options = {}) {
1492
1617
  const abs = `${INLINE_PREFIX}${inlineSeq++}.mjs`;
1493
1618
  inlineSources.set(abs, body);
1494
1619
  entryModuleUrls.push(loadModuleUrl(abs));
1495
- return `<script${pre}${post}src="__adep_vite_entry_${entryModuleUrls.length - 1}__"><\/script>`;
1620
+ return `<script${pre}${post}src="__adep_vite_entry_${entryModuleUrls.length - 1}__" type="module"><\/script>`;
1496
1621
  }
1497
1622
  );
1498
1623
  const urls = await Promise.all(entryModuleUrls);
@@ -1516,7 +1641,10 @@ function createViteServer(vfs, options = {}) {
1516
1641
  lastDoc = doc;
1517
1642
  if (currentUrl !== "") revokeObjectURL(currentUrl);
1518
1643
  currentUrl = createObjectURL(new Blob([doc], { type: "text/html" }));
1519
- if (changed) broadcast(currentUrl);
1644
+ if (changed) {
1645
+ broadcast(currentUrl);
1646
+ options.onDocumentChange?.(currentUrl);
1647
+ }
1520
1648
  }
1521
1649
  const server = {
1522
1650
  get url() {
@@ -3553,7 +3681,11 @@ function bootstrap(options) {
3553
3681
  const { createViteServer: createViteServer2 } = await Promise.resolve().then(() => (init_vite_dev(), vite_dev_exports));
3554
3682
  const server = createViteServer2(vfs, {
3555
3683
  root,
3556
- ...options.viteCompiler === void 0 ? {} : { sfcCompiler: options.viteCompiler }
3684
+ ...options.viteCompiler === void 0 ? {} : { sfcCompiler: options.viteCompiler },
3685
+ // PV-006:内容重建 → 以 `serverready`(update: true)事件上报新文档 URL,宿主导出预览产物。
3686
+ onDocumentChange: (url) => {
3687
+ emit("serverready", { port: server.port, url, kind: "vite", root: server.root, update: true });
3688
+ }
3557
3689
  });
3558
3690
  await server.ready;
3559
3691
  viteServer = server;
@@ -3718,6 +3850,92 @@ init_node_resolve();
3718
3850
  init_vite_dev();
3719
3851
  init_path();
3720
3852
 
3853
+ // src/bundle-export.ts
3854
+ var BUNDLE_MODULE_PATH_PREFIX = "/_adep/m/";
3855
+ var BLOB_REF_RE = /blob:[^\s"'`<>()\\]+/g;
3856
+ function fnv1a(code) {
3857
+ let hash = 2166136261;
3858
+ for (let i = 0; i < code.length; i++) {
3859
+ hash ^= code.charCodeAt(i);
3860
+ hash = Math.imul(hash, 16777619) >>> 0;
3861
+ }
3862
+ return `${hash.toString(16).padStart(8, "0")}${code.length.toString(16)}`;
3863
+ }
3864
+ async function defaultModuleName(code) {
3865
+ const subtle = globalThis.crypto?.subtle;
3866
+ if (subtle === void 0) return fnv1a(code);
3867
+ const digest = await subtle.digest("SHA-256", new TextEncoder().encode(code));
3868
+ let hex = "";
3869
+ for (const byte of new Uint8Array(digest).slice(0, 8)) {
3870
+ hex += byte.toString(16).padStart(2, "0");
3871
+ }
3872
+ return hex;
3873
+ }
3874
+ function findBlobRefs(text) {
3875
+ const found = text.match(BLOB_REF_RE);
3876
+ return found === null ? [] : [...new Set(found)];
3877
+ }
3878
+ function rewriteRefs(text, urls) {
3879
+ let out = text;
3880
+ for (const [blobUrl, path] of urls) {
3881
+ if (out.includes(blobUrl)) out = out.split(blobUrl).join(path);
3882
+ }
3883
+ return out;
3884
+ }
3885
+ function injectScript(html, script) {
3886
+ return /<\/body>/i.test(html) ? html.replace(/<\/body>/i, `${script}</body>`) : html + script;
3887
+ }
3888
+ async function exportBundle(options) {
3889
+ const readText = options.readText ?? ((url) => fetch(url).then((response) => response.text()));
3890
+ const nameOf = options.moduleName ?? defaultModuleName;
3891
+ const prefix = options.modulePathPrefix ?? BUNDLE_MODULE_PATH_PREFIX;
3892
+ const uploaded = new Set(options.known === void 0 ? [] : [...options.known.values()]);
3893
+ const urls = /* @__PURE__ */ new Map();
3894
+ const sources = [];
3895
+ const readOrThrow = async (url) => {
3896
+ try {
3897
+ return await readText(url);
3898
+ } catch (error) {
3899
+ throw new Error(
3900
+ `\u9884\u89C8\u4EA7\u7269\u5BFC\u51FA\u5931\u8D25\uFF1A\u8BFB\u4E0D\u5230\u6A21\u5757 ${url}\uFF08${error instanceof Error ? error.message : String(error)}\uFF09`,
3901
+ { cause: error }
3902
+ );
3903
+ }
3904
+ };
3905
+ const html = await readOrThrow(options.documentUrl);
3906
+ const loadLayer = async (layer) => {
3907
+ const batch = [...new Set(layer)].filter((url) => !urls.has(url));
3908
+ if (batch.length === 0) return;
3909
+ const loaded = await Promise.all(
3910
+ batch.map(async (url) => {
3911
+ const code = await readOrThrow(url);
3912
+ return { url, code, path: `${prefix}${await nameOf(code)}.js` };
3913
+ })
3914
+ );
3915
+ const next = [];
3916
+ for (const item of loaded) {
3917
+ urls.set(item.url, item.path);
3918
+ sources.push({ url: item.url, code: item.code });
3919
+ next.push(...findBlobRefs(item.code));
3920
+ }
3921
+ await loadLayer(next);
3922
+ };
3923
+ await loadLayer(findBlobRefs(html));
3924
+ const modules = {};
3925
+ for (const { url, code } of sources) {
3926
+ const path = urls.get(url);
3927
+ if (uploaded.has(path)) continue;
3928
+ modules[path] = rewriteRefs(code, urls);
3929
+ }
3930
+ const rewrittenHtml = rewriteRefs(html, urls);
3931
+ return {
3932
+ html: options.appendScript === void 0 ? rewrittenHtml : injectScript(rewrittenHtml, options.appendScript),
3933
+ modules,
3934
+ paths: [...new Set(urls.values())].toSorted(),
3935
+ urls
3936
+ };
3937
+ }
3938
+
3721
3939
  // src/persistence.ts
3722
3940
  function cloneEntries(entries) {
3723
3941
  return entries.map(
@@ -4459,6 +4677,8 @@ var CHAIN_CAPABILITY_KEY = "__adepChain";
4459
4677
  var DB_RPC = {
4460
4678
  /** 直通方法(如 query):`(method=query, args=[sql, params])`。 */
4461
4679
  query: "query",
4680
+ /** 写路径(CF-013):`(method=writeQuery, args=[sql, params])` → `{ changes }`。 */
4681
+ writeQuery: "writeQuery",
4462
4682
  /** 读取 owned 表变更流(DB-006):`(method=changes, args=[table, query])`。 */
4463
4683
  changes: "changes",
4464
4684
  /** 开启事务:`begin → txId`。 */
@@ -4535,21 +4755,35 @@ function unsafeOperation(message) {
4535
4755
  function stripLiterals(sql) {
4536
4756
  return sql.replace(/'[^']*(?:''[^']*)*'/g, "").replace(/"[^"]*(?:""[^"]*)*"/g, "").replace(/--[^\n]*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
4537
4757
  }
4538
- function assertReadOnlyQuery(sql) {
4758
+ function sqlHead(sql) {
4759
+ return sql.trim().replace(/^\(+/, "").trim().toUpperCase();
4760
+ }
4761
+ function assertSafeStatement(sql) {
4539
4762
  const stripped = stripLiterals(sql);
4540
4763
  if (stripped.includes(";")) {
4541
4764
  throw unsafeOperation("\u4EC5\u5141\u8BB8\u5355\u6761\u8BED\u53E5\uFF0C\u7981\u6B62\u591A\u8BED\u53E5\u5806\u53E0");
4542
4765
  }
4543
- const head = stripped.trim().replace(/^\(+/, "").trim().toUpperCase();
4544
- if (!head.startsWith("SELECT") && !head.startsWith("WITH")) {
4545
- throw unsafeOperation("cloud.db.query \u4EC5\u5141\u8BB8\u53EA\u8BFB\u67E5\u8BE2\uFF08SELECT / WITH\uFF09");
4546
- }
4547
4766
  if (/ATTACH|DETACH/.test(stripped.toUpperCase())) {
4548
4767
  throw unsafeOperation("\u7981\u6B62\u8DE8\u5E93\u64CD\u4F5C\uFF08ATTACH / DETACH\uFF09");
4549
4768
  }
4550
4769
  if (/SQLITE_\w+/i.test(stripped)) {
4551
4770
  throw unsafeOperation("\u7981\u6B62\u8BBF\u95EE\u7CFB\u7EDF\u8868\uFF08sqlite_*\uFF09");
4552
4771
  }
4772
+ return sqlHead(stripped);
4773
+ }
4774
+ function assertReadOnlyQuery(sql) {
4775
+ const head = assertSafeStatement(sql);
4776
+ if (!head.startsWith("SELECT") && !head.startsWith("WITH")) {
4777
+ throw unsafeOperation("cloud.db.query \u4EC5\u5141\u8BB8\u53EA\u8BFB\u67E5\u8BE2\uFF08SELECT / WITH\uFF09");
4778
+ }
4779
+ }
4780
+ function assertWriteQuery(sql) {
4781
+ const head = assertSafeStatement(sql);
4782
+ if (!head.startsWith("INSERT") && !head.startsWith("UPDATE") && !head.startsWith("DELETE")) {
4783
+ throw unsafeOperation(
4784
+ "cloud.db.writeQuery \u4EC5\u5141\u8BB8 DML\uFF08INSERT / UPDATE / DELETE\uFF09\uFF0CDDL \u8BF7\u8D70\u63A7\u5236\u53F0"
4785
+ );
4786
+ }
4553
4787
  }
4554
4788
 
4555
4789
  // ../runtime/src/database/builder/owned.ts
@@ -5095,6 +5329,14 @@ function createCloudDb(driver, options = {}) {
5095
5329
  assertReadOnlyQuery(sql);
5096
5330
  return driver.all(sql, params);
5097
5331
  },
5332
+ async writeQuery(sql, params) {
5333
+ if (!Array.isArray(params)) {
5334
+ throw unsafeOperation("writeQuery \u7684 params \u5FC5\u987B\u63D0\u4F9B\uFF08\u65E0\u53C2\u4F20 []\uFF09");
5335
+ }
5336
+ guardWrite();
5337
+ assertWriteQuery(sql);
5338
+ return driver.run(sql, params);
5339
+ },
5098
5340
  async changes(table, query = {}) {
5099
5341
  return readChanges(driver, table, query);
5100
5342
  }
@@ -5110,7 +5352,8 @@ var CLOUD_DB_SPEC = {
5110
5352
  rootMethod: "table",
5111
5353
  stepMethods: ["select", "where", "orderBy", "limit", "offset"],
5112
5354
  terminalMethods: ["get", "first", "count", "insert", "insertMany", "update", "delete"],
5113
- directMethods: ["query", "changes"],
5355
+ // CF-013:writeQuery 是 D1 shim 的写路径(INSERT/UPDATE/DELETE),与 query 并列直通方法。
5356
+ directMethods: ["query", "writeQuery", "changes"],
5114
5357
  transactionMethod: "transaction"
5115
5358
  };
5116
5359
  var WRITE_TERMINALS = /* @__PURE__ */ new Set(["insert", "insertMany", "update", "delete"]);
@@ -5165,6 +5408,10 @@ function createDbCapability(driver, options = {}) {
5165
5408
  const [sql, params] = args;
5166
5409
  return await db.query(sql, params);
5167
5410
  }
5411
+ case DB_RPC.writeQuery: {
5412
+ const [sql, params] = args;
5413
+ return await db.writeQuery(sql, params);
5414
+ }
5168
5415
  case DB_RPC.changes: {
5169
5416
  const [table, query] = args;
5170
5417
  return await db.changes(table, query);
@@ -5450,6 +5697,17 @@ var SimSqlEngine = class {
5450
5697
  }
5451
5698
  return { changes: 0 };
5452
5699
  }
5700
+ if (/^CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?:IF\s+NOT\s+EXISTS\s+)?/i.test(stmt)) {
5701
+ const idx = /^CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?:IF\s+NOT\s+EXISTS\s+)?((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_]*))\s+ON\s+((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_]*))/i.exec(
5702
+ stmt
5703
+ );
5704
+ if (idx === null) throw new SimDbError("DB_UNSAFE_OP", `\u65E0\u6CD5\u89E3\u6790 CREATE INDEX \u8BED\u53E5`);
5705
+ const tableName = ident(idx[3]);
5706
+ if (this.tables[tableName] === void 0) {
5707
+ throw new SimDbError("DB_UNSAFE_OP", `CREATE INDEX \u76EE\u6807\u8868\u4E0D\u5B58\u5728\uFF1A${tableName}`);
5708
+ }
5709
+ return { changes: 0 };
5710
+ }
5453
5711
  if (/^INSERT\s+INTO/i.test(stmt)) return this.execInsert(stmt, params);
5454
5712
  if (/^UPDATE\s+/i.test(stmt)) return this.execUpdate(stmt, params);
5455
5713
  if (/^DELETE\s+FROM/i.test(stmt)) return this.execDelete(stmt, params);
@@ -5694,6 +5952,19 @@ function assertSafeStoragePath(path) {
5694
5952
  }
5695
5953
  return path;
5696
5954
  }
5955
+ function assertStoragePrefix(prefix) {
5956
+ if (prefix !== void 0 && prefix !== "") {
5957
+ const segments = prefix.split("/");
5958
+ if (prefix.startsWith("/") || /[\\]/.test(prefix) || segments.some((segment) => segment === "..")) {
5959
+ throw new StorageError(
5960
+ 400,
5961
+ STORAGE_CODES.invalidPath,
5962
+ `\u975E\u6CD5\u524D\u7F00 "${prefix}"\uFF08\u7981\u6B62 / \u5F00\u5934\u3001\u53CD\u659C\u6760\u6216 .. \u7A7F\u8D8A\uFF09`
5963
+ );
5964
+ }
5965
+ }
5966
+ return prefix ?? "";
5967
+ }
5697
5968
 
5698
5969
  // ../runtime/src/storage/hmac-sha256.ts
5699
5970
  var K = new Uint32Array([
@@ -5894,9 +6165,12 @@ function createStorageCapability(driver, signer, projectId) {
5894
6165
  const handler = async (method, args) => {
5895
6166
  switch (method) {
5896
6167
  case "upload": {
5897
- const [path, data] = args;
6168
+ const [path, data, options] = args;
5898
6169
  return toStoredFile(
5899
- await driver.put(projectId, path, asBytes(data), { visibility: DEFAULT_VISIBILITY })
6170
+ await driver.put(projectId, path, asBytes(data), {
6171
+ visibility: DEFAULT_VISIBILITY,
6172
+ ...options?.contentType === void 0 ? {} : { contentType: options.contentType }
6173
+ })
5900
6174
  );
5901
6175
  }
5902
6176
  case "get": {
@@ -6010,16 +6284,7 @@ function createBrowserStorageDriver(options) {
6010
6284
  await saveBucket(bucket);
6011
6285
  },
6012
6286
  async list(_projectId, prefix) {
6013
- if (prefix !== void 0 && prefix !== "") {
6014
- const segments = prefix.split("/");
6015
- if (prefix.startsWith("/") || /[\\]/.test(prefix) || segments.some((segment) => segment === "..")) {
6016
- throw new StorageError(
6017
- 400,
6018
- STORAGE_CODES.invalidPath,
6019
- `\u975E\u6CD5\u524D\u7F00 "${prefix}"\uFF08\u7981\u6B62 / \u5F00\u5934\u3001\u53CD\u659C\u6760\u6216 .. \u7A7F\u8D8A\uFF09`
6020
- );
6021
- }
6022
- }
6287
+ assertStoragePrefix(prefix);
6023
6288
  const bucket = await loadBucket();
6024
6289
  return Object.values(bucket).filter((object) => prefix === void 0 || object.path.startsWith(prefix)).map(toMeta).toSorted((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
6025
6290
  },
@@ -6343,6 +6608,10 @@ var KNOWN_CAPABILITY_HINTS = {
6343
6608
  realtime: {
6344
6609
  code: "REALTIME_NOT_AVAILABLE",
6345
6610
  message: "\u5B9E\u65F6\u901A\u9053\u672A\u88C5\u914D\uFF1Arealtime \u57DF\u672A\u88C5\u8F7D\uFF08\u68C0\u67E5\u90E8\u7F72\u5F62\u6001\u4E0E Redis \u914D\u7F6E\uFF09\uFF08REALTIME_NOT_AVAILABLE\uFF09"
6611
+ },
6612
+ kv: {
6613
+ code: "KV_NOT_PROVISIONED",
6614
+ message: "\u9879\u76EE KV \u5B58\u50A8\u672A\u53EF\u7528\uFF1Akv \u968F\u9879\u76EE\u6570\u636E\u5E93\u63D0\u4F9B\uFF0C\u8BF7\u5148\u542F\u52A8\u6570\u636E\u5E93\uFF08KV_NOT_PROVISIONED\uFF09"
6346
6615
  }
6347
6616
  };
6348
6617
  var CapabilityNotRegisteredError = class extends Error {
@@ -6402,6 +6671,19 @@ function createCloudContainer() {
6402
6671
  };
6403
6672
  }
6404
6673
 
6674
+ // ../runtime/src/functions/runtime/rpc-wire.ts
6675
+ function wireRpcResponses(port, pending) {
6676
+ port.on?.((message) => {
6677
+ const reply = message;
6678
+ if (reply?.type !== "rpc-response" || typeof reply.id !== "number") return;
6679
+ const entry = pending.get(reply.id);
6680
+ if (entry === void 0) return;
6681
+ pending.delete(reply.id);
6682
+ if (reply.ok === true) entry.resolve(reply.result);
6683
+ else entry.reject(new Error(reply.error ?? "RPC \u80FD\u529B\u8C03\u7528\u5931\u8D25"));
6684
+ });
6685
+ }
6686
+
6405
6687
  // src/sim/ctx.ts
6406
6688
  function createLocalPort(handler) {
6407
6689
  const listeners = [];
@@ -6431,17 +6713,6 @@ function createLocalPort(handler) {
6431
6713
  }
6432
6714
  };
6433
6715
  }
6434
- function wireRpcResponses(port, pending) {
6435
- port.on((message) => {
6436
- const reply = message;
6437
- if (reply?.type !== "rpc-response" || typeof reply.id !== "number") return;
6438
- const entry = pending.get(reply.id);
6439
- if (entry === void 0) return;
6440
- pending.delete(reply.id);
6441
- if (reply.ok === true) entry.resolve(reply.result);
6442
- else entry.reject(new Error(reply.error ?? "RPC \u80FD\u529B\u8C03\u7528\u5931\u8D25"));
6443
- });
6444
- }
6445
6716
  function createFlatRpcClient(handler) {
6446
6717
  return new Proxy(
6447
6718
  {},
@@ -6655,7 +6926,7 @@ function createOfflineFunctionRunner(options = {}) {
6655
6926
  return { run };
6656
6927
  }
6657
6928
 
6658
- // src/sim/runtime.ts
6929
+ // ../runtime/src/sim/merge.ts
6659
6930
  function mergeBundles(bundles) {
6660
6931
  const capabilities = [];
6661
6932
  const byName = /* @__PURE__ */ new Map();
@@ -6675,6 +6946,108 @@ function mergeBundles(bundles) {
6675
6946
  }
6676
6947
  return { capabilities, rpcHandlers };
6677
6948
  }
6949
+
6950
+ // ../runtime/src/database/sdk/kv.ts
6951
+ var KV_TABLE = "_adep_kv";
6952
+ var KV_RPC = {
6953
+ get: "get",
6954
+ put: "put",
6955
+ delete: "delete",
6956
+ list: "list"
6957
+ };
6958
+ var KV_CAPABILITY_CODES = {
6959
+ invalidMethod: "KV_INVALID_METHOD"
6960
+ };
6961
+ var KV_LIST_DEFAULT_LIMIT = 100;
6962
+ function nowSeconds() {
6963
+ return Math.floor(Date.now() / 1e3);
6964
+ }
6965
+ function errorWithCode2(error) {
6966
+ const code = typeof error === "object" && error !== null && typeof error.code === "string" ? error.code : void 0;
6967
+ if (code !== void 0 && error instanceof Error) {
6968
+ return new Error(`[${code}] ${error.message}`);
6969
+ }
6970
+ return error;
6971
+ }
6972
+ function createKvCapability(driver) {
6973
+ let ensurePromise = null;
6974
+ const ensureTable = () => {
6975
+ if (ensurePromise === null) {
6976
+ ensurePromise = driver.run(
6977
+ `CREATE TABLE IF NOT EXISTS ${KV_TABLE} (key TEXT PRIMARY KEY, value TEXT, expires_at INTEGER)`
6978
+ ).then(() => void 0);
6979
+ }
6980
+ return ensurePromise;
6981
+ };
6982
+ const handler = async (method, args) => {
6983
+ try {
6984
+ await ensureTable();
6985
+ switch (method) {
6986
+ case KV_RPC.get: {
6987
+ const [key] = args;
6988
+ const row = await driver.get(`SELECT value, expires_at FROM ${KV_TABLE} WHERE key = ?`, [
6989
+ key
6990
+ ]);
6991
+ if (row === null || row === void 0) return null;
6992
+ const expiresAt = row.expires_at;
6993
+ if (expiresAt !== null && expiresAt !== void 0 && Number(expiresAt) <= nowSeconds()) {
6994
+ return null;
6995
+ }
6996
+ return row.value;
6997
+ }
6998
+ case KV_RPC.put: {
6999
+ const [key, value, options] = args;
7000
+ const ttl = options?.expirationTtlSeconds;
7001
+ const expiresAt = typeof ttl === "number" && ttl > 0 ? nowSeconds() + Math.floor(ttl) : null;
7002
+ await driver.run(`DELETE FROM ${KV_TABLE} WHERE key = ?`, [key]);
7003
+ await driver.run(`INSERT INTO ${KV_TABLE} (key, value, expires_at) VALUES (?, ?, ?)`, [
7004
+ key,
7005
+ value,
7006
+ expiresAt
7007
+ ]);
7008
+ return void 0;
7009
+ }
7010
+ case KV_RPC.delete: {
7011
+ const [key] = args;
7012
+ await driver.run(`DELETE FROM ${KV_TABLE} WHERE key = ?`, [key]);
7013
+ return void 0;
7014
+ }
7015
+ case KV_RPC.list: {
7016
+ const [options] = args;
7017
+ const prefix = options?.prefix ?? "";
7018
+ const limit = options?.limit ?? KV_LIST_DEFAULT_LIMIT;
7019
+ const rows = prefix === "" ? await driver.all(`SELECT key, expires_at FROM ${KV_TABLE}`) : await driver.all(`SELECT key, expires_at FROM ${KV_TABLE} WHERE key LIKE ?`, [
7020
+ `${prefix}%`
7021
+ ]);
7022
+ const now = nowSeconds();
7023
+ const entries = [];
7024
+ for (const row of rows) {
7025
+ const expiresAt = row.expires_at;
7026
+ if (expiresAt !== null && expiresAt !== void 0 && Number(expiresAt) <= now) continue;
7027
+ entries.push({
7028
+ name: String(row.key),
7029
+ expiration: expiresAt === null || expiresAt === void 0 ? null : Number(expiresAt)
7030
+ });
7031
+ if (entries.length >= limit) break;
7032
+ }
7033
+ return entries;
7034
+ }
7035
+ default:
7036
+ throw new Error(
7037
+ `\u672A\u77E5\u7684 cloud.kv \u65B9\u6CD5 "${String(method)}"\uFF08${KV_CAPABILITY_CODES.invalidMethod}\uFF09`
7038
+ );
7039
+ }
7040
+ } catch (error) {
7041
+ throw errorWithCode2(error);
7042
+ }
7043
+ };
7044
+ return {
7045
+ capabilities: [{ name: "kv", value: { [RPC_CAPABILITY_KEY]: true } }],
7046
+ rpcHandlers: { kv: handler }
7047
+ };
7048
+ }
7049
+
7050
+ // src/sim/runtime.ts
6678
7051
  async function createBrowserSimRuntime(options) {
6679
7052
  const kv = options.kv ?? pickDefaultSimKv();
6680
7053
  const db = createBrowserSimDb({ projectId: options.projectId, kv });
@@ -6689,7 +7062,8 @@ async function createBrowserSimRuntime(options) {
6689
7062
  projectId: options.projectId,
6690
7063
  ...options.realtime === void 0 ? {} : options.realtime
6691
7064
  });
6692
- const bundle = mergeBundles([db.bundle, storage.bundle, realtime.bundle]);
7065
+ const kvBundle = createKvCapability(db.driver);
7066
+ const bundle = mergeBundles([db.bundle, storage.bundle, kvBundle, realtime.bundle]);
6693
7067
  await db.engine.load();
6694
7068
  const runner = createOfflineFunctionRunner(options.runner ?? {});
6695
7069
  return {
@@ -6705,6 +7079,7 @@ async function createBrowserSimRuntime(options) {
6705
7079
  // src/index.ts
6706
7080
  init_function_fetch_proxy();
6707
7081
  export {
7082
+ BUNDLE_MODULE_PATH_PREFIX,
6708
7083
  COMPLETABLE_COMMANDS,
6709
7084
  DEFAULT_MAX_INSTALL_DEPTH,
6710
7085
  EXTRA_COMMANDS,
@@ -6750,12 +7125,15 @@ export {
6750
7125
  createViteServer,
6751
7126
  createWorkerRuntime,
6752
7127
  deepEqual,
7128
+ defaultModuleName,
6753
7129
  displayPath,
6754
7130
  entriesToTree,
6755
7131
  evaluateModuleSource,
6756
7132
  evaluateSource,
6757
7133
  exampleTestSource,
6758
7134
  expect as expectAssertion,
7135
+ exportBundle,
7136
+ findBlobRefs,
6759
7137
  formatTestReport,
6760
7138
  formatValue,
6761
7139
  fullName,