@temboplus/afloat 0.1.70 → 0.1.72

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.
@@ -108,7 +108,7 @@ export declare class BaseRepository<TContract extends AppRouter> {
108
108
  * // - x-request-id: "uuid-v4-string"
109
109
  * ```
110
110
  */
111
- get client(): { [TKey in keyof TContract]: TContract[TKey] extends import("@ts-rest/core").AppRoute ? import("@ts-rest/core").AppRouteFunction<TContract[TKey], InitClientArgs, import("@ts-rest/core").PartialClientInferRequest<TContract[TKey], InitClientArgs>> : TContract[TKey] extends AppRouter ? TContract[TKey] extends infer T extends AppRouter ? { [TKey_1 in keyof T]: TContract[TKey][TKey_1] extends import("@ts-rest/core").AppRoute ? import("@ts-rest/core").AppRouteFunction<TContract[TKey][TKey_1], InitClientArgs, import("@ts-rest/core").PartialClientInferRequest<TContract[TKey][TKey_1], InitClientArgs>> : TContract[TKey][TKey_1] extends AppRouter ? TContract[TKey][TKey_1] extends infer T_1 extends AppRouter ? { [TKey_2 in keyof T_1]: TContract[TKey][TKey_1][TKey_2] extends import("@ts-rest/core").AppRoute ? import("@ts-rest/core").AppRouteFunction<TContract[TKey][TKey_1][TKey_2], InitClientArgs, import("@ts-rest/core").PartialClientInferRequest<TContract[TKey][TKey_1][TKey_2], InitClientArgs>> : TContract[TKey][TKey_1][TKey_2] extends AppRouter ? TContract[TKey][TKey_1][TKey_2] extends infer T_2 extends AppRouter ? { [TKey_3 in keyof T_2]: TContract[TKey][TKey_1][TKey_2][TKey_3] extends import("@ts-rest/core").AppRoute ? import("@ts-rest/core").AppRouteFunction<TContract[TKey][TKey_1][TKey_2][TKey_3], InitClientArgs, import("@ts-rest/core").PartialClientInferRequest<TContract[TKey][TKey_1][TKey_2][TKey_3], InitClientArgs>> : TContract[TKey][TKey_1][TKey_2][TKey_3] extends AppRouter ? TContract[TKey][TKey_1][TKey_2][TKey_3] extends infer T_3 extends AppRouter ? { [TKey_4 in keyof T_3]: TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4] extends import("@ts-rest/core").AppRoute ? import("@ts-rest/core").AppRouteFunction<TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4], InitClientArgs, import("@ts-rest/core").PartialClientInferRequest<TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4], InitClientArgs>> : TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4] extends AppRouter ? TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4] extends infer T_4 extends AppRouter ? { [TKey_5 in keyof T_4]: TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5] extends import("@ts-rest/core").AppRoute ? import("@ts-rest/core").AppRouteFunction<TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5], InitClientArgs, import("@ts-rest/core").PartialClientInferRequest<TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5], InitClientArgs>> : TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5] extends AppRouter ? TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5] extends infer T_5 extends AppRouter ? { [TKey_6 in keyof T_5]: TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6] extends import("@ts-rest/core").AppRoute ? import("@ts-rest/core").AppRouteFunction<TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6], InitClientArgs, import("@ts-rest/core").PartialClientInferRequest<TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6], InitClientArgs>> : TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6] extends AppRouter ? TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6] extends infer T_6 extends AppRouter ? { [TKey_7 in keyof T_6]: TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6][TKey_7] extends import("@ts-rest/core").AppRoute ? import("@ts-rest/core").AppRouteFunction<TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6][TKey_7], InitClientArgs, import("@ts-rest/core").PartialClientInferRequest<TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6][TKey_7], InitClientArgs>> : TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6][TKey_7] extends AppRouter ? TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6][TKey_7] extends infer T_7 extends AppRouter ? { [TKey_8 in keyof T_7]: TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6][TKey_7][TKey_8] extends import("@ts-rest/core").AppRoute ? import("@ts-rest/core").AppRouteFunction<TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6][TKey_7][TKey_8], InitClientArgs, import("@ts-rest/core").PartialClientInferRequest<TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6][TKey_7][TKey_8], InitClientArgs>> : TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6][TKey_7][TKey_8] extends AppRouter ? TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6][TKey_7][TKey_8] extends infer T_8 extends AppRouter ? { [TKey_9 in keyof T_8]: TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6][TKey_7][TKey_8][TKey_9] extends import("@ts-rest/core").AppRoute ? import("@ts-rest/core").AppRouteFunction<TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6][TKey_7][TKey_8][TKey_9], InitClientArgs, import("@ts-rest/core").PartialClientInferRequest<TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6][TKey_7][TKey_8][TKey_9], InitClientArgs>> : TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6][TKey_7][TKey_8][TKey_9] extends AppRouter ? TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6][TKey_7][TKey_8][TKey_9] extends infer T_9 extends AppRouter ? { [TKey_10 in keyof T_9]: TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6][TKey_7][TKey_8][TKey_9][TKey_10] extends import("@ts-rest/core").AppRoute ? import("@ts-rest/core").AppRouteFunction<TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6][TKey_7][TKey_8][TKey_9][TKey_10], InitClientArgs, import("@ts-rest/core").PartialClientInferRequest<TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6][TKey_7][TKey_8][TKey_9][TKey_10], InitClientArgs>> : TContract[TKey][TKey_1][TKey_2][TKey_3][TKey_4][TKey_5][TKey_6][TKey_7][TKey_8][TKey_9][TKey_10] extends AppRouter ? /*elided*/ any : never; } : never : never; } : never : never; } : never : never; } : never : never; } : never : never; } : never : never; } : never : never; } : never : never; } : never : never; } : never : never; };
111
+ get client(): { [TKey in keyof TContract]: TContract[TKey] extends import("@ts-rest/core").AppRoute ? import("@ts-rest/core").AppRouteFunction<TContract[TKey], InitClientArgs, import("@ts-rest/core").PartialClientInferRequest<TContract[TKey], InitClientArgs>> : TContract[TKey] extends AppRouter ? TContract[TKey] extends infer T extends AppRouter ? { [TKey_2 in keyof T]: T[TKey_2] extends import("@ts-rest/core").AppRoute ? import("@ts-rest/core").AppRouteFunction<T[TKey_2], TClientArgs, import("@ts-rest/core").PartialClientInferRequest<T[TKey_2], TClientArgs>> : T[TKey_2] extends AppRouter ? T[TKey_2] extends infer T_1 extends AppRouter ? { [TKey_3 in keyof T_1]: T_1[TKey_3] extends import("@ts-rest/core").AppRoute ? import("@ts-rest/core").AppRouteFunction<T_1[TKey_3], TClientArgs, import("@ts-rest/core").PartialClientInferRequest<T_1[TKey_3], TClientArgs>> : T_1[TKey_3] extends AppRouter ? T_1[TKey_3] extends infer T_2 extends AppRouter ? { [TKey_4 in keyof T_2]: T_2[TKey_4] extends import("@ts-rest/core").AppRoute ? import("@ts-rest/core").AppRouteFunction<T_2[TKey_4], TClientArgs, import("@ts-rest/core").PartialClientInferRequest<T_2[TKey_4], TClientArgs>> : T_2[TKey_4] extends AppRouter ? T_2[TKey_4] extends infer T_3 extends AppRouter ? { [TKey_5 in keyof T_3]: T_3[TKey_5] extends import("@ts-rest/core").AppRoute ? import("@ts-rest/core").AppRouteFunction<T_3[TKey_5], TClientArgs, import("@ts-rest/core").PartialClientInferRequest<T_3[TKey_5], TClientArgs>> : T_3[TKey_5] extends AppRouter ? T_3[TKey_5] extends infer T_4 extends AppRouter ? { [TKey_6 in keyof T_4]: T_4[TKey_6] extends import("@ts-rest/core").AppRoute ? import("@ts-rest/core").AppRouteFunction<T_4[TKey_6], TClientArgs, import("@ts-rest/core").PartialClientInferRequest<T_4[TKey_6], TClientArgs>> : T_4[TKey_6] extends AppRouter ? T_4[TKey_6] extends infer T_5 extends AppRouter ? { [TKey_7 in keyof T_5]: T_5[TKey_7] extends import("@ts-rest/core").AppRoute ? import("@ts-rest/core").AppRouteFunction<T_5[TKey_7], TClientArgs, import("@ts-rest/core").PartialClientInferRequest<T_5[TKey_7], TClientArgs>> : T_5[TKey_7] extends AppRouter ? T_5[TKey_7] extends infer T_6 extends AppRouter ? { [TKey_8 in keyof T_6]: T_6[TKey_8] extends import("@ts-rest/core").AppRoute ? import("@ts-rest/core").AppRouteFunction<T_6[TKey_8], TClientArgs, import("@ts-rest/core").PartialClientInferRequest<T_6[TKey_8], TClientArgs>> : T_6[TKey_8] extends AppRouter ? T_6[TKey_8] extends infer T_7 extends AppRouter ? { [TKey_9 in keyof T_7]: T_7[TKey_9] extends import("@ts-rest/core").AppRoute ? import("@ts-rest/core").AppRouteFunction<T_7[TKey_9], TClientArgs, import("@ts-rest/core").PartialClientInferRequest<T_7[TKey_9], TClientArgs>> : T_7[TKey_9] extends AppRouter ? T_7[TKey_9] extends infer T_8 extends AppRouter ? { [TKey_10 in keyof T_8]: T_8[TKey_10] extends import("@ts-rest/core").AppRoute ? import("@ts-rest/core").AppRouteFunction<T_8[TKey_10], TClientArgs, import("@ts-rest/core").PartialClientInferRequest<T_8[TKey_10], TClientArgs>> : T_8[TKey_10] extends AppRouter ? T_8[TKey_10] extends infer T_9 extends AppRouter ? { [TKey_11 in keyof T_9]: T_9[TKey_11] extends import("@ts-rest/core").AppRoute ? import("@ts-rest/core").AppRouteFunction<T_9[TKey_11], TClientArgs, import("@ts-rest/core").PartialClientInferRequest<T_9[TKey_11], TClientArgs>> : T_9[TKey_11] extends AppRouter ? /*elided*/ any : never; } : never : never; } : never : never; } : never : never; } : never : never; } : never : never; } : never : never; } : never : never; } : never : never; } : never : never; } : never : never; };
112
112
  /**
113
113
  * Updates the authentication token used by this repository.
114
114
  *
@@ -9,11 +9,15 @@ import type { BankSwiftCode, MNOId } from "@temboplus/frontend-core";
9
9
  * Serves as the foundation for type-safe contact handling throughout the application,
10
10
  * ensuring consistent behavior between mobile money and bank transfer contacts.
11
11
  *
12
+ * **Country Code Handling:**
13
+ * The country code is always derived from the underlying domain objects (PhoneNumber or Bank)
14
+ * rather than being passed as a separate parameter, ensuring consistency and single source of truth.
15
+ *
12
16
  * @abstract
13
17
  * @class BaseContactInfo
14
18
  *
15
19
  * @property {ContactType} type - The type of contact (either "Mobile" or "Bank")
16
- * @property {ISO2CountryCode} countryCode - The ISO2 country code where this contact operates
20
+ * @property {ISO2CountryCode} countryCode - The ISO2 country code derived from PhoneNumber or Bank
17
21
  *
18
22
  * @example
19
23
  * ```typescript
@@ -25,6 +29,7 @@ import type { BankSwiftCode, MNOId } from "@temboplus/frontend-core";
25
29
  * function processContact(contact: BaseContactInfo) {
26
30
  * console.log(`Processing ${contact.type} contact: ${contact.displayName}`);
27
31
  * console.log(`Channel: ${contact.channelDisplayName}`);
32
+ * console.log(`Country: ${contact.countryCode}`); // Always available
28
33
  * }
29
34
  * ```
30
35
  */
@@ -37,7 +42,7 @@ declare abstract class BaseContactInfo {
37
42
  *
38
43
  * @protected
39
44
  * @param {ContactType} type - The type of contact to create ("Mobile" or "Bank")
40
- * @param {ISO2CountryCode} countryCode - The ISO2 country code for this contact
45
+ * @param {ISO2CountryCode} countryCode - The ISO2 country code derived from domain objects
41
46
  */
42
47
  constructor(type: ContactType, countryCode: ISO2CountryCode);
43
48
  /**
@@ -117,12 +122,14 @@ declare abstract class BaseContactInfo {
117
122
  *
118
123
  * This class properly delegates MNO-related logic to country-specific implementations,
119
124
  * supporting both countries with Mobile Number Portability (MNP) and those without.
125
+ * The country code is always derived from the PhoneNumber object, ensuring consistency.
120
126
  *
121
127
  * **Key Features:**
122
128
  * - Automatic MNO detection for countries without MNP (e.g., Tanzania)
123
129
  * - Explicit MNO requirement for countries with MNP (e.g., Kenya)
124
130
  * - Country-specific validation through MNOUtils delegation
125
131
  * - Comprehensive error handling with structured context
132
+ * - Country code derived from PhoneNumber (single source of truth)
126
133
  *
127
134
  * **MNP Handling:**
128
135
  * - **Tanzania (no MNP)**: MNO is always auto-detected from phone number prefix, ignoring any provided MNO
@@ -140,6 +147,7 @@ declare abstract class BaseContactInfo {
140
147
  * // Tanzania - MNO auto-detected from prefix (ignores provided MNO)
141
148
  * const tzContact = new MobileContactInfo("John Doe", tzPhoneNumber);
142
149
  * console.log(tzContact.channel); // "VODACOM" (auto-detected)
150
+ * console.log(tzContact.countryCode); // "TZ" (from phoneNumber)
143
151
  *
144
152
  * // Tanzania - Even with explicit MNO, it's auto-detected from prefix
145
153
  * const tzExplicit = new MobileContactInfo("John Doe", tzPhoneNumber, TZMNOId.AIRTEL);
@@ -147,6 +155,7 @@ declare abstract class BaseContactInfo {
147
155
  *
148
156
  * // Kenya - MNO must be explicit due to MNP
149
157
  * const keContact = new MobileContactInfo("Jane Smith", kePhoneNumber, KEMNOId.SAFARICOM);
158
+ * console.log(keContact.countryCode); // "KE" (from phoneNumber)
150
159
  *
151
160
  * // Kenya - This would throw an error (MNO required)
152
161
  * // const keContact = new MobileContactInfo("Jane Smith", kePhoneNumber); // ❌ Error
@@ -164,12 +173,13 @@ export declare class MobileContactInfo extends BaseContactInfo {
164
173
  * **Validation Process:**
165
174
  * 1. Validates name is non-empty
166
175
  * 2. Validates phone number structure
167
- * 3. Handles MNO validation based on country MNP status:
176
+ * 3. Extracts country code from PhoneNumber object
177
+ * 4. Handles MNO validation based on country MNP status:
168
178
  * - **Countries with MNP (KE)**: Requires explicit MNO, validates it's valid for country
169
179
  * - **Countries without MNP (TZ)**: Always auto-detects MNO from phone number prefix (ignores provided MNO)
170
180
  *
171
181
  * @param {string} name - The contact's personal name (required, non-empty)
172
- * @param {PhoneNumber} phoneNumber - The validated phone number object
182
+ * @param {PhoneNumber} phoneNumber - The validated phone number object (contains country code)
173
183
  * @param {MNOId} [mnoId] - MNO ID. Required for MNP countries (KE), ignored for non-MNP countries (TZ)
174
184
  *
175
185
  * @throws {ContactInfoError} When any validation fails:
@@ -199,21 +209,20 @@ export declare class MobileContactInfo extends BaseContactInfo {
199
209
  /**
200
210
  * Creates a MobileContactInfo instance from a ContactDTO object.
201
211
  * Handles validation and MNO extraction from the DTO's channel field.
212
+ * The country code is automatically derived from the parsed phone number.
202
213
  *
203
214
  * **Process:**
204
215
  * 1. Validates DTO type is "Mobile"
205
- * 2. Validates country code format
206
- * 3. Parses phone number with country context
207
- * 4. Handles MNO based on country MNP status:
216
+ * 2. Parses phone number (extracts country code from E164 format)
217
+ * 3. Handles MNO based on country MNP status:
208
218
  * - **MNP countries**: Uses channel field (required)
209
219
  * - **Non-MNP countries**: Auto-detects from phone number (ignores channel field)
210
- * 5. Delegates to constructor for final validation
220
+ * 4. Delegates to constructor for final validation
211
221
  *
212
222
  * @static
213
223
  * @param {ContactDTO} info - The contact data transfer object
214
224
  * @param {string} info.type - Must be "Mobile"
215
- * @param {string} info.accountNo - The phone number string to parse
216
- * @param {string} info.countryCode - ISO2 country code
225
+ * @param {string} info.accountNo - The phone number string to parse (should be E164 format)
217
226
  * @param {string} info.displayName - The contact's name
218
227
  * @param {string} [info.channel] - MNO ID (required for MNP countries, ignored for non-MNP countries)
219
228
  *
@@ -225,7 +234,6 @@ export declare class MobileContactInfo extends BaseContactInfo {
225
234
  * const tzContactDTO = {
226
235
  * type: "Mobile",
227
236
  * accountNo: "+255712345678", // Vodacom prefix
228
- * countryCode: "TZ",
229
237
  * displayName: "John Doe",
230
238
  * channel: "AIRTEL" // This will be ignored, Vodacom will be auto-detected
231
239
  * };
@@ -234,36 +242,39 @@ export declare class MobileContactInfo extends BaseContactInfo {
234
242
  * const keContactDTO = {
235
243
  * type: "Mobile",
236
244
  * accountNo: "+254712345678",
237
- * countryCode: "KE",
238
245
  * displayName: "Jane Smith",
239
246
  * channel: "SAFARICOM" // Required for Kenya
240
247
  * };
241
248
  *
242
249
  * const tzContact = MobileContactInfo.fromContactDTO(tzContactDTO);
243
250
  * console.log(tzContact?.channelId); // "VODACOM" (not "AIRTEL")
251
+ * console.log(tzContact?.countryCode); // "TZ" (from phone number)
244
252
  *
245
253
  * const keContact = MobileContactInfo.fromContactDTO(keContactDTO);
246
254
  * console.log(keContact?.channelId); // "SAFARICOM"
255
+ * console.log(keContact?.countryCode); // "KE" (from phone number)
247
256
  * ```
248
257
  */
249
258
  static fromContactDTO(info: ContactDTO): MobileContactInfo | undefined;
250
259
  /**
251
260
  * Creates a MobileContactInfo instance from a PayoutDTO object.
252
261
  * Extracts mobile contact information from payout data structure.
262
+ * The country code is derived from the parsed phone number.
253
263
  *
254
264
  * **Process:**
255
- * 1. Validates country code format
256
- * 2. Parses phone number from msisdn field
257
- * 3. Handles MNO based on country MNP status:
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:
258
269
  * - **MNP countries**: Uses channel field (required)
259
270
  * - **Non-MNP countries**: Auto-detects from phone number (ignores channel field)
260
- * 4. Uses payeeName as the contact name
261
- * 5. Delegates to constructor for validation
271
+ * 5. Uses payeeName as the contact name
272
+ * 6. Delegates to constructor for validation
262
273
  *
263
274
  * @static
264
275
  * @param {PayoutDTO} info - The payout data transfer object
265
- * @param {string} info.msisdn - The phone number in various formats
266
- * @param {string} info.countryCode - ISO2 country code
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)
267
278
  * @param {string} info.payeeName - The recipient's name
268
279
  * @param {string} [info.channel] - MNO ID (required for MNP countries, ignored for non-MNP countries)
269
280
  *
@@ -289,6 +300,7 @@ export declare class MobileContactInfo extends BaseContactInfo {
289
300
  *
290
301
  * const tzContact = MobileContactInfo.fromPayoutDTO(tzPayoutDTO);
291
302
  * console.log(tzContact?.channelName); // "M-Pesa" (Vodacom's service)
303
+ * console.log(tzContact?.countryCode); // "TZ" (from phoneNumber)
292
304
  * ```
293
305
  */
294
306
  static fromPayoutDTO(info: PayoutDTO): MobileContactInfo | undefined;
@@ -317,6 +329,7 @@ export declare class MobileContactInfo extends BaseContactInfo {
317
329
  * console.log(unknownData.name); // ✅ Type-safe access
318
330
  * console.log(unknownData.phoneNumber.e164Format); // ✅ Type-safe
319
331
  * console.log(unknownData.mnoId); // ✅ Type-safe
332
+ * console.log(unknownData.countryCode); // ✅ Type-safe (from phoneNumber)
320
333
  * } else {
321
334
  * console.log("Invalid MobileContactInfo structure");
322
335
  * }
@@ -414,15 +427,15 @@ export declare class MobileContactInfo extends BaseContactInfo {
414
427
  get accountName(): string;
415
428
  /**
416
429
  * Gets the phone number formatted for display and storage.
417
- * Returns the number in international numeric format (without + prefix).
430
+ * Returns the number in e164 format (with + prefix).
418
431
  *
419
432
  * @override
420
- * @returns {string} Phone number in international numeric format (e.g., "255712345678")
433
+ * @returns {string} Phone number in e164 format (e.g., "+255712345678")
421
434
  *
422
435
  * @example
423
436
  * ```typescript
424
437
  * const contact = new MobileContactInfo("John", phoneNumber);
425
- * console.log(contact.accNumber); // "255712345678"
438
+ * console.log(contact.accountNumber); // "+255712345678"
426
439
  * ```
427
440
  */
428
441
  get accountNumber(): string;
@@ -456,11 +469,11 @@ export declare class MobileContactInfo extends BaseContactInfo {
456
469
  * @example
457
470
  * ```typescript
458
471
  * const contact = new MobileContactInfo("John", tzPhone, TZMNOId.VODACOM);
459
- * console.log(contact.channel); // "VODACOM" (for MNP countries)
472
+ * console.log(contact.channelId); // "VODACOM" (for MNP countries)
460
473
  *
461
474
  * // For non-MNP countries, always returns auto-detected value
462
475
  * const contact2 = new MobileContactInfo("John", tzPhone, TZMNOId.AIRTEL); // AIRTEL ignored
463
- * console.log(contact2.channel); // "VODACOM" (auto-detected from phone prefix)
476
+ * console.log(contact2.channelId); // "VODACOM" (auto-detected from phone prefix)
464
477
  * ```
465
478
  */
466
479
  get channelId(): MNOId;
@@ -479,14 +492,14 @@ export declare class MobileContactInfo extends BaseContactInfo {
479
492
  * @example
480
493
  * ```typescript
481
494
  * const vodacomContact = new MobileContactInfo("John", tzPhone, TZMNOId.VODACOM);
482
- * console.log(vodacomContact.channelDisplayName); // "M-Pesa"
495
+ * console.log(vodacomContact.channelName); // "M-Pesa"
483
496
  *
484
497
  * const safaricomContact = new MobileContactInfo("Jane", kePhone, KEMNOId.SAFARICOM);
485
- * console.log(safaricomContact.channelDisplayName); // "M-Pesa"
498
+ * console.log(safaricomContact.channelName); // "M-Pesa"
486
499
  *
487
500
  * // For non-MNP countries, shows auto-detected service regardless of provided MNO
488
501
  * const tzContact = new MobileContactInfo("Bob", tzVodacomPhone, TZMNOId.AIRTEL); // AIRTEL ignored
489
- * console.log(tzContact.channelDisplayName); // "M-Pesa" (Vodacom's service, auto-detected)
502
+ * console.log(tzContact.channelName); // "M-Pesa" (Vodacom's service, auto-detected)
490
503
  * ```
491
504
  *
492
505
  * @remarks
@@ -498,6 +511,7 @@ export declare class MobileContactInfo extends BaseContactInfo {
498
511
  /**
499
512
  * Implementation of BaseContactInfo for bank account contacts.
500
513
  * Handles storage, validation, and display of contact details specific to bank transfers.
514
+ * The country code is automatically derived from the Bank object.
501
515
  *
502
516
  * This class provides comprehensive validation for bank account information including
503
517
  * SWIFT code validation, account name verification, and account number format checking.
@@ -507,6 +521,7 @@ export declare class MobileContactInfo extends BaseContactInfo {
507
521
  * - Account name format validation
508
522
  * - Account number format validation (country-specific rules)
509
523
  * - Integration with Bank service for institution data
524
+ * - Country code derived from Bank (single source of truth)
510
525
  *
511
526
  * @extends BaseContactInfo
512
527
  * @class BankContactInfo
@@ -521,10 +536,11 @@ export declare class MobileContactInfo extends BaseContactInfo {
521
536
  * const bank = Bank.from("CORUTZTZ", "TZ"); // CRDB Bank
522
537
  * const contact = new BankContactInfo("John Doe", bank, "0150123456789");
523
538
  *
524
- * console.log(contact.channel); // "CORUTZTZ" (SWIFT code)
525
- * console.log(contact.channelDisplayName); // "CRDB" (bank short name)
526
- * console.log(contact.displayName); // "John Doe"
527
- * console.log(contact.accNumber); // "0150123456789"
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)
528
544
  * ```
529
545
  *
530
546
  * @throws {ContactInfoError} When validation fails (invalid account name, number, or bank)
@@ -535,14 +551,16 @@ export declare class BankContactInfo extends BaseContactInfo {
535
551
  readonly accNo: string;
536
552
  /**
537
553
  * Creates a new bank contact with comprehensive validation.
554
+ * The country code is automatically extracted from the Bank object.
538
555
  *
539
556
  * **Validation Process:**
540
- * 1. **Account name validation**: Checks format and character requirements
541
- * 2. **Account number validation**: Validates format per country banking rules
542
- * 3. **Bank validation**: Ensures bank object is valid and contains required data
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
543
561
  *
544
562
  * @param {string} accName - The bank account holder's name (must pass BankValidation.validateAccountName)
545
- * @param {Bank} bank - The bank institution object (must be valid Bank instance)
563
+ * @param {Bank} bank - The bank institution object (must be valid Bank instance with countryCode)
546
564
  * @param {string} accNo - The bank account number (must pass country-specific validation)
547
565
  *
548
566
  * @throws {ContactInfoError} When validation fails:
@@ -556,6 +574,7 @@ export declare class BankContactInfo extends BaseContactInfo {
556
574
  * const bank = Bank.from("CORUTZTZ", "TZ");
557
575
  * const contact = new BankContactInfo("John Doe", bank, "0150123456789");
558
576
  * console.log("Bank contact created successfully");
577
+ * console.log(`Country: ${contact.countryCode}`); // "TZ" (from bank)
559
578
  * } catch (error) {
560
579
  * if (error instanceof ContactInfoError) {
561
580
  * console.log(`Validation failed: ${error.message}`);
@@ -567,19 +586,20 @@ export declare class BankContactInfo extends BaseContactInfo {
567
586
  /**
568
587
  * Creates a BankContactInfo instance from a ContactDTO object.
569
588
  * Handles SWIFT code validation and bank lookup.
589
+ * The country code is derived from the SWIFT code.
570
590
  *
571
591
  * **Process:**
572
592
  * 1. Validates DTO type is "Bank"
573
- * 2. Validates country code format
574
- * 3. Validates SWIFT code format and existence
575
- * 4. Looks up bank information using SWIFT code
576
- * 5. Delegates to constructor for final validation
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
577
598
  *
578
599
  * @static
579
600
  * @param {ContactDTO} info - The contact data transfer object
580
601
  * @param {string} info.type - Must be "Bank"
581
602
  * @param {string} info.channel - The SWIFT code for the bank
582
- * @param {string} info.countryCode - ISO2 country code
583
603
  * @param {string} info.displayName - The account holder's name
584
604
  * @param {string} info.accountNo - The bank account number
585
605
  *
@@ -590,14 +610,14 @@ export declare class BankContactInfo extends BaseContactInfo {
590
610
  * const contactDTO = {
591
611
  * type: "Bank",
592
612
  * channel: "CORUTZTZ", // CRDB Bank SWIFT code
593
- * countryCode: "TZ",
594
613
  * displayName: "John Doe",
595
614
  * accountNo: "0150123456789"
596
615
  * };
597
616
  *
598
617
  * const contact = BankContactInfo.fromContactDTO(contactDTO);
599
618
  * if (contact) {
600
- * console.log(`Created bank contact: ${contact.displayName} at ${contact.bank.shortName}`);
619
+ * console.log(`Created bank contact: ${contact.accountName} at ${contact.bank.shortName}`);
620
+ * console.log(`Country: ${contact.countryCode}`); // "TZ" (derived from SWIFT)
601
621
  * }
602
622
  * ```
603
623
  */
@@ -605,20 +625,21 @@ export declare class BankContactInfo extends BaseContactInfo {
605
625
  /**
606
626
  * Creates a BankContactInfo instance from a PayoutDTO object.
607
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.
608
629
  *
609
630
  * **Expected Format:** The msisdn field should contain "SWIFTCODE:ACCOUNTNUMBER"
610
631
  *
611
632
  * **Process:**
612
- * 1. Validates country code format
633
+ * 1. Validates country code format in DTO (used as hint/validation)
613
634
  * 2. Splits msisdn field on ":" delimiter
614
635
  * 3. Validates SWIFT code format and existence
615
- * 4. Looks up bank information
636
+ * 4. Looks up bank information (bank contains country code)
616
637
  * 5. Creates contact with parsed information
617
638
  *
618
639
  * @static
619
640
  * @param {PayoutDTO} info - The payout data transfer object
620
641
  * @param {string} info.msisdn - Bank info in format "SWIFTCODE:ACCOUNTNUMBER"
621
- * @param {string} info.countryCode - ISO2 country code
642
+ * @param {string} info.countryCode - ISO2 country code (used for validation)
622
643
  * @param {string} info.payeeName - The account holder's name
623
644
  *
624
645
  * @returns {BankContactInfo | undefined} New instance if successful, undefined if parsing fails
@@ -633,9 +654,10 @@ export declare class BankContactInfo extends BaseContactInfo {
633
654
  *
634
655
  * const contact = BankContactInfo.fromPayoutDTO(payoutDTO);
635
656
  * if (contact) {
636
- * console.log(`Payout to: ${contact.displayName}`);
657
+ * console.log(`Payout to: ${contact.accountName}`);
637
658
  * console.log(`Bank: ${contact.bank.fullName}`);
638
- * console.log(`Account: ${contact.accNumber}`);
659
+ * console.log(`Account: ${contact.accountNumber}`);
660
+ * console.log(`Country: ${contact.countryCode}`); // "TZ" (from bank)
639
661
  * }
640
662
  * ```
641
663
  *
@@ -670,6 +692,7 @@ export declare class BankContactInfo extends BaseContactInfo {
670
692
  * console.log(unknownData.accName); // ✅ Type-safe access
671
693
  * console.log(unknownData.bank.fullName); // ✅ Type-safe
672
694
  * console.log(unknownData.accNo); // ✅ Type-safe
695
+ * console.log(unknownData.countryCode); // ✅ Type-safe (from bank)
673
696
  * } else {
674
697
  * console.log("Invalid BankContactInfo structure");
675
698
  * }
@@ -731,10 +754,10 @@ export declare class BankContactInfo extends BaseContactInfo {
731
754
  * @example
732
755
  * ```typescript
733
756
  * const contact = new BankContactInfo("John", crdBank, "123456789");
734
- * console.log(contact.channel); // "CORUTZTZ"
757
+ * console.log(contact.channelId); // "CORUTZTZ"
735
758
  *
736
759
  * // Type-safe usage
737
- * if (contact.channel === "CORUTZTZ") {
760
+ * if (contact.channelId === "CORUTZTZ") {
738
761
  * console.log("This is a CRDB Bank account");
739
762
  * }
740
763
  * ```
@@ -749,10 +772,10 @@ export declare class BankContactInfo extends BaseContactInfo {
749
772
  * @example
750
773
  * ```typescript
751
774
  * const crdContact = new BankContactInfo("John", crdBank, "123456789");
752
- * console.log(crdContact.channelDisplayName); // "CRDB"
775
+ * console.log(crdContact.channelName); // "CRDB"
753
776
  *
754
777
  * const kcbContact = new BankContactInfo("Jane", kcbBank, "987654321");
755
- * console.log(kcbContact.channelDisplayName); // "KCB"
778
+ * console.log(kcbContact.channelName); // "KCB"
756
779
  * ```
757
780
  *
758
781
  * @remarks
@@ -770,6 +793,7 @@ export declare class BankContactInfo extends BaseContactInfo {
770
793
  * - **Runtime type discrimination**: Use `contact.type` to determine specific type
771
794
  * - **Comprehensive validation**: Each type provides its own validation logic
772
795
  * - **Consistent API**: Both types implement BaseContactInfo interface
796
+ * - **Country code access**: Always available via contact.countryCode (derived from domain objects)
773
797
  *
774
798
  * @typedef {MobileContactInfo | BankContactInfo} ContactInfo
775
799
  *
@@ -777,8 +801,9 @@ export declare class BankContactInfo extends BaseContactInfo {
777
801
  * ```typescript
778
802
  * // Type-safe handling of mixed contact types
779
803
  * function processContact(contact: ContactInfo) {
780
- * console.log(`Processing ${contact.type} contact: ${contact.displayName}`);
781
- * console.log(`Channel: ${contact.channelDisplayName}`);
804
+ * console.log(`Processing ${contact.type} contact: ${contact.accountName}`);
805
+ * console.log(`Channel: ${contact.channelName}`);
806
+ * console.log(`Country: ${contact.countryCode}`); // Always available
782
807
  *
783
808
  * // Type discrimination for specific behavior
784
809
  * if (contact.type === "Mobile") {
@@ -1,6 +1,5 @@
1
1
  import { type ContactDTO, ContactType } from "../features/contact/contact.dtos";
2
2
  import { type ContactInfo } from "./contact-info.model";
3
- import { Country, ISO2CountryCode } from "@temboplus/frontend-core";
4
3
  /**
5
4
  * Contact class that wraps the Zod schema and provides additional functionality
6
5
  */
@@ -87,21 +86,7 @@ export declare class Contact {
87
86
  * - "Display Name" as fallback
88
87
  */
89
88
  get accNameLabel(): string;
90
- /**
91
- * Country code associated with this contact
92
- *
93
- * @returns {string} Two-letter ISO country code
94
- * @throws an error if the country code is not a valid ISO-2 country code
95
- */
96
- get countryCode(): ISO2CountryCode;
97
89
  get channelName(): string;
98
- /**
99
- * Country object associated with this contact
100
- *
101
- * @returns {Country} Country instance representing the contact's country
102
- * @throws
103
- */
104
- get country(): Country;
105
90
  /**
106
91
  * Creates a Contact instance from raw data
107
92
  * @throws {ZodError} if validation fails
package/package.json CHANGED
@@ -1,15 +1,12 @@
1
1
  {
2
2
  "name": "@temboplus/afloat",
3
- "version": "0.1.70",
3
+ "version": "0.1.72",
4
4
  "description": "A foundational library for Temboplus-Afloat projects.",
5
- "main": "./dist/index.cjs.js",
6
- "module": "./dist/index.esm.js",
7
- "types": "./dist/index.d.ts",
8
5
  "type": "module",
9
6
  "exports": {
10
7
  ".": {
11
- "import": "./dist/index.esm.js",
12
- "require": "./dist/index.cjs.js",
8
+ "import": "./dist/index.js",
9
+ "require": "./dist/index.cjs",
13
10
  "types": "./dist/index.d.ts"
14
11
  }
15
12
  },
@@ -19,8 +16,7 @@
19
16
  "scripts": {
20
17
  "build": "rollup -c rollup.config.js",
21
18
  "prepare": "npm run build",
22
- "dev": "npm run build -- --watch",
23
- "test": "echo \"Error: no test specified\" && exit 1"
19
+ "dev": "npm run build -- --watch"
24
20
  },
25
21
  "repository": {
26
22
  "type": "git",
@@ -37,12 +33,9 @@
37
33
  },
38
34
  "homepage": "https://github.com/TemboPlus-Frontend/afloat-js#readme",
39
35
  "peerDependencies": {
40
- "@temboplus/frontend-core": "^0.2.16",
41
- "@ts-rest/core": "^3.52.1",
42
36
  "tslib": "^2.8.1",
43
37
  "uuid": "^11.1.0",
44
- "zod": "^3.24.2",
45
- "zustand": "^4.5.7"
38
+ "zod": "^3.24.2"
46
39
  },
47
40
  "devDependencies": {
48
41
  "@rollup/plugin-alias": "^5.1.1",
@@ -57,5 +50,10 @@
57
50
  "ts-jest": "^29.3.1",
58
51
  "ts-node": "^10.9.2",
59
52
  "typescript": "^5.8.3"
53
+ },
54
+ "dependencies": {
55
+ "@temboplus/frontend-core": "^0.2.17",
56
+ "zustand": "^4.5.7",
57
+ "@ts-rest/core": "^3.52.1"
60
58
  }
61
59
  }