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