weifuwu 0.18.1 → 0.18.2
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/README.md +127 -61
- package/cli.ts +7 -6
- package/dist/cli.js +7 -6
- package/dist/index.d.ts +1 -2
- package/dist/index.js +511 -1002
- package/dist/router.d.ts +1 -0
- package/dist/ssr/compile.d.ts +2 -0
- package/dist/ssr/error-boundary.d.ts +2 -0
- package/dist/ssr/index.d.ts +7 -0
- package/dist/ssr/index.js +936 -0
- package/dist/ssr/layout.d.ts +2 -0
- package/dist/ssr/live.d.ts +6 -0
- package/dist/ssr/not-found.d.ts +2 -0
- package/dist/ssr/ssr.d.ts +3 -0
- package/dist/ssr/stream.d.ts +14 -0
- package/dist/ssr/tailwind.d.ts +2 -0
- package/dist/types.d.ts +5 -0
- package/package.json +4 -3
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
|
}
|
|
@@ -369,13 +371,13 @@ var Router = class _Router {
|
|
|
369
371
|
const mw = match.middlewares[index++];
|
|
370
372
|
return mw(innerReq, ctx2, dispatch);
|
|
371
373
|
}
|
|
372
|
-
return await new Promise((
|
|
374
|
+
return await new Promise((resolve12) => {
|
|
373
375
|
try {
|
|
374
376
|
upgradeSocket(router.wss, req, socket, head, match.handler, ctx2);
|
|
375
|
-
|
|
377
|
+
resolve12(new Response(null, { status: 101 }));
|
|
376
378
|
} catch {
|
|
377
379
|
socket.destroy();
|
|
378
|
-
|
|
380
|
+
resolve12(new Response("WebSocket upgrade failed", { status: 500 }));
|
|
379
381
|
}
|
|
380
382
|
});
|
|
381
383
|
};
|
|
@@ -561,19 +563,6 @@ function sendHttpResponseOnSocket(socket, response) {
|
|
|
561
563
|
});
|
|
562
564
|
}
|
|
563
565
|
|
|
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
566
|
// tsx-context.ts
|
|
578
567
|
import { createContext } from "react";
|
|
579
568
|
var DEFAULT_CTX = { params: {}, query: {}, parsed: {}, prefs: {}, loaderData: {}, env: {}, user: {} };
|
|
@@ -604,845 +593,6 @@ function setCtx(value) {
|
|
|
604
593
|
}
|
|
605
594
|
var TsxContext = createContext(DEFAULT_CTX);
|
|
606
595
|
|
|
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
596
|
// middleware.ts
|
|
1447
597
|
function logger(options) {
|
|
1448
598
|
return async (req, ctx, next) => {
|
|
@@ -1598,12 +748,12 @@ function auth(options) {
|
|
|
1598
748
|
}
|
|
1599
749
|
|
|
1600
750
|
// static.ts
|
|
1601
|
-
import { createHash
|
|
751
|
+
import { createHash } from "node:crypto";
|
|
1602
752
|
import { open, realpath } from "node:fs/promises";
|
|
1603
|
-
import { extname, resolve as
|
|
753
|
+
import { extname, resolve as resolve2, normalize, sep } from "node:path";
|
|
1604
754
|
import { Readable } from "node:stream";
|
|
1605
755
|
function serveStatic(root, options) {
|
|
1606
|
-
const rootDir =
|
|
756
|
+
const rootDir = resolve2(root);
|
|
1607
757
|
const opts = options ?? {};
|
|
1608
758
|
return async (req, ctx) => {
|
|
1609
759
|
const relativePath = ctx.params["*"] ?? new URL(req.url).pathname.slice(1);
|
|
@@ -1611,8 +761,8 @@ function serveStatic(root, options) {
|
|
|
1611
761
|
if (decoded.includes("..") || decoded.includes("\0")) {
|
|
1612
762
|
return new Response("Forbidden", { status: 403 });
|
|
1613
763
|
}
|
|
1614
|
-
let filePath = normalize(
|
|
1615
|
-
if (!filePath.startsWith(rootDir +
|
|
764
|
+
let filePath = normalize(resolve2(rootDir, decoded));
|
|
765
|
+
if (!filePath.startsWith(rootDir + sep) && filePath !== rootDir) {
|
|
1616
766
|
return new Response("Forbidden", { status: 403 });
|
|
1617
767
|
}
|
|
1618
768
|
let fileHandle;
|
|
@@ -1620,15 +770,15 @@ function serveStatic(root, options) {
|
|
|
1620
770
|
fileHandle = await open(filePath, "r");
|
|
1621
771
|
let stat = await fileHandle.stat();
|
|
1622
772
|
const realPath = await realpath(filePath);
|
|
1623
|
-
if (!realPath.startsWith(rootDir +
|
|
773
|
+
if (!realPath.startsWith(rootDir + sep) && realPath !== rootDir) {
|
|
1624
774
|
await fileHandle.close();
|
|
1625
775
|
return new Response("Forbidden", { status: 403 });
|
|
1626
776
|
}
|
|
1627
777
|
if (stat.isDirectory()) {
|
|
1628
778
|
await fileHandle.close();
|
|
1629
779
|
const indexFile = opts.index ?? "index.html";
|
|
1630
|
-
filePath =
|
|
1631
|
-
if (!filePath.startsWith(rootDir +
|
|
780
|
+
filePath = resolve2(filePath, indexFile);
|
|
781
|
+
if (!filePath.startsWith(rootDir + sep)) {
|
|
1632
782
|
return new Response("Forbidden", { status: 403 });
|
|
1633
783
|
}
|
|
1634
784
|
fileHandle = await open(filePath, "r");
|
|
@@ -1639,7 +789,7 @@ function serveStatic(root, options) {
|
|
|
1639
789
|
}
|
|
1640
790
|
}
|
|
1641
791
|
const mimeType = MIME_TYPES[extname(filePath).toLowerCase()] ?? "application/octet-stream";
|
|
1642
|
-
const etag = `"${
|
|
792
|
+
const etag = `"${createHash("md5").update(`${stat.size}-${stat.mtimeMs}`).digest("hex")}"`;
|
|
1643
793
|
const ifNoneMatch = req.headers.get("if-none-match");
|
|
1644
794
|
if (ifNoneMatch === etag) {
|
|
1645
795
|
await fileHandle.close();
|
|
@@ -1860,7 +1010,7 @@ function deleteCookie(res, name, options) {
|
|
|
1860
1010
|
// upload.ts
|
|
1861
1011
|
import { writeFile, mkdir } from "node:fs/promises";
|
|
1862
1012
|
import { randomUUID } from "node:crypto";
|
|
1863
|
-
import { join
|
|
1013
|
+
import { join, extname as extname2 } from "node:path";
|
|
1864
1014
|
var extensionMimeMap = {
|
|
1865
1015
|
".jpg": "image/jpeg",
|
|
1866
1016
|
".jpeg": "image/jpeg",
|
|
@@ -1927,7 +1077,7 @@ function upload(options) {
|
|
|
1927
1077
|
};
|
|
1928
1078
|
if (saveDir) {
|
|
1929
1079
|
const safeName = value.name.replace(/[/\\\0]/g, "_");
|
|
1930
|
-
const filePath =
|
|
1080
|
+
const filePath = join(saveDir, `${randomUUID()}-${safeName}`);
|
|
1931
1081
|
await writeFile(filePath, buf);
|
|
1932
1082
|
uf.path = filePath;
|
|
1933
1083
|
}
|
|
@@ -2117,12 +1267,12 @@ function requestId(options) {
|
|
|
2117
1267
|
const gen = options?.generator ?? (() => crypto2.randomUUID());
|
|
2118
1268
|
return async (req, ctx, next) => {
|
|
2119
1269
|
const existing = req.headers.get(header);
|
|
2120
|
-
const
|
|
2121
|
-
ctx.requestId =
|
|
1270
|
+
const id3 = existing ?? gen();
|
|
1271
|
+
ctx.requestId = id3;
|
|
2122
1272
|
const res = await next(req, ctx);
|
|
2123
1273
|
if (res.headers.has(header)) return res;
|
|
2124
1274
|
const h = new Headers(res.headers);
|
|
2125
|
-
h.set(header,
|
|
1275
|
+
h.set(header, id3);
|
|
2126
1276
|
return new Response(res.body, { status: res.status, statusText: res.statusText, headers: h });
|
|
2127
1277
|
};
|
|
2128
1278
|
}
|
|
@@ -2344,10 +1494,10 @@ function resolveRef(path2, ctx) {
|
|
|
2344
1494
|
const after = path2.slice(7);
|
|
2345
1495
|
const dot = after.indexOf(".");
|
|
2346
1496
|
if (dot === -1) return ctx.nodeOutputs.get(after);
|
|
2347
|
-
const
|
|
1497
|
+
const id3 = after.slice(0, dot);
|
|
2348
1498
|
const propPath = after.slice(dot + 1);
|
|
2349
|
-
const output = ctx.nodeOutputs.get(
|
|
2350
|
-
if (output === void 0) throw new Error(`Node "${
|
|
1499
|
+
const output = ctx.nodeOutputs.get(id3);
|
|
1500
|
+
if (output === void 0) throw new Error(`Node "${id3}" has no output yet`);
|
|
2351
1501
|
return getByPath(output, propPath.startsWith("output") ? propPath.slice(7).split(".").filter(Boolean) : propPath.split("."));
|
|
2352
1502
|
}
|
|
2353
1503
|
if (path2.startsWith("$var.")) {
|
|
@@ -2873,18 +2023,18 @@ var Table = class {
|
|
|
2873
2023
|
`;
|
|
2874
2024
|
return rows;
|
|
2875
2025
|
}
|
|
2876
|
-
async read(sql2,
|
|
2026
|
+
async read(sql2, id3, opts) {
|
|
2877
2027
|
if (opts?.select?.length) {
|
|
2878
2028
|
const columns = opts.select.map((c) => `"${c}"`).join(", ");
|
|
2879
2029
|
const [row2] = await sql2.unsafe(
|
|
2880
2030
|
`SELECT ${columns} FROM "${this.tableName}" WHERE id = $1 LIMIT 1`,
|
|
2881
|
-
[
|
|
2031
|
+
[id3]
|
|
2882
2032
|
);
|
|
2883
2033
|
return row2 ?? void 0;
|
|
2884
2034
|
}
|
|
2885
2035
|
const [row] = await sql2`
|
|
2886
2036
|
SELECT * FROM ${sql2(this.tableName)}
|
|
2887
|
-
WHERE ${sql2("id")} = ${
|
|
2037
|
+
WHERE ${sql2("id")} = ${id3} LIMIT 1
|
|
2888
2038
|
`;
|
|
2889
2039
|
return row ?? void 0;
|
|
2890
2040
|
}
|
|
@@ -2918,11 +2068,11 @@ var Table = class {
|
|
|
2918
2068
|
const rows = await sql2.unsafe(query, values);
|
|
2919
2069
|
return { count, data: rows };
|
|
2920
2070
|
}
|
|
2921
|
-
async update(sql2,
|
|
2071
|
+
async update(sql2, id3, data) {
|
|
2922
2072
|
const { sets, values: setValues } = this._buildSET(data);
|
|
2923
2073
|
if (sets.length === 0) return void 0;
|
|
2924
2074
|
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,
|
|
2075
|
+
const rows = await sql2.unsafe(query, [...setValues, id3]);
|
|
2926
2076
|
return rows[0] ?? void 0;
|
|
2927
2077
|
}
|
|
2928
2078
|
async updateMany(sql2, where, data) {
|
|
@@ -2936,22 +2086,22 @@ var Table = class {
|
|
|
2936
2086
|
);
|
|
2937
2087
|
return rows.length;
|
|
2938
2088
|
}
|
|
2939
|
-
async delete(sql2,
|
|
2089
|
+
async delete(sql2, id3) {
|
|
2940
2090
|
if (this.hasColumn("deleted_at")) {
|
|
2941
2091
|
const [row2] = await sql2.unsafe(
|
|
2942
2092
|
`UPDATE "${this.tableName}" SET "deleted_at" = NOW() WHERE id = $1 RETURNING *`,
|
|
2943
|
-
[
|
|
2093
|
+
[id3]
|
|
2944
2094
|
);
|
|
2945
2095
|
return row2 ?? void 0;
|
|
2946
2096
|
}
|
|
2947
2097
|
const [row] = await sql2`
|
|
2948
|
-
DELETE FROM ${sql2(this.tableName)} WHERE ${sql2("id")} = ${
|
|
2098
|
+
DELETE FROM ${sql2(this.tableName)} WHERE ${sql2("id")} = ${id3} RETURNING *
|
|
2949
2099
|
`;
|
|
2950
2100
|
return row ?? void 0;
|
|
2951
2101
|
}
|
|
2952
|
-
async hardDelete(sql2,
|
|
2102
|
+
async hardDelete(sql2, id3) {
|
|
2953
2103
|
const [row] = await sql2`
|
|
2954
|
-
DELETE FROM ${sql2(this.tableName)} WHERE ${sql2("id")} = ${
|
|
2104
|
+
DELETE FROM ${sql2(this.tableName)} WHERE ${sql2("id")} = ${id3} RETURNING *
|
|
2955
2105
|
`;
|
|
2956
2106
|
return row ?? void 0;
|
|
2957
2107
|
}
|
|
@@ -3047,23 +2197,23 @@ var BoundTable = class _BoundTable {
|
|
|
3047
2197
|
async insertMany(data) {
|
|
3048
2198
|
return await this.inner.insertMany(this.sql, data);
|
|
3049
2199
|
}
|
|
3050
|
-
async read(
|
|
3051
|
-
return await this.inner.read(this.sql,
|
|
2200
|
+
async read(id3, opts) {
|
|
2201
|
+
return await this.inner.read(this.sql, id3, opts);
|
|
3052
2202
|
}
|
|
3053
2203
|
async readMany(where, opts) {
|
|
3054
2204
|
return await this.inner.readMany(this.sql, where, opts);
|
|
3055
2205
|
}
|
|
3056
|
-
async update(
|
|
3057
|
-
return await this.inner.update(this.sql,
|
|
2206
|
+
async update(id3, data) {
|
|
2207
|
+
return await this.inner.update(this.sql, id3, data);
|
|
3058
2208
|
}
|
|
3059
2209
|
async updateMany(where, data) {
|
|
3060
2210
|
return await this.inner.updateMany(this.sql, where, data);
|
|
3061
2211
|
}
|
|
3062
|
-
async delete(
|
|
3063
|
-
return await this.inner.delete(this.sql,
|
|
2212
|
+
async delete(id3) {
|
|
2213
|
+
return await this.inner.delete(this.sql, id3);
|
|
3064
2214
|
}
|
|
3065
|
-
async hardDelete(
|
|
3066
|
-
return await this.inner.hardDelete(this.sql,
|
|
2215
|
+
async hardDelete(id3) {
|
|
2216
|
+
return await this.inner.hardDelete(this.sql, id3);
|
|
3067
2217
|
}
|
|
3068
2218
|
async deleteMany(where) {
|
|
3069
2219
|
return await this.inner.deleteMany(this.sql, where);
|
|
@@ -3530,8 +2680,8 @@ function user(options) {
|
|
|
3530
2680
|
const { data: rows } = await users.readMany({ email });
|
|
3531
2681
|
return rows[0];
|
|
3532
2682
|
}
|
|
3533
|
-
async function findById(
|
|
3534
|
-
return await users.read(
|
|
2683
|
+
async function findById(id3) {
|
|
2684
|
+
return await users.read(id3);
|
|
3535
2685
|
}
|
|
3536
2686
|
async function register(data) {
|
|
3537
2687
|
const { email, password, name } = RegisterSchema.parse(data);
|
|
@@ -3687,7 +2837,7 @@ function createHub(opts) {
|
|
|
3687
2837
|
}
|
|
3688
2838
|
});
|
|
3689
2839
|
}
|
|
3690
|
-
function
|
|
2840
|
+
function join6(key, ws) {
|
|
3691
2841
|
if (!channels.has(key)) {
|
|
3692
2842
|
channels.set(key, /* @__PURE__ */ new Set());
|
|
3693
2843
|
redisSub?.subscribe(`${prefix}${key}`);
|
|
@@ -3728,7 +2878,7 @@ function createHub(opts) {
|
|
|
3728
2878
|
await redisSub.quit();
|
|
3729
2879
|
}
|
|
3730
2880
|
}
|
|
3731
|
-
return { join:
|
|
2881
|
+
return { join: join6, leave, broadcast, close };
|
|
3732
2882
|
}
|
|
3733
2883
|
|
|
3734
2884
|
// queue/index.ts
|
|
@@ -3854,7 +3004,7 @@ function queue(opts) {
|
|
|
3854
3004
|
}
|
|
3855
3005
|
}
|
|
3856
3006
|
mw.add = function add(type, payload, opts2) {
|
|
3857
|
-
const
|
|
3007
|
+
const id3 = crypto4.randomUUID();
|
|
3858
3008
|
let runAt;
|
|
3859
3009
|
if (opts2?.schedule) {
|
|
3860
3010
|
runAt = cronNext(opts2.schedule);
|
|
@@ -3863,9 +3013,9 @@ function queue(opts) {
|
|
|
3863
3013
|
} else {
|
|
3864
3014
|
runAt = Date.now();
|
|
3865
3015
|
}
|
|
3866
|
-
const job = { id:
|
|
3016
|
+
const job = { id: id3, type, payload, createdAt: Date.now(), runAt };
|
|
3867
3017
|
if (opts2?.schedule) job.schedule = opts2.schedule;
|
|
3868
|
-
return redis2.zadd(jobKey, runAt, JSON.stringify(job)).then(() =>
|
|
3018
|
+
return redis2.zadd(jobKey, runAt, JSON.stringify(job)).then(() => id3);
|
|
3869
3019
|
};
|
|
3870
3020
|
mw.process = function process2(type, handler) {
|
|
3871
3021
|
handlers.set(type, handler);
|
|
@@ -4803,8 +3953,8 @@ import { createOpenAI as createOpenAI2 } from "@ai-sdk/openai";
|
|
|
4803
3953
|
// agent/rest.ts
|
|
4804
3954
|
function buildRouter2(deps) {
|
|
4805
3955
|
const { agents: agentsTable, knowledge, runner } = deps;
|
|
4806
|
-
async function getAgent(
|
|
4807
|
-
const row = await agentsTable.read(
|
|
3956
|
+
async function getAgent(id3) {
|
|
3957
|
+
const row = await agentsTable.read(id3);
|
|
4808
3958
|
return row ?? null;
|
|
4809
3959
|
}
|
|
4810
3960
|
const r = new Router();
|
|
@@ -4831,8 +3981,8 @@ function buildRouter2(deps) {
|
|
|
4831
3981
|
return Response.json(agent2);
|
|
4832
3982
|
});
|
|
4833
3983
|
r.patch("/agents/:id", async (req, ctx) => {
|
|
4834
|
-
const
|
|
4835
|
-
const agent2 = await getAgent(
|
|
3984
|
+
const id3 = parseInt(ctx.params.id, 10);
|
|
3985
|
+
const agent2 = await getAgent(id3);
|
|
4836
3986
|
if (!agent2) return Response.json({ error: "Agent not found" }, { status: 404 });
|
|
4837
3987
|
const body = await req.json();
|
|
4838
3988
|
const updateData = {};
|
|
@@ -4844,23 +3994,23 @@ function buildRouter2(deps) {
|
|
|
4844
3994
|
if (Object.keys(updateData).length === 0) {
|
|
4845
3995
|
return Response.json({ error: "No fields to update" }, { status: 400 });
|
|
4846
3996
|
}
|
|
4847
|
-
const row = await agentsTable.update(
|
|
3997
|
+
const row = await agentsTable.update(id3, updateData);
|
|
4848
3998
|
return Response.json(row);
|
|
4849
3999
|
});
|
|
4850
4000
|
r.delete("/agents/:id", async (_req, ctx) => {
|
|
4851
|
-
const
|
|
4852
|
-
const row = await agentsTable.delete(
|
|
4001
|
+
const id3 = parseInt(ctx.params.id, 10);
|
|
4002
|
+
const row = await agentsTable.delete(id3);
|
|
4853
4003
|
if (!row) return Response.json({ error: "Agent not found" }, { status: 404 });
|
|
4854
4004
|
return Response.json({ ok: true });
|
|
4855
4005
|
});
|
|
4856
4006
|
r.post("/agents/:id/run", async (req, ctx) => {
|
|
4857
|
-
const
|
|
4007
|
+
const id3 = parseInt(ctx.params.id, 10);
|
|
4858
4008
|
const body = await req.json();
|
|
4859
4009
|
if (!body.input && !body.messages) {
|
|
4860
4010
|
return Response.json({ error: "input or messages is required" }, { status: 400 });
|
|
4861
4011
|
}
|
|
4862
4012
|
try {
|
|
4863
|
-
const result = await runner.run(
|
|
4013
|
+
const result = await runner.run(id3, body);
|
|
4864
4014
|
if ("stream" in result) {
|
|
4865
4015
|
return new Response(result.stream, {
|
|
4866
4016
|
headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache" }
|
|
@@ -5271,15 +4421,15 @@ function buildRouter3(deps) {
|
|
|
5271
4421
|
return Response.json(rows);
|
|
5272
4422
|
});
|
|
5273
4423
|
r.get("/channels/:id", async (_req, ctx) => {
|
|
5274
|
-
const
|
|
5275
|
-
const ch = await channels.read(
|
|
4424
|
+
const id3 = parseInt(ctx.params.id, 10);
|
|
4425
|
+
const ch = await channels.read(id3);
|
|
5276
4426
|
if (!ch) return Response.json({ error: "Channel not found" }, { status: 404 });
|
|
5277
|
-
const { data: memberRows } = await members.readMany({ channel_id:
|
|
4427
|
+
const { data: memberRows } = await members.readMany({ channel_id: id3 });
|
|
5278
4428
|
return Response.json({ channel: ch, members: memberRows });
|
|
5279
4429
|
});
|
|
5280
4430
|
r.delete("/channels/:id", async (_req, ctx) => {
|
|
5281
|
-
const
|
|
5282
|
-
await channels.delete(
|
|
4431
|
+
const id3 = parseInt(ctx.params.id, 10);
|
|
4432
|
+
await channels.delete(id3);
|
|
5283
4433
|
return Response.json({ ok: true });
|
|
5284
4434
|
});
|
|
5285
4435
|
r.post("/channels/:id/members", async (req, ctx) => {
|
|
@@ -5538,14 +4688,14 @@ function forkApp(opts) {
|
|
|
5538
4688
|
return { child, port: opts.port };
|
|
5539
4689
|
}
|
|
5540
4690
|
function stopProcess(mp, timeout = 1e4) {
|
|
5541
|
-
return new Promise((
|
|
4691
|
+
return new Promise((resolve12) => {
|
|
5542
4692
|
const timer = setTimeout(() => {
|
|
5543
4693
|
mp.child.kill("SIGKILL");
|
|
5544
|
-
|
|
4694
|
+
resolve12();
|
|
5545
4695
|
}, timeout);
|
|
5546
4696
|
mp.child.on("exit", () => {
|
|
5547
4697
|
clearTimeout(timer);
|
|
5548
|
-
|
|
4698
|
+
resolve12();
|
|
5549
4699
|
});
|
|
5550
4700
|
mp.child.kill("SIGTERM");
|
|
5551
4701
|
});
|
|
@@ -5974,6 +5124,366 @@ function ensureCertificates(config) {
|
|
|
5974
5124
|
// opencode/client.ts
|
|
5975
5125
|
import { createOpenAI as createOpenAI3 } from "@ai-sdk/openai";
|
|
5976
5126
|
|
|
5127
|
+
// opencode/rest.ts
|
|
5128
|
+
import { join as join4 } from "node:path";
|
|
5129
|
+
|
|
5130
|
+
// ssr/ssr.ts
|
|
5131
|
+
import { createElement } from "react";
|
|
5132
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
5133
|
+
import { dirname as dirname2, resolve as resolve4 } from "node:path";
|
|
5134
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
5135
|
+
|
|
5136
|
+
// ssr/compile.ts
|
|
5137
|
+
import * as esbuild from "esbuild";
|
|
5138
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2 } from "node:fs";
|
|
5139
|
+
import { join as join2, resolve as resolve3, dirname } from "node:path";
|
|
5140
|
+
import { pathToFileURL } from "node:url";
|
|
5141
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
5142
|
+
var OUT_DIR = ".weifuwu/ssr";
|
|
5143
|
+
var cache = /* @__PURE__ */ new Map();
|
|
5144
|
+
var externals = [
|
|
5145
|
+
"react",
|
|
5146
|
+
"react-dom",
|
|
5147
|
+
"esbuild",
|
|
5148
|
+
"graphql",
|
|
5149
|
+
"ws",
|
|
5150
|
+
"zod",
|
|
5151
|
+
"@graphql-tools/schema",
|
|
5152
|
+
"ai"
|
|
5153
|
+
];
|
|
5154
|
+
var _alias = null;
|
|
5155
|
+
function resolveAliases() {
|
|
5156
|
+
if (_alias) return _alias;
|
|
5157
|
+
const configFiles = ["tsconfig.json", "jsconfig.json"];
|
|
5158
|
+
for (const file of configFiles) {
|
|
5159
|
+
const p = resolve3(file);
|
|
5160
|
+
if (existsSync2(p)) {
|
|
5161
|
+
try {
|
|
5162
|
+
const config = JSON.parse(readFileSync2(p, "utf-8"));
|
|
5163
|
+
const paths = config.compilerOptions?.paths;
|
|
5164
|
+
if (paths) {
|
|
5165
|
+
const alias = {};
|
|
5166
|
+
for (const [key, values] of Object.entries(paths)) {
|
|
5167
|
+
const cleanKey = key.replace("/*", "");
|
|
5168
|
+
const val = values[0]?.replace("/*", "");
|
|
5169
|
+
if (val) alias[cleanKey] = resolve3(dirname(p), val);
|
|
5170
|
+
}
|
|
5171
|
+
_alias = alias;
|
|
5172
|
+
return alias;
|
|
5173
|
+
}
|
|
5174
|
+
} catch {
|
|
5175
|
+
}
|
|
5176
|
+
}
|
|
5177
|
+
}
|
|
5178
|
+
_alias = {};
|
|
5179
|
+
return {};
|
|
5180
|
+
}
|
|
5181
|
+
function id(s) {
|
|
5182
|
+
return createHash2("md5").update(s).digest("hex").slice(0, 8);
|
|
5183
|
+
}
|
|
5184
|
+
async function compileTsx(path2) {
|
|
5185
|
+
if (cache.has(path2)) return cache.get(path2);
|
|
5186
|
+
const absPath = resolve3(path2);
|
|
5187
|
+
mkdirSync(OUT_DIR, { recursive: true });
|
|
5188
|
+
const hash = id(absPath);
|
|
5189
|
+
const outPath = join2(OUT_DIR, hash + ".js");
|
|
5190
|
+
await esbuild.build({
|
|
5191
|
+
entryPoints: { [hash]: absPath },
|
|
5192
|
+
outdir: OUT_DIR,
|
|
5193
|
+
format: "esm",
|
|
5194
|
+
platform: "node",
|
|
5195
|
+
jsx: "automatic",
|
|
5196
|
+
jsxImportSource: "react",
|
|
5197
|
+
bundle: true,
|
|
5198
|
+
external: externals,
|
|
5199
|
+
alias: resolveAliases(),
|
|
5200
|
+
write: true,
|
|
5201
|
+
allowOverwrite: true
|
|
5202
|
+
});
|
|
5203
|
+
const mod = await import(pathToFileURL(outPath).href);
|
|
5204
|
+
cache.set(path2, mod);
|
|
5205
|
+
return mod;
|
|
5206
|
+
}
|
|
5207
|
+
|
|
5208
|
+
// ssr/stream.ts
|
|
5209
|
+
import { TextDecoder, TextEncoder as TextEncoder2 } from "node:util";
|
|
5210
|
+
var _publicEnv = null;
|
|
5211
|
+
function getPublicEnv() {
|
|
5212
|
+
if (_publicEnv) return _publicEnv;
|
|
5213
|
+
_publicEnv = {};
|
|
5214
|
+
for (const key of Object.keys(process.env)) {
|
|
5215
|
+
if (key.startsWith("WEIFUWU_PUBLIC_")) {
|
|
5216
|
+
_publicEnv[key] = process.env[key];
|
|
5217
|
+
}
|
|
5218
|
+
}
|
|
5219
|
+
return _publicEnv;
|
|
5220
|
+
}
|
|
5221
|
+
function buildHeadPayload(opts) {
|
|
5222
|
+
const { ctx, base, compiledTailwindCss } = opts;
|
|
5223
|
+
let result = "";
|
|
5224
|
+
if (ctx.prefs?.theme) {
|
|
5225
|
+
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>
|
|
5226
|
+
`;
|
|
5227
|
+
}
|
|
5228
|
+
if (compiledTailwindCss) {
|
|
5229
|
+
result += `<link rel="stylesheet" href="${base}/__wfw/style.css" />
|
|
5230
|
+
`;
|
|
5231
|
+
}
|
|
5232
|
+
const localeData = ctx.parsed?.__localeData ?? globalThis.__LOCALE_DATA__;
|
|
5233
|
+
if (localeData && Object.keys(localeData).length > 0) {
|
|
5234
|
+
result += `<script>window.__LOCALE_DATA__=${JSON.stringify(localeData)}</script>
|
|
5235
|
+
`;
|
|
5236
|
+
}
|
|
5237
|
+
const loaderData = opts.loaderData || {};
|
|
5238
|
+
const ctxData = {
|
|
5239
|
+
params: ctx.params,
|
|
5240
|
+
query: ctx.query,
|
|
5241
|
+
user: ctx.user,
|
|
5242
|
+
parsed: ctx.parsed,
|
|
5243
|
+
prefs: ctx.prefs,
|
|
5244
|
+
loaderData
|
|
5245
|
+
};
|
|
5246
|
+
const publicEnv = getPublicEnv();
|
|
5247
|
+
if (Object.keys(publicEnv).length > 0) {
|
|
5248
|
+
ctxData.env = publicEnv;
|
|
5249
|
+
}
|
|
5250
|
+
result += `<script>window.__WEIFUWU_CTX=${JSON.stringify(ctxData)}</script>
|
|
5251
|
+
`;
|
|
5252
|
+
return result;
|
|
5253
|
+
}
|
|
5254
|
+
function buildBodyScripts(opts) {
|
|
5255
|
+
const parts = [];
|
|
5256
|
+
if (opts.loaderData && Object.keys(opts.loaderData).length > 0) {
|
|
5257
|
+
parts.push(`<script>window.__WEIFUWU_PROPS=${JSON.stringify(opts.loaderData)}</script>`);
|
|
5258
|
+
}
|
|
5259
|
+
if (opts.bundle) {
|
|
5260
|
+
parts.push(`<script type="module" src="${opts.base}${opts.bundle.url}"></script>`);
|
|
5261
|
+
}
|
|
5262
|
+
return parts.join("\n");
|
|
5263
|
+
}
|
|
5264
|
+
function streamResponse(reactStream, opts) {
|
|
5265
|
+
const decoder = new TextDecoder();
|
|
5266
|
+
const encoder2 = new TextEncoder2();
|
|
5267
|
+
const headPayload = buildHeadPayload(opts);
|
|
5268
|
+
let buffer = "";
|
|
5269
|
+
let headFlushed = false;
|
|
5270
|
+
let extractedHead = "";
|
|
5271
|
+
const output = new ReadableStream({
|
|
5272
|
+
async start(controller) {
|
|
5273
|
+
try {
|
|
5274
|
+
const reader = reactStream.getReader();
|
|
5275
|
+
async function push(chunk) {
|
|
5276
|
+
buffer += decoder.decode(chunk, { stream: true });
|
|
5277
|
+
if (!extractedHead) {
|
|
5278
|
+
const m = buffer.match(/<template id="__wfw_head">([\s\S]*?)<\/template>/);
|
|
5279
|
+
if (m) {
|
|
5280
|
+
extractedHead = m[1];
|
|
5281
|
+
buffer = buffer.replace(m[0], "");
|
|
5282
|
+
}
|
|
5283
|
+
}
|
|
5284
|
+
if (!headFlushed) {
|
|
5285
|
+
const idx = buffer.indexOf("</head>");
|
|
5286
|
+
if (idx !== -1) {
|
|
5287
|
+
const before = buffer.slice(0, idx);
|
|
5288
|
+
let injection = "";
|
|
5289
|
+
if (extractedHead) injection += "\n" + extractedHead;
|
|
5290
|
+
injection += headPayload;
|
|
5291
|
+
controller.enqueue(encoder2.encode(before + injection));
|
|
5292
|
+
buffer = buffer.slice(idx);
|
|
5293
|
+
headFlushed = true;
|
|
5294
|
+
}
|
|
5295
|
+
return;
|
|
5296
|
+
}
|
|
5297
|
+
controller.enqueue(encoder2.encode(buffer));
|
|
5298
|
+
buffer = "";
|
|
5299
|
+
}
|
|
5300
|
+
while (true) {
|
|
5301
|
+
const { done, value } = await reader.read();
|
|
5302
|
+
if (done) break;
|
|
5303
|
+
await push(value);
|
|
5304
|
+
}
|
|
5305
|
+
buffer = buffer.replace(/<template id="__wfw_head">[\s\S]*?<\/template>/g, "");
|
|
5306
|
+
if (buffer) controller.enqueue(encoder2.encode(buffer));
|
|
5307
|
+
const body = buildBodyScripts(opts);
|
|
5308
|
+
if (body) controller.enqueue(encoder2.encode("\n" + body));
|
|
5309
|
+
if (opts.isDev) {
|
|
5310
|
+
controller.enqueue(encoder2.encode(
|
|
5311
|
+
`
|
|
5312
|
+
<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>`
|
|
5313
|
+
));
|
|
5314
|
+
}
|
|
5315
|
+
} catch {
|
|
5316
|
+
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>`;
|
|
5317
|
+
controller.enqueue(encoder2.encode(fallback));
|
|
5318
|
+
} finally {
|
|
5319
|
+
controller.close();
|
|
5320
|
+
}
|
|
5321
|
+
}
|
|
5322
|
+
});
|
|
5323
|
+
return new Response(output, {
|
|
5324
|
+
status: opts.status ?? 200,
|
|
5325
|
+
headers: { "content-type": "text/html; charset=utf-8" }
|
|
5326
|
+
});
|
|
5327
|
+
}
|
|
5328
|
+
|
|
5329
|
+
// ssr/ssr.ts
|
|
5330
|
+
var als = new AsyncLocalStorage();
|
|
5331
|
+
__registerAls(() => als.getStore());
|
|
5332
|
+
var isDev = process.env.NODE_ENV !== "production";
|
|
5333
|
+
function id2(s) {
|
|
5334
|
+
return createHash3("md5").update(s).digest("hex").slice(0, 8);
|
|
5335
|
+
}
|
|
5336
|
+
async function buildClientBundle(entryPath, layoutPaths) {
|
|
5337
|
+
try {
|
|
5338
|
+
const absEntry = resolve4(entryPath);
|
|
5339
|
+
const absLayouts = layoutPaths.map((p) => resolve4(p));
|
|
5340
|
+
const layoutImports = absLayouts.map((p) => `import${JSON.stringify(p)};`).join("");
|
|
5341
|
+
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()})}})()`;
|
|
5342
|
+
const code = [
|
|
5343
|
+
layoutImports,
|
|
5344
|
+
`import{hydrateRoot}from'react-dom/client';`,
|
|
5345
|
+
`import{createElement,useState,useEffect}from'react';`,
|
|
5346
|
+
`import{TsxContext}from'weifuwu/react';`,
|
|
5347
|
+
`import P from${JSON.stringify(absEntry)};`,
|
|
5348
|
+
`var setCtx=${_sc};`,
|
|
5349
|
+
`const c=document.getElementById('__weifuwu_root');`,
|
|
5350
|
+
`if(window.__WEIFUWU_PROPS)setCtx({loaderData:window.__WEIFUWU_PROPS});`,
|
|
5351
|
+
`if(!window.__WFW_ROOT){`,
|
|
5352
|
+
`function App(){`,
|
|
5353
|
+
`const[p,setP]=useState({C:P});`,
|
|
5354
|
+
`useEffect(()=>{window.__WFW_SET_PAGE=(C)=>{setCtx({loaderData:window.__WEIFUWU_PROPS});setP({C})}},[]);`,
|
|
5355
|
+
`const ctx=window.__WEIFUWU_CTX||{};`,
|
|
5356
|
+
`return createElement(TsxContext.Provider,{value:ctx},`,
|
|
5357
|
+
`createElement(p.C,null))`,
|
|
5358
|
+
`}`,
|
|
5359
|
+
`window.__WFW_ROOT=hydrateRoot(c,createElement(App));`,
|
|
5360
|
+
`}else{`,
|
|
5361
|
+
`window.__WFW_SET_PAGE?.(P);`,
|
|
5362
|
+
`}`
|
|
5363
|
+
].join("");
|
|
5364
|
+
const { default: esbuild2 } = await import("esbuild");
|
|
5365
|
+
const result = await esbuild2.build({
|
|
5366
|
+
stdin: { contents: code, loader: "tsx", resolveDir: dirname2(absEntry) },
|
|
5367
|
+
bundle: true,
|
|
5368
|
+
format: "esm",
|
|
5369
|
+
jsx: "automatic",
|
|
5370
|
+
jsxImportSource: "react",
|
|
5371
|
+
banner: { js: "self.process={env:{}};" },
|
|
5372
|
+
loader: { ".node": "empty" },
|
|
5373
|
+
write: false,
|
|
5374
|
+
minify: true
|
|
5375
|
+
});
|
|
5376
|
+
return result.outputFiles[0].contents;
|
|
5377
|
+
} catch (err) {
|
|
5378
|
+
console.error("hydration bundle failed:", err);
|
|
5379
|
+
return null;
|
|
5380
|
+
}
|
|
5381
|
+
}
|
|
5382
|
+
var bundleRegistry = /* @__PURE__ */ new Map();
|
|
5383
|
+
function serializeLoaderData(ctx) {
|
|
5384
|
+
const data = {};
|
|
5385
|
+
for (const key of Object.keys(ctx)) {
|
|
5386
|
+
if (!["params", "query", "mountPath", "layoutStack"].includes(key)) {
|
|
5387
|
+
data[key] = ctx[key];
|
|
5388
|
+
}
|
|
5389
|
+
}
|
|
5390
|
+
return data;
|
|
5391
|
+
}
|
|
5392
|
+
function ssr(path2) {
|
|
5393
|
+
const entryId = id2(resolve4(path2));
|
|
5394
|
+
const bundleKey = `/__ssr/${entryId}.js`;
|
|
5395
|
+
let bundleBuilt = false;
|
|
5396
|
+
return async (req, ctx) => {
|
|
5397
|
+
const pageMod = await compileTsx(path2);
|
|
5398
|
+
const Component = pageMod.default;
|
|
5399
|
+
if (!Component) return new Response("", { status: 500 });
|
|
5400
|
+
const layouts = ctx.layoutStack || [];
|
|
5401
|
+
const layoutComponents = layouts.map((l) => l.component);
|
|
5402
|
+
const layoutPaths = layouts.map((l) => l.path);
|
|
5403
|
+
const base = (ctx.mountPath || "").replace(/\/$/, "");
|
|
5404
|
+
const loaderData = serializeLoaderData(ctx);
|
|
5405
|
+
const ctxValue = {
|
|
5406
|
+
params: ctx.params,
|
|
5407
|
+
query: ctx.query,
|
|
5408
|
+
user: ctx.user ?? {},
|
|
5409
|
+
parsed: ctx.parsed ?? {},
|
|
5410
|
+
prefs: ctx.prefs ?? {},
|
|
5411
|
+
loaderData,
|
|
5412
|
+
env: ctx.env ?? {}
|
|
5413
|
+
};
|
|
5414
|
+
return als.run(ctxValue, async () => {
|
|
5415
|
+
setCtx(ctxValue);
|
|
5416
|
+
let element = createElement(
|
|
5417
|
+
TsxContext.Provider,
|
|
5418
|
+
{ value: ctxValue },
|
|
5419
|
+
createElement(
|
|
5420
|
+
"div",
|
|
5421
|
+
{ id: "__weifuwu_root" },
|
|
5422
|
+
createElement(Component, null)
|
|
5423
|
+
)
|
|
5424
|
+
);
|
|
5425
|
+
if (layoutComponents.length === 0) {
|
|
5426
|
+
element = createElement(
|
|
5427
|
+
"html",
|
|
5428
|
+
{ lang: "en" },
|
|
5429
|
+
createElement(
|
|
5430
|
+
"head",
|
|
5431
|
+
null,
|
|
5432
|
+
createElement("meta", { charSet: "utf-8" }),
|
|
5433
|
+
createElement("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
|
|
5434
|
+
createElement("title", null, "weifuwu")
|
|
5435
|
+
),
|
|
5436
|
+
createElement("body", null, element)
|
|
5437
|
+
);
|
|
5438
|
+
} else {
|
|
5439
|
+
for (const L of layoutComponents.toReversed()) {
|
|
5440
|
+
element = createElement(L, { children: element });
|
|
5441
|
+
}
|
|
5442
|
+
}
|
|
5443
|
+
let bundle = null;
|
|
5444
|
+
if (!bundleBuilt) {
|
|
5445
|
+
const buf = await buildClientBundle(path2, layoutPaths);
|
|
5446
|
+
if (buf) {
|
|
5447
|
+
bundleRegistry.set(bundleKey, buf);
|
|
5448
|
+
bundleBuilt = true;
|
|
5449
|
+
}
|
|
5450
|
+
}
|
|
5451
|
+
if (bundleRegistry.has(bundleKey)) {
|
|
5452
|
+
bundle = { url: bundleKey };
|
|
5453
|
+
}
|
|
5454
|
+
const { renderToReadableStream } = await import("react-dom/server");
|
|
5455
|
+
const stream = await renderToReadableStream(element);
|
|
5456
|
+
return streamResponse(stream, {
|
|
5457
|
+
ctx,
|
|
5458
|
+
base,
|
|
5459
|
+
isDev,
|
|
5460
|
+
bundle,
|
|
5461
|
+
loaderData
|
|
5462
|
+
});
|
|
5463
|
+
});
|
|
5464
|
+
};
|
|
5465
|
+
}
|
|
5466
|
+
|
|
5467
|
+
// ssr/layout.ts
|
|
5468
|
+
function layout(path2) {
|
|
5469
|
+
return async (req, ctx, next) => {
|
|
5470
|
+
const mod = await compileTsx(path2);
|
|
5471
|
+
const Component = mod.default;
|
|
5472
|
+
if (!Component) throw new Error(`Layout ${path2} has no default export`);
|
|
5473
|
+
ctx.layoutStack = [...ctx.layoutStack || [], { path: path2, component: Component }];
|
|
5474
|
+
return next(req, ctx);
|
|
5475
|
+
};
|
|
5476
|
+
}
|
|
5477
|
+
|
|
5478
|
+
// ssr/tailwind.ts
|
|
5479
|
+
var isDev2 = process.env.NODE_ENV !== "production";
|
|
5480
|
+
|
|
5481
|
+
// ssr/error-boundary.ts
|
|
5482
|
+
import { createElement as createElement2 } from "react";
|
|
5483
|
+
|
|
5484
|
+
// ssr/live.ts
|
|
5485
|
+
import chokidar from "chokidar";
|
|
5486
|
+
|
|
5977
5487
|
// opencode/session.ts
|
|
5978
5488
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
5979
5489
|
import { join as join3 } from "node:path";
|
|
@@ -6001,12 +5511,12 @@ var messages = pgTable("_opencode_messages", {
|
|
|
6001
5511
|
created_at: timestamptz("created_at")
|
|
6002
5512
|
});
|
|
6003
5513
|
async function createSession(sql2, opts, cwd, mountPath) {
|
|
6004
|
-
const
|
|
6005
|
-
const ws = computeSessionWorkspace(cwd, mountPath,
|
|
5514
|
+
const id3 = randomUUID2();
|
|
5515
|
+
const ws = computeSessionWorkspace(cwd, mountPath, id3);
|
|
6006
5516
|
await mkdir2(ws, { recursive: true });
|
|
6007
5517
|
const [row] = await sql2`
|
|
6008
5518
|
INSERT INTO "_opencode_sessions" ("id", "user_id", "title", "model", "workspace", "system_prompt")
|
|
6009
|
-
VALUES (${
|
|
5519
|
+
VALUES (${id3}, ${opts.userId ?? 0}, ${opts.title ?? null}, ${opts.model ?? "deepseek-v4-flash"}, ${ws}, ${opts.systemPrompt ?? null})
|
|
6010
5520
|
RETURNING *
|
|
6011
5521
|
`;
|
|
6012
5522
|
return row;
|
|
@@ -6015,8 +5525,8 @@ function computeSessionWorkspace(cwd, mountPath, sessionId) {
|
|
|
6015
5525
|
const name = !mountPath || mountPath === "/" ? "default" : mountPath.replace(/^\//, "");
|
|
6016
5526
|
return join3(cwd, ".sessions", name, sessionId);
|
|
6017
5527
|
}
|
|
6018
|
-
async function getSession(sql2,
|
|
6019
|
-
const { data: rows } = await sessions.readMany(sql2, { id:
|
|
5528
|
+
async function getSession(sql2, id3) {
|
|
5529
|
+
const { data: rows } = await sessions.readMany(sql2, { id: id3, active: true });
|
|
6020
5530
|
return rows[0] ?? null;
|
|
6021
5531
|
}
|
|
6022
5532
|
async function listSessions(sql2, userId) {
|
|
@@ -6028,8 +5538,8 @@ async function listSessions(sql2, userId) {
|
|
|
6028
5538
|
const { data: rows } = await sessions.readMany(sql2, { active: true }, opts);
|
|
6029
5539
|
return rows;
|
|
6030
5540
|
}
|
|
6031
|
-
async function deleteSession(sql2,
|
|
6032
|
-
await sessions.update(sql2,
|
|
5541
|
+
async function deleteSession(sql2, id3) {
|
|
5542
|
+
await sessions.update(sql2, id3, { active: false, updated_at: sql`NOW()` });
|
|
6033
5543
|
}
|
|
6034
5544
|
async function getHistory(sql2, sessionId, limit = 50) {
|
|
6035
5545
|
const { data: rows } = await messages.readMany(sql2, { session_id: sessionId }, {
|
|
@@ -6210,10 +5720,10 @@ function createBashTool(ctx) {
|
|
|
6210
5720
|
return { stdout: "", stderr: "Command denied: potentially dangerous command", exitCode: 1 };
|
|
6211
5721
|
}
|
|
6212
5722
|
const cwd = workdir ? `${ctx.workspace}/${workdir}` : ctx.workspace;
|
|
6213
|
-
return new Promise((
|
|
5723
|
+
return new Promise((resolve12) => {
|
|
6214
5724
|
const child = exec(command, { cwd, timeout: timeout * 1e3, maxBuffer: 1024 * 1024 }, (error, stdout, stderr) => {
|
|
6215
5725
|
const truncated = stdout.length > 1e6 || stderr.length > 1e6;
|
|
6216
|
-
|
|
5726
|
+
resolve12({
|
|
6217
5727
|
stdout: stdout.slice(0, 1e6),
|
|
6218
5728
|
stderr: stderr.slice(0, 1e6),
|
|
6219
5729
|
exitCode: error?.code ?? 0,
|
|
@@ -6230,7 +5740,7 @@ function createBashTool(ctx) {
|
|
|
6230
5740
|
import { tool as tool4 } from "ai";
|
|
6231
5741
|
import { z as z6 } from "zod";
|
|
6232
5742
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
6233
|
-
import { resolve as
|
|
5743
|
+
import { resolve as resolve5 } from "node:path";
|
|
6234
5744
|
function createReadTool(ctx) {
|
|
6235
5745
|
return tool4({
|
|
6236
5746
|
description: "Read file contents. Supports offset and limit for reading specific line ranges.",
|
|
@@ -6240,7 +5750,7 @@ function createReadTool(ctx) {
|
|
|
6240
5750
|
limit: z6.number().optional().describe("Number of lines to read")
|
|
6241
5751
|
}),
|
|
6242
5752
|
execute: async ({ path: path2, offset, limit }) => {
|
|
6243
|
-
const resolved =
|
|
5753
|
+
const resolved = resolve5(ctx.workspace, path2);
|
|
6244
5754
|
if (!isPathAllowed(resolved, ctx.workspace, ctx.permissions)) {
|
|
6245
5755
|
return { error: "Path not allowed", content: null, totalLines: 0 };
|
|
6246
5756
|
}
|
|
@@ -6271,8 +5781,8 @@ function createReadTool(ctx) {
|
|
|
6271
5781
|
// opencode/tools/write.ts
|
|
6272
5782
|
import { tool as tool5 } from "ai";
|
|
6273
5783
|
import { z as z7 } from "zod";
|
|
6274
|
-
import { writeFileSync
|
|
6275
|
-
import { resolve as
|
|
5784
|
+
import { writeFileSync, mkdirSync as mkdirSync2 } from "node:fs";
|
|
5785
|
+
import { resolve as resolve6, dirname as dirname3 } from "node:path";
|
|
6276
5786
|
function createWriteTool(ctx) {
|
|
6277
5787
|
return tool5({
|
|
6278
5788
|
description: "Create or overwrite a file. Parent directories are created automatically.",
|
|
@@ -6281,12 +5791,12 @@ function createWriteTool(ctx) {
|
|
|
6281
5791
|
content: z7.string().describe("File content")
|
|
6282
5792
|
}),
|
|
6283
5793
|
execute: async ({ path: path2, content }) => {
|
|
6284
|
-
const resolved =
|
|
5794
|
+
const resolved = resolve6(ctx.workspace, path2);
|
|
6285
5795
|
if (!isPathAllowed(resolved, ctx.workspace, ctx.permissions)) {
|
|
6286
5796
|
return { error: "Path not allowed" };
|
|
6287
5797
|
}
|
|
6288
|
-
mkdirSync2(
|
|
6289
|
-
|
|
5798
|
+
mkdirSync2(dirname3(resolved), { recursive: true });
|
|
5799
|
+
writeFileSync(resolved, content, "utf-8");
|
|
6290
5800
|
return { path: path2, size: content.length };
|
|
6291
5801
|
}
|
|
6292
5802
|
});
|
|
@@ -6295,8 +5805,8 @@ function createWriteTool(ctx) {
|
|
|
6295
5805
|
// opencode/tools/edit.ts
|
|
6296
5806
|
import { tool as tool6 } from "ai";
|
|
6297
5807
|
import { z as z8 } from "zod";
|
|
6298
|
-
import { readFileSync as readFileSync4, writeFileSync as
|
|
6299
|
-
import { resolve as
|
|
5808
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "node:fs";
|
|
5809
|
+
import { resolve as resolve7 } from "node:path";
|
|
6300
5810
|
function createEditTool(ctx) {
|
|
6301
5811
|
return tool6({
|
|
6302
5812
|
description: "Perform exact string replacements in a file. If oldString appears multiple times, provide more surrounding context.",
|
|
@@ -6307,7 +5817,7 @@ function createEditTool(ctx) {
|
|
|
6307
5817
|
replaceAll: z8.boolean().default(false).describe("Replace all occurrences")
|
|
6308
5818
|
}),
|
|
6309
5819
|
execute: async ({ path: path2, oldString, newString, replaceAll }) => {
|
|
6310
|
-
const resolved =
|
|
5820
|
+
const resolved = resolve7(ctx.workspace, path2);
|
|
6311
5821
|
if (!isPathAllowed(resolved, ctx.workspace, ctx.permissions)) {
|
|
6312
5822
|
return { error: "Path not allowed" };
|
|
6313
5823
|
}
|
|
@@ -6318,7 +5828,7 @@ function createEditTool(ctx) {
|
|
|
6318
5828
|
}
|
|
6319
5829
|
const count = content.split(oldString).length - 1;
|
|
6320
5830
|
const result2 = content.replaceAll(oldString, newString);
|
|
6321
|
-
|
|
5831
|
+
writeFileSync2(resolved, result2, "utf-8");
|
|
6322
5832
|
return { path: path2, replaced: count };
|
|
6323
5833
|
}
|
|
6324
5834
|
const firstIdx = content.indexOf(oldString);
|
|
@@ -6330,7 +5840,7 @@ function createEditTool(ctx) {
|
|
|
6330
5840
|
return { error: "Found multiple matches. Provide more surrounding context in oldString.", replaced: 0 };
|
|
6331
5841
|
}
|
|
6332
5842
|
const result = content.replace(oldString, newString);
|
|
6333
|
-
|
|
5843
|
+
writeFileSync2(resolved, result, "utf-8");
|
|
6334
5844
|
return { path: path2, replaced: 1 };
|
|
6335
5845
|
}
|
|
6336
5846
|
});
|
|
@@ -6340,7 +5850,7 @@ function createEditTool(ctx) {
|
|
|
6340
5850
|
import { tool as tool7 } from "ai";
|
|
6341
5851
|
import { z as z9 } from "zod";
|
|
6342
5852
|
import { execFileSync } from "node:child_process";
|
|
6343
|
-
import { resolve as
|
|
5853
|
+
import { resolve as resolve8 } from "node:path";
|
|
6344
5854
|
import { existsSync as existsSync3 } from "node:fs";
|
|
6345
5855
|
function createGrepTool(ctx) {
|
|
6346
5856
|
return tool7({
|
|
@@ -6352,7 +5862,7 @@ function createGrepTool(ctx) {
|
|
|
6352
5862
|
context: z9.number().default(0).describe("Number of context lines before and after each match")
|
|
6353
5863
|
}),
|
|
6354
5864
|
execute: async ({ pattern, include, path: path2, context }) => {
|
|
6355
|
-
const searchDir = path2 ?
|
|
5865
|
+
const searchDir = path2 ? resolve8(ctx.workspace, path2) : ctx.workspace;
|
|
6356
5866
|
try {
|
|
6357
5867
|
let stdout;
|
|
6358
5868
|
if (existsSync3("/usr/bin/rg") || existsSync3("/usr/local/bin/rg")) {
|
|
@@ -6384,7 +5894,7 @@ function createGrepTool(ctx) {
|
|
|
6384
5894
|
import { tool as tool8 } from "ai";
|
|
6385
5895
|
import { z as z10 } from "zod";
|
|
6386
5896
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
6387
|
-
import { resolve as
|
|
5897
|
+
import { resolve as resolve9 } from "node:path";
|
|
6388
5898
|
function createGlobTool(ctx) {
|
|
6389
5899
|
return tool8({
|
|
6390
5900
|
description: "Find files matching a glob pattern.",
|
|
@@ -6393,7 +5903,7 @@ function createGlobTool(ctx) {
|
|
|
6393
5903
|
path: z10.string().optional().describe("Subdirectory relative to workspace")
|
|
6394
5904
|
}),
|
|
6395
5905
|
execute: async ({ pattern, path: path2 }) => {
|
|
6396
|
-
const searchDir = path2 ?
|
|
5906
|
+
const searchDir = path2 ? resolve9(ctx.workspace, path2) : ctx.workspace;
|
|
6397
5907
|
try {
|
|
6398
5908
|
const stdout = execFileSync2("find", [
|
|
6399
5909
|
searchDir,
|
|
@@ -6454,7 +5964,7 @@ function createQuestionTool(ctx) {
|
|
|
6454
5964
|
options: z12.array(z12.string()).optional().describe("Optional multiple choice options")
|
|
6455
5965
|
}),
|
|
6456
5966
|
execute: async ({ question, options }, { toolCallId }) => {
|
|
6457
|
-
return new Promise((
|
|
5967
|
+
return new Promise((resolve12, reject) => {
|
|
6458
5968
|
const timeout = setTimeout(() => {
|
|
6459
5969
|
ctx.pendingQuestions.delete(toolCallId);
|
|
6460
5970
|
reject(new Error("Question timed out"));
|
|
@@ -6462,7 +5972,7 @@ function createQuestionTool(ctx) {
|
|
|
6462
5972
|
ctx.pendingQuestions.set(toolCallId, {
|
|
6463
5973
|
resolve: (answer) => {
|
|
6464
5974
|
clearTimeout(timeout);
|
|
6465
|
-
|
|
5975
|
+
resolve12(answer);
|
|
6466
5976
|
},
|
|
6467
5977
|
reject: (err) => {
|
|
6468
5978
|
clearTimeout(timeout);
|
|
@@ -6563,15 +6073,15 @@ async function buildRouter4(deps) {
|
|
|
6563
6073
|
return Response.json(sessions2);
|
|
6564
6074
|
});
|
|
6565
6075
|
router.get("/sessions/:id", async (_req, ctx) => {
|
|
6566
|
-
const
|
|
6567
|
-
const session = await getSession(sql2,
|
|
6076
|
+
const id3 = ctx.params.id;
|
|
6077
|
+
const session = await getSession(sql2, id3);
|
|
6568
6078
|
if (!session) return new Response("Not Found", { status: 404 });
|
|
6569
|
-
const messages2 = await getHistory(sql2,
|
|
6079
|
+
const messages2 = await getHistory(sql2, id3);
|
|
6570
6080
|
return Response.json({ session, messages: messages2 });
|
|
6571
6081
|
});
|
|
6572
6082
|
router.delete("/sessions/:id", async (_req, ctx) => {
|
|
6573
|
-
const
|
|
6574
|
-
await deleteSession(sql2,
|
|
6083
|
+
const id3 = ctx.params.id;
|
|
6084
|
+
await deleteSession(sql2, id3);
|
|
6575
6085
|
return new Response(null, { status: 204 });
|
|
6576
6086
|
});
|
|
6577
6087
|
router.post("/sessions/:id/message", async (req, ctx) => {
|
|
@@ -6609,8 +6119,8 @@ async function buildRouter4(deps) {
|
|
|
6609
6119
|
});
|
|
6610
6120
|
try {
|
|
6611
6121
|
const uiDir = new URL("../opencode/ui/", import.meta.url).pathname;
|
|
6612
|
-
|
|
6613
|
-
router.
|
|
6122
|
+
router.use(layout(join4(uiDir, "layout.tsx")));
|
|
6123
|
+
router.get("/", ssr(join4(uiDir, "page.tsx")));
|
|
6614
6124
|
} catch (e) {
|
|
6615
6125
|
console.warn("[opencode] UI not available:", e);
|
|
6616
6126
|
}
|
|
@@ -6745,7 +6255,7 @@ function createWSHandler2(deps) {
|
|
|
6745
6255
|
import { readFile } from "node:fs/promises";
|
|
6746
6256
|
import { glob } from "node:fs/promises";
|
|
6747
6257
|
import { homedir } from "node:os";
|
|
6748
|
-
import { resolve as
|
|
6258
|
+
import { resolve as resolve10 } from "node:path";
|
|
6749
6259
|
import { parse as parseYaml } from "yaml";
|
|
6750
6260
|
var SEARCH_DIRS = [
|
|
6751
6261
|
(ws) => `${ws}/.opencode/skills`,
|
|
@@ -6783,7 +6293,7 @@ async function scanDir(dir) {
|
|
|
6783
6293
|
try {
|
|
6784
6294
|
const files = [];
|
|
6785
6295
|
for await (const entry of glob("*/SKILL.md", { cwd: dir })) {
|
|
6786
|
-
const skill = await parseSkillFile(
|
|
6296
|
+
const skill = await parseSkillFile(resolve10(dir, entry));
|
|
6787
6297
|
if (skill) files.push(skill);
|
|
6788
6298
|
}
|
|
6789
6299
|
return files;
|
|
@@ -7119,7 +6629,7 @@ function analytics(options) {
|
|
|
7119
6629
|
// preferences.ts
|
|
7120
6630
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
7121
6631
|
import { existsSync as existsSync4 } from "node:fs";
|
|
7122
|
-
import { join as
|
|
6632
|
+
import { join as join5, resolve as resolve11 } from "node:path";
|
|
7123
6633
|
var defaults = {
|
|
7124
6634
|
locale: { default: "en", cookie: "locale", fromAcceptLanguage: true },
|
|
7125
6635
|
theme: { default: "system", cookie: "theme" }
|
|
@@ -7168,24 +6678,24 @@ async function handlePrefSwitch(req, value, cookieName, load) {
|
|
|
7168
6678
|
});
|
|
7169
6679
|
}
|
|
7170
6680
|
function preferences(options) {
|
|
7171
|
-
const dir = options.dir ?
|
|
6681
|
+
const dir = options.dir ? resolve11(options.dir) : void 0;
|
|
7172
6682
|
const localeOpts = { ...defaults.locale, ...options.locale };
|
|
7173
6683
|
const themeOpts = { ...defaults.theme, ...options.theme };
|
|
7174
|
-
const
|
|
6684
|
+
const cache2 = /* @__PURE__ */ new Map();
|
|
7175
6685
|
function validLocale(locale) {
|
|
7176
6686
|
return /^[\w-]+$/.test(locale) && !locale.includes("..");
|
|
7177
6687
|
}
|
|
7178
6688
|
async function load(locale) {
|
|
7179
6689
|
if (!dir) return {};
|
|
7180
6690
|
if (!validLocale(locale)) return {};
|
|
7181
|
-
const cached =
|
|
6691
|
+
const cached = cache2.get(locale);
|
|
7182
6692
|
if (cached) return cached;
|
|
7183
|
-
const filePath =
|
|
6693
|
+
const filePath = join5(dir, `${locale}.json`);
|
|
7184
6694
|
if (!existsSync4(filePath)) return {};
|
|
7185
6695
|
try {
|
|
7186
6696
|
const content = await readFile2(filePath, "utf-8");
|
|
7187
6697
|
const data = JSON.parse(content);
|
|
7188
|
-
|
|
6698
|
+
cache2.set(locale, data);
|
|
7189
6699
|
return data;
|
|
7190
6700
|
} catch {
|
|
7191
6701
|
return {};
|
|
@@ -7532,9 +7042,9 @@ function listHandler(entries) {
|
|
|
7532
7042
|
}
|
|
7533
7043
|
function getHandler(entries) {
|
|
7534
7044
|
return async (_req, ctx) => {
|
|
7535
|
-
const
|
|
7536
|
-
if (!
|
|
7537
|
-
const row = await entries.read(parseInt(
|
|
7045
|
+
const id3 = ctx.params?.id;
|
|
7046
|
+
if (!id3) return Response.json({ error: "id is required" }, { status: 400 });
|
|
7047
|
+
const row = await entries.read(parseInt(id3));
|
|
7538
7048
|
if (!row) return Response.json({ error: "not found" }, { status: 404 });
|
|
7539
7049
|
return Response.json(parseMetadata(row));
|
|
7540
7050
|
};
|
|
@@ -7752,8 +7262,8 @@ function createMemoryStore(channels) {
|
|
|
7752
7262
|
}));
|
|
7753
7263
|
return { streams, count: streams.length };
|
|
7754
7264
|
},
|
|
7755
|
-
async send(stream, group, type, data,
|
|
7756
|
-
notify(channels, stream, group,
|
|
7265
|
+
async send(stream, group, type, data, id3) {
|
|
7266
|
+
notify(channels, stream, group, id3 ?? "", "send", { type, data });
|
|
7757
7267
|
},
|
|
7758
7268
|
async update(stream, group, item, ops) {
|
|
7759
7269
|
const k = key(stream, group, item);
|
|
@@ -7833,8 +7343,8 @@ function createPgStore(channels, pg) {
|
|
|
7833
7343
|
}));
|
|
7834
7344
|
return { streams, count: streams.length };
|
|
7835
7345
|
},
|
|
7836
|
-
async send(stream, group, type, data,
|
|
7837
|
-
notify(channels, stream, group,
|
|
7346
|
+
async send(stream, group, type, data, id3) {
|
|
7347
|
+
notify(channels, stream, group, id3 ?? "", "send", { type, data });
|
|
7838
7348
|
},
|
|
7839
7349
|
async update(stream, group, item, ops) {
|
|
7840
7350
|
const { value: oldVal } = await this.get(stream, group, item);
|
|
@@ -7930,8 +7440,8 @@ function createRedisStore(channels, redis2, ttl) {
|
|
|
7930
7440
|
}));
|
|
7931
7441
|
return { streams, count: streams.length };
|
|
7932
7442
|
},
|
|
7933
|
-
async send(stream, group, type, data,
|
|
7934
|
-
notify(channels, stream, group,
|
|
7443
|
+
async send(stream, group, type, data, id3) {
|
|
7444
|
+
notify(channels, stream, group, id3 ?? "", "send", { type, data });
|
|
7935
7445
|
},
|
|
7936
7446
|
async update(stream, group, item, ops) {
|
|
7937
7447
|
const hk = hashKey(stream, group);
|
|
@@ -8144,9 +7654,9 @@ function iii(opts = {}) {
|
|
|
8144
7654
|
const functions = /* @__PURE__ */ new Map();
|
|
8145
7655
|
const triggers = /* @__PURE__ */ new Map();
|
|
8146
7656
|
const pending = /* @__PURE__ */ new Map();
|
|
8147
|
-
function registerBuiltin(
|
|
8148
|
-
functions.set(
|
|
8149
|
-
id:
|
|
7657
|
+
function registerBuiltin(id3, handler) {
|
|
7658
|
+
functions.set(id3, {
|
|
7659
|
+
id: id3,
|
|
8150
7660
|
handler,
|
|
8151
7661
|
workerId: "__iii__",
|
|
8152
7662
|
workerName: "__iii__",
|
|
@@ -8201,34 +7711,34 @@ function iii(opts = {}) {
|
|
|
8201
7711
|
}
|
|
8202
7712
|
workers.set(workerId, reg);
|
|
8203
7713
|
}
|
|
8204
|
-
function addRemoteFunction(workerId,
|
|
7714
|
+
function addRemoteFunction(workerId, id3) {
|
|
8205
7715
|
const worker = workers.get(workerId);
|
|
8206
7716
|
if (!worker) return;
|
|
8207
7717
|
const handler = async (payload) => {
|
|
8208
7718
|
if (!worker.ws) throw new Error(`Worker "${worker.name}" disconnected`);
|
|
8209
7719
|
const invocationId = crypto6.randomUUID();
|
|
8210
|
-
return new Promise((
|
|
7720
|
+
return new Promise((resolve12, reject) => {
|
|
8211
7721
|
const timer = setTimeout(() => {
|
|
8212
7722
|
pending.delete(invocationId);
|
|
8213
|
-
reject(new Error(`Invocation timed out for "${
|
|
7723
|
+
reject(new Error(`Invocation timed out for "${id3}"`));
|
|
8214
7724
|
}, 3e4);
|
|
8215
|
-
pending.set(invocationId, { resolve:
|
|
7725
|
+
pending.set(invocationId, { resolve: resolve12, reject, timer });
|
|
8216
7726
|
worker.ws.send(JSON.stringify({
|
|
8217
7727
|
type: "invoke",
|
|
8218
7728
|
invocation_id: invocationId,
|
|
8219
|
-
function_id:
|
|
7729
|
+
function_id: id3,
|
|
8220
7730
|
payload
|
|
8221
7731
|
}));
|
|
8222
7732
|
});
|
|
8223
7733
|
};
|
|
8224
7734
|
const fnReg = {
|
|
8225
|
-
id:
|
|
7735
|
+
id: id3,
|
|
8226
7736
|
handler,
|
|
8227
7737
|
workerId,
|
|
8228
7738
|
workerName: worker.name,
|
|
8229
7739
|
triggers: []
|
|
8230
7740
|
};
|
|
8231
|
-
functions.set(
|
|
7741
|
+
functions.set(id3, fnReg);
|
|
8232
7742
|
worker.functions.push(fnReg);
|
|
8233
7743
|
}
|
|
8234
7744
|
function removeWorker(workerId) {
|
|
@@ -8241,15 +7751,15 @@ function iii(opts = {}) {
|
|
|
8241
7751
|
let engineRef = null;
|
|
8242
7752
|
const wsHandler = createWsHandler({
|
|
8243
7753
|
registerRemoteWorker(ws, name) {
|
|
8244
|
-
const
|
|
8245
|
-
workers.set(
|
|
8246
|
-
return
|
|
7754
|
+
const id3 = crypto6.randomUUID();
|
|
7755
|
+
workers.set(id3, { id: id3, name, ws, functions: [], triggers: [] });
|
|
7756
|
+
return id3;
|
|
8247
7757
|
},
|
|
8248
7758
|
unregisterRemoteWorker(workerId) {
|
|
8249
7759
|
removeWorker(workerId);
|
|
8250
7760
|
},
|
|
8251
|
-
registerRemoteFunction(workerId,
|
|
8252
|
-
addRemoteFunction(workerId,
|
|
7761
|
+
registerRemoteFunction(workerId, id3) {
|
|
7762
|
+
addRemoteFunction(workerId, id3);
|
|
8253
7763
|
},
|
|
8254
7764
|
registerRemoteTrigger(workerId, input) {
|
|
8255
7765
|
const tid = crypto6.randomUUID();
|
|
@@ -8258,11 +7768,11 @@ function iii(opts = {}) {
|
|
|
8258
7768
|
const worker = workers.get(workerId);
|
|
8259
7769
|
if (worker) worker.triggers.push(reg);
|
|
8260
7770
|
},
|
|
8261
|
-
unregisterRemoteFunction(workerId,
|
|
8262
|
-
functions.delete(
|
|
7771
|
+
unregisterRemoteFunction(workerId, id3) {
|
|
7772
|
+
functions.delete(id3);
|
|
8263
7773
|
const worker = workers.get(workerId);
|
|
8264
7774
|
if (worker) {
|
|
8265
|
-
worker.functions = worker.functions.filter((f) => f.id !==
|
|
7775
|
+
worker.functions = worker.functions.filter((f) => f.id !== id3);
|
|
8266
7776
|
}
|
|
8267
7777
|
},
|
|
8268
7778
|
unregisterRemoteTrigger(workerId, functionId) {
|
|
@@ -8397,12 +7907,12 @@ function createWorker(name) {
|
|
|
8397
7907
|
const triggers = /* @__PURE__ */ new Map();
|
|
8398
7908
|
return {
|
|
8399
7909
|
name,
|
|
8400
|
-
registerFunction(
|
|
8401
|
-
functions.set(
|
|
7910
|
+
registerFunction(id3, handler) {
|
|
7911
|
+
functions.set(id3, handler);
|
|
8402
7912
|
return this;
|
|
8403
7913
|
},
|
|
8404
|
-
unregisterFunction(
|
|
8405
|
-
functions.delete(
|
|
7914
|
+
unregisterFunction(id3) {
|
|
7915
|
+
functions.delete(id3);
|
|
8406
7916
|
return this;
|
|
8407
7917
|
},
|
|
8408
7918
|
registerTrigger(input) {
|
|
@@ -8414,10 +7924,10 @@ function createWorker(name) {
|
|
|
8414
7924
|
return this;
|
|
8415
7925
|
},
|
|
8416
7926
|
getFunctions() {
|
|
8417
|
-
return Array.from(functions.entries()).map(([
|
|
7927
|
+
return Array.from(functions.entries()).map(([id3, handler]) => ({ id: id3, handler }));
|
|
8418
7928
|
},
|
|
8419
7929
|
getTriggers() {
|
|
8420
|
-
return Array.from(triggers.entries()).map(([
|
|
7930
|
+
return Array.from(triggers.entries()).map(([id3, input]) => ({ id: id3, input }));
|
|
8421
7931
|
}
|
|
8422
7932
|
};
|
|
8423
7933
|
}
|
|
@@ -8453,8 +7963,8 @@ function registerWorker(url) {
|
|
|
8453
7963
|
function connect() {
|
|
8454
7964
|
if (intentionalClose) return;
|
|
8455
7965
|
ws = new WebSocket(url);
|
|
8456
|
-
ready = new Promise((
|
|
8457
|
-
resolveReady =
|
|
7966
|
+
ready = new Promise((resolve12) => {
|
|
7967
|
+
resolveReady = resolve12;
|
|
8458
7968
|
});
|
|
8459
7969
|
ws.onopen = () => {
|
|
8460
7970
|
reconnectAttempt = 0;
|
|
@@ -8537,15 +8047,15 @@ function registerWorker(url) {
|
|
|
8537
8047
|
}
|
|
8538
8048
|
connect();
|
|
8539
8049
|
return {
|
|
8540
|
-
registerFunction(
|
|
8541
|
-
handlers.set(
|
|
8542
|
-
registeredFunctionIds.add(
|
|
8543
|
-
send({ type: "register_function", id:
|
|
8050
|
+
registerFunction(id3, handler) {
|
|
8051
|
+
handlers.set(id3, handler);
|
|
8052
|
+
registeredFunctionIds.add(id3);
|
|
8053
|
+
send({ type: "register_function", id: id3 });
|
|
8544
8054
|
},
|
|
8545
|
-
unregisterFunction(
|
|
8546
|
-
handlers.delete(
|
|
8547
|
-
registeredFunctionIds.delete(
|
|
8548
|
-
send({ type: "unregister_function", id:
|
|
8055
|
+
unregisterFunction(id3) {
|
|
8056
|
+
handlers.delete(id3);
|
|
8057
|
+
registeredFunctionIds.delete(id3);
|
|
8058
|
+
send({ type: "unregister_function", id: id3 });
|
|
8549
8059
|
},
|
|
8550
8060
|
registerTrigger(input) {
|
|
8551
8061
|
registeredTriggers.add(JSON.stringify(input));
|
|
@@ -8574,13 +8084,13 @@ function registerWorker(url) {
|
|
|
8574
8084
|
}
|
|
8575
8085
|
return Promise.resolve(fn(request.payload, ctx));
|
|
8576
8086
|
}
|
|
8577
|
-
return new Promise((
|
|
8087
|
+
return new Promise((resolve12, reject) => {
|
|
8578
8088
|
const invocationId = genId();
|
|
8579
8089
|
const timer = setTimeout(() => {
|
|
8580
8090
|
pendingInvocations.delete(invocationId);
|
|
8581
8091
|
reject(new Error(`Invocation timed out for "${request.function_id}"`));
|
|
8582
8092
|
}, request.timeout_ms || 3e4);
|
|
8583
|
-
pendingInvocations.set(invocationId, { resolve:
|
|
8093
|
+
pendingInvocations.set(invocationId, { resolve: resolve12, reject, timer });
|
|
8584
8094
|
send({
|
|
8585
8095
|
type: "invoke",
|
|
8586
8096
|
invocation_id: invocationId,
|
|
@@ -8655,7 +8165,6 @@ export {
|
|
|
8655
8165
|
streamText,
|
|
8656
8166
|
tenant,
|
|
8657
8167
|
tool2 as tool,
|
|
8658
|
-
tsx,
|
|
8659
8168
|
upload,
|
|
8660
8169
|
user,
|
|
8661
8170
|
validate
|