@allbluecn/web-app 0.22.4 → 0.23.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (500) hide show
  1. package/package.json +4 -14
  2. package/src/__tests__/integration/login-email-acceptance.test.ts +16 -0
  3. package/src/__tests__/story-view.test.ts +33 -1
  4. package/src/components/agents/__tests__/agent-bindings-tab.test.tsx +221 -0
  5. package/src/components/agents/__tests__/agents-page.test.tsx +284 -0
  6. package/src/components/agents/agent-bindings-tab.tsx +59 -45
  7. package/src/components/agents/agent-form-dialog.tsx +3 -3
  8. package/src/components/agents/agent-selector.tsx +2 -3
  9. package/src/components/agents/agents-page.tsx +66 -31
  10. package/src/components/agents/slash-skill-menu.tsx +2 -3
  11. package/src/components/auth/__tests__/session-guard.test.tsx +74 -0
  12. package/src/components/auth/session-guard.tsx +8 -0
  13. package/src/components/billing/login-prompt-dialog.tsx +1 -1
  14. package/src/components/billing/subscription-provider.tsx +2 -16
  15. package/src/components/bug/__tests__/peek-modes.test.tsx +8 -0
  16. package/src/components/bug/__tests__/subgroup-header.test.tsx +202 -40
  17. package/src/components/bug/peek-panel.tsx +5 -3
  18. package/src/components/bug/views/bug-list/group.tsx +12 -2
  19. package/src/components/bug/views/bug-list/index.tsx +94 -67
  20. package/src/components/command/command-palette.tsx +10 -9
  21. package/src/components/design/canvas/document/frame-custom-presets.ts +9 -1
  22. package/src/components/design/canvas/panels/toolbar.tsx +21 -22
  23. package/src/components/design/canvas/react/__tests__/canvas-context-load-echo.test.tsx +199 -0
  24. package/src/components/design/canvas/react/__tests__/hooks.test.tsx +17 -3
  25. package/src/components/design/canvas/react/canvas-context.tsx +47 -26
  26. package/src/components/design/canvas/react/hooks.ts +39 -34
  27. package/src/components/design/editor/layout/__tests__/collab-param-wiring.test.tsx +17 -0
  28. package/src/components/design/editor/layout/__tests__/context-menu.test.tsx +17 -1
  29. package/src/components/design/editor/layout/__tests__/no-page-save-toast.test.tsx +17 -0
  30. package/src/components/design/editor/layout/__tests__/persistence-restore.test.tsx +17 -1
  31. package/src/components/design/editor/layout/__tests__/ssr-localstorage-smoke.test.tsx +17 -1
  32. package/src/components/design/editor/layout/design-editor-layout.tsx +13 -2
  33. package/src/components/design/editor/layout/hooks/use-design-auto-save.ts +3 -19
  34. package/src/components/devtools/devtools-panel.tsx +56 -0
  35. package/src/components/forms/__tests__/create-app-form.test.tsx +131 -0
  36. package/src/components/forms/app-field-error.tsx +21 -1
  37. package/src/components/forms/app-field.tsx +8 -8
  38. package/src/components/forms/app-submit.tsx +12 -9
  39. package/src/components/forms/create-app-form.tsx +124 -0
  40. package/src/components/forms/index.ts +2 -3
  41. package/src/components/harness/__tests__/gallery-behavior.test.tsx +37 -1
  42. package/src/components/harness/__tests__/harness-workbench-first-send.test.tsx +4 -1
  43. package/src/components/harness/__tests__/message-actions.test.tsx +7 -6
  44. package/src/components/harness/__tests__/use-video-generation.test.tsx +165 -0
  45. package/src/components/harness/ai-chat-history/index.tsx +5 -3
  46. package/src/components/harness/gallery/gallery-card.tsx +57 -35
  47. package/src/components/harness/gallery/gallery-grid.tsx +32 -15
  48. package/src/components/harness/gallery/gallery-types.ts +19 -0
  49. package/src/components/harness/gallery/gallery-video-card.tsx +54 -0
  50. package/src/components/harness/gallery/types.ts +2 -0
  51. package/src/components/harness/gallery/use-video-generation.ts +95 -0
  52. package/src/components/harness/harness-workbench-page.tsx +2 -3
  53. package/src/components/harness/message-actions.tsx +5 -3
  54. package/src/components/hotkeys/shortcuts-panel.tsx +28 -13
  55. package/src/components/iteration/__tests__/burndown-chart.test.tsx +118 -0
  56. package/src/components/iteration/burndown-chart.tsx +54 -23
  57. package/src/components/knowledge/editor/__tests__/knowledge-doc-editor-collab.test.tsx +96 -0
  58. package/src/components/knowledge/editor/knowledge-doc-editor.tsx +56 -1
  59. package/src/components/knowledge/editor/mindmap-doc-editor.tsx +12 -0
  60. package/src/components/knowledge/editor/use-auto-save-channels.ts +3 -1
  61. package/src/components/layout/sidebar-03/__tests__/nav-workspace.test.tsx +0 -4
  62. package/src/components/layout/sidebar-03/nav-knowledge.tsx +11 -11
  63. package/src/components/layout/sidebar-03/nav-main.tsx +12 -15
  64. package/src/components/layout/sidebar-03/nav-notifications.tsx +5 -8
  65. package/src/components/layout/sidebar-03/nav-workspace.tsx +11 -9
  66. package/src/components/notifications/__tests__/settings-notifications.test.tsx +158 -0
  67. package/src/components/notifications/settings-notifications.tsx +37 -13
  68. package/src/components/notifications/team-notifications.tsx +10 -14
  69. package/src/components/settings/personal-team/account/__tests__/account-client.test.tsx +170 -0
  70. package/src/components/settings/personal-team/account/account-client.tsx +44 -7
  71. package/src/components/settings/personal-team/team/team-client.tsx +17 -19
  72. package/src/components/shared-kit/list-kit/__tests__/frozen-header.test.ts +210 -41
  73. package/src/components/shared-kit/list-kit/frozen-header.ts +134 -21
  74. package/src/components/shared-kit/list-kit/kanban/frozen-header.ts +20 -27
  75. package/src/components/story/__tests__/peek-panel-patch-sync.test.tsx +8 -0
  76. package/src/components/story/__tests__/story-list-table.test.tsx +214 -0
  77. package/src/components/story/columns.tsx +11 -2
  78. package/src/components/story/peek-panel.tsx +4 -2
  79. package/src/components/story/story-list-table.tsx +16 -1
  80. package/src/components/story/views/story-list/__tests__/frozen-headers.test.tsx +186 -0
  81. package/src/components/story/views/story-list/group.tsx +12 -1
  82. package/src/components/story/views/story-list/index.tsx +101 -68
  83. package/src/components/testcase/__tests__/case-row.test.tsx +134 -2
  84. package/src/components/testcase/__tests__/peek-panel.test.tsx +8 -0
  85. package/src/components/testcase/__tests__/step-editor.test.tsx +106 -0
  86. package/src/components/testcase/list/grouped-list.tsx +50 -22
  87. package/src/components/testcase/peek-panel.tsx +7 -4
  88. package/src/components/testcase/step-editor.tsx +196 -150
  89. package/src/components/tiptap/notion-like/editor-extensions.ts +0 -3
  90. package/src/components/tiptap/notion-like/notion-like-editor-header.tsx +1 -31
  91. package/src/components/tiptap/notion-like/notion-like-editor.tsx +32 -1
  92. package/src/components/workspace/__tests__/dialogs/create-workspace-dialog.test.tsx +2 -28
  93. package/src/components/workspace/__tests__/dialogs/edit-workspace-dialog.test.tsx +2 -28
  94. package/src/components/workspace/dialogs/create-workspace-dialog.tsx +45 -43
  95. package/src/components/workspace/dialogs/edit-workspace-dialog.tsx +38 -36
  96. package/src/design-engine/engine/engine-decor.ts +2 -0
  97. package/src/design-engine/engine/engine-path.ts +2 -0
  98. package/src/hooks/__tests__/use-unsaved-guard.test.tsx +180 -0
  99. package/src/hooks/use-notifications.ts +9 -16
  100. package/src/hooks/use-unsaved-guard.tsx +87 -0
  101. package/src/lib/__tests__/pacer.test.ts +33 -96
  102. package/src/lib/__tests__/query-defaults.test.ts +169 -0
  103. package/src/lib/__tests__/query-global-error.test.ts +256 -0
  104. package/src/lib/anyhub/anyhub-store.ts +2 -2
  105. package/src/lib/changelog/sdk-versions.ts +2 -10
  106. package/src/lib/collab/presence-store.ts +5 -5
  107. package/src/lib/collab/use-presence-list-refresh.ts +2 -2
  108. package/src/lib/collab/use-share-presence.ts +2 -2
  109. package/src/lib/collections/query-keys.ts +7 -2
  110. package/src/lib/commands/__tests__/command-palette-state.test.ts +12 -14
  111. package/src/lib/commands/__tests__/registry.test.ts +6 -3
  112. package/src/lib/commands/command-palette-state.ts +8 -31
  113. package/src/lib/hotkeys/__tests__/registry.test.ts +71 -18
  114. package/src/lib/hotkeys/registry.ts +188 -85
  115. package/src/lib/hotkeys/types.ts +1 -13
  116. package/src/lib/pacer.ts +1 -79
  117. package/src/lib/queries/README.md +67 -0
  118. package/src/lib/queries/__tests__/agents-queries.test.ts +101 -0
  119. package/src/lib/queries/__tests__/compliance-queries.test.ts +136 -0
  120. package/src/lib/queries/__tests__/notifications-queries.test.ts +175 -0
  121. package/src/lib/queries/__tests__/team-queries.test.ts +87 -0
  122. package/src/lib/queries/agents.ts +40 -0
  123. package/src/lib/queries/compliance.ts +69 -0
  124. package/src/lib/queries/notifications.ts +63 -0
  125. package/src/lib/queries/team.ts +39 -0
  126. package/src/lib/query-defaults.ts +8 -0
  127. package/src/lib/query-global-error.ts +128 -0
  128. package/src/lib/remote-auth-client.ts +16 -0
  129. package/src/paraglide/README.md +1 -1
  130. package/src/paraglide/messages/_index.d.ts +11 -0
  131. package/src/paraglide/messages/_index.js +5659 -88285
  132. package/src/paraglide/messages/common_error_generic.d.ts +16 -0
  133. package/src/paraglide/messages/common_error_generic.js +29 -0
  134. package/src/paraglide/messages/common_unsaved_body.d.ts +16 -0
  135. package/src/paraglide/messages/common_unsaved_body.js +29 -0
  136. package/src/paraglide/messages/common_unsaved_leave.d.ts +16 -0
  137. package/src/paraglide/messages/common_unsaved_leave.js +29 -0
  138. package/src/paraglide/messages/common_unsaved_stay.d.ts +16 -0
  139. package/src/paraglide/messages/common_unsaved_stay.js +29 -0
  140. package/src/paraglide/messages/common_unsaved_title.d.ts +16 -0
  141. package/src/paraglide/messages/common_unsaved_title.js +29 -0
  142. package/src/paraglide/messages/gallery_videofailed1.d.ts +17 -0
  143. package/src/paraglide/messages/gallery_videofailed1.js +30 -0
  144. package/src/paraglide/messages/gallery_videogenerating1.d.ts +17 -0
  145. package/src/paraglide/messages/gallery_videogenerating1.js +30 -0
  146. package/src/paraglide/messages/gallery_videomissingprompt2.d.ts +17 -0
  147. package/src/paraglide/messages/gallery_videomissingprompt2.js +30 -0
  148. package/src/paraglide/messages/gallery_videoprogress1.d.ts +19 -0
  149. package/src/paraglide/messages/gallery_videoprogress1.js +30 -0
  150. package/src/paraglide/messages/gallery_videostop1.d.ts +17 -0
  151. package/src/paraglide/messages/gallery_videostop1.js +30 -0
  152. package/src/paraglide/messages/story_table_resizecolumn1.d.ts +17 -0
  153. package/src/paraglide/messages/story_table_resizecolumn1.js +30 -0
  154. package/src/providers/index.tsx +5 -50
  155. package/src/routeTree.gen.ts +21 -0
  156. package/src/router.tsx +21 -8
  157. package/src/routes/__root.tsx +2 -1
  158. package/src/routes/__tests__/-edition-routing.test.tsx +6 -1
  159. package/src/routes/_login/forgot-password/route.lazy.tsx +7 -6
  160. package/src/routes/_login/login/route.lazy.tsx +10 -9
  161. package/src/routes/_login/register/route.lazy.tsx +19 -18
  162. package/src/routes/_login/reset-password/route.lazy.tsx +10 -9
  163. package/src/routes/_nav/knowledge/compliance/$id.lazy.tsx +9 -12
  164. package/src/routes/_nav/knowledge/compliance/index.lazy.tsx +16 -13
  165. package/src/routes/_nav/knowledge/laws/$id.lazy.tsx +1 -1
  166. package/src/routes/_nav/notifications/route.tsx +6 -16
  167. package/src/routes/_nav/settings/-settings-tabs.tsx +9 -12
  168. package/src/routes/api/generate/__tests__/media.test.ts +378 -0
  169. package/src/routes/api/generate/media.ts +179 -0
  170. package/src/server/__tests__/agent-client-graph.test.ts +0 -1
  171. package/src/server/__tests__/agent-crud.test.ts +37 -4
  172. package/src/server/__tests__/bug-groups-two-level.test.ts +34 -1
  173. package/src/server/__tests__/chat-conversations.test.ts +37 -4
  174. package/src/server/__tests__/chat-list-messages.test.ts +40 -7
  175. package/src/server/__tests__/csv-export.test.ts +36 -3
  176. package/src/server/__tests__/desktop-bootstrap.test.ts +189 -0
  177. package/src/server/__tests__/remote-auth.test.ts +72 -0
  178. package/src/server/__tests__/skill-crud.test.ts +37 -4
  179. package/src/server/__tests__/sso-domain.test.ts +1 -1
  180. package/src/server/__tests__/sso-rate-limit-singleton.test.ts +123 -0
  181. package/src/server/__tests__/task-serverfn-crud.test.ts +35 -2
  182. package/src/server/__tests__/task-serverfn-queries.test.ts +35 -2
  183. package/src/server/__tests__/testcase-board.test.ts +38 -5
  184. package/src/server/__tests__/testcase-bulk.test.ts +38 -5
  185. package/src/server/__tests__/testcase-list-scope.test.ts +38 -5
  186. package/src/server/ai-gateway/__tests__/ai-output-guard.test.ts +126 -2
  187. package/src/server/ai-gateway/__tests__/chat-stream-builder-code-mode.test.ts +4 -0
  188. package/src/server/ai-gateway/__tests__/chat-stream-builder-memory.test.ts +4 -0
  189. package/src/server/ai-gateway/__tests__/chat-stream-builder-sandbox.test.ts +4 -0
  190. package/src/server/ai-gateway/__tests__/chat-stream-builder-skills.test.ts +4 -0
  191. package/src/server/ai-gateway/__tests__/pgvector-memory-adapter.test.ts +30 -0
  192. package/src/server/ai-gateway/__tests__/pgvector-memory-conformance.test.ts +92 -0
  193. package/src/server/ai-gateway/__tests__/source-mode.test.ts +49 -8
  194. package/src/server/ai-gateway/ai-output-guard.ts +50 -2
  195. package/src/server/ai-gateway/chat-stream-builder.ts +3 -0
  196. package/src/server/ai-gateway/media/index.ts +36 -29
  197. package/src/server/ai-gateway/media/trim-input.ts +52 -0
  198. package/src/server/ai-gateway/memory/pgvector-adapter.ts +27 -13
  199. package/src/server/ai-gateway/sandbox/__tests__/harness-sandbox.test.ts +252 -41
  200. package/src/server/ai-gateway/sandbox/harness-sandbox.ts +6 -67
  201. package/src/server/ai-gateway/source-mode.ts +24 -8
  202. package/src/server/desktop-bootstrap.ts +74 -0
  203. package/src/server/lib/__tests__/rate-limit.test.ts +0 -1
  204. package/src/server/lib/rate-limit.ts +0 -2
  205. package/src/server/middlewares/__tests__/auth-context.test.ts +156 -0
  206. package/src/server/middlewares/auth-context.ts +62 -0
  207. package/src/server/remote-auth.ts +58 -31
  208. package/src/server/serverFns/__tests__/ai-hosted-models.test.ts +47 -15
  209. package/src/server/serverFns/__tests__/ai-source-mode.test.ts +45 -15
  210. package/src/server/serverFns/__tests__/billing.test.ts +37 -2
  211. package/src/server/serverFns/__tests__/collab-snapshot.test.ts +41 -14
  212. package/src/server/serverFns/__tests__/collab.test.ts +41 -14
  213. package/src/server/serverFns/__tests__/compliance.test.ts +33 -1
  214. package/src/server/serverFns/__tests__/email-verification.test.ts +35 -1
  215. package/src/server/serverFns/__tests__/knowledge-breadcrumb.test.ts +46 -6
  216. package/src/server/serverFns/__tests__/knowledge-delete.test.ts +42 -14
  217. package/src/server/serverFns/__tests__/knowledge-kb-projects.test.ts +46 -6
  218. package/src/server/serverFns/__tests__/knowledge-public-compliance.test.ts +36 -2
  219. package/src/server/serverFns/__tests__/knowledge-readable-kb.test.ts +42 -10
  220. package/src/server/serverFns/__tests__/knowledge-search.test.ts +45 -9
  221. package/src/server/serverFns/__tests__/legal-code-canonical.test.ts +36 -2
  222. package/src/server/serverFns/__tests__/link-preview.test.ts +38 -4
  223. package/src/server/serverFns/__tests__/notifications-list.test.ts +36 -3
  224. package/src/server/serverFns/__tests__/ownership-merge.test.ts +38 -4
  225. package/src/server/serverFns/__tests__/project-delete-transaction.test.ts +39 -2
  226. package/src/server/serverFns/__tests__/project-kb.test.ts +34 -1
  227. package/src/server/serverFns/__tests__/project-member-idor.test.ts +34 -1
  228. package/src/server/serverFns/__tests__/project-team-assign.test.ts +34 -1
  229. package/src/server/serverFns/__tests__/read-write-merge.test.ts +38 -4
  230. package/src/server/serverFns/__tests__/story-comments.test.ts +38 -4
  231. package/src/server/serverFns/__tests__/story-crud-archive-detail.test.ts +38 -4
  232. package/src/server/serverFns/__tests__/story-crud-labels-users.test.ts +37 -3
  233. package/src/server/serverFns/__tests__/story-crud.test.ts +36 -3
  234. package/src/server/serverFns/__tests__/story-links.test.ts +38 -4
  235. package/src/server/serverFns/__tests__/story-reactions.test.ts +38 -4
  236. package/src/server/serverFns/__tests__/story-tree.test.ts +38 -4
  237. package/src/server/serverFns/__tests__/team-accept.test.ts +34 -1
  238. package/src/server/serverFns/__tests__/team-invitation.test.ts +34 -1
  239. package/src/server/serverFns/__tests__/team-join-request.test.ts +34 -1
  240. package/src/server/serverFns/__tests__/team-members.test.ts +34 -1
  241. package/src/server/serverFns/__tests__/team-ownership-merge.test.ts +34 -1
  242. package/src/server/serverFns/__tests__/update-bug-guard.test.ts +37 -3
  243. package/src/server/serverFns/__tests__/update-document-guard.test.ts +38 -4
  244. package/src/server/serverFns/__tests__/update-page-guard.test.ts +40 -4
  245. package/src/server/serverFns/__tests__/update-seats.test.ts +33 -1
  246. package/src/server/serverFns/__tests__/update-story-guard.test.ts +36 -3
  247. package/src/server/serverFns/__tests__/update-testcase-guard.test.ts +37 -3
  248. package/src/server/serverFns/__tests__/workspace-kb-idor.test.ts +36 -2
  249. package/src/server/serverFns/__tests__/workspace-kb.test.ts +36 -2
  250. package/src/server/serverFns/__tests__/workspace.test.ts +34 -1
  251. package/src/server/serverFns/activity.ts +10 -14
  252. package/src/server/serverFns/agents/agent-crud.ts +16 -15
  253. package/src/server/serverFns/agents/bindings.ts +12 -13
  254. package/src/server/serverFns/agents/skill-crud.ts +16 -15
  255. package/src/server/serverFns/ai/code-mode-readiness.ts +3 -4
  256. package/src/server/serverFns/ai/search-capability.ts +3 -4
  257. package/src/server/serverFns/anyhub/app.ts +10 -14
  258. package/src/server/serverFns/anyhub/index.ts +7 -10
  259. package/src/server/serverFns/anyhub/install.ts +4 -4
  260. package/src/server/serverFns/anyhub/permissions.ts +10 -14
  261. package/src/server/serverFns/anyhub/proxy.ts +4 -6
  262. package/src/server/serverFns/auth/email-verification.ts +4 -5
  263. package/src/server/serverFns/auth/session.ts +9 -0
  264. package/src/server/serverFns/billing.ts +18 -28
  265. package/src/server/serverFns/blob-upload.ts +6 -9
  266. package/src/server/serverFns/bug/__tests__/bug-access-tokens.test.ts +34 -1
  267. package/src/server/serverFns/bug/__tests__/bug-activities.test.ts +34 -1
  268. package/src/server/serverFns/bug/__tests__/bug-comments.test.ts +34 -1
  269. package/src/server/serverFns/bug/__tests__/bug-crud.test.ts +34 -1
  270. package/src/server/serverFns/bug/__tests__/bug-fix.test.ts +34 -1
  271. package/src/server/serverFns/bug/__tests__/bug-groups.test.ts +34 -1
  272. package/src/server/serverFns/bug/__tests__/bug-reactions.test.ts +34 -1
  273. package/src/server/serverFns/bug/__tests__/bug-reorder.test.ts +39 -5
  274. package/src/server/serverFns/bug/__tests__/bug-repro.test.ts +34 -1
  275. package/src/server/serverFns/bug/__tests__/bug-story.test.ts +34 -1
  276. package/src/server/serverFns/bug/__tests__/bug-webhooks.test.ts +34 -1
  277. package/src/server/serverFns/bug/bug-access-tokens.ts +16 -22
  278. package/src/server/serverFns/bug/bug-activities.ts +4 -6
  279. package/src/server/serverFns/bug/bug-collect-tokens.ts +13 -18
  280. package/src/server/serverFns/bug/bug-comments.ts +13 -18
  281. package/src/server/serverFns/bug/bug-crud/detail.ts +10 -14
  282. package/src/server/serverFns/bug/bug-crud.ts +28 -38
  283. package/src/server/serverFns/bug/bug-display-options.ts +8 -11
  284. package/src/server/serverFns/bug/bug-export.ts +5 -7
  285. package/src/server/serverFns/bug/bug-fix.ts +10 -14
  286. package/src/server/serverFns/bug/bug-groups.ts +10 -14
  287. package/src/server/serverFns/bug/bug-reactions.ts +10 -14
  288. package/src/server/serverFns/bug/bug-reorder.ts +4 -6
  289. package/src/server/serverFns/bug/bug-repro.ts +8 -11
  290. package/src/server/serverFns/bug/bug-story-bulk.ts +13 -18
  291. package/src/server/serverFns/bug/bug-story.ts +10 -14
  292. package/src/server/serverFns/bug/bug-views.ts +12 -18
  293. package/src/server/serverFns/bug/bug-webhooks.ts +13 -18
  294. package/src/server/serverFns/bug/test-bug-confirm.ts +7 -10
  295. package/src/server/serverFns/changelog/__tests__/fetch.test.ts +40 -1
  296. package/src/server/serverFns/changelog/fetch.ts +4 -6
  297. package/src/server/serverFns/chat/conversations.ts +17 -28
  298. package/src/server/serverFns/chat/list-messages.ts +4 -7
  299. package/src/server/serverFns/collab-presence.ts +11 -13
  300. package/src/server/serverFns/collab-snapshot.ts +6 -7
  301. package/src/server/serverFns/collab.ts +7 -7
  302. package/src/server/serverFns/compliance.ts +8 -8
  303. package/src/server/serverFns/design/__tests__/comments.test.ts +54 -10
  304. package/src/server/serverFns/design/__tests__/designs.test.ts +39 -16
  305. package/src/server/serverFns/design/__tests__/page-versions.test.ts +52 -14
  306. package/src/server/serverFns/design/__tests__/shares-password.test.ts +44 -14
  307. package/src/server/serverFns/design/__tests__/shares.test.ts +44 -14
  308. package/src/server/serverFns/design/__tests__/versions.test.ts +44 -14
  309. package/src/server/serverFns/design/ai/__tests__/agent-conversations.test.ts +50 -21
  310. package/src/server/serverFns/design/ai/__tests__/providers.test.ts +42 -8
  311. package/src/server/serverFns/design/ai/agent-conversations.ts +19 -26
  312. package/src/server/serverFns/design/ai/fill-annotation.ts +5 -7
  313. package/src/server/serverFns/design/ai/generate-prototype.ts +5 -7
  314. package/src/server/serverFns/design/ai/hosted-models.ts +4 -5
  315. package/src/server/serverFns/design/ai/providers.ts +30 -39
  316. package/src/server/serverFns/design/ai/source-mode.ts +10 -12
  317. package/src/server/serverFns/design/comments.ts +14 -13
  318. package/src/server/serverFns/design/designs.ts +13 -19
  319. package/src/server/serverFns/design/page-versions.ts +17 -18
  320. package/src/server/serverFns/design/pages.ts +17 -18
  321. package/src/server/serverFns/design/reviews.ts +8 -9
  322. package/src/server/serverFns/design/shares-password.ts +13 -19
  323. package/src/server/serverFns/design/shares.ts +22 -31
  324. package/src/server/serverFns/design/versions.ts +8 -9
  325. package/src/server/serverFns/harness/__tests__/attach-prototype.spec.ts +52 -2
  326. package/src/server/serverFns/harness/__tests__/attach-to-kb.spec.ts +52 -2
  327. package/src/server/serverFns/harness/__tests__/attach-to-story-ssrf.spec.ts +52 -2
  328. package/src/server/serverFns/harness/__tests__/attach-to-story.spec.ts +52 -2
  329. package/src/server/serverFns/harness/__tests__/cancel-run.test.ts +40 -15
  330. package/src/server/serverFns/harness/__tests__/extract-attachment.spec.ts +52 -2
  331. package/src/server/serverFns/harness/__tests__/gallery.spec.ts +76 -12
  332. package/src/server/serverFns/harness/__tests__/github-workspace.spec.ts +38 -6
  333. package/src/server/serverFns/harness/__tests__/media-prototype.spec.ts +50 -6
  334. package/src/server/serverFns/harness/__tests__/media.spec.ts +55 -11
  335. package/src/server/serverFns/harness/__tests__/sandbox-policy.test.ts +41 -16
  336. package/src/server/serverFns/harness/__tests__/workspace-files.test.ts +41 -16
  337. package/src/server/serverFns/harness/attach-prototype.ts +4 -4
  338. package/src/server/serverFns/harness/attach-to-kb.ts +4 -4
  339. package/src/server/serverFns/harness/attach-to-story.ts +4 -4
  340. package/src/server/serverFns/harness/cancel-run.ts +4 -6
  341. package/src/server/serverFns/harness/extract-attachment.ts +3 -4
  342. package/src/server/serverFns/harness/gallery.ts +19 -23
  343. package/src/server/serverFns/harness/github-workspace.ts +14 -21
  344. package/src/server/serverFns/harness/media.ts +18 -117
  345. package/src/server/serverFns/harness/sandbox-policy.ts +11 -10
  346. package/src/server/serverFns/harness/search-mention-candidates.ts +4 -6
  347. package/src/server/serverFns/harness/workspace-files.ts +19 -26
  348. package/src/server/serverFns/iteration/__tests__/iteration-auto-schedule.test.ts +35 -3
  349. package/src/server/serverFns/iteration/__tests__/iteration-crud.test.ts +35 -3
  350. package/src/server/serverFns/iteration/__tests__/iteration-stories.test.ts +35 -3
  351. package/src/server/serverFns/iteration/__tests__/iteration-transfer.test.ts +35 -3
  352. package/src/server/serverFns/iteration/iteration-auto-schedule.ts +7 -10
  353. package/src/server/serverFns/iteration/iteration-burndown.ts +4 -6
  354. package/src/server/serverFns/iteration/iteration-crud.ts +26 -35
  355. package/src/server/serverFns/iteration/iteration-stories.ts +10 -14
  356. package/src/server/serverFns/iteration/iteration-transfer.ts +4 -6
  357. package/src/server/serverFns/knowledge/public/bookmarks/categories.ts +11 -15
  358. package/src/server/serverFns/knowledge/public/bookmarks/create.ts +4 -6
  359. package/src/server/serverFns/knowledge/public/bookmarks/delete.ts +5 -7
  360. package/src/server/serverFns/knowledge/public/bookmarks/detail.ts +4 -6
  361. package/src/server/serverFns/knowledge/public/bookmarks/favorite.ts +4 -6
  362. package/src/server/serverFns/knowledge/public/bookmarks/list.ts +4 -6
  363. package/src/server/serverFns/knowledge/public/bookmarks/refresh-favicon.ts +4 -6
  364. package/src/server/serverFns/knowledge/public/bookmarks/share.ts +4 -6
  365. package/src/server/serverFns/knowledge/public/bookmarks/sync-github.ts +5 -7
  366. package/src/server/serverFns/knowledge/public/bookmarks/unshare.ts +4 -6
  367. package/src/server/serverFns/knowledge/public/bookmarks/update.ts +6 -8
  368. package/src/server/serverFns/knowledge/public/compliance/create.ts +4 -6
  369. package/src/server/serverFns/knowledge/public/compliance/delete.ts +5 -7
  370. package/src/server/serverFns/knowledge/public/compliance/detail.ts +4 -6
  371. package/src/server/serverFns/knowledge/public/compliance/list.ts +4 -6
  372. package/src/server/serverFns/knowledge/public/compliance/share.ts +4 -6
  373. package/src/server/serverFns/knowledge/public/compliance/unshare.ts +4 -6
  374. package/src/server/serverFns/knowledge/public/compliance/update.ts +5 -7
  375. package/src/server/serverFns/knowledge/public/dictionary/create.ts +4 -6
  376. package/src/server/serverFns/knowledge/public/dictionary/delete.ts +5 -7
  377. package/src/server/serverFns/knowledge/public/dictionary/detail.ts +4 -6
  378. package/src/server/serverFns/knowledge/public/dictionary/list.ts +4 -6
  379. package/src/server/serverFns/knowledge/public/dictionary/share.ts +4 -6
  380. package/src/server/serverFns/knowledge/public/dictionary/unshare.ts +4 -6
  381. package/src/server/serverFns/knowledge/public/dictionary/update.ts +5 -7
  382. package/src/server/serverFns/knowledge/public/entity-tags.ts +4 -6
  383. package/src/server/serverFns/knowledge/public/favorite.ts +7 -10
  384. package/src/server/serverFns/knowledge/public/legal/create.ts +4 -6
  385. package/src/server/serverFns/knowledge/public/legal/delete.ts +5 -7
  386. package/src/server/serverFns/knowledge/public/legal/detail.ts +4 -6
  387. package/src/server/serverFns/knowledge/public/legal/list.ts +4 -6
  388. package/src/server/serverFns/knowledge/public/legal/share.ts +4 -6
  389. package/src/server/serverFns/knowledge/public/legal/unshare.ts +4 -6
  390. package/src/server/serverFns/knowledge/public/legal/update.ts +5 -7
  391. package/src/server/serverFns/knowledge-index.ts +12 -16
  392. package/src/server/serverFns/knowledge.ts +50 -67
  393. package/src/server/serverFns/notifications.ts +25 -34
  394. package/src/server/serverFns/plugins/harness-plugins.ts +16 -23
  395. package/src/server/serverFns/project/module-overview.ts +7 -10
  396. package/src/server/serverFns/project.ts +48 -68
  397. package/src/server/serverFns/references/create.ts +4 -6
  398. package/src/server/serverFns/references/resolve.ts +4 -6
  399. package/src/server/serverFns/references/search.ts +4 -6
  400. package/src/server/serverFns/share/design/[designId]/events.ts +4 -6
  401. package/src/server/serverFns/sso.ts +1 -1
  402. package/src/server/serverFns/story/__tests__/bulk.test.ts +34 -1
  403. package/src/server/serverFns/story/__tests__/story-assoc.test.ts +34 -1
  404. package/src/server/serverFns/story/__tests__/story-attachments.test.ts +34 -1
  405. package/src/server/serverFns/story/__tests__/story-crud-date-key.test.ts +42 -17
  406. package/src/server/serverFns/story/__tests__/story-dependencies.test.ts +34 -1
  407. package/src/server/serverFns/story/__tests__/story-gantt-deps.test.ts +34 -1
  408. package/src/server/serverFns/story/__tests__/story-groups.test.ts +34 -1
  409. package/src/server/serverFns/story/__tests__/story-read-path-authz.test.ts +40 -4
  410. package/src/server/serverFns/story/__tests__/story-search.test.ts +34 -1
  411. package/src/server/serverFns/story/__tests__/story-transfer.test.ts +34 -1
  412. package/src/server/serverFns/story/link-preview.ts +5 -7
  413. package/src/server/serverFns/story/story-assoc.ts +28 -38
  414. package/src/server/serverFns/story/story-attachments.ts +7 -10
  415. package/src/server/serverFns/story/story-children.ts +4 -6
  416. package/src/server/serverFns/story/story-comments.ts +13 -18
  417. package/src/server/serverFns/story/story-crud/activities.ts +4 -6
  418. package/src/server/serverFns/story/story-crud/archive.ts +7 -10
  419. package/src/server/serverFns/story/story-crud/bulk.ts +10 -14
  420. package/src/server/serverFns/story/story-crud/detail.ts +7 -10
  421. package/src/server/serverFns/story/story-crud/label-suggest.ts +4 -6
  422. package/src/server/serverFns/story/story-crud/labels.ts +6 -9
  423. package/src/server/serverFns/story/story-crud/user-brief.ts +4 -6
  424. package/src/server/serverFns/story/story-crud.ts +13 -18
  425. package/src/server/serverFns/story/story-dependencies.ts +16 -22
  426. package/src/server/serverFns/story/story-groups.ts +10 -14
  427. package/src/server/serverFns/story/story-links.ts +13 -18
  428. package/src/server/serverFns/story/story-reactions.ts +13 -18
  429. package/src/server/serverFns/story/story-search.ts +7 -10
  430. package/src/server/serverFns/story/story-transfer.ts +10 -14
  431. package/src/server/serverFns/story/story-tree.ts +7 -10
  432. package/src/server/serverFns/story-display-options.ts +7 -8
  433. package/src/server/serverFns/story-view.ts +12 -18
  434. package/src/server/serverFns/tasks/task-crud.ts +13 -17
  435. package/src/server/serverFns/tasks/task-queries.ts +12 -18
  436. package/src/server/serverFns/team.ts +46 -66
  437. package/src/server/serverFns/testcase/__tests__/automation.test.ts +38 -5
  438. package/src/server/serverFns/testcase/__tests__/evidence-upload.test.ts +37 -3
  439. package/src/server/serverFns/testcase/__tests__/generation.test.ts +38 -5
  440. package/src/server/serverFns/testcase/__tests__/plans.test.ts +36 -3
  441. package/src/server/serverFns/testcase/__tests__/regression.test.ts +36 -3
  442. package/src/server/serverFns/testcase/__tests__/run-cases.test.ts +36 -3
  443. package/src/server/serverFns/testcase/__tests__/runs.test.ts +36 -3
  444. package/src/server/serverFns/testcase/__tests__/stats.test.ts +36 -3
  445. package/src/server/serverFns/testcase/__tests__/testcase-board.test.ts +39 -5
  446. package/src/server/serverFns/testcase/__tests__/testcase-crud.test.ts +36 -3
  447. package/src/server/serverFns/testcase/__tests__/testcase-folders.test.ts +36 -3
  448. package/src/server/serverFns/testcase/__tests__/testcase-groups.test.ts +38 -5
  449. package/src/server/serverFns/testcase/automation.ts +13 -17
  450. package/src/server/serverFns/testcase/bulk.ts +10 -14
  451. package/src/server/serverFns/testcase/evidence-upload.ts +5 -7
  452. package/src/server/serverFns/testcase/generation.ts +10 -13
  453. package/src/server/serverFns/testcase/plans.ts +23 -31
  454. package/src/server/serverFns/testcase/regression.ts +7 -10
  455. package/src/server/serverFns/testcase/run-cases.ts +13 -18
  456. package/src/server/serverFns/testcase/runs.ts +13 -18
  457. package/src/server/serverFns/testcase/stats.ts +13 -18
  458. package/src/server/serverFns/testcase/testcase-activities.ts +4 -6
  459. package/src/server/serverFns/testcase/testcase-board.ts +4 -6
  460. package/src/server/serverFns/testcase/testcase-crud.ts +20 -27
  461. package/src/server/serverFns/testcase/testcase-display-options.ts +8 -11
  462. package/src/server/serverFns/testcase/testcase-export.ts +5 -7
  463. package/src/server/serverFns/testcase/testcase-filter-views.ts +12 -18
  464. package/src/server/serverFns/testcase/testcase-folders.ts +16 -22
  465. package/src/server/serverFns/testcase/testcase-groups.ts +4 -6
  466. package/src/server/serverFns/testcase/testcase-reorder.ts +4 -6
  467. package/src/server/serverFns/translation.ts +4 -6
  468. package/src/server/serverFns/user/avatar.ts +4 -6
  469. package/src/server/serverFns/user/settings.ts +4 -6
  470. package/src/server/serverFns/user/update-locale.ts +4 -6
  471. package/src/server/serverFns/workspace-kb.ts +26 -35
  472. package/src/server/serverFns/workspace.ts +43 -59
  473. package/src/server/serverFns/ws.ts +4 -6
  474. package/src/server/serverfn-public-allowlist.ts +117 -0
  475. package/src/server/story/types.ts +0 -1
  476. package/src/server/sync/__tests__/scopes.test.ts +64 -0
  477. package/src/server/sync/scopes.ts +7 -0
  478. package/src/server/testcase/__tests__/auto-bug.test.ts +44 -12
  479. package/src/__tests__/bench/baselines/format-timestamp.json +0 -44
  480. package/src/__typeprobe__.d.ts +0 -4
  481. package/src/components/forms/app-form-dialog.tsx +0 -126
  482. package/src/components/forms/hooks/use-form-submit.ts +0 -57
  483. package/src/components/forms/types.ts +0 -34
  484. package/src/components/harness/code/workspace-picker.tsx +0 -239
  485. package/src/components/tiptap/extensions/local-file/insert-local-file.ts +0 -35
  486. package/src/components/tiptap/extensions/local-file/local-file-node.ts +0 -71
  487. package/src/devframe-docks/ai-chat-iframe.tsx +0 -29
  488. package/src/devframe-docks/session-iframe.tsx +0 -90
  489. package/src/lib/__tests__/desktop-detect.test.ts +0 -19
  490. package/src/lib/collections/index.ts +0 -22
  491. package/src/lib/collections/knowledge/index.ts +0 -18
  492. package/src/lib/collections/knowledge/knowledge-bases-collection.ts +0 -34
  493. package/src/lib/collections/reference/bookmark-categories-collection.ts +0 -31
  494. package/src/lib/collections/reference/labels-collection.ts +0 -31
  495. package/src/lib/collections/reference/projects-collection.ts +0 -31
  496. package/src/lib/collections/reference/users-brief-collection.ts +0 -35
  497. package/src/lib/collections/reference/workspaces-collection.ts +0 -34
  498. package/src/lib/desktop-detect.ts +0 -29
  499. package/src/paraglide/messages/en.js +0 -28260
  500. package/src/paraglide/messages/zh.js +0 -28258
@@ -0,0 +1,156 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+ //
5
+ // This program is free software: you can redistribute it and/or modify
6
+ // it under the terms of the GNU Affero General Public License as published by
7
+ // the Free Software Foundation, either version 3 of the License, or
8
+ // (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU Affero General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU Affero General Public License
16
+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ import { describe, it, expect, vi, beforeEach } from 'vitest'
19
+
20
+ // auth-context middleware 内部经 getRequest() 取请求 → requireAuth(request) 解 session。
21
+ // 本测试 mock 请求入口(getRequest)与 session 底座(getCurrentSession / desktop-guest),
22
+ // 让「真实 requireAuth 链」在受控输入下运行——requireAuth 本身不 mock,
23
+ // 以此锁定 middleware 与旧 handler 内联鉴权走同一获取链。
24
+ vi.mock('@tanstack/react-start/server', () => ({
25
+ getRequest: vi.fn(),
26
+ }))
27
+
28
+ vi.mock('@/lib/session', () => ({
29
+ getCurrentSession: vi.fn(),
30
+ }))
31
+
32
+ vi.mock('@/server/desktop-guest', () => ({
33
+ isDesktopServer: vi.fn(() => false),
34
+ buildGuestSession: vi.fn(() => ({
35
+ user: { id: 'local-guest', email: 'guest@localhost', isGuest: true },
36
+ })),
37
+ }))
38
+
39
+ import { getRequest } from '@tanstack/react-start/server'
40
+ import { getCurrentSession } from '@/lib/session'
41
+ import { isDesktopServer } from '@/server/desktop-guest'
42
+ import { requireAuth, UnauthorizedError } from '@/server/auth-helpers'
43
+ import { authContextMiddleware } from '../auth-context'
44
+
45
+ /** 直调 middleware 的 server 段(框架 executeMiddleware 的最小等价调用)。 */
46
+ async function runAuthContextMiddleware(initialContext: Record<string, unknown> = {}) {
47
+ const serverFn = (authContextMiddleware as { options: { server?: Function } }).options.server
48
+ if (!serverFn) throw new Error('authContextMiddleware 未定义 .server() 段')
49
+ let merged: Record<string, unknown> = { ...initialContext }
50
+ return await (serverFn as any)({
51
+ data: undefined,
52
+ context: merged,
53
+ method: 'GET' as const,
54
+ serverFnMeta: {},
55
+ signal: new AbortController().signal,
56
+ next: async (inner?: { context?: Record<string, unknown> }) => {
57
+ // 与框架 callNextMiddleware 一致:next 的 context 增量并入调用方 context
58
+ merged = { ...merged, ...(inner?.context ?? {}) }
59
+ return { context: merged }
60
+ },
61
+ })
62
+ }
63
+
64
+ const FAKE_REQUEST = new Request('http://localhost:3000/_serverFn/x')
65
+
66
+ const DB_USER = {
67
+ id: 'u1',
68
+ email: 'u1@test.com',
69
+ name: '用户一',
70
+ role: 'USER',
71
+ }
72
+
73
+ describe('authContextMiddleware(function middleware 注入 context.user)', () => {
74
+ beforeEach(() => {
75
+ vi.clearAllMocks()
76
+ vi.mocked(getRequest).mockReturnValue(FAKE_REQUEST)
77
+ vi.mocked(isDesktopServer).mockReturnValue(false)
78
+ })
79
+
80
+ it('① 无 session:抛出与旧 requireAuth() 完全同型的 UnauthorizedError(name/message/constructor 逐字段一致)', async () => {
81
+ vi.mocked(getCurrentSession).mockResolvedValue(null)
82
+
83
+ // 基准:同一输入下旧 requireAuth 的抛错形状
84
+ let baseline: unknown
85
+ try {
86
+ await requireAuth(FAKE_REQUEST)
87
+ } catch (e) {
88
+ baseline = e
89
+ }
90
+ expect(baseline).toBeInstanceOf(UnauthorizedError)
91
+ const base = baseline as UnauthorizedError
92
+
93
+ let caught: unknown
94
+ try {
95
+ await runAuthContextMiddleware()
96
+ } catch (e) {
97
+ caught = e
98
+ }
99
+ expect(caught).toBeInstanceOf(UnauthorizedError)
100
+ const err = caught as UnauthorizedError
101
+ expect(err.name).toBe('UnauthorizedError')
102
+ expect(err.message).toBe('UNAUTHORIZED')
103
+ // 同型判定:与旧 requireAuth 抛错逐字段一致(客户端 401 处理依赖此形状)
104
+ expect(err.constructor).toBe(base.constructor)
105
+ expect(err.name).toBe(base.name)
106
+ expect(err.message).toBe(base.message)
107
+ })
108
+
109
+ it('①b 无 session:鉴权请求来自 getRequest()(与旧 handler 内联取法同源)', async () => {
110
+ vi.mocked(getCurrentSession).mockResolvedValue(null)
111
+ await expect(runAuthContextMiddleware()).rejects.toBeInstanceOf(UnauthorizedError)
112
+ expect(getRequest).toHaveBeenCalledTimes(1)
113
+ // requireAuth 收到的 request 与 getRequest() 返回值同源
114
+ expect(getCurrentSession).toHaveBeenCalledWith(FAKE_REQUEST)
115
+ })
116
+
117
+ it('② 有 session:context.user 为 DB 用户对象(requireAuth 返回的同一引用)', async () => {
118
+ vi.mocked(getCurrentSession).mockResolvedValue({
119
+ user: DB_USER,
120
+ } as never)
121
+
122
+ const result = await runAuthContextMiddleware()
123
+ expect(result.context).toBeDefined()
124
+ expect(result.context.user).toBe(DB_USER)
125
+ expect(result.context.user.id).toBe('u1')
126
+ })
127
+
128
+ it('②b desktop guest 降级语义保持:DEPLOY_TARGET=desktop 时匿名请求注入共享 guest 用户', async () => {
129
+ vi.mocked(getCurrentSession).mockResolvedValue(null)
130
+ vi.mocked(isDesktopServer).mockReturnValue(true)
131
+
132
+ const result = await runAuthContextMiddleware()
133
+ expect(result.context.user.id).toBe('local-guest')
134
+ expect(result.context.user.isGuest).toBe(true)
135
+ })
136
+
137
+ it('③ session 校验用户存在防线不变:session.user 为空(session callback getCachedProfile 拒绝的下游形态)→ 抛 UnauthorizedError', async () => {
138
+ // session callback 用户存在性校验失败时,session.user 为 null/缺失 id——
139
+ // middleware 必须与旧 requireAuth 一样拒绝该 session,而非注入无 id 的 user
140
+ vi.mocked(getCurrentSession).mockResolvedValue({ user: null } as never)
141
+
142
+ await expect(runAuthContextMiddleware()).rejects.toBeInstanceOf(UnauthorizedError)
143
+
144
+ // user 存在但缺 id(JWT 无 id 字段)同样拒绝
145
+ vi.mocked(getCurrentSession).mockResolvedValue({ user: { email: 'x@test.com' } } as never)
146
+ await expect(runAuthContextMiddleware()).rejects.toBeInstanceOf(UnauthorizedError)
147
+ })
148
+
149
+ it('③b 既有 context 增量保留:middleware 注入 user 不覆盖调用方已有 context 字段', async () => {
150
+ vi.mocked(getCurrentSession).mockResolvedValue({ user: DB_USER } as never)
151
+
152
+ const result = await runAuthContextMiddleware({ requestId: 'ctx-1' })
153
+ expect(result.context.requestId).toBe('ctx-1')
154
+ expect(result.context.user).toBe(DB_USER)
155
+ })
156
+ })
@@ -0,0 +1,62 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+ //
5
+ // This program is free software: you can redistribute it and/or modify
6
+ // it under the terms of the GNU Affero General Public License as published by
7
+ // the Free Software Foundation, either version 3 of the License, or
8
+ // (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU Affero General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU Affero General Public License
16
+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ import { createMiddleware } from '@tanstack/react-start'
19
+ import { getRequest } from '@tanstack/react-start/server'
20
+ import { requireAuth } from '@/server/auth-helpers'
21
+ import type { AuthedSession } from '@/server/auth-helpers'
22
+
23
+ /**
24
+ * context.user 的注入类型:与 requireAuth 成功返回的 session.user 同型
25
+ * (SessionUser & { id: string },消费方免非空断言)。
26
+ */
27
+ export type AuthedContextUser = AuthedSession['user']
28
+
29
+ /**
30
+ * function middleware 注入的 context 增量形状(per-fn `.middleware()` 挂载后,
31
+ * handler 的 `context` 参数自动获得本类型)。
32
+ */
33
+ export interface AuthedContext {
34
+ user: AuthedContextUser
35
+ }
36
+
37
+ /**
38
+ * serverFn 鉴权 context 注入 middleware(TanStack 优化计划任务 6,team 域试点)。
39
+ *
40
+ * 复核结论(@tanstack/react-start@1.169.4 / start-client-core@1.170.39,.d.ts 实证):
41
+ * - per-fn `.middleware()` 是本基建采用的唯一挂载路径:`createServerFn(...).middleware([mw])`
42
+ * (createServerFn.d.ts ServerFnMiddleware),middleware 的 `.server()` 产出 context 经
43
+ * `AssignAllServerFnContext` 自动流入 handler 的 `context` 类型(ServerFnCtx),
44
+ * 无需 `declare module` augmentation。
45
+ * - 全局挂载点在本版本实际存在(StartInstanceOptions.functionMiddleware 声明 +
46
+ * createServerFn.js 运行时把 getStartOptions().functionMiddleware 拼进执行链),
47
+ * 但不用:① 全局路径的类型注入依赖 Register.config augmentation(app 的 Register
48
+ * 仅 augment 了 router);② 全局注入会对全部 serverFn(含邀请 token 查询、bug 上报
49
+ * 等 ~600 个公开/免鉴权端点)跑鉴权查询,改变公开端点行为与性能。T7 CI 守护按
50
+ * per-fn 存在性检查配套。
51
+ * - 错误同型:middleware 抛错与 handler 内抛错走同一条 RPC 错误序列化路径
52
+ * (handleServerAction 同一 try/catch → createServerFnErrorResponse),故本 middleware
53
+ * 内部直接复用 `requireAuth(getRequest())` 旧链,UnauthorizedError 形状零变化
54
+ * (客户端 401 处理依赖)。资源属主校验(assertOwned 等)不在此层,仍在各 handler。
55
+ */
56
+ export const authContextMiddleware = createMiddleware({ type: 'function' }).server<AuthedContext>(
57
+ async ({ next }) => {
58
+ const request = getRequest()
59
+ const session = await requireAuth(request)
60
+ return next({ context: { user: session.user } })
61
+ },
62
+ )
@@ -1,5 +1,11 @@
1
- // DESKTOP-LEGACY(迁移 P1 标记,勿删勿改):Tauri 时代的桌面远端会话读取桥,
2
- // Electron 壳(P2)将以 preload desktopBridge 等价实现替代后整链移除。
1
+ // 桌面远端会话持久层(Electron):读写 Electron 宿主注入的
2
+ // DESKTOP_USER_DATA_DIR 下的 remote-auth.json(main.ts 集中注入 env,
3
+ // backend serverFn 进程内 fs 直达,无 IPC)。Tauri invoke 实现已随
4
+ // Tauri 2 → Electron 迁移清除(2026-10-31);云/Web 部署(DEPLOY_TARGET
5
+ // 非 desktop)恒 null / no-op,行为与旧版一致。
6
+ import { promises as fs } from "node:fs"
7
+ import path from "node:path"
8
+
3
9
  export interface RemoteAuthData {
4
10
  userId: string
5
11
  planName: string
@@ -16,23 +22,61 @@ export interface RemoteAuthData {
16
22
  bgColor?: string
17
23
  }
18
24
 
19
- export async function readRemoteAuth(): Promise<RemoteAuthData | null> {
20
- if (process.env.DEPLOY_TARGET !== 'desktop') return null
25
+ /** 磁盘形态:auth(登录 token)与 session(exchange 后的会话态)分次写入、合并读取 */
26
+ interface RemoteAuthFile {
27
+ token?: string
28
+ sessionToken?: string
29
+ session?: {
30
+ userId: string
31
+ planName: string
32
+ sessionToken?: string
33
+ }
34
+ }
35
+
36
+ function filePath(): string | null {
37
+ const dir = process.env.DESKTOP_USER_DATA_DIR
38
+ if (!dir) return null
39
+ return path.join(dir, "remote-auth.json")
40
+ }
41
+
42
+ async function readFile(): Promise<RemoteAuthFile | null> {
43
+ const file = filePath()
44
+ if (!file) return null
21
45
  try {
22
- const { invoke } = await import('@tauri-apps/api/core')
23
- return (await invoke<RemoteAuthData | null>('read_remote_auth')) ?? null
46
+ return JSON.parse(await fs.readFile(file, "utf8")) as RemoteAuthFile
24
47
  } catch {
48
+ // 文件不存在/损坏均视为未登录(损坏文件在下次写入时被覆盖自愈)
25
49
  return null
26
50
  }
27
51
  }
28
52
 
29
- // 写入防御(2026-10 审计 🟢:原 invoke 无 try/catch,rejection 完全依赖调用方兜底,
30
- // 与 readRemoteAuth 的防御风格不一致——本地持久化失败不应反噬登录/登出主流程)
53
+ async function writeFile(next: RemoteAuthFile): Promise<void> {
54
+ const file = filePath()
55
+ if (!file) return
56
+ const tmp = `${file}.tmp`
57
+ // 0600:文件含云会话 token(敏感),限属主读写;tmp+rename 原子替换防半写
58
+ await fs.writeFile(tmp, JSON.stringify(next, null, 2), { mode: 0o600 })
59
+ await fs.rename(tmp, file)
60
+ }
61
+
62
+ export async function readRemoteAuth(): Promise<RemoteAuthData | null> {
63
+ if (process.env.DEPLOY_TARGET !== 'desktop') return null
64
+ const data = await readFile()
65
+ if (!data?.session?.userId) return null
66
+ return {
67
+ userId: data.session.userId,
68
+ planName: data.session.planName,
69
+ features: {},
70
+ sessionToken: data.session.sessionToken ?? data.sessionToken,
71
+ }
72
+ }
73
+
74
+ // 写入防御(2026-10 审计 🟢):本地持久化失败不应反噬登录/登出主流程
31
75
  export async function writeRemoteAuth(token: string, sessionToken?: string): Promise<void> {
32
76
  if (process.env.DEPLOY_TARGET !== 'desktop') return
33
- const { invoke } = await import('@tauri-apps/api/core')
34
77
  try {
35
- await invoke('write_remote_auth', { token, sessionToken })
78
+ const prev = (await readFile()) ?? {}
79
+ await writeFile({ ...prev, token, sessionToken })
36
80
  } catch (e) {
37
81
  console.warn('[remote-auth] write_remote_auth 失败(本地权益态未更新):', e instanceof Error ? e.message : String(e))
38
82
  }
@@ -44,9 +88,9 @@ export async function writeRemoteSession(
44
88
  sessionToken?: string,
45
89
  ): Promise<void> {
46
90
  if (process.env.DEPLOY_TARGET !== 'desktop') return
47
- const { invoke } = await import('@tauri-apps/api/core')
48
91
  try {
49
- await invoke('write_remote_session', { userId, planName, sessionToken })
92
+ const prev = (await readFile()) ?? {}
93
+ await writeFile({ ...prev, session: { userId, planName, sessionToken } })
50
94
  } catch (e) {
51
95
  console.warn('[remote-auth] write_remote_session 失败(本地会话态未更新):', e instanceof Error ? e.message : String(e))
52
96
  }
@@ -54,27 +98,10 @@ export async function writeRemoteSession(
54
98
 
55
99
  export async function clearRemoteAuth(): Promise<void> {
56
100
  if (process.env.DEPLOY_TARGET !== 'desktop') return
57
- const { invoke } = await import('@tauri-apps/api/core')
58
101
  try {
59
- await invoke('clear_remote_auth')
102
+ const file = filePath()
103
+ if (file) await fs.rm(file, { force: true })
60
104
  } catch (e) {
61
105
  console.warn('[remote-auth] clear_remote_auth 失败(本地态可能残留):', e instanceof Error ? e.message : String(e))
62
106
  }
63
107
  }
64
-
65
- export async function openLoginUrl(loginUrl: string): Promise<void> {
66
- if (process.env.DEPLOY_TARGET !== 'desktop') {
67
- if (typeof window !== 'undefined') {
68
- window.open(
69
- loginUrl.startsWith('/')
70
- ? `${window.location.origin}${loginUrl}`
71
- : loginUrl,
72
- '_blank',
73
- 'noopener,noreferrer',
74
- )
75
- }
76
- return
77
- }
78
- const { invoke } = await import('@tauri-apps/api/core')
79
- await invoke('open_login_url', { url: loginUrl })
80
- }
@@ -2,17 +2,50 @@
2
2
  import { describe, expect, it, vi, beforeEach } from 'vitest'
3
3
 
4
4
  // ① createServerFn chain builder mock(与 ai-source-mode.test.ts 相同)
5
- vi.mock('@tanstack/react-start', () => {
6
- const createServerFn = () => {
5
+ vi.mock('@tanstack/react-start', () => ({
6
+ // 迁移后经 .middleware([authContextMiddleware]) 注入 context.user:
7
+ // mock 依序执行 middleware 的 server 段(复现框架 executeMiddleware 的
8
+ // context 合并语义),真实鉴权链由被 mock 的 auth-helpers/getRequest 承接
9
+ createServerFn: () => {
7
10
  const api: any = {
11
+ _middlewares: [] as any[],
12
+ middleware(mws: any[]) {
13
+ api._middlewares.push(...mws)
14
+ return api
15
+ },
8
16
  handler(fn: Function) {
9
- return async (args: { data: unknown }) => fn(args)
17
+ return async (args: { data: unknown }) => {
18
+ let context: any = {}
19
+ for (const mw of api._middlewares) {
20
+ const serverFn = mw?.options?.server
21
+ if (!serverFn) continue
22
+ const result = await serverFn({
23
+ data: args?.data,
24
+ context,
25
+ method: 'GET',
26
+ serverFnMeta: {},
27
+ signal: new AbortController().signal,
28
+ next: async (inner: any) => ({ context: { ...context, ...(inner?.context ?? {}) } }),
29
+ })
30
+ context = result.context
31
+ }
32
+ return fn({ ...args, context })
33
+ }
10
34
  },
11
35
  }
12
36
  return api
13
- }
14
- return { createServerFn }
15
- })
37
+ },
38
+ // auth-context.ts 依赖 createMiddleware({ type: 'function' }).server(fn):
39
+ // mock 产出与真实 middleware 同构的 { options: { server } } 形状
40
+ createMiddleware: (opts: any) => {
41
+ const mw: any = { options: { type: opts?.type } }
42
+ mw.server = (fn: Function) => {
43
+ mw.options.server = fn
44
+ return mw
45
+ }
46
+ return mw
47
+ },
48
+ }))
16
49
  vi.mock('@tanstack/react-start/server', () => ({
17
50
  getRequest: () => ({}),
18
51
  }))
@@ -22,20 +55,19 @@ const mocks = vi.hoisted(() => ({
22
55
  currentSession: vi.fn(),
23
56
  }))
24
57
 
25
- vi.mock('@allbluecn/kernel', async (importOriginal) => {
26
- const actual = await importOriginal<typeof import('@allbluecn/kernel')>()
58
+ // 迁移后 requireAuth 消费入口:authContextMiddleware 内部调用
59
+ vi.mock('@/server/auth-helpers', async (importOriginal) => {
60
+ const actual = await importOriginal<typeof import('@/server/auth-helpers')>()
27
61
  const UnauthorizedError = class UnauthorizedError extends Error {
28
62
  constructor(message = 'UNAUTHORIZED') { super(message); this.name = 'UnauthorizedError' }
29
63
  }
30
64
  return {
31
65
  ...actual,
32
- getServerSeam: () => ({
33
- requireAuth: async () => {
34
- const session = await mocks.currentSession()
35
- if (!session?.user?.id) throw new UnauthorizedError()
36
- return session
37
- },
38
- }),
66
+ requireAuth: async () => {
67
+ const session = await mocks.currentSession()
68
+ if (!session?.user?.id) throw new UnauthorizedError()
69
+ return session
70
+ },
39
71
  }
40
72
  })
41
73
 
@@ -2,9 +2,17 @@
2
2
  import { describe, expect, it, vi, beforeEach } from 'vitest'
3
3
 
4
4
  // ① createServerFn chain builder mock(照抄 workspace-kb-idor.test.ts:25-45)
5
- vi.mock('@tanstack/react-start', () => {
6
- const createServerFn = () => {
5
+ vi.mock('@tanstack/react-start', () => ({
6
+ // 迁移后经 .middleware([authContextMiddleware]) 注入 context.user:
7
+ // mock 依序执行 middleware 的 server 段(复现框架 executeMiddleware 的
8
+ // context 合并语义),真实鉴权链由被 mock 的 auth-helpers/getRequest 承接
9
+ createServerFn: () => {
7
10
  const api: any = {
11
+ _middlewares: [] as any[],
12
+ middleware(mws: any[]) {
13
+ api._middlewares.push(...mws)
14
+ return api
15
+ },
8
16
  validator(schema: { parse: (d: unknown) => unknown }) {
9
17
  api._validator = schema
10
18
  return api
@@ -15,14 +23,37 @@ vi.mock('@tanstack/react-start', () => {
15
23
  if (api._validator && data !== undefined) {
16
24
  data = api._validator.parse ? api._validator.parse(data) : data
17
25
  }
18
- return fn({ data })
26
+ let context: any = {}
27
+ for (const mw of api._middlewares) {
28
+ const serverFn = mw?.options?.server
29
+ if (!serverFn) continue
30
+ const result = await serverFn({
31
+ data,
32
+ context,
33
+ method: 'POST',
34
+ serverFnMeta: {},
35
+ signal: new AbortController().signal,
36
+ next: async (inner: any) => ({ context: { ...context, ...(inner?.context ?? {}) } }),
37
+ })
38
+ context = result.context
39
+ }
40
+ return fn({ data, context })
19
41
  }
20
42
  },
21
43
  }
22
44
  return api
23
- }
24
- return { createServerFn }
25
- })
45
+ },
46
+ // auth-context.ts 依赖 createMiddleware({ type: 'function' }).server(fn):
47
+ // mock 产出与真实 middleware 同构的 { options: { server } } 形状
48
+ createMiddleware: (opts: any) => {
49
+ const mw: any = { options: { type: opts?.type } }
50
+ mw.server = (fn: Function) => {
51
+ mw.options.server = fn
52
+ return mw
53
+ }
54
+ return mw
55
+ },
56
+ }))
26
57
  vi.mock('@tanstack/react-start/server', () => ({
27
58
  getRequest: () => ({}),
28
59
  }))
@@ -32,20 +63,19 @@ const mocks = vi.hoisted(() => ({
32
63
  currentSession: vi.fn(),
33
64
  }))
34
65
 
35
- vi.mock('@allbluecn/kernel', async (importOriginal) => {
36
- const actual = await importOriginal<typeof import('@allbluecn/kernel')>()
66
+ // 迁移后 requireAuth 消费入口:authContextMiddleware 内部调用
67
+ vi.mock('@/server/auth-helpers', async (importOriginal) => {
68
+ const actual = await importOriginal<typeof import('@/server/auth-helpers')>()
37
69
  const UnauthorizedError = class UnauthorizedError extends Error {
38
70
  constructor(message = 'UNAUTHORIZED') { super(message); this.name = 'UnauthorizedError' }
39
71
  }
40
72
  return {
41
73
  ...actual,
42
- getServerSeam: () => ({
43
- requireAuth: async () => {
44
- const session = await mocks.currentSession()
45
- if (!session?.user?.id) throw new UnauthorizedError()
46
- return session
47
- },
48
- }),
74
+ requireAuth: async () => {
75
+ const session = await mocks.currentSession()
76
+ if (!session?.user?.id) throw new UnauthorizedError()
77
+ return session
78
+ },
49
79
  }
50
80
  })
51
81
 
@@ -46,11 +46,16 @@ vi.mock("@tanstack/react-start", () => ({
46
46
  createServerFn: () => {
47
47
  const api = {
48
48
  _validator: undefined as unknown,
49
+ _middlewares: [] as unknown[],
50
+ middleware(mws: unknown[]) {
51
+ this._middlewares.push(...mws);
52
+ return this;
53
+ },
49
54
  validator(schema: unknown) {
50
55
  this._validator = schema;
51
56
  return this;
52
57
  },
53
- handler(fn: (p: { data: unknown }) => Promise<unknown>) {
58
+ handler(fn: (p: { data: unknown; context: unknown }) => Promise<unknown>) {
54
59
  const self = this;
55
60
  return async (args: { data?: unknown }) => {
56
61
  let data = args?.data;
@@ -58,12 +63,42 @@ vi.mock("@tanstack/react-start", () => ({
58
63
  const v = self._validator as { parse?: (d: unknown) => unknown };
59
64
  data = v.parse ? v.parse(data) : data;
60
65
  }
61
- return fn({ data });
66
+ // 迁移后经 .middleware([authContextMiddleware]) 注入 context.user:
67
+ // 依序执行 middleware 的 server 段,真实鉴权链由被 mock 的 auth-helpers 承接
68
+ let context: unknown = {};
69
+ for (const mw of self._middlewares) {
70
+ const serverFn = (mw as { options?: { server?: unknown } })?.options?.server;
71
+ if (typeof serverFn !== "function") continue;
72
+ const result = await (
73
+ serverFn as (p: unknown) => Promise<{ context?: unknown }>
74
+ )({
75
+ data,
76
+ context,
77
+ method: "POST",
78
+ serverFnMeta: {},
79
+ signal: new AbortController().signal,
80
+ next: (inner: { context?: unknown } | undefined) =>
81
+ Promise.resolve({ context: { ...(context as object), ...(inner?.context ?? {}) } }),
82
+ });
83
+ context = result.context;
84
+ }
85
+ return fn({ data, context });
62
86
  };
63
87
  },
64
88
  };
65
89
  return api;
66
90
  },
91
+ // auth-context.ts 依赖 createMiddleware({ type: 'function' }).server(fn):
92
+ // mock 产出与真实 middleware 同构的 { options: { server } } 形状,
93
+ // 供上方 handler 包装器执行 server 段注入 context.user
94
+ createMiddleware: (opts: any) => {
95
+ const mw: any = { options: { type: opts?.type } };
96
+ mw.server = (fn: Function) => {
97
+ mw.options.server = fn;
98
+ return mw;
99
+ };
100
+ return mw;
101
+ },
67
102
  }));
68
103
 
69
104
  vi.mock("@tanstack/react-start/server", () => ({ getRequest: () => ({}) }));
@@ -28,7 +28,6 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
28
28
  import { readFileSync } from "node:fs";
29
29
  import { join } from "node:path";
30
30
  import * as Y from "yjs";
31
- import type { ZodType } from "zod";
32
31
 
33
32
  const mocks = vi.hoisted(() => ({
34
33
  requireAuth: vi.fn(),
@@ -43,30 +42,58 @@ const mocks = vi.hoisted(() => ({
43
42
  }));
44
43
 
45
44
  vi.mock("@tanstack/react-start", () => ({
46
- createServerFn: (_config: unknown) => {
47
- const api: {
48
- _validator?: ZodType;
49
- validator: (schema: ZodType) => unknown;
50
- handler: (fn: (args: { data: unknown }) => unknown) => unknown;
51
- } = {
45
+ // 迁移后经 .middleware([authContextMiddleware]) 注入 context.user:
46
+ // mock 依序执行 middleware 的 server 段(复现框架 executeMiddleware 的
47
+ // context 合并语义),真实鉴权链由被 mock 的 auth-helpers/getRequest 承接
48
+ createServerFn: (config: any) => {
49
+ const api: any = {
52
50
  _validator: undefined,
53
- validator(schema: ZodType) {
51
+ _middlewares: [] as any[],
52
+ middleware(mws: any[]) {
53
+ api._middlewares.push(...mws);
54
+ return api;
55
+ },
56
+ validator(schema: any) {
54
57
  this._validator = schema;
55
58
  return this;
56
59
  },
57
- handler(fn: (args: { data: unknown }) => unknown) {
58
- const validator = this._validator;
59
- return async (args: { data?: unknown }) => {
60
+ handler(fn: Function) {
61
+ const wrapped = async (args: any) => {
60
62
  let data = args?.data;
61
- if (validator && data !== undefined) {
62
- data = validator.parse(data);
63
+ if (api._validator && data !== undefined) {
64
+ data = api._validator.parse ? api._validator.parse(data) : data;
65
+ }
66
+ let context: any = {};
67
+ for (const mw of api._middlewares) {
68
+ const serverFn = mw?.options?.server;
69
+ if (!serverFn) continue;
70
+ const result = await serverFn({
71
+ data,
72
+ context,
73
+ method: "POST",
74
+ serverFnMeta: {},
75
+ signal: new AbortController().signal,
76
+ next: async (inner: any) => ({ context: { ...context, ...(inner?.context ?? {}) } }),
77
+ });
78
+ context = result.context;
63
79
  }
64
- return fn({ data });
80
+ return fn({ data, context });
65
81
  };
82
+ return wrapped;
66
83
  },
67
84
  };
68
85
  return api;
69
86
  },
87
+ // auth-context.ts 依赖 createMiddleware({ type: "function" }).server(fn):
88
+ // mock 产出与真实 middleware 同构的 { options: { server } } 形状
89
+ createMiddleware: (opts: any) => {
90
+ const mw: any = { options: { type: opts?.type } };
91
+ mw.server = (fn: Function) => {
92
+ mw.options.server = fn;
93
+ return mw;
94
+ };
95
+ return mw;
96
+ },
70
97
  }));
71
98
 
72
99
  vi.mock("@tanstack/react-start/server", () => ({