@taskforcehq/taskforce 0.3.302 → 0.3.304
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/dist/Taskforce.module.css +113 -5
- package/dist/TaskforceCore.js +560 -208
- package/dist/TaskforceCore.test.js +1833 -91
- package/dist/annotatedAttachments/service.d.ts +1 -1
- package/dist/annotatedAttachments/types.d.ts +1 -1
- package/dist/components/features/AgentsModule.js +1 -1
- package/dist/components/features/AgentsModule.test.js +1 -1
- package/dist/components/features/TaskSettings.js +58 -38
- package/dist/components/features/TaskSettings.test.js +139 -40
- package/dist/components/task/TaskActionHeader.d.ts +2 -1
- package/dist/components/task/TaskActionHeader.js +3 -3
- package/dist/components/task/TaskActionHeader.test.js +8 -0
- package/dist/components/task/TaskCard.js +16 -1
- package/dist/components/task/TaskCard.test.js +31 -0
- package/dist/components/task/TaskForm.d.ts +2 -1
- package/dist/components/task/TaskForm.js +22 -4
- package/dist/components/task/TaskForm.test.js +46 -0
- package/dist/components/task/TaskKanban.d.ts +1 -1
- package/dist/components/task/TaskKanban.js +31 -160
- package/dist/components/task/TaskKanban.test.js +17 -0
- package/dist/components/task/TaskStatusActions.d.ts +6 -1
- package/dist/components/task/TaskStatusActions.js +8 -3
- package/dist/components/task/TaskStatusActions.test.js +9 -0
- package/dist/components/task/taskKanbanDropRules.d.ts +58 -0
- package/dist/components/task/taskKanbanDropRules.js +187 -0
- package/dist/components/task/taskKanbanDropRules.test.d.ts +1 -0
- package/dist/components/task/taskKanbanDropRules.test.js +114 -0
- package/dist/components/ui/Modal.d.ts +1 -1
- package/dist/components/ui/Modal.js +1 -0
- package/dist/components/views/AppShellHeader.js +5 -1
- package/dist/components/views/AppShellHeader.test.js +4 -0
- package/dist/components/views/PlanComparisonPage.d.ts +3 -2
- package/dist/components/views/PlanComparisonPage.js +4 -2
- package/dist/components/views/PlanComparisonPage.test.js +4 -0
- package/dist/components/views/PlansPage.d.ts +7 -1
- package/dist/components/views/PlansPage.js +139 -53
- package/dist/components/views/PlansPage.test.d.ts +1 -0
- package/dist/components/views/PlansPage.test.js +157 -0
- package/dist/components/views/StandaloneLayout.d.ts +1 -0
- package/dist/components/views/StandaloneLayout.js +216 -186
- package/dist/components/views/WidgetView.js +11 -2
- package/dist/components/views/standalone/modals/AccountHubModal.d.ts +8 -3
- package/dist/components/views/standalone/modals/AccountHubModal.js +16 -2
- package/dist/components/views/standalone/modals/AccountHubModal.test.d.ts +1 -0
- package/dist/components/views/standalone/modals/AccountHubModal.test.js +26 -0
- package/dist/components/views/standalone/modals/SyncStatusModal.js +1 -1
- package/dist/core/DeletedTaskLifecycleService.d.ts +2 -1
- package/dist/core/EntitlementsPolicy.test.js +2 -2
- package/dist/core/GlobalSettingsService.js +78 -18
- package/dist/core/PlanEntitlementService.d.ts +31 -5
- package/dist/core/PlanEntitlementService.js +350 -222
- package/dist/core/SignupMonetizationSettings.test.js +208 -49
- package/dist/core/SystemAdmin.test.js +186 -96
- package/dist/core/TaskActivityService.d.ts +4 -1
- package/dist/core/TaskActivityService.js +45 -0
- package/dist/core/TaskAuditTimeline.test.js +52 -1
- package/dist/core/Taskforce.d.ts +65 -20
- package/dist/core/Taskforce.js +261 -51
- package/dist/core/Taskforce.mcpAuth.test.js +0 -2
- package/dist/core/UserProfileAvatarDrafts.test.js +12 -3
- package/dist/core/WorkspacePlanMode.test.js +65 -0
- package/dist/core/types.d.ts +11 -12
- package/dist/documentReviews/service.d.ts +1 -1
- package/dist/documentReviews/types.d.ts +1 -1
- package/dist/hooks/auth/useTaskforceAuthBootstrap.d.ts +48 -0
- package/dist/hooks/auth/useTaskforceAuthBootstrap.js +219 -0
- package/dist/hooks/sync/auth.d.ts +37 -0
- package/dist/hooks/sync/auth.js +61 -0
- package/dist/hooks/sync/bootstrap.d.ts +34 -0
- package/dist/hooks/sync/bootstrap.js +52 -0
- package/dist/hooks/sync/orchestratorShared.d.ts +36 -0
- package/dist/hooks/sync/orchestratorShared.js +209 -0
- package/dist/hooks/sync/orchestratorShared.test.d.ts +1 -0
- package/dist/hooks/sync/orchestratorShared.test.js +49 -0
- package/dist/hooks/sync/realtime.d.ts +25 -0
- package/dist/hooks/sync/realtime.js +60 -0
- package/dist/hooks/sync/recovery.d.ts +69 -0
- package/dist/hooks/sync/recovery.js +118 -0
- package/dist/hooks/sync/transfers.d.ts +122 -0
- package/dist/hooks/sync/transfers.js +431 -0
- package/dist/hooks/sync/useDataVersionRefresh.d.ts +16 -0
- package/dist/hooks/sync/useDataVersionRefresh.js +73 -0
- package/dist/hooks/ui/useResourceExport.d.ts +3 -1
- package/dist/hooks/ui/useResourceExport.js +5 -2
- package/dist/hooks/ui/useWorkflowTemplates.js +11 -6
- package/dist/hooks/useRealtimeSync.js +2 -1
- package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +8 -0
- package/dist/hooks/useSyncOrchestrator.context-assets.test.d.ts +1 -0
- package/dist/hooks/useSyncOrchestrator.context-assets.test.js +228 -0
- package/dist/hooks/useSyncOrchestrator.d.ts +5 -4
- package/dist/hooks/useSyncOrchestrator.js +315 -860
- package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +665 -8
- package/dist/hooks/useTaskMutations.js +45 -6
- package/dist/hooks/useTaskMutations.test.js +147 -0
- package/dist/hooks/useTaskforce.d.ts +11 -2
- package/dist/hooks/useTaskforce.js +290 -812
- package/dist/hooks/useWorkspaceSyncController.d.ts +1 -0
- package/dist/hooks/useWorkspaceSyncController.js +22 -10
- package/dist/hooks/workspace/useTaskforceApiRouting.test.js +17 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +166 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +434 -0
- package/dist/hooks/workspace/workspaceLocalState.d.ts +19 -0
- package/dist/hooks/workspace/workspaceLocalState.js +100 -0
- package/dist/hooks/workspace/workspaceLocalState.test.d.ts +1 -0
- package/dist/hooks/workspace/workspaceLocalState.test.js +59 -0
- package/dist/localization/locales/en-US.js +2 -2
- package/dist/mcp/canonicalAssetHelpers.d.ts +70 -0
- package/dist/mcp/canonicalAssetHelpers.js +259 -0
- package/dist/mcp/clientIntegrations.d.ts +12 -1
- package/dist/mcp/clientIntegrations.js +161 -6
- package/dist/mcp/clientIntegrations.test.js +76 -4
- package/dist/mcp/documentHelpers.d.ts +100 -0
- package/dist/mcp/documentHelpers.js +161 -0
- package/dist/mcp/runtime.js +264 -505
- package/dist/mcp/runtime.test.js +353 -89
- package/dist/mcp/taskAttachmentHelpers.d.ts +41 -0
- package/dist/mcp/taskAttachmentHelpers.js +60 -0
- package/dist/mcp/taskAttachmentTypes.d.ts +37 -0
- package/dist/mcp/taskAttachmentTypes.js +1 -0
- package/dist/migrations/billingSchemaParity.test.js +3 -0
- package/dist/migrations/taskSchemaMigrations.js +15 -0
- package/dist/plugins/vite.js +1 -1
- package/dist/runtime/appGateDefinitions.d.ts +1 -1
- package/dist/runtime/appGateDefinitions.js +1 -1
- package/dist/server/index.cookieProxy.test.js +1 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +48 -3
- package/dist/server/index.test.js +14 -2
- package/dist/server/mockStripe.d.ts +1 -0
- package/dist/server/mockStripe.js +2 -0
- package/dist/server/routes/admin.js +91 -40
- package/dist/server/routes/auth.d.ts +1 -0
- package/dist/server/routes/auth.js +231 -55
- package/dist/server/routes/billing.js +473 -39
- package/dist/server/routes/billing.test.js +972 -37
- package/dist/server/routes/shared.d.ts +30 -0
- package/dist/server/routes/shared.js +31 -3
- package/dist/server/routes/sync.integration.test.js +180 -0
- package/dist/server/routes/sync.js +125 -242
- package/dist/server/routes/tasks.js +49 -7
- package/dist/server/routes.js +11 -22
- package/dist/server/routes.test.js +530 -81
- package/dist/shared/taskActor.d.ts +10 -0
- package/dist/shared/taskActor.js +1 -0
- package/dist/sync/cloudSyncApi.d.ts +1 -0
- package/dist/sync/collaborationSyncPayload.js +4 -0
- package/dist/sync/collaborationSyncPayload.test.js +8 -0
- package/dist/sync/collaborationSyncState.d.ts +3 -1
- package/dist/sync/collaborationSyncState.js +19 -0
- package/dist/sync/contentSyncState.d.ts +10 -0
- package/dist/sync/contentSyncState.js +277 -14
- package/dist/sync/syncApplyHandlers.d.ts +87 -1
- package/dist/sync/syncApplyHandlers.js +370 -8
- package/dist/sync/syncApplyHandlers.test.d.ts +1 -0
- package/dist/sync/syncApplyHandlers.test.js +377 -0
- package/dist/sync/syncService.d.ts +9 -1
- package/dist/sync/syncService.js +57 -10
- package/dist/sync/syncService.test.js +48 -0
- package/dist/sync/workspacePullFeed.d.ts +11 -0
- package/dist/sync/workspacePullFeed.js +123 -68
- package/dist/sync/workspacePullFeed.test.js +180 -0
- package/dist/sync/workspaceSyncModel.d.ts +22 -1
- package/dist/sync/workspaceSyncModel.js +65 -0
- package/dist/sync/workspaceSyncModel.test.js +119 -0
- package/dist/types.d.ts +2 -10
- package/dist/ui/assets/AgentsModule-BLWVbuKP.js +1 -0
- package/dist/ui/assets/{AnnotatedAttachmentWorkspace-Dvi02Y7q.js → AnnotatedAttachmentWorkspace-BlS-cqnl.js} +1 -1
- package/dist/ui/assets/{DocumentWorkspace-iys3zfca.js → DocumentWorkspace-BH_6DF6x.js} +1 -1
- package/dist/ui/assets/{InitiativesModule-DJvLJI3A.js → InitiativesModule-BjR6iBf9.js} +1 -1
- package/dist/ui/assets/{PlansPage-BlVC_lRq.css → PlansPage-C2dd2n1X.css} +1 -1
- package/dist/ui/assets/PlansPage-CSDQ4sLa.js +1 -0
- package/dist/ui/assets/TaskSettings-CEDy34Jo.js +9 -0
- package/dist/ui/assets/{WorkflowsModule-BguHeQaV.js → WorkflowsModule-DnFqdUME.js} +1 -1
- package/dist/ui/assets/index-DXUdtH1B.js +6 -0
- package/dist/ui/assets/index-Ii0B0rTO.css +1 -0
- package/dist/ui/assets/{vendor-icons-C8EED3Oh.js → vendor-icons-I7ZwG1z_.js} +1 -1
- package/dist/ui/index.html +4 -4
- package/dist/utils/accountProfileSummaryCache.d.ts +31 -0
- package/dist/utils/accountProfileSummaryCache.js +97 -0
- package/dist/utils/accountProfileSummaryCache.test.d.ts +1 -0
- package/dist/utils/accountProfileSummaryCache.test.js +63 -0
- package/dist/utils/taskActivity.js +4 -0
- package/dist/utils/taskActivity.test.js +25 -1
- package/package.json +5 -3
- package/scripts/playwright-auth.sh +4 -0
- package/dist/ui/assets/AgentsModule-JG5jc3he.js +0 -1
- package/dist/ui/assets/PlansPage-BMPlpFpw.js +0 -1
- package/dist/ui/assets/TaskSettings-Bqd4cCzW.js +0 -8
- package/dist/ui/assets/index-MXeWoebC.css +0 -1
- package/dist/ui/assets/index-YJ4k5QNa.js +0 -6
- package/dist/utils/billingStatusCache.d.ts +0 -21
- package/dist/utils/billingStatusCache.js +0 -70
package/dist/core/Taskforce.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { WorkspaceAssetStore } from '../storage/workspaceAssetStore.js';
|
|
|
3
3
|
import { type SyncEventInput } from './SyncReconciliationService.js';
|
|
4
4
|
import { type FirstClassTaxonomyDisplayLabels, type WorkspaceTaxonomyState } from '../shared/taxonomyState.js';
|
|
5
5
|
import { type AiProfileSurfaceType } from '../shared/aiProfileSurfaceType.js';
|
|
6
|
+
import type { TaskActor } from '../shared/taskActor.js';
|
|
7
|
+
export type { TaskActor } from '../shared/taskActor.js';
|
|
6
8
|
export type { WorkspaceDeletedAssetRecord, WorkspaceDeleteSummary } from './types.js';
|
|
7
9
|
import type { GlobalTaskforceSettings, UserGlobalSyncSettings, WorkspaceDeleteSummary } from './types.js';
|
|
8
10
|
import type { AnnotatedAttachmentAnnotation, AnnotatedAttachmentPayload, AnnotatedAttachmentSession, AnnotatedAttachmentSessionRecord } from '../annotatedAttachments/types.js';
|
|
@@ -73,16 +75,6 @@ export interface DeletedTaskRecord {
|
|
|
73
75
|
}
|
|
74
76
|
export type TaskStatus = 'task' | 'on-hold' | 'in-progress' | 'review' | 'done' | 'cancelled';
|
|
75
77
|
export type TaskAssignee = string;
|
|
76
|
-
export interface TaskActor {
|
|
77
|
-
id: string;
|
|
78
|
-
kind: 'human' | 'ai';
|
|
79
|
-
label: string;
|
|
80
|
-
username: string;
|
|
81
|
-
icon: string;
|
|
82
|
-
color: string;
|
|
83
|
-
isNamed: boolean;
|
|
84
|
-
meta?: Record<string, unknown>;
|
|
85
|
-
}
|
|
86
78
|
export interface TaskItem {
|
|
87
79
|
id: string;
|
|
88
80
|
referenceNumber?: number | null;
|
|
@@ -343,14 +335,10 @@ export interface InitiativeTemplate {
|
|
|
343
335
|
milestones: InitiativeTemplateMilestone[];
|
|
344
336
|
}
|
|
345
337
|
type WorkspaceSyncSettingsPayload = Record<string, Record<string, unknown>>;
|
|
346
|
-
type SignupMonetizationStrategy = 'auto_assign_default' | 'plan_selection_required';
|
|
347
|
-
interface SignupMonetizationSettings {
|
|
348
|
-
strategy: SignupMonetizationStrategy;
|
|
349
|
-
defaultSignupPlanVersionId: string | null;
|
|
350
|
-
}
|
|
351
338
|
type AccessRole = 'owner' | 'admin' | 'member' | 'read-only';
|
|
352
339
|
export type SystemRole = 'system_admin' | 'user';
|
|
353
340
|
type PermissionMode = 'read-only' | 'read-write';
|
|
341
|
+
type AuthTokenPurpose = 'email_verification' | 'password_reset' | 'invite_accept';
|
|
354
342
|
export type McpAccessTokenScope = 'tasks:read' | 'tasks:write' | 'workspace:read';
|
|
355
343
|
type McpAccessTokenStatus = 'active' | 'revoked' | 'expired';
|
|
356
344
|
export type McpOAuthProvider = 'chatgpt' | 'claude';
|
|
@@ -453,6 +441,24 @@ interface SystemUserRecord {
|
|
|
453
441
|
updatedAt?: string | null;
|
|
454
442
|
emailVerifiedAt?: string | null;
|
|
455
443
|
}
|
|
444
|
+
export interface PurgedSystemUserSummary {
|
|
445
|
+
targetUserId: string;
|
|
446
|
+
email: string;
|
|
447
|
+
unassignedTaskCount: number;
|
|
448
|
+
clearedInitiativeOwnerCount: number;
|
|
449
|
+
clearedWorkstreamOwnerCount: number;
|
|
450
|
+
deletedWorkspaceMembershipCount: number;
|
|
451
|
+
deletedAuthTokenCount: number;
|
|
452
|
+
deletedAvatarDraftCount: number;
|
|
453
|
+
deletedMcpAccessTokenCount: number;
|
|
454
|
+
deletedMcpOauthAuthCodeCount: number;
|
|
455
|
+
deletedMcpOauthConnectorGrantCount: number;
|
|
456
|
+
deletedUiStateCount: number;
|
|
457
|
+
deletedUserPreferenceCount: number;
|
|
458
|
+
deletedEntitlementCount: number;
|
|
459
|
+
deletedUserBillingCount: number;
|
|
460
|
+
deletedUserCount: number;
|
|
461
|
+
}
|
|
456
462
|
export type SetupState = 'present' | 'missing' | 'unreadable';
|
|
457
463
|
export type RuntimeMode = 'local' | 'cloud';
|
|
458
464
|
export type WorkspaceMode = 'core' | 'operations';
|
|
@@ -529,7 +535,7 @@ interface McpAuditLogRecord {
|
|
|
529
535
|
reasonCode: string | null;
|
|
530
536
|
details: Record<string, unknown>;
|
|
531
537
|
}
|
|
532
|
-
export type EntitlementState = 'active' | 'trialing' | 'grace' | 'suspended' | 'canceled';
|
|
538
|
+
export type EntitlementState = 'pending_plan_selection' | 'checkout_pending' | 'active' | 'trialing' | 'grace' | 'suspended' | 'canceled';
|
|
533
539
|
export type PlanFeatureAccess = 'enabled' | 'disabled' | 'limited';
|
|
534
540
|
export interface PlanFeatureSnapshot {
|
|
535
541
|
featureKey: string;
|
|
@@ -591,6 +597,11 @@ interface PasswordAuthResult {
|
|
|
591
597
|
};
|
|
592
598
|
code?: 'INVALID_CREDENTIALS' | 'EMAIL_NOT_VERIFIED';
|
|
593
599
|
}
|
|
600
|
+
interface AuthTokenInspection {
|
|
601
|
+
state: 'valid' | 'expired' | 'used' | 'missing' | 'revoked';
|
|
602
|
+
userId?: string;
|
|
603
|
+
workspaceId?: string;
|
|
604
|
+
}
|
|
594
605
|
export interface McpAccessTokenRecord {
|
|
595
606
|
id: string;
|
|
596
607
|
workspaceId: string;
|
|
@@ -736,6 +747,9 @@ export interface TaskforceSyncCapable {
|
|
|
736
747
|
workspaceId?: string | null;
|
|
737
748
|
includeDeleted?: boolean;
|
|
738
749
|
}): AnnotatedAttachmentSessionRecord[];
|
|
750
|
+
listTaskEventsForSync(input: {
|
|
751
|
+
workspaceId?: string | null;
|
|
752
|
+
}): TaskEvent[];
|
|
739
753
|
upsertAiProfileForSync(profile: AiProfileRecord): AiProfileRecord;
|
|
740
754
|
replaceWorkspaceUsersForSync(input: {
|
|
741
755
|
workspaceId: string;
|
|
@@ -746,6 +760,7 @@ export interface TaskforceSyncCapable {
|
|
|
746
760
|
upsertDocumentReviewSessionForSync(session: DocumentReviewSessionRecord): DocumentReviewSessionRecord;
|
|
747
761
|
upsertDocumentReviewCommentForSync(comment: DocumentReviewCommentSyncRecord): DocumentReviewCommentSyncRecord;
|
|
748
762
|
upsertAnnotatedAttachmentSessionForSync(session: AnnotatedAttachmentSessionRecord): AnnotatedAttachmentSessionRecord;
|
|
763
|
+
upsertTaskEventForSync(event: TaskEvent): TaskEvent;
|
|
749
764
|
deleteDocumentReviewSessionForSync(input: {
|
|
750
765
|
workspaceId?: string | null;
|
|
751
766
|
sessionId: string;
|
|
@@ -828,6 +843,7 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
|
|
|
828
843
|
private areTaskEventValuesEqual;
|
|
829
844
|
private normalizeTaskEventValue;
|
|
830
845
|
private buildTaskUpdateChanges;
|
|
846
|
+
private filterAutosaveTaskEventChanges;
|
|
831
847
|
private normalizeTaxonomyToken;
|
|
832
848
|
private normalizeStatusValue;
|
|
833
849
|
private sanitizeAssignee;
|
|
@@ -867,11 +883,25 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
|
|
|
867
883
|
getWorkspaceAssetStore(): WorkspaceAssetStore;
|
|
868
884
|
private normalizeEntitlementState;
|
|
869
885
|
private upsertCanonicalEntitlementRecord;
|
|
886
|
+
transitionCanonicalCommercialState(input: {
|
|
887
|
+
accountId: string;
|
|
888
|
+
planVersionId?: string | null;
|
|
889
|
+
state: EntitlementState;
|
|
890
|
+
effectiveAt?: string | null;
|
|
891
|
+
effectiveUntil?: string | null;
|
|
892
|
+
billingMirrorPlanId?: string | null;
|
|
893
|
+
source: 'registration' | 'invite-accept' | 'checkout-start' | 'checkout-confirm' | 'stripe-webhook' | 'backfill' | 'legacy-plan-mode' | 'admin' | 'system';
|
|
894
|
+
updatedBy: string;
|
|
895
|
+
createdAt?: string | null;
|
|
896
|
+
updatedAt?: string | null;
|
|
897
|
+
}): import("./types.js").AccountEntitlementSnapshot;
|
|
870
898
|
private resolveWorkspaceLimitForUser;
|
|
871
|
-
private
|
|
899
|
+
private resolveRegistrationOnboardingOutcome;
|
|
900
|
+
private ensureDefaultOnboardingEntitlement;
|
|
872
901
|
createUserBillingRecord(userId: string, options?: {
|
|
873
902
|
entitlementState?: string;
|
|
874
903
|
planId?: string | null;
|
|
904
|
+
effectiveUntil?: string | null;
|
|
875
905
|
}): void;
|
|
876
906
|
getUserEntitlement(userId: string): {
|
|
877
907
|
entitlementState: string;
|
|
@@ -958,8 +988,11 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
|
|
|
958
988
|
hasProjectThemeOverride(workspaceId?: string, userId?: string): boolean;
|
|
959
989
|
getEffectiveTheme(workspaceId?: string, userId?: string): TaskforceTheme;
|
|
960
990
|
hasProjectJsonBackupOverride(workspaceId?: string, userId?: string): boolean;
|
|
961
|
-
|
|
962
|
-
|
|
991
|
+
getOnboardingPolicy(): import("./types.js").OnboardingPolicy;
|
|
992
|
+
validateOnboardingPolicy(input?: {
|
|
993
|
+
mode?: 'require_plan_selection' | 'auto_grant_free' | 'auto_start_trial';
|
|
994
|
+
planVersionId?: string | null;
|
|
995
|
+
}): import("./types.js").OnboardingPolicyValidationResult;
|
|
963
996
|
updateGlobalSettings(settings: GlobalTaskforceSettings): void;
|
|
964
997
|
private sanitizeUserGlobalSyncSettings;
|
|
965
998
|
getUserGlobalSyncSettings(userId: string): {
|
|
@@ -1137,6 +1170,11 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
|
|
|
1137
1170
|
setSystemRole(userId: string, role: SystemRole): boolean;
|
|
1138
1171
|
setUserDisabledGlobal(userId: string, disabled: boolean): boolean;
|
|
1139
1172
|
setUserBetaAccessGlobal(userId: string, enabled: boolean): boolean;
|
|
1173
|
+
purgeSystemUser(input: {
|
|
1174
|
+
targetUserId: string;
|
|
1175
|
+
actorUserId: string;
|
|
1176
|
+
emailConfirmation: string;
|
|
1177
|
+
}): PurgedSystemUserSummary;
|
|
1140
1178
|
private clearActiveAssignmentsForUnavailableActor;
|
|
1141
1179
|
listWorkspaceUsers(workspaceId: string): WorkspaceUserRecord[];
|
|
1142
1180
|
replaceWorkspaceUsersForSync(input: {
|
|
@@ -1229,6 +1267,7 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
|
|
|
1229
1267
|
upsertDocumentReviewSessionForSync(session: DocumentReviewSessionRecord): DocumentReviewSessionRecord;
|
|
1230
1268
|
upsertDocumentReviewCommentForSync(comment: DocumentReviewCommentSyncRecord): DocumentReviewCommentSyncRecord;
|
|
1231
1269
|
upsertAnnotatedAttachmentSessionForSync(session: AnnotatedAttachmentSessionRecord): AnnotatedAttachmentSessionRecord;
|
|
1270
|
+
upsertTaskEventForSync(event: TaskEvent): TaskEvent;
|
|
1232
1271
|
deleteDocumentReviewSessionForSync(input: {
|
|
1233
1272
|
workspaceId?: string | null;
|
|
1234
1273
|
sessionId: string;
|
|
@@ -1471,10 +1510,12 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
|
|
|
1471
1510
|
workspaceId: string | null;
|
|
1472
1511
|
role: AccessRole;
|
|
1473
1512
|
planSelectionRequired: boolean;
|
|
1513
|
+
checkoutPending: boolean;
|
|
1514
|
+
commercialState: EntitlementState;
|
|
1474
1515
|
};
|
|
1475
1516
|
private createOneTimeAuthToken;
|
|
1476
1517
|
private consumeOneTimeAuthToken;
|
|
1477
|
-
|
|
1518
|
+
inspectOneTimeAuthToken(token: string, purpose: AuthTokenPurpose): AuthTokenInspection;
|
|
1478
1519
|
revokeMcpCredentialsForUserWorkspace(userId: string, workspaceId: string, revokedByUserId?: string | null): void;
|
|
1479
1520
|
private revokeMcpCredentialsForWorkspace;
|
|
1480
1521
|
listMcpAccessTokens(input: {
|
|
@@ -1627,6 +1668,9 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
|
|
|
1627
1668
|
updateWorkspaceUserRole(userId: string, workspaceId: string, role: AccessRole): boolean;
|
|
1628
1669
|
getTask(id: string, workspaceId?: string): TaskItem | null;
|
|
1629
1670
|
listTaskEvents(taskId: string, workspaceId?: string): TaskEvent[];
|
|
1671
|
+
listTaskEventsForSync(input: {
|
|
1672
|
+
workspaceId?: string | null;
|
|
1673
|
+
}): TaskEvent[];
|
|
1630
1674
|
getScheduleBoard(weekKey: string, showWeekends?: boolean, workspaceId?: string): ScheduleBoardResult;
|
|
1631
1675
|
updateTaskSchedule(id: string, input: {
|
|
1632
1676
|
scheduledDate: string | null;
|
|
@@ -1658,6 +1702,7 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
|
|
|
1658
1702
|
syncUpdatedAt?: string;
|
|
1659
1703
|
actorRef?: string;
|
|
1660
1704
|
skipTaskEvents?: boolean;
|
|
1705
|
+
saveSource?: 'manual' | 'autosave';
|
|
1661
1706
|
}): TaskItem | null;
|
|
1662
1707
|
addComment(id: string, text: string, author: string, workspaceId?: string, options?: {
|
|
1663
1708
|
persistBackup?: boolean;
|
package/dist/core/Taskforce.js
CHANGED
|
@@ -9,7 +9,7 @@ import { WorkspaceAssetStore } from '../storage/workspaceAssetStore.js';
|
|
|
9
9
|
import { AuthTokenService } from './AuthTokenService.js';
|
|
10
10
|
import { getAiProfileByTokenService, listAiProfilesService, mergeAiProfilesService, resolveAiProfileService, upsertAiProfileForSyncService, } from './AiProfileService.js';
|
|
11
11
|
import { syncCanonicalTaskAttachmentLinksService, } from './AttachmentLinkService.js';
|
|
12
|
-
import { addTaskEventService, buildTaskActivityService, listTaskEventsInternalService, replaceTaskCommentsService, replaceTaskEventsService, } from './TaskActivityService.js';
|
|
12
|
+
import { addTaskEventService, buildTaskActivityService, listTaskEventsInternalService, listWorkspaceTaskEventsService, replaceTaskCommentsService, replaceTaskEventsService, upsertTaskEventForSyncService, } from './TaskActivityService.js';
|
|
13
13
|
import { addDeletedTaskRecordService, getDeletedTaskService, listDeletedTasksService, mapDeletedTaskRowService, normalizeTaskSnapshotForRestoreService, pruneDeletedTasksService, purgeExpiredDeletedTasksService, } from './DeletedTaskLifecycleService.js';
|
|
14
14
|
import { applyWorkspaceSyncSnapshotService, deleteDocumentWatermarkService, getDocumentWatermarkService, listTasksForSyncService, listWorkspaceSyncDeletesSinceService, readPushIdempotencyService, recordSyncEventService, upsertDocumentWatermarkService, writePushIdempotencyService, } from './SyncReconciliationService.js';
|
|
15
15
|
import { getGlobalSettingsService, hasPersistedGlobalSettingsService, readGlobalConfigService, updateGlobalSettingsService, writeGlobalConfigService, } from './GlobalSettingsService.js';
|
|
@@ -666,6 +666,9 @@ export class TaskforceCore {
|
|
|
666
666
|
}
|
|
667
667
|
return changes;
|
|
668
668
|
}
|
|
669
|
+
filterAutosaveTaskEventChanges(changes) {
|
|
670
|
+
return Object.fromEntries(Object.entries(changes).filter(([field]) => field !== 'title' && field !== 'description'));
|
|
671
|
+
}
|
|
669
672
|
normalizeTaxonomyToken(value) {
|
|
670
673
|
return String(value || '')
|
|
671
674
|
.trim()
|
|
@@ -1175,7 +1178,6 @@ export class TaskforceCore {
|
|
|
1175
1178
|
writeGlobalConfig: (config) => this.writeGlobalConfig(config),
|
|
1176
1179
|
});
|
|
1177
1180
|
this.planEntitlementService.repairPlanCatalogDefaultsIfNeeded();
|
|
1178
|
-
this.planEntitlementService.repairSignupMonetizationSettingsIfNeeded();
|
|
1179
1181
|
this.planEntitlementService.normalizeLegacyPlanDataIfNeeded();
|
|
1180
1182
|
this.planEntitlementService.backfillAccountEntitlements();
|
|
1181
1183
|
this.repairDetachedAnnotatedAttachmentSessions();
|
|
@@ -1209,11 +1211,37 @@ export class TaskforceCore {
|
|
|
1209
1211
|
upsertCanonicalEntitlementRecord(input) {
|
|
1210
1212
|
return this.planEntitlementService.upsertCanonicalEntitlementRecord(input);
|
|
1211
1213
|
}
|
|
1214
|
+
transitionCanonicalCommercialState(input) {
|
|
1215
|
+
return this.planEntitlementService.transitionCanonicalCommercialState(input);
|
|
1216
|
+
}
|
|
1212
1217
|
resolveWorkspaceLimitForUser(userId) {
|
|
1213
1218
|
return this.planEntitlementService.resolveWorkspaceLimitForUser(userId);
|
|
1214
1219
|
}
|
|
1215
|
-
|
|
1216
|
-
return this.planEntitlementService.
|
|
1220
|
+
resolveRegistrationOnboardingOutcome(selectedPlanVersionIdRaw) {
|
|
1221
|
+
return this.planEntitlementService.resolveRegistrationOnboardingOutcome(selectedPlanVersionIdRaw);
|
|
1222
|
+
}
|
|
1223
|
+
ensureDefaultOnboardingEntitlement(accountIdRaw, options) {
|
|
1224
|
+
const accountId = String(accountIdRaw || '').trim();
|
|
1225
|
+
if (!accountId) {
|
|
1226
|
+
throw new TaskforceRuleError('accountId is required', 400, 'ACCOUNT_ID_REQUIRED');
|
|
1227
|
+
}
|
|
1228
|
+
if (this.hasAccountEntitlement(accountId)) {
|
|
1229
|
+
return this.getAccountEntitlement(accountId);
|
|
1230
|
+
}
|
|
1231
|
+
const now = options?.now || new Date().toISOString();
|
|
1232
|
+
const onboardingOutcome = this.resolveRegistrationOnboardingOutcome();
|
|
1233
|
+
this.transitionCanonicalCommercialState({
|
|
1234
|
+
accountId,
|
|
1235
|
+
planVersionId: onboardingOutcome.planVersionId,
|
|
1236
|
+
state: onboardingOutcome.commercialState,
|
|
1237
|
+
effectiveAt: now,
|
|
1238
|
+
billingMirrorPlanId: onboardingOutcome.planId,
|
|
1239
|
+
source: options?.source || 'registration',
|
|
1240
|
+
updatedBy: options?.updatedBy || 'registration',
|
|
1241
|
+
createdAt: now,
|
|
1242
|
+
updatedAt: now
|
|
1243
|
+
});
|
|
1244
|
+
return this.getAccountEntitlement(accountId);
|
|
1217
1245
|
}
|
|
1218
1246
|
createUserBillingRecord(userId, options) {
|
|
1219
1247
|
return this.planEntitlementService.createUserBillingRecord(userId, options);
|
|
@@ -2598,11 +2626,11 @@ export class TaskforceCore {
|
|
|
2598
2626
|
const config = this.readConfig(workspaceId, userId) || {};
|
|
2599
2627
|
return typeof config.jsonBackupEnabled === 'boolean';
|
|
2600
2628
|
}
|
|
2601
|
-
|
|
2602
|
-
return this.planEntitlementService.
|
|
2629
|
+
getOnboardingPolicy() {
|
|
2630
|
+
return this.planEntitlementService.getOnboardingPolicy();
|
|
2603
2631
|
}
|
|
2604
|
-
|
|
2605
|
-
return this.planEntitlementService.
|
|
2632
|
+
validateOnboardingPolicy(input) {
|
|
2633
|
+
return this.planEntitlementService.validateOnboardingPolicy(input);
|
|
2606
2634
|
}
|
|
2607
2635
|
updateGlobalSettings(settings) {
|
|
2608
2636
|
updateGlobalSettingsService(this.getGlobalSettingsServiceDeps(), settings);
|
|
@@ -4375,6 +4403,193 @@ export class TaskforceCore {
|
|
|
4375
4403
|
`).run(enabled ? 1 : 0, new Date().toISOString(), this.tenantId, normalizedUserId);
|
|
4376
4404
|
return Number(result?.changes || 0) > 0;
|
|
4377
4405
|
}
|
|
4406
|
+
purgeSystemUser(input) {
|
|
4407
|
+
const targetUserId = String(input.targetUserId || '').trim();
|
|
4408
|
+
const actorUserId = String(input.actorUserId || '').trim();
|
|
4409
|
+
const emailConfirmation = String(input.emailConfirmation || '').trim().toLowerCase();
|
|
4410
|
+
if (!targetUserId) {
|
|
4411
|
+
throw new TaskforceRuleError('targetUserId is required', 400, 'TARGET_USER_ID_REQUIRED');
|
|
4412
|
+
}
|
|
4413
|
+
if (!actorUserId || actorUserId === 'anonymous') {
|
|
4414
|
+
throw new TaskforceRuleError('actorUserId is required', 400, 'ACTOR_USER_ID_REQUIRED');
|
|
4415
|
+
}
|
|
4416
|
+
if (!emailConfirmation) {
|
|
4417
|
+
throw new TaskforceRuleError('Email confirmation is required', 400, 'EMAIL_CONFIRMATION_REQUIRED');
|
|
4418
|
+
}
|
|
4419
|
+
if (targetUserId === actorUserId) {
|
|
4420
|
+
throw new TaskforceRuleError('Cannot purge the current system admin session user', 400, 'CURRENT_SYSTEM_USER_PURGE_FORBIDDEN');
|
|
4421
|
+
}
|
|
4422
|
+
return this.db.transaction(() => {
|
|
4423
|
+
const user = this.db.prepare(`
|
|
4424
|
+
SELECT
|
|
4425
|
+
id,
|
|
4426
|
+
email,
|
|
4427
|
+
COALESCE(system_role, 'user') AS system_role,
|
|
4428
|
+
COALESCE(is_disabled, 0) AS is_disabled
|
|
4429
|
+
FROM users
|
|
4430
|
+
WHERE tenant_id = ? AND id = ?
|
|
4431
|
+
LIMIT 1
|
|
4432
|
+
`).get(this.tenantId, targetUserId);
|
|
4433
|
+
if (!user?.id || !user.email) {
|
|
4434
|
+
throw new TaskforceRuleError('User not found', 404, 'USER_NOT_FOUND');
|
|
4435
|
+
}
|
|
4436
|
+
const normalizedEmail = String(user.email).trim().toLowerCase();
|
|
4437
|
+
if (normalizedEmail !== emailConfirmation) {
|
|
4438
|
+
throw new TaskforceRuleError('Email confirmation did not match the target user', 400, 'EMAIL_CONFIRMATION_MISMATCH');
|
|
4439
|
+
}
|
|
4440
|
+
const currentRole = this.normalizeSystemRole(user.system_role, 'user');
|
|
4441
|
+
const isDisabled = Boolean(user.is_disabled);
|
|
4442
|
+
if (currentRole === 'system_admin' && !isDisabled && this.countSystemAdmins() <= 1) {
|
|
4443
|
+
throw new TaskforceRuleError('Cannot purge the last enabled system admin', 400, 'LAST_SYSTEM_ADMIN_REQUIRED');
|
|
4444
|
+
}
|
|
4445
|
+
const elevatedWorkspaceMemberships = this.db.prepare(`
|
|
4446
|
+
SELECT
|
|
4447
|
+
m.workspace_id AS workspace_id,
|
|
4448
|
+
COALESCE(m.role, 'member') AS role,
|
|
4449
|
+
w.name AS workspace_name
|
|
4450
|
+
FROM workspace_memberships m
|
|
4451
|
+
LEFT JOIN workspaces w
|
|
4452
|
+
ON w.tenant_id = m.tenant_id
|
|
4453
|
+
AND w.id = m.workspace_id
|
|
4454
|
+
WHERE m.tenant_id = ?
|
|
4455
|
+
AND m.user_id = ?
|
|
4456
|
+
AND COALESCE(m.status, 'active') = 'active'
|
|
4457
|
+
AND COALESCE(m.role, 'member') IN ('owner', 'admin')
|
|
4458
|
+
ORDER BY COALESCE(w.updated_at, w.created_at) DESC, w.name ASC
|
|
4459
|
+
LIMIT 10
|
|
4460
|
+
`).all(this.tenantId, targetUserId);
|
|
4461
|
+
if (elevatedWorkspaceMemberships.length > 0) {
|
|
4462
|
+
throw new TaskforceRuleError('Cannot purge a user with active owner/admin workspace memberships', 409, 'SYSTEM_USER_PURGE_BLOCKED_ACTIVE_WORKSPACE_ROLE', {
|
|
4463
|
+
memberships: elevatedWorkspaceMemberships.map((membership) => ({
|
|
4464
|
+
workspaceId: membership.workspace_id ? String(membership.workspace_id) : null,
|
|
4465
|
+
workspaceName: membership.workspace_name ? String(membership.workspace_name) : null,
|
|
4466
|
+
role: membership.role ? String(membership.role) : null
|
|
4467
|
+
}))
|
|
4468
|
+
});
|
|
4469
|
+
}
|
|
4470
|
+
const billingRow = this.db.prepare(`
|
|
4471
|
+
SELECT
|
|
4472
|
+
stripe_customer_id,
|
|
4473
|
+
stripe_subscription_id,
|
|
4474
|
+
stripe_price_id,
|
|
4475
|
+
stripe_status,
|
|
4476
|
+
billing_interval
|
|
4477
|
+
FROM user_billing
|
|
4478
|
+
WHERE tenant_id = ? AND user_id = ?
|
|
4479
|
+
LIMIT 1
|
|
4480
|
+
`).get(this.tenantId, targetUserId);
|
|
4481
|
+
const hasCommercialBillingState = [
|
|
4482
|
+
billingRow?.stripe_customer_id,
|
|
4483
|
+
billingRow?.stripe_subscription_id,
|
|
4484
|
+
billingRow?.stripe_price_id,
|
|
4485
|
+
billingRow?.stripe_status,
|
|
4486
|
+
billingRow?.billing_interval
|
|
4487
|
+
].some((value) => String(value || '').trim().length > 0);
|
|
4488
|
+
if (hasCommercialBillingState) {
|
|
4489
|
+
throw new TaskforceRuleError('Cannot purge a user with active commercial billing state', 409, 'SYSTEM_USER_PURGE_BLOCKED_BILLING_STATE');
|
|
4490
|
+
}
|
|
4491
|
+
const now = new Date().toISOString();
|
|
4492
|
+
const runCount = (sql, ...params) => Number(this.db.prepare(sql).run(...params)?.changes || 0);
|
|
4493
|
+
const unassignedTaskCount = runCount(`
|
|
4494
|
+
UPDATE tasks
|
|
4495
|
+
SET assignee = 'unassigned',
|
|
4496
|
+
updated_at = ?
|
|
4497
|
+
WHERE tenant_id = ?
|
|
4498
|
+
AND assignee = ?
|
|
4499
|
+
AND is_archived = 0
|
|
4500
|
+
`, now, this.tenantId, targetUserId);
|
|
4501
|
+
const clearedInitiativeOwnerCount = runCount(`
|
|
4502
|
+
UPDATE initiatives
|
|
4503
|
+
SET owner_id = NULL,
|
|
4504
|
+
updated_at = ?
|
|
4505
|
+
WHERE tenant_id = ?
|
|
4506
|
+
AND owner_id = ?
|
|
4507
|
+
`, now, this.tenantId, targetUserId);
|
|
4508
|
+
const clearedWorkstreamOwnerCount = runCount(`
|
|
4509
|
+
UPDATE workstreams
|
|
4510
|
+
SET owner_id = NULL,
|
|
4511
|
+
updated_at = ?
|
|
4512
|
+
WHERE tenant_id = ?
|
|
4513
|
+
AND owner_id = ?
|
|
4514
|
+
`, now, this.tenantId, targetUserId);
|
|
4515
|
+
const deletedEntitlementCount = runCount(`
|
|
4516
|
+
DELETE FROM account_entitlements
|
|
4517
|
+
WHERE tenant_id = ?
|
|
4518
|
+
AND account_id = ?
|
|
4519
|
+
`, this.tenantId, targetUserId);
|
|
4520
|
+
const deletedWorkspaceMembershipCount = runCount(`
|
|
4521
|
+
DELETE FROM workspace_memberships
|
|
4522
|
+
WHERE tenant_id = ?
|
|
4523
|
+
AND user_id = ?
|
|
4524
|
+
`, this.tenantId, targetUserId);
|
|
4525
|
+
const deletedAuthTokenCount = runCount(`
|
|
4526
|
+
DELETE FROM auth_tokens
|
|
4527
|
+
WHERE tenant_id = ?
|
|
4528
|
+
AND user_id = ?
|
|
4529
|
+
`, this.tenantId, targetUserId);
|
|
4530
|
+
const deletedAvatarDraftCount = runCount(`
|
|
4531
|
+
DELETE FROM user_avatar_upload_drafts
|
|
4532
|
+
WHERE tenant_id = ?
|
|
4533
|
+
AND user_id = ?
|
|
4534
|
+
`, this.tenantId, targetUserId);
|
|
4535
|
+
const deletedMcpAccessTokenCount = runCount(`
|
|
4536
|
+
DELETE FROM mcp_access_tokens
|
|
4537
|
+
WHERE tenant_id = ?
|
|
4538
|
+
AND user_id = ?
|
|
4539
|
+
`, this.tenantId, targetUserId);
|
|
4540
|
+
const deletedMcpOauthAuthCodeCount = runCount(`
|
|
4541
|
+
DELETE FROM mcp_oauth_auth_codes
|
|
4542
|
+
WHERE tenant_id = ?
|
|
4543
|
+
AND user_id = ?
|
|
4544
|
+
`, this.tenantId, targetUserId);
|
|
4545
|
+
const deletedMcpOauthConnectorGrantCount = runCount(`
|
|
4546
|
+
DELETE FROM mcp_oauth_connector_grants
|
|
4547
|
+
WHERE tenant_id = ?
|
|
4548
|
+
AND user_id = ?
|
|
4549
|
+
`, this.tenantId, targetUserId);
|
|
4550
|
+
const deletedUiStateCount = runCount(`
|
|
4551
|
+
DELETE FROM ui_state
|
|
4552
|
+
WHERE tenant_id = ?
|
|
4553
|
+
AND user_id = ?
|
|
4554
|
+
`, this.tenantId, targetUserId);
|
|
4555
|
+
const deletedUserPreferenceCount = runCount(`
|
|
4556
|
+
DELETE FROM user_preferences
|
|
4557
|
+
WHERE tenant_id = ?
|
|
4558
|
+
AND user_id = ?
|
|
4559
|
+
`, this.tenantId, targetUserId);
|
|
4560
|
+
const deletedUserBillingCount = runCount(`
|
|
4561
|
+
DELETE FROM user_billing
|
|
4562
|
+
WHERE tenant_id = ?
|
|
4563
|
+
AND user_id = ?
|
|
4564
|
+
`, this.tenantId, targetUserId);
|
|
4565
|
+
const deletedUserCount = runCount(`
|
|
4566
|
+
DELETE FROM users
|
|
4567
|
+
WHERE tenant_id = ?
|
|
4568
|
+
AND id = ?
|
|
4569
|
+
`, this.tenantId, targetUserId);
|
|
4570
|
+
if (deletedUserCount !== 1) {
|
|
4571
|
+
throw new TaskforceRuleError('User not found', 404, 'USER_NOT_FOUND');
|
|
4572
|
+
}
|
|
4573
|
+
return {
|
|
4574
|
+
targetUserId,
|
|
4575
|
+
email: String(user.email),
|
|
4576
|
+
unassignedTaskCount,
|
|
4577
|
+
clearedInitiativeOwnerCount,
|
|
4578
|
+
clearedWorkstreamOwnerCount,
|
|
4579
|
+
deletedWorkspaceMembershipCount,
|
|
4580
|
+
deletedAuthTokenCount,
|
|
4581
|
+
deletedAvatarDraftCount,
|
|
4582
|
+
deletedMcpAccessTokenCount,
|
|
4583
|
+
deletedMcpOauthAuthCodeCount,
|
|
4584
|
+
deletedMcpOauthConnectorGrantCount,
|
|
4585
|
+
deletedUiStateCount,
|
|
4586
|
+
deletedUserPreferenceCount,
|
|
4587
|
+
deletedEntitlementCount,
|
|
4588
|
+
deletedUserBillingCount,
|
|
4589
|
+
deletedUserCount
|
|
4590
|
+
};
|
|
4591
|
+
})();
|
|
4592
|
+
}
|
|
4378
4593
|
clearActiveAssignmentsForUnavailableActor(actorId, workspaceId, updatedAt) {
|
|
4379
4594
|
const normalizedActorId = String(actorId || '').trim();
|
|
4380
4595
|
const normalizedWorkspaceId = String(workspaceId || 'default').trim() || 'default';
|
|
@@ -4652,6 +4867,9 @@ export class TaskforceCore {
|
|
|
4652
4867
|
deletedAt: session.deletedAt,
|
|
4653
4868
|
});
|
|
4654
4869
|
}
|
|
4870
|
+
upsertTaskEventForSync(event) {
|
|
4871
|
+
return upsertTaskEventForSyncService(this.getTaskActivityServiceDeps(), event);
|
|
4872
|
+
}
|
|
4655
4873
|
deleteDocumentReviewSessionForSync(input) {
|
|
4656
4874
|
const deps = this.getDocumentReviewServiceDeps();
|
|
4657
4875
|
return deps.sessionStore.softDelete(input.sessionId, deps.normalizeWorkspaceId(input.workspaceId), input.deletedAt || undefined);
|
|
@@ -5329,7 +5547,20 @@ export class TaskforceCore {
|
|
|
5329
5547
|
const assignFirstSystemAdmin = !this.hasAnySystemAdmin();
|
|
5330
5548
|
const betaAccess = input.betaAccess !== false;
|
|
5331
5549
|
const requestedWorkspaceId = String(input.workspaceId || '').trim();
|
|
5332
|
-
const
|
|
5550
|
+
const onboardingOutcome = this.resolveRegistrationOnboardingOutcome(input.planVersionId);
|
|
5551
|
+
const applyRegistrationCommercialState = (accountId, now) => {
|
|
5552
|
+
this.transitionCanonicalCommercialState({
|
|
5553
|
+
accountId,
|
|
5554
|
+
planVersionId: onboardingOutcome.planVersionId,
|
|
5555
|
+
state: onboardingOutcome.commercialState,
|
|
5556
|
+
effectiveAt: now,
|
|
5557
|
+
billingMirrorPlanId: onboardingOutcome.planId,
|
|
5558
|
+
source: 'registration',
|
|
5559
|
+
updatedBy: 'registration',
|
|
5560
|
+
createdAt: now,
|
|
5561
|
+
updatedAt: now
|
|
5562
|
+
});
|
|
5563
|
+
};
|
|
5333
5564
|
if (!requestedWorkspaceId || requestedWorkspaceId.toLowerCase() === 'default') {
|
|
5334
5565
|
const now = new Date().toISOString();
|
|
5335
5566
|
const userId = this.generateEntityId('user');
|
|
@@ -5338,32 +5569,14 @@ export class TaskforceCore {
|
|
|
5338
5569
|
INSERT INTO users (id, tenant_id, email, display_name, auth_provider, external_auth_id, password_hash, system_role, beta_access, is_disabled, created_at, updated_at)
|
|
5339
5570
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?)
|
|
5340
5571
|
`).run(userId, this.tenantId, email, displayName, 'password', email, hashPassword(password), assignFirstSystemAdmin ? 'system_admin' : 'user', betaAccess ? 1 : 0, now, now);
|
|
5341
|
-
|
|
5342
|
-
this.createUserBillingRecord(userId, {
|
|
5343
|
-
entitlementState: 'pending_plan_selection',
|
|
5344
|
-
planId: null
|
|
5345
|
-
});
|
|
5346
|
-
}
|
|
5347
|
-
if (!registrationPlanAssignment.requiresPlanSelection && registrationPlanAssignment.planVersionId && registrationPlanAssignment.planId) {
|
|
5348
|
-
this.createUserBillingRecord(userId, {
|
|
5349
|
-
entitlementState: 'active',
|
|
5350
|
-
planId: registrationPlanAssignment.planId
|
|
5351
|
-
});
|
|
5352
|
-
this.upsertCanonicalEntitlementRecord({
|
|
5353
|
-
accountId: userId,
|
|
5354
|
-
planVersionId: registrationPlanAssignment.planVersionId,
|
|
5355
|
-
state: 'active',
|
|
5356
|
-
effectiveAt: now,
|
|
5357
|
-
updatedBy: 'registration',
|
|
5358
|
-
createdAt: now,
|
|
5359
|
-
updatedAt: now
|
|
5360
|
-
});
|
|
5361
|
-
}
|
|
5572
|
+
applyRegistrationCommercialState(userId, now);
|
|
5362
5573
|
return {
|
|
5363
5574
|
userId,
|
|
5364
5575
|
workspaceId: null,
|
|
5365
5576
|
role: 'member',
|
|
5366
|
-
planSelectionRequired:
|
|
5577
|
+
planSelectionRequired: onboardingOutcome.requiresPlanSelection,
|
|
5578
|
+
checkoutPending: onboardingOutcome.checkoutPending,
|
|
5579
|
+
commercialState: onboardingOutcome.commercialState
|
|
5367
5580
|
};
|
|
5368
5581
|
}
|
|
5369
5582
|
const workspaceId = requestedWorkspaceId;
|
|
@@ -5381,27 +5594,12 @@ export class TaskforceCore {
|
|
|
5381
5594
|
WHERE tenant_id = ? AND id = ?
|
|
5382
5595
|
`).run(new Date().toISOString(), this.tenantId, created.userId);
|
|
5383
5596
|
}
|
|
5384
|
-
|
|
5385
|
-
this.createUserBillingRecord(created.userId, {
|
|
5386
|
-
entitlementState: 'pending_plan_selection',
|
|
5387
|
-
planId: null
|
|
5388
|
-
});
|
|
5389
|
-
}
|
|
5390
|
-
if (!registrationPlanAssignment.requiresPlanSelection && registrationPlanAssignment.planVersionId && registrationPlanAssignment.planId) {
|
|
5391
|
-
this.createUserBillingRecord(created.userId, {
|
|
5392
|
-
entitlementState: 'active',
|
|
5393
|
-
planId: registrationPlanAssignment.planId
|
|
5394
|
-
});
|
|
5395
|
-
this.upsertCanonicalEntitlementRecord({
|
|
5396
|
-
accountId: created.userId,
|
|
5397
|
-
planVersionId: registrationPlanAssignment.planVersionId,
|
|
5398
|
-
state: 'active',
|
|
5399
|
-
updatedBy: 'registration'
|
|
5400
|
-
});
|
|
5401
|
-
}
|
|
5597
|
+
applyRegistrationCommercialState(created.userId);
|
|
5402
5598
|
return {
|
|
5403
5599
|
...created,
|
|
5404
|
-
planSelectionRequired:
|
|
5600
|
+
planSelectionRequired: onboardingOutcome.requiresPlanSelection,
|
|
5601
|
+
checkoutPending: onboardingOutcome.checkoutPending,
|
|
5602
|
+
commercialState: onboardingOutcome.commercialState
|
|
5405
5603
|
};
|
|
5406
5604
|
}
|
|
5407
5605
|
createOneTimeAuthToken(userId, purpose, ttlSeconds, workspaceId) {
|
|
@@ -5626,6 +5824,11 @@ export class TaskforceCore {
|
|
|
5626
5824
|
updated_at = ?
|
|
5627
5825
|
WHERE tenant_id = ? AND id = ?
|
|
5628
5826
|
`).run(hashPassword(password), 'password', user.email, now, now, this.tenantId, consumed.userId);
|
|
5827
|
+
this.ensureDefaultOnboardingEntitlement(consumed.userId, {
|
|
5828
|
+
source: 'invite-accept',
|
|
5829
|
+
updatedBy: 'invite-accept',
|
|
5830
|
+
now
|
|
5831
|
+
});
|
|
5629
5832
|
return this.completeInviteWorkspaceActivation({
|
|
5630
5833
|
userId: consumed.userId,
|
|
5631
5834
|
workspaceId: inviteWorkspaceId
|
|
@@ -5784,6 +5987,10 @@ export class TaskforceCore {
|
|
|
5784
5987
|
const normalizedWorkspaceId = this.normalizeWorkspaceId(workspaceId);
|
|
5785
5988
|
return this.listTaskEventsInternal(taskId, normalizedWorkspaceId);
|
|
5786
5989
|
}
|
|
5990
|
+
listTaskEventsForSync(input) {
|
|
5991
|
+
const normalizedWorkspaceId = this.normalizeWorkspaceId(input.workspaceId || undefined);
|
|
5992
|
+
return listWorkspaceTaskEventsService(this.getTaskActivityServiceDeps(), normalizedWorkspaceId);
|
|
5993
|
+
}
|
|
5787
5994
|
getScheduleBoard(weekKey, showWeekends = false, workspaceId) {
|
|
5788
5995
|
const parsedWeek = this.parseIsoWeekKeyToDates(weekKey);
|
|
5789
5996
|
if (!parsedWeek) {
|
|
@@ -6341,7 +6548,10 @@ export class TaskforceCore {
|
|
|
6341
6548
|
if (!nextTask)
|
|
6342
6549
|
return null;
|
|
6343
6550
|
if (options?.skipTaskEvents !== true) {
|
|
6344
|
-
const
|
|
6551
|
+
const rawChanges = this.buildTaskUpdateChanges(existing, nextTask, patch);
|
|
6552
|
+
const changes = options?.saveSource === 'autosave'
|
|
6553
|
+
? this.filterAutosaveTaskEventChanges(rawChanges)
|
|
6554
|
+
: rawChanges;
|
|
6345
6555
|
if (Object.keys(changes).length > 0) {
|
|
6346
6556
|
let action = 'task-updated';
|
|
6347
6557
|
if (changes.status) {
|
|
@@ -27,7 +27,6 @@ function setupWorkspace(core, userId = 'owner-1', workspaceId = 'workspace-1') {
|
|
|
27
27
|
hasEntitlement: true,
|
|
28
28
|
canAccessApp: true,
|
|
29
29
|
canAccessPlans: true,
|
|
30
|
-
signupMonetizationStrategy: 'none',
|
|
31
30
|
planSelectionRequired: false,
|
|
32
31
|
message: null,
|
|
33
32
|
entitlement: null
|
|
@@ -328,7 +327,6 @@ describe('TaskforceCore MCP auth invalidation', () => {
|
|
|
328
327
|
hasEntitlement: false,
|
|
329
328
|
canAccessApp: false,
|
|
330
329
|
canAccessPlans: true,
|
|
331
|
-
signupMonetizationStrategy: 'none',
|
|
332
330
|
planSelectionRequired: false,
|
|
333
331
|
message: 'Suspended for test',
|
|
334
332
|
entitlement: null
|
|
@@ -13,10 +13,19 @@ function seedPlans(core) {
|
|
|
13
13
|
versionNumber: 1,
|
|
14
14
|
seatLimit: 1
|
|
15
15
|
});
|
|
16
|
+
const db = core.db;
|
|
17
|
+
const now = new Date().toISOString();
|
|
18
|
+
db.prepare(`
|
|
19
|
+
INSERT OR IGNORE INTO billing_price_mappings (
|
|
20
|
+
tenant_id, plan_version_id, billing_interval, stripe_price_id, pricing_type, active, unit_amount, currency, created_at, updated_at
|
|
21
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
22
|
+
`).run(core.getTenantId(), 'starter-v1', 'month', 'free:starter-v1:month', 'free', 1, 0, null, now, now);
|
|
16
23
|
core.updateGlobalSettings({
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
24
|
+
billing: {
|
|
25
|
+
onboardingPolicy: {
|
|
26
|
+
mode: 'auto_grant_free',
|
|
27
|
+
planVersionId: 'starter-v1'
|
|
28
|
+
}
|
|
20
29
|
}
|
|
21
30
|
});
|
|
22
31
|
}
|