@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.
- package/package.json +4 -14
- package/src/__tests__/integration/login-email-acceptance.test.ts +16 -0
- package/src/__tests__/story-view.test.ts +33 -1
- package/src/components/agents/__tests__/agent-bindings-tab.test.tsx +221 -0
- package/src/components/agents/__tests__/agents-page.test.tsx +284 -0
- package/src/components/agents/agent-bindings-tab.tsx +59 -45
- package/src/components/agents/agent-form-dialog.tsx +3 -3
- package/src/components/agents/agent-selector.tsx +2 -3
- package/src/components/agents/agents-page.tsx +66 -31
- package/src/components/agents/slash-skill-menu.tsx +2 -3
- package/src/components/auth/__tests__/session-guard.test.tsx +74 -0
- package/src/components/auth/session-guard.tsx +8 -0
- package/src/components/billing/login-prompt-dialog.tsx +1 -1
- package/src/components/billing/subscription-provider.tsx +2 -16
- package/src/components/bug/__tests__/peek-modes.test.tsx +8 -0
- package/src/components/bug/__tests__/subgroup-header.test.tsx +202 -40
- package/src/components/bug/peek-panel.tsx +5 -3
- package/src/components/bug/views/bug-list/group.tsx +12 -2
- package/src/components/bug/views/bug-list/index.tsx +94 -67
- package/src/components/command/command-palette.tsx +10 -9
- package/src/components/design/canvas/document/frame-custom-presets.ts +9 -1
- package/src/components/design/canvas/panels/toolbar.tsx +21 -22
- package/src/components/design/canvas/react/__tests__/canvas-context-load-echo.test.tsx +199 -0
- package/src/components/design/canvas/react/__tests__/hooks.test.tsx +17 -3
- package/src/components/design/canvas/react/canvas-context.tsx +47 -26
- package/src/components/design/canvas/react/hooks.ts +39 -34
- package/src/components/design/editor/layout/__tests__/collab-param-wiring.test.tsx +17 -0
- package/src/components/design/editor/layout/__tests__/context-menu.test.tsx +17 -1
- package/src/components/design/editor/layout/__tests__/no-page-save-toast.test.tsx +17 -0
- package/src/components/design/editor/layout/__tests__/persistence-restore.test.tsx +17 -1
- package/src/components/design/editor/layout/__tests__/ssr-localstorage-smoke.test.tsx +17 -1
- package/src/components/design/editor/layout/design-editor-layout.tsx +13 -2
- package/src/components/design/editor/layout/hooks/use-design-auto-save.ts +3 -19
- package/src/components/devtools/devtools-panel.tsx +56 -0
- package/src/components/forms/__tests__/create-app-form.test.tsx +131 -0
- package/src/components/forms/app-field-error.tsx +21 -1
- package/src/components/forms/app-field.tsx +8 -8
- package/src/components/forms/app-submit.tsx +12 -9
- package/src/components/forms/create-app-form.tsx +124 -0
- package/src/components/forms/index.ts +2 -3
- package/src/components/harness/__tests__/gallery-behavior.test.tsx +37 -1
- package/src/components/harness/__tests__/harness-workbench-first-send.test.tsx +4 -1
- package/src/components/harness/__tests__/message-actions.test.tsx +7 -6
- package/src/components/harness/__tests__/use-video-generation.test.tsx +165 -0
- package/src/components/harness/ai-chat-history/index.tsx +5 -3
- package/src/components/harness/gallery/gallery-card.tsx +57 -35
- package/src/components/harness/gallery/gallery-grid.tsx +32 -15
- package/src/components/harness/gallery/gallery-types.ts +19 -0
- package/src/components/harness/gallery/gallery-video-card.tsx +54 -0
- package/src/components/harness/gallery/types.ts +2 -0
- package/src/components/harness/gallery/use-video-generation.ts +95 -0
- package/src/components/harness/harness-workbench-page.tsx +2 -3
- package/src/components/harness/message-actions.tsx +5 -3
- package/src/components/hotkeys/shortcuts-panel.tsx +28 -13
- package/src/components/iteration/__tests__/burndown-chart.test.tsx +118 -0
- package/src/components/iteration/burndown-chart.tsx +54 -23
- package/src/components/knowledge/editor/__tests__/knowledge-doc-editor-collab.test.tsx +96 -0
- package/src/components/knowledge/editor/knowledge-doc-editor.tsx +56 -1
- package/src/components/knowledge/editor/mindmap-doc-editor.tsx +12 -0
- package/src/components/knowledge/editor/use-auto-save-channels.ts +3 -1
- package/src/components/layout/sidebar-03/__tests__/nav-workspace.test.tsx +0 -4
- package/src/components/layout/sidebar-03/nav-knowledge.tsx +11 -11
- package/src/components/layout/sidebar-03/nav-main.tsx +12 -15
- package/src/components/layout/sidebar-03/nav-notifications.tsx +5 -8
- package/src/components/layout/sidebar-03/nav-workspace.tsx +11 -9
- package/src/components/notifications/__tests__/settings-notifications.test.tsx +158 -0
- package/src/components/notifications/settings-notifications.tsx +37 -13
- package/src/components/notifications/team-notifications.tsx +10 -14
- package/src/components/settings/personal-team/account/__tests__/account-client.test.tsx +170 -0
- package/src/components/settings/personal-team/account/account-client.tsx +44 -7
- package/src/components/settings/personal-team/team/team-client.tsx +17 -19
- package/src/components/shared-kit/list-kit/__tests__/frozen-header.test.ts +210 -41
- package/src/components/shared-kit/list-kit/frozen-header.ts +134 -21
- package/src/components/shared-kit/list-kit/kanban/frozen-header.ts +20 -27
- package/src/components/story/__tests__/peek-panel-patch-sync.test.tsx +8 -0
- package/src/components/story/__tests__/story-list-table.test.tsx +214 -0
- package/src/components/story/columns.tsx +11 -2
- package/src/components/story/peek-panel.tsx +4 -2
- package/src/components/story/story-list-table.tsx +16 -1
- package/src/components/story/views/story-list/__tests__/frozen-headers.test.tsx +186 -0
- package/src/components/story/views/story-list/group.tsx +12 -1
- package/src/components/story/views/story-list/index.tsx +101 -68
- package/src/components/testcase/__tests__/case-row.test.tsx +134 -2
- package/src/components/testcase/__tests__/peek-panel.test.tsx +8 -0
- package/src/components/testcase/__tests__/step-editor.test.tsx +106 -0
- package/src/components/testcase/list/grouped-list.tsx +50 -22
- package/src/components/testcase/peek-panel.tsx +7 -4
- package/src/components/testcase/step-editor.tsx +196 -150
- package/src/components/tiptap/notion-like/editor-extensions.ts +0 -3
- package/src/components/tiptap/notion-like/notion-like-editor-header.tsx +1 -31
- package/src/components/tiptap/notion-like/notion-like-editor.tsx +32 -1
- package/src/components/workspace/__tests__/dialogs/create-workspace-dialog.test.tsx +2 -28
- package/src/components/workspace/__tests__/dialogs/edit-workspace-dialog.test.tsx +2 -28
- package/src/components/workspace/dialogs/create-workspace-dialog.tsx +45 -43
- package/src/components/workspace/dialogs/edit-workspace-dialog.tsx +38 -36
- package/src/design-engine/engine/engine-decor.ts +2 -0
- package/src/design-engine/engine/engine-path.ts +2 -0
- package/src/hooks/__tests__/use-unsaved-guard.test.tsx +180 -0
- package/src/hooks/use-notifications.ts +9 -16
- package/src/hooks/use-unsaved-guard.tsx +87 -0
- package/src/lib/__tests__/pacer.test.ts +33 -96
- package/src/lib/__tests__/query-defaults.test.ts +169 -0
- package/src/lib/__tests__/query-global-error.test.ts +256 -0
- package/src/lib/anyhub/anyhub-store.ts +2 -2
- package/src/lib/changelog/sdk-versions.ts +2 -10
- package/src/lib/collab/presence-store.ts +5 -5
- package/src/lib/collab/use-presence-list-refresh.ts +2 -2
- package/src/lib/collab/use-share-presence.ts +2 -2
- package/src/lib/collections/query-keys.ts +7 -2
- package/src/lib/commands/__tests__/command-palette-state.test.ts +12 -14
- package/src/lib/commands/__tests__/registry.test.ts +6 -3
- package/src/lib/commands/command-palette-state.ts +8 -31
- package/src/lib/hotkeys/__tests__/registry.test.ts +71 -18
- package/src/lib/hotkeys/registry.ts +188 -85
- package/src/lib/hotkeys/types.ts +1 -13
- package/src/lib/pacer.ts +1 -79
- package/src/lib/queries/README.md +67 -0
- package/src/lib/queries/__tests__/agents-queries.test.ts +101 -0
- package/src/lib/queries/__tests__/compliance-queries.test.ts +136 -0
- package/src/lib/queries/__tests__/notifications-queries.test.ts +175 -0
- package/src/lib/queries/__tests__/team-queries.test.ts +87 -0
- package/src/lib/queries/agents.ts +40 -0
- package/src/lib/queries/compliance.ts +69 -0
- package/src/lib/queries/notifications.ts +63 -0
- package/src/lib/queries/team.ts +39 -0
- package/src/lib/query-defaults.ts +8 -0
- package/src/lib/query-global-error.ts +128 -0
- package/src/lib/remote-auth-client.ts +16 -0
- package/src/paraglide/README.md +1 -1
- package/src/paraglide/messages/_index.d.ts +11 -0
- package/src/paraglide/messages/_index.js +5659 -88285
- package/src/paraglide/messages/common_error_generic.d.ts +16 -0
- package/src/paraglide/messages/common_error_generic.js +29 -0
- package/src/paraglide/messages/common_unsaved_body.d.ts +16 -0
- package/src/paraglide/messages/common_unsaved_body.js +29 -0
- package/src/paraglide/messages/common_unsaved_leave.d.ts +16 -0
- package/src/paraglide/messages/common_unsaved_leave.js +29 -0
- package/src/paraglide/messages/common_unsaved_stay.d.ts +16 -0
- package/src/paraglide/messages/common_unsaved_stay.js +29 -0
- package/src/paraglide/messages/common_unsaved_title.d.ts +16 -0
- package/src/paraglide/messages/common_unsaved_title.js +29 -0
- package/src/paraglide/messages/gallery_videofailed1.d.ts +17 -0
- package/src/paraglide/messages/gallery_videofailed1.js +30 -0
- package/src/paraglide/messages/gallery_videogenerating1.d.ts +17 -0
- package/src/paraglide/messages/gallery_videogenerating1.js +30 -0
- package/src/paraglide/messages/gallery_videomissingprompt2.d.ts +17 -0
- package/src/paraglide/messages/gallery_videomissingprompt2.js +30 -0
- package/src/paraglide/messages/gallery_videoprogress1.d.ts +19 -0
- package/src/paraglide/messages/gallery_videoprogress1.js +30 -0
- package/src/paraglide/messages/gallery_videostop1.d.ts +17 -0
- package/src/paraglide/messages/gallery_videostop1.js +30 -0
- package/src/paraglide/messages/story_table_resizecolumn1.d.ts +17 -0
- package/src/paraglide/messages/story_table_resizecolumn1.js +30 -0
- package/src/providers/index.tsx +5 -50
- package/src/routeTree.gen.ts +21 -0
- package/src/router.tsx +21 -8
- package/src/routes/__root.tsx +2 -1
- package/src/routes/__tests__/-edition-routing.test.tsx +6 -1
- package/src/routes/_login/forgot-password/route.lazy.tsx +7 -6
- package/src/routes/_login/login/route.lazy.tsx +10 -9
- package/src/routes/_login/register/route.lazy.tsx +19 -18
- package/src/routes/_login/reset-password/route.lazy.tsx +10 -9
- package/src/routes/_nav/knowledge/compliance/$id.lazy.tsx +9 -12
- package/src/routes/_nav/knowledge/compliance/index.lazy.tsx +16 -13
- package/src/routes/_nav/knowledge/laws/$id.lazy.tsx +1 -1
- package/src/routes/_nav/notifications/route.tsx +6 -16
- package/src/routes/_nav/settings/-settings-tabs.tsx +9 -12
- package/src/routes/api/generate/__tests__/media.test.ts +378 -0
- package/src/routes/api/generate/media.ts +179 -0
- package/src/server/__tests__/agent-client-graph.test.ts +0 -1
- package/src/server/__tests__/agent-crud.test.ts +37 -4
- package/src/server/__tests__/bug-groups-two-level.test.ts +34 -1
- package/src/server/__tests__/chat-conversations.test.ts +37 -4
- package/src/server/__tests__/chat-list-messages.test.ts +40 -7
- package/src/server/__tests__/csv-export.test.ts +36 -3
- package/src/server/__tests__/desktop-bootstrap.test.ts +189 -0
- package/src/server/__tests__/remote-auth.test.ts +72 -0
- package/src/server/__tests__/skill-crud.test.ts +37 -4
- package/src/server/__tests__/sso-domain.test.ts +1 -1
- package/src/server/__tests__/sso-rate-limit-singleton.test.ts +123 -0
- package/src/server/__tests__/task-serverfn-crud.test.ts +35 -2
- package/src/server/__tests__/task-serverfn-queries.test.ts +35 -2
- package/src/server/__tests__/testcase-board.test.ts +38 -5
- package/src/server/__tests__/testcase-bulk.test.ts +38 -5
- package/src/server/__tests__/testcase-list-scope.test.ts +38 -5
- package/src/server/ai-gateway/__tests__/ai-output-guard.test.ts +126 -2
- package/src/server/ai-gateway/__tests__/chat-stream-builder-code-mode.test.ts +4 -0
- package/src/server/ai-gateway/__tests__/chat-stream-builder-memory.test.ts +4 -0
- package/src/server/ai-gateway/__tests__/chat-stream-builder-sandbox.test.ts +4 -0
- package/src/server/ai-gateway/__tests__/chat-stream-builder-skills.test.ts +4 -0
- package/src/server/ai-gateway/__tests__/pgvector-memory-adapter.test.ts +30 -0
- package/src/server/ai-gateway/__tests__/pgvector-memory-conformance.test.ts +92 -0
- package/src/server/ai-gateway/__tests__/source-mode.test.ts +49 -8
- package/src/server/ai-gateway/ai-output-guard.ts +50 -2
- package/src/server/ai-gateway/chat-stream-builder.ts +3 -0
- package/src/server/ai-gateway/media/index.ts +36 -29
- package/src/server/ai-gateway/media/trim-input.ts +52 -0
- package/src/server/ai-gateway/memory/pgvector-adapter.ts +27 -13
- package/src/server/ai-gateway/sandbox/__tests__/harness-sandbox.test.ts +252 -41
- package/src/server/ai-gateway/sandbox/harness-sandbox.ts +6 -67
- package/src/server/ai-gateway/source-mode.ts +24 -8
- package/src/server/desktop-bootstrap.ts +74 -0
- package/src/server/lib/__tests__/rate-limit.test.ts +0 -1
- package/src/server/lib/rate-limit.ts +0 -2
- package/src/server/middlewares/__tests__/auth-context.test.ts +156 -0
- package/src/server/middlewares/auth-context.ts +62 -0
- package/src/server/remote-auth.ts +58 -31
- package/src/server/serverFns/__tests__/ai-hosted-models.test.ts +47 -15
- package/src/server/serverFns/__tests__/ai-source-mode.test.ts +45 -15
- package/src/server/serverFns/__tests__/billing.test.ts +37 -2
- package/src/server/serverFns/__tests__/collab-snapshot.test.ts +41 -14
- package/src/server/serverFns/__tests__/collab.test.ts +41 -14
- package/src/server/serverFns/__tests__/compliance.test.ts +33 -1
- package/src/server/serverFns/__tests__/email-verification.test.ts +35 -1
- package/src/server/serverFns/__tests__/knowledge-breadcrumb.test.ts +46 -6
- package/src/server/serverFns/__tests__/knowledge-delete.test.ts +42 -14
- package/src/server/serverFns/__tests__/knowledge-kb-projects.test.ts +46 -6
- package/src/server/serverFns/__tests__/knowledge-public-compliance.test.ts +36 -2
- package/src/server/serverFns/__tests__/knowledge-readable-kb.test.ts +42 -10
- package/src/server/serverFns/__tests__/knowledge-search.test.ts +45 -9
- package/src/server/serverFns/__tests__/legal-code-canonical.test.ts +36 -2
- package/src/server/serverFns/__tests__/link-preview.test.ts +38 -4
- package/src/server/serverFns/__tests__/notifications-list.test.ts +36 -3
- package/src/server/serverFns/__tests__/ownership-merge.test.ts +38 -4
- package/src/server/serverFns/__tests__/project-delete-transaction.test.ts +39 -2
- package/src/server/serverFns/__tests__/project-kb.test.ts +34 -1
- package/src/server/serverFns/__tests__/project-member-idor.test.ts +34 -1
- package/src/server/serverFns/__tests__/project-team-assign.test.ts +34 -1
- package/src/server/serverFns/__tests__/read-write-merge.test.ts +38 -4
- package/src/server/serverFns/__tests__/story-comments.test.ts +38 -4
- package/src/server/serverFns/__tests__/story-crud-archive-detail.test.ts +38 -4
- package/src/server/serverFns/__tests__/story-crud-labels-users.test.ts +37 -3
- package/src/server/serverFns/__tests__/story-crud.test.ts +36 -3
- package/src/server/serverFns/__tests__/story-links.test.ts +38 -4
- package/src/server/serverFns/__tests__/story-reactions.test.ts +38 -4
- package/src/server/serverFns/__tests__/story-tree.test.ts +38 -4
- package/src/server/serverFns/__tests__/team-accept.test.ts +34 -1
- package/src/server/serverFns/__tests__/team-invitation.test.ts +34 -1
- package/src/server/serverFns/__tests__/team-join-request.test.ts +34 -1
- package/src/server/serverFns/__tests__/team-members.test.ts +34 -1
- package/src/server/serverFns/__tests__/team-ownership-merge.test.ts +34 -1
- package/src/server/serverFns/__tests__/update-bug-guard.test.ts +37 -3
- package/src/server/serverFns/__tests__/update-document-guard.test.ts +38 -4
- package/src/server/serverFns/__tests__/update-page-guard.test.ts +40 -4
- package/src/server/serverFns/__tests__/update-seats.test.ts +33 -1
- package/src/server/serverFns/__tests__/update-story-guard.test.ts +36 -3
- package/src/server/serverFns/__tests__/update-testcase-guard.test.ts +37 -3
- package/src/server/serverFns/__tests__/workspace-kb-idor.test.ts +36 -2
- package/src/server/serverFns/__tests__/workspace-kb.test.ts +36 -2
- package/src/server/serverFns/__tests__/workspace.test.ts +34 -1
- package/src/server/serverFns/activity.ts +10 -14
- package/src/server/serverFns/agents/agent-crud.ts +16 -15
- package/src/server/serverFns/agents/bindings.ts +12 -13
- package/src/server/serverFns/agents/skill-crud.ts +16 -15
- package/src/server/serverFns/ai/code-mode-readiness.ts +3 -4
- package/src/server/serverFns/ai/search-capability.ts +3 -4
- package/src/server/serverFns/anyhub/app.ts +10 -14
- package/src/server/serverFns/anyhub/index.ts +7 -10
- package/src/server/serverFns/anyhub/install.ts +4 -4
- package/src/server/serverFns/anyhub/permissions.ts +10 -14
- package/src/server/serverFns/anyhub/proxy.ts +4 -6
- package/src/server/serverFns/auth/email-verification.ts +4 -5
- package/src/server/serverFns/auth/session.ts +9 -0
- package/src/server/serverFns/billing.ts +18 -28
- package/src/server/serverFns/blob-upload.ts +6 -9
- package/src/server/serverFns/bug/__tests__/bug-access-tokens.test.ts +34 -1
- package/src/server/serverFns/bug/__tests__/bug-activities.test.ts +34 -1
- package/src/server/serverFns/bug/__tests__/bug-comments.test.ts +34 -1
- package/src/server/serverFns/bug/__tests__/bug-crud.test.ts +34 -1
- package/src/server/serverFns/bug/__tests__/bug-fix.test.ts +34 -1
- package/src/server/serverFns/bug/__tests__/bug-groups.test.ts +34 -1
- package/src/server/serverFns/bug/__tests__/bug-reactions.test.ts +34 -1
- package/src/server/serverFns/bug/__tests__/bug-reorder.test.ts +39 -5
- package/src/server/serverFns/bug/__tests__/bug-repro.test.ts +34 -1
- package/src/server/serverFns/bug/__tests__/bug-story.test.ts +34 -1
- package/src/server/serverFns/bug/__tests__/bug-webhooks.test.ts +34 -1
- package/src/server/serverFns/bug/bug-access-tokens.ts +16 -22
- package/src/server/serverFns/bug/bug-activities.ts +4 -6
- package/src/server/serverFns/bug/bug-collect-tokens.ts +13 -18
- package/src/server/serverFns/bug/bug-comments.ts +13 -18
- package/src/server/serverFns/bug/bug-crud/detail.ts +10 -14
- package/src/server/serverFns/bug/bug-crud.ts +28 -38
- package/src/server/serverFns/bug/bug-display-options.ts +8 -11
- package/src/server/serverFns/bug/bug-export.ts +5 -7
- package/src/server/serverFns/bug/bug-fix.ts +10 -14
- package/src/server/serverFns/bug/bug-groups.ts +10 -14
- package/src/server/serverFns/bug/bug-reactions.ts +10 -14
- package/src/server/serverFns/bug/bug-reorder.ts +4 -6
- package/src/server/serverFns/bug/bug-repro.ts +8 -11
- package/src/server/serverFns/bug/bug-story-bulk.ts +13 -18
- package/src/server/serverFns/bug/bug-story.ts +10 -14
- package/src/server/serverFns/bug/bug-views.ts +12 -18
- package/src/server/serverFns/bug/bug-webhooks.ts +13 -18
- package/src/server/serverFns/bug/test-bug-confirm.ts +7 -10
- package/src/server/serverFns/changelog/__tests__/fetch.test.ts +40 -1
- package/src/server/serverFns/changelog/fetch.ts +4 -6
- package/src/server/serverFns/chat/conversations.ts +17 -28
- package/src/server/serverFns/chat/list-messages.ts +4 -7
- package/src/server/serverFns/collab-presence.ts +11 -13
- package/src/server/serverFns/collab-snapshot.ts +6 -7
- package/src/server/serverFns/collab.ts +7 -7
- package/src/server/serverFns/compliance.ts +8 -8
- package/src/server/serverFns/design/__tests__/comments.test.ts +54 -10
- package/src/server/serverFns/design/__tests__/designs.test.ts +39 -16
- package/src/server/serverFns/design/__tests__/page-versions.test.ts +52 -14
- package/src/server/serverFns/design/__tests__/shares-password.test.ts +44 -14
- package/src/server/serverFns/design/__tests__/shares.test.ts +44 -14
- package/src/server/serverFns/design/__tests__/versions.test.ts +44 -14
- package/src/server/serverFns/design/ai/__tests__/agent-conversations.test.ts +50 -21
- package/src/server/serverFns/design/ai/__tests__/providers.test.ts +42 -8
- package/src/server/serverFns/design/ai/agent-conversations.ts +19 -26
- package/src/server/serverFns/design/ai/fill-annotation.ts +5 -7
- package/src/server/serverFns/design/ai/generate-prototype.ts +5 -7
- package/src/server/serverFns/design/ai/hosted-models.ts +4 -5
- package/src/server/serverFns/design/ai/providers.ts +30 -39
- package/src/server/serverFns/design/ai/source-mode.ts +10 -12
- package/src/server/serverFns/design/comments.ts +14 -13
- package/src/server/serverFns/design/designs.ts +13 -19
- package/src/server/serverFns/design/page-versions.ts +17 -18
- package/src/server/serverFns/design/pages.ts +17 -18
- package/src/server/serverFns/design/reviews.ts +8 -9
- package/src/server/serverFns/design/shares-password.ts +13 -19
- package/src/server/serverFns/design/shares.ts +22 -31
- package/src/server/serverFns/design/versions.ts +8 -9
- package/src/server/serverFns/harness/__tests__/attach-prototype.spec.ts +52 -2
- package/src/server/serverFns/harness/__tests__/attach-to-kb.spec.ts +52 -2
- package/src/server/serverFns/harness/__tests__/attach-to-story-ssrf.spec.ts +52 -2
- package/src/server/serverFns/harness/__tests__/attach-to-story.spec.ts +52 -2
- package/src/server/serverFns/harness/__tests__/cancel-run.test.ts +40 -15
- package/src/server/serverFns/harness/__tests__/extract-attachment.spec.ts +52 -2
- package/src/server/serverFns/harness/__tests__/gallery.spec.ts +76 -12
- package/src/server/serverFns/harness/__tests__/github-workspace.spec.ts +38 -6
- package/src/server/serverFns/harness/__tests__/media-prototype.spec.ts +50 -6
- package/src/server/serverFns/harness/__tests__/media.spec.ts +55 -11
- package/src/server/serverFns/harness/__tests__/sandbox-policy.test.ts +41 -16
- package/src/server/serverFns/harness/__tests__/workspace-files.test.ts +41 -16
- package/src/server/serverFns/harness/attach-prototype.ts +4 -4
- package/src/server/serverFns/harness/attach-to-kb.ts +4 -4
- package/src/server/serverFns/harness/attach-to-story.ts +4 -4
- package/src/server/serverFns/harness/cancel-run.ts +4 -6
- package/src/server/serverFns/harness/extract-attachment.ts +3 -4
- package/src/server/serverFns/harness/gallery.ts +19 -23
- package/src/server/serverFns/harness/github-workspace.ts +14 -21
- package/src/server/serverFns/harness/media.ts +18 -117
- package/src/server/serverFns/harness/sandbox-policy.ts +11 -10
- package/src/server/serverFns/harness/search-mention-candidates.ts +4 -6
- package/src/server/serverFns/harness/workspace-files.ts +19 -26
- package/src/server/serverFns/iteration/__tests__/iteration-auto-schedule.test.ts +35 -3
- package/src/server/serverFns/iteration/__tests__/iteration-crud.test.ts +35 -3
- package/src/server/serverFns/iteration/__tests__/iteration-stories.test.ts +35 -3
- package/src/server/serverFns/iteration/__tests__/iteration-transfer.test.ts +35 -3
- package/src/server/serverFns/iteration/iteration-auto-schedule.ts +7 -10
- package/src/server/serverFns/iteration/iteration-burndown.ts +4 -6
- package/src/server/serverFns/iteration/iteration-crud.ts +26 -35
- package/src/server/serverFns/iteration/iteration-stories.ts +10 -14
- package/src/server/serverFns/iteration/iteration-transfer.ts +4 -6
- package/src/server/serverFns/knowledge/public/bookmarks/categories.ts +11 -15
- package/src/server/serverFns/knowledge/public/bookmarks/create.ts +4 -6
- package/src/server/serverFns/knowledge/public/bookmarks/delete.ts +5 -7
- package/src/server/serverFns/knowledge/public/bookmarks/detail.ts +4 -6
- package/src/server/serverFns/knowledge/public/bookmarks/favorite.ts +4 -6
- package/src/server/serverFns/knowledge/public/bookmarks/list.ts +4 -6
- package/src/server/serverFns/knowledge/public/bookmarks/refresh-favicon.ts +4 -6
- package/src/server/serverFns/knowledge/public/bookmarks/share.ts +4 -6
- package/src/server/serverFns/knowledge/public/bookmarks/sync-github.ts +5 -7
- package/src/server/serverFns/knowledge/public/bookmarks/unshare.ts +4 -6
- package/src/server/serverFns/knowledge/public/bookmarks/update.ts +6 -8
- package/src/server/serverFns/knowledge/public/compliance/create.ts +4 -6
- package/src/server/serverFns/knowledge/public/compliance/delete.ts +5 -7
- package/src/server/serverFns/knowledge/public/compliance/detail.ts +4 -6
- package/src/server/serverFns/knowledge/public/compliance/list.ts +4 -6
- package/src/server/serverFns/knowledge/public/compliance/share.ts +4 -6
- package/src/server/serverFns/knowledge/public/compliance/unshare.ts +4 -6
- package/src/server/serverFns/knowledge/public/compliance/update.ts +5 -7
- package/src/server/serverFns/knowledge/public/dictionary/create.ts +4 -6
- package/src/server/serverFns/knowledge/public/dictionary/delete.ts +5 -7
- package/src/server/serverFns/knowledge/public/dictionary/detail.ts +4 -6
- package/src/server/serverFns/knowledge/public/dictionary/list.ts +4 -6
- package/src/server/serverFns/knowledge/public/dictionary/share.ts +4 -6
- package/src/server/serverFns/knowledge/public/dictionary/unshare.ts +4 -6
- package/src/server/serverFns/knowledge/public/dictionary/update.ts +5 -7
- package/src/server/serverFns/knowledge/public/entity-tags.ts +4 -6
- package/src/server/serverFns/knowledge/public/favorite.ts +7 -10
- package/src/server/serverFns/knowledge/public/legal/create.ts +4 -6
- package/src/server/serverFns/knowledge/public/legal/delete.ts +5 -7
- package/src/server/serverFns/knowledge/public/legal/detail.ts +4 -6
- package/src/server/serverFns/knowledge/public/legal/list.ts +4 -6
- package/src/server/serverFns/knowledge/public/legal/share.ts +4 -6
- package/src/server/serverFns/knowledge/public/legal/unshare.ts +4 -6
- package/src/server/serverFns/knowledge/public/legal/update.ts +5 -7
- package/src/server/serverFns/knowledge-index.ts +12 -16
- package/src/server/serverFns/knowledge.ts +50 -67
- package/src/server/serverFns/notifications.ts +25 -34
- package/src/server/serverFns/plugins/harness-plugins.ts +16 -23
- package/src/server/serverFns/project/module-overview.ts +7 -10
- package/src/server/serverFns/project.ts +48 -68
- package/src/server/serverFns/references/create.ts +4 -6
- package/src/server/serverFns/references/resolve.ts +4 -6
- package/src/server/serverFns/references/search.ts +4 -6
- package/src/server/serverFns/share/design/[designId]/events.ts +4 -6
- package/src/server/serverFns/sso.ts +1 -1
- package/src/server/serverFns/story/__tests__/bulk.test.ts +34 -1
- package/src/server/serverFns/story/__tests__/story-assoc.test.ts +34 -1
- package/src/server/serverFns/story/__tests__/story-attachments.test.ts +34 -1
- package/src/server/serverFns/story/__tests__/story-crud-date-key.test.ts +42 -17
- package/src/server/serverFns/story/__tests__/story-dependencies.test.ts +34 -1
- package/src/server/serverFns/story/__tests__/story-gantt-deps.test.ts +34 -1
- package/src/server/serverFns/story/__tests__/story-groups.test.ts +34 -1
- package/src/server/serverFns/story/__tests__/story-read-path-authz.test.ts +40 -4
- package/src/server/serverFns/story/__tests__/story-search.test.ts +34 -1
- package/src/server/serverFns/story/__tests__/story-transfer.test.ts +34 -1
- package/src/server/serverFns/story/link-preview.ts +5 -7
- package/src/server/serverFns/story/story-assoc.ts +28 -38
- package/src/server/serverFns/story/story-attachments.ts +7 -10
- package/src/server/serverFns/story/story-children.ts +4 -6
- package/src/server/serverFns/story/story-comments.ts +13 -18
- package/src/server/serverFns/story/story-crud/activities.ts +4 -6
- package/src/server/serverFns/story/story-crud/archive.ts +7 -10
- package/src/server/serverFns/story/story-crud/bulk.ts +10 -14
- package/src/server/serverFns/story/story-crud/detail.ts +7 -10
- package/src/server/serverFns/story/story-crud/label-suggest.ts +4 -6
- package/src/server/serverFns/story/story-crud/labels.ts +6 -9
- package/src/server/serverFns/story/story-crud/user-brief.ts +4 -6
- package/src/server/serverFns/story/story-crud.ts +13 -18
- package/src/server/serverFns/story/story-dependencies.ts +16 -22
- package/src/server/serverFns/story/story-groups.ts +10 -14
- package/src/server/serverFns/story/story-links.ts +13 -18
- package/src/server/serverFns/story/story-reactions.ts +13 -18
- package/src/server/serverFns/story/story-search.ts +7 -10
- package/src/server/serverFns/story/story-transfer.ts +10 -14
- package/src/server/serverFns/story/story-tree.ts +7 -10
- package/src/server/serverFns/story-display-options.ts +7 -8
- package/src/server/serverFns/story-view.ts +12 -18
- package/src/server/serverFns/tasks/task-crud.ts +13 -17
- package/src/server/serverFns/tasks/task-queries.ts +12 -18
- package/src/server/serverFns/team.ts +46 -66
- package/src/server/serverFns/testcase/__tests__/automation.test.ts +38 -5
- package/src/server/serverFns/testcase/__tests__/evidence-upload.test.ts +37 -3
- package/src/server/serverFns/testcase/__tests__/generation.test.ts +38 -5
- package/src/server/serverFns/testcase/__tests__/plans.test.ts +36 -3
- package/src/server/serverFns/testcase/__tests__/regression.test.ts +36 -3
- package/src/server/serverFns/testcase/__tests__/run-cases.test.ts +36 -3
- package/src/server/serverFns/testcase/__tests__/runs.test.ts +36 -3
- package/src/server/serverFns/testcase/__tests__/stats.test.ts +36 -3
- package/src/server/serverFns/testcase/__tests__/testcase-board.test.ts +39 -5
- package/src/server/serverFns/testcase/__tests__/testcase-crud.test.ts +36 -3
- package/src/server/serverFns/testcase/__tests__/testcase-folders.test.ts +36 -3
- package/src/server/serverFns/testcase/__tests__/testcase-groups.test.ts +38 -5
- package/src/server/serverFns/testcase/automation.ts +13 -17
- package/src/server/serverFns/testcase/bulk.ts +10 -14
- package/src/server/serverFns/testcase/evidence-upload.ts +5 -7
- package/src/server/serverFns/testcase/generation.ts +10 -13
- package/src/server/serverFns/testcase/plans.ts +23 -31
- package/src/server/serverFns/testcase/regression.ts +7 -10
- package/src/server/serverFns/testcase/run-cases.ts +13 -18
- package/src/server/serverFns/testcase/runs.ts +13 -18
- package/src/server/serverFns/testcase/stats.ts +13 -18
- package/src/server/serverFns/testcase/testcase-activities.ts +4 -6
- package/src/server/serverFns/testcase/testcase-board.ts +4 -6
- package/src/server/serverFns/testcase/testcase-crud.ts +20 -27
- package/src/server/serverFns/testcase/testcase-display-options.ts +8 -11
- package/src/server/serverFns/testcase/testcase-export.ts +5 -7
- package/src/server/serverFns/testcase/testcase-filter-views.ts +12 -18
- package/src/server/serverFns/testcase/testcase-folders.ts +16 -22
- package/src/server/serverFns/testcase/testcase-groups.ts +4 -6
- package/src/server/serverFns/testcase/testcase-reorder.ts +4 -6
- package/src/server/serverFns/translation.ts +4 -6
- package/src/server/serverFns/user/avatar.ts +4 -6
- package/src/server/serverFns/user/settings.ts +4 -6
- package/src/server/serverFns/user/update-locale.ts +4 -6
- package/src/server/serverFns/workspace-kb.ts +26 -35
- package/src/server/serverFns/workspace.ts +43 -59
- package/src/server/serverFns/ws.ts +4 -6
- package/src/server/serverfn-public-allowlist.ts +117 -0
- package/src/server/story/types.ts +0 -1
- package/src/server/sync/__tests__/scopes.test.ts +64 -0
- package/src/server/sync/scopes.ts +7 -0
- package/src/server/testcase/__tests__/auto-bug.test.ts +44 -12
- package/src/__tests__/bench/baselines/format-timestamp.json +0 -44
- package/src/__typeprobe__.d.ts +0 -4
- package/src/components/forms/app-form-dialog.tsx +0 -126
- package/src/components/forms/hooks/use-form-submit.ts +0 -57
- package/src/components/forms/types.ts +0 -34
- package/src/components/harness/code/workspace-picker.tsx +0 -239
- package/src/components/tiptap/extensions/local-file/insert-local-file.ts +0 -35
- package/src/components/tiptap/extensions/local-file/local-file-node.ts +0 -71
- package/src/devframe-docks/ai-chat-iframe.tsx +0 -29
- package/src/devframe-docks/session-iframe.tsx +0 -90
- package/src/lib/__tests__/desktop-detect.test.ts +0 -19
- package/src/lib/collections/index.ts +0 -22
- package/src/lib/collections/knowledge/index.ts +0 -18
- package/src/lib/collections/knowledge/knowledge-bases-collection.ts +0 -34
- package/src/lib/collections/reference/bookmark-categories-collection.ts +0 -31
- package/src/lib/collections/reference/labels-collection.ts +0 -31
- package/src/lib/collections/reference/projects-collection.ts +0 -31
- package/src/lib/collections/reference/users-brief-collection.ts +0 -35
- package/src/lib/collections/reference/workspaces-collection.ts +0 -34
- package/src/lib/desktop-detect.ts +0 -29
- package/src/paraglide/messages/en.js +0 -28260
- package/src/paraglide/messages/zh.js +0 -28258
|
@@ -18,9 +18,17 @@
|
|
|
18
18
|
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
19
19
|
|
|
20
20
|
vi.mock("@tanstack/react-start", () => ({
|
|
21
|
+
// 迁移后经 .middleware([authContextMiddleware]) 注入 context.user:
|
|
22
|
+
// mock 依序执行 middleware 的 server 段(复现框架 executeMiddleware 的
|
|
23
|
+
// context 合并语义),真实鉴权链由被 mock 的 auth-helpers/getRequest 承接
|
|
21
24
|
createServerFn: (config: any) => {
|
|
22
25
|
const api: any = {
|
|
23
26
|
_validator: undefined,
|
|
27
|
+
_middlewares: [] as any[],
|
|
28
|
+
middleware(mws: any[]) {
|
|
29
|
+
api._middlewares.push(...mws);
|
|
30
|
+
return api;
|
|
31
|
+
},
|
|
24
32
|
validator(schema: any) {
|
|
25
33
|
this._validator = schema;
|
|
26
34
|
return this;
|
|
@@ -28,16 +36,40 @@ vi.mock("@tanstack/react-start", () => ({
|
|
|
28
36
|
handler(fn: Function) {
|
|
29
37
|
const wrapped = async (args: any) => {
|
|
30
38
|
let data = args?.data;
|
|
31
|
-
if (
|
|
32
|
-
data =
|
|
39
|
+
if (api._validator && data !== undefined) {
|
|
40
|
+
data = api._validator.parse ? api._validator.parse(data) : data;
|
|
41
|
+
}
|
|
42
|
+
let context: any = {};
|
|
43
|
+
for (const mw of api._middlewares) {
|
|
44
|
+
const serverFn = mw?.options?.server;
|
|
45
|
+
if (!serverFn) continue;
|
|
46
|
+
const result = await serverFn({
|
|
47
|
+
data,
|
|
48
|
+
context,
|
|
49
|
+
method: "POST",
|
|
50
|
+
serverFnMeta: {},
|
|
51
|
+
signal: new AbortController().signal,
|
|
52
|
+
next: async (inner: any) => ({ context: { ...context, ...(inner?.context ?? {}) } }),
|
|
53
|
+
});
|
|
54
|
+
context = result.context;
|
|
33
55
|
}
|
|
34
|
-
return fn({ data });
|
|
56
|
+
return fn({ data, context });
|
|
35
57
|
};
|
|
36
58
|
return wrapped;
|
|
37
59
|
},
|
|
38
60
|
};
|
|
39
61
|
return api;
|
|
40
62
|
},
|
|
63
|
+
// auth-context.ts 依赖 createMiddleware({ type: "function" }).server(fn):
|
|
64
|
+
// mock 产出与真实 middleware 同构的 { options: { server } } 形状
|
|
65
|
+
createMiddleware: (opts: any) => {
|
|
66
|
+
const mw: any = { options: { type: opts?.type } };
|
|
67
|
+
mw.server = (fn: Function) => {
|
|
68
|
+
mw.options.server = fn;
|
|
69
|
+
return mw;
|
|
70
|
+
};
|
|
71
|
+
return mw;
|
|
72
|
+
},
|
|
41
73
|
}));
|
|
42
74
|
|
|
43
75
|
vi.mock("@tanstack/react-start/server", () => ({
|
|
@@ -18,9 +18,17 @@
|
|
|
18
18
|
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
19
19
|
|
|
20
20
|
vi.mock("@tanstack/react-start", () => ({
|
|
21
|
+
// 迁移后经 .middleware([authContextMiddleware]) 注入 context.user:
|
|
22
|
+
// mock 依序执行 middleware 的 server 段(复现框架 executeMiddleware 的
|
|
23
|
+
// context 合并语义),真实鉴权链由被 mock 的 auth-helpers/getRequest 承接
|
|
21
24
|
createServerFn: (config: any) => {
|
|
22
25
|
const api: any = {
|
|
23
26
|
_validator: undefined,
|
|
27
|
+
_middlewares: [] as any[],
|
|
28
|
+
middleware(mws: any[]) {
|
|
29
|
+
api._middlewares.push(...mws);
|
|
30
|
+
return api;
|
|
31
|
+
},
|
|
24
32
|
validator(schema: any) {
|
|
25
33
|
this._validator = schema;
|
|
26
34
|
return this;
|
|
@@ -28,16 +36,40 @@ vi.mock("@tanstack/react-start", () => ({
|
|
|
28
36
|
handler(fn: Function) {
|
|
29
37
|
const wrapped = async (args: any) => {
|
|
30
38
|
let data = args?.data;
|
|
31
|
-
if (
|
|
32
|
-
data =
|
|
39
|
+
if (api._validator && data !== undefined) {
|
|
40
|
+
data = api._validator.parse ? api._validator.parse(data) : data;
|
|
41
|
+
}
|
|
42
|
+
let context: any = {};
|
|
43
|
+
for (const mw of api._middlewares) {
|
|
44
|
+
const serverFn = mw?.options?.server;
|
|
45
|
+
if (!serverFn) continue;
|
|
46
|
+
const result = await serverFn({
|
|
47
|
+
data,
|
|
48
|
+
context,
|
|
49
|
+
method: "POST",
|
|
50
|
+
serverFnMeta: {},
|
|
51
|
+
signal: new AbortController().signal,
|
|
52
|
+
next: async (inner: any) => ({ context: { ...context, ...(inner?.context ?? {}) } }),
|
|
53
|
+
});
|
|
54
|
+
context = result.context;
|
|
33
55
|
}
|
|
34
|
-
return fn({ data });
|
|
56
|
+
return fn({ data, context });
|
|
35
57
|
};
|
|
36
58
|
return wrapped;
|
|
37
59
|
},
|
|
38
60
|
};
|
|
39
61
|
return api;
|
|
40
62
|
},
|
|
63
|
+
// auth-context.ts 依赖 createMiddleware({ type: "function" }).server(fn):
|
|
64
|
+
// mock 产出与真实 middleware 同构的 { options: { server } } 形状
|
|
65
|
+
createMiddleware: (opts: any) => {
|
|
66
|
+
const mw: any = { options: { type: opts?.type } };
|
|
67
|
+
mw.server = (fn: Function) => {
|
|
68
|
+
mw.options.server = fn;
|
|
69
|
+
return mw;
|
|
70
|
+
};
|
|
71
|
+
return mw;
|
|
72
|
+
},
|
|
41
73
|
}));
|
|
42
74
|
|
|
43
75
|
vi.mock("@tanstack/react-start/server", () => ({
|
|
@@ -17,9 +17,8 @@
|
|
|
17
17
|
|
|
18
18
|
import { getPrisma } from "@allbluecn/database/get-prisma"
|
|
19
19
|
import { createServerFn } from "@tanstack/react-start";
|
|
20
|
-
import {
|
|
20
|
+
import { authContextMiddleware } from "@/server/middlewares/auth-context"
|
|
21
21
|
import { z } from "zod";
|
|
22
|
-
import { requireAuth } from "@/server/auth-helpers";
|
|
23
22
|
import { toDatePart } from "@/lib/iteration/status";
|
|
24
23
|
import { ensureUpcomingIterations } from "@/server/iteration/auto-schedule-internal";
|
|
25
24
|
import { assertIterationProjectMembership as assertProjectMembership } from "@/server/iteration/permissions";
|
|
@@ -31,12 +30,11 @@ const CONFIG_SELECT = {
|
|
|
31
30
|
|
|
32
31
|
|
|
33
32
|
export const getAutoScheduleFn = createServerFn({ method: "GET" })
|
|
33
|
+
.middleware([authContextMiddleware])
|
|
34
34
|
.validator(z.object({ projectId: z.string() }))
|
|
35
|
-
.handler(async ({ data }) => {
|
|
35
|
+
.handler(async ({ data, context }) => {
|
|
36
36
|
const prisma = await getPrisma()
|
|
37
|
-
|
|
38
|
-
const session = await requireAuth(request);
|
|
39
|
-
await assertProjectMembership(data.projectId, session.user.id);
|
|
37
|
+
await assertProjectMembership(data.projectId, context.user.id);
|
|
40
38
|
const [cfg] = await prisma.iterationAutoSchedule.findMany({
|
|
41
39
|
where: { projectId: data.projectId }, select: CONFIG_SELECT, take: 1,
|
|
42
40
|
});
|
|
@@ -44,6 +42,7 @@ export const getAutoScheduleFn = createServerFn({ method: "GET" })
|
|
|
44
42
|
});
|
|
45
43
|
|
|
46
44
|
export const updateAutoScheduleFn = createServerFn({ method: "POST" })
|
|
45
|
+
.middleware([authContextMiddleware])
|
|
47
46
|
.validator(
|
|
48
47
|
z.object({
|
|
49
48
|
projectId: z.string(),
|
|
@@ -56,12 +55,10 @@ export const updateAutoScheduleFn = createServerFn({ method: "POST" })
|
|
|
56
55
|
autoRollover: z.boolean(),
|
|
57
56
|
}),
|
|
58
57
|
)
|
|
59
|
-
.handler(async ({ data }) => {
|
|
58
|
+
.handler(async ({ data, context }) => {
|
|
60
59
|
const prisma = await getPrisma()
|
|
61
|
-
const request = getRequest();
|
|
62
|
-
const session = await requireAuth(request);
|
|
63
60
|
// 配置写入会连锁触发排期补建,须为项目有效成员(SEC-03)
|
|
64
|
-
await assertProjectMembership(data.projectId,
|
|
61
|
+
await assertProjectMembership(data.projectId, context.user.id);
|
|
65
62
|
await prisma.iterationAutoSchedule.upsert({
|
|
66
63
|
where: { projectId: data.projectId },
|
|
67
64
|
create: { ...data, startsOn: new Date(data.startsOn + "T00:00:00.000Z") },
|
|
@@ -17,9 +17,8 @@
|
|
|
17
17
|
|
|
18
18
|
import { getPrisma } from "@allbluecn/database/get-prisma"
|
|
19
19
|
import { createServerFn } from "@tanstack/react-start";
|
|
20
|
-
import {
|
|
20
|
+
import { authContextMiddleware } from "@/server/middlewares/auth-context"
|
|
21
21
|
import { z } from "zod";
|
|
22
|
-
import { requireAuth } from "@/server/auth-helpers";
|
|
23
22
|
import { assertIterationProjectMember } from "@/server/iteration/permissions";
|
|
24
23
|
import { toDatePart } from "@/lib/iteration/status";
|
|
25
24
|
import { computeBurndown } from "@/lib/iteration/burndown";
|
|
@@ -29,12 +28,11 @@ const ACTIVITY_STORY_SELECT = {
|
|
|
29
28
|
} as const;
|
|
30
29
|
|
|
31
30
|
export const getIterationBurndownFn = createServerFn({ method: "GET" })
|
|
31
|
+
.middleware([authContextMiddleware])
|
|
32
32
|
.validator(z.object({ iterationId: z.string() }))
|
|
33
|
-
.handler(async ({ data }) => {
|
|
33
|
+
.handler(async ({ data, context }) => {
|
|
34
34
|
const prisma = await getPrisma()
|
|
35
|
-
|
|
36
|
-
const session = await requireAuth(request);
|
|
37
|
-
await assertIterationProjectMember(data.iterationId, session.user.id);
|
|
35
|
+
await assertIterationProjectMember(data.iterationId, context.user.id);
|
|
38
36
|
const iteration = await prisma.iteration.findUnique({
|
|
39
37
|
where: { id: data.iterationId },
|
|
40
38
|
select: { startDate: true, endDate: true, project: { select: { timezone: true } } },
|
|
@@ -18,8 +18,7 @@
|
|
|
18
18
|
import { getPrisma } from "@allbluecn/database/get-prisma"
|
|
19
19
|
import { z } from "zod";
|
|
20
20
|
import { createServerFn } from "@tanstack/react-start";
|
|
21
|
-
import {
|
|
22
|
-
import { requireAuth } from "@/server/auth-helpers";
|
|
21
|
+
import { authContextMiddleware } from "@/server/middlewares/auth-context"
|
|
23
22
|
import { deriveIterationStatus, isDateRangeOverlapping, toDatePart } from "@/lib/iteration/status";
|
|
24
23
|
import {
|
|
25
24
|
listIterationsSchema,
|
|
@@ -77,14 +76,13 @@ function toSummary(
|
|
|
77
76
|
}
|
|
78
77
|
|
|
79
78
|
export const listIterationsFn = createServerFn({ method: "GET" })
|
|
79
|
+
.middleware([authContextMiddleware])
|
|
80
80
|
.validator(listIterationsSchema)
|
|
81
|
-
.handler(async ({ data }) => {
|
|
81
|
+
.handler(async ({ data, context }) => {
|
|
82
82
|
const prisma = await getPrisma()
|
|
83
|
-
const request = getRequest();
|
|
84
|
-
const session = await requireAuth(request);
|
|
85
83
|
// 读门槛与列表 scope 同口径(SEC-03):非成员静默回退独立项目,
|
|
86
84
|
// 同时避免借读路径触发他人项目的迭代自愈排期
|
|
87
|
-
const scopeProjectId = await resolveStoryScopeProjectId(data.projectId,
|
|
85
|
+
const scopeProjectId = await resolveStoryScopeProjectId(data.projectId, context.user.id);
|
|
88
86
|
// 惰性自愈:自动排期补建 + autoRollover(规格 §3.6)
|
|
89
87
|
await ensureUpcomingIterations(scopeProjectId);
|
|
90
88
|
await ensureAutoRollover(scopeProjectId);
|
|
@@ -118,12 +116,11 @@ export const listIterationsFn = createServerFn({ method: "GET" })
|
|
|
118
116
|
* listIterationsFn 的读时惰性自愈,避免只读视图触发建行。
|
|
119
117
|
*/
|
|
120
118
|
export const listIterationsScopeFn = createServerFn({ method: "GET" })
|
|
119
|
+
.middleware([authContextMiddleware])
|
|
121
120
|
.validator(z.object({ projectId: z.string().optional() }))
|
|
122
|
-
.handler(async ({ data }) => {
|
|
121
|
+
.handler(async ({ data, context }) => {
|
|
123
122
|
const prisma = await getPrisma()
|
|
124
|
-
const
|
|
125
|
-
const session = await requireAuth(request);
|
|
126
|
-
const projectIds = await resolveStoryScopeProjectIds(data.projectId, session.user.id);
|
|
123
|
+
const projectIds = await resolveStoryScopeProjectIds(data.projectId, context.user.id);
|
|
127
124
|
const items = await prisma.iteration.findMany({
|
|
128
125
|
where: { projectId: { in: projectIds }, archived: false },
|
|
129
126
|
select: { id: true, name: true, startDate: true, endDate: true },
|
|
@@ -133,13 +130,12 @@ export const listIterationsScopeFn = createServerFn({ method: "GET" })
|
|
|
133
130
|
});
|
|
134
131
|
|
|
135
132
|
export const getIterationFn = createServerFn({ method: "GET" })
|
|
133
|
+
.middleware([authContextMiddleware])
|
|
136
134
|
.validator(iterationIdSchema)
|
|
137
|
-
.handler(async ({ data }) => {
|
|
135
|
+
.handler(async ({ data, context }) => {
|
|
138
136
|
const prisma = await getPrisma()
|
|
139
|
-
const request = getRequest();
|
|
140
|
-
const session = await requireAuth(request);
|
|
141
137
|
// 读侧与写侧同口径:须为迭代所属项目的有效成员(审计 2026-10-25 读路径缺口)
|
|
142
|
-
await assertIterationProjectMember(data.id,
|
|
138
|
+
await assertIterationProjectMember(data.id, context.user.id);
|
|
143
139
|
const it = await prisma.iteration.findUnique({ where: { id: data.id }, select: ITERATION_SELECT });
|
|
144
140
|
if (!it) throw new Error("迭代不存在");
|
|
145
141
|
const grouped = await prisma.story.groupBy({
|
|
@@ -152,13 +148,12 @@ export const getIterationFn = createServerFn({ method: "GET" })
|
|
|
152
148
|
});
|
|
153
149
|
|
|
154
150
|
export const createIterationsFn = createServerFn({ method: "POST" })
|
|
151
|
+
.middleware([authContextMiddleware])
|
|
155
152
|
.validator(createIterationSchema)
|
|
156
|
-
.handler(async ({ data }) => {
|
|
153
|
+
.handler(async ({ data, context }) => {
|
|
157
154
|
const prisma = await getPrisma()
|
|
158
|
-
const request = getRequest();
|
|
159
|
-
const session = await requireAuth(request);
|
|
160
155
|
// 与 testcase createTestCaseFn 同范式:建入前校验目标项目成员资格(SEC-03 残口收口)
|
|
161
|
-
await assertProjectMembership(data.projectId,
|
|
156
|
+
await assertProjectMembership(data.projectId, context.user.id);
|
|
162
157
|
await assertNoOverlap(data.projectId, data);
|
|
163
158
|
const created = await prisma.iteration.create({
|
|
164
159
|
data: {
|
|
@@ -167,7 +162,7 @@ export const createIterationsFn = createServerFn({ method: "POST" })
|
|
|
167
162
|
description: data.description,
|
|
168
163
|
startDate: new Date(data.startDate + "T00:00:00.000Z"),
|
|
169
164
|
endDate: new Date(data.endDate + "T00:00:00.000Z"),
|
|
170
|
-
createdById:
|
|
165
|
+
createdById: context.user.id,
|
|
171
166
|
},
|
|
172
167
|
select: { id: true },
|
|
173
168
|
});
|
|
@@ -175,12 +170,11 @@ export const createIterationsFn = createServerFn({ method: "POST" })
|
|
|
175
170
|
});
|
|
176
171
|
|
|
177
172
|
export const updateIterationsFn = createServerFn({ method: "POST" })
|
|
173
|
+
.middleware([authContextMiddleware])
|
|
178
174
|
.validator(updateIterationSchema)
|
|
179
|
-
.handler(async ({ data }) => {
|
|
175
|
+
.handler(async ({ data, context }) => {
|
|
180
176
|
const prisma = await getPrisma()
|
|
181
|
-
const
|
|
182
|
-
const session = await requireAuth(request);
|
|
183
|
-
const userId = session.user.id;
|
|
177
|
+
const userId = context.user.id;
|
|
184
178
|
const existing = await prisma.iteration.findUnique({ where: { id: data.id }, select: ITERATION_SELECT });
|
|
185
179
|
if (!existing) throw new Error("迭代不存在");
|
|
186
180
|
await assertProjectMembership(existing.projectId, userId);
|
|
@@ -207,18 +201,17 @@ export const updateIterationsFn = createServerFn({ method: "POST" })
|
|
|
207
201
|
});
|
|
208
202
|
|
|
209
203
|
export const archiveIterationsFn = createServerFn({ method: "POST" })
|
|
204
|
+
.middleware([authContextMiddleware])
|
|
210
205
|
.validator(z.object({ id: z.string(), archived: z.boolean() }))
|
|
211
|
-
.handler(async ({ data }) => {
|
|
206
|
+
.handler(async ({ data, context }) => {
|
|
212
207
|
const prisma = await getPrisma()
|
|
213
|
-
const request = getRequest();
|
|
214
|
-
const session = await requireAuth(request);
|
|
215
208
|
// 先取回目标行校验成员资格,再改(SEC-03:防跨项目归档他人迭代)
|
|
216
209
|
const existing = await prisma.iteration.findUnique({
|
|
217
210
|
where: { id: data.id },
|
|
218
211
|
select: { id: true, projectId: true },
|
|
219
212
|
});
|
|
220
213
|
if (!existing) throw new Error("迭代不存在");
|
|
221
|
-
await assertProjectMembership(existing.projectId,
|
|
214
|
+
await assertProjectMembership(existing.projectId, context.user.id);
|
|
222
215
|
await prisma.iteration.update({
|
|
223
216
|
where: { id: data.id },
|
|
224
217
|
data: { archived: data.archived, archivedAt: data.archived ? new Date() : null },
|
|
@@ -227,18 +220,17 @@ export const archiveIterationsFn = createServerFn({ method: "POST" })
|
|
|
227
220
|
});
|
|
228
221
|
|
|
229
222
|
export const deleteIterationsFn = createServerFn({ method: "POST" })
|
|
223
|
+
.middleware([authContextMiddleware])
|
|
230
224
|
.validator(iterationIdSchema)
|
|
231
|
-
.handler(async ({ data }) => {
|
|
225
|
+
.handler(async ({ data, context }) => {
|
|
232
226
|
const prisma = await getPrisma()
|
|
233
|
-
const request = getRequest();
|
|
234
|
-
const session = await requireAuth(request);
|
|
235
227
|
// 先取回目标行校验成员资格,再删(SEC-03:防跨项目删除他人迭代)
|
|
236
228
|
const existing = await prisma.iteration.findUnique({
|
|
237
229
|
where: { id: data.id },
|
|
238
230
|
select: { id: true, projectId: true },
|
|
239
231
|
});
|
|
240
232
|
if (!existing) throw new Error("迭代不存在");
|
|
241
|
-
await assertProjectMembership(existing.projectId,
|
|
233
|
+
await assertProjectMembership(existing.projectId, context.user.id);
|
|
242
234
|
await prisma.iteration.delete({ where: { id: data.id } }); // Story.iterationId SetNull 自动解绑
|
|
243
235
|
return { ok: true };
|
|
244
236
|
});
|
|
@@ -246,12 +238,11 @@ export const deleteIterationsFn = createServerFn({ method: "POST" })
|
|
|
246
238
|
const listIterationStoriesSchema = z.object({ iterationId: z.string() });
|
|
247
239
|
|
|
248
240
|
export const listIterationStoriesFn = createServerFn({ method: "GET" })
|
|
241
|
+
.middleware([authContextMiddleware])
|
|
249
242
|
.validator(listIterationStoriesSchema)
|
|
250
|
-
.handler(async ({ data }) => {
|
|
243
|
+
.handler(async ({ data, context }) => {
|
|
251
244
|
const prisma = await getPrisma()
|
|
252
|
-
|
|
253
|
-
const session = await requireAuth(request);
|
|
254
|
-
await assertIterationProjectMember(data.iterationId, session.user.id);
|
|
245
|
+
await assertIterationProjectMember(data.iterationId, context.user.id);
|
|
255
246
|
const stories = await prisma.story.findMany({
|
|
256
247
|
where: { iterationId: data.iterationId, archived: false },
|
|
257
248
|
orderBy: [{ state: "asc" }, { updatedAt: "desc" }],
|
|
@@ -17,9 +17,8 @@
|
|
|
17
17
|
|
|
18
18
|
import { getPrisma } from "@allbluecn/database/get-prisma"
|
|
19
19
|
import { createServerFn } from "@tanstack/react-start";
|
|
20
|
-
import {
|
|
20
|
+
import { authContextMiddleware } from "@/server/middlewares/auth-context"
|
|
21
21
|
import { z } from "zod";
|
|
22
|
-
import { requireAuth } from "@/server/auth-helpers";
|
|
23
22
|
import { deriveIterationStatus, toDatePart } from "@/lib/iteration/status";
|
|
24
23
|
import { assertIterationProjectMembership as assertProjectMembership } from "@/server/iteration/permissions";
|
|
25
24
|
|
|
@@ -40,12 +39,11 @@ async function assertTargetJoinable(iterationId: string, userId: string) {
|
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
export const setStoryIterationFn = createServerFn({ method: "POST" })
|
|
42
|
+
.middleware([authContextMiddleware])
|
|
43
43
|
.validator(z.object({ storyId: z.string(), iterationId: z.string().nullable() }))
|
|
44
|
-
.handler(async ({ data }) => {
|
|
44
|
+
.handler(async ({ data, context }) => {
|
|
45
45
|
const prisma = await getPrisma()
|
|
46
|
-
const
|
|
47
|
-
const session = await requireAuth(request);
|
|
48
|
-
const userId = session.user.id;
|
|
46
|
+
const userId = context.user.id;
|
|
49
47
|
const story = await prisma.story.findUnique({
|
|
50
48
|
where: { id: data.storyId },
|
|
51
49
|
select: { projectId: true, iterationId: true, iteration: { select: { name: true } } },
|
|
@@ -73,12 +71,11 @@ export const setStoryIterationFn = createServerFn({ method: "POST" })
|
|
|
73
71
|
});
|
|
74
72
|
|
|
75
73
|
export const addStoriesToIterationFn = createServerFn({ method: "POST" })
|
|
74
|
+
.middleware([authContextMiddleware])
|
|
76
75
|
.validator(z.object({ iterationId: z.string(), storyIds: z.array(z.string()).min(1).max(200) }))
|
|
77
|
-
.handler(async ({ data }) => {
|
|
76
|
+
.handler(async ({ data, context }) => {
|
|
78
77
|
const prisma = await getPrisma()
|
|
79
|
-
const
|
|
80
|
-
const session = await requireAuth(request);
|
|
81
|
-
const userId = session.user.id;
|
|
78
|
+
const userId = context.user.id;
|
|
82
79
|
const newName = await assertTargetJoinable(data.iterationId, userId);
|
|
83
80
|
// 批量圈定后按项目去重校验成员资格(SEC-03:任一跨项目 id 整批拒绝,不做部分写入)
|
|
84
81
|
const stories = await prisma.story.findMany({
|
|
@@ -114,12 +111,11 @@ export const addStoriesToIterationFn = createServerFn({ method: "POST" })
|
|
|
114
111
|
});
|
|
115
112
|
|
|
116
113
|
export const removeStoryFromIterationFn = createServerFn({ method: "POST" })
|
|
114
|
+
.middleware([authContextMiddleware])
|
|
117
115
|
.validator(z.object({ storyId: z.string() }))
|
|
118
|
-
.handler(async ({ data }) => {
|
|
116
|
+
.handler(async ({ data, context }) => {
|
|
119
117
|
const prisma = await getPrisma()
|
|
120
|
-
const
|
|
121
|
-
const session = await requireAuth(request);
|
|
122
|
-
const userId = session.user.id;
|
|
118
|
+
const userId = context.user.id;
|
|
123
119
|
const story = await prisma.story.findUnique({
|
|
124
120
|
where: { id: data.storyId },
|
|
125
121
|
select: { projectId: true, iterationId: true, iteration: { select: { name: true } } },
|
|
@@ -16,9 +16,8 @@
|
|
|
16
16
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
17
|
|
|
18
18
|
import { createServerFn } from "@tanstack/react-start";
|
|
19
|
-
import {
|
|
19
|
+
import { authContextMiddleware } from "@/server/middlewares/auth-context"
|
|
20
20
|
import { z } from "zod";
|
|
21
|
-
import { requireAuth } from "@/server/auth-helpers";
|
|
22
21
|
import { transferStoriesInternal } from "@/server/iteration/transfer-internal";
|
|
23
22
|
|
|
24
23
|
// 模块私有:serverFn 文件只准导出 createServerFn(客户端 split 会保留普通导出)
|
|
@@ -29,15 +28,14 @@ const transferUnfinishedSchema = z.object({
|
|
|
29
28
|
});
|
|
30
29
|
|
|
31
30
|
export const transferUnfinishedFn = createServerFn({ method: "POST" })
|
|
31
|
+
.middleware([authContextMiddleware])
|
|
32
32
|
.validator(transferUnfinishedSchema)
|
|
33
|
-
.handler(async ({ data }) => {
|
|
34
|
-
const request = getRequest();
|
|
35
|
-
const session = await requireAuth(request);
|
|
33
|
+
.handler(async ({ data, context }) => {
|
|
36
34
|
const count = await transferStoriesInternal(
|
|
37
35
|
data.iterationId,
|
|
38
36
|
data.targetIterationId,
|
|
39
37
|
data.storyIds,
|
|
40
|
-
|
|
38
|
+
context.user.id,
|
|
41
39
|
);
|
|
42
40
|
return { count };
|
|
43
41
|
});
|
|
@@ -17,41 +17,38 @@
|
|
|
17
17
|
|
|
18
18
|
import { getPrisma } from "@allbluecn/database/get-prisma"
|
|
19
19
|
import { createServerFn } from '@tanstack/react-start'
|
|
20
|
-
import { getRequest } from '@tanstack/react-start/server'
|
|
21
20
|
import { z } from 'zod'
|
|
22
|
-
import {
|
|
21
|
+
import { authContextMiddleware } from '@/server/middlewares/auth-context'
|
|
23
22
|
|
|
24
23
|
export const listBookmarkCategoriesFn = createServerFn({ method: 'GET' })
|
|
24
|
+
.middleware([authContextMiddleware])
|
|
25
25
|
.validator(z.object({}).optional())
|
|
26
|
-
.handler(async () => {
|
|
26
|
+
.handler(async ({ context }) => {
|
|
27
27
|
const prisma = await getPrisma()
|
|
28
|
-
const request = getRequest()
|
|
29
|
-
const session = await requireAuth(request)
|
|
30
28
|
return prisma.bookmarkCategory.findMany({
|
|
31
|
-
where: { OR: [{ userId: null }, { userId:
|
|
29
|
+
where: { OR: [{ userId: null }, { userId: context.user.id }] },
|
|
32
30
|
orderBy: [{ sortOrder: 'asc' }, { name: 'asc' }],
|
|
33
31
|
select: { id: true, name: true, icon: true, sortOrder: true, isDefault: true, userId: true },
|
|
34
32
|
})
|
|
35
33
|
})
|
|
36
34
|
|
|
37
35
|
export const createBookmarkCategoryFn = createServerFn({ method: 'POST' })
|
|
36
|
+
.middleware([authContextMiddleware])
|
|
38
37
|
.validator(z.object({ name: z.string().min(1).max(20), icon: z.string().default('Folder') }))
|
|
39
|
-
.handler(async ({ data }) => {
|
|
38
|
+
.handler(async ({ data, context }) => {
|
|
40
39
|
const prisma = await getPrisma()
|
|
41
|
-
const request = getRequest()
|
|
42
|
-
const session = await requireAuth(request)
|
|
43
40
|
// max+1 聚合与创建同事务(审计 2026-10-25:收窄 check-then-act 竞态窗口;
|
|
44
41
|
// 极端并发仍可能重复 sortOrder,展示层按 sortOrder+name 排序可容忍)
|
|
45
42
|
return prisma.$transaction(async (tx) => {
|
|
46
43
|
const last = await tx.bookmarkCategory.findFirst({
|
|
47
|
-
where: { userId:
|
|
44
|
+
where: { userId: context.user.id },
|
|
48
45
|
orderBy: { sortOrder: 'desc' },
|
|
49
46
|
})
|
|
50
47
|
return tx.bookmarkCategory.create({
|
|
51
48
|
data: {
|
|
52
49
|
name: data.name,
|
|
53
50
|
icon: data.icon,
|
|
54
|
-
userId:
|
|
51
|
+
userId: context.user.id,
|
|
55
52
|
sortOrder: (last?.sortOrder ?? 0) + 1,
|
|
56
53
|
},
|
|
57
54
|
select: { id: true, name: true, icon: true, sortOrder: true },
|
|
@@ -60,15 +57,14 @@ export const createBookmarkCategoryFn = createServerFn({ method: 'POST' })
|
|
|
60
57
|
})
|
|
61
58
|
|
|
62
59
|
export const deleteBookmarkCategoryFn = createServerFn({ method: 'POST' })
|
|
60
|
+
.middleware([authContextMiddleware])
|
|
63
61
|
.validator(z.object({ id: z.string() }))
|
|
64
|
-
.handler(async ({ data }) => {
|
|
62
|
+
.handler(async ({ data, context }) => {
|
|
65
63
|
const prisma = await getPrisma()
|
|
66
|
-
const request = getRequest()
|
|
67
|
-
const session = await requireAuth(request)
|
|
68
64
|
const cat = await prisma.bookmarkCategory.findUnique({ where: { id: data.id } })
|
|
69
65
|
if (!cat) throw new Error('未找到')
|
|
70
66
|
if (cat.isDefault) throw new Error('预置分类不可删除')
|
|
71
|
-
if (cat.userId !==
|
|
67
|
+
if (cat.userId !== context.user.id) throw new Error('无权限')
|
|
72
68
|
await prisma.bookmarkCategory.delete({ where: { id: data.id } })
|
|
73
69
|
return { success: true }
|
|
74
70
|
})
|
|
@@ -17,9 +17,8 @@
|
|
|
17
17
|
|
|
18
18
|
import { getPrisma } from "@allbluecn/database/get-prisma"
|
|
19
19
|
import { createServerFn } from '@tanstack/react-start'
|
|
20
|
-
import { getRequest } from '@tanstack/react-start/server'
|
|
21
20
|
import { z } from 'zod'
|
|
22
|
-
import {
|
|
21
|
+
import { authContextMiddleware } from '@/server/middlewares/auth-context'
|
|
23
22
|
import { checkUserActionRateLimit } from '@/server/lib/rate-limit'
|
|
24
23
|
import { bookmarkCanonicalId, parseGithubUrl } from '@/server/knowledge/public/canonical-id'
|
|
25
24
|
import { fetchGithubData } from '@/server/knowledge/public/github-sync'
|
|
@@ -41,12 +40,11 @@ const createSchema = z.object({
|
|
|
41
40
|
})
|
|
42
41
|
|
|
43
42
|
export const createBookmarkFn = createServerFn({ method: 'POST' })
|
|
43
|
+
.middleware([authContextMiddleware])
|
|
44
44
|
.validator(createSchema)
|
|
45
|
-
.handler(async ({ data }) => {
|
|
45
|
+
.handler(async ({ data, context }) => {
|
|
46
46
|
const prisma = await getPrisma()
|
|
47
|
-
const
|
|
48
|
-
const session = await requireAuth(request)
|
|
49
|
-
const userId = session.user.id
|
|
47
|
+
const userId = context.user.id
|
|
50
48
|
// categoryId 必须存在且属于当前用户或为公共分类(审计 2026-10-25:
|
|
51
49
|
// 防把书签挂到他人自定义分类下造成数据关联错乱)
|
|
52
50
|
if (data.categoryId) {
|
|
@@ -17,20 +17,18 @@
|
|
|
17
17
|
|
|
18
18
|
import { getPrisma } from "@allbluecn/database/get-prisma"
|
|
19
19
|
import { createServerFn } from '@tanstack/react-start'
|
|
20
|
-
import { getRequest } from '@tanstack/react-start/server'
|
|
21
20
|
import { z } from 'zod'
|
|
22
|
-
import {
|
|
21
|
+
import { authContextMiddleware } from '@/server/middlewares/auth-context'
|
|
23
22
|
|
|
24
23
|
export const deleteBookmarkFn = createServerFn({ method: 'POST' })
|
|
24
|
+
.middleware([authContextMiddleware])
|
|
25
25
|
.validator(z.object({ id: z.string() }))
|
|
26
|
-
.handler(async ({ data }) => {
|
|
26
|
+
.handler(async ({ data, context }) => {
|
|
27
27
|
const prisma = await getPrisma()
|
|
28
|
-
const request = getRequest()
|
|
29
|
-
const session = await requireAuth(request)
|
|
30
28
|
const existing = await prisma.websiteBookmark.findUnique({ where: { id: data.id } })
|
|
31
29
|
if (!existing) throw new Error('未找到')
|
|
32
|
-
const isOwner = existing.userId ===
|
|
33
|
-
const isAdmin =
|
|
30
|
+
const isOwner = existing.userId === context.user.id
|
|
31
|
+
const isAdmin = context.user.role === 'ADMIN' || context.user.role === 'SUPER_ADMIN'
|
|
34
32
|
if (!isOwner && !isAdmin) throw new Error('无权限')
|
|
35
33
|
await prisma.websiteBookmark.update({ where: { id: data.id }, data: { isDeleted: true } })
|
|
36
34
|
return { success: true }
|
|
@@ -17,18 +17,16 @@
|
|
|
17
17
|
|
|
18
18
|
import { getPrisma } from "@allbluecn/database/get-prisma"
|
|
19
19
|
import { createServerFn } from '@tanstack/react-start'
|
|
20
|
-
import { getRequest } from '@tanstack/react-start/server'
|
|
21
20
|
import { z } from 'zod'
|
|
22
|
-
import {
|
|
21
|
+
import { authContextMiddleware } from '@/server/middlewares/auth-context'
|
|
23
22
|
import { aggregateSharers, type PublicSharer } from '@/server/knowledge/public/share-merge'
|
|
24
23
|
|
|
25
24
|
export const getBookmarkDetailFn = createServerFn({ method: 'GET' })
|
|
25
|
+
.middleware([authContextMiddleware])
|
|
26
26
|
.validator(z.object({ id: z.string() }))
|
|
27
|
-
.handler(async ({ data }) => {
|
|
27
|
+
.handler(async ({ data, context }) => {
|
|
28
28
|
const prisma = await getPrisma()
|
|
29
|
-
const
|
|
30
|
-
const session = await requireAuth(request)
|
|
31
|
-
const userId = session.user.id
|
|
29
|
+
const userId = context.user.id
|
|
32
30
|
const item = await prisma.websiteBookmark.findFirst({
|
|
33
31
|
where: { id: data.id, isDeleted: false },
|
|
34
32
|
include: { category: { select: { icon: true } } },
|
|
@@ -17,17 +17,15 @@
|
|
|
17
17
|
|
|
18
18
|
import { getPrisma } from "@allbluecn/database/get-prisma"
|
|
19
19
|
import { createServerFn } from '@tanstack/react-start'
|
|
20
|
-
import { getRequest } from '@tanstack/react-start/server'
|
|
21
20
|
import { z } from 'zod'
|
|
22
|
-
import {
|
|
21
|
+
import { authContextMiddleware } from '@/server/middlewares/auth-context'
|
|
23
22
|
|
|
24
23
|
export const toggleFavoriteBookmarkFn = createServerFn({ method: 'POST' })
|
|
24
|
+
.middleware([authContextMiddleware])
|
|
25
25
|
.validator(z.object({ canonicalId: z.string() }))
|
|
26
|
-
.handler(async ({ data }) => {
|
|
26
|
+
.handler(async ({ data, context }) => {
|
|
27
27
|
const prisma = await getPrisma()
|
|
28
|
-
const
|
|
29
|
-
const session = await requireAuth(request)
|
|
30
|
-
const userId = session.user.id
|
|
28
|
+
const userId = context.user.id
|
|
31
29
|
// DB-03:同 toggleFavoriteFn——deleteMany 计数判定合并查后写,防并发重复收藏。
|
|
32
30
|
// 审计 2026-10-25 核实:ArticleFavorite 有 @@unique([entityType, entityId, userId])
|
|
33
31
|
// 兜底,并发双击时 create 撞唯一约束(P2002)——按「已收藏」语义吞掉该竞态。
|
|
@@ -18,9 +18,8 @@
|
|
|
18
18
|
import { getPrisma } from "@allbluecn/database/get-prisma"
|
|
19
19
|
import { Prisma } from '@allbluecn/database'
|
|
20
20
|
import { createServerFn } from '@tanstack/react-start'
|
|
21
|
-
import { getRequest } from '@tanstack/react-start/server'
|
|
22
21
|
import { z } from 'zod'
|
|
23
|
-
import {
|
|
22
|
+
import { authContextMiddleware } from '@/server/middlewares/auth-context'
|
|
24
23
|
import { aggregateSharers } from '@/server/knowledge/public/share-merge'
|
|
25
24
|
|
|
26
25
|
const listSchema = z.object({
|
|
@@ -33,12 +32,11 @@ const listSchema = z.object({
|
|
|
33
32
|
})
|
|
34
33
|
|
|
35
34
|
export const listBookmarksFn = createServerFn({ method: 'GET' })
|
|
35
|
+
.middleware([authContextMiddleware])
|
|
36
36
|
.validator(listSchema)
|
|
37
|
-
.handler(async ({ data }) => {
|
|
37
|
+
.handler(async ({ data, context }) => {
|
|
38
38
|
const prisma = await getPrisma()
|
|
39
|
-
const
|
|
40
|
-
const session = await requireAuth(request)
|
|
41
|
-
const userId = session.user.id
|
|
39
|
+
const userId = context.user.id
|
|
42
40
|
const where: Prisma.WebsiteBookmarkWhereInput = { isDeleted: false }
|
|
43
41
|
if (data.scope === 'private') {
|
|
44
42
|
where.userId = userId
|