@allbluecn/web-app 0.22.4 → 0.23.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 (500) hide show
  1. package/package.json +4 -14
  2. package/src/__tests__/integration/login-email-acceptance.test.ts +16 -0
  3. package/src/__tests__/story-view.test.ts +33 -1
  4. package/src/components/agents/__tests__/agent-bindings-tab.test.tsx +221 -0
  5. package/src/components/agents/__tests__/agents-page.test.tsx +284 -0
  6. package/src/components/agents/agent-bindings-tab.tsx +59 -45
  7. package/src/components/agents/agent-form-dialog.tsx +3 -3
  8. package/src/components/agents/agent-selector.tsx +2 -3
  9. package/src/components/agents/agents-page.tsx +66 -31
  10. package/src/components/agents/slash-skill-menu.tsx +2 -3
  11. package/src/components/auth/__tests__/session-guard.test.tsx +74 -0
  12. package/src/components/auth/session-guard.tsx +8 -0
  13. package/src/components/billing/login-prompt-dialog.tsx +1 -1
  14. package/src/components/billing/subscription-provider.tsx +2 -16
  15. package/src/components/bug/__tests__/peek-modes.test.tsx +8 -0
  16. package/src/components/bug/__tests__/subgroup-header.test.tsx +202 -40
  17. package/src/components/bug/peek-panel.tsx +5 -3
  18. package/src/components/bug/views/bug-list/group.tsx +12 -2
  19. package/src/components/bug/views/bug-list/index.tsx +94 -67
  20. package/src/components/command/command-palette.tsx +10 -9
  21. package/src/components/design/canvas/document/frame-custom-presets.ts +9 -1
  22. package/src/components/design/canvas/panels/toolbar.tsx +21 -22
  23. package/src/components/design/canvas/react/__tests__/canvas-context-load-echo.test.tsx +199 -0
  24. package/src/components/design/canvas/react/__tests__/hooks.test.tsx +17 -3
  25. package/src/components/design/canvas/react/canvas-context.tsx +47 -26
  26. package/src/components/design/canvas/react/hooks.ts +39 -34
  27. package/src/components/design/editor/layout/__tests__/collab-param-wiring.test.tsx +17 -0
  28. package/src/components/design/editor/layout/__tests__/context-menu.test.tsx +17 -1
  29. package/src/components/design/editor/layout/__tests__/no-page-save-toast.test.tsx +17 -0
  30. package/src/components/design/editor/layout/__tests__/persistence-restore.test.tsx +17 -1
  31. package/src/components/design/editor/layout/__tests__/ssr-localstorage-smoke.test.tsx +17 -1
  32. package/src/components/design/editor/layout/design-editor-layout.tsx +13 -2
  33. package/src/components/design/editor/layout/hooks/use-design-auto-save.ts +3 -19
  34. package/src/components/devtools/devtools-panel.tsx +56 -0
  35. package/src/components/forms/__tests__/create-app-form.test.tsx +131 -0
  36. package/src/components/forms/app-field-error.tsx +21 -1
  37. package/src/components/forms/app-field.tsx +8 -8
  38. package/src/components/forms/app-submit.tsx +12 -9
  39. package/src/components/forms/create-app-form.tsx +124 -0
  40. package/src/components/forms/index.ts +2 -3
  41. package/src/components/harness/__tests__/gallery-behavior.test.tsx +37 -1
  42. package/src/components/harness/__tests__/harness-workbench-first-send.test.tsx +4 -1
  43. package/src/components/harness/__tests__/message-actions.test.tsx +7 -6
  44. package/src/components/harness/__tests__/use-video-generation.test.tsx +165 -0
  45. package/src/components/harness/ai-chat-history/index.tsx +5 -3
  46. package/src/components/harness/gallery/gallery-card.tsx +57 -35
  47. package/src/components/harness/gallery/gallery-grid.tsx +32 -15
  48. package/src/components/harness/gallery/gallery-types.ts +19 -0
  49. package/src/components/harness/gallery/gallery-video-card.tsx +54 -0
  50. package/src/components/harness/gallery/types.ts +2 -0
  51. package/src/components/harness/gallery/use-video-generation.ts +95 -0
  52. package/src/components/harness/harness-workbench-page.tsx +2 -3
  53. package/src/components/harness/message-actions.tsx +5 -3
  54. package/src/components/hotkeys/shortcuts-panel.tsx +28 -13
  55. package/src/components/iteration/__tests__/burndown-chart.test.tsx +118 -0
  56. package/src/components/iteration/burndown-chart.tsx +54 -23
  57. package/src/components/knowledge/editor/__tests__/knowledge-doc-editor-collab.test.tsx +96 -0
  58. package/src/components/knowledge/editor/knowledge-doc-editor.tsx +56 -1
  59. package/src/components/knowledge/editor/mindmap-doc-editor.tsx +12 -0
  60. package/src/components/knowledge/editor/use-auto-save-channels.ts +3 -1
  61. package/src/components/layout/sidebar-03/__tests__/nav-workspace.test.tsx +0 -4
  62. package/src/components/layout/sidebar-03/nav-knowledge.tsx +11 -11
  63. package/src/components/layout/sidebar-03/nav-main.tsx +12 -15
  64. package/src/components/layout/sidebar-03/nav-notifications.tsx +5 -8
  65. package/src/components/layout/sidebar-03/nav-workspace.tsx +11 -9
  66. package/src/components/notifications/__tests__/settings-notifications.test.tsx +158 -0
  67. package/src/components/notifications/settings-notifications.tsx +37 -13
  68. package/src/components/notifications/team-notifications.tsx +10 -14
  69. package/src/components/settings/personal-team/account/__tests__/account-client.test.tsx +170 -0
  70. package/src/components/settings/personal-team/account/account-client.tsx +44 -7
  71. package/src/components/settings/personal-team/team/team-client.tsx +17 -19
  72. package/src/components/shared-kit/list-kit/__tests__/frozen-header.test.ts +210 -41
  73. package/src/components/shared-kit/list-kit/frozen-header.ts +134 -21
  74. package/src/components/shared-kit/list-kit/kanban/frozen-header.ts +20 -27
  75. package/src/components/story/__tests__/peek-panel-patch-sync.test.tsx +8 -0
  76. package/src/components/story/__tests__/story-list-table.test.tsx +214 -0
  77. package/src/components/story/columns.tsx +11 -2
  78. package/src/components/story/peek-panel.tsx +4 -2
  79. package/src/components/story/story-list-table.tsx +16 -1
  80. package/src/components/story/views/story-list/__tests__/frozen-headers.test.tsx +186 -0
  81. package/src/components/story/views/story-list/group.tsx +12 -1
  82. package/src/components/story/views/story-list/index.tsx +101 -68
  83. package/src/components/testcase/__tests__/case-row.test.tsx +134 -2
  84. package/src/components/testcase/__tests__/peek-panel.test.tsx +8 -0
  85. package/src/components/testcase/__tests__/step-editor.test.tsx +106 -0
  86. package/src/components/testcase/list/grouped-list.tsx +50 -22
  87. package/src/components/testcase/peek-panel.tsx +7 -4
  88. package/src/components/testcase/step-editor.tsx +196 -150
  89. package/src/components/tiptap/notion-like/editor-extensions.ts +0 -3
  90. package/src/components/tiptap/notion-like/notion-like-editor-header.tsx +1 -31
  91. package/src/components/tiptap/notion-like/notion-like-editor.tsx +32 -1
  92. package/src/components/workspace/__tests__/dialogs/create-workspace-dialog.test.tsx +2 -28
  93. package/src/components/workspace/__tests__/dialogs/edit-workspace-dialog.test.tsx +2 -28
  94. package/src/components/workspace/dialogs/create-workspace-dialog.tsx +45 -43
  95. package/src/components/workspace/dialogs/edit-workspace-dialog.tsx +38 -36
  96. package/src/design-engine/engine/engine-decor.ts +2 -0
  97. package/src/design-engine/engine/engine-path.ts +2 -0
  98. package/src/hooks/__tests__/use-unsaved-guard.test.tsx +180 -0
  99. package/src/hooks/use-notifications.ts +9 -16
  100. package/src/hooks/use-unsaved-guard.tsx +87 -0
  101. package/src/lib/__tests__/pacer.test.ts +33 -96
  102. package/src/lib/__tests__/query-defaults.test.ts +169 -0
  103. package/src/lib/__tests__/query-global-error.test.ts +256 -0
  104. package/src/lib/anyhub/anyhub-store.ts +2 -2
  105. package/src/lib/changelog/sdk-versions.ts +2 -10
  106. package/src/lib/collab/presence-store.ts +5 -5
  107. package/src/lib/collab/use-presence-list-refresh.ts +2 -2
  108. package/src/lib/collab/use-share-presence.ts +2 -2
  109. package/src/lib/collections/query-keys.ts +7 -2
  110. package/src/lib/commands/__tests__/command-palette-state.test.ts +12 -14
  111. package/src/lib/commands/__tests__/registry.test.ts +6 -3
  112. package/src/lib/commands/command-palette-state.ts +8 -31
  113. package/src/lib/hotkeys/__tests__/registry.test.ts +71 -18
  114. package/src/lib/hotkeys/registry.ts +188 -85
  115. package/src/lib/hotkeys/types.ts +1 -13
  116. package/src/lib/pacer.ts +1 -79
  117. package/src/lib/queries/README.md +67 -0
  118. package/src/lib/queries/__tests__/agents-queries.test.ts +101 -0
  119. package/src/lib/queries/__tests__/compliance-queries.test.ts +136 -0
  120. package/src/lib/queries/__tests__/notifications-queries.test.ts +175 -0
  121. package/src/lib/queries/__tests__/team-queries.test.ts +87 -0
  122. package/src/lib/queries/agents.ts +40 -0
  123. package/src/lib/queries/compliance.ts +69 -0
  124. package/src/lib/queries/notifications.ts +63 -0
  125. package/src/lib/queries/team.ts +39 -0
  126. package/src/lib/query-defaults.ts +8 -0
  127. package/src/lib/query-global-error.ts +128 -0
  128. package/src/lib/remote-auth-client.ts +16 -0
  129. package/src/paraglide/README.md +1 -1
  130. package/src/paraglide/messages/_index.d.ts +11 -0
  131. package/src/paraglide/messages/_index.js +5659 -88285
  132. package/src/paraglide/messages/common_error_generic.d.ts +16 -0
  133. package/src/paraglide/messages/common_error_generic.js +29 -0
  134. package/src/paraglide/messages/common_unsaved_body.d.ts +16 -0
  135. package/src/paraglide/messages/common_unsaved_body.js +29 -0
  136. package/src/paraglide/messages/common_unsaved_leave.d.ts +16 -0
  137. package/src/paraglide/messages/common_unsaved_leave.js +29 -0
  138. package/src/paraglide/messages/common_unsaved_stay.d.ts +16 -0
  139. package/src/paraglide/messages/common_unsaved_stay.js +29 -0
  140. package/src/paraglide/messages/common_unsaved_title.d.ts +16 -0
  141. package/src/paraglide/messages/common_unsaved_title.js +29 -0
  142. package/src/paraglide/messages/gallery_videofailed1.d.ts +17 -0
  143. package/src/paraglide/messages/gallery_videofailed1.js +30 -0
  144. package/src/paraglide/messages/gallery_videogenerating1.d.ts +17 -0
  145. package/src/paraglide/messages/gallery_videogenerating1.js +30 -0
  146. package/src/paraglide/messages/gallery_videomissingprompt2.d.ts +17 -0
  147. package/src/paraglide/messages/gallery_videomissingprompt2.js +30 -0
  148. package/src/paraglide/messages/gallery_videoprogress1.d.ts +19 -0
  149. package/src/paraglide/messages/gallery_videoprogress1.js +30 -0
  150. package/src/paraglide/messages/gallery_videostop1.d.ts +17 -0
  151. package/src/paraglide/messages/gallery_videostop1.js +30 -0
  152. package/src/paraglide/messages/story_table_resizecolumn1.d.ts +17 -0
  153. package/src/paraglide/messages/story_table_resizecolumn1.js +30 -0
  154. package/src/providers/index.tsx +5 -50
  155. package/src/routeTree.gen.ts +21 -0
  156. package/src/router.tsx +21 -8
  157. package/src/routes/__root.tsx +2 -1
  158. package/src/routes/__tests__/-edition-routing.test.tsx +6 -1
  159. package/src/routes/_login/forgot-password/route.lazy.tsx +7 -6
  160. package/src/routes/_login/login/route.lazy.tsx +10 -9
  161. package/src/routes/_login/register/route.lazy.tsx +19 -18
  162. package/src/routes/_login/reset-password/route.lazy.tsx +10 -9
  163. package/src/routes/_nav/knowledge/compliance/$id.lazy.tsx +9 -12
  164. package/src/routes/_nav/knowledge/compliance/index.lazy.tsx +16 -13
  165. package/src/routes/_nav/knowledge/laws/$id.lazy.tsx +1 -1
  166. package/src/routes/_nav/notifications/route.tsx +6 -16
  167. package/src/routes/_nav/settings/-settings-tabs.tsx +9 -12
  168. package/src/routes/api/generate/__tests__/media.test.ts +378 -0
  169. package/src/routes/api/generate/media.ts +179 -0
  170. package/src/server/__tests__/agent-client-graph.test.ts +0 -1
  171. package/src/server/__tests__/agent-crud.test.ts +37 -4
  172. package/src/server/__tests__/bug-groups-two-level.test.ts +34 -1
  173. package/src/server/__tests__/chat-conversations.test.ts +37 -4
  174. package/src/server/__tests__/chat-list-messages.test.ts +40 -7
  175. package/src/server/__tests__/csv-export.test.ts +36 -3
  176. package/src/server/__tests__/desktop-bootstrap.test.ts +189 -0
  177. package/src/server/__tests__/remote-auth.test.ts +72 -0
  178. package/src/server/__tests__/skill-crud.test.ts +37 -4
  179. package/src/server/__tests__/sso-domain.test.ts +1 -1
  180. package/src/server/__tests__/sso-rate-limit-singleton.test.ts +123 -0
  181. package/src/server/__tests__/task-serverfn-crud.test.ts +35 -2
  182. package/src/server/__tests__/task-serverfn-queries.test.ts +35 -2
  183. package/src/server/__tests__/testcase-board.test.ts +38 -5
  184. package/src/server/__tests__/testcase-bulk.test.ts +38 -5
  185. package/src/server/__tests__/testcase-list-scope.test.ts +38 -5
  186. package/src/server/ai-gateway/__tests__/ai-output-guard.test.ts +126 -2
  187. package/src/server/ai-gateway/__tests__/chat-stream-builder-code-mode.test.ts +4 -0
  188. package/src/server/ai-gateway/__tests__/chat-stream-builder-memory.test.ts +4 -0
  189. package/src/server/ai-gateway/__tests__/chat-stream-builder-sandbox.test.ts +4 -0
  190. package/src/server/ai-gateway/__tests__/chat-stream-builder-skills.test.ts +4 -0
  191. package/src/server/ai-gateway/__tests__/pgvector-memory-adapter.test.ts +30 -0
  192. package/src/server/ai-gateway/__tests__/pgvector-memory-conformance.test.ts +92 -0
  193. package/src/server/ai-gateway/__tests__/source-mode.test.ts +49 -8
  194. package/src/server/ai-gateway/ai-output-guard.ts +50 -2
  195. package/src/server/ai-gateway/chat-stream-builder.ts +3 -0
  196. package/src/server/ai-gateway/media/index.ts +36 -29
  197. package/src/server/ai-gateway/media/trim-input.ts +52 -0
  198. package/src/server/ai-gateway/memory/pgvector-adapter.ts +27 -13
  199. package/src/server/ai-gateway/sandbox/__tests__/harness-sandbox.test.ts +252 -41
  200. package/src/server/ai-gateway/sandbox/harness-sandbox.ts +6 -67
  201. package/src/server/ai-gateway/source-mode.ts +24 -8
  202. package/src/server/desktop-bootstrap.ts +74 -0
  203. package/src/server/lib/__tests__/rate-limit.test.ts +0 -1
  204. package/src/server/lib/rate-limit.ts +0 -2
  205. package/src/server/middlewares/__tests__/auth-context.test.ts +156 -0
  206. package/src/server/middlewares/auth-context.ts +62 -0
  207. package/src/server/remote-auth.ts +58 -31
  208. package/src/server/serverFns/__tests__/ai-hosted-models.test.ts +47 -15
  209. package/src/server/serverFns/__tests__/ai-source-mode.test.ts +45 -15
  210. package/src/server/serverFns/__tests__/billing.test.ts +37 -2
  211. package/src/server/serverFns/__tests__/collab-snapshot.test.ts +41 -14
  212. package/src/server/serverFns/__tests__/collab.test.ts +41 -14
  213. package/src/server/serverFns/__tests__/compliance.test.ts +33 -1
  214. package/src/server/serverFns/__tests__/email-verification.test.ts +35 -1
  215. package/src/server/serverFns/__tests__/knowledge-breadcrumb.test.ts +46 -6
  216. package/src/server/serverFns/__tests__/knowledge-delete.test.ts +42 -14
  217. package/src/server/serverFns/__tests__/knowledge-kb-projects.test.ts +46 -6
  218. package/src/server/serverFns/__tests__/knowledge-public-compliance.test.ts +36 -2
  219. package/src/server/serverFns/__tests__/knowledge-readable-kb.test.ts +42 -10
  220. package/src/server/serverFns/__tests__/knowledge-search.test.ts +45 -9
  221. package/src/server/serverFns/__tests__/legal-code-canonical.test.ts +36 -2
  222. package/src/server/serverFns/__tests__/link-preview.test.ts +38 -4
  223. package/src/server/serverFns/__tests__/notifications-list.test.ts +36 -3
  224. package/src/server/serverFns/__tests__/ownership-merge.test.ts +38 -4
  225. package/src/server/serverFns/__tests__/project-delete-transaction.test.ts +39 -2
  226. package/src/server/serverFns/__tests__/project-kb.test.ts +34 -1
  227. package/src/server/serverFns/__tests__/project-member-idor.test.ts +34 -1
  228. package/src/server/serverFns/__tests__/project-team-assign.test.ts +34 -1
  229. package/src/server/serverFns/__tests__/read-write-merge.test.ts +38 -4
  230. package/src/server/serverFns/__tests__/story-comments.test.ts +38 -4
  231. package/src/server/serverFns/__tests__/story-crud-archive-detail.test.ts +38 -4
  232. package/src/server/serverFns/__tests__/story-crud-labels-users.test.ts +37 -3
  233. package/src/server/serverFns/__tests__/story-crud.test.ts +36 -3
  234. package/src/server/serverFns/__tests__/story-links.test.ts +38 -4
  235. package/src/server/serverFns/__tests__/story-reactions.test.ts +38 -4
  236. package/src/server/serverFns/__tests__/story-tree.test.ts +38 -4
  237. package/src/server/serverFns/__tests__/team-accept.test.ts +34 -1
  238. package/src/server/serverFns/__tests__/team-invitation.test.ts +34 -1
  239. package/src/server/serverFns/__tests__/team-join-request.test.ts +34 -1
  240. package/src/server/serverFns/__tests__/team-members.test.ts +34 -1
  241. package/src/server/serverFns/__tests__/team-ownership-merge.test.ts +34 -1
  242. package/src/server/serverFns/__tests__/update-bug-guard.test.ts +37 -3
  243. package/src/server/serverFns/__tests__/update-document-guard.test.ts +38 -4
  244. package/src/server/serverFns/__tests__/update-page-guard.test.ts +40 -4
  245. package/src/server/serverFns/__tests__/update-seats.test.ts +33 -1
  246. package/src/server/serverFns/__tests__/update-story-guard.test.ts +36 -3
  247. package/src/server/serverFns/__tests__/update-testcase-guard.test.ts +37 -3
  248. package/src/server/serverFns/__tests__/workspace-kb-idor.test.ts +36 -2
  249. package/src/server/serverFns/__tests__/workspace-kb.test.ts +36 -2
  250. package/src/server/serverFns/__tests__/workspace.test.ts +34 -1
  251. package/src/server/serverFns/activity.ts +10 -14
  252. package/src/server/serverFns/agents/agent-crud.ts +16 -15
  253. package/src/server/serverFns/agents/bindings.ts +12 -13
  254. package/src/server/serverFns/agents/skill-crud.ts +16 -15
  255. package/src/server/serverFns/ai/code-mode-readiness.ts +3 -4
  256. package/src/server/serverFns/ai/search-capability.ts +3 -4
  257. package/src/server/serverFns/anyhub/app.ts +10 -14
  258. package/src/server/serverFns/anyhub/index.ts +7 -10
  259. package/src/server/serverFns/anyhub/install.ts +4 -4
  260. package/src/server/serverFns/anyhub/permissions.ts +10 -14
  261. package/src/server/serverFns/anyhub/proxy.ts +4 -6
  262. package/src/server/serverFns/auth/email-verification.ts +4 -5
  263. package/src/server/serverFns/auth/session.ts +9 -0
  264. package/src/server/serverFns/billing.ts +18 -28
  265. package/src/server/serverFns/blob-upload.ts +6 -9
  266. package/src/server/serverFns/bug/__tests__/bug-access-tokens.test.ts +34 -1
  267. package/src/server/serverFns/bug/__tests__/bug-activities.test.ts +34 -1
  268. package/src/server/serverFns/bug/__tests__/bug-comments.test.ts +34 -1
  269. package/src/server/serverFns/bug/__tests__/bug-crud.test.ts +34 -1
  270. package/src/server/serverFns/bug/__tests__/bug-fix.test.ts +34 -1
  271. package/src/server/serverFns/bug/__tests__/bug-groups.test.ts +34 -1
  272. package/src/server/serverFns/bug/__tests__/bug-reactions.test.ts +34 -1
  273. package/src/server/serverFns/bug/__tests__/bug-reorder.test.ts +39 -5
  274. package/src/server/serverFns/bug/__tests__/bug-repro.test.ts +34 -1
  275. package/src/server/serverFns/bug/__tests__/bug-story.test.ts +34 -1
  276. package/src/server/serverFns/bug/__tests__/bug-webhooks.test.ts +34 -1
  277. package/src/server/serverFns/bug/bug-access-tokens.ts +16 -22
  278. package/src/server/serverFns/bug/bug-activities.ts +4 -6
  279. package/src/server/serverFns/bug/bug-collect-tokens.ts +13 -18
  280. package/src/server/serverFns/bug/bug-comments.ts +13 -18
  281. package/src/server/serverFns/bug/bug-crud/detail.ts +10 -14
  282. package/src/server/serverFns/bug/bug-crud.ts +28 -38
  283. package/src/server/serverFns/bug/bug-display-options.ts +8 -11
  284. package/src/server/serverFns/bug/bug-export.ts +5 -7
  285. package/src/server/serverFns/bug/bug-fix.ts +10 -14
  286. package/src/server/serverFns/bug/bug-groups.ts +10 -14
  287. package/src/server/serverFns/bug/bug-reactions.ts +10 -14
  288. package/src/server/serverFns/bug/bug-reorder.ts +4 -6
  289. package/src/server/serverFns/bug/bug-repro.ts +8 -11
  290. package/src/server/serverFns/bug/bug-story-bulk.ts +13 -18
  291. package/src/server/serverFns/bug/bug-story.ts +10 -14
  292. package/src/server/serverFns/bug/bug-views.ts +12 -18
  293. package/src/server/serverFns/bug/bug-webhooks.ts +13 -18
  294. package/src/server/serverFns/bug/test-bug-confirm.ts +7 -10
  295. package/src/server/serverFns/changelog/__tests__/fetch.test.ts +40 -1
  296. package/src/server/serverFns/changelog/fetch.ts +4 -6
  297. package/src/server/serverFns/chat/conversations.ts +17 -28
  298. package/src/server/serverFns/chat/list-messages.ts +4 -7
  299. package/src/server/serverFns/collab-presence.ts +11 -13
  300. package/src/server/serverFns/collab-snapshot.ts +6 -7
  301. package/src/server/serverFns/collab.ts +7 -7
  302. package/src/server/serverFns/compliance.ts +8 -8
  303. package/src/server/serverFns/design/__tests__/comments.test.ts +54 -10
  304. package/src/server/serverFns/design/__tests__/designs.test.ts +39 -16
  305. package/src/server/serverFns/design/__tests__/page-versions.test.ts +52 -14
  306. package/src/server/serverFns/design/__tests__/shares-password.test.ts +44 -14
  307. package/src/server/serverFns/design/__tests__/shares.test.ts +44 -14
  308. package/src/server/serverFns/design/__tests__/versions.test.ts +44 -14
  309. package/src/server/serverFns/design/ai/__tests__/agent-conversations.test.ts +50 -21
  310. package/src/server/serverFns/design/ai/__tests__/providers.test.ts +42 -8
  311. package/src/server/serverFns/design/ai/agent-conversations.ts +19 -26
  312. package/src/server/serverFns/design/ai/fill-annotation.ts +5 -7
  313. package/src/server/serverFns/design/ai/generate-prototype.ts +5 -7
  314. package/src/server/serverFns/design/ai/hosted-models.ts +4 -5
  315. package/src/server/serverFns/design/ai/providers.ts +30 -39
  316. package/src/server/serverFns/design/ai/source-mode.ts +10 -12
  317. package/src/server/serverFns/design/comments.ts +14 -13
  318. package/src/server/serverFns/design/designs.ts +13 -19
  319. package/src/server/serverFns/design/page-versions.ts +17 -18
  320. package/src/server/serverFns/design/pages.ts +17 -18
  321. package/src/server/serverFns/design/reviews.ts +8 -9
  322. package/src/server/serverFns/design/shares-password.ts +13 -19
  323. package/src/server/serverFns/design/shares.ts +22 -31
  324. package/src/server/serverFns/design/versions.ts +8 -9
  325. package/src/server/serverFns/harness/__tests__/attach-prototype.spec.ts +52 -2
  326. package/src/server/serverFns/harness/__tests__/attach-to-kb.spec.ts +52 -2
  327. package/src/server/serverFns/harness/__tests__/attach-to-story-ssrf.spec.ts +52 -2
  328. package/src/server/serverFns/harness/__tests__/attach-to-story.spec.ts +52 -2
  329. package/src/server/serverFns/harness/__tests__/cancel-run.test.ts +40 -15
  330. package/src/server/serverFns/harness/__tests__/extract-attachment.spec.ts +52 -2
  331. package/src/server/serverFns/harness/__tests__/gallery.spec.ts +76 -12
  332. package/src/server/serverFns/harness/__tests__/github-workspace.spec.ts +38 -6
  333. package/src/server/serverFns/harness/__tests__/media-prototype.spec.ts +50 -6
  334. package/src/server/serverFns/harness/__tests__/media.spec.ts +55 -11
  335. package/src/server/serverFns/harness/__tests__/sandbox-policy.test.ts +41 -16
  336. package/src/server/serverFns/harness/__tests__/workspace-files.test.ts +41 -16
  337. package/src/server/serverFns/harness/attach-prototype.ts +4 -4
  338. package/src/server/serverFns/harness/attach-to-kb.ts +4 -4
  339. package/src/server/serverFns/harness/attach-to-story.ts +4 -4
  340. package/src/server/serverFns/harness/cancel-run.ts +4 -6
  341. package/src/server/serverFns/harness/extract-attachment.ts +3 -4
  342. package/src/server/serverFns/harness/gallery.ts +19 -23
  343. package/src/server/serverFns/harness/github-workspace.ts +14 -21
  344. package/src/server/serverFns/harness/media.ts +18 -117
  345. package/src/server/serverFns/harness/sandbox-policy.ts +11 -10
  346. package/src/server/serverFns/harness/search-mention-candidates.ts +4 -6
  347. package/src/server/serverFns/harness/workspace-files.ts +19 -26
  348. package/src/server/serverFns/iteration/__tests__/iteration-auto-schedule.test.ts +35 -3
  349. package/src/server/serverFns/iteration/__tests__/iteration-crud.test.ts +35 -3
  350. package/src/server/serverFns/iteration/__tests__/iteration-stories.test.ts +35 -3
  351. package/src/server/serverFns/iteration/__tests__/iteration-transfer.test.ts +35 -3
  352. package/src/server/serverFns/iteration/iteration-auto-schedule.ts +7 -10
  353. package/src/server/serverFns/iteration/iteration-burndown.ts +4 -6
  354. package/src/server/serverFns/iteration/iteration-crud.ts +26 -35
  355. package/src/server/serverFns/iteration/iteration-stories.ts +10 -14
  356. package/src/server/serverFns/iteration/iteration-transfer.ts +4 -6
  357. package/src/server/serverFns/knowledge/public/bookmarks/categories.ts +11 -15
  358. package/src/server/serverFns/knowledge/public/bookmarks/create.ts +4 -6
  359. package/src/server/serverFns/knowledge/public/bookmarks/delete.ts +5 -7
  360. package/src/server/serverFns/knowledge/public/bookmarks/detail.ts +4 -6
  361. package/src/server/serverFns/knowledge/public/bookmarks/favorite.ts +4 -6
  362. package/src/server/serverFns/knowledge/public/bookmarks/list.ts +4 -6
  363. package/src/server/serverFns/knowledge/public/bookmarks/refresh-favicon.ts +4 -6
  364. package/src/server/serverFns/knowledge/public/bookmarks/share.ts +4 -6
  365. package/src/server/serverFns/knowledge/public/bookmarks/sync-github.ts +5 -7
  366. package/src/server/serverFns/knowledge/public/bookmarks/unshare.ts +4 -6
  367. package/src/server/serverFns/knowledge/public/bookmarks/update.ts +6 -8
  368. package/src/server/serverFns/knowledge/public/compliance/create.ts +4 -6
  369. package/src/server/serverFns/knowledge/public/compliance/delete.ts +5 -7
  370. package/src/server/serverFns/knowledge/public/compliance/detail.ts +4 -6
  371. package/src/server/serverFns/knowledge/public/compliance/list.ts +4 -6
  372. package/src/server/serverFns/knowledge/public/compliance/share.ts +4 -6
  373. package/src/server/serverFns/knowledge/public/compliance/unshare.ts +4 -6
  374. package/src/server/serverFns/knowledge/public/compliance/update.ts +5 -7
  375. package/src/server/serverFns/knowledge/public/dictionary/create.ts +4 -6
  376. package/src/server/serverFns/knowledge/public/dictionary/delete.ts +5 -7
  377. package/src/server/serverFns/knowledge/public/dictionary/detail.ts +4 -6
  378. package/src/server/serverFns/knowledge/public/dictionary/list.ts +4 -6
  379. package/src/server/serverFns/knowledge/public/dictionary/share.ts +4 -6
  380. package/src/server/serverFns/knowledge/public/dictionary/unshare.ts +4 -6
  381. package/src/server/serverFns/knowledge/public/dictionary/update.ts +5 -7
  382. package/src/server/serverFns/knowledge/public/entity-tags.ts +4 -6
  383. package/src/server/serverFns/knowledge/public/favorite.ts +7 -10
  384. package/src/server/serverFns/knowledge/public/legal/create.ts +4 -6
  385. package/src/server/serverFns/knowledge/public/legal/delete.ts +5 -7
  386. package/src/server/serverFns/knowledge/public/legal/detail.ts +4 -6
  387. package/src/server/serverFns/knowledge/public/legal/list.ts +4 -6
  388. package/src/server/serverFns/knowledge/public/legal/share.ts +4 -6
  389. package/src/server/serverFns/knowledge/public/legal/unshare.ts +4 -6
  390. package/src/server/serverFns/knowledge/public/legal/update.ts +5 -7
  391. package/src/server/serverFns/knowledge-index.ts +12 -16
  392. package/src/server/serverFns/knowledge.ts +50 -67
  393. package/src/server/serverFns/notifications.ts +25 -34
  394. package/src/server/serverFns/plugins/harness-plugins.ts +16 -23
  395. package/src/server/serverFns/project/module-overview.ts +7 -10
  396. package/src/server/serverFns/project.ts +48 -68
  397. package/src/server/serverFns/references/create.ts +4 -6
  398. package/src/server/serverFns/references/resolve.ts +4 -6
  399. package/src/server/serverFns/references/search.ts +4 -6
  400. package/src/server/serverFns/share/design/[designId]/events.ts +4 -6
  401. package/src/server/serverFns/sso.ts +1 -1
  402. package/src/server/serverFns/story/__tests__/bulk.test.ts +34 -1
  403. package/src/server/serverFns/story/__tests__/story-assoc.test.ts +34 -1
  404. package/src/server/serverFns/story/__tests__/story-attachments.test.ts +34 -1
  405. package/src/server/serverFns/story/__tests__/story-crud-date-key.test.ts +42 -17
  406. package/src/server/serverFns/story/__tests__/story-dependencies.test.ts +34 -1
  407. package/src/server/serverFns/story/__tests__/story-gantt-deps.test.ts +34 -1
  408. package/src/server/serverFns/story/__tests__/story-groups.test.ts +34 -1
  409. package/src/server/serverFns/story/__tests__/story-read-path-authz.test.ts +40 -4
  410. package/src/server/serverFns/story/__tests__/story-search.test.ts +34 -1
  411. package/src/server/serverFns/story/__tests__/story-transfer.test.ts +34 -1
  412. package/src/server/serverFns/story/link-preview.ts +5 -7
  413. package/src/server/serverFns/story/story-assoc.ts +28 -38
  414. package/src/server/serverFns/story/story-attachments.ts +7 -10
  415. package/src/server/serverFns/story/story-children.ts +4 -6
  416. package/src/server/serverFns/story/story-comments.ts +13 -18
  417. package/src/server/serverFns/story/story-crud/activities.ts +4 -6
  418. package/src/server/serverFns/story/story-crud/archive.ts +7 -10
  419. package/src/server/serverFns/story/story-crud/bulk.ts +10 -14
  420. package/src/server/serverFns/story/story-crud/detail.ts +7 -10
  421. package/src/server/serverFns/story/story-crud/label-suggest.ts +4 -6
  422. package/src/server/serverFns/story/story-crud/labels.ts +6 -9
  423. package/src/server/serverFns/story/story-crud/user-brief.ts +4 -6
  424. package/src/server/serverFns/story/story-crud.ts +13 -18
  425. package/src/server/serverFns/story/story-dependencies.ts +16 -22
  426. package/src/server/serverFns/story/story-groups.ts +10 -14
  427. package/src/server/serverFns/story/story-links.ts +13 -18
  428. package/src/server/serverFns/story/story-reactions.ts +13 -18
  429. package/src/server/serverFns/story/story-search.ts +7 -10
  430. package/src/server/serverFns/story/story-transfer.ts +10 -14
  431. package/src/server/serverFns/story/story-tree.ts +7 -10
  432. package/src/server/serverFns/story-display-options.ts +7 -8
  433. package/src/server/serverFns/story-view.ts +12 -18
  434. package/src/server/serverFns/tasks/task-crud.ts +13 -17
  435. package/src/server/serverFns/tasks/task-queries.ts +12 -18
  436. package/src/server/serverFns/team.ts +46 -66
  437. package/src/server/serverFns/testcase/__tests__/automation.test.ts +38 -5
  438. package/src/server/serverFns/testcase/__tests__/evidence-upload.test.ts +37 -3
  439. package/src/server/serverFns/testcase/__tests__/generation.test.ts +38 -5
  440. package/src/server/serverFns/testcase/__tests__/plans.test.ts +36 -3
  441. package/src/server/serverFns/testcase/__tests__/regression.test.ts +36 -3
  442. package/src/server/serverFns/testcase/__tests__/run-cases.test.ts +36 -3
  443. package/src/server/serverFns/testcase/__tests__/runs.test.ts +36 -3
  444. package/src/server/serverFns/testcase/__tests__/stats.test.ts +36 -3
  445. package/src/server/serverFns/testcase/__tests__/testcase-board.test.ts +39 -5
  446. package/src/server/serverFns/testcase/__tests__/testcase-crud.test.ts +36 -3
  447. package/src/server/serverFns/testcase/__tests__/testcase-folders.test.ts +36 -3
  448. package/src/server/serverFns/testcase/__tests__/testcase-groups.test.ts +38 -5
  449. package/src/server/serverFns/testcase/automation.ts +13 -17
  450. package/src/server/serverFns/testcase/bulk.ts +10 -14
  451. package/src/server/serverFns/testcase/evidence-upload.ts +5 -7
  452. package/src/server/serverFns/testcase/generation.ts +10 -13
  453. package/src/server/serverFns/testcase/plans.ts +23 -31
  454. package/src/server/serverFns/testcase/regression.ts +7 -10
  455. package/src/server/serverFns/testcase/run-cases.ts +13 -18
  456. package/src/server/serverFns/testcase/runs.ts +13 -18
  457. package/src/server/serverFns/testcase/stats.ts +13 -18
  458. package/src/server/serverFns/testcase/testcase-activities.ts +4 -6
  459. package/src/server/serverFns/testcase/testcase-board.ts +4 -6
  460. package/src/server/serverFns/testcase/testcase-crud.ts +20 -27
  461. package/src/server/serverFns/testcase/testcase-display-options.ts +8 -11
  462. package/src/server/serverFns/testcase/testcase-export.ts +5 -7
  463. package/src/server/serverFns/testcase/testcase-filter-views.ts +12 -18
  464. package/src/server/serverFns/testcase/testcase-folders.ts +16 -22
  465. package/src/server/serverFns/testcase/testcase-groups.ts +4 -6
  466. package/src/server/serverFns/testcase/testcase-reorder.ts +4 -6
  467. package/src/server/serverFns/translation.ts +4 -6
  468. package/src/server/serverFns/user/avatar.ts +4 -6
  469. package/src/server/serverFns/user/settings.ts +4 -6
  470. package/src/server/serverFns/user/update-locale.ts +4 -6
  471. package/src/server/serverFns/workspace-kb.ts +26 -35
  472. package/src/server/serverFns/workspace.ts +43 -59
  473. package/src/server/serverFns/ws.ts +4 -6
  474. package/src/server/serverfn-public-allowlist.ts +117 -0
  475. package/src/server/story/types.ts +0 -1
  476. package/src/server/sync/__tests__/scopes.test.ts +64 -0
  477. package/src/server/sync/scopes.ts +7 -0
  478. package/src/server/testcase/__tests__/auto-bug.test.ts +44 -12
  479. package/src/__tests__/bench/baselines/format-timestamp.json +0 -44
  480. package/src/__typeprobe__.d.ts +0 -4
  481. package/src/components/forms/app-form-dialog.tsx +0 -126
  482. package/src/components/forms/hooks/use-form-submit.ts +0 -57
  483. package/src/components/forms/types.ts +0 -34
  484. package/src/components/harness/code/workspace-picker.tsx +0 -239
  485. package/src/components/tiptap/extensions/local-file/insert-local-file.ts +0 -35
  486. package/src/components/tiptap/extensions/local-file/local-file-node.ts +0 -71
  487. package/src/devframe-docks/ai-chat-iframe.tsx +0 -29
  488. package/src/devframe-docks/session-iframe.tsx +0 -90
  489. package/src/lib/__tests__/desktop-detect.test.ts +0 -19
  490. package/src/lib/collections/index.ts +0 -22
  491. package/src/lib/collections/knowledge/index.ts +0 -18
  492. package/src/lib/collections/knowledge/knowledge-bases-collection.ts +0 -34
  493. package/src/lib/collections/reference/bookmark-categories-collection.ts +0 -31
  494. package/src/lib/collections/reference/labels-collection.ts +0 -31
  495. package/src/lib/collections/reference/projects-collection.ts +0 -31
  496. package/src/lib/collections/reference/users-brief-collection.ts +0 -35
  497. package/src/lib/collections/reference/workspaces-collection.ts +0 -34
  498. package/src/lib/desktop-detect.ts +0 -29
  499. package/src/paraglide/messages/en.js +0 -28260
  500. package/src/paraglide/messages/zh.js +0 -28258
@@ -98,6 +98,7 @@ import { Route as ApiCronAiRunReaperRouteImport } from './routes/api/cron/ai-run
98
98
  import { Route as ApiCronChangelogReleaseRouteImport } from './routes/api/cron/changelog-release'
99
99
  import { Route as ApiCronSubscriptionRemindersRouteImport } from './routes/api/cron/subscription-reminders'
100
100
  import { Route as ApiDesignPrototypeRouteRouteImport } from './routes/api/design/prototype/route'
101
+ import { Route as ApiGenerateMediaRouteImport } from './routes/api/generate/media'
101
102
  import { Route as ApiInternalCollabReindexRouteImport } from './routes/api/internal/collab-reindex'
102
103
  import { Route as ApiKnowledgeSyncGithubRouteImport } from './routes/api/knowledge/sync-github'
103
104
  import { Route as ApiLicenseActivateRouteRouteImport } from './routes/api/license/activate/route'
@@ -713,6 +714,11 @@ const ApiDesignPrototypeRouteRoute = ApiDesignPrototypeRouteRouteImport.update({
713
714
  path: '/api/design/prototype',
714
715
  getParentRoute: () => rootRouteImport,
715
716
  } as any)
717
+ const ApiGenerateMediaRoute = ApiGenerateMediaRouteImport.update({
718
+ id: '/api/generate/media',
719
+ path: '/api/generate/media',
720
+ getParentRoute: () => rootRouteImport,
721
+ } as any)
716
722
  const ApiInternalCollabReindexRoute =
717
723
  ApiInternalCollabReindexRouteImport.update({
718
724
  id: '/api/internal/collab-reindex',
@@ -1183,6 +1189,7 @@ export interface FileRoutesByFullPath {
1183
1189
  '/api/cron/ai-run-reaper': typeof ApiCronAiRunReaperRoute
1184
1190
  '/api/cron/changelog-release': typeof ApiCronChangelogReleaseRoute
1185
1191
  '/api/cron/subscription-reminders': typeof ApiCronSubscriptionRemindersRoute
1192
+ '/api/generate/media': typeof ApiGenerateMediaRoute
1186
1193
  '/api/internal/collab-reindex': typeof ApiInternalCollabReindexRoute
1187
1194
  '/api/knowledge/sync-github': typeof ApiKnowledgeSyncGithubRoute
1188
1195
  '/api/mcp/bugs': typeof ApiMcpBugsRoute
@@ -1305,6 +1312,7 @@ export interface FileRoutesByTo {
1305
1312
  '/api/cron/ai-run-reaper': typeof ApiCronAiRunReaperRoute
1306
1313
  '/api/cron/changelog-release': typeof ApiCronChangelogReleaseRoute
1307
1314
  '/api/cron/subscription-reminders': typeof ApiCronSubscriptionRemindersRoute
1315
+ '/api/generate/media': typeof ApiGenerateMediaRoute
1308
1316
  '/api/internal/collab-reindex': typeof ApiInternalCollabReindexRoute
1309
1317
  '/api/knowledge/sync-github': typeof ApiKnowledgeSyncGithubRoute
1310
1318
  '/api/mcp/bugs': typeof ApiMcpBugsRoute
@@ -1446,6 +1454,7 @@ export interface FileRoutesById {
1446
1454
  '/api/cron/ai-run-reaper': typeof ApiCronAiRunReaperRoute
1447
1455
  '/api/cron/changelog-release': typeof ApiCronChangelogReleaseRoute
1448
1456
  '/api/cron/subscription-reminders': typeof ApiCronSubscriptionRemindersRoute
1457
+ '/api/generate/media': typeof ApiGenerateMediaRoute
1449
1458
  '/api/internal/collab-reindex': typeof ApiInternalCollabReindexRoute
1450
1459
  '/api/knowledge/sync-github': typeof ApiKnowledgeSyncGithubRoute
1451
1460
  '/api/mcp/bugs': typeof ApiMcpBugsRoute
@@ -1585,6 +1594,7 @@ export interface FileRouteTypes {
1585
1594
  | '/api/cron/ai-run-reaper'
1586
1595
  | '/api/cron/changelog-release'
1587
1596
  | '/api/cron/subscription-reminders'
1597
+ | '/api/generate/media'
1588
1598
  | '/api/internal/collab-reindex'
1589
1599
  | '/api/knowledge/sync-github'
1590
1600
  | '/api/mcp/bugs'
@@ -1707,6 +1717,7 @@ export interface FileRouteTypes {
1707
1717
  | '/api/cron/ai-run-reaper'
1708
1718
  | '/api/cron/changelog-release'
1709
1719
  | '/api/cron/subscription-reminders'
1720
+ | '/api/generate/media'
1710
1721
  | '/api/internal/collab-reindex'
1711
1722
  | '/api/knowledge/sync-github'
1712
1723
  | '/api/mcp/bugs'
@@ -1847,6 +1858,7 @@ export interface FileRouteTypes {
1847
1858
  | '/api/cron/ai-run-reaper'
1848
1859
  | '/api/cron/changelog-release'
1849
1860
  | '/api/cron/subscription-reminders'
1861
+ | '/api/generate/media'
1850
1862
  | '/api/internal/collab-reindex'
1851
1863
  | '/api/knowledge/sync-github'
1852
1864
  | '/api/mcp/bugs'
@@ -1932,6 +1944,7 @@ export interface RootRouteChildren {
1932
1944
  ApiCronAiRunReaperRoute: typeof ApiCronAiRunReaperRoute
1933
1945
  ApiCronChangelogReleaseRoute: typeof ApiCronChangelogReleaseRoute
1934
1946
  ApiCronSubscriptionRemindersRoute: typeof ApiCronSubscriptionRemindersRoute
1947
+ ApiGenerateMediaRoute: typeof ApiGenerateMediaRoute
1935
1948
  ApiInternalCollabReindexRoute: typeof ApiInternalCollabReindexRoute
1936
1949
  ApiKnowledgeSyncGithubRoute: typeof ApiKnowledgeSyncGithubRoute
1937
1950
  ApiMcpBugsRoute: typeof ApiMcpBugsRoute
@@ -2558,6 +2571,13 @@ declare module '@tanstack/react-router' {
2558
2571
  preLoaderRoute: typeof ApiDesignPrototypeRouteRouteImport
2559
2572
  parentRoute: typeof rootRouteImport
2560
2573
  }
2574
+ '/api/generate/media': {
2575
+ id: '/api/generate/media'
2576
+ path: '/api/generate/media'
2577
+ fullPath: '/api/generate/media'
2578
+ preLoaderRoute: typeof ApiGenerateMediaRouteImport
2579
+ parentRoute: typeof rootRouteImport
2580
+ }
2561
2581
  '/api/internal/collab-reindex': {
2562
2582
  id: '/api/internal/collab-reindex'
2563
2583
  path: '/api/internal/collab-reindex'
@@ -3420,6 +3440,7 @@ const rootRouteChildren: RootRouteChildren = {
3420
3440
  ApiCronAiRunReaperRoute: ApiCronAiRunReaperRoute,
3421
3441
  ApiCronChangelogReleaseRoute: ApiCronChangelogReleaseRoute,
3422
3442
  ApiCronSubscriptionRemindersRoute: ApiCronSubscriptionRemindersRoute,
3443
+ ApiGenerateMediaRoute: ApiGenerateMediaRoute,
3423
3444
  ApiInternalCollabReindexRoute: ApiInternalCollabReindexRoute,
3424
3445
  ApiKnowledgeSyncGithubRoute: ApiKnowledgeSyncGithubRoute,
3425
3446
  ApiMcpBugsRoute: ApiMcpBugsRoute,
package/src/router.tsx CHANGED
@@ -17,8 +17,12 @@
17
17
 
18
18
  import { createRouter as createTanstackRouter } from '@tanstack/react-router'
19
19
  import { setupRouterSsrQueryIntegration } from '@tanstack/react-router-ssr-query'
20
- import { MutationCache, QueryClient } from '@tanstack/react-query'
21
- import { navigateToLoginOnUnauthorized } from '@/lib/auth/anonymous-safe'
20
+ import { MutationCache, QueryCache, QueryClient } from '@tanstack/react-query'
21
+ import {
22
+ handleGlobalMutationError,
23
+ handleGlobalQueryError,
24
+ } from '@/lib/query-global-error'
25
+ import { QUERY_STALE_TIME_MS } from '@/lib/query-defaults'
22
26
  import { setQueryClient } from '@/lib/query-client-seam'
23
27
  import { Loader2 } from 'lucide-react'
24
28
  import { routeTree } from './routeTree.gen'
@@ -38,16 +42,25 @@ function DefaultPendingComponent() {
38
42
  }
39
43
 
40
44
  export function getRouter() {
41
- // MutationCache 必须在 QueryClient 构造期注入(该版本 MutationCache 实例无 onError 方法);
42
- // onError 闭包引用下方才声明的 router——onError 只在 mutation 报错时触发,
43
- // 必然晚于 getRouter 返回,运行时不会读到未初始化的 router
45
+ // QueryCache/MutationCache 必须在 QueryClient 构造期注入(该版本 Cache 实例无 onError 方法);
46
+ // onError 闭包引用下方才声明的 router——onError 只在 query/mutation 报错时触发,
47
+ // 必然晚于 getRouter 返回,运行时不会读到未初始化的 router。
48
+ // 全局兜底(401 跳登录 / 分级 toast / suppressGlobalToast meta 约定 / SSR 守卫)
49
+ // 见 @/lib/query-global-error
44
50
  const queryClient = new QueryClient({
45
51
  defaultOptions: {
46
- queries: { staleTime: 60 * 1000, refetchOnWindowFocus: false },
52
+ // 全局 staleTime 30s(见 @/lib/query-defaults 注释:纯导航窗口内命中缓存、
53
+ // invalidate 协同不阻断)
54
+ queries: { staleTime: QUERY_STALE_TIME_MS, refetchOnWindowFocus: false },
47
55
  },
56
+ queryCache: new QueryCache({
57
+ onError: (error, query) => {
58
+ handleGlobalQueryError(error, query, router)
59
+ },
60
+ }),
48
61
  mutationCache: new MutationCache({
49
- onError: (error) => {
50
- navigateToLoginOnUnauthorized(error, router)
62
+ onError: (error, _variables, _onMutateResult, mutation) => {
63
+ handleGlobalMutationError(error, mutation, router)
51
64
  },
52
65
  }),
53
66
  })
@@ -18,6 +18,7 @@
18
18
  import { Link, Outlet, createRootRouteWithContext, HeadContent, Scripts, useParams } from '@tanstack/react-router'
19
19
  import { useEffect } from 'react'
20
20
  import { HotkeysProvider } from '@tanstack/react-hotkeys'
21
+ import { appHotkeys } from '@/lib/hotkeys/registry'
21
22
  import { ShortcutsPanel } from '@/components/hotkeys/shortcuts-panel'
22
23
  import { Analytics } from '@vercel/analytics/react'
23
24
  import { SpeedInsights } from '@vercel/speed-insights/react'
@@ -89,7 +90,7 @@ function RootComponent() {
89
90
  <body className="w-full h-full min-h-screen antialiased">
90
91
  <Providers session={session}>
91
92
  <RootProvider i18n={i18nProvider(translations, lang)} search={{ preload: false }}>
92
- <HotkeysProvider>
93
+ <HotkeysProvider appHotkeys={appHotkeys}>
93
94
  <Outlet />
94
95
  <ShortcutsPanel />
95
96
  <Toaster />
@@ -18,7 +18,12 @@ async function importIndexRoute(profileId: 'oss' | 'saas', desktop = false) {
18
18
  async function importNavRoute(opts: { profileId: 'oss' | 'saas'; desktop: boolean }) {
19
19
  vi.resetModules()
20
20
  vi.doMock('@/plugins/modules.gen', () => ({ profileId: opts.profileId }))
21
- vi.doMock('@/server/desktop-guest', () => ({ isDesktopServer: () => opts.desktop }))
21
+ // 部分 mock:保留真实 GUEST_USER_ID 等导出——source-mode 键隔离引入了
22
+ // GUEST_USER_ID 消费(经 unified-router 拉起),整体替换会断其模块初始化。
23
+ vi.doMock('@/server/desktop-guest', async (importOriginal) => {
24
+ const actual = await importOriginal<typeof import('@/server/desktop-guest')>()
25
+ return { ...actual, isDesktopServer: () => opts.desktop }
26
+ })
22
27
  return import('../_nav/route')
23
28
  }
24
29
 
@@ -16,10 +16,9 @@
16
16
  // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
 
18
18
  import { createLazyFileRoute, Link } from '@tanstack/react-router'
19
- import { useForm } from '@tanstack/react-form'
20
19
  import { toast } from '@/components/ui/toast'
21
20
  import { RainbowButton } from '@/components/magicui/rainbow-button'
22
- import { AppField } from '@/components/forms'
21
+ import { useAppForm, firstFieldErrorMessage } from '@/components/forms'
23
22
  import { ArrowRight, Mail } from 'lucide-react'
24
23
  import { AuthLayout, AuthLayoutLeft, AuthLayoutRight } from '@/components/auth/auth-layout'
25
24
  import { AuthHeader } from '@/components/auth/auth-header'
@@ -38,7 +37,7 @@ export const Route = createLazyFileRoute('/_login/forgot-password')({
38
37
  function ForgotPasswordPage() {
39
38
  const loginFeatures = buildAuthFeatures()
40
39
 
41
- const form = useForm({
40
+ const form = useAppForm({
42
41
  defaultValues: { email: '' },
43
42
  validators: [{ run: forgotPasswordSchema, triggers: ['change'] }],
44
43
  onSubmit: async ({ value }) => {
@@ -55,11 +54,12 @@ function ForgotPasswordPage() {
55
54
  <AuthLayout>
56
55
  <AuthLayoutLeft>
57
56
  <AuthHeader title={m.auth_forgotPassword_title()} subtitle={m.auth_forgotPassword_subtitle()} />
57
+ <form.AppForm>
58
58
  <form
59
59
  onSubmit={(e) => { e.preventDefault(); e.stopPropagation(); form.handleSubmit() }}
60
60
  className="space-y-6"
61
61
  >
62
- <AppField name="email" form={form} renderError={false}>
62
+ <form.AppField name="email" renderError={false}>
63
63
  {(field) => (
64
64
  <IconInput
65
65
  icon={Mail}
@@ -68,10 +68,10 @@ function ForgotPasswordPage() {
68
68
  value={field.value}
69
69
  onBlur={field.handleBlur}
70
70
  onChange={(e) => field.handleChange(e.target.value)}
71
- error={field.meta.isTouched && field.errors.length > 0 ? (field.errors.map((e) => e.message).filter(Boolean)[0] as string | undefined) : undefined}
71
+ error={firstFieldErrorMessage(field)}
72
72
  />
73
73
  )}
74
- </AppField>
74
+ </form.AppField>
75
75
  <form.Subscribe
76
76
  selector={(state) => state.isSubmitting}
77
77
  children={(isSubmitting) => (
@@ -82,6 +82,7 @@ function ForgotPasswordPage() {
82
82
  )}
83
83
  />
84
84
  </form>
85
+ </form.AppForm>
85
86
  <div className="text-center text-sm">
86
87
  {m.auth_forgotPassword_remembered()}{' '}
87
88
  <Link to="/login" className="font-medium text-primary hover:underline">{m.auth_forgotPassword_goLogin()}</Link>
@@ -17,13 +17,12 @@
17
17
 
18
18
  import { useEffect } from 'react'
19
19
  import { createLazyFileRoute, Link } from '@tanstack/react-router'
20
- import { useForm } from '@tanstack/react-form'
21
20
  import { toast } from '@/components/ui/toast'
22
21
  import { RainbowButton } from '@/components/magicui/rainbow-button'
23
22
  import { Checkbox } from '@/components/ui/checkbox'
24
23
  import { Field, FieldLabel } from '@/components/ui/field'
25
24
  import { Separator } from '@/components/ui/separator'
26
- import { AppField } from '@/components/forms'
25
+ import { useAppForm, firstFieldErrorMessage } from '@/components/forms'
27
26
  import { ArrowRight, Mail } from 'lucide-react'
28
27
  import { AuthLayout, AuthLayoutLeft, AuthLayoutRight } from '@/components/auth/auth-layout'
29
28
  import { AuthHeader } from '@/components/auth/auth-header'
@@ -71,7 +70,7 @@ function LoginPage() {
71
70
  void submitSsoLogin()
72
71
  }, [ssoToken, redirectTo, ])
73
72
 
74
- const form = useForm({
73
+ const form = useAppForm({
75
74
  defaultValues: { email: '', password: '', remember: false },
76
75
  validators: [{ run: loginSchema, triggers: ['change'] }],
77
76
  onSubmit: async ({ value }) => {
@@ -106,11 +105,12 @@ function LoginPage() {
106
105
  </div>
107
106
  </>
108
107
  )}
108
+ <form.AppForm>
109
109
  <form
110
110
  onSubmit={(e) => { e.preventDefault(); e.stopPropagation(); form.handleSubmit() }}
111
111
  className="space-y-6"
112
112
  >
113
- <AppField name="email" form={form} renderError={false}>
113
+ <form.AppField name="email" renderError={false}>
114
114
  {(field) => (
115
115
  <IconInput
116
116
  icon={Mail}
@@ -119,17 +119,17 @@ function LoginPage() {
119
119
  value={field.value}
120
120
  onBlur={field.handleBlur}
121
121
  onChange={(e) => field.handleChange(e.target.value)}
122
- error={field.meta.isTouched && field.errors.length > 0 ? (field.errors.map((e) => e.message).filter(Boolean)[0] as string | undefined) : undefined}
122
+ error={firstFieldErrorMessage(field)}
123
123
  />
124
124
  )}
125
- </AppField>
125
+ </form.AppField>
126
126
  <form.Subscribe
127
127
  selector={(state) => state.values.email}
128
128
  children={(email) => (
129
129
  <SsoSection email={email} />
130
130
  )}
131
131
  />
132
- <AppField name="password" form={form} renderError={false}>
132
+ <form.AppField name="password" renderError={false}>
133
133
  {(field) => (
134
134
  <PasswordInput
135
135
  label={m.auth_login_passwordLabel()}
@@ -137,10 +137,10 @@ function LoginPage() {
137
137
  value={field.value}
138
138
  onBlur={field.handleBlur}
139
139
  onChange={(e) => field.handleChange(e.target.value)}
140
- error={field.meta.isTouched && field.errors.length > 0 ? (field.errors.map((e) => e.message).filter(Boolean)[0] as string | undefined) : undefined}
140
+ error={firstFieldErrorMessage(field)}
141
141
  />
142
142
  )}
143
- </AppField>
143
+ </form.AppField>
144
144
  <div className="flex items-center justify-between gap-2">
145
145
  <Field orientation="horizontal" className="min-w-0">
146
146
  <FieldLabel>
@@ -170,6 +170,7 @@ function LoginPage() {
170
170
  )}
171
171
  />
172
172
  </form>
173
+ </form.AppForm>
173
174
  <div className="text-center text-sm">
174
175
  {m.auth_login_noAccount()}{' '}
175
176
  <Link to="/register" className="font-medium text-primary hover:underline">{m.auth_login_createAccount()}</Link>
@@ -16,11 +16,10 @@
16
16
  // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
 
18
18
  import { createLazyFileRoute, useRouter, Link } from '@tanstack/react-router'
19
- import { useForm } from '@tanstack/react-form'
20
19
  import { toast } from '@/components/ui/toast'
21
20
  import { RainbowButton } from '@/components/magicui/rainbow-button'
22
21
  import { Separator } from '@/components/ui/separator'
23
- import { AppField } from '@/components/forms'
22
+ import { useAppForm, firstFieldErrorMessage } from '@/components/forms'
24
23
  import { ArrowRight, Mail, User, QrCode } from 'lucide-react'
25
24
  import { AuthLayout, AuthLayoutLeft, AuthLayoutRight } from '@/components/auth/auth-layout'
26
25
  import { AuthHeader } from '@/components/auth/auth-header'
@@ -45,7 +44,7 @@ function RegisterPage() {
45
44
  const { invite, email: emailFromUrl } = Route.useSearch()
46
45
  const registerFeatures = buildAuthFeatures()
47
46
 
48
- const form = useForm({
47
+ const form = useAppForm({
49
48
  defaultValues: {
50
49
  username: '',
51
50
  email: emailFromUrl ?? '',
@@ -83,11 +82,12 @@ function RegisterPage() {
83
82
  </div>
84
83
  </>
85
84
  )}
85
+ <form.AppForm>
86
86
  <form
87
87
  onSubmit={(e) => { e.preventDefault(); e.stopPropagation(); form.handleSubmit() }}
88
88
  className="space-y-6"
89
89
  >
90
- <AppField name="username" form={form} renderError={false}>
90
+ <form.AppField name="username" renderError={false}>
91
91
  {(field) => (
92
92
  <IconInput
93
93
  icon={User}
@@ -96,11 +96,11 @@ function RegisterPage() {
96
96
  value={field.value}
97
97
  onBlur={field.handleBlur}
98
98
  onChange={(e) => field.handleChange(e.target.value)}
99
- error={field.meta.isTouched && field.errors.length > 0 ? (field.errors.map((e) => e.message).filter(Boolean)[0] as string | undefined) : undefined}
99
+ error={firstFieldErrorMessage(field)}
100
100
  />
101
101
  )}
102
- </AppField>
103
- <AppField name="email" form={form} renderError={false}>
102
+ </form.AppField>
103
+ <form.AppField name="email" renderError={false}>
104
104
  {(field) => (
105
105
  <IconInput
106
106
  icon={Mail}
@@ -109,12 +109,12 @@ function RegisterPage() {
109
109
  value={field.value}
110
110
  onBlur={field.handleBlur}
111
111
  onChange={(e) => field.handleChange(e.target.value)}
112
- error={field.meta.isTouched && field.errors.length > 0 ? (field.errors.map((e) => e.message).filter(Boolean)[0] as string | undefined) : undefined}
112
+ error={firstFieldErrorMessage(field)}
113
113
  />
114
114
  )}
115
- </AppField>
115
+ </form.AppField>
116
116
  <div className="grid grid-cols-2 gap-4">
117
- <AppField name="password" form={form} renderError={false}>
117
+ <form.AppField name="password" renderError={false}>
118
118
  {(field) => (
119
119
  <PasswordInput
120
120
  label={m.auth_register_passwordLabel()}
@@ -122,11 +122,11 @@ function RegisterPage() {
122
122
  value={field.value}
123
123
  onBlur={field.handleBlur}
124
124
  onChange={(e) => field.handleChange(e.target.value)}
125
- error={field.meta.isTouched && field.errors.length > 0 ? (field.errors.map((e) => e.message).filter(Boolean)[0] as string | undefined) : undefined}
125
+ error={firstFieldErrorMessage(field)}
126
126
  />
127
127
  )}
128
- </AppField>
129
- <AppField name="confirmPassword" form={form} renderError={false}>
128
+ </form.AppField>
129
+ <form.AppField name="confirmPassword" renderError={false}>
130
130
  {(field) => (
131
131
  <PasswordInput
132
132
  label={m.auth_register_confirmPasswordLabel()}
@@ -134,13 +134,13 @@ function RegisterPage() {
134
134
  value={field.value}
135
135
  onBlur={field.handleBlur}
136
136
  onChange={(e) => field.handleChange(e.target.value)}
137
- error={field.meta.isTouched && field.errors.length > 0 ? (field.errors.map((e) => e.message).filter(Boolean)[0] as string | undefined) : undefined}
137
+ error={firstFieldErrorMessage(field)}
138
138
  />
139
139
  )}
140
- </AppField>
140
+ </form.AppField>
141
141
  </div>
142
142
  {registrationMode === 'invite' && (
143
- <AppField name="invitationCode" form={form} renderError={false}>
143
+ <form.AppField name="invitationCode" renderError={false}>
144
144
  {(field) => (
145
145
  <IconInput
146
146
  icon={QrCode}
@@ -149,10 +149,10 @@ function RegisterPage() {
149
149
  value={field.value}
150
150
  onBlur={field.handleBlur}
151
151
  onChange={(e) => field.handleChange(e.target.value)}
152
- error={field.meta.isTouched && field.errors.length > 0 ? (field.errors.map((e) => e.message).filter(Boolean)[0] as string | undefined) : undefined}
152
+ error={firstFieldErrorMessage(field)}
153
153
  />
154
154
  )}
155
- </AppField>
155
+ </form.AppField>
156
156
  )}
157
157
  <form.Subscribe
158
158
  selector={(state) => state.isSubmitting}
@@ -164,6 +164,7 @@ function RegisterPage() {
164
164
  )}
165
165
  />
166
166
  </form>
167
+ </form.AppForm>
167
168
  <div className="text-center text-sm">
168
169
  {m.auth_register_hasAccount()}{' '}
169
170
  <Link to="/login" className="font-medium text-primary hover:underline">{m.auth_register_goLogin()}</Link>
@@ -16,10 +16,9 @@
16
16
  // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
 
18
18
  import { createLazyFileRoute, useRouter, useSearch, Link } from '@tanstack/react-router'
19
- import { useForm } from '@tanstack/react-form'
20
19
  import { toast } from '@/components/ui/toast'
21
20
  import { RainbowButton } from '@/components/magicui/rainbow-button'
22
- import { AppField } from '@/components/forms'
21
+ import { useAppForm, firstFieldErrorMessage } from '@/components/forms'
23
22
  import { ArrowRight } from 'lucide-react'
24
23
  import { AuthLayout, AuthLayoutLeft, AuthLayoutRight } from '@/components/auth/auth-layout'
25
24
  import { AuthHeader } from '@/components/auth/auth-header'
@@ -40,7 +39,7 @@ function ResetPasswordPage() {
40
39
  const { token } = useSearch({ from: '/_login/reset-password' })
41
40
  const loginFeatures = buildAuthFeatures()
42
41
 
43
- const form = useForm({
42
+ const form = useAppForm({
44
43
  defaultValues: { password: '', confirmPassword: '' },
45
44
  validators: [{ run: resetPasswordSchema, triggers: ['change'] }],
46
45
  onSubmit: async ({ value }) => {
@@ -58,12 +57,13 @@ function ResetPasswordPage() {
58
57
  <AuthLayout>
59
58
  <AuthLayoutLeft>
60
59
  <AuthHeader title={m.auth_resetPassword_title()} subtitle={m.auth_resetPassword_subtitle()} />
60
+ <form.AppForm>
61
61
  <form
62
62
  onSubmit={(e) => { e.preventDefault(); e.stopPropagation(); form.handleSubmit() }}
63
63
  className="space-y-6"
64
64
  >
65
65
  <div className="grid grid-cols-2 gap-4">
66
- <AppField name="password" form={form} renderError={false}>
66
+ <form.AppField name="password" renderError={false}>
67
67
  {(field) => (
68
68
  <PasswordInput
69
69
  label={m.auth_resetPassword_newPasswordLabel()}
@@ -71,11 +71,11 @@ function ResetPasswordPage() {
71
71
  value={field.value}
72
72
  onBlur={field.handleBlur}
73
73
  onChange={(e) => field.handleChange(e.target.value)}
74
- error={field.meta.isTouched && field.errors.length > 0 ? (field.errors.map((e) => e.message).filter(Boolean)[0] as string | undefined) : undefined}
74
+ error={firstFieldErrorMessage(field)}
75
75
  />
76
76
  )}
77
- </AppField>
78
- <AppField name="confirmPassword" form={form} renderError={false}>
77
+ </form.AppField>
78
+ <form.AppField name="confirmPassword" renderError={false}>
79
79
  {(field) => (
80
80
  <PasswordInput
81
81
  label={m.auth_resetPassword_confirmPasswordLabel()}
@@ -83,10 +83,10 @@ function ResetPasswordPage() {
83
83
  value={field.value}
84
84
  onBlur={field.handleBlur}
85
85
  onChange={(e) => field.handleChange(e.target.value)}
86
- error={field.meta.isTouched && field.errors.length > 0 ? (field.errors.map((e) => e.message).filter(Boolean)[0] as string | undefined) : undefined}
86
+ error={firstFieldErrorMessage(field)}
87
87
  />
88
88
  )}
89
- </AppField>
89
+ </form.AppField>
90
90
  </div>
91
91
  <form.Subscribe
92
92
  selector={(state) => state.isSubmitting}
@@ -98,6 +98,7 @@ function ResetPasswordPage() {
98
98
  )}
99
99
  />
100
100
  </form>
101
+ </form.AppForm>
101
102
  <div className="text-center text-sm">
102
103
  <Link to="/login" className="font-medium text-primary hover:underline">{m.auth_resetPassword_goLogin()}</Link>
103
104
  </div>
@@ -18,8 +18,10 @@
18
18
  import { Suspense } from 'react'
19
19
  import { createLazyFileRoute } from '@tanstack/react-router'
20
20
  import { useQuery } from '@tanstack/react-query'
21
- import { getComplianceDetailFn } from '@/server/serverFns/knowledge/public/compliance/detail'
22
- import { getFavoriteIdsFn } from '@/server/serverFns/knowledge/public/favorite'
21
+ import {
22
+ complianceDetailQueryOptions,
23
+ favoriteIdsQueryOptions,
24
+ } from '@/lib/queries/compliance'
23
25
  import { KnowledgeDocEditor } from '@/components/knowledge/editor/knowledge-doc-editor'
24
26
  import { COMPLIANCE_FIELDS } from '@/components/knowledge/public/legal-compliance-editor'
25
27
  import { LegalDetailActions, LegalDetailBackButton } from '@/components/knowledge/public/legal-detail-actions'
@@ -30,15 +32,10 @@ export const Route = createLazyFileRoute('/_nav/knowledge/compliance/$id')({ com
30
32
 
31
33
  function ComplianceDetailPage() {
32
34
  const { id } = Route.useParams()
33
- const { data, isLoading, isError } = useQuery({
34
- queryKey: ['compliance-detail', id],
35
- queryFn: () => getComplianceDetailFn({ data: { id } }),
36
- })
35
+ const detailOptions = complianceDetailQueryOptions(id)
36
+ const { data, isLoading, isError } = useQuery(detailOptions)
37
37
 
38
- const { data: favoriteIds } = useQuery({
39
- queryKey: ['favorite-ids', 'compliance'],
40
- queryFn: () => getFavoriteIdsFn({ data: { entityType: 'compliance' } }),
41
- })
38
+ const { data: favoriteIds } = useQuery(favoriteIdsQueryOptions('compliance'))
42
39
  const ctx = Route.useRouteContext()
43
40
 
44
41
  // 加载失败不再渲染空白:区分 loading / error / 空数据三态
@@ -108,9 +105,9 @@ function ComplianceDetailPage() {
108
105
  favorited={favorited}
109
106
  sharers={data.sharers}
110
107
  currentUserId={currentUserId}
111
- detailQueryKey={['compliance-detail', id]}
108
+ detailQueryKey={detailOptions.queryKey}
112
109
  listQueryKey="compliance"
113
- favoriteQueryKey={['favorite-ids', 'compliance']}
110
+ favoriteQueryKey={favoriteIdsQueryOptions('compliance').queryKey}
114
111
  editTo="/knowledge/compliance/edit/$id"
115
112
  shareBasePath="/share/compliance"
116
113
  msg={{
@@ -18,10 +18,13 @@
18
18
  import { cn } from "@/lib/utils"
19
19
  import { createLazyFileRoute, useNavigate } from '@tanstack/react-router'
20
20
  import { useState } from 'react'
21
- import { useQuery, keepPreviousData, useQueryClient } from '@tanstack/react-query'
22
- import { listComplianceFn } from '@/server/serverFns/knowledge/public/compliance/list'
21
+ import { useQuery, useQueryClient } from '@tanstack/react-query'
23
22
  import { createComplianceFn } from '@/server/serverFns/knowledge/public/compliance/create'
24
- import { getEntityTagsFn } from '@/server/serverFns/knowledge/public/entity-tags'
23
+ import {
24
+ COMPLIANCE_LIST_KEY,
25
+ complianceListQueryOptions,
26
+ entityTagsQueryOptions,
27
+ } from '@/lib/queries/compliance'
25
28
  import { KnowledgeSearchBar } from '@/components/knowledge/public/knowledge-search-bar'
26
29
  import { KnowledgeFilters } from '@/components/knowledge/public/knowledge-filters'
27
30
  import { KnowledgeCard } from '@/components/knowledge/public/knowledge-card'
@@ -49,15 +52,15 @@ function CompliancePage() {
49
52
  const [tag, setTag] = useState<string | undefined>()
50
53
  // 搜索防抖:原始输入直连 queryKey 会每键一次 serverFn RPC
51
54
  const [debouncedSearch] = useDebouncedValue(search, { wait: SEARCH_DEBOUNCE_MS })
52
- const { data: tagList } = useQuery({
53
- queryKey: ['entity-tags', 'compliance'],
54
- queryFn: () => getEntityTagsFn({ data: { entityType: 'compliance' } }),
55
- })
56
- const { data } = useQuery({
57
- queryKey: ['compliance', scope, debouncedSearch, industry, tag],
58
- queryFn: () => listComplianceFn({ data: { scope, search: debouncedSearch || undefined, industry, tag: tag || undefined } }),
59
- placeholderData: keepPreviousData,
60
- })
55
+ const { data: tagList } = useQuery(entityTagsQueryOptions('compliance'))
56
+ const { data } = useQuery(
57
+ complianceListQueryOptions({
58
+ scope,
59
+ search: debouncedSearch,
60
+ industry,
61
+ tag,
62
+ }),
63
+ )
61
64
 
62
65
  return (
63
66
  <div className="relative flex min-h-full flex-col overflow-hidden">
@@ -88,7 +91,7 @@ function CompliancePage() {
88
91
  try {
89
92
  const r = await createComplianceFn({ data: { title: m.knowledge_compliance_index_untitled(), industry: '', tags: [] } })
90
93
  // invalidate 已触发活跃查询 refetch,无需再显式 refetch(双份请求)
91
- qc.invalidateQueries({ queryKey: ['compliance'] })
94
+ qc.invalidateQueries({ queryKey: COMPLIANCE_LIST_KEY })
92
95
  await navigate({ to: '/knowledge/compliance/edit/$id', params: { id: r.id } })
93
96
  } catch (e) {
94
97
  toastError(e, m.common_operationFailed())
@@ -125,7 +125,7 @@ function LawDetailPage() {
125
125
  listQueryKey="legal"
126
126
  favoriteQueryKey={['favorite-ids', 'legal']}
127
127
  editTo="/knowledge/laws/edit/$id"
128
- shareBasePath="/share/laws"
128
+ shareBasePath="/share/law"
129
129
  msg={{
130
130
  cancel: m.knowledge_laws_detail_cancel(),
131
131
  confirmDeleteTitle: m.knowledge_laws_detail_confirmDeleteTitle(),
@@ -2,9 +2,10 @@
2
2
 
3
3
  import { createFileRoute } from '@tanstack/react-router'
4
4
  import { requireSessionPage } from '@/lib/auth/page-gate'
5
- import type { NotificationListResult } from '@allbluecn/kernel'
6
- import { NOTIFICATION_LIST_KEY, NOTIFICATION_UNREAD_KEY } from '@/hooks/use-notifications'
7
- import { getUnreadCountFn, listNotificationsFn } from '@/server/serverFns/notifications'
5
+ import {
6
+ notificationsListInfiniteQueryOptions,
7
+ notificationsUnreadQueryOptions,
8
+ } from '@/lib/queries/notifications'
8
9
 
9
10
  export const Route = createFileRoute('/_nav/notifications')({
10
11
  beforeLoad: requireSessionPage,
@@ -13,19 +14,8 @@ export const Route = createFileRoute('/_nav/notifications')({
13
14
  // SSR 预取未读数 + 列表第一页,保证服务端与客户端 hydrate 首帧渲染一致
14
15
  // (否则 SSR 渲染空态、客户端首帧已有数据 → hydration mismatch 整树重渲染)
15
16
  await Promise.all([
16
- queryClient.ensureQueryData({
17
- queryKey: NOTIFICATION_UNREAD_KEY,
18
- queryFn: () => getUnreadCountFn({ data: {} }),
19
- }),
20
- queryClient.fetchInfiniteQuery({
21
- queryKey: [...NOTIFICATION_LIST_KEY, undefined],
22
- queryFn: ({ pageParam }) =>
23
- listNotificationsFn({ data: pageParam ? { cursor: pageParam } : {} }),
24
- initialPageParam: undefined as string | undefined,
25
- getNextPageParam: (lastPage: NotificationListResult) =>
26
- // .at(-1) 防御 hasMore=true 而 items 为空的服务端边界 bug([-1].id 会抛 TypeError)
27
- lastPage.hasMore ? lastPage.items.at(-1)?.id : undefined,
28
- }),
17
+ queryClient.ensureQueryData(notificationsUnreadQueryOptions()),
18
+ queryClient.fetchInfiniteQuery(notificationsListInfiniteQueryOptions()),
29
19
  ]).catch(() => {
30
20
  // 预取失败降级为客户端 fetch(与旧行为一致),不阻塞页面
31
21
  })