weifuwu 0.24.0 → 0.24.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +970 -756
  2. package/cli/template/app.ts +5 -1
  3. package/cli/template/index.ts +4 -1
  4. package/cli/template/locales/en.json +6 -1
  5. package/cli/template/locales/zh-CN.json +6 -1
  6. package/cli/template/locales/zh-TW.json +6 -1
  7. package/cli/template/locales/zh.json +6 -1
  8. package/cli/template/ui/app/globals.css +1 -1
  9. package/cli/template/ui/app/page.tsx +55 -16
  10. package/cli.ts +148 -104
  11. package/dist/agent/rest.d.ts +1 -1
  12. package/dist/agent/run.d.ts +2 -2
  13. package/dist/agent/types.d.ts +2 -1
  14. package/dist/ai/workflow.d.ts +1 -1
  15. package/dist/ai-sdk.d.ts +1 -1
  16. package/dist/analytics.d.ts +2 -2
  17. package/dist/cache.d.ts +4 -4
  18. package/dist/cli.js +135 -97
  19. package/dist/cookie.d.ts +24 -0
  20. package/dist/cors.d.ts +2 -2
  21. package/dist/deploy/types.d.ts +2 -2
  22. package/dist/fts.d.ts +5 -5
  23. package/dist/helmet.d.ts +2 -2
  24. package/dist/hub.d.ts +2 -1
  25. package/dist/iii/index.d.ts +1 -1
  26. package/dist/iii/register-worker.d.ts +1 -1
  27. package/dist/iii/types.d.ts +4 -4
  28. package/dist/index.d.ts +5 -5
  29. package/dist/index.js +905 -442
  30. package/dist/kb/types.d.ts +8 -0
  31. package/dist/live.d.ts +2 -3
  32. package/dist/logdb/rest.d.ts +1 -1
  33. package/dist/logdb/types.d.ts +2 -1
  34. package/dist/mailer.d.ts +3 -2
  35. package/dist/messager/agent.d.ts +2 -2
  36. package/dist/messager/rest.d.ts +3 -3
  37. package/dist/messager/types.d.ts +2 -1
  38. package/dist/messager/ws.d.ts +3 -3
  39. package/dist/opencode/index.d.ts +1 -1
  40. package/dist/opencode/permissions.d.ts +1 -1
  41. package/dist/opencode/run.d.ts +1 -1
  42. package/dist/opencode/session.d.ts +9 -9
  43. package/dist/opencode/tools/web.d.ts +1 -1
  44. package/dist/opencode/types.d.ts +2 -1
  45. package/dist/opencode/ws.d.ts +1 -2
  46. package/dist/permissions.d.ts +4 -4
  47. package/dist/postgres/module.d.ts +5 -4
  48. package/dist/postgres/schema/index.d.ts +1 -1
  49. package/dist/postgres/schema/table.d.ts +22 -20
  50. package/dist/postgres/types.d.ts +6 -6
  51. package/dist/queue/types.d.ts +3 -3
  52. package/dist/rate-limit.d.ts +1 -1
  53. package/dist/react.d.ts +1 -1
  54. package/dist/react.js +141 -96
  55. package/dist/redis/types.d.ts +2 -2
  56. package/dist/router.d.ts +10 -10
  57. package/dist/seo.d.ts +2 -2
  58. package/dist/serve.d.ts +1 -1
  59. package/dist/session.d.ts +8 -5
  60. package/dist/tailwind.d.ts +9 -0
  61. package/dist/tenant/graphql.d.ts +2 -2
  62. package/dist/tenant/index.d.ts +1 -1
  63. package/dist/tenant/rest.d.ts +2 -2
  64. package/dist/tenant/types.d.ts +3 -3
  65. package/dist/test-utils.d.ts +3 -3
  66. package/dist/types.d.ts +8 -0
  67. package/dist/upload.d.ts +4 -2
  68. package/dist/user/index.d.ts +1 -1
  69. package/dist/user/oauth-login.d.ts +2 -2
  70. package/dist/user/types.d.ts +2 -2
  71. package/dist/vendor.d.ts +4 -0
  72. package/opencode/ui/app/globals.css +1 -1
  73. package/opencode/ui/app/layout.tsx +2 -3
  74. package/opencode/ui/app/page.tsx +302 -73
  75. package/package.json +33 -10
  76. package/cli/template/.weifuwu/ssr/2e3a7e60.js +0 -112
package/dist/react.js CHANGED
@@ -95,42 +95,45 @@ function useAction(url, options) {
95
95
  const [error, setError] = useState2(null);
96
96
  const [pending, setPending] = useState2(false);
97
97
  const mountedRef = useRef2(true);
98
- const submit = useCallback2(async (body) => {
99
- setPending(true);
100
- setError(null);
101
- try {
102
- const csrfToken = getCsrfToken();
103
- const hdrs = { ...headers };
104
- if (csrfToken) hdrs["x-csrf-token"] = csrfToken;
105
- if (body && typeof body === "object" && !(body instanceof FormData)) {
106
- hdrs["content-type"] = "application/json";
107
- }
108
- const res = await fetch(url, {
109
- method,
110
- headers: hdrs,
111
- body: body instanceof FormData ? body : body !== void 0 ? JSON.stringify(body) : void 0
112
- });
113
- if (!res.ok) {
114
- const text = await res.text();
115
- throw new Error(text || `HTTP ${res.status}`);
116
- }
117
- const result = res.status === 204 ? void 0 : await res.json();
118
- if (mountedRef.current) {
119
- setData(result);
120
- onSuccess?.(result);
121
- }
122
- return result;
123
- } catch (err) {
124
- const e = err instanceof Error ? err : new Error(String(err));
125
- if (mountedRef.current) {
126
- setError(e);
127
- onError?.(e);
98
+ const submit = useCallback2(
99
+ async (body) => {
100
+ setPending(true);
101
+ setError(null);
102
+ try {
103
+ const csrfToken = getCsrfToken();
104
+ const hdrs = { ...headers };
105
+ if (csrfToken) hdrs["x-csrf-token"] = csrfToken;
106
+ if (body && typeof body === "object" && !(body instanceof FormData)) {
107
+ hdrs["content-type"] = "application/json";
108
+ }
109
+ const res = await fetch(url, {
110
+ method,
111
+ headers: hdrs,
112
+ body: body instanceof FormData ? body : body !== void 0 ? JSON.stringify(body) : void 0
113
+ });
114
+ if (!res.ok) {
115
+ const text = await res.text();
116
+ throw new Error(text || `HTTP ${res.status}`);
117
+ }
118
+ const result = res.status === 204 ? void 0 : await res.json();
119
+ if (mountedRef.current) {
120
+ setData(result);
121
+ onSuccess?.(result);
122
+ }
123
+ return result;
124
+ } catch (err) {
125
+ const e = err instanceof Error ? err : new Error(String(err));
126
+ if (mountedRef.current) {
127
+ setError(e);
128
+ onError?.(e);
129
+ }
130
+ return void 0;
131
+ } finally {
132
+ if (mountedRef.current) setPending(false);
128
133
  }
129
- return void 0;
130
- } finally {
131
- if (mountedRef.current) setPending(false);
132
- }
133
- }, [url, method, headers, onSuccess, onError]);
134
+ },
135
+ [url, method, headers, onSuccess, onError]
136
+ );
134
137
  const reset = useCallback2(() => {
135
138
  setData(null);
136
139
  setError(null);
@@ -155,7 +158,15 @@ async function runInterceptors(url) {
155
158
 
156
159
  // tsx-context.ts
157
160
  import { useSyncExternalStore, createContext } from "react";
158
- var DEFAULT_CTX = { params: {}, query: {}, parsed: {}, loaderData: {}, env: {}, user: {}, flash: {} };
161
+ var DEFAULT_CTX = {
162
+ params: {},
163
+ query: {},
164
+ parsed: {},
165
+ loaderData: {},
166
+ env: {},
167
+ user: {},
168
+ flash: {}
169
+ };
159
170
  var KEY = "__WEIFUWU_CTX_STORE";
160
171
  function getStore() {
161
172
  if (typeof globalThis !== "undefined" && globalThis[KEY]) {
@@ -163,12 +174,22 @@ function getStore() {
163
174
  }
164
175
  const s = {
165
176
  _ctx: DEFAULT_CTX,
166
- _snapshot: { params: DEFAULT_CTX.params, query: DEFAULT_CTX.query, user: DEFAULT_CTX.user, parsed: DEFAULT_CTX.parsed, theme: DEFAULT_CTX.theme, i18n: DEFAULT_CTX.i18n, loaderData: DEFAULT_CTX.loaderData, env: DEFAULT_CTX.env },
177
+ _snapshot: {
178
+ params: DEFAULT_CTX.params,
179
+ query: DEFAULT_CTX.query,
180
+ user: DEFAULT_CTX.user,
181
+ parsed: DEFAULT_CTX.parsed,
182
+ theme: DEFAULT_CTX.theme,
183
+ i18n: DEFAULT_CTX.i18n,
184
+ loaderData: DEFAULT_CTX.loaderData,
185
+ env: DEFAULT_CTX.env
186
+ },
167
187
  _listeners: /* @__PURE__ */ new Set(),
168
188
  _rebuilders: [],
169
189
  _alsGetStore: null
170
190
  };
171
191
  if (typeof globalThis !== "undefined") {
192
+ ;
172
193
  globalThis[KEY] = s;
173
194
  }
174
195
  return s;
@@ -192,7 +213,16 @@ function setCtx(value) {
192
213
  }
193
214
  }
194
215
  store._ctx = { ...store._ctx, ...value };
195
- store._snapshot = { params: store._ctx.params, query: store._ctx.query, user: store._ctx.user, parsed: store._ctx.parsed, theme: store._ctx.theme, i18n: store._ctx.i18n, loaderData: store._ctx.loaderData, env: store._ctx.env };
216
+ store._snapshot = {
217
+ params: store._ctx.params,
218
+ query: store._ctx.query,
219
+ user: store._ctx.user,
220
+ parsed: store._ctx.parsed,
221
+ theme: store._ctx.theme,
222
+ i18n: store._ctx.i18n,
223
+ loaderData: store._ctx.loaderData,
224
+ env: store._ctx.env
225
+ };
196
226
  if (typeof window !== "undefined") {
197
227
  ;
198
228
  window.__WEIFUWU_CTX = { ...window.__WEIFUWU_CTX, ...value };
@@ -290,7 +320,9 @@ function applyHead(html) {
290
320
  const doc = new DOMParser().parseFromString(headHtml, "text/html");
291
321
  const newMeta = doc.querySelectorAll("meta");
292
322
  const existing = document.querySelectorAll("head meta");
293
- const newNames = new Set(Array.from(newMeta).map((m) => m.getAttribute("name") || m.getAttribute("property") || ""));
323
+ const newNames = new Set(
324
+ Array.from(newMeta).map((m) => m.getAttribute("name") || m.getAttribute("property") || "")
325
+ );
294
326
  for (const el of existing) {
295
327
  const key = el.getAttribute("name") || el.getAttribute("property") || "";
296
328
  if (!newNames.has(key)) el.remove();
@@ -307,7 +339,8 @@ function applyHead(html) {
307
339
  }
308
340
  }
309
341
  if (existingEl) {
310
- for (const attr of el.attributes) existingEl.setAttribute(attr.name, attr.value);
342
+ for (const attr of el.attributes)
343
+ existingEl.setAttribute(attr.name, attr.value);
311
344
  } else {
312
345
  document.head.appendChild(el.cloneNode());
313
346
  }
@@ -345,27 +378,37 @@ function Link({ href, children, onClick, prefetch, ...props }) {
345
378
  }
346
379
  }
347
380
  if (!el) return;
348
- const observer = new IntersectionObserver(([entry]) => {
349
- if (entry.isIntersecting) prefetchPage(href);
350
- }, { rootMargin: "200px" });
381
+ const observer = new IntersectionObserver(
382
+ ([entry]) => {
383
+ if (entry.isIntersecting) prefetchPage(href);
384
+ },
385
+ { rootMargin: "200px" }
386
+ );
351
387
  observer.observe(el);
352
388
  return () => observer.disconnect();
353
389
  }, [href, prefetch]);
354
390
  const handleMouseEnter = useCallback3(() => {
355
391
  if (prefetch) prefetchPage(href);
356
392
  }, [href, prefetch]);
357
- const handleClick = useCallback3((e) => {
358
- if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
359
- e.preventDefault();
360
- doNavigate(href);
361
- onClick?.(e);
362
- }, [href, onClick, doNavigate]);
363
- return createElement("a", {
364
- href,
365
- onClick: handleClick,
366
- onMouseEnter: handleMouseEnter,
367
- ...props
368
- }, children);
393
+ const handleClick = useCallback3(
394
+ (e) => {
395
+ if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
396
+ e.preventDefault();
397
+ doNavigate(href);
398
+ onClick?.(e);
399
+ },
400
+ [href, onClick, doNavigate]
401
+ );
402
+ return createElement(
403
+ "a",
404
+ {
405
+ href,
406
+ onClick: handleClick,
407
+ onMouseEnter: handleMouseEnter,
408
+ ...props
409
+ },
410
+ children
411
+ );
369
412
  }
370
413
  async function prefetchPage(href) {
371
414
  const cached = prefetchCache.get(href);
@@ -400,10 +443,7 @@ function createStore(initial) {
400
443
  listeners.delete(listener);
401
444
  };
402
445
  };
403
- const useStore = ((selector) => useSyncExternalStore2(
404
- subscribe2,
405
- () => selector ? selector(state) : state
406
- ));
446
+ const useStore = ((selector) => useSyncExternalStore2(subscribe2, () => selector ? selector(state) : state));
407
447
  useStore.getState = getState;
408
448
  useStore.setState = setState;
409
449
  useStore.subscribe = subscribe2;
@@ -430,19 +470,23 @@ function useFetch(url, options) {
430
470
  let cancelled = false;
431
471
  const cached = dataCache.get(u);
432
472
  if (cached && Date.now() - cached.timestamp < ttl) {
433
- if (!cancelled) setState({
434
- data: cached.data,
435
- error: cached.error,
436
- loading: false
437
- });
473
+ if (!cancelled)
474
+ setState({
475
+ data: cached.data,
476
+ error: cached.error,
477
+ loading: false
478
+ });
438
479
  return;
439
480
  }
440
481
  async function doFetch() {
441
482
  if (!inflight.has(u)) {
442
- inflight.set(u, fetch(u).then((r) => {
443
- if (!r.ok) throw new Error(r.statusText || `HTTP ${r.status}`);
444
- return r.json();
445
- }));
483
+ inflight.set(
484
+ u,
485
+ fetch(u).then((r) => {
486
+ if (!r.ok) throw new Error(r.statusText || `HTTP ${r.status}`);
487
+ return r.json();
488
+ })
489
+ );
446
490
  }
447
491
  const promise = inflight.get(u);
448
492
  try {
@@ -501,18 +545,21 @@ function useQueryState(key, defaultValue = "") {
501
545
  getSnapshot2,
502
546
  () => defaultValue
503
547
  );
504
- const setValue = useCallback4((val) => {
505
- if (typeof window === "undefined") return;
506
- const resolved = typeof val === "function" ? val(getSnapshot2()) : val;
507
- const url = new URL(window.location.href);
508
- if (resolved === defaultValue || resolved === "") {
509
- url.searchParams.delete(key);
510
- } else {
511
- url.searchParams.set(key, resolved);
512
- }
513
- window.history.replaceState(null, "", url.toString());
514
- notifyQueryListeners();
515
- }, [key, defaultValue]);
548
+ const setValue = useCallback4(
549
+ (val) => {
550
+ if (typeof window === "undefined") return;
551
+ const resolved = typeof val === "function" ? val(getSnapshot2()) : val;
552
+ const url = new URL(window.location.href);
553
+ if (resolved === defaultValue || resolved === "") {
554
+ url.searchParams.delete(key);
555
+ } else {
556
+ url.searchParams.set(key, resolved);
557
+ }
558
+ window.history.replaceState(null, "", url.toString());
559
+ notifyQueryListeners();
560
+ },
561
+ [key, defaultValue]
562
+ );
516
563
  return [value, setValue];
517
564
  }
518
565
 
@@ -593,7 +640,10 @@ addInterceptor(async (url) => {
593
640
  headers: { accept: "application/json" }
594
641
  });
595
642
  const data = await res.json();
596
- window.__WEIFUWU_CTX = { ...window.__WEIFUWU_CTX, theme: { value: data.theme } };
643
+ window.__WEIFUWU_CTX = {
644
+ ...window.__WEIFUWU_CTX,
645
+ theme: { value: data.theme }
646
+ };
597
647
  setCtx({ theme: { value: data.theme } });
598
648
  applyTheme(data.theme);
599
649
  } catch {
@@ -629,43 +679,38 @@ function useFlashMessage() {
629
679
  // use-agent-stream.ts
630
680
  import { useState as useState6, useCallback as useCallback5, useRef as useRef4 } from "react";
631
681
  function useAgentStream(opts) {
632
- const { wsPath, channelId, onStreamEnd, onError } = opts;
682
+ const { wsPath, onStreamEnd, onError } = opts;
633
683
  const [streams, setStreams] = useState6({});
634
684
  const activeRef = useRef4(/* @__PURE__ */ new Set());
635
- const getAgentText = useCallback5(
636
- (agentId) => streams[agentId] || "",
637
- [streams]
638
- );
639
- const isAgentStreaming = useCallback5(
640
- (agentId) => activeRef.current.has(agentId),
641
- []
642
- );
685
+ const streamsRef = useRef4({});
686
+ const getAgentText = useCallback5((agentId) => streams[agentId] || "", [streams]);
687
+ const isAgentStreaming = useCallback5((agentId) => activeRef.current.has(agentId), []);
643
688
  const streaming = activeRef.current.size > 0;
644
689
  useWebsocket(wsPath, {
645
690
  onMessage: (raw) => {
646
691
  try {
647
692
  const msg = JSON.parse(raw);
648
- if (msg.type !== "agent_stream" && msg.type !== "agent_stream_end" && msg.type !== "agent_error") return;
693
+ if (msg.type !== "agent_stream" && msg.type !== "agent_stream_end" && msg.type !== "agent_error")
694
+ return;
649
695
  const agentId = msg.data?.agent_id;
650
696
  if (agentId === void 0 || agentId === null) return;
651
697
  switch (msg.type) {
652
698
  case "agent_stream": {
653
699
  activeRef.current.add(agentId);
654
700
  const token = msg.data?.token || "";
655
- setStreams((prev) => {
656
- const current = prev[agentId] || "";
657
- return { ...prev, [agentId]: current + token };
658
- });
701
+ streamsRef.current[agentId] = (streamsRef.current[agentId] || "") + token;
702
+ setStreams({ ...streamsRef.current });
659
703
  break;
660
704
  }
661
705
  case "agent_stream_end": {
662
706
  activeRef.current.delete(agentId);
663
- const fullText = streams[agentId] || "";
707
+ const fullText = streamsRef.current[agentId] || "";
664
708
  onStreamEnd?.(agentId, fullText);
665
709
  break;
666
710
  }
667
711
  case "agent_error": {
668
712
  activeRef.current.delete(agentId);
713
+ delete streamsRef.current[agentId];
669
714
  onError?.(agentId, msg.data?.error || "Unknown error");
670
715
  break;
671
716
  }
@@ -1,5 +1,5 @@
1
1
  import type { Redis, RedisOptions as IORedisOptions } from '../vendor.ts';
2
- import type { Context, Middleware } from '../types.ts';
2
+ import type { Context, Middleware, Closeable } from '../types.ts';
3
3
  declare module '../types.ts' {
4
4
  interface Context {
5
5
  redis: Redis;
@@ -12,7 +12,7 @@ export type RedisOptions = IORedisOptions & {
12
12
  export interface RedisInjected {
13
13
  redis: Redis;
14
14
  }
15
- export interface RedisClient extends Middleware<Context, Context & RedisInjected> {
15
+ export interface RedisClient extends Middleware<Context, Context & RedisInjected>, Closeable {
16
16
  redis: Redis;
17
17
  close: () => Promise<void>;
18
18
  }
package/dist/router.d.ts CHANGED
@@ -2,7 +2,7 @@ import type { WebSocket } from './vendor.ts';
2
2
  import { type IncomingMessage } from 'node:http';
3
3
  import type { Duplex } from 'node:stream';
4
4
  import type { Context, Handler, Middleware, ErrorHandler } from './types.ts';
5
- import type { Hub } from './hub.ts';
5
+ import { type Hub } from './hub.ts';
6
6
  export type WebSocketHandler = {
7
7
  open?: (ws: WebSocket, ctx: Context) => void | Promise<void>;
8
8
  message?: (ws: WebSocket, ctx: Context, data: string | Buffer) => void | Promise<void>;
@@ -24,18 +24,18 @@ export declare class Router<T extends Context = Context> {
24
24
  wsHub(hub: Hub): this;
25
25
  use<Out extends Context>(mw: Middleware<Context, Out>): Router<T & Out>;
26
26
  use(path: string, mw: Middleware<T, T>): Router<T>;
27
- use(path: string, router: Router<any>): Router<T>;
27
+ use(path: string, router: Router<Context>): Router<T>;
28
28
  use(mod: Router & {
29
29
  middleware: () => Middleware;
30
30
  }): Router<T>;
31
- get(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<any>]): Router<T>;
32
- post(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<any>]): Router<T>;
33
- put(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<any>]): Router<T>;
34
- delete(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<any>]): Router<T>;
35
- patch(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<any>]): Router<T>;
36
- head(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<any>]): Router<T>;
37
- options(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<any>]): Router<T>;
38
- all(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<any>]): Router<T>;
31
+ get(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<Context>]): Router<T>;
32
+ post(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<Context>]): Router<T>;
33
+ put(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<Context>]): Router<T>;
34
+ delete(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<Context>]): Router<T>;
35
+ patch(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<Context>]): Router<T>;
36
+ head(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<Context>]): Router<T>;
37
+ options(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<Context>]): Router<T>;
38
+ all(path: string, ...args: [...Middleware<T, T>[], Handler<T> | Router<Context>]): Router<T>;
39
39
  onError(handler: ErrorHandler<T>): Router<T>;
40
40
  private _route;
41
41
  /** Internal route registration — no type constraints (used by _mountRouter). */
package/dist/seo.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Middleware } from './types.ts';
1
+ import type { Middleware, Context } from './types.ts';
2
2
  import { Router } from './router.ts';
3
3
  /** A rule in `robots.txt`. */
4
4
  export interface RobotsRule {
@@ -54,7 +54,7 @@ export interface SeoOptions {
54
54
  * }))
55
55
  * ```
56
56
  */
57
- export declare function seoMiddleware(options?: SeoOptions): Middleware;
57
+ export declare function seoMiddleware(options?: SeoOptions): Middleware<Context, Context>;
58
58
  /**
59
59
  * SEO module — serves `robots.txt` and `sitemap.xml`.
60
60
  *
package/dist/serve.d.ts CHANGED
@@ -29,7 +29,7 @@ export declare function createRequest(req: IncomingMessage, body: Buffer): [Requ
29
29
  export declare function sendResponse(res: ServerResponse, response: Response, opts?: {
30
30
  traceId?: string | null;
31
31
  }): Promise<void>;
32
- export declare function createTestServer(handler: Handler): Promise<{
32
+ export declare function createTestServer(handler: Handler, options?: ServeOptions): Promise<{
33
33
  server: Server;
34
34
  url: string;
35
35
  }>;
package/dist/session.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Middleware } from './types.ts';
1
+ import type { Context, Middleware, Closeable } from './types.ts';
2
2
  import type { Redis } from './vendor.ts';
3
3
  declare module './types.ts' {
4
4
  interface Context {
@@ -27,10 +27,12 @@ export interface Session extends SessionData {
27
27
  [kStore]: SessionStore;
28
28
  [kTtl]: number;
29
29
  }
30
- export interface SessionStore {
30
+ export interface SessionStore extends Closeable {
31
31
  get(sid: string): Promise<Record<string, unknown> | null>;
32
32
  set(sid: string, data: Record<string, unknown>, ttl: number): Promise<void>;
33
33
  destroy(sid: string): Promise<void>;
34
+ /** Release resources. Default no-op. */
35
+ close(): Promise<void>;
34
36
  }
35
37
  export interface SessionOptions {
36
38
  /** Session store. 'memory' (default) or 'redis'. */
@@ -74,7 +76,7 @@ export declare class MemoryStore implements SessionStore {
74
76
  set(sid: string, data: Record<string, unknown>, ttl: number): Promise<void>;
75
77
  destroy(sid: string): Promise<void>;
76
78
  private cleanup;
77
- close(): void;
79
+ close(): Promise<void>;
78
80
  /** Testing only: return approximate count. */
79
81
  get size(): number;
80
82
  }
@@ -86,9 +88,10 @@ export declare class RedisStore implements SessionStore {
86
88
  get(sid: string): Promise<Record<string, unknown> | null>;
87
89
  set(sid: string, data: Record<string, unknown>, ttl: number): Promise<void>;
88
90
  destroy(sid: string): Promise<void>;
91
+ close(): Promise<void>;
89
92
  }
90
- export declare function session(options?: SessionOptions): Middleware & {
91
- close: () => void;
93
+ export declare function session(options?: SessionOptions): Middleware<Context, Context & SessionInjected> & {
94
+ close: () => Promise<void>;
92
95
  store: SessionStore;
93
96
  };
94
97
  export {};
@@ -1,5 +1,14 @@
1
1
  import { Router } from './router.ts';
2
2
  import type { Middleware } from './types.ts';
3
+ export interface TailwindInjected {
4
+ css: string;
5
+ url: string;
6
+ }
7
+ declare module './types.ts' {
8
+ interface Context {
9
+ tailwind?: TailwindInjected;
10
+ }
11
+ }
3
12
  export declare function addTailwindSource(dir: string): void;
4
13
  export declare function tailwindContext(dir: string): Middleware;
5
14
  export declare function tailwindRouter(dir: string): Router;
@@ -1,3 +1,3 @@
1
- import type { Sql } from '../vendor.ts';
1
+ import type { SqlClient } from '../vendor.ts';
2
2
  import { Router } from '../router.ts';
3
- export declare function buildGraphQLHandler(sql: Sql<{}>): Router;
3
+ export declare function buildGraphQLHandler(sql: SqlClient): Router;
@@ -1,2 +1,2 @@
1
1
  export { tenant } from './client.ts';
2
- export type { TenantOptions, TenantModule, TenantContext, FieldDef, FieldType, RelationDef, UserTableRow } from './types.ts';
2
+ export type { TenantOptions, TenantModule, TenantContext, FieldDef, FieldType, RelationDef, UserTableRow, } from './types.ts';
@@ -1,3 +1,3 @@
1
- import type { Sql } from '../vendor.ts';
1
+ import type { SqlClient } from '../vendor.ts';
2
2
  import { Router } from '../router.ts';
3
- export declare function buildRouter(sql: Sql<{}>, usersTable: string): Router;
3
+ export declare function buildRouter(sql: SqlClient, usersTable: string): Router;
@@ -1,4 +1,4 @@
1
- import type { Context } from '../types.ts';
1
+ import type { Context, Handler } from '../types.ts';
2
2
  import type { Router } from '../router.ts';
3
3
  import type { PostgresClient } from '../postgres/types.ts';
4
4
  declare module '../types.ts' {
@@ -42,7 +42,7 @@ export interface TenantOptions {
42
42
  }
43
43
  export interface TenantModule extends Router {
44
44
  migrate: () => Promise<void>;
45
- middleware: () => (req: Request, ctx: Context, next: any) => Promise<Response>;
46
- graphql: () => any;
45
+ middleware: () => (req: Request, ctx: Context, next: Handler<Context>) => Promise<Response>;
46
+ graphql: () => Router;
47
47
  close: () => Promise<void>;
48
48
  }
@@ -1,5 +1,5 @@
1
1
  import type { Context, Handler } from './types.ts';
2
- import type { Sql } from './vendor.ts';
2
+ import type { SqlClient } from './vendor.ts';
3
3
  export interface TestResponse {
4
4
  readonly status: number;
5
5
  readonly headers: Headers;
@@ -68,7 +68,7 @@ export declare function testApp(): TestApp;
68
68
  */
69
69
  export interface TestDb {
70
70
  /** Tagged-template SQL client connected to the test database. */
71
- sql: Sql<{}>;
71
+ sql: SqlClient;
72
72
  /** Connection URL of the test database. */
73
73
  url: string;
74
74
  /** Schema name used for this test session. */
@@ -113,4 +113,4 @@ export declare function createTestDb(options?: {
113
113
  */
114
114
  export declare function withTestDb(optionsOrFn: string | {
115
115
  url?: string;
116
- } | ((sql: Sql<{}>) => Promise<void>), fn?: (sql: Sql<{}>) => Promise<void>): Promise<void>;
116
+ } | ((sql: SqlClient) => Promise<void>), fn?: (sql: SqlClient) => Promise<void>): Promise<void>;
package/dist/types.d.ts CHANGED
@@ -11,3 +11,11 @@ export interface Context {
11
11
  export type Handler<T extends Context = Context> = (req: Request, ctx: T) => Response | Promise<Response>;
12
12
  export type Middleware<In extends Context = Context, Out extends In = In> = (req: Request, ctx: In, next: Handler<Out>) => Response | Promise<Response>;
13
13
  export type ErrorHandler<T extends Context = Context> = (error: Error, req: Request, ctx: T) => Response | Promise<Response>;
14
+ /**
15
+ * Interface for resources that require explicit cleanup (connections, pools, timers).
16
+ * All stateful modules implement this.
17
+ */
18
+ export interface Closeable {
19
+ /** Release all resources. Call once when shutting down. */
20
+ close(): Promise<void>;
21
+ }
package/dist/upload.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Middleware } from './types.ts';
1
+ import type { Context, Middleware } from './types.ts';
2
2
  declare module './types.ts' {
3
3
  interface Context {
4
4
  parsed: Record<string, unknown>;
@@ -46,4 +46,6 @@ export interface UploadOptions {
46
46
  * })
47
47
  * ```
48
48
  */
49
- export declare function upload(options?: UploadOptions): Middleware;
49
+ export declare function upload(options?: UploadOptions): Middleware<Context, Context & {
50
+ parsed: Record<string, unknown>;
51
+ }>;
@@ -1,2 +1,2 @@
1
1
  export { user } from './client.ts';
2
- export type { UserOptions, UserData, UserModule, AuthResult, OAuth2Client, OAuthProviderConfig, UserInjected } from './types.ts';
2
+ export type { UserOptions, UserData, UserModule, AuthResult, OAuth2Client, OAuthProviderConfig, UserInjected, } from './types.ts';
@@ -1,8 +1,8 @@
1
- import type { Sql } from '../vendor.ts';
1
+ import type { SqlClient } from '../vendor.ts';
2
2
  import type { Router } from '../router.ts';
3
3
  import type { OAuthProviderConfig } from './types.ts';
4
4
  interface OAuthLoginDeps {
5
- sql: Sql<{}>;
5
+ sql: SqlClient;
6
6
  jwtSecret: string;
7
7
  expiresIn: string | number;
8
8
  usersTable: string;
@@ -1,4 +1,4 @@
1
- import type { Middleware, Context } from '../types.ts';
1
+ import type { Middleware, Context, Closeable } from '../types.ts';
2
2
  import type { Router } from '../router.ts';
3
3
  import type { PostgresClient } from '../postgres/types.ts';
4
4
  /** A user record from the database. */
@@ -107,7 +107,7 @@ export interface UserInjected {
107
107
  * app.use('/', auth) // mounts routes: /register, /login
108
108
  * ```
109
109
  */
110
- export interface UserModule extends Router {
110
+ export interface UserModule extends Router, Closeable {
111
111
  /**
112
112
  * Strict auth middleware. Reads JWT from `Authorization: Bearer` header.
113
113
  * Returns 401 if no valid token is found.
package/dist/vendor.d.ts CHANGED
@@ -1,3 +1,7 @@
1
+ import type postgres from 'postgres';
2
+ /** Untyped postgres.js SQL client. Use typed `Sql<{ table: { col: type } }>` for schemas. */
3
+ export type SqlClient = postgres.Sql<Record<string, unknown>>;
4
+ /** Re-export for downstream usage. */
1
5
  export type { Sql } from 'postgres';
2
6
  export type { WebSocket } from 'ws';
3
7
  export type { Redis, RedisOptions } from 'ioredis';
@@ -1 +1 @@
1
- @import "tailwindcss"
1
+ @import 'tailwindcss';
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
1
2
  export default function RootLayout({ children }: { children: any }) {
2
3
  return (
3
4
  <html lang="en">
@@ -6,9 +7,7 @@ export default function RootLayout({ children }: { children: any }) {
6
7
  <meta name="viewport" content="width=device-width, initial-scale=1" />
7
8
  <title>Opencode Chat</title>
8
9
  </head>
9
- <body>
10
- {children}
11
- </body>
10
+ <body>{children}</body>
12
11
  </html>
13
12
  )
14
13
  }