weifuwu 0.18.2 → 0.18.4

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.
Files changed (78) hide show
  1. package/cli.ts +10 -101
  2. package/dist/cli.js +7 -95
  3. package/dist/dist/agent/client.d.ts +2 -0
  4. package/dist/dist/agent/index.d.ts +2 -0
  5. package/dist/dist/agent/migrate.d.ts +6 -0
  6. package/dist/dist/agent/rest.d.ts +13 -0
  7. package/dist/dist/agent/run.d.ts +17 -0
  8. package/dist/dist/agent/types.d.ts +51 -0
  9. package/dist/dist/ai/workflow.d.ts +14 -0
  10. package/dist/dist/analytics.d.ts +15 -0
  11. package/dist/dist/client-locale.d.ts +5 -0
  12. package/dist/dist/client-pref.d.ts +3 -0
  13. package/dist/dist/client-state.d.ts +22 -0
  14. package/dist/dist/client-theme.d.ts +7 -0
  15. package/dist/dist/compress.d.ts +6 -0
  16. package/dist/dist/cookie.d.ts +12 -0
  17. package/dist/dist/deploy/config.d.ts +2 -0
  18. package/dist/dist/deploy/gateway.d.ts +2 -0
  19. package/dist/dist/deploy/index.d.ts +4 -0
  20. package/dist/dist/deploy/manager.d.ts +16 -0
  21. package/dist/dist/deploy/process.d.ts +14 -0
  22. package/dist/dist/deploy/types.d.ts +62 -0
  23. package/dist/dist/head.d.ts +6 -0
  24. package/dist/dist/helmet.d.ts +18 -0
  25. package/dist/dist/iii/client.d.ts +2 -0
  26. package/dist/dist/iii/index.d.ts +4 -0
  27. package/dist/dist/iii/register-worker.d.ts +10 -0
  28. package/dist/dist/iii/rest.d.ts +3 -0
  29. package/dist/dist/iii/stream.d.ts +82 -0
  30. package/dist/dist/iii/types.d.ts +133 -0
  31. package/dist/dist/iii/worker.d.ts +2 -0
  32. package/dist/dist/iii/ws.d.ts +29 -0
  33. package/dist/dist/index.js +8180 -0
  34. package/dist/dist/messager/agent.d.ts +6 -0
  35. package/dist/dist/messager/client.d.ts +2 -0
  36. package/dist/dist/messager/index.d.ts +2 -0
  37. package/dist/dist/messager/migrate.d.ts +2 -0
  38. package/dist/dist/messager/rest.d.ts +15 -0
  39. package/dist/dist/messager/types.d.ts +56 -0
  40. package/dist/dist/messager/ws.d.ts +14 -0
  41. package/dist/dist/preferences.d.ts +14 -0
  42. package/dist/dist/react.d.ts +12 -0
  43. package/dist/dist/react.js +637 -0
  44. package/dist/dist/request-id.d.ts +6 -0
  45. package/dist/dist/seo.d.ts +39 -0
  46. package/dist/dist/ssr/compile.d.ts +2 -0
  47. package/dist/{ssr → dist/ssr}/index.d.ts +1 -1
  48. package/dist/{ssr → dist/ssr}/index.js +372 -375
  49. package/dist/dist/ssr/ssr.d.ts +2 -0
  50. package/dist/dist/tenant/client.d.ts +2 -0
  51. package/dist/dist/tenant/graphql.d.ts +3 -0
  52. package/dist/dist/tenant/index.d.ts +2 -0
  53. package/dist/dist/tenant/migrate.d.ts +6 -0
  54. package/dist/dist/tenant/rest.d.ts +3 -0
  55. package/dist/dist/tenant/schema.d.ts +5 -0
  56. package/dist/dist/tenant/types.d.ts +48 -0
  57. package/dist/dist/tenant/utils.d.ts +10 -0
  58. package/dist/dist/types.d.ts +19 -0
  59. package/dist/dist/use-flash-message.d.ts +1 -0
  60. package/dist/error-boundary.d.ts +2 -0
  61. package/dist/index.d.ts +7 -0
  62. package/dist/index.js +213 -53
  63. package/dist/layout.d.ts +2 -0
  64. package/dist/live.d.ts +6 -0
  65. package/dist/not-found.d.ts +2 -0
  66. package/dist/router.d.ts +9 -9
  67. package/dist/ssr.d.ts +2 -0
  68. package/dist/stream.d.ts +14 -0
  69. package/dist/tailwind.d.ts +2 -0
  70. package/package.json +3 -4
  71. package/dist/ssr/ssr.d.ts +0 -3
  72. /package/dist/{ssr/compile.d.ts → compile.d.ts} +0 -0
  73. /package/dist/{ssr → dist/ssr}/error-boundary.d.ts +0 -0
  74. /package/dist/{ssr → dist/ssr}/layout.d.ts +0 -0
  75. /package/dist/{ssr → dist/ssr}/live.d.ts +0 -0
  76. /package/dist/{ssr → dist/ssr}/not-found.d.ts +0 -0
  77. /package/dist/{ssr → dist/ssr}/stream.d.ts +0 -0
  78. /package/dist/{ssr → dist/ssr}/tailwind.d.ts +0 -0
@@ -231,279 +231,6 @@ function setCtx(value) {
231
231
  }
232
232
  var TsxContext = createContext(DEFAULT_CTX);
233
233
 
234
- // ssr/ssr.ts
235
- var als = new AsyncLocalStorage();
236
- __registerAls(() => als.getStore());
237
- var isDev = process.env.NODE_ENV !== "production";
238
- function id2(s) {
239
- return createHash2("md5").update(s).digest("hex").slice(0, 8);
240
- }
241
- async function buildClientBundle(entryPath, layoutPaths) {
242
- try {
243
- const absEntry = resolve2(entryPath);
244
- const absLayouts = layoutPaths.map((p) => resolve2(p));
245
- const layoutImports = absLayouts.map((p) => `import${JSON.stringify(p)};`).join("");
246
- const _sc = `(function(){var k='__WEIFUWU_CTX_STORE';var s=typeof globalThis!='undefined'&&globalThis[k];if(!s)return function(){};return function(v){s._ctx={...s._ctx,...v};s._snapshot={params:s._ctx.params,query:s._ctx.query,user:s._ctx.user,parsed:s._ctx.parsed,prefs:s._ctx.prefs,env:s._ctx.env};s._listeners.forEach(function(fn){fn()})}})()`;
247
- const code = [
248
- layoutImports,
249
- `import{hydrateRoot}from'react-dom/client';`,
250
- `import{createElement,useState,useEffect}from'react';`,
251
- `import{TsxContext}from'weifuwu/react';`,
252
- `import P from${JSON.stringify(absEntry)};`,
253
- `var setCtx=${_sc};`,
254
- `const c=document.getElementById('__weifuwu_root');`,
255
- `if(window.__WEIFUWU_PROPS)setCtx({loaderData:window.__WEIFUWU_PROPS});`,
256
- `if(!window.__WFW_ROOT){`,
257
- `function App(){`,
258
- `const[p,setP]=useState({C:P});`,
259
- `useEffect(()=>{window.__WFW_SET_PAGE=(C)=>{setCtx({loaderData:window.__WEIFUWU_PROPS});setP({C})}},[]);`,
260
- `const ctx=window.__WEIFUWU_CTX||{};`,
261
- `return createElement(TsxContext.Provider,{value:ctx},`,
262
- `createElement(p.C,null))`,
263
- `}`,
264
- `window.__WFW_ROOT=hydrateRoot(c,createElement(App));`,
265
- `}else{`,
266
- `window.__WFW_SET_PAGE?.(P);`,
267
- `}`
268
- ].join("");
269
- const { default: esbuild2 } = await import("esbuild");
270
- const result = await esbuild2.build({
271
- stdin: { contents: code, loader: "tsx", resolveDir: dirname2(absEntry) },
272
- bundle: true,
273
- format: "esm",
274
- jsx: "automatic",
275
- jsxImportSource: "react",
276
- banner: { js: "self.process={env:{}};" },
277
- loader: { ".node": "empty" },
278
- write: false,
279
- minify: true
280
- });
281
- return result.outputFiles[0].contents;
282
- } catch (err) {
283
- console.error("hydration bundle failed:", err);
284
- return null;
285
- }
286
- }
287
- var bundleRegistry = /* @__PURE__ */ new Map();
288
- function serializeLoaderData(ctx) {
289
- const data = {};
290
- for (const key of Object.keys(ctx)) {
291
- if (!["params", "query", "mountPath", "layoutStack"].includes(key)) {
292
- data[key] = ctx[key];
293
- }
294
- }
295
- return data;
296
- }
297
- function ssr(path) {
298
- const entryId = id2(resolve2(path));
299
- const bundleKey = `/__ssr/${entryId}.js`;
300
- let bundleBuilt = false;
301
- return async (req, ctx) => {
302
- const pageMod = await compileTsx(path);
303
- const Component = pageMod.default;
304
- if (!Component) return new Response("", { status: 500 });
305
- const layouts = ctx.layoutStack || [];
306
- const layoutComponents = layouts.map((l) => l.component);
307
- const layoutPaths = layouts.map((l) => l.path);
308
- const base = (ctx.mountPath || "").replace(/\/$/, "");
309
- const loaderData = serializeLoaderData(ctx);
310
- const ctxValue = {
311
- params: ctx.params,
312
- query: ctx.query,
313
- user: ctx.user ?? {},
314
- parsed: ctx.parsed ?? {},
315
- prefs: ctx.prefs ?? {},
316
- loaderData,
317
- env: ctx.env ?? {}
318
- };
319
- return als.run(ctxValue, async () => {
320
- setCtx(ctxValue);
321
- let element = createElement(
322
- TsxContext.Provider,
323
- { value: ctxValue },
324
- createElement(
325
- "div",
326
- { id: "__weifuwu_root" },
327
- createElement(Component, null)
328
- )
329
- );
330
- if (layoutComponents.length === 0) {
331
- element = createElement(
332
- "html",
333
- { lang: "en" },
334
- createElement(
335
- "head",
336
- null,
337
- createElement("meta", { charSet: "utf-8" }),
338
- createElement("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
339
- createElement("title", null, "weifuwu")
340
- ),
341
- createElement("body", null, element)
342
- );
343
- } else {
344
- for (const L of layoutComponents.toReversed()) {
345
- element = createElement(L, { children: element });
346
- }
347
- }
348
- let bundle = null;
349
- if (!bundleBuilt) {
350
- const buf = await buildClientBundle(path, layoutPaths);
351
- if (buf) {
352
- bundleRegistry.set(bundleKey, buf);
353
- bundleBuilt = true;
354
- }
355
- }
356
- if (bundleRegistry.has(bundleKey)) {
357
- bundle = { url: bundleKey };
358
- }
359
- const { renderToReadableStream } = await import("react-dom/server");
360
- const stream = await renderToReadableStream(element);
361
- return streamResponse(stream, {
362
- ctx,
363
- base,
364
- isDev,
365
- bundle,
366
- loaderData
367
- });
368
- });
369
- };
370
- }
371
- function ssrBundleHandler() {
372
- return (req, ctx) => {
373
- const url = new URL(req.url);
374
- const buf = bundleRegistry.get(url.pathname);
375
- return buf ? new Response(buf, {
376
- headers: { "content-type": "application/javascript; charset=utf-8" }
377
- }) : new Response("", { status: 404 });
378
- };
379
- }
380
-
381
- // ssr/layout.ts
382
- function layout(path) {
383
- return async (req, ctx, next) => {
384
- const mod = await compileTsx(path);
385
- const Component = mod.default;
386
- if (!Component) throw new Error(`Layout ${path} has no default export`);
387
- ctx.layoutStack = [...ctx.layoutStack || [], { path, component: Component }];
388
- return next(req, ctx);
389
- };
390
- }
391
-
392
- // ssr/tailwind.ts
393
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync } from "node:fs";
394
- import { relative, resolve as resolve3 } from "node:path";
395
- var isDev2 = process.env.NODE_ENV !== "production";
396
- function tailwind(cssPath, scanDir) {
397
- let compiledCss = "";
398
- let twWatcher = null;
399
- return async (req, ctx, next) => {
400
- const url = new URL(req.url);
401
- if (url.pathname === "/__wfw/style.css") {
402
- if (!compiledCss) compiledCss = await compile(cssPath, scanDir);
403
- return new Response(compiledCss || "", {
404
- headers: { "content-type": "text/css; charset=utf-8" }
405
- });
406
- }
407
- ctx.compiledTailwindCss = compiledCss;
408
- if (isDev2 && !twWatcher) {
409
- twWatcher = watchFile(cssPath, () => {
410
- compiledCss = "";
411
- });
412
- }
413
- return next(req, ctx);
414
- };
415
- }
416
- async function compile(cssPath, scanDir) {
417
- try {
418
- const inputFile = resolve3(cssPath);
419
- if (!existsSync2(inputFile)) {
420
- mkdirSync2(dirname3(inputFile), { recursive: true });
421
- writeFileSync(inputFile, '@import "tailwindcss"\n', "utf-8");
422
- }
423
- const { default: tailwindPlugin } = await import("@tailwindcss/postcss");
424
- const { default: postcss } = await import("postcss");
425
- let src = readFileSync2(inputFile, "utf-8");
426
- const scanSource = scanDir ? relative(dirname3(inputFile), scanDir) || "." : ".";
427
- const sourcePath = scanSource === "." ? "./" : `./${scanSource}/`;
428
- src = `@source "${sourcePath}";
429
- ${src}`;
430
- const result = await postcss([tailwindPlugin()]).process(src, { from: inputFile });
431
- return result.css;
432
- } catch (err) {
433
- console.warn("Tailwind CSS processing failed:", err.message);
434
- return "";
435
- }
436
- }
437
- function dirname3(p) {
438
- return p.substring(0, p.lastIndexOf("/")) || "/";
439
- }
440
- function watchFile(path, onChange) {
441
- let watcher = null;
442
- import("chokidar").then((chokidar2) => {
443
- watcher = chokidar2.default.watch(resolve3(path), { persistent: false });
444
- watcher.on("change", onChange);
445
- });
446
- return watcher;
447
- }
448
-
449
- // ssr/not-found.ts
450
- function notFound(path) {
451
- return async (req, ctx) => {
452
- if (!path) return new Response("Not Found", { status: 404 });
453
- const mod = await compileTsx(path);
454
- const Component = mod?.default;
455
- const body = Component ? "404 - Not Found" : "404 - Not Found";
456
- return new Response(body, {
457
- status: 404,
458
- headers: { "content-type": "text/html; charset=utf-8" }
459
- });
460
- };
461
- }
462
-
463
- // ssr/error-boundary.ts
464
- import { createElement as createElement2 } from "react";
465
- import { TextEncoder as TextEncoder2 } from "node:util";
466
- function errorBoundary(errorPath) {
467
- return async (req, ctx, next) => {
468
- try {
469
- return await next(req, ctx);
470
- } catch (err) {
471
- const mod = await compileTsx(errorPath);
472
- const ErrorComponent = mod.default;
473
- if (!ErrorComponent) throw err;
474
- const layouts = (ctx.layoutStack || []).map((l) => l.component);
475
- const stream = await import("react-dom/server").then((m) => m.renderToReadableStream(
476
- createElement2(ErrorComponent, {
477
- error: err instanceof Error ? err : new Error(String(err)),
478
- reset: () => {
479
- }
480
- })
481
- ));
482
- const reader = stream.getReader();
483
- const chunks = [];
484
- while (true) {
485
- const { done, value } = await reader.read();
486
- if (done) break;
487
- chunks.push(value);
488
- }
489
- const encoder = new TextEncoder2();
490
- const body = chunks.reduce((acc, c) => {
491
- const merged = new Uint8Array(acc.length + c.length);
492
- merged.set(acc);
493
- merged.set(c, acc.length);
494
- return merged;
495
- }, new Uint8Array(0));
496
- return new Response(body, {
497
- status: 500,
498
- headers: { "content-type": "text/html; charset=utf-8" }
499
- });
500
- }
501
- };
502
- }
503
-
504
- // ssr/live.ts
505
- import chokidar from "chokidar";
506
-
507
234
  // router.ts
508
235
  import { WebSocketServer } from "ws";
509
236
  var createTrieNode = () => ({
@@ -632,6 +359,11 @@ var Router = class _Router {
632
359
  return this;
633
360
  }
634
361
  route(method, path, ...args) {
362
+ const last = args[args.length - 1];
363
+ if (last instanceof _Router) {
364
+ this._mountRouter(path, last);
365
+ return this;
366
+ }
635
367
  const handler = args.pop();
636
368
  const middlewares = args;
637
369
  const segments = this.splitPath(path);
@@ -779,117 +511,383 @@ var Router = class _Router {
779
511
  wildcardIdx = i;
780
512
  }
781
513
  }
782
- const segment = segments[i];
783
- if (!segment) break;
784
- const next = matchTrieNode(node, segment, params);
785
- if (!next) {
786
- if (wildcardHandler) {
787
- params["*"] = segments.slice(wildcardIdx).join("/");
788
- return { handler: wildcardHandler, middlewares: wildcardMws, pathMws, params };
789
- }
790
- return null;
514
+ const segment = segments[i];
515
+ if (!segment) break;
516
+ const next = matchTrieNode(node, segment, params);
517
+ if (!next) {
518
+ if (wildcardHandler) {
519
+ params["*"] = segments.slice(wildcardIdx).join("/");
520
+ return { handler: wildcardHandler, middlewares: wildcardMws, pathMws, params };
521
+ }
522
+ return null;
523
+ }
524
+ node = next;
525
+ }
526
+ pathMws.push(...node.pathMws);
527
+ const handler = node.handlers.get(method) || node.handlers.get("*");
528
+ if (handler) {
529
+ if (node.wildcard) params["*"] = segments.slice(segments.length).join("/");
530
+ return {
531
+ handler,
532
+ middlewares: node.middlewares.get(method) || node.middlewares.get("*") || [],
533
+ pathMws,
534
+ params
535
+ };
536
+ }
537
+ if (wildcardHandler) {
538
+ params["*"] = segments.slice(wildcardIdx).join("/");
539
+ return { handler: wildcardHandler, middlewares: wildcardMws, pathMws, params };
540
+ }
541
+ return null;
542
+ }
543
+ matchWsTrie(root, segments) {
544
+ let node = root;
545
+ const params = {};
546
+ for (const segment of segments) {
547
+ const next = matchWsNode(node, segment, params);
548
+ if (!next) return null;
549
+ node = next;
550
+ }
551
+ return node.handler ? { handler: node.handler, middlewares: node.middlewares, params } : null;
552
+ }
553
+ async handle(req, ctx, segments, query) {
554
+ const match = this.matchTrie(req.method, segments);
555
+ if (match?.handler) {
556
+ const { handler, middlewares: routeMws, pathMws, params } = match;
557
+ const allMws = this.globalMws.length + pathMws.length + routeMws.length === 0 ? [] : [...this.globalMws, ...pathMws, ...routeMws];
558
+ const ctxWithMatch = { ...ctx, params: { ...ctx.params, ...params } };
559
+ try {
560
+ return await this.runChain(allMws, handler, req, ctxWithMatch);
561
+ } catch (e) {
562
+ const err = e instanceof Error ? e : new Error(String(e));
563
+ return this.errorHandler ? this.errorHandler(err, req, ctxWithMatch) : new Response("Internal Server Error", { status: 500 });
564
+ }
565
+ }
566
+ if (this.globalMws.length > 0) {
567
+ try {
568
+ const delegate = () => new Response("Not Found", { status: 404 });
569
+ return await this.runChain(this.globalMws, delegate, req, ctx);
570
+ } catch (e) {
571
+ const err = e instanceof Error ? e : new Error(String(e));
572
+ return this.errorHandler ? this.errorHandler(err, req, ctx) : new Response("Internal Server Error", { status: 500 });
573
+ }
574
+ }
575
+ return new Response("Not Found", { status: 404 });
576
+ }
577
+ async runChain(middlewares, finalHandler, req, ctx) {
578
+ let index = 0;
579
+ const dispatch = async (req2, ctx2) => {
580
+ if (index < middlewares.length) {
581
+ const mw = middlewares[index++];
582
+ return mw ? await mw(req2, ctx2, dispatch) : new Response("Middleware error", { status: 500 });
583
+ }
584
+ return await finalHandler(req2, ctx2);
585
+ };
586
+ return dispatch(req, ctx);
587
+ }
588
+ };
589
+ function upgradeSocket(wss, req, socket, head, handler, ctx) {
590
+ wss.handleUpgrade(req, socket, head, (ws) => {
591
+ if (handler.open) {
592
+ handler.open(ws, ctx);
593
+ }
594
+ ws.on("message", (data) => {
595
+ handler.message?.(ws, ctx, data);
596
+ });
597
+ ws.on("close", () => {
598
+ handler.close?.(ws, ctx);
599
+ });
600
+ ws.on("error", (err) => {
601
+ handler.error?.(ws, ctx, err);
602
+ });
603
+ });
604
+ }
605
+ function sendHttpResponseOnSocket(socket, response) {
606
+ const statusLine = `HTTP/1.1 ${response.status} ${response.statusText}`;
607
+ const headerLines = [statusLine];
608
+ response.headers.forEach((value, key) => {
609
+ headerLines.push(`${key}: ${value}`);
610
+ });
611
+ headerLines.push("Connection: close");
612
+ headerLines.push("");
613
+ const headerStr = headerLines.join("\r\n");
614
+ response.arrayBuffer().then((buf) => {
615
+ const body = Buffer.from(buf);
616
+ socket.write(headerStr + "\r\n" + body.toString());
617
+ socket.end();
618
+ }).catch(() => {
619
+ socket.write(headerStr + "\r\n");
620
+ socket.end();
621
+ });
622
+ }
623
+
624
+ // ssr/ssr.ts
625
+ var als = new AsyncLocalStorage();
626
+ __registerAls(() => als.getStore());
627
+ var isDev = process.env.NODE_ENV !== "production";
628
+ var bundleCache = /* @__PURE__ */ new Map();
629
+ function id2(s) {
630
+ return createHash2("md5").update(s).digest("hex").slice(0, 8);
631
+ }
632
+ function serializeLoaderData(ctx) {
633
+ const data = {};
634
+ for (const key of Object.keys(ctx)) {
635
+ if (!["params", "query", "mountPath", "layoutStack"].includes(key)) {
636
+ data[key] = ctx[key];
637
+ }
638
+ }
639
+ return data;
640
+ }
641
+ async function buildClientBundle(entryPath, layoutPaths) {
642
+ try {
643
+ const absEntry = resolve2(entryPath);
644
+ const absLayouts = layoutPaths.map((p) => resolve2(p));
645
+ const layoutImports = absLayouts.map((p) => `import${JSON.stringify(p)};`).join("");
646
+ const _sc = `(function(){var k='__WEIFUWU_CTX_STORE';var s=typeof globalThis!='undefined'&&globalThis[k];if(!s)return function(){};return function(v){s._ctx={...s._ctx,...v};s._snapshot={params:s._ctx.params,query:s._ctx.query,user:s._ctx.user,parsed:s._ctx.parsed,prefs:s._ctx.prefs,env:s._ctx.env};s._listeners.forEach(function(fn){fn()})}})()`;
647
+ const code = [
648
+ layoutImports,
649
+ `import{hydrateRoot}from'react-dom/client';`,
650
+ `import{createElement,useState,useEffect}from'react';`,
651
+ `import{TsxContext}from'weifuwu/react';`,
652
+ `import P from${JSON.stringify(absEntry)};`,
653
+ `var setCtx=${_sc};`,
654
+ `const c=document.getElementById('__weifuwu_root');`,
655
+ `if(window.__WEIFUWU_PROPS)setCtx({loaderData:window.__WEIFUWU_PROPS});`,
656
+ `if(!window.__WFW_ROOT){`,
657
+ `function App(){`,
658
+ `const[p,setP]=useState({C:P});`,
659
+ `useEffect(()=>{window.__WFW_SET_PAGE=(C)=>{setCtx({loaderData:window.__WEIFUWU_PROPS});setP({C})}},[]);`,
660
+ `const ctx=window.__WEIFUWU_CTX||{};`,
661
+ `return createElement(TsxContext.Provider,{value:ctx},`,
662
+ `createElement(p.C,null))`,
663
+ `}`,
664
+ `window.__WFW_ROOT=hydrateRoot(c,createElement(App));`,
665
+ `}else{`,
666
+ `window.__WFW_SET_PAGE?.(P);`,
667
+ `}`
668
+ ].join("");
669
+ const { default: esbuild2 } = await import("esbuild");
670
+ const result = await esbuild2.build({
671
+ stdin: { contents: code, loader: "tsx", resolveDir: dirname2(absEntry) },
672
+ bundle: true,
673
+ format: "esm",
674
+ jsx: "automatic",
675
+ jsxImportSource: "react",
676
+ banner: { js: "self.process={env:{}};" },
677
+ loader: { ".node": "empty" },
678
+ write: false,
679
+ minify: true
680
+ });
681
+ return result.outputFiles[0].contents;
682
+ } catch (err) {
683
+ console.error("hydration bundle failed:", err);
684
+ return null;
685
+ }
686
+ }
687
+ function ssr(path) {
688
+ const entryId = id2(resolve2(path));
689
+ const bundleKey = `/__ssr/${entryId}.js`;
690
+ const r = new Router();
691
+ r.get("/__ssr/:path", (req, ctx) => {
692
+ const buf = bundleCache.get("/__ssr/" + ctx.params.path);
693
+ return buf ? new Response(buf, {
694
+ headers: { "content-type": "application/javascript; charset=utf-8" }
695
+ }) : new Response("", { status: 404 });
696
+ });
697
+ r.get("/", async (req, ctx) => {
698
+ const pageMod = await compileTsx(path);
699
+ const Component = pageMod.default;
700
+ if (!Component) return new Response("", { status: 500 });
701
+ const layouts = ctx.layoutStack || [];
702
+ const layoutComponents = layouts.map((l) => l.component);
703
+ const layoutPaths = layouts.map((l) => l.path);
704
+ const base = (ctx.mountPath || "").replace(/\/$/, "");
705
+ const loaderData = serializeLoaderData(ctx);
706
+ const ctxValue = {
707
+ params: ctx.params,
708
+ query: ctx.query,
709
+ user: ctx.user ?? {},
710
+ parsed: ctx.parsed ?? {},
711
+ prefs: ctx.prefs ?? {},
712
+ loaderData,
713
+ env: ctx.env ?? {}
714
+ };
715
+ return als.run(ctxValue, async () => {
716
+ setCtx(ctxValue);
717
+ let element = createElement(
718
+ TsxContext.Provider,
719
+ { value: ctxValue },
720
+ createElement(
721
+ "div",
722
+ { id: "__weifuwu_root" },
723
+ createElement(Component, null)
724
+ )
725
+ );
726
+ if (layoutComponents.length === 0) {
727
+ element = createElement(
728
+ "html",
729
+ { lang: "en" },
730
+ createElement(
731
+ "head",
732
+ null,
733
+ createElement("meta", { charSet: "utf-8" }),
734
+ createElement("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
735
+ createElement("title", null, "weifuwu")
736
+ ),
737
+ createElement("body", null, element)
738
+ );
739
+ } else {
740
+ for (const L of layoutComponents.toReversed()) {
741
+ element = createElement(L, { children: element });
742
+ }
743
+ }
744
+ let bundle = null;
745
+ if (!bundleCache.has(bundleKey)) {
746
+ const buf = await buildClientBundle(path, layoutPaths);
747
+ if (buf) bundleCache.set(bundleKey, buf);
791
748
  }
792
- node = next;
793
- }
794
- pathMws.push(...node.pathMws);
795
- const handler = node.handlers.get(method) || node.handlers.get("*");
796
- if (handler) {
797
- if (node.wildcard) params["*"] = segments.slice(segments.length).join("/");
798
- return {
799
- handler,
800
- middlewares: node.middlewares.get(method) || node.middlewares.get("*") || [],
801
- pathMws,
802
- params
803
- };
804
- }
805
- if (wildcardHandler) {
806
- params["*"] = segments.slice(wildcardIdx).join("/");
807
- return { handler: wildcardHandler, middlewares: wildcardMws, pathMws, params };
808
- }
809
- return null;
810
- }
811
- matchWsTrie(root, segments) {
812
- let node = root;
813
- const params = {};
814
- for (const segment of segments) {
815
- const next = matchWsNode(node, segment, params);
816
- if (!next) return null;
817
- node = next;
818
- }
819
- return node.handler ? { handler: node.handler, middlewares: node.middlewares, params } : null;
820
- }
821
- async handle(req, ctx, segments, query) {
822
- const match = this.matchTrie(req.method, segments);
823
- if (match?.handler) {
824
- const { handler, middlewares: routeMws, pathMws, params } = match;
825
- const allMws = this.globalMws.length + pathMws.length + routeMws.length === 0 ? [] : [...this.globalMws, ...pathMws, ...routeMws];
826
- const ctxWithMatch = { ...ctx, params: { ...ctx.params, ...params } };
827
- try {
828
- return await this.runChain(allMws, handler, req, ctxWithMatch);
829
- } catch (e) {
830
- const err = e instanceof Error ? e : new Error(String(e));
831
- return this.errorHandler ? this.errorHandler(err, req, ctxWithMatch) : new Response("Internal Server Error", { status: 500 });
749
+ if (bundleCache.has(bundleKey)) {
750
+ bundle = { url: bundleKey };
832
751
  }
752
+ const { renderToReadableStream } = await import("react-dom/server");
753
+ const stream = await renderToReadableStream(element);
754
+ return streamResponse(stream, {
755
+ ctx,
756
+ base,
757
+ isDev,
758
+ bundle,
759
+ loaderData
760
+ });
761
+ });
762
+ });
763
+ return r;
764
+ }
765
+
766
+ // ssr/layout.ts
767
+ function layout(path) {
768
+ return async (req, ctx, next) => {
769
+ const mod = await compileTsx(path);
770
+ const Component = mod.default;
771
+ if (!Component) throw new Error(`Layout ${path} has no default export`);
772
+ ctx.layoutStack = [...ctx.layoutStack || [], { path, component: Component }];
773
+ return next(req, ctx);
774
+ };
775
+ }
776
+
777
+ // ssr/tailwind.ts
778
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync } from "node:fs";
779
+ import { relative, resolve as resolve3 } from "node:path";
780
+ var isDev2 = process.env.NODE_ENV !== "production";
781
+ function tailwind(cssPath, scanDir) {
782
+ let compiledCss = "";
783
+ let twWatcher = null;
784
+ return async (req, ctx, next) => {
785
+ const url = new URL(req.url);
786
+ if (url.pathname === "/__wfw/style.css") {
787
+ if (!compiledCss) compiledCss = await compile(cssPath, scanDir);
788
+ return new Response(compiledCss || "", {
789
+ headers: { "content-type": "text/css; charset=utf-8" }
790
+ });
833
791
  }
834
- if (this.globalMws.length > 0) {
835
- try {
836
- const delegate = () => new Response("Not Found", { status: 404 });
837
- return await this.runChain(this.globalMws, delegate, req, ctx);
838
- } catch (e) {
839
- const err = e instanceof Error ? e : new Error(String(e));
840
- return this.errorHandler ? this.errorHandler(err, req, ctx) : new Response("Internal Server Error", { status: 500 });
841
- }
792
+ ctx.compiledTailwindCss = compiledCss;
793
+ if (isDev2 && !twWatcher) {
794
+ twWatcher = watchFile(cssPath, () => {
795
+ compiledCss = "";
796
+ });
842
797
  }
843
- return new Response("Not Found", { status: 404 });
844
- }
845
- async runChain(middlewares, finalHandler, req, ctx) {
846
- let index = 0;
847
- const dispatch = async (req2, ctx2) => {
848
- if (index < middlewares.length) {
849
- const mw = middlewares[index++];
850
- return mw ? await mw(req2, ctx2, dispatch) : new Response("Middleware error", { status: 500 });
851
- }
852
- return await finalHandler(req2, ctx2);
853
- };
854
- return dispatch(req, ctx);
855
- }
856
- };
857
- function upgradeSocket(wss, req, socket, head, handler, ctx) {
858
- wss.handleUpgrade(req, socket, head, (ws) => {
859
- if (handler.open) {
860
- handler.open(ws, ctx);
798
+ return next(req, ctx);
799
+ };
800
+ }
801
+ async function compile(cssPath, scanDir) {
802
+ try {
803
+ const inputFile = resolve3(cssPath);
804
+ if (!existsSync2(inputFile)) {
805
+ mkdirSync2(dirname3(inputFile), { recursive: true });
806
+ writeFileSync(inputFile, '@import "tailwindcss"\n', "utf-8");
861
807
  }
862
- ws.on("message", (data) => {
863
- handler.message?.(ws, ctx, data);
864
- });
865
- ws.on("close", () => {
866
- handler.close?.(ws, ctx);
867
- });
868
- ws.on("error", (err) => {
869
- handler.error?.(ws, ctx, err);
870
- });
871
- });
808
+ const { default: tailwindPlugin } = await import("@tailwindcss/postcss");
809
+ const { default: postcss } = await import("postcss");
810
+ let src = readFileSync2(inputFile, "utf-8");
811
+ const scanSource = scanDir ? relative(dirname3(inputFile), scanDir) || "." : ".";
812
+ const sourcePath = scanSource === "." ? "./" : `./${scanSource}/`;
813
+ src = `@source "${sourcePath}";
814
+ ${src}`;
815
+ const result = await postcss([tailwindPlugin()]).process(src, { from: inputFile });
816
+ return result.css;
817
+ } catch (err) {
818
+ console.warn("Tailwind CSS processing failed:", err.message);
819
+ return "";
820
+ }
872
821
  }
873
- function sendHttpResponseOnSocket(socket, response) {
874
- const statusLine = `HTTP/1.1 ${response.status} ${response.statusText}`;
875
- const headerLines = [statusLine];
876
- response.headers.forEach((value, key) => {
877
- headerLines.push(`${key}: ${value}`);
878
- });
879
- headerLines.push("Connection: close");
880
- headerLines.push("");
881
- const headerStr = headerLines.join("\r\n");
882
- response.arrayBuffer().then((buf) => {
883
- const body = Buffer.from(buf);
884
- socket.write(headerStr + "\r\n" + body.toString());
885
- socket.end();
886
- }).catch(() => {
887
- socket.write(headerStr + "\r\n");
888
- socket.end();
822
+ function dirname3(p) {
823
+ return p.substring(0, p.lastIndexOf("/")) || "/";
824
+ }
825
+ function watchFile(path, onChange) {
826
+ let watcher = null;
827
+ import("chokidar").then((chokidar2) => {
828
+ watcher = chokidar2.default.watch(resolve3(path), { persistent: false });
829
+ watcher.on("change", onChange);
889
830
  });
831
+ return watcher;
832
+ }
833
+
834
+ // ssr/not-found.ts
835
+ function notFound(path) {
836
+ return async (req, ctx) => {
837
+ if (!path) return new Response("Not Found", { status: 404 });
838
+ const mod = await compileTsx(path);
839
+ const Component = mod?.default;
840
+ const body = Component ? "404 - Not Found" : "404 - Not Found";
841
+ return new Response(body, {
842
+ status: 404,
843
+ headers: { "content-type": "text/html; charset=utf-8" }
844
+ });
845
+ };
846
+ }
847
+
848
+ // ssr/error-boundary.ts
849
+ import { createElement as createElement2 } from "react";
850
+ import { TextEncoder as TextEncoder2 } from "node:util";
851
+ function errorBoundary(errorPath) {
852
+ return async (req, ctx, next) => {
853
+ try {
854
+ return await next(req, ctx);
855
+ } catch (err) {
856
+ const mod = await compileTsx(errorPath);
857
+ const ErrorComponent = mod.default;
858
+ if (!ErrorComponent) throw err;
859
+ const layouts = (ctx.layoutStack || []).map((l) => l.component);
860
+ const stream = await import("react-dom/server").then((m) => m.renderToReadableStream(
861
+ createElement2(ErrorComponent, {
862
+ error: err instanceof Error ? err : new Error(String(err)),
863
+ reset: () => {
864
+ }
865
+ })
866
+ ));
867
+ const reader = stream.getReader();
868
+ const chunks = [];
869
+ while (true) {
870
+ const { done, value } = await reader.read();
871
+ if (done) break;
872
+ chunks.push(value);
873
+ }
874
+ const encoder = new TextEncoder2();
875
+ const body = chunks.reduce((acc, c) => {
876
+ const merged = new Uint8Array(acc.length + c.length);
877
+ merged.set(acc);
878
+ merged.set(c, acc.length);
879
+ return merged;
880
+ }, new Uint8Array(0));
881
+ return new Response(body, {
882
+ status: 500,
883
+ headers: { "content-type": "text/html; charset=utf-8" }
884
+ });
885
+ }
886
+ };
890
887
  }
891
888
 
892
889
  // ssr/live.ts
890
+ import chokidar from "chokidar";
893
891
  var clients = /* @__PURE__ */ new Set();
894
892
  function broadcastReload() {
895
893
  for (const ws of clients) {
@@ -931,6 +929,5 @@ export {
931
929
  liveReload,
932
930
  notFound,
933
931
  ssr,
934
- ssrBundleHandler,
935
932
  tailwind
936
933
  };