weifuwu 0.24.2 → 0.24.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -65,7 +65,8 @@ function isBundled() {
65
65
  return true ? true : false;
66
66
  }
67
67
  function isDev() {
68
- return process.env.NODE_ENV === "development";
68
+ const env2 = process.env.NODE_ENV;
69
+ return env2 !== "production" && env2 !== "test";
69
70
  }
70
71
  function isProd() {
71
72
  return process.env.NODE_ENV === "production";
@@ -293,20 +294,20 @@ function serve(handler, options) {
293
294
  process.off("SIGINT", shutdownHandler);
294
295
  shutdownHandler = null;
295
296
  }
296
- return new Promise((resolve14) => {
297
+ return new Promise((resolve16) => {
297
298
  if (!server.listening) {
298
- resolve14();
299
+ resolve16();
299
300
  return;
300
301
  }
301
302
  server.close();
302
303
  server.closeIdleConnections();
303
304
  const timer = setTimeout(() => {
304
305
  server.closeAllConnections();
305
- resolve14();
306
+ resolve16();
306
307
  }, timeoutMs);
307
308
  server.on("close", () => {
308
309
  clearTimeout(timer);
309
- resolve14();
310
+ resolve16();
310
311
  });
311
312
  });
312
313
  },
@@ -1487,7 +1488,7 @@ function upload(options) {
1487
1488
  }
1488
1489
 
1489
1490
  // rate-limit.ts
1490
- function defaultKey(_req, _ctx) {
1491
+ function defaultKey(_req, _ctx2) {
1491
1492
  const forwarded = _req.headers.get("x-forwarded-for");
1492
1493
  if (forwarded) return forwarded.split(",")[0].trim();
1493
1494
  const realIp = _req.headers.get("x-real-ip");
@@ -3317,7 +3318,7 @@ h2{color:#dc2626}.desc{color:#555}</style>
3317
3318
  { status: 400, headers: { "Content-Type": "text/html; charset=utf-8" } }
3318
3319
  );
3319
3320
  }
3320
- async function authorizeHandler(req, _ctx) {
3321
+ async function authorizeHandler(req, _ctx2) {
3321
3322
  const url = new URL(req.url);
3322
3323
  const clientId = url.searchParams.get("client_id") || "";
3323
3324
  const redirectUri = url.searchParams.get("redirect_uri") || "";
@@ -5590,23 +5591,23 @@ function buildGraphQLHandler(sql2) {
5590
5591
  });
5591
5592
  return Response.json(result, { status: result.errors ? 400 : 200 });
5592
5593
  });
5593
- r.get("/", async (req, _ctx) => {
5594
+ r.get("/", async (req, _ctx2) => {
5594
5595
  const url = new URL(req.url);
5595
5596
  if (url.searchParams.has("query")) {
5596
- return handleGET(req, _ctx);
5597
+ return handleGET(req, _ctx2);
5597
5598
  }
5598
5599
  return new Response("GraphQL endpoint. Send POST /graphql with { query, variables }", {
5599
5600
  status: 200,
5600
5601
  headers: { "Content-Type": "text/plain" }
5601
5602
  });
5602
5603
  });
5603
- async function handleGET(req, _ctx) {
5604
+ async function handleGET(req, _ctx2) {
5604
5605
  const tables = await sql2`
5605
5606
  SELECT * FROM "_user_tables"
5606
- WHERE tenant_id = ${_ctx.tenant.id}
5607
+ WHERE tenant_id = ${_ctx2.tenant.id}
5607
5608
  ORDER BY created_at ASC
5608
5609
  `;
5609
- const buildCtx = { sql: sql2, tenantId: _ctx.tenant.id, tables, typeCache: /* @__PURE__ */ new Map() };
5610
+ const buildCtx = { sql: sql2, tenantId: _ctx2.tenant.id, tables, typeCache: /* @__PURE__ */ new Map() };
5610
5611
  const schema = new GraphQLSchema({
5611
5612
  query: new GraphQLObjectType({
5612
5613
  name: "Query",
@@ -5626,7 +5627,7 @@ function buildGraphQLHandler(sql2) {
5626
5627
  source: query,
5627
5628
  variableValues: variables,
5628
5629
  operationName: url.searchParams.get("operationName") || void 0,
5629
- contextValue: _ctx
5630
+ contextValue: _ctx2
5630
5631
  });
5631
5632
  return Response.json(result, { status: result.errors ? 400 : 200 });
5632
5633
  }
@@ -6653,14 +6654,14 @@ function forkApp(opts) {
6653
6654
  return { child, port: opts.port };
6654
6655
  }
6655
6656
  function stopProcess(mp, timeout = 1e4) {
6656
- return new Promise((resolve14) => {
6657
+ return new Promise((resolve16) => {
6657
6658
  const timer = setTimeout(() => {
6658
6659
  mp.child.kill("SIGKILL");
6659
- resolve14();
6660
+ resolve16();
6660
6661
  }, timeout);
6661
6662
  mp.child.on("exit", () => {
6662
6663
  clearTimeout(timer);
6663
- resolve14();
6664
+ resolve16();
6664
6665
  });
6665
6666
  mp.child.kill("SIGTERM");
6666
6667
  });
@@ -6992,22 +6993,168 @@ import { createOpenAI as createOpenAI3 } from "@ai-sdk/openai";
6992
6993
 
6993
6994
  // ssr.ts
6994
6995
  import { createElement as createElement3 } from "react";
6995
- import { createHash as createHash3 } from "node:crypto";
6996
- import { existsSync as existsSync4, readFileSync as readFileSync4, readdirSync } from "node:fs";
6996
+ import { createHash as createHash4 } from "node:crypto";
6997
+ import { existsSync as existsSync6, readdirSync } from "node:fs";
6997
6998
  import { readdir, stat } from "node:fs/promises";
6998
- import { dirname as dirname3, join as join5, resolve as resolve6, relative as relative2 } from "node:path";
6999
+ import { dirname as dirname4, join as join5, resolve as resolve8, relative as relative3 } from "node:path";
6999
7000
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
7000
7001
 
7001
7002
  // compile.ts
7002
- import * as esbuild from "esbuild";
7003
- import { existsSync, mkdirSync, readFileSync as readFileSync2 } from "node:fs";
7004
- import { join as join2, resolve as resolve3, dirname } from "node:path";
7003
+ import * as esbuild2 from "esbuild";
7004
+ import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync3 } from "node:fs";
7005
+ import { join as join2, resolve as resolve4, dirname as dirname2 } from "node:path";
7005
7006
  import { pathToFileURL } from "node:url";
7006
7007
  import { createHash } from "node:crypto";
7008
+ import { createRequire as createRequire2 } from "node:module";
7009
+
7010
+ // server-registry.ts
7011
+ import * as esbuild from "esbuild";
7012
+ import { existsSync, readFileSync as readFileSync2, statSync } from "node:fs";
7013
+ import { resolve as resolve3, dirname } from "node:path";
7007
7014
  import vm from "node:vm";
7008
7015
  import { createRequire } from "node:module";
7009
- var _cjsRequire = createRequire(import.meta.url);
7010
7016
  var _userRequire = null;
7017
+ function getUserRequire() {
7018
+ if (!_userRequire) {
7019
+ try {
7020
+ _userRequire = createRequire(resolve3(process.cwd(), "package.json"));
7021
+ } catch {
7022
+ _userRequire = createRequire(import.meta.url);
7023
+ }
7024
+ }
7025
+ return _userRequire;
7026
+ }
7027
+ var _alias = null;
7028
+ function resolveAliases() {
7029
+ if (_alias) return _alias;
7030
+ const configFiles = ["tsconfig.json", "jsconfig.json"];
7031
+ for (const file of configFiles) {
7032
+ const p = resolve3(file);
7033
+ if (existsSync(p)) {
7034
+ try {
7035
+ const config = JSON.parse(readFileSync2(p, "utf-8"));
7036
+ const paths = config.compilerOptions?.paths;
7037
+ if (paths) {
7038
+ const alias = {};
7039
+ for (const [key, values] of Object.entries(paths)) {
7040
+ const cleanKey = key.replace("/*", "");
7041
+ const val = values[0]?.replace("/*", "");
7042
+ if (val) alias[cleanKey] = resolve3(dirname(p), val);
7043
+ }
7044
+ _alias = alias;
7045
+ return alias;
7046
+ }
7047
+ } catch {
7048
+ }
7049
+ }
7050
+ }
7051
+ _alias = {};
7052
+ return {};
7053
+ }
7054
+ function applyAlias(id2, _moduleDir) {
7055
+ const aliases = resolveAliases();
7056
+ for (const [prefix, target] of Object.entries(aliases)) {
7057
+ if (id2.startsWith(prefix)) {
7058
+ const rest = id2.slice(prefix.length);
7059
+ return target + rest;
7060
+ }
7061
+ }
7062
+ return null;
7063
+ }
7064
+ var exts = [".tsx", ".ts", ".jsx", ".js"];
7065
+ function tryResolve(base) {
7066
+ if (existsSync(base)) {
7067
+ const stat3 = statSync(base);
7068
+ if (stat3.isFile()) return base;
7069
+ if (stat3.isDirectory()) {
7070
+ for (const ext of exts) {
7071
+ const p = resolve3(base, `index${ext}`);
7072
+ if (existsSync(p)) return p;
7073
+ }
7074
+ return null;
7075
+ }
7076
+ }
7077
+ for (const ext of exts) {
7078
+ const p = base + ext;
7079
+ if (existsSync(p)) return p;
7080
+ }
7081
+ return null;
7082
+ }
7083
+ var registry = /* @__PURE__ */ new Map();
7084
+ var _ctx = vm.createContext(Object.create(globalThis));
7085
+ function transformToCjs(absPath, source) {
7086
+ const isTsx = absPath.endsWith(".tsx");
7087
+ const result = esbuild.transformSync(source, {
7088
+ loader: isTsx ? "tsx" : "ts",
7089
+ format: "cjs",
7090
+ jsx: isTsx ? "automatic" : void 0,
7091
+ jsxImportSource: isTsx ? "react" : void 0,
7092
+ sourcemap: false
7093
+ });
7094
+ return result.code;
7095
+ }
7096
+ function makeRequire(modulePath) {
7097
+ const moduleDir = dirname(modulePath);
7098
+ return (id2) => {
7099
+ if (id2.startsWith(".")) {
7100
+ const base = resolve3(moduleDir, id2);
7101
+ const file = tryResolve(base);
7102
+ if (!file) {
7103
+ throw new Error(
7104
+ `[server-registry] Cannot resolve '${id2}' from '${modulePath}'. Tried: ${[base, ...exts.map((e) => base + e)].filter((p) => !p.endsWith(base)).join(", ")}`
7105
+ );
7106
+ }
7107
+ return getServerModule(file);
7108
+ }
7109
+ const aliased = applyAlias(id2, moduleDir);
7110
+ if (aliased) {
7111
+ const file = tryResolve(aliased);
7112
+ if (file) return getServerModule(file);
7113
+ }
7114
+ return getUserRequire()(id2);
7115
+ };
7116
+ }
7117
+ function evaluateModule(code, modulePath) {
7118
+ const mod = { exports: {} };
7119
+ const require2 = makeRequire(modulePath);
7120
+ const _dirname = dirname(modulePath);
7121
+ const _filename = modulePath;
7122
+ const wrapped = `(function(require,module,exports,__dirname,__filename){
7123
+ ${code}
7124
+ })`;
7125
+ try {
7126
+ new vm.Script(wrapped).runInContext(_ctx)(require2, mod, mod.exports, _dirname, _filename);
7127
+ } catch (err) {
7128
+ const msg = err instanceof Error ? err.message : String(err);
7129
+ const cause = err instanceof Error ? err : void 0;
7130
+ throw new Error(
7131
+ `[server-registry] Error evaluating '${modulePath}': ${msg}`,
7132
+ cause ? { cause } : void 0
7133
+ );
7134
+ }
7135
+ return mod.exports;
7136
+ }
7137
+ function getServerModule(absPath) {
7138
+ const normalized = resolve3(absPath);
7139
+ if (registry.has(normalized)) return registry.get(normalized).exports;
7140
+ const source = readFileSync2(normalized, "utf-8");
7141
+ const code = transformToCjs(normalized, source);
7142
+ const exports = evaluateModule(code, normalized);
7143
+ registry.set(normalized, { exports });
7144
+ return exports;
7145
+ }
7146
+ function clearServerModule(absPath) {
7147
+ if (absPath) {
7148
+ const normalized = resolve3(absPath);
7149
+ registry.delete(normalized);
7150
+ } else {
7151
+ registry.clear();
7152
+ _alias = null;
7153
+ }
7154
+ }
7155
+
7156
+ // compile.ts
7157
+ var _userRequire2 = null;
7011
7158
  var OUT_DIR = ".weifuwu/ssr";
7012
7159
  var cache = /* @__PURE__ */ new Map();
7013
7160
  var externals = [
@@ -7020,31 +7167,31 @@ var externals = [
7020
7167
  "@graphql-tools/schema",
7021
7168
  "ai"
7022
7169
  ];
7023
- var _alias = null;
7024
- function resolveAliases() {
7025
- if (_alias) return _alias;
7170
+ var _alias2 = null;
7171
+ function resolveAliases2() {
7172
+ if (_alias2) return _alias2;
7026
7173
  const configFiles = ["tsconfig.json", "jsconfig.json"];
7027
7174
  for (const file of configFiles) {
7028
- const p = resolve3(file);
7029
- if (existsSync(p)) {
7175
+ const p = resolve4(file);
7176
+ if (existsSync2(p)) {
7030
7177
  try {
7031
- const config = JSON.parse(readFileSync2(p, "utf-8"));
7178
+ const config = JSON.parse(readFileSync3(p, "utf-8"));
7032
7179
  const paths = config.compilerOptions?.paths;
7033
7180
  if (paths) {
7034
7181
  const alias = {};
7035
7182
  for (const [key, values] of Object.entries(paths)) {
7036
7183
  const cleanKey = key.replace("/*", "");
7037
7184
  const val = values[0]?.replace("/*", "");
7038
- if (val) alias[cleanKey] = resolve3(dirname(p), val);
7185
+ if (val) alias[cleanKey] = resolve4(dirname2(p), val);
7039
7186
  }
7040
- _alias = alias;
7187
+ _alias2 = alias;
7041
7188
  return alias;
7042
7189
  }
7043
7190
  } catch {
7044
7191
  }
7045
7192
  }
7046
7193
  }
7047
- _alias = {};
7194
+ _alias2 = {};
7048
7195
  return {};
7049
7196
  }
7050
7197
  function id(s) {
@@ -7052,16 +7199,17 @@ function id(s) {
7052
7199
  }
7053
7200
  function clearCompileCache() {
7054
7201
  cache.clear();
7055
- _alias = null;
7202
+ clearServerModule();
7203
+ _alias2 = null;
7056
7204
  }
7057
7205
  async function compileTsx(path2) {
7058
- const absPath = resolve3(path2);
7206
+ const absPath = resolve4(path2);
7059
7207
  if (cache.has(absPath)) return cache.get(absPath);
7060
- const outDir = resolve3(OUT_DIR);
7208
+ const outDir = resolve4(OUT_DIR);
7061
7209
  mkdirSync(outDir, { recursive: true });
7062
7210
  const hash = id(absPath);
7063
7211
  const outPath = join2(outDir, hash + ".js");
7064
- await esbuild.build({
7212
+ await esbuild2.build({
7065
7213
  entryPoints: { [hash]: absPath },
7066
7214
  outdir: outDir,
7067
7215
  format: "esm",
@@ -7070,7 +7218,7 @@ async function compileTsx(path2) {
7070
7218
  jsxImportSource: "react",
7071
7219
  bundle: true,
7072
7220
  external: externals,
7073
- alias: resolveAliases(),
7221
+ alias: resolveAliases2(),
7074
7222
  write: true,
7075
7223
  allowOverwrite: true
7076
7224
  });
@@ -7078,42 +7226,20 @@ async function compileTsx(path2) {
7078
7226
  cache.set(absPath, mod);
7079
7227
  return mod;
7080
7228
  }
7081
- function loadSSRModule(code) {
7082
- const ctx = vm.createContext(Object.create(globalThis));
7083
- const mod = { exports: {} };
7084
- ctx.require = (name) => _cjsRequire(name);
7085
- ctx.module = mod;
7086
- ctx.exports = mod.exports;
7087
- new vm.Script(code).runInContext(ctx);
7088
- return mod.exports;
7089
- }
7090
- async function compileTsxDev(path2) {
7091
- const absPath = resolve3(path2);
7092
- if (cache.has(absPath)) return cache.get(absPath);
7093
- const result = await esbuild.build({
7094
- entryPoints: { [id(absPath)]: absPath },
7095
- format: "cjs",
7096
- platform: "node",
7097
- jsx: "automatic",
7098
- jsxImportSource: "react",
7099
- bundle: true,
7100
- external: externals,
7101
- alias: resolveAliases(),
7102
- write: false
7103
- });
7104
- const code = new TextDecoder().decode(result.outputFiles[0].contents);
7105
- const mod = loadSSRModule(code);
7229
+ function compileTsxDev(path2) {
7230
+ const absPath = resolve4(path2);
7231
+ const mod = getServerModule(absPath);
7106
7232
  cache.set(absPath, mod);
7107
7233
  return mod;
7108
7234
  }
7109
7235
  function compile(path2) {
7110
- return isDev() ? compileTsxDev(path2) : compileTsx(path2);
7236
+ return isDev() ? Promise.resolve(compileTsxDev(path2)) : compileTsx(path2);
7111
7237
  }
7112
7238
  var vendorBundle = null;
7113
7239
  var vendorHash = "";
7114
7240
  async function compileVendorBundle() {
7115
7241
  if (vendorBundle) return vendorBundle;
7116
- if (!_userRequire) _userRequire = createRequire(join2(process.cwd(), "package.json"));
7242
+ if (!_userRequire2) _userRequire2 = createRequire2(join2(process.cwd(), "package.json"));
7117
7243
  const modules = {
7118
7244
  react: [],
7119
7245
  "react-dom": ["react"],
@@ -7121,13 +7247,13 @@ async function compileVendorBundle() {
7121
7247
  "react/jsx-runtime": ["react"]
7122
7248
  };
7123
7249
  for (const request of Object.keys(modules)) {
7124
- const mod = _userRequire(request);
7250
+ const mod = _userRequire2(request);
7125
7251
  const keys = Object.keys(mod).filter((k) => !k.startsWith("_") && k !== "default");
7126
7252
  modules[request] = keys;
7127
7253
  }
7128
7254
  const baseDir = import.meta.dirname ?? __dirname;
7129
- const reactAbsPath = isBundled() ? resolve3(baseDir, "react.js") : resolve3(baseDir, "react.ts");
7130
- const reactSrc = readFileSync2(reactAbsPath, "utf-8");
7255
+ const reactAbsPath = isBundled() ? resolve4(baseDir, "react.js") : resolve4(baseDir, "react.ts");
7256
+ const reactSrc = readFileSync3(reactAbsPath, "utf-8");
7131
7257
  const wfwKeys = [];
7132
7258
  if (reactAbsPath.endsWith(".ts")) {
7133
7259
  for (const line of reactSrc.split("\n")) {
@@ -7158,7 +7284,7 @@ async function compileVendorBundle() {
7158
7284
  const uidWfw = wfwKeys.filter((k) => !used.has(k) && used.add(k));
7159
7285
  if (uidWfw.length > 0)
7160
7286
  stmts.push(`export { ${uidWfw.join(", ")} } from ${JSON.stringify(reactAbsPath)};`);
7161
- const result = await esbuild.build({
7287
+ const result = await esbuild2.build({
7162
7288
  stdin: { contents: stmts.join("\n"), resolveDir: process.cwd() },
7163
7289
  format: "esm",
7164
7290
  bundle: true,
@@ -7170,95 +7296,6 @@ async function compileVendorBundle() {
7170
7296
  vendorHash = Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, 8);
7171
7297
  return vendorBundle;
7172
7298
  }
7173
- async function compileBrowser(path2, outDir) {
7174
- const absPath = resolve3(path2);
7175
- const h = id(absPath);
7176
- outDir = outDir ?? resolve3(OUT_DIR);
7177
- const outPath = join2(outDir, h + ".js");
7178
- if (!isDev() && existsSync(outPath)) return h;
7179
- mkdirSync(outDir, { recursive: true });
7180
- const wfwDir = resolve3(import.meta.dirname ?? __dirname);
7181
- const plugin = {
7182
- name: "wfw-external",
7183
- setup(build2) {
7184
- build2.onResolve({ filter: /./ }, (args) => {
7185
- if (args.kind === "entry-point") return;
7186
- const abs = args.path.startsWith(".") ? join2(args.resolveDir, args.path) : args.path;
7187
- if (abs.startsWith(wfwDir) && !abs.includes("node_modules")) {
7188
- const rel = abs.slice(wfwDir.length + 1);
7189
- if (rel.includes("/")) return;
7190
- return { path: "weifuwu/react", external: true };
7191
- }
7192
- });
7193
- }
7194
- };
7195
- await esbuild.build({
7196
- entryPoints: { [h]: absPath },
7197
- outdir: outDir,
7198
- format: "esm",
7199
- platform: "browser",
7200
- jsx: "automatic",
7201
- jsxImportSource: "react",
7202
- bundle: true,
7203
- external: [
7204
- "react",
7205
- "react-dom",
7206
- "react-dom/client",
7207
- "react/jsx-runtime",
7208
- "weifuwu",
7209
- "weifuwu/react"
7210
- ],
7211
- plugins: [plugin],
7212
- write: true,
7213
- allowOverwrite: true
7214
- });
7215
- return h;
7216
- }
7217
- async function compileHotComponent(path2) {
7218
- const absPath = resolve3(path2);
7219
- const h = id(absPath);
7220
- const stdin = `import C from ${JSON.stringify(absPath)};
7221
- (window.__WFW_REFRESH||function(){})(C)`;
7222
- const wfwDir = resolve3(import.meta.dirname ?? __dirname);
7223
- const plugin = {
7224
- name: "wfw-external",
7225
- setup(build2) {
7226
- build2.onResolve({ filter: /./ }, (args) => {
7227
- if (args.kind === "entry-point") return;
7228
- const abs = args.path.startsWith(".") ? join2(args.resolveDir, args.path) : args.path;
7229
- if (abs.startsWith(wfwDir) && !abs.includes("node_modules")) {
7230
- const rel = abs.slice(wfwDir.length + 1);
7231
- if (rel.includes("/")) return;
7232
- return { path: "weifuwu/react", external: true };
7233
- }
7234
- });
7235
- }
7236
- };
7237
- const result = await esbuild.build({
7238
- stdin: { contents: stdin, loader: "tsx", resolveDir: dirname(absPath) },
7239
- format: "esm",
7240
- platform: "browser",
7241
- jsx: "automatic",
7242
- jsxImportSource: "react",
7243
- bundle: true,
7244
- external: [
7245
- "react",
7246
- "react-dom",
7247
- "react-dom/client",
7248
- "react/jsx-runtime",
7249
- "weifuwu",
7250
- "weifuwu/react"
7251
- ],
7252
- plugins: [plugin],
7253
- write: false
7254
- });
7255
- let code = new TextDecoder().decode(result.outputFiles[0].contents);
7256
- if (code.includes("__require") && (code.includes('"react"') || code.includes("'react'"))) {
7257
- code = `import * as __r from 'react';
7258
- ` + code.replace(/__require\(["']react["']\)/g, "__r");
7259
- }
7260
- return { hash: h, code };
7261
- }
7262
7299
 
7263
7300
  // stream.ts
7264
7301
  import { TextDecoder as TextDecoder2, TextEncoder as TextEncoder2 } from "node:util";
@@ -7276,6 +7313,8 @@ function getPublicEnv2() {
7276
7313
  function buildHeadPayload(opts) {
7277
7314
  const { ctx, base, tailwind } = opts;
7278
7315
  let result = "";
7316
+ result += `<script>window.__wfw={_cache:{},_k:function(u){return u.split('?')[0]},h:async function(u){var k=this._k(u);if(this._cache[k])return this._cache[k];var m=await import(u);this._cache[k]=m;return m},_update:function(u,mod){var k=this._k(u);this._cache[k]=mod}}</script>
7317
+ `;
7279
7318
  const vUrl = `${base}/__wfw/v/bundle?h=${vendorHash}`;
7280
7319
  result += `<script type="importmap">{
7281
7320
  "imports": {
@@ -7360,26 +7399,37 @@ function streamResponse(reactStream, opts, hydrationScript) {
7360
7399
  if (built) bodyScripts += built;
7361
7400
  if (opts.isDev) {
7362
7401
  const wsUrl = `${opts.base}/__weifuwu/livereload`;
7363
- const hbUrl = `${opts.base}/__wfw/h/`;
7364
7402
  bodyScripts += `
7365
7403
  <script>
7366
7404
  (function(){
7367
7405
  var ws=new WebSocket((location.protocol==='https:'?'wss:':'ws:')+'//'+location.host+'${wsUrl}');
7368
7406
  var t=0;
7407
+ var _w=window;
7369
7408
  ws.onmessage=function(e){
7370
7409
  try{
7371
7410
  var m=JSON.parse(e.data);
7372
- if(m.type==='component'){
7373
- import('${hbUrl}'+m.hash+'?t='+Date.now()).catch(function(){location.reload()});
7374
- if(m.css){
7375
- var s=document.querySelector('style[data-lr]')||function(){
7376
- var x=document.createElement('style');
7377
- x.setAttribute('data-lr','');
7378
- document.head.appendChild(x);
7379
- return x
7380
- }();
7381
- s.textContent=m.css
7382
- }
7411
+ if(m.type==='update'&&m.url&&m.code){
7412
+ var blob=new Blob([m.code],{type:'application/javascript'});
7413
+ var blobUrl=URL.createObjectURL(blob);
7414
+ import(blobUrl).then(function(mod){
7415
+ if(_w.__wfw) _w.__wfw._update(m.url,mod);
7416
+ // Re-import page module so it re-evaluates its __wfw.h() imports
7417
+ var pageUrl=_w.__WFW_PAGE_URL;
7418
+ if(pageUrl&&_w.__WFW_REFRESH){
7419
+ import(pageUrl.split('?')[0]+'?t='+Date.now()).then(function(pageMod){
7420
+ if(pageMod.default) _w.__WFW_REFRESH(pageMod.default);
7421
+ if(m.css){
7422
+ var s=document.querySelector('style[data-lr]')||function(){
7423
+ var x=document.createElement('style');
7424
+ x.setAttribute('data-lr','');
7425
+ document.head.appendChild(x);
7426
+ return x
7427
+ }();
7428
+ s.textContent=m.css
7429
+ }
7430
+ });
7431
+ }else{location.reload()}
7432
+ }).catch(function(){location.reload()});
7383
7433
  return
7384
7434
  }
7385
7435
  if(m.type==='css'){
@@ -7430,12 +7480,12 @@ var ssrEntries = /* @__PURE__ */ new Map();
7430
7480
 
7431
7481
  // tailwind.ts
7432
7482
  import { createHash as createHash2 } from "node:crypto";
7433
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync } from "node:fs";
7434
- import { join as join3, relative, resolve as resolve4 } from "node:path";
7483
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync } from "node:fs";
7484
+ import { join as join3, relative, resolve as resolve5 } from "node:path";
7435
7485
  var extraSources = /* @__PURE__ */ new Set();
7436
7486
  var cssCache = /* @__PURE__ */ new Map();
7437
7487
  function tailwindContext(dir) {
7438
- const cssDir = resolve4(dir);
7488
+ const cssDir = resolve5(dir);
7439
7489
  const cssPath = join3(cssDir, "app", "globals.css");
7440
7490
  return async (req, ctx, next) => {
7441
7491
  if (!cssCache.has(cssPath)) {
@@ -7449,10 +7499,10 @@ function tailwindContext(dir) {
7449
7499
  };
7450
7500
  }
7451
7501
  function tailwindRouter(dir) {
7452
- const cssDir = resolve4(dir);
7502
+ const cssDir = resolve5(dir);
7453
7503
  const cssPath = join3(cssDir, "app", "globals.css");
7454
7504
  const r = new Router();
7455
- r.get("/__wfw/style/:hash.css", async (_req, _ctx) => {
7505
+ r.get("/__wfw/style/:hash.css", async (_req, _ctx2) => {
7456
7506
  if (!cssCache.has(cssPath)) {
7457
7507
  await compileTailwindCss(cssPath, cssDir);
7458
7508
  }
@@ -7466,13 +7516,13 @@ function tailwindRouter(dir) {
7466
7516
  }
7467
7517
  async function compileTailwindCss(cssPath, cssDir) {
7468
7518
  try {
7469
- if (!existsSync2(cssPath)) {
7519
+ if (!existsSync3(cssPath)) {
7470
7520
  mkdirSync2(cssDir, { recursive: true });
7471
7521
  writeFileSync(cssPath, '@import "tailwindcss"\n', "utf-8");
7472
7522
  }
7473
7523
  const { default: tailwindPlugin } = await import("@tailwindcss/postcss");
7474
7524
  const { default: postcss } = await import("postcss");
7475
- let src = readFileSync3(cssPath, "utf-8");
7525
+ let src = readFileSync4(cssPath, "utf-8");
7476
7526
  src = `@source "./";
7477
7527
  ${src}`;
7478
7528
  for (const srcDir of extraSources) {
@@ -7492,22 +7542,151 @@ ${src}`;
7492
7542
 
7493
7543
  // live.ts
7494
7544
  import chokidar from "chokidar";
7495
- import { existsSync as existsSync3 } from "node:fs";
7496
- import { dirname as dirname2, join as join4, resolve as resolve5 } from "node:path";
7497
- var clients = /* @__PURE__ */ new Set();
7498
- var hotBundleCache = /* @__PURE__ */ new Map();
7499
- var hotKeys = [];
7500
- var MAX_HOT = 10;
7501
- function setHot(hash, code) {
7502
- if (!hotBundleCache.has(hash)) {
7503
- hotKeys.push(hash);
7504
- if (hotKeys.length > MAX_HOT) {
7505
- const old = hotKeys.shift();
7506
- hotBundleCache.delete(old);
7507
- }
7545
+ import { existsSync as existsSync5 } from "node:fs";
7546
+ import { join as join4, resolve as resolve7 } from "node:path";
7547
+
7548
+ // module-server.ts
7549
+ import * as esbuild3 from "esbuild";
7550
+ import { existsSync as existsSync4, readFileSync as readFileSync5 } from "node:fs";
7551
+ import { resolve as resolve6, dirname as dirname3, relative as relative2 } from "node:path";
7552
+ import { createHash as createHash3 } from "node:crypto";
7553
+ var moduleCache = /* @__PURE__ */ new Map();
7554
+ var hashCache = /* @__PURE__ */ new Map();
7555
+ function clearModuleCache(filePath) {
7556
+ if (filePath) {
7557
+ const abs = resolve6(filePath);
7558
+ for (const key of moduleCache.keys()) {
7559
+ if (key.endsWith(abs)) moduleCache.delete(key);
7560
+ }
7561
+ hashCache.delete(abs);
7562
+ } else {
7563
+ moduleCache.clear();
7564
+ hashCache.clear();
7508
7565
  }
7509
- hotBundleCache.set(hash, code);
7510
7566
  }
7567
+ var _importRoots = [];
7568
+ function _setImportRoots(roots) {
7569
+ _importRoots = roots;
7570
+ }
7571
+ function fileHash(absPath) {
7572
+ const cached = hashCache.get(absPath);
7573
+ if (cached) return cached;
7574
+ try {
7575
+ const content = readFileSync5(absPath);
7576
+ const h = createHash3("md5").update(content).digest("hex").slice(0, 8);
7577
+ hashCache.set(absPath, h);
7578
+ return h;
7579
+ } catch {
7580
+ return "00000000";
7581
+ }
7582
+ }
7583
+ function rewriteImports(code, absPath, mountPath) {
7584
+ const prefix = mountPath ? `${mountPath}/__wfw/m` : "/__wfw/m";
7585
+ let varCounter = 0;
7586
+ return code.replace(
7587
+ /^(import|export)\s+(.+?)\s+from\s+['"]([^'"]+)['"];?\s*$/gm,
7588
+ (_match, keyword, clause, modPath) => {
7589
+ if (!modPath.startsWith(".")) return _match;
7590
+ const isReexport = keyword === "export";
7591
+ const imports = clause.replace(/^type\s+/, "");
7592
+ const resolved = resolve6(dirname3(absPath), modPath);
7593
+ for (const root of _importRoots) {
7594
+ const rel = relative2(root, resolved);
7595
+ if (!rel.startsWith("..") && !rel.startsWith("/")) {
7596
+ const v = fileHash(resolved);
7597
+ const url = `${prefix}/${rel}?v=${v}`;
7598
+ const defaultMatch = imports.match(/^\s*(\w[\w$]*)\s*$/);
7599
+ const namedMatch = imports.match(/^\s*\{\s*([\w$,\s]+)\s*\}\s*$/);
7600
+ const mixedMatch = imports.match(/^\s*(\w[\w$]*)\s*,\s*\{\s*([\w$,\s]+)\s*\}\s*$/);
7601
+ if (defaultMatch) {
7602
+ const name = defaultMatch[1];
7603
+ if (isReexport) {
7604
+ return `const { default: ${name} } = await __wfw.h("${url}");
7605
+ export { ${name} as default }`;
7606
+ }
7607
+ return `const { default: ${name} } = await __wfw.h("${url}");`;
7608
+ }
7609
+ if (namedMatch) {
7610
+ const names = namedMatch[1].split(",").map((s) => s.trim()).filter(Boolean);
7611
+ if (isReexport) {
7612
+ const tmp = `__wfw$${varCounter++}`;
7613
+ const lines = [`const ${tmp} = await __wfw.h("${url}");`];
7614
+ for (const n of names) lines.push(`export const ${n} = ${tmp}.${n};`);
7615
+ return lines.join("\n");
7616
+ }
7617
+ const decl = names.map((n) => `${n}`).join(", ");
7618
+ return `const { ${decl} } = await __wfw.h("${url}");`;
7619
+ }
7620
+ if (mixedMatch) {
7621
+ const defaultName = mixedMatch[1];
7622
+ const namedNames = mixedMatch[2].split(",").map((s) => s.trim()).filter(Boolean);
7623
+ const varName = `__wfw$${varCounter++}`;
7624
+ const lines = [
7625
+ `const ${varName} = await __wfw.h("${url}");`,
7626
+ `const ${defaultName} = ${varName}.default;`
7627
+ ];
7628
+ for (const n of namedNames) lines.push(`const { ${n} } = ${varName};`);
7629
+ return lines.join("\n");
7630
+ }
7631
+ return _match;
7632
+ }
7633
+ }
7634
+ return _match;
7635
+ }
7636
+ );
7637
+ }
7638
+ async function transformModule(absPath, root, mountPath) {
7639
+ const mp = mountPath || "";
7640
+ const cacheKey = mp + absPath;
7641
+ const cached = moduleCache.get(cacheKey);
7642
+ if (cached) return { url: `${mp}/__wfw/m/${relative2(root, absPath)}`, code: cached };
7643
+ const source = readFileSync5(absPath, "utf-8");
7644
+ const isTsx = absPath.endsWith(".tsx");
7645
+ const result = await esbuild3.transform(source, {
7646
+ loader: isTsx ? "tsx" : "ts",
7647
+ jsx: isTsx ? "automatic" : void 0,
7648
+ jsxImportSource: isTsx ? "react" : void 0,
7649
+ sourcemap: false
7650
+ });
7651
+ let code = result.code;
7652
+ code = rewriteImports(code, absPath, mp);
7653
+ moduleCache.set(cacheKey, code);
7654
+ const url = `${mp}/__wfw/m/${relative2(root, absPath)}`;
7655
+ return { url, code };
7656
+ }
7657
+ function moduleServer(opts) {
7658
+ const roots = Array.isArray(opts.root) ? opts.root : [opts.root];
7659
+ _setImportRoots(roots);
7660
+ const router = new Router();
7661
+ router.get("/__wfw/m/*", (async (req, ctx) => {
7662
+ const reqUrl = new URL(req.url);
7663
+ const filePath = (ctx.params["*"] || "").split("?")[0];
7664
+ const ext = filePath.split(".").pop();
7665
+ if (ext !== "tsx" && ext !== "ts") {
7666
+ return new Response("Not Found", { status: 404 });
7667
+ }
7668
+ const mountPath = ctx.mountPath || "";
7669
+ for (const root of roots) {
7670
+ const absPath = resolve6(root, filePath);
7671
+ if (existsSync4(absPath)) {
7672
+ try {
7673
+ const { code } = await transformModule(absPath, root, mountPath);
7674
+ return new Response(code, {
7675
+ headers: { "content-type": "application/javascript; charset=utf-8" }
7676
+ });
7677
+ } catch (err) {
7678
+ const msg = err instanceof Error ? err.message : String(err);
7679
+ return new Response(`/* Error: ${msg} */`, { status: 500 });
7680
+ }
7681
+ }
7682
+ }
7683
+ return new Response("Not Found", { status: 404 });
7684
+ }));
7685
+ return router;
7686
+ }
7687
+
7688
+ // live.ts
7689
+ var clients = /* @__PURE__ */ new Set();
7511
7690
  function broadcastReload() {
7512
7691
  for (const ws of clients) {
7513
7692
  try {
@@ -7529,7 +7708,7 @@ function broadcastCss(css) {
7529
7708
  }
7530
7709
  function liveWs() {
7531
7710
  return {
7532
- open(ws) {
7711
+ open(ws, _ctx2) {
7533
7712
  clients.add(ws);
7534
7713
  ws.on("close", () => clients.delete(ws));
7535
7714
  ws.on("error", () => clients.delete(ws));
@@ -7540,78 +7719,52 @@ function liveRouter(_dir) {
7540
7719
  const r = new Router();
7541
7720
  compileVendorBundle().catch(() => {
7542
7721
  });
7543
- r.get("/__wfw/h/:hash", async (req, ctx) => {
7544
- const hash = ctx.params.hash.replace(/\.js$/i, "");
7545
- const code = hotBundleCache.get(hash);
7546
- if (!code) return new Response("", { status: 404 });
7547
- return new Response(code, {
7548
- headers: { "content-type": "application/javascript; charset=utf-8" }
7549
- });
7550
- });
7551
7722
  return r;
7552
7723
  }
7553
7724
  function liveWatcher(dir) {
7554
- const resolved = resolve5(dir);
7555
- const entryPath = join4(resolved, "page.tsx");
7725
+ const resolved = resolve7(dir);
7556
7726
  const watcher = chokidar.watch(dir, {
7557
7727
  ignored: /(^|[/\\])\.|node_modules|[/\\]\.weifuwu[/\\]/,
7558
7728
  ignoreInitial: true
7559
7729
  });
7560
- function findEntries(changedPath) {
7561
- const matched = [];
7562
- for (const [, entry] of ssrEntries) {
7563
- if (!entry.path.startsWith(resolved)) continue;
7564
- if (entry.path === changedPath) {
7565
- matched.push(entry.path);
7566
- } else {
7567
- const ed = dirname2(entry.path);
7568
- if (changedPath.startsWith(ed)) matched.push(entry.path);
7569
- }
7570
- }
7571
- if (matched.length === 0) {
7572
- for (const [, entry] of ssrEntries) {
7573
- if (entry.path.startsWith(resolved)) matched.push(entry.path);
7574
- }
7575
- }
7576
- return matched;
7577
- }
7578
7730
  watcher.on("change", async (filePath) => {
7579
7731
  if (/\.tsx?$/i.test(filePath)) {
7580
7732
  if (filePath.endsWith("layout.tsx")) {
7581
7733
  return broadcastReload();
7582
7734
  }
7583
7735
  clearCompileCache();
7584
- const targets = existsSync3(entryPath) ? [entryPath] : findEntries(resolve5(filePath));
7585
- if (targets.length === 0) return broadcastReload();
7736
+ clearModuleCache();
7586
7737
  try {
7587
- let css;
7588
- const cssPath = join4(resolved, "app", "globals.css");
7589
- if (existsSync3(cssPath)) {
7590
- css = await compileTailwindCss(cssPath, resolved);
7591
- }
7592
- for (const target of targets) {
7593
- await compileTsxDev(target);
7594
- const { hash, code } = await compileHotComponent(target);
7595
- setHot(hash, code);
7596
- const entry = id(target);
7597
- const msg = { type: "component", hash, entry };
7598
- if (css) msg.css = css;
7599
- const str = JSON.stringify(msg);
7600
- for (const ws of clients) {
7601
- try {
7602
- ws.send(str);
7603
- } catch {
7604
- clients.delete(ws);
7605
- }
7738
+ await compileTsxDev(filePath);
7739
+ } catch (e) {
7740
+ console.error("server-side recompile failed:", e);
7741
+ return broadcastReload();
7742
+ }
7743
+ let css;
7744
+ const cssPath = join4(resolved, "app", "globals.css");
7745
+ if (existsSync5(cssPath)) {
7746
+ css = await compileTailwindCss(cssPath, resolved);
7747
+ }
7748
+ try {
7749
+ const absPath = resolve7(filePath);
7750
+ const { url, code } = await transformModule(absPath, resolved);
7751
+ const msg = { type: "update", url, code };
7752
+ if (css) msg.css = css;
7753
+ const str = JSON.stringify(msg);
7754
+ for (const ws of clients) {
7755
+ try {
7756
+ ws.send(str);
7757
+ } catch {
7758
+ clients.delete(ws);
7606
7759
  }
7607
7760
  }
7608
7761
  } catch (e) {
7609
- console.error("live reload failed, fallback to full reload:", e);
7762
+ console.error("module transform failed for HMR:", e);
7610
7763
  broadcastReload();
7611
7764
  }
7612
7765
  } else if (/\.css$/i.test(filePath)) {
7613
7766
  const cssPath = join4(resolved, "app", "globals.css");
7614
- if (existsSync3(cssPath)) {
7767
+ if (existsSync5(cssPath)) {
7615
7768
  const css = await compileTailwindCss(cssPath, resolved);
7616
7769
  if (css) broadcastCss(css);
7617
7770
  }
@@ -7699,7 +7852,7 @@ var isDev2 = isDev();
7699
7852
  var als2 = new AsyncLocalStorage2();
7700
7853
  __registerAls(() => als2.getStore());
7701
7854
  function hashId(s) {
7702
- return createHash3("md5").update(s).digest("hex").slice(0, 8);
7855
+ return createHash4("md5").update(s).digest("hex").slice(0, 8);
7703
7856
  }
7704
7857
  function serializeLoaderData(ctx) {
7705
7858
  const ld = ctx.loaderData;
@@ -7774,7 +7927,7 @@ async function resolveRoute(ssrDir, segments, routeCache) {
7774
7927
  return null;
7775
7928
  }
7776
7929
  const pageFile = join5(dir, "page.tsx");
7777
- if (!existsSync4(pageFile)) {
7930
+ if (!existsSync6(pageFile)) {
7778
7931
  routeCache.set(cacheKey, null);
7779
7932
  return null;
7780
7933
  }
@@ -7785,28 +7938,28 @@ async function resolveRoute(ssrDir, segments, routeCache) {
7785
7938
  let d = dir;
7786
7939
  while (d.startsWith(appDir)) {
7787
7940
  const lf = join5(d, "layout.tsx");
7788
- if (existsSync4(lf)) layoutFiles.unshift(lf);
7941
+ if (existsSync6(lf)) layoutFiles.unshift(lf);
7789
7942
  if (d === appDir) break;
7790
- d = dirname3(d);
7943
+ d = dirname4(d);
7791
7944
  }
7792
7945
  const errorFiles = [];
7793
7946
  d = dir;
7794
7947
  while (d.startsWith(appDir)) {
7795
7948
  const ef = join5(d, "error.tsx");
7796
- if (existsSync4(ef)) errorFiles.unshift(ef);
7949
+ if (existsSync6(ef)) errorFiles.unshift(ef);
7797
7950
  if (d === appDir) break;
7798
- d = dirname3(d);
7951
+ d = dirname4(d);
7799
7952
  }
7800
7953
  let notFoundFile = null;
7801
7954
  d = dir;
7802
7955
  while (d.startsWith(appDir)) {
7803
7956
  const nf = join5(d, "not-found.tsx");
7804
- if (existsSync4(nf)) {
7957
+ if (existsSync6(nf)) {
7805
7958
  notFoundFile = nf;
7806
7959
  break;
7807
7960
  }
7808
7961
  if (d === appDir) break;
7809
- d = dirname3(d);
7962
+ d = dirname4(d);
7810
7963
  }
7811
7964
  const result = {
7812
7965
  routePath: "/" + routeParams.join("/"),
@@ -7818,8 +7971,7 @@ async function resolveRoute(ssrDir, segments, routeCache) {
7818
7971
  routeCache.set(cacheKey, result);
7819
7972
  return result;
7820
7973
  }
7821
- function buildHydrationScript(entryId, ctxJson, base) {
7822
- const ssrPrefix = `${base}/__ssr`;
7974
+ function buildHydrationScript(pageUrl, ctxJson) {
7823
7975
  return `
7824
7976
  <script type="module">
7825
7977
  import { setCtx, TsxContext } from 'weifuwu/react';
@@ -7832,10 +7984,11 @@ setCtx(_ctx);
7832
7984
  const _root = document.getElementById('__weifuwu_root');
7833
7985
 
7834
7986
  async function init() {
7835
- const { default: Page } = await import('${ssrPrefix}/${entryId}.js');
7836
- const app = createElement(TsxContext.Provider, { value: _ctx },
7837
- createElement(Page));
7987
+ const { default: Page } = await import('${pageUrl}');
7838
7988
  ${isDev2 ? `
7989
+ // Store page URL for __wfw runtime
7990
+ window.__WFW_PAGE_URL = '${pageUrl}';
7991
+
7839
7992
  // Stable proxy \u2014 same function ref = React preserves fiber + useState state across HMR
7840
7993
  const _pageImpl = { current: Page };
7841
7994
  const _pageProxy = new Proxy(function __wfw_page(){}, {
@@ -7852,14 +8005,22 @@ async function init() {
7852
8005
  }
7853
8006
  renderPage();
7854
8007
 
8008
+ // HMR: re-render page (sub-modules resolved via __wfw.h() pick up changes)
8009
+ window.__WFW_RERENDER = () => {
8010
+ _tick++;
8011
+ reactRoot.render(createElement(TsxContext.Provider, { value: _ctx },
8012
+ createElement(_pageProxy, { __t: _tick })));
8013
+ };
8014
+
8015
+ // Fallback: swap entire page component
7855
8016
  window.__WFW_REFRESH = async (NewComponent) => {
7856
8017
  const store = globalThis.__WEIFUWU_CTX_STORE?._ctx || _ctx;
7857
8018
  _pageImpl.current = NewComponent;
7858
- _tick++;
7859
- reactRoot.render(createElement(TsxContext.Provider, { value: store },
7860
- createElement(_pageProxy, { __t: _tick })));
8019
+ __WFW_RERENDER();
7861
8020
  };
7862
8021
  ` : `
8022
+ const app = createElement(TsxContext.Provider, { value: _ctx },
8023
+ createElement(Page));
7863
8024
  hydrateRoot(_root, app);
7864
8025
  `}
7865
8026
  }
@@ -7867,8 +8028,8 @@ async function init() {
7867
8028
  init();
7868
8029
  </script>`;
7869
8030
  }
7870
- function renderPage(pageFile, outDir) {
7871
- const absPath = resolve6(pageFile);
8031
+ function renderPage(pageFile, projectDir) {
8032
+ const absPath = resolve8(pageFile);
7872
8033
  const entryId = hashId(absPath);
7873
8034
  ssrEntries.set(entryId, { path: absPath });
7874
8035
  return async (req, ctx) => {
@@ -7897,9 +8058,10 @@ function renderPage(pageFile, outDir) {
7897
8058
  loaderData,
7898
8059
  env: ctx.env ?? {}
7899
8060
  };
8061
+ const pageRelative = relative3(projectDir, absPath);
8062
+ const pageUrl = `${base}/__wfw/m/${pageRelative}`;
7900
8063
  return als2.run(ctxValue, async () => {
7901
8064
  setCtx(ctxValue);
7902
- await compileBrowser(absPath, outDir);
7903
8065
  let element = createElement3(
7904
8066
  "div",
7905
8067
  { id: "__weifuwu_root" },
@@ -7917,7 +8079,7 @@ function renderPage(pageFile, outDir) {
7917
8079
  loaderData,
7918
8080
  tailwind: ctx.tailwind
7919
8081
  },
7920
- buildHydrationScript(entryId, JSON.stringify(ctxValue), base)
8082
+ buildHydrationScript(pageUrl, JSON.stringify(ctxValue))
7921
8083
  );
7922
8084
  });
7923
8085
  };
@@ -7932,7 +8094,7 @@ function runChain(mws, handler, req, ctx) {
7932
8094
  }
7933
8095
  function discoverRoutes(dir) {
7934
8096
  const appDir = join5(dir, "app");
7935
- if (!existsSync4(appDir)) return [];
8097
+ if (!existsSync6(appDir)) return [];
7936
8098
  const result = [];
7937
8099
  function walk(currentDir, routePath) {
7938
8100
  let entries;
@@ -7953,7 +8115,7 @@ function discoverRoutes(dir) {
7953
8115
  } else if (entry.name === "page.tsx") {
7954
8116
  result.push({
7955
8117
  path: routePath || "/",
7956
- file: relative2(appDir, join5(currentDir, entry.name))
8118
+ file: relative3(appDir, join5(currentDir, entry.name))
7957
8119
  });
7958
8120
  }
7959
8121
  }
@@ -7963,28 +8125,19 @@ function discoverRoutes(dir) {
7963
8125
  }
7964
8126
  function ssr(opts) {
7965
8127
  const r = new Router();
7966
- const dir = resolve6(opts.dir);
7967
- const outDir = resolve6(OUT_DIR);
8128
+ const dir = resolve8(opts.dir);
7968
8129
  const routeCache = /* @__PURE__ */ new Map();
8130
+ const wfwRoot = resolve8(import.meta.dirname ?? __dirname);
8131
+ r.use("/", moduleServer({ root: [dir, wfwRoot] }));
7969
8132
  compileVendorBundle().catch(() => {
7970
8133
  });
7971
- r.get("/__ssr/:file", (req, ctx) => {
7972
- const filePath = join5(outDir, ctx.params.file);
7973
- if (!filePath.startsWith(outDir) || !existsSync4(filePath)) {
7974
- return new Response("Not Found", { status: 404 });
7975
- }
7976
- const content = readFileSync4(filePath, "utf-8");
7977
- return new Response(content, {
7978
- headers: { "content-type": "application/javascript; charset=utf-8" }
7979
- });
7980
- });
7981
8134
  r.get("/__wfw/v/bundle", async () => {
7982
8135
  const code = await compileVendorBundle();
7983
8136
  return new Response(code, {
7984
8137
  headers: { "content-type": "application/javascript; charset=utf-8" }
7985
8138
  });
7986
8139
  });
7987
- if (existsSync4(join5(dir, "app", "globals.css"))) {
8140
+ if (existsSync6(join5(dir, "app", "globals.css"))) {
7988
8141
  r.use("/", tailwindRouter(dir));
7989
8142
  }
7990
8143
  let devWatcher;
@@ -8020,7 +8173,7 @@ function ssr(opts) {
8020
8173
  ...resolved.layoutFiles.map((f) => layout(f)),
8021
8174
  tailwindContext(dir)
8022
8175
  ];
8023
- const handler = (req2, ctx2) => renderPage(resolved.pageFile, outDir)(req2, ctx2);
8176
+ const handler = (req2, ctx2) => renderPage(resolved.pageFile, dir)(req2, ctx2);
8024
8177
  return runChain(mws, handler, req, ctx);
8025
8178
  });
8026
8179
  const mod = r;
@@ -8272,13 +8425,13 @@ function createBashTool(ctx) {
8272
8425
  return { stdout: "", stderr: "Command denied: potentially dangerous command", exitCode: 1 };
8273
8426
  }
8274
8427
  const cwd = workdir ? `${ctx.workspace}/${workdir}` : ctx.workspace;
8275
- return new Promise((resolve14) => {
8428
+ return new Promise((resolve16) => {
8276
8429
  const child = exec(
8277
8430
  command,
8278
8431
  { cwd, timeout: timeout * 1e3, maxBuffer: 1024 * 1024 },
8279
8432
  (error, stdout, stderr) => {
8280
8433
  const truncated = stdout.length > 1e6 || stderr.length > 1e6;
8281
- resolve14({
8434
+ resolve16({
8282
8435
  stdout: stdout.slice(0, 1e6),
8283
8436
  stderr: stderr.slice(0, 1e6),
8284
8437
  exitCode: error?.code ?? 0,
@@ -8295,8 +8448,8 @@ function createBashTool(ctx) {
8295
8448
  // opencode/tools/read.ts
8296
8449
  import { tool as tool4 } from "ai";
8297
8450
  import { z as z6 } from "zod";
8298
- import { readFileSync as readFileSync5 } from "node:fs";
8299
- import { resolve as resolve7 } from "node:path";
8451
+ import { readFileSync as readFileSync7 } from "node:fs";
8452
+ import { resolve as resolve9 } from "node:path";
8300
8453
  function createReadTool(ctx) {
8301
8454
  return tool4({
8302
8455
  description: "Read file contents. Supports offset and limit for reading specific line ranges.",
@@ -8306,11 +8459,11 @@ function createReadTool(ctx) {
8306
8459
  limit: z6.number().optional().describe("Number of lines to read")
8307
8460
  }),
8308
8461
  execute: async ({ path: path2, offset, limit }) => {
8309
- const resolved = resolve7(ctx.workspace, path2);
8462
+ const resolved = resolve9(ctx.workspace, path2);
8310
8463
  if (!isPathAllowed(resolved, ctx.workspace, ctx.permissions.permissions)) {
8311
8464
  return { error: "Path not allowed", content: null, totalLines: 0 };
8312
8465
  }
8313
- const content = readFileSync5(resolved, "utf-8");
8466
+ const content = readFileSync7(resolved, "utf-8");
8314
8467
  const lines = content.split("\n");
8315
8468
  const totalLines = lines.length;
8316
8469
  if (offset !== void 0) {
@@ -8338,7 +8491,7 @@ function createReadTool(ctx) {
8338
8491
  import { tool as tool5 } from "ai";
8339
8492
  import { z as z7 } from "zod";
8340
8493
  import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync3 } from "node:fs";
8341
- import { resolve as resolve8, dirname as dirname4 } from "node:path";
8494
+ import { resolve as resolve10, dirname as dirname5 } from "node:path";
8342
8495
  function createWriteTool(ctx) {
8343
8496
  return tool5({
8344
8497
  description: "Create or overwrite a file. Parent directories are created automatically.",
@@ -8347,11 +8500,11 @@ function createWriteTool(ctx) {
8347
8500
  content: z7.string().describe("File content")
8348
8501
  }),
8349
8502
  execute: async ({ path: path2, content }) => {
8350
- const resolved = resolve8(ctx.workspace, path2);
8503
+ const resolved = resolve10(ctx.workspace, path2);
8351
8504
  if (!isPathAllowed(resolved, ctx.workspace, ctx.permissions.permissions)) {
8352
8505
  return { error: "Path not allowed" };
8353
8506
  }
8354
- mkdirSync3(dirname4(resolved), { recursive: true });
8507
+ mkdirSync3(dirname5(resolved), { recursive: true });
8355
8508
  writeFileSync2(resolved, content, "utf-8");
8356
8509
  return { path: path2, size: content.length };
8357
8510
  }
@@ -8361,8 +8514,8 @@ function createWriteTool(ctx) {
8361
8514
  // opencode/tools/edit.ts
8362
8515
  import { tool as tool6 } from "ai";
8363
8516
  import { z as z8 } from "zod";
8364
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "node:fs";
8365
- import { resolve as resolve9 } from "node:path";
8517
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync3 } from "node:fs";
8518
+ import { resolve as resolve11 } from "node:path";
8366
8519
  function createEditTool(ctx) {
8367
8520
  return tool6({
8368
8521
  description: "Perform exact string replacements in a file. If oldString appears multiple times, provide more surrounding context.",
@@ -8373,11 +8526,11 @@ function createEditTool(ctx) {
8373
8526
  replaceAll: z8.boolean().default(false).describe("Replace all occurrences")
8374
8527
  }),
8375
8528
  execute: async ({ path: path2, oldString, newString, replaceAll }) => {
8376
- const resolved = resolve9(ctx.workspace, path2);
8529
+ const resolved = resolve11(ctx.workspace, path2);
8377
8530
  if (!isPathAllowed(resolved, ctx.workspace, ctx.permissions.permissions)) {
8378
8531
  return { error: "Path not allowed" };
8379
8532
  }
8380
- const content = readFileSync6(resolved, "utf-8");
8533
+ const content = readFileSync8(resolved, "utf-8");
8381
8534
  if (replaceAll) {
8382
8535
  if (!content.includes(oldString)) {
8383
8536
  return { error: "oldString not found in file", replaced: 0 };
@@ -8409,8 +8562,8 @@ function createEditTool(ctx) {
8409
8562
  import { tool as tool7 } from "ai";
8410
8563
  import { z as z9 } from "zod";
8411
8564
  import { execFileSync } from "node:child_process";
8412
- import { resolve as resolve10 } from "node:path";
8413
- import { existsSync as existsSync5 } from "node:fs";
8565
+ import { resolve as resolve12 } from "node:path";
8566
+ import { existsSync as existsSync7 } from "node:fs";
8414
8567
  function createGrepTool(ctx) {
8415
8568
  return tool7({
8416
8569
  description: "Search file contents using regex. Supports file type filtering and context lines.",
@@ -8421,10 +8574,10 @@ function createGrepTool(ctx) {
8421
8574
  context: z9.number().default(0).describe("Number of context lines before and after each match")
8422
8575
  }),
8423
8576
  execute: async ({ pattern, include, path: path2, context }) => {
8424
- const searchDir = path2 ? resolve10(ctx.workspace, path2) : ctx.workspace;
8577
+ const searchDir = path2 ? resolve12(ctx.workspace, path2) : ctx.workspace;
8425
8578
  try {
8426
8579
  let stdout;
8427
- if (existsSync5("/usr/bin/rg") || existsSync5("/usr/local/bin/rg")) {
8580
+ if (existsSync7("/usr/bin/rg") || existsSync7("/usr/local/bin/rg")) {
8428
8581
  const args = ["-n"];
8429
8582
  if (context > 0) args.push("-C", String(context));
8430
8583
  if (include) args.push("-g", include);
@@ -8457,7 +8610,7 @@ function createGrepTool(ctx) {
8457
8610
  import { tool as tool8 } from "ai";
8458
8611
  import { z as z10 } from "zod";
8459
8612
  import { execFileSync as execFileSync2 } from "node:child_process";
8460
- import { resolve as resolve11 } from "node:path";
8613
+ import { resolve as resolve13 } from "node:path";
8461
8614
  function createGlobTool(ctx) {
8462
8615
  return tool8({
8463
8616
  description: "Find files matching a glob pattern.",
@@ -8466,7 +8619,7 @@ function createGlobTool(ctx) {
8466
8619
  path: z10.string().optional().describe("Subdirectory relative to workspace")
8467
8620
  }),
8468
8621
  execute: async ({ pattern, path: path2 }) => {
8469
- const searchDir = path2 ? resolve11(ctx.workspace, path2) : ctx.workspace;
8622
+ const searchDir = path2 ? resolve13(ctx.workspace, path2) : ctx.workspace;
8470
8623
  try {
8471
8624
  const stdout = execFileSync2(
8472
8625
  "find",
@@ -8492,7 +8645,7 @@ function createGlobTool(ctx) {
8492
8645
  // opencode/tools/web.ts
8493
8646
  import { tool as tool9 } from "ai";
8494
8647
  import { z as z11 } from "zod";
8495
- function createWebTool(_ctx) {
8648
+ function createWebTool(_ctx2) {
8496
8649
  return tool9({
8497
8650
  description: "Fetch a URL and return the content as text.",
8498
8651
  inputSchema: z11.object({
@@ -8528,7 +8681,7 @@ function createQuestionTool(ctx) {
8528
8681
  options: z12.array(z12.string()).optional().describe("Optional multiple choice options")
8529
8682
  }),
8530
8683
  execute: async ({ question, options }, { toolCallId }) => {
8531
- return new Promise((resolve14, reject) => {
8684
+ return new Promise((resolve16, reject) => {
8532
8685
  const timeout = setTimeout(() => {
8533
8686
  ctx.pendingQuestions.delete(toolCallId);
8534
8687
  reject(new Error("Question timed out"));
@@ -8536,7 +8689,7 @@ function createQuestionTool(ctx) {
8536
8689
  ctx.pendingQuestions.set(toolCallId, {
8537
8690
  resolve: (answer) => {
8538
8691
  clearTimeout(timeout);
8539
- resolve14(answer);
8692
+ resolve16(answer);
8540
8693
  },
8541
8694
  reject: (err) => {
8542
8695
  clearTimeout(timeout);
@@ -8857,7 +9010,7 @@ function createWSHandler2(deps) {
8857
9010
  clients2.delete(ws);
8858
9011
  }
8859
9012
  },
8860
- error(ws, _ctx, _err) {
9013
+ error(ws, _ctx2, _err) {
8861
9014
  const client = clients2.get(ws);
8862
9015
  if (client) {
8863
9016
  client.abortController?.abort();
@@ -8870,7 +9023,7 @@ function createWSHandler2(deps) {
8870
9023
  // opencode/skills.ts
8871
9024
  import { readFile, glob } from "node:fs/promises";
8872
9025
  import { homedir } from "node:os";
8873
- import { resolve as resolve12 } from "node:path";
9026
+ import { resolve as resolve14 } from "node:path";
8874
9027
  import { parse as parseYaml } from "yaml";
8875
9028
  var SEARCH_DIRS = [
8876
9029
  (ws) => `${ws}/.opencode/skills`,
@@ -8908,7 +9061,7 @@ async function scanDir(dir) {
8908
9061
  try {
8909
9062
  const files = [];
8910
9063
  for await (const entry of glob("*/SKILL.md", { cwd: dir })) {
8911
- const skill = await parseSkillFile(resolve12(dir, entry));
9064
+ const skill = await parseSkillFile(resolve14(dir, entry));
8912
9065
  if (skill) files.push(skill);
8913
9066
  }
8914
9067
  return files;
@@ -9335,7 +9488,7 @@ function theme(options) {
9335
9488
 
9336
9489
  // i18n.ts
9337
9490
  import { readFile as readFile2, stat as stat2 } from "node:fs/promises";
9338
- import { join as join7, resolve as resolve13 } from "node:path";
9491
+ import { join as join7, resolve as resolve15 } from "node:path";
9339
9492
  var DEFAULTS2 = {
9340
9493
  default: "en",
9341
9494
  cookie: "locale",
@@ -9353,7 +9506,7 @@ function translate(msgs, key, params, fallback) {
9353
9506
  }
9354
9507
  function i18n(options) {
9355
9508
  const opts = { ...DEFAULTS2, ...options };
9356
- const dir = opts.dir ? resolve13(opts.dir) : void 0;
9509
+ const dir = opts.dir ? resolve15(opts.dir) : void 0;
9357
9510
  const cache3 = /* @__PURE__ */ new Map();
9358
9511
  function validLocale(locale) {
9359
9512
  return /^[\w-]+$/.test(locale) && !locale.includes("..");
@@ -10245,7 +10398,7 @@ function createWsHandler(deps) {
10245
10398
  return wsToWorkerId.get(ws) || "";
10246
10399
  }
10247
10400
  return {
10248
- open(_ws, _ctx) {
10401
+ open(_ws, _ctx2) {
10249
10402
  },
10250
10403
  async message(ws, ctx, data) {
10251
10404
  let msg;
@@ -10447,12 +10600,12 @@ function iii(opts = {}) {
10447
10600
  const handler = async (payload) => {
10448
10601
  if (!worker.ws) throw new Error(`Worker "${worker.name}" disconnected`);
10449
10602
  const invocationId = crypto8.randomUUID();
10450
- return new Promise((resolve14, reject) => {
10603
+ return new Promise((resolve16, reject) => {
10451
10604
  const timer = setTimeout(() => {
10452
10605
  pending.delete(invocationId);
10453
10606
  reject(new Error(`Invocation timed out for "${id2}"`));
10454
10607
  }, 3e4);
10455
- pending.set(invocationId, { resolve: resolve14, reject, timer });
10608
+ pending.set(invocationId, { resolve: resolve16, reject, timer });
10456
10609
  worker.ws.send(
10457
10610
  JSON.stringify({
10458
10611
  type: "invoke",
@@ -10703,8 +10856,8 @@ function registerWorker(url) {
10703
10856
  function connect() {
10704
10857
  if (intentionalClose) return;
10705
10858
  ws = new WebSocket(url);
10706
- ready = new Promise((resolve14) => {
10707
- resolveReady = resolve14;
10859
+ ready = new Promise((resolve16) => {
10860
+ resolveReady = resolve16;
10708
10861
  });
10709
10862
  ws.onopen = () => {
10710
10863
  reconnectAttempt = 0;
@@ -10835,13 +10988,13 @@ function registerWorker(url) {
10835
10988
  }
10836
10989
  return Promise.resolve(fn(request.payload, ctx));
10837
10990
  }
10838
- return new Promise((resolve14, reject) => {
10991
+ return new Promise((resolve16, reject) => {
10839
10992
  const invocationId = genId();
10840
10993
  const timer = setTimeout(() => {
10841
10994
  pendingInvocations.delete(invocationId);
10842
10995
  reject(new Error(`Invocation timed out for "${request.function_id}"`));
10843
10996
  }, request.timeout_ms || 3e4);
10844
- pendingInvocations.set(invocationId, { resolve: resolve14, reject, timer });
10997
+ pendingInvocations.set(invocationId, { resolve: resolve16, reject, timer });
10845
10998
  send({
10846
10999
  type: "invoke",
10847
11000
  invocation_id: invocationId,