@multitenantkit/domain 0.1.1

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 (125) hide show
  1. package/dist/index.d.ts +5 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +9 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/organization-memberships/index.d.ts +3 -0
  6. package/dist/organization-memberships/index.d.ts.map +1 -0
  7. package/dist/organization-memberships/index.js +3 -0
  8. package/dist/organization-memberships/index.js.map +1 -0
  9. package/dist/organization-memberships/use-cases/accept-organization-invitation/AcceptOrganizationInvitation.d.ts +26 -0
  10. package/dist/organization-memberships/use-cases/accept-organization-invitation/AcceptOrganizationInvitation.d.ts.map +1 -0
  11. package/dist/organization-memberships/use-cases/accept-organization-invitation/AcceptOrganizationInvitation.js +85 -0
  12. package/dist/organization-memberships/use-cases/accept-organization-invitation/AcceptOrganizationInvitation.js.map +1 -0
  13. package/dist/organization-memberships/use-cases/add-organization-member/AddOrganizationMember.d.ts +19 -0
  14. package/dist/organization-memberships/use-cases/add-organization-member/AddOrganizationMember.d.ts.map +1 -0
  15. package/dist/organization-memberships/use-cases/add-organization-member/AddOrganizationMember.js +126 -0
  16. package/dist/organization-memberships/use-cases/add-organization-member/AddOrganizationMember.js.map +1 -0
  17. package/dist/organization-memberships/use-cases/index.d.ts +6 -0
  18. package/dist/organization-memberships/use-cases/index.d.ts.map +1 -0
  19. package/dist/organization-memberships/use-cases/index.js +8 -0
  20. package/dist/organization-memberships/use-cases/index.js.map +1 -0
  21. package/dist/organization-memberships/use-cases/leave-organization/LeaveOrganization.d.ts +15 -0
  22. package/dist/organization-memberships/use-cases/leave-organization/LeaveOrganization.d.ts.map +1 -0
  23. package/dist/organization-memberships/use-cases/leave-organization/LeaveOrganization.js +64 -0
  24. package/dist/organization-memberships/use-cases/leave-organization/LeaveOrganization.js.map +1 -0
  25. package/dist/organization-memberships/use-cases/remove-organization-member/RemoveOrganizationMember.d.ts +16 -0
  26. package/dist/organization-memberships/use-cases/remove-organization-member/RemoveOrganizationMember.d.ts.map +1 -0
  27. package/dist/organization-memberships/use-cases/remove-organization-member/RemoveOrganizationMember.js +87 -0
  28. package/dist/organization-memberships/use-cases/remove-organization-member/RemoveOrganizationMember.js.map +1 -0
  29. package/dist/organization-memberships/use-cases/update-organization-member-role/UpdateOrganizationMemberRole.d.ts +16 -0
  30. package/dist/organization-memberships/use-cases/update-organization-member-role/UpdateOrganizationMemberRole.d.ts.map +1 -0
  31. package/dist/organization-memberships/use-cases/update-organization-member-role/UpdateOrganizationMemberRole.js +85 -0
  32. package/dist/organization-memberships/use-cases/update-organization-member-role/UpdateOrganizationMemberRole.js.map +1 -0
  33. package/dist/organizations/index.d.ts +2 -0
  34. package/dist/organizations/index.d.ts.map +1 -0
  35. package/dist/organizations/index.js +3 -0
  36. package/dist/organizations/index.js.map +1 -0
  37. package/dist/organizations/use-cases/archive-organization/ArchiveOrganization.d.ts +38 -0
  38. package/dist/organizations/use-cases/archive-organization/ArchiveOrganization.d.ts.map +1 -0
  39. package/dist/organizations/use-cases/archive-organization/ArchiveOrganization.js +117 -0
  40. package/dist/organizations/use-cases/archive-organization/ArchiveOrganization.js.map +1 -0
  41. package/dist/organizations/use-cases/create-organization/CreateOrganization.d.ts +19 -0
  42. package/dist/organizations/use-cases/create-organization/CreateOrganization.d.ts.map +1 -0
  43. package/dist/organizations/use-cases/create-organization/CreateOrganization.js +96 -0
  44. package/dist/organizations/use-cases/create-organization/CreateOrganization.js.map +1 -0
  45. package/dist/organizations/use-cases/delete-organization/DeleteOrganization.d.ts +34 -0
  46. package/dist/organizations/use-cases/delete-organization/DeleteOrganization.d.ts.map +1 -0
  47. package/dist/organizations/use-cases/delete-organization/DeleteOrganization.js +103 -0
  48. package/dist/organizations/use-cases/delete-organization/DeleteOrganization.js.map +1 -0
  49. package/dist/organizations/use-cases/get-organization/GetOrganization.d.ts +18 -0
  50. package/dist/organizations/use-cases/get-organization/GetOrganization.d.ts.map +1 -0
  51. package/dist/organizations/use-cases/get-organization/GetOrganization.js +51 -0
  52. package/dist/organizations/use-cases/get-organization/GetOrganization.js.map +1 -0
  53. package/dist/organizations/use-cases/index.d.ts +9 -0
  54. package/dist/organizations/use-cases/index.d.ts.map +1 -0
  55. package/dist/organizations/use-cases/index.js +11 -0
  56. package/dist/organizations/use-cases/index.js.map +1 -0
  57. package/dist/organizations/use-cases/list-organization-members/ListOrganizationMembers.d.ts +46 -0
  58. package/dist/organizations/use-cases/list-organization-members/ListOrganizationMembers.d.ts.map +1 -0
  59. package/dist/organizations/use-cases/list-organization-members/ListOrganizationMembers.js +130 -0
  60. package/dist/organizations/use-cases/list-organization-members/ListOrganizationMembers.js.map +1 -0
  61. package/dist/organizations/use-cases/restore-organization/RestoreOrganization.d.ts +30 -0
  62. package/dist/organizations/use-cases/restore-organization/RestoreOrganization.d.ts.map +1 -0
  63. package/dist/organizations/use-cases/restore-organization/RestoreOrganization.js +98 -0
  64. package/dist/organizations/use-cases/restore-organization/RestoreOrganization.js.map +1 -0
  65. package/dist/organizations/use-cases/transfer-organization-ownership/TransferOrganizationOwnership.d.ts +30 -0
  66. package/dist/organizations/use-cases/transfer-organization-ownership/TransferOrganizationOwnership.d.ts.map +1 -0
  67. package/dist/organizations/use-cases/transfer-organization-ownership/TransferOrganizationOwnership.js +139 -0
  68. package/dist/organizations/use-cases/transfer-organization-ownership/TransferOrganizationOwnership.js.map +1 -0
  69. package/dist/organizations/use-cases/update-organization/UpdateOrganization.d.ts +22 -0
  70. package/dist/organizations/use-cases/update-organization/UpdateOrganization.d.ts.map +1 -0
  71. package/dist/organizations/use-cases/update-organization/UpdateOrganization.js +100 -0
  72. package/dist/organizations/use-cases/update-organization/UpdateOrganization.js.map +1 -0
  73. package/dist/shared/index.d.ts +3 -0
  74. package/dist/shared/index.d.ts.map +1 -0
  75. package/dist/shared/index.js +4 -0
  76. package/dist/shared/index.js.map +1 -0
  77. package/dist/shared/result/Result.d.ts +30 -0
  78. package/dist/shared/result/Result.d.ts.map +1 -0
  79. package/dist/shared/result/Result.js +69 -0
  80. package/dist/shared/result/Result.js.map +1 -0
  81. package/dist/shared/result/index.d.ts +4 -0
  82. package/dist/shared/result/index.d.ts.map +1 -0
  83. package/dist/shared/result/index.js +2 -0
  84. package/dist/shared/result/index.js.map +1 -0
  85. package/dist/shared/use-case/BaseUseCase.d.ts +164 -0
  86. package/dist/shared/use-case/BaseUseCase.d.ts.map +1 -0
  87. package/dist/shared/use-case/BaseUseCase.js +366 -0
  88. package/dist/shared/use-case/BaseUseCase.js.map +1 -0
  89. package/dist/shared/use-case/UseCaseHelpers.d.ts +43 -0
  90. package/dist/shared/use-case/UseCaseHelpers.d.ts.map +1 -0
  91. package/dist/shared/use-case/UseCaseHelpers.js +56 -0
  92. package/dist/shared/use-case/UseCaseHelpers.js.map +1 -0
  93. package/dist/shared/use-case/index.d.ts +3 -0
  94. package/dist/shared/use-case/index.d.ts.map +1 -0
  95. package/dist/shared/use-case/index.js +4 -0
  96. package/dist/shared/use-case/index.js.map +1 -0
  97. package/dist/users/index.d.ts +2 -0
  98. package/dist/users/index.d.ts.map +1 -0
  99. package/dist/users/index.js +3 -0
  100. package/dist/users/index.js.map +1 -0
  101. package/dist/users/use-cases/create-user/CreateUser.d.ts +21 -0
  102. package/dist/users/use-cases/create-user/CreateUser.d.ts.map +1 -0
  103. package/dist/users/use-cases/create-user/CreateUser.js +81 -0
  104. package/dist/users/use-cases/create-user/CreateUser.js.map +1 -0
  105. package/dist/users/use-cases/delete-user/DeleteUser.d.ts +35 -0
  106. package/dist/users/use-cases/delete-user/DeleteUser.d.ts.map +1 -0
  107. package/dist/users/use-cases/delete-user/DeleteUser.js +120 -0
  108. package/dist/users/use-cases/delete-user/DeleteUser.js.map +1 -0
  109. package/dist/users/use-cases/get-user/GetUser.d.ts +18 -0
  110. package/dist/users/use-cases/get-user/GetUser.d.ts.map +1 -0
  111. package/dist/users/use-cases/get-user/GetUser.js +29 -0
  112. package/dist/users/use-cases/get-user/GetUser.js.map +1 -0
  113. package/dist/users/use-cases/index.d.ts +6 -0
  114. package/dist/users/use-cases/index.d.ts.map +1 -0
  115. package/dist/users/use-cases/index.js +8 -0
  116. package/dist/users/use-cases/index.js.map +1 -0
  117. package/dist/users/use-cases/list-user-organizations/ListUserOrganizations.d.ts +20 -0
  118. package/dist/users/use-cases/list-user-organizations/ListUserOrganizations.d.ts.map +1 -0
  119. package/dist/users/use-cases/list-user-organizations/ListUserOrganizations.js +68 -0
  120. package/dist/users/use-cases/list-user-organizations/ListUserOrganizations.js.map +1 -0
  121. package/dist/users/use-cases/update-user/UpdateUser.d.ts +19 -0
  122. package/dist/users/use-cases/update-user/UpdateUser.d.ts.map +1 -0
  123. package/dist/users/use-cases/update-user/UpdateUser.js +73 -0
  124. package/dist/users/use-cases/update-user/UpdateUser.js.map +1 -0
  125. package/package.json +81 -0
@@ -0,0 +1,35 @@
1
+ import type { DeleteUserInput, IDeleteUser, OperationContext, ToolkitOptions, User } from '@multitenantkit/domain-contracts';
2
+ import { type Adapters, type NotFoundError, ValidationError } from '@multitenantkit/domain-contracts';
3
+ import { Result } from '../../../shared/result';
4
+ import { BaseUseCase } from '../../../shared/use-case';
5
+ /**
6
+ * DeleteUser use case
7
+ * Handles the business logic for soft deleting a user
8
+ * Sets the deletedAt timestamp without removing the user from the database
9
+ *
10
+ * Cascade behavior:
11
+ * - Soft deletes all organizations owned by the user (sets deletedAt)
12
+ * - Does NOT modify memberships in owned organizations (preserves state for future restore)
13
+ * - Soft deletes memberships in organizations NOT owned by the user (sets leftAt AND deletedAt)
14
+ * because the user is conceptually "leaving" these organizations
15
+ *
16
+ * Semantic distinction for owned organizations:
17
+ * - organization.deletedAt = organization was soft deleted (owner deleted)
18
+ * - membership.deletedAt = null → membership was active, can be restored
19
+ * - membership.deletedAt = set → membership was explicitly removed, should NOT be restored
20
+ * - membership.leftAt = user voluntarily left before organization deletion
21
+ *
22
+ * Semantic distinction for non-owned organizations:
23
+ * - membership.leftAt = user is leaving (being deleted)
24
+ * - membership.deletedAt = user no longer exists
25
+ *
26
+ * Generic support for custom fields:
27
+ * @template TUserCustomFields - Custom fields added to User
28
+ * @template TOrganizationCustomFields - Custom fields added to Organization (for toolkit options compatibility)
29
+ * @template TOrganizationMembershipCustomFields - Custom fields added to OrganizationMembership (for toolkit options compatibility)
30
+ */
31
+ export declare class DeleteUser<TUserCustomFields = {}, TOrganizationCustomFields = {}, TOrganizationMembershipCustomFields = {}> extends BaseUseCase<DeleteUserInput, User & TUserCustomFields, ValidationError | NotFoundError, TUserCustomFields, TOrganizationCustomFields, TOrganizationMembershipCustomFields> implements IDeleteUser {
32
+ constructor(adapters: Adapters<TUserCustomFields, TOrganizationCustomFields, TOrganizationMembershipCustomFields>, toolkitOptions?: ToolkitOptions<TUserCustomFields, TOrganizationCustomFields, TOrganizationMembershipCustomFields>);
33
+ protected executeBusinessLogic(input: DeleteUserInput, context: OperationContext): Promise<Result<User & TUserCustomFields, ValidationError | NotFoundError>>;
34
+ }
35
+ //# sourceMappingURL=DeleteUser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeleteUser.d.ts","sourceRoot":"","sources":["../../../../src/users/use-cases/delete-user/DeleteUser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,eAAe,EACf,WAAW,EACX,gBAAgB,EAGhB,cAAc,EACd,IAAI,EACP,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACH,KAAK,QAAQ,EAEb,KAAK,aAAa,EAIlB,eAAe,EAClB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAkB,MAAM,0BAA0B,CAAC;AAEvE;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,UAAU,CAEf,iBAAiB,GAAG,EAAE,EAEtB,yBAAyB,GAAG,EAAE,EAE9B,mCAAmC,GAAG,EAAE,CAE5C,SAAQ,WAAW,CACf,eAAe,EACf,IAAI,GAAG,iBAAiB,EACxB,eAAe,GAAG,aAAa,EAC/B,iBAAiB,EACjB,yBAAyB,EACzB,mCAAmC,CAEvC,YAAW,WAAW;gBAGlB,QAAQ,EAAE,QAAQ,CACd,iBAAiB,EACjB,yBAAyB,EACzB,mCAAmC,CACtC,EACD,cAAc,CAAC,EAAE,cAAc,CAC3B,iBAAiB,EACjB,yBAAyB,EACzB,mCAAmC,CACtC;cAYW,oBAAoB,CAChC,KAAK,EAAE,eAAe,EACtB,OAAO,EAAE,gBAAgB,GAC1B,OAAO,CAAC,MAAM,CAAC,IAAI,GAAG,iBAAiB,EAAE,eAAe,GAAG,aAAa,CAAC,CAAC;CA8GhF"}
@@ -0,0 +1,120 @@
1
+ import { DeleteUserInputSchema, OrganizationMembershipSchema, OrganizationSchema, UserSchema, ValidationError } from '@multitenantkit/domain-contracts';
2
+ import { z } from 'zod';
3
+ import { Result } from '../../../shared/result';
4
+ import { BaseUseCase, UseCaseHelpers } from '../../../shared/use-case';
5
+ /**
6
+ * DeleteUser use case
7
+ * Handles the business logic for soft deleting a user
8
+ * Sets the deletedAt timestamp without removing the user from the database
9
+ *
10
+ * Cascade behavior:
11
+ * - Soft deletes all organizations owned by the user (sets deletedAt)
12
+ * - Does NOT modify memberships in owned organizations (preserves state for future restore)
13
+ * - Soft deletes memberships in organizations NOT owned by the user (sets leftAt AND deletedAt)
14
+ * because the user is conceptually "leaving" these organizations
15
+ *
16
+ * Semantic distinction for owned organizations:
17
+ * - organization.deletedAt = organization was soft deleted (owner deleted)
18
+ * - membership.deletedAt = null → membership was active, can be restored
19
+ * - membership.deletedAt = set → membership was explicitly removed, should NOT be restored
20
+ * - membership.leftAt = user voluntarily left before organization deletion
21
+ *
22
+ * Semantic distinction for non-owned organizations:
23
+ * - membership.leftAt = user is leaving (being deleted)
24
+ * - membership.deletedAt = user no longer exists
25
+ *
26
+ * Generic support for custom fields:
27
+ * @template TUserCustomFields - Custom fields added to User
28
+ * @template TOrganizationCustomFields - Custom fields added to Organization (for toolkit options compatibility)
29
+ * @template TOrganizationMembershipCustomFields - Custom fields added to OrganizationMembership (for toolkit options compatibility)
30
+ */
31
+ export class DeleteUser extends BaseUseCase {
32
+ constructor(adapters, toolkitOptions) {
33
+ super('user-deleteUser', adapters, toolkitOptions, DeleteUserInputSchema, z.any(), // No validation needed for output - domain entities are already type-safe
34
+ 'Failed to delete user');
35
+ }
36
+ async executeBusinessLogic(input, context) {
37
+ // 1. Get user by externalId
38
+ const getUserResult = await this.getUserFromExternalId(input.principalExternalId);
39
+ if (getUserResult.isFailure) {
40
+ return Result.fail(getUserResult.getError());
41
+ }
42
+ const existingUser = getUserResult.getValue();
43
+ // 2. Check if user is already deleted
44
+ if (existingUser.deletedAt) {
45
+ return Result.fail(new ValidationError('User is already deleted', 'userId'));
46
+ }
47
+ // 3. Build deleted user data (soft delete)
48
+ const now = this.adapters.system.clock.now();
49
+ const deletedUserData = {
50
+ ...existingUser,
51
+ deletedAt: now,
52
+ updatedAt: now
53
+ };
54
+ // 4. Validate the updated data
55
+ const validationResult = UserSchema.strip().safeParse(deletedUserData);
56
+ if (!validationResult.success) {
57
+ const firstError = validationResult.error.errors[0];
58
+ return Result.fail(new ValidationError(firstError.message, firstError.path.join('.')));
59
+ }
60
+ // Use validated and potentially transformed data from Zod
61
+ const deletedUser = validationResult.data;
62
+ // 5. Persist the deleted user using Unit of Work (transaction) with audit context
63
+ const auditContext = UseCaseHelpers.enrichAuditContext(context, 'DELETE_USER', undefined // Users don't belong directly to a organization
64
+ );
65
+ await this.adapters.persistence.uow.transaction(async (repos) => {
66
+ // 5.1. Save the soft-deleted user
67
+ await repos.users.update(deletedUser, auditContext);
68
+ // 5.2. Soft delete all organizations owned by this user (using internal user ID)
69
+ const ownedOrganizations = await this.adapters.persistence.organizationRepository.findByOwner(existingUser.id);
70
+ for (const organization of ownedOrganizations) {
71
+ if (!organization.deletedAt) {
72
+ const deletedOrganization = {
73
+ ...organization,
74
+ deletedAt: now,
75
+ updatedAt: now
76
+ };
77
+ // Validate the organization data
78
+ const organizationValidation = OrganizationSchema.strip().safeParse(deletedOrganization);
79
+ if (organizationValidation.success) {
80
+ await repos.organizations.update(deletedOrganization, auditContext);
81
+ }
82
+ // 5.2.1. Do NOT modify memberships of owned organizations
83
+ // Rationale: Same as DeleteOrganization use case - preserving membership state
84
+ // allows future restore to distinguish between:
85
+ // - Active memberships (deletedAt=null) → should be restored
86
+ // - Explicitly deleted memberships (deletedAt set) → should NOT be restored
87
+ // - Voluntary departures (leftAt set) → historical record preserved
88
+ }
89
+ }
90
+ // 5.3. Soft delete all organization memberships for this user in organizations where they are NOT the owner
91
+ // NOTE: Here we DO set both leftAt AND deletedAt because:
92
+ // - leftAt: the user is conceptually "leaving" all organizations they're part of
93
+ // - deletedAt: the membership should be soft-deleted since the user no longer exists
94
+ const userMemberships = await this.adapters.persistence.organizationMembershipRepository.findByUser(existingUser.id);
95
+ const ownedOrganizationIds = new Set(ownedOrganizations.map((t) => t.id));
96
+ for (const membership of userMemberships) {
97
+ // Skip memberships in owned organizations (those organizations were deleted in step 5.2)
98
+ if (ownedOrganizationIds.has(membership.organizationId)) {
99
+ continue;
100
+ }
101
+ if (!membership.deletedAt && !membership.leftAt) {
102
+ const deletedMembership = {
103
+ ...membership,
104
+ leftAt: now, // User is leaving (being deleted)
105
+ deletedAt: now,
106
+ updatedAt: now
107
+ };
108
+ // Validate the membership data
109
+ const membershipValidation = OrganizationMembershipSchema.strip().safeParse(deletedMembership);
110
+ if (membershipValidation.success) {
111
+ await repos.organizationMemberships.update(deletedMembership, auditContext);
112
+ }
113
+ }
114
+ }
115
+ });
116
+ // 6. Return deleted user
117
+ return Result.ok(deletedUser);
118
+ }
119
+ }
120
+ //# sourceMappingURL=DeleteUser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeleteUser.js","sourceRoot":"","sources":["../../../../src/users/use-cases/delete-user/DeleteUser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { GetUserInput, IGetUser, OperationContext, ToolkitOptions, User } from '@multitenantkit/domain-contracts';
2
+ import { type Adapters, type DomainError } from '@multitenantkit/domain-contracts';
3
+ import type { Result } from '../../../shared/result/Result';
4
+ import { BaseUseCase } from '../../../shared/use-case';
5
+ /**
6
+ * GetUser use case
7
+ * Handles the business logic for retrieving a user by ID
8
+ *
9
+ * Generic support for custom fields:
10
+ * @template TUserCustomFields - Custom fields added to User
11
+ * @template TOrganizationCustomFields - Custom fields added to Organization (for toolkit options compatibility)
12
+ * @template TOrganizationMembershipCustomFields - Custom fields added to OrganizationMembership (for toolkit options compatibility)
13
+ */
14
+ export declare class GetUser<TUserCustomFields = {}, TOrganizationCustomFields = {}, TOrganizationMembershipCustomFields = {}> extends BaseUseCase<GetUserInput, User & TUserCustomFields, DomainError, TUserCustomFields, TOrganizationCustomFields, TOrganizationMembershipCustomFields> implements IGetUser {
15
+ constructor(adapters: Adapters<TUserCustomFields, TOrganizationCustomFields, TOrganizationMembershipCustomFields>, toolkitOptions?: ToolkitOptions<TUserCustomFields, TOrganizationCustomFields, TOrganizationMembershipCustomFields>);
16
+ protected executeBusinessLogic(input: GetUserInput, _context: OperationContext): Promise<Result<User & TUserCustomFields, DomainError>>;
17
+ }
18
+ //# sourceMappingURL=GetUser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GetUser.d.ts","sourceRoot":"","sources":["../../../../src/users/use-cases/get-user/GetUser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,YAAY,EACZ,QAAQ,EACR,gBAAgB,EAChB,cAAc,EACd,IAAI,EACP,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACH,KAAK,QAAQ,EACb,KAAK,WAAW,EAGnB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD;;;;;;;;GAQG;AACH,qBAAa,OAAO,CAEZ,iBAAiB,GAAG,EAAE,EAEtB,yBAAyB,GAAG,EAAE,EAE9B,mCAAmC,GAAG,EAAE,CAE5C,SAAQ,WAAW,CACf,YAAY,EACZ,IAAI,GAAG,iBAAiB,EACxB,WAAW,EACX,iBAAiB,EACjB,yBAAyB,EACzB,mCAAmC,CAEvC,YAAW,QAAQ;gBAGf,QAAQ,EAAE,QAAQ,CACd,iBAAiB,EACjB,yBAAyB,EACzB,mCAAmC,CACtC,EACD,cAAc,CAAC,EAAE,cAAc,CAC3B,iBAAiB,EACjB,yBAAyB,EACzB,mCAAmC,CACtC;cAsBW,oBAAoB,CAChC,KAAK,EAAE,YAAY,EACnB,QAAQ,EAAE,gBAAgB,GAC3B,OAAO,CAAC,MAAM,CAAC,IAAI,GAAG,iBAAiB,EAAE,WAAW,CAAC,CAAC;CAO5D"}
@@ -0,0 +1,29 @@
1
+ import { GetUserInputSchema, UserSchema } from '@multitenantkit/domain-contracts';
2
+ import { BaseUseCase } from '../../../shared/use-case';
3
+ /**
4
+ * GetUser use case
5
+ * Handles the business logic for retrieving a user by ID
6
+ *
7
+ * Generic support for custom fields:
8
+ * @template TUserCustomFields - Custom fields added to User
9
+ * @template TOrganizationCustomFields - Custom fields added to Organization (for toolkit options compatibility)
10
+ * @template TOrganizationMembershipCustomFields - Custom fields added to OrganizationMembership (for toolkit options compatibility)
11
+ */
12
+ export class GetUser extends BaseUseCase {
13
+ constructor(adapters, toolkitOptions) {
14
+ // Extract custom schema from toolkit options
15
+ const customSchema = toolkitOptions?.users?.customFields?.customSchema;
16
+ // Extend base schema with custom fields if provided
17
+ const outputSchema = (customSchema
18
+ ? UserSchema.merge(customSchema)
19
+ : UserSchema);
20
+ super('user-getUser', adapters, toolkitOptions, GetUserInputSchema, outputSchema, 'Failed to retrieve user');
21
+ }
22
+ async executeBusinessLogic(input, _context) {
23
+ // input.userId is actually an externalId from auth provider
24
+ // Use helper to map externalId -> User entity
25
+ const userResult = await this.getUserFromExternalId(input.principalExternalId);
26
+ return userResult;
27
+ }
28
+ }
29
+ //# sourceMappingURL=GetUser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GetUser.js","sourceRoot":"","sources":["../../../../src/users/use-cases/get-user/GetUser.ts"],"names":[],"mappings":"AAOA,OAAO,EAGH,kBAAkB,EAClB,UAAU,EACb,MAAM,kCAAkC,CAAC;AAG1C,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD;;;;;;;;GAQG;AACH,MAAM,OAAO,OAQT,SAAQ,WAOP;IAGD,YACI,QAIC,EACD,cAIC;QAED,6CAA6C;QAC7C,MAAM,YAAY,GAAG,cAAc,EAAE,KAAK,EAAE,YAAY,EAAE,YAE3C,CAAC;QAEhB,oDAAoD;QACpD,MAAM,YAAY,GAAG,CAAC,YAAY;YAC9B,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,YAAY,CAAC;YAChC,CAAC,CAAC,UAAU,CAAmD,CAAC;QAEpE,KAAK,CACD,cAAc,EACd,QAAQ,EACR,cAAc,EACd,kBAAkB,EAClB,YAAY,EACZ,yBAAyB,CAC5B,CAAC;IACN,CAAC;IAES,KAAK,CAAC,oBAAoB,CAChC,KAAmB,EACnB,QAA0B;QAE1B,4DAA4D;QAC5D,8CAA8C;QAC9C,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QAE/E,OAAO,UAAU,CAAC;IACtB,CAAC;CACJ"}
@@ -0,0 +1,6 @@
1
+ export { CreateUser } from './create-user/CreateUser';
2
+ export { DeleteUser } from './delete-user/DeleteUser';
3
+ export { GetUser } from './get-user/GetUser';
4
+ export { ListUserOrganizations } from './list-user-organizations/ListUserOrganizations';
5
+ export { UpdateUser } from './update-user/UpdateUser';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/users/use-cases/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,iDAAiD,CAAC;AACxF,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,8 @@
1
+ // Use Cases
2
+ export { CreateUser } from './create-user/CreateUser';
3
+ export { DeleteUser } from './delete-user/DeleteUser';
4
+ export { GetUser } from './get-user/GetUser';
5
+ export { ListUserOrganizations } from './list-user-organizations/ListUserOrganizations';
6
+ export { UpdateUser } from './update-user/UpdateUser';
7
+ // DTOs
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/users/use-cases/index.ts"],"names":[],"mappings":"AAAA,YAAY;AACZ,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,qBAAqB,EAAE,MAAM,iDAAiD,CAAC;AACxF,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD,OAAO"}
@@ -0,0 +1,20 @@
1
+ import type { Adapters, ToolkitOptions } from '@multitenantkit/domain-contracts';
2
+ import { type Organization } from '@multitenantkit/domain-contracts/organizations';
3
+ import type { OperationContext } from '@multitenantkit/domain-contracts/shared';
4
+ import { type DomainError } from '@multitenantkit/domain-contracts/shared/errors/index';
5
+ import type { IListUserOrganizations, ListUserOrganizationsInput } from '@multitenantkit/domain-contracts/users';
6
+ import { Result } from '../../../shared/result/Result';
7
+ import { BaseUseCase } from '../../../shared/use-case';
8
+ /**
9
+ * ListUserOrganizations use case
10
+ * Handles business logic for listing organizations where user is a member or owner
11
+ *
12
+ * Generic support for custom fields:
13
+ * @template TUserCustomFields - Custom fields added to User
14
+ * @template TOrganizationCustomFields - Custom fields added to Organization
15
+ */
16
+ export declare class ListUserOrganizations<TUserCustomFields = {}, TOrganizationCustomFields = {}, TOrganizationMembershipCustomFields = {}> extends BaseUseCase<ListUserOrganizationsInput, Array<Organization & TOrganizationCustomFields>, DomainError, TUserCustomFields, TOrganizationCustomFields, TOrganizationMembershipCustomFields> implements IListUserOrganizations {
17
+ constructor(adapters: Adapters<TUserCustomFields, TOrganizationCustomFields, TOrganizationMembershipCustomFields>, toolkitOptions?: ToolkitOptions<TUserCustomFields, TOrganizationCustomFields, TOrganizationMembershipCustomFields>);
18
+ protected executeBusinessLogic(input: ListUserOrganizationsInput, _context: OperationContext): Promise<Result<Array<Organization & TOrganizationCustomFields>, DomainError>>;
19
+ }
20
+ //# sourceMappingURL=ListUserOrganizations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListUserOrganizations.d.ts","sourceRoot":"","sources":["../../../../src/users/use-cases/list-user-organizations/ListUserOrganizations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AACjF,OAAO,EACH,KAAK,YAAY,EAEpB,MAAM,gDAAgD,CAAC;AACxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAChF,OAAO,EACH,KAAK,WAAW,EAEnB,MAAM,sDAAsD,CAAC;AAC9D,OAAO,KAAK,EACR,sBAAsB,EACtB,0BAA0B,EAC7B,MAAM,wCAAwC,CAAC;AAMhD,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD;;;;;;;GAOG;AACH,qBAAa,qBAAqB,CAE1B,iBAAiB,GAAG,EAAE,EAEtB,yBAAyB,GAAG,EAAE,EAE9B,mCAAmC,GAAG,EAAE,CAE5C,SAAQ,WAAW,CACf,0BAA0B,EAC1B,KAAK,CAAC,YAAY,GAAG,yBAAyB,CAAC,EAC/C,WAAW,EACX,iBAAiB,EACjB,yBAAyB,EACzB,mCAAmC,CAEvC,YAAW,sBAAsB;gBAG7B,QAAQ,EAAE,QAAQ,CACd,iBAAiB,EACjB,yBAAyB,EACzB,mCAAmC,CACtC,EACD,cAAc,CAAC,EAAE,cAAc,CAC3B,iBAAiB,EACjB,yBAAyB,EACzB,mCAAmC,CACtC;cAwBW,oBAAoB,CAChC,KAAK,EAAE,0BAA0B,EACjC,QAAQ,EAAE,gBAAgB,GAC3B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG,yBAAyB,CAAC,EAAE,WAAW,CAAC,CAAC;CA0DnF"}
@@ -0,0 +1,68 @@
1
+ import { OrganizationSchema } from '@multitenantkit/domain-contracts/organizations';
2
+ import { ValidationError } from '@multitenantkit/domain-contracts/shared/errors/index';
3
+ import { ListUserOrganizationsInputSchema, ListUserOrganizationsOutputSchema } from '@multitenantkit/domain-contracts/users';
4
+ import { z } from 'zod';
5
+ import { Result } from '../../../shared/result/Result';
6
+ import { BaseUseCase } from '../../../shared/use-case';
7
+ /**
8
+ * ListUserOrganizations use case
9
+ * Handles business logic for listing organizations where user is a member or owner
10
+ *
11
+ * Generic support for custom fields:
12
+ * @template TUserCustomFields - Custom fields added to User
13
+ * @template TOrganizationCustomFields - Custom fields added to Organization
14
+ */
15
+ export class ListUserOrganizations extends BaseUseCase {
16
+ constructor(adapters, toolkitOptions) {
17
+ // Extract organization custom schema from toolkit options if provided
18
+ const customSchema = toolkitOptions?.organizations?.customFields?.customSchema;
19
+ // Extend base schema with custom fields if provided
20
+ const outputSchema = (customSchema
21
+ ? z.array(OrganizationSchema.merge(customSchema))
22
+ : ListUserOrganizationsOutputSchema);
23
+ super('user-listUserOrganizations', adapters, toolkitOptions, ListUserOrganizationsInputSchema, outputSchema, 'Failed to list user organizations');
24
+ }
25
+ async executeBusinessLogic(input, _context) {
26
+ // 1. Get user by externalId
27
+ const getUserResult = await this.getUserFromExternalId(input.principalExternalId);
28
+ if (getUserResult.isFailure) {
29
+ return Result.fail(getUserResult.getError());
30
+ }
31
+ const user = getUserResult.getValue();
32
+ try {
33
+ // 2. Get all user memberships (active and non-left) using internal user ID
34
+ const membershipsDB = await this.adapters.persistence.organizationMembershipRepository.findByUser(user.id);
35
+ const activeMemberships = membershipsDB.filter((m) => m.joinedAt && !m.leftAt && !m.deletedAt);
36
+ // 3. Get organizations for active memberships
37
+ const organizationIds = activeMemberships.map((m) => m.organizationId);
38
+ const organizations = [];
39
+ for (const organizationId of organizationIds) {
40
+ const organizationDB = await this.adapters.persistence.organizationRepository.findById(organizationId);
41
+ if (organizationDB) {
42
+ const organization = organizationDB;
43
+ // Only include organizations that are not deleted
44
+ if (organization && !organization.deletedAt) {
45
+ organizations.push(organization);
46
+ }
47
+ }
48
+ }
49
+ // 4. Also include organizations where user is owner (even without explicit membership)
50
+ const ownedOrganizations = await this.adapters.persistence.organizationRepository.findByOwner(user.id);
51
+ // Merge and deduplicate organizations
52
+ const allOrganizations = [...organizations];
53
+ for (const ownedOrganization of ownedOrganizations) {
54
+ if (!allOrganizations.some((t) => t.id === ownedOrganization.id)) {
55
+ allOrganizations.push(ownedOrganization);
56
+ }
57
+ }
58
+ // 5. Return raw data; BaseUseCase will parse with output schema
59
+ return Result.ok(allOrganizations);
60
+ }
61
+ catch (error) {
62
+ return Result.fail(new ValidationError('Failed to list user organizations', undefined, {
63
+ originalError: error
64
+ }));
65
+ }
66
+ }
67
+ }
68
+ //# sourceMappingURL=ListUserOrganizations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListUserOrganizations.js","sourceRoot":"","sources":["../../../../src/users/use-cases/list-user-organizations/ListUserOrganizations.ts"],"names":[],"mappings":"AACA,OAAO,EAEH,kBAAkB,EACrB,MAAM,gDAAgD,CAAC;AAExD,OAAO,EAEH,eAAe,EAClB,MAAM,sDAAsD,CAAC;AAK9D,OAAO,EACH,gCAAgC,EAChC,iCAAiC,EACpC,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD;;;;;;;GAOG;AACH,MAAM,OAAO,qBAQT,SAAQ,WAOP;IAGD,YACI,QAIC,EACD,cAIC;QAED,sEAAsE;QACtE,MAAM,YAAY,GAAG,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,YAEnD,CAAC;QAEhB,oDAAoD;QACpD,MAAM,YAAY,GAAG,CAAC,YAAY;YAC9B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;YACjD,CAAC,CAAC,iCAAiC,CAEtC,CAAC;QAEF,KAAK,CACD,4BAA4B,EAC5B,QAAQ,EACR,cAAc,EACd,gCAAgC,EAChC,YAAY,EACZ,mCAAmC,CACtC,CAAC;IACN,CAAC;IAES,KAAK,CAAC,oBAAoB,CAChC,KAAiC,EACjC,QAA0B;QAE1B,4BAA4B;QAC5B,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QAClF,IAAI,aAAa,CAAC,SAAS,EAAE,CAAC;YAC1B,OAAO,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,CAAC,CAAC;QACjD,CAAC;QACD,MAAM,IAAI,GAAG,aAAa,CAAC,QAAQ,EAAE,CAAC;QAEtC,IAAI,CAAC;YACD,2EAA2E;YAC3E,MAAM,aAAa,GACf,MAAM,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,gCAAgC,CAAC,UAAU,CACvE,IAAI,CAAC,EAAE,CACV,CAAC;YACN,MAAM,iBAAiB,GAAG,aAAa,CAAC,MAAM,CAC1C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,SAAS,CACjD,CAAC;YAEF,8CAA8C;YAC9C,MAAM,eAAe,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC;YACvE,MAAM,aAAa,GAAG,EAAqD,CAAC;YAE5E,KAAK,MAAM,cAAc,IAAI,eAAe,EAAE,CAAC;gBAC3C,MAAM,cAAc,GAChB,MAAM,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,sBAAsB,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;gBACpF,IAAI,cAAc,EAAE,CAAC;oBACjB,MAAM,YAAY,GAAG,cAA0D,CAAC;oBAChF,kDAAkD;oBAClD,IAAI,YAAY,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC;wBAC1C,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;oBACrC,CAAC;gBACL,CAAC;YACL,CAAC;YAED,uFAAuF;YACvF,MAAM,kBAAkB,GACpB,MAAM,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,sBAAsB,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAEhF,sCAAsC;YACtC,MAAM,gBAAgB,GAAG,CAAC,GAAG,aAAa,CAAC,CAAC;YAC5C,KAAK,MAAM,iBAAiB,IAAI,kBAAkB,EAAE,CAAC;gBACjD,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,iBAAiB,CAAC,EAAE,CAAC,EAAE,CAAC;oBAC/D,gBAAgB,CAAC,IAAI,CACjB,iBAA6D,CAChE,CAAC;gBACN,CAAC;YACL,CAAC;YAED,gEAAgE;YAChE,OAAO,MAAM,CAAC,EAAE,CAAC,gBAAmE,CAAC,CAAC;QAC1F,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,OAAO,MAAM,CAAC,IAAI,CACd,IAAI,eAAe,CAAC,mCAAmC,EAAE,SAAS,EAAE;gBAChE,aAAa,EAAE,KAAK;aACvB,CAAC,CACL,CAAC;QACN,CAAC;IACL,CAAC;CACJ"}
@@ -0,0 +1,19 @@
1
+ import type { IUpdateUser, OperationContext, ToolkitOptions, UpdateUserInput, User } from '@multitenantkit/domain-contracts';
2
+ import { type Adapters, type ConflictError, type NotFoundError, ValidationError } from '@multitenantkit/domain-contracts';
3
+ import { Result } from '../../../shared/result';
4
+ import { BaseUseCase } from '../../../shared/use-case';
5
+ /**
6
+ * UpdateUser use case
7
+ * Handles the business logic for updating a user's profile
8
+ *
9
+ * Generic support for custom fields:
10
+ * @template TUserCustomFields - Custom fields added to User
11
+ * @template TOrganizationCustomFields - Custom fields added to Organization (for toolkit options compatibility)
12
+ * @template TOrganizationMembershipCustomFields - Custom fields added to OrganizationMembership (for toolkit options compatibility)
13
+ */
14
+ export declare class UpdateUser<TUserCustomFields = {}, TOrganizationCustomFields = {}, TOrganizationMembershipCustomFields = {}> extends BaseUseCase<UpdateUserInput & TUserCustomFields, User & TUserCustomFields, ValidationError | NotFoundError | ConflictError, TUserCustomFields, TOrganizationCustomFields, TOrganizationMembershipCustomFields> implements IUpdateUser {
15
+ private readonly customSchema?;
16
+ constructor(adapters: Adapters<TUserCustomFields, TOrganizationCustomFields, TOrganizationMembershipCustomFields>, toolkitOptions?: ToolkitOptions<TUserCustomFields, TOrganizationCustomFields, TOrganizationMembershipCustomFields>);
17
+ protected executeBusinessLogic(input: UpdateUserInput & TUserCustomFields, context: OperationContext): Promise<Result<User & TUserCustomFields, ValidationError | NotFoundError | ConflictError>>;
18
+ }
19
+ //# sourceMappingURL=UpdateUser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UpdateUser.d.ts","sourceRoot":"","sources":["../../../../src/users/use-cases/update-user/UpdateUser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,WAAW,EACX,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,IAAI,EACP,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACH,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,aAAa,EAGlB,eAAe,EAClB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAkB,MAAM,0BAA0B,CAAC;AAEvE;;;;;;;;GAQG;AACH,qBAAa,UAAU,CAEf,iBAAiB,GAAG,EAAE,EAEtB,yBAAyB,GAAG,EAAE,EAE9B,mCAAmC,GAAG,EAAE,CAE5C,SAAQ,WAAW,CACf,eAAe,GAAG,iBAAiB,EACnC,IAAI,GAAG,iBAAiB,EACxB,eAAe,GAAG,aAAa,GAAG,aAAa,EAC/C,iBAAiB,EACjB,yBAAyB,EACzB,mCAAmC,CAEvC,YAAW,WAAW;IAEtB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAmB;gBAG7C,QAAQ,EAAE,QAAQ,CACd,iBAAiB,EACjB,yBAAyB,EACzB,mCAAmC,CACtC,EACD,cAAc,CAAC,EAAE,cAAc,CAC3B,iBAAiB,EACjB,yBAAyB,EACzB,mCAAmC,CACtC;cAuCW,oBAAoB,CAChC,KAAK,EAAE,eAAe,GAAG,iBAAiB,EAC1C,OAAO,EAAE,gBAAgB,GAC1B,OAAO,CAAC,MAAM,CAAC,IAAI,GAAG,iBAAiB,EAAE,eAAe,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;CAmDhG"}
@@ -0,0 +1,73 @@
1
+ import { UpdateUserInputSchema, UserSchema, ValidationError } from '@multitenantkit/domain-contracts';
2
+ import { z } from 'zod';
3
+ import { Result } from '../../../shared/result';
4
+ import { BaseUseCase, UseCaseHelpers } from '../../../shared/use-case';
5
+ /**
6
+ * UpdateUser use case
7
+ * Handles the business logic for updating a user's profile
8
+ *
9
+ * Generic support for custom fields:
10
+ * @template TUserCustomFields - Custom fields added to User
11
+ * @template TOrganizationCustomFields - Custom fields added to Organization (for toolkit options compatibility)
12
+ * @template TOrganizationMembershipCustomFields - Custom fields added to OrganizationMembership (for toolkit options compatibility)
13
+ */
14
+ export class UpdateUser extends BaseUseCase {
15
+ customSchema;
16
+ constructor(adapters, toolkitOptions) {
17
+ // Extract custom schema from toolkit options
18
+ const customSchema = toolkitOptions?.users?.customFields?.customSchema;
19
+ // Extend base input schema with custom fields if provided
20
+ // Using .and() instead of .merge() because UpdateUserInputSchema uses .refine() (ZodEffects)
21
+ const inputSchema = (customSchema
22
+ ? UpdateUserInputSchema.and(customSchema.partial())
23
+ : UpdateUserInputSchema).refine((data) => {
24
+ // At least one field must be provided
25
+ return Object.keys(data).length > 0;
26
+ }, {
27
+ message: 'At least one field must be provided for update',
28
+ path: ['root']
29
+ });
30
+ super('user-updateUser', adapters, toolkitOptions, inputSchema, z.any(), // No validation needed for output - domain entities are already type-safe
31
+ 'Failed to update user profile');
32
+ // Store custom schema for use in executeBusinessLogic
33
+ this.customSchema = customSchema;
34
+ }
35
+ async executeBusinessLogic(input, context) {
36
+ // 2. Get existing user by externalId
37
+ const getUserResult = await this.getUserFromExternalId(input.principalExternalId);
38
+ if (getUserResult.isFailure) {
39
+ return Result.fail(getUserResult.getError());
40
+ }
41
+ const existingUser = getUserResult.getValue();
42
+ // 3. Build updated user data
43
+ const now = this.adapters.system.clock.now();
44
+ // Filter out undefined values from input to preserve existing values
45
+ const definedInputFields = Object.fromEntries(Object.entries(input).filter(([_, value]) => value !== undefined));
46
+ // Merge existing user with defined input fields
47
+ const updatedUserData = {
48
+ ...existingUser,
49
+ ...definedInputFields,
50
+ updatedAt: now
51
+ };
52
+ // Validate the merged data with custom schema if provided
53
+ const validationSchema = this.customSchema
54
+ ? UserSchema.strip().and(this.customSchema.strip())
55
+ : UserSchema.strip();
56
+ const validationResult = validationSchema.safeParse(updatedUserData);
57
+ if (!validationResult.success) {
58
+ const firstError = validationResult.error.errors[0];
59
+ return Result.fail(new ValidationError(firstError.message, firstError.path.join('.')));
60
+ }
61
+ // Use validated and potentially transformed data from Zod
62
+ const updatedUser = validationResult.data;
63
+ // 4. Persist the updated user using Unit of Work (transaction) with audit context
64
+ const auditContext = UseCaseHelpers.enrichAuditContext(context, 'UPDATE_USER_PROFILE', undefined // Users don't belong directly to a organization
65
+ );
66
+ await this.adapters.persistence.uow.transaction(async (repos) => {
67
+ await repos.users.update(updatedUser, auditContext);
68
+ });
69
+ // 5. Return updated user
70
+ return Result.ok(updatedUser);
71
+ }
72
+ }
73
+ //# sourceMappingURL=UpdateUser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UpdateUser.js","sourceRoot":"","sources":["../../../../src/users/use-cases/update-user/UpdateUser.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,81 @@
1
+ {
2
+ "name": "@multitenantkit/domain",
3
+ "version": "0.1.1",
4
+ "type": "module",
5
+ "description": "Core domain logic and use cases for MultiTenantKit - Pure business logic layer",
6
+ "keywords": [
7
+ "multitenantkit",
8
+ "saas",
9
+ "saas-toolkit",
10
+ "multi-tenant",
11
+ "multitenancy",
12
+ "organization-management",
13
+ "team-management",
14
+ "user-management",
15
+ "organizations",
16
+ "teams",
17
+ "users",
18
+ "business-logic",
19
+ "typescript",
20
+ "clean-architecture"
21
+ ],
22
+ "author": "",
23
+ "license": "MIT",
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "https://github.com/multitenantkit/multitenantkit.git",
27
+ "directory": "packages/domain"
28
+ },
29
+ "bugs": {
30
+ "url": "https://github.com/multitenantkit/multitenantkit/issues"
31
+ },
32
+ "homepage": "https://github.com/multitenantkit/multitenantkit#readme",
33
+ "publishConfig": {
34
+ "access": "public"
35
+ },
36
+ "main": "./dist/index.js",
37
+ "types": "./dist/index.d.ts",
38
+ "files": [
39
+ "dist",
40
+ "README.md"
41
+ ],
42
+ "exports": {
43
+ ".": {
44
+ "types": "./dist/index.d.ts",
45
+ "default": "./dist/index.js"
46
+ },
47
+ "./users": {
48
+ "types": "./dist/users/index.d.ts",
49
+ "default": "./dist/users/index.js"
50
+ },
51
+ "./organizations": {
52
+ "types": "./dist/organizations/index.d.ts",
53
+ "default": "./dist/organizations/index.js"
54
+ },
55
+ "./organization-memberships": {
56
+ "types": "./dist/organization-memberships/index.d.ts",
57
+ "default": "./dist/organization-memberships/index.js"
58
+ },
59
+ "./shared": {
60
+ "types": "./dist/shared/index.d.ts",
61
+ "default": "./dist/shared/index.js"
62
+ }
63
+ },
64
+ "scripts": {
65
+ "build": "tsc --build",
66
+ "dev": "tsc --build --watch",
67
+ "clean": "rm -rf dist",
68
+ "type-check": "tsc --noEmit",
69
+ "test": "vitest run",
70
+ "test:watch": "vitest",
71
+ "test:coverage": "vitest run --coverage"
72
+ },
73
+ "dependencies": {
74
+ "@multitenantkit/domain-contracts": "^0.1.1",
75
+ "zod": "^3.22.4"
76
+ },
77
+ "devDependencies": {
78
+ "@types/node": "^20.0.0",
79
+ "typescript": "^5.0.0"
80
+ }
81
+ }