@tearleads/client-sdk 0.1.87 → 0.1.89
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/Tearleads.js +1 -1
- package/Tearleads.js.map +1 -1
- package/client/containerContents/documentDiscovery.js +16 -2
- package/client/containerContents/documentDiscovery.js.map +1 -1
- package/client/containerContents/index.d.ts +1 -1
- package/client/containerContents/index.js +1 -0
- package/client/containerContents/index.js.map +1 -1
- package/client/index.d.ts +1 -1
- package/client/index.js.map +1 -1
- package/client/organizations/index.d.ts +4 -2
- package/client/organizations/index.js +15 -8
- package/client/organizations/index.js.map +1 -1
- package/client/organizations/organizationMemberships.d.ts +41 -0
- package/client/organizations/organizationMemberships.js +166 -0
- package/client/organizations/organizationMemberships.js.map +1 -0
- package/client/organizations/organizationReadModels.d.ts +7 -1
- package/client/organizations/organizationReadModels.js +15 -6
- package/client/organizations/organizationReadModels.js.map +1 -1
- package/client/organizations/organizationsTypes.d.ts +3 -0
- package/client/organizations/organizationsTypes.js.map +1 -1
- package/data/persistence/container-contents/containerStructuralRepair.js +19 -14
- package/data/persistence/container-contents/containerStructuralRepair.js.map +1 -1
- package/data/persistence/container-contents/exclusiveDocumentPlacements.js +60 -0
- package/data/persistence/container-contents/exclusiveDocumentPlacements.js.map +1 -0
- package/data/persistence/organizations/organizationReadModelPersistence.js +14 -0
- package/data/persistence/organizations/organizationReadModelPersistence.js.map +1 -1
- package/data/persistence/organizations/organizationReadModelProjection.js +12 -0
- package/data/persistence/organizations/organizationReadModelProjection.js.map +1 -1
- package/data/sqlite/schema/index.d.ts +90 -0
- package/data/sqlite/schema/index.js +3 -0
- package/data/sqlite/schema/index.js.map +1 -1
- package/data/sqlite/schema/organizationReadModelSchema.js +2 -0
- package/data/sqlite/schema/organizationReadModelSchema.js.map +1 -1
- package/data/sqlite/schema/organizationReadModelTableRegistry.d.ts +19 -0
- package/data/sqlite/schema/organizationSyncPauseSchema.js +32 -0
- package/data/sqlite/schema/organizationSyncPauseSchema.js.map +1 -0
- package/data/sync/organizationSyncPauses.d.ts +59 -0
- package/data/sync/organizationSyncPauses.js +149 -0
- package/data/sync/organizationSyncPauses.js.map +1 -0
- package/index.d.ts +2 -2
- package/index.js.map +1 -1
- package/internal/api-client/ApiClient.d.ts +21 -2
- package/internal/api-client/ApiClient.js +15 -1
- package/internal/api-client/ApiClient.js.map +1 -1
- package/internal/api-client/routes/organizations/memberships.js +36 -0
- package/internal/api-client/routes/organizations/memberships.js.map +1 -0
- package/internal/crypto/index.d.ts +1 -0
- package/internal/crypto/index.js +1 -0
- package/internal/crypto/index.js.map +1 -1
- package/internal/crypto/organizationLeaveRequest.d.ts +13 -0
- package/internal/crypto/organizationLeaveRequest.js +39 -0
- package/internal/crypto/organizationLeaveRequest.js.map +1 -0
- package/internal/validators/operation/index.d.ts +1 -0
- package/internal/validators/operation/index.js +1 -0
- package/internal/validators/operation/index.js.map +1 -1
- package/internal/validators/operation/organizationMemberships.d.ts +503 -0
- package/internal/validators/operation/organizationMemberships.js +93 -0
- package/internal/validators/operation/organizationMemberships.js.map +1 -0
- package/internal/validators/operation/organizations.d.ts +48 -0
- package/internal/validators/operation/registry.d.ts +5 -0
- package/internal/validators/operation/registry.js +5 -0
- package/internal/validators/operation/registry.js.map +1 -1
- package/internal/validators/realtime/index.js +1 -1
- package/internal/validators/realtime/index.js.map +1 -1
- package/internal/validators/realtime/wsInvalidationHints.js +8 -0
- package/internal/validators/realtime/wsInvalidationHints.js.map +1 -1
- package/internal/validators/request/index.d.ts +1 -1
- package/internal/validators/request/index.js +1 -1
- package/internal/validators/request/index.js.map +1 -1
- package/internal/validators/request/organization.d.ts +6 -0
- package/internal/validators/request/organization.js +7 -0
- package/internal/validators/request/organization.js.map +1 -1
- package/internal/validators/response/index.d.ts +1 -0
- package/internal/validators/response/index.js +1 -0
- package/internal/validators/response/index.js.map +1 -1
- package/internal/validators/response/organization.d.ts +82 -0
- package/internal/validators/response/organization.js +6 -0
- package/internal/validators/response/organization.js.map +1 -1
- package/internal/validators/response/organizationMembership.d.ts +66 -0
- package/internal/validators/response/organizationMembership.js +29 -0
- package/internal/validators/response/organizationMembership.js.map +1 -0
- package/internal/validators/response/organizationReadModel.d.ts +60 -0
- package/internal/validators/util/index.d.ts +1 -0
- package/internal/validators/util/index.js +1 -0
- package/internal/validators/util/index.js.map +1 -1
- package/internal/validators/util/organizationLeaveRequest.d.ts +15 -0
- package/internal/validators/util/organizationLeaveRequest.js +22 -0
- package/internal/validators/util/organizationLeaveRequest.js.map +1 -0
- package/package.json +1 -1
- package/stores/container-contents/containerContentsStore.d.ts +1 -1
- package/stores/container-contents/containerContentsStore.js +2 -0
- package/stores/container-contents/containerContentsStore.js.map +1 -1
- package/stores/container-contents/operations/forgetOrganizationContentOperation.js +76 -0
- package/stores/container-contents/operations/forgetOrganizationContentOperation.js.map +1 -0
- package/stores/container-contents/types.d.ts +6 -0
- package/stores/container-contents/types.js.map +1 -1
- package/stores/documents/documentStore/attachments/attachmentRemoval.js +3 -4
- package/stores/documents/documentStore/attachments/attachmentRemoval.js.map +1 -1
- package/stores/documents/documentStore/attachments/index.js +5 -7
- package/stores/documents/documentStore/attachments/index.js.map +1 -1
- package/stores/documents/documentStore/index.js +16 -12
- package/stores/documents/documentStore/index.js.map +1 -1
- package/stores/documents/documentStore/initialization/index.js +9 -0
- package/stores/documents/documentStore/initialization/index.js.map +1 -1
- package/stores/documents/documentStore/mutations.js +5 -7
- package/stores/documents/documentStore/mutations.js.map +1 -1
- package/stores/documents/documentStore/rotation/index.js +2 -1
- package/stores/documents/documentStore/rotation/index.js.map +1 -1
- package/stores/documents/documentStore/rows/index.js +3 -4
- package/stores/documents/documentStore/rows/index.js.map +1 -1
- package/stores/documents/documentStore/state.js +18 -0
- package/stores/documents/documentStore/state.js.map +1 -1
- package/stores/documents/documentStore/sync/index.js +5 -2
- package/stores/documents/documentStore/sync/index.js.map +1 -1
- package/stores/documents/registry.d.ts +32 -0
- package/stores/documents/registry.js +79 -4
- package/stores/documents/registry.js.map +1 -1
- package/stores/documents/removedDocumentStore.js +38 -0
- package/stores/documents/removedDocumentStore.js.map +1 -0
- package/stores/documents/types.d.ts +2 -0
- package/stores/documents/types.js.map +1 -1
- package/sync/reconciliation/service.js +2 -2
- package/sync/reconciliation/service.js.map +1 -1
- package/sync/reconciliation/serviceTypes.d.ts +8 -1
- package/sync/reconciliation/serviceTypes.js.map +1 -1
- package/workflows/container-contents/pendingWrites/index.d.ts +5 -0
- package/workflows/container-contents/pendingWrites/index.js +7 -0
- package/workflows/container-contents/pendingWrites/index.js.map +1 -1
- package/workflows/container-contents/remoteHydration/index.js +7 -1
- package/workflows/container-contents/remoteHydration/index.js.map +1 -1
- package/workflows/container-contents/remoteHydration/remoteContainers/organizationSyncPauseFilter.js +13 -0
- package/workflows/container-contents/remoteHydration/remoteContainers/organizationSyncPauseFilter.js.map +1 -0
- package/workflows/container-contents/remoteHydration/remoteContainers/remoteContainerPageHydration.js +13 -2
- package/workflows/container-contents/remoteHydration/remoteContainers/remoteContainerPageHydration.js.map +1 -1
- package/workflows/container-contents/syncPause/discoveryGuard.js +31 -0
- package/workflows/container-contents/syncPause/discoveryGuard.js.map +1 -0
- package/workflows/container-contents/syncPause/documentRemoval.js +154 -0
- package/workflows/container-contents/syncPause/documentRemoval.js.map +1 -0
- package/workflows/organizations/index.d.ts +3 -0
- package/workflows/organizations/index.js +3 -0
- package/workflows/organizations/index.js.map +1 -1
- package/workflows/organizations/memberships/leaveRequest.d.ts +31 -0
- package/workflows/organizations/memberships/leaveRequest.js +20 -0
- package/workflows/organizations/memberships/leaveRequest.js.map +1 -0
- package/workflows/organizations/memberships/leaveRequestVerification.d.ts +15 -0
- package/workflows/organizations/memberships/leaveRequestVerification.js +46 -0
- package/workflows/organizations/memberships/leaveRequestVerification.js.map +1 -0
- package/workflows/organizations/memberships/organizationMemberships.d.ts +84 -0
- package/workflows/organizations/memberships/organizationMemberships.js +95 -0
- package/workflows/organizations/memberships/organizationMemberships.js.map +1 -0
- package/workflows/sync/index.d.ts +1 -0
- package/workflows/sync/index.js +1 -0
- package/workflows/sync/index.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { NativeSubscriptionStore } from \"@tearleads/validators/billing\";\nimport { runWithSecurityIncidentReporting } from \"../../data/keyingProjectionVerification/error\";\nimport {\n cancelStripeSubscription,\n checkNativePurchaseEligibility,\n claimNativeOrganizationSubscription,\n createStripeCheckout,\n createStripeCheckoutSession,\n importOrganizationUser,\n listLocalOrganizations,\n loadOrganizationBilling,\n loadOrganizationBillingHistory,\n loadOrganizationBillingManagementUrl,\n loadStripeCheckoutOptions,\n startOrganizationTrial,\n updateOrganizationProfile,\n updateOrganizationRosterEntry,\n} from \"../../workflows/organizations\";\nimport type { ContainerContents } from \"../containerContents\";\nimport type { InternalRuntime } from \"../runtime/workflowRuntime\";\nimport {\n createOrganizationDataUsageCoordinator,\n type OrganizationDataUsageCoordinator,\n} from \"./organizationDataUsage\";\nimport { loadOrganizationGroupPresentationDetails } from \"./organizationGroupPresentation\";\nimport {\n createOrganizationReadModelCoordinator,\n type OrganizationReadModelCoordinator,\n} from \"./organizationReadModels\";\nimport type { Organizations } from \"./organizationsTypes\";\nimport {\n authenticatedOrganizationId,\n runForOrganization,\n} from \"./organizationWorkflowRuntime\";\nimport {\n type AbandonOrganizationPolicyMutationInput,\n abandonPendingOrganizationPolicyMutation,\n type DiscardUnreadableOrganizationPolicyMutationInput,\n discardUnreadableOrganizationPolicyMutation,\n readPendingOrganizationPolicyMutation,\n retryPendingOrganizationPolicyMutation,\n} from \"./principalMutationRecovery\";\nimport { currentOrganizationMutation } from \"./principalMutationScope\";\nimport {\n type AddOrganizationGroupUserInput,\n addUserToOrganizationGroup,\n createGroupForOrganization,\n deleteGroupForOrganization,\n type OrganizationGrantRef,\n type RemoveOrganizationGroupUserInput,\n removeUserFromOrganizationGroup,\n revokeOrganizationGrant,\n} from \"./principalMutations\";\n\nexport type {\n ImportedOrganizationUser,\n LocalOrganizationSummary,\n OrganizationBilling,\n OrganizationBillingHistory,\n OrganizationBillingHistoryEntry,\n OrganizationBillingManagementUrl,\n OrganizationBillingView,\n OrganizationContainerGrant,\n OrganizationContainerGrants,\n OrganizationDataUsage,\n OrganizationDirectory,\n OrganizationDirectoryAndGroups,\n OrganizationDirectoryUser,\n OrganizationGroupContainer,\n OrganizationGroupContainers,\n OrganizationGroupDetails,\n OrganizationGroupMember,\n OrganizationGroupMembers,\n OrganizationGroupPolicyHistory,\n OrganizationGroupSummary,\n OrganizationPolicyGrantChange,\n OrganizationPolicyGroupChange,\n OrganizationPolicyHistory,\n OrganizationPolicyHistoryEntry,\n OrganizationProfile,\n OrganizationUserDetail,\n} from \"../../workflows/organizations\";\nexport type {\n OrganizationGroupMutationReceipt,\n Organizations,\n} from \"./organizationsTypes\";\nexport type {\n AbandonOrganizationPolicyMutationInput,\n DiscardUnreadableOrganizationPolicyMutationInput,\n} from \"./principalMutationRecovery\";\nexport type {\n AddOrganizationGroupUserInput,\n OrganizationGrantRef,\n RemoveOrganizationGroupUserInput,\n} from \"./principalMutations\";\n\nexport function createOrganizations(\n runtime: InternalRuntime,\n containerContents: ContainerContents,\n): Organizations {\n return new OrganizationsService(runtime, containerContents);\n}\n\nclass OrganizationsService implements Organizations {\n private readonly dataUsageCoordinator: OrganizationDataUsageCoordinator;\n private readonly readModelCoordinator: OrganizationReadModelCoordinator;\n\n constructor(\n private readonly runtimeService: InternalRuntime,\n private readonly containerContents: ContainerContents,\n ) {\n this.dataUsageCoordinator = createOrganizationDataUsageCoordinator(\n this.runtimeService,\n );\n this.readModelCoordinator = createOrganizationReadModelCoordinator(\n this.runtimeService,\n );\n }\n\n async addUserToGroup(input: AddOrganizationGroupUserInput) {\n return addUserToOrganizationGroup({\n ...input,\n containerContents: this.containerContents,\n readModelCoordinator: this.readModelCoordinator,\n ...currentOrganizationMutation(this.runtimeService),\n });\n }\n\n readPendingPolicyMutation(organizationId: string) {\n return readPendingOrganizationPolicyMutation(\n this.runtimeService,\n organizationId,\n );\n }\n\n discardUnreadablePolicyMutation(\n input: DiscardUnreadableOrganizationPolicyMutationInput,\n ) {\n return discardUnreadableOrganizationPolicyMutation(\n this.runtimeService,\n input,\n );\n }\n\n retryPendingPolicyMutation(organizationId: string) {\n return retryPendingOrganizationPolicyMutation(\n this.runtimeService,\n organizationId,\n );\n }\n\n abandonPendingPolicyMutation(input: AbandonOrganizationPolicyMutationInput) {\n return abandonPendingOrganizationPolicyMutation(this.runtimeService, input);\n }\n\n createGroup(name: string) {\n return createGroupForOrganization({\n name,\n ...currentOrganizationMutation(this.runtimeService),\n });\n }\n\n deleteGroup(groupId: string) {\n return deleteGroupForOrganization({\n groupId,\n ...currentOrganizationMutation(this.runtimeService),\n });\n }\n\n importUserById(userId: string) {\n const runtime = this.runtimeService.workflowInput();\n return importOrganizationUser({\n resolveTrustedUserIdentity: runtime.resolveTrustedUserIdentity,\n userId,\n });\n }\n\n loadBilling() {\n return runForOrganization(this.runtimeService, loadOrganizationBilling);\n }\n\n loadBillingForOrganization(organizationId: string) {\n // Gated on an authenticated session rather than on the target being the\n // active org. The server still enforces membership, so an org the caller\n // cannot reach resolves to `null`.\n return runForOrganization(\n this.runtimeService,\n loadOrganizationBilling,\n organizationId,\n );\n }\n\n loadBillingHistory() {\n return runForOrganization(\n this.runtimeService,\n loadOrganizationBillingHistory,\n );\n }\n\n loadBillingManagementUrl() {\n return runForOrganization(\n this.runtimeService,\n loadOrganizationBillingManagementUrl,\n );\n }\n\n loadStripeCheckoutOptions(organizationId?: string) {\n return runForOrganization(\n this.runtimeService,\n loadStripeCheckoutOptions,\n organizationId,\n );\n }\n\n createStripeCheckout(organizationId?: string) {\n return runForOrganization(\n this.runtimeService,\n createStripeCheckout,\n organizationId,\n );\n }\n\n createStripeCheckoutSession(returnUrl: string, organizationId?: string) {\n return runForOrganization(\n this.runtimeService,\n (input) => createStripeCheckoutSession({ ...input, returnUrl }),\n organizationId,\n );\n }\n\n cancelStripeSubscription() {\n return runForOrganization(this.runtimeService, cancelStripeSubscription);\n }\n\n claimNativeSubscription(\n organizationId: string,\n store: NativeSubscriptionStore,\n ) {\n return runForOrganization(\n this.runtimeService,\n (input) => claimNativeOrganizationSubscription({ ...input, store }),\n organizationId,\n );\n }\n\n checkNativePurchaseEligibility(\n organizationId: string,\n store: NativeSubscriptionStore,\n ) {\n return runForOrganization(\n this.runtimeService,\n (input) => checkNativePurchaseEligibility({ ...input, store }),\n organizationId,\n );\n }\n\n loadDataUsage() {\n return this.dataUsageCoordinator.reconcile();\n }\n\n loadLocalDataUsage() {\n return this.dataUsageCoordinator.loadLocal();\n }\n\n loadDirectoryAndGroups() {\n const runtime = this.runtimeService.workflowInput();\n return runWithSecurityIncidentReporting(\n runtime.util.reportSecurityIncident,\n {\n objectId: runtime.auth.organizationId,\n objectKind: \"principal\",\n operation: \"organization.read_model.reconcile\",\n organizationId: runtime.auth.organizationId,\n },\n () => this.readModelCoordinator.reconcile(),\n );\n }\n\n loadDirectoryAndGroupsAfterMutation() {\n const runtime = this.runtimeService.workflowInput();\n return runWithSecurityIncidentReporting(\n runtime.util.reportSecurityIncident,\n {\n objectId: runtime.auth.organizationId,\n objectKind: \"principal\",\n operation: \"organization.read_model.reconcile_after_mutation\",\n organizationId: runtime.auth.organizationId,\n },\n () => this.readModelCoordinator.reconcileAfterMutation(),\n );\n }\n\n loadLocalDirectoryAndGroups() {\n return this.readModelCoordinator.loadLocal();\n }\n\n loadGroupMembers(groupId: string) {\n const runtime = this.runtimeService.workflowInput();\n const organizationId = authenticatedOrganizationId(runtime);\n if (!organizationId || groupId.length === 0) {\n return Promise.resolve(null);\n }\n\n return runtime.apiClient.listOrganizationGroupMembers(\n organizationId,\n groupId,\n );\n }\n\n loadGroupPresentationDetails(groupId: string, beforeVersion?: number) {\n const runtime = this.runtimeService.workflowInput();\n return runWithSecurityIncidentReporting(\n runtime.util.reportSecurityIncident,\n {\n objectId: groupId,\n objectKind: \"principal\",\n operation: \"group.presentation.load\",\n organizationId: runtime.auth.organizationId,\n },\n () =>\n loadOrganizationGroupPresentationDetails({\n groupId,\n beforeVersion,\n readModelCoordinator: this.readModelCoordinator,\n runtime,\n }),\n );\n }\n\n loadGrants() {\n return this.readModelCoordinator.loadLocalGrants();\n }\n\n loadGroupContainers(groupId: string) {\n return this.readModelCoordinator.loadLocalGroupContainers(groupId);\n }\n\n listLocalOrganizations() {\n const runtime = this.runtimeService.workflowInput();\n if (runtime.infra.dbStatus !== \"ready\") {\n return Promise.resolve([]);\n }\n\n return listLocalOrganizations({ execSql: runtime.infra.execSql });\n }\n\n loadPolicyHistory(beforeVersion?: number) {\n const runtime = this.runtimeService.workflowInput();\n return runWithSecurityIncidentReporting(\n runtime.util.reportSecurityIncident,\n {\n objectId: runtime.auth.organizationId,\n objectKind: \"principal\",\n operation: \"organization.policy_history.load\",\n organizationId: runtime.auth.organizationId,\n },\n () =>\n this.readModelCoordinator.loadOrganizationPolicyHistory(\n undefined,\n beforeVersion,\n ),\n );\n }\n\n loadUserDetail(userId: string) {\n return this.readModelCoordinator.loadLocalUserDetail(userId);\n }\n\n updateRosterEntry(userId: string, profileDocumentId: string | null) {\n const runtime = this.runtimeService.workflowInput();\n const organizationId = authenticatedOrganizationId(runtime);\n if (!organizationId || userId.length === 0) {\n return Promise.resolve(null);\n }\n\n return updateOrganizationRosterEntry({\n apiClient: runtime.apiClient,\n organizationId,\n profileDocumentId,\n userId,\n });\n }\n\n updateProfile(profileDocumentId: string | null) {\n const runtime = this.runtimeService.workflowInput();\n const organizationId = authenticatedOrganizationId(runtime);\n if (!organizationId) {\n return Promise.resolve(null);\n }\n\n return updateOrganizationProfile({\n apiClient: runtime.apiClient,\n organizationId,\n profileDocumentId,\n });\n }\n\n async removeUserFromGroup(input: RemoveOrganizationGroupUserInput) {\n return removeUserFromOrganizationGroup({\n ...input,\n containerContents: this.containerContents,\n readModelCoordinator: this.readModelCoordinator,\n ...currentOrganizationMutation(this.runtimeService),\n });\n }\n\n async revokeGrant(grant: OrganizationGrantRef) {\n return revokeOrganizationGrant({\n ...grant,\n containerContents: this.containerContents,\n readModelCoordinator: this.readModelCoordinator,\n ...currentOrganizationMutation(this.runtimeService),\n });\n }\n\n startTrial(organizationId?: string) {\n return runForOrganization(\n this.runtimeService,\n startOrganizationTrial,\n organizationId,\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { NativeSubscriptionStore } from \"@tearleads/validators/billing\";\nimport { runWithSecurityIncidentReporting } from \"../../data/keyingProjectionVerification/error\";\nimport {\n cancelStripeSubscription,\n checkNativePurchaseEligibility,\n claimNativeOrganizationSubscription,\n createStripeCheckout,\n createStripeCheckoutSession,\n importOrganizationUser,\n listLocalOrganizations,\n loadOrganizationBilling,\n loadOrganizationBillingHistory,\n loadOrganizationBillingManagementUrl,\n loadStripeCheckoutOptions,\n startOrganizationTrial,\n updateOrganizationProfile,\n updateOrganizationRosterEntry,\n withVerifiedDirectoryUser,\n} from \"../../workflows/organizations\";\nimport type { ContainerContents } from \"../containerContents\";\nimport type { InternalRuntime } from \"../runtime/workflowRuntime\";\nimport {\n createOrganizationDataUsageCoordinator,\n type OrganizationDataUsageCoordinator,\n} from \"./organizationDataUsage\";\nimport { loadOrganizationGroupPresentationDetails } from \"./organizationGroupPresentation\";\nimport {\n createOrganizationMemberships,\n type OrganizationContentReconciler,\n type OrganizationMemberships,\n} from \"./organizationMemberships\";\nimport {\n createOrganizationReadModelCoordinator,\n leaveRequestSignerResolver,\n type OrganizationReadModelCoordinator,\n} from \"./organizationReadModels\";\nimport type { Organizations } from \"./organizationsTypes\";\nimport {\n authenticatedOrganizationId,\n runForOrganization,\n} from \"./organizationWorkflowRuntime\";\nimport {\n type AbandonOrganizationPolicyMutationInput,\n abandonPendingOrganizationPolicyMutation,\n type DiscardUnreadableOrganizationPolicyMutationInput,\n discardUnreadableOrganizationPolicyMutation,\n readPendingOrganizationPolicyMutation,\n retryPendingOrganizationPolicyMutation,\n} from \"./principalMutationRecovery\";\nimport { currentOrganizationMutation } from \"./principalMutationScope\";\nimport {\n type AddOrganizationGroupUserInput,\n addUserToOrganizationGroup,\n createGroupForOrganization,\n deleteGroupForOrganization,\n type OrganizationGrantRef,\n type RemoveOrganizationGroupUserInput,\n removeUserFromOrganizationGroup,\n revokeOrganizationGrant,\n} from \"./principalMutations\";\n\nexport type {\n ImportedOrganizationUser,\n LocalOrganizationSummary,\n OrganizationBilling,\n OrganizationBillingHistory,\n OrganizationBillingHistoryEntry,\n OrganizationBillingManagementUrl,\n OrganizationBillingView,\n OrganizationContainerGrant,\n OrganizationContainerGrants,\n OrganizationDataUsage,\n OrganizationDirectory,\n OrganizationDirectoryAndGroups,\n OrganizationDirectoryUser,\n OrganizationGroupContainer,\n OrganizationGroupContainers,\n OrganizationGroupDetails,\n OrganizationGroupMember,\n OrganizationGroupMembers,\n OrganizationGroupPolicyHistory,\n OrganizationGroupSummary,\n OrganizationLeaveRequestResult,\n OrganizationMembership,\n OrganizationPolicyGrantChange,\n OrganizationPolicyGroupChange,\n OrganizationPolicyHistory,\n OrganizationPolicyHistoryEntry,\n OrganizationProfile,\n OrganizationSyncPauseResult,\n OrganizationUserDetail,\n} from \"../../workflows/organizations\";\nexport type {\n OrganizationContentReconciler,\n OrganizationMemberships,\n} from \"./organizationMemberships\";\nexport type {\n OrganizationGroupMutationReceipt,\n Organizations,\n} from \"./organizationsTypes\";\nexport type {\n AbandonOrganizationPolicyMutationInput,\n DiscardUnreadableOrganizationPolicyMutationInput,\n} from \"./principalMutationRecovery\";\nexport type {\n AddOrganizationGroupUserInput,\n OrganizationGrantRef,\n RemoveOrganizationGroupUserInput,\n} from \"./principalMutations\";\n\nexport function createOrganizations(\n runtime: InternalRuntime,\n containerContents: ContainerContents,\n openReconciler: () => OrganizationContentReconciler,\n): Organizations {\n return new OrganizationsService(runtime, containerContents, openReconciler);\n}\n\nclass OrganizationsService implements Organizations {\n readonly memberships: OrganizationMemberships;\n private readonly dataUsageCoordinator: OrganizationDataUsageCoordinator;\n private readonly readModelCoordinator: OrganizationReadModelCoordinator;\n\n constructor(\n private readonly runtimeService: InternalRuntime,\n private readonly containerContents: ContainerContents,\n openReconciler: () => OrganizationContentReconciler,\n ) {\n this.dataUsageCoordinator = createOrganizationDataUsageCoordinator(\n this.runtimeService,\n );\n this.readModelCoordinator = createOrganizationReadModelCoordinator(\n this.runtimeService,\n );\n this.memberships = createOrganizationMemberships(\n this.runtimeService,\n this.containerContents,\n openReconciler,\n );\n }\n\n async addUserToGroup(input: AddOrganizationGroupUserInput) {\n return addUserToOrganizationGroup({\n ...input,\n containerContents: this.containerContents,\n readModelCoordinator: this.readModelCoordinator,\n ...currentOrganizationMutation(this.runtimeService),\n });\n }\n\n readPendingPolicyMutation(organizationId: string) {\n return readPendingOrganizationPolicyMutation(\n this.runtimeService,\n organizationId,\n );\n }\n\n discardUnreadablePolicyMutation(\n input: DiscardUnreadableOrganizationPolicyMutationInput,\n ) {\n return discardUnreadableOrganizationPolicyMutation(\n this.runtimeService,\n input,\n );\n }\n\n retryPendingPolicyMutation(organizationId: string) {\n return retryPendingOrganizationPolicyMutation(\n this.runtimeService,\n organizationId,\n );\n }\n\n abandonPendingPolicyMutation(input: AbandonOrganizationPolicyMutationInput) {\n return abandonPendingOrganizationPolicyMutation(this.runtimeService, input);\n }\n\n createGroup(name: string) {\n return createGroupForOrganization({\n name,\n ...currentOrganizationMutation(this.runtimeService),\n });\n }\n\n deleteGroup(groupId: string) {\n return deleteGroupForOrganization({\n groupId,\n ...currentOrganizationMutation(this.runtimeService),\n });\n }\n\n importUserById(userId: string) {\n const runtime = this.runtimeService.workflowInput();\n return importOrganizationUser({\n resolveTrustedUserIdentity: runtime.resolveTrustedUserIdentity,\n userId,\n });\n }\n\n loadBilling() {\n return runForOrganization(this.runtimeService, loadOrganizationBilling);\n }\n\n loadBillingForOrganization(organizationId: string) {\n // Gated on an authenticated session rather than on the target being the\n // active org. The server still enforces membership, so an org the caller\n // cannot reach resolves to `null`.\n return runForOrganization(\n this.runtimeService,\n loadOrganizationBilling,\n organizationId,\n );\n }\n\n loadBillingHistory() {\n return runForOrganization(\n this.runtimeService,\n loadOrganizationBillingHistory,\n );\n }\n\n loadBillingManagementUrl() {\n return runForOrganization(\n this.runtimeService,\n loadOrganizationBillingManagementUrl,\n );\n }\n\n loadStripeCheckoutOptions(organizationId?: string) {\n return runForOrganization(\n this.runtimeService,\n loadStripeCheckoutOptions,\n organizationId,\n );\n }\n\n createStripeCheckout(organizationId?: string) {\n return runForOrganization(\n this.runtimeService,\n createStripeCheckout,\n organizationId,\n );\n }\n\n createStripeCheckoutSession(returnUrl: string, organizationId?: string) {\n return runForOrganization(\n this.runtimeService,\n (input) => createStripeCheckoutSession({ ...input, returnUrl }),\n organizationId,\n );\n }\n\n cancelStripeSubscription() {\n return runForOrganization(this.runtimeService, cancelStripeSubscription);\n }\n\n claimNativeSubscription(\n organizationId: string,\n store: NativeSubscriptionStore,\n ) {\n return runForOrganization(\n this.runtimeService,\n (input) => claimNativeOrganizationSubscription({ ...input, store }),\n organizationId,\n );\n }\n\n checkNativePurchaseEligibility(\n organizationId: string,\n store: NativeSubscriptionStore,\n ) {\n return runForOrganization(\n this.runtimeService,\n (input) => checkNativePurchaseEligibility({ ...input, store }),\n organizationId,\n );\n }\n\n loadDataUsage() {\n return this.dataUsageCoordinator.reconcile();\n }\n\n loadLocalDataUsage() {\n return this.dataUsageCoordinator.loadLocal();\n }\n\n loadDirectoryAndGroups() {\n const runtime = this.runtimeService.workflowInput();\n return runWithSecurityIncidentReporting(\n runtime.util.reportSecurityIncident,\n {\n objectId: runtime.auth.organizationId,\n objectKind: \"principal\",\n operation: \"organization.read_model.reconcile\",\n organizationId: runtime.auth.organizationId,\n },\n () => this.readModelCoordinator.reconcile(),\n );\n }\n\n loadDirectoryAndGroupsAfterMutation() {\n const runtime = this.runtimeService.workflowInput();\n return runWithSecurityIncidentReporting(\n runtime.util.reportSecurityIncident,\n {\n objectId: runtime.auth.organizationId,\n objectKind: \"principal\",\n operation: \"organization.read_model.reconcile_after_mutation\",\n organizationId: runtime.auth.organizationId,\n },\n () => this.readModelCoordinator.reconcileAfterMutation(),\n );\n }\n\n loadLocalDirectoryAndGroups() {\n return this.readModelCoordinator.loadLocal();\n }\n\n loadGroupMembers(groupId: string) {\n const runtime = this.runtimeService.workflowInput();\n const organizationId = authenticatedOrganizationId(runtime);\n if (!organizationId || groupId.length === 0) {\n return Promise.resolve(null);\n }\n\n return runtime.apiClient.listOrganizationGroupMembers(\n organizationId,\n groupId,\n );\n }\n\n loadGroupPresentationDetails(groupId: string, beforeVersion?: number) {\n const runtime = this.runtimeService.workflowInput();\n return runWithSecurityIncidentReporting(\n runtime.util.reportSecurityIncident,\n {\n objectId: groupId,\n objectKind: \"principal\",\n operation: \"group.presentation.load\",\n organizationId: runtime.auth.organizationId,\n },\n () =>\n loadOrganizationGroupPresentationDetails({\n groupId,\n beforeVersion,\n readModelCoordinator: this.readModelCoordinator,\n runtime,\n }),\n );\n }\n\n loadGrants() {\n return this.readModelCoordinator.loadLocalGrants();\n }\n\n loadGroupContainers(groupId: string) {\n return this.readModelCoordinator.loadLocalGroupContainers(groupId);\n }\n\n listLocalOrganizations() {\n const runtime = this.runtimeService.workflowInput();\n if (runtime.infra.dbStatus !== \"ready\") {\n return Promise.resolve([]);\n }\n\n return listLocalOrganizations({ execSql: runtime.infra.execSql });\n }\n\n loadPolicyHistory(beforeVersion?: number) {\n const runtime = this.runtimeService.workflowInput();\n return runWithSecurityIncidentReporting(\n runtime.util.reportSecurityIncident,\n {\n objectId: runtime.auth.organizationId,\n objectKind: \"principal\",\n operation: \"organization.policy_history.load\",\n organizationId: runtime.auth.organizationId,\n },\n () =>\n this.readModelCoordinator.loadOrganizationPolicyHistory(\n undefined,\n beforeVersion,\n ),\n );\n }\n\n loadUserDetail(userId: string) {\n return this.readModelCoordinator.loadLocalUserDetail(userId);\n }\n\n async updateRosterEntry(userId: string, profileDocumentId: string | null) {\n const runtime = this.runtimeService.workflowInput();\n const organizationId = authenticatedOrganizationId(runtime);\n if (!organizationId || userId.length === 0) {\n return null;\n }\n\n const user = await updateOrganizationRosterEntry({\n apiClient: runtime.apiClient,\n organizationId,\n profileDocumentId,\n userId,\n });\n // Callers store this response as directory state, so its leave request\n // passes the same check as one read from the read model.\n return (\n user &&\n withVerifiedDirectoryUser(\n organizationId,\n user,\n leaveRequestSignerResolver(this.runtimeService, runtime),\n )\n );\n }\n\n updateProfile(profileDocumentId: string | null) {\n const runtime = this.runtimeService.workflowInput();\n const organizationId = authenticatedOrganizationId(runtime);\n if (!organizationId) {\n return Promise.resolve(null);\n }\n\n return updateOrganizationProfile({\n apiClient: runtime.apiClient,\n organizationId,\n profileDocumentId,\n });\n }\n\n async removeUserFromGroup(input: RemoveOrganizationGroupUserInput) {\n return removeUserFromOrganizationGroup({\n ...input,\n containerContents: this.containerContents,\n readModelCoordinator: this.readModelCoordinator,\n ...currentOrganizationMutation(this.runtimeService),\n });\n }\n\n async revokeGrant(grant: OrganizationGrantRef) {\n return revokeOrganizationGrant({\n ...grant,\n containerContents: this.containerContents,\n readModelCoordinator: this.readModelCoordinator,\n ...currentOrganizationMutation(this.runtimeService),\n });\n }\n\n startTrial(organizationId?: string) {\n return runForOrganization(\n this.runtimeService,\n startOrganizationTrial,\n organizationId,\n );\n }\n}\n"]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type OrganizationLeaveRequestResult, type OrganizationMembership, type OrganizationSyncPauseResult } from "../../workflows/organizations/index.js";
|
|
2
|
+
import { type DomainScope } from "../../workflows/sync/index.js";
|
|
3
|
+
import { type ContainerContents } from "../containerContents/index.js";
|
|
4
|
+
import type { InternalRuntime } from "../runtime/workflowRuntime.js";
|
|
5
|
+
/** The user's own conduit to the organizations they belong to. */
|
|
6
|
+
export interface OrganizationMemberships {
|
|
7
|
+
/**
|
|
8
|
+
* Reads the user's memberships and applies their pause choices on this
|
|
9
|
+
* device. Null when offline or the list could not be read.
|
|
10
|
+
*/
|
|
11
|
+
refresh(): Promise<OrganizationMembership[] | null>;
|
|
12
|
+
/** Pauses or resumes one organization for all of the user's devices. */
|
|
13
|
+
setSyncPaused(organizationId: string, paused: boolean): Promise<OrganizationSyncPauseResult>;
|
|
14
|
+
/**
|
|
15
|
+
* Asks the organization's administrators to remove the user, or withdraws
|
|
16
|
+
* that request. Signed with the user's identity key; an administrator still
|
|
17
|
+
* has to approve it.
|
|
18
|
+
*/
|
|
19
|
+
setLeaveRequested(organizationId: string, requested: boolean): Promise<OrganizationLeaveRequestResult>;
|
|
20
|
+
/** The organizations paused on this device, read from local storage. */
|
|
21
|
+
loadPausedOrganizationIds(): Promise<ReadonlySet<string>>;
|
|
22
|
+
/** Notifies when the paused set for the current scope changes. */
|
|
23
|
+
subscribeToSyncPauses(listener: () => void): () => void;
|
|
24
|
+
/**
|
|
25
|
+
* Hands each membership list a refresh reads for the current scope, so a
|
|
26
|
+
* choice made on another device reaches every view of it.
|
|
27
|
+
*/
|
|
28
|
+
subscribeToMemberships(listener: (memberships: readonly OrganizationMembership[]) => void): () => void;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The scope's document reconciler. Containers it reconciled before a pause
|
|
32
|
+
* stay marked as listed, so a resume has to forget that before reconciling.
|
|
33
|
+
*/
|
|
34
|
+
export interface OrganizationContentReconciler {
|
|
35
|
+
resetDiscovered(): void;
|
|
36
|
+
reconcileNow(options: {
|
|
37
|
+
readonly freshListing: true;
|
|
38
|
+
}): Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
export declare function retryWhenWritesSettle(domainScope: DomainScope, retry: () => Promise<boolean>): void;
|
|
41
|
+
export declare function createOrganizationMemberships(runtimeService: InternalRuntime, containerContents: ContainerContents, openReconciler: () => OrganizationContentReconciler): OrganizationMemberships;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { refreshOrganizationMemberships, setOrganizationLeaveRequested, setOrganizationSyncPaused, } from "../../workflows/organizations/index.js";
|
|
2
|
+
import { getOrCreateOrganizationSyncPauses, hasDomainSyncCoordinatorPendingWork, requestAllDomainSyncLanes, subscribeToDomainSyncCoordinator, waitForDomainSyncCoordinatorToSettle, } from "../../workflows/sync/index.js";
|
|
3
|
+
import { carriesLocalWrites, } from "../containerContents/index.js";
|
|
4
|
+
// Long enough for a typical upload burst, short enough to answer a tap.
|
|
5
|
+
const PAUSE_FLUSH_TIMEOUT_MS = 10_000;
|
|
6
|
+
const membershipListenersByScope = new WeakMap();
|
|
7
|
+
const settleRetriesByScope = new WeakMap();
|
|
8
|
+
// One retry per scope: it runs whenever the scope's sync lanes go idle and
|
|
9
|
+
// stops once it reports the work done.
|
|
10
|
+
export function retryWhenWritesSettle(domainScope, retry) {
|
|
11
|
+
const existing = settleRetriesByScope.get(domainScope);
|
|
12
|
+
if (existing) {
|
|
13
|
+
existing.retry = retry;
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const entry = { retry, running: false, unsubscribe: () => { } };
|
|
17
|
+
settleRetriesByScope.set(domainScope, entry);
|
|
18
|
+
const attempt = () => {
|
|
19
|
+
if (entry.running || hasDomainSyncCoordinatorPendingWork(domainScope)) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
entry.running = true;
|
|
23
|
+
void entry
|
|
24
|
+
.retry()
|
|
25
|
+
.then((done) => {
|
|
26
|
+
if (!done)
|
|
27
|
+
return;
|
|
28
|
+
entry.unsubscribe();
|
|
29
|
+
settleRetriesByScope.delete(domainScope);
|
|
30
|
+
}, () => undefined)
|
|
31
|
+
.finally(() => {
|
|
32
|
+
entry.running = false;
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
entry.unsubscribe = subscribeToDomainSyncCoordinator(domainScope, attempt);
|
|
36
|
+
// The lanes may already have gone idle before the subscription existed.
|
|
37
|
+
attempt();
|
|
38
|
+
}
|
|
39
|
+
// Bound to the scope the operation started in: the tree is opened once, and
|
|
40
|
+
// every action re-checks the scope so stale work never reaches another
|
|
41
|
+
// identity's device state.
|
|
42
|
+
function createOrganizationContentHost(runtime, containerContents, openReconciler, isCurrent) {
|
|
43
|
+
const { domainScope } = runtime.state;
|
|
44
|
+
const tree = containerContents.openTree();
|
|
45
|
+
return {
|
|
46
|
+
async forgetOrganizationContent(organizationId) {
|
|
47
|
+
// A scope that ended has nothing left to retry.
|
|
48
|
+
if (!isCurrent())
|
|
49
|
+
return true;
|
|
50
|
+
return tree.forgetOrganizationContent(organizationId);
|
|
51
|
+
},
|
|
52
|
+
async hasUnsyncedOrganizationWrites(organizationId) {
|
|
53
|
+
if (!isCurrent())
|
|
54
|
+
return true;
|
|
55
|
+
const pending = await containerContents
|
|
56
|
+
.documentQueries()
|
|
57
|
+
.listPendingWrites();
|
|
58
|
+
return pending.some((item) => item.organizationId === organizationId && carriesLocalWrites(item));
|
|
59
|
+
},
|
|
60
|
+
async flushWrites() {
|
|
61
|
+
requestAllDomainSyncLanes(domainScope);
|
|
62
|
+
await waitForDomainSyncCoordinatorToSettle(domainScope, {
|
|
63
|
+
timeoutMs: PAUSE_FLUSH_TIMEOUT_MS,
|
|
64
|
+
});
|
|
65
|
+
},
|
|
66
|
+
async refetchContent() {
|
|
67
|
+
if (!isCurrent())
|
|
68
|
+
return;
|
|
69
|
+
// Re-lists the whole tree and every container's documents. The resumed
|
|
70
|
+
// organization's folders were listed before the pause, and a hydration
|
|
71
|
+
// may already have restored them, so they must be forgotten explicitly.
|
|
72
|
+
// A sweep that started listing while paused would miss them, so this
|
|
73
|
+
// one queues behind it rather than joining it.
|
|
74
|
+
const reconciler = openReconciler();
|
|
75
|
+
reconciler.resetDiscovered();
|
|
76
|
+
await reconciler.reconcileNow({ freshListing: true });
|
|
77
|
+
},
|
|
78
|
+
retryWhenWritesSettle: (retry) => retryWhenWritesSettle(domainScope, retry),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function canReachServer(runtime) {
|
|
82
|
+
return (runtime.infra.dbStatus === "ready" &&
|
|
83
|
+
runtime.auth.isAuthenticated &&
|
|
84
|
+
runtime.state.online);
|
|
85
|
+
}
|
|
86
|
+
export function createOrganizationMemberships(runtimeService, containerContents, openReconciler) {
|
|
87
|
+
const membershipInput = (runtime) => {
|
|
88
|
+
const { domainScope } = runtime.state;
|
|
89
|
+
const isCurrent = () => runtimeService.workflowInput().state.domainScope === domainScope;
|
|
90
|
+
return {
|
|
91
|
+
apiClient: runtime.apiClient,
|
|
92
|
+
domainScope,
|
|
93
|
+
execSql: runtime.infra.execSql,
|
|
94
|
+
host: createOrganizationContentHost(runtime, containerContents, openReconciler, isCurrent),
|
|
95
|
+
isCurrent,
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
return {
|
|
99
|
+
async refresh() {
|
|
100
|
+
const runtime = runtimeService.workflowInput();
|
|
101
|
+
if (!canReachServer(runtime))
|
|
102
|
+
return null;
|
|
103
|
+
const memberships = await refreshOrganizationMemberships(membershipInput(runtime));
|
|
104
|
+
const listeners = membershipListenersByScope.get(runtime.state.domainScope);
|
|
105
|
+
if (memberships && listeners) {
|
|
106
|
+
for (const listener of [...listeners])
|
|
107
|
+
listener(memberships);
|
|
108
|
+
}
|
|
109
|
+
return memberships;
|
|
110
|
+
},
|
|
111
|
+
async setSyncPaused(organizationId, paused) {
|
|
112
|
+
const runtime = runtimeService.workflowInput();
|
|
113
|
+
if (!canReachServer(runtime)) {
|
|
114
|
+
return {
|
|
115
|
+
httpStatus: null,
|
|
116
|
+
message: "Connect to change sync for an organization.",
|
|
117
|
+
status: "failed",
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return setOrganizationSyncPaused({
|
|
121
|
+
...membershipInput(runtime),
|
|
122
|
+
organizationId,
|
|
123
|
+
paused,
|
|
124
|
+
});
|
|
125
|
+
},
|
|
126
|
+
async setLeaveRequested(organizationId, requested) {
|
|
127
|
+
const runtime = runtimeService.workflowInput();
|
|
128
|
+
const { userId } = runtime.auth;
|
|
129
|
+
const { signingKeyPair } = runtime.crypto;
|
|
130
|
+
if (!canReachServer(runtime) || !userId || !signingKeyPair) {
|
|
131
|
+
return {
|
|
132
|
+
httpStatus: null,
|
|
133
|
+
message: "Connect to ask to leave an organization.",
|
|
134
|
+
status: "failed",
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
return setOrganizationLeaveRequested({
|
|
138
|
+
apiClient: runtime.apiClient,
|
|
139
|
+
organizationId,
|
|
140
|
+
requested,
|
|
141
|
+
signer: { signingKeyPair, userId },
|
|
142
|
+
});
|
|
143
|
+
},
|
|
144
|
+
async loadPausedOrganizationIds() {
|
|
145
|
+
const runtime = runtimeService.workflowInput();
|
|
146
|
+
if (runtime.infra.dbStatus !== "ready")
|
|
147
|
+
return new Set();
|
|
148
|
+
const pauses = getOrCreateOrganizationSyncPauses(runtime.state.domainScope);
|
|
149
|
+
await pauses.load(runtime.infra.execSql);
|
|
150
|
+
return pauses.pausedOrganizationIds();
|
|
151
|
+
},
|
|
152
|
+
subscribeToSyncPauses(listener) {
|
|
153
|
+
return getOrCreateOrganizationSyncPauses(runtimeService.workflowInput().state.domainScope).subscribe(listener);
|
|
154
|
+
},
|
|
155
|
+
subscribeToMemberships(listener) {
|
|
156
|
+
const { domainScope } = runtimeService.workflowInput().state;
|
|
157
|
+
const listeners = membershipListenersByScope.get(domainScope) ?? new Set();
|
|
158
|
+
membershipListenersByScope.set(domainScope, listeners);
|
|
159
|
+
listeners.add(listener);
|
|
160
|
+
return () => {
|
|
161
|
+
listeners.delete(listener);
|
|
162
|
+
};
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=organizationMemberships.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"organizationMemberships.js","sourceRoot":"","sources":["organizationMemberships.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type OrganizationContentHost,\n type OrganizationLeaveRequestResult,\n type OrganizationMembership,\n type OrganizationSyncPauseResult,\n refreshOrganizationMemberships,\n setOrganizationLeaveRequested,\n setOrganizationSyncPaused,\n} from \"../../workflows/organizations\";\nimport {\n type DomainScope,\n getOrCreateOrganizationSyncPauses,\n hasDomainSyncCoordinatorPendingWork,\n requestAllDomainSyncLanes,\n subscribeToDomainSyncCoordinator,\n waitForDomainSyncCoordinatorToSettle,\n} from \"../../workflows/sync\";\nimport {\n type ContainerContents,\n carriesLocalWrites,\n} from \"../containerContents\";\nimport type {\n InternalRuntime,\n InternalWorkflowRuntimeInput,\n} from \"../runtime/workflowRuntime\";\n\n// Long enough for a typical upload burst, short enough to answer a tap.\nconst PAUSE_FLUSH_TIMEOUT_MS = 10_000;\n\n/** The user's own conduit to the organizations they belong to. */\nexport interface OrganizationMemberships {\n /**\n * Reads the user's memberships and applies their pause choices on this\n * device. Null when offline or the list could not be read.\n */\n refresh(): Promise<OrganizationMembership[] | null>;\n /** Pauses or resumes one organization for all of the user's devices. */\n setSyncPaused(\n organizationId: string,\n paused: boolean,\n ): Promise<OrganizationSyncPauseResult>;\n /**\n * Asks the organization's administrators to remove the user, or withdraws\n * that request. Signed with the user's identity key; an administrator still\n * has to approve it.\n */\n setLeaveRequested(\n organizationId: string,\n requested: boolean,\n ): Promise<OrganizationLeaveRequestResult>;\n /** The organizations paused on this device, read from local storage. */\n loadPausedOrganizationIds(): Promise<ReadonlySet<string>>;\n /** Notifies when the paused set for the current scope changes. */\n subscribeToSyncPauses(listener: () => void): () => void;\n /**\n * Hands each membership list a refresh reads for the current scope, so a\n * choice made on another device reaches every view of it.\n */\n subscribeToMemberships(\n listener: (memberships: readonly OrganizationMembership[]) => void,\n ): () => void;\n}\n\ntype MembershipsListener = (\n memberships: readonly OrganizationMembership[],\n) => void;\n\nconst membershipListenersByScope = new WeakMap<\n DomainScope,\n Set<MembershipsListener>\n>();\n\n/**\n * The scope's document reconciler. Containers it reconciled before a pause\n * stay marked as listed, so a resume has to forget that before reconciling.\n */\nexport interface OrganizationContentReconciler {\n resetDiscovered(): void;\n reconcileNow(options: { readonly freshListing: true }): Promise<void>;\n}\n\ninterface SettleRetry {\n retry: () => Promise<boolean>;\n running: boolean;\n unsubscribe: () => void;\n}\n\nconst settleRetriesByScope = new WeakMap<DomainScope, SettleRetry>();\n\n// One retry per scope: it runs whenever the scope's sync lanes go idle and\n// stops once it reports the work done.\nexport function retryWhenWritesSettle(\n domainScope: DomainScope,\n retry: () => Promise<boolean>,\n): void {\n const existing = settleRetriesByScope.get(domainScope);\n if (existing) {\n existing.retry = retry;\n return;\n }\n const entry: SettleRetry = { retry, running: false, unsubscribe: () => {} };\n settleRetriesByScope.set(domainScope, entry);\n const attempt = () => {\n if (entry.running || hasDomainSyncCoordinatorPendingWork(domainScope)) {\n return;\n }\n entry.running = true;\n void entry\n .retry()\n .then(\n (done) => {\n if (!done) return;\n entry.unsubscribe();\n settleRetriesByScope.delete(domainScope);\n },\n () => undefined,\n )\n .finally(() => {\n entry.running = false;\n });\n };\n entry.unsubscribe = subscribeToDomainSyncCoordinator(domainScope, attempt);\n // The lanes may already have gone idle before the subscription existed.\n attempt();\n}\n\n// Bound to the scope the operation started in: the tree is opened once, and\n// every action re-checks the scope so stale work never reaches another\n// identity's device state.\nfunction createOrganizationContentHost(\n runtime: InternalWorkflowRuntimeInput,\n containerContents: ContainerContents,\n openReconciler: () => OrganizationContentReconciler,\n isCurrent: () => boolean,\n): OrganizationContentHost {\n const { domainScope } = runtime.state;\n const tree = containerContents.openTree();\n return {\n async forgetOrganizationContent(organizationId) {\n // A scope that ended has nothing left to retry.\n if (!isCurrent()) return true;\n return tree.forgetOrganizationContent(organizationId);\n },\n async hasUnsyncedOrganizationWrites(organizationId) {\n if (!isCurrent()) return true;\n const pending = await containerContents\n .documentQueries()\n .listPendingWrites();\n return pending.some(\n (item) =>\n item.organizationId === organizationId && carriesLocalWrites(item),\n );\n },\n async flushWrites() {\n requestAllDomainSyncLanes(domainScope);\n await waitForDomainSyncCoordinatorToSettle(domainScope, {\n timeoutMs: PAUSE_FLUSH_TIMEOUT_MS,\n });\n },\n async refetchContent() {\n if (!isCurrent()) return;\n // Re-lists the whole tree and every container's documents. The resumed\n // organization's folders were listed before the pause, and a hydration\n // may already have restored them, so they must be forgotten explicitly.\n // A sweep that started listing while paused would miss them, so this\n // one queues behind it rather than joining it.\n const reconciler = openReconciler();\n reconciler.resetDiscovered();\n await reconciler.reconcileNow({ freshListing: true });\n },\n retryWhenWritesSettle: (retry) => retryWhenWritesSettle(domainScope, retry),\n };\n}\n\nfunction canReachServer(runtime: InternalWorkflowRuntimeInput): boolean {\n return (\n runtime.infra.dbStatus === \"ready\" &&\n runtime.auth.isAuthenticated &&\n runtime.state.online\n );\n}\n\nexport function createOrganizationMemberships(\n runtimeService: InternalRuntime,\n containerContents: ContainerContents,\n openReconciler: () => OrganizationContentReconciler,\n): OrganizationMemberships {\n const membershipInput = (runtime: InternalWorkflowRuntimeInput) => {\n const { domainScope } = runtime.state;\n const isCurrent = () =>\n runtimeService.workflowInput().state.domainScope === domainScope;\n return {\n apiClient: runtime.apiClient,\n domainScope,\n execSql: runtime.infra.execSql,\n host: createOrganizationContentHost(\n runtime,\n containerContents,\n openReconciler,\n isCurrent,\n ),\n isCurrent,\n };\n };\n return {\n async refresh() {\n const runtime = runtimeService.workflowInput();\n if (!canReachServer(runtime)) return null;\n const memberships = await refreshOrganizationMemberships(\n membershipInput(runtime),\n );\n const listeners = membershipListenersByScope.get(\n runtime.state.domainScope,\n );\n if (memberships && listeners) {\n for (const listener of [...listeners]) listener(memberships);\n }\n return memberships;\n },\n async setSyncPaused(organizationId, paused) {\n const runtime = runtimeService.workflowInput();\n if (!canReachServer(runtime)) {\n return {\n httpStatus: null,\n message: \"Connect to change sync for an organization.\",\n status: \"failed\",\n };\n }\n return setOrganizationSyncPaused({\n ...membershipInput(runtime),\n organizationId,\n paused,\n });\n },\n async setLeaveRequested(organizationId, requested) {\n const runtime = runtimeService.workflowInput();\n const { userId } = runtime.auth;\n const { signingKeyPair } = runtime.crypto;\n if (!canReachServer(runtime) || !userId || !signingKeyPair) {\n return {\n httpStatus: null,\n message: \"Connect to ask to leave an organization.\",\n status: \"failed\",\n };\n }\n return setOrganizationLeaveRequested({\n apiClient: runtime.apiClient,\n organizationId,\n requested,\n signer: { signingKeyPair, userId },\n });\n },\n async loadPausedOrganizationIds() {\n const runtime = runtimeService.workflowInput();\n if (runtime.infra.dbStatus !== \"ready\") return new Set<string>();\n const pauses = getOrCreateOrganizationSyncPauses(\n runtime.state.domainScope,\n );\n await pauses.load(runtime.infra.execSql);\n return pauses.pausedOrganizationIds();\n },\n subscribeToSyncPauses(listener) {\n return getOrCreateOrganizationSyncPauses(\n runtimeService.workflowInput().state.domainScope,\n ).subscribe(listener);\n },\n subscribeToMemberships(listener) {\n const { domainScope } = runtimeService.workflowInput().state;\n const listeners =\n membershipListenersByScope.get(domainScope) ?? new Set();\n membershipListenersByScope.set(domainScope, listeners);\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n };\n}\n"]}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { type OrganizationContainerGrants, type OrganizationDirectoryAndGroups, type OrganizationGroupContainers, type OrganizationGroupMembers, type OrganizationGroupPolicyHistory, type OrganizationPolicyHistory, type OrganizationUserDetail } from "../../workflows/organizations/index.js";
|
|
2
|
-
import type { InternalRuntime } from "../runtime/workflowRuntime.js";
|
|
2
|
+
import type { InternalRuntime, InternalWorkflowRuntimeInput } from "../runtime/workflowRuntime.js";
|
|
3
|
+
/**
|
|
4
|
+
* Resolves the identity a leave request is checked against: the device's
|
|
5
|
+
* durable pin first, so a request already stored still verifies offline,
|
|
6
|
+
* then a trusted remote resolution for a member not pinned yet.
|
|
7
|
+
*/
|
|
8
|
+
export declare function leaveRequestSignerResolver(runtimeService: InternalRuntime, runtime: InternalWorkflowRuntimeInput): InternalWorkflowRuntimeInput["resolveTrustedUserIdentity"];
|
|
3
9
|
export interface OrganizationReadModelCoordinator {
|
|
4
10
|
loadLocal(organizationId?: string | undefined): Promise<OrganizationDirectoryAndGroups | null>;
|
|
5
11
|
loadLocalGroupMembers(groupId: string, organizationId?: string | undefined): Promise<OrganizationGroupMembers | null>;
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import { recoverOrganizationAccess } from "../../workflows/container-contents/recovery/accessRestoration.js";
|
|
2
|
-
import { loadLocalOrganizationContainerGrants, loadLocalOrganizationDirectoryAndGroups, loadLocalOrganizationGroupContainers, loadLocalOrganizationGroupMembers, loadLocalOrganizationUserDetail, reconcileOrganizationDirectoryAndGroups, } from "../../workflows/organizations/index.js";
|
|
2
|
+
import { loadLocalOrganizationContainerGrants, loadLocalOrganizationDirectoryAndGroups, loadLocalOrganizationGroupContainers, loadLocalOrganizationGroupMembers, loadLocalOrganizationUserDetail, reconcileOrganizationDirectoryAndGroups, withVerifiedLeaveRequests, withVerifiedUserLeaveRequest, } from "../../workflows/organizations/index.js";
|
|
3
3
|
import { organizationAccessScopeKey, wasOrganizationPresentationAccessDeniedByServer, } from "../../workflows/organizations/readModel/organizationPresentationAccessState.js";
|
|
4
4
|
import { loadBoundedOrganizationGroupHistory } from "./organizationGroupHistory.js";
|
|
5
5
|
import { hydrateOrganizationGroupNamesForRuntime } from "./organizationGroupNameHydration.js";
|
|
6
6
|
import { loadBoundedOrganizationHistory } from "./organizationHistory.js";
|
|
7
7
|
import { activeOrganizationDataRuntime, isOrganizationDataRuntimeCurrent, } from "./organizationWorkflowRuntime.js";
|
|
8
8
|
const coordinatorsByRuntime = new WeakMap();
|
|
9
|
+
/**
|
|
10
|
+
* Resolves the identity a leave request is checked against: the device's
|
|
11
|
+
* durable pin first, so a request already stored still verifies offline,
|
|
12
|
+
* then a trusted remote resolution for a member not pinned yet.
|
|
13
|
+
*/
|
|
14
|
+
export function leaveRequestSignerResolver(runtimeService, runtime) {
|
|
15
|
+
return async (userId) => (await runtimeService.identityLinks.resolvePinned(userId)) ??
|
|
16
|
+
runtime.resolveTrustedUserIdentity(userId);
|
|
17
|
+
}
|
|
9
18
|
class OrganizationReadModelCoordinatorImpl {
|
|
10
19
|
runtimeService;
|
|
11
20
|
reconciliationsByScope = new WeakMap();
|
|
@@ -26,11 +35,11 @@ class OrganizationReadModelCoordinatorImpl {
|
|
|
26
35
|
if (!active) {
|
|
27
36
|
return null;
|
|
28
37
|
}
|
|
29
|
-
return loadLocalOrganizationDirectoryAndGroups({
|
|
38
|
+
return withVerifiedLeaveRequests(await loadLocalOrganizationDirectoryAndGroups({
|
|
30
39
|
currentUserId: active.userId,
|
|
31
40
|
execSql: active.runtime.infra.execSql,
|
|
32
41
|
organizationId: active.organizationId,
|
|
33
|
-
});
|
|
42
|
+
}), leaveRequestSignerResolver(this.runtimeService, active.runtime));
|
|
34
43
|
}
|
|
35
44
|
async loadLocalGrants(organizationId) {
|
|
36
45
|
const active = activeOrganizationDataRuntime(this.runtimeService, organizationId);
|
|
@@ -96,12 +105,12 @@ class OrganizationReadModelCoordinatorImpl {
|
|
|
96
105
|
if (!active || userId.length === 0) {
|
|
97
106
|
return null;
|
|
98
107
|
}
|
|
99
|
-
return loadLocalOrganizationUserDetail({
|
|
108
|
+
return withVerifiedUserLeaveRequest(await loadLocalOrganizationUserDetail({
|
|
100
109
|
currentUserId: active.userId,
|
|
101
110
|
execSql: active.runtime.infra.execSql,
|
|
102
111
|
organizationId: active.organizationId,
|
|
103
112
|
userId,
|
|
104
|
-
});
|
|
113
|
+
}), active.organizationId, leaveRequestSignerResolver(this.runtimeService, active.runtime));
|
|
105
114
|
}
|
|
106
115
|
reconcile(organizationId) {
|
|
107
116
|
const active = activeOrganizationDataRuntime(this.runtimeService, organizationId);
|
|
@@ -153,7 +162,7 @@ class OrganizationReadModelCoordinatorImpl {
|
|
|
153
162
|
});
|
|
154
163
|
if (!stillCurrent())
|
|
155
164
|
return null;
|
|
156
|
-
return hydrateOrganizationGroupNamesForRuntime(this.runtimeService, active, domainScope, directoryAndGroups);
|
|
165
|
+
return withVerifiedLeaveRequests(await hydrateOrganizationGroupNamesForRuntime(this.runtimeService, active, domainScope, directoryAndGroups), leaveRequestSignerResolver(this.runtimeService, active.runtime));
|
|
157
166
|
})
|
|
158
167
|
.finally(() => {
|
|
159
168
|
if (byKey.get(key) === reconciliation) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"organizationReadModels.js","sourceRoot":"","sources":["organizationReadModels.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DomainScope } from \"../../data/shared/domainScope\";\nimport { recoverOrganizationAccess } from \"../../workflows/container-contents/recovery/accessRestoration\";\nimport {\n loadLocalOrganizationContainerGrants,\n loadLocalOrganizationDirectoryAndGroups,\n loadLocalOrganizationGroupContainers,\n loadLocalOrganizationGroupMembers,\n loadLocalOrganizationUserDetail,\n type OrganizationContainerGrants,\n type OrganizationDirectoryAndGroups,\n type OrganizationGroupContainers,\n type OrganizationGroupMembers,\n type OrganizationGroupPolicyHistory,\n type OrganizationPolicyHistory,\n type OrganizationUserDetail,\n reconcileOrganizationDirectoryAndGroups,\n} from \"../../workflows/organizations\";\nimport {\n organizationAccessScopeKey,\n wasOrganizationPresentationAccessDeniedByServer,\n} from \"../../workflows/organizations/readModel/organizationPresentationAccessState\";\nimport type { InternalRuntime } from \"../runtime/workflowRuntime\";\nimport { loadBoundedOrganizationGroupHistory } from \"./organizationGroupHistory\";\nimport { hydrateOrganizationGroupNamesForRuntime } from \"./organizationGroupNameHydration\";\nimport { loadBoundedOrganizationHistory } from \"./organizationHistory\";\nimport {\n type ActiveOrganizationDataRuntime,\n activeOrganizationDataRuntime,\n isOrganizationDataRuntimeCurrent,\n} from \"./organizationWorkflowRuntime\";\n\nconst coordinatorsByRuntime = new WeakMap<\n InternalRuntime,\n OrganizationReadModelCoordinator\n>();\n\nexport interface OrganizationReadModelCoordinator {\n loadLocal(\n organizationId?: string | undefined,\n ): Promise<OrganizationDirectoryAndGroups | null>;\n loadLocalGroupMembers(\n groupId: string,\n organizationId?: string | undefined,\n ): Promise<OrganizationGroupMembers | null>;\n loadGroupPolicyHistory(\n groupId: string,\n organizationId?: string | undefined,\n beforeVersion?: number | undefined,\n ): Promise<OrganizationGroupPolicyHistory | null>;\n loadOrganizationPolicyHistory(\n organizationId?: string | undefined,\n beforeVersion?: number | undefined,\n ): Promise<OrganizationPolicyHistory | null>;\n loadLocalGrants(\n organizationId?: string | undefined,\n ): Promise<OrganizationContainerGrants | null>;\n loadLocalGroupContainers(\n groupId: string,\n organizationId?: string | undefined,\n ): Promise<OrganizationGroupContainers | null>;\n loadLocalUserDetail(\n userId: string,\n organizationId?: string | undefined,\n ): Promise<OrganizationUserDetail | null>;\n /**\n * Resolves `undefined` when the runtime declines without I/O (offline,\n * database not ready, organization mismatch) or when the feed failed with\n * no locally retained projection — passes that must not count as caught\n * up; `null` when the reconcile completed but produced nothing presentable\n * — including an authoritative denial that purged the projection, which\n * consumers must repaint.\n */\n reconcile(\n organizationId?: string | undefined,\n ): Promise<OrganizationDirectoryAndGroups | null | undefined>;\n reconcileAfterMutation(\n organizationId?: string | undefined,\n ): Promise<OrganizationDirectoryAndGroups | null | undefined>;\n}\n\nclass OrganizationReadModelCoordinatorImpl\n implements OrganizationReadModelCoordinator\n{\n private readonly reconciliationsByScope = new WeakMap<\n DomainScope,\n Map<string, Promise<OrganizationDirectoryAndGroups | null | undefined>>\n >();\n constructor(private readonly runtimeService: InternalRuntime) {}\n\n private reconciliationMap(active: ActiveOrganizationDataRuntime) {\n const scope = active.runtime.state.domainScope;\n let byKey = this.reconciliationsByScope.get(scope);\n if (!byKey) {\n byKey = new Map();\n this.reconciliationsByScope.set(scope, byKey);\n }\n return byKey;\n }\n\n async loadLocal(organizationId?: string) {\n const active = activeOrganizationDataRuntime(\n this.runtimeService,\n organizationId,\n );\n if (!active) {\n return null;\n }\n return loadLocalOrganizationDirectoryAndGroups({\n currentUserId: active.userId,\n execSql: active.runtime.infra.execSql,\n organizationId: active.organizationId,\n });\n }\n\n async loadLocalGrants(organizationId?: string) {\n const active = activeOrganizationDataRuntime(\n this.runtimeService,\n organizationId,\n );\n if (!active) {\n return null;\n }\n return loadLocalOrganizationContainerGrants({\n currentUserId: active.userId,\n execSql: active.runtime.infra.execSql,\n organizationId: active.organizationId,\n });\n }\n\n async loadLocalGroupContainers(groupId: string, organizationId?: string) {\n const active = activeOrganizationDataRuntime(\n this.runtimeService,\n organizationId,\n );\n if (!active || groupId.length === 0) {\n return null;\n }\n return loadLocalOrganizationGroupContainers({\n currentUserId: active.userId,\n execSql: active.runtime.infra.execSql,\n groupId,\n organizationId: active.organizationId,\n });\n }\n\n async loadLocalGroupMembers(groupId: string, organizationId?: string) {\n const active = activeOrganizationDataRuntime(\n this.runtimeService,\n organizationId,\n );\n if (!active || groupId.length === 0) {\n return null;\n }\n return loadLocalOrganizationGroupMembers({\n currentUserId: active.userId,\n execSql: active.runtime.infra.execSql,\n groupId,\n organizationId: active.organizationId,\n });\n }\n\n async loadGroupPolicyHistory(\n groupId: string,\n organizationId?: string,\n beforeVersion?: number,\n ) {\n const active = activeOrganizationDataRuntime(\n this.runtimeService,\n organizationId,\n );\n if (!active || groupId.length === 0) {\n return null;\n }\n const domainScope = active.runtime.state.domainScope;\n return loadBoundedOrganizationGroupHistory({\n active,\n groupId,\n beforeVersion,\n stillCurrent: () =>\n isOrganizationDataRuntimeCurrent(\n this.runtimeService,\n active,\n domainScope,\n ),\n });\n }\n\n async loadOrganizationPolicyHistory(\n organizationId?: string,\n beforeVersion?: number,\n ) {\n const active = activeOrganizationDataRuntime(\n this.runtimeService,\n organizationId,\n );\n if (!active) return null;\n const domainScope = active.runtime.state.domainScope;\n return loadBoundedOrganizationHistory({\n active,\n beforeVersion,\n stillCurrent: () =>\n isOrganizationDataRuntimeCurrent(\n this.runtimeService,\n active,\n domainScope,\n ),\n });\n }\n\n async loadLocalUserDetail(userId: string, organizationId?: string) {\n const active = activeOrganizationDataRuntime(\n this.runtimeService,\n organizationId,\n );\n if (!active || userId.length === 0) {\n return null;\n }\n return loadLocalOrganizationUserDetail({\n currentUserId: active.userId,\n execSql: active.runtime.infra.execSql,\n organizationId: active.organizationId,\n userId,\n });\n }\n\n reconcile(\n organizationId?: string,\n ): Promise<OrganizationDirectoryAndGroups | null | undefined> {\n const active = activeOrganizationDataRuntime(\n this.runtimeService,\n organizationId,\n );\n if (!active?.runtime.state.online) {\n return Promise.resolve(undefined);\n }\n\n const byKey = this.reconciliationMap(active);\n const key = organizationAccessScopeKey(\n active.organizationId,\n active.userId,\n );\n const existing = byKey.get(key);\n if (existing) {\n return existing;\n }\n\n // Snapshot the server-denied flag before reconciling. A reconcile that\n // flips it back to readable means org access was just restored (e.g. the\n // user was re-added to a group), and any write lanes idled by\n // permission-denied submissions have no self re-arm — regaining access is\n // their retry signal, mirroring how billing recovery re-requests all\n // lanes. Only a genuine server denial counts: a local session reset also\n // marks scopes denied, and re-arming on its first reconcile would race the\n // startup sync passes (e.g. pending-create adoption between panes).\n const accessWasDenied = wasOrganizationPresentationAccessDeniedByServer(\n {\n execSql: active.runtime.infra.execSql,\n organizationId: active.organizationId,\n requesterUserId: active.userId,\n },\n \"readModel\",\n );\n const domainScope = active.runtime.state.domainScope;\n const stillCurrent = () =>\n isOrganizationDataRuntimeCurrent(\n this.runtimeService,\n active,\n domainScope,\n );\n\n const reconciliation = reconcileOrganizationDirectoryAndGroups({\n apiClient: active.runtime.apiClient,\n currentUserId: active.userId,\n execSql: active.runtime.infra.execSql,\n logError: active.runtime.util.logError,\n organizationId: active.organizationId,\n })\n .then(async (directoryAndGroups) => {\n if (!stillCurrent()) return null;\n // Feed success restores retry eligibility even if name decryption fails.\n const accessWasRestored =\n accessWasDenied &&\n directoryAndGroups !== null &&\n directoryAndGroups !== undefined;\n if (accessWasRestored)\n await recoverOrganizationAccess({\n domainScope,\n execSql: active.runtime.infra.execSql,\n organizationId: active.organizationId,\n stillCurrent,\n userId: active.userId,\n });\n if (!stillCurrent()) return null;\n return hydrateOrganizationGroupNamesForRuntime(\n this.runtimeService,\n active,\n domainScope,\n directoryAndGroups,\n );\n })\n .finally(() => {\n if (byKey.get(key) === reconciliation) {\n byKey.delete(key);\n }\n });\n byKey.set(key, reconciliation);\n return reconciliation;\n }\n\n async reconcileAfterMutation(\n organizationId?: string,\n ): Promise<OrganizationDirectoryAndGroups | null | undefined> {\n const active = activeOrganizationDataRuntime(\n this.runtimeService,\n organizationId,\n );\n if (!active?.runtime.state.online) {\n return undefined;\n }\n const existing = this.reconciliationMap(active).get(\n organizationAccessScopeKey(active.organizationId, active.userId),\n );\n if (existing) {\n await existing.catch(() => null);\n }\n return this.reconcile(active.organizationId);\n }\n}\n\nexport function createOrganizationReadModelCoordinator(\n runtimeService: InternalRuntime,\n): OrganizationReadModelCoordinator {\n const existing = coordinatorsByRuntime.get(runtimeService);\n if (existing) {\n return existing;\n }\n\n const coordinator = new OrganizationReadModelCoordinatorImpl(runtimeService);\n coordinatorsByRuntime.set(runtimeService, coordinator);\n return coordinator;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"organizationReadModels.js","sourceRoot":"","sources":["organizationReadModels.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DomainScope } from \"../../data/shared/domainScope\";\nimport { recoverOrganizationAccess } from \"../../workflows/container-contents/recovery/accessRestoration\";\nimport {\n loadLocalOrganizationContainerGrants,\n loadLocalOrganizationDirectoryAndGroups,\n loadLocalOrganizationGroupContainers,\n loadLocalOrganizationGroupMembers,\n loadLocalOrganizationUserDetail,\n type OrganizationContainerGrants,\n type OrganizationDirectoryAndGroups,\n type OrganizationGroupContainers,\n type OrganizationGroupMembers,\n type OrganizationGroupPolicyHistory,\n type OrganizationPolicyHistory,\n type OrganizationUserDetail,\n reconcileOrganizationDirectoryAndGroups,\n withVerifiedLeaveRequests,\n withVerifiedUserLeaveRequest,\n} from \"../../workflows/organizations\";\nimport {\n organizationAccessScopeKey,\n wasOrganizationPresentationAccessDeniedByServer,\n} from \"../../workflows/organizations/readModel/organizationPresentationAccessState\";\nimport type {\n InternalRuntime,\n InternalWorkflowRuntimeInput,\n} from \"../runtime/workflowRuntime\";\nimport { loadBoundedOrganizationGroupHistory } from \"./organizationGroupHistory\";\nimport { hydrateOrganizationGroupNamesForRuntime } from \"./organizationGroupNameHydration\";\nimport { loadBoundedOrganizationHistory } from \"./organizationHistory\";\nimport {\n type ActiveOrganizationDataRuntime,\n activeOrganizationDataRuntime,\n isOrganizationDataRuntimeCurrent,\n} from \"./organizationWorkflowRuntime\";\n\nconst coordinatorsByRuntime = new WeakMap<\n InternalRuntime,\n OrganizationReadModelCoordinator\n>();\n\n/**\n * Resolves the identity a leave request is checked against: the device's\n * durable pin first, so a request already stored still verifies offline,\n * then a trusted remote resolution for a member not pinned yet.\n */\nexport function leaveRequestSignerResolver(\n runtimeService: InternalRuntime,\n runtime: InternalWorkflowRuntimeInput,\n): InternalWorkflowRuntimeInput[\"resolveTrustedUserIdentity\"] {\n return async (userId) =>\n (await runtimeService.identityLinks.resolvePinned(userId)) ??\n runtime.resolveTrustedUserIdentity(userId);\n}\n\nexport interface OrganizationReadModelCoordinator {\n loadLocal(\n organizationId?: string | undefined,\n ): Promise<OrganizationDirectoryAndGroups | null>;\n loadLocalGroupMembers(\n groupId: string,\n organizationId?: string | undefined,\n ): Promise<OrganizationGroupMembers | null>;\n loadGroupPolicyHistory(\n groupId: string,\n organizationId?: string | undefined,\n beforeVersion?: number | undefined,\n ): Promise<OrganizationGroupPolicyHistory | null>;\n loadOrganizationPolicyHistory(\n organizationId?: string | undefined,\n beforeVersion?: number | undefined,\n ): Promise<OrganizationPolicyHistory | null>;\n loadLocalGrants(\n organizationId?: string | undefined,\n ): Promise<OrganizationContainerGrants | null>;\n loadLocalGroupContainers(\n groupId: string,\n organizationId?: string | undefined,\n ): Promise<OrganizationGroupContainers | null>;\n loadLocalUserDetail(\n userId: string,\n organizationId?: string | undefined,\n ): Promise<OrganizationUserDetail | null>;\n /**\n * Resolves `undefined` when the runtime declines without I/O (offline,\n * database not ready, organization mismatch) or when the feed failed with\n * no locally retained projection — passes that must not count as caught\n * up; `null` when the reconcile completed but produced nothing presentable\n * — including an authoritative denial that purged the projection, which\n * consumers must repaint.\n */\n reconcile(\n organizationId?: string | undefined,\n ): Promise<OrganizationDirectoryAndGroups | null | undefined>;\n reconcileAfterMutation(\n organizationId?: string | undefined,\n ): Promise<OrganizationDirectoryAndGroups | null | undefined>;\n}\n\nclass OrganizationReadModelCoordinatorImpl\n implements OrganizationReadModelCoordinator\n{\n private readonly reconciliationsByScope = new WeakMap<\n DomainScope,\n Map<string, Promise<OrganizationDirectoryAndGroups | null | undefined>>\n >();\n constructor(private readonly runtimeService: InternalRuntime) {}\n\n private reconciliationMap(active: ActiveOrganizationDataRuntime) {\n const scope = active.runtime.state.domainScope;\n let byKey = this.reconciliationsByScope.get(scope);\n if (!byKey) {\n byKey = new Map();\n this.reconciliationsByScope.set(scope, byKey);\n }\n return byKey;\n }\n\n async loadLocal(organizationId?: string) {\n const active = activeOrganizationDataRuntime(\n this.runtimeService,\n organizationId,\n );\n if (!active) {\n return null;\n }\n return withVerifiedLeaveRequests(\n await loadLocalOrganizationDirectoryAndGroups({\n currentUserId: active.userId,\n execSql: active.runtime.infra.execSql,\n organizationId: active.organizationId,\n }),\n leaveRequestSignerResolver(this.runtimeService, active.runtime),\n );\n }\n\n async loadLocalGrants(organizationId?: string) {\n const active = activeOrganizationDataRuntime(\n this.runtimeService,\n organizationId,\n );\n if (!active) {\n return null;\n }\n return loadLocalOrganizationContainerGrants({\n currentUserId: active.userId,\n execSql: active.runtime.infra.execSql,\n organizationId: active.organizationId,\n });\n }\n\n async loadLocalGroupContainers(groupId: string, organizationId?: string) {\n const active = activeOrganizationDataRuntime(\n this.runtimeService,\n organizationId,\n );\n if (!active || groupId.length === 0) {\n return null;\n }\n return loadLocalOrganizationGroupContainers({\n currentUserId: active.userId,\n execSql: active.runtime.infra.execSql,\n groupId,\n organizationId: active.organizationId,\n });\n }\n\n async loadLocalGroupMembers(groupId: string, organizationId?: string) {\n const active = activeOrganizationDataRuntime(\n this.runtimeService,\n organizationId,\n );\n if (!active || groupId.length === 0) {\n return null;\n }\n return loadLocalOrganizationGroupMembers({\n currentUserId: active.userId,\n execSql: active.runtime.infra.execSql,\n groupId,\n organizationId: active.organizationId,\n });\n }\n\n async loadGroupPolicyHistory(\n groupId: string,\n organizationId?: string,\n beforeVersion?: number,\n ) {\n const active = activeOrganizationDataRuntime(\n this.runtimeService,\n organizationId,\n );\n if (!active || groupId.length === 0) {\n return null;\n }\n const domainScope = active.runtime.state.domainScope;\n return loadBoundedOrganizationGroupHistory({\n active,\n groupId,\n beforeVersion,\n stillCurrent: () =>\n isOrganizationDataRuntimeCurrent(\n this.runtimeService,\n active,\n domainScope,\n ),\n });\n }\n\n async loadOrganizationPolicyHistory(\n organizationId?: string,\n beforeVersion?: number,\n ) {\n const active = activeOrganizationDataRuntime(\n this.runtimeService,\n organizationId,\n );\n if (!active) return null;\n const domainScope = active.runtime.state.domainScope;\n return loadBoundedOrganizationHistory({\n active,\n beforeVersion,\n stillCurrent: () =>\n isOrganizationDataRuntimeCurrent(\n this.runtimeService,\n active,\n domainScope,\n ),\n });\n }\n\n async loadLocalUserDetail(userId: string, organizationId?: string) {\n const active = activeOrganizationDataRuntime(\n this.runtimeService,\n organizationId,\n );\n if (!active || userId.length === 0) {\n return null;\n }\n return withVerifiedUserLeaveRequest(\n await loadLocalOrganizationUserDetail({\n currentUserId: active.userId,\n execSql: active.runtime.infra.execSql,\n organizationId: active.organizationId,\n userId,\n }),\n active.organizationId,\n leaveRequestSignerResolver(this.runtimeService, active.runtime),\n );\n }\n\n reconcile(\n organizationId?: string,\n ): Promise<OrganizationDirectoryAndGroups | null | undefined> {\n const active = activeOrganizationDataRuntime(\n this.runtimeService,\n organizationId,\n );\n if (!active?.runtime.state.online) {\n return Promise.resolve(undefined);\n }\n\n const byKey = this.reconciliationMap(active);\n const key = organizationAccessScopeKey(\n active.organizationId,\n active.userId,\n );\n const existing = byKey.get(key);\n if (existing) {\n return existing;\n }\n\n // Snapshot the server-denied flag before reconciling. A reconcile that\n // flips it back to readable means org access was just restored (e.g. the\n // user was re-added to a group), and any write lanes idled by\n // permission-denied submissions have no self re-arm — regaining access is\n // their retry signal, mirroring how billing recovery re-requests all\n // lanes. Only a genuine server denial counts: a local session reset also\n // marks scopes denied, and re-arming on its first reconcile would race the\n // startup sync passes (e.g. pending-create adoption between panes).\n const accessWasDenied = wasOrganizationPresentationAccessDeniedByServer(\n {\n execSql: active.runtime.infra.execSql,\n organizationId: active.organizationId,\n requesterUserId: active.userId,\n },\n \"readModel\",\n );\n const domainScope = active.runtime.state.domainScope;\n const stillCurrent = () =>\n isOrganizationDataRuntimeCurrent(\n this.runtimeService,\n active,\n domainScope,\n );\n\n const reconciliation = reconcileOrganizationDirectoryAndGroups({\n apiClient: active.runtime.apiClient,\n currentUserId: active.userId,\n execSql: active.runtime.infra.execSql,\n logError: active.runtime.util.logError,\n organizationId: active.organizationId,\n })\n .then(async (directoryAndGroups) => {\n if (!stillCurrent()) return null;\n // Feed success restores retry eligibility even if name decryption fails.\n const accessWasRestored =\n accessWasDenied &&\n directoryAndGroups !== null &&\n directoryAndGroups !== undefined;\n if (accessWasRestored)\n await recoverOrganizationAccess({\n domainScope,\n execSql: active.runtime.infra.execSql,\n organizationId: active.organizationId,\n stillCurrent,\n userId: active.userId,\n });\n if (!stillCurrent()) return null;\n return withVerifiedLeaveRequests(\n await hydrateOrganizationGroupNamesForRuntime(\n this.runtimeService,\n active,\n domainScope,\n directoryAndGroups,\n ),\n leaveRequestSignerResolver(this.runtimeService, active.runtime),\n );\n })\n .finally(() => {\n if (byKey.get(key) === reconciliation) {\n byKey.delete(key);\n }\n });\n byKey.set(key, reconciliation);\n return reconciliation;\n }\n\n async reconcileAfterMutation(\n organizationId?: string,\n ): Promise<OrganizationDirectoryAndGroups | null | undefined> {\n const active = activeOrganizationDataRuntime(\n this.runtimeService,\n organizationId,\n );\n if (!active?.runtime.state.online) {\n return undefined;\n }\n const existing = this.reconciliationMap(active).get(\n organizationAccessScopeKey(active.organizationId, active.userId),\n );\n if (existing) {\n await existing.catch(() => null);\n }\n return this.reconcile(active.organizationId);\n }\n}\n\nexport function createOrganizationReadModelCoordinator(\n runtimeService: InternalRuntime,\n): OrganizationReadModelCoordinator {\n const existing = coordinatorsByRuntime.get(runtimeService);\n if (existing) {\n return existing;\n }\n\n const coordinator = new OrganizationReadModelCoordinatorImpl(runtimeService);\n coordinatorsByRuntime.set(runtimeService, coordinator);\n return coordinator;\n}\n"]}
|
|
@@ -4,6 +4,7 @@ import type { cancelStripeSubscription, checkNativePurchaseEligibility, claimNat
|
|
|
4
4
|
import type { InternalWorkflowRuntimeInput } from "../runtime/workflowRuntime.js";
|
|
5
5
|
import type { OrganizationDataUsageCoordinator } from "./organizationDataUsage.js";
|
|
6
6
|
import type { loadOrganizationGroupPresentationDetails } from "./organizationGroupPresentation.js";
|
|
7
|
+
import type { OrganizationMemberships } from "./organizationMemberships.js";
|
|
7
8
|
import type { OrganizationReadModelCoordinator } from "./organizationReadModels.js";
|
|
8
9
|
import type { AbandonOrganizationPolicyMutationInput, DiscardUnreadableOrganizationPolicyMutationInput, readPendingOrganizationPolicyMutation } from "./principalMutationRecovery.js";
|
|
9
10
|
import type { AddOrganizationGroupUserInput, deleteGroupForOrganization, OrganizationGrantRef, RemoveOrganizationGroupUserInput } from "./principalMutations.js";
|
|
@@ -40,6 +41,8 @@ export interface Organizations {
|
|
|
40
41
|
loadGroupContainers: (groupId: string) => ReturnType<OrganizationReadModelCoordinator["loadLocalGroupContainers"]>;
|
|
41
42
|
loadGrants: () => ReturnType<OrganizationReadModelCoordinator["loadLocalGrants"]>;
|
|
42
43
|
listLocalOrganizations: () => Promise<LocalOrganizationSummary[]>;
|
|
44
|
+
/** The user's own memberships and per-organization sync choices. */
|
|
45
|
+
readonly memberships: OrganizationMemberships;
|
|
43
46
|
loadPolicyHistory: (beforeVersion?: number) => ReturnType<OrganizationReadModelCoordinator["loadOrganizationPolicyHistory"]>;
|
|
44
47
|
loadUserDetail: (userId: string) => ReturnType<OrganizationReadModelCoordinator["loadLocalUserDetail"]>;
|
|
45
48
|
updateRosterEntry: (userId: string, profileDocumentId: string | null) => ReturnType<typeof updateOrganizationRosterEntry>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"organizationsTypes.js","sourceRoot":"","sources":["organizationsTypes.ts"],"names":[],"mappings":"","sourcesContent":["import type { NativeSubscriptionStore } from \"@tearleads/validators/billing\";\nimport type { PrincipalPolicyMutationResponse } from \"@tearleads/validators/response\";\nimport type {\n cancelStripeSubscription,\n checkNativePurchaseEligibility,\n claimNativeOrganizationSubscription,\n createOrganizationGroup,\n createStripeCheckout,\n createStripeCheckoutSession,\n importOrganizationUser,\n LocalOrganizationSummary,\n loadOrganizationBilling,\n loadOrganizationBillingHistory,\n loadOrganizationBillingManagementUrl,\n loadStripeCheckoutOptions,\n revokeOrganizationContainerGrant,\n startOrganizationTrial,\n updateOrganizationProfile,\n updateOrganizationRosterEntry,\n} from \"../../workflows/organizations\";\nimport type { InternalWorkflowRuntimeInput } from \"../runtime/workflowRuntime\";\nimport type { OrganizationDataUsageCoordinator } from \"./organizationDataUsage\";\nimport type { loadOrganizationGroupPresentationDetails } from \"./organizationGroupPresentation\";\nimport type { OrganizationReadModelCoordinator } from \"./organizationReadModels\";\nimport type {\n AbandonOrganizationPolicyMutationInput,\n DiscardUnreadableOrganizationPolicyMutationInput,\n readPendingOrganizationPolicyMutation,\n} from \"./principalMutationRecovery\";\nimport type {\n AddOrganizationGroupUserInput,\n deleteGroupForOrganization,\n OrganizationGrantRef,\n RemoveOrganizationGroupUserInput,\n} from \"./principalMutations\";\n\n/** Exact current artifacts and container receipts; no historical prefix. */\nexport type OrganizationGroupMutationReceipt = PrincipalPolicyMutationResponse;\n\nexport interface Organizations {\n discardUnreadablePolicyMutation: (\n input: DiscardUnreadableOrganizationPolicyMutationInput,\n ) => Promise<boolean>;\n readPendingPolicyMutation: (\n organizationId: string,\n ) => ReturnType<typeof readPendingOrganizationPolicyMutation>;\n retryPendingPolicyMutation: (organizationId: string) => Promise<void>;\n abandonPendingPolicyMutation: (\n input: AbandonOrganizationPolicyMutationInput,\n ) => Promise<boolean>;\n addUserToGroup: (\n input: AddOrganizationGroupUserInput,\n ) => Promise<OrganizationGroupMutationReceipt>;\n createGroup: (name: string) => ReturnType<typeof createOrganizationGroup>;\n deleteGroup: (\n groupId: string,\n ) => ReturnType<typeof deleteGroupForOrganization>;\n importUserById: (userId: string) => ReturnType<typeof importOrganizationUser>;\n loadBilling: () => ReturnType<typeof loadOrganizationBilling>;\n /** Billing for an organization the session is not currently switched to. */\n loadBillingForOrganization: (\n organizationId: string,\n ) => ReturnType<typeof loadOrganizationBilling>;\n loadBillingHistory: () => ReturnType<typeof loadOrganizationBillingHistory>;\n loadBillingManagementUrl: () => ReturnType<\n typeof loadOrganizationBillingManagementUrl\n >;\n /** Direct Stripe checkout (issue #1654): options, start, and cancel. */\n loadStripeCheckoutOptions: (\n organizationId?: string,\n ) => ReturnType<typeof loadStripeCheckoutOptions>;\n createStripeCheckout: (\n organizationId?: string,\n ) => ReturnType<typeof createStripeCheckout>;\n createStripeCheckoutSession: (\n returnUrl: string,\n organizationId?: string,\n ) => ReturnType<typeof createStripeCheckoutSession>;\n cancelStripeSubscription: () => ReturnType<typeof cancelStripeSubscription>;\n claimNativeSubscription: (\n organizationId: string,\n store: NativeSubscriptionStore,\n ) => ReturnType<typeof claimNativeOrganizationSubscription>;\n checkNativePurchaseEligibility: (\n organizationId: string,\n store: NativeSubscriptionStore,\n ) => ReturnType<typeof checkNativePurchaseEligibility>;\n loadDataUsage: () => ReturnType<\n OrganizationDataUsageCoordinator[\"reconcile\"]\n >;\n loadLocalDataUsage: () => ReturnType<\n OrganizationDataUsageCoordinator[\"loadLocal\"]\n >;\n loadDirectoryAndGroups: () => ReturnType<\n OrganizationReadModelCoordinator[\"reconcile\"]\n >;\n loadDirectoryAndGroupsAfterMutation: () => ReturnType<\n OrganizationReadModelCoordinator[\"reconcileAfterMutation\"]\n >;\n loadLocalDirectoryAndGroups: () => ReturnType<\n OrganizationReadModelCoordinator[\"loadLocal\"]\n >;\n loadGroupMembers: (\n groupId: string,\n ) => ReturnType<\n InternalWorkflowRuntimeInput[\"apiClient\"][\"listOrganizationGroupMembers\"]\n >;\n loadGroupPresentationDetails(\n groupId: string,\n beforeVersion?: number,\n ): ReturnType<typeof loadOrganizationGroupPresentationDetails>;\n loadGroupContainers: (\n groupId: string,\n ) => ReturnType<OrganizationReadModelCoordinator[\"loadLocalGroupContainers\"]>;\n loadGrants: () => ReturnType<\n OrganizationReadModelCoordinator[\"loadLocalGrants\"]\n >;\n listLocalOrganizations: () => Promise<LocalOrganizationSummary[]>;\n loadPolicyHistory: (\n beforeVersion?: number,\n ) => ReturnType<\n OrganizationReadModelCoordinator[\"loadOrganizationPolicyHistory\"]\n >;\n loadUserDetail: (\n userId: string,\n ) => ReturnType<OrganizationReadModelCoordinator[\"loadLocalUserDetail\"]>;\n updateRosterEntry: (\n userId: string,\n profileDocumentId: string | null,\n ) => ReturnType<typeof updateOrganizationRosterEntry>;\n updateProfile: (\n profileDocumentId: string | null,\n ) => ReturnType<typeof updateOrganizationProfile>;\n removeUserFromGroup: (\n input: RemoveOrganizationGroupUserInput,\n ) => Promise<OrganizationGroupMutationReceipt>;\n revokeGrant: (\n grant: OrganizationGrantRef,\n ) => Promise<\n | Awaited<ReturnType<typeof revokeOrganizationContainerGrant>>\n | OrganizationGroupMutationReceipt\n >;\n startTrial: (\n organizationId?: string,\n ) => ReturnType<typeof startOrganizationTrial>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"organizationsTypes.js","sourceRoot":"","sources":["organizationsTypes.ts"],"names":[],"mappings":"","sourcesContent":["import type { NativeSubscriptionStore } from \"@tearleads/validators/billing\";\nimport type { PrincipalPolicyMutationResponse } from \"@tearleads/validators/response\";\nimport type {\n cancelStripeSubscription,\n checkNativePurchaseEligibility,\n claimNativeOrganizationSubscription,\n createOrganizationGroup,\n createStripeCheckout,\n createStripeCheckoutSession,\n importOrganizationUser,\n LocalOrganizationSummary,\n loadOrganizationBilling,\n loadOrganizationBillingHistory,\n loadOrganizationBillingManagementUrl,\n loadStripeCheckoutOptions,\n revokeOrganizationContainerGrant,\n startOrganizationTrial,\n updateOrganizationProfile,\n updateOrganizationRosterEntry,\n} from \"../../workflows/organizations\";\nimport type { InternalWorkflowRuntimeInput } from \"../runtime/workflowRuntime\";\nimport type { OrganizationDataUsageCoordinator } from \"./organizationDataUsage\";\nimport type { loadOrganizationGroupPresentationDetails } from \"./organizationGroupPresentation\";\nimport type { OrganizationMemberships } from \"./organizationMemberships\";\nimport type { OrganizationReadModelCoordinator } from \"./organizationReadModels\";\nimport type {\n AbandonOrganizationPolicyMutationInput,\n DiscardUnreadableOrganizationPolicyMutationInput,\n readPendingOrganizationPolicyMutation,\n} from \"./principalMutationRecovery\";\nimport type {\n AddOrganizationGroupUserInput,\n deleteGroupForOrganization,\n OrganizationGrantRef,\n RemoveOrganizationGroupUserInput,\n} from \"./principalMutations\";\n\n/** Exact current artifacts and container receipts; no historical prefix. */\nexport type OrganizationGroupMutationReceipt = PrincipalPolicyMutationResponse;\n\nexport interface Organizations {\n discardUnreadablePolicyMutation: (\n input: DiscardUnreadableOrganizationPolicyMutationInput,\n ) => Promise<boolean>;\n readPendingPolicyMutation: (\n organizationId: string,\n ) => ReturnType<typeof readPendingOrganizationPolicyMutation>;\n retryPendingPolicyMutation: (organizationId: string) => Promise<void>;\n abandonPendingPolicyMutation: (\n input: AbandonOrganizationPolicyMutationInput,\n ) => Promise<boolean>;\n addUserToGroup: (\n input: AddOrganizationGroupUserInput,\n ) => Promise<OrganizationGroupMutationReceipt>;\n createGroup: (name: string) => ReturnType<typeof createOrganizationGroup>;\n deleteGroup: (\n groupId: string,\n ) => ReturnType<typeof deleteGroupForOrganization>;\n importUserById: (userId: string) => ReturnType<typeof importOrganizationUser>;\n loadBilling: () => ReturnType<typeof loadOrganizationBilling>;\n /** Billing for an organization the session is not currently switched to. */\n loadBillingForOrganization: (\n organizationId: string,\n ) => ReturnType<typeof loadOrganizationBilling>;\n loadBillingHistory: () => ReturnType<typeof loadOrganizationBillingHistory>;\n loadBillingManagementUrl: () => ReturnType<\n typeof loadOrganizationBillingManagementUrl\n >;\n /** Direct Stripe checkout (issue #1654): options, start, and cancel. */\n loadStripeCheckoutOptions: (\n organizationId?: string,\n ) => ReturnType<typeof loadStripeCheckoutOptions>;\n createStripeCheckout: (\n organizationId?: string,\n ) => ReturnType<typeof createStripeCheckout>;\n createStripeCheckoutSession: (\n returnUrl: string,\n organizationId?: string,\n ) => ReturnType<typeof createStripeCheckoutSession>;\n cancelStripeSubscription: () => ReturnType<typeof cancelStripeSubscription>;\n claimNativeSubscription: (\n organizationId: string,\n store: NativeSubscriptionStore,\n ) => ReturnType<typeof claimNativeOrganizationSubscription>;\n checkNativePurchaseEligibility: (\n organizationId: string,\n store: NativeSubscriptionStore,\n ) => ReturnType<typeof checkNativePurchaseEligibility>;\n loadDataUsage: () => ReturnType<\n OrganizationDataUsageCoordinator[\"reconcile\"]\n >;\n loadLocalDataUsage: () => ReturnType<\n OrganizationDataUsageCoordinator[\"loadLocal\"]\n >;\n loadDirectoryAndGroups: () => ReturnType<\n OrganizationReadModelCoordinator[\"reconcile\"]\n >;\n loadDirectoryAndGroupsAfterMutation: () => ReturnType<\n OrganizationReadModelCoordinator[\"reconcileAfterMutation\"]\n >;\n loadLocalDirectoryAndGroups: () => ReturnType<\n OrganizationReadModelCoordinator[\"loadLocal\"]\n >;\n loadGroupMembers: (\n groupId: string,\n ) => ReturnType<\n InternalWorkflowRuntimeInput[\"apiClient\"][\"listOrganizationGroupMembers\"]\n >;\n loadGroupPresentationDetails(\n groupId: string,\n beforeVersion?: number,\n ): ReturnType<typeof loadOrganizationGroupPresentationDetails>;\n loadGroupContainers: (\n groupId: string,\n ) => ReturnType<OrganizationReadModelCoordinator[\"loadLocalGroupContainers\"]>;\n loadGrants: () => ReturnType<\n OrganizationReadModelCoordinator[\"loadLocalGrants\"]\n >;\n listLocalOrganizations: () => Promise<LocalOrganizationSummary[]>;\n /** The user's own memberships and per-organization sync choices. */\n readonly memberships: OrganizationMemberships;\n loadPolicyHistory: (\n beforeVersion?: number,\n ) => ReturnType<\n OrganizationReadModelCoordinator[\"loadOrganizationPolicyHistory\"]\n >;\n loadUserDetail: (\n userId: string,\n ) => ReturnType<OrganizationReadModelCoordinator[\"loadLocalUserDetail\"]>;\n updateRosterEntry: (\n userId: string,\n profileDocumentId: string | null,\n ) => ReturnType<typeof updateOrganizationRosterEntry>;\n updateProfile: (\n profileDocumentId: string | null,\n ) => ReturnType<typeof updateOrganizationProfile>;\n removeUserFromGroup: (\n input: RemoveOrganizationGroupUserInput,\n ) => Promise<OrganizationGroupMutationReceipt>;\n revokeGrant: (\n grant: OrganizationGrantRef,\n ) => Promise<\n | Awaited<ReturnType<typeof revokeOrganizationContainerGrant>>\n | OrganizationGroupMutationReceipt\n >;\n startTrial: (\n organizationId?: string,\n ) => ReturnType<typeof startOrganizationTrial>;\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { and, asc, eq, inArray } from "drizzle-orm";
|
|
2
2
|
import { containers, documentContainerProjection, documentProjection, inContainerIntentLanes, inLocalIntentLane, LOCAL_INTENT_LANES, localIntents, } from "../../sqlite/schema/index.js";
|
|
3
|
+
import { sqliteRowsPerStatement } from "../../sqlite/sqliteBindBudget.js";
|
|
3
4
|
import { deleteContainerDocumentTombstoneHoldsForContainers } from "../documents/containerDocumentTombstoneHoldsPersistence.js";
|
|
4
5
|
import { setDocumentProjectionContainerInTransaction } from "../documents/documentProjectionContainers.js";
|
|
5
6
|
import { getLatestTimestamp } from "../latestTimestamp.js";
|
|
@@ -26,25 +27,29 @@ async function loadOrganizationIdsForContainers(tx, containerIds) {
|
|
|
26
27
|
}
|
|
27
28
|
return organizationIdByContainerId;
|
|
28
29
|
}
|
|
30
|
+
// One removed container can hold any number of documents, so their ids are
|
|
31
|
+
// read back in batches that fit SQLite's bind budget.
|
|
32
|
+
const DOCUMENT_ID_BATCH_SIZE = sqliteRowsPerStatement(1);
|
|
29
33
|
// A document unlinked from a removed container may keep other live links; its
|
|
30
34
|
// projection then re-homes to the first remaining link (deterministic order)
|
|
31
35
|
// instead of dropping to null.
|
|
32
36
|
async function loadFirstRemainingContainerIdByDocumentId(tx, documentIds) {
|
|
33
37
|
const firstRemainingContainerIdByDocumentId = new Map();
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
38
|
+
for (let index = 0; index < documentIds.length; index += DOCUMENT_ID_BATCH_SIZE) {
|
|
39
|
+
// A document's links all fall in its own batch, so the first per
|
|
40
|
+
// document is still the lowest container id.
|
|
41
|
+
const remainingLinks = await tx
|
|
42
|
+
.select({
|
|
43
|
+
containerId: documentContainerProjection.containerId,
|
|
44
|
+
documentId: documentContainerProjection.documentId,
|
|
45
|
+
})
|
|
46
|
+
.from(documentContainerProjection)
|
|
47
|
+
.where(inArray(documentContainerProjection.documentId, documentIds.slice(index, index + DOCUMENT_ID_BATCH_SIZE)))
|
|
48
|
+
.orderBy(asc(documentContainerProjection.documentId), asc(documentContainerProjection.containerId));
|
|
49
|
+
for (const link of remainingLinks) {
|
|
50
|
+
if (!firstRemainingContainerIdByDocumentId.has(link.documentId)) {
|
|
51
|
+
firstRemainingContainerIdByDocumentId.set(link.documentId, link.containerId);
|
|
52
|
+
}
|
|
48
53
|
}
|
|
49
54
|
}
|
|
50
55
|
return firstRemainingContainerIdByDocumentId;
|