weifuwu 0.27.24 → 0.27.26

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
@@ -9,7 +9,7 @@ var HttpError = class extends Error {
9
9
  };
10
10
 
11
11
  // core/trace.ts
12
- import crypto2 from "node:crypto";
12
+ import crypto from "node:crypto";
13
13
  import { AsyncLocalStorage } from "node:async_hooks";
14
14
  var als = new AsyncLocalStorage();
15
15
  function currentTraceId() {
@@ -19,7 +19,7 @@ function currentTrace() {
19
19
  return als.getStore();
20
20
  }
21
21
  function runWithTrace(incomingTraceId, fn) {
22
- const traceId = incomingTraceId || crypto2.randomUUID();
22
+ const traceId = incomingTraceId || crypto.randomUUID();
23
23
  const startTime = Date.now();
24
24
  return als.run({ traceId, startTime }, fn);
25
25
  }
@@ -30,7 +30,7 @@ function traceElapsed() {
30
30
  }
31
31
  function trace(options) {
32
32
  const header = options?.header ?? "X-Request-ID";
33
- const gen = options?.generator ?? (() => crypto2.randomUUID());
33
+ const gen = options?.generator ?? (() => crypto.randomUUID());
34
34
  return async (req, ctx, next) => {
35
35
  const existing = req.headers.get(header);
36
36
  const requestId2 = existing ?? gen();
@@ -293,14 +293,14 @@ function serve(handler, options) {
293
293
  if (!server.listening) return;
294
294
  server.close();
295
295
  server.closeIdleConnections();
296
- return new Promise((resolve8) => {
296
+ return new Promise((resolve3) => {
297
297
  const timer = setTimeout(() => {
298
298
  server.closeAllConnections();
299
- resolve8();
299
+ resolve3();
300
300
  }, timeoutMs);
301
301
  server.on("close", () => {
302
302
  clearTimeout(timer);
303
- resolve8();
303
+ resolve3();
304
304
  });
305
305
  });
306
306
  }
@@ -345,7 +345,7 @@ function createHub(opts) {
345
345
  }
346
346
  });
347
347
  }
348
- function join4(key, ws) {
348
+ function join2(key, ws) {
349
349
  if (!channels.has(key)) {
350
350
  channels.set(key, /* @__PURE__ */ new Set());
351
351
  redisSub?.subscribe(`${prefix}${key}`);
@@ -407,7 +407,7 @@ function createHub(opts) {
407
407
  redisPub = void 0;
408
408
  redisSub = null;
409
409
  }
410
- return { join: join4, leave, broadcast, close };
410
+ return { join: join2, leave, broadcast, close };
411
411
  }
412
412
 
413
413
  // core/router.ts
@@ -919,7 +919,7 @@ function upgradeSocket(wss, req, socket, head, handler, ctx, hub) {
919
919
  hub.leave(ws);
920
920
  },
921
921
  sendRoom(room, data) {
922
- hub.broadcast(room, JSON.stringify(data));
922
+ hub.broadcast(room, data);
923
923
  }
924
924
  };
925
925
  if (handler.open) {
@@ -1082,13 +1082,13 @@ function serveStatic(root, options) {
1082
1082
  let fileHandle;
1083
1083
  try {
1084
1084
  fileHandle = await open(filePath, "r");
1085
- let stat2 = await fileHandle.stat();
1085
+ let stat = await fileHandle.stat();
1086
1086
  const realPath = await realpath(filePath);
1087
1087
  if (!realPath.startsWith(rootDir + sep) && realPath !== rootDir) {
1088
1088
  await fileHandle.close();
1089
1089
  return new Response("Forbidden", { status: 403 });
1090
1090
  }
1091
- if (stat2.isDirectory()) {
1091
+ if (stat.isDirectory()) {
1092
1092
  await fileHandle.close();
1093
1093
  const indexFile = opts.index ?? "index.html";
1094
1094
  filePath = resolve2(filePath, indexFile);
@@ -1096,29 +1096,29 @@ function serveStatic(root, options) {
1096
1096
  return new Response("Forbidden", { status: 403 });
1097
1097
  }
1098
1098
  fileHandle = await open(filePath, "r");
1099
- stat2 = await fileHandle.stat();
1100
- if (!stat2.isFile()) {
1099
+ stat = await fileHandle.stat();
1100
+ if (!stat.isFile()) {
1101
1101
  await fileHandle.close();
1102
1102
  return new Response("Not Found", { status: 404 });
1103
1103
  }
1104
1104
  }
1105
1105
  const mimeType = MIME_TYPES[extname(filePath).toLowerCase()] ?? "application/octet-stream";
1106
- const etag = `"${stat2.ino}-${stat2.size}-${stat2.mtimeMs}"`;
1106
+ const etag = `"${stat.ino}-${stat.size}-${stat.mtimeMs}"`;
1107
1107
  const ifNoneMatch = req.headers.get("if-none-match");
1108
1108
  if (ifNoneMatch === etag) {
1109
1109
  await fileHandle.close();
1110
1110
  return new Response(null, { status: 304 });
1111
1111
  }
1112
1112
  const ifModifiedSince = req.headers.get("if-modified-since");
1113
- if (ifModifiedSince && stat2.mtimeMs <= new Date(ifModifiedSince).getTime()) {
1113
+ if (ifModifiedSince && stat.mtimeMs <= new Date(ifModifiedSince).getTime()) {
1114
1114
  await fileHandle.close();
1115
1115
  return new Response(null, { status: 304 });
1116
1116
  }
1117
1117
  const headers = {
1118
1118
  "Content-Type": mimeType,
1119
- "Content-Length": String(stat2.size),
1119
+ "Content-Length": String(stat.size),
1120
1120
  ETag: etag,
1121
- "Last-Modified": stat2.mtime.toUTCString(),
1121
+ "Last-Modified": stat.mtime.toUTCString(),
1122
1122
  "Cache-Control": opts.immutable ? `public, max-age=${opts.maxAge ?? 31536e3}, immutable` : `public, max-age=${opts.maxAge ?? 0}`
1123
1123
  };
1124
1124
  const readStream = fileHandle.createReadStream();
@@ -1656,10 +1656,10 @@ var DEFAULTS = {
1656
1656
  };
1657
1657
 
1658
1658
  // middleware/request-id.ts
1659
- import crypto3 from "node:crypto";
1659
+ import crypto2 from "node:crypto";
1660
1660
  function requestId(options) {
1661
1661
  const header = options?.header ?? "X-Request-ID";
1662
- const gen = options?.generator ?? (() => crypto3.randomUUID());
1662
+ const gen = options?.generator ?? (() => crypto2.randomUUID());
1663
1663
  const mw = async (req, ctx, next) => {
1664
1664
  const existing = req.headers.get(header);
1665
1665
  const id = existing ?? gen();
@@ -1960,7 +1960,7 @@ var TestWSRequest = class {
1960
1960
  const baseUrl = await this.app._ensureServer();
1961
1961
  const wsUrl = baseUrl.replace(/^http/, "ws") + this.path;
1962
1962
  const ws = new WSWebSocket(wsUrl, { handshakeTimeout: this._timeout });
1963
- return new Promise((resolve8, reject) => {
1963
+ return new Promise((resolve3, reject) => {
1964
1964
  const timer = setTimeout(() => {
1965
1965
  reject(new Error(`WebSocket connection timed out after ${this._timeout}ms`));
1966
1966
  ws.close();
@@ -1969,7 +1969,7 @@ var TestWSRequest = class {
1969
1969
  clearTimeout(timer);
1970
1970
  const conn = new TestWSConnection(ws, this._timeout);
1971
1971
  this.app._trackConnection(conn);
1972
- resolve8(conn);
1972
+ resolve3(conn);
1973
1973
  });
1974
1974
  ws.on("error", (err) => {
1975
1975
  clearTimeout(timer);
@@ -2000,8 +2000,8 @@ var TestWSConnection = class {
2000
2000
  ws.on("message", (data) => {
2001
2001
  const str = data.toString();
2002
2002
  if (this.resolveQueue.length > 0) {
2003
- const resolve8 = this.resolveQueue.shift();
2004
- resolve8(str);
2003
+ const resolve3 = this.resolveQueue.shift();
2004
+ resolve3(str);
2005
2005
  } else {
2006
2006
  this.messageQueue.push(str);
2007
2007
  }
@@ -2031,15 +2031,15 @@ var TestWSConnection = class {
2031
2031
  if (this._closed) {
2032
2032
  throw new Error("WebSocket connection closed");
2033
2033
  }
2034
- return new Promise((resolve8, reject) => {
2034
+ return new Promise((resolve3, reject) => {
2035
2035
  const timer = setTimeout(() => {
2036
- const idx = this.resolveQueue.indexOf(resolve8);
2036
+ const idx = this.resolveQueue.indexOf(resolve3);
2037
2037
  if (idx !== -1) this.resolveQueue.splice(idx, 1);
2038
2038
  reject(new Error(`WebSocket receive timed out after ${timeout ?? this._timeout}ms`));
2039
2039
  }, timeout ?? this._timeout);
2040
2040
  this.resolveQueue.push((msg) => {
2041
2041
  clearTimeout(timer);
2042
- resolve8(msg);
2042
+ resolve3(msg);
2043
2043
  });
2044
2044
  });
2045
2045
  }
@@ -2053,12 +2053,12 @@ var TestWSConnection = class {
2053
2053
  * Useful for verifying that something did NOT happen.
2054
2054
  */
2055
2055
  async expectSilent(ms) {
2056
- return new Promise((resolve8, reject) => {
2056
+ return new Promise((resolve3, reject) => {
2057
2057
  if (this.messageQueue.length > 0) {
2058
2058
  reject(new Error(`Expected silence but got message: ${this.messageQueue[0].slice(0, 100)}`));
2059
2059
  return;
2060
2060
  }
2061
- const timer = setTimeout(() => resolve8(), ms);
2061
+ const timer = setTimeout(() => resolve3(), ms);
2062
2062
  const origPush = this.resolveQueue.push.bind(this.resolveQueue);
2063
2063
  this.resolveQueue.push = (_fn) => {
2064
2064
  clearTimeout(timer);
@@ -2460,8 +2460,8 @@ function postgres(opts) {
2460
2460
  const stmtTimeout = options.statementTimeout ?? 3e4;
2461
2461
  let connStr = typeof connection === "string" ? connection : "";
2462
2462
  if (stmtTimeout > 0 && typeof connection === "string") {
2463
- const sep3 = connStr.includes("?") ? "&" : "?";
2464
- connStr = `${connStr}${sep3}options=-c%20statement_timeout%3D${stmtTimeout}`;
2463
+ const sep2 = connStr.includes("?") ? "&" : "?";
2464
+ connStr = `${connStr}${sep2}options=-c%20statement_timeout%3D${stmtTimeout}`;
2465
2465
  }
2466
2466
  const sql = postgresFactory(connStr, {
2467
2467
  max: options.max,
@@ -2554,7 +2554,7 @@ function redis(opts) {
2554
2554
 
2555
2555
  // queue/index.ts
2556
2556
  import { Redis as IORedis2 } from "ioredis";
2557
- import crypto4 from "node:crypto";
2557
+ import crypto3 from "node:crypto";
2558
2558
 
2559
2559
  // queue/cron.ts
2560
2560
  function parseField(field, min, max) {
@@ -2633,7 +2633,7 @@ function escapeIdent(s) {
2633
2633
  function attachCron(q, handlers) {
2634
2634
  ;
2635
2635
  q.cron = function(pattern, handler) {
2636
- const id = "__cron_" + pattern.replace(/[^a-zA-Z0-9]/g, "_") + "_" + crypto4.randomUUID().slice(0, 8);
2636
+ const id = "__cron_" + pattern.replace(/[^a-zA-Z0-9]/g, "_") + "_" + crypto3.randomUUID().slice(0, 8);
2637
2637
  q.process(id, async () => {
2638
2638
  await handler();
2639
2639
  });
@@ -2674,7 +2674,7 @@ function createMemoryQueue(opts) {
2674
2674
  try {
2675
2675
  insertJob({
2676
2676
  ...job,
2677
- id: crypto4.randomUUID(),
2677
+ id: crypto3.randomUUID(),
2678
2678
  runAt: cronNext(job.schedule),
2679
2679
  createdAt: Date.now()
2680
2680
  });
@@ -2699,7 +2699,7 @@ function createMemoryQueue(opts) {
2699
2699
  });
2700
2700
  const q = mw;
2701
2701
  mw.add = function add(type, payload, opts2) {
2702
- const id = crypto4.randomUUID();
2702
+ const id = crypto3.randomUUID();
2703
2703
  let runAt;
2704
2704
  if (opts2?.schedule) {
2705
2705
  try {
@@ -2815,7 +2815,7 @@ function createPgQueue(opts) {
2815
2815
  await sql.unsafe(
2816
2816
  `INSERT INTO ${escapeIdent(table)} (id, type, payload, run_at, schedule) VALUES ($1, $2, $3::jsonb, $4, $5)`,
2817
2817
  [
2818
- crypto4.randomUUID(),
2818
+ crypto3.randomUUID(),
2819
2819
  job.type,
2820
2820
  JSON.stringify(job.payload),
2821
2821
  new Date(nextRun).toISOString(),
@@ -2865,7 +2865,7 @@ function createPgQueue(opts) {
2865
2865
  const q = mw;
2866
2866
  mw.add = function add(type, payload, opts2) {
2867
2867
  return (async () => {
2868
- const id = crypto4.randomUUID();
2868
+ const id = crypto3.randomUUID();
2869
2869
  let runAt;
2870
2870
  if (opts2?.schedule) {
2871
2871
  try {
@@ -2996,7 +2996,7 @@ function createRedisQueue(opts) {
2996
2996
  nextRun,
2997
2997
  JSON.stringify({
2998
2998
  ...job,
2999
- id: crypto4.randomUUID(),
2999
+ id: crypto3.randomUUID(),
3000
3000
  runAt: nextRun,
3001
3001
  createdAt: Date.now()
3002
3002
  })
@@ -3014,14 +3014,14 @@ function createRedisQueue(opts) {
3014
3014
  while (running && inflight < MAX_CONCURRENT) {
3015
3015
  const result = await redis2.zpopmin(jobKey);
3016
3016
  if (result.length < 2) break;
3017
- const raw2 = result[0], score = parseInt(result[1], 10);
3017
+ const raw = result[0], score = parseInt(result[1], 10);
3018
3018
  if (score > now) {
3019
- await redis2.zadd(jobKey, score, raw2);
3019
+ await redis2.zadd(jobKey, score, raw);
3020
3020
  break;
3021
3021
  }
3022
3022
  let job;
3023
3023
  try {
3024
- job = JSON.parse(raw2);
3024
+ job = JSON.parse(raw);
3025
3025
  } catch {
3026
3026
  continue;
3027
3027
  }
@@ -3039,7 +3039,7 @@ function createRedisQueue(opts) {
3039
3039
  });
3040
3040
  const q = mw;
3041
3041
  mw.add = function add(type, payload, opts2) {
3042
- const id = crypto4.randomUUID();
3042
+ const id = crypto3.randomUUID();
3043
3043
  let runAt;
3044
3044
  if (opts2?.schedule) {
3045
3045
  runAt = cronNext(opts2.schedule);
@@ -3071,8 +3071,8 @@ function createRedisQueue(opts) {
3071
3071
  redis2.disconnect();
3072
3072
  };
3073
3073
  mw.jobs = async function jobs(limit) {
3074
- const raw2 = await redis2.zrevrange(jobKey, 0, (limit ?? 50) - 1);
3075
- return raw2.map((r) => {
3074
+ const raw = await redis2.zrevrange(jobKey, 0, (limit ?? 50) - 1);
3075
+ return raw.map((r) => {
3076
3076
  try {
3077
3077
  return JSON.parse(r);
3078
3078
  } catch {
@@ -3081,8 +3081,8 @@ function createRedisQueue(opts) {
3081
3081
  }).filter(Boolean);
3082
3082
  };
3083
3083
  mw.failedJobs = async function failedJobs(limit) {
3084
- const raw2 = await redis2.lrange(failedKey, 0, (limit ?? 50) - 1);
3085
- return raw2.map((r) => {
3084
+ const raw = await redis2.lrange(failedKey, 0, (limit ?? 50) - 1);
3085
+ return raw.map((r) => {
3086
3086
  try {
3087
3087
  return JSON.parse(r);
3088
3088
  } catch {
@@ -3091,8 +3091,8 @@ function createRedisQueue(opts) {
3091
3091
  }).filter(Boolean);
3092
3092
  };
3093
3093
  mw.retryFailed = async function retryFailed(jobId) {
3094
- const raw2 = await redis2.lrange(failedKey, 0, -1);
3095
- for (const entry of raw2) {
3094
+ const raw = await redis2.lrange(failedKey, 0, -1);
3095
+ for (const entry of raw) {
3096
3096
  try {
3097
3097
  const job = JSON.parse(entry);
3098
3098
  if (job.id === jobId) {
@@ -3111,8 +3111,8 @@ function createRedisQueue(opts) {
3111
3111
  };
3112
3112
  mw.retryAllFailed = async function retryAllFailed(type) {
3113
3113
  let count = 0;
3114
- const raw2 = await redis2.lrange(failedKey, 0, -1);
3115
- for (const entry of raw2) {
3114
+ const raw = await redis2.lrange(failedKey, 0, -1);
3115
+ for (const entry of raw) {
3116
3116
  try {
3117
3117
  const job = JSON.parse(entry);
3118
3118
  if (type && job.type !== type) continue;
@@ -3190,540 +3190,6 @@ function health(options) {
3190
3190
  r.head(path, handler);
3191
3191
  return r;
3192
3192
  }
3193
-
3194
- // middleware/theme.ts
3195
- function makeSetTheme(cookie, location) {
3196
- return (value, loc) => {
3197
- const finalLoc = loc ?? location;
3198
- const c = `${cookie}=${encodeURIComponent(value)}; Path=/; SameSite=Lax`;
3199
- return new Response(null, { status: 302, headers: { Location: finalLoc, "Set-Cookie": c } });
3200
- };
3201
- }
3202
- function theme(options) {
3203
- const opts = { default: "system", cookie: "theme", ...options };
3204
- const mw = async (req, ctx, next) => {
3205
- let themeValue = opts.default;
3206
- if (opts.cookie) {
3207
- const fromCookie = getCookies(req)[opts.cookie];
3208
- if (fromCookie) themeValue = fromCookie;
3209
- }
3210
- ;
3211
- ctx.theme = {
3212
- value: themeValue,
3213
- set: makeSetTheme(opts.cookie, req.headers.get("referer") || "/")
3214
- };
3215
- return next(req, ctx);
3216
- };
3217
- mw.__meta = { injects: ["theme"], depends: [] };
3218
- class ThemeRouter extends Router {
3219
- middleware() {
3220
- return mw;
3221
- }
3222
- }
3223
- const router = new ThemeRouter();
3224
- router.get("/__theme/:value", (req) => {
3225
- const url = new URL(req.url);
3226
- const value = url.pathname.split("/__theme/")[1] ?? "";
3227
- const cookie = `${opts.cookie}=${encodeURIComponent(value)}; Path=/; SameSite=Lax`;
3228
- const accept = req.headers.get("accept") ?? "";
3229
- if (accept.includes("application/json")) {
3230
- return Response.json({ ok: true, theme: value }, { headers: { "Set-Cookie": cookie } });
3231
- }
3232
- const referer = req.headers.get("referer") || "/";
3233
- return new Response(null, { status: 302, headers: { Location: referer, "Set-Cookie": cookie } });
3234
- });
3235
- return router;
3236
- }
3237
-
3238
- // middleware/i18n.ts
3239
- import { readFile, stat } from "node:fs/promises";
3240
- import { join as join2, resolve as resolve3 } from "node:path";
3241
- var DEFAULTS2 = {
3242
- default: "en",
3243
- cookie: "locale",
3244
- fromAcceptLanguage: true
3245
- };
3246
- function translate(msgs, key, params, fallback) {
3247
- const msg = key.split(".").reduce((o, k) => o?.[k], msgs);
3248
- if (msg === void 0 || msg === null) return fallback ?? key;
3249
- if (!params) return String(msg);
3250
- let result = String(msg);
3251
- for (const [k, v] of Object.entries(params)) {
3252
- result = result.replace(`{${k}}`, v);
3253
- }
3254
- return result;
3255
- }
3256
- function i18n(options) {
3257
- const opts = { ...DEFAULTS2, ...options };
3258
- const dir = opts.dir ? resolve3(opts.dir) : void 0;
3259
- const cache = /* @__PURE__ */ new Map();
3260
- function validLocale(locale) {
3261
- return /^[\w-]+$/.test(locale) && !locale.includes("..");
3262
- }
3263
- async function loadMessages(locale) {
3264
- if (opts.messages?.[locale] && Object.keys(opts.messages[locale]).length > 0) {
3265
- cache.set(locale, opts.messages[locale]);
3266
- return opts.messages[locale];
3267
- }
3268
- if (!dir || !validLocale(locale)) return {};
3269
- const cached = cache.get(locale);
3270
- if (cached) return cached;
3271
- const filePath = join2(dir, `${locale}.json`);
3272
- try {
3273
- await stat(filePath);
3274
- const content = await readFile(filePath, "utf-8");
3275
- const data = JSON.parse(content);
3276
- cache.set(locale, data);
3277
- return data;
3278
- } catch {
3279
- }
3280
- const short = locale.split("-")[0];
3281
- if (short !== locale) {
3282
- const fallback = cache.get(short) || await loadMessages(short);
3283
- if (fallback && Object.keys(fallback).length > 0) {
3284
- cache.set(locale, fallback);
3285
- return fallback;
3286
- }
3287
- }
3288
- return {};
3289
- }
3290
- function detectLocale(req) {
3291
- if (opts.cookie) {
3292
- const fromCookie = getCookies(req)[opts.cookie];
3293
- if (fromCookie && validLocale(fromCookie)) return fromCookie;
3294
- }
3295
- if (opts.fromAcceptLanguage) {
3296
- const fromHeader = req.headers.get("Accept-Language")?.split(",")[0]?.trim();
3297
- if (fromHeader && validLocale(fromHeader)) return fromHeader;
3298
- }
3299
- return opts.default;
3300
- }
3301
- const mw = async (req, ctx, next) => {
3302
- const locale = detectLocale(req);
3303
- const msgs = await loadMessages(locale);
3304
- ctx.i18n = {
3305
- locale,
3306
- messages: msgs,
3307
- t: (key, params, fallback) => translate(msgs, key, params, fallback),
3308
- set: (value, loc) => {
3309
- const cookie = `${opts.cookie}=${encodeURIComponent(value)}; Path=/; SameSite=Lax`;
3310
- const location = loc ?? (req.headers.get("referer") || "/");
3311
- return new Response(null, {
3312
- status: 302,
3313
- headers: { Location: location, "Set-Cookie": cookie }
3314
- });
3315
- }
3316
- };
3317
- return next(req, ctx);
3318
- };
3319
- mw.__meta = { injects: ["i18n"], depends: [] };
3320
- class I18nRouter extends Router {
3321
- middleware() {
3322
- return mw;
3323
- }
3324
- }
3325
- const router = new I18nRouter();
3326
- router.get("/__lang/:locale", async (req) => {
3327
- const url = new URL(req.url);
3328
- const value = url.pathname.split("/__lang/")[1] ?? "";
3329
- const cookie = `${opts.cookie}=${encodeURIComponent(value)}; Path=/; SameSite=Lax`;
3330
- const messages = await loadMessages(value);
3331
- const accept = req.headers.get("accept") ?? "";
3332
- if (accept.includes("application/json")) {
3333
- return Response.json(
3334
- {
3335
- ok: true,
3336
- locale: value,
3337
- messages: Object.keys(messages).length > 0 ? messages : void 0
3338
- },
3339
- { headers: { "Set-Cookie": cookie } }
3340
- );
3341
- }
3342
- const referer = req.headers.get("referer") || "/";
3343
- return new Response(null, { status: 302, headers: { Location: referer, "Set-Cookie": cookie } });
3344
- });
3345
- return router;
3346
- }
3347
-
3348
- // middleware/flash.ts
3349
- function makeSetFlash(name, location) {
3350
- return (data, loc) => {
3351
- const finalLoc = loc ?? location;
3352
- const value = encodeURIComponent(JSON.stringify(data));
3353
- return new Response(null, {
3354
- status: 302,
3355
- headers: {
3356
- Location: finalLoc,
3357
- "Set-Cookie": `${name}=${value}; Path=/; SameSite=Lax`
3358
- }
3359
- });
3360
- };
3361
- }
3362
- function flash(options) {
3363
- const name = options?.name ?? "flash";
3364
- const mw = async (req, ctx, next) => {
3365
- const raw2 = getCookies(req)[name] ?? null;
3366
- const referer = req.headers.get("referer") || "/";
3367
- let value = void 0;
3368
- if (raw2) {
3369
- try {
3370
- value = JSON.parse(decodeURIComponent(raw2));
3371
- } catch {
3372
- value = raw2;
3373
- }
3374
- }
3375
- ctx.flash = {
3376
- value,
3377
- set: makeSetFlash(name, referer)
3378
- };
3379
- const res = await next(req, ctx);
3380
- if (raw2) {
3381
- const headers = new Headers(res.headers);
3382
- headers.append("Set-Cookie", `${name}=; Path=/; Max-Age=0`);
3383
- return new Response(res.body, { status: res.status, statusText: res.statusText, headers });
3384
- }
3385
- return res;
3386
- };
3387
- mw.__meta = { injects: ["flash"], depends: [] };
3388
- return mw;
3389
- }
3390
-
3391
- // middleware/csrf.ts
3392
- function csrf(options) {
3393
- const cookieName = options?.cookie ?? "_csrf";
3394
- const headerName = options?.header ?? "x-csrf-token";
3395
- const bodyKey = options?.key ?? "_csrf";
3396
- const excluded = new Set(options?.excludeMethods ?? ["GET", "HEAD", "OPTIONS"]);
3397
- const mw = async (req, ctx, next) => {
3398
- const method = req.method.toUpperCase();
3399
- if (excluded.has(method)) {
3400
- let token = getCookies(req)[cookieName];
3401
- if (!token) {
3402
- token = crypto.randomUUID();
3403
- ctx.csrf = { token };
3404
- } else {
3405
- ;
3406
- ctx.csrf = { token };
3407
- }
3408
- const res = await next(req, ctx);
3409
- const tokenToSet = ctx.csrf?.token;
3410
- if (tokenToSet && !getCookies(req)[cookieName]) {
3411
- return setCookie(res, cookieName, tokenToSet, {
3412
- httpOnly: true,
3413
- sameSite: "strict",
3414
- path: "/"
3415
- });
3416
- }
3417
- return res;
3418
- }
3419
- const cookieToken = getCookies(req)[cookieName];
3420
- let headerToken = req.headers.get(headerName) ?? "";
3421
- if (!headerToken && (req.method === "POST" || req.method === "PUT" || req.method === "PATCH" || req.method === "DELETE")) {
3422
- try {
3423
- const body = await req.clone().json();
3424
- headerToken = body[bodyKey] ?? "";
3425
- } catch (e) {
3426
- return new Response("Invalid request body", { status: 400 });
3427
- }
3428
- }
3429
- if (!cookieToken || !headerToken || cookieToken !== headerToken) {
3430
- return new Response("CSRF token mismatch", { status: 403 });
3431
- }
3432
- return next(req, ctx);
3433
- };
3434
- mw.__meta = { injects: ["csrf"], depends: [] };
3435
- return mw;
3436
- }
3437
-
3438
- // ssr/html.ts
3439
- var ESCAPE_MAP = {
3440
- "&": "&amp;",
3441
- "<": "&lt;",
3442
- ">": "&gt;",
3443
- '"': "&quot;",
3444
- "'": "&#39;"
3445
- };
3446
- function escapeHtml(s) {
3447
- const str = String(s);
3448
- if (!/[&<>"']/.test(str)) return str;
3449
- return str.replace(/[&<>"']/g, (c) => ESCAPE_MAP[c] || c);
3450
- }
3451
- function raw(s) {
3452
- return {
3453
- __brand: "RawString",
3454
- value: s,
3455
- toString() {
3456
- return this.value;
3457
- }
3458
- };
3459
- }
3460
- function isRaw(v) {
3461
- return typeof v === "object" && v !== null && "__brand" in v && v.__brand === "RawString";
3462
- }
3463
- function html(strings, ...values) {
3464
- let result = "";
3465
- for (let i = 0; i < strings.length; i++) {
3466
- result += strings[i];
3467
- if (i < values.length) {
3468
- result += stringify(values[i]);
3469
- }
3470
- }
3471
- return raw(result);
3472
- }
3473
- function stringify(v) {
3474
- if (v === null || v === void 0 || v === false) return "";
3475
- if (isRaw(v)) return v.value;
3476
- if (Array.isArray(v)) {
3477
- let out = "";
3478
- for (let i = 0; i < v.length; i++) {
3479
- out += stringify(v[i]);
3480
- }
3481
- return out;
3482
- }
3483
- if (typeof v === "number") return String(v);
3484
- return escapeHtml(v);
3485
- }
3486
-
3487
- // ssr/layout.ts
3488
- import { resolve as resolve4, isAbsolute } from "node:path";
3489
- function layout(path) {
3490
- const absPath = isAbsolute(path) ? path : resolve4(process.cwd(), path);
3491
- let modPromise = null;
3492
- async function getRenderFn() {
3493
- if (!modPromise) {
3494
- modPromise = import(absPath).catch((err) => {
3495
- modPromise = null;
3496
- throw new Error(
3497
- `[layout] Failed to load layout module "${path}": ${err instanceof Error ? err.message : String(err)}`
3498
- );
3499
- });
3500
- }
3501
- const mod = await modPromise;
3502
- const renderFn = mod.default;
3503
- if (typeof renderFn !== "function") {
3504
- throw new Error(
3505
- `[layout] Layout module "${path}" must export a default function, got ${typeof renderFn}`
3506
- );
3507
- }
3508
- return renderFn;
3509
- }
3510
- const mw = async (req, ctx, next) => {
3511
- const renderFn = await getRenderFn();
3512
- const response = await next(req, ctx);
3513
- const ct = response.headers.get("content-type") ?? "";
3514
- if (!ct.includes("text/html")) return response;
3515
- const body = await response.text();
3516
- const wrapped = await renderFn(body, ctx);
3517
- return new Response(wrapped, {
3518
- status: response.status,
3519
- headers: { "content-type": "text/html; charset=utf-8" }
3520
- });
3521
- };
3522
- mw.__meta = { injects: [], depends: [] };
3523
- return mw;
3524
- }
3525
-
3526
- // ssr/compile.ts
3527
- import { resolve as resolve5, isAbsolute as isAbsolute2 } from "node:path";
3528
- var moduleCache = /* @__PURE__ */ new Map();
3529
- var loading = /* @__PURE__ */ new Map();
3530
- async function loadModule(path) {
3531
- const absPath = isAbsolute2(path) ? path : resolve5(process.cwd(), path);
3532
- const cached = moduleCache.get(absPath);
3533
- if (cached) return cached;
3534
- const inFlight = loading.get(absPath);
3535
- if (inFlight) return inFlight;
3536
- const promise = import(absPath).then((mod) => {
3537
- loading.delete(absPath);
3538
- moduleCache.set(absPath, Promise.resolve(mod));
3539
- return mod;
3540
- }).catch((err) => {
3541
- loading.delete(absPath);
3542
- moduleCache.delete(absPath);
3543
- throw new Error(
3544
- `[compile] Failed to load module "${path}": ${err instanceof Error ? err.message : String(err)}`
3545
- );
3546
- });
3547
- loading.set(absPath, promise);
3548
- return promise;
3549
- }
3550
- function clearModuleCache(path) {
3551
- if (path) {
3552
- const absPath = isAbsolute2(path) ? path : resolve5(process.cwd(), path);
3553
- moduleCache.delete(absPath);
3554
- loading.delete(absPath);
3555
- } else {
3556
- moduleCache.clear();
3557
- loading.clear();
3558
- }
3559
- }
3560
-
3561
- // ssr/view.ts
3562
- function isRawString(v) {
3563
- return typeof v === "object" && v !== null && "__brand" in v && v.__brand === "RawString";
3564
- }
3565
- function isResponse(v) {
3566
- return v instanceof Response;
3567
- }
3568
- function view(path, options) {
3569
- return async (req, ctx) => {
3570
- let mod;
3571
- if (options?.module) {
3572
- mod = options.module;
3573
- } else {
3574
- mod = await loadModule(path);
3575
- }
3576
- const renderFn = mod.default;
3577
- if (typeof renderFn !== "function") {
3578
- throw new Error(
3579
- `[view] Module "${path}" must export a default function, got ${typeof renderFn}`
3580
- );
3581
- }
3582
- const result = renderFn.length >= 1 ? await renderFn(ctx) : await renderFn();
3583
- if (isResponse(result)) return result;
3584
- const body = isRawString(result) ? result.value : String(result);
3585
- return new Response(body, {
3586
- status: 200,
3587
- headers: { "content-type": "text/html; charset=utf-8" }
3588
- });
3589
- };
3590
- }
3591
-
3592
- // ssr/css.ts
3593
- import { createHash } from "node:crypto";
3594
- import { existsSync, readFileSync as readFileSync2 } from "node:fs";
3595
- import { join as join3, resolve as resolve6, sep as sep2 } from "node:path";
3596
- import tailwindPlugin from "@tailwindcss/postcss";
3597
- import postcssNesting from "postcss-nesting";
3598
- import postcss from "postcss";
3599
- var cssCache = /* @__PURE__ */ new Map();
3600
- function findTailwindDir() {
3601
- const hoisted = resolve6(process.cwd(), "node_modules", "tailwindcss");
3602
- if (existsSync(hoisted)) return hoisted;
3603
- let dir = process.cwd();
3604
- const root = sep2 === "/" ? "/" : "";
3605
- while (dir !== root) {
3606
- const wfwDir = resolve6(dir, "node_modules", "weifuwu");
3607
- if (existsSync(wfwDir)) {
3608
- const nested = resolve6(wfwDir, "node_modules", "tailwindcss");
3609
- if (existsSync(nested)) return nested;
3610
- const parent = resolve6(dir, "..", "node_modules", "tailwindcss");
3611
- if (existsSync(parent)) return parent;
3612
- }
3613
- dir = resolve6(dir, "..");
3614
- }
3615
- return null;
3616
- }
3617
- async function compileCSS(cssPath, sourceDir) {
3618
- if (!existsSync(cssPath)) {
3619
- return { css: "", hash: "empty", url: "" };
3620
- }
3621
- let raw2 = readFileSync2(cssPath, "utf-8");
3622
- const tailwindDir = findTailwindDir();
3623
- if (tailwindDir && raw2.includes('@import "tailwindcss"')) {
3624
- const tailwindCss = readFileSync2(join3(tailwindDir, "index.css"), "utf-8");
3625
- raw2 = raw2.replace('@import "tailwindcss"', tailwindCss);
3626
- }
3627
- const src = `@source "${sourceDir}";
3628
- ${raw2}`;
3629
- const result = await postcss([tailwindPlugin(), postcssNesting()]).process(src, { from: cssPath });
3630
- const hash = createHash("md5").update(result.css).digest("hex").slice(0, 8);
3631
- const asset = { css: result.css, hash, url: `/__wfw/style/${hash}.css` };
3632
- cssCache.set(cssPath, asset);
3633
- return asset;
3634
- }
3635
- function cssContext(dir) {
3636
- const appDir = resolve6(dir, "app");
3637
- const cssPath = join3(appDir, "globals.css");
3638
- let cached = null;
3639
- return async (req, ctx, next) => {
3640
- if (!cached) cached = compileCSS(cssPath, appDir);
3641
- const asset = await cached;
3642
- if (asset.css) ctx.css = asset;
3643
- return next(req, ctx);
3644
- };
3645
- }
3646
- function cssRouter(dir) {
3647
- const router = new Router();
3648
- router.get("/__wfw/style/:hash.css", async () => {
3649
- const cssPath = join3(resolve6(dir, "app"), "globals.css");
3650
- const asset = cssCache.get(cssPath);
3651
- if (!asset) return new Response("", { status: 404 });
3652
- return new Response(asset.css, {
3653
- headers: { "content-type": "text/css; charset=utf-8" }
3654
- });
3655
- });
3656
- return router;
3657
- }
3658
- function clearCSSCache() {
3659
- cssCache.clear();
3660
- }
3661
-
3662
- // ssr/ui/assets.ts
3663
- import { readFileSync as readFileSync3 } from "node:fs";
3664
- import { resolve as resolve7, dirname } from "node:path";
3665
- import { fileURLToPath } from "node:url";
3666
- var __dirname = dirname(fileURLToPath(import.meta.url));
3667
- var wfuwVersion = (() => {
3668
- try {
3669
- const js = readFileSync3(resolve7(__dirname, "weifuwu-ui.js"), "utf-8");
3670
- const m = js.match(/WFU_VERSION = '([^']+)'/);
3671
- return m ? m[1] : "0.0.0";
3672
- } catch {
3673
- return "0.0.0";
3674
- }
3675
- })();
3676
- function wfuwAssets() {
3677
- const router = new Router();
3678
- const jsPath = resolve7(__dirname, "weifuwu-ui.js");
3679
- const cssPath = resolve7(__dirname, "weifuwu-ui.css");
3680
- let jsContent = null;
3681
- let cssContent = null;
3682
- router.get("/__wfw/js/weifuwu-ui.js", () => {
3683
- if (!jsContent) {
3684
- try {
3685
- jsContent = readFileSync3(jsPath, "utf-8");
3686
- } catch {
3687
- return new Response("weifuwu-ui.js not found", { status: 404 });
3688
- }
3689
- }
3690
- return new Response(jsContent, {
3691
- headers: {
3692
- "content-type": "application/javascript; charset=utf-8",
3693
- "cache-control": "public, max-age=31536000, immutable"
3694
- }
3695
- });
3696
- });
3697
- router.get("/__wfw/css/weifuwu-ui.css", () => {
3698
- if (!cssContent) {
3699
- try {
3700
- cssContent = readFileSync3(cssPath, "utf-8");
3701
- } catch {
3702
- return new Response("weifuwu-ui.css not found", { status: 404 });
3703
- }
3704
- }
3705
- return new Response(cssContent, {
3706
- headers: {
3707
- "content-type": "text/css; charset=utf-8",
3708
- "cache-control": "public, max-age=31536000, immutable"
3709
- }
3710
- });
3711
- });
3712
- return router;
3713
- }
3714
-
3715
- // ssr/assets.ts
3716
- function assetRouter() {
3717
- console.warn("[weifuwu] assetRouter() is deprecated. Use wfuwAssets() instead.");
3718
- return wfuwAssets();
3719
- }
3720
- function assetScripts() {
3721
- console.warn("[weifuwu] assetScripts() is deprecated. Use weifuwu-ui.js directly.");
3722
- return raw(`
3723
- <script src="/__wfw/js/weifuwu-ui.js"></script>
3724
- <link rel="stylesheet" href="/__wfw/css/weifuwu-ui.css">
3725
- `);
3726
- }
3727
3193
  export {
3728
3194
  DEFAULT_MAX_BODY,
3729
3195
  HttpError,
@@ -3733,10 +3199,6 @@ export {
3733
3199
  TestRequest,
3734
3200
  aiProvider,
3735
3201
  aiStream,
3736
- assetRouter,
3737
- assetScripts,
3738
- clearCSSCache,
3739
- clearModuleCache,
3740
3202
  compress,
3741
3203
  cors,
3742
3204
  createHub,
@@ -3744,16 +3206,12 @@ export {
3744
3206
  createSSEStream,
3745
3207
  createTestDb,
3746
3208
  createTestServer,
3747
- csrf,
3748
- cssContext,
3749
- cssRouter,
3750
3209
  currentTrace,
3751
3210
  currentTraceId,
3752
3211
  deleteCookie,
3753
3212
  embed,
3754
3213
  embedMany,
3755
3214
  env,
3756
- flash,
3757
3215
  formatSSE,
3758
3216
  formatSSEData,
3759
3217
  generateObject,
@@ -3763,20 +3221,15 @@ export {
3763
3221
  graphql,
3764
3222
  health,
3765
3223
  helmet,
3766
- html,
3767
- i18n,
3768
3224
  isBundled,
3769
3225
  isDev,
3770
3226
  isProd,
3771
- layout,
3772
3227
  loadEnv,
3773
- loadModule,
3774
3228
  logger,
3775
3229
  openai,
3776
3230
  postgres,
3777
3231
  queue,
3778
3232
  rateLimit,
3779
- raw,
3780
3233
  redis,
3781
3234
  requestId,
3782
3235
  runWithTrace,
@@ -3787,14 +3240,10 @@ export {
3787
3240
  streamObject,
3788
3241
  streamText,
3789
3242
  testApp,
3790
- theme,
3791
3243
  tool,
3792
3244
  trace,
3793
3245
  traceElapsed,
3794
3246
  upload,
3795
3247
  validate,
3796
- view,
3797
- wfuwAssets,
3798
- wfuwVersion,
3799
3248
  withTestDb
3800
3249
  };