weifuwu 0.25.2 → 0.27.1

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 (208) hide show
  1. package/README.md +291 -2489
  2. package/ai/provider.ts +129 -0
  3. package/ai/stream.ts +63 -0
  4. package/{dist/cli.d.ts → cli.js} +1 -1
  5. package/cli.ts +55 -257
  6. package/core/cookie.ts +114 -0
  7. package/core/env.ts +142 -0
  8. package/core/logger.ts +72 -0
  9. package/core/router.ts +795 -0
  10. package/core/serve.ts +294 -0
  11. package/core/sse.ts +85 -0
  12. package/core/trace.ts +146 -0
  13. package/graphql.ts +267 -0
  14. package/hub.ts +133 -0
  15. package/index.ts +71 -0
  16. package/mailer.ts +81 -0
  17. package/middleware/compress.ts +103 -0
  18. package/middleware/cors.ts +81 -0
  19. package/middleware/csrf.ts +112 -0
  20. package/middleware/flash.ts +144 -0
  21. package/middleware/health.ts +44 -0
  22. package/middleware/helmet.ts +98 -0
  23. package/middleware/i18n.ts +175 -0
  24. package/middleware/rate-limit.ts +167 -0
  25. package/middleware/request-id.ts +60 -0
  26. package/middleware/static.ts +149 -0
  27. package/middleware/theme.ts +84 -0
  28. package/middleware/upload.ts +168 -0
  29. package/middleware/validate.ts +186 -0
  30. package/package.json +15 -36
  31. package/postgres/client.ts +132 -0
  32. package/postgres/index.ts +4 -0
  33. package/postgres/module.ts +37 -0
  34. package/postgres/schema/columns.ts +186 -0
  35. package/postgres/schema/index.ts +36 -0
  36. package/postgres/schema/sql.ts +39 -0
  37. package/postgres/schema/table.ts +548 -0
  38. package/postgres/schema/where.ts +99 -0
  39. package/postgres/types.ts +48 -0
  40. package/queue/cron.ts +90 -0
  41. package/queue/index.ts +654 -0
  42. package/queue/types.ts +60 -0
  43. package/redis/client.ts +24 -0
  44. package/{dist/redis/index.d.ts → redis/index.ts} +2 -2
  45. package/redis/types.ts +28 -0
  46. package/types.ts +78 -0
  47. package/cli/template/app.ts +0 -22
  48. package/cli/template/index.ts +0 -10
  49. package/cli/template/locales/en.json +0 -13
  50. package/cli/template/locales/zh-CN.json +0 -13
  51. package/cli/template/locales/zh-TW.json +0 -13
  52. package/cli/template/locales/zh.json +0 -13
  53. package/cli/template/ui/app/globals.css +0 -2
  54. package/cli/template/ui/app/layout.tsx +0 -15
  55. package/cli/template/ui/app/page.tsx +0 -124
  56. package/cli/template/ui/components/Greeting.tsx +0 -3
  57. package/dist/agent/client.d.ts +0 -2
  58. package/dist/agent/index.d.ts +0 -2
  59. package/dist/agent/rest.d.ts +0 -14
  60. package/dist/agent/run.d.ts +0 -19
  61. package/dist/agent/types.d.ts +0 -55
  62. package/dist/ai/provider.d.ts +0 -45
  63. package/dist/ai/utils.d.ts +0 -5
  64. package/dist/ai/workflow.d.ts +0 -17
  65. package/dist/ai-sdk.d.ts +0 -2
  66. package/dist/ai.d.ts +0 -13
  67. package/dist/analytics.d.ts +0 -45
  68. package/dist/auth.d.ts +0 -22
  69. package/dist/cache.d.ts +0 -74
  70. package/dist/cli.js +0 -302
  71. package/dist/client-locale.d.ts +0 -25
  72. package/dist/client-pref.d.ts +0 -3
  73. package/dist/client-router.d.ts +0 -300
  74. package/dist/client-state.d.ts +0 -22
  75. package/dist/client-theme.d.ts +0 -36
  76. package/dist/compile.d.ts +0 -15
  77. package/dist/compress.d.ts +0 -20
  78. package/dist/cookie.d.ts +0 -36
  79. package/dist/cors.d.ts +0 -25
  80. package/dist/cron-utils.d.ts +0 -73
  81. package/dist/csrf.d.ts +0 -47
  82. package/dist/deploy/config.d.ts +0 -2
  83. package/dist/deploy/gateway.d.ts +0 -2
  84. package/dist/deploy/index.d.ts +0 -4
  85. package/dist/deploy/manager.d.ts +0 -16
  86. package/dist/deploy/process.d.ts +0 -14
  87. package/dist/deploy/types.d.ts +0 -53
  88. package/dist/env.d.ts +0 -69
  89. package/dist/error-boundary.d.ts +0 -2
  90. package/dist/flash.d.ts +0 -90
  91. package/dist/fts.d.ts +0 -36
  92. package/dist/graphql.d.ts +0 -16
  93. package/dist/head.d.ts +0 -6
  94. package/dist/health.d.ts +0 -24
  95. package/dist/helmet.d.ts +0 -33
  96. package/dist/html-shell.d.ts +0 -1
  97. package/dist/hub.d.ts +0 -37
  98. package/dist/i18n.d.ts +0 -39
  99. package/dist/iii/client.d.ts +0 -2
  100. package/dist/iii/index.d.ts +0 -4
  101. package/dist/iii/register-worker.d.ts +0 -9
  102. package/dist/iii/rest.d.ts +0 -3
  103. package/dist/iii/stream.d.ts +0 -82
  104. package/dist/iii/types.d.ts +0 -121
  105. package/dist/iii/worker.d.ts +0 -2
  106. package/dist/iii/ws.d.ts +0 -22
  107. package/dist/index.d.ts +0 -101
  108. package/dist/index.js +0 -12752
  109. package/dist/kb/index.d.ts +0 -3
  110. package/dist/kb/types.d.ts +0 -72
  111. package/dist/layout.d.ts +0 -2
  112. package/dist/live.d.ts +0 -7
  113. package/dist/logdb/client.d.ts +0 -2
  114. package/dist/logdb/index.d.ts +0 -2
  115. package/dist/logdb/rest.d.ts +0 -5
  116. package/dist/logdb/types.d.ts +0 -27
  117. package/dist/logger.d.ts +0 -16
  118. package/dist/mailer.d.ts +0 -51
  119. package/dist/mcp.d.ts +0 -34
  120. package/dist/messager/agent.d.ts +0 -11
  121. package/dist/messager/client.d.ts +0 -2
  122. package/dist/messager/index.d.ts +0 -2
  123. package/dist/messager/rest.d.ts +0 -15
  124. package/dist/messager/types.d.ts +0 -57
  125. package/dist/messager/ws.d.ts +0 -14
  126. package/dist/module-server.d.ts +0 -9
  127. package/dist/not-found.d.ts +0 -2
  128. package/dist/notifier/client.d.ts +0 -2
  129. package/dist/notifier/index.d.ts +0 -2
  130. package/dist/notifier/types.d.ts +0 -105
  131. package/dist/opencode/client.d.ts +0 -2
  132. package/dist/opencode/index.d.ts +0 -2
  133. package/dist/opencode/permissions.d.ts +0 -5
  134. package/dist/opencode/prompt.d.ts +0 -8
  135. package/dist/opencode/rest.d.ts +0 -16
  136. package/dist/opencode/run.d.ts +0 -13
  137. package/dist/opencode/session.d.ts +0 -26
  138. package/dist/opencode/skills.d.ts +0 -4
  139. package/dist/opencode/tools/bash.d.ts +0 -6
  140. package/dist/opencode/tools/edit.d.ts +0 -19
  141. package/dist/opencode/tools/glob.d.ts +0 -9
  142. package/dist/opencode/tools/grep.d.ts +0 -17
  143. package/dist/opencode/tools/index.d.ts +0 -12
  144. package/dist/opencode/tools/question.d.ts +0 -5
  145. package/dist/opencode/tools/read.d.ts +0 -16
  146. package/dist/opencode/tools/skill.d.ts +0 -18
  147. package/dist/opencode/tools/web.d.ts +0 -18
  148. package/dist/opencode/tools/write.d.ts +0 -13
  149. package/dist/opencode/types.d.ts +0 -90
  150. package/dist/opencode/ws.d.ts +0 -21
  151. package/dist/permissions.d.ts +0 -51
  152. package/dist/postgres/client.d.ts +0 -4
  153. package/dist/postgres/index.d.ts +0 -4
  154. package/dist/postgres/module.d.ts +0 -17
  155. package/dist/postgres/schema/columns.d.ts +0 -99
  156. package/dist/postgres/schema/index.d.ts +0 -6
  157. package/dist/postgres/schema/sql.d.ts +0 -22
  158. package/dist/postgres/schema/table.d.ts +0 -141
  159. package/dist/postgres/schema/where.d.ts +0 -29
  160. package/dist/postgres/types.d.ts +0 -50
  161. package/dist/queue/index.d.ts +0 -2
  162. package/dist/queue/types.d.ts +0 -62
  163. package/dist/rate-limit.d.ts +0 -45
  164. package/dist/react.d.ts +0 -14
  165. package/dist/react.js +0 -751
  166. package/dist/redis/client.d.ts +0 -2
  167. package/dist/redis/types.d.ts +0 -18
  168. package/dist/request-id.d.ts +0 -40
  169. package/dist/router.d.ts +0 -73
  170. package/dist/s3.d.ts +0 -68
  171. package/dist/seo.d.ts +0 -104
  172. package/dist/serve.d.ts +0 -38
  173. package/dist/server-registry.d.ts +0 -10
  174. package/dist/session.d.ts +0 -117
  175. package/dist/sse.d.ts +0 -47
  176. package/dist/ssr-entries.d.ts +0 -4
  177. package/dist/ssr.d.ts +0 -11
  178. package/dist/static.d.ts +0 -23
  179. package/dist/stream.d.ts +0 -24
  180. package/dist/tailwind.d.ts +0 -15
  181. package/dist/tenant/client.d.ts +0 -2
  182. package/dist/tenant/graphql.d.ts +0 -3
  183. package/dist/tenant/index.d.ts +0 -2
  184. package/dist/tenant/rest.d.ts +0 -3
  185. package/dist/tenant/schema.d.ts +0 -5
  186. package/dist/tenant/types.d.ts +0 -48
  187. package/dist/tenant/utils.d.ts +0 -9
  188. package/dist/test-utils.d.ts +0 -194
  189. package/dist/theme.d.ts +0 -31
  190. package/dist/trace.d.ts +0 -95
  191. package/dist/tsx-context.d.ts +0 -32
  192. package/dist/types.d.ts +0 -47
  193. package/dist/upload.d.ts +0 -55
  194. package/dist/use-action.d.ts +0 -42
  195. package/dist/use-agent-stream.d.ts +0 -49
  196. package/dist/use-flash-message.d.ts +0 -17
  197. package/dist/use-websocket.d.ts +0 -42
  198. package/dist/user/client.d.ts +0 -30
  199. package/dist/user/index.d.ts +0 -2
  200. package/dist/user/oauth-login.d.ts +0 -21
  201. package/dist/user/oauth2.d.ts +0 -31
  202. package/dist/user/types.d.ts +0 -178
  203. package/dist/validate.d.ts +0 -32
  204. package/dist/vendor.d.ts +0 -7
  205. package/dist/webhook.d.ts +0 -79
  206. package/opencode/ui/app/globals.css +0 -1
  207. package/opencode/ui/app/layout.tsx +0 -13
  208. package/opencode/ui/app/page.tsx +0 -523
package/dist/react.js DELETED
@@ -1,751 +0,0 @@
1
- // use-websocket.ts
2
- import { useEffect, useRef, useCallback, useState } from "react";
3
- var RECONNECT_DELAY = 3e3;
4
- var MAX_RETRIES = 10;
5
- function resolveUrl(url) {
6
- return typeof url === "function" ? url() : url;
7
- }
8
- function useWebsocket(url, options) {
9
- const { onMessage, reconnect: reconnectOpt = true, protocols, enabled = true } = options ?? {};
10
- const [lastMessage, setLastMessage] = useState(null);
11
- const [readyState, setReadyState] = useState(WebSocket.CLOSED);
12
- const wsRef = useRef(null);
13
- const retryRef = useRef(0);
14
- const timerRef = useRef(void 0);
15
- const mountedRef = useRef(true);
16
- const shouldReconnectRef = useRef(true);
17
- const urlRef = useRef(url);
18
- const optsRef = useRef({ onMessage, reconnectOpt, protocols });
19
- urlRef.current = url;
20
- optsRef.current = { onMessage, reconnectOpt, protocols };
21
- const cleanup = useCallback(() => {
22
- clearTimeout(timerRef.current);
23
- wsRef.current?.close();
24
- wsRef.current = null;
25
- }, []);
26
- const connect = useCallback(() => {
27
- if (!mountedRef.current || !enabled) return;
28
- const resolved = resolveUrl(urlRef.current);
29
- if (!resolved) return;
30
- wsRef.current?.close();
31
- const ws = new WebSocket(resolved, optsRef.current.protocols);
32
- wsRef.current = ws;
33
- setReadyState(WebSocket.CONNECTING);
34
- ws.addEventListener("open", () => {
35
- if (!mountedRef.current) return;
36
- retryRef.current = 0;
37
- setReadyState(WebSocket.OPEN);
38
- });
39
- ws.addEventListener("message", (e) => {
40
- if (!mountedRef.current) return;
41
- const data = typeof e.data === "string" ? e.data : String(e.data);
42
- setLastMessage(data);
43
- optsRef.current.onMessage?.(data);
44
- });
45
- ws.addEventListener("close", () => {
46
- if (!mountedRef.current) return;
47
- setReadyState(WebSocket.CLOSED);
48
- const ro = optsRef.current.reconnectOpt;
49
- if (ro && shouldReconnectRef.current && mountedRef.current) {
50
- const maxRetries = typeof ro === "object" ? ro.maxRetries ?? MAX_RETRIES : MAX_RETRIES;
51
- const delay = typeof ro === "object" ? ro.delay ?? RECONNECT_DELAY : RECONNECT_DELAY;
52
- if (retryRef.current < maxRetries) {
53
- retryRef.current++;
54
- timerRef.current = setTimeout(() => connect(), delay);
55
- }
56
- }
57
- });
58
- }, [enabled]);
59
- useEffect(() => {
60
- mountedRef.current = true;
61
- shouldReconnectRef.current = true;
62
- if (enabled) connect();
63
- return () => {
64
- mountedRef.current = false;
65
- cleanup();
66
- };
67
- }, [enabled, connect, cleanup]);
68
- const send = useCallback((data) => {
69
- wsRef.current?.send(data);
70
- }, []);
71
- const close = useCallback(() => {
72
- shouldReconnectRef.current = false;
73
- cleanup();
74
- setReadyState(WebSocket.CLOSED);
75
- }, [cleanup]);
76
- const reconnectFn = useCallback(() => {
77
- retryRef.current = 0;
78
- shouldReconnectRef.current = true;
79
- cleanup();
80
- connect();
81
- }, [cleanup, connect]);
82
- return { send, close, readyState, lastMessage, reconnect: reconnectFn };
83
- }
84
-
85
- // use-action.ts
86
- import { useState as useState2, useCallback as useCallback2, useRef as useRef2 } from "react";
87
- function getCsrfToken() {
88
- if (typeof document === "undefined") return void 0;
89
- const match = document.cookie.match(/(?:^|;\s*)_csrf=([^;]+)/);
90
- return match ? decodeURIComponent(match[1]) : void 0;
91
- }
92
- function useAction(url, options) {
93
- const { method = "POST", headers, onSuccess, onError } = options ?? {};
94
- const [data, setData] = useState2(null);
95
- const [error, setError] = useState2(null);
96
- const [pending, setPending] = useState2(false);
97
- const mountedRef = useRef2(true);
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);
133
- }
134
- },
135
- [url, method, headers, onSuccess, onError]
136
- );
137
- const reset = useCallback2(() => {
138
- setData(null);
139
- setError(null);
140
- }, []);
141
- return { submit, data, error, pending, reset };
142
- }
143
-
144
- // client-router.ts
145
- import { createElement, useCallback as useCallback3, useState as useState3, useEffect as useEffect2 } from "react";
146
-
147
- // client-pref.ts
148
- var interceptors = [];
149
- function addInterceptor(fn) {
150
- interceptors.push(fn);
151
- }
152
- async function runInterceptors(url) {
153
- for (const fn of interceptors) {
154
- if (await fn(url)) return true;
155
- }
156
- return false;
157
- }
158
-
159
- // tsx-context.ts
160
- import { useSyncExternalStore, createContext } from "react";
161
- var DEFAULT_CTX = {
162
- params: {},
163
- query: {},
164
- parsed: {},
165
- loaderData: {},
166
- env: {},
167
- user: {},
168
- flash: {}
169
- };
170
- var KEY = "__WEIFUWU_CTX_STORE";
171
- function getStore() {
172
- if (typeof globalThis !== "undefined" && globalThis[KEY]) {
173
- return globalThis[KEY];
174
- }
175
- const s = {
176
- _ctx: DEFAULT_CTX,
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
- },
187
- _listeners: /* @__PURE__ */ new Set(),
188
- _rebuilders: [],
189
- _alsGetStore: null
190
- };
191
- if (typeof globalThis !== "undefined") {
192
- ;
193
- globalThis[KEY] = s;
194
- }
195
- return s;
196
- }
197
- var store = getStore();
198
- function addCtxRebuilder(fn) {
199
- store._rebuilders.push(fn);
200
- }
201
- var subscribe = (cb) => {
202
- store._listeners.add(cb);
203
- return () => {
204
- store._listeners.delete(cb);
205
- };
206
- };
207
- var getSnapshot = () => store._snapshot;
208
- function setCtx(value) {
209
- if (typeof window !== "undefined") {
210
- for (const r of store._rebuilders) {
211
- const rebuilt = r(value);
212
- if (rebuilt) Object.assign(value, rebuilt);
213
- }
214
- }
215
- store._ctx = { ...store._ctx, ...value };
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
- };
226
- if (typeof window !== "undefined") {
227
- ;
228
- window.__WEIFUWU_CTX = { ...window.__WEIFUWU_CTX, ...value };
229
- }
230
- store._listeners.forEach((fn) => fn());
231
- }
232
- function useCtx() {
233
- if (typeof window !== "undefined") {
234
- return useSyncExternalStore(subscribe, getSnapshot);
235
- }
236
- const alsStore = store._alsGetStore?.();
237
- return alsStore ?? store._ctx;
238
- }
239
- function useLoaderData() {
240
- const ctx = useCtx();
241
- return ctx.loaderData;
242
- }
243
- var TsxContext = createContext(DEFAULT_CTX);
244
-
245
- // client-router.ts
246
- var _navigating = false;
247
- var _listeners = [];
248
- function onNavigate(fn) {
249
- _listeners.push(fn);
250
- return () => {
251
- _listeners = _listeners.filter((l) => l !== fn);
252
- };
253
- }
254
- function setNavigating(v) {
255
- _navigating = v;
256
- for (const fn of _listeners) fn(v);
257
- }
258
- async function navigate(href) {
259
- if (typeof document === "undefined") return;
260
- const url = new URL(href, location.origin);
261
- if (url.origin !== location.origin) {
262
- location.href = href;
263
- return;
264
- }
265
- if (await runInterceptors(url)) return;
266
- const scrollPos = [window.scrollX, window.scrollY];
267
- setNavigating(true);
268
- try {
269
- const html = await fetch(url.pathname + url.search, {
270
- headers: { accept: "text/html" }
271
- }).then((r) => r.text());
272
- const doc = new DOMParser().parseFromString(html, "text/html");
273
- const rootEl = doc.getElementById("__weifuwu_root");
274
- if (!rootEl) {
275
- location.href = href;
276
- return;
277
- }
278
- const newHtml = rootEl.innerHTML;
279
- const bundleMatch = html.match(/src="(\/__ssr\/[^"]+\.js)"/);
280
- const bundleUrl = bundleMatch ? bundleMatch[1] : null;
281
- const ctxMatch = html.match(/window\.__WEIFUWU_CTX=(.+?)<\/script>/);
282
- if (ctxMatch) {
283
- try {
284
- const ctx = JSON.parse(ctxMatch[1]);
285
- window.__WEIFUWU_CTX = ctx;
286
- setCtx(ctx);
287
- } catch {
288
- }
289
- }
290
- applyHead(html);
291
- const currentRoot = document.getElementById("__weifuwu_root");
292
- if (!currentRoot) {
293
- location.href = href;
294
- return;
295
- }
296
- history.pushState(null, "", url.pathname + url.search);
297
- currentRoot.innerHTML = newHtml;
298
- if (bundleUrl) {
299
- try {
300
- await import(
301
- /* @vite-ignore */
302
- `${bundleUrl}`
303
- );
304
- } catch (e) {
305
- console.error("[weifuwu/router] hydration failed:", e);
306
- location.href = href;
307
- }
308
- }
309
- window.scrollTo(scrollPos[0], scrollPos[1]);
310
- } finally {
311
- setNavigating(false);
312
- }
313
- }
314
- function applyHead(html) {
315
- const match = html.match(/<template id="__wfw_head">([\s\S]*?)<\/template>/);
316
- if (!match) return;
317
- const headHtml = match[1];
318
- const titleMatch = headHtml.match(/<title>([^<]*)<\/title>/);
319
- if (titleMatch) document.title = titleMatch[1];
320
- const doc = new DOMParser().parseFromString(headHtml, "text/html");
321
- const newMeta = doc.querySelectorAll("meta");
322
- const existing = document.querySelectorAll("head meta");
323
- const newNames = new Set(
324
- Array.from(newMeta).map((m) => m.getAttribute("name") || m.getAttribute("property") || "")
325
- );
326
- for (const el of existing) {
327
- const key = el.getAttribute("name") || el.getAttribute("property") || "";
328
- if (!newNames.has(key)) el.remove();
329
- }
330
- for (const el of newMeta) {
331
- const key = el.getAttribute("name") || el.getAttribute("property") || "";
332
- let existingEl = null;
333
- if (key) {
334
- for (const m of document.head.querySelectorAll("meta")) {
335
- if (m.getAttribute("name") === key || m.getAttribute("property") === key) {
336
- existingEl = m;
337
- break;
338
- }
339
- }
340
- }
341
- if (existingEl) {
342
- for (const attr of el.attributes)
343
- existingEl.setAttribute(attr.name, attr.value);
344
- } else {
345
- document.head.appendChild(el.cloneNode());
346
- }
347
- }
348
- const newLink = doc.querySelector('link[rel="canonical"]');
349
- const existingLink = document.querySelector('link[rel="canonical"]');
350
- if (newLink) {
351
- if (existingLink) existingLink.setAttribute("href", newLink.getAttribute("href") || "");
352
- else document.head.appendChild(newLink.cloneNode());
353
- } else if (existingLink) {
354
- existingLink.remove();
355
- }
356
- }
357
- function useNavigate() {
358
- return useCallback3((href) => navigate(href), []);
359
- }
360
- function useNavigating() {
361
- const [v, setV] = useState3(false);
362
- useEffect2(() => onNavigate(setV), []);
363
- return v;
364
- }
365
- var prefetchCache = /* @__PURE__ */ new Map();
366
- var PREFETCH_TTL = 6e4;
367
- function Link({ href, children, onClick, prefetch, ...props }) {
368
- const doNavigate = useNavigate();
369
- useEffect2(() => {
370
- if (!prefetch) return;
371
- let el = document.querySelector(`a[href="${CSS.escape(href)}"]`);
372
- if (!el) {
373
- for (const a of document.querySelectorAll("a")) {
374
- if (a.getAttribute("href") === href) {
375
- el = a;
376
- break;
377
- }
378
- }
379
- }
380
- if (!el) return;
381
- const observer = new IntersectionObserver(
382
- ([entry]) => {
383
- if (entry.isIntersecting) prefetchPage(href);
384
- },
385
- { rootMargin: "200px" }
386
- );
387
- observer.observe(el);
388
- return () => observer.disconnect();
389
- }, [href, prefetch]);
390
- const handleMouseEnter = useCallback3(() => {
391
- if (prefetch) prefetchPage(href);
392
- }, [href, prefetch]);
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
- );
412
- }
413
- async function prefetchPage(href) {
414
- const cached = prefetchCache.get(href);
415
- if (cached && Date.now() - cached.fetched < PREFETCH_TTL) return;
416
- try {
417
- const html = await fetch(href, { headers: { accept: "text/html" } }).then((r) => r.text());
418
- prefetchCache.set(href, { html, fetched: Date.now() });
419
- } catch {
420
- }
421
- }
422
-
423
- // head.tsx
424
- import { createElement as createElement2 } from "react";
425
- function Head({ children }) {
426
- return createElement2("template", { id: "__wfw_head" }, children);
427
- }
428
-
429
- // client-state.ts
430
- import { useSyncExternalStore as useSyncExternalStore2, useCallback as useCallback4, useEffect as useEffect3, useRef as useRef3, useState as useState4 } from "react";
431
- function createStore(initial) {
432
- let state = { ...initial };
433
- const listeners = /* @__PURE__ */ new Set();
434
- const getState = () => state;
435
- const setState = (partial) => {
436
- const next = typeof partial === "function" ? partial(state) : partial;
437
- state = { ...state, ...next };
438
- listeners.forEach((fn) => fn());
439
- };
440
- const subscribe2 = (listener) => {
441
- listeners.add(listener);
442
- return () => {
443
- listeners.delete(listener);
444
- };
445
- };
446
- const useStore = ((selector) => useSyncExternalStore2(subscribe2, () => selector ? selector(state) : state));
447
- useStore.getState = getState;
448
- useStore.setState = setState;
449
- useStore.subscribe = subscribe2;
450
- return useStore;
451
- }
452
- var dataCache = /* @__PURE__ */ new Map();
453
- var inflight = /* @__PURE__ */ new Map();
454
- var CACHE_TTL = 6e4;
455
- function useFetch(url, options) {
456
- const ttl = options?.ttl ?? CACHE_TTL;
457
- const [state, setState] = useState4({
458
- data: options?.fallback,
459
- loading: !options?.fallback && !!url
460
- });
461
- const urlRef = useRef3(url);
462
- urlRef.current = url;
463
- useEffect3(() => {
464
- if (!url) {
465
- setState({ data: void 0, loading: false });
466
- return;
467
- }
468
- if (typeof window === "undefined") return;
469
- const u = url;
470
- let cancelled = false;
471
- const cached = dataCache.get(u);
472
- if (cached && Date.now() - cached.timestamp < ttl) {
473
- if (!cancelled)
474
- setState({
475
- data: cached.data,
476
- error: cached.error,
477
- loading: false
478
- });
479
- return;
480
- }
481
- async function doFetch() {
482
- if (!inflight.has(u)) {
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
- );
490
- }
491
- const promise = inflight.get(u);
492
- try {
493
- const data = await promise;
494
- dataCache.set(u, { data, error: null, timestamp: Date.now() });
495
- if (!cancelled) setState({ data, loading: false });
496
- } catch (err) {
497
- dataCache.set(u, { data: null, error: err, timestamp: Date.now() });
498
- if (!cancelled) setState({ error: err, loading: false });
499
- }
500
- }
501
- doFetch();
502
- return () => {
503
- cancelled = true;
504
- };
505
- }, [url, ttl]);
506
- const mutate = useCallback4(async (data) => {
507
- const u = urlRef.current;
508
- if (!u) return;
509
- const uStr = u;
510
- if (data !== void 0) {
511
- dataCache.set(uStr, { data, error: null, timestamp: Date.now() });
512
- setState({ data, loading: false, error: void 0 });
513
- return;
514
- }
515
- inflight.delete(uStr);
516
- try {
517
- const res = await fetch(uStr);
518
- if (!res.ok) throw new Error(res.statusText || `HTTP ${res.status}`);
519
- const newData = await res.json();
520
- dataCache.set(uStr, { data: newData, error: null, timestamp: Date.now() });
521
- setState({ data: newData, loading: false, error: void 0 });
522
- } catch (err) {
523
- setState({ error: err, loading: false });
524
- }
525
- }, []);
526
- return { data: state.data, error: state.error, loading: state.loading, mutate };
527
- }
528
- function notifyQueryListeners() {
529
- if (typeof window === "undefined") return;
530
- window.dispatchEvent(new PopStateEvent("popstate"));
531
- }
532
- function useQueryState(key, defaultValue = "") {
533
- function getSnapshot2() {
534
- if (typeof window === "undefined") return defaultValue;
535
- const params = new URLSearchParams(window.location.search);
536
- return params.get(key) ?? defaultValue;
537
- }
538
- const value = useSyncExternalStore2(
539
- (cb) => {
540
- if (typeof window === "undefined") return () => {
541
- };
542
- window.addEventListener("popstate", cb);
543
- return () => window.removeEventListener("popstate", cb);
544
- },
545
- getSnapshot2,
546
- () => defaultValue
547
- );
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
- );
563
- return [value, setValue];
564
- }
565
-
566
- // client-locale.ts
567
- function buildT(messages) {
568
- if (!messages || Object.keys(messages).length === 0) {
569
- return (key, _p, fb) => fb ?? key;
570
- }
571
- return (key, params, fallback) => {
572
- const msg = key.split(".").reduce((o, k) => o?.[k], messages);
573
- if (msg === void 0 || msg === null) return fallback ?? key;
574
- if (!params) return String(msg);
575
- let result = String(msg);
576
- for (const [k, v] of Object.entries(params)) result = result.replace(`{${k}}`, v);
577
- return result;
578
- };
579
- }
580
- addCtxRebuilder((value) => {
581
- if (value.i18n?.messages) {
582
- return { i18n: { ...value.i18n, t: buildT(value.i18n.messages) } };
583
- }
584
- return null;
585
- });
586
- addInterceptor(async (url) => {
587
- const m = url.pathname.match(/^\/__lang\/([\w-]+)$/);
588
- if (!m) return false;
589
- try {
590
- const res = await fetch(url.pathname, {
591
- headers: { accept: "application/json" }
592
- });
593
- const data = await res.json();
594
- setCtx({ i18n: { locale: data.locale, messages: data.messages || {} } });
595
- } catch {
596
- location.href = url.href;
597
- }
598
- return true;
599
- });
600
- function useLocale() {
601
- const ctx = useCtx();
602
- return {
603
- locale: ctx.i18n?.locale,
604
- setLocale: (locale) => navigate("/__lang/" + locale),
605
- t: ctx.i18n?.t ?? ((key, _p, fb) => fb ?? key)
606
- };
607
- }
608
-
609
- // client-theme.ts
610
- import { useEffect as useEffect4 } from "react";
611
- function resolveTheme(theme) {
612
- if (theme === "system") {
613
- if (typeof window === "undefined") return "light";
614
- return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
615
- }
616
- return theme;
617
- }
618
- var _mqListener = null;
619
- function applyTheme(theme) {
620
- if (typeof document === "undefined") return;
621
- const resolved = resolveTheme(theme);
622
- document.documentElement.dataset.theme = resolved;
623
- if (theme === "system") {
624
- if (!_mqListener) {
625
- const mq = window.matchMedia("(prefers-color-scheme: dark)");
626
- mq.addEventListener("change", (e) => {
627
- if (window.__WEIFUWU_CTX?.theme?.value === "system") {
628
- document.documentElement.dataset.theme = e.matches ? "dark" : "light";
629
- }
630
- });
631
- _mqListener = mq;
632
- }
633
- }
634
- }
635
- addInterceptor(async (url) => {
636
- const m = url.pathname.match(/^\/__theme\/([\w-]+)$/);
637
- if (!m) return false;
638
- try {
639
- const res = await fetch(url.pathname, {
640
- headers: { accept: "application/json" }
641
- });
642
- const data = await res.json();
643
- window.__WEIFUWU_CTX = {
644
- ...window.__WEIFUWU_CTX,
645
- theme: { value: data.theme }
646
- };
647
- setCtx({ theme: { value: data.theme } });
648
- applyTheme(data.theme);
649
- } catch {
650
- location.href = url.href;
651
- }
652
- return true;
653
- });
654
- function useTheme() {
655
- const ctx = useCtx();
656
- const theme = ctx.theme?.value ?? "system";
657
- useEffect4(() => {
658
- applyTheme(theme);
659
- }, [theme]);
660
- return {
661
- theme,
662
- resolvedTheme: resolveTheme(theme),
663
- setTheme: (t) => navigate("/__theme/" + t)
664
- };
665
- }
666
-
667
- // use-flash-message.ts
668
- import { useState as useState5 } from "react";
669
- function useFlashMessage() {
670
- const [flash] = useState5(() => {
671
- if (typeof window === "undefined") return null;
672
- const raw = window.__WEIFUWU_CTX?.flash?.value;
673
- if (raw === void 0 || raw === null) return null;
674
- return raw;
675
- });
676
- return flash;
677
- }
678
-
679
- // use-agent-stream.ts
680
- import { useState as useState6, useCallback as useCallback5, useRef as useRef4 } from "react";
681
- function useAgentStream(opts) {
682
- const { wsPath, onStreamEnd, onError } = opts;
683
- const [streams, setStreams] = useState6({});
684
- const activeRef = useRef4(/* @__PURE__ */ new Set());
685
- const streamsRef = useRef4({});
686
- const getAgentText = useCallback5((agentId) => streams[agentId] || "", [streams]);
687
- const isAgentStreaming = useCallback5((agentId) => activeRef.current.has(agentId), []);
688
- const streaming = activeRef.current.size > 0;
689
- useWebsocket(wsPath, {
690
- onMessage: (raw) => {
691
- try {
692
- const msg = JSON.parse(raw);
693
- if (msg.type !== "agent_stream" && msg.type !== "agent_stream_end" && msg.type !== "agent_error")
694
- return;
695
- const agentId = msg.data?.agent_id;
696
- if (agentId === void 0 || agentId === null) return;
697
- switch (msg.type) {
698
- case "agent_stream": {
699
- activeRef.current.add(agentId);
700
- const token = msg.data?.token || "";
701
- streamsRef.current[agentId] = (streamsRef.current[agentId] || "") + token;
702
- setStreams({ ...streamsRef.current });
703
- break;
704
- }
705
- case "agent_stream_end": {
706
- activeRef.current.delete(agentId);
707
- const fullText = streamsRef.current[agentId] || "";
708
- onStreamEnd?.(agentId, fullText);
709
- break;
710
- }
711
- case "agent_error": {
712
- activeRef.current.delete(agentId);
713
- delete streamsRef.current[agentId];
714
- onError?.(agentId, msg.data?.error || "Unknown error");
715
- break;
716
- }
717
- }
718
- } catch {
719
- }
720
- },
721
- reconnect: { maxRetries: 10, delay: 3e3 }
722
- });
723
- return {
724
- stream: { streams, streaming, activeAgents: activeRef.current },
725
- getAgentText,
726
- isAgentStreaming
727
- };
728
- }
729
- export {
730
- Head,
731
- Link,
732
- TsxContext,
733
- addCtxRebuilder,
734
- addInterceptor,
735
- applyTheme,
736
- createStore,
737
- navigate,
738
- setCtx,
739
- useAction,
740
- useAgentStream,
741
- useCtx,
742
- useFetch,
743
- useFlashMessage,
744
- useLoaderData,
745
- useLocale,
746
- useNavigate,
747
- useNavigating,
748
- useQueryState,
749
- useTheme,
750
- useWebsocket
751
- };