@taskforcehq/taskforce 0.3.305 → 0.3.307
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 +0 -2
- package/dist/Taskforce.module.css +603 -107
- package/dist/TaskforceCore.js +216 -43
- package/dist/TaskforceCore.test.js +611 -28
- package/dist/assets/fonts/CourierPrime-Bold.woff2 +0 -0
- package/dist/assets/fonts/CourierPrime-BoldItalic.woff2 +0 -0
- package/dist/assets/fonts/CourierPrime-Italic.woff2 +0 -0
- package/dist/assets/fonts/CourierPrime-Regular.woff2 +0 -0
- package/dist/assets/fonts/Noir_medium.woff2 +0 -0
- package/dist/assets/fonts/Noir_regular.woff2 +0 -0
- package/dist/assets/fonts/RussoOne-Regular.woff2 +0 -0
- package/dist/assets/fonts/SpecialElite-Regular.woff2 +0 -0
- package/dist/compat/workspaceSyncCompat.js +46 -2
- package/dist/compat/workspaceSyncCompat.test.js +38 -1
- package/dist/components/activity/EntityActivityTimeline.d.ts +34 -0
- package/dist/components/activity/EntityActivityTimeline.js +81 -0
- package/dist/components/context/ContextAttachmentManager.d.ts +14 -0
- package/dist/components/context/ContextAttachmentManager.js +561 -0
- package/dist/components/features/AgentsModule.d.ts +14 -1
- package/dist/components/features/AgentsModule.js +366 -18
- package/dist/components/features/AgentsModule.test.js +507 -8
- package/dist/components/features/AnnotatedAttachmentWorkspace.d.ts +3 -1
- package/dist/components/features/AnnotatedAttachmentWorkspace.js +118 -4
- package/dist/components/features/AnnotatedAttachmentWorkspace.test.js +52 -0
- package/dist/components/features/DocumentIndex.d.ts +2 -2
- package/dist/components/features/DocumentIndex.js +3 -4
- package/dist/components/features/DocumentViewer.d.ts +7 -1
- package/dist/components/features/DocumentViewer.js +62 -4
- package/dist/components/features/DocumentWorkspace.d.ts +10 -2
- package/dist/components/features/DocumentWorkspace.js +15 -4
- package/dist/components/features/DocumentWorkspace.test.js +51 -1
- package/dist/components/features/TaskSettings.d.ts +2 -0
- package/dist/components/features/TaskSettings.js +83 -78
- package/dist/components/features/TaskSettings.test.js +171 -82
- package/dist/components/features/documentWorkspaceModel.d.ts +1 -1
- package/dist/components/task/TaskActionHeader.js +11 -5
- package/dist/components/task/TaskActionHeader.test.js +10 -0
- package/dist/components/task/TaskCard.js +24 -29
- package/dist/components/task/TaskCard.test.js +38 -3
- package/dist/components/task/TaskContextUpload.js +4 -526
- package/dist/components/task/TaskContextUpload.test.js +3 -3
- package/dist/components/task/TaskForm.js +61 -116
- package/dist/components/task/TaskForm.test.js +110 -8
- package/dist/components/task/TaskKanban.d.ts +2 -1
- package/dist/components/task/TaskKanban.js +94 -21
- package/dist/components/task/TaskKanban.test.js +36 -0
- package/dist/components/task/TaskList.js +5 -1
- package/dist/components/task/TaskList.test.js +4 -0
- package/dist/components/ui/EditableAvatarButton.d.ts +18 -0
- package/dist/components/ui/EditableAvatarButton.js +18 -0
- package/dist/components/ui/HierarchyActionBadge.d.ts +10 -0
- package/dist/components/ui/HierarchyActionBadge.js +5 -0
- package/dist/components/views/AppShellHeader.d.ts +3 -1
- package/dist/components/views/AppShellHeader.js +27 -11
- package/dist/components/views/AppShellHeader.test.js +18 -1
- package/dist/components/views/PlanComparisonPage.d.ts +9 -1
- package/dist/components/views/PlanComparisonPage.js +78 -14
- package/dist/components/views/PlanComparisonPage.test.js +257 -0
- package/dist/components/views/PlansPage.js +127 -36
- package/dist/components/views/PlansPage.test.js +294 -12
- package/dist/components/views/StandaloneLayout.js +529 -592
- package/dist/components/views/WidgetView.js +10 -8
- package/dist/components/views/panels/PlanningDrawer.d.ts +25 -5
- package/dist/components/views/panels/PlanningDrawer.js +270 -55
- package/dist/components/views/panels/PlanningDrawer.test.d.ts +1 -0
- package/dist/components/views/panels/PlanningDrawer.test.js +529 -0
- package/dist/components/views/planningScope.d.ts +20 -0
- package/dist/components/views/planningScope.js +25 -0
- package/dist/components/views/planningScope.test.d.ts +1 -0
- package/dist/components/views/planningScope.test.js +60 -0
- package/dist/components/views/standalone/modals/AccountHubModal.d.ts +26 -1
- package/dist/components/views/standalone/modals/AccountHubModal.js +76 -2
- package/dist/components/views/standalone/modals/AccountHubModal.test.js +20 -3
- package/dist/components/views/standalone/modals/AvatarImageManagerModal.d.ts +20 -0
- package/dist/components/views/standalone/modals/AvatarImageManagerModal.js +127 -0
- package/dist/components/views/standalone/modals/EditProfileModal.d.ts +2 -9
- package/dist/components/views/standalone/modals/EditProfileModal.js +3 -2
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.d.ts +9 -0
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.js +6 -0
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.d.ts +1 -0
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.js +24 -0
- package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +2 -1
- package/dist/components/views/standalone/modals/SyncStatusModal.js +2 -2
- package/dist/config/envSchema.js +1 -0
- package/dist/core/AiProfileService.d.ts +46 -2
- package/dist/core/AiProfileService.js +1073 -82
- package/dist/core/AiProfileService.test.js +19 -1
- package/dist/core/AiProfiles.test.js +1249 -44
- package/dist/core/AttachmentLinkService.d.ts +3 -0
- package/dist/core/AttachmentLinkService.js +110 -23
- package/dist/core/AuthIdentityService.d.ts +107 -0
- package/dist/core/AuthIdentityService.js +284 -0
- package/dist/core/AuthTokenService.d.ts +4 -0
- package/dist/core/AuthTokenService.js +34 -6
- package/dist/core/AuthTokenService.test.js +3 -3
- package/dist/core/EntitlementsPolicy.test.js +2 -2
- package/dist/core/GlobalSettingsService.js +127 -6
- package/dist/core/McpTokenService.d.ts +12 -0
- package/dist/core/McpTokenService.js +44 -1
- package/dist/core/PlanEntitlementService.d.ts +23 -2
- package/dist/core/PlanEntitlementService.js +343 -57
- package/dist/core/PlanFeatureCatalog.test.d.ts +1 -0
- package/dist/core/PlanFeatureCatalog.test.js +84 -0
- package/dist/core/PlanVersionPolicy.test.js +35 -2
- package/dist/core/PlanningEntities.test.js +418 -4
- package/dist/core/SignupMonetizationSettings.test.js +199 -27
- package/dist/core/SyncReconciliationService.js +2 -65
- package/dist/core/SystemAdmin.test.js +42 -42
- package/dist/core/TaskActivityService.d.ts +28 -1
- package/dist/core/TaskActivityService.js +227 -46
- package/dist/core/TaskActivitySync.test.d.ts +1 -0
- package/dist/core/TaskActivitySync.test.js +90 -0
- package/dist/core/TaskAttachmentsCanonical.test.js +51 -1
- package/dist/core/TaskAuditTimeline.test.js +96 -0
- package/dist/core/Taskforce.d.ts +415 -40
- package/dist/core/Taskforce.ids.test.js +58 -0
- package/dist/core/Taskforce.js +1543 -266
- package/dist/core/Taskforce.listTasksSlim.test.d.ts +1 -0
- package/dist/core/Taskforce.listTasksSlim.test.js +91 -0
- package/dist/core/Taskforce.mcpAuth.test.js +109 -0
- package/dist/core/UserProfileAvatarDrafts.test.js +30 -3
- package/dist/core/WorkspaceLifecycleService.js +0 -5
- package/dist/core/WorkspacePermissions.test.js +25 -1
- package/dist/core/WorkspacePlanMode.test.js +117 -16
- package/dist/core/shared.d.ts +1 -1
- package/dist/core/shared.js +5 -1
- package/dist/core/types.d.ts +75 -2
- package/dist/hooks/auth/useTaskforceAuthBootstrap.js +28 -2
- package/dist/hooks/bootstrapTimeouts.d.ts +4 -0
- package/dist/hooks/bootstrapTimeouts.js +8 -0
- package/dist/hooks/bootstrapTimeouts.test.d.ts +1 -0
- package/dist/hooks/bootstrapTimeouts.test.js +12 -0
- package/dist/hooks/sync/bootstrap.js +2 -0
- package/dist/hooks/sync/controlPlane.d.ts +37 -0
- package/dist/hooks/sync/controlPlane.js +78 -0
- package/dist/hooks/sync/controlPlane.test.d.ts +1 -0
- package/dist/hooks/sync/controlPlane.test.js +121 -0
- package/dist/hooks/sync/lifecyclePolicy.d.ts +45 -0
- package/dist/hooks/sync/lifecyclePolicy.js +93 -0
- package/dist/hooks/sync/lifecyclePolicy.test.d.ts +1 -0
- package/dist/hooks/sync/lifecyclePolicy.test.js +124 -0
- package/dist/hooks/sync/orchestratorShared.d.ts +13 -4
- package/dist/hooks/sync/orchestratorShared.js +129 -48
- package/dist/hooks/sync/orchestratorShared.test.js +50 -1
- package/dist/hooks/sync/pullLifecycle.d.ts +31 -0
- package/dist/hooks/sync/pullLifecycle.js +24 -0
- package/dist/hooks/sync/pullLifecycle.test.d.ts +1 -0
- package/dist/hooks/sync/pullLifecycle.test.js +80 -0
- package/dist/hooks/sync/recovery.d.ts +16 -2
- package/dist/hooks/sync/recovery.js +179 -53
- package/dist/hooks/sync/recovery.test.d.ts +1 -0
- package/dist/hooks/sync/recovery.test.js +292 -0
- package/dist/hooks/sync/transfers.d.ts +16 -3
- package/dist/hooks/sync/transfers.js +210 -66
- package/dist/hooks/sync/transfers.test.d.ts +1 -0
- package/dist/hooks/sync/transfers.test.js +928 -0
- package/dist/hooks/sync/useRecentSyncEvents.d.ts +21 -0
- package/dist/hooks/sync/useRecentSyncEvents.js +92 -0
- package/dist/hooks/sync/useRecentSyncEvents.test.d.ts +1 -0
- package/dist/hooks/sync/useRecentSyncEvents.test.js +124 -0
- package/dist/hooks/sync/useSyncStatusActions.d.ts +30 -0
- package/dist/hooks/sync/useSyncStatusActions.js +88 -0
- package/dist/hooks/sync/useSyncStatusActions.test.d.ts +1 -0
- package/dist/hooks/sync/useSyncStatusActions.test.js +133 -0
- package/dist/hooks/sync/useSyncStatusControls.d.ts +25 -0
- package/dist/hooks/sync/useSyncStatusControls.js +60 -0
- package/dist/hooks/sync/useSyncStatusControls.test.d.ts +1 -0
- package/dist/hooks/sync/useSyncStatusControls.test.js +88 -0
- package/dist/hooks/useFilterSort.js +13 -13
- package/dist/hooks/useFilterSort.test.js +87 -1
- package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +12 -0
- package/dist/hooks/useSyncOrchestrator.d.ts +9 -2
- package/dist/hooks/useSyncOrchestrator.js +409 -183
- package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +407 -0
- package/dist/hooks/useTaskData.js +8 -3
- package/dist/hooks/useTaskData.test.js +45 -0
- package/dist/hooks/useTaskforce.d.ts +145 -52
- package/dist/hooks/useTaskforce.js +592 -253
- package/dist/hooks/useTaskforce.runtime-routing.test.d.ts +1 -0
- package/dist/hooks/useTaskforce.runtime-routing.test.js +246 -0
- package/dist/hooks/useTaskforce.sync-behavior.test.js +2468 -201
- package/dist/hooks/useWorkspaceSyncController.d.ts +1 -0
- package/dist/hooks/useWorkspaceSyncController.js +13 -2
- package/dist/hooks/useWorkspaceSyncController.test.js +48 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +16 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +328 -40
- package/dist/localization/locales/en-US.d.ts +0 -1
- package/dist/localization/locales/en-US.js +0 -1
- package/dist/localization/locales/es-419.js +0 -1
- package/dist/localization/locales/pt-BR.js +0 -1
- package/dist/mcp/canonicalAssetHelpers.d.ts +16 -4
- package/dist/mcp/canonicalAssetHelpers.js +18 -10
- package/dist/mcp/canonicalAssetHelpers.test.d.ts +1 -0
- package/dist/mcp/canonicalAssetHelpers.test.js +67 -0
- package/dist/mcp/clientIntegrations.d.ts +1 -0
- package/dist/mcp/clientIntegrations.js +25 -0
- package/dist/mcp/clientIntegrations.test.js +14 -3
- package/dist/mcp/clientProfileDefaults.js +3 -3
- package/dist/mcp/collaborationRegistrar.js +7 -7
- package/dist/mcp/documentAssetRegistrar.js +116 -10
- package/dist/mcp/runtime.d.ts +3 -0
- package/dist/mcp/runtime.js +1099 -185
- package/dist/mcp/runtime.test.js +1491 -140
- package/dist/mcp/taskAttachmentTypes.d.ts +1 -1
- package/dist/mcp/taskPlanningRegistrar.js +48 -0
- package/dist/mcp/toolRegistry.d.ts +56 -0
- package/dist/mcp/toolRegistry.js +8 -0
- package/dist/mcp/toolRegistry.test.js +4 -0
- package/dist/migrations/taskSchemaMigrations.d.ts +1 -1
- package/dist/migrations/taskSchemaMigrations.js +192 -61
- package/dist/migrations/taskSchemaMigrations.test.js +15 -0
- package/dist/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
- package/dist/resources/templates/workflows/collaborate.yaml +1 -1
- package/dist/resources/templates/workflows/evaluate.yaml +2 -2
- package/dist/resources/templates/workflows/plan.yaml +1 -1
- package/dist/resources/templates/workflows/review.yaml +2 -2
- package/dist/server/aiProfileAvatarAssets.d.ts +49 -0
- package/dist/server/aiProfileAvatarAssets.js +319 -0
- package/dist/server/aiProfileAvatarAssets.test.d.ts +1 -0
- package/dist/server/aiProfileAvatarAssets.test.js +213 -0
- package/dist/server/annotatedAttachmentsRoutes.test.js +69 -10
- package/dist/server/auth/providers/apple.d.ts +33 -0
- package/dist/server/auth/providers/apple.js +82 -0
- package/dist/server/auth/providers/appleClientSecret.d.ts +37 -0
- package/dist/server/auth/providers/appleClientSecret.js +65 -0
- package/dist/server/auth/providers/github.d.ts +26 -0
- package/dist/server/auth/providers/github.js +86 -0
- package/dist/server/auth/providers/google.d.ts +21 -0
- package/dist/server/auth/providers/google.js +56 -0
- package/dist/server/auth/providers/types.d.ts +21 -0
- package/dist/server/auth/providers/types.js +1 -0
- package/dist/server/auth.d.ts +2 -0
- package/dist/server/auth.js +6 -3
- package/dist/server/documentReviewRoutes.test.js +36 -3
- package/dist/server/index.cookieProxy.test.js +1 -0
- package/dist/server/index.d.ts +12 -0
- package/dist/server/index.js +124 -9
- package/dist/server/index.rateLimit.test.js +3 -0
- package/dist/server/index.test.js +111 -3
- package/dist/server/routes/admin.d.ts +3 -0
- package/dist/server/routes/admin.js +459 -28
- package/dist/server/routes/annotatedAttachments.js +51 -0
- package/dist/server/routes/auth.d.ts +26 -2
- package/dist/server/routes/auth.js +1170 -71
- package/dist/server/routes/authSupport.d.ts +5 -1
- package/dist/server/routes/authSupport.js +13 -2
- package/dist/server/routes/billing.js +372 -35
- package/dist/server/routes/billing.test.js +595 -12
- package/dist/server/routes/documents.d.ts +1 -0
- package/dist/server/routes/documents.js +182 -70
- package/dist/server/routes/shared.d.ts +28 -2
- package/dist/server/routes/shared.js +69 -14
- package/dist/server/routes/sync.integration.test.js +658 -39
- package/dist/server/routes/sync.js +74 -608
- package/dist/server/routes/syncAuxRoutes.d.ts +15 -0
- package/dist/server/routes/syncAuxRoutes.js +91 -0
- package/dist/server/routes/syncAuxRoutes.test.d.ts +1 -0
- package/dist/server/routes/syncAuxRoutes.test.js +158 -0
- package/dist/server/routes/syncPullApplyRoutes.d.ts +36 -0
- package/dist/server/routes/syncPullApplyRoutes.js +204 -0
- package/dist/server/routes/syncPushRoutes.d.ts +24 -0
- package/dist/server/routes/syncPushRoutes.js +212 -0
- package/dist/server/routes/syncRouteGuards.d.ts +36 -0
- package/dist/server/routes/syncRouteGuards.js +67 -0
- package/dist/server/routes/syncRouteGuards.test.d.ts +1 -0
- package/dist/server/routes/syncRouteGuards.test.js +94 -0
- package/dist/server/routes/syncRouteTypes.d.ts +13 -0
- package/dist/server/routes/syncRouteTypes.js +1 -0
- package/dist/server/routes/syncSnapshotRoutes.d.ts +66 -0
- package/dist/server/routes/syncSnapshotRoutes.js +182 -0
- package/dist/server/routes/tasks.js +55 -10
- package/dist/server/routes/workspaces.js +36 -5
- package/dist/server/routes.js +147 -11
- package/dist/server/routes.test.js +2704 -183
- package/dist/services/workflowExportSnapshots.test.js +2 -0
- package/dist/shared/aiProfileSeatScope.d.ts +5 -0
- package/dist/shared/aiProfileSeatScope.js +21 -0
- package/dist/shared/aiProfileSurfaceType.d.ts +1 -1
- package/dist/shared/aiProfileSurfaceType.js +10 -8
- package/dist/shared/passwordPolicy.d.ts +13 -0
- package/dist/shared/passwordPolicy.js +84 -0
- package/dist/shared/passwordPolicy.test.d.ts +1 -0
- package/dist/shared/passwordPolicy.test.js +34 -0
- package/dist/storage/objectStorage.d.ts +1 -0
- package/dist/storage/objectStorage.js +2 -1
- package/dist/storage/objectStorageClient.d.ts +1 -0
- package/dist/storage/objectStorageClient.js +41 -8
- package/dist/storage/objectStorageClient.test.js +26 -1
- package/dist/storage/objectStorageConfig.js +3 -1
- package/dist/storage/objectStorageConfig.test.js +13 -1
- package/dist/storage/workspaceAssetStore.d.ts +15 -3
- package/dist/storage/workspaceAssetStore.js +132 -44
- package/dist/storage/workspaceAssetStore.test.js +93 -6
- package/dist/styles/fonts.css +70 -0
- package/dist/sync/collaborationSyncPayload.d.ts +6 -1
- package/dist/sync/collaborationSyncPayload.js +19 -11
- package/dist/sync/collaborationSyncPayload.test.js +14 -1
- package/dist/sync/collaborationSyncState.d.ts +3 -3
- package/dist/sync/collaborationSyncState.js +19 -12
- package/dist/sync/contentSyncPayload.d.ts +5 -1
- package/dist/sync/contentSyncPayload.js +9 -0
- package/dist/sync/contentSyncPayload.test.js +39 -0
- package/dist/sync/contentSyncState.d.ts +9 -9
- package/dist/sync/contentSyncState.js +248 -107
- package/dist/sync/planningSyncPayload.js +5 -0
- package/dist/sync/planningSyncPayload.test.js +24 -0
- package/dist/sync/syncApplyHandlers.d.ts +11 -4
- package/dist/sync/syncApplyHandlers.js +115 -42
- package/dist/sync/syncApplyHandlers.test.js +251 -4
- package/dist/sync/syncFieldSemantics.d.ts +12 -0
- package/dist/sync/syncFieldSemantics.js +55 -0
- package/dist/sync/syncResourceAdapters.d.ts +46 -0
- package/dist/sync/syncResourceAdapters.js +79 -0
- package/dist/sync/syncService.d.ts +6 -0
- package/dist/sync/syncService.js +65 -1
- package/dist/sync/syncService.test.js +96 -3
- package/dist/sync/taskSyncChangeKey.d.ts +2 -0
- package/dist/sync/taskSyncChangeKey.js +143 -0
- package/dist/sync/taskSyncPayload.js +3 -8
- package/dist/sync/workspacePullFeed.d.ts +4 -0
- package/dist/sync/workspacePullFeed.js +132 -72
- package/dist/sync/workspacePullFeed.test.js +92 -0
- package/dist/sync/workspaceRepair.js +5 -2
- package/dist/sync/workspaceSyncModel.d.ts +73 -6
- package/dist/sync/workspaceSyncModel.js +342 -73
- package/dist/sync/workspaceSyncModel.test.js +559 -14
- package/dist/sync/workspaceSyncState.d.ts +17 -0
- package/dist/sync/workspaceSyncState.js +2 -1
- package/dist/sync/workspaceSyncSurface.js +3 -8
- package/dist/types.d.ts +50 -2
- package/dist/ui/assets/AgentsModule-2y82_3DO.js +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BTLZZCiQ.js +3 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BVKew-mH.css +1 -0
- package/dist/ui/assets/ContextAttachmentManager-D2epuNnG.js +3 -0
- package/dist/ui/assets/CourierPrime-Bold-BuLj_dpw.woff2 +0 -0
- package/dist/ui/assets/CourierPrime-BoldItalic-BrK2pUkZ.woff2 +0 -0
- package/dist/ui/assets/CourierPrime-Italic-DFUZK5Ey.woff2 +0 -0
- package/dist/ui/assets/CourierPrime-Regular-BsKphzVf.woff2 +0 -0
- package/dist/ui/assets/DocumentWorkspace-D4rJKXzd.css +1 -0
- package/dist/ui/assets/DocumentWorkspace-sVa-3Do6.js +252 -0
- package/dist/ui/assets/EntityActivityTimeline-DyqvvhuF.css +1 -0
- package/dist/ui/assets/EntityActivityTimeline-Zods27y_.js +1 -0
- package/dist/ui/assets/{InitiativesModule-Dhm7M8e7.js → InitiativesModule-D4XseTwW.js} +1 -1
- package/dist/ui/assets/Noir_medium-bxQwKGzB.woff2 +0 -0
- package/dist/ui/assets/Noir_regular-ojf2kxlG.woff2 +0 -0
- package/dist/ui/assets/PlansPage-D5AcbO0L.js +1 -0
- package/dist/ui/assets/PlansPage-Dvqsz5zc.css +1 -0
- package/dist/ui/assets/RussoOne-Regular-Cu_qq_qC.woff2 +0 -0
- package/dist/ui/assets/SpecialElite-Regular-Di6gSvAS.woff2 +0 -0
- package/dist/ui/assets/TaskContextUpload-uC5qx4Bv.js +1 -0
- package/dist/ui/assets/TaskSettings-CqvPAsTv.js +9 -0
- package/dist/ui/assets/{WorkflowsModule-BcS4afRn.js → WorkflowsModule-oOA9bcdK.js} +4 -4
- package/dist/ui/assets/documentReferences-DPZuTgHh.js +1 -0
- package/dist/ui/assets/index-607WPo_X.js +4 -0
- package/dist/ui/assets/index-CYyodXsg.css +1 -0
- package/dist/ui/assets/{vendor-icons-BSUaRwF8.js → vendor-icons-B32hGuF2.js} +1 -1
- package/dist/ui/fonts/CourierPrime-Bold.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-Bold.woff2 +0 -0
- package/dist/ui/fonts/CourierPrime-BoldItalic.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-BoldItalic.woff2 +0 -0
- package/dist/ui/fonts/CourierPrime-Italic.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-Italic.woff2 +0 -0
- package/dist/ui/fonts/CourierPrime-Regular.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-Regular.woff2 +0 -0
- package/dist/ui/fonts/Noir_medium.otf +0 -0
- package/dist/ui/fonts/Noir_medium.woff2 +0 -0
- package/dist/ui/fonts/Noir_regular.otf +0 -0
- package/dist/ui/fonts/Noir_regular.woff2 +0 -0
- package/dist/ui/fonts/RussoOne-Regular.woff2 +0 -0
- package/dist/ui/fonts/SpecialElite-Regular.ttf +0 -0
- package/dist/ui/fonts/SpecialElite-Regular.woff2 +0 -0
- package/dist/ui/index.html +3 -3
- package/dist/ui/product/agent manager.png +0 -0
- package/dist/ui/product/agent_manager_02.png +0 -0
- package/dist/utils/accountProfileSummaryCache.d.ts +5 -0
- package/dist/utils/aiProfileEvents.d.ts +7 -0
- package/dist/utils/aiProfileEvents.js +6 -0
- package/dist/utils/assignees.d.ts +8 -0
- package/dist/utils/assignees.js +10 -1
- package/dist/utils/assignees.test.d.ts +1 -0
- package/dist/utils/assignees.test.js +25 -0
- package/dist/utils/avatarDisplay.d.ts +1 -0
- package/dist/utils/avatarDisplay.js +15 -0
- package/dist/utils/avatarUpload.d.ts +27 -0
- package/dist/utils/avatarUpload.js +132 -0
- package/dist/utils/avatarUpload.test.d.ts +1 -0
- package/dist/utils/avatarUpload.test.js +40 -0
- package/dist/utils/bootstrapTrace.d.ts +7 -0
- package/dist/utils/bootstrapTrace.js +29 -0
- package/dist/utils/commercialLifecyclePresentation.js +3 -0
- package/dist/utils/contextAssetEvents.d.ts +2 -0
- package/dist/utils/contextFiles.d.ts +3 -1
- package/dist/utils/contextFiles.js +2 -1
- package/dist/utils/syncEventDetails.d.ts +3 -0
- package/dist/utils/syncEventDetails.js +64 -0
- package/dist/utils/syncEventDetails.test.d.ts +1 -0
- package/dist/utils/syncEventDetails.test.js +23 -0
- package/dist/utils/syncEventPresentation.d.ts +15 -0
- package/dist/utils/syncEventPresentation.js +129 -0
- package/dist/utils/syncEventPresentation.test.d.ts +1 -0
- package/dist/utils/syncEventPresentation.test.js +64 -0
- package/dist/utils/syncStatusPresentation.d.ts +72 -0
- package/dist/utils/syncStatusPresentation.js +217 -0
- package/dist/utils/syncStatusPresentation.test.d.ts +1 -0
- package/dist/utils/syncStatusPresentation.test.js +164 -0
- package/dist/utils/taskActivity.d.ts +9 -1
- package/dist/utils/taskActivity.js +290 -22
- package/dist/utils/taskActivity.test.js +141 -8
- package/dist/utils/taskSearch.d.ts +22 -0
- package/dist/utils/taskSearch.js +87 -0
- package/dist/utils/taskSearch.test.d.ts +1 -0
- package/dist/utils/taskSearch.test.js +69 -0
- package/dist/utils/taskUtils.js +10 -3
- package/dist/utils/taskUtils.test.d.ts +1 -0
- package/dist/utils/taskUtils.test.js +19 -0
- package/dist/utils/workspaceSyncPresentation.d.ts +4 -0
- package/dist/utils/workspaceSyncPresentation.js +68 -2
- package/dist/utils/workspaceSyncPresentation.test.js +36 -1
- package/package.json +3 -2
- package/scripts/export-sqlite-to-postgres.mjs +7 -9
- package/scripts/run-e2e-realtime.sh +17 -3
- package/scripts/run-smoke.sh +17 -5
- package/scripts/run-soak.sh +17 -5
- package/src/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
- package/src/resources/templates/workflows/collaborate.yaml +1 -1
- package/src/resources/templates/workflows/evaluate.yaml +2 -2
- package/src/resources/templates/workflows/plan.yaml +1 -1
- package/src/resources/templates/workflows/review.yaml +2 -2
- package/dist/ui/assets/AgentsModule-N2MnQBZk.js +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BG6P_GVW.js +0 -3
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +0 -1
- package/dist/ui/assets/DocumentWorkspace-B3nV_Gc5.css +0 -1
- package/dist/ui/assets/DocumentWorkspace-DRbDMwh8.js +0 -252
- package/dist/ui/assets/PlansPage-C2dd2n1X.css +0 -1
- package/dist/ui/assets/PlansPage-Cq0zXj3I.js +0 -1
- package/dist/ui/assets/RussoOne-Regular-C3BxZIj7.ttf +0 -0
- package/dist/ui/assets/TaskSettings-ln0aF7xc.js +0 -9
- package/dist/ui/assets/index-C2-OXZV7.css +0 -1
- package/dist/ui/assets/index-DcSI5F86.js +0 -6
- package/scripts/migrate-planning-model.ts +0 -233
package/dist/server/index.d.ts
CHANGED
|
@@ -11,6 +11,13 @@ export interface StandaloneServerOptions {
|
|
|
11
11
|
projectRoot: string;
|
|
12
12
|
port: number;
|
|
13
13
|
}
|
|
14
|
+
export type HttpServerTimeoutSettings = {
|
|
15
|
+
keepAliveTimeoutMs: number;
|
|
16
|
+
headersTimeoutMs: number;
|
|
17
|
+
requestTimeoutMs: number;
|
|
18
|
+
};
|
|
19
|
+
export declare function resolveHttpServerTimeoutSettings(env?: NodeJS.ProcessEnv): HttpServerTimeoutSettings;
|
|
20
|
+
export declare function configureHttpServerTimeouts(server: Pick<http.Server, 'keepAliveTimeout' | 'headersTimeout' | 'requestTimeout'>, env?: NodeJS.ProcessEnv): HttpServerTimeoutSettings;
|
|
14
21
|
export declare const TASKFORCE_PROXY_ORIGIN_HOST_HEADER = "x-taskforce-origin-host";
|
|
15
22
|
export declare const TASKFORCE_PROXY_ORIGIN_PROTO_HEADER = "x-taskforce-origin-proto";
|
|
16
23
|
export declare const TASKFORCE_PROXY_ORIGIN_BASE_URL_HEADER = "x-taskforce-origin-base-url";
|
|
@@ -18,10 +25,15 @@ export declare const TASKFORCE_PROXY_ORIGIN_RUNTIME_HEADER = "x-taskforce-origin
|
|
|
18
25
|
export declare const TASKFORCE_PROXY_CLOUD_ENVIRONMENT_HEADER = "x-taskforce-cloud-environment";
|
|
19
26
|
interface AuthorizedRequestAccess extends RequestAccessContext {
|
|
20
27
|
disabled?: boolean;
|
|
28
|
+
accountDisabled?: boolean;
|
|
29
|
+
workspaceDisabled?: boolean;
|
|
21
30
|
}
|
|
31
|
+
export declare function isWorkspaceAccessRecoveryRoute(pathname: string): boolean;
|
|
32
|
+
export declare function resolveDisabledAccessError(access: Pick<AuthorizedRequestAccess, 'disabled' | 'accountDisabled' | 'workspaceDisabled'>, pathname: string): string | null;
|
|
22
33
|
export declare function shouldProxyCloudPath(pathname: string): boolean;
|
|
23
34
|
export declare function resolveCloudProxyUpstreamBaseUrl(req: http.IncomingMessage, fallbackBaseUrl: string): string;
|
|
24
35
|
export declare function resolveAuthorizedWorkspaceAccess(core: Pick<TaskforceCore, 'resolveUserAccess' | 'getSystemRole'>, access: AuthorizedRequestAccess, requestedWorkspaceId: string): AuthorizedRequestAccess;
|
|
36
|
+
export declare function shouldApplyReadOnlyMutationGuard(methodRaw: string | undefined, pathname: string): boolean;
|
|
25
37
|
export declare function resolveEffectiveRequestUserId(accessUserId: string, explicitUserId: string): string;
|
|
26
38
|
export declare function resolveMaxPayloadBytesForPath(pathname: string, defaultMaxBytes: number): number;
|
|
27
39
|
export declare function shouldRewriteSetCookieForLocalDevHost(hostHeader: string | undefined): boolean;
|
package/dist/server/index.js
CHANGED
|
@@ -84,11 +84,85 @@ const CORS_RESPONSE_HEADERS = new Set([
|
|
|
84
84
|
'access-control-max-age',
|
|
85
85
|
'vary'
|
|
86
86
|
]);
|
|
87
|
+
const REFRESH_DIAGNOSTIC_PATH_PREFIXES = [
|
|
88
|
+
'/api/taskforce/auth/session',
|
|
89
|
+
'/api/taskforce/config',
|
|
90
|
+
'/api/taskforce/tasks',
|
|
91
|
+
'/api/taskforce/archive',
|
|
92
|
+
'/api/taskforce/workspaces',
|
|
93
|
+
'/api/taskforce/workspace/assignee-options',
|
|
94
|
+
'/api/taskforce/auth/workspace-members',
|
|
95
|
+
'/api/taskforce/taxonomy-state',
|
|
96
|
+
'/api/taskforce/categories',
|
|
97
|
+
'/api/taskforce/types',
|
|
98
|
+
'/api/taskforce/priorities',
|
|
99
|
+
'/api/taskforce/taxonomies',
|
|
100
|
+
'/api/taskforce/initiative-templates',
|
|
101
|
+
'/api/taskforce/workflow-templates',
|
|
102
|
+
'/api/taskforce/workflow-editor/overrides',
|
|
103
|
+
'/api/taskforce/environments',
|
|
104
|
+
'/api/taskforce/sync/'
|
|
105
|
+
];
|
|
106
|
+
const REFRESH_DIAGNOSTIC_DURATION_MS = 100;
|
|
107
|
+
const DEFAULT_HTTP_KEEP_ALIVE_TIMEOUT_MS = 65_000;
|
|
108
|
+
const DEFAULT_HTTP_HEADERS_TIMEOUT_MS = 70_000;
|
|
109
|
+
const DEFAULT_HTTP_REQUEST_TIMEOUT_MS = 120_000;
|
|
110
|
+
export function resolveHttpServerTimeoutSettings(env = process.env) {
|
|
111
|
+
const keepAliveTimeoutMs = readPositiveInteger(env.TASKFORCE_HTTP_KEEP_ALIVE_TIMEOUT_MS, DEFAULT_HTTP_KEEP_ALIVE_TIMEOUT_MS);
|
|
112
|
+
const configuredHeadersTimeoutMs = readPositiveInteger(env.TASKFORCE_HTTP_HEADERS_TIMEOUT_MS, DEFAULT_HTTP_HEADERS_TIMEOUT_MS);
|
|
113
|
+
const headersTimeoutMs = Math.max(configuredHeadersTimeoutMs, keepAliveTimeoutMs + 5_000);
|
|
114
|
+
const requestTimeoutMs = readPositiveInteger(env.TASKFORCE_HTTP_REQUEST_TIMEOUT_MS, DEFAULT_HTTP_REQUEST_TIMEOUT_MS);
|
|
115
|
+
return {
|
|
116
|
+
keepAliveTimeoutMs,
|
|
117
|
+
headersTimeoutMs,
|
|
118
|
+
requestTimeoutMs
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
export function configureHttpServerTimeouts(server, env = process.env) {
|
|
122
|
+
const settings = resolveHttpServerTimeoutSettings(env);
|
|
123
|
+
server.keepAliveTimeout = settings.keepAliveTimeoutMs;
|
|
124
|
+
server.headersTimeout = settings.headersTimeoutMs;
|
|
125
|
+
server.requestTimeout = settings.requestTimeoutMs;
|
|
126
|
+
return settings;
|
|
127
|
+
}
|
|
87
128
|
export const TASKFORCE_PROXY_ORIGIN_HOST_HEADER = 'x-taskforce-origin-host';
|
|
88
129
|
export const TASKFORCE_PROXY_ORIGIN_PROTO_HEADER = 'x-taskforce-origin-proto';
|
|
89
130
|
export const TASKFORCE_PROXY_ORIGIN_BASE_URL_HEADER = 'x-taskforce-origin-base-url';
|
|
90
131
|
export const TASKFORCE_PROXY_ORIGIN_RUNTIME_HEADER = 'x-taskforce-origin-runtime';
|
|
91
132
|
export const TASKFORCE_PROXY_CLOUD_ENVIRONMENT_HEADER = 'x-taskforce-cloud-environment';
|
|
133
|
+
export function isWorkspaceAccessRecoveryRoute(pathname) {
|
|
134
|
+
return pathname === '/api/taskforce/workspaces'
|
|
135
|
+
|| pathname === '/api/taskforce/session/workspace';
|
|
136
|
+
}
|
|
137
|
+
export function resolveDisabledAccessError(access, pathname) {
|
|
138
|
+
if (pathname.startsWith('/api/taskforce/auth/'))
|
|
139
|
+
return null;
|
|
140
|
+
if (access.accountDisabled ?? access.disabled) {
|
|
141
|
+
return 'Forbidden: user account is disabled.';
|
|
142
|
+
}
|
|
143
|
+
if (access.workspaceDisabled && !isWorkspaceAccessRecoveryRoute(pathname)) {
|
|
144
|
+
return 'Forbidden: workspace access is not active for this user.';
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
function shouldLogRefreshDiagnostic(pathname) {
|
|
149
|
+
return REFRESH_DIAGNOSTIC_PATH_PREFIXES.some((prefix) => pathname === prefix || pathname.startsWith(prefix));
|
|
150
|
+
}
|
|
151
|
+
function getRequestTimingNow() {
|
|
152
|
+
return Date.now();
|
|
153
|
+
}
|
|
154
|
+
function isCloudOwnedUserAvatarContextPath(pathname) {
|
|
155
|
+
const prefix = '/api/taskforce/context/';
|
|
156
|
+
if (!pathname.startsWith(prefix))
|
|
157
|
+
return false;
|
|
158
|
+
try {
|
|
159
|
+
const decodedPath = decodeURIComponent(pathname.slice(prefix.length)).replace(/\\/g, '/');
|
|
160
|
+
return /^users\/[^/]+\/profile\/avatar\/[^/]+$/i.test(decodedPath);
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
92
166
|
export function shouldProxyCloudPath(pathname) {
|
|
93
167
|
if (!pathname)
|
|
94
168
|
return false;
|
|
@@ -114,6 +188,7 @@ export function shouldProxyCloudPath(pathname) {
|
|
|
114
188
|
|| pathname.startsWith('/api/taskforce/admin/')
|
|
115
189
|
|| pathname.startsWith('/api/taskforce/billing/')
|
|
116
190
|
|| pathname.startsWith('/api/taskforce/auth/')
|
|
191
|
+
|| isCloudOwnedUserAvatarContextPath(pathname)
|
|
117
192
|
|| pathname.startsWith('/api/taskforce/settings/mcp/')
|
|
118
193
|
|| pathname.startsWith('/api/platform/')
|
|
119
194
|
|| pathname.startsWith('/api/taskforce/sync/');
|
|
@@ -142,11 +217,27 @@ export function resolveAuthorizedWorkspaceAccess(core, access, requestedWorkspac
|
|
|
142
217
|
workspaceId: resolved.workspaceId,
|
|
143
218
|
userId: resolved.userId,
|
|
144
219
|
systemRole: core.getSystemRole(resolved.userId),
|
|
145
|
-
disabled: resolved.disabled
|
|
220
|
+
disabled: resolved.disabled,
|
|
221
|
+
accountDisabled: resolved.accountDisabled ?? resolved.disabled,
|
|
222
|
+
workspaceDisabled: resolved.workspaceDisabled ?? false
|
|
146
223
|
};
|
|
147
224
|
}
|
|
148
225
|
return access;
|
|
149
226
|
}
|
|
227
|
+
export function shouldApplyReadOnlyMutationGuard(methodRaw, pathname) {
|
|
228
|
+
const method = String(methodRaw || 'GET').toUpperCase();
|
|
229
|
+
if (method !== 'POST' && method !== 'PATCH' && method !== 'DELETE')
|
|
230
|
+
return false;
|
|
231
|
+
if (!pathname.startsWith('/api/taskforce/'))
|
|
232
|
+
return false;
|
|
233
|
+
if (pathname.startsWith('/api/taskforce/auth/'))
|
|
234
|
+
return false;
|
|
235
|
+
if (pathname === '/api/taskforce/health')
|
|
236
|
+
return false;
|
|
237
|
+
if (method === 'POST' && pathname === '/api/taskforce/session/workspace')
|
|
238
|
+
return false;
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
150
241
|
export function resolveEffectiveRequestUserId(accessUserId, explicitUserId) {
|
|
151
242
|
const normalizedAccessUserId = String(accessUserId || '').trim();
|
|
152
243
|
if (normalizedAccessUserId && normalizedAccessUserId !== 'anonymous') {
|
|
@@ -163,6 +254,10 @@ export function resolveMaxPayloadBytesForPath(pathname, defaultMaxBytes) {
|
|
|
163
254
|
// Sync routes (especially applying local changes) often include large binary attachments
|
|
164
255
|
return Math.max(defaultMaxBytes, 50 * 1024 * 1024);
|
|
165
256
|
}
|
|
257
|
+
if (pathname === '/api/taskforce/ui-state') {
|
|
258
|
+
// Workspace-sync UI state can carry large baselines; keep the global guard aligned with its route parser.
|
|
259
|
+
return Math.max(defaultMaxBytes, 50 * 1024 * 1024);
|
|
260
|
+
}
|
|
166
261
|
return defaultMaxBytes;
|
|
167
262
|
}
|
|
168
263
|
export function shouldRewriteSetCookieForLocalDevHost(hostHeader) {
|
|
@@ -259,6 +354,7 @@ export function shouldApplyAuthRateLimitForPath(pathname) {
|
|
|
259
354
|
const normalizedPath = String(pathname || '').trim();
|
|
260
355
|
return normalizedPath.startsWith('/api/taskforce/auth/')
|
|
261
356
|
&& normalizedPath !== '/api/taskforce/auth/session'
|
|
357
|
+
&& normalizedPath !== '/api/taskforce/auth/providers'
|
|
262
358
|
&& normalizedPath !== '/api/taskforce/auth/runtime-config'
|
|
263
359
|
&& normalizedPath !== '/api/taskforce/auth/admin-session';
|
|
264
360
|
}
|
|
@@ -458,6 +554,17 @@ export function createStandaloneServer(options) {
|
|
|
458
554
|
statusCode
|
|
459
555
|
}, counterKeys);
|
|
460
556
|
};
|
|
557
|
+
const logRefreshDiagnostic = (input) => {
|
|
558
|
+
const { pathname, method, statusCode, durationMs, req } = input;
|
|
559
|
+
if (!shouldLogRefreshDiagnostic(pathname))
|
|
560
|
+
return;
|
|
561
|
+
if (durationMs < REFRESH_DIAGNOSTIC_DURATION_MS && statusCode < 400)
|
|
562
|
+
return;
|
|
563
|
+
const requestId = String(req.headers['x-request-id'] || req.headers['x-railway-request-id'] || '').trim() || '-';
|
|
564
|
+
const workspaceId = String(req.headers['x-taskforce-workspace-id'] || '').trim() || '-';
|
|
565
|
+
const userId = String(req.headers['x-taskforce-user-id'] || '').trim() || '-';
|
|
566
|
+
console.info(`[Taskforce RefreshDiag] method=${method} path=${pathname} status=${statusCode} durationMs=${durationMs} requestId=${requestId} workspaceId=${workspaceId} userId=${userId}`);
|
|
567
|
+
};
|
|
461
568
|
// Resolve static files directory at runtime
|
|
462
569
|
// Standalone UI source now lives in apps/app and builds to dist/ui.
|
|
463
570
|
// When built: dist/server/index.js -> dist/ui/
|
|
@@ -514,6 +621,7 @@ export function createStandaloneServer(options) {
|
|
|
514
621
|
const integritySchedulePollMinutes = readPositiveInteger(process.env.TASKFORCE_STORAGE_INTEGRITY_SCHEDULE_POLL_MINUTES, 1);
|
|
515
622
|
console.log(`[Taskforce] Storage integrity scheduler poll: every ${integritySchedulePollMinutes} minute(s)`);
|
|
516
623
|
const server = http.createServer(async (req, res) => {
|
|
624
|
+
const requestStartedAt = getRequestTimingNow();
|
|
517
625
|
if (!distUiPath) {
|
|
518
626
|
uiResolution = resolveStaticUiPath();
|
|
519
627
|
distUiPath = uiResolution.uiPath;
|
|
@@ -568,11 +676,12 @@ export function createStandaloneServer(options) {
|
|
|
568
676
|
const hasBody = method !== 'GET' && method !== 'HEAD';
|
|
569
677
|
const requestMaxPayload = resolveMaxPayloadBytesForPath(url.pathname, maxPayloadBytes);
|
|
570
678
|
const body = hasBody ? await readRequestBody(req, requestMaxPayload) : undefined;
|
|
679
|
+
const shouldStreamCloudAvatar = method === 'GET' && isCloudOwnedUserAvatarContextPath(url.pathname);
|
|
571
680
|
const upstream = await fetch(upstreamUrl, {
|
|
572
681
|
method,
|
|
573
682
|
headers,
|
|
574
683
|
body: body && body.length > 0 ? new Uint8Array(body) : undefined,
|
|
575
|
-
redirect: 'manual'
|
|
684
|
+
redirect: shouldStreamCloudAvatar ? 'follow' : 'manual'
|
|
576
685
|
});
|
|
577
686
|
const outgoingHeaders = {};
|
|
578
687
|
for (const [key, value] of upstream.headers.entries()) {
|
|
@@ -714,19 +823,16 @@ export function createStandaloneServer(options) {
|
|
|
714
823
|
return;
|
|
715
824
|
}
|
|
716
825
|
const pathname = url.pathname;
|
|
717
|
-
const isMutation = (req.method
|
|
718
|
-
&& pathname.startsWith('/api/taskforce/')
|
|
719
|
-
&& !pathname.startsWith('/api/taskforce/auth/')
|
|
720
|
-
&& pathname !== '/api/taskforce/health';
|
|
826
|
+
const isMutation = shouldApplyReadOnlyMutationGuard(req.method, pathname);
|
|
721
827
|
let access = accessForRateLimit;
|
|
722
|
-
const isAuthRoute = pathname.startsWith('/api/taskforce/auth/');
|
|
723
828
|
if (access.authenticated) {
|
|
724
829
|
access = resolveAuthorizedWorkspaceAccess(core, access, Array.isArray(req.headers['x-taskforce-workspace-id'])
|
|
725
830
|
? String(req.headers['x-taskforce-workspace-id'][0] || '')
|
|
726
831
|
: String(req.headers['x-taskforce-workspace-id'] || ''));
|
|
727
|
-
|
|
832
|
+
const disabledAccessError = resolveDisabledAccessError(access, pathname);
|
|
833
|
+
if (disabledAccessError) {
|
|
728
834
|
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
729
|
-
res.end(JSON.stringify({ error:
|
|
835
|
+
res.end(JSON.stringify({ error: disabledAccessError }));
|
|
730
836
|
return;
|
|
731
837
|
}
|
|
732
838
|
}
|
|
@@ -756,6 +862,13 @@ export function createStandaloneServer(options) {
|
|
|
756
862
|
res.writeHead = originalWriteHead;
|
|
757
863
|
const finalStatus = Number.isFinite(Number(observedStatusCode)) ? Number(observedStatusCode) : 200;
|
|
758
864
|
recordCollaborationRouteTelemetry(url.pathname, req.method || 'GET', finalStatus);
|
|
865
|
+
logRefreshDiagnostic({
|
|
866
|
+
pathname: url.pathname,
|
|
867
|
+
method: String(req.method || 'GET').toUpperCase(),
|
|
868
|
+
statusCode: finalStatus,
|
|
869
|
+
durationMs: Math.max(0, Math.round(getRequestTimingNow() - requestStartedAt)),
|
|
870
|
+
req
|
|
871
|
+
});
|
|
759
872
|
}
|
|
760
873
|
return;
|
|
761
874
|
}
|
|
@@ -789,6 +902,8 @@ export function createStandaloneServer(options) {
|
|
|
789
902
|
res.writeHead(404);
|
|
790
903
|
res.end('Not Found');
|
|
791
904
|
});
|
|
905
|
+
const timeoutSettings = configureHttpServerTimeouts(server);
|
|
906
|
+
console.log(`[Taskforce] HTTP timeouts: keepAlive=${timeoutSettings.keepAliveTimeoutMs}ms headers=${timeoutSettings.headersTimeoutMs}ms request=${timeoutSettings.requestTimeoutMs}ms`);
|
|
792
907
|
// WebSocket server at /Taskforce-ws path
|
|
793
908
|
const wss = new WebSocketServer({ server, path: '/taskforce-ws' });
|
|
794
909
|
const realtimeWsManager = createRealtimeSyncWsManager(core, authConfig);
|
|
@@ -7,6 +7,9 @@ describe('shouldApplyAuthRateLimitForPath', () => {
|
|
|
7
7
|
it('excludes auth session endpoint', () => {
|
|
8
8
|
expect(shouldApplyAuthRateLimitForPath('/api/taskforce/auth/session')).toBe(false);
|
|
9
9
|
});
|
|
10
|
+
it('excludes auth providers metadata endpoint', () => {
|
|
11
|
+
expect(shouldApplyAuthRateLimitForPath('/api/taskforce/auth/providers')).toBe(false);
|
|
12
|
+
});
|
|
10
13
|
it('excludes runtime config bootstrap endpoint', () => {
|
|
11
14
|
expect(shouldApplyAuthRateLimitForPath('/api/taskforce/auth/runtime-config')).toBe(false);
|
|
12
15
|
});
|
|
@@ -1,6 +1,42 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { ensureBillingWebhookAuthExclusion, ensurePublicSiteConfigAuthExclusion, isBillingWebhookPath, rewriteProxySetCookieForLocalHost, resolveEffectiveRequestUserId, resolveAuthorizedWorkspaceAccess, shouldRewriteProxySetCookieDomain, shouldApplyAuthRateLimitForPath, shouldProxyCloudPath, writeJsonErrorIfPossible } from './index.js';
|
|
2
|
+
import { ensureBillingWebhookAuthExclusion, ensurePublicSiteConfigAuthExclusion, configureHttpServerTimeouts, isBillingWebhookPath, rewriteProxySetCookieForLocalHost, resolveHttpServerTimeoutSettings, resolveEffectiveRequestUserId, resolveAuthorizedWorkspaceAccess, resolveDisabledAccessError, resolveMaxPayloadBytesForPath, shouldApplyReadOnlyMutationGuard, shouldRewriteProxySetCookieDomain, shouldApplyAuthRateLimitForPath, shouldProxyCloudPath, writeJsonErrorIfPossible } from './index.js';
|
|
3
3
|
describe('server index helper policies', () => {
|
|
4
|
+
it('uses proxy-friendly HTTP server timeouts by default', () => {
|
|
5
|
+
const settings = resolveHttpServerTimeoutSettings({});
|
|
6
|
+
expect(settings.keepAliveTimeoutMs).toBe(65_000);
|
|
7
|
+
expect(settings.headersTimeoutMs).toBe(70_000);
|
|
8
|
+
expect(settings.requestTimeoutMs).toBe(120_000);
|
|
9
|
+
});
|
|
10
|
+
it('keeps headers timeout above keep-alive timeout for reverse proxies', () => {
|
|
11
|
+
const settings = resolveHttpServerTimeoutSettings({
|
|
12
|
+
TASKFORCE_HTTP_KEEP_ALIVE_TIMEOUT_MS: '80000',
|
|
13
|
+
TASKFORCE_HTTP_HEADERS_TIMEOUT_MS: '1000',
|
|
14
|
+
TASKFORCE_HTTP_REQUEST_TIMEOUT_MS: '150000'
|
|
15
|
+
});
|
|
16
|
+
expect(settings.keepAliveTimeoutMs).toBe(80_000);
|
|
17
|
+
expect(settings.headersTimeoutMs).toBe(85_000);
|
|
18
|
+
expect(settings.requestTimeoutMs).toBe(150_000);
|
|
19
|
+
});
|
|
20
|
+
it('applies resolved HTTP server timeouts to the Node server', () => {
|
|
21
|
+
const server = {
|
|
22
|
+
keepAliveTimeout: 0,
|
|
23
|
+
headersTimeout: 0,
|
|
24
|
+
requestTimeout: 0
|
|
25
|
+
};
|
|
26
|
+
const settings = configureHttpServerTimeouts(server, {
|
|
27
|
+
TASKFORCE_HTTP_KEEP_ALIVE_TIMEOUT_MS: '61000',
|
|
28
|
+
TASKFORCE_HTTP_HEADERS_TIMEOUT_MS: '66000',
|
|
29
|
+
TASKFORCE_HTTP_REQUEST_TIMEOUT_MS: '90000'
|
|
30
|
+
});
|
|
31
|
+
expect(settings).toEqual({
|
|
32
|
+
keepAliveTimeoutMs: 61_000,
|
|
33
|
+
headersTimeoutMs: 66_000,
|
|
34
|
+
requestTimeoutMs: 90_000
|
|
35
|
+
});
|
|
36
|
+
expect(server.keepAliveTimeout).toBe(61_000);
|
|
37
|
+
expect(server.headersTimeout).toBe(66_000);
|
|
38
|
+
expect(server.requestTimeout).toBe(90_000);
|
|
39
|
+
});
|
|
4
40
|
it('adds webhook path to auth exclusions without duplicates', () => {
|
|
5
41
|
const base = ['/api/taskforce/health', '/api/taskforce/auth'];
|
|
6
42
|
const next = ensureBillingWebhookAuthExclusion(base);
|
|
@@ -24,6 +60,11 @@ describe('server index helper policies', () => {
|
|
|
24
60
|
expect(shouldApplyAuthRateLimitForPath('/api/taskforce/auth/session')).toBe(false);
|
|
25
61
|
expect(shouldApplyAuthRateLimitForPath('/api/taskforce/billing/webhook')).toBe(false);
|
|
26
62
|
});
|
|
63
|
+
it('allows workspace sync-sized ui-state payloads through the global guard', () => {
|
|
64
|
+
expect(resolveMaxPayloadBytesForPath('/api/taskforce/ui-state', 1_048_576)).toBe(50 * 1024 * 1024);
|
|
65
|
+
expect(resolveMaxPayloadBytesForPath('/api/taskforce/sync/workspace/push', 1_048_576)).toBe(50 * 1024 * 1024);
|
|
66
|
+
expect(resolveMaxPayloadBytesForPath('/api/taskforce/task', 1_048_576)).toBe(1_048_576);
|
|
67
|
+
});
|
|
27
68
|
it('writes a json error when headers are still available', () => {
|
|
28
69
|
let headersSent = false;
|
|
29
70
|
let writableEnded = false;
|
|
@@ -82,6 +123,12 @@ describe('shouldProxyCloudPath', () => {
|
|
|
82
123
|
expect(shouldProxyCloudPath('/api/taskforce/sync/workspace/pull')).toBe(true);
|
|
83
124
|
expect(shouldProxyCloudPath('/api/taskforce/sync/workspace/push')).toBe(true);
|
|
84
125
|
});
|
|
126
|
+
it('proxies cloud-owned user avatar context paths only', () => {
|
|
127
|
+
expect(shouldProxyCloudPath('/api/taskforce/context/users%2Fuser-1%2Fprofile%2Favatar%2Favatar.webp')).toBe(true);
|
|
128
|
+
expect(shouldProxyCloudPath('/api/taskforce/context/users/user-1/profile/avatar/avatar.webp')).toBe(true);
|
|
129
|
+
expect(shouldProxyCloudPath('/api/taskforce/context/workspaces%2Fworkspace-1%2Fassets%2Fimages%2Fasset.png')).toBe(false);
|
|
130
|
+
expect(shouldProxyCloudPath('/api/taskforce/context/users%2Fuser-1%2Fexports%2Favatar.webp')).toBe(false);
|
|
131
|
+
});
|
|
85
132
|
it('proxies admin, billing, and auth routes', () => {
|
|
86
133
|
expect(shouldProxyCloudPath('/api/taskforce/admin/users')).toBe(true);
|
|
87
134
|
expect(shouldProxyCloudPath('/api/taskforce/billing/plans')).toBe(true);
|
|
@@ -91,6 +138,11 @@ describe('shouldProxyCloudPath', () => {
|
|
|
91
138
|
expect(shouldProxyCloudPath('/api/taskforce/public/site-config')).toBe(true);
|
|
92
139
|
expect(shouldProxyCloudPath('/api/taskforce/public/site-config-script')).toBe(true);
|
|
93
140
|
});
|
|
141
|
+
it('keeps AI profile workspace mutations local so workspace sync owns replication', () => {
|
|
142
|
+
expect(shouldProxyCloudPath('/api/taskforce/workspace/ai-profiles/avatar')).toBe(false);
|
|
143
|
+
expect(shouldProxyCloudPath('/api/taskforce/workspace/ai-profiles/archive')).toBe(false);
|
|
144
|
+
expect(shouldProxyCloudPath('/api/taskforce/workspace/ai-profiles/merge')).toBe(false);
|
|
145
|
+
});
|
|
94
146
|
});
|
|
95
147
|
describe('proxy cookie helpers', () => {
|
|
96
148
|
it('rewrites mismatched cookie domains for non-loopback local hosts', () => {
|
|
@@ -126,7 +178,8 @@ describe('resolveAuthorizedWorkspaceAccess', () => {
|
|
|
126
178
|
userId: 'user-1',
|
|
127
179
|
workspaceId: 'workspace-personal',
|
|
128
180
|
role: 'member',
|
|
129
|
-
systemRole: 'user'
|
|
181
|
+
systemRole: 'user',
|
|
182
|
+
identityId: null
|
|
130
183
|
}, 'workspace-team');
|
|
131
184
|
expect(core.resolveUserAccess).toHaveBeenCalledWith('user-1', 'workspace-team', 'member');
|
|
132
185
|
expect(next.workspaceId).toBe('workspace-team');
|
|
@@ -154,12 +207,67 @@ describe('resolveAuthorizedWorkspaceAccess', () => {
|
|
|
154
207
|
userId: 'user-1',
|
|
155
208
|
workspaceId: 'workspace-personal',
|
|
156
209
|
role: 'member',
|
|
157
|
-
systemRole: 'user'
|
|
210
|
+
systemRole: 'user',
|
|
211
|
+
identityId: null
|
|
158
212
|
}, 'workspace-team');
|
|
159
213
|
expect(core.resolveUserAccess).toHaveBeenNthCalledWith(1, 'user-1', 'workspace-team', 'member');
|
|
160
214
|
expect(core.resolveUserAccess).toHaveBeenNthCalledWith(2, 'user-1', 'workspace-personal', 'member');
|
|
161
215
|
expect(next.workspaceId).toBe('workspace-personal');
|
|
162
216
|
});
|
|
217
|
+
it('preserves account and workspace disabled scopes separately', () => {
|
|
218
|
+
const core = {
|
|
219
|
+
resolveUserAccess: vi.fn((userId, workspaceId, role) => ({
|
|
220
|
+
userId,
|
|
221
|
+
workspaceId,
|
|
222
|
+
role,
|
|
223
|
+
permissionMode: 'read-write',
|
|
224
|
+
disabled: true,
|
|
225
|
+
accountDisabled: false,
|
|
226
|
+
workspaceDisabled: true,
|
|
227
|
+
betaAccess: true
|
|
228
|
+
})),
|
|
229
|
+
getSystemRole: vi.fn(() => 'user')
|
|
230
|
+
};
|
|
231
|
+
const next = resolveAuthorizedWorkspaceAccess(core, {
|
|
232
|
+
authenticated: true,
|
|
233
|
+
sessionId: 'session-1',
|
|
234
|
+
userId: 'user-1',
|
|
235
|
+
workspaceId: 'workspace-shared',
|
|
236
|
+
role: 'member',
|
|
237
|
+
systemRole: 'user',
|
|
238
|
+
identityId: null
|
|
239
|
+
}, 'workspace-shared');
|
|
240
|
+
expect(next.disabled).toBe(true);
|
|
241
|
+
expect(next.accountDisabled).toBe(false);
|
|
242
|
+
expect(next.workspaceDisabled).toBe(true);
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
describe('resolveDisabledAccessError', () => {
|
|
246
|
+
it('blocks globally disabled accounts outside auth routes', () => {
|
|
247
|
+
expect(resolveDisabledAccessError({ disabled: true, accountDisabled: true }, '/api/taskforce/workspaces')).toBe('Forbidden: user account is disabled.');
|
|
248
|
+
expect(resolveDisabledAccessError({ disabled: true, accountDisabled: true }, '/api/taskforce/auth/session')).toBeNull();
|
|
249
|
+
});
|
|
250
|
+
it('allows workspace-disabled sessions to reach recovery routes only', () => {
|
|
251
|
+
const access = { disabled: true, accountDisabled: false, workspaceDisabled: true };
|
|
252
|
+
expect(resolveDisabledAccessError(access, '/api/taskforce/workspaces')).toBeNull();
|
|
253
|
+
expect(resolveDisabledAccessError(access, '/api/taskforce/session/workspace')).toBeNull();
|
|
254
|
+
expect(resolveDisabledAccessError(access, '/api/taskforce/tasks')).toBe('Forbidden: workspace access is not active for this user.');
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
describe('shouldApplyReadOnlyMutationGuard', () => {
|
|
258
|
+
it('guards ordinary Taskforce mutations', () => {
|
|
259
|
+
expect(shouldApplyReadOnlyMutationGuard('POST', '/api/taskforce/tasks')).toBe(true);
|
|
260
|
+
expect(shouldApplyReadOnlyMutationGuard('PATCH', '/api/taskforce/task/task-1')).toBe(true);
|
|
261
|
+
expect(shouldApplyReadOnlyMutationGuard('DELETE', '/api/taskforce/task/task-1')).toBe(true);
|
|
262
|
+
});
|
|
263
|
+
it('allows session workspace switching through route-level access validation', () => {
|
|
264
|
+
expect(shouldApplyReadOnlyMutationGuard('POST', '/api/taskforce/session/workspace')).toBe(false);
|
|
265
|
+
});
|
|
266
|
+
it('does not guard non-mutations, auth routes, or health checks', () => {
|
|
267
|
+
expect(shouldApplyReadOnlyMutationGuard('GET', '/api/taskforce/tasks')).toBe(false);
|
|
268
|
+
expect(shouldApplyReadOnlyMutationGuard('POST', '/api/taskforce/auth/login')).toBe(false);
|
|
269
|
+
expect(shouldApplyReadOnlyMutationGuard('POST', '/api/taskforce/health')).toBe(false);
|
|
270
|
+
});
|
|
163
271
|
});
|
|
164
272
|
describe('resolveEffectiveRequestUserId', () => {
|
|
165
273
|
it('prefers the authenticated access user when present', () => {
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Routes registered here:
|
|
9
9
|
* GET/POST /api/platform/plans
|
|
10
|
+
* GET /api/platform/onboarding-plan-options
|
|
10
11
|
* GET/POST /api/platform/plans/:planId/versions
|
|
11
12
|
* GET /api/platform/features
|
|
12
13
|
* GET/PATCH /api/platform/plans/:planId/versions/:versionId/features
|
|
@@ -23,6 +24,8 @@
|
|
|
23
24
|
* GET/POST /api/taskforce/admin/email-settings
|
|
24
25
|
* GET /api/taskforce/admin/email-settings/health
|
|
25
26
|
* POST /api/taskforce/admin/email-settings/test
|
|
27
|
+
* GET/POST /api/taskforce/admin/auth-provider-settings
|
|
28
|
+
* GET /api/taskforce/admin/auth-provider-settings/health
|
|
26
29
|
* GET/POST /api/taskforce/admin/system-settings
|
|
27
30
|
* GET/POST /api/taskforce/admin/object-storage-settings
|
|
28
31
|
* GET /api/taskforce/admin/object-storage-telemetry
|