@allbluecn/web-app 0.10.3 → 0.11.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 (246) hide show
  1. package/package.json +24 -11
  2. package/public/favicon-dark.svg +1 -0
  3. package/public/favicon.ico +0 -0
  4. package/public/favicon.svg +1 -0
  5. package/public/logo/allblue-logo-app-icon.svg +7 -0
  6. package/public/logo/allblue-logo-dark-square.svg +4 -0
  7. package/public/logo/allblue-logo-dark.png +0 -0
  8. package/public/logo/allblue-logo-dark.svg +4 -0
  9. package/public/logo/allblue-logo-light-square.svg +4 -0
  10. package/public/logo/allblue-logo-light.png +0 -0
  11. package/public/logo/allblue-logo-light.svg +4 -0
  12. package/src/__tests__/bench/baselines/format-timestamp.json +44 -0
  13. package/src/__tests__/bench/core-hot-path.bench.ts +71 -0
  14. package/src/__tests__/integration/db-crud.integration.test.ts +79 -0
  15. package/src/__tests__/integration/login-email-acceptance.test.ts +202 -0
  16. package/src/__tests__/integration/login-email-p2-acceptance.test.ts +142 -0
  17. package/src/__tests__/rejects-tothrow-regression.test.ts +31 -0
  18. package/src/__tests__/security/ai/prompt-injection.test.ts +105 -0
  19. package/src/__tests__/security/ssrf-url-whitelist.test.ts +54 -0
  20. package/src/__tests__/security/xss-sanitize.test.ts +99 -0
  21. package/src/__tests__/setup.ts +9 -0
  22. package/src/__tests__/visual/__screenshots__/theme-surface.vrt.test.tsx/theme-surface-dark-baseline-1-chromium-darwin.png +0 -0
  23. package/src/__tests__/visual/__screenshots__/theme-surface.vrt.test.tsx/theme-surface-light-baseline-1-chromium-darwin.png +0 -0
  24. package/src/__tests__/visual/__screenshots__/user-avatar.vrt.test.tsx/user-avatar-initial-fallback-baseline-1-chromium-darwin.png +0 -0
  25. package/src/__tests__/visual/theme-surface.vrt.test.tsx +54 -0
  26. package/src/__tests__/visual/user-avatar.vrt.test.tsx +32 -0
  27. package/src/components/auth/icon-input.tsx +9 -1
  28. package/src/components/auth/password-input.tsx +9 -1
  29. package/src/components/changelog/changelog-page.tsx +44 -1
  30. package/src/components/error/global-error-boundary.tsx +2 -2
  31. package/src/components/forms/app-field.tsx +3 -1
  32. package/src/components/knowledge/general-groups.ts +15 -0
  33. package/src/components/knowledge/kb-filter-popover.tsx +143 -0
  34. package/src/components/knowledge/knowledge-toolbar.tsx +17 -21
  35. package/src/components/knowledge-public/legal-compliance-editor.tsx +4 -2
  36. package/src/components/layout/sidebar-03/__tests__/nav-workspace.test.tsx +9 -6
  37. package/src/components/layout/sidebar-03/app-sidebar.tsx +4 -15
  38. package/src/components/layout/sidebar-03/nav-knowledge.tsx +19 -17
  39. package/src/components/layout/sidebar-03/nav-workspace.tsx +20 -22
  40. package/src/components/notifications/settings-notifications.tsx +41 -1
  41. package/src/components/settings/personal-team/account/settings-profile.tsx +68 -1
  42. package/src/components/shared-kit/avatars/notion-avatar.tsx +2 -1
  43. package/src/components/shared-kit/icons/__tests__/lucide-curated-icons.test.ts +2 -2
  44. package/src/components/shared-kit/icons/__tests__/lucide-icon-picker.test.tsx +3 -2
  45. package/src/components/shared-kit/icons/lucide-icon-picker/curated-icons.ts +5 -10
  46. package/src/components/shared-kit/icons/lucide-icon-picker/lucide-icon-by-name.tsx +3 -3
  47. package/src/components/shared-kit/theme/theme-surface.tsx +52 -0
  48. package/src/components/story/relations/general-groups.ts +1 -15
  49. package/src/components/story/relations/knowledge-select-dialog.tsx +13 -87
  50. package/src/components/story/story-list-view.tsx +7 -1
  51. package/src/components/tiptap/node/table-node/ui/table-move-row-column-button/use-table-move-row-column.ts +0 -2
  52. package/src/components/workspace/__tests__/activity/workspace-activity-card.test.tsx +36 -0
  53. package/src/components/workspace/__tests__/contribution/workspace-contribution-card.test.tsx +17 -0
  54. package/src/components/workspace/__tests__/dialogs/create-workspace-dialog.test.tsx +63 -0
  55. package/src/components/workspace/__tests__/dialogs/delete-workspace-options.test.tsx +89 -0
  56. package/src/components/workspace/__tests__/dialogs/edit-workspace-dialog.test.tsx +68 -0
  57. package/src/components/workspace/__tests__/header/workspace-header.test.tsx +40 -0
  58. package/src/components/workspace/__tests__/kb/workspace-kb-card.test.tsx +154 -0
  59. package/src/components/workspace/__tests__/members/workspace-member-item.test.tsx +24 -0
  60. package/src/components/workspace/__tests__/members/workspace-members-manager.test.tsx +51 -0
  61. package/src/components/workspace/__tests__/projects/workspace-project-list.test.tsx +46 -0
  62. package/src/components/workspace/{create-workspace-dialog.tsx → dialogs/create-workspace-dialog.tsx} +1 -1
  63. package/src/components/workspace/{edit-workspace-dialog.tsx → dialogs/edit-workspace-dialog.tsx} +1 -1
  64. package/src/components/workspace/kb/workspace-kb-card.tsx +594 -0
  65. package/src/components/workspace/kb/workspace-kb-manage-dialog.tsx +174 -0
  66. package/src/components/workspace/kb/workspace-quick-doc-dialog.tsx +431 -0
  67. package/src/components/workspace/{workspace-members-manager.tsx → members/workspace-members-manager.tsx} +78 -40
  68. package/src/lib/__tests__/edition-desktop.test.ts +23 -0
  69. package/src/lib/__tests__/msw-sample.test.ts +68 -0
  70. package/src/lib/__tests__/pgvector.test.ts +2 -2
  71. package/src/lib/app-version.ts +1 -1
  72. package/src/lib/auth/auth.config.ts +123 -99
  73. package/src/lib/changelog/sdk-versions.ts +21 -21
  74. package/src/lib/collections/knowledge/knowledge-bases-collection.ts +3 -1
  75. package/src/lib/collections/reference/workspaces-collection.ts +3 -1
  76. package/src/lib/edition-desktop.ts +22 -0
  77. package/src/lib/fetch-json.ts +23 -0
  78. package/src/{components/workspace/workspace-kb-card.tsx → lib/i18n/resolver.ts} +6 -12
  79. package/src/lib/sanitize.ts +14 -1
  80. package/src/lib/session.ts +10 -2
  81. package/src/lib/vector-store/__tests__/factory.test.ts +1 -1
  82. package/src/lib/vector-store/__tests__/sqlite-vec-store.test.ts +2 -2
  83. package/src/plugins/core/tags/__tests__/tags.test.ts +10 -10
  84. package/src/routeTree.gen.ts +114 -0
  85. package/src/routes/__root.tsx +20 -3
  86. package/src/routes/__tests__/-auth-schemas.test.ts +62 -0
  87. package/src/routes/__tests__/-edition-routing.test.tsx +18 -5
  88. package/src/routes/__tests__/route-tree-structure.test.ts +66 -0
  89. package/src/routes/_login/changelog/confirm/route.lazy.tsx +72 -0
  90. package/src/routes/_login/changelog/confirm/route.tsx +28 -0
  91. package/src/routes/_login/email-unsubscribe/route.lazy.tsx +76 -0
  92. package/src/routes/_login/email-unsubscribe/route.tsx +28 -0
  93. package/src/routes/_login/forgot-password/route.lazy.tsx +2 -1
  94. package/src/routes/_login/login/route.lazy.tsx +4 -2
  95. package/src/routes/_login/register/route.lazy.tsx +28 -17
  96. package/src/routes/_login/register/route.tsx +8 -1
  97. package/src/routes/_login/reset-password/route.lazy.tsx +4 -2
  98. package/src/routes/_login/schemas/-auth.ts +30 -7
  99. package/src/routes/_login/verify-email/route.lazy.tsx +82 -0
  100. package/src/routes/_login/verify-email/route.tsx +28 -0
  101. package/src/routes/_nav/knowledge/compliance/index.lazy.tsx +5 -2
  102. package/src/routes/_nav/knowledge/index.lazy.tsx +1 -1
  103. package/src/routes/_nav/knowledge/laws/index.lazy.tsx +5 -2
  104. package/src/routes/_nav/route.tsx +26 -0
  105. package/src/routes/_nav/workspaces/$workspaceId/route.lazy.tsx +13 -11
  106. package/src/routes/_nav/workspaces/$workspaceId/route.tsx +4 -2
  107. package/src/routes/_nav/workspaces/$workspaceId/settings/route.lazy.tsx +1 -1
  108. package/src/routes/_nav/workspaces/index.lazy.tsx +3 -3
  109. package/src/routes/_public/index/route.tsx +2 -1
  110. package/src/routes/api/auth/desktop-callback.ts +2 -2
  111. package/src/routes/api/billing-webhook.ts +4 -0
  112. package/src/routes/api/cron/changelog-release.ts +100 -0
  113. package/src/routes/api/cron/subscription-reminders.ts +110 -0
  114. package/src/routes/api.auth.$.ts +3 -5
  115. package/src/server/__tests__/agent-crud.test.ts +4 -4
  116. package/src/server/__tests__/auth-registration.test.ts +60 -0
  117. package/src/server/__tests__/chat-conversations.test.ts +1 -3
  118. package/src/server/__tests__/fetch-guard.test.ts +99 -0
  119. package/src/server/__tests__/permissions.test.ts +1 -3
  120. package/src/server/__tests__/resources.team-seats.test.ts +2 -0
  121. package/src/server/__tests__/skill-crud.test.ts +3 -3
  122. package/src/server/ai-gateway/__tests__/ai-output-guard.test.ts +95 -0
  123. package/src/server/ai-gateway/__tests__/kb-context-guard.test.ts +136 -0
  124. package/src/server/ai-gateway/__tests__/knowledge-search-fence.test.ts +240 -0
  125. package/src/server/ai-gateway/__tests__/llm-fence.test.ts +125 -0
  126. package/src/server/ai-gateway/__tests__/run-store.test.ts +52 -0
  127. package/src/server/ai-gateway/ai-output-guard.ts +77 -0
  128. package/src/server/ai-gateway/index.ts +5 -0
  129. package/src/server/ai-gateway/kb-context-guard.ts +46 -0
  130. package/src/server/ai-gateway/llm-fence.ts +82 -0
  131. package/src/server/ai-gateway/persistence/run-store.ts +19 -0
  132. package/src/server/ai-gateway/story-prompt.ts +4 -2
  133. package/src/server/ai-gateway/tools/definitions.ts +12 -6
  134. package/src/server/ai-gateway/tools/server.ts +97 -54
  135. package/src/server/auth-registration.ts +40 -0
  136. package/src/server/billing-email.ts +39 -0
  137. package/src/server/builtin-project.ts +21 -0
  138. package/src/server/email/__tests__/deliverability.test.ts +68 -0
  139. package/src/server/email/__tests__/index.test.ts +32 -0
  140. package/src/server/email/__tests__/outbox.test.tsx +129 -0
  141. package/src/server/email/__tests__/product-templates.test.tsx +106 -0
  142. package/src/server/email/__tests__/registry.test.tsx +50 -0
  143. package/src/server/email/deliverability.ts +57 -0
  144. package/src/server/email/drivers/console.ts +11 -0
  145. package/src/server/email/drivers/resend.ts +31 -0
  146. package/src/server/email/drivers/smtp.ts +27 -0
  147. package/src/server/email/index.ts +56 -0
  148. package/src/server/email/outbox.ts +141 -0
  149. package/src/server/email/preferences.ts +20 -0
  150. package/src/server/email/registry.ts +38 -0
  151. package/src/server/email/sender.ts +36 -13
  152. package/src/server/email/templates/_base/button.tsx +12 -0
  153. package/src/server/email/templates/_base/email-layout.tsx +117 -0
  154. package/src/server/email/templates/_base/theme-fonts.tsx +43 -0
  155. package/src/server/email/templates/_base/theme.ts +22 -0
  156. package/src/server/email/templates/auth/reset-password.tsx +58 -0
  157. package/src/server/email/templates/auth/verify-email.tsx +59 -0
  158. package/src/server/email/templates/auth/welcome.tsx +49 -0
  159. package/src/server/email/templates/billing/payment-receipt.tsx +51 -0
  160. package/src/server/email/templates/billing/subscription-canceled.tsx +51 -0
  161. package/src/server/email/templates/billing/subscription-ending.tsx +51 -0
  162. package/src/server/email/templates/notification/mirror.tsx +50 -0
  163. package/src/server/email/templates/product/changelog-confirm.tsx +53 -0
  164. package/src/server/email/templates/product/changelog-release.tsx +65 -0
  165. package/src/server/email/templates/team/apply-notify.tsx +53 -0
  166. package/src/server/email/templates/team/approved.tsx +53 -0
  167. package/src/server/email/templates/team/invite.tsx +57 -0
  168. package/src/server/fetch-guard.ts +170 -0
  169. package/src/server/middlewares/security-headers.ts +122 -0
  170. package/src/server/notifications/__tests__/email-mirror.test.ts +193 -0
  171. package/src/server/notifications/__tests__/verify-reminder.test.ts +94 -0
  172. package/src/server/notifications/notification-service.ts +71 -1
  173. package/src/server/notifications/verify-reminder.ts +55 -0
  174. package/src/server/oauth-config.ts +59 -0
  175. package/src/server/serverFns/__tests__/auth-server-schemas.test.ts +168 -0
  176. package/src/server/serverFns/__tests__/billing.test.ts +263 -0
  177. package/src/server/serverFns/__tests__/email-verification.test.ts +149 -0
  178. package/src/server/serverFns/__tests__/link-preview.test.ts +239 -0
  179. package/src/server/serverFns/__tests__/project-kb.test.ts +3 -3
  180. package/src/server/serverFns/__tests__/project-team-assign.test.ts +1 -1
  181. package/src/server/serverFns/__tests__/story-comments.test.ts +265 -0
  182. package/src/server/serverFns/__tests__/story-crud-archive-detail.test.ts +266 -0
  183. package/src/server/serverFns/__tests__/story-crud-labels-users.test.ts +227 -0
  184. package/src/server/serverFns/__tests__/story-crud.test.ts +526 -0
  185. package/src/server/serverFns/__tests__/story-links.test.ts +262 -0
  186. package/src/server/serverFns/__tests__/story-list-query.test.ts +259 -0
  187. package/src/server/serverFns/__tests__/story-reactions.test.ts +230 -0
  188. package/src/server/serverFns/__tests__/story-tree.test.ts +317 -0
  189. package/src/server/serverFns/__tests__/story-types.test.ts +294 -0
  190. package/src/server/serverFns/__tests__/team-accept.test.ts +6 -6
  191. package/src/server/serverFns/__tests__/team-invitation.test.ts +5 -5
  192. package/src/server/serverFns/__tests__/team-join-request.test.ts +8 -8
  193. package/src/server/serverFns/__tests__/update-seats.test.ts +4 -4
  194. package/src/server/serverFns/__tests__/workspace-kb-idor.test.ts +160 -0
  195. package/src/server/serverFns/__tests__/workspace-kb-utils.test.ts +54 -0
  196. package/src/server/serverFns/__tests__/workspace-kb.test.ts +348 -0
  197. package/src/server/serverFns/__tests__/workspace.test.ts +28 -8
  198. package/src/server/serverFns/auth/email-verification.ts +132 -0
  199. package/src/server/serverFns/auth/forgot-password.ts +22 -2
  200. package/src/server/serverFns/auth/providers.ts +4 -3
  201. package/src/server/serverFns/auth/register.ts +63 -19
  202. package/src/server/serverFns/auth/registration-mode.ts +23 -0
  203. package/src/server/serverFns/auth/reset-password.ts +1 -1
  204. package/src/server/serverFns/auth/{invitation.ts → verify-reminder.ts} +9 -26
  205. package/src/server/serverFns/changelog/__tests__/subscribe.test.ts +119 -0
  206. package/src/server/serverFns/changelog/subscribe.ts +89 -0
  207. package/src/server/serverFns/email-unsubscribe.ts +66 -0
  208. package/src/server/serverFns/iteration/__tests__/iteration-crud.test.ts +3 -5
  209. package/src/server/serverFns/iteration/__tests__/iteration-stories.test.ts +1 -1
  210. package/src/server/serverFns/iteration/__tests__/iteration-transfer.test.ts +2 -2
  211. package/src/server/serverFns/kb-doc-search.ts +111 -0
  212. package/src/server/serverFns/knowledge-public/compliance/create.ts +2 -1
  213. package/src/server/serverFns/knowledge-public/legal/create.ts +2 -1
  214. package/src/server/serverFns/notifications.ts +10 -0
  215. package/src/server/serverFns/story/__tests__/bulk.test.ts +1 -1
  216. package/src/server/serverFns/story/__tests__/label-suggest-fn.test.ts +2 -6
  217. package/src/server/serverFns/story/__tests__/story-assoc.test.ts +2 -4
  218. package/src/server/serverFns/story/__tests__/story-dependencies.test.ts +2 -2
  219. package/src/server/serverFns/story/__tests__/story-groups.test.ts +2 -2
  220. package/src/server/serverFns/story/kb-general-consts.ts +39 -0
  221. package/src/server/serverFns/story/kb-general.ts +30 -17
  222. package/src/server/serverFns/story/story-assoc.ts +13 -103
  223. package/src/server/serverFns/story/story-crud.ts +2 -5
  224. package/src/server/serverFns/story/story-groups.ts +4 -13
  225. package/src/server/serverFns/team.ts +50 -12
  226. package/src/server/serverFns/workspace-kb-utils.ts +138 -0
  227. package/src/server/serverFns/workspace-kb.ts +403 -0
  228. package/src/server/serverFns/workspace.ts +4 -1
  229. package/src/shared/ai-cli/__tests__/adapter.test.ts +67 -0
  230. package/src/shared/ai-cli/__tests__/cli-detector.test.ts +99 -0
  231. package/src/shared/ai-cli/adapter.ts +2 -2
  232. package/src/shared/ai-cli/cli-detector.ts +18 -9
  233. package/src/start.ts +2 -1
  234. package/src/styles/globals.css +114 -0
  235. package/src/types/jest-dom-vitest.d.ts +8 -7
  236. package/vite.shared.ts +105 -4
  237. package/public/file.svg +0 -1
  238. package/public/globe.svg +0 -1
  239. package/public/window.svg +0 -1
  240. package/src/lib/__tests__/cli-detector.test.ts +0 -80
  241. /package/src/components/workspace/{workspace-activity-card.tsx → activity/workspace-activity-card.tsx} +0 -0
  242. /package/src/components/workspace/{workspace-contribution-card.tsx → contribution/workspace-contribution-card.tsx} +0 -0
  243. /package/src/components/workspace/{delete-workspace-options.tsx → dialogs/delete-workspace-options.tsx} +0 -0
  244. /package/src/components/workspace/{workspace-header.tsx → header/workspace-header.tsx} +0 -0
  245. /package/src/components/workspace/{workspace-member-item.tsx → members/workspace-member-item.tsx} +0 -0
  246. /package/src/components/workspace/{workspace-project-list.tsx → projects/workspace-project-list.tsx} +0 -0
@@ -10,7 +10,7 @@ export const SDK_GROUPS: SdkGroup[] = [
10
10
  "name": "@tanstack/react-start",
11
11
  "displayName": "TanStack Start",
12
12
  "version": "v1.168.49",
13
- "lastUpdate": "Sep 9, 2026",
13
+ "lastUpdate": "Sep 11, 2026",
14
14
  "source": "apps/web/package.json#dependencies",
15
15
  "docsUrl": "https://tanstack.com/start/latest"
16
16
  },
@@ -18,7 +18,7 @@ export const SDK_GROUPS: SdkGroup[] = [
18
18
  "name": "@tanstack/react-router",
19
19
  "displayName": "TanStack Router",
20
20
  "version": "v1.170.32",
21
- "lastUpdate": "Sep 9, 2026",
21
+ "lastUpdate": "Sep 11, 2026",
22
22
  "source": "apps/web/package.json#dependencies",
23
23
  "docsUrl": "https://tanstack.com/router/latest"
24
24
  },
@@ -26,7 +26,7 @@ export const SDK_GROUPS: SdkGroup[] = [
26
26
  "name": "@tanstack/react-query",
27
27
  "displayName": "TanStack Query",
28
28
  "version": "v5.102.8",
29
- "lastUpdate": "Sep 9, 2026",
29
+ "lastUpdate": "Sep 11, 2026",
30
30
  "source": "apps/web/package.json#dependencies",
31
31
  "docsUrl": "https://tanstack.com/query/latest"
32
32
  },
@@ -34,7 +34,7 @@ export const SDK_GROUPS: SdkGroup[] = [
34
34
  "name": "@tanstack/ai",
35
35
  "displayName": "TanStack AI",
36
36
  "version": "v0.52.0",
37
- "lastUpdate": "Sep 9, 2026",
37
+ "lastUpdate": "Sep 11, 2026",
38
38
  "source": "apps/web/package.json#dependencies",
39
39
  "docsUrl": "https://tanstack.com/ai/latest"
40
40
  },
@@ -42,7 +42,7 @@ export const SDK_GROUPS: SdkGroup[] = [
42
42
  "name": "@tanstack/react-table",
43
43
  "displayName": "TanStack Table",
44
44
  "version": "v9.2.3",
45
- "lastUpdate": "Sep 9, 2026",
45
+ "lastUpdate": "Sep 11, 2026",
46
46
  "source": "apps/web/package.json#dependencies",
47
47
  "docsUrl": "https://tanstack.com/table/latest"
48
48
  },
@@ -50,7 +50,7 @@ export const SDK_GROUPS: SdkGroup[] = [
50
50
  "name": "@tanstack/react-form",
51
51
  "displayName": "TanStack Form",
52
52
  "version": "v2.0.0-alpha.2",
53
- "lastUpdate": "Sep 9, 2026",
53
+ "lastUpdate": "Sep 11, 2026",
54
54
  "source": "apps/web/package.json#dependencies",
55
55
  "docsUrl": "https://tanstack.com/form/latest"
56
56
  },
@@ -58,7 +58,7 @@ export const SDK_GROUPS: SdkGroup[] = [
58
58
  "name": "@tanstack/charts",
59
59
  "displayName": "TanStack Charts",
60
60
  "version": "v0.16.0",
61
- "lastUpdate": "Sep 9, 2026",
61
+ "lastUpdate": "Sep 11, 2026",
62
62
  "source": "apps/admin/package.json#dependencies",
63
63
  "docsUrl": "https://tanstack.com/charts/latest"
64
64
  },
@@ -66,7 +66,7 @@ export const SDK_GROUPS: SdkGroup[] = [
66
66
  "name": "@tanstack/react-pacer",
67
67
  "displayName": "TanStack Pacer",
68
68
  "version": "v0.23.0",
69
- "lastUpdate": "Sep 9, 2026",
69
+ "lastUpdate": "Sep 11, 2026",
70
70
  "source": "apps/web/package.json#dependencies",
71
71
  "docsUrl": "https://tanstack.com/pacer/latest"
72
72
  },
@@ -74,7 +74,7 @@ export const SDK_GROUPS: SdkGroup[] = [
74
74
  "name": "@tanstack/react-hotkeys",
75
75
  "displayName": "TanStack Hotkeys",
76
76
  "version": "v0.10.0",
77
- "lastUpdate": "Sep 9, 2026",
77
+ "lastUpdate": "Sep 11, 2026",
78
78
  "source": "apps/web/package.json#dependencies",
79
79
  "docsUrl": "https://tanstack.com/hotkeys/latest"
80
80
  },
@@ -82,7 +82,7 @@ export const SDK_GROUPS: SdkGroup[] = [
82
82
  "name": "@tanstack/react-virtual",
83
83
  "displayName": "TanStack Virtual",
84
84
  "version": "v3.14.10",
85
- "lastUpdate": "Sep 9, 2026",
85
+ "lastUpdate": "Sep 11, 2026",
86
86
  "source": "apps/admin/package.json#dependencies",
87
87
  "docsUrl": "https://tanstack.com/virtual/latest"
88
88
  }
@@ -95,15 +95,15 @@ export const SDK_GROUPS: SdkGroup[] = [
95
95
  "items": [
96
96
  {
97
97
  "name": "@allbluecn/web-app",
98
- "version": "v0.10.3",
99
- "lastUpdate": "Sep 9, 2026",
98
+ "version": "v0.11.1",
99
+ "lastUpdate": "Sep 12, 2026",
100
100
  "source": "apps/web/package.json",
101
101
  "docsUrl": "https://github.com/allbluecn/allblue"
102
102
  },
103
103
  {
104
104
  "name": "@allbluecn/kernel",
105
- "version": "v0.6.0",
106
- "lastUpdate": "Sep 9, 2026",
105
+ "version": "v0.8.0",
106
+ "lastUpdate": "Sep 12, 2026",
107
107
  "source": "packages/kernel/package.json",
108
108
  "docsUrl": "https://github.com/allbluecn/allblue"
109
109
  }
@@ -117,42 +117,42 @@ export const SDK_GROUPS: SdkGroup[] = [
117
117
  {
118
118
  "name": "Vite",
119
119
  "version": "v8.1.5",
120
- "lastUpdate": "Sep 9, 2026",
120
+ "lastUpdate": "Sep 11, 2026",
121
121
  "source": "apps/web/package.json#devDependencies",
122
122
  "docsUrl": "https://vite.dev/"
123
123
  },
124
124
  {
125
125
  "name": "Node.js",
126
126
  "version": "v24.19.0",
127
- "lastUpdate": "Sep 9, 2026",
127
+ "lastUpdate": "Sep 11, 2026",
128
128
  "source": ".nvmrc",
129
129
  "docsUrl": "https://nodejs.org/"
130
130
  },
131
131
  {
132
132
  "name": "Prisma",
133
133
  "version": "v7.8.0",
134
- "lastUpdate": "Sep 9, 2026",
134
+ "lastUpdate": "Sep 11, 2026",
135
135
  "source": "packages/database/package.json#devDependencies",
136
136
  "docsUrl": "https://www.prisma.io/docs"
137
137
  },
138
138
  {
139
139
  "name": "shadcn UI",
140
140
  "version": "v1.2.4",
141
- "lastUpdate": "Sep 9, 2026",
141
+ "lastUpdate": "Sep 11, 2026",
142
142
  "source": "apps/web/package.json#dependencies",
143
143
  "docsUrl": "https://ui.shadcn.com/"
144
144
  },
145
145
  {
146
146
  "name": "TipTap",
147
147
  "version": "v3.27.4",
148
- "lastUpdate": "Sep 9, 2026",
148
+ "lastUpdate": "Sep 11, 2026",
149
149
  "source": "apps/web/package.json#dependencies",
150
150
  "docsUrl": "https://tiptap.dev/"
151
151
  },
152
152
  {
153
153
  "name": "Lucide React",
154
- "version": "v1.27.0",
155
- "lastUpdate": "Sep 9, 2026",
154
+ "version": "v1.43.0",
155
+ "lastUpdate": "Sep 11, 2026",
156
156
  "source": "apps/web/package.json#dependencies",
157
157
  "docsUrl": "https://lucide.dev/"
158
158
  }
@@ -20,10 +20,12 @@ import { queryCollectionOptions } from '@tanstack/query-db-collection'
20
20
  import { listKnowledgeFn } from '@/server/serverFns/knowledge'
21
21
  import { getQueryClient } from '@/lib/query-client-seam'
22
22
 
23
+ export const KNOWLEDGE_BASES_QUERY_KEY = ['knowledge-bases'] as const
24
+
23
25
  export const knowledgeBasesCollection = createCollection(
24
26
  queryCollectionOptions({
25
27
  id: 'knowledge-bases',
26
- queryKey: ['knowledge-bases'],
28
+ queryKey: KNOWLEDGE_BASES_QUERY_KEY,
27
29
  queryFn: () => listKnowledgeFn(),
28
30
  getKey: (item: { id: string }) => item.id,
29
31
  queryClient: getQueryClient(),
@@ -20,10 +20,12 @@ import { queryCollectionOptions } from '@tanstack/query-db-collection'
20
20
  import { listPinnedWorkspacesBriefFn } from '@/server/serverFns/workspace'
21
21
  import { getQueryClient } from '@/lib/query-client-seam'
22
22
 
23
+ export const WORKSPACES_QUERY_KEY = ['workspaces'] as const
24
+
23
25
  export const workspacesCollection = createCollection(
24
26
  queryCollectionOptions({
25
27
  id: 'workspaces',
26
- queryKey: ['workspaces'],
28
+ queryKey: WORKSPACES_QUERY_KEY,
27
29
  queryFn: () => listPinnedWorkspacesBriefFn(),
28
30
  getKey: (item: { id: string }) => item.id,
29
31
  queryClient: getQueryClient(),
@@ -0,0 +1,22 @@
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
+ // beforeLoad 同构执行(SSR + 客户端导航),不能读 process.env;
19
+ // Vite define 已注入 import.meta.env.VITE_DEPLOY_TARGET(见 vite.shared.ts)
20
+ export function isDesktopEdition(): boolean {
21
+ return import.meta.env.VITE_DEPLOY_TARGET === 'desktop'
22
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * 带默认超时与 JSON 解析的 fetch 封装(供客户端 SDK / 工具函数复用)。
3
+ *
4
+ * 默认超时 10s:接口调用应在 10 秒内返回;超过视为网络/服务异常,
5
+ * 由上层(React Query 等)触发重试或降级。
6
+ *
7
+ * 调用方可传入自己的 AbortSignal 覆盖默认超时(如与外层 Promise.race
8
+ * 联动,或用 AbortController 手动取消),不会被默认超时覆盖。
9
+ *
10
+ * @throws 当响应非 2xx 时抛 `Error`,消息含 URL 与 HTTP 状态码,便于日志定位。
11
+ */
12
+ export async function fetchJson<T>(url: string, init?: RequestInit): Promise<T> {
13
+ const res = await fetch(url, {
14
+ ...init,
15
+ headers: {
16
+ "content-type": "application/json",
17
+ ...(init?.headers ?? {}),
18
+ },
19
+ signal: init?.signal ?? AbortSignal.timeout(10_000),
20
+ })
21
+ if (!res.ok) throw new Error(`fetchJson ${url} 失败:HTTP ${res.status}`)
22
+ return (await res.json()) as T
23
+ }
@@ -15,17 +15,11 @@
15
15
  // You should have received a copy of the GNU Affero General Public License
16
16
  // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
 
18
- import { LayoutGrid } from "lucide-react";
19
- import { m } from "@/paraglide/messages.js";
18
+ // paraglide 动态 key 解析:静态具名导出(m.xxx)覆盖不到的运行时拼接 key 场景。
19
+ import * as messages from "@/paraglide/messages.js";
20
20
 
21
- export function WorkspaceKbCard() {
22
- return (
23
- <div className="mb-6 rounded-lg border bg-card p-4">
24
- <div className="mb-3 flex items-center gap-2">
25
- <LayoutGrid className="size-4 text-muted-foreground" />
26
- <h2 className="text-base font-semibold">{m.workspace_home_kbTitle()}</h2>
27
- </div>
28
- <p className="py-4 text-center text-sm text-muted-foreground">{m.workspace_home_kbPlaceholder()}</p>
29
- </div>
30
- );
21
+ /** 按消息 key 取文案;未知 key 原样返回(便于发现缺失) */
22
+ export function t(key: string): string {
23
+ const fn = (messages as unknown as Record<string, unknown>)[key];
24
+ return typeof fn === "function" ? (fn as () => string)() : key;
31
25
  }
@@ -1,5 +1,18 @@
1
1
  import DOMPurify from 'isomorphic-dompurify'
2
2
 
3
+ // HTML 清理:默认配置(html + svg + mathMl profile 均启用),
4
+ // 覆盖富文本 diff、附件预览等 7 处 HTML 渲染场景。
3
5
  export function sanitize(html: string): string {
4
6
  return DOMPurify.sanitize(html)
5
- }
7
+ }
8
+
9
+ // SVG 清理:头像渲染(NotionAvatar)专用。
10
+ // 显式复用默认配置——DOMPurify 默认 profile 已包含 SVG 滤镜元素
11
+ // (<defs>/<filter>/<feMorphology>/<feFlood>/<feComposite>/<feMerge>/<feMergeNode>),
12
+ // 同时清除 <script>/on*/javascript: 等 XSS 载荷。
13
+ // 禁止改成 USE_PROFILES: { svg: true }——严格 SVG profile 会移除全部 fe* 滤镜元素,
14
+ // 头像轮廓辉光(feMorphology+feFlood+feComposite+feMerge)会失效渲染白屏。
15
+ // 结构完整性由 __tests__/security/xss-sanitize.test.ts 的双向断言锁定。
16
+ export function sanitizeSvg(svg: string): string {
17
+ return DOMPurify.sanitize(svg)
18
+ }
@@ -17,7 +17,7 @@
17
17
 
18
18
  import { getSession } from 'start-authjs'
19
19
  import type { AuthSession } from 'start-authjs'
20
- import { authConfig } from './auth/auth.config'
20
+ import { getAuthConfig } from './auth/auth.config'
21
21
 
22
22
  export type SessionUser = NonNullable<AuthSession['user']> & {
23
23
  id?: string
@@ -40,5 +40,13 @@ export type Session = Omit<AuthSession, 'user'> & { user?: SessionUser | null }
40
40
 
41
41
  export async function getCurrentSession(request?: Request): Promise<Session | null> {
42
42
  if (!request) return null
43
- return (await getSession(request, authConfig)) as Session | null
43
+ try {
44
+ return (await getSession(request, await getAuthConfig())) as Session | null
45
+ } catch (error) {
46
+ // JWT 解密失败(AUTH_SECRET 轮换 / 跨应用同名 cookie 污染)等效于无 session:
47
+ // 返回 null 走未登录分支;@auth/core 会自行清理坏 cookie。
48
+ // 不兜底时 JWTSessionError 会炸穿所有未捕获的调用点(route beforeLoad / serverFn)。
49
+ console.warn('[session] 读取 session 失败(坏 cookie 或 auth 配置异常),降级为未登录:', error instanceof Error ? error.message : error)
50
+ return null
51
+ }
44
52
  }
@@ -54,6 +54,6 @@ describe("getVectorStore 工厂", () => {
54
54
 
55
55
  it("未知 VECTOR_BACKEND 抛错", async () => {
56
56
  process.env.VECTOR_BACKEND = "unknown_backend";
57
- await expect(getVectorStore()).rejects.toMatchObject({ message: expect.stringContaining("未知 VECTOR_BACKEND") });
57
+ await expect(getVectorStore()).rejects.toThrow("未知 VECTOR_BACKEND");
58
58
  });
59
59
  });
@@ -131,13 +131,13 @@ describe("sqliteVecStore", () => {
131
131
  it("非法表名/列名抛错", async () => {
132
132
  await expect(
133
133
  sqliteVecStore.searchByVector([1, 0, 0, 0], "evil" as never)
134
- ).rejects.toMatchObject({ message: expect.stringContaining("非法表名") });
134
+ ).rejects.toThrow("非法表名");
135
135
  await expect(
136
136
  sqliteVecStore.deleteEmbeddings(
137
137
  "knowledge_embeddings",
138
138
  "evil" as never,
139
139
  "x"
140
140
  )
141
- ).rejects.toMatchObject({ message: expect.stringContaining("非法删除过滤列") });
141
+ ).rejects.toThrow("非法删除过滤列");
142
142
  });
143
143
  });
@@ -140,7 +140,7 @@ describe('listTagsFn', () => {
140
140
  it('未登录时抛 UnauthorizedError', async () => {
141
141
  mocks.getCurrentSession.mockResolvedValue(null)
142
142
 
143
- await expect(listTagsFn()).rejects.toMatchObject({ message: expect.stringMatching(/UNAUTHORIZED/) })
143
+ await expect(listTagsFn()).rejects.toThrow(/UNAUTHORIZED/)
144
144
  })
145
145
  })
146
146
 
@@ -194,7 +194,7 @@ describe('createTagFn', () => {
194
194
  it('未登录时抛 UnauthorizedError', async () => {
195
195
  mocks.getCurrentSession.mockResolvedValue(null)
196
196
 
197
- await expect(createTagFn({ data: { name: 'AI' } })).rejects.toMatchObject({ message: expect.stringMatching(/UNAUTHORIZED/) })
197
+ await expect(createTagFn({ data: { name: 'AI' } })).rejects.toThrow(/UNAUTHORIZED/)
198
198
  })
199
199
  })
200
200
 
@@ -227,7 +227,7 @@ describe('updateTagFn', () => {
227
227
  mocks.getCurrentSession.mockResolvedValue({ user: { id: 'user-1' } })
228
228
  mocks.findFirst.mockResolvedValue(null)
229
229
 
230
- await expect(updateTagFn({ data: { id: 't-other', name: 'X' } })).rejects.toMatchObject({ message: expect.stringMatching(/FORBIDDEN/) })
230
+ await expect(updateTagFn({ data: { id: 't-other', name: 'X' } })).rejects.toThrow(/FORBIDDEN/)
231
231
  expect(mocks.update).not.toHaveBeenCalled()
232
232
  })
233
233
 
@@ -237,13 +237,13 @@ describe('updateTagFn', () => {
237
237
  .mockResolvedValueOnce({ id: 't1', name: 'AI', userId: 'user-1' })
238
238
  .mockResolvedValueOnce({ id: 't2', name: 'AI-New', userId: 'user-1' })
239
239
 
240
- await expect(updateTagFn({ data: { id: 't1', name: 'AI-New' } })).rejects.toMatchObject({ message: expect.stringMatching(/TAG_NAME_CONFLICT/) })
240
+ await expect(updateTagFn({ data: { id: 't1', name: 'AI-New' } })).rejects.toThrow(/TAG_NAME_CONFLICT/)
241
241
  })
242
242
 
243
243
  it('未登录时抛 UnauthorizedError', async () => {
244
244
  mocks.getCurrentSession.mockResolvedValue(null)
245
245
 
246
- await expect(updateTagFn({ data: { id: 't1', name: 'X' } })).rejects.toMatchObject({ message: expect.stringMatching(/UNAUTHORIZED/) })
246
+ await expect(updateTagFn({ data: { id: 't1', name: 'X' } })).rejects.toThrow(/UNAUTHORIZED/)
247
247
  })
248
248
  })
249
249
 
@@ -258,7 +258,7 @@ describe('deleteTagFn', () => {
258
258
  mocks.getCurrentSession.mockResolvedValue({ user: { id: 'user-1' } })
259
259
  mocks.findFirst.mockResolvedValue(null)
260
260
 
261
- await expect(deleteTagFn({ data: { id: 't-other' } })).rejects.toMatchObject({ message: expect.stringMatching(/FORBIDDEN/) })
261
+ await expect(deleteTagFn({ data: { id: 't-other' } })).rejects.toThrow(/FORBIDDEN/)
262
262
  expect(mocks.update).not.toHaveBeenCalled()
263
263
  })
264
264
 
@@ -279,7 +279,7 @@ describe('deleteTagFn', () => {
279
279
  it('未登录时抛 UnauthorizedError', async () => {
280
280
  mocks.getCurrentSession.mockResolvedValue(null)
281
281
 
282
- await expect(deleteTagFn({ data: { id: 't1' } })).rejects.toMatchObject({ message: expect.stringMatching(/UNAUTHORIZED/) })
282
+ await expect(deleteTagFn({ data: { id: 't1' } })).rejects.toThrow(/UNAUTHORIZED/)
283
283
  })
284
284
  })
285
285
 
@@ -329,7 +329,7 @@ describe('reorderTagsFn', () => {
329
329
  it('未登录时抛 UnauthorizedError', async () => {
330
330
  mocks.getCurrentSession.mockResolvedValue(null)
331
331
 
332
- await expect(reorderTagsFn({ data: { orderedIds: ['t1'] } })).rejects.toMatchObject({ message: expect.stringMatching(/UNAUTHORIZED/) })
332
+ await expect(reorderTagsFn({ data: { orderedIds: ['t1'] } })).rejects.toThrow(/UNAUTHORIZED/)
333
333
  })
334
334
  })
335
335
 
@@ -342,7 +342,7 @@ describe('assignTagsToPrdFn', () => {
342
342
  mocks.getCurrentSession.mockResolvedValue({ user: { id: 'user-1' } })
343
343
  mocks.prdFindFirst.mockResolvedValue(null)
344
344
 
345
- await expect(assignTagsToPrdFn({ data: { prdId: 'p1', tagIds: ['t1'] } })).rejects.toMatchObject({ message: expect.stringMatching(/FORBIDDEN/) })
345
+ await expect(assignTagsToPrdFn({ data: { prdId: 'p1', tagIds: ['t1'] } })).rejects.toThrow(/FORBIDDEN/)
346
346
  })
347
347
 
348
348
  it('校验 tagId 不属于自己时抛 FORBIDDEN', async () => {
@@ -350,7 +350,7 @@ describe('assignTagsToPrdFn', () => {
350
350
  mocks.prdFindFirst.mockResolvedValue({ id: 'p1' })
351
351
  mocks.findFirst.mockResolvedValue(null)
352
352
 
353
- await expect(assignTagsToPrdFn({ data: { prdId: 'p1', tagIds: ['t-other'] } })).rejects.toMatchObject({ message: expect.stringMatching(/FORBIDDEN/) })
353
+ await expect(assignTagsToPrdFn({ data: { prdId: 'p1', tagIds: ['t-other'] } })).rejects.toThrow(/FORBIDDEN/)
354
354
  })
355
355
 
356
356
  it('事务内 diff 增删', async () => {