weifuwu 0.24.1 → 0.24.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +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/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 +787 -346
- 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/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/session.d.ts +1 -2
- 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 +26 -3
- package/cli/template/.weifuwu/ssr/2e3a7e60.js +0 -112
package/dist/index.js
CHANGED
|
@@ -262,9 +262,13 @@ function serve(handler, options) {
|
|
|
262
262
|
}
|
|
263
263
|
};
|
|
264
264
|
}
|
|
265
|
-
options.signal.addEventListener(
|
|
266
|
-
|
|
267
|
-
|
|
265
|
+
options.signal.addEventListener(
|
|
266
|
+
"abort",
|
|
267
|
+
() => {
|
|
268
|
+
server.close();
|
|
269
|
+
},
|
|
270
|
+
{ once: true }
|
|
271
|
+
);
|
|
268
272
|
}
|
|
269
273
|
server.on("error", (err) => {
|
|
270
274
|
console.error("Failed to start server:", err.message);
|
|
@@ -488,7 +492,8 @@ var Router = class _Router {
|
|
|
488
492
|
}
|
|
489
493
|
} else if (typeof arg1 === "function") {
|
|
490
494
|
this.globalMws.push(arg1);
|
|
491
|
-
} else if (typeof arg1 === "object" && arg1 !== null && "middleware" in arg1 &&
|
|
495
|
+
} else if (typeof arg1 === "object" && arg1 !== null && "middleware" in arg1 && // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
496
|
+
typeof arg1.middleware === "function" && arg1 instanceof _Router) {
|
|
492
497
|
const mod = arg1;
|
|
493
498
|
this.globalMws.push(mod.middleware());
|
|
494
499
|
this._mountRouter("/", mod);
|
|
@@ -529,6 +534,7 @@ var Router = class _Router {
|
|
|
529
534
|
return this._routeImpl(method, path2, args);
|
|
530
535
|
}
|
|
531
536
|
/** Internal route registration — no type constraints (used by _mountRouter). */
|
|
537
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
532
538
|
_routeImpl(method, path2, args) {
|
|
533
539
|
const last = args[args.length - 1];
|
|
534
540
|
if (last instanceof _Router) {
|
|
@@ -554,9 +560,7 @@ var Router = class _Router {
|
|
|
554
560
|
node = getOrCreateChild(node, segment, createTrieNode, false);
|
|
555
561
|
}
|
|
556
562
|
if (!isProd() && node.handlers.has(method)) {
|
|
557
|
-
console.warn(
|
|
558
|
-
`[router] route conflict: ${method} ${path2} overwrites existing handler`
|
|
559
|
-
);
|
|
563
|
+
console.warn(`[router] route conflict: ${method} ${path2} overwrites existing handler`);
|
|
560
564
|
}
|
|
561
565
|
node.handlers.set(method, handler);
|
|
562
566
|
if (middlewares.length > 0) node.middlewares.set(method, middlewares);
|
|
@@ -591,7 +595,7 @@ var Router = class _Router {
|
|
|
591
595
|
return result;
|
|
592
596
|
}
|
|
593
597
|
_collectRoutes(node, prefix, result) {
|
|
594
|
-
for (const [method
|
|
598
|
+
for (const [method] of node.handlers) {
|
|
595
599
|
const m = method === "*" ? "ANY" : method;
|
|
596
600
|
const path2 = (prefix || "/") + (node.wildcard ? "/*" : "");
|
|
597
601
|
const middlewares = node.middlewares.get(method);
|
|
@@ -669,7 +673,12 @@ var Router = class _Router {
|
|
|
669
673
|
const wsRoutes = [];
|
|
670
674
|
this._collectWs(sub.wsRoot, "", wsRoutes);
|
|
671
675
|
for (const { path: path2, handler, middlewares } of wsRoutes) {
|
|
672
|
-
this.ws(
|
|
676
|
+
this.ws(
|
|
677
|
+
base + path2,
|
|
678
|
+
...allExtra,
|
|
679
|
+
...middlewares,
|
|
680
|
+
handler
|
|
681
|
+
);
|
|
673
682
|
}
|
|
674
683
|
}
|
|
675
684
|
mergeMws(base, extra) {
|
|
@@ -682,7 +691,12 @@ var Router = class _Router {
|
|
|
682
691
|
for (const [method, handler] of node.handlers) {
|
|
683
692
|
const rmws = node.middlewares.get(method) || [];
|
|
684
693
|
const suffix = node.wildcard ? "/*" : "";
|
|
685
|
-
result.push({
|
|
694
|
+
result.push({
|
|
695
|
+
method,
|
|
696
|
+
path: (prefix || "/") + suffix,
|
|
697
|
+
handler,
|
|
698
|
+
middlewares: this.mergeMws(mws, rmws)
|
|
699
|
+
});
|
|
686
700
|
}
|
|
687
701
|
for (const [seg, child] of node.children) {
|
|
688
702
|
const next = seg === ":" ? `/:${child.param}` : `/${seg}`;
|
|
@@ -744,7 +758,12 @@ var Router = class _Router {
|
|
|
744
758
|
return { handler: wildcardHandler, middlewares: wildcardMws, pathMws, params };
|
|
745
759
|
}
|
|
746
760
|
if (node.handlers.size > 0) {
|
|
747
|
-
return {
|
|
761
|
+
return {
|
|
762
|
+
middlewares: [],
|
|
763
|
+
pathMws,
|
|
764
|
+
params,
|
|
765
|
+
allowedMethods: [...node.handlers.keys()].filter((k) => k !== "*")
|
|
766
|
+
};
|
|
748
767
|
}
|
|
749
768
|
return null;
|
|
750
769
|
}
|
|
@@ -779,38 +798,54 @@ var Router = class _Router {
|
|
|
779
798
|
if (match.allowedMethods && match.allowedMethods.length > 0) {
|
|
780
799
|
if (this.globalMws.length > 0) {
|
|
781
800
|
try {
|
|
782
|
-
return await this.runChain(
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
801
|
+
return await this.runChain(
|
|
802
|
+
this.globalMws,
|
|
803
|
+
() => new Response("Method Not Allowed", {
|
|
804
|
+
status: 405,
|
|
805
|
+
headers: { Allow: match.allowedMethods.join(", ") }
|
|
806
|
+
}),
|
|
807
|
+
req,
|
|
808
|
+
ctx
|
|
809
|
+
);
|
|
786
810
|
} catch (e) {
|
|
787
811
|
return this.handleError(e, req, ctx);
|
|
788
812
|
}
|
|
789
813
|
}
|
|
790
814
|
return new Response("Method Not Allowed", {
|
|
791
815
|
status: 405,
|
|
792
|
-
headers: {
|
|
816
|
+
headers: { Allow: match.allowedMethods.join(", ") }
|
|
793
817
|
});
|
|
794
818
|
}
|
|
795
819
|
}
|
|
796
820
|
if (this.globalMws.length > 0) {
|
|
797
821
|
try {
|
|
798
|
-
return await this.runChain(
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
822
|
+
return await this.runChain(
|
|
823
|
+
this.globalMws,
|
|
824
|
+
() => {
|
|
825
|
+
if (!isProd()) {
|
|
826
|
+
return Response.json(
|
|
827
|
+
{ error: "Not Found", path: "/" + segments.join("/"), method: req.method },
|
|
828
|
+
{ status: 404 }
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
return new Response("Not Found", { status: 404 });
|
|
832
|
+
},
|
|
833
|
+
req,
|
|
834
|
+
ctx
|
|
835
|
+
);
|
|
804
836
|
} catch (e) {
|
|
805
837
|
return this.handleError(e, req, ctx);
|
|
806
838
|
}
|
|
807
839
|
}
|
|
808
840
|
if (!isProd()) {
|
|
809
|
-
return Response.json(
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
841
|
+
return Response.json(
|
|
842
|
+
{
|
|
843
|
+
error: "Not Found",
|
|
844
|
+
path: "/" + segments.join("/"),
|
|
845
|
+
method: req.method
|
|
846
|
+
},
|
|
847
|
+
{ status: 404 }
|
|
848
|
+
);
|
|
814
849
|
}
|
|
815
850
|
return new Response("Not Found", { status: 404 });
|
|
816
851
|
}
|
|
@@ -825,7 +860,9 @@ function runChainLoop(middlewares, index, finalHandler, req, ctx) {
|
|
|
825
860
|
let called = false;
|
|
826
861
|
const dispatch = (r, c) => {
|
|
827
862
|
if (called) {
|
|
828
|
-
console.warn(
|
|
863
|
+
console.warn(
|
|
864
|
+
"[router] next() called more than once in middleware \u2014 ignoring duplicate call"
|
|
865
|
+
);
|
|
829
866
|
return Promise.resolve(new Response("Internal Server Error", { status: 500 }));
|
|
830
867
|
}
|
|
831
868
|
called = true;
|
|
@@ -849,7 +886,7 @@ function upgradeSocket(wss, req, socket, head, handler, ctx, hub) {
|
|
|
849
886
|
join(room) {
|
|
850
887
|
hub.join(room, ws);
|
|
851
888
|
},
|
|
852
|
-
leave(
|
|
889
|
+
leave(_room) {
|
|
853
890
|
hub.leave(ws);
|
|
854
891
|
},
|
|
855
892
|
sendRoom(room, data) {
|
|
@@ -899,7 +936,15 @@ function sendHttpResponseOnSocket(socket, response) {
|
|
|
899
936
|
|
|
900
937
|
// tsx-context.ts
|
|
901
938
|
import { useSyncExternalStore, createContext } from "react";
|
|
902
|
-
var DEFAULT_CTX = {
|
|
939
|
+
var DEFAULT_CTX = {
|
|
940
|
+
params: {},
|
|
941
|
+
query: {},
|
|
942
|
+
parsed: {},
|
|
943
|
+
loaderData: {},
|
|
944
|
+
env: {},
|
|
945
|
+
user: {},
|
|
946
|
+
flash: {}
|
|
947
|
+
};
|
|
903
948
|
var KEY = "__WEIFUWU_CTX_STORE";
|
|
904
949
|
function getStore() {
|
|
905
950
|
if (typeof globalThis !== "undefined" && globalThis[KEY]) {
|
|
@@ -907,12 +952,22 @@ function getStore() {
|
|
|
907
952
|
}
|
|
908
953
|
const s = {
|
|
909
954
|
_ctx: DEFAULT_CTX,
|
|
910
|
-
_snapshot: {
|
|
955
|
+
_snapshot: {
|
|
956
|
+
params: DEFAULT_CTX.params,
|
|
957
|
+
query: DEFAULT_CTX.query,
|
|
958
|
+
user: DEFAULT_CTX.user,
|
|
959
|
+
parsed: DEFAULT_CTX.parsed,
|
|
960
|
+
theme: DEFAULT_CTX.theme,
|
|
961
|
+
i18n: DEFAULT_CTX.i18n,
|
|
962
|
+
loaderData: DEFAULT_CTX.loaderData,
|
|
963
|
+
env: DEFAULT_CTX.env
|
|
964
|
+
},
|
|
911
965
|
_listeners: /* @__PURE__ */ new Set(),
|
|
912
966
|
_rebuilders: [],
|
|
913
967
|
_alsGetStore: null
|
|
914
968
|
};
|
|
915
969
|
if (typeof globalThis !== "undefined") {
|
|
970
|
+
;
|
|
916
971
|
globalThis[KEY] = s;
|
|
917
972
|
}
|
|
918
973
|
return s;
|
|
@@ -929,7 +984,16 @@ function setCtx(value) {
|
|
|
929
984
|
}
|
|
930
985
|
}
|
|
931
986
|
store._ctx = { ...store._ctx, ...value };
|
|
932
|
-
store._snapshot = {
|
|
987
|
+
store._snapshot = {
|
|
988
|
+
params: store._ctx.params,
|
|
989
|
+
query: store._ctx.query,
|
|
990
|
+
user: store._ctx.user,
|
|
991
|
+
parsed: store._ctx.parsed,
|
|
992
|
+
theme: store._ctx.theme,
|
|
993
|
+
i18n: store._ctx.i18n,
|
|
994
|
+
loaderData: store._ctx.loaderData,
|
|
995
|
+
env: store._ctx.env
|
|
996
|
+
};
|
|
933
997
|
if (typeof window !== "undefined") {
|
|
934
998
|
;
|
|
935
999
|
window.__WEIFUWU_CTX = { ...window.__WEIFUWU_CTX, ...value };
|
|
@@ -1014,7 +1078,8 @@ function cors(options) {
|
|
|
1014
1078
|
const headers = new Headers(res.headers);
|
|
1015
1079
|
headers.set("Access-Control-Allow-Origin", acao);
|
|
1016
1080
|
if (opts.credentials) headers.set("Access-Control-Allow-Credentials", "true");
|
|
1017
|
-
if (opts.exposedHeaders?.length)
|
|
1081
|
+
if (opts.exposedHeaders?.length)
|
|
1082
|
+
headers.set("Access-Control-Expose-Headers", opts.exposedHeaders.join(", "));
|
|
1018
1083
|
if (acao !== "*") headers.set("Vary", "Origin");
|
|
1019
1084
|
return new Response(res.body, { status: res.status, statusText: res.statusText, headers });
|
|
1020
1085
|
}
|
|
@@ -1091,7 +1156,7 @@ function serveStatic(root, options) {
|
|
|
1091
1156
|
const headers = {
|
|
1092
1157
|
"Content-Type": mimeType,
|
|
1093
1158
|
"Content-Length": String(stat3.size),
|
|
1094
|
-
|
|
1159
|
+
ETag: etag,
|
|
1095
1160
|
"Last-Modified": stat3.mtime.toUTCString(),
|
|
1096
1161
|
"Cache-Control": opts.immutable ? `public, max-age=${opts.maxAge ?? 31536e3}, immutable` : `public, max-age=${opts.maxAge ?? 0}`
|
|
1097
1162
|
};
|
|
@@ -1181,10 +1246,12 @@ function validate(schemas) {
|
|
|
1181
1246
|
if (result.success) {
|
|
1182
1247
|
parsed.params = result.data;
|
|
1183
1248
|
} else {
|
|
1184
|
-
issues.push(
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1249
|
+
issues.push(
|
|
1250
|
+
...result.error.issues.map((i) => ({
|
|
1251
|
+
path: ["params", ...i.path.map(String)],
|
|
1252
|
+
message: i.message
|
|
1253
|
+
}))
|
|
1254
|
+
);
|
|
1188
1255
|
}
|
|
1189
1256
|
}
|
|
1190
1257
|
if (schemas?.query) {
|
|
@@ -1192,10 +1259,12 @@ function validate(schemas) {
|
|
|
1192
1259
|
if (result.success) {
|
|
1193
1260
|
parsed.query = result.data;
|
|
1194
1261
|
} else {
|
|
1195
|
-
issues.push(
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1262
|
+
issues.push(
|
|
1263
|
+
...result.error.issues.map((i) => ({
|
|
1264
|
+
path: ["query", ...i.path.map(String)],
|
|
1265
|
+
message: i.message
|
|
1266
|
+
}))
|
|
1267
|
+
);
|
|
1199
1268
|
}
|
|
1200
1269
|
}
|
|
1201
1270
|
if (schemas?.headers) {
|
|
@@ -1207,10 +1276,12 @@ function validate(schemas) {
|
|
|
1207
1276
|
if (result.success) {
|
|
1208
1277
|
parsed.headers = result.data;
|
|
1209
1278
|
} else {
|
|
1210
|
-
issues.push(
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1279
|
+
issues.push(
|
|
1280
|
+
...result.error.issues.map((i) => ({
|
|
1281
|
+
path: ["headers", ...i.path.map(String)],
|
|
1282
|
+
message: i.message
|
|
1283
|
+
}))
|
|
1284
|
+
);
|
|
1214
1285
|
}
|
|
1215
1286
|
}
|
|
1216
1287
|
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
@@ -1234,10 +1305,12 @@ function validate(schemas) {
|
|
|
1234
1305
|
if (result.success) {
|
|
1235
1306
|
parsed.body = result.data;
|
|
1236
1307
|
} else {
|
|
1237
|
-
issues.push(
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1308
|
+
issues.push(
|
|
1309
|
+
...result.error.issues.map((i) => ({
|
|
1310
|
+
path: ["body", ...i.path.map(String)],
|
|
1311
|
+
message: i.message
|
|
1312
|
+
}))
|
|
1313
|
+
);
|
|
1241
1314
|
}
|
|
1242
1315
|
} else {
|
|
1243
1316
|
parsed.body = bodyValue;
|
|
@@ -1305,11 +1378,14 @@ function setCookie(res, name, value, options) {
|
|
|
1305
1378
|
}
|
|
1306
1379
|
function deleteCookie(res, name, options) {
|
|
1307
1380
|
const headers = new Headers(res.headers);
|
|
1308
|
-
headers.append(
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1381
|
+
headers.append(
|
|
1382
|
+
"Set-Cookie",
|
|
1383
|
+
serializeCookie(name, "", {
|
|
1384
|
+
...options,
|
|
1385
|
+
maxAge: 0,
|
|
1386
|
+
expires: /* @__PURE__ */ new Date(0)
|
|
1387
|
+
})
|
|
1388
|
+
);
|
|
1313
1389
|
return new Response(res.body, {
|
|
1314
1390
|
status: res.status,
|
|
1315
1391
|
statusText: res.statusText,
|
|
@@ -1433,21 +1509,24 @@ function rateLimit(options) {
|
|
|
1433
1509
|
const keyPrefix = options?.prefix ?? "ratelimit:";
|
|
1434
1510
|
const MAX_ENTRIES2 = 1e4;
|
|
1435
1511
|
const hits = /* @__PURE__ */ new Map();
|
|
1436
|
-
const interval = storeType === "memory" ? setInterval(
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1512
|
+
const interval = storeType === "memory" ? setInterval(
|
|
1513
|
+
() => {
|
|
1514
|
+
const now = Date.now();
|
|
1515
|
+
for (const [key, entry] of hits) {
|
|
1516
|
+
if (entry.reset < now) hits.delete(key);
|
|
1517
|
+
}
|
|
1518
|
+
if (hits.size > MAX_ENTRIES2) {
|
|
1519
|
+
const toDelete = hits.size - MAX_ENTRIES2;
|
|
1520
|
+
let deleted = 0;
|
|
1521
|
+
for (const key of hits.keys()) {
|
|
1522
|
+
if (deleted >= toDelete) break;
|
|
1523
|
+
hits.delete(key);
|
|
1524
|
+
deleted++;
|
|
1525
|
+
}
|
|
1448
1526
|
}
|
|
1449
|
-
}
|
|
1450
|
-
|
|
1527
|
+
},
|
|
1528
|
+
Math.min(window2, 3e4)
|
|
1529
|
+
) : null;
|
|
1451
1530
|
if (interval?.unref) interval.unref();
|
|
1452
1531
|
async function checkAndIncrement(key) {
|
|
1453
1532
|
const now = Date.now();
|
|
@@ -1461,7 +1540,7 @@ function rateLimit(options) {
|
|
|
1461
1540
|
const reset = pttl > 0 ? now + pttl : now + window2;
|
|
1462
1541
|
return { count, reset };
|
|
1463
1542
|
}
|
|
1464
|
-
|
|
1543
|
+
const entry = hits.get(key);
|
|
1465
1544
|
if (!entry || entry.reset < now) {
|
|
1466
1545
|
hits.set(key, { count: 1, reset: now + window2 });
|
|
1467
1546
|
return { count: 1, reset: now + window2 };
|
|
@@ -1492,7 +1571,6 @@ function rateLimit(options) {
|
|
|
1492
1571
|
if (interval) clearInterval(interval);
|
|
1493
1572
|
hits.clear();
|
|
1494
1573
|
};
|
|
1495
|
-
mw.stop = mw.close;
|
|
1496
1574
|
mw.stats = () => ({
|
|
1497
1575
|
store: storeType,
|
|
1498
1576
|
entries: storeType === "memory" ? hits.size : void 0,
|
|
@@ -1536,7 +1614,9 @@ function compress(options) {
|
|
|
1536
1614
|
let compressed;
|
|
1537
1615
|
try {
|
|
1538
1616
|
if (encoding === "br") {
|
|
1539
|
-
compressed = await brotliCompressAsync(body, {
|
|
1617
|
+
compressed = await brotliCompressAsync(body, {
|
|
1618
|
+
params: { [constants.BROTLI_PARAM_QUALITY]: Math.min(level, 11) }
|
|
1619
|
+
});
|
|
1540
1620
|
} else if (encoding === "gzip") {
|
|
1541
1621
|
compressed = await gzipAsync(body, { level: Math.min(level, 9) });
|
|
1542
1622
|
} else {
|
|
@@ -1650,9 +1730,7 @@ function createSSEStream(iterable, opts) {
|
|
|
1650
1730
|
}
|
|
1651
1731
|
} catch (e) {
|
|
1652
1732
|
if (e.name !== "AbortError") {
|
|
1653
|
-
controller.enqueue(
|
|
1654
|
-
encoder.encode(formatSSE("error", { error: e.message }))
|
|
1655
|
-
);
|
|
1733
|
+
controller.enqueue(encoder.encode(formatSSE("error", { error: e.message })));
|
|
1656
1734
|
}
|
|
1657
1735
|
} finally {
|
|
1658
1736
|
controller.close();
|
|
@@ -1777,26 +1855,31 @@ var TestApp = class {
|
|
|
1777
1855
|
}
|
|
1778
1856
|
/** Register a GET route — supports route-level middleware via spread args. */
|
|
1779
1857
|
get(path2, ...args) {
|
|
1858
|
+
;
|
|
1780
1859
|
this.router.get(path2, ...args);
|
|
1781
1860
|
return this;
|
|
1782
1861
|
}
|
|
1783
1862
|
/** Register a POST route. */
|
|
1784
1863
|
post(path2, ...args) {
|
|
1864
|
+
;
|
|
1785
1865
|
this.router.post(path2, ...args);
|
|
1786
1866
|
return this;
|
|
1787
1867
|
}
|
|
1788
1868
|
/** Register a PUT route. */
|
|
1789
1869
|
put(path2, ...args) {
|
|
1870
|
+
;
|
|
1790
1871
|
this.router.put(path2, ...args);
|
|
1791
1872
|
return this;
|
|
1792
1873
|
}
|
|
1793
1874
|
/** Register a PATCH route. */
|
|
1794
1875
|
patch(path2, ...args) {
|
|
1876
|
+
;
|
|
1795
1877
|
this.router.patch(path2, ...args);
|
|
1796
1878
|
return this;
|
|
1797
1879
|
}
|
|
1798
1880
|
/** Register a DELETE route. */
|
|
1799
1881
|
delete(path2, ...args) {
|
|
1882
|
+
;
|
|
1800
1883
|
this.router.delete(path2, ...args);
|
|
1801
1884
|
return this;
|
|
1802
1885
|
}
|
|
@@ -1879,7 +1962,12 @@ async function withTestDb(optionsOrFn, fn) {
|
|
|
1879
1962
|
}
|
|
1880
1963
|
|
|
1881
1964
|
// graphql.ts
|
|
1882
|
-
import {
|
|
1965
|
+
import {
|
|
1966
|
+
buildSchema,
|
|
1967
|
+
graphql as executeGraphQL,
|
|
1968
|
+
validate as validateQuery,
|
|
1969
|
+
parse
|
|
1970
|
+
} from "graphql";
|
|
1883
1971
|
import { makeExecutableSchema } from "@graphql-tools/schema";
|
|
1884
1972
|
function parseParamsFromGet(url) {
|
|
1885
1973
|
const query = url.searchParams.get("query");
|
|
@@ -1940,11 +2028,17 @@ async function executeQuery(schema, params, options, req, ctx) {
|
|
|
1940
2028
|
const doc = parse(params.query);
|
|
1941
2029
|
const depth = queryDepth(doc);
|
|
1942
2030
|
if (depth > maxDepth) {
|
|
1943
|
-
return Response.json(
|
|
2031
|
+
return Response.json(
|
|
2032
|
+
{ errors: [{ message: `Query depth ${depth} exceeds limit ${maxDepth}` }] },
|
|
2033
|
+
{ status: 400 }
|
|
2034
|
+
);
|
|
1944
2035
|
}
|
|
1945
2036
|
const validationErrors = validateQuery(schema, doc);
|
|
1946
2037
|
if (validationErrors.length > 0) {
|
|
1947
|
-
return Response.json(
|
|
2038
|
+
return Response.json(
|
|
2039
|
+
{ errors: validationErrors.map((e) => ({ message: e.message })) },
|
|
2040
|
+
{ status: 400 }
|
|
2041
|
+
);
|
|
1948
2042
|
}
|
|
1949
2043
|
} catch (err) {
|
|
1950
2044
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -2125,7 +2219,10 @@ function resolveRef(path2, ctx) {
|
|
|
2125
2219
|
const propPath = after.slice(dot + 1);
|
|
2126
2220
|
const output = ctx.nodeOutputs.get(id2);
|
|
2127
2221
|
if (output === void 0) throw new Error(`Node "${id2}" has no output yet`);
|
|
2128
|
-
return getByPath(
|
|
2222
|
+
return getByPath(
|
|
2223
|
+
output,
|
|
2224
|
+
propPath.startsWith("output") ? propPath.slice(7).split(".").filter(Boolean) : propPath.split(".")
|
|
2225
|
+
);
|
|
2129
2226
|
}
|
|
2130
2227
|
if (path2.startsWith("$var.")) {
|
|
2131
2228
|
const name = path2.slice(5);
|
|
@@ -2145,7 +2242,8 @@ function resolveValue(v, ctx) {
|
|
|
2145
2242
|
if (Array.isArray(v)) return v.map((item) => resolveValue(item, ctx));
|
|
2146
2243
|
if (typeof v === "object" && v !== null) {
|
|
2147
2244
|
const result = {};
|
|
2148
|
-
for (const [k, val] of Object.entries(v))
|
|
2245
|
+
for (const [k, val] of Object.entries(v))
|
|
2246
|
+
result[k] = resolveValue(val, ctx);
|
|
2149
2247
|
return result;
|
|
2150
2248
|
}
|
|
2151
2249
|
return v;
|
|
@@ -2241,7 +2339,7 @@ async function executeNode(node, ctx) {
|
|
|
2241
2339
|
iters++;
|
|
2242
2340
|
ctx.stepCount++;
|
|
2243
2341
|
if (ctx.stepCount > ctx.maxSteps) throw new Error(`Step limit exceeded`);
|
|
2244
|
-
if (!
|
|
2342
|
+
if (!evaluateExpression(conditionExpr, ctx)) break;
|
|
2245
2343
|
for (const n of body ?? []) {
|
|
2246
2344
|
last = await executeNode(n, ctx);
|
|
2247
2345
|
ctx.nodeOutputs.set(n.id, last);
|
|
@@ -2273,7 +2371,10 @@ async function executeNode(node, ctx) {
|
|
|
2273
2371
|
signal: controller.signal
|
|
2274
2372
|
});
|
|
2275
2373
|
const ct = res.headers.get("content-type") ?? "";
|
|
2276
|
-
return {
|
|
2374
|
+
return {
|
|
2375
|
+
status: res.status,
|
|
2376
|
+
body: ct.includes("json") ? await res.json() : await res.text()
|
|
2377
|
+
};
|
|
2277
2378
|
} finally {
|
|
2278
2379
|
clearTimeout(timer);
|
|
2279
2380
|
}
|
|
@@ -2293,20 +2394,25 @@ function runWorkflow(opts = {}) {
|
|
|
2293
2394
|
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
2395
|
inputSchema: z.object({
|
|
2295
2396
|
goal: z.string().describe("What the workflow should accomplish"),
|
|
2296
|
-
nodes: z.array(
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2397
|
+
nodes: z.array(
|
|
2398
|
+
z.object({
|
|
2399
|
+
id: z.string(),
|
|
2400
|
+
tool: z.string(),
|
|
2401
|
+
input: z.record(z.string(), z.unknown()).optional(),
|
|
2402
|
+
conditions: z.array(z.object({ test: z.any(), body: z.any() })).optional(),
|
|
2403
|
+
body: z.array(z.any()).optional()
|
|
2404
|
+
})
|
|
2405
|
+
).optional().describe("Workflow nodes. Skip this and provide model for LLM to generate from goal.")
|
|
2303
2406
|
}),
|
|
2304
2407
|
execute: async (input) => {
|
|
2305
2408
|
let nodes;
|
|
2306
2409
|
if (input.nodes && input.nodes.length > 0) {
|
|
2307
2410
|
nodes = input.nodes;
|
|
2308
2411
|
} else {
|
|
2309
|
-
if (!opts.provider && !opts.model)
|
|
2412
|
+
if (!opts.provider && !opts.model)
|
|
2413
|
+
throw new Error(
|
|
2414
|
+
'Provide either "nodes", a "model", or a "provider" with a model to generate the workflow from "goal"'
|
|
2415
|
+
);
|
|
2310
2416
|
const toolsDesc = Object.entries(opts.tools ?? {}).map(([k, t]) => `- ${k}: ${t.description}`).join("\n");
|
|
2311
2417
|
const system = [
|
|
2312
2418
|
"You are a workflow generator. Given a user goal and available tools, output a workflow JSON.",
|
|
@@ -2318,7 +2424,10 @@ function runWorkflow(opts = {}) {
|
|
|
2318
2424
|
"Reference syntax: $var.name, $nodes.id.output, $nodes.id.output.field, $input.field",
|
|
2319
2425
|
"Output ONLY valid JSON. No explanation, no markdown."
|
|
2320
2426
|
].filter(Boolean).join("\n");
|
|
2321
|
-
const genParams = {
|
|
2427
|
+
const genParams = {
|
|
2428
|
+
system,
|
|
2429
|
+
messages: [{ role: "user", content: input.goal }]
|
|
2430
|
+
};
|
|
2322
2431
|
const result = opts.provider ? await opts.provider.generateText(genParams) : await generateText({ ...genParams, model: opts.model });
|
|
2323
2432
|
const text2 = result.text.trim();
|
|
2324
2433
|
const jsonStart = text2.indexOf("{");
|
|
@@ -2411,10 +2520,7 @@ import {
|
|
|
2411
2520
|
embedMany,
|
|
2412
2521
|
smoothStream
|
|
2413
2522
|
} from "ai";
|
|
2414
|
-
import {
|
|
2415
|
-
openai,
|
|
2416
|
-
createOpenAI as createOpenAI2
|
|
2417
|
-
} from "@ai-sdk/openai";
|
|
2523
|
+
import { openai, createOpenAI as createOpenAI2 } from "@ai-sdk/openai";
|
|
2418
2524
|
|
|
2419
2525
|
// postgres/client.ts
|
|
2420
2526
|
import postgresFactory from "postgres";
|
|
@@ -2657,7 +2763,10 @@ var Table = class {
|
|
|
2657
2763
|
const using = opts?.type ? `USING ${opts.type.toUpperCase()}` : "";
|
|
2658
2764
|
const colList = cols.map((c) => opts?.desc ? `"${c}" DESC` : `"${c}"`).join(", ");
|
|
2659
2765
|
const operator = opts?.operator ? ` ${opts.operator}` : "";
|
|
2660
|
-
const ddl = `CREATE ${unique} INDEX IF NOT EXISTS ${name} ON "${this.tableName}" ${using} (${colList}${operator})`.replace(
|
|
2766
|
+
const ddl = `CREATE ${unique} INDEX IF NOT EXISTS ${name} ON "${this.tableName}" ${using} (${colList}${operator})`.replace(
|
|
2767
|
+
/\s+/g,
|
|
2768
|
+
" "
|
|
2769
|
+
);
|
|
2661
2770
|
await sql2.unsafe(ddl);
|
|
2662
2771
|
}
|
|
2663
2772
|
async createUniqueIndex(sql2, columns) {
|
|
@@ -2761,7 +2870,10 @@ var Table = class {
|
|
|
2761
2870
|
const softDel = this._softDeleteFilter(where, opts);
|
|
2762
2871
|
if (softDel) conditions.push(softDel);
|
|
2763
2872
|
const whereClause = conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "";
|
|
2764
|
-
const [countRow] = await sql2.unsafe(
|
|
2873
|
+
const [countRow] = await sql2.unsafe(
|
|
2874
|
+
`SELECT COUNT(*) AS _total FROM "${this.tableName}"${whereClause}`,
|
|
2875
|
+
values
|
|
2876
|
+
);
|
|
2765
2877
|
const count = Number(countRow._total);
|
|
2766
2878
|
if (conditions.length === 0 && !opts?.orderBy && !opts?.limit && !opts?.offset && !opts?.select) {
|
|
2767
2879
|
const rows2 = await sql2`SELECT * FROM ${sql2(this.tableName)}`;
|
|
@@ -2794,7 +2906,10 @@ var Table = class {
|
|
|
2794
2906
|
async updateMany(sql2, where, data) {
|
|
2795
2907
|
const { sets, values: setValues } = this._buildSET(data);
|
|
2796
2908
|
if (sets.length === 0) return 0;
|
|
2797
|
-
const { conditions: wConditions, values: wValues } = this._buildConditions(
|
|
2909
|
+
const { conditions: wConditions, values: wValues } = this._buildConditions(
|
|
2910
|
+
where,
|
|
2911
|
+
setValues.length
|
|
2912
|
+
);
|
|
2798
2913
|
if (wConditions.length === 0) return 0;
|
|
2799
2914
|
const rows = await sql2.unsafe(
|
|
2800
2915
|
`UPDATE "${this.tableName}" SET ${sets.join(", ")} WHERE ${wConditions.join(" AND ")} RETURNING 1`,
|
|
@@ -2883,13 +2998,20 @@ var Table = class {
|
|
|
2883
2998
|
const softDel = this._softDeleteFilter(where);
|
|
2884
2999
|
if (softDel) conditions.push(softDel);
|
|
2885
3000
|
const whereClause = conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "";
|
|
2886
|
-
const [row] = await sql2.unsafe(
|
|
3001
|
+
const [row] = await sql2.unsafe(
|
|
3002
|
+
`SELECT COUNT(*) AS _total FROM "${this.tableName}"${whereClause}`,
|
|
3003
|
+
values
|
|
3004
|
+
);
|
|
2887
3005
|
return Number(row._total);
|
|
2888
3006
|
}
|
|
2889
3007
|
};
|
|
2890
3008
|
var BoundTable = class _BoundTable {
|
|
2891
3009
|
inner;
|
|
2892
3010
|
sql;
|
|
3011
|
+
/** The underlying table name. */
|
|
3012
|
+
get tableName() {
|
|
3013
|
+
return this.inner.tableName;
|
|
3014
|
+
}
|
|
2893
3015
|
constructor(sql2, tableName, builders) {
|
|
2894
3016
|
this.inner = new Table(tableName, builders);
|
|
2895
3017
|
this.sql = sql2;
|
|
@@ -2977,13 +3099,17 @@ function postgres(opts) {
|
|
|
2977
3099
|
connect_timeout: options.connect_timeout
|
|
2978
3100
|
});
|
|
2979
3101
|
if (options.signal) {
|
|
2980
|
-
options.signal.addEventListener(
|
|
2981
|
-
|
|
2982
|
-
|
|
3102
|
+
options.signal.addEventListener(
|
|
3103
|
+
"abort",
|
|
3104
|
+
() => {
|
|
3105
|
+
sql2.end();
|
|
3106
|
+
},
|
|
3107
|
+
{ once: true }
|
|
3108
|
+
);
|
|
2983
3109
|
}
|
|
2984
3110
|
const closeTimeout = options.closeTimeout ?? 5;
|
|
2985
|
-
|
|
2986
|
-
|
|
3111
|
+
const _active = 0;
|
|
3112
|
+
const _waiting = 0;
|
|
2987
3113
|
const poolMax = options.max ?? 10;
|
|
2988
3114
|
const mw = ((req, ctx, next) => {
|
|
2989
3115
|
ctx.sql = sql2;
|
|
@@ -3011,10 +3137,9 @@ function postgres(opts) {
|
|
|
3011
3137
|
);
|
|
3012
3138
|
};
|
|
3013
3139
|
mw.isMigrated = async (moduleName) => {
|
|
3014
|
-
const [row] = await sql2.unsafe(
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
);
|
|
3140
|
+
const [row] = await sql2.unsafe(`SELECT 1 FROM "${MIGRATIONS_TABLE}" WHERE name = $1`, [
|
|
3141
|
+
moduleName
|
|
3142
|
+
]);
|
|
3018
3143
|
return !!row;
|
|
3019
3144
|
};
|
|
3020
3145
|
mw.transaction = (async (fn, retryOpts) => {
|
|
@@ -3146,10 +3271,9 @@ function createOAuth2Server(deps) {
|
|
|
3146
3271
|
return null;
|
|
3147
3272
|
}
|
|
3148
3273
|
function consentPage(client, params) {
|
|
3149
|
-
const fields = Object.entries(params).map(
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
return new Response(`<!DOCTYPE html>
|
|
3274
|
+
const fields = Object.entries(params).map(([k, v]) => `<input type="hidden" name="${k}" value="${v.replace(/"/g, """)}">`).join("\n ");
|
|
3275
|
+
return new Response(
|
|
3276
|
+
`<!DOCTYPE html>
|
|
3153
3277
|
<html lang="en">
|
|
3154
3278
|
<head><meta charset="utf-8"><title>Authorize</title>
|
|
3155
3279
|
<style>
|
|
@@ -3176,17 +3300,22 @@ function createOAuth2Server(deps) {
|
|
|
3176
3300
|
</form>
|
|
3177
3301
|
</div>
|
|
3178
3302
|
</body>
|
|
3179
|
-
</html>`,
|
|
3303
|
+
</html>`,
|
|
3304
|
+
{ headers: { "Content-Type": "text/html; charset=utf-8" } }
|
|
3305
|
+
);
|
|
3180
3306
|
}
|
|
3181
3307
|
function errorPage2(error, description) {
|
|
3182
|
-
return new Response(
|
|
3308
|
+
return new Response(
|
|
3309
|
+
`<!DOCTYPE html>
|
|
3183
3310
|
<html lang="en">
|
|
3184
3311
|
<head><meta charset="utf-8"><title>Error</title>
|
|
3185
3312
|
<style>body{font-family:sans-serif;max-width:480px;margin:80px auto;padding:0 20px}
|
|
3186
3313
|
h2{color:#dc2626}.desc{color:#555}</style>
|
|
3187
3314
|
</head>
|
|
3188
3315
|
<body><h2>${error}</h2>${description ? `<p class="desc">${description}</p>` : ""}</body>
|
|
3189
|
-
</html>`,
|
|
3316
|
+
</html>`,
|
|
3317
|
+
{ status: 400, headers: { "Content-Type": "text/html; charset=utf-8" } }
|
|
3318
|
+
);
|
|
3190
3319
|
}
|
|
3191
3320
|
async function authorizeHandler(req, _ctx) {
|
|
3192
3321
|
const url = new URL(req.url);
|
|
@@ -3205,7 +3334,10 @@ h2{color:#dc2626}.desc{color:#555}</style>
|
|
|
3205
3334
|
return errorPage2("Invalid client_id", "No client found with the given client_id.");
|
|
3206
3335
|
}
|
|
3207
3336
|
if (!client.redirectUris.includes(redirectUri)) {
|
|
3208
|
-
return errorPage2(
|
|
3337
|
+
return errorPage2(
|
|
3338
|
+
"Invalid redirect_uri",
|
|
3339
|
+
"The redirect_uri is not registered for this client."
|
|
3340
|
+
);
|
|
3209
3341
|
}
|
|
3210
3342
|
const user2 = extractUser(req);
|
|
3211
3343
|
if (!user2) {
|
|
@@ -3291,14 +3423,23 @@ h2{color:#dc2626}.desc{color:#555}</style>
|
|
|
3291
3423
|
return Response.json({ error: "invalid_grant" }, { status: 400 });
|
|
3292
3424
|
}
|
|
3293
3425
|
if (new Date(stored.expires_at) < /* @__PURE__ */ new Date()) {
|
|
3294
|
-
return Response.json(
|
|
3426
|
+
return Response.json(
|
|
3427
|
+
{ error: "invalid_grant", error_description: "Code expired" },
|
|
3428
|
+
{ status: 400 }
|
|
3429
|
+
);
|
|
3295
3430
|
}
|
|
3296
3431
|
if (stored.redirect_uri !== redirectUri) {
|
|
3297
|
-
return Response.json(
|
|
3432
|
+
return Response.json(
|
|
3433
|
+
{ error: "invalid_grant", error_description: "redirect_uri mismatch" },
|
|
3434
|
+
{ status: 400 }
|
|
3435
|
+
);
|
|
3298
3436
|
}
|
|
3299
3437
|
if (stored.code_challenge) {
|
|
3300
3438
|
if (!codeVerifier) {
|
|
3301
|
-
return Response.json(
|
|
3439
|
+
return Response.json(
|
|
3440
|
+
{ error: "invalid_grant", error_description: "code_verifier required" },
|
|
3441
|
+
{ status: 400 }
|
|
3442
|
+
);
|
|
3302
3443
|
}
|
|
3303
3444
|
let expected;
|
|
3304
3445
|
if (stored.code_challenge_method === "plain") {
|
|
@@ -3307,7 +3448,10 @@ h2{color:#dc2626}.desc{color:#555}</style>
|
|
|
3307
3448
|
expected = crypto4.createHash("sha256").update(codeVerifier).digest().toString("base64url");
|
|
3308
3449
|
}
|
|
3309
3450
|
if (expected !== stored.code_challenge) {
|
|
3310
|
-
return Response.json(
|
|
3451
|
+
return Response.json(
|
|
3452
|
+
{ error: "invalid_grant", error_description: "code_verifier mismatch" },
|
|
3453
|
+
{ status: 400 }
|
|
3454
|
+
);
|
|
3311
3455
|
}
|
|
3312
3456
|
}
|
|
3313
3457
|
await pg.sql`UPDATE "_oauth2_codes" SET "used" = TRUE WHERE "id" = ${stored.id}`;
|
|
@@ -3512,7 +3656,7 @@ function registerOAuthLoginRoutes(router, deps, providers) {
|
|
|
3512
3656
|
try {
|
|
3513
3657
|
tokenRes = await fetch(meta.tokenUrl, {
|
|
3514
3658
|
method: "POST",
|
|
3515
|
-
headers: { "Content-Type": "application/json",
|
|
3659
|
+
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
|
3516
3660
|
body: JSON.stringify({
|
|
3517
3661
|
code,
|
|
3518
3662
|
client_id: config.clientId,
|
|
@@ -3522,7 +3666,10 @@ function registerOAuthLoginRoutes(router, deps, providers) {
|
|
|
3522
3666
|
})
|
|
3523
3667
|
});
|
|
3524
3668
|
} catch (err) {
|
|
3525
|
-
console.error(
|
|
3669
|
+
console.error(
|
|
3670
|
+
`[oauth] token exchange network error for ${providerName}:`,
|
|
3671
|
+
err.message
|
|
3672
|
+
);
|
|
3526
3673
|
return Response.json({ error: "Failed to connect to OAuth provider" }, { status: 502 });
|
|
3527
3674
|
}
|
|
3528
3675
|
if (!tokenRes.ok) {
|
|
@@ -3539,7 +3686,10 @@ function registerOAuthLoginRoutes(router, deps, providers) {
|
|
|
3539
3686
|
try {
|
|
3540
3687
|
userRes = await fetch(meta.userUrl, { headers: { Authorization: "Bearer " + accessToken } });
|
|
3541
3688
|
} catch (err) {
|
|
3542
|
-
console.error(
|
|
3689
|
+
console.error(
|
|
3690
|
+
"[oauth] user info network error for " + providerName + ":",
|
|
3691
|
+
err.message
|
|
3692
|
+
);
|
|
3543
3693
|
return Response.json({ error: "Failed to connect to OAuth provider" }, { status: 502 });
|
|
3544
3694
|
}
|
|
3545
3695
|
if (!userRes.ok) {
|
|
@@ -3707,11 +3857,9 @@ function user(options) {
|
|
|
3707
3857
|
await tokens.create();
|
|
3708
3858
|
}
|
|
3709
3859
|
function signToken(user2) {
|
|
3710
|
-
return jwt2.sign(
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
{ expiresIn }
|
|
3714
|
-
);
|
|
3860
|
+
return jwt2.sign({ sub: user2.id, email: user2.email, role: user2.role }, secret, {
|
|
3861
|
+
expiresIn
|
|
3862
|
+
});
|
|
3715
3863
|
}
|
|
3716
3864
|
function stripPassword(row) {
|
|
3717
3865
|
const { password: _, ...user2 } = row;
|
|
@@ -3879,6 +4027,7 @@ function user(options) {
|
|
|
3879
4027
|
return async (req, ctx, next) => {
|
|
3880
4028
|
const userData = await resolveUser(req, ctx);
|
|
3881
4029
|
if (userData) {
|
|
4030
|
+
;
|
|
3882
4031
|
ctx.user = userData;
|
|
3883
4032
|
}
|
|
3884
4033
|
return next(req, ctx);
|
|
@@ -3940,18 +4089,22 @@ function user(options) {
|
|
|
3940
4089
|
r.post("/oauth/token", (req) => oauth2.tokenHandler(req));
|
|
3941
4090
|
}
|
|
3942
4091
|
if (hasDb && options.oauthLogin) {
|
|
3943
|
-
registerOAuthLoginRoutes(
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
4092
|
+
registerOAuthLoginRoutes(
|
|
4093
|
+
r,
|
|
4094
|
+
{
|
|
4095
|
+
sql: _pg.sql,
|
|
4096
|
+
jwtSecret: secret,
|
|
4097
|
+
expiresIn,
|
|
4098
|
+
usersTable: table,
|
|
4099
|
+
providerTable: "_auth_providers",
|
|
4100
|
+
redirectUrl: options.oauthLogin.redirectUrl || "/",
|
|
4101
|
+
signToken,
|
|
4102
|
+
createPlaceholderUser,
|
|
4103
|
+
findUserById: findById,
|
|
4104
|
+
findUserByEmail: findByEmail
|
|
4105
|
+
},
|
|
4106
|
+
options.oauthLogin.providers
|
|
4107
|
+
);
|
|
3955
4108
|
}
|
|
3956
4109
|
const mod = r;
|
|
3957
4110
|
mod.middleware = middleware;
|
|
@@ -4048,9 +4201,7 @@ var FIELD_RANGES = [
|
|
|
4048
4201
|
function parsePattern(pattern) {
|
|
4049
4202
|
const fields = pattern.trim().split(/\s+/);
|
|
4050
4203
|
if (fields.length !== 5) {
|
|
4051
|
-
throw new Error(
|
|
4052
|
-
`Invalid cron pattern "${pattern}": expected 5 fields, got ${fields.length}`
|
|
4053
|
-
);
|
|
4204
|
+
throw new Error(`Invalid cron pattern "${pattern}": expected 5 fields, got ${fields.length}`);
|
|
4054
4205
|
}
|
|
4055
4206
|
return fields.map((f, i) => parseField(f, FIELD_RANGES[i][0], FIELD_RANGES[i][1]));
|
|
4056
4207
|
}
|
|
@@ -4059,7 +4210,7 @@ function matches(fields, date) {
|
|
|
4059
4210
|
}
|
|
4060
4211
|
function cronNext(expr, from = /* @__PURE__ */ new Date()) {
|
|
4061
4212
|
const fields = parsePattern(expr);
|
|
4062
|
-
|
|
4213
|
+
const candidate = new Date(from.getTime() + 6e4);
|
|
4063
4214
|
candidate.setSeconds(0, 0);
|
|
4064
4215
|
for (let i = 0; i < 525600; i++) {
|
|
4065
4216
|
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 +4273,12 @@ function createMemoryQueue(opts) {
|
|
|
4122
4273
|
}
|
|
4123
4274
|
if (job.schedule) {
|
|
4124
4275
|
try {
|
|
4125
|
-
insertJob({
|
|
4276
|
+
insertJob({
|
|
4277
|
+
...job,
|
|
4278
|
+
id: crypto6.randomUUID(),
|
|
4279
|
+
runAt: cronNext(job.schedule),
|
|
4280
|
+
createdAt: Date.now()
|
|
4281
|
+
});
|
|
4126
4282
|
} catch (e) {
|
|
4127
4283
|
console.error("[queue] cron re-queue failed:", e.message);
|
|
4128
4284
|
}
|
|
@@ -4210,7 +4366,14 @@ function createMemoryQueue(opts) {
|
|
|
4210
4366
|
mw.dashboard = function dashboard() {
|
|
4211
4367
|
return buildDashboard(q);
|
|
4212
4368
|
};
|
|
4213
|
-
mw.stats = () => ({
|
|
4369
|
+
mw.stats = () => ({
|
|
4370
|
+
running,
|
|
4371
|
+
inflight,
|
|
4372
|
+
processed: _processed,
|
|
4373
|
+
failed: _failed,
|
|
4374
|
+
handlers: handlers.size,
|
|
4375
|
+
maxConcurrent: MAX_CONCURRENT
|
|
4376
|
+
});
|
|
4214
4377
|
attachCron(q, handlers);
|
|
4215
4378
|
return q;
|
|
4216
4379
|
}
|
|
@@ -4225,8 +4388,12 @@ function createPgQueue(opts) {
|
|
|
4225
4388
|
const MAX_FAILED = 1e3;
|
|
4226
4389
|
async function ensureTable() {
|
|
4227
4390
|
if (ready) return;
|
|
4228
|
-
await sql2.unsafe(
|
|
4229
|
-
|
|
4391
|
+
await sql2.unsafe(
|
|
4392
|
+
`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())`
|
|
4393
|
+
);
|
|
4394
|
+
await sql2.unsafe(
|
|
4395
|
+
`CREATE INDEX IF NOT EXISTS ${escapeIdent3(table + "_run_at_idx")} ON ${escapeIdent3(table)} (run_at, status)`
|
|
4396
|
+
);
|
|
4230
4397
|
ready = true;
|
|
4231
4398
|
}
|
|
4232
4399
|
async function processJob(job, handler) {
|
|
@@ -4239,14 +4406,26 @@ function createPgQueue(opts) {
|
|
|
4239
4406
|
_failed++;
|
|
4240
4407
|
const msg = e.message;
|
|
4241
4408
|
console.error("[queue] handler error:", msg);
|
|
4242
|
-
await sql2.unsafe(
|
|
4409
|
+
await sql2.unsafe(
|
|
4410
|
+
`UPDATE ${escapeIdent3(table)} SET status = 'failed', error = $2, failed_at = NOW() WHERE id = $1`,
|
|
4411
|
+
[job.id, msg]
|
|
4412
|
+
);
|
|
4243
4413
|
} finally {
|
|
4244
4414
|
inflight--;
|
|
4245
4415
|
}
|
|
4246
4416
|
if (job.schedule) {
|
|
4247
4417
|
try {
|
|
4248
4418
|
const nextRun = cronNext(job.schedule);
|
|
4249
|
-
await sql2.unsafe(
|
|
4419
|
+
await sql2.unsafe(
|
|
4420
|
+
`INSERT INTO ${escapeIdent3(table)} (id, type, payload, run_at, schedule) VALUES ($1, $2, $3::jsonb, $4, $5)`,
|
|
4421
|
+
[
|
|
4422
|
+
crypto6.randomUUID(),
|
|
4423
|
+
job.type,
|
|
4424
|
+
JSON.stringify(job.payload),
|
|
4425
|
+
new Date(nextRun).toISOString(),
|
|
4426
|
+
job.schedule
|
|
4427
|
+
]
|
|
4428
|
+
);
|
|
4250
4429
|
} catch (e) {
|
|
4251
4430
|
console.error("[queue] cron re-queue failed:", e.message);
|
|
4252
4431
|
}
|
|
@@ -4256,10 +4435,20 @@ function createPgQueue(opts) {
|
|
|
4256
4435
|
if (!running) return;
|
|
4257
4436
|
try {
|
|
4258
4437
|
while (running && inflight < MAX_CONCURRENT) {
|
|
4259
|
-
const rows = await sql2.unsafe(
|
|
4438
|
+
const rows = await sql2.unsafe(
|
|
4439
|
+
`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 *`
|
|
4440
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4441
|
+
);
|
|
4260
4442
|
if (rows.length === 0) break;
|
|
4261
4443
|
const row = rows[0];
|
|
4262
|
-
const job = {
|
|
4444
|
+
const job = {
|
|
4445
|
+
id: row.id,
|
|
4446
|
+
type: row.type,
|
|
4447
|
+
payload: typeof row.payload === "string" ? JSON.parse(row.payload) : row.payload,
|
|
4448
|
+
createdAt: new Date(row.created_at).getTime(),
|
|
4449
|
+
runAt: new Date(row.run_at).getTime(),
|
|
4450
|
+
schedule: row.schedule || void 0
|
|
4451
|
+
};
|
|
4263
4452
|
const handler = handlers.get(job.type);
|
|
4264
4453
|
if (handler) processJob(job, handler);
|
|
4265
4454
|
}
|
|
@@ -4294,7 +4483,10 @@ function createPgQueue(opts) {
|
|
|
4294
4483
|
} else {
|
|
4295
4484
|
runAt = /* @__PURE__ */ new Date();
|
|
4296
4485
|
}
|
|
4297
|
-
await sql2.unsafe(
|
|
4486
|
+
await sql2.unsafe(
|
|
4487
|
+
`INSERT INTO ${escapeIdent3(table)} (id, type, payload, run_at, schedule) VALUES ($1, $2, $3::jsonb, $4, $5)`,
|
|
4488
|
+
[id2, type, JSON.stringify(payload), runAt.toISOString(), opts2?.schedule || null]
|
|
4489
|
+
);
|
|
4298
4490
|
return id2;
|
|
4299
4491
|
})();
|
|
4300
4492
|
};
|
|
@@ -4320,25 +4512,64 @@ function createPgQueue(opts) {
|
|
|
4320
4512
|
while (inflight > 0) await new Promise((r) => setTimeout(r, 50));
|
|
4321
4513
|
};
|
|
4322
4514
|
mw.jobs = async function jobs(limit) {
|
|
4323
|
-
const rows = await sql2.unsafe(
|
|
4324
|
-
|
|
4515
|
+
const rows = await sql2.unsafe(
|
|
4516
|
+
`SELECT * FROM ${escapeIdent3(table)} WHERE status = 'pending' ORDER BY run_at LIMIT $1`,
|
|
4517
|
+
[limit ?? 50]
|
|
4518
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4519
|
+
);
|
|
4520
|
+
return rows.map((r) => ({
|
|
4521
|
+
id: r.id,
|
|
4522
|
+
type: r.type,
|
|
4523
|
+
payload: typeof r.payload === "string" ? JSON.parse(r.payload) : r.payload,
|
|
4524
|
+
createdAt: new Date(r.created_at).getTime(),
|
|
4525
|
+
runAt: new Date(r.run_at).getTime(),
|
|
4526
|
+
schedule: r.schedule || void 0
|
|
4527
|
+
}));
|
|
4325
4528
|
};
|
|
4326
4529
|
mw.failedJobs = async function failedJobs(limit) {
|
|
4327
|
-
const rows = await sql2.unsafe(
|
|
4328
|
-
|
|
4530
|
+
const rows = await sql2.unsafe(
|
|
4531
|
+
`SELECT * FROM ${escapeIdent3(table)} WHERE status = 'failed' ORDER BY failed_at DESC LIMIT $1`,
|
|
4532
|
+
[limit ?? 50]
|
|
4533
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4534
|
+
);
|
|
4535
|
+
return rows.map((r) => ({
|
|
4536
|
+
id: r.id,
|
|
4537
|
+
type: r.type,
|
|
4538
|
+
payload: typeof r.payload === "string" ? JSON.parse(r.payload) : r.payload,
|
|
4539
|
+
createdAt: new Date(r.created_at).getTime(),
|
|
4540
|
+
runAt: new Date(r.run_at).getTime(),
|
|
4541
|
+
schedule: r.schedule || void 0,
|
|
4542
|
+
error: r.error || "",
|
|
4543
|
+
failedAt: new Date(r.failed_at).getTime()
|
|
4544
|
+
}));
|
|
4329
4545
|
};
|
|
4330
4546
|
mw.retryFailed = async function retryFailed(jobId) {
|
|
4331
|
-
const result = await sql2.unsafe(
|
|
4547
|
+
const result = await sql2.unsafe(
|
|
4548
|
+
`UPDATE ${escapeIdent3(table)} SET status = 'pending', error = NULL, failed_at = NULL, run_at = NOW() WHERE id = $1 AND status = 'failed' RETURNING id`,
|
|
4549
|
+
[jobId]
|
|
4550
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4551
|
+
);
|
|
4332
4552
|
return result.length > 0;
|
|
4333
4553
|
};
|
|
4334
4554
|
mw.retryAllFailed = async function retryAllFailed(type) {
|
|
4335
|
-
const result = await sql2.unsafe(
|
|
4555
|
+
const result = await sql2.unsafe(
|
|
4556
|
+
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`,
|
|
4557
|
+
type ? [type] : []
|
|
4558
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4559
|
+
);
|
|
4336
4560
|
return result.length;
|
|
4337
4561
|
};
|
|
4338
4562
|
mw.dashboard = function dashboard() {
|
|
4339
4563
|
return buildDashboard(q);
|
|
4340
4564
|
};
|
|
4341
|
-
mw.stats = () => ({
|
|
4565
|
+
mw.stats = () => ({
|
|
4566
|
+
running,
|
|
4567
|
+
inflight,
|
|
4568
|
+
processed: _processed,
|
|
4569
|
+
failed: _failed,
|
|
4570
|
+
handlers: handlers.size,
|
|
4571
|
+
maxConcurrent: MAX_CONCURRENT
|
|
4572
|
+
});
|
|
4342
4573
|
attachCron(q, handlers);
|
|
4343
4574
|
return q;
|
|
4344
4575
|
}
|
|
@@ -4367,7 +4598,16 @@ function createRedisQueue(opts) {
|
|
|
4367
4598
|
if (job.schedule) {
|
|
4368
4599
|
try {
|
|
4369
4600
|
const nextRun = cronNext(job.schedule);
|
|
4370
|
-
await redis2.zadd(
|
|
4601
|
+
await redis2.zadd(
|
|
4602
|
+
jobKey,
|
|
4603
|
+
nextRun,
|
|
4604
|
+
JSON.stringify({
|
|
4605
|
+
...job,
|
|
4606
|
+
id: crypto6.randomUUID(),
|
|
4607
|
+
runAt: nextRun,
|
|
4608
|
+
createdAt: Date.now()
|
|
4609
|
+
})
|
|
4610
|
+
);
|
|
4371
4611
|
} catch (e) {
|
|
4372
4612
|
console.error("[queue] cron re-queue failed:", e.message);
|
|
4373
4613
|
}
|
|
@@ -4501,7 +4741,14 @@ function createRedisQueue(opts) {
|
|
|
4501
4741
|
mw.dashboard = function dashboard() {
|
|
4502
4742
|
return buildDashboard(q);
|
|
4503
4743
|
};
|
|
4504
|
-
mw.stats = () => ({
|
|
4744
|
+
mw.stats = () => ({
|
|
4745
|
+
running,
|
|
4746
|
+
inflight,
|
|
4747
|
+
processed: _processed,
|
|
4748
|
+
failed: _failed,
|
|
4749
|
+
handlers: handlers.size,
|
|
4750
|
+
maxConcurrent: MAX_CONCURRENT
|
|
4751
|
+
});
|
|
4505
4752
|
attachCron(q, handlers);
|
|
4506
4753
|
return q;
|
|
4507
4754
|
}
|
|
@@ -4649,10 +4896,14 @@ function createIndexesSQL(tenantId, slug, fields) {
|
|
|
4649
4896
|
const name = internalTableName(tenantId, slug);
|
|
4650
4897
|
const statements = [];
|
|
4651
4898
|
statements.push(`CREATE INDEX IF NOT EXISTS "${name}_tenant_idx" ON "${name}" ("tenant_id")`);
|
|
4652
|
-
statements.push(
|
|
4899
|
+
statements.push(
|
|
4900
|
+
`CREATE INDEX IF NOT EXISTS "${name}_tenant_id_idx" ON "${name}" ("tenant_id", "id")`
|
|
4901
|
+
);
|
|
4653
4902
|
for (const f of fields) {
|
|
4654
4903
|
if (f.unique) {
|
|
4655
|
-
statements.push(
|
|
4904
|
+
statements.push(
|
|
4905
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS "${name}_${f.name}_uidx" ON "${name}" ("${f.name}")`
|
|
4906
|
+
);
|
|
4656
4907
|
} else if (f.index === "hnsw") {
|
|
4657
4908
|
statements.push(
|
|
4658
4909
|
`CREATE INDEX IF NOT EXISTS "${name}_${f.name}_hnsw_idx" ON "${name}" USING hnsw ("${f.name}" vector_cosine_ops)`
|
|
@@ -4914,10 +5165,9 @@ function buildRouter(sql2, usersTable) {
|
|
|
4914
5165
|
`SELECT *, "${searchField}" ${operator} $1::vector AS "_distance" FROM "${name2}" WHERE tenant_id = $2 ORDER BY "_distance" LIMIT $3 OFFSET $4`,
|
|
4915
5166
|
[parsed, ctx.tenant.id, limit, offset]
|
|
4916
5167
|
),
|
|
4917
|
-
sql2.unsafe(
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
)
|
|
5168
|
+
sql2.unsafe(`SELECT count(*) as count FROM "${name2}" WHERE tenant_id = $1`, [
|
|
5169
|
+
ctx.tenant.id
|
|
5170
|
+
])
|
|
4921
5171
|
]);
|
|
4922
5172
|
return Response.json({ rows: rows2, count: extractCount(countResult2) });
|
|
4923
5173
|
} catch {
|
|
@@ -4930,10 +5180,7 @@ function buildRouter(sql2, usersTable) {
|
|
|
4930
5180
|
`SELECT * FROM "${name}" WHERE tenant_id = $1 ORDER BY "${orderCol}" ${orderDir} LIMIT $2 OFFSET $3`,
|
|
4931
5181
|
[ctx.tenant.id, limit, offset]
|
|
4932
5182
|
),
|
|
4933
|
-
sql2.unsafe(
|
|
4934
|
-
`SELECT count(*) as count FROM "${name}" WHERE tenant_id = $1`,
|
|
4935
|
-
[ctx.tenant.id]
|
|
4936
|
-
)
|
|
5183
|
+
sql2.unsafe(`SELECT count(*) as count FROM "${name}" WHERE tenant_id = $1`, [ctx.tenant.id])
|
|
4937
5184
|
]);
|
|
4938
5185
|
return Response.json({ rows, count: extractCount(countResult) });
|
|
4939
5186
|
});
|
|
@@ -5015,7 +5262,10 @@ function buildRouter(sql2, usersTable) {
|
|
|
5015
5262
|
if (!childTable) return Response.json({ error: "Nested table not found" }, { status: 404 });
|
|
5016
5263
|
const relField = findRelation(childTable.fields, ctx.params["_slug"]);
|
|
5017
5264
|
if (!relField) {
|
|
5018
|
-
return Response.json(
|
|
5265
|
+
return Response.json(
|
|
5266
|
+
{ error: `No relation from "${nestedSlug}" to "${ctx.params["_slug"]}"` },
|
|
5267
|
+
{ status: 400 }
|
|
5268
|
+
);
|
|
5019
5269
|
}
|
|
5020
5270
|
const relFields = getRelationFields(childTable.fields);
|
|
5021
5271
|
if (relFields.length === 2) {
|
|
@@ -5086,11 +5336,11 @@ import {
|
|
|
5086
5336
|
GraphQLID,
|
|
5087
5337
|
GraphQLList,
|
|
5088
5338
|
GraphQLNonNull,
|
|
5089
|
-
GraphQLEnumType
|
|
5339
|
+
GraphQLEnumType,
|
|
5340
|
+
graphql as executeGraphQL2
|
|
5090
5341
|
} from "graphql";
|
|
5091
|
-
import { graphql as executeGraphQL2 } from "graphql";
|
|
5092
5342
|
function graphqlType(field, required) {
|
|
5093
|
-
let t;
|
|
5343
|
+
let t = GraphQLString;
|
|
5094
5344
|
switch (field.type) {
|
|
5095
5345
|
case "integer":
|
|
5096
5346
|
t = GraphQLInt;
|
|
@@ -5107,15 +5357,11 @@ function graphqlType(field, required) {
|
|
|
5107
5357
|
name: `Enum_${field.name}`,
|
|
5108
5358
|
values: Object.fromEntries(field.options.map((o) => [o, { value: o }]))
|
|
5109
5359
|
});
|
|
5110
|
-
} else {
|
|
5111
|
-
t = GraphQLString;
|
|
5112
5360
|
}
|
|
5113
5361
|
break;
|
|
5114
5362
|
case "vector":
|
|
5115
5363
|
t = GraphQLString;
|
|
5116
5364
|
break;
|
|
5117
|
-
default:
|
|
5118
|
-
t = GraphQLString;
|
|
5119
5365
|
}
|
|
5120
5366
|
return required ? new GraphQLNonNull(t) : t;
|
|
5121
5367
|
}
|
|
@@ -5142,6 +5388,7 @@ function buildObjectType(table, ctx) {
|
|
|
5142
5388
|
limit: { type: GraphQLInt, defaultValue: 20 },
|
|
5143
5389
|
offset: { type: GraphQLInt, defaultValue: 0 }
|
|
5144
5390
|
},
|
|
5391
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5145
5392
|
resolve: async (parent) => {
|
|
5146
5393
|
const childName = internalTableName(ctx.tenantId, other.slug);
|
|
5147
5394
|
const rows = await ctx.sql.unsafe(
|
|
@@ -5164,6 +5411,7 @@ function buildObjectType(table, ctx) {
|
|
|
5164
5411
|
limit: { type: GraphQLInt, defaultValue: 20 },
|
|
5165
5412
|
offset: { type: GraphQLInt, defaultValue: 0 }
|
|
5166
5413
|
},
|
|
5414
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5167
5415
|
resolve: async (parent) => {
|
|
5168
5416
|
const childName = internalTableName(ctx.tenantId, other.slug);
|
|
5169
5417
|
const targetName = internalTableName(ctx.tenantId, targetSlug);
|
|
@@ -5185,6 +5433,7 @@ function buildObjectType(table, ctx) {
|
|
|
5185
5433
|
if (!targetTable) continue;
|
|
5186
5434
|
fields[targetSlug] = {
|
|
5187
5435
|
type: buildObjectType(targetTable, ctx),
|
|
5436
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5188
5437
|
resolve: async (parent) => {
|
|
5189
5438
|
const name = internalTableName(ctx.tenantId, targetSlug);
|
|
5190
5439
|
const [row] = await ctx.sql.unsafe(
|
|
@@ -5205,9 +5454,7 @@ function buildInputType(table, prefix) {
|
|
|
5205
5454
|
const typeName = pascalCase(`${prefix}_${table.slug}`) + "Input";
|
|
5206
5455
|
return new GraphQLInputObjectType({
|
|
5207
5456
|
name: typeName,
|
|
5208
|
-
fields: Object.fromEntries(
|
|
5209
|
-
table.fields.map((f) => [f.name, { type: inputGraphqlType(f) }])
|
|
5210
|
-
)
|
|
5457
|
+
fields: Object.fromEntries(table.fields.map((f) => [f.name, { type: inputGraphqlType(f) }]))
|
|
5211
5458
|
});
|
|
5212
5459
|
}
|
|
5213
5460
|
function buildQueryFields(tables, ctx) {
|
|
@@ -5222,6 +5469,7 @@ function buildQueryFields(tables, ctx) {
|
|
|
5222
5469
|
limit: { type: GraphQLInt, defaultValue: 20 },
|
|
5223
5470
|
offset: { type: GraphQLInt, defaultValue: 0 }
|
|
5224
5471
|
},
|
|
5472
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5225
5473
|
resolve: async (_, args) => {
|
|
5226
5474
|
const name = internalTableName(ctx.tenantId, slug);
|
|
5227
5475
|
const rows = await ctx.sql.unsafe(
|
|
@@ -5234,6 +5482,7 @@ function buildQueryFields(tables, ctx) {
|
|
|
5234
5482
|
fields[`get${pascal}`] = {
|
|
5235
5483
|
type: objType,
|
|
5236
5484
|
args: { id: { type: new GraphQLNonNull(GraphQLID) } },
|
|
5485
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5237
5486
|
resolve: async (_, args) => {
|
|
5238
5487
|
const name = internalTableName(ctx.tenantId, slug);
|
|
5239
5488
|
const [row] = await ctx.sql.unsafe(
|
|
@@ -5256,6 +5505,7 @@ function buildMutationFields(tables, ctx) {
|
|
|
5256
5505
|
fields[`create${pascal}`] = {
|
|
5257
5506
|
type: objType,
|
|
5258
5507
|
args: { data: { type: new GraphQLNonNull(inputType) } },
|
|
5508
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5259
5509
|
resolve: async (_, args) => {
|
|
5260
5510
|
const name = internalTableName(ctx.tenantId, table.slug);
|
|
5261
5511
|
const data = { ...args.data, tenant_id: ctx.tenantId };
|
|
@@ -5272,6 +5522,7 @@ function buildMutationFields(tables, ctx) {
|
|
|
5272
5522
|
id: { type: new GraphQLNonNull(GraphQLID) },
|
|
5273
5523
|
data: { type: new GraphQLNonNull(patchType) }
|
|
5274
5524
|
},
|
|
5525
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5275
5526
|
resolve: async (_, args) => {
|
|
5276
5527
|
const name = internalTableName(ctx.tenantId, table.slug);
|
|
5277
5528
|
const setClauses = table.fields.filter((f) => args.data[f.name] !== void 0).map((f, i) => `"${f.name}" = $${i + 1}`);
|
|
@@ -5294,6 +5545,7 @@ function buildMutationFields(tables, ctx) {
|
|
|
5294
5545
|
fields[`delete${pascal}`] = {
|
|
5295
5546
|
type: GraphQLBoolean,
|
|
5296
5547
|
args: { id: { type: new GraphQLNonNull(GraphQLID) } },
|
|
5548
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5297
5549
|
resolve: async (_, args) => {
|
|
5298
5550
|
const name = internalTableName(ctx.tenantId, table.slug);
|
|
5299
5551
|
const result = await ctx.sql.unsafe(
|
|
@@ -5404,7 +5656,9 @@ function tenant(options) {
|
|
|
5404
5656
|
});
|
|
5405
5657
|
await members.create();
|
|
5406
5658
|
await members.createIndex("user_id");
|
|
5407
|
-
await sql2.unsafe(
|
|
5659
|
+
await sql2.unsafe(
|
|
5660
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS "_tenant_members_unique_idx" ON "_tenant_members" ("tenant_id", "user_id")`
|
|
5661
|
+
);
|
|
5408
5662
|
const tables = pg.table("_user_tables", {
|
|
5409
5663
|
id: serial("id").primaryKey(),
|
|
5410
5664
|
tenant_id: text("tenant_id").notNull().references("_tenants", "id", "cascade"),
|
|
@@ -5415,7 +5669,9 @@ function tenant(options) {
|
|
|
5415
5669
|
});
|
|
5416
5670
|
await tables.create();
|
|
5417
5671
|
await tables.createIndex("tenant_id");
|
|
5418
|
-
await sql2.unsafe(
|
|
5672
|
+
await sql2.unsafe(
|
|
5673
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS "_user_tables_unique_idx" ON "_user_tables" ("tenant_id", "slug")`
|
|
5674
|
+
);
|
|
5419
5675
|
}
|
|
5420
5676
|
function middleware() {
|
|
5421
5677
|
return async (req, ctx, next) => {
|
|
@@ -5439,10 +5695,13 @@ function tenant(options) {
|
|
|
5439
5695
|
}
|
|
5440
5696
|
const headerId = req.headers.get("X-Tenant-ID");
|
|
5441
5697
|
if (!headerId) {
|
|
5442
|
-
return Response.json(
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5698
|
+
return Response.json(
|
|
5699
|
+
{
|
|
5700
|
+
error: "Multiple tenants. Set X-Tenant-ID header.",
|
|
5701
|
+
tenants: members.map((m) => ({ id: m.id, name: m.name, role: m.role }))
|
|
5702
|
+
},
|
|
5703
|
+
{ status: 300 }
|
|
5704
|
+
);
|
|
5446
5705
|
}
|
|
5447
5706
|
const member = members.find((m) => m.id === headerId);
|
|
5448
5707
|
if (!member) {
|
|
@@ -5483,7 +5742,9 @@ function buildRouter2(deps) {
|
|
|
5483
5742
|
return Response.json(row, { status: 201 });
|
|
5484
5743
|
});
|
|
5485
5744
|
r.get("/agents", async () => {
|
|
5486
|
-
const { data: rows } = await agentsTable.readMany(void 0, {
|
|
5745
|
+
const { data: rows } = await agentsTable.readMany(void 0, {
|
|
5746
|
+
orderBy: { created_at: "desc" }
|
|
5747
|
+
});
|
|
5487
5748
|
return Response.json(rows);
|
|
5488
5749
|
});
|
|
5489
5750
|
r.get("/agents/:id", async (_req, ctx) => {
|
|
@@ -5497,7 +5758,14 @@ function buildRouter2(deps) {
|
|
|
5497
5758
|
if (!agent2) return Response.json({ error: "Agent not found" }, { status: 404 });
|
|
5498
5759
|
const body = await req.json();
|
|
5499
5760
|
const updateData = {};
|
|
5500
|
-
for (const key of [
|
|
5761
|
+
for (const key of [
|
|
5762
|
+
"name",
|
|
5763
|
+
"description",
|
|
5764
|
+
"type",
|
|
5765
|
+
"model",
|
|
5766
|
+
"system_prompt",
|
|
5767
|
+
"active"
|
|
5768
|
+
]) {
|
|
5501
5769
|
if (body[key] !== void 0) {
|
|
5502
5770
|
updateData[key] = body[key];
|
|
5503
5771
|
}
|
|
@@ -5634,7 +5902,9 @@ function chunkContent(content, chunkSize, overlap) {
|
|
|
5634
5902
|
|
|
5635
5903
|
// agent/run.ts
|
|
5636
5904
|
function hasKnowledgeDocs(sql2, agentId) {
|
|
5637
|
-
return sql2`SELECT 1 FROM "_knowledge_documents" WHERE agent_id = ${agentId} LIMIT 1`.then(
|
|
5905
|
+
return sql2`SELECT 1 FROM "_knowledge_documents" WHERE agent_id = ${agentId} LIMIT 1`.then(
|
|
5906
|
+
(r) => r.length > 0
|
|
5907
|
+
);
|
|
5638
5908
|
}
|
|
5639
5909
|
async function searchKnowledge(sql2, provider, agentId, query, limit = 5) {
|
|
5640
5910
|
const embedding = await provider.embed(query);
|
|
@@ -5808,7 +6078,14 @@ function agent(options) {
|
|
|
5808
6078
|
trace_id: text("trace_id"),
|
|
5809
6079
|
created_at: timestamptz("created_at").notNull().default(sql`NOW()`)
|
|
5810
6080
|
});
|
|
5811
|
-
const runner = createRunner({
|
|
6081
|
+
const runner = createRunner({
|
|
6082
|
+
sql: sql2,
|
|
6083
|
+
agents: agentsTable,
|
|
6084
|
+
runs: runsTable,
|
|
6085
|
+
knowledge: knowledgeTable,
|
|
6086
|
+
provider: resolvedProvider,
|
|
6087
|
+
userTools: options.tools
|
|
6088
|
+
});
|
|
5812
6089
|
const base = new PgModule(pg);
|
|
5813
6090
|
const r = buildRouter2({ agents: agentsTable, runs: runsTable, knowledge: knowledgeTable, runner });
|
|
5814
6091
|
const mod = r;
|
|
@@ -6577,12 +6854,24 @@ async function deploy(config) {
|
|
|
6577
6854
|
if (ac.ports && old?.process) {
|
|
6578
6855
|
targetPort = old.currentPort === ac.ports[0] ? ac.ports[1] : ac.ports[0];
|
|
6579
6856
|
}
|
|
6580
|
-
const mp = await forkAndCheck(
|
|
6857
|
+
const mp = await forkAndCheck(
|
|
6858
|
+
name,
|
|
6859
|
+
appDir,
|
|
6860
|
+
ac.entry,
|
|
6861
|
+
targetPort,
|
|
6862
|
+
ac.env,
|
|
6863
|
+
log,
|
|
6864
|
+
ac.healthEndpoint
|
|
6865
|
+
);
|
|
6581
6866
|
if (!mp) {
|
|
6582
6867
|
log("[deploy] new process failed to start, keeping old running");
|
|
6583
6868
|
if (old?.process) apps.set(name, old);
|
|
6584
6869
|
else {
|
|
6585
|
-
setAppRuntime(name, ac, logs, {
|
|
6870
|
+
setAppRuntime(name, ac, logs, {
|
|
6871
|
+
status: "error",
|
|
6872
|
+
port: targetPort,
|
|
6873
|
+
error: "failed to start"
|
|
6874
|
+
});
|
|
6586
6875
|
}
|
|
6587
6876
|
return;
|
|
6588
6877
|
}
|
|
@@ -6625,7 +6914,7 @@ async function deploy(config) {
|
|
|
6625
6914
|
function setAppRuntime(name, ac, logs, overrides) {
|
|
6626
6915
|
apps.set(name, {
|
|
6627
6916
|
config: ac,
|
|
6628
|
-
status: { name, ...overrides },
|
|
6917
|
+
status: { name, status: "starting", port: 0, ...overrides },
|
|
6629
6918
|
logs,
|
|
6630
6919
|
process: null,
|
|
6631
6920
|
currentPort: overrides.port ?? ac.port ?? 0,
|
|
@@ -6826,7 +7115,7 @@ async function compileVendorBundle() {
|
|
|
6826
7115
|
if (vendorBundle) return vendorBundle;
|
|
6827
7116
|
if (!_userRequire) _userRequire = createRequire(join2(process.cwd(), "package.json"));
|
|
6828
7117
|
const modules = {
|
|
6829
|
-
|
|
7118
|
+
react: [],
|
|
6830
7119
|
"react-dom": ["react"],
|
|
6831
7120
|
"react-dom/client": ["react"],
|
|
6832
7121
|
"react/jsx-runtime": ["react"]
|
|
@@ -6863,10 +7152,12 @@ async function compileVendorBundle() {
|
|
|
6863
7152
|
const stmts = [""];
|
|
6864
7153
|
for (const [request, keys] of Object.entries(modules)) {
|
|
6865
7154
|
const unique = keys.filter((k) => !used.has(k) && used.add(k));
|
|
6866
|
-
if (unique.length > 0)
|
|
7155
|
+
if (unique.length > 0)
|
|
7156
|
+
stmts.push(`export { ${unique.join(", ")} } from ${JSON.stringify(request)};`);
|
|
6867
7157
|
}
|
|
6868
7158
|
const uidWfw = wfwKeys.filter((k) => !used.has(k) && used.add(k));
|
|
6869
|
-
if (uidWfw.length > 0)
|
|
7159
|
+
if (uidWfw.length > 0)
|
|
7160
|
+
stmts.push(`export { ${uidWfw.join(", ")} } from ${JSON.stringify(reactAbsPath)};`);
|
|
6870
7161
|
const result = await esbuild.build({
|
|
6871
7162
|
stdin: { contents: stmts.join("\n"), resolveDir: process.cwd() },
|
|
6872
7163
|
format: "esm",
|
|
@@ -6909,7 +7200,14 @@ async function compileBrowser(path2, outDir) {
|
|
|
6909
7200
|
jsx: "automatic",
|
|
6910
7201
|
jsxImportSource: "react",
|
|
6911
7202
|
bundle: true,
|
|
6912
|
-
external: [
|
|
7203
|
+
external: [
|
|
7204
|
+
"react",
|
|
7205
|
+
"react-dom",
|
|
7206
|
+
"react-dom/client",
|
|
7207
|
+
"react/jsx-runtime",
|
|
7208
|
+
"weifuwu",
|
|
7209
|
+
"weifuwu/react"
|
|
7210
|
+
],
|
|
6913
7211
|
plugins: [plugin],
|
|
6914
7212
|
write: true,
|
|
6915
7213
|
allowOverwrite: true
|
|
@@ -6943,7 +7241,14 @@ async function compileHotComponent(path2) {
|
|
|
6943
7241
|
jsx: "automatic",
|
|
6944
7242
|
jsxImportSource: "react",
|
|
6945
7243
|
bundle: true,
|
|
6946
|
-
external: [
|
|
7244
|
+
external: [
|
|
7245
|
+
"react",
|
|
7246
|
+
"react-dom",
|
|
7247
|
+
"react-dom/client",
|
|
7248
|
+
"react/jsx-runtime",
|
|
7249
|
+
"weifuwu",
|
|
7250
|
+
"weifuwu/react"
|
|
7251
|
+
],
|
|
6947
7252
|
plugins: [plugin],
|
|
6948
7253
|
write: false
|
|
6949
7254
|
});
|
|
@@ -7147,7 +7452,7 @@ function tailwindRouter(dir) {
|
|
|
7147
7452
|
const cssDir = resolve4(dir);
|
|
7148
7453
|
const cssPath = join3(cssDir, "app", "globals.css");
|
|
7149
7454
|
const r = new Router();
|
|
7150
|
-
r.get("/__wfw/style/:hash.css", async (
|
|
7455
|
+
r.get("/__wfw/style/:hash.css", async (_req, _ctx) => {
|
|
7151
7456
|
if (!cssCache.has(cssPath)) {
|
|
7152
7457
|
await compileTailwindCss(cssPath, cssDir);
|
|
7153
7458
|
}
|
|
@@ -7231,7 +7536,7 @@ function liveWs() {
|
|
|
7231
7536
|
}
|
|
7232
7537
|
};
|
|
7233
7538
|
}
|
|
7234
|
-
function liveRouter(
|
|
7539
|
+
function liveRouter(_dir) {
|
|
7235
7540
|
const r = new Router();
|
|
7236
7541
|
compileVendorBundle().catch(() => {
|
|
7237
7542
|
});
|
|
@@ -7503,7 +7808,13 @@ async function resolveRoute(ssrDir, segments, routeCache) {
|
|
|
7503
7808
|
if (d === appDir) break;
|
|
7504
7809
|
d = dirname3(d);
|
|
7505
7810
|
}
|
|
7506
|
-
const result = {
|
|
7811
|
+
const result = {
|
|
7812
|
+
routePath: "/" + routeParams.join("/"),
|
|
7813
|
+
pageFile,
|
|
7814
|
+
layoutFiles,
|
|
7815
|
+
errorFiles,
|
|
7816
|
+
notFoundFile
|
|
7817
|
+
};
|
|
7507
7818
|
routeCache.set(cacheKey, result);
|
|
7508
7819
|
return result;
|
|
7509
7820
|
}
|
|
@@ -7560,7 +7871,6 @@ function renderPage(pageFile, outDir) {
|
|
|
7560
7871
|
const absPath = resolve6(pageFile);
|
|
7561
7872
|
const entryId = hashId(absPath);
|
|
7562
7873
|
ssrEntries.set(entryId, { path: absPath });
|
|
7563
|
-
const bundleKey = `/__ssr/${entryId}.js`;
|
|
7564
7874
|
return async (req, ctx) => {
|
|
7565
7875
|
let pageMod;
|
|
7566
7876
|
try {
|
|
@@ -7574,7 +7884,6 @@ function renderPage(pageFile, outDir) {
|
|
|
7574
7884
|
if (!Component) return errorPage("Missing default export", pageFile);
|
|
7575
7885
|
const layouts = ctx.layoutStack || [];
|
|
7576
7886
|
const layoutComponents = layouts.map((l) => l.component);
|
|
7577
|
-
const layoutPaths = layouts.map((l) => l.path);
|
|
7578
7887
|
const base = (ctx.mountPath || "").replace(/\/$/, "");
|
|
7579
7888
|
const loaderData = serializeLoaderData(ctx);
|
|
7580
7889
|
const ctxValue = {
|
|
@@ -7594,22 +7903,22 @@ function renderPage(pageFile, outDir) {
|
|
|
7594
7903
|
let element = createElement3(
|
|
7595
7904
|
"div",
|
|
7596
7905
|
{ id: "__weifuwu_root" },
|
|
7597
|
-
createElement3(
|
|
7598
|
-
TsxContext.Provider,
|
|
7599
|
-
{ value: ctxValue },
|
|
7600
|
-
createElement3(Component, null)
|
|
7601
|
-
)
|
|
7906
|
+
createElement3(TsxContext.Provider, { value: ctxValue }, createElement3(Component, null))
|
|
7602
7907
|
);
|
|
7603
7908
|
element = buildHtmlShell("weifuwu", element, layoutComponents);
|
|
7604
7909
|
const { renderToReadableStream } = await import("react-dom/server");
|
|
7605
7910
|
const stream = await renderToReadableStream(element);
|
|
7606
|
-
return streamResponse(
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
|
|
7610
|
-
|
|
7611
|
-
|
|
7612
|
-
|
|
7911
|
+
return streamResponse(
|
|
7912
|
+
stream,
|
|
7913
|
+
{
|
|
7914
|
+
ctx,
|
|
7915
|
+
base,
|
|
7916
|
+
isDev: isDev2,
|
|
7917
|
+
loaderData,
|
|
7918
|
+
tailwind: ctx.tailwind
|
|
7919
|
+
},
|
|
7920
|
+
buildHydrationScript(entryId, JSON.stringify(ctxValue), base)
|
|
7921
|
+
);
|
|
7613
7922
|
});
|
|
7614
7923
|
};
|
|
7615
7924
|
}
|
|
@@ -7693,13 +8002,16 @@ function ssr(opts) {
|
|
|
7693
8002
|
if (!resolved) {
|
|
7694
8003
|
if (isDev2) {
|
|
7695
8004
|
const pages = discoverRoutes(dir).map((p) => p.path).sort();
|
|
7696
|
-
return Response.json(
|
|
7697
|
-
|
|
7698
|
-
|
|
7699
|
-
|
|
7700
|
-
|
|
7701
|
-
|
|
7702
|
-
|
|
8005
|
+
return Response.json(
|
|
8006
|
+
{
|
|
8007
|
+
error: "Not Found",
|
|
8008
|
+
path: "/" + segments.join("/"),
|
|
8009
|
+
method: req.method,
|
|
8010
|
+
hint: "Available SSR pages",
|
|
8011
|
+
pages
|
|
8012
|
+
},
|
|
8013
|
+
{ status: 404 }
|
|
8014
|
+
);
|
|
7703
8015
|
}
|
|
7704
8016
|
return new Response("Not Found", { status: 404 });
|
|
7705
8017
|
}
|
|
@@ -7765,7 +8077,11 @@ async function getSession(sql2, id2) {
|
|
|
7765
8077
|
async function listSessions(sql2, userId2) {
|
|
7766
8078
|
const opts = { orderBy: { updated_at: "desc" } };
|
|
7767
8079
|
if (userId2 !== void 0) {
|
|
7768
|
-
const { data: rows2 } = await sessions.readMany(
|
|
8080
|
+
const { data: rows2 } = await sessions.readMany(
|
|
8081
|
+
sql2,
|
|
8082
|
+
{ user_id: userId2, active: true },
|
|
8083
|
+
opts
|
|
8084
|
+
);
|
|
7769
8085
|
return rows2;
|
|
7770
8086
|
}
|
|
7771
8087
|
const { data: rows } = await sessions.readMany(sql2, { active: true }, opts);
|
|
@@ -7844,7 +8160,14 @@ async function* executeGenerator(opts) {
|
|
|
7844
8160
|
totalTokens: result2.usage?.totalTokens ?? 0
|
|
7845
8161
|
};
|
|
7846
8162
|
try {
|
|
7847
|
-
await addTextMessage(
|
|
8163
|
+
await addTextMessage(
|
|
8164
|
+
sql2,
|
|
8165
|
+
sessionId,
|
|
8166
|
+
"assistant",
|
|
8167
|
+
currentAssistantText,
|
|
8168
|
+
currentUsage.promptTokens,
|
|
8169
|
+
currentUsage.completionTokens
|
|
8170
|
+
);
|
|
7848
8171
|
} catch (e) {
|
|
7849
8172
|
console.error("[opencode] save message failed:", e);
|
|
7850
8173
|
}
|
|
@@ -7887,11 +8210,7 @@ var DENIED_COMMANDS = [
|
|
|
7887
8210
|
/^:\(\)\{.*\}:;$/,
|
|
7888
8211
|
/^fork\s+bomb/i
|
|
7889
8212
|
];
|
|
7890
|
-
var DENIED_PATHS = [
|
|
7891
|
-
/\/\.env$/,
|
|
7892
|
-
/\/\.env\.\w+$/,
|
|
7893
|
-
/\/node_modules\//
|
|
7894
|
-
];
|
|
8213
|
+
var DENIED_PATHS = [/\/\.env$/, /\/\.env\.\w+$/, /\/node_modules\//];
|
|
7895
8214
|
function isCommandAllowed(command) {
|
|
7896
8215
|
const trimmed = command.trim();
|
|
7897
8216
|
for (const re of DENIED_COMMANDS) {
|
|
@@ -7899,7 +8218,7 @@ function isCommandAllowed(command) {
|
|
|
7899
8218
|
}
|
|
7900
8219
|
return true;
|
|
7901
8220
|
}
|
|
7902
|
-
function isPathAllowed(resolvedPath, workspace,
|
|
8221
|
+
function isPathAllowed(resolvedPath, workspace, _perms) {
|
|
7903
8222
|
if (!resolvedPath.startsWith(workspace)) return false;
|
|
7904
8223
|
for (const re of DENIED_PATHS) {
|
|
7905
8224
|
if (re.test(resolvedPath)) return false;
|
|
@@ -7954,16 +8273,20 @@ function createBashTool(ctx) {
|
|
|
7954
8273
|
}
|
|
7955
8274
|
const cwd = workdir ? `${ctx.workspace}/${workdir}` : ctx.workspace;
|
|
7956
8275
|
return new Promise((resolve14) => {
|
|
7957
|
-
const child = exec(
|
|
7958
|
-
|
|
7959
|
-
|
|
7960
|
-
|
|
7961
|
-
|
|
7962
|
-
|
|
7963
|
-
|
|
7964
|
-
|
|
7965
|
-
|
|
7966
|
-
|
|
8276
|
+
const child = exec(
|
|
8277
|
+
command,
|
|
8278
|
+
{ cwd, timeout: timeout * 1e3, maxBuffer: 1024 * 1024 },
|
|
8279
|
+
(error, stdout, stderr) => {
|
|
8280
|
+
const truncated = stdout.length > 1e6 || stderr.length > 1e6;
|
|
8281
|
+
resolve14({
|
|
8282
|
+
stdout: stdout.slice(0, 1e6),
|
|
8283
|
+
stderr: stderr.slice(0, 1e6),
|
|
8284
|
+
exitCode: error?.code ?? 0,
|
|
8285
|
+
signal: error?.signal ?? null,
|
|
8286
|
+
truncated
|
|
8287
|
+
});
|
|
8288
|
+
}
|
|
8289
|
+
);
|
|
7967
8290
|
});
|
|
7968
8291
|
}
|
|
7969
8292
|
});
|
|
@@ -8070,7 +8393,10 @@ function createEditTool(ctx) {
|
|
|
8070
8393
|
}
|
|
8071
8394
|
const secondIdx = content.indexOf(oldString, firstIdx + 1);
|
|
8072
8395
|
if (secondIdx !== -1) {
|
|
8073
|
-
return {
|
|
8396
|
+
return {
|
|
8397
|
+
error: "Found multiple matches. Provide more surrounding context in oldString.",
|
|
8398
|
+
replaced: 0
|
|
8399
|
+
};
|
|
8074
8400
|
}
|
|
8075
8401
|
const result = content.replace(oldString, newString);
|
|
8076
8402
|
writeFileSync3(resolved, result, "utf-8");
|
|
@@ -8112,7 +8438,11 @@ function createGrepTool(ctx) {
|
|
|
8112
8438
|
stdout = execFileSync("grep", args, { timeout: 15e3, maxBuffer: 1024 * 1024 }).toString();
|
|
8113
8439
|
}
|
|
8114
8440
|
const lines = stdout.split("\n").filter(Boolean);
|
|
8115
|
-
return {
|
|
8441
|
+
return {
|
|
8442
|
+
matches: lines.length,
|
|
8443
|
+
results: lines.slice(0, 200),
|
|
8444
|
+
truncated: lines.length > 200
|
|
8445
|
+
};
|
|
8116
8446
|
} catch (e) {
|
|
8117
8447
|
if (e.status === 1) {
|
|
8118
8448
|
return { matches: 0, results: [], truncated: false };
|
|
@@ -8138,19 +8468,20 @@ function createGlobTool(ctx) {
|
|
|
8138
8468
|
execute: async ({ pattern, path: path2 }) => {
|
|
8139
8469
|
const searchDir = path2 ? resolve11(ctx.workspace, path2) : ctx.workspace;
|
|
8140
8470
|
try {
|
|
8141
|
-
const stdout = execFileSync2(
|
|
8142
|
-
|
|
8143
|
-
"-name",
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
|
|
8149
|
-
timeout: 1e4,
|
|
8150
|
-
maxBuffer: 1024 * 1024
|
|
8151
|
-
}).toString();
|
|
8471
|
+
const stdout = execFileSync2(
|
|
8472
|
+
"find",
|
|
8473
|
+
[searchDir, "-name", pattern, "-not", "-path", "*/node_modules/*"],
|
|
8474
|
+
{
|
|
8475
|
+
timeout: 1e4,
|
|
8476
|
+
maxBuffer: 1024 * 1024
|
|
8477
|
+
}
|
|
8478
|
+
).toString();
|
|
8152
8479
|
const lines = stdout.split("\n").filter(Boolean).slice(0, 200);
|
|
8153
|
-
return {
|
|
8480
|
+
return {
|
|
8481
|
+
files: lines,
|
|
8482
|
+
total: lines.length,
|
|
8483
|
+
truncated: stdout.split("\n").filter(Boolean).length > 200
|
|
8484
|
+
};
|
|
8154
8485
|
} catch {
|
|
8155
8486
|
return { files: [], total: 0, truncated: false };
|
|
8156
8487
|
}
|
|
@@ -8161,7 +8492,7 @@ function createGlobTool(ctx) {
|
|
|
8161
8492
|
// opencode/tools/web.ts
|
|
8162
8493
|
import { tool as tool9 } from "ai";
|
|
8163
8494
|
import { z as z11 } from "zod";
|
|
8164
|
-
function createWebTool(
|
|
8495
|
+
function createWebTool(_ctx) {
|
|
8165
8496
|
return tool9({
|
|
8166
8497
|
description: "Fetch a URL and return the content as text.",
|
|
8167
8498
|
inputSchema: z11.object({
|
|
@@ -8290,15 +8621,29 @@ function createTools(ctx) {
|
|
|
8290
8621
|
|
|
8291
8622
|
// opencode/rest.ts
|
|
8292
8623
|
async function buildRouter4(deps) {
|
|
8293
|
-
const {
|
|
8624
|
+
const {
|
|
8625
|
+
sql: sql2,
|
|
8626
|
+
model,
|
|
8627
|
+
workspace,
|
|
8628
|
+
systemPrompt,
|
|
8629
|
+
skills,
|
|
8630
|
+
skillsRegistry,
|
|
8631
|
+
permissions: permissions2,
|
|
8632
|
+
pendingQuestions
|
|
8633
|
+
} = deps;
|
|
8294
8634
|
const router = new Router();
|
|
8295
8635
|
router.post("/sessions", async (req, ctx) => {
|
|
8296
8636
|
const body = await req.json().catch(() => ({}));
|
|
8297
|
-
const session2 = await createSession(
|
|
8298
|
-
|
|
8299
|
-
|
|
8300
|
-
|
|
8301
|
-
|
|
8637
|
+
const session2 = await createSession(
|
|
8638
|
+
sql2,
|
|
8639
|
+
{
|
|
8640
|
+
title: body.title,
|
|
8641
|
+
model: body.model,
|
|
8642
|
+
systemPrompt: body.systemPrompt || systemPrompt
|
|
8643
|
+
},
|
|
8644
|
+
workspace,
|
|
8645
|
+
ctx.mountPath || ""
|
|
8646
|
+
);
|
|
8302
8647
|
return Response.json(session2, { status: 201 });
|
|
8303
8648
|
});
|
|
8304
8649
|
router.get("/sessions", async () => {
|
|
@@ -8362,7 +8707,11 @@ async function buildRouter4(deps) {
|
|
|
8362
8707
|
FROM "_opencode_messages"
|
|
8363
8708
|
WHERE session_id = ${sessionId}
|
|
8364
8709
|
`;
|
|
8365
|
-
const stats = rows[0] || {
|
|
8710
|
+
const stats = rows[0] || {
|
|
8711
|
+
message_count: 0,
|
|
8712
|
+
total_tokens_in: 0,
|
|
8713
|
+
total_tokens_out: 0
|
|
8714
|
+
};
|
|
8366
8715
|
return Response.json({
|
|
8367
8716
|
session_id: sessionId,
|
|
8368
8717
|
message_count: stats.message_count,
|
|
@@ -8383,7 +8732,16 @@ async function buildRouter4(deps) {
|
|
|
8383
8732
|
// opencode/ws.ts
|
|
8384
8733
|
var clients2 = /* @__PURE__ */ new WeakMap();
|
|
8385
8734
|
function createWSHandler2(deps) {
|
|
8386
|
-
const {
|
|
8735
|
+
const {
|
|
8736
|
+
sql: sql2,
|
|
8737
|
+
model,
|
|
8738
|
+
workspace,
|
|
8739
|
+
systemPrompt,
|
|
8740
|
+
skills,
|
|
8741
|
+
skillsRegistry,
|
|
8742
|
+
permissions: permissions2,
|
|
8743
|
+
pendingQuestions
|
|
8744
|
+
} = deps;
|
|
8387
8745
|
return {
|
|
8388
8746
|
open(ws, ctx) {
|
|
8389
8747
|
const userId2 = ctx.user?.id ?? 0;
|
|
@@ -8403,12 +8761,17 @@ function createWSHandler2(deps) {
|
|
|
8403
8761
|
switch (msg.type) {
|
|
8404
8762
|
case "create": {
|
|
8405
8763
|
try {
|
|
8406
|
-
const session2 = await createSession(
|
|
8407
|
-
|
|
8408
|
-
|
|
8409
|
-
|
|
8410
|
-
|
|
8411
|
-
|
|
8764
|
+
const session2 = await createSession(
|
|
8765
|
+
sql2,
|
|
8766
|
+
{
|
|
8767
|
+
userId: client.userId,
|
|
8768
|
+
title: msg.title,
|
|
8769
|
+
model: msg.model,
|
|
8770
|
+
systemPrompt: msg.systemPrompt || systemPrompt
|
|
8771
|
+
},
|
|
8772
|
+
workspace,
|
|
8773
|
+
client.mountPath
|
|
8774
|
+
);
|
|
8412
8775
|
ws.send(JSON.stringify({ type: "session_created", session: session2 }));
|
|
8413
8776
|
} catch (e) {
|
|
8414
8777
|
ws.send(JSON.stringify({ type: "error", error: e.message }));
|
|
@@ -8505,8 +8868,7 @@ function createWSHandler2(deps) {
|
|
|
8505
8868
|
}
|
|
8506
8869
|
|
|
8507
8870
|
// opencode/skills.ts
|
|
8508
|
-
import { readFile } from "node:fs/promises";
|
|
8509
|
-
import { glob } from "node:fs/promises";
|
|
8871
|
+
import { readFile, glob } from "node:fs/promises";
|
|
8510
8872
|
import { homedir } from "node:os";
|
|
8511
8873
|
import { resolve as resolve12 } from "node:path";
|
|
8512
8874
|
import { parse as parseYaml } from "yaml";
|
|
@@ -8603,7 +8965,16 @@ async function opencode(options) {
|
|
|
8603
8965
|
const model = provider.chat(modelName);
|
|
8604
8966
|
const pendingQuestions = /* @__PURE__ */ new Map();
|
|
8605
8967
|
const base = new PgModule(pg);
|
|
8606
|
-
const r = await buildRouter4({
|
|
8968
|
+
const r = await buildRouter4({
|
|
8969
|
+
sql: sql2,
|
|
8970
|
+
model,
|
|
8971
|
+
workspace,
|
|
8972
|
+
systemPrompt,
|
|
8973
|
+
skills: manualSkills,
|
|
8974
|
+
skillsRegistry,
|
|
8975
|
+
permissions: permissions2,
|
|
8976
|
+
pendingQuestions
|
|
8977
|
+
});
|
|
8607
8978
|
const mod = r;
|
|
8608
8979
|
mod.migrate = async () => {
|
|
8609
8980
|
const sessions2 = pg.table("_opencode_sessions", {
|
|
@@ -8636,7 +9007,16 @@ async function opencode(options) {
|
|
|
8636
9007
|
await messages2.create();
|
|
8637
9008
|
await messages2.createIndex(["session_id", "created_at"]);
|
|
8638
9009
|
};
|
|
8639
|
-
mod.wsHandler = () => createWSHandler2({
|
|
9010
|
+
mod.wsHandler = () => createWSHandler2({
|
|
9011
|
+
sql: sql2,
|
|
9012
|
+
model,
|
|
9013
|
+
workspace,
|
|
9014
|
+
systemPrompt,
|
|
9015
|
+
skills: manualSkills,
|
|
9016
|
+
skillsRegistry,
|
|
9017
|
+
permissions: permissions2,
|
|
9018
|
+
pendingQuestions
|
|
9019
|
+
});
|
|
8640
9020
|
mod.close = () => base.close();
|
|
8641
9021
|
return mod;
|
|
8642
9022
|
}
|
|
@@ -8745,7 +9125,10 @@ var MemStore = class {
|
|
|
8745
9125
|
daily,
|
|
8746
9126
|
top_pages: topPages,
|
|
8747
9127
|
referrers: [...refMap.entries()].sort((a, b) => b[1] - a[1]).slice(0, 10).map(([domain, count]) => ({ domain, count })),
|
|
8748
|
-
devices: {
|
|
9128
|
+
devices: {
|
|
9129
|
+
mobile: Math.round(totalMobile / total * 1e3) / 10,
|
|
9130
|
+
desktop: Math.round(totalDesktop / total * 1e3) / 10
|
|
9131
|
+
}
|
|
8749
9132
|
};
|
|
8750
9133
|
}
|
|
8751
9134
|
};
|
|
@@ -8798,7 +9181,10 @@ async function queryPg(sql2, days) {
|
|
|
8798
9181
|
daily: daily.map((d) => ({ date: d.date, pv: d.pv, uv: d.uv })),
|
|
8799
9182
|
top_pages: pageRows.map((p) => ({ path: p.path, pv: p.pv })),
|
|
8800
9183
|
referrers: [],
|
|
8801
|
-
devices: {
|
|
9184
|
+
devices: {
|
|
9185
|
+
mobile: Math.round(t.total_mobile / denom * 1e3) / 10,
|
|
9186
|
+
desktop: Math.round(t.total_desktop / denom * 1e3) / 10
|
|
9187
|
+
}
|
|
8802
9188
|
};
|
|
8803
9189
|
}
|
|
8804
9190
|
function escapeHtml2(s) {
|
|
@@ -8813,9 +9199,7 @@ function renderDashboard(days, data) {
|
|
|
8813
9199
|
const rows = top_pages.map(
|
|
8814
9200
|
(p, i) => `<tr><td class="num">${i + 1}</td><td class="path">${escapeHtml2(p.path)}</td><td class="num">${p.pv}</td></tr>`
|
|
8815
9201
|
).join("");
|
|
8816
|
-
const refRows = referrers.map(
|
|
8817
|
-
(r) => `<tr><td>${escapeHtml2(r.domain)}</td><td class="num">${r.count}</td></tr>`
|
|
8818
|
-
).join("");
|
|
9202
|
+
const refRows = referrers.map((r) => `<tr><td>${escapeHtml2(r.domain)}</td><td class="num">${r.count}</td></tr>`).join("");
|
|
8819
9203
|
return `<!DOCTYPE html><html lang="en">
|
|
8820
9204
|
<head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>Analytics - weifuwu</title>
|
|
8821
9205
|
<style>*,:before,:after{box-sizing:border-box;margin:0;padding:0}
|
|
@@ -9022,7 +9406,10 @@ function i18n(options) {
|
|
|
9022
9406
|
set: (value, loc) => {
|
|
9023
9407
|
const cookie = `${opts.cookie}=${encodeURIComponent(value)}; Path=/; SameSite=Lax`;
|
|
9024
9408
|
const location = loc ?? (req.headers.get("referer") || "/");
|
|
9025
|
-
return new Response(null, {
|
|
9409
|
+
return new Response(null, {
|
|
9410
|
+
status: 302,
|
|
9411
|
+
headers: { Location: location, "Set-Cookie": cookie }
|
|
9412
|
+
});
|
|
9026
9413
|
}
|
|
9027
9414
|
};
|
|
9028
9415
|
return next(req, ctx);
|
|
@@ -9041,7 +9428,11 @@ function i18n(options) {
|
|
|
9041
9428
|
const accept = req.headers.get("accept") ?? "";
|
|
9042
9429
|
if (accept.includes("application/json")) {
|
|
9043
9430
|
return Response.json(
|
|
9044
|
-
{
|
|
9431
|
+
{
|
|
9432
|
+
ok: true,
|
|
9433
|
+
locale: value,
|
|
9434
|
+
messages: Object.keys(messages2).length > 0 ? messages2 : void 0
|
|
9435
|
+
},
|
|
9045
9436
|
{ headers: { "Set-Cookie": cookie } }
|
|
9046
9437
|
);
|
|
9047
9438
|
}
|
|
@@ -9359,10 +9750,11 @@ function listHandler(entries) {
|
|
|
9359
9750
|
if (before) conditions.push(lt("created_at", before));
|
|
9360
9751
|
const limit = parseInt(url.searchParams.get("limit") ?? "50", 10);
|
|
9361
9752
|
const offset = parseInt(url.searchParams.get("offset") ?? "0", 10);
|
|
9362
|
-
const { count, data } = await entries.readMany(
|
|
9363
|
-
|
|
9364
|
-
|
|
9365
|
-
|
|
9753
|
+
const { count, data } = await entries.readMany(conditions.length > 0 ? conditions : void 0, {
|
|
9754
|
+
orderBy: { created_at: "desc" },
|
|
9755
|
+
limit,
|
|
9756
|
+
offset
|
|
9757
|
+
});
|
|
9366
9758
|
return Response.json({ entries: data.map(parseMetadata), total: count });
|
|
9367
9759
|
};
|
|
9368
9760
|
}
|
|
@@ -9473,12 +9865,15 @@ import crypto8 from "node:crypto";
|
|
|
9473
9865
|
|
|
9474
9866
|
// iii/stream.ts
|
|
9475
9867
|
function notify(channels, stream, group, item, event, data) {
|
|
9476
|
-
const keys = [
|
|
9477
|
-
|
|
9478
|
-
|
|
9479
|
-
|
|
9480
|
-
|
|
9481
|
-
|
|
9868
|
+
const keys = [`${stream}`, `${stream}:${group}`, `${stream}:${group}:${item}`];
|
|
9869
|
+
const msg = JSON.stringify({
|
|
9870
|
+
type: "stream",
|
|
9871
|
+
stream_name: stream,
|
|
9872
|
+
group_id: group,
|
|
9873
|
+
item_id: item,
|
|
9874
|
+
event,
|
|
9875
|
+
data
|
|
9876
|
+
});
|
|
9482
9877
|
for (const key of keys) {
|
|
9483
9878
|
const subs = channels.get(key);
|
|
9484
9879
|
if (!subs) continue;
|
|
@@ -9697,10 +10092,13 @@ function createRedisStore(channels, redis2, ttl) {
|
|
|
9697
10092
|
async set(stream, group, item, data) {
|
|
9698
10093
|
const hk = hashKey(stream, group);
|
|
9699
10094
|
const oldRaw = await redis2.hget(hk, item);
|
|
9700
|
-
|
|
10095
|
+
const old = oldRaw ? JSON.parse(oldRaw) : null;
|
|
9701
10096
|
await redis2.hset(hk, item, JSON.stringify(data));
|
|
9702
10097
|
setTTL(hk);
|
|
9703
|
-
await redis2.publish(
|
|
10098
|
+
await redis2.publish(
|
|
10099
|
+
`iii:stream:${stream}`,
|
|
10100
|
+
JSON.stringify({ event: "set", group, item, data })
|
|
10101
|
+
);
|
|
9704
10102
|
notify(channels, stream, group, item, "set", data);
|
|
9705
10103
|
return { old_value: old, new_value: deepClone(data) };
|
|
9706
10104
|
},
|
|
@@ -9776,7 +10174,10 @@ function createRedisStore(channels, redis2, ttl) {
|
|
|
9776
10174
|
const newVal = applyOps(old, ops);
|
|
9777
10175
|
await redis2.hset(hk, item, JSON.stringify(newVal));
|
|
9778
10176
|
setTTL(hk);
|
|
9779
|
-
await redis2.publish(
|
|
10177
|
+
await redis2.publish(
|
|
10178
|
+
`iii:stream:${stream}`,
|
|
10179
|
+
JSON.stringify({ event: "update", group, item, data: newVal })
|
|
10180
|
+
);
|
|
9780
10181
|
notify(channels, stream, group, item, "update", newVal);
|
|
9781
10182
|
return { old_value: old, new_value: deepClone(newVal) };
|
|
9782
10183
|
}
|
|
@@ -9856,10 +10257,7 @@ function createWsHandler(deps) {
|
|
|
9856
10257
|
}
|
|
9857
10258
|
switch (msg.type) {
|
|
9858
10259
|
case "register_worker": {
|
|
9859
|
-
const workerId = deps.registerRemoteWorker(
|
|
9860
|
-
ws,
|
|
9861
|
-
msg.worker_name || `remote-${Date.now()}`
|
|
9862
|
-
);
|
|
10260
|
+
const workerId = deps.registerRemoteWorker(ws, msg.worker_name || `remote-${Date.now()}`);
|
|
9863
10261
|
wsToWorkerId.set(ws, workerId);
|
|
9864
10262
|
ws.send(JSON.stringify({ type: "registered", worker_id: workerId }));
|
|
9865
10263
|
break;
|
|
@@ -9963,10 +10361,7 @@ function buildRouter5(engine, wsHandler) {
|
|
|
9963
10361
|
}
|
|
9964
10362
|
return Response.json(result);
|
|
9965
10363
|
} catch (err) {
|
|
9966
|
-
return Response.json(
|
|
9967
|
-
{ error: err.message || "Internal error" },
|
|
9968
|
-
{ status: 500 }
|
|
9969
|
-
);
|
|
10364
|
+
return Response.json({ error: err.message || "Internal error" }, { status: 500 });
|
|
9970
10365
|
}
|
|
9971
10366
|
});
|
|
9972
10367
|
r.ws("/worker", wsHandler);
|
|
@@ -9989,14 +10384,23 @@ function iii(opts = {}) {
|
|
|
9989
10384
|
triggers: []
|
|
9990
10385
|
});
|
|
9991
10386
|
}
|
|
9992
|
-
registerBuiltin(
|
|
10387
|
+
registerBuiltin(
|
|
10388
|
+
"stream::set",
|
|
10389
|
+
(p) => stream.set(p.stream_name, p.group_id, p.item_id, p.data)
|
|
10390
|
+
);
|
|
9993
10391
|
registerBuiltin("stream::get", (p) => stream.get(p.stream_name, p.group_id, p.item_id));
|
|
9994
10392
|
registerBuiltin("stream::delete", (p) => stream.delete(p.stream_name, p.group_id, p.item_id));
|
|
9995
10393
|
registerBuiltin("stream::list", (p) => stream.list(p.stream_name, p.group_id));
|
|
9996
10394
|
registerBuiltin("stream::list_groups", (p) => stream.list_groups(p.stream_name));
|
|
9997
10395
|
registerBuiltin("stream::list_all", () => stream.list_all());
|
|
9998
|
-
registerBuiltin(
|
|
9999
|
-
|
|
10396
|
+
registerBuiltin(
|
|
10397
|
+
"stream::send",
|
|
10398
|
+
(p) => stream.send(p.stream_name, p.group_id, p.type, p.data, p.id)
|
|
10399
|
+
);
|
|
10400
|
+
registerBuiltin(
|
|
10401
|
+
"stream::update",
|
|
10402
|
+
(p) => stream.update(p.stream_name, p.group_id, p.item_id, p.ops)
|
|
10403
|
+
);
|
|
10000
10404
|
function addLocalWorker(worker) {
|
|
10001
10405
|
const workerId = crypto8.randomUUID();
|
|
10002
10406
|
const reg = {
|
|
@@ -10049,12 +10453,14 @@ function iii(opts = {}) {
|
|
|
10049
10453
|
reject(new Error(`Invocation timed out for "${id2}"`));
|
|
10050
10454
|
}, 3e4);
|
|
10051
10455
|
pending.set(invocationId, { resolve: resolve14, reject, timer });
|
|
10052
|
-
worker.ws.send(
|
|
10053
|
-
|
|
10054
|
-
|
|
10055
|
-
|
|
10056
|
-
|
|
10057
|
-
|
|
10456
|
+
worker.ws.send(
|
|
10457
|
+
JSON.stringify({
|
|
10458
|
+
type: "invoke",
|
|
10459
|
+
invocation_id: invocationId,
|
|
10460
|
+
function_id: id2,
|
|
10461
|
+
payload
|
|
10462
|
+
})
|
|
10463
|
+
);
|
|
10058
10464
|
});
|
|
10059
10465
|
};
|
|
10060
10466
|
const fnReg = {
|
|
@@ -10138,18 +10544,26 @@ function iii(opts = {}) {
|
|
|
10138
10544
|
handleInvoke(ws, invocationId, functionId, payload) {
|
|
10139
10545
|
const fn = functions.get(functionId);
|
|
10140
10546
|
if (!fn) {
|
|
10141
|
-
ws.send(
|
|
10142
|
-
|
|
10143
|
-
|
|
10144
|
-
|
|
10145
|
-
|
|
10547
|
+
ws.send(
|
|
10548
|
+
JSON.stringify({
|
|
10549
|
+
type: "invoke_error",
|
|
10550
|
+
invocation_id: invocationId,
|
|
10551
|
+
error: `Function "${functionId}" not found`
|
|
10552
|
+
})
|
|
10553
|
+
);
|
|
10146
10554
|
return;
|
|
10147
10555
|
}
|
|
10148
10556
|
const ctx = { engine: engineRef, functionId, workerName: fn.workerName };
|
|
10149
10557
|
Promise.resolve(fn.handler(payload, ctx)).then((result) => {
|
|
10150
10558
|
ws.send(JSON.stringify({ type: "invoke_result", invocation_id: invocationId, result }));
|
|
10151
10559
|
}).catch((err) => {
|
|
10152
|
-
ws.send(
|
|
10560
|
+
ws.send(
|
|
10561
|
+
JSON.stringify({
|
|
10562
|
+
type: "invoke_error",
|
|
10563
|
+
invocation_id: invocationId,
|
|
10564
|
+
error: err.message
|
|
10565
|
+
})
|
|
10566
|
+
);
|
|
10153
10567
|
});
|
|
10154
10568
|
}
|
|
10155
10569
|
});
|
|
@@ -10313,25 +10727,31 @@ function registerWorker(url) {
|
|
|
10313
10727
|
case "invoke": {
|
|
10314
10728
|
const handler = handlers.get(msg.function_id);
|
|
10315
10729
|
if (!handler) {
|
|
10316
|
-
ws?.send(
|
|
10317
|
-
|
|
10318
|
-
|
|
10319
|
-
|
|
10320
|
-
|
|
10730
|
+
ws?.send(
|
|
10731
|
+
JSON.stringify({
|
|
10732
|
+
type: "invoke_error",
|
|
10733
|
+
invocation_id: msg.invocation_id,
|
|
10734
|
+
error: `Function "${msg.function_id}" not found`
|
|
10735
|
+
})
|
|
10736
|
+
);
|
|
10321
10737
|
return;
|
|
10322
10738
|
}
|
|
10323
10739
|
Promise.resolve(handler(msg.payload, {})).then((result) => {
|
|
10324
|
-
ws?.send(
|
|
10325
|
-
|
|
10326
|
-
|
|
10327
|
-
|
|
10328
|
-
|
|
10740
|
+
ws?.send(
|
|
10741
|
+
JSON.stringify({
|
|
10742
|
+
type: "invoke_result",
|
|
10743
|
+
invocation_id: msg.invocation_id,
|
|
10744
|
+
result
|
|
10745
|
+
})
|
|
10746
|
+
);
|
|
10329
10747
|
}).catch((err) => {
|
|
10330
|
-
ws?.send(
|
|
10331
|
-
|
|
10332
|
-
|
|
10333
|
-
|
|
10334
|
-
|
|
10748
|
+
ws?.send(
|
|
10749
|
+
JSON.stringify({
|
|
10750
|
+
type: "invoke_error",
|
|
10751
|
+
invocation_id: msg.invocation_id,
|
|
10752
|
+
error: err.message
|
|
10753
|
+
})
|
|
10754
|
+
);
|
|
10335
10755
|
});
|
|
10336
10756
|
break;
|
|
10337
10757
|
}
|
|
@@ -10385,7 +10805,12 @@ function registerWorker(url) {
|
|
|
10385
10805
|
},
|
|
10386
10806
|
registerTrigger(input) {
|
|
10387
10807
|
registeredTriggers.add(JSON.stringify(input));
|
|
10388
|
-
send({
|
|
10808
|
+
send({
|
|
10809
|
+
type: "register_trigger",
|
|
10810
|
+
function_id: input.function_id,
|
|
10811
|
+
trigger_type: input.type,
|
|
10812
|
+
config: input.config
|
|
10813
|
+
});
|
|
10389
10814
|
},
|
|
10390
10815
|
unregisterTrigger(functionId) {
|
|
10391
10816
|
for (const key of registeredTriggers) {
|
|
@@ -10560,8 +10985,18 @@ function createSessionObject(data, sid, store2, ttl, createdAt) {
|
|
|
10560
10985
|
enumerable: false,
|
|
10561
10986
|
configurable: false
|
|
10562
10987
|
});
|
|
10563
|
-
Object.defineProperty(obj, "save", {
|
|
10564
|
-
|
|
10988
|
+
Object.defineProperty(obj, "save", {
|
|
10989
|
+
enumerable: false,
|
|
10990
|
+
configurable: true,
|
|
10991
|
+
writable: true,
|
|
10992
|
+
value: obj.save
|
|
10993
|
+
});
|
|
10994
|
+
Object.defineProperty(obj, "destroy", {
|
|
10995
|
+
enumerable: false,
|
|
10996
|
+
configurable: true,
|
|
10997
|
+
writable: true,
|
|
10998
|
+
value: obj.destroy
|
|
10999
|
+
});
|
|
10565
11000
|
return obj;
|
|
10566
11001
|
}
|
|
10567
11002
|
function isSessionActive(session2) {
|
|
@@ -10931,7 +11366,8 @@ function createStripeVerifier(config) {
|
|
|
10931
11366
|
}, {});
|
|
10932
11367
|
const timestamp = parts["t"];
|
|
10933
11368
|
const signature = parts["v1"];
|
|
10934
|
-
if (!timestamp || !signature)
|
|
11369
|
+
if (!timestamp || !signature)
|
|
11370
|
+
return { valid: false, provider: "stripe", event: "", id: void 0 };
|
|
10935
11371
|
const signed = `${timestamp}.${body}`;
|
|
10936
11372
|
const expected = crypto11.createHmac("sha256", config.secret).update(signed).digest("hex");
|
|
10937
11373
|
const valid = timingSafeEqual2(signature, expected);
|
|
@@ -10952,7 +11388,7 @@ function createGitHubVerifier(config) {
|
|
|
10952
11388
|
if (!sig) return { valid: false, provider: "github", event: "", id: void 0 };
|
|
10953
11389
|
const expected = `sha256=${crypto11.createHmac("sha256", config.secret).update(body).digest("hex")}`;
|
|
10954
11390
|
const valid = timingSafeEqual2(sig, expected);
|
|
10955
|
-
|
|
11391
|
+
const event = headers["x-github-event"] ?? "";
|
|
10956
11392
|
let id2;
|
|
10957
11393
|
try {
|
|
10958
11394
|
const parsed = JSON.parse(body);
|
|
@@ -10966,7 +11402,8 @@ function createSlackVerifier(config) {
|
|
|
10966
11402
|
return (body, headers) => {
|
|
10967
11403
|
const signature = headers["x-slack-signature"];
|
|
10968
11404
|
const timestamp = headers["x-slack-request-timestamp"];
|
|
10969
|
-
if (!signature || !timestamp)
|
|
11405
|
+
if (!signature || !timestamp)
|
|
11406
|
+
return { valid: false, provider: "slack", event: "", id: void 0 };
|
|
10970
11407
|
const now = Math.floor(Date.now() / 1e3);
|
|
10971
11408
|
const ts = parseInt(timestamp, 10);
|
|
10972
11409
|
if (isNaN(ts) || Math.abs(now - ts) > 300) {
|
|
@@ -11128,11 +11565,7 @@ __export(fts_exports, {
|
|
|
11128
11565
|
suggest: () => suggest
|
|
11129
11566
|
});
|
|
11130
11567
|
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;
|
|
11568
|
+
return table.tableName;
|
|
11136
11569
|
}
|
|
11137
11570
|
function escapeIdent4(s) {
|
|
11138
11571
|
return `"${s.replace(/"/g, '""')}"`;
|
|
@@ -11344,7 +11777,15 @@ function escapeIdent5(s) {
|
|
|
11344
11777
|
return `"${s.replace(/"/g, '""')}"`;
|
|
11345
11778
|
}
|
|
11346
11779
|
function knowledgeBase(options) {
|
|
11347
|
-
const {
|
|
11780
|
+
const {
|
|
11781
|
+
pg,
|
|
11782
|
+
provider,
|
|
11783
|
+
table = "_kb_docs",
|
|
11784
|
+
chunkSize = 512,
|
|
11785
|
+
chunkOverlap = 64,
|
|
11786
|
+
searchLimit = 5,
|
|
11787
|
+
searchThreshold = 0
|
|
11788
|
+
} = options;
|
|
11348
11789
|
const sql2 = pg.sql;
|
|
11349
11790
|
const dimension = provider.dimension;
|
|
11350
11791
|
const docsTable = pg.table(table, {
|