weifuwu 0.24.1 → 0.24.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +818 -712
- package/cli/template/app.ts +5 -1
- package/cli/template/index.ts +4 -1
- package/cli/template/locales/en.json +6 -1
- package/cli/template/locales/zh-CN.json +6 -1
- package/cli/template/locales/zh-TW.json +6 -1
- package/cli/template/locales/zh.json +6 -1
- package/cli/template/ui/app/globals.css +1 -1
- package/cli/template/ui/app/page.tsx +55 -16
- package/cli.ts +148 -104
- package/dist/agent/rest.d.ts +1 -1
- package/dist/agent/run.d.ts +2 -2
- package/dist/ai/workflow.d.ts +1 -1
- package/dist/ai-sdk.d.ts +1 -1
- package/dist/cli.js +135 -97
- package/dist/compile.d.ts +7 -12
- package/dist/cookie.d.ts +24 -0
- package/dist/fts.d.ts +5 -5
- package/dist/iii/index.d.ts +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +1233 -639
- package/dist/live.d.ts +2 -3
- package/dist/logdb/rest.d.ts +1 -1
- package/dist/mailer.d.ts +1 -1
- package/dist/messager/agent.d.ts +2 -2
- package/dist/messager/rest.d.ts +3 -3
- package/dist/messager/ws.d.ts +3 -3
- package/dist/module-server.d.ts +10 -0
- package/dist/opencode/index.d.ts +1 -1
- package/dist/opencode/permissions.d.ts +1 -1
- package/dist/opencode/run.d.ts +1 -1
- package/dist/opencode/session.d.ts +9 -9
- package/dist/opencode/tools/web.d.ts +1 -1
- package/dist/opencode/ws.d.ts +1 -2
- package/dist/permissions.d.ts +2 -2
- package/dist/postgres/module.d.ts +3 -3
- package/dist/postgres/schema/index.d.ts +1 -1
- package/dist/postgres/schema/table.d.ts +22 -20
- package/dist/postgres/types.d.ts +4 -4
- package/dist/queue/types.d.ts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +135 -90
- package/dist/router.d.ts +10 -10
- package/dist/server-registry.d.ts +12 -0
- package/dist/session.d.ts +1 -2
- package/dist/stream.d.ts +0 -5
- package/dist/tenant/graphql.d.ts +2 -2
- package/dist/tenant/index.d.ts +1 -1
- package/dist/tenant/rest.d.ts +2 -2
- package/dist/test-utils.d.ts +3 -3
- package/dist/user/index.d.ts +1 -1
- package/dist/user/oauth-login.d.ts +2 -2
- package/dist/vendor.d.ts +4 -0
- package/opencode/ui/app/globals.css +1 -1
- package/opencode/ui/app/layout.tsx +2 -3
- package/opencode/ui/app/page.tsx +302 -73
- package/package.json +27 -4
- package/cli/template/.weifuwu/ssr/2e3a7e60.js +0 -112
package/dist/index.js
CHANGED
|
@@ -65,7 +65,8 @@ function isBundled() {
|
|
|
65
65
|
return true ? true : false;
|
|
66
66
|
}
|
|
67
67
|
function isDev() {
|
|
68
|
-
|
|
68
|
+
const env2 = process.env.NODE_ENV;
|
|
69
|
+
return env2 !== "production" && env2 !== "test";
|
|
69
70
|
}
|
|
70
71
|
function isProd() {
|
|
71
72
|
return process.env.NODE_ENV === "production";
|
|
@@ -262,9 +263,13 @@ function serve(handler, options) {
|
|
|
262
263
|
}
|
|
263
264
|
};
|
|
264
265
|
}
|
|
265
|
-
options.signal.addEventListener(
|
|
266
|
-
|
|
267
|
-
|
|
266
|
+
options.signal.addEventListener(
|
|
267
|
+
"abort",
|
|
268
|
+
() => {
|
|
269
|
+
server.close();
|
|
270
|
+
},
|
|
271
|
+
{ once: true }
|
|
272
|
+
);
|
|
268
273
|
}
|
|
269
274
|
server.on("error", (err) => {
|
|
270
275
|
console.error("Failed to start server:", err.message);
|
|
@@ -289,20 +294,20 @@ function serve(handler, options) {
|
|
|
289
294
|
process.off("SIGINT", shutdownHandler);
|
|
290
295
|
shutdownHandler = null;
|
|
291
296
|
}
|
|
292
|
-
return new Promise((
|
|
297
|
+
return new Promise((resolve16) => {
|
|
293
298
|
if (!server.listening) {
|
|
294
|
-
|
|
299
|
+
resolve16();
|
|
295
300
|
return;
|
|
296
301
|
}
|
|
297
302
|
server.close();
|
|
298
303
|
server.closeIdleConnections();
|
|
299
304
|
const timer = setTimeout(() => {
|
|
300
305
|
server.closeAllConnections();
|
|
301
|
-
|
|
306
|
+
resolve16();
|
|
302
307
|
}, timeoutMs);
|
|
303
308
|
server.on("close", () => {
|
|
304
309
|
clearTimeout(timer);
|
|
305
|
-
|
|
310
|
+
resolve16();
|
|
306
311
|
});
|
|
307
312
|
});
|
|
308
313
|
},
|
|
@@ -488,7 +493,8 @@ var Router = class _Router {
|
|
|
488
493
|
}
|
|
489
494
|
} else if (typeof arg1 === "function") {
|
|
490
495
|
this.globalMws.push(arg1);
|
|
491
|
-
} else if (typeof arg1 === "object" && arg1 !== null && "middleware" in arg1 &&
|
|
496
|
+
} else if (typeof arg1 === "object" && arg1 !== null && "middleware" in arg1 && // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
497
|
+
typeof arg1.middleware === "function" && arg1 instanceof _Router) {
|
|
492
498
|
const mod = arg1;
|
|
493
499
|
this.globalMws.push(mod.middleware());
|
|
494
500
|
this._mountRouter("/", mod);
|
|
@@ -529,6 +535,7 @@ var Router = class _Router {
|
|
|
529
535
|
return this._routeImpl(method, path2, args);
|
|
530
536
|
}
|
|
531
537
|
/** Internal route registration — no type constraints (used by _mountRouter). */
|
|
538
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
532
539
|
_routeImpl(method, path2, args) {
|
|
533
540
|
const last = args[args.length - 1];
|
|
534
541
|
if (last instanceof _Router) {
|
|
@@ -554,9 +561,7 @@ var Router = class _Router {
|
|
|
554
561
|
node = getOrCreateChild(node, segment, createTrieNode, false);
|
|
555
562
|
}
|
|
556
563
|
if (!isProd() && node.handlers.has(method)) {
|
|
557
|
-
console.warn(
|
|
558
|
-
`[router] route conflict: ${method} ${path2} overwrites existing handler`
|
|
559
|
-
);
|
|
564
|
+
console.warn(`[router] route conflict: ${method} ${path2} overwrites existing handler`);
|
|
560
565
|
}
|
|
561
566
|
node.handlers.set(method, handler);
|
|
562
567
|
if (middlewares.length > 0) node.middlewares.set(method, middlewares);
|
|
@@ -591,7 +596,7 @@ var Router = class _Router {
|
|
|
591
596
|
return result;
|
|
592
597
|
}
|
|
593
598
|
_collectRoutes(node, prefix, result) {
|
|
594
|
-
for (const [method
|
|
599
|
+
for (const [method] of node.handlers) {
|
|
595
600
|
const m = method === "*" ? "ANY" : method;
|
|
596
601
|
const path2 = (prefix || "/") + (node.wildcard ? "/*" : "");
|
|
597
602
|
const middlewares = node.middlewares.get(method);
|
|
@@ -669,7 +674,12 @@ var Router = class _Router {
|
|
|
669
674
|
const wsRoutes = [];
|
|
670
675
|
this._collectWs(sub.wsRoot, "", wsRoutes);
|
|
671
676
|
for (const { path: path2, handler, middlewares } of wsRoutes) {
|
|
672
|
-
this.ws(
|
|
677
|
+
this.ws(
|
|
678
|
+
base + path2,
|
|
679
|
+
...allExtra,
|
|
680
|
+
...middlewares,
|
|
681
|
+
handler
|
|
682
|
+
);
|
|
673
683
|
}
|
|
674
684
|
}
|
|
675
685
|
mergeMws(base, extra) {
|
|
@@ -682,7 +692,12 @@ var Router = class _Router {
|
|
|
682
692
|
for (const [method, handler] of node.handlers) {
|
|
683
693
|
const rmws = node.middlewares.get(method) || [];
|
|
684
694
|
const suffix = node.wildcard ? "/*" : "";
|
|
685
|
-
result.push({
|
|
695
|
+
result.push({
|
|
696
|
+
method,
|
|
697
|
+
path: (prefix || "/") + suffix,
|
|
698
|
+
handler,
|
|
699
|
+
middlewares: this.mergeMws(mws, rmws)
|
|
700
|
+
});
|
|
686
701
|
}
|
|
687
702
|
for (const [seg, child] of node.children) {
|
|
688
703
|
const next = seg === ":" ? `/:${child.param}` : `/${seg}`;
|
|
@@ -744,7 +759,12 @@ var Router = class _Router {
|
|
|
744
759
|
return { handler: wildcardHandler, middlewares: wildcardMws, pathMws, params };
|
|
745
760
|
}
|
|
746
761
|
if (node.handlers.size > 0) {
|
|
747
|
-
return {
|
|
762
|
+
return {
|
|
763
|
+
middlewares: [],
|
|
764
|
+
pathMws,
|
|
765
|
+
params,
|
|
766
|
+
allowedMethods: [...node.handlers.keys()].filter((k) => k !== "*")
|
|
767
|
+
};
|
|
748
768
|
}
|
|
749
769
|
return null;
|
|
750
770
|
}
|
|
@@ -779,38 +799,54 @@ var Router = class _Router {
|
|
|
779
799
|
if (match.allowedMethods && match.allowedMethods.length > 0) {
|
|
780
800
|
if (this.globalMws.length > 0) {
|
|
781
801
|
try {
|
|
782
|
-
return await this.runChain(
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
802
|
+
return await this.runChain(
|
|
803
|
+
this.globalMws,
|
|
804
|
+
() => new Response("Method Not Allowed", {
|
|
805
|
+
status: 405,
|
|
806
|
+
headers: { Allow: match.allowedMethods.join(", ") }
|
|
807
|
+
}),
|
|
808
|
+
req,
|
|
809
|
+
ctx
|
|
810
|
+
);
|
|
786
811
|
} catch (e) {
|
|
787
812
|
return this.handleError(e, req, ctx);
|
|
788
813
|
}
|
|
789
814
|
}
|
|
790
815
|
return new Response("Method Not Allowed", {
|
|
791
816
|
status: 405,
|
|
792
|
-
headers: {
|
|
817
|
+
headers: { Allow: match.allowedMethods.join(", ") }
|
|
793
818
|
});
|
|
794
819
|
}
|
|
795
820
|
}
|
|
796
821
|
if (this.globalMws.length > 0) {
|
|
797
822
|
try {
|
|
798
|
-
return await this.runChain(
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
823
|
+
return await this.runChain(
|
|
824
|
+
this.globalMws,
|
|
825
|
+
() => {
|
|
826
|
+
if (!isProd()) {
|
|
827
|
+
return Response.json(
|
|
828
|
+
{ error: "Not Found", path: "/" + segments.join("/"), method: req.method },
|
|
829
|
+
{ status: 404 }
|
|
830
|
+
);
|
|
831
|
+
}
|
|
832
|
+
return new Response("Not Found", { status: 404 });
|
|
833
|
+
},
|
|
834
|
+
req,
|
|
835
|
+
ctx
|
|
836
|
+
);
|
|
804
837
|
} catch (e) {
|
|
805
838
|
return this.handleError(e, req, ctx);
|
|
806
839
|
}
|
|
807
840
|
}
|
|
808
841
|
if (!isProd()) {
|
|
809
|
-
return Response.json(
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
842
|
+
return Response.json(
|
|
843
|
+
{
|
|
844
|
+
error: "Not Found",
|
|
845
|
+
path: "/" + segments.join("/"),
|
|
846
|
+
method: req.method
|
|
847
|
+
},
|
|
848
|
+
{ status: 404 }
|
|
849
|
+
);
|
|
814
850
|
}
|
|
815
851
|
return new Response("Not Found", { status: 404 });
|
|
816
852
|
}
|
|
@@ -825,7 +861,9 @@ function runChainLoop(middlewares, index, finalHandler, req, ctx) {
|
|
|
825
861
|
let called = false;
|
|
826
862
|
const dispatch = (r, c) => {
|
|
827
863
|
if (called) {
|
|
828
|
-
console.warn(
|
|
864
|
+
console.warn(
|
|
865
|
+
"[router] next() called more than once in middleware \u2014 ignoring duplicate call"
|
|
866
|
+
);
|
|
829
867
|
return Promise.resolve(new Response("Internal Server Error", { status: 500 }));
|
|
830
868
|
}
|
|
831
869
|
called = true;
|
|
@@ -849,7 +887,7 @@ function upgradeSocket(wss, req, socket, head, handler, ctx, hub) {
|
|
|
849
887
|
join(room) {
|
|
850
888
|
hub.join(room, ws);
|
|
851
889
|
},
|
|
852
|
-
leave(
|
|
890
|
+
leave(_room) {
|
|
853
891
|
hub.leave(ws);
|
|
854
892
|
},
|
|
855
893
|
sendRoom(room, data) {
|
|
@@ -899,7 +937,15 @@ function sendHttpResponseOnSocket(socket, response) {
|
|
|
899
937
|
|
|
900
938
|
// tsx-context.ts
|
|
901
939
|
import { useSyncExternalStore, createContext } from "react";
|
|
902
|
-
var DEFAULT_CTX = {
|
|
940
|
+
var DEFAULT_CTX = {
|
|
941
|
+
params: {},
|
|
942
|
+
query: {},
|
|
943
|
+
parsed: {},
|
|
944
|
+
loaderData: {},
|
|
945
|
+
env: {},
|
|
946
|
+
user: {},
|
|
947
|
+
flash: {}
|
|
948
|
+
};
|
|
903
949
|
var KEY = "__WEIFUWU_CTX_STORE";
|
|
904
950
|
function getStore() {
|
|
905
951
|
if (typeof globalThis !== "undefined" && globalThis[KEY]) {
|
|
@@ -907,12 +953,22 @@ function getStore() {
|
|
|
907
953
|
}
|
|
908
954
|
const s = {
|
|
909
955
|
_ctx: DEFAULT_CTX,
|
|
910
|
-
_snapshot: {
|
|
956
|
+
_snapshot: {
|
|
957
|
+
params: DEFAULT_CTX.params,
|
|
958
|
+
query: DEFAULT_CTX.query,
|
|
959
|
+
user: DEFAULT_CTX.user,
|
|
960
|
+
parsed: DEFAULT_CTX.parsed,
|
|
961
|
+
theme: DEFAULT_CTX.theme,
|
|
962
|
+
i18n: DEFAULT_CTX.i18n,
|
|
963
|
+
loaderData: DEFAULT_CTX.loaderData,
|
|
964
|
+
env: DEFAULT_CTX.env
|
|
965
|
+
},
|
|
911
966
|
_listeners: /* @__PURE__ */ new Set(),
|
|
912
967
|
_rebuilders: [],
|
|
913
968
|
_alsGetStore: null
|
|
914
969
|
};
|
|
915
970
|
if (typeof globalThis !== "undefined") {
|
|
971
|
+
;
|
|
916
972
|
globalThis[KEY] = s;
|
|
917
973
|
}
|
|
918
974
|
return s;
|
|
@@ -929,7 +985,16 @@ function setCtx(value) {
|
|
|
929
985
|
}
|
|
930
986
|
}
|
|
931
987
|
store._ctx = { ...store._ctx, ...value };
|
|
932
|
-
store._snapshot = {
|
|
988
|
+
store._snapshot = {
|
|
989
|
+
params: store._ctx.params,
|
|
990
|
+
query: store._ctx.query,
|
|
991
|
+
user: store._ctx.user,
|
|
992
|
+
parsed: store._ctx.parsed,
|
|
993
|
+
theme: store._ctx.theme,
|
|
994
|
+
i18n: store._ctx.i18n,
|
|
995
|
+
loaderData: store._ctx.loaderData,
|
|
996
|
+
env: store._ctx.env
|
|
997
|
+
};
|
|
933
998
|
if (typeof window !== "undefined") {
|
|
934
999
|
;
|
|
935
1000
|
window.__WEIFUWU_CTX = { ...window.__WEIFUWU_CTX, ...value };
|
|
@@ -1014,7 +1079,8 @@ function cors(options) {
|
|
|
1014
1079
|
const headers = new Headers(res.headers);
|
|
1015
1080
|
headers.set("Access-Control-Allow-Origin", acao);
|
|
1016
1081
|
if (opts.credentials) headers.set("Access-Control-Allow-Credentials", "true");
|
|
1017
|
-
if (opts.exposedHeaders?.length)
|
|
1082
|
+
if (opts.exposedHeaders?.length)
|
|
1083
|
+
headers.set("Access-Control-Expose-Headers", opts.exposedHeaders.join(", "));
|
|
1018
1084
|
if (acao !== "*") headers.set("Vary", "Origin");
|
|
1019
1085
|
return new Response(res.body, { status: res.status, statusText: res.statusText, headers });
|
|
1020
1086
|
}
|
|
@@ -1091,7 +1157,7 @@ function serveStatic(root, options) {
|
|
|
1091
1157
|
const headers = {
|
|
1092
1158
|
"Content-Type": mimeType,
|
|
1093
1159
|
"Content-Length": String(stat3.size),
|
|
1094
|
-
|
|
1160
|
+
ETag: etag,
|
|
1095
1161
|
"Last-Modified": stat3.mtime.toUTCString(),
|
|
1096
1162
|
"Cache-Control": opts.immutable ? `public, max-age=${opts.maxAge ?? 31536e3}, immutable` : `public, max-age=${opts.maxAge ?? 0}`
|
|
1097
1163
|
};
|
|
@@ -1181,10 +1247,12 @@ function validate(schemas) {
|
|
|
1181
1247
|
if (result.success) {
|
|
1182
1248
|
parsed.params = result.data;
|
|
1183
1249
|
} else {
|
|
1184
|
-
issues.push(
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1250
|
+
issues.push(
|
|
1251
|
+
...result.error.issues.map((i) => ({
|
|
1252
|
+
path: ["params", ...i.path.map(String)],
|
|
1253
|
+
message: i.message
|
|
1254
|
+
}))
|
|
1255
|
+
);
|
|
1188
1256
|
}
|
|
1189
1257
|
}
|
|
1190
1258
|
if (schemas?.query) {
|
|
@@ -1192,10 +1260,12 @@ function validate(schemas) {
|
|
|
1192
1260
|
if (result.success) {
|
|
1193
1261
|
parsed.query = result.data;
|
|
1194
1262
|
} else {
|
|
1195
|
-
issues.push(
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1263
|
+
issues.push(
|
|
1264
|
+
...result.error.issues.map((i) => ({
|
|
1265
|
+
path: ["query", ...i.path.map(String)],
|
|
1266
|
+
message: i.message
|
|
1267
|
+
}))
|
|
1268
|
+
);
|
|
1199
1269
|
}
|
|
1200
1270
|
}
|
|
1201
1271
|
if (schemas?.headers) {
|
|
@@ -1207,10 +1277,12 @@ function validate(schemas) {
|
|
|
1207
1277
|
if (result.success) {
|
|
1208
1278
|
parsed.headers = result.data;
|
|
1209
1279
|
} else {
|
|
1210
|
-
issues.push(
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1280
|
+
issues.push(
|
|
1281
|
+
...result.error.issues.map((i) => ({
|
|
1282
|
+
path: ["headers", ...i.path.map(String)],
|
|
1283
|
+
message: i.message
|
|
1284
|
+
}))
|
|
1285
|
+
);
|
|
1214
1286
|
}
|
|
1215
1287
|
}
|
|
1216
1288
|
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
@@ -1234,10 +1306,12 @@ function validate(schemas) {
|
|
|
1234
1306
|
if (result.success) {
|
|
1235
1307
|
parsed.body = result.data;
|
|
1236
1308
|
} else {
|
|
1237
|
-
issues.push(
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1309
|
+
issues.push(
|
|
1310
|
+
...result.error.issues.map((i) => ({
|
|
1311
|
+
path: ["body", ...i.path.map(String)],
|
|
1312
|
+
message: i.message
|
|
1313
|
+
}))
|
|
1314
|
+
);
|
|
1241
1315
|
}
|
|
1242
1316
|
} else {
|
|
1243
1317
|
parsed.body = bodyValue;
|
|
@@ -1305,11 +1379,14 @@ function setCookie(res, name, value, options) {
|
|
|
1305
1379
|
}
|
|
1306
1380
|
function deleteCookie(res, name, options) {
|
|
1307
1381
|
const headers = new Headers(res.headers);
|
|
1308
|
-
headers.append(
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1382
|
+
headers.append(
|
|
1383
|
+
"Set-Cookie",
|
|
1384
|
+
serializeCookie(name, "", {
|
|
1385
|
+
...options,
|
|
1386
|
+
maxAge: 0,
|
|
1387
|
+
expires: /* @__PURE__ */ new Date(0)
|
|
1388
|
+
})
|
|
1389
|
+
);
|
|
1313
1390
|
return new Response(res.body, {
|
|
1314
1391
|
status: res.status,
|
|
1315
1392
|
statusText: res.statusText,
|
|
@@ -1411,7 +1488,7 @@ function upload(options) {
|
|
|
1411
1488
|
}
|
|
1412
1489
|
|
|
1413
1490
|
// rate-limit.ts
|
|
1414
|
-
function defaultKey(_req,
|
|
1491
|
+
function defaultKey(_req, _ctx2) {
|
|
1415
1492
|
const forwarded = _req.headers.get("x-forwarded-for");
|
|
1416
1493
|
if (forwarded) return forwarded.split(",")[0].trim();
|
|
1417
1494
|
const realIp = _req.headers.get("x-real-ip");
|
|
@@ -1433,21 +1510,24 @@ function rateLimit(options) {
|
|
|
1433
1510
|
const keyPrefix = options?.prefix ?? "ratelimit:";
|
|
1434
1511
|
const MAX_ENTRIES2 = 1e4;
|
|
1435
1512
|
const hits = /* @__PURE__ */ new Map();
|
|
1436
|
-
const interval = storeType === "memory" ? setInterval(
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1513
|
+
const interval = storeType === "memory" ? setInterval(
|
|
1514
|
+
() => {
|
|
1515
|
+
const now = Date.now();
|
|
1516
|
+
for (const [key, entry] of hits) {
|
|
1517
|
+
if (entry.reset < now) hits.delete(key);
|
|
1518
|
+
}
|
|
1519
|
+
if (hits.size > MAX_ENTRIES2) {
|
|
1520
|
+
const toDelete = hits.size - MAX_ENTRIES2;
|
|
1521
|
+
let deleted = 0;
|
|
1522
|
+
for (const key of hits.keys()) {
|
|
1523
|
+
if (deleted >= toDelete) break;
|
|
1524
|
+
hits.delete(key);
|
|
1525
|
+
deleted++;
|
|
1526
|
+
}
|
|
1448
1527
|
}
|
|
1449
|
-
}
|
|
1450
|
-
|
|
1528
|
+
},
|
|
1529
|
+
Math.min(window2, 3e4)
|
|
1530
|
+
) : null;
|
|
1451
1531
|
if (interval?.unref) interval.unref();
|
|
1452
1532
|
async function checkAndIncrement(key) {
|
|
1453
1533
|
const now = Date.now();
|
|
@@ -1461,7 +1541,7 @@ function rateLimit(options) {
|
|
|
1461
1541
|
const reset = pttl > 0 ? now + pttl : now + window2;
|
|
1462
1542
|
return { count, reset };
|
|
1463
1543
|
}
|
|
1464
|
-
|
|
1544
|
+
const entry = hits.get(key);
|
|
1465
1545
|
if (!entry || entry.reset < now) {
|
|
1466
1546
|
hits.set(key, { count: 1, reset: now + window2 });
|
|
1467
1547
|
return { count: 1, reset: now + window2 };
|
|
@@ -1492,7 +1572,6 @@ function rateLimit(options) {
|
|
|
1492
1572
|
if (interval) clearInterval(interval);
|
|
1493
1573
|
hits.clear();
|
|
1494
1574
|
};
|
|
1495
|
-
mw.stop = mw.close;
|
|
1496
1575
|
mw.stats = () => ({
|
|
1497
1576
|
store: storeType,
|
|
1498
1577
|
entries: storeType === "memory" ? hits.size : void 0,
|
|
@@ -1536,7 +1615,9 @@ function compress(options) {
|
|
|
1536
1615
|
let compressed;
|
|
1537
1616
|
try {
|
|
1538
1617
|
if (encoding === "br") {
|
|
1539
|
-
compressed = await brotliCompressAsync(body, {
|
|
1618
|
+
compressed = await brotliCompressAsync(body, {
|
|
1619
|
+
params: { [constants.BROTLI_PARAM_QUALITY]: Math.min(level, 11) }
|
|
1620
|
+
});
|
|
1540
1621
|
} else if (encoding === "gzip") {
|
|
1541
1622
|
compressed = await gzipAsync(body, { level: Math.min(level, 9) });
|
|
1542
1623
|
} else {
|
|
@@ -1650,9 +1731,7 @@ function createSSEStream(iterable, opts) {
|
|
|
1650
1731
|
}
|
|
1651
1732
|
} catch (e) {
|
|
1652
1733
|
if (e.name !== "AbortError") {
|
|
1653
|
-
controller.enqueue(
|
|
1654
|
-
encoder.encode(formatSSE("error", { error: e.message }))
|
|
1655
|
-
);
|
|
1734
|
+
controller.enqueue(encoder.encode(formatSSE("error", { error: e.message })));
|
|
1656
1735
|
}
|
|
1657
1736
|
} finally {
|
|
1658
1737
|
controller.close();
|
|
@@ -1777,26 +1856,31 @@ var TestApp = class {
|
|
|
1777
1856
|
}
|
|
1778
1857
|
/** Register a GET route — supports route-level middleware via spread args. */
|
|
1779
1858
|
get(path2, ...args) {
|
|
1859
|
+
;
|
|
1780
1860
|
this.router.get(path2, ...args);
|
|
1781
1861
|
return this;
|
|
1782
1862
|
}
|
|
1783
1863
|
/** Register a POST route. */
|
|
1784
1864
|
post(path2, ...args) {
|
|
1865
|
+
;
|
|
1785
1866
|
this.router.post(path2, ...args);
|
|
1786
1867
|
return this;
|
|
1787
1868
|
}
|
|
1788
1869
|
/** Register a PUT route. */
|
|
1789
1870
|
put(path2, ...args) {
|
|
1871
|
+
;
|
|
1790
1872
|
this.router.put(path2, ...args);
|
|
1791
1873
|
return this;
|
|
1792
1874
|
}
|
|
1793
1875
|
/** Register a PATCH route. */
|
|
1794
1876
|
patch(path2, ...args) {
|
|
1877
|
+
;
|
|
1795
1878
|
this.router.patch(path2, ...args);
|
|
1796
1879
|
return this;
|
|
1797
1880
|
}
|
|
1798
1881
|
/** Register a DELETE route. */
|
|
1799
1882
|
delete(path2, ...args) {
|
|
1883
|
+
;
|
|
1800
1884
|
this.router.delete(path2, ...args);
|
|
1801
1885
|
return this;
|
|
1802
1886
|
}
|
|
@@ -1879,7 +1963,12 @@ async function withTestDb(optionsOrFn, fn) {
|
|
|
1879
1963
|
}
|
|
1880
1964
|
|
|
1881
1965
|
// graphql.ts
|
|
1882
|
-
import {
|
|
1966
|
+
import {
|
|
1967
|
+
buildSchema,
|
|
1968
|
+
graphql as executeGraphQL,
|
|
1969
|
+
validate as validateQuery,
|
|
1970
|
+
parse
|
|
1971
|
+
} from "graphql";
|
|
1883
1972
|
import { makeExecutableSchema } from "@graphql-tools/schema";
|
|
1884
1973
|
function parseParamsFromGet(url) {
|
|
1885
1974
|
const query = url.searchParams.get("query");
|
|
@@ -1940,11 +2029,17 @@ async function executeQuery(schema, params, options, req, ctx) {
|
|
|
1940
2029
|
const doc = parse(params.query);
|
|
1941
2030
|
const depth = queryDepth(doc);
|
|
1942
2031
|
if (depth > maxDepth) {
|
|
1943
|
-
return Response.json(
|
|
2032
|
+
return Response.json(
|
|
2033
|
+
{ errors: [{ message: `Query depth ${depth} exceeds limit ${maxDepth}` }] },
|
|
2034
|
+
{ status: 400 }
|
|
2035
|
+
);
|
|
1944
2036
|
}
|
|
1945
2037
|
const validationErrors = validateQuery(schema, doc);
|
|
1946
2038
|
if (validationErrors.length > 0) {
|
|
1947
|
-
return Response.json(
|
|
2039
|
+
return Response.json(
|
|
2040
|
+
{ errors: validationErrors.map((e) => ({ message: e.message })) },
|
|
2041
|
+
{ status: 400 }
|
|
2042
|
+
);
|
|
1948
2043
|
}
|
|
1949
2044
|
} catch (err) {
|
|
1950
2045
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -2125,7 +2220,10 @@ function resolveRef(path2, ctx) {
|
|
|
2125
2220
|
const propPath = after.slice(dot + 1);
|
|
2126
2221
|
const output = ctx.nodeOutputs.get(id2);
|
|
2127
2222
|
if (output === void 0) throw new Error(`Node "${id2}" has no output yet`);
|
|
2128
|
-
return getByPath(
|
|
2223
|
+
return getByPath(
|
|
2224
|
+
output,
|
|
2225
|
+
propPath.startsWith("output") ? propPath.slice(7).split(".").filter(Boolean) : propPath.split(".")
|
|
2226
|
+
);
|
|
2129
2227
|
}
|
|
2130
2228
|
if (path2.startsWith("$var.")) {
|
|
2131
2229
|
const name = path2.slice(5);
|
|
@@ -2145,7 +2243,8 @@ function resolveValue(v, ctx) {
|
|
|
2145
2243
|
if (Array.isArray(v)) return v.map((item) => resolveValue(item, ctx));
|
|
2146
2244
|
if (typeof v === "object" && v !== null) {
|
|
2147
2245
|
const result = {};
|
|
2148
|
-
for (const [k, val] of Object.entries(v))
|
|
2246
|
+
for (const [k, val] of Object.entries(v))
|
|
2247
|
+
result[k] = resolveValue(val, ctx);
|
|
2149
2248
|
return result;
|
|
2150
2249
|
}
|
|
2151
2250
|
return v;
|
|
@@ -2241,7 +2340,7 @@ async function executeNode(node, ctx) {
|
|
|
2241
2340
|
iters++;
|
|
2242
2341
|
ctx.stepCount++;
|
|
2243
2342
|
if (ctx.stepCount > ctx.maxSteps) throw new Error(`Step limit exceeded`);
|
|
2244
|
-
if (!
|
|
2343
|
+
if (!evaluateExpression(conditionExpr, ctx)) break;
|
|
2245
2344
|
for (const n of body ?? []) {
|
|
2246
2345
|
last = await executeNode(n, ctx);
|
|
2247
2346
|
ctx.nodeOutputs.set(n.id, last);
|
|
@@ -2273,7 +2372,10 @@ async function executeNode(node, ctx) {
|
|
|
2273
2372
|
signal: controller.signal
|
|
2274
2373
|
});
|
|
2275
2374
|
const ct = res.headers.get("content-type") ?? "";
|
|
2276
|
-
return {
|
|
2375
|
+
return {
|
|
2376
|
+
status: res.status,
|
|
2377
|
+
body: ct.includes("json") ? await res.json() : await res.text()
|
|
2378
|
+
};
|
|
2277
2379
|
} finally {
|
|
2278
2380
|
clearTimeout(timer);
|
|
2279
2381
|
}
|
|
@@ -2293,20 +2395,25 @@ function runWorkflow(opts = {}) {
|
|
|
2293
2395
|
description: "Execute a multi-step workflow. Supports eval, set, get, if, while, call, http nodes. Use $var.x for variables, $nodes.id.output for previous node results, $input.x for input parameters. Call nodes invoke registered tools.",
|
|
2294
2396
|
inputSchema: z.object({
|
|
2295
2397
|
goal: z.string().describe("What the workflow should accomplish"),
|
|
2296
|
-
nodes: z.array(
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2398
|
+
nodes: z.array(
|
|
2399
|
+
z.object({
|
|
2400
|
+
id: z.string(),
|
|
2401
|
+
tool: z.string(),
|
|
2402
|
+
input: z.record(z.string(), z.unknown()).optional(),
|
|
2403
|
+
conditions: z.array(z.object({ test: z.any(), body: z.any() })).optional(),
|
|
2404
|
+
body: z.array(z.any()).optional()
|
|
2405
|
+
})
|
|
2406
|
+
).optional().describe("Workflow nodes. Skip this and provide model for LLM to generate from goal.")
|
|
2303
2407
|
}),
|
|
2304
2408
|
execute: async (input) => {
|
|
2305
2409
|
let nodes;
|
|
2306
2410
|
if (input.nodes && input.nodes.length > 0) {
|
|
2307
2411
|
nodes = input.nodes;
|
|
2308
2412
|
} else {
|
|
2309
|
-
if (!opts.provider && !opts.model)
|
|
2413
|
+
if (!opts.provider && !opts.model)
|
|
2414
|
+
throw new Error(
|
|
2415
|
+
'Provide either "nodes", a "model", or a "provider" with a model to generate the workflow from "goal"'
|
|
2416
|
+
);
|
|
2310
2417
|
const toolsDesc = Object.entries(opts.tools ?? {}).map(([k, t]) => `- ${k}: ${t.description}`).join("\n");
|
|
2311
2418
|
const system = [
|
|
2312
2419
|
"You are a workflow generator. Given a user goal and available tools, output a workflow JSON.",
|
|
@@ -2318,7 +2425,10 @@ function runWorkflow(opts = {}) {
|
|
|
2318
2425
|
"Reference syntax: $var.name, $nodes.id.output, $nodes.id.output.field, $input.field",
|
|
2319
2426
|
"Output ONLY valid JSON. No explanation, no markdown."
|
|
2320
2427
|
].filter(Boolean).join("\n");
|
|
2321
|
-
const genParams = {
|
|
2428
|
+
const genParams = {
|
|
2429
|
+
system,
|
|
2430
|
+
messages: [{ role: "user", content: input.goal }]
|
|
2431
|
+
};
|
|
2322
2432
|
const result = opts.provider ? await opts.provider.generateText(genParams) : await generateText({ ...genParams, model: opts.model });
|
|
2323
2433
|
const text2 = result.text.trim();
|
|
2324
2434
|
const jsonStart = text2.indexOf("{");
|
|
@@ -2411,10 +2521,7 @@ import {
|
|
|
2411
2521
|
embedMany,
|
|
2412
2522
|
smoothStream
|
|
2413
2523
|
} from "ai";
|
|
2414
|
-
import {
|
|
2415
|
-
openai,
|
|
2416
|
-
createOpenAI as createOpenAI2
|
|
2417
|
-
} from "@ai-sdk/openai";
|
|
2524
|
+
import { openai, createOpenAI as createOpenAI2 } from "@ai-sdk/openai";
|
|
2418
2525
|
|
|
2419
2526
|
// postgres/client.ts
|
|
2420
2527
|
import postgresFactory from "postgres";
|
|
@@ -2657,7 +2764,10 @@ var Table = class {
|
|
|
2657
2764
|
const using = opts?.type ? `USING ${opts.type.toUpperCase()}` : "";
|
|
2658
2765
|
const colList = cols.map((c) => opts?.desc ? `"${c}" DESC` : `"${c}"`).join(", ");
|
|
2659
2766
|
const operator = opts?.operator ? ` ${opts.operator}` : "";
|
|
2660
|
-
const ddl = `CREATE ${unique} INDEX IF NOT EXISTS ${name} ON "${this.tableName}" ${using} (${colList}${operator})`.replace(
|
|
2767
|
+
const ddl = `CREATE ${unique} INDEX IF NOT EXISTS ${name} ON "${this.tableName}" ${using} (${colList}${operator})`.replace(
|
|
2768
|
+
/\s+/g,
|
|
2769
|
+
" "
|
|
2770
|
+
);
|
|
2661
2771
|
await sql2.unsafe(ddl);
|
|
2662
2772
|
}
|
|
2663
2773
|
async createUniqueIndex(sql2, columns) {
|
|
@@ -2761,7 +2871,10 @@ var Table = class {
|
|
|
2761
2871
|
const softDel = this._softDeleteFilter(where, opts);
|
|
2762
2872
|
if (softDel) conditions.push(softDel);
|
|
2763
2873
|
const whereClause = conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "";
|
|
2764
|
-
const [countRow] = await sql2.unsafe(
|
|
2874
|
+
const [countRow] = await sql2.unsafe(
|
|
2875
|
+
`SELECT COUNT(*) AS _total FROM "${this.tableName}"${whereClause}`,
|
|
2876
|
+
values
|
|
2877
|
+
);
|
|
2765
2878
|
const count = Number(countRow._total);
|
|
2766
2879
|
if (conditions.length === 0 && !opts?.orderBy && !opts?.limit && !opts?.offset && !opts?.select) {
|
|
2767
2880
|
const rows2 = await sql2`SELECT * FROM ${sql2(this.tableName)}`;
|
|
@@ -2794,7 +2907,10 @@ var Table = class {
|
|
|
2794
2907
|
async updateMany(sql2, where, data) {
|
|
2795
2908
|
const { sets, values: setValues } = this._buildSET(data);
|
|
2796
2909
|
if (sets.length === 0) return 0;
|
|
2797
|
-
const { conditions: wConditions, values: wValues } = this._buildConditions(
|
|
2910
|
+
const { conditions: wConditions, values: wValues } = this._buildConditions(
|
|
2911
|
+
where,
|
|
2912
|
+
setValues.length
|
|
2913
|
+
);
|
|
2798
2914
|
if (wConditions.length === 0) return 0;
|
|
2799
2915
|
const rows = await sql2.unsafe(
|
|
2800
2916
|
`UPDATE "${this.tableName}" SET ${sets.join(", ")} WHERE ${wConditions.join(" AND ")} RETURNING 1`,
|
|
@@ -2883,13 +2999,20 @@ var Table = class {
|
|
|
2883
2999
|
const softDel = this._softDeleteFilter(where);
|
|
2884
3000
|
if (softDel) conditions.push(softDel);
|
|
2885
3001
|
const whereClause = conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "";
|
|
2886
|
-
const [row] = await sql2.unsafe(
|
|
3002
|
+
const [row] = await sql2.unsafe(
|
|
3003
|
+
`SELECT COUNT(*) AS _total FROM "${this.tableName}"${whereClause}`,
|
|
3004
|
+
values
|
|
3005
|
+
);
|
|
2887
3006
|
return Number(row._total);
|
|
2888
3007
|
}
|
|
2889
3008
|
};
|
|
2890
3009
|
var BoundTable = class _BoundTable {
|
|
2891
3010
|
inner;
|
|
2892
3011
|
sql;
|
|
3012
|
+
/** The underlying table name. */
|
|
3013
|
+
get tableName() {
|
|
3014
|
+
return this.inner.tableName;
|
|
3015
|
+
}
|
|
2893
3016
|
constructor(sql2, tableName, builders) {
|
|
2894
3017
|
this.inner = new Table(tableName, builders);
|
|
2895
3018
|
this.sql = sql2;
|
|
@@ -2977,13 +3100,17 @@ function postgres(opts) {
|
|
|
2977
3100
|
connect_timeout: options.connect_timeout
|
|
2978
3101
|
});
|
|
2979
3102
|
if (options.signal) {
|
|
2980
|
-
options.signal.addEventListener(
|
|
2981
|
-
|
|
2982
|
-
|
|
3103
|
+
options.signal.addEventListener(
|
|
3104
|
+
"abort",
|
|
3105
|
+
() => {
|
|
3106
|
+
sql2.end();
|
|
3107
|
+
},
|
|
3108
|
+
{ once: true }
|
|
3109
|
+
);
|
|
2983
3110
|
}
|
|
2984
3111
|
const closeTimeout = options.closeTimeout ?? 5;
|
|
2985
|
-
|
|
2986
|
-
|
|
3112
|
+
const _active = 0;
|
|
3113
|
+
const _waiting = 0;
|
|
2987
3114
|
const poolMax = options.max ?? 10;
|
|
2988
3115
|
const mw = ((req, ctx, next) => {
|
|
2989
3116
|
ctx.sql = sql2;
|
|
@@ -3011,10 +3138,9 @@ function postgres(opts) {
|
|
|
3011
3138
|
);
|
|
3012
3139
|
};
|
|
3013
3140
|
mw.isMigrated = async (moduleName) => {
|
|
3014
|
-
const [row] = await sql2.unsafe(
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
);
|
|
3141
|
+
const [row] = await sql2.unsafe(`SELECT 1 FROM "${MIGRATIONS_TABLE}" WHERE name = $1`, [
|
|
3142
|
+
moduleName
|
|
3143
|
+
]);
|
|
3018
3144
|
return !!row;
|
|
3019
3145
|
};
|
|
3020
3146
|
mw.transaction = (async (fn, retryOpts) => {
|
|
@@ -3146,10 +3272,9 @@ function createOAuth2Server(deps) {
|
|
|
3146
3272
|
return null;
|
|
3147
3273
|
}
|
|
3148
3274
|
function consentPage(client, params) {
|
|
3149
|
-
const fields = Object.entries(params).map(
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
return new Response(`<!DOCTYPE html>
|
|
3275
|
+
const fields = Object.entries(params).map(([k, v]) => `<input type="hidden" name="${k}" value="${v.replace(/"/g, """)}">`).join("\n ");
|
|
3276
|
+
return new Response(
|
|
3277
|
+
`<!DOCTYPE html>
|
|
3153
3278
|
<html lang="en">
|
|
3154
3279
|
<head><meta charset="utf-8"><title>Authorize</title>
|
|
3155
3280
|
<style>
|
|
@@ -3176,19 +3301,24 @@ function createOAuth2Server(deps) {
|
|
|
3176
3301
|
</form>
|
|
3177
3302
|
</div>
|
|
3178
3303
|
</body>
|
|
3179
|
-
</html>`,
|
|
3304
|
+
</html>`,
|
|
3305
|
+
{ headers: { "Content-Type": "text/html; charset=utf-8" } }
|
|
3306
|
+
);
|
|
3180
3307
|
}
|
|
3181
3308
|
function errorPage2(error, description) {
|
|
3182
|
-
return new Response(
|
|
3309
|
+
return new Response(
|
|
3310
|
+
`<!DOCTYPE html>
|
|
3183
3311
|
<html lang="en">
|
|
3184
3312
|
<head><meta charset="utf-8"><title>Error</title>
|
|
3185
3313
|
<style>body{font-family:sans-serif;max-width:480px;margin:80px auto;padding:0 20px}
|
|
3186
3314
|
h2{color:#dc2626}.desc{color:#555}</style>
|
|
3187
3315
|
</head>
|
|
3188
3316
|
<body><h2>${error}</h2>${description ? `<p class="desc">${description}</p>` : ""}</body>
|
|
3189
|
-
</html>`,
|
|
3317
|
+
</html>`,
|
|
3318
|
+
{ status: 400, headers: { "Content-Type": "text/html; charset=utf-8" } }
|
|
3319
|
+
);
|
|
3190
3320
|
}
|
|
3191
|
-
async function authorizeHandler(req,
|
|
3321
|
+
async function authorizeHandler(req, _ctx2) {
|
|
3192
3322
|
const url = new URL(req.url);
|
|
3193
3323
|
const clientId = url.searchParams.get("client_id") || "";
|
|
3194
3324
|
const redirectUri = url.searchParams.get("redirect_uri") || "";
|
|
@@ -3205,7 +3335,10 @@ h2{color:#dc2626}.desc{color:#555}</style>
|
|
|
3205
3335
|
return errorPage2("Invalid client_id", "No client found with the given client_id.");
|
|
3206
3336
|
}
|
|
3207
3337
|
if (!client.redirectUris.includes(redirectUri)) {
|
|
3208
|
-
return errorPage2(
|
|
3338
|
+
return errorPage2(
|
|
3339
|
+
"Invalid redirect_uri",
|
|
3340
|
+
"The redirect_uri is not registered for this client."
|
|
3341
|
+
);
|
|
3209
3342
|
}
|
|
3210
3343
|
const user2 = extractUser(req);
|
|
3211
3344
|
if (!user2) {
|
|
@@ -3291,14 +3424,23 @@ h2{color:#dc2626}.desc{color:#555}</style>
|
|
|
3291
3424
|
return Response.json({ error: "invalid_grant" }, { status: 400 });
|
|
3292
3425
|
}
|
|
3293
3426
|
if (new Date(stored.expires_at) < /* @__PURE__ */ new Date()) {
|
|
3294
|
-
return Response.json(
|
|
3427
|
+
return Response.json(
|
|
3428
|
+
{ error: "invalid_grant", error_description: "Code expired" },
|
|
3429
|
+
{ status: 400 }
|
|
3430
|
+
);
|
|
3295
3431
|
}
|
|
3296
3432
|
if (stored.redirect_uri !== redirectUri) {
|
|
3297
|
-
return Response.json(
|
|
3433
|
+
return Response.json(
|
|
3434
|
+
{ error: "invalid_grant", error_description: "redirect_uri mismatch" },
|
|
3435
|
+
{ status: 400 }
|
|
3436
|
+
);
|
|
3298
3437
|
}
|
|
3299
3438
|
if (stored.code_challenge) {
|
|
3300
3439
|
if (!codeVerifier) {
|
|
3301
|
-
return Response.json(
|
|
3440
|
+
return Response.json(
|
|
3441
|
+
{ error: "invalid_grant", error_description: "code_verifier required" },
|
|
3442
|
+
{ status: 400 }
|
|
3443
|
+
);
|
|
3302
3444
|
}
|
|
3303
3445
|
let expected;
|
|
3304
3446
|
if (stored.code_challenge_method === "plain") {
|
|
@@ -3307,7 +3449,10 @@ h2{color:#dc2626}.desc{color:#555}</style>
|
|
|
3307
3449
|
expected = crypto4.createHash("sha256").update(codeVerifier).digest().toString("base64url");
|
|
3308
3450
|
}
|
|
3309
3451
|
if (expected !== stored.code_challenge) {
|
|
3310
|
-
return Response.json(
|
|
3452
|
+
return Response.json(
|
|
3453
|
+
{ error: "invalid_grant", error_description: "code_verifier mismatch" },
|
|
3454
|
+
{ status: 400 }
|
|
3455
|
+
);
|
|
3311
3456
|
}
|
|
3312
3457
|
}
|
|
3313
3458
|
await pg.sql`UPDATE "_oauth2_codes" SET "used" = TRUE WHERE "id" = ${stored.id}`;
|
|
@@ -3512,7 +3657,7 @@ function registerOAuthLoginRoutes(router, deps, providers) {
|
|
|
3512
3657
|
try {
|
|
3513
3658
|
tokenRes = await fetch(meta.tokenUrl, {
|
|
3514
3659
|
method: "POST",
|
|
3515
|
-
headers: { "Content-Type": "application/json",
|
|
3660
|
+
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
|
3516
3661
|
body: JSON.stringify({
|
|
3517
3662
|
code,
|
|
3518
3663
|
client_id: config.clientId,
|
|
@@ -3522,7 +3667,10 @@ function registerOAuthLoginRoutes(router, deps, providers) {
|
|
|
3522
3667
|
})
|
|
3523
3668
|
});
|
|
3524
3669
|
} catch (err) {
|
|
3525
|
-
console.error(
|
|
3670
|
+
console.error(
|
|
3671
|
+
`[oauth] token exchange network error for ${providerName}:`,
|
|
3672
|
+
err.message
|
|
3673
|
+
);
|
|
3526
3674
|
return Response.json({ error: "Failed to connect to OAuth provider" }, { status: 502 });
|
|
3527
3675
|
}
|
|
3528
3676
|
if (!tokenRes.ok) {
|
|
@@ -3539,7 +3687,10 @@ function registerOAuthLoginRoutes(router, deps, providers) {
|
|
|
3539
3687
|
try {
|
|
3540
3688
|
userRes = await fetch(meta.userUrl, { headers: { Authorization: "Bearer " + accessToken } });
|
|
3541
3689
|
} catch (err) {
|
|
3542
|
-
console.error(
|
|
3690
|
+
console.error(
|
|
3691
|
+
"[oauth] user info network error for " + providerName + ":",
|
|
3692
|
+
err.message
|
|
3693
|
+
);
|
|
3543
3694
|
return Response.json({ error: "Failed to connect to OAuth provider" }, { status: 502 });
|
|
3544
3695
|
}
|
|
3545
3696
|
if (!userRes.ok) {
|
|
@@ -3707,11 +3858,9 @@ function user(options) {
|
|
|
3707
3858
|
await tokens.create();
|
|
3708
3859
|
}
|
|
3709
3860
|
function signToken(user2) {
|
|
3710
|
-
return jwt2.sign(
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
{ expiresIn }
|
|
3714
|
-
);
|
|
3861
|
+
return jwt2.sign({ sub: user2.id, email: user2.email, role: user2.role }, secret, {
|
|
3862
|
+
expiresIn
|
|
3863
|
+
});
|
|
3715
3864
|
}
|
|
3716
3865
|
function stripPassword(row) {
|
|
3717
3866
|
const { password: _, ...user2 } = row;
|
|
@@ -3879,6 +4028,7 @@ function user(options) {
|
|
|
3879
4028
|
return async (req, ctx, next) => {
|
|
3880
4029
|
const userData = await resolveUser(req, ctx);
|
|
3881
4030
|
if (userData) {
|
|
4031
|
+
;
|
|
3882
4032
|
ctx.user = userData;
|
|
3883
4033
|
}
|
|
3884
4034
|
return next(req, ctx);
|
|
@@ -3940,18 +4090,22 @@ function user(options) {
|
|
|
3940
4090
|
r.post("/oauth/token", (req) => oauth2.tokenHandler(req));
|
|
3941
4091
|
}
|
|
3942
4092
|
if (hasDb && options.oauthLogin) {
|
|
3943
|
-
registerOAuthLoginRoutes(
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
4093
|
+
registerOAuthLoginRoutes(
|
|
4094
|
+
r,
|
|
4095
|
+
{
|
|
4096
|
+
sql: _pg.sql,
|
|
4097
|
+
jwtSecret: secret,
|
|
4098
|
+
expiresIn,
|
|
4099
|
+
usersTable: table,
|
|
4100
|
+
providerTable: "_auth_providers",
|
|
4101
|
+
redirectUrl: options.oauthLogin.redirectUrl || "/",
|
|
4102
|
+
signToken,
|
|
4103
|
+
createPlaceholderUser,
|
|
4104
|
+
findUserById: findById,
|
|
4105
|
+
findUserByEmail: findByEmail
|
|
4106
|
+
},
|
|
4107
|
+
options.oauthLogin.providers
|
|
4108
|
+
);
|
|
3955
4109
|
}
|
|
3956
4110
|
const mod = r;
|
|
3957
4111
|
mod.middleware = middleware;
|
|
@@ -4048,9 +4202,7 @@ var FIELD_RANGES = [
|
|
|
4048
4202
|
function parsePattern(pattern) {
|
|
4049
4203
|
const fields = pattern.trim().split(/\s+/);
|
|
4050
4204
|
if (fields.length !== 5) {
|
|
4051
|
-
throw new Error(
|
|
4052
|
-
`Invalid cron pattern "${pattern}": expected 5 fields, got ${fields.length}`
|
|
4053
|
-
);
|
|
4205
|
+
throw new Error(`Invalid cron pattern "${pattern}": expected 5 fields, got ${fields.length}`);
|
|
4054
4206
|
}
|
|
4055
4207
|
return fields.map((f, i) => parseField(f, FIELD_RANGES[i][0], FIELD_RANGES[i][1]));
|
|
4056
4208
|
}
|
|
@@ -4059,7 +4211,7 @@ function matches(fields, date) {
|
|
|
4059
4211
|
}
|
|
4060
4212
|
function cronNext(expr, from = /* @__PURE__ */ new Date()) {
|
|
4061
4213
|
const fields = parsePattern(expr);
|
|
4062
|
-
|
|
4214
|
+
const candidate = new Date(from.getTime() + 6e4);
|
|
4063
4215
|
candidate.setSeconds(0, 0);
|
|
4064
4216
|
for (let i = 0; i < 525600; i++) {
|
|
4065
4217
|
if (fields[4].has(candidate.getDay()) && fields[3].has(candidate.getMonth() + 1) && fields[2].has(candidate.getDate()) && fields[1].has(candidate.getHours()) && fields[0].has(candidate.getMinutes())) {
|
|
@@ -4122,7 +4274,12 @@ function createMemoryQueue(opts) {
|
|
|
4122
4274
|
}
|
|
4123
4275
|
if (job.schedule) {
|
|
4124
4276
|
try {
|
|
4125
|
-
insertJob({
|
|
4277
|
+
insertJob({
|
|
4278
|
+
...job,
|
|
4279
|
+
id: crypto6.randomUUID(),
|
|
4280
|
+
runAt: cronNext(job.schedule),
|
|
4281
|
+
createdAt: Date.now()
|
|
4282
|
+
});
|
|
4126
4283
|
} catch (e) {
|
|
4127
4284
|
console.error("[queue] cron re-queue failed:", e.message);
|
|
4128
4285
|
}
|
|
@@ -4210,7 +4367,14 @@ function createMemoryQueue(opts) {
|
|
|
4210
4367
|
mw.dashboard = function dashboard() {
|
|
4211
4368
|
return buildDashboard(q);
|
|
4212
4369
|
};
|
|
4213
|
-
mw.stats = () => ({
|
|
4370
|
+
mw.stats = () => ({
|
|
4371
|
+
running,
|
|
4372
|
+
inflight,
|
|
4373
|
+
processed: _processed,
|
|
4374
|
+
failed: _failed,
|
|
4375
|
+
handlers: handlers.size,
|
|
4376
|
+
maxConcurrent: MAX_CONCURRENT
|
|
4377
|
+
});
|
|
4214
4378
|
attachCron(q, handlers);
|
|
4215
4379
|
return q;
|
|
4216
4380
|
}
|
|
@@ -4225,8 +4389,12 @@ function createPgQueue(opts) {
|
|
|
4225
4389
|
const MAX_FAILED = 1e3;
|
|
4226
4390
|
async function ensureTable() {
|
|
4227
4391
|
if (ready) return;
|
|
4228
|
-
await sql2.unsafe(
|
|
4229
|
-
|
|
4392
|
+
await sql2.unsafe(
|
|
4393
|
+
`CREATE TABLE IF NOT EXISTS ${escapeIdent3(table)} (id UUID PRIMARY KEY, type TEXT NOT NULL, payload JSONB NOT NULL DEFAULT '{}', run_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), schedule TEXT, status TEXT NOT NULL DEFAULT 'pending', error TEXT, failed_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW())`
|
|
4394
|
+
);
|
|
4395
|
+
await sql2.unsafe(
|
|
4396
|
+
`CREATE INDEX IF NOT EXISTS ${escapeIdent3(table + "_run_at_idx")} ON ${escapeIdent3(table)} (run_at, status)`
|
|
4397
|
+
);
|
|
4230
4398
|
ready = true;
|
|
4231
4399
|
}
|
|
4232
4400
|
async function processJob(job, handler) {
|
|
@@ -4239,14 +4407,26 @@ function createPgQueue(opts) {
|
|
|
4239
4407
|
_failed++;
|
|
4240
4408
|
const msg = e.message;
|
|
4241
4409
|
console.error("[queue] handler error:", msg);
|
|
4242
|
-
await sql2.unsafe(
|
|
4410
|
+
await sql2.unsafe(
|
|
4411
|
+
`UPDATE ${escapeIdent3(table)} SET status = 'failed', error = $2, failed_at = NOW() WHERE id = $1`,
|
|
4412
|
+
[job.id, msg]
|
|
4413
|
+
);
|
|
4243
4414
|
} finally {
|
|
4244
4415
|
inflight--;
|
|
4245
4416
|
}
|
|
4246
4417
|
if (job.schedule) {
|
|
4247
4418
|
try {
|
|
4248
4419
|
const nextRun = cronNext(job.schedule);
|
|
4249
|
-
await sql2.unsafe(
|
|
4420
|
+
await sql2.unsafe(
|
|
4421
|
+
`INSERT INTO ${escapeIdent3(table)} (id, type, payload, run_at, schedule) VALUES ($1, $2, $3::jsonb, $4, $5)`,
|
|
4422
|
+
[
|
|
4423
|
+
crypto6.randomUUID(),
|
|
4424
|
+
job.type,
|
|
4425
|
+
JSON.stringify(job.payload),
|
|
4426
|
+
new Date(nextRun).toISOString(),
|
|
4427
|
+
job.schedule
|
|
4428
|
+
]
|
|
4429
|
+
);
|
|
4250
4430
|
} catch (e) {
|
|
4251
4431
|
console.error("[queue] cron re-queue failed:", e.message);
|
|
4252
4432
|
}
|
|
@@ -4256,10 +4436,20 @@ function createPgQueue(opts) {
|
|
|
4256
4436
|
if (!running) return;
|
|
4257
4437
|
try {
|
|
4258
4438
|
while (running && inflight < MAX_CONCURRENT) {
|
|
4259
|
-
const rows = await sql2.unsafe(
|
|
4439
|
+
const rows = await sql2.unsafe(
|
|
4440
|
+
`UPDATE ${escapeIdent3(table)} SET status = 'running' WHERE id = (SELECT id FROM ${escapeIdent3(table)} WHERE run_at <= NOW() AND status = 'pending' ORDER BY run_at LIMIT 1 FOR UPDATE SKIP LOCKED) RETURNING *`
|
|
4441
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4442
|
+
);
|
|
4260
4443
|
if (rows.length === 0) break;
|
|
4261
4444
|
const row = rows[0];
|
|
4262
|
-
const job = {
|
|
4445
|
+
const job = {
|
|
4446
|
+
id: row.id,
|
|
4447
|
+
type: row.type,
|
|
4448
|
+
payload: typeof row.payload === "string" ? JSON.parse(row.payload) : row.payload,
|
|
4449
|
+
createdAt: new Date(row.created_at).getTime(),
|
|
4450
|
+
runAt: new Date(row.run_at).getTime(),
|
|
4451
|
+
schedule: row.schedule || void 0
|
|
4452
|
+
};
|
|
4263
4453
|
const handler = handlers.get(job.type);
|
|
4264
4454
|
if (handler) processJob(job, handler);
|
|
4265
4455
|
}
|
|
@@ -4294,7 +4484,10 @@ function createPgQueue(opts) {
|
|
|
4294
4484
|
} else {
|
|
4295
4485
|
runAt = /* @__PURE__ */ new Date();
|
|
4296
4486
|
}
|
|
4297
|
-
await sql2.unsafe(
|
|
4487
|
+
await sql2.unsafe(
|
|
4488
|
+
`INSERT INTO ${escapeIdent3(table)} (id, type, payload, run_at, schedule) VALUES ($1, $2, $3::jsonb, $4, $5)`,
|
|
4489
|
+
[id2, type, JSON.stringify(payload), runAt.toISOString(), opts2?.schedule || null]
|
|
4490
|
+
);
|
|
4298
4491
|
return id2;
|
|
4299
4492
|
})();
|
|
4300
4493
|
};
|
|
@@ -4320,25 +4513,64 @@ function createPgQueue(opts) {
|
|
|
4320
4513
|
while (inflight > 0) await new Promise((r) => setTimeout(r, 50));
|
|
4321
4514
|
};
|
|
4322
4515
|
mw.jobs = async function jobs(limit) {
|
|
4323
|
-
const rows = await sql2.unsafe(
|
|
4324
|
-
|
|
4516
|
+
const rows = await sql2.unsafe(
|
|
4517
|
+
`SELECT * FROM ${escapeIdent3(table)} WHERE status = 'pending' ORDER BY run_at LIMIT $1`,
|
|
4518
|
+
[limit ?? 50]
|
|
4519
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4520
|
+
);
|
|
4521
|
+
return rows.map((r) => ({
|
|
4522
|
+
id: r.id,
|
|
4523
|
+
type: r.type,
|
|
4524
|
+
payload: typeof r.payload === "string" ? JSON.parse(r.payload) : r.payload,
|
|
4525
|
+
createdAt: new Date(r.created_at).getTime(),
|
|
4526
|
+
runAt: new Date(r.run_at).getTime(),
|
|
4527
|
+
schedule: r.schedule || void 0
|
|
4528
|
+
}));
|
|
4325
4529
|
};
|
|
4326
4530
|
mw.failedJobs = async function failedJobs(limit) {
|
|
4327
|
-
const rows = await sql2.unsafe(
|
|
4328
|
-
|
|
4531
|
+
const rows = await sql2.unsafe(
|
|
4532
|
+
`SELECT * FROM ${escapeIdent3(table)} WHERE status = 'failed' ORDER BY failed_at DESC LIMIT $1`,
|
|
4533
|
+
[limit ?? 50]
|
|
4534
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4535
|
+
);
|
|
4536
|
+
return rows.map((r) => ({
|
|
4537
|
+
id: r.id,
|
|
4538
|
+
type: r.type,
|
|
4539
|
+
payload: typeof r.payload === "string" ? JSON.parse(r.payload) : r.payload,
|
|
4540
|
+
createdAt: new Date(r.created_at).getTime(),
|
|
4541
|
+
runAt: new Date(r.run_at).getTime(),
|
|
4542
|
+
schedule: r.schedule || void 0,
|
|
4543
|
+
error: r.error || "",
|
|
4544
|
+
failedAt: new Date(r.failed_at).getTime()
|
|
4545
|
+
}));
|
|
4329
4546
|
};
|
|
4330
4547
|
mw.retryFailed = async function retryFailed(jobId) {
|
|
4331
|
-
const result = await sql2.unsafe(
|
|
4548
|
+
const result = await sql2.unsafe(
|
|
4549
|
+
`UPDATE ${escapeIdent3(table)} SET status = 'pending', error = NULL, failed_at = NULL, run_at = NOW() WHERE id = $1 AND status = 'failed' RETURNING id`,
|
|
4550
|
+
[jobId]
|
|
4551
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4552
|
+
);
|
|
4332
4553
|
return result.length > 0;
|
|
4333
4554
|
};
|
|
4334
4555
|
mw.retryAllFailed = async function retryAllFailed(type) {
|
|
4335
|
-
const result = await sql2.unsafe(
|
|
4556
|
+
const result = await sql2.unsafe(
|
|
4557
|
+
type ? `UPDATE ${escapeIdent3(table)} SET status = 'pending', error = NULL, failed_at = NULL, run_at = NOW() WHERE status = 'failed' AND type = $1 RETURNING id` : `UPDATE ${escapeIdent3(table)} SET status = 'pending', error = NULL, failed_at = NULL, run_at = NOW() WHERE status = 'failed' RETURNING id`,
|
|
4558
|
+
type ? [type] : []
|
|
4559
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4560
|
+
);
|
|
4336
4561
|
return result.length;
|
|
4337
4562
|
};
|
|
4338
4563
|
mw.dashboard = function dashboard() {
|
|
4339
4564
|
return buildDashboard(q);
|
|
4340
4565
|
};
|
|
4341
|
-
mw.stats = () => ({
|
|
4566
|
+
mw.stats = () => ({
|
|
4567
|
+
running,
|
|
4568
|
+
inflight,
|
|
4569
|
+
processed: _processed,
|
|
4570
|
+
failed: _failed,
|
|
4571
|
+
handlers: handlers.size,
|
|
4572
|
+
maxConcurrent: MAX_CONCURRENT
|
|
4573
|
+
});
|
|
4342
4574
|
attachCron(q, handlers);
|
|
4343
4575
|
return q;
|
|
4344
4576
|
}
|
|
@@ -4367,7 +4599,16 @@ function createRedisQueue(opts) {
|
|
|
4367
4599
|
if (job.schedule) {
|
|
4368
4600
|
try {
|
|
4369
4601
|
const nextRun = cronNext(job.schedule);
|
|
4370
|
-
await redis2.zadd(
|
|
4602
|
+
await redis2.zadd(
|
|
4603
|
+
jobKey,
|
|
4604
|
+
nextRun,
|
|
4605
|
+
JSON.stringify({
|
|
4606
|
+
...job,
|
|
4607
|
+
id: crypto6.randomUUID(),
|
|
4608
|
+
runAt: nextRun,
|
|
4609
|
+
createdAt: Date.now()
|
|
4610
|
+
})
|
|
4611
|
+
);
|
|
4371
4612
|
} catch (e) {
|
|
4372
4613
|
console.error("[queue] cron re-queue failed:", e.message);
|
|
4373
4614
|
}
|
|
@@ -4501,7 +4742,14 @@ function createRedisQueue(opts) {
|
|
|
4501
4742
|
mw.dashboard = function dashboard() {
|
|
4502
4743
|
return buildDashboard(q);
|
|
4503
4744
|
};
|
|
4504
|
-
mw.stats = () => ({
|
|
4745
|
+
mw.stats = () => ({
|
|
4746
|
+
running,
|
|
4747
|
+
inflight,
|
|
4748
|
+
processed: _processed,
|
|
4749
|
+
failed: _failed,
|
|
4750
|
+
handlers: handlers.size,
|
|
4751
|
+
maxConcurrent: MAX_CONCURRENT
|
|
4752
|
+
});
|
|
4505
4753
|
attachCron(q, handlers);
|
|
4506
4754
|
return q;
|
|
4507
4755
|
}
|
|
@@ -4649,10 +4897,14 @@ function createIndexesSQL(tenantId, slug, fields) {
|
|
|
4649
4897
|
const name = internalTableName(tenantId, slug);
|
|
4650
4898
|
const statements = [];
|
|
4651
4899
|
statements.push(`CREATE INDEX IF NOT EXISTS "${name}_tenant_idx" ON "${name}" ("tenant_id")`);
|
|
4652
|
-
statements.push(
|
|
4900
|
+
statements.push(
|
|
4901
|
+
`CREATE INDEX IF NOT EXISTS "${name}_tenant_id_idx" ON "${name}" ("tenant_id", "id")`
|
|
4902
|
+
);
|
|
4653
4903
|
for (const f of fields) {
|
|
4654
4904
|
if (f.unique) {
|
|
4655
|
-
statements.push(
|
|
4905
|
+
statements.push(
|
|
4906
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS "${name}_${f.name}_uidx" ON "${name}" ("${f.name}")`
|
|
4907
|
+
);
|
|
4656
4908
|
} else if (f.index === "hnsw") {
|
|
4657
4909
|
statements.push(
|
|
4658
4910
|
`CREATE INDEX IF NOT EXISTS "${name}_${f.name}_hnsw_idx" ON "${name}" USING hnsw ("${f.name}" vector_cosine_ops)`
|
|
@@ -4914,10 +5166,9 @@ function buildRouter(sql2, usersTable) {
|
|
|
4914
5166
|
`SELECT *, "${searchField}" ${operator} $1::vector AS "_distance" FROM "${name2}" WHERE tenant_id = $2 ORDER BY "_distance" LIMIT $3 OFFSET $4`,
|
|
4915
5167
|
[parsed, ctx.tenant.id, limit, offset]
|
|
4916
5168
|
),
|
|
4917
|
-
sql2.unsafe(
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
)
|
|
5169
|
+
sql2.unsafe(`SELECT count(*) as count FROM "${name2}" WHERE tenant_id = $1`, [
|
|
5170
|
+
ctx.tenant.id
|
|
5171
|
+
])
|
|
4921
5172
|
]);
|
|
4922
5173
|
return Response.json({ rows: rows2, count: extractCount(countResult2) });
|
|
4923
5174
|
} catch {
|
|
@@ -4930,10 +5181,7 @@ function buildRouter(sql2, usersTable) {
|
|
|
4930
5181
|
`SELECT * FROM "${name}" WHERE tenant_id = $1 ORDER BY "${orderCol}" ${orderDir} LIMIT $2 OFFSET $3`,
|
|
4931
5182
|
[ctx.tenant.id, limit, offset]
|
|
4932
5183
|
),
|
|
4933
|
-
sql2.unsafe(
|
|
4934
|
-
`SELECT count(*) as count FROM "${name}" WHERE tenant_id = $1`,
|
|
4935
|
-
[ctx.tenant.id]
|
|
4936
|
-
)
|
|
5184
|
+
sql2.unsafe(`SELECT count(*) as count FROM "${name}" WHERE tenant_id = $1`, [ctx.tenant.id])
|
|
4937
5185
|
]);
|
|
4938
5186
|
return Response.json({ rows, count: extractCount(countResult) });
|
|
4939
5187
|
});
|
|
@@ -5015,7 +5263,10 @@ function buildRouter(sql2, usersTable) {
|
|
|
5015
5263
|
if (!childTable) return Response.json({ error: "Nested table not found" }, { status: 404 });
|
|
5016
5264
|
const relField = findRelation(childTable.fields, ctx.params["_slug"]);
|
|
5017
5265
|
if (!relField) {
|
|
5018
|
-
return Response.json(
|
|
5266
|
+
return Response.json(
|
|
5267
|
+
{ error: `No relation from "${nestedSlug}" to "${ctx.params["_slug"]}"` },
|
|
5268
|
+
{ status: 400 }
|
|
5269
|
+
);
|
|
5019
5270
|
}
|
|
5020
5271
|
const relFields = getRelationFields(childTable.fields);
|
|
5021
5272
|
if (relFields.length === 2) {
|
|
@@ -5086,11 +5337,11 @@ import {
|
|
|
5086
5337
|
GraphQLID,
|
|
5087
5338
|
GraphQLList,
|
|
5088
5339
|
GraphQLNonNull,
|
|
5089
|
-
GraphQLEnumType
|
|
5340
|
+
GraphQLEnumType,
|
|
5341
|
+
graphql as executeGraphQL2
|
|
5090
5342
|
} from "graphql";
|
|
5091
|
-
import { graphql as executeGraphQL2 } from "graphql";
|
|
5092
5343
|
function graphqlType(field, required) {
|
|
5093
|
-
let t;
|
|
5344
|
+
let t = GraphQLString;
|
|
5094
5345
|
switch (field.type) {
|
|
5095
5346
|
case "integer":
|
|
5096
5347
|
t = GraphQLInt;
|
|
@@ -5107,15 +5358,11 @@ function graphqlType(field, required) {
|
|
|
5107
5358
|
name: `Enum_${field.name}`,
|
|
5108
5359
|
values: Object.fromEntries(field.options.map((o) => [o, { value: o }]))
|
|
5109
5360
|
});
|
|
5110
|
-
} else {
|
|
5111
|
-
t = GraphQLString;
|
|
5112
5361
|
}
|
|
5113
5362
|
break;
|
|
5114
5363
|
case "vector":
|
|
5115
5364
|
t = GraphQLString;
|
|
5116
5365
|
break;
|
|
5117
|
-
default:
|
|
5118
|
-
t = GraphQLString;
|
|
5119
5366
|
}
|
|
5120
5367
|
return required ? new GraphQLNonNull(t) : t;
|
|
5121
5368
|
}
|
|
@@ -5142,6 +5389,7 @@ function buildObjectType(table, ctx) {
|
|
|
5142
5389
|
limit: { type: GraphQLInt, defaultValue: 20 },
|
|
5143
5390
|
offset: { type: GraphQLInt, defaultValue: 0 }
|
|
5144
5391
|
},
|
|
5392
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5145
5393
|
resolve: async (parent) => {
|
|
5146
5394
|
const childName = internalTableName(ctx.tenantId, other.slug);
|
|
5147
5395
|
const rows = await ctx.sql.unsafe(
|
|
@@ -5164,6 +5412,7 @@ function buildObjectType(table, ctx) {
|
|
|
5164
5412
|
limit: { type: GraphQLInt, defaultValue: 20 },
|
|
5165
5413
|
offset: { type: GraphQLInt, defaultValue: 0 }
|
|
5166
5414
|
},
|
|
5415
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5167
5416
|
resolve: async (parent) => {
|
|
5168
5417
|
const childName = internalTableName(ctx.tenantId, other.slug);
|
|
5169
5418
|
const targetName = internalTableName(ctx.tenantId, targetSlug);
|
|
@@ -5185,6 +5434,7 @@ function buildObjectType(table, ctx) {
|
|
|
5185
5434
|
if (!targetTable) continue;
|
|
5186
5435
|
fields[targetSlug] = {
|
|
5187
5436
|
type: buildObjectType(targetTable, ctx),
|
|
5437
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5188
5438
|
resolve: async (parent) => {
|
|
5189
5439
|
const name = internalTableName(ctx.tenantId, targetSlug);
|
|
5190
5440
|
const [row] = await ctx.sql.unsafe(
|
|
@@ -5205,9 +5455,7 @@ function buildInputType(table, prefix) {
|
|
|
5205
5455
|
const typeName = pascalCase(`${prefix}_${table.slug}`) + "Input";
|
|
5206
5456
|
return new GraphQLInputObjectType({
|
|
5207
5457
|
name: typeName,
|
|
5208
|
-
fields: Object.fromEntries(
|
|
5209
|
-
table.fields.map((f) => [f.name, { type: inputGraphqlType(f) }])
|
|
5210
|
-
)
|
|
5458
|
+
fields: Object.fromEntries(table.fields.map((f) => [f.name, { type: inputGraphqlType(f) }]))
|
|
5211
5459
|
});
|
|
5212
5460
|
}
|
|
5213
5461
|
function buildQueryFields(tables, ctx) {
|
|
@@ -5222,6 +5470,7 @@ function buildQueryFields(tables, ctx) {
|
|
|
5222
5470
|
limit: { type: GraphQLInt, defaultValue: 20 },
|
|
5223
5471
|
offset: { type: GraphQLInt, defaultValue: 0 }
|
|
5224
5472
|
},
|
|
5473
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5225
5474
|
resolve: async (_, args) => {
|
|
5226
5475
|
const name = internalTableName(ctx.tenantId, slug);
|
|
5227
5476
|
const rows = await ctx.sql.unsafe(
|
|
@@ -5234,6 +5483,7 @@ function buildQueryFields(tables, ctx) {
|
|
|
5234
5483
|
fields[`get${pascal}`] = {
|
|
5235
5484
|
type: objType,
|
|
5236
5485
|
args: { id: { type: new GraphQLNonNull(GraphQLID) } },
|
|
5486
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5237
5487
|
resolve: async (_, args) => {
|
|
5238
5488
|
const name = internalTableName(ctx.tenantId, slug);
|
|
5239
5489
|
const [row] = await ctx.sql.unsafe(
|
|
@@ -5256,6 +5506,7 @@ function buildMutationFields(tables, ctx) {
|
|
|
5256
5506
|
fields[`create${pascal}`] = {
|
|
5257
5507
|
type: objType,
|
|
5258
5508
|
args: { data: { type: new GraphQLNonNull(inputType) } },
|
|
5509
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5259
5510
|
resolve: async (_, args) => {
|
|
5260
5511
|
const name = internalTableName(ctx.tenantId, table.slug);
|
|
5261
5512
|
const data = { ...args.data, tenant_id: ctx.tenantId };
|
|
@@ -5272,6 +5523,7 @@ function buildMutationFields(tables, ctx) {
|
|
|
5272
5523
|
id: { type: new GraphQLNonNull(GraphQLID) },
|
|
5273
5524
|
data: { type: new GraphQLNonNull(patchType) }
|
|
5274
5525
|
},
|
|
5526
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5275
5527
|
resolve: async (_, args) => {
|
|
5276
5528
|
const name = internalTableName(ctx.tenantId, table.slug);
|
|
5277
5529
|
const setClauses = table.fields.filter((f) => args.data[f.name] !== void 0).map((f, i) => `"${f.name}" = $${i + 1}`);
|
|
@@ -5294,6 +5546,7 @@ function buildMutationFields(tables, ctx) {
|
|
|
5294
5546
|
fields[`delete${pascal}`] = {
|
|
5295
5547
|
type: GraphQLBoolean,
|
|
5296
5548
|
args: { id: { type: new GraphQLNonNull(GraphQLID) } },
|
|
5549
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5297
5550
|
resolve: async (_, args) => {
|
|
5298
5551
|
const name = internalTableName(ctx.tenantId, table.slug);
|
|
5299
5552
|
const result = await ctx.sql.unsafe(
|
|
@@ -5338,23 +5591,23 @@ function buildGraphQLHandler(sql2) {
|
|
|
5338
5591
|
});
|
|
5339
5592
|
return Response.json(result, { status: result.errors ? 400 : 200 });
|
|
5340
5593
|
});
|
|
5341
|
-
r.get("/", async (req,
|
|
5594
|
+
r.get("/", async (req, _ctx2) => {
|
|
5342
5595
|
const url = new URL(req.url);
|
|
5343
5596
|
if (url.searchParams.has("query")) {
|
|
5344
|
-
return handleGET(req,
|
|
5597
|
+
return handleGET(req, _ctx2);
|
|
5345
5598
|
}
|
|
5346
5599
|
return new Response("GraphQL endpoint. Send POST /graphql with { query, variables }", {
|
|
5347
5600
|
status: 200,
|
|
5348
5601
|
headers: { "Content-Type": "text/plain" }
|
|
5349
5602
|
});
|
|
5350
5603
|
});
|
|
5351
|
-
async function handleGET(req,
|
|
5604
|
+
async function handleGET(req, _ctx2) {
|
|
5352
5605
|
const tables = await sql2`
|
|
5353
5606
|
SELECT * FROM "_user_tables"
|
|
5354
|
-
WHERE tenant_id = ${
|
|
5607
|
+
WHERE tenant_id = ${_ctx2.tenant.id}
|
|
5355
5608
|
ORDER BY created_at ASC
|
|
5356
5609
|
`;
|
|
5357
|
-
const buildCtx = { sql: sql2, tenantId:
|
|
5610
|
+
const buildCtx = { sql: sql2, tenantId: _ctx2.tenant.id, tables, typeCache: /* @__PURE__ */ new Map() };
|
|
5358
5611
|
const schema = new GraphQLSchema({
|
|
5359
5612
|
query: new GraphQLObjectType({
|
|
5360
5613
|
name: "Query",
|
|
@@ -5374,7 +5627,7 @@ function buildGraphQLHandler(sql2) {
|
|
|
5374
5627
|
source: query,
|
|
5375
5628
|
variableValues: variables,
|
|
5376
5629
|
operationName: url.searchParams.get("operationName") || void 0,
|
|
5377
|
-
contextValue:
|
|
5630
|
+
contextValue: _ctx2
|
|
5378
5631
|
});
|
|
5379
5632
|
return Response.json(result, { status: result.errors ? 400 : 200 });
|
|
5380
5633
|
}
|
|
@@ -5404,7 +5657,9 @@ function tenant(options) {
|
|
|
5404
5657
|
});
|
|
5405
5658
|
await members.create();
|
|
5406
5659
|
await members.createIndex("user_id");
|
|
5407
|
-
await sql2.unsafe(
|
|
5660
|
+
await sql2.unsafe(
|
|
5661
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS "_tenant_members_unique_idx" ON "_tenant_members" ("tenant_id", "user_id")`
|
|
5662
|
+
);
|
|
5408
5663
|
const tables = pg.table("_user_tables", {
|
|
5409
5664
|
id: serial("id").primaryKey(),
|
|
5410
5665
|
tenant_id: text("tenant_id").notNull().references("_tenants", "id", "cascade"),
|
|
@@ -5415,7 +5670,9 @@ function tenant(options) {
|
|
|
5415
5670
|
});
|
|
5416
5671
|
await tables.create();
|
|
5417
5672
|
await tables.createIndex("tenant_id");
|
|
5418
|
-
await sql2.unsafe(
|
|
5673
|
+
await sql2.unsafe(
|
|
5674
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS "_user_tables_unique_idx" ON "_user_tables" ("tenant_id", "slug")`
|
|
5675
|
+
);
|
|
5419
5676
|
}
|
|
5420
5677
|
function middleware() {
|
|
5421
5678
|
return async (req, ctx, next) => {
|
|
@@ -5439,10 +5696,13 @@ function tenant(options) {
|
|
|
5439
5696
|
}
|
|
5440
5697
|
const headerId = req.headers.get("X-Tenant-ID");
|
|
5441
5698
|
if (!headerId) {
|
|
5442
|
-
return Response.json(
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5699
|
+
return Response.json(
|
|
5700
|
+
{
|
|
5701
|
+
error: "Multiple tenants. Set X-Tenant-ID header.",
|
|
5702
|
+
tenants: members.map((m) => ({ id: m.id, name: m.name, role: m.role }))
|
|
5703
|
+
},
|
|
5704
|
+
{ status: 300 }
|
|
5705
|
+
);
|
|
5446
5706
|
}
|
|
5447
5707
|
const member = members.find((m) => m.id === headerId);
|
|
5448
5708
|
if (!member) {
|
|
@@ -5483,7 +5743,9 @@ function buildRouter2(deps) {
|
|
|
5483
5743
|
return Response.json(row, { status: 201 });
|
|
5484
5744
|
});
|
|
5485
5745
|
r.get("/agents", async () => {
|
|
5486
|
-
const { data: rows } = await agentsTable.readMany(void 0, {
|
|
5746
|
+
const { data: rows } = await agentsTable.readMany(void 0, {
|
|
5747
|
+
orderBy: { created_at: "desc" }
|
|
5748
|
+
});
|
|
5487
5749
|
return Response.json(rows);
|
|
5488
5750
|
});
|
|
5489
5751
|
r.get("/agents/:id", async (_req, ctx) => {
|
|
@@ -5497,7 +5759,14 @@ function buildRouter2(deps) {
|
|
|
5497
5759
|
if (!agent2) return Response.json({ error: "Agent not found" }, { status: 404 });
|
|
5498
5760
|
const body = await req.json();
|
|
5499
5761
|
const updateData = {};
|
|
5500
|
-
for (const key of [
|
|
5762
|
+
for (const key of [
|
|
5763
|
+
"name",
|
|
5764
|
+
"description",
|
|
5765
|
+
"type",
|
|
5766
|
+
"model",
|
|
5767
|
+
"system_prompt",
|
|
5768
|
+
"active"
|
|
5769
|
+
]) {
|
|
5501
5770
|
if (body[key] !== void 0) {
|
|
5502
5771
|
updateData[key] = body[key];
|
|
5503
5772
|
}
|
|
@@ -5634,7 +5903,9 @@ function chunkContent(content, chunkSize, overlap) {
|
|
|
5634
5903
|
|
|
5635
5904
|
// agent/run.ts
|
|
5636
5905
|
function hasKnowledgeDocs(sql2, agentId) {
|
|
5637
|
-
return sql2`SELECT 1 FROM "_knowledge_documents" WHERE agent_id = ${agentId} LIMIT 1`.then(
|
|
5906
|
+
return sql2`SELECT 1 FROM "_knowledge_documents" WHERE agent_id = ${agentId} LIMIT 1`.then(
|
|
5907
|
+
(r) => r.length > 0
|
|
5908
|
+
);
|
|
5638
5909
|
}
|
|
5639
5910
|
async function searchKnowledge(sql2, provider, agentId, query, limit = 5) {
|
|
5640
5911
|
const embedding = await provider.embed(query);
|
|
@@ -5808,7 +6079,14 @@ function agent(options) {
|
|
|
5808
6079
|
trace_id: text("trace_id"),
|
|
5809
6080
|
created_at: timestamptz("created_at").notNull().default(sql`NOW()`)
|
|
5810
6081
|
});
|
|
5811
|
-
const runner = createRunner({
|
|
6082
|
+
const runner = createRunner({
|
|
6083
|
+
sql: sql2,
|
|
6084
|
+
agents: agentsTable,
|
|
6085
|
+
runs: runsTable,
|
|
6086
|
+
knowledge: knowledgeTable,
|
|
6087
|
+
provider: resolvedProvider,
|
|
6088
|
+
userTools: options.tools
|
|
6089
|
+
});
|
|
5812
6090
|
const base = new PgModule(pg);
|
|
5813
6091
|
const r = buildRouter2({ agents: agentsTable, runs: runsTable, knowledge: knowledgeTable, runner });
|
|
5814
6092
|
const mod = r;
|
|
@@ -6376,14 +6654,14 @@ function forkApp(opts) {
|
|
|
6376
6654
|
return { child, port: opts.port };
|
|
6377
6655
|
}
|
|
6378
6656
|
function stopProcess(mp, timeout = 1e4) {
|
|
6379
|
-
return new Promise((
|
|
6657
|
+
return new Promise((resolve16) => {
|
|
6380
6658
|
const timer = setTimeout(() => {
|
|
6381
6659
|
mp.child.kill("SIGKILL");
|
|
6382
|
-
|
|
6660
|
+
resolve16();
|
|
6383
6661
|
}, timeout);
|
|
6384
6662
|
mp.child.on("exit", () => {
|
|
6385
6663
|
clearTimeout(timer);
|
|
6386
|
-
|
|
6664
|
+
resolve16();
|
|
6387
6665
|
});
|
|
6388
6666
|
mp.child.kill("SIGTERM");
|
|
6389
6667
|
});
|
|
@@ -6577,12 +6855,24 @@ async function deploy(config) {
|
|
|
6577
6855
|
if (ac.ports && old?.process) {
|
|
6578
6856
|
targetPort = old.currentPort === ac.ports[0] ? ac.ports[1] : ac.ports[0];
|
|
6579
6857
|
}
|
|
6580
|
-
const mp = await forkAndCheck(
|
|
6858
|
+
const mp = await forkAndCheck(
|
|
6859
|
+
name,
|
|
6860
|
+
appDir,
|
|
6861
|
+
ac.entry,
|
|
6862
|
+
targetPort,
|
|
6863
|
+
ac.env,
|
|
6864
|
+
log,
|
|
6865
|
+
ac.healthEndpoint
|
|
6866
|
+
);
|
|
6581
6867
|
if (!mp) {
|
|
6582
6868
|
log("[deploy] new process failed to start, keeping old running");
|
|
6583
6869
|
if (old?.process) apps.set(name, old);
|
|
6584
6870
|
else {
|
|
6585
|
-
setAppRuntime(name, ac, logs, {
|
|
6871
|
+
setAppRuntime(name, ac, logs, {
|
|
6872
|
+
status: "error",
|
|
6873
|
+
port: targetPort,
|
|
6874
|
+
error: "failed to start"
|
|
6875
|
+
});
|
|
6586
6876
|
}
|
|
6587
6877
|
return;
|
|
6588
6878
|
}
|
|
@@ -6625,7 +6915,7 @@ async function deploy(config) {
|
|
|
6625
6915
|
function setAppRuntime(name, ac, logs, overrides) {
|
|
6626
6916
|
apps.set(name, {
|
|
6627
6917
|
config: ac,
|
|
6628
|
-
status: { name, ...overrides },
|
|
6918
|
+
status: { name, status: "starting", port: 0, ...overrides },
|
|
6629
6919
|
logs,
|
|
6630
6920
|
process: null,
|
|
6631
6921
|
currentPort: overrides.port ?? ac.port ?? 0,
|
|
@@ -6703,22 +6993,168 @@ import { createOpenAI as createOpenAI3 } from "@ai-sdk/openai";
|
|
|
6703
6993
|
|
|
6704
6994
|
// ssr.ts
|
|
6705
6995
|
import { createElement as createElement3 } from "react";
|
|
6706
|
-
import { createHash as
|
|
6707
|
-
import { existsSync as
|
|
6996
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
6997
|
+
import { existsSync as existsSync6, readdirSync } from "node:fs";
|
|
6708
6998
|
import { readdir, stat } from "node:fs/promises";
|
|
6709
|
-
import { dirname as
|
|
6999
|
+
import { dirname as dirname4, join as join5, resolve as resolve8, relative as relative3 } from "node:path";
|
|
6710
7000
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
6711
7001
|
|
|
6712
7002
|
// compile.ts
|
|
6713
|
-
import * as
|
|
6714
|
-
import { existsSync, mkdirSync, readFileSync as
|
|
6715
|
-
import { join as join2, resolve as
|
|
7003
|
+
import * as esbuild2 from "esbuild";
|
|
7004
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync3 } from "node:fs";
|
|
7005
|
+
import { join as join2, resolve as resolve4, dirname as dirname2 } from "node:path";
|
|
6716
7006
|
import { pathToFileURL } from "node:url";
|
|
6717
7007
|
import { createHash } from "node:crypto";
|
|
7008
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
7009
|
+
|
|
7010
|
+
// server-registry.ts
|
|
7011
|
+
import * as esbuild from "esbuild";
|
|
7012
|
+
import { existsSync, readFileSync as readFileSync2, statSync } from "node:fs";
|
|
7013
|
+
import { resolve as resolve3, dirname } from "node:path";
|
|
6718
7014
|
import vm from "node:vm";
|
|
6719
7015
|
import { createRequire } from "node:module";
|
|
6720
|
-
var _cjsRequire = createRequire(import.meta.url);
|
|
6721
7016
|
var _userRequire = null;
|
|
7017
|
+
function getUserRequire() {
|
|
7018
|
+
if (!_userRequire) {
|
|
7019
|
+
try {
|
|
7020
|
+
_userRequire = createRequire(resolve3(process.cwd(), "package.json"));
|
|
7021
|
+
} catch {
|
|
7022
|
+
_userRequire = createRequire(import.meta.url);
|
|
7023
|
+
}
|
|
7024
|
+
}
|
|
7025
|
+
return _userRequire;
|
|
7026
|
+
}
|
|
7027
|
+
var _alias = null;
|
|
7028
|
+
function resolveAliases() {
|
|
7029
|
+
if (_alias) return _alias;
|
|
7030
|
+
const configFiles = ["tsconfig.json", "jsconfig.json"];
|
|
7031
|
+
for (const file of configFiles) {
|
|
7032
|
+
const p = resolve3(file);
|
|
7033
|
+
if (existsSync(p)) {
|
|
7034
|
+
try {
|
|
7035
|
+
const config = JSON.parse(readFileSync2(p, "utf-8"));
|
|
7036
|
+
const paths = config.compilerOptions?.paths;
|
|
7037
|
+
if (paths) {
|
|
7038
|
+
const alias = {};
|
|
7039
|
+
for (const [key, values] of Object.entries(paths)) {
|
|
7040
|
+
const cleanKey = key.replace("/*", "");
|
|
7041
|
+
const val = values[0]?.replace("/*", "");
|
|
7042
|
+
if (val) alias[cleanKey] = resolve3(dirname(p), val);
|
|
7043
|
+
}
|
|
7044
|
+
_alias = alias;
|
|
7045
|
+
return alias;
|
|
7046
|
+
}
|
|
7047
|
+
} catch {
|
|
7048
|
+
}
|
|
7049
|
+
}
|
|
7050
|
+
}
|
|
7051
|
+
_alias = {};
|
|
7052
|
+
return {};
|
|
7053
|
+
}
|
|
7054
|
+
function applyAlias(id2, _moduleDir) {
|
|
7055
|
+
const aliases = resolveAliases();
|
|
7056
|
+
for (const [prefix, target] of Object.entries(aliases)) {
|
|
7057
|
+
if (id2.startsWith(prefix)) {
|
|
7058
|
+
const rest = id2.slice(prefix.length);
|
|
7059
|
+
return target + rest;
|
|
7060
|
+
}
|
|
7061
|
+
}
|
|
7062
|
+
return null;
|
|
7063
|
+
}
|
|
7064
|
+
var exts = [".tsx", ".ts", ".jsx", ".js"];
|
|
7065
|
+
function tryResolve(base) {
|
|
7066
|
+
if (existsSync(base)) {
|
|
7067
|
+
const stat3 = statSync(base);
|
|
7068
|
+
if (stat3.isFile()) return base;
|
|
7069
|
+
if (stat3.isDirectory()) {
|
|
7070
|
+
for (const ext of exts) {
|
|
7071
|
+
const p = resolve3(base, `index${ext}`);
|
|
7072
|
+
if (existsSync(p)) return p;
|
|
7073
|
+
}
|
|
7074
|
+
return null;
|
|
7075
|
+
}
|
|
7076
|
+
}
|
|
7077
|
+
for (const ext of exts) {
|
|
7078
|
+
const p = base + ext;
|
|
7079
|
+
if (existsSync(p)) return p;
|
|
7080
|
+
}
|
|
7081
|
+
return null;
|
|
7082
|
+
}
|
|
7083
|
+
var registry = /* @__PURE__ */ new Map();
|
|
7084
|
+
var _ctx = vm.createContext(Object.create(globalThis));
|
|
7085
|
+
function transformToCjs(absPath, source) {
|
|
7086
|
+
const isTsx = absPath.endsWith(".tsx");
|
|
7087
|
+
const result = esbuild.transformSync(source, {
|
|
7088
|
+
loader: isTsx ? "tsx" : "ts",
|
|
7089
|
+
format: "cjs",
|
|
7090
|
+
jsx: isTsx ? "automatic" : void 0,
|
|
7091
|
+
jsxImportSource: isTsx ? "react" : void 0,
|
|
7092
|
+
sourcemap: false
|
|
7093
|
+
});
|
|
7094
|
+
return result.code;
|
|
7095
|
+
}
|
|
7096
|
+
function makeRequire(modulePath) {
|
|
7097
|
+
const moduleDir = dirname(modulePath);
|
|
7098
|
+
return (id2) => {
|
|
7099
|
+
if (id2.startsWith(".")) {
|
|
7100
|
+
const base = resolve3(moduleDir, id2);
|
|
7101
|
+
const file = tryResolve(base);
|
|
7102
|
+
if (!file) {
|
|
7103
|
+
throw new Error(
|
|
7104
|
+
`[server-registry] Cannot resolve '${id2}' from '${modulePath}'. Tried: ${[base, ...exts.map((e) => base + e)].filter((p) => !p.endsWith(base)).join(", ")}`
|
|
7105
|
+
);
|
|
7106
|
+
}
|
|
7107
|
+
return getServerModule(file);
|
|
7108
|
+
}
|
|
7109
|
+
const aliased = applyAlias(id2, moduleDir);
|
|
7110
|
+
if (aliased) {
|
|
7111
|
+
const file = tryResolve(aliased);
|
|
7112
|
+
if (file) return getServerModule(file);
|
|
7113
|
+
}
|
|
7114
|
+
return getUserRequire()(id2);
|
|
7115
|
+
};
|
|
7116
|
+
}
|
|
7117
|
+
function evaluateModule(code, modulePath) {
|
|
7118
|
+
const mod = { exports: {} };
|
|
7119
|
+
const require2 = makeRequire(modulePath);
|
|
7120
|
+
const _dirname = dirname(modulePath);
|
|
7121
|
+
const _filename = modulePath;
|
|
7122
|
+
const wrapped = `(function(require,module,exports,__dirname,__filename){
|
|
7123
|
+
${code}
|
|
7124
|
+
})`;
|
|
7125
|
+
try {
|
|
7126
|
+
new vm.Script(wrapped).runInContext(_ctx)(require2, mod, mod.exports, _dirname, _filename);
|
|
7127
|
+
} catch (err) {
|
|
7128
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
7129
|
+
const cause = err instanceof Error ? err : void 0;
|
|
7130
|
+
throw new Error(
|
|
7131
|
+
`[server-registry] Error evaluating '${modulePath}': ${msg}`,
|
|
7132
|
+
cause ? { cause } : void 0
|
|
7133
|
+
);
|
|
7134
|
+
}
|
|
7135
|
+
return mod.exports;
|
|
7136
|
+
}
|
|
7137
|
+
function getServerModule(absPath) {
|
|
7138
|
+
const normalized = resolve3(absPath);
|
|
7139
|
+
if (registry.has(normalized)) return registry.get(normalized).exports;
|
|
7140
|
+
const source = readFileSync2(normalized, "utf-8");
|
|
7141
|
+
const code = transformToCjs(normalized, source);
|
|
7142
|
+
const exports = evaluateModule(code, normalized);
|
|
7143
|
+
registry.set(normalized, { exports });
|
|
7144
|
+
return exports;
|
|
7145
|
+
}
|
|
7146
|
+
function clearServerModule(absPath) {
|
|
7147
|
+
if (absPath) {
|
|
7148
|
+
const normalized = resolve3(absPath);
|
|
7149
|
+
registry.delete(normalized);
|
|
7150
|
+
} else {
|
|
7151
|
+
registry.clear();
|
|
7152
|
+
_alias = null;
|
|
7153
|
+
}
|
|
7154
|
+
}
|
|
7155
|
+
|
|
7156
|
+
// compile.ts
|
|
7157
|
+
var _userRequire2 = null;
|
|
6722
7158
|
var OUT_DIR = ".weifuwu/ssr";
|
|
6723
7159
|
var cache = /* @__PURE__ */ new Map();
|
|
6724
7160
|
var externals = [
|
|
@@ -6731,31 +7167,31 @@ var externals = [
|
|
|
6731
7167
|
"@graphql-tools/schema",
|
|
6732
7168
|
"ai"
|
|
6733
7169
|
];
|
|
6734
|
-
var
|
|
6735
|
-
function
|
|
6736
|
-
if (
|
|
7170
|
+
var _alias2 = null;
|
|
7171
|
+
function resolveAliases2() {
|
|
7172
|
+
if (_alias2) return _alias2;
|
|
6737
7173
|
const configFiles = ["tsconfig.json", "jsconfig.json"];
|
|
6738
7174
|
for (const file of configFiles) {
|
|
6739
|
-
const p =
|
|
6740
|
-
if (
|
|
7175
|
+
const p = resolve4(file);
|
|
7176
|
+
if (existsSync2(p)) {
|
|
6741
7177
|
try {
|
|
6742
|
-
const config = JSON.parse(
|
|
7178
|
+
const config = JSON.parse(readFileSync3(p, "utf-8"));
|
|
6743
7179
|
const paths = config.compilerOptions?.paths;
|
|
6744
7180
|
if (paths) {
|
|
6745
7181
|
const alias = {};
|
|
6746
7182
|
for (const [key, values] of Object.entries(paths)) {
|
|
6747
7183
|
const cleanKey = key.replace("/*", "");
|
|
6748
7184
|
const val = values[0]?.replace("/*", "");
|
|
6749
|
-
if (val) alias[cleanKey] =
|
|
7185
|
+
if (val) alias[cleanKey] = resolve4(dirname2(p), val);
|
|
6750
7186
|
}
|
|
6751
|
-
|
|
7187
|
+
_alias2 = alias;
|
|
6752
7188
|
return alias;
|
|
6753
7189
|
}
|
|
6754
7190
|
} catch {
|
|
6755
7191
|
}
|
|
6756
7192
|
}
|
|
6757
7193
|
}
|
|
6758
|
-
|
|
7194
|
+
_alias2 = {};
|
|
6759
7195
|
return {};
|
|
6760
7196
|
}
|
|
6761
7197
|
function id(s) {
|
|
@@ -6763,16 +7199,17 @@ function id(s) {
|
|
|
6763
7199
|
}
|
|
6764
7200
|
function clearCompileCache() {
|
|
6765
7201
|
cache.clear();
|
|
6766
|
-
|
|
7202
|
+
clearServerModule();
|
|
7203
|
+
_alias2 = null;
|
|
6767
7204
|
}
|
|
6768
7205
|
async function compileTsx(path2) {
|
|
6769
|
-
const absPath =
|
|
7206
|
+
const absPath = resolve4(path2);
|
|
6770
7207
|
if (cache.has(absPath)) return cache.get(absPath);
|
|
6771
|
-
const outDir =
|
|
7208
|
+
const outDir = resolve4(OUT_DIR);
|
|
6772
7209
|
mkdirSync(outDir, { recursive: true });
|
|
6773
7210
|
const hash = id(absPath);
|
|
6774
7211
|
const outPath = join2(outDir, hash + ".js");
|
|
6775
|
-
await
|
|
7212
|
+
await esbuild2.build({
|
|
6776
7213
|
entryPoints: { [hash]: absPath },
|
|
6777
7214
|
outdir: outDir,
|
|
6778
7215
|
format: "esm",
|
|
@@ -6781,7 +7218,7 @@ async function compileTsx(path2) {
|
|
|
6781
7218
|
jsxImportSource: "react",
|
|
6782
7219
|
bundle: true,
|
|
6783
7220
|
external: externals,
|
|
6784
|
-
alias:
|
|
7221
|
+
alias: resolveAliases2(),
|
|
6785
7222
|
write: true,
|
|
6786
7223
|
allowOverwrite: true
|
|
6787
7224
|
});
|
|
@@ -6789,56 +7226,34 @@ async function compileTsx(path2) {
|
|
|
6789
7226
|
cache.set(absPath, mod);
|
|
6790
7227
|
return mod;
|
|
6791
7228
|
}
|
|
6792
|
-
function
|
|
6793
|
-
const
|
|
6794
|
-
const mod =
|
|
6795
|
-
ctx.require = (name) => _cjsRequire(name);
|
|
6796
|
-
ctx.module = mod;
|
|
6797
|
-
ctx.exports = mod.exports;
|
|
6798
|
-
new vm.Script(code).runInContext(ctx);
|
|
6799
|
-
return mod.exports;
|
|
6800
|
-
}
|
|
6801
|
-
async function compileTsxDev(path2) {
|
|
6802
|
-
const absPath = resolve3(path2);
|
|
6803
|
-
if (cache.has(absPath)) return cache.get(absPath);
|
|
6804
|
-
const result = await esbuild.build({
|
|
6805
|
-
entryPoints: { [id(absPath)]: absPath },
|
|
6806
|
-
format: "cjs",
|
|
6807
|
-
platform: "node",
|
|
6808
|
-
jsx: "automatic",
|
|
6809
|
-
jsxImportSource: "react",
|
|
6810
|
-
bundle: true,
|
|
6811
|
-
external: externals,
|
|
6812
|
-
alias: resolveAliases(),
|
|
6813
|
-
write: false
|
|
6814
|
-
});
|
|
6815
|
-
const code = new TextDecoder().decode(result.outputFiles[0].contents);
|
|
6816
|
-
const mod = loadSSRModule(code);
|
|
7229
|
+
function compileTsxDev(path2) {
|
|
7230
|
+
const absPath = resolve4(path2);
|
|
7231
|
+
const mod = getServerModule(absPath);
|
|
6817
7232
|
cache.set(absPath, mod);
|
|
6818
7233
|
return mod;
|
|
6819
7234
|
}
|
|
6820
7235
|
function compile(path2) {
|
|
6821
|
-
return isDev() ? compileTsxDev(path2) : compileTsx(path2);
|
|
7236
|
+
return isDev() ? Promise.resolve(compileTsxDev(path2)) : compileTsx(path2);
|
|
6822
7237
|
}
|
|
6823
7238
|
var vendorBundle = null;
|
|
6824
7239
|
var vendorHash = "";
|
|
6825
7240
|
async function compileVendorBundle() {
|
|
6826
7241
|
if (vendorBundle) return vendorBundle;
|
|
6827
|
-
if (!
|
|
7242
|
+
if (!_userRequire2) _userRequire2 = createRequire2(join2(process.cwd(), "package.json"));
|
|
6828
7243
|
const modules = {
|
|
6829
|
-
|
|
7244
|
+
react: [],
|
|
6830
7245
|
"react-dom": ["react"],
|
|
6831
7246
|
"react-dom/client": ["react"],
|
|
6832
7247
|
"react/jsx-runtime": ["react"]
|
|
6833
7248
|
};
|
|
6834
7249
|
for (const request of Object.keys(modules)) {
|
|
6835
|
-
const mod =
|
|
7250
|
+
const mod = _userRequire2(request);
|
|
6836
7251
|
const keys = Object.keys(mod).filter((k) => !k.startsWith("_") && k !== "default");
|
|
6837
7252
|
modules[request] = keys;
|
|
6838
7253
|
}
|
|
6839
7254
|
const baseDir = import.meta.dirname ?? __dirname;
|
|
6840
|
-
const reactAbsPath = isBundled() ?
|
|
6841
|
-
const reactSrc =
|
|
7255
|
+
const reactAbsPath = isBundled() ? resolve4(baseDir, "react.js") : resolve4(baseDir, "react.ts");
|
|
7256
|
+
const reactSrc = readFileSync3(reactAbsPath, "utf-8");
|
|
6842
7257
|
const wfwKeys = [];
|
|
6843
7258
|
if (reactAbsPath.endsWith(".ts")) {
|
|
6844
7259
|
for (const line of reactSrc.split("\n")) {
|
|
@@ -6863,11 +7278,13 @@ async function compileVendorBundle() {
|
|
|
6863
7278
|
const stmts = [""];
|
|
6864
7279
|
for (const [request, keys] of Object.entries(modules)) {
|
|
6865
7280
|
const unique = keys.filter((k) => !used.has(k) && used.add(k));
|
|
6866
|
-
if (unique.length > 0)
|
|
7281
|
+
if (unique.length > 0)
|
|
7282
|
+
stmts.push(`export { ${unique.join(", ")} } from ${JSON.stringify(request)};`);
|
|
6867
7283
|
}
|
|
6868
7284
|
const uidWfw = wfwKeys.filter((k) => !used.has(k) && used.add(k));
|
|
6869
|
-
if (uidWfw.length > 0)
|
|
6870
|
-
|
|
7285
|
+
if (uidWfw.length > 0)
|
|
7286
|
+
stmts.push(`export { ${uidWfw.join(", ")} } from ${JSON.stringify(reactAbsPath)};`);
|
|
7287
|
+
const result = await esbuild2.build({
|
|
6871
7288
|
stdin: { contents: stmts.join("\n"), resolveDir: process.cwd() },
|
|
6872
7289
|
format: "esm",
|
|
6873
7290
|
bundle: true,
|
|
@@ -6879,81 +7296,6 @@ async function compileVendorBundle() {
|
|
|
6879
7296
|
vendorHash = Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, 8);
|
|
6880
7297
|
return vendorBundle;
|
|
6881
7298
|
}
|
|
6882
|
-
async function compileBrowser(path2, outDir) {
|
|
6883
|
-
const absPath = resolve3(path2);
|
|
6884
|
-
const h = id(absPath);
|
|
6885
|
-
outDir = outDir ?? resolve3(OUT_DIR);
|
|
6886
|
-
const outPath = join2(outDir, h + ".js");
|
|
6887
|
-
if (!isDev() && existsSync(outPath)) return h;
|
|
6888
|
-
mkdirSync(outDir, { recursive: true });
|
|
6889
|
-
const wfwDir = resolve3(import.meta.dirname ?? __dirname);
|
|
6890
|
-
const plugin = {
|
|
6891
|
-
name: "wfw-external",
|
|
6892
|
-
setup(build2) {
|
|
6893
|
-
build2.onResolve({ filter: /./ }, (args) => {
|
|
6894
|
-
if (args.kind === "entry-point") return;
|
|
6895
|
-
const abs = args.path.startsWith(".") ? join2(args.resolveDir, args.path) : args.path;
|
|
6896
|
-
if (abs.startsWith(wfwDir) && !abs.includes("node_modules")) {
|
|
6897
|
-
const rel = abs.slice(wfwDir.length + 1);
|
|
6898
|
-
if (rel.includes("/")) return;
|
|
6899
|
-
return { path: "weifuwu/react", external: true };
|
|
6900
|
-
}
|
|
6901
|
-
});
|
|
6902
|
-
}
|
|
6903
|
-
};
|
|
6904
|
-
await esbuild.build({
|
|
6905
|
-
entryPoints: { [h]: absPath },
|
|
6906
|
-
outdir: outDir,
|
|
6907
|
-
format: "esm",
|
|
6908
|
-
platform: "browser",
|
|
6909
|
-
jsx: "automatic",
|
|
6910
|
-
jsxImportSource: "react",
|
|
6911
|
-
bundle: true,
|
|
6912
|
-
external: ["react", "react-dom", "react-dom/client", "react/jsx-runtime", "weifuwu", "weifuwu/react"],
|
|
6913
|
-
plugins: [plugin],
|
|
6914
|
-
write: true,
|
|
6915
|
-
allowOverwrite: true
|
|
6916
|
-
});
|
|
6917
|
-
return h;
|
|
6918
|
-
}
|
|
6919
|
-
async function compileHotComponent(path2) {
|
|
6920
|
-
const absPath = resolve3(path2);
|
|
6921
|
-
const h = id(absPath);
|
|
6922
|
-
const stdin = `import C from ${JSON.stringify(absPath)};
|
|
6923
|
-
(window.__WFW_REFRESH||function(){})(C)`;
|
|
6924
|
-
const wfwDir = resolve3(import.meta.dirname ?? __dirname);
|
|
6925
|
-
const plugin = {
|
|
6926
|
-
name: "wfw-external",
|
|
6927
|
-
setup(build2) {
|
|
6928
|
-
build2.onResolve({ filter: /./ }, (args) => {
|
|
6929
|
-
if (args.kind === "entry-point") return;
|
|
6930
|
-
const abs = args.path.startsWith(".") ? join2(args.resolveDir, args.path) : args.path;
|
|
6931
|
-
if (abs.startsWith(wfwDir) && !abs.includes("node_modules")) {
|
|
6932
|
-
const rel = abs.slice(wfwDir.length + 1);
|
|
6933
|
-
if (rel.includes("/")) return;
|
|
6934
|
-
return { path: "weifuwu/react", external: true };
|
|
6935
|
-
}
|
|
6936
|
-
});
|
|
6937
|
-
}
|
|
6938
|
-
};
|
|
6939
|
-
const result = await esbuild.build({
|
|
6940
|
-
stdin: { contents: stdin, loader: "tsx", resolveDir: dirname(absPath) },
|
|
6941
|
-
format: "esm",
|
|
6942
|
-
platform: "browser",
|
|
6943
|
-
jsx: "automatic",
|
|
6944
|
-
jsxImportSource: "react",
|
|
6945
|
-
bundle: true,
|
|
6946
|
-
external: ["react", "react-dom", "react-dom/client", "react/jsx-runtime", "weifuwu", "weifuwu/react"],
|
|
6947
|
-
plugins: [plugin],
|
|
6948
|
-
write: false
|
|
6949
|
-
});
|
|
6950
|
-
let code = new TextDecoder().decode(result.outputFiles[0].contents);
|
|
6951
|
-
if (code.includes("__require") && (code.includes('"react"') || code.includes("'react'"))) {
|
|
6952
|
-
code = `import * as __r from 'react';
|
|
6953
|
-
` + code.replace(/__require\(["']react["']\)/g, "__r");
|
|
6954
|
-
}
|
|
6955
|
-
return { hash: h, code };
|
|
6956
|
-
}
|
|
6957
7299
|
|
|
6958
7300
|
// stream.ts
|
|
6959
7301
|
import { TextDecoder as TextDecoder2, TextEncoder as TextEncoder2 } from "node:util";
|
|
@@ -6971,6 +7313,8 @@ function getPublicEnv2() {
|
|
|
6971
7313
|
function buildHeadPayload(opts) {
|
|
6972
7314
|
const { ctx, base, tailwind } = opts;
|
|
6973
7315
|
let result = "";
|
|
7316
|
+
result += `<script>window.__wfw={_cache:{},_k:function(u){return u.split('?')[0]},h:async function(u){var k=this._k(u);if(this._cache[k])return this._cache[k];var m=await import(u);this._cache[k]=m;return m},_update:function(u,mod){var k=this._k(u);this._cache[k]=mod}}</script>
|
|
7317
|
+
`;
|
|
6974
7318
|
const vUrl = `${base}/__wfw/v/bundle?h=${vendorHash}`;
|
|
6975
7319
|
result += `<script type="importmap">{
|
|
6976
7320
|
"imports": {
|
|
@@ -7055,26 +7399,37 @@ function streamResponse(reactStream, opts, hydrationScript) {
|
|
|
7055
7399
|
if (built) bodyScripts += built;
|
|
7056
7400
|
if (opts.isDev) {
|
|
7057
7401
|
const wsUrl = `${opts.base}/__weifuwu/livereload`;
|
|
7058
|
-
const hbUrl = `${opts.base}/__wfw/h/`;
|
|
7059
7402
|
bodyScripts += `
|
|
7060
7403
|
<script>
|
|
7061
7404
|
(function(){
|
|
7062
7405
|
var ws=new WebSocket((location.protocol==='https:'?'wss:':'ws:')+'//'+location.host+'${wsUrl}');
|
|
7063
7406
|
var t=0;
|
|
7407
|
+
var _w=window;
|
|
7064
7408
|
ws.onmessage=function(e){
|
|
7065
7409
|
try{
|
|
7066
7410
|
var m=JSON.parse(e.data);
|
|
7067
|
-
if(m.type==='
|
|
7068
|
-
|
|
7069
|
-
|
|
7070
|
-
|
|
7071
|
-
|
|
7072
|
-
|
|
7073
|
-
|
|
7074
|
-
|
|
7075
|
-
|
|
7076
|
-
|
|
7077
|
-
|
|
7411
|
+
if(m.type==='update'&&m.url&&m.code){
|
|
7412
|
+
var blob=new Blob([m.code],{type:'application/javascript'});
|
|
7413
|
+
var blobUrl=URL.createObjectURL(blob);
|
|
7414
|
+
import(blobUrl).then(function(mod){
|
|
7415
|
+
if(_w.__wfw) _w.__wfw._update(m.url,mod);
|
|
7416
|
+
// Re-import page module so it re-evaluates its __wfw.h() imports
|
|
7417
|
+
var pageUrl=_w.__WFW_PAGE_URL;
|
|
7418
|
+
if(pageUrl&&_w.__WFW_REFRESH){
|
|
7419
|
+
import(pageUrl.split('?')[0]+'?t='+Date.now()).then(function(pageMod){
|
|
7420
|
+
if(pageMod.default) _w.__WFW_REFRESH(pageMod.default);
|
|
7421
|
+
if(m.css){
|
|
7422
|
+
var s=document.querySelector('style[data-lr]')||function(){
|
|
7423
|
+
var x=document.createElement('style');
|
|
7424
|
+
x.setAttribute('data-lr','');
|
|
7425
|
+
document.head.appendChild(x);
|
|
7426
|
+
return x
|
|
7427
|
+
}();
|
|
7428
|
+
s.textContent=m.css
|
|
7429
|
+
}
|
|
7430
|
+
});
|
|
7431
|
+
}else{location.reload()}
|
|
7432
|
+
}).catch(function(){location.reload()});
|
|
7078
7433
|
return
|
|
7079
7434
|
}
|
|
7080
7435
|
if(m.type==='css'){
|
|
@@ -7125,12 +7480,12 @@ var ssrEntries = /* @__PURE__ */ new Map();
|
|
|
7125
7480
|
|
|
7126
7481
|
// tailwind.ts
|
|
7127
7482
|
import { createHash as createHash2 } from "node:crypto";
|
|
7128
|
-
import { existsSync as
|
|
7129
|
-
import { join as join3, relative, resolve as
|
|
7483
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync } from "node:fs";
|
|
7484
|
+
import { join as join3, relative, resolve as resolve5 } from "node:path";
|
|
7130
7485
|
var extraSources = /* @__PURE__ */ new Set();
|
|
7131
7486
|
var cssCache = /* @__PURE__ */ new Map();
|
|
7132
7487
|
function tailwindContext(dir) {
|
|
7133
|
-
const cssDir =
|
|
7488
|
+
const cssDir = resolve5(dir);
|
|
7134
7489
|
const cssPath = join3(cssDir, "app", "globals.css");
|
|
7135
7490
|
return async (req, ctx, next) => {
|
|
7136
7491
|
if (!cssCache.has(cssPath)) {
|
|
@@ -7144,10 +7499,10 @@ function tailwindContext(dir) {
|
|
|
7144
7499
|
};
|
|
7145
7500
|
}
|
|
7146
7501
|
function tailwindRouter(dir) {
|
|
7147
|
-
const cssDir =
|
|
7502
|
+
const cssDir = resolve5(dir);
|
|
7148
7503
|
const cssPath = join3(cssDir, "app", "globals.css");
|
|
7149
7504
|
const r = new Router();
|
|
7150
|
-
r.get("/__wfw/style/:hash.css", async (
|
|
7505
|
+
r.get("/__wfw/style/:hash.css", async (_req, _ctx2) => {
|
|
7151
7506
|
if (!cssCache.has(cssPath)) {
|
|
7152
7507
|
await compileTailwindCss(cssPath, cssDir);
|
|
7153
7508
|
}
|
|
@@ -7161,13 +7516,13 @@ function tailwindRouter(dir) {
|
|
|
7161
7516
|
}
|
|
7162
7517
|
async function compileTailwindCss(cssPath, cssDir) {
|
|
7163
7518
|
try {
|
|
7164
|
-
if (!
|
|
7519
|
+
if (!existsSync3(cssPath)) {
|
|
7165
7520
|
mkdirSync2(cssDir, { recursive: true });
|
|
7166
7521
|
writeFileSync(cssPath, '@import "tailwindcss"\n', "utf-8");
|
|
7167
7522
|
}
|
|
7168
7523
|
const { default: tailwindPlugin } = await import("@tailwindcss/postcss");
|
|
7169
7524
|
const { default: postcss } = await import("postcss");
|
|
7170
|
-
let src =
|
|
7525
|
+
let src = readFileSync4(cssPath, "utf-8");
|
|
7171
7526
|
src = `@source "./";
|
|
7172
7527
|
${src}`;
|
|
7173
7528
|
for (const srcDir of extraSources) {
|
|
@@ -7187,22 +7542,151 @@ ${src}`;
|
|
|
7187
7542
|
|
|
7188
7543
|
// live.ts
|
|
7189
7544
|
import chokidar from "chokidar";
|
|
7190
|
-
import { existsSync as
|
|
7191
|
-
import {
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
|
|
7195
|
-
|
|
7196
|
-
|
|
7197
|
-
|
|
7198
|
-
|
|
7199
|
-
|
|
7200
|
-
|
|
7201
|
-
|
|
7202
|
-
|
|
7545
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
7546
|
+
import { join as join4, resolve as resolve7 } from "node:path";
|
|
7547
|
+
|
|
7548
|
+
// module-server.ts
|
|
7549
|
+
import * as esbuild3 from "esbuild";
|
|
7550
|
+
import { existsSync as existsSync4, readFileSync as readFileSync5 } from "node:fs";
|
|
7551
|
+
import { resolve as resolve6, dirname as dirname3, relative as relative2 } from "node:path";
|
|
7552
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
7553
|
+
var moduleCache = /* @__PURE__ */ new Map();
|
|
7554
|
+
var hashCache = /* @__PURE__ */ new Map();
|
|
7555
|
+
function clearModuleCache(filePath) {
|
|
7556
|
+
if (filePath) {
|
|
7557
|
+
const abs = resolve6(filePath);
|
|
7558
|
+
for (const key of moduleCache.keys()) {
|
|
7559
|
+
if (key.endsWith(abs)) moduleCache.delete(key);
|
|
7560
|
+
}
|
|
7561
|
+
hashCache.delete(abs);
|
|
7562
|
+
} else {
|
|
7563
|
+
moduleCache.clear();
|
|
7564
|
+
hashCache.clear();
|
|
7203
7565
|
}
|
|
7204
|
-
hotBundleCache.set(hash, code);
|
|
7205
7566
|
}
|
|
7567
|
+
var _importRoots = [];
|
|
7568
|
+
function _setImportRoots(roots) {
|
|
7569
|
+
_importRoots = roots;
|
|
7570
|
+
}
|
|
7571
|
+
function fileHash(absPath) {
|
|
7572
|
+
const cached = hashCache.get(absPath);
|
|
7573
|
+
if (cached) return cached;
|
|
7574
|
+
try {
|
|
7575
|
+
const content = readFileSync5(absPath);
|
|
7576
|
+
const h = createHash3("md5").update(content).digest("hex").slice(0, 8);
|
|
7577
|
+
hashCache.set(absPath, h);
|
|
7578
|
+
return h;
|
|
7579
|
+
} catch {
|
|
7580
|
+
return "00000000";
|
|
7581
|
+
}
|
|
7582
|
+
}
|
|
7583
|
+
function rewriteImports(code, absPath, mountPath) {
|
|
7584
|
+
const prefix = mountPath ? `${mountPath}/__wfw/m` : "/__wfw/m";
|
|
7585
|
+
let varCounter = 0;
|
|
7586
|
+
return code.replace(
|
|
7587
|
+
/^(import|export)\s+(.+?)\s+from\s+['"]([^'"]+)['"];?\s*$/gm,
|
|
7588
|
+
(_match, keyword, clause, modPath) => {
|
|
7589
|
+
if (!modPath.startsWith(".")) return _match;
|
|
7590
|
+
const isReexport = keyword === "export";
|
|
7591
|
+
const imports = clause.replace(/^type\s+/, "");
|
|
7592
|
+
const resolved = resolve6(dirname3(absPath), modPath);
|
|
7593
|
+
for (const root of _importRoots) {
|
|
7594
|
+
const rel = relative2(root, resolved);
|
|
7595
|
+
if (!rel.startsWith("..") && !rel.startsWith("/")) {
|
|
7596
|
+
const v = fileHash(resolved);
|
|
7597
|
+
const url = `${prefix}/${rel}?v=${v}`;
|
|
7598
|
+
const defaultMatch = imports.match(/^\s*(\w[\w$]*)\s*$/);
|
|
7599
|
+
const namedMatch = imports.match(/^\s*\{\s*([\w$,\s]+)\s*\}\s*$/);
|
|
7600
|
+
const mixedMatch = imports.match(/^\s*(\w[\w$]*)\s*,\s*\{\s*([\w$,\s]+)\s*\}\s*$/);
|
|
7601
|
+
if (defaultMatch) {
|
|
7602
|
+
const name = defaultMatch[1];
|
|
7603
|
+
if (isReexport) {
|
|
7604
|
+
return `const { default: ${name} } = await __wfw.h("${url}");
|
|
7605
|
+
export { ${name} as default }`;
|
|
7606
|
+
}
|
|
7607
|
+
return `const { default: ${name} } = await __wfw.h("${url}");`;
|
|
7608
|
+
}
|
|
7609
|
+
if (namedMatch) {
|
|
7610
|
+
const names = namedMatch[1].split(",").map((s) => s.trim()).filter(Boolean);
|
|
7611
|
+
if (isReexport) {
|
|
7612
|
+
const tmp = `__wfw$${varCounter++}`;
|
|
7613
|
+
const lines = [`const ${tmp} = await __wfw.h("${url}");`];
|
|
7614
|
+
for (const n of names) lines.push(`export const ${n} = ${tmp}.${n};`);
|
|
7615
|
+
return lines.join("\n");
|
|
7616
|
+
}
|
|
7617
|
+
const decl = names.map((n) => `${n}`).join(", ");
|
|
7618
|
+
return `const { ${decl} } = await __wfw.h("${url}");`;
|
|
7619
|
+
}
|
|
7620
|
+
if (mixedMatch) {
|
|
7621
|
+
const defaultName = mixedMatch[1];
|
|
7622
|
+
const namedNames = mixedMatch[2].split(",").map((s) => s.trim()).filter(Boolean);
|
|
7623
|
+
const varName = `__wfw$${varCounter++}`;
|
|
7624
|
+
const lines = [
|
|
7625
|
+
`const ${varName} = await __wfw.h("${url}");`,
|
|
7626
|
+
`const ${defaultName} = ${varName}.default;`
|
|
7627
|
+
];
|
|
7628
|
+
for (const n of namedNames) lines.push(`const { ${n} } = ${varName};`);
|
|
7629
|
+
return lines.join("\n");
|
|
7630
|
+
}
|
|
7631
|
+
return _match;
|
|
7632
|
+
}
|
|
7633
|
+
}
|
|
7634
|
+
return _match;
|
|
7635
|
+
}
|
|
7636
|
+
);
|
|
7637
|
+
}
|
|
7638
|
+
async function transformModule(absPath, root, mountPath) {
|
|
7639
|
+
const mp = mountPath || "";
|
|
7640
|
+
const cacheKey = mp + absPath;
|
|
7641
|
+
const cached = moduleCache.get(cacheKey);
|
|
7642
|
+
if (cached) return { url: `${mp}/__wfw/m/${relative2(root, absPath)}`, code: cached };
|
|
7643
|
+
const source = readFileSync5(absPath, "utf-8");
|
|
7644
|
+
const isTsx = absPath.endsWith(".tsx");
|
|
7645
|
+
const result = await esbuild3.transform(source, {
|
|
7646
|
+
loader: isTsx ? "tsx" : "ts",
|
|
7647
|
+
jsx: isTsx ? "automatic" : void 0,
|
|
7648
|
+
jsxImportSource: isTsx ? "react" : void 0,
|
|
7649
|
+
sourcemap: false
|
|
7650
|
+
});
|
|
7651
|
+
let code = result.code;
|
|
7652
|
+
code = rewriteImports(code, absPath, mp);
|
|
7653
|
+
moduleCache.set(cacheKey, code);
|
|
7654
|
+
const url = `${mp}/__wfw/m/${relative2(root, absPath)}`;
|
|
7655
|
+
return { url, code };
|
|
7656
|
+
}
|
|
7657
|
+
function moduleServer(opts) {
|
|
7658
|
+
const roots = Array.isArray(opts.root) ? opts.root : [opts.root];
|
|
7659
|
+
_setImportRoots(roots);
|
|
7660
|
+
const router = new Router();
|
|
7661
|
+
router.get("/__wfw/m/*", (async (req, ctx) => {
|
|
7662
|
+
const reqUrl = new URL(req.url);
|
|
7663
|
+
const filePath = (ctx.params["*"] || "").split("?")[0];
|
|
7664
|
+
const ext = filePath.split(".").pop();
|
|
7665
|
+
if (ext !== "tsx" && ext !== "ts") {
|
|
7666
|
+
return new Response("Not Found", { status: 404 });
|
|
7667
|
+
}
|
|
7668
|
+
const mountPath = ctx.mountPath || "";
|
|
7669
|
+
for (const root of roots) {
|
|
7670
|
+
const absPath = resolve6(root, filePath);
|
|
7671
|
+
if (existsSync4(absPath)) {
|
|
7672
|
+
try {
|
|
7673
|
+
const { code } = await transformModule(absPath, root, mountPath);
|
|
7674
|
+
return new Response(code, {
|
|
7675
|
+
headers: { "content-type": "application/javascript; charset=utf-8" }
|
|
7676
|
+
});
|
|
7677
|
+
} catch (err) {
|
|
7678
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
7679
|
+
return new Response(`/* Error: ${msg} */`, { status: 500 });
|
|
7680
|
+
}
|
|
7681
|
+
}
|
|
7682
|
+
}
|
|
7683
|
+
return new Response("Not Found", { status: 404 });
|
|
7684
|
+
}));
|
|
7685
|
+
return router;
|
|
7686
|
+
}
|
|
7687
|
+
|
|
7688
|
+
// live.ts
|
|
7689
|
+
var clients = /* @__PURE__ */ new Set();
|
|
7206
7690
|
function broadcastReload() {
|
|
7207
7691
|
for (const ws of clients) {
|
|
7208
7692
|
try {
|
|
@@ -7224,89 +7708,63 @@ function broadcastCss(css) {
|
|
|
7224
7708
|
}
|
|
7225
7709
|
function liveWs() {
|
|
7226
7710
|
return {
|
|
7227
|
-
open(ws) {
|
|
7711
|
+
open(ws, _ctx2) {
|
|
7228
7712
|
clients.add(ws);
|
|
7229
7713
|
ws.on("close", () => clients.delete(ws));
|
|
7230
7714
|
ws.on("error", () => clients.delete(ws));
|
|
7231
7715
|
}
|
|
7232
7716
|
};
|
|
7233
7717
|
}
|
|
7234
|
-
function liveRouter(
|
|
7718
|
+
function liveRouter(_dir) {
|
|
7235
7719
|
const r = new Router();
|
|
7236
7720
|
compileVendorBundle().catch(() => {
|
|
7237
7721
|
});
|
|
7238
|
-
r.get("/__wfw/h/:hash", async (req, ctx) => {
|
|
7239
|
-
const hash = ctx.params.hash.replace(/\.js$/i, "");
|
|
7240
|
-
const code = hotBundleCache.get(hash);
|
|
7241
|
-
if (!code) return new Response("", { status: 404 });
|
|
7242
|
-
return new Response(code, {
|
|
7243
|
-
headers: { "content-type": "application/javascript; charset=utf-8" }
|
|
7244
|
-
});
|
|
7245
|
-
});
|
|
7246
7722
|
return r;
|
|
7247
7723
|
}
|
|
7248
7724
|
function liveWatcher(dir) {
|
|
7249
|
-
const resolved =
|
|
7250
|
-
const entryPath = join4(resolved, "page.tsx");
|
|
7725
|
+
const resolved = resolve7(dir);
|
|
7251
7726
|
const watcher = chokidar.watch(dir, {
|
|
7252
7727
|
ignored: /(^|[/\\])\.|node_modules|[/\\]\.weifuwu[/\\]/,
|
|
7253
7728
|
ignoreInitial: true
|
|
7254
7729
|
});
|
|
7255
|
-
function findEntries(changedPath) {
|
|
7256
|
-
const matched = [];
|
|
7257
|
-
for (const [, entry] of ssrEntries) {
|
|
7258
|
-
if (!entry.path.startsWith(resolved)) continue;
|
|
7259
|
-
if (entry.path === changedPath) {
|
|
7260
|
-
matched.push(entry.path);
|
|
7261
|
-
} else {
|
|
7262
|
-
const ed = dirname2(entry.path);
|
|
7263
|
-
if (changedPath.startsWith(ed)) matched.push(entry.path);
|
|
7264
|
-
}
|
|
7265
|
-
}
|
|
7266
|
-
if (matched.length === 0) {
|
|
7267
|
-
for (const [, entry] of ssrEntries) {
|
|
7268
|
-
if (entry.path.startsWith(resolved)) matched.push(entry.path);
|
|
7269
|
-
}
|
|
7270
|
-
}
|
|
7271
|
-
return matched;
|
|
7272
|
-
}
|
|
7273
7730
|
watcher.on("change", async (filePath) => {
|
|
7274
7731
|
if (/\.tsx?$/i.test(filePath)) {
|
|
7275
7732
|
if (filePath.endsWith("layout.tsx")) {
|
|
7276
7733
|
return broadcastReload();
|
|
7277
7734
|
}
|
|
7278
7735
|
clearCompileCache();
|
|
7279
|
-
|
|
7280
|
-
if (targets.length === 0) return broadcastReload();
|
|
7736
|
+
clearModuleCache();
|
|
7281
7737
|
try {
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
7286
|
-
|
|
7287
|
-
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
|
|
7293
|
-
|
|
7294
|
-
|
|
7295
|
-
|
|
7296
|
-
|
|
7297
|
-
|
|
7298
|
-
|
|
7299
|
-
|
|
7300
|
-
|
|
7738
|
+
await compileTsxDev(filePath);
|
|
7739
|
+
} catch (e) {
|
|
7740
|
+
console.error("server-side recompile failed:", e);
|
|
7741
|
+
return broadcastReload();
|
|
7742
|
+
}
|
|
7743
|
+
let css;
|
|
7744
|
+
const cssPath = join4(resolved, "app", "globals.css");
|
|
7745
|
+
if (existsSync5(cssPath)) {
|
|
7746
|
+
css = await compileTailwindCss(cssPath, resolved);
|
|
7747
|
+
}
|
|
7748
|
+
try {
|
|
7749
|
+
const absPath = resolve7(filePath);
|
|
7750
|
+
const { url, code } = await transformModule(absPath, resolved);
|
|
7751
|
+
const msg = { type: "update", url, code };
|
|
7752
|
+
if (css) msg.css = css;
|
|
7753
|
+
const str = JSON.stringify(msg);
|
|
7754
|
+
for (const ws of clients) {
|
|
7755
|
+
try {
|
|
7756
|
+
ws.send(str);
|
|
7757
|
+
} catch {
|
|
7758
|
+
clients.delete(ws);
|
|
7301
7759
|
}
|
|
7302
7760
|
}
|
|
7303
7761
|
} catch (e) {
|
|
7304
|
-
console.error("
|
|
7762
|
+
console.error("module transform failed for HMR:", e);
|
|
7305
7763
|
broadcastReload();
|
|
7306
7764
|
}
|
|
7307
7765
|
} else if (/\.css$/i.test(filePath)) {
|
|
7308
7766
|
const cssPath = join4(resolved, "app", "globals.css");
|
|
7309
|
-
if (
|
|
7767
|
+
if (existsSync5(cssPath)) {
|
|
7310
7768
|
const css = await compileTailwindCss(cssPath, resolved);
|
|
7311
7769
|
if (css) broadcastCss(css);
|
|
7312
7770
|
}
|
|
@@ -7394,7 +7852,7 @@ var isDev2 = isDev();
|
|
|
7394
7852
|
var als2 = new AsyncLocalStorage2();
|
|
7395
7853
|
__registerAls(() => als2.getStore());
|
|
7396
7854
|
function hashId(s) {
|
|
7397
|
-
return
|
|
7855
|
+
return createHash4("md5").update(s).digest("hex").slice(0, 8);
|
|
7398
7856
|
}
|
|
7399
7857
|
function serializeLoaderData(ctx) {
|
|
7400
7858
|
const ld = ctx.loaderData;
|
|
@@ -7469,7 +7927,7 @@ async function resolveRoute(ssrDir, segments, routeCache) {
|
|
|
7469
7927
|
return null;
|
|
7470
7928
|
}
|
|
7471
7929
|
const pageFile = join5(dir, "page.tsx");
|
|
7472
|
-
if (!
|
|
7930
|
+
if (!existsSync6(pageFile)) {
|
|
7473
7931
|
routeCache.set(cacheKey, null);
|
|
7474
7932
|
return null;
|
|
7475
7933
|
}
|
|
@@ -7480,35 +7938,40 @@ async function resolveRoute(ssrDir, segments, routeCache) {
|
|
|
7480
7938
|
let d = dir;
|
|
7481
7939
|
while (d.startsWith(appDir)) {
|
|
7482
7940
|
const lf = join5(d, "layout.tsx");
|
|
7483
|
-
if (
|
|
7941
|
+
if (existsSync6(lf)) layoutFiles.unshift(lf);
|
|
7484
7942
|
if (d === appDir) break;
|
|
7485
|
-
d =
|
|
7943
|
+
d = dirname4(d);
|
|
7486
7944
|
}
|
|
7487
7945
|
const errorFiles = [];
|
|
7488
7946
|
d = dir;
|
|
7489
7947
|
while (d.startsWith(appDir)) {
|
|
7490
7948
|
const ef = join5(d, "error.tsx");
|
|
7491
|
-
if (
|
|
7949
|
+
if (existsSync6(ef)) errorFiles.unshift(ef);
|
|
7492
7950
|
if (d === appDir) break;
|
|
7493
|
-
d =
|
|
7951
|
+
d = dirname4(d);
|
|
7494
7952
|
}
|
|
7495
7953
|
let notFoundFile = null;
|
|
7496
7954
|
d = dir;
|
|
7497
7955
|
while (d.startsWith(appDir)) {
|
|
7498
7956
|
const nf = join5(d, "not-found.tsx");
|
|
7499
|
-
if (
|
|
7957
|
+
if (existsSync6(nf)) {
|
|
7500
7958
|
notFoundFile = nf;
|
|
7501
7959
|
break;
|
|
7502
7960
|
}
|
|
7503
7961
|
if (d === appDir) break;
|
|
7504
|
-
d =
|
|
7505
|
-
}
|
|
7506
|
-
const result = {
|
|
7962
|
+
d = dirname4(d);
|
|
7963
|
+
}
|
|
7964
|
+
const result = {
|
|
7965
|
+
routePath: "/" + routeParams.join("/"),
|
|
7966
|
+
pageFile,
|
|
7967
|
+
layoutFiles,
|
|
7968
|
+
errorFiles,
|
|
7969
|
+
notFoundFile
|
|
7970
|
+
};
|
|
7507
7971
|
routeCache.set(cacheKey, result);
|
|
7508
7972
|
return result;
|
|
7509
7973
|
}
|
|
7510
|
-
function buildHydrationScript(
|
|
7511
|
-
const ssrPrefix = `${base}/__ssr`;
|
|
7974
|
+
function buildHydrationScript(pageUrl, ctxJson) {
|
|
7512
7975
|
return `
|
|
7513
7976
|
<script type="module">
|
|
7514
7977
|
import { setCtx, TsxContext } from 'weifuwu/react';
|
|
@@ -7521,10 +7984,11 @@ setCtx(_ctx);
|
|
|
7521
7984
|
const _root = document.getElementById('__weifuwu_root');
|
|
7522
7985
|
|
|
7523
7986
|
async function init() {
|
|
7524
|
-
const { default: Page } = await import('${
|
|
7525
|
-
const app = createElement(TsxContext.Provider, { value: _ctx },
|
|
7526
|
-
createElement(Page));
|
|
7987
|
+
const { default: Page } = await import('${pageUrl}');
|
|
7527
7988
|
${isDev2 ? `
|
|
7989
|
+
// Store page URL for __wfw runtime
|
|
7990
|
+
window.__WFW_PAGE_URL = '${pageUrl}';
|
|
7991
|
+
|
|
7528
7992
|
// Stable proxy \u2014 same function ref = React preserves fiber + useState state across HMR
|
|
7529
7993
|
const _pageImpl = { current: Page };
|
|
7530
7994
|
const _pageProxy = new Proxy(function __wfw_page(){}, {
|
|
@@ -7541,14 +8005,22 @@ async function init() {
|
|
|
7541
8005
|
}
|
|
7542
8006
|
renderPage();
|
|
7543
8007
|
|
|
8008
|
+
// HMR: re-render page (sub-modules resolved via __wfw.h() pick up changes)
|
|
8009
|
+
window.__WFW_RERENDER = () => {
|
|
8010
|
+
_tick++;
|
|
8011
|
+
reactRoot.render(createElement(TsxContext.Provider, { value: _ctx },
|
|
8012
|
+
createElement(_pageProxy, { __t: _tick })));
|
|
8013
|
+
};
|
|
8014
|
+
|
|
8015
|
+
// Fallback: swap entire page component
|
|
7544
8016
|
window.__WFW_REFRESH = async (NewComponent) => {
|
|
7545
8017
|
const store = globalThis.__WEIFUWU_CTX_STORE?._ctx || _ctx;
|
|
7546
8018
|
_pageImpl.current = NewComponent;
|
|
7547
|
-
|
|
7548
|
-
reactRoot.render(createElement(TsxContext.Provider, { value: store },
|
|
7549
|
-
createElement(_pageProxy, { __t: _tick })));
|
|
8019
|
+
__WFW_RERENDER();
|
|
7550
8020
|
};
|
|
7551
8021
|
` : `
|
|
8022
|
+
const app = createElement(TsxContext.Provider, { value: _ctx },
|
|
8023
|
+
createElement(Page));
|
|
7552
8024
|
hydrateRoot(_root, app);
|
|
7553
8025
|
`}
|
|
7554
8026
|
}
|
|
@@ -7556,11 +8028,10 @@ async function init() {
|
|
|
7556
8028
|
init();
|
|
7557
8029
|
</script>`;
|
|
7558
8030
|
}
|
|
7559
|
-
function renderPage(pageFile,
|
|
7560
|
-
const absPath =
|
|
8031
|
+
function renderPage(pageFile, projectDir) {
|
|
8032
|
+
const absPath = resolve8(pageFile);
|
|
7561
8033
|
const entryId = hashId(absPath);
|
|
7562
8034
|
ssrEntries.set(entryId, { path: absPath });
|
|
7563
|
-
const bundleKey = `/__ssr/${entryId}.js`;
|
|
7564
8035
|
return async (req, ctx) => {
|
|
7565
8036
|
let pageMod;
|
|
7566
8037
|
try {
|
|
@@ -7574,7 +8045,6 @@ function renderPage(pageFile, outDir) {
|
|
|
7574
8045
|
if (!Component) return errorPage("Missing default export", pageFile);
|
|
7575
8046
|
const layouts = ctx.layoutStack || [];
|
|
7576
8047
|
const layoutComponents = layouts.map((l) => l.component);
|
|
7577
|
-
const layoutPaths = layouts.map((l) => l.path);
|
|
7578
8048
|
const base = (ctx.mountPath || "").replace(/\/$/, "");
|
|
7579
8049
|
const loaderData = serializeLoaderData(ctx);
|
|
7580
8050
|
const ctxValue = {
|
|
@@ -7588,28 +8058,29 @@ function renderPage(pageFile, outDir) {
|
|
|
7588
8058
|
loaderData,
|
|
7589
8059
|
env: ctx.env ?? {}
|
|
7590
8060
|
};
|
|
8061
|
+
const pageRelative = relative3(projectDir, absPath);
|
|
8062
|
+
const pageUrl = `${base}/__wfw/m/${pageRelative}`;
|
|
7591
8063
|
return als2.run(ctxValue, async () => {
|
|
7592
8064
|
setCtx(ctxValue);
|
|
7593
|
-
await compileBrowser(absPath, outDir);
|
|
7594
8065
|
let element = createElement3(
|
|
7595
8066
|
"div",
|
|
7596
8067
|
{ id: "__weifuwu_root" },
|
|
7597
|
-
createElement3(
|
|
7598
|
-
TsxContext.Provider,
|
|
7599
|
-
{ value: ctxValue },
|
|
7600
|
-
createElement3(Component, null)
|
|
7601
|
-
)
|
|
8068
|
+
createElement3(TsxContext.Provider, { value: ctxValue }, createElement3(Component, null))
|
|
7602
8069
|
);
|
|
7603
8070
|
element = buildHtmlShell("weifuwu", element, layoutComponents);
|
|
7604
8071
|
const { renderToReadableStream } = await import("react-dom/server");
|
|
7605
8072
|
const stream = await renderToReadableStream(element);
|
|
7606
|
-
return streamResponse(
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
|
|
7610
|
-
|
|
7611
|
-
|
|
7612
|
-
|
|
8073
|
+
return streamResponse(
|
|
8074
|
+
stream,
|
|
8075
|
+
{
|
|
8076
|
+
ctx,
|
|
8077
|
+
base,
|
|
8078
|
+
isDev: isDev2,
|
|
8079
|
+
loaderData,
|
|
8080
|
+
tailwind: ctx.tailwind
|
|
8081
|
+
},
|
|
8082
|
+
buildHydrationScript(pageUrl, JSON.stringify(ctxValue))
|
|
8083
|
+
);
|
|
7613
8084
|
});
|
|
7614
8085
|
};
|
|
7615
8086
|
}
|
|
@@ -7623,7 +8094,7 @@ function runChain(mws, handler, req, ctx) {
|
|
|
7623
8094
|
}
|
|
7624
8095
|
function discoverRoutes(dir) {
|
|
7625
8096
|
const appDir = join5(dir, "app");
|
|
7626
|
-
if (!
|
|
8097
|
+
if (!existsSync6(appDir)) return [];
|
|
7627
8098
|
const result = [];
|
|
7628
8099
|
function walk(currentDir, routePath) {
|
|
7629
8100
|
let entries;
|
|
@@ -7644,7 +8115,7 @@ function discoverRoutes(dir) {
|
|
|
7644
8115
|
} else if (entry.name === "page.tsx") {
|
|
7645
8116
|
result.push({
|
|
7646
8117
|
path: routePath || "/",
|
|
7647
|
-
file:
|
|
8118
|
+
file: relative3(appDir, join5(currentDir, entry.name))
|
|
7648
8119
|
});
|
|
7649
8120
|
}
|
|
7650
8121
|
}
|
|
@@ -7654,28 +8125,19 @@ function discoverRoutes(dir) {
|
|
|
7654
8125
|
}
|
|
7655
8126
|
function ssr(opts) {
|
|
7656
8127
|
const r = new Router();
|
|
7657
|
-
const dir =
|
|
7658
|
-
const outDir = resolve6(OUT_DIR);
|
|
8128
|
+
const dir = resolve8(opts.dir);
|
|
7659
8129
|
const routeCache = /* @__PURE__ */ new Map();
|
|
8130
|
+
const wfwRoot = resolve8(import.meta.dirname ?? __dirname);
|
|
8131
|
+
r.use("/", moduleServer({ root: [dir, wfwRoot] }));
|
|
7660
8132
|
compileVendorBundle().catch(() => {
|
|
7661
8133
|
});
|
|
7662
|
-
r.get("/__ssr/:file", (req, ctx) => {
|
|
7663
|
-
const filePath = join5(outDir, ctx.params.file);
|
|
7664
|
-
if (!filePath.startsWith(outDir) || !existsSync4(filePath)) {
|
|
7665
|
-
return new Response("Not Found", { status: 404 });
|
|
7666
|
-
}
|
|
7667
|
-
const content = readFileSync4(filePath, "utf-8");
|
|
7668
|
-
return new Response(content, {
|
|
7669
|
-
headers: { "content-type": "application/javascript; charset=utf-8" }
|
|
7670
|
-
});
|
|
7671
|
-
});
|
|
7672
8134
|
r.get("/__wfw/v/bundle", async () => {
|
|
7673
8135
|
const code = await compileVendorBundle();
|
|
7674
8136
|
return new Response(code, {
|
|
7675
8137
|
headers: { "content-type": "application/javascript; charset=utf-8" }
|
|
7676
8138
|
});
|
|
7677
8139
|
});
|
|
7678
|
-
if (
|
|
8140
|
+
if (existsSync6(join5(dir, "app", "globals.css"))) {
|
|
7679
8141
|
r.use("/", tailwindRouter(dir));
|
|
7680
8142
|
}
|
|
7681
8143
|
let devWatcher;
|
|
@@ -7693,13 +8155,16 @@ function ssr(opts) {
|
|
|
7693
8155
|
if (!resolved) {
|
|
7694
8156
|
if (isDev2) {
|
|
7695
8157
|
const pages = discoverRoutes(dir).map((p) => p.path).sort();
|
|
7696
|
-
return Response.json(
|
|
7697
|
-
|
|
7698
|
-
|
|
7699
|
-
|
|
7700
|
-
|
|
7701
|
-
|
|
7702
|
-
|
|
8158
|
+
return Response.json(
|
|
8159
|
+
{
|
|
8160
|
+
error: "Not Found",
|
|
8161
|
+
path: "/" + segments.join("/"),
|
|
8162
|
+
method: req.method,
|
|
8163
|
+
hint: "Available SSR pages",
|
|
8164
|
+
pages
|
|
8165
|
+
},
|
|
8166
|
+
{ status: 404 }
|
|
8167
|
+
);
|
|
7703
8168
|
}
|
|
7704
8169
|
return new Response("Not Found", { status: 404 });
|
|
7705
8170
|
}
|
|
@@ -7708,7 +8173,7 @@ function ssr(opts) {
|
|
|
7708
8173
|
...resolved.layoutFiles.map((f) => layout(f)),
|
|
7709
8174
|
tailwindContext(dir)
|
|
7710
8175
|
];
|
|
7711
|
-
const handler = (req2, ctx2) => renderPage(resolved.pageFile,
|
|
8176
|
+
const handler = (req2, ctx2) => renderPage(resolved.pageFile, dir)(req2, ctx2);
|
|
7712
8177
|
return runChain(mws, handler, req, ctx);
|
|
7713
8178
|
});
|
|
7714
8179
|
const mod = r;
|
|
@@ -7765,7 +8230,11 @@ async function getSession(sql2, id2) {
|
|
|
7765
8230
|
async function listSessions(sql2, userId2) {
|
|
7766
8231
|
const opts = { orderBy: { updated_at: "desc" } };
|
|
7767
8232
|
if (userId2 !== void 0) {
|
|
7768
|
-
const { data: rows2 } = await sessions.readMany(
|
|
8233
|
+
const { data: rows2 } = await sessions.readMany(
|
|
8234
|
+
sql2,
|
|
8235
|
+
{ user_id: userId2, active: true },
|
|
8236
|
+
opts
|
|
8237
|
+
);
|
|
7769
8238
|
return rows2;
|
|
7770
8239
|
}
|
|
7771
8240
|
const { data: rows } = await sessions.readMany(sql2, { active: true }, opts);
|
|
@@ -7844,7 +8313,14 @@ async function* executeGenerator(opts) {
|
|
|
7844
8313
|
totalTokens: result2.usage?.totalTokens ?? 0
|
|
7845
8314
|
};
|
|
7846
8315
|
try {
|
|
7847
|
-
await addTextMessage(
|
|
8316
|
+
await addTextMessage(
|
|
8317
|
+
sql2,
|
|
8318
|
+
sessionId,
|
|
8319
|
+
"assistant",
|
|
8320
|
+
currentAssistantText,
|
|
8321
|
+
currentUsage.promptTokens,
|
|
8322
|
+
currentUsage.completionTokens
|
|
8323
|
+
);
|
|
7848
8324
|
} catch (e) {
|
|
7849
8325
|
console.error("[opencode] save message failed:", e);
|
|
7850
8326
|
}
|
|
@@ -7887,11 +8363,7 @@ var DENIED_COMMANDS = [
|
|
|
7887
8363
|
/^:\(\)\{.*\}:;$/,
|
|
7888
8364
|
/^fork\s+bomb/i
|
|
7889
8365
|
];
|
|
7890
|
-
var DENIED_PATHS = [
|
|
7891
|
-
/\/\.env$/,
|
|
7892
|
-
/\/\.env\.\w+$/,
|
|
7893
|
-
/\/node_modules\//
|
|
7894
|
-
];
|
|
8366
|
+
var DENIED_PATHS = [/\/\.env$/, /\/\.env\.\w+$/, /\/node_modules\//];
|
|
7895
8367
|
function isCommandAllowed(command) {
|
|
7896
8368
|
const trimmed = command.trim();
|
|
7897
8369
|
for (const re of DENIED_COMMANDS) {
|
|
@@ -7899,7 +8371,7 @@ function isCommandAllowed(command) {
|
|
|
7899
8371
|
}
|
|
7900
8372
|
return true;
|
|
7901
8373
|
}
|
|
7902
|
-
function isPathAllowed(resolvedPath, workspace,
|
|
8374
|
+
function isPathAllowed(resolvedPath, workspace, _perms) {
|
|
7903
8375
|
if (!resolvedPath.startsWith(workspace)) return false;
|
|
7904
8376
|
for (const re of DENIED_PATHS) {
|
|
7905
8377
|
if (re.test(resolvedPath)) return false;
|
|
@@ -7953,17 +8425,21 @@ function createBashTool(ctx) {
|
|
|
7953
8425
|
return { stdout: "", stderr: "Command denied: potentially dangerous command", exitCode: 1 };
|
|
7954
8426
|
}
|
|
7955
8427
|
const cwd = workdir ? `${ctx.workspace}/${workdir}` : ctx.workspace;
|
|
7956
|
-
return new Promise((
|
|
7957
|
-
const child = exec(
|
|
7958
|
-
|
|
7959
|
-
|
|
7960
|
-
|
|
7961
|
-
|
|
7962
|
-
|
|
7963
|
-
|
|
7964
|
-
|
|
7965
|
-
|
|
7966
|
-
|
|
8428
|
+
return new Promise((resolve16) => {
|
|
8429
|
+
const child = exec(
|
|
8430
|
+
command,
|
|
8431
|
+
{ cwd, timeout: timeout * 1e3, maxBuffer: 1024 * 1024 },
|
|
8432
|
+
(error, stdout, stderr) => {
|
|
8433
|
+
const truncated = stdout.length > 1e6 || stderr.length > 1e6;
|
|
8434
|
+
resolve16({
|
|
8435
|
+
stdout: stdout.slice(0, 1e6),
|
|
8436
|
+
stderr: stderr.slice(0, 1e6),
|
|
8437
|
+
exitCode: error?.code ?? 0,
|
|
8438
|
+
signal: error?.signal ?? null,
|
|
8439
|
+
truncated
|
|
8440
|
+
});
|
|
8441
|
+
}
|
|
8442
|
+
);
|
|
7967
8443
|
});
|
|
7968
8444
|
}
|
|
7969
8445
|
});
|
|
@@ -7972,8 +8448,8 @@ function createBashTool(ctx) {
|
|
|
7972
8448
|
// opencode/tools/read.ts
|
|
7973
8449
|
import { tool as tool4 } from "ai";
|
|
7974
8450
|
import { z as z6 } from "zod";
|
|
7975
|
-
import { readFileSync as
|
|
7976
|
-
import { resolve as
|
|
8451
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
8452
|
+
import { resolve as resolve9 } from "node:path";
|
|
7977
8453
|
function createReadTool(ctx) {
|
|
7978
8454
|
return tool4({
|
|
7979
8455
|
description: "Read file contents. Supports offset and limit for reading specific line ranges.",
|
|
@@ -7983,11 +8459,11 @@ function createReadTool(ctx) {
|
|
|
7983
8459
|
limit: z6.number().optional().describe("Number of lines to read")
|
|
7984
8460
|
}),
|
|
7985
8461
|
execute: async ({ path: path2, offset, limit }) => {
|
|
7986
|
-
const resolved =
|
|
8462
|
+
const resolved = resolve9(ctx.workspace, path2);
|
|
7987
8463
|
if (!isPathAllowed(resolved, ctx.workspace, ctx.permissions.permissions)) {
|
|
7988
8464
|
return { error: "Path not allowed", content: null, totalLines: 0 };
|
|
7989
8465
|
}
|
|
7990
|
-
const content =
|
|
8466
|
+
const content = readFileSync7(resolved, "utf-8");
|
|
7991
8467
|
const lines = content.split("\n");
|
|
7992
8468
|
const totalLines = lines.length;
|
|
7993
8469
|
if (offset !== void 0) {
|
|
@@ -8015,7 +8491,7 @@ function createReadTool(ctx) {
|
|
|
8015
8491
|
import { tool as tool5 } from "ai";
|
|
8016
8492
|
import { z as z7 } from "zod";
|
|
8017
8493
|
import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync3 } from "node:fs";
|
|
8018
|
-
import { resolve as
|
|
8494
|
+
import { resolve as resolve10, dirname as dirname5 } from "node:path";
|
|
8019
8495
|
function createWriteTool(ctx) {
|
|
8020
8496
|
return tool5({
|
|
8021
8497
|
description: "Create or overwrite a file. Parent directories are created automatically.",
|
|
@@ -8024,11 +8500,11 @@ function createWriteTool(ctx) {
|
|
|
8024
8500
|
content: z7.string().describe("File content")
|
|
8025
8501
|
}),
|
|
8026
8502
|
execute: async ({ path: path2, content }) => {
|
|
8027
|
-
const resolved =
|
|
8503
|
+
const resolved = resolve10(ctx.workspace, path2);
|
|
8028
8504
|
if (!isPathAllowed(resolved, ctx.workspace, ctx.permissions.permissions)) {
|
|
8029
8505
|
return { error: "Path not allowed" };
|
|
8030
8506
|
}
|
|
8031
|
-
mkdirSync3(
|
|
8507
|
+
mkdirSync3(dirname5(resolved), { recursive: true });
|
|
8032
8508
|
writeFileSync2(resolved, content, "utf-8");
|
|
8033
8509
|
return { path: path2, size: content.length };
|
|
8034
8510
|
}
|
|
@@ -8038,8 +8514,8 @@ function createWriteTool(ctx) {
|
|
|
8038
8514
|
// opencode/tools/edit.ts
|
|
8039
8515
|
import { tool as tool6 } from "ai";
|
|
8040
8516
|
import { z as z8 } from "zod";
|
|
8041
|
-
import { readFileSync as
|
|
8042
|
-
import { resolve as
|
|
8517
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync3 } from "node:fs";
|
|
8518
|
+
import { resolve as resolve11 } from "node:path";
|
|
8043
8519
|
function createEditTool(ctx) {
|
|
8044
8520
|
return tool6({
|
|
8045
8521
|
description: "Perform exact string replacements in a file. If oldString appears multiple times, provide more surrounding context.",
|
|
@@ -8050,11 +8526,11 @@ function createEditTool(ctx) {
|
|
|
8050
8526
|
replaceAll: z8.boolean().default(false).describe("Replace all occurrences")
|
|
8051
8527
|
}),
|
|
8052
8528
|
execute: async ({ path: path2, oldString, newString, replaceAll }) => {
|
|
8053
|
-
const resolved =
|
|
8529
|
+
const resolved = resolve11(ctx.workspace, path2);
|
|
8054
8530
|
if (!isPathAllowed(resolved, ctx.workspace, ctx.permissions.permissions)) {
|
|
8055
8531
|
return { error: "Path not allowed" };
|
|
8056
8532
|
}
|
|
8057
|
-
const content =
|
|
8533
|
+
const content = readFileSync8(resolved, "utf-8");
|
|
8058
8534
|
if (replaceAll) {
|
|
8059
8535
|
if (!content.includes(oldString)) {
|
|
8060
8536
|
return { error: "oldString not found in file", replaced: 0 };
|
|
@@ -8070,7 +8546,10 @@ function createEditTool(ctx) {
|
|
|
8070
8546
|
}
|
|
8071
8547
|
const secondIdx = content.indexOf(oldString, firstIdx + 1);
|
|
8072
8548
|
if (secondIdx !== -1) {
|
|
8073
|
-
return {
|
|
8549
|
+
return {
|
|
8550
|
+
error: "Found multiple matches. Provide more surrounding context in oldString.",
|
|
8551
|
+
replaced: 0
|
|
8552
|
+
};
|
|
8074
8553
|
}
|
|
8075
8554
|
const result = content.replace(oldString, newString);
|
|
8076
8555
|
writeFileSync3(resolved, result, "utf-8");
|
|
@@ -8083,8 +8562,8 @@ function createEditTool(ctx) {
|
|
|
8083
8562
|
import { tool as tool7 } from "ai";
|
|
8084
8563
|
import { z as z9 } from "zod";
|
|
8085
8564
|
import { execFileSync } from "node:child_process";
|
|
8086
|
-
import { resolve as
|
|
8087
|
-
import { existsSync as
|
|
8565
|
+
import { resolve as resolve12 } from "node:path";
|
|
8566
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
8088
8567
|
function createGrepTool(ctx) {
|
|
8089
8568
|
return tool7({
|
|
8090
8569
|
description: "Search file contents using regex. Supports file type filtering and context lines.",
|
|
@@ -8095,10 +8574,10 @@ function createGrepTool(ctx) {
|
|
|
8095
8574
|
context: z9.number().default(0).describe("Number of context lines before and after each match")
|
|
8096
8575
|
}),
|
|
8097
8576
|
execute: async ({ pattern, include, path: path2, context }) => {
|
|
8098
|
-
const searchDir = path2 ?
|
|
8577
|
+
const searchDir = path2 ? resolve12(ctx.workspace, path2) : ctx.workspace;
|
|
8099
8578
|
try {
|
|
8100
8579
|
let stdout;
|
|
8101
|
-
if (
|
|
8580
|
+
if (existsSync7("/usr/bin/rg") || existsSync7("/usr/local/bin/rg")) {
|
|
8102
8581
|
const args = ["-n"];
|
|
8103
8582
|
if (context > 0) args.push("-C", String(context));
|
|
8104
8583
|
if (include) args.push("-g", include);
|
|
@@ -8112,7 +8591,11 @@ function createGrepTool(ctx) {
|
|
|
8112
8591
|
stdout = execFileSync("grep", args, { timeout: 15e3, maxBuffer: 1024 * 1024 }).toString();
|
|
8113
8592
|
}
|
|
8114
8593
|
const lines = stdout.split("\n").filter(Boolean);
|
|
8115
|
-
return {
|
|
8594
|
+
return {
|
|
8595
|
+
matches: lines.length,
|
|
8596
|
+
results: lines.slice(0, 200),
|
|
8597
|
+
truncated: lines.length > 200
|
|
8598
|
+
};
|
|
8116
8599
|
} catch (e) {
|
|
8117
8600
|
if (e.status === 1) {
|
|
8118
8601
|
return { matches: 0, results: [], truncated: false };
|
|
@@ -8127,7 +8610,7 @@ function createGrepTool(ctx) {
|
|
|
8127
8610
|
import { tool as tool8 } from "ai";
|
|
8128
8611
|
import { z as z10 } from "zod";
|
|
8129
8612
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
8130
|
-
import { resolve as
|
|
8613
|
+
import { resolve as resolve13 } from "node:path";
|
|
8131
8614
|
function createGlobTool(ctx) {
|
|
8132
8615
|
return tool8({
|
|
8133
8616
|
description: "Find files matching a glob pattern.",
|
|
@@ -8136,21 +8619,22 @@ function createGlobTool(ctx) {
|
|
|
8136
8619
|
path: z10.string().optional().describe("Subdirectory relative to workspace")
|
|
8137
8620
|
}),
|
|
8138
8621
|
execute: async ({ pattern, path: path2 }) => {
|
|
8139
|
-
const searchDir = path2 ?
|
|
8622
|
+
const searchDir = path2 ? resolve13(ctx.workspace, path2) : ctx.workspace;
|
|
8140
8623
|
try {
|
|
8141
|
-
const stdout = execFileSync2(
|
|
8142
|
-
|
|
8143
|
-
"-name",
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
|
|
8149
|
-
timeout: 1e4,
|
|
8150
|
-
maxBuffer: 1024 * 1024
|
|
8151
|
-
}).toString();
|
|
8624
|
+
const stdout = execFileSync2(
|
|
8625
|
+
"find",
|
|
8626
|
+
[searchDir, "-name", pattern, "-not", "-path", "*/node_modules/*"],
|
|
8627
|
+
{
|
|
8628
|
+
timeout: 1e4,
|
|
8629
|
+
maxBuffer: 1024 * 1024
|
|
8630
|
+
}
|
|
8631
|
+
).toString();
|
|
8152
8632
|
const lines = stdout.split("\n").filter(Boolean).slice(0, 200);
|
|
8153
|
-
return {
|
|
8633
|
+
return {
|
|
8634
|
+
files: lines,
|
|
8635
|
+
total: lines.length,
|
|
8636
|
+
truncated: stdout.split("\n").filter(Boolean).length > 200
|
|
8637
|
+
};
|
|
8154
8638
|
} catch {
|
|
8155
8639
|
return { files: [], total: 0, truncated: false };
|
|
8156
8640
|
}
|
|
@@ -8161,7 +8645,7 @@ function createGlobTool(ctx) {
|
|
|
8161
8645
|
// opencode/tools/web.ts
|
|
8162
8646
|
import { tool as tool9 } from "ai";
|
|
8163
8647
|
import { z as z11 } from "zod";
|
|
8164
|
-
function createWebTool(
|
|
8648
|
+
function createWebTool(_ctx2) {
|
|
8165
8649
|
return tool9({
|
|
8166
8650
|
description: "Fetch a URL and return the content as text.",
|
|
8167
8651
|
inputSchema: z11.object({
|
|
@@ -8197,7 +8681,7 @@ function createQuestionTool(ctx) {
|
|
|
8197
8681
|
options: z12.array(z12.string()).optional().describe("Optional multiple choice options")
|
|
8198
8682
|
}),
|
|
8199
8683
|
execute: async ({ question, options }, { toolCallId }) => {
|
|
8200
|
-
return new Promise((
|
|
8684
|
+
return new Promise((resolve16, reject) => {
|
|
8201
8685
|
const timeout = setTimeout(() => {
|
|
8202
8686
|
ctx.pendingQuestions.delete(toolCallId);
|
|
8203
8687
|
reject(new Error("Question timed out"));
|
|
@@ -8205,7 +8689,7 @@ function createQuestionTool(ctx) {
|
|
|
8205
8689
|
ctx.pendingQuestions.set(toolCallId, {
|
|
8206
8690
|
resolve: (answer) => {
|
|
8207
8691
|
clearTimeout(timeout);
|
|
8208
|
-
|
|
8692
|
+
resolve16(answer);
|
|
8209
8693
|
},
|
|
8210
8694
|
reject: (err) => {
|
|
8211
8695
|
clearTimeout(timeout);
|
|
@@ -8290,15 +8774,29 @@ function createTools(ctx) {
|
|
|
8290
8774
|
|
|
8291
8775
|
// opencode/rest.ts
|
|
8292
8776
|
async function buildRouter4(deps) {
|
|
8293
|
-
const {
|
|
8777
|
+
const {
|
|
8778
|
+
sql: sql2,
|
|
8779
|
+
model,
|
|
8780
|
+
workspace,
|
|
8781
|
+
systemPrompt,
|
|
8782
|
+
skills,
|
|
8783
|
+
skillsRegistry,
|
|
8784
|
+
permissions: permissions2,
|
|
8785
|
+
pendingQuestions
|
|
8786
|
+
} = deps;
|
|
8294
8787
|
const router = new Router();
|
|
8295
8788
|
router.post("/sessions", async (req, ctx) => {
|
|
8296
8789
|
const body = await req.json().catch(() => ({}));
|
|
8297
|
-
const session2 = await createSession(
|
|
8298
|
-
|
|
8299
|
-
|
|
8300
|
-
|
|
8301
|
-
|
|
8790
|
+
const session2 = await createSession(
|
|
8791
|
+
sql2,
|
|
8792
|
+
{
|
|
8793
|
+
title: body.title,
|
|
8794
|
+
model: body.model,
|
|
8795
|
+
systemPrompt: body.systemPrompt || systemPrompt
|
|
8796
|
+
},
|
|
8797
|
+
workspace,
|
|
8798
|
+
ctx.mountPath || ""
|
|
8799
|
+
);
|
|
8302
8800
|
return Response.json(session2, { status: 201 });
|
|
8303
8801
|
});
|
|
8304
8802
|
router.get("/sessions", async () => {
|
|
@@ -8362,7 +8860,11 @@ async function buildRouter4(deps) {
|
|
|
8362
8860
|
FROM "_opencode_messages"
|
|
8363
8861
|
WHERE session_id = ${sessionId}
|
|
8364
8862
|
`;
|
|
8365
|
-
const stats = rows[0] || {
|
|
8863
|
+
const stats = rows[0] || {
|
|
8864
|
+
message_count: 0,
|
|
8865
|
+
total_tokens_in: 0,
|
|
8866
|
+
total_tokens_out: 0
|
|
8867
|
+
};
|
|
8366
8868
|
return Response.json({
|
|
8367
8869
|
session_id: sessionId,
|
|
8368
8870
|
message_count: stats.message_count,
|
|
@@ -8383,7 +8885,16 @@ async function buildRouter4(deps) {
|
|
|
8383
8885
|
// opencode/ws.ts
|
|
8384
8886
|
var clients2 = /* @__PURE__ */ new WeakMap();
|
|
8385
8887
|
function createWSHandler2(deps) {
|
|
8386
|
-
const {
|
|
8888
|
+
const {
|
|
8889
|
+
sql: sql2,
|
|
8890
|
+
model,
|
|
8891
|
+
workspace,
|
|
8892
|
+
systemPrompt,
|
|
8893
|
+
skills,
|
|
8894
|
+
skillsRegistry,
|
|
8895
|
+
permissions: permissions2,
|
|
8896
|
+
pendingQuestions
|
|
8897
|
+
} = deps;
|
|
8387
8898
|
return {
|
|
8388
8899
|
open(ws, ctx) {
|
|
8389
8900
|
const userId2 = ctx.user?.id ?? 0;
|
|
@@ -8403,12 +8914,17 @@ function createWSHandler2(deps) {
|
|
|
8403
8914
|
switch (msg.type) {
|
|
8404
8915
|
case "create": {
|
|
8405
8916
|
try {
|
|
8406
|
-
const session2 = await createSession(
|
|
8407
|
-
|
|
8408
|
-
|
|
8409
|
-
|
|
8410
|
-
|
|
8411
|
-
|
|
8917
|
+
const session2 = await createSession(
|
|
8918
|
+
sql2,
|
|
8919
|
+
{
|
|
8920
|
+
userId: client.userId,
|
|
8921
|
+
title: msg.title,
|
|
8922
|
+
model: msg.model,
|
|
8923
|
+
systemPrompt: msg.systemPrompt || systemPrompt
|
|
8924
|
+
},
|
|
8925
|
+
workspace,
|
|
8926
|
+
client.mountPath
|
|
8927
|
+
);
|
|
8412
8928
|
ws.send(JSON.stringify({ type: "session_created", session: session2 }));
|
|
8413
8929
|
} catch (e) {
|
|
8414
8930
|
ws.send(JSON.stringify({ type: "error", error: e.message }));
|
|
@@ -8494,7 +9010,7 @@ function createWSHandler2(deps) {
|
|
|
8494
9010
|
clients2.delete(ws);
|
|
8495
9011
|
}
|
|
8496
9012
|
},
|
|
8497
|
-
error(ws,
|
|
9013
|
+
error(ws, _ctx2, _err) {
|
|
8498
9014
|
const client = clients2.get(ws);
|
|
8499
9015
|
if (client) {
|
|
8500
9016
|
client.abortController?.abort();
|
|
@@ -8505,10 +9021,9 @@ function createWSHandler2(deps) {
|
|
|
8505
9021
|
}
|
|
8506
9022
|
|
|
8507
9023
|
// opencode/skills.ts
|
|
8508
|
-
import { readFile } from "node:fs/promises";
|
|
8509
|
-
import { glob } from "node:fs/promises";
|
|
9024
|
+
import { readFile, glob } from "node:fs/promises";
|
|
8510
9025
|
import { homedir } from "node:os";
|
|
8511
|
-
import { resolve as
|
|
9026
|
+
import { resolve as resolve14 } from "node:path";
|
|
8512
9027
|
import { parse as parseYaml } from "yaml";
|
|
8513
9028
|
var SEARCH_DIRS = [
|
|
8514
9029
|
(ws) => `${ws}/.opencode/skills`,
|
|
@@ -8546,7 +9061,7 @@ async function scanDir(dir) {
|
|
|
8546
9061
|
try {
|
|
8547
9062
|
const files = [];
|
|
8548
9063
|
for await (const entry of glob("*/SKILL.md", { cwd: dir })) {
|
|
8549
|
-
const skill = await parseSkillFile(
|
|
9064
|
+
const skill = await parseSkillFile(resolve14(dir, entry));
|
|
8550
9065
|
if (skill) files.push(skill);
|
|
8551
9066
|
}
|
|
8552
9067
|
return files;
|
|
@@ -8603,7 +9118,16 @@ async function opencode(options) {
|
|
|
8603
9118
|
const model = provider.chat(modelName);
|
|
8604
9119
|
const pendingQuestions = /* @__PURE__ */ new Map();
|
|
8605
9120
|
const base = new PgModule(pg);
|
|
8606
|
-
const r = await buildRouter4({
|
|
9121
|
+
const r = await buildRouter4({
|
|
9122
|
+
sql: sql2,
|
|
9123
|
+
model,
|
|
9124
|
+
workspace,
|
|
9125
|
+
systemPrompt,
|
|
9126
|
+
skills: manualSkills,
|
|
9127
|
+
skillsRegistry,
|
|
9128
|
+
permissions: permissions2,
|
|
9129
|
+
pendingQuestions
|
|
9130
|
+
});
|
|
8607
9131
|
const mod = r;
|
|
8608
9132
|
mod.migrate = async () => {
|
|
8609
9133
|
const sessions2 = pg.table("_opencode_sessions", {
|
|
@@ -8636,7 +9160,16 @@ async function opencode(options) {
|
|
|
8636
9160
|
await messages2.create();
|
|
8637
9161
|
await messages2.createIndex(["session_id", "created_at"]);
|
|
8638
9162
|
};
|
|
8639
|
-
mod.wsHandler = () => createWSHandler2({
|
|
9163
|
+
mod.wsHandler = () => createWSHandler2({
|
|
9164
|
+
sql: sql2,
|
|
9165
|
+
model,
|
|
9166
|
+
workspace,
|
|
9167
|
+
systemPrompt,
|
|
9168
|
+
skills: manualSkills,
|
|
9169
|
+
skillsRegistry,
|
|
9170
|
+
permissions: permissions2,
|
|
9171
|
+
pendingQuestions
|
|
9172
|
+
});
|
|
8640
9173
|
mod.close = () => base.close();
|
|
8641
9174
|
return mod;
|
|
8642
9175
|
}
|
|
@@ -8745,7 +9278,10 @@ var MemStore = class {
|
|
|
8745
9278
|
daily,
|
|
8746
9279
|
top_pages: topPages,
|
|
8747
9280
|
referrers: [...refMap.entries()].sort((a, b) => b[1] - a[1]).slice(0, 10).map(([domain, count]) => ({ domain, count })),
|
|
8748
|
-
devices: {
|
|
9281
|
+
devices: {
|
|
9282
|
+
mobile: Math.round(totalMobile / total * 1e3) / 10,
|
|
9283
|
+
desktop: Math.round(totalDesktop / total * 1e3) / 10
|
|
9284
|
+
}
|
|
8749
9285
|
};
|
|
8750
9286
|
}
|
|
8751
9287
|
};
|
|
@@ -8798,7 +9334,10 @@ async function queryPg(sql2, days) {
|
|
|
8798
9334
|
daily: daily.map((d) => ({ date: d.date, pv: d.pv, uv: d.uv })),
|
|
8799
9335
|
top_pages: pageRows.map((p) => ({ path: p.path, pv: p.pv })),
|
|
8800
9336
|
referrers: [],
|
|
8801
|
-
devices: {
|
|
9337
|
+
devices: {
|
|
9338
|
+
mobile: Math.round(t.total_mobile / denom * 1e3) / 10,
|
|
9339
|
+
desktop: Math.round(t.total_desktop / denom * 1e3) / 10
|
|
9340
|
+
}
|
|
8802
9341
|
};
|
|
8803
9342
|
}
|
|
8804
9343
|
function escapeHtml2(s) {
|
|
@@ -8813,9 +9352,7 @@ function renderDashboard(days, data) {
|
|
|
8813
9352
|
const rows = top_pages.map(
|
|
8814
9353
|
(p, i) => `<tr><td class="num">${i + 1}</td><td class="path">${escapeHtml2(p.path)}</td><td class="num">${p.pv}</td></tr>`
|
|
8815
9354
|
).join("");
|
|
8816
|
-
const refRows = referrers.map(
|
|
8817
|
-
(r) => `<tr><td>${escapeHtml2(r.domain)}</td><td class="num">${r.count}</td></tr>`
|
|
8818
|
-
).join("");
|
|
9355
|
+
const refRows = referrers.map((r) => `<tr><td>${escapeHtml2(r.domain)}</td><td class="num">${r.count}</td></tr>`).join("");
|
|
8819
9356
|
return `<!DOCTYPE html><html lang="en">
|
|
8820
9357
|
<head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>Analytics - weifuwu</title>
|
|
8821
9358
|
<style>*,:before,:after{box-sizing:border-box;margin:0;padding:0}
|
|
@@ -8951,7 +9488,7 @@ function theme(options) {
|
|
|
8951
9488
|
|
|
8952
9489
|
// i18n.ts
|
|
8953
9490
|
import { readFile as readFile2, stat as stat2 } from "node:fs/promises";
|
|
8954
|
-
import { join as join7, resolve as
|
|
9491
|
+
import { join as join7, resolve as resolve15 } from "node:path";
|
|
8955
9492
|
var DEFAULTS2 = {
|
|
8956
9493
|
default: "en",
|
|
8957
9494
|
cookie: "locale",
|
|
@@ -8969,7 +9506,7 @@ function translate(msgs, key, params, fallback) {
|
|
|
8969
9506
|
}
|
|
8970
9507
|
function i18n(options) {
|
|
8971
9508
|
const opts = { ...DEFAULTS2, ...options };
|
|
8972
|
-
const dir = opts.dir ?
|
|
9509
|
+
const dir = opts.dir ? resolve15(opts.dir) : void 0;
|
|
8973
9510
|
const cache3 = /* @__PURE__ */ new Map();
|
|
8974
9511
|
function validLocale(locale) {
|
|
8975
9512
|
return /^[\w-]+$/.test(locale) && !locale.includes("..");
|
|
@@ -9022,7 +9559,10 @@ function i18n(options) {
|
|
|
9022
9559
|
set: (value, loc) => {
|
|
9023
9560
|
const cookie = `${opts.cookie}=${encodeURIComponent(value)}; Path=/; SameSite=Lax`;
|
|
9024
9561
|
const location = loc ?? (req.headers.get("referer") || "/");
|
|
9025
|
-
return new Response(null, {
|
|
9562
|
+
return new Response(null, {
|
|
9563
|
+
status: 302,
|
|
9564
|
+
headers: { Location: location, "Set-Cookie": cookie }
|
|
9565
|
+
});
|
|
9026
9566
|
}
|
|
9027
9567
|
};
|
|
9028
9568
|
return next(req, ctx);
|
|
@@ -9041,7 +9581,11 @@ function i18n(options) {
|
|
|
9041
9581
|
const accept = req.headers.get("accept") ?? "";
|
|
9042
9582
|
if (accept.includes("application/json")) {
|
|
9043
9583
|
return Response.json(
|
|
9044
|
-
{
|
|
9584
|
+
{
|
|
9585
|
+
ok: true,
|
|
9586
|
+
locale: value,
|
|
9587
|
+
messages: Object.keys(messages2).length > 0 ? messages2 : void 0
|
|
9588
|
+
},
|
|
9045
9589
|
{ headers: { "Set-Cookie": cookie } }
|
|
9046
9590
|
);
|
|
9047
9591
|
}
|
|
@@ -9359,10 +9903,11 @@ function listHandler(entries) {
|
|
|
9359
9903
|
if (before) conditions.push(lt("created_at", before));
|
|
9360
9904
|
const limit = parseInt(url.searchParams.get("limit") ?? "50", 10);
|
|
9361
9905
|
const offset = parseInt(url.searchParams.get("offset") ?? "0", 10);
|
|
9362
|
-
const { count, data } = await entries.readMany(
|
|
9363
|
-
|
|
9364
|
-
|
|
9365
|
-
|
|
9906
|
+
const { count, data } = await entries.readMany(conditions.length > 0 ? conditions : void 0, {
|
|
9907
|
+
orderBy: { created_at: "desc" },
|
|
9908
|
+
limit,
|
|
9909
|
+
offset
|
|
9910
|
+
});
|
|
9366
9911
|
return Response.json({ entries: data.map(parseMetadata), total: count });
|
|
9367
9912
|
};
|
|
9368
9913
|
}
|
|
@@ -9473,12 +10018,15 @@ import crypto8 from "node:crypto";
|
|
|
9473
10018
|
|
|
9474
10019
|
// iii/stream.ts
|
|
9475
10020
|
function notify(channels, stream, group, item, event, data) {
|
|
9476
|
-
const keys = [
|
|
9477
|
-
|
|
9478
|
-
|
|
9479
|
-
|
|
9480
|
-
|
|
9481
|
-
|
|
10021
|
+
const keys = [`${stream}`, `${stream}:${group}`, `${stream}:${group}:${item}`];
|
|
10022
|
+
const msg = JSON.stringify({
|
|
10023
|
+
type: "stream",
|
|
10024
|
+
stream_name: stream,
|
|
10025
|
+
group_id: group,
|
|
10026
|
+
item_id: item,
|
|
10027
|
+
event,
|
|
10028
|
+
data
|
|
10029
|
+
});
|
|
9482
10030
|
for (const key of keys) {
|
|
9483
10031
|
const subs = channels.get(key);
|
|
9484
10032
|
if (!subs) continue;
|
|
@@ -9697,10 +10245,13 @@ function createRedisStore(channels, redis2, ttl) {
|
|
|
9697
10245
|
async set(stream, group, item, data) {
|
|
9698
10246
|
const hk = hashKey(stream, group);
|
|
9699
10247
|
const oldRaw = await redis2.hget(hk, item);
|
|
9700
|
-
|
|
10248
|
+
const old = oldRaw ? JSON.parse(oldRaw) : null;
|
|
9701
10249
|
await redis2.hset(hk, item, JSON.stringify(data));
|
|
9702
10250
|
setTTL(hk);
|
|
9703
|
-
await redis2.publish(
|
|
10251
|
+
await redis2.publish(
|
|
10252
|
+
`iii:stream:${stream}`,
|
|
10253
|
+
JSON.stringify({ event: "set", group, item, data })
|
|
10254
|
+
);
|
|
9704
10255
|
notify(channels, stream, group, item, "set", data);
|
|
9705
10256
|
return { old_value: old, new_value: deepClone(data) };
|
|
9706
10257
|
},
|
|
@@ -9776,7 +10327,10 @@ function createRedisStore(channels, redis2, ttl) {
|
|
|
9776
10327
|
const newVal = applyOps(old, ops);
|
|
9777
10328
|
await redis2.hset(hk, item, JSON.stringify(newVal));
|
|
9778
10329
|
setTTL(hk);
|
|
9779
|
-
await redis2.publish(
|
|
10330
|
+
await redis2.publish(
|
|
10331
|
+
`iii:stream:${stream}`,
|
|
10332
|
+
JSON.stringify({ event: "update", group, item, data: newVal })
|
|
10333
|
+
);
|
|
9780
10334
|
notify(channels, stream, group, item, "update", newVal);
|
|
9781
10335
|
return { old_value: old, new_value: deepClone(newVal) };
|
|
9782
10336
|
}
|
|
@@ -9844,7 +10398,7 @@ function createWsHandler(deps) {
|
|
|
9844
10398
|
return wsToWorkerId.get(ws) || "";
|
|
9845
10399
|
}
|
|
9846
10400
|
return {
|
|
9847
|
-
open(_ws,
|
|
10401
|
+
open(_ws, _ctx2) {
|
|
9848
10402
|
},
|
|
9849
10403
|
async message(ws, ctx, data) {
|
|
9850
10404
|
let msg;
|
|
@@ -9856,10 +10410,7 @@ function createWsHandler(deps) {
|
|
|
9856
10410
|
}
|
|
9857
10411
|
switch (msg.type) {
|
|
9858
10412
|
case "register_worker": {
|
|
9859
|
-
const workerId = deps.registerRemoteWorker(
|
|
9860
|
-
ws,
|
|
9861
|
-
msg.worker_name || `remote-${Date.now()}`
|
|
9862
|
-
);
|
|
10413
|
+
const workerId = deps.registerRemoteWorker(ws, msg.worker_name || `remote-${Date.now()}`);
|
|
9863
10414
|
wsToWorkerId.set(ws, workerId);
|
|
9864
10415
|
ws.send(JSON.stringify({ type: "registered", worker_id: workerId }));
|
|
9865
10416
|
break;
|
|
@@ -9963,10 +10514,7 @@ function buildRouter5(engine, wsHandler) {
|
|
|
9963
10514
|
}
|
|
9964
10515
|
return Response.json(result);
|
|
9965
10516
|
} catch (err) {
|
|
9966
|
-
return Response.json(
|
|
9967
|
-
{ error: err.message || "Internal error" },
|
|
9968
|
-
{ status: 500 }
|
|
9969
|
-
);
|
|
10517
|
+
return Response.json({ error: err.message || "Internal error" }, { status: 500 });
|
|
9970
10518
|
}
|
|
9971
10519
|
});
|
|
9972
10520
|
r.ws("/worker", wsHandler);
|
|
@@ -9989,14 +10537,23 @@ function iii(opts = {}) {
|
|
|
9989
10537
|
triggers: []
|
|
9990
10538
|
});
|
|
9991
10539
|
}
|
|
9992
|
-
registerBuiltin(
|
|
10540
|
+
registerBuiltin(
|
|
10541
|
+
"stream::set",
|
|
10542
|
+
(p) => stream.set(p.stream_name, p.group_id, p.item_id, p.data)
|
|
10543
|
+
);
|
|
9993
10544
|
registerBuiltin("stream::get", (p) => stream.get(p.stream_name, p.group_id, p.item_id));
|
|
9994
10545
|
registerBuiltin("stream::delete", (p) => stream.delete(p.stream_name, p.group_id, p.item_id));
|
|
9995
10546
|
registerBuiltin("stream::list", (p) => stream.list(p.stream_name, p.group_id));
|
|
9996
10547
|
registerBuiltin("stream::list_groups", (p) => stream.list_groups(p.stream_name));
|
|
9997
10548
|
registerBuiltin("stream::list_all", () => stream.list_all());
|
|
9998
|
-
registerBuiltin(
|
|
9999
|
-
|
|
10549
|
+
registerBuiltin(
|
|
10550
|
+
"stream::send",
|
|
10551
|
+
(p) => stream.send(p.stream_name, p.group_id, p.type, p.data, p.id)
|
|
10552
|
+
);
|
|
10553
|
+
registerBuiltin(
|
|
10554
|
+
"stream::update",
|
|
10555
|
+
(p) => stream.update(p.stream_name, p.group_id, p.item_id, p.ops)
|
|
10556
|
+
);
|
|
10000
10557
|
function addLocalWorker(worker) {
|
|
10001
10558
|
const workerId = crypto8.randomUUID();
|
|
10002
10559
|
const reg = {
|
|
@@ -10043,18 +10600,20 @@ function iii(opts = {}) {
|
|
|
10043
10600
|
const handler = async (payload) => {
|
|
10044
10601
|
if (!worker.ws) throw new Error(`Worker "${worker.name}" disconnected`);
|
|
10045
10602
|
const invocationId = crypto8.randomUUID();
|
|
10046
|
-
return new Promise((
|
|
10603
|
+
return new Promise((resolve16, reject) => {
|
|
10047
10604
|
const timer = setTimeout(() => {
|
|
10048
10605
|
pending.delete(invocationId);
|
|
10049
10606
|
reject(new Error(`Invocation timed out for "${id2}"`));
|
|
10050
10607
|
}, 3e4);
|
|
10051
|
-
pending.set(invocationId, { resolve:
|
|
10052
|
-
worker.ws.send(
|
|
10053
|
-
|
|
10054
|
-
|
|
10055
|
-
|
|
10056
|
-
|
|
10057
|
-
|
|
10608
|
+
pending.set(invocationId, { resolve: resolve16, reject, timer });
|
|
10609
|
+
worker.ws.send(
|
|
10610
|
+
JSON.stringify({
|
|
10611
|
+
type: "invoke",
|
|
10612
|
+
invocation_id: invocationId,
|
|
10613
|
+
function_id: id2,
|
|
10614
|
+
payload
|
|
10615
|
+
})
|
|
10616
|
+
);
|
|
10058
10617
|
});
|
|
10059
10618
|
};
|
|
10060
10619
|
const fnReg = {
|
|
@@ -10138,18 +10697,26 @@ function iii(opts = {}) {
|
|
|
10138
10697
|
handleInvoke(ws, invocationId, functionId, payload) {
|
|
10139
10698
|
const fn = functions.get(functionId);
|
|
10140
10699
|
if (!fn) {
|
|
10141
|
-
ws.send(
|
|
10142
|
-
|
|
10143
|
-
|
|
10144
|
-
|
|
10145
|
-
|
|
10700
|
+
ws.send(
|
|
10701
|
+
JSON.stringify({
|
|
10702
|
+
type: "invoke_error",
|
|
10703
|
+
invocation_id: invocationId,
|
|
10704
|
+
error: `Function "${functionId}" not found`
|
|
10705
|
+
})
|
|
10706
|
+
);
|
|
10146
10707
|
return;
|
|
10147
10708
|
}
|
|
10148
10709
|
const ctx = { engine: engineRef, functionId, workerName: fn.workerName };
|
|
10149
10710
|
Promise.resolve(fn.handler(payload, ctx)).then((result) => {
|
|
10150
10711
|
ws.send(JSON.stringify({ type: "invoke_result", invocation_id: invocationId, result }));
|
|
10151
10712
|
}).catch((err) => {
|
|
10152
|
-
ws.send(
|
|
10713
|
+
ws.send(
|
|
10714
|
+
JSON.stringify({
|
|
10715
|
+
type: "invoke_error",
|
|
10716
|
+
invocation_id: invocationId,
|
|
10717
|
+
error: err.message
|
|
10718
|
+
})
|
|
10719
|
+
);
|
|
10153
10720
|
});
|
|
10154
10721
|
}
|
|
10155
10722
|
});
|
|
@@ -10289,8 +10856,8 @@ function registerWorker(url) {
|
|
|
10289
10856
|
function connect() {
|
|
10290
10857
|
if (intentionalClose) return;
|
|
10291
10858
|
ws = new WebSocket(url);
|
|
10292
|
-
ready = new Promise((
|
|
10293
|
-
resolveReady =
|
|
10859
|
+
ready = new Promise((resolve16) => {
|
|
10860
|
+
resolveReady = resolve16;
|
|
10294
10861
|
});
|
|
10295
10862
|
ws.onopen = () => {
|
|
10296
10863
|
reconnectAttempt = 0;
|
|
@@ -10313,25 +10880,31 @@ function registerWorker(url) {
|
|
|
10313
10880
|
case "invoke": {
|
|
10314
10881
|
const handler = handlers.get(msg.function_id);
|
|
10315
10882
|
if (!handler) {
|
|
10316
|
-
ws?.send(
|
|
10317
|
-
|
|
10318
|
-
|
|
10319
|
-
|
|
10320
|
-
|
|
10883
|
+
ws?.send(
|
|
10884
|
+
JSON.stringify({
|
|
10885
|
+
type: "invoke_error",
|
|
10886
|
+
invocation_id: msg.invocation_id,
|
|
10887
|
+
error: `Function "${msg.function_id}" not found`
|
|
10888
|
+
})
|
|
10889
|
+
);
|
|
10321
10890
|
return;
|
|
10322
10891
|
}
|
|
10323
10892
|
Promise.resolve(handler(msg.payload, {})).then((result) => {
|
|
10324
|
-
ws?.send(
|
|
10325
|
-
|
|
10326
|
-
|
|
10327
|
-
|
|
10328
|
-
|
|
10893
|
+
ws?.send(
|
|
10894
|
+
JSON.stringify({
|
|
10895
|
+
type: "invoke_result",
|
|
10896
|
+
invocation_id: msg.invocation_id,
|
|
10897
|
+
result
|
|
10898
|
+
})
|
|
10899
|
+
);
|
|
10329
10900
|
}).catch((err) => {
|
|
10330
|
-
ws?.send(
|
|
10331
|
-
|
|
10332
|
-
|
|
10333
|
-
|
|
10334
|
-
|
|
10901
|
+
ws?.send(
|
|
10902
|
+
JSON.stringify({
|
|
10903
|
+
type: "invoke_error",
|
|
10904
|
+
invocation_id: msg.invocation_id,
|
|
10905
|
+
error: err.message
|
|
10906
|
+
})
|
|
10907
|
+
);
|
|
10335
10908
|
});
|
|
10336
10909
|
break;
|
|
10337
10910
|
}
|
|
@@ -10385,7 +10958,12 @@ function registerWorker(url) {
|
|
|
10385
10958
|
},
|
|
10386
10959
|
registerTrigger(input) {
|
|
10387
10960
|
registeredTriggers.add(JSON.stringify(input));
|
|
10388
|
-
send({
|
|
10961
|
+
send({
|
|
10962
|
+
type: "register_trigger",
|
|
10963
|
+
function_id: input.function_id,
|
|
10964
|
+
trigger_type: input.type,
|
|
10965
|
+
config: input.config
|
|
10966
|
+
});
|
|
10389
10967
|
},
|
|
10390
10968
|
unregisterTrigger(functionId) {
|
|
10391
10969
|
for (const key of registeredTriggers) {
|
|
@@ -10410,13 +10988,13 @@ function registerWorker(url) {
|
|
|
10410
10988
|
}
|
|
10411
10989
|
return Promise.resolve(fn(request.payload, ctx));
|
|
10412
10990
|
}
|
|
10413
|
-
return new Promise((
|
|
10991
|
+
return new Promise((resolve16, reject) => {
|
|
10414
10992
|
const invocationId = genId();
|
|
10415
10993
|
const timer = setTimeout(() => {
|
|
10416
10994
|
pendingInvocations.delete(invocationId);
|
|
10417
10995
|
reject(new Error(`Invocation timed out for "${request.function_id}"`));
|
|
10418
10996
|
}, request.timeout_ms || 3e4);
|
|
10419
|
-
pendingInvocations.set(invocationId, { resolve:
|
|
10997
|
+
pendingInvocations.set(invocationId, { resolve: resolve16, reject, timer });
|
|
10420
10998
|
send({
|
|
10421
10999
|
type: "invoke",
|
|
10422
11000
|
invocation_id: invocationId,
|
|
@@ -10560,8 +11138,18 @@ function createSessionObject(data, sid, store2, ttl, createdAt) {
|
|
|
10560
11138
|
enumerable: false,
|
|
10561
11139
|
configurable: false
|
|
10562
11140
|
});
|
|
10563
|
-
Object.defineProperty(obj, "save", {
|
|
10564
|
-
|
|
11141
|
+
Object.defineProperty(obj, "save", {
|
|
11142
|
+
enumerable: false,
|
|
11143
|
+
configurable: true,
|
|
11144
|
+
writable: true,
|
|
11145
|
+
value: obj.save
|
|
11146
|
+
});
|
|
11147
|
+
Object.defineProperty(obj, "destroy", {
|
|
11148
|
+
enumerable: false,
|
|
11149
|
+
configurable: true,
|
|
11150
|
+
writable: true,
|
|
11151
|
+
value: obj.destroy
|
|
11152
|
+
});
|
|
10565
11153
|
return obj;
|
|
10566
11154
|
}
|
|
10567
11155
|
function isSessionActive(session2) {
|
|
@@ -10931,7 +11519,8 @@ function createStripeVerifier(config) {
|
|
|
10931
11519
|
}, {});
|
|
10932
11520
|
const timestamp = parts["t"];
|
|
10933
11521
|
const signature = parts["v1"];
|
|
10934
|
-
if (!timestamp || !signature)
|
|
11522
|
+
if (!timestamp || !signature)
|
|
11523
|
+
return { valid: false, provider: "stripe", event: "", id: void 0 };
|
|
10935
11524
|
const signed = `${timestamp}.${body}`;
|
|
10936
11525
|
const expected = crypto11.createHmac("sha256", config.secret).update(signed).digest("hex");
|
|
10937
11526
|
const valid = timingSafeEqual2(signature, expected);
|
|
@@ -10952,7 +11541,7 @@ function createGitHubVerifier(config) {
|
|
|
10952
11541
|
if (!sig) return { valid: false, provider: "github", event: "", id: void 0 };
|
|
10953
11542
|
const expected = `sha256=${crypto11.createHmac("sha256", config.secret).update(body).digest("hex")}`;
|
|
10954
11543
|
const valid = timingSafeEqual2(sig, expected);
|
|
10955
|
-
|
|
11544
|
+
const event = headers["x-github-event"] ?? "";
|
|
10956
11545
|
let id2;
|
|
10957
11546
|
try {
|
|
10958
11547
|
const parsed = JSON.parse(body);
|
|
@@ -10966,7 +11555,8 @@ function createSlackVerifier(config) {
|
|
|
10966
11555
|
return (body, headers) => {
|
|
10967
11556
|
const signature = headers["x-slack-signature"];
|
|
10968
11557
|
const timestamp = headers["x-slack-request-timestamp"];
|
|
10969
|
-
if (!signature || !timestamp)
|
|
11558
|
+
if (!signature || !timestamp)
|
|
11559
|
+
return { valid: false, provider: "slack", event: "", id: void 0 };
|
|
10970
11560
|
const now = Math.floor(Date.now() / 1e3);
|
|
10971
11561
|
const ts = parseInt(timestamp, 10);
|
|
10972
11562
|
if (isNaN(ts) || Math.abs(now - ts) > 300) {
|
|
@@ -11128,11 +11718,7 @@ __export(fts_exports, {
|
|
|
11128
11718
|
suggest: () => suggest
|
|
11129
11719
|
});
|
|
11130
11720
|
function resolveTableName(table) {
|
|
11131
|
-
|
|
11132
|
-
if (!name || typeof name !== "string") {
|
|
11133
|
-
throw new Error("fts: could not determine table name. Ensure you pass a pg.table() result.");
|
|
11134
|
-
}
|
|
11135
|
-
return name;
|
|
11721
|
+
return table.tableName;
|
|
11136
11722
|
}
|
|
11137
11723
|
function escapeIdent4(s) {
|
|
11138
11724
|
return `"${s.replace(/"/g, '""')}"`;
|
|
@@ -11344,7 +11930,15 @@ function escapeIdent5(s) {
|
|
|
11344
11930
|
return `"${s.replace(/"/g, '""')}"`;
|
|
11345
11931
|
}
|
|
11346
11932
|
function knowledgeBase(options) {
|
|
11347
|
-
const {
|
|
11933
|
+
const {
|
|
11934
|
+
pg,
|
|
11935
|
+
provider,
|
|
11936
|
+
table = "_kb_docs",
|
|
11937
|
+
chunkSize = 512,
|
|
11938
|
+
chunkOverlap = 64,
|
|
11939
|
+
searchLimit = 5,
|
|
11940
|
+
searchThreshold = 0
|
|
11941
|
+
} = options;
|
|
11348
11942
|
const sql2 = pg.sql;
|
|
11349
11943
|
const dimension = provider.dimension;
|
|
11350
11944
|
const docsTable = pg.table(table, {
|