weifuwu 0.23.4 → 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/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,43 @@ 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
+ }
31
64
  function isBundled() {
32
65
  return true ? true : false;
33
66
  }
@@ -65,6 +98,14 @@ function loadEnv(path2) {
65
98
  process.env[key] = value;
66
99
  }
67
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
+ }
68
109
 
69
110
  // serve.ts
70
111
  import http from "node:http";
@@ -447,6 +488,10 @@ var Router = class _Router {
447
488
  }
448
489
  } else if (typeof arg1 === "function") {
449
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);
450
495
  }
451
496
  return this;
452
497
  }
@@ -991,114 +1036,6 @@ function cors(options) {
991
1036
  };
992
1037
  }
993
1038
 
994
- // auth.ts
995
- function auth(options) {
996
- if (!options.token && !options.verify && !options.proxy && !options.session) {
997
- throw new Error("auth() requires at least one of: token, verify, proxy, or session");
998
- }
999
- return async (req, ctx, next) => {
1000
- if (options.session) {
1001
- const sessionUserId = ctx.session?.userId;
1002
- if (sessionUserId !== void 0 && sessionUserId !== null) {
1003
- if (options.resolveUser) {
1004
- const userData = await options.resolveUser(sessionUserId);
1005
- if (userData) {
1006
- ctx.user = userData;
1007
- return next(req, ctx);
1008
- }
1009
- if (typeof ctx.session?.destroy === "function") {
1010
- ;
1011
- ctx.session.destroy();
1012
- }
1013
- console.warn(`[${currentTraceId()}] auth: session userId ${sessionUserId} resolved to null`);
1014
- } else {
1015
- ctx.user = { id: sessionUserId };
1016
- return next(req, ctx);
1017
- }
1018
- }
1019
- }
1020
- const headerName = options.header ?? "Authorization";
1021
- let from = "header";
1022
- let header = req.headers.get(headerName);
1023
- let token = "";
1024
- if (header) {
1025
- token = header.trim();
1026
- if (headerName.toLowerCase() === "authorization") {
1027
- const parts = header.split(" ");
1028
- if (parts[0]?.toLowerCase() === "bearer") {
1029
- token = parts.slice(1).join(" ").trim();
1030
- }
1031
- }
1032
- } else if (!options.header) {
1033
- const url = new URL(req.url);
1034
- const qsToken = url.searchParams.get("access_token");
1035
- if (qsToken) {
1036
- token = qsToken;
1037
- from = "query";
1038
- }
1039
- }
1040
- if (!token) {
1041
- return new Response("Unauthorized", {
1042
- status: 401,
1043
- headers: headerName.toLowerCase() === "authorization" ? { "WWW-Authenticate": "Bearer" } : void 0
1044
- });
1045
- }
1046
- if (options.proxy) {
1047
- let proxyUrl;
1048
- try {
1049
- proxyUrl = typeof options.proxy === "string" ? new URL(options.proxy) : options.proxy;
1050
- } catch {
1051
- return new Response("Invalid proxy URL", { status: 500 });
1052
- }
1053
- const proxyHeaders = {};
1054
- if (from === "header" && header) {
1055
- proxyHeaders[headerName] = header;
1056
- } else {
1057
- proxyUrl.searchParams.set("access_token", token);
1058
- }
1059
- for (const name of ["x-forwarded-for", "x-real-ip", "user-agent", "content-type"]) {
1060
- const v = req.headers.get(name);
1061
- if (v) proxyHeaders[name] = v;
1062
- }
1063
- const proxyRes = await fetch(proxyUrl.href, { headers: proxyHeaders });
1064
- if (proxyRes.status >= 400) {
1065
- return new Response(await proxyRes.text() || "Forbidden", { status: proxyRes.status });
1066
- }
1067
- let userData = void 0;
1068
- if (proxyRes.status === 200) {
1069
- const ct = proxyRes.headers.get("content-type");
1070
- if (ct?.includes("application/json")) {
1071
- try {
1072
- userData = await proxyRes.json();
1073
- } catch {
1074
- }
1075
- }
1076
- }
1077
- ctx.user = userData;
1078
- return next(req, ctx);
1079
- }
1080
- if (options.token) {
1081
- if (token !== options.token) {
1082
- console.warn(`[${currentTraceId()}] auth: invalid static token`);
1083
- return new Response("Forbidden", { status: 403 });
1084
- }
1085
- return next(req, ctx);
1086
- }
1087
- if (options.verify) {
1088
- const result = await options.verify(token, req);
1089
- if (!result) {
1090
- console.warn(`[${currentTraceId()}] auth: verify failed for token`);
1091
- return new Response("Forbidden", { status: 403 });
1092
- }
1093
- if (typeof result === "object" && result !== null) {
1094
- ctx.user = result;
1095
- }
1096
- return next(req, ctx);
1097
- }
1098
- return next(req, ctx);
1099
- };
1100
- }
1101
-
1102
1039
  // static.ts
1103
1040
  import { open, realpath } from "node:fs/promises";
1104
1041
  import { extname, resolve as resolve2, normalize, sep } from "node:path";
@@ -1382,7 +1319,7 @@ function deleteCookie(res, name, options) {
1382
1319
 
1383
1320
  // upload.ts
1384
1321
  import { writeFile, mkdir } from "node:fs/promises";
1385
- import { randomUUID as randomUUID2 } from "node:crypto";
1322
+ import { randomUUID } from "node:crypto";
1386
1323
  import { join, extname as extname2 } from "node:path";
1387
1324
  var extensionMimeMap = {
1388
1325
  ".jpg": "image/jpeg",
@@ -1454,7 +1391,7 @@ function upload(options) {
1454
1391
  };
1455
1392
  if (saveDir) {
1456
1393
  const safeName = value.name.replace(/[/\\\0]/g, "_").replace(/\.\./g, "_");
1457
- const filePath = join(saveDir, `${randomUUID2()}-${safeName}`);
1394
+ const filePath = join(saveDir, `${randomUUID()}-${safeName}`);
1458
1395
  await writeFile(filePath, buf);
1459
1396
  uf.path = filePath;
1460
1397
  }
@@ -1551,10 +1488,11 @@ function rateLimit(options) {
1551
1488
  const res = await next(req, ctx);
1552
1489
  return addRateLimitHeaders(res, max, remaining, reset);
1553
1490
  };
1554
- mw.stop = () => {
1491
+ mw.close = () => {
1555
1492
  if (interval) clearInterval(interval);
1556
1493
  hits.clear();
1557
1494
  };
1495
+ mw.stop = mw.close;
1558
1496
  mw.stats = () => ({
1559
1497
  store: storeType,
1560
1498
  entries: storeType === "memory" ? hits.size : void 0,
@@ -1672,10 +1610,10 @@ var DEFAULTS = {
1672
1610
  };
1673
1611
 
1674
1612
  // request-id.ts
1675
- import crypto2 from "node:crypto";
1613
+ import crypto3 from "node:crypto";
1676
1614
  function requestId(options) {
1677
1615
  const header = options?.header ?? "X-Request-ID";
1678
- const gen = options?.generator ?? (() => crypto2.randomUUID());
1616
+ const gen = options?.generator ?? (() => crypto3.randomUUID());
1679
1617
  return async (req, ctx, next) => {
1680
1618
  const existing = req.headers.get(header);
1681
1619
  const id2 = existing ?? gen();
@@ -2425,7 +2363,7 @@ function aiProvider(options) {
2425
2363
  const client = createOpenAI({ baseURL, apiKey });
2426
2364
  let _model;
2427
2365
  let _embedModel;
2428
- return {
2366
+ const provider = {
2429
2367
  get dimension() {
2430
2368
  return dimension;
2431
2369
  },
@@ -2454,6 +2392,12 @@ function aiProvider(options) {
2454
2392
  return aiStreamText({ ...params, model: this.model() });
2455
2393
  }
2456
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);
2457
2401
  }
2458
2402
 
2459
2403
  // ai-sdk.ts
@@ -3126,7 +3070,7 @@ import jwt2 from "jsonwebtoken";
3126
3070
  import { z as z2 } from "zod";
3127
3071
 
3128
3072
  // user/oauth2.ts
3129
- import crypto3 from "node:crypto";
3073
+ import crypto4 from "node:crypto";
3130
3074
  import jwt from "jsonwebtoken";
3131
3075
  function createOAuth2Server(deps) {
3132
3076
  const { pg, users, jwtSecret, expiresIn } = deps;
@@ -3145,8 +3089,8 @@ function createOAuth2Server(deps) {
3145
3089
  };
3146
3090
  }
3147
3091
  async function registerClient(data) {
3148
- const clientId = crypto3.randomUUID();
3149
- const clientSecret = crypto3.randomBytes(32).toString("hex");
3092
+ const clientId = crypto4.randomUUID();
3093
+ const clientSecret = crypto4.randomBytes(32).toString("hex");
3150
3094
  const [row] = await pg.sql`
3151
3095
  INSERT INTO "_oauth2_clients" ("name", "client_id", "client_secret", "redirect_uris")
3152
3096
  VALUES (${data.name}, ${clientId}, ${clientSecret}, ${pg.sql.array(data.redirectUris)})
@@ -3294,7 +3238,7 @@ h2{color:#dc2626}.desc{color:#555}</style>
3294
3238
  const loc2 = `${redirectUri}?error=access_denied${state ? `&state=${state}` : ""}`;
3295
3239
  return Response.redirect(loc2, 302);
3296
3240
  }
3297
- const code = crypto3.randomUUID();
3241
+ const code = crypto4.randomUUID();
3298
3242
  const expiresAt = new Date(Date.now() + 10 * 60 * 1e3);
3299
3243
  await pg.sql`
3300
3244
  INSERT INTO "_oauth2_codes" ("code", "client_id", "user_id", "redirect_uri", "code_challenge", "code_challenge_method", "scope", "expires_at")
@@ -3359,7 +3303,7 @@ h2{color:#dc2626}.desc{color:#555}</style>
3359
3303
  if (stored.code_challenge_method === "plain") {
3360
3304
  expected = codeVerifier;
3361
3305
  } else {
3362
- expected = crypto3.createHash("sha256").update(codeVerifier).digest().toString("base64url");
3306
+ expected = crypto4.createHash("sha256").update(codeVerifier).digest().toString("base64url");
3363
3307
  }
3364
3308
  if (expected !== stored.code_challenge) {
3365
3309
  return Response.json({ error: "invalid_grant", error_description: "code_verifier mismatch" }, { status: 400 });
@@ -3376,7 +3320,7 @@ h2{color:#dc2626}.desc{color:#555}</style>
3376
3320
  jwtSecret,
3377
3321
  { expiresIn }
3378
3322
  );
3379
- const refreshToken = crypto3.randomUUID();
3323
+ const refreshToken = crypto4.randomUUID();
3380
3324
  const refreshExpires = new Date(Date.now() + 30 * 24 * 60 * 60 * 1e3);
3381
3325
  await pg.sql`
3382
3326
  INSERT INTO "_oauth2_tokens" ("token", "client_id", "user_id", "scope", "expires_at")
@@ -3414,7 +3358,7 @@ h2{color:#dc2626}.desc{color:#555}</style>
3414
3358
  }
3415
3359
 
3416
3360
  // user/oauth-login.ts
3417
- import crypto4 from "node:crypto";
3361
+ import crypto5 from "node:crypto";
3418
3362
  var BUILTIN_PROVIDERS = {
3419
3363
  google: {
3420
3364
  authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
@@ -3526,7 +3470,7 @@ function registerOAuthLoginRoutes(router, deps, providers) {
3526
3470
  return Response.json({ error: `Unsupported provider: ${providerName}` }, { status: 400 });
3527
3471
  }
3528
3472
  const { config, meta } = resolved;
3529
- const state = crypto4.randomUUID();
3473
+ const state = crypto5.randomUUID();
3530
3474
  const redirectUri = new URL(req.url);
3531
3475
  redirectUri.pathname = redirectUri.pathname.replace(/\/[^/]+$/, "/") + providerName + "/callback";
3532
3476
  if (ctx.session) {
@@ -3657,14 +3601,40 @@ function verifyPassword(password, stored) {
3657
3601
  if (hash.length !== verify.length) return false;
3658
3602
  return timingSafeEqual(Buffer.from(hash), Buffer.from(verify));
3659
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
+ }
3660
3629
  function user(options) {
3630
+ const hasDb = !!options.pg;
3661
3631
  const table = options.table ?? "_users";
3662
3632
  const pg = options.pg;
3663
3633
  const secret = options.jwtSecret;
3664
3634
  const expiresIn = options.expiresIn ?? "24h";
3665
3635
  const oauth2Enabled = options.oauth2?.server ?? false;
3666
- const base = new PgModule(pg);
3667
- const users = pg.table(table, {
3636
+ const base = hasDb ? new PgModule(pg) : null;
3637
+ const users = hasDb ? pg.table(table, {
3668
3638
  id: serial("id").primaryKey(),
3669
3639
  email: text("email").unique().notNull(),
3670
3640
  password: text("password").notNull(),
@@ -3672,15 +3642,17 @@ function user(options) {
3672
3642
  role: text("role").default("user"),
3673
3643
  created_at: timestamptz("created_at").default(sql`NOW()`),
3674
3644
  updated_at: timestamptz("updated_at").default(sql`NOW()`)
3675
- });
3645
+ }) : null;
3646
+ const _pg = pg;
3647
+ const _users = users;
3676
3648
  let oauth2 = null;
3677
3649
  if (oauth2Enabled) {
3678
- oauth2 = createOAuth2Server({ pg, users, jwtSecret: secret, expiresIn });
3650
+ oauth2 = createOAuth2Server({ pg: _pg, users: _users, jwtSecret: secret, expiresIn });
3679
3651
  }
3680
3652
  async function migrate() {
3681
- await users.create();
3653
+ await _users.create();
3682
3654
  if (options.oauthLogin) {
3683
- await pg.sql.unsafe(`
3655
+ await _pg.sql.unsafe(`
3684
3656
  CREATE TABLE IF NOT EXISTS "_auth_providers" (
3685
3657
  id SERIAL PRIMARY KEY,
3686
3658
  user_id INTEGER NOT NULL REFERENCES ${escapeIdent2(table)}(id) ON DELETE CASCADE,
@@ -3693,13 +3665,13 @@ function user(options) {
3693
3665
  UNIQUE(provider, provider_id)
3694
3666
  )
3695
3667
  `);
3696
- await pg.sql.unsafe(`
3668
+ await _pg.sql.unsafe(`
3697
3669
  CREATE INDEX IF NOT EXISTS "_auth_providers_user_idx"
3698
3670
  ON "_auth_providers"(user_id)
3699
3671
  `);
3700
3672
  }
3701
3673
  if (!oauth2Enabled) return;
3702
- const clients3 = pg.table("_oauth2_clients", {
3674
+ const clients3 = _pg.table("_oauth2_clients", {
3703
3675
  id: serial("id").primaryKey(),
3704
3676
  name: text("name").notNull(),
3705
3677
  client_id: text("client_id").unique().notNull(),
@@ -3709,7 +3681,7 @@ function user(options) {
3709
3681
  created_at: timestamptz("created_at").default(sql`NOW()`)
3710
3682
  });
3711
3683
  await clients3.create();
3712
- const codes = pg.table("_oauth2_codes", {
3684
+ const codes = _pg.table("_oauth2_codes", {
3713
3685
  id: serial("id").primaryKey(),
3714
3686
  code: text("code").unique().notNull(),
3715
3687
  client_id: text("client_id").notNull(),
@@ -3722,7 +3694,7 @@ function user(options) {
3722
3694
  used: boolean_("used").default(false)
3723
3695
  });
3724
3696
  await codes.create();
3725
- const tokens = pg.table("_oauth2_tokens", {
3697
+ const tokens = _pg.table("_oauth2_tokens", {
3726
3698
  id: serial("id").primaryKey(),
3727
3699
  token: text("token").unique().notNull(),
3728
3700
  client_id: text("client_id").notNull(),
@@ -3745,15 +3717,15 @@ function user(options) {
3745
3717
  return user2;
3746
3718
  }
3747
3719
  async function findByEmail(email) {
3748
- const { data: rows } = await users.readMany({ email });
3720
+ const { data: rows } = await _users.readMany({ email });
3749
3721
  return rows[0];
3750
3722
  }
3751
3723
  async function findById(id2) {
3752
- return await users.read(id2);
3724
+ return await _users.read(id2);
3753
3725
  }
3754
3726
  async function createPlaceholderUser(email, name) {
3755
3727
  const randomPassword = randomBytes(32).toString("hex");
3756
- const row = await users.insert({ email, password: randomPassword, name });
3728
+ const row = await _users.insert({ email, password: randomPassword, name });
3757
3729
  return row;
3758
3730
  }
3759
3731
  async function register(data) {
@@ -3765,14 +3737,14 @@ function user(options) {
3765
3737
  throw err;
3766
3738
  }
3767
3739
  const hashed = hashPassword(password);
3768
- const row = await users.insert({ email, password: hashed, name });
3740
+ const row = await _users.insert({ email, password: hashed, name });
3769
3741
  const userData = row;
3770
3742
  const token = signToken(userData);
3771
3743
  return { user: stripPassword(userData), token };
3772
3744
  }
3773
3745
  async function login(data) {
3774
3746
  const { email, password } = LoginSchema.parse(data);
3775
- const { data: rows } = await users.readMany({ email });
3747
+ const { data: rows } = await _users.readMany({ email });
3776
3748
  const row = rows[0];
3777
3749
  if (!row) {
3778
3750
  const err = new Error("Invalid email or password");
@@ -3792,6 +3764,7 @@ function user(options) {
3792
3764
  try {
3793
3765
  const payload = jwt2.verify(token, secret);
3794
3766
  if (payload.token_type === "client_credentials") return null;
3767
+ if (!hasDb || !findById) return null;
3795
3768
  const row = await findById(payload.sub);
3796
3769
  if (!row) return null;
3797
3770
  return stripPassword(row);
@@ -3799,26 +3772,14 @@ function user(options) {
3799
3772
  return null;
3800
3773
  }
3801
3774
  }
3802
- function extractToken(req, cookieName) {
3803
- const header = req.headers.get("Authorization");
3804
- if (header?.startsWith("Bearer ")) return header.slice(7);
3805
- if (cookieName) {
3806
- const cookies = req.headers.get("cookie")?.split(";").map((c) => c.trim()).filter(Boolean) || [];
3807
- for (const c of cookies) {
3808
- const eq2 = c.indexOf("=");
3809
- if (eq2 > 0 && c.slice(0, eq2) === cookieName) return c.slice(eq2 + 1);
3810
- }
3811
- }
3812
- return null;
3813
- }
3814
- function middleware() {
3815
- return async (req, ctx, next) => {
3816
- const sessionUserId = ctx.session?.userId;
3817
- 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) {
3818
3780
  const row = await findById(sessionUserId);
3819
3781
  if (row) {
3820
- ctx.user = stripPassword(row);
3821
- return next(req, ctx);
3782
+ return stripPassword(row);
3822
3783
  }
3823
3784
  if (typeof ctx.session?.destroy === "function") {
3824
3785
  ;
@@ -3826,27 +3787,99 @@ function user(options) {
3826
3787
  } else {
3827
3788
  delete ctx.session?.userId;
3828
3789
  }
3829
- }
3830
- const token = extractToken(req);
3831
- if (token) {
3832
- const userData = await verify(token);
3790
+ } else if (options.resolveUser) {
3791
+ const userData = await options.resolveUser(sessionUserId);
3833
3792
  if (userData) {
3834
- ctx.user = userData;
3835
- return next(req, ctx);
3793
+ return userData;
3836
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;
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;
3837
3851
  }
3838
- return new Response("Unauthorized", { status: 401, headers: { "WWW-Authenticate": "Bearer" } });
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);
3871
+ }
3872
+ return new Response("Unauthorized", {
3873
+ status: 401,
3874
+ headers: headerName.toLowerCase() === "authorization" ? { "WWW-Authenticate": "Bearer" } : void 0
3875
+ });
3839
3876
  };
3840
3877
  }
3841
- function middlewareOptional(opts) {
3842
- const cookieName = opts?.cookie;
3878
+ function middlewareOptional(_opts) {
3843
3879
  return async (req, ctx, next) => {
3844
- const token = extractToken(req, cookieName);
3845
- if (token) {
3846
- const userData = await verify(token);
3847
- if (userData) {
3848
- ctx.user = userData;
3849
- }
3880
+ const userData = await resolveUser(req, ctx);
3881
+ if (userData) {
3882
+ ctx.user = userData;
3850
3883
  }
3851
3884
  return next(req, ctx);
3852
3885
  };
@@ -3863,9 +3896,9 @@ function user(options) {
3863
3896
  }
3864
3897
  return obj;
3865
3898
  }
3866
- function router() {
3867
- const r2 = new Router();
3868
- r2.post("/register", async (req) => {
3899
+ const r = new Router();
3900
+ if (hasDb) {
3901
+ r.post("/register", async (req) => {
3869
3902
  try {
3870
3903
  const body = await parseBody2(req);
3871
3904
  const result = await register(body);
@@ -3878,7 +3911,7 @@ function user(options) {
3878
3911
  return Response.json({ error: err.message }, { status });
3879
3912
  }
3880
3913
  });
3881
- r2.post("/login", async (req, ctx) => {
3914
+ r.post("/login", async (req, ctx) => {
3882
3915
  try {
3883
3916
  const body = await parseBody2(req);
3884
3917
  const result = await login(body);
@@ -3900,17 +3933,15 @@ function user(options) {
3900
3933
  return Response.json({ error: err.message }, { status });
3901
3934
  }
3902
3935
  });
3903
- if (oauth2) {
3904
- r2.get("/oauth/authorize", (req, ctx) => oauth2.authorizeHandler(req, ctx));
3905
- r2.post("/oauth/consent", (req) => oauth2.consentHandler(req));
3906
- r2.post("/oauth/token", (req) => oauth2.tokenHandler(req));
3907
- }
3908
- return r2;
3909
3936
  }
3910
- const r = router();
3911
- if (options.oauthLogin) {
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) {
3912
3943
  registerOAuthLoginRoutes(r, {
3913
- sql: pg.sql,
3944
+ sql: _pg.sql,
3914
3945
  jwtSecret: secret,
3915
3946
  expiresIn,
3916
3947
  usersTable: table,
@@ -3925,10 +3956,15 @@ function user(options) {
3925
3956
  const mod = r;
3926
3957
  mod.middleware = middleware;
3927
3958
  mod.middlewareOptional = middlewareOptional;
3928
- mod.migrate = migrate;
3929
- mod.register = register;
3930
- mod.login = login;
3931
- mod.verify = verify;
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;
3932
3968
  mod.registerClient = oauth2 ? (data) => oauth2.registerClient(data) : async () => {
3933
3969
  throw new Error("OAuth2 server is not enabled");
3934
3970
  };
@@ -3938,7 +3974,8 @@ function user(options) {
3938
3974
  mod.revokeClient = oauth2 ? (clientId) => oauth2.revokeClient(clientId) : async () => {
3939
3975
  throw new Error("OAuth2 server is not enabled");
3940
3976
  };
3941
- mod.close = () => base.close();
3977
+ mod.close = hasDb ? () => base.close() : async () => {
3978
+ };
3942
3979
  return mod;
3943
3980
  }
3944
3981
 
@@ -3960,7 +3997,7 @@ function redis(opts) {
3960
3997
 
3961
3998
  // queue/index.ts
3962
3999
  import { Redis as IORedis2 } from "ioredis";
3963
- import crypto5 from "node:crypto";
4000
+ import crypto6 from "node:crypto";
3964
4001
 
3965
4002
  // cron-utils.ts
3966
4003
  function parseField(field, min, max) {
@@ -4046,7 +4083,7 @@ function escapeIdent3(s) {
4046
4083
  function attachCron(q, handlers) {
4047
4084
  ;
4048
4085
  q.cron = function(pattern, handler) {
4049
- const id2 = "__cron_" + pattern.replace(/[^a-zA-Z0-9]/g, "_") + "_" + crypto5.randomUUID().slice(0, 8);
4086
+ const id2 = "__cron_" + pattern.replace(/[^a-zA-Z0-9]/g, "_") + "_" + crypto6.randomUUID().slice(0, 8);
4050
4087
  q.process(id2, async () => {
4051
4088
  await handler();
4052
4089
  });
@@ -4085,7 +4122,7 @@ function createMemoryQueue(opts) {
4085
4122
  }
4086
4123
  if (job.schedule) {
4087
4124
  try {
4088
- insertJob({ ...job, id: crypto5.randomUUID(), runAt: cronNext(job.schedule), createdAt: Date.now() });
4125
+ insertJob({ ...job, id: crypto6.randomUUID(), runAt: cronNext(job.schedule), createdAt: Date.now() });
4089
4126
  } catch (e) {
4090
4127
  console.error("[queue] cron re-queue failed:", e.message);
4091
4128
  }
@@ -4107,7 +4144,7 @@ function createMemoryQueue(opts) {
4107
4144
  });
4108
4145
  const q = mw;
4109
4146
  mw.add = function add(type, payload, opts2) {
4110
- const id2 = crypto5.randomUUID();
4147
+ const id2 = crypto6.randomUUID();
4111
4148
  let runAt;
4112
4149
  if (opts2?.schedule) {
4113
4150
  try {
@@ -4209,7 +4246,7 @@ function createPgQueue(opts) {
4209
4246
  if (job.schedule) {
4210
4247
  try {
4211
4248
  const nextRun = cronNext(job.schedule);
4212
- await sql2.unsafe(`INSERT INTO ${escapeIdent3(table)} (id, type, payload, run_at, schedule) VALUES ($1, $2, $3::jsonb, $4, $5)`, [crypto5.randomUUID(), job.type, JSON.stringify(job.payload), new Date(nextRun).toISOString(), job.schedule]);
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]);
4213
4250
  } catch (e) {
4214
4251
  console.error("[queue] cron re-queue failed:", e.message);
4215
4252
  }
@@ -4243,7 +4280,7 @@ function createPgQueue(opts) {
4243
4280
  const q = mw;
4244
4281
  mw.add = function add(type, payload, opts2) {
4245
4282
  return (async () => {
4246
- const id2 = crypto5.randomUUID();
4283
+ const id2 = crypto6.randomUUID();
4247
4284
  let runAt;
4248
4285
  if (opts2?.schedule) {
4249
4286
  try {
@@ -4330,7 +4367,7 @@ function createRedisQueue(opts) {
4330
4367
  if (job.schedule) {
4331
4368
  try {
4332
4369
  const nextRun = cronNext(job.schedule);
4333
- await redis2.zadd(jobKey, nextRun, JSON.stringify({ ...job, id: crypto5.randomUUID(), runAt: nextRun, createdAt: Date.now() }));
4370
+ await redis2.zadd(jobKey, nextRun, JSON.stringify({ ...job, id: crypto6.randomUUID(), runAt: nextRun, createdAt: Date.now() }));
4334
4371
  } catch (e) {
4335
4372
  console.error("[queue] cron re-queue failed:", e.message);
4336
4373
  }
@@ -4369,7 +4406,7 @@ function createRedisQueue(opts) {
4369
4406
  });
4370
4407
  const q = mw;
4371
4408
  mw.add = function add(type, payload, opts2) {
4372
- const id2 = crypto5.randomUUID();
4409
+ const id2 = crypto6.randomUUID();
4373
4410
  let runAt;
4374
4411
  if (opts2?.schedule) {
4375
4412
  runAt = cronNext(opts2.schedule);
@@ -6294,7 +6331,7 @@ function createGateway(config, getPort) {
6294
6331
  }
6295
6332
 
6296
6333
  // deploy/manager.ts
6297
- import crypto6 from "node:crypto";
6334
+ import crypto7 from "node:crypto";
6298
6335
 
6299
6336
  // deploy/process.ts
6300
6337
  import { fork } from "node:child_process";
@@ -6347,27 +6384,27 @@ async function healthCheck(port, path2 = "/") {
6347
6384
  // deploy/manager.ts
6348
6385
  function createManager(config, apps, manager) {
6349
6386
  const router = new Router();
6350
- const auth2 = (req, ctx, next) => {
6387
+ const auth = (req, ctx, next) => {
6351
6388
  if (!config.deployToken) return next(req, ctx);
6352
6389
  const header = req.headers.get("authorization") ?? "";
6353
6390
  const token = header.replace("Bearer ", "");
6354
6391
  const tokenBuf = Buffer.from(token);
6355
6392
  const secretBuf = Buffer.from(config.deployToken);
6356
- if (tokenBuf.length !== secretBuf.length || !crypto6.timingSafeEqual(tokenBuf, secretBuf)) {
6393
+ if (tokenBuf.length !== secretBuf.length || !crypto7.timingSafeEqual(tokenBuf, secretBuf)) {
6357
6394
  return Response.json({ error: "Unauthorized" }, { status: 401 });
6358
6395
  }
6359
6396
  return next(req, ctx);
6360
6397
  };
6361
- router.get("/apps", auth2, () => {
6398
+ router.get("/apps", auth, () => {
6362
6399
  const list = Array.from(apps.values()).map((a) => a.status);
6363
6400
  return Response.json(list);
6364
6401
  });
6365
- router.get("/apps/:name", auth2, (req, ctx) => {
6402
+ router.get("/apps/:name", auth, (req, ctx) => {
6366
6403
  const app = apps.get(ctx.params.name);
6367
6404
  if (!app) return new Response("Not Found", { status: 404 });
6368
6405
  return Response.json(app.status);
6369
6406
  });
6370
- router.post("/apps/:name/deploy", auth2, async (req, ctx) => {
6407
+ router.post("/apps/:name/deploy", auth, async (req, ctx) => {
6371
6408
  const app = apps.get(ctx.params.name);
6372
6409
  if (!app) return new Response("Not Found", { status: 404 });
6373
6410
  try {
@@ -6378,7 +6415,7 @@ function createManager(config, apps, manager) {
6378
6415
  return Response.json({ error: msg }, { status: 500 });
6379
6416
  }
6380
6417
  });
6381
- router.post("/apps/:name/restart", auth2, async (req, ctx) => {
6418
+ router.post("/apps/:name/restart", auth, async (req, ctx) => {
6382
6419
  const app = apps.get(ctx.params.name);
6383
6420
  if (!app) return new Response("Not Found", { status: 404 });
6384
6421
  try {
@@ -6389,7 +6426,7 @@ function createManager(config, apps, manager) {
6389
6426
  return Response.json({ error: msg }, { status: 500 });
6390
6427
  }
6391
6428
  });
6392
- router.post("/apps/:name/stop", auth2, async (req, ctx) => {
6429
+ router.post("/apps/:name/stop", auth, async (req, ctx) => {
6393
6430
  const app = apps.get(ctx.params.name);
6394
6431
  if (!app) return new Response("Not Found", { status: 404 });
6395
6432
  if (app.process) {
@@ -6399,7 +6436,7 @@ function createManager(config, apps, manager) {
6399
6436
  app.status = { ...app.status, status: "stopped", pid: void 0 };
6400
6437
  return Response.json({ success: true });
6401
6438
  });
6402
- router.post("/apps/:name/start", auth2, async (req, ctx) => {
6439
+ router.post("/apps/:name/start", auth, async (req, ctx) => {
6403
6440
  const app = apps.get(ctx.params.name);
6404
6441
  if (!app) return new Response("Not Found", { status: 404 });
6405
6442
  try {
@@ -6410,7 +6447,7 @@ function createManager(config, apps, manager) {
6410
6447
  return Response.json({ error: msg }, { status: 500 });
6411
6448
  }
6412
6449
  });
6413
- router.get("/apps/:name/logs", auth2, (req, ctx) => {
6450
+ router.get("/apps/:name/logs", auth, (req, ctx) => {
6414
6451
  const app = apps.get(ctx.params.name);
6415
6452
  if (!app) return new Response("Not Found", { status: 404 });
6416
6453
  let index = app.logs.length;
@@ -6462,9 +6499,9 @@ function defineConfig(config) {
6462
6499
  async function deploy(config) {
6463
6500
  const apps = /* @__PURE__ */ new Map();
6464
6501
  let httpServer;
6465
- async function forkAndCheck(name, cwd, entry, port, env, onLog, healthEndpoint) {
6502
+ async function forkAndCheck(name, cwd, entry, port, env2, onLog, healthEndpoint) {
6466
6503
  try {
6467
- const mp = forkApp({ cwd, entry, port, env, onLog });
6504
+ const mp = forkApp({ cwd, entry, port, env: env2, onLog });
6468
6505
  onLog(`[deploy] forked ${name} (pid ${mp.child.pid}) on port ${mp.port}`);
6469
6506
  const healthy = await healthCheck(port, healthEndpoint ?? "/");
6470
6507
  if (healthy) onLog(`[deploy] health check passed`);
@@ -6903,7 +6940,7 @@ async function compileHotComponent(path2) {
6903
6940
  // stream.ts
6904
6941
  import { TextDecoder as TextDecoder2, TextEncoder as TextEncoder2 } from "node:util";
6905
6942
  var _publicEnv = null;
6906
- function getPublicEnv() {
6943
+ function getPublicEnv2() {
6907
6944
  if (_publicEnv) return _publicEnv;
6908
6945
  _publicEnv = {};
6909
6946
  for (const key of Object.keys(process.env)) {
@@ -6954,7 +6991,7 @@ function buildHeadPayload(opts) {
6954
6991
  }
6955
6992
  ctxData.user = safeUser;
6956
6993
  }
6957
- const publicEnv = getPublicEnv();
6994
+ const publicEnv = getPublicEnv2();
6958
6995
  if (Object.keys(publicEnv).length > 0) {
6959
6996
  ctxData.env = publicEnv;
6960
6997
  }
@@ -7662,7 +7699,7 @@ function ssr(opts) {
7662
7699
  }
7663
7700
 
7664
7701
  // opencode/session.ts
7665
- import { randomUUID as randomUUID3 } from "node:crypto";
7702
+ import { randomUUID as randomUUID2 } from "node:crypto";
7666
7703
  import { join as join6 } from "node:path";
7667
7704
  import { mkdir as mkdir2 } from "node:fs/promises";
7668
7705
  var sessions = pgTable("_opencode_sessions", {
@@ -7688,7 +7725,7 @@ var messages = pgTable("_opencode_messages", {
7688
7725
  created_at: timestamptz("created_at")
7689
7726
  });
7690
7727
  async function createSession(sql2, opts, cwd, mountPath) {
7691
- const id2 = randomUUID3();
7728
+ const id2 = randomUUID2();
7692
7729
  const ws = computeSessionWorkspace(cwd, mountPath, id2);
7693
7730
  await mkdir2(ws, { recursive: true });
7694
7731
  const [row] = await sql2`
@@ -8860,30 +8897,37 @@ function makeSetTheme(cookie, location) {
8860
8897
  }
8861
8898
  function theme(options) {
8862
8899
  const opts = { default: "system", cookie: "theme", ...options };
8863
- return async (req, ctx, next) => {
8864
- const url = new URL(req.url);
8865
- const match = url.pathname.match(/^\/__theme\/([\w-]+)$/);
8866
- if (match && req.method === "GET") {
8867
- const value = match[1];
8868
- const cookie = `${opts.cookie}=${encodeURIComponent(value)}; Path=/; SameSite=Lax`;
8869
- const accept = req.headers.get("accept") ?? "";
8870
- if (accept.includes("application/json")) {
8871
- return Response.json({ ok: true, theme: value }, { headers: { "Set-Cookie": cookie } });
8872
- }
8873
- const referer = req.headers.get("referer") || "/";
8874
- return new Response(null, { status: 302, headers: { Location: referer, "Set-Cookie": cookie } });
8875
- }
8900
+ const mw = async (req, ctx, next) => {
8876
8901
  let themeValue = opts.default;
8877
8902
  if (opts.cookie) {
8878
8903
  const fromCookie = getCookies(req)[opts.cookie];
8879
8904
  if (fromCookie) themeValue = fromCookie;
8880
8905
  }
8906
+ ;
8881
8907
  ctx.theme = {
8882
8908
  value: themeValue,
8883
8909
  set: makeSetTheme(opts.cookie, req.headers.get("referer") || "/")
8884
8910
  };
8885
8911
  return next(req, ctx);
8886
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;
8887
8931
  }
8888
8932
 
8889
8933
  // i18n.ts
@@ -8949,23 +8993,7 @@ function i18n(options) {
8949
8993
  }
8950
8994
  return opts.default;
8951
8995
  }
8952
- return async (req, ctx, next) => {
8953
- const url = new URL(req.url);
8954
- const match = url.pathname.match(/^\/__lang\/([\w-]+)$/);
8955
- if (match && req.method === "GET") {
8956
- const value = match[1];
8957
- const cookie = `${opts.cookie}=${encodeURIComponent(value)}; Path=/; SameSite=Lax`;
8958
- const messages2 = await loadMessages(value);
8959
- const accept = req.headers.get("accept") ?? "";
8960
- if (accept.includes("application/json")) {
8961
- return Response.json(
8962
- { ok: true, locale: value, messages: Object.keys(messages2).length > 0 ? messages2 : void 0 },
8963
- { headers: { "Set-Cookie": cookie } }
8964
- );
8965
- }
8966
- const referer = req.headers.get("referer") || "/";
8967
- return new Response(null, { status: 302, headers: { Location: referer, "Set-Cookie": cookie } });
8968
- }
8996
+ const mw = async (req, ctx, next) => {
8969
8997
  const locale = detectLocale(req);
8970
8998
  const msgs = await loadMessages(locale);
8971
8999
  ctx.i18n = {
@@ -8980,6 +9008,28 @@ function i18n(options) {
8980
9008
  };
8981
9009
  return next(req, ctx);
8982
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;
8983
9033
  }
8984
9034
 
8985
9035
  // flash.ts
@@ -9209,13 +9259,13 @@ function csrf(options) {
9209
9259
  let token = getCookies(req)[cookieName];
9210
9260
  if (!token) {
9211
9261
  token = crypto.randomUUID();
9212
- ctx.csrfToken = token;
9262
+ ctx.csrf = { token };
9213
9263
  } else {
9214
9264
  ;
9215
- ctx.csrfToken = token;
9265
+ ctx.csrf = { token };
9216
9266
  }
9217
9267
  const res = await next(req, ctx);
9218
- const tokenToSet = ctx.csrfToken;
9268
+ const tokenToSet = ctx.csrf?.token;
9219
9269
  if (tokenToSet && !getCookies(req)[cookieName]) {
9220
9270
  return setCookie(res, cookieName, tokenToSet, {
9221
9271
  httpOnly: true,
@@ -9400,7 +9450,7 @@ function logdb(options) {
9400
9450
  }
9401
9451
 
9402
9452
  // iii/client.ts
9403
- import crypto7 from "node:crypto";
9453
+ import crypto8 from "node:crypto";
9404
9454
 
9405
9455
  // iii/stream.ts
9406
9456
  function notify(channels, stream, group, item, event, data) {
@@ -9929,7 +9979,7 @@ function iii(opts = {}) {
9929
9979
  registerBuiltin("stream::send", (p) => stream.send(p.stream_name, p.group_id, p.type, p.data, p.id));
9930
9980
  registerBuiltin("stream::update", (p) => stream.update(p.stream_name, p.group_id, p.item_id, p.ops));
9931
9981
  function addLocalWorker(worker) {
9932
- const workerId = crypto7.randomUUID();
9982
+ const workerId = crypto8.randomUUID();
9933
9983
  const reg = {
9934
9984
  id: workerId,
9935
9985
  name: worker.name,
@@ -9944,7 +9994,7 @@ function iii(opts = {}) {
9944
9994
  const triggerIds = [];
9945
9995
  for (const t of worker.getTriggers()) {
9946
9996
  if (t.input.function_id === fn.id) {
9947
- const tid = crypto7.randomUUID();
9997
+ const tid = crypto8.randomUUID();
9948
9998
  triggers.set(tid, {
9949
9999
  id: tid,
9950
10000
  type: t.input.type,
@@ -9973,7 +10023,7 @@ function iii(opts = {}) {
9973
10023
  if (!worker) return;
9974
10024
  const handler = async (payload) => {
9975
10025
  if (!worker.ws) throw new Error(`Worker "${worker.name}" disconnected`);
9976
- const invocationId = crypto7.randomUUID();
10026
+ const invocationId = crypto8.randomUUID();
9977
10027
  return new Promise((resolve14, reject) => {
9978
10028
  const timer = setTimeout(() => {
9979
10029
  pending.delete(invocationId);
@@ -10008,7 +10058,7 @@ function iii(opts = {}) {
10008
10058
  let engineRef = null;
10009
10059
  const wsHandler = createWsHandler({
10010
10060
  registerRemoteWorker(ws, name) {
10011
- const id2 = crypto7.randomUUID();
10061
+ const id2 = crypto8.randomUUID();
10012
10062
  workers.set(id2, { id: id2, name, ws, functions: [], triggers: [] });
10013
10063
  return id2;
10014
10064
  },
@@ -10019,7 +10069,7 @@ function iii(opts = {}) {
10019
10069
  addRemoteFunction(workerId, id2);
10020
10070
  },
10021
10071
  registerRemoteTrigger(workerId, input) {
10022
- const tid = crypto7.randomUUID();
10072
+ const tid = crypto8.randomUUID();
10023
10073
  const reg = { id: tid, ...input, workerId };
10024
10074
  triggers.set(tid, reg);
10025
10075
  const worker = workers.get(workerId);
@@ -10155,6 +10205,7 @@ function iii(opts = {}) {
10155
10205
  triggers.clear();
10156
10206
  await stream.close();
10157
10207
  };
10208
+ mod.close = mod.shutdown;
10158
10209
  return mod;
10159
10210
  }
10160
10211
 
@@ -10369,7 +10420,7 @@ function registerWorker(url) {
10369
10420
  }
10370
10421
 
10371
10422
  // session.ts
10372
- import crypto8 from "node:crypto";
10423
+ import crypto9 from "node:crypto";
10373
10424
  var kSaved = /* @__PURE__ */ Symbol("session.saved");
10374
10425
  var kDestroyed = /* @__PURE__ */ Symbol("session.destroyed");
10375
10426
  var kId = /* @__PURE__ */ Symbol("session.id");
@@ -10447,7 +10498,7 @@ var RedisStore = class {
10447
10498
  };
10448
10499
  var COOKIE_SEPARATOR = ".";
10449
10500
  function signSessionId(sid, secret) {
10450
- const hmac = crypto8.createHmac("sha256", secret).update(sid).digest("base64url").slice(0, 16);
10501
+ const hmac = crypto9.createHmac("sha256", secret).update(sid).digest("base64url").slice(0, 16);
10451
10502
  return sid + COOKIE_SEPARATOR + hmac;
10452
10503
  }
10453
10504
  function unsignSessionId(value, secret) {
@@ -10455,10 +10506,10 @@ function unsignSessionId(value, secret) {
10455
10506
  if (dot === -1) return null;
10456
10507
  const sid = value.slice(0, dot);
10457
10508
  const sig = value.slice(dot + 1);
10458
- const expected = crypto8.createHmac("sha256", secret).update(sid).digest("base64url").slice(0, 16);
10509
+ const expected = crypto9.createHmac("sha256", secret).update(sid).digest("base64url").slice(0, 16);
10459
10510
  if (sig.length !== expected.length) return null;
10460
10511
  try {
10461
- return crypto8.timingSafeEqual(Buffer.from(sig), Buffer.from(expected)) ? sid : null;
10512
+ return crypto9.timingSafeEqual(Buffer.from(sig), Buffer.from(expected)) ? sid : null;
10462
10513
  } catch {
10463
10514
  return null;
10464
10515
  }
@@ -10546,11 +10597,11 @@ function session(options) {
10546
10597
  }
10547
10598
  } else {
10548
10599
  loadedSid = null;
10549
- session2 = createSessionObject({}, crypto8.randomUUID(), store2, ttl, Date.now());
10600
+ session2 = createSessionObject({}, crypto9.randomUUID(), store2, ttl, Date.now());
10550
10601
  }
10551
10602
  } else {
10552
10603
  loadedSid = null;
10553
- session2 = createSessionObject({}, crypto8.randomUUID(), store2, ttl, Date.now());
10604
+ session2 = createSessionObject({}, crypto9.randomUUID(), store2, ttl, Date.now());
10554
10605
  }
10555
10606
  const snapshot = isSessionActive(session2) ? JSON.stringify(session2) : null;
10556
10607
  ctx.session = session2;
@@ -10563,7 +10614,7 @@ function session(options) {
10563
10614
  return deleteCookie(res, cookieName, cookieOpts);
10564
10615
  }
10565
10616
  if (needsRotation && loadedSid) {
10566
- const newId = crypto8.randomUUID();
10617
+ const newId = crypto9.randomUUID();
10567
10618
  const data = JSON.parse(JSON.stringify(currentSession));
10568
10619
  data[kCreatedAt] = Date.now();
10569
10620
  await store2.set(newId, data, ttl);
@@ -10604,7 +10655,7 @@ function session(options) {
10604
10655
  }
10605
10656
 
10606
10657
  // cache.ts
10607
- import crypto9 from "node:crypto";
10658
+ import crypto10 from "node:crypto";
10608
10659
  var BINARY_PREFIXES = [
10609
10660
  "image/",
10610
10661
  "audio/",
@@ -10624,7 +10675,7 @@ function isCacheableStatus(status, allowed) {
10624
10675
  return allowed.includes(status);
10625
10676
  }
10626
10677
  function defaultCacheKey(req) {
10627
- const hash = crypto9.createHash("sha256");
10678
+ const hash = crypto10.createHash("sha256");
10628
10679
  hash.update(req.method);
10629
10680
  hash.update(req.url);
10630
10681
  return hash.digest("hex");
@@ -10839,10 +10890,10 @@ function cache2(options) {
10839
10890
  }
10840
10891
 
10841
10892
  // webhook.ts
10842
- import crypto10 from "node:crypto";
10893
+ import crypto11 from "node:crypto";
10843
10894
  function timingSafeEqual2(a, b) {
10844
10895
  try {
10845
- return crypto10.timingSafeEqual(Buffer.from(a), Buffer.from(b));
10896
+ return crypto11.timingSafeEqual(Buffer.from(a), Buffer.from(b));
10846
10897
  } catch {
10847
10898
  return false;
10848
10899
  }
@@ -10860,7 +10911,7 @@ function createStripeVerifier(config) {
10860
10911
  const signature = parts["v1"];
10861
10912
  if (!timestamp || !signature) return { valid: false, provider: "stripe", event: "", id: void 0 };
10862
10913
  const signed = `${timestamp}.${body}`;
10863
- const expected = crypto10.createHmac("sha256", config.secret).update(signed).digest("hex");
10914
+ const expected = crypto11.createHmac("sha256", config.secret).update(signed).digest("hex");
10864
10915
  const valid = timingSafeEqual2(signature, expected);
10865
10916
  let event = "";
10866
10917
  let id2;
@@ -10877,7 +10928,7 @@ function createGitHubVerifier(config) {
10877
10928
  return (body, headers) => {
10878
10929
  const sig = headers["x-hub-signature-256"];
10879
10930
  if (!sig) return { valid: false, provider: "github", event: "", id: void 0 };
10880
- const expected = `sha256=${crypto10.createHmac("sha256", config.secret).update(body).digest("hex")}`;
10931
+ const expected = `sha256=${crypto11.createHmac("sha256", config.secret).update(body).digest("hex")}`;
10881
10932
  const valid = timingSafeEqual2(sig, expected);
10882
10933
  let event = headers["x-github-event"] ?? "";
10883
10934
  let id2;
@@ -10900,7 +10951,7 @@ function createSlackVerifier(config) {
10900
10951
  return { valid: false, provider: "slack", event: "", id: void 0 };
10901
10952
  }
10902
10953
  const sigBase = `v0:${timestamp}:${body}`;
10903
- const expected = `v0=${crypto10.createHmac("sha256", config.secret).update(sigBase).digest("hex")}`;
10954
+ const expected = `v0=${crypto11.createHmac("sha256", config.secret).update(sigBase).digest("hex")}`;
10904
10955
  const valid = timingSafeEqual2(signature, expected);
10905
10956
  let event = "";
10906
10957
  let id2;
@@ -11534,7 +11585,6 @@ export {
11534
11585
  aiProvider,
11535
11586
  aiStream,
11536
11587
  analytics,
11537
- auth,
11538
11588
  cache2 as cache,
11539
11589
  compress,
11540
11590
  cors,
@@ -11552,6 +11602,7 @@ export {
11552
11602
  deploy,
11553
11603
  embed,
11554
11604
  embedMany,
11605
+ env,
11555
11606
  flash,
11556
11607
  formatSSE,
11557
11608
  formatSSEData,
@@ -11559,6 +11610,7 @@ export {
11559
11610
  generateObject,
11560
11611
  generateText2 as generateText,
11561
11612
  getCookies,
11613
+ getPublicEnv,
11562
11614
  graphql,
11563
11615
  health,
11564
11616
  helmet,
@@ -11600,6 +11652,7 @@ export {
11600
11652
  testApp,
11601
11653
  theme,
11602
11654
  tool2 as tool,
11655
+ trace,
11603
11656
  traceElapsed,
11604
11657
  upload,
11605
11658
  user,