@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
@@ -2,14 +2,13 @@
2
2
  // (我的任务列表)/ getAiTaskFn(任务详情 + run 历史)。本文件只准导出 createServerFn
3
3
  // 产物(纯净红线,CI 守护):serializeTask、probeSourceExists 等辅助逻辑一律文件内
4
4
  // 非导出成员。
5
- // 鉴权惯例(同 testcase-crud):serverFn 是独立 RPC 入口,路由层守卫拦不到,handler
6
- // 首行业务必须 requireAuth(getRequest()) 自查。
5
+ // 鉴权惯例(同 testcase-crud):serverFn 是独立 RPC 入口,路由层守卫拦不到,
6
+ // 链上挂 authContextMiddleware 注入 context.user。
7
7
  import { getPrisma } from "@allbluecn/database/get-prisma";
8
8
  import type { Prisma } from "@allbluecn/database";
9
9
  import { createServerFn } from "@tanstack/react-start";
10
- import { getRequest } from "@tanstack/react-start/server";
11
10
  import { z } from "zod";
12
- import { requireAuth } from "@/server/auth-helpers";
11
+ import { authContextMiddleware } from '@/server/middlewares/auth-context'
13
12
  import { fetchAssignedToMe } from "@/server/ai-task/assigned-query";
14
13
  import type { AssignedResult } from "@/server/ai-task/types";
15
14
 
@@ -58,11 +57,9 @@ async function probeSourceExists(
58
57
  }
59
58
 
60
59
  /** 「分配给我的」三表聚合(story → bug → testcase),直接透传任务 3 的查询结果 */
61
- export const listAssignedToMeFn = createServerFn({ method: "GET" }).handler(
62
- async (): Promise<AssignedResult> => {
63
- const request = getRequest();
64
- const session = await requireAuth(request);
65
- const userId = session.user.id;
60
+ export const listAssignedToMeFn = createServerFn({ method: "GET" }).middleware([authContextMiddleware]).handler(
61
+ async ({ context }): Promise<AssignedResult> => {
62
+ const userId = context.user.id;
66
63
 
67
64
  return fetchAssignedToMe(userId);
68
65
  },
@@ -70,11 +67,9 @@ export const listAssignedToMeFn = createServerFn({ method: "GET" }).handler(
70
67
 
71
68
  /** 我的任务列表:归属圈定 + updatedAt 倒序投影(含 instruction 供前端指令搜索,
72
69
  * useTaskFilter 纯函数按字段存在性自适应——任务 47 的过渡兼容即插即用) */
73
- export const listAiTasksFn = createServerFn({ method: "GET" }).handler(
74
- async () => {
75
- const request = getRequest();
76
- const session = await requireAuth(request);
77
- const userId = session.user.id;
70
+ export const listAiTasksFn = createServerFn({ method: "GET" }).middleware([authContextMiddleware]).handler(
71
+ async ({ context }) => {
72
+ const userId = context.user.id;
78
73
 
79
74
  const prisma = await getPrisma();
80
75
  const rows = await prisma.aiTask.findMany({
@@ -113,15 +108,14 @@ const getAiTaskSchema = z.object({ id: z.string().min(1) });
113
108
 
114
109
  /** 任务详情:全字段 task(附关联项目名,信息区展示)+ run 历史(startedAt 倒序)+ 源条目存在性 */
115
110
  export const getAiTaskFn = createServerFn({ method: "GET" })
111
+ .middleware([authContextMiddleware])
116
112
  .validator(getAiTaskSchema)
117
- .handler(async ({ data }): Promise<{
113
+ .handler(async ({ data, context }): Promise<{
118
114
  task: ReturnType<typeof serializeTask> & { projectName: string | null };
119
115
  runs: AiTaskRunRow[];
120
116
  sourceExists: boolean | null;
121
117
  }> => {
122
- const request = getRequest();
123
- const session = await requireAuth(request);
124
- const userId = session.user.id;
118
+ const userId = context.user.id;
125
119
 
126
120
  const prisma = await getPrisma();
127
121
 
@@ -3,7 +3,7 @@ import { createServerFn } from '@tanstack/react-start'
3
3
  import { getRequest } from '@tanstack/react-start/server'
4
4
  import crypto from 'node:crypto'
5
5
  import { z } from 'zod'
6
- import { requireAuth } from '@/server/auth-helpers'
6
+ import { authContextMiddleware } from '@/server/middlewares/auth-context'
7
7
  import { assertOwned } from '@/server/lib/ownership'
8
8
  import { requireTeamSeats } from '@/server/resources'
9
9
  import { auditLog } from '@/server/audit'
@@ -31,12 +31,11 @@ const createInvitationSchema = z.object({
31
31
  })
32
32
 
33
33
  export const createTeamInvitationFn = createServerFn({ method: 'POST' })
34
+ .middleware([authContextMiddleware])
34
35
  .validator(createInvitationSchema)
35
- .handler(async ({ data }) => {
36
+ .handler(async ({ data, context }) => {
36
37
  const prisma = await getPrisma()
37
- const request = getRequest()
38
- const session = await requireAuth(request)
39
- const ownerId = session.user.id
38
+ const ownerId = context.user.id
40
39
 
41
40
  const email = data.channel === 'email' ? data.email!.toLowerCase() : null
42
41
 
@@ -129,12 +128,10 @@ export const createTeamInvitationFn = createServerFn({ method: 'POST' })
129
128
  return { success: true, token, invitationId: invitation.id }
130
129
  })
131
130
 
132
- export const listTeamInvitationsFn = createServerFn({ method: 'GET' }).handler(async () => {
131
+ export const listTeamInvitationsFn = createServerFn({ method: 'GET' }).middleware([authContextMiddleware]).handler(async ({ context }) => {
133
132
  const prisma = await getPrisma()
134
133
  try {
135
- const request = getRequest()
136
- const session = await requireAuth(request)
137
- const ownerId = session.user.id
134
+ const ownerId = context.user.id
138
135
  const now = new Date()
139
136
 
140
137
  await prisma.teamInvitation.updateMany({
@@ -187,12 +184,11 @@ export const listTeamInvitationsFn = createServerFn({ method: 'GET' }).handler(a
187
184
  const revokeSchema = z.object({ invitationId: z.string() })
188
185
 
189
186
  export const clearExpiredInvitationsFn = createServerFn({ method: 'POST' })
187
+ .middleware([authContextMiddleware])
190
188
  .validator(z.object({}))
191
- .handler(async () => {
189
+ .handler(async ({ context }) => {
192
190
  const prisma = await getPrisma()
193
- const request = getRequest()
194
- const session = await requireAuth(request)
195
- const ownerId = session.user.id
191
+ const ownerId = context.user.id
196
192
  const res = await prisma.teamInvitation.deleteMany({
197
193
  where: { ownerId, status: 'expired', channel: 'email' },
198
194
  })
@@ -208,12 +204,11 @@ export const clearExpiredInvitationsFn = createServerFn({ method: 'POST' })
208
204
  })
209
205
 
210
206
  export const revokeTeamInvitationFn = createServerFn({ method: 'POST' })
207
+ .middleware([authContextMiddleware])
211
208
  .validator(revokeSchema)
212
- .handler(async ({ data }) => {
209
+ .handler(async ({ data, context }) => {
213
210
  const prisma = await getPrisma()
214
- const request = getRequest()
215
- const session = await requireAuth(request)
216
- const ownerId = session.user.id
211
+ const ownerId = context.user.id
217
212
  // DB-03:属主校验并入单次 findFirst(消除查后比对二次往返与 TOCTOU),文案保持
218
213
  const inv = await assertOwned(prisma.teamInvitation, { where: { id: data.invitationId, ownerId } }, '邀请不存在')
219
214
  if (inv.status !== 'pending' && inv.status !== 'pending_approval') throw new Error('仅待处理/待批准邀请可撤销')
@@ -238,12 +233,11 @@ export const revokeTeamInvitationFn = createServerFn({ method: 'POST' })
238
233
  })
239
234
 
240
235
  export const resendTeamInvitationFn = createServerFn({ method: 'POST' })
236
+ .middleware([authContextMiddleware])
241
237
  .validator(revokeSchema)
242
- .handler(async ({ data }) => {
238
+ .handler(async ({ data, context }) => {
243
239
  const prisma = await getPrisma()
244
- const request = getRequest()
245
- const session = await requireAuth(request)
246
- const ownerId = session.user.id
240
+ const ownerId = context.user.id
247
241
  // DB-03:属主校验并入单次 findFirst(消除查后比对二次往返与 TOCTOU),文案保持
248
242
  const inv = await assertOwned(prisma.teamInvitation, { where: { id: data.invitationId, ownerId } }, '邀请不存在')
249
243
  if (inv.status !== 'pending' && inv.status !== 'expired') {
@@ -282,12 +276,11 @@ export const resendTeamInvitationFn = createServerFn({ method: 'POST' })
282
276
  })
283
277
 
284
278
  export const refreshTeamInvitationLinkFn = createServerFn({ method: 'POST' })
279
+ .middleware([authContextMiddleware])
285
280
  .validator(z.object({ expiresInDays: z.number().int().min(1).max(365).optional() }))
286
- .handler(async ({ data }) => {
281
+ .handler(async ({ data, context }) => {
287
282
  const prisma = await getPrisma()
288
- const request = getRequest()
289
- const session = await requireAuth(request)
290
- const ownerId = session.user.id
283
+ const ownerId = context.user.id
291
284
 
292
285
  await requireTeamSeats(ownerId, 'member', 1)
293
286
 
@@ -333,11 +326,9 @@ export const refreshTeamInvitationLinkFn = createServerFn({ method: 'POST' })
333
326
 
334
327
  // ---------- 成员管理 ----------
335
328
 
336
- export const listTeamMembersFn = createServerFn({ method: 'GET' }).handler(async () => {
329
+ export const listTeamMembersFn = createServerFn({ method: 'GET' }).middleware([authContextMiddleware]).handler(async ({ context }) => {
337
330
  const prisma = await getPrisma()
338
- const request = getRequest()
339
- const session = await requireAuth(request)
340
- const ownerId = session.user.id
331
+ const ownerId = context.user.id
341
332
 
342
333
  // 以 memberId 判当前用户的归属:避免为已是别家成员的账号创建自引用 owner 记录(P2002)
343
334
  const ownEntry = await prisma.teamMembership.findUnique({
@@ -378,12 +369,11 @@ export const listTeamMembersFn = createServerFn({ method: 'GET' }).handler(async
378
369
  const removeMemberSchema = z.object({ membershipId: z.string() })
379
370
 
380
371
  export const removeTeamMemberFn = createServerFn({ method: 'POST' })
372
+ .middleware([authContextMiddleware])
381
373
  .validator(removeMemberSchema)
382
- .handler(async ({ data }) => {
374
+ .handler(async ({ data, context }) => {
383
375
  const prisma = await getPrisma()
384
- const request = getRequest()
385
- const session = await requireAuth(request)
386
- const ownerId = session.user.id
376
+ const ownerId = context.user.id
387
377
  const m = await prisma.teamMembership.findUnique({ where: { id: data.membershipId } })
388
378
  if (!m) throw new Error('成员不存在')
389
379
  if (m.ownerId !== ownerId) throw new Error('权限不足:仅团队所有者可移除成员')
@@ -401,11 +391,9 @@ export const removeTeamMemberFn = createServerFn({ method: 'POST' })
401
391
  return { success: true }
402
392
  })
403
393
 
404
- export const leaveTeamFn = createServerFn({ method: 'POST' }).validator(z.object({})).handler(async () => {
394
+ export const leaveTeamFn = createServerFn({ method: 'POST' }).middleware([authContextMiddleware]).validator(z.object({})).handler(async ({ context }) => {
405
395
  const prisma = await getPrisma()
406
- const request = getRequest()
407
- const session = await requireAuth(request)
408
- const userId = session.user.id
396
+ const userId = context.user.id
409
397
  const m = await prisma.teamMembership.findUnique({ where: { memberId: userId } })
410
398
  if (!m) throw new Error('你未加入任何团队')
411
399
  await prisma.$transaction(async (tx) => {
@@ -430,12 +418,11 @@ const approveJoinRequestSchema = z.object({
430
418
  })
431
419
 
432
420
  export const approveTeamJoinRequestFn = createServerFn({ method: 'POST' })
421
+ .middleware([authContextMiddleware])
433
422
  .validator(approveJoinRequestSchema)
434
- .handler(async ({ data }) => {
423
+ .handler(async ({ data, context }) => {
435
424
  const prisma = await getPrisma()
436
- const request = getRequest()
437
- const session = await requireAuth(request)
438
- const ownerId = session.user.id
425
+ const ownerId = context.user.id
439
426
 
440
427
  // DB-03:属主校验并入单次 findFirst(include 关系一并取回)。
441
428
  // 此处内联 findFirst 而非 assertOwned:include 投影类型(reqRow.invitation)需走
@@ -499,12 +486,11 @@ export const approveTeamJoinRequestFn = createServerFn({ method: 'POST' })
499
486
  })
500
487
 
501
488
  export const rejectTeamJoinRequestFn = createServerFn({ method: 'POST' })
489
+ .middleware([authContextMiddleware])
502
490
  .validator(joinRequestSchema)
503
- .handler(async ({ data }) => {
491
+ .handler(async ({ data, context }) => {
504
492
  const prisma = await getPrisma()
505
- const request = getRequest()
506
- const session = await requireAuth(request)
507
- const ownerId = session.user.id
493
+ const ownerId = context.user.id
508
494
 
509
495
  // DB-03:属主校验并入单次 findFirst
510
496
  const reqRow = await assertOwned(prisma.teamJoinRequest, { where: { id: data.requestId, ownerId } }, '申请不存在')
@@ -527,12 +513,11 @@ export const rejectTeamJoinRequestFn = createServerFn({ method: 'POST' })
527
513
  })
528
514
 
529
515
  export const deleteTeamInvitationFn = createServerFn({ method: 'POST' })
516
+ .middleware([authContextMiddleware])
530
517
  .validator(revokeSchema)
531
- .handler(async ({ data }) => {
518
+ .handler(async ({ data, context }) => {
532
519
  const prisma = await getPrisma()
533
- const request = getRequest()
534
- const session = await requireAuth(request)
535
- const ownerId = session.user.id
520
+ const ownerId = context.user.id
536
521
 
537
522
  // DB-03:属主校验并入单次 findFirst
538
523
  const invRow = await assertOwned(prisma.teamInvitation, { where: { id: data.invitationId, ownerId } }, '邀请不存在')
@@ -553,12 +538,11 @@ export const deleteTeamInvitationFn = createServerFn({ method: 'POST' })
553
538
  })
554
539
 
555
540
  export const deleteTeamJoinRequestFn = createServerFn({ method: 'POST' })
541
+ .middleware([authContextMiddleware])
556
542
  .validator(joinRequestSchema)
557
- .handler(async ({ data }) => {
543
+ .handler(async ({ data, context }) => {
558
544
  const prisma = await getPrisma()
559
- const request = getRequest()
560
- const session = await requireAuth(request)
561
- const ownerId = session.user.id
545
+ const ownerId = context.user.id
562
546
 
563
547
  // DB-03:属主校验并入单次 findFirst
564
548
  const reqRow = await assertOwned(prisma.teamJoinRequest, { where: { id: data.requestId, ownerId } }, '申请不存在')
@@ -576,11 +560,9 @@ export const deleteTeamJoinRequestFn = createServerFn({ method: 'POST' })
576
560
  return { success: true }
577
561
  })
578
562
 
579
- export const listTeamUsersFn = createServerFn({ method: 'GET' }).handler(async () => {
563
+ export const listTeamUsersFn = createServerFn({ method: 'GET' }).middleware([authContextMiddleware]).handler(async ({ context }) => {
580
564
  const prisma = await getPrisma()
581
- const request = getRequest()
582
- const session = await requireAuth(request)
583
- const userId = session.user.id
565
+ const userId = context.user.id
584
566
  const joined = await prisma.teamMembership.findUnique({ where: { memberId: userId } })
585
567
  const ownerId = joined ? joined.ownerId : userId
586
568
  const [owner, members] = await Promise.all([
@@ -796,17 +778,16 @@ export const applyTeamInvitationFn = createServerFn({ method: 'POST' })
796
778
  })
797
779
 
798
780
  export const acceptTeamInvitationFn = createServerFn({ method: 'POST' })
781
+ .middleware([authContextMiddleware])
799
782
  .validator(tokenSchema)
800
- .handler(async ({ data }) => {
783
+ .handler(async ({ data, context }) => {
801
784
  const prisma = await getPrisma()
802
- const request = getRequest()
803
- const session = await requireAuth(request)
804
- const userId = session.user.id
785
+ const userId = context.user.id
805
786
  const currentUser = await prisma.user.findUnique({
806
787
  where: { id: userId },
807
788
  select: { email: true },
808
789
  })
809
- const email = (currentUser?.email ?? session.user.email ?? '').toLowerCase()
790
+ const email = (currentUser?.email ?? context.user.email ?? '').toLowerCase()
810
791
  if (!email) throw new Error('当前账号缺少邮箱,无法申请')
811
792
 
812
793
  const inv = await prisma.teamInvitation.findUnique({ where: { token: data.token } })
@@ -864,12 +845,11 @@ const approveSchema = z.object({
864
845
  })
865
846
 
866
847
  export const approveTeamInvitationFn = createServerFn({ method: 'POST' })
848
+ .middleware([authContextMiddleware])
867
849
  .validator(approveSchema)
868
- .handler(async ({ data }) => {
850
+ .handler(async ({ data, context }) => {
869
851
  const prisma = await getPrisma()
870
- const request = getRequest()
871
- const session = await requireAuth(request)
872
- const ownerId = session.user.id
852
+ const ownerId = context.user.id
873
853
 
874
854
  // DB-03:属主校验并入单次 findFirst
875
855
  const inv = await assertOwned(prisma.teamInvitation, { where: { id: data.invitationId, ownerId } }, '邀请不存在')
@@ -72,24 +72,57 @@ const PRISMA = H.prisma;
72
72
  vi.mock("@tanstack/react-start", () => {
73
73
  // 每个 serverFn 实例独立持有自己的 capture,避免同模块多实例共用导致 validator 串号
74
74
  const createServerFn = () => {
75
- const capture: { validator?: unknown; handler?: unknown } = {};
75
+ const capture: { validator?: unknown; handler?: unknown; middlewares?: unknown[] } = {};
76
76
  const api = {
77
77
  validator: (v: unknown) => {
78
78
  capture.validator = v;
79
79
  return api;
80
80
  },
81
+ middleware: (mws: unknown[]) => {
82
+ capture.middlewares = mws;
83
+ return api;
84
+ },
81
85
  handler: (h: unknown) => {
82
86
  capture.handler = h;
83
87
  return async (args: { data: unknown }) => {
84
88
  const v = capture.validator as { parse?: (d: unknown) => unknown } | undefined;
85
89
  const data = v && v.parse ? v.parse(args.data) : args.data;
86
- return (h as (p: { data: unknown }) => Promise<unknown>)({ data });
90
+ // 迁移后经 .middleware([authContextMiddleware]) 注入 context.user:
91
+ // 依序执行 middleware 的 server 段,真实鉴权链由被 mock 的 auth-helpers 承接
92
+ let context: Record<string, unknown> = {};
93
+ for (const mw of capture.middlewares ?? []) {
94
+ const serverFn = (mw as { options?: { server?: unknown } })?.options?.server;
95
+ if (typeof serverFn !== "function") continue;
96
+ const result = await (
97
+ serverFn as (p: unknown) => Promise<{ context?: unknown }>
98
+ )({
99
+ data,
100
+ context,
101
+ method: "POST",
102
+ serverFnMeta: {},
103
+ signal: new AbortController().signal,
104
+ next: async (inner: { context?: unknown }) => ({
105
+ context: { ...context, ...(inner?.context ?? {}) },
106
+ }),
107
+ });
108
+ context = (result?.context ?? context) as Record<string, unknown>;
109
+ }
110
+ return (h as (p: { data: unknown; context: unknown }) => Promise<unknown>)({ data, context });
87
111
  };
88
112
  },
89
113
  };
90
114
  return api;
91
115
  };
92
- return { createServerFn };
116
+ // auth-context.ts 依赖 createMiddleware({ type: 'function' }).server(fn)
117
+ const createMiddleware = (opts?: { type?: string }) => {
118
+ const mw: { options: { type?: string; server?: unknown }; server?: unknown } = { options: { type: opts?.type } };
119
+ mw.server = (fn: unknown) => {
120
+ mw.options.server = fn;
121
+ return mw;
122
+ };
123
+ return mw;
124
+ };
125
+ return { createServerFn, createMiddleware };
93
126
  });
94
127
 
95
128
  vi.mock("@tanstack/react-start/server", () => ({ getRequest: () => REQ }));
@@ -223,7 +256,7 @@ describe("generateArtifactFn", () => {
223
256
  ).resolves.toMatchObject({ artifact: expect.anything() });
224
257
  });
225
258
 
226
- it("requireFeature 第一行门控 + AI 调用走 testgen bizKey + testcase.automation promptKey 覆盖", async () => {
259
+ it("requireFeature 门控先于业务逻辑(认证经 authContextMiddleware 前置)+ AI 调用走 testgen bizKey + testcase.automation promptKey 覆盖", async () => {
227
260
  M.runChatAsAgent.mockResolvedValue(aiOutput());
228
261
  M.runVitestSpec.mockResolvedValue(runResult());
229
262
 
@@ -231,7 +264,7 @@ describe("generateArtifactFn", () => {
231
264
 
232
265
  expect(M.requireFeature).toHaveBeenCalledWith(REQ, "testGeneration");
233
266
  expect(M.requireFeature.mock.invocationCallOrder[0]).toBeLessThan(
234
- M.requireAuth.mock.invocationCallOrder[0],
267
+ M.checkAiRateLimit.mock.invocationCallOrder[0],
235
268
  );
236
269
  expect(M.checkAiRateLimit).toHaveBeenCalledWith(U, "testGeneration");
237
270
  expect(M.runChatAsAgent).toHaveBeenCalledTimes(1);
@@ -33,25 +33,59 @@ const M = H.fns;
33
33
  const BLOB_PUT = H.blobPut;
34
34
 
35
35
  vi.mock("@tanstack/react-start", () => {
36
+ // 每个 serverFn 实例独立持有自己的 capture,避免同模块多实例共用导致 validator 串号
36
37
  const createServerFn = () => {
37
- const capture: { validator?: unknown; handler?: unknown } = {};
38
+ const capture: { validator?: unknown; handler?: unknown; middlewares?: unknown[] } = {};
38
39
  const api = {
39
40
  validator: (v: unknown) => {
40
41
  capture.validator = v;
41
42
  return api;
42
43
  },
44
+ middleware: (mws: unknown[]) => {
45
+ capture.middlewares = mws;
46
+ return api;
47
+ },
43
48
  handler: (h: unknown) => {
44
49
  capture.handler = h;
45
50
  return async (args: { data: unknown }) => {
46
51
  const v = capture.validator as { parse?: (d: unknown) => unknown } | undefined;
47
52
  const data = v && v.parse ? v.parse(args.data) : args.data;
48
- return (h as (p: { data: unknown }) => Promise<unknown>)({ data });
53
+ // 迁移后经 .middleware([authContextMiddleware]) 注入 context.user:
54
+ // 依序执行 middleware 的 server 段,真实鉴权链由被 mock 的 auth-helpers 承接
55
+ let context: Record<string, unknown> = {};
56
+ for (const mw of capture.middlewares ?? []) {
57
+ const serverFn = (mw as { options?: { server?: unknown } })?.options?.server;
58
+ if (typeof serverFn !== "function") continue;
59
+ const result = await (
60
+ serverFn as (p: unknown) => Promise<{ context?: unknown }>
61
+ )({
62
+ data,
63
+ context,
64
+ method: "POST",
65
+ serverFnMeta: {},
66
+ signal: new AbortController().signal,
67
+ next: async (inner: { context?: unknown }) => ({
68
+ context: { ...context, ...(inner?.context ?? {}) },
69
+ }),
70
+ });
71
+ context = (result?.context ?? context) as Record<string, unknown>;
72
+ }
73
+ return (h as (p: { data: unknown; context: unknown }) => Promise<unknown>)({ data, context });
49
74
  };
50
75
  },
51
76
  };
52
77
  return api;
53
78
  };
54
- return { createServerFn };
79
+ // auth-context.ts 依赖 createMiddleware({ type: 'function' }).server(fn)
80
+ const createMiddleware = (opts?: { type?: string }) => {
81
+ const mw: { options: { type?: string; server?: unknown }; server?: unknown } = { options: { type: opts?.type } };
82
+ mw.server = (fn: unknown) => {
83
+ mw.options.server = fn;
84
+ return mw;
85
+ };
86
+ return mw;
87
+ };
88
+ return { createServerFn, createMiddleware };
55
89
  });
56
90
 
57
91
  vi.mock("@tanstack/react-start/server", () => ({ getRequest: () => ({}) }));
@@ -82,24 +82,57 @@ const PRISMA = H.prisma;
82
82
  vi.mock("@tanstack/react-start", () => {
83
83
  // 每个 serverFn 实例独立持有自己的 capture,避免同模块多实例共用导致 validator 串号
84
84
  const createServerFn = () => {
85
- const capture: { validator?: unknown; handler?: unknown } = {};
85
+ const capture: { validator?: unknown; handler?: unknown; middlewares?: unknown[] } = {};
86
86
  const api = {
87
87
  validator: (v: unknown) => {
88
88
  capture.validator = v;
89
89
  return api;
90
90
  },
91
+ middleware: (mws: unknown[]) => {
92
+ capture.middlewares = mws;
93
+ return api;
94
+ },
91
95
  handler: (h: unknown) => {
92
96
  capture.handler = h;
93
97
  return async (args: { data: unknown }) => {
94
98
  const v = capture.validator as { parse?: (d: unknown) => unknown } | undefined;
95
99
  const data = v && v.parse ? v.parse(args.data) : args.data;
96
- return (h as (p: { data: unknown }) => Promise<unknown>)({ data });
100
+ // 迁移后经 .middleware([authContextMiddleware]) 注入 context.user:
101
+ // 依序执行 middleware 的 server 段,真实鉴权链由被 mock 的 auth-helpers 承接
102
+ let context: Record<string, unknown> = {};
103
+ for (const mw of capture.middlewares ?? []) {
104
+ const serverFn = (mw as { options?: { server?: unknown } })?.options?.server;
105
+ if (typeof serverFn !== "function") continue;
106
+ const result = await (
107
+ serverFn as (p: unknown) => Promise<{ context?: unknown }>
108
+ )({
109
+ data,
110
+ context,
111
+ method: "POST",
112
+ serverFnMeta: {},
113
+ signal: new AbortController().signal,
114
+ next: async (inner: { context?: unknown }) => ({
115
+ context: { ...context, ...(inner?.context ?? {}) },
116
+ }),
117
+ });
118
+ context = (result?.context ?? context) as Record<string, unknown>;
119
+ }
120
+ return (h as (p: { data: unknown; context: unknown }) => Promise<unknown>)({ data, context });
97
121
  };
98
122
  },
99
123
  };
100
124
  return api;
101
125
  };
102
- return { createServerFn };
126
+ // auth-context.ts 依赖 createMiddleware({ type: 'function' }).server(fn)
127
+ const createMiddleware = (opts?: { type?: string }) => {
128
+ const mw: { options: { type?: string; server?: unknown }; server?: unknown } = { options: { type: opts?.type } };
129
+ mw.server = (fn: unknown) => {
130
+ mw.options.server = fn;
131
+ return mw;
132
+ };
133
+ return mw;
134
+ };
135
+ return { createServerFn, createMiddleware };
103
136
  });
104
137
 
105
138
  vi.mock("@tanstack/react-start/server", () => ({ getRequest: () => REQ }));
@@ -227,7 +260,7 @@ beforeEach(() => {
227
260
  });
228
261
 
229
262
  describe("startGenerationFn", () => {
230
- it("requireFeature('testGeneration') 在认证前第一行执行(计费门控)", async () => {
263
+ it("requireFeature('testGeneration') 门控先于业务逻辑(认证经 authContextMiddleware 前置)", async () => {
231
264
  DB.storyFindUnique.mockResolvedValue({
232
265
  id: "s-1",
233
266
  projectId: P,
@@ -243,7 +276,7 @@ describe("startGenerationFn", () => {
243
276
 
244
277
  expect(M.requireFeature).toHaveBeenCalledWith(REQ, "testGeneration");
245
278
  expect(M.requireFeature.mock.invocationCallOrder[0]).toBeLessThan(
246
- M.requireAuth.mock.invocationCallOrder[0]!,
279
+ DB.storyFindUnique.mock.invocationCallOrder[0]!,
247
280
  );
248
281
  });
249
282
 
@@ -72,24 +72,57 @@ const PRISMA = H.prisma;
72
72
  vi.mock("@tanstack/react-start", () => {
73
73
  // 每个 serverFn 实例独立持有自己的 capture,避免同模块多实例共用导致 validator 串号
74
74
  const createServerFn = () => {
75
- const capture: { validator?: unknown; handler?: unknown } = {};
75
+ const capture: { validator?: unknown; handler?: unknown; middlewares?: unknown[] } = {};
76
76
  const api = {
77
77
  validator: (v: unknown) => {
78
78
  capture.validator = v;
79
79
  return api;
80
80
  },
81
+ middleware: (mws: unknown[]) => {
82
+ capture.middlewares = mws;
83
+ return api;
84
+ },
81
85
  handler: (h: unknown) => {
82
86
  capture.handler = h;
83
87
  return async (args: { data: unknown }) => {
84
88
  const v = capture.validator as { parse?: (d: unknown) => unknown } | undefined;
85
89
  const data = v && v.parse ? v.parse(args.data) : args.data;
86
- return (h as (p: { data: unknown }) => Promise<unknown>)({ data });
90
+ // 迁移后经 .middleware([authContextMiddleware]) 注入 context.user:
91
+ // 依序执行 middleware 的 server 段,真实鉴权链由被 mock 的 auth-helpers 承接
92
+ let context: Record<string, unknown> = {};
93
+ for (const mw of capture.middlewares ?? []) {
94
+ const serverFn = (mw as { options?: { server?: unknown } })?.options?.server;
95
+ if (typeof serverFn !== "function") continue;
96
+ const result = await (
97
+ serverFn as (p: unknown) => Promise<{ context?: unknown }>
98
+ )({
99
+ data,
100
+ context,
101
+ method: "POST",
102
+ serverFnMeta: {},
103
+ signal: new AbortController().signal,
104
+ next: async (inner: { context?: unknown }) => ({
105
+ context: { ...context, ...(inner?.context ?? {}) },
106
+ }),
107
+ });
108
+ context = (result?.context ?? context) as Record<string, unknown>;
109
+ }
110
+ return (h as (p: { data: unknown; context: unknown }) => Promise<unknown>)({ data, context });
87
111
  };
88
112
  },
89
113
  };
90
114
  return api;
91
115
  };
92
- return { createServerFn };
116
+ // auth-context.ts 依赖 createMiddleware({ type: 'function' }).server(fn)
117
+ const createMiddleware = (opts?: { type?: string }) => {
118
+ const mw: { options: { type?: string; server?: unknown }; server?: unknown } = { options: { type: opts?.type } };
119
+ mw.server = (fn: unknown) => {
120
+ mw.options.server = fn;
121
+ return mw;
122
+ };
123
+ return mw;
124
+ };
125
+ return { createServerFn, createMiddleware };
93
126
  });
94
127
 
95
128
  vi.mock("@tanstack/react-start/server", () => ({ getRequest: () => ({}) }));