@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,136 @@
1
+ import { describe, expect, it, vi, beforeEach } from 'vitest'
2
+ import { QueryClient, keepPreviousData } from '@tanstack/react-query'
3
+
4
+ vi.mock('@/server/serverFns/knowledge/public/compliance/list', () => ({
5
+ listComplianceFn: vi.fn().mockResolvedValue({ items: [], hasMore: false }),
6
+ }))
7
+ vi.mock('@/server/serverFns/knowledge/public/compliance/detail', () => ({
8
+ getComplianceDetailFn: vi.fn().mockResolvedValue({}),
9
+ }))
10
+ vi.mock('@/server/serverFns/knowledge/public/entity-tags', () => ({
11
+ getEntityTagsFn: vi.fn().mockResolvedValue([]),
12
+ }))
13
+ vi.mock('@/server/serverFns/knowledge/public/favorite', () => ({
14
+ getFavoriteIdsFn: vi.fn().mockResolvedValue([]),
15
+ }))
16
+
17
+ import { listComplianceFn } from '@/server/serverFns/knowledge/public/compliance/list'
18
+ import { getComplianceDetailFn } from '@/server/serverFns/knowledge/public/compliance/detail'
19
+ import { getEntityTagsFn } from '@/server/serverFns/knowledge/public/entity-tags'
20
+ import { getFavoriteIdsFn } from '@/server/serverFns/knowledge/public/favorite'
21
+ import {
22
+ COMPLIANCE_LIST_KEY,
23
+ ENTITY_TAGS_KEY,
24
+ FAVORITE_IDS_KEY,
25
+ complianceDetailQueryOptions,
26
+ complianceListQueryOptions,
27
+ entityTagsQueryOptions,
28
+ favoriteIdsQueryOptions,
29
+ } from '../compliance'
30
+
31
+ const mockedList = vi.mocked(listComplianceFn)
32
+ const mockedDetail = vi.mocked(getComplianceDetailFn)
33
+ const mockedTags = vi.mocked(getEntityTagsFn)
34
+ const mockedFavoriteIds = vi.mocked(getFavoriteIdsFn)
35
+
36
+ beforeEach(() => {
37
+ vi.clearAllMocks()
38
+ })
39
+
40
+ /** queryFn 运行时恒存在(工厂必传),类型上可选故窄化;context 形状对齐 react-query v5 调用面 */
41
+ function invokeQueryFn(
42
+ options: { queryFn?: (...args: never[]) => unknown },
43
+ queryKey: readonly unknown[],
44
+ ): Promise<unknown> {
45
+ return (options.queryFn as (c: unknown) => Promise<unknown>)({
46
+ client: new QueryClient(),
47
+ queryKey,
48
+ signal: new AbortController().signal,
49
+ meta: undefined,
50
+ })
51
+ }
52
+
53
+ /**
54
+ * compliance key 结构零漂移:与迁移前两个路由文件的内联字面量逐字一致。
55
+ * 迁移前 $id.lazy.tsx 的 detail / favorite-ids key 在 useQuery 与
56
+ * LegalDetailActions props 各持一份靠人工对齐(审计点名的双份维护税),
57
+ * 现在两处消费 factory().queryKey,编译期防漂移。
58
+ */
59
+ describe('compliance queryOptions key 结构', () => {
60
+ it('列表 key 前缀为 [\'compliance\'](invalidateQueries 前缀匹配同形)', () => {
61
+ expect(COMPLIANCE_LIST_KEY).toEqual(['compliance'])
62
+ expect(ENTITY_TAGS_KEY).toEqual(['entity-tags'])
63
+ expect(FAVORITE_IDS_KEY).toEqual(['favorite-ids'])
64
+ })
65
+
66
+ it('列表 key 五段结构与迁移前 [compliance, scope, search, industry, tag] 同形', () => {
67
+ // 迁移前:['compliance', scope, debouncedSearch, industry, tag]
68
+ expect(
69
+ complianceListQueryOptions({ scope: 'all', search: '', industry: undefined, tag: undefined })
70
+ .queryKey,
71
+ ).toEqual(['compliance', 'all', '', undefined, undefined])
72
+ expect(
73
+ complianceListQueryOptions({ scope: 'private', search: 'gdpr', industry: '金融', tag: '安全' })
74
+ .queryKey,
75
+ ).toEqual(['compliance', 'private', 'gdpr', '金融', '安全'])
76
+ })
77
+
78
+ it('详情 key 与迁移前 [compliance-detail, id] 逐字一致', () => {
79
+ expect(complianceDetailQueryOptions('abc').queryKey).toEqual(['compliance-detail', 'abc'])
80
+ })
81
+
82
+ it('entity-tags key 与迁移前 [entity-tags, entityType] 逐字一致', () => {
83
+ expect(entityTagsQueryOptions('compliance').queryKey).toEqual(['entity-tags', 'compliance'])
84
+ expect(entityTagsQueryOptions('legal').queryKey).toEqual(['entity-tags', 'legal'])
85
+ })
86
+
87
+ it('favorite-ids key 与迁移前 [favorite-ids, entityType] 逐字一致', () => {
88
+ expect(favoriteIdsQueryOptions('compliance').queryKey).toEqual(['favorite-ids', 'compliance'])
89
+ })
90
+
91
+ it('列表工厂保留 placeholderData: keepPreviousData(迁移前 index 页行为)', () => {
92
+ expect(complianceListQueryOptions({ scope: 'all' }).placeholderData).toBe(keepPreviousData)
93
+ })
94
+ })
95
+
96
+ /** queryFn 接线:必须调用既有 serverFn 且 data 形状与迁移前内联写法逐字一致 */
97
+ describe('compliance queryOptions queryFn 接线', () => {
98
+ it('列表:空 search 归一化为 undefined(迁移前 search || undefined 同形)', async () => {
99
+ const options = complianceListQueryOptions({ scope: 'all', search: '' })
100
+ await invokeQueryFn(options, options.queryKey)
101
+ expect(mockedList).toHaveBeenCalledWith({
102
+ data: { scope: 'all', search: undefined, industry: undefined, tag: undefined },
103
+ })
104
+ })
105
+
106
+ it('列表:全量过滤直传(迁移前同形)', async () => {
107
+ const options = complianceListQueryOptions({
108
+ scope: 'share',
109
+ search: 'gdpr',
110
+ industry: '金融',
111
+ tag: '安全',
112
+ })
113
+ await invokeQueryFn(options, options.queryKey)
114
+ expect(mockedList).toHaveBeenCalledWith({
115
+ data: { scope: 'share', search: 'gdpr', industry: '金融', tag: '安全' },
116
+ })
117
+ })
118
+
119
+ it('详情 → getComplianceDetailFn({ data: { id } })', async () => {
120
+ const options = complianceDetailQueryOptions('abc')
121
+ await invokeQueryFn(options, options.queryKey)
122
+ expect(mockedDetail).toHaveBeenCalledWith({ data: { id: 'abc' } })
123
+ })
124
+
125
+ it('entity-tags → getEntityTagsFn({ data: { entityType } })', async () => {
126
+ const options = entityTagsQueryOptions('compliance')
127
+ await invokeQueryFn(options, options.queryKey)
128
+ expect(mockedTags).toHaveBeenCalledWith({ data: { entityType: 'compliance' } })
129
+ })
130
+
131
+ it('favorite-ids → getFavoriteIdsFn({ data: { entityType } })', async () => {
132
+ const options = favoriteIdsQueryOptions('compliance')
133
+ await invokeQueryFn(options, options.queryKey)
134
+ expect(mockedFavoriteIds).toHaveBeenCalledWith({ data: { entityType: 'compliance' } })
135
+ })
136
+ })
@@ -0,0 +1,175 @@
1
+ import { describe, expect, it, vi, beforeEach } from 'vitest'
2
+ import { QueryClient } from '@tanstack/react-query'
3
+
4
+ vi.mock('@/server/serverFns/notifications', () => ({
5
+ getUnreadCountFn: vi.fn().mockResolvedValue({ count: 0 }),
6
+ getNotificationPreferencesFn: vi.fn().mockResolvedValue({}),
7
+ listNotificationsFn: vi.fn().mockResolvedValue({ items: [], hasMore: false }),
8
+ markNotificationReadFn: vi.fn(),
9
+ markAllNotificationsReadFn: vi.fn(),
10
+ deleteNotificationFn: vi.fn(),
11
+ clearNotificationsFn: vi.fn(),
12
+ updateNotificationPreferencesFn: vi.fn(),
13
+ }))
14
+
15
+ import type { NotificationItem } from '@allbluecn/kernel'
16
+ import { getNotificationPreferencesFn, getUnreadCountFn, listNotificationsFn } from '@/server/serverFns/notifications'
17
+ import {
18
+ NOTIFICATION_LIST_KEY,
19
+ NOTIFICATION_POPOVER_KEY,
20
+ NOTIFICATION_PREFERENCES_KEY,
21
+ NOTIFICATION_ROOT_KEY,
22
+ NOTIFICATION_UNREAD_KEY,
23
+ notificationPreferencesQueryOptions,
24
+ notificationsListInfiniteQueryOptions,
25
+ notificationsPopoverUnreadQueryOptions,
26
+ notificationsUnreadQueryOptions,
27
+ } from '../notifications'
28
+
29
+ const mockedUnread = vi.mocked(getUnreadCountFn)
30
+ const mockedPreferences = vi.mocked(getNotificationPreferencesFn)
31
+ const mockedList = vi.mocked(listNotificationsFn)
32
+
33
+ beforeEach(() => {
34
+ vi.clearAllMocks()
35
+ })
36
+
37
+ /** queryFn 运行时恒存在(工厂必传),类型上可选故窄化;context 形状对齐 react-query v5 调用面 */
38
+ function invokeQueryFn(
39
+ options: { queryFn?: (...args: never[]) => unknown },
40
+ ctx: unknown,
41
+ ): Promise<unknown> {
42
+ return (options.queryFn as (c: unknown) => Promise<unknown>)(ctx)
43
+ }
44
+
45
+ const queryCtx = (queryKey: readonly unknown[]) => ({
46
+ client: new QueryClient(),
47
+ queryKey,
48
+ signal: new AbortController().signal,
49
+ meta: undefined,
50
+ })
51
+
52
+ /** notifications key 结构零漂移:与迁移前 hooks/use-notifications.ts 常量逐字一致 */
53
+ describe('notifications queryOptions key 结构', () => {
54
+ it('五个 key 常量与历史字面量逐字一致', () => {
55
+ expect(NOTIFICATION_ROOT_KEY).toEqual(['notifications'])
56
+ expect(NOTIFICATION_LIST_KEY).toEqual(['notifications', 'list'])
57
+ expect(NOTIFICATION_POPOVER_KEY).toEqual(['notifications', 'popover'])
58
+ expect(NOTIFICATION_UNREAD_KEY).toEqual(['notifications', 'unread'])
59
+ expect(NOTIFICATION_PREFERENCES_KEY).toEqual(['notifications', 'preferences'])
60
+ })
61
+
62
+ it('unread 工厂产出 NOTIFICATION_UNREAD_KEY 同一引用', () => {
63
+ expect(notificationsUnreadQueryOptions().queryKey).toBe(NOTIFICATION_UNREAD_KEY)
64
+ })
65
+
66
+ it('preferences 工厂产出 NOTIFICATION_PREFERENCES_KEY 同一引用', () => {
67
+ expect(notificationPreferencesQueryOptions().queryKey).toBe(NOTIFICATION_PREFERENCES_KEY)
68
+ })
69
+
70
+ it('popover 工厂 key 为 [...POPOVER, status, unread](迁移前 nav-notifications 内联同形)', () => {
71
+ expect(notificationsPopoverUnreadQueryOptions().queryKey).toEqual([
72
+ 'notifications',
73
+ 'popover',
74
+ 'status',
75
+ 'unread',
76
+ ])
77
+ })
78
+
79
+ it('列表工厂 category 省略时 key 为 [...LIST, undefined](迁移前 loader 预取同形)', () => {
80
+ expect(notificationsListInfiniteQueryOptions().queryKey).toEqual([
81
+ 'notifications',
82
+ 'list',
83
+ undefined,
84
+ ])
85
+ })
86
+
87
+ it('列表工厂 category 传入时追加到 key 尾位(迁移前 [...LIST, categoryFilter] 同形)', () => {
88
+ expect(notificationsListInfiniteQueryOptions('team').queryKey).toEqual([
89
+ 'notifications',
90
+ 'list',
91
+ 'team',
92
+ ])
93
+ })
94
+ })
95
+
96
+ /** queryFn 接线:必须调用既有 serverFn 且 data 形状与迁移前内联写法逐字一致 */
97
+ describe('notifications queryOptions queryFn 接线', () => {
98
+ it('unread → getUnreadCountFn({ data: {} })', async () => {
99
+ const options = notificationsUnreadQueryOptions()
100
+ await invokeQueryFn(options, queryCtx(options.queryKey))
101
+ expect(mockedUnread).toHaveBeenCalledWith({ data: {} })
102
+ })
103
+
104
+ it('preferences → getNotificationPreferencesFn({ data: {} })', async () => {
105
+ const options = notificationPreferencesQueryOptions()
106
+ await invokeQueryFn(options, queryCtx(options.queryKey))
107
+ expect(mockedPreferences).toHaveBeenCalledWith({ data: {} })
108
+ })
109
+
110
+ it('popover → listNotificationsFn({ data: { status: "unread" } })', async () => {
111
+ const options = notificationsPopoverUnreadQueryOptions()
112
+ await invokeQueryFn(options, queryCtx(options.queryKey))
113
+ expect(mockedList).toHaveBeenCalledWith({ data: { status: 'unread' } })
114
+ })
115
+
116
+ it('列表首页(无 category 无 cursor)→ listNotificationsFn({ data: {} })(迁移前 loader 同形)', async () => {
117
+ const options = notificationsListInfiniteQueryOptions()
118
+ await invokeQueryFn(options, {
119
+ ...queryCtx(options.queryKey),
120
+ pageParam: options.initialPageParam,
121
+ direction: 'forward',
122
+ })
123
+ expect(mockedList).toHaveBeenCalledWith({ data: {} })
124
+ })
125
+
126
+ it('列表带 category + cursor → listNotificationsFn({ data: { category, cursor } })(迁移前面板同形)', async () => {
127
+ const options = notificationsListInfiniteQueryOptions('team')
128
+ await invokeQueryFn(options, {
129
+ ...queryCtx(options.queryKey),
130
+ pageParam: 'c1',
131
+ direction: 'forward',
132
+ })
133
+ expect(mockedList).toHaveBeenCalledWith({ data: { category: 'team', cursor: 'c1' } })
134
+ })
135
+
136
+ it('initialPageParam 为 undefined(字符串游标)', () => {
137
+ expect(notificationsListInfiniteQueryOptions().initialPageParam).toBeUndefined()
138
+ })
139
+ })
140
+
141
+ /** getNextPageParam 防御边界(迁移自 loader 注释:hasMore=true 而 items 为空不抛 TypeError) */
142
+ describe('notifications 列表 getNextPageParam', () => {
143
+ const options = notificationsListInfiniteQueryOptions()
144
+
145
+ const makeItem = (id: string): NotificationItem => ({
146
+ id,
147
+ category: 'system',
148
+ type: 'test',
149
+ title: 't',
150
+ body: null,
151
+ link: null,
152
+ readAt: null,
153
+ createdAt: '2026-01-01T00:00:00Z',
154
+ })
155
+ const makePage = (items: ReturnType<typeof makeItem>[]) => ({
156
+ items,
157
+ total: items.length,
158
+ hasMore: true,
159
+ })
160
+
161
+ it('hasMore=true 取最后一个 item 的 id', () => {
162
+ const page = makePage([makeItem('a'), makeItem('b')])
163
+ expect(options.getNextPageParam(page, [page], undefined, [undefined])).toBe('b')
164
+ })
165
+
166
+ it('hasMore=false 返回 undefined', () => {
167
+ const page = { ...makePage([makeItem('a')]), hasMore: false }
168
+ expect(options.getNextPageParam(page, [page], undefined, [undefined])).toBeUndefined()
169
+ })
170
+
171
+ it('hasMore=true 而 items 为空 → undefined(.at(-1) 防御,不抛 TypeError)', () => {
172
+ const page = makePage([])
173
+ expect(options.getNextPageParam(page, [page], undefined, [undefined])).toBeUndefined()
174
+ })
175
+ })
@@ -0,0 +1,87 @@
1
+ import { describe, expect, it, vi, beforeEach } from 'vitest'
2
+ import { QueryClient } from '@tanstack/react-query'
3
+
4
+ vi.mock('@/server/serverFns/team', () => ({
5
+ listTeamMembersFn: vi.fn().mockResolvedValue([]),
6
+ listTeamInvitationsFn: vi.fn().mockResolvedValue({ invitations: [] }),
7
+ listTeamUsersFn: vi.fn().mockResolvedValue([]),
8
+ createTeamInvitationFn: vi.fn(),
9
+ refreshTeamInvitationLinkFn: vi.fn(),
10
+ revokeTeamInvitationFn: vi.fn(),
11
+ resendTeamInvitationFn: vi.fn(),
12
+ approveTeamInvitationFn: vi.fn(),
13
+ approveTeamJoinRequestFn: vi.fn(),
14
+ rejectTeamJoinRequestFn: vi.fn(),
15
+ deleteTeamInvitationFn: vi.fn(),
16
+ deleteTeamJoinRequestFn: vi.fn(),
17
+ removeTeamMemberFn: vi.fn(),
18
+ leaveTeamFn: vi.fn(),
19
+ clearExpiredInvitationsFn: vi.fn(),
20
+ }))
21
+
22
+ import { listTeamInvitationsFn, listTeamMembersFn, listTeamUsersFn } from '@/server/serverFns/team'
23
+ import {
24
+ TEAM_INVITATIONS_QUERY_KEY,
25
+ TEAM_MEMBERS_QUERY_KEY,
26
+ TEAM_USERS_QUERY_KEY,
27
+ teamInvitationsQueryOptions,
28
+ teamMembersQueryOptions,
29
+ teamUsersQueryOptions,
30
+ } from '../team'
31
+
32
+ const mockedMembers = vi.mocked(listTeamMembersFn)
33
+ const mockedInvitations = vi.mocked(listTeamInvitationsFn)
34
+ const mockedUsers = vi.mocked(listTeamUsersFn)
35
+
36
+ beforeEach(() => {
37
+ vi.clearAllMocks()
38
+ })
39
+
40
+ /** queryFn 运行时恒存在(工厂必传),类型上可选故窄化;context 形状对齐 react-query v5 调用面 */
41
+ function invokeQueryFn(
42
+ options: { queryFn?: (...args: never[]) => unknown },
43
+ queryKey: readonly unknown[],
44
+ ): Promise<unknown> {
45
+ return (options.queryFn as (c: unknown) => Promise<unknown>)({
46
+ client: new QueryClient(),
47
+ queryKey,
48
+ signal: new AbortController().signal,
49
+ meta: undefined,
50
+ })
51
+ }
52
+
53
+ /** team key 结构零漂移:与迁移前 team-client.tsx 内联字面量逐字一致(此前无常量,自此收敛单一来源) */
54
+ describe('team queryOptions key 结构', () => {
55
+ it('三个 key 常量与历史内联字面量逐字一致', () => {
56
+ expect(TEAM_MEMBERS_QUERY_KEY).toEqual(['teamMembers'])
57
+ expect(TEAM_INVITATIONS_QUERY_KEY).toEqual(['teamInvitations'])
58
+ expect(TEAM_USERS_QUERY_KEY).toEqual(['teamUsers'])
59
+ })
60
+
61
+ it('各工厂产出对应常量同一引用(invalidate 与 useQuery 同源)', () => {
62
+ expect(teamMembersQueryOptions().queryKey).toBe(TEAM_MEMBERS_QUERY_KEY)
63
+ expect(teamInvitationsQueryOptions().queryKey).toBe(TEAM_INVITATIONS_QUERY_KEY)
64
+ expect(teamUsersQueryOptions().queryKey).toBe(TEAM_USERS_QUERY_KEY)
65
+ })
66
+ })
67
+
68
+ /** queryFn 接线:必须调用既有 serverFn 且无参形态与迁移前内联写法一致 */
69
+ describe('team queryOptions queryFn 接线', () => {
70
+ it('members → listTeamMembersFn()(无参)', async () => {
71
+ const options = teamMembersQueryOptions()
72
+ await invokeQueryFn(options, options.queryKey)
73
+ expect(mockedMembers).toHaveBeenCalledWith()
74
+ })
75
+
76
+ it('invitations → listTeamInvitationsFn()(无参)', async () => {
77
+ const options = teamInvitationsQueryOptions()
78
+ await invokeQueryFn(options, options.queryKey)
79
+ expect(mockedInvitations).toHaveBeenCalledWith()
80
+ })
81
+
82
+ it('users → listTeamUsersFn()(无参)', async () => {
83
+ const options = teamUsersQueryOptions()
84
+ await invokeQueryFn(options, options.queryKey)
85
+ expect(mockedUsers).toHaveBeenCalledWith()
86
+ })
87
+ })
@@ -0,0 +1,40 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+
5
+ // agents 模块 queryOptions 工厂(key + queryFn 单一来源)。
6
+ // 消费方(组件 useQuery / invalidate / setQueryData)一律从本模块取,
7
+ // 禁止再写 ['agents'] 等内联字面量。模式说明见 ./README.md。
8
+ import { queryOptions } from '@tanstack/react-query'
9
+ import { listAgentsFn } from '@/server/serverFns/agents/agent-crud'
10
+ import { listSkillsFn } from '@/server/serverFns/agents/skill-crud'
11
+ import { listBindingsFn, getPersonaHintFn } from '@/server/serverFns/agents/bindings'
12
+
13
+ export const AGENTS_QUERY_KEY = ['agents'] as const
14
+ export const SKILLS_QUERY_KEY = ['skills'] as const
15
+ export const AGENT_BINDINGS_QUERY_KEY = ['agent-bindings'] as const
16
+ export const PERSONA_HINT_QUERY_KEY = ['persona-hint'] as const
17
+
18
+ export const agentsQueryOptions = () =>
19
+ queryOptions({
20
+ queryKey: AGENTS_QUERY_KEY,
21
+ queryFn: () => listAgentsFn(),
22
+ })
23
+
24
+ export const skillsQueryOptions = () =>
25
+ queryOptions({
26
+ queryKey: SKILLS_QUERY_KEY,
27
+ queryFn: () => listSkillsFn(),
28
+ })
29
+
30
+ export const agentBindingsQueryOptions = () =>
31
+ queryOptions({
32
+ queryKey: AGENT_BINDINGS_QUERY_KEY,
33
+ queryFn: () => listBindingsFn(),
34
+ })
35
+
36
+ export const personaHintQueryOptions = () =>
37
+ queryOptions({
38
+ queryKey: PERSONA_HINT_QUERY_KEY,
39
+ queryFn: () => getPersonaHintFn(),
40
+ })
@@ -0,0 +1,69 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+
5
+ // compliance 模块 queryOptions 工厂(key + queryFn 单一来源)。
6
+ // 审计点名的双份维护税:detail / favorite-ids 的 key 字面量曾在
7
+ // $id.lazy.tsx 的 useQuery 与 LegalDetailActions props 各持一份靠人工对齐;
8
+ // 现在两处都从本模块取 factory().queryKey,编译期防漂移。
9
+ // entity-tags / favorite-ids 的 entityType 参数化了 legal / compliance /
10
+ // dictionary 共用族(laws / dictionary 渐进迁移见 ./README.md)。
11
+ import { keepPreviousData, queryOptions } from '@tanstack/react-query'
12
+ import { listComplianceFn } from '@/server/serverFns/knowledge/public/compliance/list'
13
+ import { getComplianceDetailFn } from '@/server/serverFns/knowledge/public/compliance/detail'
14
+ import { getEntityTagsFn } from '@/server/serverFns/knowledge/public/entity-tags'
15
+ import { getFavoriteIdsFn } from '@/server/serverFns/knowledge/public/favorite'
16
+
17
+ export type ComplianceScope = 'all' | 'private' | 'share' | 'favorite'
18
+
19
+ export const COMPLIANCE_LIST_KEY = ['compliance'] as const
20
+ export const ENTITY_TAGS_KEY = ['entity-tags'] as const
21
+ export const FAVORITE_IDS_KEY = ['favorite-ids'] as const
22
+
23
+ export interface ComplianceListFilters {
24
+ scope: ComplianceScope
25
+ search?: string
26
+ industry?: string
27
+ tag?: string
28
+ }
29
+
30
+ export const complianceListQueryOptions = (filters: ComplianceListFilters) =>
31
+ queryOptions({
32
+ queryKey: [
33
+ ...COMPLIANCE_LIST_KEY,
34
+ filters.scope,
35
+ filters.search,
36
+ filters.industry,
37
+ filters.tag,
38
+ ],
39
+ queryFn: () =>
40
+ listComplianceFn({
41
+ data: {
42
+ scope: filters.scope,
43
+ search: filters.search || undefined,
44
+ industry: filters.industry,
45
+ tag: filters.tag || undefined,
46
+ },
47
+ }),
48
+ placeholderData: keepPreviousData,
49
+ })
50
+
51
+ export const complianceDetailQueryOptions = (id: string) =>
52
+ queryOptions({
53
+ queryKey: ['compliance-detail', id] as const,
54
+ queryFn: () => getComplianceDetailFn({ data: { id } }),
55
+ })
56
+
57
+ export const entityTagsQueryOptions = (entityType: 'legal' | 'compliance' | 'dictionary') =>
58
+ queryOptions({
59
+ queryKey: [...ENTITY_TAGS_KEY, entityType] as const,
60
+ queryFn: () => getEntityTagsFn({ data: { entityType } }),
61
+ })
62
+
63
+ export const favoriteIdsQueryOptions = (
64
+ entityType: 'legal' | 'compliance' | 'dictionary' | 'bookmark',
65
+ ) =>
66
+ queryOptions({
67
+ queryKey: [...FAVORITE_IDS_KEY, entityType] as const,
68
+ queryFn: () => getFavoriteIdsFn({ data: { entityType } }),
69
+ })
@@ -0,0 +1,63 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+
5
+ // notifications 模块 queryOptions 工厂(key + queryFn 单一来源)。
6
+ //
7
+ // key 常量原本散在 hooks/use-notifications.ts(NOTIFICATION_*)与
8
+ // settings-notifications.tsx(preferences 内联字面量),消费方(loader prefetch
9
+ // / 组件 useQuery / invalidate / setQueryData)一律从本模块取,禁止再写内联
10
+ // 字面量。模式说明见 ./README.md。
11
+ import { infiniteQueryOptions, queryOptions } from '@tanstack/react-query'
12
+ import type { NotificationCategory, NotificationListResult } from '@allbluecn/kernel'
13
+ import {
14
+ getNotificationPreferencesFn,
15
+ getUnreadCountFn,
16
+ listNotificationsFn,
17
+ } from '@/server/serverFns/notifications'
18
+
19
+ export const NOTIFICATION_ROOT_KEY = ['notifications'] as const
20
+ export const NOTIFICATION_LIST_KEY = ['notifications', 'list'] as const
21
+ export const NOTIFICATION_POPOVER_KEY = ['notifications', 'popover'] as const
22
+ export const NOTIFICATION_UNREAD_KEY = ['notifications', 'unread'] as const
23
+ export const NOTIFICATION_PREFERENCES_KEY = ['notifications', 'preferences'] as const
24
+
25
+ /** 未读数(SSE setQueryData 写入目标;loader SSR 预取 + 铃铛消费) */
26
+ export const notificationsUnreadQueryOptions = () =>
27
+ queryOptions({
28
+ queryKey: NOTIFICATION_UNREAD_KEY,
29
+ queryFn: () => getUnreadCountFn({ data: {} }),
30
+ })
31
+
32
+ /** 通知偏好(settings 面板读写 + useNotifications 预热供 DND 判断) */
33
+ export const notificationPreferencesQueryOptions = () =>
34
+ queryOptions({
35
+ queryKey: NOTIFICATION_PREFERENCES_KEY,
36
+ queryFn: () => getNotificationPreferencesFn({ data: {} }),
37
+ })
38
+
39
+ /** 铃铛 popover 未读列表(非分页形态,与列表查询必须独立 key) */
40
+ export const notificationsPopoverUnreadQueryOptions = () =>
41
+ queryOptions({
42
+ queryKey: [...NOTIFICATION_POPOVER_KEY, 'status', 'unread'] as const,
43
+ queryFn: () => listNotificationsFn({ data: { status: 'unread' } }),
44
+ })
45
+
46
+ /**
47
+ * 通知列表(分页 + 分类过滤)。
48
+ * category 传 undefined 表示「全部」(与旧 [...NOTIFICATION_LIST_KEY, undefined] 同形)。
49
+ */
50
+ export const notificationsListInfiniteQueryOptions = (category?: NotificationCategory) =>
51
+ infiniteQueryOptions({
52
+ queryKey: [...NOTIFICATION_LIST_KEY, category],
53
+ queryFn: ({ pageParam }) => {
54
+ const base = category ? { category } : {}
55
+ return listNotificationsFn({
56
+ data: pageParam ? { ...base, cursor: pageParam } : base,
57
+ })
58
+ },
59
+ initialPageParam: undefined as string | undefined,
60
+ getNextPageParam: (lastPage: NotificationListResult) =>
61
+ // .at(-1) 防御 hasMore=true 而 items 为空的服务端边界 bug([-1].id 会抛 TypeError)
62
+ lastPage.hasMore ? lastPage.items.at(-1)?.id : undefined,
63
+ })
@@ -0,0 +1,39 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+
5
+ // team 模块 queryOptions 工厂(key + queryFn 单一来源)。
6
+ // 消费方(组件 useQuery / invalidate)一律从本模块取,禁止再写
7
+ // ['teamMembers'] 等内联字面量。模式说明见 ./README.md。
8
+ //
9
+ // ⚠ tiptap mention-dropdown-menu 的 ['teamUsers'] 是另一数据源
10
+ // (编辑器 mentionUserSource),与本工厂同 key 不同 queryFn,属既有
11
+ // 缓存共键碰撞,迁移时禁止单方面改其一(缓存行为会漂移)。
12
+ import { queryOptions } from '@tanstack/react-query'
13
+ import {
14
+ listTeamMembersFn,
15
+ listTeamInvitationsFn,
16
+ listTeamUsersFn,
17
+ } from '@/server/serverFns/team'
18
+
19
+ export const TEAM_MEMBERS_QUERY_KEY = ['teamMembers'] as const
20
+ export const TEAM_INVITATIONS_QUERY_KEY = ['teamInvitations'] as const
21
+ export const TEAM_USERS_QUERY_KEY = ['teamUsers'] as const
22
+
23
+ export const teamMembersQueryOptions = () =>
24
+ queryOptions({
25
+ queryKey: TEAM_MEMBERS_QUERY_KEY,
26
+ queryFn: () => listTeamMembersFn(),
27
+ })
28
+
29
+ export const teamInvitationsQueryOptions = () =>
30
+ queryOptions({
31
+ queryKey: TEAM_INVITATIONS_QUERY_KEY,
32
+ queryFn: () => listTeamInvitationsFn(),
33
+ })
34
+
35
+ export const teamUsersQueryOptions = () =>
36
+ queryOptions({
37
+ queryKey: TEAM_USERS_QUERY_KEY,
38
+ queryFn: () => listTeamUsersFn(),
39
+ })
@@ -0,0 +1,8 @@
1
+ // 全局查询默认 staleTime:30 秒(毫秒常量)。
2
+ // - 30s 内纯导航:loader 的 ensureQueryData / useQuery 命中缓存不重跑
3
+ // - mutation 后 invalidateQueries 不受 staleTime 阻断:显式失效把 fresh 数据
4
+ // 标记为 stale,active 查询立即 refetch、非 active 查询在下次访问时重拉
5
+ // - SSR:水合数据携带服务端 dataUpdatedAt,30s 窗口内客户端不重复请求(期望行为)
6
+ // 单一来源:router.tsx 的 defaultOptions 与协同测试
7
+ // (lib/__tests__/query-defaults.test.ts)共同引用本常量。
8
+ export const QUERY_STALE_TIME_MS = 30_000