weifuwu 0.18.1 → 0.18.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
@@ -270,6 +270,8 @@ var Router = class _Router {
270
270
  }
271
271
  node.pathMws.push(arg2);
272
272
  }
273
+ } else if (arg1 instanceof _Router) {
274
+ this._mountRouter("/", arg1);
273
275
  } else if (typeof arg1 === "function") {
274
276
  this.globalMws.push(arg1);
275
277
  }
@@ -304,6 +306,11 @@ var Router = class _Router {
304
306
  return this;
305
307
  }
306
308
  route(method, path2, ...args) {
309
+ const last = args[args.length - 1];
310
+ if (last instanceof _Router) {
311
+ this._mountRouter(path2, last);
312
+ return this;
313
+ }
307
314
  const handler = args.pop();
308
315
  const middlewares = args;
309
316
  const segments = this.splitPath(path2);
@@ -369,13 +376,13 @@ var Router = class _Router {
369
376
  const mw = match.middlewares[index++];
370
377
  return mw(innerReq, ctx2, dispatch);
371
378
  }
372
- return await new Promise((resolve11) => {
379
+ return await new Promise((resolve12) => {
373
380
  try {
374
381
  upgradeSocket(router.wss, req, socket, head, match.handler, ctx2);
375
- resolve11(new Response(null, { status: 101 }));
382
+ resolve12(new Response(null, { status: 101 }));
376
383
  } catch {
377
384
  socket.destroy();
378
- resolve11(new Response("WebSocket upgrade failed", { status: 500 }));
385
+ resolve12(new Response("WebSocket upgrade failed", { status: 500 }));
379
386
  }
380
387
  });
381
388
  };
@@ -561,19 +568,6 @@ function sendHttpResponseOnSocket(socket, response) {
561
568
  });
562
569
  }
563
570
 
564
- // tsx-instance.ts
565
- import { createElement } from "react";
566
- import { renderToReadableStream } from "react-dom/server";
567
- import * as esbuild from "esbuild";
568
- import { readdirSync, statSync, existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "node:fs";
569
- import { join, relative, resolve as resolve2, sep, dirname, basename } from "node:path";
570
- import { pathToFileURL } from "node:url";
571
- import { createHash } from "node:crypto";
572
- import vm from "node:vm";
573
- import { createRequire } from "node:module";
574
- import { AsyncLocalStorage } from "node:async_hooks";
575
- import chokidar from "chokidar";
576
-
577
571
  // tsx-context.ts
578
572
  import { createContext } from "react";
579
573
  var DEFAULT_CTX = { params: {}, query: {}, parsed: {}, prefs: {}, loaderData: {}, env: {}, user: {} };
@@ -604,845 +598,6 @@ function setCtx(value) {
604
598
  }
605
599
  var TsxContext = createContext(DEFAULT_CTX);
606
600
 
607
- // tsx-instance.ts
608
- var als = new AsyncLocalStorage();
609
- __registerAls(() => als.getStore());
610
- var liveReloadClients = /* @__PURE__ */ new Set();
611
- function broadcastReload() {
612
- for (const ws of liveReloadClients) {
613
- try {
614
- ws.send("reload");
615
- } catch {
616
- liveReloadClients.delete(ws);
617
- }
618
- }
619
- }
620
- var isDev = process.env.NODE_ENV !== "production";
621
- var _tailwindPlugin = null;
622
- var _postcss = null;
623
- var _cjsRequire = createRequire(import.meta.url);
624
- function loadSSRModule(code) {
625
- const ctx = vm.createContext(Object.create(globalThis));
626
- const mod = { exports: {} };
627
- ctx.require = (name) => _cjsRequire(name);
628
- ctx.module = mod;
629
- ctx.exports = mod.exports;
630
- new vm.Script(code).runInContext(ctx);
631
- return mod.exports;
632
- }
633
- function id(s) {
634
- return createHash("md5").update(s).digest("hex").slice(0, 8);
635
- }
636
- var _alias = null;
637
- function resolveAliases() {
638
- if (_alias) return _alias;
639
- const configFiles = ["tsconfig.json", "jsconfig.json"];
640
- for (const file of configFiles) {
641
- const p = resolve2(file);
642
- if (existsSync2(p)) {
643
- try {
644
- const config = JSON.parse(readFileSync2(p, "utf-8"));
645
- const paths = config.compilerOptions?.paths;
646
- if (paths) {
647
- const alias = {};
648
- for (const [key, values] of Object.entries(paths)) {
649
- const cleanKey = key.replace("/*", "");
650
- const val = values[0]?.replace("/*", "");
651
- if (val) alias[cleanKey] = resolve2(dirname(p), val);
652
- }
653
- _alias = alias;
654
- return alias;
655
- }
656
- } catch {
657
- }
658
- }
659
- }
660
- _alias = {};
661
- return {};
662
- }
663
- function scanPages(dir) {
664
- const pages = [];
665
- function walk(current) {
666
- let entries;
667
- try {
668
- entries = readdirSync(current);
669
- } catch {
670
- return;
671
- }
672
- const dirs = [];
673
- for (const name of entries) {
674
- const full = join(current, name);
675
- const st = statSync(full);
676
- if (st.isDirectory()) {
677
- if (!name.startsWith(".")) dirs.push(full);
678
- }
679
- }
680
- const pagePath = join(current, "page.tsx");
681
- const tsPagePath = join(current, "page.ts");
682
- let entryPath = "";
683
- if (existsSync2(pagePath)) {
684
- entryPath = pagePath;
685
- } else if (existsSync2(tsPagePath)) {
686
- entryPath = tsPagePath;
687
- }
688
- if (entryPath) {
689
- let relPath = relative(dir, entryPath).replace(sep, "/");
690
- relPath = relPath.replace(/\/page\.tsx?$/, "");
691
- relPath = relPath.replace(/^page\.tsx?$/, "");
692
- const route = filePathToRoute(relPath);
693
- const layouts = resolveLayouts(current, dir);
694
- const loadPath = existsSync2(join(current, "load.ts")) ? join(current, "load.ts") : void 0;
695
- const rPath = existsSync2(join(current, "route.ts")) ? join(current, "route.ts") : void 0;
696
- pages.push({
697
- route,
698
- entryPath,
699
- loadPath,
700
- layouts,
701
- routePath: rPath
702
- });
703
- } else {
704
- const rPath = join(current, "route.ts");
705
- if (existsSync2(rPath)) {
706
- let relPath = relative(dir, rPath).replace(sep, "/");
707
- relPath = relPath.replace(/\/route\.tsx?$/, "");
708
- const route = filePathToRoute(relPath);
709
- pages.push({
710
- route,
711
- entryPath: "",
712
- layouts: [],
713
- routePath: rPath,
714
- routeOnly: true
715
- });
716
- }
717
- }
718
- for (const d of dirs) walk(d);
719
- }
720
- walk(dir);
721
- return pages;
722
- }
723
- function filePathToRoute(relPath) {
724
- let route = relPath.replace(/\\/g, "/");
725
- route = route.replace(/\[\.\.\.(\w+)\]/g, "*");
726
- route = route.replace(/\[(\w+)\]/g, ":$1");
727
- return route.startsWith("/") ? route : "/" + route;
728
- }
729
- function resolveLayouts(dir, pagesDir) {
730
- const layouts = [];
731
- let current = dir;
732
- while (current.startsWith(pagesDir)) {
733
- const p = join(current, "layout.tsx");
734
- if (existsSync2(p)) {
735
- layouts.push(p);
736
- }
737
- const parent = dirname(current);
738
- if (parent === current) break;
739
- current = parent;
740
- }
741
- return layouts.reverse();
742
- }
743
- async function compileAll(files, outDir, platform, alias) {
744
- const entryPoints = {};
745
- for (const f of files) {
746
- entryPoints[id(f)] = f;
747
- }
748
- const isBrowser = platform === "browser";
749
- await esbuild.build({
750
- entryPoints,
751
- outdir: outDir,
752
- format: "esm",
753
- platform: "node",
754
- jsx: "automatic",
755
- jsxImportSource: "react",
756
- bundle: true,
757
- external: isBrowser ? void 0 : [
758
- "react",
759
- "react-dom",
760
- "esbuild",
761
- "graphql",
762
- "ws",
763
- "zod",
764
- "@graphql-tools/schema",
765
- "ai"
766
- ],
767
- write: true,
768
- alias,
769
- allowOverwrite: true
770
- });
771
- }
772
- function compiledUrl(filePath, outDir) {
773
- const hash = id(join(outDir, id(filePath)));
774
- const p = join(outDir, id(filePath) + ".js");
775
- return pathToFileURL(p).href;
776
- }
777
- var TsxInstance = class {
778
- uiDir;
779
- pagesDir;
780
- outDir;
781
- router;
782
- pageModules = /* @__PURE__ */ new Map();
783
- layoutModules = /* @__PURE__ */ new Map();
784
- loadModules = /* @__PURE__ */ new Map();
785
- routeModules = /* @__PURE__ */ new Map();
786
- allFiles = [];
787
- nodeEntries = {};
788
- compiledTailwindCss = "";
789
- // client bundle cache (per-instance)
790
- clientBundleCache = /* @__PURE__ */ new Map();
791
- clientBuildParams = /* @__PURE__ */ new Map();
792
- clientRouteLog = /* @__PURE__ */ new Set();
793
- // file watchers (dev mode, stored for cleanup)
794
- watcher = null;
795
- twWatcher = null;
796
- debounceTimer = null;
797
- constructor(options) {
798
- this.uiDir = resolve2(options.dir);
799
- this.pagesDir = existsSync2(join(this.uiDir, "pages")) ? join(this.uiDir, "pages") : this.uiDir;
800
- this.outDir = join(this.uiDir, ".weifuwu", "ssr");
801
- this.router = new Router();
802
- }
803
- async build() {
804
- const pages = scanPages(this.pagesDir);
805
- if (pages.length === 0) return attachStop(this.router, this);
806
- const allFiles = /* @__PURE__ */ new Set();
807
- for (const p of pages) {
808
- if (p.entryPath) allFiles.add(p.entryPath);
809
- if (p.loadPath) allFiles.add(p.loadPath);
810
- for (const lp of p.layouts) allFiles.add(lp);
811
- if (p.routePath) allFiles.add(p.routePath);
812
- }
813
- const nfPath = join(this.pagesDir, "not-found.tsx");
814
- const hasNotFound = existsSync2(nfPath);
815
- if (hasNotFound) {
816
- allFiles.add(nfPath);
817
- const rootLayouts = resolveLayouts(this.pagesDir, this.pagesDir);
818
- for (const lp of rootLayouts) allFiles.add(lp);
819
- }
820
- mkdirSync(this.outDir, { recursive: true });
821
- this.allFiles = [...allFiles];
822
- await compileAll(this.allFiles, this.outDir, "node", resolveAliases());
823
- const methods = ["POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"];
824
- for (const p of pages) {
825
- const nodeKey = p.entryPath || p.routePath || "";
826
- this.nodeEntries[nodeKey] = { route: p.route, entryPath: p.entryPath || "", layouts: p.layouts, loadPath: p.loadPath, routePath: p.routePath };
827
- if (p.routeOnly && p.routePath) {
828
- const rUrl = compiledUrl(p.routePath, this.outDir);
829
- const modR = await import(rUrl);
830
- const handlers = /* @__PURE__ */ new Map();
831
- for (const m of ["GET", ...methods]) {
832
- if (modR[m]) handlers.set(m, modR[m]);
833
- }
834
- this.routeModules.set(p.routePath, handlers);
835
- this.router.route(
836
- "GET",
837
- p.route,
838
- (req, ctx) => this.routeModules.get(p.routePath)?.get("GET")?.(req, ctx) ?? new Response("", { status: 501 })
839
- );
840
- for (const m of methods) {
841
- this.router.route(
842
- m,
843
- p.route,
844
- (req, ctx) => this.routeModules.get(p.routePath)?.get(m)?.(req, ctx) ?? new Response("", { status: 501 })
845
- );
846
- }
847
- continue;
848
- }
849
- const pageUrl = compiledUrl(p.entryPath, this.outDir);
850
- this.pageModules.set(p.entryPath, await import(pageUrl));
851
- if (p.loadPath) {
852
- const loadUrl = compiledUrl(p.loadPath, this.outDir);
853
- this.loadModules.set(p.loadPath, await import(loadUrl));
854
- }
855
- for (const lp of p.layouts) {
856
- const lUrl = compiledUrl(lp, this.outDir);
857
- this.layoutModules.set(lp, await import(lUrl));
858
- }
859
- if (p.routePath) {
860
- const rUrl = compiledUrl(p.routePath, this.outDir);
861
- const modR = await import(rUrl);
862
- const handlers = /* @__PURE__ */ new Map();
863
- for (const m of methods) {
864
- if (modR[m]) handlers.set(m, modR[m]);
865
- }
866
- this.routeModules.set(p.routePath, handlers);
867
- }
868
- const handler = this.makeSsrHandler(p.entryPath, p.layouts, p.loadPath);
869
- this.router.get(p.route, handler);
870
- if (p.routePath) {
871
- for (const m of methods) {
872
- this.router.route(
873
- m,
874
- p.route,
875
- (req, ctx) => this.routeModules.get(p.routePath)?.get(m)?.(req, ctx) ?? new Response("", { status: 501 })
876
- );
877
- }
878
- }
879
- }
880
- if (hasNotFound) {
881
- const nfUrl = compiledUrl(nfPath, this.outDir);
882
- this.pageModules.set(nfPath, await import(nfUrl));
883
- const rootLayouts = resolveLayouts(this.pagesDir, this.pagesDir);
884
- for (const lp of rootLayouts) {
885
- if (!this.layoutModules.has(lp)) {
886
- const lUrl = compiledUrl(lp, this.outDir);
887
- this.layoutModules.set(lp, await import(lUrl));
888
- }
889
- }
890
- const handler = async (req, ctx) => {
891
- const base = (ctx.mountPath || "").replace(/\/$/, "");
892
- const nfMod = this.pageModules.get(nfPath);
893
- if (!nfMod) return new Response("Not Found", { status: 404 });
894
- const NfComponent = nfMod.default;
895
- const ctxValue = {
896
- params: ctx.params,
897
- query: ctx.query,
898
- user: ctx.user ?? {},
899
- parsed: ctx.parsed ?? {},
900
- prefs: ctx.prefs ?? {},
901
- loaderData: {},
902
- env: ctx.env ?? {}
903
- };
904
- return als.run(ctxValue, async () => {
905
- setCtx(ctxValue);
906
- let element = createElement(
907
- TsxContext.Provider,
908
- { value: ctxValue },
909
- createElement(NfComponent, { params: ctx.params, query: ctx.query })
910
- );
911
- for (let i = rootLayouts.length - 1; i >= 0; i--) {
912
- const LMod = this.layoutModules.get(rootLayouts[i]);
913
- if (!LMod) continue;
914
- element = createElement(LMod.default, { children: element });
915
- }
916
- const stream = await renderToReadableStream(element);
917
- return streamResponse(stream, {
918
- ctx,
919
- base,
920
- compiledTailwindCss: this.compiledTailwindCss,
921
- isDev,
922
- status: 404
923
- });
924
- });
925
- };
926
- this.router.all("/*", handler);
927
- }
928
- for (const p of pages) {
929
- if (p.entryPath) {
930
- const rootLayouts = resolveLayouts(this.pagesDir, this.pagesDir);
931
- this.registerClientBundleRoute(p.entryPath, p.layouts.length > 0 ? p.layouts : rootLayouts, this.pagesDir);
932
- }
933
- }
934
- await this.setupTailwind();
935
- if (isDev) {
936
- this.router.ws("/__weifuwu/livereload", {
937
- open: (ws) => {
938
- liveReloadClients.add(ws);
939
- ws.on("close", () => liveReloadClients.delete(ws));
940
- ws.on("error", () => liveReloadClients.delete(ws));
941
- }
942
- });
943
- this.startFileWatcher();
944
- }
945
- return attachStop(this.router, this);
946
- }
947
- /**
948
- * Clean up file watchers and pending timers. Call when shutting down
949
- * to prevent resource leaks.
950
- */
951
- stop() {
952
- this.watcher?.close();
953
- this.twWatcher?.close();
954
- if (this.debounceTimer) clearTimeout(this.debounceTimer);
955
- this.debounceTimer = null;
956
- }
957
- // ── Tailwind CSS ──────────────────────────────────────────────────────────
958
- async compileTailwind() {
959
- if (this.compiledTailwindCss) return this.compiledTailwindCss;
960
- try {
961
- _tailwindPlugin ??= (await import("@tailwindcss/postcss")).default;
962
- _postcss ??= (await import("postcss")).default;
963
- } catch {
964
- return "";
965
- }
966
- const inputFile = resolve2(this.uiDir, "app.css");
967
- if (!existsSync2(inputFile)) {
968
- mkdirSync(this.uiDir, { recursive: true });
969
- writeFileSync(inputFile, '@import "tailwindcss"\n', "utf-8");
970
- console.log("\u2139 weifuwu/tsx: created " + relative(process.cwd(), inputFile));
971
- }
972
- try {
973
- let src = readFileSync2(inputFile, "utf-8");
974
- const sourceRel = relative(this.uiDir, this.pagesDir) || ".";
975
- const sourcePath = sourceRel === "." ? "./" : `./${sourceRel}/`;
976
- src = `@source "${sourcePath}";
977
- ${src}`;
978
- const result = await _postcss([_tailwindPlugin()]).process(src, { from: inputFile });
979
- this.compiledTailwindCss = result.css;
980
- } catch (err) {
981
- console.warn("Tailwind CSS processing failed:", err.message);
982
- }
983
- return this.compiledTailwindCss;
984
- }
985
- async setupTailwind() {
986
- await this.compileTailwind();
987
- this.router.get("/__wfw/style.css", () => new Response(this.compiledTailwindCss || "", {
988
- headers: { "content-type": "text/css; charset=utf-8" }
989
- }));
990
- if (isDev) {
991
- const inputFile = resolve2(this.uiDir, "app.css");
992
- this.twWatcher = chokidar.watch(inputFile, { persistent: false });
993
- this.twWatcher.on("change", async () => {
994
- this.compiledTailwindCss = "";
995
- await this.compileTailwind();
996
- broadcastReload();
997
- });
998
- }
999
- }
1000
- // ── client bundle ─────────────────────────────────────────────────────────
1001
- async buildClientBundle(entryPath, layoutPaths, pagesDir) {
1002
- try {
1003
- const layoutImports = layoutPaths.map((p) => `import${JSON.stringify(p)};`).join("");
1004
- const _sc = `(function(){var k='__WEIFUWU_CTX_STORE';var s=typeof globalThis!='undefined'&&globalThis[k];if(!s)return function(){};return function(v){s._ctx={...s._ctx,...v};s._snapshot={params:s._ctx.params,query:s._ctx.query,user:s._ctx.user,parsed:s._ctx.parsed,prefs:s._ctx.prefs,env:s._ctx.env};s._listeners.forEach(function(fn){fn()})}})()`;
1005
- const code = [
1006
- layoutImports,
1007
- `import{hydrateRoot}from'react-dom/client';`,
1008
- `import{createElement,useState,useEffect}from'react';`,
1009
- `import{TsxContext}from'weifuwu/react';`,
1010
- `import P from${JSON.stringify(entryPath)};`,
1011
- `var setCtx=${_sc};`,
1012
- `const c=document.getElementById('__weifuwu_root');`,
1013
- `if(window.__WEIFUWU_PROPS)setCtx({loaderData:window.__WEIFUWU_PROPS});`,
1014
- `if(!window.__WFW_ROOT){`,
1015
- `function App(){`,
1016
- `const[p,setP]=useState({C:P});`,
1017
- `useEffect(()=>{window.__WFW_SET_PAGE=(C)=>{setCtx({loaderData:window.__WEIFUWU_PROPS});setP({C})}},[]);`,
1018
- `const ctx=window.__WEIFUWU_CTX||{};`,
1019
- `return createElement(TsxContext.Provider,{value:ctx},`,
1020
- `createElement(p.C,null))`,
1021
- `}`,
1022
- `window.__WFW_ROOT=hydrateRoot(c,createElement(App));`,
1023
- `}else{`,
1024
- `window.__WFW_SET_PAGE?.(P);`,
1025
- `}`
1026
- ].join("");
1027
- const publicEnv = {};
1028
- for (const key of Object.keys(process.env)) {
1029
- if (key.startsWith("WEIFUWU_PUBLIC_")) {
1030
- publicEnv[`process.env.${key}`] = JSON.stringify(process.env[key]);
1031
- }
1032
- }
1033
- const result = await esbuild.build({
1034
- stdin: { contents: code, loader: "tsx", resolveDir: pagesDir },
1035
- bundle: true,
1036
- format: "esm",
1037
- jsx: "automatic",
1038
- jsxImportSource: "react",
1039
- alias: resolveAliases(),
1040
- banner: { js: "self.process={env:{}};" },
1041
- define: Object.keys(publicEnv).length > 0 ? publicEnv : void 0,
1042
- loader: { ".node": "empty" },
1043
- write: false,
1044
- minify: true
1045
- });
1046
- return result.outputFiles[0].contents;
1047
- } catch (err) {
1048
- console.error("hydration bundle failed:", err);
1049
- return null;
1050
- }
1051
- }
1052
- async getOrBuildClientBundle(entryPath, layoutPaths, pagesDir) {
1053
- const key = id(entryPath);
1054
- const url = `/__wfw/client/${key}.js`;
1055
- this.clientBuildParams.set(key, { entryPath, layoutPaths, pagesDir });
1056
- if (!this.clientBundleCache.has(key)) {
1057
- const buf = await this.buildClientBundle(entryPath, layoutPaths, pagesDir);
1058
- if (!buf) return null;
1059
- this.clientBundleCache.set(key, buf);
1060
- }
1061
- return { url };
1062
- }
1063
- registerClientBundleRoute(entryPath, layoutPaths, pagesDir) {
1064
- const key = id(entryPath);
1065
- const url = `/__wfw/client/${key}.js`;
1066
- this.clientBuildParams.set(key, { entryPath, layoutPaths, pagesDir });
1067
- if (!this.clientRouteLog.has(url)) {
1068
- this.router.get(url, async () => {
1069
- let buf = this.clientBundleCache.get(key);
1070
- if (!buf) {
1071
- const params = this.clientBuildParams.get(key);
1072
- if (params) {
1073
- const rebuilt = await this.buildClientBundle(params.entryPath, params.layoutPaths, params.pagesDir);
1074
- if (rebuilt) {
1075
- this.clientBundleCache.set(key, rebuilt);
1076
- buf = rebuilt;
1077
- }
1078
- }
1079
- }
1080
- return buf ? new Response(buf, {
1081
- headers: { "content-type": "application/javascript; charset=utf-8" }
1082
- }) : new Response("", { status: 500 });
1083
- });
1084
- this.clientRouteLog.add(url);
1085
- }
1086
- }
1087
- // ── SSR handler ───────────────────────────────────────────────────────────
1088
- makeSsrHandler(entryPath, layoutPaths, loadPath) {
1089
- return async (req, ctx) => {
1090
- const base = (ctx.mountPath || "").replace(/\/$/, "");
1091
- const pageMod = this.pageModules.get(entryPath);
1092
- if (!pageMod) return new Response("", { status: 500 });
1093
- const Component = pageMod.default;
1094
- const loadMod = loadPath ? this.loadModules.get(loadPath) : void 0;
1095
- const loadFn = loadMod?.default;
1096
- const loadProps = loadFn ? await loadFn({ params: ctx.params, query: ctx.query }) : {};
1097
- const ctxValue = {
1098
- params: ctx.params,
1099
- query: ctx.query,
1100
- user: ctx.user ?? {},
1101
- parsed: ctx.parsed ?? {},
1102
- prefs: ctx.prefs ?? {},
1103
- loaderData: loadProps,
1104
- env: ctx.env ?? {}
1105
- };
1106
- return als.run(ctxValue, async () => {
1107
- setCtx(ctxValue);
1108
- let element = createElement(
1109
- TsxContext.Provider,
1110
- { value: ctxValue },
1111
- createElement(
1112
- "div",
1113
- { id: "__weifuwu_root" },
1114
- createElement(Component, null)
1115
- )
1116
- );
1117
- if (layoutPaths.length === 0) {
1118
- element = createElement(
1119
- "html",
1120
- { lang: "en" },
1121
- createElement(
1122
- "head",
1123
- null,
1124
- createElement("meta", { charSet: "utf-8" }),
1125
- createElement("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
1126
- createElement("title", null, "weifuwu")
1127
- ),
1128
- createElement("body", null, element)
1129
- );
1130
- } else {
1131
- for (let i = layoutPaths.length - 1; i >= 0; i--) {
1132
- const lp = layoutPaths[i];
1133
- const LMod = this.layoutModules.get(lp);
1134
- if (!LMod) continue;
1135
- const Layout = LMod.default;
1136
- const isRoot = i === 0;
1137
- element = createElement(
1138
- Layout,
1139
- { children: element }
1140
- );
1141
- }
1142
- }
1143
- const bundle = await this.getOrBuildClientBundle(entryPath, layoutPaths, this.pagesDir);
1144
- const stream = await renderToReadableStream(element);
1145
- return streamResponse(stream, {
1146
- ctx,
1147
- base,
1148
- compiledTailwindCss: this.compiledTailwindCss,
1149
- isDev,
1150
- bundle,
1151
- loaderData: loadProps
1152
- });
1153
- });
1154
- };
1155
- }
1156
- // ── dev file watcher ──────────────────────────────────────────────────────
1157
- startFileWatcher() {
1158
- const pending = /* @__PURE__ */ new Set();
1159
- this.watcher = chokidar.watch(this.uiDir, {
1160
- ignored: /(^|[/\\])\.(?!\.)|node_modules|[/\\]\.weifuwu[/\\]|[/\\]dist[/\\]/,
1161
- persistent: false,
1162
- ignoreInitial: true
1163
- });
1164
- this.watcher.on("all", async (event, filePath) => {
1165
- if (event !== "change" && event !== "add") return;
1166
- if (!/\.tsx?$/.test(filePath)) return;
1167
- pending.add(filePath);
1168
- if (this.debounceTimer) clearTimeout(this.debounceTimer);
1169
- this.debounceTimer = setTimeout(async () => {
1170
- this.debounceTimer = null;
1171
- const files = [...pending];
1172
- pending.clear();
1173
- const exists = files.filter((f) => existsSync2(f));
1174
- const allKnown = exists.every(
1175
- (f) => this.pageModules.has(f) || this.layoutModules.has(f) || this.loadModules.has(f) || this.routeModules.has(f)
1176
- );
1177
- if (allKnown) {
1178
- for (const f of exists) await this.recompileAndSwap(f);
1179
- this.compiledTailwindCss = "";
1180
- await this.compileTailwind();
1181
- broadcastReload();
1182
- } else {
1183
- await this.recompileAll();
1184
- }
1185
- }, 50);
1186
- });
1187
- }
1188
- async recompileAndSwap(filePath) {
1189
- try {
1190
- const result = await esbuild.build({
1191
- entryPoints: { [id(filePath)]: filePath },
1192
- outdir: this.outDir,
1193
- format: "cjs",
1194
- platform: "node",
1195
- jsx: "automatic",
1196
- jsxImportSource: "react",
1197
- bundle: true,
1198
- external: ["react", "react-dom", "esbuild", "graphql", "ws", "zod", "@graphql-tools/schema", "ai"],
1199
- alias: resolveAliases(),
1200
- write: false
1201
- });
1202
- const code = new TextDecoder().decode(result.outputFiles[0].contents);
1203
- const mod = loadSSRModule(code);
1204
- const name = basename(filePath);
1205
- if (name === "layout.tsx") {
1206
- this.layoutModules.set(filePath, mod);
1207
- this.clientBundleCache.clear();
1208
- } else if (name === "route.ts") {
1209
- const handlers = /* @__PURE__ */ new Map();
1210
- for (const m of ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]) {
1211
- if (mod[m]) handlers.set(m, mod[m]);
1212
- }
1213
- this.routeModules.set(filePath, handlers);
1214
- } else if (name === "load.ts") {
1215
- this.loadModules.set(filePath, mod);
1216
- } else {
1217
- this.pageModules.set(filePath, mod);
1218
- this.clientBundleCache.delete(id(filePath));
1219
- }
1220
- } catch (err) {
1221
- console.error("recompile failed:", err.message);
1222
- }
1223
- }
1224
- async recompileAll() {
1225
- try {
1226
- const freshPages = scanPages(this.pagesDir);
1227
- const freshFiles = /* @__PURE__ */ new Set();
1228
- const nodeEntries = {};
1229
- for (const p of freshPages) {
1230
- const nodeKey = p.entryPath || p.routePath || "";
1231
- nodeEntries[nodeKey] = { route: p.route, entryPath: p.entryPath, layouts: p.layouts, loadPath: p.loadPath, routePath: p.routePath };
1232
- if (p.entryPath) freshFiles.add(p.entryPath);
1233
- if (p.loadPath) freshFiles.add(p.loadPath);
1234
- for (const lp of p.layouts) freshFiles.add(lp);
1235
- if (p.routePath) freshFiles.add(p.routePath);
1236
- }
1237
- const nfPath = join(this.pagesDir, "not-found.tsx");
1238
- if (existsSync2(nfPath)) {
1239
- freshFiles.add(nfPath);
1240
- const rootLayouts = resolveLayouts(this.pagesDir, this.pagesDir);
1241
- for (const lp of rootLayouts) freshFiles.add(lp);
1242
- }
1243
- this.allFiles = [...freshFiles];
1244
- const result = await esbuild.build({
1245
- entryPoints: Object.fromEntries(this.allFiles.map((f) => [id(f), f])),
1246
- outdir: this.outDir,
1247
- format: "cjs",
1248
- platform: "node",
1249
- jsx: "automatic",
1250
- jsxImportSource: "react",
1251
- bundle: true,
1252
- external: ["react", "react-dom", "esbuild", "graphql", "ws", "zod", "@graphql-tools/schema", "ai"],
1253
- alias: resolveAliases(),
1254
- write: false
1255
- });
1256
- for (const file of result.outputFiles) {
1257
- const code = new TextDecoder().decode(file.contents);
1258
- const mod = loadSSRModule(code);
1259
- const srcPath = this.allFiles.find((f) => file.path.endsWith(id(f) + ".js"));
1260
- if (!srcPath) continue;
1261
- const name = basename(srcPath);
1262
- if (name === "layout.tsx") {
1263
- this.layoutModules.set(srcPath, mod);
1264
- } else if (name === "route.ts") {
1265
- const handlers = /* @__PURE__ */ new Map();
1266
- for (const m of ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]) {
1267
- if (mod[m]) handlers.set(m, mod[m]);
1268
- }
1269
- this.routeModules.set(srcPath, handlers);
1270
- } else if (name === "load.ts") {
1271
- this.loadModules.set(srcPath, mod);
1272
- } else if (name !== "not-found.tsx") {
1273
- this.pageModules.set(srcPath, mod);
1274
- }
1275
- }
1276
- const methods = ["POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"];
1277
- for (const [key, entry] of Object.entries(nodeEntries)) {
1278
- if (this.nodeEntries[key]) continue;
1279
- if (entry.routePath && !entry.entryPath) {
1280
- this.router.route(
1281
- "GET",
1282
- entry.route,
1283
- (req, ctx) => this.routeModules.get(entry.routePath)?.get("GET")?.(req, ctx) ?? new Response("", { status: 501 })
1284
- );
1285
- for (const m of methods) {
1286
- this.router.route(
1287
- m,
1288
- entry.route,
1289
- (req, ctx) => this.routeModules.get(entry.routePath)?.get(m)?.(req, ctx) ?? new Response("", { status: 501 })
1290
- );
1291
- }
1292
- }
1293
- if (entry.entryPath) {
1294
- const handler = this.makeSsrHandler(entry.entryPath, entry.layouts, entry.loadPath);
1295
- this.router.get(entry.route, handler);
1296
- if (entry.routePath) {
1297
- for (const m of methods) {
1298
- this.router.route(
1299
- m,
1300
- entry.route,
1301
- (req, ctx) => this.routeModules.get(entry.routePath)?.get(m)?.(req, ctx) ?? new Response("", { status: 501 })
1302
- );
1303
- }
1304
- }
1305
- }
1306
- console.log("\u2139 weifuwu/tsx: registered new route " + entry.route);
1307
- }
1308
- this.nodeEntries = nodeEntries;
1309
- this.clientBundleCache.clear();
1310
- this.compiledTailwindCss = "";
1311
- await this.compileTailwind();
1312
- broadcastReload();
1313
- } catch (err) {
1314
- console.error("recompile all failed:", err.message);
1315
- }
1316
- }
1317
- };
1318
- function attachStop(router, instance) {
1319
- ;
1320
- router.stop = () => instance.stop();
1321
- return router;
1322
- }
1323
- function streamResponse(reactStream, opts) {
1324
- const decoder = new TextDecoder();
1325
- const encoder2 = new TextEncoder();
1326
- const headPayload = buildHeadPayload(opts);
1327
- let buffer = "";
1328
- let headFlushed = false;
1329
- let extractedHead = "";
1330
- const output = new ReadableStream({
1331
- async start(controller) {
1332
- try {
1333
- const reader = reactStream.getReader();
1334
- async function push(chunk) {
1335
- buffer += decoder.decode(chunk, { stream: true });
1336
- if (!extractedHead) {
1337
- const m = buffer.match(/<template id="__wfw_head">([\s\S]*?)<\/template>/);
1338
- if (m) {
1339
- extractedHead = m[1];
1340
- buffer = buffer.replace(m[0], "");
1341
- }
1342
- }
1343
- if (!headFlushed) {
1344
- const idx = buffer.indexOf("</head>");
1345
- if (idx !== -1) {
1346
- const before = buffer.slice(0, idx);
1347
- let injection = "";
1348
- if (extractedHead) injection += "\n" + extractedHead;
1349
- injection += headPayload;
1350
- controller.enqueue(encoder2.encode(before + injection));
1351
- buffer = buffer.slice(idx);
1352
- headFlushed = true;
1353
- }
1354
- return;
1355
- }
1356
- controller.enqueue(encoder2.encode(buffer));
1357
- buffer = "";
1358
- }
1359
- while (true) {
1360
- const { done, value } = await reader.read();
1361
- if (done) break;
1362
- await push(value);
1363
- }
1364
- buffer = buffer.replace(/<template id="__wfw_head">[\s\S]*?<\/template>/g, "");
1365
- if (buffer) controller.enqueue(encoder2.encode(buffer));
1366
- const body = buildBodyScripts(opts);
1367
- if (body) controller.enqueue(encoder2.encode("\n" + body));
1368
- if (opts.isDev) {
1369
- controller.enqueue(encoder2.encode(
1370
- `
1371
- <script>(function(){var ws=new WebSocket((location.protocol==='https:'?'wss:':'ws:')+'//'+location.host+'${opts.base}/__weifuwu/livereload');ws.onmessage=function(e){if(e.data==='reload')location.reload()};ws.onclose=function(){setTimeout(function(){location.reload()},500)}})()</script>`
1372
- ));
1373
- }
1374
- } catch (err) {
1375
- const fallback = `<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>500</title></head><body><h1>500 - Internal Server Error</h1></body></html>`;
1376
- controller.enqueue(encoder2.encode(fallback));
1377
- } finally {
1378
- controller.close();
1379
- }
1380
- }
1381
- });
1382
- return new Response(output, {
1383
- status: opts.status ?? 200,
1384
- headers: { "content-type": "text/html; charset=utf-8" }
1385
- });
1386
- }
1387
- var _publicEnv = null;
1388
- function getPublicEnv() {
1389
- if (_publicEnv) return _publicEnv;
1390
- _publicEnv = {};
1391
- for (const key of Object.keys(process.env)) {
1392
- if (key.startsWith("WEIFUWU_PUBLIC_")) {
1393
- _publicEnv[key] = process.env[key];
1394
- }
1395
- }
1396
- return _publicEnv;
1397
- }
1398
- function buildHeadPayload(opts) {
1399
- const { ctx, base, compiledTailwindCss } = opts;
1400
- let result = "";
1401
- if (ctx.prefs?.theme) {
1402
- result += `<script>!function(){var t=(document.cookie.match(/(?:^|;\\s*)theme=([^;]+)/)||[])[1]||'system';if(t==='system'){t=window.matchMedia('(prefers-color-scheme:dark)').matches?'dark':'light'}document.documentElement.setAttribute('data-theme',t)}()</script>
1403
- `;
1404
- }
1405
- if (compiledTailwindCss) {
1406
- result += `<link rel="stylesheet" href="${base}/__wfw/style.css" />
1407
- `;
1408
- }
1409
- const localeData = ctx.parsed?.__localeData ?? globalThis.__LOCALE_DATA__;
1410
- if (localeData && Object.keys(localeData).length > 0) {
1411
- result += `<script>window.__LOCALE_DATA__=${JSON.stringify(localeData)}</script>
1412
- `;
1413
- }
1414
- const ctxData = {
1415
- params: ctx.params,
1416
- query: ctx.query,
1417
- user: ctx.user,
1418
- parsed: ctx.parsed,
1419
- prefs: ctx.prefs
1420
- };
1421
- const publicEnv = getPublicEnv();
1422
- if (Object.keys(publicEnv).length > 0) {
1423
- ctxData.env = publicEnv;
1424
- }
1425
- result += `<script>window.__WEIFUWU_CTX=${JSON.stringify(ctxData)}</script>
1426
- `;
1427
- return result;
1428
- }
1429
- function buildBodyScripts(opts) {
1430
- const parts = [];
1431
- if (opts.loaderData && Object.keys(opts.loaderData).length > 0) {
1432
- parts.push(`<script>window.__WEIFUWU_PROPS=${JSON.stringify(opts.loaderData)}</script>`);
1433
- }
1434
- if (opts.bundle) {
1435
- parts.push(`<script type="module" src="${opts.base}${opts.bundle.url}"></script>`);
1436
- }
1437
- return parts.join("\n");
1438
- }
1439
-
1440
- // tsx.ts
1441
- async function tsx(options) {
1442
- const instance = new TsxInstance(options);
1443
- return instance.build();
1444
- }
1445
-
1446
601
  // middleware.ts
1447
602
  function logger(options) {
1448
603
  return async (req, ctx, next) => {
@@ -1598,12 +753,12 @@ function auth(options) {
1598
753
  }
1599
754
 
1600
755
  // static.ts
1601
- import { createHash as createHash2 } from "node:crypto";
756
+ import { createHash } from "node:crypto";
1602
757
  import { open, realpath } from "node:fs/promises";
1603
- import { extname, resolve as resolve3, normalize, sep as sep2 } from "node:path";
758
+ import { extname, resolve as resolve2, normalize, sep } from "node:path";
1604
759
  import { Readable } from "node:stream";
1605
760
  function serveStatic(root, options) {
1606
- const rootDir = resolve3(root);
761
+ const rootDir = resolve2(root);
1607
762
  const opts = options ?? {};
1608
763
  return async (req, ctx) => {
1609
764
  const relativePath = ctx.params["*"] ?? new URL(req.url).pathname.slice(1);
@@ -1611,8 +766,8 @@ function serveStatic(root, options) {
1611
766
  if (decoded.includes("..") || decoded.includes("\0")) {
1612
767
  return new Response("Forbidden", { status: 403 });
1613
768
  }
1614
- let filePath = normalize(resolve3(rootDir, decoded));
1615
- if (!filePath.startsWith(rootDir + sep2) && filePath !== rootDir) {
769
+ let filePath = normalize(resolve2(rootDir, decoded));
770
+ if (!filePath.startsWith(rootDir + sep) && filePath !== rootDir) {
1616
771
  return new Response("Forbidden", { status: 403 });
1617
772
  }
1618
773
  let fileHandle;
@@ -1620,15 +775,15 @@ function serveStatic(root, options) {
1620
775
  fileHandle = await open(filePath, "r");
1621
776
  let stat = await fileHandle.stat();
1622
777
  const realPath = await realpath(filePath);
1623
- if (!realPath.startsWith(rootDir + sep2) && realPath !== rootDir) {
778
+ if (!realPath.startsWith(rootDir + sep) && realPath !== rootDir) {
1624
779
  await fileHandle.close();
1625
780
  return new Response("Forbidden", { status: 403 });
1626
781
  }
1627
782
  if (stat.isDirectory()) {
1628
783
  await fileHandle.close();
1629
784
  const indexFile = opts.index ?? "index.html";
1630
- filePath = resolve3(filePath, indexFile);
1631
- if (!filePath.startsWith(rootDir + sep2)) {
785
+ filePath = resolve2(filePath, indexFile);
786
+ if (!filePath.startsWith(rootDir + sep)) {
1632
787
  return new Response("Forbidden", { status: 403 });
1633
788
  }
1634
789
  fileHandle = await open(filePath, "r");
@@ -1639,7 +794,7 @@ function serveStatic(root, options) {
1639
794
  }
1640
795
  }
1641
796
  const mimeType = MIME_TYPES[extname(filePath).toLowerCase()] ?? "application/octet-stream";
1642
- const etag = `"${createHash2("md5").update(`${stat.size}-${stat.mtimeMs}`).digest("hex")}"`;
797
+ const etag = `"${createHash("md5").update(`${stat.size}-${stat.mtimeMs}`).digest("hex")}"`;
1643
798
  const ifNoneMatch = req.headers.get("if-none-match");
1644
799
  if (ifNoneMatch === etag) {
1645
800
  await fileHandle.close();
@@ -1860,7 +1015,7 @@ function deleteCookie(res, name, options) {
1860
1015
  // upload.ts
1861
1016
  import { writeFile, mkdir } from "node:fs/promises";
1862
1017
  import { randomUUID } from "node:crypto";
1863
- import { join as join2, extname as extname2 } from "node:path";
1018
+ import { join, extname as extname2 } from "node:path";
1864
1019
  var extensionMimeMap = {
1865
1020
  ".jpg": "image/jpeg",
1866
1021
  ".jpeg": "image/jpeg",
@@ -1927,7 +1082,7 @@ function upload(options) {
1927
1082
  };
1928
1083
  if (saveDir) {
1929
1084
  const safeName = value.name.replace(/[/\\\0]/g, "_");
1930
- const filePath = join2(saveDir, `${randomUUID()}-${safeName}`);
1085
+ const filePath = join(saveDir, `${randomUUID()}-${safeName}`);
1931
1086
  await writeFile(filePath, buf);
1932
1087
  uf.path = filePath;
1933
1088
  }
@@ -2117,12 +1272,12 @@ function requestId(options) {
2117
1272
  const gen = options?.generator ?? (() => crypto2.randomUUID());
2118
1273
  return async (req, ctx, next) => {
2119
1274
  const existing = req.headers.get(header);
2120
- const id2 = existing ?? gen();
2121
- ctx.requestId = id2;
1275
+ const id3 = existing ?? gen();
1276
+ ctx.requestId = id3;
2122
1277
  const res = await next(req, ctx);
2123
1278
  if (res.headers.has(header)) return res;
2124
1279
  const h = new Headers(res.headers);
2125
- h.set(header, id2);
1280
+ h.set(header, id3);
2126
1281
  return new Response(res.body, { status: res.status, statusText: res.statusText, headers: h });
2127
1282
  };
2128
1283
  }
@@ -2344,10 +1499,10 @@ function resolveRef(path2, ctx) {
2344
1499
  const after = path2.slice(7);
2345
1500
  const dot = after.indexOf(".");
2346
1501
  if (dot === -1) return ctx.nodeOutputs.get(after);
2347
- const id2 = after.slice(0, dot);
1502
+ const id3 = after.slice(0, dot);
2348
1503
  const propPath = after.slice(dot + 1);
2349
- const output = ctx.nodeOutputs.get(id2);
2350
- if (output === void 0) throw new Error(`Node "${id2}" has no output yet`);
1504
+ const output = ctx.nodeOutputs.get(id3);
1505
+ if (output === void 0) throw new Error(`Node "${id3}" has no output yet`);
2351
1506
  return getByPath(output, propPath.startsWith("output") ? propPath.slice(7).split(".").filter(Boolean) : propPath.split("."));
2352
1507
  }
2353
1508
  if (path2.startsWith("$var.")) {
@@ -2873,18 +2028,18 @@ var Table = class {
2873
2028
  `;
2874
2029
  return rows;
2875
2030
  }
2876
- async read(sql2, id2, opts) {
2031
+ async read(sql2, id3, opts) {
2877
2032
  if (opts?.select?.length) {
2878
2033
  const columns = opts.select.map((c) => `"${c}"`).join(", ");
2879
2034
  const [row2] = await sql2.unsafe(
2880
2035
  `SELECT ${columns} FROM "${this.tableName}" WHERE id = $1 LIMIT 1`,
2881
- [id2]
2036
+ [id3]
2882
2037
  );
2883
2038
  return row2 ?? void 0;
2884
2039
  }
2885
2040
  const [row] = await sql2`
2886
2041
  SELECT * FROM ${sql2(this.tableName)}
2887
- WHERE ${sql2("id")} = ${id2} LIMIT 1
2042
+ WHERE ${sql2("id")} = ${id3} LIMIT 1
2888
2043
  `;
2889
2044
  return row ?? void 0;
2890
2045
  }
@@ -2918,11 +2073,11 @@ var Table = class {
2918
2073
  const rows = await sql2.unsafe(query, values);
2919
2074
  return { count, data: rows };
2920
2075
  }
2921
- async update(sql2, id2, data) {
2076
+ async update(sql2, id3, data) {
2922
2077
  const { sets, values: setValues } = this._buildSET(data);
2923
2078
  if (sets.length === 0) return void 0;
2924
2079
  const query = `UPDATE "${this.tableName}" AS t SET ${sets.join(", ")} FROM (SELECT ctid FROM "${this.tableName}" WHERE id = $${setValues.length + 1} LIMIT 1) AS sub WHERE t.ctid = sub.ctid RETURNING t.*`;
2925
- const rows = await sql2.unsafe(query, [...setValues, id2]);
2080
+ const rows = await sql2.unsafe(query, [...setValues, id3]);
2926
2081
  return rows[0] ?? void 0;
2927
2082
  }
2928
2083
  async updateMany(sql2, where, data) {
@@ -2936,22 +2091,22 @@ var Table = class {
2936
2091
  );
2937
2092
  return rows.length;
2938
2093
  }
2939
- async delete(sql2, id2) {
2094
+ async delete(sql2, id3) {
2940
2095
  if (this.hasColumn("deleted_at")) {
2941
2096
  const [row2] = await sql2.unsafe(
2942
2097
  `UPDATE "${this.tableName}" SET "deleted_at" = NOW() WHERE id = $1 RETURNING *`,
2943
- [id2]
2098
+ [id3]
2944
2099
  );
2945
2100
  return row2 ?? void 0;
2946
2101
  }
2947
2102
  const [row] = await sql2`
2948
- DELETE FROM ${sql2(this.tableName)} WHERE ${sql2("id")} = ${id2} RETURNING *
2103
+ DELETE FROM ${sql2(this.tableName)} WHERE ${sql2("id")} = ${id3} RETURNING *
2949
2104
  `;
2950
2105
  return row ?? void 0;
2951
2106
  }
2952
- async hardDelete(sql2, id2) {
2107
+ async hardDelete(sql2, id3) {
2953
2108
  const [row] = await sql2`
2954
- DELETE FROM ${sql2(this.tableName)} WHERE ${sql2("id")} = ${id2} RETURNING *
2109
+ DELETE FROM ${sql2(this.tableName)} WHERE ${sql2("id")} = ${id3} RETURNING *
2955
2110
  `;
2956
2111
  return row ?? void 0;
2957
2112
  }
@@ -3047,23 +2202,23 @@ var BoundTable = class _BoundTable {
3047
2202
  async insertMany(data) {
3048
2203
  return await this.inner.insertMany(this.sql, data);
3049
2204
  }
3050
- async read(id2, opts) {
3051
- return await this.inner.read(this.sql, id2, opts);
2205
+ async read(id3, opts) {
2206
+ return await this.inner.read(this.sql, id3, opts);
3052
2207
  }
3053
2208
  async readMany(where, opts) {
3054
2209
  return await this.inner.readMany(this.sql, where, opts);
3055
2210
  }
3056
- async update(id2, data) {
3057
- return await this.inner.update(this.sql, id2, data);
2211
+ async update(id3, data) {
2212
+ return await this.inner.update(this.sql, id3, data);
3058
2213
  }
3059
2214
  async updateMany(where, data) {
3060
2215
  return await this.inner.updateMany(this.sql, where, data);
3061
2216
  }
3062
- async delete(id2) {
3063
- return await this.inner.delete(this.sql, id2);
2217
+ async delete(id3) {
2218
+ return await this.inner.delete(this.sql, id3);
3064
2219
  }
3065
- async hardDelete(id2) {
3066
- return await this.inner.hardDelete(this.sql, id2);
2220
+ async hardDelete(id3) {
2221
+ return await this.inner.hardDelete(this.sql, id3);
3067
2222
  }
3068
2223
  async deleteMany(where) {
3069
2224
  return await this.inner.deleteMany(this.sql, where);
@@ -3530,8 +2685,8 @@ function user(options) {
3530
2685
  const { data: rows } = await users.readMany({ email });
3531
2686
  return rows[0];
3532
2687
  }
3533
- async function findById(id2) {
3534
- return await users.read(id2);
2688
+ async function findById(id3) {
2689
+ return await users.read(id3);
3535
2690
  }
3536
2691
  async function register(data) {
3537
2692
  const { email, password, name } = RegisterSchema.parse(data);
@@ -3687,7 +2842,7 @@ function createHub(opts) {
3687
2842
  }
3688
2843
  });
3689
2844
  }
3690
- function join5(key, ws) {
2845
+ function join6(key, ws) {
3691
2846
  if (!channels.has(key)) {
3692
2847
  channels.set(key, /* @__PURE__ */ new Set());
3693
2848
  redisSub?.subscribe(`${prefix}${key}`);
@@ -3728,7 +2883,7 @@ function createHub(opts) {
3728
2883
  await redisSub.quit();
3729
2884
  }
3730
2885
  }
3731
- return { join: join5, leave, broadcast, close };
2886
+ return { join: join6, leave, broadcast, close };
3732
2887
  }
3733
2888
 
3734
2889
  // queue/index.ts
@@ -3854,7 +3009,7 @@ function queue(opts) {
3854
3009
  }
3855
3010
  }
3856
3011
  mw.add = function add(type, payload, opts2) {
3857
- const id2 = crypto4.randomUUID();
3012
+ const id3 = crypto4.randomUUID();
3858
3013
  let runAt;
3859
3014
  if (opts2?.schedule) {
3860
3015
  runAt = cronNext(opts2.schedule);
@@ -3863,9 +3018,9 @@ function queue(opts) {
3863
3018
  } else {
3864
3019
  runAt = Date.now();
3865
3020
  }
3866
- const job = { id: id2, type, payload, createdAt: Date.now(), runAt };
3021
+ const job = { id: id3, type, payload, createdAt: Date.now(), runAt };
3867
3022
  if (opts2?.schedule) job.schedule = opts2.schedule;
3868
- return redis2.zadd(jobKey, runAt, JSON.stringify(job)).then(() => id2);
3023
+ return redis2.zadd(jobKey, runAt, JSON.stringify(job)).then(() => id3);
3869
3024
  };
3870
3025
  mw.process = function process2(type, handler) {
3871
3026
  handlers.set(type, handler);
@@ -4803,8 +3958,8 @@ import { createOpenAI as createOpenAI2 } from "@ai-sdk/openai";
4803
3958
  // agent/rest.ts
4804
3959
  function buildRouter2(deps) {
4805
3960
  const { agents: agentsTable, knowledge, runner } = deps;
4806
- async function getAgent(id2) {
4807
- const row = await agentsTable.read(id2);
3961
+ async function getAgent(id3) {
3962
+ const row = await agentsTable.read(id3);
4808
3963
  return row ?? null;
4809
3964
  }
4810
3965
  const r = new Router();
@@ -4831,8 +3986,8 @@ function buildRouter2(deps) {
4831
3986
  return Response.json(agent2);
4832
3987
  });
4833
3988
  r.patch("/agents/:id", async (req, ctx) => {
4834
- const id2 = parseInt(ctx.params.id, 10);
4835
- const agent2 = await getAgent(id2);
3989
+ const id3 = parseInt(ctx.params.id, 10);
3990
+ const agent2 = await getAgent(id3);
4836
3991
  if (!agent2) return Response.json({ error: "Agent not found" }, { status: 404 });
4837
3992
  const body = await req.json();
4838
3993
  const updateData = {};
@@ -4844,23 +3999,23 @@ function buildRouter2(deps) {
4844
3999
  if (Object.keys(updateData).length === 0) {
4845
4000
  return Response.json({ error: "No fields to update" }, { status: 400 });
4846
4001
  }
4847
- const row = await agentsTable.update(id2, updateData);
4002
+ const row = await agentsTable.update(id3, updateData);
4848
4003
  return Response.json(row);
4849
4004
  });
4850
4005
  r.delete("/agents/:id", async (_req, ctx) => {
4851
- const id2 = parseInt(ctx.params.id, 10);
4852
- const row = await agentsTable.delete(id2);
4006
+ const id3 = parseInt(ctx.params.id, 10);
4007
+ const row = await agentsTable.delete(id3);
4853
4008
  if (!row) return Response.json({ error: "Agent not found" }, { status: 404 });
4854
4009
  return Response.json({ ok: true });
4855
4010
  });
4856
4011
  r.post("/agents/:id/run", async (req, ctx) => {
4857
- const id2 = parseInt(ctx.params.id, 10);
4012
+ const id3 = parseInt(ctx.params.id, 10);
4858
4013
  const body = await req.json();
4859
4014
  if (!body.input && !body.messages) {
4860
4015
  return Response.json({ error: "input or messages is required" }, { status: 400 });
4861
4016
  }
4862
4017
  try {
4863
- const result = await runner.run(id2, body);
4018
+ const result = await runner.run(id3, body);
4864
4019
  if ("stream" in result) {
4865
4020
  return new Response(result.stream, {
4866
4021
  headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache" }
@@ -5271,15 +4426,15 @@ function buildRouter3(deps) {
5271
4426
  return Response.json(rows);
5272
4427
  });
5273
4428
  r.get("/channels/:id", async (_req, ctx) => {
5274
- const id2 = parseInt(ctx.params.id, 10);
5275
- const ch = await channels.read(id2);
4429
+ const id3 = parseInt(ctx.params.id, 10);
4430
+ const ch = await channels.read(id3);
5276
4431
  if (!ch) return Response.json({ error: "Channel not found" }, { status: 404 });
5277
- const { data: memberRows } = await members.readMany({ channel_id: id2 });
4432
+ const { data: memberRows } = await members.readMany({ channel_id: id3 });
5278
4433
  return Response.json({ channel: ch, members: memberRows });
5279
4434
  });
5280
4435
  r.delete("/channels/:id", async (_req, ctx) => {
5281
- const id2 = parseInt(ctx.params.id, 10);
5282
- await channels.delete(id2);
4436
+ const id3 = parseInt(ctx.params.id, 10);
4437
+ await channels.delete(id3);
5283
4438
  return Response.json({ ok: true });
5284
4439
  });
5285
4440
  r.post("/channels/:id/members", async (req, ctx) => {
@@ -5538,14 +4693,14 @@ function forkApp(opts) {
5538
4693
  return { child, port: opts.port };
5539
4694
  }
5540
4695
  function stopProcess(mp, timeout = 1e4) {
5541
- return new Promise((resolve11) => {
4696
+ return new Promise((resolve12) => {
5542
4697
  const timer = setTimeout(() => {
5543
4698
  mp.child.kill("SIGKILL");
5544
- resolve11();
4699
+ resolve12();
5545
4700
  }, timeout);
5546
4701
  mp.child.on("exit", () => {
5547
4702
  clearTimeout(timer);
5548
- resolve11();
4703
+ resolve12();
5549
4704
  });
5550
4705
  mp.child.kill("SIGTERM");
5551
4706
  });
@@ -5974,6 +5129,370 @@ function ensureCertificates(config) {
5974
5129
  // opencode/client.ts
5975
5130
  import { createOpenAI as createOpenAI3 } from "@ai-sdk/openai";
5976
5131
 
5132
+ // opencode/rest.ts
5133
+ import { join as join4 } from "node:path";
5134
+
5135
+ // ssr/ssr.ts
5136
+ import { createElement } from "react";
5137
+ import { createHash as createHash3 } from "node:crypto";
5138
+ import { dirname as dirname2, resolve as resolve4 } from "node:path";
5139
+ import { AsyncLocalStorage } from "node:async_hooks";
5140
+
5141
+ // ssr/compile.ts
5142
+ import * as esbuild from "esbuild";
5143
+ import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2 } from "node:fs";
5144
+ import { join as join2, resolve as resolve3, dirname } from "node:path";
5145
+ import { pathToFileURL } from "node:url";
5146
+ import { createHash as createHash2 } from "node:crypto";
5147
+ var OUT_DIR = ".weifuwu/ssr";
5148
+ var cache = /* @__PURE__ */ new Map();
5149
+ var externals = [
5150
+ "react",
5151
+ "react-dom",
5152
+ "esbuild",
5153
+ "graphql",
5154
+ "ws",
5155
+ "zod",
5156
+ "@graphql-tools/schema",
5157
+ "ai"
5158
+ ];
5159
+ var _alias = null;
5160
+ function resolveAliases() {
5161
+ if (_alias) return _alias;
5162
+ const configFiles = ["tsconfig.json", "jsconfig.json"];
5163
+ for (const file of configFiles) {
5164
+ const p = resolve3(file);
5165
+ if (existsSync2(p)) {
5166
+ try {
5167
+ const config = JSON.parse(readFileSync2(p, "utf-8"));
5168
+ const paths = config.compilerOptions?.paths;
5169
+ if (paths) {
5170
+ const alias = {};
5171
+ for (const [key, values] of Object.entries(paths)) {
5172
+ const cleanKey = key.replace("/*", "");
5173
+ const val = values[0]?.replace("/*", "");
5174
+ if (val) alias[cleanKey] = resolve3(dirname(p), val);
5175
+ }
5176
+ _alias = alias;
5177
+ return alias;
5178
+ }
5179
+ } catch {
5180
+ }
5181
+ }
5182
+ }
5183
+ _alias = {};
5184
+ return {};
5185
+ }
5186
+ function id(s) {
5187
+ return createHash2("md5").update(s).digest("hex").slice(0, 8);
5188
+ }
5189
+ async function compileTsx(path2) {
5190
+ if (cache.has(path2)) return cache.get(path2);
5191
+ const absPath = resolve3(path2);
5192
+ mkdirSync(OUT_DIR, { recursive: true });
5193
+ const hash = id(absPath);
5194
+ const outPath = join2(OUT_DIR, hash + ".js");
5195
+ await esbuild.build({
5196
+ entryPoints: { [hash]: absPath },
5197
+ outdir: OUT_DIR,
5198
+ format: "esm",
5199
+ platform: "node",
5200
+ jsx: "automatic",
5201
+ jsxImportSource: "react",
5202
+ bundle: true,
5203
+ external: externals,
5204
+ alias: resolveAliases(),
5205
+ write: true,
5206
+ allowOverwrite: true
5207
+ });
5208
+ const mod = await import(pathToFileURL(outPath).href);
5209
+ cache.set(path2, mod);
5210
+ return mod;
5211
+ }
5212
+
5213
+ // ssr/stream.ts
5214
+ import { TextDecoder, TextEncoder as TextEncoder2 } from "node:util";
5215
+ var _publicEnv = null;
5216
+ function getPublicEnv() {
5217
+ if (_publicEnv) return _publicEnv;
5218
+ _publicEnv = {};
5219
+ for (const key of Object.keys(process.env)) {
5220
+ if (key.startsWith("WEIFUWU_PUBLIC_")) {
5221
+ _publicEnv[key] = process.env[key];
5222
+ }
5223
+ }
5224
+ return _publicEnv;
5225
+ }
5226
+ function buildHeadPayload(opts) {
5227
+ const { ctx, base, compiledTailwindCss } = opts;
5228
+ let result = "";
5229
+ if (ctx.prefs?.theme) {
5230
+ result += `<script>!function(){var t=(document.cookie.match(/(?:^|;\\s*)theme=([^;]+)/)||[])[1]||'system';if(t==='system'){t=window.matchMedia('(prefers-color-scheme:dark)').matches?'dark':'light'}document.documentElement.setAttribute('data-theme',t)}()</script>
5231
+ `;
5232
+ }
5233
+ if (compiledTailwindCss) {
5234
+ result += `<link rel="stylesheet" href="${base}/__wfw/style.css" />
5235
+ `;
5236
+ }
5237
+ const localeData = ctx.parsed?.__localeData ?? globalThis.__LOCALE_DATA__;
5238
+ if (localeData && Object.keys(localeData).length > 0) {
5239
+ result += `<script>window.__LOCALE_DATA__=${JSON.stringify(localeData)}</script>
5240
+ `;
5241
+ }
5242
+ const loaderData = opts.loaderData || {};
5243
+ const ctxData = {
5244
+ params: ctx.params,
5245
+ query: ctx.query,
5246
+ user: ctx.user,
5247
+ parsed: ctx.parsed,
5248
+ prefs: ctx.prefs,
5249
+ loaderData
5250
+ };
5251
+ const publicEnv = getPublicEnv();
5252
+ if (Object.keys(publicEnv).length > 0) {
5253
+ ctxData.env = publicEnv;
5254
+ }
5255
+ result += `<script>window.__WEIFUWU_CTX=${JSON.stringify(ctxData)}</script>
5256
+ `;
5257
+ return result;
5258
+ }
5259
+ function buildBodyScripts(opts) {
5260
+ const parts = [];
5261
+ if (opts.loaderData && Object.keys(opts.loaderData).length > 0) {
5262
+ parts.push(`<script>window.__WEIFUWU_PROPS=${JSON.stringify(opts.loaderData)}</script>`);
5263
+ }
5264
+ if (opts.bundle) {
5265
+ parts.push(`<script type="module" src="${opts.base}${opts.bundle.url}"></script>`);
5266
+ }
5267
+ return parts.join("\n");
5268
+ }
5269
+ function streamResponse(reactStream, opts) {
5270
+ const decoder = new TextDecoder();
5271
+ const encoder2 = new TextEncoder2();
5272
+ const headPayload = buildHeadPayload(opts);
5273
+ let buffer = "";
5274
+ let headFlushed = false;
5275
+ let extractedHead = "";
5276
+ const output = new ReadableStream({
5277
+ async start(controller) {
5278
+ try {
5279
+ const reader = reactStream.getReader();
5280
+ async function push(chunk) {
5281
+ buffer += decoder.decode(chunk, { stream: true });
5282
+ if (!extractedHead) {
5283
+ const m = buffer.match(/<template id="__wfw_head">([\s\S]*?)<\/template>/);
5284
+ if (m) {
5285
+ extractedHead = m[1];
5286
+ buffer = buffer.replace(m[0], "");
5287
+ }
5288
+ }
5289
+ if (!headFlushed) {
5290
+ const idx = buffer.indexOf("</head>");
5291
+ if (idx !== -1) {
5292
+ const before = buffer.slice(0, idx);
5293
+ let injection = "";
5294
+ if (extractedHead) injection += "\n" + extractedHead;
5295
+ injection += headPayload;
5296
+ controller.enqueue(encoder2.encode(before + injection));
5297
+ buffer = buffer.slice(idx);
5298
+ headFlushed = true;
5299
+ }
5300
+ return;
5301
+ }
5302
+ controller.enqueue(encoder2.encode(buffer));
5303
+ buffer = "";
5304
+ }
5305
+ while (true) {
5306
+ const { done, value } = await reader.read();
5307
+ if (done) break;
5308
+ await push(value);
5309
+ }
5310
+ buffer = buffer.replace(/<template id="__wfw_head">[\s\S]*?<\/template>/g, "");
5311
+ if (buffer) controller.enqueue(encoder2.encode(buffer));
5312
+ const body = buildBodyScripts(opts);
5313
+ if (body) controller.enqueue(encoder2.encode("\n" + body));
5314
+ if (opts.isDev) {
5315
+ controller.enqueue(encoder2.encode(
5316
+ `
5317
+ <script>(function(){var ws=new WebSocket((location.protocol==='https:'?'wss:':'ws:')+'//'+location.host+'${opts.base}/__weifuwu/livereload');ws.onmessage=function(e){if(e.data==='reload')location.reload()};ws.onclose=function(){setTimeout(function(){location.reload()},500)}})()</script>`
5318
+ ));
5319
+ }
5320
+ } catch {
5321
+ const fallback = `<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>500</title></head><body><h1>500 - Internal Server Error</h1></body></html>`;
5322
+ controller.enqueue(encoder2.encode(fallback));
5323
+ } finally {
5324
+ controller.close();
5325
+ }
5326
+ }
5327
+ });
5328
+ return new Response(output, {
5329
+ status: opts.status ?? 200,
5330
+ headers: { "content-type": "text/html; charset=utf-8" }
5331
+ });
5332
+ }
5333
+
5334
+ // ssr/ssr.ts
5335
+ var als = new AsyncLocalStorage();
5336
+ __registerAls(() => als.getStore());
5337
+ var isDev = process.env.NODE_ENV !== "production";
5338
+ var bundleCache = /* @__PURE__ */ new Map();
5339
+ function id2(s) {
5340
+ return createHash3("md5").update(s).digest("hex").slice(0, 8);
5341
+ }
5342
+ function serializeLoaderData(ctx) {
5343
+ const data = {};
5344
+ for (const key of Object.keys(ctx)) {
5345
+ if (!["params", "query", "mountPath", "layoutStack"].includes(key)) {
5346
+ data[key] = ctx[key];
5347
+ }
5348
+ }
5349
+ return data;
5350
+ }
5351
+ async function buildClientBundle(entryPath, layoutPaths) {
5352
+ try {
5353
+ const absEntry = resolve4(entryPath);
5354
+ const absLayouts = layoutPaths.map((p) => resolve4(p));
5355
+ const layoutImports = absLayouts.map((p) => `import${JSON.stringify(p)};`).join("");
5356
+ const _sc = `(function(){var k='__WEIFUWU_CTX_STORE';var s=typeof globalThis!='undefined'&&globalThis[k];if(!s)return function(){};return function(v){s._ctx={...s._ctx,...v};s._snapshot={params:s._ctx.params,query:s._ctx.query,user:s._ctx.user,parsed:s._ctx.parsed,prefs:s._ctx.prefs,env:s._ctx.env};s._listeners.forEach(function(fn){fn()})}})()`;
5357
+ const code = [
5358
+ layoutImports,
5359
+ `import{hydrateRoot}from'react-dom/client';`,
5360
+ `import{createElement,useState,useEffect}from'react';`,
5361
+ `import{TsxContext}from'weifuwu/react';`,
5362
+ `import P from${JSON.stringify(absEntry)};`,
5363
+ `var setCtx=${_sc};`,
5364
+ `const c=document.getElementById('__weifuwu_root');`,
5365
+ `if(window.__WEIFUWU_PROPS)setCtx({loaderData:window.__WEIFUWU_PROPS});`,
5366
+ `if(!window.__WFW_ROOT){`,
5367
+ `function App(){`,
5368
+ `const[p,setP]=useState({C:P});`,
5369
+ `useEffect(()=>{window.__WFW_SET_PAGE=(C)=>{setCtx({loaderData:window.__WEIFUWU_PROPS});setP({C})}},[]);`,
5370
+ `const ctx=window.__WEIFUWU_CTX||{};`,
5371
+ `return createElement(TsxContext.Provider,{value:ctx},`,
5372
+ `createElement(p.C,null))`,
5373
+ `}`,
5374
+ `window.__WFW_ROOT=hydrateRoot(c,createElement(App));`,
5375
+ `}else{`,
5376
+ `window.__WFW_SET_PAGE?.(P);`,
5377
+ `}`
5378
+ ].join("");
5379
+ const { default: esbuild2 } = await import("esbuild");
5380
+ const result = await esbuild2.build({
5381
+ stdin: { contents: code, loader: "tsx", resolveDir: dirname2(absEntry) },
5382
+ bundle: true,
5383
+ format: "esm",
5384
+ jsx: "automatic",
5385
+ jsxImportSource: "react",
5386
+ banner: { js: "self.process={env:{}};" },
5387
+ loader: { ".node": "empty" },
5388
+ write: false,
5389
+ minify: true
5390
+ });
5391
+ return result.outputFiles[0].contents;
5392
+ } catch (err) {
5393
+ console.error("hydration bundle failed:", err);
5394
+ return null;
5395
+ }
5396
+ }
5397
+ function ssr(path2) {
5398
+ const entryId = id2(resolve4(path2));
5399
+ const bundleKey = `/__ssr/${entryId}.js`;
5400
+ const r = new Router();
5401
+ r.get("/__ssr/:path", (req, ctx) => {
5402
+ const buf = bundleCache.get("/__ssr/" + ctx.params.path);
5403
+ return buf ? new Response(buf, {
5404
+ headers: { "content-type": "application/javascript; charset=utf-8" }
5405
+ }) : new Response("", { status: 404 });
5406
+ });
5407
+ r.get("/", async (req, ctx) => {
5408
+ const pageMod = await compileTsx(path2);
5409
+ const Component = pageMod.default;
5410
+ if (!Component) return new Response("", { status: 500 });
5411
+ const layouts = ctx.layoutStack || [];
5412
+ const layoutComponents = layouts.map((l) => l.component);
5413
+ const layoutPaths = layouts.map((l) => l.path);
5414
+ const base = (ctx.mountPath || "").replace(/\/$/, "");
5415
+ const loaderData = serializeLoaderData(ctx);
5416
+ const ctxValue = {
5417
+ params: ctx.params,
5418
+ query: ctx.query,
5419
+ user: ctx.user ?? {},
5420
+ parsed: ctx.parsed ?? {},
5421
+ prefs: ctx.prefs ?? {},
5422
+ loaderData,
5423
+ env: ctx.env ?? {}
5424
+ };
5425
+ return als.run(ctxValue, async () => {
5426
+ setCtx(ctxValue);
5427
+ let element = createElement(
5428
+ TsxContext.Provider,
5429
+ { value: ctxValue },
5430
+ createElement(
5431
+ "div",
5432
+ { id: "__weifuwu_root" },
5433
+ createElement(Component, null)
5434
+ )
5435
+ );
5436
+ if (layoutComponents.length === 0) {
5437
+ element = createElement(
5438
+ "html",
5439
+ { lang: "en" },
5440
+ createElement(
5441
+ "head",
5442
+ null,
5443
+ createElement("meta", { charSet: "utf-8" }),
5444
+ createElement("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
5445
+ createElement("title", null, "weifuwu")
5446
+ ),
5447
+ createElement("body", null, element)
5448
+ );
5449
+ } else {
5450
+ for (const L of layoutComponents.toReversed()) {
5451
+ element = createElement(L, { children: element });
5452
+ }
5453
+ }
5454
+ let bundle = null;
5455
+ if (!bundleCache.has(bundleKey)) {
5456
+ const buf = await buildClientBundle(path2, layoutPaths);
5457
+ if (buf) bundleCache.set(bundleKey, buf);
5458
+ }
5459
+ if (bundleCache.has(bundleKey)) {
5460
+ bundle = { url: bundleKey };
5461
+ }
5462
+ const { renderToReadableStream } = await import("react-dom/server");
5463
+ const stream = await renderToReadableStream(element);
5464
+ return streamResponse(stream, {
5465
+ ctx,
5466
+ base,
5467
+ isDev,
5468
+ bundle,
5469
+ loaderData
5470
+ });
5471
+ });
5472
+ });
5473
+ return r;
5474
+ }
5475
+
5476
+ // ssr/layout.ts
5477
+ function layout(path2) {
5478
+ return async (req, ctx, next) => {
5479
+ const mod = await compileTsx(path2);
5480
+ const Component = mod.default;
5481
+ if (!Component) throw new Error(`Layout ${path2} has no default export`);
5482
+ ctx.layoutStack = [...ctx.layoutStack || [], { path: path2, component: Component }];
5483
+ return next(req, ctx);
5484
+ };
5485
+ }
5486
+
5487
+ // ssr/tailwind.ts
5488
+ var isDev2 = process.env.NODE_ENV !== "production";
5489
+
5490
+ // ssr/error-boundary.ts
5491
+ import { createElement as createElement2 } from "react";
5492
+
5493
+ // ssr/live.ts
5494
+ import chokidar from "chokidar";
5495
+
5977
5496
  // opencode/session.ts
5978
5497
  import { randomUUID as randomUUID2 } from "node:crypto";
5979
5498
  import { join as join3 } from "node:path";
@@ -6001,12 +5520,12 @@ var messages = pgTable("_opencode_messages", {
6001
5520
  created_at: timestamptz("created_at")
6002
5521
  });
6003
5522
  async function createSession(sql2, opts, cwd, mountPath) {
6004
- const id2 = randomUUID2();
6005
- const ws = computeSessionWorkspace(cwd, mountPath, id2);
5523
+ const id3 = randomUUID2();
5524
+ const ws = computeSessionWorkspace(cwd, mountPath, id3);
6006
5525
  await mkdir2(ws, { recursive: true });
6007
5526
  const [row] = await sql2`
6008
5527
  INSERT INTO "_opencode_sessions" ("id", "user_id", "title", "model", "workspace", "system_prompt")
6009
- VALUES (${id2}, ${opts.userId ?? 0}, ${opts.title ?? null}, ${opts.model ?? "deepseek-v4-flash"}, ${ws}, ${opts.systemPrompt ?? null})
5528
+ VALUES (${id3}, ${opts.userId ?? 0}, ${opts.title ?? null}, ${opts.model ?? "deepseek-v4-flash"}, ${ws}, ${opts.systemPrompt ?? null})
6010
5529
  RETURNING *
6011
5530
  `;
6012
5531
  return row;
@@ -6015,8 +5534,8 @@ function computeSessionWorkspace(cwd, mountPath, sessionId) {
6015
5534
  const name = !mountPath || mountPath === "/" ? "default" : mountPath.replace(/^\//, "");
6016
5535
  return join3(cwd, ".sessions", name, sessionId);
6017
5536
  }
6018
- async function getSession(sql2, id2) {
6019
- const { data: rows } = await sessions.readMany(sql2, { id: id2, active: true });
5537
+ async function getSession(sql2, id3) {
5538
+ const { data: rows } = await sessions.readMany(sql2, { id: id3, active: true });
6020
5539
  return rows[0] ?? null;
6021
5540
  }
6022
5541
  async function listSessions(sql2, userId) {
@@ -6028,8 +5547,8 @@ async function listSessions(sql2, userId) {
6028
5547
  const { data: rows } = await sessions.readMany(sql2, { active: true }, opts);
6029
5548
  return rows;
6030
5549
  }
6031
- async function deleteSession(sql2, id2) {
6032
- await sessions.update(sql2, id2, { active: false, updated_at: sql`NOW()` });
5550
+ async function deleteSession(sql2, id3) {
5551
+ await sessions.update(sql2, id3, { active: false, updated_at: sql`NOW()` });
6033
5552
  }
6034
5553
  async function getHistory(sql2, sessionId, limit = 50) {
6035
5554
  const { data: rows } = await messages.readMany(sql2, { session_id: sessionId }, {
@@ -6210,10 +5729,10 @@ function createBashTool(ctx) {
6210
5729
  return { stdout: "", stderr: "Command denied: potentially dangerous command", exitCode: 1 };
6211
5730
  }
6212
5731
  const cwd = workdir ? `${ctx.workspace}/${workdir}` : ctx.workspace;
6213
- return new Promise((resolve11) => {
5732
+ return new Promise((resolve12) => {
6214
5733
  const child = exec(command, { cwd, timeout: timeout * 1e3, maxBuffer: 1024 * 1024 }, (error, stdout, stderr) => {
6215
5734
  const truncated = stdout.length > 1e6 || stderr.length > 1e6;
6216
- resolve11({
5735
+ resolve12({
6217
5736
  stdout: stdout.slice(0, 1e6),
6218
5737
  stderr: stderr.slice(0, 1e6),
6219
5738
  exitCode: error?.code ?? 0,
@@ -6230,7 +5749,7 @@ function createBashTool(ctx) {
6230
5749
  import { tool as tool4 } from "ai";
6231
5750
  import { z as z6 } from "zod";
6232
5751
  import { readFileSync as readFileSync3 } from "node:fs";
6233
- import { resolve as resolve4 } from "node:path";
5752
+ import { resolve as resolve5 } from "node:path";
6234
5753
  function createReadTool(ctx) {
6235
5754
  return tool4({
6236
5755
  description: "Read file contents. Supports offset and limit for reading specific line ranges.",
@@ -6240,7 +5759,7 @@ function createReadTool(ctx) {
6240
5759
  limit: z6.number().optional().describe("Number of lines to read")
6241
5760
  }),
6242
5761
  execute: async ({ path: path2, offset, limit }) => {
6243
- const resolved = resolve4(ctx.workspace, path2);
5762
+ const resolved = resolve5(ctx.workspace, path2);
6244
5763
  if (!isPathAllowed(resolved, ctx.workspace, ctx.permissions)) {
6245
5764
  return { error: "Path not allowed", content: null, totalLines: 0 };
6246
5765
  }
@@ -6271,8 +5790,8 @@ function createReadTool(ctx) {
6271
5790
  // opencode/tools/write.ts
6272
5791
  import { tool as tool5 } from "ai";
6273
5792
  import { z as z7 } from "zod";
6274
- import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "node:fs";
6275
- import { resolve as resolve5, dirname as dirname2 } from "node:path";
5793
+ import { writeFileSync, mkdirSync as mkdirSync2 } from "node:fs";
5794
+ import { resolve as resolve6, dirname as dirname3 } from "node:path";
6276
5795
  function createWriteTool(ctx) {
6277
5796
  return tool5({
6278
5797
  description: "Create or overwrite a file. Parent directories are created automatically.",
@@ -6281,12 +5800,12 @@ function createWriteTool(ctx) {
6281
5800
  content: z7.string().describe("File content")
6282
5801
  }),
6283
5802
  execute: async ({ path: path2, content }) => {
6284
- const resolved = resolve5(ctx.workspace, path2);
5803
+ const resolved = resolve6(ctx.workspace, path2);
6285
5804
  if (!isPathAllowed(resolved, ctx.workspace, ctx.permissions)) {
6286
5805
  return { error: "Path not allowed" };
6287
5806
  }
6288
- mkdirSync2(dirname2(resolved), { recursive: true });
6289
- writeFileSync2(resolved, content, "utf-8");
5807
+ mkdirSync2(dirname3(resolved), { recursive: true });
5808
+ writeFileSync(resolved, content, "utf-8");
6290
5809
  return { path: path2, size: content.length };
6291
5810
  }
6292
5811
  });
@@ -6295,8 +5814,8 @@ function createWriteTool(ctx) {
6295
5814
  // opencode/tools/edit.ts
6296
5815
  import { tool as tool6 } from "ai";
6297
5816
  import { z as z8 } from "zod";
6298
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
6299
- import { resolve as resolve6 } from "node:path";
5817
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "node:fs";
5818
+ import { resolve as resolve7 } from "node:path";
6300
5819
  function createEditTool(ctx) {
6301
5820
  return tool6({
6302
5821
  description: "Perform exact string replacements in a file. If oldString appears multiple times, provide more surrounding context.",
@@ -6307,7 +5826,7 @@ function createEditTool(ctx) {
6307
5826
  replaceAll: z8.boolean().default(false).describe("Replace all occurrences")
6308
5827
  }),
6309
5828
  execute: async ({ path: path2, oldString, newString, replaceAll }) => {
6310
- const resolved = resolve6(ctx.workspace, path2);
5829
+ const resolved = resolve7(ctx.workspace, path2);
6311
5830
  if (!isPathAllowed(resolved, ctx.workspace, ctx.permissions)) {
6312
5831
  return { error: "Path not allowed" };
6313
5832
  }
@@ -6318,7 +5837,7 @@ function createEditTool(ctx) {
6318
5837
  }
6319
5838
  const count = content.split(oldString).length - 1;
6320
5839
  const result2 = content.replaceAll(oldString, newString);
6321
- writeFileSync3(resolved, result2, "utf-8");
5840
+ writeFileSync2(resolved, result2, "utf-8");
6322
5841
  return { path: path2, replaced: count };
6323
5842
  }
6324
5843
  const firstIdx = content.indexOf(oldString);
@@ -6330,7 +5849,7 @@ function createEditTool(ctx) {
6330
5849
  return { error: "Found multiple matches. Provide more surrounding context in oldString.", replaced: 0 };
6331
5850
  }
6332
5851
  const result = content.replace(oldString, newString);
6333
- writeFileSync3(resolved, result, "utf-8");
5852
+ writeFileSync2(resolved, result, "utf-8");
6334
5853
  return { path: path2, replaced: 1 };
6335
5854
  }
6336
5855
  });
@@ -6340,7 +5859,7 @@ function createEditTool(ctx) {
6340
5859
  import { tool as tool7 } from "ai";
6341
5860
  import { z as z9 } from "zod";
6342
5861
  import { execFileSync } from "node:child_process";
6343
- import { resolve as resolve7 } from "node:path";
5862
+ import { resolve as resolve8 } from "node:path";
6344
5863
  import { existsSync as existsSync3 } from "node:fs";
6345
5864
  function createGrepTool(ctx) {
6346
5865
  return tool7({
@@ -6352,7 +5871,7 @@ function createGrepTool(ctx) {
6352
5871
  context: z9.number().default(0).describe("Number of context lines before and after each match")
6353
5872
  }),
6354
5873
  execute: async ({ pattern, include, path: path2, context }) => {
6355
- const searchDir = path2 ? resolve7(ctx.workspace, path2) : ctx.workspace;
5874
+ const searchDir = path2 ? resolve8(ctx.workspace, path2) : ctx.workspace;
6356
5875
  try {
6357
5876
  let stdout;
6358
5877
  if (existsSync3("/usr/bin/rg") || existsSync3("/usr/local/bin/rg")) {
@@ -6384,7 +5903,7 @@ function createGrepTool(ctx) {
6384
5903
  import { tool as tool8 } from "ai";
6385
5904
  import { z as z10 } from "zod";
6386
5905
  import { execFileSync as execFileSync2 } from "node:child_process";
6387
- import { resolve as resolve8 } from "node:path";
5906
+ import { resolve as resolve9 } from "node:path";
6388
5907
  function createGlobTool(ctx) {
6389
5908
  return tool8({
6390
5909
  description: "Find files matching a glob pattern.",
@@ -6393,7 +5912,7 @@ function createGlobTool(ctx) {
6393
5912
  path: z10.string().optional().describe("Subdirectory relative to workspace")
6394
5913
  }),
6395
5914
  execute: async ({ pattern, path: path2 }) => {
6396
- const searchDir = path2 ? resolve8(ctx.workspace, path2) : ctx.workspace;
5915
+ const searchDir = path2 ? resolve9(ctx.workspace, path2) : ctx.workspace;
6397
5916
  try {
6398
5917
  const stdout = execFileSync2("find", [
6399
5918
  searchDir,
@@ -6454,7 +5973,7 @@ function createQuestionTool(ctx) {
6454
5973
  options: z12.array(z12.string()).optional().describe("Optional multiple choice options")
6455
5974
  }),
6456
5975
  execute: async ({ question, options }, { toolCallId }) => {
6457
- return new Promise((resolve11, reject) => {
5976
+ return new Promise((resolve12, reject) => {
6458
5977
  const timeout = setTimeout(() => {
6459
5978
  ctx.pendingQuestions.delete(toolCallId);
6460
5979
  reject(new Error("Question timed out"));
@@ -6462,7 +5981,7 @@ function createQuestionTool(ctx) {
6462
5981
  ctx.pendingQuestions.set(toolCallId, {
6463
5982
  resolve: (answer) => {
6464
5983
  clearTimeout(timeout);
6465
- resolve11(answer);
5984
+ resolve12(answer);
6466
5985
  },
6467
5986
  reject: (err) => {
6468
5987
  clearTimeout(timeout);
@@ -6563,15 +6082,15 @@ async function buildRouter4(deps) {
6563
6082
  return Response.json(sessions2);
6564
6083
  });
6565
6084
  router.get("/sessions/:id", async (_req, ctx) => {
6566
- const id2 = ctx.params.id;
6567
- const session = await getSession(sql2, id2);
6085
+ const id3 = ctx.params.id;
6086
+ const session = await getSession(sql2, id3);
6568
6087
  if (!session) return new Response("Not Found", { status: 404 });
6569
- const messages2 = await getHistory(sql2, id2);
6088
+ const messages2 = await getHistory(sql2, id3);
6570
6089
  return Response.json({ session, messages: messages2 });
6571
6090
  });
6572
6091
  router.delete("/sessions/:id", async (_req, ctx) => {
6573
- const id2 = ctx.params.id;
6574
- await deleteSession(sql2, id2);
6092
+ const id3 = ctx.params.id;
6093
+ await deleteSession(sql2, id3);
6575
6094
  return new Response(null, { status: 204 });
6576
6095
  });
6577
6096
  router.post("/sessions/:id/message", async (req, ctx) => {
@@ -6609,8 +6128,8 @@ async function buildRouter4(deps) {
6609
6128
  });
6610
6129
  try {
6611
6130
  const uiDir = new URL("../opencode/ui/", import.meta.url).pathname;
6612
- const uiRouter = await tsx({ dir: uiDir });
6613
- router.use("/", uiRouter);
6131
+ router.use(layout(join4(uiDir, "layout.tsx")));
6132
+ router.get("/", ssr(join4(uiDir, "page.tsx")));
6614
6133
  } catch (e) {
6615
6134
  console.warn("[opencode] UI not available:", e);
6616
6135
  }
@@ -6745,7 +6264,7 @@ function createWSHandler2(deps) {
6745
6264
  import { readFile } from "node:fs/promises";
6746
6265
  import { glob } from "node:fs/promises";
6747
6266
  import { homedir } from "node:os";
6748
- import { resolve as resolve9 } from "node:path";
6267
+ import { resolve as resolve10 } from "node:path";
6749
6268
  import { parse as parseYaml } from "yaml";
6750
6269
  var SEARCH_DIRS = [
6751
6270
  (ws) => `${ws}/.opencode/skills`,
@@ -6783,7 +6302,7 @@ async function scanDir(dir) {
6783
6302
  try {
6784
6303
  const files = [];
6785
6304
  for await (const entry of glob("*/SKILL.md", { cwd: dir })) {
6786
- const skill = await parseSkillFile(resolve9(dir, entry));
6305
+ const skill = await parseSkillFile(resolve10(dir, entry));
6787
6306
  if (skill) files.push(skill);
6788
6307
  }
6789
6308
  return files;
@@ -7119,7 +6638,7 @@ function analytics(options) {
7119
6638
  // preferences.ts
7120
6639
  import { readFile as readFile2 } from "node:fs/promises";
7121
6640
  import { existsSync as existsSync4 } from "node:fs";
7122
- import { join as join4, resolve as resolve10 } from "node:path";
6641
+ import { join as join5, resolve as resolve11 } from "node:path";
7123
6642
  var defaults = {
7124
6643
  locale: { default: "en", cookie: "locale", fromAcceptLanguage: true },
7125
6644
  theme: { default: "system", cookie: "theme" }
@@ -7168,24 +6687,24 @@ async function handlePrefSwitch(req, value, cookieName, load) {
7168
6687
  });
7169
6688
  }
7170
6689
  function preferences(options) {
7171
- const dir = options.dir ? resolve10(options.dir) : void 0;
6690
+ const dir = options.dir ? resolve11(options.dir) : void 0;
7172
6691
  const localeOpts = { ...defaults.locale, ...options.locale };
7173
6692
  const themeOpts = { ...defaults.theme, ...options.theme };
7174
- const cache = /* @__PURE__ */ new Map();
6693
+ const cache2 = /* @__PURE__ */ new Map();
7175
6694
  function validLocale(locale) {
7176
6695
  return /^[\w-]+$/.test(locale) && !locale.includes("..");
7177
6696
  }
7178
6697
  async function load(locale) {
7179
6698
  if (!dir) return {};
7180
6699
  if (!validLocale(locale)) return {};
7181
- const cached = cache.get(locale);
6700
+ const cached = cache2.get(locale);
7182
6701
  if (cached) return cached;
7183
- const filePath = join4(dir, `${locale}.json`);
6702
+ const filePath = join5(dir, `${locale}.json`);
7184
6703
  if (!existsSync4(filePath)) return {};
7185
6704
  try {
7186
6705
  const content = await readFile2(filePath, "utf-8");
7187
6706
  const data = JSON.parse(content);
7188
- cache.set(locale, data);
6707
+ cache2.set(locale, data);
7189
6708
  return data;
7190
6709
  } catch {
7191
6710
  return {};
@@ -7532,9 +7051,9 @@ function listHandler(entries) {
7532
7051
  }
7533
7052
  function getHandler(entries) {
7534
7053
  return async (_req, ctx) => {
7535
- const id2 = ctx.params?.id;
7536
- if (!id2) return Response.json({ error: "id is required" }, { status: 400 });
7537
- const row = await entries.read(parseInt(id2));
7054
+ const id3 = ctx.params?.id;
7055
+ if (!id3) return Response.json({ error: "id is required" }, { status: 400 });
7056
+ const row = await entries.read(parseInt(id3));
7538
7057
  if (!row) return Response.json({ error: "not found" }, { status: 404 });
7539
7058
  return Response.json(parseMetadata(row));
7540
7059
  };
@@ -7752,8 +7271,8 @@ function createMemoryStore(channels) {
7752
7271
  }));
7753
7272
  return { streams, count: streams.length };
7754
7273
  },
7755
- async send(stream, group, type, data, id2) {
7756
- notify(channels, stream, group, id2 ?? "", "send", { type, data });
7274
+ async send(stream, group, type, data, id3) {
7275
+ notify(channels, stream, group, id3 ?? "", "send", { type, data });
7757
7276
  },
7758
7277
  async update(stream, group, item, ops) {
7759
7278
  const k = key(stream, group, item);
@@ -7833,8 +7352,8 @@ function createPgStore(channels, pg) {
7833
7352
  }));
7834
7353
  return { streams, count: streams.length };
7835
7354
  },
7836
- async send(stream, group, type, data, id2) {
7837
- notify(channels, stream, group, id2 ?? "", "send", { type, data });
7355
+ async send(stream, group, type, data, id3) {
7356
+ notify(channels, stream, group, id3 ?? "", "send", { type, data });
7838
7357
  },
7839
7358
  async update(stream, group, item, ops) {
7840
7359
  const { value: oldVal } = await this.get(stream, group, item);
@@ -7930,8 +7449,8 @@ function createRedisStore(channels, redis2, ttl) {
7930
7449
  }));
7931
7450
  return { streams, count: streams.length };
7932
7451
  },
7933
- async send(stream, group, type, data, id2) {
7934
- notify(channels, stream, group, id2 ?? "", "send", { type, data });
7452
+ async send(stream, group, type, data, id3) {
7453
+ notify(channels, stream, group, id3 ?? "", "send", { type, data });
7935
7454
  },
7936
7455
  async update(stream, group, item, ops) {
7937
7456
  const hk = hashKey(stream, group);
@@ -8144,9 +7663,9 @@ function iii(opts = {}) {
8144
7663
  const functions = /* @__PURE__ */ new Map();
8145
7664
  const triggers = /* @__PURE__ */ new Map();
8146
7665
  const pending = /* @__PURE__ */ new Map();
8147
- function registerBuiltin(id2, handler) {
8148
- functions.set(id2, {
8149
- id: id2,
7666
+ function registerBuiltin(id3, handler) {
7667
+ functions.set(id3, {
7668
+ id: id3,
8150
7669
  handler,
8151
7670
  workerId: "__iii__",
8152
7671
  workerName: "__iii__",
@@ -8201,34 +7720,34 @@ function iii(opts = {}) {
8201
7720
  }
8202
7721
  workers.set(workerId, reg);
8203
7722
  }
8204
- function addRemoteFunction(workerId, id2) {
7723
+ function addRemoteFunction(workerId, id3) {
8205
7724
  const worker = workers.get(workerId);
8206
7725
  if (!worker) return;
8207
7726
  const handler = async (payload) => {
8208
7727
  if (!worker.ws) throw new Error(`Worker "${worker.name}" disconnected`);
8209
7728
  const invocationId = crypto6.randomUUID();
8210
- return new Promise((resolve11, reject) => {
7729
+ return new Promise((resolve12, reject) => {
8211
7730
  const timer = setTimeout(() => {
8212
7731
  pending.delete(invocationId);
8213
- reject(new Error(`Invocation timed out for "${id2}"`));
7732
+ reject(new Error(`Invocation timed out for "${id3}"`));
8214
7733
  }, 3e4);
8215
- pending.set(invocationId, { resolve: resolve11, reject, timer });
7734
+ pending.set(invocationId, { resolve: resolve12, reject, timer });
8216
7735
  worker.ws.send(JSON.stringify({
8217
7736
  type: "invoke",
8218
7737
  invocation_id: invocationId,
8219
- function_id: id2,
7738
+ function_id: id3,
8220
7739
  payload
8221
7740
  }));
8222
7741
  });
8223
7742
  };
8224
7743
  const fnReg = {
8225
- id: id2,
7744
+ id: id3,
8226
7745
  handler,
8227
7746
  workerId,
8228
7747
  workerName: worker.name,
8229
7748
  triggers: []
8230
7749
  };
8231
- functions.set(id2, fnReg);
7750
+ functions.set(id3, fnReg);
8232
7751
  worker.functions.push(fnReg);
8233
7752
  }
8234
7753
  function removeWorker(workerId) {
@@ -8241,15 +7760,15 @@ function iii(opts = {}) {
8241
7760
  let engineRef = null;
8242
7761
  const wsHandler = createWsHandler({
8243
7762
  registerRemoteWorker(ws, name) {
8244
- const id2 = crypto6.randomUUID();
8245
- workers.set(id2, { id: id2, name, ws, functions: [], triggers: [] });
8246
- return id2;
7763
+ const id3 = crypto6.randomUUID();
7764
+ workers.set(id3, { id: id3, name, ws, functions: [], triggers: [] });
7765
+ return id3;
8247
7766
  },
8248
7767
  unregisterRemoteWorker(workerId) {
8249
7768
  removeWorker(workerId);
8250
7769
  },
8251
- registerRemoteFunction(workerId, id2) {
8252
- addRemoteFunction(workerId, id2);
7770
+ registerRemoteFunction(workerId, id3) {
7771
+ addRemoteFunction(workerId, id3);
8253
7772
  },
8254
7773
  registerRemoteTrigger(workerId, input) {
8255
7774
  const tid = crypto6.randomUUID();
@@ -8258,11 +7777,11 @@ function iii(opts = {}) {
8258
7777
  const worker = workers.get(workerId);
8259
7778
  if (worker) worker.triggers.push(reg);
8260
7779
  },
8261
- unregisterRemoteFunction(workerId, id2) {
8262
- functions.delete(id2);
7780
+ unregisterRemoteFunction(workerId, id3) {
7781
+ functions.delete(id3);
8263
7782
  const worker = workers.get(workerId);
8264
7783
  if (worker) {
8265
- worker.functions = worker.functions.filter((f) => f.id !== id2);
7784
+ worker.functions = worker.functions.filter((f) => f.id !== id3);
8266
7785
  }
8267
7786
  },
8268
7787
  unregisterRemoteTrigger(workerId, functionId) {
@@ -8397,12 +7916,12 @@ function createWorker(name) {
8397
7916
  const triggers = /* @__PURE__ */ new Map();
8398
7917
  return {
8399
7918
  name,
8400
- registerFunction(id2, handler) {
8401
- functions.set(id2, handler);
7919
+ registerFunction(id3, handler) {
7920
+ functions.set(id3, handler);
8402
7921
  return this;
8403
7922
  },
8404
- unregisterFunction(id2) {
8405
- functions.delete(id2);
7923
+ unregisterFunction(id3) {
7924
+ functions.delete(id3);
8406
7925
  return this;
8407
7926
  },
8408
7927
  registerTrigger(input) {
@@ -8414,10 +7933,10 @@ function createWorker(name) {
8414
7933
  return this;
8415
7934
  },
8416
7935
  getFunctions() {
8417
- return Array.from(functions.entries()).map(([id2, handler]) => ({ id: id2, handler }));
7936
+ return Array.from(functions.entries()).map(([id3, handler]) => ({ id: id3, handler }));
8418
7937
  },
8419
7938
  getTriggers() {
8420
- return Array.from(triggers.entries()).map(([id2, input]) => ({ id: id2, input }));
7939
+ return Array.from(triggers.entries()).map(([id3, input]) => ({ id: id3, input }));
8421
7940
  }
8422
7941
  };
8423
7942
  }
@@ -8453,8 +7972,8 @@ function registerWorker(url) {
8453
7972
  function connect() {
8454
7973
  if (intentionalClose) return;
8455
7974
  ws = new WebSocket(url);
8456
- ready = new Promise((resolve11) => {
8457
- resolveReady = resolve11;
7975
+ ready = new Promise((resolve12) => {
7976
+ resolveReady = resolve12;
8458
7977
  });
8459
7978
  ws.onopen = () => {
8460
7979
  reconnectAttempt = 0;
@@ -8537,15 +8056,15 @@ function registerWorker(url) {
8537
8056
  }
8538
8057
  connect();
8539
8058
  return {
8540
- registerFunction(id2, handler) {
8541
- handlers.set(id2, handler);
8542
- registeredFunctionIds.add(id2);
8543
- send({ type: "register_function", id: id2 });
8059
+ registerFunction(id3, handler) {
8060
+ handlers.set(id3, handler);
8061
+ registeredFunctionIds.add(id3);
8062
+ send({ type: "register_function", id: id3 });
8544
8063
  },
8545
- unregisterFunction(id2) {
8546
- handlers.delete(id2);
8547
- registeredFunctionIds.delete(id2);
8548
- send({ type: "unregister_function", id: id2 });
8064
+ unregisterFunction(id3) {
8065
+ handlers.delete(id3);
8066
+ registeredFunctionIds.delete(id3);
8067
+ send({ type: "unregister_function", id: id3 });
8549
8068
  },
8550
8069
  registerTrigger(input) {
8551
8070
  registeredTriggers.add(JSON.stringify(input));
@@ -8574,13 +8093,13 @@ function registerWorker(url) {
8574
8093
  }
8575
8094
  return Promise.resolve(fn(request.payload, ctx));
8576
8095
  }
8577
- return new Promise((resolve11, reject) => {
8096
+ return new Promise((resolve12, reject) => {
8578
8097
  const invocationId = genId();
8579
8098
  const timer = setTimeout(() => {
8580
8099
  pendingInvocations.delete(invocationId);
8581
8100
  reject(new Error(`Invocation timed out for "${request.function_id}"`));
8582
8101
  }, request.timeout_ms || 3e4);
8583
- pendingInvocations.set(invocationId, { resolve: resolve11, reject, timer });
8102
+ pendingInvocations.set(invocationId, { resolve: resolve12, reject, timer });
8584
8103
  send({
8585
8104
  type: "invoke",
8586
8105
  invocation_id: invocationId,
@@ -8655,7 +8174,6 @@ export {
8655
8174
  streamText,
8656
8175
  tenant,
8657
8176
  tool2 as tool,
8658
- tsx,
8659
8177
  upload,
8660
8178
  user,
8661
8179
  validate