@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
@@ -17,6 +17,7 @@
17
17
 
18
18
  import { getPrisma } from "@allbluecn/database/get-prisma"
19
19
  import { createServerFn } from "@tanstack/react-start"
20
+ import { authContextMiddleware } from "@/server/middlewares/auth-context"
20
21
  import { getRequest } from "@tanstack/react-start/server"
21
22
  import { z } from "zod"
22
23
  import { getCurrentSession } from "@/lib/session"
@@ -72,13 +73,11 @@ export const getGithubConnectionFn = createServerFn({ method: "GET" })
72
73
  })
73
74
 
74
75
  export const listGithubReposFn = createServerFn({ method: "GET" })
75
- .handler(async () => {
76
+ .middleware([authContextMiddleware])
77
+ .handler(async ({ context }) => {
76
78
  const prisma = await getPrisma()
77
- const request = getRequest()
78
- const session = await getCurrentSession(request)
79
- if (!session?.user?.id) throw new Error("Unauthorized")
80
79
 
81
- const { token } = await resolveGithubToken(session.user.id)
80
+ const { token } = await resolveGithubToken(context.user.id)
82
81
 
83
82
  if (!token) return { repos: [] }
84
83
 
@@ -118,14 +117,12 @@ export const listGithubReposFn = createServerFn({ method: "GET" })
118
117
  * 获取指定仓库的分支列表。
119
118
  */
120
119
  export const listGithubBranchesFn = createServerFn({ method: "GET" })
120
+ .middleware([authContextMiddleware])
121
121
  .validator(githubRepoRefSchema)
122
- .handler(async ({ data: { owner, repo } }) => {
122
+ .handler(async ({ data: { owner, repo }, context }) => {
123
123
  const prisma = await getPrisma()
124
- const request = getRequest()
125
- const session = await getCurrentSession(request)
126
- if (!session?.user?.id) throw new Error("Unauthorized")
127
124
 
128
- const userId = session.user.id
125
+ const userId = context.user.id
129
126
 
130
127
  const providerConfig = await prisma.aiProviderConfig.findFirst({
131
128
  where: { userId, providerId: "github" },
@@ -176,21 +173,19 @@ export const listGithubBranchesFn = createServerFn({ method: "GET" })
176
173
  * BYOK 优先策略:默认只存 session 级 Account,用户显式「保存到服务器」才落库加密。
177
174
  */
178
175
  export const saveGithubTokenFn = createServerFn({ method: "POST" })
176
+ .middleware([authContextMiddleware])
179
177
  // max(255):GitHub 各类 token 远短于此,超长即误填/滥用
180
178
  // (不做前缀白名单:OAuth App 存量 token 为 40 位十六进制无前缀,前缀校验会误杀)
181
179
  .validator(z.object({ token: z.string().min(1).max(255) }))
182
- .handler(async ({ data: { token } }) => {
180
+ .handler(async ({ data: { token }, context }) => {
183
181
  const prisma = await getPrisma()
184
- const request = getRequest()
185
- const session = await getCurrentSession(request)
186
- if (!session?.user?.id) throw new Error("Unauthorized")
187
182
 
188
183
  const encrypted = encryptApiKey(token)
189
184
  await prisma.aiProviderConfig.upsert({
190
- where: { userId_providerId: { userId: session.user.id, providerId: "github" } },
185
+ where: { userId_providerId: { userId: context.user.id, providerId: "github" } },
191
186
  update: { apiKey: encrypted },
192
187
  create: {
193
- userId: session.user.id,
188
+ userId: context.user.id,
194
189
  providerId: "github",
195
190
  apiKey: encrypted,
196
191
  },
@@ -203,14 +198,12 @@ export const saveGithubTokenFn = createServerFn({ method: "POST" })
203
198
  * 清除保存的 GitHub token。
204
199
  */
205
200
  export const clearGithubTokenFn = createServerFn({ method: "POST" })
206
- .handler(async () => {
201
+ .middleware([authContextMiddleware])
202
+ .handler(async ({ context }) => {
207
203
  const prisma = await getPrisma()
208
- const request = getRequest()
209
- const session = await getCurrentSession(request)
210
- if (!session?.user?.id) throw new Error("Unauthorized")
211
204
 
212
205
  await prisma.aiProviderConfig.deleteMany({
213
- where: { providerId: "github", userId: session.user.id },
206
+ where: { providerId: "github", userId: context.user.id },
214
207
  })
215
208
 
216
209
  return { success: true }
@@ -16,13 +16,13 @@
16
16
  // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
 
18
18
  import { createServerFn } from "@tanstack/react-start"
19
+ import { authContextMiddleware } from "@/server/middlewares/auth-context"
19
20
  import { getRequest } from "@tanstack/react-start/server"
20
21
  import { getPrisma } from "@allbluecn/database/get-prisma"
21
22
  import { z } from "zod"
22
- import { generateImageForUser, generateVideoForUser, pollVideoForUser, generateSpeechForUser, generateTranscriptionForUser, generatePrototypeForUser } from "@/server/ai-gateway/media"
23
+ import { generateImageForUser, generateSpeechForUser, generateTranscriptionForUser, generatePrototypeForUser } from "@/server/ai-gateway/media"
23
24
  import { resolveAiConfig } from "@/server/ai-gateway/adapter"
24
25
  import { checkAiRateLimit } from "@/server/lib/rate-limit"
25
- import { requireAuth } from "@/server/auth-helpers"
26
26
  import { requireFeature } from "@/server/entitlements"
27
27
  import { requireResource } from "@/server/resources"
28
28
 
@@ -43,18 +43,17 @@ const GenerateImageSchema = z.object({
43
43
  })
44
44
 
45
45
  export const generateImageFn = createServerFn({ method: "POST" })
46
+ .middleware([authContextMiddleware])
46
47
  .validator(GenerateImageSchema)
47
- .handler(async ({ data }) => {
48
+ .handler(async ({ data, context }) => {
48
49
  const prisma = await getPrisma()
49
50
  const request = getRequest()
50
51
  await requireFeature(request, "mediaGeneration")
51
52
  await requireResource(request, "mediaGenerationsMonthly")
52
-
53
- const session = await requireAuth(request)
54
- if (!session?.user?.id) {
53
+ if (!context.user.id) {
55
54
  return { error: "Unauthorized" }
56
55
  }
57
- const userId = session.user.id
56
+ const userId = context.user.id
58
57
  await checkAiRateLimit(userId, "mediaImage")
59
58
  const thread = await prisma.chatThread.findFirst({
60
59
  where: { id: data.threadId, userId }, select: { id: true },
@@ -89,101 +88,6 @@ export const generateImageFn = createServerFn({ method: "POST" })
89
88
  }
90
89
  })
91
90
 
92
- const GenerateVideoSchema = z.object({
93
- prompt: z.string().min(1),
94
- duration: z.number().optional(),
95
- size: z.string().optional(),
96
- referenceImage: z.string().min(1).optional(),
97
- threadId: z.string(),
98
- })
99
-
100
- export const startVideoFn = createServerFn({ method: "POST" })
101
- .validator(GenerateVideoSchema)
102
- .handler(async ({ data }) => {
103
- const prisma = await getPrisma()
104
- const request = getRequest()
105
- await requireFeature(request, "mediaGeneration")
106
- await requireResource(request, "mediaGenerationsMonthly")
107
-
108
- const session = await requireAuth(request)
109
- if (!session?.user?.id) {
110
- return { error: "Unauthorized" }
111
- }
112
- const userId = session.user.id
113
- await checkAiRateLimit(userId, "mediaVideo")
114
- const thread = await prisma.chatThread.findFirst({
115
- where: { id: data.threadId, userId }, select: { id: true },
116
- })
117
- if (!thread) throw new Error("Thread not found")
118
-
119
- const aiConfig = await resolveAiConfig(userId)
120
- if (!aiConfig) {
121
- return { error: "AI key not configured" }
122
- }
123
-
124
- const result = await generateVideoForUser({
125
- userId,
126
- threadId: data.threadId,
127
- prompt: data.prompt,
128
- duration: data.duration,
129
- size: data.size,
130
- referenceImage: data.referenceImage,
131
- adapterKind: aiConfig.provider,
132
- apiKey: aiConfig.apiKey,
133
- model: aiConfig.model,
134
- ...(aiConfig.baseUrl ? { baseURL: aiConfig.baseUrl } : {}),
135
- })
136
-
137
- return { jobId: result.jobId }
138
- })
139
-
140
- const PollVideoSchema = z.object({
141
- jobId: z.string(),
142
- threadId: z.string(),
143
- })
144
-
145
- export const pollVideoFn = createServerFn({ method: "POST" })
146
- .validator(PollVideoSchema)
147
- .handler(async ({ data }) => {
148
- const prisma = await getPrisma()
149
- const request = getRequest()
150
- await requireFeature(request, "mediaGeneration")
151
-
152
- const session = await requireAuth(request)
153
- if (!session?.user?.id) {
154
- return { error: "Unauthorized" }
155
- }
156
- const userId = session.user.id
157
- await checkAiRateLimit(userId, "mediaPoll")
158
- const thread = await prisma.chatThread.findFirst({
159
- where: { id: data.threadId, userId }, select: { id: true },
160
- })
161
- if (!thread) throw new Error("Thread not found")
162
-
163
- const aiConfig = await resolveAiConfig(userId)
164
- if (!aiConfig) {
165
- return { error: "AI key not configured" }
166
- }
167
-
168
- const result = await pollVideoForUser({
169
- userId,
170
- threadId: data.threadId,
171
- jobId: data.jobId,
172
- adapterKind: aiConfig.provider,
173
- apiKey: aiConfig.apiKey,
174
- model: aiConfig.model,
175
- ...(aiConfig.baseUrl ? { baseURL: aiConfig.baseUrl } : {}),
176
- })
177
-
178
- return {
179
- status: result.status,
180
- progress: result.progress,
181
- url: result.url,
182
- artifacts: result.artifacts,
183
- error: result.error,
184
- }
185
- })
186
-
187
91
  const GenerateSpeechSchema = z.object({
188
92
  text: z.string().min(1),
189
93
  voice: z.string().optional(),
@@ -192,18 +96,17 @@ const GenerateSpeechSchema = z.object({
192
96
  })
193
97
 
194
98
  export const generateSpeechFn = createServerFn({ method: "POST" })
99
+ .middleware([authContextMiddleware])
195
100
  .validator(GenerateSpeechSchema)
196
- .handler(async ({ data }) => {
101
+ .handler(async ({ data, context }) => {
197
102
  const prisma = await getPrisma()
198
103
  const request = getRequest()
199
104
  await requireFeature(request, "mediaGeneration")
200
105
  await requireResource(request, "mediaGenerationsMonthly")
201
-
202
- const session = await requireAuth(request)
203
- if (!session?.user?.id) {
106
+ if (!context.user.id) {
204
107
  return { error: "Unauthorized" }
205
108
  }
206
- const userId = session.user.id
109
+ const userId = context.user.id
207
110
  await checkAiRateLimit(userId, "mediaSpeech")
208
111
  const thread = await prisma.chatThread.findFirst({
209
112
  where: { id: data.threadId, userId }, select: { id: true },
@@ -247,18 +150,17 @@ const GenerateTranscriptionSchema = z.object({
247
150
  })
248
151
 
249
152
  export const generateTranscriptionFn = createServerFn({ method: "POST" })
153
+ .middleware([authContextMiddleware])
250
154
  .validator(GenerateTranscriptionSchema)
251
- .handler(async ({ data }) => {
155
+ .handler(async ({ data, context }) => {
252
156
  const prisma = await getPrisma()
253
157
  const request = getRequest()
254
158
  await requireFeature(request, "mediaGeneration")
255
159
  await requireResource(request, "mediaGenerationsMonthly")
256
-
257
- const session = await requireAuth(request)
258
- if (!session?.user?.id) {
160
+ if (!context.user.id) {
259
161
  return { error: "Unauthorized" }
260
162
  }
261
- const userId = session.user.id
163
+ const userId = context.user.id
262
164
  await checkAiRateLimit(userId, "mediaTranscription")
263
165
  const thread = await prisma.chatThread.findFirst({
264
166
  where: { id: data.threadId, userId }, select: { id: true },
@@ -301,16 +203,15 @@ const GeneratePrototypeSchema = z.object({
301
203
  * 不扣 mediaGenerationsMonthly 配额(token 计量由 runChat 既有 AiUsageLog 承担)。
302
204
  */
303
205
  export const generatePrototypeFn = createServerFn({ method: "POST" })
206
+ .middleware([authContextMiddleware])
304
207
  .validator(GeneratePrototypeSchema)
305
- .handler(async ({ data }) => {
208
+ .handler(async ({ data, context }) => {
306
209
  const request = getRequest()
307
210
  await requireFeature(request, "mediaGeneration")
308
-
309
- const session = await requireAuth(request)
310
- if (!session?.user?.id) {
211
+ if (!context.user.id) {
311
212
  return { error: "Unauthorized" }
312
213
  }
313
- const userId = session.user.id
214
+ const userId = context.user.id
314
215
  await checkAiRateLimit(userId, "mediaPrototype")
315
216
  // threadId 归属由下游 generatePrototypeForUser 的 requireThread 校验
316
217
  // ({ id, userId } findFirst,media/index.ts)——与上方各 fn 的本层校验同口径
@@ -19,7 +19,7 @@ import { getPrisma } from "@allbluecn/database/get-prisma"
19
19
  import { createServerFn } from "@tanstack/react-start"
20
20
  import { getRequest } from "@tanstack/react-start/server"
21
21
  import { z } from "zod"
22
- import { getCurrentSession } from "@/lib/session"
22
+ import { authContextMiddleware } from "@/server/middlewares/auth-context"
23
23
  import {
24
24
  SANDBOX_DEFAULT_POLICY_LEVEL,
25
25
  isSandboxPolicyLevel,
@@ -28,26 +28,26 @@ import { assertSandboxEntitled } from "@/server/ai-gateway/sandbox/entitlement"
28
28
 
29
29
  const threadIdInput = z.object({ threadId: z.string().min(1) })
30
30
 
31
- async function requireOwnedThread(threadId: string) {
32
- const session = await getCurrentSession(getRequest())
33
- if (!session?.user?.id) throw new Error("Unauthorized")
34
-
31
+ // 归属校验 helper:userId 由 authContextMiddleware 注入(context.user.id),
32
+ // 未登录拒绝走 middleware 的 UnauthorizedError;跨用户仍抛原 Error("Unauthorized")
33
+ async function requireOwnedThread(threadId: string, userId: string) {
35
34
  const prisma = await getPrisma()
36
35
  const thread = await prisma.chatThread.findUnique({
37
36
  where: { id: threadId },
38
37
  select: { id: true, userId: true, sandboxPolicy: true },
39
38
  })
40
39
  if (!thread) throw new Error(`Chat thread not found: ${threadId}`)
41
- if (thread.userId !== session.user.id) throw new Error("Unauthorized")
40
+ if (thread.userId !== userId) throw new Error("Unauthorized")
42
41
 
43
42
  return thread
44
43
  }
45
44
 
46
45
  /** 读取线程沙箱策略档;DB 值非法时回落默认档(fail-closed,不返回更宽的档)。 */
47
46
  export const getSandboxPolicyFn = createServerFn({ method: "GET" })
47
+ .middleware([authContextMiddleware])
48
48
  .validator(threadIdInput)
49
- .handler(async ({ data }) => {
50
- const thread = await requireOwnedThread(data.threadId)
49
+ .handler(async ({ data, context }) => {
50
+ const thread = await requireOwnedThread(data.threadId, context.user.id)
51
51
  return isSandboxPolicyLevel(thread.sandboxPolicy)
52
52
  ? thread.sandboxPolicy
53
53
  : SANDBOX_DEFAULT_POLICY_LEVEL
@@ -58,6 +58,7 @@ export const getSandboxPolicyFn = createServerFn({ method: "GET" })
58
58
  * confirmFull: true,否则直接拒绝——UI 弹窗只是体验,这里才是安全边界。
59
59
  */
60
60
  export const setSandboxPolicyFn = createServerFn({ method: "POST" })
61
+ .middleware([authContextMiddleware])
61
62
  .validator(
62
63
  z.object({
63
64
  threadId: z.string().min(1),
@@ -65,7 +66,7 @@ export const setSandboxPolicyFn = createServerFn({ method: "POST" })
65
66
  confirmFull: z.boolean().default(false),
66
67
  }),
67
68
  )
68
- .handler(async ({ data }) => {
69
+ .handler(async ({ data, context }) => {
69
70
  const prisma = await getPrisma()
70
71
  // 启用面也过闸:策略档只在你有权使用沙箱时才有意义,UI 层的 FeatureGate
71
72
  // 只是体验优化,这里才是边界(desktop 在本函数内直放)。
@@ -77,7 +78,7 @@ export const setSandboxPolicyFn = createServerFn({ method: "POST" })
77
78
  throw new Error("Enabling full sandbox policy requires confirmFull")
78
79
  }
79
80
 
80
- const thread = await requireOwnedThread(data.threadId)
81
+ const thread = await requireOwnedThread(data.threadId, context.user.id)
81
82
  const updated = await prisma.chatThread.update({
82
83
  where: { id: thread.id },
83
84
  data: { sandboxPolicy: data.level },
@@ -17,18 +17,16 @@
17
17
 
18
18
  import { getPrisma } from "@allbluecn/database/get-prisma"
19
19
  import { createServerFn } from "@tanstack/react-start"
20
- import { getRequest } from "@tanstack/react-start/server"
20
+ import { authContextMiddleware } from "@/server/middlewares/auth-context"
21
21
  import { z } from "zod"
22
- import { requireAuth } from "@/server/auth-helpers"
23
22
 
24
23
  /** 搜索当前用户有权访问的 KB 文档(自有知识库)——不依赖 storyId */
25
24
  export const searchKbDocsForMentionFn = createServerFn({ method: "GET" })
25
+ .middleware([authContextMiddleware])
26
26
  .validator(z.object({ query: z.string().default("") }))
27
- .handler(async ({ data }) => {
27
+ .handler(async ({ data, context }) => {
28
28
  const prisma = await getPrisma()
29
- const request = getRequest()
30
- const session = await requireAuth(request)
31
- const userId = session.user.id
29
+ const userId = context.user.id
32
30
 
33
31
  const accessibleKbs = await prisma.knowledgeBase.findMany({
34
32
  where: { userId, isDeleted: false },
@@ -17,9 +17,8 @@
17
17
 
18
18
  import { getPrisma } from "@allbluecn/database/get-prisma"
19
19
  import { createServerFn } from "@tanstack/react-start"
20
- import { getRequest } from "@tanstack/react-start/server"
20
+ import { authContextMiddleware } from "@/server/middlewares/auth-context"
21
21
  import { z } from "zod"
22
- import { getCurrentSession } from "@/lib/session"
23
22
 
24
23
  async function assertWorkspaceOwner(workspaceId: string, userId: string) {
25
24
  const prisma = await getPrisma()
@@ -32,24 +31,22 @@ async function assertWorkspaceOwner(workspaceId: string, userId: string) {
32
31
  }
33
32
 
34
33
  export const createHarnessWorkspaceFn = createServerFn({ method: "POST" })
34
+ .middleware([authContextMiddleware])
35
35
  .validator(z.object({ name: z.string().min(1).max(80) }))
36
- .handler(async ({ data }) => {
36
+ .handler(async ({ data, context }) => {
37
37
  const prisma = await getPrisma()
38
- const session = await getCurrentSession(getRequest())
39
- if (!session?.user?.id) throw new Error("Unauthorized")
40
38
  return prisma.harnessWorkspace.create({
41
- data: { name: data.name, ownerId: session.user.id },
39
+ data: { name: data.name, ownerId: context.user.id },
42
40
  select: { id: true, name: true },
43
41
  })
44
42
  })
45
43
 
46
44
  export const listHarnessWorkspacesFn = createServerFn({ method: "GET" })
47
- .handler(async () => {
45
+ .middleware([authContextMiddleware])
46
+ .handler(async ({ context }) => {
48
47
  const prisma = await getPrisma()
49
- const session = await getCurrentSession(getRequest())
50
- if (!session?.user?.id) throw new Error("Unauthorized")
51
48
  return prisma.harnessWorkspace.findMany({
52
- where: { ownerId: session.user.id },
49
+ where: { ownerId: context.user.id },
53
50
  orderBy: { updatedAt: "desc" },
54
51
  select: {
55
52
  id: true,
@@ -62,12 +59,11 @@ export const listHarnessWorkspacesFn = createServerFn({ method: "GET" })
62
59
  })
63
60
 
64
61
  export const listWorkspaceFilesFn = createServerFn({ method: "GET" })
62
+ .middleware([authContextMiddleware])
65
63
  .validator(z.object({ workspaceId: z.string().min(1) }))
66
- .handler(async ({ data }) => {
64
+ .handler(async ({ data, context }) => {
67
65
  const prisma = await getPrisma()
68
- const session = await getCurrentSession(getRequest())
69
- if (!session?.user?.id) throw new Error("Unauthorized")
70
- await assertWorkspaceOwner(data.workspaceId, session.user.id)
66
+ await assertWorkspaceOwner(data.workspaceId, context.user.id)
71
67
  return prisma.workspaceFile.findMany({
72
68
  where: { workspaceId: data.workspaceId },
73
69
  orderBy: { path: "asc" },
@@ -83,6 +79,7 @@ export const listWorkspaceFilesFn = createServerFn({ method: "GET" })
83
79
  })
84
80
 
85
81
  export const uploadWorkspaceFileFn = createServerFn({ method: "POST" })
82
+ .middleware([authContextMiddleware])
86
83
  .validator(
87
84
  z.object({
88
85
  workspaceId: z.string(),
@@ -91,11 +88,9 @@ export const uploadWorkspaceFileFn = createServerFn({ method: "POST" })
91
88
  mimeType: z.string().default("application/octet-stream"),
92
89
  }),
93
90
  )
94
- .handler(async ({ data }) => {
91
+ .handler(async ({ data, context }) => {
95
92
  const prisma = await getPrisma()
96
- const session = await getCurrentSession(getRequest())
97
- if (!session?.user?.id) throw new Error("Unauthorized")
98
- await assertWorkspaceOwner(data.workspaceId, session.user.id)
93
+ await assertWorkspaceOwner(data.workspaceId, context.user.id)
99
94
  return prisma.workspaceFile.upsert({
100
95
  where: { workspaceId_path: { workspaceId: data.workspaceId, path: data.path } },
101
96
  create: { ...data, size: data.content.length, source: "upload" },
@@ -105,12 +100,11 @@ export const uploadWorkspaceFileFn = createServerFn({ method: "POST" })
105
100
  })
106
101
 
107
102
  export const readWorkspaceFileFn = createServerFn({ method: "GET" })
103
+ .middleware([authContextMiddleware])
108
104
  .validator(z.object({ workspaceId: z.string().min(1), path: z.string().min(1) }))
109
- .handler(async ({ data }) => {
105
+ .handler(async ({ data, context }) => {
110
106
  const prisma = await getPrisma()
111
- const session = await getCurrentSession(getRequest())
112
- if (!session?.user?.id) throw new Error("Unauthorized")
113
- await assertWorkspaceOwner(data.workspaceId, session.user.id)
107
+ await assertWorkspaceOwner(data.workspaceId, context.user.id)
114
108
  const file = await prisma.workspaceFile.findFirst({
115
109
  where: { workspaceId: data.workspaceId, path: data.path },
116
110
  select: { content: true, mimeType: true },
@@ -120,15 +114,14 @@ export const readWorkspaceFileFn = createServerFn({ method: "GET" })
120
114
  })
121
115
 
122
116
  export const deleteWorkspaceFileFn = createServerFn({ method: "POST" })
117
+ .middleware([authContextMiddleware])
123
118
  .validator(z.object({ fileId: z.string() }))
124
- .handler(async ({ data }) => {
119
+ .handler(async ({ data, context }) => {
125
120
  const prisma = await getPrisma()
126
- const session = await getCurrentSession(getRequest())
127
- if (!session?.user?.id) throw new Error("Unauthorized")
128
121
  const file = await prisma.workspaceFile.findFirst({
129
122
  where: {
130
123
  id: data.fileId,
131
- workspace: { ownerId: session.user.id },
124
+ workspace: { ownerId: context.user.id },
132
125
  },
133
126
  select: { id: true },
134
127
  })
@@ -19,9 +19,17 @@
19
19
  import { describe, it, expect, vi, beforeEach } from "vitest";
20
20
 
21
21
  vi.mock("@tanstack/react-start", () => ({
22
+ // 迁移后经 .middleware([authContextMiddleware]) 注入 context.user:
23
+ // mock 依序执行 middleware 的 server 段(复现框架 executeMiddleware 的
24
+ // context 合并语义),真实鉴权链由被 mock 的 auth-helpers/getRequest 承接
22
25
  createServerFn: (config: any) => {
23
26
  const api: any = {
24
27
  _validator: undefined,
28
+ _middlewares: [] as any[],
29
+ middleware(mws: any[]) {
30
+ api._middlewares.push(...mws);
31
+ return api;
32
+ },
25
33
  validator(schema: any) {
26
34
  this._validator = schema;
27
35
  return this;
@@ -29,16 +37,40 @@ vi.mock("@tanstack/react-start", () => ({
29
37
  handler(fn: Function) {
30
38
  const wrapped = async (args: any) => {
31
39
  let data = args?.data;
32
- if (this._validator && data !== undefined) {
33
- data = this._validator.parse ? this._validator.parse(data) : data;
40
+ if (api._validator && data !== undefined) {
41
+ data = api._validator.parse ? api._validator.parse(data) : data;
42
+ }
43
+ let context: any = {};
44
+ for (const mw of api._middlewares) {
45
+ const serverFn = mw?.options?.server;
46
+ if (!serverFn) continue;
47
+ const result = await serverFn({
48
+ data,
49
+ context,
50
+ method: "POST",
51
+ serverFnMeta: {},
52
+ signal: new AbortController().signal,
53
+ next: async (inner: any) => ({ context: { ...context, ...(inner?.context ?? {}) } }),
54
+ });
55
+ context = result.context;
34
56
  }
35
- return fn({ data });
57
+ return fn({ data, context });
36
58
  };
37
59
  return wrapped;
38
60
  },
39
61
  };
40
62
  return api;
41
63
  },
64
+ // auth-context.ts 依赖 createMiddleware({ type: "function" }).server(fn):
65
+ // mock 产出与真实 middleware 同构的 { options: { server } } 形状
66
+ createMiddleware: (opts: any) => {
67
+ const mw: any = { options: { type: opts?.type } };
68
+ mw.server = (fn: Function) => {
69
+ mw.options.server = fn;
70
+ return mw;
71
+ };
72
+ return mw;
73
+ },
42
74
  }));
43
75
 
44
76
  vi.mock("@tanstack/react-start/server", () => ({
@@ -18,9 +18,17 @@
18
18
  import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
19
19
 
20
20
  vi.mock("@tanstack/react-start", () => ({
21
+ // 迁移后经 .middleware([authContextMiddleware]) 注入 context.user:
22
+ // mock 依序执行 middleware 的 server 段(复现框架 executeMiddleware 的
23
+ // context 合并语义),真实鉴权链由被 mock 的 auth-helpers/getRequest 承接
21
24
  createServerFn: (config: any) => {
22
25
  const api: any = {
23
26
  _validator: undefined,
27
+ _middlewares: [] as any[],
28
+ middleware(mws: any[]) {
29
+ api._middlewares.push(...mws);
30
+ return api;
31
+ },
24
32
  validator(schema: any) {
25
33
  this._validator = schema;
26
34
  return this;
@@ -28,16 +36,40 @@ vi.mock("@tanstack/react-start", () => ({
28
36
  handler(fn: Function) {
29
37
  const wrapped = async (args: any) => {
30
38
  let data = args?.data;
31
- if (this._validator && data !== undefined) {
32
- data = this._validator.parse ? this._validator.parse(data) : data;
39
+ if (api._validator && data !== undefined) {
40
+ data = api._validator.parse ? api._validator.parse(data) : data;
41
+ }
42
+ let context: any = {};
43
+ for (const mw of api._middlewares) {
44
+ const serverFn = mw?.options?.server;
45
+ if (!serverFn) continue;
46
+ const result = await serverFn({
47
+ data,
48
+ context,
49
+ method: "POST",
50
+ serverFnMeta: {},
51
+ signal: new AbortController().signal,
52
+ next: async (inner: any) => ({ context: { ...context, ...(inner?.context ?? {}) } }),
53
+ });
54
+ context = result.context;
33
55
  }
34
- return fn({ data });
56
+ return fn({ data, context });
35
57
  };
36
58
  return wrapped;
37
59
  },
38
60
  };
39
61
  return api;
40
62
  },
63
+ // auth-context.ts 依赖 createMiddleware({ type: "function" }).server(fn):
64
+ // mock 产出与真实 middleware 同构的 { options: { server } } 形状
65
+ createMiddleware: (opts: any) => {
66
+ const mw: any = { options: { type: opts?.type } };
67
+ mw.server = (fn: Function) => {
68
+ mw.options.server = fn;
69
+ return mw;
70
+ };
71
+ return mw;
72
+ },
41
73
  }));
42
74
 
43
75
  vi.mock("@tanstack/react-start/server", () => ({