weifuwu 0.23.3 → 0.24.0
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 +234 -63
- package/cli.ts +3 -0
- package/dist/ai/provider.d.ts +10 -1
- package/dist/cli.js +3 -0
- package/dist/csrf.d.ts +11 -5
- package/dist/env.d.ts +41 -0
- package/dist/flash.d.ts +5 -0
- package/dist/i18n.d.ts +27 -2
- package/dist/iii/types.d.ts +2 -0
- package/dist/index.d.ts +8 -10
- package/dist/index.js +343 -275
- package/dist/rate-limit.d.ts +2 -1
- package/dist/request-id.d.ts +16 -7
- package/dist/router.d.ts +3 -0
- package/dist/theme.d.ts +25 -2
- package/dist/trace.d.ts +44 -0
- package/dist/types.d.ts +0 -17
- package/dist/upload.d.ts +5 -0
- package/dist/user/client.d.ts +11 -3
- package/dist/user/types.d.ts +19 -4
- package/dist/validate.d.ts +5 -0
- package/package.json +2 -2
- package/dist/kb.d.ts +0 -70
- package/dist/oauth-client.d.ts +0 -41
- package/dist/preferences.d.ts +0 -18
- package/dist/server.d.ts +0 -1
package/dist/index.js
CHANGED
|
@@ -5,8 +5,8 @@ var __export = (target, all) => {
|
|
|
5
5
|
};
|
|
6
6
|
|
|
7
7
|
// trace.ts
|
|
8
|
+
import crypto2 from "node:crypto";
|
|
8
9
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
9
|
-
import { randomUUID } from "node:crypto";
|
|
10
10
|
var als = new AsyncLocalStorage();
|
|
11
11
|
function currentTraceId() {
|
|
12
12
|
return als.getStore()?.traceId;
|
|
@@ -15,7 +15,7 @@ function currentTrace() {
|
|
|
15
15
|
return als.getStore();
|
|
16
16
|
}
|
|
17
17
|
function runWithTrace(incomingTraceId, fn) {
|
|
18
|
-
const traceId = incomingTraceId || randomUUID();
|
|
18
|
+
const traceId = incomingTraceId || crypto2.randomUUID();
|
|
19
19
|
const startTime = Date.now();
|
|
20
20
|
return als.run({ traceId, startTime }, fn);
|
|
21
21
|
}
|
|
@@ -24,10 +24,46 @@ function traceElapsed() {
|
|
|
24
24
|
if (!ctx) return 0;
|
|
25
25
|
return Date.now() - ctx.startTime;
|
|
26
26
|
}
|
|
27
|
+
function trace(options) {
|
|
28
|
+
const header = options?.header ?? "X-Request-ID";
|
|
29
|
+
const gen = options?.generator ?? (() => crypto2.randomUUID());
|
|
30
|
+
return async (req, ctx, next) => {
|
|
31
|
+
const existing = req.headers.get(header);
|
|
32
|
+
const requestId2 = existing ?? gen();
|
|
33
|
+
const tc = als.getStore();
|
|
34
|
+
ctx.trace = {
|
|
35
|
+
requestId: requestId2,
|
|
36
|
+
traceId: tc?.traceId ?? requestId2,
|
|
37
|
+
startTime: tc?.startTime ?? Date.now(),
|
|
38
|
+
elapsed: () => {
|
|
39
|
+
const t = als.getStore();
|
|
40
|
+
return t ? Date.now() - t.startTime : 0;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const res = await next(req, ctx);
|
|
44
|
+
if (res.headers.has(header)) return res;
|
|
45
|
+
const h = new Headers(res.headers);
|
|
46
|
+
h.set(header, requestId2);
|
|
47
|
+
return new Response(res.body, { status: res.status, statusText: res.statusText, headers: h });
|
|
48
|
+
};
|
|
49
|
+
}
|
|
27
50
|
|
|
28
51
|
// env.ts
|
|
29
52
|
import { readFileSync } from "node:fs";
|
|
30
53
|
import { resolve } from "node:path";
|
|
54
|
+
var PUBLIC_PREFIX = "WEIFUWU_PUBLIC_";
|
|
55
|
+
function getPublicEnv() {
|
|
56
|
+
const result = {};
|
|
57
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
58
|
+
if (key.startsWith(PUBLIC_PREFIX) && value !== void 0) {
|
|
59
|
+
result[key.slice(PUBLIC_PREFIX.length)] = value;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
function isBundled() {
|
|
65
|
+
return true ? true : false;
|
|
66
|
+
}
|
|
31
67
|
function isDev() {
|
|
32
68
|
return process.env.NODE_ENV === "development";
|
|
33
69
|
}
|
|
@@ -62,6 +98,14 @@ function loadEnv(path2) {
|
|
|
62
98
|
process.env[key] = value;
|
|
63
99
|
}
|
|
64
100
|
}
|
|
101
|
+
function env() {
|
|
102
|
+
const entries = getPublicEnv();
|
|
103
|
+
return async (req, ctx, next) => {
|
|
104
|
+
;
|
|
105
|
+
ctx.env = entries;
|
|
106
|
+
return next(req, ctx);
|
|
107
|
+
};
|
|
108
|
+
}
|
|
65
109
|
|
|
66
110
|
// serve.ts
|
|
67
111
|
import http from "node:http";
|
|
@@ -444,6 +488,10 @@ var Router = class _Router {
|
|
|
444
488
|
}
|
|
445
489
|
} else if (typeof arg1 === "function") {
|
|
446
490
|
this.globalMws.push(arg1);
|
|
491
|
+
} else if (typeof arg1 === "object" && arg1 !== null && "middleware" in arg1 && typeof arg1.middleware === "function" && arg1 instanceof _Router) {
|
|
492
|
+
const mod = arg1;
|
|
493
|
+
this.globalMws.push(mod.middleware());
|
|
494
|
+
this._mountRouter("/", mod);
|
|
447
495
|
}
|
|
448
496
|
return this;
|
|
449
497
|
}
|
|
@@ -988,114 +1036,6 @@ function cors(options) {
|
|
|
988
1036
|
};
|
|
989
1037
|
}
|
|
990
1038
|
|
|
991
|
-
// auth.ts
|
|
992
|
-
function auth(options) {
|
|
993
|
-
if (!options.token && !options.verify && !options.proxy && !options.session) {
|
|
994
|
-
throw new Error("auth() requires at least one of: token, verify, proxy, or session");
|
|
995
|
-
}
|
|
996
|
-
return async (req, ctx, next) => {
|
|
997
|
-
if (options.session) {
|
|
998
|
-
const sessionUserId = ctx.session?.userId;
|
|
999
|
-
if (sessionUserId !== void 0 && sessionUserId !== null) {
|
|
1000
|
-
if (options.resolveUser) {
|
|
1001
|
-
const userData = await options.resolveUser(sessionUserId);
|
|
1002
|
-
if (userData) {
|
|
1003
|
-
ctx.user = userData;
|
|
1004
|
-
return next(req, ctx);
|
|
1005
|
-
}
|
|
1006
|
-
if (typeof ctx.session?.destroy === "function") {
|
|
1007
|
-
;
|
|
1008
|
-
ctx.session.destroy();
|
|
1009
|
-
}
|
|
1010
|
-
console.warn(`[${currentTraceId()}] auth: session userId ${sessionUserId} resolved to null`);
|
|
1011
|
-
} else {
|
|
1012
|
-
ctx.user = { id: sessionUserId };
|
|
1013
|
-
return next(req, ctx);
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
const headerName = options.header ?? "Authorization";
|
|
1018
|
-
let from = "header";
|
|
1019
|
-
let header = req.headers.get(headerName);
|
|
1020
|
-
let token = "";
|
|
1021
|
-
if (header) {
|
|
1022
|
-
token = header.trim();
|
|
1023
|
-
if (headerName.toLowerCase() === "authorization") {
|
|
1024
|
-
const parts = header.split(" ");
|
|
1025
|
-
if (parts[0]?.toLowerCase() === "bearer") {
|
|
1026
|
-
token = parts.slice(1).join(" ").trim();
|
|
1027
|
-
}
|
|
1028
|
-
}
|
|
1029
|
-
} else if (!options.header) {
|
|
1030
|
-
const url = new URL(req.url);
|
|
1031
|
-
const qsToken = url.searchParams.get("access_token");
|
|
1032
|
-
if (qsToken) {
|
|
1033
|
-
token = qsToken;
|
|
1034
|
-
from = "query";
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
if (!token) {
|
|
1038
|
-
return new Response("Unauthorized", {
|
|
1039
|
-
status: 401,
|
|
1040
|
-
headers: headerName.toLowerCase() === "authorization" ? { "WWW-Authenticate": "Bearer" } : void 0
|
|
1041
|
-
});
|
|
1042
|
-
}
|
|
1043
|
-
if (options.proxy) {
|
|
1044
|
-
let proxyUrl;
|
|
1045
|
-
try {
|
|
1046
|
-
proxyUrl = typeof options.proxy === "string" ? new URL(options.proxy) : options.proxy;
|
|
1047
|
-
} catch {
|
|
1048
|
-
return new Response("Invalid proxy URL", { status: 500 });
|
|
1049
|
-
}
|
|
1050
|
-
const proxyHeaders = {};
|
|
1051
|
-
if (from === "header" && header) {
|
|
1052
|
-
proxyHeaders[headerName] = header;
|
|
1053
|
-
} else {
|
|
1054
|
-
proxyUrl.searchParams.set("access_token", token);
|
|
1055
|
-
}
|
|
1056
|
-
for (const name of ["x-forwarded-for", "x-real-ip", "user-agent", "content-type"]) {
|
|
1057
|
-
const v = req.headers.get(name);
|
|
1058
|
-
if (v) proxyHeaders[name] = v;
|
|
1059
|
-
}
|
|
1060
|
-
const proxyRes = await fetch(proxyUrl.href, { headers: proxyHeaders });
|
|
1061
|
-
if (proxyRes.status >= 400) {
|
|
1062
|
-
return new Response(await proxyRes.text() || "Forbidden", { status: proxyRes.status });
|
|
1063
|
-
}
|
|
1064
|
-
let userData = void 0;
|
|
1065
|
-
if (proxyRes.status === 200) {
|
|
1066
|
-
const ct = proxyRes.headers.get("content-type");
|
|
1067
|
-
if (ct?.includes("application/json")) {
|
|
1068
|
-
try {
|
|
1069
|
-
userData = await proxyRes.json();
|
|
1070
|
-
} catch {
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1073
|
-
}
|
|
1074
|
-
ctx.user = userData;
|
|
1075
|
-
return next(req, ctx);
|
|
1076
|
-
}
|
|
1077
|
-
if (options.token) {
|
|
1078
|
-
if (token !== options.token) {
|
|
1079
|
-
console.warn(`[${currentTraceId()}] auth: invalid static token`);
|
|
1080
|
-
return new Response("Forbidden", { status: 403 });
|
|
1081
|
-
}
|
|
1082
|
-
return next(req, ctx);
|
|
1083
|
-
}
|
|
1084
|
-
if (options.verify) {
|
|
1085
|
-
const result = await options.verify(token, req);
|
|
1086
|
-
if (!result) {
|
|
1087
|
-
console.warn(`[${currentTraceId()}] auth: verify failed for token`);
|
|
1088
|
-
return new Response("Forbidden", { status: 403 });
|
|
1089
|
-
}
|
|
1090
|
-
if (typeof result === "object" && result !== null) {
|
|
1091
|
-
ctx.user = result;
|
|
1092
|
-
}
|
|
1093
|
-
return next(req, ctx);
|
|
1094
|
-
}
|
|
1095
|
-
return next(req, ctx);
|
|
1096
|
-
};
|
|
1097
|
-
}
|
|
1098
|
-
|
|
1099
1039
|
// static.ts
|
|
1100
1040
|
import { open, realpath } from "node:fs/promises";
|
|
1101
1041
|
import { extname, resolve as resolve2, normalize, sep } from "node:path";
|
|
@@ -1379,7 +1319,7 @@ function deleteCookie(res, name, options) {
|
|
|
1379
1319
|
|
|
1380
1320
|
// upload.ts
|
|
1381
1321
|
import { writeFile, mkdir } from "node:fs/promises";
|
|
1382
|
-
import { randomUUID
|
|
1322
|
+
import { randomUUID } from "node:crypto";
|
|
1383
1323
|
import { join, extname as extname2 } from "node:path";
|
|
1384
1324
|
var extensionMimeMap = {
|
|
1385
1325
|
".jpg": "image/jpeg",
|
|
@@ -1451,7 +1391,7 @@ function upload(options) {
|
|
|
1451
1391
|
};
|
|
1452
1392
|
if (saveDir) {
|
|
1453
1393
|
const safeName = value.name.replace(/[/\\\0]/g, "_").replace(/\.\./g, "_");
|
|
1454
|
-
const filePath = join(saveDir, `${
|
|
1394
|
+
const filePath = join(saveDir, `${randomUUID()}-${safeName}`);
|
|
1455
1395
|
await writeFile(filePath, buf);
|
|
1456
1396
|
uf.path = filePath;
|
|
1457
1397
|
}
|
|
@@ -1548,10 +1488,11 @@ function rateLimit(options) {
|
|
|
1548
1488
|
const res = await next(req, ctx);
|
|
1549
1489
|
return addRateLimitHeaders(res, max, remaining, reset);
|
|
1550
1490
|
};
|
|
1551
|
-
mw.
|
|
1491
|
+
mw.close = () => {
|
|
1552
1492
|
if (interval) clearInterval(interval);
|
|
1553
1493
|
hits.clear();
|
|
1554
1494
|
};
|
|
1495
|
+
mw.stop = mw.close;
|
|
1555
1496
|
mw.stats = () => ({
|
|
1556
1497
|
store: storeType,
|
|
1557
1498
|
entries: storeType === "memory" ? hits.size : void 0,
|
|
@@ -1669,10 +1610,10 @@ var DEFAULTS = {
|
|
|
1669
1610
|
};
|
|
1670
1611
|
|
|
1671
1612
|
// request-id.ts
|
|
1672
|
-
import
|
|
1613
|
+
import crypto3 from "node:crypto";
|
|
1673
1614
|
function requestId(options) {
|
|
1674
1615
|
const header = options?.header ?? "X-Request-ID";
|
|
1675
|
-
const gen = options?.generator ?? (() =>
|
|
1616
|
+
const gen = options?.generator ?? (() => crypto3.randomUUID());
|
|
1676
1617
|
return async (req, ctx, next) => {
|
|
1677
1618
|
const existing = req.headers.get(header);
|
|
1678
1619
|
const id2 = existing ?? gen();
|
|
@@ -2422,7 +2363,7 @@ function aiProvider(options) {
|
|
|
2422
2363
|
const client = createOpenAI({ baseURL, apiKey });
|
|
2423
2364
|
let _model;
|
|
2424
2365
|
let _embedModel;
|
|
2425
|
-
|
|
2366
|
+
const provider = {
|
|
2426
2367
|
get dimension() {
|
|
2427
2368
|
return dimension;
|
|
2428
2369
|
},
|
|
@@ -2451,6 +2392,12 @@ function aiProvider(options) {
|
|
|
2451
2392
|
return aiStreamText({ ...params, model: this.model() });
|
|
2452
2393
|
}
|
|
2453
2394
|
};
|
|
2395
|
+
const mw = async (req, ctx, next) => {
|
|
2396
|
+
;
|
|
2397
|
+
ctx.ai = provider;
|
|
2398
|
+
return next(req, ctx);
|
|
2399
|
+
};
|
|
2400
|
+
return Object.assign(mw, provider);
|
|
2454
2401
|
}
|
|
2455
2402
|
|
|
2456
2403
|
// ai-sdk.ts
|
|
@@ -3123,7 +3070,7 @@ import jwt2 from "jsonwebtoken";
|
|
|
3123
3070
|
import { z as z2 } from "zod";
|
|
3124
3071
|
|
|
3125
3072
|
// user/oauth2.ts
|
|
3126
|
-
import
|
|
3073
|
+
import crypto4 from "node:crypto";
|
|
3127
3074
|
import jwt from "jsonwebtoken";
|
|
3128
3075
|
function createOAuth2Server(deps) {
|
|
3129
3076
|
const { pg, users, jwtSecret, expiresIn } = deps;
|
|
@@ -3142,8 +3089,8 @@ function createOAuth2Server(deps) {
|
|
|
3142
3089
|
};
|
|
3143
3090
|
}
|
|
3144
3091
|
async function registerClient(data) {
|
|
3145
|
-
const clientId =
|
|
3146
|
-
const clientSecret =
|
|
3092
|
+
const clientId = crypto4.randomUUID();
|
|
3093
|
+
const clientSecret = crypto4.randomBytes(32).toString("hex");
|
|
3147
3094
|
const [row] = await pg.sql`
|
|
3148
3095
|
INSERT INTO "_oauth2_clients" ("name", "client_id", "client_secret", "redirect_uris")
|
|
3149
3096
|
VALUES (${data.name}, ${clientId}, ${clientSecret}, ${pg.sql.array(data.redirectUris)})
|
|
@@ -3291,7 +3238,7 @@ h2{color:#dc2626}.desc{color:#555}</style>
|
|
|
3291
3238
|
const loc2 = `${redirectUri}?error=access_denied${state ? `&state=${state}` : ""}`;
|
|
3292
3239
|
return Response.redirect(loc2, 302);
|
|
3293
3240
|
}
|
|
3294
|
-
const code =
|
|
3241
|
+
const code = crypto4.randomUUID();
|
|
3295
3242
|
const expiresAt = new Date(Date.now() + 10 * 60 * 1e3);
|
|
3296
3243
|
await pg.sql`
|
|
3297
3244
|
INSERT INTO "_oauth2_codes" ("code", "client_id", "user_id", "redirect_uri", "code_challenge", "code_challenge_method", "scope", "expires_at")
|
|
@@ -3356,7 +3303,7 @@ h2{color:#dc2626}.desc{color:#555}</style>
|
|
|
3356
3303
|
if (stored.code_challenge_method === "plain") {
|
|
3357
3304
|
expected = codeVerifier;
|
|
3358
3305
|
} else {
|
|
3359
|
-
expected =
|
|
3306
|
+
expected = crypto4.createHash("sha256").update(codeVerifier).digest().toString("base64url");
|
|
3360
3307
|
}
|
|
3361
3308
|
if (expected !== stored.code_challenge) {
|
|
3362
3309
|
return Response.json({ error: "invalid_grant", error_description: "code_verifier mismatch" }, { status: 400 });
|
|
@@ -3373,7 +3320,7 @@ h2{color:#dc2626}.desc{color:#555}</style>
|
|
|
3373
3320
|
jwtSecret,
|
|
3374
3321
|
{ expiresIn }
|
|
3375
3322
|
);
|
|
3376
|
-
const refreshToken =
|
|
3323
|
+
const refreshToken = crypto4.randomUUID();
|
|
3377
3324
|
const refreshExpires = new Date(Date.now() + 30 * 24 * 60 * 60 * 1e3);
|
|
3378
3325
|
await pg.sql`
|
|
3379
3326
|
INSERT INTO "_oauth2_tokens" ("token", "client_id", "user_id", "scope", "expires_at")
|
|
@@ -3411,7 +3358,7 @@ h2{color:#dc2626}.desc{color:#555}</style>
|
|
|
3411
3358
|
}
|
|
3412
3359
|
|
|
3413
3360
|
// user/oauth-login.ts
|
|
3414
|
-
import
|
|
3361
|
+
import crypto5 from "node:crypto";
|
|
3415
3362
|
var BUILTIN_PROVIDERS = {
|
|
3416
3363
|
google: {
|
|
3417
3364
|
authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
@@ -3523,7 +3470,7 @@ function registerOAuthLoginRoutes(router, deps, providers) {
|
|
|
3523
3470
|
return Response.json({ error: `Unsupported provider: ${providerName}` }, { status: 400 });
|
|
3524
3471
|
}
|
|
3525
3472
|
const { config, meta } = resolved;
|
|
3526
|
-
const state =
|
|
3473
|
+
const state = crypto5.randomUUID();
|
|
3527
3474
|
const redirectUri = new URL(req.url);
|
|
3528
3475
|
redirectUri.pathname = redirectUri.pathname.replace(/\/[^/]+$/, "/") + providerName + "/callback";
|
|
3529
3476
|
if (ctx.session) {
|
|
@@ -3654,14 +3601,40 @@ function verifyPassword(password, stored) {
|
|
|
3654
3601
|
if (hash.length !== verify.length) return false;
|
|
3655
3602
|
return timingSafeEqual(Buffer.from(hash), Buffer.from(verify));
|
|
3656
3603
|
}
|
|
3604
|
+
function extractToken(req, headerName, cookieName) {
|
|
3605
|
+
const header = req.headers.get(headerName);
|
|
3606
|
+
if (header) {
|
|
3607
|
+
if (headerName.toLowerCase() === "authorization") {
|
|
3608
|
+
const parts = header.split(" ");
|
|
3609
|
+
if (parts[0]?.toLowerCase() === "bearer") {
|
|
3610
|
+
return parts.slice(1).join(" ").trim();
|
|
3611
|
+
}
|
|
3612
|
+
}
|
|
3613
|
+
return header.trim();
|
|
3614
|
+
}
|
|
3615
|
+
if (headerName.toLowerCase() === "authorization") {
|
|
3616
|
+
const url = new URL(req.url);
|
|
3617
|
+
const qsToken = url.searchParams.get("access_token");
|
|
3618
|
+
if (qsToken) return qsToken;
|
|
3619
|
+
}
|
|
3620
|
+
if (cookieName) {
|
|
3621
|
+
const cookies = req.headers.get("cookie")?.split(";").map((c) => c.trim()).filter(Boolean) || [];
|
|
3622
|
+
for (const c of cookies) {
|
|
3623
|
+
const eq2 = c.indexOf("=");
|
|
3624
|
+
if (eq2 > 0 && c.slice(0, eq2) === cookieName) return c.slice(eq2 + 1);
|
|
3625
|
+
}
|
|
3626
|
+
}
|
|
3627
|
+
return null;
|
|
3628
|
+
}
|
|
3657
3629
|
function user(options) {
|
|
3630
|
+
const hasDb = !!options.pg;
|
|
3658
3631
|
const table = options.table ?? "_users";
|
|
3659
3632
|
const pg = options.pg;
|
|
3660
3633
|
const secret = options.jwtSecret;
|
|
3661
3634
|
const expiresIn = options.expiresIn ?? "24h";
|
|
3662
3635
|
const oauth2Enabled = options.oauth2?.server ?? false;
|
|
3663
|
-
const base = new PgModule(pg);
|
|
3664
|
-
const users = pg.table(table, {
|
|
3636
|
+
const base = hasDb ? new PgModule(pg) : null;
|
|
3637
|
+
const users = hasDb ? pg.table(table, {
|
|
3665
3638
|
id: serial("id").primaryKey(),
|
|
3666
3639
|
email: text("email").unique().notNull(),
|
|
3667
3640
|
password: text("password").notNull(),
|
|
@@ -3669,15 +3642,17 @@ function user(options) {
|
|
|
3669
3642
|
role: text("role").default("user"),
|
|
3670
3643
|
created_at: timestamptz("created_at").default(sql`NOW()`),
|
|
3671
3644
|
updated_at: timestamptz("updated_at").default(sql`NOW()`)
|
|
3672
|
-
});
|
|
3645
|
+
}) : null;
|
|
3646
|
+
const _pg = pg;
|
|
3647
|
+
const _users = users;
|
|
3673
3648
|
let oauth2 = null;
|
|
3674
3649
|
if (oauth2Enabled) {
|
|
3675
|
-
oauth2 = createOAuth2Server({ pg, users, jwtSecret: secret, expiresIn });
|
|
3650
|
+
oauth2 = createOAuth2Server({ pg: _pg, users: _users, jwtSecret: secret, expiresIn });
|
|
3676
3651
|
}
|
|
3677
3652
|
async function migrate() {
|
|
3678
|
-
await
|
|
3653
|
+
await _users.create();
|
|
3679
3654
|
if (options.oauthLogin) {
|
|
3680
|
-
await
|
|
3655
|
+
await _pg.sql.unsafe(`
|
|
3681
3656
|
CREATE TABLE IF NOT EXISTS "_auth_providers" (
|
|
3682
3657
|
id SERIAL PRIMARY KEY,
|
|
3683
3658
|
user_id INTEGER NOT NULL REFERENCES ${escapeIdent2(table)}(id) ON DELETE CASCADE,
|
|
@@ -3690,13 +3665,13 @@ function user(options) {
|
|
|
3690
3665
|
UNIQUE(provider, provider_id)
|
|
3691
3666
|
)
|
|
3692
3667
|
`);
|
|
3693
|
-
await
|
|
3668
|
+
await _pg.sql.unsafe(`
|
|
3694
3669
|
CREATE INDEX IF NOT EXISTS "_auth_providers_user_idx"
|
|
3695
3670
|
ON "_auth_providers"(user_id)
|
|
3696
3671
|
`);
|
|
3697
3672
|
}
|
|
3698
3673
|
if (!oauth2Enabled) return;
|
|
3699
|
-
const clients3 =
|
|
3674
|
+
const clients3 = _pg.table("_oauth2_clients", {
|
|
3700
3675
|
id: serial("id").primaryKey(),
|
|
3701
3676
|
name: text("name").notNull(),
|
|
3702
3677
|
client_id: text("client_id").unique().notNull(),
|
|
@@ -3706,7 +3681,7 @@ function user(options) {
|
|
|
3706
3681
|
created_at: timestamptz("created_at").default(sql`NOW()`)
|
|
3707
3682
|
});
|
|
3708
3683
|
await clients3.create();
|
|
3709
|
-
const codes =
|
|
3684
|
+
const codes = _pg.table("_oauth2_codes", {
|
|
3710
3685
|
id: serial("id").primaryKey(),
|
|
3711
3686
|
code: text("code").unique().notNull(),
|
|
3712
3687
|
client_id: text("client_id").notNull(),
|
|
@@ -3719,7 +3694,7 @@ function user(options) {
|
|
|
3719
3694
|
used: boolean_("used").default(false)
|
|
3720
3695
|
});
|
|
3721
3696
|
await codes.create();
|
|
3722
|
-
const tokens =
|
|
3697
|
+
const tokens = _pg.table("_oauth2_tokens", {
|
|
3723
3698
|
id: serial("id").primaryKey(),
|
|
3724
3699
|
token: text("token").unique().notNull(),
|
|
3725
3700
|
client_id: text("client_id").notNull(),
|
|
@@ -3742,15 +3717,15 @@ function user(options) {
|
|
|
3742
3717
|
return user2;
|
|
3743
3718
|
}
|
|
3744
3719
|
async function findByEmail(email) {
|
|
3745
|
-
const { data: rows } = await
|
|
3720
|
+
const { data: rows } = await _users.readMany({ email });
|
|
3746
3721
|
return rows[0];
|
|
3747
3722
|
}
|
|
3748
3723
|
async function findById(id2) {
|
|
3749
|
-
return await
|
|
3724
|
+
return await _users.read(id2);
|
|
3750
3725
|
}
|
|
3751
3726
|
async function createPlaceholderUser(email, name) {
|
|
3752
3727
|
const randomPassword = randomBytes(32).toString("hex");
|
|
3753
|
-
const row = await
|
|
3728
|
+
const row = await _users.insert({ email, password: randomPassword, name });
|
|
3754
3729
|
return row;
|
|
3755
3730
|
}
|
|
3756
3731
|
async function register(data) {
|
|
@@ -3762,14 +3737,14 @@ function user(options) {
|
|
|
3762
3737
|
throw err;
|
|
3763
3738
|
}
|
|
3764
3739
|
const hashed = hashPassword(password);
|
|
3765
|
-
const row = await
|
|
3740
|
+
const row = await _users.insert({ email, password: hashed, name });
|
|
3766
3741
|
const userData = row;
|
|
3767
3742
|
const token = signToken(userData);
|
|
3768
3743
|
return { user: stripPassword(userData), token };
|
|
3769
3744
|
}
|
|
3770
3745
|
async function login(data) {
|
|
3771
3746
|
const { email, password } = LoginSchema.parse(data);
|
|
3772
|
-
const { data: rows } = await
|
|
3747
|
+
const { data: rows } = await _users.readMany({ email });
|
|
3773
3748
|
const row = rows[0];
|
|
3774
3749
|
if (!row) {
|
|
3775
3750
|
const err = new Error("Invalid email or password");
|
|
@@ -3789,6 +3764,7 @@ function user(options) {
|
|
|
3789
3764
|
try {
|
|
3790
3765
|
const payload = jwt2.verify(token, secret);
|
|
3791
3766
|
if (payload.token_type === "client_credentials") return null;
|
|
3767
|
+
if (!hasDb || !findById) return null;
|
|
3792
3768
|
const row = await findById(payload.sub);
|
|
3793
3769
|
if (!row) return null;
|
|
3794
3770
|
return stripPassword(row);
|
|
@@ -3796,26 +3772,14 @@ function user(options) {
|
|
|
3796
3772
|
return null;
|
|
3797
3773
|
}
|
|
3798
3774
|
}
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
if (
|
|
3803
|
-
|
|
3804
|
-
for (const c of cookies) {
|
|
3805
|
-
const eq2 = c.indexOf("=");
|
|
3806
|
-
if (eq2 > 0 && c.slice(0, eq2) === cookieName) return c.slice(eq2 + 1);
|
|
3807
|
-
}
|
|
3808
|
-
}
|
|
3809
|
-
return null;
|
|
3810
|
-
}
|
|
3811
|
-
function middleware() {
|
|
3812
|
-
return async (req, ctx, next) => {
|
|
3813
|
-
const sessionUserId = ctx.session?.userId;
|
|
3814
|
-
if (sessionUserId) {
|
|
3775
|
+
const headerName = options.header ?? "Authorization";
|
|
3776
|
+
async function resolveUser(req, ctx) {
|
|
3777
|
+
const sessionUserId = ctx.session?.userId;
|
|
3778
|
+
if (sessionUserId !== void 0 && sessionUserId !== null) {
|
|
3779
|
+
if (hasDb) {
|
|
3815
3780
|
const row = await findById(sessionUserId);
|
|
3816
3781
|
if (row) {
|
|
3817
|
-
|
|
3818
|
-
return next(req, ctx);
|
|
3782
|
+
return stripPassword(row);
|
|
3819
3783
|
}
|
|
3820
3784
|
if (typeof ctx.session?.destroy === "function") {
|
|
3821
3785
|
;
|
|
@@ -3823,27 +3787,99 @@ function user(options) {
|
|
|
3823
3787
|
} else {
|
|
3824
3788
|
delete ctx.session?.userId;
|
|
3825
3789
|
}
|
|
3826
|
-
}
|
|
3827
|
-
|
|
3828
|
-
if (token) {
|
|
3829
|
-
const userData = await verify(token);
|
|
3790
|
+
} else if (options.resolveUser) {
|
|
3791
|
+
const userData = await options.resolveUser(sessionUserId);
|
|
3830
3792
|
if (userData) {
|
|
3831
|
-
|
|
3832
|
-
|
|
3793
|
+
return userData;
|
|
3794
|
+
}
|
|
3795
|
+
if (typeof ctx.session?.destroy === "function") {
|
|
3796
|
+
;
|
|
3797
|
+
ctx.session.destroy();
|
|
3798
|
+
}
|
|
3799
|
+
console.warn(`[${currentTraceId()}] user: session userId ${sessionUserId} resolved to null`);
|
|
3800
|
+
} else {
|
|
3801
|
+
return { id: sessionUserId };
|
|
3802
|
+
}
|
|
3803
|
+
}
|
|
3804
|
+
const token = extractToken(req, headerName);
|
|
3805
|
+
if (!token) return null;
|
|
3806
|
+
if (options.tokens?.length) {
|
|
3807
|
+
if (options.tokens.includes(token)) {
|
|
3808
|
+
return { id: token };
|
|
3809
|
+
}
|
|
3810
|
+
console.warn(`[${currentTraceId()}] user: invalid static token`);
|
|
3811
|
+
return null;
|
|
3812
|
+
}
|
|
3813
|
+
if (options.verify) {
|
|
3814
|
+
const result = await options.verify(token, req);
|
|
3815
|
+
if (!result) {
|
|
3816
|
+
console.warn(`[${currentTraceId()}] user: verify failed for token`);
|
|
3817
|
+
return null;
|
|
3818
|
+
}
|
|
3819
|
+
return result;
|
|
3820
|
+
}
|
|
3821
|
+
if (options.proxy) {
|
|
3822
|
+
let proxyUrl;
|
|
3823
|
+
try {
|
|
3824
|
+
proxyUrl = typeof options.proxy === "string" ? new URL(options.proxy) : options.proxy;
|
|
3825
|
+
} catch {
|
|
3826
|
+
return null;
|
|
3827
|
+
}
|
|
3828
|
+
const proxyHeaders = {};
|
|
3829
|
+
proxyHeaders[headerName] = req.headers.get(headerName) ?? `Bearer ${token}`;
|
|
3830
|
+
for (const name of ["x-forwarded-for", "x-real-ip", "user-agent", "content-type"]) {
|
|
3831
|
+
const v = req.headers.get(name);
|
|
3832
|
+
if (v) proxyHeaders[name] = v;
|
|
3833
|
+
}
|
|
3834
|
+
try {
|
|
3835
|
+
const proxyRes = await fetch(proxyUrl.href, { headers: proxyHeaders });
|
|
3836
|
+
if (proxyRes.status >= 400) {
|
|
3837
|
+
console.warn(`[${currentTraceId()}] user: proxy auth rejected (${proxyRes.status})`);
|
|
3838
|
+
return null;
|
|
3833
3839
|
}
|
|
3840
|
+
const ct = proxyRes.headers.get("content-type");
|
|
3841
|
+
if (ct?.includes("application/json")) {
|
|
3842
|
+
try {
|
|
3843
|
+
return await proxyRes.json();
|
|
3844
|
+
} catch {
|
|
3845
|
+
}
|
|
3846
|
+
}
|
|
3847
|
+
return { id: token };
|
|
3848
|
+
} catch (err) {
|
|
3849
|
+
console.warn(`[${currentTraceId()}] user: proxy auth error: ${err}`);
|
|
3850
|
+
return null;
|
|
3851
|
+
}
|
|
3852
|
+
}
|
|
3853
|
+
if (secret && hasDb) {
|
|
3854
|
+
try {
|
|
3855
|
+
const payload = jwt2.verify(token, secret);
|
|
3856
|
+
if (payload.token_type === "client_credentials") return null;
|
|
3857
|
+
const row = await findById(payload.sub);
|
|
3858
|
+
if (row) return stripPassword(row);
|
|
3859
|
+
} catch {
|
|
3860
|
+
}
|
|
3861
|
+
return null;
|
|
3862
|
+
}
|
|
3863
|
+
return null;
|
|
3864
|
+
}
|
|
3865
|
+
function middleware() {
|
|
3866
|
+
return async (req, ctx, next) => {
|
|
3867
|
+
const userData = await resolveUser(req, ctx);
|
|
3868
|
+
if (userData) {
|
|
3869
|
+
ctx.user = userData;
|
|
3870
|
+
return next(req, ctx);
|
|
3834
3871
|
}
|
|
3835
|
-
return new Response("Unauthorized", {
|
|
3872
|
+
return new Response("Unauthorized", {
|
|
3873
|
+
status: 401,
|
|
3874
|
+
headers: headerName.toLowerCase() === "authorization" ? { "WWW-Authenticate": "Bearer" } : void 0
|
|
3875
|
+
});
|
|
3836
3876
|
};
|
|
3837
3877
|
}
|
|
3838
|
-
function middlewareOptional(
|
|
3839
|
-
const cookieName = opts?.cookie;
|
|
3878
|
+
function middlewareOptional(_opts) {
|
|
3840
3879
|
return async (req, ctx, next) => {
|
|
3841
|
-
const
|
|
3842
|
-
if (
|
|
3843
|
-
|
|
3844
|
-
if (userData) {
|
|
3845
|
-
ctx.user = userData;
|
|
3846
|
-
}
|
|
3880
|
+
const userData = await resolveUser(req, ctx);
|
|
3881
|
+
if (userData) {
|
|
3882
|
+
ctx.user = userData;
|
|
3847
3883
|
}
|
|
3848
3884
|
return next(req, ctx);
|
|
3849
3885
|
};
|
|
@@ -3860,9 +3896,9 @@ function user(options) {
|
|
|
3860
3896
|
}
|
|
3861
3897
|
return obj;
|
|
3862
3898
|
}
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3899
|
+
const r = new Router();
|
|
3900
|
+
if (hasDb) {
|
|
3901
|
+
r.post("/register", async (req) => {
|
|
3866
3902
|
try {
|
|
3867
3903
|
const body = await parseBody2(req);
|
|
3868
3904
|
const result = await register(body);
|
|
@@ -3875,7 +3911,7 @@ function user(options) {
|
|
|
3875
3911
|
return Response.json({ error: err.message }, { status });
|
|
3876
3912
|
}
|
|
3877
3913
|
});
|
|
3878
|
-
|
|
3914
|
+
r.post("/login", async (req, ctx) => {
|
|
3879
3915
|
try {
|
|
3880
3916
|
const body = await parseBody2(req);
|
|
3881
3917
|
const result = await login(body);
|
|
@@ -3897,17 +3933,15 @@ function user(options) {
|
|
|
3897
3933
|
return Response.json({ error: err.message }, { status });
|
|
3898
3934
|
}
|
|
3899
3935
|
});
|
|
3900
|
-
if (oauth2) {
|
|
3901
|
-
r2.get("/oauth/authorize", (req, ctx) => oauth2.authorizeHandler(req, ctx));
|
|
3902
|
-
r2.post("/oauth/consent", (req) => oauth2.consentHandler(req));
|
|
3903
|
-
r2.post("/oauth/token", (req) => oauth2.tokenHandler(req));
|
|
3904
|
-
}
|
|
3905
|
-
return r2;
|
|
3906
3936
|
}
|
|
3907
|
-
|
|
3908
|
-
|
|
3937
|
+
if (oauth2) {
|
|
3938
|
+
r.get("/oauth/authorize", (req, ctx) => oauth2.authorizeHandler(req, ctx));
|
|
3939
|
+
r.post("/oauth/consent", (req) => oauth2.consentHandler(req));
|
|
3940
|
+
r.post("/oauth/token", (req) => oauth2.tokenHandler(req));
|
|
3941
|
+
}
|
|
3942
|
+
if (hasDb && options.oauthLogin) {
|
|
3909
3943
|
registerOAuthLoginRoutes(r, {
|
|
3910
|
-
sql:
|
|
3944
|
+
sql: _pg.sql,
|
|
3911
3945
|
jwtSecret: secret,
|
|
3912
3946
|
expiresIn,
|
|
3913
3947
|
usersTable: table,
|
|
@@ -3922,10 +3956,15 @@ function user(options) {
|
|
|
3922
3956
|
const mod = r;
|
|
3923
3957
|
mod.middleware = middleware;
|
|
3924
3958
|
mod.middlewareOptional = middlewareOptional;
|
|
3925
|
-
mod.migrate = migrate
|
|
3926
|
-
|
|
3927
|
-
mod.
|
|
3928
|
-
|
|
3959
|
+
mod.migrate = hasDb ? migrate : async () => {
|
|
3960
|
+
};
|
|
3961
|
+
mod.register = hasDb ? register : async () => {
|
|
3962
|
+
throw new Error("user(): pg required for register");
|
|
3963
|
+
};
|
|
3964
|
+
mod.login = hasDb ? login : async () => {
|
|
3965
|
+
throw new Error("user(): pg required for login");
|
|
3966
|
+
};
|
|
3967
|
+
mod.verify = hasDb ? verify : async () => null;
|
|
3929
3968
|
mod.registerClient = oauth2 ? (data) => oauth2.registerClient(data) : async () => {
|
|
3930
3969
|
throw new Error("OAuth2 server is not enabled");
|
|
3931
3970
|
};
|
|
@@ -3935,7 +3974,8 @@ function user(options) {
|
|
|
3935
3974
|
mod.revokeClient = oauth2 ? (clientId) => oauth2.revokeClient(clientId) : async () => {
|
|
3936
3975
|
throw new Error("OAuth2 server is not enabled");
|
|
3937
3976
|
};
|
|
3938
|
-
mod.close = () => base.close()
|
|
3977
|
+
mod.close = hasDb ? () => base.close() : async () => {
|
|
3978
|
+
};
|
|
3939
3979
|
return mod;
|
|
3940
3980
|
}
|
|
3941
3981
|
|
|
@@ -3957,7 +3997,7 @@ function redis(opts) {
|
|
|
3957
3997
|
|
|
3958
3998
|
// queue/index.ts
|
|
3959
3999
|
import { Redis as IORedis2 } from "ioredis";
|
|
3960
|
-
import
|
|
4000
|
+
import crypto6 from "node:crypto";
|
|
3961
4001
|
|
|
3962
4002
|
// cron-utils.ts
|
|
3963
4003
|
function parseField(field, min, max) {
|
|
@@ -4043,7 +4083,7 @@ function escapeIdent3(s) {
|
|
|
4043
4083
|
function attachCron(q, handlers) {
|
|
4044
4084
|
;
|
|
4045
4085
|
q.cron = function(pattern, handler) {
|
|
4046
|
-
const id2 = "__cron_" + pattern.replace(/[^a-zA-Z0-9]/g, "_") + "_" +
|
|
4086
|
+
const id2 = "__cron_" + pattern.replace(/[^a-zA-Z0-9]/g, "_") + "_" + crypto6.randomUUID().slice(0, 8);
|
|
4047
4087
|
q.process(id2, async () => {
|
|
4048
4088
|
await handler();
|
|
4049
4089
|
});
|
|
@@ -4082,7 +4122,7 @@ function createMemoryQueue(opts) {
|
|
|
4082
4122
|
}
|
|
4083
4123
|
if (job.schedule) {
|
|
4084
4124
|
try {
|
|
4085
|
-
insertJob({ ...job, id:
|
|
4125
|
+
insertJob({ ...job, id: crypto6.randomUUID(), runAt: cronNext(job.schedule), createdAt: Date.now() });
|
|
4086
4126
|
} catch (e) {
|
|
4087
4127
|
console.error("[queue] cron re-queue failed:", e.message);
|
|
4088
4128
|
}
|
|
@@ -4104,7 +4144,7 @@ function createMemoryQueue(opts) {
|
|
|
4104
4144
|
});
|
|
4105
4145
|
const q = mw;
|
|
4106
4146
|
mw.add = function add(type, payload, opts2) {
|
|
4107
|
-
const id2 =
|
|
4147
|
+
const id2 = crypto6.randomUUID();
|
|
4108
4148
|
let runAt;
|
|
4109
4149
|
if (opts2?.schedule) {
|
|
4110
4150
|
try {
|
|
@@ -4206,7 +4246,7 @@ function createPgQueue(opts) {
|
|
|
4206
4246
|
if (job.schedule) {
|
|
4207
4247
|
try {
|
|
4208
4248
|
const nextRun = cronNext(job.schedule);
|
|
4209
|
-
await sql2.unsafe(`INSERT INTO ${escapeIdent3(table)} (id, type, payload, run_at, schedule) VALUES ($1, $2, $3::jsonb, $4, $5)`, [
|
|
4249
|
+
await sql2.unsafe(`INSERT INTO ${escapeIdent3(table)} (id, type, payload, run_at, schedule) VALUES ($1, $2, $3::jsonb, $4, $5)`, [crypto6.randomUUID(), job.type, JSON.stringify(job.payload), new Date(nextRun).toISOString(), job.schedule]);
|
|
4210
4250
|
} catch (e) {
|
|
4211
4251
|
console.error("[queue] cron re-queue failed:", e.message);
|
|
4212
4252
|
}
|
|
@@ -4240,7 +4280,7 @@ function createPgQueue(opts) {
|
|
|
4240
4280
|
const q = mw;
|
|
4241
4281
|
mw.add = function add(type, payload, opts2) {
|
|
4242
4282
|
return (async () => {
|
|
4243
|
-
const id2 =
|
|
4283
|
+
const id2 = crypto6.randomUUID();
|
|
4244
4284
|
let runAt;
|
|
4245
4285
|
if (opts2?.schedule) {
|
|
4246
4286
|
try {
|
|
@@ -4327,7 +4367,7 @@ function createRedisQueue(opts) {
|
|
|
4327
4367
|
if (job.schedule) {
|
|
4328
4368
|
try {
|
|
4329
4369
|
const nextRun = cronNext(job.schedule);
|
|
4330
|
-
await redis2.zadd(jobKey, nextRun, JSON.stringify({ ...job, id:
|
|
4370
|
+
await redis2.zadd(jobKey, nextRun, JSON.stringify({ ...job, id: crypto6.randomUUID(), runAt: nextRun, createdAt: Date.now() }));
|
|
4331
4371
|
} catch (e) {
|
|
4332
4372
|
console.error("[queue] cron re-queue failed:", e.message);
|
|
4333
4373
|
}
|
|
@@ -4366,7 +4406,7 @@ function createRedisQueue(opts) {
|
|
|
4366
4406
|
});
|
|
4367
4407
|
const q = mw;
|
|
4368
4408
|
mw.add = function add(type, payload, opts2) {
|
|
4369
|
-
const id2 =
|
|
4409
|
+
const id2 = crypto6.randomUUID();
|
|
4370
4410
|
let runAt;
|
|
4371
4411
|
if (opts2?.schedule) {
|
|
4372
4412
|
runAt = cronNext(opts2.schedule);
|
|
@@ -6291,7 +6331,7 @@ function createGateway(config, getPort) {
|
|
|
6291
6331
|
}
|
|
6292
6332
|
|
|
6293
6333
|
// deploy/manager.ts
|
|
6294
|
-
import
|
|
6334
|
+
import crypto7 from "node:crypto";
|
|
6295
6335
|
|
|
6296
6336
|
// deploy/process.ts
|
|
6297
6337
|
import { fork } from "node:child_process";
|
|
@@ -6344,27 +6384,27 @@ async function healthCheck(port, path2 = "/") {
|
|
|
6344
6384
|
// deploy/manager.ts
|
|
6345
6385
|
function createManager(config, apps, manager) {
|
|
6346
6386
|
const router = new Router();
|
|
6347
|
-
const
|
|
6387
|
+
const auth = (req, ctx, next) => {
|
|
6348
6388
|
if (!config.deployToken) return next(req, ctx);
|
|
6349
6389
|
const header = req.headers.get("authorization") ?? "";
|
|
6350
6390
|
const token = header.replace("Bearer ", "");
|
|
6351
6391
|
const tokenBuf = Buffer.from(token);
|
|
6352
6392
|
const secretBuf = Buffer.from(config.deployToken);
|
|
6353
|
-
if (tokenBuf.length !== secretBuf.length || !
|
|
6393
|
+
if (tokenBuf.length !== secretBuf.length || !crypto7.timingSafeEqual(tokenBuf, secretBuf)) {
|
|
6354
6394
|
return Response.json({ error: "Unauthorized" }, { status: 401 });
|
|
6355
6395
|
}
|
|
6356
6396
|
return next(req, ctx);
|
|
6357
6397
|
};
|
|
6358
|
-
router.get("/apps",
|
|
6398
|
+
router.get("/apps", auth, () => {
|
|
6359
6399
|
const list = Array.from(apps.values()).map((a) => a.status);
|
|
6360
6400
|
return Response.json(list);
|
|
6361
6401
|
});
|
|
6362
|
-
router.get("/apps/:name",
|
|
6402
|
+
router.get("/apps/:name", auth, (req, ctx) => {
|
|
6363
6403
|
const app = apps.get(ctx.params.name);
|
|
6364
6404
|
if (!app) return new Response("Not Found", { status: 404 });
|
|
6365
6405
|
return Response.json(app.status);
|
|
6366
6406
|
});
|
|
6367
|
-
router.post("/apps/:name/deploy",
|
|
6407
|
+
router.post("/apps/:name/deploy", auth, async (req, ctx) => {
|
|
6368
6408
|
const app = apps.get(ctx.params.name);
|
|
6369
6409
|
if (!app) return new Response("Not Found", { status: 404 });
|
|
6370
6410
|
try {
|
|
@@ -6375,7 +6415,7 @@ function createManager(config, apps, manager) {
|
|
|
6375
6415
|
return Response.json({ error: msg }, { status: 500 });
|
|
6376
6416
|
}
|
|
6377
6417
|
});
|
|
6378
|
-
router.post("/apps/:name/restart",
|
|
6418
|
+
router.post("/apps/:name/restart", auth, async (req, ctx) => {
|
|
6379
6419
|
const app = apps.get(ctx.params.name);
|
|
6380
6420
|
if (!app) return new Response("Not Found", { status: 404 });
|
|
6381
6421
|
try {
|
|
@@ -6386,7 +6426,7 @@ function createManager(config, apps, manager) {
|
|
|
6386
6426
|
return Response.json({ error: msg }, { status: 500 });
|
|
6387
6427
|
}
|
|
6388
6428
|
});
|
|
6389
|
-
router.post("/apps/:name/stop",
|
|
6429
|
+
router.post("/apps/:name/stop", auth, async (req, ctx) => {
|
|
6390
6430
|
const app = apps.get(ctx.params.name);
|
|
6391
6431
|
if (!app) return new Response("Not Found", { status: 404 });
|
|
6392
6432
|
if (app.process) {
|
|
@@ -6396,7 +6436,7 @@ function createManager(config, apps, manager) {
|
|
|
6396
6436
|
app.status = { ...app.status, status: "stopped", pid: void 0 };
|
|
6397
6437
|
return Response.json({ success: true });
|
|
6398
6438
|
});
|
|
6399
|
-
router.post("/apps/:name/start",
|
|
6439
|
+
router.post("/apps/:name/start", auth, async (req, ctx) => {
|
|
6400
6440
|
const app = apps.get(ctx.params.name);
|
|
6401
6441
|
if (!app) return new Response("Not Found", { status: 404 });
|
|
6402
6442
|
try {
|
|
@@ -6407,7 +6447,7 @@ function createManager(config, apps, manager) {
|
|
|
6407
6447
|
return Response.json({ error: msg }, { status: 500 });
|
|
6408
6448
|
}
|
|
6409
6449
|
});
|
|
6410
|
-
router.get("/apps/:name/logs",
|
|
6450
|
+
router.get("/apps/:name/logs", auth, (req, ctx) => {
|
|
6411
6451
|
const app = apps.get(ctx.params.name);
|
|
6412
6452
|
if (!app) return new Response("Not Found", { status: 404 });
|
|
6413
6453
|
let index = app.logs.length;
|
|
@@ -6459,9 +6499,9 @@ function defineConfig(config) {
|
|
|
6459
6499
|
async function deploy(config) {
|
|
6460
6500
|
const apps = /* @__PURE__ */ new Map();
|
|
6461
6501
|
let httpServer;
|
|
6462
|
-
async function forkAndCheck(name, cwd, entry, port,
|
|
6502
|
+
async function forkAndCheck(name, cwd, entry, port, env2, onLog, healthEndpoint) {
|
|
6463
6503
|
try {
|
|
6464
|
-
const mp = forkApp({ cwd, entry, port, env, onLog });
|
|
6504
|
+
const mp = forkApp({ cwd, entry, port, env: env2, onLog });
|
|
6465
6505
|
onLog(`[deploy] forked ${name} (pid ${mp.child.pid}) on port ${mp.port}`);
|
|
6466
6506
|
const healthy = await healthCheck(port, healthEndpoint ?? "/");
|
|
6467
6507
|
if (healthy) onLog(`[deploy] health check passed`);
|
|
@@ -6778,13 +6818,24 @@ async function compileVendorBundle() {
|
|
|
6778
6818
|
const keys = Object.keys(mod).filter((k) => !k.startsWith("_") && k !== "default");
|
|
6779
6819
|
modules[request] = keys;
|
|
6780
6820
|
}
|
|
6781
|
-
const
|
|
6782
|
-
const
|
|
6821
|
+
const baseDir = import.meta.dirname ?? __dirname;
|
|
6822
|
+
const reactAbsPath = isBundled() ? resolve3(baseDir, "react.js") : resolve3(baseDir, "react.ts");
|
|
6823
|
+
const reactSrc = readFileSync2(reactAbsPath, "utf-8");
|
|
6783
6824
|
const wfwKeys = [];
|
|
6784
|
-
|
|
6785
|
-
const
|
|
6786
|
-
|
|
6787
|
-
|
|
6825
|
+
if (reactAbsPath.endsWith(".ts")) {
|
|
6826
|
+
for (const line of reactSrc.split("\n")) {
|
|
6827
|
+
const m = line.match(/^export\s+\{[^}]+\}\s*from/);
|
|
6828
|
+
if (m) {
|
|
6829
|
+
const names = line.slice(line.indexOf("{") + 1, line.indexOf("}")).split(",").map((s) => s.trim()).filter(Boolean);
|
|
6830
|
+
for (const n of names) {
|
|
6831
|
+
if (!n.startsWith("type ") && !wfwKeys.includes(n)) wfwKeys.push(n);
|
|
6832
|
+
}
|
|
6833
|
+
}
|
|
6834
|
+
}
|
|
6835
|
+
} else {
|
|
6836
|
+
const exportMatch = reactSrc.match(/\bexport\s*\{([^}]+)\}\s*;/);
|
|
6837
|
+
if (exportMatch) {
|
|
6838
|
+
const names = exportMatch[1].split(",").map((s) => s.trim()).filter(Boolean);
|
|
6788
6839
|
for (const n of names) {
|
|
6789
6840
|
if (!n.startsWith("type ") && !wfwKeys.includes(n)) wfwKeys.push(n);
|
|
6790
6841
|
}
|
|
@@ -6797,7 +6848,7 @@ async function compileVendorBundle() {
|
|
|
6797
6848
|
if (unique.length > 0) stmts.push(`export { ${unique.join(", ")} } from ${JSON.stringify(request)};`);
|
|
6798
6849
|
}
|
|
6799
6850
|
const uidWfw = wfwKeys.filter((k) => !used.has(k) && used.add(k));
|
|
6800
|
-
if (uidWfw.length > 0) stmts.push(`export { ${uidWfw.join(", ")} } from ${JSON.stringify(
|
|
6851
|
+
if (uidWfw.length > 0) stmts.push(`export { ${uidWfw.join(", ")} } from ${JSON.stringify(reactAbsPath)};`);
|
|
6801
6852
|
const result = await esbuild.build({
|
|
6802
6853
|
stdin: { contents: stmts.join("\n"), resolveDir: process.cwd() },
|
|
6803
6854
|
format: "esm",
|
|
@@ -6889,7 +6940,7 @@ async function compileHotComponent(path2) {
|
|
|
6889
6940
|
// stream.ts
|
|
6890
6941
|
import { TextDecoder as TextDecoder2, TextEncoder as TextEncoder2 } from "node:util";
|
|
6891
6942
|
var _publicEnv = null;
|
|
6892
|
-
function
|
|
6943
|
+
function getPublicEnv2() {
|
|
6893
6944
|
if (_publicEnv) return _publicEnv;
|
|
6894
6945
|
_publicEnv = {};
|
|
6895
6946
|
for (const key of Object.keys(process.env)) {
|
|
@@ -6940,7 +6991,7 @@ function buildHeadPayload(opts) {
|
|
|
6940
6991
|
}
|
|
6941
6992
|
ctxData.user = safeUser;
|
|
6942
6993
|
}
|
|
6943
|
-
const publicEnv =
|
|
6994
|
+
const publicEnv = getPublicEnv2();
|
|
6944
6995
|
if (Object.keys(publicEnv).length > 0) {
|
|
6945
6996
|
ctxData.env = publicEnv;
|
|
6946
6997
|
}
|
|
@@ -7648,7 +7699,7 @@ function ssr(opts) {
|
|
|
7648
7699
|
}
|
|
7649
7700
|
|
|
7650
7701
|
// opencode/session.ts
|
|
7651
|
-
import { randomUUID as
|
|
7702
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
7652
7703
|
import { join as join6 } from "node:path";
|
|
7653
7704
|
import { mkdir as mkdir2 } from "node:fs/promises";
|
|
7654
7705
|
var sessions = pgTable("_opencode_sessions", {
|
|
@@ -7674,7 +7725,7 @@ var messages = pgTable("_opencode_messages", {
|
|
|
7674
7725
|
created_at: timestamptz("created_at")
|
|
7675
7726
|
});
|
|
7676
7727
|
async function createSession(sql2, opts, cwd, mountPath) {
|
|
7677
|
-
const id2 =
|
|
7728
|
+
const id2 = randomUUID2();
|
|
7678
7729
|
const ws = computeSessionWorkspace(cwd, mountPath, id2);
|
|
7679
7730
|
await mkdir2(ws, { recursive: true });
|
|
7680
7731
|
const [row] = await sql2`
|
|
@@ -8846,30 +8897,37 @@ function makeSetTheme(cookie, location) {
|
|
|
8846
8897
|
}
|
|
8847
8898
|
function theme(options) {
|
|
8848
8899
|
const opts = { default: "system", cookie: "theme", ...options };
|
|
8849
|
-
|
|
8850
|
-
const url = new URL(req.url);
|
|
8851
|
-
const match = url.pathname.match(/^\/__theme\/([\w-]+)$/);
|
|
8852
|
-
if (match && req.method === "GET") {
|
|
8853
|
-
const value = match[1];
|
|
8854
|
-
const cookie = `${opts.cookie}=${encodeURIComponent(value)}; Path=/; SameSite=Lax`;
|
|
8855
|
-
const accept = req.headers.get("accept") ?? "";
|
|
8856
|
-
if (accept.includes("application/json")) {
|
|
8857
|
-
return Response.json({ ok: true, theme: value }, { headers: { "Set-Cookie": cookie } });
|
|
8858
|
-
}
|
|
8859
|
-
const referer = req.headers.get("referer") || "/";
|
|
8860
|
-
return new Response(null, { status: 302, headers: { Location: referer, "Set-Cookie": cookie } });
|
|
8861
|
-
}
|
|
8900
|
+
const mw = async (req, ctx, next) => {
|
|
8862
8901
|
let themeValue = opts.default;
|
|
8863
8902
|
if (opts.cookie) {
|
|
8864
8903
|
const fromCookie = getCookies(req)[opts.cookie];
|
|
8865
8904
|
if (fromCookie) themeValue = fromCookie;
|
|
8866
8905
|
}
|
|
8906
|
+
;
|
|
8867
8907
|
ctx.theme = {
|
|
8868
8908
|
value: themeValue,
|
|
8869
8909
|
set: makeSetTheme(opts.cookie, req.headers.get("referer") || "/")
|
|
8870
8910
|
};
|
|
8871
8911
|
return next(req, ctx);
|
|
8872
8912
|
};
|
|
8913
|
+
class ThemeRouter extends Router {
|
|
8914
|
+
middleware() {
|
|
8915
|
+
return mw;
|
|
8916
|
+
}
|
|
8917
|
+
}
|
|
8918
|
+
const router = new ThemeRouter();
|
|
8919
|
+
router.get("/__theme/:value", (req) => {
|
|
8920
|
+
const url = new URL(req.url);
|
|
8921
|
+
const value = url.pathname.split("/__theme/")[1] ?? "";
|
|
8922
|
+
const cookie = `${opts.cookie}=${encodeURIComponent(value)}; Path=/; SameSite=Lax`;
|
|
8923
|
+
const accept = req.headers.get("accept") ?? "";
|
|
8924
|
+
if (accept.includes("application/json")) {
|
|
8925
|
+
return Response.json({ ok: true, theme: value }, { headers: { "Set-Cookie": cookie } });
|
|
8926
|
+
}
|
|
8927
|
+
const referer = req.headers.get("referer") || "/";
|
|
8928
|
+
return new Response(null, { status: 302, headers: { Location: referer, "Set-Cookie": cookie } });
|
|
8929
|
+
});
|
|
8930
|
+
return router;
|
|
8873
8931
|
}
|
|
8874
8932
|
|
|
8875
8933
|
// i18n.ts
|
|
@@ -8935,23 +8993,7 @@ function i18n(options) {
|
|
|
8935
8993
|
}
|
|
8936
8994
|
return opts.default;
|
|
8937
8995
|
}
|
|
8938
|
-
|
|
8939
|
-
const url = new URL(req.url);
|
|
8940
|
-
const match = url.pathname.match(/^\/__lang\/([\w-]+)$/);
|
|
8941
|
-
if (match && req.method === "GET") {
|
|
8942
|
-
const value = match[1];
|
|
8943
|
-
const cookie = `${opts.cookie}=${encodeURIComponent(value)}; Path=/; SameSite=Lax`;
|
|
8944
|
-
const messages2 = await loadMessages(value);
|
|
8945
|
-
const accept = req.headers.get("accept") ?? "";
|
|
8946
|
-
if (accept.includes("application/json")) {
|
|
8947
|
-
return Response.json(
|
|
8948
|
-
{ ok: true, locale: value, messages: Object.keys(messages2).length > 0 ? messages2 : void 0 },
|
|
8949
|
-
{ headers: { "Set-Cookie": cookie } }
|
|
8950
|
-
);
|
|
8951
|
-
}
|
|
8952
|
-
const referer = req.headers.get("referer") || "/";
|
|
8953
|
-
return new Response(null, { status: 302, headers: { Location: referer, "Set-Cookie": cookie } });
|
|
8954
|
-
}
|
|
8996
|
+
const mw = async (req, ctx, next) => {
|
|
8955
8997
|
const locale = detectLocale(req);
|
|
8956
8998
|
const msgs = await loadMessages(locale);
|
|
8957
8999
|
ctx.i18n = {
|
|
@@ -8966,6 +9008,28 @@ function i18n(options) {
|
|
|
8966
9008
|
};
|
|
8967
9009
|
return next(req, ctx);
|
|
8968
9010
|
};
|
|
9011
|
+
class I18nRouter extends Router {
|
|
9012
|
+
middleware() {
|
|
9013
|
+
return mw;
|
|
9014
|
+
}
|
|
9015
|
+
}
|
|
9016
|
+
const router = new I18nRouter();
|
|
9017
|
+
router.get("/__lang/:locale", async (req) => {
|
|
9018
|
+
const url = new URL(req.url);
|
|
9019
|
+
const value = url.pathname.split("/__lang/")[1] ?? "";
|
|
9020
|
+
const cookie = `${opts.cookie}=${encodeURIComponent(value)}; Path=/; SameSite=Lax`;
|
|
9021
|
+
const messages2 = await loadMessages(value);
|
|
9022
|
+
const accept = req.headers.get("accept") ?? "";
|
|
9023
|
+
if (accept.includes("application/json")) {
|
|
9024
|
+
return Response.json(
|
|
9025
|
+
{ ok: true, locale: value, messages: Object.keys(messages2).length > 0 ? messages2 : void 0 },
|
|
9026
|
+
{ headers: { "Set-Cookie": cookie } }
|
|
9027
|
+
);
|
|
9028
|
+
}
|
|
9029
|
+
const referer = req.headers.get("referer") || "/";
|
|
9030
|
+
return new Response(null, { status: 302, headers: { Location: referer, "Set-Cookie": cookie } });
|
|
9031
|
+
});
|
|
9032
|
+
return router;
|
|
8969
9033
|
}
|
|
8970
9034
|
|
|
8971
9035
|
// flash.ts
|
|
@@ -9195,13 +9259,13 @@ function csrf(options) {
|
|
|
9195
9259
|
let token = getCookies(req)[cookieName];
|
|
9196
9260
|
if (!token) {
|
|
9197
9261
|
token = crypto.randomUUID();
|
|
9198
|
-
ctx.
|
|
9262
|
+
ctx.csrf = { token };
|
|
9199
9263
|
} else {
|
|
9200
9264
|
;
|
|
9201
|
-
ctx.
|
|
9265
|
+
ctx.csrf = { token };
|
|
9202
9266
|
}
|
|
9203
9267
|
const res = await next(req, ctx);
|
|
9204
|
-
const tokenToSet = ctx.
|
|
9268
|
+
const tokenToSet = ctx.csrf?.token;
|
|
9205
9269
|
if (tokenToSet && !getCookies(req)[cookieName]) {
|
|
9206
9270
|
return setCookie(res, cookieName, tokenToSet, {
|
|
9207
9271
|
httpOnly: true,
|
|
@@ -9386,7 +9450,7 @@ function logdb(options) {
|
|
|
9386
9450
|
}
|
|
9387
9451
|
|
|
9388
9452
|
// iii/client.ts
|
|
9389
|
-
import
|
|
9453
|
+
import crypto8 from "node:crypto";
|
|
9390
9454
|
|
|
9391
9455
|
// iii/stream.ts
|
|
9392
9456
|
function notify(channels, stream, group, item, event, data) {
|
|
@@ -9915,7 +9979,7 @@ function iii(opts = {}) {
|
|
|
9915
9979
|
registerBuiltin("stream::send", (p) => stream.send(p.stream_name, p.group_id, p.type, p.data, p.id));
|
|
9916
9980
|
registerBuiltin("stream::update", (p) => stream.update(p.stream_name, p.group_id, p.item_id, p.ops));
|
|
9917
9981
|
function addLocalWorker(worker) {
|
|
9918
|
-
const workerId =
|
|
9982
|
+
const workerId = crypto8.randomUUID();
|
|
9919
9983
|
const reg = {
|
|
9920
9984
|
id: workerId,
|
|
9921
9985
|
name: worker.name,
|
|
@@ -9930,7 +9994,7 @@ function iii(opts = {}) {
|
|
|
9930
9994
|
const triggerIds = [];
|
|
9931
9995
|
for (const t of worker.getTriggers()) {
|
|
9932
9996
|
if (t.input.function_id === fn.id) {
|
|
9933
|
-
const tid =
|
|
9997
|
+
const tid = crypto8.randomUUID();
|
|
9934
9998
|
triggers.set(tid, {
|
|
9935
9999
|
id: tid,
|
|
9936
10000
|
type: t.input.type,
|
|
@@ -9959,7 +10023,7 @@ function iii(opts = {}) {
|
|
|
9959
10023
|
if (!worker) return;
|
|
9960
10024
|
const handler = async (payload) => {
|
|
9961
10025
|
if (!worker.ws) throw new Error(`Worker "${worker.name}" disconnected`);
|
|
9962
|
-
const invocationId =
|
|
10026
|
+
const invocationId = crypto8.randomUUID();
|
|
9963
10027
|
return new Promise((resolve14, reject) => {
|
|
9964
10028
|
const timer = setTimeout(() => {
|
|
9965
10029
|
pending.delete(invocationId);
|
|
@@ -9994,7 +10058,7 @@ function iii(opts = {}) {
|
|
|
9994
10058
|
let engineRef = null;
|
|
9995
10059
|
const wsHandler = createWsHandler({
|
|
9996
10060
|
registerRemoteWorker(ws, name) {
|
|
9997
|
-
const id2 =
|
|
10061
|
+
const id2 = crypto8.randomUUID();
|
|
9998
10062
|
workers.set(id2, { id: id2, name, ws, functions: [], triggers: [] });
|
|
9999
10063
|
return id2;
|
|
10000
10064
|
},
|
|
@@ -10005,7 +10069,7 @@ function iii(opts = {}) {
|
|
|
10005
10069
|
addRemoteFunction(workerId, id2);
|
|
10006
10070
|
},
|
|
10007
10071
|
registerRemoteTrigger(workerId, input) {
|
|
10008
|
-
const tid =
|
|
10072
|
+
const tid = crypto8.randomUUID();
|
|
10009
10073
|
const reg = { id: tid, ...input, workerId };
|
|
10010
10074
|
triggers.set(tid, reg);
|
|
10011
10075
|
const worker = workers.get(workerId);
|
|
@@ -10141,6 +10205,7 @@ function iii(opts = {}) {
|
|
|
10141
10205
|
triggers.clear();
|
|
10142
10206
|
await stream.close();
|
|
10143
10207
|
};
|
|
10208
|
+
mod.close = mod.shutdown;
|
|
10144
10209
|
return mod;
|
|
10145
10210
|
}
|
|
10146
10211
|
|
|
@@ -10355,7 +10420,7 @@ function registerWorker(url) {
|
|
|
10355
10420
|
}
|
|
10356
10421
|
|
|
10357
10422
|
// session.ts
|
|
10358
|
-
import
|
|
10423
|
+
import crypto9 from "node:crypto";
|
|
10359
10424
|
var kSaved = /* @__PURE__ */ Symbol("session.saved");
|
|
10360
10425
|
var kDestroyed = /* @__PURE__ */ Symbol("session.destroyed");
|
|
10361
10426
|
var kId = /* @__PURE__ */ Symbol("session.id");
|
|
@@ -10433,7 +10498,7 @@ var RedisStore = class {
|
|
|
10433
10498
|
};
|
|
10434
10499
|
var COOKIE_SEPARATOR = ".";
|
|
10435
10500
|
function signSessionId(sid, secret) {
|
|
10436
|
-
const hmac =
|
|
10501
|
+
const hmac = crypto9.createHmac("sha256", secret).update(sid).digest("base64url").slice(0, 16);
|
|
10437
10502
|
return sid + COOKIE_SEPARATOR + hmac;
|
|
10438
10503
|
}
|
|
10439
10504
|
function unsignSessionId(value, secret) {
|
|
@@ -10441,10 +10506,10 @@ function unsignSessionId(value, secret) {
|
|
|
10441
10506
|
if (dot === -1) return null;
|
|
10442
10507
|
const sid = value.slice(0, dot);
|
|
10443
10508
|
const sig = value.slice(dot + 1);
|
|
10444
|
-
const expected =
|
|
10509
|
+
const expected = crypto9.createHmac("sha256", secret).update(sid).digest("base64url").slice(0, 16);
|
|
10445
10510
|
if (sig.length !== expected.length) return null;
|
|
10446
10511
|
try {
|
|
10447
|
-
return
|
|
10512
|
+
return crypto9.timingSafeEqual(Buffer.from(sig), Buffer.from(expected)) ? sid : null;
|
|
10448
10513
|
} catch {
|
|
10449
10514
|
return null;
|
|
10450
10515
|
}
|
|
@@ -10532,11 +10597,11 @@ function session(options) {
|
|
|
10532
10597
|
}
|
|
10533
10598
|
} else {
|
|
10534
10599
|
loadedSid = null;
|
|
10535
|
-
session2 = createSessionObject({},
|
|
10600
|
+
session2 = createSessionObject({}, crypto9.randomUUID(), store2, ttl, Date.now());
|
|
10536
10601
|
}
|
|
10537
10602
|
} else {
|
|
10538
10603
|
loadedSid = null;
|
|
10539
|
-
session2 = createSessionObject({},
|
|
10604
|
+
session2 = createSessionObject({}, crypto9.randomUUID(), store2, ttl, Date.now());
|
|
10540
10605
|
}
|
|
10541
10606
|
const snapshot = isSessionActive(session2) ? JSON.stringify(session2) : null;
|
|
10542
10607
|
ctx.session = session2;
|
|
@@ -10549,7 +10614,7 @@ function session(options) {
|
|
|
10549
10614
|
return deleteCookie(res, cookieName, cookieOpts);
|
|
10550
10615
|
}
|
|
10551
10616
|
if (needsRotation && loadedSid) {
|
|
10552
|
-
const newId =
|
|
10617
|
+
const newId = crypto9.randomUUID();
|
|
10553
10618
|
const data = JSON.parse(JSON.stringify(currentSession));
|
|
10554
10619
|
data[kCreatedAt] = Date.now();
|
|
10555
10620
|
await store2.set(newId, data, ttl);
|
|
@@ -10590,7 +10655,7 @@ function session(options) {
|
|
|
10590
10655
|
}
|
|
10591
10656
|
|
|
10592
10657
|
// cache.ts
|
|
10593
|
-
import
|
|
10658
|
+
import crypto10 from "node:crypto";
|
|
10594
10659
|
var BINARY_PREFIXES = [
|
|
10595
10660
|
"image/",
|
|
10596
10661
|
"audio/",
|
|
@@ -10610,7 +10675,7 @@ function isCacheableStatus(status, allowed) {
|
|
|
10610
10675
|
return allowed.includes(status);
|
|
10611
10676
|
}
|
|
10612
10677
|
function defaultCacheKey(req) {
|
|
10613
|
-
const hash =
|
|
10678
|
+
const hash = crypto10.createHash("sha256");
|
|
10614
10679
|
hash.update(req.method);
|
|
10615
10680
|
hash.update(req.url);
|
|
10616
10681
|
return hash.digest("hex");
|
|
@@ -10825,10 +10890,10 @@ function cache2(options) {
|
|
|
10825
10890
|
}
|
|
10826
10891
|
|
|
10827
10892
|
// webhook.ts
|
|
10828
|
-
import
|
|
10893
|
+
import crypto11 from "node:crypto";
|
|
10829
10894
|
function timingSafeEqual2(a, b) {
|
|
10830
10895
|
try {
|
|
10831
|
-
return
|
|
10896
|
+
return crypto11.timingSafeEqual(Buffer.from(a), Buffer.from(b));
|
|
10832
10897
|
} catch {
|
|
10833
10898
|
return false;
|
|
10834
10899
|
}
|
|
@@ -10846,7 +10911,7 @@ function createStripeVerifier(config) {
|
|
|
10846
10911
|
const signature = parts["v1"];
|
|
10847
10912
|
if (!timestamp || !signature) return { valid: false, provider: "stripe", event: "", id: void 0 };
|
|
10848
10913
|
const signed = `${timestamp}.${body}`;
|
|
10849
|
-
const expected =
|
|
10914
|
+
const expected = crypto11.createHmac("sha256", config.secret).update(signed).digest("hex");
|
|
10850
10915
|
const valid = timingSafeEqual2(signature, expected);
|
|
10851
10916
|
let event = "";
|
|
10852
10917
|
let id2;
|
|
@@ -10863,7 +10928,7 @@ function createGitHubVerifier(config) {
|
|
|
10863
10928
|
return (body, headers) => {
|
|
10864
10929
|
const sig = headers["x-hub-signature-256"];
|
|
10865
10930
|
if (!sig) return { valid: false, provider: "github", event: "", id: void 0 };
|
|
10866
|
-
const expected = `sha256=${
|
|
10931
|
+
const expected = `sha256=${crypto11.createHmac("sha256", config.secret).update(body).digest("hex")}`;
|
|
10867
10932
|
const valid = timingSafeEqual2(sig, expected);
|
|
10868
10933
|
let event = headers["x-github-event"] ?? "";
|
|
10869
10934
|
let id2;
|
|
@@ -10886,7 +10951,7 @@ function createSlackVerifier(config) {
|
|
|
10886
10951
|
return { valid: false, provider: "slack", event: "", id: void 0 };
|
|
10887
10952
|
}
|
|
10888
10953
|
const sigBase = `v0:${timestamp}:${body}`;
|
|
10889
|
-
const expected = `v0=${
|
|
10954
|
+
const expected = `v0=${crypto11.createHmac("sha256", config.secret).update(sigBase).digest("hex")}`;
|
|
10890
10955
|
const valid = timingSafeEqual2(signature, expected);
|
|
10891
10956
|
let event = "";
|
|
10892
10957
|
let id2;
|
|
@@ -11520,7 +11585,6 @@ export {
|
|
|
11520
11585
|
aiProvider,
|
|
11521
11586
|
aiStream,
|
|
11522
11587
|
analytics,
|
|
11523
|
-
auth,
|
|
11524
11588
|
cache2 as cache,
|
|
11525
11589
|
compress,
|
|
11526
11590
|
cors,
|
|
@@ -11538,6 +11602,7 @@ export {
|
|
|
11538
11602
|
deploy,
|
|
11539
11603
|
embed,
|
|
11540
11604
|
embedMany,
|
|
11605
|
+
env,
|
|
11541
11606
|
flash,
|
|
11542
11607
|
formatSSE,
|
|
11543
11608
|
formatSSEData,
|
|
@@ -11545,11 +11610,13 @@ export {
|
|
|
11545
11610
|
generateObject,
|
|
11546
11611
|
generateText2 as generateText,
|
|
11547
11612
|
getCookies,
|
|
11613
|
+
getPublicEnv,
|
|
11548
11614
|
graphql,
|
|
11549
11615
|
health,
|
|
11550
11616
|
helmet,
|
|
11551
11617
|
i18n,
|
|
11552
11618
|
iii,
|
|
11619
|
+
isBundled,
|
|
11553
11620
|
isDev,
|
|
11554
11621
|
isProd,
|
|
11555
11622
|
knowledgeBase,
|
|
@@ -11585,6 +11652,7 @@ export {
|
|
|
11585
11652
|
testApp,
|
|
11586
11653
|
theme,
|
|
11587
11654
|
tool2 as tool,
|
|
11655
|
+
trace,
|
|
11588
11656
|
traceElapsed,
|
|
11589
11657
|
upload,
|
|
11590
11658
|
user,
|