@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
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// AllBlue - 理想之海
|
|
3
|
+
// Copyright (C) 2026 AllBlue Contributors
|
|
4
|
+
//
|
|
5
|
+
// This program is free software: you can redistribute it and/or modify
|
|
6
|
+
// it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
// the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
// (at your option) any later version.
|
|
9
|
+
//
|
|
10
|
+
// This program is distributed in the hope that it will be useful,
|
|
11
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
// GNU Affero General Public License for more details.
|
|
14
|
+
//
|
|
15
|
+
// You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
19
|
+
|
|
20
|
+
// auth-context middleware 内部经 getRequest() 取请求 → requireAuth(request) 解 session。
|
|
21
|
+
// 本测试 mock 请求入口(getRequest)与 session 底座(getCurrentSession / desktop-guest),
|
|
22
|
+
// 让「真实 requireAuth 链」在受控输入下运行——requireAuth 本身不 mock,
|
|
23
|
+
// 以此锁定 middleware 与旧 handler 内联鉴权走同一获取链。
|
|
24
|
+
vi.mock('@tanstack/react-start/server', () => ({
|
|
25
|
+
getRequest: vi.fn(),
|
|
26
|
+
}))
|
|
27
|
+
|
|
28
|
+
vi.mock('@/lib/session', () => ({
|
|
29
|
+
getCurrentSession: vi.fn(),
|
|
30
|
+
}))
|
|
31
|
+
|
|
32
|
+
vi.mock('@/server/desktop-guest', () => ({
|
|
33
|
+
isDesktopServer: vi.fn(() => false),
|
|
34
|
+
buildGuestSession: vi.fn(() => ({
|
|
35
|
+
user: { id: 'local-guest', email: 'guest@localhost', isGuest: true },
|
|
36
|
+
})),
|
|
37
|
+
}))
|
|
38
|
+
|
|
39
|
+
import { getRequest } from '@tanstack/react-start/server'
|
|
40
|
+
import { getCurrentSession } from '@/lib/session'
|
|
41
|
+
import { isDesktopServer } from '@/server/desktop-guest'
|
|
42
|
+
import { requireAuth, UnauthorizedError } from '@/server/auth-helpers'
|
|
43
|
+
import { authContextMiddleware } from '../auth-context'
|
|
44
|
+
|
|
45
|
+
/** 直调 middleware 的 server 段(框架 executeMiddleware 的最小等价调用)。 */
|
|
46
|
+
async function runAuthContextMiddleware(initialContext: Record<string, unknown> = {}) {
|
|
47
|
+
const serverFn = (authContextMiddleware as { options: { server?: Function } }).options.server
|
|
48
|
+
if (!serverFn) throw new Error('authContextMiddleware 未定义 .server() 段')
|
|
49
|
+
let merged: Record<string, unknown> = { ...initialContext }
|
|
50
|
+
return await (serverFn as any)({
|
|
51
|
+
data: undefined,
|
|
52
|
+
context: merged,
|
|
53
|
+
method: 'GET' as const,
|
|
54
|
+
serverFnMeta: {},
|
|
55
|
+
signal: new AbortController().signal,
|
|
56
|
+
next: async (inner?: { context?: Record<string, unknown> }) => {
|
|
57
|
+
// 与框架 callNextMiddleware 一致:next 的 context 增量并入调用方 context
|
|
58
|
+
merged = { ...merged, ...(inner?.context ?? {}) }
|
|
59
|
+
return { context: merged }
|
|
60
|
+
},
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const FAKE_REQUEST = new Request('http://localhost:3000/_serverFn/x')
|
|
65
|
+
|
|
66
|
+
const DB_USER = {
|
|
67
|
+
id: 'u1',
|
|
68
|
+
email: 'u1@test.com',
|
|
69
|
+
name: '用户一',
|
|
70
|
+
role: 'USER',
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
describe('authContextMiddleware(function middleware 注入 context.user)', () => {
|
|
74
|
+
beforeEach(() => {
|
|
75
|
+
vi.clearAllMocks()
|
|
76
|
+
vi.mocked(getRequest).mockReturnValue(FAKE_REQUEST)
|
|
77
|
+
vi.mocked(isDesktopServer).mockReturnValue(false)
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('① 无 session:抛出与旧 requireAuth() 完全同型的 UnauthorizedError(name/message/constructor 逐字段一致)', async () => {
|
|
81
|
+
vi.mocked(getCurrentSession).mockResolvedValue(null)
|
|
82
|
+
|
|
83
|
+
// 基准:同一输入下旧 requireAuth 的抛错形状
|
|
84
|
+
let baseline: unknown
|
|
85
|
+
try {
|
|
86
|
+
await requireAuth(FAKE_REQUEST)
|
|
87
|
+
} catch (e) {
|
|
88
|
+
baseline = e
|
|
89
|
+
}
|
|
90
|
+
expect(baseline).toBeInstanceOf(UnauthorizedError)
|
|
91
|
+
const base = baseline as UnauthorizedError
|
|
92
|
+
|
|
93
|
+
let caught: unknown
|
|
94
|
+
try {
|
|
95
|
+
await runAuthContextMiddleware()
|
|
96
|
+
} catch (e) {
|
|
97
|
+
caught = e
|
|
98
|
+
}
|
|
99
|
+
expect(caught).toBeInstanceOf(UnauthorizedError)
|
|
100
|
+
const err = caught as UnauthorizedError
|
|
101
|
+
expect(err.name).toBe('UnauthorizedError')
|
|
102
|
+
expect(err.message).toBe('UNAUTHORIZED')
|
|
103
|
+
// 同型判定:与旧 requireAuth 抛错逐字段一致(客户端 401 处理依赖此形状)
|
|
104
|
+
expect(err.constructor).toBe(base.constructor)
|
|
105
|
+
expect(err.name).toBe(base.name)
|
|
106
|
+
expect(err.message).toBe(base.message)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('①b 无 session:鉴权请求来自 getRequest()(与旧 handler 内联取法同源)', async () => {
|
|
110
|
+
vi.mocked(getCurrentSession).mockResolvedValue(null)
|
|
111
|
+
await expect(runAuthContextMiddleware()).rejects.toBeInstanceOf(UnauthorizedError)
|
|
112
|
+
expect(getRequest).toHaveBeenCalledTimes(1)
|
|
113
|
+
// requireAuth 收到的 request 与 getRequest() 返回值同源
|
|
114
|
+
expect(getCurrentSession).toHaveBeenCalledWith(FAKE_REQUEST)
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('② 有 session:context.user 为 DB 用户对象(requireAuth 返回的同一引用)', async () => {
|
|
118
|
+
vi.mocked(getCurrentSession).mockResolvedValue({
|
|
119
|
+
user: DB_USER,
|
|
120
|
+
} as never)
|
|
121
|
+
|
|
122
|
+
const result = await runAuthContextMiddleware()
|
|
123
|
+
expect(result.context).toBeDefined()
|
|
124
|
+
expect(result.context.user).toBe(DB_USER)
|
|
125
|
+
expect(result.context.user.id).toBe('u1')
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
it('②b desktop guest 降级语义保持:DEPLOY_TARGET=desktop 时匿名请求注入共享 guest 用户', async () => {
|
|
129
|
+
vi.mocked(getCurrentSession).mockResolvedValue(null)
|
|
130
|
+
vi.mocked(isDesktopServer).mockReturnValue(true)
|
|
131
|
+
|
|
132
|
+
const result = await runAuthContextMiddleware()
|
|
133
|
+
expect(result.context.user.id).toBe('local-guest')
|
|
134
|
+
expect(result.context.user.isGuest).toBe(true)
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
it('③ session 校验用户存在防线不变:session.user 为空(session callback getCachedProfile 拒绝的下游形态)→ 抛 UnauthorizedError', async () => {
|
|
138
|
+
// session callback 用户存在性校验失败时,session.user 为 null/缺失 id——
|
|
139
|
+
// middleware 必须与旧 requireAuth 一样拒绝该 session,而非注入无 id 的 user
|
|
140
|
+
vi.mocked(getCurrentSession).mockResolvedValue({ user: null } as never)
|
|
141
|
+
|
|
142
|
+
await expect(runAuthContextMiddleware()).rejects.toBeInstanceOf(UnauthorizedError)
|
|
143
|
+
|
|
144
|
+
// user 存在但缺 id(JWT 无 id 字段)同样拒绝
|
|
145
|
+
vi.mocked(getCurrentSession).mockResolvedValue({ user: { email: 'x@test.com' } } as never)
|
|
146
|
+
await expect(runAuthContextMiddleware()).rejects.toBeInstanceOf(UnauthorizedError)
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
it('③b 既有 context 增量保留:middleware 注入 user 不覆盖调用方已有 context 字段', async () => {
|
|
150
|
+
vi.mocked(getCurrentSession).mockResolvedValue({ user: DB_USER } as never)
|
|
151
|
+
|
|
152
|
+
const result = await runAuthContextMiddleware({ requestId: 'ctx-1' })
|
|
153
|
+
expect(result.context.requestId).toBe('ctx-1')
|
|
154
|
+
expect(result.context.user).toBe(DB_USER)
|
|
155
|
+
})
|
|
156
|
+
})
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// AllBlue - 理想之海
|
|
3
|
+
// Copyright (C) 2026 AllBlue Contributors
|
|
4
|
+
//
|
|
5
|
+
// This program is free software: you can redistribute it and/or modify
|
|
6
|
+
// it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
// the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
// (at your option) any later version.
|
|
9
|
+
//
|
|
10
|
+
// This program is distributed in the hope that it will be useful,
|
|
11
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
// GNU Affero General Public License for more details.
|
|
14
|
+
//
|
|
15
|
+
// You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
import { createMiddleware } from '@tanstack/react-start'
|
|
19
|
+
import { getRequest } from '@tanstack/react-start/server'
|
|
20
|
+
import { requireAuth } from '@/server/auth-helpers'
|
|
21
|
+
import type { AuthedSession } from '@/server/auth-helpers'
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* context.user 的注入类型:与 requireAuth 成功返回的 session.user 同型
|
|
25
|
+
* (SessionUser & { id: string },消费方免非空断言)。
|
|
26
|
+
*/
|
|
27
|
+
export type AuthedContextUser = AuthedSession['user']
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* function middleware 注入的 context 增量形状(per-fn `.middleware()` 挂载后,
|
|
31
|
+
* handler 的 `context` 参数自动获得本类型)。
|
|
32
|
+
*/
|
|
33
|
+
export interface AuthedContext {
|
|
34
|
+
user: AuthedContextUser
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* serverFn 鉴权 context 注入 middleware(TanStack 优化计划任务 6,team 域试点)。
|
|
39
|
+
*
|
|
40
|
+
* 复核结论(@tanstack/react-start@1.169.4 / start-client-core@1.170.39,.d.ts 实证):
|
|
41
|
+
* - per-fn `.middleware()` 是本基建采用的唯一挂载路径:`createServerFn(...).middleware([mw])`
|
|
42
|
+
* (createServerFn.d.ts ServerFnMiddleware),middleware 的 `.server()` 产出 context 经
|
|
43
|
+
* `AssignAllServerFnContext` 自动流入 handler 的 `context` 类型(ServerFnCtx),
|
|
44
|
+
* 无需 `declare module` augmentation。
|
|
45
|
+
* - 全局挂载点在本版本实际存在(StartInstanceOptions.functionMiddleware 声明 +
|
|
46
|
+
* createServerFn.js 运行时把 getStartOptions().functionMiddleware 拼进执行链),
|
|
47
|
+
* 但不用:① 全局路径的类型注入依赖 Register.config augmentation(app 的 Register
|
|
48
|
+
* 仅 augment 了 router);② 全局注入会对全部 serverFn(含邀请 token 查询、bug 上报
|
|
49
|
+
* 等 ~600 个公开/免鉴权端点)跑鉴权查询,改变公开端点行为与性能。T7 CI 守护按
|
|
50
|
+
* per-fn 存在性检查配套。
|
|
51
|
+
* - 错误同型:middleware 抛错与 handler 内抛错走同一条 RPC 错误序列化路径
|
|
52
|
+
* (handleServerAction 同一 try/catch → createServerFnErrorResponse),故本 middleware
|
|
53
|
+
* 内部直接复用 `requireAuth(getRequest())` 旧链,UnauthorizedError 形状零变化
|
|
54
|
+
* (客户端 401 处理依赖)。资源属主校验(assertOwned 等)不在此层,仍在各 handler。
|
|
55
|
+
*/
|
|
56
|
+
export const authContextMiddleware = createMiddleware({ type: 'function' }).server<AuthedContext>(
|
|
57
|
+
async ({ next }) => {
|
|
58
|
+
const request = getRequest()
|
|
59
|
+
const session = await requireAuth(request)
|
|
60
|
+
return next({ context: { user: session.user } })
|
|
61
|
+
},
|
|
62
|
+
)
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
1
|
+
// 桌面远端会话持久层(Electron):读写 Electron 宿主注入的
|
|
2
|
+
// DESKTOP_USER_DATA_DIR 下的 remote-auth.json(main.ts 集中注入 env,
|
|
3
|
+
// backend serverFn 进程内 fs 直达,无 IPC)。Tauri invoke 实现已随
|
|
4
|
+
// Tauri 2 → Electron 迁移清除(2026-10-31);云/Web 部署(DEPLOY_TARGET
|
|
5
|
+
// 非 desktop)恒 null / no-op,行为与旧版一致。
|
|
6
|
+
import { promises as fs } from "node:fs"
|
|
7
|
+
import path from "node:path"
|
|
8
|
+
|
|
3
9
|
export interface RemoteAuthData {
|
|
4
10
|
userId: string
|
|
5
11
|
planName: string
|
|
@@ -16,23 +22,61 @@ export interface RemoteAuthData {
|
|
|
16
22
|
bgColor?: string
|
|
17
23
|
}
|
|
18
24
|
|
|
19
|
-
|
|
20
|
-
|
|
25
|
+
/** 磁盘形态:auth(登录 token)与 session(exchange 后的会话态)分次写入、合并读取 */
|
|
26
|
+
interface RemoteAuthFile {
|
|
27
|
+
token?: string
|
|
28
|
+
sessionToken?: string
|
|
29
|
+
session?: {
|
|
30
|
+
userId: string
|
|
31
|
+
planName: string
|
|
32
|
+
sessionToken?: string
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function filePath(): string | null {
|
|
37
|
+
const dir = process.env.DESKTOP_USER_DATA_DIR
|
|
38
|
+
if (!dir) return null
|
|
39
|
+
return path.join(dir, "remote-auth.json")
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function readFile(): Promise<RemoteAuthFile | null> {
|
|
43
|
+
const file = filePath()
|
|
44
|
+
if (!file) return null
|
|
21
45
|
try {
|
|
22
|
-
|
|
23
|
-
return (await invoke<RemoteAuthData | null>('read_remote_auth')) ?? null
|
|
46
|
+
return JSON.parse(await fs.readFile(file, "utf8")) as RemoteAuthFile
|
|
24
47
|
} catch {
|
|
48
|
+
// 文件不存在/损坏均视为未登录(损坏文件在下次写入时被覆盖自愈)
|
|
25
49
|
return null
|
|
26
50
|
}
|
|
27
51
|
}
|
|
28
52
|
|
|
29
|
-
|
|
30
|
-
|
|
53
|
+
async function writeFile(next: RemoteAuthFile): Promise<void> {
|
|
54
|
+
const file = filePath()
|
|
55
|
+
if (!file) return
|
|
56
|
+
const tmp = `${file}.tmp`
|
|
57
|
+
// 0600:文件含云会话 token(敏感),限属主读写;tmp+rename 原子替换防半写
|
|
58
|
+
await fs.writeFile(tmp, JSON.stringify(next, null, 2), { mode: 0o600 })
|
|
59
|
+
await fs.rename(tmp, file)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export async function readRemoteAuth(): Promise<RemoteAuthData | null> {
|
|
63
|
+
if (process.env.DEPLOY_TARGET !== 'desktop') return null
|
|
64
|
+
const data = await readFile()
|
|
65
|
+
if (!data?.session?.userId) return null
|
|
66
|
+
return {
|
|
67
|
+
userId: data.session.userId,
|
|
68
|
+
planName: data.session.planName,
|
|
69
|
+
features: {},
|
|
70
|
+
sessionToken: data.session.sessionToken ?? data.sessionToken,
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// 写入防御(2026-10 审计 🟢):本地持久化失败不应反噬登录/登出主流程
|
|
31
75
|
export async function writeRemoteAuth(token: string, sessionToken?: string): Promise<void> {
|
|
32
76
|
if (process.env.DEPLOY_TARGET !== 'desktop') return
|
|
33
|
-
const { invoke } = await import('@tauri-apps/api/core')
|
|
34
77
|
try {
|
|
35
|
-
await
|
|
78
|
+
const prev = (await readFile()) ?? {}
|
|
79
|
+
await writeFile({ ...prev, token, sessionToken })
|
|
36
80
|
} catch (e) {
|
|
37
81
|
console.warn('[remote-auth] write_remote_auth 失败(本地权益态未更新):', e instanceof Error ? e.message : String(e))
|
|
38
82
|
}
|
|
@@ -44,9 +88,9 @@ export async function writeRemoteSession(
|
|
|
44
88
|
sessionToken?: string,
|
|
45
89
|
): Promise<void> {
|
|
46
90
|
if (process.env.DEPLOY_TARGET !== 'desktop') return
|
|
47
|
-
const { invoke } = await import('@tauri-apps/api/core')
|
|
48
91
|
try {
|
|
49
|
-
|
|
92
|
+
const prev = (await readFile()) ?? {}
|
|
93
|
+
await writeFile({ ...prev, session: { userId, planName, sessionToken } })
|
|
50
94
|
} catch (e) {
|
|
51
95
|
console.warn('[remote-auth] write_remote_session 失败(本地会话态未更新):', e instanceof Error ? e.message : String(e))
|
|
52
96
|
}
|
|
@@ -54,27 +98,10 @@ export async function writeRemoteSession(
|
|
|
54
98
|
|
|
55
99
|
export async function clearRemoteAuth(): Promise<void> {
|
|
56
100
|
if (process.env.DEPLOY_TARGET !== 'desktop') return
|
|
57
|
-
const { invoke } = await import('@tauri-apps/api/core')
|
|
58
101
|
try {
|
|
59
|
-
|
|
102
|
+
const file = filePath()
|
|
103
|
+
if (file) await fs.rm(file, { force: true })
|
|
60
104
|
} catch (e) {
|
|
61
105
|
console.warn('[remote-auth] clear_remote_auth 失败(本地态可能残留):', e instanceof Error ? e.message : String(e))
|
|
62
106
|
}
|
|
63
107
|
}
|
|
64
|
-
|
|
65
|
-
export async function openLoginUrl(loginUrl: string): Promise<void> {
|
|
66
|
-
if (process.env.DEPLOY_TARGET !== 'desktop') {
|
|
67
|
-
if (typeof window !== 'undefined') {
|
|
68
|
-
window.open(
|
|
69
|
-
loginUrl.startsWith('/')
|
|
70
|
-
? `${window.location.origin}${loginUrl}`
|
|
71
|
-
: loginUrl,
|
|
72
|
-
'_blank',
|
|
73
|
-
'noopener,noreferrer',
|
|
74
|
-
)
|
|
75
|
-
}
|
|
76
|
-
return
|
|
77
|
-
}
|
|
78
|
-
const { invoke } = await import('@tauri-apps/api/core')
|
|
79
|
-
await invoke('open_login_url', { url: loginUrl })
|
|
80
|
-
}
|
|
@@ -2,17 +2,50 @@
|
|
|
2
2
|
import { describe, expect, it, vi, beforeEach } from 'vitest'
|
|
3
3
|
|
|
4
4
|
// ① createServerFn chain builder mock(与 ai-source-mode.test.ts 相同)
|
|
5
|
-
vi.mock('@tanstack/react-start', () => {
|
|
6
|
-
|
|
5
|
+
vi.mock('@tanstack/react-start', () => ({
|
|
6
|
+
// 迁移后经 .middleware([authContextMiddleware]) 注入 context.user:
|
|
7
|
+
// mock 依序执行 middleware 的 server 段(复现框架 executeMiddleware 的
|
|
8
|
+
// context 合并语义),真实鉴权链由被 mock 的 auth-helpers/getRequest 承接
|
|
9
|
+
createServerFn: () => {
|
|
7
10
|
const api: any = {
|
|
11
|
+
_middlewares: [] as any[],
|
|
12
|
+
middleware(mws: any[]) {
|
|
13
|
+
api._middlewares.push(...mws)
|
|
14
|
+
return api
|
|
15
|
+
},
|
|
8
16
|
handler(fn: Function) {
|
|
9
|
-
return async (args: { data: unknown }) =>
|
|
17
|
+
return async (args: { data: unknown }) => {
|
|
18
|
+
let context: any = {}
|
|
19
|
+
for (const mw of api._middlewares) {
|
|
20
|
+
const serverFn = mw?.options?.server
|
|
21
|
+
if (!serverFn) continue
|
|
22
|
+
const result = await serverFn({
|
|
23
|
+
data: args?.data,
|
|
24
|
+
context,
|
|
25
|
+
method: 'GET',
|
|
26
|
+
serverFnMeta: {},
|
|
27
|
+
signal: new AbortController().signal,
|
|
28
|
+
next: async (inner: any) => ({ context: { ...context, ...(inner?.context ?? {}) } }),
|
|
29
|
+
})
|
|
30
|
+
context = result.context
|
|
31
|
+
}
|
|
32
|
+
return fn({ ...args, context })
|
|
33
|
+
}
|
|
10
34
|
},
|
|
11
35
|
}
|
|
12
36
|
return api
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
}
|
|
37
|
+
},
|
|
38
|
+
// auth-context.ts 依赖 createMiddleware({ type: 'function' }).server(fn):
|
|
39
|
+
// mock 产出与真实 middleware 同构的 { options: { server } } 形状
|
|
40
|
+
createMiddleware: (opts: any) => {
|
|
41
|
+
const mw: any = { options: { type: opts?.type } }
|
|
42
|
+
mw.server = (fn: Function) => {
|
|
43
|
+
mw.options.server = fn
|
|
44
|
+
return mw
|
|
45
|
+
}
|
|
46
|
+
return mw
|
|
47
|
+
},
|
|
48
|
+
}))
|
|
16
49
|
vi.mock('@tanstack/react-start/server', () => ({
|
|
17
50
|
getRequest: () => ({}),
|
|
18
51
|
}))
|
|
@@ -22,20 +55,19 @@ const mocks = vi.hoisted(() => ({
|
|
|
22
55
|
currentSession: vi.fn(),
|
|
23
56
|
}))
|
|
24
57
|
|
|
25
|
-
|
|
26
|
-
|
|
58
|
+
// 迁移后 requireAuth 消费入口:authContextMiddleware 内部调用
|
|
59
|
+
vi.mock('@/server/auth-helpers', async (importOriginal) => {
|
|
60
|
+
const actual = await importOriginal<typeof import('@/server/auth-helpers')>()
|
|
27
61
|
const UnauthorizedError = class UnauthorizedError extends Error {
|
|
28
62
|
constructor(message = 'UNAUTHORIZED') { super(message); this.name = 'UnauthorizedError' }
|
|
29
63
|
}
|
|
30
64
|
return {
|
|
31
65
|
...actual,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
},
|
|
38
|
-
}),
|
|
66
|
+
requireAuth: async () => {
|
|
67
|
+
const session = await mocks.currentSession()
|
|
68
|
+
if (!session?.user?.id) throw new UnauthorizedError()
|
|
69
|
+
return session
|
|
70
|
+
},
|
|
39
71
|
}
|
|
40
72
|
})
|
|
41
73
|
|
|
@@ -2,9 +2,17 @@
|
|
|
2
2
|
import { describe, expect, it, vi, beforeEach } from 'vitest'
|
|
3
3
|
|
|
4
4
|
// ① createServerFn chain builder mock(照抄 workspace-kb-idor.test.ts:25-45)
|
|
5
|
-
vi.mock('@tanstack/react-start', () => {
|
|
6
|
-
|
|
5
|
+
vi.mock('@tanstack/react-start', () => ({
|
|
6
|
+
// 迁移后经 .middleware([authContextMiddleware]) 注入 context.user:
|
|
7
|
+
// mock 依序执行 middleware 的 server 段(复现框架 executeMiddleware 的
|
|
8
|
+
// context 合并语义),真实鉴权链由被 mock 的 auth-helpers/getRequest 承接
|
|
9
|
+
createServerFn: () => {
|
|
7
10
|
const api: any = {
|
|
11
|
+
_middlewares: [] as any[],
|
|
12
|
+
middleware(mws: any[]) {
|
|
13
|
+
api._middlewares.push(...mws)
|
|
14
|
+
return api
|
|
15
|
+
},
|
|
8
16
|
validator(schema: { parse: (d: unknown) => unknown }) {
|
|
9
17
|
api._validator = schema
|
|
10
18
|
return api
|
|
@@ -15,14 +23,37 @@ vi.mock('@tanstack/react-start', () => {
|
|
|
15
23
|
if (api._validator && data !== undefined) {
|
|
16
24
|
data = api._validator.parse ? api._validator.parse(data) : data
|
|
17
25
|
}
|
|
18
|
-
|
|
26
|
+
let context: any = {}
|
|
27
|
+
for (const mw of api._middlewares) {
|
|
28
|
+
const serverFn = mw?.options?.server
|
|
29
|
+
if (!serverFn) continue
|
|
30
|
+
const result = await serverFn({
|
|
31
|
+
data,
|
|
32
|
+
context,
|
|
33
|
+
method: 'POST',
|
|
34
|
+
serverFnMeta: {},
|
|
35
|
+
signal: new AbortController().signal,
|
|
36
|
+
next: async (inner: any) => ({ context: { ...context, ...(inner?.context ?? {}) } }),
|
|
37
|
+
})
|
|
38
|
+
context = result.context
|
|
39
|
+
}
|
|
40
|
+
return fn({ data, context })
|
|
19
41
|
}
|
|
20
42
|
},
|
|
21
43
|
}
|
|
22
44
|
return api
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
}
|
|
45
|
+
},
|
|
46
|
+
// auth-context.ts 依赖 createMiddleware({ type: 'function' }).server(fn):
|
|
47
|
+
// mock 产出与真实 middleware 同构的 { options: { server } } 形状
|
|
48
|
+
createMiddleware: (opts: any) => {
|
|
49
|
+
const mw: any = { options: { type: opts?.type } }
|
|
50
|
+
mw.server = (fn: Function) => {
|
|
51
|
+
mw.options.server = fn
|
|
52
|
+
return mw
|
|
53
|
+
}
|
|
54
|
+
return mw
|
|
55
|
+
},
|
|
56
|
+
}))
|
|
26
57
|
vi.mock('@tanstack/react-start/server', () => ({
|
|
27
58
|
getRequest: () => ({}),
|
|
28
59
|
}))
|
|
@@ -32,20 +63,19 @@ const mocks = vi.hoisted(() => ({
|
|
|
32
63
|
currentSession: vi.fn(),
|
|
33
64
|
}))
|
|
34
65
|
|
|
35
|
-
|
|
36
|
-
|
|
66
|
+
// 迁移后 requireAuth 消费入口:authContextMiddleware 内部调用
|
|
67
|
+
vi.mock('@/server/auth-helpers', async (importOriginal) => {
|
|
68
|
+
const actual = await importOriginal<typeof import('@/server/auth-helpers')>()
|
|
37
69
|
const UnauthorizedError = class UnauthorizedError extends Error {
|
|
38
70
|
constructor(message = 'UNAUTHORIZED') { super(message); this.name = 'UnauthorizedError' }
|
|
39
71
|
}
|
|
40
72
|
return {
|
|
41
73
|
...actual,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
},
|
|
48
|
-
}),
|
|
74
|
+
requireAuth: async () => {
|
|
75
|
+
const session = await mocks.currentSession()
|
|
76
|
+
if (!session?.user?.id) throw new UnauthorizedError()
|
|
77
|
+
return session
|
|
78
|
+
},
|
|
49
79
|
}
|
|
50
80
|
})
|
|
51
81
|
|
|
@@ -46,11 +46,16 @@ vi.mock("@tanstack/react-start", () => ({
|
|
|
46
46
|
createServerFn: () => {
|
|
47
47
|
const api = {
|
|
48
48
|
_validator: undefined as unknown,
|
|
49
|
+
_middlewares: [] as unknown[],
|
|
50
|
+
middleware(mws: unknown[]) {
|
|
51
|
+
this._middlewares.push(...mws);
|
|
52
|
+
return this;
|
|
53
|
+
},
|
|
49
54
|
validator(schema: unknown) {
|
|
50
55
|
this._validator = schema;
|
|
51
56
|
return this;
|
|
52
57
|
},
|
|
53
|
-
handler(fn: (p: { data: unknown }) => Promise<unknown>) {
|
|
58
|
+
handler(fn: (p: { data: unknown; context: unknown }) => Promise<unknown>) {
|
|
54
59
|
const self = this;
|
|
55
60
|
return async (args: { data?: unknown }) => {
|
|
56
61
|
let data = args?.data;
|
|
@@ -58,12 +63,42 @@ vi.mock("@tanstack/react-start", () => ({
|
|
|
58
63
|
const v = self._validator as { parse?: (d: unknown) => unknown };
|
|
59
64
|
data = v.parse ? v.parse(data) : data;
|
|
60
65
|
}
|
|
61
|
-
|
|
66
|
+
// 迁移后经 .middleware([authContextMiddleware]) 注入 context.user:
|
|
67
|
+
// 依序执行 middleware 的 server 段,真实鉴权链由被 mock 的 auth-helpers 承接
|
|
68
|
+
let context: unknown = {};
|
|
69
|
+
for (const mw of self._middlewares) {
|
|
70
|
+
const serverFn = (mw as { options?: { server?: unknown } })?.options?.server;
|
|
71
|
+
if (typeof serverFn !== "function") continue;
|
|
72
|
+
const result = await (
|
|
73
|
+
serverFn as (p: unknown) => Promise<{ context?: unknown }>
|
|
74
|
+
)({
|
|
75
|
+
data,
|
|
76
|
+
context,
|
|
77
|
+
method: "POST",
|
|
78
|
+
serverFnMeta: {},
|
|
79
|
+
signal: new AbortController().signal,
|
|
80
|
+
next: (inner: { context?: unknown } | undefined) =>
|
|
81
|
+
Promise.resolve({ context: { ...(context as object), ...(inner?.context ?? {}) } }),
|
|
82
|
+
});
|
|
83
|
+
context = result.context;
|
|
84
|
+
}
|
|
85
|
+
return fn({ data, context });
|
|
62
86
|
};
|
|
63
87
|
},
|
|
64
88
|
};
|
|
65
89
|
return api;
|
|
66
90
|
},
|
|
91
|
+
// auth-context.ts 依赖 createMiddleware({ type: 'function' }).server(fn):
|
|
92
|
+
// mock 产出与真实 middleware 同构的 { options: { server } } 形状,
|
|
93
|
+
// 供上方 handler 包装器执行 server 段注入 context.user
|
|
94
|
+
createMiddleware: (opts: any) => {
|
|
95
|
+
const mw: any = { options: { type: opts?.type } };
|
|
96
|
+
mw.server = (fn: Function) => {
|
|
97
|
+
mw.options.server = fn;
|
|
98
|
+
return mw;
|
|
99
|
+
};
|
|
100
|
+
return mw;
|
|
101
|
+
},
|
|
67
102
|
}));
|
|
68
103
|
|
|
69
104
|
vi.mock("@tanstack/react-start/server", () => ({ getRequest: () => ({}) }));
|
|
@@ -28,7 +28,6 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
|
28
28
|
import { readFileSync } from "node:fs";
|
|
29
29
|
import { join } from "node:path";
|
|
30
30
|
import * as Y from "yjs";
|
|
31
|
-
import type { ZodType } from "zod";
|
|
32
31
|
|
|
33
32
|
const mocks = vi.hoisted(() => ({
|
|
34
33
|
requireAuth: vi.fn(),
|
|
@@ -43,30 +42,58 @@ const mocks = vi.hoisted(() => ({
|
|
|
43
42
|
}));
|
|
44
43
|
|
|
45
44
|
vi.mock("@tanstack/react-start", () => ({
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
} = {
|
|
45
|
+
// 迁移后经 .middleware([authContextMiddleware]) 注入 context.user:
|
|
46
|
+
// mock 依序执行 middleware 的 server 段(复现框架 executeMiddleware 的
|
|
47
|
+
// context 合并语义),真实鉴权链由被 mock 的 auth-helpers/getRequest 承接
|
|
48
|
+
createServerFn: (config: any) => {
|
|
49
|
+
const api: any = {
|
|
52
50
|
_validator: undefined,
|
|
53
|
-
|
|
51
|
+
_middlewares: [] as any[],
|
|
52
|
+
middleware(mws: any[]) {
|
|
53
|
+
api._middlewares.push(...mws);
|
|
54
|
+
return api;
|
|
55
|
+
},
|
|
56
|
+
validator(schema: any) {
|
|
54
57
|
this._validator = schema;
|
|
55
58
|
return this;
|
|
56
59
|
},
|
|
57
|
-
handler(fn:
|
|
58
|
-
const
|
|
59
|
-
return async (args: { data?: unknown }) => {
|
|
60
|
+
handler(fn: Function) {
|
|
61
|
+
const wrapped = async (args: any) => {
|
|
60
62
|
let data = args?.data;
|
|
61
|
-
if (
|
|
62
|
-
data =
|
|
63
|
+
if (api._validator && data !== undefined) {
|
|
64
|
+
data = api._validator.parse ? api._validator.parse(data) : data;
|
|
65
|
+
}
|
|
66
|
+
let context: any = {};
|
|
67
|
+
for (const mw of api._middlewares) {
|
|
68
|
+
const serverFn = mw?.options?.server;
|
|
69
|
+
if (!serverFn) continue;
|
|
70
|
+
const result = await serverFn({
|
|
71
|
+
data,
|
|
72
|
+
context,
|
|
73
|
+
method: "POST",
|
|
74
|
+
serverFnMeta: {},
|
|
75
|
+
signal: new AbortController().signal,
|
|
76
|
+
next: async (inner: any) => ({ context: { ...context, ...(inner?.context ?? {}) } }),
|
|
77
|
+
});
|
|
78
|
+
context = result.context;
|
|
63
79
|
}
|
|
64
|
-
return fn({ data });
|
|
80
|
+
return fn({ data, context });
|
|
65
81
|
};
|
|
82
|
+
return wrapped;
|
|
66
83
|
},
|
|
67
84
|
};
|
|
68
85
|
return api;
|
|
69
86
|
},
|
|
87
|
+
// auth-context.ts 依赖 createMiddleware({ type: "function" }).server(fn):
|
|
88
|
+
// mock 产出与真实 middleware 同构的 { options: { server } } 形状
|
|
89
|
+
createMiddleware: (opts: any) => {
|
|
90
|
+
const mw: any = { options: { type: opts?.type } };
|
|
91
|
+
mw.server = (fn: Function) => {
|
|
92
|
+
mw.options.server = fn;
|
|
93
|
+
return mw;
|
|
94
|
+
};
|
|
95
|
+
return mw;
|
|
96
|
+
},
|
|
70
97
|
}));
|
|
71
98
|
|
|
72
99
|
vi.mock("@tanstack/react-start/server", () => ({
|