@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
@@ -0,0 +1,256 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
2
+ import { MutationCache, QueryCache, QueryClient } from '@tanstack/react-query'
3
+ import { m } from '@/paraglide/messages.js'
4
+ import { toast } from '@/components/ui/toast'
5
+ import {
6
+ handleGlobalMutationError,
7
+ handleGlobalQueryError,
8
+ } from '../query-global-error'
9
+
10
+ vi.mock('@/components/ui/toast', () => ({
11
+ toast: { error: vi.fn() },
12
+ }))
13
+
14
+ function makeRouter() {
15
+ const navigate = vi.fn()
16
+ // 结构桩仅含 handler 实际消费的字段,与既有 anonymous-safe.test.ts 同口径 as never
17
+ const router = {
18
+ state: { location: { pathname: '/prd', searchStr: '?tab=all' } },
19
+ navigate,
20
+ } as never
21
+ return { router, navigate }
22
+ }
23
+
24
+ /** 构建一个直接失败的 query 并触发其 fetch(retry: false 免去重试延迟) */
25
+ async function fetchFailingQuery(
26
+ queryCache: QueryCache,
27
+ client: QueryClient,
28
+ options: { error: unknown; meta?: Record<string, unknown> },
29
+ ) {
30
+ const query = queryCache.build(client, {
31
+ queryKey: ['test-global-error'],
32
+ queryFn: () => Promise.reject(options.error),
33
+ retry: false,
34
+ meta: options.meta,
35
+ })
36
+ await query.fetch().catch(() => undefined)
37
+ }
38
+
39
+ /** 构建并执行一个直接失败的 mutation */
40
+ async function executeFailingMutation(
41
+ mutationCache: MutationCache,
42
+ client: QueryClient,
43
+ options: { error: unknown; meta?: Record<string, unknown> },
44
+ ) {
45
+ const mutation = mutationCache.build(client, {
46
+ mutationFn: () => Promise.reject(options.error),
47
+ meta: options.meta,
48
+ })
49
+ await mutation.execute(undefined as never).catch(() => undefined)
50
+ }
51
+
52
+ beforeEach(() => {
53
+ vi.mocked(toast.error).mockClear()
54
+ })
55
+
56
+ describe('QueryCache 全局 onError(web)', () => {
57
+ it('401 查询错误跳登录(带回跳)且不 toast', async () => {
58
+ const { router, navigate } = makeRouter()
59
+ const queryCache = new QueryCache({
60
+ onError: (error, query) => handleGlobalQueryError(error, query, router),
61
+ })
62
+ const client = new QueryClient({ queryCache })
63
+ await fetchFailingQuery(queryCache, client, {
64
+ error: new Error('UNAUTHORIZED'),
65
+ })
66
+ expect(navigate).toHaveBeenCalledWith({
67
+ to: '/login',
68
+ search: { redirect: '/prd?tab=all' },
69
+ })
70
+ expect(toast.error).not.toHaveBeenCalled()
71
+ })
72
+
73
+ it('4xx(非 401)toast 展示错误详情', async () => {
74
+ const { router, navigate } = makeRouter()
75
+ const queryCache = new QueryCache({
76
+ onError: (error, query) => handleGlobalQueryError(error, query, router),
77
+ })
78
+ const client = new QueryClient({ queryCache })
79
+ await fetchFailingQuery(queryCache, client, {
80
+ error: Object.assign(new Error('没有权限'), { status: 403 }),
81
+ })
82
+ expect(toast.error).toHaveBeenCalledWith('没有权限')
83
+ expect(navigate).not.toHaveBeenCalled()
84
+ })
85
+
86
+ it('5xx toast 通用文案(不透出服务端错误详情)', async () => {
87
+ const { router } = makeRouter()
88
+ const queryCache = new QueryCache({
89
+ onError: (error, query) => handleGlobalQueryError(error, query, router),
90
+ })
91
+ const client = new QueryClient({ queryCache })
92
+ await fetchFailingQuery(queryCache, client, {
93
+ error: Object.assign(new Error('Internal Server Error'), {
94
+ statusCode: 500,
95
+ }),
96
+ })
97
+ expect(toast.error).toHaveBeenCalledWith(m.common_error_generic())
98
+ })
99
+
100
+ it('网络错误(无 status)toast 通用文案', async () => {
101
+ const { router } = makeRouter()
102
+ const queryCache = new QueryCache({
103
+ onError: (error, query) => handleGlobalQueryError(error, query, router),
104
+ })
105
+ const client = new QueryClient({ queryCache })
106
+ await fetchFailingQuery(queryCache, client, {
107
+ error: new TypeError('Failed to fetch'),
108
+ })
109
+ expect(toast.error).toHaveBeenCalledWith(m.common_error_generic())
110
+ })
111
+
112
+ it('query meta.suppressGlobalToast=true 时全局 onError 不出手(防双 toast)', async () => {
113
+ const { router, navigate } = makeRouter()
114
+ const queryCache = new QueryCache({
115
+ onError: (error, query) => handleGlobalQueryError(error, query, router),
116
+ })
117
+ const client = new QueryClient({ queryCache })
118
+ await fetchFailingQuery(queryCache, client, {
119
+ error: Object.assign(new Error('没有权限'), { status: 403 }),
120
+ meta: { suppressGlobalToast: true },
121
+ })
122
+ expect(toast.error).not.toHaveBeenCalled()
123
+ expect(navigate).not.toHaveBeenCalled()
124
+ })
125
+
126
+ it('error 对象自带 meta.suppressGlobalToast 同样抑制 toast', async () => {
127
+ const { router } = makeRouter()
128
+ const queryCache = new QueryCache({
129
+ onError: (error, query) => handleGlobalQueryError(error, query, router),
130
+ })
131
+ const client = new QueryClient({ queryCache })
132
+ await fetchFailingQuery(queryCache, client, {
133
+ error: Object.assign(new Error('没有权限'), {
134
+ status: 403,
135
+ meta: { suppressGlobalToast: true },
136
+ }),
137
+ })
138
+ expect(toast.error).not.toHaveBeenCalled()
139
+ })
140
+
141
+ it('查询取消(CancelledError)不 toast 不跳转', async () => {
142
+ const { router, navigate } = makeRouter()
143
+ const queryCache = new QueryCache({
144
+ onError: (error, query) => handleGlobalQueryError(error, query, router),
145
+ })
146
+ const client = new QueryClient({ queryCache })
147
+ await fetchFailingQuery(queryCache, client, {
148
+ error: new Error('CancelledError'),
149
+ })
150
+ expect(toast.error).not.toHaveBeenCalled()
151
+ expect(navigate).not.toHaveBeenCalled()
152
+ })
153
+
154
+ it('SSR(window 缺失)不跳转不 toast', async () => {
155
+ vi.stubGlobal('window', undefined)
156
+ try {
157
+ const { router, navigate } = makeRouter()
158
+ const queryCache = new QueryCache({
159
+ onError: (error, query) => handleGlobalQueryError(error, query, router),
160
+ })
161
+ const client = new QueryClient({ queryCache })
162
+ await fetchFailingQuery(queryCache, client, {
163
+ error: new Error('UNAUTHORIZED'),
164
+ })
165
+ await fetchFailingQuery(queryCache, client, {
166
+ error: Object.assign(new Error('没有权限'), { status: 403 }),
167
+ })
168
+ expect(navigate).not.toHaveBeenCalled()
169
+ expect(toast.error).not.toHaveBeenCalled()
170
+ } finally {
171
+ vi.unstubAllGlobals()
172
+ }
173
+ })
174
+ })
175
+
176
+ describe('MutationCache 全局 onError(web 补齐对称面)', () => {
177
+ it('401 变更错误跳登录(保留既有逻辑)', async () => {
178
+ const { router, navigate } = makeRouter()
179
+ const mutationCache = new MutationCache({
180
+ onError: (error, _variables, _onMutateResult, mutation) =>
181
+ handleGlobalMutationError(error, mutation, router),
182
+ })
183
+ const client = new QueryClient({ mutationCache })
184
+ await executeFailingMutation(mutationCache, client, {
185
+ error: new Error('UNAUTHORIZED'),
186
+ })
187
+ expect(navigate).toHaveBeenCalledWith({
188
+ to: '/login',
189
+ search: { redirect: '/prd?tab=all' },
190
+ })
191
+ expect(toast.error).not.toHaveBeenCalled()
192
+ })
193
+
194
+ it('非 401 变更错误 toast 详情(403)', async () => {
195
+ const { router, navigate } = makeRouter()
196
+ const mutationCache = new MutationCache({
197
+ onError: (error, _variables, _onMutateResult, mutation) =>
198
+ handleGlobalMutationError(error, mutation, router),
199
+ })
200
+ const client = new QueryClient({ mutationCache })
201
+ await executeFailingMutation(mutationCache, client, {
202
+ error: Object.assign(new Error('配额不足'), { status: 403 }),
203
+ })
204
+ expect(toast.error).toHaveBeenCalledWith('配额不足')
205
+ expect(navigate).not.toHaveBeenCalled()
206
+ })
207
+
208
+ it('5xx 变更错误 toast 通用文案', async () => {
209
+ const { router } = makeRouter()
210
+ const mutationCache = new MutationCache({
211
+ onError: (error, _variables, _onMutateResult, mutation) =>
212
+ handleGlobalMutationError(error, mutation, router),
213
+ })
214
+ const client = new QueryClient({ mutationCache })
215
+ await executeFailingMutation(mutationCache, client, {
216
+ error: Object.assign(new Error('Bad Gateway'), { status: 502 }),
217
+ })
218
+ expect(toast.error).toHaveBeenCalledWith(m.common_error_generic())
219
+ })
220
+
221
+ it('mutation options.meta.suppressGlobalToast=true 时全局 onError 不出手', async () => {
222
+ const { router } = makeRouter()
223
+ const mutationCache = new MutationCache({
224
+ onError: (error, _variables, _onMutateResult, mutation) =>
225
+ handleGlobalMutationError(error, mutation, router),
226
+ })
227
+ const client = new QueryClient({ mutationCache })
228
+ await executeFailingMutation(mutationCache, client, {
229
+ error: Object.assign(new Error('配额不足'), { status: 403 }),
230
+ meta: { suppressGlobalToast: true },
231
+ })
232
+ expect(toast.error).not.toHaveBeenCalled()
233
+ })
234
+
235
+ it('SSR(window 缺失)不跳转不 toast', async () => {
236
+ vi.stubGlobal('window', undefined)
237
+ try {
238
+ const { router, navigate } = makeRouter()
239
+ const mutationCache = new MutationCache({
240
+ onError: (error, _variables, _onMutateResult, mutation) =>
241
+ handleGlobalMutationError(error, mutation, router),
242
+ })
243
+ const client = new QueryClient({ mutationCache })
244
+ await executeFailingMutation(mutationCache, client, {
245
+ error: new Error('UNAUTHORIZED'),
246
+ })
247
+ await executeFailingMutation(mutationCache, client, {
248
+ error: Object.assign(new Error('配额不足'), { status: 403 }),
249
+ })
250
+ expect(navigate).not.toHaveBeenCalled()
251
+ expect(toast.error).not.toHaveBeenCalled()
252
+ } finally {
253
+ vi.unstubAllGlobals()
254
+ }
255
+ })
256
+ })
@@ -16,7 +16,7 @@
16
16
  // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
 
18
18
  import { Store } from '@tanstack/store'
19
- import { useStore } from '@tanstack/react-store'
19
+ import { useSelector } from '@tanstack/react-store'
20
20
  import type { AnyHubAppData, AnyHubMarketAppData } from './types'
21
21
  import { listAnyHubAppsFn, listMarketplaceAppsFn, togglePinFn } from '@/server/serverFns/anyhub/index'
22
22
  import { installAnyHubAppFn } from '@/server/serverFns/anyhub/install'
@@ -41,7 +41,7 @@ export const anyHubStore = new Store<AnyHubState>({
41
41
  })
42
42
 
43
43
  export function useAnyHubStore<T>(selector: (state: AnyHubState) => T): T {
44
- return useStore(anyHubStore, selector)
44
+ return useSelector(anyHubStore, selector)
45
45
  }
46
46
 
47
47
  export const anyHubActions = {
@@ -87,14 +87,6 @@ export const SDK_GROUPS: SdkGroup[] = [
87
87
  "source": "apps/admin/package.json#dependencies",
88
88
  "docsUrl": "https://tanstack.com/virtual/latest"
89
89
  },
90
- {
91
- "name": "@tanstack/db",
92
- "displayName": "TanStack DB",
93
- "version": "v1.0.0-rc.1",
94
- "lastUpdate": "Oct 30, 2026",
95
- "source": "apps/web/package.json#dependencies",
96
- "docsUrl": "https://tanstack.com/db/latest"
97
- },
98
90
  {
99
91
  "name": "@tanstack/store",
100
92
  "displayName": "TanStack Store",
@@ -120,8 +112,8 @@ export const SDK_GROUPS: SdkGroup[] = [
120
112
  "items": [
121
113
  {
122
114
  "name": "@allbluecn/web-app",
123
- "version": "v0.22.4",
124
- "lastUpdate": "Oct 31, 2026",
115
+ "version": "v0.23.1",
116
+ "lastUpdate": "Nov 1, 2026",
125
117
  "source": "apps/web/package.json",
126
118
  "docsUrl": "https://github.com/allbluecn/allblue"
127
119
  },
@@ -33,7 +33,7 @@
33
33
  // 重建)。
34
34
 
35
35
  import { Store } from '@tanstack/store'
36
- import { useStore } from '@tanstack/react-store'
36
+ import { useSelector } from '@tanstack/react-store'
37
37
 
38
38
  // ---------------------------------------------------------------------------
39
39
  // 类型(§8.1 awareness state schema 逐字)
@@ -250,7 +250,7 @@ export function __resetPresenceStoreForTests(): void {
250
250
  // hooks(任务 10 消费面)
251
251
  // ---------------------------------------------------------------------------
252
252
 
253
- /** 浅比较数组(元素引用级):selector 产出新数组时避免 useStore 死循环 */
253
+ /** 浅比较数组(元素引用级):selector 产出新数组时避免死循环重渲染 */
254
254
  function areStateListsEqual(a: readonly PresenceState[], b: readonly PresenceState[]): boolean {
255
255
  if (a === b) return true
256
256
  if (a.length !== b.length) return false
@@ -317,7 +317,7 @@ export function useTeammates(
317
317
  selfId?: string | null,
318
318
  equality: (a: PresenceState[], b: PresenceState[]) => boolean = areStateListsEqual,
319
319
  ): PresenceState[] {
320
- return useStore(
320
+ return useSelector(
321
321
  presenceStore,
322
322
  (state) => {
323
323
  const list = [...state.teammates.values()].filter(
@@ -325,7 +325,7 @@ export function useTeammates(
325
325
  )
326
326
  return selector ? selector(list) : list
327
327
  },
328
- equality,
328
+ { compare: equality },
329
329
  )
330
330
  }
331
331
 
@@ -346,5 +346,5 @@ export function byModule(module: PresenceModule): (list: PresenceState[]) => Pre
346
346
 
347
347
  /** 订阅 presence 连接状态(降级 UI 用:offline → 不渲染头像组) */
348
348
  export function usePresenceStatus(): PresenceStatus {
349
- return useStore(presenceStore, (state) => state.status)
349
+ return useSelector(presenceStore, (state) => state.status)
350
350
  }
@@ -43,7 +43,7 @@
43
43
  // isEntityViewer。
44
44
 
45
45
  import { useEffect, useRef } from 'react'
46
- import { useStore } from '@tanstack/react-store'
46
+ import { useSelector } from '@tanstack/react-store'
47
47
  import { useDebouncedCallback } from '@/lib/pacer'
48
48
  import { presenceStore } from './presence-store'
49
49
  import { MODULE_ROUTES } from './module-map'
@@ -98,7 +98,7 @@ export function usePresenceListRefresh({
98
98
  // Object.is 值相等),心跳式全量重建(id+route 不变的新对象)不再触发
99
99
  // 挂载组件(StoryListView 等重型列表体)的空转重渲染。模块过滤收进
100
100
  // selector(原 byModule 前置口径不变),跨模块 presence 噪声不进签名。
101
- const signature = useStore(
101
+ const signature = useSelector(
102
102
  presenceStore,
103
103
  (state) =>
104
104
  entityViewersSignature(
@@ -44,7 +44,7 @@
44
44
 
45
45
  import { useEffect, useMemo } from 'react'
46
46
  import { Store } from '@tanstack/store'
47
- import { useStore } from '@tanstack/react-store'
47
+ import { useSelector } from '@tanstack/react-store'
48
48
  import { m } from '@/paraglide/messages.js'
49
49
  import { createSharePresenceTicketFn } from '@/server/serverFns/collab'
50
50
  import { destroyProvider, getOrCreateProvider } from './provider'
@@ -534,7 +534,7 @@ export function useSharePresence(
534
534
  }
535
535
  }, [shareToken, designId, designver])
536
536
 
537
- const state = useStore(sharePresenceStore, (s) => s)
537
+ const state = useSelector(sharePresenceStore, (s) => s)
538
538
 
539
539
  const { members, guests } = useMemo(() => {
540
540
  const members: SharePresencePerson[] = []
@@ -4,12 +4,17 @@
4
4
 
5
5
  // React Query key 常量(零依赖纯模块)。
6
6
  //
7
- // 为什么单独成文件:collection 模块在**模块作用域**执行
7
+ // 为什么单独成文件(历史):原 DB collection 模块在**模块作用域**执行
8
8
  // `createCollection({ ... queryClient: getQueryClient() })`,而 getQueryClient()
9
9
  // 在 SSR 未注入时 fail-fast(防跨请求缓存串染)。路由文件(如 _nav/route.tsx)
10
10
  // 只需要 key 常量做 prefetch,却值引入 collection 模块 → SSR 模块初始化阶段
11
11
  // 就触发 getQueryClient(),早于 router.tsx 的 setQueryClient,全站 500。
12
- // 消费方一律从本模块取 key;collection 模块转 re-export 保持兼容。
12
+ // 现状:collection 模块与 @tanstack/db / query-db-collection 已于 2026-10-31
13
+ // 删除/卸载(TanStack 优化计划 T28),本文件为现存消费方(_nav/route.tsx 预取、
14
+ // sidebar nav-workspace / nav-knowledge)保留,仍保持零依赖(路由只为取 key,
15
+ // 不应牵连任何模块作用域副作用)。新查询不再往这里加 key:走 lib/queries/ 的
16
+ // xxxQueryOptions 工厂(AGENTS.md「新查询必须走 queryOptions 工厂单一来源」),
17
+ // 本文件存量随触碰迁移。
13
18
  export const WORKSPACES_QUERY_KEY = ['workspaces'] as const
14
19
  export const KNOWLEDGE_BASES_QUERY_KEY = ['knowledge-bases'] as const
15
20
  export const PROJECTS_QUERY_KEY = ['projects'] as const
@@ -18,8 +18,6 @@
18
18
  import { describe, it, expect, vi, beforeEach } from "vitest"
19
19
  import {
20
20
  commandPaletteStore,
21
- getCommandPaletteSnapshot,
22
- subscribeCommandPalette,
23
21
  setCommandPaletteOpen,
24
22
  toggleCommandPalette,
25
23
  } from "../command-palette-state"
@@ -30,39 +28,39 @@ describe("command-palette-state", () => {
30
28
  })
31
29
 
32
30
  it("初始状态为关闭", () => {
33
- expect(getCommandPaletteSnapshot()).toBe(false)
31
+ expect(commandPaletteStore.get()).toBe(false)
34
32
  })
35
33
 
36
34
  it("setCommandPaletteOpen 更新快照并通知订阅者", () => {
37
35
  const listener = vi.fn()
38
- const unsub = subscribeCommandPalette(listener)
36
+ const sub = commandPaletteStore.subscribe(listener)
39
37
  setCommandPaletteOpen(true)
40
- expect(getCommandPaletteSnapshot()).toBe(true)
38
+ expect(commandPaletteStore.get()).toBe(true)
41
39
  expect(listener).toHaveBeenCalledTimes(1)
42
- unsub()
40
+ sub.unsubscribe()
43
41
  })
44
42
 
45
43
  it("toggleCommandPalette 翻转状态", () => {
46
44
  toggleCommandPalette()
47
- expect(getCommandPaletteSnapshot()).toBe(true)
45
+ expect(commandPaletteStore.get()).toBe(true)
48
46
  toggleCommandPalette()
49
- expect(getCommandPaletteSnapshot()).toBe(false)
47
+ expect(commandPaletteStore.get()).toBe(false)
50
48
  })
51
49
 
52
50
  it("订阅后取消订阅不再收到通知", () => {
53
51
  const listener = vi.fn()
54
- const unsub = subscribeCommandPalette(listener)
55
- unsub()
52
+ const sub = commandPaletteStore.subscribe(listener)
53
+ sub.unsubscribe()
56
54
  setCommandPaletteOpen(true)
57
55
  expect(listener).not.toHaveBeenCalled()
58
56
  })
59
57
 
60
- it("getCommandPaletteSnapshot 引用稳定(相同状态返回同一 boolean)", () => {
61
- expect(getCommandPaletteSnapshot()).toBe(getCommandPaletteSnapshot())
58
+ it("get 引用稳定(相同状态返回同一 boolean)", () => {
59
+ expect(commandPaletteStore.get()).toBe(commandPaletteStore.get())
62
60
  })
63
61
 
64
- it("commandPaletteStore 暴露 useSyncExternalStore 兼容接口", () => {
62
+ it("commandPaletteStore 暴露官方 Store 接口(useSelector 兼容)", () => {
65
63
  expect(commandPaletteStore.subscribe).toBeTypeOf("function")
66
- expect(commandPaletteStore.getSnapshot).toBeTypeOf("function")
64
+ expect(commandPaletteStore.get).toBeTypeOf("function")
67
65
  })
68
66
  })
@@ -17,7 +17,7 @@
17
17
 
18
18
  import { describe, it, expect } from "vitest"
19
19
  import { COMMAND_REGISTRY, getSequencePairs } from "../registry"
20
- import { HOTKEY_REGISTRY } from "../../hotkeys/registry"
20
+ import { appHotkeys } from "../../hotkeys/registry"
21
21
 
22
22
  const KNOWN_ROUTES = new Set([
23
23
  "/dashboard",
@@ -81,13 +81,16 @@ describe("COMMAND_REGISTRY", () => {
81
81
  })
82
82
  })
83
83
 
84
- describe("COMMAND_REGISTRY ↔ HOTKEY_REGISTRY 跨表一致性", () => {
84
+ describe("COMMAND_REGISTRY ↔ appHotkeys 跨表一致性", () => {
85
85
  it("序列键集合一致", () => {
86
86
  const cmdSeq = new Set(
87
87
  COMMAND_REGISTRY.filter((c) => c.shortcut).map((c) => c.shortcut!.join(" "))
88
88
  )
89
89
  const hkSeq = new Set(
90
- HOTKEY_REGISTRY.filter((h) => h.keys.includes(" ")).map((h) => h.keys)
90
+ Object.values(appHotkeys)
91
+ .filter((entry): entry is typeof entry & { hotkey: ReadonlyArray<string> } =>
92
+ Array.isArray(entry.hotkey))
93
+ .map((entry) => entry.hotkey.join(" "))
91
94
  )
92
95
  expect(cmdSeq).toEqual(hkSeq)
93
96
  })
@@ -15,42 +15,19 @@
15
15
  // You should have received a copy of the GNU Affero General Public License
16
16
  // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
 
18
- export interface CommandPaletteStore {
19
- subscribe: (listener: () => void) => () => void
20
- getSnapshot: () => boolean
21
- }
22
-
23
- let open = false
24
- const listeners = new Set<() => void>()
25
-
26
- function emit() {
27
- for (const listener of listeners) listener()
28
- }
18
+ import { Store } from '@tanstack/store'
29
19
 
30
- export const commandPaletteStore: CommandPaletteStore = {
31
- subscribe(listener: () => void) {
32
- listeners.add(listener)
33
- return () => {
34
- listeners.delete(listener)
35
- }
36
- },
37
- getSnapshot: () => open,
38
- }
39
-
40
- export function subscribeCommandPalette(listener: () => void) {
41
- return commandPaletteStore.subscribe(listener)
42
- }
20
+ // 命令面板开关全局单例(任务 25:手写 useSyncExternalStore store 迁官方
21
+ // Store,与 anyhub-store 同构)。初始值模块级 false 且仅由客户端交互
22
+ // (热键/菜单/侧栏触发器)经 setState 变更,SSR 渲染期间恒为 false——
23
+ // useSelector 以 get() 同时充当 server snapshot,无 hydration 差异。
43
24
 
44
- export function getCommandPaletteSnapshot() {
45
- return commandPaletteStore.getSnapshot()
46
- }
25
+ export const commandPaletteStore = new Store<boolean>(false)
47
26
 
48
27
  export function setCommandPaletteOpen(next: boolean) {
49
- if (open === next) return
50
- open = next
51
- emit()
28
+ commandPaletteStore.setState(() => next)
52
29
  }
53
30
 
54
31
  export function toggleCommandPalette() {
55
- setCommandPaletteOpen(!open)
32
+ setCommandPaletteOpen(!commandPaletteStore.get())
56
33
  }
@@ -16,31 +16,84 @@
16
16
  // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
 
18
18
  import { describe, it, expect } from "vitest"
19
- import { HOTKEY_REGISTRY, CATEGORY_ORDER, getHotkeysByCategory } from "../registry"
19
+ import { checkHotkey } from "@tanstack/hotkeys"
20
20
 
21
- describe("HOTKEY_REGISTRY", () => {
22
- it("快捷键组合(keys 字段整体)不重复", () => {
23
- const keys = HOTKEY_REGISTRY.map((h) => h.keys)
24
- expect(new Set(keys).size).toBe(keys.length)
21
+ import { appHotkeys, findAppHotkeyConflicts, formatAppHotkeyForBadge, CATEGORY_ORDER, type AppHotkeyId } from "../registry"
22
+
23
+ const DECLARED_IDS = Object.keys(appHotkeys) as AppHotkeyId[]
24
+
25
+ describe("appHotkeys(defineAppHotkeys 官方声明)", () => {
26
+ it("恰好 25 条声明,且 id 与迁移前注册表对齐", () => {
27
+ expect(DECLARED_IDS).toHaveLength(25)
28
+ expect(DECLARED_IDS).toEqual(
29
+ expect.arrayContaining([
30
+ "shortcuts-panel",
31
+ "toggle-sidebar",
32
+ "save",
33
+ "close-panel",
34
+ "copy-message",
35
+ "chat-prev",
36
+ "chat-next",
37
+ "command-palette",
38
+ "toggle-theme",
39
+ "goto-dashboard",
40
+ "goto-chat",
41
+ "goto-agents",
42
+ "goto-inspiration",
43
+ "goto-stories",
44
+ "goto-prd",
45
+ "goto-design",
46
+ "goto-test-cases",
47
+ "goto-bugs",
48
+ "goto-knowledge",
49
+ "goto-anyhub",
50
+ "goto-workspaces",
51
+ "goto-settings",
52
+ "create-prd-hk",
53
+ "create-conversation-hk",
54
+ "create-story-hk",
55
+ ]),
56
+ )
25
57
  })
26
58
 
27
- it("序列键条目 keys 为空格分隔的两键(如 'G D')", () => {
28
- const seqKeys = HOTKEY_REGISTRY.filter((h) => h.keys.includes(" "))
29
- expect(seqKeys.length).toBeGreaterThanOrEqual(16)
30
- for (const h of seqKeys) {
31
- expect(h.keys.split(" ")).toHaveLength(2)
59
+ it("每条声明都是合法组合键(官方 validateHotkey),且 meta 完整(descriptionKey + category)", () => {
60
+ for (const id of DECLARED_IDS) {
61
+ const entry = appHotkeys[id]!
62
+ const hotkey = entry.hotkey
63
+ expect(hotkey, `${id} 应有默认组合键`).not.toBeNull()
64
+ expect(checkHotkey(hotkey!), `${id} 组合键非法`).toBe(true)
65
+ expect(entry.meta?.descriptionKey, `${id} 缺 descriptionKey`).toMatch(/^common_hotkey_desc_/)
66
+ expect(CATEGORY_ORDER, `${id} category 非法`).toContain(entry.meta?.category)
32
67
  }
33
68
  })
34
69
 
35
- it("所有条目 category 都在 CATEGORY_ORDER 中", () => {
36
- for (const h of HOTKEY_REGISTRY) {
37
- expect(CATEGORY_ORDER).toContain(h.category)
70
+ it("组合键(chord 整体)不重复", () => {
71
+ const chords = DECLARED_IDS.map((id) => formatAppHotkeyForBadge(appHotkeys[id]!.hotkey))
72
+ expect(new Set(chords).size).toBe(chords.length)
73
+ })
74
+
75
+ it("序列键条目为两步序列(G/N 前缀,共 16 条)", () => {
76
+ const sequences = DECLARED_IDS.map((id) => appHotkeys[id]!).filter((e) => Array.isArray(e.hotkey))
77
+ expect(sequences).toHaveLength(16)
78
+ for (const entry of sequences) {
79
+ const seq = entry.hotkey
80
+ expect(seq).toHaveLength(2)
81
+ expect(["G", "N"]).toContain(seq![0])
38
82
  }
39
83
  })
40
84
 
41
- it("getHotkeysByCategory 过滤正确", () => {
42
- const nav = getHotkeysByCategory("导航")
43
- expect(nav.length).toBeGreaterThan(0)
44
- expect(nav.every((h) => h.category === "导航")).toBe(true)
85
+ it("非序列条目为 9 条 chord(Mod+/ 等)", () => {
86
+ const chords = DECLARED_IDS.map((id) => appHotkeys[id]!).filter((e) => typeof e.hotkey === "string")
87
+ expect(chords).toHaveLength(9)
88
+ })
89
+
90
+ it("现网声明零冲突(findAppHotkeyConflicts)", () => {
91
+ expect(findAppHotkeyConflicts()).toEqual([])
92
+ })
93
+
94
+ it("formatAppHotkeyForBadge:chord 原样、序列空格连接、null 返回空串", () => {
95
+ expect(formatAppHotkeyForBadge("Mod+/")).toBe("Mod+/")
96
+ expect(formatAppHotkeyForBadge(["G", "D"])).toBe("G D")
97
+ expect(formatAppHotkeyForBadge(null)).toBe("")
45
98
  })
46
- })
99
+ })