@temboplus/afloat 0.1.77-beta.2 → 0.1.77-beta.21

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 (42) hide show
  1. package/dist/index.cjs.js +1 -1
  2. package/dist/index.cjs.js.map +1 -1
  3. package/dist/index.esm.js +1 -1
  4. package/dist/index.esm.js.map +1 -1
  5. package/dist/lib/api/base-repository.d.ts +3 -1
  6. package/dist/lib/query/query.builder.d.ts +5 -1
  7. package/dist/modules/auth/auth.contract.d.ts +2 -2
  8. package/dist/modules/auth/company-membership.model.d.ts +122 -9
  9. package/dist/modules/auth/index.d.ts +0 -1
  10. package/dist/modules/auth/user.model.d.ts +238 -15
  11. package/dist/modules/contact/contact-info.model.d.ts +183 -533
  12. package/dist/modules/contact/contact.api-contract.d.ts +8 -8
  13. package/dist/modules/contact/contact.dtos.d.ts +2 -2
  14. package/dist/modules/contact/contact.model.d.ts +309 -32
  15. package/dist/modules/login/login.api-contract.d.ts +2 -2
  16. package/dist/modules/login/login.dtos.d.ts +4 -4
  17. package/dist/modules/login/login.model.d.ts +54 -24
  18. package/dist/modules/payout/payout.api-contract.d.ts +37 -37
  19. package/dist/modules/payout/payout.dtos.d.ts +47 -39
  20. package/dist/modules/payout/payout.model.d.ts +242 -2
  21. package/dist/modules/payout/payout.query.d.ts +11 -3
  22. package/dist/modules/payout/payout.repository.d.ts +48 -25
  23. package/dist/modules/profile/profile.model.d.ts +65 -30
  24. package/dist/modules/team-member/role.model.d.ts +49 -1
  25. package/dist/modules/team-member/team-member.contract.d.ts +44 -44
  26. package/dist/modules/team-member/team-member.dtos.d.ts +14 -14
  27. package/dist/modules/team-member/team-member.model.d.ts +106 -6
  28. package/dist/modules/wallet/index.d.ts +0 -1
  29. package/dist/modules/wallet/narration.model.d.ts +34 -38
  30. package/dist/modules/wallet/statement-entry.model.d.ts +172 -73
  31. package/dist/modules/wallet/wallet.contract.d.ts +6 -6
  32. package/dist/modules/wallet/wallet.dtos.d.ts +12 -12
  33. package/dist/modules/wallet/wallet.model.d.ts +56 -19
  34. package/dist/modules/wallet/wallet.query.d.ts +95 -0
  35. package/dist/modules/wallet/wallet.repository.d.ts +45 -13
  36. package/package.json +2 -2
  37. package/dist/modules/auth/auth.manager.d.ts +0 -249
  38. package/dist/modules/auth/auth.store.d.ts +0 -139
  39. package/dist/modules/auth/storage/client-store.d.ts +0 -29
  40. package/dist/modules/auth/storage/client-token-handler.d.ts +0 -31
  41. package/dist/modules/auth/storage/types.d.ts +0 -41
  42. package/dist/modules/wallet/wallet-manager.session.d.ts +0 -143
@@ -2,6 +2,91 @@ import { ContactType, ContactDTO } from "@/modules/contact/contact.dtos.js";
2
2
  import { PayoutDTO } from "@/modules/payout/payout.dtos.js";
3
3
  import { Bank, ISO2CountryCode, PhoneNumber } from "@temboplus/frontend-core";
4
4
  import type { BankSwiftCode, MNOId } from "@temboplus/frontend-core";
5
+ import { z } from "zod";
6
+ export declare const MobileContactInfoJSONSchema: z.ZodObject<{
7
+ type: z.ZodLiteral<"Mobile">;
8
+ name: z.ZodString;
9
+ phoneNumber: z.ZodString;
10
+ mnoId: z.ZodString;
11
+ version: z.ZodDefault<z.ZodOptional<z.ZodString>>;
12
+ }, "strip", z.ZodTypeAny, {
13
+ type: "Mobile";
14
+ name: string;
15
+ version: string;
16
+ phoneNumber: string;
17
+ mnoId: string;
18
+ }, {
19
+ type: "Mobile";
20
+ name: string;
21
+ phoneNumber: string;
22
+ mnoId: string;
23
+ version?: string | undefined;
24
+ }>;
25
+ export declare const BankContactInfoJSONSchema: z.ZodObject<{
26
+ type: z.ZodLiteral<"Bank">;
27
+ accName: z.ZodString;
28
+ swiftCode: z.ZodString;
29
+ countryCode: z.ZodString;
30
+ accNo: z.ZodString;
31
+ version: z.ZodDefault<z.ZodOptional<z.ZodString>>;
32
+ }, "strip", z.ZodTypeAny, {
33
+ type: "Bank";
34
+ version: string;
35
+ countryCode: string;
36
+ accName: string;
37
+ swiftCode: string;
38
+ accNo: string;
39
+ }, {
40
+ type: "Bank";
41
+ countryCode: string;
42
+ accName: string;
43
+ swiftCode: string;
44
+ accNo: string;
45
+ version?: string | undefined;
46
+ }>;
47
+ export declare const ContactInfoJSONSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
48
+ type: z.ZodLiteral<"Mobile">;
49
+ name: z.ZodString;
50
+ phoneNumber: z.ZodString;
51
+ mnoId: z.ZodString;
52
+ version: z.ZodDefault<z.ZodOptional<z.ZodString>>;
53
+ }, "strip", z.ZodTypeAny, {
54
+ type: "Mobile";
55
+ name: string;
56
+ version: string;
57
+ phoneNumber: string;
58
+ mnoId: string;
59
+ }, {
60
+ type: "Mobile";
61
+ name: string;
62
+ phoneNumber: string;
63
+ mnoId: string;
64
+ version?: string | undefined;
65
+ }>, z.ZodObject<{
66
+ type: z.ZodLiteral<"Bank">;
67
+ accName: z.ZodString;
68
+ swiftCode: z.ZodString;
69
+ countryCode: z.ZodString;
70
+ accNo: z.ZodString;
71
+ version: z.ZodDefault<z.ZodOptional<z.ZodString>>;
72
+ }, "strip", z.ZodTypeAny, {
73
+ type: "Bank";
74
+ version: string;
75
+ countryCode: string;
76
+ accName: string;
77
+ swiftCode: string;
78
+ accNo: string;
79
+ }, {
80
+ type: "Bank";
81
+ countryCode: string;
82
+ accName: string;
83
+ swiftCode: string;
84
+ accNo: string;
85
+ version?: string | undefined;
86
+ }>]>;
87
+ export type MobileContactInfoJSON = z.infer<typeof MobileContactInfoJSONSchema>;
88
+ export type BankContactInfoJSON = z.infer<typeof BankContactInfoJSONSchema>;
89
+ export type ContactInfoJSON = z.infer<typeof ContactInfoJSONSchema>;
5
90
  /**
6
91
  * Abstract base class that provides a common interface for different types of contact information.
7
92
  * This class defines the structure and validation requirements for both mobile and bank contacts.
@@ -22,8 +107,8 @@ import type { BankSwiftCode, MNOId } from "@temboplus/frontend-core";
22
107
  * @example
23
108
  * ```typescript
24
109
  * // Cannot instantiate directly - use concrete implementations
25
- * const mobileContact = new MobileContactInfo("John Doe", phoneNumber);
26
- * const bankContact = new BankContactInfo("Jane Smith", bank, "123456789");
110
+ * const mobileContact = MobileContactInfo.from({ name: "John Doe", phoneNumber });
111
+ * const bankContact = BankContactInfo.from({ accName: "Jane Smith", bank, accNo: "123456789" });
27
112
  *
28
113
  * // Polymorphic usage
29
114
  * function processContact(contact: BaseContactInfo) {
@@ -115,6 +200,17 @@ declare abstract class BaseContactInfo {
115
200
  * @returns {boolean} True if the contact information is valid
116
201
  */
117
202
  abstract validate(): boolean;
203
+ /**
204
+ * Serializes the ContactInfo instance to a JSON-compatible object
205
+ */
206
+ abstract toJSON(): ContactInfoJSON;
207
+ /**
208
+ * Converts the ContactInfo instance to a JSON string.
209
+ */
210
+ toJSONString(): string;
211
+ get isMobile(): boolean;
212
+ get isBank(): boolean;
213
+ get displayName(): string;
118
214
  }
119
215
  /**
120
216
  * Implementation of BaseContactInfo for mobile phone contacts.
@@ -144,24 +240,16 @@ declare abstract class BaseContactInfo {
144
240
  *
145
241
  * @example
146
242
  * ```typescript
147
- * // Tanzania - MNO auto-detected from prefix (ignores provided MNO)
148
- * const tzContact = new MobileContactInfo("John Doe", tzPhoneNumber);
149
- * console.log(tzContact.channel); // "VODACOM" (auto-detected)
150
- * console.log(tzContact.countryCode); // "TZ" (from phoneNumber)
151
- *
152
- * // Tanzania - Even with explicit MNO, it's auto-detected from prefix
153
- * const tzExplicit = new MobileContactInfo("John Doe", tzPhoneNumber, TZMNOId.AIRTEL);
154
- * console.log(tzExplicit.channel); // "VODACOM" (auto-detected, not AIRTEL)
243
+ * // Preferred: Use static factory method
244
+ * const tzContact = MobileContactInfo.from({
245
+ * name: "John Doe",
246
+ * phoneNumber: tzPhoneNumber
247
+ * });
248
+ * console.log(tzContact?.channelName); // "M-Pesa" (Vodacom's service)
155
249
  *
156
- * // Kenya - MNO must be explicit due to MNP
157
- * const keContact = new MobileContactInfo("Jane Smith", kePhoneNumber, KEMNOId.SAFARICOM);
158
- * console.log(keContact.countryCode); // "KE" (from phoneNumber)
159
- *
160
- * // Kenya - This would throw an error (MNO required)
161
- * // const keContact = new MobileContactInfo("Jane Smith", kePhoneNumber); // ❌ Error
250
+ * // From JSON
251
+ * const jsonContact = MobileContactInfo.fromJSON(jsonString);
162
252
  * ```
163
- *
164
- * @throws {ContactInfoError} When validation fails (invalid name, phone, or MNO)
165
253
  */
166
254
  export declare class MobileContactInfo extends BaseContactInfo {
167
255
  readonly name: string;
@@ -174,147 +262,86 @@ export declare class MobileContactInfo extends BaseContactInfo {
174
262
  * 1. Validates name is non-empty
175
263
  * 2. Validates phone number structure
176
264
  * 3. Extracts country code from PhoneNumber object
177
- * 4. Handles MNO validation based on country MNP status:
178
- * - **Countries with MNP (KE)**: Requires explicit MNO, validates it's valid for country
179
- * - **Countries without MNP (TZ)**: Always auto-detects MNO from phone number prefix (ignores provided MNO)
265
+ * 4. Handles MNO validation based on country MNP status
180
266
  *
267
+ * @deprecated Use {@link MobileContactInfo.from} static factory method instead
181
268
  * @param {string} name - The contact's personal name (required, non-empty)
182
269
  * @param {PhoneNumber} phoneNumber - The validated phone number object (contains country code)
183
270
  * @param {MNOId} [mnoId] - MNO ID. Required for MNP countries (KE), ignored for non-MNP countries (TZ)
184
271
  *
185
- * @throws {ContactInfoError} When any validation fails:
186
- * - Empty or invalid name
187
- * - Invalid phone number structure
188
- * - Invalid MNO for the country (MNP countries only)
189
- * - Missing MNO for MNP countries
190
- * - Unable to auto-detect MNO for non-MNP countries
272
+ * @throws {ContactInfoError} When any validation fails
273
+ */
274
+ constructor(name: string, phoneNumber: PhoneNumber, mnoId?: MNOId);
275
+ /**
276
+ * Creates a MobileContactInfo instance from data object.
277
+ * This is the preferred method for creating instances.
278
+ *
279
+ * @static
280
+ * @param {Object} data - The mobile contact data
281
+ * @param {string} data.name - The contact's personal name
282
+ * @param {PhoneNumber} data.phoneNumber - The validated phone number object
283
+ * @param {MNOId} [data.mnoId] - MNO ID (required for MNP countries)
284
+ *
285
+ * @returns {MobileContactInfo | undefined} New instance if successful, undefined if validation fails
191
286
  *
192
287
  * @example
193
288
  * ```typescript
194
- * try {
195
- * // Tanzania - MNO always auto-detected
196
- * const tzAuto = new MobileContactInfo("John", tzPhone);
197
- * const tzIgnored = new MobileContactInfo("John", tzPhone, TZMNOId.AIRTEL); // AIRTEL ignored, auto-detected from prefix
198
- *
199
- * // Kenya - MNO must be explicit
200
- * const keExplicit = new MobileContactInfo("Jane", kePhone, KEMNOId.SAFARICOM);
201
- * } catch (error) {
202
- * if (error instanceof ContactInfoError) {
203
- * console.log(`${error.message} - Context:`, error.context);
204
- * }
205
- * }
289
+ * const contact = MobileContactInfo.from({
290
+ * name: "John Doe",
291
+ * phoneNumber: tzPhone,
292
+ * mnoId: TZMNOId.VODACOM // Optional for TZ, required for KE
293
+ * });
206
294
  * ```
207
295
  */
208
- constructor(name: string, phoneNumber: PhoneNumber, mnoId?: MNOId);
296
+ static from(data: {
297
+ name: string;
298
+ phoneNumber: PhoneNumber;
299
+ mnoId?: MNOId;
300
+ }): MobileContactInfo | undefined;
209
301
  /**
210
302
  * Creates a MobileContactInfo instance from a ContactDTO object.
211
303
  * Handles validation and MNO extraction from the DTO's channel field.
212
- * The country code is automatically derived from the parsed phone number.
213
- *
214
- * **Process:**
215
- * 1. Validates DTO type is "Mobile"
216
- * 2. Parses phone number (extracts country code from E164 format)
217
- * 3. Handles MNO based on country MNP status:
218
- * - **MNP countries**: Uses channel field (required)
219
- * - **Non-MNP countries**: Auto-detects from phone number (ignores channel field)
220
- * 4. Delegates to constructor for final validation
221
304
  *
222
305
  * @static
223
306
  * @param {ContactDTO} info - The contact data transfer object
224
- * @param {string} info.type - Must be "Mobile"
225
- * @param {string} info.accountNo - The phone number string to parse (should be E164 format)
226
- * @param {string} info.displayName - The contact's name
227
- * @param {string} [info.channel] - MNO ID (required for MNP countries, ignored for non-MNP countries)
228
- *
229
307
  * @returns {MobileContactInfo | undefined} New instance if successful, undefined if validation fails
230
308
  *
231
309
  * @example
232
310
  * ```typescript
233
- * // Tanzania DTO - channel ignored, auto-detected from phone number
234
- * const tzContactDTO = {
311
+ * const contactDTO = {
235
312
  * type: "Mobile",
236
- * accountNo: "+255712345678", // Vodacom prefix
313
+ * accountNo: "+255712345678",
237
314
  * displayName: "John Doe",
238
- * channel: "AIRTEL" // This will be ignored, Vodacom will be auto-detected
239
- * };
240
- *
241
- * // Kenya DTO - channel required
242
- * const keContactDTO = {
243
- * type: "Mobile",
244
- * accountNo: "+254712345678",
245
- * displayName: "Jane Smith",
246
- * channel: "SAFARICOM" // Required for Kenya
315
+ * channel: "VODACOM"
247
316
  * };
248
317
  *
249
- * const tzContact = MobileContactInfo.fromContactDTO(tzContactDTO);
250
- * console.log(tzContact?.channelId); // "VODACOM" (not "AIRTEL")
251
- * console.log(tzContact?.countryCode); // "TZ" (from phone number)
252
- *
253
- * const keContact = MobileContactInfo.fromContactDTO(keContactDTO);
254
- * console.log(keContact?.channelId); // "SAFARICOM"
255
- * console.log(keContact?.countryCode); // "KE" (from phone number)
318
+ * const contact = MobileContactInfo.fromContactDTO(contactDTO);
256
319
  * ```
257
320
  */
258
321
  static fromContactDTO(info: ContactDTO): MobileContactInfo | undefined;
259
322
  /**
260
323
  * Creates a MobileContactInfo instance from a PayoutDTO object.
261
324
  * Extracts mobile contact information from payout data structure.
262
- * The country code is derived from the parsed phone number.
263
- *
264
- * **Process:**
265
- * 1. Validates country code format in DTO
266
- * 2. Parses phone number from msisdn field (uses DTO country as hint)
267
- * 3. Uses phone number's country code (derived from E164 format)
268
- * 4. Handles MNO based on country MNP status:
269
- * - **MNP countries**: Uses channel field (required)
270
- * - **Non-MNP countries**: Auto-detects from phone number (ignores channel field)
271
- * 5. Uses payeeName as the contact name
272
- * 6. Delegates to constructor for validation
273
325
  *
274
326
  * @static
275
327
  * @param {PayoutDTO} info - The payout data transfer object
276
- * @param {string} info.msisdn - The phone number in E164 or local format
277
- * @param {string} info.countryCode - ISO2 country code (used as parsing hint)
278
- * @param {string} info.payeeName - The recipient's name
279
- * @param {string} [info.channel] - MNO ID (required for MNP countries, ignored for non-MNP countries)
280
- *
281
328
  * @returns {MobileContactInfo | undefined} New instance if successful, undefined if parsing fails
282
329
  *
283
330
  * @example
284
331
  * ```typescript
285
- * // Tanzania payout - channel ignored
286
- * const tzPayoutDTO = {
287
- * msisdn: "+255712345678", // Vodacom prefix
332
+ * const payoutDTO = {
333
+ * msisdn: "+255712345678",
288
334
  * countryCode: "TZ",
289
335
  * payeeName: "John Doe",
290
- * channel: "AIRTEL" // Ignored, Vodacom auto-detected
336
+ * channel: "VODACOM"
291
337
  * };
292
338
  *
293
- * // Kenya payout - channel required
294
- * const kePayoutDTO = {
295
- * msisdn: "+254712345678",
296
- * countryCode: "KE",
297
- * payeeName: "Jane Smith",
298
- * channel: "SAFARICOM" // Required
299
- * };
300
- *
301
- * const tzContact = MobileContactInfo.fromPayoutDTO(tzPayoutDTO);
302
- * console.log(tzContact?.channelName); // "M-Pesa" (Vodacom's service)
303
- * console.log(tzContact?.countryCode); // "TZ" (from phoneNumber)
339
+ * const contact = MobileContactInfo.fromPayoutDTO(payoutDTO);
304
340
  * ```
305
341
  */
306
342
  static fromPayoutDTO(info: PayoutDTO): MobileContactInfo | undefined;
307
343
  /**
308
344
  * Type guard to validate if an unknown object is a valid MobileContactInfo instance.
309
- * Performs comprehensive structural and data validation including country-specific MNO rules.
310
- *
311
- * **Validation Process:**
312
- * 1. **Structural validation**: Checks required properties exist with correct types
313
- * 2. **Name validation**: Ensures name is non-empty string
314
- * 3. **Phone validation**: Validates phone number can be parsed and is valid
315
- * 4. **MNO validation**: Country-specific validation:
316
- * - **MNP countries (KE)**: Validates MNO ID is valid for country
317
- * - **Non-MNP countries (TZ)**: Validates MNO matches phone number prefix (auto-detected)
318
345
  *
319
346
  * @static
320
347
  * @param {unknown} obj - The object to validate
@@ -322,228 +349,56 @@ export declare class MobileContactInfo extends BaseContactInfo {
322
349
  *
323
350
  * @example
324
351
  * ```typescript
325
- * const unknownData = JSON.parse(someJsonString);
326
- *
327
352
  * if (MobileContactInfo.is(unknownData)) {
328
- * // TypeScript now knows this is MobileContactInfo
329
- * console.log(unknownData.name); // ✅ Type-safe access
330
- * console.log(unknownData.phoneNumber.e164Format); // ✅ Type-safe
331
- * console.log(unknownData.mnoId); // ✅ Type-safe
332
- * console.log(unknownData.countryCode); // ✅ Type-safe (from phoneNumber)
333
- * } else {
334
- * console.log("Invalid MobileContactInfo structure");
353
+ * console.log(unknownData.name); // Type-safe access
335
354
  * }
336
- *
337
- * // Usage in arrays
338
- * const contacts = jsonArray.filter(MobileContactInfo.is);
339
- * // contacts is now typed as MobileContactInfo[]
340
355
  * ```
341
- *
342
- * @remarks
343
- * - Validates both serialized and live objects
344
- * - Phone numbers can be provided as strings or PhoneNumber objects
345
- * - Uses country-specific MNO validation through MNOUtils
346
- * - Returns false for any validation failure (fail-fast approach)
347
- * - For non-MNP countries, validates that the MNO matches what would be auto-detected
348
356
  */
349
357
  static is(obj: unknown): obj is MobileContactInfo;
350
358
  /**
351
359
  * Validates that all contact information is consistent and correct.
352
- * Uses country-specific validation logic through MNOUtils delegation.
353
- *
354
- * **Validation Checks:**
355
- * 1. **Name validation**: Non-empty string
356
- * 2. **Phone validation**: Valid phone number structure
357
- * 3. **MNO validation**: Valid MNO for the country
358
- * 4. **Consistency check**: For non-MNP countries, validates MNO matches auto-detected value from phone prefix
359
360
  *
360
361
  * @returns {boolean} True if all validations pass, false otherwise
361
- *
362
- * @example
363
- * ```typescript
364
- * const contact = new MobileContactInfo("John", phoneNumber, TZMNOId.VODACOM);
365
- *
366
- * if (contact.validate()) {
367
- * console.log("Contact is valid and ready to use");
368
- * } else {
369
- * console.log("Contact has validation issues");
370
- * // Use getValidationDetails() for specific error information
371
- * }
372
- * ```
373
- *
374
- * @see {@link getValidationDetails} For detailed validation results with specific errors
375
362
  */
376
363
  validate(): boolean;
377
364
  /**
378
365
  * Provides detailed validation results with specific error and warning information.
379
- * Uses country-specific validation logic for comprehensive analysis.
380
- *
381
- * **Validation Categories:**
382
- * - **Errors**: Critical issues that make the contact invalid
383
- * - **Warnings**: Potential issues that don't prevent usage but indicate inconsistencies
384
366
  *
385
367
  * @returns {Object} Detailed validation results
386
- * @returns {boolean} returns.isValid - True if no errors found
387
- * @returns {string[]} returns.errors - Array of error messages for critical issues
388
- * @returns {string[]} returns.warnings - Array of warning messages for potential issues
389
- *
390
- * @example
391
- * ```typescript
392
- * const contact = new MobileContactInfo("John", phoneNumber);
393
- * const validation = contact.getValidationDetails();
394
- *
395
- * console.log(`Valid: ${validation.isValid}`);
396
- *
397
- * if (validation.errors.length > 0) {
398
- * console.log("Errors found:");
399
- * validation.errors.forEach(error => console.log(`- ${error}`));
400
- * }
401
- *
402
- * if (validation.warnings.length > 0) {
403
- * console.log("Warnings:");
404
- * validation.warnings.forEach(warning => console.log(`- ${warning}`));
405
- * }
406
- *
407
- * // For non-MNP countries, the MNO is always consistent as it's auto-detected
408
- * // Warnings would only appear if there were other potential issues
409
- * ```
410
- *
411
- * @remarks
412
- * Uses MNOUtils for country-specific validation logic:
413
- * - **Tanzania**: Validates MNO matches auto-detected value from phone number prefix
414
- * - **Kenya**: Acknowledges MNP limitations, focuses on MNO validity for country
415
368
  */
416
369
  getValidationDetails(): {
417
370
  isValid: boolean;
418
371
  errors: string[];
419
372
  warnings: string[];
420
373
  };
421
- /**
422
- * Gets the contact's personal name for display purposes.
423
- *
424
- * @override
425
- * @returns {string} The contact's personal name
426
- */
427
374
  get accountName(): string;
428
- /**
429
- * Gets the phone number formatted for display and storage.
430
- * Returns the number in e164 format (with + prefix).
431
- *
432
- * @override
433
- * @returns {string} Phone number in e164 format (e.g., "+255712345678")
434
- *
435
- * @example
436
- * ```typescript
437
- * const contact = new MobileContactInfo("John", phoneNumber);
438
- * console.log(contact.accountNumber); // "+255712345678"
439
- * ```
440
- */
441
375
  get accountNumber(): string;
442
- /**
443
- * Gets the localized label for the display name field.
444
- *
445
- * @override
446
- * @returns {string} Always returns "Name" for mobile contacts
447
- */
448
376
  get accountNameLabel(): string;
449
- /**
450
- * Gets the localized label for the account number field.
451
- *
452
- * @override
453
- * @returns {string} Always returns "Phone Number" for mobile contacts
454
- */
455
377
  get accountNumberLabel(): string;
456
- /**
457
- * Gets the localized label for the channel field.
458
- *
459
- * @override
460
- * @returns {string} Always returns "Channel" for mobile contacts
461
- */
462
378
  get channelLabel(): string;
463
- /**
464
- * Gets the typed MNO identifier for this mobile contact.
465
- * This is the programmatic identifier used for API calls and business logic.
466
- *
467
- * @returns {MNOId} The MNO identifier (e.g., "VODACOM", "SAFARICOM")
468
- *
469
- * @example
470
- * ```typescript
471
- * const contact = new MobileContactInfo("John", tzPhone, TZMNOId.VODACOM);
472
- * console.log(contact.channelId); // "VODACOM" (for MNP countries)
473
- *
474
- * // For non-MNP countries, always returns auto-detected value
475
- * const contact2 = new MobileContactInfo("John", tzPhone, TZMNOId.AIRTEL); // AIRTEL ignored
476
- * console.log(contact2.channelId); // "VODACOM" (auto-detected from phone prefix)
477
- * ```
478
- */
479
379
  get channelId(): MNOId;
480
- /**
481
- * Gets the human-readable mobile money service name for display purposes.
482
- * Uses MNOUtils to retrieve service information from country-specific implementations.
483
- *
484
- * **Behavior:**
485
- * - Returns the mobile money service name (e.g., "M-Pesa", "Airtel Money")
486
- * - Falls back to MNO display name if service name unavailable
487
- * - Falls back to MNO ID if no display information available
488
- * - For non-MNP countries, always reflects the auto-detected MNO service
489
- *
490
- * @returns {string} The mobile money service name for display
491
- *
492
- * @example
493
- * ```typescript
494
- * const vodacomContact = new MobileContactInfo("John", tzPhone, TZMNOId.VODACOM);
495
- * console.log(vodacomContact.channelName); // "M-Pesa"
496
- *
497
- * const safaricomContact = new MobileContactInfo("Jane", kePhone, KEMNOId.SAFARICOM);
498
- * console.log(safaricomContact.channelName); // "M-Pesa"
499
- *
500
- * // For non-MNP countries, shows auto-detected service regardless of provided MNO
501
- * const tzContact = new MobileContactInfo("Bob", tzVodacomPhone, TZMNOId.AIRTEL); // AIRTEL ignored
502
- * console.log(tzContact.channelName); // "M-Pesa" (Vodacom's service, auto-detected)
503
- * ```
504
- *
505
- * @remarks
506
- * Uses MNOUtils.getMNOById() which delegates to country-specific implementations
507
- * for consistent and accurate service name retrieval.
508
- */
509
380
  get channelName(): string;
381
+ toJSON(): MobileContactInfoJSON;
382
+ static fromJSON(json: MobileContactInfoJSON | string): MobileContactInfo | undefined;
383
+ static fromJSONString(jsonString: string): MobileContactInfo | undefined;
384
+ static isMobileContactInfoJSON(obj: unknown): obj is MobileContactInfoJSON;
510
385
  }
511
386
  /**
512
387
  * Implementation of BaseContactInfo for bank account contacts.
513
388
  * Handles storage, validation, and display of contact details specific to bank transfers.
514
- * The country code is automatically derived from the Bank object.
515
- *
516
- * This class provides comprehensive validation for bank account information including
517
- * SWIFT code validation, account name verification, and account number format checking.
518
- *
519
- * **Key Features:**
520
- * - SWIFT code validation per country regulations
521
- * - Account name format validation
522
- * - Account number format validation (country-specific rules)
523
- * - Integration with Bank service for institution data
524
- * - Country code derived from Bank (single source of truth)
525
389
  *
526
390
  * @extends BaseContactInfo
527
391
  * @class BankContactInfo
528
392
  *
529
- * @property {string} accName - The bank account holder's name
530
- * @property {Bank} bank - The bank institution object with SWIFT code and details
531
- * @property {string} accNo - The bank account number
532
- *
533
393
  * @example
534
394
  * ```typescript
535
- * // Create bank contact with validation
536
- * const bank = Bank.from("CORUTZTZ", "TZ"); // CRDB Bank
537
- * const contact = new BankContactInfo("John Doe", bank, "0150123456789");
538
- *
539
- * console.log(contact.channelId); // "CORUTZTZ" (SWIFT code)
540
- * console.log(contact.channelName); // "CRDB" (bank short name)
541
- * console.log(contact.accountName); // "John Doe"
542
- * console.log(contact.accountNumber); // "0150123456789"
543
- * console.log(contact.countryCode); // "TZ" (from bank)
395
+ * const bank = Bank.from("CORUTZTZ", "TZ");
396
+ * const contact = BankContactInfo.from({
397
+ * accName: "John Doe",
398
+ * bank,
399
+ * accNo: "0150123456789"
400
+ * });
544
401
  * ```
545
- *
546
- * @throws {ContactInfoError} When validation fails (invalid account name, number, or bank)
547
402
  */
548
403
  export declare class BankContactInfo extends BaseContactInfo {
549
404
  readonly accName: string;
@@ -551,288 +406,83 @@ export declare class BankContactInfo extends BaseContactInfo {
551
406
  readonly accNo: string;
552
407
  /**
553
408
  * Creates a new bank contact with comprehensive validation.
554
- * The country code is automatically extracted from the Bank object.
555
409
  *
556
- * **Validation Process:**
557
- * 1. **Country code extraction**: Derived from bank.countryCode
558
- * 2. **Account name validation**: Checks format and character requirements
559
- * 3. **Account number validation**: Validates format per country banking rules
560
- * 4. **Bank validation**: Ensures bank object is valid and contains required data
410
+ * @deprecated Use {@link BankContactInfo.from} static factory method instead
411
+ * @param {string} accName - The bank account holder's name
412
+ * @param {Bank} bank - The bank institution object
413
+ * @param {string} accNo - The bank account number
414
+ *
415
+ * @throws {ContactInfoError} When validation fails
416
+ */
417
+ constructor(accName: string, bank: Bank, accNo: string);
418
+ /**
419
+ * Creates a BankContactInfo instance from data object.
420
+ * This is the preferred method for creating instances.
561
421
  *
562
- * @param {string} accName - The bank account holder's name (must pass BankValidation.validateAccountName)
563
- * @param {Bank} bank - The bank institution object (must be valid Bank instance with countryCode)
564
- * @param {string} accNo - The bank account number (must pass country-specific validation)
422
+ * @static
423
+ * @param {Object} data - The bank contact data
424
+ * @param {string} data.accName - The account holder's name
425
+ * @param {Bank} data.bank - The bank institution object
426
+ * @param {string} data.accNo - The bank account number
565
427
  *
566
- * @throws {ContactInfoError} When validation fails:
567
- * - Invalid account name format
568
- * - Invalid account number format for the country
569
- * - Invalid or missing bank information
428
+ * @returns {BankContactInfo | undefined} New instance if successful, undefined if validation fails
570
429
  *
571
430
  * @example
572
431
  * ```typescript
573
- * try {
574
- * const bank = Bank.from("CORUTZTZ", "TZ");
575
- * const contact = new BankContactInfo("John Doe", bank, "0150123456789");
576
- * console.log("Bank contact created successfully");
577
- * console.log(`Country: ${contact.countryCode}`); // "TZ" (from bank)
578
- * } catch (error) {
579
- * if (error instanceof ContactInfoError) {
580
- * console.log(`Validation failed: ${error.message}`);
581
- * }
582
- * }
432
+ * const bank = Bank.from("CORUTZTZ", "TZ");
433
+ * const contact = BankContactInfo.from({
434
+ * accName: "John Doe",
435
+ * bank,
436
+ * accNo: "0150123456789"
437
+ * });
583
438
  * ```
584
439
  */
585
- constructor(accName: string, bank: Bank, accNo: string);
440
+ static from(data: {
441
+ accName: string;
442
+ bank: Bank;
443
+ accNo: string;
444
+ }): BankContactInfo | undefined;
586
445
  /**
587
446
  * Creates a BankContactInfo instance from a ContactDTO object.
588
- * Handles SWIFT code validation and bank lookup.
589
- * The country code is derived from the SWIFT code.
590
- *
591
- * **Process:**
592
- * 1. Validates DTO type is "Bank"
593
- * 2. Extracts SWIFT code from channel field
594
- * 3. Derives country code from SWIFT code
595
- * 4. Validates SWIFT code format and existence
596
- * 5. Looks up bank information using SWIFT code
597
- * 6. Delegates to constructor for final validation
598
447
  *
599
448
  * @static
600
449
  * @param {ContactDTO} info - The contact data transfer object
601
- * @param {string} info.type - Must be "Bank"
602
- * @param {string} info.channel - The SWIFT code for the bank
603
- * @param {string} info.displayName - The account holder's name
604
- * @param {string} info.accountNo - The bank account number
605
- *
606
450
  * @returns {BankContactInfo | undefined} New instance if successful, undefined if validation fails
607
- *
608
- * @example
609
- * ```typescript
610
- * const contactDTO = {
611
- * type: "Bank",
612
- * channel: "CORUTZTZ", // CRDB Bank SWIFT code
613
- * displayName: "John Doe",
614
- * accountNo: "0150123456789"
615
- * };
616
- *
617
- * const contact = BankContactInfo.fromContactDTO(contactDTO);
618
- * if (contact) {
619
- * console.log(`Created bank contact: ${contact.accountName} at ${contact.bank.shortName}`);
620
- * console.log(`Country: ${contact.countryCode}`); // "TZ" (derived from SWIFT)
621
- * }
622
- * ```
623
451
  */
624
452
  static fromContactDTO(info: ContactDTO): BankContactInfo | undefined;
625
453
  /**
626
454
  * Creates a BankContactInfo instance from a PayoutDTO object.
627
- * Parses bank information from the payout's msisdn field using "swiftcode:accountno" format.
628
- * The country code is derived from the parsed phone number or validated against the SWIFT code.
629
- *
630
- * **Expected Format:** The msisdn field should contain "SWIFTCODE:ACCOUNTNUMBER"
631
- *
632
- * **Process:**
633
- * 1. Validates country code format in DTO (used as hint/validation)
634
- * 2. Splits msisdn field on ":" delimiter
635
- * 3. Validates SWIFT code format and existence
636
- * 4. Looks up bank information (bank contains country code)
637
- * 5. Creates contact with parsed information
638
455
  *
639
456
  * @static
640
457
  * @param {PayoutDTO} info - The payout data transfer object
641
- * @param {string} info.msisdn - Bank info in format "SWIFTCODE:ACCOUNTNUMBER"
642
- * @param {string} info.countryCode - ISO2 country code (used for validation)
643
- * @param {string} info.payeeName - The account holder's name
644
- *
645
458
  * @returns {BankContactInfo | undefined} New instance if successful, undefined if parsing fails
646
- *
647
- * @example
648
- * ```typescript
649
- * const payoutDTO = {
650
- * msisdn: "CORUTZTZ:0150123456789", // SWIFT:Account format
651
- * countryCode: "TZ",
652
- * payeeName: "Jane Smith"
653
- * };
654
- *
655
- * const contact = BankContactInfo.fromPayoutDTO(payoutDTO);
656
- * if (contact) {
657
- * console.log(`Payout to: ${contact.accountName}`);
658
- * console.log(`Bank: ${contact.bank.fullName}`);
659
- * console.log(`Account: ${contact.accountNumber}`);
660
- * console.log(`Country: ${contact.countryCode}`); // "TZ" (from bank)
661
- * }
662
- * ```
663
- *
664
- * @remarks
665
- * Returns undefined if:
666
- * - msisdn doesn't contain exactly one ":" separator
667
- * - SWIFT code is invalid for the country
668
- * - Bank lookup fails
669
- * - Any validation error occurs
670
459
  */
671
460
  static fromPayoutDTO(info: PayoutDTO): BankContactInfo | undefined;
672
461
  /**
673
462
  * Type guard to validate if an unknown object is a valid BankContactInfo instance.
674
- * Performs comprehensive structural and business logic validation.
675
- *
676
- * **Validation Process:**
677
- * 1. **Structural validation**: Checks required properties exist with correct types
678
- * 2. **Account name validation**: Uses BankValidation.validateAccountName()
679
- * 3. **Account number validation**: Uses country-specific BankValidation.validateAccountNumber()
680
- * 4. **Bank validation**: Ensures bank object passes Bank.is() validation
681
463
  *
682
464
  * @static
683
465
  * @param {unknown} obj - The object to validate
684
466
  * @returns {obj is BankContactInfo} Type predicate indicating validity
685
- *
686
- * @example
687
- * ```typescript
688
- * const unknownData = JSON.parse(bankJsonString);
689
- *
690
- * if (BankContactInfo.is(unknownData)) {
691
- * // TypeScript now knows this is BankContactInfo
692
- * console.log(unknownData.accName); // ✅ Type-safe access
693
- * console.log(unknownData.bank.fullName); // ✅ Type-safe
694
- * console.log(unknownData.accNo); // ✅ Type-safe
695
- * console.log(unknownData.countryCode); // ✅ Type-safe (from bank)
696
- * } else {
697
- * console.log("Invalid BankContactInfo structure");
698
- * }
699
- *
700
- * // Usage in arrays
701
- * const bankContacts = jsonArray.filter(BankContactInfo.is);
702
- * // bankContacts is now typed as BankContactInfo[]
703
- * ```
704
- *
705
- * @remarks
706
- * - Validates both serialized and live objects
707
- * - Uses banking industry validation rules through BankValidation
708
- * - Ensures bank object contains valid SWIFT code and institution data
709
- * - Returns false for any validation failure (fail-fast approach)
710
467
  */
711
468
  static is(obj: unknown): obj is BankContactInfo;
712
469
  validate(): boolean;
713
- /**
714
- * Gets the bank account holder's name for display purposes.
715
- *
716
- * @override
717
- * @returns {string} The account holder's name
718
- */
719
470
  get accountName(): string;
720
- /**
721
- * Gets the bank account number for display and processing.
722
- *
723
- * @override
724
- * @returns {string} The bank account number as provided
725
- */
726
471
  get accountNumber(): string;
727
- /**
728
- * Gets the localized label for the display name field.
729
- *
730
- * @override
731
- * @returns {string} Always returns "Acc. Name" for bank contacts
732
- */
733
472
  get accountNameLabel(): string;
734
- /**
735
- * Gets the localized label for the account number field.
736
- *
737
- * @override
738
- * @returns {string} Always returns "Bank Acc. No." for bank contacts
739
- */
740
473
  get accountNumberLabel(): string;
741
- /**
742
- * Gets the localized label for the channel field.
743
- *
744
- * @override
745
- * @returns {string} Always returns "Bank" for bank contacts
746
- */
747
474
  get channelLabel(): string;
748
- /**
749
- * Gets the bank's SWIFT code as the channel identifier.
750
- * This is the programmatic identifier used for bank transfers and API calls.
751
- *
752
- * @returns {BankSwiftCode} The bank's SWIFT/BIC code (e.g., "CORUTZTZ", "KCBLKENX")
753
- *
754
- * @example
755
- * ```typescript
756
- * const contact = new BankContactInfo("John", crdBank, "123456789");
757
- * console.log(contact.channelId); // "CORUTZTZ"
758
- *
759
- * // Type-safe usage
760
- * if (contact.channelId === "CORUTZTZ") {
761
- * console.log("This is a CRDB Bank account");
762
- * }
763
- * ```
764
- */
765
475
  get channelId(): BankSwiftCode;
766
- /**
767
- * Gets the bank's short name for display purposes.
768
- * Provides a human-readable identifier for the banking institution.
769
- *
770
- * @returns {string} The bank's abbreviated name (e.g., "CRDB", "KCB", "Equity")
771
- *
772
- * @example
773
- * ```typescript
774
- * const crdContact = new BankContactInfo("John", crdBank, "123456789");
775
- * console.log(crdContact.channelName); // "CRDB"
776
- *
777
- * const kcbContact = new BankContactInfo("Jane", kcbBank, "987654321");
778
- * console.log(kcbContact.channelName); // "KCB"
779
- * ```
780
- *
781
- * @remarks
782
- * The short name is maintained by the Bank service and represents
783
- * the commonly used abbreviation for the banking institution.
784
- */
785
476
  get channelName(): string;
477
+ toJSON(): BankContactInfoJSON;
478
+ static fromJSON(json: BankContactInfoJSON | string): BankContactInfo | undefined;
479
+ static fromJSONString(jsonString: string): BankContactInfo | undefined;
480
+ static isBankContactInfoJSON(obj: unknown): obj is BankContactInfoJSON;
786
481
  }
787
482
  /**
788
483
  * Union type representing either a mobile or bank contact.
789
- * Used for type-safe handling of contact information throughout the application.
790
- *
791
- * This discriminated union allows for:
792
- * - **Type-safe polymorphism**: Handle different contact types with single interface
793
- * - **Runtime type discrimination**: Use `contact.type` to determine specific type
794
- * - **Comprehensive validation**: Each type provides its own validation logic
795
- * - **Consistent API**: Both types implement BaseContactInfo interface
796
- * - **Country code access**: Always available via contact.countryCode (derived from domain objects)
797
484
  *
798
485
  * @typedef {MobileContactInfo | BankContactInfo} ContactInfo
799
- *
800
- * @example
801
- * ```typescript
802
- * // Type-safe handling of mixed contact types
803
- * function processContact(contact: ContactInfo) {
804
- * console.log(`Processing ${contact.type} contact: ${contact.accountName}`);
805
- * console.log(`Channel: ${contact.channelName}`);
806
- * console.log(`Country: ${contact.countryCode}`); // Always available
807
- *
808
- * // Type discrimination for specific behavior
809
- * if (contact.type === "Mobile") {
810
- * // TypeScript knows this is MobileContactInfo
811
- * console.log(`MNO: ${contact.mnoId}`);
812
- * console.log(`Phone: ${contact.phoneNumber.e164Format}`);
813
- * } else {
814
- * // TypeScript knows this is BankContactInfo
815
- * console.log(`Bank: ${contact.bank.fullName}`);
816
- * console.log(`SWIFT: ${contact.bank.swiftCode}`);
817
- * }
818
- * }
819
- *
820
- * // Usage with arrays
821
- * const contacts: ContactInfo[] = [
822
- * new MobileContactInfo("John", phoneNumber, TZMNOId.VODACOM),
823
- * new BankContactInfo("Jane", bank, "123456789")
824
- * ];
825
- *
826
- * contacts.forEach(processContact);
827
- *
828
- * // Type guards work seamlessly
829
- * const mobileContacts = contacts.filter((c): c is MobileContactInfo => c.type === "Mobile");
830
- * const bankContacts = contacts.filter((c): c is BankContactInfo => c.type === "Bank");
831
- * ```
832
- *
833
- * @see {@link MobileContactInfo} For mobile money contact implementation
834
- * @see {@link BankContactInfo} For bank transfer contact implementation
835
- * @see {@link BaseContactInfo} For common interface and behavior
836
486
  */
837
487
  export type ContactInfo = MobileContactInfo | BankContactInfo;
838
488
  export {};