@tearleads/client-sdk 0.1.105 → 0.1.106

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.
Files changed (32) hide show
  1. package/client/organizations/index.js +5 -2
  2. package/client/organizations/index.js.map +1 -1
  3. package/client/organizations/organizationMemberships.js +26 -18
  4. package/client/organizations/organizationMemberships.js.map +1 -1
  5. package/client/organizations/organizationReadModels.d.ts +9 -4
  6. package/client/organizations/organizationReadModels.js +20 -9
  7. package/client/organizations/organizationReadModels.js.map +1 -1
  8. package/internal/api-client/ApiClient.d.ts +7 -0
  9. package/internal/crypto/organizationLeaveRequest.d.ts +1 -1
  10. package/internal/crypto/organizationLeaveRequest.js +9 -2
  11. package/internal/crypto/organizationLeaveRequest.js.map +1 -1
  12. package/internal/validators/operation/organizationMemberships.d.ts +7 -0
  13. package/internal/validators/operation/organizations.d.ts +56 -0
  14. package/internal/validators/response/organization.d.ts +91 -0
  15. package/internal/validators/response/organizationReadModel.d.ts +70 -0
  16. package/internal/validators/util/index.d.ts +1 -1
  17. package/internal/validators/util/index.js.map +1 -1
  18. package/internal/validators/util/organizationLeaveRequest.d.ts +25 -2
  19. package/internal/validators/util/organizationLeaveRequest.js +19 -3
  20. package/internal/validators/util/organizationLeaveRequest.js.map +1 -1
  21. package/package.json +1 -1
  22. package/workflows/organizations/memberships/leaveRequest.d.ts +6 -2
  23. package/workflows/organizations/memberships/leaveRequest.js +20 -5
  24. package/workflows/organizations/memberships/leaveRequest.js.map +1 -1
  25. package/workflows/organizations/memberships/leaveRequestMembersEvidence.js +80 -0
  26. package/workflows/organizations/memberships/leaveRequestMembersEvidence.js.map +1 -0
  27. package/workflows/organizations/memberships/leaveRequestMembership.d.ts +24 -0
  28. package/workflows/organizations/memberships/leaveRequestMembership.js +65 -0
  29. package/workflows/organizations/memberships/leaveRequestMembership.js.map +1 -0
  30. package/workflows/organizations/memberships/leaveRequestVerification.d.ts +15 -7
  31. package/workflows/organizations/memberships/leaveRequestVerification.js +18 -11
  32. package/workflows/organizations/memberships/leaveRequestVerification.js.map +1 -1
@@ -3,7 +3,7 @@ import { cancelStripeSubscription, checkNativePurchaseEligibility, claimNativeOr
3
3
  import { createOrganizationDataUsageCoordinator, } from "./organizationDataUsage.js";
4
4
  import { loadOrganizationGroupPresentationDetails } from "./organizationGroupPresentation.js";
5
5
  import { createOrganizationMemberships, } from "./organizationMemberships.js";
6
- import { createOrganizationReadModelCoordinator, leaveRequestSignerResolver, } from "./organizationReadModels.js";
6
+ import { createOrganizationReadModelCoordinator, leaveRequestVerifier, } from "./organizationReadModels.js";
7
7
  import { authenticatedOrganizationId, runForOrganization, } from "./organizationWorkflowRuntime.js";
8
8
  import { abandonPendingOrganizationPolicyMutation, discardUnreadableOrganizationPolicyMutation, readPendingOrganizationPolicyMutation, retryPendingOrganizationPolicyMutation, } from "./principalMutationRecovery.js";
9
9
  import { currentOrganizationMutation } from "./principalMutationScope.js";
@@ -185,7 +185,10 @@ class OrganizationsService {
185
185
  // Callers store this response as directory state, so its leave request
186
186
  // passes the same check as one read from the read model.
187
187
  return (user &&
188
- withVerifiedDirectoryUser(organizationId, user, leaveRequestSignerResolver(this.runtimeService, runtime)));
188
+ withVerifiedDirectoryUser(organizationId, user, leaveRequestVerifier(this.runtimeService, runtime, {
189
+ organizationId,
190
+ userId: runtime.auth.userId ?? "",
191
+ })));
189
192
  }
190
193
  updateProfile(profileDocumentId) {
191
194
  const runtime = this.runtimeService.workflowInput();
@@ -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 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"]}
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 leaveRequestVerifier,\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 leaveRequestVerifier(this.runtimeService, runtime, {\n organizationId,\n userId: runtime.auth.userId ?? \"\",\n }),\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"]}
@@ -1,4 +1,5 @@
1
1
  import { refreshOrganizationMemberships, setOrganizationLeaveRequested, setOrganizationSyncPaused, } from "../../workflows/organizations/index.js";
2
+ import { loadCurrentMembersHead } from "../../workflows/organizations/memberships/leaveRequestMembersEvidence.js";
2
3
  import { getOrCreateOrganizationSyncPauses, hasDomainSyncCoordinatorPendingWork, requestAllDomainSyncLanes, subscribeToDomainSyncCoordinator, waitForDomainSyncCoordinatorToSettle, } from "../../workflows/sync/index.js";
3
4
  import { carriesLocalWrites, } from "../containerContents/index.js";
4
5
  // Long enough for a typical upload burst, short enough to answer a tap.
@@ -83,6 +84,30 @@ function canReachServer(runtime) {
83
84
  runtime.auth.isAuthenticated &&
84
85
  runtime.state.online);
85
86
  }
87
+ function setLeaveRequestedFor(runtimeService, organizationId, requested) {
88
+ const runtime = runtimeService.workflowInput();
89
+ const { userId } = runtime.auth;
90
+ const { signingKeyPair } = runtime.crypto;
91
+ if (!canReachServer(runtime) || !userId || !signingKeyPair) {
92
+ return Promise.resolve({
93
+ httpStatus: null,
94
+ message: "Connect to ask to leave an organization.",
95
+ status: "failed",
96
+ });
97
+ }
98
+ const { domainScope } = runtime.state;
99
+ return setOrganizationLeaveRequested({
100
+ apiClient: runtime.apiClient,
101
+ loadMembersHead: () => loadCurrentMembersHead({
102
+ organizationId,
103
+ runtime,
104
+ stillCurrent: () => runtimeService.workflowInput().state.domainScope === domainScope,
105
+ }),
106
+ organizationId,
107
+ requested,
108
+ signer: { signingKeyPair, userId },
109
+ });
110
+ }
86
111
  export function createOrganizationMemberships(runtimeService, containerContents, openReconciler) {
87
112
  const membershipInput = (runtime) => {
88
113
  const { domainScope } = runtime.state;
@@ -123,24 +148,7 @@ export function createOrganizationMemberships(runtimeService, containerContents,
123
148
  paused,
124
149
  });
125
150
  },
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
- },
151
+ setLeaveRequested: (organizationId, requested) => setLeaveRequestedFor(runtimeService, organizationId, requested),
144
152
  async loadPausedOrganizationIds() {
145
153
  const runtime = runtimeService.workflowInput();
146
154
  if (runtime.infra.dbStatus !== "ready")
@@ -1 +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
+ {"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 { loadCurrentMembersHead } from \"../../workflows/organizations/memberships/leaveRequestMembersEvidence\";\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\nfunction setLeaveRequestedFor(\n runtimeService: InternalRuntime,\n organizationId: string,\n requested: boolean,\n): Promise<OrganizationLeaveRequestResult> {\n const runtime = runtimeService.workflowInput();\n const { userId } = runtime.auth;\n const { signingKeyPair } = runtime.crypto;\n if (!canReachServer(runtime) || !userId || !signingKeyPair) {\n return Promise.resolve({\n httpStatus: null,\n message: \"Connect to ask to leave an organization.\",\n status: \"failed\",\n });\n }\n const { domainScope } = runtime.state;\n return setOrganizationLeaveRequested({\n apiClient: runtime.apiClient,\n loadMembersHead: () =>\n loadCurrentMembersHead({\n organizationId,\n runtime,\n stillCurrent: () =>\n runtimeService.workflowInput().state.domainScope === domainScope,\n }),\n organizationId,\n requested,\n signer: { signingKeyPair, userId },\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 setLeaveRequested: (organizationId, requested) =>\n setLeaveRequestedFor(runtimeService, organizationId, requested),\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,11 +1,16 @@
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 { LeaveRequestVerifier } from "../../workflows/organizations/memberships/leaveRequestVerification.js";
2
3
  import type { InternalRuntime, InternalWorkflowRuntimeInput } from "../runtime/workflowRuntime.js";
3
4
  /**
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.
5
+ * What one view's leave requests are checked against. The signer comes from
6
+ * the device's durable pin first, so a request already stored still verifies
7
+ * offline, then a trusted remote resolution for a member not pinned yet. The
8
+ * membership comes from this device's verified organization policy.
7
9
  */
8
- export declare function leaveRequestSignerResolver(runtimeService: InternalRuntime, runtime: InternalWorkflowRuntimeInput): InternalWorkflowRuntimeInput["resolveTrustedUserIdentity"];
10
+ export declare function leaveRequestVerifier(runtimeService: InternalRuntime, runtime: InternalWorkflowRuntimeInput, organization: {
11
+ readonly organizationId: string;
12
+ readonly userId: string;
13
+ }): LeaveRequestVerifier;
9
14
  export interface OrganizationReadModelCoordinator {
10
15
  loadLocal(organizationId?: string | undefined): Promise<OrganizationDirectoryAndGroups | null>;
11
16
  loadLocalGroupMembers(groupId: string, organizationId?: string | undefined): Promise<OrganizationGroupMembers | null>;
@@ -1,5 +1,6 @@
1
1
  import { recoverOrganizationAccess } from "../../workflows/container-contents/recovery/accessRestoration.js";
2
2
  import { loadLocalOrganizationContainerGrants, loadLocalOrganizationDirectoryAndGroups, loadLocalOrganizationGroupContainers, loadLocalOrganizationGroupMembers, loadLocalOrganizationUserDetail, reconcileOrganizationDirectoryAndGroups, withVerifiedLeaveRequests, withVerifiedUserLeaveRequest, } from "../../workflows/organizations/index.js";
3
+ import { createRuntimeLeaveRequestMembershipCheck } from "../../workflows/organizations/memberships/leaveRequestMembersEvidence.js";
3
4
  import { organizationAccessScopeKey, wasOrganizationPresentationAccessDeniedByServer, } from "../../workflows/organizations/readModel/organizationPresentationAccessState.js";
4
5
  import { loadBoundedOrganizationGroupHistory } from "./organizationGroupHistory.js";
5
6
  import { hydrateOrganizationGroupNamesForRuntime } from "./organizationGroupNameHydration.js";
@@ -7,13 +8,23 @@ import { loadBoundedOrganizationHistory } from "./organizationHistory.js";
7
8
  import { activeOrganizationDataRuntime, isOrganizationDataRuntimeCurrent, } from "./organizationWorkflowRuntime.js";
8
9
  const coordinatorsByRuntime = new WeakMap();
9
10
  /**
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.
11
+ * What one view's leave requests are checked against. The signer comes from
12
+ * the device's durable pin first, so a request already stored still verifies
13
+ * offline, then a trusted remote resolution for a member not pinned yet. The
14
+ * membership comes from this device's verified organization policy.
13
15
  */
14
- export function leaveRequestSignerResolver(runtimeService, runtime) {
15
- return async (userId) => (await runtimeService.identityLinks.resolvePinned(userId)) ??
16
- runtime.resolveTrustedUserIdentity(userId);
16
+ export function leaveRequestVerifier(runtimeService, runtime, organization) {
17
+ const { domainScope } = runtime.state;
18
+ return {
19
+ resolveTrustedUserIdentity: async (userId) => (await runtimeService.identityLinks.resolvePinned(userId)) ??
20
+ runtime.resolveTrustedUserIdentity(userId),
21
+ membershipIsCurrent: createRuntimeLeaveRequestMembershipCheck({
22
+ currentUserId: organization.userId,
23
+ organizationId: organization.organizationId,
24
+ runtime,
25
+ stillCurrent: () => runtimeService.workflowInput().state.domainScope === domainScope,
26
+ }),
27
+ };
17
28
  }
18
29
  class OrganizationReadModelCoordinatorImpl {
19
30
  runtimeService;
@@ -39,7 +50,7 @@ class OrganizationReadModelCoordinatorImpl {
39
50
  currentUserId: active.userId,
40
51
  execSql: active.runtime.infra.execSql,
41
52
  organizationId: active.organizationId,
42
- }), leaveRequestSignerResolver(this.runtimeService, active.runtime));
53
+ }), leaveRequestVerifier(this.runtimeService, active.runtime, active));
43
54
  }
44
55
  async loadLocalGrants(organizationId) {
45
56
  const active = activeOrganizationDataRuntime(this.runtimeService, organizationId);
@@ -110,7 +121,7 @@ class OrganizationReadModelCoordinatorImpl {
110
121
  execSql: active.runtime.infra.execSql,
111
122
  organizationId: active.organizationId,
112
123
  userId,
113
- }), active.organizationId, leaveRequestSignerResolver(this.runtimeService, active.runtime));
124
+ }), active.organizationId, leaveRequestVerifier(this.runtimeService, active.runtime, active));
114
125
  }
115
126
  reconcile(organizationId) {
116
127
  const active = activeOrganizationDataRuntime(this.runtimeService, organizationId);
@@ -162,7 +173,7 @@ class OrganizationReadModelCoordinatorImpl {
162
173
  });
163
174
  if (!stillCurrent())
164
175
  return null;
165
- return withVerifiedLeaveRequests(await hydrateOrganizationGroupNamesForRuntime(this.runtimeService, active, domainScope, directoryAndGroups), leaveRequestSignerResolver(this.runtimeService, active.runtime));
176
+ return withVerifiedLeaveRequests(await hydrateOrganizationGroupNamesForRuntime(this.runtimeService, active, domainScope, directoryAndGroups), leaveRequestVerifier(this.runtimeService, active.runtime, active));
166
177
  })
167
178
  .finally(() => {
168
179
  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 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"]}
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 { createRuntimeLeaveRequestMembershipCheck } from \"../../workflows/organizations/memberships/leaveRequestMembersEvidence\";\nimport type { LeaveRequestVerifier } from \"../../workflows/organizations/memberships/leaveRequestVerification\";\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 * What one view's leave requests are checked against. The signer comes from\n * the device's durable pin first, so a request already stored still verifies\n * offline, then a trusted remote resolution for a member not pinned yet. The\n * membership comes from this device's verified organization policy.\n */\nexport function leaveRequestVerifier(\n runtimeService: InternalRuntime,\n runtime: InternalWorkflowRuntimeInput,\n organization: { readonly organizationId: string; readonly userId: string },\n): LeaveRequestVerifier {\n const { domainScope } = runtime.state;\n return {\n resolveTrustedUserIdentity: async (userId) =>\n (await runtimeService.identityLinks.resolvePinned(userId)) ??\n runtime.resolveTrustedUserIdentity(userId),\n membershipIsCurrent: createRuntimeLeaveRequestMembershipCheck({\n currentUserId: organization.userId,\n organizationId: organization.organizationId,\n runtime,\n stillCurrent: () =>\n runtimeService.workflowInput().state.domainScope === domainScope,\n }),\n };\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 leaveRequestVerifier(this.runtimeService, active.runtime, active),\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 leaveRequestVerifier(this.runtimeService, active.runtime, active),\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 leaveRequestVerifier(this.runtimeService, active.runtime, active),\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"]}
@@ -2095,6 +2095,13 @@ export declare class ApiClient {
2095
2095
  organizationId: string;
2096
2096
  userId: string;
2097
2097
  requestedAt: string;
2098
+ membersHead: {
2099
+ principalId: string;
2100
+ version: number;
2101
+ keyEpoch: number;
2102
+ stateHash: string;
2103
+ keyFingerprint: string;
2104
+ };
2098
2105
  signature: string;
2099
2106
  } | null;
2100
2107
  profileDocumentId: string | null;
@@ -7,7 +7,7 @@ export declare function signOrganizationLeaveRequest(payload: LeaveRequestPayloa
7
7
  /**
8
8
  * Whether `value` is a well-formed leave request signed by the holder of
9
9
  * `publicKey`. Callers still check that it names the organization and member
10
- * they expect.
10
+ * they expect, and that the member has stayed in Members since the cited head.
11
11
  */
12
12
  export declare function isValidOrganizationLeaveRequest(value: unknown, publicKey: Uint8Array): value is OrganizationLeaveRequest;
13
13
  export {};
@@ -5,7 +5,14 @@ import { sign } from "./signing/sign.js";
5
5
  import { verify } from "./signing/verify.js";
6
6
  export function organizationLeaveRequestSigningBytes(payload) {
7
7
  return new TextEncoder().encode(serializeKeyingCanonicalJson({
8
- domain: "tearleads.organization-leave-request.v1",
8
+ domain: "tearleads.organization-leave-request.v2",
9
+ membersHead: {
10
+ keyEpoch: payload.membersHead.keyEpoch,
11
+ keyFingerprint: payload.membersHead.keyFingerprint,
12
+ principalId: payload.membersHead.principalId,
13
+ stateHash: payload.membersHead.stateHash,
14
+ version: payload.membersHead.version,
15
+ },
9
16
  organizationId: payload.organizationId,
10
17
  requestedAt: payload.requestedAt,
11
18
  userId: payload.userId,
@@ -21,7 +28,7 @@ export function signOrganizationLeaveRequest(payload, keys) {
21
28
  /**
22
29
  * Whether `value` is a well-formed leave request signed by the holder of
23
30
  * `publicKey`. Callers still check that it names the organization and member
24
- * they expect.
31
+ * they expect, and that the member has stayed in Members since the cited head.
25
32
  */
26
33
  export function isValidOrganizationLeaveRequest(value, publicKey) {
27
34
  const parsed = OrganizationLeaveRequestSchema.safeParse(value);
@@ -1 +1 @@
1
- {"version":3,"file":"organizationLeaveRequest.js","sourceRoot":"","sources":["organizationLeaveRequest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAEL,8BAA8B,GAC/B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAC;AAElE,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAI1C,MAAM,UAAU,oCAAoC,CAClD,OAA4B;IAE5B,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAC7B,4BAA4B,CAAC;QAC3B,MAAM,EAAE,yCAAyC;QACjD,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CACH,CAAC;AACJ,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,4BAA4B,CAC1C,OAA4B,EAC5B,IAA+C;IAE/C,OAAO,8BAA8B,CAAC,KAAK,CAAC;QAC1C,GAAG,OAAO;QACV,SAAS,EAAE,aAAa,CACtB,IAAI,CACF,oCAAoC,CAAC,OAAO,CAAC,EAC7C,IAAI,CAAC,iBAAiB,CACvB,CACF;KACF,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,+BAA+B,CAC7C,KAAc,EACd,SAAqB;IAErB,MAAM,MAAM,GAAG,8BAA8B,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/D,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAClC,IAAI,SAAqB,CAAC;IAC1B,IAAI,CAAC;QACH,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,MAAM,CACX,SAAS,EACT,oCAAoC,CAAC,MAAM,CAAC,IAAI,CAAC,EACjD,SAAS,CACV,CAAC;AACJ,CAAC","sourcesContent":["import { base64ToBytes, bytesToBase64 } from \"@tearleads/encoding\";\nimport {\n type OrganizationLeaveRequest,\n OrganizationLeaveRequestSchema,\n} from \"@tearleads/validators/util\";\nimport { serializeKeyingCanonicalJson } from \"./keying/canonical\";\nimport type { SigningKeyPair } from \"./signing/generateKeyPair\";\nimport { sign } from \"./signing/sign\";\nimport { verify } from \"./signing/verify\";\n\ntype LeaveRequestPayload = Omit<OrganizationLeaveRequest, \"signature\">;\n\nexport function organizationLeaveRequestSigningBytes(\n payload: LeaveRequestPayload,\n): Uint8Array {\n return new TextEncoder().encode(\n serializeKeyingCanonicalJson({\n domain: \"tearleads.organization-leave-request.v1\",\n organizationId: payload.organizationId,\n requestedAt: payload.requestedAt,\n userId: payload.userId,\n }),\n );\n}\n\n/** Signs a member's request to leave one organization. */\nexport function signOrganizationLeaveRequest(\n payload: LeaveRequestPayload,\n keys: Pick<SigningKeyPair, \"signingPrivateKey\">,\n): OrganizationLeaveRequest {\n return OrganizationLeaveRequestSchema.parse({\n ...payload,\n signature: bytesToBase64(\n sign(\n organizationLeaveRequestSigningBytes(payload),\n keys.signingPrivateKey,\n ),\n ),\n });\n}\n\n/**\n * Whether `value` is a well-formed leave request signed by the holder of\n * `publicKey`. Callers still check that it names the organization and member\n * they expect.\n */\nexport function isValidOrganizationLeaveRequest(\n value: unknown,\n publicKey: Uint8Array,\n): value is OrganizationLeaveRequest {\n const parsed = OrganizationLeaveRequestSchema.safeParse(value);\n if (!parsed.success) return false;\n let signature: Uint8Array;\n try {\n signature = base64ToBytes(parsed.data.signature);\n } catch {\n return false;\n }\n return verify(\n signature,\n organizationLeaveRequestSigningBytes(parsed.data),\n publicKey,\n );\n}\n"]}
1
+ {"version":3,"file":"organizationLeaveRequest.js","sourceRoot":"","sources":["organizationLeaveRequest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAEL,8BAA8B,GAC/B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAC;AAElE,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAI1C,MAAM,UAAU,oCAAoC,CAClD,OAA4B;IAE5B,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAC7B,4BAA4B,CAAC;QAC3B,MAAM,EAAE,yCAAyC;QACjD,WAAW,EAAE;YACX,QAAQ,EAAE,OAAO,CAAC,WAAW,CAAC,QAAQ;YACtC,cAAc,EAAE,OAAO,CAAC,WAAW,CAAC,cAAc;YAClD,WAAW,EAAE,OAAO,CAAC,WAAW,CAAC,WAAW;YAC5C,SAAS,EAAE,OAAO,CAAC,WAAW,CAAC,SAAS;YACxC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,OAAO;SACrC;QACD,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CACH,CAAC;AACJ,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,4BAA4B,CAC1C,OAA4B,EAC5B,IAA+C;IAE/C,OAAO,8BAA8B,CAAC,KAAK,CAAC;QAC1C,GAAG,OAAO;QACV,SAAS,EAAE,aAAa,CACtB,IAAI,CACF,oCAAoC,CAAC,OAAO,CAAC,EAC7C,IAAI,CAAC,iBAAiB,CACvB,CACF;KACF,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,+BAA+B,CAC7C,KAAc,EACd,SAAqB;IAErB,MAAM,MAAM,GAAG,8BAA8B,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/D,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAClC,IAAI,SAAqB,CAAC;IAC1B,IAAI,CAAC;QACH,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,MAAM,CACX,SAAS,EACT,oCAAoC,CAAC,MAAM,CAAC,IAAI,CAAC,EACjD,SAAS,CACV,CAAC;AACJ,CAAC","sourcesContent":["import { base64ToBytes, bytesToBase64 } from \"@tearleads/encoding\";\nimport {\n type OrganizationLeaveRequest,\n OrganizationLeaveRequestSchema,\n} from \"@tearleads/validators/util\";\nimport { serializeKeyingCanonicalJson } from \"./keying/canonical\";\nimport type { SigningKeyPair } from \"./signing/generateKeyPair\";\nimport { sign } from \"./signing/sign\";\nimport { verify } from \"./signing/verify\";\n\ntype LeaveRequestPayload = Omit<OrganizationLeaveRequest, \"signature\">;\n\nexport function organizationLeaveRequestSigningBytes(\n payload: LeaveRequestPayload,\n): Uint8Array {\n return new TextEncoder().encode(\n serializeKeyingCanonicalJson({\n domain: \"tearleads.organization-leave-request.v2\",\n membersHead: {\n keyEpoch: payload.membersHead.keyEpoch,\n keyFingerprint: payload.membersHead.keyFingerprint,\n principalId: payload.membersHead.principalId,\n stateHash: payload.membersHead.stateHash,\n version: payload.membersHead.version,\n },\n organizationId: payload.organizationId,\n requestedAt: payload.requestedAt,\n userId: payload.userId,\n }),\n );\n}\n\n/** Signs a member's request to leave one organization. */\nexport function signOrganizationLeaveRequest(\n payload: LeaveRequestPayload,\n keys: Pick<SigningKeyPair, \"signingPrivateKey\">,\n): OrganizationLeaveRequest {\n return OrganizationLeaveRequestSchema.parse({\n ...payload,\n signature: bytesToBase64(\n sign(\n organizationLeaveRequestSigningBytes(payload),\n keys.signingPrivateKey,\n ),\n ),\n });\n}\n\n/**\n * Whether `value` is a well-formed leave request signed by the holder of\n * `publicKey`. Callers still check that it names the organization and member\n * they expect, and that the member has stayed in Members since the cited head.\n */\nexport function isValidOrganizationLeaveRequest(\n value: unknown,\n publicKey: Uint8Array,\n): value is OrganizationLeaveRequest {\n const parsed = OrganizationLeaveRequestSchema.safeParse(value);\n if (!parsed.success) return false;\n let signature: Uint8Array;\n try {\n signature = base64ToBytes(parsed.data.signature);\n } catch {\n return false;\n }\n return verify(\n signature,\n organizationLeaveRequestSigningBytes(parsed.data),\n publicKey,\n );\n}\n"]}
@@ -255,6 +255,13 @@ export declare const requestOrganizationLeaveOperation: Omit<{
255
255
  organizationId: z.ZodCustom<string, string>;
256
256
  userId: z.ZodCustom<string, string>;
257
257
  requestedAt: z.ZodString;
258
+ membersHead: z.ZodObject<{
259
+ principalId: z.ZodCustom<string, string>;
260
+ version: z.ZodCustom<number, number>;
261
+ keyEpoch: z.ZodCustom<number, number>;
262
+ stateHash: z.ZodString;
263
+ keyFingerprint: z.ZodString;
264
+ }, z.core.$strict>;
258
265
  signature: z.ZodString;
259
266
  }, z.core.$strict>;
260
267
  readonly failureResponses: {