@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,366 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { AbortedError, InfrastructureError, NotFoundError, ValidationError } from '@multitenantkit/domain-contracts';
3
+ import { Result } from '../result/Result';
4
+ /**
5
+ * Base class for all use cases following a consistent execution pipeline.
6
+ *
7
+ * Provides automatic:
8
+ * - Input validation with Zod schemas
9
+ * - Output parsing/transformation
10
+ * - Error handling and wrapping
11
+ * - Hook lifecycle management with abort support
12
+ * - Consistent structure across all use cases
13
+ *
14
+ * @template TInput - Input type for the use case
15
+ * @template TOutput - Output type returned by the use case
16
+ * @template TError - Domain error types that can be returned
17
+ * @template TCustomFields - Custom fields extension for entities
18
+ * @template TOrganizationCustomFields - Custom fields for organizations (toolkit options compatibility)
19
+ * @template TOrganizationMembershipCustomFields - Custom fields for organization memberships (toolkit options compatibility)
20
+ */
21
+ export class BaseUseCase {
22
+ adapters;
23
+ toolkitOptions;
24
+ inputSchema;
25
+ outputSchema;
26
+ errorMessage;
27
+ /**
28
+ * Abort state tracking
29
+ * These track whether a hook has requested abort and the reason
30
+ */
31
+ abortRequested = false;
32
+ abortReason = '';
33
+ /**
34
+ * Shared state object for hooks
35
+ * Reset at the start of each execution
36
+ */
37
+ sharedState = {};
38
+ /**
39
+ * Step results object for hooks
40
+ * Stores results from each pipeline step
41
+ */
42
+ stepResults = {};
43
+ /**
44
+ * Execution ID for tracking
45
+ * Generated at the start of each execution
46
+ */
47
+ executionId = '';
48
+ /**
49
+ * Use case name in format "entity-useCaseName"
50
+ * Example: "user-updateUser", "organization-createOrganization"
51
+ * This helps prevent name collisions between different entities
52
+ */
53
+ useCaseName;
54
+ constructor(useCaseName, adapters, toolkitOptions, inputSchema, outputSchema, errorMessage) {
55
+ this.adapters = adapters;
56
+ this.toolkitOptions = toolkitOptions;
57
+ this.inputSchema = inputSchema;
58
+ this.outputSchema = outputSchema;
59
+ this.errorMessage = errorMessage;
60
+ this.useCaseName = useCaseName;
61
+ }
62
+ /**
63
+ * Initialize execution state for a new execution
64
+ * Resets abort state, shared state, step results, and generates execution ID
65
+ */
66
+ initializeExecutionState() {
67
+ this.abortRequested = false;
68
+ this.abortReason = '';
69
+ this.sharedState = {};
70
+ this.stepResults = {};
71
+ this.executionId = randomUUID();
72
+ }
73
+ /**
74
+ * Create abort function for hook context
75
+ * When called, sets abort state which will be checked after each hook
76
+ *
77
+ * @returns Abort function that hooks can call
78
+ */
79
+ createAbortFunction() {
80
+ return (reason) => {
81
+ this.abortRequested = true;
82
+ this.abortReason = reason;
83
+ };
84
+ }
85
+ /**
86
+ * Check if abort was requested
87
+ * Should be called after each hook execution
88
+ *
89
+ * @returns true if abort was requested
90
+ */
91
+ checkAborted() {
92
+ return this.abortRequested;
93
+ }
94
+ /**
95
+ * Build HookContext object for passing to hooks
96
+ * Provides immutable access to input/stepResults and mutable shared state
97
+ *
98
+ * @param input - Original input to the use case
99
+ * @param context - Operation context
100
+ * @returns HookContext object
101
+ */
102
+ buildHookContext(input, context) {
103
+ return {
104
+ executionId: this.executionId,
105
+ useCaseName: this.useCaseName,
106
+ input: input, // Readonly via type
107
+ stepResults: this.stepResults, // Readonly via type
108
+ shared: this.sharedState,
109
+ adapters: this.adapters,
110
+ context: context,
111
+ abort: this.createAbortFunction()
112
+ };
113
+ }
114
+ /**
115
+ * Get configured hooks for this use case from ToolkitOptions
116
+ *
117
+ * @returns UseCaseHooks if configured, undefined otherwise
118
+ */
119
+ getHooksConfig() {
120
+ if (!this.toolkitOptions?.useCaseHooks) {
121
+ return undefined;
122
+ }
123
+ const useCaseName = this.constructor.name;
124
+ return this.toolkitOptions.useCaseHooks[useCaseName];
125
+ }
126
+ /**
127
+ * Execute a hook safely with error handling and metrics logging
128
+ * If hook throws an error, it propagates (hooks can abort execution)
129
+ *
130
+ * @param hookFn - Hook function to execute
131
+ * @param ctx - HookContext to pass to the hook
132
+ * @param hookName - Name of the hook for logging purposes
133
+ */
134
+ async executeHook(hookFn, ctx, hookName) {
135
+ // 🔥 Fire-and-forget: Log hook execution (without await)
136
+ this.logMetrics(hookName, ctx);
137
+ if (!hookFn) {
138
+ return;
139
+ }
140
+ await hookFn(ctx);
141
+ }
142
+ /**
143
+ * Log hook execution metrics (fire-and-forget)
144
+ * Errors are silently caught to not affect execution flow
145
+ *
146
+ * @param hookName - Name of the hook being executed
147
+ * @param ctx - Hook context (will be filtered for PII)
148
+ */
149
+ logMetrics(hookName, ctx) {
150
+ try {
151
+ // Fire-and-forget (no await)
152
+ this.adapters.observability
153
+ ?.logHookExecution({
154
+ requestId: ctx.context.requestId || 'unknown',
155
+ useCaseName: this.useCaseName,
156
+ hookName,
157
+ executionId: ctx.executionId,
158
+ timestamp: new Date(),
159
+ params: ctx
160
+ })
161
+ .catch(() => {
162
+ // Silent fail - metrics should never break execution
163
+ });
164
+ }
165
+ catch {
166
+ // Silent fail - if extracting data fails, don't break execution
167
+ }
168
+ }
169
+ /**
170
+ * Get user from external ID (auth provider ID)
171
+ *
172
+ * This helper maps the external auth provider ID to the internal User entity.
173
+ * It's used by use cases that operate on the authenticated user.
174
+ *
175
+ * @param externalId - Auth provider user ID (from Principal.authProviderId)
176
+ * @returns User entity with internal ID
177
+ * @throws NotFoundError if user doesn't exist
178
+ *
179
+ * @example
180
+ * ```typescript
181
+ * // In a use case
182
+ * const user = await this.getUserFromExternalId(context.principal.authProviderId);
183
+ * ```
184
+ */
185
+ async getUserFromExternalId(externalId) {
186
+ if (!this.adapters.persistence.userRepository) {
187
+ return Result.fail(new InfrastructureError('UserRepository is required for getUserFromExternalId'));
188
+ }
189
+ const user = await this.adapters.persistence.userRepository.findByExternalId(externalId);
190
+ if (!user) {
191
+ return Result.fail(new NotFoundError('User', externalId, {
192
+ message: 'User not found with the provided external ID from auth provider. Please ensure the user is registered in the system.'
193
+ }));
194
+ }
195
+ return Result.ok(user);
196
+ }
197
+ /**
198
+ * Main execution method - defines the pipeline with hook integration
199
+ *
200
+ * Pipeline stages:
201
+ * 1. Initialize execution state
202
+ * 2. onStart hook
203
+ * 3. Validate input with schema
204
+ * 4. afterValidation hook
205
+ * 5. Authorize (optional)
206
+ * 6. beforeExecution hook (renamed from afterAuthorization)
207
+ * 7. Execute business logic
208
+ * 8. afterExecution hook
209
+ * 9. Parse output with schema
210
+ * 10. onError hook (if error occurs)
211
+ * 11. onAbort hook (if abort requested)
212
+ * 12. onFinally hook (always executes)
213
+ */
214
+ async execute(input, context) {
215
+ // Initialize execution state
216
+ this.initializeExecutionState();
217
+ const hooks = this.getHooksConfig();
218
+ let result = await this.withErrorHandling(async () => {
219
+ // Build hook context (will be updated as execution progresses)
220
+ const hookCtx = this.buildHookContext(input, context);
221
+ // HOOK 1: onStart - before validation
222
+ await this.executeHook(hooks?.onStart, hookCtx, 'onStart');
223
+ if (this.checkAborted()) {
224
+ return Result.fail(new AbortedError(this.abortReason));
225
+ }
226
+ // 1. Validate input
227
+ const validatedInput = await this.validateInput(input);
228
+ if (validatedInput.isFailure) {
229
+ return validatedInput;
230
+ }
231
+ // Store validated input in step results
232
+ this.stepResults.validatedInput = validatedInput.getValue();
233
+ // HOOK 2: afterValidation - after successful validation
234
+ await this.executeHook(hooks?.afterValidation, hookCtx, 'afterValidation');
235
+ if (this.checkAborted()) {
236
+ return Result.fail(new AbortedError(this.abortReason));
237
+ }
238
+ // 2. Authorize (optional)
239
+ const authResult = await this.authorize(validatedInput.getValue(), context);
240
+ if (authResult.isFailure) {
241
+ return authResult;
242
+ }
243
+ // Store authorization result in step results
244
+ this.stepResults.authorized = true;
245
+ // HOOK 3: beforeExecution - after successful authorization, before business logic
246
+ await this.executeHook(hooks?.beforeExecution, hookCtx, 'beforeExecution');
247
+ if (this.checkAborted()) {
248
+ return Result.fail(new AbortedError(this.abortReason));
249
+ }
250
+ // 3. Execute business logic
251
+ const businessResult = await this.executeBusinessLogic(validatedInput.getValue(), context);
252
+ if (businessResult.isFailure) {
253
+ return businessResult;
254
+ }
255
+ // Store business output in step results
256
+ this.stepResults.output = businessResult.getValue();
257
+ // HOOK 4: afterExecution - after successful business logic
258
+ await this.executeHook(hooks?.afterExecution, hookCtx, 'afterExecution');
259
+ if (this.checkAborted()) {
260
+ return Result.fail(new AbortedError(this.abortReason));
261
+ }
262
+ // 4. Parse and return output
263
+ return this.parseOutput(businessResult.getValue());
264
+ });
265
+ // If result is AbortedError, execute onAbort hook
266
+ if (result.isFailure && result.getError() instanceof AbortedError) {
267
+ try {
268
+ const hookCtx = this.buildHookContext(input, context);
269
+ const onAbortHook = hooks?.onAbort;
270
+ if (onAbortHook) {
271
+ this.logMetrics('onAbort', hookCtx);
272
+ await onAbortHook({ ...hookCtx, reason: this.abortReason });
273
+ }
274
+ }
275
+ catch (abortError) {
276
+ // onAbort errors are logged but don't affect the abort result
277
+ console.error(`Error in onAbort hook for ${this.useCaseName}:`, abortError);
278
+ }
279
+ }
280
+ // If result is failure (but not abort), execute onError hook
281
+ else if (result.isFailure) {
282
+ try {
283
+ const hookCtx = this.buildHookContext(input, context);
284
+ const onErrorHook = hooks?.onError;
285
+ if (onErrorHook) {
286
+ // HOOK 5: onError - after failure
287
+ this.logMetrics('onError', hookCtx);
288
+ await onErrorHook({ ...hookCtx, error: result.getError() });
289
+ }
290
+ }
291
+ catch (error) {
292
+ // If onError hook throws, create new error result
293
+ result = Result.fail(new ValidationError(this.errorMessage, undefined, {
294
+ originalError: result.getError(),
295
+ error
296
+ }));
297
+ }
298
+ }
299
+ // HOOK 6: onFinally - always executes, errors are caught and logged
300
+ try {
301
+ const hookCtx = this.buildHookContext(input, context);
302
+ const onFinallyHook = hooks?.onFinally;
303
+ if (onFinallyHook) {
304
+ this.logMetrics('onFinally', hookCtx);
305
+ await onFinallyHook({ ...hookCtx, result });
306
+ }
307
+ }
308
+ catch (finallyError) {
309
+ // onFinally errors don't affect the result, just log them
310
+ console.error(`Error in onFinally hook for ${this.useCaseName}:`, finallyError);
311
+ }
312
+ return result;
313
+ }
314
+ /**
315
+ * Validates input using the provided Zod schema
316
+ */
317
+ async validateInput(input) {
318
+ const validationResult = this.inputSchema.safeParse(input);
319
+ if (!validationResult.success) {
320
+ const firstError = validationResult.error.errors[0];
321
+ return Result.fail(new ValidationError(firstError.message, firstError.path.join('.')));
322
+ }
323
+ return Result.ok(validationResult.data);
324
+ }
325
+ /**
326
+ * Authorization hook - override for permission checks
327
+ * Default: no authorization
328
+ */
329
+ async authorize(_input, _context) {
330
+ return Result.ok(undefined);
331
+ }
332
+ /**
333
+ * Parses output using the provided Zod schema
334
+ */
335
+ parseOutput(data) {
336
+ try {
337
+ // Handle void/undefined case - no need to spread
338
+ const valueToParse = data === undefined
339
+ ? undefined
340
+ : Array.isArray(data)
341
+ ? data
342
+ : { ...data };
343
+ const parsed = this.outputSchema.parse(valueToParse);
344
+ return Result.ok(parsed);
345
+ }
346
+ catch (error) {
347
+ return Result.fail(new ValidationError('Failed to parse output', undefined, {
348
+ originalError: error
349
+ }));
350
+ }
351
+ }
352
+ /**
353
+ * Wraps execution in try-catch for consistent error handling
354
+ */
355
+ async withErrorHandling(operation) {
356
+ try {
357
+ return await operation();
358
+ }
359
+ catch (error) {
360
+ return Result.fail(new ValidationError(this.errorMessage, undefined, {
361
+ originalError: error
362
+ }));
363
+ }
364
+ }
365
+ }
366
+ //# sourceMappingURL=BaseUseCase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseUseCase.js","sourceRoot":"","sources":["../../../src/shared/use-case/BaseUseCase.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import type { OperationContext } from '@multitenantkit/domain-contracts';
2
+ import { NotFoundError } from '@multitenantkit/domain-contracts';
3
+ import { Result } from '../result/Result';
4
+ /**
5
+ * Helper functions for common use case patterns
6
+ *
7
+ * Philosophy: Keep it minimal. Only extract truly repetitive patterns.
8
+ * If a helper reduces readability, don't use it.
9
+ */
10
+ export declare class UseCaseHelpers {
11
+ /**
12
+ * Find entity by ID or return NotFoundError
13
+ *
14
+ * Common pattern across many use cases that retrieve entities by ID
15
+ *
16
+ * @example
17
+ * const userResult = await UseCaseHelpers.findByIdOrFail(
18
+ * this.adapters.persistence.userRepository,
19
+ * input.userId,
20
+ * "User"
21
+ * );
22
+ * if (userResult.isFailure) return userResult;
23
+ * const user = userResult.getValue();
24
+ */
25
+ static findByIdOrFail<T>(repository: {
26
+ findById: (id: string) => Promise<T | null>;
27
+ }, id: string, entityName: string): Promise<Result<T, NotFoundError>>;
28
+ /**
29
+ * Enrich audit context with specific action and metadata
30
+ *
31
+ * Ensures consistent audit context across all use cases
32
+ *
33
+ * @example
34
+ * const auditContext = UseCaseHelpers.enrichAuditContext(
35
+ * context,
36
+ * "CREATE_USER",
37
+ * undefined,
38
+ * { source: "admin-panel" }
39
+ * );
40
+ */
41
+ static enrichAuditContext(context: OperationContext, action: string, organizationId?: string, metadata?: Record<string, any>): OperationContext;
42
+ }
43
+ //# sourceMappingURL=UseCaseHelpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UseCaseHelpers.d.ts","sourceRoot":"","sources":["../../../src/shared/use-case/UseCaseHelpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C;;;;;GAKG;AAGH,qBAAa,cAAc;IACvB;;;;;;;;;;;;;OAaG;WACU,cAAc,CAAC,CAAC,EACzB,UAAU,EAAE;QAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;KAAE,EAC3D,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC;IAYpC;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,kBAAkB,CACrB,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,MAAM,EACd,cAAc,CAAC,EAAE,MAAM,EACvB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC/B,gBAAgB;CAQtB"}
@@ -0,0 +1,56 @@
1
+ import { NotFoundError } from '@multitenantkit/domain-contracts';
2
+ import { Result } from '../result/Result';
3
+ /**
4
+ * Helper functions for common use case patterns
5
+ *
6
+ * Philosophy: Keep it minimal. Only extract truly repetitive patterns.
7
+ * If a helper reduces readability, don't use it.
8
+ */
9
+ // biome-ignore lint/complexity/noStaticOnlyClass: ignore
10
+ export class UseCaseHelpers {
11
+ /**
12
+ * Find entity by ID or return NotFoundError
13
+ *
14
+ * Common pattern across many use cases that retrieve entities by ID
15
+ *
16
+ * @example
17
+ * const userResult = await UseCaseHelpers.findByIdOrFail(
18
+ * this.adapters.persistence.userRepository,
19
+ * input.userId,
20
+ * "User"
21
+ * );
22
+ * if (userResult.isFailure) return userResult;
23
+ * const user = userResult.getValue();
24
+ */
25
+ static async findByIdOrFail(repository, id, entityName) {
26
+ const entity = await repository.findById(id.trim());
27
+ if (!entity) {
28
+ return Result.fail(new NotFoundError(entityName, id, {
29
+ reason: `${entityName} not found`
30
+ }));
31
+ }
32
+ return Result.ok(entity);
33
+ }
34
+ /**
35
+ * Enrich audit context with specific action and metadata
36
+ *
37
+ * Ensures consistent audit context across all use cases
38
+ *
39
+ * @example
40
+ * const auditContext = UseCaseHelpers.enrichAuditContext(
41
+ * context,
42
+ * "CREATE_USER",
43
+ * undefined,
44
+ * { source: "admin-panel" }
45
+ * );
46
+ */
47
+ static enrichAuditContext(context, action, organizationId, metadata) {
48
+ return {
49
+ ...context,
50
+ auditAction: action,
51
+ organizationId: organizationId ?? context.organizationId,
52
+ metadata: { ...context.metadata, ...metadata }
53
+ };
54
+ }
55
+ }
56
+ //# sourceMappingURL=UseCaseHelpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UseCaseHelpers.js","sourceRoot":"","sources":["../../../src/shared/use-case/UseCaseHelpers.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C;;;;;GAKG;AAEH,yDAAyD;AACzD,MAAM,OAAO,cAAc;IACvB;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,KAAK,CAAC,cAAc,CACvB,UAA2D,EAC3D,EAAU,EACV,UAAkB;QAElB,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;QACpD,IAAI,CAAC,MAAM,EAAE,CAAC;YACV,OAAO,MAAM,CAAC,IAAI,CACd,IAAI,aAAa,CAAC,UAAU,EAAE,EAAE,EAAE;gBAC9B,MAAM,EAAE,GAAG,UAAU,YAAY;aACpC,CAAC,CACL,CAAC;QACN,CAAC;QACD,OAAO,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,kBAAkB,CACrB,OAAyB,EACzB,MAAc,EACd,cAAuB,EACvB,QAA8B;QAE9B,OAAO;YACH,GAAG,OAAO;YACV,WAAW,EAAE,MAAM;YACnB,cAAc,EAAE,cAAc,IAAI,OAAO,CAAC,cAAc;YACxD,QAAQ,EAAE,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,GAAG,QAAQ,EAAE;SACjD,CAAC;IACN,CAAC;CACJ"}
@@ -0,0 +1,3 @@
1
+ export * from './BaseUseCase';
2
+ export * from './UseCaseHelpers';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/use-case/index.ts"],"names":[],"mappings":"AACA,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,4 @@
1
+ // Use case base classes and helpers
2
+ export * from './BaseUseCase';
3
+ export * from './UseCaseHelpers';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/shared/use-case/index.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './use-cases';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/users/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAC"}
@@ -0,0 +1,3 @@
1
+ // Users domain slice
2
+ export * from './use-cases';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/users/index.ts"],"names":[],"mappings":"AAAA,qBAAqB;AACrB,cAAc,aAAa,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { Adapters } from '@multitenantkit/domain-contracts';
2
+ import type { OperationContext, ToolkitOptions } from '@multitenantkit/domain-contracts/shared';
3
+ import { type DomainError } from '@multitenantkit/domain-contracts/shared/errors/index';
4
+ import type { CreateUserInput, CreateUserOutput, ICreateUser } from '@multitenantkit/domain-contracts/users';
5
+ import { Result } from '../../../shared/result/Result';
6
+ import { BaseUseCase } from '../../../shared/use-case';
7
+ /**
8
+ * CreateUser use case
9
+ * Handles the business logic for creating a new user
10
+ *
11
+ * Generic support for custom fields:
12
+ * @template TUserCustomFields - Custom fields added to User
13
+ * @template TOrganizationCustomFields - Custom fields added to Organization (for toolkit options compatibility)
14
+ * @template TOrganizationMembershipCustomFields - Custom fields added to OrganizationMembership (for toolkit options compatibility)
15
+ */
16
+ export declare class CreateUser<TUserCustomFields = {}, TOrganizationCustomFields = {}, TOrganizationMembershipCustomFields = {}> extends BaseUseCase<CreateUserInput & TUserCustomFields, CreateUserOutput, DomainError, TUserCustomFields, TOrganizationCustomFields, TOrganizationMembershipCustomFields> implements ICreateUser {
17
+ private readonly customSchema?;
18
+ constructor(adapters: Adapters<TUserCustomFields, TOrganizationCustomFields, TOrganizationMembershipCustomFields>, toolkitOptions?: ToolkitOptions<TUserCustomFields, TOrganizationCustomFields, TOrganizationMembershipCustomFields>);
19
+ protected executeBusinessLogic(input: CreateUserInput & TUserCustomFields, context: OperationContext): Promise<Result<CreateUserOutput, DomainError>>;
20
+ }
21
+ //# sourceMappingURL=CreateUser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CreateUser.d.ts","sourceRoot":"","sources":["../../../../src/users/use-cases/create-user/CreateUser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AAChG,OAAO,EAEH,KAAK,WAAW,EAEnB,MAAM,sDAAsD,CAAC;AAC9D,OAAO,KAAK,EACR,eAAe,EACf,gBAAgB,EAChB,WAAW,EAEd,MAAM,wCAAwC,CAAC;AAOhD,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD;;;;;;;;GAQG;AACH,qBAAa,UAAU,CAEf,iBAAiB,GAAG,EAAE,EAEtB,yBAAyB,GAAG,EAAE,EAE9B,mCAAmC,GAAG,EAAE,CAE5C,SAAQ,WAAW,CACf,eAAe,GAAG,iBAAiB,EACnC,gBAAgB,EAChB,WAAW,EACX,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;cA4BW,oBAAoB,CAChC,KAAK,EAAE,eAAe,GAAG,iBAAiB,EAC1C,OAAO,EAAE,gBAAgB,GAC1B,OAAO,CAAC,MAAM,CAAC,gBAAgB,EAAE,WAAW,CAAC,CAAC;CA8DpD"}
@@ -0,0 +1,81 @@
1
+ import { ConflictError, ValidationError } from '@multitenantkit/domain-contracts/shared/errors/index';
2
+ import { CreateUserInputSchema, CreateUserOutputSchema, UserSchema } from '@multitenantkit/domain-contracts/users';
3
+ import { Result } from '../../../shared/result/Result';
4
+ import { BaseUseCase } from '../../../shared/use-case';
5
+ /**
6
+ * CreateUser use case
7
+ * Handles the business logic for creating a new user
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 CreateUser extends BaseUseCase {
15
+ customSchema;
16
+ constructor(adapters, toolkitOptions) {
17
+ const customSchema = toolkitOptions?.users?.customFields?.customSchema;
18
+ // Build input schema with custom fields if provided
19
+ const inputSchema = (customSchema
20
+ ? CreateUserInputSchema.and(customSchema.partial())
21
+ : CreateUserInputSchema);
22
+ // Output is a User; merge custom fields if provided
23
+ const outputSchema = (customSchema
24
+ ? CreateUserOutputSchema.merge(customSchema)
25
+ : CreateUserOutputSchema);
26
+ super('user-createUser', adapters, toolkitOptions, inputSchema, outputSchema, 'Failed to create user');
27
+ this.customSchema = customSchema;
28
+ }
29
+ async executeBusinessLogic(input, context) {
30
+ if (input.externalId) {
31
+ const existingUser = await this.adapters.persistence.userRepository.findByExternalId(input.externalId);
32
+ if (existingUser) {
33
+ return Result.fail(new ConflictError('User', input.externalId, {
34
+ reason: 'External ID already registered'
35
+ }));
36
+ }
37
+ }
38
+ // 2. Generate ID, externalId and timestamp
39
+ const userId = input.id ?? this.adapters.system.uuid.generate();
40
+ const externalId = input.externalId ?? userId; // If externalId is not provided, use userId as externalId
41
+ const now = this.adapters.system.clock.now();
42
+ // 3. Create User data with custom fields
43
+ const user = {
44
+ ...input,
45
+ id: userId,
46
+ externalId,
47
+ username: input.username, // username is required in input
48
+ createdAt: now,
49
+ updatedAt: now
50
+ };
51
+ // 4. Validate the user data with custom schema if provided
52
+ const validationSchema = this.customSchema
53
+ ? UserSchema.strip().and(this.customSchema.strip())
54
+ : UserSchema.strip();
55
+ const validationResult = validationSchema.safeParse(user);
56
+ if (!validationResult.success) {
57
+ const firstError = validationResult.error.errors[0];
58
+ return Result.fail(new ValidationError(firstError.message, firstError.path.join('.')));
59
+ }
60
+ const validatedUser = validationResult.data;
61
+ // 5. Persist the user using Unit of Work (transaction) with audit context
62
+ const auditContext = {
63
+ ...context,
64
+ organizationId: undefined, // Users don't belong directly to a organization
65
+ auditAction: 'CREATE_USER'
66
+ };
67
+ try {
68
+ await this.adapters.persistence.uow.transaction(async (repos) => {
69
+ await repos.users.insert(validatedUser, auditContext);
70
+ });
71
+ }
72
+ catch (error) {
73
+ return Result.fail(new ValidationError('Failed to save user', undefined, {
74
+ originalError: error
75
+ }));
76
+ }
77
+ // 6. Return success response; BaseUseCase will parse output
78
+ return Result.ok({ ...validatedUser });
79
+ }
80
+ }
81
+ //# sourceMappingURL=CreateUser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CreateUser.js","sourceRoot":"","sources":["../../../../src/users/use-cases/create-user/CreateUser.ts"],"names":[],"mappings":"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"}