@taskforcehq/taskforce 0.3.169 → 0.3.300
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/README.md +52 -21
- package/dist/Taskforce.module.css +3394 -5981
- package/dist/TaskforceCore.CategoryFallback.test.js +5 -2
- package/dist/TaskforceCore.filter-persistence.test.js +402 -0
- package/dist/TaskforceCore.js +388 -71
- package/dist/TaskforceCore.routing.test.js +311 -0
- package/dist/TaskforceCore.test.js +3344 -615
- package/dist/TaskforceWidget.js +3 -2
- package/dist/__tests__/localizationCatalogs.test.js +48 -31
- package/dist/__tests__/workflowSimulation.test.js +2 -2
- package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.d.ts +60 -0
- package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.js +324 -0
- package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.test.js +278 -0
- package/dist/annotatedAttachments/payload.d.ts +2 -0
- package/dist/annotatedAttachments/payload.js +54 -0
- package/dist/annotatedAttachments/payload.test.js +67 -0
- package/dist/annotatedAttachments/service.d.ts +49 -0
- package/dist/annotatedAttachments/service.js +121 -0
- package/dist/annotatedAttachments/types.d.ts +86 -0
- package/dist/cli.js +74 -25
- package/dist/compat/deploymentCompat.d.ts +12 -0
- package/dist/compat/deploymentCompat.js +43 -0
- package/dist/compat/workspaceSyncCompat.d.ts +6 -0
- package/dist/compat/workspaceSyncCompat.js +79 -0
- package/dist/compat/workspaceSyncCompat.test.js +87 -0
- package/dist/components/features/AgentsModule.d.ts +5 -0
- package/dist/components/features/AgentsModule.js +131 -0
- package/dist/components/features/AgentsModule.test.js +102 -0
- package/dist/components/features/AnnotatedAttachmentWorkspace.d.ts +24 -0
- package/dist/components/features/AnnotatedAttachmentWorkspace.js +1942 -0
- package/dist/components/features/AnnotatedAttachmentWorkspace.test.js +2831 -0
- package/dist/components/features/DocumentGenerateModal.js +8 -16
- package/dist/components/features/DocumentIndex.d.ts +3 -4
- package/dist/components/features/DocumentIndex.js +22 -10
- package/dist/components/features/DocumentViewer.d.ts +6 -2
- package/dist/components/features/DocumentViewer.js +1000 -18
- package/dist/components/features/DocumentWorkspace.d.ts +40 -2
- package/dist/components/features/DocumentWorkspace.js +96 -16
- package/dist/components/features/DocumentWorkspace.test.js +1202 -0
- package/dist/components/features/InitiativesModule.d.ts +22 -0
- package/dist/components/features/InitiativesModule.js +33 -0
- package/dist/components/features/TaskSettings.d.ts +41 -32
- package/dist/components/features/TaskSettings.js +798 -313
- package/dist/components/features/TaskSettings.test.js +1221 -47
- package/dist/components/features/WorkflowsModule.d.ts +27 -0
- package/dist/components/features/WorkflowsModule.js +21 -0
- package/dist/components/features/documentWorkspaceFilters.d.ts +10 -0
- package/dist/components/features/documentWorkspaceFilters.js +11 -0
- package/dist/components/features/settings/CategoryManager.d.ts +2 -0
- package/dist/components/features/settings/CategoryManager.js +15 -8
- package/dist/components/features/settings/PriorityManager.d.ts +18 -0
- package/dist/components/features/settings/PriorityManager.js +51 -0
- package/dist/components/features/settings/TaxonomyEditor.d.ts +2 -1
- package/dist/components/features/settings/TaxonomyEditor.js +41 -18
- package/dist/components/features/settings/TaxonomyLibraryManager.d.ts +26 -0
- package/dist/components/features/settings/TaxonomyLibraryManager.js +301 -0
- package/dist/components/features/settings/TaxonomyLibraryManager.test.js +141 -0
- package/dist/components/features/settings/TaxonomyManager.d.ts +35 -12
- package/dist/components/features/settings/TaxonomyManager.js +59 -27
- package/dist/components/features/settings/TypeManager.d.ts +11 -0
- package/dist/components/features/settings/TypeManager.js +48 -11
- package/dist/components/features/settings/{WorkflowEditorPrototype.d.ts → WorkflowEditor.d.ts} +2 -2
- package/dist/components/features/settings/{WorkflowEditorPrototype.js → WorkflowEditor.js} +3 -3
- package/dist/components/task/TaskActionHeader.d.ts +12 -2
- package/dist/components/task/TaskActionHeader.js +64 -8
- package/dist/components/task/TaskActionHeader.test.js +73 -0
- package/dist/components/task/TaskCard.d.ts +14 -16
- package/dist/components/task/TaskCard.js +144 -174
- package/dist/components/task/TaskCard.test.js +416 -64
- package/dist/components/task/TaskContextUpload.d.ts +6 -5
- package/dist/components/task/TaskContextUpload.js +199 -64
- package/dist/components/task/TaskContextUpload.test.js +331 -14
- package/dist/components/task/TaskForm.d.ts +23 -29
- package/dist/components/task/TaskForm.js +348 -169
- package/dist/components/task/TaskForm.test.js +419 -23
- package/dist/components/task/TaskKanban.d.ts +20 -21
- package/dist/components/task/TaskKanban.js +176 -316
- package/dist/components/task/TaskKanban.planning-drop.test.js +93 -0
- package/dist/components/task/TaskList.d.ts +22 -11
- package/dist/components/task/TaskList.js +98 -12
- package/dist/components/task/TaskList.test.js +206 -7
- package/dist/components/task/TaskReferenceBadge.d.ts +12 -0
- package/dist/components/task/TaskReferenceBadge.js +5 -0
- package/dist/components/task/TaskStatusActions.d.ts +12 -0
- package/dist/components/task/TaskStatusActions.js +18 -0
- package/dist/components/task/TaskStatusActions.test.js +45 -0
- package/dist/components/ui/ImageReferenceBadge.d.ts +12 -0
- package/dist/components/ui/ImageReferenceBadge.js +5 -0
- package/dist/components/ui/LevelSelector.d.ts +2 -1
- package/dist/components/ui/LevelSelector.js +2 -2
- package/dist/components/ui/Markdown.d.ts +1 -2
- package/dist/components/ui/Markdown.js +2 -13
- package/dist/components/ui/Modal.d.ts +3 -2
- package/dist/components/ui/Modal.js +4 -3
- package/dist/components/ui/MultiSelectFilter.d.ts +3 -1
- package/dist/components/ui/MultiSelectFilter.js +2 -2
- package/dist/components/ui/ReferenceBadgeButton.d.ts +13 -0
- package/dist/components/ui/ReferenceBadgeButton.js +6 -0
- package/dist/components/ui/TaxonomyDropdown.d.ts +7 -1
- package/dist/components/ui/TaxonomyDropdown.js +58 -23
- package/dist/components/ui/TopNoticeLayer.d.ts +7 -0
- package/dist/components/ui/TopNoticeLayer.js +14 -0
- package/dist/components/ui/TopNoticeLayer.test.js +25 -0
- package/dist/components/views/AppShellHeader.d.ts +13 -0
- package/dist/components/views/AppShellHeader.js +19 -0
- package/dist/components/views/AppShellHeader.test.js +21 -0
- package/dist/components/views/PlanComparisonPage.d.ts +73 -0
- package/dist/components/views/PlanComparisonPage.js +196 -0
- package/dist/components/views/PlanComparisonPage.test.js +251 -0
- package/dist/components/views/PlansPage.d.ts +14 -0
- package/dist/components/views/PlansPage.js +355 -0
- package/dist/components/views/StandaloneLayout.d.ts +2 -2
- package/dist/components/views/StandaloneLayout.js +2212 -1194
- package/dist/components/views/WidgetView.d.ts +2 -2
- package/dist/components/views/WidgetView.js +149 -43
- package/dist/components/views/chrome/WorkspaceChromeSections.d.ts +57 -0
- package/dist/components/views/chrome/WorkspaceChromeSections.js +38 -0
- package/dist/components/views/chrome/WorkspaceChromeSections.test.js +54 -0
- package/dist/components/views/chrome/workspaceChrome.d.ts +31 -0
- package/dist/components/views/chrome/workspaceChrome.js +108 -0
- package/dist/components/views/chrome/workspaceChrome.test.js +52 -0
- package/dist/components/views/panels/DocumentFilterToolbar.d.ts +10 -0
- package/dist/components/views/panels/DocumentFilterToolbar.js +7 -0
- package/dist/components/views/panels/DocumentFilterToolbar.test.js +19 -0
- package/dist/components/views/panels/FilterToolbar.d.ts +66 -0
- package/dist/components/views/panels/FilterToolbar.js +21 -0
- package/dist/components/views/panels/FilterToolbar.test.d.ts +1 -0
- package/dist/components/views/panels/FilterToolbar.test.js +45 -0
- package/dist/components/views/panels/FilterToolbarControls.d.ts +46 -0
- package/dist/components/views/panels/FilterToolbarControls.js +61 -0
- package/dist/components/views/panels/PlanningDrawer.d.ts +115 -0
- package/dist/components/views/panels/PlanningDrawer.js +220 -0
- package/dist/components/views/panels/ScheduleSidebar.d.ts +52 -0
- package/dist/components/views/panels/ScheduleSidebar.js +127 -0
- package/dist/components/views/panels/scheduleUtils.d.ts +14 -0
- package/dist/components/views/panels/scheduleUtils.js +79 -0
- package/dist/components/views/teamManagementAccess.d.ts +6 -0
- package/dist/components/views/teamManagementAccess.js +18 -0
- package/dist/components/views/teamManagementAccess.test.d.ts +1 -0
- package/dist/components/views/teamManagementAccess.test.js +44 -0
- package/dist/config/clientDeployment.d.ts +2 -0
- package/dist/config/clientDeployment.js +13 -0
- package/dist/config/cloudEnvironment.d.ts +15 -0
- package/dist/config/cloudEnvironment.js +60 -0
- package/dist/config/deployment.d.ts +20 -0
- package/dist/config/deployment.js +67 -0
- package/dist/config/deployment.test.d.ts +1 -0
- package/dist/config/deployment.test.js +88 -0
- package/dist/config/envSchema.js +36 -8
- package/dist/config/envSchema.test.js +28 -0
- package/dist/core/AiProfileService.d.ts +66 -0
- package/dist/core/AiProfileService.js +320 -0
- package/dist/core/AiProfileService.test.d.ts +1 -0
- package/dist/core/AiProfileService.test.js +164 -0
- package/dist/core/AiProfiles.test.d.ts +1 -0
- package/dist/core/AiProfiles.test.js +449 -0
- package/dist/core/AttachmentLinkService.d.ts +15 -0
- package/dist/core/AttachmentLinkService.js +157 -0
- package/dist/core/AuthTokenService.d.ts +44 -0
- package/dist/core/AuthTokenService.js +207 -0
- package/dist/core/CreatedBy.test.js +134 -6
- package/dist/core/DeletedTaskLifecycleService.d.ts +33 -0
- package/dist/core/DeletedTaskLifecycleService.js +158 -0
- package/dist/core/DeletedTaskTrash.test.d.ts +1 -0
- package/dist/core/DeletedTaskTrash.test.js +104 -0
- package/dist/core/EntitlementsPolicy.test.js +78 -5
- package/dist/core/GlobalSettingsService.d.ts +16 -0
- package/dist/core/GlobalSettingsService.js +370 -0
- package/dist/core/JsonBackupRuntime.test.d.ts +1 -0
- package/dist/core/JsonBackupRuntime.test.js +155 -0
- package/dist/core/McpTokenService.d.ts +118 -0
- package/dist/core/McpTokenService.js +921 -0
- package/dist/core/PlanEntitlementService.d.ts +201 -0
- package/dist/core/PlanEntitlementService.js +1442 -0
- package/dist/core/PlanVersionPolicy.test.d.ts +1 -0
- package/dist/core/PlanVersionPolicy.test.js +178 -0
- package/dist/core/PlanningEntities.test.d.ts +1 -0
- package/dist/core/PlanningEntities.test.js +95 -0
- package/dist/core/ScheduleFields.test.js +15 -19
- package/dist/core/SignupMonetizationSettings.test.d.ts +1 -0
- package/dist/core/SignupMonetizationSettings.test.js +159 -0
- package/dist/core/Stats.test.d.ts +1 -0
- package/dist/core/Stats.test.js +36 -0
- package/dist/core/SyncReconciliationService.d.ts +93 -0
- package/dist/core/SyncReconciliationService.js +406 -0
- package/dist/core/SystemAdmin.test.js +578 -13
- package/dist/core/TaskActivityService.d.ts +21 -0
- package/dist/core/TaskActivityService.js +130 -0
- package/dist/core/TaskAttachmentsCanonical.test.d.ts +1 -0
- package/dist/core/TaskAttachmentsCanonical.test.js +306 -0
- package/dist/core/TaskAuditTimeline.test.d.ts +1 -0
- package/dist/core/TaskAuditTimeline.test.js +132 -0
- package/dist/core/TaskTaxonomyValidation.test.js +338 -15
- package/dist/core/Taskforce.d.ts +930 -183
- package/dist/core/Taskforce.ids.test.js +252 -0
- package/dist/core/Taskforce.js +3848 -2532
- package/dist/core/Taskforce.mcpAuth.test.d.ts +1 -0
- package/dist/core/Taskforce.mcpAuth.test.js +343 -0
- package/dist/core/Taskforce.realtimeMutation.test.js +57 -2
- package/dist/core/TaxonomySettingsService.d.ts +18 -0
- package/dist/core/TaxonomySettingsService.js +162 -0
- package/dist/core/WorkspaceDelete.test.js +32 -13
- package/dist/core/WorkspaceLifecycleService.d.ts +11 -0
- package/dist/core/WorkspaceLifecycleService.js +88 -0
- package/dist/core/WorkspacePermissions.test.js +95 -0
- package/dist/core/WorkspacePlanMode.test.js +114 -1
- package/dist/core/WorkspacePreferenceService.d.ts +41 -0
- package/dist/core/WorkspacePreferenceService.js +246 -0
- package/dist/core/WorkspaceSyncSettings.test.d.ts +1 -0
- package/dist/core/WorkspaceSyncSettings.test.js +65 -0
- package/dist/core/__tests__/TaskAttachmentsCanonical.test.d.ts +1 -0
- package/dist/core/__tests__/TaskAttachmentsCanonical.test.js +212 -0
- package/dist/core/shared.d.ts +36 -0
- package/dist/core/shared.js +128 -0
- package/dist/core/types.d.ts +614 -0
- package/dist/core/types.js +27 -0
- package/dist/documentReviews/DocumentReviewCommentStore.d.ts +56 -0
- package/dist/documentReviews/DocumentReviewCommentStore.js +230 -0
- package/dist/documentReviews/DocumentReviewSessionStore.d.ts +52 -0
- package/dist/documentReviews/DocumentReviewSessionStore.js +193 -0
- package/dist/documentReviews/DocumentReviewSessionStore.test.d.ts +1 -0
- package/dist/documentReviews/DocumentReviewSessionStore.test.js +127 -0
- package/dist/documentReviews/service.d.ts +68 -0
- package/dist/documentReviews/service.js +210 -0
- package/dist/documentReviews/types.d.ts +58 -0
- package/dist/documentReviews/types.js +1 -0
- package/dist/hooks/auth/useAuthGuardPolicy.d.ts +2 -0
- package/dist/hooks/auth/useAuthGuardPolicy.js +1 -0
- package/dist/hooks/tasks/useCurrentTaskRelations.d.ts +15 -0
- package/dist/hooks/tasks/useCurrentTaskRelations.js +37 -0
- package/dist/hooks/tasks/useTaskActions.d.ts +3 -0
- package/dist/hooks/tasks/useTaskActions.js +2 -0
- package/dist/hooks/tasks/useTaskEditorNavigation.d.ts +65 -0
- package/dist/hooks/tasks/useTaskEditorNavigation.js +235 -0
- package/dist/hooks/tasks/useTaskFilters.d.ts +2 -0
- package/dist/hooks/tasks/useTaskFilters.js +2 -0
- package/dist/hooks/tasks/useTaskFormActions.d.ts +58 -0
- package/dist/hooks/tasks/useTaskFormActions.js +365 -0
- package/dist/hooks/tasks/useTaskRelationships.d.ts +16 -0
- package/dist/hooks/tasks/useTaskRelationships.js +64 -0
- package/dist/hooks/ui/useResourceExport.d.ts +19 -0
- package/dist/hooks/ui/useResourceExport.js +84 -0
- package/dist/hooks/ui/useSettingsModel.d.ts +203 -0
- package/dist/hooks/ui/useSettingsModel.js +125 -0
- package/dist/hooks/ui/useSettingsPersistence.d.ts +36 -0
- package/dist/hooks/ui/useSettingsPersistence.js +254 -0
- package/dist/hooks/ui/useSettingsTaxonomyManagement.d.ts +119 -0
- package/dist/hooks/ui/useSettingsTaxonomyManagement.js +536 -0
- package/dist/hooks/ui/useUiNotice.d.ts +1 -0
- package/dist/hooks/ui/useUiNotice.js +1 -0
- package/dist/hooks/ui/useWorkflowTemplates.d.ts +37 -0
- package/dist/hooks/ui/useWorkflowTemplates.js +111 -0
- package/dist/hooks/ui/useZenMode.d.ts +5 -0
- package/dist/hooks/ui/useZenMode.js +32 -0
- package/dist/hooks/useFilterSort.d.ts +60 -0
- package/dist/hooks/useFilterSort.js +362 -0
- package/dist/hooks/useFilterSort.test.d.ts +1 -0
- package/dist/hooks/useFilterSort.test.js +333 -0
- package/dist/hooks/useRealtimeSync.d.ts +1 -0
- package/dist/hooks/useRealtimeSync.js +24 -9
- package/dist/hooks/useRealtimeSync.test.js +28 -1
- package/dist/hooks/useSyncOrchestrator.aiProfiles.test.d.ts +1 -0
- package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +34 -0
- package/dist/hooks/useSyncOrchestrator.d.ts +65 -103
- package/dist/hooks/useSyncOrchestrator.js +1538 -670
- package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +700 -174
- package/dist/hooks/useTaskData.d.ts +35 -0
- package/dist/hooks/useTaskData.js +239 -0
- package/dist/hooks/useTaskData.test.d.ts +1 -0
- package/dist/hooks/useTaskData.test.js +119 -0
- package/dist/hooks/useTaskMutations.d.ts +46 -0
- package/dist/hooks/useTaskMutations.js +472 -0
- package/dist/hooks/useTaskMutations.test.d.ts +1 -0
- package/dist/hooks/useTaskMutations.test.js +80 -0
- package/dist/hooks/useTaskforce.contract.test.d.ts +1 -0
- package/dist/hooks/useTaskforce.contract.test.js +7 -0
- package/dist/hooks/useTaskforce.d.ts +260 -295
- package/dist/hooks/useTaskforce.js +1954 -2623
- package/dist/hooks/useTaskforce.priority-filters.test.js +6 -11
- package/dist/hooks/useTaskforce.sync-behavior.test.d.ts +1 -0
- package/dist/hooks/useTaskforce.sync-behavior.test.js +1120 -0
- package/dist/hooks/useUiNotice.d.ts +16 -0
- package/dist/hooks/useUiNotice.js +49 -0
- package/dist/hooks/useWorkspaceSyncController.d.ts +23 -46
- package/dist/hooks/useWorkspaceSyncController.js +280 -461
- package/dist/hooks/useWorkspaceSyncController.test.js +106 -199
- package/dist/hooks/workspace/useTaskforceApiRouting.d.ts +8 -0
- package/dist/hooks/workspace/useTaskforceApiRouting.js +91 -0
- package/dist/hooks/workspace/useTaskforceApiRouting.test.d.ts +1 -0
- package/dist/hooks/workspace/useTaskforceApiRouting.test.js +60 -0
- package/dist/hooks/workspace/useWorkspaceSyncController.d.ts +1 -0
- package/dist/hooks/workspace/useWorkspaceSyncController.js +1 -0
- package/dist/hooks/workspace/workspaceLocalState.d.ts +30 -0
- package/dist/hooks/workspace/workspaceLocalState.js +101 -0
- package/dist/localization/locales/en-US.d.ts +1 -8
- package/dist/localization/locales/en-US.js +4 -11
- package/dist/localization/locales/es-419.js +2 -9
- package/dist/localization/locales/pt-BR.js +2 -9
- package/dist/localization/localizationCatalogs.test.d.ts +1 -0
- package/dist/localization/localizationCatalogs.test.js +37 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.js +9 -15
- package/dist/mcp/clientIntegrations.d.ts +33 -0
- package/dist/mcp/clientIntegrations.js +199 -0
- package/dist/mcp/clientIntegrations.test.d.ts +1 -0
- package/dist/mcp/clientIntegrations.test.js +110 -0
- package/dist/mcp/index.d.ts +2 -0
- package/dist/mcp/index.js +2 -0
- package/dist/mcp/optionResolution.test.js +6 -2
- package/dist/mcp/runtime.d.ts +120 -0
- package/dist/mcp/runtime.js +5668 -0
- package/dist/mcp/runtime.test.d.ts +1 -0
- package/dist/mcp/runtime.test.js +3293 -0
- package/dist/mcp/server.js +2 -1793
- package/dist/mcp/structuredCommentValidation.test.d.ts +1 -0
- package/dist/{__tests__ → mcp}/structuredCommentValidation.test.js +1 -1
- package/dist/mcp/structuredDocValidation.js +1 -2
- package/dist/mcp/structuredDocValidation.test.d.ts +1 -0
- package/dist/{__tests__ → mcp}/structuredDocValidation.test.js +9 -4
- package/dist/mcp/toolRegistry.d.ts +570 -0
- package/dist/mcp/toolRegistry.js +90 -0
- package/dist/mcp/toolRegistry.test.d.ts +1 -0
- package/dist/mcp/toolRegistry.test.js +30 -0
- package/dist/migrations/billingSchemaParity.test.js +111 -0
- package/dist/migrations/taskSchemaMigrations.d.ts +5 -0
- package/dist/migrations/taskSchemaMigrations.js +681 -39
- package/dist/migrations/taskSchemaMigrations.test.d.ts +1 -0
- package/dist/migrations/taskSchemaMigrations.test.js +210 -0
- package/dist/plugins/vite.js +13 -7
- package/dist/public/apple-touch-icon.png +0 -0
- package/dist/public/archive/phoenix/apple-touch-icon.png +0 -0
- package/dist/public/archive/phoenix/favicon.ico +0 -0
- package/dist/public/archive/phoenix/site.webmanifest +1 -0
- package/dist/public/favicon-96x96.png +0 -0
- package/dist/public/favicon.ico +0 -0
- package/dist/public/favicon.svg +17 -0
- package/dist/public/site.webmanifest +21 -1
- package/dist/public/web-app-manifest-192x192.png +0 -0
- package/dist/public/web-app-manifest-512x512.png +0 -0
- package/dist/releaseVersion.test.d.ts +1 -0
- package/dist/{__tests__/releaseVersion.test.js → releaseVersion.test.js} +1 -1
- package/dist/resources/templates/WORKFLOW_V2_POLICY.md +1 -1
- package/dist/resources/templates/workflow-sources/workflowDocs.mjs +62 -52
- package/dist/resources/templates/workflows/collaborate.yaml +11 -5
- package/dist/resources/templates/workflows/do.yaml +8 -2
- package/dist/resources/templates/workflows/evaluate.yaml +13 -7
- package/dist/resources/templates/workflows/execute.yaml +40 -23
- package/dist/resources/templates/workflows/plan.yaml +15 -8
- package/dist/resources/templates/workflows/review.yaml +14 -8
- package/dist/runtime/appGateDefinitions.d.ts +32 -0
- package/dist/runtime/appGateDefinitions.js +32 -0
- package/dist/runtime/appGates.d.ts +29 -0
- package/dist/runtime/appGates.js +53 -0
- package/dist/runtime/appGates.test.d.ts +1 -0
- package/dist/runtime/appGates.test.js +42 -0
- package/dist/runtime/migrationFlags.d.ts +1 -0
- package/dist/runtime/migrationFlags.js +1 -0
- package/dist/server/annotatedAttachmentsRoutes.test.d.ts +1 -0
- package/dist/server/annotatedAttachmentsRoutes.test.js +473 -0
- package/dist/server/auth.js +14 -2
- package/dist/server/auth.test.js +21 -1
- package/dist/server/cors.js +11 -5
- package/dist/server/cors.test.js +6 -0
- package/dist/server/documentReviewRoutes.test.d.ts +1 -0
- package/dist/server/documentReviewRoutes.test.js +157 -0
- package/dist/server/index.cookieProxy.test.js +46 -1
- package/dist/server/index.d.ts +20 -0
- package/dist/server/index.js +168 -41
- package/dist/server/index.rateLimit.test.js +6 -0
- package/dist/server/index.test.js +133 -2
- package/dist/server/mockStripe.d.ts +72 -0
- package/dist/server/mockStripe.js +357 -0
- package/dist/server/realtimeSyncWs.js +4 -0
- package/dist/server/routes/admin.d.ts +114 -0
- package/dist/server/routes/admin.js +2226 -0
- package/dist/server/routes/annotatedAttachments.d.ts +24 -0
- package/dist/server/routes/annotatedAttachments.js +235 -0
- package/dist/server/routes/auth.d.ts +61 -0
- package/dist/server/routes/auth.js +1296 -0
- package/dist/server/{routes.billing.d.ts → routes/billing.d.ts} +3 -2
- package/dist/server/routes/billing.js +2001 -0
- package/dist/server/routes/billing.test.d.ts +1 -0
- package/dist/server/routes/billing.test.js +1631 -0
- package/dist/server/routes/documentReviews.d.ts +11 -0
- package/dist/server/routes/documentReviews.js +191 -0
- package/dist/server/routes/documents.d.ts +118 -0
- package/dist/server/routes/documents.js +1113 -0
- package/dist/server/routes/resources.d.ts +25 -0
- package/dist/server/routes/resources.js +225 -0
- package/dist/server/routes/shared.d.ts +35 -0
- package/dist/server/routes/shared.js +305 -0
- package/dist/server/routes/shared.test.d.ts +1 -0
- package/dist/server/routes/shared.test.js +32 -0
- package/dist/server/{routes.sync.d.ts → routes/sync.d.ts} +5 -5
- package/dist/server/routes/sync.integration.test.d.ts +1 -0
- package/dist/server/routes/sync.integration.test.js +2003 -0
- package/dist/server/routes/sync.js +3143 -0
- package/dist/server/routes/tasks.d.ts +72 -0
- package/dist/server/routes/tasks.js +1252 -0
- package/dist/server/routes/workspaces.d.ts +32 -0
- package/dist/server/routes/workspaces.js +307 -0
- package/dist/server/routes.d.ts +8 -9
- package/dist/server/routes.js +968 -4092
- package/dist/server/routes.test.js +9043 -2415
- package/dist/server/runtimeMode.d.ts +1 -1
- package/dist/server/runtimeMode.js +3 -18
- package/dist/server/runtimeMode.test.js +3 -3
- package/dist/server/securityHeaders.d.ts +1 -1
- package/dist/server/securityHeaders.js +65 -6
- package/dist/server/securityHeaders.test.js +40 -2
- package/dist/services/templateEngine.test.d.ts +1 -0
- package/dist/{__tests__ → services}/templateEngine.test.js +1 -1
- package/dist/services/templates.test.d.ts +1 -0
- package/dist/{__tests__ → services}/templates.test.js +1 -1
- package/dist/services/workflowDocumentFixtures.test.d.ts +1 -0
- package/dist/{__tests__ → services}/workflowDocumentFixtures.test.js +4 -4
- package/dist/services/workflowExportMatrix.test.d.ts +1 -0
- package/dist/{__tests__ → services}/workflowExportMatrix.test.js +1 -1
- package/dist/services/workflowExportSnapshots.test.d.ts +1 -0
- package/dist/services/workflowGeneration.test.d.ts +1 -0
- package/dist/services/workflowSimulation.test.d.ts +1 -0
- package/dist/services/workflowSimulation.test.js +113 -0
- package/dist/services/workflowV2Policy.test.d.ts +1 -0
- package/dist/{__tests__ → services}/workflowV2Policy.test.js +2 -2
- package/dist/shared/aiProfileSurfaceType.d.ts +9 -0
- package/dist/shared/aiProfileSurfaceType.js +49 -0
- package/dist/shared/customTaxonomyLibrary.d.ts +11 -0
- package/dist/shared/customTaxonomyLibrary.js +276 -0
- package/dist/shared/customTaxonomyLibrary.test.d.ts +1 -0
- package/dist/shared/customTaxonomyLibrary.test.js +20 -0
- package/dist/shared/taxonomyCatalog.d.ts +19 -0
- package/dist/shared/taxonomyCatalog.js +36 -0
- package/dist/shared/taxonomyDefaults.d.ts +29 -0
- package/dist/shared/taxonomyDefaults.js +26 -0
- package/dist/shared/taxonomyLibrary.d.ts +15 -0
- package/dist/shared/taxonomyLibrary.js +98 -0
- package/dist/shared/taxonomyLibrary.test.d.ts +1 -0
- package/dist/shared/taxonomyLibrary.test.js +26 -0
- package/dist/shared/taxonomyState.d.ts +36 -0
- package/dist/shared/taxonomyState.js +73 -0
- package/dist/shared/taxonomyState.test.d.ts +1 -0
- package/dist/shared/taxonomyState.test.js +71 -0
- package/dist/shared/workflowDefaults.d.ts +9 -0
- package/dist/shared/workflowDefaults.js +11 -0
- package/dist/storage/documentIntegrity.d.ts +2 -0
- package/dist/storage/documentIntegrity.js +34 -17
- package/dist/storage/documentPurge.d.ts +2 -1
- package/dist/storage/documentPurge.js +35 -8
- package/dist/storage/index.d.ts +4 -0
- package/dist/storage/index.js +2 -0
- package/dist/storage/objectStorage.d.ts +1 -1
- package/dist/storage/objectStorageClient.d.ts +6 -4
- package/dist/storage/objectStorageClient.js +77 -29
- package/dist/storage/objectStorageClient.test.d.ts +1 -0
- package/dist/storage/objectStorageClient.test.js +57 -0
- package/dist/storage/objectStorageConfig.js +3 -1
- package/dist/storage/objectStorageConfig.test.d.ts +1 -0
- package/dist/storage/objectStorageConfig.test.js +38 -0
- package/dist/storage/postgresAdapter.d.ts +5 -0
- package/dist/storage/postgresAdapter.js +2 -2
- package/dist/storage/postgresAdapter.test.d.ts +1 -0
- package/dist/storage/postgresAdapter.test.js +29 -0
- package/dist/storage/taskAssetStore.d.ts +7 -4
- package/dist/storage/taskAssetStore.js +65 -60
- package/dist/storage/workspaceAssetStore.d.ts +122 -0
- package/dist/storage/workspaceAssetStore.js +496 -0
- package/dist/storage/workspaceAssetStore.test.d.ts +1 -0
- package/dist/storage/workspaceAssetStore.test.js +501 -0
- package/dist/sync/cloudSyncApi.d.ts +33 -2
- package/dist/sync/cloudSyncApi.js +37 -15
- package/dist/sync/cloudSyncApi.test.js +60 -3
- package/dist/sync/index.d.ts +2 -0
- package/dist/sync/index.js +3 -0
- package/dist/sync/syncService.d.ts +25 -0
- package/dist/sync/syncService.js +184 -16
- package/dist/sync/syncService.test.js +289 -25
- package/dist/sync/workspaceRepair.d.ts +114 -0
- package/dist/sync/workspaceRepair.js +566 -0
- package/dist/sync/workspaceSyncModel.d.ts +230 -2
- package/dist/sync/workspaceSyncModel.js +456 -17
- package/dist/sync/workspaceSyncModel.test.js +642 -0
- package/dist/sync/workspaceSyncState.d.ts +12 -0
- package/dist/sync/workspaceSyncState.js +12 -0
- package/dist/sync/workspaceSyncSurface.d.ts +33 -0
- package/dist/sync/workspaceSyncSurface.js +74 -0
- package/dist/types.d.ts +143 -18
- package/dist/types.js +9 -24
- package/dist/ui/assets/AgentsModule-TVmCgizS.js +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-CAyhnPeR.js +3 -0
- package/dist/ui/assets/DocumentWorkspace-BOCw5e4D.js +250 -0
- package/dist/ui/assets/DocumentWorkspace-C_8T8oz-.css +1 -0
- package/dist/ui/assets/InitiativesModule-CN0r02Oi.js +1 -0
- package/dist/ui/assets/PlansPage-BlVC_lRq.css +1 -0
- package/dist/ui/assets/PlansPage-FcQSNLZd.js +1 -0
- package/dist/ui/assets/TaskSettings-BwB9NtmJ.css +1 -0
- package/dist/ui/assets/TaskSettings-Cw5zYD1L.js +8 -0
- package/dist/ui/assets/WorkflowsModule-CY9R2zPB.js +5 -0
- package/dist/ui/assets/index-Bzqy5QGm.js +6 -0
- package/dist/ui/assets/index-DxRiI3tY.css +1 -0
- package/dist/ui/assets/vendor-dnd-DRzYolkg.js +5 -0
- package/dist/ui/assets/{vendor-icons-ZFG3SGwo.js → vendor-icons-QZyhEwgT.js} +1 -1
- package/dist/ui/assets/{vendor-markdown-CKYkQHfj.js → vendor-markdown-BUxTU7dS.js} +1 -1
- package/dist/ui/assets/vendor-react-CKJs5o3c.js +61 -0
- package/dist/ui/assets/vendor-router-BbWMxlnO.js +3 -0
- package/dist/ui/branding/logos/logo.png +0 -0
- package/dist/ui/branding/logos/logo_dark.svg +27 -0
- package/dist/ui/branding/logos/logo_favicon.svg +35 -0
- package/dist/ui/branding/logos/logo_light.svg +27 -0
- package/dist/ui/favicon/apple-touch-icon.png +0 -0
- package/dist/ui/favicon/archive/phoenix/apple-touch-icon.png +0 -0
- package/dist/ui/favicon/archive/phoenix/favicon.ico +0 -0
- package/dist/ui/favicon/archive/phoenix/site.webmanifest +1 -0
- package/dist/ui/favicon/favicon-96x96.png +0 -0
- package/dist/ui/favicon/favicon.ico +0 -0
- package/dist/ui/favicon/favicon.svg +17 -0
- package/dist/ui/favicon/site.webmanifest +21 -1
- package/dist/ui/favicon/web-app-manifest-192x192.png +0 -0
- package/dist/ui/favicon/web-app-manifest-512x512.png +0 -0
- package/dist/ui/index.html +10 -7
- package/dist/ui/product/screen_01.png +0 -0
- package/dist/ui/product/screen_02.png +0 -0
- package/dist/ui/product/screen_03.png +0 -0
- package/dist/utils/annotatedAttachments.d.ts +20 -0
- package/dist/utils/annotatedAttachments.js +74 -0
- package/dist/utils/annotatedAttachments.test.d.ts +1 -0
- package/dist/utils/annotatedAttachments.test.js +108 -0
- package/dist/utils/assignees.d.ts +26 -0
- package/dist/utils/assignees.js +132 -0
- package/dist/utils/canonicalAssetKind.d.ts +16 -0
- package/dist/utils/canonicalAssetKind.js +39 -0
- package/dist/utils/canonicalAssetKind.test.d.ts +1 -0
- package/dist/utils/canonicalAssetKind.test.js +24 -0
- package/dist/utils/coalescedRefresh.d.ts +5 -0
- package/dist/utils/coalescedRefresh.js +16 -0
- package/dist/utils/coalescedRefresh.test.d.ts +1 -0
- package/dist/utils/coalescedRefresh.test.js +30 -0
- package/dist/utils/constants.d.ts +16 -3
- package/dist/utils/constants.icons.test.js +2 -1
- package/dist/utils/constants.js +70 -13
- package/dist/utils/contextAssetEvents.d.ts +7 -0
- package/dist/utils/contextAssetEvents.js +6 -0
- package/dist/utils/contextFiles.d.ts +14 -3
- package/dist/utils/contextFiles.js +40 -8
- package/dist/utils/documentManagerApi.d.ts +6 -0
- package/dist/utils/documentManagerApi.js +19 -0
- package/dist/utils/documentNames.d.ts +24 -0
- package/dist/utils/documentNames.js +91 -0
- package/dist/utils/documentReferences.d.ts +9 -0
- package/dist/utils/documentReferences.js +11 -0
- package/dist/utils/entityReferences.d.ts +9 -0
- package/dist/utils/entityReferences.js +32 -0
- package/dist/utils/imageReferences.d.ts +9 -0
- package/dist/utils/imageReferences.js +11 -0
- package/dist/utils/planParser.d.ts +2 -2
- package/dist/utils/planParser.js +11 -11
- package/dist/utils/planParser.test.d.ts +1 -0
- package/dist/{__tests__ → utils}/planParser.test.js +22 -22
- package/dist/utils/planningReferences.d.ts +17 -0
- package/dist/utils/planningReferences.js +30 -0
- package/dist/utils/planningReferences.test.d.ts +1 -0
- package/dist/utils/planningReferences.test.js +17 -0
- package/dist/utils/taskActivity.d.ts +9 -0
- package/dist/utils/taskActivity.js +147 -0
- package/dist/utils/taskActivity.test.d.ts +1 -0
- package/dist/utils/taskActivity.test.js +34 -0
- package/dist/utils/taskDraftDefaults.d.ts +21 -0
- package/dist/utils/taskDraftDefaults.js +40 -0
- package/dist/utils/taskDraftDefaults.test.d.ts +1 -0
- package/dist/utils/taskDraftDefaults.test.js +34 -0
- package/dist/utils/taskNormalization.d.ts +25 -0
- package/dist/utils/taskNormalization.js +161 -0
- package/dist/utils/taskNormalization.test.d.ts +1 -0
- package/dist/utils/taskNormalization.test.js +158 -0
- package/dist/utils/taskReferences.d.ts +5 -0
- package/dist/utils/taskReferences.js +11 -0
- package/dist/utils/taskforceApiClient.d.ts +2 -0
- package/dist/utils/taskforceApiClient.js +101 -3
- package/dist/utils/taskforceApiClient.test.d.ts +1 -0
- package/dist/utils/taskforceApiClient.test.js +44 -0
- package/dist/utils/taxonomyFilterOptions.d.ts +2 -0
- package/dist/utils/taxonomyFilterOptions.js +17 -0
- package/dist/utils/taxonomyFormDefaults.d.ts +3 -0
- package/dist/utils/taxonomyFormDefaults.js +28 -0
- package/dist/utils/taxonomyFormDefaults.test.d.ts +1 -0
- package/dist/utils/taxonomyFormDefaults.test.js +63 -0
- package/dist/utils/taxonomyLifecycle.d.ts +3 -0
- package/dist/utils/taxonomyLifecycle.js +17 -0
- package/dist/utils/taxonomySorting.d.ts +7 -0
- package/dist/utils/taxonomySorting.js +74 -0
- package/dist/utils/theme.d.ts +15 -0
- package/dist/utils/theme.js +23 -0
- package/dist/utils/uiNotice.d.ts +7 -0
- package/dist/utils/uiNotice.js +6 -0
- package/dist/utils/uiNotice.test.d.ts +1 -0
- package/dist/utils/uiNotice.test.js +18 -0
- package/dist/utils/workspaceIdentity.d.ts +14 -0
- package/dist/utils/workspaceIdentity.js +21 -0
- package/dist/utils/workspaceIdentity.test.js +30 -1
- package/dist/utils/workspaceSyncPresentation.d.ts +20 -0
- package/dist/utils/workspaceSyncPresentation.js +21 -0
- package/dist/utils/workspaceSyncPresentation.test.d.ts +1 -0
- package/dist/utils/workspaceSyncPresentation.test.js +36 -0
- package/package.json +28 -23
- package/scripts/bootstrap-playwright-auth.mjs +155 -0
- package/scripts/check-compat-boundaries.mjs +41 -0
- package/scripts/check-env.ts +9 -2
- package/scripts/debug-login.mjs +32 -0
- package/scripts/migrate-planning-model.ts +233 -0
- package/scripts/migrate-task-data-assets.mjs +408 -0
- package/scripts/playwright-auth.sh +11 -0
- package/scripts/run-dev-proxy.sh +2 -0
- package/scripts/update-homebrew-formula.sh +20 -3
- package/scripts/with-esbuild.sh +11 -0
- package/src/resources/templates/WORKFLOW_V2_POLICY.md +1 -1
- package/src/resources/templates/workflow-sources/workflowDocs.mjs +62 -52
- package/src/resources/templates/workflows/collaborate.yaml +11 -5
- package/src/resources/templates/workflows/do.yaml +8 -2
- package/src/resources/templates/workflows/evaluate.yaml +13 -7
- package/src/resources/templates/workflows/execute.yaml +40 -23
- package/src/resources/templates/workflows/plan.yaml +15 -8
- package/src/resources/templates/workflows/review.yaml +14 -8
- package/dist/TaskforceScreenshot.d.ts +0 -11
- package/dist/TaskforceScreenshot.js +0 -113
- package/dist/compat/priorityCompat.d.ts +0 -2
- package/dist/compat/priorityCompat.js +0 -24
- package/dist/components/features/settings/TaxonomyManager 2.d.ts +0 -52
- package/dist/components/features/settings/TaxonomyManager 2.js +0 -75
- package/dist/components/task/TaskKanban 2.d.ts +0 -76
- package/dist/components/task/TaskKanban 2.js +0 -1004
- package/dist/components/task/TaskScreenshotSection.d.ts +0 -15
- package/dist/components/task/TaskScreenshotSection.js +0 -22
- package/dist/components/views/StandaloneLayout 2.d.ts +0 -8
- package/dist/components/views/StandaloneLayout 2.js +0 -1660
- package/dist/core/InitiativeTemplates.test.js +0 -50
- package/dist/core/ParentLifecycle.test.js +0 -98
- package/dist/migrations/clientMigrations.d.ts +0 -9
- package/dist/migrations/clientMigrations.js +0 -74
- package/dist/migrations/flags.d.ts +0 -6
- package/dist/migrations/flags.js +0 -8
- package/dist/migrations/taskMigrations.d.ts +0 -71
- package/dist/migrations/taskMigrations.js +0 -236
- package/dist/migrations/taskMigrations.test.js +0 -34
- package/dist/server/routes.billing.js +0 -991
- package/dist/server/routes.billing.test.js +0 -387
- package/dist/server/routes.sync.integration.test.js +0 -470
- package/dist/server/routes.sync.js +0 -1141
- package/dist/soak/syncSoakHarness.d.ts +0 -6
- package/dist/soak/syncSoakHarness.js +0 -10
- package/dist/ui/assets/index-0W5vyCpn.css +0 -1
- package/dist/ui/assets/index-MCZuNNfn.js +0 -23
- package/dist/ui/assets/logo_white_01-0Vx-iIIv.png +0 -0
- package/dist/ui/assets/vendor-dnd-BI1K77C1.js +0 -5
- package/dist/ui/assets/vendor-react-DdIDsh7f.js +0 -9
- package/dist/ui/assets/vendor-router-BtiNU7Dl.js +0 -3
- package/dist/utils/taskHierarchy.d.ts +0 -4
- package/dist/utils/taskHierarchy.js +0 -69
- package/dist/utils/taskHierarchy.test.js +0 -38
- package/dist/utils/taskParenting.d.ts +0 -3
- package/dist/utils/taskParenting.js +0 -24
- package/dist/utils/taskParenting.test.js +0 -21
- package/dist/utils/taskRelations.d.ts +0 -6
- package/dist/utils/taskRelations.js +0 -24
- package/dist/utils/taskRelations.test.js +0 -34
- package/scripts/check-compat-boundaries.js +0 -48
- /package/dist/{__tests__/planParser.test.d.ts → TaskforceCore.filter-persistence.test.d.ts} +0 -0
- /package/dist/{__tests__/releaseVersion.test.d.ts → TaskforceCore.routing.test.d.ts} +0 -0
- /package/dist/{__tests__/structuredCommentValidation.test.d.ts → annotatedAttachments/AnnotatedAttachmentSessionStore.test.d.ts} +0 -0
- /package/dist/{__tests__/structuredDocValidation.test.d.ts → annotatedAttachments/payload.test.d.ts} +0 -0
- /package/dist/{__tests__/templateEngine.test.d.ts → annotatedAttachments/types.js} +0 -0
- /package/dist/{__tests__/templates.test.d.ts → compat/workspaceSyncCompat.test.d.ts} +0 -0
- /package/dist/{__tests__/workflowDocumentFixtures.test.d.ts → components/features/AgentsModule.test.d.ts} +0 -0
- /package/dist/{__tests__/workflowExportMatrix.test.d.ts → components/features/AnnotatedAttachmentWorkspace.test.d.ts} +0 -0
- /package/dist/{__tests__/workflowExportSnapshots.test.d.ts → components/features/DocumentWorkspace.test.d.ts} +0 -0
- /package/dist/{__tests__/workflowGeneration.test.d.ts → components/features/settings/TaxonomyLibraryManager.test.d.ts} +0 -0
- /package/dist/{__tests__/workflowV2Policy.test.d.ts → components/task/TaskActionHeader.test.d.ts} +0 -0
- /package/dist/{core/InitiativeTemplates.test.d.ts → components/task/TaskKanban.planning-drop.test.d.ts} +0 -0
- /package/dist/{core/ParentLifecycle.test.d.ts → components/task/TaskStatusActions.test.d.ts} +0 -0
- /package/dist/{migrations/taskMigrations.test.d.ts → components/ui/TopNoticeLayer.test.d.ts} +0 -0
- /package/dist/{server/routes.billing.test.d.ts → components/views/AppShellHeader.test.d.ts} +0 -0
- /package/dist/{server/routes.sync.integration.test.d.ts → components/views/PlanComparisonPage.test.d.ts} +0 -0
- /package/dist/{utils/taskHierarchy.test.d.ts → components/views/chrome/WorkspaceChromeSections.test.d.ts} +0 -0
- /package/dist/{utils/taskParenting.test.d.ts → components/views/chrome/workspaceChrome.test.d.ts} +0 -0
- /package/dist/{utils/taskRelations.test.d.ts → components/views/panels/DocumentFilterToolbar.test.d.ts} +0 -0
- /package/dist/public/{android-chrome-192x192.png → archive/phoenix/android-chrome-192x192.png} +0 -0
- /package/dist/public/{android-chrome-512x512.png → archive/phoenix/android-chrome-512x512.png} +0 -0
- /package/dist/public/{favicon-16x16.png → archive/phoenix/favicon-16x16.png} +0 -0
- /package/dist/public/{favicon-32x32.png → archive/phoenix/favicon-32x32.png} +0 -0
- /package/dist/public/{favicon.png → archive/phoenix/favicon.png} +0 -0
- /package/dist/{__tests__ → services}/workflowExportSnapshots.test.js +0 -0
- /package/dist/{__tests__ → services}/workflowGeneration.test.js +0 -0
- /package/dist/ui/favicon/{android-chrome-192x192.png → archive/phoenix/android-chrome-192x192.png} +0 -0
- /package/dist/ui/favicon/{android-chrome-512x512.png → archive/phoenix/android-chrome-512x512.png} +0 -0
- /package/dist/ui/favicon/{favicon-16x16.png → archive/phoenix/favicon-16x16.png} +0 -0
- /package/dist/ui/favicon/{favicon-32x32.png → archive/phoenix/favicon-32x32.png} +0 -0
- /package/dist/ui/favicon/{favicon.png → archive/phoenix/favicon.png} +0 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
2
|
+
import { Readable, Writable } from 'stream';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { TaskforceCore } from '../core/Taskforce.js';
|
|
7
|
+
import { createRoutes, matchRoute } from './routes.js';
|
|
8
|
+
function createProjectRoot() {
|
|
9
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), 'taskforce-document-review-routes-'));
|
|
10
|
+
}
|
|
11
|
+
function createMockReq(method, url, body, headers) {
|
|
12
|
+
const req = new Readable();
|
|
13
|
+
req._read = () => { };
|
|
14
|
+
if (body === undefined) {
|
|
15
|
+
req.push(null);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
req.push(JSON.stringify(body));
|
|
19
|
+
req.push(null);
|
|
20
|
+
}
|
|
21
|
+
req.method = method;
|
|
22
|
+
req.url = url;
|
|
23
|
+
req.headers = headers || {};
|
|
24
|
+
return req;
|
|
25
|
+
}
|
|
26
|
+
function createMockRes() {
|
|
27
|
+
const bodyChunks = [];
|
|
28
|
+
const headers = new Map();
|
|
29
|
+
const res = new Writable({
|
|
30
|
+
write(chunk, _encoding, callback) {
|
|
31
|
+
bodyChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
|
|
32
|
+
callback();
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
res.statusCode = 200;
|
|
36
|
+
res.writeHead = ((statusCode, nextHeaders) => {
|
|
37
|
+
res.statusCode = statusCode;
|
|
38
|
+
if (nextHeaders) {
|
|
39
|
+
for (const [key, value] of Object.entries(nextHeaders)) {
|
|
40
|
+
headers.set(key.toLowerCase(), value);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return res;
|
|
44
|
+
});
|
|
45
|
+
res.setHeader = ((name, value) => {
|
|
46
|
+
headers.set(name.toLowerCase(), value);
|
|
47
|
+
});
|
|
48
|
+
res.getHeader = ((name) => headers.get(name.toLowerCase()));
|
|
49
|
+
const originalEnd = res.end.bind(res);
|
|
50
|
+
res.end = ((chunk) => {
|
|
51
|
+
if (chunk !== undefined) {
|
|
52
|
+
bodyChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
|
|
53
|
+
}
|
|
54
|
+
return originalEnd();
|
|
55
|
+
});
|
|
56
|
+
res.__getBody = () => Buffer.concat(bodyChunks).toString('utf8');
|
|
57
|
+
return res;
|
|
58
|
+
}
|
|
59
|
+
describe('document review routes', () => {
|
|
60
|
+
afterEach(() => {
|
|
61
|
+
// no-op
|
|
62
|
+
});
|
|
63
|
+
it('creates, lists, updates, and comments on document review sessions', async () => {
|
|
64
|
+
const projectRoot = createProjectRoot();
|
|
65
|
+
const core = new TaskforceCore({
|
|
66
|
+
projectRoot,
|
|
67
|
+
storagePath: path.join(projectRoot, '.taskforce'),
|
|
68
|
+
});
|
|
69
|
+
try {
|
|
70
|
+
core.createWorkspace({ workspaceId: 'workspace-1', name: 'Workspace 1' });
|
|
71
|
+
const now = new Date().toISOString();
|
|
72
|
+
core.db.prepare(`
|
|
73
|
+
INSERT INTO users (id, tenant_id, email, display_name, auth_provider, external_auth_id, beta_access, is_disabled, created_at, updated_at)
|
|
74
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
75
|
+
`).run('user-local-1', core.getTenantId(), 'local@example.com', 'Local User', 'local', 'user-local-1', 1, 0, now, now);
|
|
76
|
+
core.db.prepare(`
|
|
77
|
+
INSERT INTO workspace_memberships (id, tenant_id, workspace_id, user_id, role, status, created_at, updated_at)
|
|
78
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
79
|
+
`).run('membership-local-1', core.getTenantId(), 'workspace-1', 'user-local-1', 'owner', 'active', now, now);
|
|
80
|
+
const assetStore = core.getWorkspaceAssetStore();
|
|
81
|
+
assetStore.upsertAsset({
|
|
82
|
+
assetId: 'asset-doc-1',
|
|
83
|
+
workspaceId: 'workspace-1',
|
|
84
|
+
kind: 'document',
|
|
85
|
+
originalFilename: 'implementation-plan.md',
|
|
86
|
+
logicalName: 'Implementation Plan',
|
|
87
|
+
mimeType: 'text/markdown',
|
|
88
|
+
storageProvider: 'local',
|
|
89
|
+
storageKey: 'workspaces/workspace-1/assets/documents/asset-doc-1-implementation-plan.md',
|
|
90
|
+
contentSha256: 'sha-doc-1',
|
|
91
|
+
sizeBytes: 512,
|
|
92
|
+
documentId: 'doc-1',
|
|
93
|
+
version: 3,
|
|
94
|
+
});
|
|
95
|
+
const routes = createRoutes(core);
|
|
96
|
+
const createReq = createMockReq('POST', '/api/taskforce/document-reviews/sessions?workspaceId=workspace-1', {
|
|
97
|
+
assetId: 'asset-doc-1',
|
|
98
|
+
title: 'Review round 1',
|
|
99
|
+
}, { 'x-taskforce-user-id': 'user-local-1' });
|
|
100
|
+
const createRes = createMockRes();
|
|
101
|
+
await matchRoute('POST', '/api/taskforce/document-reviews/sessions', routes)?.handler(createReq, createRes, {});
|
|
102
|
+
expect(createRes.statusCode).toBe(200);
|
|
103
|
+
const created = JSON.parse(createRes.__getBody());
|
|
104
|
+
expect(created.session).toMatchObject({
|
|
105
|
+
assetId: 'asset-doc-1',
|
|
106
|
+
documentId: 'doc-1',
|
|
107
|
+
documentVersion: 3,
|
|
108
|
+
title: 'Review round 1',
|
|
109
|
+
status: 'open',
|
|
110
|
+
});
|
|
111
|
+
const sessionId = String(created.session.id);
|
|
112
|
+
const commentReq = createMockReq('POST', `/api/taskforce/document-reviews/sessions/${sessionId}/comments?workspaceId=workspace-1`, {
|
|
113
|
+
body: 'Please tighten the rollout section.',
|
|
114
|
+
anchor: { kind: 'line-range', startLine: 18, endLine: 24 },
|
|
115
|
+
}, { 'x-taskforce-user-id': 'user-local-1' });
|
|
116
|
+
const commentRes = createMockRes();
|
|
117
|
+
await matchRoute('POST', `/api/taskforce/document-reviews/sessions/${sessionId}/comments`, routes)?.handler(commentReq, commentRes, { id: sessionId });
|
|
118
|
+
expect(commentRes.statusCode).toBe(200);
|
|
119
|
+
const commented = JSON.parse(commentRes.__getBody());
|
|
120
|
+
expect(commented.session.comments).toHaveLength(1);
|
|
121
|
+
expect(commented.session.comments[0]).toMatchObject({
|
|
122
|
+
body: 'Please tighten the rollout section.',
|
|
123
|
+
anchor: { kind: 'line-range', startLine: 18, endLine: 24 },
|
|
124
|
+
authorActorId: 'user-local-1',
|
|
125
|
+
authorActor: expect.objectContaining({
|
|
126
|
+
id: 'user-local-1',
|
|
127
|
+
}),
|
|
128
|
+
});
|
|
129
|
+
const commentId = String(commented.session.comments[0].id);
|
|
130
|
+
const patchReq = createMockReq('PATCH', `/api/taskforce/document-reviews/sessions/${sessionId}/comments/${commentId}?workspaceId=workspace-1`, {
|
|
131
|
+
body: 'Please tighten the rollout and ownership sections.',
|
|
132
|
+
}, { 'x-taskforce-user-id': 'user-local-1' });
|
|
133
|
+
const patchRes = createMockRes();
|
|
134
|
+
await matchRoute('PATCH', `/api/taskforce/document-reviews/sessions/${sessionId}/comments/${commentId}`, routes)?.handler(patchReq, patchRes, { id: sessionId, commentId });
|
|
135
|
+
expect(patchRes.statusCode).toBe(200);
|
|
136
|
+
const patched = JSON.parse(patchRes.__getBody());
|
|
137
|
+
expect(patched.session.comments[0].body).toBe('Please tighten the rollout and ownership sections.');
|
|
138
|
+
const listReq = createMockReq('GET', '/api/taskforce/document-reviews/sessions?workspaceId=workspace-1&assetId=asset-doc-1');
|
|
139
|
+
const listRes = createMockRes();
|
|
140
|
+
await matchRoute('GET', '/api/taskforce/document-reviews/sessions', routes)?.handler(listReq, listRes, {});
|
|
141
|
+
expect(listRes.statusCode).toBe(200);
|
|
142
|
+
const listed = JSON.parse(listRes.__getBody());
|
|
143
|
+
expect(listed.sessions).toHaveLength(1);
|
|
144
|
+
expect(listed.sessions[0].id).toBe(sessionId);
|
|
145
|
+
const deleteCommentReq = createMockReq('DELETE', `/api/taskforce/document-reviews/sessions/${sessionId}/comments/${commentId}?workspaceId=workspace-1`, undefined, { 'x-taskforce-user-id': 'user-local-1' });
|
|
146
|
+
const deleteCommentRes = createMockRes();
|
|
147
|
+
await matchRoute('DELETE', `/api/taskforce/document-reviews/sessions/${sessionId}/comments/${commentId}`, routes)?.handler(deleteCommentReq, deleteCommentRes, { id: sessionId, commentId });
|
|
148
|
+
expect(deleteCommentRes.statusCode).toBe(200);
|
|
149
|
+
const afterDelete = JSON.parse(deleteCommentRes.__getBody());
|
|
150
|
+
expect(afterDelete.session.comments).toHaveLength(0);
|
|
151
|
+
}
|
|
152
|
+
finally {
|
|
153
|
+
core.close();
|
|
154
|
+
fs.rmSync(projectRoot, { recursive: true, force: true });
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { rewriteProxySetCookieForLocalHost, shouldRewriteSetCookieForLocalDevHost } from './index';
|
|
2
|
+
import { applyCloudProxyForwardedHeaders, resolveCloudProxyBaseUrl, resolveCloudProxyUpstreamBaseUrl, rewriteProxySetCookieForLocalHost, shouldProxyCloudPath, shouldRewriteSetCookieForLocalDevHost, TASKFORCE_PROXY_CLOUD_ENVIRONMENT_HEADER, TASKFORCE_PROXY_ORIGIN_BASE_URL_HEADER, TASKFORCE_PROXY_ORIGIN_HOST_HEADER, TASKFORCE_PROXY_ORIGIN_PROTO_HEADER, TASKFORCE_PROXY_ORIGIN_RUNTIME_HEADER } from './index';
|
|
3
3
|
describe('proxy cookie rewrite helpers', () => {
|
|
4
4
|
it('detects local dev hosts', () => {
|
|
5
5
|
expect(shouldRewriteSetCookieForLocalDevHost('localhost:5174')).toBe(true);
|
|
@@ -16,4 +16,49 @@ describe('proxy cookie rewrite helpers', () => {
|
|
|
16
16
|
expect(rewritten).toContain('SameSite=None');
|
|
17
17
|
expect(rewritten.toLowerCase()).not.toContain('domain=');
|
|
18
18
|
});
|
|
19
|
+
it('includes public pricing in the local cloud proxy path set', () => {
|
|
20
|
+
expect(shouldProxyCloudPath('/api/taskforce/public/pricing')).toBe(true);
|
|
21
|
+
expect(shouldProxyCloudPath('/api/taskforce/public/site-config')).toBe(true);
|
|
22
|
+
expect(shouldProxyCloudPath('/api/taskforce/public/site-config-script')).toBe(true);
|
|
23
|
+
expect(shouldProxyCloudPath('/api/taskforce/version')).toBe(true);
|
|
24
|
+
expect(shouldProxyCloudPath('/api/taskforce/account/entitlements')).toBe(true);
|
|
25
|
+
expect(shouldProxyCloudPath('/api/taskforce/admin/mcp-audit-logs')).toBe(true);
|
|
26
|
+
expect(shouldProxyCloudPath('/api/taskforce/billing/status')).toBe(true);
|
|
27
|
+
expect(shouldProxyCloudPath('/api/taskforce/billing/checkout-session')).toBe(true);
|
|
28
|
+
expect(shouldProxyCloudPath('/api/taskforce/auth/session')).toBe(true);
|
|
29
|
+
expect(shouldProxyCloudPath('/api/taskforce/workspace/assignee-options')).toBe(false);
|
|
30
|
+
expect(shouldProxyCloudPath('/api/taskforce/settings/mcp/tokens')).toBe(true);
|
|
31
|
+
expect(shouldProxyCloudPath('/api/taskforce/settings/mcp/test-connection')).toBe(true);
|
|
32
|
+
expect(shouldProxyCloudPath('/api/platform/plans')).toBe(true);
|
|
33
|
+
expect(shouldProxyCloudPath('/api/taskforce/sync/workspace/apply-local')).toBe(false);
|
|
34
|
+
expect(shouldProxyCloudPath('/api/taskforce/sync/workspace/documents')).toBe(false);
|
|
35
|
+
expect(shouldProxyCloudPath('/api/taskforce/sync/workspace/assets')).toBe(false);
|
|
36
|
+
expect(shouldProxyCloudPath('/api/taskforce/sync/events')).toBe(false);
|
|
37
|
+
expect(shouldProxyCloudPath('/api/taskforce/auth/runtime-config')).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
it('defaults local cloud proxy base url to production when no env is configured', () => {
|
|
40
|
+
expect(resolveCloudProxyBaseUrl({})).toBe('https://app.taskforcehq.ai');
|
|
41
|
+
});
|
|
42
|
+
it('allows proxied requests to override the upstream environment per request', () => {
|
|
43
|
+
const req = {
|
|
44
|
+
headers: {
|
|
45
|
+
[TASKFORCE_PROXY_CLOUD_ENVIRONMENT_HEADER]: 'performance'
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
expect(resolveCloudProxyUpstreamBaseUrl(req, 'https://app.taskforcehq.ai')).toBe('https://performance-app.taskforcehq.ai');
|
|
49
|
+
expect(resolveCloudProxyUpstreamBaseUrl({ headers: {} }, 'https://app.taskforcehq.ai')).toBe('https://app.taskforcehq.ai');
|
|
50
|
+
});
|
|
51
|
+
it('preserves the original local host and protocol for proxied cloud requests', () => {
|
|
52
|
+
const headers = new Headers();
|
|
53
|
+
applyCloudProxyForwardedHeaders(headers, {
|
|
54
|
+
headers: { host: 'localhost:5174' },
|
|
55
|
+
socket: { encrypted: false }
|
|
56
|
+
});
|
|
57
|
+
expect(headers.get('x-forwarded-host')).toBe('localhost:5174');
|
|
58
|
+
expect(headers.get('x-forwarded-proto')).toBe('http');
|
|
59
|
+
expect(headers.get(TASKFORCE_PROXY_ORIGIN_HOST_HEADER)).toBe('localhost:5174');
|
|
60
|
+
expect(headers.get(TASKFORCE_PROXY_ORIGIN_PROTO_HEADER)).toBe('http');
|
|
61
|
+
expect(headers.get(TASKFORCE_PROXY_ORIGIN_BASE_URL_HEADER)).toBe('http://localhost:5174');
|
|
62
|
+
expect(headers.get(TASKFORCE_PROXY_ORIGIN_RUNTIME_HEADER)).toBe('local-proxy');
|
|
63
|
+
});
|
|
19
64
|
});
|
package/dist/server/index.d.ts
CHANGED
|
@@ -5,13 +5,33 @@
|
|
|
5
5
|
* Serves pre-built static UI and provides API endpoints.
|
|
6
6
|
*/
|
|
7
7
|
import * as http from 'http';
|
|
8
|
+
import { TaskforceCore } from '../core/Taskforce.js';
|
|
9
|
+
import type { RequestAccessContext } from './auth.js';
|
|
8
10
|
export interface StandaloneServerOptions {
|
|
9
11
|
projectRoot: string;
|
|
10
12
|
port: number;
|
|
11
13
|
}
|
|
14
|
+
export declare const TASKFORCE_PROXY_ORIGIN_HOST_HEADER = "x-taskforce-origin-host";
|
|
15
|
+
export declare const TASKFORCE_PROXY_ORIGIN_PROTO_HEADER = "x-taskforce-origin-proto";
|
|
16
|
+
export declare const TASKFORCE_PROXY_ORIGIN_BASE_URL_HEADER = "x-taskforce-origin-base-url";
|
|
17
|
+
export declare const TASKFORCE_PROXY_ORIGIN_RUNTIME_HEADER = "x-taskforce-origin-runtime";
|
|
18
|
+
export declare const TASKFORCE_PROXY_CLOUD_ENVIRONMENT_HEADER = "x-taskforce-cloud-environment";
|
|
19
|
+
interface AuthorizedRequestAccess extends RequestAccessContext {
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare function shouldProxyCloudPath(pathname: string): boolean;
|
|
23
|
+
export declare function resolveCloudProxyUpstreamBaseUrl(req: http.IncomingMessage, fallbackBaseUrl: string): string;
|
|
24
|
+
export declare function resolveAuthorizedWorkspaceAccess(core: Pick<TaskforceCore, 'resolveUserAccess' | 'getSystemRole'>, access: AuthorizedRequestAccess, requestedWorkspaceId: string): AuthorizedRequestAccess;
|
|
25
|
+
export declare function resolveMaxPayloadBytesForPath(pathname: string, defaultMaxBytes: number): number;
|
|
12
26
|
export declare function shouldRewriteSetCookieForLocalDevHost(hostHeader: string | undefined): boolean;
|
|
27
|
+
export declare function writeJsonErrorIfPossible(res: http.ServerResponse, statusCode: number, payload: Record<string, unknown>): boolean;
|
|
28
|
+
export declare function applyCloudProxyForwardedHeaders(headers: Headers, req: http.IncomingMessage): void;
|
|
13
29
|
export declare function rewriteProxySetCookieForLocalHost(cookie: string): string;
|
|
14
30
|
export declare function shouldApplyAuthRateLimitForPath(pathname: string): boolean;
|
|
31
|
+
export declare function resolveCloudProxyBaseUrl(env?: NodeJS.ProcessEnv): string;
|
|
15
32
|
export declare function ensureBillingWebhookAuthExclusion(excludedPaths: string[]): string[];
|
|
33
|
+
export declare function ensurePublicPricingAuthExclusion(excludedPaths: string[]): string[];
|
|
34
|
+
export declare function ensurePublicSiteConfigAuthExclusion(excludedPaths: string[]): string[];
|
|
16
35
|
export declare function isBillingWebhookPath(pathname: string): boolean;
|
|
17
36
|
export declare function createStandaloneServer(options: StandaloneServerOptions): http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>;
|
|
37
|
+
export {};
|
package/dist/server/index.js
CHANGED
|
@@ -23,9 +23,11 @@ import { purgeExpiredDocuments } from '../storage/documentPurge.js';
|
|
|
23
23
|
import { scanDocumentIntegrity } from '../storage/documentIntegrity.js';
|
|
24
24
|
import { resolveStorageIntegrityScheduleSettings, shouldRunStorageIntegritySchedule } from '../storage/integritySchedule.js';
|
|
25
25
|
import { TaskAssetStore } from '../storage/taskAssetStore.js';
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
26
|
+
import { WorkspaceAssetStore } from '../storage/workspaceAssetStore.js';
|
|
27
|
+
import { validateEnvironment } from '../config/envSchema.js';
|
|
28
28
|
import { createRealtimeSyncWsManager } from './realtimeSyncWs.js';
|
|
29
|
+
import { resolveDeploymentConfig } from '../config/deployment.js';
|
|
30
|
+
import { TASKFORCE_CLOUD_ENVIRONMENTS, parseTaskforceCloudEnvironment } from '../config/cloudEnvironment.js';
|
|
29
31
|
const __filename = fileURLToPath(import.meta.url);
|
|
30
32
|
const __dirname = path.dirname(__filename);
|
|
31
33
|
const MIME_TYPES = {
|
|
@@ -82,12 +84,73 @@ const CORS_RESPONSE_HEADERS = new Set([
|
|
|
82
84
|
'access-control-max-age',
|
|
83
85
|
'vary'
|
|
84
86
|
]);
|
|
85
|
-
|
|
87
|
+
export const TASKFORCE_PROXY_ORIGIN_HOST_HEADER = 'x-taskforce-origin-host';
|
|
88
|
+
export const TASKFORCE_PROXY_ORIGIN_PROTO_HEADER = 'x-taskforce-origin-proto';
|
|
89
|
+
export const TASKFORCE_PROXY_ORIGIN_BASE_URL_HEADER = 'x-taskforce-origin-base-url';
|
|
90
|
+
export const TASKFORCE_PROXY_ORIGIN_RUNTIME_HEADER = 'x-taskforce-origin-runtime';
|
|
91
|
+
export const TASKFORCE_PROXY_CLOUD_ENVIRONMENT_HEADER = 'x-taskforce-cloud-environment';
|
|
92
|
+
export function shouldProxyCloudPath(pathname) {
|
|
86
93
|
if (!pathname)
|
|
87
94
|
return false;
|
|
88
95
|
if (pathname === '/api/taskforce/auth/runtime-config')
|
|
89
96
|
return false;
|
|
90
|
-
|
|
97
|
+
if (pathname === '/api/taskforce/sync/workspace/apply-local')
|
|
98
|
+
return false;
|
|
99
|
+
if (pathname === '/api/taskforce/sync/workspace/documents')
|
|
100
|
+
return false;
|
|
101
|
+
if (pathname === '/api/taskforce/sync/workspace/assets')
|
|
102
|
+
return false;
|
|
103
|
+
if (pathname === '/api/taskforce/sync/workspace/ai-profiles')
|
|
104
|
+
return false;
|
|
105
|
+
if (pathname === '/api/taskforce/sync/events')
|
|
106
|
+
return false;
|
|
107
|
+
return pathname === PUBLIC_PRICING_PATH
|
|
108
|
+
|| pathname === PUBLIC_SITE_CONFIG_PATH
|
|
109
|
+
|| pathname === PUBLIC_SITE_CONFIG_SCRIPT_PATH
|
|
110
|
+
|| pathname === '/api/taskforce/version'
|
|
111
|
+
|| pathname === '/api/taskforce/account/entitlements'
|
|
112
|
+
|| pathname.startsWith('/api/taskforce/admin/')
|
|
113
|
+
|| pathname.startsWith('/api/taskforce/billing/')
|
|
114
|
+
|| pathname.startsWith('/api/taskforce/auth/')
|
|
115
|
+
|| pathname.startsWith('/api/taskforce/settings/mcp/')
|
|
116
|
+
|| pathname.startsWith('/api/platform/')
|
|
117
|
+
|| pathname.startsWith('/api/taskforce/sync/');
|
|
118
|
+
}
|
|
119
|
+
export function resolveCloudProxyUpstreamBaseUrl(req, fallbackBaseUrl) {
|
|
120
|
+
const requestedEnvironment = parseTaskforceCloudEnvironment(req.headers[TASKFORCE_PROXY_CLOUD_ENVIRONMENT_HEADER]);
|
|
121
|
+
if (!requestedEnvironment)
|
|
122
|
+
return fallbackBaseUrl;
|
|
123
|
+
return TASKFORCE_CLOUD_ENVIRONMENTS[requestedEnvironment].appBaseUrl;
|
|
124
|
+
}
|
|
125
|
+
export function resolveAuthorizedWorkspaceAccess(core, access, requestedWorkspaceId) {
|
|
126
|
+
if (!access.authenticated || !access.userId || access.userId === 'anonymous')
|
|
127
|
+
return access;
|
|
128
|
+
const trimmedRequestedWorkspaceId = String(requestedWorkspaceId || '').trim();
|
|
129
|
+
const candidateWorkspaceIds = [
|
|
130
|
+
trimmedRequestedWorkspaceId,
|
|
131
|
+
String(access.workspaceId || '').trim()
|
|
132
|
+
].filter((workspaceId, index, values) => Boolean(workspaceId) && values.indexOf(workspaceId) === index);
|
|
133
|
+
for (const workspaceId of candidateWorkspaceIds) {
|
|
134
|
+
const resolved = core.resolveUserAccess(access.userId, workspaceId, access.role);
|
|
135
|
+
if (!resolved)
|
|
136
|
+
continue;
|
|
137
|
+
return {
|
|
138
|
+
...access,
|
|
139
|
+
role: resolved.role,
|
|
140
|
+
workspaceId: resolved.workspaceId,
|
|
141
|
+
userId: resolved.userId,
|
|
142
|
+
systemRole: core.getSystemRole(resolved.userId),
|
|
143
|
+
disabled: resolved.disabled
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
return access;
|
|
147
|
+
}
|
|
148
|
+
export function resolveMaxPayloadBytesForPath(pathname, defaultMaxBytes) {
|
|
149
|
+
if (pathname.startsWith('/api/taskforce/sync/')) {
|
|
150
|
+
// Sync routes (especially applying local changes) often include large binary attachments
|
|
151
|
+
return Math.max(defaultMaxBytes, 50 * 1024 * 1024);
|
|
152
|
+
}
|
|
153
|
+
return defaultMaxBytes;
|
|
91
154
|
}
|
|
92
155
|
export function shouldRewriteSetCookieForLocalDevHost(hostHeader) {
|
|
93
156
|
const host = String(hostHeader || '').trim().toLowerCase();
|
|
@@ -96,6 +159,31 @@ export function shouldRewriteSetCookieForLocalDevHost(hostHeader) {
|
|
|
96
159
|
const hostname = host.replace(/:\d+$/, '');
|
|
97
160
|
return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1' || hostname === '[::1]';
|
|
98
161
|
}
|
|
162
|
+
export function writeJsonErrorIfPossible(res, statusCode, payload) {
|
|
163
|
+
if (res.headersSent || res.writableEnded)
|
|
164
|
+
return false;
|
|
165
|
+
res.writeHead(statusCode, { 'Content-Type': 'application/json' });
|
|
166
|
+
res.end(JSON.stringify(payload));
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
export function applyCloudProxyForwardedHeaders(headers, req) {
|
|
170
|
+
const originalHost = String(req.headers.host || '').trim();
|
|
171
|
+
const proto = String(req.headers['x-forwarded-proto'] || '').trim().toLowerCase() === 'https'
|
|
172
|
+
? 'https'
|
|
173
|
+
: (req.socket?.encrypted ? 'https' : 'http');
|
|
174
|
+
if (originalHost && !headers.has('x-forwarded-host')) {
|
|
175
|
+
headers.set('x-forwarded-host', originalHost);
|
|
176
|
+
}
|
|
177
|
+
if (!headers.has('x-forwarded-proto')) {
|
|
178
|
+
headers.set('x-forwarded-proto', proto);
|
|
179
|
+
}
|
|
180
|
+
if (originalHost) {
|
|
181
|
+
headers.set(TASKFORCE_PROXY_ORIGIN_HOST_HEADER, originalHost);
|
|
182
|
+
headers.set(TASKFORCE_PROXY_ORIGIN_PROTO_HEADER, proto);
|
|
183
|
+
headers.set(TASKFORCE_PROXY_ORIGIN_BASE_URL_HEADER, `${proto}://${originalHost.replace(/\/+$/, '')}`);
|
|
184
|
+
headers.set(TASKFORCE_PROXY_ORIGIN_RUNTIME_HEADER, 'local-proxy');
|
|
185
|
+
}
|
|
186
|
+
}
|
|
99
187
|
export function rewriteProxySetCookieForLocalHost(cookie) {
|
|
100
188
|
const parts = String(cookie || '').split(';').map((part) => part.trim()).filter(Boolean);
|
|
101
189
|
if (parts.length === 0)
|
|
@@ -120,34 +208,66 @@ async function readRequestBody(req, maxBytes) {
|
|
|
120
208
|
export function shouldApplyAuthRateLimitForPath(pathname) {
|
|
121
209
|
const normalizedPath = String(pathname || '').trim();
|
|
122
210
|
return normalizedPath.startsWith('/api/taskforce/auth/')
|
|
123
|
-
&& normalizedPath !== '/api/taskforce/auth/session'
|
|
211
|
+
&& normalizedPath !== '/api/taskforce/auth/session'
|
|
212
|
+
&& normalizedPath !== '/api/taskforce/auth/runtime-config'
|
|
213
|
+
&& normalizedPath !== '/api/taskforce/auth/admin-session';
|
|
124
214
|
}
|
|
125
215
|
const BILLING_WEBHOOK_PATH = '/api/taskforce/billing/webhook';
|
|
216
|
+
const PUBLIC_PRICING_PATH = '/api/taskforce/public/pricing';
|
|
217
|
+
const PUBLIC_SITE_CONFIG_PATH = '/api/taskforce/public/site-config';
|
|
218
|
+
const PUBLIC_SITE_CONFIG_SCRIPT_PATH = '/api/taskforce/public/site-config-script';
|
|
219
|
+
export function resolveCloudProxyBaseUrl(env = process.env) {
|
|
220
|
+
return resolveDeploymentConfig(env).cloudBaseUrl || TASKFORCE_CLOUD_ENVIRONMENTS.production.appBaseUrl;
|
|
221
|
+
}
|
|
126
222
|
export function ensureBillingWebhookAuthExclusion(excludedPaths) {
|
|
127
223
|
if (excludedPaths.includes(BILLING_WEBHOOK_PATH))
|
|
128
224
|
return excludedPaths;
|
|
129
225
|
return [...excludedPaths, BILLING_WEBHOOK_PATH];
|
|
130
226
|
}
|
|
227
|
+
export function ensurePublicPricingAuthExclusion(excludedPaths) {
|
|
228
|
+
if (excludedPaths.includes(PUBLIC_PRICING_PATH))
|
|
229
|
+
return excludedPaths;
|
|
230
|
+
return [...excludedPaths, PUBLIC_PRICING_PATH];
|
|
231
|
+
}
|
|
232
|
+
export function ensurePublicSiteConfigAuthExclusion(excludedPaths) {
|
|
233
|
+
const next = excludedPaths.includes(PUBLIC_SITE_CONFIG_PATH)
|
|
234
|
+
? excludedPaths
|
|
235
|
+
: [...excludedPaths, PUBLIC_SITE_CONFIG_PATH];
|
|
236
|
+
if (next.includes(PUBLIC_SITE_CONFIG_SCRIPT_PATH))
|
|
237
|
+
return next;
|
|
238
|
+
return [...next, PUBLIC_SITE_CONFIG_SCRIPT_PATH];
|
|
239
|
+
}
|
|
131
240
|
export function isBillingWebhookPath(pathname) {
|
|
132
241
|
return String(pathname || '').trim() === BILLING_WEBHOOK_PATH;
|
|
133
242
|
}
|
|
134
243
|
export function createStandaloneServer(options) {
|
|
135
|
-
|
|
244
|
+
const envValidation = validateEnvironment(process.env, { target: 'server', strictUnknown: true });
|
|
245
|
+
if (!envValidation.ok) {
|
|
246
|
+
const details = envValidation.errors.map((entry) => `- ${entry}`).join('\n');
|
|
247
|
+
throw new Error(`Environment validation failed:\n${details}`);
|
|
248
|
+
}
|
|
249
|
+
for (const warning of envValidation.warnings) {
|
|
250
|
+
console.warn(`[Taskforce env] ${warning}`);
|
|
251
|
+
}
|
|
136
252
|
const db = resolveDatabaseConfigFromEnv();
|
|
137
253
|
const runtimeMode = resolveRuntimeModeFromEnv(process.env, db.provider);
|
|
138
254
|
assertCloudDatabaseProvider(runtimeMode, db.provider, process.env);
|
|
139
255
|
const core = new TaskforceCore({
|
|
140
256
|
projectRoot: options.projectRoot,
|
|
141
257
|
tenantId: process.env.TASKFORCE_TENANT_ID || 'default',
|
|
258
|
+
runtimeMode,
|
|
142
259
|
database: {
|
|
143
260
|
provider: db.provider,
|
|
144
261
|
connectionString: db.connectionString
|
|
145
262
|
}
|
|
146
263
|
});
|
|
147
264
|
const { basePath } = core.getPaths();
|
|
148
|
-
const taskAssetStore = new TaskAssetStore(core.getDatabaseAdapter(), core.getTenantId()
|
|
265
|
+
const taskAssetStore = new TaskAssetStore(core.getDatabaseAdapter(), core.getTenantId());
|
|
266
|
+
const workspaceAssetStore = new WorkspaceAssetStore(core.getDatabaseAdapter(), core.getTenantId());
|
|
149
267
|
const authConfig = resolveAuthConfigFromEnv(runtimeMode, process.env);
|
|
150
268
|
authConfig.excludedPaths = ensureBillingWebhookAuthExclusion(authConfig.excludedPaths);
|
|
269
|
+
authConfig.excludedPaths = ensurePublicPricingAuthExclusion(authConfig.excludedPaths);
|
|
270
|
+
authConfig.excludedPaths = ensurePublicSiteConfigAuthExclusion(authConfig.excludedPaths);
|
|
151
271
|
const objectStorage = resolveObjectStorageConfigFromEnv(process.env);
|
|
152
272
|
const resolveEffectiveObjectStorage = () => {
|
|
153
273
|
if (objectStorage.provider !== 'r2' || !objectStorage.r2)
|
|
@@ -159,13 +279,14 @@ export function createStandaloneServer(options) {
|
|
|
159
279
|
const keyPrefixRaw = typeof storageSettings.keyPrefix === 'string'
|
|
160
280
|
? storageSettings.keyPrefix.trim().replace(/^\/+|\/+$/g, '')
|
|
161
281
|
: '';
|
|
282
|
+
const hasKeyPrefixOverride = typeof storageSettings.keyPrefix === 'string';
|
|
162
283
|
const uploadTtlRaw = Number(storageSettings.signedUploadTtlSeconds);
|
|
163
284
|
const downloadTtlRaw = Number(storageSettings.signedDownloadTtlSeconds);
|
|
164
285
|
return {
|
|
165
286
|
provider: 'r2',
|
|
166
287
|
r2: {
|
|
167
288
|
...objectStorage.r2,
|
|
168
|
-
keyPrefix: keyPrefixRaw
|
|
289
|
+
keyPrefix: hasKeyPrefixOverride ? keyPrefixRaw : objectStorage.r2.keyPrefix,
|
|
169
290
|
signedUploadTtlSeconds: Number.isFinite(uploadTtlRaw) && uploadTtlRaw > 0
|
|
170
291
|
? Math.floor(uploadTtlRaw)
|
|
171
292
|
: objectStorage.r2.signedUploadTtlSeconds,
|
|
@@ -180,7 +301,7 @@ export function createStandaloneServer(options) {
|
|
|
180
301
|
objectStorage: resolveEffectiveObjectStorage()
|
|
181
302
|
});
|
|
182
303
|
const allowedOrigins = getAllowedOriginsFromEnv(process.env.TASKFORCE_ALLOWED_ORIGINS);
|
|
183
|
-
const cloudProxyBaseUrl =
|
|
304
|
+
const cloudProxyBaseUrl = resolveCloudProxyBaseUrl(process.env);
|
|
184
305
|
const cloudProxyEnabled = runtimeMode === 'local' && Boolean(cloudProxyBaseUrl);
|
|
185
306
|
const cloudProxyClientId = String(process.env.TASKFORCE_CF_ACCESS_CLIENT_ID || process.env.CF_ACCESS_CLIENT_ID || '').trim();
|
|
186
307
|
const cloudProxyClientSecret = String(process.env.TASKFORCE_CF_ACCESS_CLIENT_SECRET || process.env.CF_ACCESS_CLIENT_SECRET || '').trim();
|
|
@@ -291,8 +412,8 @@ export function createStandaloneServer(options) {
|
|
|
291
412
|
// Standalone UI source now lives in apps/app and builds to dist/ui.
|
|
292
413
|
// When built: dist/server/index.js -> dist/ui/
|
|
293
414
|
// When source: src/server/index.ts -> dist/ui/
|
|
294
|
-
|
|
295
|
-
|
|
415
|
+
let uiResolution = resolveStaticUiPath();
|
|
416
|
+
let distUiPath = uiResolution.uiPath;
|
|
296
417
|
if (distUiPath) {
|
|
297
418
|
console.log(`[Taskforce] Serving static files from: ${distUiPath}`);
|
|
298
419
|
}
|
|
@@ -343,8 +464,13 @@ export function createStandaloneServer(options) {
|
|
|
343
464
|
const integritySchedulePollMinutes = readPositiveInteger(process.env.TASKFORCE_STORAGE_INTEGRITY_SCHEDULE_POLL_MINUTES, 1);
|
|
344
465
|
console.log(`[Taskforce] Storage integrity scheduler poll: every ${integritySchedulePollMinutes} minute(s)`);
|
|
345
466
|
const server = http.createServer(async (req, res) => {
|
|
467
|
+
if (!distUiPath) {
|
|
468
|
+
uiResolution = resolveStaticUiPath();
|
|
469
|
+
distUiPath = uiResolution.uiPath;
|
|
470
|
+
}
|
|
346
471
|
const url = new URL(req.url || '/', `http://localhost`);
|
|
347
|
-
|
|
472
|
+
const isMcpPath = url.pathname === '/mcp' || url.pathname === '/mcp/' || url.pathname.startsWith('/mcp/');
|
|
473
|
+
applySecurityHeaders(res, runtimeMode, process.env);
|
|
348
474
|
// Handle CORS preflight
|
|
349
475
|
if (req.method === 'OPTIONS') {
|
|
350
476
|
const cors = applyCorsHeaders(req, res, allowedOrigins);
|
|
@@ -367,25 +493,31 @@ export function createStandaloneServer(options) {
|
|
|
367
493
|
}
|
|
368
494
|
try {
|
|
369
495
|
const method = String(req.method || 'GET').toUpperCase();
|
|
370
|
-
const
|
|
496
|
+
const upstreamBaseUrl = resolveCloudProxyUpstreamBaseUrl(req, cloudProxyBaseUrl);
|
|
497
|
+
const upstreamUrl = `${upstreamBaseUrl}${url.pathname}${url.search || ''}`;
|
|
371
498
|
const headers = new Headers();
|
|
372
499
|
for (const [key, value] of Object.entries(req.headers)) {
|
|
373
500
|
const name = key.toLowerCase();
|
|
374
501
|
if (!value)
|
|
375
502
|
continue;
|
|
376
|
-
if (name === 'host'
|
|
503
|
+
if (name === 'host'
|
|
504
|
+
|| name === 'content-length'
|
|
505
|
+
|| name === TASKFORCE_PROXY_CLOUD_ENVIRONMENT_HEADER
|
|
506
|
+
|| HOP_BY_HOP_HEADERS.has(name))
|
|
377
507
|
continue;
|
|
378
508
|
const serialized = Array.isArray(value) ? value.join(', ') : String(value);
|
|
379
509
|
if (!serialized.trim())
|
|
380
510
|
continue;
|
|
381
511
|
headers.set(key, serialized);
|
|
382
512
|
}
|
|
513
|
+
applyCloudProxyForwardedHeaders(headers, req);
|
|
383
514
|
if (cloudProxyClientId && cloudProxyClientSecret) {
|
|
384
515
|
headers.set('CF-Access-Client-Id', cloudProxyClientId);
|
|
385
516
|
headers.set('CF-Access-Client-Secret', cloudProxyClientSecret);
|
|
386
517
|
}
|
|
387
518
|
const hasBody = method !== 'GET' && method !== 'HEAD';
|
|
388
|
-
const
|
|
519
|
+
const requestMaxPayload = resolveMaxPayloadBytesForPath(url.pathname, maxPayloadBytes);
|
|
520
|
+
const body = hasBody ? await readRequestBody(req, requestMaxPayload) : undefined;
|
|
389
521
|
const upstream = await fetch(upstreamUrl, {
|
|
390
522
|
method,
|
|
391
523
|
headers,
|
|
@@ -417,13 +549,12 @@ export function createStandaloneServer(options) {
|
|
|
417
549
|
catch (error) {
|
|
418
550
|
const message = String(error?.message || '');
|
|
419
551
|
if (message.startsWith('PAYLOAD_TOO_LARGE:')) {
|
|
420
|
-
const
|
|
421
|
-
|
|
422
|
-
res
|
|
552
|
+
const requestMaxPayload = resolveMaxPayloadBytesForPath(url.pathname, maxPayloadBytes);
|
|
553
|
+
const max = Number(message.split(':')[1] || requestMaxPayload);
|
|
554
|
+
writeJsonErrorIfPossible(res, 413, { error: `Payload too large (max ${max} bytes)` });
|
|
423
555
|
return;
|
|
424
556
|
}
|
|
425
|
-
res
|
|
426
|
-
res.end(JSON.stringify({ error: 'Cloud proxy request failed.' }));
|
|
557
|
+
writeJsonErrorIfPossible(res, 502, { error: 'Cloud proxy request failed.' });
|
|
427
558
|
}
|
|
428
559
|
return;
|
|
429
560
|
}
|
|
@@ -451,11 +582,12 @@ export function createStandaloneServer(options) {
|
|
|
451
582
|
// Enforce request payload guard before route handlers parse bodies.
|
|
452
583
|
const contentLength = req.headers['content-length'];
|
|
453
584
|
if (typeof contentLength === 'string') {
|
|
585
|
+
const requestMaxPayload = resolveMaxPayloadBytesForPath(url.pathname, maxPayloadBytes);
|
|
454
586
|
const contentLengthNumber = Number.parseInt(contentLength, 10);
|
|
455
|
-
if (Number.isFinite(contentLengthNumber) && contentLengthNumber >
|
|
587
|
+
if (Number.isFinite(contentLengthNumber) && contentLengthNumber > requestMaxPayload) {
|
|
456
588
|
req.resume();
|
|
457
589
|
res.writeHead(413, { 'Content-Type': 'application/json' });
|
|
458
|
-
res.end(JSON.stringify({ error: `Payload too large (max ${
|
|
590
|
+
res.end(JSON.stringify({ error: `Payload too large (max ${requestMaxPayload} bytes)` }));
|
|
459
591
|
return;
|
|
460
592
|
}
|
|
461
593
|
}
|
|
@@ -463,7 +595,7 @@ export function createStandaloneServer(options) {
|
|
|
463
595
|
const shouldApplyAuthRateLimit = shouldApplyAuthRateLimitForPath(url.pathname);
|
|
464
596
|
const accessForRateLimit = resolveRequestAccess(req, authConfig);
|
|
465
597
|
const isBillingWebhook = isBillingWebhookPath(url.pathname);
|
|
466
|
-
if (rateLimitEnabled && !isAuthApiPath) {
|
|
598
|
+
if (rateLimitEnabled && !isAuthApiPath && !isMcpPath) {
|
|
467
599
|
const key = resolveRateLimitKey({
|
|
468
600
|
req,
|
|
469
601
|
pathname: url.pathname,
|
|
@@ -533,21 +665,13 @@ export function createStandaloneServer(options) {
|
|
|
533
665
|
let access = accessForRateLimit;
|
|
534
666
|
const isAuthRoute = pathname.startsWith('/api/taskforce/auth/');
|
|
535
667
|
if (access.authenticated) {
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
userId: resolved.userId,
|
|
544
|
-
systemRole
|
|
545
|
-
};
|
|
546
|
-
if (resolved.disabled && !isAuthRoute) {
|
|
547
|
-
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
548
|
-
res.end(JSON.stringify({ error: 'Forbidden: user account is disabled.' }));
|
|
549
|
-
return;
|
|
550
|
-
}
|
|
668
|
+
access = resolveAuthorizedWorkspaceAccess(core, access, Array.isArray(req.headers['x-taskforce-workspace-id'])
|
|
669
|
+
? String(req.headers['x-taskforce-workspace-id'][0] || '')
|
|
670
|
+
: String(req.headers['x-taskforce-workspace-id'] || ''));
|
|
671
|
+
if (access.disabled && !isAuthRoute) {
|
|
672
|
+
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
673
|
+
res.end(JSON.stringify({ error: 'Forbidden: user account is disabled.' }));
|
|
674
|
+
return;
|
|
551
675
|
}
|
|
552
676
|
}
|
|
553
677
|
req.headers['x-taskforce-role'] = access.role;
|
|
@@ -590,6 +714,9 @@ export function createStandaloneServer(options) {
|
|
|
590
714
|
// 3. SPA fallback: serve index.html for client-side routing
|
|
591
715
|
const indexPath = distUiPath ? path.join(distUiPath, 'index.html') : '';
|
|
592
716
|
if (!url.pathname.startsWith('/api/') && distUiPath && fs.existsSync(indexPath)) {
|
|
717
|
+
if (isMcpPath) {
|
|
718
|
+
console.warn(`[Taskforce MCP] unmatched path fell through to SPA method=${req.method || 'GET'} path=${url.pathname} contentType="${String(req.headers['content-type'] || '')}" accept="${String(req.headers.accept || '')}" userAgent="${String(req.headers['user-agent'] || '')}"`);
|
|
719
|
+
}
|
|
593
720
|
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
594
721
|
fs.createReadStream(indexPath).pipe(res);
|
|
595
722
|
return;
|
|
@@ -638,10 +765,9 @@ export function createStandaloneServer(options) {
|
|
|
638
765
|
};
|
|
639
766
|
const runDocumentPurge = async () => {
|
|
640
767
|
try {
|
|
641
|
-
const { basePath
|
|
768
|
+
const { basePath } = core.getPaths();
|
|
642
769
|
const summary = await purgeExpiredDocuments({
|
|
643
770
|
basePath,
|
|
644
|
-
taskDataDir,
|
|
645
771
|
objectStorage: resolveEffectiveObjectStorage(),
|
|
646
772
|
assetStore: taskAssetStore
|
|
647
773
|
});
|
|
@@ -685,7 +811,8 @@ export function createStandaloneServer(options) {
|
|
|
685
811
|
includeDeleted: schedule.includeDeleted,
|
|
686
812
|
requireMirror: schedule.requireMirror,
|
|
687
813
|
limit: schedule.limit,
|
|
688
|
-
assetStore: taskAssetStore
|
|
814
|
+
assetStore: taskAssetStore,
|
|
815
|
+
workspaceAssetStore
|
|
689
816
|
});
|
|
690
817
|
core.updateGlobalSettings({
|
|
691
818
|
storageIntegritySchedule: {
|
|
@@ -7,6 +7,12 @@ describe('shouldApplyAuthRateLimitForPath', () => {
|
|
|
7
7
|
it('excludes auth session endpoint', () => {
|
|
8
8
|
expect(shouldApplyAuthRateLimitForPath('/api/taskforce/auth/session')).toBe(false);
|
|
9
9
|
});
|
|
10
|
+
it('excludes runtime config bootstrap endpoint', () => {
|
|
11
|
+
expect(shouldApplyAuthRateLimitForPath('/api/taskforce/auth/runtime-config')).toBe(false);
|
|
12
|
+
});
|
|
13
|
+
it('excludes admin session endpoint', () => {
|
|
14
|
+
expect(shouldApplyAuthRateLimitForPath('/api/taskforce/auth/admin-session')).toBe(false);
|
|
15
|
+
});
|
|
10
16
|
it('does not apply to non-auth routes', () => {
|
|
11
17
|
expect(shouldApplyAuthRateLimitForPath('/api/taskforce/tasks')).toBe(false);
|
|
12
18
|
});
|